Skip to content

Commit 5f4e078

Browse files
MikeRyanDevDouweM
andauthored
fix: Relax UserError into a warning when state deps is not provided with AG-UI (#3510)
Co-authored-by: Douwe Maan <[email protected]>
1 parent f5bcf04 commit 5f4e078

File tree

3 files changed

+15
-9
lines changed

3 files changed

+15
-9
lines changed

docs/ui/ag-ui.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ validate state contained in [`RunAgentInput.state`](https://docs.ag-ui.com/sdk/j
178178

179179
If the `state` field's type is a Pydantic `BaseModel` subclass, the raw state dictionary on the request is automatically validated. If not, you can validate the raw value yourself in your dependencies dataclass's `__post_init__` method.
180180

181+
If AG-UI state is provided but your dependencies do not implement [`StateHandler`][pydantic_ai.ag_ui.StateHandler], Pydantic AI will emit a warning and ignore the state. Use [`StateDeps`][pydantic_ai.ag_ui.StateDeps] or a custom [`StateHandler`][pydantic_ai.ag_ui.StateHandler] implementation to receive and validate the incoming state.
182+
181183

182184
```python {title="ag_ui_state.py"}
183185
from pydantic import BaseModel

pydantic_ai_slim/pydantic_ai/ui/_adapter.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import warnings
34
from abc import ABC, abstractmethod
45
from collections.abc import AsyncIterator, Sequence
56
from dataclasses import KW_ONLY, Field, dataclass
@@ -21,7 +22,6 @@
2122
from pydantic_ai.agent import AbstractAgent
2223
from pydantic_ai.agent.abstract import Instructions
2324
from pydantic_ai.builtin_tools import AbstractBuiltinTool
24-
from pydantic_ai.exceptions import UserError
2525
from pydantic_ai.messages import ModelMessage
2626
from pydantic_ai.models import KnownModelName, Model
2727
from pydantic_ai.output import OutputDataT, OutputSpec
@@ -243,8 +243,10 @@ def run_stream_native(
243243

244244
deps.state = state
245245
elif self.state:
246-
raise UserError(
247-
f'State is provided but `deps` of type `{type(deps).__name__}` does not implement the `StateHandler` protocol: it needs to be a dataclass with a non-optional `state` field.'
246+
warnings.warn(
247+
f'State was provided but `deps` of type `{type(deps).__name__}` does not implement the `StateHandler` protocol, so the state was ignored. Use `StateDeps[...]` or implement `StateHandler` to receive AG-UI state.',
248+
UserWarning,
249+
stacklevel=2,
248250
)
249251

250252
return self.agent.run_stream_events(

tests/test_ag_ui.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
from pydantic_ai._run_context import RunContext
4040
from pydantic_ai.agent import Agent, AgentRunResult
4141
from pydantic_ai.builtin_tools import WebSearchTool
42-
from pydantic_ai.exceptions import UserError
4342
from pydantic_ai.models.function import (
4443
AgentInfo,
4544
BuiltinToolCallsReturns,
@@ -1206,12 +1205,15 @@ async def test_request_with_state_without_handler() -> None:
12061205
state=StateInt(value=41),
12071206
)
12081207

1209-
with pytest.raises(
1210-
UserError,
1211-
match='State is provided but `deps` of type `NoneType` does not implement the `StateHandler` protocol: it needs to be a dataclass with a non-optional `state` field.',
1208+
with pytest.warns(
1209+
UserWarning,
1210+
match='State was provided but `deps` of type `NoneType` does not implement the `StateHandler` protocol, so the state was ignored. Use `StateDeps\\[\\.\\.\\.\\]` or implement `StateHandler` to receive AG-UI state.',
12121211
):
1213-
async for _ in run_ag_ui(agent, run_input):
1214-
pass
1212+
events = list[dict[str, Any]]()
1213+
async for event in run_ag_ui(agent, run_input):
1214+
events.append(json.loads(event.removeprefix('data: ')))
1215+
1216+
assert events == simple_result()
12151217

12161218

12171219
async def test_request_with_empty_state_without_handler() -> None:

0 commit comments

Comments
 (0)