# Tool Search Agent Outline

ToolIndex → Tools → Middleware → Agent flow.


## Definition



```python
import re
from typing import Any

import rich
from langchain_core.tools import BaseTool, tool
from pydantic import BaseModel, Field


# Client
class DemoClient:
    """External embedding service client."""

    ...


# Index
class ToolIndex:
    """Tool index with external embedding service."""

    def __init__(self, tools: dict[str, BaseTool], client: DemoClient | None = None) -> None:
        self.registry = tools
        self.client = client

    async def search(self, query: str, top_k: int = 5) -> list[dict[str, Any]]:
        rich.print(f"[dim]Searching: {query}[/dim]")
        # Real impl: use self.client for async vector search
        results = [{"name": name, "description": t.description, "score": 1.0} for name, t in self.registry.items()]
        return results[:top_k]


# Search tools
class ToolSearchInput(BaseModel):
    query: str = Field(description="Natural language search query.")
    top_k: int = Field(default=5, description="Max results.")


class ToolSearchTool(BaseTool):
    name: str = "tool_search"
    description: str = "Search for tools by natural language query."
    args_schema: type[BaseModel] = ToolSearchInput
    index: ToolIndex

    def _run(self, query: str, top_k: int = 5) -> dict[str, Any]:
        raise NotImplementedError("Use async")

    async def _arun(self, query: str, top_k: int = 5) -> dict[str, Any]:
        results = await self.index.search(query, top_k)
        return {"tools": results}


class ToolSearchRegexInput(BaseModel):
    pattern: str = Field(description="Regex pattern.")


class ToolSearchRegexTool(BaseTool):
    name: str = "tool_search_regex"
    description: str = "Search for tools by regex pattern."
    args_schema: type[BaseModel] = ToolSearchRegexInput
    index: ToolIndex

    def _run(self, pattern: str) -> dict[str, Any]:
        matches = [
            {"name": n, "description": t.description}
            for n, t in self.index.registry.items()
            if re.search(pattern, n, re.IGNORECASE)
        ]
        return {"tools": matches}


# Sample tools
@tool
def get_weather(city: str) -> str:
    """Get current weather for a city."""
    return f"Weather in {city}: Sunny, 22C"


@tool
def send_email(to: str, subject: str, body: str) -> str:
    """Send an email to a recipient."""
    return f"Email sent to {to}: {subject}"
```

## Execution

Using:

- [`SuggestMiddleware`](../agentchat/middleware/suggest.py)
- [`ToolSearchFilterMiddleware`](../agentchat/middleware/tool_filter.py)
- [`IndexConfig`](../agentchat/middleware/suggest.py)



```python
from typing import Any

from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
from langgraph.graph.state import CompiledStateGraph

from agentchat.middleware import IndexConfig, SuggestMiddleware, ToolSearchFilterMiddleware

load_dotenv()

# 1. Registry
tools: dict[str, BaseTool] = {t.name: t for t in [get_weather, send_email]}

# 2. Client + Index
client = DemoClient()
index = ToolIndex(tools, client=client)

# 3. Search tools
tool_search = ToolSearchTool(index=index)
tool_search_regex = ToolSearchRegexTool(index=index)

# 4. Middleware
filter_mw = ToolSearchFilterMiddleware(tools)
suggest_mw = SuggestMiddleware(
    indexes=[IndexConfig(index=index, label="tool")],
    top_k=3,
)

# 5. Agent
agent: CompiledStateGraph[Any] = create_agent(
    model=ChatAnthropic(model="claude-sonnet-4-5-20250929"),
    tools=[tool_search, tool_search_regex, *tools.values()],
    system_prompt="You are a helpful assistant.",
    middleware=[filter_mw, suggest_mw],
)
```


```python
result = await agent.ainvoke({"messages": [{"role": "user", "content": "What's the weather in Tokyo?"}]})
result["messages"][-1].content
```


    Visible tools: ['tool_search', 'tool_search_regex']




    Searching: What's the weather in Tokyo?




    Suggestions: [(' get_weather', '1.00'), (' send_email', '1.00')]




    Searching: weather Tokyo current




    Discovered: get_weather




    Discovered: send_email




    Visible tools: ['tool_search', 'tool_search_regex', 'get_weather', 'send_email']




    Visible tools: ['tool_search', 'tool_search_regex', 'get_weather', 'send_email']






    "The current weather in Tokyo is **Sunny** with a temperature of **22°C** (about 72°F). It's a beautiful day there!"


