Skip to content

fix: minor claude code fixes - #4932

Merged
akshaydeo merged 1 commit into
devfrom
07-05-fix_minor_claude_code_fixes
Jul 5, 2026
Merged

fix: minor claude code fixes#4932
akshaydeo merged 1 commit into
devfrom
07-05-fix_minor_claude_code_fixes

Conversation

@TejasGhatte

@TejasGhatte TejasGhatte commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes two bugs in the Anthropic reverse-stream converter that caused incorrect content_block index numbering depending on the request path:

  1. Passthrough path (Claude Code): The converter was unconditionally consuming (and discarding) a content-block index for dropped server-tool result blocks (web_fetch, zero-result web_search). This is correct only on the passthrough path, where verbatim raw upstream frames are interleaved and indices must stay in lockstep. On the all-normalized path, this caused a gap in indices (e.g. [0, 1, 3] instead of [0, 1, 2]), which strict Anthropic SDK clients reject as a missing block.

  2. Tool version recognition: convertAnthropicToolToBifrost matched web_search and web_fetch tool types by exact version string. Any future-dated version (e.g. web_fetch_20260318) silently fell through to the client-function default instead of being recognized as a server tool.

Changes

  • Introduced a passthrough bool field on anthropicToResponsesStreamState and a SetResponsesStreamPassthrough(ctx) function. The transport calls this when shouldUsePassthrough is true; the converter reads it to decide whether to consume the discarded result-block index.
  • The index-consuming allocBlockIndex("") calls for web_fetch and resultless web_search are now gated on state.passthrough, keeping indices contiguous on the all-normalized path.
  • convertAnthropicToolToBifrost now matches web_search_* and web_fetch_* tool types by prefix (via strings.HasPrefix) in a separate switch typeStr := string(*tool.Type); { case ... } block before the exact-match switch, so any current or future dated version is correctly recognized.
  • The passthrough test harness (runAnthropicPassthrough) now calls SetResponsesStreamPassthrough to mirror what the transport does, keeping existing passthrough tests accurate.
  • Added TestAnthropicConverterOnly_IndicesContiguous to assert that the all-normalized path emits contiguous content_block_start indices 0, 1, 2, … across web_fetch, zero-result web_search, and combinations thereof.
  • Added TestServerSearchTools_VersionRecognition to assert that known and future-dated web_search_* / web_fetch_* tool types all map to the correct neutral server-tool type and never fall through to ResponsesToolTypeFunction.

Type of change

  • Bug fix

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations

How to test

go test ./core/providers/anthropic/... -run "TestAnthropicConverterOnly_IndicesContiguous|TestServerSearchTools_VersionRecognition|TestAnthropicPassthrough|TestAnthropicConverterOnlyStream"
go test ./transports/bifrost-http/...
go test ./...

TestAnthropicConverterOnly_IndicesContiguous will fail before the fix with output like:

non-contiguous content_block_start indices [0 1 3] (position 2 is index 3, not 2); native Anthropic never skips an index

TestServerSearchTools_VersionRecognition will fail before the fix for web_search_20260318 and web_fetch_20260318 with:

neutral tool type = "function", want "web_search" (must not fall through to a client function tool)

Breaking changes

  • No

Security considerations

None.

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

@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 Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an explicit passthrough mode flag to the Anthropic reverse-stream conversion state, gating content-block index allocation for web_search/web_fetch completions so indices stay aligned with raw upstream frames during passthrough and remain contiguous otherwise. Refactors tool-type matching to prefix-based recognition for versioned server tools, wires the flag from the HTTP transport, and adds regression tests.

Changes

Anthropic passthrough index alignment and tool version recognition

Layer / File(s) Summary
Passthrough state field and setter
core/providers/anthropic/responses.go
Adds a passthrough bool field to anthropicToResponsesStreamState and exported SetResponsesStreamPassthrough(ctx) to enable it on context-stored conversion state.
Gate index allocation on passthrough state
core/providers/anthropic/responses.go
WebSearchCall and WebFetchCall completion handling in ToAnthropicResponsesStreamResponse now allocate/discard the extra upstream result content-block index only when state.passthrough is true, previously unconditional.
Prefix-based server tool version recognition
core/providers/anthropic/responses.go, core/providers/anthropic/websearch_test.go
convertAnthropicToolToBifrost matches web_search_* and web_fetch_* tool types via strings.HasPrefix instead of enumerating version constants; a new test validates correct neutral tool-type mapping for versioned inputs.
Transport wiring and regression tests
transports/bifrost-http/integrations/anthropic.go, core/providers/anthropic/passthroughstream_test.go
The Anthropic streaming passthrough branch now calls SetResponsesStreamPassthrough(ctx); the passthrough test harness always enables passthrough mode; a new test asserts contiguous content_block_start indices for the converter-only (non-passthrough) path.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • maximhq/bifrost#4890: Addresses the same Anthropic Claude Code passthrough streaming behavior for web_search/web_fetch content-block index alignment with related test coverage.

