Skip to main content
An agent is an LLM-driven capability registered alongside tools. You author it against one uniform contract — the Agent ABC — and the manifest loads it the same way it loads a tool module.

The Agent contract

The whole agent shape is owned once by the contract: the Agent ABC with its default stream and drain behaviour, the neutral spec descriptors, and a typed event vocabulary. The skeleton adds no agent implementation of its own — it surfaces the contract in its own namespace and registers agents against the app. You register an agent with a decorator that also names it. The skeleton synthesizes the agent’s JSON run tool from its declared input model, so an agent is callable exactly like any other tool:
An agent whose run can park (it async-asks, or its tool calls park it) declares that its run tool can pause, meta={"tai42/pauses": True} on the decorator, like any tool that can pause. A tool an agent calls that parks without that declaration fails the agent’s run with UndeclaredPauseError naming the tool; the model is never handed a tool error to retry around, so the tool’s body runs once. An ask inside an agent’s run returns {answer, reply_to, params}, as it does anywhere (see Block or park). A parked agent run resumes through the agents’ continuation tool (agent_resume), which is run with {interaction_id, ask_result} and hands the waiting ask the ask_result object unchanged.

Streaming events

An agent run streams a typed sequence of StreamEvents rather than returning a single blob. The vocabulary covers message deltas and finals, reasoning steps, tool-call and tool-result steps, structured finals, interrupt finals, and run usage. The event producers — the projection over the agent runtime’s updates and messages — live in the agents runtime; a client renders the frames as they arrive. When a run carries a response_format, the structured result reaches a user-visible stream only as the terminal structured final — the stream carries no synthetic structured-output tool-call/result frame for the internal call that produced it. A structured-output run that never conforms, or one that exhausts its graph step limit, ends with a typed non-fatal terminal — structured_output_unresolved_final (the schema, the attempts, the last validation error) or recursion_limit_final (the limit) — that a calling run or route branches on by type rather than receiving a generic failure. The re-prompt bound is the server-wide TAI_AGENTS_STRUCTURED_OUTPUT_REPROMPT_CAP (default 3). Run an agent and watch its stream from the CLI:

Context management

Before each model call an agent trims its conversation history to fit a token budget — the default context-management strategy, configurable via CONTEXT_OVERFLOW_METHODS — keeping the most recent turns and dropping older ones; a trim that drops history logs a warning. The newest human message is never discarded: when the budget cannot hold the system prompt plus the current message, the run raises a typed TrimmingBudgetTooSmallError naming the budget rather than answering from the system prompt alone, so an overflow surfaces loudly instead of returning a silently wrong reply. Raise the budget with TRIMMING_MIDDLEWARE_MAX_TOKENS. The system prompt is per-run configuration, supplied fresh at each model call (create_agent(system_prompt=...)) — it is never stored in thread or checkpoint state. Any system message found in replayed thread history is stripped before the model sees it, so the prompt comes only from the run’s own configuration; it counts against the trimming budget above.

System-prompt caching

Every agent turn re-sends its whole system prompt. On a provider that takes a system-prompt cache breakpoint, marking that stable prefix lets the provider cache it and read it back on later turns instead of re-billing it. This marking is on by default (TAI_AGENTS_SYSTEM_PROMPT_CACHE_DEFAULT=true), server-wide; a provider that caches without a mark, or supports none, is left unmarked. A tools_agent node overrides the default with system_content_kwargs: leave it unset to take the default, pass {} to opt the node out (no mark), or pass an explicit mark of your own. Most agent faces carry the default; the retrieval agent and the Claude Code agent are excluded — see the agents plugin for the per-face detail.

Authored agents

Beyond code-defined agents, you can author an agent as a saved spec that rides the versioning spine — a preset that bakes the agent’s preset-bakeable fields. Authored agents version and roll back exactly like presets, so an agent’s configuration evolves without breaking its callers.

Composition

An agent can drive other agents as sub-agents and chain multi-step work. That compositional side — sub-agents and the ready-made set — is its own pillar: deep agents. The platform ships ready-made deep agents that run that durable, code-executing work over the sandbox — the execution surface an agent reaches for a persistent workspace and code — see the agents plugin and the guide. See the author-an-agent guide for the full authoring path and the Python SDK reference for the Agent ABC and the StreamEvent types.