pydantic-ai-slim 0.6.2__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pydantic-ai-slim might be problematic. Click here for more details.

Files changed (57) hide show
  1. pydantic_ai/_a2a.py +6 -4
  2. pydantic_ai/_agent_graph.py +25 -32
  3. pydantic_ai/_cli.py +3 -3
  4. pydantic_ai/_output.py +8 -0
  5. pydantic_ai/_tool_manager.py +3 -0
  6. pydantic_ai/ag_ui.py +25 -14
  7. pydantic_ai/{agent.py → agent/__init__.py} +209 -1027
  8. pydantic_ai/agent/abstract.py +942 -0
  9. pydantic_ai/agent/wrapper.py +227 -0
  10. pydantic_ai/direct.py +9 -9
  11. pydantic_ai/durable_exec/__init__.py +0 -0
  12. pydantic_ai/durable_exec/temporal/__init__.py +83 -0
  13. pydantic_ai/durable_exec/temporal/_agent.py +699 -0
  14. pydantic_ai/durable_exec/temporal/_function_toolset.py +92 -0
  15. pydantic_ai/durable_exec/temporal/_logfire.py +48 -0
  16. pydantic_ai/durable_exec/temporal/_mcp_server.py +145 -0
  17. pydantic_ai/durable_exec/temporal/_model.py +168 -0
  18. pydantic_ai/durable_exec/temporal/_run_context.py +50 -0
  19. pydantic_ai/durable_exec/temporal/_toolset.py +77 -0
  20. pydantic_ai/ext/aci.py +10 -9
  21. pydantic_ai/ext/langchain.py +4 -2
  22. pydantic_ai/mcp.py +203 -75
  23. pydantic_ai/messages.py +2 -2
  24. pydantic_ai/models/__init__.py +65 -9
  25. pydantic_ai/models/anthropic.py +16 -7
  26. pydantic_ai/models/bedrock.py +8 -5
  27. pydantic_ai/models/cohere.py +1 -4
  28. pydantic_ai/models/fallback.py +4 -2
  29. pydantic_ai/models/function.py +9 -4
  30. pydantic_ai/models/gemini.py +15 -9
  31. pydantic_ai/models/google.py +18 -14
  32. pydantic_ai/models/groq.py +17 -14
  33. pydantic_ai/models/huggingface.py +18 -12
  34. pydantic_ai/models/instrumented.py +3 -1
  35. pydantic_ai/models/mcp_sampling.py +3 -1
  36. pydantic_ai/models/mistral.py +12 -18
  37. pydantic_ai/models/openai.py +29 -26
  38. pydantic_ai/models/test.py +3 -0
  39. pydantic_ai/models/wrapper.py +6 -2
  40. pydantic_ai/profiles/openai.py +1 -1
  41. pydantic_ai/providers/google.py +7 -7
  42. pydantic_ai/result.py +21 -55
  43. pydantic_ai/run.py +357 -0
  44. pydantic_ai/tools.py +0 -1
  45. pydantic_ai/toolsets/__init__.py +2 -0
  46. pydantic_ai/toolsets/_dynamic.py +87 -0
  47. pydantic_ai/toolsets/abstract.py +23 -3
  48. pydantic_ai/toolsets/combined.py +19 -4
  49. pydantic_ai/toolsets/deferred.py +10 -2
  50. pydantic_ai/toolsets/function.py +23 -8
  51. pydantic_ai/toolsets/prefixed.py +4 -0
  52. pydantic_ai/toolsets/wrapper.py +14 -1
  53. {pydantic_ai_slim-0.6.2.dist-info → pydantic_ai_slim-0.7.0.dist-info}/METADATA +6 -4
  54. {pydantic_ai_slim-0.6.2.dist-info → pydantic_ai_slim-0.7.0.dist-info}/RECORD +57 -44
  55. {pydantic_ai_slim-0.6.2.dist-info → pydantic_ai_slim-0.7.0.dist-info}/WHEEL +0 -0
  56. {pydantic_ai_slim-0.6.2.dist-info → pydantic_ai_slim-0.7.0.dist-info}/entry_points.txt +0 -0
  57. {pydantic_ai_slim-0.6.2.dist-info → pydantic_ai_slim-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -5,22 +5,18 @@ import inspect
5
5
  import json
6
6
  import warnings
7
7
  from asyncio import Lock
8
- from collections.abc import AsyncIterator, Awaitable, Iterator, Mapping, Sequence
8
+ from collections.abc import AsyncIterator, Awaitable, Iterator, Sequence
9
9
  from contextlib import AbstractAsyncContextManager, AsyncExitStack, asynccontextmanager, contextmanager
10
10
  from contextvars import ContextVar
11
- from copy import deepcopy
12
- from types import FrameType
13
- from typing import TYPE_CHECKING, Any, Callable, ClassVar, Generic, cast, final, overload
11
+ from typing import TYPE_CHECKING, Any, Callable, ClassVar, cast, overload
14
12
 
15
13
  from opentelemetry.trace import NoOpTracer, use_span
16
14
  from pydantic.json_schema import GenerateJsonSchema
17
- from typing_extensions import Literal, Never, Self, TypeIs, TypeVar, deprecated
15
+ from typing_extensions import TypeVar, deprecated
18
16
 
19
- from pydantic_ai.builtin_tools import AbstractBuiltinTool
20
- from pydantic_graph import End, Graph, GraphRun, GraphRunContext
21
- from pydantic_graph._utils import get_event_loop
17
+ from pydantic_graph import Graph
22
18
 
23
- from . import (
19
+ from .. import (
24
20
  _agent_graph,
25
21
  _output,
26
22
  _system_prompt,
@@ -28,18 +24,19 @@ from . import (
28
24
  exceptions,
29
25
  messages as _messages,
30
26
  models,
31
- result,
32
27
  usage as _usage,
33
28
  )
34
- from ._agent_graph import HistoryProcessor
35
- from ._output import OutputToolset
36
- from ._tool_manager import ToolManager
37
- from .models.instrumented import InstrumentationSettings, InstrumentedModel, instrument_model
38
- from .output import OutputDataT, OutputSpec
39
- from .profiles import ModelProfile
40
- from .result import AgentStream, FinalResult, StreamedRunResult
41
- from .settings import ModelSettings, merge_model_settings
42
- from .tools import (
29
+ from .._agent_graph import HistoryProcessor
30
+ from .._output import OutputToolset
31
+ from .._tool_manager import ToolManager
32
+ from ..builtin_tools import AbstractBuiltinTool
33
+ from ..models.instrumented import InstrumentationSettings, InstrumentedModel, instrument_model
34
+ from ..output import OutputDataT, OutputSpec
35
+ from ..profiles import ModelProfile
36
+ from ..result import FinalResult
37
+ from ..run import AgentRun, AgentRunResult
38
+ from ..settings import ModelSettings, merge_model_settings
39
+ from ..tools import (
43
40
  AgentDepsT,
44
41
  DocstringFormat,
45
42
  GenerateToolJsonSchema,
@@ -52,11 +49,16 @@ from .tools import (
52
49
  ToolPrepareFunc,
53
50
  ToolsPrepareFunc,
54
51
  )
55
- from .toolsets import AbstractToolset
56
- from .toolsets.combined import CombinedToolset
57
- from .toolsets.function import FunctionToolset
58
- from .toolsets.prepared import PreparedToolset
59
- from .usage import Usage, UsageLimits
52
+ from ..toolsets import AbstractToolset
53
+ from ..toolsets._dynamic import (
54
+ DynamicToolset,
55
+ ToolsetFunc,
56
+ )
57
+ from ..toolsets.combined import CombinedToolset
58
+ from ..toolsets.function import FunctionToolset
59
+ from ..toolsets.prepared import PreparedToolset
60
+ from .abstract import AbstractAgent, EventStreamHandler, RunOutputDataT
61
+ from .wrapper import WrapperAgent
60
62
 
61
63
  # Re-exporting like this improves auto-import behavior in PyCharm
62
64
  capture_run_messages = _agent_graph.capture_run_messages
@@ -66,17 +68,7 @@ ModelRequestNode = _agent_graph.ModelRequestNode
66
68
  UserPromptNode = _agent_graph.UserPromptNode
67
69
 
68
70
  if TYPE_CHECKING:
69
- from fasta2a.applications import FastA2A
70
- from fasta2a.broker import Broker
71
- from fasta2a.schema import AgentProvider, Skill
72
- from fasta2a.storage import Storage
73
- from starlette.middleware import Middleware
74
- from starlette.routing import BaseRoute, Route
75
- from starlette.types import ExceptionHandler, Lifespan
76
-
77
- from pydantic_ai.mcp import MCPServer
78
-
79
- from .ag_ui import AGUIApp
71
+ from ..mcp import MCPServer
80
72
 
81
73
  __all__ = (
82
74
  'Agent',
@@ -88,19 +80,19 @@ __all__ = (
88
80
  'ModelRequestNode',
89
81
  'UserPromptNode',
90
82
  'InstrumentationSettings',
83
+ 'WrapperAgent',
84
+ 'AbstractAgent',
85
+ 'EventStreamHandler',
91
86
  )
92
87
 
93
88
 
94
89
  T = TypeVar('T')
95
90
  S = TypeVar('S')
96
91
  NoneType = type(None)
97
- RunOutputDataT = TypeVar('RunOutputDataT')
98
- """Type variable for the result data of a run where `output_type` was customized on the run call."""
99
92
 
100
93
 
101
- @final
102
94
  @dataclasses.dataclass(init=False)
103
- class Agent(Generic[AgentDepsT, OutputDataT]):
95
+ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
104
96
  """Class for defining "agents" - a way to have a specific type of "conversation" with an LLM.
105
97
 
106
98
  Agents are generic in the dependency type they take [`AgentDepsT`][pydantic_ai.tools.AgentDepsT]
@@ -116,21 +108,13 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
116
108
  agent = Agent('openai:gpt-4o')
117
109
  result = agent.run_sync('What is the capital of France?')
118
110
  print(result.output)
119
- #> Paris
111
+ #> The capital of France is Paris.
120
112
  ```
121
113
  """
122
114
 
123
- model: models.Model | models.KnownModelName | str | None
124
- """The default model configured for this agent.
125
-
126
- We allow `str` here since the actual list of allowed models changes frequently.
127
- """
128
-
129
- name: str | None
130
- """The name of the agent, used for logging.
115
+ _model: models.Model | models.KnownModelName | str | None
131
116
 
132
- If `None`, we try to infer the agent name from the call frame when the agent is first run.
133
- """
117
+ _name: str | None
134
118
  end_strategy: EndStrategy
135
119
  """Strategy for handling tool calls when a final result is found."""
136
120
 
@@ -141,10 +125,7 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
141
125
  be merged with this value, with the runtime argument taking priority.
142
126
  """
143
127
 
144
- output_type: OutputSpec[OutputDataT]
145
- """
146
- The type of data output by agent runs, used to validate the data returned by the model, defaults to `str`.
147
- """
128
+ _output_type: OutputSpec[OutputDataT]
148
129
 
149
130
  instrument: InstrumentationSettings | bool | None
150
131
  """Options to automatically instrument with OpenTelemetry."""
@@ -163,10 +144,13 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
163
144
  )
164
145
  _function_toolset: FunctionToolset[AgentDepsT] = dataclasses.field(repr=False)
165
146
  _output_toolset: OutputToolset[AgentDepsT] | None = dataclasses.field(repr=False)
166
- _user_toolsets: Sequence[AbstractToolset[AgentDepsT]] = dataclasses.field(repr=False)
147
+ _user_toolsets: list[AbstractToolset[AgentDepsT]] = dataclasses.field(repr=False)
167
148
  _prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = dataclasses.field(repr=False)
168
149
  _prepare_output_tools: ToolsPrepareFunc[AgentDepsT] | None = dataclasses.field(repr=False)
169
150
  _max_result_retries: int = dataclasses.field(repr=False)
151
+ _max_tool_retries: int = dataclasses.field(repr=False)
152
+
153
+ _event_stream_handler: EventStreamHandler[AgentDepsT] | None = dataclasses.field(repr=False)
170
154
 
171
155
  _enter_lock: Lock = dataclasses.field(repr=False)
172
156
  _entered_count: int = dataclasses.field(repr=False)
@@ -192,11 +176,12 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
192
176
  builtin_tools: Sequence[AbstractBuiltinTool] = (),
193
177
  prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
194
178
  prepare_output_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
195
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
179
+ toolsets: Sequence[AbstractToolset[AgentDepsT] | ToolsetFunc[AgentDepsT]] | None = None,
196
180
  defer_model_check: bool = False,
197
181
  end_strategy: EndStrategy = 'early',
198
182
  instrument: InstrumentationSettings | bool | None = None,
199
183
  history_processors: Sequence[HistoryProcessor[AgentDepsT]] | None = None,
184
+ event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
200
185
  ) -> None: ...
201
186
 
202
187
  @overload
@@ -225,6 +210,7 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
225
210
  end_strategy: EndStrategy = 'early',
226
211
  instrument: InstrumentationSettings | bool | None = None,
227
212
  history_processors: Sequence[HistoryProcessor[AgentDepsT]] | None = None,
213
+ event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
228
214
  ) -> None: ...
229
215
 
230
216
  def __init__(
@@ -246,11 +232,12 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
246
232
  builtin_tools: Sequence[AbstractBuiltinTool] = (),
247
233
  prepare_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
248
234
  prepare_output_tools: ToolsPrepareFunc[AgentDepsT] | None = None,
249
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
235
+ toolsets: Sequence[AbstractToolset[AgentDepsT] | ToolsetFunc[AgentDepsT]] | None = None,
250
236
  defer_model_check: bool = False,
251
237
  end_strategy: EndStrategy = 'early',
252
238
  instrument: InstrumentationSettings | bool | None = None,
253
239
  history_processors: Sequence[HistoryProcessor[AgentDepsT]] | None = None,
240
+ event_stream_handler: EventStreamHandler[AgentDepsT] | None = None,
254
241
  **_deprecated_kwargs: Any,
255
242
  ):
256
243
  """Create an agent.
@@ -283,7 +270,8 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
283
270
  prepare_output_tools: Custom function to prepare the tool definition of all output tools for each step.
284
271
  This is useful if you want to customize the definition of multiple output tools or you want to register
285
272
  a subset of output tools for a given step. See [`ToolsPrepareFunc`][pydantic_ai.tools.ToolsPrepareFunc]
286
- toolsets: Toolsets to register with the agent, including MCP servers.
273
+ toolsets: Toolsets to register with the agent, including MCP servers and functions which take a run context
274
+ and return a toolset. See [`ToolsetFunc`][pydantic_ai.toolsets.ToolsetFunc] for more information.
287
275
  defer_model_check: by default, if you provide a [named][pydantic_ai.models.KnownModelName] model,
288
276
  it's evaluated to create a [`Model`][pydantic_ai.models.Model] instance immediately,
289
277
  which checks for the necessary environment variables. Set this to `false`
@@ -301,17 +289,18 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
301
289
  history_processors: Optional list of callables to process the message history before sending it to the model.
302
290
  Each processor takes a list of messages and returns a modified list of messages.
303
291
  Processors can be sync or async and are applied in sequence.
292
+ event_stream_handler: Optional handler for events from the model's streaming response and the agent's execution of tools.
304
293
  """
305
294
  if model is None or defer_model_check:
306
- self.model = model
295
+ self._model = model
307
296
  else:
308
- self.model = models.infer_model(model)
297
+ self._model = models.infer_model(model)
309
298
 
299
+ self._name = name
310
300
  self.end_strategy = end_strategy
311
- self.name = name
312
301
  self.model_settings = model_settings
313
302
 
314
- self.output_type = output_type
303
+ self._output_type = output_type
315
304
  self.instrument = instrument
316
305
  self._deps_type = deps_type
317
306
 
@@ -346,6 +335,8 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
346
335
  self._system_prompt_dynamic_functions = {}
347
336
 
348
337
  self._max_result_retries = output_retries if output_retries is not None else retries
338
+ self._max_tool_retries = retries
339
+
349
340
  self._builtin_tools = builtin_tools
350
341
 
351
342
  self._prepare_tools = prepare_tools
@@ -355,16 +346,26 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
355
346
  if self._output_toolset:
356
347
  self._output_toolset.max_retries = self._max_result_retries
357
348
 
358
- self._function_toolset = FunctionToolset(tools, max_retries=retries)
359
- self._user_toolsets = toolsets or ()
349
+ self._function_toolset = _AgentFunctionToolset(tools, max_retries=self._max_tool_retries)
350
+ self._dynamic_toolsets = [
351
+ DynamicToolset[AgentDepsT](toolset_func=toolset)
352
+ for toolset in toolsets or []
353
+ if not isinstance(toolset, AbstractToolset)
354
+ ]
355
+ self._user_toolsets = [toolset for toolset in toolsets or [] if isinstance(toolset, AbstractToolset)]
360
356
 
361
357
  self.history_processors = history_processors or []
362
358
 
359
+ self._event_stream_handler = event_stream_handler
360
+
363
361
  self._override_deps: ContextVar[_utils.Option[AgentDepsT]] = ContextVar('_override_deps', default=None)
364
362
  self._override_model: ContextVar[_utils.Option[models.Model]] = ContextVar('_override_model', default=None)
365
363
  self._override_toolsets: ContextVar[_utils.Option[Sequence[AbstractToolset[AgentDepsT]]]] = ContextVar(
366
364
  '_override_toolsets', default=None
367
365
  )
366
+ self._override_tools: ContextVar[
367
+ _utils.Option[Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]]]
368
+ ] = ContextVar('_override_tools', default=None)
368
369
 
369
370
  self._enter_lock = _utils.get_async_lock()
370
371
  self._entered_count = 0
@@ -375,107 +376,49 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
375
376
  """Set the instrumentation options for all agents where `instrument` is not set."""
376
377
  Agent._instrument_default = instrument
377
378
 
378
- @overload
379
- async def run(
380
- self,
381
- user_prompt: str | Sequence[_messages.UserContent] | None = None,
382
- *,
383
- output_type: None = None,
384
- message_history: list[_messages.ModelMessage] | None = None,
385
- model: models.Model | models.KnownModelName | str | None = None,
386
- deps: AgentDepsT = None,
387
- model_settings: ModelSettings | None = None,
388
- usage_limits: _usage.UsageLimits | None = None,
389
- usage: _usage.Usage | None = None,
390
- infer_name: bool = True,
391
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
392
- ) -> AgentRunResult[OutputDataT]: ...
393
-
394
- @overload
395
- async def run(
396
- self,
397
- user_prompt: str | Sequence[_messages.UserContent] | None = None,
398
- *,
399
- output_type: OutputSpec[RunOutputDataT],
400
- message_history: list[_messages.ModelMessage] | None = None,
401
- model: models.Model | models.KnownModelName | str | None = None,
402
- deps: AgentDepsT = None,
403
- model_settings: ModelSettings | None = None,
404
- usage_limits: _usage.UsageLimits | None = None,
405
- usage: _usage.Usage | None = None,
406
- infer_name: bool = True,
407
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
408
- ) -> AgentRunResult[RunOutputDataT]: ...
409
-
410
- async def run(
411
- self,
412
- user_prompt: str | Sequence[_messages.UserContent] | None = None,
413
- *,
414
- output_type: OutputSpec[RunOutputDataT] | None = None,
415
- message_history: list[_messages.ModelMessage] | None = None,
416
- model: models.Model | models.KnownModelName | str | None = None,
417
- deps: AgentDepsT = None,
418
- model_settings: ModelSettings | None = None,
419
- usage_limits: _usage.UsageLimits | None = None,
420
- usage: _usage.Usage | None = None,
421
- infer_name: bool = True,
422
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
423
- **_deprecated_kwargs: Never,
424
- ) -> AgentRunResult[Any]:
425
- """Run the agent with a user prompt in async mode.
379
+ @property
380
+ def model(self) -> models.Model | models.KnownModelName | str | None:
381
+ """The default model configured for this agent."""
382
+ return self._model
426
383
 
427
- This method builds an internal agent graph (using system prompts, tools and result schemas) and then
428
- runs the graph to completion. The result of the run is returned.
384
+ @model.setter
385
+ def model(self, value: models.Model | models.KnownModelName | str | None) -> None:
386
+ """Set the default model configured for this agent.
429
387
 
430
- Example:
431
- ```python
432
- from pydantic_ai import Agent
388
+ We allow `str` here since the actual list of allowed models changes frequently.
389
+ """
390
+ self._model = value
433
391
 
434
- agent = Agent('openai:gpt-4o')
392
+ @property
393
+ def name(self) -> str | None:
394
+ """The name of the agent, used for logging.
435
395
 
436
- async def main():
437
- agent_run = await agent.run('What is the capital of France?')
438
- print(agent_run.output)
439
- #> Paris
440
- ```
396
+ If `None`, we try to infer the agent name from the call frame when the agent is first run.
397
+ """
398
+ return self._name
441
399
 
442
- Args:
443
- user_prompt: User input to start/continue the conversation.
444
- output_type: Custom output type to use for this run, `output_type` may only be used if the agent has no
445
- output validators since output validators would expect an argument that matches the agent's output type.
446
- message_history: History of the conversation so far.
447
- model: Optional model to use for this run, required if `model` was not set when creating the agent.
448
- deps: Optional dependencies to use for this run.
449
- model_settings: Optional settings to use for this model's request.
450
- usage_limits: Optional limits on model request count or token usage.
451
- usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
452
- infer_name: Whether to try to infer the agent name from the call frame if it's not set.
453
- toolsets: Optional additional toolsets for this run.
400
+ @name.setter
401
+ def name(self, value: str | None) -> None:
402
+ """Set the name of the agent, used for logging."""
403
+ self._name = value
454
404
 
455
- Returns:
456
- The result of the run.
457
- """
458
- if infer_name and self.name is None:
459
- self._infer_name(inspect.currentframe())
405
+ @property
406
+ def deps_type(self) -> type:
407
+ """The type of dependencies used by the agent."""
408
+ return self._deps_type
460
409
 
461
- _utils.validate_empty_kwargs(_deprecated_kwargs)
410
+ @property
411
+ def output_type(self) -> OutputSpec[OutputDataT]:
412
+ """The type of data output by agent runs, used to validate the data returned by the model, defaults to `str`."""
413
+ return self._output_type
462
414
 
463
- async with self.iter(
464
- user_prompt=user_prompt,
465
- output_type=output_type,
466
- message_history=message_history,
467
- model=model,
468
- deps=deps,
469
- model_settings=model_settings,
470
- usage_limits=usage_limits,
471
- usage=usage,
472
- toolsets=toolsets,
473
- ) as agent_run:
474
- async for _ in agent_run:
475
- pass
415
+ @property
416
+ def event_stream_handler(self) -> EventStreamHandler[AgentDepsT] | None:
417
+ """Optional handler for events from the model's streaming response and the agent's execution of tools."""
418
+ return self._event_stream_handler
476
419
 
477
- assert agent_run.result is not None, 'The graph run did not finish properly'
478
- return agent_run.result
420
+ def __repr__(self) -> str:
421
+ return f'{type(self).__name__}(model={self.model!r}, name={self.name!r}, end_strategy={self.end_strategy!r}, model_settings={self.model_settings!r}, output_type={self.output_type!r}, instrument={self.instrument!r})'
479
422
 
480
423
  @overload
481
424
  def iter(
@@ -491,7 +434,6 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
491
434
  usage: _usage.Usage | None = None,
492
435
  infer_name: bool = True,
493
436
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
494
- **_deprecated_kwargs: Never,
495
437
  ) -> AbstractAsyncContextManager[AgentRun[AgentDepsT, OutputDataT]]: ...
496
438
 
497
439
  @overload
@@ -508,7 +450,6 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
508
450
  usage: _usage.Usage | None = None,
509
451
  infer_name: bool = True,
510
452
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
511
- **_deprecated_kwargs: Never,
512
453
  ) -> AbstractAsyncContextManager[AgentRun[AgentDepsT, RunOutputDataT]]: ...
513
454
 
514
455
  @asynccontextmanager
@@ -525,7 +466,6 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
525
466
  usage: _usage.Usage | None = None,
526
467
  infer_name: bool = True,
527
468
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
528
- **_deprecated_kwargs: Never,
529
469
  ) -> AsyncIterator[AgentRun[AgentDepsT, Any]]:
530
470
  """A contextmanager which can be used to iterate over the agent graph's nodes as they are executed.
531
471
 
@@ -573,19 +513,19 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
573
513
  ),
574
514
  CallToolsNode(
575
515
  model_response=ModelResponse(
576
- parts=[TextPart(content='Paris')],
516
+ parts=[TextPart(content='The capital of France is Paris.')],
577
517
  usage=Usage(
578
- requests=1, request_tokens=56, response_tokens=1, total_tokens=57
518
+ requests=1, request_tokens=56, response_tokens=7, total_tokens=63
579
519
  ),
580
520
  model_name='gpt-4o',
581
521
  timestamp=datetime.datetime(...),
582
522
  )
583
523
  ),
584
- End(data=FinalResult(output='Paris')),
524
+ End(data=FinalResult(output='The capital of France is Paris.')),
585
525
  ]
586
526
  '''
587
527
  print(agent_run.result.output)
588
- #> Paris
528
+ #> The capital of France is Paris.
589
529
  ```
590
530
 
591
531
  Args:
@@ -609,8 +549,6 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
609
549
  model_used = self._get_model(model)
610
550
  del model
611
551
 
612
- _utils.validate_empty_kwargs(_deprecated_kwargs)
613
-
614
552
  deps = self._get_deps(deps)
615
553
  new_message_index = len(message_history) if message_history else 0
616
554
  output_schema = self._prepare_output_schema(output_type, model_used.profile)
@@ -662,9 +600,10 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
662
600
  )
663
601
 
664
602
  toolset = self._get_toolset(output_toolset=output_toolset, additional_toolsets=toolsets)
665
- # This will raise errors for any name conflicts
603
+
666
604
  async with toolset:
667
- run_toolset = await ToolManager[AgentDepsT].build(toolset, run_context)
605
+ # This will raise errors for any name conflicts
606
+ tool_manager = await ToolManager[AgentDepsT].build(toolset, run_context)
668
607
 
669
608
  # Merge model settings in order of precedence: run > agent > model
670
609
  merged_settings = merge_model_settings(model_used.settings, self.model_settings)
@@ -709,7 +648,7 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
709
648
  output_validators=output_validators,
710
649
  history_processors=self.history_processors,
711
650
  builtin_tools=list(self._builtin_tools),
712
- tool_manager=run_toolset,
651
+ tool_manager=tool_manager,
713
652
  tracer=tracer,
714
653
  get_instructions=get_instructions,
715
654
  instrumentation_settings=instrumentation_settings,
@@ -769,266 +708,6 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
769
708
  ),
770
709
  }
771
710
 
772
- @overload
773
- def run_sync(
774
- self,
775
- user_prompt: str | Sequence[_messages.UserContent] | None = None,
776
- *,
777
- message_history: list[_messages.ModelMessage] | None = None,
778
- model: models.Model | models.KnownModelName | str | None = None,
779
- deps: AgentDepsT = None,
780
- model_settings: ModelSettings | None = None,
781
- usage_limits: _usage.UsageLimits | None = None,
782
- usage: _usage.Usage | None = None,
783
- infer_name: bool = True,
784
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
785
- ) -> AgentRunResult[OutputDataT]: ...
786
-
787
- @overload
788
- def run_sync(
789
- self,
790
- user_prompt: str | Sequence[_messages.UserContent] | None = None,
791
- *,
792
- output_type: OutputSpec[RunOutputDataT] | None = None,
793
- message_history: list[_messages.ModelMessage] | None = None,
794
- model: models.Model | models.KnownModelName | str | None = None,
795
- deps: AgentDepsT = None,
796
- model_settings: ModelSettings | None = None,
797
- usage_limits: _usage.UsageLimits | None = None,
798
- usage: _usage.Usage | None = None,
799
- infer_name: bool = True,
800
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
801
- ) -> AgentRunResult[RunOutputDataT]: ...
802
-
803
- def run_sync(
804
- self,
805
- user_prompt: str | Sequence[_messages.UserContent] | None = None,
806
- *,
807
- output_type: OutputSpec[RunOutputDataT] | None = None,
808
- message_history: list[_messages.ModelMessage] | None = None,
809
- model: models.Model | models.KnownModelName | str | None = None,
810
- deps: AgentDepsT = None,
811
- model_settings: ModelSettings | None = None,
812
- usage_limits: _usage.UsageLimits | None = None,
813
- usage: _usage.Usage | None = None,
814
- infer_name: bool = True,
815
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
816
- **_deprecated_kwargs: Never,
817
- ) -> AgentRunResult[Any]:
818
- """Synchronously run the agent with a user prompt.
819
-
820
- This is a convenience method that wraps [`self.run`][pydantic_ai.Agent.run] with `loop.run_until_complete(...)`.
821
- You therefore can't use this method inside async code or if there's an active event loop.
822
-
823
- Example:
824
- ```python
825
- from pydantic_ai import Agent
826
-
827
- agent = Agent('openai:gpt-4o')
828
-
829
- result_sync = agent.run_sync('What is the capital of Italy?')
830
- print(result_sync.output)
831
- #> Rome
832
- ```
833
-
834
- Args:
835
- user_prompt: User input to start/continue the conversation.
836
- output_type: Custom output type to use for this run, `output_type` may only be used if the agent has no
837
- output validators since output validators would expect an argument that matches the agent's output type.
838
- message_history: History of the conversation so far.
839
- model: Optional model to use for this run, required if `model` was not set when creating the agent.
840
- deps: Optional dependencies to use for this run.
841
- model_settings: Optional settings to use for this model's request.
842
- usage_limits: Optional limits on model request count or token usage.
843
- usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
844
- infer_name: Whether to try to infer the agent name from the call frame if it's not set.
845
- toolsets: Optional additional toolsets for this run.
846
-
847
- Returns:
848
- The result of the run.
849
- """
850
- if infer_name and self.name is None:
851
- self._infer_name(inspect.currentframe())
852
-
853
- _utils.validate_empty_kwargs(_deprecated_kwargs)
854
-
855
- return get_event_loop().run_until_complete(
856
- self.run(
857
- user_prompt,
858
- output_type=output_type,
859
- message_history=message_history,
860
- model=model,
861
- deps=deps,
862
- model_settings=model_settings,
863
- usage_limits=usage_limits,
864
- usage=usage,
865
- infer_name=False,
866
- toolsets=toolsets,
867
- )
868
- )
869
-
870
- @overload
871
- def run_stream(
872
- self,
873
- user_prompt: str | Sequence[_messages.UserContent] | None = None,
874
- *,
875
- message_history: list[_messages.ModelMessage] | None = None,
876
- model: models.Model | models.KnownModelName | None = None,
877
- deps: AgentDepsT = None,
878
- model_settings: ModelSettings | None = None,
879
- usage_limits: _usage.UsageLimits | None = None,
880
- usage: _usage.Usage | None = None,
881
- infer_name: bool = True,
882
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
883
- ) -> AbstractAsyncContextManager[result.StreamedRunResult[AgentDepsT, OutputDataT]]: ...
884
-
885
- @overload
886
- def run_stream(
887
- self,
888
- user_prompt: str | Sequence[_messages.UserContent],
889
- *,
890
- output_type: OutputSpec[RunOutputDataT],
891
- message_history: list[_messages.ModelMessage] | None = None,
892
- model: models.Model | models.KnownModelName | str | None = None,
893
- deps: AgentDepsT = None,
894
- model_settings: ModelSettings | None = None,
895
- usage_limits: _usage.UsageLimits | None = None,
896
- usage: _usage.Usage | None = None,
897
- infer_name: bool = True,
898
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
899
- ) -> AbstractAsyncContextManager[result.StreamedRunResult[AgentDepsT, RunOutputDataT]]: ...
900
-
901
- @asynccontextmanager
902
- async def run_stream(
903
- self,
904
- user_prompt: str | Sequence[_messages.UserContent] | None = None,
905
- *,
906
- output_type: OutputSpec[RunOutputDataT] | None = None,
907
- message_history: list[_messages.ModelMessage] | None = None,
908
- model: models.Model | models.KnownModelName | str | None = None,
909
- deps: AgentDepsT = None,
910
- model_settings: ModelSettings | None = None,
911
- usage_limits: _usage.UsageLimits | None = None,
912
- usage: _usage.Usage | None = None,
913
- infer_name: bool = True,
914
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
915
- **_deprecated_kwargs: Never,
916
- ) -> AsyncIterator[result.StreamedRunResult[AgentDepsT, Any]]:
917
- """Run the agent with a user prompt in async mode, returning a streamed response.
918
-
919
- Example:
920
- ```python
921
- from pydantic_ai import Agent
922
-
923
- agent = Agent('openai:gpt-4o')
924
-
925
- async def main():
926
- async with agent.run_stream('What is the capital of the UK?') as response:
927
- print(await response.get_output())
928
- #> London
929
- ```
930
-
931
- Args:
932
- user_prompt: User input to start/continue the conversation.
933
- output_type: Custom output type to use for this run, `output_type` may only be used if the agent has no
934
- output validators since output validators would expect an argument that matches the agent's output type.
935
- message_history: History of the conversation so far.
936
- model: Optional model to use for this run, required if `model` was not set when creating the agent.
937
- deps: Optional dependencies to use for this run.
938
- model_settings: Optional settings to use for this model's request.
939
- usage_limits: Optional limits on model request count or token usage.
940
- usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
941
- infer_name: Whether to try to infer the agent name from the call frame if it's not set.
942
- toolsets: Optional additional toolsets for this run.
943
-
944
- Returns:
945
- The result of the run.
946
- """
947
- # TODO: We need to deprecate this now that we have the `iter` method.
948
- # Before that, though, we should add an event for when we reach the final result of the stream.
949
- if infer_name and self.name is None:
950
- # f_back because `asynccontextmanager` adds one frame
951
- if frame := inspect.currentframe(): # pragma: no branch
952
- self._infer_name(frame.f_back)
953
-
954
- _utils.validate_empty_kwargs(_deprecated_kwargs)
955
-
956
- yielded = False
957
- async with self.iter(
958
- user_prompt,
959
- output_type=output_type,
960
- message_history=message_history,
961
- model=model,
962
- deps=deps,
963
- model_settings=model_settings,
964
- usage_limits=usage_limits,
965
- usage=usage,
966
- infer_name=False,
967
- toolsets=toolsets,
968
- ) as agent_run:
969
- first_node = agent_run.next_node # start with the first node
970
- assert isinstance(first_node, _agent_graph.UserPromptNode) # the first node should be a user prompt node
971
- node = first_node
972
- while True:
973
- if self.is_model_request_node(node):
974
- graph_ctx = agent_run.ctx
975
- async with node.stream(graph_ctx) as stream:
976
-
977
- async def stream_to_final(s: AgentStream) -> FinalResult[AgentStream] | None:
978
- async for event in stream:
979
- if isinstance(event, _messages.FinalResultEvent):
980
- return FinalResult(s, event.tool_name, event.tool_call_id)
981
- return None
982
-
983
- final_result = await stream_to_final(stream)
984
- if final_result is not None:
985
- if yielded:
986
- raise exceptions.AgentRunError('Agent run produced final results') # pragma: no cover
987
- yielded = True
988
-
989
- messages = graph_ctx.state.message_history.copy()
990
-
991
- async def on_complete() -> None:
992
- """Called when the stream has completed.
993
-
994
- The model response will have been added to messages by now
995
- by `StreamedRunResult._marked_completed`.
996
- """
997
- last_message = messages[-1]
998
- assert isinstance(last_message, _messages.ModelResponse)
999
- tool_calls = [
1000
- part for part in last_message.parts if isinstance(part, _messages.ToolCallPart)
1001
- ]
1002
-
1003
- parts: list[_messages.ModelRequestPart] = []
1004
- async for _event in _agent_graph.process_function_tools(
1005
- graph_ctx.deps.tool_manager,
1006
- tool_calls,
1007
- final_result,
1008
- graph_ctx,
1009
- parts,
1010
- ):
1011
- pass
1012
- if parts:
1013
- messages.append(_messages.ModelRequest(parts))
1014
-
1015
- yield StreamedRunResult(
1016
- messages,
1017
- graph_ctx.deps.new_message_index,
1018
- stream,
1019
- on_complete,
1020
- )
1021
- break
1022
- next_node = await agent_run.next(node)
1023
- if not isinstance(next_node, _agent_graph.AgentNode):
1024
- raise exceptions.AgentRunError( # pragma: no cover
1025
- 'Should have produced a StreamedRunResult before getting here'
1026
- )
1027
- node = cast(_agent_graph.AgentNode[Any, Any], next_node)
1028
-
1029
- if not yielded:
1030
- raise exceptions.AgentRunError('Agent run finished without producing a final result') # pragma: no cover
1031
-
1032
711
  @contextmanager
1033
712
  def override(
1034
713
  self,
@@ -1036,8 +715,9 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
1036
715
  deps: AgentDepsT | _utils.Unset = _utils.UNSET,
1037
716
  model: models.Model | models.KnownModelName | str | _utils.Unset = _utils.UNSET,
1038
717
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | _utils.Unset = _utils.UNSET,
718
+ tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] | _utils.Unset = _utils.UNSET,
1039
719
  ) -> Iterator[None]:
1040
- """Context manager to temporarily override agent dependencies, model, or toolsets.
720
+ """Context manager to temporarily override agent dependencies, model, toolsets, or tools.
1041
721
 
1042
722
  This is particularly useful when testing.
1043
723
  You can find an example of this [here](../testing.md#overriding-model-via-pytest-fixtures).
@@ -1046,6 +726,7 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
1046
726
  deps: The dependencies to use instead of the dependencies passed to the agent run.
1047
727
  model: The model to use instead of the model passed to the agent run.
1048
728
  toolsets: The toolsets to use instead of the toolsets passed to the agent constructor and agent run.
729
+ tools: The tools to use instead of the tools registered with the agent.
1049
730
  """
1050
731
  if _utils.is_set(deps):
1051
732
  deps_token = self._override_deps.set(_utils.Some(deps))
@@ -1062,6 +743,11 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
1062
743
  else:
1063
744
  toolsets_token = None
1064
745
 
746
+ if _utils.is_set(tools):
747
+ tools_token = self._override_tools.set(_utils.Some(tools))
748
+ else:
749
+ tools_token = None
750
+
1065
751
  try:
1066
752
  yield
1067
753
  finally:
@@ -1071,6 +757,8 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
1071
757
  self._override_model.reset(model_token)
1072
758
  if toolsets_token is not None:
1073
759
  self._override_toolsets.reset(toolsets_token)
760
+ if tools_token is not None:
761
+ self._override_tools.reset(tools_token)
1074
762
 
1075
763
  @overload
1076
764
  def instructions(
@@ -1461,6 +1149,53 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
1461
1149
 
1462
1150
  return tool_decorator if func is None else tool_decorator(func)
1463
1151
 
1152
+ @overload
1153
+ def toolset(self, func: ToolsetFunc[AgentDepsT], /) -> ToolsetFunc[AgentDepsT]: ...
1154
+
1155
+ @overload
1156
+ def toolset(
1157
+ self,
1158
+ /,
1159
+ *,
1160
+ per_run_step: bool = True,
1161
+ ) -> Callable[[ToolsetFunc[AgentDepsT]], ToolsetFunc[AgentDepsT]]: ...
1162
+
1163
+ def toolset(
1164
+ self,
1165
+ func: ToolsetFunc[AgentDepsT] | None = None,
1166
+ /,
1167
+ *,
1168
+ per_run_step: bool = True,
1169
+ ) -> Any:
1170
+ """Decorator to register a toolset function which takes [`RunContext`][pydantic_ai.tools.RunContext] as its only argument.
1171
+
1172
+ Can decorate a sync or async functions.
1173
+
1174
+ The decorator can be used bare (`agent.toolset`).
1175
+
1176
+ Example:
1177
+ ```python
1178
+ from pydantic_ai import Agent, RunContext
1179
+ from pydantic_ai.toolsets import AbstractToolset, FunctionToolset
1180
+
1181
+ agent = Agent('test', deps_type=str)
1182
+
1183
+ @agent.toolset
1184
+ async def simple_toolset(ctx: RunContext[str]) -> AbstractToolset[str]:
1185
+ return FunctionToolset()
1186
+ ```
1187
+
1188
+ Args:
1189
+ func: The toolset function to register.
1190
+ per_run_step: Whether to re-evaluate the toolset for each run step. Defaults to True.
1191
+ """
1192
+
1193
+ def toolset_decorator(func_: ToolsetFunc[AgentDepsT]) -> ToolsetFunc[AgentDepsT]:
1194
+ self._dynamic_toolsets.append(DynamicToolset(func_, per_run_step=per_run_step))
1195
+ return func_
1196
+
1197
+ return toolset_decorator if func is None else toolset_decorator(func)
1198
+
1464
1199
  def _get_model(self, model: models.Model | models.KnownModelName | str | None) -> models.Model:
1465
1200
  """Create a model configured for this agent.
1466
1201
 
@@ -1514,46 +1249,56 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
1514
1249
 
1515
1250
  Args:
1516
1251
  output_toolset: The output toolset to use instead of the one built at agent construction time.
1517
- additional_toolsets: Additional toolsets to add.
1252
+ additional_toolsets: Additional toolsets to add, unless toolsets have been overridden.
1518
1253
  """
1519
- if some_user_toolsets := self._override_toolsets.get():
1520
- user_toolsets = some_user_toolsets.value
1521
- elif additional_toolsets is not None:
1522
- user_toolsets = [*self._user_toolsets, *additional_toolsets]
1523
- else:
1524
- user_toolsets = self._user_toolsets
1254
+ toolsets = self.toolsets
1255
+ # Don't add additional toolsets if the toolsets have been overridden
1256
+ if additional_toolsets and self._override_toolsets.get() is None:
1257
+ toolsets = [*toolsets, *additional_toolsets]
1525
1258
 
1526
- all_toolsets = [self._function_toolset, *user_toolsets]
1259
+ toolset = CombinedToolset(toolsets)
1260
+
1261
+ # Copy the dynamic toolsets to ensure each run has its own instances
1262
+ def copy_dynamic_toolsets(toolset: AbstractToolset[AgentDepsT]) -> AbstractToolset[AgentDepsT]:
1263
+ if isinstance(toolset, DynamicToolset):
1264
+ return dataclasses.replace(toolset)
1265
+ else:
1266
+ return toolset
1267
+
1268
+ toolset = toolset.visit_and_replace(copy_dynamic_toolsets)
1527
1269
 
1528
1270
  if self._prepare_tools:
1529
- all_toolsets = [PreparedToolset(CombinedToolset(all_toolsets), self._prepare_tools)]
1271
+ toolset = PreparedToolset(toolset, self._prepare_tools)
1530
1272
 
1531
1273
  output_toolset = output_toolset if _utils.is_set(output_toolset) else self._output_toolset
1532
1274
  if output_toolset is not None:
1533
1275
  if self._prepare_output_tools:
1534
1276
  output_toolset = PreparedToolset(output_toolset, self._prepare_output_tools)
1535
- all_toolsets = [output_toolset, *all_toolsets]
1277
+ toolset = CombinedToolset([output_toolset, toolset])
1536
1278
 
1537
- return CombinedToolset(all_toolsets)
1279
+ return toolset
1538
1280
 
1539
- def _infer_name(self, function_frame: FrameType | None) -> None:
1540
- """Infer the agent name from the call frame.
1281
+ @property
1282
+ def toolsets(self) -> Sequence[AbstractToolset[AgentDepsT]]:
1283
+ """All toolsets registered on the agent, including a function toolset holding tools that were registered on the agent directly.
1541
1284
 
1542
- Usage should be `self._infer_name(inspect.currentframe())`.
1285
+ Output tools are not included.
1543
1286
  """
1544
- assert self.name is None, 'Name already set'
1545
- if function_frame is not None: # pragma: no branch
1546
- if parent_frame := function_frame.f_back: # pragma: no branch
1547
- for name, item in parent_frame.f_locals.items():
1548
- if item is self:
1549
- self.name = name
1550
- return
1551
- if parent_frame.f_locals != parent_frame.f_globals: # pragma: no branch
1552
- # if we couldn't find the agent in locals and globals are a different dict, try globals
1553
- for name, item in parent_frame.f_globals.items():
1554
- if item is self:
1555
- self.name = name
1556
- return
1287
+ toolsets: list[AbstractToolset[AgentDepsT]] = []
1288
+
1289
+ if some_tools := self._override_tools.get():
1290
+ function_toolset = _AgentFunctionToolset(some_tools.value, max_retries=self._max_tool_retries)
1291
+ else:
1292
+ function_toolset = self._function_toolset
1293
+ toolsets.append(function_toolset)
1294
+
1295
+ if some_user_toolsets := self._override_toolsets.get():
1296
+ user_toolsets = some_user_toolsets.value
1297
+ else:
1298
+ user_toolsets = [*self._user_toolsets, *self._dynamic_toolsets]
1299
+ toolsets.extend(user_toolsets)
1300
+
1301
+ return toolsets
1557
1302
 
1558
1303
  def _prepare_output_schema(
1559
1304
  self, output_type: OutputSpec[RunOutputDataT] | None, model_profile: ModelProfile
@@ -1571,47 +1316,7 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
1571
1316
 
1572
1317
  return schema # pyright: ignore[reportReturnType]
1573
1318
 
1574
- @staticmethod
1575
- def is_model_request_node(
1576
- node: _agent_graph.AgentNode[T, S] | End[result.FinalResult[S]],
1577
- ) -> TypeIs[_agent_graph.ModelRequestNode[T, S]]:
1578
- """Check if the node is a `ModelRequestNode`, narrowing the type if it is.
1579
-
1580
- This method preserves the generic parameters while narrowing the type, unlike a direct call to `isinstance`.
1581
- """
1582
- return isinstance(node, _agent_graph.ModelRequestNode)
1583
-
1584
- @staticmethod
1585
- def is_call_tools_node(
1586
- node: _agent_graph.AgentNode[T, S] | End[result.FinalResult[S]],
1587
- ) -> TypeIs[_agent_graph.CallToolsNode[T, S]]:
1588
- """Check if the node is a `CallToolsNode`, narrowing the type if it is.
1589
-
1590
- This method preserves the generic parameters while narrowing the type, unlike a direct call to `isinstance`.
1591
- """
1592
- return isinstance(node, _agent_graph.CallToolsNode)
1593
-
1594
- @staticmethod
1595
- def is_user_prompt_node(
1596
- node: _agent_graph.AgentNode[T, S] | End[result.FinalResult[S]],
1597
- ) -> TypeIs[_agent_graph.UserPromptNode[T, S]]:
1598
- """Check if the node is a `UserPromptNode`, narrowing the type if it is.
1599
-
1600
- This method preserves the generic parameters while narrowing the type, unlike a direct call to `isinstance`.
1601
- """
1602
- return isinstance(node, _agent_graph.UserPromptNode)
1603
-
1604
- @staticmethod
1605
- def is_end_node(
1606
- node: _agent_graph.AgentNode[T, S] | End[result.FinalResult[S]],
1607
- ) -> TypeIs[End[result.FinalResult[S]]]:
1608
- """Check if the node is a `End`, narrowing the type if it is.
1609
-
1610
- This method preserves the generic parameters while narrowing the type, unlike a direct call to `isinstance`.
1611
- """
1612
- return isinstance(node, End)
1613
-
1614
- async def __aenter__(self) -> Self:
1319
+ async def __aenter__(self) -> AbstractAgent[AgentDepsT, OutputDataT]:
1615
1320
  """Enter the agent context.
1616
1321
 
1617
1322
  This will start all [`MCPServerStdio`s][pydantic_ai.mcp.MCPServerStdio] registered as `toolsets` so they are ready to be used.
@@ -1645,7 +1350,7 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
1645
1350
  except exceptions.UserError as e:
1646
1351
  raise exceptions.UserError('No sampling model provided and no model set on the agent.') from e
1647
1352
 
1648
- from .mcp import MCPServer
1353
+ from ..mcp import MCPServer
1649
1354
 
1650
1355
  def _set_sampling_model(toolset: AbstractToolset[AgentDepsT]) -> None:
1651
1356
  if isinstance(toolset, MCPServer):
@@ -1676,536 +1381,13 @@ class Agent(Generic[AgentDepsT, OutputDataT]):
1676
1381
  async with self:
1677
1382
  yield
1678
1383
 
1679
- def to_ag_ui(
1680
- self,
1681
- *,
1682
- # Agent.iter parameters
1683
- output_type: OutputSpec[OutputDataT] | None = None,
1684
- model: models.Model | models.KnownModelName | str | None = None,
1685
- deps: AgentDepsT = None,
1686
- model_settings: ModelSettings | None = None,
1687
- usage_limits: UsageLimits | None = None,
1688
- usage: Usage | None = None,
1689
- infer_name: bool = True,
1690
- toolsets: Sequence[AbstractToolset[AgentDepsT]] | None = None,
1691
- # Starlette
1692
- debug: bool = False,
1693
- routes: Sequence[BaseRoute] | None = None,
1694
- middleware: Sequence[Middleware] | None = None,
1695
- exception_handlers: Mapping[Any, ExceptionHandler] | None = None,
1696
- on_startup: Sequence[Callable[[], Any]] | None = None,
1697
- on_shutdown: Sequence[Callable[[], Any]] | None = None,
1698
- lifespan: Lifespan[AGUIApp[AgentDepsT, OutputDataT]] | None = None,
1699
- ) -> AGUIApp[AgentDepsT, OutputDataT]:
1700
- """Returns an ASGI application that handles every AG-UI request by running the agent.
1701
-
1702
- Note that the `deps` will be the same for each request, with the exception of the AG-UI state that's
1703
- injected into the `state` field of a `deps` object that implements the [`StateHandler`][pydantic_ai.ag_ui.StateHandler] protocol.
1704
- To provide different `deps` for each request (e.g. based on the authenticated user),
1705
- use [`pydantic_ai.ag_ui.run_ag_ui`][pydantic_ai.ag_ui.run_ag_ui] or
1706
- [`pydantic_ai.ag_ui.handle_ag_ui_request`][pydantic_ai.ag_ui.handle_ag_ui_request] instead.
1707
-
1708
- Example:
1709
- ```python
1710
- from pydantic_ai import Agent
1711
-
1712
- agent = Agent('openai:gpt-4o')
1713
- app = agent.to_ag_ui()
1714
- ```
1715
-
1716
- To run the application, you can use the following command:
1717
-
1718
- ```bash
1719
- uvicorn app:app --host 0.0.0.0 --port 8000
1720
- ```
1721
-
1722
- See [AG-UI docs](../ag-ui.md) for more information.
1723
-
1724
- Args:
1725
- output_type: Custom output type to use for this run, `output_type` may only be used if the agent has
1726
- no output validators since output validators would expect an argument that matches the agent's
1727
- output type.
1728
- model: Optional model to use for this run, required if `model` was not set when creating the agent.
1729
- deps: Optional dependencies to use for this run.
1730
- model_settings: Optional settings to use for this model's request.
1731
- usage_limits: Optional limits on model request count or token usage.
1732
- usage: Optional usage to start with, useful for resuming a conversation or agents used in tools.
1733
- infer_name: Whether to try to infer the agent name from the call frame if it's not set.
1734
- toolsets: Optional additional toolsets for this run.
1735
-
1736
- debug: Boolean indicating if debug tracebacks should be returned on errors.
1737
- routes: A list of routes to serve incoming HTTP and WebSocket requests.
1738
- middleware: A list of middleware to run for every request. A starlette application will always
1739
- automatically include two middleware classes. `ServerErrorMiddleware` is added as the very
1740
- outermost middleware, to handle any uncaught errors occurring anywhere in the entire stack.
1741
- `ExceptionMiddleware` is added as the very innermost middleware, to deal with handled
1742
- exception cases occurring in the routing or endpoints.
1743
- exception_handlers: A mapping of either integer status codes, or exception class types onto
1744
- callables which handle the exceptions. Exception handler callables should be of the form
1745
- `handler(request, exc) -> response` and may be either standard functions, or async functions.
1746
- on_startup: A list of callables to run on application startup. Startup handler callables do not
1747
- take any arguments, and may be either standard functions, or async functions.
1748
- on_shutdown: A list of callables to run on application shutdown. Shutdown handler callables do
1749
- not take any arguments, and may be either standard functions, or async functions.
1750
- lifespan: A lifespan context function, which can be used to perform startup and shutdown tasks.
1751
- This is a newer style that replaces the `on_startup` and `on_shutdown` handlers. Use one or
1752
- the other, not both.
1753
-
1754
- Returns:
1755
- An ASGI application for running Pydantic AI agents with AG-UI protocol support.
1756
- """
1757
- from .ag_ui import AGUIApp
1758
-
1759
- return AGUIApp(
1760
- agent=self,
1761
- # Agent.iter parameters
1762
- output_type=output_type,
1763
- model=model,
1764
- deps=deps,
1765
- model_settings=model_settings,
1766
- usage_limits=usage_limits,
1767
- usage=usage,
1768
- infer_name=infer_name,
1769
- toolsets=toolsets,
1770
- # Starlette
1771
- debug=debug,
1772
- routes=routes,
1773
- middleware=middleware,
1774
- exception_handlers=exception_handlers,
1775
- on_startup=on_startup,
1776
- on_shutdown=on_shutdown,
1777
- lifespan=lifespan,
1778
- )
1779
-
1780
- def to_a2a(
1781
- self,
1782
- *,
1783
- storage: Storage | None = None,
1784
- broker: Broker | None = None,
1785
- # Agent card
1786
- name: str | None = None,
1787
- url: str = 'http://localhost:8000',
1788
- version: str = '1.0.0',
1789
- description: str | None = None,
1790
- provider: AgentProvider | None = None,
1791
- skills: list[Skill] | None = None,
1792
- # Starlette
1793
- debug: bool = False,
1794
- routes: Sequence[Route] | None = None,
1795
- middleware: Sequence[Middleware] | None = None,
1796
- exception_handlers: dict[Any, ExceptionHandler] | None = None,
1797
- lifespan: Lifespan[FastA2A] | None = None,
1798
- ) -> FastA2A:
1799
- """Convert the agent to a FastA2A application.
1800
-
1801
- Example:
1802
- ```python
1803
- from pydantic_ai import Agent
1804
-
1805
- agent = Agent('openai:gpt-4o')
1806
- app = agent.to_a2a()
1807
- ```
1808
-
1809
- The `app` is an ASGI application that can be used with any ASGI server.
1810
-
1811
- To run the application, you can use the following command:
1812
-
1813
- ```bash
1814
- uvicorn app:app --host 0.0.0.0 --port 8000
1815
- ```
1816
- """
1817
- from ._a2a import agent_to_a2a
1818
-
1819
- return agent_to_a2a(
1820
- self,
1821
- storage=storage,
1822
- broker=broker,
1823
- name=name,
1824
- url=url,
1825
- version=version,
1826
- description=description,
1827
- provider=provider,
1828
- skills=skills,
1829
- debug=debug,
1830
- routes=routes,
1831
- middleware=middleware,
1832
- exception_handlers=exception_handlers,
1833
- lifespan=lifespan,
1834
- )
1835
-
1836
- async def to_cli(self: Self, deps: AgentDepsT = None, prog_name: str = 'pydantic-ai') -> None:
1837
- """Run the agent in a CLI chat interface.
1838
-
1839
- Args:
1840
- deps: The dependencies to pass to the agent.
1841
- prog_name: The name of the program to use for the CLI. Defaults to 'pydantic-ai'.
1842
-
1843
- Example:
1844
- ```python {title="agent_to_cli.py" test="skip"}
1845
- from pydantic_ai import Agent
1846
-
1847
- agent = Agent('openai:gpt-4o', instructions='You always respond in Italian.')
1848
-
1849
- async def main():
1850
- await agent.to_cli()
1851
- ```
1852
- """
1853
- from rich.console import Console
1854
-
1855
- from pydantic_ai._cli import run_chat
1856
-
1857
- await run_chat(stream=True, agent=self, deps=deps, console=Console(), code_theme='monokai', prog_name=prog_name)
1858
-
1859
- def to_cli_sync(self: Self, deps: AgentDepsT = None, prog_name: str = 'pydantic-ai') -> None:
1860
- """Run the agent in a CLI chat interface with the non-async interface.
1861
-
1862
- Args:
1863
- deps: The dependencies to pass to the agent.
1864
- prog_name: The name of the program to use for the CLI. Defaults to 'pydantic-ai'.
1865
-
1866
- ```python {title="agent_to_cli_sync.py" test="skip"}
1867
- from pydantic_ai import Agent
1868
-
1869
- agent = Agent('openai:gpt-4o', instructions='You always respond in Italian.')
1870
- agent.to_cli_sync()
1871
- agent.to_cli_sync(prog_name='assistant')
1872
- ```
1873
- """
1874
- return get_event_loop().run_until_complete(self.to_cli(deps=deps, prog_name=prog_name))
1875
-
1876
-
1877
- @dataclasses.dataclass(repr=False)
1878
- class AgentRun(Generic[AgentDepsT, OutputDataT]):
1879
- """A stateful, async-iterable run of an [`Agent`][pydantic_ai.agent.Agent].
1880
-
1881
- You generally obtain an `AgentRun` instance by calling `async with my_agent.iter(...) as agent_run:`.
1882
-
1883
- Once you have an instance, you can use it to iterate through the run's nodes as they execute. When an
1884
- [`End`][pydantic_graph.nodes.End] is reached, the run finishes and [`result`][pydantic_ai.agent.AgentRun.result]
1885
- becomes available.
1886
-
1887
- Example:
1888
- ```python
1889
- from pydantic_ai import Agent
1890
-
1891
- agent = Agent('openai:gpt-4o')
1892
-
1893
- async def main():
1894
- nodes = []
1895
- # Iterate through the run, recording each node along the way:
1896
- async with agent.iter('What is the capital of France?') as agent_run:
1897
- async for node in agent_run:
1898
- nodes.append(node)
1899
- print(nodes)
1900
- '''
1901
- [
1902
- UserPromptNode(
1903
- user_prompt='What is the capital of France?',
1904
- instructions=None,
1905
- instructions_functions=[],
1906
- system_prompts=(),
1907
- system_prompt_functions=[],
1908
- system_prompt_dynamic_functions={},
1909
- ),
1910
- ModelRequestNode(
1911
- request=ModelRequest(
1912
- parts=[
1913
- UserPromptPart(
1914
- content='What is the capital of France?',
1915
- timestamp=datetime.datetime(...),
1916
- )
1917
- ]
1918
- )
1919
- ),
1920
- CallToolsNode(
1921
- model_response=ModelResponse(
1922
- parts=[TextPart(content='Paris')],
1923
- usage=Usage(
1924
- requests=1, request_tokens=56, response_tokens=1, total_tokens=57
1925
- ),
1926
- model_name='gpt-4o',
1927
- timestamp=datetime.datetime(...),
1928
- )
1929
- ),
1930
- End(data=FinalResult(output='Paris')),
1931
- ]
1932
- '''
1933
- print(agent_run.result.output)
1934
- #> Paris
1935
- ```
1936
-
1937
- You can also manually drive the iteration using the [`next`][pydantic_ai.agent.AgentRun.next] method for
1938
- more granular control.
1939
- """
1940
-
1941
- _graph_run: GraphRun[
1942
- _agent_graph.GraphAgentState, _agent_graph.GraphAgentDeps[AgentDepsT, Any], FinalResult[OutputDataT]
1943
- ]
1944
-
1945
- @overload
1946
- def _traceparent(self, *, required: Literal[False]) -> str | None: ...
1947
- @overload
1948
- def _traceparent(self) -> str: ...
1949
- def _traceparent(self, *, required: bool = True) -> str | None:
1950
- traceparent = self._graph_run._traceparent(required=False) # type: ignore[reportPrivateUsage]
1951
- if traceparent is None and required: # pragma: no cover
1952
- raise AttributeError('No span was created for this agent run')
1953
- return traceparent
1954
-
1955
- @property
1956
- def ctx(self) -> GraphRunContext[_agent_graph.GraphAgentState, _agent_graph.GraphAgentDeps[AgentDepsT, Any]]:
1957
- """The current context of the agent run."""
1958
- return GraphRunContext[_agent_graph.GraphAgentState, _agent_graph.GraphAgentDeps[AgentDepsT, Any]](
1959
- self._graph_run.state, self._graph_run.deps
1960
- )
1961
1384
 
1385
+ @dataclasses.dataclass(init=False)
1386
+ class _AgentFunctionToolset(FunctionToolset[AgentDepsT]):
1962
1387
  @property
1963
- def next_node(
1964
- self,
1965
- ) -> _agent_graph.AgentNode[AgentDepsT, OutputDataT] | End[FinalResult[OutputDataT]]:
1966
- """The next node that will be run in the agent graph.
1967
-
1968
- This is the next node that will be used during async iteration, or if a node is not passed to `self.next(...)`.
1969
- """
1970
- next_node = self._graph_run.next_node
1971
- if isinstance(next_node, End):
1972
- return next_node
1973
- if _agent_graph.is_agent_node(next_node):
1974
- return next_node
1975
- raise exceptions.AgentRunError(f'Unexpected node type: {type(next_node)}') # pragma: no cover
1388
+ def id(self) -> str:
1389
+ return '<agent>'
1976
1390
 
1977
1391
  @property
1978
- def result(self) -> AgentRunResult[OutputDataT] | None:
1979
- """The final result of the run if it has ended, otherwise `None`.
1980
-
1981
- Once the run returns an [`End`][pydantic_graph.nodes.End] node, `result` is populated
1982
- with an [`AgentRunResult`][pydantic_ai.agent.AgentRunResult].
1983
- """
1984
- graph_run_result = self._graph_run.result
1985
- if graph_run_result is None:
1986
- return None
1987
- return AgentRunResult(
1988
- graph_run_result.output.output,
1989
- graph_run_result.output.tool_name,
1990
- graph_run_result.state,
1991
- self._graph_run.deps.new_message_index,
1992
- self._traceparent(required=False),
1993
- )
1994
-
1995
- def __aiter__(
1996
- self,
1997
- ) -> AsyncIterator[_agent_graph.AgentNode[AgentDepsT, OutputDataT] | End[FinalResult[OutputDataT]]]:
1998
- """Provide async-iteration over the nodes in the agent run."""
1999
- return self
2000
-
2001
- async def __anext__(
2002
- self,
2003
- ) -> _agent_graph.AgentNode[AgentDepsT, OutputDataT] | End[FinalResult[OutputDataT]]:
2004
- """Advance to the next node automatically based on the last returned node."""
2005
- next_node = await self._graph_run.__anext__()
2006
- if _agent_graph.is_agent_node(node=next_node):
2007
- return next_node
2008
- assert isinstance(next_node, End), f'Unexpected node type: {type(next_node)}'
2009
- return next_node
2010
-
2011
- async def next(
2012
- self,
2013
- node: _agent_graph.AgentNode[AgentDepsT, OutputDataT],
2014
- ) -> _agent_graph.AgentNode[AgentDepsT, OutputDataT] | End[FinalResult[OutputDataT]]:
2015
- """Manually drive the agent run by passing in the node you want to run next.
2016
-
2017
- This lets you inspect or mutate the node before continuing execution, or skip certain nodes
2018
- under dynamic conditions. The agent run should be stopped when you return an [`End`][pydantic_graph.nodes.End]
2019
- node.
2020
-
2021
- Example:
2022
- ```python
2023
- from pydantic_ai import Agent
2024
- from pydantic_graph import End
2025
-
2026
- agent = Agent('openai:gpt-4o')
2027
-
2028
- async def main():
2029
- async with agent.iter('What is the capital of France?') as agent_run:
2030
- next_node = agent_run.next_node # start with the first node
2031
- nodes = [next_node]
2032
- while not isinstance(next_node, End):
2033
- next_node = await agent_run.next(next_node)
2034
- nodes.append(next_node)
2035
- # Once `next_node` is an End, we've finished:
2036
- print(nodes)
2037
- '''
2038
- [
2039
- UserPromptNode(
2040
- user_prompt='What is the capital of France?',
2041
- instructions=None,
2042
- instructions_functions=[],
2043
- system_prompts=(),
2044
- system_prompt_functions=[],
2045
- system_prompt_dynamic_functions={},
2046
- ),
2047
- ModelRequestNode(
2048
- request=ModelRequest(
2049
- parts=[
2050
- UserPromptPart(
2051
- content='What is the capital of France?',
2052
- timestamp=datetime.datetime(...),
2053
- )
2054
- ]
2055
- )
2056
- ),
2057
- CallToolsNode(
2058
- model_response=ModelResponse(
2059
- parts=[TextPart(content='Paris')],
2060
- usage=Usage(
2061
- requests=1,
2062
- request_tokens=56,
2063
- response_tokens=1,
2064
- total_tokens=57,
2065
- ),
2066
- model_name='gpt-4o',
2067
- timestamp=datetime.datetime(...),
2068
- )
2069
- ),
2070
- End(data=FinalResult(output='Paris')),
2071
- ]
2072
- '''
2073
- print('Final result:', agent_run.result.output)
2074
- #> Final result: Paris
2075
- ```
2076
-
2077
- Args:
2078
- node: The node to run next in the graph.
2079
-
2080
- Returns:
2081
- The next node returned by the graph logic, or an [`End`][pydantic_graph.nodes.End] node if
2082
- the run has completed.
2083
- """
2084
- # Note: It might be nice to expose a synchronous interface for iteration, but we shouldn't do it
2085
- # on this class, or else IDEs won't warn you if you accidentally use `for` instead of `async for` to iterate.
2086
- next_node = await self._graph_run.next(node)
2087
- if _agent_graph.is_agent_node(next_node):
2088
- return next_node
2089
- assert isinstance(next_node, End), f'Unexpected node type: {type(next_node)}'
2090
- return next_node
2091
-
2092
- def usage(self) -> _usage.Usage:
2093
- """Get usage statistics for the run so far, including token usage, model requests, and so on."""
2094
- return self._graph_run.state.usage
2095
-
2096
- def __repr__(self) -> str: # pragma: no cover
2097
- result = self._graph_run.result
2098
- result_repr = '<run not finished>' if result is None else repr(result.output)
2099
- return f'<{type(self).__name__} result={result_repr} usage={self.usage()}>'
2100
-
2101
-
2102
- @dataclasses.dataclass
2103
- class AgentRunResult(Generic[OutputDataT]):
2104
- """The final result of an agent run."""
2105
-
2106
- output: OutputDataT
2107
- """The output data from the agent run."""
2108
-
2109
- _output_tool_name: str | None = dataclasses.field(repr=False)
2110
- _state: _agent_graph.GraphAgentState = dataclasses.field(repr=False)
2111
- _new_message_index: int = dataclasses.field(repr=False)
2112
- _traceparent_value: str | None = dataclasses.field(repr=False)
2113
-
2114
- @overload
2115
- def _traceparent(self, *, required: Literal[False]) -> str | None: ...
2116
- @overload
2117
- def _traceparent(self) -> str: ...
2118
- def _traceparent(self, *, required: bool = True) -> str | None:
2119
- if self._traceparent_value is None and required: # pragma: no cover
2120
- raise AttributeError('No span was created for this agent run')
2121
- return self._traceparent_value
2122
-
2123
- def _set_output_tool_return(self, return_content: str) -> list[_messages.ModelMessage]:
2124
- """Set return content for the output tool.
2125
-
2126
- Useful if you want to continue the conversation and want to set the response to the output tool call.
2127
- """
2128
- if not self._output_tool_name:
2129
- raise ValueError('Cannot set output tool return content when the return type is `str`.')
2130
-
2131
- messages = self._state.message_history
2132
- last_message = messages[-1]
2133
- for idx, part in enumerate(last_message.parts):
2134
- if isinstance(part, _messages.ToolReturnPart) and part.tool_name == self._output_tool_name:
2135
- # Only do deepcopy when we have to modify
2136
- copied_messages = list(messages)
2137
- copied_last = deepcopy(last_message)
2138
- copied_last.parts[idx].content = return_content # type: ignore[misc]
2139
- copied_messages[-1] = copied_last
2140
- return copied_messages
2141
-
2142
- raise LookupError(f'No tool call found with tool name {self._output_tool_name!r}.')
2143
-
2144
- def all_messages(self, *, output_tool_return_content: str | None = None) -> list[_messages.ModelMessage]:
2145
- """Return the history of _messages.
2146
-
2147
- Args:
2148
- output_tool_return_content: The return content of the tool call to set in the last message.
2149
- This provides a convenient way to modify the content of the output tool call if you want to continue
2150
- the conversation and want to set the response to the output tool call. If `None`, the last message will
2151
- not be modified.
2152
-
2153
- Returns:
2154
- List of messages.
2155
- """
2156
- if output_tool_return_content is not None:
2157
- return self._set_output_tool_return(output_tool_return_content)
2158
- else:
2159
- return self._state.message_history
2160
-
2161
- def all_messages_json(self, *, output_tool_return_content: str | None = None) -> bytes:
2162
- """Return all messages from [`all_messages`][pydantic_ai.agent.AgentRunResult.all_messages] as JSON bytes.
2163
-
2164
- Args:
2165
- output_tool_return_content: The return content of the tool call to set in the last message.
2166
- This provides a convenient way to modify the content of the output tool call if you want to continue
2167
- the conversation and want to set the response to the output tool call. If `None`, the last message will
2168
- not be modified.
2169
-
2170
- Returns:
2171
- JSON bytes representing the messages.
2172
- """
2173
- return _messages.ModelMessagesTypeAdapter.dump_json(
2174
- self.all_messages(output_tool_return_content=output_tool_return_content)
2175
- )
2176
-
2177
- def new_messages(self, *, output_tool_return_content: str | None = None) -> list[_messages.ModelMessage]:
2178
- """Return new messages associated with this run.
2179
-
2180
- Messages from older runs are excluded.
2181
-
2182
- Args:
2183
- output_tool_return_content: The return content of the tool call to set in the last message.
2184
- This provides a convenient way to modify the content of the output tool call if you want to continue
2185
- the conversation and want to set the response to the output tool call. If `None`, the last message will
2186
- not be modified.
2187
-
2188
- Returns:
2189
- List of new messages.
2190
- """
2191
- return self.all_messages(output_tool_return_content=output_tool_return_content)[self._new_message_index :]
2192
-
2193
- def new_messages_json(self, *, output_tool_return_content: str | None = None) -> bytes:
2194
- """Return new messages from [`new_messages`][pydantic_ai.agent.AgentRunResult.new_messages] as JSON bytes.
2195
-
2196
- Args:
2197
- output_tool_return_content: The return content of the tool call to set in the last message.
2198
- This provides a convenient way to modify the content of the output tool call if you want to continue
2199
- the conversation and want to set the response to the output tool call. If `None`, the last message will
2200
- not be modified.
2201
-
2202
- Returns:
2203
- JSON bytes representing the new messages.
2204
- """
2205
- return _messages.ModelMessagesTypeAdapter.dump_json(
2206
- self.new_messages(output_tool_return_content=output_tool_return_content)
2207
- )
2208
-
2209
- def usage(self) -> _usage.Usage:
2210
- """Return the usage of the whole run."""
2211
- return self._state.usage
1392
+ def label(self) -> str:
1393
+ return 'the agent'