Skip to content

feat: Provider tools on /tools subpath with per-model type gating#466

Open
AlemTuzlak wants to merge 46 commits intomainfrom
worktree-cheeky-mapping-harp
Open

feat: Provider tools on /tools subpath with per-model type gating#466
AlemTuzlak wants to merge 46 commits intomainfrom
worktree-cheeky-mapping-harp

Conversation

@AlemTuzlak
Copy link
Copy Markdown
Contributor

@AlemTuzlak AlemTuzlak commented Apr 17, 2026

Summary

  • Every adapter package (ai-anthropic, ai-openai, ai-gemini, ai-openrouter, ai-grok, ai-groq) now exposes provider-specific tool factories (web search, code execution, computer use, etc.) on a dedicated tree-shakeable /tools subpath.
  • New ProviderTool<TProvider, TKind> phantom-branded type in @tanstack/ai gates tool usage at the type level — passing a provider tool to a model that doesn't support it produces a compile-time error on the tools: [...] array. User-defined toolDefinition() tools stay unbranded and always assignable.
  • One breaking export change in @tanstack/ai-openrouter: createWebSearchTool removed from package root, renamed to webSearchTool, moved to /tools subpath. Documented in Migration Guide §6.

What's new

Core (@tanstack/ai, minor):

  • ProviderTool<TProvider, TKind> phantom-branded subtype of Tool
  • toolCapabilities channel on TextAdapter['~types']
  • TextActivityOptions['tools'] gated with a discriminated union (Tool & { '~toolKind'?: never }) | ProviderTool<string, TAdapter['~types']['toolCapabilities'][number]>

Adapters (minor for openai/anthropic/gemini/openrouter, patch for grok/groq):

  • New /tools subpath on every adapter package.json
  • Branded factory return types (AnthropicWebSearchTool, OpenAICodeInterpreterTool, GeminiGoogleSearchTool, etc.)
  • <Provider>ChatModelToolCapabilitiesByName type maps exported from each adapter root
  • Gemini: supports.capabilities split into capabilities + new tools field
  • OpenAI: supports.tools union expanded with web_search_preview, local_shell, shell, apply_patch
  • Anthropic: new supports.tools array added per model (haiku-3 web_search only, haiku-3-5 web tools only, all others full superset)
  • OpenRouter: mapped-type capabilities ({ [K in OpenRouterChatModel]: readonly ['web_search'] }) — no per-model population needed
  • customTool factories in anthropic/openai return plain Tool (universal, not branded — every model accepts them)

Sync script (scripts/sync-provider-models.ts):

  • referenceSupportsBody templates updated for anthropic/openai/gemini/grok so newly-synced models land with correct tools fields out of the box

Tests:

  • Core type tests (5) + per-adapter type tests (3-5 each) using expectTypeOf + @ts-expect-error pattern
  • Runtime smoke tests for anthropic factory shapes + converter
  • Narrow tsconfig include for new test files to avoid surfacing unrelated pre-existing errors

