mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 01:57:57 +00:00
+3








46c3c3b44d
* feat(orchestration): support OpenCode worker model selection Allow supervised OpenCode workers to use per-launch model overrides through the existing launch-preference and receipt path. Preserve existing OpenCode agent arguments while replacing only model flags, and reject unsupported effort values explicitly. Keep Native Chat option exposure unchanged and update the worker CLI and orchestration guidance. * 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(orchestration): gate OpenCode worker model preferences by host capability Co-authored-by: user141514 <user141514@users.noreply.github.com> * feat(opencode): probe launch capabilities on the execution host * feat(opencode): probe execution-host CLI capabilities * feat(opencode): probe launch capabilities on the execution host * feat(orchestration): resolve explicitly configured command aliases * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(orchestration): verify available OpenCode model on execution host * Add host-owned OpenCode and Devin account profiles * fix(orchestration): inspect OpenCode models with selected account environment * fix(orchestration): bind model validation to direct existing-workspace launch * fix(opencode): preserve launch environment deletion boundaries * fix(orchestration): limit effective model contract to verified OpenCode release * 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 * Restore inherited account environment and preserve cleanup retries * 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 * Check relay environment values before merging * 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> * fix(orchestration): validate configured aliases with target shell grammar * fix(orchestration): use actual shell and refuse assignment-only aliases * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * Support verified OpenCode v2 model selection in fresh native workers * fix(opencode): refuse unsupported startup preferences before model probing * 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: preserve typed calls in configured worker target checks Replace Reflect.apply with the existing typed prototype call pattern so the unchanged regression cases pass the anti-slop lint gate. * test: check typed model host calls and terminal delay state Replace Reflect dispatch and property reads with checked access and typed calls. Complete the existing resume request fixture with its required identity fields without changing the rejection boundary or assertions. * 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 * Verify OpenCode catalog model launches and preserve current launch behavior * Verify OpenCode catalog model launches and preserve current launch behavior * Refuse unverified new-worktree OpenCode models and complete host audits * Wait for OpenCode location hydration in intent startup * Refuse unverified new-worktree OpenCode model launches and record startup attribution * fix(opencode): bind startup readiness to the composer location * Bind OpenCode startup readiness to the current location in intent startup * Restore the owning Orca CLI path after shell profiles * Use a literal marker for the Bash lookup regression * Preserve plain panes and initialize zsh after prompt hook replacement * Preserve user line-editor dispatchers during deferred startup * fix: retain CLI startup when global Zsh replaces prompt hooks * test: replay global Zsh hook replacement after host startup * test: isolate controlled Zsh widgets from distro keyboard setup * fix(shell): preserve user hooks during deferred zsh initialization * Retry interrupted OpenCode startup prompt claims * Keep completed Zsh startup hooks retired when the wrapper is sourced again * Reject truncated OpenCode catalogs and explain worktree model limits * Use a template literal in truncated-catalog coverage * Refuse unfinished OpenCode model catalogs --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Co-authored-by: user141514 <user141514@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: Codex <codex@openai.com> Co-authored-by: Orca maintenance <orca-maintenance@users.noreply.github.com> Co-authored-by: Orca <dev@stably.ai> Co-authored-by: Orca campaign <orca-campaign@local.invalid> Co-authored-by: Orca OpenCode issue campaign <opencode-campaign@stably.ai> Co-authored-by: OpenCode issue campaign <codex@localhost> Co-authored-by: Nathan Parker <nwparker@users.noreply.github.com>
217 lines
8.1 KiB
TypeScript
217 lines
8.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { resolveAgentStartupPlanInputs } from '../../shared/agent-startup-plan-inputs'
|
|
import { applyManagedDataAccountEnvironment } from '../managed-data-accounts/launch-environment'
|
|
import { probeOpenCodeLaunchCapabilities } from './opencode-launch-capabilities'
|
|
import {
|
|
probeOpenCodeModelAvailability,
|
|
resolveOpenCodeDirectModelExecutable
|
|
} from './opencode-model-availability'
|
|
import { probeOpenCodeLaunchModelContext } from './opencode-launch-model-context'
|
|
import { buildExecutionHostAgentStartupPlan } from './opencode-model-startup-plan'
|
|
|
|
vi.mock('../managed-data-accounts/launch-environment', () => ({
|
|
applyManagedDataAccountEnvironment: vi.fn()
|
|
}))
|
|
vi.mock('./opencode-launch-capabilities', () => ({ probeOpenCodeLaunchCapabilities: vi.fn() }))
|
|
vi.mock('./opencode-model-availability', () => ({
|
|
resolveOpenCodeDirectModelExecutable: vi.fn(),
|
|
probeOpenCodeModelAvailability: vi.fn()
|
|
}))
|
|
vi.mock('./opencode-launch-model-context', () => ({ probeOpenCodeLaunchModelContext: vi.fn() }))
|
|
|
|
const preferred = 'opencode/fledge-alpha-free'
|
|
const original = JSON.stringify({
|
|
default_agent: 'reviewer',
|
|
providers: { custom: { apiKey: 'placeholder' } },
|
|
agents: { reviewer: { system: 'Review only', model: 'opencode/big-pickle' } }
|
|
})
|
|
function scope() {
|
|
return {
|
|
inputs: resolveAgentStartupPlanInputs({
|
|
agent: 'opencode',
|
|
settings: {
|
|
agentCmdOverrides: {},
|
|
agentDefaultEnv: { opencode: { OPENCODE_CONFIG_CONTENT: original } }
|
|
},
|
|
platform: process.platform,
|
|
isRemote: false,
|
|
sessionOptions: { model: preferred }
|
|
}),
|
|
cwd: '/private/project',
|
|
prompt: 'Read only',
|
|
hostIdentity: 'host'
|
|
}
|
|
}
|
|
|
|
describe('execution-host OpenCode model startup', () => {
|
|
beforeEach(() => {
|
|
vi.resetAllMocks()
|
|
vi.mocked(resolveOpenCodeDirectModelExecutable).mockResolvedValue('/private/opencode')
|
|
vi.mocked(probeOpenCodeLaunchCapabilities).mockResolvedValue({
|
|
version: '2.0.16',
|
|
pluginApi: 'v2',
|
|
promptMode: 'prefill'
|
|
})
|
|
vi.mocked(probeOpenCodeModelAvailability).mockResolvedValue(true)
|
|
vi.mocked(probeOpenCodeLaunchModelContext)
|
|
.mockResolvedValueOnce({
|
|
primaryAgent: 'reviewer',
|
|
availableModels: [preferred],
|
|
primaryModel: 'opencode/big-pickle'
|
|
})
|
|
.mockResolvedValue({
|
|
primaryAgent: 'reviewer',
|
|
availableModels: [preferred],
|
|
primaryModel: preferred
|
|
})
|
|
})
|
|
|
|
it('refuses unsupported effort preferences before probing or dropping them', async () => {
|
|
const options = scope()
|
|
options.inputs.sessionOptions = { model: preferred, effort: 'high' }
|
|
await expect(buildExecutionHostAgentStartupPlan(options)).rejects.toMatchObject({
|
|
code: 'capability_unsupported'
|
|
})
|
|
expect(probeOpenCodeLaunchModelContext).not.toHaveBeenCalled()
|
|
expect(probeOpenCodeLaunchCapabilities).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('launches current v2 in isolation and keeps one-time model preferences out of resume state', async () => {
|
|
const options = scope()
|
|
const plan = await buildExecutionHostAgentStartupPlan(options)
|
|
expect(plan?.launchCommand).toContain('--standalone')
|
|
expect(plan?.launchCommand).not.toContain('--model')
|
|
expect(plan?.sessionOptions).toEqual({ model: preferred })
|
|
expect(JSON.parse(plan?.env?.OPENCODE_CONFIG_CONTENT ?? 'null')).toEqual({
|
|
default_agent: 'reviewer',
|
|
model: preferred,
|
|
providers: { custom: { apiKey: 'placeholder' } },
|
|
agents: { reviewer: { system: 'Review only', model: preferred } }
|
|
})
|
|
expect(plan?.launchConfig).toEqual({
|
|
agentCommand: 'opencode',
|
|
agentArgs: '',
|
|
agentEnv: { OPENCODE_CONFIG_CONTENT: original }
|
|
})
|
|
expect(options.inputs.agentEnv.OPENCODE_CONFIG_CONTENT).toBe(original)
|
|
})
|
|
|
|
it('uses the selected account environment in both authoritative probes', async () => {
|
|
vi.mocked(applyManagedDataAccountEnvironment).mockImplementation((env) => {
|
|
env.XDG_DATA_HOME = '/selected/data'
|
|
env.OPENCODE_DB = 'opencode.db'
|
|
})
|
|
await buildExecutionHostAgentStartupPlan(scope())
|
|
for (const call of vi.mocked(probeOpenCodeLaunchModelContext).mock.calls) {
|
|
expect(call[0].env).toMatchObject({
|
|
XDG_DATA_HOME: '/selected/data',
|
|
OPENCODE_DB: 'opencode.db'
|
|
})
|
|
}
|
|
})
|
|
|
|
it.each(['1.18.30', '1.18.32'])(
|
|
'preserves the verified legacy launch route %s',
|
|
async (version) => {
|
|
vi.mocked(probeOpenCodeLaunchCapabilities).mockResolvedValue({
|
|
version,
|
|
pluginApi: 'v1',
|
|
promptMode: 'submit'
|
|
})
|
|
expect((await buildExecutionHostAgentStartupPlan(scope()))?.launchCommand).toContain(
|
|
'--model'
|
|
)
|
|
expect(probeOpenCodeLaunchModelContext).not.toHaveBeenCalled()
|
|
}
|
|
)
|
|
|
|
it('preserves ordinary launches without any private server probe', async () => {
|
|
const options = scope()
|
|
options.inputs.sessionOptions = undefined
|
|
expect((await buildExecutionHostAgentStartupPlan(options))?.launchCommand).not.toContain(
|
|
'--standalone'
|
|
)
|
|
expect(probeOpenCodeLaunchCapabilities).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it.each(['--agent build', '--continue', '--server http://localhost'])(
|
|
'refuses current-v2 manual launch arguments %s',
|
|
async (agentArgs) => {
|
|
const options = scope()
|
|
options.inputs.agentArgs = agentArgs
|
|
await expect(buildExecutionHostAgentStartupPlan(options)).rejects.toMatchObject({
|
|
code: 'capability_unsupported'
|
|
})
|
|
expect(probeOpenCodeLaunchModelContext).not.toHaveBeenCalled()
|
|
}
|
|
)
|
|
|
|
it('refuses unavailable models and mismatched observed model preferences', async () => {
|
|
vi.mocked(probeOpenCodeLaunchModelContext)
|
|
.mockReset()
|
|
.mockResolvedValue({ primaryAgent: 'reviewer', availableModels: [], primaryModel: null })
|
|
await expect(buildExecutionHostAgentStartupPlan(scope())).rejects.toMatchObject({
|
|
code: 'capability_unsupported'
|
|
})
|
|
vi.mocked(probeOpenCodeLaunchModelContext)
|
|
.mockReset()
|
|
.mockResolvedValue({
|
|
primaryAgent: 'reviewer',
|
|
availableModels: [preferred],
|
|
primaryModel: 'opencode/big-pickle'
|
|
})
|
|
await expect(buildExecutionHostAgentStartupPlan(scope())).rejects.toMatchObject({
|
|
code: 'capability_unsupported'
|
|
})
|
|
})
|
|
|
|
it('refuses remote and WSL execution before touching the local binary', async () => {
|
|
const options = scope()
|
|
options.inputs.isRemote = true
|
|
await expect(buildExecutionHostAgentStartupPlan(options)).rejects.toMatchObject({
|
|
code: 'capability_unsupported'
|
|
})
|
|
options.inputs.isRemote = false
|
|
await expect(
|
|
buildExecutionHostAgentStartupPlan({ ...options, isWsl: true })
|
|
).rejects.toMatchObject({ code: 'capability_unsupported' })
|
|
expect(resolveOpenCodeDirectModelExecutable).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it.each(['1.18.31', '1.18.33', '2.0.17'])(
|
|
'refuses unverified version %s before model probing',
|
|
async (version) => {
|
|
vi.mocked(probeOpenCodeLaunchCapabilities).mockResolvedValue({
|
|
version,
|
|
pluginApi: 'v2',
|
|
promptMode: 'prefill'
|
|
})
|
|
await expect(buildExecutionHostAgentStartupPlan(scope())).rejects.toMatchObject({
|
|
code: 'capability_unsupported'
|
|
})
|
|
expect(probeOpenCodeLaunchModelContext).not.toHaveBeenCalled()
|
|
expect(probeOpenCodeModelAvailability).not.toHaveBeenCalled()
|
|
}
|
|
)
|
|
|
|
it('resolves the default bare launch command through the execution host', async () => {
|
|
await buildExecutionHostAgentStartupPlan(scope())
|
|
expect(resolveOpenCodeDirectModelExecutable).toHaveBeenCalledWith(
|
|
expect.objectContaining({ command: 'opencode' })
|
|
)
|
|
})
|
|
|
|
it.each(['blank-model', 'effort-only'])(
|
|
'refuses invalid preferences before probing',
|
|
async (scenario) => {
|
|
const options = scope()
|
|
options.inputs.sessionOptions =
|
|
scenario === 'blank-model' ? { model: '' } : { effort: 'high' }
|
|
await expect(buildExecutionHostAgentStartupPlan(options)).rejects.toMatchObject({
|
|
code: 'capability_unsupported'
|
|
})
|
|
expect(resolveOpenCodeDirectModelExecutable).not.toHaveBeenCalled()
|
|
}
|
|
)
|
|
})
|