v0.11.0 — Multi-agent debate
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 onjudge.consensus === true(or a customuntil:predicate) or at theroundscap, which is an outcome (satisfied: false), not a failure. Compiles toevaluate()+ 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 withrounds;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 oversteps.{id}.transcript(append(),entries(),bySpeaker(),round(),render(lastRounds:)).AgentStepResult::sum()— key-wise usage aggregation for multi-call step bodies.- Callback steps now receive their
StepDefinitionas a second argument and may return aStepResultto report token usage on the audit row.
Guard rails, priced in tokens
- A judge whose verdict lacks a
consensusboolean fails the debate loudly after one round under the default predicate; with a customuntil:the check is waived. Debater count/type, duplicate speaker names,rounds, andtranscriptWindoware 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.