Skip to main content
Tools enable AI models to call functions in your code. ai-query provides a type-safe way to define tools using Python decorators and type hints.

Defining Tools

Use the @tool decorator to create a tool from any function:

The @tool Decorator

The decorator accepts this optional parameter:

Parameter Definitions with Field

Use Field to describe each parameter:

Supported Parameter Types

ai-query supports these Python types:
  • str - String values
  • int - Integer values
  • float - Floating point numbers
  • bool - Boolean values
  • list[T] - Arrays with inferred item types
  • dict[str, T] - Objects with typed values
  • tuple[T1, T2] and tuple[T, ...] - Fixed or variable-length arrays
  • Optional[T], Union[...], and Literal[...] - Optional, union, and enum-like values
  • TypedDict and dataclasses - Nested object schemas
If a type annotation is not recognized, inference falls back to string. For full control, create a tool with an explicit parameters schema.

Using Tools with generate_text

Pass tools as a dictionary:

Sync vs Async Tools

Tools can be either synchronous or asynchronous:

Tool Execution Context

Annotate one parameter as ToolExecutionContext to receive framework runtime data that must not be generated by the model. The parameter is omitted from the provider tool schema and ai-query injects a separate context for every call.
The context exposes:
  • tool_call_id, tool_name, and step_number
  • the effective AbortSignal
  • turn_id and agent_id when execution belongs to an AgentTurn
  • deeply immutable application metadata
  • emit_progress(message, data=...) for correlated typed progress events
Pass metadata with generate_text(..., metadata={...}), stream_text(..., metadata={...}), or TurnOptions(metadata={...}). Metadata is not sent to the model. Parallel tool calls receive isolated context objects. Progress events are emitted live, so their order reflects actual concurrent execution rather than provider call order.

Automatic Tool Execution

When you provide tools, ai-query automatically:
  1. Sends the tool definitions to the AI
  2. Executes any tools the AI calls
  3. Returns the results to the AI
  4. Repeats until the AI responds without tool calls

Accessing Tool Calls and Results

Inspect what tools were called:

Returning Images and Files

Return ToolOutput when a tool needs to send rich content back to the model. The same normalized value flows through ToolResult, hooks, streaming events, and persisted agent history. Provider adapters handle the wire format.
Use ordinary strings, numbers, lists, or dictionaries for normal tool results. A list is not treated as rich content unless it is wrapped in ToolOutput. Rich tool outputs require upstream support:
  • OpenAI uses the Responses API. Set provider_options={"openai": {"api": "responses"}} to use it from the first request; ai-query also selects it when rich output is present in a follow-up request.
  • Anthropic Messages supports nested text, image, and document tool-result blocks.
  • Gemini multimodal function responses require a Gemini 3 or newer model.
  • Bedrock image tool results require Amazon Nova or Anthropic Claude 3/4.
  • OpenAI-compatible chat-completions endpoints do not have a lossless rich tool-result representation.
Unsupported endpoint and model combinations raise UnsupportedToolOutputError before the request is sent. Binary values are encoded for persistence and wire transport; ToolOutput representations redact their payloads.

Limiting Execution Steps

Control the maximum number of tool execution loops using stop_when:

Next Steps

Agents

Build autonomous agents with advanced loop control