Files
clawdbot/src/infra/agent-events.ts
2026-01-10 00:52:24 +01:00

78 lines
1.9 KiB
TypeScript

export type AgentEventStream =
| "lifecycle"
| "tool"
| "assistant"
| "error"
| (string & {});
export type AgentEventPayload = {
runId: string;
seq: number;
stream: AgentEventStream;
ts: number;
data: Record<string, unknown>;
sessionKey?: string;
};
export type AgentRunContext = {
sessionKey?: string;
verboseLevel?: "off" | "on";
};
// Keep per-run counters so streams stay strictly monotonic per runId.
const seqByRun = new Map<string, number>();
const listeners = new Set<(evt: AgentEventPayload) => void>();
const runContextById = new Map<string, AgentRunContext>();
export function registerAgentRunContext(
runId: string,
context: AgentRunContext,
) {
if (!runId) return;
const existing = runContextById.get(runId);
if (!existing) {
runContextById.set(runId, { ...context });
return;
}
if (context.sessionKey && existing.sessionKey !== context.sessionKey) {
existing.sessionKey = context.sessionKey;
}
if (context.verboseLevel && existing.verboseLevel !== context.verboseLevel) {
existing.verboseLevel = context.verboseLevel;
}
}
export function getAgentRunContext(runId: string) {
return runContextById.get(runId);
}
export function clearAgentRunContext(runId: string) {
runContextById.delete(runId);
}
export function resetAgentRunContextForTest() {
runContextById.clear();
}
export function emitAgentEvent(event: Omit<AgentEventPayload, "seq" | "ts">) {
const nextSeq = (seqByRun.get(event.runId) ?? 0) + 1;
seqByRun.set(event.runId, nextSeq);
const enriched: AgentEventPayload = {
...event,
seq: nextSeq,
ts: Date.now(),
};
for (const listener of listeners) {
try {
listener(enriched);
} catch {
/* ignore */
}
}
}
export function onAgentEvent(listener: (evt: AgentEventPayload) => void) {
listeners.add(listener);
return () => listeners.delete(listener);
}