mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
fix(runtime): only override a paired host's agent args when the client chose one
Forwarding the client's fully-resolved args made an unconfigured client push the built-in YOLO default onto a host whose own Agent Permissions say Manual. Send the override only when the caller passed args or the user actually configured a mode for this agent; otherwise stay silent and keep the host's choice. Manual's empty string still rides the wire, which is the #15373 fix.
This commit is contained in:
@@ -93,10 +93,11 @@ describe('launchAgentInNewTab paired web runtime', () => {
|
||||
activate: true,
|
||||
agentSessionKind: 'fresh',
|
||||
agent: 'claude',
|
||||
// Why: the client resolves its default explicitly so the host cannot apply its own.
|
||||
agentArgs: '--dangerously-skip-permissions',
|
||||
viewMode: 'terminal'
|
||||
})
|
||||
// Why (#15373): an unconfigured client must not push the built-in YOLO default onto a host
|
||||
// whose own Agent Permissions say Manual; omission keeps the host's choice.
|
||||
expect(mocks.createWebRuntimeSessionTerminal.mock.calls[0]?.[0]).not.toHaveProperty('agentArgs')
|
||||
expect(mocks.createTab).not.toHaveBeenCalled()
|
||||
await Promise.resolve()
|
||||
expect(mocks.setActiveTabType).toHaveBeenCalledWith('terminal')
|
||||
@@ -159,4 +160,22 @@ describe('launchAgentInNewTab paired web runtime', () => {
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('forwards caller-supplied agent args even when the client has no configured default', async () => {
|
||||
const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab')
|
||||
|
||||
launchAgentInNewTab({
|
||||
agent: 'claude',
|
||||
worktreeId: 'wt-1',
|
||||
groupId: 'group-1',
|
||||
agentArgs: '--permission-mode plan'
|
||||
})
|
||||
|
||||
expect(mocks.createWebRuntimeSessionTerminal).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
agent: 'claude',
|
||||
agentArgs: '--permission-mode plan'
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -17,6 +17,7 @@ import { getLocalProjectExecutionRuntimeContext } from '@/lib/local-preflight-co
|
||||
import { isWebRuntimeSessionActive } from '@/runtime/web-runtime-session'
|
||||
import { launchAgentInWebHostTab } from '@/lib/launch-agent-web-host-tab'
|
||||
import {
|
||||
hasConfiguredTuiAgentLaunchArgs,
|
||||
resolveTuiAgentLaunchArgs,
|
||||
resolveTuiAgentLaunchEnv
|
||||
} from '../../../shared/tui-agent-launch-defaults'
|
||||
@@ -106,6 +107,14 @@ export function launchAgentInNewTab(args: LaunchAgentInNewTabArgs): LaunchAgentI
|
||||
agentArgs !== undefined
|
||||
? agentArgs
|
||||
: resolveTuiAgentLaunchArgs(agent, store.settings?.agentDefaultArgs)
|
||||
// Why (#15373): a paired host re-resolves omitted args against its own settings, so a client that
|
||||
// actually chose a permission mode must send it — including Manual's empty string. An unconfigured
|
||||
// client has chosen nothing, so stay silent rather than forcing the built-in YOLO default on the host.
|
||||
const pairedHostAgentArgs =
|
||||
agentArgs !== undefined ||
|
||||
hasConfiguredTuiAgentLaunchArgs(agent, store.settings?.agentDefaultArgs)
|
||||
? effectiveAgentArgs
|
||||
: undefined
|
||||
const agentEnv = resolveTuiAgentLaunchEnv(agent, store.settings?.agentDefaultEnv)
|
||||
const trimmedPrompt = prompt?.trim() ?? ''
|
||||
const hasPrompt = trimmedPrompt.length > 0
|
||||
@@ -157,9 +166,7 @@ export function launchAgentInNewTab(args: LaunchAgentInNewTabArgs): LaunchAgentI
|
||||
promptDelivery,
|
||||
pastePromptAfterReady: pasteDraftAfterLaunch,
|
||||
submitPastedPrompt,
|
||||
// Why: the raw param is undefined on ordinary UI launches, so omission let a headless host apply its
|
||||
// own YOLO default (#15373). Send the resolved value — present-but-empty is an explicit no-args override.
|
||||
agentArgs: effectiveAgentArgs,
|
||||
agentArgs: pairedHostAgentArgs,
|
||||
// Why: omission means terminal locally, but would let a paired host apply
|
||||
// its own default; send the client's resolved terminal choice explicitly.
|
||||
viewMode: initialViewModeProps.viewMode ?? 'terminal',
|
||||
|
||||
@@ -79,16 +79,24 @@ export function getTuiAgentDefaultEnv(agent: TuiAgent): Record<string, string> {
|
||||
return { ...DEFAULT_TUI_AGENT_ENV[agent] }
|
||||
}
|
||||
|
||||
/** Manual is stored as `''`, so the key's presence — not its truthiness — is the user's explicit choice. */
|
||||
export function hasConfiguredTuiAgentLaunchArgs(
|
||||
agent: TuiAgent,
|
||||
configuredArgs: Partial<Record<TuiAgent, string>> | null | undefined
|
||||
): boolean {
|
||||
return Boolean(
|
||||
configuredArgs &&
|
||||
Object.hasOwn(configuredArgs, agent) &&
|
||||
typeof configuredArgs[agent] === 'string'
|
||||
)
|
||||
}
|
||||
|
||||
export function resolveTuiAgentLaunchArgs(
|
||||
agent: TuiAgent,
|
||||
configuredArgs: Partial<Record<TuiAgent, string>> | null | undefined
|
||||
): string {
|
||||
if (
|
||||
configuredArgs &&
|
||||
Object.hasOwn(configuredArgs, agent) &&
|
||||
typeof configuredArgs[agent] === 'string'
|
||||
) {
|
||||
return configuredArgs[agent] ?? ''
|
||||
if (hasConfiguredTuiAgentLaunchArgs(agent, configuredArgs)) {
|
||||
return configuredArgs?.[agent] ?? ''
|
||||
}
|
||||
return getTuiAgentDefaultArgs(agent)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user