Subagents
Introduction
Section titled “Introduction”An orchestrator agent can hand work to other agents: a researcher gathers, a writer drafts, an analyst checks. Each handoff is a subagent, built from that agent’s own definition. Use this when one prompt would otherwise carry too many jobs, or when some of the work should run while the user keeps chatting.
The runtime builds on DeepAgents, which provides the task tool used for delegation (see Concepts).
Making an agent an orchestrator
Section titled “Making an agent an orchestrator”The repository’s sample orchestrator lists three agents it can delegate to. It also needs the built-in task tool.
runtime: profileId: default tools: [] builtinTools: [task] subagents: [researcher, writer, analyst]runtime.subagents lists the ids of other agents, at most AGENT_LIMITS.subagents (8), none twice. The agent manager requires task in builtinTools for a non-empty list.
Each subagent runs with its own prompt, the model and params of its own profile, its own tools, builtinTools and skills, and the tool policy. The orchestrator learns about it from its description, so write that as “when to use this agent”.
Choosing which agents are available
Section titled “Choosing which agents are available”- Absent keeps the one general-purpose subagent DeepAgents adds.
- A list, even an empty one, makes the choice exactly those agents. DeepAgents cannot leave its general-purpose subagent out of a graph, so
taskrefuses a call naming it while the model still reads its line in the tool description.
Subagents resolve when the graph is built, through the same AgentDefinitionSource and in the caller’s identity. A tenant’s agents and the system agents both resolve; another tenant’s never do. The depth is one: a subagent’s own list is not read.
Handling failures
Section titled “Handling failures”- A subagent that is missing, a draft, invalid or on an unknown profile fails the run at start, naming the orchestrator and the subagent. It is never silently dropped.
- A failing subagent (a provider error or timeout) reaches its parent as an error result of that
taskcall and does not end the run. The parent decides what to do. The kit never retries a failed subagent itself, and a cancelled run still stops. - Editing a subagent, its file or its profile reaches the orchestrator’s next run, because the graph cache version includes every subagent’s definition and profile.
- A subagent’s model calls are recorded under the subagent’s own provider and model. The run summary keeps the orchestrator’s.
Running subagents in the background
Section titled “Running subagents in the background”Every PilotooModule.forRoot host wires BackgroundTaskService into its runner as the tasks launcher. The orchestrator then gets DeepAgents’ async tools beside task, and each subagent runs as a task that can outlive the turn.
| Behavior | What happens |
|---|---|
| Each task has its own conversation | Owned by the caller and hidden from GET /conversations. It opens like any thread. SUBAGENT_STARTED carries taskId and childThreadId. |
| Results come back on their own | A task nobody waits on posts a turn on the parent thread once no run is active there and no decision is pending. It is a human message marked task; a client should render it as a notice, not as the reader’s message. |
| One run per thread | A run:start on a thread with a run in flight, or with turns already queued, is queued and starts when the thread frees. A queued message that keeps failing to start is given up with INVALID_COMMAND. |
| Moving to the background | run:start on a thread waiting on task moves it to the background and runs the message after the run. run:detach { runId, toolCallId? } does it without a message (INVALID_COMMAND when nothing waits). run:cancel and cancel_async_task still cancel. |
| Continuing a task | run:start on a task’s conversation interrupts and continues the task, or runs a settled one again. |
| Restart | Tasks left running are marked interrupted at boot and announced to their parent. The announcement runs without the owner’s credentials, so the agent is told to offer a new start rather than make one. |
A host assembling its own runner without the module passes tasks: new InMemoryBackgroundTaskLauncher({ onSettled }) (from @pilotoo/agent-runtime), or none, which keeps DeepAgents’ in-run task.
Storage
Section titled “Storage”The backgroundTaskStorage port (BackgroundTaskStorage, token BACKGROUND_TASK_STORAGE) is PostgreSQL by default (table created on first use; see Storage) and SQLite in the local backend. It must share storage with conversationStore, which hides a task’s conversation and deletes it, at any depth, with its parent. A host that supplies the persistence ports and not this one runs without background tasks (one log line at boot), and its agents keep DeepAgents’ in-run task.
What the model reads
Section titled “What the model reads”On an agent that runs tasks, the model reads an announcement turn as the result of a check_async_task call on that task, so the subagent’s output never carries a user’s authority. The checkpoint and history keep the marked human message.
Showing subagents in a client
Section titled “Showing subagents in a client”useConversation from @pilotoo/chat-core gives detach(toolCallId?) and sendableWhileRunning. A wake-up turn is a ChatMessage with task, and SubagentActivity.task carries taskId and childThreadId. SUBAGENT_FINISHED.detached marks a subagent moved to the background. @pilotoo/ui/chat and @pilotoo/chat-ui draw a task call as a subagent card and a wake-up as a notice.
Managing subagents from the editor
Section titled “Managing subagents from the editor”The agent manager refuses an unknown, draft, malformed or own id as an issue on runtime.subagents. Deleting or drafting an agent that others name is a 409 referenced-agent with referencedBy. GET /agent-admin/options lists the active agents the caller can read as agents (id, name, description, source) for the editor.
After a reload, a task call in the thread history carries its subagent (name, description), so the tool-call row renders as it did live.
Next steps
Section titled “Next steps”- Agents for the full agent definition.
- Skills to give a subagent reusable instructions.
- Connecting a client for the events a client receives.