OpenHands / OpenHands/software-agent-sdk
Each client declares which ACP harnesses it offers — adding one to the SDK must not reach Cloud or Replicated
Nobody has claimed this yet.
- 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/optionsto it, and returns 400 for anything else at conversation start — OpenHands/enterprise#315 - Bumping
openhands-sdkto a version registering a new harness produces no observable Cloud change: no/api/optionsdiff, no image change, no new code path -
DEFAULT_PREINSTALLED_ACP_PROVIDERSis frozen by a test, so growing the default image stays a deliberate PR (#4643, #4820) - Canvas declares
SURFACED_ACP_PROVIDERSindependently and asserts onlySURFACED_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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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