feat: 先进智能体功能上线
- 基于 agent-runtime 打造,默认 ReAct agent - 支持 agent 能力对接,已对接工作流、插件、知识库等 tool 能力 - 全新 agent 编排界面,支持可视化便捷配置 agent - 全新 agent 聊天界面,支持快捷操作、额外知识库选择等
This commit is contained in:
@@ -111,6 +111,135 @@ describe('agentTimelineAdapter', () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('hides knowledge retrieval cards when restoring agent chat history', () => {
|
||||
const items = recordsToTimelineItems([
|
||||
{
|
||||
id: '417197643647811584',
|
||||
senderRole: 'assistant',
|
||||
contentText:
|
||||
'根据知识库中的信息,2026年暑假的时间安排是:7月1日到8月15日。',
|
||||
roundId: '417197622424633344',
|
||||
contentPayload: {
|
||||
chains: [
|
||||
{
|
||||
id: 'call_0fc660e9d203416983ccca7e',
|
||||
name: 'retrieve_knowledge',
|
||||
result: 'Retrieved 2 relevant document(s)',
|
||||
status: 'TOOL_RESULT',
|
||||
arguments: {
|
||||
query: '暑假时间',
|
||||
},
|
||||
},
|
||||
],
|
||||
agentResult: {
|
||||
text: '根据知识库中的信息,2026年暑假的时间安排是:7月1日到8月15日。',
|
||||
knowledgeReferences: [
|
||||
{
|
||||
chunkContent:
|
||||
'问题:2026 年暑假安排\n答案:2026 年7 月 1 日到 8 月 15 日',
|
||||
documentId: '411358369563336704',
|
||||
knowledgeName: 'faq',
|
||||
knowledgeType: 'FAQ',
|
||||
},
|
||||
],
|
||||
},
|
||||
messageChain: [
|
||||
{
|
||||
role: 'assistant',
|
||||
toolCalls: [
|
||||
{
|
||||
id: 'call_0fc660e9d203416983ccca7e',
|
||||
name: 'retrieve_knowledge',
|
||||
arguments: '{query=暑假时间}',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
role: 'tool',
|
||||
content: 'Retrieved 2 relevant document(s)',
|
||||
toolCallId: 'call_0fc660e9d203416983ccca7e',
|
||||
},
|
||||
{
|
||||
role: 'assistant',
|
||||
content:
|
||||
'根据知识库中的信息,2026年暑假的时间安排是:7月1日到8月15日。',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(items.some((item) => item.type === 'tool')).toBe(false);
|
||||
expect(
|
||||
items.some(
|
||||
(item) => item.type === 'status' && item.label === '已检索知识库',
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
items.some((item) => item.type === 'message' && item.role === 'assistant'),
|
||||
).toBe(true);
|
||||
const assistant = items.find(
|
||||
(item): item is ChatTimelineMessageItem =>
|
||||
item.type === 'message' && item.role === 'assistant',
|
||||
);
|
||||
expect(assistant?.knowledgeItems?.[0]?.knowledgeName).toBe('faq');
|
||||
});
|
||||
|
||||
it('hides internal fragment and context reload tools from history', () => {
|
||||
const items = recordsToTimelineItems([
|
||||
{
|
||||
id: 'internal-tools',
|
||||
senderRole: 'assistant',
|
||||
contentText: '已处理',
|
||||
roundId: 'round-internal',
|
||||
contentPayload: {
|
||||
chains: [
|
||||
{
|
||||
id: 'fragment-1',
|
||||
name: '__fragment__',
|
||||
status: 'TOOL_RESULT',
|
||||
result: 'fragment',
|
||||
},
|
||||
{
|
||||
id: 'context-1',
|
||||
name: 'context_reload',
|
||||
status: 'TOOL_RESULT',
|
||||
result: 'reload',
|
||||
},
|
||||
],
|
||||
agentResult: {
|
||||
text: '已处理',
|
||||
},
|
||||
messageChain: [
|
||||
{
|
||||
role: 'assistant',
|
||||
toolCalls: [
|
||||
{ id: 'fragment-1', name: '__fragment__' },
|
||||
{ id: 'context-1', name: 'context_reload' },
|
||||
],
|
||||
},
|
||||
{
|
||||
role: 'tool',
|
||||
toolCallId: 'fragment-1',
|
||||
content: 'fragment',
|
||||
},
|
||||
{
|
||||
role: 'tool',
|
||||
toolCallId: 'context-1',
|
||||
content: 'reload',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(items.some((item) => item.type === 'tool')).toBe(false);
|
||||
expect(items.some((item) => item.type === 'status')).toBe(false);
|
||||
expect(
|
||||
items.some((item) => item.type === 'message' && item.role === 'assistant'),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('parses raw SSE text as message delta', () => {
|
||||
const envelope = parseAgentSseMessage({
|
||||
data: 'hello',
|
||||
@@ -227,4 +356,123 @@ describe('agentTimelineAdapter', () => {
|
||||
expect(assistant?.roundId).toBe('runtime-round-1');
|
||||
expect(assistant?.parts[0]?.content).toBe('准备调用工具');
|
||||
});
|
||||
|
||||
it('updates memory compression status within the current round', () => {
|
||||
const items: any[] = [];
|
||||
|
||||
applyAgentSseEnvelope(
|
||||
items,
|
||||
{
|
||||
domain: 'BUSINESS',
|
||||
type: 'STATUS',
|
||||
payload: {
|
||||
label: '正在整理上下文',
|
||||
phase: 'started',
|
||||
status: 'running',
|
||||
statusKey: 'memory-compression',
|
||||
},
|
||||
},
|
||||
{ roundId: 'round-a' },
|
||||
);
|
||||
applyAgentSseEnvelope(
|
||||
items,
|
||||
{
|
||||
domain: 'BUSINESS',
|
||||
type: 'STATUS',
|
||||
payload: {
|
||||
compressed: true,
|
||||
label: '已整理上下文',
|
||||
phase: 'completed',
|
||||
status: 'done',
|
||||
statusKey: 'memory-compression',
|
||||
},
|
||||
},
|
||||
{ roundId: 'round-a' },
|
||||
);
|
||||
|
||||
const statuses = items.filter((item) => item.type === 'status');
|
||||
expect(statuses).toHaveLength(1);
|
||||
expect(statuses[0]?.label).toBe('已整理上下文');
|
||||
expect(statuses[0]?.status).toBe('done');
|
||||
expect(statuses[0]?.statusKey).toBe('memory-compression:round-a');
|
||||
});
|
||||
|
||||
it('keeps memory compression statuses isolated by round', () => {
|
||||
const items: any[] = [];
|
||||
|
||||
applyAgentSseEnvelope(
|
||||
items,
|
||||
{
|
||||
domain: 'BUSINESS',
|
||||
type: 'STATUS',
|
||||
payload: {
|
||||
compressed: true,
|
||||
label: '已整理上下文',
|
||||
phase: 'completed',
|
||||
status: 'done',
|
||||
statusKey: 'memory-compression',
|
||||
},
|
||||
},
|
||||
{ roundId: 'round-a' },
|
||||
);
|
||||
applyAgentSseEnvelope(
|
||||
items,
|
||||
{
|
||||
domain: 'BUSINESS',
|
||||
type: 'STATUS',
|
||||
payload: {
|
||||
compressed: false,
|
||||
label: '无需压缩上下文',
|
||||
phase: 'completed',
|
||||
status: 'done',
|
||||
statusKey: 'memory-compression',
|
||||
},
|
||||
},
|
||||
{ roundId: 'round-b' },
|
||||
);
|
||||
|
||||
const statuses = items.filter((item) => item.type === 'status');
|
||||
expect(statuses).toHaveLength(1);
|
||||
expect(statuses[0]?.statusKey).toBe('memory-compression:round-a');
|
||||
expect(statuses[0]?.label).toBe('已整理上下文');
|
||||
});
|
||||
|
||||
it('does not show no-compression status before a later compression run', () => {
|
||||
const items: any[] = [];
|
||||
|
||||
applyAgentSseEnvelope(
|
||||
items,
|
||||
{
|
||||
domain: 'BUSINESS',
|
||||
type: 'STATUS',
|
||||
payload: {
|
||||
compressed: false,
|
||||
label: '无需压缩上下文',
|
||||
phase: 'completed',
|
||||
status: 'done',
|
||||
statusKey: 'memory-compression',
|
||||
},
|
||||
},
|
||||
{ roundId: 'round-a' },
|
||||
);
|
||||
applyAgentSseEnvelope(
|
||||
items,
|
||||
{
|
||||
domain: 'BUSINESS',
|
||||
type: 'STATUS',
|
||||
payload: {
|
||||
label: '正在整理上下文',
|
||||
phase: 'started',
|
||||
status: 'running',
|
||||
statusKey: 'memory-compression',
|
||||
},
|
||||
},
|
||||
{ roundId: 'round-a' },
|
||||
);
|
||||
|
||||
const statuses = items.filter((item) => item.type === 'status');
|
||||
expect(statuses).toHaveLength(1);
|
||||
expect(statuses[0]?.label).toBe('正在整理上下文');
|
||||
expect(statuses[0]?.status).toBe('running');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user