OpenHands / OpenHands/software-agent-sdk

Each client declares which ACP harnesses it offers — adding one to the SDK must not reach Cloud or Replicated

Open
#4,841 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

acp enhancement
Dominant language
Python
Stars
1.1k
Forks
539
Avg merge
1d 19h
Merged PRs (30d)
137

Description

[!IMPORTANT]
Rewritten 2026-09-04. Filed as an open design question (options A–D); the decision is below. Requirement: adding an ACP harness to the SDK must not change Cloud or Replicated behaviour.

Problem

ACP_PROVIDERS declares what exists. Nothing declares what a deployment offers, so registry membership leaks straight into product surfaces.

Enterprise republishes the whole registry unfiltered:

# openhands/app_server/web_client/default_web_client_config_injector.py:320-335
acp_providers = [... for provider in ACP_PROVIDERS.values()]   # no filter

frontend/src/routes/agent-settings.tsx:97 renders it. Enterprise pins openhands-sdk==1.44.1, which predates Kimi (#4714) and Pi (#4419) — so the next routine bump puts both in Cloud Settings → Agent with no brand mark, no secret fields, no credential preflight, and a KIMI_API_KEY that per #4819 does not authenticate on its own.

Cloud legitimately differs from OSS: headless credential shape (#4629, #4819), image size (#4624 is 518 MiB, #4639 ~123 MB), install shape (#4823), licensing (#4644).

Decision

Each client declares the harnesses it offers and enforces that at conversation start. The SDK stays a registry and carries no deployment policy.

Client Declares Posture
Cloud / Replicated (OpenHands/enterprise) SURFACED_ACP_PROVIDERS, hardcoded — operators cannot widen claude-code, codex, gemini-cli
Canvas / OSS (OpenHands/OpenHands) SURFACED_ACP_PROVIDERS, derived from ACP_PROVIDER_UI claude-code, codex, gemini-cli
Evaluation (OpenHands/benchmarks) derived from the registry (#4833) everything; one harness per run

Adding a harness is an evaluation event. Canvas and Cloud enablement are separate, deliberate client changes.

A UI filter alone is not enough. ACPServerKind widens with the registry, so a persisted setting, an org-settings value (#14675/#14678), an agent profile or a direct API call will validate a harness the client does not offer. Filter and fail closed.

Why not the alternatives. A cloud_supported field on ACPProviderInfo puts deployment policy in a library that also serves OSS and eval, where the answer differs. Deriving from image contents does not work — #4805's npx fallback runs an absent npm provider anyway. A runtime capability endpoint cannot serve the app server's global web-client config, which is emitted before any sandbox exists.

Acceptance Criteria

  • Cloud declares its set, filters /api/options to it, and returns 400 for anything else at conversation start — OpenHands/enterprise#315
  • Bumping openhands-sdk to a version registering a new harness produces no observable Cloud change: no /api/options diff, no image change, no new code path
  • DEFAULT_PREINSTALLED_ACP_PROVIDERS is frozen by a test, so growing the default image stays a deliberate PR (#4643, #4820)
  • Canvas declares SURFACED_ACP_PROVIDERS independently and asserts only SURFACED_ACP_PROVIDERS ⊆ ACP_PROVIDERS, so a rename or removal breaks while an addition is a no-op
  • Benchmarks and evaluation derive their ACP tables from the registry (#4833)
  • No deployment-policy field is added to ACPProviderInfo

Open question. Cloud's free-text acp_command field launches any ACP server regardless of the allowlist. Gate it, or accept that the list governs the picker and not the escape hatch — product call.

Out of scope

Support for any particular harness (#4819, #4639, #4635, #4624) and the non-npm install mechanism (#4823).

Related: #4820 · #4833 · #4832 · #4805 · #4643 · #4644 · OpenHands/enterprise#315

This issue update was made by an AI agent (OpenHands) on behalf of the issue author.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing ACP_PROVIDERS and ACPProviderInfo, then inspect default_web_client_config_injector.py and frontend/src/routes/agent-settings.tsx to understand how registry entries reach /api/options. Review the related Cloud, Canvas, and benchmark requirements and the test that freezes DEFAULT_PREINSTALLED_ACP_PROVIDERS. Done means each client declares its offered set, unsupported harnesses fail closed, and SDK registry additions cause no unintended Cloud change.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, typescript
Domain
api, backend-api-design, cloud
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.