pydantic-ai-slim 1.0.11__py3-none-any.whl → 1.0.13__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 (80) hide show
  1. pydantic_ai/__init__.py +134 -4
  2. pydantic_ai/_a2a.py +1 -1
  3. pydantic_ai/_agent_graph.py +4 -0
  4. pydantic_ai/_instrumentation.py +95 -0
  5. pydantic_ai/{profiles/_json_schema.py → _json_schema.py} +5 -3
  6. pydantic_ai/_output.py +26 -12
  7. pydantic_ai/_run_context.py +4 -0
  8. pydantic_ai/_thinking_part.py +1 -1
  9. pydantic_ai/_tool_manager.py +15 -7
  10. pydantic_ai/_utils.py +24 -7
  11. pydantic_ai/agent/__init__.py +68 -36
  12. pydantic_ai/agent/abstract.py +12 -1
  13. pydantic_ai/agent/wrapper.py +11 -3
  14. pydantic_ai/builtin_tools.py +20 -1
  15. pydantic_ai/common_tools/duckduckgo.py +2 -2
  16. pydantic_ai/common_tools/tavily.py +2 -2
  17. pydantic_ai/direct.py +6 -6
  18. pydantic_ai/durable_exec/dbos/_agent.py +12 -3
  19. pydantic_ai/durable_exec/dbos/_mcp_server.py +1 -2
  20. pydantic_ai/durable_exec/dbos/_model.py +2 -2
  21. pydantic_ai/durable_exec/temporal/_agent.py +13 -4
  22. pydantic_ai/durable_exec/temporal/_function_toolset.py +1 -1
  23. pydantic_ai/durable_exec/temporal/_mcp_server.py +1 -1
  24. pydantic_ai/durable_exec/temporal/_model.py +3 -3
  25. pydantic_ai/durable_exec/temporal/_toolset.py +1 -3
  26. pydantic_ai/ext/aci.py +1 -1
  27. pydantic_ai/ext/langchain.py +1 -1
  28. pydantic_ai/mcp.py +32 -8
  29. pydantic_ai/messages.py +14 -11
  30. pydantic_ai/models/__init__.py +19 -2
  31. pydantic_ai/models/anthropic.py +29 -14
  32. pydantic_ai/models/bedrock.py +14 -5
  33. pydantic_ai/models/cohere.py +4 -0
  34. pydantic_ai/models/fallback.py +2 -9
  35. pydantic_ai/models/function.py +8 -0
  36. pydantic_ai/models/gemini.py +8 -0
  37. pydantic_ai/models/google.py +14 -2
  38. pydantic_ai/models/groq.py +8 -0
  39. pydantic_ai/models/huggingface.py +8 -2
  40. pydantic_ai/models/instrumented.py +16 -6
  41. pydantic_ai/models/mcp_sampling.py +2 -0
  42. pydantic_ai/models/mistral.py +8 -0
  43. pydantic_ai/models/openai.py +95 -29
  44. pydantic_ai/models/test.py +8 -0
  45. pydantic_ai/models/wrapper.py +7 -0
  46. pydantic_ai/output.py +11 -1
  47. pydantic_ai/profiles/__init__.py +1 -1
  48. pydantic_ai/profiles/google.py +1 -1
  49. pydantic_ai/profiles/openai.py +1 -1
  50. pydantic_ai/providers/__init__.py +1 -1
  51. pydantic_ai/providers/anthropic.py +1 -1
  52. pydantic_ai/providers/azure.py +1 -1
  53. pydantic_ai/providers/bedrock.py +1 -1
  54. pydantic_ai/providers/cerebras.py +1 -1
  55. pydantic_ai/providers/cohere.py +1 -1
  56. pydantic_ai/providers/deepseek.py +1 -1
  57. pydantic_ai/providers/fireworks.py +1 -1
  58. pydantic_ai/providers/github.py +1 -1
  59. pydantic_ai/providers/google.py +1 -1
  60. pydantic_ai/providers/google_gla.py +1 -1
  61. pydantic_ai/providers/google_vertex.py +1 -1
  62. pydantic_ai/providers/grok.py +1 -1
  63. pydantic_ai/providers/groq.py +1 -1
  64. pydantic_ai/providers/heroku.py +1 -1
  65. pydantic_ai/providers/huggingface.py +1 -1
  66. pydantic_ai/providers/litellm.py +1 -1
  67. pydantic_ai/providers/mistral.py +1 -1
  68. pydantic_ai/providers/moonshotai.py +1 -1
  69. pydantic_ai/providers/ollama.py +1 -1
  70. pydantic_ai/providers/openai.py +1 -1
  71. pydantic_ai/providers/openrouter.py +1 -1
  72. pydantic_ai/providers/together.py +1 -1
  73. pydantic_ai/providers/vercel.py +1 -1
  74. pydantic_ai/toolsets/function.py +1 -2
  75. {pydantic_ai_slim-1.0.11.dist-info → pydantic_ai_slim-1.0.13.dist-info}/METADATA +3 -3
  76. pydantic_ai_slim-1.0.13.dist-info/RECORD +128 -0
  77. pydantic_ai_slim-1.0.11.dist-info/RECORD +0 -127
  78. {pydantic_ai_slim-1.0.11.dist-info → pydantic_ai_slim-1.0.13.dist-info}/WHEEL +0 -0
  79. {pydantic_ai_slim-1.0.11.dist-info → pydantic_ai_slim-1.0.13.dist-info}/entry_points.txt +0 -0
  80. {pydantic_ai_slim-1.0.11.dist-info → pydantic_ai_slim-1.0.13.dist-info}/licenses/LICENSE +0 -0
