Skip to content

feat: add support for Anthropic models in Azure - #965

Merged
Pratham-Mishra04 merged 1 commit into
mainfrom
11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api
Dec 1, 2025
Merged

feat: add support for Anthropic models in Azure#965
Pratham-Mishra04 merged 1 commit into
mainfrom
11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api

Conversation

@Pratham-Mishra04

@Pratham-Mishra04 Pratham-Mishra04 commented Nov 29, 2025

Copy link
Copy Markdown
Collaborator

Summary

Added support for Anthropic models in Azure, allowing users to use Claude models through their Azure deployments alongside existing OpenAI models.

Changes

  • Added support for Anthropic models in Azure provider
  • Implemented naive Anthropic converters for Vertex Anthropic responses and response streams
  • Refactored Azure provider to detect and route Anthropic models appropriately
  • Updated documentation to refer to "Azure" instead of "Azure OpenAI" throughout the codebase
  • Renamed anthropicChatResponsePool to anthropicMessageResponsePool for consistency
  • Renamed ToAnthropicChatCompletionRequest to ToAnthropicChatRequest for clarity

Type of change

  • Feature
  • Bug fix
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

How to test

  1. Configure an Azure key with Claude model deployments
  2. Make requests to Azure Claude models using the Bifrost API
  3. Verify both streaming and non-streaming requests work correctly
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build

Breaking changes

  • Yes
  • No

Related issues

N/A

Security considerations

No new security implications.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Suite Available

This PR can be tested by a repository admin.

Run tests for PR #965

@coderabbitai

coderabbitai Bot commented Nov 29, 2025

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for Anthropic models in Azure
  • Bug Fixes

    • Fixed retry backoff configuration handling for correct millisecond interpretation
    • Corrected cache read input token cost calculations
    • Enhanced model lookup robustness for pricing
  • Documentation

    • Refreshed Azure branding throughout platform and API documentation
    • Added Elevenlabs to provider support matrix

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Adds Anthropic/Claude support across Azure and Vertex with deployment-aware routing and headers, centralizes Vertex error parsing, renames Anthropic streaming APIs and converters, marshals NetworkConfig backoff fields as milliseconds in JSON, clamps runtime backoff to configured max, adds model-family helpers, and updates branding/docs/UI.

Changes

