Skip to content

pydantic_ai.tools

AgentDepsT module-attribute

AgentDepsT = TypeVar(
    "AgentDepsT", default=object, contravariant=True
)

Type variable for agent dependencies.

RunContext dataclass

Bases: Generic[RunContextAgentDepsT]

Information about the current call.

Source code in pydantic_ai_slim/pydantic_ai/_run_context.py
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
@dataclasses.dataclass(repr=False, kw_only=True)
class RunContext(Generic[RunContextAgentDepsT]):
    """Information about the current call."""

    deps: RunContextAgentDepsT
    """Dependencies for the agent."""
    model: Model
    """The model used in this run."""
    usage: RunUsage
    """LLM usage associated with the run."""
    agent: Agent[RunContextAgentDepsT, Any] | None = field(default=None, repr=False)
    """The agent running this context, or `None` if not set."""
    prompt: str | Sequence[_messages.UserContent] | None = None
    """The original user prompt passed to the run."""
    messages: list[_messages.ModelMessage] = field(default_factory=list[_messages.ModelMessage])
    """Messages exchanged in the conversation so far."""
    validation_context: Any = None
    """Pydantic [validation context](https://docs.pydantic.dev/latest/concepts/validators/#validation-context) for tool args and run outputs."""
    tracer: Tracer = field(default_factory=NoOpTracer)
    """The tracer to use for tracing the run."""
    trace_include_content: bool = False
    """Whether to include the content of the messages in the trace."""
    instrumentation_version: int = DEFAULT_INSTRUMENTATION_VERSION
    """Instrumentation settings version, if instrumentation is enabled."""
    retries: dict[str, int] = field(default_factory=dict[str, int])
    """Number of retries for each tool so far."""
    tool_call_id: str | None = None
    """The ID of the tool call."""
    tool_name: str | None = None
    """Name of the tool being called."""
    retry: int = 0
    """Number of retries so far.

    For tool calls, this is the number of retries of the specific tool.
    For output validation, this is the number of output validation retries.
    """
    max_retries: int = 0
    """The maximum number of retries allowed.

    For tool calls, this is the maximum retries for the specific tool.
    For output validation, this is the maximum output validation retries.
    """
    run_step: int = 0
    """The current step in the run."""
    tool_call_approved: bool = False
    """Whether a tool call that required approval has now been approved."""
    tool_call_metadata: Any = None
    """Metadata from `DeferredToolResults.metadata[tool_call_id]`, available when `tool_call_approved=True`."""
    partial_output: bool = False
    """Whether the output passed to an output validator is partial."""
    run_id: str | None = None
    """"Unique identifier for the agent run."""
    conversation_id: str | None = None
    """Unique identifier for the conversation this run belongs to.

    A conversation spans potentially multiple agent runs that share message history.
    Resolved at the start of `Agent.run` (etc.) from the explicit `conversation_id`
    argument, the most recent `conversation_id` on `message_history`, or a fresh UUID7.
    """
    metadata: dict[str, Any] | None = None
    """Metadata associated with this agent run, if configured."""
    model_settings: ModelSettings | None = None
    """The resolved model settings for the current run step.

    Populated before each model request, after all model settings layers
    (model defaults, agent-level, capability, and run-level) have been merged.
    Available in model request hooks (`before_model_request`, `wrap_model_request`,
    `after_model_request`). Currently `None` in tool hooks, output validators,
    and during agent construction.
    """

    tool_manager: ToolManager[RunContextAgentDepsT] | None = None
    """The tool manager for the current run step.

    Provides access to tool validation and execution, including tracing and
    capability hooks. Useful for toolsets that need to dispatch tool calls
    programmatically (e.g. code execution sandboxes).

    Not available in `TemporalRunContext` — it is not serializable across
    Temporal activity boundaries.
    """

    @property
    def last_attempt(self) -> bool:
        """Whether this is the last attempt at running this tool before an error is raised."""
        return self.retry == self.max_retries

    __repr__ = _utils.dataclasses_no_defaults_repr

deps instance-attribute

deps: RunContextAgentDepsT

Dependencies for the agent.

model instance-attribute

model: Model

The model used in this run.

usage instance-attribute

usage: RunUsage

LLM usage associated with the run.

agent class-attribute instance-attribute

agent: Agent[RunContextAgentDepsT, Any] | None = field(
    default=None, repr=False
)

The agent running this context, or None if not set.

prompt class-attribute instance-attribute

prompt: str | Sequence[UserContent] | None = None

The original user prompt passed to the run.

messages class-attribute instance-attribute

messages: list[ModelMessage] = field(
    default_factory=list[ModelMessage]
)

Messages exchanged in the conversation so far.

validation_context class-attribute instance-attribute

validation_context: Any = None

Pydantic validation context for tool args and run outputs.

tracer class-attribute instance-attribute

tracer: Tracer = field(default_factory=NoOpTracer)

The tracer to use for tracing the run.

trace_include_content class-attribute instance-attribute

trace_include_content: bool = False

Whether to include the content of the messages in the trace.

instrumentation_version class-attribute instance-attribute

instrumentation_version: int = (
    DEFAULT_INSTRUMENTATION_VERSION
)

Instrumentation settings version, if instrumentation is enabled.

retries class-attribute instance-attribute

retries: dict[str, int] = field(
    default_factory=dict[str, int]
)

Number of retries for each tool so far.

tool_call_id class-attribute instance-attribute

tool_call_id: str | None = None

The ID of the tool call.

tool_name class-attribute instance-attribute

tool_name: str | None = None

Name of the tool being called.

retry class-attribute instance-attribute

retry: int = 0

Number of retries so far.

For tool calls, this is the number of retries of the specific tool. For output validation, this is the number of output validation retries.

max_retries class-attribute instance-attribute

max_retries: int = 0

The maximum number of retries allowed.

For tool calls, this is the maximum retries for the specific tool. For output validation, this is the maximum output validation retries.

run_step class-attribute instance-attribute

run_step: int = 0

The current step in the run.

tool_call_approved class-attribute instance-attribute

tool_call_approved: bool = False

Whether a tool call that required approval has now been approved.

tool_call_metadata class-attribute instance-attribute

tool_call_metadata: Any = None

Metadata from DeferredToolResults.metadata[tool_call_id], available when tool_call_approved=True.

partial_output class-attribute instance-attribute

partial_output: bool = False

Whether the output passed to an output validator is partial.

run_id class-attribute instance-attribute

run_id: str | None = None

"Unique identifier for the agent run.

conversation_id class-attribute instance-attribute

conversation_id: str | None = None

Unique identifier for the conversation this run belongs to.

A conversation spans potentially multiple agent runs that share message history. Resolved at the start of Agent.run (etc.) from the explicit conversation_id argument, the most recent conversation_id on message_history, or a fresh UUID7.

metadata class-attribute instance-attribute

metadata: dict[str, Any] | None = None

Metadata associated with this agent run, if configured.

model_settings class-attribute instance-attribute

model_settings: ModelSettings | None = None

The resolved model settings for the current run step.

Populated before each model request, after all model settings layers (model defaults, agent-level, capability, and run-level) have been merged. Available in model request hooks (before_model_request, wrap_model_request, after_model_request). Currently None in tool hooks, output validators, and during agent construction.

tool_manager class-attribute instance-attribute

tool_manager: ToolManager[RunContextAgentDepsT] | None = (
    None
)

The tool manager for the current run step.

Provides access to tool validation and execution, including tracing and capability hooks. Useful for toolsets that need to dispatch tool calls programmatically (e.g. code execution sandboxes).

Not available in TemporalRunContext — it is not serializable across Temporal activity boundaries.

last_attempt property

last_attempt: bool

Whether this is the last attempt at running this tool before an error is raised.

ToolParams module-attribute

ToolParams = ParamSpec('ToolParams', default=...)

Retrieval function param spec.

SystemPromptFunc module-attribute

SystemPromptFunc: TypeAlias = (
    Callable[[RunContext[AgentDepsT]], str | None]
    | Callable[
        [RunContext[AgentDepsT]], Awaitable[str | None]
    ]
    | Callable[[], str | None]
    | Callable[[], Awaitable[str | None]]
)

A function that may or maybe not take RunContext as an argument, and may or may not be async.

Functions which return None are excluded from model requests.

Usage SystemPromptFunc[AgentDepsT].

ToolFuncContext module-attribute

A tool function that takes RunContext as the first argument.

Usage ToolContextFunc[AgentDepsT, ToolParams].

