// Supervisor agent: routes user requests to the best agent via a cheap LLM // classification call. Activated when session.agent_id === 'supervisor'. import type { Agent } from '../../types/api.js'; import { taskModelCompletion } from '../task-model.js'; export interface SupervisorRoute { agent_id: string; confidence: number; reasoning: string; } const SUPERVISOR_SYSTEM_PROMPT = `You are a router. Given the user's request and the available agents, choose the best agent to handle the request. Rules: - Match the request to the agent whose description and toolset best fits the task. - For code review / bug finding requests → code-reviewer - For debugging / diagnosing failures → debugger - For refactoring / simplifying code → refactorer - For architecture / design / planning → architect or planner - For security audits → security-auditor - For building prompts for other agents → prompt-builder - For exploring / understanding unfamiliar code → recon - For implementing / writing code changes → builder - Respond with ONLY the agent id (e.g. "builder") or "none" if no agent fits. - Do not include any other text, punctuation, or explanation.`; const MAX_ROUTING_TOKENS = 30; /** * Given the user's latest message and available agents, classifies which agent * should handle this turn. Returns null to fall through to default (no agent). */ export async function resolveSupervisorTurn( latestUserMessage: string, agents: Agent[], fallbackModel?: string, ): Promise { // Build agent listing — skip the supervisor itself to avoid self-routing. const agentList = agents .filter((a) => a.id !== 'supervisor') .map((a) => `- ${a.id}: ${a.description} (${a.tools.length} tools)`) .join('\n'); if (!agentList) { return null; } const userPrompt = `Available agents:\n${agentList}\n\nUser request: ${latestUserMessage.slice(0, 2000)}`; const response = await taskModelCompletion({ system: SUPERVISOR_SYSTEM_PROMPT, user: userPrompt, maxTokens: MAX_ROUTING_TOKENS, temperature: 0.1, fallbackModel, }); const agentId = response.trim().toLowerCase(); if (!agentId || agentId === 'none') { return null; } // Map back to a real agent to validate the id. const matched = agents.find((a) => a.id === agentId); if (!matched) { return null; } return { agent_id: matched.id, confidence: 1, reasoning: `supervisor routed to "${matched.name}" based on request classification`, }; }