From cc9ea7c71827d3e165ec24e1d8a722b3e72b6c15 Mon Sep 17 00:00:00 2001 From: mesalogo Date: Wed, 16 Sep 2026 16:35:13 +0800 Subject: [PATCH] fix: prevent send queue flicker when the agent is idle Claim idle conversation inputs before publishing queue changes so immediately dispatched messages do not briefly appear as pending. Preserve busy conversation queueing and add a regression assertion for notification ordering. Validation: 369 focused tests, typecheck, and changed-file lint passed. Full-suite runs timed out with failures in other modules; repository lint reports errors in the existing story-graph demo. Release note: Fix a brief pending-queue flash when sending a message while the agent is idle. --- src/main/ipc.test.ts | 20 ++++++++++++++------ src/main/ipc.ts | 7 +++---- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/ipc.test.ts b/src/main/ipc.test.ts index 5baed4e6..722e5148 100644 --- a/src/main/ipc.test.ts +++ b/src/main/ipc.test.ts @@ -7342,7 +7342,7 @@ describe('registerIpcHandlers agent terminal state', () => { await harness.dispose() }) - it('dispatches and accepts a queued user message through the renderer', async () => { + it('claims an idle user message before notifying the renderer and accepts its dispatch', async () => { const runtime = { runtimeId: 'model', capability: 'chat', @@ -7406,14 +7406,22 @@ describe('registerIpcHandlers agent terminal state', () => { const enqueueHandler = electronMocks.handlers.get( ipcChannels.conversationQueueEnqueueUser ) + harness.webContents.send.mockClear() expect( enqueueHandler?.(trustedEvent(harness.webContents), input) ).toEqual(item) - await vi.waitFor(() => - expect(harness.webContents.send).toHaveBeenCalledWith( - ipcChannels.conversationQueueDispatch, - { item, input } - ) + expect(harness.webContents.send).toHaveBeenCalledWith( + ipcChannels.conversationQueueDispatch, + { item, input } + ) + const queueChangeIndex = harness.webContents.send.mock.calls.findIndex( + ([channel]) => channel === ipcChannels.conversationQueueChanged + ) + expect(queueChangeIndex).toBeGreaterThanOrEqual(0) + expect( + harness.assistantDatabase.claimConversationQueueItem.mock.invocationCallOrder[0] + ).toBeLessThan( + harness.webContents.send.mock.invocationCallOrder[queueChangeIndex] ?? 0 ) await harness.handler?.(trustedEvent(harness.webContents), { diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 26f606cf..ecd8c507 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -6947,13 +6947,12 @@ export function registerIpcHandlers( contextManager.remove(attachment.id) } rendererReadyConversationQueues.add(item.conversationId) - publishConversationQueueChange(item.conversationId) if (!isConversationExecuting(item.conversationId)) { readyConversationQueues.add(item.conversationId) - setTimeout(() => { - void pumpConversationQueue(item.conversationId) - }, 0) + // Claim idle sends before exposing pending items to the renderer. + void pumpConversationQueue(item.conversationId) } + publishConversationQueueChange(item.conversationId) return item } )