diff --git a/openhands-agent-server/openhands/agent_server/conversation_router_acp.py b/openhands-agent-server/openhands/agent_server/conversation_router_acp.py index d1e48df1d6..d4795a4e09 100644 --- a/openhands-agent-server/openhands/agent_server/conversation_router_acp.py +++ b/openhands-agent-server/openhands/agent_server/conversation_router_acp.py @@ -50,7 +50,13 @@ ), ).model_dump(exclude_defaults=True, mode="json"), StartACPConversationRequest( - agent=ACPAgent(acp_command=["npx", "-y", "claude-agent-acp"]), + agent=ACPAgent( + acp_command=[ + "npx", + "-y", + "@agentclientprotocol/claude-agent-acp@0.30.0", + ] + ), workspace=LocalWorkspace(working_dir="workspace/project"), initial_message=SendMessageRequest( role="user", diff --git a/openhands-agent-server/openhands/agent_server/docker/Dockerfile b/openhands-agent-server/openhands/agent_server/docker/Dockerfile index d4b59784bb..2fdbada531 100644 --- a/openhands-agent-server/openhands/agent_server/docker/Dockerfile +++ b/openhands-agent-server/openhands/agent_server/docker/Dockerfile @@ -173,7 +173,7 @@ RUN set -ux; \ if "$ACP_NODE_DIR/bin/npm" install -g \ @agentclientprotocol/claude-agent-acp@0.30.0 \ @zed-industries/codex-acp@0.11.1 \ - @google/gemini-cli@0.38.0; then \ + @google/gemini-cli@0.39.1; then \ # Create wrappers in /usr/local/bin that prepend ACP's Node 22 to PATH. # This ensures the ACP binary's #!/usr/bin/env node shebang resolves # to Node 22, while the repo's own node (NVM/system) stays untouched diff --git a/openhands-sdk/openhands/sdk/settings/acp_providers.py b/openhands-sdk/openhands/sdk/settings/acp_providers.py index f29684d93d..39ca454a6e 100644 --- a/openhands-sdk/openhands/sdk/settings/acp_providers.py +++ b/openhands-sdk/openhands/sdk/settings/acp_providers.py @@ -194,12 +194,39 @@ class ACPProviderInfo: ) +# --------------------------------------------------------------------------- +# Pinned npm versions for the built-in ACP launchers. +# +# These pair with the corresponding versions in +# ``openhands-agent-server/openhands/agent_server/docker/Dockerfile`` so that +# the version installed at image build time and the version launched at agent +# runtime cannot diverge. Bumping these requires also bumping the Dockerfile +# pins (and vice versa). +# +# Each provider runs with a permission-disabling default session mode, so the +# floating ``npx -y `` form (which would resolve npm's ``latest`` at +# launch time, after commit and lock review) is intentionally avoided here. +# +# - ``CLAUDE_AGENT_ACP_VERSION`` — pairs with Dockerfile ``@...@0.30.0`` +# - ``CODEX_ACP_VERSION`` — pairs with Dockerfile ``@...@0.11.1`` +# - ``GEMINI_CLI_VERSION`` — bumped to a patched release (>= 0.39.1) +# --------------------------------------------------------------------------- + +CLAUDE_AGENT_ACP_VERSION = "0.30.0" +CODEX_ACP_VERSION = "0.11.1" +GEMINI_CLI_VERSION = "0.39.1" + + ACP_PROVIDERS: Mapping[str, ACPProviderInfo] = MappingProxyType( { "claude-code": ACPProviderInfo( key="claude-code", display_name="Claude Code", - default_command=("npx", "-y", "@agentclientprotocol/claude-agent-acp"), + default_command=( + "npx", + "-y", + f"@agentclientprotocol/claude-agent-acp@{CLAUDE_AGENT_ACP_VERSION}", + ), api_key_env_var="ANTHROPIC_API_KEY", base_url_env_var="ANTHROPIC_BASE_URL", default_session_mode="bypassPermissions", @@ -212,7 +239,11 @@ class ACPProviderInfo: "codex": ACPProviderInfo( key="codex", display_name="Codex", - default_command=("npx", "-y", "@zed-industries/codex-acp"), + default_command=( + "npx", + "-y", + f"@zed-industries/codex-acp@{CODEX_ACP_VERSION}", + ), api_key_env_var="OPENAI_API_KEY", base_url_env_var="OPENAI_BASE_URL", default_session_mode="full-access", @@ -225,7 +256,12 @@ class ACPProviderInfo: "gemini-cli": ACPProviderInfo( key="gemini-cli", display_name="Gemini CLI", - default_command=("npx", "-y", "@google/gemini-cli", "--acp"), + default_command=( + "npx", + "-y", + f"@google/gemini-cli@{GEMINI_CLI_VERSION}", + "--acp", + ), api_key_env_var="GEMINI_API_KEY", base_url_env_var="GEMINI_BASE_URL", default_session_mode="yolo", diff --git a/tests/sdk/test_settings.py b/tests/sdk/test_settings.py index ff27ca5a1b..2fe683a6b9 100644 --- a/tests/sdk/test_settings.py +++ b/tests/sdk/test_settings.py @@ -559,7 +559,7 @@ def test_acp_create_agent_uses_server_default_command() -> None: assert agent.acp_command == [ "npx", "-y", - "@agentclientprotocol/claude-agent-acp", + "@agentclientprotocol/claude-agent-acp@0.30.0", ] assert agent.acp_model == "claude-opus-4-6"