Veto/docs

PydanticAI Integration

Use Veto with PydanticAI to validate tool calls before execution.

Veto integrates with PydanticAI by wrapping async tool handler functions.

The Python SDK exposes two native helpers:

  • wrap_pydanticai_tool(veto, tool_name, handler)
  • create_veto_tool_decorator(veto, tool_name)

Python only — PydanticAI is a Python framework.

Installation

pip install veto pydantic-ai

Quick start

from veto import Veto
from pydantic_ai import Agent
from veto.integrations.pydanticai import wrap_pydanticai_tool

veto = await Veto.init()
agent = Agent("openai:gpt-4o")

async def transfer_funds_handler(amount: float, to_account: str) -> str:
    return f"Transferred ${amount} to {to_account}"

guarded_transfer_funds = wrap_pydanticai_tool(
    veto,
    "transfer_funds",
    transfer_funds_handler,
)

@agent.tool_plain
async def transfer_funds(amount: float, to_account: str) -> str:
    """Transfer money between accounts."""
    return await guarded_transfer_funds(amount=amount, to_account=to_account)

Decorator API

from veto import Veto
from pydantic_ai import Agent
from veto.integrations.pydanticai import create_veto_tool_decorator

veto = await Veto.init()
agent = Agent("openai:gpt-4o")

@agent.tool_plain
@create_veto_tool_decorator(veto, "get_balance")
async def get_balance(account_id: str) -> str:
    return f"Balance for {account_id}: $5,000"

The decorator inspects the function signature, builds an args dict from call kwargs, runs veto.guard(...), and then executes the original function only when allowed.

How it works

For wrapped handlers/decorators, Veto runs:

  1. Build args dict from the function signature + call arguments
  2. await veto.guard(tool_name, args_dict)
  3. If denied, raise ToolCallDeniedError
  4. If allowed, execute the original async handler

Example output

transfer_funds(200) -> Transferred $200 to ACC-001          # allowed
transfer_funds(5000) -> DENIED: Tool call denied:           # blocked by policy
  transfer_funds - Amount 5000 exceeds limit of 1000
get_balance('ACC-001') -> Balance for ACC-001: $5,000       # allowed

total_calls:    3
allowed_calls:  2
denied_calls:   1

Notes

  • pydantic-ai remains an optional dependency in the SDK.
  • These helpers wrap plain async Python functions, so they can be used in or out of PydanticAI as long as the function call contract is the same.