Skip to content

normalize tool_search_tool_* on the Responses path - #5891

Merged
akshaydeo merged 6 commits into
devfrom
08-06-normalize_tool_search_tool__on_the_responses_path
Aug 6, 2026
Merged

normalize tool_search_tool_* on the Responses path#5891
akshaydeo merged 6 commits into
devfrom
08-06-normalize_tool_search_tool__on_the_responses_path

Conversation

@akshaydeo

@akshaydeo akshaydeo commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes a bug (#5279) where Anthropic's server-side tool-search meta-tool (tool_search_tool_regex_20251119 / tool_search_tool_bm25_20251119) was silently downcast to a plain custom client tool. Because normalizeResponsesToolType had no case for the dated tool_search_tool_* spellings, they passed through unchanged, missed every switch comparing against ResponsesToolTypeToolSearch, and were emitted without a type field — causing Anthropic to treat them as client tools and never run the server-side search. Additionally, Bedrock's Converse API cannot run server-side tool search at all (AWS restricts it to InvokeModel/InvokeModelWithResponseStream), so ToolSearch is now correctly gated per provider rather than assumed universally supported.

Changes

  • normalizeResponsesToolType now maps all tool_search_tool_* spellings (dated and undated, regex and bm25) to the canonical ResponsesToolTypeToolSearch, matching the existing pattern for other dated tool types.
  • toolSearchVariantName is introduced to recover the regex-vs-bm25 variant from the raw type string. The two variants are not interchangeable (regex expects Python re.search() patterns; bm25 expects natural language), so the variant is backfilled onto Name during unmarshaling when the caller declared the tool by type alone (as Anthropic's own Go/C# SDK examples do).
  • ResponsesTool.UnmarshalJSON is refactored from a map[string]interface{} decode + re-marshal round-trip to a single gjson.GetManyBytes pass. This eliminates redundant allocations and the intermediate marshal/unmarshal of structured fields (cache_control, allowed_callers, input_examples). Malformed JSON that the map decode previously rejected for free is now explicitly validated via gjson.ValidBytes. Wrong-typed scalar fields (e.g. "defer_loading": "true") continue to be silently skipped rather than rejected, preserving existing tolerance.
  • Provider feature map updated: ToolSearch is now asserted false for Bedrock (Converse cannot run it) and true for all other providers (Anthropic, Vertex, Azure).
  • Bedrock document placeholder tests updated to reflect that a document-only Converse message gets a required placeholder text block injected ahead of it.
  • Tracer test fixed to use trace.SnapshotForExport() instead of a bare struct copy, which would duplicate a sync.Mutex and share the underlying spans slice.

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

go test ./core/schemas/... ./core/providers/anthropic/... ./core/providers/bedrock/... ./core/internal/llmtests/... ./framework/tracing/...
  • Confirm TestResponsesToolUnmarshalNormalizesToolSearchType passes for all dated/undated/no-name variants.
  • Confirm TestConvertBifrostToolToAnthropicDatedToolSearch passes and that the emitted tool carries a type and no input_schema.
  • Confirm TestValidateResponsesToolsForProviderDatedToolSearch drops the dated regex variant for Bedrock and keeps it for Anthropic and Vertex.
  • Confirm TestProviderFeatureMapCompleteness passes with Bedrock asserting ToolSearch = false.

Breaking changes

  • Yes
  • No

Related issues

Closes #5279

Security considerations

None. Changes are confined to request normalization and JSON decoding; no auth, secrets, or PII are involved.

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

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added support for recognizing and preserving dated, regex, and BM25 tool-search variants across supported interfaces.
    • Improved Anthropic server-side tool-search handling, including provider filtering and message conversion.
  • Bug Fixes

    • Improved tool configuration parsing and round-trip serialization while preserving optional fields.
    • Improved Bedrock document conversion for Converse API compatibility.
    • Improved trace export reliability by safely copying exported data.
    • Clarified that ToolSearch is not supported through Bedrock Converse.
  • Documentation

    • Added guidance for excluding files and directories from indexing.

Walkthrough

The change normalizes dated and variant-specific tool-search types, adds Anthropic conversion coverage, updates Bedrock capability and document expectations, uses trace snapshots for injection, and documents .cursorignore patterns.

Changes

Tool search support

Layer / File(s) Summary
Responses tool normalization
core/schemas/responses.go, core/schemas/responsestoolunmarshal_test.go, core/schemas/serialization_test.go
Tool-search variants normalize to the canonical type. Variant names, common fields, optional fields, malformed JSON, and nested function wrappers receive explicit handling.
Anthropic tool-search conversion
core/providers/anthropic/toolsearchrequest_test.go
Tests cover typed server tools, deferred client tools, provider filtering, and dated Anthropic round trips.
Provider capability validation
core/internal/llmtests/provider_feature_support_test.go
Bedrock is marked unsupported for ToolSearch. Other providers retain ToolSearch support.

Bedrock document conversion expectations

Layer / File(s) Summary
Placeholder text block expectations
core/providers/bedrock/bedrock_test.go
Tests expect a placeholder text block before converted document content and preserve the document format.

Tracing snapshot delivery

Layer / File(s) Summary
Trace snapshot injection
framework/tracing/tracer_test.go
Observability plugin injection uses Trace.SnapshotForExport().

Cursor indexing documentation

Layer / File(s) Summary
Ignore pattern documentation
.cursorignore
The file documents directory and file-pattern exclusions.

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

Sequence Diagram(s)

sequenceDiagram
  participant ResponsesTool
  participant normalizeResponsesToolType
  participant AnthropicConversion
  ResponsesTool->>normalizeResponsesToolType: Decode tool type
  normalizeResponsesToolType->>ResponsesTool: Return canonical tool-search type
  ResponsesTool->>AnthropicConversion: Pass normalized tool
  AnthropicConversion->>ResponsesTool: Preserve dated Anthropic variant
Loading

Possibly related PRs

  • maximhq/bifrost#4711: Both changes modify Responses tool-search normalization and unmarshalling behavior.
  • maximhq/bifrost#5280: Both changes extend normalization for Anthropic tool-search variants.
  • maximhq/bifrost#5817: The related change introduced the Bedrock document placeholder covered by these tests.

Suggested reviewers: pratham-mishra04, tejasghatte

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the primary normalization change for tool_search_tool_* on the Responses path.
Description check ✅ Passed The description covers the required sections, explains the changes, identifies affected areas, and provides targeted test commands and expected outcomes.
✨ 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 08-06-normalize_tool_search_tool__on_the_responses_path

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

@akshaydeo
akshaydeo marked this pull request as ready for review August 6, 2026 07:32
@akshaydeo akshaydeo mentioned this pull request Aug 6, 2026
18 tasks

@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

🤖 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/schemas/responses.go`:
- Around line 2439-2473: Restrict the normalization case in
normalizeResponsesToolType to recognize only tool_search_tool_regex and
tool_search_tool_bm25 forms, including their supported dated or undated
variants, while leaving unrelated values such as tool_search_preview unchanged
for unknown-tool handling. Add a regression test covering the prefix-sharing
unknown type and preserve the existing canonical ResponsesToolTypeToolSearch
result for recognized variants.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: 8a7403d1-e45f-465e-941d-3e6385061271

📥 Commits

Reviewing files that changed from the base of the PR and between 53d6ff5 and f6c605d.

📒 Files selected for processing (8)
  • .cursorignore
  • core/internal/llmtests/provider_feature_support_test.go
  • core/providers/anthropic/toolsearchrequest_test.go
  • core/providers/bedrock/bedrock_test.go
  • core/schemas/responses.go
  • core/schemas/responsestoolunmarshal_test.go
  • core/schemas/serialization_test.go
  • framework/tracing/tracer_test.go

Comment thread core/schemas/responses.go Outdated
@akshaydeo
akshaydeo force-pushed the 08-05-deepseek_thinking_fixes branch from 53d6ff5 to d088d10 Compare August 6, 2026 09:11
@akshaydeo
akshaydeo force-pushed the 08-06-normalize_tool_search_tool__on_the_responses_path branch from f6c605d to 8c154bc Compare August 6, 2026 09:11
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@akshaydeo
akshaydeo force-pushed the 08-05-deepseek_thinking_fixes branch from d088d10 to 76ea20e Compare August 6, 2026 17:18
@akshaydeo
akshaydeo force-pushed the 08-06-normalize_tool_search_tool__on_the_responses_path branch from 8c154bc to 656f6a1 Compare August 6, 2026 17:18
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@akshaydeo akshaydeo mentioned this pull request Aug 6, 2026
18 tasks

@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

🤖 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/schemas/responses.go`:
- Around line 2757-2761: Update convertBifrostToolToAnthropic and
toolSearchVariantName so explicit tool-search names are validated against only
the exact supported values tool_search_tool_regex and tool_search_tool_bm25;
reject unsupported names rather than preserving them or mapping them to BM25,
while retaining inference only when t.Name is nil.
🪄 Autofix

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: CHILL

Plan: Pro Plus

Run ID: cf4a9dd9-bb6c-4080-abfb-bee545860e7a

📥 Commits

Reviewing files that changed from the base of the PR and between 76ea20e and 656f6a1.

📒 Files selected for processing (8)
  • .cursorignore
  • core/internal/llmtests/provider_feature_support_test.go
  • core/providers/anthropic/toolsearchrequest_test.go
  • core/providers/bedrock/bedrock_test.go
  • core/schemas/responses.go
  • core/schemas/responsestoolunmarshal_test.go
  • core/schemas/serialization_test.go
  • framework/tracing/tracer_test.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • .cursorignore
  • framework/tracing/tracer_test.go
  • core/schemas/serialization_test.go
  • core/providers/bedrock/bedrock_test.go
  • core/internal/llmtests/provider_feature_support_test.go
  • core/providers/anthropic/toolsearchrequest_test.go
  • core/schemas/responsestoolunmarshal_test.go

Comment thread core/schemas/responses.go
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 6, 2026
@akshaydeo
akshaydeo force-pushed the 08-06-normalize_tool_search_tool__on_the_responses_path branch from 656f6a1 to f15a03d Compare August 6, 2026 18:01
@akshaydeo
akshaydeo force-pushed the 08-05-deepseek_thinking_fixes branch from 76ea20e to 45a458b Compare August 6, 2026 18:01
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@akshaydeo
akshaydeo force-pushed the 08-06-normalize_tool_search_tool__on_the_responses_path branch from f15a03d to 8eabaaf Compare August 6, 2026 19:38
@akshaydeo
akshaydeo force-pushed the 08-05-deepseek_thinking_fixes branch from 45a458b to 84c3bdd Compare August 6, 2026 19:38
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@akshaydeo
akshaydeo force-pushed the 08-06-normalize_tool_search_tool__on_the_responses_path branch from 8eabaaf to 7d0f894 Compare August 6, 2026 19:57
@akshaydeo
akshaydeo force-pushed the 08-05-deepseek_thinking_fixes branch from 84c3bdd to d3d2281 Compare August 6, 2026 19:57
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

akshaydeo commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Aug 6, 7:58 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Aug 6, 8:03 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo changed the base branch from 08-05-deepseek_thinking_fixes to graphite-base/5891 August 6, 2026 20:02
@akshaydeo
akshaydeo changed the base branch from graphite-base/5891 to dev August 6, 2026 20:03
@akshaydeo
akshaydeo dismissed coderabbitai[bot]’s stale review August 6, 2026 20:03

The base branch was changed.

@akshaydeo
akshaydeo requested a review from a team as a code owner August 6, 2026 20:03
@akshaydeo
akshaydeo merged commit 4b17b6f into dev Aug 6, 2026
6 checks passed
@akshaydeo
akshaydeo deleted the 08-06-normalize_tool_search_tool__on_the_responses_path branch August 6, 2026 20:03
akshaydeo added a commit that referenced this pull request Aug 7, 2026
## Summary

Fixes a bug (#5279) where Anthropic's server-side tool-search meta-tool (`tool_search_tool_regex_20251119` / `tool_search_tool_bm25_20251119`) was silently downcast to a plain custom client tool. Because `normalizeResponsesToolType` had no case for the dated `tool_search_tool_*` spellings, they passed through unchanged, missed every switch comparing against `ResponsesToolTypeToolSearch`, and were emitted without a `type` field — causing Anthropic to treat them as client tools and never run the server-side search. Additionally, Bedrock's Converse API cannot run server-side tool search at all (AWS restricts it to `InvokeModel`/`InvokeModelWithResponseStream`), so `ToolSearch` is now correctly gated per provider rather than assumed universally supported.

## Changes

- **`normalizeResponsesToolType`** now maps all `tool_search_tool_*` spellings (dated and undated, regex and bm25) to the canonical `ResponsesToolTypeToolSearch`, matching the existing pattern for other dated tool types.
- **`toolSearchVariantName`** is introduced to recover the regex-vs-bm25 variant from the raw type string. The two variants are not interchangeable (regex expects Python `re.search()` patterns; bm25 expects natural language), so the variant is backfilled onto `Name` during unmarshaling when the caller declared the tool by type alone (as Anthropic's own Go/C# SDK examples do).
- **`ResponsesTool.UnmarshalJSON`** is refactored from a `map[string]interface{}` decode + re-marshal round-trip to a single `gjson.GetManyBytes` pass. This eliminates redundant allocations and the intermediate marshal/unmarshal of structured fields (`cache_control`, `allowed_callers`, `input_examples`). Malformed JSON that the map decode previously rejected for free is now explicitly validated via `gjson.ValidBytes`. Wrong-typed scalar fields (e.g. `"defer_loading": "true"`) continue to be silently skipped rather than rejected, preserving existing tolerance.
- **Provider feature map** updated: `ToolSearch` is now asserted `false` for Bedrock (Converse cannot run it) and `true` for all other providers (Anthropic, Vertex, Azure).
- **Bedrock document placeholder tests** updated to reflect that a document-only Converse message gets a required placeholder text block injected ahead of it.
- **Tracer test** fixed to use `trace.SnapshotForExport()` instead of a bare struct copy, which would duplicate a `sync.Mutex` and share the underlying spans slice.

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./core/schemas/... ./core/providers/anthropic/... ./core/providers/bedrock/... ./core/internal/llmtests/... ./framework/tracing/...
```

- Confirm `TestResponsesToolUnmarshalNormalizesToolSearchType` passes for all dated/undated/no-name variants.
- Confirm `TestConvertBifrostToolToAnthropicDatedToolSearch` passes and that the emitted tool carries a `type` and no `input_schema`.
- Confirm `TestValidateResponsesToolsForProviderDatedToolSearch` drops the dated regex variant for Bedrock and keeps it for Anthropic and Vertex.
- Confirm `TestProviderFeatureMapCompleteness` passes with Bedrock asserting `ToolSearch = false`.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

Closes #5279

## Security considerations

None. Changes are confined to request normalization and JSON decoding; no auth, secrets, or PII are involved.

## Checklist

- [x] 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)
- [x] I verified the CI pipeline passes locally if applicable
@akshaydeo akshaydeo mentioned this pull request Aug 7, 2026
18 tasks
atharvamhaske pushed a commit to atharvamhaske/bifrost that referenced this pull request Aug 13, 2026
## Summary

Fixes a bug (maximhq#5279) where Anthropic's server-side tool-search meta-tool (`tool_search_tool_regex_20251119` / `tool_search_tool_bm25_20251119`) was silently downcast to a plain custom client tool. Because `normalizeResponsesToolType` had no case for the dated `tool_search_tool_*` spellings, they passed through unchanged, missed every switch comparing against `ResponsesToolTypeToolSearch`, and were emitted without a `type` field — causing Anthropic to treat them as client tools and never run the server-side search. Additionally, Bedrock's Converse API cannot run server-side tool search at all (AWS restricts it to `InvokeModel`/`InvokeModelWithResponseStream`), so `ToolSearch` is now correctly gated per provider rather than assumed universally supported.

## Changes

- **`normalizeResponsesToolType`** now maps all `tool_search_tool_*` spellings (dated and undated, regex and bm25) to the canonical `ResponsesToolTypeToolSearch`, matching the existing pattern for other dated tool types.
- **`toolSearchVariantName`** is introduced to recover the regex-vs-bm25 variant from the raw type string. The two variants are not interchangeable (regex expects Python `re.search()` patterns; bm25 expects natural language), so the variant is backfilled onto `Name` during unmarshaling when the caller declared the tool by type alone (as Anthropic's own Go/C# SDK examples do).
- **`ResponsesTool.UnmarshalJSON`** is refactored from a `map[string]interface{}` decode + re-marshal round-trip to a single `gjson.GetManyBytes` pass. This eliminates redundant allocations and the intermediate marshal/unmarshal of structured fields (`cache_control`, `allowed_callers`, `input_examples`). Malformed JSON that the map decode previously rejected for free is now explicitly validated via `gjson.ValidBytes`. Wrong-typed scalar fields (e.g. `"defer_loading": "true"`) continue to be silently skipped rather than rejected, preserving existing tolerance.
- **Provider feature map** updated: `ToolSearch` is now asserted `false` for Bedrock (Converse cannot run it) and `true` for all other providers (Anthropic, Vertex, Azure).
- **Bedrock document placeholder tests** updated to reflect that a document-only Converse message gets a required placeholder text block injected ahead of it.
- **Tracer test** fixed to use `trace.SnapshotForExport()` instead of a bare struct copy, which would duplicate a `sync.Mutex` and share the underlying spans slice.

## Type of change

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

## Affected areas

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

## How to test

```sh
go test ./core/schemas/... ./core/providers/anthropic/... ./core/providers/bedrock/... ./core/internal/llmtests/... ./framework/tracing/...
```

- Confirm `TestResponsesToolUnmarshalNormalizesToolSearchType` passes for all dated/undated/no-name variants.
- Confirm `TestConvertBifrostToolToAnthropicDatedToolSearch` passes and that the emitted tool carries a `type` and no `input_schema`.
- Confirm `TestValidateResponsesToolsForProviderDatedToolSearch` drops the dated regex variant for Bedrock and keeps it for Anthropic and Vertex.
- Confirm `TestProviderFeatureMapCompleteness` passes with Bedrock asserting `ToolSearch = false`.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

Closes maximhq#5279

## Security considerations

None. Changes are confined to request normalization and JSON decoding; no auth, secrets, or PII are involved.

## Checklist

- [x] 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)
- [x] 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.

[Bug]: OpenAI /v1/responses → Anthropic drops the tool_search_tool_regex type, so server-side tool_search never runs

1 participant