docs/examples.md
Pydantic AI runs Monty behind
CodeModeToolset.
Instead of making sequential tool calls, the model writes Python that calls your tools as functions, and Monty executes
it: one round trip for a task that would otherwise take three.
import asyncio
import json
import logfire
from httpx import AsyncClient
from pydantic_ai import Agent, RunContext
from pydantic_ai.toolsets.code_mode import CodeModeToolset
from pydantic_ai.toolsets.function import FunctionToolset
from typing_extensions import TypedDict
logfire.configure()
logfire.instrument_pydantic_ai()
class LatLng(TypedDict):
lat: float
lng: float
weather_toolset: FunctionToolset[AsyncClient] = FunctionToolset()
@weather_toolset.tool
async def get_lat_lng(
ctx: RunContext[AsyncClient], location_description: str
) -> LatLng:
"""Get the latitude and longitude of a location."""
# NOTE: the response here will be random, and is not related to the location description.
r = await ctx.deps.get(
'https://demo-endpoints.pydantic.workers.dev/latlng',
params={'location': location_description},
)
r.raise_for_status()
return json.loads(r.content)
@weather_toolset.tool
async def get_temp(ctx: RunContext[AsyncClient], lat: float, lng: float) -> float:
"""Get the temp at a location."""
# NOTE: the responses here will be random, and are not related to the lat and lng.
r = await ctx.deps.get(
'https://demo-endpoints.pydantic.workers.dev/number',
params={'min': 10, 'max': 30},
)
r.raise_for_status()
return float(r.text)
@weather_toolset.tool
async def get_weather_description(
ctx: RunContext[AsyncClient], lat: float, lng: float
) -> str:
"""Get the weather description at a location."""
# NOTE: the responses here will be random, and are not related to the lat and lng.
r = await ctx.deps.get(
'https://demo-endpoints.pydantic.workers.dev/weather',
params={'lat': lat, 'lng': lng},
)
r.raise_for_status()
return r.text
agent = Agent(
'gateway/anthropic:claude-sonnet-4-5',
toolsets=[CodeModeToolset(weather_toolset)],
deps_type=AsyncClient,
)
async def main():
async with AsyncClient() as client:
await agent.run('Compare the weather of London, Paris, and Tokyo.', deps=client)
if __name__ == '__main__':
asyncio.run(main())
Swap CodeModeToolset(weather_toolset) for weather_toolset to see the same task done with ordinary tool calls.
Each directory under examples/ is runnable after make dev-py; its README has the command.
sql_playground: customer purchase data in CSV
joined with tweets in JSON, with sentiment analysis called in a loop from the sandbox.
With JSON tool calling the 50+ per-tweet results would flood the context window; in Monty they stay inside the sandbox
and only the aggregate comes out.
Also shows file sandboxing via the os callback and type checking against a stub file.expense_analysis: Anthropic's programmatic
tool calling cookbook example, run on
Monty.web_scraper: Playwright and BeautifulSoup
exposed to the sandbox as host objects so the model can extract prices from model labs' websites;
example_code.py is the code Claude Sonnet 4.5 wrote for it.classes: one short file per behaviour of host
objects, in Python and TypeScript: explicit policies, lazy attributes, sandbox-side copies,
convert_value hooks, constructing host classes from the sandbox, and round-tripping sandbox-defined classes.