feat: service tier mappings for gemini and anthropic - #3554
Conversation
|
tejas ghatte seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (22)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (20)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds typed Bifrost service-tier enums and provider-specific mapping/helpers; propagates mapped tiers across Anthropic, Bedrock, Gemini, and Vertex request/response conversions; updates schemas, pricing, and tests. ChangesAnthropic Service Tier Mapping
Bedrock Service Tier Typing and Mapping
Gemini Service Tier Mapping
Schemas and Consumers
Vertex header forwarding and stripping
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Comment |
Confidence Score: 4/5Safe to merge with minor known gaps; the mapping logic is correct for the common paths but a few edge cases in the Anthropic and Bedrock reverse mappers still return unrecognised Bifrost tier values to callers. The core mappings, type promotion, and Vertex header injection are all correct and well-tested. However, core/providers/anthropic/utils.go (batch tier passthrough) and core/providers/bedrock/utils.go (reserved tier not mapped to priority) Important Files Changed
Reviews (7): Last reviewed commit: "feat: service tier mappings for gemini a..." | Re-trigger Greptile |
ae06dac
f28d336 to
ae06dac
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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.
Inline comments:
In `@core/providers/bedrock/utils.go`:
- Around line 91-104: The mapping function mapBedrockServiceTierToBifrost
incorrectly lets the BedrockServiceTierTypeReserved fall through to the default
cast; update the switch in mapBedrockServiceTierToBifrost to include an explicit
case for BedrockServiceTierTypeReserved that returns
schemas.BifrostServiceTierPriority (so "reserved" maps to priority), leaving the
other cases (BedrockServiceTierTypePriority, BedrockServiceTierTypeFlex,
BedrockServiceTierTypeDefault) unchanged and keeping the default cast as a
fallback.
In `@core/schemas/responses.go`:
- Around line 179-185: In WithDefaults(), the current logic only assigns
result.ServiceTier when the incoming resp.ServiceTier is invalid, causing valid
tiers to be dropped; update the logic in the resp.ServiceTier handling so that
if resp.ServiceTier is non-nil and one of the valid enum values
(BifrostServiceTierAuto, BifrostServiceTierDefault, BifrostServiceTierFlex,
BifrostServiceTierPriority) you set result.ServiceTier = new(BifrostServiceTier)
and copy the value from resp.ServiceTier, otherwise set result.ServiceTier to a
default (new(BifrostServiceTierAuto)); keep the nil behavior unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 16418932-b105-4492-89ef-f94517f5c61c
📒 Files selected for processing (17)
core/providers/anthropic/chat.gocore/providers/anthropic/responses.gocore/providers/anthropic/utils.gocore/providers/bedrock/bedrock_test.gocore/providers/bedrock/chat.gocore/providers/bedrock/responses.gocore/providers/bedrock/types.gocore/providers/bedrock/utils.gocore/providers/gemini/gemini_test.gocore/providers/gemini/responses.gocore/providers/gemini/types.gocore/providers/gemini/utils.gocore/schemas/chatcompletions.gocore/schemas/responses.goframework/modelcatalog/pricing.goframework/modelcatalog/pricing_test.goplugins/semanticcache/plugin_responses_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
- core/providers/gemini/responses.go
- core/providers/gemini/types.go
- core/providers/anthropic/chat.go
- core/providers/anthropic/utils.go
- core/providers/anthropic/responses.go
- core/providers/gemini/gemini_test.go
ae06dac to
9395231
Compare
9395231 to
10d67be
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
core/providers/gemini/utils.go (2)
1245-1257: ⚡ Quick winConsider adding an explicit case for
BifrostServiceTierAuto.The default case currently handles unknown Bifrost tiers by returning
ServiceTierUnspecified. For clarity and maintainability, add an explicit case:case schemas.BifrostServiceTierAuto: return ServiceTierUnspecifiedThis makes the mapping intention clear and ensures bidirectional consistency is explicit: Gemini's
Unspecified↔ Bifrost'sAuto.🤖 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 `@core/providers/gemini/utils.go` around lines 1245 - 1257, Add an explicit mapping for the BifrostServiceTierAuto value inside mapBifrostServiceTierToGemini so it returns ServiceTierUnspecified; update the switch in mapBifrostServiceTierToGemini to include the case schemas.BifrostServiceTierAuto returning ServiceTierUnspecified to make the intent explicit and keep bidirectional mapping consistent with Gemini's Unspecified.
356-368: ⚡ Quick winConsider adding an explicit case for
ServiceTierUnspecified.The default case currently handles unknown/unspecified tiers by returning
BifrostServiceTierAuto. For clarity and maintainability, add an explicit case:case ServiceTierUnspecified: return schemas.BifrostServiceTierAutoThis makes the mapping intention clear and prevents future tier additions from silently falling through to the auto default.
Also, the comment "OpenAI-compatible BifrostServiceTier" is slightly misleading—Bifrost's service tier enum is provider-agnostic. Consider: "Converts a Gemini ServiceTier to Bifrost's BifrostServiceTier."
🤖 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 `@core/providers/gemini/utils.go` around lines 356 - 368, The mapGeminiServiceTierToBifrost function currently relies on the default branch for unspecified/unknown tiers; add an explicit case for ServiceTierUnspecified that returns schemas.BifrostServiceTierAuto to make the intent clear (in the same switch alongside ServiceTierStandard, ServiceTierFlex, ServiceTierPriority). Also update the function comment to "Converts a Gemini ServiceTier to Bifrost's BifrostServiceTier" to avoid implying an OpenAI-specific mapping; keep the rest of the switch logic unchanged.
🤖 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.
Inline comments:
In `@core/providers/gemini/responses.go`:
- Around line 1834-1837: The Completed branch in ToGeminiResponsesStreamResponse
is failing to copy Response.ServiceTier into
streamResp.UsageMetadata.ServiceTier, dropping service_tier for streamed
completed events; update the Completed branch of ToGeminiResponsesStreamResponse
to check Response.ServiceTier and, if present, map it back to Gemini form (use
the inverse mapping, e.g., mapBifrostServiceTierToGemini or equivalent) and
assign it to streamResp.UsageMetadata.ServiceTier (handle nil/pointer conversion
as done when setting completedResp.ServiceTier earlier) so streamed responses
preserve service_tier metadata.
---
Nitpick comments:
In `@core/providers/gemini/utils.go`:
- Around line 1245-1257: Add an explicit mapping for the BifrostServiceTierAuto
value inside mapBifrostServiceTierToGemini so it returns ServiceTierUnspecified;
update the switch in mapBifrostServiceTierToGemini to include the case
schemas.BifrostServiceTierAuto returning ServiceTierUnspecified to make the
intent explicit and keep bidirectional mapping consistent with Gemini's
Unspecified.
- Around line 356-368: The mapGeminiServiceTierToBifrost function currently
relies on the default branch for unspecified/unknown tiers; add an explicit case
for ServiceTierUnspecified that returns schemas.BifrostServiceTierAuto to make
the intent clear (in the same switch alongside ServiceTierStandard,
ServiceTierFlex, ServiceTierPriority). Also update the function comment to
"Converts a Gemini ServiceTier to Bifrost's BifrostServiceTier" to avoid
implying an OpenAI-specific mapping; keep the rest of the switch logic
unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 55800d91-fa97-4981-8fe9-97786b93f7a1
📒 Files selected for processing (18)
core/providers/anthropic/chat.gocore/providers/anthropic/responses.gocore/providers/anthropic/utils.gocore/providers/bedrock/bedrock_test.gocore/providers/bedrock/chat.gocore/providers/bedrock/responses.gocore/providers/bedrock/types.gocore/providers/bedrock/utils.gocore/providers/gemini/chat.gocore/providers/gemini/gemini_test.gocore/providers/gemini/responses.gocore/providers/gemini/types.gocore/providers/gemini/utils.gocore/schemas/chatcompletions.gocore/schemas/responses.goframework/modelcatalog/pricing.goframework/modelcatalog/pricing_test.goplugins/semanticcache/plugin_responses_test.go
🚧 Files skipped from review as they are similar to previous changes (13)
- framework/modelcatalog/pricing.go
- core/providers/bedrock/types.go
- plugins/semanticcache/plugin_responses_test.go
- core/providers/bedrock/chat.go
- core/providers/bedrock/bedrock_test.go
- core/schemas/chatcompletions.go
- core/providers/bedrock/utils.go
- core/providers/anthropic/chat.go
- core/providers/anthropic/utils.go
- core/providers/bedrock/responses.go
- core/schemas/responses.go
- core/providers/anthropic/responses.go
- framework/modelcatalog/pricing_test.go
10d67be to
25ea64e
Compare
25ea64e to
dd66f43
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
core/providers/vertex/vertex.go (1)
2570-2573:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAlways strip top-level
serviceTierbefore early returns in raw sanitizer.Line 2570-2573 returns early when
contentsis missing/non-array, so the new top-levelserviceTierdeletion at Line 2602-2607 is skipped. That leaks an unsupported field for valid raw bodies that omitcontents.💡 Suggested fix
func stripVertexGeminiUnsupportedFieldsRaw(jsonBody []byte) []byte { if len(jsonBody) == 0 { return jsonBody } + out := jsonBody + // Strip top-level serviceTier first so it applies regardless of contents shape. + if providerUtils.JSONFieldExists(out, "serviceTier") { + if updated, err := providerUtils.DeleteJSONField(out, "serviceTier"); err == nil { + out = updated + } + } + - contents := gjson.GetBytes(jsonBody, "contents") + contents := gjson.GetBytes(out, "contents") if !contents.IsArray() { - return jsonBody + return out } - out := jsonBody contentIndex := 0 contents.ForEach(func(_, content gjson.Result) bool { ... }) - - // Strip top-level serviceTier — Vertex uses HTTP headers for this, not the request body. - if providerUtils.JSONFieldExists(out, "serviceTier") { - if updated, err := providerUtils.DeleteJSONField(out, "serviceTier"); err == nil { - out = updated - } - } return out }Also applies to: 2602-2607
🤖 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 `@core/providers/vertex/vertex.go` around lines 2570 - 2573, The raw sanitizer currently checks contents via gjson.GetBytes(jsonBody, "contents") and returns early if it's not an array, which skips the top-level serviceTier removal; move or duplicate the logic that deletes the top-level "serviceTier" field so it runs before any early returns (i.e., execute the serviceTier strip immediately after parsing jsonBody and before the contents check in the same function), and ensure any other early-return paths in the same sanitizer also call the same removal routine so "serviceTier" is always stripped for raw bodies.
🤖 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.
Inline comments:
In `@core/providers/anthropic/utils.go`:
- Around line 390-396: The raw-path branch removes the "service_tier" JSON field
when features.ServiceTier is false (using providerUtils.JSONFieldExists and
providerUtils.DeleteJSONField) but the typed-path function
stripUnsupportedAnthropicFields still leaves req.ServiceTier set; make their
behavior consistent by updating stripUnsupportedAnthropicFields to clear or
unset req.ServiceTier when features.ServiceTier is false (mirror the same guard
and removal logic), ensuring both code paths strip service_tier for unsupported
providers.
In `@core/providers/vertex/vertex.go`:
- Around line 913-919: The VertexServiceTierHeader is being set whenever
request.Params.ServiceTier exists in multiple places (see the block that uses
headers[VertexServiceTierHeader] = v), which allows Gemma models to receive
unsupported values; update the other two sites to match the guard used at the
earlier location by first checking that provider.networkConfig.ExtraHeaders does
not override VertexServiceTierHeader and that the computed
vertexServiceTierHeaderValue(region, *request.Params.ServiceTier) is only
applied for Gemini/all-digits requests (i.e., replicate the same guard pattern
used around the existing header-setting block that checks
provider.networkConfig.ExtraHeaders and uses vertexServiceTierHeaderValue before
writing headers[VertexServiceTierHeader]); ensure you change the two additional
occurrences where request.Params.ServiceTier is used to set
VertexServiceTierHeader.
---
Outside diff comments:
In `@core/providers/vertex/vertex.go`:
- Around line 2570-2573: The raw sanitizer currently checks contents via
gjson.GetBytes(jsonBody, "contents") and returns early if it's not an array,
which skips the top-level serviceTier removal; move or duplicate the logic that
deletes the top-level "serviceTier" field so it runs before any early returns
(i.e., execute the serviceTier strip immediately after parsing jsonBody and
before the contents check in the same function), and ensure any other
early-return paths in the same sanitizer also call the same removal routine so
"serviceTier" is always stripped for raw bodies.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 002c75e9-fa31-4cce-884f-8e688e0bbb5c
📒 Files selected for processing (22)
core/providers/anthropic/chat.gocore/providers/anthropic/responses.gocore/providers/anthropic/types.gocore/providers/anthropic/utils.gocore/providers/bedrock/bedrock_test.gocore/providers/bedrock/chat.gocore/providers/bedrock/responses.gocore/providers/bedrock/types.gocore/providers/bedrock/utils.gocore/providers/gemini/chat.gocore/providers/gemini/gemini_test.gocore/providers/gemini/responses.gocore/providers/gemini/types.gocore/providers/gemini/utils.gocore/providers/vertex/types.gocore/providers/vertex/utils.gocore/providers/vertex/vertex.gocore/schemas/chatcompletions.gocore/schemas/responses.goframework/modelcatalog/pricing.goframework/modelcatalog/pricing_test.goplugins/semanticcache/plugin_responses_test.go
🚧 Files skipped from review as they are similar to previous changes (17)
- core/providers/bedrock/chat.go
- framework/modelcatalog/pricing.go
- core/providers/bedrock/types.go
- core/providers/gemini/utils.go
- plugins/semanticcache/plugin_responses_test.go
- core/providers/gemini/chat.go
- core/providers/bedrock/utils.go
- core/providers/bedrock/responses.go
- core/providers/anthropic/chat.go
- core/schemas/chatcompletions.go
- core/providers/bedrock/bedrock_test.go
- core/providers/gemini/types.go
- framework/modelcatalog/pricing_test.go
- core/providers/gemini/gemini_test.go
- core/providers/gemini/responses.go
- core/schemas/responses.go
- core/providers/anthropic/responses.go
dd66f43 to
d24b9d7
Compare
Merge activity
|
## Summary Adds proper `service_tier` translation between Bifrost's OpenAI-compatible values and the native wire formats for Anthropic and Gemini providers, rather than passing the raw string through unchanged. ## Changes - Introduced four mapping helpers in the Anthropic provider (`MapBifrostServiceTierToAnthropicRequest`, `MapAnthropicRequestServiceTierToBifrost`, `MapAnthropicServiceTierToBifrost`, `MapBifrostServiceTierToAnthropicResponse`) to translate between Bifrost values (`auto`, `default`, `priority`, `flex`) and Anthropic's request values (`auto`, `standard_only`) and response values (`standard`, `priority`, `batch`). - Applied these mappers in both the chat and responses conversion paths for Anthropic, covering request encoding and response decoding in both directions. - Added a `ServiceTier` typed string and constants (`unspecified`, `flex`, `standard`, `priority`) to the Gemini types, along with a `ServiceTier` field on `GenerationConfig`. - Introduced `mapBifrostServiceTierToGemini` and `mapGeminiServiceTierToBifrost` helpers and wired them into both the chat and responses parameter conversion paths for Gemini. - Added tests covering forward and reverse service tier mapping for Gemini chat, responses, and the reverse-mapping path from a `GeminiGenerationRequest` back to a `BifrostResponsesRequest`. ## Type of change - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Documentation - [ ] Chore/CI ## Affected areas - [x] Core (Go) - [ ] Transports (HTTP) - [x] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [ ] Docs ## How to test ```sh go test ./core/providers/anthropic/... go test ./core/providers/gemini/... ``` The new Gemini tests (`TestServiceTierMappingChat`, `TestServiceTierMappingResponses`, `TestServiceTierReverseMapping`) exercise all tier values in both directions. Verify that: - Bifrost `"default"` → Anthropic request `"standard_only"`, Gemini `"standard"` - Bifrost `"auto"` / `"priority"` → Anthropic request `"auto"` - Anthropic response `"standard"` → Bifrost `"default"` - Gemini `"flex"` / `"priority"` round-trip correctly through Bifrost ## Breaking changes - [ ] Yes - [x] No ## Related issues ## Security considerations None. ## Checklist - [ ] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [ ] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable
## Summary This PR cuts the `v1.5.11` / `v1.3.11` release across core, framework, and all plugins, and introduces a new Claude skill (`release-checklist`) for pre-release migration safety auditing. ## Changes - **`release-checklist` skill** — Adds `.claude/skills/release-checklist/SKILL.md`, a read-only pre-release audit tool that scans Go-defined database migrations changed in a release for high-scale deadlock/lock-contention risks and boot-time-blocking operations. It produces a structured `PASS`/`WARN`/`FAIL` report with a concrete remediation plan per finding. The skill is designed to grow via an extensible Checks Registry. - **Version bumps** — `core` → `1.5.11`, `framework` → `1.3.11`, `transports` → `1.5.3`, `plugins/governance` → `1.5.11`, `plugins/logging` → `1.5.11`, `plugins/semanticcache` → `1.5.11`, `plugins/otel` → `1.2.11`, `plugins/maxim` → `1.6.11`, `plugins/prompts` → `1.0.11`, and remaining plugins bumped accordingly. - **Changelogs populated** — All per-package changelogs updated with the full set of features and fixes shipping in this release. Key highlights in this release: - Temporary access tokens for scoped, time-limited API access - MCP per-user OAuth flow refactor - Bedrock Mantle inference engine support - Azure Realtime provider with enriched session tracking - Direct access control (DAC) and virtual key rotation - Cluster-aware log metadata and per-node usage aggregation - Feature flag framework - Config-hash-based file value override of DB on restart - Semantic cache plugin rewrite - Numerous streaming stability, Bedrock, Anthropic, and Gemini fixes - AWS SDK and dependency security updates ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [ ] Documentation - [x] Chore/CI ## Affected areas - [x] Core (Go) - [x] Transports (HTTP) - [x] Providers/Integrations - [x] Plugins - [x] UI (React) - [ ] Docs ## How to test ```sh # Verify version files reflect the new release cat core/version # expect 1.5.11 cat framework/version # expect 1.3.11 cat transports/version # expect 1.5.3 # Core/Transports go test ./... ``` To exercise the new `release-checklist` skill, invoke it via Claude with: ``` /release-checklist origin/dev...HEAD ``` Expected output: a structured report with `PASS`/`WARN`/`FAIL` per check and a Remediation Plan table for any findings. ## Screenshots/Recordings N/A ## Breaking changes - [ ] Yes - [x] No ## Related issues #3603, #3565, #3489, #3334, #3335, #3435, #3554, #3590, #3444, #3198, #3581, #3610, #3599, #3567, #3382, #3461 and others listed in the changelogs. ## Security considerations - AWS SDK and dependency security updates are included (#3461). - `FullyRedacted()` for proxy passwords and `MarshalForStorage()` for `ProxyConfig` prevent partial secret leakage in API responses (#3445). - The `release-checklist` skill is strictly read-only and never modifies files. ## Checklist - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable

Summary
Adds proper
service_tiertranslation between Bifrost's OpenAI-compatible values and the native wire formats for Anthropic and Gemini providers, rather than passing the raw string through unchanged.Changes
MapBifrostServiceTierToAnthropicRequest,MapAnthropicRequestServiceTierToBifrost,MapAnthropicServiceTierToBifrost,MapBifrostServiceTierToAnthropicResponse) to translate between Bifrost values (auto,default,priority,flex) and Anthropic's request values (auto,standard_only) and response values (standard,priority,batch).ServiceTiertyped string and constants (unspecified,flex,standard,priority) to the Gemini types, along with aServiceTierfield onGenerationConfig.mapBifrostServiceTierToGeminiandmapGeminiServiceTierToBifrosthelpers and wired them into both the chat and responses parameter conversion paths for Gemini.GeminiGenerationRequestback to aBifrostResponsesRequest.Type of change
Affected areas
How to test
The new Gemini tests (
TestServiceTierMappingChat,TestServiceTierMappingResponses,TestServiceTierReverseMapping) exercise all tier values in both directions. Verify that:"default"→ Anthropic request"standard_only", Gemini"standard""auto"/"priority"→ Anthropic request"auto""standard"→ Bifrost"default""flex"/"priority"round-trip correctly through BifrostBreaking changes
Related issues
Security considerations
None.
Checklist
docs/contributing/README.mdand followed the guidelines