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

fix(provider): port upstream provider/model transform for Claude 5#73
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).

filehowconflicts
provider/transform.tsreplaced wholesale w/ upstream HEAD0 — fork never touched it
test/provider/transform.test.tsreplaced wholesale0 — ours asserted 6 superseded behaviors
core/models-dev.tsadditive reasoning_options field0 — without it the port is 4 type errors
session/llm/request.tsgit merge-file 3-way0 — 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/opencodeandpackages/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-champagneforce-pushed the jack/provider-model-port branch from 3a801e4 to 80008a6CompareJuly 28, 2026 22:07
@jack-champagne
jack-champagne merged commit 3880d16 into local/amicodeJul 28, 2026
1 of 4 checks passed
Sign up for freeto 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

@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
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

fix(provider): port upstream provider/model transform for Claude 5#73
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).

filehowconflicts
provider/transform.tsreplaced wholesale w/ upstream HEAD0 — fork never touched it
test/provider/transform.test.tsreplaced wholesale0 — ours asserted 6 superseded behaviors
core/models-dev.tsadditive reasoning_options field0 — without it the port is 4 type errors
session/llm/request.tsgit merge-file 3-way0 — 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/opencodeandpackages/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-champagneforce-pushed the jack/provider-model-port branch from 3a801e4 to 80008a6CompareJuly 28, 2026 22:07
@jack-champagne
jack-champagne merged commit 3880d16 into local/amicodeJul 28, 2026
1 of 4 checks passed
Sign up for freeto 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

@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

fix(provider): port upstream provider/model transform for Claude 5#73
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).

filehowconflicts
provider/transform.tsreplaced wholesale w/ upstream HEAD0 — fork never touched it
test/provider/transform.test.tsreplaced wholesale0 — ours asserted 6 superseded behaviors
core/models-dev.tsadditive reasoning_options field0 — without it the port is 4 type errors
session/llm/request.tsgit merge-file 3-way0 — 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/opencodeandpackages/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-champagneforce-pushed the jack/provider-model-port branch from 3a801e4 to 80008a6CompareJuly 28, 2026 22:07
@jack-champagne
jack-champagne merged commit 3880d16 into local/amicodeJul 28, 2026
1 of 4 checks passed
Sign up for freeto 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

@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

fix(provider): port upstream provider/model transform for Claude 5#73
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).

filehowconflicts
provider/transform.tsreplaced wholesale w/ upstream HEAD0 — fork never touched it
test/provider/transform.test.tsreplaced wholesale0 — ours asserted 6 superseded behaviors
core/models-dev.tsadditive reasoning_options field0 — without it the port is 4 type errors
session/llm/request.tsgit merge-file 3-way0 — 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/opencodeandpackages/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-champagneforce-pushed the jack/provider-model-port branch from 3a801e4 to 80008a6CompareJuly 28, 2026 22:07
@jack-champagne
jack-champagne merged commit 3880d16 into local/amicodeJul 28, 2026
1 of 4 checks passed
Sign up for freeto 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

@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
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

fix(provider): port upstream provider/model transform for Claude 5#73
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).

filehowconflicts
provider/transform.tsreplaced wholesale w/ upstream HEAD0 — fork never touched it
test/provider/transform.test.tsreplaced wholesale0 — ours asserted 6 superseded behaviors
core/models-dev.tsadditive reasoning_options field0 — without it the port is 4 type errors
session/llm/request.tsgit merge-file 3-way0 — 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/opencodeandpackages/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-champagneforce-pushed the jack/provider-model-port branch from 3a801e4 to 80008a6CompareJuly 28, 2026 22:07
@jack-champagne
jack-champagne merged commit 3880d16 into local/amicodeJul 28, 2026
1 of 4 checks passed
Sign up for freeto 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

@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

fix(provider): port upstream provider/model transform for Claude 5#73
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).

filehowconflicts
provider/transform.tsreplaced wholesale w/ upstream HEAD0 — fork never touched it
test/provider/transform.test.tsreplaced wholesale0 — ours asserted 6 superseded behaviors
core/models-dev.tsadditive reasoning_options field0 — without it the port is 4 type errors
session/llm/request.tsgit merge-file 3-way0 — 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/opencodeandpackages/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-champagneforce-pushed the jack/provider-model-port branch from 3a801e4 to 80008a6CompareJuly 28, 2026 22:07
@jack-champagne
jack-champagne merged commit 3880d16 into local/amicodeJul 28, 2026
1 of 4 checks passed
Sign up for freeto 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

@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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

fix(provider): port upstream provider/model transform for Claude 5#73
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).

filehowconflicts
provider/transform.tsreplaced wholesale w/ upstream HEAD0 — fork never touched it
test/provider/transform.test.tsreplaced wholesale0 — ours asserted 6 superseded behaviors
core/models-dev.tsadditive reasoning_options field0 — without it the port is 4 type errors
session/llm/request.tsgit merge-file 3-way0 — 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/opencodeandpackages/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-champagneforce-pushed the jack/provider-model-port branch from 3a801e4 to 80008a6CompareJuly 28, 2026 22:07
@jack-champagne
jack-champagne merged commit 3880d16 into local/amicodeJul 28, 2026
1 of 4 checks passed
Sign up for freeto 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

@jack-champagne
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
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

fix(provider): port upstream provider/model transform for Claude 5#73
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).

filehowconflicts
provider/transform.tsreplaced wholesale w/ upstream HEAD0 — fork never touched it
test/provider/transform.test.tsreplaced wholesale0 — ours asserted 6 superseded behaviors
core/models-dev.tsadditive reasoning_options field0 — without it the port is 4 type errors
session/llm/request.tsgit merge-file 3-way0 — 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/opencodeandpackages/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-champagneforce-pushed the jack/provider-model-port branch from 3a801e4 to 80008a6CompareJuly 28, 2026 22:07
@jack-champagne
jack-champagne merged commit 3880d16 into local/amicodeJul 28, 2026
1 of 4 checks passed
Sign up for freeto 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

@jack-champagne