Agent Loop (OpenClaw)
Source: Agent Loop (OpenClaw)
Original file: raw/docs/agent-loop.md from openclaw.md
Topic: Agent loop lifecycle, streams, and wait semantics in OpenClaw.
Summary
OpenClaw's agent loop is the end-to-end execution path that turns an incoming message into model inference, tool calls, and a final reply — while keeping session state consistent. A loop is a single, serialized run per session.
Key entry points
- Gateway RPC:
agent(fire-and-forget, returns{runId, acceptedAt}immediately) andagent.wait(blocks until lifecycle end/error). - CLI:
agentcommand.
Execution flow
agentRPC validates params, resolves/persists session, returns immediately.agentCommandresolves model + defaults, loads skills snapshot, callsrunEmbeddedPiAgent.runEmbeddedPiAgentserializes runs via per-session + global queues, builds the pi session, subscribes to events, enforces timeout.subscribeEmbeddedPiSessionbridges pi-agent-core events → OpenClaw streams (tool,assistant,lifecycle).agent.waitcallswaitForAgentRun— waits forlifecycle end/error, returns{status, startedAt, endedAt, error?}.
Queueing & concurrency
Runs are serialized per session key (session lane) + optionally a global lane, preventing tool/session races. See Command Queue.
Prompt assembly
System prompt = base prompt + skills prompt + bootstrap context + per-run overrides. Model-specific token limits enforced. See System Prompt.
Hook points
Internal (Gateway) hooks
| Hook | When |
|---|---|
agent:bootstrap |
Before system prompt finalization — add/remove bootstrap context files |
| Command hooks | /new, /reset, /stop, etc. |
Plugin hooks (inside agent/tool lifecycle)
| Hook | Purpose |
|---|---|
before_model_resolve |
Override provider/model before resolution (no messages yet) |
before_prompt_build |
Inject context/system-prompt additions after session load |
before_agent_reply |
Claim the turn and return a synthetic reply or silence it |
agent_end |
Inspect final message list + run metadata |
before_compaction / after_compaction |
Observe or annotate compaction cycles |
before_tool_call / after_tool_call |
Intercept tool params/results |
before_install |
Inspect scan findings, optionally block skill/plugin installs |
tool_result_persist |
Transform tool results before writing to transcript |
message_received / message_sending / message_sent |
Inbound + outbound message hooks |
session_start / session_end |
Session lifecycle boundaries |
gateway_start / gateway_stop |
Gateway lifecycle events |
Block/cancel semantics: block: true or cancel: true is terminal; block: false / cancel: false is a no-op (cannot clear a prior block).
Streaming
- Assistant deltas streamed from pi-agent-core → emitted as
assistantevents. - Partial replies emitted on
text_endormessage_end. - Reasoning can be a separate stream or embedded as block replies.
- See Streaming.
Reply shaping
Final payload = assistant text + optional reasoning + inline tool summaries (verbose mode) + fallback tool-error reply. The NO_REPLY/no_reply token is filtered out. Messaging-tool duplicates are removed.
Compaction & retries
Auto-compaction emits compaction stream events and can trigger a retry (resets in-memory buffers). See Compaction.
Timeouts
| Timeout | Default | Config key |
|---|---|---|
agent.wait |
30s | timeoutMs param |
| Agent runtime | 172800s (48h) | agents.defaults.timeoutSeconds |
| LLM idle | 60s (fallback) | agents.defaults.llm.idleTimeoutSeconds (0 = disabled) |
Cron-triggered runs disable the LLM idle watchdog and rely on the cron outer timeout.
Early termination causes
- Agent timeout (abort)
- AbortSignal (cancel)
- Gateway disconnect / RPC timeout
agent.waittimeout (wait-only — does not stop the agent)