Files
timmy-tower/artifacts/api-server/src/lib/event-bus.ts
Alexander Whitestone 29d4a53f8a
Some checks failed
CI / Typecheck & Lint (pull_request) Failing after 0s
feat: agent commentary during job execution
Add character-appropriate narration for each agent (Alpha, Beta, Gamma,
Delta) at each job lifecycle phase. Generated by Claude Haiku per agent
per phase and broadcast as agent_commentary WebSocket events.

- Add CommentaryEvent type to event-bus.ts
- Add AgentService.generateCommentary() with per-agent personas and
  stub mode canned responses
- Dispatch commentary in events.ts after job:state and job:paid
  transitions via a global event bus listener
- Handle agent_commentary on frontend: show speech bubble + event log

Fixes #1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 16:40:03 -04:00

45 lines
1.6 KiB
TypeScript

import { EventEmitter } from "events";
export type JobEvent =
| { type: "job:state"; jobId: string; state: string }
| { type: "job:paid"; jobId: string; invoiceType: "eval" | "work" }
| { type: "job:completed"; jobId: string; result: string }
| { type: "job:failed"; jobId: string; reason: string };
export type SessionEvent =
| { type: "session:state"; sessionId: string; state: string }
| { type: "session:paid"; sessionId: string; amountSats: number }
| { type: "session:balance"; sessionId: string; balanceSats: number };
export type DebateEvent =
| { type: "debate:argument"; jobId: string; agent: "Beta-A" | "Beta-B"; position: "accept" | "reject"; argument: string }
| { type: "debate:verdict"; jobId: string; accepted: boolean; reason: string };
export type CostEvent =
| { type: "cost:update"; jobId: string; sats: number; phase: "eval" | "work" | "session"; isFinal: boolean };
export type CommentaryEvent =
| { type: "agent_commentary"; agentId: string; jobId: string; text: string };
export type BusEvent = JobEvent | SessionEvent | DebateEvent | CostEvent | CommentaryEvent;
class EventBus extends EventEmitter {
emit(event: "bus", data: BusEvent): boolean;
emit(event: string, ...args: unknown[]): boolean {
return super.emit(event, ...args);
}
on(event: "bus", listener: (data: BusEvent) => void): this;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
on(event: string, listener: (...args: any[]) => void): this {
return super.on(event, listener);
}
publish(data: BusEvent): void {
this.emit("bus", data);
}
}
export const eventBus = new EventBus();
eventBus.setMaxListeners(256);