Skip to content

fix(acp): launch ACP/stdio mode for managed agents with no runtime preset - #3804

Open
bradhallett wants to merge 2 commits into
block:mainfrom
bradhallett:fix/acp-managed-agent-launch-args
Open

fix(acp): launch ACP/stdio mode for managed agents with no runtime preset#3804
bradhallett wants to merge 2 commits into
block:mainfrom
bradhallett:fix/acp-managed-agent-launch-args

Conversation

@bradhallett

@bradhallett bradhallett commented Jul 30, 2026

Copy link
Copy Markdown

Summary

Managed agents pinned to a known ACP runtime via agent_command_override (omp, grok, opencode, kimi, …) but with no runtime id launched the agent's interactive TUI instead of its ACP/stdio mode. Under headless Buzz there is no controlling TTY, so the JSON-RPC initialize handshake never completed and the agent timed out at startup:

  • omp / opencode / kimi → Request timeout
  • grok → ENXIO: Device not configured

Root cause

resolve_effective_harness_descriptor (readiness.rs) only resolved launch args when the record carried explicit instance args or a resolvable harness preset (record.runtimelookup_loaded_harness_by_id). A command-override agent with runtime = None satisfied neither, so descriptor.args stayed empty — while the effective command (e.g. omp) was still correct. The bare command then ran the TUI.

The correct per-runtime args already existed as the single source of truth in PRESET_HARNESSES (now in discovery/presets.rs); they just weren't consulted on this path.

Fix

In resolve_effective_harness_descriptor's final else branch, fall back to the PRESET_HARNESSES entry whose command matches the effective command, via a new preset_args_for_command() helper that mirrors the existing single-source preset_harness_ids() helper and lives alongside it in the managed_agents::discovery::presets submodule (re-exported through discovery.rs).

  • Single source of truth — per-runtime args live only in PRESET_HARNESSES; no hand-mirrored copy.
  • Covers every preset at once — omp, grok, opencode, kimi, cursor, openclaw, and devin.
  • descriptor.args now flows correctly to the spawn env (BUZZ_ACP_AGENT_ARGS), the config hash, and the agent summary.
  } else if let Some(ref def) = harness_def {
      normalize_agent_args(&effective_command, def.args.clone())
+ } else if let Some(preset_args) =
+     crate::managed_agents::discovery::preset_args_for_command(&effective_command)
+ {
+     normalize_agent_args(&effective_command, preset_args)
  } else {
      normalize_agent_args(&effective_command, record_args)
  }

Why not in buzz-acp

An earlier iteration mirrored the args into buzz-acp's default_agent_args. That duplicated the preset table in a third place and still left the desktop's descriptor.args (env/hash/summary) empty — relying on the child to repair the parent's omission. Fixing at resolve_effective_harness_descriptor corrects the source and needs no buzz-acp change; buzz-acp's existing default_value = "acp" still covers standalone CLI use with an unset env.

Verification

  • New unit test resolve_effective_harness_descriptor_uses_preset_args_for_pinned_command — asserts omp/grok/opencode/kimi/cursor/openclaw/devin resolve correctly, explicit args win, unknown commands stay empty. ✅
  • cargo fmt --check clean (pinned 1.95.0 toolchain); full managed_agents:: lib suite: 910 passed, 0 failed.
  • Rebased onto latest block/buzz main (resolves the conflict with Add Devin as a preset ACP harness #3225, which relocated PRESET_HARNESSES and its helpers into discovery/presets.rs; this helper follows it there).
  • Confirmed end-to-end in a local app build that an omp managed agent initializes without the ACP timeout.

No regressions

  • Explicit instance args still take precedence.
  • goose (not in PRESET_HARNESSES) still resolves via default_agent_args.
  • amp-acp / hermes-acp presets carry empty args — unchanged.
  • Custom harness ids collide with reserved preset ids, so they cannot shadow a preset.

Resolves #3399
Resolves #3457
Resolves #3729

Managed agents pinned to a known ACP runtime via agent_command_override
(e.g. `omp`, `grok`, `opencode`, `kimi`) but with no `runtime` id resolved
the effective command (e.g. `omp`) yet launched it with empty args. With no
controlling TTY under headless Buzz, the agent's interactive TUI started
instead of its ACP/stdio mode, so the JSON-RPC `initialize` handshake never
completed and the agent timed out at startup (omp/opencode/kimi: Request
timeout; grok: ENXIO "Device not configured").

Root cause: resolve_effective_harness_descriptor only filled args when the
record carried explicit instance args or a resolvable harness preset
(record.runtime -> lookup_loaded_harness_by_id). A command-override agent
with runtime=None hit neither, so descriptor.args stayed empty.

Fix: when no preset resolves, fall back to the PRESET_HARNESSES entry whose
command matches the effective command (new preset_args_for_command, mirroring
the existing single-source preset_harness_ids helper and living alongside it
in the managed_agents::discovery::presets submodule). The PresetHarness
table stays the single source of truth for per-runtime launch args, so this
covers omp, grok, opencode, kimi, cursor, openclaw, and devin at once with no
hand-mirroring, and descriptor.args now flows correctly to the spawn env
(BUZZ_ACP_AGENT_ARGS), the config hash, and the agent summary.

No regressions: explicit instance args still win; goose still resolves via
default_agent_args; amp/hermes presets (empty args) are unchanged; custom
harness ids collide with reserved preset ids so cannot shadow them.

Resolves block#3399
Resolves block#3457
Resolves block#3729

Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com>
@Chessing234

Copy link
Copy Markdown
Contributor

good for #3729. maybe add a log line of the resolved launch args at spawn so failed initialize is easier to debug

@bradhallett

Copy link
Copy Markdown
Author

@Chessing234 Implemented in b9825af and pushed to the PR branch. spawn_agent_child now writes the resolved agent command and argument vector to the managed-agent runtime log immediately before spawn, so failed ACP initialization includes the launch values. Verified with the full desktop library suite (1,996 passed, 14 ignored) and Clippy with -D warnings.

@bradhallett

Copy link
Copy Markdown
Author

Maintainer approval requested:

PR #3905 overlaps with #3804 on command-only preset argument resolution. I recommend keeping #3804 as the canonical fix:

  • resolves built-in preset args from normalized PRESET_HARNESSES data;
  • covers all affected presets and explicit-args precedence;
  • includes the requested resolved-command/args runtime-log diagnostic;
  • passes the full desktop library suite, formatting, and Clippy with -D warnings.

#3905 additionally explores loaded-registry matching and runtime-ID/command mismatch diagnostics. I am happy to port the mismatch diagnostic if command-only custom-harness support is required, but I recommend not merging both implementations.

Can we proceed with #3804 as the canonical PR and close #3905 in favor of it?

Signed-off-by: Brad Hallett <53977268+bradhallett@users.noreply.github.com>
@bradhallett
bradhallett force-pushed the fix/acp-managed-agent-launch-args branch from b9825af to 8b2db59 Compare July 31, 2026 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment