Skip to main content

What are Agents?

Agents are autonomous execution units that orchestrate LLM interactions with tool calling. Without tools, an agent functions as a basic LLM. The simplest agent requires just a name and model:
For a full step-by-step guide, check the quickstart section or see practical examples in the examples section.

Reading guide

The sidebar follows a basics → platform → production path. You can jump anywhere, but this order matches how most agents are built:
  1. Tools — give the agent capabilities (the core primitive)
  2. Structured output — constrain what comes back
  3. Memory → Memory compaction — multi-turn context, then keeping oversized tool results and history within the window
  4. Skills — domain packages (knowledge + tools) once the agent loop makes sense
  5. Dynamic agents — runtime prompts and tool sets
  6. Background tasks · Commands — utilities (async tools, slash shortcuts)
After Workflows, see Human in the loop for approvals, suspend(), and durable resume (agents, workflow steps, and tools). For live spoken conversations, continue to Voice agents for speech providers, browser and phone transports, interruptions, and usage tracking. This page covers running agents, models, and I/O. The sections below are the reference for that; the linked pages go deeper on each topic.

Model Providers

You can specify any model using the “provider/model” format. See all supported models in the Model Reference. Some models require specific parameters (like max_tokens for Claude). Pass it as a top-level field:
Note: Make sure to define all required environment variables—such as the API key model that you need—in your .env file.

Fallback Models

Use FallbackModel when you want an agent to try another model if the primary provider fails, including authentication errors, rate limits, timeouts, and server errors.
Models are tried in order. By default, each model gets up to two retries for transient errors. Authentication errors trigger fallback immediately, as do rate limits when another model is available. If every model fails, Timbal raises FallbackExhausted with the per-model errors. For per-model settings, use ModelEntry:
Fallback only switches models before the first streamed chunk is emitted. If a stream fails after output has started, Timbal raises the error instead of silently switching models and risking duplicated or inconsistent output. The agent’s api_key and base_url apply only to models from the primary provider. When the chain switches providers, Timbal resolves that provider’s own credentials and endpoint from its environment variables or the platform proxy. Use ModelEntry(api_key=..., base_url=...) to override these for an individual model, including when multiple providers share a gateway. The agent’s model_params (or per-request provider_params) also apply only to models from the primary provider. Other providers use their defaults unless their ModelEntry sets provider_params. An entry’s dict replaces, rather than merges with, the shared params; use {} to clear them explicitly. An omitted value or None inherits shared params only for the primary provider. Timbal does not translate provider-specific options such as OpenAI’s reasoning into Anthropic’s thinking. This scoping also applies to providers that share an API format, such as OpenAI and xAI; set entry-level params explicitly to reuse compatible options. Shared max_tokens, temperature, tools, and structured output configuration still apply across the chain.

Thinking and reasoning

Some models support extended thinking before responding. Check per-model capabilities on the Model Reference pages. Configure at construction time via model_params (per-request overrides use provider_params — see Overriding Model Configuration below):
Define tools as Python functions - the framework handles schema generation, parameter validation, and execution orchestration.

Running Agents

Execute agents by calling them with a prompt parameter and using .collect() to get the result:

Streaming Events

For real-time processing, you can stream events as they happen:

Iteration Budget

max_iter (default 10) bounds the LLM → tool rounds in one turn. on_max_iter decides what happens when the budget is spent and the model still wants tools: The notice matters: silently handed an empty tool list, models narrate the step they were about to take (“I’ll update the file now”) as if it had happened. For anything custom, pass a callable (sync or async). It receives a MaxIterContext(max_iter, memory, agent_path) and returns a message: role="user" is used as the notice for a final tool-less call, role="assistant" is the reply and ends the turn, None makes the tool-less call with no notice, and raising fails the run.
Every mode records metadata["max_iter_reached"] = {"max_iter", "behavior"} on the agent span. Injected messages are persisted in memory tagged metadata={"source": "runtime", "kind": "max_iter_notice" | "max_iter_stop"}, so Message.is_runtime() lets you hide them when rendering a human transcript.

Timeout

