Agent contract.
An agent plugin ships one or more agents as a distributable package. Each agent implements the Agent ABC; the runtime derives two faces from it — a JSON run tool for LLM, MCP, and flow callers, and an in-process astream method for API and SSE callers. You write only the Agent class. This guide covers the full contract surface and packaging; for a first agent in your own app, see Author an agent.
Implement the contract
Declare the three class attributes that drive tool generation and implementrun, the primitive that returns a single final value:
tool_name— the registered name and the auto-generated tool name.tool_description— the LLM-facing description.ToolInput— a JSON-able pydantic model of the tool parameters. A non-JSON field fails loudly when its schema is generated.
examples/agent_plugin/greeter_agent.py
Stream real events
run is the primitive; the base class provides a free astream that runs once and emits one terminal event. A streaming agent overrides astream with real per-step events and implements run by draining its own stream through the base _drain helper — which raises on an interrupt (a non-streaming caller cannot answer one) and never returns a partial.
Declare preset-bakeable fields
An authored variant of an agent is a preset that bakesfixed_kwargs over the agent, run with tai agents authored-run. Which ToolInput fields may be baked is a per-field capability the implementation declares — it is never inferred:
spec_runnable = Truedeclares that the agent’sToolInputadvertises exactly the composable fields its runtime honors, so every field is preset-bakeable.preset_bakeable_fields = frozenset({"..."})names the individual fields that are bakeable when the agent is not (or not only)spec_runnable. A field is bakeable iff the agent isspec_runnableor the field is listed here; the default — not spec-runnable, empty set — bakes nothing.
400:
fixed_kwargs field '<key>' is not preset-bakeable for agent '<agent>': the agent is not spec_runnable and does not declare it in preset_bakeable_fields- a field that is not on the agent’s
ToolInputat all →fixed_kwargs field '<key>' is not a field of agent '<agent>'s input - a baked value that violates the field’s declared type or constraints →
fixed_kwargs field '<key>' is invalid for agent '<agent>': ...
POST /api/presets) and the save-version door (POST /api/presets/{name}/versions) whenever the body carries fixed_kwargs, so a later version cannot smuggle in an un-bakeable field either.
Package and load
Depend ontai42-contract (and tai42-kit for shared LLM factories) only; never import the skeleton. The host loads the agents by naming the module under agents[]; the agents router that drives them over SSE mounts by default, so you do not list it:
manifest.yml
Shipped implementations
Shipped agent packages appear in the ecosystem catalog, each linking to its own repository.See also
- Agents — the two faces of one
Agentclass. - Deep agents — sub-agents, skills, and strategies.
- Author an agent — a first agent, end to end.
- Python SDK reference — the
Agentcontract surface.

