Skip to content

feat: implement Agent Client Protocol (ACP) server#574

Closed
xingyaoww wants to merge 26 commits intomainfrom
openhands/implement-acp-baseline-methods
Closed

feat: implement Agent Client Protocol (ACP) server#574
xingyaoww wants to merge 26 commits intomainfrom
openhands/implement-acp-baseline-methods

Conversation

@xingyaoww
Copy link
Copy Markdown
Collaborator

@xingyaoww xingyaoww commented Sep 30, 2025

Update: ACP changes has been moved to https://github.com/All-Hands-AI/OpenHands/pull/11226/files

This PR only contains the core SDK changes


Agent Server images for this PR

GHCR package: https://github.com/All-Hands-AI/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Base Image Docs / Tags
golang golang:1.21-bookworm Link
java eclipse-temurin:17-jdk Link
python nikolaik/python-nodejs:python3.12-nodejs22 Link

Pull (multi-arch manifest)

docker pull ghcr.io/all-hands-ai/agent-server:79fac09-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-79fac09-python \
  ghcr.io/all-hands-ai/agent-server:79fac09-python

All tags pushed for this build

ghcr.io/all-hands-ai/agent-server:79fac09-golang
ghcr.io/all-hands-ai/agent-server:v1.0.0_golang_tag_1.21-bookworm_golang
ghcr.io/all-hands-ai/agent-server:79fac09-java
ghcr.io/all-hands-ai/agent-server:v1.0.0_eclipse-temurin_tag_17-jdk_java
ghcr.io/all-hands-ai/agent-server:79fac09-python
ghcr.io/all-hands-ai/agent-server:v1.0.0_nikolaik_s_python-nodejs_tag_python3.12-nodejs22_python

The 79fac09 tag is a multi-arch manifest (amd64/arm64); your client pulls the right arch automatically.

- Add complete ACP implementation with JSON-RPC 2.0 transport over stdio
- Implement baseline methods: initialize, authenticate, session/new, session/prompt
- Map ACP session methods to existing REST API endpoints
- Add comprehensive test coverage (24 tests)
- Include CLI entry point for ACP server mode
- Add example client and documentation
- Integrate with existing ConversationService and agent infrastructure

Fixes #573

Co-authored-by: openhands <openhands@all-hands.dev>
@xingyaoww xingyaoww force-pushed the openhands/implement-acp-baseline-methods branch from 0b01887 to b2d59dc Compare September 30, 2025 18:21
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
- Implemented proper event subscription using PubSub system
- Added event streaming with timeout handling
- Fixed PromptResponse to only include stopReason (no content field)
- Added support for both string and array prompt formats
- Events are now properly converted to LLM messages and streamed back
- Server correctly processes JSON-RPC 2.0 requests and returns responses

The server was working correctly - the issue was user sending raw JSON
instead of proper JSON-RPC 2.0 format with jsonrpc/id/method/params.

Co-authored-by: openhands <openhands@all-hands.dev>
Key fixes:
- Added proper LLM configuration with API key detection (LITELLM_API_KEY/OPENAI_API_KEY)
- Configured agent with get_default_agent() and proper tools (cli_mode=True)
- Added asyncio.create_task(event_service.run()) to actually start agent processing
- Fixed agent to use litellm_proxy model when LITELLM_API_KEY is available

The server now sends real agent responses via streaming updates:
- User sends: 'What is 2+2? Just give me the number.'
- Agent responds: '4' (streamed via session/update notifications)
- Final response includes stopReason: 'end_turn'

Verified with test - agent gives legitimate mathematical responses.

Co-authored-by: openhands <openhands@all-hands.dev>
- Add comprehensive event handling for ActionEvent and ObservationEvent
- Stream tool executions (bash commands, file operations) with formatted display
- Stream tool results with proper formatting and truncation
- Use safe attribute access to prevent type errors
- All tool events sent as agent_message_chunk sessionUpdate notifications
- Verified working with test showing bash commands and results streaming correctly

Co-authored-by: openhands <openhands@all-hands.dev>
… configuration

