Skip to content

fix: bump the agent SDK to 0.3.281, and unstick Opus from a superseded release - #341

Merged
saucam merged 1 commit into
mainfrom
chore/bump-agent-sdk
Sep 24, 2026
Merged

saucam merged 1 commit into
mainfrom
chore/bump-agent-sdk

Conversation

@saucam

@saucam saucam commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

Bumps @anthropic-ai/claude-agent-sdk 0.3.258 → 0.3.281, so opus runs Opus 5.5.

Why the bump is what unlocks the model

The SDK version tracks the bundled Claude Code CLI 1:1, and the model list comes from that CLI at runtime — not from the package. So I ran both and compared what the live backend reports:

SDK opus / default reports as
0.3.258 Opus 5 with 1M context
0.3.281 Opus 5.5 with 1M context

An opus turn on 0.3.281 reports init.model = claude-opus-5-5, with canonicalModel: "claude-opus-5-5" and contextWindow: 1000000 in modelUsage.

Breaking-change check: the sdk.d.ts diff is purely additive — new optional fields (omitClaudeMd, mcpServer, defaultToNo, suppressAlwaysAllowRule) and new exported types (McpServerProvenance, SDKStartupFailureReason, SDKUsageReport). Nothing codeoid calls changed shape.

Two stale things behind it — both the second occurrence of #315

1. MODEL_CATALOG still pinned opus → claude-opus-5.

The catalog is only the pre-first-report fallback (the live list wins), but a session created before the backend has reported its list gets pinned to whatever it says. That is exactly how the alias came to run claude-opus-4-8 after Opus 5 shipped. Now claude-opus-5-5, live-verified rather than guessed.

2. contextWindowForModel had no opus-5 family — so a 1M model measured as 200k.

Not cosmetic. Once the SDK reports the concrete id back, SessionInfo.model carries a value the table doesn't know:

before:  claude-opus-5-5 → 200000     claude-opus-5 → 200000
after:   claude-opus-5-5 → 1000000    claude-opus-5 → 1000000

modelUsage says the real window is 1,000,000, so every consumer was off by 5×: the percent-of-window display, the fork seed budget, and the auto-rotate occupancy that decides when a session rolls — meaning auto-rotate fired at about a fifth of real capacity. claude-opus-5 was already broken this way from #315, which moved the catalog id without adding the family.

The guard that would have caught it

The two tables are now cross-checked: every catalog entry's declared contextWindow must equal what contextWindowForModel derives from its id and from its alias. It fails if either table moves without the other — mutation-verified: dropping opus-5 from the family list turns it red.

The resolveAgainstList fixture is refreshed from the real 0.3.281 payload, which also changed shape: Fable is now reported bare (claude-fable-5-1) where 0.3.258 reported it suffixed (claude-fable-5-1[1m]). The suffix-stripping test now builds its own local fixture rather than leaning on the shared one, so the shared fixture stays verbatim-honest — a fixture that flattered the code is why #315's bug survived a test that looked like it covered it.

Deliberately not in this PR

The root cause. The SDK already reports modelUsage[model].contextWindow on every turn and codeoid throws it away — providers/claude/index.ts types the payload as { inputTokens?, outputTokens? } and reads only the key to derive the model name. That is why a hardcoded table existed to go stale.

It can't simply be deleted, for two reasons I verified rather than assumed:

  • ModelInfo (the supported-models list codeoid caches) carries no contextWindow, so the number is unknown until a turn completes — a fresh or just-resumed session still needs one to render.
  • Some backends report none; the qwen provider's own comment records modelUsage as "observed empty against the Bailian gateway".

So the correct shape is: consume the provider's number as authoritative, demote the static tables to a pre-first-turn bootstrap. That touches ProviderResult/LLMCallUsage, the claude provider's result parsing, session state and every other backend's equivalent — a provider-interface change, kept separate so this dependency bump stays independently revertable. providers/context-windows.ts already anticipated it in its header ("or later from provider-reported ModelInfo").

Verification

  • Ran the live backend on both SDK versions to establish the model-name change, rather than reading it off the package.
  • init.model / modelUsage read directly from a real opus turn for the id and the window.
  • Catalog↔window cross-check mutation-tested.
  • bun run typecheck · bun run lint · bun test → 2593 pass, 19 skip, 0 fail.

🤖 Generated with Claude Code

…d release

`opus` ran Opus 5 months after Opus 5.5 shipped, and a 1M-context model was
being measured against a 200k window.

The SDK version tracks the bundled Claude Code CLI 1:1, and the model list
comes from that CLI at runtime rather than from the package, so the dependency
bump is what surfaces a new model at all. Confirmed by running both: on
0.3.258 the backend reports the `opus` alias as "Opus 5", on 0.3.281 it reports
"Opus 5.5". The type surface between the two is purely additive — new optional
fields (`omitClaudeMd`, `mcpServer`, `defaultToNo`, `suppressAlwaysAllowRule`)
and new exported types — so nothing codeoid calls changed shape.

Two things were stale behind that, and both are the SECOND occurrence of a bug
#315 already fixed once.

`MODEL_CATALOG` still pinned the premium alias to `claude-opus-5`. The catalog
is only the pre-first-report fallback — the live list wins — but a session
created before the backend has reported its list gets pinned to whatever it
says, which is how the alias came to run `claude-opus-4-8` after Opus 5
shipped. Now `claude-opus-5-5`, live-verified: an `opus` turn on 0.3.281
reports `init.model = claude-opus-5-5`, with `canonicalModel:
"claude-opus-5-5"` in `modelUsage`.

`contextWindowForModel` had no `opus-5` family at all, so `claude-opus-5-5`
— and `claude-opus-5` before it, since #315 moved the catalog id without
adding the family — fell through to the 200k default. That one is not
cosmetic: once the SDK reports the concrete id back, `SessionInfo.model`
carries a value the table does not know, and `modelUsage` says the real
window is 1,000,000. Every consumer of that number was off by 5x — the
percent-of-window display, the fork seed budget, and the auto-rotate occupancy
that decides when a session rolls, meaning auto-rotate fired at about a fifth
of real capacity.

The two tables are now cross-checked: every catalog entry's declared
`contextWindow` must equal what `contextWindowForModel` derives from its id AND
from its alias. That is the assertion that would have caught this, and it
fails if either table moves without the other — verified by mutation, dropping
`opus-5` from the family list turns it red.

The `resolveAgainstList` fixture is refreshed from the live 0.3.281 payload,
which also changed: Fable is now reported bare (`claude-fable-5-1`) where
0.3.258 reported it suffixed (`claude-fable-5-1[1m]`). The suffix-stripping
test keeps its own local fixture rather than relying on the shared one, so the
shared fixture can stay verbatim-honest — a fixture that flattered the code is
why #315's bug survived a test that looked like it covered it.

Not fixed here, and the actual root cause: the SDK already reports
`modelUsage[model].contextWindow` on every turn, and codeoid discards it
(`providers/claude/index.ts` types the payload as `{inputTokens?,
outputTokens?}` and reads only the key), which is why a hardcoded table
existed to go stale in the first place. It cannot simply be deleted — the
supported-models list carries no window, so the number is unknown until a turn
completes, and some backends report none (qwen's own comment records
`modelUsage` as empty against the Bailian gateway). Threading the
provider-reported value through with the static tables demoted to a
pre-first-turn bootstrap is a follow-up, kept separate so a dependency bump
stays independently revertable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​anthropic-ai/​claude-agent-sdk@​0.3.258 ⏵ 0.3.281100 +11009210070

View full report

@saucam
saucam merged commit 379b27b into main Sep 24, 2026
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.

2 participants