--- summary: "Agent loop lifecycle, streams, and wait semantics" read_when: - You need an exact walkthrough of the agent loop or lifecycle events --- # Agent Loop (Clawdbot) Short, exact flow of one agent run. ## Entry points - Gateway RPC: `agent` and `agent.wait`. - CLI: `agent` command. ## High-level flow 1) `agent` RPC validates params, resolves session (sessionKey/sessionId), persists session metadata, returns `{ runId, acceptedAt }` immediately. 2) `agentCommand` runs the agent: - resolves model + thinking/verbose defaults - loads skills snapshot - calls `runEmbeddedPiAgent` (pi-agent-core runtime) - emits **lifecycle end/error** if the embedded loop does not emit one 3) `runEmbeddedPiAgent`: - builds `AgentSession` and subscribes to pi events - streams assistant deltas + tool events - enforces timeout -> aborts run if exceeded - returns payloads + usage metadata 4) `subscribeEmbeddedPiSession` bridges pi-agent-core events to Clawdbot `agent` stream: - tool events => `stream: "tool"` - assistant deltas => `stream: "assistant"` - lifecycle events => `stream: "lifecycle"` (`phase: "start" | "end" | "error"`) 5) `agent.wait` uses `waitForAgentJob`: - waits for **lifecycle end/error** for `runId` - returns `{ status: ok|error|timeout, startedAt, endedAt, error? }` ## Event streams (today) - `lifecycle`: emitted by `subscribeEmbeddedPiSession` (and as a fallback by `agentCommand`) - `assistant`: streamed deltas from pi-agent-core - `tool`: streamed tool events from pi-agent-core ## Chat provider handling - Assistant deltas are buffered into chat `delta` messages. - A chat `final` is emitted on **lifecycle end/error**. ## Timeouts - `agent.wait` default: 30s (just the wait). `timeoutMs` param overrides. - Agent runtime: `agents.defaults.timeoutSeconds` default 600s; enforced in `runEmbeddedPiAgent` abort timer. ## Where things can end early - Agent timeout (abort) - AbortSignal (cancel) - Gateway disconnect or RPC timeout - `agent.wait` timeout (wait-only, does not stop agent)