Duck Council
duck_councilSubmit a question to a council of AI ducks and receive multiple perspectives for debugging or problem-solving.
Instructions
Get responses from all configured ducks (like a panel discussion)
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | The question for the duck council | |
| model | No | Specific model to use for all ducks (optional) | |
| images | No | Optional images to include with the prompt (for vision-capable models) |
Implementation Reference
- src/tools/duck-council.ts:7-107 (handler)Main handler for the duck_council tool. Gathers responses from all configured providers (ducks), formats them into a panel discussion, and returns the result. Uses duckCouncil() or compareDucksWithProgress() depending on whether a ProgressReporter is provided.
export async function duckCouncilTool( providerManager: ProviderManager, args: Record<string, unknown>, progress?: ProgressReporter ) { const { prompt, model, images } = args as { prompt?: string; model?: string; images?: ImageInput[]; }; if (!prompt) { throw new Error('Prompt is required for the duck council'); } logger.info('Convening the duck council...'); // Get all available ducks const allProviders = providerManager.getProviderNames(); if (allProviders.length === 0) { throw new Error('No ducks available for the council!'); } const content = buildContent(prompt, images); // Get responses from all ducks, reporting progress as each completes const responses = progress ? await providerManager.compareDucksWithProgress( content, undefined, { model }, (providerName, completed, total) => { void progress.report( completed, total, `${providerName} responded (${completed}/${total})` ); } ) : await providerManager.duckCouncil(content, { model }); // Build council response with a panel discussion format let response = `${duckArt.panel}\n\n`; response += `ποΈ **Duck Council Topic:** "${prompt}"\n`; response += `π₯ **${allProviders.length} ducks in attendance**\n\n`; response += `βββββββββββββββββββββββββββββββββββββββ\n\n`; // Present each duck's perspective for (let i = 0; i < responses.length; i++) { const duckResponse = responses[i]; const duckNumber = i + 1; response += `**Duck #${duckNumber}: ${duckResponse.nickname}**\n`; response += `βββββββββββββββββββββββββββββββββββββ\n`; if (duckResponse.content.startsWith('Error:')) { response += `π¦π¬ *[Duck had to leave early: ${duckResponse.content}]*\n`; } else { response += `π¦π¬ "${duckResponse.content}"\n`; // Add metadata in a subtle way response += `\n`; response += `*[${duckResponse.model}`; if (duckResponse.latency > 0) { response += ` β’ ${duckResponse.latency}ms`; } if (duckResponse.usage) { response += ` β’ ${duckResponse.usage.total_tokens} tokens`; } response += `]*\n`; } response += `\n`; } // Add council summary const successCount = responses.filter((r) => !r.content.startsWith('Error:')).length; response += `βββββββββββββββββββββββββββββββββββββββ\n`; response += `ποΈ **Council Summary**\n`; response += `β’ ${successCount}/${responses.length} ducks provided their wisdom\n`; if (successCount === responses.length) { response += `β’ ${getRandomDuckMessage('success')}\n`; } else if (successCount > 0) { response += `β’ Partial council - some ducks were unavailable\n`; } else { response += `β’ ${getRandomDuckMessage('error')}\n`; } logger.info(`Duck council completed: ${successCount}/${responses.length} responses`); return { content: [ { type: 'text', text: response, }, ], }; } - src/server.ts:1123-1165 (handler)Alternative handler when MCP is enabled. Calls enhancedProviderManager.duckCouncilWithMCP() or compareDucksWithProgressMCP() and formats results with header using formatEnhancedDuckResponse().
private async handleDuckCouncilWithMCP( args: Record<string, unknown>, progress?: import('./services/progress.js').ProgressReporter ) { if (!this.enhancedProviderManager) { throw new Error('Enhanced provider manager not available'); } const { prompt, model, images } = args as { prompt: string; model?: string; images?: ImageInput[]; }; const content = buildContent(prompt, images); const responses = progress ? await this.enhancedProviderManager.compareDucksWithProgressMCP( content, undefined, { model }, (providerName, completed, total) => { void progress.report( completed, total, `${providerName} responded (${completed}/${total})` ); } ) : await this.enhancedProviderManager.duckCouncilWithMCP(content, { model }); const header = 'π¦ Duck Council in Session π¦\n============================='; const formattedResponse = responses .map((response) => this.formatEnhancedDuckResponse(response)) .join('\n\nβββββββββββββββββββββββββββββββββββββββ\n\n'); return { content: [ { type: 'text' as const, text: `${header}\n\n${formattedResponse}`, }, ], }; - src/server.ts:471-488 (schema)Registration of duck_council tool with its input schema (prompt, optional model, optional images array with ImageInputSchema). Registered via this.server.registerTool().
this.server.registerTool( 'duck_council', { title: 'Duck Council', description: 'Get responses from all configured ducks (like a panel discussion)', inputSchema: { prompt: z.string().describe('The question for the duck council'), model: z.string().optional().describe('Specific model to use for all ducks (optional)'), images: z .array(ImageInputSchema) .optional() .describe('Optional images to include with the prompt (for vision-capable models)'), }, annotations: { readOnlyHint: true, openWorldHint: true, }, }, - src/server.ts:470-507 (registration)Registration block for duck_council tool. Dispatches to either handleDuckCouncilWithMCP() or duckCouncilTool() depending on whether MCP is enabled.
// duck_council this.server.registerTool( 'duck_council', { title: 'Duck Council', description: 'Get responses from all configured ducks (like a panel discussion)', inputSchema: { prompt: z.string().describe('The question for the duck council'), model: z.string().optional().describe('Specific model to use for all ducks (optional)'), images: z .array(ImageInputSchema) .optional() .describe('Optional images to include with the prompt (for vision-capable models)'), }, annotations: { readOnlyHint: true, openWorldHint: true, }, }, async (args, extra) => { try { const progress = createProgressReporter( extra._meta?.progressToken, extra.sendNotification ); if (this.mcpEnabled && this.enhancedProviderManager) { return this.toolResult( await this.handleDuckCouncilWithMCP(args as Record<string, unknown>, progress) ); } return this.toolResult( await duckCouncilTool(this.providerManager, args as Record<string, unknown>, progress) ); } catch (error) { return this.toolErrorResult(error); } } ); - src/providers/manager.ts:250-255 (helper)Base duckCouncil() method in ProviderManager - delegates to compareDucks() which queries all providers in parallel.
async duckCouncil( prompt: MessageContent, options?: Partial<ChatOptions> ): Promise<DuckResponse[]> { return this.compareDucks(prompt, undefined, options); }