fix(agents): resolve preset harness args at spawn - #4765
Open
lnv-louis wants to merge 1 commit into
Open
Conversation
`default_agent_args` matched only `KNOWN_ACP_RUNTIMES`, so every entry in `PRESET_HARNESSES` fell through to `None` and the args a preset declares were dropped. Presets have carried their own invocations since block#3225 (`devin acp`, `cursor-agent acp`, `grok agent --always-approve stdio`), but nothing on the spawn path read them. An agent pinned to a preset by command rather than by runtime id hits this: with `record.agent_args` empty and `record.runtime` unset, the id-keyed registry lookup in `resolve_effective_harness_descriptor` misses and resolution falls to `normalize_agent_args`, which returns `[]`. `runtime.rs` then sets `BUZZ_ACP_AGENT_ARGS=""`, overriding buzz-acp's `[default: acp]`, and the harness spawns bare. `devin` with no args opens the interactive TUI on a stdio pipe and exits: ERROR buzz_acp: agent initialize failed: Agent process exited unexpectedly agent=0 Error: all 10 agents failed to start - cannot continue Same shape as block#4631, one field over: that fixed preset invisibility for the harness *command*, this fixes it for the *args*. Add `preset_args_for_command` and consult it as tier 2, mirroring `canonical_harness_command`. Static-only by design - no loaded-registry tier, because this runs inside `preset_catalog_entry` while the catalog is being built and taking the registry lock there risks deadlocking against a concurrent warm. Registry-backed harnesses already resolve args by runtime id. `devin_preset_uses_official_native_acp_invocation` passed throughout: `preset_catalog_entry` passes `def.args` in explicitly, so the catalog never exercised the empty-args path that spawn takes. The new tests cover that path. Verified: 2204 passed / 0 failed (`just desktop-tauri-test`), clippy clean under `-D warnings`. Reverting the one-line change fails `preset_commands_keep_their_declared_args`, `preset_args_resolve_through_path_prefixes_and_runtime_ids` and `adapter_presets_stay_argless` with `left: [] right: ["acp"]`. Signed-off-by: Louis <louisle236@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4764.
Problem
default_agent_argsmatched onlyKNOWN_ACP_RUNTIMES, so every entry inPRESET_HARNESSESfell through toNoneand the args a preset declares were dropped. Presets have carried their own invocations since #3225 —devin acp,cursor-agent acp,grok agent --always-approve stdio— but nothing on the spawn path read them.An agent pinned to a preset by command rather than by runtime id hits this. With
record.agent_argsempty andrecord.runtimeunset, the id-keyed registry lookup inresolve_effective_harness_descriptormisses and resolution falls tonormalize_agent_args, which returns[].runtime.rs:573then setsBUZZ_ACP_AGENT_ARGS="", which overrides buzz-acp's own[default: acp], and the harness spawns bare:devinwith no args opens the interactive TUI on a stdio pipe and exits (Error: Scrollback error: io error).devin acpreturns a valid initialize result.Affects devin, cursor, omp, opencode, kimi, openclaw and grok. Adapter presets (amp, hermes) declare no args and are unaffected in practice.
Relationship to #4631
Same shape, one field over. #4631 fixed preset invisibility for the harness command and added
canonical_harness_commandwith builtins → static presets → loaded registry. The args kept the builtin-only blind spot.Fix
Add
preset_args_for_commandindiscovery/presets.rsand consult it as tier 2 ofdefault_agent_args, soPRESET_HARNESSESis the single source of truth for its own invocations instead of requiring a parallel entry in a hardcoded match.Deliberately static-only — no loaded-registry tier. This runs inside
preset_catalog_entrywhile the catalog is being built, so acquiring the registry lock there risks deadlocking against a concurrent warm/refresh. Registry-backed harnesses already resolve their args by runtime id inresolve_effective_harness_descriptor, so the tier would be redundant as well as risky.Adding
"devin" => Some(vec!["acp".to_string()])to the match would have fixed the reported symptom and left cursor, omp, opencode, kimi, openclaw and grok broken, plus every preset added later. Hence the lookup.Why existing tests passed
devin_preset_uses_official_native_acp_invocationassertsentry.default_args == vec!["acp"]and passed throughout.preset_catalog_entrypassesdef.argsin explicitly, so the non-empty branch returns them unchanged — the catalog never exercised the empty-args path that spawn takes. The new tests cover that path directly.Tests
Five new tests in
discovery/tests.rs:preset_commands_keep_their_declared_args— devin, cursor-agent, omp, openclaw resolve to["acp"]; grok keeps all three of its argspreset_args_resolve_through_path_prefixes_and_runtime_ids—/Users/me/.local/bin/devinand the bare idcursorboth resolveexplicit_preset_args_win_over_declared_defaults— user args are not clobberedadapter_presets_stay_argless— amp-acp and hermes-acp stay empty; a strayacpis dropped as it is for claude-code-acpunknown_commands_still_resolve_to_no_args— custom harnesses unchangedVerification
Regression check — reverting the one-line change in
default_agent_argsto_ => Nonefails exactly the new tests:Restoring it returns the suite to green.
Note for maintainers
Records already written with
"agent_args": []are fixed by this change, since resolution is recomputed at spawn rather than read from the frozen snapshot. No migration needed.