fix: send queued messages to the original session

Prevents queued messages from being sent to a newly opened session
Adds explicit session targeting for queued auto-send
Covers the behavior with a unit test
This commit is contained in:
Bohdan Triapitsyn
2026-05-25 00:29:52 +03:00
parent 16d8fcd408
commit 73ab36bc91
4 changed files with 173 additions and 88 deletions
@@ -3,6 +3,7 @@ import type { Agent } from '@opencode-ai/sdk/v2';
import type { QueuedMessage } from '../stores/messageQueueStore';
let visibleAgents: Agent[] = [];
const sendMessageCalls: unknown[][] = [];
const getVisibleAgentsMock = mock(() => visibleAgents);
@@ -14,11 +15,24 @@ mock.module('@/stores/useConfigStore', () => ({
},
}));
import { buildQueuedAutoSendPayload } from './useQueuedMessageAutoSend';
mock.module('@/sync/session-ui-store', () => ({
useSessionUIStore: {
getState: () => ({
sendMessage: (...args: unknown[]) => {
sendMessageCalls.push(args);
return Promise.resolve();
},
sessionAbortFlags: new Map(),
}),
},
}));
import { buildQueuedAutoSendPayload, sendQueuedAutoSendPayload } from './useQueuedMessageAutoSend';
describe('buildQueuedAutoSendPayload', () => {
beforeEach(() => {
visibleAgents = [];
sendMessageCalls.length = 0;
});
test('returns only the first queued message for auto-send', () => {
@@ -101,4 +115,36 @@ describe('buildQueuedAutoSendPayload', () => {
expect(payload?.primaryAttachments).toHaveLength(1);
expect(payload?.primaryAttachments[0]?.filename).toBe('notes.txt');
});
test('auto-send targets the queued session explicitly', async () => {
const payload = buildQueuedAutoSendPayload([
{
id: 'queued-1',
content: 'queued message',
createdAt: 1,
},
]);
expect(payload).not.toBeNull();
await sendQueuedAutoSendPayload('session-original', payload!, {
providerID: 'provider-1',
modelID: 'model-1',
agent: 'agent-1',
variant: 'variant-1',
});
expect(sendMessageCalls.length).toBe(1);
expect(sendMessageCalls[0]).toEqual([
'queued message',
'provider-1',
'model-1',
'agent-1',
[],
undefined,
undefined,
'variant-1',
'normal',
{ sessionId: 'session-original' },
]);
});
});
@@ -38,6 +38,33 @@ export const buildQueuedAutoSendPayload = (queue: QueuedMessage[]) => {
};
};
type QueuedAutoSendPayload = NonNullable<ReturnType<typeof buildQueuedAutoSendPayload>>;
type ResolvedQueuedSendConfig = {
providerID: string;
modelID: string;
agent?: string;
variant?: string;
};
export const sendQueuedAutoSendPayload = (
sessionId: string,
payload: QueuedAutoSendPayload,
resolved: ResolvedQueuedSendConfig,
) => {
return useSessionUIStore.getState().sendMessage(
payload.primaryText,
resolved.providerID,
resolved.modelID,
resolved.agent,
payload.primaryAttachments,
payload.agentMentionName,
undefined,
resolved.variant,
'normal',
{ sessionId },
);
};
const resolveSessionSendConfig = (sessionId: string) => {
const context = useContextStore.getState();
const config = useConfigStore.getState();
@@ -128,17 +155,12 @@ export function useQueuedMessageAutoSend(enabledOrOptions?: boolean | { enabled?
inFlightSessionsRef.current.add(sessionId);
try {
await useSessionUIStore.getState().sendMessage(
payload.primaryText,
resolved.providerID,
resolved.modelID,
resolved.agent,
payload.primaryAttachments,
payload.agentMentionName,
undefined,
resolved.variant,
'normal'
);
await sendQueuedAutoSendPayload(sessionId, payload, {
providerID: resolved.providerID,
modelID: resolved.modelID,
agent: resolved.agent,
variant: resolved.variant,
});
const removeFromQueue = useMessageQueueStore.getState().removeFromQueue;
removeFromQueue(sessionId, payload.queuedMessageId);