Auto-managed state agents (using
AutomaticallyManagedStateAgent) are TypeScript functions you write yourself. They execute deterministically from start to finish, with no LLM driving the control flow — though you can call LLMs as needed within your code.
The runtime handles state persistence automatically. You write a straightforward async run function, and the babel-plugin-agent-compiler transforms it into a resumable state machine behind the scenes.
Example
Add the"use agent" directive at the top of your file so the runtime can manage state between tool calls.
The
description field is optional and deprecated as of @guildai/agents-sdk 0.4.0. Guild generates the agent’s published description automatically from its code, so setting description no longer affects the published description.Input and output schemas
Define your schemas using Zod. The runtime uses them to validate input and expose the agent as a typed tool for orchestrating agents.Error handling
Any exception thrown from yourrun function is returned to the calling agent or user. Use standard TypeScript error handling:
Limitations
The"use agent" directive relies on the Babel compiler to transform your code into a state machine. This means:
- No
Promise.all,Promise.any, orPromise.race— awaiting tool calls one at a time serializes between the calls, so each runs independently. If the calls are independent tool calls and you want them to run in parallel rather than one after another, usetask.gather/task.gatherSettledinstead — see Parallel tool calls withtask.gatherbelow. These are the compiler-supported replacement forPromise.all/Promise.allSettledwhen every input is a tool call. - No dynamic function references across
awaitpoints — conditionally assigned functions may not survive serialization - No external imports — only
@guildai/agents-sdk,zod, and@guildai-services/*are supported
Compilation required for sub-agents and service hooks
Calling a sub-agent or service hook from an uncompiled auto-managed state agent crashes at runtime. To prevent this, Guild validates at build time that any auto-managed state agent using these tools is compiled. An auto-managed state agent must be compiled with the"use agent" directive when it registers or calls:
- Sub-agents (tools of
toolType: "agent"). - Individually registered integration service hooks.
ui, guild, and console — are exempt and do not require compilation.
Parallel tool calls with task.gather
Promise.all does not survive serialization (see Limitations above). For auto-managed state agents ("use agent"), the supported way to fan out independent tool calls concurrently is task.gather and task.gatherSettled. The runtime allocates every subtask atomically, dispatches them as a single batch, suspends the state machine while they run, and assembles the results in source order on resume.
task.gather — fail fast
Analogous to Promise.all: resolves to an array of results in source order, or rejects on the first failure.
task.gather([a, b]) returns a tuple whose elements are the awaited return types of a and b, in order.
task.gatherSettled — collect every outcome
Analogous to Promise.allSettled: never rejects. Each entry is a PromiseSettledResult describing whether that call fulfilled or rejected, so one failing call doesn’t sink the rest.
Rules and limits
- Inputs must be tool-call expressions —
task.tools.X(...), sub-agent tool calls, or hook tools. TheToolCallPromisebrand on the parameter type rejects arbitrary promises (fetch(...), timers, library code) at compile time. This is the deliberate boundary that makesgatherwork wherePromise.allcan’t: every input is a dispatchable tool call the runtime can serialize, not an opaque promise. - Use only from a compiled (
"use agent") agent body. Self-managed state agents already fan out in parallel by returningcallTools([...])with more than one entry — they don’t needgather.