Repository navigation
fix(agents): apply paired host preferences to launch menus - #31971
Conversation
📝 Walkthrough
Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: 🟡 Moderate · up to
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
217f189b-908e-4b09-9f8c-720a1fa17685
📒 Files selected for processing: 4
src/renderer/src/components/settings/agent-launch-settings-transport.tssrc/renderer/src/components/settings/use-host-agent-launch-preferences.tssrc/renderer/src/components/tab-bar/use-new-tab-agent-menu-host-preferences.test.tsxsrc/renderer/src/components/tab-bar/use-new-tab-agent-menu-rows.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.
| AGENT_LAUNCH_SETTINGS_CAPABILITY, | ||
| 15_000 |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
sed -n '1,145p' src/renderer/src/components/settings/agent-launch-settings-transport.ts
sed -n '1,115p' src/renderer/src/components/settings/use-host-agent-launch-preferences.ts
rg -n 'function runtimeEnvironmentSupportsCapability|const runtimeEnvironmentSupportsCapability|preferencesPending|inventoryReady' src/renderer/src/componentsRepository: stablyai/orca
Length of output: 7199
Bound the combined host-settings read deadline.
When the paired host responds slowly, readHostAgentLaunchSettings can spend 15 seconds in the capability check and then another 15 seconds in settings.getAgentLaunch. useHostAgentMenuSettings keeps pending true until both operations settle, so the new-tab menu can remain in its loading state for about 30 seconds while inventoryReady remains false.
Use one 15-second deadline for both operations and pass the remaining time to the RPC.
♻️ Suggested fix
export async function readHostAgentLaunchSettings(
owner: AgentLaunchSettingsOwner,
signal?: AbortSignal
): Promise<AgentLaunchSettings | null> {
+ const deadline = Date.now() + 15_000
if (
!(await runtimeEnvironmentSupportsCapability(
owner.environmentId,
AGENT_LAUNCH_SETTINGS_CAPABILITY,
- 15_000
+ Math.max(1, deadline - Date.now())
))
) {
return null
}
...
- timeoutMs: 15_000
+ timeoutMs: Math.max(1, deadline - Date.now())35bd4b8 to
d655c66
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments: 1
src/renderer/src/components/terminal-agent-tab-shortcut.ts: 1
29-29: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winDefer the preference read until an agent shortcut needs it.
handleTerminalWorkspaceKeyDowncalls this resolver for each non-repeating keydown that reaches the agent-shortcut block. The resolver reads preferences before matchingtab.newAgent. That read callsbuildAgentLaunchRouteInput, which resolves the execution host, capabilities, and project runtime. Most keydowns do not use the preferences, so this can add unnecessary route-resolution work to ordinary key handling.Read preferences inside the
tab.newAgentbranch. Before the bound-agent loop, read them only whenlistBoundAgentTabActions(keybindings, undefined)finds at least one agent binding.♻️ Suggested fix
- const preferences = readAgentLaunchPreferencesForWorktree(state, activeWorktreeId) if (matchShortcut('tab.newAgent')) { + const preferences = readAgentLaunchPreferencesForWorktree(state, activeWorktreeId) const agent = resolveDefaultAgentForNewTab({ ...preferences, detectedAgentIds: readDetectedAgentsForWorktree(state, activeWorktreeId) @@ - for (const bound of listBoundAgentTabActions(keybindings, preferences.disabledTuiAgents)) { - if (matchShortcut(bound.actionId)) { - return { actionId: bound.actionId, agent: bound.agent } + if (listBoundAgentTabActions(keybindings, undefined).length > 0) { + const preferences = readAgentLaunchPreferencesForWorktree(state, activeWorktreeId) + for (const bound of listBoundAgentTabActions(keybindings, preferences.disabledTuiAgents)) { + if (matchShortcut(bound.actionId)) { + return { actionId: bound.actionId, agent: bound.agent } + } } }
ℹ️ Review info
⚙️ Run configuration
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
ee4a0953-3914-497c-8bc7-17dc15347e39
📥 Commits
Reviewing files that changed from the base of the PR and between 35bd4b8 and d655c66680c9f904b6d8c0323645ddabc884802e.
📒 Files selected for processing: 6
src/renderer/src/components/settings/use-host-agent-launch-preferences.tssrc/renderer/src/components/tab-bar/QuickLaunchButton.tsxsrc/renderer/src/components/tab-bar/use-new-tab-agent-menu-host-preferences.test.tsxsrc/renderer/src/components/tab-bar/use-new-tab-agent-menu-rows.tssrc/renderer/src/components/terminal-agent-tab-shortcut.tssrc/renderer/src/lib/agent-tab-shortcuts.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.
| getState: () => AppState, | ||
| worktreeId: string | ||
| ): Promise<TuiAgent | null> { | ||
| const detectedAgentIds = await loadDetectedAgentsForWorktree(getState(), worktreeId) | ||
| // Why: settings may change while the host answers; pick with the current ones. | ||
| const state = getState() | ||
| // Why: preferences may change while the host answers; pick with the current ones. | ||
| return resolveDefaultAgentForNewTab({ | ||
| defaultTuiAgent: state.settings?.defaultTuiAgent, | ||
| detectedAgentIds, | ||
| disabledTuiAgents: state.settings?.disabledTuiAgents | ||
| ...readAgentLaunchPreferencesForWorktree(getState(), worktreeId), | ||
| detectedAgentIds |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🔎 Supported by static analysis
🏁 Script executed:
sed -n '1,115p' src/renderer/src/lib/agent-tab-shortcuts.ts
sed -n '1,175p' src/renderer/src/components/settings/use-host-agent-launch-preferences.ts
rg -n 'resolveDefaultAgentForWorktreeNewTab|readAgentLaunchPreferencesForWorktree|useHostAgentMenuSettings' src/renderer/srcRepository: stablyai/orca
Length of output: 11641
🏁 Script executed:
sed -n '1,200p' src/renderer/src/components/settings/agent-launch-settings-transport.ts
echo '--- callers ---'
rg -n -F -e 'readHostAgentLaunchSettings' -e 'subscribeHostAgentLaunchSettings' -e 'notifyHostAgentLaunchSettings' -- src/renderer/src || test "$?" -eq 1
echo '--- shortcut ---'
sed -n '1,80p' src/renderer/src/components/terminal-agent-tab-shortcut.tsRepository: stablyai/orca
Length of output: 7485
Cold host-preference cache makes the new-agent shortcut use desktop settings for paired servers.
On a paired-server workspace, the tab.newAgent shortcut can choose an agent from desktop preferences instead of the host's. This happens when no menu has loaded that host's launch settings in the current app session, or when host settings were saved and no menu has reloaded them since. The shortcut then pairs host-detected agents with the desktop default and disabled list. It can launch an agent the host has disabled, or skip the host's default. Opening the + menu once for that host restores host preferences.
The shortcut reads only the in-memory cache. It never requests the host's settings. Add a host read on a cache miss for runtime hosts. Await that read in the shortcut path, the same way detection is awaited, and store the result in the cache before choosing an agent.
…s instantly Hosts without settings.agent-launch.v1 (before 2026-10-11) cannot store launch preferences, so their menus keep the desktop's visibility and default instead of losing both. Cache the last host answer per environment so freshly mounted menus render at once and revalidate; host-settings saves invalidate the cache. Co-Authored-By: Claude <noreply@anthropic.com>
…read The tab.newAgent shortcut, its menu badge, and bound per-agent shortcuts now use the same per-host preference snapshot as the menu. A first read that fails or stalls past 3s falls back to desktop preferences (pre-PR behavior) instead of a neutral order or a long placeholder; a late answer still applies. Co-Authored-By: Claude <noreply@anthropic.com>
d655c66 to
8f48a76
Compare
Resolve conflicts with #31971 (paired host launch preferences) and #28569 (Resolve with AI): the + menu, new-agent shortcut and default-agent pick use the host's disabled list and default together with the host chat program answer; the Source Control dialog uses main's availability helper over the PR's launchable agents. Main's new auto-start test lands its detected agents in the store the dialog reads.
ELI5
When you open + / New tab in a workspace that lives on a paired server, Orca lists the agents installed on that server, but it hid and ordered them using this desktop's Settings -> Agents choices. So an agent you disabled for the server still showed up, and the server's default agent wasn't first.
Now the menu, the new-agent keyboard shortcut, and the shortcut badge in the menu all use the server's own disabled list and default (the ones you edit under Settings -> Agents -> Host: ). Local workspaces are unchanged. If the server can't answer quickly, Orca uses this desktop's choices, the same as before this PR.
What changes for the user
tab.newAgentshortcut launches that same default, and the badge marks that row.settings.agent-launch.v1, added by Edit agent launch settings on the workspace host #26479): nothing changes. The menu and shortcut keep using the desktop's choices.What Changed
use-host-agent-launch-preferences.ts: readssettings.getAgentLaunchthrough the existing transport and capability check, keyed by environment + pairing revision + runtime id. Late answers after a host switch, restart, or re-pair are ignored. A per-environment snapshot cache lets freshly mounted menus render without waiting on an RPC; host-settings saves invalidate it. A 3s first-read deadline falls back to desktop preferences.readAgentLaunchPreferencesForWorktreeexposes the same snapshot synchronously.terminal-agent-tab-shortcut.ts/agent-tab-shortcuts.ts:tab.newAgent, its async fallback, and per-agent bound shortcuts read that snapshot, so the shortcut launches what the menu shows first.use-new-tab-agent-menu-rows.ts/QuickLaunchButton.tsx: the menu model uses host-aware preferences and carries its default, so the shortcut badge marks the same row.agent-launch-settings-transport.ts: reads pin the runtime id, bound the capability probe to 15s, and successful saves notify listeners.No new RPC, wire field, capability, or settings schema.
Linked Issue
Fixes #31889
Verification
main(28c7268, which includes the main typecheck/lint fix fix(runtime): main lints and typechecks again after #32018 #32168) with no conflicts.RuntimeClient:status.get75ms, advertisessettings.agent-launch.v1;settings.getAgentLaunchanswered in 10ms with{"defaultTuiAgent":"claude","disabledTuiAgents":[]}. That is far under the 3s deadline, so a healthy host never shows desktop preferences first.Unknown method: settings.getAgentLaunch. The hook checks the capability first and keeps desktop preferences, so this mixed-version case does not regress.orca serveruntime with independent profiles on macOS (screenshots below). Desktop: OpenCode default, Codex disabled. Server: Codex default, OpenCode disabled.pnpm teston tab-bar, settings, shortcut, and keydown suites: 2,519 tests in 337 files plus the 2 keydown/shortcut suites (31 tests) pass. oxlint, oxfmt, and the changed-code quality gate pass.pnpm tcpassed for every touched file; the one error before the rebase came frommainand is fixed by fix(runtime): main lints and typechecks again after #32018 #32168.Before: OpenCode first and Codex absent (desktop preferences applied to the server menu).
After: Codex first and OpenCode absent. OpenCode 2 is a distinct enabled agent.
Risks / tradeoffs
Related PRs
No external contributor PRs address this issue (searched open/closed PRs for the issue number and host menu preferences).
Agent skill upstream boundary