@@ -14,6 +14,7 @@ from opentelemetry.trace import NoOpTracer, use_span
14
14
  from pydantic.json_schema import GenerateJsonSchema
15
15
  from typing_extensions import Self, TypeVar, deprecated
16
16
 
17
+ from pydantic_ai._instrumentation import DEFAULT_INSTRUMENTATION_VERSION, InstrumentationNames
17
18
  from pydantic_graph import Graph
18
19
 
19
20
  from .. import (
@@ -65,7 +66,7 @@ from ..toolsets._dynamic import (
65
66
  from ..toolsets.combined import CombinedToolset
66
67
  from ..toolsets.function import FunctionToolset
67
68
  from ..toolsets.prepared import PreparedToolset
68
- from .abstract import AbstractAgent, EventStreamHandler, RunOutputDataT
69
+ from .abstract import AbstractAgent, EventStreamHandler, Instructions, RunOutputDataT
69
70
  from .wrapper import WrapperAgent
70
71
 
71
72
  if TYPE_CHECKING:
@@ -136,8 +137,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
136
137
  _deps_type: type[AgentDepsT] = dataclasses.field(repr=False)
137
138
  _output_schema: _output.BaseOutputSchema[OutputDataT] = dataclasses.field(repr=False)
138
139
  _output_validators: list[_output.OutputValidator[AgentDepsT, OutputDataT]] = dataclasses.field(repr=False)
139
- _instructions: str | None = dataclasses.field(repr=False)
140
- _instructions_functions: list[_system_prompt.SystemPromptRunner[AgentDepsT]] = dataclasses.field(repr=False)
140
+ _instructions: list[str | _system_prompt.SystemPromptFunc[AgentDepsT]] = dataclasses.field(repr=False)
141
141
  _system_prompts: tuple[str, ...] = dataclasses.field(repr=False)
142
142
  _system_prompt_functions: list[_system_prompt.SystemPromptRunner[AgentDepsT]] = dataclasses.field(repr=False)
143
143
  _system_prompt_dynamic_functions: dict[str, _system_prompt.SystemPromptRunner[AgentDepsT]] = dataclasses.field(
@@ -163,10 +163,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
163
163
  model: models.Model | models.KnownModelName | str | None = None,
164
164
  *,
165
165
  output_type: OutputSpec[OutputDataT] = str,
166
- instructions: str
167
- | _system_prompt.SystemPromptFunc[AgentDepsT]
168
- | Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
169
- | None = None,
166
+ instructions: Instructions[AgentDepsT] = None,
170
167
  system_prompt: str | Sequence[str] = (),
171
168
  deps_type: type[AgentDepsT] = NoneType,
172
169
  name: str | None = None,
@@ -192,10 +189,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
192
189
  model: models.Model | models.KnownModelName | str | None = None,
193
190
  *,
194
191
  output_type: OutputSpec[OutputDataT] = str,
195
- instructions: str
196
- | _system_prompt.SystemPromptFunc[AgentDepsT]
197
- | Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
198
- | None = None,
192
+ instructions: Instructions[AgentDepsT] = None,
199
193
  system_prompt: str | Sequence[str] = (),
200
194
  deps_type: type[AgentDepsT] = NoneType,
201
195
  name: str | None = None,
@@ -219,10 +213,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
219
213
  model: models.Model | models.KnownModelName | str | None = None,
220
214
  *,
221
215
  output_type: OutputSpec[OutputDataT] = str,
222
- instructions: str
223
- | _system_prompt.SystemPromptFunc[AgentDepsT]
224
- | Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
225
- | None = None,
216
+ instructions: Instructions[AgentDepsT] = None,
226
217
  system_prompt: str | Sequence[str] = (),
227
218
  deps_type: type[AgentDepsT] = NoneType,
228
219
  name: str | None = None,
@@ -321,16 +312,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
321
312
  self._output_schema = _output.OutputSchema[OutputDataT].build(output_type, default_mode=default_output_mode)
322
313
  self._output_validators = []
323
314
 
324
- self._instructions = ''
325
- self._instructions_functions = []
326
- if isinstance(instructions, str | Callable):
327
- instructions = [instructions]
328
- for instruction in instructions or []:
329
- if isinstance(instruction, str):
330
- self._instructions += instruction + '\n'
331
- else:
332
- self._instructions_functions.append(_system_prompt.SystemPromptRunner(instruction))
333
- self._instructions = self._instructions.strip() or None
315
+ self._instructions = self._normalize_instructions(instructions)
334
316
 
335
317
  self._system_prompts = (system_prompt,) if isinstance(system_prompt, str) else tuple(system_prompt)
336
318
  self._system_prompt_functions = []
@@ -370,6 +352,9 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
370
352
  self._override_tools: ContextVar[
371
353
  _utils.Option[Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]]]
372
354
  ] = ContextVar('_override_tools', default=None)
355
+ self._override_instructions: ContextVar[
356
+ _utils.Option[list[str | _system_prompt.SystemPromptFunc[AgentDepsT]]]
357
+ ] = ContextVar('_override_instructions', default=None)
373
358
 
374
359
  self._enter_lock = Lock()
375
360
  self._entered_count = 0
@@ -592,10 +577,12 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
592
577
  model_settings = merge_model_settings(merged_settings, model_settings)
593
578
  usage_limits = usage_limits or _usage.UsageLimits()
594
579
 
580
+ instructions_literal, instructions_functions = self._get_instructions()
581
+
595
582
  async def get_instructions(run_context: RunContext[AgentDepsT]) -> str | None:
596
583
  parts = [
597
- self._instructions,
598
- *[await func.run(run_context) for func in self._instructions_functions],
584
+ instructions_literal,
585
+ *[await func.run(run_context) for func in instructions_functions],
599
586
  ]
600
587
 
601
588
  model_profile = model_used.profile
@@ -633,22 +620,28 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
633
620
  get_instructions=get_instructions,
634
621
  instrumentation_settings=instrumentation_settings,
635
622
  )
