Skip to content

Commit e9665fb

Browse files
committed
Merge branch 'main' into streaming-poc
2 parents 4b73815 + 34b221b commit e9665fb

814 files changed

Lines changed: 134524 additions & 10294 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci_metrics.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
send:
1717
runs-on: ubuntu-slim
1818
steps:
19-
- uses: int128/datadog-actions-metrics@c472230ac378d9f1dfb9f7ff28a9179d831c8cd4 # v1.163.0
19+
- uses: int128/datadog-actions-metrics@bb2bfb0ab9ebbf1cb1b66c891f3cd2528e21fede # v1.165.0
2020
with:
2121
datadog-api-key: ${{ secrets.DATADOG_API_KEY }}
2222
datadog-site: "datadoghq.eu"

.github/workflows/claude-code-review.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232

3333
- name: Run Claude Code Review
3434
id: claude-review
35-
uses: anthropics/claude-code-action@ef50f123a3a9be95b60040d042717517407c7256 # v1.0.110
35+
uses: anthropics/claude-code-action@476e359e6203e73dad705c8b322e333fabbd7416 # v1.0.119
3636
with:
3737
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_PR_REVIEWS_PUBLIC_REPOS }}
3838
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'

.github/workflows/claude.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353

5454
- name: Run Claude Code
5555
id: claude
56-
uses: anthropics/claude-code-action@ef50f123a3a9be95b60040d042717517407c7256 # v1.0.110
56+
uses: anthropics/claude-code-action@476e359e6203e73dad705c8b322e333fabbd7416 # v1.0.119
5757
with:
5858
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_PR_REVIEWS_PUBLIC_REPOS }}
5959
additional_permissions: |

.github/workflows/labeler.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ jobs:
1010
triage:
1111
runs-on: ubuntu-slim
1212
steps:
13-
- uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
13+
- uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
1414
with:
1515
repo-token: "${{ secrets.GITHUB_TOKEN }}"

.github/workflows/project.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
name: Add new issues to project for triage
1111
runs-on: ubuntu-slim
1212
steps:
13-
- uses: actions/add-to-project@244f685bbc3b7adfa8466e08b698b5577571133e # v1.0.2
13+
- uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2.0.0
1414
with:
1515
project-url: https://github.com/orgs/deepset-ai/projects/5
1616
github-token: ${{ secrets.GH_PROJECT_PAT }}

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ jobs:
268268
run: .github/utils/prepare_release_notification.sh
269269

270270
- name: Send release notification to Slack
271-
uses: slackapi/slack-github-action@03ea5433c137af7c0495bc0cad1af10403fc800c # v3.0.2
271+
uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3
272272
with:
273273
webhook: ${{ secrets.SLACK_WEBHOOK_URL_RELEASE }}
274274
webhook-type: incoming-webhook

VERSION.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.29.0-rc0
1+
2.30.0-rc0

docs-website/docs/concepts/agents.mdx

Lines changed: 53 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -18,86 +18,93 @@ An AI agent is a system that can:
1818
- Generate intelligent responses (using LLMs like OpenAI or Hugging Face models),
1919
- Perform actions (calling APIs, fetching live data, executing functions).
2020

21-
### Understanding AI Agents
21+
AI agents are autonomous systems that use large language models (LLMs) to make decisions and solve complex tasks.
22+
They interact with their environment using tools, memory, and reasoning.
23+
An AI agent is more than a chatbot — it actively plans, chooses the right tools, and executes tasks to achieve a goal.
24+
Unlike traditional software, it adapts to new information and refines its process as needed.
2225

23-
AI agents are autonomous systems that use large language models (LLMs) to make decisions and solve complex tasks. They interact with their environment using tools, memory, and reasoning.
24-
25-
### What Makes an AI Agent
26-
27-
An AI agent is more than a chatbot. It actively plans, chooses the right tools and executes tasks to achieve a goal. Unlike traditional software, it adapts to new information and refines its process as needed.
28-
29-
1. **LLM as the Brain**: The agent's core is an LLM, which understands context, processes natural language and serves as the central intelligence system.
26+
1. **LLM as the Brain**: The agent’s core is an LLM, which understands context, processes natural language and serves as the central intelligence system.
3027
2. **Tools for Interaction**: Agents connect to external tools, APIs, and databases to gather information and take action.
3128
3. **Memory for Context**: Short-term memory helps track conversations, while long-term memory stores knowledge for future interactions.
3229
4. **Reasoning and Planning**: Agents break down complex problems, come up with step-by-step action plans, and adapt based on new data and feedback.
3330

