Skip to content

feat: automate TypeScript client contract handoff - #4234

Merged
neubig merged 6 commits into
mainfrom
feat/oss-6124-typescript-client-release-handoff
Jul 27, 2026
Merged

neubig merged 6 commits into
mainfrom
feat/oss-6124-typescript-client-release-handoff

Conversation

@neubig

@neubig neubig commented Jul 27, 2026 •

Copy link
Copy Markdown
Member

HUMAN: I checked the code here.


AGENT:

Why

The existing SDK release job only changes the TypeScript client's Agent Server
image pin. That leaves the generated transport contract stale and makes the
release handoff depend on a reviewer noticing and regenerating it manually.

Fixes #4228
Linear: OSS-6124

Summary

  • Add a tested release updater that validates an exact versioned OpenAPI
    artifact and updates every client-side Agent Server version mirror.
  • Wait for both the exact GHCR image and release openapi.json, regenerate and
    commit the client contract, and include a generated API-change summary in the
    downstream PR.
  • Keep downstream typechecking, pinned regeneration, and integration tests as
    required client PR checks so contract incompatibilities are visible without
    preventing the update PR from being proposed.

Issue Number

#4228 / OSS-6124

How to Test

  • uv run pytest -q tests/cross/test_prepare_typescript_client_agent_server_bump.py
    — 7 passed.
  • Staged pre-commit hooks passed: YAML formatting, Ruff format/lint,
    pycodestyle, Pyright, import rules, and tool registration.
  • Parsed version-bump-prs.yml and asserted the exact-artifact step exists.
  • Ran the updater against a temporary copy of the current TypeScript client and
    an OpenAPI artifact exported by this stacked SDK code. It updated 1.37.0 to
    the artifact's 1.37.1 version, regenerated the client, produced a non-empty
    API summary, and verified the generated source metadata and image pin.

The matching client-side automation and fixtures are in
OpenHands/typescript-client#303 (OSS-6126). Agent Canvas typecheck and production
build also pass against that exact packed client in a disposable HOME/XDG/state/
settings environment; ~/.openhands was never used.

Video/Screenshots

Not applicable: release automation only.

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

Stacked on #4229 and should be rebased to main after that PR merges. This SDK
workflow intentionally opens the generated client update even if handwritten
aliases need adjustment; required checks on that PR expose the incompatibility
and must pass before merge.


Agent Server images for this PR

• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.13-nodejs22-slim Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:07ee8d1-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-07ee8d1-python \
  ghcr.io/openhands/agent-server:07ee8d1-python

All tags pushed for this build

