perf: 优化 Agent 流式会话处理
- 合并流式通知与持久化写入,限制浏览器会话缓存 - 增量投影轮次事件并稳定关联异步工具任务
This commit is contained in:
@@ -241,4 +241,158 @@ describe('useAgentTryoutRawRounds', () => {
|
||||
toolCallId: 'call-approval',
|
||||
});
|
||||
});
|
||||
|
||||
it('异步工作流轮询事件始终归并到首张审批卡', () => {
|
||||
const store = useAgentTryoutRawRounds({
|
||||
mode: 'draft',
|
||||
sessionId: 'session-raw-async-tool',
|
||||
});
|
||||
const roundId = store.createRound('生成文档');
|
||||
store.recordEvent(roundId, {
|
||||
domain: 'TOOL',
|
||||
payload: {
|
||||
input: { user_input: '写一篇小作文' },
|
||||
requestId: 'req-async',
|
||||
resumeToken: 'resume-async',
|
||||
toolCallId: 'submit-call-1',
|
||||
toolName: '文档生成',
|
||||
},
|
||||
type: 'FORM_REQUEST',
|
||||
});
|
||||
store.recordEvent(roundId, {
|
||||
domain: 'TOOL',
|
||||
payload: {
|
||||
asyncTool: true,
|
||||
phase: 'submit',
|
||||
sourceToolCallId: 'submit-call-1',
|
||||
status: 'RUNNING',
|
||||
taskId: 'task-1',
|
||||
toolCallId: 'task-1',
|
||||
toolName: '文档生成',
|
||||
},
|
||||
type: 'TOOL_RESULT',
|
||||
});
|
||||
for (const sourceToolCallId of ['observe-call-1', 'observe-call-2']) {
|
||||
store.recordEvent(roundId, {
|
||||
domain: 'TOOL',
|
||||
payload: {
|
||||
asyncTool: true,
|
||||
input: { taskId: 'task-1' },
|
||||
phase: 'observe',
|
||||
sourceToolCallId,
|
||||
status: 'RUNNING',
|
||||
taskId: 'task-1',
|
||||
toolCallId: 'task-1',
|
||||
toolName: '文档生成',
|
||||
},
|
||||
type: 'TOOL_CALL',
|
||||
});
|
||||
}
|
||||
store.recordEvent(roundId, {
|
||||
domain: 'TOOL',
|
||||
payload: {
|
||||
asyncTool: true,
|
||||
phase: 'result',
|
||||
sourceToolCallId: 'result-call-1',
|
||||
status: 'SUCCEEDED',
|
||||
taskId: 'task-1',
|
||||
toolCallId: 'task-1',
|
||||
toolName: '文档生成',
|
||||
},
|
||||
type: 'TOOL_RESULT',
|
||||
});
|
||||
|
||||
const tools = store
|
||||
.buildTimelineItems()
|
||||
.filter((item) => item.type === 'tool');
|
||||
|
||||
expect(tools).toHaveLength(1);
|
||||
expect(tools[0]).toMatchObject({
|
||||
mode: 'approval',
|
||||
status: 'success',
|
||||
taskId: 'task-1',
|
||||
toolCallId: 'task-1',
|
||||
toolName: '文档生成',
|
||||
});
|
||||
});
|
||||
|
||||
it('连续文本增量压缩后刷新内容保持一致', () => {
|
||||
const sessionId = 'stream-compaction';
|
||||
const store = useAgentTryoutRawRounds({
|
||||
mode: 'draft',
|
||||
sessionId,
|
||||
});
|
||||
const roundId = store.createRound('你好');
|
||||
const liveItems = store.buildTimelineItems();
|
||||
const assistantText = (
|
||||
items: ReturnType<typeof store.buildTimelineItems>,
|
||||
) =>
|
||||
items
|
||||
.flatMap((item) =>
|
||||
item.type === 'message' && item.role === 'assistant'
|
||||
? item.parts
|
||||
.filter((part) => part.type === 'text')
|
||||
.map((part) => part.content)
|
||||
: [],
|
||||
)
|
||||
.join('');
|
||||
|
||||
for (const delta of ['你', '好', ',', '世界']) {
|
||||
const event = store.recordEvent(roundId, {
|
||||
domain: 'LLM',
|
||||
payload: { delta },
|
||||
type: 'MESSAGE',
|
||||
});
|
||||
if (!event) {
|
||||
throw new Error('流式事件记录失败');
|
||||
}
|
||||
store.projectEvent(liveItems, roundId, event);
|
||||
}
|
||||
|
||||
expect(store.currentVariant(roundId)?.runtimeEvents).toHaveLength(1);
|
||||
expect(store.currentVariant(roundId)?.runtimeEvents[0]?.payload.delta).toBe(
|
||||
'你好,世界',
|
||||
);
|
||||
expect(assistantText(liveItems)).toBe('你好,世界');
|
||||
|
||||
store.flush();
|
||||
const restored = useAgentTryoutRawRounds({
|
||||
mode: 'draft',
|
||||
sessionId,
|
||||
});
|
||||
expect(assistantText(restored.buildTimelineItems())).toBe('你好,世界');
|
||||
});
|
||||
|
||||
it('存在待持久化增量时结束事件仍立即落盘', () => {
|
||||
const sessionId = 'terminal-persist';
|
||||
const store = useAgentTryoutRawRounds({
|
||||
mode: 'draft',
|
||||
sessionId,
|
||||
});
|
||||
const roundId = store.createRound('结束测试');
|
||||
|
||||
store.recordEvent(roundId, {
|
||||
domain: 'LLM',
|
||||
payload: { reasoning: '思考中' },
|
||||
type: 'THINKING',
|
||||
});
|
||||
store.recordEvent(roundId, {
|
||||
domain: 'SYSTEM',
|
||||
payload: {},
|
||||
type: 'DONE',
|
||||
});
|
||||
|
||||
const restored = useAgentTryoutRawRounds({
|
||||
mode: 'draft',
|
||||
sessionId,
|
||||
});
|
||||
expect(restored.currentVariant(roundId)?.status).toBe('completed');
|
||||
expect(
|
||||
restored
|
||||
.currentVariant(roundId)
|
||||
?.runtimeEvents.some(
|
||||
(event) => event.domain === 'SYSTEM' && event.type === 'DONE',
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user