Vote for your favorite SkillMD. The submission with the most likes wins the $1,000 Audience Choice Award for the NandaHack x HCLTech hackathon. Voting is open through September 25.Vote now →
in reviewhumanPR #157Negotiation

adarx: tiered-discount negotiation plugin with strategic bargaining

A third plugin for the Negotiation layer — adarx — alongside the existing alternating_offers (Rubinstein patience-discount) and pareto (utility-based trade-off) reference implementations.

Author

merry-tresata avatar

@merry-tresata

github profile →
Status
In review
Opened on
Jul 10
Branch
hackathon/adarx-negotiation-plugin

Description

The pitch.

## What this adds

A third plugin for the Negotiation layer — adarx — alongside the existing alternating_offers (Rubinstein patience-discount) and pareto (utility-based trade-off) reference implementations.

The existing two plugins are general-purpose bargaining models, designed to work for any negotiable good regardless of domain — that generality is their strength, and it's exactly what makes them good defaults for the simulator. adarx takes a complementary approach: instead of a domain-agnostic model, it ports real, independently-tested procurement business logic from a working system (an autonomous procurement agent). The goal isn't to replace the general-purpose plugins, but to give the layer a concrete example of what a domain-specific negotiation protocol looks like in practice, and to test whether the simulator handles that kind of plugin as well as it handles the mathematical ones.

## Why this is a useful addition

The existing plugins are well-suited to testing whether a general bargaining protocol converges mathematically. This plugin gives the same test rig something complementary to work with: a negotiation protocol built around real business rules — volume discounts, strategic posture, compliance gating — so we can see how it holds up under Nanda Town's adversarial simulation conditions (message drops, Byzantine agents, scale).

Concretely, adarx demonstrates a different style of negotiation logic than the layer currently has an example of:

- Tiered volume discounts — larger orders unlock better pricing in real percentage steps (5% at 500+ units, 8% at 1000+, 12% at 5000+), a business rule rather than a continuous mathematical decay curve.
- Strategic posture — an agent can negotiate aggressive (bigger discount, slower delivery/payment), defensive (smaller discount, faster delivery, longer warranty), or balanced, changing the shape of the deal, not just the price.
- A hard compliance gate — a counterparty flagged as non-compliant is rejected immediately at open(), before any bargaining round is spent — modeling a real-world constraint (you don't negotiate price with a supplier that hasn't passed compliance) that's naturally out of scope for a general-purpose bargaining model.

## How business context reaches the plugin

Terms.metadata (a free-form dict on the SDK's Terms type) carries quantity, strategy, and compliance_status, seeded by the initiating agent at open(). The negotiated price target is computed once, from the fixed opening price (session.history[0]), and held constant — later rounds compare whatever's currently on the table against that fixed target, rather than recomputing a moving target every round.

## Update — addressing review feedback

Following review, this PR now also includes:

- Discriminator scenario — a new adarx_compliance_gate scenario (scenarios/adarx_compliance_gate.yaml, factory in nest_core/scenarios_builtin/adarx_compliance_gate.py, validators in nest_core/validators.py) runs 10 buyer/seller pairs, half against an APPROVED counterparty and half against PENDING_REVIEW. ADARXNegotiation rejects the non-compliant half at open(), before any price is exchanged; alternating_offers has no compliance concept and reaches agreement with them anyway. Swapping negotiation: adarx → negotiation: alternating_offers in the YAML flips validate_adarx_compliance_gate from PASS to FAIL — verified locally both ways.
- Deterministic session ids — adarx.py no longer uses uuid.uuid4(); session ids are now derived as f"adarx-{agent_id}-{counter}" from a per-instance counter, matching the pattern already used in pareto.py.
- File placement — the scenario config that was at repo root (marketplace.yaml) has moved into scenarios/ (renamed adarx_marketplace.yaml, since scenarios/marketplace.yaml already exists), and report-adarx.html has been removed from the repo.

## Testing

Unit + property tests (test_adarx_negotiation.py, 16/16 passing):
- Exact discount-tier boundaries

…

Try it

Open PR on GitHubView diff

Checkout locally

git fetch origin pull/157/head:pr-157
git checkout pr-157