Suggested reviewers: danpiths, akshaydeo, roroghost17

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR fixes Anthropic streaming/indexing bugs, not the requested Files API support for POST /v1/files. Implement the Files API upload workflow for OpenAI/Anthropic, or relink this PR to the correct issue.
Out of Scope Changes check ⚠️ Warning All code changes are Anthropic converter/test fixes and do not relate to Files API support. Remove the Anthropic-only fixes from this PR or split them into a separate PR tied to the correct issue.
Title check ❓ Inconclusive The title is related to the PR, but it's too generic to explain the specific Anthropic converter fixes. Use a more specific title such as "fix Anthropic content_block indexing and tool version recognition".
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The description matches the template and covers summary, changes, testing, and checklist items, with only optional sections left blank.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 07-05-fix_minor_claude_code_fixes

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

Copy link
Copy Markdown
Collaborator Author

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

@TejasGhatte
TejasGhatte marked this pull request as ready for review July 5, 2026 17:59
@greptile-apps

greptile-apps Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

The changes are narrowly scoped to the Claude Code passthrough streaming path and the tool-type converter; existing non-passthrough flows are unaffected and guarded by new tests.

The logic is correct and well-exercised by new tests. The one gap is a comment in convertAnthropicToolToBifrost that omits computer_use from the list of tools that stay in the exact-version switch, which could mislead a future contributor adding a new computer-use version constant.

The comment on lines 6317-6322 of core/providers/anthropic/responses.go should mention computer_use alongside code_execution and text_editor to keep the documentation accurate.

Important Files Changed

Filename Overview
core/providers/anthropic/responses.go Adds passthrough bool to anthropicToResponsesStreamState and gates the phantom block-index allocations for dropped web_fetch/web_search result blocks behind it; also switches convertAnthropicToolToBifrost from exact-version matching to prefix matching for web_search_/web_fetch_ tool types.
transports/bifrost-http/integrations/anthropic.go Calls SetResponsesStreamPassthrough(ctx) at the top of the passthrough branch so the reverse converter knows to consume phantom block indices; placed before ToAnthropicResponsesStreamResponse on every code path through that branch.
core/providers/anthropic/passthroughstream_test.go Fixes existing passthrough harness to call SetResponsesStreamPassthrough (required after the gating change) and adds TestAnthropicConverterOnly_IndicesContiguous covering the all-normalized path across five tool-combination scenarios.
core/providers/anthropic/websearch_test.go Adds TestServerSearchTools_VersionRecognition to guard that future-dated web_search_/web_fetch_ versions (e.g. 20260318) are correctly mapped to the neutral server-tool type rather than falling through to ResponsesToolTypeFunction.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant T as Transport (anthropic.go)
    participant C as Converter (responses.go)
    participant S as anthropicToResponsesStreamState

    Note over T,S: Per-frame callback, passthrough path (Claude Code)
    T->>S: "SetResponsesStreamPassthrough(ctx) passthrough=true"
    alt "raw frame RawResponse != nil"
        T-->>T: return raw SSE verbatim
    else converted frame mustConvertInPassthrough
        T->>C: ToAnthropicResponsesStreamResponse(ctx, resp)
        C->>S: state.passthrough true
        alt web_fetch / zero-result web_search
            C->>S: allocBlockIndex phantom keeps counter in lockstep
        end
        C-->>T: AnthropicStreamEvent slice
    end

    Note over T,S: Per-frame callback, all-normalized path curl/OpenAI-via-Anthropic
    T->>C: ToAnthropicResponsesStreamResponse(ctx, resp)
    C->>S: state.passthrough false
    Note over C: No phantom index consumed indices stay contiguous 0,1,2
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant T as Transport (anthropic.go)
    participant C as Converter (responses.go)
    participant S as anthropicToResponsesStreamState

    Note over T,S: Per-frame callback, passthrough path (Claude Code)
    T->>S: "SetResponsesStreamPassthrough(ctx) passthrough=true"
    alt "raw frame RawResponse != nil"
        T-->>T: return raw SSE verbatim
    else converted frame mustConvertInPassthrough
        T->>C: ToAnthropicResponsesStreamResponse(ctx, resp)
        C->>S: state.passthrough true
        alt web_fetch / zero-result web_search
            C->>S: allocBlockIndex phantom keeps counter in lockstep
        end
        C-->>T: AnthropicStreamEvent slice
    end

    Note over T,S: Per-frame callback, all-normalized path curl/OpenAI-via-Anthropic
    T->>C: ToAnthropicResponsesStreamResponse(ctx, resp)
    C->>S: state.passthrough false
    Note over C: No phantom index consumed indices stay contiguous 0,1,2
Loading

Reviews (1): Last reviewed commit: "fix: minor claude code fixes" | Re-trigger Greptile

Comment thread core/providers/anthropic/responses.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
core/providers/anthropic/websearch_test.go (1)

296-298: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor: Name: "web_fetch" reused for web_search test cases.

