6 custom skills (assign-task, dispatch-webhook, daily-briefing, task-capture, qmd-brain, tts-voice) with technical documentation. Compatible with Claude Code, OpenClaw, Codex CLI, and OpenCode.
89 lines
8.4 KiB
JSON
Executable File
89 lines
8.4 KiB
JSON
Executable File
{
|
||
"title": "Agent Loop (OpenClaw)",
|
||
"content": "An agentic loop is the full “real” run of an agent: intake → context assembly → model inference →\ntool execution → streaming replies → persistence. It’s the authoritative path that turns a message\ninto actions and a final reply, while keeping session state consistent.\n\nIn OpenClaw, a loop is a single, serialized run per session that emits lifecycle and stream events\nas the model thinks, calls tools, and streams output. This doc explains how that authentic loop is\nwired end-to-end.\n\n* Gateway RPC: `agent` and `agent.wait`.\n* CLI: `agent` command.\n\n## How it works (high-level)\n\n1. `agent` RPC validates params, resolves session (sessionKey/sessionId), persists session metadata, returns `{ runId, acceptedAt }` immediately.\n2. `agentCommand` runs the agent:\n * resolves model + thinking/verbose defaults\n * loads skills snapshot\n * calls `runEmbeddedPiAgent` (pi-agent-core runtime)\n * emits **lifecycle end/error** if the embedded loop does not emit one\n3. `runEmbeddedPiAgent`:\n * serializes runs via per-session + global queues\n * resolves model + auth profile and builds the pi session\n * subscribes to pi events and streams assistant/tool deltas\n * enforces timeout -> aborts run if exceeded\n * returns payloads + usage metadata\n4. `subscribeEmbeddedPiSession` bridges pi-agent-core events to OpenClaw `agent` stream:\n * tool events => `stream: \"tool\"`\n * assistant deltas => `stream: \"assistant\"`\n * lifecycle events => `stream: \"lifecycle\"` (`phase: \"start\" | \"end\" | \"error\"`)\n5. `agent.wait` uses `waitForAgentJob`:\n * waits for **lifecycle end/error** for `runId`\n * returns `{ status: ok|error|timeout, startedAt, endedAt, error? }`\n\n## Queueing + concurrency\n\n* Runs are serialized per session key (session lane) and optionally through a global lane.\n* This prevents tool/session races and keeps session history consistent.\n* Messaging channels can choose queue modes (collect/steer/followup) that feed this lane system.\n See [Command Queue](/concepts/queue).\n\n## Session + workspace preparation\n\n* Workspace is resolved and created; sandboxed runs may redirect to a sandbox workspace root.\n* Skills are loaded (or reused from a snapshot) and injected into env and prompt.\n* Bootstrap/context files are resolved and injected into the system prompt report.\n* A session write lock is acquired; `SessionManager` is opened and prepared before streaming.\n\n## Prompt assembly + system prompt\n\n* System prompt is built from OpenClaw’s base prompt, skills prompt, bootstrap context, and per-run overrides.\n* Model-specific limits and compaction reserve tokens are enforced.\n* See [System prompt](/concepts/system-prompt) for what the model sees.\n\n## Hook points (where you can intercept)\n\nOpenClaw has two hook systems:\n\n* **Internal hooks** (Gateway hooks): event-driven scripts for commands and lifecycle events.\n* **Plugin hooks**: extension points inside the agent/tool lifecycle and gateway pipeline.\n\n### Internal hooks (Gateway hooks)\n\n* **`agent:bootstrap`**: runs while building bootstrap files before the system prompt is finalized.\n Use this to add/remove bootstrap context files.\n* **Command hooks**: `/new`, `/reset`, `/stop`, and other command events (see Hooks doc).\n\nSee [Hooks](/hooks) for setup and examples.\n\n### Plugin hooks (agent + gateway lifecycle)\n\nThese run inside the agent loop or gateway pipeline:\n\n* **`before_agent_start`**: inject context or override system prompt before the run starts.\n* **`agent_end`**: inspect the final message list and run metadata after completion.\n* **`before_compaction` / `after_compaction`**: observe or annotate compaction cycles.\n* **`before_tool_call` / `after_tool_call`**: intercept tool params/results.\n* **`tool_result_persist`**: synchronously transform tool results before they are written to the session transcript.\n* **`message_received` / `message_sending` / `message_sent`**: inbound + outbound message hooks.\n* **`session_start` / `session_end`**: session lifecycle boundaries.\n* **`gateway_start` / `gateway_stop`**: gateway lifecycle events.\n\nSee [Plugins](/plugin#plugin-hooks) for the hook API and registration details.\n\n## Streaming + partial replies\n\n* Assistant deltas are streamed from pi-agent-core and emitted as `assistant` events.\n* Block streaming can emit partial replies either on `text_end` or `message_end`.\n* Reasoning streaming can be emitted as a separate stream or as block replies.\n* See [Streaming](/concepts/streaming) for chunking and block reply behavior.\n\n## Tool execution + messaging tools\n\n* Tool start/update/end events are emitted on the `tool` stream.\n* Tool results are sanitized for size and image payloads before logging/emitting.\n* Messaging tool sends are tracked to suppress duplicate assistant confirmations.\n\n## Reply shaping + suppression\n\n* Final payloads are assembled from:\n * assistant text (and optional reasoning)\n * inline tool summaries (when verbose + allowed)\n * assistant error text when the model errors\n* `NO_REPLY` is treated as a silent token and filtered from outgoing payloads.\n* Messaging tool duplicates are removed from the final payload list.\n* If no renderable payloads remain and a tool errored, a fallback tool error reply is emitted\n (unless a messaging tool already sent a user-visible reply).\n\n## Compaction + retries\n\n* Auto-compaction emits `compaction` stream events and can trigger a retry.\n* On retry, in-memory buffers and tool summaries are reset to avoid duplicate output.\n* See [Compaction](/concepts/compaction) for the compaction pipeline.\n\n## Event streams (today)\n\n* `lifecycle`: emitted by `subscribeEmbeddedPiSession` (and as a fallback by `agentCommand`)\n* `assistant`: streamed deltas from pi-agent-core\n* `tool`: streamed tool events from pi-agent-core\n\n## Chat channel handling\n\n* Assistant deltas are buffered into chat `delta` messages.\n* A chat `final` is emitted on **lifecycle end/error**.\n\n* `agent.wait` default: 30s (just the wait). `timeoutMs` param overrides.\n* Agent runtime: `agents.defaults.timeoutSeconds` default 600s; enforced in `runEmbeddedPiAgent` abort timer.\n\n## Where things can end early\n\n* Agent timeout (abort)\n* AbortSignal (cancel)\n* Gateway disconnect or RPC timeout\n* `agent.wait` timeout (wait-only, does not stop agent)",
|
||
"code_samples": [],
|
||
"headings": [
|
||
{
|
||
"level": "h2",
|
||
"text": "Entry points",
|
||
"id": "entry-points"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "How it works (high-level)",
|
||
"id": "how-it-works-(high-level)"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Queueing + concurrency",
|
||
"id": "queueing-+-concurrency"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Session + workspace preparation",
|
||
"id": "session-+-workspace-preparation"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Prompt assembly + system prompt",
|
||
"id": "prompt-assembly-+-system-prompt"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Hook points (where you can intercept)",
|
||
"id": "hook-points-(where-you-can-intercept)"
|
||
},
|
||
{
|
||
"level": "h3",
|
||
"text": "Internal hooks (Gateway hooks)",
|
||
"id": "internal-hooks-(gateway-hooks)"
|
||
},
|
||
{
|
||
"level": "h3",
|
||
"text": "Plugin hooks (agent + gateway lifecycle)",
|
||
"id": "plugin-hooks-(agent-+-gateway-lifecycle)"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Streaming + partial replies",
|
||
"id": "streaming-+-partial-replies"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Tool execution + messaging tools",
|
||
"id": "tool-execution-+-messaging-tools"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Reply shaping + suppression",
|
||
"id": "reply-shaping-+-suppression"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Compaction + retries",
|
||
"id": "compaction-+-retries"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Event streams (today)",
|
||
"id": "event-streams-(today)"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Chat channel handling",
|
||
"id": "chat-channel-handling"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Timeouts",
|
||
"id": "timeouts"
|
||
},
|
||
{
|
||
"level": "h2",
|
||
"text": "Where things can end early",
|
||
"id": "where-things-can-end-early"
|
||
}
|
||
],
|
||
"url": "llms-txt#agent-loop-(openclaw)",
|
||
"links": []
|
||
} |