max_iter bounds steps; timeout bounds time. It is the wall-clock budget, in seconds, for one turn — every LLM call and tool call included. Default None (no limit).
When the deadline passes, the in-flight LLM or tool call is cancelled and the turn ends with status.code == "timeout" and an error of type RunTimeout. Memory stays consistent: an interrupted tool call gets a synthetic result, so the next turn runs normally. timeout is available on every runnable, not just agents:
  • Sub-agents and tools. A child’s own timeout fails only that call. The parent agent receives it as an error tool result and can recover. A timeout on the parent bounds the whole turn, children included.
  • Workflow steps. A step that times out blocks its dependents, including transitive dependents. Unrelated branches may finish before the workflow reports the step failure. An agent inside a workflow can still recover from its own tools’ timeouts; the workflow uses that agent’s final result. See Errors & failure.
  • Hooks. pre_hook, the handler, and post_hook share one deadline. A slow hook times out the call; the budget is not restarted between stages. If the handler finished before a post-hook timed out, its output is retained.
  • What doesn’t count. The clock starts after input validation and the approval gate, so time a run spends paused waiting for approval does not use up the budget. Children detached with background_mode use background_timeout instead (see Background Tasks).
  • Sync handlers. A sync tool running inline on the event loop can’t be interrupted. Make it async, or set offload_blocking=True.
A TimeoutError raised inside a handler, such as a slow HTTP call, is still reported as a regular error. Only the runnable’s own deadline produces timeout. Performance. An unset timeout has negligible overhead: the per-call check remains, but the stream relay and timers are bypassed. Enabling a timeout adds timer and relay work per streamed event. The benchmarks/timeout/bench_streaming.py benchmark measures this cost separately from network and LLM latency.

Approval-Required Tools

Any runnable — Tool, Agent, or Workflow step — can pause for human approval before it runs. Mark it with requires_approval, listen for ApprovalEvent, and resume by calling the runnable again with resume:
The full reference — durable cross-process resume, audit fields, redaction, parallel gates, pending_approvals(), status reasons, usage counters, plus suspend() for asking the user mid-run — lives on the dedicated Human in the Loop section.

Input

Agents communicate through Message objects - Timbal’s data structure that standardizes both input and output.
Agents accept multiple input formats, automatically converting them to Message objects:

Passing Input Parameters

You can pass custom input parameters when calling an agent. Access these values anywhere in your agent (tools, system prompts, hooks) using get_run_context().current_span().input:
The tool can access user_id and role from the input parameters. Input parameters work with both .collect() and streaming.
For more information about accessing input parameters and using the run context, see the Context & State Management page.

Overriding Model Configuration

What if you want to change the model, max_tokens, or thinking config for each run? Instead of creating multiple agents, you can pass these as input parameters. This is useful for A/B testing different models, adjusting token limits per request, or dynamically selecting models based on task complexity.
The parameter names model, max_tokens, and provider_params are reserved and will affect model configuration when passed as input. These parameters will not be available as regular input to your agent. If you need to pass custom data without changing the actual model configuration, use different parameter names (e.g., data_model instead of model if you want to pass a data model name).

Output

Calling .collect() returns an OutputEvent containing the agent’s response. Access the Message via the .output property:
Learn more about events in Events & Streaming.
Response content can contain thinking, text, tool, and other blocks in a provider-dependent order. content[0] is not guaranteed to be text, and reasoning need not occupy a fixed position. Use collect_text() to extract the text response.

Messages

Messages are the structured data format that agents use to communicate. They contain a role and content, with automatic handling of different content types and provider compatibility.
Messages contain a role and content: Role Types:
  • user - Messages from the user
  • assistant - Messages from the AI agent
  • system - System instructions and context
  • tool - Tool execution results
Content Types:
  • TextContent - Plain text messages
  • FileContent - Files like PDFs, images, documents
  • ToolUseContent - Function calls to tools
  • ToolResultContent - Results from tool executions
Messages can contain different types of content - text, files, tool calls, and tool results. The framework automatically handles complex content structures:
The same message above can be created easily using Message.validate():

Files

Agents can process files directly through the message content system. The framework automatically handles file reading, content extraction, and formatting for the AI model.
The framework supports common document and media formats:
  • Text files (.txt, .md) - Direct content inclusion
  • PDFs (.pdf) - Text extraction with structure preservation
  • Images (.png, .jpg, .gif) - Visual analysis through vision-capable models
  • Spreadsheets (.xlsx, .csv) - Structured data representation
  • Documents (.docx) - Text and formatting extraction
Files are automatically converted to Timbal File objects using File.validate():