/** * TeamLead — Manages a group of SMEs for a specific domain. * * Receives tasks from the Orchestrator, decomposes them, * assigns to SMEs, and aggregates results. */ import type { AgentId, Task, TaskMessage, TaskResult, TaskType, SpeckDefinition, ProvenanceEdge, } from "./types.js"; import { SME } from "./sme.js"; import { TillDoneTracker } from "./till-done.js"; import { ProvenanceGraphImpl } from "./provenance.js"; export class TeamLead { readonly id: AgentId; private smes: SME[] = []; protected provenance: ProvenanceGraphImpl; protected tillDone: TillDoneTracker; constructor(name: string, specialization: string) { this.id = { type: "team_lead", name, specialization }; this.provenance = new ProvenanceGraphImpl(); this.tillDone = new TillDoneTracker(); } /** Register an SME under this team lead. */ registerSME(sme: SME): void { this.smes.push(sme); } /** Get the task types this team can handle via its SMEs. */ get capabilities(): TaskType[] { return [...new Set(this.smes.flatMap((sme) => sme.capabilities))]; } /** Can this team handle the given task? */ canHandle(task: Task): boolean { return this.smes.some((sme) => sme.canHandle(task)); } /** Handle a task assignment from the Orchestrator. */ async handleAssignment( message: TaskMessage, speck?: SpeckDefinition ): Promise { const task = message.payload.task; // Find the right SME const sme = this.smes.find((s) => s.canHandle(task)); if (!sme) { return { taskId: task.id, status: "failure", output: { error: `No SME available for task type ${task.taskType}` }, provenance: [], completedAt: new Date().toISOString(), }; } // Register TillDone condition this.tillDone.register( task.id, `${sme.id.name} completes ${task.taskType}`, (result) => result.status === "success" ); // Execute const result = await sme.execute(task, speck); // Evaluate completion this.tillDone.evaluate(task.id, result); // Merge provenance for (const edge of result.provenance) { this.provenance.addEdge(edge); } return result; } /** Get all SMEs in this team. */ getTeam(): SME[] { return [...this.smes]; } /** Check if this team is at capacity (queue depth > threshold). */ isAtCapacity(threshold: number = 5): boolean { return this.pendingCount() > threshold; } /** Number of pending tasks (not yet done). */ private pendingCount(): number { return this.tillDone.pending().length; } } // ─── Pre-built Team Lead configurations ────────────────────── import { VerificationSME } from "./smes/verification-sme.js"; import { CodegenSME } from "./smes/codegen-sme.js"; export class VerificationTeamLead extends TeamLead { constructor() { super("verification-lead", "verification"); this.registerSME(new VerificationSME()); } } export class CodegenTeamLead extends TeamLead { constructor() { super("codegen-lead", "codegen"); this.registerSME(new CodegenSME("typescript")); this.registerSME(new CodegenSME("rust")); } }