Skip to content

Conversation

Pratham-Mishra04
Copy link
Collaborator

Add Anthropic API Compatibility Layer

This PR adds a native Anthropic API compatibility layer to Bifrost, allowing applications built for Anthropic's API to work with Bifrost without modification.

Key changes:

  • Added /anthropic/v1/messages endpoint that mirrors Anthropic's Messages API
  • Implemented request/response conversion between Anthropic and Bifrost formats
  • Added support for Anthropic's content types including text, tool_use, and tool_result
  • Enhanced tool choice handling in the Anthropic provider to support both "tool" and "function" types
  • Registered the Anthropic router alongside existing OpenAI and GenAI compatibility layers

This implementation handles all Anthropic-specific features including:

  • Message format with array-based content blocks
  • Tool definitions and tool choice parameters
  • Proper conversion of tool calls and results between formats
  • Usage statistics in Anthropic's expected format

Copy link
Contributor

coderabbitai bot commented Jun 9, 2025

Caution

Review failed

The pull request is closed.

Summary by CodeRabbit

  • New Features
    • Added support for Anthropic AI models, including chat and image-enabled vision capabilities, accessible via new API endpoints.
  • Improvements
    • Enhanced route configuration for integrations, ensuring safer and more flexible request handling across AI providers.
  • Bug Fixes
    • Unified tool choice handling for Anthropic requests to ensure consistent behavior.
  • Chores
    • Improved validation and error handling for route registration and request processing.

Summary by CodeRabbit

  • New Features

    • Added support for Anthropic AI model endpoints, including chat and image-enabled vision capabilities.
    • Enabled bidirectional translation between Anthropic and internal message formats, supporting tools, tool choices, and detailed usage statistics.
  • Improvements

    • Enhanced route configuration for AI providers to ensure safer request handling and dynamic request type instantiation.
    • Improved validation and error handling for route registration and response processing.
    • Unified handling of tool choices for Anthropic requests, ensuring consistent parameter preparation.

Walkthrough

These changes introduce Anthropic API compatibility to the Bifrost HTTP transport layer. New files define request/response types and conversion logic between Anthropic and Bifrost schemas. An Anthropic router is added, handling /anthropic/v1/messages POST requests, and the main server is updated to register this integration. Minor logic in the core provider is adjusted for tool choice handling. Additionally, GenAI and OpenAI routers are updated to use factory functions for request instances, and route config validation is strengthened.

Changes

File(s) Change Summary
core/providers/anthropic.go Adjusted switch logic to handle both schemas.ToolChoiceTypeFunction and "tool" cases identically.
transports/bifrost-http/integrations/anthropic/types.go Added: Defines Anthropic message/request/response types and conversion logic to/from Bifrost schemas.
transports/bifrost-http/integrations/anthropic/router.go Added: Implements AnthropicRouter, registers /anthropic/v1/messages endpoint, handles request/response flow.
transports/bifrost-http/main.go Modified: Registers Anthropic router as an extension in the HTTP server initialization.
transports/bifrost-http/integrations/genai/router.go Modified: Changed GenAI route config to use a factory function for request type instance creation.
transports/bifrost-http/integrations/openai/router.go Modified: Changed OpenAI route config to use a factory function for request type instance creation.
transports/bifrost-http/integrations/utils.go Modified: Renamed RequestType field to GetRequestTypeInstance function in RouteConfig for fresh instances; added validation checks.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AnthropicRouter
    participant BifrostClient
    participant CoreProvider

    Client->>AnthropicRouter: POST /anthropic/v1/messages (AnthropicMessageRequest)
    AnthropicRouter->>AnthropicRouter: Convert AnthropicMessageRequest to BifrostRequest
    AnthropicRouter->>BifrostClient: ChatCompletionRequest(BifrostRequest)
    BifrostClient->>CoreProvider: Process request
    CoreProvider-->>BifrostClient: BifrostResponse
    BifrostClient-->>AnthropicRouter: BifrostResponse
    AnthropicRouter->>AnthropicRouter: Convert BifrostResponse to AnthropicMessageResponse
    AnthropicRouter-->>Client: 200 OK (AnthropicMessageResponse)
Loading

Poem

In Bifrost’s warren, new paths appear,
Anthropic’s voice now rings out clear.
With types and routes, we hop along,
Translating messages, swift and strong.
A rabbit’s cheer for code so bright—
More models join the server’s light!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c58221 and 684f6ee.

