Skip to content

fix(acp): resolve preset args by command match when no runtime id is set - #3905

Open
Kamal-Nayan-Kumar wants to merge 3 commits into
block:mainfrom
Kamal-Nayan-Kumar:fix/opencode-acp-args-command-match
Open

fix(acp): resolve preset args by command match when no runtime id is set#3905
Kamal-Nayan-Kumar wants to merge 3 commits into
block:mainfrom
Kamal-Nayan-Kumar:fix/opencode-acp-args-command-match

Conversation

@Kamal-Nayan-Kumar

Copy link
Copy Markdown

Summary

Managed agents pinned to a preset's command via agent_command_override (e.g. "opencode") but with no explicit runtime id silently lost the preset's default args. This is the exact bug I hit locally: Buzz spawned bare opencode (its interactive TUI) instead of opencode acp, so every one of the 10 pooled workers timed out at the ACP initialize handshake, and the agent never came online.

Root cause

resolve_effective_harness_descriptor (readiness.rs) resolves the harness definition (for default args/env) only via record.runtimepersona.runtimelookup_loaded_harness_by_id. An agent whose command was set directly to a preset's command string — without also recording that preset's runtime id — satisfies neither, so the lookup misses and the agent falls back to its own (empty) agent_args, even though the command exactly matches a known preset (opencode → args ["acp"]).

Fix

Add lookup_loaded_harness_by_command in custom_harnesses.rs, scanning the same already-loaded registry (preset + custom harnesses) by command instead of id. Wire it as an .or_else fallback in both harness_def resolution sites in readiness.rs (resolve_effective_harness_descriptor and resolve_effective_agent_env), so a command match still finds the definition when no runtime id is set.

Verification

  • New regression test command_override_without_runtime_id_still_gets_preset_args in discovery/tests.rs — builds a record shaped exactly like the reported bug (agent_command_override: "opencode", no runtime, empty agent_args) and asserts the resolved descriptor carries args = ["acp"].
  • Full managed_agents:: lib suite: 910 passed, 0 failed.
  • cargo fmt --check and cargo clippy --all-targets -- -D warnings clean.
  • Confirmed end-to-end against a local Buzz Desktop install: before the fix, agents configured this way hung and timed out on every restart; after, agent_pool_ready, relay connection, and presence-online all completed successfully.

Related

This same root cause is already tracked in #3824, #3729, #3457, #3660, and is also addressed by #3804 (already open, using a similar command-match fallback sourced from PRESET_HARNESSES directly rather than the loaded registry). Posting this as an independent, fully-tested fix per the repo's own diagnosis path in case the alternate approach here (matching against the already-loaded registry, which already carries every preset + custom harness) is useful — happy to close in favor of #3804 if a maintainer prefers consolidating on that one.

Managed agents pinned to a preset's command via agent_command_override
(e.g. "opencode") but without an explicit runtime id silently lost the
preset's default args. resolve_effective_harness_descriptor only looked
up the harness definition via record.runtime / persona.runtime, so a
command-override-only agent found no definition and fell back to its
own (empty) agent_args. For OpenCode this meant Buzz spawned the bare
interactive TUI instead of `opencode acp`, and every pooled worker
timed out at the ACP initialize handshake.

Add lookup_loaded_harness_by_command as a fallback in both harness_def
resolution sites in readiness.rs, matching the effective command
against the already-loaded preset/custom registry when the id-based
lookup misses.

Adds a regression test reproducing the exact scenario (agent_command_override
= "opencode", no runtime id, empty agent_args) and asserting the resolved
descriptor carries args = ["acp"].

Signed-off-by: Kamal Nayan Kumar <kamalnayanofficialwork@gmail.com>
@Kamal-Nayan-Kumar
Kamal-Nayan-Kumar requested a review from a team as a code owner July 31, 2026 11:10
@Chessing234

Copy link
Copy Markdown
Contributor

clean preset-arg fallback. one ask: if both runtime id and command match are set and disagree, which wins — and is that spelled out in a test?

Per review on block#3905: when record.runtime and the effective command (from
agent_command_override) name different presets, the explicit runtime id
wins — lookup_loaded_harness_by_id short-circuits the new
lookup_loaded_harness_by_command fallback via or_else, so the fallback
only ever fires when the id-based lookup misses. This precedence
predates this PR; this test just documents it now that a command-match
path exists to disagree with the id at all.

Signed-off-by: Kamal Nayan Kumar <kamalnayanofficialwork@gmail.com>
@Kamal-Nayan-Kumar

Copy link
Copy Markdown
Author

Good question — traced it through:

lookup_loaded_harness_by_id(runtime_id).or_else(|| lookup_loaded_harness_by_command(&effective_command)) — the fallback is an .or_else, so it only runs when the id-based lookup misses. The explicit runtime id always wins when both resolve and disagree; command-match is strictly a "nothing else matched" fallback, never an override.

That precedence isn't new — it's inherited from the original record.runtime → persona.runtime → id lookup chain this PR only extends with one more fallback link. But you're right nothing pinned it down before (there was no second path to disagree with the id). Added runtime_id_wins_over_disagreeing_command_match in discovery/tests.rs: record.runtime = Some("amp") (args []) vs. agent_command_override = Some("opencode") (would independently match args ["acp"] via command-match) — asserts the resolved command is still "opencode" (override wins for what launches) but the args come from amp's definition ([], empty) — i.e. the id wins for which definition supplies args/env, even though it disagrees with the actual command being spawned.

Pushed as a follow-up commit. Full managed_agents:: suite (911 tests) + fmt + clippy still clean.

@Chessing234 Chessing234 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the right seam for #3824 — command-override without runtime id was silently dropping preset args. the opencode acp regression test is exactly what i'd want before merge. one nit: when runtime id and command disagree, id-wins leaving opencode with amp's empty args is still a footgun; maybe a warn log on that mismatch path so desktop shows why acp never started.

Per review on block#3905: when record.runtime resolves to a harness whose
command differs from the agent's effective command (from
agent_command_override), that mismatched definition's args/env still
apply — the id always wins over a disagreeing command match, per
runtime_id_wins_over_disagreeing_command_match. This can silently strip
args the effective command actually needs (e.g. an ACP subcommand),
and previously surfaced only as a bare ACP initialize timeout with no
clue why.

Log a tracing::warn! in resolve_effective_harness_descriptor when this
mismatch occurs, naming the agent pubkey, the runtime id, the harness's
own command, and the effective command, so the agent's log explains the
mismatch instead of just timing out.

Scoped to resolve_effective_harness_descriptor only (spawn/hash/model
probe path) — not the sibling resolve_effective_agent_env, which is
also called from several UI preview paths (e.g. live env-diff previews
as a user edits settings) where firing on every keystroke would be
noise rather than signal.

Signed-off-by: Kamal Nayan Kumar <kamalnayanofficialwork@gmail.com>
@Kamal-Nayan-Kumar

Copy link
Copy Markdown
Author

Good nit — pushed a follow-up: a tracing::warn! in resolve_effective_harness_descriptor when the resolved runtime id names a harness whose command differs from the agent's effective command (the exact mismatch runtime_id_wins_over_disagreeing_command_match exercises). It logs the agent pubkey, the runtime id, the mismatched harness's command, and the actual effective command — so the agent's log names the cause instead of just a bare ACP init timeout.

Scoped it to resolve_effective_harness_descriptor only (the spawn/hash/model-probe path) — not resolve_effective_agent_env, which is also called from several UI preview paths (e.g. live env-diff previews while editing agent settings in the desktop UI) where warning on every keystroke would be noise, not signal.

911 tests still pass, fmt/clippy clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants