import { describe, expect, it } from 'vitest'; import { parseSsePayload, reduceAiSseMessage } from './provider'; describe('AI chat SSE message reducer', () => { it('separates reasoning and answer deltas', () => { let message = reduceAiSseMessage(undefined, { event: 'reasoning.delta', data: JSON.stringify({ messageId: 8, delta: '分析' }), }); message = reduceAiSseMessage(message, { event: 'content.delta', data: JSON.stringify({ delta: '**答案**' }), }); expect(message.reasoningContent).toBe('分析'); expect(message.content).toBe('**答案**'); }); it('tracks tool lifecycle without exposing raw payloads', () => { let message = reduceAiSseMessage(undefined, { event: 'tool.started', data: JSON.stringify({ toolCallId: 'call-1', toolName: 'search_students', summary: '姓名条件', }), }); message = reduceAiSseMessage(message, { event: 'tool.completed', data: JSON.stringify({ toolCallId: 'call-1', toolName: 'search_students', status: 'success', summary: '找到 1 条记录', }), }); expect(message.toolRuns).toHaveLength(1); expect(message.toolRuns[0]).toMatchObject({ status: 'success', summary: '找到 1 条记录' }); }); it('tracks processed attachments and final feedback state', () => { let message = reduceAiSseMessage(undefined, { event: 'attachment.processed', data: JSON.stringify({ attachment: { id: 4, name: '名单.xlsx', mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', size: 1200, status: 'ready', url: '/api/ai/chat/attachments/4', createdAt: '2026-07-24T00:00:00.000Z', }, }), }); message = reduceAiSseMessage(message, { event: 'message.completed', data: JSON.stringify({ message: { id: 12, content: '完成', reasoningContent: null, feedback: 'like', attachments: message.attachments, }, }), }); expect(message.attachments).toHaveLength(1); expect(message.feedback).toBe('like'); }); it('uses final content and records cancellation and errors', () => { let message = reduceAiSseMessage(undefined, { event: 'message.completed', data: JSON.stringify({ message: { id: 12, content: '最终回答', reasoningContent: '完成', status: 'completed', toolRuns: [ { toolCallId: 'nested-tool', toolName: 'search_rooms', status: 'success', resultSummary: '共 4 间', }, ], }, }), }); message = reduceAiSseMessage(message, { event: 'error', data: JSON.stringify({ message: '上游服务不可用' }), }); message = reduceAiSseMessage(message, { event: 'message.cancelled', data: JSON.stringify({ messageId: 12 }), }); expect(message).toMatchObject({ id: 12, content: '最终回答', reasoningContent: '完成', error: '上游服务不可用', cancelled: true, }); expect(message.toolRuns[0]).toMatchObject({ toolCallId: 'nested-tool', status: 'success' }); }); it('reads nested assistant message from message.created', () => { const message = reduceAiSseMessage(undefined, { event: 'message.created', data: JSON.stringify({ message: { id: 9, content: '', reasoningContent: null, status: 'pending' }, }), }); expect(message.id).toBe(9); }); it('tolerates non-JSON event data', () => { expect(parseSsePayload({ event: 'content.delta', data: 'plain text' })).toEqual({ event: 'content.delta', payload: { delta: 'plain text' }, }); }); });