fix(workbench): coalesce realtime turn snapshots by trace

This commit is contained in:
UniDesk Codex
2026-07-03 04:03:09 +08:00
parent 0a8f925c57
commit c9da0ec416
2 changed files with 22 additions and 3 deletions
@@ -0,0 +1,18 @@
import assert from "node:assert/strict";
import { test } from "bun:test";
import { realtimeCoalesceKey, type WorkbenchRealtimeEvent } from "./workbench-events";
test("turn snapshot coalescing keys by trace instead of per sequence", () => {
const first: WorkbenchRealtimeEvent = { type: "turn.snapshot", turn: { sessionId: "ses_queue", traceId: "trc_queue", status: "running" }, cursor: { traceSeq: 10 } };
const next: WorkbenchRealtimeEvent = { type: "turn.snapshot", turn: { sessionId: "ses_queue", traceId: "trc_queue", status: "running" }, cursor: { traceSeq: 11 } };
assert.equal(realtimeCoalesceKey(first, "workbench.turn.snapshot"), realtimeCoalesceKey(next, "workbench.turn.snapshot"));
});
test("trace events keep sequence-specific coalescing keys", () => {
const first: WorkbenchRealtimeEvent = { type: "trace.event", traceId: "trc_queue", event: { traceId: "trc_queue", projectedSeq: 10 } };
const next: WorkbenchRealtimeEvent = { type: "trace.event", traceId: "trc_queue", event: { traceId: "trc_queue", projectedSeq: 11 } };
assert.notEqual(realtimeCoalesceKey(first, "workbench.trace.event"), realtimeCoalesceKey(next, "workbench.trace.event"));
});
@@ -176,11 +176,12 @@ function scheduleRealtimeFlushYield(flush: () => void, yieldMs: number | null |
return () => clearTimeout(id);
}
function realtimeCoalesceKey(event: WorkbenchRealtimeEvent, eventName: string): string | null {
const sessionId = firstScopePart(event.sessionId, event.message?.sessionId, event.snapshot?.sessionId, event.event?.sessionId);
const traceId = firstScopePart(event.traceId, event.message?.traceId, event.snapshot?.traceId, event.event?.traceId);
export function realtimeCoalesceKey(event: WorkbenchRealtimeEvent, eventName: string): string | null {
const sessionId = firstScopePart(event.sessionId, event.message?.sessionId, event.snapshot?.sessionId, event.event?.sessionId, event.turn?.sessionId);
const traceId = firstScopePart(event.traceId, event.message?.traceId, event.snapshot?.traceId, event.event?.traceId, event.turn?.traceId);
const outboxSeq = numericCursor(event.cursor?.outboxSeq ?? event.outboxSeq);
const traceSeq = numericCursor(event.cursor?.traceSeq ?? event.traceSeq ?? event.event?.seq ?? event.event?.projectedSeq);
if (eventName === "workbench.turn.snapshot" && traceId) return composeWorkbenchScopedKey("workbench.sse.turn-snapshot", sessionId, traceId);
if (eventName === "workbench.trace.event" || eventName === "message") {
const eventSeq = outboxSeq ?? traceSeq;
return eventSeq === null ? null : composeWorkbenchScopedKey("workbench.sse.event", sessionId, traceId, eventName, eventSeq);