pydantic-ai-slim 1.0.6__py3-none-any.whl → 1.0.7__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.

@@ -45,15 +45,11 @@ from ..run import AgentRun, AgentRunResult
45
45
  from ..settings import ModelSettings, merge_model_settings
46
46
  from ..tools import (
47
47
  AgentDepsT,
48
- DeferredToolCallResult,
49
- DeferredToolResult,
50
48
  DeferredToolResults,
51
49
  DocstringFormat,
52
50
  GenerateToolJsonSchema,
53
51
  RunContext,
54
52
  Tool,
55
- ToolApproved,
56
- ToolDenied,
57
53
  ToolFuncContext,
58
54
  ToolFuncEither,
59
55
  ToolFuncPlain,
@@ -462,7 +458,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
462
458
  ) -> AbstractAsyncContextManager[AgentRun[AgentDepsT, RunOutputDataT]]: ...
463
459
 
464
460
  @asynccontextmanager
465
- async def iter( # noqa: C901
461
+ async def iter(
466
462
  self,
467
463
  user_prompt: str | Sequence[_messages.UserContent] | None = None,
468
464
  *,
@@ -505,7 +501,6 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
505
501
  [
506
502
  UserPromptNode(
507
503
  user_prompt='What is the capital of France?',
508
- instructions=None,
509
504
  instructions_functions=[],
510
505
  system_prompts=(),
511
506
  system_prompt_functions=[],
@@ -559,7 +554,6 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
559
554
  del model
560
555
 
561
556
  deps = self._get_deps(deps)
562
- new_message_index = len(message_history) if message_history else 0
563
557
  output_schema = self._prepare_output_schema(output_type, model_used.profile)
564
558
 
565
559
  output_type_ = output_type or self.output_type
@@ -620,27 +614,12 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
620
614
  instrumentation_settings = None
621
615
  tracer = NoOpTracer()
622
616
 
623
- tool_call_results: dict[str, DeferredToolResult] | None = None
624
- if deferred_tool_results is not None:
625
- tool_call_results = {}
626
- for tool_call_id, approval in deferred_tool_results.approvals.items():
627
- if approval is True:
628
- approval = ToolApproved()
629
- elif approval is False:
630
- approval = ToolDenied()
631
- tool_call_results[tool_call_id] = approval
632
-
633
- if calls := deferred_tool_results.calls:
634
- call_result_types = _utils.get_union_args(DeferredToolCallResult)
635
- for tool_call_id, result in calls.items():
636
- if not isinstance(result, call_result_types):
637
- result = _messages.ToolReturn(result)
638
- tool_call_results[tool_call_id] = result
639
-
640
- graph_deps = _agent_graph.GraphAgentDeps[AgentDepsT, RunOutputDataT](
617
+ graph_deps = _agent_graph.GraphAgentDeps[
618
+ AgentDepsT, RunOutputDataT
619
+ ](
641
620
  user_deps=deps,
642
621
  prompt=user_prompt,
643
- new_message_index=new_message_index,
622
+ new_message_index=0, # This will be set in `UserPromptNode` based on the length of the cleaned message history
644
623
  model=model_used,
645
624
  model_settings=model_settings,
646
625
  usage_limits=usage_limits,
@@ -651,13 +630,13 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
651
630
  history_processors=self.history_processors,
652
631
  builtin_tools=list(self._builtin_tools),
653
632
  tool_manager=tool_manager,
654
- tool_call_results=tool_call_results,
655
633
  tracer=tracer,
656
634
  get_instructions=get_instructions,
657
635
  instrumentation_settings=instrumentation_settings,
658
636
  )
659
637
  start_node = _agent_graph.UserPromptNode[AgentDepsT](
660
638
  user_prompt=user_prompt,
639
+ deferred_tool_results=deferred_tool_results,
661
640
  instructions=self._instructions,
662
641
  instructions_functions=self._instructions_functions,
663
642
  system_prompts=self._system_prompts,
@@ -1005,7 +984,9 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1005
984
  require_parameter_descriptions: bool = False,
1006
985
  schema_generator: type[GenerateJsonSchema] = GenerateToolJsonSchema,
1007
986
  strict: bool | None = None,
987
+ sequential: bool = False,
1008
988
  requires_approval: bool = False,
989
+ metadata: dict[str, Any] | None = None,
1009
990
  ) -> Callable[[ToolFuncContext[AgentDepsT, ToolParams]], ToolFuncContext[AgentDepsT, ToolParams]]: ...
1010
991
 
1011
992
  def tool(
@@ -1020,7 +1001,9 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1020
1001
  require_parameter_descriptions: bool = False,
1021
1002
  schema_generator: type[GenerateJsonSchema] = GenerateToolJsonSchema,
1022
1003
  strict: bool | None = None,
1004
+ sequential: bool = False,
1023
1005
  requires_approval: bool = False,
1006
+ metadata: dict[str, Any] | None = None,
1024
1007
  ) -> Any:
1025
1008
  """Decorator to register a tool function which takes [`RunContext`][pydantic_ai.tools.RunContext] as its first argument.
1026
1009
 
@@ -1065,8 +1048,10 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1065
1048
  schema_generator: The JSON schema generator class to use for this tool. Defaults to `GenerateToolJsonSchema`.
1066
1049
  strict: Whether to enforce JSON schema compliance (only affects OpenAI).
1067
1050
  See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info.
1051
+ sequential: Whether the function requires a sequential/serial execution environment. Defaults to False.
1068
1052
  requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
1069
1053
  See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
1054
+ metadata: Optional metadata for the tool. This is not sent to the model but can be used for filtering and tool behavior customization.
1070
1055
  """
1071
1056
 
1072
1057
  def tool_decorator(
@@ -1075,15 +1060,17 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1075
1060
  # noinspection PyTypeChecker
1076
1061
  self._function_toolset.add_function(
1077
1062
  func_,
1078
- True,
1079
- name,
1080
- retries,
1081
- prepare,
1082
- docstring_format,
1083
- require_parameter_descriptions,
1084
- schema_generator,
1085
- strict,
1086
- requires_approval,
1063
+ takes_ctx=True,
1064
+ name=name,
1065
+ retries=retries,
1066
+ prepare=prepare,
1067
+ docstring_format=docstring_format,
1068
+ require_parameter_descriptions=require_parameter_descriptions,
1069
+ schema_generator=schema_generator,
1070
+ strict=strict,
1071
+ sequential=sequential,
1072
+ requires_approval=requires_approval,
1073
+ metadata=metadata,
1087
1074
  )
1088
1075
  return func_
1089
1076
 
@@ -1104,7 +1091,9 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1104
1091
  require_parameter_descriptions: bool = False,
1105
1092
  schema_generator: type[GenerateJsonSchema] = GenerateToolJsonSchema,
1106
1093
  strict: bool | None = None,
1094
+ sequential: bool = False,
1107
1095
  requires_approval: bool = False,
1096
+ metadata: dict[str, Any] | None = None,
1108
1097
  ) -> Callable[[ToolFuncPlain[ToolParams]], ToolFuncPlain[ToolParams]]: ...
1109
1098
 
1110
1099
  def tool_plain(
@@ -1121,6 +1110,7 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1121
1110
  strict: bool | None = None,
1122
1111
  sequential: bool = False,
1123
1112
  requires_approval: bool = False,
1113
+ metadata: dict[str, Any] | None = None,
1124
1114
  ) -> Any:
1125
1115
  """Decorator to register a tool function which DOES NOT take `RunContext` as an argument.
1126
1116
 
@@ -1168,22 +1158,24 @@ class Agent(AbstractAgent[AgentDepsT, OutputDataT]):
1168
1158
  sequential: Whether the function requires a sequential/serial execution environment. Defaults to False.
1169
1159
  requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
1170
1160
  See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
1161
+ metadata: Optional metadata for the tool. This is not sent to the model but can be used for filtering and tool behavior customization.
1171
1162
  """
1172
1163
 
1173
1164
  def tool_decorator(func_: ToolFuncPlain[ToolParams]) -> ToolFuncPlain[ToolParams]:
1174
1165
  # noinspection PyTypeChecker
1175
1166
  self._function_toolset.add_function(
1176
1167
  func_,
1177
- False,
1178
- name,
1179
- retries,
1180
- prepare,
1181
- docstring_format,
1182
- require_parameter_descriptions,
1183
- schema_generator,
1184
- strict,
1185
- sequential,
1186
- requires_approval,
1168
+ takes_ctx=False,
1169
+ name=name,
1170
+ retries=retries,
1171
+ prepare=prepare,
1172
+ docstring_format=docstring_format,
1173
+ require_parameter_descriptions=require_parameter_descriptions,
1174
+ schema_generator=schema_generator,
1175
+ strict=strict,
1176
+ sequential=sequential,
1177
+ requires_approval=requires_approval,
1178
+ metadata=metadata,
1187
1179
  )
1188
1180
  return func_
1189
1181
 
@@ -499,12 +499,13 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
499
499
  ]
500
500
 
501
501
  parts: list[_messages.ModelRequestPart] = []
502
- async for _event in _agent_graph.process_function_tools(
503
- graph_ctx.deps.tool_manager,
504
- tool_calls,
505
- final_result,
506
- graph_ctx,
507
- parts,
502
+ async for _event in _agent_graph.process_tool_calls(
503
+ tool_manager=graph_ctx.deps.tool_manager,
504
+ tool_calls=tool_calls,
505
+ tool_call_results=None,
506
+ final_result=final_result,
507
+ ctx=graph_ctx,
508
+ output_parts=parts,
508
509
  ):
509
510
  pass
510
511
  if parts:
@@ -621,7 +622,6 @@ class AbstractAgent(Generic[AgentDepsT, OutputDataT], ABC):
621
622
  [
622
623
  UserPromptNode(
623
624
  user_prompt='What is the capital of France?',
624
- instructions=None,
625
625
  instructions_functions=[],
626
626
  system_prompts=(),
627
627
  system_prompt_functions=[],
@@ -144,7 +144,6 @@ class WrapperAgent(AbstractAgent[AgentDepsT, OutputDataT]):
144
144
  [
145
145
  UserPromptNode(
146
146
  user_prompt='What is the capital of France?',
147
- instructions=None,
148
147
  instructions_functions=[],
149
148
  system_prompts=(),
150
149
  system_prompt_functions=[],
@@ -15,7 +15,6 @@ from pydantic_ai import (
15
15
  )
16
16
  from pydantic_ai.agent import AbstractAgent, AgentRun, AgentRunResult, EventStreamHandler, RunOutputDataT, WrapperAgent
17
17
  from pydantic_ai.exceptions import UserError
18
- from pydantic_ai.mcp import MCPServer
19
18
  from pydantic_ai.models import Model
20
19
  from pydantic_ai.output import OutputDataT, OutputSpec
21
20
  from pydantic_ai.result import StreamedRunResult
@@ -29,7 +28,6 @@ from pydantic_ai.tools import (
29
28
  )
30
29
  from pydantic_ai.toolsets import AbstractToolset
31
30
 
32
- from ._mcp_server import DBOSMCPServer
33
31
  from ._model import DBOSModel
34
32
  from ._utils import StepConfig
35
33
 
@@ -86,14 +84,21 @@ class DBOSAgent(WrapperAgent[AgentDepsT, OutputDataT], DBOSConfiguredInstance):
86
84
 
87
85
  def dbosify_toolset(toolset: AbstractToolset[AgentDepsT]) -> AbstractToolset[AgentDepsT]:
88
86
  # Replace MCPServer with DBOSMCPServer
89
- if isinstance(toolset, MCPServer):
90
- return DBOSMCPServer(
91
- wrapped=toolset,
92
- step_name_prefix=dbosagent_name,
93
- step_config=self._mcp_step_config,
94
- )
87
+ try:
88
+ from pydantic_ai.mcp import MCPServer
89
+
90
+ from ._mcp_server import DBOSMCPServer
91
+ except ImportError:
92
+ pass
95
93
  else:
96
- return toolset
94
+ if isinstance(toolset, MCPServer):
95
+ return DBOSMCPServer(
96
+ wrapped=toolset,
97
+ step_name_prefix=dbosagent_name,
98
+ step_config=self._mcp_step_config,
99
+ )
100
+
101
+ return toolset
97
102
 
98
103
  dbos_toolsets = [toolset.visit_and_replace(dbosify_toolset) for toolset in wrapped.toolsets]
99
104
  self._toolsets = dbos_toolsets
@@ -622,7 +627,6 @@ class DBOSAgent(WrapperAgent[AgentDepsT, OutputDataT], DBOSConfiguredInstance):
622
627
  [
623
628
  UserPromptNode(
624
629
  user_prompt='What is the capital of France?',
625
- instructions=None,
626
630
  instructions_functions=[],
627
631
  system_prompts=(),
628
632
  system_prompt_functions=[],
@@ -2,18 +2,20 @@ from __future__ import annotations
2
2
 
3
3
  from abc import ABC
4
4
  from collections.abc import Callable
5
- from typing import Any
5
+ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from dbos import DBOS
8
8
  from typing_extensions import Self
9
9
 
10
- from pydantic_ai.mcp import MCPServer, ToolResult
11
10
  from pydantic_ai.tools import AgentDepsT, RunContext
12
11
  from pydantic_ai.toolsets.abstract import AbstractToolset, ToolsetTool
13
12
  from pydantic_ai.toolsets.wrapper import WrapperToolset
14
13
 
15
14
  from ._utils import StepConfig
16
15
 
16
+ if TYPE_CHECKING:
17
+ from pydantic_ai.mcp import MCPServer, ToolResult
18
+
17
19
 
18
20
  class DBOSMCPServer(WrapperToolset[AgentDepsT], ABC):
19
21
  """A wrapper for MCPServer that integrates with DBOS, turning call_tool and get_tools to DBOS steps."""
@@ -660,7 +660,6 @@ class TemporalAgent(WrapperAgent[AgentDepsT, OutputDataT]):
660
660
  [
661
661
  UserPromptNode(
662
662
  user_prompt='What is the capital of France?',
663
- instructions=None,
664
663
  instructions_functions=[],
665
664
  system_prompts=(),
666
665
  system_prompt_functions=[],
@@ -1,14 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from collections.abc import Callable
4
+ from typing import TYPE_CHECKING
4
5
 
5
- from logfire import Logfire
6
- from opentelemetry.trace import get_tracer
7
6
  from temporalio.client import ClientConfig, Plugin as ClientPlugin
8
- from temporalio.contrib.opentelemetry import TracingInterceptor
9
7
  from temporalio.runtime import OpenTelemetryConfig, Runtime, TelemetryConfig
10
8
  from temporalio.service import ConnectConfig, ServiceClient
11
9
 
10
+ if TYPE_CHECKING:
11
+ from logfire import Logfire
12
+
12
13
 
13
14
  def _default_setup_logfire() -> Logfire:
14
15
  import logfire
@@ -22,6 +23,14 @@ class LogfirePlugin(ClientPlugin):
22
23
  """Temporal client plugin for Logfire."""
23
24
 
24
25
  def __init__(self, setup_logfire: Callable[[], Logfire] = _default_setup_logfire, *, metrics: bool = True):
26
+ try:
27
+ import logfire # noqa: F401 # pyright: ignore[reportUnusedImport]
28
+ except ImportError as _import_error:
29
+ raise ImportError(
30
+ 'Please install the `logfire` package to use the Logfire plugin, '
31
+ 'you can use the `logfire` optional group — `pip install "pydantic-ai-slim[logfire]"`'
32
+ ) from _import_error
33
+
25
34
  self.setup_logfire = setup_logfire
26
35
  self.metrics = metrics
27
36
 
@@ -29,6 +38,9 @@ class LogfirePlugin(ClientPlugin):
29
38
  self.next_client_plugin = next
30
39
 
31
40
  def configure_client(self, config: ClientConfig) -> ClientConfig:
41
+ from opentelemetry.trace import get_tracer
42
+ from temporalio.contrib.opentelemetry import TracingInterceptor
43
+
32
44
  interceptors = config.get('interceptors', [])
33
45
  config['interceptors'] = [*interceptors, TracingInterceptor(get_tracer('temporalio'))]
34
46
  return self.next_client_plugin.configure_client(config)
@@ -6,7 +6,6 @@ from typing import Any, Literal
6
6
 
7
7
  from temporalio.workflow import ActivityConfig
8
8
 
9
- from pydantic_ai.mcp import MCPServer
10
9
  from pydantic_ai.tools import AgentDepsT
11
10
  from pydantic_ai.toolsets.abstract import AbstractToolset
12
11
  from pydantic_ai.toolsets.function import FunctionToolset
@@ -63,16 +62,22 @@ def temporalize_toolset(
63
62
  deps_type=deps_type,
64
63
  run_context_type=run_context_type,
65
64
  )
66
- elif isinstance(toolset, MCPServer):
67
- from ._mcp_server import TemporalMCPServer
68
65
 
69
- return TemporalMCPServer(
70
- toolset,
71
- activity_name_prefix=activity_name_prefix,
72
- activity_config=activity_config,
73
- tool_activity_config=tool_activity_config,
74
- deps_type=deps_type,
75
- run_context_type=run_context_type,
76
- )
66
+ try:
67
+ from pydantic_ai.mcp import MCPServer
68
+
69
+ from ._mcp_server import TemporalMCPServer
70
+ except ImportError:
71
+ pass
77
72
  else:
78
- return toolset
73
+ if isinstance(toolset, MCPServer):
74
+ return TemporalMCPServer(
75
+ toolset,
76
+ activity_name_prefix=activity_name_prefix,
77
+ activity_config=activity_config,
78
+ tool_activity_config=tool_activity_config,
79
+ deps_type=deps_type,
80
+ run_context_type=run_context_type,
81
+ )
82
+
83
+ return toolset
pydantic_ai/mcp.py CHANGED
@@ -256,6 +256,11 @@ class MCPServer(AbstractToolset[Any], ABC):
256
256
  name=name,
257
257
  description=mcp_tool.description,
258
258
  parameters_json_schema=mcp_tool.inputSchema,
259
+ metadata={
260
+ 'meta': mcp_tool.meta,
261
+ 'annotations': mcp_tool.annotations.model_dump() if mcp_tool.annotations else None,
262
+ 'output_schema': mcp_tool.outputSchema or None,
263
+ },
259
264
  ),
260
265
  )
261
266
  for mcp_tool in await self.list_tools()
pydantic_ai/run.py CHANGED
@@ -48,7 +48,6 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
48
48
  [
49
49
  UserPromptNode(
50
50
  user_prompt='What is the capital of France?',
51
- instructions=None,
52
51
  instructions_functions=[],
53
52
  system_prompts=(),
54
53
  system_prompt_functions=[],
@@ -183,7 +182,6 @@ class AgentRun(Generic[AgentDepsT, OutputDataT]):
183
182
  [
184
183
  UserPromptNode(
185
184
  user_prompt='What is the capital of France?',
186
- instructions=None,
187
185
  instructions_functions=[],
188
186
  system_prompts=(),
189
187
  system_prompt_functions=[],
pydantic_ai/tools.py CHANGED
@@ -255,6 +255,7 @@ class Tool(Generic[AgentDepsT]):
255
255
  strict: bool | None
256
256
  sequential: bool
257
257
  requires_approval: bool
258
+ metadata: dict[str, Any] | None
258
259
  function_schema: _function_schema.FunctionSchema
259
260
  """
260
261
  The base JSON schema for the tool's parameters.
@@ -277,6 +278,7 @@ class Tool(Generic[AgentDepsT]):
277
278
  strict: bool | None = None,
278
279
  sequential: bool = False,
279
280
  requires_approval: bool = False,
281
+ metadata: dict[str, Any] | None = None,
280
282
  function_schema: _function_schema.FunctionSchema | None = None,
281
283
  ):
282
284
  """Create a new tool instance.
@@ -332,6 +334,7 @@ class Tool(Generic[AgentDepsT]):
332
334
  sequential: Whether the function requires a sequential/serial execution environment. Defaults to False.
333
335
  requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
334
336
  See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
337
+ metadata: Optional metadata for the tool. This is not sent to the model but can be used for filtering and tool behavior customization.
335
338
  function_schema: The function schema to use for the tool. If not provided, it will be generated.
336
339
  """
337
340
  self.function = function
@@ -352,6 +355,7 @@ class Tool(Generic[AgentDepsT]):
352
355
  self.strict = strict
353
356
  self.sequential = sequential
354
357
  self.requires_approval = requires_approval
358
+ self.metadata = metadata
355
359
 
356
360
  @classmethod
357
361
  def from_schema(
@@ -406,6 +410,7 @@ class Tool(Generic[AgentDepsT]):
406
410
  parameters_json_schema=self.function_schema.json_schema,
407
411
  strict=self.strict,
408
412
  sequential=self.sequential,
413
+ metadata=self.metadata,
409
414
  )
410
415
 
411
416
  async def prepare_tool_def(self, ctx: RunContext[AgentDepsT]) -> ToolDefinition | None:
@@ -488,6 +493,12 @@ class ToolDefinition:
488
493
  See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
489
494
  """
490
495
 
496
+ metadata: dict[str, Any] | None = None
497
+ """Tool metadata that can be set by the toolset this tool came from. It is not sent to the model, but can be used for filtering and tool behavior customization.
498
+
499
+ For MCP tools, this contains the `meta`, `annotations`, and `output_schema` fields from the tool definition.
500
+ """
501
+
491
502
  @property
492
503
  def defer(self) -> bool:
493
504
  """Whether calls to this tool will be deferred.
@@ -45,18 +45,21 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
45
45
  tools: Sequence[Tool[AgentDepsT] | ToolFuncEither[AgentDepsT, ...]] = [],
46
46
  *,
47
47
  max_retries: int = 1,
48
- id: str | None = None,
49
48
  docstring_format: DocstringFormat = 'auto',
50
49
  require_parameter_descriptions: bool = False,
51
50
  schema_generator: type[GenerateJsonSchema] = GenerateToolJsonSchema,
51
+ strict: bool | None = None,
52
+ sequential: bool = False,
53
+ requires_approval: bool = False,
54
+ metadata: dict[str, Any] | None = None,
55
+ id: str | None = None,
52
56
  ):
53
57
  """Build a new function toolset.
54
58
 
55
59
  Args:
56
60
  tools: The tools to add to the toolset.
57
61
  max_retries: The maximum number of retries for each tool during a run.
58
- id: An optional unique ID for the toolset. A toolset needs to have an ID in order to be used in a durable execution environment like Temporal,
59
- in which case the ID will be used to identify the toolset's activities within the workflow.
62
+ Applies to all tools, unless overridden when adding a tool.
60
63
  docstring_format: Format of tool docstring, see [`DocstringFormat`][pydantic_ai.tools.DocstringFormat].
61
64
  Defaults to `'auto'`, such that the format is inferred from the structure of the docstring.
62
65
  Applies to all tools, unless overridden when adding a tool.
@@ -64,12 +67,27 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
64
67
  Applies to all tools, unless overridden when adding a tool.
65
68
  schema_generator: The JSON schema generator class to use for this tool. Defaults to `GenerateToolJsonSchema`.
66
69
  Applies to all tools, unless overridden when adding a tool.
70
+ strict: Whether to enforce JSON schema compliance (only affects OpenAI).
71
+ See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info.
72
+ sequential: Whether the function requires a sequential/serial execution environment. Defaults to False.
73
+ Applies to all tools, unless overridden when adding a tool.
74
+ requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
75
+ See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
76
+ Applies to all tools, unless overridden when adding a tool.
77
+ metadata: Optional metadata for the tool. This is not sent to the model but can be used for filtering and tool behavior customization.
78
+ Applies to all tools, unless overridden when adding a tool, which will be merged with the toolset's metadata.
79
+ id: An optional unique ID for the toolset. A toolset needs to have an ID in order to be used in a durable execution environment like Temporal,
80
+ in which case the ID will be used to identify the toolset's activities within the workflow.
67
81
  """
68
82
  self.max_retries = max_retries
69
83
  self._id = id
70
84
  self.docstring_format = docstring_format
71
85
  self.require_parameter_descriptions = require_parameter_descriptions
72
86
  self.schema_generator = schema_generator
87
+ self.strict = strict
88
+ self.sequential = sequential
89
+ self.requires_approval = requires_approval
90
+ self.metadata = metadata
73
91
 
74
92
  self.tools = {}
75
93
  for tool in tools:
@@ -97,8 +115,9 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
97
115
  require_parameter_descriptions: bool | None = None,
98
116
  schema_generator: type[GenerateJsonSchema] | None = None,
99
117
  strict: bool | None = None,
100
- sequential: bool = False,
101
- requires_approval: bool = False,
118
+ sequential: bool | None = None,
119
+ requires_approval: bool | None = None,
120
+ metadata: dict[str, Any] | None = None,
102
121
  ) -> Callable[[ToolFuncEither[AgentDepsT, ToolParams]], ToolFuncEither[AgentDepsT, ToolParams]]: ...
103
122
 
104
123
  def tool(
@@ -113,8 +132,9 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
113
132
  require_parameter_descriptions: bool | None = None,
114
133
  schema_generator: type[GenerateJsonSchema] | None = None,
115
134
  strict: bool | None = None,
116
- sequential: bool = False,
117
- requires_approval: bool = False,
135
+ sequential: bool | None = None,
136
+ requires_approval: bool | None = None,
137
+ metadata: dict[str, Any] | None = None,
118
138
  ) -> Any:
119
139
  """Decorator to register a tool function which takes [`RunContext`][pydantic_ai.tools.RunContext] as its first argument.
120
140
 
@@ -163,9 +183,14 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
163
183
  If `None`, the default value is determined by the toolset.
164
184
  strict: Whether to enforce JSON schema compliance (only affects OpenAI).
165
185
  See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info.
186
+ If `None`, the default value is determined by the toolset.
166
187
  sequential: Whether the function requires a sequential/serial execution environment. Defaults to False.
188
+ If `None`, the default value is determined by the toolset.
167
189
  requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
168
190
  See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
191
+ If `None`, the default value is determined by the toolset.
192
+ metadata: Optional metadata for the tool. This is not sent to the model but can be used for filtering and tool behavior customization.
193
+ If `None`, the default value is determined by the toolset. If provided, it will be merged with the toolset's metadata.
169
194
  """
170
195
 
171
196
  def tool_decorator(
@@ -184,6 +209,7 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
184
209
  strict,
185
210
  sequential,
186
211
  requires_approval,
212
+ metadata,
187
213
  )
188
214
  return func_
189
215
 
@@ -200,8 +226,9 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
200
226
  require_parameter_descriptions: bool | None = None,
201
227
  schema_generator: type[GenerateJsonSchema] | None = None,
202
228
  strict: bool | None = None,
203
- sequential: bool = False,
204
- requires_approval: bool = False,
229
+ sequential: bool | None = None,
230
+ requires_approval: bool | None = None,
231
+ metadata: dict[str, Any] | None = None,
205
232
  ) -> None:
206
233
  """Add a function as a tool to the toolset.
207
234
 
@@ -227,9 +254,14 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
227
254
  If `None`, the default value is determined by the toolset.
228
255
  strict: Whether to enforce JSON schema compliance (only affects OpenAI).
229
256
  See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info.
257
+ If `None`, the default value is determined by the toolset.
230
258
  sequential: Whether the function requires a sequential/serial execution environment. Defaults to False.
259
+ If `None`, the default value is determined by the toolset.
231
260
  requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
232
261
  See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
262
+ If `None`, the default value is determined by the toolset.
263
+ metadata: Optional metadata for the tool. This is not sent to the model but can be used for filtering and tool behavior customization.
264
+ If `None`, the default value is determined by the toolset. If provided, it will be merged with the toolset's metadata.
233
265
  """
234
266
  if docstring_format is None:
235
267
  docstring_format = self.docstring_format
@@ -237,6 +269,12 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
237
269
  require_parameter_descriptions = self.require_parameter_descriptions
238
270
  if schema_generator is None:
239
271
  schema_generator = self.schema_generator
272
+ if strict is None:
273
+ strict = self.strict
274
+ if sequential is None:
275
+ sequential = self.sequential
276
+ if requires_approval is None:
277
+ requires_approval = self.requires_approval
240
278
 
241
279
  tool = Tool[AgentDepsT](
242
280
  func,
@@ -250,6 +288,7 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
250
288
  strict=strict,
251
289
  sequential=sequential,
252
290
  requires_approval=requires_approval,
291
+ metadata=metadata,
253
292
  )
254
293
  self.add_tool(tool)
255
294
 
@@ -263,6 +302,8 @@ class FunctionToolset(AbstractToolset[AgentDepsT]):
263
302
  raise UserError(f'Tool name conflicts with existing tool: {tool.name!r}')
264
303
  if tool.max_retries is None:
265
304
  tool.max_retries = self.max_retries
305
+ if self.metadata is not None:
306
+ tool.metadata = self.metadata | (tool.metadata or {})
266
307
  self.tools[tool.name] = tool
267
308
 
268
309
  async def get_tools(self, ctx: RunContext[AgentDepsT]) -> dict[str, ToolsetTool[AgentDepsT]]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-ai-slim
3
- Version: 1.0.6
3
+ Version: 1.0.7
4
4
  Summary: Agent Framework / shim to use Pydantic with LLMs, slim package
5
5
  Project-URL: Homepage, https://github.com/pydantic/pydantic-ai/tree/main/pydantic_ai_slim
6
6
  Project-URL: Source, https://github.com/pydantic/pydantic-ai/tree/main/pydantic_ai_slim
@@ -33,7 +33,7 @@ Requires-Dist: genai-prices>=0.0.23
33
33
  Requires-Dist: griffe>=1.3.2
34
34
  Requires-Dist: httpx>=0.27
35
35
  Requires-Dist: opentelemetry-api>=1.28.0
36
- Requires-Dist: pydantic-graph==1.0.6
36
+ Requires-Dist: pydantic-graph==1.0.7
37
37
  Requires-Dist: pydantic>=2.10
38
38
  Requires-Dist: typing-inspection>=0.4.0
39
39
  Provides-Extra: a2a
@@ -57,7 +57,7 @@ Requires-Dist: dbos>=1.13.0; extra == 'dbos'
57
57
  Provides-Extra: duckduckgo
58
58
  Requires-Dist: ddgs>=9.0.0; extra == 'duckduckgo'
59
59
  Provides-Extra: evals
60
- Requires-Dist: pydantic-evals==1.0.6; extra == 'evals'
60
+ Requires-Dist: pydantic-evals==1.0.7; extra == 'evals'
61
61
  Provides-Extra: google
62
62
  Requires-Dist: google-genai>=1.31.0; extra == 'google'
63
63
  Provides-Extra: groq