ghcr.io/openhands/agent-server:07ee8d1-golang-amd64
ghcr.io/openhands/agent-server:07ee8d10704e5e98b74ad80303e9de1b2f19b641-golang-amd64
ghcr.io/openhands/agent-server:feat-oss-6124-typescript-client-release-handoff-golang-amd64
ghcr.io/openhands/agent-server:07ee8d1-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:07ee8d1-golang-arm64
ghcr.io/openhands/agent-server:07ee8d10704e5e98b74ad80303e9de1b2f19b641-golang-arm64
ghcr.io/openhands/agent-server:feat-oss-6124-typescript-client-release-handoff-golang-arm64
ghcr.io/openhands/agent-server:07ee8d1-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:07ee8d1-java-amd64
ghcr.io/openhands/agent-server:07ee8d10704e5e98b74ad80303e9de1b2f19b641-java-amd64
ghcr.io/openhands/agent-server:feat-oss-6124-typescript-client-release-handoff-java-amd64
ghcr.io/openhands/agent-server:07ee8d1-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:07ee8d1-java-arm64
ghcr.io/openhands/agent-server:07ee8d10704e5e98b74ad80303e9de1b2f19b641-java-arm64
ghcr.io/openhands/agent-server:feat-oss-6124-typescript-client-release-handoff-java-arm64
ghcr.io/openhands/agent-server:07ee8d1-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:07ee8d1-python-amd64
ghcr.io/openhands/agent-server:07ee8d10704e5e98b74ad80303e9de1b2f19b641-python-amd64
ghcr.io/openhands/agent-server:feat-oss-6124-typescript-client-release-handoff-python-amd64
ghcr.io/openhands/agent-server:07ee8d1-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-amd64
ghcr.io/openhands/agent-server:07ee8d1-python-arm64
ghcr.io/openhands/agent-server:07ee8d10704e5e98b74ad80303e9de1b2f19b641-python-arm64
ghcr.io/openhands/agent-server:feat-oss-6124-typescript-client-release-handoff-python-arm64
ghcr.io/openhands/agent-server:07ee8d1-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-arm64
ghcr.io/openhands/agent-server:07ee8d1-golang
ghcr.io/openhands/agent-server:07ee8d10704e5e98b74ad80303e9de1b2f19b641-golang
ghcr.io/openhands/agent-server:feat-oss-6124-typescript-client-release-handoff-golang
ghcr.io/openhands/agent-server:07ee8d1-golang_tag_1.21-bookworm
ghcr.io/openhands/agent-server:07ee8d1-java
ghcr.io/openhands/agent-server:07ee8d10704e5e98b74ad80303e9de1b2f19b641-java
ghcr.io/openhands/agent-server:feat-oss-6124-typescript-client-release-handoff-java
ghcr.io/openhands/agent-server:07ee8d1-eclipse-temurin_tag_17-jdk
ghcr.io/openhands/agent-server:07ee8d1-python
ghcr.io/openhands/agent-server:07ee8d10704e5e98b74ad80303e9de1b2f19b641-python
ghcr.io/openhands/agent-server:feat-oss-6124-typescript-client-release-handoff-python
ghcr.io/openhands/agent-server:07ee8d1-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim

About Multi-Architecture Support

  • Each variant tag (e.g., 07ee8d1-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., 07ee8d1-python-amd64) are also available if needed

neubig and others added 2 commits July 27, 2026 12:25
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>

@hieptl hieptl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you! 🙏

@enyst
enyst marked this pull request as ready for review July 27, 2026 19:17
Base automatically changed from feat/oss-6121-agent-server-openapi-contract to main July 27, 2026 19:17

@enyst enyst left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Great, thank you! We need more of these ❤️

@neubig
neubig enabled auto-merge (squash) July 27, 2026 19:22
@github-actions

Copy link
Copy Markdown
Contributor

Python API breakage checks — ✅ PASSED

Result: ✅ PASSED

Action log

@github-actions

Copy link
Copy Markdown
Contributor

REST API breakage checks (OpenAPI) — ✅ PASSED

Result: ✅ PASSED

Action log

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

⚠️ QA Report: PASS WITH ISSUES

The OpenAPI artifact export and contract handoff work end-to-end, but the workflow currently depends on unmerged TypeScript-client automation.

Does this PR achieve its stated goal?

Yes, in the intended stacked setup: I generated the exact public openapi.json, validated it, ran the TypeScript client updater against the matching client automation branch, regenerated src/generated/agent-server-schema.ts, and produced a non-empty API summary. As a standalone release workflow against the current OpenHands/typescript-client default branch, it does not fully achieve the goal yet because npm run summarize:agent-server-api is missing there.

Phase Result
Environment Setup ✅ make build completed; no tests, linters, type checks, or pre-commit hooks were run.
CI Status ⚠️ Most checks are green, but Validate PR description is failing and qa-changes was in progress when checked.
Functional Verification ⚠️ Core behavior verified; downstream default-branch dependency found.
Functional Verification

Test 1: Public OpenAPI release artifact generation

Step 1 — Establish baseline/problem:
The PR says the release handoff should use an exact versioned openapi.json artifact instead of leaving the client contract stale.

Step 2 — Apply the PR's changes:
Ran the new release-artifact path on commit e99e9f9446dca3f7be9bdc0469c6f988533c6c44:

