toolSearch

Search deferred tools and load their definitions on demand for direct calling or code mode.

Creates a tool that searches the surrounding generation's deferred tools, using keyword matching by default or a custom search callback. Use it with generateText, streamText, ToolLoopAgent, or WorkflowAgent from @ai-sdk/workflow. WorkflowAgent supports direct tool calling. The other APIs also support code mode configured with toolDiscovery: 'conversation'.

import { toolSearch } from 'ai';

const search = toolSearch();

See the Tool Search guide for direct-calling and code mode examples, including how code mode preserves the tool-definition cache.

Options

Pass an optional configuration object to control the result limit:

const search = toolSearch({ maxResults: 10 });

maxResults is the maximum number of matching tools returned and discovered per search. It defaults to 5 and must be a positive safe integer. Invalid values throw InvalidArgumentError when creating the search tool. The model-facing description reflects the configured limit.

The limit applies to both default keyword search and custom search callbacks, without changing their matching or ranking. Discovered tools accumulate across searches, so this is not a limit on the total number of tools loaded during a generation.

Pass a search callback to select and rank tools using your application's search logic. The callback can return synchronously or asynchronously:

const search = toolSearch({
  search: ({ query, tools }) => {
    const preferred = /\bgmail\b/i.test(query)
      ? ['gmail_list_messages', 'gmail_get_message']
      : [];
    return preferred.filter(name => tools.some(tool => tool.name === name));
  },
});

The callback has this signature:

search?: (options: {
  query: string;
  tools: Array<{ name: string; description?: string }>;
}) => string[] | PromiseLike<string[]>;

tools contains all eligible deferred tools, before keyword matching or ranking. Eligibility respects activeTools and caller routing. Descriptions are resolved using the current tool context and sandbox; schemas are not included.

Return tool names in ranked order. The SDK ignores unknown or ineligible names, removes duplicates while preserving order, and keeps the first maxResults valid names (five by default). Returned descriptions come from the SDK's candidate catalog. An empty array discovers no tools. Callback errors follow normal tool-execution error handling; the SDK does not fall back to keyword search.

Without a callback, toolSearch() uses the default keyword search described below.

Model Input

The model supplies the following input to the search tool:

{ "query": "weather forecast" }

query is a required, nonempty string. By default, search is local and case-insensitive, matching words in tool names and descriptions. Camel-case names are split into words. Name matches rank above description matches; equal scores preserve registration order. Function descriptions are resolved with the current tool context and sandbox. The default search uses no embedding service or additional model call. A custom callback can use either.

Output

{
  tools: [
    { name: 'getForecast', description: 'Get the weather forecast for a city.' },
  ],
}

Results contain at most maxResults matching tools (five by default), with their names and optional descriptions. They do not include schemas. No matches returns { tools: [] }. Every returned match is queued for discovery. Newly discovered tools can only be called on the next model step, after their definitions have been provided. A parallel call in the same response as the search cannot use a newly discovered tool. For code mode, finish the current execution and wait for the capability update.

Discovery Lifecycle

Before the next model step, the SDK makes discovered tools available through their configured callers:

  • Direct calling: the provider receives the updated tool definitions.
  • Code mode: the SDK appends a user message containing the updated capability catalog. The provider-visible code mode definition stays unchanged. Existing catalogs remain in the conversation; the latest catalog describes the complete currently available tool set.

Actual prompt-cache reuse depends on the provider. Code mode search still requires toolDiscovery: 'conversation'; description discovery and provider callers are not supported.

Discovered tools remain loaded for the rest of the generation, subject to activeTools. Search cannot discover tools excluded by activeTools. Discovery state is isolated between generation calls, including calls that reuse the same agent or tool instances.

Set a multi-step stopWhen condition with generateText and streamText so the model can search, use the discovered tools, and answer.