Docs:

  • New concept page docs/tools/provider-tools.md with provider × tools matrix
  • Provider Tools H2 section on every adapter page (docs/adapters/*.md)
  • Migration Guide §6 for OpenRouter rename
  • Callout from docs/tools/tools.md → provider-tools page
  • Nav entry in docs/config.json

Test plan

  • pnpm test:types passes across all 30 projects
  • pnpm build produces dist/esm/tools/index.{js,d.ts} for every adapter with a /tools subpath
  • pnpm test:lib passes (full test suite)
  • pnpm test:eslint passes (0 errors)
  • pnpm test:build (publint) passes
  • pnpm test:sherif passes (workspace consistency)
  • pnpm test:knip passes (no unused deps introduced)
  • Verify @ts-expect-error directives actually fire: remove one per adapter, confirm TypeScript reports a real TS2322 on the line
  • Before next scheduled sync job runs, confirm the updated referenceSupportsBody templates produce correctly-shaped new model entries

Known follow-ups (out of scope)

  • Capability map drift: hand-maintained <Provider>ChatModelToolCapabilitiesByName maps in anthropic/openai/gemini/grok/groq need manual updates when the sync script adds new models. Migrating them to mapped types (like OpenRouter already does) would eliminate the drift surface. Small follow-up PR.
  • Anthropic textEditorTool name hardcode: name: 'str_replace_editor' is the 2025-01-24 variant; newer SDK variants (20250429/20250728) use 'str_replace_based_edit_tool'. Tool-result dispatcher matches by name — users on newer variants silently lose tool results. One-line fix (name: config.name) deferred to a focused PR.
  • OpenRouter wire format check: factory emits { type: 'web_search', web_search: {...} } (legacy plugin shape) but the SDK types ChatRequest.tools as a flat ChatWebSearchShorthand. Shape predates this PR; worth a one-shot gateway test to confirm acceptance.
  • Full Playwright E2E: a proper testing/e2e/ feature scenario for anthropic webSearchTool is deferred. Runtime smoke tests in ai-anthropic/tests/provider-tools-smoke.test.ts cover the critical factory → converter → SDK shape path.

Summary by CodeRabbit

  • New Features

    • Provider-native tools exposed under each adapter’s /tools subpath (web search, code execution, file search, maps, shell, image/code tools, memory, custom, etc.) with compile-time gating so models only accept supported tools.
  • Breaking Changes

    • OpenRouter: import webSearchTool from @tanstack/ai-openrouter/tools (createWebSearchTool removed from package root).
  • Documentation

    • Added Provider Tools guide, per-adapter docs, migration notes, and model/tool compatibility matrix.
  • Tests

    • Added compile-time type-safety tests and runtime smoke tests validating per-model tool compatibility.

Separates tool-type entries (code_execution, file_search, search_grounding,
grounding_with_gmaps, url_context, image_generation) from general capability
flags in ModelMeta.supports. Adds a new tools field to the supports shape,
renames grounding_with_gmaps → google_maps and search_grounding → google_search,
drops image_generation (no tool factory yet), and introduces
GeminiChatModelToolCapabilitiesByName. Threads a fifth TToolCapabilities
generic through GeminiTextAdapter and exports the new type map from the root.
…hTool on /tools subpath

Renames createWebSearchTool → webSearchTool, brands its return type as
OpenRouterWebSearchTool (ProviderTool<'openrouter', 'web_search'>), moves
web_search exports to the new ./tools subpath, adds
OpenRouterChatModelToolCapabilitiesByName mapped type (all chat models
support web_search via the gateway), threads TToolCapabilities through the
text adapter, and adds per-model type tests.
…d toolCapabilities

- Add tools?: ReadonlyArray<never> to ModelMeta.supports interface in both packages
- Add tools: [] as const to every chat model constant
- Export GrokChatModelToolCapabilitiesByName / GroqChatModelToolCapabilitiesByName type maps
- Add 5th TToolCapabilities generic to GrokTextAdapter / GroqTextAdapter via ResolveToolCapabilities
- Add ./tools subpath to package.json exports and vite.config.ts entry for both packages
- Re-export new ToolCapabilitiesByName types from root index.ts in both packages
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 17, 2026

📝 Walkthrough

Walkthrough

This PR adds provider-native tool exports under new /tools subpaths, introduces a branded ProviderTool<TProvider, TKind> type and per-model supports.tools metadata, threads tool-capability types through adapters, renames tool config types to *ToolConfig with deprecated aliases, and updates docs, tests, and build exports.

Changes

Cohort / File(s) Summary
Changesets
.changeset/provider-tools-*.md
Added changeset entries for multiple packages documenting new /tools subpaths, branded provider-tool returns, tool-capability gating, and OpenRouter migration note (root export removal).
Core types & adapter API
packages/typescript/ai/src/tools/provider-tool.ts, packages/typescript/ai/src/activities/chat/adapter.ts, packages/typescript/ai/src/activities/chat/index.ts, packages/typescript/ai/src/index.ts
Introduced ProviderTool<TProvider,TKind> (phantom brands); extended TextAdapter/BaseTextAdapter with TToolCapabilities; added toolCapabilities into adapter ~types; constrained TextActivityOptions['tools'] to accept user Tools or provider-branded tools matching adapter capabilities.
Provider tools — anthropic/gemini/openai/groq/grok/openrouter
packages/typescript/ai-anthropic/src/tools/*, packages/typescript/ai-gemini/src/tools/*, packages/typescript/ai-openai/src/tools/*, packages/typescript/ai-openrouter/src/tools/*, packages/typescript/ai-groq/..., packages/typescript/ai-grok/...
Renamed canonical tool config types to *ToolConfig and added deprecated *Tool aliases; factory functions now return branded ProviderXxxTool types via type-only casts; added per-provider src/tools/index.ts barrels where applicable.
Adapter integration & model metadata
packages/typescript/ai-*/src/adapters/text.ts, packages/typescript/ai-*/src/model-meta.ts, packages/typescript/ai-*/src/index.ts
Threaded TToolCapabilities into adapter generics and public factory return types; exported *ChatModelToolCapabilitiesByName types; added supports.tools arrays to model metadata (non-empty for Anthropic/Gemini/OpenAI/OpenRouter, empty arrays for Grok/Groq).
Package exports & build
packages/typescript/ai-*/package.json, packages/typescript/ai-*/vite.config.ts
Added ./tools export subpath to multiple package.json files; added ./src/tools/index.ts as a Vite entry for affected packages.
OpenRouter breaking change
packages/typescript/ai-openrouter/src/index.ts, packages/typescript/ai-openrouter/src/tools/*, docs/migration/migration.md
Removed createWebSearchTool from package root; new import is webSearchTool from @tanstack/ai-openrouter/tools; introduced web-search branding, detection, conversion, and adjusted tool-converter dispatch.
Docs & navigation
docs/adapters/*, docs/tools/provider-tools.md, docs/tools/tools.md, docs/migration/migration.md, docs/config.json
Added "Provider Tools" docs per adapter, new provider-tools guide, migration notes (OpenRouter), per-adapter usage/config examples, and nav entry linking to provider-tools.
Tests & type-safety checks
packages/typescript/ai*/tests/*, packages/typescript/ai/tests/*, packages/typescript/ai/tests/test-utils.ts
Added runtime smoke tests and compile-time TypeScript tests validating per-model tool gating; updated mock adapter test helpers to include toolCapabilities.
Scripts
scripts/sync-provider-models.ts
Updated templates to include supports.tools in generated provider model metadata and expanded per-provider tool lists.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant ToolFactory as Provider Tool Factory
    participant Adapter as TextAdapter
    participant TS as TypeScript Compiler
    Dev->>ToolFactory: import webSearchTool from `@pkg/tools`\ncall webSearchTool(config)
    ToolFactory->>Dev: returns AnthropicWebSearchTool (ProviderTool<'anthropic','web_search'>)
    Dev->>Adapter: adapter.chat({ tools: [webSearchTool(...)] })
    Adapter->>TS: validate tools[] elements vs\nAdapter['~types']['toolCapabilities']
    alt tool kind ∈ supported capabilities
        TS->>Adapter: Accept (compiles)
        Adapter->>Runtime: Chat runs with tool passed through
    else not supported
        TS->>Dev: Compile-time error (type mismatch)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

🐰 I hopped through types and docs so bright,
New tools tucked in each provider's light.
Branded kinds keep order true,
Models say which tools they'll woo—
A carrot for typechecks, hops of delight!

✨ 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 worktree-cheeky-mapping-harp

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 17, 2026

🚀 Changeset Version Preview

7 package(s) bumped directly, 26 bumped as dependents.

🟥 Major bumps

Package Version Reason
@tanstack/ai-anthropic 0.7.4 → 1.0.0 Changeset
@tanstack/ai-gemini 0.8.8 → 1.0.0 Changeset
@tanstack/ai-grok 0.6.5 → 1.0.0 Changeset
@tanstack/ai-groq 0.1.4 → 1.0.0 Changeset
@tanstack/ai-openai 0.7.5 → 1.0.0 Changeset
@tanstack/ai-openrouter 0.7.7 → 1.0.0 Changeset
@tanstack/ai-code-mode 0.1.3 → 1.0.0 Dependent
@tanstack/ai-code-mode-skills 0.1.3 → 1.0.0 Dependent
@tanstack/ai-elevenlabs 0.1.4 → 1.0.0 Dependent
@tanstack/ai-event-client 0.2.3 → 1.0.0 Dependent
@tanstack/ai-fal 0.6.13 → 1.0.0 Dependent
@tanstack/ai-isolate-node 0.1.3 → 1.0.0 Dependent
@tanstack/ai-isolate-quickjs 0.1.3 → 1.0.0 Dependent
@tanstack/ai-ollama 0.6.6 → 1.0.0 Dependent
@tanstack/ai-preact 0.6.15 → 1.0.0 Dependent
@tanstack/ai-react 0.7.11 → 1.0.0 Dependent
@tanstack/ai-react-ui 0.6.1 → 1.0.0 Dependent
@tanstack/ai-solid 0.6.15 → 1.0.0 Dependent
@tanstack/ai-solid-ui 0.6.1 → 1.0.0 Dependent
@tanstack/ai-svelte 0.6.15 → 1.0.0 Dependent
@tanstack/ai-vue 0.6.15 → 1.0.0 Dependent

🟨 Minor bumps

Package Version Reason
@tanstack/ai 0.10.3 → 0.11.0 Changeset

🟩 Patch bumps

Package Version Reason
@tanstack/ai-client 0.7.10 → 0.7.11 Dependent
@tanstack/ai-code-mode-models-eval 0.0.6 → 0.0.7 Dependent
@tanstack/ai-devtools-core 0.3.20 → 0.3.21 Dependent
@tanstack/ai-isolate-cloudflare 0.1.3 → 0.1.4 Dependent
@tanstack/ai-vue-ui 0.1.26 → 0.1.27 Dependent
@tanstack/preact-ai-devtools 0.1.24 → 0.1.25 Dependent
@tanstack/react-ai-devtools 0.2.24 → 0.2.25 Dependent
@tanstack/solid-ai-devtools 0.2.24 → 0.2.25 Dependent
ts-svelte-chat 0.1.32 → 0.1.33 Dependent
ts-vue-chat 0.1.32 → 0.1.33 Dependent
vanilla-chat 0.0.30 → 0.0.31 Dependent

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Apr 17, 2026

View your CI Pipeline Execution ↗ for commit 416d8b0

Command Status Duration Result
nx run-many --targets=build --exclude=examples/** ✅ Succeeded 1m 1s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-20 10:41:05 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 17, 2026

Open in StackBlitz

@tanstack/ai

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

@tanstack/ai-anthropic

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

@tanstack/ai-client

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

@tanstack/ai-code-mode

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

@tanstack/ai-code-mode-skills

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

@tanstack/ai-devtools-core

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

@tanstack/ai-elevenlabs

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

@tanstack/ai-event-client

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

@tanstack/ai-fal

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

@tanstack/ai-gemini

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

@tanstack/ai-grok

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

@tanstack/ai-groq

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

@tanstack/ai-isolate-cloudflare

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

@tanstack/ai-isolate-node

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

@tanstack/ai-isolate-quickjs

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

@tanstack/ai-ollama

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

@tanstack/ai-openai

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

@tanstack/ai-openrouter

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

@tanstack/ai-preact

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

@tanstack/ai-react

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

@tanstack/ai-react-ui

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

@tanstack/ai-solid

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

@tanstack/ai-solid-ui

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

@tanstack/ai-svelte

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

@tanstack/ai-vue

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

@tanstack/ai-vue-ui

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

@tanstack/preact-ai-devtools

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

@tanstack/react-ai-devtools

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

@tanstack/solid-ai-devtools

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

commit: 416d8b0

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 13

Caution

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

⚠️ Outside diff range comments (4)
packages/typescript/ai/tests/type-check.test.ts (1)

11-22: ⚠️ Potential issue | 🟡 Minor

Pass explicit toolCapabilities type parameter to MockAdapter.

The TextAdapter interface has 5 type parameters, but the MockAdapter instantiation (lines 11–22) provides only 4 arguments. The TToolCapabilities parameter relies on its default value (ReadonlyArray<string>) rather than explicitly matching the toolCapabilities: [] as ReadonlyArray<string> type from the mock literal at line 38. Pass the 5th type argument to make the type instantiation explicit and align with the mock object definition:

type MockAdapter = TextAdapter<
  'test-model',
  { validOption: string; anotherOption?: number },
  readonly ['text', 'image'],
  {
    text: unknown
    image: unknown
    audio: unknown
    video: unknown
    document: unknown
  },
  readonly string[]
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai/tests/type-check.test.ts` around lines 11 - 22, The
MockAdapter type instantiation omits the TToolCapabilities type parameter,
causing it to fall back to the default instead of matching the mock's
toolCapabilities literal; update the MockAdapter alias (the TextAdapter
instantiation) to include the fifth type argument (e.g., readonly string[]) so
the generic list of tool capabilities is explicit and aligns with the mock
object’s toolCapabilities value.
docs/migration/migration.md (1)

13-19: ⚠️ Potential issue | 🟡 Minor

Overview list is out of date — "Provider Tools" isn’t mentioned.

Section 6 was added below but the numbered list at the top still stops at item 5 (Embeddings Removed). Users skimming the overview will miss the OpenRouter breaking rename.

Proposed fix
 1. **Adapter functions split** - Adapters are now split into activity-specific functions for optimal tree-shaking
 2. **Common options flattened** - Options are now flattened in the config instead of nested
 3. **`providerOptions` renamed** - Now called `modelOptions` for clarity
 4. **`toResponseStream` renamed** - Now called `toServerSentEventsStream` for clarity
 5. **Embeddings removed** - Embeddings support has been removed (most vector DB services have built-in support)
+6. **Provider tools moved to `/tools` subpath** - Provider-specific tool factories are now imported from each adapter's `/tools` subpath; `@tanstack/ai-openrouter`'s `createWebSearchTool` is renamed to `webSearchTool`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/migration/migration.md` around lines 13 - 19, The top overview numbered
list is missing the new Section 6 about Provider Tools/OpenRouter; update the
list to include a sixth bullet describing "Provider Tools added — OpenRouter
rename and related breaking changes" (or similar), and ensure the summary
mentions the existing renames: `providerOptions` → `modelOptions` and
`toResponseStream` → `toServerSentEventsStream` and removal of Embeddings so
readers see the OpenRouter/provider-tools note at a glance; edit the list
entries (the overview block containing "Adapter functions split", "Common
options flattened", etc.) to add the sixth item and make sure it references the
new Provider Tools/OpenRouter change so the overview and Section 6 are
consistent.
scripts/sync-provider-models.ts (1)

102-124: ⚠️ Potential issue | 🟠 Major

Template-level tool capability drift for Anthropic/Gemini newly synced models.

Both the Anthropic (line 104) and Gemini (line 124) reference templates hardcode the full tool superset for every newly synced model. The real matrix already has restricted Anthropic families (claude-3-haiku['web_search'], claude-3-5-haiku['web_search', 'web_fetch']) and narrower Gemini variants (Lite, image/video), per docs/tools/provider-tools.md and model-meta.ts. Any future haiku-class or Lite-class model picked up by this script will be minted with an over-broad supports.tools, which feeds AnthropicChatModelToolCapabilitiesByName / Gemini's capability map and silently permits unsupported tools at compile time — defeating the type gate this PR is introducing.

This matches the "capability map drift" follow-up called out in the PR description, but it's worth leaving a defensive marker so the next sync run doesn't quietly regress type safety. A minimum mitigation is to emit tools: [] (or a conservative ['web_search']) in the template and require manual review, rather than the full superset.

🛡️ Suggested conservative defaults
     referenceSupportsBody: `    extended_thinking: true,
     priority_tier: true,
-    tools: ['web_search', 'web_fetch', 'code_execution', 'computer_use', 'bash', 'text_editor', 'memory'],`,
+    // NOTE: conservative default — widen manually after verifying model capabilities.
+    tools: [],`,
     referenceSupportsBody: `    output: ['text'],
     capabilities: ['batch_api', 'caching', 'function_calling', 'structured_output', 'thinking'],
-    tools: ['code_execution', 'file_search', 'google_search', 'url_context'],`,
+    // NOTE: conservative default — widen manually after verifying model capabilities.
+    tools: [],`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/sync-provider-models.ts` around lines 102 - 124, The templates for
new model entries (the referenceSupportsBody string used in the 'anthropic/' and
'google/' blocks) currently hardcode the full tools superset, which will
incorrectly grant unsupported tools to newly synced models; change those
template snippets to emit a conservative default tools list (e.g., tools: [] or
tools: ['web_search']) instead of the full superset, add a short comment in the
template reminding reviewers to manually map per-model tool capabilities, and
ensure any existing per-model capability overrides (the canonical capability
map) remain authoritative so the sync doesn't auto-promote unsupported tools.
packages/typescript/ai-gemini/src/model-meta.ts (1)

289-313: ⚠️ Potential issue | 🟠 Major

Remove file_search from the TTS model tool declarations.

GEMINI_2_5_PRO_TTS and GEMINI_2_5_FLASH_TTS incorrectly declare tools: ['file_search']. Official Gemini documentation explicitly states that TTS models do not support the file_search tool or any general tool use capabilities—they are specialized for audio generation from text inputs only. This appears to be a stale entry carried over from an earlier configuration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-gemini/src/model-meta.ts` around lines 289 - 313,
Remove the unsupported file_search tool from the TTS model metadata objects:
update GEMINI_2_5_PRO_TTS and GEMINI_2_5_FLASH_TTS by deleting 'file_search'
from their supports.tools arrays so their supports only reflect text->audio
capability; ensure the objects still satisfy the ModelMeta type
(GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions &
GeminiCachedContentOptions) after the removal and run type checks to confirm no
other tool entries remain for TTS models.
🧹 Nitpick comments (20)
packages/typescript/ai-openrouter/src/tools/web-search-tool.ts (1)

40-51: Empty description may be rejected by stricter consumers/tool registries.

description: '' is returned unconditionally. Some tool-pipeline paths / validators treat the description as required and non-empty (and LLM-facing tool schemas generally benefit from a meaningful description). Since this is a provider-native tool executed by OpenRouter (not the model), an empty string is likely fine on the wire, but consider a short static description (e.g., 'Search the web via OpenRouter.') for clarity and to avoid future validation surprises.

Proposed tweak
-    name: 'web_search',
-    description: '',
+    name: 'web_search',
+    description: 'Search the web via OpenRouter.',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-openrouter/src/tools/web-search-tool.ts` around lines
40 - 51, The returned tool object for web_search uses an empty description which
can break stricter validators; update the factory that returns the object (the
one creating name: 'web_search' and casting to OpenRouterWebSearchTool) to
provide a concise static description like "Search the web via OpenRouter."
instead of '', ensuring the description field on the returned object is
non-empty and stays compatible with the existing metadata and the
OpenRouterWebSearchTool cast.
packages/typescript/ai-openai/src/tools/computer-use-tool.ts (1)

29-39: Metadata shape mismatch between factory and converter.

computerUseTool stores metadata = { ...toolData }, which includes toolData.type ('computer_use_preview' per OpenAI.Responses.ComputerTool). convertComputerUseToolToAdapterFormat then casts tool.metadata as ComputerUseToolConfig and reads display_height/display_width/environment — this works, but it means the stored metadata is ComputerUseToolConfig itself (type-tagged), not a plain options object. That’s inconsistent with e.g. webSearchTool in ai-openrouter which stores a nested config. Not a bug, but worth making the pattern consistent across providers for future refactors.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-openai/src/tools/computer-use-tool.ts` around lines 29
- 39, The factory computerUseTool currently spreads toolData directly into
metadata causing metadata to be the full ComputerUseToolConfig (including its
type tag); change metadata to wrap the options in a nested key (e.g., metadata:
{ config: toolData } or metadata: { computerUseConfig: toolData }) so metadata
is a plain container like other providers, and update
convertComputerUseToolToAdapterFormat to read the nested config key instead of
casting metadata directly; reference computerUseTool,
convertComputerUseToolToAdapterFormat, ComputerUseToolConfig and
OpenAIComputerUseTool when making the change.
packages/typescript/ai-anthropic/tsconfig.json (1)

6-10: Consider broadening include to the whole tests/ directory rather than a single file.

Hard-coding tests/tools-per-model-type-safety.test.ts means any future test file under tests/ won't be type-checked by tsc and must be added here manually. Prefer "tests" (or "tests/**/*.ts") so new type-level tests are picked up automatically, and rely on exclude/Vitest's own include patterns for runtime filtering.

Proposed change
   "include": [
     "vite.config.ts",
     "./src",
-    "tests/tools-per-model-type-safety.test.ts"
+    "tests"
   ],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-anthropic/tsconfig.json` around lines 6 - 10, The
tsconfig currently only includes the single file
"tests/tools-per-model-type-safety.test.ts", which will miss any new tests;
update the "include" array in tsconfig.json (the entry used to list
"vite.config.ts", "./src", and the single test file) to cover the whole tests
directory (e.g., "tests" or "tests/**/*.ts") so all new type-level tests are
picked up automatically while runtime filtering remains handled by Vitest.
packages/typescript/ai-gemini/tsconfig.json (1)

6-10: Same note as the Anthropic tsconfig: prefer including the tests/ directory.

Listing a single test file by name is fragile and will silently skip type-checking of any future tests added under tests/.

Proposed change
   "include": [
     "vite.config.ts",
     "./src",
-    "tests/tools-per-model-type-safety.test.ts"
+    "tests"
   ],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-gemini/tsconfig.json` around lines 6 - 10, The
tsconfig.json "include" array currently references a single test file
("tests/tools-per-model-type-safety.test.ts"), which is fragile; update the
"include" array (the include property in tsconfig.json) to include the entire
tests directory (e.g., "tests" or "./tests") instead of the single filename so
that all current and future tests under tests/ are type-checked; keep the
existing entries ("vite.config.ts" and "./src") and replace or add the tests
directory entry accordingly.
docs/adapters/grok.md (1)

234-241: Minor: verify internal doc link style.

Other docs in this repo typically reference pages by slug (no .md suffix), e.g., the existing [Tools Guide](../tools/tools) on line 231 of this same file. The new links use ../tools/tools.md and ../tools/provider-tools.md, which is inconsistent and may break under the docs site router. Please confirm with pnpm test:docs.

✏️ Suggested alignment
-See [Tools](../tools/tools.md) for the general tool-definition flow, or
-[Provider Tools](../tools/provider-tools.md) for other providers'
-native-tool offerings.
+See [Tools](../tools/tools) for the general tool-definition flow, or
+[Provider Tools](../tools/provider-tools) for other providers'
+native-tool offerings.

As per coding guidelines: "Verify documentation links are valid via pnpm test:docs command".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/adapters/grok.md` around lines 234 - 241, Update the two internal links
in the "Provider Tools" section to use slug-style references (remove the .md
suffix) so they match the repo convention: change "../tools/tools.md" to
"../tools/tools" and "../tools/provider-tools.md" to "../tools/provider-tools";
then run the docs validation command (pnpm test:docs) and fix any remaining link
warnings/errors reported for the "[Tools]" and "[Provider Tools]" references.
packages/typescript/ai-openai/tsconfig.json (1)

6-10: Consider broadening the include to cover all test files.

Pinning a single test path means future type-safety tests added under tests/ won't be picked up by tsc (test:types). Consider a glob like tests/**/*.test.ts so compile-time assertions added later are automatically enforced.

♻️ Proposed change
   "include": [
     "vite.config.ts",
     "./src",
-    "tests/tools-per-model-type-safety.test.ts"
+    "tests/**/*.test.ts"
   ],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-openai/tsconfig.json` around lines 6 - 10, The
tsconfig's "include" currently pins only a single test file
("tests/tools-per-model-type-safety.test.ts"), which will miss future tests;
update the "include" array entry for tests to a glob such as
"tests/**/*.test.ts" (or "tests/**/*") so all test files under tests/ are picked
up by tsc for the test:types run—locate the "include" array in tsconfig.json and
replace or add the broader glob entry.
packages/typescript/ai-anthropic/tests/provider-tools-smoke.test.ts (1)

88-117: Consider asserting on type too when converting multiple tools.

The multi-tool conversion only checks names, so a regression where convertFunctionToolToAdapterFormat is mistakenly picked for a branded provider tool (e.g., due to a name-based dispatch bug) would still pass. Adding expect(converted).toContainEqual(expect.objectContaining({ type: 'web_search_20250305' })) (and equivalents) would close that gap and is especially relevant given name-based dispatch patterns exist elsewhere in this PR.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-anthropic/tests/provider-tools-smoke.test.ts` around
lines 88 - 117, The test "converts multiple provider tools in one call" only
asserts names, so add assertions that the returned converted array contains
objects with the expected types to guard against name-based dispatch
regressions; after calling convertToolsToProviderFormat (variable converted)
include assertions like
expect(converted).toContainEqual(expect.objectContaining({ type:
'web_search_20250305' })) and equivalents for 'code_execution_20250825' and
'bash_20250124' to ensure convertToolsToProviderFormat actually produced
provider-shaped tool objects rather than e.g. convertFunctionToolToAdapterFormat
outputs.
packages/typescript/ai-groq/src/model-meta.ts (1)

367-386: Consider deriving the capabilities map from GROQ_CHAT_MODELS.

Since Groq exposes no provider tools, every entry resolves to readonly []. A mapped type would avoid the risk of adding a new model to GROQ_CHAT_MODELS and forgetting to extend this map (which would silently fall back to never in consumers). For example:

export type GroqChatModelToolCapabilitiesByName = {
  [K in GroqChatModels]: readonly []
}

Keeping the explicit listing is fine for consistency with other providers that do have per-model tool support; flagging as optional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/model-meta.ts` around lines 367 - 386, The
explicit per-model mapping in GroqChatModelToolCapabilitiesByName is brittle
(you must update it whenever GROQ_CHAT_MODELS changes); replace it with a
derived mapped type from the Groq model union/collection (e.g., use
GroqChatModels or GROQ_CHAT_MODELS as the key type) that maps each model name to
readonly [] so all current and future Groq models automatically get the correct
tool-capabilities type; update the GroqChatModelToolCapabilitiesByName
definition to use that mapped type instead of enumerating LLAMA_3_1_8B_INSTANT,
LLAMA_3_3_70B_VERSATILE, etc.
.changeset/provider-tools-ai-anthropic.md (1)

5-5: Nit: clarify "signatures unchanged" vs. branded return types.

Return types now widen to branded subtypes (e.g. AnthropicWebSearchTool extends Tool). Consumers who annotated variables as Tool or previously-exported config types should still assign, but anyone who captured the prior return type by name may see differences. Consider noting "runtime behavior is unchanged; factory return types are now branded subtypes of Tool" for precision.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/provider-tools-ai-anthropic.md at line 5, Update the changelog
sentence to explicitly state that runtime behavior and factory signatures remain
unchanged but the declared return types are now branded subtypes of Tool (for
example: AnthropicWebSearchTool extends Tool) and that consumers who typed
variables as Tool or used the `@deprecated` config aliases are unaffected while
callers that depended on the old named return types may observe a different
compile-time type; reference the factories (webSearchTool, codeExecutionTool,
computerUseTool, bashTool, textEditorTool, webFetchTool, memoryTool, customTool)
and the branded examples (AnthropicWebSearchTool) in the wording for clarity.
packages/typescript/ai-grok/src/model-meta.ts (1)

321-333: Consider a mapped type for GrokChatModelToolCapabilitiesByName.

Listing every model by hand works, but drifts easily when models are added/removed. A mapped type keyed on the already-maintained const tuple keeps it in sync automatically (mirroring the pattern in GrokChatModelProviderOptionsByName):

♻️ Proposed refactor
-export type GrokChatModelToolCapabilitiesByName = {
-  [GROK_4_1_FAST_REASONING.name]: typeof GROK_4_1_FAST_REASONING.supports.tools
-  [GROK_4_1_FAST_NON_REASONING.name]: typeof GROK_4_1_FAST_NON_REASONING.supports.tools
-  ...
-}
+export type GrokChatModelToolCapabilitiesByName = {
+  [K in (typeof GROK_CHAT_MODELS)[number]]: readonly []
+}

Since every Grok chat model currently has tools: [] as const, collapsing to readonly [] is equivalent. If per-model divergence is anticipated, keep the per-model form but at minimum add a const-tuple exhaustiveness check.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-grok/src/model-meta.ts` around lines 321 - 333, The
explicit GrokChatModelToolCapabilitiesByName object should be rewritten as a
mapped type keyed from the shared models tuple to avoid drift: replace the
manual keys in GrokChatModelToolCapabilitiesByName with a mapped type like
Record<(typeof GROK_CHAT_MODELS)[number]['name'], (typeof
GROK_CHAT_MODELS)[number]['supports']['tools']>; mirror the pattern used by
GrokChatModelProviderOptionsByName, and ensure the shared tuple (e.g.
GROK_CHAT_MODELS) is declared as const so the mapping is exhaustive and stays in
sync when models are added/removed.
packages/typescript/ai-openrouter/tests/tools-per-model-type-safety.test.ts (1)

25-27: Env is set after module-load; verify no adapter is constructed at import time.

beforeAll runs after top-level module evaluation. Adapter construction here happens inside each it, so this is fine — but userTool and any future top-level adapter factory would execute before this hook. If openRouterText(...) is ever moved out of an it body, this will throw. Consider setting the env synchronously at the top of the file instead of in beforeAll to make the guarantee explicit and future-proof.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-openrouter/tests/tools-per-model-type-safety.test.ts`
around lines 25 - 27, Set the OPENROUTER_API_KEY synchronously at
module-evaluation time instead of in beforeAll so adapters aren't accidentally
constructed before the env exists: move the assignment
process.env['OPENROUTER_API_KEY'] = 'sk-or-test-dummy' to the top-level of the
test file (above any imports or top-level declarations) and ensure no call to
openRouterText or any adapter factory like userTool runs at import time; this
guarantees adapters created during import will see the env and prevents future
breakage if openRouterText is moved out of an it block.
packages/typescript/ai-gemini/tests/tools-per-model-type-safety.test.ts (1)

44-44: Test title understates coverage.

The it title lists only the positive tools, but the body also asserts rejection of computerUseTool, googleMapsTool, and googleSearchRetrievalTool. Consider renaming to reflect both halves, e.g. "gemini-3.1-pro-preview: accepts {code_execution, file_search, google_search, url_context}; rejects {computer_use, google_maps, google_search_retrieval}", or split into two it blocks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-gemini/tests/tools-per-model-type-safety.test.ts` at
line 44, Update the test title for the `it` block whose current description is
"gemini-3.1-pro-preview accepts code_execution, file_search, google_search,
url_context" to accurately reflect that the test both accepts and rejects tools
(e.g., "gemini-3.1-pro-preview: accepts {code_execution, file_search,
google_search, url_context}; rejects {computer_use, google_maps,
google_search_retrieval}") or split the body into two `it` blocks (one asserting
accepted tools and one asserting rejected tools) so the test name matches its
assertions; ensure you update any assertion messages/labels within that `it`
block to remain consistent with the new titles.
packages/typescript/ai/tests/tools-per-model-type-safety.test.ts (1)

53-59: Replace toMatchTypeOf with toExtend for type expectations.

Vitest's expectTypeOf().toMatchTypeOf() is deprecated in favor of .toExtend(). Update lines 54 and 58 to use .toExtend() instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai/tests/tools-per-model-type-safety.test.ts` around
lines 53 - 59, Replace deprecated expectTypeOf(...).toMatchTypeOf() calls with
expectTypeOf(...).toExtend() for the two assertions: change the assertion on
userTool to use expectTypeOf(userTool).toExtend<MockToolsOption>() and change
the assertion on supportedProviderTool to use
expectTypeOf(supportedProviderTool).toExtend<MockToolsOption>(); update the two
occurrences referencing userTool, supportedProviderTool, and MockToolsOption
accordingly.
packages/typescript/ai-anthropic/src/adapters/text.ts (1)

794-821: Pass ResolveToolCapabilities<TModel> explicitly for symmetry.

Both factory return types enumerate ResolveProviderOptions<TModel> and ResolveInputModalities<TModel> but omit the 4th argument. It currently resolves correctly via the class-level default, but explicit symmetry makes the intent obvious and is resilient if the default is ever reordered/removed.

♻️ Optional consistency fix
 ): AnthropicTextAdapter<
   TModel,
   ResolveProviderOptions<TModel>,