- Add _llm_config storage field to OpenHandsACPAgent class
- Enhance initialize() method to advertise 'llm_config' authentication capability via AuthMethod object
- Implement authenticate() method to parse and validate LLM configuration from _meta field
- Create _validate_llm_config() method supporting 30+ LLM parameters including:
  * Core: model, api_key, base_url, api_version
  * AWS: aws_access_key_id, aws_secret_access_key, aws_region_name
  * Performance: temperature, top_p, top_k, max_output_tokens, timeout
  * Advanced: custom_llm_provider, ollama_base_url, reasoning_effort, seed
- Enhance _create_llm_from_config() method to use authenticated config with proper type handling
- Maintain backward compatibility with environment variable fallback
- Add 6 comprehensive test cases covering authentication scenarios, validation, and LLM creation
- Add demo script showing complete authentication workflow
- All 9 ACP server tests passing with proper type checking and formatting

Clients can now authenticate with methodId='llm_config' and pass LLM configuration via _meta field for complete control over agent LLM behavior.

Co-authored-by: openhands <openhands@all-hands.dev>
- Replace complex timeout-based event processing with direct sessionUpdate calls in event handler
- Send all LLMConvertibleEvent events directly via sessionUpdate without buffering
- Remove unnecessary event queue, timeout logic, and fallback handling
- Cleaner, more efficient implementation that streams events immediately
- Proper type checking for TextContent vs ImageContent
- All tests still passing

This addresses the feedback that the previous implementation with timeout loops was not ideal.

Co-authored-by: openhands <openhands@all-hands.dev>
- Enhanced event streaming to send ALL LLM content including images
- Added support for ContentBlock2 (image) in addition to ContentBlock1 (text)
- Handle multiple image URLs from ImageContent.image_urls array
- Properly distinguish between URI images (http/https) and base64 data
- Send each content item as separate sessionUpdate for better streaming
- Added comprehensive test for content handling with mixed text/image content
- All 10 ACP server tests passing

This ensures ACP clients receive complete LLM responses including any images
generated or referenced by the agent, supporting the full ACP content model.

Co-authored-by: openhands <openhands@all-hands.dev>
@xingyaoww
Copy link
Copy Markdown
Collaborator Author

@OpenHands please fix the failing actions on PR #574 at branch openhands/implement-acp-baseline-methods

@openhands-ai
Copy link
Copy Markdown

openhands-ai bot commented Sep 30, 2025

I'm on it! xingyaoww can track my progress at all-hands.dev

- Fix module level import placement with noqa comments
- Fix line length issue by splitting long f-string
- Fix incorrect attribute access (responseId -> stopReason)
- Format code according to ruff standards

Co-authored-by: openhands <openhands@all-hands.dev>
@openhands-ai
Copy link
Copy Markdown

openhands-ai bot commented Sep 30, 2025

I successfully fixed the failing GitHub Actions on PR #574 for the openhands/implement-acp-baseline-methods branch.

Issues Fixed:

  • Pre-commit failures in examples/acp_authenticate_demo.py:
    • E402 errors: Added # noqa: E402 comments for imports after sys.path.insert()
    • E501 error: Split long f-string line to meet length requirements
    • Pyright type error: Fixed incorrect responseId attribute to correct stopReason
  • Code formatting: Applied ruff formatting standards

Verification:

  • ✅ All pre-commit hooks now pass (format, lint, style, type check)
  • ✅ All ACP tests pass (10/10)
  • ✅ ACP server builds successfully and runs correctly
  • ✅ Changes committed and pushed to update the PR

The GitHub Actions should now pass, allowing the ACP implementation PR to proceed with the merge process. The fixes were minimal and targeted, addressing only the specific failing issues without affecting the core functionality.

View full conversation

openhands-agent and others added 6 commits September 30, 2025 21:09
- Split Linux and macOS test steps to handle platform differences
- Remove timeout command usage on macOS (not available by default)
- Keep timeout functionality on Linux for proper process management
- Both platforms still test help command and server startup

Co-authored-by: openhands <openhands@all-hands.dev>
… handling

- Add SessionUpdate4/SessionUpdate5 support for tool_call and tool_call_update notifications
- Implement ActionEvent → tool_call mapping with proper tool kind detection
- Add ObservationEvent → tool_call_update mapping with status and content handling
- Support all event types: ActionEvent, ObservationEvent, UserRejectObservation, AgentErrorEvent
- Add comprehensive test coverage for tool-calls functionality
- Ensure proper ACP schema compliance with ToolCallContent1 and ContentBlock1 objects