623
+
636
624
  start_node = _agent_graph.UserPromptNode[AgentDepsT](
637
625
  user_prompt=user_prompt,
638
626
  deferred_tool_results=deferred_tool_results,
639
- instructions=self._instructions,
640
- instructions_functions=self._instructions_functions,
627
+ instructions=instructions_literal,
628
+ instructions_functions=instructions_functions,
641
629
  system_prompts=self._system_prompts,
642
630
  system_prompt_functions=self._system_prompt_functions,
643
631
  system_prompt_dynamic_functions=self._system_prompt_dynamic_functions,
644
632
  )
645
633
 
646
634
  agent_name = self.name or 'agent'
635
+ instrumentation_names = InstrumentationNames.for_version(
636
+ instrumentation_settings.version if instrumentation_settings else DEFAULT_INSTRUMENTATION_VERSION
637
+ )
638
+
647
639
  run_span = tracer.start_span(
648
- 'agent run',
640
+ instrumentation_names.get_agent_run_span_name(agent_name),
649
641
  attributes={
650
642
  'model_name': model_used.model_name if model_used else 'no-model',
651
643
  'agent_name': agent_name,
644
+ 'gen_ai.agent.name': agent_name,
652
645
  'logfire.msg': f'{agent_name} run',
653
646
  },
654
647
  )
@@ -684,6 +677,8 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
684
677
  def _run_span_end_attributes(
685
678
  self, state: _agent_graph.GraphAgentState, usage: _usage.RunUsage, settings: InstrumentationSettings
686
679
  ):
680
+ literal_instructions, _ = self._get_instructions()
681
+
687
682
  if settings.version == 1:
