feat: add Anthropic OAuth passthrough support and gzip response decoding in all providers - #729
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughImplements Anthropic passthrough behavior by conditionally setting API keys, introducing modular route configuration builders, adding model-detection and context-augmentation logic for Claude models, and refactoring utility functions for authentication mode detection and path extraction. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Bifrost as Bifrost HTTP
participant Passthrough as checkAnthropicPassthrough
participant Core as Core Provider
participant Anthropic as Anthropic API
Client->>Bifrost: POST /messages (Claude model)
Bifrost->>Passthrough: PreCallback triggered
rect rgb(240, 248, 255)
note over Passthrough: Detect Claude model<br/>Check auth mode
alt x-api-key present
Passthrough->>Passthrough: Skip key selection
else Bearer token present
Passthrough->>Passthrough: OAuth mode detected
end
end
Passthrough->>Passthrough: Strip anthropic/ prefix<br/>Augment bifrost context
Passthrough-->>Bifrost: Context updated with headers & path
Bifrost->>Core: Forward request
Core->>Core: Conditionally set x-api-key<br/>(only if non-empty)
Core->>Anthropic: Send request
Anthropic-->>Core: Response
Core-->>Bifrost: Response
Bifrost-->>Client: Response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
core/providers/anthropic.go(1 hunks)transports/bifrost-http/integrations/anthropic.go(4 hunks)transports/bifrost-http/integrations/utils.go(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
transports/bifrost-http/integrations/anthropic.go (6)
transports/bifrost-http/integrations/router.go (5)
RouteConfig(190-207)RouteConfigTypeAnthropic(184-184)RequestConverter(80-80)TextResponseConverter(88-88)ErrorConverter(128-128)core/schemas/providers/anthropic/types.go (2)
AnthropicTextRequest(19-28)AnthropicMessageRequest(36-49)core/schemas/bifrost.go (9)
BifrostRequest(134-144)TextCompletionRequest(83-83)BifrostError(326-335)ModelProvider(32-32)Anthropic(37-37)BifrostContextKeyExtraHeaders(108-108)BifrostContextKeyURLPath(109-109)BifrostContextKeySkipKeySelection(107-107)BifrostContextKeyRequestBody(110-110)core/schemas/providers/anthropic/text.go (1)
ToAnthropicTextCompletionResponse(110-137)core/schemas/providers/anthropic/chat.go (1)
ToAnthropicChatCompletionError(991-1012)core/schemas/utils.go (1)
ParseModelString(21-34)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: Graphite / mergeability_check
- GitHub Check: Graphite / mergeability_check
- GitHub Check: Graphite / mergeability_check
- GitHub Check: Graphite / mergeability_check
- GitHub Check: Graphite / mergeability_check
- GitHub Check: Graphite / mergeability_check
- GitHub Check: Graphite / mergeability_check
- GitHub Check: Graphite / mergeability_check
- GitHub Check: Graphite / mergeability_check
- GitHub Check: Graphite / mergeability_check
| case *anthropic.AnthropicTextRequest: | ||
| provider, model = schemas.ParseModelString(r.Model, "") | ||
| // Check if model parameter explicitly has `anthropic/` prefix | ||
| if after, ok := strings.CutPrefix(model, "anthropic/"); ok { | ||
| r.Model = after | ||
| } | ||
|
|
||
| case *anthropic.AnthropicMessageRequest: | ||
| provider, model = schemas.ParseModelString(r.Model, "") | ||
| // Check if model parameter explicitly has `anthropic/` prefix | ||
| if after, ok := strings.CutPrefix(model, "anthropic/"); ok { | ||
| r.Model = after | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
Prefix trimming never executes
schemas.ParseModelString already strips the provider prefix from model, so this CutPrefix guard is always false and r.Model keeps values like anthropic/claude-3.5-sonnet. Those provider-qualified names are forwarded unchanged and Anthropic rejects them. Trim r.Model directly (and keep the local model variable in sync) so passthrough requests receive the bare model name they expect.
- if after, ok := strings.CutPrefix(model, "anthropic/"); ok {
- r.Model = after
+ if after, ok := strings.CutPrefix(r.Model, "anthropic/"); ok {
+ r.Model = after
+ model = after
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case *anthropic.AnthropicTextRequest: | |
| provider, model = schemas.ParseModelString(r.Model, "") | |
| // Check if model parameter explicitly has `anthropic/` prefix | |
| if after, ok := strings.CutPrefix(model, "anthropic/"); ok { | |
| r.Model = after | |
| } | |
| case *anthropic.AnthropicMessageRequest: | |
| provider, model = schemas.ParseModelString(r.Model, "") | |
| // Check if model parameter explicitly has `anthropic/` prefix | |
| if after, ok := strings.CutPrefix(model, "anthropic/"); ok { | |
| r.Model = after | |
| } | |
| } | |
| case *anthropic.AnthropicTextRequest: | |
| provider, model = schemas.ParseModelString(r.Model, "") | |
| // Check if model parameter explicitly has `anthropic/` prefix | |
| if after, ok := strings.CutPrefix(r.Model, "anthropic/"); ok { | |
| r.Model = after | |
| model = after | |
| } | |
| case *anthropic.AnthropicMessageRequest: | |
| provider, model = schemas.ParseModelString(r.Model, "") | |
| // Check if model parameter explicitly has `anthropic/` prefix | |
| if after, ok := strings.CutPrefix(r.Model, "anthropic/"); ok { | |
| r.Model = after | |
| model = after | |
| } | |
| } |
🤖 Prompt for AI Agents
In transports/bifrost-http/integrations/anthropic.go around lines 133 to 147,
the current CutPrefix check never runs because schemas.ParseModelString already
removed the provider prefix; as a result r.Model can remain as "anthropic/..."
and be forwarded to Anthropic. Fix by trimming the "anthropic/" prefix directly
on r.Model (e.g. use strings.CutPrefix on r.Model and set r.Model = after when
ok) and then update the local model variable to match (model = r.Model) in both
the AnthropicTextRequest and AnthropicMessageRequest cases so passthrough
requests send the bare model name.

Summary
Add support for Anthropic OAuth authentication to enable Claude Code integration. This PR allows Bifrost to handle both API key and OAuth authentication methods for Anthropic models.
Changes
sk-ant-oat)Type of change
Affected areas
How to test
Breaking changes
Related issues
Enables Claude Code integration
Security considerations
This PR handles authentication tokens securely by passing them through to the Anthropic API without modification.
Checklist