Repository navigation
fix(ci): pin the TypeScript client's Agent Server in the release PR - #5476
Conversation
The npm publish packs the release tag as-is, but the client's agentServerImage and generated types were only bumped by a PR opened after the release, so every published client shipped a stale contract (1.51.0 pinned agent-server 1.47.0). Prepare Release now exports the OpenAPI contract from the release branch and regenerates the client with the existing bump script, and both publishers refuse a package whose agentServerImage doesn't match the release. The post-release bump job becomes a no-op. Closes #5474
REST API breakage checks (OpenAPI) — ✅ PASSEDResult: ✅ PASSED |
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was posted by an AI agent (OpenHands).
Scope check: this change belongs in this repository (release automation plus clients/typescript, both owned here) and has the direction it needs, so I reviewed the implementation. The core idea is right: build the contract from the release-branch source, as release-binaries.yml already does, and refuse to publish a client whose agentServerImage does not match the release.
One material problem, described inline: pinning the release PR to ghcr.io/openhands/agent-server:X.Y.Z-python before that image and its openapi.json release asset exist makes the release PR's own TypeScript client CI fail, and those checks cannot be re-run green while the PR is open. The PR description's local test exercised only the prepare-release.yml steps, not the release PR's client checks, so this path is untested.
The publish-time guard in both publish workflows is correct and does not depend on the image existing (it only reads package.json), and leaving bump-typescript-client in place as a no-op fallback is fine. The blocking issue is the release-PR CI regression.
🔄 CHANGES REQUESTED
| --openapi "$OPENAPI_PATH" | ||
| npm ci --prefix "$CLIENT_ROOT" | ||
| AGENT_SERVER_OPENAPI_PATH="$OPENAPI_PATH" \ | ||
| npm --prefix "$CLIENT_ROOT" run generate:agent-server-api |
There was a problem hiding this comment.
This step pins the release branch to ghcr.io/openhands/agent-server:X.Y.Z-python, but that image and the matching release asset openapi.json are only produced by create-release.yml after this PR merges (it dispatches server.yml and release-binaries.yml post-merge). The TypeScript client resolves its contract from exactly that pin: clients/typescript/scripts/agent-server-openapi.mjs first fetches https://github.com/OpenHands/software-agent-sdk/releases/download/vX.Y.Z/openapi.json, then falls back to docker run <pinned image>. Neither exists while the release PR is open, so:
.github/workflows/typescript-client-ci.yml(npm run check:agent-server-api) fails:check-agent-server-api.mjsregenerates with noAGENT_SERVER_OPENAPI_PATH, so it resolves through the pin and the generator throws.- The
endpoint-auditjob fails for the same reason (endpoint-audit.config.jsonusessource: pinned-agent-server-release). - The
smoke-testjob fails atdocker pull $AGENT_SERVER_IMAGE.
Evidence on the currently open release PR #5483 (rel-1.51.1, pin still 1.51.0): agent-server-api, endpoint-audit, and smoke-test all pass, and the agent-server-api log reads Generated .../src/generated/agent-server-schema.ts from https://github.com/OpenHands/software-agent-sdk/releases/download/v1.51.0/openapi.json. For the new pin, .../releases/download/v1.51.1/openapi.json returns 404 and docker manifest inspect ghcr.io/openhands/agent-server:1.51.1-python reports manifest unknown. Because the asset and image never exist during the PR's lifetime, these checks cannot be re-run green, which blocks the release this workflow is meant to prepare.
Consider feeding the branch-built contract to those checks instead of the pin (for example, set AGENT_SERVER_OPENAPI_PATH / AGENT_SERVER_SCHEMA_SOURCE for the client contract jobs on rel-* branches), or otherwise ensure the contract jobs tolerate a not-yet-published pin while still verifying the checked-in schema.
|
🧹 PR Artifact Cleanup Queued The |
HUMAN:
Fixing the CI for the release of the typescript client.
AGENT:
Why
typescript-client-npm-publish.ymlpacksclients/typescriptexactly as it is at tagvX.Y.Z. The client'sconfig.agentServerImageandsrc/generated/agent-server-schema.tswere only updated afterwards, by thebump-typescript-clientPR fromversion-bump-prs.yml. So every npm release shipped an older contract, and because those PRs often stayed open the gap grew:@openhands/typescript-client@1.51.0pinsagent-server:1.47.0-pythonwith 1.47.0 types (#5474).The release PR doesn't need the published image to build the contract.
export_agent_server_openapi.pybuilds it from source, asrelease-binaries.ymlalready does.Summary
prepare-release.yml: after setting versions, exportopenapi.jsonfrom the release branch, run the existingprepare_typescript_client_agent_server_bump.pyandgenerate:agent-server-api, and commit the result into therel-X.Y.ZPR.typescript-client-{npm,github-packages}-publish.yml: "Validate package version" also requiresagentServerImage == ghcr.io/openhands/agent-server:X.Y.Z-python, so a mismatched client can't be published.README-RELEASE.mdupdated.bump-typescript-clientis left as is: it already exits early when the client is "already pinned to $VERSION", so it now only acts as a fallback.Issue Number
Closes #5474
How to Test
The workflow is
workflow_dispatch-only, so I ran its steps locally in a clean worktree of this branch. I pulled therun:scripts out of the editedprepare-release.ymlwith PyYAML and ran "Set package version" → "Set TypeScript client version" → "Pin TypeScript client to the release Agent Server" withINPUTS_VERSION=9.9.9:openapi.jsonhasinfo.version == "9.9.9", so the bump script's version validation passes aftermake set-package-version.git statusmatches what the release commit should contain: 4×pyproject.toml,uv.lock, andclients/typescript/{package.json,package-lock.json,src/generated/agent-server-schema.ts}.node_modules/distare ignored.main's schema was generated by chore(typescript): agent-server to v1.51.0 #5472 from the published v1.51.0openapi.json. Comparing it with the source-built schema gives 0 changed lines apart from version strings.Publish guard, using the extracted "Validate package version" script:
pre-commit run --files <changed workflows>passes.Video/Screenshots
N/A (CI only).
Type
Notes
X.Y.Z-pythonfor the ~25 min beforeserver.ymlfinishes pushing that image. I didn't add a GHCR wait to the publishers to keep this minimal.🐳 Agent Server images for this PR — GHCR package, pull/run commands, and all pushed tags (click to expand)
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdkpython-node-runtimepython-node-runtimepython-node-runtimegolang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:8130925-pythonRun
All tags pushed for this build
About Multi-Architecture Support
8130925-python) is a multi-arch manifest supporting both amd64 and arm648130925-python-amd64) are also available if needed