34-
### How AI Agents Work
31+
An AI agent starts with a prompt that defines its role and objectives.
32+
It decides when to use tools, gathers data, and refines its approach through loops of reasoning and action.
33+
For example, a customer service agent answers queries using a database — if it lacks an answer, it fetches real-time data, summarizes it, and responds.
34+
A coding assistant understands project requirements, suggests solutions, and writes code.
3535

36-
An AI agent starts with a prompt that defines its role and objectives. It decides when to use tools, gathers data, and refines its approach through loops of reasoning and action. It evaluates progress and adjusts its strategy to improve results.
36+
## Key Components
3737

38-
For example, a customer service agent answers queries using a database. If it lacks an answer, it fetches real-time data, summarizes it, and provides a response. A coding assistant understands project requirements, suggests solutions, and even writes code.
38+
### Agent Component
3939

40-
## Key Components
40+
Haystack has a built-in [Agent](../pipeline-components/agents-1/agent.mdx) component that manages the full tool-calling loop — it calls the LLM, invokes tools, updates state, and continues until a stopping condition is met.
41+
Key capabilities include:
4142

42-
### Agents
43+
- **State management**: Share typed data between tools, accumulate results across iterations, and surface them in the result dict using `state_schema`. See [State](../pipeline-components/agents-1/state.mdx).
44+
- **Streaming**: Stream token-by-token output with a `streaming_callback`.
45+
- **Human-in-the-loop**: Intercept tool calls for human review before execution. See [Human in the Loop](../pipeline-components/agents-1/human-in-the-loop.mdx).
46+
- **Multi-agent systems**: Wrap an `Agent` as a `ComponentTool` to build coordinator/specialist architectures. See [Multi-Agent Systems](./agents/multi-agent-systems.mdx).
47+
- **MCP server exposure**: Expose your agent as an MCP server using [Hayhooks](../development/hayhooks.mdx), making it callable from any MCP-compatible client such as Claude Desktop or Cursor.
48+
- **Multimodal inputs**: Pass images alongside text using `ImageContent` in `ChatMessage` content parts, or return `ImageContent` from tools for dynamic image analysis. Requires a vision-capable model such as `gpt-5` or `gemini-2.5-flash`. See [Multimodal Inputs](../pipeline-components/agents-1/agent.mdx#multimodal-inputs).
4349

44-
Haystack has a universal [Agent](../pipeline-components/agents-1/agent.mdx) component that interacts with chat-based LLMs and tools to solve complex queries. It requires a Chat Generator that supports tools to work and can be customizable according to your needs. Check out the [Agent](../pipeline-components/agents-1/agent.mdx) documentation, or the [example](#tool-calling-agent) below to see how it works.
50+
Check out the [Agent](../pipeline-components/agents-1/agent.mdx) documentation, or the [example](#tool-calling-agent) below to get started.
4551

46-
### Additional Components
52+
### State
4753

48-
You can build an AI agent in Haystack yourself, using the three main elements in a pipeline:
54+
[`State`](../pipeline-components/agents-1/state.mdx) is Haystack's built-in mechanism for sharing data between tools and accumulating results across multiple tool calls.
55+
You define a `state_schema` on the `Agent`, and any keys declared there are returned alongside `messages` and `last_message` in the agent's result dict.
4956

50-
- [Chat Generators](../pipeline-components/generators.mdx) to generate tool calls (with tool name and arguments) or assistant responses with an LLM,
51-
- [`Tool`](../tools/tool.mdx) class that allows the LLM to perform actions such as running a pipeline or calling an external API, connecting to the external world,
52-
- [`ToolInvoker`](../pipeline-components/tools/toolinvoker.mdx) component to execute tool calls generated by an LLM. It parses the LLM's tool-calling responses and invokes the appropriate tool with the correct arguments from the pipeline.
57+
### Tools
5358

54-
There are three ways of creating a tool in Haystack:
59+
Haystack provides several ways to create and manage tools:
5560

56-
- [`Tool`](../tools/tool.mdx) class – Creates a tool representation for a consistent tool-calling experience across all Generators. It allows for most customization, as you can define its own name and description.
57-
- [`ComponentTool`](../tools/componenttool.mdx) class – Wraps a Haystack component as a callable tool.
58-
- [`@tool`](../tools/tool.mdx#tool-decorator) decorator – Creates tools from Python functions and automatically uses their function name and docstring.
59-
- [Toolset](../tools/toolset.mdx) – A container for grouping multiple tools that can be passed directly to Agents or Generators.
61+
- [`Tool`](../tools/tool.mdx) class / [`@tool`](../tools/tool.mdx#tool-decorator) decorator – Define a tool from a Python function. The `@tool` decorator automatically uses the function's name and docstring; the `Tool` class gives full control over the name, description, and schema.
62+
- [`ComponentTool`](../tools/componenttool.mdx) – Wraps any Haystack component as a callable tool.
63+
- [`PipelineTool`](../tools/pipelinetool.mdx) – Wraps a full Haystack pipeline as a callable tool.
64+
- [`MCPTool`](../tools/mcptool.mdx) / [`MCPToolset`](../tools/mcptoolset.mdx) – Connects to Model Context Protocol (MCP) servers to load external tools.
65+
- [`Toolset`](../tools/toolset.mdx) – Groups multiple tools into a single unit to pass to an Agent or Generator.
66+
- [`SearchableToolset`](../tools/searchabletoolset.mdx) – Enables keyword-based tool discovery for large catalogs, so the LLM only sees relevant tools at each step.
6067

61-
## Example Agents
68+
## Example
6269

6370
### Tool-Calling Agent
6471

65-
You can create a similar tool-calling agent with the `Agent` component:
72+
Create a tool-calling agent with the `Agent` component. This example requires `OPENAI_API_KEY` and `SERPERDEV_API_KEY` to be set as environment variables:
73+
74+
```shell
75+
export OPENAI_API_KEY=<your-openai-key>
76+
export SERPERDEV_API_KEY=<your-serperdev-key>
77+
```
6678

6779
```python
6880
from haystack.components.agents import Agent
6981
from haystack.components.generators.chat import OpenAIChatGenerator
82+
from haystack.components.generators.utils import print_streaming_chunk
7083
from haystack.components.websearch import SerperDevWebSearch
71-
from haystack.dataclasses import Document, ChatMessage
72-
from haystack.tools.component_tool import ComponentTool
73-
74-
75-
## Create the web search component
76-
web_search = SerperDevWebSearch(top_k=3)
84+
from haystack.dataclasses import ChatMessage
85+
from haystack.tools import ComponentTool
7786

78-
## Create the ComponentTool with simpler parameters
87+
# Wrap the web search component as a tool
7988
web_tool = ComponentTool(
80-
component=web_search,
89+
component=SerperDevWebSearch(top_k=3),
8190
name="web_search",
8291
description="Search the web for current information like weather, news, or facts.",
8392
)
8493

85-
## Create the agent with the web tool
8694
tool_calling_agent = Agent(
87-
chat_generator=OpenAIChatGenerator(model="gpt-4o-mini"),
88-
system_prompt="""You're a helpful agent. When asked about current information like weather, news, or facts,
89-
use the web_search tool to find the information and then summarize the findings.
90-
When you get web search results, extract the relevant information and present it in a clear,
91-
concise manner.""",
95+
chat_generator=OpenAIChatGenerator(model="gpt-5.4-nano"),
96+
system_prompt=(
97+
"You're a helpful agent. When asked about current information like weather, news, or facts, "
98+
"use the web_search tool to find the information and then summarize the findings."
99+
),
92100
tools=[web_tool],
101+
streaming_callback=print_streaming_chunk,
93102
)
94103

95-
## Run the agent with the user message
96-
user_message = ChatMessage.from_user("How is the weather in Berlin?")
97-
result = tool_calling_agent.run(messages=[user_message])
98-
99-
## Print the result - using .text instead of .content
100-
print(result["messages"][-1].text)
104+
result = tool_calling_agent.run(
105+
messages=[ChatMessage.from_user("How is the weather in Berlin?")],
106+
)
107+
print(result["last_message"].text)
101108
```
102109

103110
Resulting in:
@@ -112,98 +119,3 @@ Resulting in:
112119

113120
For more details, you can check the full forecasts on [AccuWeather](https://www.accuweather.com/en/de/berlin/10178/current-weather/178087) or [Weather.com](https://weather.com/weather/today/l/5ca23443513a0fdc1d37ae2ffaf5586162c6fe592a66acc9320a0d0536be1bb9).
114121
```
115-
116-
### Pipeline With Tools
117-
118-
Here’s an example of how you would build a tool-calling agent with the help of `ToolInvoker`.
119-
120-
This is what’s happening in this code example:
121-
122-
1. `OpenAIChatGenerator` uses an LLM to analyze the user's message and determines whether to provide an assistant response or initiate a tool call.
123-
2. `ConditionalRouter` directs the output from the `OpenAIChatGenerator` to `there_are_tool_calls` branch if it’s a tool call or to `final_replies` to return to the user directly.
124-
3. `ToolInvoker` executes the tool call generated by the LLM. `ComponentTool` wraps the `SerperDevWebSearch` component that fetches real-time search results, making it accessible for `ToolInvoker` to execute it as a tool.
125-
4. After the tool provides its output, the `ToolInvoker` sends this information back to the `OpenAIChatGenerator`, along with the original user question stored by the `MessageCollector`.
126-
127-
```python
128-
from haystack import component, Pipeline
129-
from haystack.components.tools import ToolInvoker
130-
from haystack.components.generators.chat import OpenAIChatGenerator
131-
from haystack.components.routers import ConditionalRouter
132-
from haystack.components.websearch import SerperDevWebSearch
133-
from haystack.core.component.types import Variadic
134-
from haystack.dataclasses import ChatMessage
135-
from haystack.tools import ComponentTool
136-
137-
from typing import Any
138-
139-
140-
## helper component to temporarily store last user query before the tool call
141-
@component()
142-
class MessageCollector:
143-
def __init__(self):
144-
self._messages = []
145-
146-
@component.output_types(messages=list[ChatMessage])
147-
def run(self, messages: Variadic[list[ChatMessage]]) -> dict[str, Any]:
148-
self._messages.extend([msg for inner in messages for msg in inner])
149-
return {"messages": self._messages}
150-
151-
def clear(self):
152-
self._messages = []
153-
154-
155-
## Create a tool from a component
156-
web_tool = ComponentTool(component=SerperDevWebSearch(top_k=3))
157-
158-
## Define routing conditions
159-
routes = [
160-
{
161-
"condition": "{{replies[0].tool_calls | length > 0}}",
162-
"output": "{{replies}}",
163-
"output_name": "there_are_tool_calls",
164-
"output_type": list[ChatMessage],
165-
},
166-
{
167-
"condition": "{{replies[0].tool_calls | length == 0}}",
168-
"output": "{{replies}}",
169-
"output_name": "final_replies",
170-
"output_type": list[ChatMessage],
171-
},
172-
]
173-
174-
## Create the pipeline
175-
tool_agent = Pipeline()
176-
tool_agent.add_component("message_collector", MessageCollector())
177-
tool_agent.add_component(
178-
"generator",
179-
OpenAIChatGenerator(model="gpt-4o-mini", tools=[web_tool]),
180-
)
181-
tool_agent.add_component("router", ConditionalRouter(routes, unsafe=True))
182-
tool_agent.add_component("tool_invoker", ToolInvoker(tools=[web_tool]))
183-
184-
tool_agent.connect("generator.replies", "router")
185-
tool_agent.connect("router.there_are_tool_calls", "tool_invoker")
186-
tool_agent.connect("router.there_are_tool_calls", "message_collector")
187-
tool_agent.connect("tool_invoker.tool_messages", "message_collector")
188-
tool_agent.connect("message_collector", "generator.messages")
189-
190-
messages = [
191-
ChatMessage.from_system(
192-
"You're a helpful agent choosing the right tool when necessary",
193-
),
194-
ChatMessage.from_user("How is the weather in Berlin?"),
195-
]
196-
result = tool_agent.run({"messages": messages})
197-
198-
print(result["router"]["final_replies"][0].text)
199-
```
200-
201-
Resulting in:
202-
203-
```python
204-
>>> The current weather in Berlin is around 46°F (8°C) with cloudy conditions. The high for today is forecasted to reach 48°F (9°C) and the low is expected to be around 37°F (3°C). The humidity is quite high at 92%, and there is a light wind blowing at 4 mph.
205-
206-
For more detailed weather updates, you can check the following links:
207-
- [AccuWeather](https://www.accuweather.com/en/de/berlin/10178/weather-forecast/178087)
208-
- [Weather.com](https://weather.com/weather/today/l/5ca23443513a0fdc1d37ae2ffaf5586162c6fe592a66acc9320a0d0536be1bb9)
209-
```

0 commit comments

Comments
 (0)