Files
EasyFlow/easyflow-ui-usercenter/packages/utils/src/helpers/__tests__/chat-time.test.ts
陈子默 72df00f25b feat: 全新智能体功能
- 基于先进智能体框架,增加智能体编排功能
- 增加智能体聊天,并对接持久化
2026-05-25 11:42:48 +08:00

188 lines
5.7 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('appends markdown deltas without altering repeated symbols', () => {
const items: any[] = [];
ChatTimeTimelineBuilder.appendThinkingDelta(items, '先想一下', 1);
ChatTimeTimelineBuilder.appendMessageDelta(items, '## 标题\n', 2);
ChatTimeTimelineBuilder.appendMessageDelta(items, '| 模型 | 说明 |\n', 3);
ChatTimeTimelineBuilder.appendMessageDelta(items, '| --- | --- |\n', 4);
ChatTimeTimelineBuilder.appendMessageDelta(items, '| ACL | 访问控制列表 |\n', 5);
ChatTimeTimelineBuilder.appendMessageDelta(
items,
'Final Answer: ```echartsoption',
6,
);
expect(items).toHaveLength(1);
expect(items[0]).toMatchObject({
content:
'## 标题\n| 模型 | 说明 |\n| --- | --- |\n| ACL | 访问控制列表 |\nFinal Answer: ```echartsoption',
role: 'assistant',
typing: true,
});
expect(items[0].segments).toMatchObject([
{ content: '先想一下', status: 'end', type: 'thinking' },
{
content:
'## 标题\n| 模型 | 说明 |\n| --- | --- |\n| ACL | 访问控制列表 |\nFinal Answer: ```echartsoption',
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',
});
});
});