Skip to content

v0.11.0 — Multi-agent debate

Choose a tag to compare

@timmcleod timmcleod released this 30 Jul 23:35

Feature release: durable multi-agent debate. No schema changes, no migration.

Added

  • debate() — two or more debater agents argue a topic in rounds (openings, then rebuttals) while a structured-output judge rules on the transcript after each round; the loop stops on judge.consensus === true (or a custom until: predicate) or at the rounds cap, which is an outcome (satisfied: false), not a failure. Compiles to evaluate() + a package-shipped callback body, so each round is one checkpoint and one audit row, drift hashing and the dashboard treat it as machinery they already know, and the graph stays static. as: is required. Costs grow quadratically with rounds; transcriptWindow: bounds the debaters' prompts to the last N rounds (the judge always sees the full transcript). Full guide: docs/agent-debate.md.
  • Support\Transcript — a JSON-safe view over steps.{id}.transcript (append(), entries(), bySpeaker(), round(), render(lastRounds:)).
  • AgentStepResult::sum() — key-wise usage aggregation for multi-call step bodies.
  • Callback steps now receive their StepDefinition as a second argument and may return a StepResult to report token usage on the audit row.

Guard rails, priced in tokens

  • A judge whose verdict lacks a consensus boolean fails the debate loudly after one round under the default predicate; with a custom until: the check is waived. Debater count/type, duplicate speaker names, rounds, and transcriptWindow are validated at definition time.
  • A debater (or judge) pausing on SDK tool approvals mid-round fails the round loudly naming the participant — per-speaker decision replay doesn't exist yet. Move approval-gated tools outside the debate.
  • The shipped protocol prompts are versioned into the definition hash (DebateRoundStep::PROTOCOL_VERSION), so a package upgrade that changes them refuses to resume an in-flight debate under strict drift mode.

Compatibility note on the callback signature: every single-parameter callback (__invoke(WorkflowState $state)) keeps working unchanged. A callback that declares an optional second parameter of another type (__invoke(WorkflowState $state, ?Foo $extra = null)) now receives the StepDefinition there and will TypeError; rename or retype that parameter.

Pair with agent-workflows-ui v0.4.0 for debate round-progress in the dashboard.