feat: Add ACPAgent for Agent Client Protocol integration#2133
feat: Add ACPAgent for Agent Client Protocol integration#2133simonrosenberg merged 11 commits intomainfrom
Conversation
Add ACPAgent, an AgentBase subclass that delegates to ACP-compatible servers (Claude Code, Gemini CLI, etc.) instead of direct LLM calls. The ACP server manages its own LLM, tools, and execution lifecycle. Closes #590 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Record per-turn token usage from PromptResponse.usage in step() - Record incremental cost from UsageUpdate notifications in session_update() - Yield sentinel LLM from get_all_llms() for telemetry pipeline - Wire _llm_ref on client for dynamic metrics/telemetry access - Trigger stats callback after each step for GUI updates - Extract notification drain delay to configurable constant - Add audit logging for auto-approved permission requests - Add debug logging in cleanup for process/executor errors - Wrap example in try/finally for robust cleanup - Add 8 telemetry tests in TestACPAgentTelemetry Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
all-hands-bot
left a comment
There was a problem hiding this comment.
🟢 Good taste - Clean integration with pragmatic workarounds for ecosystem quirks. Solid testing and good defensive error handling.
…ition Add ACP_NOTIFICATION_DRAIN_DELAY env var override, yield to the event loop before the timed sleep, and add a TODO for protocol-level fix. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Coverage Report •
|
|||||||||||||||||||||||||
- Fix RequestPermissionResponse constructor (outcome, not result) - Add proper signatures to Client protocol stub methods - Narrow content[0] type in tests with isinstance checks - Pass required args in fs/terminal stub tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Renumber example 36 -> 40 to avoid conflict with 36_event_json_to_openai_messages.py - Add type: ignore[reportMissingImports] to all acp imports (optional dep) - Add TYPE_CHECKING import in __init__.py to satisfy pyright __all__ check - Add @requires_acp skip marker for tests needing the acp package Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move acp from optional to required deps, removing: - Lazy import guard in init_state - type: ignore[reportMissingImports] comments - @requires_acp skip markers on tests - test_missing_acp_sdk_raises_import_error test The __getattr__ in __init__.py is kept to avoid a circular import. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
neubig
left a comment
There was a problem hiding this comment.
I think overall it looks good, I left a few comments. I assume that this has been tested, in which case we can probably merge it in and then iterate.
Co-authored-by: Engel Nyst <engel.nyst@gmail.com>
Co-authored-by: Engel Nyst <engel.nyst@gmail.com>
934a9d8 to
d5c43b1
Compare
- Rename _make_sentinel_llm → _make_dummy_llm - Move inline acp imports to top-level - Add GitHub issue link to TODO comment - Simplify _filter_jsonrpc_lines exception handling - Add debug logging for on_token and stats callback failures - Remove chatty Example from class docstring - Remove critic validation check (ACP server manages its own evaluation) - Add comment explaining lazy import in __init__.py (avoids circular dependency) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
d5c43b1 to
506a50a
Compare
|
@simonrosenberg btw, this workflow is broken. We should also add a docs for this script on OpenHands/docs repo: https://github.com/OpenHands/software-agent-sdk/actions/runs/22243244271/job/64351561891?pr=2160 |
CLI Compatibility NoteThis PR introduced breaking changes to the
CLI fix PR: OpenHands/OpenHands-CLI#548 Question: Are subsequent SDK fixes/features intended for CLI use now blocked until the CLI PR #548 is merged? For example, we're trying to test #2334 (terminal escape filter fix) with the CLI, but it fails because it's based on post-breaking-change main. cc @enyst |
|
@OpenHands We see this error. Check if that example is still undocumented, and if so, do what it says below. Verify in the sync workflows on the docs/ repo in the same org to understand CI on this, so you know: ❌ Found 1 undocumented example(s):
|
|
I'm on it! enyst can track my progress at all-hands.dev |
This comment was marked as duplicate.
This comment was marked as duplicate.
|
@OpenHands Read this comment #2133 (comment) and verify each link. Look at our workflow with griffe on api breakage. Did that happen in this PR? If not, why not? Were these methods referenced in the public api? (if not, do you think they should be, wdyt?) Then. We just made a release of the SDK, find the release PR. Clone yourself the CLI repo and verify on which SDK version it is. If we upgrade it, will the comment still apply? Make a new investigation issue in the sdk repo, and answer my questions there, plus any results of your investigation. Answer the questions in the comment linked, too. |
|
I'm on it! enyst can track my progress at all-hands.dev |
|
Final summary of work:
No code changes were made; therefore there is nothing to push. |
Summary
ACPAgent, anAgentBasesubclass that delegates to ACP-compatible servers (Claude Code, Gemini CLI, etc.) instead of direct LLM callsPromptResponse.usage, incremental cost fromUsageUpdatenotifications, and stats callback for GUI updatesclaude-code-acpv0.1.x which emits non-JSON-RPC log lines to stdoutpip install 'openhands-sdk[acp]'(requiresagent-client-protocol>=0.8.1)Changes
openhands-sdk/openhands/sdk/agent/acp_agent.py_OpenHandsACPClient,_filter_jsonrpc_lines,ACPAgentwith telemetryopenhands-sdk/openhands/sdk/agent/__init__.pyACPAgentto avoid requiringagent-client-protocolat import timeopenhands-sdk/pyproject.tomlacpoptional dependencytests/sdk/agent/test_acp_agent.pyexamples/01_standalone_sdk/36_acp_agent_example.pyTest plan
uv run pytest tests/sdk/agent/test_acp_agent.py -v)claude-code-acpserverCloses #590
🤖 Generated with Claude Code
Agent Server images for this PR
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdknikolaik/python-nodejs:python3.12-nodejs22golang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:7154df8-pythonRun
All tags pushed for this build
About Multi-Architecture Support
7154df8-python) is a multi-arch manifest supporting both amd64 and arm647154df8-python-amd64) are also available if neededDocumentation