> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tool Search

> Discover tools using natural language queries with semantic, local, or auto search modes

<Info>
  New to tool search? Start with [Tool Search 101](/agents/typescript/tool-search-101) for an overview of why, how, and when to use it.
</Info>

## Agent-Driven Search (Recommended)

The simplest way to use tool search: give your agent `tool_search` and `tool_execute`, and let it discover tools on demand.

```typescript theme={null}
import { StackOneToolSet } from '@stackone/ai';

const toolset = new StackOneToolSet();

// LLM receives only 2 tools: tool_search + tool_execute
const tools = toolset.getTools();
const openaiTools = tools.toOpenAI();
```

<Tip>
  Only 2 tools are sent to the LLM regardless of how many tools exist in your catalog. Token usage stays constant.
</Tip>

### Framework Examples

<CodeGroup>
  ```typescript Vercel AI SDK theme={null}
  import { openai } from '@ai-sdk/openai';
  import { StackOneToolSet } from '@stackone/ai';
  import { generateText, stepCountIs } from 'ai';

  // Uses STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environment
  const toolset = new StackOneToolSet({
    search: { method: 'semantic', topK: 3 },
  });

  // LLM receives only 2 tools: tool_search + tool_execute
  const tools = toolset.getTools();

  const { text } = await generateText({
    model: openai('gpt-5.4'),
    tools: await tools.toAISDK(),
    prompt: 'List my upcoming Calendly events for the next week.',
    stopWhen: stepCountIs(10),
  });

  console.log(text);
  ```

  ```typescript OpenAI theme={null}
  import OpenAI from 'openai';
  import { StackOneToolSet } from '@stackone/ai';

  // Uses STACKONE_API_KEY and STACKONE_ACCOUNT_ID from environment
  const toolset = new StackOneToolSet({
    search: { method: 'semantic', topK: 3 },
  });

  // LLM receives only 2 tools: tool_search + tool_execute
  const tools = toolset.getTools();
  const openaiTools = tools.toOpenAI();

  const client = new OpenAI();
  const messages = [
    {
      role: 'system' as const,
      content:
        'Use tool_search to find relevant tools, then tool_execute to run them. ' +
        'Read parameter schemas from tool_search results carefully.',
    },
    { role: 'user' as const, content: 'List my upcoming Calendly events for the next week.' },
  ];

  for (let i = 0; i < 10; i++) {
    const response = await client.chat.completions.create({
      model: 'gpt-5.4',
      messages,
      tools: openaiTools,
      tool_choice: 'auto',
    });

    const choice = response.choices[0];
    if (!choice.message.tool_calls?.length) {
      console.log(choice.message.content);
      break;
    }

    messages.push(choice.message);
    for (const toolCall of choice.message.tool_calls) {
      const tool = tools.getTool(toolCall.function.name);
      const result = tool ? await tool.execute(toolCall.function.arguments) : { error: 'Unknown tool' };
      messages.push({ role: 'tool', tool_call_id: toolCall.id, content: JSON.stringify(result) });
    }
  }
  ```
</CodeGroup>

## Manual Search

When you need to find tools yourself before passing them to an agent:

```typescript theme={null}
import { StackOneToolSet } from '@stackone/ai';

const toolset = new StackOneToolSet();
const tools = await toolset.searchTools('manage employee records');

// Use with any framework
const openAITools = tools.toOpenAI();
const aiSdkTools = await tools.toAISDK();
```

No configuration needed. Defaults to auto mode with sensible defaults.

