Crux
GuidesCompositions

Consensus

Run multiple agents and determine a winner via voting with configurable quorum.

consensus() runs multiple agents (or the same agent multiple times) in parallel and picks a winner via voting. Use it when you need reliable classification, grading, or any decision where multiple opinions reduce error.

classify-ticket.ts
import { consensus } from "@use-crux/ai";
import { agent } from "@use-crux/core/agent";

const decision = await consensus({
  id: "consensus-consensus-1",
  agents: [classifier, classifier, classifier],
  context: { ticket: supportTicket },
  extract: (result) => result.output.category,
  quorum: "majority",
});

decision.result; // 'billing' (winning category)
decision.votes; // { billing: 2, shipping: 1 }
decision.agreement; // 0.67
decision.details; // all 3 agent results

How it works

  1. All agents run in parallel (built on top of parallel() internally)
  2. extract() pulls a vote string from each agent's result
  3. Votes are counted, the most frequent value wins
  4. Quorum is validated, if not met, ConsensusError is thrown
  5. Returns the winning value, vote breakdown, all results, and agreement ratio

The extract function

extract() receives each agent's AgentResult and returns a string that represents the vote:

// Extract the category field from structured output
extract: (result) => result.output.category;

// Extract from nested data
extract: (result) => result.output.sentiment.label;

// Custom logic
extract: (result) => (result.output.score > 0.8 ? "pass" : "fail");

Quorum options

ValueBehavior
'majority' (default)Winner must have > 50% of votes
'unanimous'All agents must agree (100%)
numberWinner must have at least this many votes
// Require all 3 agents to agree
await consensus({ ..., quorum: 'unanimous' })

// Require at least 2 votes
await consensus({ ..., quorum: 2 })

When quorum is not met, a ConsensusError is thrown with the vote breakdown:

import { ConsensusError } from '@use-crux/core/agent'

try {
  await consensus({ ..., quorum: 'unanimous' })
} catch (err) {
  if (err instanceof ConsensusError) {
    console.log(err.votes)   // { billing: 2, shipping: 1 }
    console.log(err.quorum)  // 'unanimous'
  }
}

Tie-breaking

When multiple values have the same count, the first encountered value wins. For deterministic tie-breaking, use a custom extract() that normalizes values.

Different agents as voters

You can use different agents (not just the same one repeated) for diverse perspectives:

const decision = await consensus({
  id: "consensus-consensus-2",
  agents: [conservativeClassifier, aggressiveClassifier, balancedClassifier],
  context: { ticket: supportTicket },
  extract: (result) => result.output.category,
});

Devtools

In the devtools timeline, consensus compositions show the agreement ratio:

comp  → consensus  3 agents
comp  ← classifier  0.9s
comp  ← classifier  1.1s
comp  ← classifier  0.8s
comp  ← consensus  3/3 ok  1.1s  67% agree

On this page