consensus
Poll 3-7 models and aggregate responses using majority, supermajority, or unanimous voting. Returns consensus answer with confidence score.
Instructions
Query 3-7 models and aggregate responses using voting strategy (majority/supermajority/unanimous). Returns consensus answer with confidence score.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| models | Yes | List of model IDs to poll (3-7 models) | |
| prompt | Yes | The prompt to send to all models | |
| strategy | No | Voting strategy — how many models must agree | majority |
| judge_model | No | Optional model ID to use as judge. Auto-picks if not specified. | |
| system_prompt | No | ||
| temperature | No | ||
| max_tokens | No |
Implementation Reference
- src/server.ts:144-165 (registration)Registration of the 'consensus' tool with the MCP server, including its description, schema, and handler binding.
// --- consensus --- server.tool( "consensus", "Query 3-7 models and aggregate responses using voting strategy (majority/supermajority/unanimous). Returns consensus answer with confidence score.", consensusSchema.shape, async (input) => { logger.info( `consensus: polling ${input.models.length} models (${input.strategy})` ); try { const result = await consensus(provider, input); return { content: [{ type: "text" as const, text: result }] }; } catch (err) { const message = err instanceof Error ? err.message : String(err); logger.error(`consensus failed: ${message}`); return { content: [{ type: "text" as const, text: `Error: ${message}` }], isError: true, }; } } ); - src/tools/consensus.ts:53-130 (handler)Main handler function 'consensus' that polls multiple models, determines agreement via a judge model (or keyword fallback), and returns a consensus result.
export async function consensus( provider: Provider, input: ConsensusInput ): Promise<string> { // Query all models in parallel const results = await Promise.allSettled( input.models.map((model) => provider.query(model, input.prompt, { system_prompt: input.system_prompt, temperature: input.temperature, max_tokens: input.max_tokens, }) ) ); const votes: ModelVote[] = results.map((result, i) => { if (result.status === "fulfilled") { return { model: input.models[i], content: result.value.content }; } return { model: input.models[i], content: "", error: result.reason instanceof Error ? result.reason.message : String(result.reason), }; }); const successful = votes.filter((v) => !v.error); const failed = votes.filter((v) => v.error); if (successful.length < 2) { return `## Consensus Failed\n\nOnly ${successful.length} model(s) responded. Need at least 2 for consensus.\n\nErrors:\n${failed.map((f) => `- ${f.model}: ${f.error}`).join("\n")}`; } const threshold = getThreshold(input.strategy ?? "majority"); const requiredVotes = Math.ceil(successful.length * threshold); // Use a judge model to determine agreement const judgeModel = input.judge_model ?? await pickJudge(provider, input.models); let agreeing: ModelVote[]; let dissenting: ModelVote[]; let judgeLatency: number | undefined; if (judgeModel) { logger.info(`consensus: using ${judgeModel} as judge`); const judgeStart = Date.now(); const judgeResult = await judgeAgreement(provider, judgeModel, successful); judgeLatency = Date.now() - judgeStart; if (judgeResult) { agreeing = judgeResult.agreeing; dissenting = judgeResult.dissenting; } else { // Judge failed, fall back to keyword matching logger.warn("consensus: judge failed, falling back to keyword matching"); ({ agreeing, dissenting } = keywordFallback(successful)); } } else { logger.warn("consensus: no judge available, using keyword matching"); ({ agreeing, dissenting } = keywordFallback(successful)); } const reached = agreeing.length >= requiredVotes; return formatConsensus({ reached, strategy: input.strategy ?? "majority", agreeing, dissenting, failed, requiredVotes, totalVoters: successful.length, judgeModel, judgeLatency, }); } - src/tools/consensus.ts:27-43 (schema)Zod schema 'consensusSchema' defining the tool's input: models array (3-7), prompt, strategy (majority/supermajority/unanimous), judge_model, system_prompt, temperature, and max_tokens.
export const consensusSchema = z.object({ models: z .array(z.string()) .min(3) .max(7) .describe("List of model IDs to poll (3-7 models)"), prompt: z.string().describe("The prompt to send to all models"), strategy: z .enum(["majority", "supermajority", "unanimous"]) .optional() .default("majority") .describe("Voting strategy — how many models must agree"), judge_model: z.string().optional().describe("Optional model ID to use as judge. Auto-picks if not specified."), system_prompt: z.string().optional(), temperature: z.number().min(0).max(2).optional().default(0), max_tokens: z.number().int().positive().optional().default(1024), }); - src/tools/consensus.ts:132-141 (helper)Helper function 'getThreshold' that maps strategy names to numeric thresholds (0.5, 0.66, 1.0).
function getThreshold(strategy: "majority" | "supermajority" | "unanimous"): number { switch (strategy) { case "majority": return 0.5; case "supermajority": return 0.66; case "unanimous": return 1.0; } } - src/tools/consensus.ts:289-343 (helper)Helper function 'formatConsensus' that formats the consensus result into a markdown string with agreement stats, individual responses, and dissenting views.
function formatConsensus(result: ConsensusResult): string { const confidence = Math.round( (result.agreeing.length / result.totalVoters) * 100 ); const lines: string[] = [ `## Consensus: ${result.reached ? "REACHED" : "NOT REACHED"}`, "", `**Strategy:** ${result.strategy} (needed ${result.requiredVotes}/${result.totalVoters})`, `**Agreement:** ${result.agreeing.length}/${result.totalVoters} models (${confidence}%)`, result.judgeModel ? `**Judge:** ${result.judgeModel}${result.judgeLatency ? ` (${result.judgeLatency}ms)` : ""}` : "", "", ]; // Show the consensus answer (first agreeing model's response) if (result.agreeing.length > 0) { lines.push("### Consensus Response"); lines.push(""); lines.push(result.agreeing[0].content); lines.push(""); lines.push( `*Agreed by: ${result.agreeing.map((v) => v.model).join(", ")}*` ); lines.push(""); } // Show what each model actually said so the judge can be sanity-checked const allVotes = [...result.agreeing, ...result.dissenting]; if (allVotes.length > 1) { lines.push("### Individual Responses"); for (const v of allVotes) { const summary = v.content.slice(0, 150).replace(/\n/g, " "); lines.push(`- **${v.model}:** ${summary}${v.content.length > 150 ? "..." : ""}`); } lines.push(""); } // Show dissent if (result.dissenting.length > 0) { lines.push("### Dissenting Views"); for (const d of result.dissenting) { lines.push(`- **${d.model}:** ${d.content.slice(0, 200)}${d.content.length > 200 ? "..." : ""}`); } lines.push(""); } // Show failures if (result.failed.length > 0) { lines.push(`*${result.failed.length} model(s) failed to respond*`); } return lines.join("\n"); }