<AccordionGroup>
  <Accordion title="Search modes (auto, semantic, local)">
    | Mode       | Behaviour                                                                                                                                               |
    | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `auto`     | Tries semantic API first, falls back to local search on failure. Recommended for production.                                                            |
    | `semantic` | Strict mode. Uses semantic API only, throws `SemanticSearchError` on failure.                                                                           |
    | `local`    | Hybrid BM25 + TF-IDF search entirely in-process (powered by [Orama](https://orama.com/)). No network call. Useful for offline or low-latency scenarios. |

    ```typescript theme={null}
    // Auto (default)
    const tools = await toolset.searchTools('manage employees', { search: 'auto' });

    // Semantic only
    const tools = await toolset.searchTools('manage employees', { search: 'semantic' });

    // Local only
    const tools = await toolset.searchTools('manage employees', { search: 'local' });
    ```
  </Accordion>

  <Accordion title="Constructor configuration">
    Set default search options at the constructor level. These apply to all search calls unless overridden per-call.

    ### SearchConfig Options

    | Option          | Type                              | Description                             |
    | --------------- | --------------------------------- | --------------------------------------- |
    | `method`        | `'auto' \| 'semantic' \| 'local'` | Search mode (default: `'auto'`)         |
    | `topK`          | `number`                          | Maximum number of tools to return       |
    | `minSimilarity` | `number`                          | Minimum relevance score threshold (0-1) |

    ```typescript theme={null}
    import { StackOneToolSet } from '@stackone/ai';

    // Custom search config
    const toolset = new StackOneToolSet({ search: { method: 'semantic', topK: 5 } });

    // Disable search
    const toolset = new StackOneToolSet({ search: null });

    // Default: search enabled with method: 'auto'
    const toolset = new StackOneToolSet();
    ```

    Per-call overrides take precedence over constructor defaults:

    ```typescript theme={null}
    // Constructor sets topK=5 for all search calls
    const toolset = new StackOneToolSet({ search: { method: 'semantic', topK: 5 } });

    // Uses constructor defaults: method='semantic', topK=5
    const tools = await toolset.searchTools('manage employees');

    // topK overridden to 10 for this call; method remains 'semantic'
    const tools = await toolset.searchTools('manage employees', { topK: 10 });
    ```
  </Accordion>

  <Accordion title="Parameters reference">
    | Parameter       | Type                              | Description                                       |
    | --------------- | --------------------------------- | ------------------------------------------------- |
    | `topK`          | `number`                          | Maximum number of tools to return                 |
    | `search`        | `'auto' \| 'semantic' \| 'local'` | Search mode (default: `'auto'`)                   |
    | `connector`     | `string`                          | Filter to a specific provider (e.g., `'workday'`) |
    | `minSimilarity` | `number`                          | Minimum relevance score threshold (0-1)           |
    | `accountIds`    | `string[]`                        | Override account IDs for this search              |
  </Accordion>
</AccordionGroup>

## Advanced Patterns

<AccordionGroup>
  <Accordion title="searchActionNames(), lightweight preview">
    Returns action names and similarity scores without fetching full tool definitions. Use it to inspect results before committing to a full fetch.

    ```typescript theme={null}
    const results = await toolset.searchActionNames('manage employees', {
      topK: 5,
    });

    for (const result of results) {
      console.log(`${result.id}: ${result.similarityScore}`);
    }
    ```

    <Tip>
      `searchActionNames()` works with just `STACKONE_API_KEY`, no account ID needed. When called without `accountIds`, results come from the full StackOne catalog.
    </Tip>
  </Accordion>

  <Accordion title="getSearchTool(), callable for custom agent loops">
    Returns a reusable `SearchTool` for agent loops where the LLM decides what to search for.

    ```typescript theme={null}
    const searchTool = toolset.getSearchTool({ search: 'auto' });

    // In an agent loop, search for tools as needed
    const queries = [
      'create a new employee',
      'list job candidates',
      'send a message to a channel',
    ];

    for (const query of queries) {
      const tools = await searchTool.search(query, { topK: 3 });
      const toolNames = tools.toArray().map((t) => t.name);
      console.log(`"${query}" -> ${toolNames.join(', ')}`);
    }
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

* [OpenAI Integration](/agents/typescript/frameworks/openai-integration)
* [Vercel AI SDK](/agents/typescript/frameworks/vercel-ai-sdk)
* [Tool Filtering](/agents/typescript/tool-filtering)
