diff --git a/apps/web/tests/code-mode-fixture.snapshot.ts b/apps/web/tests/code-mode-fixture.snapshot.ts index f53777fff8..d90a60641c 100644 --- a/apps/web/tests/code-mode-fixture.snapshot.ts +++ b/apps/web/tests/code-mode-fixture.snapshot.ts @@ -206,16 +206,15 @@ it('trajectory and waterfall surface the run_code sub-calls with real timing', a }, { timeout: 10_000 }) const subCells = [...document.querySelectorAll('[data-kind="subtool"]')] expect({ - // Three Sub cells nested under the run_code Tool cell, in dispatch order, - // each with a real +N.Ns own-duration off the start/settle pair (the - // fixture spaces every event 800ms apart — never the em dash). + // Three Subtool cells nested under the run_code Tool cell in dispatch + // order, each paired with its result preview. subCells: subCells.map(cell => visibleText(cell)), }).toMatchInlineSnapshot(` { "subCells": [ - "#51Subbash · {"command":"ls notes","description":"List notes"}+0.8s", - "#52Subread · {"path":"notes/demo.txt"}+0.8s", - "#53Subread · {"path":"notes/missing.txt"}+0.8s", + "SUBTOOLbash{"command":"ls notes","description":"List notes"}→demo.txt new-demo.txt", + "SUBTOOLread{"path":"notes/demo.txt"}→hello fixture", + "SUBTOOLread{"path":"notes/missing.txt"}→error", ], } `) @@ -239,17 +238,17 @@ it('trajectory and waterfall surface the run_code sub-calls with real timing', a { "label": "bash", "timing": "measured", - "title": "bash · 0.80s", + "title": "bash · 0.80 s", }, { "label": "read", "timing": "measured", - "title": "read · 0.80s", + "title": "read · 0.80 s", }, { "label": "read", "timing": "measured", - "title": "read · 0.80s", + "title": "read · 0.80 s", }, ], } diff --git a/packages/client/runtime/src/client/sessions/fold-adapter.ts b/packages/client/runtime/src/client/sessions/fold-adapter.ts index d96cc2c16c..3caf00e400 100644 --- a/packages/client/runtime/src/client/sessions/fold-adapter.ts +++ b/packages/client/runtime/src/client/sessions/fold-adapter.ts @@ -196,23 +196,9 @@ export class FoldAdapter { } const out: ConversationNode[] = [] for (const seq of seqs) { - const cached = this.nodeCache.get(seq) - if (cached !== undefined) { - out.push(cached) - continue - } - const event = this.padded[seq] - /* v8 ignore next -- sparse guard: both seq sources (surface fold and degradedSeqs) only emit indexes present in padded. */ - if (event === undefined) continue - const node = materializeNode( - event, - this.callIdx, - this.resultViews.get(seq) ?? null, - event.type === 'assistant/message' ? this.assistantTiming(event) : undefined, - event.type === 'assistant/message' ? this.assistantRequestConfig(event) : undefined, - ) - this.nodeCache.set(seq, node) - out.push(node) + const node = this.materialize(seq) + /* v8 ignore next -- both seq sources only emit indexes present in padded. */ + if (node !== undefined) out.push(node) } const value = { nodes: out, degraded: this.degraded } this.nodesResult = { rev: this.rev, value } diff --git a/packages/client/ui-trajectory/src/client/layout.ts b/packages/client/ui-trajectory/src/client/layout.ts index d6b0ec0edc..47e8d01cb6 100644 --- a/packages/client/ui-trajectory/src/client/layout.ts +++ b/packages/client/ui-trajectory/src/client/layout.ts @@ -68,6 +68,11 @@ interface TurnBucket { groups: LaidGroup[] } +type InputNode = Extract< + ConversationSnapshot['nodes'][number], + { kind: 'user' | 'steering' | 'context' } +> + type OrderedLayoutEntry = | { kind: 'node' @@ -97,6 +102,21 @@ function layoutEntryOrder(entry: OrderedLayoutEntry): number { : entry.seq } +function inputCellDetail(node: InputNode): Pick< + TrajectoryCellProps, + 'text' | 'sourceSeq' | 'messageSource' | 'inputDetail' | 'sourceBlocks' | 'timeSeconds' | 'startedAt' +> { + return { + text: summarizeContent(node.content), + sourceSeq: node.seq, + messageSource: node.source, + inputDetail: detailContent(node.content), + sourceBlocks: node.content.map(block => sourceBlock(block)), + timeSeconds: 0, + startedAt: finiteTime(node.time), + } +} + /** * Fold a snapshot into turn → Message/Step groups with expanded cells. * @param input - nodes plus in-flight partial/runningCalls. @@ -294,15 +314,11 @@ export function deriveTrajectoryLayout(input: TrajectoryLayoutInput): readonly T pushMessage(turn, { absTime: finiteTime(node.time), cell: { - index: ++index, kind: 'user', text: summarizeContent(node.content), - sourceSeq: node.seq, - messageSource: node.source, + index: ++index, + kind: 'user', + ...inputCellDetail(node), ...(node.meta === undefined ? {} : { messageMeta: node.meta }), opensTurn: node.kind === 'user', - inputDetail: detailContent(node.content), - sourceBlocks: node.content.map(block => sourceBlock(block)), - timeSeconds: 0, - startedAt: finiteTime(node.time), }, }) prevAbsTime = finiteTime(node.time) ?? prevAbsTime @@ -328,13 +344,7 @@ export function deriveTrajectoryLayout(input: TrajectoryLayoutInput): readonly T cell: { index: ++index, kind: 'context', - text: summarizeContent(node.content), - sourceSeq: node.seq, - messageSource: node.source, - inputDetail: detailContent(node.content), - sourceBlocks: node.content.map(block => sourceBlock(block)), - timeSeconds: 0, - startedAt: finiteTime(node.time), + ...inputCellDetail(node), }, }) prevAbsTime = finiteTime(node.time) ?? prevAbsTime