hermes - ✅(Solved) Fix [Feature]: Auto-detect OpenCode ACP command syntax for delegate_task subagents [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#19493Fetched 2026-05-05 06:06:27
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
labeled ×3cross-referenced ×1

Fix Action

Fix / Workaround

delegate_task supports acp_command to spawn external ACP agents (e.g. acp_command: "copilot"), but only Copilot CLI works out of the box. OpenCode — a popular open-source coding agent — also implements the ACP stdio JSON-RPC protocol but uses a subcommand-style syntax (opencode acp) instead of Copilot's flag-style (copilot --acp --stdio). Currently, users must manually pass acp_args: ["acp"] every time they want to use OpenCode as an ACP backend. Discovering this workaround requires reading the source code.

OpenCode ACP communication has been verified end-to-end with Hermes Agent: the initialize handshake, tool dispatch (bash), and response streaming all work correctly via CopilotACPClient.

PR fix notes

PR #19495: feat(acp): auto-detect OpenCode ACP command syntax

Description (problem / solution / changelog)

What does this PR do?

Makes delegate_task detect OpenCode's ACP command syntax automatically. Currently, only Copilot CLI works out of the box because _resolve_args() hardcodes copilot --acp --stdio. OpenCode uses opencode acp (subcommand-style), requiring users to manually pass acp_args: ["acp"]. This PR makes the detection automatic based on the command name.

Related Issue

Fixes #19493

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • agent/copilot_acp_client.py: _resolve_args() now accepts an optional command parameter and returns ["acp"] when the command is opencode (vs ["--acp", "--stdio"] for copilot)
  • agent/copilot_acp_client.py: CopilotACPClient.__init__ passes the resolved command to _resolve_args()

How to Test

  1. Install OpenCode CLI (npm install -g opencode)
  2. Verify OpenCode ACP is available: opencode acp --help
  3. Start Hermes Agent and run:
    delegate_task(acp_command="opencode", toolsets=["terminal"], goal="Run: echo 'test ok'")
  4. Confirm:
    • No "process exited early" error (args are now correct)
    • Subagent returns text output (ACP handshake + tool dispatch working)
    • tokens: {"input": 0, "output": 0} in the result (ACP path confirmed)
  5. Verify copilot path is unaffected: regular copilot ACP delegation still works

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15.2

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A (minor internal change)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) — N/A (pure Python, Linux)
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Changed files

  • agent/copilot_acp_client.py (modified, +10/-5)
  • tests/agent/test_copilot_acp_client.py (modified, +30/-0)

Code Example

def _resolve_args(command: str = "") -> list[str]:
    raw = os.getenv("HERMES_COPILOT_ACP_ARGS", "").strip()
    if raw:
        return shlex.split(raw)
    # Copilot CLI uses flag-style: copilot --acp --stdio
    # OpenCode uses subcommand-style: opencode acp
    cmd_name = os.path.basename(command) if command else _resolve_command()
    if cmd_name == "opencode":
        return ["acp"]
    return ["--acp", "--stdio"]

---

self._acp_args = list(acp_args or args or _resolve_args(self._acp_command))
RAW_BUFFERClick to expand / collapse

Problem or Use Case

delegate_task supports acp_command to spawn external ACP agents (e.g. acp_command: "copilot"), but only Copilot CLI works out of the box. OpenCode — a popular open-source coding agent — also implements the ACP stdio JSON-RPC protocol but uses a subcommand-style syntax (opencode acp) instead of Copilot's flag-style (copilot --acp --stdio). Currently, users must manually pass acp_args: ["acp"] every time they want to use OpenCode as an ACP backend. Discovering this workaround requires reading the source code.

OpenCode ACP communication has been verified end-to-end with Hermes Agent: the initialize handshake, tool dispatch (bash), and response streaming all work correctly via CopilotACPClient.

Proposed Solution

Make _resolve_args() in agent/copilot_acp_client.py detect the command name and return the appropriate default args:

def _resolve_args(command: str = "") -> list[str]:
    raw = os.getenv("HERMES_COPILOT_ACP_ARGS", "").strip()
    if raw:
        return shlex.split(raw)
    # Copilot CLI uses flag-style: copilot --acp --stdio
    # OpenCode uses subcommand-style: opencode acp
    cmd_name = os.path.basename(command) if command else _resolve_command()
    if cmd_name == "opencode":
        return ["acp"]
    return ["--acp", "--stdio"]

Update the call site in CopilotACPClient.__init__ to pass the resolved command:

self._acp_args = list(acp_args or args or _resolve_args(self._acp_command))

Also update delegate_task's tool schema description to mention opencode alongside claude and copilot.

Scope: 1 file (agent/copilot_acp_client.py), ~10 lines added. The existing Copilot CLI path is completely unaffected. The HERMES_COPILOT_ACP_ARGS env var override remains highest priority. All 7 existing tests pass.

Alternatives Considered

  1. Require users to always pass acp_args explicitly — works but poor DX. Users shouldn't need to memorize that OpenCode uses ["acp"] vs Copilot's ["--acp", "--stdio"].

  2. Add a registry of known ACP agents (_KNOWN_ACP_AGENTS dict mapping command names to default args) — more extensible but over-engineered for the current 2-agent landscape. Can be trivially refactored if/when a third ACP agent appears.

  3. Rename CopilotACPClient to ACPClient — semantically correct now that the class serves multiple agents, but out of scope. Worth a follow-up issue.

Feature Type

  • New Feature
  • Enhancement
  • Documentation
  • Refactor

extent analysis

TL;DR

Update the _resolve_args() function in agent/copilot_acp_client.py to detect the command name and return the appropriate default args for OpenCode and Copilot ACP agents.

Guidance

  • Review the proposed solution and test it with both Copilot and OpenCode ACP agents to ensure compatibility.
  • Verify that the HERMES_COPILOT_ACP_ARGS env var override still takes priority over the default args.
  • Consider adding a test case to cover the OpenCode ACP agent scenario.
  • Update the delegate_task tool schema description to mention opencode alongside claude and copilot for better user experience.

Example

def _resolve_args(command: str = "") -> list[str]:
    # ... (rest of the function remains the same)
    if cmd_name == "opencode":
        return ["acp"]
    return ["--acp", "--stdio"]

Notes

The proposed solution only affects the agent/copilot_acp_client.py file and does not introduce any breaking changes. However, it's essential to test the update thoroughly to ensure it works as expected with both ACP agents.

Recommendation

Apply the proposed workaround by updating the _resolve_args() function to detect the command name and return the appropriate default args. This solution provides a better user experience by eliminating the need to manually pass acp_args for OpenCode ACP agent.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING