Skip to content

Commit 7b4ad0d

Browse files
committed
Docs
1 parent 3d628b8 commit 7b4ad0d

File tree

14 files changed

+138
-51
lines changed

14 files changed

+138
-51
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ Designed to give your IDE or AI coding agent as much context as possible for aut
5050
5. **Powerful Evals**:
5151
Enables you to systematically test and [evaluate](https://ai.pydantic.dev/evals) the performance and accuracy of the agentic systems you build, and monitor the performance over time in Pydantic Logfire.
5252

53-
6. **MCP, A2A, and AG-UI**:
54-
Integrates the [Model Context Protocol](https://ai.pydantic.dev/mcp/client), [Agent2Agent](https://ai.pydantic.dev/a2a), and [AG-UI](https://ai.pydantic.dev/ag-ui) standards to give your agent access to external tools and data, let it interoperate with other agents, and build interactive applications with streaming event-based communication.
53+
6. **MCP, A2A, and UI**:
54+
Integrates the [Model Context Protocol](https://ai.pydantic.dev/mcp/overview), [Agent2Agent](https://ai.pydantic.dev/a2a), and various [UI event stream](https://ai.pydantic.dev/ui/overview) standards to give your agent access to external tools and data, let it interoperate with other agents, and build interactive applications with streaming event-based communication.
5555

5656
7. **Human-in-the-Loop Tool Approval**:
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.

docs-site/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ const redirect_lookup: Record<string, string> = {
5555
'/examples': 'examples/setup/',
5656
'/mcp': '/mcp/overview/',
5757
'/models': '/models/overview/',
58+
'/ag-ui': '/ui/ag-ui/'
5859
}
5960

6061
function redirect(pathname: string): string | null {

docs/api/ui.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# `pydantic_ai.ui`
2+
3+
::: pydantic_ai.ui
4+
5+
::: pydantic_ai.ui.app
6+
7+
::: pydantic_ai.ui.ag_ui
8+
9+
::: pydantic_ai.ui.ag_ui.app
10+
11+
::: pydantic_ai.ui.vercel_ai
12+
13+
::: pydantic_ai.ui.vercel_ai.app

docs/examples/ag-ui.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
Example of using Pydantic AI agents with the [AG-UI Dojo](https://github.com/ag-ui-protocol/ag-ui/tree/main/typescript-sdk/apps/dojo) example app.
44

5-
See the [AG-UI docs](../ag-ui.md) for more information about the AG-UI integration.
5+
See the [AG-UI docs](../ui/ag-ui.md) for more information about the AG-UI integration.
66

77
Demonstrates:
88

9-
- [AG-UI](../ag-ui.md)
9+
- [AG-UI](../ui/ag-ui.md)
1010
- [Tools](../tools.md)
1111

1212
## Prerequisites

docs/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ Designed to give your IDE or AI coding agent as much context as possible for aut
2525
5. **Powerful Evals**:
2626
Enables you to systematically test and [evaluate](evals.md) the performance and accuracy of the agentic systems you build, and monitor the performance over time in Pydantic Logfire.
2727

28-
6. **MCP, A2A, and AG-UI**:
29-
Integrates the [Model Context Protocol](mcp/client.md), [Agent2Agent](a2a.md), and [AG-UI](ag-ui.md) standards to give your agent access to external tools and data, let it interoperate with other agents, and build interactive applications with streaming event-based communication.
28+
6. **MCP, A2A, and UI**:
29+
Integrates the [Model Context Protocol](mcp/overview.md), [Agent2Agent](a2a.md), and various [UI event stream](ui/overview.md) standards to give your agent access to external tools and data, let it interoperate with other agents, and build interactive applications with streaming event-based communication.
3030

3131
7. **Human-in-the-Loop Tool Approval**:
3232
Easily lets you flag that certain tool calls [require approval](deferred-tools.md#human-in-the-loop-tool-approval) before they can proceed, possibly depending on tool call arguments, conversation history, or user preferences.

docs/ag-ui.md renamed to docs/ui/ag-ui.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ from fastapi.responses import Response, StreamingResponse
5252
from pydantic import ValidationError
5353

5454
from pydantic_ai import Agent
55-
from pydantic_ai.ui.ag_ui import AGUIAdapter, SSE_CONTENT_TYPE
55+
from pydantic_ai.ui import SSE_CONTENT_TYPE
56+
from pydantic_ai.ui.ag_ui import AGUIAdapter
5657

5758
agent = Agent('openai:gpt-4.1', instructions='Be fun!')
5859

@@ -63,23 +64,24 @@ app = FastAPI()
6364
async def run_agent(request: Request) -> Response:
6465
accept = request.headers.get('accept', SSE_CONTENT_TYPE)
6566
try:
66-
run_input = AGUIAdapter.build_run_input(await request.json()) # (1)
67-
except ValidationError as e: # pragma: no cover
67+
run_input = AGUIAdapter.build_run_input(await request.body()) # (1)
68+
except ValidationError as e:
6869
return Response(
6970
content=json.dumps(e.json()),
7071
media_type='application/json',
7172
status_code=HTTPStatus.UNPROCESSABLE_ENTITY,
7273
)
7374

7475
adapter = AGUIAdapter(agent=agent, run_input=run_input, accept=accept)
75-
events = adapter.run_stream() # (2)
76+
event_stream = adapter.run_stream() # (2)
7677

77-
return StreamingResponse(adapter.encode_stream(events), media_type=accept) # (3)
78+
sse_event_stream = adapter.encode_stream(event_stream)
79+
return StreamingResponse(sse_event_stream, media_type=accept) # (3)
7880
```
7981

80-
1. You can also use the [`AGUIAdapter.from_request()`][pydantic_ai.ui.ag_ui.AGUIAdapter.from_request] class method to build an adapter directly from a request.
81-
2. You can also use the [`AGUIAdapter.run_stream_native()`][pydantic_ai.ui.ag_ui.AGUIAdapter.run_stream_native] method to run the agent and return a stream of Pydantic AI events instead of AG-UI events. These can then be transformed into AG-UI events using the [`AGUIAdapter.transform_stream()`][pydantic_ai.ui.ag_ui.AGUIAdapter.transform_stream] method.
82-
3. The [`AGUIAdapter.encode_stream()`][pydantic_ai.ui.ag_ui.AGUIAdapter.encode_stream] method encodes the stream of AG-UI events as strings according to the accept header value. You can also use the [`AGUIAdapter.streaming_response()`][pydantic_ai.ui.ag_ui.AGUIAdapter.streaming_response] method to generate a streaming response directly from the AG-UI event stream returned by `run_stream()`.
82+
1. [`AGUIAdapter.build_run_input()`][pydantic_ai.ui.ag_ui.AGUIAdapter.build_run_input] takes the request body as bytes and returns an AG-UI [`RunAgentInput`](https://docs.ag-ui.com/sdk/python/core/types#runagentinput) object. You can also use the [`AGUIAdapter.from_request()`][pydantic_ai.ui.ag_ui.AGUIAdapter.from_request] class method to build an adapter directly from a request.
83+
2. [`AGUIAdapter.run_stream()`][pydantic_ai.ui.ag_ui.AGUIAdapter.run_stream] runs the agent and returns a stream of AG-UI events. It supports the same optional arguments as [`Agent.run_stream_events()`](../agents.md#running-agents), including `deps`. You can also use [`AGUIAdapter.run_stream_native()`][pydantic_ai.ui.ag_ui.AGUIAdapter.run_stream_native] to run the agent and return a stream of Pydantic AI events instead, which can then be transformed into AG-UI events using [`AGUIAdapter.transform_stream()`][pydantic_ai.ui.ag_ui.AGUIAdapter.transform_stream].
84+
3. [`AGUIAdapter.encode_stream()`][pydantic_ai.ui.ag_ui.AGUIAdapter.encode_stream] encodes the stream of AG-UI events as strings according to the accept header value. You can also use [`AGUIAdapter.streaming_response()`][pydantic_ai.ui.ag_ui.AGUIAdapter.streaming_response] to generate a streaming response directly from the AG-UI event stream returned by `run_stream()`.
8385

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

@@ -167,7 +169,7 @@ The integration provides full support for
167169
real-time synchronization between agents and frontend applications.
168170

169171
In the example below we have document state which is shared between the UI and
170-
server using the [`StateDeps`][pydantic_ai.ag_ui.StateDeps] [dependencies type](./dependencies.md) that can be used to automatically
172+
server using the [`StateDeps`][pydantic_ai.ag_ui.StateDeps] [dependencies type](../dependencies.md) that can be used to automatically
171173
validate state contained in [`RunAgentInput.state`](https://docs.ag-ui.com/sdk/js/core/types#runagentinput) using a Pydantic `BaseModel` specified as a generic parameter.
172174

173175
!!! note "Custom dependencies type with AG-UI state"
@@ -182,7 +184,7 @@ from pydantic import BaseModel
182184

183185
from pydantic_ai import Agent
184186
from pydantic_ai.ui import StateDeps
185-
from pydantic_ai.ui.ag_ui import AGUIApp
187+
from pydantic_ai.ui.ag_ui.app import AGUIApp
186188

187189

188190
class DocumentState(BaseModel):
@@ -213,7 +215,7 @@ user experiences with frontend user interfaces.
213215
### Events
214216

215217
Pydantic AI tools can send [AG-UI events](https://docs.ag-ui.com/concepts/events) simply by returning a
216-
[`ToolReturn`](tools-advanced.md#advanced-tool-returns) object with a
218+
[`ToolReturn`](../tools-advanced.md#advanced-tool-returns) object with a
217219
[`BaseEvent`](https://docs.ag-ui.com/sdk/python/core/events#baseevent) (or a list of events) as `metadata`,
218220
which allows for custom events and state updates.
219221

@@ -223,7 +225,7 @@ from pydantic import BaseModel
223225

224226
from pydantic_ai import Agent, RunContext, ToolReturn
225227
from pydantic_ai.ui import StateDeps
226-
from pydantic_ai.ui.ag_ui import AGUIApp
228+
from pydantic_ai.ui.ag_ui.app import AGUIApp
227229

228230

229231
class DocumentState(BaseModel):

docs/ui/overview.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# UI Event Streams
2+
3+
If you're building a chat app or other interactive frontend for an AI agent, your backend will need to receive agent run input (like a chat message or full message history) from the frontend, and will need to stream the [agent's events](../agents.md#streaming-all-events) (like text, thinking, and tool calls) to the frontend so that the user knows what's happening in real time.
4+
5+
While your frontend could use Pydantic AI's [`ModelRequest`s](../message-history.md) and [`AgentStreamEvent`s][pydantic_ai.messages.AgentStreamEvent] directly, you'll typically want to use a UI event stream protocol that's natively supported by your frontend framework.
6+
7+
Pydantic AI natively supports two UI event stream protocols:
8+
9+
- [Agent User Interaction (AG-UI) Protocol](./ag-ui.md)
10+
- [Vercel AI Data Stream Protocol](./vercel-ai.md)
11+
12+
These integrations are implemented as subclasses of the abstract [`UIAdapter`][pydantic_ai.ui.UIAdapter] class, so they also serve as a reference for integrating with other UI event stream protocols.
13+
14+
## Usage
15+
16+
The protocol-specific [`UIAdapter`][pydantic_ai.ui.UIAdapter] subclass (i.e. [`AGUIAdapter`][pydantic_ai.ui.ag_ui.AGUIAdapter] or [`VercelAIAdapter`][pydantic_ai.ui.vercel_ai.VercelAIAdapter]) is responsible for transforming agent run input received from the frontend into arguments for [`Agent.run_stream_events()`](../agents.md#running-agents), running the agent, and then transforming Pydantic AI events into protocol-specific events. The event stream transformation is handled by a protocol-specific [`UIEventStream`][pydantic_ai.ui.UIEventStream] subclass, but you typically won't use this directly.
17+
18+
If you're using a Starlette-based web framework like FastAPI, you can use the [`UIAdapter.dispatch_request()`][pydantic_ai.ui.UIAdapter.dispatch_request] class method from an endpoint function to directly handle a request and return a streaming response of protocol-specific events. Besides the request, this method takes the agent and supports the same optional arguments as [`Agent.run_stream_events()`](../agents.md#running-agents), including `deps`.
19+
20+
!!! note
21+
These examples use the `VercelAIAdapter`, but the same patterns apply to all `UIAdapter` subclasses.
22+
23+
```py {title="dispatch_request.py"}
24+
from fastapi import FastAPI
25+
from starlette.requests import Request
26+
from starlette.responses import Response
27+
28+
from pydantic_ai import Agent
29+
from pydantic_ai.ui.vercel_ai import VercelAIAdapter
30+
31+
agent = Agent('openai:gpt-5')
32+
33+
app = FastAPI()
34+
35+
@app.post('/chat')
36+
async def chat(request: Request) -> Response:
37+
return await VercelAIAdapter.dispatch_request(request, agent=agent)
38+
```
39+
40+
If you're using a web framework not based on Starlette (e.g. Django or Flask) or want fine-grained control over the input or output, you can create and use a `UIAdapter` instance directly.
41+
42+
!!! note
43+
This example uses FastAPI, but can be modified to work with any web framework.
44+
45+
```py {title="run_stream.py"}
46+
import json
47+
from http import HTTPStatus
48+
49+
from fastapi import FastAPI
50+
from fastapi.requests import Request
51+
from fastapi.responses import Response, StreamingResponse
52+
from pydantic import ValidationError
53+
54+
from pydantic_ai import Agent
55+
from pydantic_ai.ui import SSE_CONTENT_TYPE
56+
from pydantic_ai.ui.vercel_ai import VercelAIAdapter
57+
58+
agent = Agent('openai:gpt-5')
59+
60+
app = FastAPI()
61+
62+
63+
@app.post('/chat')
64+
async def chat(request: Request) -> Response:
65+
accept = request.headers.get('accept', SSE_CONTENT_TYPE)
66+
try:
67+
run_input = VercelAIAdapter.build_run_input(await request.body()) # (1)
68+
except ValidationError as e:
69+
return Response(
70+
content=json.dumps(e.json()),
71+
media_type='application/json',
72+
status_code=HTTPStatus.UNPROCESSABLE_ENTITY,
73+
)
74+
75+
adapter = VercelAIAdapter(agent=agent, run_input=run_input, accept=accept)
76+
event_stream = adapter.run_stream() # (2)
77+
78+
sse_event_stream = adapter.encode_stream(event_stream)
79+
return StreamingResponse(sse_event_stream, media_type=accept) # (3)
80+
```
81+
82+
1. [`UIAdapter.build_run_input()`][pydantic_ai.ui.UIAdapter.build_run_input] takes the request body as bytes and returns a protocol-specific run input object. You can also use the [`UIAdapter.from_request()`][pydantic_ai.ui.UIAdapter.from_request] class method to build an adapter directly from a request.
83+
2. [`UIAdapter.run_stream()`][pydantic_ai.ui.UIAdapter.run_stream] runs the agent and returns a stream of protocol-specific events. It supports the same optional arguments as [`Agent.run_stream_events()`](../agents.md#running-agents), including `deps`. You can also use [`UIAdapter.run_stream_native()`][pydantic_ai.ui.UIAdapter.run_stream_native] to run the agent and return a stream of Pydantic AI events instead, which can then be transformed into protocol-specific events using [`UIAdapter.transform_stream()`][pydantic_ai.ui.UIAdapter.transform_stream].
84+
3. [`UIAdapter.encode_stream()`][pydantic_ai.ui.UIAdapter.encode_stream] encodes the stream of protocol-specific events as strings according to the accept header value. You can also use [`UIAdapter.streaming_response()`][pydantic_ai.ui.UIAdapter.streaming_response] to generate a streaming response directly from the protocol-specific event stream returned by `run_stream()`.

docs/ui/vercel-ai.md

Whitespace-only changes.

mkdocs.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ nav:
9292
- Temporal: durable_execution/temporal.md
9393
- DBOS: durable_execution/dbos.md
9494
- Prefect: durable_execution/prefect.md
95-
- Agent-User Interaction (AG-UI): ag-ui.md
95+
- UI Event Streams:
96+
- Overview: ui/overview.md
97+
- AG-UI: ui/ag-ui.md
98+
- Vercel AI: ui/vercel-ai.md
9699
- Agent2Agent (A2A): a2a.md
97100

98101
- Related Packages:
@@ -160,6 +163,7 @@ nav:
160163
- api/providers.md
161164
- api/retries.md
162165
- api/run.md
166+
- api/ui.md
163167
- pydantic_evals:
164168
- api/pydantic_evals/dataset.md
165169
- api/pydantic_evals/evaluators.md

pydantic_ai_slim/pydantic_ai/agent/abstract.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,7 @@ def to_ag_ui(
10401040
uvicorn app:app --host 0.0.0.0 --port 8000
10411041
```
10421042
1043-
See [AG-UI docs](../ag-ui.md) for more information.
1043+
See [AG-UI docs](../ui/ag-ui.md) for more information.
10441044
10451045
Args:
10461046
output_type: Custom output type to use for this run, `output_type` may only be used if the agent has

0 commit comments

Comments
 (0)