Files
EasyFlow/easyflow-ui-usercenter/packages/utils/src/helpers/__tests__/chat-time.test.ts
陈子默 4a15124183 feat: 重构聊天时间线与附件上传交互
- 管理端和用户中心统一切换到 chatTime 时间线模型,按真实 assistant/tool 时序渲染

- 收紧工具气泡与 JSON 展示样式,保留同气泡内的工具状态更新

- 回形针直接触发文件选择,附件列表上移到输入框上方并补充共享 helper 测试
2026-05-11 21:25:21 +08:00

160 lines
4.5 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
ChatTimeHistoryMapper,
ChatTimeTimelineBuilder,
} from '../chat-time';
describe('chat-time timeline builder', () => {
it('builds assistant thinking and message in the same assistant item', () => {
const items: any[] = [];
ChatTimeTimelineBuilder.appendUserMessage(items, {
content: '你好',
created: 1,
id: 'user-1',
});
ChatTimeTimelineBuilder.appendThinkingDelta(items, '先想一下', 2);
ChatTimeTimelineBuilder.appendMessageDelta(items, '最终回答', 3);
ChatTimeTimelineBuilder.finalize(items);
expect(items).toHaveLength(2);
expect(items[1]).toMatchObject({
content: '最终回答',
role: 'assistant',
});
expect(items[1].segments).toMatchObject([
{ content: '先想一下', status: 'end', type: 'thinking' },
{ content: '最终回答', type: 'text' },
]);
});
it('creates a new assistant item after tool result', () => {
const items: any[] = [];
ChatTimeTimelineBuilder.appendMessageDelta(items, '第一段回答', 1);
ChatTimeTimelineBuilder.upsertToolCall(items, {
name: 'search_docs',
toolCallId: 'tool-1',
value: '{"query":"java"}',
});
ChatTimeTimelineBuilder.upsertToolResult(items, {
result: '{"hits":1}',
toolCallId: 'tool-1',
});
ChatTimeTimelineBuilder.appendThinkingDelta(items, '继续思考', 2);
ChatTimeTimelineBuilder.appendMessageDelta(items, '第二段回答', 3);
ChatTimeTimelineBuilder.finalize(items);
expect(items).toHaveLength(3);
expect(items[0]).toMatchObject({ content: '第一段回答', role: 'assistant' });
expect(items[1]).toMatchObject({
name: 'search_docs',
result: '{"hits":1}',
role: 'tool',
status: 'TOOL_RESULT',
toolCallId: 'tool-1',
});
expect(items[2]).toMatchObject({ content: '第二段回答', role: 'assistant' });
expect(items[2].segments).toMatchObject([
{ content: '继续思考', status: 'end', type: 'thinking' },
{ content: '第二段回答', type: 'text' },
]);
});
});
describe('chat-time history mapper', () => {
it('expands structured messageChain into assistant and tool timeline items', () => {
const items = ChatTimeHistoryMapper.fromHistoryRecords([
{
contentPayload: {
messageChain: [
{
content: '先回答一点',
reasoningContent: '先思考',
role: 'assistant',
toolCalls: [
{
arguments: '{"query":"java"}',
id: 'tool-1',
name: 'search_docs',
},
],
},
{
content: '{"hits":1}',
role: 'tool',
toolCallId: 'tool-1',
},
{
content: '最后总结',
reasoningContent: '继续思考',
role: 'assistant',
},
],
},
created: 100,
id: 'assistant-record',
senderRole: 'assistant',
},
]);
expect(items).toHaveLength(3);
expect(items[0]).toMatchObject({
content: '先回答一点',
role: 'assistant',
});
expect(items[1]).toMatchObject({
arguments: '{"query":"java"}',
name: 'search_docs',
result: '{"hits":1}',
role: 'tool',
toolCallId: 'tool-1',
});
expect(items[2]).toMatchObject({
content: '最后总结',
role: 'assistant',
});
expect(items[0]?.id).not.toBe(items[2]?.id);
});
it('falls back to legacy chains when messageChain is unavailable', () => {
const items = ChatTimeHistoryMapper.fromLegacyMessages([
{
chains: [
{
reasoning_content: '旧思考',
thinkingStatus: 'end',
},
{
id: 'tool-2',
name: 'legacy_tool',
result: '{"ok":true}',
status: 'TOOL_RESULT',
},
],
content: '旧回答',
created: '2026-05-11 10:00:00',
id: 'legacy-1',
role: 'assistant',
},
]);
expect(items).toHaveLength(2);
expect(items[0]).toMatchObject({
content: '旧回答',
role: 'assistant',
});
expect(items[0].segments).toMatchObject([
{ content: '旧思考', status: 'end', type: 'thinking' },
{ content: '旧回答', type: 'text' },
]);
expect(items[1]).toMatchObject({
name: 'legacy_tool',
result: '{"ok":true}',
role: 'tool',
toolCallId: 'tool-2',
});
});
});