feat: implement Claude Sonnet 5 support in Zoo Code#778
Conversation
Add full Claude Sonnet 5 support across all provider paths with correct model definitions, adaptive-thinking handling, fetcher overrides, and accurate introductory pricing. Model definitions (anthropic.ts, bedrock.ts, vertex.ts): - 1M native context window (no beta header required) - Adaptive-thinking binary toggle (supportsReasoningBudget/Binary) - supportsTemperature: false (sampling params return a 400) - Introductory pricing through Aug 31, 2026: inputPrice 2.0, outputPrice 10.0, cacheWrites 2.5, cacheReads 0.2 (standard $3/$15 rates take effect Sep 1, 2026) Provider handling: - Add sonnet-5 to the Bedrock adaptive-thinking guard - Add claude-sonnet-5 to OpenRouter and Vercel AI Gateway allow-lists - Apply Sonnet 5 overrides (maxTokens, reasoning budget, temperature) in the openrouter, requesty, and vercel-ai-gateway fetchers Tests: - Add Sonnet 5 coverage across provider and fetcher test suites Closes #777
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds Claude Sonnet 5 support across provider model metadata, allowlists, adaptive-thinking handling, fetcher overrides, and unit tests for Anthropic, Bedrock, Vertex, OpenRouter, Requesty, and Vercel AI Gateway. ChangesClaude Sonnet 5 provider support
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/api/providers/fetchers/requesty.ts (1)
48-59: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider consolidating per-model override blocks.
The new
claude-sonnet-5block duplicates the exact same override logic asclaude-fable-5immediately above it. As more Anthropic models require this identicalsupportsReasoningBudget/supportsReasoningBinary/supportsTemperatureoverride, this pattern will keep growing. Consider a small lookup set instead.♻️ Proposed consolidation
- if (rawModel.id === "anthropic/claude-fable-5") { - modelInfo.supportsReasoningBudget = true - modelInfo.supportsReasoningBinary = true - modelInfo.supportsTemperature = false - } - - if (rawModel.id === "anthropic/claude-sonnet-5") { - modelInfo.supportsReasoningBudget = true - modelInfo.supportsReasoningBinary = true - modelInfo.supportsTemperature = false - } + if (REASONING_BUDGET_TEMPERATURE_OFF_MODELS.has(rawModel.id)) { + modelInfo.supportsReasoningBudget = true + modelInfo.supportsReasoningBinary = true + modelInfo.supportsTemperature = false + }(with
REASONING_BUDGET_TEMPERATURE_OFF_MODELSa module-levelSet(["anthropic/claude-fable-5", "anthropic/claude-sonnet-5"]))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/providers/fetchers/requesty.ts` around lines 48 - 59, The per-model override logic in requesty.ts is duplicated for claude-fable-5 and claude-sonnet-5, so consolidate it into a shared lookup instead of separate if blocks. Add a module-level set (for example, a reasoning-budget/temperature-off model set) and update the model override handling around the rawModel.id checks so both models use the same branch to set supportsReasoningBudget, supportsReasoningBinary, and supportsTemperature.src/api/providers/fetchers/vercel-ai-gateway.ts (1)
117-124: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueSame duplication pattern as in
requesty.ts.Consider consolidating the
claude-fable-5andclaude-sonnet-5checks into a single set-based lookup to avoid repeating this pattern for future one-off models.♻️ Proposed consolidation
- if (id === "anthropic/claude-fable-5") { - modelInfo.supportsTemperature = false - } - - if (id === "anthropic/claude-sonnet-5") { - modelInfo.supportsTemperature = false - } + if (NO_TEMPERATURE_MODELS.has(id)) { + modelInfo.supportsTemperature = false + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/api/providers/fetchers/vercel-ai-gateway.ts` around lines 117 - 124, The `fetchModelInfo` logic in `vercel-ai-gateway.ts` repeats separate `id === ...` checks for `anthropic/claude-fable-5` and `anthropic/claude-sonnet-5`, matching the duplication pattern already seen in `requesty.ts`. Consolidate these one-off model IDs into a single set-based lookup near `modelInfo.supportsTemperature` handling, then apply the flag once when `id` is in that set so future additions only need one list update.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/api/providers/fetchers/requesty.ts`:
- Around line 48-59: The per-model override logic in requesty.ts is duplicated
for claude-fable-5 and claude-sonnet-5, so consolidate it into a shared lookup
instead of separate if blocks. Add a module-level set (for example, a
reasoning-budget/temperature-off model set) and update the model override
handling around the rawModel.id checks so both models use the same branch to set
supportsReasoningBudget, supportsReasoningBinary, and supportsTemperature.
In `@src/api/providers/fetchers/vercel-ai-gateway.ts`:
- Around line 117-124: The `fetchModelInfo` logic in `vercel-ai-gateway.ts`
repeats separate `id === ...` checks for `anthropic/claude-fable-5` and
`anthropic/claude-sonnet-5`, matching the duplication pattern already seen in
`requesty.ts`. Consolidate these one-off model IDs into a single set-based
lookup near `modelInfo.supportsTemperature` handling, then apply the flag once
when `id` is in that set so future additions only need one list update.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 658e50f0-b049-4c25-902d-0d7df9a161a3
📒 Files selected for processing (19)
packages/types/src/providers/anthropic.tspackages/types/src/providers/bedrock.tspackages/types/src/providers/openrouter.tspackages/types/src/providers/vercel-ai-gateway.tspackages/types/src/providers/vertex.tssrc/api/providers/__tests__/anthropic-vertex.spec.tssrc/api/providers/__tests__/anthropic.spec.tssrc/api/providers/__tests__/bedrock.spec.tssrc/api/providers/__tests__/requesty.spec.tssrc/api/providers/__tests__/vercel-ai-gateway.spec.tssrc/api/providers/anthropic.tssrc/api/providers/bedrock.tssrc/api/providers/fetchers/__tests__/openrouter.spec.tssrc/api/providers/fetchers/__tests__/requesty.spec.tssrc/api/providers/fetchers/__tests__/vercel-ai-gateway.spec.tssrc/api/providers/fetchers/openrouter.tssrc/api/providers/fetchers/requesty.tssrc/api/providers/fetchers/vercel-ai-gateway.tssrc/shared/__tests__/api.spec.ts
edelauna
left a comment
There was a problem hiding this comment.
Looks good - nothing blocking, just a question about vercel, and if we wanted to increase test coverage.
|
|
||
| const model = handler.getModel() | ||
| expect(model.id).toBe("global.anthropic.claude-sonnet-5") | ||
| }) |
There was a problem hiding this comment.
Opus 4.7 and 4.8 each have a createMessage test that asserts inferenceConfig.temperature is absent and additionalModelRequestFields.thinking.type === "adaptive" (lines ~1410–1458). Could we add an equivalent for anthropic.claude-sonnet-5? The isAdaptiveThinkingModel unit test confirms the predicate returns true, but a regression in the handler branch for this specific model wouldn't be caught without an end-to-end request test.
|
|
||
| if (id === "anthropic/claude-sonnet-5") { | ||
| modelInfo.supportsTemperature = false | ||
| } |
There was a problem hiding this comment.
The requesty and openrouter fetchers both set supportsReasoningBinary: true for claude-sonnet-5 alongside supportsTemperature: false. Does the Vercel AI Gateway support the binary reasoning toggle? If so, should we add modelInfo.supportsReasoningBinary = true here (and in the claude-fable-5 block above at line 118)?
| temperature: undefined, | ||
| max_completion_tokens: 128000, | ||
| }), | ||
| ) |
There was a problem hiding this comment.
expect.objectContaining({ temperature: undefined }) passes whether temperature is explicitly undefined or simply absent from the call object — so it won't catch a regression where the handler stops consulting supportsTemperature entirely. Would asserting on the extracted call arg directly be tighter?
| ) | |
| const call = mockCreate.mock.calls[mockCreate.mock.calls.length - 1][0] | |
| expect(call.model).toBe("anthropic/claude-sonnet-5") | |
| expect(call.temperature).toBeUndefined() | |
| expect(call.max_completion_tokens).toBe(128000) |
- Add Bedrock createMessage adaptive-thinking test for claude-sonnet-5
(mirrors Opus 4.7/4.8: asserts thinking.type 'adaptive',
output_config.effort 'xhigh', and temperature omitted).
- Tighten Vercel AI Gateway Sonnet 5 temperature assertion to extract
the call arg directly instead of objectContaining({ temperature:
undefined }), which can't distinguish absent from explicitly undefined.
Refs #778
Related GitHub Issue
Closes: #777
Description
This PR implements full Claude Sonnet 5 support in Zoo Code across all provider paths, with correct model definitions, adaptive-thinking handling, fetcher overrides, and accurate introductory pricing.
Per Anthropic's published pricing, Sonnet 5 has introductory pricing of $2 / $10 per million input/output tokens in effect through August 31, 2026 (the standard $3 / $15 rates do not take effect until September 1, 2026). The previous definitions used the standard rates, which over-reported costs during the introductory period.
Key implementation details:
packages/types/src/providers/): Addedclaude-sonnet-5toanthropic.ts,bedrock.ts, andvertex.tswith a native 1M context window (no beta header required), the adaptive-thinking binary toggle (supportsReasoningBudget/supportsReasoningBinary),supportsTemperature: false(sampling params return a 400), and introductory pricing (inputPrice: 2.0,outputPrice: 10.0,cacheWritesPrice: 2.5,cacheReadsPrice: 0.2). Cache prices follow Anthropic's standard multipliers (1.25× base input for 5m cache writes, 0.1× base input for cache reads) applied to the $2 introductory base rate.src/api/providers/): Addedsonnet-5to the Bedrock adaptive-thinking guard so temperature is omitted, and addedclaude-sonnet-5to the OpenRouter and Vercel AI Gateway model allow-lists.src/api/providers/fetchers/): Applied Sonnet 5 overrides (maxTokens, reasoning budget, temperature) in theopenrouter,requesty, andvercel-ai-gatewayfetchers so dynamically-fetched model info matches the static Anthropic definitions.Reviewers should pay attention to the pricing values in the three provider definition files — these are the introductory rates and will need to be reverted to the standard $3 / $15 rates on September 1, 2026.
Test Procedure
cd packages/types && pnpm run lint— passes (no warnings).cd packages/types && npx tsc --noEmit— passes with no errors.cd src && pnpm run check-types— passes with no errors.cd src && npx vitest run api/providers/__tests__/bedrock.spec.ts api/providers/__tests__/anthropic-vertex.spec.ts— 112/112 tests pass.claude-sonnet-5, send a request, and confirm the reported token cost reflects the introductory $2/$10 rates rather than the standard $3/$15 rates.Pre-Submission Checklist
Screenshots / Videos
N/A — no UI changes.
Documentation Updates
Additional Notes
The introductory pricing window ends August 31, 2026. On September 1, 2026, the pricing values in
anthropic.ts,bedrock.ts, andvertex.tsshould be reverted to the standard rates (inputPrice: 3.0,outputPrice: 15.0,cacheWritesPrice: 3.75,cacheReadsPrice: 0.3).Get in Touch
navedmerchant
Summary by CodeRabbit