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