📒 Files selected for processing (7)
  • core/providers/anthropic.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/router.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/types.go (1 hunks)
  • transports/bifrost-http/integrations/genai/router.go (1 hunks)
  • transports/bifrost-http/integrations/openai/router.go (1 hunks)
  • transports/bifrost-http/integrations/utils.go (5 hunks)
  • transports/bifrost-http/main.go (2 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Collaborator Author

Pratham-Mishra04 commented Jun 9, 2025

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 70efb6c and dde6b39.

📒 Files selected for processing (4)
  • core/providers/anthropic.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/router.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/types.go (1 hunks)
  • transports/bifrost-http/main.go (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
transports/bifrost-http/main.go (1)
transports/bifrost-http/integrations/anthropic/router.go (1)
  • NewAnthropicRouter (18-20)
transports/bifrost-http/integrations/anthropic/router.go (3)
core/bifrost.go (2)
  • Bifrost (39-51)
  • ChatCompletionRequest (24-24)
transports/bifrost-http/integrations/anthropic/types.go (2)
  • AnthropicMessageRequest (90-102)
  • DeriveAnthropicFromBifrostResponse (314-377)
transports/bifrost-http/lib/ctx.go (1)
  • ConvertToBifrostContext (43-73)
🔇 Additional comments (5)
transports/bifrost-http/main.go (2)

32-33: Import side-effect looks good

Anthropic integration is cleanly added to the imports; no issues spotted.


184-185: Router registration order OK but watch for route collisions

Adding anthropic.NewAnthropicRouter after OpenAI/GenAI is fine; routes are namespaced (/anthropic/...) so no collisions expected.

core/providers/anthropic.go (1)

486-488: Nice consolidation of switch cases

The fallthrough correctly deduplicates logic for "function" vs "tool" types. 👍

transports/bifrost-http/integrations/anthropic/router.go (2)

1-10: LGTM! Clean package structure and appropriate imports.

The package declaration and imports are well-organized and include all necessary dependencies for the Anthropic integration.


12-25: LGTM! Well-structured router with clean separation of concerns.

The AnthropicRouter struct, constructor, and route registration follow Go best practices and properly encapsulate the Bifrost client dependency.

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-refactor_http_transport_gemini_integration_refactors branch from 70efb6c to 9bc0828 Compare June 9, 2025 11:23
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from dde6b39 to 2cbc913 Compare June 9, 2025 11:23
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (4)
transports/bifrost-http/integrations/anthropic/router.go (2)

34-35: Don’t ignore JSON-marshal errors
Silently discarding json.Marshal failures makes diagnosis impossible. At minimum, log and fall back to 500.


40-42: Inconsistent error format (plain text vs JSON)
The 400 branch returns a plain string whereas all other branches return JSON.

transports/bifrost-http/integrations/anthropic/types.go (2)

283-292: Swallowed marshal errors hide malformed inputs

jsonifyInput returns "{}" on marshal failure, discarding information that could aid debugging and corrupting arguments.


104-112: ⚠️ Potential issue

Stream flag is dropped – streaming requests executed in non-streaming mode

AnthropicMessageRequest.Stream is parsed but never propagated to schemas.BifrostRequest, breaking the contract for callers expecting SSE.

 		Input: schemas.RequestInput{
 			ChatCompletionInput: &[]schemas.BifrostMessage{},
 		},
+		Stream: r.Stream,
 	}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dde6b39 and 2cbc913.

📒 Files selected for processing (4)
  • core/providers/anthropic.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/router.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/types.go (1 hunks)
  • transports/bifrost-http/main.go (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
core/providers/anthropic.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
transports/bifrost-http/integrations/anthropic/types.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
🧬 Code Graph Analysis (2)
transports/bifrost-http/main.go (1)
transports/bifrost-http/integrations/anthropic/router.go (1)
  • NewAnthropicRouter (18-20)
transports/bifrost-http/integrations/anthropic/types.go (3)
core/utils.go (1)
  • Ptr (3-5)
core/schemas/bifrost.go (21)
  • ToolChoiceTypeFunction (126-126)
  • ToolChoice (137-140)
  • BifrostRequest (54-64)
  • Anthropic (36-36)
  • RequestInput (46-49)
  • BifrostMessage (143-152)
  • ModelChatMessageRoleSystem (25-25)
  • ModelChatMessageRole (20-20)
  • ToolCall (266-270)
  • Function (101-105)
  • FunctionCall (260-263)
  • AssistantMessage (166-171)
  • ModelChatMessageRoleTool (27-27)
  • ToolMessage (160-163)
  • ModelParameters (75-89)
  • Tool (108-112)
  • FunctionParameters (92-98)
  • ToolChoiceType (116-116)
  • ToolChoiceFunction (132-134)
  • BifrostResponse (184-194)
  • LLMUsage (197-203)
core/providers/anthropic.go (1)
  • AnthropicToolChoice (20-24)
🔇 Additional comments (4)
transports/bifrost-http/main.go (2)

32-35: Anthropic router import fits project layering – no action needed

The additional import is scoped to the HTTP transport layer and preserves the existing dependency direction. Good incremental extension.


184-185: Router slice now includes Anthropic – LGTM

The new router is appended after OpenAI; ordering is non-critical because each registers unique paths. No further changes required.

core/providers/anthropic.go (1)

486-491: Correct mapping of function"tool" keeps Anthropic happy

Unifying ToolChoiceTypeFunction and "tool" avoids the scenario where "function" would reach the wire even though Anthropic only accepts "tool". Implementation is concise and uses fallthrough properly.

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

47-51: ⚠️ Potential issue

Nil-pointer panic possible when context conversion fails

lib.ConvertToBifrostContext can return nil (see main.go error handling) yet *bifrostCtx is dereferenced unconditionally. A malformed or cancelled request would crash the handler.

 	bifrostCtx := lib.ConvertToBifrostContext(ctx)
-	result, err := a.client.ChatCompletionRequest(*bifrostCtx, bifrostReq)
+	if bifrostCtx == nil {
+		ctx.SetStatusCode(fasthttp.StatusInternalServerError)
+		ctx.SetContentType("application/json")
+		_ = json.NewEncoder(ctx).Encode(map[string]string{"error": "failed to convert context"})
+		return
+	}
+	result, err := a.client.ChatCompletionRequest(*bifrostCtx, bifrostReq)
⛔ Skipped due to learnings
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#63
File: transports/bifrost-http/integrations/openai/router.go:62-64
Timestamp: 2025-06-09T11:27:00.907Z
Learning: The `lib.ConvertToBifrostContext` function in the bifrost HTTP transport never returns nil and handles the conversion internally, so nil checks are not needed when calling this function.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#63
File: transports/bifrost-http/integrations/openai/router.go:62-64
Timestamp: 2025-06-09T11:27:00.907Z
Learning: The `lib.ConvertToBifrostContext` function in the bifrost HTTP transport never returns nil and always returns a pointer to a valid context. It starts with context.Background() and only adds values to it, so nil checks are not needed when calling this function.

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-refactor_http_transport_gemini_integration_refactors branch from 9bc0828 to e339c57 Compare June 9, 2025 11:42
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from 2cbc913 to 2b7b78a Compare June 9, 2025 11:42
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (9)
transports/bifrost-http/integrations/anthropic/router.go (4)

29-38: Missing streaming-flag validation still unresolved.
The handler silently ignores req.Stream, leading clients to believe they are getting a streaming response while the request is executed in non-streaming mode. Return 501 Not Implemented (or wire through once supported).


30-37: JSON marshal error ignored – identical issue persists.

json.Marshal(errResponse) errors are discarded (_). This was flagged previously and is still unfixed. Propagate or at least log the marshal failure.


40-42: Inconsistent error payload format.

Unlike other error paths, this branch returns a plain string and no Content-Type. Standardise on JSON.


49-55: Marshaling provider error loses detail & may fail.

Serialising err directly may recurse on internal pointers and omit fields. Use a structured error or the Error field already present in schemas.BifrostError. Also capture marshal errors.

transports/bifrost-http/integrations/anthropic/types.go (5)

105-113: Stream flag still not propagated to Bifrost.

Streaming intent is dropped; downstream layers never see it.


151-160: tool_result conversion still drops non-string payloads and ID mapping.

Only plain text is copied; structured outputs/images are lost and content is ignored. Preserve the full JSON.


261-277: ToolChoice handling gated behind Tools presence – logic bug remains.

Valid tool_choice without tools array is ignored.


265-269: Enum casing not normalised.

Upper-case values pass straight through; Anthropic expects lower-case.


284-291: jsonifyInput swallows marshal errors.

Returning "{}" hides schema issues; log or propagate the error.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cbc913 and 2b7b78a.

📒 Files selected for processing (4)
  • core/providers/anthropic.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/router.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/types.go (1 hunks)
  • transports/bifrost-http/main.go (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
transports/bifrost-http/integrations/anthropic/types.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
🧬 Code Graph Analysis (1)
transports/bifrost-http/main.go (1)
transports/bifrost-http/integrations/anthropic/router.go (1)
  • NewAnthropicRouter (18-20)
🔇 Additional comments (4)
transports/bifrost-http/main.go (2)

32-35: Import order OK – no action needed.

The additional Anthropic import is correct and does not introduce cyclic dependencies.


181-185: Router slice update looks good.

anthropic.NewAnthropicRouter(client) is appended to extensions; no side-effects or ordering constraints.

core/providers/anthropic.go (1)

483-490: fallthrough correctly unifies “function” / “tool” cases.

The added fallthrough makes both enum strings map to the same payload, fixing prior incompatibility.

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

47-52: ⚠️ Potential issue

Nil-pointer risk when ConvertToBifrostContext fails.

bifrostCtx may be nil; dereferencing with *bifrostCtx panics.

 bifrostCtx := lib.ConvertToBifrostContext(ctx)
+if bifrostCtx == nil {
+    ctx.SetStatusCode(fasthttp.StatusInternalServerError)
+    ctx.SetContentType("application/json")
+    ctx.SetBodyString(`{"error":"internal context conversion failed"}`)
+    return
+}
 
-result, err := a.client.ChatCompletionRequest(*bifrostCtx, bifrostReq)
+result, err := a.client.ChatCompletionRequest(*bifrostCtx, bifrostReq)
⛔ Skipped due to learnings
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#63
File: transports/bifrost-http/integrations/openai/router.go:62-64
Timestamp: 2025-06-09T11:27:00.907Z
Learning: The `lib.ConvertToBifrostContext` function in the bifrost HTTP transport never returns nil and handles the conversion internally, so nil checks are not needed when calling this function.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#63
File: transports/bifrost-http/integrations/openai/router.go:62-64
Timestamp: 2025-06-09T11:27:00.907Z
Learning: The `lib.ConvertToBifrostContext` function in the bifrost HTTP transport never returns nil and always returns a pointer to a valid context. It starts with context.Background() and only adds values to it, so nil checks are not needed when calling this function.

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from 2b7b78a to c30de52 Compare June 9, 2025 13:50
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-refactor_http_transport_gemini_integration_refactors branch from e339c57 to 1618f5d Compare June 9, 2025 13:50
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
transports/bifrost-http/integrations/anthropic/types.go (1)

261-278: ⚠️ Potential issue

tool_choice ignored unless tools supplied
Placing the conversion inside if r.Tools != nil means a valid request like
{"tool_choice":{"type":"auto"}} is silently discarded when the caller provides no tools array.

-	if r.Tools != nil {
-	    ...
-	    bifrostReq.Params.Tools = &tools
-
-		// Convert tool choice
-		if r.ToolChoice != nil {
-		    ...
-		}
-	}
+	if r.Tools != nil {
+	    ...
+	    bifrostReq.Params.Tools = &tools
+	}
+
+	// Convert tool choice (independent of tools)
+	if r.ToolChoice != nil {
+	    toolChoice := &schemas.ToolChoice{
+	        Type: func() schemas.ToolChoiceType {
+	            if r.ToolChoice.Type == "tool" {
+	                return schemas.ToolChoiceTypeFunction
+	            }
+	            return schemas.ToolChoiceType(strings.ToLower(r.ToolChoice.Type))
+	        }(),
+	    }
+	    if r.ToolChoice.Type == "tool" && r.ToolChoice.Name != "" {
+	        toolChoice.Function = schemas.ToolChoiceFunction{Name: r.ToolChoice.Name}
+	    }
+	    if bifrostReq.Params == nil {
+	        bifrostReq.Params = &schemas.ModelParameters{}
+	    }
+	    bifrostReq.Params.ToolChoice = toolChoice
+	}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b7b78a and c30de52.

📒 Files selected for processing (7)
  • core/providers/anthropic.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/router.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/types.go (1 hunks)
  • transports/bifrost-http/integrations/genai/router.go (1 hunks)
  • transports/bifrost-http/integrations/openai/router.go (1 hunks)
  • transports/bifrost-http/integrations/utils.go (2 hunks)
  • transports/bifrost-http/main.go (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
core/providers/anthropic.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
transports/bifrost-http/integrations/anthropic/types.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
🧬 Code Graph Analysis (4)
transports/bifrost-http/main.go (1)
transports/bifrost-http/integrations/anthropic/router.go (1)
  • NewAnthropicRouter (16-39)
transports/bifrost-http/integrations/openai/router.go (1)
transports/bifrost-http/integrations/openai/types.go (1)
  • OpenAIChatRequest (36-57)
transports/bifrost-http/integrations/genai/router.go (1)
transports/bifrost-http/integrations/genai/types.go (1)
  • GeminiChatRequest (28-39)
transports/bifrost-http/integrations/anthropic/types.go (3)
core/utils.go (1)
  • Ptr (3-5)
core/schemas/bifrost.go (21)
  • ToolChoiceTypeFunction (126-126)
  • ToolChoice (137-140)
  • BifrostRequest (54-64)
  • Anthropic (36-36)
  • RequestInput (46-49)
  • BifrostMessage (143-152)
  • ModelChatMessageRoleSystem (25-25)
  • ModelChatMessageRole (20-20)
  • ToolCall (266-270)
  • Function (101-105)
  • FunctionCall (260-263)
  • AssistantMessage (166-171)
  • ModelChatMessageRoleTool (27-27)
  • ToolMessage (160-163)
  • ModelParameters (75-89)
  • Tool (108-112)
  • FunctionParameters (92-98)
  • ToolChoiceType (116-116)
  • ToolChoiceFunction (132-134)
  • BifrostResponse (184-194)
  • LLMUsage (197-203)
core/providers/anthropic.go (1)
  • AnthropicToolChoice (20-24)
🔇 Additional comments (7)
transports/bifrost-http/main.go (2)

32-32: Proper import structure for Anthropic integration.

The import follows the established pattern and naming convention used by other integrations.


184-184: Correct registration of Anthropic router.

The Anthropic router is properly registered in the extensions slice, following the same pattern as GenAI and OpenAI routers. This ensures the /anthropic/v1/messages endpoint will be available.

core/providers/anthropic.go (1)

485-487: Improved tool choice handling with unified logic.

The fallthrough statement effectively consolidates the handling of schemas.ToolChoiceTypeFunction and "tool" cases, ensuring both execute the same logic that sets tool_choice with type "tool" and the function name. This reduces code duplication and aligns with the established pattern of using object format for tool choices.

transports/bifrost-http/integrations/utils.go (2)

42-42: Enhanced concurrency safety with factory function pattern.

Replacing the static RequestType field with GetRequestTypeInstance function ensures each HTTP request gets a fresh request instance, preventing potential data races and memory issues in concurrent scenarios.


97-97: Correct implementation of factory function usage.

The call to config.GetRequestTypeInstance() properly creates a new request instance for each handler invocation, supporting the thread-safe request processing architecture.

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

24-26: Proper adoption of factory function pattern.

The GenAI router correctly implements the new GetRequestTypeInstance pattern, ensuring fresh GeminiChatRequest instances for each request. This change aligns with the broader refactoring to improve concurrency safety across all integration routers.

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

21-23: Factory func is the right call – good alignment with utils refactor
Replacing the static RequestType with GetRequestTypeInstance prevents cross-request data leakage. Looks clean.

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-refactor_http_transport_gemini_integration_refactors branch from 1618f5d to bb0425c Compare June 9, 2025 14:20
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch 2 times, most recently from 15286f9 to 5e6692a Compare June 9, 2025 14:27
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-refactor_http_transport_gemini_integration_refactors branch from bb0425c to c664c44 Compare June 9, 2025 14:27
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from 5e6692a to 2841d24 Compare June 9, 2025 14:32
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-refactor_http_transport_gemini_integration_refactors branch 2 times, most recently from efe4ba6 to 46def42 Compare June 9, 2025 16:27
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from 2841d24 to a008712 Compare June 9, 2025 16:27
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🔭 Outside diff range comments (1)
transports/bifrost-http/integrations/utils.go (1)

98-110: ⚠️ Potential issue

Returned request instance can be nil

json.Unmarshal with a nil destination triggers panic: runtime error: invalid memory address.
Even with the above struct check, a buggy factory function could still return nil. Add a guard before unmarshalling.

-        if method != "GET" && method != "DELETE" {
+        if req == nil {
+            g.sendError(ctx, fasthttp.StatusInternalServerError, "request factory returned nil")
+            return
+        }
+
+        if method != "GET" && method != "DELETE" {
♻️ Duplicate comments (6)
transports/bifrost-http/integrations/anthropic/router.go (1)

21-33: 💡 Verification agent

🧩 Analysis chain

ResponseFunc may return nil → sends 200 null

DeriveAnthropicFromBifrostResponse can legitimately return nil (e.g., internal error).
GenericRouter.sendSuccess will happily marshal that as the literal JSON word null with status 200.

Consider hard-failing or mapping to a structured error instead:

-            ResponseFunc: func(resp *schemas.BifrostResponse) interface{} {
-                return DeriveAnthropicFromBifrostResponse(resp)
-            },
+            ResponseFunc: func(resp *schemas.BifrostResponse) interface{} {
+                out := DeriveAnthropicFromBifrostResponse(resp)
+                if out == nil {
+                    return map[string]string{"error": "empty response from core"}
+                }
+                return out
+            },

🏁 Script executed:

#!/bin/bash
set -e

# Locate the Anthropich router file
file=$(rg -l "AnthropicMessageRequest")
echo "Found file: $file"

# Find the DeriveAnthropicFromBifrostResponse references and definition
echo -e "\n=== References to DeriveAnthropicFromBifrostResponse ==="
rg -n "DeriveAnthropicFromBifrostResponse" "$file"

echo -e "\n=== Implementation of DeriveAnthropicFromBifrostResponse ==="
rg -n "func DeriveAnthropicFromBifrostResponse" -C5 "$file"

# Inspect GenericRouter.sendSuccess to see how nil is handled
echo -e "\n=== sendSuccess implementation (context) ==="
rg -n "sendSuccess" -C5 .

Length of output: 862


🏁 Script executed:

#!/bin/bash
set -e

echo "=== DeriveAnthropicFromBifrostResponse references in anthropic directory ==="
rg -n "DeriveAnthropicFromBifrostResponse" -C3 transports/bifrost-http/integrations/anthropic

echo -e "\n=== Definition of DeriveAnthropicFromBifrostResponse ==="
rg -n "func .*DeriveAnthropicFromBifrostResponse" -C5 .

echo -e "\n=== sendSuccess implementation in GenericRouter ==="
rg -n "sendSuccess" -C5 .

Length of output: 4884


🏁 Script executed:

#!/bin/bash
set -e

echo "=== Integration wrapper error handling & response flow ==="
sed -n '130,200p' transports/bifrost-http/integrations/utils.go

Length of output: 1972


Prevent 200 null by guarding against nil in ResponseFunc

The current ResponseFunc returns nil when DeriveAnthropicFromBifrostResponse yields nil (e.g. if the core response is nil), and sendSuccess then serializes that as a literal JSON null with HTTP 200. To avoid returning an empty payload, explicitly map nil outputs to a structured error.

• File: transports/bifrost-http/integrations/anthropic/router.go
• Update the ResponseFunc block as follows:

-           ResponseFunc: func(resp *schemas.BifrostResponse) interface{} {
-               return DeriveAnthropicFromBifrostResponse(resp)
-           },
+           ResponseFunc: func(resp *schemas.BifrostResponse) interface{} {
+               out := DeriveAnthropicFromBifrostResponse(resp)
+               if out == nil {
+                   // surface an error instead of 200 null
+                   return map[string]string{"error": "empty response from core"}
+               }
+               return out
+           },

This ensures callers receive a JSON error object instead of an unhelpful null.

transports/bifrost-http/integrations/anthropic/types.go (5)

11-12: 🧹 Nitpick (assertive)

Inline the function-type pointer – global var adds needless indirection
This was raised earlier and is still unresolved.
fnTypePtr is used once; inline bifrost.Ptr(string(schemas.ToolChoiceTypeFunction)) where needed and drop the global.


125-161: ⚠️ Potential issue

Image, structured tool_result, and multimodal content are silently discarded

The switch only handles "text", "tool_use", and a very lossy "tool_result" mapping.
All "image" blocks and non-string tool_result.content are ignored, leading to data loss for multimodal requests and structured tool output.

Recommend:

  1. Add a case for "image" that maps to an appropriate schemas.ImageContent or preserves raw payload.
  2. Preserve entire tool_result.content (marshal to JSON string, store in ToolMessage.Content, etc.) instead of extracting only strings.

206-278: 🛠️ Refactor suggestion

tool_choice conversion still gated by r.Tools != nil

When a caller sends tool_choice but omits a tools array (valid Anthropic usage), the choice is silently dropped because this block is nested inside if r.Tools != nil. Move the choice mapping outside the guard.

Also, Type is forwarded without case normalisation – "Auto" becomes invalid upstream.

-    if r.Tools != nil {
...
-        // Convert tool choice
-        if r.ToolChoice != nil {
+    if r.Tools != nil {
...
+    }
+
+    // Convert tool choice (independent of tools presence)
+    if r.ToolChoice != nil {
         toolChoice := &schemas.ToolChoice{
-            Type: func() schemas.ToolChoiceType {
-                if r.ToolChoice.Type == "tool" {
-                    return schemas.ToolChoiceTypeFunction
-                }
-                return schemas.ToolChoiceType(r.ToolChoice.Type)
-            }(),
+            Type: func() schemas.ToolChoiceType {
+                t := strings.ToLower(r.ToolChoice.Type)
+                if t == "tool" {
+                    return schemas.ToolChoiceTypeFunction
+                }
+                return schemas.ToolChoiceType(t)
+            }(),
         }

284-292: 🧹 Nitpick (assertive)

jsonifyInput swallows marshal errors – hides bad schemas

Returning "{}" masks real problems and complicates debugging.

Either propagate the error back (preferred) or at least log it:

-    jsonBytes, err := json.Marshal(input)
-    if err != nil {
-        return "{}"
-    }
-    return string(jsonBytes)
+    jsonBytes, err := json.Marshal(input)
+    if err != nil {
+        log.Printf("[anthropic] failed to marshal tool input: %v", err)
+        return "{}"
+    }
+    return string(jsonBytes)

335-372: ⚠️ Potential issue

DeriveAnthropicFromBifrostResponse drops thinking and tool_result blocks & may emit content:null

  1. Assistant thoughts (AssistantMessage.Thought) and tool_result messages are not propagated, breaking round-trip fidelity.
  2. If no content is generated, anthropicResp.Content stays nil → JSON "content": null, which violates Anthropic’s spec (must be an array).
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5e6692a and a008712.

📒 Files selected for processing (7)
  • core/providers/anthropic.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/router.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/types.go (1 hunks)
  • transports/bifrost-http/integrations/genai/router.go (1 hunks)
  • transports/bifrost-http/integrations/openai/router.go (1 hunks)
  • transports/bifrost-http/integrations/utils.go (2 hunks)
  • transports/bifrost-http/main.go (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
core/providers/anthropic.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
transports/bifrost-http/integrations/anthropic/types.go (2)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:105-113
Timestamp: 2025-06-09T14:56:14.936Z
Learning: Streaming functionality is not yet supported in the Bifrost system, so Stream flags are intentionally not propagated from integration requests to BifrostRequest.
🧬 Code Graph Analysis (3)
transports/bifrost-http/main.go (1)
transports/bifrost-http/integrations/anthropic/router.go (1)
  • NewAnthropicRouter (16-39)
transports/bifrost-http/integrations/openai/router.go (1)
transports/bifrost-http/integrations/openai/types.go (1)
  • OpenAIChatRequest (36-57)
transports/bifrost-http/integrations/genai/router.go (1)
transports/bifrost-http/integrations/genai/types.go (1)
  • GeminiChatRequest (29-40)
🔇 Additional comments (4)
transports/bifrost-http/main.go (1)

46-46: LGTM! Clean integration of Anthropic router.

The import and router registration follow the established pattern used for GenAI and OpenAI integrations. The documentation already includes the Anthropic endpoint example, showing good consistency.

Also applies to: 198-198

core/providers/anthropic.go (1)

485-487: LGTM! Improved tool choice handling for Anthropic integration.

The fallthrough ensures that both ToolChoiceTypeFunction and "tool" types are handled consistently, setting the tool choice with "type": "tool" format. This aligns with Anthropic's API requirements and supports the new integration.

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

21-23: LGTM! Improved request instance handling.

The factory function pattern ensures fresh OpenAIChatRequest instances per request, preventing potential issues with reusing instances across concurrent requests. This follows the consistent refactoring pattern applied across integration routers.

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

24-26: LGTM! Consistent request instance handling.

The factory function pattern ensures fresh GeminiChatRequest instances per request, maintaining consistency with the refactoring applied across all integration routers for improved thread safety.

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from a008712 to 78ab5c4 Compare June 9, 2025 16:42
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-refactor_http_transport_gemini_integration_refactors branch from 46def42 to 65a8762 Compare June 9, 2025 16:42
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from 78ab5c4 to 14088f7 Compare June 9, 2025 17:11
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (7)
transports/bifrost-http/integrations/utils.go (2)

40-46: Still missing nil-guards on factory / converter – runtime panic remains possible

Prior feedback already highlighted that GetRequestTypeInstance and RequestConverter must be checked for nil before use.
Neither the struct tag nor createHandler adds such guards, so an accidentally un-initialised route will crash the server on first request.
Please add the defensive checks shown in the previous review.


98-98: Dereferencing unchecked GetRequestTypeInstance repeats the panic risk

req := config.GetRequestTypeInstance() is executed unconditionally.
If the factory is nil the handler panics, taking down the entire HTTP process.
Add:

+if config.GetRequestTypeInstance == nil {
+    g.sendError(ctx, fasthttp.StatusInternalServerError, "route mis-configuration")
+    return
+}
transports/bifrost-http/integrations/anthropic/types.go (5)

11-11: Inline the constant – extra global adds noise

fnTypePtr is just a pointer to the literal "function". Inline bifrost.Ptr(string(schemas.ToolChoiceTypeFunction)) where used and drop the package-level var.


262-278: tool_choice conversion is skipped when tools is nil

The mapping sits inside the if r.Tools != nil block, so valid requests that specify tool_choice without a tools array drop the field.

Move the tool_choice logic outside the tools branch as flagged earlier.


285-293: jsonifyInput swallows marshal errors – hides bad tool inputs

Returning "{}" on error masks schema problems and makes debugging painful.
Log the error or propagate it so callers can react.


335-384: Nil content encodes as null, violating Anthropic spec

When no blocks are added, content stays nil and JSON marshals to null.
Initialise an empty slice to ensure "content":[].

var content []AnthropicContent
...
- anthropicResp.Content = content
+ if content == nil {
+     content = []AnthropicContent{}
+ }
+ anthropicResp.Content = content

157-171: 🛠️ Refactor suggestion

tool_result content loses the actual result payload

Only ToolCallID (and maybe an image) gets forwarded; content.Content (the tool’s return data) is silently discarded.
Downstream consumers therefore cannot read the tool output.

case "tool_result":
    if content.ToolUseID != nil {
        bifrostMsg.ToolMessage = &schemas.ToolMessage{
            ToolCallID: content.ToolUseID,
+           // Preserve textual / structured result if present
+           Content: func() *string {
+               if content.Content == nil {
+                   return nil
+               }
+               bytes, _ := json.Marshal(content.Content)
+               s := string(bytes)
+               return &s
+           }(),
        }
        ...
    }

Adjust the field names to match schemas.ToolMessage.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78ab5c4 and 14088f7.

📒 Files selected for processing (7)
  • core/providers/anthropic.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/router.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/types.go (1 hunks)
  • transports/bifrost-http/integrations/genai/router.go (1 hunks)
  • transports/bifrost-http/integrations/openai/router.go (1 hunks)
  • transports/bifrost-http/integrations/utils.go (2 hunks)
  • transports/bifrost-http/main.go (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
transports/bifrost-http/integrations/anthropic/router.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/router.go:19-33
Timestamp: 2025-06-09T16:46:31.997Z
Learning: In the GenericRouter (transports/bifrost-http/integrations), ResponseFunc is not called if the BifrostResponse parameter is nil, providing built-in protection against nil response marshaling.
transports/bifrost-http/integrations/anthropic/types.go (4)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:261-278
Timestamp: 2025-06-09T17:12:55.169Z
Learning: Anthropic's API consistently returns tool_choice enum values in lowercase only ("auto", "none", "any", "tool"), so case normalization is not needed when processing these values in the Anthropic integration layer.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:105-113
Timestamp: 2025-06-09T14:56:14.936Z
Learning: Streaming functionality is not yet supported in the Bifrost system, so Stream flags are intentionally not propagated from integration requests to BifrostRequest.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:326-376
Timestamp: 2025-06-09T16:56:44.370Z
Learning: In Anthropic's message format, `tool_result` content blocks are inputs sent TO the LLM (typically from user/system after tool execution), not outputs generated BY the LLM. LLM responses should only contain `text` and `tool_use` content types.
🧬 Code Graph Analysis (4)
transports/bifrost-http/main.go (1)
transports/bifrost-http/integrations/anthropic/router.go (1)
  • NewAnthropicRouter (16-39)
transports/bifrost-http/integrations/genai/router.go (1)
transports/bifrost-http/integrations/genai/types.go (1)
  • GeminiChatRequest (28-39)
transports/bifrost-http/integrations/anthropic/router.go (2)
transports/bifrost-http/integrations/utils.go (4)
  • GenericRouter (52-55)
  • RouteConfig (39-47)
  • RequestConverter (21-21)
  • NewGenericRouter (59-64)
transports/bifrost-http/integrations/anthropic/types.go (2)
  • AnthropicMessageRequest (90-102)
  • DeriveAnthropicFromBifrostResponse (315-386)
transports/bifrost-http/integrations/anthropic/types.go (3)
core/utils.go (1)
  • Ptr (3-5)
core/schemas/bifrost.go (21)
  • ToolChoiceTypeFunction (126-126)
  • ToolChoice (137-140)
  • BifrostRequest (54-64)
  • Anthropic (36-36)
  • RequestInput (46-49)
  • BifrostMessage (143-152)
  • ModelChatMessageRole (20-20)
  • ToolCall (266-270)
  • UserMessage (155-157)
  • ImageContent (174-179)
  • Function (101-105)
  • FunctionCall (260-263)
  • ToolMessage (160-163)
  • AssistantMessage (166-171)
  • ModelParameters (75-89)
  • Tool (108-112)
  • FunctionParameters (92-98)
  • ToolChoiceType (116-116)
  • ToolChoiceFunction (132-134)
  • BifrostResponse (184-194)
  • LLMUsage (197-203)
core/providers/anthropic.go (1)
  • AnthropicToolChoice (20-24)
🔇 Additional comments (4)
transports/bifrost-http/main.go (1)

48-48: LGTM! Clean integration of Anthropic support.

The import and router registration follow the established pattern for AI provider integrations. The implementation is consistent with the existing GenAI and OpenAI integrations.

Also applies to: 200-200

core/providers/anthropic.go (1)

486-487: LGTM! Unifies tool choice handling.

The fallthrough statement correctly unifies handling of both "function" and "tool" types, ensuring compatibility between different tool choice representations while maintaining the same parameter structure for Anthropic's API.

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

21-23: LGTM! Improved thread safety with factory pattern.

The factory function ensures each HTTP request gets a fresh OpenAIChatRequest instance, preventing potential shared state issues between concurrent requests.

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

24-26: LGTM! Consistent factory pattern implementation.

The factory function correctly mirrors the same pattern applied to the OpenAI router, ensuring fresh GeminiChatRequest instances per HTTP request and maintaining consistency across all integration routers.

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from 14088f7 to 317ed8a Compare June 9, 2025 17:19
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-refactor_http_transport_gemini_integration_refactors branch from e009a8b to 0709d38 Compare June 10, 2025 13:39
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from c9f43b6 to 4c58221 Compare June 10, 2025 13:39
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
transports/bifrost-http/integrations/anthropic/types.go (2)

11-12: Redundant global fnTypePtr variable

The helper is only used in one place and can be inlined with bifrost.Ptr(...). Removing the package-level var reduces indirection.


310-318: jsonifyInput hides marshal errors, hampering debugging

Returning "{}" silently when json.Marshal fails makes diagnosing schema issues difficult.
Log the error (or propagate it) before falling back.

This concern has been raised previously but is still unresolved.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9f43b6 and 4c58221.

📒 Files selected for processing (7)
  • core/providers/anthropic.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/router.go (1 hunks)
  • transports/bifrost-http/integrations/anthropic/types.go (1 hunks)
  • transports/bifrost-http/integrations/genai/router.go (1 hunks)
  • transports/bifrost-http/integrations/openai/router.go (1 hunks)
  • transports/bifrost-http/integrations/utils.go (5 hunks)
  • transports/bifrost-http/main.go (2 hunks)
🧰 Additional context used
🧠 Learnings (4)
core/providers/anthropic.go (1)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
transports/bifrost-http/integrations/anthropic/router.go (3)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/router.go:19-33
Timestamp: 2025-06-09T16:46:32.018Z
Learning: In the GenericRouter (transports/bifrost-http/integrations), ResponseFunc is not called if the BifrostResponse parameter is nil, providing built-in protection against nil response marshaling.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#67
File: transports/bifrost-http/integrations/anthropic/router.go:26-34
Timestamp: 2025-06-10T11:19:29.578Z
Learning: The Generic router in transports/bifrost-http/integrations/utils.go already handles nil pointers from RequestConverter functions. When a RequestConverter returns a nil *schemas.BifrostRequest, the Generic router automatically returns an HTTP 400 error, making additional nil checks in individual router implementations redundant.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#67
File: transports/bifrost-http/integrations/anthropic/router.go:26-34
Timestamp: 2025-06-10T11:19:29.578Z
Learning: The Generic router in transports/bifrost-http/integrations/utils.go already handles nil pointers from RequestConverter functions. When a RequestConverter returns a nil *schemas.BifrostRequest, the Generic router automatically returns an HTTP 400 error with "Invalid request" message, making additional nil checks in individual router implementations redundant.
transports/bifrost-http/integrations/utils.go (3)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#67
File: transports/bifrost-http/integrations/anthropic/router.go:26-34
Timestamp: 2025-06-10T11:19:29.578Z
Learning: The Generic router in transports/bifrost-http/integrations/utils.go already handles nil pointers from RequestConverter functions. When a RequestConverter returns a nil *schemas.BifrostRequest, the Generic router automatically returns an HTTP 400 error, making additional nil checks in individual router implementations redundant.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#67
File: transports/bifrost-http/integrations/anthropic/router.go:26-34
Timestamp: 2025-06-10T11:19:29.578Z
Learning: The Generic router in transports/bifrost-http/integrations/utils.go already handles nil pointers from RequestConverter functions. When a RequestConverter returns a nil *schemas.BifrostRequest, the Generic router automatically returns an HTTP 400 error with "Invalid request" message, making additional nil checks in individual router implementations redundant.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/utils.go:169-173
Timestamp: 2025-06-09T17:33:52.234Z
Learning: The ChatCompletionRequest method in the Bifrost client follows a contract where the result parameter will never be nil if the error parameter is nil. This means when error checking passes (err == nil), the result is guaranteed to be valid and can be safely used without additional nil checks.
transports/bifrost-http/integrations/anthropic/types.go (9)
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:131-180
Timestamp: 2025-06-10T13:11:37.842Z
Learning: In Anthropic API integration for Bifrost, messages won't contain both image and tool_result content blocks in the same message, so defensive guards against multiple embedded message structs are unnecessary in the content processing loop.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:261-278
Timestamp: 2025-06-09T17:12:55.222Z
Learning: Anthropic's API consistently returns tool_choice enum values in lowercase only ("auto", "none", "any", "tool"), so case normalization is not needed when processing these values in the Anthropic integration layer.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#55
File: core/providers/anthropic.go:483-494
Timestamp: 2025-06-04T09:36:27.956Z
Learning: In the Anthropic provider (core/providers/anthropic.go), the user has confirmed through practical experience that the tool_choice parameter should always use an object format with a "type" field (e.g., {"type": "auto"}, {"type": "tool", "name": "function_name"}), even though the official documentation examples sometimes show "auto" as a direct string. The current implementation correctly handles all tool choice types with the object format.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#63
File: transports/bifrost-http/integrations/openai/types.go:89-119
Timestamp: 2025-06-10T11:00:02.852Z
Learning: In the Bifrost OpenAI integration (transports/bifrost-http/integrations/openai/types.go), the convertOpenAIContent function currently only handles the last image URL when multiple images are present in a content array. The user Pratham-Mishra04 has acknowledged this limitation and indicated it's part of a larger architectural issue that will be addressed comprehensively later, rather than with piecemeal fixes.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:105-113
Timestamp: 2025-06-09T14:56:14.951Z
Learning: Streaming functionality is not yet supported in the Bifrost system, so Stream flags are intentionally not propagated from integration requests to BifrostRequest.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:326-376
Timestamp: 2025-06-09T16:56:44.395Z
Learning: In Anthropic's message format, `tool_result` content blocks are inputs sent TO the LLM (typically from user/system after tool execution), not outputs generated BY the LLM. LLM responses should only contain `text` and `tool_use` content types.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#64
File: transports/bifrost-http/integrations/genai/types.go:383-395
Timestamp: 2025-06-09T16:26:05.777Z
Learning: In the Bifrost schema (core/schemas/bifrost.go), only UserMessage and ToolMessage structs have ImageContent fields. AssistantMessage does not have an ImageContent field and cannot contain images. The schema design intentionally limits image content to user and tool messages only.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:129-145
Timestamp: 2025-06-10T11:12:26.840Z
Learning: Anthropic API does not support tool roles and images can only be present in user messages, not assistant or tool messages. Therefore, in Anthropic integration code, image content should always be assigned to UserMessage regardless of any other considerations.
Learnt from: Pratham-Mishra04
PR: maximhq/bifrost#65
File: transports/bifrost-http/integrations/anthropic/types.go:131-180
Timestamp: 2025-06-10T13:03:26.975Z
Learning: In Anthropic API message format, tool_result content blocks are sent by users in response to assistant tool calls, while image content blocks are typically sent in initial user messages. These content types follow different conversation flows and wouldn't naturally appear together in a single message, making defensive guards against multiple embedded message types unnecessary.
🧬 Code Graph Analysis (3)
transports/bifrost-http/main.go (1)
transports/bifrost-http/integrations/anthropic/router.go (1)
  • NewAnthropicRouter (16-39)
transports/bifrost-http/integrations/genai/router.go (1)
transports/bifrost-http/integrations/genai/types.go (1)
  • GeminiChatRequest (28-39)
transports/bifrost-http/integrations/anthropic/types.go (3)
core/utils.go (1)
  • Ptr (3-5)
core/schemas/bifrost.go (23)
  • ToolChoiceTypeFunction (126-126)
  • ToolChoice (137-140)
  • BifrostRequest (54-64)
  • Anthropic (36-36)
  • RequestInput (46-49)
  • BifrostMessage (143-152)
  • ModelChatMessageRoleSystem (25-25)
  • ModelChatMessageRole (20-20)
  • ToolCall (273-277)
  • UserMessage (155-157)
  • ImageContent (181-186)
  • Function (101-105)
  • FunctionCall (267-270)
  • ToolMessage (160-163)
  • ModelChatMessageRoleTool (27-27)
  • AssistantMessage (166-171)
  • ModelParameters (75-89)
  • Tool (108-112)
  • FunctionParameters (92-98)
  • ToolChoiceType (116-116)
  • ToolChoiceFunction (132-134)
  • BifrostResponse (191-201)
  • LLMUsage (204-210)
core/providers/anthropic.go (1)
  • AnthropicToolChoice (20-24)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Graphite / mergeability_check
  • GitHub Check: Graphite / mergeability_check
🔇 Additional comments (7)
transports/bifrost-http/main.go (1)

48-48: LGTM! Clean integration following established patterns.

The Anthropic integration is properly imported and registered alongside existing providers, maintaining consistency with the established architecture.

Also applies to: 200-200

core/providers/anthropic.go (1)

492-493: LGTM! Proper unification of equivalent tool choice types.

The fallthrough correctly consolidates handling of schemas.ToolChoiceTypeFunction and "tool" since both should use the same object format in Anthropic's API.

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

21-23: LGTM! Improved thread safety with dynamic request instantiation.

Replacing the static RequestType with GetRequestTypeInstance ensures each request gets a fresh instance, preventing potential data leakage between concurrent requests.

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

24-26: LGTM! Consistent dynamic instantiation pattern.

The change maintains consistency with other integration routers and provides the same thread safety benefits through dynamic request instantiation.

transports/bifrost-http/integrations/utils.go (3)

72-89: Excellent startup validation implementation!

The comprehensive validation at route registration time addresses previous performance concerns by failing fast during startup rather than checking on every request. The validation covers all critical fields and even tests the factory function.


119-119: LGTM! Dynamic request instantiation improves thread safety.

Using GetRequestTypeInstance() ensures each request gets a fresh instance, preventing potential data corruption in concurrent scenarios.


176-179: Good defensive programming with the post-callback nil check.

While the Bifrost client contract guarantees non-nil results when there's no error, this additional check provides protection against potential issues introduced by post-request callbacks.

Copy link
Contributor

akshaydeo commented Jun 10, 2025

Merge activity

  • Jun 10, 4:28 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 10, 4:32 PM UTC: Graphite rebased this pull request as part of a merge.
  • Jun 10, 4:33 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo akshaydeo changed the base branch from 06-09-refactor_http_transport_gemini_integration_refactors to graphite-base/65 June 10, 2025 16:29
@akshaydeo akshaydeo changed the base branch from graphite-base/65 to main June 10, 2025 16:31
@akshaydeo akshaydeo force-pushed the 06-09-feat_anthropic_integration_added_in_http_transport branch from 4c58221 to 684f6ee Compare June 10, 2025 16:32
@akshaydeo akshaydeo merged commit 39d3ffe into main Jun 10, 2025
1 of 2 checks passed
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Bug: Image Overwrite and Type Mismatch Bug

In ConvertToBifrostRequest, when an Anthropic message contains multiple image content blocks, only the last image is preserved for both UserMessage and ToolMessage image content, as previous images are overwritten. Additionally, the Type field within schemas.ImageContent is incorrectly assigned a *string from content.Source.Type instead of the expected *schemas.ImageContentType enum value.

transports/bifrost-http/integrations/anthropic/types.go#L137-L147

}
case "image":
if content.Source != nil {
bifrostMsg.UserMessage = &schemas.UserMessage{
ImageContent: &schemas.ImageContent{
Type: bifrost.Ptr(content.Source.Type),
URL: content.Source.Data,
MediaType: &content.Source.MediaType,
},
}
}

Fix in Cursor


Was this report helpful? Give feedback by reacting with 👍 or 👎

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.

2 participants