From 6a86ad7e363ea6c0251e96c40e2275f779c99ce5 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Sun, 4 Oct 2026 16:00:26 -0700 Subject: [PATCH] fix(native-chat): text sent to a new agent claims an empty starting chat only in its own split Notes sent from the right-hand split could land in, and focus, an empty chat still starting in the left-hand one. A request with text now claims an empty starting chat only in the tab group it opens in, the same rule a request without text follows; elsewhere it opens its own chat there. --- ...red-agent-session-empty-chat-reuse.test.ts | 33 ++++++++++++++++++- ...structured-agent-session-launch-holders.ts | 7 ++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/renderer/src/lib/structured-agent-session-empty-chat-reuse.test.ts b/src/renderer/src/lib/structured-agent-session-empty-chat-reuse.test.ts index aa267b764d5..9f4f2b0c459 100644 --- a/src/renderer/src/lib/structured-agent-session-empty-chat-reuse.test.ts +++ b/src/renderer/src/lib/structured-agent-session-empty-chat-reuse.test.ts @@ -103,7 +103,10 @@ vi.mock('@/store', () => ({ } })) -import { appendStructuredAgentSessionOutboxMessage } from '@/components/native-chat/structured-agent-session-outbox-storage' +import { + appendStructuredAgentSessionOutboxMessage, + readOutbox +} from '@/components/native-chat/structured-agent-session-outbox-storage' import { appendNativeChatAttachmentCache, clearNativeChatAttachmentCacheForTests @@ -452,6 +455,34 @@ describe('a "new chat" with text', () => { }) }) + it('opens its own chat in its own split beside an empty chat starting in another', () => { + mocks.launch.mockImplementation(() => new Promise(() => undefined)) + const blank = pick('plus-pick-1', { group: 'group-left' }) + + const notes = pick('notes-send', { prompt: 'review notes', group: 'group-right' }) + + expect(notes.sessionId).toBe(second.sessionId) + expect( + store.state.unifiedTabsByWorktree[WORKTREE_ID]?.find( + (tab) => tab.entityId === second.sessionId + )?.groupId + ).toBe('group-right') + expect(mocks.focusGroup).not.toHaveBeenCalled() + expect(readOutbox(blank.sessionId)).toEqual([]) + expect(readOutbox(second.sessionId).map((entry) => entry.body.blocks)).toEqual([ + [{ type: 'text', text: 'review notes' }] + ]) + }) + + it('takes an empty chat starting in its own split', () => { + mocks.launch.mockImplementation(() => new Promise(() => undefined)) + const blank = pick('plus-pick-1', { group: 'group-right' }) + + expect(pick('notes-send', { prompt: 'review notes', group: 'group-right' }).sessionId).toBe( + blank.sessionId + ) + }) + it('takes an empty chat still starting, as before', () => { mocks.launch.mockImplementation(() => new Promise(() => undefined)) const blank = pick('plus-pick-1') diff --git a/src/renderer/src/lib/structured-agent-session-launch-holders.ts b/src/renderer/src/lib/structured-agent-session-launch-holders.ts index 09081e8c01d..2b9b62a1473 100644 --- a/src/renderer/src/lib/structured-agent-session-launch-holders.ts +++ b/src/renderer/src/lib/structured-agent-session-launch-holders.ts @@ -67,8 +67,8 @@ export function claimableStructuredLaunchAttempt( return request.hasText ? emptyStructuredLaunchAttempt(state) : undefined } -/** The launch a new start of `request` joins: one it re-delivers, else an empty starting chat, which - * a request with text claims and one without reuses in its own tab group. The newest wins. */ +/** The launch a new start of `request` joins: one it re-delivers, else an empty starting chat in the + * tab group it opens in, which a request with text claims and one without reuses. The newest wins. */ export function getJoinableStructuredLaunchState( identity: string, request: StructuredLaunchRequest @@ -79,8 +79,7 @@ export function getJoinableStructuredLaunchState( structuredLaunchesHoldingIdentity(matches).findLast( (state) => emptyStructuredLaunchAttempt(state) && - (request.hasText || - !request.groupId || + (!request.groupId || structuredChatTabGroupId(state.intent.worktreeId, state.intent.sessionId) === request.groupId) )