Skip to content

fix(agents): apply paired host preferences to launch menus - #31971

Merged
nwparker merged 3 commits into
mainfrom
nwparker/host-agent-menu-preferences
Oct 23, 2026
Merged

nwparker merged 3 commits into
mainfrom
nwparker/host-agent-menu-preferences

Conversation

@nwparker

@nwparker nwparker commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​309 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​309
Prod 6 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​224 $\color{#cf222e}{\Huge{\mathbf{−}}}$​21 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​203

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

  • Server workspace, server is up to date: the menu hides the server's disabled agents and puts the server's default first. The tab.newAgent shortcut launches that same default, and the badge marks that row.
  • Server older than the host-settings feature (no 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.
  • Server unreachable, or no answer within 3s on the first read: desktop choices apply (pre-PR behavior) instead of a long placeholder. A late answer still updates the menu. A later failure keeps the last good answer.
  • Saving host settings updates an already-open menu.
  • Reopening a menu shows the last known host answer right away and refreshes it in the background.

What Changed

  • use-host-agent-launch-preferences.ts: reads settings.getAgentLaunch through 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. readAgentLaunchPreferencesForWorktree exposes 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

  • Rebased onto current main (28c7268, which includes the main typecheck/lint fix fix(runtime): main lints and typechecks again after #32018 #32168) with no conflicts.
  • Live read-only RPC against real paired servers, using this branch's CLI RuntimeClient:
    • awin (Windows, 1.4.237): status.get 75ms, advertises settings.agent-launch.v1; settings.getAgentLaunch answered in 10ms with {"defaultTuiAgent":"claude","disabledTuiAgents":[]}. That is far under the 3s deadline, so a healthy host never shows desktop preferences first.
    • win-lowspec (Windows, 1.4.205): does not advertise the capability; calling the method directly returns Unknown method: settings.getAgentLaunch. The hook checks the capability first and keeps desktop preferences, so this mixed-version case does not regress.
  • Original author: real hidden Electron desktop + a separate orca serve runtime with independent profiles on macOS (screenshots below). Desktop: OpenCode default, Codex disabled. Server: Codex default, OpenCode disabled.
  • Regression tests cover host switch/restart/re-pair fencing, save refresh, cached reopen, old hosts, first-read failure -> desktop order, stalled host -> desktop after 3s then the late host answer, and the shortcut/badge getting the host default.
  • pnpm test on 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 tc passed for every touched file; the one error before the rebase came from main and 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).

Before: desktop preferences incorrectly filter the server menu

After: Codex first and OpenCode absent. OpenCode 2 is a distinct enabled agent.

After: server preferences filter and order the menu

Risks / tradeoffs

  • On a host that takes more than 3s to answer the first read, the menu shows desktop order first and then reorders when the answer arrives. Measured healthy round trips are about 10ms.
  • The shortcut uses the cached host answer, which the workspace's tab bar fetches when the workspace is shown. If you press the shortcut before that first answer arrives, it uses desktop preferences, as it did before this PR.
  • Not exercised: a hidden Electron build paired to awin through the real UI. Pairing a new device would change awin's device list, and this pass kept the remote read-only. Mobile does not use this renderer menu. Legacy SSH-target menus are unchanged and still use desktop settings. The new-workspace composer's agent picker is a separate surface and still uses desktop settings.

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

  • Not applicable; this change copies no upstream skill-installer source or resources.

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Walkthrough

The new-tab agent menu now uses launch preferences associated with the workspace runtime. Settings reads include the expected runtime ID when available, and successful mutations notify subscribed listeners. The menu uses resolved host preferences for agent availability and the default agent, and waits for preference resolution before marking inventory ready. Terminal and worktree shortcut resolution also use worktree-specific launch preferences. Tests cover preference application, stale reads, refreshes, fallback behavior, and delayed responses.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: 🟡 Moderate · up to d655c

A paired-server shortcut can launch an agent disabled in host preferences or miss the host's default until its menu has loaded. Fix that shortcut path before merging; the menu no longer waits for the full settings timeout.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 7 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: applying paired host preferences to agent launch menus.
Linked Issues check Passed Issue #31889 requires the new-tab menu for a server-owned workspace to use the execution host's disabled-agent list and default agent. useHostAgentMenuSettings reads host launch settings for the det…
Out of Scope Changes check Passed The transport changes, capability timeout, cache invalidation, stale-read fencing, shortcut updates, menu integration, and regression tests support the host-preference behavior in issue #31889. The re…
Description check Passed The description is complete and relevant. It explains the user impact, implementation, rationale, linked issue, visual before/after evidence, testing, risks, platform limitations, and agent skill boun…
Full details: Linked Issues check

Explanation

Issue #31889 requires the new-tab menu for a server-owned workspace to use the execution host's disabled-agent list and default agent. useHostAgentMenuSettings reads host launch settings for the detected runtime and fences results by environment, pairing revision, and runtime ID. use-new-tab-agent-menu-rows.ts applies the host settings to filtering and ordering, and QuickLaunchButton.tsx uses the same resolved default for the badge. Shortcut resolution also reads the worktree host preferences. The added tests cover divergent host and desktop settings, unsupported hosts, failures, stale reads, cache reuse, saves, and late answers.

Full details: Out of Scope Changes check

Explanation

The transport changes, capability timeout, cache invalidation, stale-read fencing, shortcut updates, menu integration, and regression tests support the host-preference behavior in issue #31889. The reviewed changes do not establish an unrelated product change.

Full details: Description check

Explanation

The description is complete and relevant. It explains the user impact, implementation, rationale, linked issue, visual before/after evidence, testing, risks, platform limitations, and agent skill boundary. It uses Verification and Risks / tradeoffs headings instead of the template's Testing and Notes headings, and it omits the checklist, but the required information is still covered.

✨ Finishing Touches: 💡 2
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
📥 Commits

Reviewing files that changed from the base of the PR and between 8e96904 and 2d048a2.

📒 Files selected for processing: 4
  • src/renderer/src/components/settings/agent-launch-settings-transport.ts
  • src/renderer/src/components/settings/use-host-agent-launch-preferences.ts
  • src/renderer/src/components/tab-bar/use-new-tab-agent-menu-host-preferences.test.tsx
  • src/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.

Comment on lines +35 to +36
AGENT_LAUNCH_SETTINGS_CAPABILITY,
15_000

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 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/components

Repository: 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())

@nwparker
nwparker force-pushed the nwparker/host-agent-menu-preferences branch from 35bd4b8 to d655c66 Compare October 23, 2026 03:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments: 1
src/renderer/src/components/terminal-agent-tab-shortcut.ts: 1

29-29: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Defer the preference read until an agent shortcut needs it.

handleTerminalWorkspaceKeyDown calls this resolver for each non-repeating keydown that reaches the agent-shortcut block. The resolver reads preferences before matching tab.newAgent. That read calls buildAgentLaunchRouteInput, 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.newAgent branch. Before the bound-agent loop, read them only when listBoundAgentTabActions(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.ts
  • src/renderer/src/components/tab-bar/QuickLaunchButton.tsx
  • src/renderer/src/components/tab-bar/use-new-tab-agent-menu-host-preferences.test.tsx
  • src/renderer/src/components/tab-bar/use-new-tab-agent-menu-rows.ts
  • src/renderer/src/components/terminal-agent-tab-shortcut.ts
  • src/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.

Comment on lines +63 to +70
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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/src

Repository: 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.ts

Repository: 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.

nwparker and others added 3 commits October 22, 2026 21:01
…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>
@nwparker
nwparker force-pushed the nwparker/host-agent-menu-preferences branch from d655c66 to 8f48a76 Compare October 23, 2026 04:01
@nwparker
nwparker merged commit f4a1b05 into main Oct 23, 2026
33 checks passed
brennanb2025 added a commit that referenced this pull request Oct 23, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: New-tab agent menu uses desktop-local disabled/default preferences instead of the workspace server’s settings

1 participant