OPENHANDS_SUPPRESS_BANNER=1 uv run python .github/scripts/export_agent_server_openapi.py --output /tmp/oh-pr4234-qa/release-assets/openapi.json
OPENHANDS_SUPPRESS_BANNER=1 uv run python .github/scripts/export_agent_server_openapi.py --output /tmp/oh-pr4234-qa/release-assets/openapi-second.json
cmp /tmp/oh-pr4234-qa/release-assets/openapi.json /tmp/oh-pr4234-qa/release-assets/openapi-second.json
uv run python .github/scripts/check_agent_server_openapi_quality.py --schema /tmp/oh-pr4234-qa/release-assets/openapi.json
npx --yes @apidevtools/swagger-cli@^4 validate /tmp/oh-pr4234-qa/release-assets/openapi.json

Observed:

Agent Server OpenAPI type-quality check passed (98 allowlisted weak locations).
/tmp/oh-pr4234-qa/release-assets/openapi.json is valid

Artifact summary:

{
  "openapi": "3.1.0",
  "info": {"title": "OpenHands Agent Server", "version": "1.37.1"},
  "path_count": 94,
  "schema_count": 384,
  "has_public_only": true,
  "selected_paths": ["/api/mcp/test", "/api/settings"],
  "selected_schemas": {
    "AgentSettings": true,
    "AgentSettingsPatch": true,
    "MCPConfig": true,
    "MCPConfigPatch": true,
    "MCPTestResponse": true
  }
}

This shows the release artifact is deterministic, valid OpenAPI, public-API-filtered, versioned as 1.37.1, and includes the contract components the downstream client needs.

I also started the Agent Server with uvicorn and fetched /openapi.json over HTTP; the live app reported info.version: 1.37.1 and exposed /api/mcp/test plus /api/settings.

Test 2: Old image-only handoff reproduces the stale-contract problem

Step 1 — Reproduce / establish baseline without this PR's new handoff:
Cloned the real OpenHands/typescript-client default branch, which was pinned to ghcr.io/openhands/agent-server:1.37.0-python, then emulated the old workflow's version mirror replacement to 1.37.1.

Observed:

Baseline old workflow: 1.37.0 -> 1.37.1
schema_sha_before=af6c746f3fb6fb518aa7be1f1e69a21842af9437dbb2799468681b323a665fac
schema_sha_after=af6c746f3fb6fb518aa7be1f1e69a21842af9437dbb2799468681b323a665fac
changed_files:
AGENTS.md
README.md
package.json
package_image=ghcr.io/openhands/agent-server:1.37.1-python

This confirms the author’s stated problem: the old handoff updates the image pin but leaves src/generated/agent-server-schema.ts unchanged.

Test 3: New handoff updates mirrors, regenerates the client contract, and summarizes API changes

Step 2 — Apply the PR's changes:
Checked out the matching OpenHands/typescript-client PR branch (pull/303/head, commit 3ff8e35), installed dependencies with npm ci, and ran the same workflow commands this SDK PR adds:

python3 .github/scripts/prepare_typescript_client_agent_server_bump.py   --client-root /tmp/oh-pr4234-qa/typescript-client   --version 1.37.1   --openapi /tmp/oh-pr4234-qa/release-assets/openapi.json
AGENT_SERVER_OPENAPI_PATH=/tmp/oh-pr4234-qa/release-assets/openapi.json npm run generate:agent-server-api
npm run summarize:agent-server-api --   --before /tmp/oh-pr4234-qa/agent-server-schema-before-pr303.ts   --after src/generated/agent-server-schema.ts   --output /tmp/oh-pr4234-qa/agent-server-api-summary-pr303.md

Observed:

Prepared TypeScript client Agent Server bump 1.37.0 -> 1.37.1; changed files: package.json, AGENTS.md, README.md
Generated /tmp/oh-pr4234-qa/typescript-client/src/generated/agent-server-schema.ts from /tmp/oh-pr4234-qa/release-assets/openapi.json
schema_sha_before=b77dccad58b36925341bdc7d491776cf5dbafab429949443502cbc956cc3b8b2
schema_sha_after=160996871fb77b19af0855de300169b09f52aee058b1dd9ff8b4726e732be8a1
package_image_after=ghcr.io/openhands/agent-server:1.37.1-python
changed_files:
AGENTS.md
README.md
package.json
src/generated/agent-server-schema.ts
api_summary_lines=4

API summary preview:

