mirror of
https://github.com/stablyai/orca.git
synced 2026-10-07 08:02:21 +00:00
Pass wrapped OpenCode run prompts as positional messages (#25001)
* fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): unsubscribe hook settings during async host shutdown * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * test(readiness): census recorded OpenCode composer boots * fix(opencode): reject redirected overlay parents before cleanup * fix(orcad): retain runtime cleanup when subscribing to hook settings * refactor(launch): extract OpenCode config and attachment authority * fix(opencode): retain host version selection across relay restarts * fix(opencode): pass run prompts as positional messages Preserve run flags and use the existing shell quoting and run-command detector to append the initial message after --, reusing an existing separator. TUI launches retain their version-selected prompt transport and draft behavior. Original run-order work: @coelho-doti (#13065, tracked in #17551). * fix(opencode): keep wrapped run tasks positional Recognize supported environment prefixes and PowerShell call operators without mistaking prompt arguments for executables. Keep environment and run separators separate, preserve the task text and exclude run commands from native submission. Source-parent:23fc08b4e9Related-to: stablya/orca#17551 Credits: @coelho-doti (stablya/orca#13065) * Prepare complete private OpenCode launch validation source Integrate the complete reviewed readiness, capability, native prompt, overlay and positional-run source onto frozen main. Preserve canonical atomic ACL retry, status generator/disposal, restrictive-umask fixtures and unowned source. Keep supported wrapped run commands positional. Private-validation-source:a44345ce49Original-full-source:23fc08b4e9Original-core-base:8186ded0bdFrozen-main:08ee7ba9efOwned-source-paths: 111 Publication-policy: private validation only; preserve the six separate PR boundaries and held model/provider drafts Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Co-authored-by: Adnan Khan <adnank11427@gmail.com> Credits: juli-gonzalez readiness contribution; Ahmed Nagy atomic plugin writer; coelho-doti positional run contribution * Prepare private complete 111-path launch validation on current main Private validation only. Preserve main credential additions and original launch ownership. Held model and provider topics remain excluded. * Recognize env options before positional OpenCode run messages * STRICT launch CI contract correction * CAPS launch CI contract correction * INTENT launch CI contract correction * test(opencode): wait for malformed claim retries before expiring intent Observe real endpoint I/O completion under fake timers before forcing expiry. * test: initialize Claude prompt state in output retention fixture * Wait for OpenCode location hydration in intent startup * fix(opencode): bind startup readiness to the composer location * Bind OpenCode startup readiness to the current location in intent startup * Retry interrupted OpenCode startup prompt claims --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> Co-authored-by: Adnan Khan <adnank11427@gmail.com> Co-authored-by: Orca startup hydration review <agents@stably.ai> Co-authored-by: Orca <dev@stably.ai>
This commit is contained in:
co-authored by
Brennan Benson
Adnan Khan
Ahmed Nagy
Orca startup hydration review
Orca
parent
d77c57022e
commit
ea6a6d6077
@@ -0,0 +1,50 @@
|
||||
import type { AgentStartupPlan } from './tui-agent-startup'
|
||||
import type { SleepingAgentLaunchConfig } from './agent-session-resume'
|
||||
import type { SessionOptionValue } from './native-chat-session-options'
|
||||
import type { TuiAgent } from './tui-agent'
|
||||
import { TUI_AGENT_CONFIG } from './tui-agent-config'
|
||||
import { tokenizeStartupCommand, type AgentStartupShell } from './tui-agent-startup-shell'
|
||||
import { findOpenCodeRunCommand } from './opencode-headless-command'
|
||||
import { openCodeStartupPromptEnv } from './opencode-startup-prompt'
|
||||
|
||||
export function appliedSessionOptionProps(values: Record<string, SessionOptionValue>) {
|
||||
return Object.keys(values).length > 0 ? { sessionOptions: { ...values } } : {}
|
||||
}
|
||||
|
||||
export function buildFlagPromptStartupPlan(args: {
|
||||
agent: TuiAgent
|
||||
launchCommand: string
|
||||
quotedPrompt: string
|
||||
prompt: string
|
||||
shell: AgentStartupShell
|
||||
launchConfig: SleepingAgentLaunchConfig
|
||||
sessionOptions: Record<string, SessionOptionValue>
|
||||
agentEnv: Record<string, string> | null | undefined
|
||||
}): AgentStartupPlan {
|
||||
const parsed = tokenizeStartupCommand(args.launchCommand, args.shell)
|
||||
const openCodeRun =
|
||||
(args.agent === 'opencode' || args.agent === 'opencode2') && parsed.ok
|
||||
? findOpenCodeRunCommand(parsed.tokens, args.shell)
|
||||
: null
|
||||
// OpenCode run takes a positional message; --prompt belongs to its TUI.
|
||||
const promptSuffix = openCodeRun
|
||||
? openCodeRun.messageSeparatorIndex !== null
|
||||
? ` ${args.quotedPrompt}`
|
||||
: ` -- ${args.quotedPrompt}`
|
||||
: ` --prompt ${args.quotedPrompt}`
|
||||
return {
|
||||
agent: args.agent,
|
||||
launchCommand: `${args.launchCommand}${promptSuffix}`,
|
||||
expectedProcess: TUI_AGENT_CONFIG[args.agent].expectedProcess,
|
||||
followupPrompt: null,
|
||||
launchConfig: args.launchConfig,
|
||||
...appliedSessionOptionProps(args.sessionOptions),
|
||||
...openCodeStartupPromptEnv(
|
||||
args.agent,
|
||||
args.launchCommand,
|
||||
args.shell,
|
||||
args.prompt,
|
||||
args.agentEnv
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
OPENCODE_STARTUP_PROMPT_BODY_ENV,
|
||||
OPENCODE_STARTUP_PROMPT_SHELL_ENV
|
||||
} from './opencode-startup-prompt'
|
||||
import { tokenizeStartupCommand } from './tui-agent-startup-shell'
|
||||
|
||||
describe('native OpenCode startup submission intent', () => {
|
||||
it('binds the exact trimmed native prompt to host-selectable transport', () => {
|
||||
@@ -33,9 +34,63 @@ describe('native OpenCode startup submission intent', () => {
|
||||
platform: 'linux'
|
||||
})
|
||||
expect(plan?.env).toBeUndefined()
|
||||
expect(plan?.launchCommand).toContain('run --prompt')
|
||||
expect(plan?.launchCommand).toContain("run -- 'task'")
|
||||
})
|
||||
|
||||
it.each(['posix', 'powershell', 'cmd'] as const)(
|
||||
'keeps run and its flags before a positional message in %s',
|
||||
(shell) => {
|
||||
for (const agent of ['opencode', 'opencode2'] as const) {
|
||||
const prompt = '--literal task with unicode é'
|
||||
const plan = buildAgentStartupPlan({
|
||||
agent,
|
||||
prompt,
|
||||
cmdOverrides: { [agent]: 'opencode --log-level debug run --standalone' },
|
||||
platform: shell === 'posix' ? 'linux' : 'win32',
|
||||
shell,
|
||||
agentEnv: { CUSTOM_CONFIG: 'kept' }
|
||||
})
|
||||
expect(plan).not.toBeNull()
|
||||
const parsed = tokenizeStartupCommand(plan?.launchCommand ?? '', shell)
|
||||
expect(parsed.ok).toBe(true)
|
||||
if (!parsed.ok) {
|
||||
throw new Error(parsed.error)
|
||||
}
|
||||
expect(parsed.tokens).toEqual([
|
||||
'opencode',
|
||||
'--log-level',
|
||||
'debug',
|
||||
'run',
|
||||
'--standalone',
|
||||
'--',
|
||||
prompt
|
||||
])
|
||||
expect(plan?.env).toEqual({ CUSTOM_CONFIG: 'kept' })
|
||||
expect(plan?.followupPrompt).toBeNull()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
it.each(['posix', 'powershell', 'cmd'] as const)(
|
||||
'reuses an existing run message separator in %s',
|
||||
(shell) => {
|
||||
const plan = buildAgentStartupPlan({
|
||||
agent: 'opencode',
|
||||
prompt: '--literal task',
|
||||
cmdOverrides: { opencode: 'opencode run --standalone --' },
|
||||
platform: shell === 'posix' ? 'linux' : 'win32',
|
||||
shell
|
||||
})
|
||||
const parsed = tokenizeStartupCommand(plan?.launchCommand ?? '', shell)
|
||||
expect(parsed.ok).toBe(true)
|
||||
if (!parsed.ok) {
|
||||
throw new Error(parsed.error)
|
||||
}
|
||||
expect(parsed.tokens).toEqual(['opencode', 'run', '--standalone', '--', '--literal task'])
|
||||
expect(plan?.env).toBeUndefined()
|
||||
}
|
||||
)
|
||||
|
||||
it('never gives an editable draft or empty launch an automatic submission intent', () => {
|
||||
const args = { agent: 'opencode' as const, cmdOverrides: {}, platform: 'linux' as const }
|
||||
expect(
|
||||
@@ -50,3 +105,53 @@ describe('native OpenCode startup submission intent', () => {
|
||||
).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('wrapped OpenCode run startup', () => {
|
||||
it.each(['opencode', 'opencode2'] as const)(
|
||||
'keeps %s run flags and positional task behind POSIX prefixes',
|
||||
(agent) => {
|
||||
for (const command of [
|
||||
'CUSTOM_CONFIG=private opencode run --standalone',
|
||||
'env CUSTOM_CONFIG=private opencode run --standalone',
|
||||
'env -- CUSTOM_CONFIG=private opencode run --standalone',
|
||||
'env -- CUSTOM_CONFIG=private opencode run --standalone --',
|
||||
'env CUSTOM_CONFIG=private opencode run --title "--"'
|
||||
]) {
|
||||
const plan = buildAgentStartupPlan({
|
||||
agent,
|
||||
prompt: '--literal task',
|
||||
cmdOverrides: { [agent]: command },
|
||||
platform: 'linux',
|
||||
shell: 'posix',
|
||||
isRemote: true,
|
||||
agentEnv: { CUSTOM_CONFIG: 'kept' }
|
||||
})
|
||||
expect(plan?.launchCommand).toBe(
|
||||
command.endsWith(' --') ? `${command} '--literal task'` : `${command} -- '--literal task'`
|
||||
)
|
||||
expect(plan?.env).toEqual({ CUSTOM_CONFIG: 'kept' })
|
||||
expect(plan?.followupPrompt).toBeNull()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
it.each(['opencode', 'opencode2'] as const)(
|
||||
'preserves %s PowerShell call syntax and its run separator',
|
||||
(agent) => {
|
||||
for (const separator of ['', ' --']) {
|
||||
const command = `& "C:\\Program Files\\opencode\\opencode.exe" --log-level debug run --standalone${separator}`
|
||||
const plan = buildAgentStartupPlan({
|
||||
agent,
|
||||
prompt: "--task's é",
|
||||
cmdOverrides: { [agent]: command },
|
||||
platform: 'win32',
|
||||
shell: 'powershell',
|
||||
agentEnv: { CUSTOM_CONFIG: 'kept' }
|
||||
})
|
||||
expect(plan?.launchCommand).toBe(`${command}${separator ? ' ' : ' -- '}'--task''s é'`)
|
||||
expect(plan?.env).toEqual({ CUSTOM_CONFIG: 'kept' })
|
||||
expect(plan?.followupPrompt).toBeNull()
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
@@ -21,7 +21,7 @@ export function openCodeStartupPromptEnv(
|
||||
if (
|
||||
(agent !== 'opencode' && agent !== 'opencode2') ||
|
||||
!parsed.ok ||
|
||||
isOpenCodeRunCommand(parsed.tokens)
|
||||
isOpenCodeRunCommand(parsed.tokens, shell)
|
||||
) {
|
||||
return env ? { env: { ...env } } : {}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import { inlineAgentDraftFitsPlatform } from './agent-draft-platform-limit'
|
||||
import type { TuiAgent } from './tui-agent'
|
||||
import type { SessionOptionValue } from './native-chat-session-options'
|
||||
import { resolveAgentLaunchCommand } from './tui-agent-launch-command'
|
||||
import { openCodeStartupPromptEnv } from './opencode-startup-prompt'
|
||||
import { appliedSessionOptionProps, buildFlagPromptStartupPlan } from './flag-prompt-startup'
|
||||
|
||||
export { buildAgentResumeStartupPlan } from './tui-agent-resume-startup'
|
||||
|
||||
@@ -36,10 +36,6 @@ export type AgentStartupPlan = {
|
||||
sessionOptions?: Record<string, SessionOptionValue>
|
||||
}
|
||||
|
||||
function appliedSessionOptionProps(values: Record<string, SessionOptionValue>) {
|
||||
return Object.keys(values).length > 0 ? { sessionOptions: { ...values } } : {}
|
||||
}
|
||||
|
||||
export function buildAgentStartupPlan(args: {
|
||||
agent: TuiAgent
|
||||
prompt: string
|
||||
@@ -117,15 +113,16 @@ export function buildAgentStartupPlan(args: {
|
||||
}
|
||||
|
||||
if (config.promptInjectionMode === 'flag-prompt') {
|
||||
return {
|
||||
return buildFlagPromptStartupPlan({
|
||||
agent,
|
||||
launchCommand: `${launchCommand} --prompt ${quotedPrompt}`,
|
||||
expectedProcess: config.expectedProcess,
|
||||
followupPrompt: null,
|
||||
launchCommand,
|
||||
quotedPrompt,
|
||||
prompt: trimmedPrompt,
|
||||
shell,
|
||||
launchConfig,
|
||||
...appliedSessionOptionProps(baseCommand.appliedSessionOptions),
|
||||
...openCodeStartupPromptEnv(agent, launchCommand, shell, trimmedPrompt, args.agentEnv)
|
||||
}
|
||||
sessionOptions: baseCommand.appliedSessionOptions,
|
||||
agentEnv: args.agentEnv
|
||||
})
|
||||
}
|
||||
|
||||
if (config.promptInjectionMode === 'hermes-query') {
|
||||
|
||||
Reference in New Issue
Block a user