Skip to content

Commit 8c9ad90

Browse files
committed
Merge branch 'main' into dmontagu/new-graph-api
2 parents a73c781 + bfcccba commit 8c9ad90

File tree

115 files changed

+26811
-5847
lines changed

Some content is hidden

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

115 files changed

+26811
-5847
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ node_modules/
2020
.coverage*
2121
/test_tmp/
2222
.mcp.json
23+
.claude/

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Integrates the [Model Context Protocol](https://ai.pydantic.dev/mcp/client), [Ag
5757
Easily lets you flag that certain tool calls [require approval](https://ai.pydantic.dev/deferred-tools#human-in-the-loop-tool-approval) before they can proceed, possibly depending on tool call arguments, conversation history, or user preferences.
5858

5959
8. **Durable Execution**:
60-
Enables you to build [durable agents](https://ai.pydantic.dev/temporal) that can preserve their progress across transient API failures and application errors or restarts, and handle long-running, asynchronous, and human-in-the-loop workflows with production-grade reliability.
60+
Enables you to build [durable agents](https://ai.pydantic.dev/durable_execution/overview/) that can preserve their progress across transient API failures and application errors or restarts, and handle long-running, asynchronous, and human-in-the-loop workflows with production-grade reliability.
6161

6262
9. **Streamed Outputs**:
6363
Provides the ability to [stream](https://ai.pydantic.dev/output#streamed-results) structured output continuously, with immediate validation, ensuring real time access to generated data.

docs/ag-ui.md

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -204,18 +204,18 @@ user experiences with frontend user interfaces.
204204

205205
### Events
206206

207-
Pydantic AI tools can send
208-
[AG-UI events](https://docs.ag-ui.com/concepts/events) simply by defining a tool
209-
which returns a (subclass of)
210-
[`BaseEvent`](https://docs.ag-ui.com/sdk/python/core/events#baseevent), which allows
211-
for custom events and state updates.
207+
Pydantic AI tools can send [AG-UI events](https://docs.ag-ui.com/concepts/events) simply by returning a
208+
[`ToolReturn`](tools-advanced.md#advanced-tool-returns) object with a
209+
[`BaseEvent`](https://docs.ag-ui.com/sdk/python/core/events#baseevent) (or a list of events) as `metadata`,
210+
which allows for custom events and state updates.
212211

213212
```python {title="ag_ui_tool_events.py"}
214213
from ag_ui.core import CustomEvent, EventType, StateSnapshotEvent
215214
from pydantic import BaseModel
216215

217216
from pydantic_ai import Agent, RunContext
218217
from pydantic_ai.ag_ui import StateDeps
218+
from pydantic_ai.messages import ToolReturn
219219

220220

221221
class DocumentState(BaseModel):
@@ -233,27 +233,35 @@ app = agent.to_ag_ui(deps=StateDeps(DocumentState()))
233233

234234

235235
@agent.tool
236-
async def update_state(ctx: RunContext[StateDeps[DocumentState]]) -> StateSnapshotEvent:
237-
return StateSnapshotEvent(
238-
type=EventType.STATE_SNAPSHOT,
239-
snapshot=ctx.deps.state,
236+
async def update_state(ctx: RunContext[StateDeps[DocumentState]]) -> ToolReturn:
237+
return ToolReturn(
238+
return_value='State updated',
239+
metadata=[
240+
StateSnapshotEvent(
241+
type=EventType.STATE_SNAPSHOT,
242+
snapshot=ctx.deps.state,
243+
),
244+
],
240245
)
241246

242247

243248
@agent.tool_plain
244-
async def custom_events() -> list[CustomEvent]:
245-
return [
246-
CustomEvent(
247-
type=EventType.CUSTOM,
248-
name='count',
249-
value=1,
250-
),
251-
CustomEvent(
252-
type=EventType.CUSTOM,
253-
name='count',
254-
value=2,
255-
),
256-
]
249+
async def custom_events() -> ToolReturn:
250+
return ToolReturn(
251+
return_value='Count events sent',
252+
metadata=[
253+
CustomEvent(
254+
type=EventType.CUSTOM,
255+
name='count',
256+
value=1,
257+
),
258+
CustomEvent(
259+
type=EventType.CUSTOM,
260+
name='count',
261+
value=2,
262+
),
263+
]
264+
)
257265
```
258266

259267
Since `app` is an ASGI application, it can be used with any ASGI server:

docs/agents.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,6 @@ async def main():
280280
[
281281
UserPromptNode(
282282
user_prompt='What is the capital of France?',
283-
instructions=None,
284283
instructions_functions=[],
285284
system_prompts=(),
286285
system_prompt_functions=[],
@@ -343,7 +342,6 @@ async def main():
343342
[
344343
UserPromptNode(
345344
user_prompt='What is the capital of France?',
346-
instructions=None,
347345
instructions_functions=[],
348346
system_prompts=(),
349347
system_prompt_functions=[],

docs/builtin-tools.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,38 @@ making it ideal for queries that require up-to-date data.
2626

2727
| Provider | Supported | Notes |
2828
|----------|-----------|-------|
29-
| OpenAI || Full feature support |
29+
| OpenAI Responses || Full feature support. To include search results on the [`BuiltinToolReturnPart`][pydantic_ai.messages.BuiltinToolReturnPart], set the `openai_include_web_search_sources` setting to `True` on [`OpenAIResponsesModelSettings`][pydantic_ai.models.openai.OpenAIResponsesModelSettings]. |
3030
| Anthropic || Full feature support |
31+
| Google || No parameter support. No [`BuiltinToolCallPart`][pydantic_ai.messages.BuiltinToolCallPart] or [`BuiltinToolReturnPart`][pydantic_ai.messages.BuiltinToolReturnPart] is generated when streaming. Using built-in tools and user tools (including [output tools](output.md#tool-output)) at the same time is not supported; to use structured output, use [`PromptedOutput`](output.md#prompted-output) instead. |
3132
| Groq || Limited parameter support. To use web search capabilities with Groq, you need to use the [compound models](https://console.groq.com/docs/compound). |
32-
| Google | | No parameter support. Google does not support using built-in tools and user tools (including [output tools](output.md#tool-output)) at the same time. To use structured output, use [`PromptedOutput`](output.md#prompted-output) instead. |
33+
| OpenAI Chat Completions | | Not supported |
3334
| Bedrock || Not supported |
3435
| Mistral || Not supported |
3536
| Cohere || Not supported |
3637
| HuggingFace || Not supported |
3738

3839
### Usage
3940

40-
```py title="web_search_basic.py"
41+
```py title="web_search_anthropic.py"
4142
from pydantic_ai import Agent, WebSearchTool
4243

4344
agent = Agent('anthropic:claude-sonnet-4-0', builtin_tools=[WebSearchTool()])
4445

4546
result = agent.run_sync('Give me a sentence with the biggest news in AI this week.')
46-
# > Scientists have developed a universal AI detector that can identify deepfake videos.
47+
print(result.output)
48+
#> Scientists have developed a universal AI detector that can identify deepfake videos.
49+
```
50+
51+
With OpenAI, you must use their responses API to access the web search tool.
52+
53+
```py title="web_search_openai.py"
54+
from pydantic_ai import Agent, WebSearchTool
55+
56+
agent = Agent('openai-responses:gpt-4.1', builtin_tools=[WebSearchTool()])
4757

58+
result = agent.run_sync('Give me a sentence with the biggest news in AI this week.')
59+
print(result.output)
60+
#> Scientists have developed a universal AI detector that can identify deepfake videos.
4861
```
4962

5063
### Configuration Options
@@ -98,9 +111,9 @@ in a secure environment, making it perfect for computational tasks, data analysi
98111

99112
| Provider | Supported | Notes |
100113
|----------|-----------|-------|
101-
| OpenAI || |
114+
| OpenAI || To include outputs on the [`BuiltinToolReturnPart`][pydantic_ai.messages.BuiltinToolReturnPart], set the `openai_include_code_execution_outputs` setting to `True` on [`OpenAIResponsesModelSettings`][pydantic_ai.models.openai.OpenAIResponsesModelSettings]. |
102115
| Anthropic || |
103-
| Google || Google does not support using built-in tools and user tools (including [output tools](output.md#tool-output)) at the same time. To use structured output, use [`PromptedOutput`](output.md#prompted-output) instead. |
116+
| Google || Using built-in tools and user tools (including [output tools](output.md#tool-output)) at the same time is not supported; to use structured output, use [`PromptedOutput`](output.md#prompted-output) instead. |
104117
| Groq || |
105118
| Bedrock || |
106119
| Mistral || |
@@ -127,7 +140,7 @@ allowing it to pull up-to-date information from the web.
127140

128141
| Provider | Supported | Notes |
129142
|----------|-----------|-------|
130-
| Google || Google does not support using built-in tools and user tools (including [output tools](output.md#tool-output)) at the same time. To use structured output, use [`PromptedOutput`](output.md#prompted-output) instead. |
143+
| Google || No [`BuiltinToolCallPart`][pydantic_ai.messages.BuiltinToolCallPart] or [`BuiltinToolReturnPart`][pydantic_ai.messages.BuiltinToolReturnPart] is currently generated; please submit an issue if you need this. Using built-in tools and user tools (including [output tools](output.md#tool-output)) at the same time is not supported; to use structured output, use [`PromptedOutput`](output.md#prompted-output) instead. |
131144
| OpenAI || |
132145
| Anthropic || |
133146
| Groq || |

docs/deferred-tools.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,17 +132,21 @@ print(result.all_messages())
132132
),
133133
ModelRequest(
134134
parts=[
135-
ToolReturnPart(
136-
tool_name='delete_file',
137-
content='Deleting files is not allowed',
138-
tool_call_id='delete_file',
139-
timestamp=datetime.datetime(...),
140-
),
141135
ToolReturnPart(
142136
tool_name='update_file',
143137
content="File 'README.md' updated: 'Hello, world!'",
144138
tool_call_id='update_file_readme',
145139
timestamp=datetime.datetime(...),
140+
)
141+
]
142+
),
143+
ModelRequest(
144+
parts=[
145+
ToolReturnPart(
146+
tool_name='delete_file',
147+
content='Deleting files is not allowed',
148+
tool_call_id='delete_file',
149+
timestamp=datetime.datetime(...),
146150
),
147151
ToolReturnPart(
148152
tool_name='update_file',

docs/durable_execution/dbos.md

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -153,21 +153,6 @@ You can customize DBOS's retry policy using [step configuration](#step-configura
153153

154154
## Observability with Logfire
155155

156-
When using [Pydantic Logfire](../logfire.md), we **recommend disabling DBOS's built-in OpenTelemetry tracing**.
157-
DBOS automatically wraps workflow and step execution in spans, while Pydantic AI and Logfire already emit spans for the same function calls, model requests, and tool invocations. Without disabling DBOS tracing, these operations may appear twice in your trace tree.
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.
158157

159-
To disable DBOS traces and logs, you can set `disable_otlp=True` in `DBOSConfig`. For example:
160-
161-
162-
```python {title="dbos_no_traces.py" test="skip"}
163-
from dbos import DBOS, DBOSConfig
164-
165-
dbos_config: DBOSConfig = {
166-
'name': 'pydantic_dbos_agent',
167-
'system_database_url': 'sqlite:///dbostest.sqlite',
168-
'disable_otlp': True # (1)!
169-
}
170-
DBOS(config=dbos_config)
171-
```
172-
173-
1. If `True`, disables OpenTelemetry tracing and logging for DBOS. Default is `False`.
158+
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/durable_execution/temporal.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ As workflows and activities run in separate processes, any values passed between
172172

173173
To account for these limitations, tool functions and the [event stream handler](#streaming) running inside activities receive a limited version of the agent's [`RunContext`][pydantic_ai.tools.RunContext], and it's your responsibility to make sure that the [dependencies](../dependencies.md) object provided to [`TemporalAgent.run()`][pydantic_ai.durable_exec.temporal.TemporalAgent.run] can be serialized using Pydantic.
174174

175-
Specifically, only the `deps`, `retries`, `tool_call_id`, `tool_name`, `tool_call_approved`, `retry`, and `run_step` fields are available by default, and trying to access `model`, `usage`, `prompt`, `messages`, or `tracer` will raise an error.
175+
Specifically, only the `deps`, `retries`, `tool_call_id`, `tool_name`, `tool_call_approved`, `retry`, `max_retries` and `run_step` fields are available by default, and trying to access `model`, `usage`, `prompt`, `messages`, or `tracer` will raise an error.
176176
If you need one or more of these attributes to be available inside activities, you can create a [`TemporalRunContext`][pydantic_ai.durable_exec.temporal.TemporalRunContext] subclass with custom `serialize_run_context` and `deserialize_run_context` class methods and pass it to [`TemporalAgent`][pydantic_ai.durable_exec.temporal.TemporalAgent] as `run_context_type`.
177177

178178
### Streaming

0 commit comments

Comments
 (0)