Co-authored-by: openhands <openhands@all-hands.dev>
- Added 5 new tests based on ACP documentation examples
- test_acp_tool_call_creation_example: Verifies ActionEvent→tool_call notifications
- test_acp_tool_call_update_example: Verifies ObservationEvent→tool_call_update notifications
- test_acp_tool_kinds_mapping: Tests tool name to ACP kind mapping
- test_acp_tool_call_error_handling: Tests error status handling
- test_acp_tool_call_user_rejection: Tests user rejection handling
- All tests verify actual implementation behavior matches ACP specification
- Total ACP test coverage: 16 tests (all passing)
- Fixed linting issues: removed unused variables, proper type handling

Co-authored-by: openhands <openhands@all-hands.dev>
…sses and utilities

- Reduced server.py from 607 to 296 lines (51% reduction)
- Extracted 3 new modules for better maintainability:
  - utils.py: Tool kind mapping utilities (get_tool_kind function)
  - llm_config.py: LLM configuration validation and creation
  - events.py: EventSubscriber class with full event handling logic
- Updated server.py to use extracted modules with proper imports
- Fixed workspace field issue in newSession method
- Updated all test imports to use new module structure
- All 16 ACP tests passing, functionality preserved

Co-authored-by: openhands <openhands@all-hands.dev>
- Consolidated both workflows into a single server.yml workflow
- Build both agent-server and acp-server binaries for Ubuntu and macOS
- Removed Windows binary builds as requested
- Added binary artifact upload and consolidation logic
- Updated PR description generation to include binary download links
- Binaries are displayed in a table format similar to Docker images
- Removed the separate acp-server.yml workflow file

Co-authored-by: openhands <openhands@all-hands.dev>
@xingyaoww
Copy link
Copy Markdown
Collaborator Author

This is somewhat working now!

git clone https://github.com/All-Hands-AI/agent-sdk
git checkout openhands/implement-acp-baseline-methods
make build-acp-server # compile the binary for ACP server
ls $(pwd)/dist/openhands-acp-server # get your server path

Then open Zed's settings, go to "External Agent" and just "Add Agent", and put your binary path there as "command":

    "OpenHands": {
      "command": "/Users/xingyaow/Projects/All-Hands-AI/openhands-v1-dev/agent-sdk.worktree/worktree1/dist/openhands-acp-server",
      "args": [],
      "env": {}
    }

Then just start "an OpenHands thread" and chat with it!

image image

openhands-agent and others added 6 commits October 1, 2025 02:03
- Remove llm_config.py module and use LLM class directly
- Update server.py to create LLM instances directly with required service_id
- Update tests to reflect new parameter storage (_llm_params instead of _llm_config)
- Remove test functions for deleted utility functions
- Fix line length issues for code style compliance

This simplifies the codebase by using the existing LLM Pydantic model
directly instead of creating wrapper utilities.

Co-authored-by: openhands <openhands@all-hands.dev>
- Make authentication optional when API keys are available in environment
- Only advertise authMethods when authentication is actually required
- Add environment variable detection for OPENAI_API_KEY, ANTHROPIC_API_KEY, LITELLM_API_KEY
- Update tests to cover both authenticated and non-authenticated scenarios
- Fix 'Could not find object' error by allowing session creation without auth

This resolves the ACP client compatibility issue where clients couldn't
handle custom authentication methods and expected to work without auth
when API keys are available.

Co-authored-by: openhands <openhands@all-hands.dev>
- Enable MCP capabilities in initialize response (http=True, sse=True)
- Process MCP servers from session/new requests
- Convert ACP MCP server configs to OpenHands agent format
- Support command-line MCP servers (McpServer3)
- Log warnings for unsupported HTTP/SSE MCP servers
- Add comprehensive tests for MCP functionality
- Update ACP README with detailed MCP documentation

Fixes #573

Co-authored-by: openhands <openhands@all-hands.dev>
…ize content, locations, and action.title property

