refactor(chat): execution graph optimize (#873)
Co-authored-by: Haze <hazeone@users.noreply.github.com>
This commit is contained in:
140
tests/unit/chat-event-dedupe.test.ts
Normal file
140
tests/unit/chat-event-dedupe.test.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { extractText } from '@/pages/Chat/message-utils';
|
||||
|
||||
const { gatewayRpcMock, hostApiFetchMock, agentsState } = vi.hoisted(() => ({
|
||||
gatewayRpcMock: vi.fn(),
|
||||
hostApiFetchMock: vi.fn(),
|
||||
agentsState: {
|
||||
agents: [] as Array<Record<string, unknown>>,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/gateway', () => ({
|
||||
useGatewayStore: {
|
||||
getState: () => ({
|
||||
status: { state: 'running', port: 18789 },
|
||||
rpc: gatewayRpcMock,
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/agents', () => ({
|
||||
useAgentsStore: {
|
||||
getState: () => agentsState,
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/host-api', () => ({
|
||||
hostApiFetch: (...args: unknown[]) => hostApiFetchMock(...args),
|
||||
}));
|
||||
|
||||
describe('chat event dedupe', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
window.localStorage.clear();
|
||||
gatewayRpcMock.mockReset();
|
||||
hostApiFetchMock.mockReset();
|
||||
agentsState.agents = [];
|
||||
});
|
||||
|
||||
it('keeps processing delta events without seq for the same run', async () => {
|
||||
const { useChatStore } = await import('@/stores/chat');
|
||||
|
||||
useChatStore.setState({
|
||||
currentSessionKey: 'agent:main:main',
|
||||
currentAgentId: 'main',
|
||||
sessions: [{ key: 'agent:main:main' }],
|
||||
messages: [],
|
||||
sessionLabels: {},
|
||||
sessionLastActivity: {},
|
||||
sending: false,
|
||||
activeRunId: null,
|
||||
streamingText: '',
|
||||
streamingMessage: null,
|
||||
streamingTools: [],
|
||||
pendingFinal: true,
|
||||
lastUserMessageAt: null,
|
||||
pendingToolImages: [],
|
||||
error: null,
|
||||
loading: false,
|
||||
thinkingLevel: null,
|
||||
});
|
||||
|
||||
useChatStore.getState().handleChatEvent({
|
||||
state: 'delta',
|
||||
runId: 'run-no-seq',
|
||||
sessionKey: 'agent:main:main',
|
||||
message: {
|
||||
role: 'assistant',
|
||||
id: 'reply-stream',
|
||||
content: [{ type: 'text', text: 'Checked X.' }],
|
||||
},
|
||||
});
|
||||
|
||||
useChatStore.getState().handleChatEvent({
|
||||
state: 'delta',
|
||||
runId: 'run-no-seq',
|
||||
sessionKey: 'agent:main:main',
|
||||
message: {
|
||||
role: 'assistant',
|
||||
id: 'reply-stream',
|
||||
content: [
|
||||
{ type: 'text', text: 'Checked X.' },
|
||||
{ type: 'text', text: 'Checked X. Here is the summary.' },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
expect(extractText(useChatStore.getState().streamingMessage)).toBe('Checked X. Here is the summary.');
|
||||
});
|
||||
|
||||
it('still dedupes repeated delta events when seq matches', async () => {
|
||||
const { useChatStore } = await import('@/stores/chat');
|
||||
|
||||
useChatStore.setState({
|
||||
currentSessionKey: 'agent:main:main',
|
||||
currentAgentId: 'main',
|
||||
sessions: [{ key: 'agent:main:main' }],
|
||||
messages: [],
|
||||
sessionLabels: {},
|
||||
sessionLastActivity: {},
|
||||
sending: false,
|
||||
activeRunId: null,
|
||||
streamingText: '',
|
||||
streamingMessage: null,
|
||||
streamingTools: [],
|
||||
pendingFinal: false,
|
||||
lastUserMessageAt: null,
|
||||
pendingToolImages: [],
|
||||
error: null,
|
||||
loading: false,
|
||||
thinkingLevel: null,
|
||||
});
|
||||
|
||||
useChatStore.getState().handleChatEvent({
|
||||
state: 'delta',
|
||||
runId: 'run-with-seq',
|
||||
sessionKey: 'agent:main:main',
|
||||
seq: 3,
|
||||
message: {
|
||||
role: 'assistant',
|
||||
id: 'reply-stream',
|
||||
content: [{ type: 'text', text: 'first version' }],
|
||||
},
|
||||
});
|
||||
|
||||
useChatStore.getState().handleChatEvent({
|
||||
state: 'delta',
|
||||
runId: 'run-with-seq',
|
||||
sessionKey: 'agent:main:main',
|
||||
seq: 3,
|
||||
message: {
|
||||
role: 'assistant',
|
||||
id: 'reply-stream',
|
||||
content: [{ type: 'text', text: 'duplicate version should be ignored' }],
|
||||
},
|
||||
});
|
||||
|
||||
expect(extractText(useChatStore.getState().streamingMessage)).toBe('first version');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user