Skip to content

fix: distinguish custom and native provider tools - #932

Merged
AlemTuzlak merged 15 commits into
TanStack:mainfrom
jan-kubica:fix/anthropic-web-search-name-collision
Aug 19, 2026
Merged

fix: distinguish custom and native provider tools#932
AlemTuzlak merged 15 commits into
TanStack:mainfrom
jan-kubica:fix/anthropic-web-search-name-collision

Conversation

@jan-kubica

@jan-kubicajan-kubica commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

What changed

  • classify Anthropic, Gemini, and OpenAI native tools with stable, namespaced metadata.__kind values
  • preserve the documented type-only core ProviderTool phantom brand
  • keep ordinary functions custom even when their public names match provider-native tools
  • strip internal runtime markers before constructing provider wire payloads
  • cover Anthropic beta/skills selection and Gemini's experimental Interactions converter
  • add unit invariants for every native factory/name plus final-wire E2E coverage

Root cause

The Anthropic, Gemini, and OpenAI converters selected provider-native behavior by tool.name. Tool names are public application identifiers, so an ordinary function could accidentally enter a native converter, acquire provider-only request fields or beta headers, and fail or change behavior on only one provider.

Matching versioned provider metadata would fix individual payloads but couple classification to dated wire identifiers. This PR follows the existing OpenRouter and Grok convention instead: adapter-owned metadata carries a stable canonical kind, while provider API versions remain confined to wire converters.

Adapter details

  • Anthropic: all seven native factories use stable markers; beta and hosted-skill selection also use the marker rather than code_execution by name.
  • Gemini: all seven native factories use stable markers in both Generate Content and experimental Interactions paths. Interactions now translates the public Google Search factory's camelCase searchTypes metadata to its snake_case wire list.
  • OpenAI: all eleven special Responses tools, including the unbranded customTool, use stable markers in openai-base; @tanstack/ai-openai receives a patch release alongside the base package.

Test plan

  • every provider-native factory still selects its native converter
  • every provider-native public name remains valid for an ordinary function
  • runtime markers survive plain-data round trips
  • runtime markers never reach provider wire payloads
  • Anthropic custom web_search, OpenAI custom web_search, and Gemini custom google_search final-wire regressions
  • Gemini Interactions reserved-name and public-factory regression coverage

Summary by CodeRabbit

  • New Features

    • Provider-native tools now use stable identification across Anthropic, Gemini, and OpenAI integrations.
    • Standard function tools can safely share names with provider-native tools without triggering special behavior.
    • Provider tool identity is preserved through serialization and deserialization.
    • Gemini Google Search settings now translate correctly to the Interactions API format.
  • Bug Fixes

    • Corrected Anthropic code execution and skills handling for similarly named custom functions.
    • Improved provider tool conversion and metadata handling across supported integrations.
  • Tests

    • Added coverage for custom-name dispatch, wire formats, and serialized provider tools.

@coderabbitai

coderabbitaiBot commented Jul 14, 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

Anthropic, Gemini, and OpenAI provider tools now carry stable runtime kind discriminators. Converters use these discriminators instead of names. Tests cover custom-name collisions, JSON round trips, SDK output, Gemini search configuration translation, and wire payloads.

Changes

Provider tool dispatch

