Skip to content

Commit 7746f77

Browse files
authored
Add convenience functions to handle AG-UI requests with request-specific deps (#2397)
1 parent 6515302 commit 7746f77

File tree

4 files changed

+483
-375
lines changed

4 files changed

+483
-375
lines changed

docs/ag-ui.md

Lines changed: 96 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,15 @@ The [Agent User Interaction (AG-UI) Protocol](https://docs.ag-ui.com/introductio
44
[CopilotKit](https://webflow.copilotkit.ai/blog/introducing-ag-ui-the-protocol-where-agents-meet-users)
55
team that standardises how frontend applications communicate with AI agents, with support for streaming, frontend tools, shared state, and custom events.
66

7-
Any Pydantic AI agent can be exposed as an AG-UI server using the [`Agent.to_ag_ui()`][pydantic_ai.Agent.to_ag_ui] convenience method.
8-
97
!!! note
108
The AG-UI integration was originally built by the team at [Rocket Science](https://www.rocketscience.gg/) and contributed in collaboration with the Pydantic AI and CopilotKit teams. Thanks Rocket Science!
119

1210
## Installation
1311

1412
The only dependencies are:
1513

16-
- [ag-ui-protocol](https://docs.ag-ui.com/introduction): to provide the AG-UI types and encoder
17-
- [starlette](https://www.starlette.io): to expose the AG-UI server as an [ASGI application](https://asgi.readthedocs.io/en/latest/)
14+
- [ag-ui-protocol](https://docs.ag-ui.com/introduction): to provide the AG-UI types and encoder.
15+
- [starlette](https://www.starlette.io): to handle [ASGI](https://asgi.readthedocs.io/en/latest/) requests from a framework like FastAPI.
1816

1917
You can install Pydantic AI with the `ag-ui` extra to ensure you have all the
2018
required AG-UI dependencies:
@@ -31,9 +29,95 @@ To run the examples you'll also need:
3129
pip/uv-add uvicorn
3230
```
3331

34-
## Quick start
32+
## Usage
33+
34+
There are three ways to run a Pydantic AI agent based on AG-UI run input with streamed AG-UI events as output, from most to least flexible. If you're using a Starlette-based web framework like FastAPI, you'll typically want to use the second method.
35+
36+
1. [`run_ag_ui()`][pydantic_ai.ag_ui.run_ag_ui] takes an agent and an AG-UI [`RunAgentInput`](https://docs.ag-ui.com/sdk/python/core/types#runagentinput) object, and returns a stream of AG-UI events encoded as strings. It also takes optional [`Agent.iter()`][pydantic_ai.Agent.iter] arguments including `deps`. Use this if you're using a web framework not based on Starlette (e.g. Django or Flask) or want to modify the input or output some way.
37+
2. [`handle_ag_ui_request()`][pydantic_ai.ag_ui.handle_ag_ui_request] takes an agent and a Starlette request (e.g. from FastAPI) coming from an AG-UI frontend, and returns a streaming Starlette response of AG-UI events that you can return directly from your endpoint. It also takes optional [`Agent.iter()`][pydantic_ai.Agent.iter] arguments including `deps`, that you can vary for each request (e.g. based on the authenticated user).
38+
3. [`Agent.to_ag_ui()`][pydantic_ai.Agent.to_ag_ui] returns an ASGI application that handles every AG-UI request by running the agent. It also takes optional [`Agent.iter()`][pydantic_ai.Agent.iter] arguments including `deps`, but these will be the same for each request, with the exception of the AG-UI state that's injected as described under [state management](#state-management). This ASGI app can be [mounted](https://fastapi.tiangolo.com/advanced/sub-applications/) at a given path in an existing FastAPI app.
39+
40+
### Handle run input and output directly
41+
42+
This example uses [`run_ag_ui()`][pydantic_ai.ag_ui.run_ag_ui] and performs its own request parsing and response generation.
43+
This can be modified to work with any web framework.
44+
45+
```py {title="run_ag_ui.py"}
46+
from ag_ui.core import RunAgentInput
47+
from fastapi import FastAPI
48+
from http import HTTPStatus
49+
from fastapi.requests import Request
50+
from fastapi.responses import Response, StreamingResponse
51+
from pydantic import ValidationError
52+
import json
53+
54+
from pydantic_ai import Agent
55+
from pydantic_ai.ag_ui import run_ag_ui, SSE_CONTENT_TYPE
56+
57+
58+
agent = Agent('openai:gpt-4.1', instructions='Be fun!')
59+
60+
app = FastAPI()
61+
62+
63+
@app.post("/")
64+
async def run_agent(request: Request) -> Response:
65+
accept = request.headers.get('accept', SSE_CONTENT_TYPE)
66+
try:
67+
run_input = RunAgentInput.model_validate(await request.json())
68+
except ValidationError as e: # pragma: no cover
69+
return Response(
70+
content=json.dumps(e.json()),
71+
media_type='application/json',
72+
status_code=HTTPStatus.UNPROCESSABLE_ENTITY,
73+
)
74+
75+
event_stream = run_ag_ui(agent, run_input, accept=accept)
76+
77+
return StreamingResponse(event_stream, media_type=accept)
78+
```
79+
80+
Since `app` is an ASGI application, it can be used with any ASGI server:
81+
82+
```shell
83+
uvicorn run_ag_ui:app
84+
```
85+
86+
This will expose the agent as an AG-UI server, and your frontend can start sending requests to it.
87+
88+
### Handle a Starlette request
89+
90+
This example uses [`handle_ag_ui_request()`][pydantic_ai.ag_ui.run_ag_ui] to directly handle a FastAPI request and return a response. Something analogous to this will work with any Starlette-based web framework.
91+
92+
```py {title="handle_ag_ui_request.py"}
93+
from fastapi import FastAPI
94+
from starlette.requests import Request
95+
from starlette.responses import Response
96+
97+
from pydantic_ai import Agent
98+
from pydantic_ai.ag_ui import handle_ag_ui_request
99+
100+
101+
agent = Agent('openai:gpt-4.1', instructions='Be fun!')
102+
103+
app = FastAPI()
104+
105+
@app.post("/")
106+
async def run_agent(request: Request) -> Response:
107+
return await handle_ag_ui_request(agent, request)
108+
```
109+
110+
Since `app` is an ASGI application, it can be used with any ASGI server:
35111

36-
To expose a Pydantic AI agent as an AG-UI server, you can use the [`Agent.to_ag_ui()`][pydantic_ai.Agent.to_ag_ui] method:
112+
```shell
113+
uvicorn handle_ag_ui_request:app
114+
```
115+
116+
This will expose the agent as an AG-UI server, and your frontend can start sending requests to it.
117+
118+
### Stand-alone ASGI app
119+
120+
This example uses [`Agent.to_ag_ui()`][pydantic_ai.Agent.to_ag_ui] to turn the agent into a stand-alone ASGI application:
37121

38122
```py {title="agent_to_ag_ui.py" py="3.10" hl_lines="4"}
39123
from pydantic_ai import Agent
@@ -45,13 +129,11 @@ app = agent.to_ag_ui()
45129
Since `app` is an ASGI application, it can be used with any ASGI server:
46130

47131
```shell
48-
uvicorn agent_to_ag_ui:app --host 0.0.0.0 --port 9000
132+
uvicorn agent_to_ag_ui:app
49133
```
50134

51135
This will expose the agent as an AG-UI server, and your frontend can start sending requests to it.
52136

53-
The `to_ag_ui()` method accepts the same arguments as the [`Agent.iter()`][pydantic_ai.agent.Agent.iter] method as well as arguments that let you configure the [Starlette](https://www.starlette.io)-based ASGI app.
54-
55137
## Design
56138

57139
The Pydantic AI AG-UI integration supports all features of the spec:
@@ -61,14 +143,11 @@ The Pydantic AI AG-UI integration supports all features of the spec:
61143
- [State Management](https://docs.ag-ui.com/concepts/state)
62144
- [Tools](https://docs.ag-ui.com/concepts/tools)
63145

64-
The app receives messages in the form of a
65-
[`RunAgentInput`](https://docs.ag-ui.com/sdk/js/core/types#runagentinput)
66-
which describes the details of a request being passed to the agent including
67-
messages and state. These are then converted to Pydantic AI types and passed to the
68-
agent which then process the request.
146+
The integration receives messages in the form of a
147+
[`RunAgentInput`](https://docs.ag-ui.com/sdk/python/core/types#runagentinput) object
148+
that describes the details of the requested agent run including message history, state, and available tools.
69149

70-
Events from the agent, including tool calls, are converted to AG-UI events and
71-
streamed back to the caller as Server-Sent Events (SSE).
150+
These are converted to Pydantic AI types and passed to the agent's run method. Events from the agent, including tool calls, are converted to AG-UI events and streamed back to the caller as Server-Sent Events (SSE).
72151

73152
A user request may require multiple round trips between client UI and Pydantic AI
74153
server, depending on the tools and events needed.
@@ -77,7 +156,7 @@ server, depending on the tools and events needed.
77156

78157
### State management
79158

80-
The adapter provides full support for
159+
The integration provides full support for
81160
[AG-UI state management](https://docs.ag-ui.com/concepts/state), which enables
82161
real-time synchronization between agents and frontend applications.
83162

0 commit comments

Comments
 (0)