diff --git a/src/logging/diagnostic-stability.test.ts b/src/logging/diagnostic-stability.test.ts index 549160e2964..733796a2d3e 100644 --- a/src/logging/diagnostic-stability.test.ts +++ b/src/logging/diagnostic-stability.test.ts @@ -22,7 +22,7 @@ describe("diagnostic stability recorder", () => { resetDiagnosticEventsForTest(); }); - it("records a bounded payload-free projection of diagnostic events", () => { + it("records a bounded payload-free projection of diagnostic events", async () => { startDiagnosticStabilityRecorder(); emitDiagnosticEvent({ @@ -41,13 +41,29 @@ describe("diagnostic stability recorder", () => { count: 3, message: "message that should not be stored", }); + emitDiagnosticEvent({ + type: "talk.event", + sessionId: "talk-session-secret", + turnId: "talk-turn-secret", + captureId: "talk-capture-secret", + talkEventType: "latency.metrics", + mode: "realtime", + transport: "gateway-relay", + brain: "agent-consult", + provider: "openai", + final: true, + durationMs: 12, + byteLength: 345, + }); + await new Promise((resolve) => setImmediate(resolve)); const snapshot = getDiagnosticStabilitySnapshot({ limit: 10 }); - expect(snapshot.count).toBe(2); + expect(snapshot.count).toBe(3); expect(snapshot.summary.byType).toMatchObject({ "webhook.error": 1, "tool.loop": 1, + "talk.event": 1, }); expect(snapshot.events[0]).toMatchObject({ type: "webhook.error", @@ -66,6 +82,20 @@ describe("diagnostic stability recorder", () => { expect(snapshot.events[1]).not.toHaveProperty("message"); expect(snapshot.events[1]).not.toHaveProperty("sessionId"); expect(snapshot.events[1]).not.toHaveProperty("sessionKey"); + expect(snapshot.events[2]).toMatchObject({ + type: "talk.event", + talkEventType: "latency.metrics", + mode: "realtime", + transport: "gateway-relay", + brain: "agent-consult", + provider: "openai", + final: true, + durationMs: 12, + bytes: 345, + }); + expect(snapshot.events[2]).not.toHaveProperty("sessionId"); + expect(snapshot.events[2]).not.toHaveProperty("turnId"); + expect(snapshot.events[2]).not.toHaveProperty("captureId"); }); it("keeps stable reason codes but drops free-form reason text", () => { diff --git a/src/logging/diagnostic-stability.ts b/src/logging/diagnostic-stability.ts index 1266c113a63..796ae68a4e7 100644 --- a/src/logging/diagnostic-stability.ts +++ b/src/logging/diagnostic-stability.ts @@ -27,6 +27,9 @@ export type DiagnosticStabilityEventRecord = { phase?: string; detector?: string; deliveryKind?: string; + talkEventType?: string; + transport?: string; + brain?: string; toolName?: string; activeWorkKind?: string; pairedToolName?: string; @@ -40,6 +43,7 @@ export type DiagnosticStabilityEventRecord = { commandLength?: number; exitCode?: number; timedOut?: boolean; + final?: boolean; costUsd?: number; count?: number; bytes?: number; @@ -228,6 +232,16 @@ function sanitizeDiagnosticEvent(event: DiagnosticEventPayload): DiagnosticStabi record.outcome = "error"; assignReasonCode(record, event.errorCategory); break; + case "talk.event": + record.talkEventType = event.talkEventType; + record.mode = event.mode; + record.transport = event.transport; + record.brain = event.brain; + record.provider = event.provider; + record.final = event.final; + record.durationMs = event.durationMs; + record.bytes = event.byteLength; + break; case "session.state": record.outcome = event.state; assignReasonCode(record, event.reason);