688
683
  attrs = {
689
684
  'all_messages_events': json.dumps(
@@ -696,7 +691,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
696
691
  else:
697
692
  attrs = {
698
693
  'pydantic_ai.all_messages': json.dumps(settings.messages_to_otel_messages(state.message_history)),
699
- **settings.system_instructions_attributes(self._instructions),
694
+ **settings.system_instructions_attributes(literal_instructions),
700
695
  }
701
696
 
702
697
  return {
@@ -721,8 +716,9 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
721
716
  model: models.Model | models.KnownModelName | str | _utils.Unset = _utils.UNSET,
722
717
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | _utils.Unset = _utils.UNSET,
723
718
  tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] | _utils.Unset = _utils.UNSET,
719
+ instructions: Instructions[AgentDepsT] | _utils.Unset = _utils.UNSET,
724
720
  ) -> Iterator[None]:
725
- """Context manager to temporarily override agent dependencies, model, toolsets, or tools.
721
+ """Context manager to temporarily override agent dependencies, model, toolsets, tools, or instructions.
726
722
 
727
723
  This is particularly useful when testing.
728
724
  You can find an example of this [here](../testing.md#overriding-model-via-pytest-fixtures).
@@ -732,6 +728,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
732
728
  model: The model to use instead of the model passed to the agent run.
733
729
  toolsets: The toolsets to use instead of the toolsets passed to the agent constructor and agent run.
734
730
  tools: The tools to use instead of the tools registered with the agent.
731
+ instructions: The instructions to use instead of the instructions registered with the agent.
735
732
  """
736
733
  if _utils.is_set(deps):
737
734
  deps_token = self._override_deps.set(_utils.Some(deps))
@@ -753,6 +750,12 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
753
750
  else:
754
751
  tools_token = None
755
752
 
753
+ if _utils.is_set(instructions):
754
+ normalized_instructions = self._normalize_instructions(instructions)
755
+ instructions_token = self._override_instructions.set(_utils.Some(normalized_instructions))
756
+ else:
757
+ instructions_token = None
758
+
756
759
  try:
757
760
  yield
758
761
  finally:
@@ -764,6 +767,8 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
764
767
  self._override_toolsets.reset(toolsets_token)
765
768
  if tools_token is not None:
766
769
  self._override_tools.reset(tools_token)
770
+ if instructions_token is not None:
771
+ self._override_instructions.reset(instructions_token)
767
772
 
768
773
  @overload
769
774
  def instructions(
@@ -824,12 +829,12 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
824
829
  def decorator(
825
830
  func_: _system_prompt.SystemPromptFunc[AgentDepsT],
826
831
  ) -> _system_prompt.SystemPromptFunc[AgentDepsT]:
827
- self._instructions_functions.append(_system_prompt.SystemPromptRunner(func_))
832
+ self._instructions.append(func_)
828
833
  return func_
829
834
 
830
835
  return decorator
831
836
  else:
832
- self._instructions_functions.append(_system_prompt.SystemPromptRunner(func))
837
+ self._instructions.append(func)
833
838
  return func
834
839
 
835
840
  @overload
@@ -1206,8 +1211,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1206
1211
 
1207
1212
  Example:
1208
1213
  ```python
1209
- from pydantic_ai import Agent, RunContext
1210
- from pydantic_ai.toolsets import AbstractToolset, FunctionToolset
1214
+ from pydantic_ai import AbstractToolset, Agent, FunctionToolset, RunContext
1211
1215
 
1212
1216
  agent = Agent('test', deps_type=str)
1213
1217
 
@@ -1271,6 +1275,34 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1271
1275
  else:
1272
1276
  return deps
1273
1277
 
1278
+ def _normalize_instructions(
1279
+ self,
1280
+ instructions: Instructions[AgentDepsT],
1281
+ ) -> list[str | _system_prompt.SystemPromptFunc[AgentDepsT]]:
1282
+ if instructions is None:
1283
+ return []
1284
+ if isinstance(instructions, str) or callable(instructions):
1285
+ return [instructions]
1286
+ return list(instructions)
1287
+
1288
+ def _get_instructions(
1289
+ self,
1290
+ ) -> tuple[str | None, list[_system_prompt.SystemPromptRunner[AgentDepsT]]]:
1291
+ override_instructions = self._override_instructions.get()
1292
+ instructions = override_instructions.value if override_instructions else self._instructions
1293
+
1294
+ literal_parts: list[str] = []
1295
+ functions: list[_system_prompt.SystemPromptRunner[AgentDepsT]] = []
1296
+
1297
+ for instruction in instructions:
1298
+ if isinstance(instruction, str):
1299
+ literal_parts.append(instruction)
1300
+ else:
1301
+ functions.append(_system_prompt.SystemPromptRunner[AgentDepsT](instruction))
1302
+
1303
+ literal = '\n'.join(literal_parts).strip() or None
1304
+ return literal, functions
1305
+
1274
1306
  def _get_toolset(
1275
1307
  self,
1276
1308
  output_toolset: AbstractToolset[AgentDepsT] | None | _utils.Unset = _utils.UNSET,
@@ -14,6 +14,7 @@ from pydantic_graph._utils import get_event_loop
14
14
 
15
15
  from .. import (
16
16
  _agent_graph,
17
+ _system_prompt,
17
18
  _utils,
18
19
  exceptions,
19
20
  messages as _messages,
@@ -60,6 +61,14 @@ EventStreamHandler: TypeAlias = Callable[
60
61
  """A function that receives agent [`RunContext`][pydantic_ai.tools.RunContext] and an async iterable of events from the model's streaming response and the agent's execution of tools."""
61
62
 
62
63
 
64
+ Instructions = (
65
+ str
66
+ | _system_prompt.SystemPromptFunc[AgentDepsT]
67
+ | Sequence[str | _system_prompt.SystemPromptFunc[AgentDepsT]]
68
+ | None
69
+ )
70
+
71
+
63
72
  class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
64
73
  """Abstract superclass for [`Agent`][pydantic_ai.agent.Agent], [`WrapperAgent`][pydantic_ai.agent.WrapperAgent], and your own custom agent implementations."""
65
74
 
@@ -681,8 +690,9 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
681
690
  model: models.Model | models.KnownModelName | str | _utils.Unset = _utils.UNSET,
682
691
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | _utils.Unset = _utils.UNSET,
683
692
  tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] | _utils.Unset = _utils.UNSET,
693
+ instructions: Instructions[AgentDepsT] | _utils.Unset = _utils.UNSET,
684
694
  ) -> Iterator[None]:
685
- """Context manager to temporarily override agent dependencies, model, toolsets, or tools.
695
+ """Context manager to temporarily override agent dependencies, model, toolsets, tools, or instructions.
686
696
 
687
697
  This is particularly useful when testing.
688
698
  You can find an example of this [here](../testing.md#overriding-model-via-pytest-fixtures).
@@ -692,6 +702,7 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
692
702
  model: The model to use instead of the model passed to the agent run.
693
703
  toolsets: The toolsets to use instead of the toolsets passed to the agent constructor and agent run.
694
704
  tools: The tools to use instead of the tools registered with the agent.
705
+ instructions: The instructions to use instead of the instructions registered with the agent.
695
706
  """
696
707
  raise NotImplementedError
697
708
  yield
@@ -20,7 +20,7 @@ from ..tools import (
20
20
  ToolFuncEither,
21
21
  )
22
22
  from ..toolsets import AbstractToolset
23
- from .abstract import AbstractAgent, EventStreamHandler, RunOutputDataT
23
+ from .abstract import AbstractAgent, EventStreamHandler, Instructions, RunOutputDataT
24
24
 
25
25
 
26
26
  class WrapperAgent(AbstractAgent[AgentDepsT, OutputDataT]):
@@ -214,8 +214,9 @@ class WrapperAgent(AbstractAgent[AgentDepsT, OutputDataT]):
214
214
  model: models.Model | models.KnownModelName | str | _utils.Unset = _utils.UNSET,
215
215
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | _utils.Unset = _utils.UNSET,
216
216
  tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] | _utils.Unset = _utils.UNSET,
217
+ instructions: Instructions[AgentDepsT] | _utils.Unset = _utils.UNSET,
217
218
  ) -> Iterator[None]:
