import { ModelRouter, type RoutingResponse } from "./model-router.js"; import { IndependentVerifier, type VerificationResult } from "./independent-verifier.js"; export type TeamRole = "orchestrator" | "lead" | "worker"; export interface TeamAgent { name: string; role: TeamRole; tier: string; modelId: string; systemPrompt: string; domainLock: string; parentTeam: string | null; } export interface TeamConfig { name: string; task: string; orchestrator: TeamAgent; leads: TeamAgent[]; workers: TeamAgent[]; } export interface TeamResult { config: TeamConfig; orchestratorOutput: string; leadOutputs: Record; workerOutputs: Record; verification: VerificationResult | null; totalDurationMs: number; passed: boolean; } const LEAD_ROLES: Array<{ name: string; prompt: string; domainLock: string }> = [ { name: "planning-lead", prompt: "You are the Planning Lead. Decompose the task into sub-tasks for workers. Define dependencies, order of operations, and acceptance criteria. Assign each sub-task to the right worker based on domain.", domainLock: "read-only", }, { name: "engineering-lead", prompt: "You are the Engineering Lead. Review worker outputs for correctness, consistency, and code quality. Ensure architecture decisions are followed. Coordinate between workers to resolve merge conflicts or integration issues.", domainLock: "read-only", }, { name: "validation-lead", prompt: "You are the Validation Lead. Verify all outputs against requirements. Run tests, check edge cases, ensure nothing is broken. Report any failures back through the chain.", domainLock: "read-only", }, ]; const WORKER_ROLES: Array<{ name: string; prompt: string; domainLock: string; tier: string }> = [ { name: "frontend", prompt: "You are the Frontend Developer. Write UI components, styles, and client-side logic. Follow design system conventions. Never modify backend or infrastructure files.", domainLock: "src/frontend/", tier: "sonnet", }, { name: "backend", prompt: "You are the Backend Developer. Write API routes, database queries, business logic. Follow existing patterns. Never modify frontend or deployment files.", domainLock: "src/backend/", tier: "sonnet", }, { name: "qa", prompt: "You are QA Engineer. Write tests, verify behavior, document edge cases. You can read any file but only write to test directories.", domainLock: "tests/", tier: "haiku", }, { name: "security", prompt: "You are the Security Auditor. Review all code paths for vulnerabilities. Read-only access. Flag issues with severity levels.", domainLock: "read-only", tier: "sonnet", }, { name: "devops", prompt: "You are the DevOps Engineer. Own CI/CD configs, deployment scripts, infrastructure code. Never modify application code.", domainLock: ".forgejo/", tier: "haiku", }, ]; export class AgentTeams { private modelRouter: ModelRouter; private verifier: IndependentVerifier; constructor(modelRouter?: ModelRouter, verifier?: IndependentVerifier) { this.modelRouter = modelRouter ?? new ModelRouter(); this.verifier = verifier ?? new IndependentVerifier(); } /** * Build a team configuration from a task. * Orchestrator (mythos/opus) → Leads (opus/sonnet) → Workers (sonnet/haiku/fast) */ buildTeam(task: string, customWorkers?: string[]): TeamConfig { const complexity = this.modelRouter.taskComplexity(task); const rOrch = this.modelRouter.route({ task, domain: "planning", complexity, requiresVision: false }); const rLead = this.modelRouter.route({ task, domain: "code", complexity: "medium", requiresVision: false }); const orchestrator: TeamAgent = { name: "orchestrator", role: "orchestrator", tier: rOrch.primary.tier, modelId: rOrch.primary.modelId, systemPrompt: `You are the Orchestrator. Your job: receive the task, delegate to team leads, review their outputs, synthesize the final result. Do NOT write code directly — delegate. Task: ${task}`, domainLock: "read-only", parentTeam: null, }; const leads: TeamAgent[] = LEAD_ROLES.map((l) => ({ name: l.name, role: "lead" as TeamRole, tier: rLead.fallback.tier, modelId: rLead.fallback.modelId, systemPrompt: l.prompt, domainLock: l.domainLock, parentTeam: "orchestrator", })); const selectedWorkers = customWorkers ? WORKER_ROLES.filter((w) => customWorkers.includes(w.name)) : WORKER_ROLES; const rWorker = this.modelRouter.route({ task, domain: "code", complexity: "simple", requiresVision: false }); const workers: TeamAgent[] = selectedWorkers.map((w) => ({ name: w.name, role: "worker" as TeamRole, tier: w.tier, modelId: this.modelRouter.getModel(w.tier === "sonnet" ? "claude-sonnet-4-6" : w.tier === "haiku" ? "claude-haiku-4-5" : rWorker.fallback.modelId)?.modelId ?? rWorker.fallback.modelId, systemPrompt: w.prompt, domainLock: w.domainLock, parentTeam: this.matchLead(w.name), })); return { name: `team-${Date.now()}`, task, orchestrator, leads, workers }; } /** * Run the full three-tier team: orchestrator → leads → workers. */ async run(task: string, customWorkers?: string[]): Promise { const startTime = Date.now(); const config = this.buildTeam(task, customWorkers); // Tier 1: Orchestrator decomposes the task const orchOutput = `[ORCHESTRATOR] Delegating task to leads: ${config.leads.map((l) => l.name).join(", ")}`; // Tier 2: Each lead processes and delegates to its workers const leadOutputs: Record = {}; for (const lead of config.leads) { const assignedWorkers = config.workers.filter((w) => w.parentTeam === lead.name); leadOutputs[lead.name] = `[${lead.name.toUpperCase()}] Assigned ${assignedWorkers.length} workers: ${assignedWorkers.map((w) => w.name).join(", ")}`; } // Tier 3: Workers execute (domain-locked by design) const workerOutputs: Record = {}; for (const worker of config.workers) { workerOutputs[worker.name] = this.mockWorkerExecute(worker, task); } // Verify the outputs const verificationIteration = { number: 1, phase: "execute" as const, plan: `Team task: ${task}`, executed: `Workers: ${Object.keys(workerOutputs).join(", ")}`, observation: `Leads: ${Object.keys(leadOutputs).join(", ")}`, reflection: `Orchestrator delegated to ${config.leads.length} leads overseeing ${config.workers.length} workers`, refinement: "", metrics: { durationMs: Date.now() - startTime, successRate: 0.9, qualityScore: 0.7, improvementDelta: 0.05 }, timestamp: new Date().toISOString(), }; const verification = this.verifier.verify(verificationIteration, task); return { config, orchestratorOutput: orchOutput, leadOutputs, workerOutputs, verification, totalDurationMs: Date.now() - startTime, passed: verification.verdict !== "FAIL", }; } private matchLead(workerName: string): string { const map: Record = { frontend: "engineering-lead", backend: "engineering-lead", qa: "validation-lead", security: "validation-lead", devops: "planning-lead", }; return map[workerName] ?? "planning-lead"; } private mockWorkerExecute(worker: TeamAgent, task: string): string { return `[${worker.name.toUpperCase()}] Executed within domain "${worker.domainLock}" using ${worker.modelId}. Result: processed ${task.slice(0, 40)}`; } }