From ef37a2d403795045b605eb56ee30464a9bd7d1ad Mon Sep 17 00:00:00 2001 From: Simon Rosenberg Date: Mon, 9 Mar 2026 10:49:06 -0300 Subject: [PATCH] fix(sdk): revert agent-client-protocol to optional [acp] extra Move agent-client-protocol from a hard required dependency back to an optional extra (pip install openhands-sdk[acp]). This unblocks downstream consumers (e.g. the CLI) that pin ACP <0.8.0 from upgrading to SDK v1.12.0+. Changes: - pyproject.toml: move agent-client-protocol to [project.optional-dependencies] acp - __init__.py: catch ImportError in lazy __getattr__ with helpful message - test_acp_agent.py: skip entire module when acp not installed - example: add install prerequisite note - root pyproject.toml: add agent-client-protocol to dev deps for CI Co-Authored-By: Claude Opus 4.6 --- .../01_standalone_sdk/40_acp_agent_example.py | 1 + openhands-sdk/openhands/sdk/agent/__init__.py | 9 ++++++++- openhands-sdk/pyproject.toml | 2 +- pyproject.toml | 1 + tests/sdk/agent/test_acp_agent.py | 19 +++++++++++++------ uv.lock | 9 ++++++--- 6 files changed, 30 insertions(+), 11 deletions(-) diff --git a/examples/01_standalone_sdk/40_acp_agent_example.py b/examples/01_standalone_sdk/40_acp_agent_example.py index cdd04bbbb4..5718761c67 100644 --- a/examples/01_standalone_sdk/40_acp_agent_example.py +++ b/examples/01_standalone_sdk/40_acp_agent_example.py @@ -8,6 +8,7 @@ Prerequisites: - Node.js / npx available - Claude Code CLI authenticated (or CLAUDE_API_KEY set) + - pip install 'openhands-sdk[acp]' Usage: uv run python examples/01_standalone_sdk/40_acp_agent_example.py diff --git a/openhands-sdk/openhands/sdk/agent/__init__.py b/openhands-sdk/openhands/sdk/agent/__init__.py index 666921be92..2fb01ccc14 100644 --- a/openhands-sdk/openhands/sdk/agent/__init__.py +++ b/openhands-sdk/openhands/sdk/agent/__init__.py @@ -15,7 +15,14 @@ # that previously defaulted. def __getattr__(name: str): if name == "ACPAgent": - from openhands.sdk.agent.acp_agent import ACPAgent + try: + from openhands.sdk.agent.acp_agent import ACPAgent + except ImportError: + raise ImportError( + "The 'agent-client-protocol' package is required for ACPAgent. " + "Install it with: pip install 'openhands-sdk[acp]' or " + "pip install agent-client-protocol" + ) from None return ACPAgent raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/openhands-sdk/pyproject.toml b/openhands-sdk/pyproject.toml index 874f99518b..4d43f11802 100644 --- a/openhands-sdk/pyproject.toml +++ b/openhands-sdk/pyproject.toml @@ -5,7 +5,6 @@ description = "OpenHands SDK - Core functionality for building AI agents" requires-python = ">=3.12" dependencies = [ - "agent-client-protocol>=0.8.1", "deprecation>=2.1.0", "fakeredis[lua]>=2.32.1", # Explicit dependency for docket/fastmcp background tasks "fastmcp>=3.0.0", @@ -27,6 +26,7 @@ Documentation = "https://docs.openhands.dev/sdk" "Bug Tracker" = "https://github.com/OpenHands/software-agent-sdk/issues" [project.optional-dependencies] +acp = ["agent-client-protocol>=0.8.1"] boto3 = ["boto3>=1.35.0"] [build-system] diff --git a/pyproject.toml b/pyproject.toml index 89aafa6630..ad024b4fb5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ openhands-agent-server = { workspace = true } [dependency-groups] dev = [ + "agent-client-protocol>=0.8.1", # Optional SDK extra; included for ACP tests "pre-commit>=4.3.0", "packaging>=24.2", "psutil>=7.0.0", diff --git a/tests/sdk/agent/test_acp_agent.py b/tests/sdk/agent/test_acp_agent.py index 2d97d4babc..b3be2d90bd 100644 --- a/tests/sdk/agent/test_acp_agent.py +++ b/tests/sdk/agent/test_acp_agent.py @@ -9,15 +9,22 @@ import pytest -from openhands.sdk.agent.acp_agent import ACPAgent, _OpenHandsACPBridge -from openhands.sdk.agent.base import AgentBase -from openhands.sdk.conversation.state import ( + +pytest.importorskip("acp", reason="agent-client-protocol not installed") + +from openhands.sdk.agent.acp_agent import ACPAgent, _OpenHandsACPBridge # noqa: E402 +from openhands.sdk.agent.base import AgentBase # noqa: E402 +from openhands.sdk.conversation.state import ( # noqa: E402 ConversationExecutionStatus, ConversationState, ) -from openhands.sdk.event import ACPToolCallEvent, MessageEvent, SystemPromptEvent -from openhands.sdk.llm import Message, TextContent -from openhands.sdk.workspace.local import LocalWorkspace +from openhands.sdk.event import ( # noqa: E402 + ACPToolCallEvent, + MessageEvent, + SystemPromptEvent, +) +from openhands.sdk.llm import Message, TextContent # noqa: E402 +from openhands.sdk.workspace.local import LocalWorkspace # noqa: E402 # --------------------------------------------------------------------------- diff --git a/uv.lock b/uv.lock index 2371a160d0..eb54bd41f8 100644 --- a/uv.lock +++ b/uv.lock @@ -25,6 +25,7 @@ constraints = [ [manifest.dependency-groups] dev = [ + { name = "agent-client-protocol", specifier = ">=0.8.1" }, { name = "griffe", extras = ["pypi"], specifier = ">=2.0.0" }, { name = "packaging", specifier = ">=24.2" }, { name = "pre-commit", specifier = ">=4.3.0" }, @@ -2377,7 +2378,6 @@ name = "openhands-sdk" version = "1.12.0" source = { editable = "openhands-sdk" } dependencies = [ - { name = "agent-client-protocol" }, { name = "deprecation" }, { name = "fakeredis", extra = ["lua"] }, { name = "fastmcp" }, @@ -2393,13 +2393,16 @@ dependencies = [ ] [package.optional-dependencies] +acp = [ + { name = "agent-client-protocol" }, +] boto3 = [ { name = "boto3" }, ] [package.metadata] requires-dist = [ - { name = "agent-client-protocol", specifier = ">=0.8.1" }, + { name = "agent-client-protocol", marker = "extra == 'acp'", specifier = ">=0.8.1" }, { name = "boto3", marker = "extra == 'boto3'", specifier = ">=1.35.0" }, { name = "deprecation", specifier = ">=2.1.0" }, { name = "fakeredis", extras = ["lua"], specifier = ">=2.32.1" }, @@ -2414,7 +2417,7 @@ requires-dist = [ { name = "tenacity", specifier = ">=9.1.2" }, { name = "websockets", specifier = ">=12" }, ] -provides-extras = ["boto3"] +provides-extras = ["acp", "boto3"] [[package]] name = "openhands-tools"