fix: bump the agent SDK to 0.3.281, and unstick Opus from a superseded release - #341
Merged
Merged
Conversation
…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>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
akashjavelin
approved these changes
Sep 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps
@anthropic-ai/claude-agent-sdk0.3.258 → 0.3.281, soopusruns 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:
opus/defaultreports asOpus 5 with 1M contextOpus 5.5 with 1M contextAn
opusturn on 0.3.281 reportsinit.model = claude-opus-5-5, withcanonicalModel: "claude-opus-5-5"andcontextWindow: 1000000inmodelUsage.Breaking-change check: the
sdk.d.tsdiff 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_CATALOGstill pinnedopus→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-8after Opus 5 shipped. Nowclaude-opus-5-5, live-verified rather than guessed.2.
contextWindowForModelhad noopus-5family — so a 1M model measured as 200k.Not cosmetic. Once the SDK reports the concrete id back,
SessionInfo.modelcarries a value the table doesn't know:modelUsagesays 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-5was 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
contextWindowmust equal whatcontextWindowForModelderives from its id and from its alias. It fails if either table moves without the other — mutation-verified: droppingopus-5from the family list turns it red.The
resolveAgainstListfixture 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].contextWindowon every turn and codeoid throws it away —providers/claude/index.tstypes 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 nocontextWindow, so the number is unknown until a turn completes — a fresh or just-resumed session still needs one to render.modelUsageas "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.tsalready anticipated it in its header ("or later from provider-reported ModelInfo").Verification
init.model/modelUsageread directly from a realopusturn for the id and the window.bun run typecheck·bun run lint·bun test→ 2593 pass, 19 skip, 0 fail.🤖 Generated with Claude Code