Exclude later turn work from observed reasoning duration

This commit is contained in:
Merge Sim
2026-09-08 16:59:09 -07:00
parent 9bcb747bc2
commit ab0675aed2
2 changed files with 28 additions and 4 deletions
@@ -72,6 +72,19 @@ describe('reasoning disclosure', () => {
expect(screen.getByRole('button')).toHaveTextContent('Thought for 1m 5s')
})
it('excludes later turn work after the block stops changing', () => {
const now = vi.spyOn(Date, 'now').mockReturnValue(10_000)
const { rerender } = render(<NativeChatReasoningRow markdown="Starting" isStreaming />)
now.mockReturnValue(22_000)
rerender(<NativeChatReasoningRow markdown="Reasoning complete" isStreaming />)
now.mockReturnValue(70_000)
rerender(<NativeChatReasoningRow markdown="Reasoning complete" isStreaming />)
expect(screen.getByRole('button')).toHaveTextContent('Thinking...')
now.mockReturnValue(100_000)
rerender(<NativeChatReasoningRow markdown="Reasoning complete" />)
expect(screen.getByRole('button')).toHaveTextContent('Thought for 12s')
})
it('resets the clock when block identity changes without a streaming-state transition', () => {
const now = vi.spyOn(Date, 'now').mockReturnValue(10_000)
const { rerender } = render(<NativeChatReasoningRow blockId="a" markdown="First" isStreaming />)
@@ -23,6 +23,8 @@ export function NativeChatReasoningRow({
const [timing, setTiming] = useState(() => ({
blockId,
streaming: isStreaming,
markdown,
lastUpdatedAt: Date.now(),
startedAt: isStreaming ? Date.now() : null,
elapsedMs: null as number | null
}))
@@ -33,22 +35,31 @@ export function NativeChatReasoningRow({
return {
blockId,
streaming: isStreaming,
markdown,
lastUpdatedAt: now,
startedAt: isStreaming ? now : null,
elapsedMs: null
}
}
if (previous.streaming === isStreaming) {
if (previous.streaming === isStreaming && (!isStreaming || previous.markdown === markdown)) {
return previous
}
// Only an observed stream supplies a duration; journal history has no local start.
const lastUpdatedAt =
(isStreaming && !previous.streaming) || previous.markdown !== markdown
? now
: previous.lastUpdatedAt
return {
...previous,
markdown,
lastUpdatedAt,
streaming: isStreaming,
startedAt: isStreaming ? now : previous.startedAt,
elapsedMs: isStreaming || previous.startedAt === null ? null : now - previous.startedAt
startedAt: isStreaming && !previous.streaming ? now : previous.startedAt,
elapsedMs:
isStreaming || previous.startedAt === null ? null : lastUpdatedAt - previous.startedAt
}
})
}, [blockId, isStreaming])
}, [blockId, isStreaming, markdown])
if (!markdown.trim()) {
return null
}