-  ResolveInputModalities<TModel>
+  ResolveInputModalities<TModel>,
+  ResolveToolCapabilities<TModel>
 > {

(Apply to both createAnthropicChat and anthropicText.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-anthropic/src/adapters/text.ts` around lines 794 -
821, The return types of createAnthropicChat and anthropicText omit the fourth
generic (ResolveToolCapabilities<TModel>) which currently relies on the class
default; update both function return type annotations to include
ResolveToolCapabilities<TModel> as the fourth generic parameter so signatures
read AnthropicTextAdapter<TModel, ResolveProviderOptions<TModel>,
ResolveInputModalities<TModel>, ResolveToolCapabilities<TModel>> to make intent
explicit and robust if class generics change.
packages/typescript/ai-gemini/src/tools/google-maps-tool.ts (1)

11-27: Defensive default is optional; current pattern works correctly.

When googleMapsTool() is called without arguments, metadata is undefined, and convertGoogleMapsToolToAdapterFormat returns { googleMaps: undefined }. However, tests confirm this pattern works—the @google/genai SDK serializes and handles undefined fields gracefully (standard JSON behavior omits undefined values). The identical pattern in googleSearchTool() reinforces this is intentional.

If you prefer explicit defensive defaults for clarity:

Optional improvement
 export function googleMapsTool(
   config?: GoogleMapsToolConfig,
 ): GeminiGoogleMapsTool {
   // Phantom-brand cast: '~provider'/'~toolKind' are type-only and never assigned at runtime.
   return {
     name: 'google_maps',
     description: '',
-    metadata: config,
+    metadata: config ?? ({} as GoogleMapsToolConfig),
   } as unknown as GeminiGoogleMapsTool
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-gemini/src/tools/google-maps-tool.ts` around lines 11
- 27, No change required: the current pattern in googleMapsTool and
convertGoogleMapsToolToAdapterFormat correctly allows metadata to be undefined
(the SDK will omit undefined fields); leave the implementations of
googleMapsTool(config?: GoogleMapsToolConfig) and
convertGoogleMapsToolToAdapterFormat(tool: Tool) as-is. If you prefer an
explicit defensive variant, set default metadata in googleMapsTool by using
metadata: config ?? undefined or default to an empty object, but this is
optional.
packages/typescript/ai-gemini/src/tools/file-search-tool.ts (1)

18-26: LGTM — consistent with the cross-package provider-tool branding pattern.

Factory shape and phantom-brand cast match the other provider tool files; metadata: config preserves the runtime payload expected by convertFileSearchToolToAdapterFormat.

One minor tightening (optional): you can preserve more type safety by asserting the object satisfies Tool before branding:

♻️ Optional tightening
-  return {
-    name: 'file_search',
-    description: '',
-    metadata: config,
-  } as unknown as GeminiFileSearchTool
+  const tool: Tool = {
+    name: 'file_search',
+    description: '',
+    metadata: config,
+  }
+  return tool as unknown as GeminiFileSearchTool

This way, if the underlying Tool shape ever changes, the factory fails to compile instead of silently drifting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-gemini/src/tools/file-search-tool.ts` around lines 18
- 26, The factory currently returns a branded GeminiFileSearchTool via an unsafe
cast; tighten types by first ensuring the returned object satisfies the Tool
shape (e.g., construct the object and assert it satisfies the Tool interface
using a TypeScript "satisfies" check or an explicit Tool-typed const) before
performing the phantom-brand cast to GeminiFileSearchTool in fileSearchTool;
update the return to build a Tool-typed value (retaining name, description,
metadata) and then cast that value to GeminiFileSearchTool so future Tool shape
changes cause a compile error.
packages/typescript/ai-gemini/src/tools/google-search-retriveal-tool.ts (1)

4-30: LGTM.

GoogleSearchRetrievalToolConfig + deprecated alias + GeminiGoogleSearchRetrievalTool brand follow the PR-wide pattern. Optional config parameter and resulting metadata: config (possibly undefined) preserves prior runtime behavior since convertGoogleSearchRetrievalToolToAdapterFormat passes metadata straight into googleSearchRetrieval.

Filename typo google-search-retriveal-tool.tsgoogle-search-retrieval-tool.ts is pre-existing and out of scope here, but worth fixing in a follow-up since this file is now re-exported from the new public ./tools entrypoint.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-gemini/src/tools/google-search-retriveal-tool.ts`
around lines 4 - 30, Rename the file from google-search-retriveal-tool.ts to
google-search-retrieval-tool.ts and update any imports/exports that reference it
so the module continues to export GoogleSearchRetrievalToolConfig,
GoogleSearchRetrievalTool (deprecated alias), GeminiGoogleSearchRetrievalTool,
convertGoogleSearchRetrievalToolToAdapterFormat, and googleSearchRetrievalTool
under the new filename; ensure public entrypoints (e.g., the new ./tools index)
re-export the renamed module and run the build/tests to catch any remaining
broken imports.
packages/typescript/ai-groq/src/adapters/text.ts (1)

577-617: Minor: consider mirroring Gemini’s explicit factory return types.

In createGrokText/grokText (and here in createGroqText/groqText), the return type is declared as GroqTextAdapter<TModel>, relying on the class generic defaults (ResolveProviderOptions<TModel>, ResolveInputModalities<TModel>, ResolveToolCapabilities<TModel>) to fill in the rest. Functionally this is equivalent, but createGeminiChat/geminiText in ai-gemini/src/adapters/text.ts (Lines 732-759) spell the resolved generics out explicitly. Making these factory signatures consistent across adapters helps with IDE hovers and avoids surprises if a default is ever changed. Not a blocker.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/adapters/text.ts` around lines 577 - 617, The
factory functions createGroqText and groqText currently declare their return
type as GroqTextAdapter<TModel>, relying on class generic defaults; change both
signatures to explicitly spell out the resolved generics (e.g.,
GroqTextAdapter<TModel, ResolveProviderOptions<TModel>,
ResolveInputModalities<TModel>, ResolveToolCapabilities<TModel>>) so IDE hovers
and type resolution match the pattern used in createGeminiChat/geminiText;
update both createGroqText and groqText return type annotations to reference
GroqTextAdapter plus ResolveProviderOptions, ResolveInputModalities, and
ResolveToolCapabilities generics.
packages/typescript/ai-openai/src/model-meta.ts (1)

2297-2343: Consider deriving OpenAIChatModelToolCapabilitiesByName via a mapped type to avoid drift.

The map is hand-maintained in parallel with the model constants and with OpenAIChatModelProviderOptionsByName. The PR notes already list "capability map drift" as a known follow-up; one way to eliminate it is to tag each model constant with as const satisfies ModelMeta<...> & { readonly name: K } and build the map from a union of constants, or export the constants so a Record<keyof …, …['supports']['tools']> can be generated. As per coding guidelines ("Provide type safety per model by using model-specific provider options in adapter packages"), this also keeps per-model capability typing authoritative without manual enumeration.

Not blocking; flagging since the same drift risk will re-appear every time a chat model is added.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-openai/src/model-meta.ts` around lines 2297 - 2343,
The current OpenAIChatModelToolCapabilitiesByName manual map will drift as
models change; replace it with a derived mapped type built from the existing
model constants/types: create (or use) a union/type of the model constants
(e.g., the exported model constants used to define GPT5_2, GPT_4O, etc.), ensure
each constant is typed as const satisfies ModelMeta<...> & { readonly name: K }
(or export them if not already), then define
OpenAIChatModelToolCapabilitiesByName as Record<typeof
MODEL_CONSTANTS[number]['name'], typeof
MODEL_CONSTANTS[number]['supports']['tools']> (or an equivalent mapped type over
the union) so the per-model supports.tools type is generated automatically from
the model metadata instead of being hand-enumerated.
packages/typescript/ai-openai/src/tools/index.ts (1)

31-115: LGTM — explicit named re-exports are the right move here.

Replacing export * with enumerated exports makes the public surface auditable and the new branded OpenAI*Tool types discoverable. customTool without OpenAICustomTool and function-tool without a factory re-export are both intentional per the PR design (custom is debranded; function tools come from core toolDefinition()).

One small nit: the leading comment on lines 1-3 describes the OpenAITool union below, so it would read more naturally if it sat directly above the export type OpenAITool = ... block (line 17) rather than before the imports.

♻️ Move the documentation comment next to the union it describes
-// Keep the existing discriminated union defined inline.
-// Built from the deprecated config-type aliases — matches the SDK shape that
-// `convertToolsToProviderFormat` emits.
 import type { ApplyPatchTool } from './apply-patch-tool'
@@
 import type { WebSearchTool } from './web-search-tool'

+// Keep the existing discriminated union defined inline.
+// Built from the deprecated config-type aliases — matches the SDK shape that
+// `convertToolsToProviderFormat` emits.
 export type OpenAITool =
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-openai/src/tools/index.ts` around lines 31 - 115, Move
the leading documentation comment that currently sits above the imports so it
directly precedes the OpenAITool union declaration; locate the comment at the
top of packages/typescript/ai-openai/src/tools/index.ts and cut/paste it to sit
immediately above the export type OpenAITool = ... block (the union declaration)
so the comment documents that union (keep the comment text unchanged).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/provider-tools-ai-gemini.md:
- Around line 1-7: This changeset reshapes exported model metadata by moving
entries from supports.capabilities into supports.tools and renaming
grounding_with_gmaps→google_maps and search_grounding→google_search while
removing code_execution, file_search, and url_context from capabilities; update
the changeset to reflect a breaking change by changing the release type from
minor to major (or add a prominent “BREAKING CHANGE” header and migration note)
so consumers inspecting model.supports.capabilities at runtime/types know to
migrate to supports.tools and the new names.

In @.changeset/provider-tools-ai-openrouter.md:
- Around line 1-7: The changeset incorrectly uses a minor bump for a breaking
export removal; update the changeset to mark the release as major. Change the
version tag from 'minor' to 'major' in the .changeset file for
'@tanstack/ai-openrouter' and adjust the description to clearly state that
createWebSearchTool was removed from the package root and consumers must import
webSearchTool from '@tanstack/ai-openrouter/tools' (mentioning symbols
createWebSearchTool and webSearchTool/OpenRouterWebSearchTool and the tools
subpath) so the changeset accurately represents the breaking change.

In `@docs/adapters/gemini.md`:
- Around line 431-437: Update the example and prose to use the correct
FileSearch property: replace the incorrect fileIds usage inside the
fileSearchTool call with fileSearchStoreNames (an array of file search store
resource names) and change any mentions of "corpus and file IDs" to describe
that the parameter accepts file search store names; reference the FileSearch
type and the fileSearchTool call so the example uses fileSearchStoreNames:
["fileSearchStores/my-store"] instead of fileIds.

In `@docs/adapters/openai.md`:
- Around line 518-568: The examples for localShellTool, shellTool, and
applyPatchTool use openaiText("gpt-5.2") but the "Supported models" note says
only Codex CLI / agent-capable models are supported, causing a mismatch with the
compile-time supports.tools gating; fix by either replacing
openaiText("gpt-5.2") in the localShellTool, shellTool, and applyPatchTool
examples with a model id that is actually listed under supports.tools for those
tools (e.g. an agent-capable/Codex CLI model id used by your provider), or
update the "Supported models" text to explicitly include gpt-5.2 if it truly
supports local_shell/shell/apply_patch; ensure you update the examples
referencing openaiText and the Supported models lines consistently.
- Around line 344-360: The docs example for webSearchTool uses the wrong type
value; update the example call to webSearchTool(...) to pass type: "web_search"
(not "web_search_preview") so it matches the implementation and distinguishes it
from webSearchPreviewTool; locate the example that calls webSearchTool in the
docs and change the type string accordingly.

In `@docs/tools/provider-tools.md`:
- Line 37: Update the string inside the messages array (the object with role:
'user' and content: 'Summarize todays AI news.') to correct the typo by changing
"todays" to "today's" so the content reads "Summarize today's AI news."; locate
the messages array/entry and edit the content value accordingly.

In `@packages/typescript/ai-anthropic/tests/tools-per-model-type-safety.test.ts`:
- Around line 7-21: Reorder the import block to satisfy ESLint import/order and
alphabetical ordering: move external package imports (e.g., z from 'zod' and
toolDefinition from '@tanstack/ai' and TextActivityOptions from
'@tanstack/ai/adapters') above local imports (../src and ../src/tools), and
alphabetize named imports so that beforeAll is correctly ordered inside the
'vitest' import (describe, it, beforeAll -> alphabetically: beforeAll, describe,
it or follow project rule); ensure the tools import list (bashTool,
codeExecutionTool, computerUseTool, customTool, memoryTool, textEditorTool,
webFetchTool, webSearchTool) is alphabetized as required.

In `@packages/typescript/ai-openai/src/adapters/text.ts`:
- Around line 119-121: The public method signatures use the broad
OpenAITextProviderOptions instead of the generic TProviderOptions resolved
per-model; update chatStream and structuredOutput to accept
TextOptions<ResolveProviderOptions<TModel>> and
StructuredOutputOptions<ResolveProviderOptions<TModel>> respectively (or, if
implementation requires the base type, keep the existing parameter type but
narrow it immediately inside the method by casting to
ResolveProviderOptions<TModel>) so callers get model-specific type safety;
reference the chatStream and structuredOutput methods and the
ResolveProviderOptions<TModel> helper when making the change.

In `@packages/typescript/ai-openai/src/model-meta.ts`:
- Around line 40-51: Fix three issues in the tool metadata: update the
computerUseTool() branding and its converter emission so the
ProviderTool<'openai','computer_use'> brand matches the wire type (replace any
emission of 'computer_use_preview' with the correct current wire type 'computer'
or align the ProviderTool brand to the actual wire type used), remove the
deprecated local_shell entry from supports.tools (or consolidate to only
'shell') so only the maintained shell tool is present, and add missing
ProviderTool<'openai',...> factory brands for web_search_preview,
image_generation, and code_interpreter (or remove those supports.tools entries)
so every entry in supports.tools corresponds to an actual ProviderTool factory
and the type-level gating is preserved. Ensure changes touch computerUseTool(),
the converter that emits the tool type, and the supports.tools array and the
respective tool factory definitions to keep compile-time brands and runtime wire
types consistent.

In `@packages/typescript/ai-openrouter/src/tools/tool-converter.ts`:
- Around line 9-18: The current dispatch in convertToolsToProviderFormat uses
the user-controllable tool.name which is brittle; change the branching to detect
a stable provider kind/brand on the Tool (e.g., a metadata.kind or __kind
property set by webSearchTool / ProviderTool) instead of name, so
convertWebSearchToolToAdapterFormat is only called for tools with that explicit
kind/brand; update the code that creates web-search tools (webSearchTool or
ProviderTool<TProvider, 'web_search'>) to set the metadata.kind or __kind marker
and alter convertToolsToProviderFormat to check that marker before delegating to
convertWebSearchToolToAdapterFormat, otherwise call
convertFunctionToolToAdapterFormat.

In `@packages/typescript/ai-openrouter/src/tools/web-search-tool.ts`:
- Around line 20-25: The converter convertWebSearchToolToAdapterFormat currently
casts tool.metadata to WebSearchToolConfig without validation; update it to
verify that tool.metadata has the expected branded shape (e.g., metadata.type
=== 'web_search' and metadata.web_search is present and has required fields)
before returning, and throw/return a clear error if the shape is invalid.
Alternatively, restrict conversion to only tools created by webSearchTool by
checking an explicit brand (metadata.type or a specific sentinel) and reject
plain toolDefinition instances; reference convertWebSearchToolToAdapterFormat,
Tool, WebSearchToolConfig, and webSearchTool when implementing the
validation/guard.

In `@packages/typescript/ai-openrouter/tests/tools-per-model-type-safety.test.ts`:
- Around line 7-13: Reorder and alphabetize imports to satisfy ESLint
import/order and sort-imports: move external packages (vitest, `@tanstack/ai`,
`@tanstack/ai/adapters`, zod) before the local ../src import, and alphabetize
named imports (change "describe, it, beforeAll" to "beforeAll, describe, it")
and package import order (ensure `@tanstack/`* and zod appear before ../src);
apply the same ordering pattern to the Gemini and OpenAI type-safety test files
for consistency.

In `@packages/typescript/ai/tests/tools-per-model-type-safety.test.ts`:
- Around line 8-13: Reorder the imports to satisfy ESLint: alphabetically sort
the named imports so expectTypeOf appears between describe and it (import {
describe, expectTypeOf, it }), and move the value import toolDefinition before
the type-only imports (ProviderTool, TextActivityOptions, TextAdapter) so that
all value imports come before type imports; update the import list in the file
containing expectTypeOf, toolDefinition, ProviderTool, TextActivityOptions, and
TextAdapter accordingly.

---

Outside diff comments:
In `@docs/migration/migration.md`:
- Around line 13-19: The top overview numbered list is missing the new Section 6
about Provider Tools/OpenRouter; update the list to include a sixth bullet
describing "Provider Tools added — OpenRouter rename and related breaking
changes" (or similar), and ensure the summary mentions the existing renames:
`providerOptions` → `modelOptions` and `toResponseStream` →
`toServerSentEventsStream` and removal of Embeddings so readers see the
OpenRouter/provider-tools note at a glance; edit the list entries (the overview
block containing "Adapter functions split", "Common options flattened", etc.) to
add the sixth item and make sure it references the new Provider Tools/OpenRouter
change so the overview and Section 6 are consistent.

In `@packages/typescript/ai-gemini/src/model-meta.ts`:
- Around line 289-313: Remove the unsupported file_search tool from the TTS
model metadata objects: update GEMINI_2_5_PRO_TTS and GEMINI_2_5_FLASH_TTS by
deleting 'file_search' from their supports.tools arrays so their supports only
reflect text->audio capability; ensure the objects still satisfy the ModelMeta
type (GeminiToolConfigOptions & GeminiSafetyOptions & GeminiCommonConfigOptions
& GeminiCachedContentOptions) after the removal and run type checks to confirm
no other tool entries remain for TTS models.

In `@packages/typescript/ai/tests/type-check.test.ts`:
- Around line 11-22: The MockAdapter type instantiation omits the
TToolCapabilities type parameter, causing it to fall back to the default instead
of matching the mock's toolCapabilities literal; update the MockAdapter alias
(the TextAdapter instantiation) to include the fifth type argument (e.g.,
readonly string[]) so the generic list of tool capabilities is explicit and
aligns with the mock object’s toolCapabilities value.

In `@scripts/sync-provider-models.ts`:
- Around line 102-124: The templates for new model entries (the
referenceSupportsBody string used in the 'anthropic/' and 'google/' blocks)
currently hardcode the full tools superset, which will incorrectly grant
unsupported tools to newly synced models; change those template snippets to emit
a conservative default tools list (e.g., tools: [] or tools: ['web_search'])
instead of the full superset, add a short comment in the template reminding
reviewers to manually map per-model tool capabilities, and ensure any existing
per-model capability overrides (the canonical capability map) remain
authoritative so the sync doesn't auto-promote unsupported tools.

---

Nitpick comments:
In @.changeset/provider-tools-ai-anthropic.md:
- Line 5: Update the changelog sentence to explicitly state that runtime
behavior and factory signatures remain unchanged but the declared return types
are now branded subtypes of Tool (for example: AnthropicWebSearchTool extends
Tool) and that consumers who typed variables as Tool or used the `@deprecated`
config aliases are unaffected while callers that depended on the old named
return types may observe a different compile-time type; reference the factories
(webSearchTool, codeExecutionTool, computerUseTool, bashTool, textEditorTool,
webFetchTool, memoryTool, customTool) and the branded examples
(AnthropicWebSearchTool) in the wording for clarity.

In `@docs/adapters/grok.md`:
- Around line 234-241: Update the two internal links in the "Provider Tools"
section to use slug-style references (remove the .md suffix) so they match the
repo convention: change "../tools/tools.md" to "../tools/tools" and
"../tools/provider-tools.md" to "../tools/provider-tools"; then run the docs
validation command (pnpm test:docs) and fix any remaining link warnings/errors
reported for the "[Tools]" and "[Provider Tools]" references.

In `@packages/typescript/ai-anthropic/src/adapters/text.ts`:
- Around line 794-821: The return types of createAnthropicChat and anthropicText
omit the fourth generic (ResolveToolCapabilities<TModel>) which currently relies
on the class default; update both function return type annotations to include
ResolveToolCapabilities<TModel> as the fourth generic parameter so signatures
read AnthropicTextAdapter<TModel, ResolveProviderOptions<TModel>,
ResolveInputModalities<TModel>, ResolveToolCapabilities<TModel>> to make intent
explicit and robust if class generics change.

In `@packages/typescript/ai-anthropic/tests/provider-tools-smoke.test.ts`:
- Around line 88-117: The test "converts multiple provider tools in one call"
only asserts names, so add assertions that the returned converted array contains
objects with the expected types to guard against name-based dispatch
regressions; after calling convertToolsToProviderFormat (variable converted)
include assertions like
expect(converted).toContainEqual(expect.objectContaining({ type:
'web_search_20250305' })) and equivalents for 'code_execution_20250825' and
'bash_20250124' to ensure convertToolsToProviderFormat actually produced
provider-shaped tool objects rather than e.g. convertFunctionToolToAdapterFormat
outputs.

In `@packages/typescript/ai-anthropic/tsconfig.json`:
- Around line 6-10: The tsconfig currently only includes the single file
"tests/tools-per-model-type-safety.test.ts", which will miss any new tests;
update the "include" array in tsconfig.json (the entry used to list
"vite.config.ts", "./src", and the single test file) to cover the whole tests
directory (e.g., "tests" or "tests/**/*.ts") so all new type-level tests are
picked up automatically while runtime filtering remains handled by Vitest.

In `@packages/typescript/ai-gemini/src/tools/file-search-tool.ts`:
- Around line 18-26: The factory currently returns a branded
GeminiFileSearchTool via an unsafe cast; tighten types by first ensuring the
returned object satisfies the Tool shape (e.g., construct the object and assert
it satisfies the Tool interface using a TypeScript "satisfies" check or an
explicit Tool-typed const) before performing the phantom-brand cast to
GeminiFileSearchTool in fileSearchTool; update the return to build a Tool-typed
value (retaining name, description, metadata) and then cast that value to
GeminiFileSearchTool so future Tool shape changes cause a compile error.

In `@packages/typescript/ai-gemini/src/tools/google-maps-tool.ts`:
- Around line 11-27: No change required: the current pattern in googleMapsTool
and convertGoogleMapsToolToAdapterFormat correctly allows metadata to be
undefined (the SDK will omit undefined fields); leave the implementations of
googleMapsTool(config?: GoogleMapsToolConfig) and
convertGoogleMapsToolToAdapterFormat(tool: Tool) as-is. If you prefer an
explicit defensive variant, set default metadata in googleMapsTool by using
metadata: config ?? undefined or default to an empty object, but this is
optional.

In `@packages/typescript/ai-gemini/src/tools/google-search-retriveal-tool.ts`:
- Around line 4-30: Rename the file from google-search-retriveal-tool.ts to
google-search-retrieval-tool.ts and update any imports/exports that reference it
so the module continues to export GoogleSearchRetrievalToolConfig,
GoogleSearchRetrievalTool (deprecated alias), GeminiGoogleSearchRetrievalTool,
convertGoogleSearchRetrievalToolToAdapterFormat, and googleSearchRetrievalTool
under the new filename; ensure public entrypoints (e.g., the new ./tools index)
re-export the renamed module and run the build/tests to catch any remaining
broken imports.

In `@packages/typescript/ai-gemini/tests/tools-per-model-type-safety.test.ts`:
- Line 44: Update the test title for the `it` block whose current description is
"gemini-3.1-pro-preview accepts code_execution, file_search, google_search,
url_context" to accurately reflect that the test both accepts and rejects tools
(e.g., "gemini-3.1-pro-preview: accepts {code_execution, file_search,
google_search, url_context}; rejects {computer_use, google_maps,
google_search_retrieval}") or split the body into two `it` blocks (one asserting
accepted tools and one asserting rejected tools) so the test name matches its
assertions; ensure you update any assertion messages/labels within that `it`
block to remain consistent with the new titles.

In `@packages/typescript/ai-gemini/tsconfig.json`:
- Around line 6-10: The tsconfig.json "include" array currently references a
single test file ("tests/tools-per-model-type-safety.test.ts"), which is
fragile; update the "include" array (the include property in tsconfig.json) to
include the entire tests directory (e.g., "tests" or "./tests") instead of the
single filename so that all current and future tests under tests/ are
type-checked; keep the existing entries ("vite.config.ts" and "./src") and
replace or add the tests directory entry accordingly.

In `@packages/typescript/ai-grok/src/model-meta.ts`:
- Around line 321-333: The explicit GrokChatModelToolCapabilitiesByName object
should be rewritten as a mapped type keyed from the shared models tuple to avoid
drift: replace the manual keys in GrokChatModelToolCapabilitiesByName with a
mapped type like Record<(typeof GROK_CHAT_MODELS)[number]['name'], (typeof
GROK_CHAT_MODELS)[number]['supports']['tools']>; mirror the pattern used by
GrokChatModelProviderOptionsByName, and ensure the shared tuple (e.g.
GROK_CHAT_MODELS) is declared as const so the mapping is exhaustive and stays in
sync when models are added/removed.

In `@packages/typescript/ai-groq/src/adapters/text.ts`:
- Around line 577-617: The factory functions createGroqText and groqText
currently declare their return type as GroqTextAdapter<TModel>, relying on class
generic defaults; change both signatures to explicitly spell out the resolved
generics (e.g., GroqTextAdapter<TModel, ResolveProviderOptions<TModel>,
ResolveInputModalities<TModel>, ResolveToolCapabilities<TModel>>) so IDE hovers
and type resolution match the pattern used in createGeminiChat/geminiText;
update both createGroqText and groqText return type annotations to reference
GroqTextAdapter plus ResolveProviderOptions, ResolveInputModalities, and
ResolveToolCapabilities generics.

In `@packages/typescript/ai-groq/src/model-meta.ts`:
- Around line 367-386: The explicit per-model mapping in
GroqChatModelToolCapabilitiesByName is brittle (you must update it whenever
GROQ_CHAT_MODELS changes); replace it with a derived mapped type from the Groq
model union/collection (e.g., use GroqChatModels or GROQ_CHAT_MODELS as the key
type) that maps each model name to readonly [] so all current and future Groq
models automatically get the correct tool-capabilities type; update the
GroqChatModelToolCapabilitiesByName definition to use that mapped type instead
of enumerating LLAMA_3_1_8B_INSTANT, LLAMA_3_3_70B_VERSATILE, etc.

In `@packages/typescript/ai-openai/src/model-meta.ts`:
- Around line 2297-2343: The current OpenAIChatModelToolCapabilitiesByName
manual map will drift as models change; replace it with a derived mapped type
built from the existing model constants/types: create (or use) a union/type of
the model constants (e.g., the exported model constants used to define GPT5_2,
GPT_4O, etc.), ensure each constant is typed as const satisfies ModelMeta<...> &
{ readonly name: K } (or export them if not already), then define
OpenAIChatModelToolCapabilitiesByName as Record<typeof
MODEL_CONSTANTS[number]['name'], typeof
MODEL_CONSTANTS[number]['supports']['tools']> (or an equivalent mapped type over
the union) so the per-model supports.tools type is generated automatically from
the model metadata instead of being hand-enumerated.

In `@packages/typescript/ai-openai/src/tools/computer-use-tool.ts`:
- Around line 29-39: The factory computerUseTool currently spreads toolData
directly into metadata causing metadata to be the full ComputerUseToolConfig
(including its type tag); change metadata to wrap the options in a nested key
(e.g., metadata: { config: toolData } or metadata: { computerUseConfig: toolData
}) so metadata is a plain container like other providers, and update
convertComputerUseToolToAdapterFormat to read the nested config key instead of
casting metadata directly; reference computerUseTool,
convertComputerUseToolToAdapterFormat, ComputerUseToolConfig and
OpenAIComputerUseTool when making the change.

In `@packages/typescript/ai-openai/src/tools/index.ts`:
- Around line 31-115: Move the leading documentation comment that currently sits
above the imports so it directly precedes the OpenAITool union declaration;
locate the comment at the top of
packages/typescript/ai-openai/src/tools/index.ts and cut/paste it to sit
immediately above the export type OpenAITool = ... block (the union declaration)
so the comment documents that union (keep the comment text unchanged).

In `@packages/typescript/ai-openai/tsconfig.json`:
- Around line 6-10: The tsconfig's "include" currently pins only a single test
file ("tests/tools-per-model-type-safety.test.ts"), which will miss future
tests; update the "include" array entry for tests to a glob such as
"tests/**/*.test.ts" (or "tests/**/*") so all test files under tests/ are picked
up by tsc for the test:types run—locate the "include" array in tsconfig.json and
replace or add the broader glob entry.

In `@packages/typescript/ai-openrouter/src/tools/web-search-tool.ts`:
- Around line 40-51: The returned tool object for web_search uses an empty
description which can break stricter validators; update the factory that returns
the object (the one creating name: 'web_search' and casting to
OpenRouterWebSearchTool) to provide a concise static description like "Search
the web via OpenRouter." instead of '', ensuring the description field on the
returned object is non-empty and stays compatible with the existing metadata and
the OpenRouterWebSearchTool cast.

In `@packages/typescript/ai-openrouter/tests/tools-per-model-type-safety.test.ts`:
- Around line 25-27: Set the OPENROUTER_API_KEY synchronously at
module-evaluation time instead of in beforeAll so adapters aren't accidentally
constructed before the env exists: move the assignment
process.env['OPENROUTER_API_KEY'] = 'sk-or-test-dummy' to the top-level of the
test file (above any imports or top-level declarations) and ensure no call to
openRouterText or any adapter factory like userTool runs at import time; this
guarantees adapters created during import will see the env and prevents future
breakage if openRouterText is moved out of an it block.

In `@packages/typescript/ai/tests/tools-per-model-type-safety.test.ts`:
- Around line 53-59: Replace deprecated expectTypeOf(...).toMatchTypeOf() calls
with expectTypeOf(...).toExtend() for the two assertions: change the assertion
on userTool to use expectTypeOf(userTool).toExtend<MockToolsOption>() and change
the assertion on supportedProviderTool to use
expectTypeOf(supportedProviderTool).toExtend<MockToolsOption>(); update the two
occurrences referencing userTool, supportedProviderTool, and MockToolsOption
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

Comment on lines +1 to +7
---
'@tanstack/ai-gemini': minor
---

Expose provider-tool factories (`codeExecutionTool`, `fileSearchTool`, `googleSearchTool`, `googleSearchRetrievalTool`, `googleMapsTool`, `urlContextTool`, `computerUseTool`) on a new `/tools` subpath, each returning a branded type gated against the selected model's `supports.tools` list.

Note: `supports.capabilities` entries that described tools (`code_execution`, `file_search`, `grounding_with_gmaps` → renamed `google_maps`, `search_grounding` → renamed `google_search`, `url_context`) have been relocated to the new `supports.tools` field. The `capabilities` array loses those entries. This is a model-meta shape change but not a runtime break.
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.

⚠️ Potential issue | 🟡 Minor

Consider flagging the supports.capabilities reshape as breaking for consumers reading model metadata.

Renaming/relocating entries (grounding_with_gmapsgoogle_maps, search_groundinggoogle_search, and removal of code_execution/file_search/url_context from capabilities) is a visible shape change to exported model metadata. Downstream code that inspects model.supports.capabilities at runtime/type-level will break, even if no adapter runtime path changes. A minor bump may be appropriate only if these maps are considered internal; otherwise this warrants a major or at least a prominent note in the migration guide.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/provider-tools-ai-gemini.md around lines 1 - 7, This changeset
reshapes exported model metadata by moving entries from supports.capabilities
into supports.tools and renaming grounding_with_gmaps→google_maps and
search_grounding→google_search while removing code_execution, file_search, and
url_context from capabilities; update the changeset to reflect a breaking change
by changing the release type from minor to major (or add a prominent “BREAKING
CHANGE” header and migration note) so consumers inspecting
model.supports.capabilities at runtime/types know to migrate to supports.tools
and the new names.

Comment on lines +1 to +7
---
'@tanstack/ai-openrouter': minor
---

**Breaking export change.** `createWebSearchTool` has been removed from the package root. Import `webSearchTool` from `@tanstack/ai-openrouter/tools` instead. See Migration Guide §6 for the before/after snippet.

Alongside: the new `/tools` subpath exposes `webSearchTool` (branded `OpenRouterWebSearchTool`) and the existing `convertToolsToProviderFormat`. A new `supports.tools` channel on each chat model gates provider tools at the type level.
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check current version and any prior breaking-change changesets for precedent.
fd -t f 'package.json' packages/typescript/ai-openrouter --exec jq -r '.name + " " + .version' {} \;
# Look at recent changesets for how past breaking changes were bumped
fd -t f -e md . .changeset | head -50

Repository: TanStack/ai

Length of output: 466


🏁 Script executed:

# Check the other provider-tools changesets to see how breaking changes were bumped
cat .changeset/provider-tools-ai-anthropic.md
cat .changeset/provider-tools-ai-core.md
cat .changeset/provider-tools-ai-openai.md

Repository: TanStack/ai

Length of output: 1566


🏁 Script executed:

# Check .changeset configuration to understand versioning policy
cat .changeset/config.json 2>/dev/null || cat .changeset/config.js 2>/dev/null || echo "No config found"

Repository: TanStack/ai

Length of output: 498


🏁 Script executed:

# Look for versioning policy documentation
fd -t f -e md '(CONTRIBUTING|README|CHANGELOG)' . | head -5 | xargs -I {} grep -l "major\|minor\|breaking\|pre-1.0\|0\." {} 2>/dev/null || echo "No policy found in docs"

Repository: TanStack/ai

Length of output: 114


Change semantic version to major for this breaking export removal.

This changeset describes an actual breaking change—createWebSearchTool is removed from the package root without a deprecation path. The similar provider-tools changesets (@tanstack/ai-anthropic, @tanstack/ai-openai) are marked minor because they add new /tools exports while preserving backward compatibility via deprecated aliases. The openrouter change removes an export entirely, which is a breaking change and should be major per semver, regardless of the 0.x version number.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/provider-tools-ai-openrouter.md around lines 1 - 7, The changeset
incorrectly uses a minor bump for a breaking export removal; update the
changeset to mark the release as major. Change the version tag from 'minor' to
'major' in the .changeset file for '@tanstack/ai-openrouter' and adjust the
description to clearly state that createWebSearchTool was removed from the
package root and consumers must import webSearchTool from
'@tanstack/ai-openrouter/tools' (mentioning symbols createWebSearchTool and
webSearchTool/OpenRouterWebSearchTool and the tools subpath) so the changeset
accurately represents the breaking change.

Comment thread docs/adapters/gemini.md
Comment thread docs/adapters/openai.md
Comment thread docs/adapters/openai.md Outdated
Comment on lines +518 to +568
```typescript
import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import { localShellTool } from "@tanstack/ai-openai/tools";

const stream = chat({
adapter: openaiText("gpt-5.2"),
messages: [{ role: "user", content: "Run the test suite and summarise failures" }],
tools: [localShellTool()],
});
```

**Supported models:** Codex CLI and agent-capable models. See [Provider Tools](../tools/provider-tools.md#which-models-support-which-tools).

### `shellTool`

A function-style shell tool that exposes shell execution as a structured
function call. Takes no arguments.

```typescript
import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import { shellTool } from "@tanstack/ai-openai/tools";

const stream = chat({
adapter: openaiText("gpt-5.2"),
messages: [{ role: "user", content: "Count lines in all JS files" }],
tools: [shellTool()],
});
```

**Supported models:** Codex CLI and agent-capable models. See [Provider Tools](../tools/provider-tools.md#which-models-support-which-tools).

### `applyPatchTool`

Lets the model apply unified-diff patches to modify files directly. Takes no
arguments — include it in the `tools` array to enable patch application.

```typescript
import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
import { applyPatchTool } from "@tanstack/ai-openai/tools";

const stream = chat({
adapter: openaiText("gpt-5.2"),
messages: [{ role: "user", content: "Fix the import paths in src/index.ts" }],
tools: [applyPatchTool()],
});
```

**Supported models:** Codex CLI and agent-capable models. See [Provider Tools](../tools/provider-tools.md#which-models-support-which-tools).
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.

⚠️ Potential issue | 🟠 Major

Shell/patch tool examples contradict their own “Supported models” notes and the type‑gating feature.

localShellTool, shellTool, and applyPatchTool examples all use openaiText("gpt-5.2"), but each section states they are only supported on "Codex CLI and agent-capable models". Since this PR’s central feature is compile-time gating via supports.tools, copy-pasting these snippets will either (a) hit a type error if gpt-5.2’s supports.tools excludes local_shell/shell/apply_patch, or (b) silently work and contradict the stated support matrix — whichever is the case, one of the two is wrong.

Please pick a model listed in the expanded supports.tools for each tool (e.g. a Codex/agent-capable model id) in the examples, or update the "Supported models" text to match reality.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/adapters/openai.md` around lines 518 - 568, The examples for
localShellTool, shellTool, and applyPatchTool use openaiText("gpt-5.2") but the
"Supported models" note says only Codex CLI / agent-capable models are
supported, causing a mismatch with the compile-time supports.tools gating; fix
by either replacing openaiText("gpt-5.2") in the localShellTool, shellTool, and
applyPatchTool examples with a model id that is actually listed under
supports.tools for those tools (e.g. an agent-capable/Codex CLI model id used by
your provider), or update the "Supported models" text to explicitly include
gpt-5.2 if it truly supports local_shell/shell/apply_patch; ensure you update
the examples referencing openaiText and the Supported models lines consistently.

Comment on lines 40 to 51
tools?: Array<
| 'web_search'
| 'web_search_preview'
| 'file_search'
| 'image_generation'
| 'code_interpreter'
| 'mcp'
| 'computer_use'
| 'local_shell'
| 'shell'
| 'apply_patch'
>
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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Extract every OpenAI tool-kind string referenced on both sides so we can
# cross-check brand strings vs. supports.tools vs. wire `type:` values.

echo "=== ProviderTool<'openai', ...> brand kinds ==="
rg -nP "ProviderTool<\s*'openai'\s*,\s*'([a-z_]+)'" --type=ts packages/typescript/ai-openai

echo
echo "=== supports.tools entries (unique) ==="
rg -nP "^\s*'(web_search|web_search_preview|file_search|image_generation|code_interpreter|mcp|computer_use|computer_use_preview|local_shell|shell|apply_patch)'," --type=ts packages/typescript/ai-openai/src/model-meta.ts \
  | sed -E "s/.*'([^']+)'.*/\1/" | sort -u

echo
echo "=== wire 'type:' values emitted by converters ==="
rg -nP --type=ts -C1 "type:\s*'[a-z_]+'" packages/typescript/ai-openai/src/tools

Repository: TanStack/ai

Length of output: 5264


🌐 Web query:

OpenAI Responses API tool types: is there a distinct "shell" tool or only "local_shell"? Also confirm the exact name for the computer-use tool (computer_use vs computer_use_preview).

💡 Result:

In the OpenAI Responses API, there is a "shell" tool that supports both hosted (e.g., container_auto) and local execution modes. The older "local_shell" tool is deprecated and marked as outdated in the documentation, recommending use of the "shell" tool instead. There is no distinct generic "shell" tool separate from "local_shell"; "shell" encompasses both hosted and local shell capabilities. The computer-use tool is named "computer" (type: "computer"). The older preview version was "computer_use_preview" (type: "computer_use_preview"), which is deprecated in favor of "computer". Official docs confirm migration from computer_use_preview to "computer".

Citations:


Fix type mismatch between computerUseTool() brand and wire type emission, and verify supports.tools entries align with all tool factories.

The verification found critical issues:

  1. Type mismatch on computer_use tool: The computerUseTool() factory is branded as ProviderTool<'openai', 'computer_use'> but the converter in computer-use-tool.ts:19 emits type: 'computer_use_preview'. This breaks the type-to-wire contract. Additionally, OpenAI API documentation indicates the current tool type should be 'computer' (not the preview variant), suggesting a broader version mismatch.

  2. Deprecated local_shell coexists with current shell: Both tools exist in the codebase (emitting types 'local_shell' and 'shell' respectively). Web search confirms 'shell' is the current maintained tool and 'local_shell' is deprecated. Having both in supports.tools risks breaking if OpenAI discontinues the preview variant.

  3. Missing ProviderTool brands: Three entries in supports.toolsweb_search_preview, image_generation, and code_interpreter—lack corresponding ProviderTool<'openai', ...> factory brands, creating unreachable entries that cannot gate tool arguments at compile time.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-openai/src/model-meta.ts` around lines 40 - 51, Fix
three issues in the tool metadata: update the computerUseTool() branding and its
converter emission so the ProviderTool<'openai','computer_use'> brand matches
the wire type (replace any emission of 'computer_use_preview' with the correct
current wire type 'computer' or align the ProviderTool brand to the actual wire
type used), remove the deprecated local_shell entry from supports.tools (or
consolidate to only 'shell') so only the maintained shell tool is present, and
add missing ProviderTool<'openai',...> factory brands for web_search_preview,
image_generation, and code_interpreter (or remove those supports.tools entries)
so every entry in supports.tools corresponds to an actual ProviderTool factory
and the type-level gating is preserved. Ensure changes touch computerUseTool(),
the converter that emits the tool type, and the supports.tools array and the
respective tool factory definitions to keep compile-time brands and runtime wire
types consistent.

Comment thread packages/typescript/ai-openrouter/src/tools/tool-converter.ts
Comment thread packages/typescript/ai-openrouter/src/tools/web-search-tool.ts
Comment thread packages/typescript/ai-openrouter/tests/tools-per-model-type-safety.test.ts Outdated
Comment thread packages/typescript/ai/tests/tools-per-model-type-safety.test.ts Outdated
…ng-harp

# Conflicts:
#	packages/typescript/ai-grok/src/adapters/text.ts
#	packages/typescript/ai-groq/src/adapters/text.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
packages/typescript/ai-grok/src/adapters/text.ts (1)

89-160: ⚠️ Potential issue | 🟠 Major

Use the resolved provider-options generic in public methods.

chatStream and structuredOutput accept the broad GrokTextProviderOptions, so direct adapter method calls lose the per-model option narrowing that TProviderOptions was added to carry. Based on learnings, Provide type safety per model by using model-specific provider options in adapter packages.

🛠️ Proposed fix
   async *chatStream(
-    options: TextOptions<GrokTextProviderOptions>,
+    options: TextOptions<TProviderOptions>,
   ): AsyncIterable<StreamChunk> {
   async structuredOutput(
-    options: StructuredOutputOptions<GrokTextProviderOptions>,
+    options: StructuredOutputOptions<TProviderOptions>,
   ): Promise<StructuredOutputResult<unknown>> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-grok/src/adapters/text.ts` around lines 89 - 160, The
public adapter methods chatStream and structuredOutput currently use the broad
GrokTextProviderOptions type and lose per-model provider-option narrowing;
update their signatures to accept the generic provider-options type (e.g.,
TextOptions<TProviderOptions> and StructuredOutputOptions<TProviderOptions> or
whatever generic alias is used in this file) so callers preserve model-specific
options, and adjust any internal uses (mapTextOptionsToGrok,
processGrokStreamChunks) to accept/return the same generic TProviderOptions to
maintain type-safety across the adapter boundary.
🧹 Nitpick comments (2)
packages/typescript/ai-groq/src/adapters/text.ts (1)

42-47: Consolidate the two GroqTextProviderOptions declarations.

Line 42 defines a local alias and line 62 separately re-exports ExternalTextProviderOptions as GroqTextProviderOptions via export type { ... } from '...'. Both are needed today because the export ... from form doesn't create a local binding, but this can be collapsed into a single declaration that is both locally usable and exported:

♻️ Proposed consolidation
-type GroqTextProviderOptions = ExternalTextProviderOptions
+export type GroqTextProviderOptions = ExternalTextProviderOptions

…and remove the duplicate re-export at line 62:

-/**
- * Alias for TextProviderOptions for external use
- */
-export type { ExternalTextProviderOptions as GroqTextProviderOptions } from '../text/text-provider-options'

You'll also need to add ExternalTextProviderOptions to the existing type import block at line 30 (already imported there, so no new import needed).

Also note: NonNullable<GroqChatModelToolCapabilitiesByName[TModel]> at line 46 is defensive — each entry in that map is typeof MODEL.supports.tools, which is non-optional by construction. Harmless, but you can drop the NonNullable<…> wrapper if you want a tighter signature.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/adapters/text.ts` around lines 42 - 47,
Replace the duplicate type alias and re-export by making the local alias
GroqTextProviderOptions also the exported name: import
ExternalTextProviderOptions into the existing type import block, then declare
"export type GroqTextProviderOptions = ExternalTextProviderOptions" (or simply
"export type GroqTextProviderOptions = ExternalTextProviderOptions" where the
local alias currently exists) and remove the separate "export type {
ExternalTextProviderOptions as GroqTextProviderOptions }" re-export; optionally
tighten ResolveToolCapabilities<TModel> by removing the NonNullable wrapper
around GroqChatModelToolCapabilitiesByName[TModel] if you want the stricter
signature.
packages/typescript/ai-openai/src/adapters/text.ts (1)

100-112: Tighten TProviderOptions constraint for consistency with BaseTextAdapter.

BaseTextAdapter constrains provider options to Record<string, any>, but OpenAITextAdapter declares TProviderOptions extends object. While the resolved types from ResolveProviderOptions<TModel> are always compatible objects, making the constraint explicit improves type clarity and consistency with the parent class.

Suggested improvement
 export class OpenAITextAdapter<
   TModel extends OpenAIChatModel,
-  TProviderOptions extends object = ResolveProviderOptions<TModel>,
+  TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,

Note: This pattern is used consistently across all provider adapters (Groq, Gemini, Anthropic, etc.), so consider aligning them together if making this change.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-openai/src/adapters/text.ts` around lines 100 - 112,
The generic constraint for TProviderOptions on OpenAITextAdapter is looser than
BaseTextAdapter; change TProviderOptions extends object to TProviderOptions
extends Record<string, any> so it matches BaseTextAdapter's constraint and keeps
type consistency with ResolveProviderOptions<TModel> (update the generic
declaration on the OpenAITextAdapter class signature that references
TProviderOptions and ensure any imports/types still type-check).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/typescript/ai-gemini/tests/tools-per-model-type-safety.test.ts`:
- Around line 7-21: Reorder and alphabetize the imports so ESLint's
sort-imports/import/order rules are satisfied: group external packages first
(e.g., '@google/genai' Environment, '@tanstack/ai' toolDefinition,
'@tanstack/ai/adapters' TextActivityOptions, 'vitest' imports), then third-party
libs like 'zod' (z), and finally local imports (../src geminiText and
../src/tools exports such as codeExecutionTool, computerUseTool, fileSearchTool,
googleMapsTool, googleSearchRetrievalTool, googleSearchTool, urlContextTool);
also alphabetize specifiers within each import statement.

In `@packages/typescript/ai-grok/src/adapters/text.ts`:
- Around line 65-78: GrokTextAdapter's generic TProviderOptions uses a too-loose
constraint (extends object) that conflicts with BaseTextAdapter's
TProviderOptions constraint; change the generic declaration for TProviderOptions
in the GrokTextAdapter class so it matches BaseTextAdapter (use the same
Record<string, any> constraint) — update the generic on the GrokTextAdapter
class declaration (the TProviderOptions type parameter) to extend Record<string,
any> to align with BaseTextAdapter.

---

Outside diff comments:
In `@packages/typescript/ai-grok/src/adapters/text.ts`:
- Around line 89-160: The public adapter methods chatStream and structuredOutput
currently use the broad GrokTextProviderOptions type and lose per-model
provider-option narrowing; update their signatures to accept the generic
provider-options type (e.g., TextOptions<TProviderOptions> and
StructuredOutputOptions<TProviderOptions> or whatever generic alias is used in
this file) so callers preserve model-specific options, and adjust any internal
uses (mapTextOptionsToGrok, processGrokStreamChunks) to accept/return the same
generic TProviderOptions to maintain type-safety across the adapter boundary.

---

Nitpick comments:
In `@packages/typescript/ai-groq/src/adapters/text.ts`:
- Around line 42-47: Replace the duplicate type alias and re-export by making
the local alias GroqTextProviderOptions also the exported name: import
ExternalTextProviderOptions into the existing type import block, then declare
"export type GroqTextProviderOptions = ExternalTextProviderOptions" (or simply
"export type GroqTextProviderOptions = ExternalTextProviderOptions" where the
local alias currently exists) and remove the separate "export type {
ExternalTextProviderOptions as GroqTextProviderOptions }" re-export; optionally
tighten ResolveToolCapabilities<TModel> by removing the NonNullable wrapper
around GroqChatModelToolCapabilitiesByName[TModel] if you want the stricter
signature.

In `@packages/typescript/ai-openai/src/adapters/text.ts`:
- Around line 100-112: The generic constraint for TProviderOptions on
OpenAITextAdapter is looser than BaseTextAdapter; change TProviderOptions
extends object to TProviderOptions extends Record<string, any> so it matches
BaseTextAdapter's constraint and keeps type consistency with
ResolveProviderOptions<TModel> (update the generic declaration on the
OpenAITextAdapter class signature that references TProviderOptions and ensure
any imports/types still type-check).
🪄 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: e202b409-2ef1-40e5-9c94-c1267a5e9802

📥 Commits

Reviewing files that changed from the base of the PR and between 0c1bd22 and 6e9919c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (23)
  • docs/adapters/anthropic.md
  • docs/adapters/gemini.md
  • docs/adapters/grok.md
  • docs/adapters/groq.md
  • docs/adapters/openai.md
  • docs/adapters/openrouter.md
  • docs/config.json
  • docs/migration/migration.md
  • docs/tools/tools.md
  • packages/typescript/ai-anthropic/package.json
  • packages/typescript/ai-anthropic/src/adapters/text.ts
  • packages/typescript/ai-gemini/package.json
  • packages/typescript/ai-gemini/src/adapters/text.ts
  • packages/typescript/ai-gemini/tests/tools-per-model-type-safety.test.ts
  • packages/typescript/ai-grok/src/adapters/text.ts
  • packages/typescript/ai-groq/src/adapters/text.ts
  • packages/typescript/ai-openai/package.json
  • packages/typescript/ai-openai/src/adapters/text.ts
  • packages/typescript/ai-openrouter/package.json
  • packages/typescript/ai-openrouter/src/adapters/text.ts
  • packages/typescript/ai-openrouter/src/model-meta.ts
  • packages/typescript/ai/src/activities/chat/index.ts
  • packages/typescript/ai/tests/test-utils.ts
✅ Files skipped from review due to trivial changes (9)
  • docs/config.json
  • packages/typescript/ai-anthropic/package.json
  • packages/typescript/ai-gemini/package.json
  • docs/adapters/gemini.md
  • docs/adapters/openai.md
  • packages/typescript/ai-openai/package.json
  • docs/adapters/grok.md
  • docs/tools/tools.md
  • docs/adapters/groq.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/typescript/ai-openrouter/package.json
  • packages/typescript/ai/src/activities/chat/index.ts
  • packages/typescript/ai-anthropic/src/adapters/text.ts
  • docs/migration/migration.md
  • packages/typescript/ai-openrouter/src/model-meta.ts
  • packages/typescript/ai-gemini/src/adapters/text.ts
  • docs/adapters/anthropic.md

Comment thread packages/typescript/ai-gemini/tests/tools-per-model-type-safety.test.ts Outdated
Comment thread packages/typescript/ai-grok/src/adapters/text.ts
- Tighten TProviderOptions constraint from 'extends object' to
  'extends Record<string, any>' across all five text adapters to match
  BaseTextAdapter (openai, anthropic, gemini, grok, groq).
- OpenAI & Anthropic: wire chatStream / structuredOutput to the
  TProviderOptions generic so per-model provider options are enforced
  at the call site, matching the openrouter/gemini pattern.
- OpenRouter webSearchTool: brand via a stable __kind marker and gate
  the converter on that; reject malformed metadata explicitly instead
  of trusting tool.name === 'web_search' (users can collide on name).
- Docs: fix fileSearchTool example to use the real
  fileSearchStoreNames shape; switch webSearchTool example back to
  type: 'web_search' (preview variant is a separate factory); update
  local_shell/shell/apply_patch supported-models copy to match the
  actual supports.tools gating; drop 'todays' typo.
- Tests: apply ESLint import/order + sort-imports to the five
  tools-per-model type-safety specs.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
packages/typescript/ai-anthropic/src/adapters/text.ts (2)

906-925: Consider propagating TToolCapabilities in factory return types.

AnthropicTextAdapter now takes a 4th generic TToolCapabilities, but createAnthropicChat and anthropicText only specify the first three type arguments in their return type annotations. The default ResolveToolCapabilities<TModel> will resolve correctly, so this is functionally fine, but being explicit keeps the public return type self-documenting and symmetric with the other resolved generics (and guards against future refactors that might change the default).

♻️ Suggested change
 ): AnthropicTextAdapter<
   TModel,
   ResolveProviderOptions<TModel>,
-  ResolveInputModalities<TModel>
+  ResolveInputModalities<TModel>,
+  ResolveToolCapabilities<TModel>
 > {

(apply to both createAnthropicChat and anthropicText)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-anthropic/src/adapters/text.ts` around lines 906 -
925, Update the return type annotations for both createAnthropicChat and
anthropicText to explicitly include the fourth generic TToolCapabilities (use
ResolveToolCapabilities<TModel>) so the
AnthropicTextAdapter/AnthropicChatAdapter signatures are fully specified; locate
the factory functions named createAnthropicChat and anthropicText and change
their return type generics from three type args to four (e.g.,
AnthropicTextAdapter<TModel, ResolveProviderOptions<TModel>,
ResolveInputModalities<TModel>, ResolveToolCapabilities<TModel>>) so the public
API documents and preserves the tool-capabilities generic explicitly.

249-251: Private helpers still typed against AnthropicTextProviderOptions.

chatStream/structuredOutput now accept TextOptions<TProviderOptions>, but mapCommonOptionsToAnthropic (line 250) and processAnthropicStream (line 542) keep their parameters as TextOptions<AnthropicTextProviderOptions>. When TProviderOptions resolves to a narrower per-model intersection (e.g. AnthropicContainerOptions & AnthropicThinkingOptions & …), passing it to a parameter typed against the broader ExternalTextProviderOptions relies on structural compatibility that may break once AnthropicTextProviderOptions diverges from the per-model maps. For consistency with the new generic threading, consider parameterizing these helpers on TProviderOptions (or at least widening to TextOptions<Record<string, any>>).

Also applies to: 540-544

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-anthropic/src/adapters/text.ts` around lines 249 -
251, The helpers mapCommonOptionsToAnthropic and processAnthropicStream are
still typed against TextOptions<AnthropicTextProviderOptions>, which breaks the
new generic threading; update their signatures to accept the generic provider
options (e.g., make them mapCommonOptionsToAnthropic<TProviderOptions>(options:
TextOptions<TProviderOptions>) and
processAnthropicStream<TProviderOptions>(options: TextOptions<TProviderOptions>,
...) ) or alternatively widen the parameter to TextOptions<Record<string, any>>;
then update all internal references and call sites to use the new
generic/widened signature so narrow per-model intersections (e.g.,
AnthropicContainerOptions & AnthropicThinkingOptions) are accepted without
relying on fragile structural compatibility.
packages/typescript/ai-groq/src/adapters/text.ts (1)

42-42: Consolidate duplicate GroqTextProviderOptions declarations.

Line 42 declares a local (unexported) alias GroqTextProviderOptions = ExternalTextProviderOptions, while line 62 re-exports the same name via export type { ExternalTextProviderOptions as GroqTextProviderOptions } from '../text/text-provider-options'. Functionally this works (the export ... from re-export does not introduce a local binding that collides with line 42), but now the module has two parallel sources of truth for the same alias — one internal, one public. A future edit to one is easy to forget in the other.

Consider collapsing into a single exported alias and removing the re-export at line 62:

♻️ Proposed consolidation
-type GroqTextProviderOptions = ExternalTextProviderOptions
+export type GroqTextProviderOptions = ExternalTextProviderOptions
-/**
- * Alias for TextProviderOptions for external use
- */
-export type { ExternalTextProviderOptions as GroqTextProviderOptions } from '../text/text-provider-options'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/adapters/text.ts` at line 42, There are two
declarations for GroqTextProviderOptions; remove the duplication by turning the
local alias into the single exported alias and deleting the separate re-export:
change the local declaration `type GroqTextProviderOptions =
ExternalTextProviderOptions` to `export type GroqTextProviderOptions =
ExternalTextProviderOptions` (ensure ExternalTextProviderOptions is imported
where needed), and remove the `export type { ExternalTextProviderOptions as
GroqTextProviderOptions }` re-export so only the exported alias
`GroqTextProviderOptions` remains.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/typescript/ai-gemini/tests/tools-per-model-type-safety.test.ts`:
- Around line 68-84: Add the missing provider tool to the rejection test: in the
"gemini-2.0-flash-lite rejects all provider tools" case, include
googleSearchRetrievalTool() in the array passed to typedTools(adapter, [...])
with the same `@ts-expect-error` comment used for other unsupported provider tools
so the test will catch regressions for that provider; locate the test by the it
description and modify the array listing userTool, codeExecutionTool(),
computerUseTool(), fileSearchTool(...), googleMapsTool(), googleSearchTool(),
urlContextTool() to also contain googleSearchRetrievalTool().

In `@packages/typescript/ai-groq/src/adapters/text.ts`:
- Around line 44-47: Add a compile-time type-safety test that asserts
provider-branded tools are not assignable to Groq models: create a new tests
file (e.g., tools-per-model-type-safety.test.ts) that imports
ResolveToolCapabilities, GroqChatModelToolCapabilitiesByName, ProviderTool,
Tool, and TextAdapter['~types'].toolCapabilities and adds `@ts-expect-error`
assertions showing that a ProviderTool with a branded TToolCapabilities cannot
be assigned to a Groq model (whose capabilities resolve to readonly []), while
plain/unbranded Tool remains assignable; ensure the test covers a representative
Groq model name and matches the pattern used in the Anthropic adapter's
type-safety test.

In `@packages/typescript/ai-openrouter/src/tools/web-search-tool.ts`:
- Around line 45-54: The validation for metadata.web_search in
convertWebSearchToolToAdapterFormat is too loose (typeof allows null and
arrays); update the check to ensure metadata.web_search is a non-null plain
object and not an array by requiring metadata.web_search !== null &&
!Array.isArray(metadata.web_search) in addition to typeof metadata.web_search
=== 'object', so that malformed branded tools (null or []) fail fast with the
existing error for tool.name when metadata.__kind !== WEB_SEARCH_TOOL_KIND or
metadata.type !== 'web_search'.

---

Nitpick comments:
In `@packages/typescript/ai-anthropic/src/adapters/text.ts`:
- Around line 906-925: Update the return type annotations for both
createAnthropicChat and anthropicText to explicitly include the fourth generic
TToolCapabilities (use ResolveToolCapabilities<TModel>) so the
AnthropicTextAdapter/AnthropicChatAdapter signatures are fully specified; locate
the factory functions named createAnthropicChat and anthropicText and change
their return type generics from three type args to four (e.g.,
AnthropicTextAdapter<TModel, ResolveProviderOptions<TModel>,
ResolveInputModalities<TModel>, ResolveToolCapabilities<TModel>>) so the public
API documents and preserves the tool-capabilities generic explicitly.
- Around line 249-251: The helpers mapCommonOptionsToAnthropic and
processAnthropicStream are still typed against
TextOptions<AnthropicTextProviderOptions>, which breaks the new generic
threading; update their signatures to accept the generic provider options (e.g.,
make them mapCommonOptionsToAnthropic<TProviderOptions>(options:
TextOptions<TProviderOptions>) and
processAnthropicStream<TProviderOptions>(options: TextOptions<TProviderOptions>,
...) ) or alternatively widen the parameter to TextOptions<Record<string, any>>;
then update all internal references and call sites to use the new
generic/widened signature so narrow per-model intersections (e.g.,
AnthropicContainerOptions & AnthropicThinkingOptions) are accepted without
relying on fragile structural compatibility.

In `@packages/typescript/ai-groq/src/adapters/text.ts`:
- Line 42: There are two declarations for GroqTextProviderOptions; remove the
duplication by turning the local alias into the single exported alias and
deleting the separate re-export: change the local declaration `type
GroqTextProviderOptions = ExternalTextProviderOptions` to `export type
GroqTextProviderOptions = ExternalTextProviderOptions` (ensure
ExternalTextProviderOptions is imported where needed), and remove the `export
type { ExternalTextProviderOptions as GroqTextProviderOptions }` re-export so
only the exported alias `GroqTextProviderOptions` remains.
🪄 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: 010e1fd9-31a6-4657-bc0a-3ce99fdf8650

📥 Commits

Reviewing files that changed from the base of the PR and between 6e9919c and 416d8b0.

📒 Files selected for processing (15)
  • docs/adapters/gemini.md
  • docs/adapters/openai.md
  • docs/tools/provider-tools.md
  • packages/typescript/ai-anthropic/src/adapters/text.ts
  • packages/typescript/ai-anthropic/tests/tools-per-model-type-safety.test.ts
  • packages/typescript/ai-gemini/src/adapters/text.ts
  • packages/typescript/ai-gemini/tests/tools-per-model-type-safety.test.ts
  • packages/typescript/ai-grok/src/adapters/text.ts
  • packages/typescript/ai-groq/src/adapters/text.ts
  • packages/typescript/ai-openai/src/adapters/text.ts
  • packages/typescript/ai-openai/tests/tools-per-model-type-safety.test.ts
  • packages/typescript/ai-openrouter/src/tools/tool-converter.ts
  • packages/typescript/ai-openrouter/src/tools/web-search-tool.ts
  • packages/typescript/ai-openrouter/tests/tools-per-model-type-safety.test.ts
  • packages/typescript/ai/tests/tools-per-model-type-safety.test.ts
✅ Files skipped from review due to trivial changes (3)
  • docs/tools/provider-tools.md
  • docs/adapters/openai.md
  • packages/typescript/ai-openai/tests/tools-per-model-type-safety.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • docs/adapters/gemini.md
  • packages/typescript/ai-openrouter/tests/tools-per-model-type-safety.test.ts
  • packages/typescript/ai/tests/tools-per-model-type-safety.test.ts
  • packages/typescript/ai-grok/src/adapters/text.ts
  • packages/typescript/ai-openrouter/src/tools/tool-converter.ts
  • packages/typescript/ai-anthropic/tests/tools-per-model-type-safety.test.ts
  • packages/typescript/ai-openai/src/adapters/text.ts

Comment on lines +68 to +84
it('gemini-2.0-flash-lite rejects all provider tools', () => {
const adapter = geminiText('gemini-2.0-flash-lite')
typedTools(adapter, [
userTool,
// @ts-expect-error - gemini-2.0-flash-lite does not support code_execution
codeExecutionTool(),
// @ts-expect-error - gemini-2.0-flash-lite does not support computer_use
computerUseTool({}),
// @ts-expect-error - gemini-2.0-flash-lite does not support file_search
fileSearchTool({ fileSearchStoreNames: [] }),
// @ts-expect-error - gemini-2.0-flash-lite does not support google_maps
googleMapsTool(),
// @ts-expect-error - gemini-2.0-flash-lite does not support google_search
googleSearchTool(),
// @ts-expect-error - gemini-2.0-flash-lite does not support url_context
urlContextTool(),
])
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.

⚠️ Potential issue | 🟡 Minor

Include googleSearchRetrievalTool() in the “rejects all provider tools” case.

This test covers every imported Gemini provider tool except googleSearchRetrievalTool(), so one provider-tool kind can regress without this no-tools model catching it.

Proposed test coverage addition
       // `@ts-expect-error` - gemini-2.0-flash-lite does not support google_search
       googleSearchTool(),
+      // `@ts-expect-error` - gemini-2.0-flash-lite does not support google_search_retrieval
+      googleSearchRetrievalTool(),
       // `@ts-expect-error` - gemini-2.0-flash-lite does not support url_context
       urlContextTool(),
📝 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
it('gemini-2.0-flash-lite rejects all provider tools', () => {
const adapter = geminiText('gemini-2.0-flash-lite')
typedTools(adapter, [
userTool,
// @ts-expect-error - gemini-2.0-flash-lite does not support code_execution
codeExecutionTool(),
// @ts-expect-error - gemini-2.0-flash-lite does not support computer_use
computerUseTool({}),
// @ts-expect-error - gemini-2.0-flash-lite does not support file_search
fileSearchTool({ fileSearchStoreNames: [] }),
// @ts-expect-error - gemini-2.0-flash-lite does not support google_maps
googleMapsTool(),
// @ts-expect-error - gemini-2.0-flash-lite does not support google_search
googleSearchTool(),
// @ts-expect-error - gemini-2.0-flash-lite does not support url_context
urlContextTool(),
])
it('gemini-2.0-flash-lite rejects all provider tools', () => {
const adapter = geminiText('gemini-2.0-flash-lite')
typedTools(adapter, [
userTool,
// `@ts-expect-error` - gemini-2.0-flash-lite does not support code_execution
codeExecutionTool(),
// `@ts-expect-error` - gemini-2.0-flash-lite does not support computer_use
computerUseTool({}),
// `@ts-expect-error` - gemini-2.0-flash-lite does not support file_search
fileSearchTool({ fileSearchStoreNames: [] }),
// `@ts-expect-error` - gemini-2.0-flash-lite does not support google_maps
googleMapsTool(),
// `@ts-expect-error` - gemini-2.0-flash-lite does not support google_search
googleSearchTool(),
// `@ts-expect-error` - gemini-2.0-flash-lite does not support google_search_retrieval
googleSearchRetrievalTool(),
// `@ts-expect-error` - gemini-2.0-flash-lite does not support url_context
urlContextTool(),
])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-gemini/tests/tools-per-model-type-safety.test.ts`
around lines 68 - 84, Add the missing provider tool to the rejection test: in
the "gemini-2.0-flash-lite rejects all provider tools" case, include
googleSearchRetrievalTool() in the array passed to typedTools(adapter, [...])
with the same `@ts-expect-error` comment used for other unsupported provider tools
so the test will catch regressions for that provider; locate the test by the it
description and modify the array listing userTool, codeExecutionTool(),
computerUseTool(), fileSearchTool(...), googleMapsTool(), googleSearchTool(),
urlContextTool() to also contain googleSearchRetrievalTool().

Comment on lines +44 to +47
type ResolveToolCapabilities<TModel extends string> =
TModel extends keyof GroqChatModelToolCapabilitiesByName
? NonNullable<GroqChatModelToolCapabilitiesByName[TModel]>
: readonly []
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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify Groq model-meta declares empty supports.tools for all chat models
# and that GroqChatModelToolCapabilitiesByName is exported.
fd -t f 'model-meta.ts' packages/typescript/ai-groq | xargs -I{} rg -n -C2 'GroqChatModelToolCapabilitiesByName|supports\s*:\s*\{|tools\s*:\s*\[\s*\]' {}

# Look for a per-model type-safety test for Groq (parallel to other adapters).
fd -t f 'tools-per-model-type-safety' packages/typescript/ai-groq

Repository: TanStack/ai

Length of output: 3729


🏁 Script executed:

#!/bin/bash
# Get the full GroqChatModelToolCapabilitiesByName definition
rg -A 50 'export type GroqChatModelToolCapabilitiesByName' packages/typescript/ai-groq/src/

# Find all test files in the groq adapter package
fd -t f '\.test\.|\.spec\.' packages/typescript/ai-groq/src/

Repository: TanStack/ai

Length of output: 3150


🏁 Script executed:

#!/bin/bash
# List entire structure of ai-groq src directory
find packages/typescript/ai-groq/src -type f -name '*.ts' -o -name '*.tsx' | head -30

# Search for any references to GroqChatModelToolCapabilitiesByName across entire ai-groq
rg 'GroqChatModelToolCapabilitiesByName|ResolveToolCapabilities' packages/typescript/ai-groq/

# Look for test patterns in other adapter packages (like ai-fal for comparison)
find packages/typescript/ai-fal -type f \( -name '*.test.ts' -o -name '*.spec.ts' \) | head -10

Repository: TanStack/ai

Length of output: 1397


🏁 Script executed:

#!/bin/bash
# Check if there's a tests directory at the root level of ai-groq
find packages/typescript/ai-groq -type d -name 'tests' -o -type d -name '__tests__'

# List all files in ai-groq package root and direct subdirectories
ls -la packages/typescript/ai-groq/ 2>/dev/null | head -20

# Check if there are any test files at all in ai-groq (not just in src)
find packages/typescript/ai-groq -type f \( -name '*.test.ts' -o -name '*.spec.ts' -o -name '*.test.tsx' -o -name '*.spec.tsx' \)

# Also check the structure of ai-fal tests for comparison
ls -la packages/typescript/ai-fal/tests/ | head -20

Repository: TanStack/ai

Length of output: 1003


🏁 Script executed:

#!/bin/bash
# Examine the groq-adapter test file
cat -n packages/typescript/ai-groq/tests/groq-adapter.test.ts

# Also search for any tool capability or type safety assertions
rg -n 'tool|Tool|capability|Capability|type.*safety|branded|ProviderTool' packages/typescript/ai-groq/tests/groq-adapter.test.ts -i

Repository: TanStack/ai

Length of output: 20775


🏁 Script executed:

#!/bin/bash
# Examine the text.ts adapter around the ResolveToolCapabilities definition and its usage
cat -n packages/typescript/ai-groq/src/adapters/text.ts | head -100

# Search for where tools are actually constrained in the adapter type definition
rg -n 'toolCapabilities|TToolCapabilities|ResolveToolCapabilities' packages/typescript/ai-groq/src/adapters/text.ts -B 2 -A 2

Repository: TanStack/ai

Length of output: 4401


🏁 Script executed:

#!/bin/bash
# Find BaseTextAdapter definition to understand how TToolCapabilities is used
rg -n 'class BaseTextAdapter|interface BaseTextAdapter' --type ts -A 20

# Also search for how toolCapabilities constrains tool types in the base adapter
rg -n 'TToolCapabilities|toolCapabilities' packages/typescript/ai-core/src/adapters -A 2 -B 2 | head -100

# Check what the TextOptions type signature looks like
rg -n 'type TextOptions|interface TextOptions' --type ts -A 10 | head -80

Repository: TanStack/ai

Length of output: 2867


🏁 Script executed:

#!/bin/bash
# Get the complete ~types property definition in BaseTextAdapter
rg -n "declare '~types'" packages/typescript/ai/src/activities/chat/adapter.ts -A 15

# Also search for how tool capabilities are enforced in the adapter
rg -n 'toolCapabilities' packages/typescript/ai/src/activities/chat/adapter.ts -B 3 -A 3

# Check the TextAdapter interface definition
rg -n 'interface TextAdapter' packages/typescript/ai/src/types.ts -A 30

Repository: TanStack/ai

Length of output: 995


🏁 Script executed:

#!/bin/bash
# Get the complete TextAdapter interface definition
rg -n 'export interface TextAdapter' packages/typescript/ai/src/types.ts -A 50

# Also check if there's a ProviderTool type and how it's constrained
rg -n 'ProviderTool|type.*Tool' packages/typescript/ai/src/types.ts | head -30

# Look at how ai-fal handles tool type safety (per the learnings)
find packages/typescript/ai-fal/src -name '*.ts' -exec grep -l 'ProviderTool\|toolCapabilities' {} \;

Repository: TanStack/ai

Length of output: 118


🏁 Script executed:

#!/bin/bash
# Search more broadly for TextAdapter interface
rg -n 'interface TextAdapter' packages/typescript/ai/src/ -A 20

# Search for ProviderTool definition
rg -n 'type ProviderTool|interface ProviderTool|ProviderTool<' packages/typescript/ai/src/ -B 2 -A 5

# Check ai-fal's adapter to see pattern
cat -n packages/typescript/ai-fal/src/adapters/image.ts | head -100

Repository: TanStack/ai

Length of output: 8957


🏁 Script executed:

#!/bin/bash
# Confirm: when TToolCapabilities = readonly [], what does ProviderTool<string, K[number]> become?
# Search for any compile-time test or type assertion examples
rg -n 'ProviderTool.*\[\]|toolCapabilities.*\[\]|tools.*never' packages/typescript/ai/ --type ts | head -20

# Check if there are any .ts files that test type constraints (not runtime)
find packages/typescript -name '*.ts' -path '*/tests/*' -o -name '*.type.ts' | head -20

Repository: TanStack/ai

Length of output: 1513


🏁 Script executed:

#!/bin/bash
# Examine the anthropic tools-per-model-type-safety test as a reference pattern
cat -n packages/typescript/ai-anthropic/tests/tools-per-model-type-safety.test.ts

# Check if groq has the same test file
ls -la packages/typescript/ai-groq/tests/tools-per-model-type-safety.test.ts 2>&1

# Also look at the model-meta.test.ts in anthropic for comparison
cat -n packages/typescript/ai-anthropic/tests/model-meta.test.ts | head -60

Repository: TanStack/ai

Length of output: 8768


ResolveToolCapabilities default is correct.

Falling back to readonly [] for unknown model strings is the right default — it makes any ProviderTool<_, _> un-assignable for models without declared tool capabilities, while keeping unbranded user Tools freely usable. Matches the core TextAdapter['~types'].toolCapabilities contract.

All 13 current Groq models declare supports.tools: [] as const, so type enforcement prevents provider-branded tools from being used with Groq. This constraint is enforced at compile time via TypeScript's TToolCapabilities generic parameter, not through runtime validation.

Unlike the Anthropic adapter, there is no dedicated tools-per-model-type-safety.test.ts to verify this constraint with explicit @ts-expect-error assertions. Adding one would improve test coverage and align with other adapters, though the type safety itself is already in effect.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/adapters/text.ts` around lines 44 - 47, Add a
compile-time type-safety test that asserts provider-branded tools are not
assignable to Groq models: create a new tests file (e.g.,
tools-per-model-type-safety.test.ts) that imports ResolveToolCapabilities,
GroqChatModelToolCapabilitiesByName, ProviderTool, Tool, and
TextAdapter['~types'].toolCapabilities and adds `@ts-expect-error` assertions
showing that a ProviderTool with a branded TToolCapabilities cannot be assigned
to a Groq model (whose capabilities resolve to readonly []), while
plain/unbranded Tool remains assignable; ensure the test covers a representative
Groq model name and matches the pattern used in the Anthropic adapter's
type-safety test.

Comment on lines +45 to +54
if (
!metadata ||
metadata.__kind !== WEB_SEARCH_TOOL_KIND ||
metadata.type !== 'web_search' ||
typeof metadata.web_search !== 'object'
) {
throw new Error(
`convertWebSearchToolToAdapterFormat: tool "${tool.name}" is not a valid webSearchTool() output (missing branded metadata).`,
)
}
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.

⚠️ Potential issue | 🟡 Minor

Tighten web_search shape check against null/arrays.

typeof metadata.web_search !== 'object' accepts both null and arrays (since typeof null === 'object' and typeof [] === 'object'), so a malformed branded tool with metadata.web_search: null or [] would pass validation and produce a wire payload that OpenRouter will reject with a less helpful error. Given the validator exists specifically to give callers a clear failure before hitting the network, consider making it precise:

🛡️ Proposed fix
-  if (
-    !metadata ||
-    metadata.__kind !== WEB_SEARCH_TOOL_KIND ||
-    metadata.type !== 'web_search' ||
-    typeof metadata.web_search !== 'object'
-  ) {
+  if (
+    !metadata ||
+    metadata.__kind !== WEB_SEARCH_TOOL_KIND ||
+    metadata.type !== 'web_search' ||
+    metadata.web_search === null ||
+    typeof metadata.web_search !== 'object' ||
+    Array.isArray(metadata.web_search)
+  ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-openrouter/src/tools/web-search-tool.ts` around lines
45 - 54, The validation for metadata.web_search in
convertWebSearchToolToAdapterFormat is too loose (typeof allows null and
arrays); update the check to ensure metadata.web_search is a non-null plain
object and not an array by requiring metadata.web_search !== null &&
!Array.isArray(metadata.web_search) in addition to typeof metadata.web_search
=== 'object', so that malformed branded tools (null or []) fail fast with the
existing error for tool.name when metadata.__kind !== WEB_SEARCH_TOOL_KIND or
metadata.type !== 'web_search'.

import type { TextActivityOptions } from '@tanstack/ai/adapters'

// Helper — keeps each `it` body to one call (test-hygiene Rule 1).
function typedTools<A extends ReturnType<typeof geminiText>>(
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.

Note this breaks a lint convention

Copy link
Copy Markdown
Contributor

@tombeckenham tombeckenham left a comment

Choose a reason for hiding this comment

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

There's a few code rabbit comments that you should fix, but in general I'm happy to approve. I was looking at the phantom-brand cast as generally I don't love casting to unknown, but every other way to do it makes it more complicated. I'm happy with it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants