mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 18:47:40 +00:00
* Source control actions start chats and terminals on their saved model A "start an agent" action's model lived only in free-text CLI arguments, which a native chat never reads, so AI Fix opened a chat on the default model. Each action now saves a structured model and effort that both routes apply: chat create options, or the agent's own flags in a terminal (winning over the same flag in CLI arguments). Desktop, dialog, fix-checks and mobile launches carry it; Settings rows get Model/Effort selects and the CLI arguments field says it is terminal-only. Tracked in STA-11102. * Name the model in the repository override note * Type the dialog's model hand-off; keep Agent in English in Japanese copy * fix: preserve action chat model choices through launch * Preserve action selection ownership across chat launches * Keep terminal host contract fixtures aligned with preflight * fix: wait for action Settings agent inventory * fix: consolidate direct agent routing imports * fix: use standard action option labels * fix: align action launch contracts with shared types * fix: sync action option localization metadata * test: provide action Settings inventory in mounted fixtures * Keep action options row height stable while loading * Let each Source Control action choose its chat permission mode An action's saved chat choice may now carry a permission mode, with or without a model; "Same as new chats" saves nothing. A model is replaced only when the action names one, so a permission-only choice keeps the chat's remembered model and options. * fix(native-chat): leave older hosts their own permission mode and keep action options readable - An action's saved permission mode is sent only to hosts that advertise agentSession.create.options-mode.v1. Older hosts get no mode, in create options or a later setOption, so the chat starts on that host's new-chat default, as a phone launch to such a host already does. Hosts from 1.4.225 to 1.4.227 refused a mode their tables lacked (OpenCode, Grok, OMP), leaving the action unable to start. - Settings action rows give Model and Permissions full rows in the options column so saved values are readable; the loading placeholder reserves the same rows. - Remove two unused locale keys; fix two stale comments. - Tests: the older-host create carries no permission mode; a permission mode picked alone keeps the remembered model on an acquired create. * fix(settings): reserve one options row while loading an action with nothing saved Terminal and permissions-only rows no longer shrink when loading ends; a chat agent with a model list may grow by its Model row once known. * fix(native-chat): keep the create options mode a checked literal type * fix(settings): share verified action option fields * fix(settings): keep action selectors on standard typography * Keep the launch files under their length limits after the main merge The structured route imports its result types where they are defined, and the two older-host action-launch tests share one setup helper. * One action settings section for chat and terminal launches A Source Control action's Model, model options and Permissions now apply whether it opens a chat or a terminal; terminals receive them as the agent's own flags, and a repository's own CLI arguments keep the flags it sets. Extra CLI arguments stay terminal-only. * fix(source-control-ai): one terminal projection for saved action choices Ask in a terminal now states its permission instead of leaving it to the user's own config: Claude and Grok pass --permission-mode default, Codex passes -a on-request -s read-only -c approvals_reviewer="user" (the interactive CLI has no untrusted policy, so a read-only sandbox is what asks before edits). Agents whose CLI has no flag for a mode show the existing "Applies to chats only" hint. The strict launch-preferences projection now requires the launch agent at every caller, composes model ids through the resolver's own step, carries a mode only where the agent's terminal has a flag for it, and the local string wire keeps booleans as 'true'/'false', so Cursor Thinking/Fast reach the terminal and an OpenCode permission-only choice is not refused. The argument parser knows flag arity, so removing a boolean permission flag keeps other options' values, following positionals and '--'. Pre-admission and executor share one terminal admission check on the options the terminal will receive. Customize with Save launches the recipe as it will resolve once saved; legacy partial repository overrides are edited as the complete recipe they resolve to. Empty Extra CLI arguments start collapsed. * fix(source-control-ai): an edited repository action saves complete Every Settings edit of a repository action (agent, model, permission, prompt or arguments) now starts from the complete recipe the action resolves to, whether its stored override is owned or a legacy partial. The resolved agent selection is kept (never an agent only detected to run a default), an explicit null args clear stays null, and empty args stay empty instead of being dropped. Clearing the last preference therefore means the action agent's own defaults rather than re-inheriting Global. The action text draft is lossless: unset or cleared prompt and args stay so until the user types, and the inputs show them as empty, so saving a prompt no longer writes empty args that suppress the agent's default flags. Untouched sibling actions are not rewritten by the edit. * fix(settings): style the Extra CLI arguments toggle through Button's own variant and size CI's changed-code quality check refuses restyle classes on Button and CollapsibleContent. Use the ghost variant at size xs with a margin, and put the content spacing on a plain inner wrapper. * fix: keep saved action and restart launch recipes consistent * fix: describe inherited arguments and chat-only permissions accurately * test: check repository action settings fixture type * test: map saved action options into terminal compiler inputs * fix: retain saved action controls during agent detection * fix(i18n): retire obsolete Portuguese action labels * test: align folder launch fallback mock with outcome export * fix: carry resolved connector launch intent and mode together * test: pin shared action launch branches to recorded agent output * test: preserve saved source control choices through detection and migration * test: align launch fixtures with integrated result contract * test: retain recipe and restart contracts after main integration * Unify Source Control action permission settings * Keep native Ask copy with its owning change * Preserve action drafts and old-host permission intent * Consume rejected Source Control action saves * Follow the moved Settings persistence fixture * Keep permission integration contracts in the cross-version test project * Include the action permission inheritance label in English catalogs * Align launch contracts with shared permission recipes * Keep Source Control action controls within their Settings columns * Use primitive variants for compact action settings controls * Show action arguments only for terminal defaults and widen recipe rows * Apply terminal-only action arguments visibility to repository overrides * Align action permission control with model controls * Use shared settings label for action permissions * Hide action model controls until argument migration ships
153 lines
5.7 KiB
TypeScript
153 lines
5.7 KiB
TypeScript
import {
|
|
removeOverriddenAgentSessionArgs,
|
|
resolveAgentSessionOptionLaunch
|
|
} from './agent-session-option-launch'
|
|
import type { SessionOptionValue } from './native-chat-session-options'
|
|
import { agentArgTerminatorIndex } from './agent-session-option-agent-args'
|
|
import { getTuiAgentLaunchCommand, TUI_AGENT_CONFIG } from './tui-agent-config'
|
|
import {
|
|
quoteStartupArg,
|
|
tokenizeStartupCommand,
|
|
type AgentStartupShell
|
|
} from './tui-agent-startup-shell'
|
|
import type { TuiAgent } from './tui-agent'
|
|
|
|
// Why: Enter on Codex's "Update available" screen picks "Update now", which installs and exits.
|
|
const STARTUP_UPDATE_PROMPT_SUPPRESSION_ARGS: Partial<Record<TuiAgent, readonly string[]>> = {
|
|
codex: ['-c', 'check_for_update_on_startup=false']
|
|
}
|
|
|
|
export type ResolvedAgentLaunchCommand =
|
|
| {
|
|
ok: true
|
|
command: string
|
|
resumeLaunch: { agentCommand: string; agentArgs?: string }
|
|
appliedSessionOptions: Record<string, SessionOptionValue>
|
|
}
|
|
| { ok: false; error: string }
|
|
|
|
export function resolveAgentLaunchCommand(args: {
|
|
agent: TuiAgent
|
|
cmdOverrides: Partial<Record<TuiAgent, string>>
|
|
platform: NodeJS.Platform
|
|
shell: AgentStartupShell
|
|
agentArgs?: string | null
|
|
sessionOptions?: Record<string, SessionOptionValue>
|
|
sessionOptionsOverrideAgentArgs?: boolean
|
|
isRemote?: boolean
|
|
/** Launch-only, like session options: a resumed session must not inherit it. */
|
|
suppressStartupUpdatePrompt?: boolean
|
|
}): ResolvedAgentLaunchCommand {
|
|
const override = args.cmdOverrides[args.agent]
|
|
const command =
|
|
override ||
|
|
getTuiAgentLaunchCommand(TUI_AGENT_CONFIG[args.agent], args.platform, {
|
|
isRemote: args.isRemote
|
|
})
|
|
const suppressionArgs = args.suppressStartupUpdatePrompt
|
|
? (STARTUP_UPDATE_PROMPT_SUPPRESSION_ARGS[args.agent] ?? [])
|
|
: []
|
|
const launchHead = suppressionArgs.length
|
|
? `${command} ${suppressionArgs.map((arg) => quoteStartupArg(arg, args.shell)).join(' ')}`
|
|
: command
|
|
const trailingTokens = args.agentArgs?.trim()
|
|
? tokenizeStartupCommand(args.agentArgs.trim(), args.shell)
|
|
: { ok: true as const, tokens: [], spans: [] }
|
|
if (!trailingTokens.ok) {
|
|
return { ok: false, error: `CLI arguments are invalid: ${trailingTokens.error}` }
|
|
}
|
|
const resolvedOptions = resolveAgentSessionOptionLaunch(
|
|
args.agent,
|
|
args.sessionOptions,
|
|
args.sessionOptionsOverrideAgentArgs ? [] : trailingTokens.tokens,
|
|
!args.sessionOptionsOverrideAgentArgs,
|
|
trailingTokens.tokens
|
|
)
|
|
if (override && args.sessionOptionsOverrideAgentArgs) {
|
|
const overrideTokens = tokenizeStartupCommand(override, args.shell)
|
|
if (!overrideTokens.ok) {
|
|
return { ok: false, error: `Agent command override is invalid: ${overrideTokens.error}` }
|
|
}
|
|
const commandOverrideOptions = resolveAgentSessionOptionLaunch(
|
|
args.agent,
|
|
args.sessionOptions,
|
|
overrideTokens.tokens,
|
|
false
|
|
)
|
|
if (
|
|
Object.entries(resolvedOptions.appliedValues).some(
|
|
([key, value]) => commandOverrideOptions.appliedValues[key] !== value
|
|
)
|
|
) {
|
|
return {
|
|
ok: false,
|
|
error:
|
|
'Agent command override conflicts with the requested launch preferences. Remove model, effort or permission flags from the command override.'
|
|
}
|
|
}
|
|
}
|
|
const rawTokens = trailingTokens.tokens
|
|
const keptTokens = args.sessionOptionsOverrideAgentArgs
|
|
? removeOverriddenAgentSessionArgs(args.agent, resolvedOptions.appliedValues, rawTokens)
|
|
: rawTokens
|
|
const render = (tokens: readonly string[]): string =>
|
|
tokens.map((token) => quoteStartupArg(token, args.shell)).join(' ')
|
|
const withArgs = (suffix: string, head = command): string => (suffix ? `${head} ${suffix}` : head)
|
|
const initialTokens = args.sessionOptionsOverrideAgentArgs
|
|
? insertBeforeTerminator(args.agent, keptTokens, resolvedOptions.args)
|
|
: [...resolvedOptions.args, ...keptTokens]
|
|
// Restart retains explicit policy and surviving raw pins, while providers restore model seeds.
|
|
const resumeArgs = render(
|
|
insertBeforeTerminator(args.agent, keptTokens, resolvedOptions.permissionArgs ?? [])
|
|
)
|
|
return {
|
|
ok: true,
|
|
command: withArgs(render(initialTokens), launchHead),
|
|
resumeLaunch: {
|
|
agentCommand: withArgs(resumeArgs),
|
|
...(keptTokens.length !== rawTokens.length || resolvedOptions.permissionArgs
|
|
? { agentArgs: resumeArgs }
|
|
: {})
|
|
},
|
|
appliedSessionOptions: resolvedOptions.appliedValues
|
|
}
|
|
}
|
|
|
|
function insertBeforeTerminator(
|
|
agent: TuiAgent,
|
|
tokens: readonly string[],
|
|
inserted: readonly string[]
|
|
): string[] {
|
|
const terminator = agentArgTerminatorIndex(agent, tokens)
|
|
return [...tokens.slice(0, terminator), ...inserted, ...tokens.slice(terminator)]
|
|
}
|
|
|
|
/** A launch's saved choice as terminal startup inputs: flags that replace conflicting raw ones, or,
|
|
* when it yields to these CLI arguments, only the pieces they do not set themselves. */
|
|
export function terminalSessionOptionInputs(args: {
|
|
agent: TuiAgent
|
|
sessionOptions: Readonly<Record<string, SessionOptionValue>> | undefined
|
|
yieldToAgentArgs?: boolean
|
|
agentArgs: string | null | undefined
|
|
shell: AgentStartupShell
|
|
}): {
|
|
sessionOptions?: Record<string, SessionOptionValue>
|
|
sessionOptionsOverrideAgentArgs?: true
|
|
} {
|
|
const tokens = args.agentArgs?.trim()
|
|
? tokenizeStartupCommand(args.agentArgs.trim(), args.shell)
|
|
: null
|
|
const sessionOptions =
|
|
args.sessionOptions && args.yieldToAgentArgs && tokens?.ok
|
|
? resolveAgentSessionOptionLaunch(
|
|
args.agent,
|
|
{ ...args.sessionOptions },
|
|
tokens.tokens,
|
|
false
|
|
).appliedValues
|
|
: args.sessionOptions && { ...args.sessionOptions }
|
|
return sessionOptions && Object.keys(sessionOptions).length > 0
|
|
? { sessionOptions, sessionOptionsOverrideAgentArgs: true }
|
|
: {}
|
|
}
|