c56bef871b
Sync docs with Docusaurus / sync (push) Waiting to run
Tests / Check if changed (push) Waiting to run
Tests / format (push) Blocked by required conditions
Tests / check-imports (push) Blocked by required conditions
Tests / Unit / macos-latest (push) Blocked by required conditions
Tests / Unit / ubuntu-latest (push) Blocked by required conditions
Tests / Unit / windows-latest (push) Blocked by required conditions
Tests / mypy (push) Blocked by required conditions
Tests / Integration / ubuntu-latest (push) Blocked by required conditions
Tests / Integration / macos-latest (push) Blocked by required conditions
Tests / Integration / windows-latest (push) Blocked by required conditions
Tests / notify-slack-on-failure (push) Blocked by required conditions
Tests / Mark tests as completed (push) Blocked by required conditions
Docker image release / Build base image (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
1330 lines
44 KiB
Markdown
1330 lines
44 KiB
Markdown
---
|
||
title: "Tools"
|
||
id: tools-api
|
||
description: "Unified abstractions to represent tools across the framework."
|
||
slug: "/tools-api"
|
||
---
|
||
|
||
|
||
## component_tool
|
||
|
||
### ComponentTool
|
||
|
||
Bases: <code>Tool</code>
|
||
|
||
A Tool that wraps Haystack components, allowing them to be used as tools by LLMs.
|
||
|
||
ComponentTool automatically generates LLM-compatible tool schemas from component input sockets,
|
||
which are derived from the component's `run` method signature and type hints.
|
||
|
||
Key features:
|
||
|
||
- Automatic LLM tool calling schema generation from component input sockets
|
||
- Type conversion and validation for component inputs
|
||
- Support for types:
|
||
- Dataclasses
|
||
- Lists of dataclasses
|
||
- Basic types (str, int, float, bool, dict)
|
||
- Lists of basic types
|
||
- Automatic name generation from component class name
|
||
- Description extraction from component docstrings
|
||
|
||
To use ComponentTool, you first need a Haystack component - either an existing one or a new one you create.
|
||
You can create a ComponentTool from the component by passing the component to the ComponentTool constructor.
|
||
Below is an example of creating a ComponentTool from an existing SerperDevWebSearch component
|
||
from the `serperdev-haystack` integration package (`pip install serperdev-haystack`).
|
||
|
||
## Usage Example:
|
||
|
||
<!-- test-ignore -->
|
||
|
||
```python
|
||
from haystack import component
|
||
from haystack.tools import ComponentTool
|
||
from haystack.utils import Secret
|
||
from haystack.components.agents import Agent
|
||
from haystack.components.generators.chat import OpenAIChatGenerator
|
||
from haystack.dataclasses import ChatMessage
|
||
from haystack_integrations.components.websearch.serperdev import SerperDevWebSearch
|
||
|
||
# Create a SerperDev search component
|
||
search = SerperDevWebSearch(api_key=Secret.from_env_var("SERPERDEV_API_KEY"), top_k=3)
|
||
|
||
# Create a tool from the component
|
||
tool = ComponentTool(
|
||
component=search,
|
||
name="web_search", # Optional: defaults to "serper_dev_web_search"
|
||
description="Search the web for current information on any topic" # Optional: defaults to component docstring
|
||
)
|
||
|
||
# Create an Agent with an OpenAIChatGenerator and the tool
|
||
agent = Agent(chat_generator=OpenAIChatGenerator(), tools=[tool])
|
||
|
||
message = ChatMessage.from_user("Use the web search tool to find information about Nikola Tesla")
|
||
|
||
# Run the Agent
|
||
result = agent.run(messages=[message])
|
||
|
||
print(result)
|
||
```
|
||
|
||
#### __init__
|
||
|
||
```python
|
||
__init__(
|
||
component: Component,
|
||
name: str | None = None,
|
||
description: str | None = None,
|
||
parameters: dict[str, Any] | None = None,
|
||
*,
|
||
outputs_to_string: dict[str, str | Callable[[Any], str]] | None = None,
|
||
inputs_from_state: dict[str, str] | None = None,
|
||
outputs_to_state: dict[str, dict[str, str | Callable]] | None = None
|
||
) -> None
|
||
```
|
||
|
||
Create a Tool instance from a Haystack component.
|
||
|
||
**Parameters:**
|
||
|
||
- **component** (<code>Component</code>) – The Haystack component to wrap as a tool.
|
||
- **name** (<code>str | None</code>) – Optional name for the tool (defaults to snake_case of component class name).
|
||
- **description** (<code>str | None</code>) – Optional description (defaults to component's docstring).
|
||
- **parameters** (<code>dict\[str, Any\] | None</code>) – A JSON schema defining the parameters expected by the Tool.
|
||
Will fall back to the parameters defined in the component's run method signature if not provided.
|
||
- **outputs_to_string** (<code>dict\[str, str | Callable\\[[Any\], str\]\] | None</code>) – Optional dictionary defining how tool outputs should be converted into string(s) or results.
|
||
If not provided, the tool result is converted to a string using a default handler.
|
||
|
||
`outputs_to_string` supports two formats:
|
||
|
||
1. Single output format - use "source", "handler", and/or "raw_result" at the root level:
|
||
|
||
```python
|
||
{
|
||
"source": "docs", "handler": format_documents, "raw_result": False
|
||
}
|
||
```
|
||
|
||
- `source`: If provided, only the specified output key is sent to the handler.
|
||
- `handler`: A function that takes the tool output (or the extracted source value) and returns the
|
||
final result.
|
||
- `raw_result`: If `True`, the result is returned raw without string conversion, but applying the
|
||
`handler` if provided. This is intended for tools that return images. In this mode, the Tool
|
||
function or the `handler` function must return a list of `TextContent`/`ImageContent` objects to
|
||
ensure compatibility with Chat Generators.
|
||
|
||
1. Multiple output format - map keys to individual configurations:
|
||
|
||
```python
|
||
{
|
||
"formatted_docs": {"source": "docs", "handler": format_documents},
|
||
"summary": {"source": "summary_text", "handler": str.upper}
|
||
}
|
||
```
|
||
|
||
Each key maps to a dictionary that can contain "source" and/or "handler".
|
||
Note that `raw_result` is not supported in the multiple output format.
|
||
|
||
- **inputs_from_state** (<code>dict\[str, str\] | None</code>) – Optional dictionary mapping state keys to tool parameter names.
|
||
Example: `{"repository": "repo"}` maps state's "repository" to tool's "repo" parameter.
|
||
- **outputs_to_state** (<code>dict\[str, dict\[str, str | Callable\]\] | None</code>) – Optional dictionary defining how tool outputs map to keys within state as well as optional handlers.
|
||
If the source is provided only the specified output key is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"source": "docs", "handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
If the source is omitted the whole tool result is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
**Raises:**
|
||
|
||
- <code>TypeError</code> – If the object passed is not a Haystack Component instance.
|
||
- <code>ValueError</code> – If the component has already been added to a pipeline, or if schema generation fails.
|
||
|
||
#### warm_up
|
||
|
||
```python
|
||
warm_up() -> None
|
||
```
|
||
|
||
Prepare the ComponentTool for use.
|
||
|
||
#### to_dict
|
||
|
||
```python
|
||
to_dict() -> dict[str, Any]
|
||
```
|
||
|
||
Serializes the ComponentTool to a dictionary.
|
||
|
||
#### from_dict
|
||
|
||
```python
|
||
from_dict(data: dict[str, Any]) -> ComponentTool
|
||
```
|
||
|
||
Deserializes the ComponentTool from a dictionary.
|
||
|
||
## from_function
|
||
|
||
### create_tool_from_function
|
||
|
||
```python
|
||
create_tool_from_function(
|
||
function: Callable,
|
||
name: str | None = None,
|
||
description: str | None = None,
|
||
inputs_from_state: dict[str, str] | None = None,
|
||
outputs_to_state: dict[str, dict[str, Any]] | None = None,
|
||
outputs_to_string: dict[str, Any] | None = None,
|
||
) -> Tool
|
||
```
|
||
|
||
Create a Tool instance from a function.
|
||
|
||
Allows customizing the Tool name and description.
|
||
For simpler use cases, consider using the `@tool` decorator.
|
||
|
||
### Usage example
|
||
|
||
```python
|
||
from typing import Annotated, Literal
|
||
from haystack.tools import create_tool_from_function
|
||
|
||
def get_weather(
|
||
city: Annotated[str, "the city for which to get the weather"] = "Munich",
|
||
unit: Annotated[Literal["Celsius", "Fahrenheit"], "the unit for the temperature"] = "Celsius"):
|
||
'''A simple function to get the current weather for a location.'''
|
||
return f"Weather report for {city}: 20 {unit}, sunny"
|
||
|
||
tool = create_tool_from_function(get_weather)
|
||
|
||
print(tool)
|
||
# >> Tool(name='get_weather', description='A simple function to get the current weather for a location.',
|
||
# >> parameters={
|
||
# >> 'type': 'object',
|
||
# >> 'properties': {
|
||
# >> 'city': {'type': 'string', 'description': 'the city for which to get the weather', 'default': 'Munich'},
|
||
# >> 'unit': {
|
||
# >> 'type': 'string',
|
||
# >> 'enum': ['Celsius', 'Fahrenheit'],
|
||
# >> 'description': 'the unit for the temperature',
|
||
# >> 'default': 'Celsius',
|
||
# >> },
|
||
# >> }
|
||
# >> },
|
||
# >> function=<function get_weather at 0x7f7b3a8a9b80>)
|
||
```
|
||
|
||
**Parameters:**
|
||
|
||
- **function** (<code>Callable</code>) – The function to be converted into a Tool. May be either a regular function (assigned to the
|
||
resulting Tool's `function` field) or a coroutine function defined with `async def` (assigned
|
||
to `async_function`).
|
||
The function must include type hints for all parameters.
|
||
The function is expected to have basic python input types (str, int, float, bool, list, dict, tuple).
|
||
Other input types may work but are not guaranteed.
|
||
If a parameter is annotated using `typing.Annotated`, its metadata will be used as parameter description.
|
||
- **name** (<code>str | None</code>) – The name of the Tool. If not provided, the name of the function will be used.
|
||
- **description** (<code>str | None</code>) – The description of the Tool. If not provided, the docstring of the function will be used.
|
||
To intentionally leave the description empty, pass an empty string.
|
||
- **inputs_from_state** (<code>dict\[str, str\] | None</code>) – Optional dictionary mapping state keys to tool parameter names.
|
||
Example: `{"repository": "repo"}` maps state's "repository" to tool's "repo" parameter.
|
||
- **outputs_to_state** (<code>dict\[str, dict\[str, Any\]\] | None</code>) – Optional dictionary defining how tool outputs map to keys within state as well as optional handlers.
|
||
If the source is provided only the specified output key is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"source": "docs", "handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
If the source is omitted the whole tool result is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
- **outputs_to_string** (<code>dict\[str, Any\] | None</code>) – Optional dictionary defining how tool outputs should be converted into string(s) or results.
|
||
If not provided, the tool result is converted to a string using a default handler.
|
||
|
||
`outputs_to_string` supports two formats:
|
||
|
||
1. Single output format - use "source", "handler", and/or "raw_result" at the root level:
|
||
|
||
```python
|
||
{
|
||
"source": "docs", "handler": format_documents, "raw_result": False
|
||
}
|
||
```
|
||
|
||
- `source`: If provided, only the specified output key is sent to the handler. If not provided, the whole
|
||
tool result is sent to the handler.
|
||
- `handler`: A function that takes the tool output (or the extracted source value) and returns the
|
||
final result.
|
||
- `raw_result`: If `True`, the result is returned raw without string conversion, but applying the `handler`
|
||
if provided. This is intended for tools that return images. In this mode, the Tool function or the
|
||
`handler` must return a list of `TextContent`/`ImageContent` objects to ensure compatibility with Chat
|
||
Generators.
|
||
|
||
1. Multiple output format - map keys to individual configurations:
|
||
|
||
```python
|
||
{
|
||
"formatted_docs": {"source": "docs", "handler": format_documents},
|
||
"summary": {"source": "summary_text", "handler": str.upper}
|
||
}
|
||
```
|
||
|
||
Each key maps to a dictionary that can contain "source" and/or "handler".
|
||
Note that `raw_result` is not supported in the multiple output format.
|
||
|
||
**Returns:**
|
||
|
||
- <code>Tool</code> – The Tool created from the function.
|
||
|
||
**Raises:**
|
||
|
||
- <code>ValueError</code> – If any parameter of the function lacks a type hint.
|
||
- <code>SchemaGenerationError</code> – If there is an error generating the JSON schema for the Tool.
|
||
|
||
### tool
|
||
|
||
```python
|
||
tool(
|
||
function: Callable | None = None,
|
||
*,
|
||
name: str | None = None,
|
||
description: str | None = None,
|
||
inputs_from_state: dict[str, str] | None = None,
|
||
outputs_to_state: dict[str, dict[str, Any]] | None = None,
|
||
outputs_to_string: dict[str, Any] | None = None
|
||
) -> Tool | Callable[[Callable], Tool]
|
||
```
|
||
|
||
Decorator to convert a function into a Tool.
|
||
|
||
Can be used with or without parameters:
|
||
@tool # without parameters
|
||
def my_function(): ...
|
||
|
||
@tool(name="custom_name") # with parameters
|
||
def my_function(): ...
|
||
|
||
### Usage example
|
||
|
||
```python
|
||
from typing import Annotated, Literal
|
||
from haystack.tools import tool
|
||
|
||
@tool
|
||
def get_weather(
|
||
city: Annotated[str, "the city for which to get the weather"] = "Munich",
|
||
unit: Annotated[Literal["Celsius", "Fahrenheit"], "the unit for the temperature"] = "Celsius"):
|
||
'''A simple function to get the current weather for a location.'''
|
||
return f"Weather report for {city}: 20 {unit}, sunny"
|
||
|
||
print(get_weather)
|
||
# >> Tool(name='get_weather', description='A simple function to get the current weather for a location.',
|
||
# >> parameters={
|
||
# >> 'type': 'object',
|
||
# >> 'properties': {
|
||
# >> 'city': {'type': 'string', 'description': 'the city for which to get the weather', 'default': 'Munich'},
|
||
# >> 'unit': {
|
||
# >> 'type': 'string',
|
||
# >> 'enum': ['Celsius', 'Fahrenheit'],
|
||
# >> 'description': 'the unit for the temperature',
|
||
# >> 'default': 'Celsius',
|
||
# >> },
|
||
# >> }
|
||
# >> },
|
||
# >> function=<function get_weather at 0x7f7b3a8a9b80>)
|
||
```
|
||
|
||
**Parameters:**
|
||
|
||
- **function** (<code>Callable | None</code>) – The function to decorate (when used without parameters)
|
||
- **name** (<code>str | None</code>) – Optional custom name for the tool
|
||
- **description** (<code>str | None</code>) – Optional custom description
|
||
- **inputs_from_state** (<code>dict\[str, str\] | None</code>) – Optional dictionary mapping state keys to tool parameter names.
|
||
Example: `{"repository": "repo"}` maps state's "repository" to tool's "repo" parameter.
|
||
- **outputs_to_state** (<code>dict\[str, dict\[str, Any\]\] | None</code>) – Optional dictionary defining how tool outputs map to keys within state as well as optional handlers.
|
||
If the source is provided only the specified output key is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"source": "docs", "handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
If the source is omitted the whole tool result is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
- **outputs_to_string** (<code>dict\[str, Any\] | None</code>) – Optional dictionary defining how tool outputs should be converted into string(s) or results.
|
||
If not provided, the tool result is converted to a string using a default handler.
|
||
|
||
`outputs_to_string` supports two formats:
|
||
|
||
1. Single output format - use "source", "handler", and/or "raw_result" at the root level:
|
||
|
||
```python
|
||
{
|
||
"source": "docs", "handler": format_documents, "raw_result": False
|
||
}
|
||
```
|
||
|
||
- `source`: If provided, only the specified output key is sent to the handler. If not provided, the whole
|
||
tool result is sent to the handler.
|
||
- `handler`: A function that takes the tool output (or the extracted source value) and returns the
|
||
final result.
|
||
- `raw_result`: If `True`, the result is returned raw without string conversion, but applying the `handler`
|
||
if provided. This is intended for tools that return images. In this mode, the Tool function or the
|
||
`handler` must return a list of `TextContent`/`ImageContent` objects to ensure compatibility with Chat
|
||
Generators.
|
||
|
||
1. Multiple output format - map keys to individual configurations:
|
||
|
||
```python
|
||
{
|
||
"formatted_docs": {"source": "docs", "handler": format_documents},
|
||
"summary": {"source": "summary_text", "handler": str.upper}
|
||
}
|
||
```
|
||
|
||
Each key maps to a dictionary that can contain "source" and/or "handler".
|
||
Note that `raw_result` is not supported in the multiple output format.
|
||
|
||
**Returns:**
|
||
|
||
- <code>Tool | Callable\\[[Callable\], Tool\]</code> – Either a Tool instance or a decorator function that will create one
|
||
|
||
## pipeline_tool
|
||
|
||
### PipelineTool
|
||
|
||
Bases: <code>ComponentTool</code>
|
||
|
||
A Tool that wraps Haystack Pipelines, allowing them to be used as tools by LLMs.
|
||
|
||
PipelineTool automatically generates LLM-compatible tool schemas from pipeline input sockets,
|
||
which are derived from the underlying components in the pipeline.
|
||
|
||
Key features:
|
||
|
||
- Automatic LLM tool calling schema generation from pipeline inputs
|
||
- Description extraction of pipeline inputs based on the underlying component docstrings
|
||
|
||
To use PipelineTool, you first need a Haystack pipeline.
|
||
Below is an example of creating a PipelineTool
|
||
|
||
## Usage Example:
|
||
|
||
```python
|
||
from haystack import Document, Pipeline
|
||
from haystack.dataclasses import ChatMessage
|
||
from haystack.document_stores.in_memory import InMemoryDocumentStore
|
||
from haystack.components.embedders import OpenAITextEmbedder, OpenAIDocumentEmbedder
|
||
from haystack.components.generators.chat import OpenAIChatGenerator
|
||
from haystack.components.retrievers import InMemoryEmbeddingRetriever
|
||
from haystack.components.agents import Agent
|
||
from haystack.tools import PipelineTool
|
||
|
||
# Initialize a document store and add some documents
|
||
document_store = InMemoryDocumentStore()
|
||
document_embedder = OpenAIDocumentEmbedder()
|
||
documents = [
|
||
Document(content="Nikola Tesla was a Serbian-American inventor and electrical engineer."),
|
||
Document(
|
||
content="He is best known for his contributions to the design of the modern alternating current (AC) "
|
||
"electricity supply system."
|
||
),
|
||
]
|
||
docs_with_embeddings = document_embedder.run(documents=documents)["documents"]
|
||
document_store.write_documents(docs_with_embeddings)
|
||
|
||
# Build a simple retrieval pipeline
|
||
retrieval_pipeline = Pipeline()
|
||
retrieval_pipeline.add_component("embedder", OpenAITextEmbedder())
|
||
retrieval_pipeline.add_component("retriever", InMemoryEmbeddingRetriever(document_store=document_store))
|
||
|
||
retrieval_pipeline.connect("embedder.embedding", "retriever.query_embedding")
|
||
|
||
# Wrap the pipeline as a tool
|
||
retriever_tool = PipelineTool(
|
||
pipeline=retrieval_pipeline,
|
||
input_mapping={"query": ["embedder.text"]},
|
||
output_mapping={"retriever.documents": "documents"},
|
||
name="document_retriever",
|
||
description="For any questions about Nikola Tesla, always use this tool",
|
||
)
|
||
|
||
# Create an Agent with the tool
|
||
agent = Agent(
|
||
chat_generator=OpenAIChatGenerator(model="gpt-4.1-mini"),
|
||
tools=[retriever_tool]
|
||
)
|
||
|
||
# Let the Agent handle a query
|
||
result = agent.run([ChatMessage.from_user("Who was Nikola Tesla?")])
|
||
|
||
# Print result of the tool call
|
||
print("Tool Call Result:")
|
||
print(result["messages"][2].tool_call_result.result)
|
||
print("")
|
||
|
||
# Print answer
|
||
print("Answer:")
|
||
print(result["messages"][-1].text)
|
||
```
|
||
|
||
#### __init__
|
||
|
||
```python
|
||
__init__(
|
||
pipeline: Pipeline,
|
||
*,
|
||
name: str,
|
||
description: str,
|
||
input_mapping: dict[str, list[str]] | None = None,
|
||
output_mapping: dict[str, str] | None = None,
|
||
parameters: dict[str, Any] | None = None,
|
||
outputs_to_string: dict[str, str | Callable[[Any], str]] | None = None,
|
||
inputs_from_state: dict[str, str] | None = None,
|
||
outputs_to_state: dict[str, dict[str, str | Callable]] | None = None
|
||
) -> None
|
||
```
|
||
|
||
Create a Tool instance from a Haystack pipeline.
|
||
|
||
**Parameters:**
|
||
|
||
- **pipeline** (<code>Pipeline</code>) – The Haystack pipeline to wrap as a tool.
|
||
- **name** (<code>str</code>) – Name of the tool.
|
||
- **description** (<code>str</code>) – Description of the tool.
|
||
- **input_mapping** (<code>dict\[str, list\[str\]\] | None</code>) – A dictionary mapping component input names to pipeline input socket paths.
|
||
If not provided, a default input mapping will be created based on all pipeline inputs.
|
||
Example:
|
||
|
||
```python
|
||
input_mapping={
|
||
"query": ["retriever.query", "prompt_builder.query"],
|
||
}
|
||
```
|
||
|
||
- **output_mapping** (<code>dict\[str, str\] | None</code>) – A dictionary mapping pipeline output socket paths to component output names.
|
||
If not provided, a default output mapping will be created based on all pipeline outputs.
|
||
Example:
|
||
|
||
```python
|
||
output_mapping={
|
||
"retriever.documents": "documents",
|
||
"generator.replies": "replies",
|
||
}
|
||
```
|
||
|
||
- **parameters** (<code>dict\[str, Any\] | None</code>) – A JSON schema defining the parameters expected by the Tool.
|
||
Will fall back to the parameters defined in the component's run method signature if not provided.
|
||
- **outputs_to_string** (<code>dict\[str, str | Callable\\[[Any\], str\]\] | None</code>) – Optional dictionary defining how tool outputs should be converted into string(s) or results.
|
||
If not provided, the tool result is converted to a string using a default handler.
|
||
|
||
`outputs_to_string` supports two formats:
|
||
|
||
1. Single output format - use "source", "handler", and/or "raw_result" at the root level:
|
||
|
||
```python
|
||
{
|
||
"source": "docs", "handler": format_documents, "raw_result": False
|
||
}
|
||
```
|
||
|
||
- `source`: If provided, only the specified output key is sent to the handler.
|
||
- `handler`: A function that takes the tool output (or the extracted source value) and returns the
|
||
final result.
|
||
- `raw_result`: If `True`, the result is returned raw without string conversion, but applying the
|
||
`handler` if provided. This is intended for tools that return images. In this mode, the Tool
|
||
function or the `handler` function must return a list of `TextContent`/`ImageContent` objects to
|
||
ensure compatibility with Chat Generators.
|
||
|
||
1. Multiple output format - map keys to individual configurations:
|
||
|
||
```python
|
||
{
|
||
"formatted_docs": {"source": "docs", "handler": format_documents},
|
||
"summary": {"source": "summary_text", "handler": str.upper}
|
||
}
|
||
```
|
||
|
||
Each key maps to a dictionary that can contain "source" and/or "handler".
|
||
Note that `raw_result` is not supported in the multiple output format.
|
||
|
||
- **inputs_from_state** (<code>dict\[str, str\] | None</code>) – Optional dictionary mapping state keys to tool parameter names.
|
||
Example: `{"repository": "repo"}` maps state's "repository" to tool's "repo" parameter.
|
||
- **outputs_to_state** (<code>dict\[str, dict\[str, str | Callable\]\] | None</code>) – Optional dictionary defining how tool outputs map to keys within state as well as optional handlers.
|
||
If the source is provided only the specified output key is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"source": "docs", "handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
If the source is omitted the whole tool result is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
**Raises:**
|
||
|
||
- <code>ValueError</code> – If the provided pipeline is not a valid Haystack Pipeline instance.
|
||
|
||
#### to_dict
|
||
|
||
```python
|
||
to_dict() -> dict[str, Any]
|
||
```
|
||
|
||
Serializes the PipelineTool to a dictionary.
|
||
|
||
**Returns:**
|
||
|
||
- <code>dict\[str, Any\]</code> – The serialized dictionary representation of PipelineTool.
|
||
|
||
#### from_dict
|
||
|
||
```python
|
||
from_dict(data: dict[str, Any]) -> PipelineTool
|
||
```
|
||
|
||
Deserializes the PipelineTool from a dictionary.
|
||
|
||
**Parameters:**
|
||
|
||
- **data** (<code>dict\[str, Any\]</code>) – The dictionary representation of PipelineTool.
|
||
|
||
**Returns:**
|
||
|
||
- <code>PipelineTool</code> – The deserialized PipelineTool instance.
|
||
|
||
## searchable_toolset
|
||
|
||
### SearchableToolset
|
||
|
||
Bases: <code>Toolset</code>
|
||
|
||
Dynamic tool discovery from large catalogs using BM25 search.
|
||
|
||
This Toolset enables LLMs to discover and use tools from large catalogs through BM25-based search.
|
||
Instead of exposing all tools at once (which can overwhelm the LLM context), it provides a `search_tools` bootstrap
|
||
tool that allows the LLM to find and load specific tools as needed.
|
||
|
||
For very small catalogs (below `search_threshold`), acts as a simple passthrough exposing all tools directly
|
||
without any discovery mechanism.
|
||
|
||
### Usage Example
|
||
|
||
```python
|
||
from typing import Annotated
|
||
|
||
from haystack.components.agents import Agent
|
||
from haystack.components.generators.chat import OpenAIChatGenerator
|
||
from haystack.dataclasses import ChatMessage
|
||
from haystack.tools import SearchableToolset, tool
|
||
|
||
@tool
|
||
def get_weather(city: Annotated[str, "The city to get the weather for"]) -> str:
|
||
'''Get the current weather for a city.'''
|
||
return f"The weather in {city} is 22°C and sunny."
|
||
|
||
@tool
|
||
def search_web(query: Annotated[str, "The query to search the web for"]) -> str:
|
||
'''Search the web for a query.'''
|
||
return f"Top result for '{query}': ..."
|
||
|
||
@tool
|
||
def convert_currency(
|
||
amount: Annotated[float, "The amount to convert"],
|
||
to_currency: Annotated[str, "The currency to convert to, e.g. 'EUR'"],
|
||
) -> str:
|
||
'''Convert an amount in USD to another currency.'''
|
||
return f"{amount} USD is {amount * 0.9} {to_currency}"
|
||
|
||
# search_threshold=2 means a catalog of 2+ tools activates discovery: the agent only sees the
|
||
# `search_tools` tool and must search to load the others (set it higher for larger catalogs).
|
||
toolset = SearchableToolset(catalog=[get_weather, search_web, convert_currency], search_threshold=2)
|
||
|
||
agent = Agent(chat_generator=OpenAIChatGenerator(), tools=toolset)
|
||
|
||
# The agent is initially provided only with the search_tools tool and will use it to find relevant tools.
|
||
result = agent.run(messages=[ChatMessage.from_user("What's the weather in Milan?")])
|
||
print(result["last_message"].text)
|
||
```
|
||
|
||
#### __init__
|
||
|
||
```python
|
||
__init__(
|
||
catalog: ToolsType,
|
||
*,
|
||
top_k: int = 3,
|
||
search_threshold: int = 8,
|
||
search_tool_name: str = "search_tools",
|
||
search_tool_description: str | None = None,
|
||
search_tool_parameters_description: dict[str, str] | None = None
|
||
) -> None
|
||
```
|
||
|
||
Initialize the SearchableToolset.
|
||
|
||
**Parameters:**
|
||
|
||
- **catalog** (<code>ToolsType</code>) – Source of tools - a list of Tools, list of Toolsets, or a single Toolset.
|
||
- **top_k** (<code>int</code>) – Default number of results for search_tools.
|
||
- **search_threshold** (<code>int</code>) – Minimum catalog size to activate search. If catalog has fewer tools, acts as
|
||
passthrough (all tools visible). Default is 8.
|
||
- **search_tool_name** (<code>str</code>) – Custom name for the bootstrap search tool. Default is "search_tools".
|
||
- **search_tool_description** (<code>str | None</code>) – Custom description for the bootstrap search tool. If not provided, uses a
|
||
default description.
|
||
- **search_tool_parameters_description** (<code>dict\[str, str\] | None</code>) – Custom descriptions for the bootstrap search tool's parameters.
|
||
Keys must be a subset of `{"tool_keywords", "k"}`.
|
||
Example: `{"tool_keywords": "Keywords to find tools, e.g. 'email send'"}`
|
||
|
||
#### add
|
||
|
||
```python
|
||
add(tool: Tool | Toolset) -> None
|
||
```
|
||
|
||
Adding new tools after initialization is not supported for SearchableToolset.
|
||
|
||
#### warm_up
|
||
|
||
```python
|
||
warm_up() -> None
|
||
```
|
||
|
||
Prepare the toolset for use.
|
||
|
||
Warms up the catalog (so lazy toolsets like MCPToolset can connect) and flattens it. Above the passthrough
|
||
threshold, it also indexes the catalog and creates the search_tools bootstrap tool.
|
||
|
||
This method is idempotent: it only warms up the toolset the first time it is called.
|
||
|
||
**Raises:**
|
||
|
||
- <code>ValueError</code> – If the flattened catalog contains tools with duplicate names.
|
||
|
||
#### get_selectable_tools
|
||
|
||
```python
|
||
get_selectable_tools() -> list[Tool]
|
||
```
|
||
|
||
Return the full catalog of tools that can be selected by name.
|
||
|
||
Iteration only exposes the search tool plus already-discovered tools, but name-based selection can target
|
||
any tool in the catalog, so this returns the entire flattened catalog (warming up first if needed).
|
||
|
||
**Returns:**
|
||
|
||
- <code>list\[Tool\]</code> – The flattened catalog of tools.
|
||
|
||
#### clear
|
||
|
||
```python
|
||
clear() -> None
|
||
```
|
||
|
||
Clear all discovered tools.
|
||
|
||
This method allows resetting the toolset's discovered tools between agent runs when the same toolset instance
|
||
is reused. This can be useful for long-running applications to control memory usage or to start fresh searches.
|
||
|
||
#### spawn
|
||
|
||
```python
|
||
spawn() -> SearchableToolset
|
||
```
|
||
|
||
Return an isolated copy for a single run.
|
||
|
||
The copy shares the read-only catalog and BM25 index but gets fresh discovered tools and name selection,
|
||
plus a bootstrap search tool bound to the copy. This way concurrent runs sharing the same configured
|
||
SearchableToolset don't share discovered tools or collide on the active selection.
|
||
|
||
**Returns:**
|
||
|
||
- <code>SearchableToolset</code> – A run-scoped copy of this SearchableToolset.
|
||
|
||
#### to_dict
|
||
|
||
```python
|
||
to_dict() -> dict[str, Any]
|
||
```
|
||
|
||
Serialize the toolset to a dictionary.
|
||
|
||
**Returns:**
|
||
|
||
- <code>dict\[str, Any\]</code> – Dictionary representation of the toolset.
|
||
|
||
#### from_dict
|
||
|
||
```python
|
||
from_dict(data: dict[str, Any]) -> SearchableToolset
|
||
```
|
||
|
||
Deserialize a toolset from a dictionary.
|
||
|
||
**Parameters:**
|
||
|
||
- **data** (<code>dict\[str, Any\]</code>) – Dictionary representation of the toolset.
|
||
|
||
**Returns:**
|
||
|
||
- <code>SearchableToolset</code> – New SearchableToolset instance.
|
||
|
||
**Raises:**
|
||
|
||
- <code>TypeError</code> – If a serialized catalog entry is not a subclass of Tool or Toolset.
|
||
|
||
## skills/skill_toolset
|
||
|
||
### SkillToolset
|
||
|
||
Bases: <code>Toolset</code>
|
||
|
||
A Toolset that lets an Agent discover and read skills via progressive disclosure.
|
||
|
||
A skill is a directory (or equivalent storage unit) containing a `SKILL.md` file with YAML frontmatter
|
||
(`name` and `description`) and a markdown body of instructions. Skills may bundle additional files
|
||
(reference docs, examples, templates).
|
||
|
||
- On `warm_up`, the name and description of every discovered skill are baked into the `load_skill` tool
|
||
description so the model knows which skills exist without any system prompt injection.
|
||
- `load_skill` returns a skill's full instructions on demand, plus a manifest of its bundled files.
|
||
- `read_skill_file` reads a bundled file on demand.
|
||
|
||
### Usage example
|
||
|
||
```python
|
||
from haystack.components.agents import Agent
|
||
from haystack.components.generators.chat import OpenAIChatGenerator
|
||
from haystack.dataclasses import ChatMessage
|
||
from haystack.tools import SkillToolset
|
||
from haystack.skill_stores.file_system import FileSystemSkillStore
|
||
|
||
store = FileSystemSkillStore("skills/")
|
||
skills_toolset = SkillToolset(store)
|
||
agent = Agent(chat_generator=OpenAIChatGenerator(), tools=skills_toolset)
|
||
result = agent.run(messages=[ChatMessage.from_user("Fill in this PDF form for me.")])
|
||
```
|
||
|
||
Expected filesystem layout:
|
||
|
||
```
|
||
skills/
|
||
pdf-forms/
|
||
SKILL.md # frontmatter (name, description) + markdown instructions
|
||
reference/forms.md
|
||
```
|
||
|
||
The tool names `load_skill` and `read_skill_file` are fixed, so an `Agent` can use at most one
|
||
`SkillToolset`. To serve skills from multiple sources, back a single toolset with a custom store that
|
||
merges them.
|
||
|
||
#### __init__
|
||
|
||
```python
|
||
__init__(store: SkillStore) -> None
|
||
```
|
||
|
||
Initialize the SkillToolset.
|
||
|
||
Constructing the toolset does not read any skills. The store is queried for the available skills on
|
||
`warm_up()`, so stores that do I/O (reading a directory, connecting to a database) stay cheap to
|
||
construct.
|
||
|
||
The `load_skill` and `read_skill_file` tools are created right away, so the toolset can be used as a
|
||
collection (length, membership checks, iteration) immediately.
|
||
|
||
**Parameters:**
|
||
|
||
- **store** (<code>SkillStore</code>) – A `haystack.skill_stores.types.SkillStore` instance to back this toolset.
|
||
|
||
#### skills
|
||
|
||
```python
|
||
skills: dict[str, SkillInfo]
|
||
```
|
||
|
||
Mapping of skill name to its metadata. Triggers `warm_up()` on first access if not already warmed up.
|
||
|
||
#### warm_up
|
||
|
||
```python
|
||
warm_up() -> None
|
||
```
|
||
|
||
Discover the available skills from the store and bake the catalog into the `load_skill` description.
|
||
|
||
Only the description content is dynamic, so the (static) tools created in `__init__` are reused; this
|
||
refreshes `load_skill`'s description once the catalog is known. Idempotent: repeated calls after the
|
||
first are no-ops.
|
||
|
||
#### add
|
||
|
||
```python
|
||
add(tool: Tool | Toolset) -> None
|
||
```
|
||
|
||
Adding tools is not supported: a SkillToolset's tools are fixed and defined by its store.
|
||
|
||
#### to_dict
|
||
|
||
```python
|
||
to_dict() -> dict[str, Any]
|
||
```
|
||
|
||
Serialize the toolset to a dictionary.
|
||
|
||
**Returns:**
|
||
|
||
- <code>dict\[str, Any\]</code> – Dictionary representation of the toolset.
|
||
|
||
#### from_dict
|
||
|
||
```python
|
||
from_dict(data: dict[str, Any]) -> SkillToolset
|
||
```
|
||
|
||
Deserialize a toolset from a dictionary.
|
||
|
||
**Parameters:**
|
||
|
||
- **data** (<code>dict\[str, Any\]</code>) – Dictionary representation of the toolset, as produced by `to_dict`.
|
||
|
||
**Returns:**
|
||
|
||
- <code>SkillToolset</code> – A new SkillToolset instance.
|
||
|
||
## tool
|
||
|
||
### Tool
|
||
|
||
Data class representing a Tool that Language Models can prepare a call for.
|
||
|
||
Accurate definitions of the textual attributes such as `name` and `description`
|
||
are important for the Language Model to correctly prepare the call.
|
||
|
||
For resource-intensive operations like establishing connections to remote services or
|
||
loading models, override the `warm_up()` method. This method is called before the Tool
|
||
is used and should be idempotent, as it may be called multiple times during
|
||
pipeline/agent setup.
|
||
|
||
**Parameters:**
|
||
|
||
- **name** (<code>str</code>) – Name of the Tool.
|
||
- **description** (<code>str</code>) – Description of the Tool.
|
||
- **parameters** (<code>dict\[str, Any\]</code>) – A JSON schema defining the parameters expected by the Tool.
|
||
- **function** (<code>Callable | None</code>) – The synchronous function invoked by `Tool.invoke`. Must be a regular function — coroutine functions should
|
||
be passed to `async_function` instead. Either `function` or `async_function` (or both) must be set.
|
||
- **async_function** (<code>Callable | None</code>) – Optional coroutine function awaited by `Tool.invoke_async`. When only `async_function` is set, `invoke` raises
|
||
a `ToolInvocationError`. When only `function` is set, `invoke_async` falls back to running `function` in a
|
||
worker thread via `asyncio.to_thread`.
|
||
- **outputs_to_string** (<code>dict\[str, Any\] | None</code>) – Optional dictionary defining how tool outputs should be converted into string(s) or results.
|
||
If not provided, the tool result is converted to a string using a default handler.
|
||
|
||
`outputs_to_string` supports two formats:
|
||
|
||
1. Single output format - use "source", "handler", and/or "raw_result" at the root level:
|
||
|
||
```python
|
||
{
|
||
"source": "docs", "handler": format_documents, "raw_result": False
|
||
}
|
||
```
|
||
|
||
- `source`: If provided, only the specified output key is sent to the handler. If not provided, the whole
|
||
tool result is sent to the handler.
|
||
- `handler`: A function that takes the tool output (or the extracted source value) and returns the
|
||
final result.
|
||
- `raw_result`: If `True`, the result is returned raw without string conversion, but applying the `handler`
|
||
if provided. This is intended for tools that return images. In this mode, the Tool function or the
|
||
`handler` must return a list of `TextContent`/`ImageContent` objects to ensure compatibility with Chat
|
||
Generators.
|
||
|
||
1. Multiple output format - map keys to individual configurations:
|
||
|
||
```python
|
||
{
|
||
"formatted_docs": {"source": "docs", "handler": format_documents},
|
||
"summary": {"source": "summary_text", "handler": str.upper}
|
||
}
|
||
```
|
||
|
||
Each key maps to a dictionary that can contain "source" and/or "handler".
|
||
Note that `raw_result` is not supported in the multiple output format.
|
||
|
||
- **inputs_from_state** (<code>dict\[str, str\] | None</code>) – Optional dictionary mapping state keys to tool parameter names.
|
||
Example: `{"repository": "repo"}` maps state's "repository" to tool's "repo" parameter.
|
||
- **outputs_to_state** (<code>dict\[str, dict\[str, Any\]\] | None</code>) – Optional dictionary defining how tool outputs map to keys within state as well as optional handlers.
|
||
If the source is provided only the specified output key is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"source": "docs", "handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
If the source is omitted the whole tool result is sent to the handler.
|
||
Example:
|
||
|
||
```python
|
||
{
|
||
"documents": {"handler": custom_handler}
|
||
}
|
||
```
|
||
|
||
**Raises:**
|
||
|
||
- <code>ValueError</code> – If neither `function` nor `async_function` is provided, if `function` is a
|
||
coroutine function, if `async_function` is not a coroutine function, if `parameters` is not a
|
||
valid JSON schema, or if the `outputs_to_state`, `outputs_to_string`, or `inputs_from_state`
|
||
configurations are invalid.
|
||
- <code>TypeError</code> – If any configuration value in `outputs_to_state`, `outputs_to_string`, or
|
||
`inputs_from_state` has the wrong type.
|
||
|
||
#### tool_spec
|
||
|
||
```python
|
||
tool_spec: dict[str, Any]
|
||
```
|
||
|
||
Return the Tool specification to be used by the Language Model.
|
||
|
||
#### warm_up
|
||
|
||
```python
|
||
warm_up() -> None
|
||
```
|
||
|
||
Prepare the Tool for use.
|
||
|
||
Override this method to establish connections to remote services, load models,
|
||
or perform other resource-intensive initialization. This method should be idempotent,
|
||
as it may be called multiple times.
|
||
|
||
#### invoke
|
||
|
||
```python
|
||
invoke(**kwargs: Any) -> Any
|
||
```
|
||
|
||
Invoke the Tool synchronously with the provided keyword arguments.
|
||
|
||
**Raises:**
|
||
|
||
- <code>ToolInvocationError</code> – If the Tool has no sync `function`, or if the underlying call
|
||
raises an exception.
|
||
|
||
#### invoke_async
|
||
|
||
```python
|
||
invoke_async(**kwargs: Any) -> Any
|
||
```
|
||
|
||
Invoke the Tool asynchronously with the provided keyword arguments.
|
||
|
||
If `async_function` is set, it is awaited directly. Otherwise the sync `function` is dispatched to a worker
|
||
thread via `asyncio.to_thread`, which propagates the current context to the worker.
|
||
|
||
**Raises:**
|
||
|
||
- <code>ToolInvocationError</code> – If the underlying call raises an exception.
|
||
|
||
#### to_dict
|
||
|
||
```python
|
||
to_dict() -> dict[str, Any]
|
||
```
|
||
|
||
Serializes the Tool to a dictionary.
|
||
|
||
**Returns:**
|
||
|
||
- <code>dict\[str, Any\]</code> – Dictionary with serialized data.
|
||
|
||
#### from_dict
|
||
|
||
```python
|
||
from_dict(data: dict[str, Any]) -> Tool
|
||
```
|
||
|
||
Deserializes the Tool from a dictionary.
|
||
|
||
**Parameters:**
|
||
|
||
- **data** (<code>dict\[str, Any\]</code>) – Dictionary to deserialize from.
|
||
|
||
**Returns:**
|
||
|
||
- <code>Tool</code> – Deserialized Tool.
|
||
|
||
## toolset
|
||
|
||
### Toolset
|
||
|
||
A collection of related Tools that can be used and managed as a cohesive unit.
|
||
|
||
Toolset serves two main purposes:
|
||
|
||
1. Group related tools together:
|
||
Toolset allows you to organize related tools into a single collection, making it easier
|
||
to manage and use them as a unit in Haystack pipelines.
|
||
|
||
Example:
|
||
|
||
```python
|
||
from typing import Annotated
|
||
from haystack.tools import tool, Toolset
|
||
from haystack.components.agents import Agent
|
||
from haystack.components.generators.chat import OpenAIChatGenerator
|
||
|
||
# Create tools with the @tool decorator (the recommended way)
|
||
@tool
|
||
def add(a: Annotated[int, "first number"], b: Annotated[int, "second number"]) -> int:
|
||
'''Add two numbers.'''
|
||
return a + b
|
||
|
||
@tool
|
||
def subtract(a: Annotated[int, "first number"], b: Annotated[int, "second number"]) -> int:
|
||
'''Subtract b from a.'''
|
||
return a - b
|
||
|
||
# Create a toolset with the math tools
|
||
math_toolset = Toolset([add, subtract])
|
||
|
||
# Use the toolset with an Agent
|
||
agent = Agent(chat_generator=OpenAIChatGenerator(), tools=math_toolset)
|
||
```
|
||
|
||
2. Base class for dynamic tool loading:
|
||
By subclassing Toolset, you can create implementations that dynamically load tools from external sources like
|
||
OpenAPI URLs, MCP servers, or other resources.
|
||
|
||
Example:
|
||
|
||
```python
|
||
from typing import Annotated
|
||
from haystack.core.serialization import generate_qualified_class_name
|
||
from haystack.tools import tool, Toolset
|
||
from haystack.components.agents import Agent
|
||
from haystack.components.generators.chat import OpenAIChatGenerator
|
||
|
||
class CalculatorToolset(Toolset):
|
||
'''A toolset for calculator operations.'''
|
||
|
||
def __init__(self) -> None:
|
||
super().__init__(self._create_tools())
|
||
|
||
def _create_tools(self):
|
||
# These tools are defined statically for illustration purposes only.
|
||
# In a real-world scenario, you would dynamically load tools from an external source here.
|
||
@tool
|
||
def add(a: Annotated[int, "first number"], b: Annotated[int, "second number"]) -> int:
|
||
'''Add two numbers.'''
|
||
return a + b
|
||
|
||
@tool
|
||
def multiply(a: Annotated[int, "first number"], b: Annotated[int, "second number"]) -> int:
|
||
'''Multiply two numbers.'''
|
||
return a * b
|
||
|
||
return [add, multiply]
|
||
|
||
def to_dict(self):
|
||
return {
|
||
"type": generate_qualified_class_name(type(self)),
|
||
"data": {}, # no data to serialize as we define the tools dynamically
|
||
}
|
||
|
||
@classmethod
|
||
def from_dict(cls, data):
|
||
return cls() # Recreate the tools dynamically during deserialization
|
||
|
||
# Create the dynamic toolset and use it with an Agent
|
||
calculator_toolset = CalculatorToolset()
|
||
agent = Agent(chat_generator=OpenAIChatGenerator(), tools=calculator_toolset)
|
||
```
|
||
|
||
Toolset implements the collection interface (__iter__, __contains__, __len__, __getitem__), making it behave like
|
||
a list of Tools. This makes it compatible with components that expect iterable tools, such as Agent or Haystack
|
||
chat generators.
|
||
|
||
When implementing a custom Toolset subclass for dynamic tool loading:
|
||
|
||
- Perform the dynamic loading in the __init__ method
|
||
- Override to_dict() and from_dict() methods if your tools are defined dynamically
|
||
- Serialize endpoint descriptors rather than tool instances if your tools are loaded from external sources
|
||
|
||
#### get_selectable_tools
|
||
|
||
```python
|
||
get_selectable_tools() -> list[Tool]
|
||
```
|
||
|
||
Return the full set of tools that can be selected by name, ignoring any active name filter.
|
||
|
||
This differs from iteration, which yields only the tools currently exposed (and respects the name filter).
|
||
Override this when a Toolset's iteration does not surface every selectable tool, so name-based selection
|
||
can still target the full set.
|
||
|
||
Warms up the Toolset first if needed, so lazily loaded tools (those a Toolset fetches in `warm_up()`)
|
||
are available for selection.
|
||
|
||
**Returns:**
|
||
|
||
- <code>list\[Tool\]</code> – The list of tools available for name-based selection.
|
||
|
||
#### spawn
|
||
|
||
```python
|
||
spawn() -> Toolset
|
||
```
|
||
|
||
Return an isolated copy of this Toolset for a single run.
|
||
|
||
The copy shares this Toolset's read-only state (its tools and any warmed-up resources) but gets fresh
|
||
run-scoped state, so concurrent runs that share the same configured Toolset don't corrupt each other (for
|
||
example, one run's name selection leaking into another). Warms up first if needed so the copy shares the
|
||
warmed state. Subclasses with additional run-scoped state should override this.
|
||
|
||
**Returns:**
|
||
|
||
- <code>Toolset</code> – A run-scoped copy of this Toolset.
|
||
|
||
#### warm_up
|
||
|
||
```python
|
||
warm_up() -> None
|
||
```
|
||
|
||
Prepare the Toolset for use.
|
||
|
||
By default, this method iterates through and warms up all tools in the Toolset.
|
||
Subclasses can override this method to customize initialization behavior, such as:
|
||
|
||
- Setting up shared resources (database connections, HTTP sessions) instead of
|
||
warming individual tools
|
||
- Implementing custom initialization logic for dynamically loaded tools
|
||
- Controlling when and how tools are initialized
|
||
|
||
For example, a Toolset that manages tools from an external service (like MCPToolset)
|
||
might override this to initialize a shared connection rather than warming up
|
||
individual tools:
|
||
|
||
```python
|
||
class MCPToolset(Toolset):
|
||
def warm_up(self) -> None:
|
||
# Only warm up the shared MCP connection, not individual tools
|
||
self.mcp_connection = establish_connection(self.server_url)
|
||
```
|
||
|
||
This method is idempotent: it only warms up the tools the first time it is called.
|
||
Subclasses overriding it should preserve this contract (for example by guarding on
|
||
`self._is_warmed_up`).
|
||
|
||
#### add
|
||
|
||
```python
|
||
add(tool: Tool | Toolset) -> None
|
||
```
|
||
|
||
Add a new Tool or merge another Toolset.
|
||
|
||
If this Toolset has already been warmed up, the newly added Tool (or the tools of the
|
||
added Toolset) are warmed up immediately so they are ready to use without requiring a
|
||
second `warm_up()` call on the whole Toolset.
|
||
|
||
Note: adding a Toolset flattens it into its individual tools, so this is only recommended
|
||
for Toolsets that don't manage shared resources in their `warm_up()` (or `__init__`).
|
||
For example, combining with an `MCPToolset`, which owns a shared connection, is not
|
||
recommended: the connection's lifecycle would no longer be managed by the original
|
||
Toolset. In those cases combine Toolsets with `+` (which preserves each Toolset as a
|
||
unit via `_ToolsetWrapper`) instead.
|
||
|
||
**Parameters:**
|
||
|
||
- **tool** (<code>Tool | Toolset</code>) – A Tool instance or another Toolset to add
|
||
|
||
**Raises:**
|
||
|
||
- <code>ValueError</code> – If adding the tool would result in duplicate tool names
|
||
- <code>TypeError</code> – If the provided object is not a Tool or Toolset
|
||
|
||
#### to_dict
|
||
|
||
```python
|
||
to_dict() -> dict[str, Any]
|
||
```
|
||
|
||
Serialize the Toolset to a dictionary.
|
||
|
||
**Returns:**
|
||
|
||
- <code>dict\[str, Any\]</code> – A dictionary representation of the Toolset
|
||
|
||
Note for subclass implementers:
|
||
The default implementation is ideal for scenarios where Tool resolution is static. However, if your subclass
|
||
of Toolset dynamically resolves Tool instances from external sources—such as an MCP server, OpenAPI URL, or
|
||
a local OpenAPI specification—you should consider serializing the endpoint descriptor instead of the Tool
|
||
instances themselves. This strategy preserves the dynamic nature of your Toolset and minimizes the overhead
|
||
associated with serializing potentially large collections of Tool objects. Moreover, by serializing the
|
||
descriptor, you ensure that the deserialization process can accurately reconstruct the Tool instances, even
|
||
if they have been modified or removed since the last serialization. Failing to serialize the descriptor may
|
||
lead to issues where outdated or incorrect Tool configurations are loaded, potentially causing errors or
|
||
unexpected behavior.
|
||
|
||
#### from_dict
|
||
|
||
```python
|
||
from_dict(data: dict[str, Any]) -> Toolset
|
||
```
|
||
|
||
Deserialize a Toolset from a dictionary.
|
||
|
||
**Parameters:**
|
||
|
||
- **data** (<code>dict\[str, Any\]</code>) – Dictionary representation of the Toolset
|
||
|
||
**Returns:**
|
||
|
||
- <code>Toolset</code> – A new Toolset instance
|