218
- """Context manager to temporarily override agent dependencies, model, toolsets, or tools.
219
+ """Context manager to temporarily override agent dependencies, model, toolsets, tools, or instructions.
219
220
 
220
221
  This is particularly useful when testing.
221
222
  You can find an example of this [here](../testing.md#overriding-model-via-pytest-fixtures).
@@ -225,6 +226,13 @@ class WrapperAgent(AbstractAgent[AgentDepsT, OutputDataT]):
225
226
  model: The model to use instead of the model passed to the agent run.
226
227
  toolsets: The toolsets to use instead of the toolsets passed to the agent constructor and agent run.
227
228
  tools: The tools to use instead of the tools registered with the agent.
229
+ instructions: The instructions to use instead of the instructions registered with the agent.
228
230
  """
229
- with self.wrapped.override(deps=deps, model=model, toolsets=toolsets, tools=tools):
231
+ with self.wrapped.override(
232
+ deps=deps,
233
+ model=model,
234
+ toolsets=toolsets,
235
+ tools=tools,
236
+ instructions=instructions,
237
+ ):
230
238
  yield
@@ -6,7 +6,14 @@ from typing import Literal
6
6
 
7
7
  from typing_extensions import TypedDict
8
8
 
9
- __all__ = ('AbstractBuiltinTool', 'WebSearchTool', 'WebSearchUserLocation', 'CodeExecutionTool', 'UrlContextTool')
9
+ __all__ = (
10
+ 'AbstractBuiltinTool',
11
+ 'WebSearchTool',
12
+ 'WebSearchUserLocation',
13
+ 'CodeExecutionTool',
14
+ 'UrlContextTool',
15
+ 'MemoryTool',
16
+ )
10
17
 
11
18
 
12
19
  @dataclass(kw_only=True)
@@ -133,3 +140,15 @@ class UrlContextTool(AbstractBuiltinTool):
133
140
 
134
141
  kind: str = 'url_context'
135
142
  """The kind of tool."""
143
+
144
+
145
+ class MemoryTool(AbstractBuiltinTool):
146
+ """A builtin tool that allows your agent to use memory.
147
+
148
+ Supported by:
149
+
150
+ * Anthropic
151
+ """
152
+
153
+ kind: str = 'memory'
154
+ """The kind of tool."""
@@ -4,7 +4,7 @@ from dataclasses import KW_ONLY, dataclass
4
4
  import anyio
5
5
  import anyio.to_thread
6
6
  from pydantic import TypeAdapter
7
- from typing_extensions import TypedDict
7
+ from typing_extensions import Any, TypedDict
8
8
 
9
9
  from pydantic_ai.tools import Tool
10
10
 
@@ -69,7 +69,7 @@ def duckduckgo_search_tool(duckduckgo_client: DDGS | None = None, max_results: i
69
69
  duckduckgo_client: The DuckDuckGo search client.
70
70
  max_results: The maximum number of results. If None, returns results only from the first response.
71
71
  """
72
- return Tool(
72
+ return Tool[Any](
73
73
  DuckDuckGoSearchTool(client=duckduckgo_client or DDGS(), max_results=max_results).__call__,
74
74
  name='duckduckgo_search',
75
75
  description='Searches DuckDuckGo for the given query and returns the results.',
@@ -2,7 +2,7 @@ from dataclasses import dataclass
2
2
  from typing import Literal
3
3
 
4
4
  from pydantic import TypeAdapter
5
- from typing_extensions import TypedDict
5
+ from typing_extensions import Any, TypedDict
6
6
 
7
7
  from pydantic_ai.tools import Tool
8
8
 
@@ -74,7 +74,7 @@ def tavily_search_tool(api_key: str):
74
74
 
75
75
  You can get one by signing up at [https://app.tavily.com/home](https://app.tavily.com/home).
76
76
  """
77
- return Tool(
77
+ return Tool[Any](
78
78
  TavilySearchTool(client=AsyncTavilyClient(api_key)).__call__,
79
79
  name='tavily_search',
80
80
  description='Searches Tavily for the given query and returns the results.',
pydantic_ai/direct.py CHANGED
@@ -44,8 +44,8 @@ async def model_request(
44
44
  """Make a non-streamed request to a model.
45
45
 
46
46
  ```py title="model_request_example.py"
47
+ from pydantic_ai import ModelRequest
47
48
  from pydantic_ai.direct import model_request
48
- from pydantic_ai.messages import ModelRequest
49
49
 
50
50
 
51
51
  async def main():
@@ -81,7 +81,7 @@ async def model_request(
81
81
  return await model_instance.request(
82
82
  messages,
83
83
  model_settings,
84
- model_instance.customize_request_parameters(model_request_parameters or models.ModelRequestParameters()),
84
+ model_request_parameters or models.ModelRequestParameters(),
85
85
  )
86
86
 
87
87
 
@@ -99,8 +99,8 @@ def model_request_sync(
99
99
  `loop.run_until_complete(...)`. You therefore can't use this method inside async code or if there's an active event loop.
100
100
 
101
101
  ```py title="model_request_sync_example.py"
102
+ from pydantic_ai import ModelRequest
102
103
  from pydantic_ai.direct import model_request_sync
103
- from pydantic_ai.messages import ModelRequest
104
104
 
105
105
  model_response = model_request_sync(
106
106
  'anthropic:claude-3-5-haiku-latest',
@@ -153,8 +153,8 @@ def model_request_stream(
153
153
 
154
154
  ```py {title="model_request_stream_example.py"}
155
155
 
156
+ from pydantic_ai import ModelRequest
156
157
  from pydantic_ai.direct import model_request_stream
157
- from pydantic_ai.messages import ModelRequest
158
158
 
159
159
 
160
160
  async def main():
@@ -193,7 +193,7 @@ def model_request_stream(
193
193
  return model_instance.request_stream(
194
194
  messages,
195
195
  model_settings,
196
- model_instance.customize_request_parameters(model_request_parameters or models.ModelRequestParameters()),
196
+ model_request_parameters or models.ModelRequestParameters(),
197
197
  )
198
198
 
199
199
 
@@ -212,8 +212,8 @@ def model_request_stream_sync(
212
212
 
213
213
  ```py {title="model_request_stream_sync_example.py"}
214
214
 
215
+ from pydantic_ai import ModelRequest
215
216
  from pydantic_ai.direct import model_request_stream_sync
216
- from pydantic_ai.messages import ModelRequest
217
217
 
218
218
  messages = [ModelRequest.user_text_prompt('Who was Albert Einstein?')]
219
219
  with model_request_stream_sync('openai:gpt-4.1-mini', messages) as stream:
@@ -8,12 +8,14 @@ from dbos import DBOS, DBOSConfiguredInstance
8
8
  from typing_extensions import Never
9
9
 
10
10
  from pydantic_ai import (
11
+ AbstractToolset,
11
12
  _utils,
12
13
  messages as _messages,
13
14
  models,
14
15
  usage as _usage,
15
16
  )
16
17
  from pydantic_ai.agent import AbstractAgent, AgentRun, AgentRunResult, EventStreamHandler, RunOutputDataT, WrapperAgent
18
+ from pydantic_ai.agent.abstract import Instructions
17
19
  from pydantic_ai.exceptions import UserError
18
20
  from pydantic_ai.models import Model
19
21
  from pydantic_ai.output import OutputDataT, OutputSpec
@@ -26,7 +28,6 @@ from pydantic_ai.tools import (
26
28
  Tool,
27
29
  ToolFuncEither,
28
30
  )
29
- from pydantic_ai.toolsets import AbstractToolset
30
31
 
31
32
  from ._model import DBOSModel
32
33
  from ._utils import StepConfig
@@ -704,8 +705,9 @@ class DBOSAgent(WrapperAgent[AgentDepsT, OutputDataT], DBOSConfiguredInstance):
704
705
  model: models.Model | models.KnownModelName | str | _utils.Unset = _utils.UNSET,
705
706
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | _utils.Unset = _utils.UNSET,
706
707
  tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] | _utils.Unset = _utils.UNSET,
708
+ instructions: Instructions[AgentDepsT] | _utils.Unset = _utils.UNSET,
707
709
  ) -> Iterator[None]:
708
- """Context manager to temporarily override agent dependencies, model, toolsets, or tools.
710
+ """Context manager to temporarily override agent dependencies, model, toolsets, tools, or instructions.
709
711
 
710
712
  This is particularly useful when testing.
711
713
  You can find an example of this [here](../testing.md#overriding-model-via-pytest-fixtures).
@@ -715,11 +717,18 @@ class DBOSAgent(WrapperAgent[AgentDepsT, OutputDataT], DBOSConfiguredInstance):
715
717
  model: The model to use instead of the model passed to the agent run.
716
718
  toolsets: The toolsets to use instead of the toolsets passed to the agent constructor and agent run.
717
719
  tools: The tools to use instead of the tools registered with the agent.
720
+ instructions: The instructions to use instead of the instructions registered with the agent.
718
721
  """
719
722
  if _utils.is_set(model) and not isinstance(model, (DBOSModel)):
720
723
  raise UserError(
721
724
  'Non-DBOS model cannot be contextually overridden inside a DBOS workflow, it must be set at agent creation time.'
722
725
  )
723
726
 
724
- with super().override(deps=deps, model=model, toolsets=toolsets, tools=tools):
727
+ with super().override(
728
+ deps=deps,
729
+ model=model,
730
+ toolsets=toolsets,
731
+ tools=tools,
732
+ instructions=instructions,
733
+ ):
725
734
  yield
@@ -7,9 +7,8 @@ from typing import TYPE_CHECKING, Any
7
7
  from dbos import DBOS
8
8
  from typing_extensions import Self
9
9
 
10
+ from pydantic_ai import AbstractToolset, ToolsetTool, WrapperToolset
10
11
  from pydantic_ai.tools import AgentDepsT, RunContext
11
- from pydantic_ai.toolsets.abstract import AbstractToolset, ToolsetTool
12
- from pydantic_ai.toolsets.wrapper import WrapperToolset
13
12
 
14
13
  from ._utils import StepConfig
15
14
 
@@ -7,12 +7,12 @@ from typing import Any
7
7
 
8
8
  from dbos import DBOS
9
9
 
10
- from pydantic_ai.agent import EventStreamHandler
11
- from pydantic_ai.messages import (
10
+ from pydantic_ai import (
12
11
  ModelMessage,
13
12
  ModelResponse,
14
13
  ModelResponseStreamEvent,
15
14
  )
15
+ from pydantic_ai.agent import EventStreamHandler
16
16
  from pydantic_ai.models import Model, ModelRequestParameters, StreamedResponse
17
17
  from pydantic_ai.models.wrapper import WrapperModel
18
18
  from pydantic_ai.settings import ModelSettings
@@ -16,12 +16,14 @@ from temporalio.workflow import ActivityConfig
16
16
  from typing_extensions import Never
17
17
 
18
18
  from pydantic_ai import (
19
+ AbstractToolset,
19
20
  _utils,
20
21
  messages as _messages,
21
22
  models,
22
23
  usage as _usage,
23
24
  )
24
- from pydantic_ai.agent import AbstractAgent, AgentRun, AgentRunResult, EventStreamHandler, RunOutputDataT, WrapperAgent
25
+ from pydantic_ai.agent import AbstractAgent, AgentRun, AgentRunResult, EventStreamHandler, WrapperAgent
26
+ from pydantic_ai.agent.abstract import Instructions, RunOutputDataT
25
27
  from pydantic_ai.exceptions import UserError
26
28
  from pydantic_ai.models import Model
27
29
  from pydantic_ai.output import OutputDataT, OutputSpec
@@ -34,7 +36,6 @@ from pydantic_ai.tools import (
34
36
  Tool,
35
37
  ToolFuncEither,
36
38
  )
37
- from pydantic_ai.toolsets import AbstractToolset
38
39
 
39
40
  from ._model import TemporalModel
40
41
  from ._run_context import TemporalRunContext
@@ -748,8 +749,9 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
748
749
  model: models.Model | models.KnownModelName | str | _utils.Unset = _utils.UNSET,
749
750
  toolsets: Sequence[AbstractToolset[AgentDepsT]] | _utils.Unset = _utils.UNSET,
750
751
  tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] | _utils.Unset = _utils.UNSET,
752
+ instructions: Instructions[AgentDepsT] | _utils.Unset = _utils.UNSET,
751
753
  ) -> Iterator[None]:
752
- """Context manager to temporarily override agent dependencies, model, toolsets, or tools.
754
+ """Context manager to temporarily override agent dependencies, model, toolsets, tools, or instructions.
753
755
 
754
756
  This is particularly useful when testing.
755
757
  You can find an example of this [here](../testing.md#overriding-model-via-pytest-fixtures).
@@ -759,6 +761,7 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
759
761
  model: The model to use instead of the model passed to the agent run.
760
762
  toolsets: The toolsets to use instead of the toolsets passed to the agent constructor and agent run.
761
763
  tools: The tools to use instead of the tools registered with the agent.
764
+ instructions: The instructions to use instead of the instructions registered with the agent.
762
765
  """
763
766
  if workflow.in_workflow():
764
767
  if _utils.is_set(model):
@@ -774,5 +777,11 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
774
777
  'Tools cannot be contextually overridden inside a Temporal workflow, they must be set at agent creation time.'
775
778
  )
776
779
 
777
- with super().override(deps=deps, model=model, toolsets=toolsets, tools=tools):
780
+ with super().override(
781
+ deps=deps,
782
+ model=model,
783
+ toolsets=toolsets,
784
+ tools=tools,
785
+ instructions=instructions,
786
+ ):
778
787
  yield
@@ -8,9 +8,9 @@ from pydantic import ConfigDict, Discriminator, with_config
8
8
  from temporalio import activity, workflow
9
9
  from temporalio.workflow import ActivityConfig
10
10
 
11
+ from pydantic_ai import FunctionToolset, ToolsetTool
11
12
  from pydantic_ai.exceptions import ApprovalRequired, CallDeferred, ModelRetry, UserError
12
13
  from pydantic_ai.tools import AgentDepsT, RunContext
13
- from pydantic_ai.toolsets import FunctionToolset, ToolsetTool
14
14
  from pydantic_ai.toolsets.function import FunctionToolsetTool
15
15
 
16
16
  from ._run_context import TemporalRunContext
@@ -9,10 +9,10 @@ from temporalio import activity, workflow
9
9
  from temporalio.workflow import ActivityConfig
10
10
  from typing_extensions import Self
11
11
 
12
+ from pydantic_ai import ToolsetTool
12
13
  from pydantic_ai.exceptions import UserError
13
14
  from pydantic_ai.mcp import MCPServer, ToolResult
14
15
  from pydantic_ai.tools import AgentDepsT, RunContext, ToolDefinition
15
- from pydantic_ai.toolsets.abstract import ToolsetTool
16
16
 
17
17
  from ._run_context import TemporalRunContext
18
18
  from ._toolset import TemporalWrapperToolset
@@ -10,13 +10,13 @@ from pydantic import ConfigDict, with_config
10
10
  from temporalio import activity, workflow
11
11
  from temporalio.workflow import ActivityConfig
12
12
 
13
- from pydantic_ai.agent import EventStreamHandler
14
- from pydantic_ai.exceptions import UserError
15
- from pydantic_ai.messages import (
13
+ from pydantic_ai import (
16
14
  ModelMessage,
17
15
  ModelResponse,
18
16
  ModelResponseStreamEvent,
19
17
  )
18
+ from pydantic_ai.agent import EventStreamHandler
19
+ from pydantic_ai.exceptions import UserError
20
20
  from pydantic_ai.models import Model, ModelRequestParameters, StreamedResponse
21
21
  from pydantic_ai.models.wrapper import WrapperModel
22
22
  from pydantic_ai.settings import ModelSettings
@@ -6,10 +6,8 @@ from typing import Any, Literal
6
6
 
7
7
  from temporalio.workflow import ActivityConfig
8
8
 
9
+ from pydantic_ai import AbstractToolset, FunctionToolset, WrapperToolset
9
10
  from pydantic_ai.tools import AgentDepsT
10
- from pydantic_ai.toolsets.abstract import AbstractToolset
11
- from pydantic_ai.toolsets.function import FunctionToolset
12
- from pydantic_ai.toolsets.wrapper import WrapperToolset
13
11
 
14
12
  from ._run_context import TemporalRunContext
15
13
 
pydantic_ai/ext/aci.py CHANGED
@@ -3,8 +3,8 @@ from __future__ import annotations
3
3
  from collections.abc import Sequence
4
4
  from typing import Any
5
5
 
6
+ from pydantic_ai import FunctionToolset
6
7
  from pydantic_ai.tools import Tool
7
- from pydantic_ai.toolsets.function import FunctionToolset
8
8
 
9
9
  try:
10
10
  from aci import ACI
@@ -4,8 +4,8 @@ from typing import Any, Protocol
4
4
 
5
5
  from pydantic.json_schema import JsonSchemaValue
6
6
 
7
+ from pydantic_ai import FunctionToolset
7
8
  from pydantic_ai.tools import Tool
8
- from pydantic_ai.toolsets.function import FunctionToolset
9
9
 
10
10
 
11
11
  class LangChainTool(Protocol):