Skip to content

fix(agents): upgrade opencode to 2.2.1 - #2767

Merged
mattzcarey merged 2 commits into
mainfrom
gardener/upstream/opencode-2.2.1
Oct 29, 2026
Merged

mattzcarey merged 2 commits into
mainfrom
gardener/upstream/opencode-2.2.1

Conversation

@github-actions

@github-actions github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Moves agents/harness/opencode, agents/models/opencode and the OpenCode example from opencode 2.0.24 to 2.2.1, and fixes agents/models/opencode, which fails every turn on 2.2.1.

Package From To
@opencode/sdk (dev pin, example) 2.0.24 2.2.1
@opencode/plugin (dev pin, example) 2.0.24 2.2.1
peer range ^2.0.24 ^2.0.24 (unchanged)

Since our pin, opencode has shipped 2.0.25–2.0.32, 2.1.0–2.1.4, 2.2.0 and 2.2.1. Our caret peer range already lets users install all of them. On 2.2.1, agents/models/opencode is broken for those users today: every run fails with provider.no-route (details below). This PR fixes that and moves our pins. It supersedes #2725 (2.2.0), which only github-actions[bot] committed to.

What changed upstream that affects us

  • high · breaking: "chore(core): remove bundled cohere, vercel and perplexity AI SDK packages" (fc6922f). This is an @opencode/core commit, not one in packages/sdk or packages/plugin. The test failure led me to it. @opencode/core 2.2.1, which @opencode/sdk 2.2.1 depends on, drops @ai-sdk/vercel and its VercelPlugin sdk hook. agents/models/opencode names aisdk:@ai-sdk/vercel as its provider package so that OpenCode's sdk step loads it in-process, and then our language hook swaps in our model (packages/agents/src/models/opencode/index.ts:50-62). Now no built-in hook claims that package, so DynamicProviderPlugin passes it to its npm installer. An external plugin's sdk hook only runs after that. I checked: adding our own sdk hook did not help. The installer can't run in workerd. Every run ended with session.execution.failed, provider.no-route: "Cannot initialize cloudflare/@cf/moonshotai/kimi-k2.7-code: Cannot destructure property 'LRUCache' of 'require(...)' as it is undefined." The provider now names gitlab-ai-provider. In every tag from v2.0.24 to v2.2.1, GitLabPlugin is registered and its sdk hook checks only evt.package !== "gitlab-ai-provider", then imports the bundled package. Its language hook and provider transforms only act on the gitlab provider id, so ours still makes the model:
    -const CARRIER_PACKAGE = "aisdk:@ai-sdk/vercel";
    +const CARRIER_PACKAGE = "aisdk:gitlab-ai-provider";
    The doc comment above it now says why.
  • high · breaking (tests and example build): "chore: upgrade Effect to rc.118" (1aae67e) and "chore: upgrade Effect to 4.0.1" (41b03de). Effect 4.0.1 ships the Scalar API-reference script at effect/dist/http-api/internal/httpApiScalar.js. Our stubs matched the old unstable/httpapi path (packages/agents/src/harness/opencode/tests/vitest.config.ts:16, examples/next/harnesses/opencode/vite.config.ts:16). Same change in both files, as in chore(deps): upgrade opencode to 2.2.0 #2725:
    -        id.includes("/effect/dist/unstable/httpapi/internal/httpApiScalar.js")
    +        id.includes("/effect/dist/http-api/internal/httpApiScalar.js")
  • high · breaking (tests only): not a packages/sdk or packages/plugin commit. @opencode/core 2.2.x inlines the models.dev catalog as one string literal (// src/models-dev/snapshot.txt / var snapshot_default = '…'). In 2.2.1 that is dist/chunks/credential-yap2aqf7.js, 8,220,567 bytes. With only the pins moved, workerd closed the module-runner socket ("WebSocket protocol error; statusCode = 1009; Message is too large") and harness-opencode ran 5/14. The test Workers set models: { fetch: false } and use only our Cloudflare provider (packages/agents/src/harness/opencode/tests/worker.ts:67-74), so the test config swaps in an empty catalog (vitest.config.ts:20-35). This is chore(deps): upgrade opencode to 2.2.0 #2725's plugin, unchanged:
    +    {
    +      name: "empty-models-dev-snapshot",
    +      enforce: "pre",
    +      transform: (code, id) =>
    +        id.includes("/@opencode/core/dist/") &&
    +        code.includes("// src/models-dev/snapshot.txt")
    +          ? code.replace(
    +              /(\/\/ src\/models-dev\/snapshot\.txt\nvar snapshot_default = )'.*';/,
    +              "$1'{}';"
    +            )
    +          : null
    +    },
  • medium · new feature (deprecation): "refactor(client): group experimental SDK methods under client.experimental" (9a9386e). sessions.wait, sessions.log and sessions.instructions move to client.experimental.session.*. The old paths stay as aliases, marked "@deprecated … Removed in the next minor". The harness calls opencode.sessions.wait (packages/agents/src/harness/opencode/harness.ts:536, :670) and opencode.sessions.log (harness.ts:1242), and the public OpenCodeLogEvent type is derived from OpenCode["sessions"]["log"] (types.ts:44-45). All of these still work and typecheck on 2.2.1. Not adopted: client.experimental.session.* doesn't exist before 2.2.1, so using it would raise the peer floor to ^2.2.1. See Needs a maintainer.
  • low · breaking (stored data, no code change): "refactor: v2.1 minor breaking changes" (acdcdb8). In the reviewed packages, this renames the plugin type SessionCompactionResult.providerState to native. Neither models/opencode nor the harness implements compaction, and the session.compaction.* cases (events.ts:264-276) read only reason and error.message. The same commit changes the stored session schema in @opencode/schema (session-message.ts, session-event.ts) and adds a session-legacy.ts decoder, so 2.1+ reads older sessions. I did not check field by field whether 2.0.x can read sessions 2.1+ writes. It only matters for rolling back a deployment (see Merge Danger).
No effect on us (68)
  • "release: v2.2.1" (3ebcf9a), "release: v2.2.0" (8697644) and 14 "sync release versions for v2.0.24 … v2.1.4" commits (bd55d48, 62e087f, 8059cdc, 03cb9b9, c5aabae, 34d8ded, f40dc43, 83c5abb, 4e95dac, d30e990, 133b1eb, 4b50f5c, e965774, 2a3e7c0): version numbers only.
  • 7 merge commits (be315b1, 4b83402, fd0efe3, bcd713e, 316a688, 15d4afd, 3a58a0c): they only carry commits listed here.
  • "feat(core): add image_generate tool" (89f3ac1): adds an image kind to the plugin's SessionIdleBackground. We don't use that hook, and the harness ignores event types it doesn't map (events.ts:299).
  • "feat(core): add /goal with a client-side done check" (8de0323): a new experimental.idle session hook and GUI registries. We don't use them.
  • "chore(plugin): remove unused @tsconfig/node22" (1dab9ae), "feat(app): refine artifact previews and file actions" (b3de41a), "feat(app): add session location menu actions" (4ba064f): a dev dependency, and GUI icon names and built-ins.
  • "feat(protocol): define experimental image and decision generation endpoints" (2a0639a): adds ctx.experimental.generate. Our plugins don't call generate.
  • "feat(plugin): add OpenCode Desktop GUI plugins" (dae4077), "feat(plugin): add toasts, dialogs, notifications, UI, tabs and composer APIs to GUI plugins" (758cf5a), "feat(app): manage desktop plugins in Extensions › Plugins" (5792c3e), "fix(app): list What's new with About in settings" (19d87a7): new @opencode/plugin/gui* subpaths. We import only the package root, and we pass plugins as objects.
  • "feat(plugin): filter event subscriptions by type" (1434464): an optional types filter. The harness subscribes through opencode.events.subscribe unfiltered, and the event-stream tests pass.
  • "fix(server): stop form polling from booting idle locations" (c8cf3a5), "fix(app,server): stop subagent form polling from stalling sends" (946c331): an internal live check in the SDK's instance map.
  • "refactor(ai): make Promise the root entry and move Effect to @opencode/ai/effect" (dad29a8): import paths inside the plugin's types.
  • "refactor(core): keep Go allowance out of messages and sessions" (de284dc) and "feat(core): record reported cost and Go allowance" (4cba1b7): TUI context only, and the two cancel out.
  • "fix(tui): identify config-defined providers" (cc4faf4) and its revert (cd15a6a): net zero.
  • "feat(plugin): expose session instruction entries to plugins" (6c74e11), "feat(plugin): expose session list" (bc5fa1c), "feat(plugin): let plugins assert permissions" (6a7cedc), "feat(plugin): expose credential.activate to server plugins" (d782675), "feat(integration): add declarative external connection method" (70c6c8c): new plugin APIs we don't use.
  • "fix(app): show untracked folders as one review row" (21ed6e4): an optional VCS diff field, unused.
  • "refactor: remove redundant casts and duplicate helpers across sdk, plugin, codemode, and schema" (7a62a46): Model.Info.default, Model.ID.make and Provider.ID.make (models/opencode/index.ts:121-124) are unchanged.
  • "feat(sdk): seed host plugins before recovery and harden workerd defaults" (55dde88): plugins register before suspended sessions resume. We had no workaround for the old order.
  • "fix(plugin): return Promise tool throws as tool failures" (1438073), "fix(plugin): keep each Promise hook rejection on its own tool call" (7351718): the example's tools throw to report failure, and the model now sees that as a tool failure, as intended.
  • "fix(sdk): release completed embedded request signals" (9ee97d8): internal fetch bookkeeping.
  • "fix(core): route file overrides through Workspace.connect" (c50e39b): Effect-entry exports. We use the Promise @opencode/sdk/workerd API.
  • "fix(cli): give plugins the host's Effect" (c28e9ec): Bun-only loader.
  • "chore: remove unused dependencies from V2 packages" (50ae4bd): we import neither zod nor @standard-schema/spec through the plugin.
  • "chore: upgrade opentui v0.7.0" (ab4d1f3), "chore: upgrade opentui v0.6.8" (c9c1dc0), "chore: OpenTUI 0.6.5" (c7ddff7), "chore(tui): revert OpenTUI 0.6 upgrade" (def5d94), "chore(tui): upgrade OpenTUI to 0.6.2" (65f8907), "chore: upgrade opentui v0.5.17" (da40b8f), "chore: upgrade opentui v0.5.16" (fcad131), "feat(tui): report pending session status to the terminal" (d0a2ce3): TUI only.
  • "feat(app): add generative UI to the GUI" (f232362), "ci: separate release builds from signing and publishing" (6996bbc), "fix(release): add repository to ai, plugin and cli package.json" (fa5b4bd), "chore: use bun check for local typechecks and TypeScript 7.1 in CI" (84578e1), "chore: upgrade typecheck to TypeScript 7.0.2" (23359e9), "chore(ci): speed up and stabilize the test workflow" (17229d2): upstream tooling.

Decisions

  • Carrier package: gitlab-ai-provider. I chose it over:

    • registering our own sdk hook. It runs after DynamicProviderPlugin's installer, and the test still failed.
    • @ai-sdk/github-copilot. Its sdk hook also requires providerID === "github-copilot".
    • moving to OpenCode's native @opencode/ai/providers/* path. That bypasses the language hook the provider is built on.

    gitlab-ai-provider is a dependency of @opencode/core in every release in our peer range. Its hook is the same in all of them, so the fix needs no floor change. One side effect: OpenCode keys per-request provider options by package, and for this package it uses the provider id. So anything OpenCode puts there now lands in providerOptions.cloudflare, which our models read, instead of providerOptions.vercel. Today that is nothing. Our models are Model.Info.default with variants: [], and OpenCode strips the only provider settings we set (baseURL, apiKey) from request options.

  • Peer range stays ^2.0.24. The fix works on every release in the range. Raising the floor would push users onto 2.1+'s session format for no code reason.

  • Changeset: patch (.changeset/opencode-2-2-1-carrier.md). Published source in agents/models/opencode changes, and the peer range doesn't.

  • Keep sessions.wait/sessions.log (deprecated in 2.2.1) instead of experimental.session.*, for the floor reason above.

  • The empty-catalog stub is test-only, as in chore(deps): upgrade opencode to 2.2.0 #2725. The OpenCode example's vite build passes without it.

  • Supersede chore(deps): upgrade opencode to 2.2.0 #2725. It includes the Scalar and catalog fixes, but on 2.2.0. Moving it to 2.2.1 would also need the carrier fix.

Needs a maintainer

  • opencode 2.3 removes sessions.wait/sessions.log, and ^2.0.24 admits 2.3. Options:

    • cap the peer range at <2.3.0 now;
    • when 2.3 ships, move to experimental.session.* and raise the floor to ^2.2.1;
    • pick the method at runtime.

    Recommendation: the second, in the run that upgrades to 2.3. It keeps 2.0.x users working until then, and the next run's review flags the removal.

  • Whether the example's vite dev hits the 8 MB module limit (carried over from chore(deps): upgrade opencode to 2.2.0 #2725). I couldn't run it: its remote AI binding needs CLOUDFLARE_API_TOKEN. Recommendation: run pnpm start in examples/next/harnesses/opencode once. If it fails with "Message is too large", add the empty-models-dev-snapshot plugin there with apply: "serve".

  • The carrier fix ran only on 2.2.1. I checked the GitLabPlugin registration and the sdk hook guard in every tag from v2.0.24 to v2.2.1, but ran tests only on 2.2.1. Recommendation: none needed, unless you want a run on 2.0.24 before release.

Affected open PRs

Other changes

  • packages/agents/package.json:55-56: dev pins @opencode/plugin and @opencode/sdk 2.0.24 → 2.2.1.
  • examples/next/harnesses/opencode/package.json:17-18: the same two pins.
  • .changeset/opencode-2-2-1-carrier.md: new, agents: patch, one line on the carrier change.
  • pnpm-lock.yaml: regenerated with pnpm install. Every @opencode/* package resolves to 2.2.1, with no 2.0.24 left. The transitive changes come from opencode's tree:
    • version moves: effect (and @effect/opentelemetry, platform-node*) 4.0.0-rc.112 → 4.0.1; @ai-sdk/provider-utils 4.0.21/4.0.23 → 4.0.62 and @ai-sdk/provider 3.0.19 (opencode 01abece); zod 4.1.8 dropped for the existing 4.6.7; @opentui/core 0.5.14 → 0.7.0; @opencode-ai/pty 0.2.0 → 0.3.1; bun-pty 0.4.9 → 0.4.11; gitlab-ai-provider 6.19.0 → 6.23.1; @modelcontextprotocol/client/core 2.0.0 → 2.3.1.
    • new: ws@8.22.0, proper-lockfile, retry.
    • dropped: @ai-sdk/vercel, @ai-sdk/cohere, @ai-sdk/perplexity, @ai-sdk/openai-compatible@2.0.37, msgpackr, msgpackr-extract, fast-check, pure-rand, mime@4.1.0, http-cache-semantics, undici@8.10.2, strip-ansi@7.1.2, node-gyp-build-optional-packages.

Evidence

  • Before:
    • On 2.0.24: harness-opencode 31/31, workers src/tests/models/opencode 5/5.
    • On 2.2.1 with only the pins moved: harness-opencode 5/14 ("Message is too large").
    • With the Scalar and catalog fixes too: 17/31. All 14 failures are in harness.test.ts, where operations end unanswered; the session log shows the provider.no-route failure quoted above.
  • After: harness-opencode 31/31, workers src/tests/models/opencode 5/5. pnpm run build passes for 23 projects, including the OpenCode example's vite build. pnpm run check passes: sherif, exports (9 packages), oxfmt, oxlint (0 warnings), and typecheck of 134 projects.

Merge Danger

Door: two-way for the published package. The carrier package is runtime provider config from the plugin's provider.transform. Sessions store only { providerID, id }, as the session.created event in the log shows, so going back to the previous agents release restores the old carrier with nothing persisted. The exception is deploying examples/next/harnesses/opencode from this commit. That puts its Durable Objects on opencode 2.2, and per acdcdb8, sessions written under 2.1+ may not decode on 2.0.x. Treat that deployment as one-way.

Blast Radius: OpenCode harness users: anyone using agents/models/opencode, usually through agents/harness/opencode.

No one gets a new peer-dependency warning, because the peer range is unchanged. Users already on opencode 2.2.1 get working Cloudflare models once this ships. Users on 2.0.24–2.2.0 see no change in behaviour.


Opened by Gardener's opencode-upgrade task. Commits pushed by Gardener don't start CI: close and reopen this pull request, or push to it, to run it. Review comments are handled by Gardener's pr-review-fix task.


Devin Review

Move the @opencode/sdk and @opencode/plugin dev and example pins from
2.0.24 to 2.2.1 and regenerate pnpm-lock.yaml.

@opencode/core 2.2.1 no longer bundles @ai-sdk/vercel, the package
agents/models/opencode named so OpenCode loads it in-process; every turn
failed with provider.no-route. The provider now names gitlab-ai-provider,
which OpenCode 2.0.24 to 2.2.1 all load in-process. Peer range unchanged.

The Effect 4.0.1 Scalar stub path moves in the test config and example,
and the test config swaps OpenCode's 8 MB models.dev catalog for an
empty one so the test runtime can load it.

Supersedes #2725.

Gardener-Operation: op_01cd0a42d8cacef705791a2563f399f6f2ecfd9e224ab4bd67b0ca9942cc803e:90fbc03809c64d97ed870f4c44c25e8147b472a47fb479caa9877d85e9ebfa36
@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Oct 29, 2026
@changeset-bot

changeset-bot Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: af146bf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
agents Patch
@cloudflare/agent-think Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

devin-ai-integration[bot]

This comment was marked as resolved.

…angeset

Gardener-Operation: op_1437d3ebe8d4d6923fc425988e7a04f125ee356ea2fef9384556708b30267bee:0f48d6f725a39c5bec490ab674abd418b4e3df574a103736d9e1c5b30863386a
@github-actions

Copy link
Copy Markdown
Contributor Author

Review round 1: fixed the one open thread in af146bf.

  • Fixed: the changeset had no documentation link. .changeset/opencode-2-2-1-carrier.md is still one line and now links to the OpenCode example README, which is the only documentation for agents/models/opencode so far.

Review body: it only reports that one finding, so it needs no separate answer.

Checks: pnpm install --frozen-lockfile, oxfmt on the changeset, pnpm run build (23 projects) and pnpm run check (134 projects typecheck) all pass. No test applies to this docs-only change.

@pkg-pr-new

pkg-pr-new Bot commented Oct 29, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@2767

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@2767

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@2767

hono-agents

npm i https://pkg.pr.new/hono-agents@2767

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@2767

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@2767

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@2767

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@2767

commit: af146bf

@mattzcarey
mattzcarey merged commit 5cfafcf into main Oct 29, 2026
26 checks passed
@mattzcarey
mattzcarey deleted the gardener/upstream/opencode-2.2.1 branch October 29, 2026 18:08
@mattzcarey

Copy link
Copy Markdown
Member

Reverted in #2775. The upgrade is redone as a draft in #2776 while we replace the gitlab-ai-provider carrier.

@github-actions github-actions Bot mentioned this pull request Oct 29, 2026
mattzcarey added a commit that referenced this pull request Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant