Sub-agents

A sub-agent is a delegation target the model sees as a tool. Calling it spawns a full child session; the child's result folds back into the parent like a tool result.

Example

The parent declares a sub-agent. Both agents live on one worker, told apart by agent_id.

server.mjs
function assistant({ trigger, proposed }) {
    if (trigger.type === "session.start") {
        return {
            agent: {
                model: "claude-haiku-4-5-20251001",
                stream: true,
                sub_agents: [{ id: "poet", description: "Writes a haiku on any topic." }]
            }
        };
    }
    return proposed;
}

function poet({ trigger, proposed }) {
    if (trigger.type === "session.start") {
        return {
            agent: {
                model: "claude-haiku-4-5-20251001",
                stream: true,
                system: "You are a poet. Respond with a single haiku."
            }
        };
    }
    return proposed;
}

// One worker, two agents told apart by agent_id.
const decide = (req) => (req.agent_id === "poet" ? poet(req) : assistant(req));

Declaring

sub_agents lists the agents this one can delegate to. Each appears to the model as a tool named by its id, taking a single message argument. That id shares the model's tool namespace, so it must not collide with a tool name.

Delegating

When the model calls a sub-agent, proposed spawns a child session and sends its opening message, the message argument. The child runs as an ordinary session with its own agent_id, transcript, and cost. Its decision requests carry an ancestry list of the parent sessions above it.

Completing

When the child's turn finishes, the parent receives a sub_agent.finished trigger. proposed records the result as the delegating tool's result and re-prompts the parent, exactly as a tool.finished does. The child's cost and token usage roll up into the parent's turn.

Spec

type SubAgent = { id: string; description?: string }

// actions that open a child, proposed for you
{ type: "sub_agent.spawn"; session_id: string; agent_id: string; tool_call_id: string; retry?: RetryPolicy }
{ type: "message.send"; session_id: string; message: DraftMessage }

// trigger
{ type: "sub_agent.finished"; id: string; ok: boolean; session_id: string; agent_id: string; result?: string; error?: string }

On sub_agent.finished, id is the delegating tool call and session_id is the child. Full types in Protocol.

Next

  • Tool calls: delegation folds back like a tool result.
  • Durability: child sessions are persisted and resume.
  • Protocol: the spawn actions and finish trigger.