Skip to content

Commit edbb712

Browse files
committed
docs: ag-ui adapter
Added documentation for the ag-ui adapter, including examples and API references.
1 parent 17080a6 commit edbb712

File tree

5 files changed

+303
-2
lines changed

5 files changed

+303
-2
lines changed

adapter_ag_ui/adapter_ag_ui/adapter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,12 @@ async def run(
197197
) -> AsyncGenerator[str, None]:
198198
"""Run the agent with streaming response using AG-UI protocol events.
199199
200+
The first two arguments are specific to `AdapterAGUI` the rest map directly to the `Agent.iter` method.
201+
200202
Args:
201203
run_input: The AG-UI run input containing thread_id, run_id, messages, etc.
202204
accept: The accept header value for the run.
203205
204-
These arguments map directly to the `Agent.iter` method:
205-
206206
output_type: Custom output type to use for this run, `output_type` may only be used if the agent has no
207207
output validators since output validators would expect an argument that matches the agent's output type.
208208
model: Optional model to use for this run, required if `model` was not set when creating the agent.

docs/ag-ui.md

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
# Agent User Interaction (AG-UI) Protocol
2+
3+
The [Agent User Interaction (AG-UI) Protocol](https://docs.ag-ui.com/introduction)
4+
is an open standard introduced by the
5+
[CopilotKit](https://webflow.copilotkit.ai/blog/introducing-ag-ui-the-protocol-where-agents-meet-users)
6+
team that standardises how front-end applications connect to AI agents through
7+
an open protocol. Think of it as a universal translator for AI-driven systems
8+
no matter what language an agent speaks: AG-UI ensures fluent communication.
9+
10+
The team at [Rocket Science](https://www.rocketscience.gg/), contributed the
11+
[adapter-ag-ui](#adapter-ag-ui) library to make it easy to implement the AG-UI
12+
protocol with PydanticAI agents.
13+
14+
This also includes a convenience method that expose PydanticAI agents as AG-UI
15+
servers - let's have a quick look at how to use it:
16+
17+
```py {title="agent_to_ag_ui.py" py="3.10" hl_lines="17-27"}
18+
"""Basic example for AG-UI with FastAPI and Pydantic AI."""
19+
from __future__ import annotations
20+
21+
from typing import TYPE_CHECKING, Annotated
22+
23+
from adapter_ag_ui import SSE_CONTENT_TYPE
24+
from fastapi import FastAPI, Header
25+
from fastapi.responses import StreamingResponse
26+
27+
from pydantic_ai import Agent
28+
29+
if TYPE_CHECKING:
30+
from ag_ui.core import RunAgentInput
31+
32+
app = FastAPI(title='AG-UI Endpoint')
33+
agent = Agent('openai:gpt-4.1', instructions='Be fun!')
34+
adapter = agent.to_ag_ui()
35+
36+
37+
@app.post('/')
38+
async def root(
39+
input_data: RunAgentInput, accept: Annotated[str, Header()] = SSE_CONTENT_TYPE
40+
) -> StreamingResponse:
41+
return StreamingResponse(
42+
adapter.run(input_data, accept),
43+
media_type=SSE_CONTENT_TYPE,
44+
)
45+
```
46+
47+
You can run the example with:
48+
49+
```shell
50+
uvicorn agent_to_ag_ui:app --host 0.0.0.0 --port 8000
51+
```
52+
53+
This will expose the agent as an AG-UI server, and you can start sending requests to it.
54+
55+
See more about [exposing PydanticAI agents as AG-UI servers](#pydanticai-agent-to-ag-ui-server).
56+
57+
## Adapter AG UI
58+
59+
**AdapterAGUI** is an adapter between PydanticAI agents and the AG-UI protocol
60+
written in Python.
61+
62+
### Design
63+
64+
The adapter receives messages in the form of a
65+
[`RunAgentInput.state`](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 translated to PydanticAI types, passed to the
68+
provided agent when then process the request. Results from the agent are then
69+
streamed back to the caller.
70+
71+
A user request may require multiple round trips between client UI and PydanticAI
72+
server, depending on the tools and events needed.
73+
74+
[AdapterAGUI][adapter_ag_ui.AdapterAGUI] can be used with any ASGI server.
75+
76+
### Installation
77+
78+
[AdapterAGUI][adapter_ag_ui.AdapterAGUI] is available on PyPI as
79+
[`adapter-ag-ui`](https://pypi.org/project/adapter-ag-ui/) so installation is as
80+
simple as:
81+
82+
```bash
83+
pip/uv-add adapter-ag-ui
84+
```
85+
86+
The only dependencies are:
87+
88+
- [ag-ui-protocol](https://docs.ag-ui.com/introduction): to provide the AG-UI
89+
types and encoder.
90+
- [pydantic](https://pydantic.dev): to validate the request/response messages
91+
- [pydantic-ai](https://ai.pydantic.dev/): to provide the agent framework
92+
93+
To run the examples you'll also need:
94+
95+
- [fastapi](https://fastapi.tiangolo.com/): to provide ASGI compatible server
96+
97+
```bash
98+
pip/uv-add 'fastapi'
99+
```
100+
101+
You can install PydanticAI with the `ag-ui` extra to include **AdapterAGUI**:
102+
103+
```bash
104+
pip/uv-add 'pydantic-ai-slim[ag-ui]'
105+
```
106+
107+
### Usage
108+
109+
To expose a PydanticAI agent as an AG-UI server including state support, you can
110+
use the [`to_ag_ui`][pydantic_ai.agent.Agent.to_ag_ui] method in combination
111+
with fastapi.
112+
113+
In the example below we have document state which is shared between the UI and
114+
server using the [`StateDeps`][adapter_ag_ui.StateDeps] which implements the
115+
[`StateHandler`][adapter_ag_ui.StateHandler] that can be used to automatically
116+
decode state contained in [`RunAgentInput.state`](https://docs.ag-ui.com/sdk/js/core/types#runagentinput)
117+
when processing requests.
118+
119+
#### State management
120+
121+
The adapter provides full support for
122+
[AG-UI state management](https://docs.ag-ui.com/concepts/state), which enables
123+
real-time synchronization between agents and frontend applications.
124+
125+
```python {title="ag_ui_state.py" py="3.10" hl_lines="18-21,28,38"}
126+
"""State example for AG-UI with FastAPI and Pydantic AI."""
127+
128+
from __future__ import annotations
129+
130+
from typing import TYPE_CHECKING, Annotated
131+
132+
from adapter_ag_ui import SSE_CONTENT_TYPE, StateDeps
133+
from fastapi import FastAPI, Header
134+
from fastapi.responses import StreamingResponse
135+
from pydantic import BaseModel
136+
137+
from pydantic_ai import Agent
138+
139+
if TYPE_CHECKING:
140+
from ag_ui.core import RunAgentInput
141+
142+
143+
class DocumentState(BaseModel):
144+
"""State for the document being written."""
145+
146+
document: str
147+
148+
149+
app = FastAPI(title='AG-UI Endpoint')
150+
agent = Agent(
151+
'openai:gpt-4.1',
152+
instructions='Be fun!',
153+
deps_type=StateDeps[DocumentState],
154+
)
155+
adapter = agent.to_ag_ui()
156+
157+
158+
@app.post('/')
159+
async def root(
160+
input_data: RunAgentInput, accept: Annotated[str, Header()] = SSE_CONTENT_TYPE
161+
) -> StreamingResponse:
162+
return StreamingResponse(
163+
adapter.run(input_data, accept, deps=StateDeps(state_type=DocumentState)),
164+
media_type=SSE_CONTENT_TYPE,
165+
)
166+
167+
```
168+
169+
Since `app` is an ASGI application, it can be used with any ASGI server.
170+
171+
```bash
172+
uvicorn agent_to_ag_ui:app --host 0.0.0.0 --port 8000
173+
```
174+
175+
Since the goal of [`to_ag_ui`][pydantic_ai.agent.Agent.to_ag_ui] is to be a
176+
convenience method, it accepts the same arguments as the
177+
[`AdapterAGUI`][adapter_ag_ui.AdapterAGUI] constructor.
178+
179+
#### Tools
180+
181+
AG-UI tools are seamlessly provided to the PydanticAI agent, enabling rich
182+
use experiences with frontend user interfaces.
183+
184+
#### Events
185+
186+
The adapter provides the ability for PydanticAI tools to send
187+
[AG-UI events](https://docs.ag-ui.com/concepts/events) simply by defining a tool
188+
which returns a type based off
189+
[`BaseEvent`](https://docs.ag-ui.com/sdk/js/core/events#baseevent) this allows
190+
for custom events and state updates.
191+
192+
```python {title="ag_ui_tool_events.py" py="3.10" hl_lines="35-56"}
193+
"""Tool events example for AG-UI with FastAPI and Pydantic AI."""
194+
195+
from __future__ import annotations
196+
197+
from typing import TYPE_CHECKING, Annotated
198+
199+
from adapter_ag_ui import SSE_CONTENT_TYPE, StateDeps
200+
from ag_ui.core import CustomEvent, EventType, StateSnapshotEvent
201+
from fastapi import FastAPI, Header
202+
from fastapi.responses import StreamingResponse
203+
from pydantic import BaseModel
204+
205+
from pydantic_ai import Agent, RunContext
206+
207+
if TYPE_CHECKING:
208+
from ag_ui.core import RunAgentInput
209+
210+
211+
class DocumentState(BaseModel):
212+
"""State for the document being written."""
213+
214+
document: str
215+
216+
217+
app = FastAPI(title='AG-UI Endpoint')
218+
219+
agent = Agent(
220+
'openai:gpt-4.1',
221+
instructions='Be fun!',
222+
deps_type=StateDeps[DocumentState],
223+
)
224+
adapter = agent.to_ag_ui()
225+
226+
227+
@agent.tool
228+
def update_state(ctx: RunContext[StateDeps[DocumentState]]) -> StateSnapshotEvent:
229+
return StateSnapshotEvent(
230+
type=EventType.STATE_SNAPSHOT,
231+
snapshot=ctx.deps.state,
232+
)
233+
234+
235+
@agent.tool_plain
236+
def custom_events() -> list[CustomEvent]:
237+
return [
238+
CustomEvent(
239+
type=EventType.CUSTOM,
240+
name='count',
241+
value=1,
242+
),
243+
CustomEvent(
244+
type=EventType.CUSTOM,
245+
name='count',
246+
value=2,
247+
),
248+
]
249+
250+
251+
@app.post('/')
252+
async def root(
253+
input_data: RunAgentInput, accept: Annotated[str, Header()] = SSE_CONTENT_TYPE
254+
) -> StreamingResponse:
255+
return StreamingResponse(
256+
adapter.run(input_data, accept, deps=StateDeps(state_type=DocumentState)),
257+
media_type=SSE_CONTENT_TYPE,
258+
)
259+
260+
```
261+
262+
### Examples
263+
264+
For more examples of how to use [`AdapterAGUI`][adapter_ag_ui.AdapterAGUI] see
265+
[`adapter_ag_ui_examples`](https://github.com/pydantic/pydantic-ai/tree/main/examples/adapter_ag_ui_examples),
266+
which includes working server for the with the
267+
[AG-UI Dojo](https://docs.ag-ui.com/tutorials/debugging#the-ag-ui-dojo) which
268+
can be run from a clone of the repo or with the `adapter_ag_ui_examples` package
269+
installed with either of the following:
270+
271+
```bash
272+
pip/uv-add 'adapter_ag_ui_examples'
273+
```
274+
275+
Direct:
276+
277+
```shell
278+
python -m adapter_ag_ui_examples.dojo_server
279+
```
280+
281+
Using uvicorn:
282+
283+
```shell
284+
uvicorn adapter_ag_ui_examples.dojo_server:app --host 0.0.0.0 --port 8000
285+
```

docs/api/adapter_ag_ui.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# `adapter_ag_ui`
2+
3+
::: adapter_ag_ui

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ nav:
4747
- mcp/server.md
4848
- mcp/run-python.md
4949
- A2A: a2a.md
50+
- AG-UI: ag-ui.md
5051
- cli.md
5152
- Examples:
5253
- examples/index.md
@@ -100,6 +101,7 @@ nav:
100101
- api/pydantic_evals/otel.md
101102
- api/pydantic_evals/generation.md
102103
- api/fasta2a.md
104+
- api/adapter_ag_ui.md
103105

104106
extra:
105107
# hide the "Made with Material for MkDocs" message

pydantic_ai_slim/pydantic_ai/agent.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,17 @@ def to_ag_ui(
17481748
logger: logging.Logger | None = None,
17491749
tool_prefix: str | None = None,
17501750
) -> AdapterAGUI[AgentDepsT, OutputDataT]:
1751+
"""Convert the agent to an AdapterAGUI instance.
1752+
1753+
This allows you to use the agent with a compatible AG-UI frontend.
1754+
1755+
Args:
1756+
logger: Optional logger to use for the adapter.
1757+
tool_prefix: Optional prefix to add to tool names in the AG-UI.
1758+
1759+
Returns:
1760+
An instance of `AdapterAGUI` that can be used with AG-UI.
1761+
"""
17511762
try:
17521763
from adapter_ag_ui.adapter import AdapterAGUI
17531764
except ImportError as _import_error:

0 commit comments

Comments
 (0)