From d305ca0cf9406bba2fa9956a13093d187ff66e22 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Fri, 29 May 2026 06:32:15 -0700 Subject: [PATCH] Remove quick agent selection repair effect --- .../components/NewWorkspaceComposerModal.tsx | 34 +++++------- .../quick-workspace-agent-selection.test.ts | 51 ++++++++++++++++- .../lib/quick-workspace-agent-selection.ts | 55 ++++++++++++++++++- 3 files changed, 119 insertions(+), 21 deletions(-) diff --git a/src/renderer/src/components/NewWorkspaceComposerModal.tsx b/src/renderer/src/components/NewWorkspaceComposerModal.tsx index d856e0cece8..cae22aa3b10 100644 --- a/src/renderer/src/components/NewWorkspaceComposerModal.tsx +++ b/src/renderer/src/components/NewWorkspaceComposerModal.tsx @@ -4,8 +4,10 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/u import NewWorkspaceComposerCard from '@/components/NewWorkspaceComposerCard' import AgentSettingsDialog from '@/components/agent/AgentSettingsDialog' import { useComposerState } from '@/hooks/useComposerState' -import { isTuiAgentEnabled } from '../../../shared/tui-agent-selection' -import { pickQuickWorkspaceAgent } from '@/lib/quick-workspace-agent-selection' +import { + pickQuickWorkspaceAgent, + resolveQuickWorkspaceAgentSelection +} from '@/lib/quick-workspace-agent-selection' import type { LinkedWorkItemSummary } from '@/lib/new-workspace' import { shouldAllowComposerEnterSubmitTarget } from '@/lib/new-workspace-enter-guard' import { isScreenSubmitShortcut } from '@/lib/screen-submit-shortcut' @@ -143,24 +145,18 @@ function QuickTabBody({ // prior catalog fallback while filtering disabled agents out of that choice. return pickQuickWorkspaceAgent(pref, cardProps.detectedAgentIds, settings?.disabledTuiAgents) }, [cardProps.detectedAgentIds, settings?.defaultTuiAgent, settings?.disabledTuiAgents]) - const quickAgent = quickAgentOverride === undefined ? preferredQuickAgent : quickAgentOverride - - useEffect(() => { - if ( - quickAgentOverride === undefined || - quickAgentOverride === null || - (isTuiAgentEnabled(quickAgentOverride, settings?.disabledTuiAgents) && - (cardProps.detectedAgentIds === null || cardProps.detectedAgentIds.has(quickAgentOverride))) - ) { - return - } - setQuickAgentOverride(preferredQuickAgent) - }, [ - cardProps.detectedAgentIds, - preferredQuickAgent, + const resolvedQuickAgentSelection = resolveQuickWorkspaceAgentSelection({ quickAgentOverride, - settings?.disabledTuiAgents - ]) + preferredQuickAgent, + detectedAgentIds: cardProps.detectedAgentIds, + disabledTuiAgents: settings?.disabledTuiAgents + }) + if (resolvedQuickAgentSelection.quickAgentOverride !== quickAgentOverride) { + // Why: detection/settings changes can invalidate a user-picked agent; repair + // before the child selector renders an unavailable option for one commit. + setQuickAgentOverride(resolvedQuickAgentSelection.quickAgentOverride) + } + const quickAgent = resolvedQuickAgentSelection.quickAgent const handleQuickAgentChange = useCallback((agent: TuiAgent | null) => { setQuickAgentOverride(agent) diff --git a/src/renderer/src/lib/quick-workspace-agent-selection.test.ts b/src/renderer/src/lib/quick-workspace-agent-selection.test.ts index b67231ebb7d..69af0807425 100644 --- a/src/renderer/src/lib/quick-workspace-agent-selection.test.ts +++ b/src/renderer/src/lib/quick-workspace-agent-selection.test.ts @@ -1,7 +1,10 @@ import { describe, expect, it } from 'vitest' import { TUI_AGENT_AUTO_PICK_ORDER } from '../../../shared/tui-agent-selection' import { AGENT_CATALOG } from './agent-catalog' -import { pickQuickWorkspaceAgent } from './quick-workspace-agent-selection' +import { + pickQuickWorkspaceAgent, + resolveQuickWorkspaceAgentSelection +} from './quick-workspace-agent-selection' describe('pickQuickWorkspaceAgent', () => { it('keeps the fallback order in sync with the desktop agent catalog', () => { @@ -25,3 +28,49 @@ describe('pickQuickWorkspaceAgent', () => { expect(pickQuickWorkspaceAgent('codex', ['claude', 'codex'], ['codex'])).toBe('claude') }) }) + +describe('resolveQuickWorkspaceAgentSelection', () => { + it('uses the preferred quick agent until the user picks an override', () => { + expect( + resolveQuickWorkspaceAgentSelection({ + quickAgentOverride: undefined, + preferredQuickAgent: 'claude', + detectedAgentIds: ['claude', 'codex'], + disabledTuiAgents: [] + }) + ).toEqual({ quickAgent: 'claude', quickAgentOverride: undefined }) + }) + + it('keeps explicit blank overrides stable', () => { + expect( + resolveQuickWorkspaceAgentSelection({ + quickAgentOverride: null, + preferredQuickAgent: 'claude', + detectedAgentIds: ['claude'], + disabledTuiAgents: [] + }) + ).toEqual({ quickAgent: null, quickAgentOverride: null }) + }) + + it('keeps an available user override', () => { + expect( + resolveQuickWorkspaceAgentSelection({ + quickAgentOverride: 'codex', + preferredQuickAgent: 'claude', + detectedAgentIds: new Set(['claude', 'codex']), + disabledTuiAgents: [] + }) + ).toEqual({ quickAgent: 'codex', quickAgentOverride: 'codex' }) + }) + + it('replaces an unavailable override with the preferred quick agent', () => { + expect( + resolveQuickWorkspaceAgentSelection({ + quickAgentOverride: 'codex', + preferredQuickAgent: 'claude', + detectedAgentIds: ['claude'], + disabledTuiAgents: [] + }) + ).toEqual({ quickAgent: 'claude', quickAgentOverride: 'claude' }) + }) +}) diff --git a/src/renderer/src/lib/quick-workspace-agent-selection.ts b/src/renderer/src/lib/quick-workspace-agent-selection.ts index b17d4f65999..51fe886e7eb 100644 --- a/src/renderer/src/lib/quick-workspace-agent-selection.ts +++ b/src/renderer/src/lib/quick-workspace-agent-selection.ts @@ -1,5 +1,9 @@ import type { TuiAgent } from '../../../shared/types' -import { pickTuiAgent, TUI_AGENT_AUTO_PICK_ORDER } from '../../../shared/tui-agent-selection' +import { + isTuiAgentEnabled, + pickTuiAgent, + TUI_AGENT_AUTO_PICK_ORDER +} from '../../../shared/tui-agent-selection' export function pickQuickWorkspaceAgent( preferred: TuiAgent | 'blank' | null | undefined, @@ -9,3 +13,52 @@ export function pickQuickWorkspaceAgent( const candidates = detectedAgentIds ?? TUI_AGENT_AUTO_PICK_ORDER return pickTuiAgent(preferred, candidates, disabledTuiAgents) } + +function hasDetectedAgent(detectedAgentIds: Iterable, agent: TuiAgent): boolean { + if (detectedAgentIds instanceof Set) { + return detectedAgentIds.has(agent) + } + for (const detectedAgentId of detectedAgentIds) { + if (detectedAgentId === agent) { + return true + } + } + return false +} + +function isQuickWorkspaceAgentAvailable( + agent: TuiAgent, + detectedAgentIds: Iterable | null, + disabledTuiAgents?: Iterable | null +): boolean { + if (!isTuiAgentEnabled(agent, disabledTuiAgents)) { + return false + } + return detectedAgentIds === null || hasDetectedAgent(detectedAgentIds, agent) +} + +export function resolveQuickWorkspaceAgentSelection({ + quickAgentOverride, + preferredQuickAgent, + detectedAgentIds, + disabledTuiAgents +}: { + quickAgentOverride: TuiAgent | null | undefined + preferredQuickAgent: TuiAgent | null + detectedAgentIds: Iterable | null + disabledTuiAgents?: Iterable | null +}): { + quickAgent: TuiAgent | null + quickAgentOverride: TuiAgent | null | undefined +} { + if (quickAgentOverride === undefined || quickAgentOverride === null) { + return { + quickAgent: quickAgentOverride === undefined ? preferredQuickAgent : null, + quickAgentOverride + } + } + if (isQuickWorkspaceAgentAvailable(quickAgentOverride, detectedAgentIds, disabledTuiAgents)) { + return { quickAgent: quickAgentOverride, quickAgentOverride } + } + return { quickAgent: preferredQuickAgent, quickAgentOverride: preferredQuickAgent } +}