fix(workbench): preserve projected trace order and duration (#1974)

This commit is contained in:
Lyon
2026-06-23 15:43:06 +08:00
committed by GitHub
parent 4759afa308
commit 2a313e1ab8
2 changed files with 19 additions and 8 deletions
@@ -146,7 +146,7 @@ function mergeTraceTimingProjection(previous: unknown, next: unknown): TraceSnap
const terminalTiming = traceTimingIsTerminal(next) || finishedAt !== null;
const previousTerminalDurationMs = previousTiming.finishedAt ? previousTiming.durationMs : null;
const durationMs = terminalTiming
? firstTraceDuration(nextTiming.durationMs, elapsedDurationMs, previousTerminalDurationMs)
? maxTraceDuration(previousTiming.durationMs, nextTiming.durationMs, elapsedDurationMs, previousTerminalDurationMs)
: maxTraceDuration(previousTiming.durationMs, nextTiming.durationMs, elapsedDurationMs);
return {
...previousTiming,
@@ -266,17 +266,23 @@ function mergeTraceEvents(previousEvents: TraceEvent[], nextEvents: TraceEvent[]
}
function traceEventSortSeq(event: TraceEvent): number {
const seq = Number(event.seq);
const seq = traceEventProjectedSeq(event);
return Number.isFinite(seq) ? seq : Number.MAX_SAFE_INTEGER;
}
function traceEventIdentity(event: TraceEvent): string | null {
const label = typeof event.label === "string" ? event.label : typeof event.type === "string" ? event.type : "";
const seq = typeof event.seq === "number" || typeof event.seq === "string" ? String(event.seq) : "";
const seqValue = event.projectedSeq ?? event.seq;
const seq = typeof seqValue === "number" || typeof seqValue === "string" ? String(seqValue) : "";
if (seq) return `projected:${seq}:${label || "event"}`;
return null;
}
function traceEventProjectedSeq(event: TraceEvent): number {
const seq = Number(event.projectedSeq ?? event.seq);
return Number.isFinite(seq) ? Math.trunc(seq) : Number.NaN;
}
export function mergeTraceResults(terminal: AgentChatResultResponse, trace: TraceSnapshot | null): AgentChatResultResponse {
if (!trace) return terminal;
const mergedTrace: TraceSnapshot = {
@@ -486,7 +492,7 @@ function traceSnapshotNextProjectedSeq(snapshot: TraceSnapshot, fallback: number
if (Number.isFinite(direct) && direct >= 0) return Math.trunc(direct);
const events = Array.isArray(snapshot.events) ? snapshot.events : [];
return events.reduce((max, event) => {
const seq = Number(event.seq);
const seq = traceEventProjectedSeq(event);
return Number.isFinite(seq) && seq > max ? Math.trunc(seq) : max;
}, fallback);
}
+9 -4
View File
@@ -1810,8 +1810,8 @@ function messageTimingPatchForMerge(message: ChatMessage, value: unknown): Parti
function terminalTimingDurationMsForMerge(message: ChatMessage, timing: WorkbenchTurnTimingProjection): number | null {
const elapsed = elapsedTimingDurationMs(timing);
const positive = firstPositiveFiniteNumber(timing.durationMs, elapsed, message.durationMs, message.timing?.durationMs, message.runnerTrace?.durationMs, message.runnerTrace?.timing?.durationMs);
if (positive !== null) return positive;
const maximum = maxFiniteNumber(timing.durationMs, elapsed, message.durationMs, message.timing?.durationMs, message.runnerTrace?.durationMs, message.runnerTrace?.timing?.durationMs);
if (maximum !== null) return maximum;
return firstFiniteNumber(timing.durationMs, elapsed, message.durationMs, message.timing?.durationMs, message.runnerTrace?.durationMs, message.runnerTrace?.timing?.durationMs);
}
@@ -2180,7 +2180,7 @@ function traceHydrationProjectedSeq(trace: ChatMessage["runnerTrace"]): number {
if (Number.isFinite(rangeNext) && rangeNext > 0 && trace?.hasMore === true) return Math.trunc(rangeNext);
const events = Array.isArray(trace?.events) ? trace.events : [];
return events.reduce((max, event) => {
const seq = Number(event.seq);
const seq = traceEventProjectedSeq(event);
return Number.isFinite(seq) && seq > max ? Math.trunc(seq) : max;
}, 0);
}
@@ -2190,11 +2190,16 @@ function traceNextProjectedSeq(result: AgentChatResultResponse, fallback: number
if (Number.isFinite(direct) && direct >= 0) return Math.trunc(direct);
const events = Array.isArray(result.events) ? result.events : Array.isArray(result.traceEvents) ? result.traceEvents : [];
return events.reduce((max, event) => {
const seq = Number(event.seq);
const seq = traceEventProjectedSeq(event);
return Number.isFinite(seq) && seq > max ? Math.trunc(seq) : max;
}, fallback);
}
function traceEventProjectedSeq(event: TraceEvent): number {
const seq = Number(event.projectedSeq ?? event.seq);
return Number.isFinite(seq) ? Math.trunc(seq) : Number.NaN;
}
function makeMessage(role: ChatMessage["role"], text: string, status: ChatMessage["status"], extra: Partial<ChatMessage> = {}): ChatMessage {
return { id: nextProtocolId("msg"), role, title: extra.title ?? (role === "user" ? "用户" : "Code Agent"), text, status, createdAt: new Date().toISOString(), ...extra };
}