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>, }, })); 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'); }); });