Agent
Full API reference for the Agent class — construct an agent, run it, register tools and output validators, and inspect its configuration.
Agent is the core user-facing class. You configure it once — its name, model, instructions, tools, and limits — then call run or arun to drive the agentic loop. The Agent itself is configuration; runtime state lives on the Context that each run creates.
Agent is a Pydantic BaseModel with extra="forbid", so passing an unknown keyword raises a validation error.
from agentroute import AgentConstructor
Agent(
name: str,
*,
model: str | Model | None = None,
api_key: str | None = None,
base_url: str | None = None,
instructions: str | None = None,
description: str | None = None,
tools: list[Tool | Callable] | None = None,
max_turns: int = 10,
max_cost: float | None = None,
retries: int = 1,
output: type | None = None,
output_mode: str = "auto",
memory: MemoryProto | None = None,
history: History | None = None,
)| Parameter | Type | Default | Description |
|---|---|---|---|
namerequired | str | — | Human-readable identifier for the agent. Used in error messages and (in a later phase) deployment. |
model | str | Model | None | None | The model to drive the loop. A string such as "claude-sonnet-4" is passed to resolve_model; you can also pass a concrete Model instance. If None, a model must be resolvable from configuration at run time. |
api_key | str | None | None | API key for the resolved model. Falls back to environment variables or ~/.agentroute/config when omitted. See Models for the full resolution order. |
base_url | str | None | None | Override the endpoint for an OpenAI-compatible provider. Leave unset to use the default routing (OpenRouter for bare model names). |
instructions | str | None | None | System prompt that defines the agent's behavior. Sent as the leading system message on every turn. |
description | str | None | None | Short description of what the agent does. Metadata only; not sent to the model. |
tools | list[Tool | Callable] | None | None | Tools to register at construction. Each item is either a Tool or a plain callable, which is wrapped with tool automatically. Registering two tools with the same name raises ValueError. |
max_turns | int | 10 | Maximum number of model turns before the loop aborts with ErrorMaxTurns. Each turn is one model call plus any tool executions it requests. |
max_cost | float | None | None | Optional spend ceiling in USD. When accumulated cost exceeds it, the loop raises ErrorBudget. None means no cost limit. |
retries | int | 1 | How many times a Retry signal — raised from a tool body or an output validator — is honored before giving up. |
output | type | None | None | A type (typically a Pydantic model) describing the structured result. When set, result.output is an instance of this type instead of a string. See Structured output. |
output_mode | str | "auto" | How structured output is produced: "auto" (use tool mode when output is set, otherwise text), "tool", or "text". |
memory | MemoryProto | None | None | Long-lived memory backend for conversation and facts. Pass Memory or MemorySQLite. Exposed to tools as ctx.memory. |
history | History | None | None | Conversation compaction policy applied as the transcript grows, e.g. HistorySlidingWindow. None keeps the full transcript. |
The Agent holds configuration only. Per-run state — usage, message transcript, retry counter, deps — lives on a fresh Context created for each call to run / arun. The same agent can be reused across many concurrent runs.
Methods
run
Run the agent synchronously. Wraps arun in asyncio.run.
def run(self, prompt: str, *, deps: Any = None, **kwargs: Any) -> Result| Parameter | Type | Default | Description |
|---|---|---|---|
promptrequired | str | — | The user message that starts the conversation. |
deps | Any | None | Arbitrary dependencies made available to tools as ctx.deps — a database handle, an API client, request-scoped config. |
**kwargs | Any | — | Forwarded to the underlying run loop. |
result.output is the final text, or an instance of output when structured output is configured. print(result) shows the text.max_turns.max_cost.run calls asyncio.run, which fails if an event loop is already running. Inside an async function, await agent.arun(...) instead.
arun
The async entry point. run is a thin synchronous wrapper around it.
async def arun(self, prompt: str, *, deps: Any = None, **kwargs: Any) -> Result| Parameter | Type | Default | Description |
|---|---|---|---|
promptrequired | str | — | The user message that starts the conversation. |
deps | Any | None | Arbitrary dependencies exposed to tools as ctx.deps. |
**kwargs | Any | — | Forwarded to the underlying run loop. |
run.max_turns.max_cost.import asyncio
from agentroute import Agent
agent = Agent(name="assistant", model="claude-sonnet-4")
async def main():
result = await agent.arun("Write a haiku about routing.")
print(result)
asyncio.run(main())tool
Decorator that registers fn as a tool on this agent. Works both bare (@agent.tool) and with arguments (@agent.tool(name="...")). See Tools for the full model and tool for the standalone decorator.
def tool(
self,
fn: Callable | None = None,
/,
*,
name: str | None = None,
description: str | None = None,
needs_approval: bool | Callable[[Context, dict], bool] = False,
timeout: float | None = None,
) -> Tool | Callable| Parameter | Type | Default | Description |
|---|---|---|---|
fn | Callable | None | None | The function to register. Supplied automatically when used as a bare decorator; omit it when calling with keyword arguments. |
name | str | None | None | Override the tool name. Defaults to the function name. |
description | str | None | None | Override the tool description. Defaults to the function docstring. |
needs_approval | bool | Callable[[Context, dict], bool] | False | Whether the tool requires approval before running. Pass a callable to decide per call from the context and arguments. |
timeout | float | None | None | Per-call timeout in seconds. None means no timeout. |
from agentroute import Agent, Context
agent = Agent(name="weather-bot", model="claude-sonnet-4")
@agent.tool
def get_weather(city: str) -> str:
"""Return the current weather for a city."""
return f"{city}: 18C, clear"
@agent.tool(needs_approval=True, timeout=10.0)
def send_email(to: str, body: str) -> str:
"""Send an email. Requires approval before running."""
return f"sent to {to}"A parameter annotated as Context is auto-injected and excluded from the model-visible schema:
@agent.tool
def save_note(ctx: Context, text: str) -> str:
"""Persist a note to agent memory."""
# ctx is injected automatically; the model only sees `text`.
return "saved"output_validator
Decorator that registers a validator run against the structured output before it is returned. Use it to enforce invariants and push the model to correct itself.
def output_validator(self, fn: Callable) -> CallableThe validator signature is (ctx: Context, output: OutputModel) -> OutputModel. Return the (possibly modified) output to accept it, or raise Retry(message) to send the model a hint and ask for another attempt. Retries are bounded by the agent's retries setting. See Errors and retries.
| Parameter | Type | Default | Description |
|---|---|---|---|
fnrequired | Callable | — | The validator function. Receives the Context and the parsed output, returns the validated output. |
from pydantic import BaseModel
from agentroute import Agent, Context, Retry
class Invoice(BaseModel):
total: float
agent = Agent(name="biller", model="claude-sonnet-4", output=Invoice)
@agent.output_validator
def must_be_positive(ctx: Context, output: Invoice) -> Invoice:
if output.total <= 0:
raise Retry("total must be a positive amount")
return outputProperties
tools_map
Read-only view of the tools registered on the agent, keyed by name.
@property
def tools_map(self) -> dict[str, Tool]tool decorator.agent = Agent(name="bot", model="claude-sonnet-4")
@agent.tool
def ping() -> str:
"""Health check."""
return "pong"
print(list(agent.tools_map)) # ['ping']
print(agent.tools_map["ping"]) # Tool(name='ping', ...)output_validators
Read-only copy of the registered output validators, in registration order.
@property
def output_validators(self) -> listExamples
A minimal agent with one tool and a budget guard:
from agentroute import Agent, Context
agent = Agent(
name="assistant",
model="claude-sonnet-4",
instructions="You are a concise, helpful assistant.",
max_turns=6,
max_cost=0.50,
)
@agent.tool
def add(a: int, b: int) -> int:
"""Add two integers."""
return a + b
result = agent.run("What is 21 + 21?")
print(result) # 42
print(result.usage) # Usage(input_tokens=..., output_tokens=..., ...)Structured output with a validator:
from pydantic import BaseModel
from agentroute import Agent, Context, Retry
class City(BaseModel):
name: str
country: str
population: int
agent = Agent(name="geo", model="claude-sonnet-4", output=City)
@agent.output_validator
def sane_population(ctx: Context, output: City) -> City:
if output.population <= 0:
raise Retry("population must be greater than zero")
return output
result = agent.run("Give me data for Lisbon.")
city = result.output # City instance
print(city.name, city.population)Handling the loop limits:
from agentroute import Agent, ErrorMaxTurns, ErrorBudget
agent = Agent(name="bounded", model="claude-sonnet-4", max_turns=3, max_cost=0.10)
try:
result = agent.run("Solve this step by step, calling tools as needed.")
print(result)
except ErrorMaxTurns as e:
print(f"hit turn limit: {e.turn}/{e.limit}")
except ErrorBudget as e:
print(f"over budget: ${e.spent:.4f} > ${e.limit:.2f}")