Skip to content

Commit e27c116

Browse files
committed
Merge main
2 parents 346eebb + 5e596f1 commit e27c116

File tree

165 files changed

+4060
-1174
lines changed

Some content is hidden

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

165 files changed

+4060
-1174
lines changed

.github/workflows/after-ci.yml

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

4242
deploy-docs-preview:
4343
runs-on: ubuntu-latest
44-
if: github.event.workflow_run.event == 'pull_request'
44+
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.pull_requests[0] != null
4545
environment:
4646
name: deploy-docs-preview
4747

docs/ag-ui.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,8 @@ which allows for custom events and state updates.
213213
from ag_ui.core import CustomEvent, EventType, StateSnapshotEvent
214214
from pydantic import BaseModel
215215

216-
from pydantic_ai import Agent, RunContext
216+
from pydantic_ai import Agent, RunContext, ToolReturn
217217
from pydantic_ai.ag_ui import StateDeps
218-
from pydantic_ai.messages import ToolReturn
219218

220219

221220
class DocumentState(BaseModel):

docs/agents.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,15 @@ import asyncio
116116
from collections.abc import AsyncIterable
117117
from datetime import date
118118

119-
from pydantic_ai import Agent, RunContext
120-
from pydantic_ai.messages import (
119+
from pydantic_ai import (
120+
Agent,
121121
AgentStreamEvent,
122122
FinalResultEvent,
123123
FunctionToolCallEvent,
124124
FunctionToolResultEvent,
125125
PartDeltaEvent,
126126
PartStartEvent,
127+
RunContext,
127128
TextPartDelta,
128129
ThinkingPartDelta,
129130
ToolCallPartDelta,
@@ -392,13 +393,14 @@ import asyncio
392393
from dataclasses import dataclass
393394
from datetime import date
394395

395-
from pydantic_ai import Agent, RunContext
396-
from pydantic_ai.messages import (
396+
from pydantic_ai import (
397+
Agent,
397398
FinalResultEvent,
398399
FunctionToolCallEvent,
399400
FunctionToolResultEvent,
400401
PartDeltaEvent,
401402
PartStartEvent,
403+
RunContext,
402404
TextPartDelta,
403405
ThinkingPartDelta,
404406
ToolCallPartDelta,

docs/api/models/function.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Here's a minimal example:
1111

1212
```py {title="function_model_usage.py" call_name="test_my_agent" noqa="I001"}
1313
from pydantic_ai import Agent
14-
from pydantic_ai.messages import ModelMessage, ModelResponse, TextPart
14+
from pydantic_ai import ModelMessage, ModelResponse, TextPart
1515
from pydantic_ai.models.function import FunctionModel, AgentInfo
1616

1717
my_agent = Agent('openai:gpt-4o')

docs/builtin-tools.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Pydantic AI supports the following builtin tools:
99
- **[`WebSearchTool`][pydantic_ai.builtin_tools.WebSearchTool]**: Allows agents to search the web
1010
- **[`CodeExecutionTool`][pydantic_ai.builtin_tools.CodeExecutionTool]**: Enables agents to execute code in a secure environment
1111
- **[`UrlContextTool`][pydantic_ai.builtin_tools.UrlContextTool]**: Enables agents to pull URL contents into their context
12+
- **[`MemoryTool`][pydantic_ai.builtin_tools.MemoryTool]**: Enables agents to use memory
1213

1314
These tools are passed to the agent via the `builtin_tools` parameter and are executed by the model provider's infrastructure.
1415

@@ -160,6 +161,89 @@ result = agent.run_sync('What is this? https://ai.pydantic.dev')
160161
# > A Python agent framework for building Generative AI applications.
161162
```
162163

164+
## Memory Tool
165+
166+
The [`MemoryTool`][pydantic_ai.builtin_tools.MemoryTool] enables your agent to use memory.
167+
168+
### Provider Support
169+
170+
| Provider | Supported | Notes |
171+
|----------|-----------|-------|
172+
| Anthropic || Requires a tool named `memory` to be defined that implements [specific sub-commands](https://docs.claude.com/en/docs/agents-and-tools/tool-use/memory-tool#tool-commands). You can use a subclass of [`anthropic.lib.tools.BetaAbstractMemoryTool`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/lib/tools/_beta_builtin_memory_tool.py) as documented below. |
173+
| Google || |
174+
| OpenAI || |
175+
| Groq || |
176+
| Bedrock || |
177+
| Mistral || |
178+
| Cohere || |
179+
| HuggingFace || |
180+
181+
### Usage
182+
183+
The Anthropic SDK provides an abstract [`BetaAbstractMemoryTool`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/lib/tools/_beta_builtin_memory_tool.py) class that you can subclass to create your own memory storage solution (e.g., database, cloud storage, encrypted files, etc.). Their [`LocalFilesystemMemoryTool`](https://github.com/anthropics/anthropic-sdk-python/blob/main/examples/memory/basic.py) example can serve as a starting point.
184+
185+
The following example uses a subclass that hard-codes a specific memory. The bits specific to Pydantic AI are the `MemoryTool` built-in tool and the `memory` tool definition that forwards commands to the `call` method of the `BetaAbstractMemoryTool` subclass.
186+
187+
```py title="anthropic_memory.py"
188+
from typing import Any
189+
190+
from anthropic.lib.tools import BetaAbstractMemoryTool
191+
from anthropic.types.beta import (
192+
BetaMemoryTool20250818CreateCommand,
193+
BetaMemoryTool20250818DeleteCommand,
194+
BetaMemoryTool20250818InsertCommand,
195+
BetaMemoryTool20250818RenameCommand,
196+
BetaMemoryTool20250818StrReplaceCommand,
197+
BetaMemoryTool20250818ViewCommand,
198+
)
199+
200+
from pydantic_ai import Agent
201+
from pydantic_ai.builtin_tools import MemoryTool
202+
203+
204+
class FakeMemoryTool(BetaAbstractMemoryTool):
205+
def view(self, command: BetaMemoryTool20250818ViewCommand) -> str:
206+
return 'The user lives in Mexico City.'
207+
208+
def create(self, command: BetaMemoryTool20250818CreateCommand) -> str:
209+
return f'File created successfully at {command.path}'
210+
211+
def str_replace(self, command: BetaMemoryTool20250818StrReplaceCommand) -> str:
212+
return f'File {command.path} has been edited'
213+
214+
def insert(self, command: BetaMemoryTool20250818InsertCommand) -> str:
215+
return f'Text inserted at line {command.insert_line} in {command.path}'
216+
217+
def delete(self, command: BetaMemoryTool20250818DeleteCommand) -> str:
218+
return f'File deleted: {command.path}'
219+
220+
def rename(self, command: BetaMemoryTool20250818RenameCommand) -> str:
221+
return f'Renamed {command.old_path} to {command.new_path}'
222+
223+
def clear_all_memory(self) -> str:
224+
return 'All memory cleared'
225+
226+
fake_memory = FakeMemoryTool()
227+
228+
agent = Agent('anthropic:claude-sonnet-4-5', builtin_tools=[MemoryTool()])
229+
230+
231+
@agent.tool_plain
232+
def memory(**command: Any) -> Any:
233+
return fake_memory.call(command)
234+
235+
236+
result = agent.run_sync('Remember that I live in Mexico City')
237+
print(result.output)
238+
"""
239+
Got it! I've recorded that you live in Mexico City. I'll remember this for future reference.
240+
"""
241+
242+
result = agent.run_sync('Where do I live?')
243+
print(result.output)
244+
#> You live in Mexico City.
245+
```
246+
163247
## API Reference
164248

165249
For complete API documentation, see the [API Reference](api/builtin_tools.md).

docs/cli.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ _(You'll need to add `asyncio.run(main())` to run `main`)_
114114
Both `Agent.to_cli()` and `Agent.to_cli_sync()` support a `message_history` parameter, allowing you to continue an existing conversation or provide conversation context:
115115

116116
```python {title="agent_with_history.py" test="skip"}
117-
from pydantic_ai import Agent
118-
from pydantic_ai.messages import (
117+
from pydantic_ai import (
118+
Agent,
119119
ModelMessage,
120120
ModelRequest,
121121
ModelResponse,

docs/direct.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ The following functions are available:
1616
Here's a simple example demonstrating how to use the direct API to make a basic request:
1717

1818
```python title="direct_basic.py"
19+
from pydantic_ai import ModelRequest
1920
from pydantic_ai.direct import model_request_sync
20-
from pydantic_ai.messages import ModelRequest
2121

2222
# Make a synchronous request to the model
2323
model_response = model_request_sync(
@@ -44,9 +44,8 @@ from typing import Literal
4444

4545
from pydantic import BaseModel
4646

47-
from pydantic_ai import ToolDefinition
47+
from pydantic_ai import ModelRequest, ToolDefinition
4848
from pydantic_ai.direct import model_request
49-
from pydantic_ai.messages import ModelRequest
5049
from pydantic_ai.models import ModelRequestParameters
5150

5251

@@ -110,8 +109,8 @@ As with [agents][pydantic_ai.Agent], you can enable OpenTelemetry/Logfire instru
110109
```python {title="direct_instrumented.py" hl_lines="1 6 7"}
111110
import logfire
112111

112+
from pydantic_ai import ModelRequest
113113
from pydantic_ai.direct import model_request_sync
114-
from pydantic_ai.messages import ModelRequest
115114

116115
logfire.configure()
117116
logfire.instrument_pydantic_ai()
@@ -133,8 +132,8 @@ You can also enable OpenTelemetry on a per call basis:
133132
```python {title="direct_instrumented.py" hl_lines="1 6 12"}
134133
import logfire
135134

135+
from pydantic_ai import ModelRequest
136136
from pydantic_ai.direct import model_request_sync
137-
from pydantic_ai.messages import ModelRequest
138137

139138
logfire.configure()
140139

docs/durable_execution/dbos.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Other than that, any agent and toolset will just work!
123123

124124
### Agent Run Context and Dependencies
125125

126-
DBOS checkpoints workflow inputs/outputs and step outputs into a database using `jsonpickle`. This means you need to make sure [dependencies](../dependencies.md) object provided to [`DBOSAgent.run()`][pydantic_ai.durable_exec.dbos.DBOSAgent.run] or [`DBOSAgent.run_sync()`][pydantic_ai.durable_exec.dbos.DBOSAgent.run_sync], and tool outputs can be serialized using jsonpickle. You may also want to keep the inputs and outputs small (under \~2 MB). PostgreSQL and SQLite support up to 1 GB per field, but large objects may impact performance.
126+
DBOS checkpoints workflow inputs/outputs and step outputs into a database using [`pickle`](https://docs.python.org/3/library/pickle.html). This means you need to make sure [dependencies](../dependencies.md) object provided to [`DBOSAgent.run()`][pydantic_ai.durable_exec.dbos.DBOSAgent.run] or [`DBOSAgent.run_sync()`][pydantic_ai.durable_exec.dbos.DBOSAgent.run_sync], and tool outputs can be serialized using pickle. You may also want to keep the inputs and outputs small (under \~2 MB). PostgreSQL and SQLite support up to 1 GB per field, but large objects may impact performance.
127127

128128
### Streaming
129129

@@ -153,6 +153,6 @@ You can customize DBOS's retry policy using [step configuration](#step-configura
153153

154154
## Observability with Logfire
155155

156-
DBOS automatically generates OpenTelemetry spans for each workflow and step execution, and Pydantic AI emits spans for each agent run, model request, and tool invocation. You can send these spans to [Pydantic Logfire](../logfire.md) to get a full, end-to-end view of what's happening in your application.
156+
DBOS can be configured to generate OpenTelemetry spans for each workflow and step execution, and Pydantic AI emits spans for each agent run, model request, and tool invocation. You can send these spans to [Pydantic Logfire](../logfire.md) to get a full, end-to-end view of what's happening in your application.
157157

158158
For more information about DBOS logging and tracing, please see the [DBOS docs](https://docs.dbos.dev/python/tutorials/logging-and-tracing) for details.

docs/graph.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,7 @@ from dataclasses import dataclass, field
359359

360360
from pydantic import BaseModel, EmailStr
361361

362-
from pydantic_ai import Agent, format_as_xml
363-
from pydantic_ai.messages import ModelMessage
362+
from pydantic_ai import Agent, ModelMessage, format_as_xml
364363
from pydantic_graph import BaseNode, End, Graph, GraphRunContext
365364

366365

@@ -662,7 +661,7 @@ from pydantic_graph import (
662661
GraphRunContext,
663662
)
664663
from pydantic_ai import Agent, format_as_xml
665-
from pydantic_ai.messages import ModelMessage
664+
from pydantic_ai import ModelMessage
666665

667666
ask_agent = Agent('openai:gpt-4o', output_type=str, instrument=True)
668667

@@ -756,7 +755,7 @@ from pathlib import Path
756755

757756
from pydantic_graph import End
758757
from pydantic_graph.persistence.file import FileStatePersistence
759-
from pydantic_ai.messages import ModelMessage # noqa: F401
758+
from pydantic_ai import ModelMessage # noqa: F401
760759

761760
from ai_q_and_a_graph import Ask, question_graph, Evaluate, QuestionState, Answer
762761

docs/mcp/client.md

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pip/uv-add "pydantic-ai-slim[mcp]"
1313

1414
## Usage
1515

16-
Pydantic AI comes with two ways to connect to MCP servers:
16+
Pydantic AI comes with three ways to connect to MCP servers:
1717

1818
- [`MCPServerStreamableHTTP`][pydantic_ai.mcp.MCPServerStreamableHTTP] which connects to an MCP server using the [Streamable HTTP](https://modelcontextprotocol.io/introduction#streamable-http) transport
1919
- [`MCPServerSSE`][pydantic_ai.mcp.MCPServerSSE] which connects to an MCP server using the [HTTP SSE](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) transport
@@ -72,14 +72,14 @@ _(This example is complete, it can be run "as is" — you'll need to add `asynci
7272

7373
**What's happening here?**
7474

75-
- The model is receiving the prompt "how many days between 2000-01-01 and 2025-03-18?"
76-
- The model decides "Oh, I've got this `run_python_code` tool, that will be a good way to answer this question", and writes some python code to calculate the answer.
75+
- The model receives the prompt "What is 7 plus 5?"
76+
- The model decides "Oh, I've got this `add` tool, that will be a good way to answer this question"
7777
- The model returns a tool call
78-
- Pydantic AI sends the tool call to the MCP server using the SSE transport
79-
- The model is called again with the return value of running the code
78+
- Pydantic AI sends the tool call to the MCP server using the Streamable HTTP transport
79+
- The model is called again with the return value of running the `add` tool (12)
8080
- The model returns the final answer
8181

82-
You can visualise this clearly, and even see the code that's run by adding three lines of code to instrument the example with [logfire](https://logfire.pydantic.dev/docs):
82+
You can visualise this clearly, and even see the tool call, by adding three lines of code to instrument the example with [logfire](https://logfire.pydantic.dev/docs):
8383

8484
```python {title="mcp_sse_client_logfire.py" test="skip"}
8585
import logfire
@@ -88,10 +88,6 @@ logfire.configure()
8888
logfire.instrument_pydantic_ai()
8989
```
9090

91-
Will display as follows:
92-
93-
![Logfire run python code](../img/logfire-run-python-code.png)
94-
9591
### SSE Client
9692

9793
[`MCPServerSSE`][pydantic_ai.mcp.MCPServerSSE] connects over HTTP using the [HTTP + Server Sent Events transport](https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse) to a server.
@@ -216,10 +212,10 @@ async def main():
216212

217213
_(This example is complete, it can be run "as is" — you'll need to add `asyncio.run(main())` to run `main`)_
218214

219-
## Tool call customisation
215+
## Tool call customization
220216

221217
The MCP servers provide the ability to set a `process_tool_call` which allows
222-
the customisation of tool call requests and their responses.
218+
the customization of tool call requests and their responses.
223219

224220
A common use case for this is to inject metadata to the requests which the server
225221
call needs:

0 commit comments

Comments
 (0)