Agent plugin · listing tai42/agentsInstall
Permissions
Provides
langchain_deep_agent
Agent — Run a deep agent with planning, subagents, skills, and a filesystem backend.
claude_code
Agent — Run Claude Code inside a sandbox: it drives the real claude binary over a versioned exec protocol, with tools, skills, and subagents.
refine_agent
Agent — Run an Evaluator-Critic refinement loop until the Critic approves or the budget runs out.
voting_agent
Agent — Run a voting workflow — voter LLMs answer in parallel, then a judge LLM decides.
retrieval_tools_agent
Agent · group tools-agents — A tools agent that retrieves its tools on demand from a vector store.
tools_agent
Agent · group tools-agents — Run a LangGraph tools agent over tools loaded by name (and optional presets).
vqa_agent
Agent — Analyze an image and answer a query about it using a multimodal LLM.
Ready-made agent workflows, each loaded by name into a manifest’s
agents_modules. The model behind them, how to run one, and how to compose them
live in the central docs linked below; this page is the per-agent index and the
shared limits.
Configuration
Limits shared by every agent in this package:Structured-output outcomes
When a run requests aresponse_format, the model’s answer is forced through a
rail that re-prompts the model each time its final answer fails to parse or
validate against the schema, or carries no structured answer at all (an empty
reply, or the answer written as plain text instead of the structured output). A
turn in which the model only calls other tools is not judged; the run continues,
also when those calls all failed to parse (see Tool-error
resilience). A structured answer whose arguments do not
parse is judged even when the same turn also calls other tools. Two typed, non-fatal terminal outcomes bound that loop, so
a run that cannot produce a conforming or bounded answer ends readably instead of
failing generically. Each surfaces exactly like a normal terminal — the streaming
faces emit it as a terminal event, run returns it as the run’s value, the agent
run route emits it as one SSE frame, and a conversation route surfaces it to the
turn’s reply — so a caller or route branches on its type:
Both carry
final: true. Neither raises — a branch that does not handle them
reads them as the run’s terminal value.
Async-park index
A park-capable run whose tool async-parks (ask(mode="async")) writes a durable
index that reverses a parked interaction id back to its parked run, so a later worker
can resume it. This needs the [park] extra (pip install tai42-agents[park]) and a
Redis URL:
The park index is the agents plugin’s own Redis, independent of the checkpoint provider
and the interactions store. It is the platform kit’s shared park index library
(
tai42_kit.interactions.park_index) under the agents’ own key namespace (agent:park);
the settings above are unchanged.
A parked run needs a durable checkpoint provider (redis or postgres), which keeps a
thread LLM_PROVIDER_CHECKPOINT_RETENTION_WAITING_MINUTES (default 7 days) after its last
write. The platform may still deliver an ask’s answer up to its redelivery horizon
(INTERACTIONS_IDLE_TTL_SECONDS, default 1 day) after the ask’s deadline, so every async ask
must carry a deadline at least that long before the checkpoint’s retention runs out (with the
defaults, within 6 days): an ask with no deadline, or one past that point, is refused loudly
before anything is parked. While a park’s barrier is live, the checkpoint sweep spares its
thread. A resume that finds the thread’s checkpoint gone ends the run as a failed terminal.
A run with no thread_id mints its own thread and marks it finished when it ends without
a park, so the checkpoint sweep removes it
LLM_PROVIDER_CHECKPOINT_RETENTION_FINISHED_MINUTES (default 1 day) later. A
caller-supplied thread_id is the caller’s: a run on it takes it out of the finished set
when it starts and never marks it.
When the ask is answered (or expires), the platform resumes the parked run and drives it
to its next outcome. The resumed run’s final outcome is delivered by the platform to the
run’s own address — the agent never delivers it itself; a caller that needs the answer runs
the agent through a door that receives it out of band (a conversation route). A kill takes
the whole run down — every open ask of the run, the runs nested under its calls and the callers
waiting on it; nothing of the run is resumed — and delivers a single terminal to that address: a deliberate
takedown (a cancel, a thread or route delete, a person erase) is delivered as withdrawn, so
the conversation says nothing to the person, and a lapsed on_expiry="kill" deadline is
delivered as a failed outcome.
A resumed run that fails — its graph raises, for example a model or provider error that
outlasts the model client’s own retries — ends as a failed terminal instead of being retried:
an outermost run’s address receives a failed outcome, and a run nested under another run (a
consumer holding the agent, an agent calling it) reaches that caller as a failure, so the
caller’s own error handling runs (for example a holder’s on_error). The same holds when the
platform gives up on a park whose resume could not be driven at all within the redelivery
horizon, or when a preset’s output map refuses the answer the parked run resumes with: the
caller the parked run was nested under is told it failed rather than waiting out its own
deadline.
An async ask may address the run’s own caller (ask(to="caller")) instead of a human
(to="user"): the run parks the same way and resumes when the caller answers, so an agent
can hand a question back up to whatever invoked it. When an agent’s own tool call drives a
nested run that async-parks, the agent parks on that call rather than blocking; once the
nested run reaches its terminal the agent’s turn resumes with that terminal as the tool’s
result, and a non-success terminal comes back as a model-visible tool error.
The parking agents (tools_agent, langchain_deep_agent, claude_code) set parks = True,
so the platform declares their run tools as tools that can pause; the hidden agent_resume and
deliver_chained_park tools declare it themselves (meta={"tai42/pauses": True}). A caller’s
park recognition accepts the park they return. A tool an agent calls that returns a park signal
without that declaration fails the agent’s run with UndeclaredPauseError naming the tool; the
model is not handed a tool error to retry around.
Parking tools
An agent that lists the generic parking tools in itstool_names — list_parked,
resume_parked, cancel_parked — can list, answer, or cancel the caller asks parked on the
run’s subject from inside its own turn. They are platform builtins and need no plugin code.
Conversation-door tools
send_conversation_message and send_conversation_event let an agent reach a conversation
route from inside its own turn, in-process under the run’s own execution identity — no route
key is handed to the agent. send_conversation_message posts a message into a route’s
conversation; send_conversation_event delivers a structured event onto an existing thread
of one. Each applies the target door’s own authorization before it runs and refuses a run
with no accountable execution identity loudly; the turn’s answer is delivered by the route’s
own configured delivery, never inline to the agent. List either in an agent’s tool_names
to include it — they are platform builtins and need no plugin code.
System-prompt caching
Every agent turn re-sends its whole system prompt. On a provider that takes a system-prompt cache breakpoint, marking the prompt lets the provider cache that stable prefix and read it back on later turns instead of re-billing it. This is on by default (TAI_AGENTS_SYSTEM_PROMPT_CACHE_DEFAULT=true), server-wide; a
provider that caches without a mark, or does not support one, is left unmarked —
the mark form is the provider’s own, so it is never named here.
Per node, the tools_agent’s system_content_kwargs overrides the default:
leave it unset to take the default, pass {} to opt this node out (no mark), or
pass an explicit mark to set your own. The other faces follow the server-wide
setting only.
Which faces carry it:
Per-provider history shaping
Each provider answers two questions about the outgoing request, and every agent applies the answers at the model call only — nothing is written to the stored thread:- A leading user turn. When a history’s first non-system message is an assistant turn
(an operator opened the thread), a provider that requires a user turn first gets an inert
[conversation start]user turn added to that one request. - A rolling cache breakpoint. A provider that takes a per-block cache mark keeps only the newest marked block per request, so per-turn marking stays within the provider’s per-request breakpoint cap.
Final text
run and astream hand back the same final text: the reply text of the last message — its
plain text, or its text blocks joined with nothing between them. Thinking, reasoning, tool-use
and server-tool blocks are never part of it.
Run keywords
Each agent’srun and astream declare the keywords that agent reads — the platform’s four
(thread_id, user_message, tool_names, response_format) plus the agent’s own knobs, the
fields of its tool input. A keyword an agent does not declare is refused with a TypeError
naming it, never dropped; a platform key an agent cannot honor is refused with a RuntimeError
naming the reason (the voting and refine agents take role-named messages instead of
user_message and per-role configs instead of thread_id; the voting agent always produces
its VotingOutput; the vqa agent runs one completion with no tools and no thread).
Live in-process
tools are the platform’s framework-neutral ClientTool handles (from
tai42_app.tools.get_client_tools, or any object with name, description, input_schema and
an async invoke); this plugin adapts each to its LangChain runtime, and every tool name the model
is handed is held to the 64-character bound — a longer one is refused, never truncated. A preset is
handed under its own name, so a short-named preset over a longer-named base tool binds.
Each agent also reports the memory its run keywords address (addressed_memory): the thread and
checkpoint ids its langgraph_config (or per-role configs) and resume_checkpoint_id carry, and
the continuity keys (resume, resume_checkpoint_id, checkpoint_provider) it reads. The
platform refuses an id in its reserved bridge: namespace from that answer, and a conversation
route refuses a start that sets a continuity key.
Session credentials
claude_code and langchain_deep_agent turn their operator creds list into what a
session receives by one rule:
Refused loudly, naming the cred:
connection cred '<env_name>' resolved HTTP headers, which delivery='env' cannot carry; use delivery='bearer'required connection cred '<env_name>' resolved to no usable credential for the current caller (connection '<connection_id>')
Tool-error resilience
A tool failure surfaces to the model as an error tool result and the agent loop continues, rather than aborting the run: aToolException — which is how an
in-process tool’s own body exception is reported — or a pydantic ValidationError
from a malformed tool call becomes an error result the model can react to. Failures
outside the tool call (agent machinery, provider or infrastructure errors) still
abort loudly. This holds across every tool-running agent in this package, including a
deep agent’s explicit and nested subagents. A tool call whose arguments did not parse
(the provider reports it as an invalid tool call) is answered right after the model
turn with an error result carrying the parse error, so the next request answers every
call the model made; the stream shows it as a tool call with no arguments followed by
that error result. A broken call that carries no call id or no tool name cannot be
answered, because a tool result needs both; it is logged as a warning. When every call
of a turn failed to parse and the turn produced no structured answer, the model is
called again to read the errors, and the run’s recursion limit bounds those retries. A
broken call to the structured-output tool is judged by the structured-output rail
instead (see above). A thread whose previous turn was aborted mid-tool-call is repaired
at the next turn start — the calls of its last model turn that have no result yet,
valid or invalid, get synthetic error results so the provider accepts the thread —
while a thread paused on a real interrupt is left untouched.
langchain_deep_agent
Runs a deep agent with planning, one level of nested subagents, skills, human-in-the-loop interrupts (resumed with a LangGraphCommand), and a per-thread
scratch filesystem.
The agent sees each skill’s whole skills/<name>/ tree under /skills/: text files
read as text, and binary assets (images, PDFs) reach the model as file attachments when
the model accepts them, otherwise as a one-line notice, so a bundle’s assets never stop
the run.
Sandbox requirement
The scratch filesystem is a durable sandbox backend over the sameSandboxSession contract, so a run requires a registered sandbox provider — with
none installed it fails loudly at require_sandbox(). Its working files persist and
reap under the operator’s durability settings, so installing a sandbox provider is a
hard prerequisite, not an optional add-on.
Structured output
Aresponse_format is validated up front: the JSON Schema must carry a top-level
title, and every oneOf variant must carry a non-empty title of its own — a schema
missing either raises a ValueError before the run starts. When a run requests a
response_format but produces no structured output, both faces raise rather than
silently omitting the structured frame: the JSON run face raises on drain, and the
streaming face raises after the stream drains — unless the run paused on a pending
interrupt, which takes precedence over the missing-structured raise.
Configuration (TAI_AGENTS_LANGCHAIN_DEEP_*)
claude_code
Runs Claude Code as a platform agent: it drives the realclaude binary through the
Claude Agent SDK inside a sandbox session over a versioned exec protocol. The plugin
server never imports the SDK — the SDK lives in the session image, and only the runner
payload (shipped as data and executed in-session) imports it.
Sandbox requirement
claude_code requires a registered sandbox provider. Install one, e.g.
tai plugins install tai42-sandbox-docker. A run on a box with no provider raises a loud
SandboxUnavailableError on every door. The session image is operator-configured and MUST
be a digest reference (a bare tag is rejected at run start).
Configuration (TAI_AGENTS_CLAUDE_*)
Session creds (
TAI_AGENTS_CLAUDE_CREDS) are a list of static values or per-caller
connection references injected into a CLEAN session env or a per-turn bearer
credential-helper file — never the host env. A connection-reference cred resolves per-caller
and fails closed on a door with no bound execution identity. See
Session credentials for the one rule both sandbox agents apply.
Adapter-proxied platform tools. Granted tool_names run under the run’s own execution
identity through the same run_tool seam every agent uses — the session reaches no
platform network surface and holds no key or MCP endpoint. The model sees each granted tool
with its own description and argument schema. A non-empty tool_names on a
door with no bound execution identity is refused loudly (fail-closed).
Stated residual (security is configuration). The one injected model credential lives in
the session env, so the session’s own Bash can read it and it can reach the persisted
transcript. The credential scrub removes credential FILES on a terminal exit; when the
platform sandbox_scrub_transcript flag is on, injected credential VALUES are also redacted
from the kept transcript.
Async ask parks are supported on threaded (conversation) runs and use the same
[park] extra + TAI_AGENTS_REDIS_URL as the other parking agents (see
Async-park index); an async ask on a thread-less tool-face run is
refused loudly (its ephemeral workspace could never be resumed).
refine_agent
Runs an Evaluator-Critic refinement loop until the Critic approves or the budget runs out.voting_agent
Runs a voting workflow — voter LLMs answer in parallel, then a judge LLM decides. Bounded byTAI_AGENTS_MAX_VOTERS and TAI_AGENTS_VOTER_CONCURRENCY.
retrieval_tools_agent
A tools agent that retrieves its tools on demand from a vector store.tools_agent
Runs a LangGraph tools agent over tools loaded by name (and optional presets). A tool that async-parks (ask(mode="async")) suspends the run instead of blocking; it
resumes on a later worker when the ask is answered or expires. This needs the [park]
extra and TAI_AGENTS_REDIS_URL (see Async-park index).
vqa_agent
Analyzes an image and answers a query about it using a multimodal LLM.See also
- Agents and Deep agents — the model.
- Use the ready-made agents — running each of these.
- Author an agent — building your own.

