Skip to content

feat: advisor tool compatibility claude - #4357

Merged
akshaydeo merged 1 commit into
devfrom
06-13-feat_advisor_tool_compatibility_claude
Jun 15, 2026
Merged

akshaydeo merged 1 commit into
devfrom
06-13-feat_advisor_tool_compatibility_claude

Conversation

@TejasGhatte

@TejasGhatte TejasGhatte commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Briefly explain the purpose of this PR and the problem it solves.

Changes

  • What was changed and why
  • Any notable design decisions or trade-offs

Type of change

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

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

Describe the steps to validate this change. Include commands and expected outcomes.

# Core/Transports
go version
go test ./...

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

If adding new configs or environment variables, document them here.

Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

Breaking changes

  • Yes
  • No

If yes, describe impact and migration instructions.

Related issues

Link related issues and discussions. Example: Closes #123

Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

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

Summary by CodeRabbit

  • New Features

    • Added end-to-end Anthropic “advisor” tool support across streaming and non-streaming conversions, including call/result pairing, preserved content ordering, and full tool configuration mapping.
  • Behavior

    • Auto-injects the advisor beta header for Anthropic requests only; omits it for other providers.
    • Enforces provider/tool gating and rejects unsupported raw advisor tools.
  • Tests

    • Expanded unit and regression coverage for advisor JSON round-trips, conversion correctness, streaming preservation, gating, and beta-header behavior.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


tejas ghatte seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds full support for Anthropic's advisor server-tool across the neutral Responses schema and Anthropic provider: introduces advisor message/tool types, Anthropic advisor types and JSON wiring, provider gating and beta-header handling, bidirectional streaming and non-stream conversions preserving advisor call/result pairs and tool config, OpenAI filtering, and comprehensive tests.

Changes

Anthropic Advisor Tool Implementation

Layer / File(s) Summary
Neutral advisor message and tool schema
core/schemas/responses.go, core/schemas/serialization_test.go
Introduces ResponsesMessageTypeAdvisorCall and ResponsesAdvisorCall, adds ResponsesToolTypeAdvisor and ResponsesToolAdvisor (model, max_uses, max_tokens, optional caching), normalizes versioned advisor_* types, and adds JSON marshal/unmarshal support and tests for round-trip preservation.
Anthropic provider advisor types and constants
core/providers/anthropic/types.go
Adds AnthropicToolTypeAdvisor20260301, AnthropicToolNameAdvisor, AnthropicAdvisorBetaHeader/prefix, AnthropicToolAdvisor and AnthropicToolAdvisorCaching, includes advisor variant in AnthropicTool, adds StopReason on AnthropicContentBlock, and updates Marshal/Unmarshal wiring.
Provider validation, feature gating, and beta-header handling
core/providers/anthropic/utils.go, core/providers/anthropic/utils_test.go
Maps advisor_ prefix to AdvisorTool feature, enforces ValidateToolsForProvider for advisor tools, auto-injects AnthropicAdvisorBetaHeader when appropriate, registers beta-header prefix, and rejects raw advisor tools for Vertex/Bedrock/Azure; includes per-provider tests.
Streaming state and SSE ↔ Bifrost conversion
core/providers/anthropic/responses.go
Extends AnthropicResponsesStreamState with advisor tracking fields (tool_id, output index, result block). Anthropic SSE→Bifrost recognizes server_tool_use named advisor, emits output_item.added for ResponsesMessageTypeAdvisorCall, accumulates advisor_tool_result, and emits output_item.done with result payload. Bifrost→Anthropic SSE emits content_block_start/content_block_stop for server_tool_use and corresponding advisor_tool_result with mapped result fields.
Bifrost ↔ Anthropic message conversion
core/providers/anthropic/responses.go
Bifrost→Anthropic handles ResponsesMessageTypeAdvisorCall by flushing pending tool results and inserting paired server_tool_use + advisor_tool_result blocks via helper while preserving reasoning-first ordering; Anthropic→Bifrost maps server_tool_use to ResponsesMessageTypeAdvisorCall and matches advisor_tool_result by tool_use_id, attaching result fields including stop reason.
Advisor tool configuration round-trip conversion
core/providers/anthropic/responses.go
Maps AnthropicToolTypeAdvisor20260301ResponsesToolTypeAdvisor preserving model, max_uses, max_tokens, and optional caching (type/ttl) both directions.
Comprehensive advisor test coverage
core/providers/anthropic/advisor_test.go
Adds fixtures and tests for advisor JSON round-trip, neutral tool round-trip, provider gating, beta-header filtering, message block round-trip preserving ordering/tool_use_id/result text, and streaming SSE round-trip preserving advisor blocks and final text block.
Cross-provider filtering and transport cleanup
core/providers/openai/advisor_filter_test.go, transports/bifrost-http/integrations/anthropic.go
Adds test ensuring OpenAI request conversion drops advisor tools; reorders two imports in Anthropic HTTP transport (no behavior change).

Sequence Diagram(s)

sequenceDiagram
  participant AnthropicSSE as Anthropic SSE
  participant StreamConv as Stream Converter
  participant Bifrost as Bifrost Stream
  AnthropicSSE->>StreamConv: content_block_start (server_tool_use name="advisor")
  StreamConv->>Bifrost: output_item.added (ResponsesMessageTypeAdvisorCall)
  AnthropicSSE->>StreamConv: content_block_start/stop (advisor_tool_result with result payload)
  StreamConv->>Bifrost: output_item.done (advisor result_type + advisor_text/encrypted/error)
  Bifrost->>StreamConv: ResponsesMessageTypeAdvisorCall (completion or result)
  StreamConv->>AnthropicSSE: content_block_stop (server_tool_use) + content_block_start/stop (advisor_tool_result)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • akshaydeo
  • danpiths

Poem

