Skip to content

feat(acp): typed switchAcpModel client method#189

Merged
simonrosenberg merged 6 commits into
mainfrom
feat-acp-switch-model
May 27, 2026
Merged

feat(acp): typed switchAcpModel client method#189
simonrosenberg merged 6 commits into
mainfrom
feat-acp-switch-model

Conversation

@simonrosenberg
Copy link
Copy Markdown
Contributor

Summary

Adds a typed switchAcpModel client method wrapping the agent-server endpoint POST /conversations/{id}/switch_acp_model (OpenHands/software-agent-sdk#3390), so consumers — notably agent-canvas — call a typed method instead of raw-fetching the route. It's the ACP analog of switchLlm and mirrors its surface.

Part of the unified-ACP-model-selection effort tracked in OpenHands/agent-canvas#769.

Changes

  • ConversationClient.switchAcpModel(conversationId, model)
  • RemoteConversation.switchAcpModel(model)

Both POST { model } (matching the endpoint's embedded model body field) and resolve void on Success. Server-side errors surface as HttpError: 400 (non-ACP conversation), 404 (unknown conversation), 409 (no ACP session yet — set the default via settings before the first message instead).

Validation

  • npm run build (tsc) clean; npm run format:check clean; npm run lint 0 errors.
  • npx jest api-clients41 passed (2 new: ConversationClient.switchAcpModel, RemoteConversation.switchAcpModel).

Notes

  • Independent of feat(acp): mirror available_models / default_model from openhands-sdk #187 (the registry-mirror PR) — both touch this repo but different files; no ordering between them.
  • Wraps #3390's contract; the route exists on the agent-server once #3390 merges. The method is contract-correct and tested against the documented body/response shape now.
  • Mirrored switchLlm's placement (client + RemoteConversation); deliberately not added to ConversationManager, which doesn't expose switchLlm either. Happy to add a manager passthrough if preferred.

🤖 Generated with Claude Code

Wraps the agent-server POST /conversations/{id}/switch_acp_model endpoint
(OpenHands/software-agent-sdk#3390) so consumers (e.g. agent-canvas) call a
typed method instead of raw-fetching the route. The ACP analog of switchLlm —
mirrors its surface (ConversationClient + RemoteConversation).

- ConversationClient.switchAcpModel(conversationId, model)
- RemoteConversation.switchAcpModel(model)

Body is { model } (matches the endpoint's embedded `model` field); returns
void on Success. Server-side errors (400 non-ACP, 404 missing, 409 before the
session exists) surface as HttpError to the caller.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Good taste - Clean, simple implementation that correctly mirrors the existing switchLlm pattern.

[RISK ASSESSMENT]

  • [Overall PR] ⚠️ Risk Assessment: 🟢 LOW
    Purely additive client method that wraps a new agent-server endpoint. Mirrors the existing switchLlm implementation with appropriate tests. No breaking changes, no security concerns, no dependency changes.

VERDICT:
Worth merging: Well-implemented feature addition with consistent API design

KEY INSIGHT:
Consistency in API design - this method follows the exact same pattern as switchLlm, making it intuitive for developers already familiar with the codebase.


Was this automated review useful? React with 👍 or 👎 to this review to help us measure review quality.
Workflow run: https://github.com/OpenHands/typescript-client/actions/runs/26457027996

Debug Agent and others added 5 commits May 27, 2026 12:51
The switchAcpModel unit tests mock fetch, so nothing verified the method
against a live agent-server that actually has the /switch_acp_model route
(added in software-agent-sdk #3390). Close that gap:

- Bump the integration AGENT_SERVER_IMAGE to an image containing #3390
  (main @ 9d35320; bump to the SDK release image once it's cut).
- Add a deterministic integration test: switchAcpModel on a non-ACP
  conversation must return 400 (not 404) — proving the route exists on the
  pinned image and the client targets the right path/body. No ACP credentials
  or real model switch needed, so it runs in the deterministic group.

Verified locally against an agent-server built from #3390: the new test plus
the existing deterministic-api suite (4/4) pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Resolved two conflicts (both "added at the same spot"):
- integration-tests.yml: keep AGENT_SERVER_IMAGE at 9d35320 (the #3390 merge,
  which has /switch_acp_model) rather than main's 71b070d (v1.23.1, predates
  #3390); the switchAcpModel integration test needs the route.
- deterministic-api.integration.test.ts: keep BOTH new tests — main's profile
  round-trip test and this branch's switchAcpModel contract test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
software-agent-sdk #3390 added supports_runtime_model_switch to ACP_PROVIDERS
(true for claude-code, codex, gemini-cli). The validate-acp-providers drift
check tracks SDK main, so the ts-side mirror must include it. Add the field to
the ACPProviderInfo interface and to acp-providers.json. It's the registry flag
that gates whether switchAcpModel is offered for a provider.

Verified: scripts/check-acp-drift.py passes against the #3390 SDK; build,
eslint, and 213 unit tests green.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@simonrosenberg simonrosenberg merged commit 0b8a66a into main May 27, 2026
7 checks passed
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