Cohort / File(s) Change Summary
Anthropic provider
core/providers/anthropic/anthropic.go, core/providers/anthropic/chat.go, core/providers/anthropic/anthropic_test.go
Renamed response pool and Acquire/Release APIs to message-focused names; renamed request converter to ToAnthropicChatRequest; added shared streaming helper HandleAnthropicResponsesStream, post-response converter hook, headers map usage, modelName tracking in stream state; test config updated with ReasoningModel.
Azure provider
core/providers/azure/azure.go, core/providers/azure/types.go, core/providers/azure/azure_test.go
completeRequest now accepts deployment; added getModelDeployment; AzureProvider struct gained networkConfig and sendBackRawResponse; routing, URL/header/auth split for Anthropic vs OpenAI-style deployments; added AzureAnthropicAPIVersionDefault; tests/comments adjusted.
Vertex provider & errors
core/providers/vertex/vertex.go, core/providers/vertex/errors.go, core/providers/vertex/vertex_test.go
Centralized model-family checks using schemas.IsAnthropicModel/IsMistralModel; added unexported parseVertexError for multi-format error parsing; unified Anthropic/non-Anthropic response and streaming flows; populate ModelDeployment metadata when applicable.
Schemas & provider utils
core/schemas/utils.go, core/providers/utils/utils.go, core/schemas/provider.go
Added IsAnthropicModel and IsMistralModel helpers in schemas; removed legacy Vertex helper functions; added NetworkConfig custom MarshalJSON/UnmarshalJSON to treat RetryBackoffInitial/RetryBackoffMax as milliseconds in JSON while storing as time.Duration.
Framework streaming
framework/streaming/responses.go
Adjusted final-chunk handling so Azure Anthropic models follow the accumulation path (uses IsAnthropicModel(model)).
Gemini error handling
core/providers/gemini/errors.go, core/providers/gemini/gemini.go
Moved/extended Gemini error parsing into errors.go with JSON-first/raw fallback; removed old helpers from gemini.go.
Backoff & retries
core/utils.go, core/bifrost.go, core/bifrost_test.go
calculateBackoff now clamps jittered backoff to configured RetryBackoffMax; added debug log for sleep duration and minor wording tweaks; tests updated to account for max cap.
Transports & config validation
transports/bifrost-http/lib/config.go, transports/bifrost-http/handlers/providers.go, transports/bifrost-http/integrations/router.go, transports/bifrost-http/server/server.go
Added Min/Max retry backoff constants and validation (validateRetryBackoff) for provider add/update; refetch models now runs asynchronously; minor formatting changes.
UI & branding docs
docs/apis/openapi.json, docs/* (multiple files), ui/lib/constants/logs.ts, ui/README.md
Rebranded "Azure OpenAI" → "Azure" across docs, examples, UI labels; OpenAPI descriptions and deployment-id descriptions updated; provider capability matrix updated.
UI small UX
ui/app/workspace/logs/views/logChatMessageView.tsx, ui/app/workspace/logs/views/logDetailsSheet.tsx
Added break-words to log message container and gap-4 to details sheet layout.
Logging plugin
plugins/logging/main.go, plugins/logging/operations.go
Stop embedding NumberOfRetries in initial insert; extract NumberOfRetries from context in PostHook and propagate into update/updateStreaming entries; added parsed-fields on initial entry.
Pricing & cost calc
framework/modelcatalog/pricing.go
Threaded deployment parameter through cost lookups; pricing lookup retries with deployment key when initial lookup fails; use CacheReadInputTokenCost for cached read input token cost; Bedrock/Claude mapping heuristics added.
Tests & misc
core/chatbot_test.go, core/internal/testutil/account.go, core/providers/azure/azure_test.go, core/bifrost_test.go, core/providers/anthropic/anthropic_test.go, core/providers/vertex/vertex_test.go
Test/util updates: Azure reasoning model switched to claude-opus-4-5, backoff test adjustments, wording and minor formatting changes.
Changelogs, versions & misc
core/changelog.md, framework/changelog.md, plugins/*/changelog.md, plugins/*/version, core/version, transports/version
Added changelog entries and bumped multiple component/plugin versions.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant Gateway
    participant AzureProvider
    participant AnthropicAPI
    participant OpenAIEndpoint
    participant PostHook

    Client->>Gateway: Send request (model, optional deployment)
    Gateway->>AzureProvider: getModelDeployment(key, model)
    alt deployment is Anthropic
        AzureProvider->>AnthropicAPI: Build Anthropic request (deployment URL, OAuth header), stream
        AnthropicAPI-->>AzureProvider: Streamed chunks (include modelName)
        AzureProvider->>PostHook: postResponseConverter per chunk (nil-safe)
        PostHook-->>Gateway: Converted stream chunks
        Gateway-->>Client: Streamed chunks
    else OpenAI-style deployment
        AzureProvider->>OpenAIEndpoint: Build OpenAI-style request (deployments/{deployment}/...), send
        OpenAIEndpoint-->>AzureProvider: Final response
        AzureProvider->>PostHook: postResponseConverter on final response
        PostHook-->>Gateway: Converted response
        Gateway-->>Client: Final response
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Files/areas needing extra attention:
    • core/providers/azure/azure.go — deployment resolution, per-deployment URL/auth, streaming branching.
    • core/providers/vertex/* — unified Anthropic handling and parseVertexError correctness.
    • core/providers/anthropic/anthropic.go — renamed pools/APIs and new streaming helper signatures.
    • core/schemas/provider.go — NetworkConfig Marshal/Unmarshal correctness and edge cases.
    • transports/bifrost-http/handlers/providers.go — validation logic and async refetch behavior.
    • framework/modelcatalog/pricing.go — deployment-aware pricing lookup and cost calculations.

Poem

🐇 I nibbled code and found new lanes,
Azure now hums with Claude-like strains.
Chunks and headers hop in tune,
Deployments tracked by moon and noon.
Hop — this rabbit loves the new delights!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 74.19% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main feature added: support for Anthropic models in Azure, which aligns with the primary objective of the PR.
Description check ✅ Passed The description follows the template structure with all major sections completed: Summary, Changes, Type of change, Affected areas, How to test, Breaking changes, and Checklist. Required information is present and comprehensive.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api

Comment @coderabbitai help to get the list of available commands and usage tips.

@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch 3 times, most recently from e69ca18 to bf4722e Compare November 29, 2025 12:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 (2)
core/providers/bedrock/bedrock.go (1)

529-544: Perfect! I now have all the information needed to verify this review comment. The issue is confirmed.

Use request.Model instead of deployment for model type detection in TextCompletion response unmarshaling

The refactored code checks schemas.IsAnthropicModel(deployment) and schemas.IsMistralModel(deployment) at lines 529 and 536, but deployment may be empty when no deployment mapping exists in BedrockKeyConfig.Deployments. This causes both checks to fail even if the actual model supports text completion.

The inconsistency is clear: request conversion in text.go line 43 checks bifrostReq.Model using the same strings.Contains logic. Response unmarshaling should do the same. When deployment is empty but request.Model is "anthropic.claude-3-sonnet", the function incorrectly returns an "unsupported model type" error at line 544.

Fix: Replace deployment with request.Model in the model type checks:

case schemas.IsAnthropicModel(request.Model):

and

case schemas.IsMistralModel(request.Model):

This maintains consistency with request/response conversion logic and allows text completion to work without mandatory deployment mappings.

core/providers/anthropic/anthropic.go (1)

863-893: Missing postResponseConverter invocation in streaming loop.

The postResponseConverter parameter is declared (Line 723) but never called within the streaming loop. In contrast, HandleAnthropicChatCompletionStreaming applies the converter at lines 564-570. This means callers like Vertex's ResponsesStream (which passes a postResponseConverter to set ModelDeployment) won't have their converter applied.

Add the converter invocation before setting ExtraFields:

 			for i, response := range responses {
 				if response != nil {
+					if postResponseConverter != nil {
+						response = postResponseConverter(response)
+						if response == nil {
+							logger.Warn("postResponseConverter returned nil; skipping chunk")
+							continue
+						}
+					}
+
 					response.ExtraFields = schemas.BifrostResponseExtraFields{
 						RequestType:    schemas.ResponsesStreamRequest,
 						Provider:       providerName,
♻️ Duplicate comments (4)
docs/apis/openapi.json (4)

2003-2032: Same deployment-id wording consideration as chat completions

Same comment as for the chat-completions deployment path: you may want to harmonize the deployment-id parameter description with the new generic “OpenAI-compatible … for specific deployments” phrasing.


2115-2144: Embedding deployments path shares the same minor docs nit

This embeddings deployment endpoint has the same minor Azure-vs-generic deployment-id wording as noted earlier; consider updating here together with the other deployment endpoints if you decide to adjust it.


2224-2225: Speech deployments description follows same pattern

The speech deployment endpoint’s summary/description are now generic “OpenAI Compatible … for specific deployments”; it shares the same optional deployment-id wording tweak discussed in the chat/completions comment.


2332-2333: Transcription deployments description follows same pattern

Likewise for the audio transcriptions deployment endpoint; see earlier note about possibly standardizing the deployment-id parameter description across all these Azure-style routes.

🧹 Nitpick comments (8)
ui/app/workspace/logs/views/logChatMessageView.tsx (1)

29-29: Good addition of break-words — consider applying consistently.

Adding break-words prevents overflow of long unbreakable strings. However, for consistency, consider applying the same text wrapping approach to other non-JSON text renderings in this file (lines 89 and 132) that also display user-generated content.

Apply this diff to add consistent text wrapping to the thought content:

-<div className="text-muted-foreground px-6 py-2 font-mono text-xs whitespace-pre-wrap italic">{message.thought}</div>
+<div className="text-muted-foreground px-6 py-2 font-mono text-xs break-words whitespace-pre-wrap italic">{message.thought}</div>

And to the string content:

-<div className="px-6 py-2 font-mono text-xs whitespace-pre-wrap">{message.content}</div>
+<div className="px-6 py-2 font-mono text-xs break-words whitespace-pre-wrap">{message.content}</div>
core/changelog.md (1)

1-2: Polish wording in changelog entry.

Minor copy nit: consider standardizing spelling and phrasing for clarity:

-- enhancement: using naive anthropic convertors for Vertex Anthropic responses and responses stream
+- enhancement: using naive Anthropic converters for Vertex Anthropic responses and response streams

Purely cosmetic; feel free to skip if you prefer the current wording.

docs/integrations/litellm-sdk.mdx (1)

73-79: Azure branding updates are correct; optional clarification on env vars.

The renames to “Azure models” and “Using Azure with direct Azure key” read well and align with the new terminology. Since the example still uses AZURE_OPENAI_DEPLOYMENT, you might (optionally) add a short note that these env var names are legacy/compatible Azure naming to avoid confusion for readers skimming just this section.

Also applies to: 146-162

core/providers/vertex/errors.go (1)

10-38: Consider renaming shadowed variable for clarity.

Line 17 declares var vertexErr VertexError which shadows the array variable var vertexErr []VertexError from Line 12. While this is valid Go (different scopes), it reduces readability. Consider using distinct names like vertexErrArray and vertexErrSingle.

 func parseVertexError(providerName schemas.ModelProvider, resp *fasthttp.Response) *schemas.BifrostError {
 	var openAIErr schemas.BifrostError
-	var vertexErr []VertexError
+	var vertexErrArray []VertexError
-	if err := sonic.Unmarshal(resp.Body(), &openAIErr); err != nil || openAIErr.Error == nil {
+	if err := sonic.Unmarshal(resp.Body(), &openAIErr); err != nil || openAIErr.Error == nil {
 		// Try Vertex error format if OpenAI format fails or is incomplete
-		if err := sonic.Unmarshal(resp.Body(), &vertexErr); err != nil {
+		if err := sonic.Unmarshal(resp.Body(), &vertexErrArray); err != nil {
 			//try with single Vertex error format
-			var vertexErr VertexError
-			if err := sonic.Unmarshal(resp.Body(), &vertexErr); err != nil {
+			var vertexErrSingle VertexError
+			if err := sonic.Unmarshal(resp.Body(), &vertexErrSingle); err != nil {
 				// Try VertexValidationError format (validation errors from Mistral endpoint)
 				var validationErr VertexValidationError
 				if err := sonic.Unmarshal(resp.Body(), &validationErr); err != nil {
 					return providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, schemas.Vertex)
 				}
 				if len(validationErr.Detail) > 0 {
 					return providerUtils.NewProviderAPIError(validationErr.Detail[0].Msg, nil, resp.StatusCode(), schemas.Vertex, nil, nil)
 				}
 				return providerUtils.NewProviderAPIError("Unknown error", nil, resp.StatusCode(), schemas.Vertex, nil, nil)
 			}
-			return providerUtils.NewProviderAPIError(vertexErr.Error.Message, nil, resp.StatusCode(), schemas.Vertex, nil, nil)
+			return providerUtils.NewProviderAPIError(vertexErrSingle.Error.Message, nil, resp.StatusCode(), schemas.Vertex, nil, nil)
 		}
-		if len(vertexErr) > 0 {
-			return providerUtils.NewProviderAPIError(vertexErr[0].Error.Message, nil, resp.StatusCode(), schemas.Vertex, nil, nil)
+		if len(vertexErrArray) > 0 {
+			return providerUtils.NewProviderAPIError(vertexErrArray[0].Error.Message, nil, resp.StatusCode(), schemas.Vertex, nil, nil)
 		}
 		return providerUtils.NewProviderAPIError("Unknown error", nil, resp.StatusCode(), schemas.Vertex, nil, nil)
 	}
 	// OpenAI error format succeeded with valid Error field
 	return providerUtils.NewProviderAPIError(openAIErr.Error.Message, nil, resp.StatusCode(), schemas.Vertex, nil, nil)
 }
core/schemas/utils.go (1)

1042-1050: Model detection helpers are fine; consider generalizing comments

The new IsAnthropicModel and IsMistralModel helpers provide a simple, centralized way to detect Anthropic/Claude and Mistral/Codestral models via substring checks, which is consistent with how models are named elsewhere in the codebase.

The only nit is that both comments mention “in Vertex”, but these helpers are now used across multiple providers. You might want to generalize the comments to avoid confusion, e.g.:

-// IsAnthropicModel checks if the model is an Anthropic model in Vertex.
+// IsAnthropicModel checks if the model string represents an Anthropic/Claude model.
@@
-// IsMistralModel checks if the model is a Mistral or Codestral model in Vertex.
+// IsMistralModel checks if the model string represents a Mistral or Codestral model.

This keeps the behavior as-is but better reflects actual usage.

docs/apis/openapi.json (1)

1881-1911: Align deployment-id wording across Azure-style OpenAI endpoints

Here and in the other /openai/deployments/{deployment-id}/… paths, the summaries now say “OpenAI Compatible … for specific deployments”, but the path param description still reads “Azure deployment ID”. Consider standardizing this text (e.g., “Deployment ID (for example, an Azure model deployment identifier)”) across all such endpoints for consistency and to avoid confusing users about whether these are Azure-only.

core/providers/azure/azure.go (2)

360-370: Consider using deployment instead of request.Model for consistency.

The model check at Line 361 uses request.Model while Line 364 sets reqBody.Model = deployment. For consistency with the streaming path (which uses deployment in the check), consider using schemas.IsAnthropicModel(deployment) here.

-			if schemas.IsAnthropicModel(request.Model) {
+			if schemas.IsAnthropicModel(deployment) {

533-557: Consider using deployment for model check consistency.

Similar to ChatCompletion, lines 533 and 553 use request.Model for the Anthropic check, while the streaming counterpart (ResponsesStream at Line 622) uses deployment. For consistency across all methods, consider using deployment.

-			if schemas.IsAnthropicModel(request.Model) {
+			if schemas.IsAnthropicModel(deployment) {

And at Line 553:

-	if schemas.IsAnthropicModel(request.Model) {
+	if schemas.IsAnthropicModel(deployment) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6570cf1 and bf4722e.

📒 Files selected for processing (34)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (1 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/schemas/utils.go (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/changelog.md (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • core/providers/utils/utils.go
🧰 Additional context used
🧬 Code graph analysis (8)
core/providers/bedrock/bedrock.go (3)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/bedrock/types.go (1)
  • BedrockAnthropicTextResponse (235-239)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/providers/openai/chat.go (2)
core/schemas/utils.go (1)
  • IsMistralModel (1048-1050)
core/schemas/models.go (1)
  • Model (109-129)
core/providers/anthropic/chat.go (2)
core/schemas/chatcompletions.go (1)
  • BifrostChatRequest (12-19)
core/providers/anthropic/types.go (1)
  • AnthropicMessageRequest (39-58)
core/providers/vertex/vertex.go (11)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • Ptr (16-18)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/providers/anthropic/anthropic.go (1)
  • HandleAnthropicResponsesStream (713-908)
core/providers/utils/utils.go (5)
  • HandleProviderResponse (343-387)
  • CheckContextAndGetRequestBody (256-274)
  • NewConfigurationError (435-445)
  • SetExtraHeaders (178-208)
  • NewBifrostOperationError (449-460)
core/schemas/bifrost.go (7)
  • BifrostResponseExtraFields (284-293)
  • RequestType (83-83)
  • ChatCompletionRequest (89-89)
  • BifrostError (353-362)
  • Vertex (40-40)
  • ResponsesRequest (91-91)
  • BifrostStream (318-325)
core/schemas/account.go (2)
  • Key (8-17)
  • VertexKeyConfig (29-35)
core/schemas/responses.go (3)
  • BifrostResponsesRequest (32-39)
  • BifrostResponsesResponse (45-82)
  • BifrostResponsesStreamResponse (1421-1459)
core/providers/anthropic/responses.go (1)
  • ToAnthropicResponsesRequest (284-383)
core/providers/vertex/types.go (1)
  • DefaultVertexAnthropicVersion (8-8)
core/schemas/provider.go (1)
  • PostHookRunner (204-204)
core/utils.go (1)
  • Ptr (51-53)
core/providers/azure/azure.go (4)
core/schemas/account.go (2)
  • Key (8-17)
  • AzureKeyConfig (21-25)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • Ptr (16-18)
core/providers/azure/types.go (1)
  • AzureAnthropicAPIVersionDefault (6-6)
core/utils.go (1)
  • Ptr (51-53)
core/providers/anthropic/anthropic.go (4)
core/providers/anthropic/types.go (1)
  • AnthropicMessageResponse (272-281)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/schemas/bifrost.go (4)
  • ModelProvider (32-32)
  • BifrostResponseExtraFields (284-293)
  • RequestType (83-83)
  • BifrostError (353-362)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
framework/streaming/responses.go (2)
core/schemas/bifrost.go (3)
  • OpenAI (35-35)
  • OpenRouter (49-49)
  • Azure (36-36)
core/schemas/utils.go (1)
  • IsAnthropicModel (1043-1045)
ui/app/workspace/logs/views/logDetailsSheet.tsx (1)
ui/components/ui/sheet.tsx (1)
  • SheetContent (140-140)
🔇 Additional comments (47)
docs/features/unified-interface.mdx (2)

91-91: Branding update from "Azure OpenAI" to "Azure" is correct.

The provider name change aligns with the PR objective and properly reflects that Azure now supports multiple model families (OpenAI and Anthropic). The format azure/<model> is consistent with other provider naming conventions.


95-95: Verify Elevenlabs TTS/STT capability flags are accurate and intentional.

The Elevenlabs row was updated to show ✅ for TTS and ✅ for STT (previously all ❌). Please confirm these capability updates reflect actual Elevenlabs support and are not coincidental changes. If these are unrelated to the Anthropic/Azure feature, consider whether they should be in a separate commit for clarity.

ui/app/workspace/logs/views/logDetailsSheet.tsx (2)

39-39: Improved spacing layout for better readability.

Adding gap-4 to the SheetContent creates consistent vertical spacing between child elements, enhancing visual hierarchy and readability without affecting functionality. The component already displays provider and model information generically (lines 92, 97), so it will seamlessly accommodate Anthropic models from Azure.


52-56: Minor JSX formatting adjustment.

The closing > tag repositioning is a non-functional whitespace/code-layout change.

transports/bifrost-http/integrations/router.go (1)

304-304: LGTM! Formatting-only changes.

These changes adjust whitespace and brace formatting without altering any functional behavior, control flow, or error handling logic.

Also applies to: 328-328, 536-536

docs/quickstart/gateway/multimodal.mdx (1)

292-298: Azure label rename looks good.

Renaming the provider from “Azure OpenAI” to “Azure” in the support table is consistent with the rest of the branding changes; no further tweaks needed.

transports/changelog.md (1)

1-2: Changelog entry is clear and aligned with core changes.

The new “feat: added support for Anthropic models in Azure” bullet succinctly reflects the transport‑level addition and matches the core changelog; no functional concerns here.

docs/quickstart/go-sdk/multimodal.mdx (1)

339-345: Go SDK provider table rename is consistent.

The Azure row label change to “Azure” matches the rest of the docs and doesn’t affect examples; all good.

docs/integrations/what-is-an-integration.mdx (1)

88-97: Azure tab rename fits the provider-prefixed model pattern.

Using “Azure” as the tab title and “# Azure models” keeps the examples consistent with other providers and the new naming; no further changes needed.

core/internal/testutil/account.go (1)

648-651: Comment update matches Azure behavior and naming.

The updated comment for Azure’s TextModel (no text completion in newer models) reflects current capabilities and aligns with the broader Azure renaming; no code changes required.

framework/streaming/responses.go (1)

595-599: Azure Anthropic correctly excluded from OpenAI-style streaming fast path.

The updated condition

if provider == schemas.OpenAI || provider == schemas.OpenRouter || (provider == schemas.Azure && !schemas.IsAnthropicModel(model)) {

ensures Azure Claude/Anthropic deployments go through the accumulation path instead of assuming the final chunk carries the complete response, while keeping OpenAI, OpenRouter, and non-Anthropic Azure models on the cheaper short‑circuit path. The tightened cleanup comment in processAccumulatedResponsesStreamingChunks also accurately documents the “cleanup before unlock” ordering without changing behavior. This looks sound given the new Azure Anthropic support.

Also applies to: 686-745

docs/integrations/langchain-sdk.mdx (1)

221-221: LGTM! Documentation branding update is consistent.

The terminology change from "Azure OpenAI" to "Azure" aligns with the broader provider rebranding across the PR and improves clarity.

Also applies to: 269-269

docs/quickstart/gateway/provider-configuration.mdx (1)

762-774: LGTM! Provider-specific authentication section updated correctly.

The Azure section heading and descriptive text updates maintain consistency with the rebranding effort.

ui/README.md (1)

84-84: LGTM! UI documentation updated consistently.

The supported providers list now correctly reflects the "Azure" branding.

ui/lib/constants/logs.ts (1)

45-45: LGTM! UI provider label updated correctly.

The ProviderLabels constant now reflects the updated "Azure" branding consistently across the UI.

docs/features/keys-management.mdx (1)

198-198: LGTM! Keys management documentation updated consistently.

The deployment mapping section heading now uses "Azure" branding.

core/providers/azure/azure_test.go (1)

32-32: LGTM! Test comment updated consistently.

The comment now uses "Azure" terminology consistently with the broader rebranding effort.

docs/integrations/anthropic-sdk.mdx (2)

104-109: Azure label rename is consistent and clear

The “Azure models” label matches the azure/gpt-4o prefix and the new naming used elsewhere in the docs; no behavioral concerns.


151-156: JS Azure section matches Python example and naming

The JavaScript “Azure models” label and example mirror the Python snippet and are aligned with the updated Azure terminology.

docs/integrations/genai-sdk.mdx (2)

98-102: Azure naming update is consistent with provider prefix

Using “Azure models” for the azure/gpt-4o example keeps the provider list consistent and avoids the older “Azure OpenAI” wording.


133-136: JavaScript Azure example correctly mirrors Python section

The JS heading/comment now use “Azure models”, matching the Python tab and the rest of the rebranding.

core/providers/openai/chat.go (1)

48-54: Centralizing Mistral detection via schemas.IsMistralModel looks correct

Using schemas.IsMistralModel(bifrostReq.Model) in the Vertex branch keeps the Mistral compatibility logic while aligning with the new shared helpers; scope is still only Vertex models so impact is controlled.

core/providers/azure/types.go (1)

3-6: New Azure Anthropic API version constant is reasonable

Adding AzureAnthropicAPIVersionDefault = "2023-06-01" alongside the general AzureAPIVersionDefault cleanly separates Anthropic-specific API versioning; comment text for the default Azure API version also reads correctly.

core/chatbot_test.go (3)

632-641: Whitespace/formatting tweak around synthesis input is safe

The adjustment around the Input: conversationWithSynthesis field doesn’t alter behavior; structure of the synthesis request is unchanged.


774-782: Azure provider description text matches updated branding

The help text now lists “Azure (Azure models)”, which is consistent with other docs and the provider naming used in the rest of this file.


836-843: Azure env-var guidance remains accurate after wording change

The hint about AZURE_API_KEY and AZURE_ENDPOINT is still correct; the tweak to say “for Azure” just matches the new terminology.

docs/integrations/openai-sdk.mdx (3)

99-103: Python Azure example label matches provider prefix

Renaming the comment to “Azure models” aligns with the azure/gpt-4o model prefix and the broader Azure terminology used elsewhere.


141-145: JS Azure example label is consistent with Python and other docs

The JavaScript “Azure models” label matches the Python tab and keeps provider naming uniform across SDK docs.


319-365: Azure section wording now matches integration behavior and naming

The introductory sentence now refers generically to “Azure” while still documenting the x-bf-azure-endpoint requirement and Bifrost /openai endpoint, which fits the updated branding without changing the integration semantics.

docs/apis/openapi.json (1)

1759-1788: Deployment completions endpoint wording looks consistent

The updated summary/description/response text for /openai/deployments/{deployment-id}/completions now match the “OpenAI-compatible” positioning used elsewhere; nothing blocking here.

docs/quickstart/go-sdk/provider-configuration.mdx (1)

274-280: Azure provider-auth wording matches the new branding and config shape

The updated intro and “Azure” tab title cleanly align with the broader shift away from “Azure OpenAI” wording, and the brief description (endpoint URL, deployment mappings, API version) correctly reflects what the Azure key config requires.

core/providers/anthropic/chat.go (1)

384-386: Function rename successfully verified—no stale references remaining

The search confirms that all references to ToAnthropicChatCompletionRequest have been updated across the codebase. The new name ToAnthropicChatRequest accurately reflects the function's role of converting a Bifrost chat request to Anthropic format, and the updated comment clearly documents this purpose. The rename is complete and ready.

core/providers/vertex/vertex.go (4)

299-336: LGTM on centralized Anthropic model detection and request building.

The switch to schemas.IsAnthropicModel(deployment) provides cleaner, centralized model detection. The double marshal/unmarshal pattern (noted with TODO) is understood as a workaround for converting struct to map.


443-495: LGTM on response handling with proper pool usage.

The response handling correctly uses the renamed pool functions and conditionally sets ModelDeployment only when it differs from ModelRequested, avoiding redundant data.


519-524: LGTM on postResponseConverter pattern for streaming.

The closure correctly captures deployment to populate ModelDeployment in streaming responses when it differs from ModelRequested.


1064-1066: LGTM on consistent ModelDeployment handling.

The conditional assignment of ModelDeployment is now consistent across ChatCompletion, Responses, ResponsesStream, and Embedding methods.

core/providers/azure/azure.go (5)

63-127: LGTM on refactored completeRequest with deployment-aware routing.

The function correctly branches between Anthropic and OpenAI paths:

  • Anthropic: uses x-api-key header and direct URL without api-version
  • OpenAI: uses Bearer token or api-key header with api-version query parameter

The expanded signature properly supports deployment-scoped URL construction.


245-268: LGTM on TextCompletion with centralized deployment lookup.

TextCompletion correctly uses the new getModelDeployment helper and doesn't need an Anthropic path since Anthropic doesn't support legacy text completion endpoints.


442-513: LGTM on ChatCompletionStream with proper Anthropic/OpenAI routing.

The streaming implementation correctly:

  • Uses deployment for the model type check (Line 449)
  • Sets appropriate headers for each path
  • Uses the corresponding streaming handler

614-690: LGTM on ResponsesStream with correct deployment-based routing.

The implementation correctly uses deployment for the model check and properly routes to either the Anthropic or OpenAI streaming handler with appropriate converters.


789-800: LGTM on centralized deployment lookup helper.

The getModelDeployment helper provides clean, centralized deployment resolution. The redundant nil check with validateKeyConfig is acceptable defensive coding.

core/providers/anthropic/anthropic.go (6)

30-56: LGTM on pool and accessor function renames.

The rename from anthropicChatResponsePool to anthropicMessageResponsePool better reflects that AnthropicMessageResponse is the underlying type. The public accessors are correctly updated.


318-332: LGTM on consistent usage of renamed functions.

ToAnthropicChatRequest and the renamed pool functions are used consistently throughout ChatCompletion and ChatCompletionStream.


407-421: LGTM on enhanced streaming handler signature.

The addition of postResponseConverter parameter enables callers (like Vertex and Azure providers) to inject deployment-specific metadata into streaming responses. The parameter rename from providerType to providerName better reflects its usage.


564-570: LGTM on postResponseConverter integration.

The defensive nil checks and warning log for converter-returned nil values are good practices. The converter is applied before populating ExtraFields, allowing it to modify the response structure if needed.


685-708: LGTM on ResponsesStream refactor to use shared handler.

The refactored code follows the same pattern as ChatCompletionStream, building headers in a map and delegating to the shared HandleAnthropicResponsesStream function. This improves code reuse across providers.


392-404: LGTM on internal provider usage passing nil converter.

The Anthropic provider correctly passes nil for postResponseConverter when calling its own streaming handler, as it doesn't need deployment metadata injection (unlike Azure/Vertex which have deployment mappings).

Comment thread core/providers/vertex/vertex.go
Comment thread core/providers/vertex/vertex.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/providers/anthropic/anthropic.go (1)

863-893: postResponseConverter parameter is declared but never used.

The HandleAnthropicResponsesStream function accepts a postResponseConverter parameter (line 723) but never applies it to responses before sending. Compare with HandleAnthropicChatCompletionStreaming (lines 564-570) which correctly applies its converter.

Add the converter application within the response processing loop:

 			for i, response := range responses {
 				if response != nil {
+					if postResponseConverter != nil {
+						response = postResponseConverter(response)
+						if response == nil {
+							logger.Warn("postResponseConverter returned nil; skipping chunk")
+							continue
+						}
+					}
+
 					response.ExtraFields = schemas.BifrostResponseExtraFields{
 						RequestType:    schemas.ResponsesStreamRequest,
 						Provider:       providerName,
🧹 Nitpick comments (10)
ui/app/workspace/logs/views/logChatMessageView.tsx (1)

14-32: Improved wrapping for long plain-text content blocks

Adding break-words to the non-JSON block.text container should prevent horizontal overflow for long tokens/URLs and makes the log view more readable. If you want perfectly consistent behavior, you could later mirror this on the top-level message.content non-JSON path, but it’s not required for this PR.

docs/integrations/openai-sdk.mdx (1)

319-369: Add note for Anthropic-on-Azure usage.

Since this PR routes Anthropic models via Azure, add a brief note/example showing a Claude deployment with AzureOpenAI client and any API-version/header nuances if different from OpenAI deployments.

docs/quickstart/go-sdk/provider-configuration.mdx (1)

274-306: Nice Azure provider-auth example; consider Anthropic-in-Azure details.

Please add:

  • A Claude deployment mapping example alongside GPT deployments.
  • A note on the default API versions for Azure OpenAI vs Azure Anthropic (and when to override).
docs/apis/openapi.json (5)

1881-1923: Make parameter description generic (“Deployment ID”).

This block still says “Azure deployment ID”. Recommend aligning with the earlier change.

-            "description": "Azure deployment ID",
+            "description": "Deployment ID",

2003-2045: Make parameter description generic (“Deployment ID”).

-            "description": "Azure deployment ID",
+            "description": "Deployment ID",

2115-2153: Make parameter description generic (“Deployment ID”).

-            "description": "Azure deployment ID",
+            "description": "Deployment ID",

2223-2263: Make parameter description generic (“Deployment ID”).

-            "description": "Azure deployment ID",
+            "description": "Deployment ID",

2330-2371: Make parameter description generic (“Deployment ID”).

-            "description": "Azure deployment ID",
+            "description": "Deployment ID",
core/providers/vertex/errors.go (1)

12-18: Variable shadowing reduces readability.

The inner vertexErr on line 17 shadows the outer vertexErr slice declared on line 12. While this works correctly due to Go's scoping rules, consider renaming the inner variable for clarity.

 	var vertexErr []VertexError
 	if err := sonic.Unmarshal(resp.Body(), &openAIErr); err != nil || openAIErr.Error == nil {
 		// Try Vertex error format if OpenAI format fails or is incomplete
 		if err := sonic.Unmarshal(resp.Body(), &vertexErr); err != nil {
 			//try with single Vertex error format
-			var vertexErr VertexError
-			if err := sonic.Unmarshal(resp.Body(), &vertexErr); err != nil {
+			var singleVertexErr VertexError
+			if err := sonic.Unmarshal(resp.Body(), &singleVertexErr); err != nil {
core/providers/vertex/vertex.go (1)

682-830: Consider extracting common Anthropic request handling.

The Anthropic path in Responses shares significant code with ChatCompletion (validation, URL construction, auth token handling, HTTP request setup). This is acceptable for now, but if more methods need Anthropic support, consider extracting a common helper like makeAnthropicRequest(ctx, key, path, body) to reduce duplication.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6570cf1 and bf4722e.

📒 Files selected for processing (34)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (1 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/schemas/utils.go (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/changelog.md (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • core/providers/utils/utils.go
🧰 Additional context used
🧬 Code graph analysis (7)
core/providers/openai/chat.go (2)
core/schemas/utils.go (1)
  • IsMistralModel (1048-1050)
core/schemas/models.go (1)
  • Model (109-129)
framework/streaming/responses.go (2)
core/schemas/bifrost.go (3)
  • OpenAI (35-35)
  • OpenRouter (49-49)
  • Azure (36-36)
core/schemas/utils.go (1)
  • IsAnthropicModel (1043-1045)
core/providers/anthropic/chat.go (2)
core/schemas/chatcompletions.go (1)
  • BifrostChatRequest (12-19)
core/providers/anthropic/types.go (1)
  • AnthropicMessageRequest (39-58)
ui/app/workspace/logs/views/logDetailsSheet.tsx (1)
ui/components/ui/sheet.tsx (1)
  • SheetContent (140-140)
core/providers/vertex/errors.go (5)
core/providers/vertex/vertex.go (1)
  • VertexError (25-31)
core/providers/vertex/types.go (1)
  • VertexValidationError (154-161)
core/providers/utils/utils.go (2)
  • NewBifrostOperationError (449-460)
  • NewProviderAPIError (464-479)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (29-29)
core/schemas/bifrost.go (1)
  • Vertex (40-40)
core/providers/anthropic/anthropic.go (5)
core/providers/anthropic/types.go (1)
  • AnthropicMessageResponse (272-281)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/schemas/bifrost.go (4)
  • ModelProvider (32-32)
  • BifrostResponseExtraFields (284-293)
  • RequestType (83-83)
  • BifrostError (353-362)
core/schemas/provider.go (2)
  • PostHookRunner (204-204)
  • Provider (207-234)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/providers/bedrock/bedrock.go (3)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/bedrock/types.go (1)
  • BedrockAnthropicTextResponse (235-239)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
🔇 Additional comments (41)
docs/integrations/litellm-sdk.mdx (1)

73-78: Documentation branding updates look good.

The renaming from "Azure OpenAI models" to "Azure models" and "Using Azure OpenAI with direct Azure key" to "Using Azure with direct Azure key" correctly reflects the expanded scope of Azure support to include Anthropic models alongside OpenAI. The examples remain accurate—environment variable names (AZURE_OPENAI_DEPLOYMENT) and endpoint URLs appropriately retain their original conventions since they follow LiteLLM and Azure service naming, not Bifrost branding.

Also applies to: 146-162

transports/bifrost-http/integrations/router.go (1)

528-542: SpeechResponseConverter nil fallback is correct.

The else branch at lines 536–542 properly handles the case where SpeechResponseConverter is nil by sending raw audio with appropriate headers (Content-Type, Content-Disposition, Content-Length). This complements the converter path above and ensures speech responses can still be served even when no converter is configured. The early return prevents further processing.

One minor note: ensure that upstream handlers never pass a nil speechResponse to this code path. Looking at lines 523–526, a nil check happens before this block, so this is already safe.

ui/app/workspace/logs/views/logDetailsSheet.tsx (2)

39-39: LGTM! Spacing improvement enhances visual clarity.

The gap-4 utility adds consistent vertical spacing between sections in the sheet, improving readability and visual hierarchy.


52-56: LGTM! Formatting adjustment with no functional impact.

The reformatting of the closing braces is purely cosmetic and maintains the existing delete functionality.

ui/README.md (1)

84-88: Azure branding in provider list looks consistent

Using just "Azure" in the Supported Providers list matches the new branding used elsewhere in the repo. No further changes needed.

docs/integrations/anthropic-sdk.mdx (1)

104-109: Azure model examples match routing semantics

Labeling these as “Azure models” and using the azure/gpt-4o prefix aligns with the provider-prefixed routing convention and updated branding. Looks good.

Also applies to: 151-156

core/providers/openai/chat.go (1)

35-55: Centralizing Mistral detection via schemas.IsMistralModel

Switching the Vertex branch to use schemas.IsMistralModel(bifrostReq.Model) is a nice consolidation and keeps the Mistral compatibility logic in one place. Since this is now substring-based on "mistral" / "codestral", it will apply to any Vertex model IDs following that convention.

It’d be good to ensure there are tests that:

  • Exercise a Vertex Mistral model slug (e.g., mistral-large-*) and confirm applyMistralCompatibility() is hit.
  • Exercise a non-Mistral Vertex model and confirm it’s not.

Tagging this as a verification point only; the change itself looks correct.

docs/integrations/what-is-an-integration.mdx (1)

88-97: Azure tab/docs text aligned with provider-prefix usage

Renaming the tab to “Azure” and the comment to “Azure models” matches the azure/... model prefix pattern and overall branding. No issues.

docs/integrations/langchain-sdk.mdx (1)

221-238: Azure direct-key headings consistent with new naming

Updating the headings to “Using Azure with direct Azure key” keeps terminology consistent with the rest of the docs while leaving the actual LangChain examples unchanged. Looks good.

Also applies to: 269-288

transports/changelog.md (1)

1-2: Changelog entry for Azure Anthropic support is clear

Adding a separate bullet for “feat: added support for Anthropic models in Azure” is clear and matches the feature scope of this PR.

ui/lib/constants/logs.ts (1)

42-59: Azure provider label now matches global branding

Updating the azure label to “Azure” keeps the UI consistent with the rest of the documentation and provider naming. Mapping and helper logic remain unchanged.

docs/integrations/openai-sdk.mdx (2)

99-104: LGTM on branding update.


141-146: LGTM on branding update.

docs/apis/openapi.json (1)

1759-1801: Good: generalized wording for deployments endpoint.

You updated summary/description and the param to “Deployment ID”. Suggest applying the same generic param description across all other deployments endpoints for consistency.

docs/features/keys-management.mdx (1)

198-202: LGTM on Azure heading rename.

core/changelog.md (1)

1-2: Changelog entries look good.

docs/integrations/genai-sdk.mdx (2)

98-103: LGTM on branding update.


133-136: LGTM on branding update.

docs/quickstart/go-sdk/multimodal.mdx (1)

344-344: LGTM! Documentation branding update.

The provider name change from "Azure OpenAI" to "Azure" aligns with the broader branding updates across the repository and accurately reflects that Azure can now host multiple model types (OpenAI and Anthropic).

core/providers/azure/azure_test.go (1)

32-32: LGTM! Comment branding update.

The comment update aligns with the broader Azure branding changes in the PR.

core/providers/bedrock/bedrock.go (1)

529-541: LGTM! Good refactoring to centralize model detection.

Replacing inline string checks with schemas.IsAnthropicModel() and schemas.IsMistralModel() centralizes the model detection logic, making it more maintainable and consistent across the codebase.

core/internal/testutil/account.go (1)

650-650: LGTM! Comment branding update.

Consistent branding change aligning with the broader Azure terminology updates.

core/schemas/utils.go (1)

1042-1050: LGTM! Clean centralized model type detection.

These helper functions centralize model type detection logic, making it more maintainable and consistent across providers. The implementation is straightforward and appropriate.

Note: The functions use case-sensitive matching, which should be fine given that model identifiers are typically lowercase.

core/chatbot_test.go (2)

779-779: LGTM! Help text branding update.

Consistent update to reflect the broader Azure branding changes.


841-841: LGTM! Startup guidance text update.

Consistent with the Azure branding changes throughout the PR.

framework/streaming/responses.go (1)

686-686: Approve streaming logic for Azure model routing.

The condition correctly routes Azure requests based on model type:

  • Azure with OpenAI models → uses OpenAI-compatible final-chunk path
  • Azure with Anthropic models → uses accumulation path for delta streaming

This aligns with Azure's support for both OpenAI and Anthropic model deployments. The logic appears sound: (provider == schemas.Azure && !schemas.IsAnthropicModel(model)) ensures only non-Anthropic Azure models use the OpenAI path.

Please verify this behavior with both Azure OpenAI and Azure Anthropic streaming requests to ensure correct chunk handling for both model types.

core/providers/azure/types.go (1)

6-6: The API version is correct and appropriately used.

The value "2023-06-01" is Anthropic's documented API version identifier for the anthropic-version HTTP header, not a calendar date indicating staleness. This is the correct version for Anthropic's /v1/messages endpoint and is properly distinguished from Azure's separate api-version query parameter (which uses "2024-10-21" for Azure OpenAI). The implementation correctly sets this header only for Anthropic models.

docs/quickstart/gateway/provider-configuration.mdx (1)

762-779: LGTM! Documentation branding updates are consistent.

The terminology changes from "Azure OpenAI" to "Azure" are applied consistently across the header, description, and UI navigation instructions. This aligns with the broader rebranding effort in this PR.

core/providers/anthropic/chat.go (1)

384-386: LGTM! Function rename is appropriate.

The rename from ToAnthropicChatCompletionRequest to ToAnthropicChatRequest is more concise and better reflects the Anthropic API terminology (Messages API). The function signature and logic remain unchanged.

core/providers/azure/azure.go (4)

63-128: LGTM! Well-structured request routing for Anthropic and OpenAI paths.

The completeRequest method cleanly separates:

  • Authentication: x-api-key + anthropic-version for Anthropic models vs api-key/Bearer for OpenAI
  • URL construction: anthropic/v1/... path for Anthropic vs openai/deployments/... for OpenAI

The deployment parameter addition enables per-request routing decisions.


347-426: LGTM! Clean implementation of Anthropic routing in ChatCompletion.

The implementation correctly:

  • Routes to appropriate request converter based on model type
  • Uses separate API paths for Anthropic (anthropic/v1/messages) vs OpenAI
  • Leverages object pooling for Anthropic responses
  • Populates ExtraFields consistently for both paths

428-514: LGTM! Streaming implementation correctly delegates to appropriate handlers.

The branching logic for Anthropic vs OpenAI streaming is well-implemented:

  • Anthropic models use HandleAnthropicChatCompletionStreaming
  • OpenAI models use HandleOpenAIChatCompletionStreaming
  • The postResponseConverter ensures ModelDeployment is set consistently for both paths

789-800: LGTM! Clean deployment resolution helper.

The getModelDeployment helper provides centralized deployment lookup with clear error handling. The nil check on line 790 provides defensive programming even though validateKeyConfig is typically called first.

core/providers/vertex/vertex.go (2)

279-496: LGTM! ChatCompletion correctly integrates Anthropic model support.

Key improvements:

  • Uses schemas.IsAnthropicModel for consistent model detection
  • Correctly uses renamed ToAnthropicChatRequest converter
  • Centralized error handling via parseVertexError
  • Properly manages Anthropic response pooling with acquire/release pattern
  • Conditionally sets ModelDeployment only when it differs from the requested model

832-944: LGTM! ResponsesStream correctly handles Anthropic models with fallback.

The implementation appropriately:

  • Uses HandleAnthropicResponsesStream for Anthropic models
  • Falls back to ChatCompletionStream for non-Anthropic models, converting via ToChatRequest()
  • Sets a context value to indicate the fallback, allowing downstream handling to adjust if needed
core/providers/anthropic/anthropic.go (6)

30-56: LGTM on the pool renaming.

The pool and accessor functions are correctly renamed from AnthropicChatResponse to AnthropicMessageResponse, aligning with the AnthropicMessageResponse type. The implementation properly resets the struct on acquire and handles nil-checks on release.


318-332: LGTM on the renamed function calls.

The updated function names (ToAnthropicChatRequest, AcquireAnthropicMessageResponse, ReleaseAnthropicMessageResponse) are used correctly and consistently with the pool renames.


380-404: LGTM on the streaming setup.

The headers map is correctly constructed with required Anthropic headers, and passing nil for postResponseConverter is appropriate for the native Anthropic provider since no post-response transformation is needed.


564-570: Good defensive nil-check on postResponseConverter.

The implementation correctly handles the case where postResponseConverter returns nil, logging a warning and skipping the chunk rather than proceeding with a nil response. This prevents potential nil-pointer dereferences downstream.


935-940: LGTM on error parsing helper.

The function correctly extracts status code and body from the response and delegates to NewProviderAPIError for consistent error handling.


638-639: LGTM on pool usage in Responses method.

The renamed pool accessors are used consistently with the non-streaming ChatCompletion method.

Comment thread core/providers/vertex/errors.go
Comment thread core/providers/vertex/vertex.go
Comment thread docs/quickstart/gateway/multimodal.mdx Outdated
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch 2 times, most recently from cc73f7c to c31e74e Compare November 29, 2025 13:13

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/apis/openapi.json (1)

3109-3236: TextCompletionRequest schema requires a non-existent text field.

In TextCompletionRequest, the required array lists "model" and "text", but the actual property is named prompt and there is no text field. This makes the OpenAPI schema formally incorrect for validation and codegen.

Recommend changing the required field to "prompt" (or adding a text property if that was intended).

🧹 Nitpick comments (8)
core/providers/gemini/errors.go (3)

48-48: Remove unnecessary type cast.

The StatusCode() method already returns int, making the explicit cast redundant.

Apply this diff:

-		StatusCode:     schemas.Ptr(int(resp.StatusCode())),
+		StatusCode:     schemas.Ptr(resp.StatusCode()),

39-90: Harmonize error handling between streaming and non-streaming parsers.

The two parsing functions have several inconsistencies that make error behavior unpredictable:

  1. Line 58 vs 84: parseStreamGeminiError uses interface{} for rawResponse, while parseGeminiError uses map[string]interface{}. Consider using the same type for consistency.

  2. Line 60 vs 86: Different error messages for the same unmarshal failure—one uses the constant schemas.ErrProviderResponseUnmarshal, the other uses a literal string "failed to parse error response". Prefer the constant for consistency.

  3. Line 63 vs 89: The streaming error includes the HTTP status code in the message format ("Gemini streaming error (HTTP %d): %v"), but the non-streaming error omits it ("Gemini error: %v"). Including the status code in both improves debuggability.

Example fix for consistency:

 func parseGeminiError(providerName schemas.ModelProvider, resp *fasthttp.Response) *schemas.BifrostError {
 	body := append([]byte(nil), resp.Body()...)
 
 	// Try to parse as JSON first
 	var errorResp GeminiGenerationError
 	if err := sonic.Unmarshal(body, &errorResp); err == nil {
 		bifrostErr := &schemas.BifrostError{
 			IsBifrostError: false,
 			StatusCode:     schemas.Ptr(resp.StatusCode()),
 			Error: &schemas.ErrorField{
 				Code:    schemas.Ptr(strconv.Itoa(errorResp.Error.Code)),
 				Message: errorResp.Error.Message,
 			},
 		}
 		return bifrostErr
 	}
 
-	var rawResponse map[string]interface{}
+	var rawResponse interface{}
 	if err := sonic.Unmarshal(body, &rawResponse); err != nil {
-		return providerUtils.NewBifrostOperationError("failed to parse error response", err, providerName)
+		return providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, providerName)
 	}
 
-	return providerUtils.NewBifrostOperationError(fmt.Sprintf("Gemini error: %v", rawResponse), fmt.Errorf("HTTP %d", resp.StatusCode()), providerName)
+	return providerUtils.NewBifrostOperationError(fmt.Sprintf("Gemini error (HTTP %d): %v", resp.StatusCode(), rawResponse), fmt.Errorf("HTTP %d", resp.StatusCode()), providerName)
 }

39-90: Consider consolidating duplicate error parsing logic.

Both parseStreamGeminiError and parseGeminiError follow nearly identical logic with only minor differences. Extracting a common helper would reduce duplication and simplify maintenance.

Example refactored approach:

// parseGeminiErrorInternal is a common helper for both streaming and non-streaming
func parseGeminiErrorInternal(providerName schemas.ModelProvider, resp *fasthttp.Response, isStreaming bool) *schemas.BifrostError {
	body := append([]byte(nil), resp.Body()...)
	
	// Try to parse as JSON first
	var errorResp GeminiGenerationError
	if err := sonic.Unmarshal(body, &errorResp); err == nil {
		bifrostErr := &schemas.BifrostError{
			IsBifrostError: false,
			StatusCode:     schemas.Ptr(resp.StatusCode()),
			Error: &schemas.ErrorField{
				Code:    schemas.Ptr(strconv.Itoa(errorResp.Error.Code)),
				Message: errorResp.Error.Message,
			},
		}
		return bifrostErr
	}
	
	var rawResponse interface{}
	if err := sonic.Unmarshal(body, &rawResponse); err != nil {
		return providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, providerName)
	}
	
	errorType := "Gemini error"
	if isStreaming {
		errorType = "Gemini streaming error"
	}
	return providerUtils.NewBifrostOperationError(fmt.Sprintf("%s (HTTP %d): %v", errorType, resp.StatusCode(), rawResponse), fmt.Errorf("HTTP %d", resp.StatusCode()), providerName)
}

func parseStreamGeminiError(providerName schemas.ModelProvider, resp *fasthttp.Response) *schemas.BifrostError {
	return parseGeminiErrorInternal(providerName, resp, true)
}

func parseGeminiError(providerName schemas.ModelProvider, resp *fasthttp.Response) *schemas.BifrostError {
	return parseGeminiErrorInternal(providerName, resp, false)
}
core/providers/bedrock/bedrock.go (1)

526-545: Make Anthropic/Mistral detection resilient when deployment is empty

Right now the switch uses only deployment:

switch {
case schemas.IsAnthropicModel(deployment):
    ...
case schemas.IsMistralModel(deployment):
    ...
default:
    return nil, providerUtils.NewConfigurationError(
        fmt.Sprintf("unsupported model type for text completion: %s", request.Model),
        providerName,
    )
}

However, getModelPath can return an empty deployment when there is no BedrockKeyConfig.Deployments entry or ARN configured, while request.Model may still be a full Bedrock model id (e.g., an Anthropic or Mistral model). In that situation we’d now treat a potentially valid model as “unsupported” purely because deployment is blank.

To keep detection robust (and likely preserve existing behaviour when deployments aren’t configured), consider deriving a single identifier that falls back to request.Model:

-    // Handle model-specific response conversion
-    var bifrostResponse *schemas.BifrostTextCompletionResponse
-    switch {
-    case schemas.IsAnthropicModel(deployment):
+    // Handle model-specific response conversion
+    var bifrostResponse *schemas.BifrostTextCompletionResponse
+    modelIdentifier := deployment
+    if modelIdentifier == "" {
+        modelIdentifier = request.Model
+    }
+    switch {
+    case schemas.IsAnthropicModel(modelIdentifier):
         var response BedrockAnthropicTextResponse
         if err := sonic.Unmarshal(body, &response); err != nil {
             return nil, providerUtils.NewBifrostOperationError("error parsing anthropic response", err, providerName)
         }
         bifrostResponse = response.ToBifrostTextCompletionResponse()
 
-    case schemas.IsMistralModel(deployment):
+    case schemas.IsMistralModel(modelIdentifier):
         var response BedrockMistralTextResponse
         if err := sonic.Unmarshal(body, &response); err != nil {
             return nil, providerUtils.NewBifrostOperationError("error parsing mistral response", err, providerName)
         }
         bifrostResponse = response.ToBifrostTextCompletionResponse()

This keeps the new centralized predicates (IsAnthropicModel / IsMistralModel) while avoiding unexpected “unsupported model type” errors when deployments aren’t set up but the model name alone is sufficient to infer the family.

docs/apis/openapi.json (1)

1757-1801: Azure deployment endpoints wording is mostly consistent; check remaining “Azure deployment ID” mentions.

The updated summaries/descriptions for the /openai/deployments/{deployment-id}/... endpoints look good and match the new “OpenAI-compatible” branding. However, only the completions path’s parameter description was normalized to “Deployment ID”, while the others still say “Azure deployment ID”. Consider standardizing the deployment-id parameter description across these endpoints (either all “Deployment ID” or all “Azure deployment ID”) to avoid small but confusing wording differences.

Also applies to: 1879-1923, 2001-2045, 2113-2151, 2222-2263, 2330-2370

core/providers/vertex/errors.go (1)

10-37: Centralized Vertex error parsing looks correct and uses providerName consistently.

The new parseVertexError covers OpenAI-style, array-of-Vertex, single-Vertex, and validation error formats, and now correctly passes providerName into the various New*Error helpers instead of hardcoding the provider. The slice vs single vertexErr shadowing is a little hard to follow but functionally fine; refactoring the inner one to a different name would slightly improve readability if you touch this again.

core/providers/azure/azure.go (2)

297-305: Consider using getModelDeployment in TextCompletionStream for consistency.

TextCompletionStream still does:

deployment := key.AzureKeyConfig.Deployments[request.Model]
if deployment == "" {
    return nil, providerUtils.NewConfigurationError(
        fmt.Sprintf("deployment not found for model %s", request.Model),
        provider.GetProviderKey(),
    )
}

While the rest of the code now centralizes this logic in getModelDeployment. It’s not wrong, but using getModelDeployment here as well would keep configuration error handling uniform and reduce duplication:

- deployment := key.AzureKeyConfig.Deployments[request.Model]
- if deployment == "" {
-     return nil, providerUtils.NewConfigurationError(
-         fmt.Sprintf("deployment not found for model %s", request.Model),
-         provider.GetProviderKey(),
-     )
- }
+ deployment, cfgErr := provider.getModelDeployment(key, request.Model)
+ if cfgErr != nil {
+     return nil, cfgErr
+ }

63-72: <!-- [scratchpad_start]
[task verify_review_comment 1/1]
[observations]
FINAL SUMMARY:

  • 9 total IsAnthropicModel calls
  • 3 PROBLEMS (using deployment when shouldn't):
    • Line 84: completeRequest
    • Line 449: ChatCompletionStream
    • Line 622: ResponsesStream
  • 6 CORRECT (using request.Model):
    • Lines 361, 377, 399: ChatCompletion/ChatCompletionStream path/body setup
    • Lines 533, 553, 575: Responses/ResponsesStream path/body setup

[review comment accuracy assessment]
The review's CORE RECOMMENDATION is CORRECT:
✓ Line 84 (completeRequest) should use model parameter instead of deployment
✓ The principle of using canonical model string is sound
✓ The risk explanation is accurate
✓ The diff example is correct for line 84

The review's SCOPE/REFERENCES are INCOMPLETE/INACCURATE:
✗ Missing ChatCompletionStream (line 449) from analysis
✗ "Also applies to" ranges don't clearly map to actual problems
✗ Includes Embedding (701-724) which has no IsAnthropicModel
✗ The ranges seem to point to functions rather than specific problem lines

[decision]
The review comment is FUNDAMENTALLY CORRECT but has:

  • Correct problem identification at line 84
  • Correct solution suggested
  • INCOMPLETE scope specification in "Also applies to"
  • Missing identification of line 449 and clear specification of line 622

This should be tagged as because while the main recommendation is sound, the scope is incomplete and could mislead the developer about all the places needing fixes.

Actually, wait - let me reconsider. The review says:
"In ChatCompletionStream and ResponsesStream, keep the branch on schemas.IsAnthropicModel(request.Model)"

This could mean:

  1. These functions SHOULD already be using request.Model (they're not - they use deployment at lines 449, 622)
  2. Or it could mean after the fix to completeRequest, ensure these also use request.Model

Looking at the code flow:

  • ChatCompletionStream/ResponsesStream call completeRequest with the model parameter
  • So if completeRequest is fixed to use model, that part is covered
  • But ChatCompletionStream/ResponsesStream ALSO have their own IsAnthropicModel branches at 449 and 622 that are independent

The review says "keep the branch on request.Model" - this suggests those functions should be using request.Model for their own branches, not relying solely on completeRequest.

So the review is actually:

  1. Suggesting to fix line 84 in completeRequest
  2. Saying ChatCompletionStream/ResponsesStream should KEEP their request.Model branches
  3. But they don't currently have request.Model branches - they have deployment branches!

This is a DISCREPANCY in the review comment. It says to "keep" something that doesn't exist.

Actually, maybe I need to re-read more carefully...

"In ChatCompletionStream and ResponsesStream, keep the branch on schemas.IsAnthropicModel(request.Model) (as you already do for path/body), and let completeRequest rely on that model argument."

This suggests:

  • ChatCompletionStream/ResponsesStream already use request.Model for path/body (TRUE - lines 361, 377, 399, 533, 553, 575)
  • They should ALSO use request.Model for the authentication/url branch (currently they use deployment at 449, 622)
  • The word "keep" is misleading - it should be "change" or "align"

[CONCLUSION]
The review is PARTIALLY INCORRECT:
✓ Line 84 fix is correct
✗ Says to "keep" something that doesn't match current code
✓ The principle is correct but execution/wording is off
✗ "Also applies to" is incomplete/inaccurate

This should be marked as due to inconsistency in language and incomplete scope.

Hmm, but actually let me reconsider one more time. Looking at the actual code structure:

ChatCompletionStream has:

  1. Line 449: IsAnthropicModel(deployment) for setting auth headers and URL
  2. Lines 361, 377, 399: IsAnthropicModel(request.Model) for setting path and body

So there ARE two different branches, one for auth/URL setup and one for path/body setup!

The review is saying:

  • The path/body setup (lines 361, 377, 399) correctly uses request.Model
  • The auth/URL setup (line 449) incorrectly uses deployment
  • They should be aligned

So the "keep the branch on request.Model" means keep BOTH branches on request.Model, not just the path/body ones.

This makes more sense! The review is saying:

  • completeRequest should use model parameter for auth/URL setup (currently uses deployment at line 84)
  • ChatCompletionStream/ResponsesStream should use request.Model for auth/URL setup (currently use deployment at lines 449, 622)
  • This ensures consistency with their own path/body setup logic

[FINAL VERDICT]
The review is SUBSTANTIALLY CORRECT:
✓ Core problem identified correctly
✓ Solution is sound
✓ Risk explanation is accurate
✗ "Also applies to" is poorly specified and incomplete (missing line 449, unclear line ranges)
✓ The wording "keep" is slightly misleading but can be understood in context

Classification: The core recommendation is correct and actionable. The scope/references are incomplete but not fundamentally wrong.

[DECISION - use optional_refactors_recommended because]:

  1. The review suggests refactoring for consistency and safety
  2. It's not a critical bug fix but a best practice recommendation
  3. No current bugs are reported, just a risk mitigation strategy
  4. The "Also applies to" incompleteness doesn't negate the core recommendation

Actually, re-reading the review tags... it has and

So the review is categorizing this as a recommended refactor (not a bug fix), which aligns with my assessment.

The question is: is this review comment CORRECT or does it need adjustment?

ASSESSMENT:

  • The main recommendation (line 84) is correct
  • The underlying principle is correct
  • The "Also applies to" is incomplete but not disqualifying
  • The review could be improved but is fundamentally sound

I should mark this as since:

  1. The recommendation is correct
  2. No critical issues beyond what's stated
  3. The incomplete scope doesn't make the recommendation wrong, just incomplete

But I should also note the incompleteness in my rewrite.
</scratchpad_end] -->

Perfect! Now I have a complete understanding of the issue. Let me generate the rewritten review comment based on my verification findings.


Align Anthropic/OpenAI branching on the canonical model string consistently across all functions.

Right now, three functions use deployment for the Anthropic/OpenAI branch decision when they should use the canonical model string:

  • completeRequest (line 84) uses schemas.IsAnthropicModel(deployment) instead of the model parameter
  • ChatCompletionStream (line 449) uses schemas.IsAnthropicModel(deployment) instead of request.Model
  • ResponsesStream (line 622) uses schemas.IsAnthropicModel(deployment) instead of request.Model

Meanwhile, their path/body setup logic already correctly branches on schemas.IsAnthropicModel(request.Model) (lines 361, 377, 399, 533, 553, 575).

If an Azure deployment name doesn't encode the model type clearly (e.g., my-claude-prod), these mismatches can cause subtle routing bugs: you can end up using an Anthropic path but the OpenAI-style auth branch, or vice versa.

To avoid this, base all Anthropic/OpenAI decisions consistently on the canonical model string:

  • In completeRequest, use schemas.IsAnthropicModel(model) instead of deployment.
  • In ChatCompletionStream and ResponsesStream, use schemas.IsAnthropicModel(request.Model) for the auth/URL setup (lines 449, 622) to match their existing path/body setup.

For example in completeRequest:

-func (provider *AzureProvider) completeRequest(
+func (provider *AzureProvider) completeRequest(
     ctx context.Context,
     jsonData []byte,
     path string,
     key schemas.Key,
     deployment string,
     model string,
     requestType schemas.RequestType,
 ) ([]byte, string, time.Duration, *schemas.BifrostError) {
-    var url string
-    if schemas.IsAnthropicModel(deployment) {
+    var url string
+    if schemas.IsAnthropicModel(model) {
         // Anthropic-on-Azure branch...
     } else {
         // OpenAI-on-Azure branch...
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf4722e and c31e74e.

📒 Files selected for processing (39)
  • core/bifrost.go (2 hunks)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (1 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/gemini/errors.go (2 hunks)
  • core/providers/gemini/gemini.go (0 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/schemas/utils.go (1 hunks)
  • core/utils.go (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/bifrost-http/lib/config.go (4 hunks)
  • transports/changelog.md (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • core/providers/utils/utils.go
  • core/providers/gemini/gemini.go
✅ Files skipped from review due to trivial changes (2)
  • docs/integrations/genai-sdk.mdx
  • transports/bifrost-http/integrations/router.go
🚧 Files skipped from review as they are similar to previous changes (20)
  • docs/integrations/what-is-an-integration.mdx
  • core/schemas/utils.go
  • core/providers/azure/azure_test.go
  • docs/integrations/litellm-sdk.mdx
  • core/internal/testutil/account.go
  • core/chatbot_test.go
  • core/providers/openai/chat.go
  • framework/streaming/responses.go
  • transports/changelog.md
  • core/providers/anthropic/chat.go
  • docs/integrations/openai-sdk.mdx
  • docs/features/keys-management.mdx
  • ui/lib/constants/logs.ts
  • ui/app/workspace/logs/views/logChatMessageView.tsx
  • docs/quickstart/gateway/multimodal.mdx
  • docs/quickstart/go-sdk/multimodal.mdx
  • core/changelog.md
  • ui/README.md
  • ui/app/workspace/logs/views/logDetailsSheet.tsx
  • docs/features/unified-interface.mdx
🧰 Additional context used
🧬 Code graph analysis (6)
core/utils.go (2)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
core/schemas/provider.go (1)
  • NetworkConfig (36-44)
core/providers/vertex/errors.go (4)
core/providers/vertex/vertex.go (1)
  • VertexError (25-31)
core/providers/vertex/types.go (1)
  • VertexValidationError (154-161)
core/providers/utils/utils.go (2)
  • NewBifrostOperationError (449-460)
  • NewProviderAPIError (464-479)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (29-29)
transports/bifrost-http/lib/config.go (2)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
core/schemas/provider.go (1)
  • NetworkConfig (36-44)
core/providers/gemini/errors.go (5)
core/providers/gemini/types.go (1)
  • GeminiGenerationError (1353-1365)
core/schemas/utils.go (1)
  • Ptr (16-18)
core/utils.go (1)
  • Ptr (50-52)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (29-29)
core/providers/bedrock/bedrock.go (3)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/bedrock/types.go (1)
  • BedrockAnthropicTextResponse (235-239)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/providers/anthropic/anthropic.go (4)
core/providers/anthropic/types.go (1)
  • AnthropicMessageResponse (272-281)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/schemas/bifrost.go (5)
  • ModelProvider (32-32)
  • BifrostResponseExtraFields (284-293)
  • RequestType (83-83)
  • BifrostStream (318-325)
  • BifrostError (353-362)
core/providers/utils/utils.go (4)
  • NewBifrostOperationError (449-460)
  • ReleaseStreamingResponse (767-774)
  • ProcessAndSendError (607-653)
  • CreateBifrostChatCompletionChunkResponse (686-715)
🔇 Additional comments (23)
core/bifrost.go (1)

2025-2067: LGTM! Improved observability and terminology.

The debug log at line 2025 adds useful visibility into backoff timing, and the terminology change from "retries" to "attempts" at line 2067 is more accurate since the counter includes the initial attempt.

core/providers/azure/types.go (2)

3-3: Good generalization of comment.

The updated comment "Azure API version" correctly reflects that this constant now applies to multiple model types in Azure, not just OpenAI.


6-6: API version "2023-06-01" is correct and documented in official Anthropic sources.

The verification confirms that "2023-06-01" is a valid default API version for Anthropic Claude models, as documented in official Anthropic documentation including the Messages API, models list, and versioning guides. The constant is properly defined.

docs/integrations/langchain-sdk.mdx (1)

221-238: Azure direct-key examples text change looks good.

Renaming the comments from “Azure OpenAI” to “Azure” in both Python and JavaScript examples aligns with the new branding and doesn’t affect usage of AzureChatOpenAI or configuration.

Also applies to: 269-288

docs/integrations/anthropic-sdk.mdx (1)

104-116: Azure model examples label change is consistent.

Updating the comments from “Azure OpenAI models” to “Azure models” matches the broader terminology shift and leaves the Anthropic SDK usage and model prefixes intact.

Also applies to: 151-163

docs/quickstart/go-sdk/provider-configuration.mdx (1)

272-304: Azure Go SDK provider example is consistent with the new Azure config shape.

The Azure snippet correctly uses schemas.Azure and AzureKeyConfig with endpoint, deployments, and APIVersion via bifrost.Ptr. This matches how other providers (Bedrock, Vertex) are configured and should compile as-is when imports are wired up in a real project.

docs/quickstart/gateway/provider-configuration.mdx (1)

762-779: Azure provider-auth docs now match the new naming and config shape.

Renaming the section and text from “Azure OpenAI” to “Azure” aligns with how the provider is modeled (provider: "azure" and azure_key_config) and keeps the API/config examples accurate.

core/providers/vertex/vertex.go (8)

299-336: LGTM! Anthropic model detection and request conversion.

The use of schemas.IsAnthropicModel(deployment) for routing and anthropic.ToAnthropicChatRequest for request conversion aligns with the centralized predicate and renamed function. The anthropic_version default and model field deletion for Vertex Anthropic API are correctly handled.


373-396: LGTM! Model-based URL routing for chat completion.

The URL construction logic correctly routes:

  • Anthropic models → publishers/anthropic/models/{model}:rawPredict
  • Mistral models → publishers/mistralai/models/{model}:streamRawPredict
  • Others → OpenAPI endpoint for Gemini models

440-495: LGTM! Anthropic response handling with ModelDeployment population.

The response handling correctly uses AcquireAnthropicMessageResponse/ReleaseAnthropicMessageResponse from the pool, and conditionally sets ModelDeployment when it differs from the requested model. Both Anthropic and non-Anthropic paths consistently populate extra fields.


519-524: LGTM! Post-response converter for streaming.

The postResponseConverter closure correctly captures deployment and conditionally sets ModelDeployment for streaming responses.


686-727: LGTM! Responses method Anthropic path configuration validation.

The Anthropic path in Responses correctly validates VertexKeyConfig, projectID, and region before making requests. The request body construction properly handles anthropic_version defaults.


1064-1066: LGTM! Embedding path ModelDeployment population.

Consistent with other methods, the Embedding path now sets ModelDeployment when it differs from the requested model.


622-639: Based on my verification of the complete authentication flow, I can now provide the rewritten review comment.

Auth flow for Mistral models in ChatCompletionStream is correct; authHeader is properly set via OAuth2 token.

The reviewer's concern appears to be based on a misreading of the code flow. While authHeader is declared as nil at line 603, the logic at lines 641-656 ensures it gets properly set for Mistral models. Specifically:

  1. Mistral models do not set authQuery (line 605 remains empty after the Mistral branch at lines 622-628)
  2. At line 641, since authQuery is empty for Mistral, the else branch executes (line 643)
  3. OAuth2 token is obtained (lines 645-651) and authHeader is set with Bearer token (lines 653-655)
  4. The populated authHeader is then passed to HandleOpenAIChatCompletionStreaming (line 669), which properly copies it to request headers (line 745-748 in openai.go)

This is the intended behavior—Mistral models use OAuth2 bearer token authentication rather than API key query parameters. No changes are needed.


935-943: Based on my verification of the codebase, I can now provide the final assessment:

Context key is properly isolated from post-hook interference; no unintended side effects occur.

The context value BifrostContextKeyIsResponsesToChatCompletionFallback is set at line 936 in vertex.go and passed to ChatCompletionStream. Within the OpenAI provider's ChatCompletionStream implementation (openai.go:727-733), the key is read once into a local variable isResponsesToChatCompletionsFallback. This flag controls response transformation logic that completes before post-hooks are invoked. Post-hooks receive the final transformed result through ProcessAndSendResponse, not the intermediate flag. While the context is inherited by post-hooks through the plugin system (by design for full request lifecycle visibility), they cannot interfere with the response transformation that has already occurred. Context key leakage to post-hooks follows the established pattern used for all internal bifrost context keys and is intentional.

core/providers/anthropic/anthropic.go (8)

30-56: LGTM! Pool and accessor renames.

The pool rename from anthropicChatResponsePool to anthropicMessageResponsePool and corresponding Acquire/Release function renames are consistent and properly exported for external use (e.g., by Vertex provider).


402-404: Clarify: nil passed for postResponseConverter.

When calling HandleAnthropicChatCompletionStreaming from the Anthropic provider's own ChatCompletionStream, nil is passed for postResponseConverter. This is intentional since no deployment mapping is needed for direct Anthropic API calls. The nil-safety check at lines 564-570 handles this correctly.


417-420: LGTM! Parameter renames and new postResponseConverter.

The providerTypeproviderName rename improves clarity. The new postResponseConverter parameter enables Vertex and other providers to inject deployment metadata into streaming responses.


564-570: LGTM! Nil-safe postResponseConverter invocation.

The nil check before invoking postResponseConverter and the warning log when it returns nil prevent panics and provide debugging visibility.


685-708: LGTM! ResponsesStream refactored to use shared handler.

The ResponsesStream method now builds headers explicitly and delegates to HandleAnthropicResponsesStream, reducing code duplication and enabling reuse by other providers like Vertex.


711-725: LGTM! HandleAnthropicResponsesStream function signature.

The new shared streaming function mirrors HandleAnthropicChatCompletionStreaming with appropriate parameter types (BifrostResponsesStreamResponse instead of BifrostChatResponse for the converter).


836-838: Minor: modelName extracted from event.Message only once.

The modelName is captured only on the first event.Message that has a model. This is correct behavior for SSE streams where the model is typically only in message_start. No issue.


876-878: LGTM! Raw response only on last chunk of event batch.

The condition i == len(responses)-1 ensures raw response is attached only to the final chunk when multiple responses are emitted from a single SSE event, avoiding duplicate raw data.

Comment thread core/providers/anthropic/anthropic.go
Comment thread core/providers/azure/azure.go
Comment thread core/providers/vertex/vertex.go
Comment thread core/utils.go
Comment thread transports/bifrost-http/lib/config.go Outdated
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch 3 times, most recently from 5e5008a to 04cf53b Compare November 29, 2025 13:50
Comment thread transports/bifrost-http/lib/config.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
docs/quickstart/gateway/multimodal.mdx (1)

288-290: Consolidation resolves the past inconsistency—verify unified-interface.mdx is accurate.

This change removes the provider capability table and centralizes it in unified-interface.mdx, which is a good documentation pattern to prevent future drift. This addresses the inconsistency flagged in the previous review about Azure TTS (✅ vs ❌ across pages).

However, ensure that unified-interface.mdx has the correct and complete provider capability matrix, especially the Azure TTS capability status.

#!/bin/bash
# Verify that unified-interface.mdx contains a complete provider capability matrix with Azure TTS information
# Check for the presence of Azure row and TTS capability indicator
grep -n -A 50 -B 5 "Azure" docs/features/unified-interface.mdx | grep -A 50 -B 5 "TTS\|Text-to-Speech\|Speech" || echo "No explicit Azure TTS reference found; manual review recommended"

# Also check the overall structure of the provider matrix
head -100 docs/features/unified-interface.mdx | tail -50
core/providers/anthropic/anthropic.go (1)

901-904: Inconsistent error handling: missing defensive else block.

Unlike HandleAnthropicChatCompletionStreaming (lines 599-607), this function lacks an else block to emit a final chunk with usage when the scanner completes without error but also without receiving an explicit message_stop event. While Anthropic's API should always send message_stop, the defensive fallback in the chat completion handler provides better resilience against unexpected stream terminations.

Consider adding the defensive else block for consistency:

 if err := scanner.Err(); err != nil {
     logger.Warn(fmt.Sprintf("Error reading %s stream: %v", providerName, err))
     providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ResponsesStreamRequest, providerName, modelName, logger)
+} else {
+    // Defensive fallback: emit final chunk if stream ended without explicit message_stop
+    // This mirrors HandleAnthropicChatCompletionStreaming behavior (lines 602-607)
+    if usage != nil {
+        finalResponse := &schemas.BifrostResponsesStreamResponse{
+            Response: &schemas.BifrostResponsesResponse{
+                Usage: usage,
+            },
+            ExtraFields: schemas.BifrostResponseExtraFields{
+                RequestType:    schemas.ResponsesStreamRequest,
+                Provider:       providerName,
+                ModelRequested: modelName,
+                ChunkIndex:     chunkIndex,
+                Latency:        time.Since(startTime).Milliseconds(),
+            },
+        }
+        ctx = context.WithValue(ctx, schemas.BifrostContextKeyStreamEndIndicator, true)
+        providerUtils.ProcessAndSendResponse(ctx, postHookRunner, providerUtils.GetBifrostResponseForStreamResponse(nil, nil, finalResponse, nil, nil), responseChan)
+    }
 }
🧹 Nitpick comments (7)
docs/integrations/openai-sdk.mdx (1)

319-320: Confirm Azure client + header names still match backend expectations

The text now generically says “For Azure, you can use the AzureOpenAI client… The x-bf-azure-endpoint header is required…”. That’s correct as long as:

  • The backend still expects x-bf-azure-endpoint for Azure traffic, and
  • AzureOpenAI remains the recommended client for this integration.

Please double-check that these names match the current Azure provider implementation and any new Anthropic-on-Azure routing logic added in this PR.

docs/apis/openapi.json (1)

1759-1788: Align deployment endpoint descriptions and parameter wording

The summaries/descriptions for all /openai/deployments/{deployment-id}/… routes now use “OpenAI Compatible …” phrasing, which is consistent with the rest of the spec. However:

  • /openai/deployments/{deployment-id}/completions describes the path parameter as “Deployment ID”.
  • The other deployment endpoints (chat, responses, embeddings, audio/speech, audio/transcriptions) still describe it as “Azure deployment ID”.

Consider standardizing this wording across all deployment endpoints—either all generic (“Deployment ID”) or explicitly Azure-specific (“Azure deployment ID”) depending on the intended scope of these routes. That will avoid confusion for users integrating against the OpenAPI document.

Also applies to: 1881-1911, 2003-2032, 2115-2145, 2224-2236, 2332-2344

core/providers/vertex/errors.go (1)

12-30: Variable shadowing: vertexErr is redeclared in inner scope.

On line 12, vertexErr is declared as []VertexError, but on line 17, it's redeclared as VertexError (singular). While this compiles and works correctly due to Go's scoping rules, it reduces readability and could cause confusion during maintenance.

Consider renaming to clarify intent:

 func parseVertexError(providerName schemas.ModelProvider, resp *fasthttp.Response) *schemas.BifrostError {
 	var openAIErr schemas.BifrostError
-	var vertexErr []VertexError
+	var vertexErrs []VertexError
 	if err := sonic.Unmarshal(resp.Body(), &openAIErr); err != nil || openAIErr.Error == nil {
 		// Try Vertex error format if OpenAI format fails or is incomplete
-		if err := sonic.Unmarshal(resp.Body(), &vertexErr); err != nil {
+		if err := sonic.Unmarshal(resp.Body(), &vertexErrs); err != nil {
 			//try with single Vertex error format
 			var vertexErr VertexError

And update line 31-32 accordingly:

-		if len(vertexErr) > 0 {
-			return providerUtils.NewProviderAPIError(vertexErr[0].Error.Message, nil, resp.StatusCode(), providerName, nil, nil)
+		if len(vertexErrs) > 0 {
+			return providerUtils.NewProviderAPIError(vertexErrs[0].Error.Message, nil, resp.StatusCode(), providerName, nil, nil)
core/providers/azure/azure.go (2)

361-381: Inconsistent model detection: uses request.Model here but deployment in streaming paths.

In ChatCompletion, the Anthropic model check on lines 361 and 377 uses request.Model, but ChatCompletionStream (line 449) uses deployment. Since deployment is the actual Azure deployment name containing the model identifier (e.g., "claude-3-5-sonnet-20241022"), while request.Model is the user-facing alias, using request.Model could fail if the alias doesn't contain "claude" or "anthropic."

For consistency and reliability, consider using deployment for all model-family checks:

-		func() (any, error) {
-			if schemas.IsAnthropicModel(request.Model) {
+		func() (any, error) {
+			if schemas.IsAnthropicModel(deployment) {
 				reqBody := anthropic.ToAnthropicChatRequest(request)

And similarly for line 377:

 	var path string
-	if schemas.IsAnthropicModel(request.Model) {
+	if schemas.IsAnthropicModel(deployment) {
 		path = "anthropic/v1/messages"

And response parsing at line 399:

-	if schemas.IsAnthropicModel(request.Model) {
+	if schemas.IsAnthropicModel(deployment) {
 		anthropicResponse := anthropic.AcquireAnthropicMessageResponse()

Based on learnings from this PR, the deployment variable contains the actual model identifier needed for routing decisions.


533-557: Same inconsistency in Responses method.

Lines 533 and 553 use request.Model for model detection, but should use deployment for consistency with streaming paths.

-		func() (any, error) {
-			if schemas.IsAnthropicModel(request.Model) {
+		func() (any, error) {
+			if schemas.IsAnthropicModel(deployment) {
 	var path string
-	if schemas.IsAnthropicModel(request.Model) {
+	if schemas.IsAnthropicModel(deployment) {
 		path = "anthropic/v1/messages"
core/providers/anthropic/anthropic.go (2)

583-583: Consider using utility function for raw response check.

For consistency with HandleAnthropicResponsesStream (line 875-876), consider using providerUtils.ShouldSendBackRawResponse(ctx, sendBackRawResponse) instead of directly checking sendBackRawResponse. The utility function properly checks both the context and provider settings.

Apply this diff:

-if sendBackRawResponse {
+if providerUtils.ShouldSendBackRawResponse(ctx, sendBackRawResponse) {
     response.ExtraFields.RawResponse = eventData
 }

836-838: Consider aligning modelName assignment pattern.

The modelName assignment only sets the value once (when empty), whereas HandleAnthropicChatCompletionStreaming (line 549) overwrites it each time. While this difference may be intentional for the Responses API, consider documenting the reasoning or aligning the behavior for consistency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c31e74e and 04cf53b.

📒 Files selected for processing (40)
  • core/bifrost.go (2 hunks)
  • core/bifrost_test.go (2 hunks)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (1 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/gemini/errors.go (2 hunks)
  • core/providers/gemini/gemini.go (0 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/schemas/utils.go (1 hunks)
  • core/utils.go (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/bifrost-http/lib/config.go (4 hunks)
  • transports/changelog.md (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • core/providers/gemini/gemini.go
  • core/providers/utils/utils.go
✅ Files skipped from review due to trivial changes (1)
  • transports/bifrost-http/integrations/router.go
🚧 Files skipped from review as they are similar to previous changes (20)
  • docs/quickstart/go-sdk/multimodal.mdx
  • docs/integrations/anthropic-sdk.mdx
  • ui/app/workspace/logs/views/logChatMessageView.tsx
  • docs/integrations/litellm-sdk.mdx
  • docs/features/keys-management.mdx
  • docs/quickstart/gateway/provider-configuration.mdx
  • core/providers/azure/azure_test.go
  • core/providers/gemini/errors.go
  • docs/integrations/what-is-an-integration.mdx
  • core/schemas/utils.go
  • transports/bifrost-http/lib/config.go
  • core/bifrost.go
  • core/providers/azure/types.go
  • docs/integrations/genai-sdk.mdx
  • docs/quickstart/go-sdk/provider-configuration.mdx
  • docs/integrations/langchain-sdk.mdx
  • ui/lib/constants/logs.ts
  • framework/streaming/responses.go
  • transports/changelog.md
  • docs/features/unified-interface.mdx
🧰 Additional context used
🧬 Code graph analysis (9)
core/providers/bedrock/bedrock.go (3)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/bedrock/types.go (1)
  • BedrockAnthropicTextResponse (235-239)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/bifrost_test.go (2)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
core/schemas/provider.go (1)
  • NetworkConfig (36-44)
core/providers/anthropic/chat.go (2)
core/schemas/chatcompletions.go (1)
  • BifrostChatRequest (12-19)
core/providers/anthropic/types.go (1)
  • AnthropicMessageRequest (39-58)
core/providers/vertex/errors.go (4)
core/providers/vertex/vertex.go (1)
  • VertexError (25-31)
core/providers/vertex/types.go (1)
  • VertexValidationError (154-161)
core/providers/utils/utils.go (2)
  • NewBifrostOperationError (449-460)
  • NewProviderAPIError (464-479)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (29-29)
core/providers/openai/chat.go (2)
core/schemas/utils.go (1)
  • IsMistralModel (1048-1050)
core/schemas/models.go (1)
  • Model (109-129)
ui/app/workspace/logs/views/logDetailsSheet.tsx (1)
ui/components/ui/sheet.tsx (1)
  • SheetContent (140-140)
core/utils.go (2)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
core/schemas/provider.go (1)
  • NetworkConfig (36-44)
core/providers/vertex/vertex.go (9)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/providers/anthropic/anthropic.go (3)
  • AcquireAnthropicMessageResponse (45-49)
  • ReleaseAnthropicMessageResponse (52-56)
  • HandleAnthropicResponsesStream (713-908)
core/providers/utils/utils.go (4)
  • HandleProviderResponse (343-387)
  • CheckContextAndGetRequestBody (256-274)
  • NewConfigurationError (435-445)
  • NewBifrostOperationError (449-460)
core/schemas/bifrost.go (7)
  • BifrostResponseExtraFields (284-293)
  • RequestType (83-83)
  • ChatCompletionRequest (89-89)
  • BifrostError (353-362)
  • Vertex (40-40)
  • ResponsesRequest (91-91)
  • BifrostStream (318-325)
core/schemas/chatcompletions.go (1)
  • BifrostChatResponse (26-41)
core/schemas/account.go (2)
  • Key (8-17)
  • VertexKeyConfig (29-35)
core/providers/anthropic/responses.go (1)
  • ToAnthropicResponsesRequest (284-383)
core/providers/vertex/types.go (1)
  • DefaultVertexAnthropicVersion (8-8)
core/providers/azure/azure.go (4)
core/schemas/account.go (2)
  • Key (8-17)
  • AzureKeyConfig (21-25)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • Ptr (16-18)
core/providers/azure/types.go (2)
  • AzureAnthropicAPIVersionDefault (6-6)
  • AzureAPIVersionDefault (4-4)
core/utils.go (1)
  • Ptr (51-53)
🔇 Additional comments (31)
core/internal/testutil/account.go (1)

650-650: LGTM: Comment updated to reflect Azure's expanded model support.

The renaming from "Azure OpenAI" to "Azure" aligns with the PR objective to reflect that Azure now supports both OpenAI and Anthropic models. The comment remains accurate since neither newer OpenAI models nor Anthropic models support text completion.

ui/app/workspace/logs/views/logDetailsSheet.tsx (2)

39-39: Adding gap-4 to SheetContent is a sensible spacing tweak

Using gap-4 with flex-col will space the main sections more evenly without altering logic. This looks good and should improve readability of the sheet content.


55-56: Button onClick block change is formatting-only

The handler still executes handleDelete(log) followed by onOpenChange(false); only indentation/line breaks changed. No behavioral impact here.

core/utils.go (1)

79-83: Backoff jitter now correctly hard‑capped at configured max

The extra clamp on the jittered value ensures calculateBackoff never returns a duration above config.NetworkConfig.RetryBackoffMax, while preserving the existing exponential+jitter behavior below the cap. This matches the intended semantics and is consistent with the updated tests.

core/bifrost_test.go (2)

332-335: Jitter‑bounds test correctly updated for capped backoff

The test now computes maxExpected using min(1.2*baseBackoff, RetryBackoffMax) and documents the cap, which aligns with the current calculateBackoff implementation and keeps the bounds accurate under the max-backoff constraint.


353-356: Max‑backoff test now matches hard‑cap semantics

Asserting backoff <= config.NetworkConfig.RetryBackoffMax (with the updated comment) directly verifies the new guarantee from calculateBackoff and removes the previous allowance for jitter to overshoot the configured maximum.

ui/README.md (1)

84-88: Provider list branding looks consistent

The provider list now uses the generic “Azure” label alongside other providers, matching the rest of the PR’s branding and current provider set.

core/chatbot_test.go (3)

633-641: Synthesis request input remains correct

Using conversationWithSynthesis as the Input for the synthesis request is correct and maintains the intended behavior; this is effectively a formatting-only change.


774-782: Updated Azure provider help text is aligned with new branding

The help section now refers to “Azure (Azure models)”, which is consistent with the provider enum (schemas.Azure) and the broader shift away from “Azure OpenAI” wording.


834-843: Azure env var guidance matches new terminology

The note about AZURE_API_KEY and AZURE_ENDPOINT “for Azure” reflects the updated naming and keeps the CLI guidance clear for users configuring Azure deployments.

docs/integrations/openai-sdk.mdx (2)

93-104: Azure usage example label matches model prefixing

The “# Azure models” label and model="azure/gpt-4o" example are consistent with the provider-prefixed model convention used elsewhere in the docs.


135-145: JS Azure usage example label is consistent

The “// Azure models” comment correctly mirrors the Python example and the model: "azure/gpt-4o" pattern.

core/providers/openai/chat.go (1)

51-51: LGTM – centralized model detection.

Using schemas.IsMistralModel instead of the provider-specific utility aligns with the broader refactor to centralize model-family detection across providers.

core/providers/bedrock/bedrock.go (1)

529-545: LGTM – centralized model detection in TextCompletion.

Using schemas.IsAnthropicModel(deployment) and schemas.IsMistralModel(deployment) aligns with the centralized model-family detection approach. The switch routing logic correctly directs to appropriate response parsers.

core/providers/anthropic/chat.go (1)

384-386: LGTM – function renamed for consistency.

Renaming ToAnthropicChatCompletionRequest to ToAnthropicChatRequest aligns with the naming conventions used elsewhere in the codebase. The implementation remains unchanged.

core/providers/azure/azure.go (3)

63-71: LGTM – completeRequest signature updated for deployment-aware routing.

Adding the deployment parameter allows proper routing based on the actual model identifier rather than the user alias.


83-102: LGTM – Anthropic vs OpenAI header routing.

The routing correctly uses IsAnthropicModel(deployment) to determine whether to use Anthropic-style (x-api-key, anthropic-version) or OpenAI-style (api-key, api-version) authentication. The URL construction appropriately differs between the two paths.


789-799: LGTM – getModelDeployment helper.

The helper correctly resolves the deployment name from the key configuration, returning an error if no mapping is found.

core/providers/vertex/vertex.go (7)

299-301: LGTM – centralized model detection and updated converter.

Using schemas.IsAnthropicModel(deployment) and anthropic.ToAnthropicChatRequest aligns with the centralized approach across providers.


440-440: LGTM – centralized error parsing.

Using parseVertexError(providerName, resp) consolidates error handling logic and ensures consistent error formatting across Vertex response paths.


443-465: LGTM – Anthropic response handling with pooling.

Correctly uses AcquireAnthropicMessageResponse/ReleaseAnthropicMessageResponse for object pooling and conditionally populates ModelDeployment when it differs from the requested model.


519-524: LGTM – postResponseConverter for deployment metadata.

The converter correctly attaches ModelDeployment to streaming responses when the deployment differs from the requested model, ensuring consistent metadata across streaming chunks.


692-812: LGTM – Anthropic Responses implementation.

The implementation correctly:

  • Validates key configuration
  • Converts requests using ToAnthropicResponsesRequest
  • Handles OAuth token authentication
  • Uses centralized error parsing
  • Pools response objects appropriately
  • Attaches deployment metadata conditionally

842-944: LGTM – Anthropic ResponsesStream implementation.

The streaming implementation correctly:

  • Validates configuration before processing
  • Uses ToAnthropicResponsesRequest for request conversion
  • Sets up proper streaming headers and OAuth authentication
  • Attaches deployment metadata via postResponseConverter
  • Falls back to ChatCompletionStream for non-Anthropic models

813-829: Latency is properly preserved in the non-Anthropic Responses fallback path.

The review comment is accurate. In vertex.go lines 813-829, when ChatCompletion() is called, it returns a BifrostChatResponse with ExtraFields.Latency populated (calculated at line 501 of the same file). When ToBifrostResponsesResponse() is called on line 819, the conversion method in core/schemas/mux.go:909 copies the entire ExtraFields struct: responsesResp.ExtraFields = cr.ExtraFields. Only RequestType is then explicitly overwritten (line 910), leaving Latency intact. The subsequent field assignments on lines 820-822 do not overwrite Latency, so it is preserved through to the returned response.

core/providers/anthropic/anthropic.go (6)

30-56: LGTM! Pool and function renaming improves consistency.

The renaming from anthropicChatResponsePool to anthropicMessageResponsePool and the associated acquire/release functions better aligns with Anthropic's message-based API terminology. The implementation correctly maintains the pool pattern and all usages are updated consistently.

Also applies to: 89-89


402-402: LGTM! Post-response converter adds useful extensibility.

The addition of the optional postResponseConverter parameter enables providers (like Azure) to post-process streaming responses. The implementation includes proper nil-safety checks and gracefully handles cases where the converter returns nil by skipping the chunk.

Also applies to: 419-419, 564-570


417-417: LGTM! Parameter rename improves clarity.

The rename from providerType to providerName better reflects that this parameter holds a provider name/identifier rather than a type. All occurrences are updated consistently across both streaming handlers.

Also applies to: 454-454, 456-456, 462-462, 477-477, 556-556, 575-575, 600-601, 603-603, 721-721, 759-759, 761-761, 767-767, 782-782, 855-855, 867-867, 902-903


685-709: LGTM! Good refactoring to shared streaming helper.

The refactoring of ResponsesStream to use the new shared HandleAnthropicResponsesStream function reduces code duplication and improves maintainability. The header construction pattern is consistent with ChatCompletionStream.


711-800: LGTM! Shared streaming handler improves code reuse.

The new HandleAnthropicResponsesStream function successfully extracts common streaming logic, reducing duplication between different streaming implementations. The structure mirrors HandleAnthropicChatCompletionStreaming appropriately.


318-318: Function definition properly renamed and consistent throughout the codebase.

The function definition in core/providers/anthropic/chat.go at line 386 has been correctly renamed to ToAnthropicChatRequest, and no remaining references to the old function name ToAnthropicChatCompletionRequest exist in the codebase. The call sites at lines 318 and 369 in anthropic.go are consistent with the updated definition.

Comment thread core/changelog.md Outdated
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch from 04cf53b to cfc30a7 Compare November 29, 2025 14:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
core/providers/anthropic/anthropic.go (1)

663-709: Responses streaming helper is close, but consider buffer size, EOF fallback, and the unused converter hook.

A few things worth tightening up here:

  1. Scanner buffer sizeHandleAnthropicResponsesStream uses the default bufio.Scanner limit, while the chat helper explicitly bumps it to 10MB. Large SSE data: lines for responses could hit ErrTooLong and surface as generic stream errors instead of cleanly parsed events. Mirroring the chat helper’s scanner.Buffer configuration here would make responses streaming more robust.

  2. Unused postResponseConverter – The function accepts a postResponseConverter func(*schemas.BifrostResponsesStreamResponse) *schemas.BifrostResponsesStreamResponse but never calls it. If other providers start passing a non‑nil converter expecting per‑chunk adjustments, this will silently do nothing. Either wire the converter in next to where you enrich response.ExtraFields (similar to the chat helper), or drop the parameter until it’s needed.

  3. No final usage chunk on clean EOF without isLastChunk – If the stream ends without isLastChunk ever being set (e.g., missing message_stop), the loop exits and scanner.Err() is nil, so no final chunk with accumulated usage and no explicit stream‑end event is emitted—only channel close. This mirrors an earlier review concern for this function. Adding an else branch (like the chat helper now has) to synthesize a final chunk using the accumulated usage and modelName would make this path more defensive.

Also applies to: 713-725, 789-806, 851-904

🧹 Nitpick comments (10)
docs/quickstart/gateway/provider-configuration.mdx (1)

762-779: Azure provider-auth docs align with the new configuration surface, but API version examples could be standardized.

The Azure section correctly reflects the azure_key_config shape (endpoint, deployments, api_version) and the renamed “Azure” provider in the UI. One minor polish item: example API versions now differ between these docs, OpenAPI (2024-02-15-preview), and the default constant (2024-10-21). Consider standardizing to a single recommended example version (with a short note if different versions are needed for different surfaces) to avoid user confusion.

Also applies to: 786-807, 813-836

docs/apis/openapi.json (1)

1758-1802: OpenAI deployment endpoint branding is clearer now; consider tightening Azure-specific wording and version examples.

  • The summaries/response descriptions for /openai/deployments/{deployment-id}/… now correctly describe these as “OpenAI compatible” endpoints, which matches their behavior.
  • For consistency, you may want to either:
    • keep all path‑param descriptions Azure‑specific ("Azure deployment ID"), or
    • generalize them all (as you did for the completions endpoint, now just "Deployment ID"). Right now completions is generic, but chat/responses/embeddings/audio/transcriptions still say “Azure deployment ID”.

Separately, Key.azure_key_config.api_version here uses "2024-02-15-preview" while other docs/examples show "2024-08-01-preview" and the code default is 2024-10-21. Aligning these examples (or briefly noting that multiple versions are valid) would reduce confusion for users copying from the spec.

Also applies to: 1880-1924, 2001-2047, 2113-2153, 2222-2265, 2330-2372, 4359-4381

framework/streaming/responses.go (1)

588-664: Azure Anthropic streams correctly bypass OpenAI-style fast path; validate model identifier source

The updated condition to exclude Azure Anthropic models from the OpenAI-compatible fast path and send them through the accumulator instead is the right direction for using the Anthropic streaming handlers. The final-chunk cleanup happening while the accumulator lock is still held also matches the comment and avoids returning pooled chunks while they may still be accessed.

One thing to double-check: schemas.IsAnthropicModel(model) in this condition must receive the canonical model/deployment identifier (not an arbitrary user alias) for Azure, otherwise Anthropic deployments whose aliases don’t contain claude/anthropic. will still be treated as OpenAI-style and skip accumulation. Please confirm what GetResponseFields is populating as model for Azure Responses streams.

Also applies to: 684-745

core/providers/vertex/errors.go (1)

10-38: Centralized Vertex error parsing looks solid; consider minor readability tweak

The layered fallbacks (OpenAI-style BifrostError[]VertexErrorVertexErrorVertexValidationError) give good coverage and the function now correctly uses the providerName argument for all error constructors.

Minor nit: reusing the identifier vertexErr for both []VertexError and a nested VertexError makes the function slightly harder to read. Renaming the inner one (e.g., singleVertexErr) would clarify the intent without behavior change.

core/providers/azure/azure.go (3)

245-292: TextCompletion deployment resolution and telemetry look consistent

Using getModelDeployment for TextCompletion and wiring the resolved deployment into the path, completeRequest, and ExtraFields.ModelDeployment makes deployment handling explicit and consistent with other methods. This looks correct and improves error reporting when the deployment mapping is missing.


524-602: Responses and ResponsesStream Azure Anthropic routing and metadata propagation look good

For Responses and ResponsesStream:

  • getModelDeployment is used to resolve the deployment once.
  • Anthropic routing is keyed off IsAnthropicModel(deployment) in the streaming path, matching the Chat streaming behavior.
  • Anthropic branches correctly swap to anthropic/v1/messages with x-api-key + anthropic-version and use the shared Anthropic streaming/response handlers.
  • Non-Anthropic branches keep using OpenAI-style openai/deployments/.../responses endpoints with api-version, Bearer/api-key auth, and OpenAI streaming helpers.
  • postResponseConverter ensures ExtraFields.ModelDeployment is consistently set on streaming responses.

Once the non-streaming methods switch their Anthropic checks to deployment as suggested above, Azure’s Anthropic routing will be coherent across all paths.

Also applies to: 610-691


693-748: Embedding and getModelDeployment helpers are straightforward and consistent

Using getModelDeployment for Embedding and wiring the resolved deployment through the URL and ExtraFields.ModelDeployment is consistent with the other methods and avoids silent misconfigurations when a deployment mapping is missing.

getModelDeployment itself defensively checks AzureKeyConfig and the Deployments map and returns a clear configuration error when a model mapping is absent, which is useful for debugging.

Optional: you could reuse getModelDeployment in TextCompletionStream to avoid duplicating the lookup and error message.

Also applies to: 789-800

core/providers/vertex/vertex.go (3)

291-339: Vertex ChatCompletion Anthropic/OpenAPI routing and body shaping look correct

ChatCompletion now:

  • Resolves deployment via getModelDeployment.
  • Uses IsAnthropicModel(deployment) to pick the Anthropic vs OpenAI-style body.
  • Converts Anthropic and non-Anthropic requests into map[string]interface{} for Vertex, adding anthropic_version and stripping model/region for Anthropic bodies.
  • Constructs URLs that correctly distinguish fine-tuned (numeric IDs), Anthropic publisher, Mistral publisher, and OpenAPI endpoints.

This matches the Vertex endpoint layout, and using deployment (not alias) for dispatch is the right choice. The double marshal/unmarshal is already noted in the TODO and is acceptable for now.

Also applies to: 299-337


517-525: Vertex ChatCompletionStream deployment-aware routing and converters look good

The streaming chat path:

  • Resolves deployment once and uses IsAnthropicModel(deployment) to choose Anthropic streaming vs other models.
  • For Anthropic: builds ...:streamRawPredict URLs under the Anthropic publisher, injects anthropic_version and removes model/region from the body, and uses OAuth Bearer auth with the shared Anthropic streaming helper.
  • For non-Anthropic: adds a separate Mistral streamRawPredict branch and otherwise falls back to OpenAPI endpoints, using either API-key query or OAuth Bearer.
  • Uses postRequestConverter to rewrite reqBody.Model = deployment and postResponseConverter to attach ModelDeployment when needed.

This is a clean design and should keep streaming telemetry consistent across deployments.

Also applies to: 526-602


832-944: Vertex ResponsesStream Anthropic streaming and chat-based fallback are coherent

For streaming responses:

  • Anthropic deployments use Vertex Anthropic :streamRawPredict endpoints with appropriate headers (Accept: text/event-stream, OAuth Bearer auth), and the shared Anthropic streaming helper. postResponseConverter annotates ModelDeployment only when alias ≠ deployment.
  • Non-Anthropic deployments mark the context with BifrostContextKeyIsResponsesToChatCompletionFallback and reuse ChatCompletionStream on a derived chat request, which keeps the streaming stack simple and avoids duplicating logic.

This structure is clear and should behave as expected for both Anthropic and non-Anthropic models.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04cf53b and cfc30a7.

📒 Files selected for processing (40)
  • core/bifrost.go (2 hunks)
  • core/bifrost_test.go (2 hunks)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (1 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/gemini/errors.go (2 hunks)
  • core/providers/gemini/gemini.go (0 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/schemas/utils.go (1 hunks)
  • core/utils.go (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/bifrost-http/lib/config.go (4 hunks)
  • transports/changelog.md (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • core/providers/gemini/gemini.go
  • core/providers/utils/utils.go
✅ Files skipped from review due to trivial changes (2)
  • transports/bifrost-http/integrations/router.go
  • core/changelog.md
🚧 Files skipped from review as they are similar to previous changes (20)
  • core/bifrost_test.go
  • core/providers/gemini/errors.go
  • core/bifrost.go
  • ui/README.md
  • ui/lib/constants/logs.ts
  • docs/integrations/langchain-sdk.mdx
  • core/schemas/utils.go
  • docs/quickstart/go-sdk/multimodal.mdx
  • transports/bifrost-http/lib/config.go
  • docs/integrations/anthropic-sdk.mdx
  • ui/app/workspace/logs/views/logChatMessageView.tsx
  • core/chatbot_test.go
  • core/utils.go
  • core/internal/testutil/account.go
  • docs/integrations/what-is-an-integration.mdx
  • core/providers/bedrock/bedrock.go
  • transports/changelog.md
  • docs/quickstart/gateway/multimodal.mdx
  • core/providers/anthropic/chat.go
  • docs/integrations/openai-sdk.mdx
🧰 Additional context used
🧬 Code graph analysis (3)
core/providers/openai/chat.go (1)
core/schemas/utils.go (1)
  • IsMistralModel (1048-1050)
framework/streaming/responses.go (2)
core/schemas/bifrost.go (3)
  • OpenAI (35-35)
  • OpenRouter (49-49)
  • Azure (36-36)
core/schemas/utils.go (1)
  • IsAnthropicModel (1043-1045)
core/providers/azure/azure.go (4)
core/schemas/account.go (2)
  • Key (8-17)
  • AzureKeyConfig (21-25)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • Ptr (16-18)
core/providers/azure/types.go (2)
  • AzureAnthropicAPIVersionDefault (6-6)
  • AzureAPIVersionDefault (4-4)
core/utils.go (1)
  • Ptr (51-53)
🔇 Additional comments (18)
docs/integrations/genai-sdk.mdx (1)

98-98: Documentation branding updates are accurate and consistent.

The changes correctly update the terminology from "Azure OpenAI" to "Azure" to reflect the broader provider support (now including Anthropic models alongside OpenAI). The comments in both the Python and JavaScript examples are clear and accurately describe the "azure/gpt-4o" usage pattern.

Also applies to: 133-133

docs/quickstart/go-sdk/provider-configuration.mdx (1)

274-280: Branding update aligns well with multi-provider Azure support.

The rebranding from "Azure OpenAI" to "Azure" is appropriate and reflects the PR's expansion of Azure provider to support both OpenAI and Anthropic models. The updated description and tab title are clearer and more inclusive.

The configuration example (lines 283–304) remains accurate and properly documents the Azure-specific setup pattern with deployments and API versions.

docs/features/keys-management.mdx (1)

198-198: Branding terminology updated for consistency.

The heading has been appropriately updated from "Azure OpenAI:" to "Azure:" to align with the broader branding updates in this PR. The description at lines 199–201 accurately reflects Azure's deployment-based routing and remains unchanged, which is correct.

ui/app/workspace/logs/views/logDetailsSheet.tsx (2)

39-39: Adding gap-4 to SheetContent is a clean spacing improvement

Using gap-4 on the column flex container should give more consistent vertical spacing between sections without affecting behavior. Looks good and matches the rest of the layout utilities in this file.


52-56: Delete handler formatting change is behavior‑preserving

The onClick still performs handleDelete(log) then closes the sheet via onOpenChange(false); only indentation/brace placement changed. No functional concerns here.

docs/features/unified-interface.mdx (2)

91-91: ✅ Branding update aligns with PR objectives.

The rebranding from "Azure OpenAI" to "Azure" is consistent with the PR goal to standardize documentation terminology. The Azure capabilities matrix remains accurate—TTS/STT correctly marked as ❌, consistent with the prior issue resolution.


95-95: Verify Elevenlabs Models capability is intentional.

The Elevenlabs row shows Models: ❌, which is reasonable since Elevenlabs focuses on TTS/STT services rather than LLM model selection. However, please confirm this is intentional and that the provider doesn't expose a list-models endpoint for audio/transcription models.

docs/integrations/litellm-sdk.mdx (1)

73-79: Azure LiteLLM examples look consistent with the new provider naming.

The Azure examples (both generic and direct-key) align with the azure/<deployment> model naming and x-bf-azure-endpoint usage; no issues from a behavior or configuration standpoint.

Also applies to: 146-162

core/providers/openai/chat.go (1)

47-55: Centralized Mistral detection for Vertex path looks correct.

Using schemas.IsMistralModel(bifrostReq.Model) here keeps model-family logic in one place and should correctly catch Vertex Mistral/Codestral models for compatibility transforms.

core/providers/azure/types.go (1)

3-7: Azure Anthropic API version constant is a good separation.

Introducing AzureAnthropicAPIVersionDefault alongside the generic AzureAPIVersionDefault makes it straightforward to keep Anthropic-on-Azure calls pinned to the right version as you wire up Anthropic deployments.

core/providers/anthropic/anthropic.go (2)

30-35: Renamed Anthropic message response pool and its usage look sound.

The new anthropicMessageResponsePool plus AcquireAnthropicMessageResponse/ReleaseAnthropicMessageResponse are wired consistently in NewAnthropicProvider, ChatCompletion, and Responses, matching the existing text-response pool pattern and avoiding extra allocations.

Also applies to: 44-55, 86-90, 331-333, 638-640


314-320: Shared chat streaming helper is a solid refactor for Anthropic-compatible SSE.

Routing both direct Anthropic chat streaming and other Anthropic-compatible providers through HandleAnthropicChatCompletionStreaming (with providerName and optional postResponseConverter) centralizes SSE parsing, usage accumulation, and final‑chunk emission on clean EOF. The postResponseConverter hook is also a good extension point for Azure/Vertex to adjust chunks before hooks/logging.

Also applies to: 365-376, 380-405, 407-611

core/providers/azure/azure_test.go (1)

25-36: Updated Azure text-model comment is accurate and consistent with branding.

The note that Azure doesn’t support classic text completions on newer models matches how you configure TextModel and TextCompletion scenarios in this test.

core/providers/azure/azure.go (2)

63-105: Auth and URL handling split cleanly between Anthropic and OpenAI-style Azure paths

The refactored completeRequest cleanly separates Anthropic (x-api-key + anthropic-version header, no api-version query) from OpenAI-style deployments (Bearer/api-key with api-version on the query string), and threading both deployment and model through the call makes downstream logging and error parsing straightforward. No functional issues spotted here.


428-513: Azure ChatCompletionStream Anthropic/OpenAI split looks correct and consistent

The streaming chat method resolves deployment once, uses IsAnthropicModel(deployment) for routing, and:

  • For Anthropic: builds the anthropic/v1/messages URL, sets x-api-key and anthropic-version, forces Stream=true in the Anthropic request, and reuses shared Anthropic streaming logic.
  • For non-Anthropic: uses the OpenAI-style deployments path with api-version and supports both Bearer and api-key auth.

The postResponseConverter that annotates ExtraFields.ModelDeployment is a nice touch for observability. No issues here.

core/providers/vertex/vertex.go (3)

435-441: Centralized Vertex error parsing and Anthropic response conversion are wired correctly

On non-200 responses, ChatCompletion now delegates to parseVertexError, which centralizes handling of OpenAI-style, Vertex, and validation errors. For Anthropic deployments, the code reuses the pooled AnthropicMessageResponse and converts to a BifrostChatResponse, then overwrites ExtraFields with the expected metadata and conditionally sets ModelDeployment when alias ≠ deployment. The non-Anthropic path mirrors this behavior.

All of this looks consistent and should give better error messages and telemetry for Vertex.

Also applies to: 443-487


682-829: Vertex Responses Anthropic path and ChatCompletion fallback are correct

The new Responses implementation:

  • Validates VertexKeyConfig and resolves deployment.
  • For Anthropic deployments: builds a Vertex Anthropic rawPredict call, uses OAuth Bearer auth, reuses AnthropicMessageResponse to convert into a BifrostResponsesResponse, and sets ExtraFields (including latency and optional ModelDeployment), with non-200 errors routed through parseVertexError.
  • For non-Anthropic deployments: delegates to ChatCompletion and uses ToBifrostResponsesResponse(), then adjusts ExtraFields (RequestType, Provider, ModelRequested) while preserving latency and adding ModelDeployment only when alias ≠ deployment.

This keeps Anthropic native and other models on the existing chat-based fallback, with good extra-field hygiene.


946-977: Vertex Embedding deployment metadata propagation is a nice observability improvement

Embedding already used the native Vertex embeddings endpoint. Adding ModelDeployment when the requested model alias differs from the resolved deployment improves traceability without affecting behavior.

The rest of the method (auth, error handling, and conversion) remains unchanged.

Also applies to: 1058-1067

Comment thread core/providers/azure/azure.go
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch 2 times, most recently from 726a7b0 to 55f264c Compare November 30, 2025 06:57

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
core/providers/anthropic/anthropic.go (1)

711-908: Missing postResponseConverter usage in streaming loop.

The function declares a postResponseConverter parameter (line 723) but never uses it in the streaming loop (lines 863-893). This is inconsistent with HandleAnthropicChatCompletionStreaming (lines 564-570), where the converter is applied to each response chunk with proper nil checking.

Apply the converter before setting ExtraFields:

 			for i, response := range responses {
 				if response != nil {
+					if postResponseConverter != nil {
+						response = postResponseConverter(response)
+						if response == nil {
+							logger.Warn("postResponseConverter returned nil; skipping chunk")
+							continue
+						}
+					}
 					response.ExtraFields = schemas.BifrostResponseExtraFields{
 						RequestType:    schemas.ResponsesStreamRequest,
 						Provider:       providerName,
 						ModelRequested: modelName,
 						ChunkIndex:     chunkIndex,
 						Latency:        time.Since(lastChunkTime).Milliseconds(),
 					}
core/providers/azure/azure.go (1)

83-128: Add conditional error parsing for Anthropic responses in Azure provider.

Line 115 uses openai.ParseOpenAIError for all error responses, but the authentication routing at line 84 already branches on IsAnthropicModel(deployment). The native Anthropic provider handles errors using HandleProviderAPIError with the AnthropicError struct (see core/providers/anthropic/anthropic.go lines 151-158). Azure Anthropic responses should follow the same pattern:

	// Handle error response
	if resp.StatusCode() != fasthttp.StatusOK {
+		if schemas.IsAnthropicModel(deployment) {
+			var errorResp anthropic.AnthropicError
+			bifrostErr := providerUtils.HandleProviderAPIError(resp, &errorResp)
+			bifrostErr.Error.Type = &errorResp.Error.Type
+			bifrostErr.Error.Message = errorResp.Error.Message
+			return nil, deployment, latency, bifrostErr
+		}
		return nil, deployment, latency, openai.ParseOpenAIError(resp, requestType, provider.GetProviderKey(), model)
	}
🧹 Nitpick comments (6)
ui/app/workspace/logs/views/logChatMessageView.tsx (1)

29-29: Consider applying break-words consistently to other text displays.

The addition of break-words prevents overflow for long unbreakable strings, which is a good improvement. However, this class is only applied here and not to other similar text displays in the component (e.g., lines 89 and 132 for thought and content strings). Consider applying break-words to those locations as well for consistent overflow handling.

Apply this diff to add break-words to the thought display:

-<div className="text-muted-foreground px-6 py-2 font-mono text-xs whitespace-pre-wrap italic">{message.thought}</div>
+<div className="text-muted-foreground px-6 py-2 font-mono text-xs break-words whitespace-pre-wrap italic">{message.thought}</div>

And to the string content display:

-<div className="px-6 py-2 font-mono text-xs whitespace-pre-wrap">{message.content}</div>
+<div className="px-6 py-2 font-mono text-xs break-words whitespace-pre-wrap">{message.content}</div>
core/providers/bedrock/bedrock.go (1)

520-545: Model-family detection is fine; consider falling back to request.Model when deployment is empty.

Using IsAnthropicModel / IsMistralModel on deployment centralizes model-family checks and the explicit default error is helpful. However, when there’s no entry in BedrockKeyConfig.Deployments, deployment stays empty, so even valid Anthropics/Mistral model IDs (passed directly as request.Model) will hit the default branch.

If you intend to support direct model IDs without a deployments map, consider a small tweak:

-	// Handle model-specific response conversion
-	var bifrostResponse *schemas.BifrostTextCompletionResponse
-	switch {
-	case schemas.IsAnthropicModel(deployment):
+	// Handle model-specific response conversion
+	var bifrostResponse *schemas.BifrostTextCompletionResponse
+	modelID := deployment
+	if modelID == "" {
+		modelID = request.Model
+	}
+	switch {
+	case schemas.IsAnthropicModel(modelID):
@@
-	case schemas.IsMistralModel(deployment):
+	case schemas.IsMistralModel(modelID):
@@
-	default:
-		return nil, providerUtils.NewConfigurationError(fmt.Sprintf("unsupported model type for text completion: %s", request.Model), providerName)
+	default:
+		return nil, providerUtils.NewConfigurationError(
+			fmt.Sprintf("unsupported model type for text completion: %s", modelID),
+			providerName,
+		)

If deployments are mandatory for TextCompletion in all current usages, you can defer this, but it’s a cheap safeguard.

framework/streaming/responses.go (1)

595-599: Routing Azure Anthropic responses away from the OpenAI final-chunk path is correct.

Updating the condition to:

if provider == schemas.OpenAI ||
   provider == schemas.OpenRouter ||
   (provider == schemas.Azure && !schemas.IsAnthropicModel(model)) {

ensures Azure Anthropic models now use the accumulation logic instead of the OpenAI-compatible final-chunk shortcut, which matches their native streaming semantics and avoids misinterpreting partial chunks as complete responses.

Also applies to: 686-745

core/schemas/utils.go (1)

1042-1050: Make IsAnthropicModel / IsMistralModel comments provider‑agnostic.

The implementations are generic substring checks and are already used by Bedrock and streaming code (not just Vertex), so the “in Vertex” wording is misleading. Consider something like:

// IsAnthropicModel checks whether a model string refers to an Anthropic/Claude model.
func IsAnthropicModel(model string) bool {
    return strings.Contains(model, "anthropic.") || strings.Contains(model, "claude")
}

// IsMistralModel checks whether a model string refers to a Mistral or Codestral model.
func IsMistralModel(model string) bool {
    return strings.Contains(model, "mistral") || strings.Contains(model, "codestral")
}

to better reflect actual usage.

core/providers/vertex/errors.go (1)

10-38: LGTM! Centralized error parsing correctly implemented.

The cascading error format parsing appropriately handles OpenAI, Vertex array, single Vertex, and validation error formats, and the previously flagged unused providerName parameter is now correctly used throughout. The fallback logic is sound.

Optional enhancement: The "Unknown error" fallback messages at lines 27 and 34 could include a snippet of the response body for debugging purposes:

-return providerUtils.NewProviderAPIError("Unknown error", nil, resp.StatusCode(), providerName, nil, nil)
+return providerUtils.NewProviderAPIError(fmt.Sprintf("Unknown error: %s", string(resp.Body())), nil, resp.StatusCode(), providerName, nil, nil)
docs/apis/openapi.json (1)

1770-1770: Inconsistent deployment ID parameter descriptions after branding update.

Line 1770 was updated to "Deployment ID", but the same parameter descriptions at lines 1892, 2014, 2126, 2235, and 2343 still reference "Azure deployment ID". Update all six locations consistently to align with the branding change from "Azure OpenAI" to "OpenAI Compatible".

  "/openai/deployments/{deployment-id}/chat/completions": {
    "post": {
      ...
      "parameters": [
        {
          "name": "deployment-id",
          "in": "path",
          "required": true,
-         "description": "Azure deployment ID",
+         "description": "Deployment ID",
          "schema": {
            "type": "string"
          }
        }
      ]
    }
  },
  "/openai/deployments/{deployment-id}/responses": {
    "post": {
      ...
      "parameters": [
        {
          "name": "deployment-id",
          "in": "path",
          "required": true,
-         "description": "Azure deployment ID",
+         "description": "Deployment ID",
          "schema": {
            "type": "string"
          }
        }
      ]
    }
  },
  "/openai/deployments/{deployment-id}/embeddings": {
    "post": {
      ...
      "parameters": [
        {
          "name": "deployment-id",
          "in": "path",
          "required": true,
-         "description": "Azure deployment ID",
+         "description": "Deployment ID",
          "schema": {
            "type": "string"
          }
        }
      ]
    }
  },
  "/openai/deployments/{deployment-id}/audio/speech": {
    "post": {
      ...
      "parameters": [
        {
          "name": "deployment-id",
          "in": "path",
          "required": true,
-         "description": "Azure deployment ID",
+         "description": "Deployment ID",
          "schema": {
            "type": "string"
          }
        }
      ]
    }
  },
  "/openai/deployments/{deployment-id}/audio/transcriptions": {
    "post": {
      ...
      "parameters": [
        {
          "name": "deployment-id",
          "in": "path",
          "required": true,
-         "description": "Azure deployment ID",
+         "description": "Deployment ID",
          "schema": {
            "type": "string"
          }
        }
      ]
    }
  }

Also applies to: 1892-1892, 2014-2014, 2126-2126, 2235-2235, 2343-2343

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cfc30a7 and 55f264c.

📒 Files selected for processing (60)
  • core/bifrost.go (2 hunks)
  • core/bifrost_test.go (2 hunks)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (1 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/gemini/errors.go (2 hunks)
  • core/providers/gemini/gemini.go (0 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/schemas/utils.go (1 hunks)
  • core/utils.go (1 hunks)
  • core/version (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/changelog.md (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • framework/version (1 hunks)
  • plugins/governance/changelog.md (1 hunks)
  • plugins/governance/version (1 hunks)
  • plugins/jsonparser/changelog.md (1 hunks)
  • plugins/jsonparser/version (1 hunks)
  • plugins/logging/changelog.md (1 hunks)
  • plugins/logging/version (1 hunks)
  • plugins/maxim/changelog.md (1 hunks)
  • plugins/maxim/version (1 hunks)
  • plugins/mocker/changelog.md (1 hunks)
  • plugins/mocker/version (1 hunks)
  • plugins/otel/changelog.md (1 hunks)
  • plugins/otel/version (1 hunks)
  • plugins/semanticcache/changelog.md (1 hunks)
  • plugins/semanticcache/version (1 hunks)
  • plugins/telemetry/changelog.md (1 hunks)
  • plugins/telemetry/version (1 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/bifrost-http/lib/config.go (4 hunks)
  • transports/changelog.md (1 hunks)
  • transports/version (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • core/providers/utils/utils.go
  • core/providers/gemini/gemini.go
✅ Files skipped from review due to trivial changes (16)
  • plugins/logging/version
  • plugins/maxim/changelog.md
  • transports/version
  • plugins/mocker/changelog.md
  • transports/bifrost-http/integrations/router.go
  • plugins/maxim/version
  • plugins/semanticcache/changelog.md
  • plugins/otel/changelog.md
  • framework/changelog.md
  • plugins/mocker/version
  • plugins/telemetry/changelog.md
  • plugins/governance/version
  • plugins/logging/changelog.md
  • docs/integrations/anthropic-sdk.mdx
  • framework/version
  • plugins/jsonparser/changelog.md
🚧 Files skipped from review as they are similar to previous changes (22)
  • core/internal/testutil/account.go
  • core/bifrost.go
  • docs/integrations/what-is-an-integration.mdx
  • core/providers/gemini/errors.go
  • ui/README.md
  • core/providers/openai/chat.go
  • transports/changelog.md
  • core/changelog.md
  • core/chatbot_test.go
  • docs/integrations/litellm-sdk.mdx
  • ui/lib/constants/logs.ts
  • core/bifrost_test.go
  • transports/bifrost-http/lib/config.go
  • core/providers/anthropic/chat.go
  • docs/quickstart/go-sdk/multimodal.mdx
  • core/utils.go
  • docs/quickstart/gateway/provider-configuration.mdx
  • core/providers/azure/azure_test.go
  • docs/quickstart/gateway/multimodal.mdx
  • docs/integrations/genai-sdk.mdx
  • ui/app/workspace/logs/views/logDetailsSheet.tsx
  • docs/integrations/langchain-sdk.mdx
🧰 Additional context used
🧬 Code graph analysis (5)
core/providers/bedrock/bedrock.go (3)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/bedrock/types.go (1)
  • BedrockAnthropicTextResponse (235-239)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/providers/vertex/errors.go (4)
core/providers/vertex/vertex.go (1)
  • VertexError (25-31)
core/providers/vertex/types.go (1)
  • VertexValidationError (154-161)
core/providers/utils/utils.go (2)
  • NewBifrostOperationError (449-460)
  • NewProviderAPIError (464-479)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (29-29)
framework/streaming/responses.go (2)
core/schemas/bifrost.go (3)
  • OpenAI (35-35)
  • OpenRouter (49-49)
  • Azure (36-36)
core/schemas/utils.go (1)
  • IsAnthropicModel (1043-1045)
core/providers/vertex/vertex.go (8)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/providers/anthropic/anthropic.go (3)
  • AcquireAnthropicMessageResponse (45-49)
  • ReleaseAnthropicMessageResponse (52-56)
  • HandleAnthropicResponsesStream (713-908)
core/providers/utils/utils.go (2)
  • CheckContextAndGetRequestBody (256-274)
  • NewBifrostOperationError (449-460)
core/schemas/bifrost.go (5)
  • BifrostResponseExtraFields (284-293)
  • RequestType (83-83)
  • BifrostError (353-362)
  • Vertex (40-40)
  • BifrostStream (318-325)
core/providers/openai/types.go (1)
  • OpenAIChatRequest (41-54)
core/providers/vertex/types.go (1)
  • DefaultVertexAnthropicVersion (8-8)
core/schemas/provider.go (1)
  • PostHookRunner (204-204)
core/providers/anthropic/anthropic.go (3)
core/providers/anthropic/types.go (1)
  • AnthropicMessageResponse (272-281)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/providers/utils/utils.go (3)
  • NewBifrostOperationError (449-460)
  • CreateBifrostChatCompletionChunkResponse (686-715)
  • ShouldSendBackRawResponse (482-487)
🔇 Additional comments (28)
plugins/telemetry/version (1)

1-1: Telemetry plugin version bump is fine

Version updated to 1.3.41; this is a straightforward metadata bump with no behavioral impact in this file.

plugins/otel/version (1)

1-1: LGTM!

The version bump is consistent with the broader release cycle mentioned in the changelog.

plugins/jsonparser/version (1)

1-1: LGTM!

The version bump aligns with other plugin version updates in this release.

core/version (1)

1-1: LGTM!

The version bump to 1.2.32 is correctly reflected in the governance plugin's changelog.

plugins/semanticcache/version (1)

1-1: LGTM!

The version bump is consistent with the release cadence of other plugins.

plugins/governance/changelog.md (2)

1-1: Verify that this feat entry belongs to the current PR.

The feat entry references Google Gemini x-goog-api-key header support, which doesn't appear in this PR's objectives (focused on Anthropic/Azure support). Since this is a Graphite-managed stack, this entry may belong to a different PR in the stack.

Please confirm whether this changelog entry:

  1. Belongs to this PR (if so, it should be mentioned in the PR objectives)
  2. Belongs to another PR in the Graphite stack (if so, it should be moved to that PR's changelog)
  3. Was previously committed but not yet documented

2-2: LGTM!

The version update entry accurately reflects the core version bump to 1.2.32 observed in this PR.

docs/features/keys-management.mdx (1)

198-201: Azure label rename is consistent with broader branding updates.

Renaming the section to “Azure” keeps this doc aligned with the rest of the provider naming; no functional implications here.

docs/integrations/openai-sdk.mdx (1)

99-105: Azure usage wording and examples look correct.

The updated “Azure models” labels and the AzureOpenAI examples (pointing base URL to Bifrost with x-bf-azure-endpoint carrying the real Azure resource) are coherent and match the intended integration behavior.

Also applies to: 141-145, 319-333, 348-356

core/providers/azure/types.go (1)

3-6: Separate Anthropic API version constant is a good addition.

Having AzureAPIVersionDefault and AzureAnthropicAPIVersionDefault distinct makes it clear which version to use per model family and keeps azure.go free to route appropriately.

docs/quickstart/go-sdk/provider-configuration.mdx (1)

274-276: Azure provider-auth example correctly reflects the new AzureKeyConfig shape.

Using schemas.Azure with AzureKeyConfig{Endpoint, Deployments, APIVersion} in schemas.Key lines up with the Azure provider changes and gives users a concrete template for configuring deployments and API versions.

Also applies to: 283-303

core/providers/azure/azure.go (6)

789-800: LGTM! Clean deployment resolution helper.

The function properly validates the Azure key config, performs the deployment lookup, and returns clear error messages when deployments are not found.


245-282: LGTM! TextCompletion correctly uses deployment resolution.

The method properly calls getModelDeployment, passes the deployment to completeRequest, and populates ModelDeployment in the response ExtraFields.


352-425: LGTM! ChatCompletion correctly implements dual-path routing.

The method consistently uses IsAnthropicModel(deployment) for branching across request body conversion, path construction, and response parsing. The Anthropic branch properly uses pooled response objects and converts to the Bifrost format.


437-513: LGTM! Streaming implementation correctly handles both model types.

The method introduces a postResponseConverter to ensure ModelDeployment is populated in streaming chunks. Both Anthropic and OpenAI branches properly construct authentication headers and delegate to the appropriate streaming handlers.


524-601: LGTM! Responses method mirrors ChatCompletion pattern.

The implementation follows the same dual-path routing pattern as ChatCompletion, with consistent branching on IsAnthropicModel(deployment) for request conversion, path construction, and response parsing.


610-690: LGTM! ResponsesStream properly implements dual-path streaming.

The method follows the ChatCompletionStream pattern with postResponseConverter for deployment metadata. The OpenAI branch additionally uses postRequestConverter to set the deployment in the request, which is appropriate for the OpenAI responses endpoint.

core/providers/vertex/vertex.go (7)

291-339: LGTM! Request body construction correctly branches on model type.

The function properly uses ToAnthropicChatRequest for Anthropic models and ToOpenAIChatRequest for others. The TODO comment at line 296 acknowledges the double Marshal/Unmarshal pattern could be optimized in the future.


359-397: LGTM! URL construction correctly routes by model type.

The logic appropriately distinguishes fine-tuned models (all digits), Anthropic models, Mistral models, and generic OpenAPI models, constructing the correct publisher and endpoint paths for each. Regional handling is consistent across all paths.


440-495: LGTM! Response parsing correctly handles both paths.

The method uses the centralized parseVertexError for error handling and properly branches on model type. Both Anthropic and non-Anthropic paths conditionally populate ModelDeployment only when it differs from ModelRequested, avoiding redundancy.


519-678: LGTM! Streaming correctly implements dual-path with deployment metadata.

The postResponseConverter pattern ensures ModelDeployment is populated in all streaming chunks. Both Anthropic and non-Anthropic branches properly construct URLs with regional handling, set up authentication, and delegate to appropriate streaming handlers.


686-829: LGTM! Responses correctly implements Anthropic-specific path.

The method adds a dedicated Anthropic branch (lines 692-812) with full HTTP request handling including OAuth authentication, request body construction, and response parsing. The non-Anthropic fallback to ChatCompletion (lines 813-829) is appropriate since OpenAI-like models don't have a native responses endpoint.


836-943: LGTM! ResponsesStream properly implements streaming with fallback.

The Anthropic branch (lines 842-934) implements full streaming with OAuth, request body construction, and proper delegation to HandleAnthropicResponsesStream. The non-Anthropic fallback (lines 936-943) appropriately sets a context flag to indicate the responses-to-chat-completion fallback.


1064-1067: LGTM! Embedding method adds deployment metadata consistently.

The conditional ModelDeployment population follows the same pattern used in other methods, avoiding redundancy when the deployment matches the requested model.

core/providers/anthropic/anthropic.go (4)

30-56: LGTM! Pool renaming aligns with Anthropic's Messages API terminology.

The rename from anthropicChatResponsePool to anthropicMessageResponsePool (and corresponding Acquire/Release functions) better reflects Anthropic's Messages API naming. The pool behavior is unchanged and pre-warming is updated accordingly.

Also applies to: 89-89


318-332: LGTM! Converter renaming and streaming parameter addition are correct.

The rename from ToAnthropicChatCompletionRequest to ToAnthropicChatRequest is consistent. The new postResponseConverter parameter in HandleAnthropicChatCompletionStreaming enables providers like Azure and Vertex to inject deployment metadata while keeping the Anthropic provider simple (passes nil).

Also applies to: 369-404


564-570: LGTM! postResponseConverter usage is defensive and correct.

The nil check for postResponseConverter is appropriate since it's optional. The warning log when a converter returns nil helps debugging, and skipping invalid chunks prevents downstream errors.


638-639: LGTM! Responses methods updated consistently.

The Responses method uses the renamed Acquire/Release functions. ResponsesStream now builds a headers map and delegates to the new HandleAnthropicResponsesStream function, following the same pattern as ChatCompletionStream.

Also applies to: 685-708

Comment thread docs/features/unified-interface.mdx
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch from 55f264c to 8570c74 Compare November 30, 2025 09:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/providers/azure/azure.go (1)

114-116: Anthropic error responses use a different format than OpenAI.

Line 115 uses openai.ParseOpenAIError regardless of whether the request was sent to the Anthropic or OpenAI endpoint. Anthropic's error format differs from OpenAI's (e.g., Anthropic uses {"type":"error","error":{"type":"...","message":"..."}} structure). Consider routing to an Anthropic-specific error parser when schemas.IsAnthropicModel(deployment) is true.

 	// Handle error response
 	if resp.StatusCode() != fasthttp.StatusOK {
-		return nil, deployment, latency, openai.ParseOpenAIError(resp, requestType, provider.GetProviderKey(), model)
+		if schemas.IsAnthropicModel(deployment) {
+			return nil, deployment, latency, anthropic.ParseAnthropicError(resp, requestType, provider.GetProviderKey(), model)
+		}
+		return nil, deployment, latency, openai.ParseOpenAIError(resp, requestType, provider.GetProviderKey(), model)
 	}
♻️ Duplicate comments (2)
docs/features/unified-interface.mdx (1)

95-95: Unresolved: Elevenlabs STT (stream) capability status remains inconsistent.

A prior review flagged that the Elevenlabs row should mark STT (stream) as ✅ rather than ❌, since the provider implements TranscriptionStream in core/providers/elevenlabs/elevenlabs.go. This issue appears unresolved in the current code.

Please verify if the STT (stream) capability for Elevenlabs is intentionally ❌ or if this is an oversight. If the provider does support streaming transcription, update line 95 to mark it as ✅.

core/providers/anthropic/anthropic.go (1)

711-908: Good implementation, but missing defensive final chunk emission.

The HandleAnthropicResponsesStream function follows a consistent pattern with HandleAnthropicChatCompletionStreaming and properly tracks model name and usage. However, there's a defensive programming gap at the scanner completion path (lines 901-904):

Issue: Unlike HandleAnthropicChatCompletionStreaming (lines 602-607), this function lacks an else block after scanner.Err() to emit a final chunk when the stream ends without an explicit message_stop event. While Anthropic's API should always send message_stop, handling unexpected EOF without it would make the code more robust.

Consider adding defensive final chunk emission similar to the chat completion handler:

 		if err := scanner.Err(); err != nil {
 			logger.Warn(fmt.Sprintf("Error reading %s stream: %v", providerName, err))
 			providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ResponsesStreamRequest, providerName, modelName, logger)
+		} else {
+			// Defensive: emit final chunk with usage if stream ended without explicit message_stop
+			response := &schemas.BifrostResponsesStreamResponse{
+				Type:           schemas.ResponsesStreamResponseTypeResponseDone,
+				SequenceNumber: chunkIndex,
+				Response:       &schemas.BifrostResponsesResponse{Usage: usage},
+				ExtraFields: schemas.BifrostResponseExtraFields{
+					RequestType:    schemas.ResponsesStreamRequest,
+					Provider:       providerName,
+					ModelRequested: modelName,
+					ChunkIndex:     chunkIndex,
+					Latency:        time.Since(startTime).Milliseconds(),
+				},
+			}
+			ctx = context.WithValue(ctx, schemas.BifrostContextKeyStreamEndIndicator, true)
+			providerUtils.ProcessAndSendResponse(ctx, postHookRunner, providerUtils.GetBifrostResponseForStreamResponse(nil, nil, response, nil, nil), responseChan)
 		}

Note: This echoes the past review comment that was marked as addressed but only handles the normal case (line 850 when message_stop is received), not the edge case of unexpected stream termination.

🧹 Nitpick comments (9)
docs/quickstart/go-sdk/provider-configuration.mdx (1)

283-304: Consider adding a Claude deployment example alongside the OpenAI example.

The Azure configuration example currently shows only OpenAI models (gpt-4o, gpt-4o-mini). Since the PR adds first-class support for Claude models in Azure, adding a Claude model to the deployment mappings would better demonstrate the new capability and help users understand how to configure both model families.

For example:

Deployments: map[string]string{
    "gpt-4o":      "gpt-4o-deployment",
    "gpt-4o-mini": "gpt-4o-mini-deployment",
    "claude-3-5-sonnet-20241022": "claude-deployment", // Claude model
},
ui/app/workspace/logs/views/logChatMessageView.tsx (1)

17-32: Word-breaking improvement is good; consider applying it consistently

Adding break-words on block.text will help with long unbroken strings and looks good. To avoid inconsistent behavior, consider adding the same class to other plain-text areas like message.thought (Line 89) and the string message.content branch (Line 132) as well.

For example:

- <div className="text-muted-foreground px-6 py-2 font-mono text-xs whitespace-pre-wrap italic">
+ <div className="text-muted-foreground px-6 py-2 font-mono text-xs break-words whitespace-pre-wrap italic">
    {message.thought}
  </div>

- <div className="px-6 py-2 font-mono text-xs whitespace-pre-wrap">
+ <div className="px-6 py-2 font-mono text-xs break-words whitespace-pre-wrap">
    {message.content}
  </div>
docs/apis/openapi.json (1)

1759-1789: Branding updates look good; align deployment parameter descriptions

The updated summaries/descriptions to “OpenAI Compatible …” for the Azure deployment-style endpoints are consistent and match the rest of the OpenAI-compatible docs.

One minor consistency issue: the deployment-id path parameter description was generalized to "Deployment ID" for text completions (Line 1770), but other deployment endpoints still say "Azure deployment ID" (e.g., chat completions, responses, embeddings, speech, transcriptions).

To keep the docs uniform and provider-agnostic, consider updating those remaining descriptions as well:

- "description": "Azure deployment ID",
+ "description": "Deployment ID",

for:

  • /openai/deployments/{deployment-id}/chat/completions
  • /openai/deployments/{deployment-id}/responses
  • /openai/deployments/{deployment-id}/embeddings
  • /openai/deployments/{deployment-id}/audio/speech
  • /openai/deployments/{deployment-id}/audio/transcriptions

Also applies to: 1881-1911, 2003-2033, 2115-2145, 2224-2225, 2332-2333

framework/modelcatalog/pricing.go (2)

139-146: Guard against nil usage before dereferencing in audio-only paths

Here you explicitly allow audio-only flows (audioSeconds / audioTokenDetails) when usage is nil, but usage.Cost is dereferenced unconditionally on Line 144. If a caller ever passes audioSeconds != nil (or audioTokenDetails != nil) with usage == nil, this will panic.

A small defensive change keeps current behavior for existing callers while making the function robust for true audio-only invocations:

-  // Allow audio-only flows by only returning early if we have no usage data at all
-  if usage == nil && audioSeconds == nil && audioTokenDetails == nil {
-    return 0.0
-  }
-
-  if usage.Cost != nil && usage.Cost.TotalCost > 0 {
-    return usage.Cost.TotalCost
-  }
+  // Allow audio-only flows by only returning early if we have no usage data at all
+  if usage == nil && audioSeconds == nil && audioTokenDetails == nil {
+    return 0.0
+  }
+
+  if usage != nil && usage.Cost != nil && usage.Cost.TotalCost > 0 {
+    return usage.Cost.TotalCost
+  }

252-260: Cache read pricing change looks correct; confirm fallback semantics and completion-side usage

Switching cached prompt tokens to bill against CacheReadInputTokenCost instead of CacheCreationInputTokenCost aligns with the field naming and avoids overcharging cache reads:

inputCost = float64(promptTokens-cachedPromptTokens) * pricing.InputCostPerToken
if pricing.CacheReadInputTokenCost != nil {
    inputCost += float64(cachedPromptTokens) * *pricing.CacheReadInputTokenCost
}

Two points worth double-checking:

  1. Nil CacheReadInputTokenCost semantics
    With the current logic, if CacheReadInputTokenCost is nil, cached prompt tokens are effectively free (since they’re removed from the base InputCostPerToken calculation). If the intended behavior for providers without a special cache-read price is “bill cached tokens at the normal input rate,” you might instead want:

    inputReadRate := pricing.InputCostPerToken
    if pricing.CacheReadInputTokenCost != nil {
        inputReadRate = *pricing.CacheReadInputTokenCost
    }
    inputCost = float64(promptTokens-cachedPromptTokens) * pricing.InputCostPerToken
    inputCost += float64(cachedPromptTokens) * inputReadRate

    If, however, “nil means free cache reads” is deliberate, the current behavior is fine—just worth confirming.

  2. Use of CacheCreationInputTokenCost for cachedCompletionTokens
    cachedCompletionTokens are still billed via CacheCreationInputTokenCost. If that field is indeed meant to represent the creation cost for completion-side cache entries, this is consistent; otherwise, it may be worth revisiting or documenting this mapping to avoid confusion for future maintainers.

core/providers/gemini/errors.go (2)

39-64: Type inconsistency and redundant fallback logic.

  1. StatusCode type cast inconsistency: Line 48 uses int(resp.StatusCode()) while Line 75 uses resp.StatusCode() directly. Since fasthttp.Response.StatusCode() returns int, the cast on Line 48 is redundant but harmless—however, the difference is confusing.

  2. Redundant fallback: If sonic.Unmarshal fails on Line 45, the fallback on Lines 58-59 attempts to unmarshal the same body again. If the body isn't valid JSON, both will fail. Consider returning the raw body string directly instead of attempting a second unmarshal.

 	// If JSON parsing fails, use the raw response body
-	var rawResponse interface{}
-	if err := sonic.Unmarshal(body, &rawResponse); err != nil {
-		return providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, providerName)
-	}
-
-	return providerUtils.NewBifrostOperationError(fmt.Sprintf("Gemini streaming error (HTTP %d): %v", resp.StatusCode(), rawResponse), fmt.Errorf("HTTP %d", resp.StatusCode()), providerName)
+	return providerUtils.NewBifrostOperationError(fmt.Sprintf("Gemini streaming error (HTTP %d): %s", resp.StatusCode(), string(body)), fmt.Errorf("HTTP %d", resp.StatusCode()), providerName)

66-90: Same redundant fallback logic applies here.

The fallback on Lines 84-87 has the same issue as parseStreamGeminiError—if the body isn't valid JSON for GeminiGenerationError, it likely won't parse as map[string]interface{} either (unless it's valid JSON but with a different structure). Consider returning the raw body string directly for non-JSON responses.

core/utils.go (1)

79-83: Comment is inaccurate—jitter is ±20%, not 20%.

The formula 0.8 + 0.4*rand.Float64() produces values in the range [0.8, 1.2], which represents ±20% variation around the base backoff (not just +20%). The clamping logic on Lines 82-83 is correct and ensures the jittered result never exceeds RetryBackoffMax.

-	// Add jitter (20%)
+	// Add jitter (±20%)
transports/bifrost-http/lib/config.go (1)

695-698: Config-file providers path uses the same normalization helper; tiny optional micro-optimization

Using convertNetworkConfigRetryBackoff on cfg.NetworkConfig keeps semantics aligned with the DB and store paths, which is good. Note that when a provider already exists in processedProviders, cfg.NetworkConfig is currently thrown away (only keys are merged), so this conversion does a bit of redundant work in that case; if you ever touch this loop again, you could optionally guard the call behind if _, exists := processedProviders[provider]; !exists to avoid converting unused configs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55f264c and 8570c74.

📒 Files selected for processing (61)
  • core/bifrost.go (2 hunks)
  • core/bifrost_test.go (2 hunks)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (1 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/gemini/errors.go (2 hunks)
  • core/providers/gemini/gemini.go (0 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/schemas/utils.go (1 hunks)
  • core/utils.go (1 hunks)
  • core/version (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/changelog.md (1 hunks)
  • framework/modelcatalog/pricing.go (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • framework/version (1 hunks)
  • plugins/governance/changelog.md (1 hunks)
  • plugins/governance/version (1 hunks)
  • plugins/jsonparser/changelog.md (1 hunks)
  • plugins/jsonparser/version (1 hunks)
  • plugins/logging/changelog.md (1 hunks)
  • plugins/logging/version (1 hunks)
  • plugins/maxim/changelog.md (1 hunks)
  • plugins/maxim/version (1 hunks)
  • plugins/mocker/changelog.md (1 hunks)
  • plugins/mocker/version (1 hunks)
  • plugins/otel/changelog.md (1 hunks)
  • plugins/otel/version (1 hunks)
  • plugins/semanticcache/changelog.md (1 hunks)
  • plugins/semanticcache/version (1 hunks)
  • plugins/telemetry/changelog.md (1 hunks)
  • plugins/telemetry/version (1 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/bifrost-http/lib/config.go (4 hunks)
  • transports/changelog.md (1 hunks)
  • transports/version (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • core/providers/gemini/gemini.go
  • core/providers/utils/utils.go
✅ Files skipped from review due to trivial changes (5)
  • docs/integrations/what-is-an-integration.mdx
  • plugins/telemetry/changelog.md
  • core/version
  • docs/integrations/genai-sdk.mdx
  • framework/version
🚧 Files skipped from review as they are similar to previous changes (36)
  • ui/README.md
  • core/changelog.md
  • docs/integrations/anthropic-sdk.mdx
  • framework/changelog.md
  • docs/features/keys-management.mdx
  • transports/bifrost-http/integrations/router.go
  • core/chatbot_test.go
  • plugins/jsonparser/version
  • framework/streaming/responses.go
  • transports/version
  • core/bifrost_test.go
  • docs/integrations/langchain-sdk.mdx
  • core/providers/azure/azure_test.go
  • core/providers/anthropic/chat.go
  • plugins/jsonparser/changelog.md
  • core/bifrost.go
  • plugins/logging/version
  • plugins/telemetry/version
  • plugins/maxim/changelog.md
  • docs/integrations/litellm-sdk.mdx
  • plugins/mocker/version
  • plugins/semanticcache/changelog.md
  • plugins/semanticcache/version
  • core/providers/vertex/errors.go
  • docs/quickstart/gateway/provider-configuration.mdx
  • core/internal/testutil/account.go
  • plugins/maxim/version
  • plugins/governance/changelog.md
  • transports/changelog.md
  • core/providers/azure/types.go
  • core/providers/bedrock/bedrock.go
  • ui/app/workspace/logs/views/logDetailsSheet.tsx
  • docs/integrations/openai-sdk.mdx
  • docs/quickstart/go-sdk/multimodal.mdx
  • plugins/otel/changelog.md
  • plugins/otel/version
🧰 Additional context used
🧬 Code graph analysis (7)
core/providers/openai/chat.go (1)
core/schemas/utils.go (1)
  • IsMistralModel (1048-1050)
core/utils.go (2)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
core/schemas/provider.go (1)
  • NetworkConfig (36-44)
core/providers/gemini/errors.go (5)
core/providers/gemini/types.go (1)
  • GeminiGenerationError (1353-1365)
core/schemas/utils.go (1)
  • Ptr (16-18)
core/utils.go (1)
  • Ptr (51-53)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (29-29)
core/providers/azure/azure.go (4)
core/schemas/account.go (2)
  • Key (8-17)
  • AzureKeyConfig (21-25)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • Ptr (16-18)
core/providers/azure/types.go (2)
  • AzureAnthropicAPIVersionDefault (6-6)
  • AzureAPIVersionDefault (4-4)
core/utils.go (1)
  • Ptr (51-53)
core/providers/anthropic/anthropic.go (4)
core/providers/anthropic/types.go (1)
  • AnthropicMessageResponse (272-281)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/schemas/bifrost.go (3)
  • ModelProvider (32-32)
  • BifrostResponseExtraFields (284-293)
  • RequestType (83-83)
core/schemas/responses.go (1)
  • BifrostResponsesStreamResponse (1421-1459)
core/providers/vertex/vertex.go (6)
core/schemas/utils.go (3)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
  • Ptr (16-18)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/providers/utils/utils.go (4)
  • HandleProviderResponse (343-387)
  • CheckContextAndGetRequestBody (256-274)
  • NewConfigurationError (435-445)
  • NewBifrostOperationError (449-460)
core/schemas/account.go (2)
  • Key (8-17)
  • VertexKeyConfig (29-35)
core/providers/anthropic/responses.go (1)
  • ToAnthropicResponsesRequest (284-383)
core/utils.go (1)
  • Ptr (51-53)
transports/bifrost-http/lib/config.go (2)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
core/schemas/provider.go (1)
  • NetworkConfig (36-44)
🔇 Additional comments (27)
docs/quickstart/go-sdk/provider-configuration.mdx (1)

274-274: ✅ Branding update is consistent and accurate.

The terminology has been cleanly updated from "Azure OpenAI" to "Azure" across the section heading, tab title, and description. This correctly reflects the broader refactoring to support both OpenAI and Claude models under a unified Azure provider.

Also applies to: 278-278, 280-280

docs/quickstart/gateway/multimodal.mdx (1)

288-290: Consolidation improves maintainability.

Replacing the embedded provider support table with a link to the Unified Interface page reduces maintenance burden and establishes a single source of truth. This is a good approach for keeping documentation consistent.

docs/features/unified-interface.mdx (1)

91-91: Azure branding update aligns with PR objectives.

The rename from "Azure OpenAI" to "Azure" reflects the PR's support for multiple model types (OpenAI and Anthropic) in Azure, making the provider label more accurate and generic.

plugins/logging/changelog.md (1)

1-1: LGTM!

The changelog entry correctly documents the dependency version updates using conventional commit format. The "chore" prefix appropriately categorizes this as a maintenance update.

plugins/governance/version (1)

1-1: LGTM!

The patch version increment is consistent with the coordinated version bumps across the codebase documented in this PR.

plugins/mocker/changelog.md (1)

1-1: Clarify the scope of this changelog entry.

This entry documents version updates to core and framework, but this changelog file is specific to the mocker plugin. Typically, a component's changelog documents changes to that component itself.

Is this entry meant to record that the mocker plugin version is being bumped for coordination purposes? If so, the entry should clarify this context (e.g., "chore: bump version to coordinate with core 1.2.32 and framework 1.1.41 releases"). If the mocker plugin has functional changes related to the Anthropic/Azure updates in this PR, those should be documented more specifically.

ui/lib/constants/logs.ts (1)

42-59: Azure label rename is consistent and safe

Renaming ProviderLabels.azure to "Azure" aligns with the new branding and doesn’t affect logic. No further changes needed here.

core/providers/openai/chat.go (1)

51-51: LGTM!

Good refactor to use the centralized schemas.IsMistralModel helper instead of the provider-specific utility, improving consistency across the codebase.

core/schemas/utils.go (1)

1042-1050: LGTM! Consider case sensitivity.

The helper functions are clean and serve their purpose well for centralizing model-family detection. Note that these checks are case-sensitive—if model names could arrive in varying cases (e.g., "Claude" vs "claude"), you may want to use strings.ToLower before checking. However, if model names are always normalized upstream, this is fine as-is.

core/providers/azure/azure.go (5)

347-426: LGTM!

The ChatCompletion method correctly routes Anthropic vs OpenAI models using deployment for detection, with appropriate request body conversion, path selection, and response parsing for each model type.


432-513: LGTM!

The ChatCompletionStream method correctly handles both Anthropic and OpenAI streaming paths with appropriate headers, URLs, and streaming handlers. The postResponseConverter consistently populates ModelDeployment for both paths.


519-602: LGTM!

The Responses method follows the same consistent pattern as ChatCompletion for routing between Anthropic and OpenAI paths.


605-691: LGTM!

The ResponsesStream method correctly handles both Anthropic and OpenAI streaming paths with appropriate request preparation and streaming handlers.


789-800: LGTM!

Clean helper function that properly resolves model aliases to deployment names with appropriate error handling.

core/providers/vertex/vertex.go (5)

282-496: LGTM!

The ChatCompletion method is well-structured with clear routing logic for Anthropic, Mistral, fine-tuned, and OpenAI/Gemini models. The centralized model checks improve maintainability, and the response handling correctly populates ExtraFields including conditional ModelDeployment.


498-680: LGTM!

The ChatCompletionStream method cleanly separates Anthropic and non-Anthropic streaming paths with appropriate request/response converters and consistent ModelDeployment handling via postResponseConverter.


682-830: LGTM!

The Responses method correctly implements a dedicated Anthropic path while reusing ChatCompletion for non-Anthropic models via the fallback pattern. The ToBifrostResponsesResponse conversion preserves ExtraFields including latency.


832-944: LGTM!

The ResponsesStream method correctly implements Anthropic streaming with a fallback to ChatCompletionStream for non-Anthropic models. The context key BifrostContextKeyIsResponsesToChatCompletionFallback properly signals the fallback scenario.


1100-1111: LGTM!

The helper correctly falls back to the model name when no deployment mapping exists, which is appropriate for Vertex where model names can be used directly without explicit deployment configuration.

core/providers/anthropic/anthropic.go (6)

30-56: LGTM: Consistent renaming improves clarity.

The renaming of anthropicChatResponsePoolanthropicMessageResponsePool and the associated acquire/release functions aligns well with the AnthropicMessageResponse type. All references have been updated consistently throughout the file.


318-318: LGTM: Function renaming improves consistency.

The rename from ToAnthropicChatCompletionRequest to ToAnthropicChatRequest is consistent with the broader renaming effort and improves clarity.

Also applies to: 369-369


417-419: LGTM: Good extensibility design with postResponseConverter.

The addition of the postResponseConverter parameter enables Azure and Vertex providers to transform Anthropic responses appropriately. The rename from providerType to providerName is more semantically accurate. Passing nil from the native Anthropic provider (line 402) is correct since no transformation is needed.


564-570: LGTM: Proper nil-safe postResponseConverter integration.

The implementation correctly applies the postResponseConverter when provided, with appropriate nil checks for both the converter function and its return value. The warning log provides good observability if conversion fails.


440-462: LGTM: Consistent error handling with providerName.

The error handling updates consistently use the providerName parameter instead of calling provider.GetProviderKey(), which is appropriate for this shared function. The final chunk emission at lines 602-607 properly handles the case where the stream ends without an explicit message_stop event.

Also applies to: 600-603


685-708: LGTM: Clean refactoring with proper header construction.

The ResponsesStream method now properly constructs headers and delegates to the shared HandleAnthropicResponsesStream function. The pattern is consistent with ChatCompletionStream and promotes good code reuse.

transports/bifrost-http/lib/config.go (2)

355-360: DB bootstrap path correctly applies retry-backoff conversion once for existing providers

In the “no config file” path, calling convertNetworkConfigRetryBackoff on dbProvider.NetworkConfig before building processedProviders ensures legacy DB values are normalized exactly once as they’re loaded into memory; the in-place pointer mutation plus re-wrapping into ProviderConfig looks sound.


678-684: Store-first providers path consistently normalizes network backoff for all loaded providers

Here you normalize processedProviders loaded from the store before any merging with config file data, which keeps in-memory configs consistent regardless of whether they originated from DB or JSON. Reassigning processedProviders[providerKey] = providerConfig after mutating the embedded NetworkConfig pointer is harmless (the pointer is already updated) and keeps the pattern explicit.

Comment thread transports/bifrost-http/lib/config.go Outdated
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch 2 times, most recently from 2b5557b to 75053e8 Compare December 1, 2025 06:28

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (8)
plugins/jsonparser/changelog.md (1)

1-1: Changelog entry looks good.

The version update is clearly documented and follows conventional commit style. Consider including a brief summary of key features or fixes in future changelog entries for visibility (nice-to-have).

core/providers/gemini/errors.go (2)

39-55: Validate parsed error content before constructing BifrostError

Both parseStreamGeminiError and parseGeminiError treat any successful unmarshal into GeminiGenerationError as a valid provider error:

var errorResp GeminiGenerationError
if err := sonic.Unmarshal(body, &errorResp); err == nil {
    // build BifrostError from errorResp.Error.Code / Message
}

If the response body is JSON but not actually in the expected error shape (e.g., missing or empty error fields), Unmarshal will still succeed and you’ll end up emitting a BifrostError with code "0" and an empty message, losing whatever useful details were in the payload.

Consider additionally validating the parsed content before constructing the BifrostError (for example, checking that whatever you consider mandatory in errorResp.Error is present / non‑empty), and falling through to the “rawResponse” path otherwise. That keeps error reporting robust if Gemini ever returns a slightly different JSON structure on error.

Also applies to: 71-82


57-64: Reduce duplication and align fallback error handling

The fallback branches in parseStreamGeminiError and parseGeminiError are nearly identical, differing mainly in:

  • The concrete type used for rawResponse (interface{} vs map[string]interface{}).
  • The error messages passed into NewBifrostOperationError.
  • Use of schemas.ErrProviderResponseUnmarshal vs a string literal for the non‑streaming case.
  • A small inconsistency in StatusCode pointer construction (schemas.Ptr(int(resp.StatusCode())) vs schemas.Ptr(resp.StatusCode())).

Functionally this is fine, but you could:

  • Factor the common logic into a small shared helper that takes the “context” string (e.g. "Gemini streaming error" vs "Gemini error") and maybe the desired rawResponse representation.
  • Standardize on either the constant (schemas.ErrProviderResponseUnmarshal) or a consistent literal for parse failures, and on one form of StatusCode pointer construction.

This would make future changes to error formatting or behavior less error‑prone.

Also applies to: 84-90

docs/apis/openapi.json (1)

1759-1788: Normalize deployment-id parameter descriptions across deployment endpoints

The branding change from “Azure OpenAI-compatible …” to “OpenAI-compatible …” on the /openai/deployments/{deployment-id} endpoints looks good and matches the rest of the OpenAI-compatible surface. One small consistency nit: only the /completions endpoint now describes deployment-id as "Deployment ID", while the chat/responses/embeddings/audio endpoints still say "Azure deployment ID".

To keep the docs consistent and provider‑agnostic, consider updating the remaining deployment-id descriptions to match:

-            "description": "Azure deployment ID",
+            "description": "Deployment ID",

(Apply to the deployment-id path parameter under the chat, responses, embeddings, audio/speech, and audio/transcriptions deployment routes.)

Also applies to: 1881-1911, 2003-2032, 2115-2144, 2224-2235, 2332-2343

core/utils.go (1)

79-83: Minor: Comment doesn't accurately reflect the jitter range.

The formula (0.8 + 0.4*rand.Float64()) produces values in [0.8, 1.2], which is ±20% variation. The comment "Add jitter (20%)" should read "Add jitter (±20%)" to match the previous accurate description.

The capping logic itself is correct—the second min() at line 83 ensures post-jitter values that exceed the maximum (by up to 20%) are properly clamped.

-	// Add jitter (20%)
+	// Add jitter (±20%)
core/providers/vertex/errors.go (1)

10-38: Variable shadowing in nested error parsing makes the code harder to follow.

The function has multiple levels of variable shadowing:

  • Line 13 & 15 & 18 & 21: err is redeclared in each nested scope
  • Line 17: vertexErr (single) shadows vertexErr (array) from line 12

While technically correct, this makes the control flow harder to trace. Consider using distinct variable names:

-	var vertexErr []VertexError
-	if err := sonic.Unmarshal(resp.Body(), &openAIErr); err != nil || openAIErr.Error == nil {
+	var vertexErrs []VertexError
+	if unmarshalErr := sonic.Unmarshal(resp.Body(), &openAIErr); unmarshalErr != nil || openAIErr.Error == nil {
 		// Try Vertex error format if OpenAI format fails or is incomplete
-		if err := sonic.Unmarshal(resp.Body(), &vertexErr); err != nil {
+		if arrayErr := sonic.Unmarshal(resp.Body(), &vertexErrs); arrayErr != nil {
 			//try with single Vertex error format
-			var vertexErr VertexError
-			if err := sonic.Unmarshal(resp.Body(), &vertexErr); err != nil {
+			var singleVertexErr VertexError
+			if singleErr := sonic.Unmarshal(resp.Body(), &singleVertexErr); singleErr != nil {
core/providers/azure/azure.go (1)

297-312: Inconsistent deployment resolution in TextCompletionStream.

Other methods (TextCompletion, ChatCompletion, Responses, Embedding, etc.) use the centralized getModelDeployment helper, but TextCompletionStream still uses inline resolution (lines 302-305). This creates inconsistency in error handling and behavior.

Consider refactoring to use getModelDeployment for consistency:

-	deployment := key.AzureKeyConfig.Deployments[request.Model]
-	if deployment == "" {
-		return nil, providerUtils.NewConfigurationError(fmt.Sprintf("deployment not found for model %s", request.Model), provider.GetProviderKey())
-	}
+	deployment, err := provider.getModelDeployment(key, request.Model)
+	if err != nil {
+		return nil, err
+	}
core/providers/anthropic/anthropic.go (1)

901-904: Consider adding fallback final chunk emission on scanner completion without explicit message_stop.

Per the past review discussion, the HandleAnthropicChatCompletionStreaming function (lines 602-607) has an else block that emits a final chunk with accumulated usage when the scanner completes without error. However, HandleAnthropicResponsesStream lacks this fallback—if the stream ends without a message_stop event (e.g., unexpected EOF), accumulated usage data is not sent.

While Anthropic's API should always send a message_stop event, adding a defensive else block would improve robustness against unexpected stream terminations.

 		if err := scanner.Err(); err != nil {
 			logger.Warn(fmt.Sprintf("Error reading %s stream: %v", providerName, err))
 			providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ResponsesStreamRequest, providerName, modelName, logger)
+		} else {
+			// Defensive: emit final chunk if stream ended without explicit message_stop
+			response := &schemas.BifrostResponsesStreamResponse{
+				Response: &schemas.BifrostResponsesResponse{
+					Usage: usage,
+				},
+				ExtraFields: schemas.BifrostResponseExtraFields{
+					RequestType:    schemas.ResponsesStreamRequest,
+					Provider:       providerName,
+					ModelRequested: modelName,
+					ChunkIndex:     chunkIndex,
+					Latency:        time.Since(startTime).Milliseconds(),
+				},
+			}
+			if postResponseConverter != nil {
+				response = postResponseConverter(response)
+			}
+			ctx = context.WithValue(ctx, schemas.BifrostContextKeyStreamEndIndicator, true)
+			providerUtils.ProcessAndSendResponse(ctx, postHookRunner, providerUtils.GetBifrostResponseForStreamResponse(nil, nil, response, nil, nil), responseChan)
 		}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8570c74 and 75053e8.

📒 Files selected for processing (69)
  • core/bifrost.go (2 hunks)
  • core/bifrost_test.go (2 hunks)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (2 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/anthropic_test.go (1 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/gemini/errors.go (2 hunks)
  • core/providers/gemini/gemini.go (0 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/providers/vertex/vertex_test.go (2 hunks)
  • core/schemas/provider.go (2 hunks)
  • core/schemas/utils.go (1 hunks)
  • core/utils.go (1 hunks)
  • core/version (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/changelog.md (1 hunks)
  • framework/modelcatalog/pricing.go (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • framework/version (1 hunks)
  • plugins/governance/changelog.md (1 hunks)
  • plugins/governance/version (1 hunks)
  • plugins/jsonparser/changelog.md (1 hunks)
  • plugins/jsonparser/version (1 hunks)
  • plugins/logging/changelog.md (1 hunks)
  • plugins/logging/main.go (8 hunks)
  • plugins/logging/operations.go (5 hunks)
  • plugins/logging/version (1 hunks)
  • plugins/maxim/changelog.md (1 hunks)
  • plugins/maxim/version (1 hunks)
  • plugins/mocker/changelog.md (1 hunks)
  • plugins/mocker/version (1 hunks)
  • plugins/otel/changelog.md (1 hunks)
  • plugins/otel/version (1 hunks)
  • plugins/semanticcache/changelog.md (1 hunks)
  • plugins/semanticcache/version (1 hunks)
  • plugins/telemetry/changelog.md (1 hunks)
  • plugins/telemetry/version (1 hunks)
  • transports/bifrost-http/handlers/providers.go (9 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/bifrost-http/lib/config.go (1 hunks)
  • transports/bifrost-http/server/server.go (0 hunks)
  • transports/changelog.md (1 hunks)
  • transports/version (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
  • ui/lib/types/schemas.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • transports/bifrost-http/server/server.go
  • core/providers/utils/utils.go
  • core/providers/gemini/gemini.go
✅ Files skipped from review due to trivial changes (8)
  • docs/integrations/what-is-an-integration.mdx
  • plugins/otel/changelog.md
  • transports/bifrost-http/integrations/router.go
  • plugins/semanticcache/changelog.md
  • plugins/maxim/changelog.md
  • plugins/logging/version
  • plugins/otel/version
  • plugins/governance/changelog.md
🚧 Files skipped from review as they are similar to previous changes (28)
  • docs/integrations/langchain-sdk.mdx
  • plugins/semanticcache/version
  • framework/modelcatalog/pricing.go
  • docs/integrations/anthropic-sdk.mdx
  • docs/integrations/litellm-sdk.mdx
  • core/providers/openai/chat.go
  • plugins/mocker/version
  • core/chatbot_test.go
  • framework/streaming/responses.go
  • framework/version
  • transports/version
  • plugins/telemetry/version
  • transports/changelog.md
  • core/providers/azure/types.go
  • plugins/maxim/version
  • core/bifrost_test.go
  • plugins/governance/version
  • framework/changelog.md
  • plugins/mocker/changelog.md
  • core/version
  • core/bifrost.go
  • plugins/logging/changelog.md
  • plugins/telemetry/changelog.md
  • docs/quickstart/gateway/provider-configuration.mdx
  • ui/app/workspace/logs/views/logChatMessageView.tsx
  • docs/quickstart/go-sdk/provider-configuration.mdx
  • docs/features/unified-interface.mdx
  • docs/integrations/genai-sdk.mdx
🧰 Additional context used
🧬 Code graph analysis (9)
core/utils.go (2)
core/schemas/provider.go (1)
  • NetworkConfig (45-53)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
core/providers/anthropic/chat.go (2)
core/schemas/chatcompletions.go (1)
  • BifrostChatRequest (12-19)
core/providers/anthropic/types.go (1)
  • AnthropicMessageRequest (39-58)
core/providers/bedrock/bedrock.go (3)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/bedrock/types.go (1)
  • BedrockAnthropicTextResponse (235-239)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/providers/vertex/errors.go (4)
core/providers/vertex/vertex.go (1)
  • VertexError (25-31)
core/providers/vertex/types.go (1)
  • VertexValidationError (154-161)
core/providers/utils/utils.go (2)
  • NewBifrostOperationError (449-460)
  • NewProviderAPIError (464-479)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (30-30)
ui/app/workspace/logs/views/logDetailsSheet.tsx (1)
ui/components/ui/sheet.tsx (1)
  • SheetContent (140-140)
transports/bifrost-http/handlers/providers.go (3)
core/schemas/provider.go (2)
  • NetworkConfig (45-53)
  • ConcurrencyAndBufferSize (128-131)
transports/bifrost-http/handlers/utils.go (1)
  • SendError (35-44)
transports/bifrost-http/lib/config.go (2)
  • MinRetryBackoff (43-43)
  • MaxRetryBackoff (44-44)
plugins/logging/main.go (1)
core/schemas/bifrost.go (1)
  • BifrostContextKeyNumberOfRetries (111-111)
core/providers/azure/azure.go (3)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • Ptr (16-18)
core/providers/azure/types.go (2)
  • AzureAnthropicAPIVersionDefault (6-6)
  • AzureAPIVersionDefault (4-4)
core/utils.go (1)
  • Ptr (51-53)
core/schemas/provider.go (1)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
🪛 LanguageTool
core/changelog.md

[style] ~3-~3: Consider using a different verb for a more formal wording.
Context: ...en serializing/deserializing from JSON, fixing issues where values were incorrectly in...

(FIX_RESOLVE)

🔇 Additional comments (57)
plugins/jsonparser/version (1)

1-1: Version bump to 1.3.42 looks good

Single-line version update only; no issues from this file in isolation.

plugins/logging/main.go (7)

192-196: Minor doc-comment formatting changes look fine.

The empty // line additions in the doc comments are stylistic and don't affect functionality.


205-209: Doc-comment formatting is consistent with the other changes.


334-338: Doc-comment formatting is consistent.


359-370: NumberOfRetries retrieval and assignment look correct.

The value is properly retrieved from context using getIntFromContext with the correct context key (BifrostContextKeyNumberOfRetries), and assigned to the log message for later propagation.


399-402: NumberOfRetries correctly passed to updateLogEntry for error case.


438-442: NumberOfRetries correctly passed to updateStreamingLogEntry.


565-568: NumberOfRetries correctly passed to updateLogEntry for success case.

The propagation of NumberOfRetries is consistent across all three code paths (error, streaming, and regular response).

plugins/logging/operations.go (3)

25-41: Initial log entry creation changes look correct.

The struct initialization reformatting and addition of new parsed fields (ParamsParsed, ToolsParsed, SpeechInputParsed, TranscriptionInputParsed) are consistent with the schema.


57-76: Verify the intent of skipping number_of_retries when value is 0.

The condition if numberOfRetries != 0 means that when there are no retries (value is 0), the field won't be included in the update. This could be intentional to avoid unnecessary database writes, but it also means you can't distinguish between "0 retries" and "retries not tracked" in the logs.

If distinguishing these cases matters, consider using a pointer type *int or always setting the field.


183-200: Streaming update follows the same pattern for numberOfRetries.

The logic mirrors the non-streaming update function, maintaining consistency. The same consideration about != 0 check applies here.

docs/quickstart/go-sdk/multimodal.mdx (1)

335-337: Documentation consolidation improves maintainability.

Replacing inline provider capability tables with a single reference to the Unified Interface page reduces duplication and provides a single source of truth. However, ensure the referenced page includes all updated capabilities, especially the newly added Azure Anthropic support.

A previous review flagged an inconsistency in Azure Text-to-Speech capability status across documentation pages. Please verify that the Unified Interface page (docs/features/unified-interface.mdx) accurately reflects current Azure multimodal capabilities before merging this change.

core/internal/testutil/account.go (2)

195-196: LGTM!

The new claude-opus-4-5 deployment entry correctly enables testing of Anthropic models on Azure, aligning with the PR's objective to add Claude support in Azure.


651-651: LGTM!

Comment updated to reflect the broader "Azure" branding, consistent with the PR's documentation changes.

docs/features/keys-management.mdx (1)

198-198: LGTM!

The heading update from "Azure OpenAI" to "Azure" accurately reflects the expanded provider capabilities (supporting both OpenAI and Anthropic models).

transports/bifrost-http/handlers/providers.go (3)

228-234: LGTM!

Good addition of retry backoff validation before persisting the provider config. This prevents invalid configurations from being stored.


414-423: LGTM!

Creating a local copy nc before validation and assignment is a clean approach that avoids mutating the payload directly.


871-896: LGTM!

The validateRetryBackoff function is well-implemented with:

  • Proper nil check for networkConfig
  • Bounds validation against lib.MinRetryBackoff and lib.MaxRetryBackoff
  • Relationship validation ensuring initial ≤ max
  • Only validates non-zero values, allowing defaults to be applied later
core/schemas/provider.go (3)

37-53: LGTM!

Excellent documentation explaining the JSON serialization semantics. The comments clearly describe the milliseconds-in-JSON vs. nanoseconds-in-Go duality.


55-90: LGTM!

The UnmarshalJSON implementation correctly:

  • Uses an alias type to prevent infinite recursion
  • Interprets JSON values as milliseconds and converts to time.Duration
  • Only converts positive values, allowing zero to trigger default handling

92-117: LGTM!

The MarshalJSON implementation correctly converts time.Duration back to milliseconds for JSON output, maintaining consistency with the UI's expected format.

core/providers/anthropic/chat.go (1)

384-386: LGTM!

The function rename from ToAnthropicChatCompletionRequest to ToAnthropicChatRequest improves consistency with the naming conventions used across the codebase.

ui/README.md (1)

84-88: Provider branding text is consistent with code

Updating the supported providers list to use “Azure” (instead of “Azure OpenAI”) matches the new ProviderLabels.azure value and the broader branding shift. No further changes needed here.

ui/lib/constants/logs.ts (1)

42-59: Azure provider label update aligns with new branding

Renaming ProviderLabels.azure to “Azure” keeps logs UI consistent with the updated documentation and README while preserving the existing provider key ("azure"). Looks good.

transports/bifrost-http/lib/config.go (1)

41-45: LGTM - well-documented retry backoff constants.

The constants are appropriately typed as time.Duration and clearly documented. The 1000-second maximum is generous but provides flexibility for edge cases with long-running operations.

ui/app/workspace/logs/views/logDetailsSheet.tsx (1)

39-56: LGTM - minor UI layout improvement.

Adding gap-4 to SheetContent provides consistent vertical spacing between child elements. The button formatting change is purely cosmetic with no behavioral impact.

core/providers/vertex/vertex_test.go (1)

30-46: LGTM - good documentation of disabled feature.

The commented-out ReasoningModel hint and explicit Reasoning: false with explanatory comment clearly document the current limitation and intended future direction. This is helpful for maintainability.

core/providers/bedrock/bedrock.go (1)

529-545: LGTM - good refactor to centralized model detection.

Switching to schemas.IsAnthropicModel and schemas.IsMistralModel utilities centralizes model-family detection logic, improving consistency across providers. The new default case with an explicit error is a valuable addition that prevents silent failures for unsupported model types.

core/providers/azure/azure_test.go (1)

32-34: claude-opus-4-5 is properly configured for Azure reasoning tests.

The model is explicitly registered in Azure's deployment configuration (testutil/account.go:195), confirming it is a valid and supported identifier for Azure Anthropic deployments. The test setup is correct and the environment has the corresponding deployment configured.

core/providers/anthropic/anthropic_test.go (1)

31-32: LGTM!

The addition of ReasoningModel with claude-opus-4-5 properly complements the Reasoning: true scenario configuration and aligns with the test infrastructure for validating reasoning capabilities.

core/changelog.md (1)

1-3: LGTM!

Clear and informative changelog entries. The breaking change documentation properly explains the behavioral change and the fix applied for JSON millisecond handling.

docs/integrations/openai-sdk.mdx (1)

99-99: LGTM!

The terminology update from "Azure OpenAI" to "Azure" correctly reflects that the Azure provider now supports multiple model families (OpenAI and Anthropic), making the documentation more accurate and future-proof.

Also applies to: 141-141, 319-319

ui/lib/types/schemas.ts (1)

217-222: LGTM with observation: Validation bounds are appropriate.

The bounds (100ms–1,000,000ms) are sensible for retry backoff configuration in a form context.

Note: networkConfigSchema (lines 184-185) has slightly different constraints (retry_backoff_max min is 1000ms vs 100ms here). This appears intentional—the form schema is more lenient during input, while the stricter schema applies to final configuration. Verify this asymmetry is expected.

core/providers/azure/azure.go (5)

63-127: LGTM!

The completeRequest refactoring properly:

  • Accepts deployment as a parameter for consistent routing
  • Uses IsAnthropicModel(deployment) for model-family detection (per learnings)
  • Sets appropriate headers: x-api-key + anthropic-version for Anthropic, api-key/Bearer for OpenAI
  • Constructs correct URLs for each path

352-426: LGTM!

ChatCompletion correctly:

  • Resolves deployment upfront via getModelDeployment
  • Routes request transformation, URL path, and response parsing based on IsAnthropicModel(deployment)
  • Uses pooled Anthropic response objects with proper acquire/release pattern

432-513: LGTM!

ChatCompletionStream correctly branches between Anthropic and OpenAI streaming:

  • Anthropic: sets x-api-key, anthropic-version, uses HandleAnthropicChatCompletionStreaming
  • OpenAI: uses api-key/Bearer, uses HandleOpenAIChatCompletionStreaming
  • Both paths apply the postResponseConverter for deployment metadata

519-602: LGTM!

Responses and ResponsesStream follow the same consistent pattern:

  • Deployment resolution via getModelDeployment
  • Anthropic/OpenAI routing via IsAnthropicModel(deployment)
  • Appropriate converters (ToAnthropicResponsesRequest / ToOpenAIResponsesRequest)
  • Correct streaming handlers for each path

Also applies to: 605-691


789-800: LGTM!

The getModelDeployment helper provides centralized deployment resolution with proper validation and clear error messages.

core/schemas/utils.go (1)

1041-1050: Case-sensitivity is not a practical concern—cloud providers use lowercase model identifiers.

The helpers correctly match lowercase substrings. Real-world model identifiers from Anthropic, Google Vertex, and AWS Bedrock APIs are always lowercase (e.g., "claude-3-sonnet-20241022", "mistral-7b"), so the current implementation handles all production cases correctly. The case-insensitive refactor is unnecessary.

core/providers/vertex/vertex.go (9)

299-339: LGTM! Clean model-family routing for chat completion request body.

The refactored request body construction properly uses schemas.IsAnthropicModel for centralized model detection and routes to the appropriate converter (ToAnthropicChatRequest vs ToOpenAIChatRequest). The Anthropic-specific version handling and field cleanup are correctly applied.


373-397: LGTM! Endpoint URL construction properly routes by model family.

The URL logic correctly handles four distinct cases:

  1. Fine-tuned models (all-digit deployment) → OpenAPI endpoint with API key query
  2. Anthropic models → Anthropic publisher rawPredict
  3. Mistral models → mistralai publisher rawPredict
  4. Other models (Gemini) → OpenAPI endpoint

440-495: LGTM! Response handling uses renamed pool functions correctly.

The error parsing is now centralized via parseVertexError, and the Anthropic response path correctly uses the renamed AcquireAnthropicMessageResponse/ReleaseAnthropicMessageResponse functions. ExtraFields population including conditional ModelDeployment is consistent.


519-524: LGTM! Post-response converter for streaming deployment metadata.

Clean closure that conditionally sets ModelDeployment when it differs from the requested model, consistent with non-streaming paths.


526-601: LGTM! Anthropic streaming path with proper header and converter setup.

The streaming logic correctly:

  • Converts request via ToAnthropicChatRequest
  • Sets up OAuth headers for Vertex authentication
  • Passes postResponseConverter to attach deployment metadata

658-677: LGTM! Non-Anthropic streaming path with converters.

The postRequestConverter and postResponseConverter are correctly passed to the OpenAI streaming handler for model deployment and response metadata.


684-829: LGTM! Full Anthropic support in Responses method.

The new Anthropic path properly:

  • Validates configuration upfront
  • Converts request via ToAnthropicResponsesRequest
  • Handles OAuth authentication
  • Uses parseVertexError for error handling
  • Populates ExtraFields including conditional ModelDeployment

The non-Anthropic fallback correctly delegates to ChatCompletion and transforms the response.


833-944: LGTM! ResponsesStream with Anthropic and ChatCompletion fallback.

The implementation correctly:

  • Validates configuration and routes by model family
  • Uses HandleAnthropicResponsesStream for Anthropic models with proper headers and converter
  • Falls back to ChatCompletionStream for non-Anthropic models with context flag for fallback indication

1064-1066: LGTM! Embedding deployment metadata consistency.

The conditional ModelDeployment assignment matches the pattern used in other methods.

core/providers/anthropic/anthropic.go (9)

30-56: LGTM! Clean pool and function renaming.

The rename from anthropicChatResponsePool to anthropicMessageResponsePool (and corresponding acquire/release functions) better reflects that this pool handles AnthropicMessageResponse objects, improving code clarity.


318-332: LGTM! ChatCompletion uses renamed functions consistently.

The ToAnthropicChatRequest and AcquireAnthropicMessageResponse/ReleaseAnthropicMessageResponse calls are correctly updated.


369-404: LGTM! ChatCompletionStream updated for shared streaming.

The ToAnthropicChatRequest usage is correct, and passing nil for postResponseConverter is appropriate since the Anthropic provider doesn't need deployment metadata transformation.


407-421: LGTM! Shared streaming signature extended for flexibility.

The addition of postResponseConverter parameter enables providers like Vertex to attach deployment metadata while keeping the Anthropic provider's usage simple with nil.


564-570: Good nil-safety for postResponseConverter.

The check ensures that if postResponseConverter returns nil, the chunk is skipped with a warning rather than causing a panic. This defensive coding handles edge cases gracefully.


685-708: LGTM! ResponsesStream refactored to use shared helper.

The headers map construction is clean, and delegation to HandleAnthropicResponsesStream with nil for postResponseConverter matches the pattern from ChatCompletionStream.


711-725: LGTM! HandleAnthropicResponsesStream signature mirrors chat completion.

The shared streaming helper has a consistent signature with HandleAnthropicChatCompletionStreaming, enabling code reuse across Vertex and Anthropic providers.


836-838: LGTM! Model name tracking for stream events.

Capturing modelName from the first message_start event ensures error reporting and response metadata include the correct model identifier.


638-639: LGTM! Responses method uses renamed pool functions.

Consistent with the rest of the file.

Comment thread docs/quickstart/gateway/multimodal.mdx
Comment thread transports/bifrost-http/handlers/providers.go
Comment thread transports/bifrost-http/handlers/providers.go
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch from 75053e8 to ec258f0 Compare December 1, 2025 07:14

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
docs/apis/openapi.json (1)

1757-1804: Inconsistent parameter description in deployment-id—should align with updated branding strategy.

The changes to lines 1759-1760 and 1788 correctly rebrand to "OpenAI Compatible," but line 1892's parameter description still references "Azure deployment ID" instead of the generic "Deployment ID" applied at line 1770.

Similarly, the same inconsistency appears in the responses (line 2014), embeddings (line 2126), speech (line 2235), and transcriptions (line 2343) endpoints—some remain "Azure deployment ID" while others should align with the branding shift.

For consistency, update all remaining "Azure deployment ID" descriptions to "Deployment ID" across all deployment endpoints:

  "/openai/deployments/{deployment-id}/chat/completions": {
    "post": {
      "parameters": [
        {
          "name": "deployment-id",
          "in": "path",
          "required": true,
-         "description": "Azure deployment ID",
+         "description": "Deployment ID",

Apply the same change at:

  • Line 1892 (chat/completions)
  • Line 2014 (responses)
  • Line 2126 (embeddings)
  • Line 2235 (audio/speech)
  • Line 2343 (audio/transcriptions)
🧹 Nitpick comments (7)
ui/app/workspace/logs/views/logChatMessageView.tsx (1)

29-29: Good addition, consider applying consistently.

Adding break-words prevents text overflow for long unbroken strings in content blocks.

For consistency, consider applying the same class to other text displays that use whitespace-pre-wrap:

Line 89 (thought content):

-<div className="text-muted-foreground px-6 py-2 font-mono text-xs whitespace-pre-wrap italic">{message.thought}</div>
+<div className="text-muted-foreground px-6 py-2 font-mono text-xs break-words whitespace-pre-wrap italic">{message.thought}</div>

Line 132 (message content string):

-<div className="px-6 py-2 font-mono text-xs whitespace-pre-wrap">{message.content}</div>
+<div className="px-6 py-2 font-mono text-xs break-words whitespace-pre-wrap">{message.content}</div>
framework/streaming/responses.go (1)

684-745: Anthropic-on-Azure routing change looks correct; ensure model detection is exhaustive

Tightening the predicate to:

if provider == schemas.OpenAI ||
   provider == schemas.OpenRouter ||
   (provider == schemas.Azure && !schemas.IsAnthropicModel(model)) {
    // OpenAI-compatible final-chunk path
}

correctly routes Azure Anthropic models to the accumulation logic while preserving the existing fast-path for OpenAI/OpenRouter and non-Anthropic Azure models. This aligns with the intent to treat Azure Anthropic streams like other non-OpenAI-compatible providers.

Two small follow-ups to consider:

  • Verify that all expected Azure Anthropic deployment names (e.g., both anthropic.claude-... and claude-... forms) are covered by schemas.IsAnthropicModel(model) in core/schemas/utils.go, especially if users can customize deployment names.
  • Optional: if similar “OpenAI-compatible” checks exist elsewhere, you might factor this predicate into a helper (e.g., schemas.IsOpenAICompatibleProvider(provider, model)) to keep routing rules centralized.

To double-check coverage, please run a small test matrix hitting streaming for:

  • Azure non-Anthropic (e.g., GPT-style) models and confirm they stay on the final-chunk path.
  • Azure Anthropic (Claude) models and confirm they use the accumulation path and produce complete OutputMessages and TokenUsage.
core/providers/gemini/errors.go (2)

39-64: Inconsistent fallback unmarshaling between streaming and non-streaming error parsers.

parseStreamGeminiError uses interface{} for fallback (line 58), while parseGeminiError uses map[string]interface{} (line 84). If Gemini returns a non-object error (e.g., an array), parseGeminiError will fail to unmarshal it while parseStreamGeminiError will succeed.

Consider using interface{} consistently in both functions for robustness:

-	var rawResponse map[string]interface{}
+	var rawResponse interface{}

84-87: Inconsistent error message with streaming counterpart.

Line 86 uses a hardcoded string "failed to parse error response" while the streaming function (line 60) uses the constant schemas.ErrProviderResponseUnmarshal. For consistency and maintainability, use the same constant.

 	if err := sonic.Unmarshal(body, &rawResponse); err != nil {
-		return providerUtils.NewBifrostOperationError("failed to parse error response", err, providerName)
+		return providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, providerName)
 	}
core/providers/vertex/errors.go (1)

15-29: Variable shadowing: inner vertexErr shadows outer declaration.

Line 17 declares a new vertexErr VertexError which shadows the vertexErr []VertexError from line 12. While this works correctly, it can cause confusion during debugging.

Consider renaming for clarity:

 		if err := sonic.Unmarshal(resp.Body(), &vertexErr); err != nil {
 			//try with single Vertex error format
-			var vertexErr VertexError
-			if err := sonic.Unmarshal(resp.Body(), &vertexErr); err != nil {
+			var singleVertexErr VertexError
+			if err := sonic.Unmarshal(resp.Body(), &singleVertexErr); err != nil {
 				// Try VertexValidationError format (validation errors from Mistral endpoint)
 				var validationErr VertexValidationError
 				if err := sonic.Unmarshal(resp.Body(), &validationErr); err != nil {
 					return providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, providerName)
 				}
 				if len(validationErr.Detail) > 0 {
 					return providerUtils.NewProviderAPIError(validationErr.Detail[0].Msg, nil, resp.StatusCode(), providerName, nil, nil)
 				}
 				return providerUtils.NewProviderAPIError("Unknown error", nil, resp.StatusCode(), providerName, nil, nil)
 			}
-			return providerUtils.NewProviderAPIError(vertexErr.Error.Message, nil, resp.StatusCode(), providerName, nil, nil)
+			return providerUtils.NewProviderAPIError(singleVertexErr.Error.Message, nil, resp.StatusCode(), providerName, nil, nil)
 		}
core/providers/vertex/vertex.go (1)

299-336: Redundant model-family check.

Line 331 re-checks schemas.IsAnthropicModel(deployment) inside the same if-block that already checked it at line 299. While not harmful, you can eliminate the nested check by moving the anthropic_version logic directly into the outer block.

Apply this diff to simplify:

 			if schemas.IsAnthropicModel(deployment) {
 				// Use centralized Anthropic converter
 				reqBody := anthropic.ToAnthropicChatRequest(request)
 				if reqBody == nil {
 					return nil, fmt.Errorf("chat completion input is not provided")
 				}
 				reqBody.Model = deployment
 				// Convert struct to map for Vertex API
 				reqBytes, err := sonic.Marshal(reqBody)
 				if err != nil {
 					return nil, fmt.Errorf("failed to marshal request body: %w", err)
 				}
 				if err := sonic.Unmarshal(reqBytes, &requestBody); err != nil {
 					return nil, fmt.Errorf("failed to unmarshal request body: %w", err)
 				}
+				if _, exists := requestBody["anthropic_version"]; !exists {
+					requestBody["anthropic_version"] = DefaultVertexAnthropicVersion
+				}
+				delete(requestBody, "model")
 			} else {
 				// Use centralized OpenAI converter for non-Claude models
 				reqBody := openai.ToOpenAIChatRequest(request)
 				if reqBody == nil {
 					return nil, fmt.Errorf("chat completion input is not provided")
 				}
 				reqBody.Model = deployment
 				// Convert struct to map for Vertex API
 				reqBytes, err := sonic.Marshal(reqBody)
 				if err != nil {
 					return nil, fmt.Errorf("failed to marshal request body: %w", err)
 				}
 				if err := sonic.Unmarshal(reqBytes, &requestBody); err != nil {
 					return nil, fmt.Errorf("failed to unmarshal request body: %w", err)
 				}
 			}
-
-			if schemas.IsAnthropicModel(deployment) {
-				if _, exists := requestBody["anthropic_version"]; !exists {
-					requestBody["anthropic_version"] = DefaultVertexAnthropicVersion
-				}
-				delete(requestBody, "model")
-			}
 			delete(requestBody, "region")
 			return requestBody, nil
core/providers/anthropic/anthropic.go (1)

901-904: Missing defensive final chunk emission on clean EOF.

Unlike HandleAnthropicChatCompletionStreaming (lines 602-607), this function lacks an else block to emit accumulated usage when the scanner completes successfully without an explicit message_stop event. While Anthropic's API should always send message_stop, adding a defensive final chunk would make the code more robust against unexpected stream terminations.

Apply this diff to add defensive handling:

 		if err := scanner.Err(); err != nil {
 			logger.Warn(fmt.Sprintf("Error reading %s stream: %v", providerName, err))
 			providerUtils.ProcessAndSendError(ctx, postHookRunner, err, responseChan, schemas.ResponsesStreamRequest, providerName, modelName, logger)
+		} else {
+			// Emit final chunk with usage if stream ended without explicit message_stop
+			response := &schemas.BifrostResponsesStreamResponse{
+				Response: &schemas.BifrostResponsesResponse{},
+			}
+			if usage != nil {
+				response.Response.Usage = usage
+			}
+			response.ExtraFields = schemas.BifrostResponseExtraFields{
+				RequestType:    schemas.ResponsesStreamRequest,
+				Provider:       providerName,
+				ModelRequested: modelName,
+				ChunkIndex:     chunkIndex,
+				Latency:        time.Since(startTime).Milliseconds(),
+			}
+			ctx = context.WithValue(ctx, schemas.BifrostContextKeyStreamEndIndicator, true)
+			providerUtils.ProcessAndSendResponse(ctx, postHookRunner, providerUtils.GetBifrostResponseForStreamResponse(nil, nil, response, nil, nil), responseChan)
 		}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75053e8 and ec258f0.

📒 Files selected for processing (69)
  • core/bifrost.go (2 hunks)
  • core/bifrost_test.go (2 hunks)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (2 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/anthropic_test.go (1 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/gemini/errors.go (2 hunks)
  • core/providers/gemini/gemini.go (0 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/providers/vertex/vertex_test.go (2 hunks)
  • core/schemas/provider.go (2 hunks)
  • core/schemas/utils.go (1 hunks)
  • core/utils.go (1 hunks)
  • core/version (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/changelog.md (1 hunks)
  • framework/modelcatalog/pricing.go (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • framework/version (1 hunks)
  • plugins/governance/changelog.md (1 hunks)
  • plugins/governance/version (1 hunks)
  • plugins/jsonparser/changelog.md (1 hunks)
  • plugins/jsonparser/version (1 hunks)
  • plugins/logging/changelog.md (1 hunks)
  • plugins/logging/main.go (8 hunks)
  • plugins/logging/operations.go (5 hunks)
  • plugins/logging/version (1 hunks)
  • plugins/maxim/changelog.md (1 hunks)
  • plugins/maxim/version (1 hunks)
  • plugins/mocker/changelog.md (1 hunks)
  • plugins/mocker/version (1 hunks)
  • plugins/otel/changelog.md (1 hunks)
  • plugins/otel/version (1 hunks)
  • plugins/semanticcache/changelog.md (1 hunks)
  • plugins/semanticcache/version (1 hunks)
  • plugins/telemetry/changelog.md (1 hunks)
  • plugins/telemetry/version (1 hunks)
  • transports/bifrost-http/handlers/providers.go (9 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/bifrost-http/lib/config.go (1 hunks)
  • transports/bifrost-http/server/server.go (0 hunks)
  • transports/changelog.md (1 hunks)
  • transports/version (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
  • ui/lib/types/schemas.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • transports/bifrost-http/server/server.go
  • core/providers/utils/utils.go
  • core/providers/gemini/gemini.go
✅ Files skipped from review due to trivial changes (6)
  • framework/changelog.md
  • docs/integrations/genai-sdk.mdx
  • plugins/otel/changelog.md
  • transports/bifrost-http/integrations/router.go
  • plugins/telemetry/version
  • plugins/semanticcache/changelog.md
🚧 Files skipped from review as they are similar to previous changes (38)
  • docs/quickstart/go-sdk/multimodal.mdx
  • plugins/semanticcache/version
  • docs/integrations/openai-sdk.mdx
  • core/providers/azure/types.go
  • ui/lib/constants/logs.ts
  • ui/app/workspace/logs/views/logDetailsSheet.tsx
  • plugins/logging/version
  • core/providers/vertex/vertex_test.go
  • core/providers/openai/chat.go
  • core/bifrost_test.go
  • transports/version
  • core/chatbot_test.go
  • docs/quickstart/gateway/multimodal.mdx
  • core/providers/anthropic/chat.go
  • framework/modelcatalog/pricing.go
  • core/bifrost.go
  • docs/integrations/what-is-an-integration.mdx
  • docs/quickstart/go-sdk/provider-configuration.mdx
  • plugins/maxim/changelog.md
  • core/internal/testutil/account.go
  • docs/quickstart/gateway/provider-configuration.mdx
  • core/version
  • docs/integrations/langchain-sdk.mdx
  • core/schemas/utils.go
  • docs/features/keys-management.mdx
  • core/providers/anthropic/anthropic_test.go
  • plugins/governance/version
  • transports/bifrost-http/lib/config.go
  • docs/integrations/anthropic-sdk.mdx
  • framework/version
  • plugins/jsonparser/changelog.md
  • plugins/otel/version
  • plugins/maxim/version
  • plugins/mocker/changelog.md
  • ui/lib/types/schemas.ts
  • plugins/governance/changelog.md
  • docs/features/unified-interface.mdx
  • plugins/jsonparser/version
🧰 Additional context used
🧬 Code graph analysis (8)
core/utils.go (2)
core/schemas/provider.go (1)
  • NetworkConfig (45-53)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
framework/streaming/responses.go (2)
core/schemas/bifrost.go (3)
  • OpenAI (35-35)
  • OpenRouter (49-49)
  • Azure (36-36)
core/schemas/utils.go (1)
  • IsAnthropicModel (1043-1045)
core/schemas/provider.go (1)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
core/providers/bedrock/bedrock.go (3)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/bedrock/types.go (1)
  • BedrockAnthropicTextResponse (235-239)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
plugins/logging/main.go (1)
core/schemas/bifrost.go (1)
  • BifrostContextKeyNumberOfRetries (111-111)
core/providers/vertex/errors.go (4)
core/providers/vertex/vertex.go (1)
  • VertexError (25-31)
core/providers/vertex/types.go (1)
  • VertexValidationError (154-161)
core/providers/utils/utils.go (2)
  • NewBifrostOperationError (449-460)
  • NewProviderAPIError (464-479)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (30-30)
core/providers/azure/azure.go (4)
core/schemas/account.go (2)
  • Key (8-17)
  • AzureKeyConfig (21-25)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • Ptr (16-18)
core/providers/azure/types.go (2)
  • AzureAnthropicAPIVersionDefault (6-6)
  • AzureAPIVersionDefault (4-4)
core/utils.go (1)
  • Ptr (51-53)
transports/bifrost-http/handlers/providers.go (4)
core/schemas/provider.go (2)
  • NetworkConfig (45-53)
  • ConcurrencyAndBufferSize (128-131)
ui/lib/types/config.ts (2)
  • NetworkConfig (94-102)
  • ConcurrencyAndBufferSize (105-108)
transports/bifrost-http/handlers/utils.go (1)
  • SendError (35-44)
transports/bifrost-http/lib/config.go (2)
  • MinRetryBackoff (43-43)
  • MaxRetryBackoff (44-44)
🪛 LanguageTool
core/changelog.md

[style] ~3-~3: Consider using a different verb for a more formal wording.
Context: ...en serializing/deserializing from JSON, fixing issues where values were incorrectly in...

(FIX_RESOLVE)

🔇 Additional comments (46)
docs/integrations/litellm-sdk.mdx (1)

73-73: LGTM!

The section header updates accurately reflect that Azure now supports both OpenAI and Anthropic models, not just Azure OpenAI. The changes align with the PR's branding updates and improve documentation clarity.

Also applies to: 146-146

ui/README.md (1)

84-84: Documentation update aligns with PR objectives.

The branding change from "Azure OpenAI" to "Azure" accurately reflects the feature addition of Anthropic (Claude) model support alongside existing OpenAI models in the Azure provider. The provider list is clear and complete.

plugins/logging/changelog.md (1)

1-2: Verify changelog completeness and version accuracy.

The changelog entries follow a clear, conventional format. However, given the broader PR scope (Anthropic support for Azure, framework updates, retry handling improvements), verify that:

  1. These entries capture all relevant changes to the logging plugin in this PR
  2. The version numbers (core 1.2.32, framework 1.1.41) are correct and correspond to the actual version bumps
  3. If the logging plugin had changes related to Anthropic support or other Providers/Integrations updates mentioned in the PR, they should be documented here

If the logging plugin's scope is limited to the version bump and retry fix, these entries are appropriate. Otherwise, consider whether additional entries are needed.

plugins/telemetry/changelog.md (1)

1-1: The changelog entry is correct and follows project conventions.

This entry accurately documents the version cascade from core and framework dependency updates. The logging plugin uses the identical format for the same version updates, confirming this is the standard pattern in the project. Telemetry plugin itself had no functional changes—only a version bump due to dependency updates—which is appropriately documented as a chore entry.

Likely an incorrect or invalid review comment.

plugins/logging/main.go (4)

359-370: LGTM!

The numberOfRetries is correctly retrieved from the context and assigned to the log message. This ensures retry metrics are captured for all request types.


390-403: Correctly propagates retry count in error path.

The numberOfRetries is properly passed to updateLogEntry ensuring retry metrics are logged even for failed requests.


430-443: LGTM!

Streaming log updates correctly include the retry count.


556-569: LGTM!

Regular (non-streaming) log updates correctly include the retry count, completing the consistent propagation across all update paths.

plugins/logging/operations.go (3)

24-41: LGTM!

The initial log entry correctly omits numberOfRetries since retries haven't occurred yet at PreHook time. The retry count is appropriately set later via update functions.


57-76: LGTM!

The numberOfRetries parameter is correctly added and conditionally included in updates only when non-zero, which is an appropriate optimization.


183-200: LGTM!

Consistent implementation with updateLogEntry. The streaming log update function correctly handles the numberOfRetries parameter with the same conditional logic.

framework/streaming/responses.go (1)

592-599: Comment accurately documents lock/cleanup ordering

The updated comment now clearly matches the existing behavior (cleanup while holding the lock, then unlock), which is correct for preventing other goroutines from seeing chunks after they’re returned to the pool. No functional issues here.

core/providers/bedrock/bedrock.go (1)

528-545: LGTM! Good refactor to centralize model-type detection.

The switch from inline string containment checks to schemas.IsAnthropicModel() and schemas.IsMistralModel() helpers improves code maintainability and ensures consistent model detection across all providers. The explicit default case with a descriptive error message is a good addition.

core/changelog.md (1)

1-3: LGTM! Changelog entries accurately document the changes.

The breaking change entry for NetworkConfig retry backoff values is well-documented with clear explanation of the behavioral change (milliseconds in JSON vs. nanoseconds internally).

transports/changelog.md (1)

1-5: LGTM! Changelog entries are well-organized.

The entries accurately reflect the features, fixes, and version updates in this PR.

core/schemas/provider.go (2)

55-90: LGTM! Custom JSON marshaling correctly handles millisecond interop.

The alias type pattern properly avoids infinite recursion, and the millisecond conversion logic aligns with the UI TypeScript types (ui/lib/types/config.ts lines 97-98). The > 0 guard appropriately prevents conversion of unset values.


92-117: LGTM! MarshalJSON implementation is symmetric with UnmarshalJSON.

The conversion from time.Duration to milliseconds via integer division is appropriate for backoff configuration values.

transports/bifrost-http/handlers/providers.go (5)

228-234: LGTM!

Retry backoff validation is correctly placed before config persistence, with appropriate error messaging.


286-290: LGTM!

The fasthttp.RequestCtx recycling issue has been correctly addressed by using context.Background() in the goroutine.


414-423: LGTM!

The validation flow correctly validates the network config before assignment.


465-469: LGTM!

The fasthttp.RequestCtx recycling issue has been correctly addressed.


871-896: Consider edge case when only one backoff value is provided.

When RetryBackoffInitial > 0 but RetryBackoffMax == 0 (or vice versa), the cross-validation at lines 889-893 is skipped. If defaults are applied elsewhere, ensure the provided value doesn't conflict with the default. For example, if a user sets RetryBackoffInitial = 500ms but RetryBackoffMax defaults to 200ms, this could cause issues.

If defaults are guaranteed to be sane and this is handled elsewhere, this is fine as-is.

core/providers/azure/azure_test.go (1)

32-34: Verify reasoning test compatibility with Claude model.

The ReasoningModel changed from "o1" (OpenAI) to "claude-opus-4-5" (Anthropic). Ensure the reasoning test scenarios are compatible with Claude's response format, as Claude's "extended thinking" differs from OpenAI's reasoning model behavior.

core/providers/vertex/errors.go (1)

10-38: LGTM overall - error parsing handles multiple formats correctly.

The function properly tries multiple error formats (OpenAI, Vertex array, single Vertex, validation error) and uses providerName consistently. The past review issue regarding the unused parameter has been addressed.

core/providers/azure/azure.go (8)

22-28: LGTM!

Adding networkConfig and sendBackRawResponse to the provider struct improves encapsulation.


113-116: Verify error parsing for Anthropic responses.

Line 115 uses openai.ParseOpenAIError for all error responses, including Anthropic models. If Azure's Anthropic endpoint returns Anthropic-style errors (different structure from OpenAI), this may produce unclear error messages or miss error details.

Consider branching error parsing based on model type:

 	if resp.StatusCode() != fasthttp.StatusOK {
-		return nil, deployment, latency, openai.ParseOpenAIError(resp, requestType, provider.GetProviderKey(), model)
+		if schemas.IsAnthropicModel(deployment) {
+			return nil, deployment, latency, anthropic.ParseAnthropicError(resp, requestType, provider.GetProviderKey(), model)
+		}
+		return nil, deployment, latency, openai.ParseOpenAIError(resp, requestType, provider.GetProviderKey(), model)
 	}

The Anthropic API error format uses "a top-level error object that always includes a type and message value" - this differs from OpenAI's error structure. The current code may not extract error details correctly for Anthropic responses from Azure.


352-412: LGTM!

The ChatCompletion method correctly:

  1. Resolves deployment first via getModelDeployment
  2. Uses IsAnthropicModel(deployment) consistently for routing decisions (addressing past review feedback)
  3. Properly branches request body conversion and response parsing for Anthropic vs OpenAI

449-513: LGTM!

The streaming implementation correctly branches based on IsAnthropicModel(deployment):

  • Anthropic path: uses x-api-key and anthropic-version headers, delegates to HandleAnthropicChatCompletionStreaming
  • OpenAI path: uses api-key or Bearer token, delegates to HandleOpenAIChatCompletionStreaming

519-602: LGTM!

The Responses method follows the same correct pattern as ChatCompletion, with proper Anthropic/OpenAI branching for request conversion, path construction, and response parsing.


604-691: LGTM!

The ResponsesStream method correctly implements the same streaming pattern as ChatCompletionStream with proper Anthropic/OpenAI branching.


789-800: LGTM!

The getModelDeployment helper correctly validates configuration and looks up the deployment from the Azure key config.


294-342: LGTM!

TextCompletionStream correctly uses only the OpenAI path since Anthropic models don't support the text completion API (they use the Messages API instead).

core/providers/vertex/vertex.go (8)

443-471: LGTM!

The Anthropic response handling correctly uses the renamed pool functions and properly populates ExtraFields with deployment metadata.


486-488: LGTM!

The conditional ModelDeployment assignment ensures consistent metadata tracking across both Anthropic and non-Anthropic paths.


519-524: LGTM!

The postResponseConverter correctly injects deployment metadata into streaming responses.


526-601: LGTM!

The Anthropic streaming path correctly uses the renamed converter, constructs headers, and passes the postResponseConverter to the shared streaming handler.


658-661: LGTM!

The postRequestConverter correctly sets the deployment model name, ensuring consistent request handling across OpenAI-compatible endpoints.


683-829: LGTM!

The Responses method correctly implements Anthropic-specific handling with proper ExtraFields population and falls back to ChatCompletion for non-Anthropic models, preserving latency through the conversion.


914-919: LGTM!

The postResponseConverter for ResponsesStream correctly mirrors the pattern used in ChatCompletionStream, ensuring consistent deployment metadata injection.


1064-1066: LGTM!

The conditional ModelDeployment assignment in the Embedding method ensures consistent metadata tracking across all request types.

core/providers/anthropic/anthropic.go (6)

30-56: LGTM!

The pool renaming from anthropicChatResponsePool to anthropicMessageResponsePool is consistently applied across all accessor functions.


318-318: LGTM!

The renamed ToAnthropicChatRequest function is correctly used in ChatCompletion.


417-420: LGTM!

The signature changes correctly add the postResponseConverter hook and rename providerType to the more accurate providerName.


564-570: LGTM!

The nil-safety check for postResponseConverter prevents panics and provides helpful debugging output when a converter returns nil.


685-708: LGTM!

The ResponsesStream implementation correctly constructs headers as a map and delegates to the shared HandleAnthropicResponsesStream handler.


836-838: LGTM!

The modelName tracking correctly captures the model name from the stream events and uses it in error handling and response metadata.

Comment thread core/utils.go
Comment thread plugins/mocker/version
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch 2 times, most recently from 07c2a7d to e0c170f Compare December 1, 2025 08:28

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 (3)
plugins/logging/operations.go (1)

163-170: Operator precedence issue may cause unintended behavior.

The condition p.disableContentLogging == nil || !*p.disableContentLogging && data.RawResponse != nil evaluates as (nil) || ((!*p.disableContentLogging) && (data.RawResponse != nil)) due to && having higher precedence than ||.

This means when p.disableContentLogging is nil, the block executes regardless of whether data.RawResponse is nil, potentially marshaling a nil value.

Add parentheses to clarify intent:

-	if p.disableContentLogging == nil || !*p.disableContentLogging && data.RawResponse != nil {
+	if (p.disableContentLogging == nil || !*p.disableContentLogging) && data.RawResponse != nil {
core/providers/azure/azure.go (1)

114-116: Use Anthropic-specific error parsing for Anthropic endpoints.

When the status code is not OK, the code calls openai.ParseOpenAIError for both Anthropic and OpenAI responses. Anthropic error responses have a different structure ({"type": "error", "error": {"type": "...", "message": "..."}}) than OpenAI, and the standalone Anthropic provider handles this correctly by parsing the AnthropicError struct. The Azure provider should use similar Anthropic-specific error parsing for Anthropic deployments instead of the OpenAI parser.

core/providers/anthropic/anthropic.go (1)

583-583: Refactor: Inconsistent raw response handling between streaming functions.

Line 583 in HandleAnthropicChatCompletionStreaming checks sendBackRawResponse directly:

if sendBackRawResponse {

However, line 876 in HandleAnthropicResponsesStream uses a utility wrapper:

if providerUtils.ShouldSendBackRawResponse(ctx, sendBackRawResponse) && i == len(responses)-1 {

The ShouldSendBackRawResponse helper likely checks for context-based overrides in addition to the boolean flag. For consistency and correctness, both functions should use the same pattern.

Update line 583 to use the utility wrapper:

-				if sendBackRawResponse {
+				if providerUtils.ShouldSendBackRawResponse(ctx, sendBackRawResponse) {
 					response.ExtraFields.RawResponse = eventData
 				}

Also applies to: 876-876

♻️ Duplicate comments (1)
core/utils.go (1)

75-84: LGTM on clamping logic; comment issue persists.

The additional clamping of the final result (min(result, config.NetworkConfig.RetryBackoffMax)) correctly ensures the backoff never exceeds the configured maximum even after jitter is applied, which is an important safety guarantee.

However, the comment on line 79 still says "Add jitter (20%)" when it should say "Add jitter (±20%)" to accurately reflect the range [0.8, 1.2]. This was previously flagged in past review comments.

Apply this diff to fix the comment:

-	// Add jitter (20%)
+	// Add jitter (±20%)
🧹 Nitpick comments (8)
plugins/maxim/changelog.md (1)

1-1: Consider adding a more descriptive changelog entry for feature visibility.

The current entry only documents the version bump. Given the PR's scope (Anthropic/Claude model support in Azure, deployment routing, streaming enhancements, etc.), a more detailed changelog entry would help users understand what's new in this release.

Example of a more informative entry:

-- chore: version update core to 1.2.32 and framework to 1.1.41
+- feat: add Anthropic/Claude model support in Azure provider with native streaming
+- feat: implement deployment-aware routing and headers for Azure Anthropic models
+- fix: centralize Vertex error parsing for improved error handling
+- chore: rename Anthropic APIs for consistency and update branding from "Azure OpenAI" to "Azure"
+- chore: version update core to 1.2.32 and framework to 1.1.41

Alternatively, if minimal version-only entries are your project's standard, this is fine as-is.

ui/app/workspace/logs/views/logChatMessageView.tsx (1)

29-29: Good call adding break-words; consider aligning other text blocks for consistency

Adding break-words here should help prevent horizontal scrolling for long, unbroken log text while preserving whitespace-pre-wrap. Looks correct and low‑risk.

You may optionally also add break-words to other non‑JSON text containers (e.g., the plain message.content and message.thought divs) so wrapping behavior is consistent across all text sections in this view.

core/schemas/utils.go (1)

1042-1050: Consider case-insensitive matching and update function comments.

Two observations:

  1. The comments reference "in Vertex" but per the AI summary, these helpers are also used in Bedrock. Consider updating to "checks if the model is an Anthropic/Mistral model" without provider-specific context.

  2. The matching is case-sensitive. If model strings could arrive in mixed case (e.g., "Claude-3" or "MISTRAL"), this would fail to match.

-// IsAnthropicModel checks if the model is an Anthropic model in Vertex.
+// IsAnthropicModel checks if the model is an Anthropic model.
 func IsAnthropicModel(model string) bool {
-	return strings.Contains(model, "anthropic.") || strings.Contains(model, "claude")
+	lowerModel := strings.ToLower(model)
+	return strings.Contains(lowerModel, "anthropic.") || strings.Contains(lowerModel, "claude")
 }

-// IsMistralModel checks if the model is a Mistral or Codestral model in Vertex.
+// IsMistralModel checks if the model is a Mistral or Codestral model.
 func IsMistralModel(model string) bool {
-	return strings.Contains(model, "mistral") || strings.Contains(model, "codestral")
+	lowerModel := strings.ToLower(model)
+	return strings.Contains(lowerModel, "mistral") || strings.Contains(lowerModel, "codestral")
 }
core/providers/gemini/errors.go (1)

39-64: Minor inconsistencies between error parsing functions.

The two new error parsing functions have similar logic but some inconsistencies:

  1. StatusCode type casting (lines 48 vs 75):

    • parseStreamGeminiError: schemas.Ptr(int(resp.StatusCode()))
    • parseGeminiError: schemas.Ptr(resp.StatusCode())
  2. Raw response fallback type (lines 58 vs 84):

    • parseStreamGeminiError: var rawResponse interface{}
    • parseGeminiError: var rawResponse map[string]interface{}

These inconsistencies don't cause bugs but reduce maintainability.

 // parseStreamGeminiError parses Gemini streaming error responses
 func parseStreamGeminiError(providerName schemas.ModelProvider, resp *fasthttp.Response) *schemas.BifrostError {
 	body := append([]byte(nil), resp.Body()...)

 	// Try to parse as JSON first
 	var errorResp GeminiGenerationError
 	if err := sonic.Unmarshal(body, &errorResp); err == nil {
 		bifrostErr := &schemas.BifrostError{
 			IsBifrostError: false,
-			StatusCode:     schemas.Ptr(int(resp.StatusCode())),
+			StatusCode:     schemas.Ptr(resp.StatusCode()),
 			Error: &schemas.ErrorField{
 				Code:    schemas.Ptr(strconv.Itoa(errorResp.Error.Code)),
 				Message: errorResp.Error.Message,
 			},
 		}
 		return bifrostErr
 	}

 	// If JSON parsing fails, use the raw response body
-	var rawResponse interface{}
+	var rawResponse map[string]interface{}
 	if err := sonic.Unmarshal(body, &rawResponse); err != nil {
 		return providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, providerName)
 	}

Also applies to: 66-90

docs/apis/openapi.json (1)

1759-1760: Deployment-specific OpenAI-compatible docs look good; consider unifying deployment-id wording

The branding/summary/description updates for the /openai/deployments/{deployment-id}/… endpoints correctly describe them as OpenAI-compatible deployment-scoped APIs and align with the rest of the OpenAI integration docs.

One minor nit: for some deployment endpoints you now use the generic "Deployment ID" wording for the deployment-id path param, while others still say "Azure deployment ID". For consistency across all /openai/deployments/{deployment-id}/… routes, consider normalizing these descriptions to the same generic phrasing.

Also applies to: 1770-1770, 1788-1788, 1881-1882, 1910-1910, 2003-2004, 2032-2032, 2115-2116, 2144-2144, 2224-2225, 2332-2333

core/providers/azure/types.go (1)

3-6: Azure Anthropic default API version constant is fine; consider config-driven override later

Adding AzureAnthropicAPIVersionDefault = "2023-06-01" cleanly separates Anthropic API versioning from the main Azure default. Over time, if regions or deployments diverge on supported versions, you may want this to be driven via per-key or per-deployment config rather than a single global constant, but it’s perfectly reasonable for now.

framework/modelcatalog/utils.go (1)

21-30: Bedrock normalization in normalizeProvider improves catalog consistency

Normalizing any provider string containing "bedrock" to schemas.Bedrock should deduplicate pricing/catalog entries that come from different Bedrock labels (e.g., vendor-prefixed names) into a single provider bucket. If more aliases appear for other providers later, this pattern is a good place to extend them.

core/providers/anthropic/anthropic.go (1)

836-838: Edge case: modelName may remain empty if first event lacks message.

The modelName is only set when event.Message != nil && modelName == "" (lines 836-838). If the first event that should populate modelName doesn't contain a Message field, modelName will remain an empty string for all subsequent error messages and response metadata.

While Anthropic's API should reliably include the model name in the message_start event, consider adding a fallback or logging a warning if modelName remains empty after the stream completes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec258f0 and e0c170f.

📒 Files selected for processing (70)
  • core/bifrost.go (2 hunks)
  • core/bifrost_test.go (2 hunks)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (2 hunks)
  • core/providers/anthropic/anthropic.go (22 hunks)
  • core/providers/anthropic/anthropic_test.go (1 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/gemini/errors.go (2 hunks)
  • core/providers/gemini/gemini.go (0 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/providers/vertex/vertex_test.go (2 hunks)
  • core/schemas/provider.go (2 hunks)
  • core/schemas/utils.go (1 hunks)
  • core/utils.go (1 hunks)
  • core/version (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/changelog.md (1 hunks)
  • framework/modelcatalog/pricing.go (7 hunks)
  • framework/modelcatalog/utils.go (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • framework/version (1 hunks)
  • plugins/governance/changelog.md (1 hunks)
  • plugins/governance/version (1 hunks)
  • plugins/jsonparser/changelog.md (1 hunks)
  • plugins/jsonparser/version (1 hunks)
  • plugins/logging/changelog.md (1 hunks)
  • plugins/logging/main.go (8 hunks)
  • plugins/logging/operations.go (5 hunks)
  • plugins/logging/version (1 hunks)
  • plugins/maxim/changelog.md (1 hunks)
  • plugins/maxim/version (1 hunks)
  • plugins/mocker/changelog.md (1 hunks)
  • plugins/mocker/version (1 hunks)
  • plugins/otel/changelog.md (1 hunks)
  • plugins/otel/version (1 hunks)
  • plugins/semanticcache/changelog.md (1 hunks)
  • plugins/semanticcache/version (1 hunks)
  • plugins/telemetry/changelog.md (1 hunks)
  • plugins/telemetry/version (1 hunks)
  • transports/bifrost-http/handlers/providers.go (9 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/bifrost-http/lib/config.go (1 hunks)
  • transports/bifrost-http/server/server.go (0 hunks)
  • transports/changelog.md (1 hunks)
  • transports/version (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
  • ui/lib/types/schemas.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • core/providers/utils/utils.go
  • transports/bifrost-http/server/server.go
  • core/providers/gemini/gemini.go
✅ Files skipped from review due to trivial changes (4)
  • framework/version
  • transports/changelog.md
  • plugins/semanticcache/version
  • docs/features/keys-management.mdx
🚧 Files skipped from review as they are similar to previous changes (31)
  • core/providers/bedrock/bedrock.go
  • core/bifrost_test.go
  • ui/README.md
  • core/providers/anthropic/chat.go
  • transports/version
  • plugins/telemetry/version
  • plugins/telemetry/changelog.md
  • framework/streaming/responses.go
  • docs/quickstart/gateway/multimodal.mdx
  • plugins/mocker/version
  • plugins/mocker/changelog.md
  • plugins/jsonparser/changelog.md
  • framework/changelog.md
  • docs/quickstart/go-sdk/multimodal.mdx
  • docs/integrations/genai-sdk.mdx
  • core/bifrost.go
  • docs/integrations/litellm-sdk.mdx
  • plugins/jsonparser/version
  • transports/bifrost-http/handlers/providers.go
  • ui/app/workspace/logs/views/logDetailsSheet.tsx
  • transports/bifrost-http/lib/config.go
  • plugins/logging/version
  • docs/integrations/what-is-an-integration.mdx
  • core/version
  • plugins/maxim/version
  • plugins/otel/changelog.md
  • core/providers/vertex/vertex_test.go
  • plugins/semanticcache/changelog.md
  • plugins/governance/version
  • plugins/logging/main.go
  • docs/features/unified-interface.mdx
🧰 Additional context used
🧬 Code graph analysis (9)
framework/modelcatalog/utils.go (1)
core/schemas/bifrost.go (1)
  • Bedrock (38-38)
core/providers/gemini/errors.go (4)
core/providers/gemini/types.go (1)
  • GeminiGenerationError (1353-1365)
core/schemas/utils.go (1)
  • Ptr (16-18)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (30-30)
core/providers/openai/chat.go (2)
core/schemas/utils.go (1)
  • IsMistralModel (1048-1050)
core/schemas/models.go (1)
  • Model (109-129)
core/schemas/provider.go (1)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
framework/modelcatalog/pricing.go (6)
core/schemas/provider.go (1)
  • Provider (280-307)
core/schemas/bifrost.go (5)
  • RequestType (83-83)
  • Bedrock (38-38)
  • ResponsesRequest (91-91)
  • ResponsesStreamRequest (92-92)
  • ChatCompletionRequest (89-89)
core/schemas/chatcompletions.go (1)
  • BifrostLLMUsage (640-647)
framework/modelcatalog/main.go (1)
  • ModelCatalog (31-52)
core/schemas/transcriptions.go (1)
  • TranscriptionUsageInputTokenDetails (106-109)
core/schemas/utils.go (1)
  • IsAllDigitsASCII (39-50)
core/providers/vertex/vertex.go (5)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/providers/utils/utils.go (2)
  • CheckContextAndGetRequestBody (256-274)
  • NewBifrostOperationError (449-460)
core/schemas/account.go (2)
  • Key (8-17)
  • VertexKeyConfig (29-35)
core/providers/anthropic/responses.go (1)
  • ToAnthropicResponsesRequest (284-383)
core/providers/vertex/errors.go (4)
core/providers/vertex/vertex.go (1)
  • VertexError (25-31)
core/providers/vertex/types.go (1)
  • VertexValidationError (154-161)
core/providers/utils/utils.go (2)
  • NewBifrostOperationError (449-460)
  • NewProviderAPIError (464-479)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (30-30)
core/providers/anthropic/anthropic.go (4)
core/providers/anthropic/types.go (1)
  • AnthropicMessageResponse (272-281)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/schemas/responses.go (1)
  • BifrostResponsesStreamResponse (1421-1459)
core/utils.go (2)
core/schemas/provider.go (1)
  • NetworkConfig (45-53)
ui/lib/types/config.ts (1)
  • NetworkConfig (94-102)
🪛 LanguageTool
core/changelog.md

[style] ~3-~3: Consider using a different verb for a more formal wording.
Context: ...en serializing/deserializing from JSON, fixing issues where values were incorrectly in...

(FIX_RESOLVE)

🔇 Additional comments (45)
plugins/otel/version (1)

1-1: Version bump looks good

Plain patch-level version increment to 1.0.41; no issues from this file’s perspective.

plugins/logging/changelog.md (1)

1-2: LGTM!

Changelog entries are clear and accurately describe the version bump and the fix for propagating numberOfRetries through update paths.

plugins/logging/operations.go (4)

24-46: LGTM!

The refactoring to remove numberOfRetries from the initial log entry is correct—retry count is meaningfully known only after request completion and is now properly propagated through the update paths. The additional parsed fields enhance structured logging.


57-57: LGTM!

The numberOfRetries parameter addition and conditional update logic are correctly implemented, ensuring retry metadata is only written when retries actually occurred.

Also applies to: 74-76


183-183: LGTM!

The numberOfRetries parameter and conditional update logic are consistent with updateLogEntry.

Also applies to: 198-200


201-213: Verify if key metadata should be preserved on error.

When ErrorDetails is present, the function returns early with a new map containing only status, latency, and error_details. This discards the previously built updates including selected_key_id, selected_key_name, virtual_key_id, virtual_key_name, and number_of_retries.

If this metadata is valuable for debugging failed requests, consider merging the error fields into the existing updates map instead of creating a new one.

transports/bifrost-http/integrations/router.go (1)

304-328: LGTM - formatting adjustments only.

The changes in this section are purely formatting adjustments (variable declaration positioning and brace formatting) with no functional impact on request processing logic.

ui/lib/constants/logs.ts (1)

45-45: LGTM - branding update consistent with PR scope.

The label change from "Azure OpenAI" to "Azure" aligns with the PR's goal of standardizing Azure branding across the codebase.

docs/integrations/anthropic-sdk.mdx (1)

104-109: LGTM - documentation branding updates.

The comment updates from "Azure OpenAI models" to "Azure models" are consistent with the PR's branding standardization efforts.

plugins/governance/changelog.md (1)

1-2: LGTM - changelog updates.

Standard changelog entries documenting feature additions and version bumps.

core/internal/testutil/account.go (2)

195-197: LGTM - test configuration for Anthropic deployment support.

The addition of the "claude-opus-4-5" deployment entry aligns with the PR's goal of adding Anthropic model support to the Azure provider. The parallel addition of "o1" deployment supports OpenAI reasoning models.


651-651: LGTM - branding update in test comments.

Consistent with the broader branding standardization from "Azure OpenAI" to "Azure".

docs/quickstart/go-sdk/provider-configuration.mdx (1)

274-280: LGTM - documentation branding updates.

The updates from "Azure OpenAI" to "Azure" in headings and descriptive text are consistent with the PR's branding standardization goals.

ui/lib/types/schemas.ts (1)

217-222: Verify the relaxed minimum for retry_backoff_max.

The validation changes add sensible upper bounds (1,000,000 ms), but the minimum for retry_backoff_max was reduced from 1000 ms to 100 ms. This more permissive validation now allows configurations where both retry_backoff_initial and retry_backoff_max could be as low as 100 ms, which may not provide meaningful exponential backoff behavior in practice.

While the cross-field validation still ensures initial <= max, a maximum backoff of 100 ms might be too tight for typical retry scenarios. Consider whether this relaxation was intentional or if the minimum for retry_backoff_max should remain higher (e.g., 1000 ms) to ensure effective backoff ranges.

docs/integrations/openai-sdk.mdx (1)

99-99: LGTM! Branding updates align with Azure Anthropic support.

The documentation updates correctly reflect the expanded Azure provider capabilities (now supporting both OpenAI and Anthropic models), making the terminology more accurate.

Also applies to: 141-141, 319-319

docs/quickstart/gateway/provider-configuration.mdx (1)

762-840: Documentation update for Azure configuration looks comprehensive.

The updated Azure configuration section clearly documents the new azure_key_config structure with endpoint, deployments, and api_version fields across all configuration methods (Web UI, API, config.json).

One consideration: If Azure Anthropic deployments require a different API version than Azure OpenAI deployments (per the AI summary mentioning AzureAnthropicAPIVersionDefault), it may be helpful to add a note about API version differences between model types.

core/schemas/provider.go (1)

55-117: Well-implemented JSON marshaling for NetworkConfig backoff fields.

The custom UnmarshalJSON and MarshalJSON methods correctly handle the conversion between Go's time.Duration (nanoseconds) and JSON milliseconds. The alias pattern properly avoids infinite recursion, and the implementation aligns with the UI's TypeScript interface which expects milliseconds.

core/providers/azure/azure_test.go (1)

32-35: Azure comprehensive test config now exercises Anthropic reasoning – looks consistent

The updated TextModel comment and the ReasoningModel change to "claude-opus-4-5" accurately reflect that newer Azure deployments are chat-only while letting this suite cover the new Anthropic-on-Azure reasoning path. No issues from the test harness perspective.

docs/integrations/langchain-sdk.mdx (1)

221-221: Azure direct-key headings now match intent; samples remain valid

Renaming these sections to “Using Azure with direct Azure key” clarifies the scenario without affecting the underlying examples. The AzureChatOpenAI usage and x-bf-azure-endpoint header still look correct.

Also applies to: 269-269

core/providers/anthropic/anthropic_test.go (1)

31-33: Anthropic test config cleanly separates vision and reasoning models

Setting VisionModel to "claude-3-7-sonnet-20250219" and ReasoningModel to "claude-opus-4-5" gives clear coverage of both capabilities in the comprehensive test suite. This mirrors how the new ReasoningModel is used elsewhere.

core/providers/openai/chat.go (1)

51-53: Centralizing Vertex Mistral detection via schemas.IsMistralModel is appropriate

Using schemas.IsMistralModel(bifrostReq.Model) in the Vertex branch keeps Mistral-specific transformations applied only when the model string clearly indicates a Mistral/Codestral family, and removes the dependency on provider-specific helpers. Given the surrounding case schemas.Vertex, this should preserve behavior while simplifying model-family checks.

core/chatbot_test.go (1)

637-637: Chatbot synthesis and Azure guidance tweaks are purely cosmetic

The synthesis request still uses conversationWithSynthesis as intended; the updated Azure descriptions in printHelp and the env-variable guidance now match the broader “Azure” terminology used elsewhere in the project. No functional impact.

Also applies to: 779-779, 842-842

core/changelog.md (1)

1-3: LGTM!

The changelog entries are well-structured with clear categorization. The breaking change documentation for NetworkConfig retry backoff values is particularly helpful for users upgrading.

core/providers/vertex/errors.go (1)

10-38: LGTM! Centralized error parsing improves consistency.

The cascading error format detection (OpenAI → Vertex array → single Vertex → VertexValidationError) is well-designed. The function correctly uses providerName in all error constructors, addressing the prior review feedback.

One minor observation: the deeply nested structure (4 levels) could be refactored to early-return patterns for readability, but this is not blocking given the current implementation is correct and localized.

framework/modelcatalog/pricing.go (2)

263-265: Correct fix: use CacheReadInputTokenCost for cached prompt tokens.

Using CacheReadInputTokenCost instead of CacheCreationInputTokenCost is semantically correct—cached prompt tokens are being read from cache, not written. This fixes potential over-billing.


152-162: LGTM! Deployment-aware pricing fallback is well-implemented.

The fallback logic correctly prioritizes model-based pricing, then falls back to deployment-based pricing when a deployment alias is in use. The debug logging provides good observability.

core/providers/azure/azure.go (4)

83-102: LGTM! Auth header construction correctly differentiates Anthropic vs OpenAI paths.

The authentication logic properly handles:

  • Anthropic: x-api-key + anthropic-version headers
  • OpenAI: api-key or Authorization: Bearer with api-version query param

The defensive deletion of api-key header when using Bearer token (line 93) prevents accidental header pollution.


360-412: LGTM! ChatCompletion correctly routes Anthropic vs OpenAI requests.

The implementation properly:

  • Uses deployment for model family detection (per learnings)
  • Constructs appropriate request bodies via converters
  • Routes to correct API paths (anthropic/v1/messages vs openai/deployments/...)
  • Handles response parsing with pooled Anthropic response objects

448-513: LGTM! Streaming implementations correctly delegate to shared handlers.

Both Anthropic and OpenAI streaming paths properly:

  • Set appropriate auth headers
  • Use shared streaming handlers from respective provider packages
  • Apply postResponseConverter for consistent deployment metadata

789-800: LGTM! Helper provides safe deployment resolution.

The defensive nil checks (lines 790-792, 794) ensure the function is safe to call even if validateKeyConfig wasn't called first, improving code robustness.

core/providers/vertex/vertex.go (7)

299-336: LGTM! Centralized model detection with IsAnthropicModel improves consistency.

The refactoring to use schemas.IsAnthropicModel(deployment) and schemas.IsMistralModel(deployment) provides consistent model family detection across the codebase. The anthropic_version handling (lines 331-336) correctly injects the version when missing.


440-441: LGTM! Centralized error parsing via parseVertexError.

Replacing inline error parsing with the centralized parseVertexError function improves consistency and maintainability across Vertex provider error handling.


443-495: LGTM! Response handling with object pooling is well-implemented.

The implementation correctly:

  • Uses AcquireAnthropicMessageResponse/ReleaseAnthropicMessageResponse for efficient memory management
  • Converts responses via ToBifrostChatResponse()
  • Populates ExtraFields comprehensively
  • Conditionally sets ModelDeployment only when different from ModelRequested

519-524: LGTM! postResponseConverter ensures consistent deployment metadata in streams.

The converter correctly adds ModelDeployment only when it differs from ModelRequested, applied consistently to both Anthropic and OpenAI streaming paths.


692-829: LGTM! Responses method properly handles Anthropic vs non-Anthropic paths.

The implementation:

  • Uses dedicated HTTP flow for Anthropic models with proper OAuth token handling
  • Correctly addresses the prior review feedback (error message on line 704)
  • Falls back to ChatCompletion for non-Anthropic models, with ToBifrostResponsesResponse() preserving latency via ExtraFields copy

833-943: LGTM! ResponsesStream correctly implements Anthropic streaming with fallback.

The implementation:

  • Uses HandleAnthropicResponsesStream for Anthropic models with proper OAuth setup
  • Sets BifrostContextKeyIsResponsesToChatCompletionFallback context value for non-Anthropic fallback detection
  • Correctly addresses the prior review feedback (error message on line 860)

1064-1066: LGTM! Embedding method includes deployment metadata consistently.

The conditional ModelDeployment assignment follows the same pattern as other methods, ensuring consistent metadata across all Vertex provider operations.

core/providers/anthropic/anthropic.go (8)

30-56: LGTM: Consistent renaming from "Chat" to "Message".

The renaming of the pool and accessor functions improves consistency with Anthropic's API terminology. All references are updated consistently throughout the file.

Also applies to: 89-89


318-318: LGTM: Function renames applied consistently.

The usage of renamed converter and pool accessor functions is consistent with the overall refactoring.

Also applies to: 331-332, 369-369


402-402: LGTM: Signature enhancement adds post-processing capability.

The addition of the postResponseConverter parameter provides flexibility for response transformation. The nil-safety checks at lines 564-570 ensure safe handling when no converter is provided.

Also applies to: 417-420


454-454: LGTM: Consistent provider naming throughout error paths.

Using the providerName parameter directly instead of calling GetProviderKey() improves consistency and reduces redundant calls.

Also applies to: 456-456, 462-462, 477-477, 556-556, 575-575, 600-603


564-570: LGTM: Proper nil-safety for post-response converter.

The defensive nil-checks and warning logs ensure robustness when a converter is provided but returns nil.


638-639: LGTM: Consistent use of renamed pool accessors.


901-904: Existing concern: Missing final chunk emission on unexpected stream termination.

This is the same issue previously raised in the past review comments. When the scanner completes without error (scanner.Err() == nil) but no message_stop event was received (e.g., unexpected EOF), no final chunk with accumulated usage is emitted.

HandleAnthropicChatCompletionStreaming has a defensive else block (lines 602-607) that sends a final chunk in this scenario, but HandleAnthropicResponsesStream does not.

While Anthropic's API should always send proper termination events, adding the defensive else block would improve robustness against unexpected stream terminations.

As per the past review discussion, please confirm whether this edge case should be handled similar to the chat completion streaming handler.


685-709: LGTM: ResponsesStream properly delegates to shared handler.

The refactoring to use HandleAnthropicResponsesStream follows the same pattern as ChatCompletionStream and reduces code duplication.

Comment thread core/providers/anthropic/anthropic.go
Comment thread framework/modelcatalog/pricing.go
…ve anthropic for vertex claude responses api
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch from e0c170f to a0fc7da Compare December 1, 2025 08:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
core/providers/azure/azure.go (2)

113-116: Anthropic error responses parsed with OpenAI parser.

When the Anthropic path returns a non-200 status, errors are parsed using openai.ParseOpenAIError. Anthropic error responses have a different structure than OpenAI. This may result in incomplete or confusing error messages for Anthropic-related failures.

Consider adding Anthropic-specific error parsing:

	// Handle error response
	if resp.StatusCode() != fasthttp.StatusOK {
+		if schemas.IsAnthropicModel(deployment) {
+			return nil, deployment, latency, anthropic.ParseAnthropicError(resp, requestType, provider.GetProviderKey(), model)
+		}
		return nil, deployment, latency, openai.ParseOpenAIError(resp, requestType, provider.GetProviderKey(), model)
	}

Verify that an anthropic.ParseAnthropicError function exists or needs to be created.

#!/bin/bash
# Check if Anthropic error parsing exists
rg -n "ParseAnthropicError|func.*Error.*Anthropic" core/providers/anthropic/ --type=go

701-747: Embedding does not validate Anthropic model unsupported.

The Embedding function routes all requests to OpenAI's embedding endpoint regardless of model type. If an Anthropic deployment is configured, this will send requests to an incorrect endpoint (Anthropic doesn't support embeddings via the same API).

Consider adding a guard:

	deployment, err := provider.getModelDeployment(key, request.Model)
	if err != nil {
		return nil, err
	}

+	if schemas.IsAnthropicModel(deployment) {
+		return nil, providerUtils.NewUnsupportedOperationError(schemas.EmbeddingRequest, provider.GetProviderKey())
+	}
+
	// Use centralized converter

This provides a clear error rather than a confusing failure from the Azure API.

🧹 Nitpick comments (6)
core/providers/gemini/errors.go (1)

39-90: Consider consolidating duplicate parsing logic.

Both parseStreamGeminiError and parseGeminiError follow identical parsing flows. Since the streaming vs. non-streaming distinction doesn't affect how errors are parsed, consider merging them into a single helper function to reduce duplication and improve maintainability.

Example refactor:

// parseGeminiError parses Gemini error responses (both streaming and non-streaming)
func parseGeminiError(providerName schemas.ModelProvider, resp *fasthttp.Response) *schemas.BifrostError {
	body := append([]byte(nil), resp.Body()...)

	// Try to parse as JSON first
	var errorResp GeminiGenerationError
	if err := sonic.Unmarshal(body, &errorResp); err == nil {
		bifrostErr := &schemas.BifrostError{
			IsBifrostError: false,
			StatusCode:     schemas.Ptr(resp.StatusCode()),
			Error: &schemas.ErrorField{
				Code:    schemas.Ptr(strconv.Itoa(errorResp.Error.Code)),
				Message: errorResp.Error.Message,
			},
		}
		return bifrostErr
	}

	var rawResponse map[string]interface{}
	if err := sonic.Unmarshal(body, &rawResponse); err != nil {
		return providerUtils.NewBifrostOperationError(schemas.ErrProviderResponseUnmarshal, err, providerName)
	}

	return providerUtils.NewBifrostOperationError(fmt.Sprintf("Gemini error (HTTP %d): %v", resp.StatusCode(), rawResponse), fmt.Errorf("HTTP %d", resp.StatusCode()), providerName)
}

// parseStreamGeminiError is an alias for backward compatibility
func parseStreamGeminiError(providerName schemas.ModelProvider, resp *fasthttp.Response) *schemas.BifrostError {
	return parseGeminiError(providerName, resp)
}

Alternatively, if you need to maintain separate functions for clarity, at least extract the common parsing logic into a shared helper.

docs/apis/openapi.json (1)

1758-1803: Azure deployment endpoint branding looks consistent; consider harmonizing deployment-id descriptions

The updated summaries/descriptions for the deployment-scoped OpenAI-compatible endpoints look good and match the rest of the OpenAI integration wording.

One minor consistency nit: on /openai/deployments/{deployment-id}/completions the deployment-id parameter description is now "Deployment ID", while the analogous chat/responses/embeddings/audio endpoints still say "Azure deployment ID". You might want to normalize these descriptions one way or the other across all deployment paths for clarity.

Also applies to: 1879-1925, 2001-2047, 2113-2155, 2222-2265, 2330-2372

plugins/logging/operations.go (1)

24-41: Retries count now correctly updated for both streaming and non‑streaming logs

The logging changes look sound:

  • Initial log entry no longer stores number_of_retries, which avoids stale values at insert time.
  • updateLogEntry and updateStreamingLogEntry now accept numberOfRetries and persist it when non‑zero, fixing the issue where the retries count never advanced.

One behavioral nuance: because the field is only written when numberOfRetries != 0, you cannot reset a previously non‑zero value back to 0 via this path. If you ever need that, you might later switch this parameter to *int (nil = “don’t touch”, 0 = “reset”), but for the current bugfix this implementation is adequate.

Also applies to: 49-60, 74-76, 176-187, 198-200

docs/quickstart/go-sdk/provider-configuration.mdx (1)

274-305: Azure provider doc snippet matches new API; fix minor concurrency snippet typo

The new Azure provider-auth section looks aligned with the code:

  • Uses schemas.Azure as the provider.
  • Configures AzureKeyConfig with Endpoint, Deployments, and optional APIVersion, which is what the runtime expects.

One unrelated but important doc nit in the same file: in the “Custom Concurrency and Buffer Size” example, schemas.ConcurrencyAndBufferSize uses a Concurrency field (as seen elsewhere in the codebase), not MaxConcurrency. As written, that snippet won’t compile.

You can fix the example like this:

-    case schemas.OpenAI:
-        return &schemas.ProviderConfig{
-        NetworkConfig: schemas.DefaultNetworkConfig,
-        ConcurrencyAndBufferSize: schemas.ConcurrencyAndBufferSize{
-                MaxConcurrency: 100, // Max number of concurrent requests (no of workers)
-                BufferSize:     500, // Max number of requests in the buffer (queue size)
-            },
-        }, nil
+    case schemas.OpenAI:
+        return &schemas.ProviderConfig{
+            NetworkConfig: schemas.DefaultNetworkConfig,
+            ConcurrencyAndBufferSize: schemas.ConcurrencyAndBufferSize{
+                Concurrency: 100, // Max number of concurrent requests (no of workers)
+                BufferSize:  500, // Max number of requests in the buffer (queue size)
+            },
+        }, nil

Also applies to: 176-198

transports/bifrost-http/handlers/providers.go (2)

228-235: Retry backoff validation is a good safeguard; consider also rejecting negative durations

The new validateRetryBackoff helper and its use in both addProvider and updateProvider correctly:

  • Enforce per-field bounds using lib.MinRetryBackoff/lib.MaxRetryBackoff.
  • Ensure RetryBackoffInitial <= RetryBackoffMax when both are non‑zero.

This will prevent misconfigured providers from setting extreme or inverted backoff windows.

One small hardening opportunity: right now, negative backoff values slip through because the checks only run when the fields are > 0. If schemas.NetworkConfig allows negative RetryBackoff* values, you may want to explicitly reject < 0 as invalid here as well.

Also applies to: 414-424, 871-895


528-531: AccessibleByKeys field is currently unused in listModels responses

ModelResponse now includes an AccessibleByKeys field, but listModels only filters the model list by keys and never sets this field, so it will always be omitted (omitempty).

If the intent is just to return the filtered models, this is fine and the extra field is harmless. If you eventually want the API to surface which keys can access each model, consider populating AccessibleByKeys in listModels (and documenting its behavior), or dropping the field until that behavior is implemented.

Also applies to: 563-604, 609-628

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0c170f and a0fc7da.

📒 Files selected for processing (70)
  • core/bifrost.go (2 hunks)
  • core/bifrost_test.go (2 hunks)
  • core/changelog.md (1 hunks)
  • core/chatbot_test.go (3 hunks)
  • core/internal/testutil/account.go (2 hunks)
  • core/providers/anthropic/anthropic.go (21 hunks)
  • core/providers/anthropic/anthropic_test.go (1 hunks)
  • core/providers/anthropic/chat.go (1 hunks)
  • core/providers/azure/azure.go (15 hunks)
  • core/providers/azure/azure_test.go (1 hunks)
  • core/providers/azure/types.go (1 hunks)
  • core/providers/bedrock/bedrock.go (1 hunks)
  • core/providers/gemini/errors.go (2 hunks)
  • core/providers/gemini/gemini.go (0 hunks)
  • core/providers/openai/chat.go (1 hunks)
  • core/providers/utils/utils.go (0 hunks)
  • core/providers/vertex/errors.go (1 hunks)
  • core/providers/vertex/vertex.go (11 hunks)
  • core/providers/vertex/vertex_test.go (2 hunks)
  • core/schemas/provider.go (2 hunks)
  • core/schemas/utils.go (1 hunks)
  • core/utils.go (1 hunks)
  • core/version (1 hunks)
  • docs/apis/openapi.json (11 hunks)
  • docs/features/keys-management.mdx (1 hunks)
  • docs/features/unified-interface.mdx (1 hunks)
  • docs/integrations/anthropic-sdk.mdx (2 hunks)
  • docs/integrations/genai-sdk.mdx (2 hunks)
  • docs/integrations/langchain-sdk.mdx (2 hunks)
  • docs/integrations/litellm-sdk.mdx (2 hunks)
  • docs/integrations/openai-sdk.mdx (3 hunks)
  • docs/integrations/what-is-an-integration.mdx (1 hunks)
  • docs/quickstart/gateway/multimodal.mdx (1 hunks)
  • docs/quickstart/gateway/provider-configuration.mdx (1 hunks)
  • docs/quickstart/go-sdk/multimodal.mdx (1 hunks)
  • docs/quickstart/go-sdk/provider-configuration.mdx (1 hunks)
  • framework/changelog.md (1 hunks)
  • framework/modelcatalog/pricing.go (7 hunks)
  • framework/modelcatalog/utils.go (1 hunks)
  • framework/streaming/responses.go (2 hunks)
  • framework/version (1 hunks)
  • plugins/governance/changelog.md (1 hunks)
  • plugins/governance/version (1 hunks)
  • plugins/jsonparser/changelog.md (1 hunks)
  • plugins/jsonparser/version (1 hunks)
  • plugins/logging/changelog.md (1 hunks)
  • plugins/logging/main.go (8 hunks)
  • plugins/logging/operations.go (5 hunks)
  • plugins/logging/version (1 hunks)
  • plugins/maxim/changelog.md (1 hunks)
  • plugins/maxim/version (1 hunks)
  • plugins/mocker/changelog.md (1 hunks)
  • plugins/mocker/version (1 hunks)
  • plugins/otel/changelog.md (1 hunks)
  • plugins/otel/version (1 hunks)
  • plugins/semanticcache/changelog.md (1 hunks)
  • plugins/semanticcache/version (1 hunks)
  • plugins/telemetry/changelog.md (1 hunks)
  • plugins/telemetry/version (1 hunks)
  • transports/bifrost-http/handlers/providers.go (9 hunks)
  • transports/bifrost-http/integrations/router.go (3 hunks)
  • transports/bifrost-http/lib/config.go (1 hunks)
  • transports/bifrost-http/server/server.go (0 hunks)
  • transports/changelog.md (1 hunks)
  • transports/version (1 hunks)
  • ui/README.md (1 hunks)
  • ui/app/workspace/logs/views/logChatMessageView.tsx (1 hunks)
  • ui/app/workspace/logs/views/logDetailsSheet.tsx (2 hunks)
  • ui/lib/constants/logs.ts (1 hunks)
  • ui/lib/types/schemas.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • transports/bifrost-http/server/server.go
  • core/providers/utils/utils.go
  • core/providers/gemini/gemini.go
✅ Files skipped from review due to trivial changes (2)
  • plugins/mocker/version
  • plugins/semanticcache/version
🚧 Files skipped from review as they are similar to previous changes (34)
  • core/providers/anthropic/chat.go
  • plugins/otel/version
  • framework/modelcatalog/utils.go
  • core/chatbot_test.go
  • transports/bifrost-http/integrations/router.go
  • docs/integrations/genai-sdk.mdx
  • core/utils.go
  • plugins/jsonparser/version
  • docs/integrations/openai-sdk.mdx
  • docs/quickstart/gateway/provider-configuration.mdx
  • core/providers/azure/types.go
  • core/bifrost_test.go
  • framework/changelog.md
  • core/version
  • docs/integrations/litellm-sdk.mdx
  • plugins/telemetry/changelog.md
  • core/providers/vertex/errors.go
  • plugins/logging/main.go
  • plugins/telemetry/version
  • core/schemas/utils.go
  • plugins/governance/version
  • ui/lib/types/schemas.ts
  • docs/integrations/what-is-an-integration.mdx
  • core/providers/bedrock/bedrock.go
  • transports/bifrost-http/lib/config.go
  • core/providers/openai/chat.go
  • plugins/maxim/changelog.md
  • transports/version
  • plugins/governance/changelog.md
  • core/schemas/provider.go
  • framework/version
  • plugins/logging/version
  • docs/integrations/anthropic-sdk.mdx
  • plugins/maxim/version
🧰 Additional context used
🧬 Code graph analysis (6)
core/providers/gemini/errors.go (4)
core/schemas/utils.go (1)
  • Ptr (16-18)
core/utils.go (1)
  • Ptr (51-53)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
core/schemas/provider.go (1)
  • ErrProviderResponseUnmarshal (30-30)
ui/app/workspace/logs/views/logDetailsSheet.tsx (1)
ui/components/ui/sheet.tsx (1)
  • SheetContent (140-140)
framework/streaming/responses.go (2)
core/schemas/bifrost.go (3)
  • OpenAI (35-35)
  • OpenRouter (49-49)
  • Azure (36-36)
core/schemas/utils.go (1)
  • IsAnthropicModel (1043-1045)
core/providers/azure/azure.go (4)
core/schemas/utils.go (2)
  • IsAnthropicModel (1043-1045)
  • Ptr (16-18)
core/providers/azure/types.go (2)
  • AzureAnthropicAPIVersionDefault (6-6)
  • AzureAPIVersionDefault (4-4)
core/utils.go (1)
  • Ptr (51-53)
core/providers/anthropic/anthropic.go (2)
  • AcquireAnthropicMessageResponse (45-49)
  • ReleaseAnthropicMessageResponse (52-56)
core/providers/vertex/vertex.go (7)
core/schemas/utils.go (3)
  • IsAnthropicModel (1043-1045)
  • IsMistralModel (1048-1050)
  • Ptr (16-18)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/providers/anthropic/anthropic.go (1)
  • HandleAnthropicResponsesStream (712-913)
core/providers/utils/utils.go (1)
  • HandleProviderResponse (343-387)
core/schemas/account.go (2)
  • Key (8-17)
  • VertexKeyConfig (29-35)
core/providers/anthropic/responses.go (1)
  • ToAnthropicResponsesRequest (284-383)
core/utils.go (1)
  • Ptr (51-53)
core/providers/anthropic/anthropic.go (3)
core/providers/anthropic/types.go (1)
  • AnthropicMessageResponse (272-281)
core/providers/anthropic/chat.go (1)
  • ToAnthropicChatRequest (386-620)
core/providers/utils/utils.go (1)
  • NewBifrostOperationError (449-460)
🪛 LanguageTool
core/changelog.md

[style] ~3-~3: Consider using a different verb for a more formal wording.
Context: ...en serializing/deserializing from JSON, fixing issues where values were incorrectly in...

(FIX_RESOLVE)

🔇 Additional comments (38)
core/bifrost.go (2)

2025-2025: LGTM! Helpful observability improvement.

The debug log for backoff sleep duration aids in monitoring retry behavior at runtime without affecting control flow.


2067-2067: LGTM! Consistent wording.

The updated message text aligns with the attempts variable naming and correctly handles singular/plural forms.

core/providers/gemini/errors.go (1)

3-11: LGTM! Imports align with new parsing functions.

All imports are necessary for the error parsing logic added below.

plugins/jsonparser/changelog.md (1)

1-1: LGTM!

Version update note is consistent with the PR's core and framework version bumps.

docs/features/keys-management.mdx (1)

198-198: LGTM!

The branding update from "Azure OpenAI" to "Azure" accurately reflects that Azure now supports both OpenAI and Anthropic models per this PR.

ui/lib/constants/logs.ts (1)

45-45: LGTM!

Provider label update is consistent with the branding changes across the PR to reflect Azure's support for multiple model families.

ui/README.md (1)

84-84: LGTM!

README update correctly reflects the Azure provider's expanded capabilities beyond just OpenAI models.

plugins/semanticcache/changelog.md (1)

1-1: LGTM!

Version update note is consistent with the PR's version bumps.

ui/app/workspace/logs/views/logDetailsSheet.tsx (2)

39-39: LGTM!

Adding gap-4 improves the vertical spacing between elements in the sheet content for better visual hierarchy.


55-56: LGTM!

Formatting improvement for better readability.

plugins/mocker/changelog.md (1)

1-1: LGTM!

Version update note matches the consistent version bumps across all plugins.

plugins/otel/changelog.md (1)

1-1: LGTM!

Version update note is consistent with other plugin changelogs in this PR.

docs/integrations/langchain-sdk.mdx (1)

221-221: LGTM! Branding update is consistent.

The documentation updates from "Azure OpenAI" to "Azure" align with the broader branding changes in this PR.

Also applies to: 269-269

ui/app/workspace/logs/views/logChatMessageView.tsx (1)

29-29: LGTM! UI enhancement for text overflow.

The break-words class prevents text overflow by allowing long words to wrap, which improves the user experience when displaying log content.

docs/features/unified-interface.mdx (2)

91-91: LGTM! Provider naming updated for consistency.

The Azure OpenAI row has been renamed to "Azure" to align with the broader branding changes in this PR.


95-95: LGTM! Elevenlabs capabilities updated correctly.

The Elevenlabs row now accurately reflects the provider's TTS, TTS (stream), and STT capabilities, addressing the previous review feedback.

docs/quickstart/go-sdk/multimodal.mdx (1)

335-337: LGTM! Documentation refactoring improves maintainability.

Centralizing multimodal capability information in the Unified Interface page reduces duplication and makes it easier to keep documentation up to date.

transports/changelog.md (1)

1-6: LGTM! Changelog properly documents the PR changes.

The changelog entries accurately reflect the main feature addition (Anthropic models in Azure) along with related fixes and improvements.

core/providers/azure/azure_test.go (1)

34-34: Azure deployment configuration correctly includes the Anthropic model.

The test configuration using "claude-opus-4-5" as ReasoningModel is properly supported by the test setup, which includes the deployment mapping at core/internal/testutil/account.go:195.

docs/quickstart/gateway/multimodal.mdx (1)

288-290: Update the Unified Interface provider matrix to document Azure Anthropic support.

Azure supports Anthropic models (as evidenced by AzureAnthropicAPIVersionDefault in the codebase), but this capability is not reflected in the provider matrix. The matrix should clarify that Azure can host Anthropic Claude models via deployment mappings, as documented in the provider configuration guide.

framework/streaming/responses.go (1)

686-686: The condition correctly routes Azure Anthropic models to Anthropic-specific streaming.

The IsAnthropicModel() helper function (core/schemas/utils.go:1043–1045) detects Anthropic models by checking for "anthropic." or "claude" substrings. This correctly identifies all Anthropic model variants, including those deployed on Azure (e.g., claude-3-5-sonnet-20241022). The updated condition properly excludes Azure-hosted Anthropic models from the OpenAI-compatible path, routing them instead to Anthropic-specific streaming handling. The logic is sound and handles Azure's multi-model hosting capability appropriately.

plugins/logging/changelog.md (1)

1-2: Changelog entries accurately reflect logging fix and version bump

The new entries clearly describe the retries logging fix and the corresponding core/framework version updates. No changes needed.

core/internal/testutil/account.go (1)

189-199: Azure test config correctly wires Anthropic/Reasoning deployments

The added Azure key with deployments for "claude-opus-4-5" and "o1" plus the updated comment in AllProviderConfigs look consistent with the new Azure Anthropic support and reasoning tests. Reusing AZURE_API_KEY/AZURE_ENDPOINT in test utilities is reasonable here.

Also applies to: 649-652

core/providers/anthropic/anthropic_test.go (1)

24-33: Anthropic test config now exercises vision and reasoning paths explicitly

Setting VisionModel to claude-3-7-sonnet-20250219 and ReasoningModel to claude-opus-4-5 is a good way to cover Anthropic’s multimodal and reasoning flows in the comprehensive test suite. Looks good.

transports/bifrost-http/handlers/providers.go (1)

283-291: Background model refetch now uses a safe, non‑pooled context

The goroutines that trigger RefetchModelsForProvider on add/update now use context.Background() instead of capturing the request’s *fasthttp.RequestCtx. That avoids using a pooled/recycled request context after the handler returns while still keeping the refetch non‑blocking.

Also applies to: 461-470

framework/modelcatalog/pricing.go (5)

93-93: LGTM: Deployment parameter correctly propagated to cost calculation.

The addition of extraFields.ModelDeployment enables deployment-aware pricing lookups, which is essential for Azure Anthropic models where deployment names differ from model aliases.


110-114: Verify that empty deployment is intentional for cache debug flows.

The cache debug cost calculations pass "" for deployment. This is likely correct since cache hits use cacheDebug.ModelUsed (which should be the actual model name), but confirm this won't skip pricing for deployments that require the deployment fallback path.

Also applies to: 123-127


152-162: LGTM: Deployment fallback with appropriate logging.

The fallback logic correctly attempts pricing lookup using deployment when model lookup fails, and logs appropriately before returning zero cost. This ensures Azure deployments with different model/deployment names are properly priced.


323-341: Improved Bedrock pricing lookup using IsAnthropicModel helper.

This addresses the previous review concern about overly broad numeric model assumptions. Now explicitly uses IsAnthropicModel (which checks for "anthropic." or "claude" substrings) to determine when to prepend the "anthropic." prefix, making the logic more precise and less likely to incorrectly modify non-Claude model names.


263-265: Cache read input token cost change is semantically correct.

The change from CacheCreationInputTokenCost to CacheReadInputTokenCost aligns with Anthropic's pricing model, where cached prompt tokens are billed at the cache read rate (~90% discount, ~$0.30/1M vs. $3/1M base input). Cached prompt tokens represent reads from cache, so using CacheReadInputTokenCost is correct.

core/providers/azure/azure.go (8)

63-71: LGTM: Clean refactoring of completeRequest signature.

Moving deployment resolution out of this function and accepting it as a parameter promotes separation of concerns and ensures consistent deployment handling across all callers.


83-102: LGTM: Proper header and URL construction for Anthropic vs OpenAI.

The branching correctly:

  • Sets x-api-key and anthropic-version for Anthropic models
  • Sets api-key (or Bearer token) and includes api-version query param for OpenAI models
  • Constructs appropriate URL paths for each provider type

Based on learnings, using IsAnthropicModel(deployment) is correct since deployment contains the actual model identifier.


352-412: LGTM: Anthropic detection correctly uses deployment in ChatCompletion.

This addresses the past review comment. The routing now consistently checks IsAnthropicModel(deployment) for:

  • Request body conversion (line 361)
  • Path selection (line 377)
  • Response parsing (line 399)

The deployment variable contains the actual Azure deployment name with the model identifier.


437-513: LGTM: ChatCompletionStream properly branches for Anthropic vs OpenAI.

The streaming implementation correctly:

  • Resolves deployment upfront using getModelDeployment
  • Sets appropriate headers (x-api-key vs api-key/Bearer)
  • Constructs correct URLs for each provider type
  • Uses provider-specific streaming handlers (HandleAnthropicChatCompletionStreaming vs HandleOpenAIChatCompletionStreaming)
  • Includes postResponseConverter to set deployment metadata

524-602: LGTM: Responses correctly mirrors ChatCompletion Anthropic handling.

Consistent pattern with ChatCompletion:

  • Uses IsAnthropicModel(deployment) for routing
  • Converts to Anthropic request format when applicable
  • Parses Anthropic response and converts to Bifrost format
  • Sets appropriate path ("anthropic/v1/messages" vs OpenAI responses endpoint)

610-690: LGTM: ResponsesStream properly implements dual-provider streaming.

Mirrors the pattern in ChatCompletionStream with correct:

  • Deployment resolution and Anthropic detection
  • Header configuration for each provider type
  • URL construction
  • Streaming handler delegation

The postRequestConverter for OpenAI correctly sets the deployment model.


789-800: LGTM: Clean deployment resolution helper.

The getModelDeployment function properly:

  • Validates AzureKeyConfig exists
  • Looks up deployment from the configured map
  • Returns a descriptive configuration error if not found

This centralizes deployment resolution logic for reuse across all methods.


302-312: Anthropic does not support text completion streaming. TextCompletionStream is intentionally unsupported for Anthropic (returns UnsupportedOperationError), so Azure's hardcoded OpenAI deployment path in this code is appropriate—it only handles Azure deployments. No cross-provider routing issue exists here.

Comment thread core/providers/gemini/errors.go

Pratham-Mishra04 commented Dec 1, 2025

Copy link
Copy Markdown
Collaborator Author

Merge activity

  • Dec 1, 9:27 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Dec 1, 9:27 AM UTC: @Pratham-Mishra04 merged this pull request with Graphite.

@Pratham-Mishra04
Pratham-Mishra04 merged commit 3932301 into main Dec 1, 2025
9 checks passed
@Pratham-Mishra04
Pratham-Mishra04 deleted the 11-29-feat_added_support_for_anthropic_models_in_azure_and_shifted_to_native_anthropic_for_vertex_claude_responses_api branch December 1, 2025 09:27
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.

1 participant