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 '@crux/ai'
import { agent } from '@crux/core/agent'

const decision = await consensus({
  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 '@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({
  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