🐰 With a twitch and a hop I test the stream,
advisor blocks preserved like a dream,
JSON, SSE, and tool IDs too,
round-trips hum as the code passes through,
carrots for CI, and a small victory cream.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is entirely empty—only the template structure is present with no substantive content filled in for any of the required sections. Fill in all required description sections: Summary, Changes, Type of change, Affected areas, How to test, Related issues, Security considerations, and complete the checklist.
Linked Issues check ⚠️ Warning The linked issue (#123) concerns Files API support for file uploads, but the PR implements Anthropic advisor tool support for the Responses API—a fundamentally different feature with no overlap. Verify the linked issue is correct or relink to the appropriate advisor tool feature issue. If this PR is unrelated to #123, remove the incorrect link and link to the actual advisor tool requirements.
Title check ❓ Inconclusive The title 'feat: advisor tool compatibility claude' is vague and incomplete, lacking clarity about what advisor tool compatibility means or what specific feature is being added. Clarify the title to be more specific about the advisor tool implementation, e.g., 'feat: add Anthropic advisor tool support for Bifrost Responses API'.
✅ Passed checks (2 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed All code changes (advisors types, responses conversions, tests, utilities, and OpenAI filtering) are cohesively focused on implementing Anthropic advisor tool support with no out-of-scope modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 92.31% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 06-13-feat_advisor_tool_compatibility_claude

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

@TejasGhatte
TejasGhatte marked this pull request as ready for review June 13, 2026 05:32

TejasGhatte commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/anthropic/types.go`:
- Around line 1285-1290: The Anthropic advisor model must be non-empty before
sending: in the Responses-to-Anthropic conversion path (advisor_20260301 branch)
check tool.ResponsesToolAdvisor.Model and if it is the empty string either
omit/strip the AnthropicToolAdvisor (do not assign an empty Model) or reject the
tool early; update the conversion logic that assigns AnthropicToolAdvisor.Model
so it only sets the field when non-empty (rather than relying on
ValidateToolsForProvider), ensuring the resulting request JSON never omits a
required-but-empty model field.

In `@core/providers/anthropic/utils_test.go`:
- Around line 850-873: The table-driven test needs Bedrock and Azure coverage
for advisor header non-injection: add two test cases similar to the "Vertex
skips advisor header" entry but with provider set to schemas.Bedrock and
schemas.Azure respectively, using the same req (AnthropicMessageRequest with an
AnthropicTool whose Type is AnthropicToolTypeAdvisor20260301, Name is
AnthropicToolNameAdvisor and AnthropicToolAdvisor.Model "claude-opus-4-8") and
assert unexpectHeaders contains AnthropicAdvisorBetaHeader so
AddMissingBetaHeadersToContext behavior is fully covered.

In `@core/schemas/responses.go`:
- Line 1797: ResponsesTool.MarshalJSON and ResponsesTool.UnmarshalJSON currently
omit the new advisor variant, causing advisor-specific fields to be dropped;
update both methods to detect and handle the ResponsesToolAdvisor variant (type
ResponsesToolAdvisor) so that the advisor discriminator is emitted/consumed and
its fields model, max_uses, max_tokens, and caching are preserved during
marshaling and unmarshaling (add case logic where other tool types are handled,
serialize the advisor struct into the same wrapper used by other tools, and on
UnmarshalJSON detect the advisor discriminator and populate a
ResponsesToolAdvisor instance with those fields).

In `@transports/bifrost-http/integrations/anthropic.go`:
- Around line 89-94: Remove the stale commented-out passthrough block (the lines
that reference soToolName, isClaudeModel, and resp.ExtraFields.RawResponse) from
the core converter path in anthropic.go so the dead code is deleted entirely;
this means deleting the commented lines that begin with "// soToolName, _ :=
ctx.Value(...)" through the closing commented if-block to avoid ambiguity and
accidental reintroduction.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fb69afc7-6025-4ec1-940e-4cfac47e8a07

📥 Commits

Reviewing files that changed from the base of the PR and between 0bbef33 and 9ea022a.

📒 Files selected for processing (9)
  • core/providers/anthropic/advisor_response_test.go
  • core/providers/anthropic/advisor_test.go
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/types.go
  • core/providers/anthropic/utils.go
  • core/providers/anthropic/utils_test.go
  • core/providers/openai/advisor_filter_test.go
  • core/schemas/responses.go
  • transports/bifrost-http/integrations/anthropic.go

Comment thread core/providers/anthropic/types.go
Comment thread core/providers/anthropic/utils_test.go
Comment thread core/schemas/responses.go
Comment thread transports/bifrost-http/integrations/anthropic.go Outdated
@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

Safe to merge; the advisor tool path is fully isolated behind provider gating and the existing passthrough path for direct Anthropic responses is untouched.

The change adds new functionality on a well-gated code path. State fields are properly reset in both the pool-acquire and flush functions. The advisor_tool_result.content bare-object constraint is handled correctly in every code path. Streaming index arithmetic stays correct because getOrCreateOutputIndex increments once per SSE content block, keeping logical output indices aligned with SSE content block indices for the content_block_stop reconstruction. Provider gating rejects advisor on Vertex, Bedrock, and Azure through both the structured and raw-passthrough paths. Test coverage is thorough across all major scenarios.

No files require special attention.

Important Files Changed

Filename Overview
core/providers/anthropic/responses.go Core streaming and non-streaming advisor logic: state fields (AdvisorToolID, AdvisorOutputIndex, AdvisorResult) with proper reset in acquireAnthropicResponsesStreamState and flush; content_block_start/stop handlers; convertBifrostAdvisorCallToAnthropicBlocks; ConvertBifrostMessagesToAnthropicMessages advisor_call case
core/providers/anthropic/types.go Adds AnthropicToolAdvisor and AnthropicToolAdvisorCaching types, AnthropicToolTypeAdvisor20260301 constant, ContentObj field on AnthropicContent for bare-object serialization, and custom MarshalJSON/UnmarshalJSON for AnthropicTool to handle shared max_uses field across variant structs
core/providers/anthropic/utils.go Adds advisor_ to anthropicToolTypePrefixToFeature, ValidateToolsForProvider, AddMissingBetaHeadersToContext, betaHeaderPrefixKnown, betaHeaderPrefixToFeature, and unsupportedRawToolTypes for Vertex, Bedrock, and Azure
core/schemas/responses.go Adds ResponsesMessageTypeAdvisorCall, ResponsesAdvisorCall, ResponsesToolTypeAdvisor, ResponsesToolAdvisor types with correct MarshalJSON/UnmarshalJSON and normalizeResponsesToolType support
core/providers/anthropic/advisor_test.go New test file covering advisor marshal round-trip, neutral schema round-trip, provider gating, raw tool gating, beta header filtering, non-streaming response round-trip (with bare-object content assertion), and streaming round-trip
transports/bifrost-http/integrations/anthropic.go Import reorder only; non-streaming passthrough (RawResponse fast path for Claude models) and streaming passthrough are both intact and unchanged
core/providers/openai/advisor_filter_test.go Verifies the advisor tool is stripped when routing through OpenAI (Anthropic-only tool), and the adjacent function tool survives
core/schemas/serialization_test.go Extends ResponsesTool round-trip and normalization tests to cover the advisor type with all config fields (model, max_uses, max_tokens, caching)
core/providers/anthropic/utils_test.go Extends AddMissingBetaHeadersToContext per-provider test table with four new cases: Anthropic gets the advisor header, Vertex/Bedrock/Azure do not

Reviews (6): Last reviewed commit: "feat: advisor tool compatibility claude" | Re-trigger Greptile

Comment thread core/providers/anthropic/advisor_response_test.go Outdated
@TejasGhatte
TejasGhatte force-pushed the 06-13-feat_advisor_tool_compatibility_claude branch from 9ea022a to 70762bc Compare June 13, 2026 13:50

@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: 6

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/utils.go (1)

1247-1258: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Align raw-path advisor rejection with typed-path provider gating.

ValidateToolsForProvider rejects advisor tools when features.AdvisorTool is false, but unsupportedRawToolTypes only blocks advisor_ for Vertex/Bedrock. This leaves Azure raw-body requests on a divergent path where advisor tools can slip through and fail later upstream instead of being rejected consistently at the provider boundary.

Suggested fix
 var unsupportedRawToolTypes = map[schemas.ModelProvider][]string{
 	schemas.Vertex: {
 		"web_fetch_",     // No web fetch support on Vertex
 		"code_execution", // No code execution on Vertex
 		"advisor_",       // Advisor tool is Anthropic API only
 	},
 	schemas.Bedrock: {
 		"web_search_",    // No web search on Bedrock
 		"web_fetch_",     // No web fetch on Bedrock
 		"code_execution", // No code execution on Bedrock
 		"advisor_",       // Advisor tool is Anthropic API only
 	},
+	schemas.Azure: {
+		"advisor_", // Advisor tool is Anthropic API only
+	},
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/anthropic/utils.go` around lines 1247 - 1258, The
provider-level gating is inconsistent: ValidateToolsForProvider rejects advisor
tools when features.AdvisorTool is false but unsupportedRawToolTypes only lists
"advisor_" for Vertex/Bedrock, allowing Azure raw-path advisor requests to slip
through; update the unsupportedRawToolTypes map in
core/providers/anthropic/utils.go to include "advisor_" for the Azure provider
(schemas.Azure) — or add a shared entry that applies to all providers that
should block advisor tools — so advisor_* raw tool types are rejected at the
provider boundary consistent with ValidateToolsForProvider.
transports/bifrost-http/integrations/anthropic.go (1)

89-93: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove active passthrough logic to match streaming behavior.

The unary ResponsesResponseConverter still returns raw responses for Claude models (lines 89-93), but the streaming path (lines 117-134) has had the same logic commented out. This inconsistency contradicts the PR's stated goal of "ensuring all responses use standard conversion logic." If the advisor feature requires conversion to handle advisor message types correctly, leaving this passthrough active means advisor calls in unary responses will bypass the converter and won't be processed.

Remove the passthrough block entirely so both unary and streaming responses flow through anthropic.ToAnthropicResponsesResponse(...).

🔧 Proposed fix to remove unary passthrough
 		ResponsesResponseConverter: func(ctx *schemas.BifrostContext, resp *schemas.BifrostResponsesResponse) (interface{}, error) {
-			soToolName, _ := ctx.Value(schemas.BifrostContextKeyStructuredOutputToolName).(string)
-			if soToolName == "" && isClaudeModel(resp.ExtraFields.OriginalModelRequested, resp.ExtraFields.ResolvedModelUsed, string(resp.ExtraFields.Provider)) {
-				if resp.ExtraFields.RawResponse != nil {
-					return resp.ExtraFields.RawResponse, nil
-				}
-			}
 			return anthropic.ToAnthropicResponsesResponse(ctx, resp), nil
 		},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@transports/bifrost-http/integrations/anthropic.go` around lines 89 - 93,
Remove the active passthrough in the unary ResponsesResponseConverter: delete
the if-block that checks soToolName == "" && isClaudeModel(...) and returns
resp.ExtraFields.RawResponse, and let the code flow into
anthropic.ToAnthropicResponsesResponse(...) so unary responses use the same
conversion logic as streaming; ensure no other early returns bypass the
converter for Claude/advisor responses.
♻️ Duplicate comments (1)
transports/bifrost-http/integrations/anthropic.go (1)

117-134: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Remove stale commented-out passthrough logic.

The commented-out streaming passthrough block should be deleted entirely to keep the converter path clean and unambiguous.

Suggested cleanup
 			ResponsesStreamResponseConverter: func(ctx *schemas.BifrostContext, resp *schemas.BifrostResponsesStreamResponse) (string, interface{}, error) {
-				// soToolName, _ := ctx.Value(schemas.BifrostContextKeyStructuredOutputToolName).(string)
-				// if soToolName == "" && shouldUsePassthrough(ctx, resp.ExtraFields.Provider, resp.ExtraFields.OriginalModelRequested, resp.ExtraFields.ResolvedModelUsed) {
-				// 	// Skip passthrough for ContentPartAdded: it's a synthetic bifrost event whose
-				// 	// RawResponse carries the parent content_block_start already emitted by OutputItemAdded.
-				// 	// Passing through here would produce a duplicate content_block_start that causes
-				// 	// the Anthropic SDK to error and drop all subsequent content_block_delta events.
-				// 	if resp.ExtraFields.RawResponse != nil && resp.Type != schemas.ResponsesStreamResponseTypeContentPartAdded {
-				// 		raw, ok := resp.ExtraFields.RawResponse.(string)
-				// 		if !ok {
-				// 			return "", nil, fmt.Errorf("expected RawResponse string, got %T", resp.ExtraFields.RawResponse)
-				// 		}
-				// 		if t := gjson.Get(raw, "type"); t.Exists() {
-				// 			return t.String(), raw, nil
-				// 		}
-				// 	}
-				// 	// Fallback: if RawResponse is not available, use bifrost-to-anthropic conversion
-				// 	// instead of silently dropping all events
-				// }
 				anthropicResponse := anthropic.ToAnthropicResponsesStreamResponse(ctx, resp)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@transports/bifrost-http/integrations/anthropic.go` around lines 117 - 134,
Remove the entire stale commented-out passthrough block (the lines referencing
soToolName, shouldUsePassthrough(...), the RawResponse handling with fmt.Errorf,
the ResponsesStreamResponseTypeContentPartAdded check, and the gjson.Get raw
type inspection) so the Anthropic converter path contains no inactive
passthrough logic; locate the commented section by searching for
shouldUsePassthrough, RawResponse, and
ResponsesStreamResponseTypeContentPartAdded and delete that commented block
cleanly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/anthropic/advisor_test.go`:
- Around line 105-121: The test currently checks only type/name/model in
TestAdvisor_ResponsesRoundTrip; extend the assertions to verify that the advisor
configuration fields are round-tripped too by asserting
bifrostTool.ResponsesToolAdvisor.{MaxUses,MaxTokens,Caching} have the expected
values after convertBifrostToolFromAnthropic and then asserting
back.AnthropicToolAdvisor.{MaxUses,MaxTokens,Caching} match those same expected
values after convertBifrostToolToAnthropic; use the existing identifiers
bifrostTool, convertBifrostToolToAnthropic and back to locate where to add these
checks and fail the test if any field is missing or changed.

In `@core/providers/anthropic/responses.go`:
- Around line 1693-1705: The streaming code currently sets the advisor tool-use
ID from bifrostResp.Item.ID; change those branches to use
ResponsesToolMessage.CallID (e.g., use bifrostResp.CallID or
bifrostResp.ResponsesToolMessage.CallID as appropriate) when populating
AnthropicContentBlock.ID and the advisor_tool_result.tool_use_id so the
streaming path matches the non-stream helper that treats CallID as
authoritative; update both the Advisor "server_tool_use" content-block branch
(where streamResp.ContentBlock.ID is set) and the other streaming branch that
emits advisor_tool_result.tool_use_id to read CallID instead of Item.ID.
- Around line 37-40: The pooled struct fields AdvisorToolID, AdvisorOutputIndex
and AdvisorResult on AnthropicResponsesStreamState are not being cleared on
reuse; update acquireAnthropicResponsesStreamState() to initialize those fields
to nil/zero when handing out a state and modify
(*AnthropicResponsesStreamState).flush() to explicitly reset AdvisorToolID =
nil, AdvisorOutputIndex = nil (or 0 with pointer nil) and AdvisorResult = nil
before returning the object to the pool so no previous advisor data can leak
into the next request.
- Around line 1180-1214: The branch that emits an advisor_call done (inside the
advisor result handling where state.AdvisorResult/state.AdvisorToolID are
checked) currently returns the completed ResponsesMessage without persisting it;
add the same persistence used for other completed items by appending the
constructed item to state.OutputItems (use the existing outputIdx as the
index/key consistent with other codepaths) before clearing
state.AdvisorToolID/AdvisorResult and returning the output_item.done so
message_stop will include this advisor_call in response.Output.

In `@core/providers/openai/advisor_filter_test.go`:
- Line 15: Remove the unused local variable declaration model :=
"claude-opus-4-8" from the test in advisor_filter_test.go (or, if the intent was
to use it, replace its literal usage with this variable); ensure no other
references to model remain so the test compiles without the unused variable.

In `@core/schemas/serialization_test.go`:
- Around line 1245-1247: The table-driven tests that include the rows named
"advisor canonical" and "advisor_20260301" currently only assert tool.Type
(ResponsesToolTypeAdvisor); update those cases to also assert that the
unmarshaled tool.ResponsesToolAdvisor is non-nil and that its representative
field (e.g., Model or model) equals the expected value ("claude-opus-4-8").
Concretely, after checking tool.Type == ResponsesToolTypeAdvisor, add assertions
like tool.ResponsesToolAdvisor != nil and tool.ResponsesToolAdvisor.Model ==
"claude-opus-4-8" for both the canonical and versioned inputs so the advisor
payload branch is validated, not just the normalized type.

---

Outside diff comments:
In `@core/providers/anthropic/utils.go`:
- Around line 1247-1258: The provider-level gating is inconsistent:
ValidateToolsForProvider rejects advisor tools when features.AdvisorTool is
false but unsupportedRawToolTypes only lists "advisor_" for Vertex/Bedrock,
allowing Azure raw-path advisor requests to slip through; update the
unsupportedRawToolTypes map in core/providers/anthropic/utils.go to include
"advisor_" for the Azure provider (schemas.Azure) — or add a shared entry that
applies to all providers that should block advisor tools — so advisor_* raw tool
types are rejected at the provider boundary consistent with
ValidateToolsForProvider.

In `@transports/bifrost-http/integrations/anthropic.go`:
- Around line 89-93: Remove the active passthrough in the unary
ResponsesResponseConverter: delete the if-block that checks soToolName == "" &&
isClaudeModel(...) and returns resp.ExtraFields.RawResponse, and let the code
flow into anthropic.ToAnthropicResponsesResponse(...) so unary responses use the
same conversion logic as streaming; ensure no other early returns bypass the
converter for Claude/advisor responses.

---

Duplicate comments:
In `@transports/bifrost-http/integrations/anthropic.go`:
- Around line 117-134: Remove the entire stale commented-out passthrough block
(the lines referencing soToolName, shouldUsePassthrough(...), the RawResponse
handling with fmt.Errorf, the ResponsesStreamResponseTypeContentPartAdded check,
and the gjson.Get raw type inspection) so the Anthropic converter path contains
no inactive passthrough logic; locate the commented section by searching for
shouldUsePassthrough, RawResponse, and
ResponsesStreamResponseTypeContentPartAdded and delete that commented block
cleanly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8d4c2e16-d0a7-4d54-a266-34173aa63d04

📥 Commits

Reviewing files that changed from the base of the PR and between 9ea022a and 70762bc.

📒 Files selected for processing (9)
  • core/providers/anthropic/advisor_test.go
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/types.go
  • core/providers/anthropic/utils.go
  • core/providers/anthropic/utils_test.go
  • core/providers/openai/advisor_filter_test.go
  • core/schemas/responses.go
  • core/schemas/serialization_test.go
  • transports/bifrost-http/integrations/anthropic.go

Comment thread core/providers/anthropic/advisor_test.go
Comment thread core/providers/anthropic/responses.go
Comment thread core/providers/anthropic/responses.go
Comment thread core/providers/anthropic/responses.go
Comment thread core/providers/openai/advisor_filter_test.go
Comment thread core/schemas/serialization_test.go Outdated
@TejasGhatte
TejasGhatte force-pushed the 06-13-feat_advisor_tool_compatibility_claude branch from 70762bc to 43f63d8 Compare June 13, 2026 14:34

@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)
core/schemas/serialization_test.go (1)

744-783: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add a round-trip case for advisor_call.

This file now exercises advisor tool serialization, but the new ResponsesMessageTypeAdvisorCall / ResponsesAdvisorCall surface in core/schemas/responses.go still has no direct marshal/unmarshal coverage. Add a case that asserts the embedded advisor-call payload and a representative field like advisor_stop_reason survive the JSON boundary.

As per coding guidelines, **/*.go: apply standard Go review practices, including table-driven coverage for behavior changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/schemas/serialization_test.go` around lines 744 - 783, Add a round-trip
test case for ResponsesMessageTypeAdvisorCall by extending the inputs table in
TestResponsesTool_MarshalJSON_RoundTrip to include an advisor_call JSON fixture
that embeds a ResponsesAdvisorCall payload (with an embedded advisor tool object
and a representative field such as advisor_stop_reason). The new input should
mirror the existing advisor tool example structure
(model/max_uses/max_tokens/caching) wrapped under the "advisor_call" message
type and include "advisor_stop_reason"; then run the same
unmarshal→marshal→unmarshal assertions (the same Unmarshal/Marshal calls and
equality checks) so the ResponsesAdvisorCall and its advisor payload survive the
JSON boundary.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/anthropic/advisor_test.go`:
- Around line 308-339: The test currently only checks presence flags and reads
advisor text from ContentBlocks[0], which misses ordering regressions and the
alternate ContentStr representation; update the loop over emitted to (1) record
the sequence of content block types (using
AnthropicContentBlockTypeServerToolUse,
AnthropicContentBlockTypeAdvisorToolResult, AnthropicContentBlockTypeText) and
assert the expected order (at minimum that advisor_tool_result appears before
plain text and that server_tool_use precedes advisor_tool_result), and (2) when
extracting advisor text (from the code that sets advisorText), accept either
representation by checking ContentStr first and falling back to
ContentBlocks[0].Text (and if using ContentBlocks, search all blocks not just
index 0) so the test is robust to reordering and to ResponsesMessageContent
emitting ContentStr instead of ContentBlocks; update references to
sawAdvisorServerToolUse, sawAdvisorResult, sawText, advisorText and the emitted
scan logic accordingly.

In `@core/providers/anthropic/responses.go`:
- Around line 3684-3709: The grouped reverse conversion
convertAnthropicContentBlocksToResponsesMessagesGrouped currently treats
advisor-type blocks as generic tool calls and loses advisor-specific fields;
update convertAnthropicContentBlocksToResponsesMessagesGrouped to detect the
advisor-specific AnthropicContentBlock shape (e.g., block type or presence of
advisor result fields created by convertBifrostAdvisorCallToAnthropicBlocks),
and when found emit a ResponsesMessage with type
schemas.ResponsesMessageTypeAdvisorCall preserving all advisor-specific fields
(server_tool_use/advisor_tool_result) and tool IDs rather than mapping them to a
generic tool-call message; ensure the mapping logic mirrors the forward helper
convertBifrostAdvisorCallToAnthropicBlocks so round-trip fidelity is maintained
and include preservation of any ID bookkeeping used by
currentToolCallIDs/pendingToolCalls.
- Around line 4485-4498: The code appends an advisor_call for blocks with Name
== AnthropicToolNameAdvisor without verifying the block is an output message;
update the branch that creates bifrostMsg (using AnthropicToolNameAdvisor,
ResponsesMessage, ResponsesToolMessage, bifrostMessages, block) to also require
the same isOutputMessage check used by the web_search/web_fetch branches (i.e.,
only construct/append the advisor_call when isOutputMessage is true), so
non-output server_tool_use blocks are not converted into assistant advisor
calls.

In `@core/providers/anthropic/types.go`:
- Around line 1346-1354: In MarshalJSON in types.go (the method that constructs
the tool JSON), preserve explicitly provided empty domain arrays by changing the
conditions that inject allowed_domains and blocked_domains from "if len(allowed)
> 0" / "if len(blocked) > 0" to checks that the slices are non-nil (e.g., "if
allowed != nil" and "if blocked != nil"); this ensures an explicitly set empty
slice ([]), not just non-empty lists, will be serialized into the JSON rather
than dropped.

In `@core/schemas/responses.go`:
- Around line 2559-2565: ResponsesToolAdvisor.Model is marked required but its
JSON tag uses omitempty which allows an empty model to be omitted; remove
omitempty from the struct tag on the Model field in the ResponsesToolAdvisor
struct (change `json:"model,omitempty"` to `json:"model"`) so an empty/missing
model serializes as null/empty and surfaces validation errors upstream;
optionally run any existing schema/validation tests for ResponsesToolAdvisor to
ensure consumers react to the stricter serialization.

---

Outside diff comments:
In `@core/schemas/serialization_test.go`:
- Around line 744-783: Add a round-trip test case for
ResponsesMessageTypeAdvisorCall by extending the inputs table in
TestResponsesTool_MarshalJSON_RoundTrip to include an advisor_call JSON fixture
that embeds a ResponsesAdvisorCall payload (with an embedded advisor tool object
and a representative field such as advisor_stop_reason). The new input should
mirror the existing advisor tool example structure
(model/max_uses/max_tokens/caching) wrapped under the "advisor_call" message
type and include "advisor_stop_reason"; then run the same
unmarshal→marshal→unmarshal assertions (the same Unmarshal/Marshal calls and
equality checks) so the ResponsesAdvisorCall and its advisor payload survive the
JSON boundary.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e7846435-fffe-4722-b98b-527fd7cb6583

📥 Commits

Reviewing files that changed from the base of the PR and between 70762bc and 43f63d8.

📒 Files selected for processing (9)
  • core/providers/anthropic/advisor_test.go
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/types.go
  • core/providers/anthropic/utils.go
  • core/providers/anthropic/utils_test.go
  • core/providers/openai/advisor_filter_test.go
  • core/schemas/responses.go
  • core/schemas/serialization_test.go
  • transports/bifrost-http/integrations/anthropic.go

Comment thread core/providers/anthropic/advisor_test.go
Comment thread core/providers/anthropic/responses.go
Comment thread core/providers/anthropic/responses.go
Comment thread core/providers/anthropic/types.go
Comment thread core/schemas/responses.go
@TejasGhatte
TejasGhatte force-pushed the 06-13-feat_advisor_tool_compatibility_claude branch from 43f63d8 to 2a6f59b Compare June 14, 2026 11:33

@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/anthropic/types.go (2)

852-877: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve bare-object content on decode.

The new ContentObj arm is only honored on marshal. Lines 869-874 still decode a single block object into ContentBlocks, so {"content": {...}} round-trips back out as {"content": [{...}]}. That changes the wire shape for advisor_tool_result.content and defeats the new single-object support.

Suggested fix
 func (mc *AnthropicContent) UnmarshalJSON(data []byte) error {
+	mc.ContentStr = nil
+	mc.ContentBlocks = nil
+	mc.ContentObj = nil
+
 	// First, try to unmarshal as a direct string
 	var stringContent string
 	if err := sonic.Unmarshal(data, &stringContent); err == nil {
 		mc.ContentStr = &stringContent
 		return nil
@@
 	// Try to unmarshal as a single ContentBlock object (e.g., web_search_tool_result_error)
-	// If successful, wrap it in an array
+	// Preserve the bare-object form so marshal/unmarshal round-trips are stable.
 	var singleBlock AnthropicContentBlock
 	if err := sonic.Unmarshal(data, &singleBlock); err == nil && singleBlock.Type != "" {
-		mc.ContentBlocks = []AnthropicContentBlock{singleBlock}
+		mc.ContentObj = &singleBlock
 		return nil
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/anthropic/types.go` around lines 852 - 877, The UnmarshalJSON
method in AnthropicContent currently wraps a single ContentBlock object into an
array and assigns it to ContentBlocks (lines 869-874), which causes round-trip
issues where bare objects become arrays. When unmarshalling a single block
object (in the third condition where singleBlock.Type is not empty), assign it
directly to the ContentObj field instead of wrapping it in an array and
assigning to ContentBlocks. This preserves the bare object format and ensures
the wire shape remains unchanged during round-trip serialization and
deserialization.

1383-1412: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset stale union arms before unmarshaling a tool.

sonic.Unmarshal leaves absent fields untouched. If the same AnthropicTool instance is reused, an old MCPToolset, AnthropicToolWebSearch, or AnthropicToolWebFetch arm can survive into the next decode. The stale MCPToolset is especially bad because MarshalJSON will then serialize it instead of the newly decoded tool.

Suggested fix
 func (t *AnthropicTool) UnmarshalJSON(data []byte) error {
+	next := AnthropicTool{}
+
 	// Peek at the type field to detect mcp_toolset entries
 	var peek struct {
 		Type string `json:"type"`
 	}
 	if err := sonic.Unmarshal(data, &peek); err == nil && peek.Type == "mcp_toolset" {
 		var toolset AnthropicMCPToolsetTool
 		if err := sonic.Unmarshal(data, &toolset); err != nil {
 			return err
 		}
-		t.MCPToolset = &toolset
+		next.MCPToolset = &toolset
+		*t = next
 		return nil
 	}
 	// Default unmarshaling for all other tool types
 	type Alias AnthropicTool
-	if err := sonic.Unmarshal(data, (*Alias)(t)); err != nil {
+	if err := sonic.Unmarshal(data, (*Alias)(&next)); err != nil {
 		return err
 	}
@@
-	t.applySharedServerToolFields(shared.MaxUses, shared.AllowedDomains, shared.BlockedDomains)
+	next.applySharedServerToolFields(shared.MaxUses, shared.AllowedDomains, shared.BlockedDomains)
+	*t = next
 	return nil
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/anthropic/types.go` around lines 1383 - 1412, The
UnmarshalJSON method for AnthropicTool can leave stale union arm data
(MCPToolset, AnthropicToolWebSearch, AnthropicToolWebFetch) from previous
decodes because sonic.Unmarshal does not clear absent fields. Add code at the
very beginning of the UnmarshalJSON method to reset all union arms (MCPToolset,
AnthropicToolWebSearch, AnthropicToolWebFetch) to nil before proceeding with the
unmarshaling logic. This ensures that only the newly decoded tool data is
present and prevents stale arms from being serialized by MarshalJSON.
♻️ Duplicate comments (1)
core/providers/anthropic/responses.go (1)

3684-3709: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Mirror advisor semantics in the grouped Anthropic→Bifrost converter.

This adds the forward ResponsesMessageTypeAdvisorCall path, but the grouped reverse path used from Line 3165 still routes server_tool_use generically in convertAnthropicContentBlocksToResponsesMessagesGrouped and never reattaches advisor_tool_result. In grouped flows, advisor calls still degrade to generic function calls and lose ResponsesAdvisorCall payloads. As per coding guidelines, SDK integration layers must stay drop-in compatible with OpenAI, Anthropic, Bedrock, Google GenAI, LangChain, LiteLLM, and PydanticAI request/response shapes where relevant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/anthropic/responses.go` around lines 3684 - 3709, The forward
path correctly handles advisor calls via ResponsesMessageTypeAdvisorCall by
converting them to Anthropic blocks, but the reverse path in
convertAnthropicContentBlocksToResponsesMessagesGrouped (around line 3165)
treats all server_tool_use blocks generically without reattaching
advisor_tool_result, causing advisor calls to degrade to generic function calls.
In the grouped converter, when processing server_tool_use blocks, check for the
presence of advisor_tool_result; if present, construct a ResponsesAdvisorCall
message structure to preserve advisor semantics instead of routing it as a
generic function call, ensuring the forward and reverse paths maintain
consistent advisor call handling.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/anthropic/advisor_test.go`:
- Around line 309-344: Modify the test loop to record the sequence of block
types as they are encountered in the emitted events, rather than just setting
boolean flags. After the loop, add an assertion that verifies the blocks appear
in the expected order (server_tool_use before advisor_tool_result before text).
Additionally, make the advisor text extraction (where advisorText is assigned
from e.ContentBlock.Content.ContentObj.Text) more robust by adding fallback
logic to check alternative content paths if the primary ContentObj.Text path is
nil, ensuring the test doesn't fail due to schema representation changes.

In `@core/providers/anthropic/responses.go`:
- Around line 2177-2241: The code in this branch synthesizes an
advisor_tool_result block at serverIdx + 1, but when subsequent bifrostResp
items arrive with their original OutputIndex or ContentIndex values, they
collide with the inserted synthetic block, breaking Anthropic content ordering.
Implement per-request index translation that tracks when an extra block has been
injected (via the advisor call handler) and shifts all subsequent real events'
indexes by +1 to maintain unique indexes. This requires either a request-scoped
counter tracking inserted blocks or a translation map that offsets OutputIndex
and ContentIndex values from bifrostResp after the advisor call block injection
point.

---

Outside diff comments:
In `@core/providers/anthropic/types.go`:
- Around line 852-877: The UnmarshalJSON method in AnthropicContent currently
wraps a single ContentBlock object into an array and assigns it to ContentBlocks
(lines 869-874), which causes round-trip issues where bare objects become
arrays. When unmarshalling a single block object (in the third condition where
singleBlock.Type is not empty), assign it directly to the ContentObj field
instead of wrapping it in an array and assigning to ContentBlocks. This
preserves the bare object format and ensures the wire shape remains unchanged
during round-trip serialization and deserialization.
- Around line 1383-1412: The UnmarshalJSON method for AnthropicTool can leave
stale union arm data (MCPToolset, AnthropicToolWebSearch, AnthropicToolWebFetch)
from previous decodes because sonic.Unmarshal does not clear absent fields. Add
code at the very beginning of the UnmarshalJSON method to reset all union arms
(MCPToolset, AnthropicToolWebSearch, AnthropicToolWebFetch) to nil before
proceeding with the unmarshaling logic. This ensures that only the newly decoded
tool data is present and prevents stale arms from being serialized by
MarshalJSON.

---

Duplicate comments:
In `@core/providers/anthropic/responses.go`:
- Around line 3684-3709: The forward path correctly handles advisor calls via
ResponsesMessageTypeAdvisorCall by converting them to Anthropic blocks, but the
reverse path in convertAnthropicContentBlocksToResponsesMessagesGrouped (around
line 3165) treats all server_tool_use blocks generically without reattaching
advisor_tool_result, causing advisor calls to degrade to generic function calls.
In the grouped converter, when processing server_tool_use blocks, check for the
presence of advisor_tool_result; if present, construct a ResponsesAdvisorCall
message structure to preserve advisor semantics instead of routing it as a
generic function call, ensuring the forward and reverse paths maintain
consistent advisor call handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9068fac7-d448-4e0d-98a8-870bdeddd007

📥 Commits

Reviewing files that changed from the base of the PR and between 43f63d8 and 2a6f59b.

📒 Files selected for processing (9)
  • core/providers/anthropic/advisor_test.go
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/types.go
  • core/providers/anthropic/utils.go
  • core/providers/anthropic/utils_test.go
  • core/providers/openai/advisor_filter_test.go
  • core/schemas/responses.go
  • core/schemas/serialization_test.go
  • transports/bifrost-http/integrations/anthropic.go

Comment thread core/providers/anthropic/advisor_test.go
Comment thread core/providers/anthropic/responses.go
@TejasGhatte
TejasGhatte force-pushed the 06-13-feat_advisor_tool_compatibility_claude branch from 2a6f59b to 4ac7964 Compare June 15, 2026 04:46

@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/anthropic/types.go (1)

833-843: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include ContentObj in the content-union guard.

ContentObj is a third mutually exclusive arm, but the guard only checks ContentStr vs ContentBlocks. A mixed state like ContentObj + ContentBlocks silently drops the blocks during marshal.

Suggested fix
 func (mc AnthropicContent) MarshalJSON() ([]byte, error) {
 	// Validation: ensure only one field is set at a time
-	if mc.ContentStr != nil && mc.ContentBlocks != nil {
-		return nil, fmt.Errorf("both ContentStr and ContentBlocks are set; only one should be non-nil")
+	active := 0
+	if mc.ContentStr != nil {
+		active++
+	}
+	if mc.ContentBlocks != nil {
+		active++
+	}
+	if mc.ContentObj != nil {
+		active++
+	}
+	if active > 1 {
+		return nil, fmt.Errorf("only one of ContentStr, ContentBlocks, or ContentObj should be non-nil")
 	}
 
 	if mc.ContentStr != nil {
 		return providerUtils.MarshalSorted(*mc.ContentStr)
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/anthropic/types.go` around lines 833 - 843, The validation
guard clause in the MessageContent type only checks that ContentStr and
ContentBlocks are mutually exclusive, but neglects ContentObj which is also a
mutually exclusive field. Update the guard clause to validate that only one of
the three fields—ContentStr, ContentBlocks, and ContentObj—is set at a time.
Ensure the error check prevents any combination of these three fields from being
simultaneously non-nil, so that invalid states like ContentObj + ContentBlocks
cannot silently drop data during marshaling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/anthropic/responses.go`:
- Around line 1189-1196: The advisor result reading logic currently only
extracts data from ContentBlocks[0] in the state.AdvisorResult.Content
structure, but the forward path writes advisor results to
AnthropicContent.ContentObj. Modify the code to also check and read advisor
results from ContentObj in addition to ContentBlocks, ensuring that the Text,
EncryptedContent, ErrorCode, and StopReason fields are properly extracted from
either ContentObj or the first ContentBlock. This issue appears at multiple
locations (line 1189-1196, 2219-2227, and 4514-4523), and the same fix pattern
should be applied at all three sites to handle object-form advisor results that
are currently losing their fields.

---

Outside diff comments:
In `@core/providers/anthropic/types.go`:
- Around line 833-843: The validation guard clause in the MessageContent type
only checks that ContentStr and ContentBlocks are mutually exclusive, but
neglects ContentObj which is also a mutually exclusive field. Update the guard
clause to validate that only one of the three fields—ContentStr, ContentBlocks,
and ContentObj—is set at a time. Ensure the error check prevents any combination
of these three fields from being simultaneously non-nil, so that invalid states
like ContentObj + ContentBlocks cannot silently drop data during marshaling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a205eb2a-cd33-4841-90fa-e436cfbc79fe

📥 Commits

Reviewing files that changed from the base of the PR and between 2a6f59b and 4ac7964.

📒 Files selected for processing (9)
  • core/providers/anthropic/advisor_test.go
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/types.go
  • core/providers/anthropic/utils.go
  • core/providers/anthropic/utils_test.go
  • core/providers/openai/advisor_filter_test.go
  • core/schemas/responses.go
  • core/schemas/serialization_test.go
  • transports/bifrost-http/integrations/anthropic.go

Comment thread core/providers/anthropic/responses.go Outdated
@TejasGhatte
TejasGhatte force-pushed the 06-13-feat_advisor_tool_compatibility_claude branch from 4ac7964 to 5cca2ec Compare June 15, 2026 05:10

akshaydeo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • Jun 15, 5:19 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jun 15, 5:20 AM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit b54c433 into dev Jun 15, 2026
15 of 16 checks passed
@akshaydeo
akshaydeo deleted the 06-13-feat_advisor_tool_compatibility_claude branch June 15, 2026 05:20
akshaydeo pushed a commit that referenced this pull request Jun 15, 2026
## Summary

Briefly explain the purpose of this PR and the problem it solves.

## Changes

- What was changed and why
- Any notable design decisions or trade-offs

## Type of change

- [ ] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
# Core/Transports
go version
go test ./...

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

If adding new configs or environment variables, document them here.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

## Related issues

Link related issues and discussions. Example: Closes #123

## Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

## 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




<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added end-to-end Anthropic “advisor” tool support across streaming and non-streaming conversions, including call/result pairing, preserved content ordering, and full tool configuration mapping.

* **Behavior**
  * Auto-injects the advisor beta header for Anthropic requests only; omits it for other providers.
  * Enforces provider/tool gating and rejects unsupported raw advisor tools.

* **Tests**
  * Expanded unit and regression coverage for advisor JSON round-trips, conversion correctness, streaming preservation, gating, and beta-header behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
akhsaul pushed a commit to akhsaul/bifrost that referenced this pull request Aug 27, 2026
## Summary

Briefly explain the purpose of this PR and the problem it solves.

## Changes

- What was changed and why
- Any notable design decisions or trade-offs

## Type of change

- [ ] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
# Core/Transports
go version
go test ./...

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

If adding new configs or environment variables, document them here.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

## Related issues

Link related issues and discussions. Example: Closes maximhq#123

## Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

## 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




<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added end-to-end Anthropic “advisor” tool support across streaming and non-streaming conversions, including call/result pairing, preserved content ordering, and full tool configuration mapping.

* **Behavior**
  * Auto-injects the advisor beta header for Anthropic requests only; omits it for other providers.
  * Enforces provider/tool gating and rejects unsupported raw advisor tools.

* **Tests**
  * Expanded unit and regression coverage for advisor JSON round-trips, conversion correctness, streaming preservation, gating, and beta-header behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
occcat pushed a commit to occcat/bifrost that referenced this pull request Sep 2, 2026
## Summary

Briefly explain the purpose of this PR and the problem it solves.

## Changes

- What was changed and why
- Any notable design decisions or trade-offs

## Type of change

- [ ] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

Describe the steps to validate this change. Include commands and expected outcomes.

```sh
# Core/Transports
go version
go test ./...

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

If adding new configs or environment variables, document them here.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [ ] No

If yes, describe impact and migration instructions.

## Related issues

Link related issues and discussions. Example: Closes maximhq#123

## Security considerations

Note any security implications (auth, secrets, PII, sandboxing, etc.).

## 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




<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added end-to-end Anthropic “advisor” tool support across streaming and non-streaming conversions, including call/result pairing, preserved content ordering, and full tool configuration mapping.

* **Behavior**
  * Auto-injects the advisor beta header for Anthropic requests only; omits it for other providers.
  * Enforces provider/tool gating and rejects unsupported raw advisor tools.

* **Tests**
  * Expanded unit and regression coverage for advisor JSON round-trips, conversion correctness, streaming preservation, gating, and beta-header behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

Files API Support

3 participants