speckl/reference-agent/src/team-lead.ts
Scott Scoble 7297b5ec58 feat: whitepaper sections 2-6, README overhaul, SpeckDL spec v0.1, reference agent scaffold
- Dark Provenance whitepaper: complete sections 2-6 (What Is Dark Provenance,
  The Speckl Approach, Semantic Preservation & SA-11, Implications, Call to Action)
- README: public launch-ready with architecture, roadmap, getting started
- SpeckDL SPEC.md: v0.1 language specification with EBNF grammar,
  type system, compilation pipeline, 5 example Specks
- Reference agent: TypeScript scaffold with Orchestrator, TeamLead, SMEs
  (VerificationSME, CodegenSME), TillDone condition tracking,
  ProvenanceGraph, and CLI with example Specks
2026-04-28 09:33:48 -07:00

122 lines
No EOL
3.2 KiB
TypeScript

/**
* 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<TaskResult> {
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"));
}
}