diff --git a/frontend-modern/src/components/AI/Chat/__tests__/transcriptExport.test.ts b/frontend-modern/src/components/AI/Chat/__tests__/transcriptExport.test.ts index 834b472e4..ac31dbb48 100644 --- a/frontend-modern/src/components/AI/Chat/__tests__/transcriptExport.test.ts +++ b/frontend-modern/src/components/AI/Chat/__tests__/transcriptExport.test.ts @@ -153,6 +153,34 @@ describe('Assistant transcript export', () => { expect(transcript).toContain('No active alerts'); }); + it('exports persisted tool calls before reconstructed assistant answer text', () => { + const transcript = formatAssistantTranscript({ + messages: [ + { + id: 'assistant-1', + role: 'assistant', + content: 'I checked the resource.', + timestamp, + toolCalls: [ + { + name: 'pulse_read', + input: JSON.stringify({ target: 'vm-100' }), + output: 'Resource is running', + success: true, + }, + ], + }, + ], + generatedAt: timestamp, + }); + + const toolIndex = transcript.indexOf('[tool:read]'); + const answerIndex = transcript.indexOf('I checked the resource.'); + expect(toolIndex).toBeGreaterThan(-1); + expect(answerIndex).toBeGreaterThan(-1); + expect(toolIndex).toBeLessThan(answerIndex); + }); + it('formats initially selected model route events distinctly from fallback switches', () => { const transcript = formatAssistantTranscript({ messages: [ diff --git a/frontend-modern/src/components/AI/Chat/__tests__/useChat.test.ts b/frontend-modern/src/components/AI/Chat/__tests__/useChat.test.ts index d8320b1bd..c0c5cdfea 100644 --- a/frontend-modern/src/components/AI/Chat/__tests__/useChat.test.ts +++ b/frontend-modern/src/components/AI/Chat/__tests__/useChat.test.ts @@ -2753,11 +2753,11 @@ describe('useChat', () => { expect(msgs[0].content).toBe('hello'); expect(msgs[1].toolCalls).toHaveLength(1); expect(msgs[1].streamEvents).toEqual([ - { type: 'content', content: 'hi there' }, { type: 'tool', tool: { name: 'test', input: '{}', output: 'ok', success: true }, }, + { type: 'content', content: 'hi there' }, ]); expect(msgs[1].timestamp).toBeInstanceOf(Date); dispose(); @@ -2873,7 +2873,6 @@ describe('useChat', () => { expect(assistant.model).toBe('openai:gpt-4'); expect(assistant.content).toBe('I checked the resource.'); expect(assistant.streamEvents).toEqual([ - { type: 'content', content: 'I checked the resource.' }, { type: 'tool', tool: { @@ -2883,6 +2882,7 @@ describe('useChat', () => { success: true, }, }, + { type: 'content', content: 'I checked the resource.' }, ]); dispose(); }); diff --git a/frontend-modern/src/components/AI/Chat/hooks/useChat.ts b/frontend-modern/src/components/AI/Chat/hooks/useChat.ts index 4a0e42916..ab40265d9 100644 --- a/frontend-modern/src/components/AI/Chat/hooks/useChat.ts +++ b/frontend-modern/src/components/AI/Chat/hooks/useChat.ts @@ -1135,15 +1135,15 @@ export function useChat(options: UseChatOptions = {}) { toolCalls?: PersistedToolCall[], ): StreamDisplayEvent[] | undefined => { const events: StreamDisplayEvent[] = []; - if (content.trim()) { - events.push({ type: 'content', content }); - } for (const tool of toolCalls || []) { events.push({ type: 'tool', tool: normalizePersistedToolExecution(tool), }); } + if (content.trim()) { + events.push({ type: 'content', content }); + } return events.length > 0 ? events : undefined; }; diff --git a/frontend-modern/src/components/AI/Chat/transcriptExport.ts b/frontend-modern/src/components/AI/Chat/transcriptExport.ts index e47e55922..8f30158a0 100644 --- a/frontend-modern/src/components/AI/Chat/transcriptExport.ts +++ b/frontend-modern/src/components/AI/Chat/transcriptExport.ts @@ -287,16 +287,16 @@ const appendAssistantStreamEvents = ( } } - if (!contentAppended) { - appendBlock(lines, visibleAssistantContent(message)); - } - if (!toolAppended) { for (const tool of message.toolCalls || []) { appendBlock(lines, formatCompletedTool(tool, options.includeToolOutput === true)); } } + if (!contentAppended) { + appendBlock(lines, visibleAssistantContent(message)); + } + if (!pendingToolAppended) { for (const tool of message.pendingTools || []) { appendBlock(lines, formatPendingTool(tool));