Bump the pinned agent-server/openhands-sdk version from 1.33.0 to 1.35.0 and
the automation package from 1.1.4 to 1.1.6. openhands-automation 1.1.6
(published to PyPI) depends on openhands-sdk/openhands-workspace 1.35.0, so
this keeps Canvas in sync with the released automation package.
Verified with: EXPECTED_SDK_VERSION=1.35.0 node scripts/check-sdk-version-sync.mjs
--check-pypi -> 'All SDK versions are in sync!'. dev-safe tests pass (52/52).
Co-authored-by: Engel Nyst <engel.nyst@gmail.com>
* chore: bump agent-server SDK to 1.33.0 and automation to 1.1.4
Bump config/defaults.json pins:
- versions.agentServer 1.32.0 -> 1.33.0
- versions.automation 1.1.3 -> 1.1.4
Everything else (dev-safe.mjs, docker.yml, mock-llm workflows) reads these
from defaults.json. Updated the dev-safe.test.ts expectations and the two
concrete AGENTS.md version references to match.
The agent-client-protocol<0.11 guard stays: openhands-sdk 1.33.0 still pins
agent-client-protocol>=0.10.1 (unchanged from 1.32.0), so acp 0.11.0 would
still break the ACP client.
Blocked until openhands-automation 1.1.4 (pinned to SDK 1.33.0) publishes to
PyPI, since the sdk-version-sync check resolves the released automation's SDK
deps. Draft until then.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: sync remaining 1.32.0 version examples to 1.33.0
The drift-detection test (docs-version-sync) requires JSDoc examples in
scripts/dev-safe.mjs and scripts/check-sdk-version-sync.mjs to match the
config/defaults.json agent-server pin. Also refresh the acp-constraint
comments in mock-llm-e2e.yml and defaults.json for consistency.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Squash merge PR #1583.
This merge commit was created by an AI agent (OpenHands) on behalf of Graham Neubig.
Co-authored-by: openhands <openhands@all-hands.dev>
* chore(deps): bump @openhands/typescript-client to 1.27.0
* test: update ACP provider/model fixtures for typescript-client 1.27.0
1.27.0 refreshed the claude-code/codex ACP registry data: provider command
versions (claude-agent-acp 0.30.0->0.44.0, codex-acp 0.15.0->0.16.0),
claude-code model ids (claude-opus-4-8->opus[1m], claude-sonnet-4-6->sonnet,
claude-haiku-4-5->haiku) plus a new well-labeled "default" option, and the
codex default (gpt-5.5/medium->gpt-5.5).
Canvas sources these lists from the client registry (closes#740), so the
source was already correct -- only the hardcoded test expectations were
stale. Also relaxed the acp-providers placeholder guard to accept the SDK's
intentional "Default (recommended)" entry.
* chore(deps): bump agent-server/openhands-sdk to 1.29.0
Align the spawned agent-server SDK release train (openhands-sdk,
openhands-tools, openhands-workspace, openhands-agent-server) with the
version @openhands/typescript-client 1.27.0 is validated against
(agent-server 1.29.0-python). Bump the coupled openhands-automation pin
to 1.0.0a12, whose SDK deps resolve to 1.29.0, to satisfy the
check-sdk-version-sync gate. minimumAgentServer compat floor unchanged.
Doc/JSDoc/test references updated to keep docs-version-sync green.
* fix: seed AUTOMATION_KV_SECRET for local dev
The KV store (automation PR#69) requires AUTOMATION_KV_SECRET to be set
or every KV endpoint returns 503. In a local dev stack the secret is never
configured, so the store is silently unavailable.
Fall back to sessionApiKey when the env var is not set explicitly — the
same zero-config pattern already used for AUTOMATION_AGENT_SERVER_URL,
AUTOMATION_BASE_URL, and AUTOMATION_WORKSPACE_BASE.
Co-authored-by: openhands <openhands@all-hands.dev>
* chore: bump openhands-automation to 1.0.0a10
Update to the latest released version of openhands-automation on PyPI.
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
The automationSdk version was always intended to equal agentServer.
Having a separate field creates a maintenance foothole where the two
values can silently drift. Remove automationSdk from defaults.json and
have all consumers (check-sdk-version-sync, dev-with-automation,
agent-canvas CLI --version output) read versions.agentServer directly.
The sync check still catches any mismatch between the released
openhands-automation package and the expected SDK version.
Co-authored-by: openhands <openhands@all-hands.dev>
* Bump minimum compatible agent server
* Apply version compatibility to backend health
* Explain backend health failures in manage modal
---------
Co-authored-by: neubig <398875+neubig@users.noreply.github.com>
* chore: bump agent-server → 1.28.1, automation → 1.0.0a9, extensions → 0.4.1
Co-authored-by: openhands <openhands@all-hands.dev>
* Test fixes
* fix: inject proxy base_url for litellm_proxy/* when server omits it (agent-server ≥1.28)
Agent-server ≥1.28 may return base_url:null when fetching a litellm_proxy/*
profile config, even when the profile was saved with the All-Hands proxy URL.
This caused the Basic-tab re-save flow in LlmSettingsLocalView.handleSave to
call isOpenHandsProxyModel(model, null) → false, hitting the else-branch that
deletes base_url and stranding the profile (issue #1146).
Fix: add a secondary check — litellm_proxy/* with a missing base_url is treated
the same as litellm_proxy/* with the proxy URL already set, and
OPENHANDS_LLM_PROXY_BASE_URL is injected before the save request is sent.
Also updates the mock-LLM E2E test to accept both storage representations:
- litellm_proxy/* + proxyBaseUrl (pre-1.28, guards issue #1146 regression)
- openhands/* + null (1.28+, server-managed routing)
And adds a unit test exercising the base_url:null path.
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
* chore: bump agent-server → 1.28.1, automation → 1.0.0a9, extensions → 0.4.1
Co-authored-by: openhands <openhands@all-hands.dev>
* chore: update doc examples to reference agent-server 1.28.1
Update version references in AGENTS.md, scripts/dev-safe.mjs, and
scripts/check-sdk-version-sync.mjs from 1.27.0 → 1.28.1 to stay
in sync with the agentServer pin in config/defaults.json.
Fixes: docs-version-sync.test.ts failures
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: inject proxy base_url for litellm_proxy/* when server omits it (agent-server ≥1.28)
Agent-server ≥1.28 may return base_url:null when fetching a litellm_proxy/*
profile config, even when the profile was saved with the All-Hands proxy URL.
This caused the Basic-tab re-save flow in LlmSettingsLocalView.handleSave to
call isOpenHandsProxyModel(model, '') → false, hitting the else-branch that
deletes base_url and stranding the profile (issue #1146).
Fix: add a secondary check for litellm_proxy/* models with a missing base_url
(null/undefined/empty), treating them the same as a stored proxy URL and
injecting OPENHANDS_LLM_PROXY_BASE_URL before the save request is sent.
Also adds a unit test exercising the base_url:null path.
Co-authored-by: openhands <openhands@all-hands.dev>
* test(e2e): accept agent-server 1.28 model rewrite in proxy profile test
Agent-server 1.28 normalises litellm_proxy/* → openhands/* on storage
and manages the proxy URL internally (returning base_url:null). The old
assertions hard-coded the pre-1.28 storage format (litellm_proxy/* +
explicit proxy URL), causing the test to fail on every 1.28 run.
Extract assertProxyProfileConfig() helper that accepts both storage
representations:
- litellm_proxy/* + proxyBaseUrl (pre-1.28, guards issue #1146 regression)
- openhands/* + null (1.28+, server-managed routing)
The issue #1146 guard is preserved: a litellm_proxy/* profile without a
proxy URL is still flagged as a stranded profile.
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
Keep package metadata in sync with config/defaults.json so npm scripts and mock E2E logs report the current agent-canvas RC version.
Co-authored-by: openhands <openhands@all-hands.dev>
* bump automation to 1.0.0a7 and add automationSdk==agentServer version test
- Update versions.automation: 1.0.0a6 → 1.0.0a7 (latest on PyPI)
- Update versions.automationSdk: 1.22.1 → 1.27.0
openhands-automation==1.0.0a7 depends on openhands-sdk==1.27.0,
which now matches versions.agentServer (1.27.0)
- Add 'versions.automationSdk matches versions.agentServer' test in
__tests__/scripts/check-sdk-version-sync.test.ts so any future bump
that forgets to keep both fields in sync fails CI immediately
- Add config/defaults.json to sdk-version-sync.yml path triggers so
the PyPI metadata check also fires when the config file is changed
Co-authored-by: openhands <openhands@all-hands.dev>
* remove automationSdk==agentServer static test
The sdk-version-sync workflow already covers the meaningful invariant
(automationSdk matches what the released openhands-automation on PyPI
actually depends on). The static test enforced automationSdk===agentServer
at all times, but the script explicitly allows automationSdk to lag
agentServer while a compatible automation release is pending — making
the test both unnecessary and incorrect.
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
* settings: persist app preferences and disabled_skills on the agent-server
The local agent-server now exposes app_preferences on the persisted
settings (OpenHands/software-agent-sdk#3539): language, sound
notifications, analytics consent, git identity, and disabled_skills are
returned on GET /api/settings under app_preferences and updated via a
new app_preferences_diff field on PATCH /api/settings.
This brings the local agent-server to parity with the cloud, which has
always accepted the same keys at the top level. Drops the localStorage
workaround that mirrored these fields in two keys
(openhands-agent-server-app-preferences and
openhands-agent-server-disabled-skills), along with the
app-preferences-store.ts module and the DISABLED_SKILLS_STORAGE_KEY
helpers it depended on.
- SettingsService.transformApiResponse reads app_preferences from the
server response and hoists each field onto the flat Settings shape so
consumers (settings.language, settings.disabled_skills, …) keep
working unchanged.
- SettingsService.saveSettings routes the same set of fields through
the new app_preferences_diff for local backends and through the
existing app_preferences flat-spread path for cloud backends.
- New legacy-app-preferences-migration.ts runs once on first
getSettings() after upgrade: when the server reports an
app_preferences block AND legacy localStorage values are still
present, it pushes them up via app_preferences_diff and clears the
legacy keys. Pre-1.27 servers (which omit app_preferences entirely)
cause the migration to no-op so existing data isn't dropped before
the server can accept it.
- Updated MSW handlers to round-trip app_preferences and
app_preferences_diff so the mock backend matches production.
- Test coverage: 5 new tests in __tests__/api/settings-service.test.ts
for the local round-trip, the mixed diff routing, the legacy
migration, and the pre-1.27 skip path.
Closes the localStorage workaround called out in the recent audit of
agent-canvas localStorage usage (items 3 and 4: disabled_skills and
app-preferences fields).
Depends on agent-server 1.27 / SDK PR #3539.
Co-authored-by: openhands <openhands@all-hands.dev>
* settings: read/write app preferences via misc_settings container
Follow-up to the localStorage cleanup in this PR + SDK refactor in
openhands/software-agent-sdk#3543. The agent-server now exposes
frontend-owned settings under a generic misc_settings container instead
of a top-level app_preferences field.
Wire shape changes:
Before: After:
GET /api/settings GET /api/settings
-> { app_preferences: {...} } -> { misc_settings: { app_preferences: {...} } }
PATCH /api/settings PATCH /api/settings
body.app_preferences_diff (shallow body.misc_settings_diff (deep-merged,
overlay, replaces named fields) same semantics as agent_settings_diff)
Why the rename to misc_settings: the previous name pinned the API to a
single 'frontend-owned' namespace. Adding a future category like
ui_preferences (sidebar layout / view modes) would have required either
yet another top-level field or shoehorning unrelated UI state into
AppPreferences. With misc_settings as a container, new categories drop
in as nested fields without churning the top-level shape.
Changes:
- settings-service.api.ts
* SettingsApiResponse.app_preferences -> .misc_settings (typed)
* SettingsUpdateRequest.app_preferences_diff -> .misc_settings_diff
* Add MiscSettings interface
* transformApiResponse reads response.misc_settings?.app_preferences
* saveSettings emits { misc_settings_diff: { app_preferences } }
* Local 'has any diffs' check tracks misc_settings_diff
* Doc comments updated; semantics noted as deep-merge
- legacy-app-preferences-migration.ts
* Gate on serverResponse.misc_settings, not .app_preferences
* pushDiff callback now wraps the diff in { app_preferences: ... }
- src/mocks/settings-handlers.ts
* GET handler returns misc_settings.app_preferences
* PATCH handler accepts misc_settings_diff; deep-merges nested
app_preferences into the persisted block
* Internal mock state stores under misc_settings to match wire shape
- __tests__/api/settings-service.test.ts
* Four tests updated to assert the new wire shape (local PATCH body,
GET round-trip, mixed-diff routing, legacy localStorage migration)
* Pre-1.27 detection test now keys off missing misc_settings
- AGENTS.md
* App-preferences note rewritten for the misc_settings container,
explains deep-merge semantics, and documents the in-flight rename
(flat shape introduced in #3539 never shipped to users)
Cloud path is unchanged: cloud /api/v1/settings still accepts the
fields as flat top-level keys, mirrored by saveCloudSettings.
Verification:
$ npm run typecheck
exit 0
$ npm test -- __tests__/api/settings-service.test.ts \
__tests__/api/mock-settings-handlers.test.ts
23 tests passed
$ npm test
3009 passed | 12 skipped | 9 todo
$ npm run lint
All matched files use Prettier code style!
$ npm run build
built in 1.50s
Co-authored-by: openhands <openhands@all-hands.dev>
* Bump agent-server default to 1.27.0
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: GitHub MCP server works in Docker without Docker-in-Docker
The GitHub MCP catalog entry uses `docker run` as its transport command,
which fails inside the agent-canvas Docker container because Docker is not
available (no daemon, no CLI). This is the only MCP integration affected —
all others use `npx` or `uvx`.
Fix:
- Pre-install the `github-mcp-server` Go binary in the Docker image via a
new multi-arch download stage (supports amd64/arm64)
- Export `getDeploymentMode()` from agent-server-adapter to expose the
runtime services info mode ("docker", "dev:automation", etc.)
- Add `patchGitHubEntry()` in mcp-marketplace-utils.ts that rewrites the
catalog entry from `docker run … ghcr.io/github/github-mcp-server` to
`github-mcp-server stdio` when deployment mode is "docker"
- The patch follows the existing `patchLinearEntry` pattern: immutable
spread, conditional on entry id, wired into `getMcpMarketplaceCatalog()`
Closes#1190
* docs: document GitHub MCP catalog patching in AGENTS.md
Co-authored-by: openhands <openhands@all-hands.dev>
* test: add E2E test for GitHub MCP install flow via marketplace UI
Exercises the full MCP page UI flow:
- Navigate to /mcp, verify GitHub marketplace card is visible
- Open install modal, verify fields (command, PAT input)
- Validate empty PAT shows error
- Fill PAT, submit with mocked /api/mcp/test success, verify installed
- Delete installed server via toggle + confirmation modal
Intercepts POST /api/mcp/test to return mock success since the real
github-mcp-server binary is not available in the test environment.
Co-authored-by: openhands <openhands@all-hands.dev>
* chore: track github-mcp-server version in config/defaults.json
Move the hardcoded GITHUB_MCP_SERVER_VERSION=1.2.0 from the Dockerfile
default into config/defaults.json (versions.githubMcpServer) alongside
the other external dependency pins.
- Dockerfile: ARG no longer has a default; CI and local builds must
pass it explicitly
- docker.yml: reads the version from config and passes it as a build-arg
- docker-build.mjs: reads the version from config and passes it too
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: correct GitHub MCP binary download URL and remove flaky validation test
- Fix Dockerfile: release assets use github-mcp-server_Linux_{arch}.tar.gz
(no version in the filename), not github-mcp-server_{version}_Linux_{arch}.tar.gz
- Remove step 3 (empty PAT validation test) which relied on CSS class
selector that doesn't work reliably in Playwright with compiled Tailwind
- Renumber remaining steps (4→3, 5→4)
Co-authored-by: openhands <openhands@all-hands.dev>
* docs: address review comments — document docker command assumption and arch fallback
- mcp-marketplace-utils.ts: explain why we match on command === 'docker'
and what happens if upstream changes the catalog entry
- Dockerfile: document the *) arch fallback and when to update it
Co-authored-by: openhands <openhands@all-hands.dev>
* test: assert Docker-specific command patching in GitHub MCP E2E test
The test now asserts the command field value based on the deployment mode:
- Docker E2E: expects 'github-mcp-server stdio' (native binary)
- npm E2E: expects 'docker' (original catalog transport)
Uses MOCK_LLM_DOCKER_IMAGE env var presence (set only by the Docker
Playwright config) to determine which assertion to make. This ensures
the patchGitHubEntry runtime rewrite is exercised in Docker E2E.
Co-authored-by: openhands <openhands@all-hands.dev>
* test: add unit tests for patchGitHubEntry Docker command rewrite
Addresses review feedback to add unit test coverage for the runtime
catalog patching. Three new tests via getMcpMarketplaceCatalog:
- Non-Docker mode: GitHub entry keeps original 'docker run' command
- Docker mode: command rewritten to 'github-mcp-server stdio'
- Docker mode: other entries (Tavily) unaffected
Uses vi.mock to control getDeploymentMode return value.
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
Update agentServer version pin in config/defaults.json from 1.25.0 to 1.26.0.
This drives all four packages (openhands-agent-server, openhands-sdk,
openhands-tools, openhands-workspace) which are released in lockstep.
Also update matching test expectations and example version strings in
dev-safe.mjs, check-sdk-version-sync.mjs, and AGENTS.md.
Co-authored-by: openhands <openhands@all-hands.dev>
* chore: bump openhands-automation to 1.0.0a6
* Remove fragile automation version assertion test
The test hardcoded an exact version string that breaks on every
version bump. It provides no utility — the version is already
covered by integration/config tests; pinning it in a unit test
just means a manual edit is required on every release.
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>