mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-07 12:18:44 +02:00
feat: render thinking process UI for intermediate agent messages
Wire message-reclassified sidecar events through the main process to the renderer, where reclassified messages are filtered out of the main transcript and collected into a collapsible ThinkingProcess component. Main process changes: - Route message-reclassified via dedicated onMessageReclassified callback - Add applyMessageReclassified handler that sets messageKind and emits the session event for the renderer - Forward assistant-intent and reasoning-delta as turn-scoped events Renderer changes: - Split session.messages into visibleMessages and thinkingMessages - Render ThinkingProcess above the last assistant message - ThinkingProcess auto-expands during active turns, collapses on finish - Update messagePhase to skip thinking-kind messages for final detection Tests: - 3 new sessionWorkspace tests for reclassification apply/dedup/ignore - 2 new messagePhase tests for thinking-kind handling - Updated runTurnPending test fixtures for new callback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -281,4 +281,73 @@ describe('session workspace helpers', () => {
|
||||
} satisfies SessionEventRecord),
|
||||
).toBe(workspace);
|
||||
});
|
||||
|
||||
test('reclassifies a message as thinking when message-reclassified event arrives', () => {
|
||||
const workspace = applySessionEventWorkspace(createWorkspace(), {
|
||||
sessionId: 'session-1',
|
||||
kind: 'message-delta',
|
||||
occurredAt: '2026-03-23T00:00:01.000Z',
|
||||
messageId: 'assistant-1',
|
||||
authorName: 'Primary Agent',
|
||||
contentDelta: 'Let me search...',
|
||||
content: 'Let me search...',
|
||||
} satisfies SessionEventRecord);
|
||||
|
||||
const reclassified = applySessionEventWorkspace(workspace, {
|
||||
sessionId: 'session-1',
|
||||
kind: 'message-reclassified',
|
||||
occurredAt: '2026-03-23T00:00:02.000Z',
|
||||
messageId: 'assistant-1',
|
||||
messageKind: 'thinking',
|
||||
} satisfies SessionEventRecord);
|
||||
|
||||
expect(reclassified?.sessions[0].messages[0]).toMatchObject({
|
||||
id: 'assistant-1',
|
||||
messageKind: 'thinking',
|
||||
});
|
||||
});
|
||||
|
||||
test('ignores message-reclassified for an already reclassified message', () => {
|
||||
let workspace = applySessionEventWorkspace(createWorkspace(), {
|
||||
sessionId: 'session-1',
|
||||
kind: 'message-delta',
|
||||
occurredAt: '2026-03-23T00:00:01.000Z',
|
||||
messageId: 'assistant-1',
|
||||
authorName: 'Primary Agent',
|
||||
contentDelta: 'Let me search...',
|
||||
content: 'Let me search...',
|
||||
} satisfies SessionEventRecord);
|
||||
|
||||
workspace = applySessionEventWorkspace(workspace, {
|
||||
sessionId: 'session-1',
|
||||
kind: 'message-reclassified',
|
||||
occurredAt: '2026-03-23T00:00:02.000Z',
|
||||
messageId: 'assistant-1',
|
||||
messageKind: 'thinking',
|
||||
} satisfies SessionEventRecord);
|
||||
|
||||
const duplicate = applySessionEventWorkspace(workspace, {
|
||||
sessionId: 'session-1',
|
||||
kind: 'message-reclassified',
|
||||
occurredAt: '2026-03-23T00:00:03.000Z',
|
||||
messageId: 'assistant-1',
|
||||
messageKind: 'thinking',
|
||||
} satisfies SessionEventRecord);
|
||||
|
||||
// Should return the same reference (no change)
|
||||
expect(duplicate).toBe(workspace);
|
||||
});
|
||||
|
||||
test('ignores message-reclassified for unknown message ids', () => {
|
||||
const workspace = createWorkspace();
|
||||
const result = applySessionEventWorkspace(workspace, {
|
||||
sessionId: 'session-1',
|
||||
kind: 'message-reclassified',
|
||||
occurredAt: '2026-03-23T00:00:01.000Z',
|
||||
messageId: 'nonexistent',
|
||||
messageKind: 'thinking',
|
||||
} satisfies SessionEventRecord);
|
||||
|
||||
expect(result).toBe(workspace);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user