- Generated TypeScript diff: **+7652 / -8599 lines**
- Added exported types: `AgentSettings`, `AgentSettingsPatch`, `AgentSettingsPatchWritable`, `McpAuthCredential`, `McpConfig`, `McpConfigPatch`, `McpConfigPatchWritable`, `McpNoneAuthCredential`, `McpServer`, `McpServerPatch`, `McpServerPatchWritable`, `McpTestResponse`, `RemoteMcpServer`, `RemoteMcpServerWritable`, `SettingsUpdateRequestWritable`, `StdioMcpServer`
- Removed exported types: `AliveAliveGetData`, `AliveAliveGetResponse`, `AliveAliveGetResponses`, `Annotation`, `AnnotationUrlCitation`, `BrowserActionWithRisk`, `BrowserClickActionWithRisk`, `BrowserCloseTabActionWithRisk`, `BrowserGetContentActionWithRisk`, `BrowserGetStateActionWithRisk`, `BrowserGetStorageActionWithRisk`, `BrowserGoBackActionWithRisk`, `BrowserListTabsActionWithRisk`, `BrowserNavigateActionWithRisk`, `BrowserScrollActionWithRisk`, `BrowserSetStorageActionWithRisk`, `BrowserStartRecordingActionWithRisk`, `BrowserStopRecordingActionWithRisk`, `BrowserSwitchTabActionWithRisk`, `BrowserTypeActionWithRisk`, `ChatCompletion`, `ChatCompletionAudio`, `ChatCompletionMessage`, `ChatCompletionMessageCustomToolCall`, `ChatCompletionMessageFunctionToolCall`, and 63 more
- Existing exported declarations may also contain field-level changes; review the generated diff.

This verifies the new flow changes the generated contract file and creates the API-change summary promised in the PR description.

Test 4: Exact-version artifact validation rejects mismatches

Ran the updater with an openapi.json whose info.version was changed to 9.9.9 while requesting release 1.37.1.

Observed:

exit_code=1
OpenAPI artifact version '9.9.9' does not match Agent Server release '1.37.1'

This confirms the updater rejects a non-exact OpenAPI artifact instead of silently using the wrong contract.

Unable to Verify / Dependency Caveat

The same new workflow commands do not currently complete against OpenHands/typescript-client default branch (ca939d7): after npm ci, prepare_typescript_client_agent_server_bump.py, and npm run generate:agent-server-api, the command npm run summarize:agent-server-api failed with:

npm error Missing script: "summarize:agent-server-api"
npm error
npm error Did you mean one of these?
npm error   npm run generate:agent-server-api # run the "generate:agent-server-api" package script
npm error   npm run check:agent-server-api # run the "check:agent-server-api" package script

I verified the full handoff on the matching client PR branch instead. Future QA would be simpler if AGENTS.md or the PR description named the exact downstream client branch/merge prerequisite for release-handoff verification.

Issues Found

  • 🟠 Issue: The SDK release workflow currently requires OpenHands/typescript-client to already contain summarize:agent-server-api; the current default branch does not, so the handoff job fails unless the matching client PR lands first.

This QA review was created by an AI agent (OpenHands) on behalf of the user.

Final verdict: PASS WITH ISSUES.

--openapi "$OPENAPI_PATH"
AGENT_SERVER_OPENAPI_PATH="$OPENAPI_PATH" \
npm run generate:agent-server-api
npm run summarize:agent-server-api -- \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Important: The workflow now calls npm run summarize:agent-server-api, but a real run against the current OpenHands/typescript-client default branch failed because that script is missing. I verified the full flow succeeds on the matching TypeScript-client PR branch (pull/303/head), so this is a release-order dependency: either ensure that downstream PR is merged before this SDK release handoff can run, or add a fallback/guard here so the job does not fail on the current client default branch.

@neubig
neubig merged commit 421601e into main Jul 27, 2026
33 checks passed
@neubig
neubig deleted the feat/oss-6124-typescript-client-release-handoff branch July 27, 2026 19:26
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.

[Agent Server] Automate versioned OpenAPI handoff in the TypeScript-client release bump

4 participants