Layer / File(s)Summary
Anthropic discriminator and dispatch
packages/ai-anthropic/src/tools/*, packages/ai-anthropic/src/adapters/text.ts
Anthropic factories add __kind metadata. Converters remove the marker before transmission. Adapter logic dispatches by provider kind.
Gemini discriminator and dispatch
packages/ai-gemini/src/tools/*, packages/ai-gemini/src/experimental/text-interactions/adapter.ts
Gemini factories and adapter conversion use provider-kind metadata. Google Search settings map to Interactions search_types.
OpenAI discriminator and dispatch
packages/openai-base/src/tools/*, packages/ai-openai/src/tools/computer-use-tool.ts
OpenAI factories use the shared discriminator wrapper. Conversion dispatch uses decoded provider kinds.
Dispatch validation and wire coverage
packages/*/tests/*, testing/e2e/..., .changeset/tidy-searches-coexist.md
Tests cover factory branding, serialization, reserved-name custom tools, provider wire payloads, and patch release entries.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
participant Application
participant ToolFactory
participant ProviderConverter
participant ProviderAPI
Application->>ToolFactory: Create provider-native or ordinary tool
ToolFactory->>ToolFactory: Attach provider kind metadata
Application->>ProviderConverter: Convert tools
ProviderConverter->>ProviderAPI: Emit native tool or custom function
Loading

Suggested reviewers:alemtuzlak, jherr

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 44.83% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly and concisely summarizes the main change: distinguishing custom tools from native provider tools.
Description check✅ PassedThe description clearly explains the changes, root cause, adapter details, and test plan, but it omits the template checklist and release-impact sections.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@jan-kubicajan-kubica changed the title fix: distinguish custom Anthropic web search toolsfix: distinguish custom and native Anthropic toolsJul 14, 2026
@jan-kubicajan-kubica changed the title fix: distinguish custom and native Anthropic toolsfix: distinguish custom and native provider toolsJul 14, 2026
@jan-kubica
jan-kubica marked this pull request as ready for review July 14, 2026 10:59

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/ai-anthropic/tests/provider-tools-smoke.test.ts (1)

125-152: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix static analysis warnings by removing the unnecessary type assertion.

The static analysis tools indicate that the as unknown as Tool[] assertion is unnecessary and that Array<Tool> should be used instead of Tool[]. Since the array elements are already compatible with Tool, you can remove the assertion entirely.

♻️ Proposed refactor
 textEditorTool({
type: 'text_editor_20250124',
name: 'str_replace_editor',
}),
- ] as unknown as Tool[])+ ])
expect(converted).toHaveLength(7)
expect(JSON.stringify(converted)).not.toContain('__kind')
🤖 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 `@packages/ai-anthropic/tests/provider-tools-smoke.test.ts` around lines 125 -
152, Update the tool array passed to convertToolsToProviderFormat in the
“converts multiple provider tools in one call” test by removing the unnecessary
“as unknown as Tool[]” assertion; rely on the inferred compatible element types
and use Array<Tool> only if an explicit annotation is required.

Source: Linters/SAST tools

testing/e2e/src/routes/api.anthropic-skills-wire.ts (1)

3-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Combine imports to fix the import/order warning.

You can resolve the static analysis warning about the import order by combining the type import for Tool into the existing @tanstack/ai import statement.

♻️ Proposed refactor
 import { createFileRoute } from '`@tanstack/react-router`'
-import { chat, createChatOptions } from '`@tanstack/ai`'-import type { Tool } from '`@tanstack/ai`'+import { chat, createChatOptions, type Tool } from '`@tanstack/ai`'
import { createAnthropicChat } from '`@tanstack/ai-anthropic`'
import { codeExecutionTool } from '`@tanstack/ai-anthropic/tools`'
🤖 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 `@testing/e2e/src/routes/api.anthropic-skills-wire.ts` around lines 3 - 18,
Combine the `Tool` type import with the existing `@tanstack/ai` import in
`api.anthropic-skills-wire.ts`, preserving type-only semantics and leaving the
`createAnthropicChat` and `codeExecutionTool` imports unchanged.

Source: Linters/SAST tools

🤖 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 `@packages/ai-gemini/tests/provider-tool-dispatch.test.ts`:
- Line 1: Move provider-tool-dispatch.test.ts from the dedicated tests directory
to packages/ai-gemini/src/tools/provider-tool-dispatch.test.ts, keeping its test
contents unchanged and colocating it with the provider tool dispatch source it
covers.
In `@packages/openai-base/src/tools/computer-use-tool.ts`:
- Around line 42-45: Move the getOpenAIProviderToolMetadata and
openAIProviderTool import to the top of computer-use-tool.ts alongside the other
module imports, removing the duplicate import from its current location.
In `@packages/openai-base/src/tools/image-generation-tool.ts`:
- Around line 58-61: Move the openAIProviderTool import to the top import
section in packages/openai-base/src/tools/image-generation-tool.ts (lines
58-61), packages/openai-base/src/tools/mcp-tool.ts (lines 56-59), and
packages/openai-base/src/tools/shell-tool.ts (lines 54-57), preserving the
existing import ordering rules and leaving usage unchanged.
---
Nitpick comments:
In `@packages/ai-anthropic/tests/provider-tools-smoke.test.ts`:
- Around line 125-152: Update the tool array passed to
convertToolsToProviderFormat in the “converts multiple provider tools in one
call” test by removing the unnecessary “as unknown as Tool[]” assertion; rely on
the inferred compatible element types and use Array<Tool> only if an explicit
annotation is required.
In `@testing/e2e/src/routes/api.anthropic-skills-wire.ts`:
- Around line 3-18: Combine the `Tool` type import with the existing
`@tanstack/ai` import in `api.anthropic-skills-wire.ts`, preserving type-only
semantics and leaving the `createAnthropicChat` and `codeExecutionTool` imports
unchanged.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83f2bb1b-2f75-4d7a-893e-ce9b4caa56cb

📥 Commits

Reviewing files that changed from the base of the PR and between 5fcaf90 and ee9e7a0.

📒 Files selected for processing (45)
  • .changeset/tidy-searches-coexist.md
  • packages/ai-anthropic/src/adapters/text.ts
  • packages/ai-anthropic/src/tools/anthropic-provider-tool.ts
  • packages/ai-anthropic/src/tools/bash-tool.ts
  • packages/ai-anthropic/src/tools/code-execution-tool.ts
  • packages/ai-anthropic/src/tools/computer-use-tool.ts
  • packages/ai-anthropic/src/tools/memory-tool.ts
  • packages/ai-anthropic/src/tools/text-editor-tool.ts
  • packages/ai-anthropic/src/tools/tool-converter.ts
  • packages/ai-anthropic/src/tools/web-fetch-tool.ts
  • packages/ai-anthropic/src/tools/web-search-tool.ts
  • packages/ai-anthropic/tests/provider-tools-smoke.test.ts
  • packages/ai-anthropic/tests/text.skills.test.ts
  • packages/ai-gemini/src/experimental/text-interactions/adapter.ts
  • packages/ai-gemini/src/tools/code-execution-tool.ts
  • packages/ai-gemini/src/tools/computer-use-tool.ts
  • packages/ai-gemini/src/tools/file-search-tool.ts
  • packages/ai-gemini/src/tools/gemini-provider-tool.ts
  • packages/ai-gemini/src/tools/google-maps-tool.ts
  • packages/ai-gemini/src/tools/google-search-retriveal-tool.ts
  • packages/ai-gemini/src/tools/google-search-tool.ts
  • packages/ai-gemini/src/tools/tool-converter.ts
  • packages/ai-gemini/src/tools/url-context-tool.ts
  • packages/ai-gemini/tests/provider-tool-dispatch.test.ts
  • packages/ai-gemini/tests/text-interactions-adapter.test.ts
  • packages/ai-openai/src/tools/computer-use-tool.ts
  • packages/openai-base/src/tools/apply-patch-tool.ts
  • packages/openai-base/src/tools/code-interpreter-tool.ts
  • packages/openai-base/src/tools/computer-use-tool.ts
  • packages/openai-base/src/tools/custom-tool.ts
  • packages/openai-base/src/tools/file-search-tool.ts
  • packages/openai-base/src/tools/image-generation-tool.ts
  • packages/openai-base/src/tools/local-shell-tool.ts
  • packages/openai-base/src/tools/mcp-tool.ts
  • packages/openai-base/src/tools/openai-provider-tool.ts
  • packages/openai-base/src/tools/shell-tool.ts
  • packages/openai-base/src/tools/tool-converter.ts
  • packages/openai-base/src/tools/web-search-preview-tool.ts
  • packages/openai-base/src/tools/web-search-tool.ts
  • packages/openai-base/tests/provider-tool-dispatch.test.ts
  • testing/e2e/fixtures/provider-tool-dispatch/basic.json
  • testing/e2e/src/routes/api.anthropic-skills-wire.ts
  • testing/e2e/src/routes/api.provider-tool-dispatch-wire.ts
  • testing/e2e/tests/anthropic-skills-wire.spec.ts
  • testing/e2e/tests/provider-tool-dispatch-wire.spec.ts

@@ -0,0 +1,66 @@
import { describe, expect, it } from 'vitest'

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Move the test file alongside the source code it covers.

As per coding guidelines, unit tests should be placed in *.test.ts files alongside the source they cover, rather than in a dedicated tests/ directory.

Please move this file to packages/ai-gemini/src/tools/provider-tool-dispatch.test.ts.

🤖 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 `@packages/ai-gemini/tests/provider-tool-dispatch.test.ts` at line 1, Move
provider-tool-dispatch.test.ts from the dedicated tests directory to
packages/ai-gemini/src/tools/provider-tool-dispatch.test.ts, keeping its test
contents unchanged and colocating it with the provider tool dispatch source it
covers.

Source: Coding guidelines

Comment threadpackages/openai-base/src/tools/computer-use-tool.ts Outdated
Comment threadpackages/openai-base/src/tools/image-generation-tool.ts Outdated

@coderabbitaicoderabbitaiBot 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 `@packages/ai-gemini/src/tools/provider-tool-dispatch.test.ts`:
- Around line 10-11: In provider-tool-dispatch.test.ts, reorder the local
imports so convertToolsToProviderFormat from ./tool-converter appears before the
import from ./index, satisfying the repository’s import/order rule.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: f84c6766-9b2c-47d8-9b12-62fb35a31c35

📥 Commits

Reviewing files that changed from the base of the PR and between 9399c21 and d66f1ef.

📒 Files selected for processing (1)
  • packages/ai-gemini/src/tools/provider-tool-dispatch.test.ts

Comment on lines +10 to +11
} from './index'
import { convertToolsToProviderFormat } from './tool-converter'

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the import order.

Move the ./tool-converter import before the ./index import to satisfy the repository’s import/order ESLint rule.

Proposed fix
+import { convertToolsToProviderFormat } from './tool-converter'
} from './index'
-import { convertToolsToProviderFormat } from './tool-converter'
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
}from'./index'
import{convertToolsToProviderFormat}from'./tool-converter'
import{convertToolsToProviderFormat}from'./tool-converter'
}from'./index'
🧰 Tools
🪛 ESLint

[error] 11-11: ./tool-converter import should occur before import of ./index

(import/order)

🤖 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 `@packages/ai-gemini/src/tools/provider-tool-dispatch.test.ts` around lines 10
- 11, In provider-tool-dispatch.test.ts, reorder the local imports so
convertToolsToProviderFormat from ./tool-converter appears before the import
from ./index, satisfying the repository’s import/order rule.

Source: Linters/SAST tools

@tombeckenham
tombeckenhamforce-pushed the fix/anthropic-web-search-name-collision branch from d66f1ef to b009147CompareAugust 10, 2026 09:13
@tombeckenham

Copy link
Copy Markdown
Contributor

Maintainer sweep: rebased onto main (force-with-lease). CI approval handled if it was waiting.

@coderabbitai

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.

@coderabbitaicoderabbitaiBot 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

🧹 Nitpick comments (1)
packages/ai-anthropic/tests/text.skills.test.ts (1)

149-164: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Place this test beside the source module.

Move this regression test to a source-adjacent *.test.ts file. Keep the Vitest test API.

As per coding guidelines, “Test files should be placed alongside source code as *.test.ts files using Vitest with happy-dom for DOM testing.”

🤖 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 `@packages/ai-anthropic/tests/text.skills.test.ts` around lines 149 - 164, Move
the regression test covering an ordinary function named code_execution from
text.skills.test.ts into a *.test.ts file adjacent to the source module that
implements computeAnthropicBetas or mapCommonOptionsToAnthropic. Preserve the
existing Vitest API and test behavior; only relocate the test and update imports
or setup as needed.

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 `@packages/ai-anthropic/src/tools/text-editor-tool.ts`:
- Around line 33-43: Update textEditorTool in
packages/ai-anthropic/src/tools/text-editor-tool.ts:33-43, the corresponding
tool factory in
packages/ai-gemini/src/tools/google-search-retriveal-tool.ts:27-37, and the
code-interpreter factory in
packages/openai-base/src/tools/code-interpreter-tool.ts:36-49 to construct tools
through toolDefinition() with the required Zod validation pattern instead of
directly branding objects. For any executable implementation, add both server
and client implementations in each affected factory.
---
Nitpick comments:
In `@packages/ai-anthropic/tests/text.skills.test.ts`:
- Around line 149-164: Move the regression test covering an ordinary function
named code_execution from text.skills.test.ts into a *.test.ts file adjacent to
the source module that implements computeAnthropicBetas or
mapCommonOptionsToAnthropic. Preserve the existing Vitest API and test behavior;
only relocate the test and update imports or setup as needed.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 422cce2d-2a83-4711-99d0-e0e49bc4b497

📥 Commits

Reviewing files that changed from the base of the PR and between 888e8b7 and d756a41.

📒 Files selected for processing (45)
  • .changeset/tidy-searches-coexist.md
  • packages/ai-anthropic/src/adapters/text.ts
  • packages/ai-anthropic/src/tools/anthropic-provider-tool.ts
  • packages/ai-anthropic/src/tools/bash-tool.ts
  • packages/ai-anthropic/src/tools/code-execution-tool.ts
  • packages/ai-anthropic/src/tools/computer-use-tool.ts
  • packages/ai-anthropic/src/tools/memory-tool.ts
  • packages/ai-anthropic/src/tools/text-editor-tool.ts
  • packages/ai-anthropic/src/tools/tool-converter.ts
  • packages/ai-anthropic/src/tools/web-fetch-tool.ts
  • packages/ai-anthropic/src/tools/web-search-tool.ts
  • packages/ai-anthropic/tests/provider-tools-smoke.test.ts
  • packages/ai-anthropic/tests/text.skills.test.ts
  • packages/ai-gemini/src/experimental/text-interactions/adapter.ts
  • packages/ai-gemini/src/tools/code-execution-tool.ts
  • packages/ai-gemini/src/tools/computer-use-tool.ts
  • packages/ai-gemini/src/tools/file-search-tool.ts
  • packages/ai-gemini/src/tools/gemini-provider-tool.ts
  • packages/ai-gemini/src/tools/google-maps-tool.ts
  • packages/ai-gemini/src/tools/google-search-retriveal-tool.ts
  • packages/ai-gemini/src/tools/google-search-tool.ts
  • packages/ai-gemini/src/tools/provider-tool-dispatch.test.ts
  • packages/ai-gemini/src/tools/tool-converter.ts
  • packages/ai-gemini/src/tools/url-context-tool.ts
  • packages/ai-gemini/tests/text-interactions-adapter.test.ts
  • packages/ai-openai/src/tools/computer-use-tool.ts
  • packages/openai-base/src/tools/apply-patch-tool.ts
  • packages/openai-base/src/tools/code-interpreter-tool.ts
  • packages/openai-base/src/tools/computer-use-tool.ts
  • packages/openai-base/src/tools/custom-tool.ts
  • packages/openai-base/src/tools/file-search-tool.ts
  • packages/openai-base/src/tools/image-generation-tool.ts
  • packages/openai-base/src/tools/local-shell-tool.ts
  • packages/openai-base/src/tools/mcp-tool.ts
  • packages/openai-base/src/tools/openai-provider-tool.ts
  • packages/openai-base/src/tools/shell-tool.ts
  • packages/openai-base/src/tools/tool-converter.ts
  • packages/openai-base/src/tools/web-search-preview-tool.ts
  • packages/openai-base/src/tools/web-search-tool.ts
  • packages/openai-base/tests/provider-tool-dispatch.test.ts
  • testing/e2e/fixtures/provider-tool-dispatch/basic.json
  • testing/e2e/src/routes/api.anthropic-skills-wire.ts
  • testing/e2e/src/routes/api.provider-tool-dispatch-wire.ts
  • testing/e2e/tests/anthropic-skills-wire.spec.ts
  • testing/e2e/tests/provider-tool-dispatch-wire.spec.ts
🚧 Files skipped from review as they are similar to previous changes (39)
  • testing/e2e/fixtures/provider-tool-dispatch/basic.json
  • packages/ai-anthropic/src/tools/web-search-tool.ts
  • packages/openai-base/tests/provider-tool-dispatch.test.ts
  • packages/ai-gemini/src/tools/computer-use-tool.ts
  • packages/ai-anthropic/src/tools/bash-tool.ts
  • packages/ai-gemini/src/tools/google-search-tool.ts
  • packages/openai-base/src/tools/apply-patch-tool.ts
  • packages/ai-anthropic/src/tools/tool-converter.ts
  • packages/ai-anthropic/src/tools/memory-tool.ts
  • packages/ai-gemini/src/tools/file-search-tool.ts
  • packages/openai-base/src/tools/tool-converter.ts
  • packages/ai-anthropic/src/tools/web-fetch-tool.ts
  • packages/openai-base/src/tools/local-shell-tool.ts
  • packages/openai-base/src/tools/openai-provider-tool.ts
  • packages/ai-gemini/src/tools/provider-tool-dispatch.test.ts
  • packages/openai-base/src/tools/custom-tool.ts
  • packages/ai-gemini/src/tools/tool-converter.ts
  • packages/openai-base/src/tools/mcp-tool.ts
  • packages/ai-anthropic/src/tools/code-execution-tool.ts
  • packages/openai-base/src/tools/image-generation-tool.ts
  • packages/openai-base/src/tools/shell-tool.ts
  • testing/e2e/src/routes/api.provider-tool-dispatch-wire.ts
  • packages/ai-gemini/src/tools/url-context-tool.ts
  • packages/ai-gemini/src/tools/google-maps-tool.ts
  • packages/openai-base/src/tools/computer-use-tool.ts
  • packages/openai-base/src/tools/file-search-tool.ts
  • packages/ai-anthropic/src/adapters/text.ts
  • testing/e2e/tests/anthropic-skills-wire.spec.ts
  • packages/ai-gemini/tests/text-interactions-adapter.test.ts
  • packages/ai-gemini/src/tools/code-execution-tool.ts
  • .changeset/tidy-searches-coexist.md
  • packages/ai-anthropic/src/tools/computer-use-tool.ts
  • packages/ai-gemini/src/tools/gemini-provider-tool.ts
  • packages/openai-base/src/tools/web-search-tool.ts
  • packages/openai-base/src/tools/web-search-preview-tool.ts
  • testing/e2e/tests/provider-tool-dispatch-wire.spec.ts
  • packages/ai-anthropic/tests/provider-tools-smoke.test.ts
  • packages/ai-openai/src/tools/computer-use-tool.ts
  • testing/e2e/src/routes/api.anthropic-skills-wire.ts

Comment threadpackages/ai-anthropic/src/tools/text-editor-tool.ts
The two new provider-tool-dispatch E2E tests were failing. They asserted
provider-native wire shapes, but aimock's /v1/_requests journal does not store
raw provider bodies -- both the Responses and Gemini handlers record the request
already normalized into the Chat-Completions envelope
(responsesToCompletionRequest / geminiToCompletionRequest). Assert that shape
instead, and say so in the spec so nobody corrects it back.
Drop the OpenAI case rather than leave it green-but-empty. The OpenAI half of
the fix lives in openai-base/src/tools/tool-converter.ts, and the only adapter
that runs it is ai-openai's openaiText(), which overrides mapOptionsToRequest to
route through the full converter. Neither OpenAI-family provider in the E2E app
reaches it: `openai` is createOpenaiChat() (Chat Completions, never dispatched
on name) and `openai-compatible` inherits the base mapOptionsToRequest, which
sends every tool through convertToolsToResponsesFormat as a function tool. That
case passed against the pre-fix converter, so it proved nothing. The leg is
covered by packages/openai-base/tests/provider-tool-dispatch.test.ts; true E2E
coverage needs an `openai-responses` provider added to the app.
The Gemini case does exercise changed code and now has verified teeth: against
the pre-fix converter the captured tools array comes back empty, because the
tool was swallowed into {googleSearch:{}} and aimock keeps only entries whose
type === 'function'.
Also:
- Commit the regenerated routeTree.gen.ts; the new route was never registered.
- Interactions adapter JSDoc still claimed mcp_server is rejected at runtime
after the throw was removed. There is no Gemini mcp_server factory, so a tool
merely named that is an ordinary function now.
- Changeset: describe the googleSearchTool({searchTypes}) fix. The Interactions
converter read a snake_case search_types array the public factory could never
produce (GoogleSearch.searchTypes: {webSearch?, imageSearch?}), so the
selection was silently dropped and every request fell back to web-search-only.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
testing/e2e/src/routes/api.provider-tool-dispatch-wire.ts (1)

76-86: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Use toolDefinition() for the custom Gemini tool.

createCustomTool currently returns a raw JSON-Schema Tool. Use toolDefinition() with a Zod tool schema so the route follows the TypeScript guideline for schema validation and tool definitions.

🤖 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 `@testing/e2e/src/routes/api.provider-tool-dispatch-wire.ts` around lines 76 -
86, Update createCustomTool to build the custom Gemini tool through
toolDefinition() using a Zod schema for the required query string, rather than
returning a raw JSON-Schema Tool object. Preserve the existing tool name and
description while allowing the helper to provide schema validation and the
resulting tool definition.

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 `@testing/e2e/tests/provider-tool-dispatch-wire.spec.ts`:
- Line 45: Replace the response.json() type assertions in the route response
handling and aimock journal parsing with Zod schemas and safe
parsing/validation. Define schemas for the route envelope and journal entries,
then parse the decoded JSON before accessing fields so malformed aimock
responses fail at the boundary.
- Around line 29-34: The beforeEach cleanup in the provider-tool dispatch tests
clears a shared singleton aimock journal and creates cross-test races. Update
the test setup and journal assertions around the provider-tool dispatch spec to
isolate entries by the current testId (or otherwise use a scoped journal key),
and stop deleting the shared journal before reading it; do not assume entries[0]
belongs to this test.
---
Outside diff comments:
In `@testing/e2e/src/routes/api.provider-tool-dispatch-wire.ts`:
- Around line 76-86: Update createCustomTool to build the custom Gemini tool
through toolDefinition() using a Zod schema for the required query string,
rather than returning a raw JSON-Schema Tool object. Preserve the existing tool
name and description while allowing the helper to provide schema validation and
the resulting tool definition.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: df252695-cec4-4091-ba4b-e6585c3f154a

📥 Commits

Reviewing files that changed from the base of the PR and between d756a41 and f4c02eb.

📒 Files selected for processing (5)
  • .changeset/tidy-searches-coexist.md
  • packages/ai-gemini/src/experimental/text-interactions/adapter.ts
  • testing/e2e/src/routeTree.gen.ts
  • testing/e2e/src/routes/api.provider-tool-dispatch-wire.ts
  • testing/e2e/tests/provider-tool-dispatch-wire.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ai-gemini/src/experimental/text-interactions/adapter.ts

Comment threadtesting/e2e/tests/provider-tool-dispatch-wire.spec.ts Outdated
`/api/provider-tool-dispatch-wire?provider=gemini&testId=${encodeURIComponent(testId)}`,
)
expect(response.ok()).toBe(true)
const result = (await response.json()) as { ok: boolean; error?: string }

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
rg -n -C 4 'response\.json\(\)|z\.object\(|z\.array\(' \
testing/e2e --glob '*.{ts,tsx}'

Repository: TanStack/ai

Length of output: 42229


🏁 Script executed:

#!/bin/bashset -euo pipefail
sed -n '1,95p' testing/e2e/tests/provider-tool-dispatch-wire.spec.ts

Repository: TanStack/ai

Length of output: 3220


🏁 Script executed:

#!/bin/bashset -euo pipefail
grep -n "createServer\|tool-dispatch-wire\|/v1/_requests\|PORT\|AIMOCK" testing/e2e/src --include='*.ts' --include='*.tsx' -R ||true

Repository: TanStack/ai

Length of output: 2930


🏁 Script executed:

#!/bin/bashset -euo pipefail
sed -n '1,220p' testing/e2e/src/routes/api.provider-tool-dispatch-wire.ts

Repository: TanStack/ai

Length of output: 3369


Validate aimock JSON with Zod.

response.json() uses as casts at both locations in testing/e2e/tests/provider-tool-dispatch-wire.spec.ts (lines 45 and 72-74). Replace these casts with Zod schema parsing for the route envelope and the aimock journal entries so malformed responses fail at the boundary.

🤖 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 `@testing/e2e/tests/provider-tool-dispatch-wire.spec.ts` at line 45, Replace
the response.json() type assertions in the route response handling and aimock
journal parsing with Zod schemas and safe parsing/validation. Define schemas for
the route envelope and journal entries, then parse the decoded JSON before
accessing fields so malformed aimock responses fail at the boundary.

Source: Coding guidelines

Addresses the review point that the dispatch spec raced other workers. aimock is
a singleton shared by every Playwright worker, so `DELETE /v1/_requests` in
beforeEach could wipe a sibling spec's entry between its write and its read, and
`entries[0]` could just as easily be somebody else's request.
createTextAdapter already tags every provider call with an X-Test-Id header and
aimock stores request headers next to the body, so filter the journal by this
test's own id and stop mutating shared state. The teeth are unchanged: pre-fix
the entry still exists but carries no function tool, so the expectation fails --
and a missing entry now fails with an explicit message instead of silently
reading an empty body.
Several sibling wire specs (openrouter-web-tools-wire, lazy-tools-wire,
multimodal-tool-result-wire, arktype-tool-wire) share the old clear-then-read
pattern and have the same latent race; worth a follow-up sweep.
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the PR, @jan-kubica! 🙌 @AlemTuzlak will take a look.

Automated pre-review checks

  • ✅ CI passing
  • ✅ No merge conflicts
  • ✅ Changeset present
  • ✅ E2E test changes included

Automated triage — a human review follows.

@github-actionsgithub-actionsBot added the waiting-on: author Waiting for the author to respond or update label Aug 13, 2026
Map Anthropic webSearchTool snake_case config onto the wire payload.
Throw DuplicateToolNameError when a factory tool and a custom function
share a public name. Strengthen factory tests and document that native
tools come from the factory.
@nx-cloud

nx-cloudBot commented Aug 19, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit c73f09a

CommandStatusDurationResult
nx run-many --targets=build --exclude=examples/...✅ Succeeded1m 19sView ↗

☁️ Nx Cloud last updated this comment at 2026-08-19 16:08:51 UTC

@pkg-pr-new

pkg-pr-newBot commented Aug 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/@tanstack/ai@932

@tanstack/ai-acp

npm i https://pkg.pr.new/@tanstack/ai-acp@932

@tanstack/ai-angular

npm i https://pkg.pr.new/@tanstack/ai-angular@932

@tanstack/ai-anthropic

npm i https://pkg.pr.new/@tanstack/ai-anthropic@932

@tanstack/ai-bedrock

npm i https://pkg.pr.new/@tanstack/ai-bedrock@932

@tanstack/ai-byteplus

npm i https://pkg.pr.new/@tanstack/ai-byteplus@932

@tanstack/ai-claude-code

npm i https://pkg.pr.new/@tanstack/ai-claude-code@932

@tanstack/ai-client

npm i https://pkg.pr.new/@tanstack/ai-client@932

@tanstack/ai-code-mode

npm i https://pkg.pr.new/@tanstack/ai-code-mode@932

@tanstack/ai-code-mode-snippets

npm i https://pkg.pr.new/@tanstack/ai-code-mode-snippets@932

@tanstack/ai-codex

npm i https://pkg.pr.new/@tanstack/ai-codex@932

@tanstack/ai-cohere

npm i https://pkg.pr.new/@tanstack/ai-cohere@932

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/@tanstack/ai-devtools-core@932

@tanstack/ai-durable-stream

npm i https://pkg.pr.new/@tanstack/ai-durable-stream@932

@tanstack/ai-elevenlabs

npm i https://pkg.pr.new/@tanstack/ai-elevenlabs@932

@tanstack/ai-event-client

npm i https://pkg.pr.new/@tanstack/ai-event-client@932

@tanstack/ai-fal

npm i https://pkg.pr.new/@tanstack/ai-fal@932

@tanstack/ai-gemini

npm i https://pkg.pr.new/@tanstack/ai-gemini@932

@tanstack/ai-grok

npm i https://pkg.pr.new/@tanstack/ai-grok@932

@tanstack/ai-grok-build

npm i https://pkg.pr.new/@tanstack/ai-grok-build@932

@tanstack/ai-groq

npm i https://pkg.pr.new/@tanstack/ai-groq@932

@tanstack/ai-isolate-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-isolate-cloudflare@932

@tanstack/ai-isolate-daytona

npm i https://pkg.pr.new/@tanstack/ai-isolate-daytona@932

@tanstack/ai-isolate-node

npm i https://pkg.pr.new/@tanstack/ai-isolate-node@932

@tanstack/ai-isolate-quickjs

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs@932

@tanstack/ai-isolate-quickjs-bun

npm i https://pkg.pr.new/@tanstack/ai-isolate-quickjs-bun@932

@tanstack/ai-mcp

npm i https://pkg.pr.new/@tanstack/ai-mcp@932

@tanstack/ai-memory

npm i https://pkg.pr.new/@tanstack/ai-memory@932

@tanstack/ai-mistral

npm i https://pkg.pr.new/@tanstack/ai-mistral@932

@tanstack/ai-ollama

npm i https://pkg.pr.new/@tanstack/ai-ollama@932

@tanstack/ai-openai

npm i https://pkg.pr.new/@tanstack/ai-openai@932

@tanstack/ai-opencode

npm i https://pkg.pr.new/@tanstack/ai-opencode@932

@tanstack/ai-openrouter

npm i https://pkg.pr.new/@tanstack/ai-openrouter@932

@tanstack/ai-perplexity

npm i https://pkg.pr.new/@tanstack/ai-perplexity@932

@tanstack/ai-persistence

npm i https://pkg.pr.new/@tanstack/ai-persistence@932

@tanstack/ai-preact

npm i https://pkg.pr.new/@tanstack/ai-preact@932

@tanstack/ai-react

npm i https://pkg.pr.new/@tanstack/ai-react@932

@tanstack/ai-react-ui

npm i https://pkg.pr.new/@tanstack/ai-react-ui@932

@tanstack/ai-sandbox

npm i https://pkg.pr.new/@tanstack/ai-sandbox@932

@tanstack/ai-sandbox-cloudflare

npm i https://pkg.pr.new/@tanstack/ai-sandbox-cloudflare@932

@tanstack/ai-sandbox-daytona

npm i https://pkg.pr.new/@tanstack/ai-sandbox-daytona@932

@tanstack/ai-sandbox-docker

npm i https://pkg.pr.new/@tanstack/ai-sandbox-docker@932

@tanstack/ai-sandbox-local-process

npm i https://pkg.pr.new/@tanstack/ai-sandbox-local-process@932

@tanstack/ai-sandbox-sprites

npm i https://pkg.pr.new/@tanstack/ai-sandbox-sprites@932

@tanstack/ai-sandbox-vercel

npm i https://pkg.pr.new/@tanstack/ai-sandbox-vercel@932

@tanstack/ai-solid

npm i https://pkg.pr.new/@tanstack/ai-solid@932

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/@tanstack/ai-solid-ui@932

@tanstack/ai-svelte

npm i https://pkg.pr.new/@tanstack/ai-svelte@932

@tanstack/ai-utils

npm i https://pkg.pr.new/@tanstack/ai-utils@932

@tanstack/ai-vercel-gateway

npm i https://pkg.pr.new/@tanstack/ai-vercel-gateway@932

@tanstack/ai-vue

npm i https://pkg.pr.new/@tanstack/ai-vue@932

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/@tanstack/ai-vue-ui@932

@tanstack/openai-base

npm i https://pkg.pr.new/@tanstack/openai-base@932

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/@tanstack/preact-ai-devtools@932

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/@tanstack/react-ai-devtools@932

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/@tanstack/solid-ai-devtools@932

commit: c73f09a

onConfig runs every iteration. Appending the same tool again made chat() throw DuplicateToolNameError. Add the tool only when it is not already in the list.
Made-with: Cursor
@AlemTuzlak
AlemTuzlak merged commit 3eda66c into TanStack:mainAug 19, 2026
9 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-on: authorWaiting for the author to respond or update

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jan-kubica@tombeckenham@AlemTuzlak