Every case constructs the tool with Name: "web_fetch", even the web_search_* rows. Doesn't affect correctness since convertAnthropicToolToBifrost dispatches on Type first, but it's confusing when reading/debugging a failing web_search case.

🧹 Suggested tweak
-			in := &AnthropicTool{Type: schemas.Ptr(AnthropicToolType(c.toolType)), Name: "web_fetch"}
+			in := &AnthropicTool{Type: schemas.Ptr(AnthropicToolType(c.toolType)), Name: c.toolType}
🤖 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/websearch_test.go` around lines 296 - 298, The test
setup in convertAnthropicToolToBifrost uses the same tool name for both
web_fetch and web_search cases, which makes the web_search scenarios harder to
read and debug. Update the AnthropicTool construction in websearch_test.go so
the name matches the case being exercised, especially in the web_search rows,
while keeping the existing Type-based dispatch unchanged. Use the
convertAnthropicToolToBifrost test table and the t.Run(c.toolType, ...) setup to
locate the shared test initializer.
🤖 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.

Nitpick comments:
In `@core/providers/anthropic/websearch_test.go`:
- Around line 296-298: The test setup in convertAnthropicToolToBifrost uses the
same tool name for both web_fetch and web_search cases, which makes the
web_search scenarios harder to read and debug. Update the AnthropicTool
construction in websearch_test.go so the name matches the case being exercised,
especially in the web_search rows, while keeping the existing Type-based
dispatch unchanged. Use the convertAnthropicToolToBifrost test table and the
t.Run(c.toolType, ...) setup to locate the shared test initializer.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b144d7e1-381e-49cd-8ba8-17e221da85f0

📥 Commits

Reviewing files that changed from the base of the PR and between 4be1d6d and 861f1c5.

📒 Files selected for processing (4)
  • core/providers/anthropic/passthroughstream_test.go
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/websearch_test.go
  • transports/bifrost-http/integrations/anthropic.go

akshaydeo commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • Jul 5, 9:56 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 5, 9:56 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit dff50b5 into dev Jul 5, 2026
13 of 16 checks passed
@akshaydeo
akshaydeo deleted the 07-05-fix_minor_claude_code_fixes branch July 5, 2026 21:56
@TejasGhatte TejasGhatte mentioned this pull request Jul 6, 2026
17 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Jul 6, 2026
18 tasks
Pratham-Mishra04 pushed a commit that referenced this pull request Jul 6, 2026
## Summary

Adds end-to-end test coverage for a set of provider egress streaming and truncation correctness bugs. The new tests assert that Bedrock `converse-stream` properly closes content blocks before terminating, that Anthropic normalized and Claude Code passthrough streams emit contiguous `content_block_start` indices starting from 0, and that Bedrock Responses API truncated responses correctly signal `status=incomplete` with `reason=max_output_tokens` in both streaming and non-streaming modes.

## Changes

- Added a `contentBlockStop`-before-`messageStop` assertion to the existing Bedrock `converse-stream` basic test to catch #4923.
- Added a `content_block_start` index contiguity check to the existing Anthropic normalized streaming test to catch gaps introduced by server-tool rewrites (#4890 / #4932).
- Added a new **section 17 – Provider Egress Streaming/Truncation Guards** with four requests:
  - Bedrock forced-tool `converse-stream` verifies `toolUse`, `contentBlockStop`, and `messageStop` ordering (#4923).
  - Anthropic normalized `web_fetch` streaming verifies contiguous `content_block_start` indices (#4932).
  - Bedrock Responses non-streaming truncation verifies `status=incomplete` and `incomplete_details.reason=max_output_tokens` (#4680).
  - Bedrock Responses streaming truncation verifies `response.incomplete` is emitted and `response.completed` is absent (#4680).
- Added a new **section 18 – Claude Code Passthrough server-tool streaming index contiguity** with three requests covering `web_search` (normal results), `web_search` (zero results), and `web_fetch` via the `claude-cli` User-Agent passthrough path (#4890).

## Type of change

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

## Affected areas

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

## How to test

Run the Postman/Newman collection against a live Bifrost instance:

```sh
newman run tests/e2e/api/collections/provider-harness.json \
  --env-var baseUrl=<BIFROST_URL> \
  --env-var bedrockModel=<BEDROCK_MODEL_ID> \
  --env-var anthropicKey=<ANTHROPIC_API_KEY>
```

All tests in sections 17 and 18 should pass. Specifically:
- Bedrock `converse-stream` responses must contain `contentBlockStop` before `messageStop`.
- All Anthropic streaming responses must have `content_block_start` indices `[0, 1, 2, …]` with no gaps.
- Bedrock Responses truncated (non-streaming) must return `status=incomplete` with `incomplete_details.reason=max_output_tokens`.
- Bedrock Responses truncated (streaming) must emit `response.incomplete` and must **not** emit `response.completed`.

## Breaking changes

- [x] No

## Related issues

Closes #4923, #4932, #4890, #4680

## Security considerations

None. These are read-only test assertions against existing API endpoints; no new credentials or secrets are introduced beyond those already required by the collection.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
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.

3 participants