TanStack / TanStack/ai

Provider-executed web search results are dropped on OpenAI and Gemini (forwarded on Anthropic)

Open
#1,328 0 comments 0 reactions 1 assignee View on GitHub

@tombeckenham is already working on this.

Since Sep 17, 2026.

has-pr waiting-on: maintainer
Dominant language
TypeScript
Stars
3.1k
Forks
331
Avg merge
1d 22h
Merged PRs (30d)
160

Description

Summary

A provider-executed web search reaches the consumer as a tool call on Anthropic only. On OpenAI and Gemini the adapters drop the search entirely, so an app cannot show what the model searched for, nor the pages it read.

@tanstack/ai-anthropic 0.18.5 does forward it (src/adapters/text.ts): a server tool yields TOOL_CALL_START with

metadata: {
  providerExecuted: true,
  anthropic: { serverToolType, resultBlockType, result }, // result = the raw web_search_result blocks: url, title, page_age
}

then TOOL_CALL_END with the parsed input. That is everything a UI needs. The other two adapters have the same data on the wire and never emit it.

OpenAI (@tanstack/ai-openai 0.22.5, @tanstack/openai-base 0.10.10)

OpenAIBaseResponsesTextAdapter.processStreamChunks maps function_call items only (src/adapters/responses-text.ts, the response.output_item.added / response.output_item.done branches check item.type === 'reasoning' and item.type === 'function_call'). Two event shapes fall through with no handler:

  • response.output_item.{added,done} where item.type === 'web_search_call' — the item carries action.queries and, when the request asks for include: ['web_search_call.action.sources'], action.sources: Array<{ type: 'url'; url: string }>.
  • response.output_text.annotation.added where the annotation is a url_citation{ url, title, start_index, end_index }. grep -n annotation src/adapters/responses-text.ts returns nothing.

So the search is invisible, and the citations (including the character positions of each citation in the answer) are lost.

A subclass can recover it today, but only by overriding processStreamChunks and re-declaring two module-private types (StreamedFunctionCallMetadata, LegacyReasoningDeltaEvent) by shape, since neither is exported.

Gemini (@tanstack/ai-gemini 0.29.1)

google_search is offered as a tool, but src/adapters/text.ts never reads candidates[].groundingMetadata (groundingChunks, groundingSupports, webSearchQueries) — zero occurrences in the file. Its processStreamChunks is private, so unlike OpenAI there is no subclass workaround at all.

Request

Forward provider-executed search results as tool-call metadata on OpenAI and Gemini, the way the Anthropic adapter already does. A provider-neutral key (for example metadata.sources: Array<{ url, title?, pageAge? }> alongside providerExecuted: true) would let a consumer render all three the same way; the raw provider blocks could stay beside it under the provider's own key.

On OpenAI that means emitting the web_search_call item as a TOOL_CALL_START/TOOL_CALL_END pair and joining the url_citation annotations (which carry the titles, and the positions) onto the sources by URL. Adding web_search_call.action.sources to include when a web search tool is present would make the sources available without the caller having to know about the flag.

Closest existing issue I found: #495 (user-executed OpenAI provider tools being dropped) — related in spirit, different path.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.