Skip to content

fix(provider): port upstream provider/model transform for Claude 5 - #73

Merged
jack-champagne merged 1 commit into
local/amicodefrom
jack/provider-model-port
Jul 28, 2026
Merged

jack-champagne merged 1 commit into
local/amicodefrom
jack/provider-model-port

Conversation

@jack-champagne

Copy link
Copy Markdown
Member

Why

Our base is sst/opencode v1.17.3 (2026-06-10). Sonnet 5 (2026-06-29) and Opus 5 (2026-07-24) both shipped after our fork point, and at our base their thinking plumbing is silently broken:

anthropicOpus47OrLater() = /opus-(\d+)[.-](\d+)/   // requires BOTH major and minor

claude-opus-5 has no minor; claude-sonnet-5 isn't "opus". Neither matches → both fall through to the legacy thinking:{type:"enabled",budgetTokens:16000} path with only high/max tiers instead of the 5-tier type:"adaptive" path. Upstream fixed this in #38757.

This is not a "new models" problem. The catalog is fetched live from models.dev at build time (script/generate.ts; amicode-release.yml pins no snapshot), so Opus 5 already shows up in the picker — just hobbled, with no effort selector. QA-ing "can I select Opus 5?" gives a false negative on the need to sync.

What's ported

The end state of 4 files, not the 112 commits behind them. Cherry-picking that history would drag in the Effect layer-node → app-node refactor and the @opencode-ai/schema extraction (upstream gutted core/src/model.ts 127→41 and core/src/provider.ts 85→25 into a new package).

file how conflicts
provider/transform.ts replaced wholesale w/ upstream HEAD 0 — fork never touched it
test/provider/transform.test.ts replaced wholesale 0 — ours asserted 6 superseded behaviors
core/models-dev.ts additive reasoning_options field 0 — without it the port is 4 type errors
session/llm/request.ts git merge-file 3-way 0 — amicode patch #18 preserved

transform.ts also carries #38424 (prompt cache keys by SDK) and the Grok/GLM/Bedrock-Mantle variant fixes. request.ts brings #33392 (strict: false on OpenAI Responses-family tools).

Measured blast radius

Ran both transform versions over all 454 reasoning models in the live models.dev catalog: 418 identical, 36 changed, 0 errors.

  • Claude 5 (opus + sonnet, across anthropic, all amazon-bedrock regions, and opencode zen): high,maxlow,medium,high,xhigh,max with type:"adaptive".
  • xAI Grok 4.3/4.5/4.20/build and GLM-5.2: gain effort variants where they previously had none.
  • claude-opus-4-5: keeps its low,medium,high keys but now also sends budgetTokens:16000 alongside effort.
  • Claude 4.8 / 4.6 / 4.1: unchanged.

Verification

  • tsgo --noEmit green on packages/opencode and packages/core
  • bun test test/provider/503 pass / 0 fail
  • bun test test/session/ test/server/identical before and after. The 3 llm-native-recorded failures and the Bun 1.3.14 teardown segfault both reproduce byte-for-byte on the unported tree.
  • oxlint → 0 errors; prettier --check clean

Needs a QA pass before the hackathon build

CI cannot exercise these — they need live creds:

  1. Whether the old legacy form actually 400s against Opus 5 or merely degrades. If it 400s, this was "Opus 5 unusable", not "Opus 5 hobbled".
  2. claude-opus-4-5 — a model in use today — with the new budgetTokens+effort combination.
  3. One xAI model, since Grok goes from no variants to effort variants.
  4. Cache hit rate / spend, since #38424 changes prompt-cache keying across all providers.

Known trade

Porting file end-states makes a future clean upstream merge harder on these 4 files. Accepted deliberately. Worth noting the bug class recurs every model generation — version-regex parsing of model IDs will break again at Opus 6 — which argues for a standing narrow sync lane on transform.ts rather than one-off unfreezes.

Unrelated risk spotted (not fixed here)

The release build does a bare fetch(models.dev/api.json) with no fallback, so a models.dev outage hard-fails the build. Worth pinning MODELS_DEV_API_JSON for the hackathon build.

Our base (sst/opencode v1.17.3, 2026-06-10) predates Sonnet 5 and Opus 5.
anthropicOpus47OrLater() required both a major and a minor version in the
model id, so claude-opus-5 and claude-sonnet-5 never matched and fell back
to legacy thinking:{type:"enabled",budgetTokens:16000} with only high/max
tiers instead of the 5-tier adaptive path.

Ports the end state of upstream's provider/model files rather than the 112
commits behind them, which would drag in the layer-node -> app-node refactor
and the @opencode-ai/schema extraction:

- provider/transform.ts + its test: replaced wholesale (fork never touched
  either; 0 conflicts). Also brings prompt-cache keys by SDK and the
  Grok/GLM/Bedrock-Mantle variant fixes.
- core/models-dev.ts: additive reasoning_options field the transform reads.
- session/llm/request.ts: 3-way merged, 0 conflicts; amicode patch #18
  preserved. Brings strict:false on OpenAI Responses-family tools.

Measured over all 454 reasoning models in the live models.dev catalog:
418 identical, 36 changed, 0 errors. Claude 4.8/4.6/4.1 unchanged.

Verified: tsgo green on opencode + core; test/provider 503 pass / 0 fail;
test/session + test/server identical before and after (3 pre-existing
llm-native-recorded failures reproduce on the unported tree).
@jack-champagne
jack-champagne force-pushed the jack/provider-model-port branch from 3a801e4 to 80008a6 Compare July 28, 2026 22:07
@jack-champagne
jack-champagne merged commit 3880d16 into local/amicode Jul 28, 2026
1 of 4 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.

1 participant