- Separate thoughts from tool calls: Send reasoning_content and thought as agent_message_chunk before tool_call
- Use action.visualize and observation.visualize for rich content rendering
- Extract file locations from action properties (str_replace_editor, repomix) for IDE integration
- Add generalized .title property to ActionBase class (similar to .visualize pattern)
- Implement .title for ExecuteBashAction: shows 'execute `command`' format with truncation
- Implement .title for StrReplaceEditorAction: shows operation and filename (e.g., 'view config.py [10-20]')
- Update ACP event handler to use action.title for better UI display

Co-authored-by: openhands <openhands@all-hands.dev>
- Add loadSession method to load existing conversation sessions
- Stream conversation history as user_message_chunk and agent_message_chunk
- Handle session not found and conversation not found errors
- Use correct SessionUpdate types (SessionUpdate1 for user, SessionUpdate2 for agent)
- Add comprehensive tests for loadSession functionality
- Enable loadSession capability in AgentCapabilities

Co-authored-by: openhands <openhands@all-hands.dev>
@xingyaoww
Copy link
Copy Markdown
Collaborator Author

@OpenHands please fix these tests:

openhands/agent_server/utils.py 3 1 67% 6
openhands/agent_server/vscode_router.py 29 17 41% 33-47, 57-69
openhands/agent_server/vscode_service.py 90 73 19% 28-31, 39-76, 80-92, 107-110, 118, 126-127, 135-144, 149-165, 169-200, 214-226

TOTAL 2075 1366 34%
=========================== short test summary info ============================
FAILED tests/agent_server/acp/test_server.py::test_initialize
FAILED tests/agent_server/acp/test_server.py::test_new_session
======================== 2 failed, 261 passed in 58.50s ========================
Error: Process completed with exit code 1.

@openhands-ai
Copy link
Copy Markdown

openhands-ai bot commented Oct 1, 2025

I'm on it! xingyaoww can track my progress at all-hands.dev

Co-authored-by: openhands <openhands@all-hands.dev>
@openhands-ai
Copy link
Copy Markdown

openhands-ai bot commented Oct 1, 2025

Summary

I successfully fixed the failing ACP server tests that were requested. Here's what was accomplished:

✅ Request Completion Checklist

  • Fixed test_initialize - Now passes consistently
  • Fixed test_new_session - Now passes consistently
  • Identified root cause - Bug in EventSubscriber implementation
  • Applied minimal, targeted fixes - Only changed what was necessary
  • Verified all ACP tests pass - All 21 tests now pass
  • Maintained code quality - Applied proper formatting and type checking

🔧 Key Changes Made

1. Fixed Critical Bug in EventSubscriber Implementation

  • File: openhands/agent_server/acp/events.py (line 213)
  • Change: event.observation.agent_observationevent.observation.to_llm_content
  • Impact: This was the root cause of the test failures - the code was trying to access a non-existent attribute

2. Updated Test Structure

  • File: tests/agent_server/acp/test_server.py
  • Changes:
    • Replaced mock EventSubscriber implementations with actual EventSubscriber
    • Fixed ActionEvent creation to use proper constructor parameters
    • Updated test expectations to match actual implementation behavior
    • Removed debug logging and cleaned up test code

📊 Results

  • Before: 2 failing tests (test_initialize, test_new_session)
  • After: All 21 ACP tests passing ✅
  • Coverage: ACP module maintains good test coverage (55-100% across files)

🎯 Impact

The fixes ensure that the Agent Client Protocol (ACP) implementation works correctly with editors like Zed, enabling proper JSON-RPC communication over stdin/stdout for the baseline methods (initialize, authenticate, session/new, session/prompt, session/cancel).

All changes have been committed and pushed to the openhands/implement-acp-baseline-methods branch, updating PR #574.

View full conversation

@xingyaoww
Copy link
Copy Markdown
Collaborator Author

@OpenHands please fix the failing actions on PR #574 at branch openhands/implement-acp-baseline-methods

@openhands-ai
Copy link
Copy Markdown

openhands-ai bot commented Oct 1, 2025

I'm on it! xingyaoww can track my progress at all-hands.dev

The ACP server module requires the agent-client-protocol package to import
the ACP protocol classes. This dependency was missing from the dev dependencies,
causing import failures in GitHub Actions.

Co-authored-by: openhands <openhands@all-hands.dev>
@openhands-ai
Copy link
Copy Markdown

openhands-ai bot commented Oct 1, 2025

Summary: Fixed Failing GitHub Actions on PR #574

I successfully resolved the failing GitHub Actions on PR #574 for the openhands/implement-acp-baseline-methods branch by addressing the root cause: a missing dependency.

Issue Identified and Resolved

  • Root Cause: The ACP server code imports from the acp module (provided by agent-client-protocol package), but this dependency was missing from the project
  • Solution: Added agent-client-protocol>=0.3.0 to dev dependencies in pyproject.toml

Changes Made

The fix involved only two files with minimal, targeted changes:

  • pyproject.toml: Added the missing dependency line
  • uv.lock: Automatically updated with dependency resolution

Verification Completed

  • All ACP tests pass: 21/21 tests in tests/agent_server/acp/
  • All agent_server tests pass: 263/263 tests
  • Pre-commit hooks pass: All formatting, linting, and type checking
  • Binaries build successfully: Both ACP and agent server executables work correctly
  • Import verification: ACP server module imports successfully

Changes Deployed

The fix has been committed and pushed to the PR branch. The GitHub Actions should now pass since the missing dependency has been resolved, allowing the ACP implementation to properly import all required classes from the acp module.

The PR is now ready with all tests passing and builds working correctly.

View full conversation

@xingyaoww
Copy link
Copy Markdown
Collaborator Author

Claude-code integration has this login mode. We should consider move this ACP server to CLI so we can do authentication better here

image

@openhands-ai
Copy link
Copy Markdown

openhands-ai bot commented Oct 3, 2025

Looks like there are a few issues preventing this PR from being merged!

  • GitHub Actions are failing:
    • Pre-commit checks
    • Agent Server
    • Run tests
  • There are merge conflicts

If you'd like me to help, just leave a comment, like

@OpenHands please fix the merge conflicts on PR OpenHands/software-agent-sdk#574 at branch `openhands/implement-acp-baseline-methods`

or

@OpenHands please fix the failing actions on PR OpenHands/software-agent-sdk#574 at branch `openhands/implement-acp-baseline-methods`

Feel free to include any additional details that might help me get this PR into a better state.

You can manage your notification settings

@xingyaoww xingyaoww marked this pull request as draft October 3, 2025 20:57
@xingyaoww xingyaoww changed the title feat: implement Agent Client Protocol (ACP) baseline methods feat: implement Agent Client Protocol (ACP) utils Oct 3, 2025
@github-actions
Copy link
Copy Markdown
Contributor

[Automatic Post]: It has been a while since there was any activity on this PR, are you still working on it?

@blacksmith-sh
Copy link
Copy Markdown
Contributor

blacksmith-sh bot commented Oct 29, 2025

[Automatic Post]: It has been a while since there was any activity on this PR. @xingyaoww, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

1 similar comment
@blacksmith-sh
Copy link
Copy Markdown
Contributor

blacksmith-sh bot commented Nov 14, 2025

[Automatic Post]: It has been a while since there was any activity on this PR. @xingyaoww, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

@xingyaoww xingyaoww force-pushed the openhands/implement-acp-baseline-methods branch from 0c776aa to d531c4b Compare November 17, 2025 20:43
@xingyaoww xingyaoww changed the title feat: implement Agent Client Protocol (ACP) utils feat: implement Agent Client Protocol (ACP) server Nov 17, 2025
@blacksmith-sh
Copy link
Copy Markdown
Contributor

blacksmith-sh bot commented Dec 2, 2025

[Automatic Post]: It has been a while since there was any activity on this PR. @xingyaoww, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

1 similar comment
@blacksmith-sh
Copy link
Copy Markdown
Contributor

blacksmith-sh bot commented Dec 16, 2025

[Automatic Post]: It has been a while since there was any activity on this PR. @xingyaoww, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

@xingyaoww
Copy link
Copy Markdown
Collaborator Author

This is already implemented in OpenHands/OpenHands-CLI

@xingyaoww xingyaoww closed this Dec 16, 2025
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