ToolFuncPlain module-attribute

ToolFuncPlain: TypeAlias = Callable[ToolParams, Any]

A tool function that does not take RunContext as the first argument.

Usage ToolPlainFunc[ToolParams].

ToolFuncEither module-attribute

Either kind of tool function.

This is just a union of ToolFuncContext and ToolFuncPlain.

Usage ToolFuncEither[AgentDepsT, ToolParams].

ArgsValidatorFunc module-attribute

A function that validates tool arguments before execution.

The validator receives the same typed parameters as the tool function, with RunContext as the first argument for dependency access.

Should raise ModelRetry on validation failure.

ToolPrepareFunc module-attribute

ToolPrepareFunc: TypeAlias = Callable[
    [RunContext[AgentDepsT], "ToolDefinition"],
    Union[
        Awaitable["ToolDefinition | None"],
        "ToolDefinition",
        None,
    ],
]

Definition of a function that can prepare a tool definition at call time. Both sync and async functions are accepted.

See tool docs for more information.

Example — here only_if_42 is valid as a ToolPrepareFunc:

from pydantic_ai import RunContext, Tool
from pydantic_ai.tools import ToolDefinition

def only_if_42(
    ctx: RunContext[int], tool_def: ToolDefinition
) -> ToolDefinition | None:
    if ctx.deps == 42:
        return tool_def

def hitchhiker(ctx: RunContext[int], answer: str) -> str:
    return f'{ctx.deps} {answer}'

hitchhiker = Tool(hitchhiker, prepare=only_if_42)

Usage ToolPrepareFunc[AgentDepsT].

ToolsPrepareFunc module-attribute

ToolsPrepareFunc: TypeAlias = Callable[
    [RunContext[AgentDepsT], list["ToolDefinition"]],
    Awaitable["list[ToolDefinition] | None"]
    | list["ToolDefinition"]
    | None,
]

Definition of a function that can prepare the tool definition of all tools for each step. This is useful if you want to customize the definition of multiple tools or you want to register a subset of tools for a given step. Both sync and async functions are accepted.

Example — here turn_on_strict_if_openai is valid as a ToolsPrepareFunc:

from dataclasses import replace

from pydantic_ai import Agent, RunContext
from pydantic_ai.capabilities import PrepareTools
from pydantic_ai.tools import ToolDefinition


def turn_on_strict_if_openai(
    ctx: RunContext, tool_defs: list[ToolDefinition]
) -> list[ToolDefinition] | None:
    if ctx.model.system == 'openai':
        return [replace(tool_def, strict=True) for tool_def in tool_defs]
    return tool_defs

agent = Agent('openai:gpt-5.2', capabilities=[PrepareTools(turn_on_strict_if_openai)])

Usage ToolsPrepareFunc[AgentDepsT].

ToolSelectorFunc module-attribute

ToolSelectorFunc: TypeAlias = Callable[
    [RunContext[AgentDepsT], "ToolDefinition"],
    bool | Awaitable[bool],
]

A callable that decides whether a tool matches a selection criterion.

Receives the run context and a tool definition, returns True if the tool is selected. Both sync and async functions are accepted.

Usage ToolSelectorFunc[AgentDepsT].

ToolSelector module-attribute

ToolSelector: TypeAlias = (
    Literal["all"]
    | Sequence[str]
    | dict[str, Any]
    | ToolSelectorFunc[AgentDepsT]
)

