Available Negotiators¶
NegMAS provides a rich set of negotiation agents for different mechanisms. This page lists all available negotiators organized by category.
Negotiation Callback Lifecycle¶
When a negotiator participates in a negotiation, the mechanism calls various callbacks in a guaranteed order. Understanding this order is essential for implementing custom negotiators.
Callback Order Flowchart¶
┌─────────────────────────────────────────────────────────────────────────┐
│ NEGOTIATION LIFECYCLE │
└─────────────────────────────────────────────────────────────────────────┘
1. JOINING PHASE (when negotiator.join() or mechanism.add() is called)
├── join(nmi, state, preferences, role)
│ └── Returns True/False to accept/reject joining
└── [preferences assigned internally, owner NOT set yet]
2. NEGOTIATION START (when mechanism.step() or mechanism.run() is called)
│
│ ┌─────────────────────────────────────────────────────────────────┐
│ │ IMPORTANT: The following callbacks are called ONCE per │
│ │ negotiation, in this EXACT order, regardless of when │
│ │ preferences were assigned (at constructor or at join time). │
│ └─────────────────────────────────────────────────────────────────┘
│
├── [owner set on preferences]
├── on_preferences_changed([Initialization]) ◄── ALWAYS FIRST (if preferences exist)
├── on_negotiation_start(state) ◄── ALWAYS SECOND
└── on_round_start(state) ◄── First round starts
3. NEGOTIATION ROUNDS (repeated until agreement, timeout, or break)
│
├── propose(state) → Outcome | None
│ └── Called when it's negotiator's turn to make an offer
│
├── respond(state, offer, source) → ResponseType
│ └── Called when evaluating an offer from another negotiator
│
├── on_partner_proposal(state, partner_id, offer)
│ └── Notification when a partner makes a proposal
│
├── on_partner_response(state, partner_id, outcome, response)
│ └── Notification when a partner responds to an offer
│
├── on_round_end(state)
│ └── Called at the end of each round
│
└── on_round_start(state) [if more rounds remain]
└── Called at the start of each new round
4. NEGOTIATION END
│
├── on_negotiation_end(state)
│ └── Called when negotiation concludes (agreement, timeout, or break)
│
└── on_leave(state)
└── Called when negotiator leaves the mechanism
└── [owner cleared from preferences]
└── on_preferences_changed([Dissociated]) ◄── Notifies of disconnection
Key Guarantees¶
Initialization Order:
on_preferences_changed([Initialization])is always called beforeon_negotiation_start(), regardless of when preferences were set.Exactly Once: Both
on_preferences_changed([Initialization])andon_negotiation_start()are called exactly once per negotiation.Before Proposals: These initialization callbacks always occur before any
propose()orrespond()calls.Owner Lifecycle: The preferences
owneris set just beforeon_preferences_changed([Initialization])and cleared inon_leave().Dissociation Notification: When a negotiator leaves, it receive an
on_preferences_changed([Dissociated])notification.
Example: Tracking Callback Order¶
from negmas.sao import SAOMechanism, SAONegotiator, ResponseType
from negmas.common import PreferencesChangeType
class CallbackTracker(SAONegotiator):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.callback_log = []
def on_preferences_changed(self, changes):
change_types = [c.type.name for c in changes]
self.callback_log.append(f"on_preferences_changed({change_types})")
super().on_preferences_changed(changes)
def on_negotiation_start(self, state):
self.callback_log.append("on_negotiation_start")
super().on_negotiation_start(state)
def on_round_start(self, state):
self.callback_log.append(f"on_round_start(step={state.step})")
super().on_round_start(state)
def propose(self, state, dest=None):
self.callback_log.append(f"propose(step={state.step})")
return self.nmi.random_outcome()
def respond(self, state, source=None):
self.callback_log.append(f"respond(step={state.step})")
return ResponseType.REJECT_OFFER
# Run a negotiation and inspect the callback order
tracker = CallbackTracker()
mechanism = SAOMechanism(issues=[...], n_steps=3)
mechanism.add(tracker, ufun=...)
mechanism.add(other_negotiator, ufun=...)
mechanism.run()
# Output shows guaranteed order:
# ['on_preferences_changed([Initialization])',
# 'on_negotiation_start',
# 'on_round_start(step=0)',
# 'propose(step=0)',
# 'respond(step=0)',
# ...]
Native SAO Negotiators¶
These negotiators work with the Stacked Alternating Offers (SAO) mechanism, which is the most common bilateral negotiation protocol.
Base Classes¶
Class |
Description |
|---|---|
|
Base class for all SAO negotiators (alias for SAOPRNegotiator) |
|
Base SAO negotiator with propose/respond interface |
|
SAO negotiator using callback functions |
Time-Based Negotiators¶
Negotiators that concede over time according to various curves.
Class |
Description |
|---|---|
|
Base time-based strategy independent of received offers |
|
Time-based with configurable starting utility |
|
Alternative interface to time-based conceding |
|
Concedes sub-linearly (tough early, concedes late) |
|
Concedes linearly over time |
|
Concedes super-linearly (concedes early) |
|
Orients offers toward partner’s first offer |
|
Orients offers toward partner’s last offer |
|
Orients offers toward partner’s best offer |
|
Additive weighted sum for Pareto-following |
|
Multiplicative weighted selection |
|
Additive with last offer filter |
|
Multiplicative with last offer filter |
|
Additive with first offer filter |
|
Multiplicative with first offer filter |
Rational Concession Negotiators¶
Negotiators based on the MiCRO (Monotonic Concession with Rational Outcomes) protocol.
Class |
Description |
|---|---|
|
Rational concession negotiator - concedes one outcome at a time |
|
Faster version of MiCRO that may skip outcomes |
|
Conceding Accepting Better (optimal, complete) |
|
Conceding Accepting Rational |
|
Conceding Accepting Not Worse (optimal, complete) |
|
Wasting Accepting Better |
|
Wasting Accepting Any (equilibrium) |
|
Wasting Accepting Not Worse (equilibrium) |
Tit-for-Tat Negotiators¶
Class |
Description |
|---|---|
|
Naive tit-for-tat without opponent model |
|
Alias for NaiveTitForTatNegotiator |
Other Native Negotiators¶
Class |
Description |
|---|---|
|
Responds randomly in negotiation |
|
Random with always-accept option |
|
Offers and accepts anything |
|
Accepts and proposes only the best outcome |
|
Offers and accepts only top fraction of outcomes |
|
Uses a fixed set of outcomes |
|
Uses a fixed set of outcomes for acceptance only |
|
Base class for utility-based decisions |
|
Combines time-based and behavior-based strategies |
|
Negotiator with external control interface |
Native GB Negotiators¶
These negotiators work with the General Bargaining (GB) mechanisms, which support more complex multi-party and concurrent negotiations.
Class |
Description |
|---|---|
|
Base class for all GB negotiators |
GB negotiators share most implementations with SAO negotiators. The same negotiator types (time-based, MiCRO, tit-for-tat, etc.) are available with identical interfaces.
Python-Native Genius Negotiators¶
NegMAS provides Python-native implementations of classic Genius negotiation agents. These implementations use transcompiled Genius BOA (Bidding-Opponent modeling-Acceptance) components and do NOT require the Java Genius bridge.
The naming convention uses a G prefix to distinguish these from Java-bridge versions.
Note
These negotiators are fully implemented in Python and can be used without any external Java dependencies. They are recommended for most use cases where Genius-style strategies are needed.
Classic Time-Dependent Agents¶
Class |
Description |
|---|---|
|
Boulware strategy (e=0.2): concedes slowly, tough early |
|
Conceder strategy (e=2.0): concedes quickly early |
|
Linear strategy (e=1.0): constant concession rate |
|
Hardliner strategy (e=0): never concedes |
ANAC Competition Agents¶
Python-native implementations of notable ANAC competition agents.
Class |
Description |
|---|---|
|
ANAC 2011 Winner: Boulware offering with frequency-based opponent modeling |
|
ANAC 2010: Time-dependent with combined acceptance conditions |
|
ANAC 2010: Time-dependent with Smith-style frequency model |
|
ANAC 2010: Boulware with previous-offer acceptance |
|
ANAC 2010: Conceder with constant threshold acceptance |
|
ANAC 2012 Winner: Conservative time-dependent with frequency modeling |
|
ANAC 2012: Time-dependent with CombiMax acceptance |
|
ANAC 2015: Adaptive with window-based acceptance and exponential smoothing |
Utility Agents¶
Class |
Description |
|---|---|
|
Random offers with always-accept policy (baseline/testing) |
Genius Bridge Negotiators¶
NegMAS provides Python wrappers for 196 negotiation agents from the Genius negotiation platform. These agents participated in the Automated Negotiating Agents Competition (ANAC) from 2010-2019.
Note
Genius negotiators require the Genius bridge to be running. See Integrating with Genius for setup instructions.
Basic/Utility Agents (18)¶
Fundamental negotiation strategies and utility-based agents.
Class |
Description |
|---|---|
|
Boulware time-dependent strategy |
|
Conceder time-dependent strategy |
|
Hardliner time-dependent strategy |
|
Linear time-dependent strategy |
|
Boulware negotiation party |
|
Conceder negotiation party |
|
Random negotiation party |
|
Alternative random party |
|
Random counter-offer strategy |
|
Simple baseline agent |
|
Bayesian learning agent |
|
Similarity-based agent |
|
ABMP strategy agent |
|
Fuzzy logic agent |
|
Simple optimal bidding |
|
Functional acceptance strategy |
|
Immediate acceptance strategy |
|
Utility-based acceptance |
TU Delft Course Agents (23)¶
Agents developed in TU Delft negotiation courses.
AI2014Group2, Group1, Group3Q2015, Group4, Group5,
Group6, Group7, Group8, Group9, Group10, Group11,
Group12, Group13, Group14, Group15, Group16, Group17,
Group18, Group19, Group20, Group21, Group22, Q12015Group2
ANAC 2010 Agents (8)¶
Class |
Description |
|---|---|
|
ANAC 2010 winner |
|
ANAC 2010 finalist |
|
ANAC 2010 finalist |
|
Southampton’s IAM haggler |
|
Aggressive IAM variant |
|
FSEGA agent |
|
Agent Smith |
|
Southampton’s agent |
ANAC 2011 Agents (9)¶
Class |
Description |
|---|---|
|
ANAC 2011 winner |
|
ANAC 2011 finalist |
|
Updated IAM haggler |
|
Updated AgentK |
|
The Negotiator agent |
|
Nice tit-for-tat strategy |
|
Value model-based agent |
|
Bram agent |
|
Bram agent variant |
ANAC 2012 Agents (8)¶
Class |
Description |
|---|---|
|
ANAC 2012 winner (CUHK) |
|
ANAC 2012 finalist |
|
OMAC agent |
|
Updated Negotiator |
|
Agent MR |
|
Updated IAM haggler |
|
Meta-learning agent |
|
Updated meta agent |
ANAC 2013 Agents (8)¶
Class |
Description |
|---|---|
|
ANAC 2013 finalist |
|
Updated meta agent |
|
TMF agent |
|
Agent KF |
|
Inox agent |
|
Slava agent |
|
G agent |
|
Agent I |
ANAC 2014 Agents (20)¶
Class |
Description |
|---|---|
|
ANAC 2014 finalist |
|
DoNA agent |
|
Gangster agent |
|
Gangster variant |
|
Whale agent |
|
E2 agent |
|
Agent YK |
|
KG agent |
|
Brave Cat agent |
|
Atlas agent |
|
Agent Quest |
|
Agent TD |
|
Agent TRP |
|
ANAC sample agent |
|
Arisawa Yaki |
|
Aster agent |
|
Flinch agent |
|
Simpatico agent |
|
Sobut agent |
|
TU Delft Group 2 |
ANAC 2015 Agents (24)¶
Class |
Description |
|---|---|
|
ANAC 2015 winner |
|
ANAC 2015 finalist |
|
Random Dance agent |
|
Kawaii agent |
|
Agent X |
|
Phoenix Party |
|
Poker Face agent |
|
Updated CUHK agent |
|
Drage Knight |
|
Jonny Black |
|
Mean Bot |
|
Mercury agent |
|
P Negotiator |
|
Sengoku agent |
|
TUD Mixed Strategy |
|
Xian Fa agent |
|
Agent Buyog |
|
Agent H |
|
Agent HP |
|
Agent Neo |
|
Agent W |
|
Ares Party |
|
Group 2 |
|
2015 Group 2 |
ANAC 2016 Agents (17)¶
Class |
Description |
|---|---|
|
ANAC 2016 finalist |
|
YX agent |
|
Pars Cat agent |
|
Pars Cat variant |
|
Updated Atlas3 |
|
Ngent agent |
|
Updated Agent HP |
|
Agent Light |
|
Updated Agent Smith |
|
Clockwork agent |
|
Farma agent |
|
Grandma agent |
|
Max Oops |
|
My Agent |
|
Updated Pars Agent |
|
SY agent |
|
Terra agent |
ANAC 2017 Agents (19)¶
Class |
Description |
|---|---|
|
ANAC 2017 winner |
|
Caduceus DC16 |
|
Rubick agent |
|
Agent KN |
|
Farma 2017 |
|
Farma 2017 variant |
|
Gene King |
|
Gin agent |
|
Group 3 |
|
Imitator agent |
|
Mad Agent |
|
Mamenchis agent |
|
Mosa agent |
|
Updated Pars Agent |
|
Shah agent |
|
Simple Agent 2017 |
|
Taxi Box |
|
Tuc agent |
|
Agent F |
ANAC 2018 Agents (23)¶
Class |
Description |
|---|---|
|
ANAC 2018 finalist |
|
Meng Wan agent |
|
Yeela agent |
|
Sontag agent |
|
PonPoko Rampage |
|
Lancelot agent |
|
A-Team agent |
|
A-Team variant |
|
Beta One |
|
Beta One variant |
|
ConD agent |
|
Exp Rubick |
|
Full agent |
|
Group Y |
|
IQ Sun 2018 |
|
Libra agent |
|
Seto agent |
|
Shiboy agent |
|
SMAC agent |
|
Agent 33 |
|
Agent 36 |
|
Agent NP1 |
|
Agreeable Agent |
ANAC 2019 Agents (19)¶
Class |
Description |
|---|---|
|
ANAC 2019 finalist |
|
Kake Soba agent |
|
SAGA agent |
|
Winky agent |
|
Agent GP |
|
Agent Larry |
|
Dandik agent |
|
E agent |
|
FSEGA 2019 |
|
Garavel agent |
|
Gravity agent |
|
Group 1 BOA |
|
Hard Dealer |
|
K agent |
|
MINF agent |
|
Pod agent |
|
SACRA agent |
|
Solver agent |
|
The New Deal |
Usage Examples¶
Using Native Negotiators¶
from negmas.sao import SAOMechanism
from negmas.sao.negotiators import (
AspirationNegotiator,
BoulwareTBNegotiator,
MiCRONegotiator,
)
from negmas.preferences import LinearAdditiveUtilityFunction as U
from negmas.outcomes import make_issue
# Create a simple negotiation scenario
issues = [make_issue(10, "price"), make_issue(5, "quantity")]
# Create negotiators with utility functions
negotiator1 = AspirationNegotiator(name="buyer")
negotiator2 = BoulwareTBNegotiator(name="seller")
# Run negotiation
mechanism = SAOMechanism(issues=issues, n_steps=100)
mechanism.add(negotiator1, ufun=U.random(issues))
mechanism.add(negotiator2, ufun=U.random(issues))
mechanism.run()
Using Python-Native Genius Negotiators (Recommended)¶
These negotiators don’t require Java or the Genius bridge.
from negmas.genius import GHardHeaded, GCUHKAgent, GBoulware
from negmas.sao import SAOMechanism
from negmas.preferences import LinearAdditiveUtilityFunction as U
from negmas.outcomes import make_issue
# Create a simple negotiation scenario
issues = [make_issue(10, "price"), make_issue(5, "quantity")]
# Create Python-native Genius negotiators - NO bridge needed!
negotiator1 = GHardHeaded(name="hardheaded") # ANAC 2011 winner
negotiator2 = GCUHKAgent(name="cuhk") # ANAC 2012 winner
# Run negotiation
mechanism = SAOMechanism(issues=issues, n_steps=100)
mechanism.add(negotiator1, ufun=U.random(issues))
mechanism.add(negotiator2, ufun=U.random(issues))
mechanism.run()
Using Genius Bridge Negotiators¶
For access to all 196 Genius agents (requires Java).
from negmas.genius import GeniusBridge
from negmas.genius.gnegotiators import Atlas3, AgentK
from negmas.sao import SAOMechanism
# Start the Genius bridge (required)
GeniusBridge.start()
# Create Genius negotiators
negotiator1 = Atlas3()
negotiator2 = AgentK()
# Run negotiation (same as native negotiators)
mechanism = SAOMechanism(issues=issues, n_steps=100)
mechanism.add(negotiator1, ufun=ufun1)
mechanism.add(negotiator2, ufun=ufun2)
mechanism.run()
Creating Custom Negotiators¶
NegMAS offers two approaches to creating custom negotiators:
Inheritance: Subclass a base negotiator and override methods
Composition: Combine multiple negotiators using
SAOMetaNegotiator
Inheritance (Traditional Approach)¶
Subclass a base negotiator and implement the required methods:
from negmas.sao import SAOMechanism, SAONegotiator, ResponseType
from negmas.preferences import LinearAdditiveUtilityFunction as U
from negmas.outcomes import make_issue, make_os
class MyNegotiator(SAONegotiator):
"""A simple negotiator using inheritance."""
def propose(self, state, dest=None):
# Propose a random outcome
return self.nmi.random_outcome()
def respond(self, state, source=None):
offer = state.current_offer
# Accept any offer with utility > 0.8
if offer is not None and self.ufun(offer) > 0.8:
return ResponseType.ACCEPT_OFFER
return ResponseType.REJECT_OFFER
# Use the custom negotiator
issues = [make_issue(10, "price"), make_issue(5, "quantity")]
os = make_os(issues)
session = SAOMechanism(issues=issues, n_steps=100)
session.add(MyNegotiator(name="custom"), ufun=U.random(os, reserved_value=0.0))
session.add(MyNegotiator(name="opponent"), ufun=U.random(os, reserved_value=0.0))
session.run()
Composition (Ensemble Approach)¶
Use SAOMetaNegotiator to combine multiple negotiators and aggregate their decisions.
This is useful for ensemble strategies, voting mechanisms, or dynamic strategy switching.
from negmas.sao import SAOMechanism, ResponseType
from negmas.sao.negotiators import (
SAOMetaNegotiator,
BoulwareTBNegotiator,
NaiveTitForTatNegotiator,
AspirationNegotiator,
)
from negmas.preferences import LinearAdditiveUtilityFunction as U
from negmas.outcomes import make_issue, make_os
class MajorityVoteNegotiator(SAOMetaNegotiator):
"""An ensemble negotiator that uses majority voting."""
def aggregate_proposals(self, state, proposals, dest=None):
# Use the proposal from the first negotiator that offers something
for neg, proposal in proposals:
if proposal is not None:
return proposal
return None
def aggregate_responses(self, state, responses, offer, source=None):
# Majority vote: accept if more than half accept
accept_count = sum(1 for _, r in responses if r == ResponseType.ACCEPT_OFFER)
if accept_count > len(responses) / 2:
return ResponseType.ACCEPT_OFFER
return ResponseType.REJECT_OFFER
# Create an ensemble of different strategies
issues = [make_issue(10, "price"), make_issue(5, "quantity")]
os = make_os(issues)
ufun = U.random(os, reserved_value=0.0)
ensemble = MajorityVoteNegotiator(
negotiators=[
BoulwareTBNegotiator(), # Tough strategy
NaiveTitForTatNegotiator(), # Reactive strategy
BoulwareTBNegotiator(), # Another tough vote
],
name="ensemble",
)
# Use in a negotiation
session = SAOMechanism(issues=issues, n_steps=100)
session.add(ensemble, ufun=ufun)
session.add(
AspirationNegotiator(name="opponent"), ufun=U.random(os, reserved_value=0.0)
)
session.run()
The ensemble approach is useful for:
Voting strategies: Combine multiple negotiators via majority/weighted voting
Dynamic delegation: Switch between strategies at runtime
A/B testing: Compare strategies within the same negotiation
Note
GBMetaNegotiator is also available for GB (General Bargaining) protocols
with additional callbacks for partner events.
Composition (BOA Components)¶
Use BOANegotiator to build negotiators from reusable components following
the Bidding-Opponent modeling-Acceptance (BOA) pattern:
from negmas.gb.negotiators.modular import BOANegotiator
from negmas.gb.components import (
GSmithFrequencyModel, # Opponent modeling
GACTime, # Acceptance strategy
GTimeDependentOffering, # Offering strategy
)
# Create a BOA negotiator with Genius-style components
negotiator = BOANegotiator(
offering=GTimeDependentOffering(e=0.2), # Boulware-style offering
acceptance=GACTime(t=0.95), # Accept after 95% of time
model=GSmithFrequencyModel(), # Opponent frequency model
name="my_boa_agent",
)
The BOA approach is useful for:
Mix-and-match: Combine different strategies from the Genius library
Research: Easily swap components to compare different strategies
Extensibility: Create custom components that integrate with existing ones
See Also¶
Running a Negotiation - Basic negotiation tutorial
Integrating with Genius - Genius integration guide
Develop a new negotiator - Creating custom negotiators
Negotiation Components - Negotiation components (acceptance, offering strategies)
negmas.sao - SAO mechanism API reference
negmas.gb - GB mechanism API reference