Specifies which tools a capability or toolset wrapper should apply to.

  • 'all': matches every tool (default for most capabilities).
  • Sequence[str]: matches tools whose names are in the sequence.
  • dict[str, Any]: matches tools whose metadata contains all the specified key-value pairs (deep inclusion check — nested dicts are compared recursively, and the tool's metadata may have additional keys).
  • Callable[[RunContext, ToolDefinition], bool | Awaitable[bool]]: custom sync or async predicate.

The first three forms are serializable for use in agent specs (YAML/JSON).

Usage ToolSelector[AgentDepsT].

matches_tool_selector async

matches_tool_selector(
    selector: ToolSelector[AgentDepsT],
    ctx: RunContext[AgentDepsT],
    tool_def: ToolDefinition,
) -> bool

Check whether a tool definition matches a ToolSelector.

Parameters:

Name Type Description Default
selector ToolSelector[AgentDepsT]

The selector to check against.

required
ctx RunContext[AgentDepsT]

The current run context.

required
tool_def ToolDefinition

The tool definition to test.

required

Returns:

Type Description
bool

True if the tool matches the selector.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
async def matches_tool_selector(
    selector: ToolSelector[AgentDepsT],
    ctx: RunContext[AgentDepsT],
    tool_def: ToolDefinition,
) -> bool:
    """Check whether a tool definition matches a [`ToolSelector`][pydantic_ai.tools.ToolSelector].

    Args:
        selector: The selector to check against.
        ctx: The current run context.
        tool_def: The tool definition to test.

    Returns:
        `True` if the tool matches the selector.
    """
    if selector == 'all':
        return True
    if callable(selector):
        result = selector(ctx, tool_def)
        if inspect.isawaitable(result):
            return await result
        return result
    if isinstance(selector, dict):
        metadata: dict[str, Any] = tool_def.metadata or {}
        return _metadata_includes(metadata, selector)
    if isinstance(selector, str):
        return tool_def.name == selector
    # Sequence[str] — match by tool name
    return tool_def.name in selector

NativeToolFunc module-attribute

Definition of a function that can prepare a native tool at call time.

This is useful if you want to customize the native tool based on the run context (e.g. user dependencies), or omit it completely from a step.

AgentNativeTool module-attribute

A native tool or a function that dynamically produces one.

This is a convenience alias for AbstractNativeTool | NativeToolFunc[AgentDepsT].

DocstringFormat module-attribute

DocstringFormat: TypeAlias = Literal[
    "google", "numpy", "sphinx", "auto"
]

Supported docstring formats.

  • 'google'Google-style docstrings.
  • 'numpy'Numpy-style docstrings.
  • 'sphinx'Sphinx-style docstrings.
  • 'auto' — Automatically infer the format based on the structure of the docstring.

DeferredToolRequests dataclass

Tool calls that require approval or external execution.

This can be used as an agent's output_type and will be used as the output of the agent run if the model called any deferred tools.

Results can be passed to the next agent run using a DeferredToolResults object with the same tool call IDs.

See deferred tools docs for more information.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
@dataclass(kw_only=True)
class DeferredToolRequests:
    """Tool calls that require approval or external execution.

    This can be used as an agent's `output_type` and will be used as the output of the agent run if the model called any deferred tools.

    Results can be passed to the next agent run using a [`DeferredToolResults`][pydantic_ai.tools.DeferredToolResults] object with the same tool call IDs.

    See [deferred tools docs](../deferred-tools.md#deferred-tools) for more information.
    """

    calls: list[ToolCallPart] = field(default_factory=list[ToolCallPart])
    """Tool calls that require external execution."""
    approvals: list[ToolCallPart] = field(default_factory=list[ToolCallPart])
    """Tool calls that require human-in-the-loop approval."""
    metadata: dict[str, dict[str, Any]] = field(default_factory=dict[str, dict[str, Any]])
    """Metadata for deferred tool calls, keyed by `tool_call_id`."""

    def build_results(
        self,
        *,
        approvals: dict[str, bool | DeferredToolApprovalResult] | None = None,
        calls: dict[str, DeferredToolCallResult | Any] | None = None,
        metadata: dict[str, dict[str, Any]] | None = None,
        approve_all: bool = False,
    ) -> DeferredToolResults:
        """Create a [`DeferredToolResults`][pydantic_ai.tools.DeferredToolResults] for these requests.

        Args:
            approvals: Results for tool calls that required approval. Keys must match
                `tool_call_id`s in `self.approvals`.
            calls: Results for tool calls that required external execution. Keys must
                match `tool_call_id`s in `self.calls`.
            metadata: Per-call metadata, keyed by `tool_call_id`.
            approve_all: If `True`, every approval-requesting call not already listed in
                `approvals` is approved (with default `ToolApproved()`).

        Raises:
            ValueError: If a key in `approvals`/`calls` doesn't match a pending request of
                the appropriate kind.
        """
        approvals = dict(approvals) if approvals else {}
        calls = dict(calls) if calls else {}

        approval_ids = {c.tool_call_id for c in self.approvals}
        call_ids = {c.tool_call_id for c in self.calls}

        if extra_approvals := set(approvals) - approval_ids:
            raise ValueError(
                f'`approvals` contains tool call IDs not in this `DeferredToolRequests.approvals`: {sorted(extra_approvals)}'
            )
        if extra_calls := set(calls) - call_ids:
            raise ValueError(
                f'`calls` contains tool call IDs not in this `DeferredToolRequests.calls`: {sorted(extra_calls)}'
            )

        if approve_all:
            for tool_call_id in approval_ids - set(approvals):
                approvals[tool_call_id] = ToolApproved()

        return DeferredToolResults(approvals=approvals, calls=calls, metadata=metadata or {})

    def remaining(self, results: DeferredToolResults) -> DeferredToolRequests | None:
        """Return unresolved requests after applying results, or `None` if all resolved."""
        resolved_ids = set(results.approvals) | set(results.calls)
        remaining = DeferredToolRequests(
            calls=[c for c in self.calls if c.tool_call_id not in resolved_ids],
            approvals=[c for c in self.approvals if c.tool_call_id not in resolved_ids],
            metadata={k: v for k, v in self.metadata.items() if k not in resolved_ids},
        )
        return remaining if remaining.calls or remaining.approvals else None

calls class-attribute instance-attribute

calls: list[ToolCallPart] = field(
    default_factory=list[ToolCallPart]
)

Tool calls that require external execution.

approvals class-attribute instance-attribute

approvals: list[ToolCallPart] = field(
    default_factory=list[ToolCallPart]
)

Tool calls that require human-in-the-loop approval.

metadata class-attribute instance-attribute

metadata: dict[str, dict[str, Any]] = field(
    default_factory=dict[str, dict[str, Any]]
)

Metadata for deferred tool calls, keyed by tool_call_id.

build_results

build_results(
    *,
    approvals: (
        dict[str, bool | DeferredToolApprovalResult] | None
    ) = None,
    calls: (
        dict[str, DeferredToolCallResult | Any] | None
    ) = None,
    metadata: dict[str, dict[str, Any]] | None = None,
    approve_all: bool = False
) -> DeferredToolResults

Create a DeferredToolResults for these requests.

Parameters:

Name Type Description Default
approvals dict[str, bool | DeferredToolApprovalResult] | None

Results for tool calls that required approval. Keys must match tool_call_ids in self.approvals.

None
calls dict[str, DeferredToolCallResult | Any] | None

Results for tool calls that required external execution. Keys must match tool_call_ids in self.calls.

None
metadata dict[str, dict[str, Any]] | None

Per-call metadata, keyed by tool_call_id.

None
approve_all bool

If True, every approval-requesting call not already listed in approvals is approved (with default ToolApproved()).

False

Raises:

Type Description
ValueError

If a key in approvals/calls doesn't match a pending request of the appropriate kind.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
def build_results(
    self,
    *,
    approvals: dict[str, bool | DeferredToolApprovalResult] | None = None,
    calls: dict[str, DeferredToolCallResult | Any] | None = None,
    metadata: dict[str, dict[str, Any]] | None = None,
    approve_all: bool = False,
) -> DeferredToolResults:
    """Create a [`DeferredToolResults`][pydantic_ai.tools.DeferredToolResults] for these requests.

    Args:
        approvals: Results for tool calls that required approval. Keys must match
            `tool_call_id`s in `self.approvals`.
        calls: Results for tool calls that required external execution. Keys must
            match `tool_call_id`s in `self.calls`.
        metadata: Per-call metadata, keyed by `tool_call_id`.
        approve_all: If `True`, every approval-requesting call not already listed in
            `approvals` is approved (with default `ToolApproved()`).

    Raises:
        ValueError: If a key in `approvals`/`calls` doesn't match a pending request of
            the appropriate kind.
    """
    approvals = dict(approvals) if approvals else {}
    calls = dict(calls) if calls else {}

    approval_ids = {c.tool_call_id for c in self.approvals}
    call_ids = {c.tool_call_id for c in self.calls}

    if extra_approvals := set(approvals) - approval_ids:
        raise ValueError(
            f'`approvals` contains tool call IDs not in this `DeferredToolRequests.approvals`: {sorted(extra_approvals)}'
        )
    if extra_calls := set(calls) - call_ids:
        raise ValueError(
            f'`calls` contains tool call IDs not in this `DeferredToolRequests.calls`: {sorted(extra_calls)}'
        )

    if approve_all:
        for tool_call_id in approval_ids - set(approvals):
            approvals[tool_call_id] = ToolApproved()

    return DeferredToolResults(approvals=approvals, calls=calls, metadata=metadata or {})

remaining

remaining(
    results: DeferredToolResults,
) -> DeferredToolRequests | None

Return unresolved requests after applying results, or None if all resolved.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
316
317
318
319
320
321
322
323
324
def remaining(self, results: DeferredToolResults) -> DeferredToolRequests | None:
    """Return unresolved requests after applying results, or `None` if all resolved."""
    resolved_ids = set(results.approvals) | set(results.calls)
    remaining = DeferredToolRequests(
        calls=[c for c in self.calls if c.tool_call_id not in resolved_ids],
        approvals=[c for c in self.approvals if c.tool_call_id not in resolved_ids],
        metadata={k: v for k, v in self.metadata.items() if k not in resolved_ids},
    )
    return remaining if remaining.calls or remaining.approvals else None

ToolApproved dataclass

Indicates that a tool call has been approved and that the tool function should be executed.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
327
328
329
330
331
332
333
334
@dataclass(kw_only=True)
class ToolApproved:
    """Indicates that a tool call has been approved and that the tool function should be executed."""

    override_args: dict[str, Any] | None = None
    """Optional tool call arguments to use instead of the original arguments."""

    kind: Literal['tool-approved'] = 'tool-approved'

override_args class-attribute instance-attribute

override_args: dict[str, Any] | None = None

Optional tool call arguments to use instead of the original arguments.

ToolDenied dataclass

Indicates that a tool call has been denied and that a denial message should be returned to the model.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
337
338
339
340
341
342
343
344
345
346
@dataclass
class ToolDenied:
    """Indicates that a tool call has been denied and that a denial message should be returned to the model."""

    message: str = 'The tool call was denied.'
    """The message to return to the model."""

    _: KW_ONLY

    kind: Literal['tool-denied'] = 'tool-denied'

message class-attribute instance-attribute

message: str = 'The tool call was denied.'

The message to return to the model.

DeferredToolApprovalResult module-attribute

DeferredToolApprovalResult: TypeAlias = Annotated[
    ToolApproved | ToolDenied, Discriminator("kind")
]

Result for a tool call that required human-in-the-loop approval.

DeferredToolCallResult module-attribute

DeferredToolCallResult: TypeAlias = Annotated[
    Annotated[ToolReturn, Tag("tool-return")]
    | Annotated[ModelRetry, Tag("model-retry")]
    | Annotated[RetryPromptPart, Tag("retry-prompt")],
    Discriminator(_deferred_tool_call_result_discriminator),
]

Result for a tool call that required external execution.

DeferredToolResult module-attribute

Result for a tool call that required approval or external execution.

DeferredToolResults dataclass

Results for deferred tool calls from a previous run that required approval or external execution.

The tool call IDs need to match those from the DeferredToolRequests output object from the previous run.

See deferred tools docs for more information.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
@dataclass(kw_only=True)
class DeferredToolResults:
    """Results for deferred tool calls from a previous run that required approval or external execution.

    The tool call IDs need to match those from the [`DeferredToolRequests`][pydantic_ai.tools.DeferredToolRequests] output object from the previous run.

    See [deferred tools docs](../deferred-tools.md#deferred-tools) for more information.
    """

    calls: dict[str, DeferredToolCallResult | Any] = field(default_factory=dict[str, DeferredToolCallResult | Any])
    """Map of tool call IDs to results for tool calls that required external execution."""
    approvals: dict[str, bool | DeferredToolApprovalResult] = field(
        default_factory=dict[str, bool | DeferredToolApprovalResult]
    )
    """Map of tool call IDs to results for tool calls that required human-in-the-loop approval."""
    metadata: dict[str, dict[str, Any]] = field(default_factory=dict[str, dict[str, Any]])
    """Metadata for deferred tool calls, keyed by `tool_call_id`. Each value will be available in the tool's RunContext as `tool_call_metadata`."""

    def update(self, other: DeferredToolResults) -> None:
        """Update this `DeferredToolResults` with entries from another, in-place."""
        self.approvals.update(other.approvals)
        self.calls.update(other.calls)
        self.metadata.update(other.metadata)

    def to_tool_call_results(self) -> dict[str, DeferredToolResult]:
        """Convert results into the internal per-call format used by the tool-execution pipeline.

        Normalizes `True`/`False` approvals to `ToolApproved`/`ToolDenied`, and wraps
        plain external-call values in `ToolReturn`.
        """
        tool_call_results: dict[str, DeferredToolResult] = {}
        for tool_call_id, approval in self.approvals.items():
            if approval is True:
                approval = ToolApproved()
            elif approval is False:
                approval = ToolDenied()
            tool_call_results[tool_call_id] = approval

        call_result_types = _utils.get_union_args(DeferredToolCallResult)
        for tool_call_id, call_result in self.calls.items():
            if not isinstance(call_result, call_result_types):
                call_result = ToolReturn(call_result)
            tool_call_results[tool_call_id] = call_result
        return tool_call_results

calls class-attribute instance-attribute

Map of tool call IDs to results for tool calls that required external execution.

approvals class-attribute instance-attribute

approvals: dict[str, bool | DeferredToolApprovalResult] = (
    field(
        default_factory=dict[
            str, bool | DeferredToolApprovalResult
        ]
    )
)

Map of tool call IDs to results for tool calls that required human-in-the-loop approval.

metadata class-attribute instance-attribute

metadata: dict[str, dict[str, Any]] = field(
    default_factory=dict[str, dict[str, Any]]
)

Metadata for deferred tool calls, keyed by tool_call_id. Each value will be available in the tool's RunContext as tool_call_metadata.

update

update(other: DeferredToolResults) -> None

Update this DeferredToolResults with entries from another, in-place.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
394
395
396
397
398
def update(self, other: DeferredToolResults) -> None:
    """Update this `DeferredToolResults` with entries from another, in-place."""
    self.approvals.update(other.approvals)
    self.calls.update(other.calls)
    self.metadata.update(other.metadata)

to_tool_call_results

to_tool_call_results() -> dict[str, DeferredToolResult]

Convert results into the internal per-call format used by the tool-execution pipeline.

Normalizes True/False approvals to ToolApproved/ToolDenied, and wraps plain external-call values in ToolReturn.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
def to_tool_call_results(self) -> dict[str, DeferredToolResult]:
    """Convert results into the internal per-call format used by the tool-execution pipeline.

    Normalizes `True`/`False` approvals to `ToolApproved`/`ToolDenied`, and wraps
    plain external-call values in `ToolReturn`.
    """
    tool_call_results: dict[str, DeferredToolResult] = {}
    for tool_call_id, approval in self.approvals.items():
        if approval is True:
            approval = ToolApproved()
        elif approval is False:
            approval = ToolDenied()
        tool_call_results[tool_call_id] = approval

    call_result_types = _utils.get_union_args(DeferredToolCallResult)
    for tool_call_id, call_result in self.calls.items():
        if not isinstance(call_result, call_result_types):
            call_result = ToolReturn(call_result)
        tool_call_results[tool_call_id] = call_result
    return tool_call_results

ToolAgentDepsT module-attribute

ToolAgentDepsT = TypeVar(
    "ToolAgentDepsT", default=object, contravariant=True
)

Type variable for agent dependencies for a tool.

Tool dataclass

Bases: Generic[ToolAgentDepsT]

A tool function for an agent.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
@dataclass(init=False)
class Tool(Generic[ToolAgentDepsT]):
    """A tool function for an agent."""

    function: ToolFuncEither[ToolAgentDepsT]
    takes_ctx: bool
    max_retries: int | None
    name: str
    description: str | None
    prepare: ToolPrepareFunc[ToolAgentDepsT] | None
    args_validator: ArgsValidatorFunc[ToolAgentDepsT, ...] | None
    docstring_format: DocstringFormat
    require_parameter_descriptions: bool
    strict: bool | None
    sequential: bool
    requires_approval: bool
    metadata: dict[str, Any] | None
    timeout: float | None
    defer_loading: bool
    include_return_schema: bool | None
    function_schema: _function_schema.FunctionSchema
    """
    The base JSON schema for the tool's parameters.

    This schema may be modified by the `prepare` function or by the Model class prior to including it in an API request.
    """

    def __init__(
        self,
        function: ToolFuncEither[ToolAgentDepsT, ToolParams],
        *,
        takes_ctx: bool | None = None,
        max_retries: int | None = None,
        name: str | None = None,
        description: str | None = None,
        prepare: ToolPrepareFunc[ToolAgentDepsT] | None = None,
        args_validator: ArgsValidatorFunc[ToolAgentDepsT, ToolParams] | None = None,
        docstring_format: DocstringFormat = 'auto',
        require_parameter_descriptions: bool = False,
        schema_generator: type[GenerateJsonSchema] = GenerateToolJsonSchema,
        strict: bool | None = None,
        sequential: bool = False,
        requires_approval: bool = False,
        metadata: dict[str, Any] | None = None,
        timeout: float | None = None,
        defer_loading: bool = False,
        include_return_schema: bool | None = None,
        function_schema: _function_schema.FunctionSchema | None = None,
    ):
        """Create a new tool instance.

        Example usage:

        ```python {noqa="I001"}
        from pydantic_ai import Agent, RunContext, Tool

        async def my_tool(ctx: RunContext[int], x: int, y: int) -> str:
            return f'{ctx.deps} {x} {y}'

        agent = Agent('test', tools=[Tool(my_tool)])
        ```

        or with a custom prepare method:

        ```python {noqa="I001"}

        from pydantic_ai import Agent, RunContext, Tool
        from pydantic_ai.tools import ToolDefinition

        async def my_tool(ctx: RunContext[int], x: int, y: int) -> str:
            return f'{ctx.deps} {x} {y}'

        async def prep_my_tool(
            ctx: RunContext[int], tool_def: ToolDefinition
        ) -> ToolDefinition | None:
            # only register the tool if `deps == 42`
            if ctx.deps == 42:
                return tool_def

        agent = Agent('test', tools=[Tool(my_tool, prepare=prep_my_tool)])
        ```


        Args:
            function: The Python function to call as the tool.
            takes_ctx: Whether the function takes a [`RunContext`][pydantic_ai.tools.RunContext] first argument,
                this is inferred if unset.
            max_retries: Maximum number of retries allowed for this tool, set to the agent default if `None`.
            name: Name of the tool, inferred from the function if `None`.
            description: Description of the tool, inferred from the function if `None`.
            prepare: custom method to prepare the tool definition for each step, return `None` to omit this
                tool from a given step. This is useful if you want to customise a tool at call time,
                or omit it completely from a step. See [`ToolPrepareFunc`][pydantic_ai.tools.ToolPrepareFunc].
            args_validator: custom method to validate tool arguments after schema validation has passed,
                before execution. The validator receives the already-validated and type-converted parameters,
                with `RunContext` as the first argument.
                Should raise [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] on validation failure,
                return `None` on success.
                See [`ArgsValidatorFunc`][pydantic_ai.tools.ArgsValidatorFunc].
            docstring_format: The format of the docstring, see [`DocstringFormat`][pydantic_ai.tools.DocstringFormat].
                Defaults to `'auto'`, such that the format is inferred from the structure of the docstring.
            require_parameter_descriptions: If True, raise an error if a parameter description is missing. Defaults to False.
            schema_generator: The JSON schema generator class to use. Defaults to `GenerateToolJsonSchema`.
            strict: Whether to enforce JSON schema compliance (only affects OpenAI).
                See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info.
            sequential: Whether this tool acts as a barrier that runs alone, not overlapping with other tool calls.
                See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info. Defaults to False.
            requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
                See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
            metadata: Optional metadata for the tool. This is not sent to the model but can be used for filtering and tool behavior customization.
            timeout: Timeout in seconds for tool execution. If the tool takes longer, a retry prompt is returned to the model.
                Defaults to None (no timeout).
            defer_loading: Whether to hide this tool until it's discovered via tool search. Defaults to False.
                See [Tool Search](../tools-advanced.md#tool-search) for more info.
            include_return_schema: Whether to include the return schema in the tool definition sent to the model.
                If `None`, defaults to `False` unless the [`IncludeToolReturnSchemas`][pydantic_ai.capabilities.IncludeToolReturnSchemas] capability is used.
            function_schema: The function schema to use for the tool. If not provided, it will be generated.
        """
        self.function = function
        self.name = name or function.__name__
        self.function_schema = function_schema or _function_schema.function_schema(
            function,
            schema_generator,
            tool_name=self.name,
            takes_ctx=takes_ctx,
            docstring_format=docstring_format,
            require_parameter_descriptions=require_parameter_descriptions,
        )
        self.takes_ctx = self.function_schema.takes_ctx
        self.max_retries = max_retries
        self.description = description or self.function_schema.description
        self.prepare = prepare
        self.args_validator = args_validator
        self.docstring_format = docstring_format
        self.require_parameter_descriptions = require_parameter_descriptions
        self.strict = strict
        self.sequential = sequential
        self.requires_approval = requires_approval
        self.metadata = metadata
        self.timeout = timeout
        self.defer_loading = defer_loading
        self.include_return_schema = include_return_schema

    @classmethod
    def from_schema(
        cls,
        function: Callable[..., Any],
        name: str,
        description: str | None,
        json_schema: JsonSchemaValue,
        takes_ctx: bool = False,
        sequential: bool = False,
        args_validator: ArgsValidatorFunc[Any, ...] | None = None,
    ) -> Self:
        """Creates a Pydantic tool from a function and a JSON schema.

        Args:
            function: The function to call.
                This will be called with keywords only. Schema validation of
                the arguments is skipped, but a custom `args_validator` will
                still run if provided.
            name: The unique name of the tool that clearly communicates its purpose
            description: Used to tell the model how/when/why to use the tool.
                You can provide few-shot examples as a part of the description.
            json_schema: The schema for the function arguments
            takes_ctx: An optional boolean parameter indicating whether the function
                accepts the context object as an argument.
            sequential: Whether this tool acts as a barrier that runs alone, not overlapping with other tool calls.
                See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info. Defaults to False.
            args_validator: custom method to validate tool arguments after schema validation has passed,
                before execution. The validator receives the already-validated and type-converted parameters,
                with `RunContext` as the first argument.
                Should raise [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] on validation failure,
                return `None` on success.
                See [`ArgsValidatorFunc`][pydantic_ai.tools.ArgsValidatorFunc].

        Returns:
            A Pydantic tool that calls the function
        """
        function_schema = _function_schema.FunctionSchema(
            function=function,
            name=name,
            description=description,
            validator=SchemaValidator(schema=core_schema.any_schema()),
            json_schema=json_schema,
            takes_ctx=takes_ctx,
            is_async=_utils.is_async_callable(function),
        )

        tool = cls(
            function,
            takes_ctx=takes_ctx,
            name=name,
            description=description,
            function_schema=function_schema,
            sequential=sequential,
            args_validator=args_validator,
        )
        return tool

    @property
    def tool_def(self) -> ToolDefinition:
        return ToolDefinition(
            name=self.name,
            description=self.description,
            parameters_json_schema=self.function_schema.json_schema,
            strict=self.strict,
            sequential=self.sequential,
            metadata=self.metadata,
            timeout=self.timeout,
            defer_loading=self.defer_loading,
            kind='unapproved' if self.requires_approval else 'function',
            return_schema=self.function_schema.return_schema,
            include_return_schema=self.include_return_schema,
        )

    async def prepare_tool_def(self, ctx: RunContext[ToolAgentDepsT]) -> ToolDefinition | None:
        """Get the tool definition.

        By default, this method creates a tool definition, then either returns it, or calls `self.prepare`
        if it's set.

        Returns:
            return a `ToolDefinition` or `None` if the tools should not be registered for this run.
        """
        tool_def = self.tool_def

        if self.prepare is not None:
            result = self.prepare(ctx, tool_def)
            if inspect.isawaitable(result):
                return await result
            return result
        else:
            return tool_def

__init__

__init__(
    function: ToolFuncEither[ToolAgentDepsT, ToolParams],
    *,
    takes_ctx: bool | None = None,
    max_retries: int | None = None,
    name: str | None = None,
    description: str | None = None,
    prepare: ToolPrepareFunc[ToolAgentDepsT] | None = None,
    args_validator: (
        ArgsValidatorFunc[ToolAgentDepsT, ToolParams] | None
    ) = None,
    docstring_format: DocstringFormat = "auto",
    require_parameter_descriptions: bool = False,
    schema_generator: type[
        GenerateJsonSchema
    ] = GenerateToolJsonSchema,
    strict: bool | None = None,
    sequential: bool = False,
    requires_approval: bool = False,
    metadata: dict[str, Any] | None = None,
    timeout: float | None = None,
    defer_loading: bool = False,
    include_return_schema: bool | None = None,
    function_schema: FunctionSchema | None = None
)

Create a new tool instance.

Example usage:

from pydantic_ai import Agent, RunContext, Tool

async def my_tool(ctx: RunContext[int], x: int, y: int) -> str:
    return f'{ctx.deps} {x} {y}'

agent = Agent('test', tools=[Tool(my_tool)])

or with a custom prepare method:

from pydantic_ai import Agent, RunContext, Tool
from pydantic_ai.tools import ToolDefinition

async def my_tool(ctx: RunContext[int], x: int, y: int) -> str:
    return f'{ctx.deps} {x} {y}'

async def prep_my_tool(
    ctx: RunContext[int], tool_def: ToolDefinition
) -> ToolDefinition | None:
    # only register the tool if `deps == 42`
    if ctx.deps == 42:
        return tool_def

agent = Agent('test', tools=[Tool(my_tool, prepare=prep_my_tool)])

Parameters:

Name Type Description Default
function ToolFuncEither[ToolAgentDepsT, ToolParams]

The Python function to call as the tool.

required
takes_ctx bool | None

Whether the function takes a RunContext first argument, this is inferred if unset.

None
max_retries int | None

Maximum number of retries allowed for this tool, set to the agent default if None.

None
name str | None

Name of the tool, inferred from the function if None.

None
description str | None

Description of the tool, inferred from the function if None.

None
prepare ToolPrepareFunc[ToolAgentDepsT] | None

custom method to prepare the tool definition for each step, return None to omit this tool from a given step. This is useful if you want to customise a tool at call time, or omit it completely from a step. See ToolPrepareFunc.

None
args_validator ArgsValidatorFunc[ToolAgentDepsT, ToolParams] | None

custom method to validate tool arguments after schema validation has passed, before execution. The validator receives the already-validated and type-converted parameters, with RunContext as the first argument. Should raise ModelRetry on validation failure, return None on success. See ArgsValidatorFunc.

None
docstring_format DocstringFormat

The format of the docstring, see DocstringFormat. Defaults to 'auto', such that the format is inferred from the structure of the docstring.

'auto'
require_parameter_descriptions bool

If True, raise an error if a parameter description is missing. Defaults to False.

False
schema_generator type[GenerateJsonSchema]

The JSON schema generator class to use. Defaults to GenerateToolJsonSchema.

GenerateToolJsonSchema
strict bool | None

Whether to enforce JSON schema compliance (only affects OpenAI). See ToolDefinition for more info.

None
sequential bool

Whether this tool acts as a barrier that runs alone, not overlapping with other tool calls. See ToolDefinition for more info. Defaults to False.

False
requires_approval bool

Whether this tool requires human-in-the-loop approval. Defaults to False. See the tools documentation for more info.

False
metadata dict[str, Any] | None

Optional metadata for the tool. This is not sent to the model but can be used for filtering and tool behavior customization.

None
timeout float | None

Timeout in seconds for tool execution. If the tool takes longer, a retry prompt is returned to the model. Defaults to None (no timeout).

None
defer_loading bool

Whether to hide this tool until it's discovered via tool search. Defaults to False. See Tool Search for more info.

False
include_return_schema bool | None

Whether to include the return schema in the tool definition sent to the model. If None, defaults to False unless the IncludeToolReturnSchemas capability is used.

None
function_schema FunctionSchema | None

The function schema to use for the tool. If not provided, it will be generated.

None
Source code in pydantic_ai_slim/pydantic_ai/tools.py
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
def __init__(
    self,
    function: ToolFuncEither[ToolAgentDepsT, ToolParams],
    *,
    takes_ctx: bool | None = None,
    max_retries: int | None = None,
    name: str | None = None,
    description: str | None = None,
    prepare: ToolPrepareFunc[ToolAgentDepsT] | None = None,
    args_validator: ArgsValidatorFunc[ToolAgentDepsT, ToolParams] | None = None,
    docstring_format: DocstringFormat = 'auto',
    require_parameter_descriptions: bool = False,
    schema_generator: type[GenerateJsonSchema] = GenerateToolJsonSchema,
    strict: bool | None = None,
    sequential: bool = False,
    requires_approval: bool = False,
    metadata: dict[str, Any] | None = None,
    timeout: float | None = None,
    defer_loading: bool = False,
    include_return_schema: bool | None = None,
    function_schema: _function_schema.FunctionSchema | None = None,
):
    """Create a new tool instance.

    Example usage:

    ```python {noqa="I001"}
    from pydantic_ai import Agent, RunContext, Tool

    async def my_tool(ctx: RunContext[int], x: int, y: int) -> str:
        return f'{ctx.deps} {x} {y}'

    agent = Agent('test', tools=[Tool(my_tool)])
    ```

    or with a custom prepare method:

    ```python {noqa="I001"}

    from pydantic_ai import Agent, RunContext, Tool
    from pydantic_ai.tools import ToolDefinition

    async def my_tool(ctx: RunContext[int], x: int, y: int) -> str:
        return f'{ctx.deps} {x} {y}'

    async def prep_my_tool(
        ctx: RunContext[int], tool_def: ToolDefinition
    ) -> ToolDefinition | None:
        # only register the tool if `deps == 42`
        if ctx.deps == 42:
            return tool_def

    agent = Agent('test', tools=[Tool(my_tool, prepare=prep_my_tool)])
    ```


    Args:
        function: The Python function to call as the tool.
        takes_ctx: Whether the function takes a [`RunContext`][pydantic_ai.tools.RunContext] first argument,
            this is inferred if unset.
        max_retries: Maximum number of retries allowed for this tool, set to the agent default if `None`.
        name: Name of the tool, inferred from the function if `None`.
        description: Description of the tool, inferred from the function if `None`.
        prepare: custom method to prepare the tool definition for each step, return `None` to omit this
            tool from a given step. This is useful if you want to customise a tool at call time,
            or omit it completely from a step. See [`ToolPrepareFunc`][pydantic_ai.tools.ToolPrepareFunc].
        args_validator: custom method to validate tool arguments after schema validation has passed,
            before execution. The validator receives the already-validated and type-converted parameters,
            with `RunContext` as the first argument.
            Should raise [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] on validation failure,
            return `None` on success.
            See [`ArgsValidatorFunc`][pydantic_ai.tools.ArgsValidatorFunc].
        docstring_format: The format of the docstring, see [`DocstringFormat`][pydantic_ai.tools.DocstringFormat].
            Defaults to `'auto'`, such that the format is inferred from the structure of the docstring.
        require_parameter_descriptions: If True, raise an error if a parameter description is missing. Defaults to False.
        schema_generator: The JSON schema generator class to use. Defaults to `GenerateToolJsonSchema`.
        strict: Whether to enforce JSON schema compliance (only affects OpenAI).
            See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info.
        sequential: Whether this tool acts as a barrier that runs alone, not overlapping with other tool calls.
            See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info. Defaults to False.
        requires_approval: Whether this tool requires human-in-the-loop approval. Defaults to False.
            See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
        metadata: Optional metadata for the tool. This is not sent to the model but can be used for filtering and tool behavior customization.
        timeout: Timeout in seconds for tool execution. If the tool takes longer, a retry prompt is returned to the model.
            Defaults to None (no timeout).
        defer_loading: Whether to hide this tool until it's discovered via tool search. Defaults to False.
            See [Tool Search](../tools-advanced.md#tool-search) for more info.
        include_return_schema: Whether to include the return schema in the tool definition sent to the model.
            If `None`, defaults to `False` unless the [`IncludeToolReturnSchemas`][pydantic_ai.capabilities.IncludeToolReturnSchemas] capability is used.
        function_schema: The function schema to use for the tool. If not provided, it will be generated.
    """
    self.function = function
    self.name = name or function.__name__
    self.function_schema = function_schema or _function_schema.function_schema(
        function,
        schema_generator,
        tool_name=self.name,
        takes_ctx=takes_ctx,
        docstring_format=docstring_format,
        require_parameter_descriptions=require_parameter_descriptions,
    )
    self.takes_ctx = self.function_schema.takes_ctx
    self.max_retries = max_retries
    self.description = description or self.function_schema.description
    self.prepare = prepare
    self.args_validator = args_validator
    self.docstring_format = docstring_format
    self.require_parameter_descriptions = require_parameter_descriptions
    self.strict = strict
    self.sequential = sequential
    self.requires_approval = requires_approval
    self.metadata = metadata
    self.timeout = timeout
    self.defer_loading = defer_loading
    self.include_return_schema = include_return_schema

function_schema instance-attribute

function_schema: FunctionSchema = (
    function_schema
    or function_schema(
        function,
        schema_generator,
        tool_name=name,
        takes_ctx=takes_ctx,
        docstring_format=docstring_format,
        require_parameter_descriptions=require_parameter_descriptions,
    )
)

The base JSON schema for the tool's parameters.

This schema may be modified by the prepare function or by the Model class prior to including it in an API request.

from_schema classmethod

from_schema(
    function: Callable[..., Any],
    name: str,
    description: str | None,
    json_schema: JsonSchemaValue,
    takes_ctx: bool = False,
    sequential: bool = False,
    args_validator: (
        ArgsValidatorFunc[Any, ...] | None
    ) = None,
) -> Self

Creates a Pydantic tool from a function and a JSON schema.

Parameters:

Name Type Description Default
function Callable[..., Any]

The function to call. This will be called with keywords only. Schema validation of the arguments is skipped, but a custom args_validator will still run if provided.

required
name str

The unique name of the tool that clearly communicates its purpose

required
description str | None

Used to tell the model how/when/why to use the tool. You can provide few-shot examples as a part of the description.

required
json_schema JsonSchemaValue

The schema for the function arguments

required
takes_ctx bool

An optional boolean parameter indicating whether the function accepts the context object as an argument.

False
sequential bool

Whether this tool acts as a barrier that runs alone, not overlapping with other tool calls. See ToolDefinition for more info. Defaults to False.

False
args_validator ArgsValidatorFunc[Any, ...] | None

custom method to validate tool arguments after schema validation has passed, before execution. The validator receives the already-validated and type-converted parameters, with RunContext as the first argument. Should raise ModelRetry on validation failure, return None on success. See ArgsValidatorFunc.

None

Returns:

Type Description
Self

A Pydantic tool that calls the function

Source code in pydantic_ai_slim/pydantic_ai/tools.py
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
@classmethod
def from_schema(
    cls,
    function: Callable[..., Any],
    name: str,
    description: str | None,
    json_schema: JsonSchemaValue,
    takes_ctx: bool = False,
    sequential: bool = False,
    args_validator: ArgsValidatorFunc[Any, ...] | None = None,
) -> Self:
    """Creates a Pydantic tool from a function and a JSON schema.

    Args:
        function: The function to call.
            This will be called with keywords only. Schema validation of
            the arguments is skipped, but a custom `args_validator` will
            still run if provided.
        name: The unique name of the tool that clearly communicates its purpose
        description: Used to tell the model how/when/why to use the tool.
            You can provide few-shot examples as a part of the description.
        json_schema: The schema for the function arguments
        takes_ctx: An optional boolean parameter indicating whether the function
            accepts the context object as an argument.
        sequential: Whether this tool acts as a barrier that runs alone, not overlapping with other tool calls.
            See [`ToolDefinition`][pydantic_ai.tools.ToolDefinition] for more info. Defaults to False.
        args_validator: custom method to validate tool arguments after schema validation has passed,
            before execution. The validator receives the already-validated and type-converted parameters,
            with `RunContext` as the first argument.
            Should raise [`ModelRetry`][pydantic_ai.exceptions.ModelRetry] on validation failure,
            return `None` on success.
            See [`ArgsValidatorFunc`][pydantic_ai.tools.ArgsValidatorFunc].

    Returns:
        A Pydantic tool that calls the function
    """
    function_schema = _function_schema.FunctionSchema(
        function=function,
        name=name,
        description=description,
        validator=SchemaValidator(schema=core_schema.any_schema()),
        json_schema=json_schema,
        takes_ctx=takes_ctx,
        is_async=_utils.is_async_callable(function),
    )

    tool = cls(
        function,
        takes_ctx=takes_ctx,
        name=name,
        description=description,
        function_schema=function_schema,
        sequential=sequential,
        args_validator=args_validator,
    )
    return tool

prepare_tool_def async

prepare_tool_def(
    ctx: RunContext[ToolAgentDepsT],
) -> ToolDefinition | None

Get the tool definition.

By default, this method creates a tool definition, then either returns it, or calls self.prepare if it's set.

Returns:

Type Description
ToolDefinition | None

return a ToolDefinition or None if the tools should not be registered for this run.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
async def prepare_tool_def(self, ctx: RunContext[ToolAgentDepsT]) -> ToolDefinition | None:
    """Get the tool definition.

    By default, this method creates a tool definition, then either returns it, or calls `self.prepare`
    if it's set.

    Returns:
        return a `ToolDefinition` or `None` if the tools should not be registered for this run.
    """
    tool_def = self.tool_def

    if self.prepare is not None:
        result = self.prepare(ctx, tool_def)
        if inspect.isawaitable(result):
            return await result
        return result
    else:
        return tool_def

ObjectJsonSchema module-attribute

ObjectJsonSchema: TypeAlias = dict[str, Any]

Type representing JSON schema of an object, e.g. where "type": "object".

This type is used to define tools parameters (aka arguments) in ToolDefinition.

With PEP-728 this should be a TypedDict with type: Literal['object'], and extra_parts=Any

ToolKind module-attribute

ToolKind: TypeAlias = Literal[
    "function", "output", "external", "unapproved"
]

Kind of tool.

ToolDefinition dataclass

Definition of a tool passed to a model.

This is used for both function tools and output tools.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
@dataclass(repr=False, kw_only=True)
class ToolDefinition:
    """Definition of a tool passed to a model.

    This is used for both function tools and output tools.
    """

    name: str
    """The name of the tool."""

    parameters_json_schema: ObjectJsonSchema = field(default_factory=lambda: {'type': 'object', 'properties': {}})
    """The JSON schema for the tool's parameters."""

    description: str | None = None
    """The description of the tool."""

    outer_typed_dict_key: str | None = None
    """The key in the outer [TypedDict] that wraps an output tool.

    This will only be set for output tools which don't have an `object` JSON schema.
    """

    strict: bool | None = None
    """Whether to enforce (vendor-specific) strict JSON schema validation for tool calls.

    Setting this to `True` while using a supported model generally imposes some restrictions on the tool's JSON schema
    in exchange for guaranteeing the API responses strictly match that schema.

    When `False`, the model may be free to generate other properties or types (depending on the vendor).
    When `None` (the default), the value will be inferred based on the compatibility of the parameters_json_schema.

    Note: this is currently supported by OpenAI and Anthropic models.
    """

    sequential: bool = False
    """Whether this tool acts as a barrier that runs alone, not overlapping with other tool calls.

    A `sequential=True` tool acts as a barrier: it runs alone, with tools the model emitted before it
    completing first and tools emitted after it starting only once it finishes. Other tools still run
    in parallel around it. To run an entire run's tools serially, use
    [`parallel_execution_mode('sequential')`][pydantic_ai.tool_manager.ToolManager.parallel_execution_mode]
    instead.
    """

    kind: ToolKind = field(default='function')
    """The kind of tool:

    - `'function'`: a tool that will be executed by Pydantic AI during an agent run and has its result returned to the model
    - `'output'`: a tool that passes through an output value that ends the run
    - `'external'`: a tool whose result will be produced outside of the Pydantic AI agent run in which it was called, because it depends on an upstream service (or user) or could take longer to generate than it's reasonable to keep the agent process running.
        See the [tools documentation](../deferred-tools.md#deferred-tools) for more info.
    - `'unapproved'`: a tool that requires human-in-the-loop approval.
        See the [tools documentation](../deferred-tools.md#human-in-the-loop-tool-approval) for more info.
    """

    metadata: dict[str, Any] | None = None
    """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.

    For MCP tools, this contains the `meta`, `annotations`, and `output_schema` fields from the tool definition.
    """

    timeout: float | None = None
    """Timeout in seconds for tool execution.

    If the tool takes longer than this, a retry prompt is returned to the model.
    Defaults to None (no timeout).
    """

    defer_loading: bool = False
    """Whether this tool should be hidden from the model until something explicitly surfaces it.

    Carries two meanings depending on where in the pipeline you observe it:

    1. **User-input intent** — set on `Tool(defer_loading=True)` (or via a custom toolset)
       to opt this tool into deferred loading. This is what `prepare_tools` hooks and other
       pre-toolset-wrapping consumers see, and is the value users persist on `ToolDefinition`.
    2. **Current visibility state** — after a toolset like
       [`ToolSearchToolset`][pydantic_ai.toolsets._tool_search.ToolSearchToolset] processes
       the corpus, it flips this field to `False` for tools whose discovery shows up in
       message history, so downstream `Model.prepare_request` filtering and adapter wire
       formatting can read "should this be on the wire?" off a single boolean.

    The dual meaning is acknowledged tech debt: a future `RunContext.loaded_tools` /
    equivalent will surface (2) as a derived view so this field cleanly stays a user-input
    flag. Until then, the toolset-set value flows through agent-graph plumbing on a per-step
    `ToolDefinition` instance built via `replace(...)`; user-persisted definitions are not
    mutated.

    See [Tool Search](../tools-advanced.md#tool-search) for more info.
    """

    unless_native: Annotated[
        str | None,
        # Old names were `prefer_builtin` and (after the builtin → native rename in #5338)
        # `prefer_native`; keep accepting both for serialized-history backward compat.
        Field(validation_alias=AliasChoices('unless_native', 'prefer_native', 'prefer_builtin')),
    ] = None
    """If set, this tool is dropped from the wire when the named native tool is supported by the model.

    Generic version of the old `prefer_builtin` flag: a function tool carrying
    `unless_native='web_search'` is treated as a local fallback for the
    [`WebSearchTool`][pydantic_ai.native_tools.WebSearchTool] native tool and silently
    removed from the request whenever the model handles `WebSearchTool` natively. It
    stays in the request when the native tool isn't supported.
    """

    with_native: str | None = None
    """If set, this tool is kept on the wire when the named native tool is supported, with the
    native tool's adapter applying any wire-format adjustments (e.g. setting `defer_loading=True`
    on the request param for the framework-managed tool-search native tool).

    Symmetric pair with `unless_native`:

    * `unless_native='X'` — drop me from the wire when X is supported (local fallback).
    * `with_native='X'` — keep me on the wire when X is supported, formatted via X's adapter
      (corpus member managed by the native tool).

    When the named native tool is unsupported, a tool with `with_native` and `defer_loading=True`
    is dropped (the corpus member is currently undiscovered, so the model can't call it on
    this provider); otherwise it's kept as a regular function tool.
    """

    # Implementation note for new typed native tools: registering a new tool_kind value
    # requires (1) extending the ToolPartKind Literal in messages.py, (2) defining
    # the typed subclass + narrower under pydantic_ai/<your_native_tool>.py and registering
    # in _TOOL_CALL_NARROWERS / _NATIVE_CALL_NARROWERS / _TOOL_RETURN_NARROWERS /
    # _NATIVE_RETURN_NARROWERS, (3) adding the (part_kind, tool_kind) → Tag entries
    # in messages.py's _TYPED_PART_TAGS and _TYPED_PART_TAGS_BY_TYPE registries, and
    # (4) extending the ModelResponsePart / ModelRequestPart Annotated unions with
    # the new typed subclasses.
    tool_kind: ToolPartKind | None = None
    """Discriminator for a cross-provider typed call/return shape (e.g. `'tool-search'`).

    Set by the framework when a tool emits parts that should be promoted to a typed
    subclass (such as [`ToolSearchCallPart`][pydantic_ai.messages.ToolSearchCallPart]
    and [`ToolSearchReturnPart`][pydantic_ai.messages.ToolSearchReturnPart]). Leave as
    `None` for user-defined function tools — they go through the standard
    [`ToolCallPart`][pydantic_ai.messages.ToolCallPart] /
    [`ToolReturnPart`][pydantic_ai.messages.ToolReturnPart] shapes.

    To detect a tool-search part regardless of execution path (native server-side vs.
    local fallback), check `part.tool_kind == 'tool-search'` — this works across both
    call/return and both server/local variants.

    Distinct from [`kind`][pydantic_ai.tools.ToolDefinition.kind], which is about invocation
    semantics (`'function'` / `'output'` / `'external'` / `'unapproved'`).
    """

    return_schema: ObjectJsonSchema | None = None
    """The JSON schema for the tool's return value.

    For models that natively support return schemas (e.g. Google Gemini), this is passed as a
    structured field in the API request. For other models, it is injected into the tool's
    description as JSON text. Only included when `include_return_schema` resolves to `True`.
    """

    include_return_schema: bool | None = None
    """Whether to include the return schema in the tool definition sent to the model.

    When `True`, the `return_schema` will be preserved and sent to the model.
    When `False`, the `return_schema` will be cleared before sending.
    When `None` (default), defaults to `False` unless the
    [`IncludeToolReturnSchemas`][pydantic_ai.capabilities.IncludeToolReturnSchemas] capability is used.
    """

    @cached_property
    def function_signature(self) -> FunctionSignature:
        """The function signature shape for this tool.

        Lazily computed from `parameters_json_schema` and `return_schema` on first access.
        Name and description are not stored on the signature — pass them at render time
        via `sig.render(body, name=td.name, description=td.description)`.
        """
        return FunctionSignature.from_schema(
            name=self.name,
            parameters_schema=self.parameters_json_schema,
            return_schema=self.return_schema,
        )

    def render_signature(self, body: str, **kwargs: Any) -> str:
        """Render the function signature with this tool's name and description.

        Convenience wrapper around `self.function_signature.render()` that
        supplies `name` and `description` from this tool definition.
        """
        return self.function_signature.render(body, name=self.name, description=self.description, **kwargs)

    @property
    def defer(self) -> bool:
        """Whether calls to this tool will be deferred.

        See the [tools documentation](../deferred-tools.md#deferred-tools) for more info.
        """
        return self.kind in ('external', 'unapproved')

    __repr__ = _utils.dataclasses_no_defaults_repr

name instance-attribute

name: str

The name of the tool.

parameters_json_schema class-attribute instance-attribute

parameters_json_schema: ObjectJsonSchema = field(
    default_factory=lambda: {
        "type": "object",
        "properties": {},
    }
)

The JSON schema for the tool's parameters.

description class-attribute instance-attribute

description: str | None = None

The description of the tool.

outer_typed_dict_key class-attribute instance-attribute

outer_typed_dict_key: str | None = None

The key in the outer [TypedDict] that wraps an output tool.

This will only be set for output tools which don't have an object JSON schema.

strict class-attribute instance-attribute

strict: bool | None = None

Whether to enforce (vendor-specific) strict JSON schema validation for tool calls.

Setting this to True while using a supported model generally imposes some restrictions on the tool's JSON schema in exchange for guaranteeing the API responses strictly match that schema.

When False, the model may be free to generate other properties or types (depending on the vendor). When None (the default), the value will be inferred based on the compatibility of the parameters_json_schema.

Note: this is currently supported by OpenAI and Anthropic models.

sequential class-attribute instance-attribute

sequential: bool = False

Whether this tool acts as a barrier that runs alone, not overlapping with other tool calls.

A sequential=True tool acts as a barrier: it runs alone, with tools the model emitted before it completing first and tools emitted after it starting only once it finishes. Other tools still run in parallel around it. To run an entire run's tools serially, use [parallel_execution_mode('sequential')][pydantic_ai.tool_manager.ToolManager.parallel_execution_mode] instead.

kind class-attribute instance-attribute

kind: ToolKind = field(default='function')

The kind of tool:

  • 'function': a tool that will be executed by Pydantic AI during an agent run and has its result returned to the model
  • 'output': a tool that passes through an output value that ends the run
  • 'external': a tool whose result will be produced outside of the Pydantic AI agent run in which it was called, because it depends on an upstream service (or user) or could take longer to generate than it's reasonable to keep the agent process running. See the tools documentation for more info.
  • 'unapproved': a tool that requires human-in-the-loop approval. See the tools documentation for more info.

metadata class-attribute instance-attribute

metadata: dict[str, Any] | None = None

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.

For MCP tools, this contains the meta, annotations, and output_schema fields from the tool definition.

timeout class-attribute instance-attribute

timeout: float | None = None

Timeout in seconds for tool execution.

If the tool takes longer than this, a retry prompt is returned to the model. Defaults to None (no timeout).

defer_loading class-attribute instance-attribute

defer_loading: bool = False

Whether this tool should be hidden from the model until something explicitly surfaces it.

Carries two meanings depending on where in the pipeline you observe it:

  1. User-input intent — set on Tool(defer_loading=True) (or via a custom toolset) to opt this tool into deferred loading. This is what prepare_tools hooks and other pre-toolset-wrapping consumers see, and is the value users persist on ToolDefinition.
  2. Current visibility state — after a toolset like [ToolSearchToolset][pydantic_ai.toolsets._tool_search.ToolSearchToolset] processes the corpus, it flips this field to False for tools whose discovery shows up in message history, so downstream Model.prepare_request filtering and adapter wire formatting can read "should this be on the wire?" off a single boolean.

The dual meaning is acknowledged tech debt: a future RunContext.loaded_tools / equivalent will surface (2) as a derived view so this field cleanly stays a user-input flag. Until then, the toolset-set value flows through agent-graph plumbing on a per-step ToolDefinition instance built via replace(...); user-persisted definitions are not mutated.

See Tool Search for more info.

unless_native class-attribute instance-attribute

unless_native: Annotated[
    str | None,
    Field(
        validation_alias=AliasChoices(
            unless_native, prefer_native, prefer_builtin
        )
    ),
] = None

If set, this tool is dropped from the wire when the named native tool is supported by the model.

Generic version of the old prefer_builtin flag: a function tool carrying unless_native='web_search' is treated as a local fallback for the WebSearchTool native tool and silently removed from the request whenever the model handles WebSearchTool natively. It stays in the request when the native tool isn't supported.

with_native class-attribute instance-attribute

with_native: str | None = None

If set, this tool is kept on the wire when the named native tool is supported, with the native tool's adapter applying any wire-format adjustments (e.g. setting defer_loading=True on the request param for the framework-managed tool-search native tool).

Symmetric pair with unless_native:

  • unless_native='X' — drop me from the wire when X is supported (local fallback).
  • with_native='X' — keep me on the wire when X is supported, formatted via X's adapter (corpus member managed by the native tool).

When the named native tool is unsupported, a tool with with_native and defer_loading=True is dropped (the corpus member is currently undiscovered, so the model can't call it on this provider); otherwise it's kept as a regular function tool.

tool_kind class-attribute instance-attribute

tool_kind: ToolPartKind | None = None

Discriminator for a cross-provider typed call/return shape (e.g. 'tool-search').

Set by the framework when a tool emits parts that should be promoted to a typed subclass (such as [ToolSearchCallPart][pydantic_ai.messages.ToolSearchCallPart] and [ToolSearchReturnPart][pydantic_ai.messages.ToolSearchReturnPart]). Leave as None for user-defined function tools — they go through the standard ToolCallPart / ToolReturnPart shapes.

To detect a tool-search part regardless of execution path (native server-side vs. local fallback), check part.tool_kind == 'tool-search' — this works across both call/return and both server/local variants.

Distinct from kind, which is about invocation semantics ('function' / 'output' / 'external' / 'unapproved').

return_schema class-attribute instance-attribute

return_schema: ObjectJsonSchema | None = None

The JSON schema for the tool's return value.

For models that natively support return schemas (e.g. Google Gemini), this is passed as a structured field in the API request. For other models, it is injected into the tool's description as JSON text. Only included when include_return_schema resolves to True.

include_return_schema class-attribute instance-attribute

include_return_schema: bool | None = None

Whether to include the return schema in the tool definition sent to the model.

When True, the return_schema will be preserved and sent to the model. When False, the return_schema will be cleared before sending. When None (default), defaults to False unless the IncludeToolReturnSchemas capability is used.

function_signature cached property

function_signature: FunctionSignature

The function signature shape for this tool.

Lazily computed from parameters_json_schema and return_schema on first access. Name and description are not stored on the signature — pass them at render time via sig.render(body, name=td.name, description=td.description).

render_signature

render_signature(body: str, **kwargs: Any) -> str

Render the function signature with this tool's name and description.

Convenience wrapper around self.function_signature.render() that supplies name and description from this tool definition.

Source code in pydantic_ai_slim/pydantic_ai/tools.py
865
866
867
868
869
870
871
def render_signature(self, body: str, **kwargs: Any) -> str:
    """Render the function signature with this tool's name and description.

    Convenience wrapper around `self.function_signature.render()` that
    supplies `name` and `description` from this tool definition.
    """
    return self.function_signature.render(body, name=self.name, description=self.description, **kwargs)

defer property

defer: bool

Whether calls to this tool will be deferred.

See the tools documentation for more info.