Agents — LLM Orchestration Engine
Multi-Provider LLM Orchestration, Tool Execution & Agent Spawning
The agents module is the execution engine of OpenClaw. It handles the full lifecycle of an AI agent command — from model resolution and auth profile management through streaming LLM responses, tool execution loops, context compaction, and cascading model fallback. It supports 12+ LLM providers, sandboxed code execution, and autonomous child agent spawning via ACP.
Multi-Provider Streaming Sandboxed Fault-Tolerant
📚 What is this & why does it exist?
The Agents module is the brain of OpenClaw. When a user sends a message, this module figures out which AI model to talk to, sends the request, streams back the response in real-time, and handles any tool calls the AI wants to make (running code, fetching web pages, spawning sub-agents). If the primary model fails, it automatically falls back to alternative providers.
💡 Real-world analogy
Think of the Agents module as an air traffic control tower at a busy international airport. Each incoming user message is a flight requesting a landing slot. The tower (agent-command pipeline) determines which runway (LLM provider) to assign. The streaming system is like the real-time radar feed — continuously updating position. Tool calls are like ground services (refueling, baggage handling) that happen mid-flight. If one runway shuts down (provider error), the tower immediately reroutes to an alternative runway (model fallback). The sandbox is the secure customs area where foreign cargo (untrusted code) is inspected before entry.
Architecture
flowchart LR
subgraph Entry["Command Entry"]
CMD["agent-command.ts\nrunAgentCommand()"]
SESS["command/session.ts\nresolveSession()"]
end
subgraph Runtime["PI Embedded Runner"]
RUN["run.ts\nrunEmbeddedPiAgent()"]
ATT["attempt.ts\nTool Execution Loop"]
PAY["payloads.ts\nbuildEmbeddedRunPayloads()"]
SETUP["setup.ts\nresolveHookModelSelection()"]
end
subgraph Providers["Provider Layer"]
OAI["openai-stream-wrappers.ts"]
ANT["anthropic-cache-retention.ts"]
GOO["google-stream-wrappers.ts"]
BED["bedrock-stream-wrappers.ts"]
PROXY["proxy-stream-wrappers.ts"]
end
subgraph Tools["Tool System"]
COMMON["tools/common.ts"]
EXEC["bash-tools.exec.ts"]
WEB["web-fetch.ts"]
SPAWN["sessions-spawn-tool.ts"]
MSG["message-tool.ts"]
end
subgraph Support["Support Systems"]
AUTH["auth-profiles.ts"]
FALL["model-fallback.ts"]
COMPACT["compact.ts"]
SANDBOX["sandbox/"]
end
CMD --> SESS
SESS --> RUN
RUN --> SETUP
SETUP --> Providers
RUN --> ATT
ATT --> PAY
ATT --> Tools
ATT --> COMPACT
RUN --> AUTH
RUN --> FALL
EXEC --> SANDBOX
Data Flow
sequenceDiagram
participant User as User Input
participant CMD as agent-command.ts
participant Session as command/session.ts
participant Setup as run/setup.ts
participant Auth as auth-profiles.ts
participant Runner as pi-embedded-runner/run.ts
participant LLM as LLM Provider
participant Tools as Tool System
participant Delivery as command/delivery.ts
User->>CMD: AgentCommandOpts
CMD->>Session: resolveSession()
Session-->>CMD: SessionResolution
CMD->>Setup: resolveHookModelSelection()
Setup->>Auth: resolveAuthProfileOrder()
Auth-->>Setup: Auth credentials
Setup-->>CMD: Model + Auth ready
CMD->>Runner: runEmbeddedPiAgent()
loop Tool Execution Loop
Runner->>LLM: Stream request
LLM-->>Runner: Streaming chunks
alt Tool call requested
Runner->>Tools: Execute tool
Tools-->>Runner: Tool result
end
alt Context overflow
Runner->>Runner: Compact history
end
end
Runner-->>CMD: EmbeddedPiRunResult
CMD->>Delivery: deliverResult()
Delivery-->>User: Agent response
🚶 Step-by-Step Narrated Walkthrough
Follow a single user chat message as it flows through the entire Agents pipeline:
- Command Entry — The user message arrives as an
AgentCommandOptsobject inagent-command.ts. This includes the message text, optional images, provider/model overrides, and delivery target. - Session Resolution —
command/session.tsresolves or creates a session using the composite key (agent ID + channel + account + thread). The session store is loaded from disk with file-lock protection (~1ms). - Model Selection —
run/setup.tscallsresolveHookModelSelection()which checks agent config, then plugin hooks, then falls back to the default model. The effective context window is calculated here. - Auth Profile Ordering —
auth-profiles.tsloads stored API credentials, filters out expired/cooldown profiles, and sorts by recency. External CLI credentials are synced with a 15-minute TTL. - Runner Initialization —
pi-embedded-runner/run.tsinitializes theSessionManagerfrom@mariozechner/pi-coding-agent, prepares tool runtimes (LSP, MCP, codex), and builds the system prompt from workspace files (SOUL, AGENTS, TOOLS, IDENTITY). - Payload Building —
payloads.tsconstructs provider-specific payloads. Anthropic gets cache-retention headers; Google gets schema sanitization viaclean-for-gemini.ts; OpenRouter gets capability flags. - LLM Streaming — The request is sent to the chosen provider. Streaming chunks arrive in real-time through provider-specific wrappers (e.g.,
openai-stream-wrappers.ts). Each chunk is assembled into the response buffer. - Tool Execution Loop — If the LLM requests a tool call,
attempt.tsvalidates arguments (withtool-call-argument-repair.tsfor malformed JSON), executes the tool, and feeds the result back to the LLM. This loop continues until the LLM stops requesting tools. - Context Compaction — If the conversation history exceeds the context window minus reserves (20K tokens floor),
compact.tstriggers adaptive compaction: split messages by token share (40% base ratio), summarize each chunk, merge preserving identifiers. A 20% safety margin accounts for token estimation inaccuracy. - Model Fallback — If the provider returns an error,
model-fallback.tscategorizes it (rate-limit, context overflow, timeout, auth) and cascades to the next model in the fallback chain. Cooldown probing allows retrying recently-failed providers with short budgets. - Result Assembly — The
EmbeddedPiRunResultis assembled with payloads, usage metrics (input/output tokens), metadata (model used, duration, stop reason), and any pending tool sends. - Delivery —
command/delivery.tsroutes the output to the target channel (webchat, WhatsApp, Slack thread, etc.). Session state and transcript are persisted to disk.
Key Components
| Component | File | Purpose |
|---|---|---|
AgentCommandOpts | command/types.ts | Main input type for agent command execution — message, images, provider, model, delivery target |
runEmbeddedPiAgent() | pi-embedded-runner/run.ts | Core orchestrator (6600+ lines) — manages model resolution, auth, tool loops, compaction |
resolveSession() | command/session.ts | Session creation/lookup by composite key; loads persisted thinking/verbose levels |
buildEmbeddedRunPayloads() | pi-embedded-runner/run/payloads.ts | Constructs provider-specific LLM payloads from assistant texts and tool metadata |
resolveHookModelSelection() | pi-embedded-runner/run/setup.ts | Model resolution through hook system with effective context window calculation |
FallbackSummaryError | model-fallback.ts | Error thrown when all fallback models exhausted; carries per-attempt details and cooldown expiry |
ToolInputError | tools/common.ts | Typed error for tool parameter validation failures (HTTP 400) |
ToolAuthorizationError | tools/common.ts | Typed error for tool access control violations (HTTP 403) |
SpawnAcpParams | acp-spawn.ts | Parameters for spawning autonomous child processes with mode, sandbox, and stream config |
EmbeddedPiRunResult | pi-embedded-runner/types.ts | Complete result from agent execution — payloads, usage, metadata, tool sends, compaction status |
SandboxConfig | sandbox/types.ts | Static sandbox configuration: mode, backend (Docker/SSH), workspace root, image, tool policies |
splitMessagesByTokenShare() | compact.ts | Splits message history by token ratio for adaptive compaction (40% base, 15% min) |
resolveAuthProfileOrder() | auth-profiles.ts | Auth credential ordering with cooldown tracking and external CLI sync |
createActionGate() | tools/common.ts | Factory for tool-level action allow/deny policy gates |
cleanForGemini() | schema/clean-for-gemini.ts | Strips unsupported JSON Schema keywords for Google Gemini compatibility |
Sub-Modules
streaming/
LLM response streaming, chunk assembly, backpressure handling, and provider-specific stream wrappers for OpenAI, Anthropic, Google, Bedrock, and more.
- Provider-specific stream wrappers
- Chunk assembly & buffering
- Error recovery mid-stream
providers/
Multi-model provider adapters with model resolution, auth profile management, payload formatting, and cascading fallback with cooldown probing.
- 12+ provider adapters
- Cascading model fallback
- API key rotation & cooldown
tool-use/
Tool/function calling infrastructure with 60+ built-in tools, schema validation, argument repair, sandbox execution, and MCP server integration.
- 60+ agent tools
- TypeBox schema validation
- Sandboxed code execution
Module Interactions
| Module | Interaction |
|---|---|
../config/ | Loads agent config, session store, model catalog; resolves paths and defaults |
../acp/ | ACP session manager, policy checking, runtime errors, session identifiers |
../channels/ | Thread binding policy, conversation ID resolution, channel plugins |
../context-engine/ | Context window info, compaction ownership flags |
../sessions/ | Session transcript repair, model/verbose overrides, send policy |
../routing/ | Session key parsing/normalization, agent ID extraction |
../infra/ | Agent events emission, outbound session context, skill eligibility |
../gateway/ | Gateway call execution for remote procedure invocations |
../plugin-sdk/ | Model ID normalization (Google, XAI), plugin extensions |
@mariozechner/pi-coding-agent | SessionManager, prompt formatting, token estimation, summarization |
Configuration
| Parameter | Default | Description |
|---|---|---|
agents.list[].model | — | Primary model reference (provider/model format, e.g. anthropic/claude-3-5-sonnet) |
agents.list[].thinkingDefault | off | Default thinking level: off, minimal, low, medium, high, xhigh, adaptive |
agents.defaults.compaction.reserveTokens | 20000 | Floor for compaction reserve tokens |
agents.defaults.compaction.keepRecentTokens | — | Number of recent tokens to preserve during compaction |
EXTERNAL_CLI_SYNC_TTL_MS | 900000 | External CLI auth sync timeout (15 minutes) |
AUTH_STORE_LOCK_OPTIONS.retries | 10 | File lock retry count with 2x exponential backoff |
DEFAULT_SANDBOX_IDLE_HOURS | 24 | Container idle cleanup threshold |
DEFAULT_SANDBOX_IMAGE | openclaw-sandbox:bookworm-slim | Default Docker image for sandboxed execution |
ACP_SPAWN_MODES | ["run","session"] | Available ACP execution lifecycle modes |
STEER_ABORT_SETTLE_TIMEOUT_MS | 5000 | Abort signal propagation timeout for subagent steering |
Directory Map
Source tree for agents/
agents/
├── agent-command.ts ← Main entry: command execution pipeline
├── agent-scope.ts ← Agent configuration resolution
├── agent-paths.ts ← Agent directory path utilities
├── acp-spawn.ts ← ACP autonomous child process spawning
├── acp-spawn-parent-stream.ts ← Parent-stream relay for ACP
├── auth-profiles.ts ← Auth credential management & cooldown
├── auth-health.ts ← Auth profile health monitoring
├── model-fallback.ts ← Cascading model fallback logic
├── subagent-spawn.ts ← Subagent task spawning
├── command/ ← Command execution pipeline
│ ├── types.ts ← AgentCommandOpts, AgentRunContext
│ ├── session.ts ← Session resolution & creation
│ ├── attempt-execution.ts ← Attempt orchestration
│ ├── delivery.ts ← Result delivery to channels
│ ├── run-context.ts ← Run context extraction
│ └── session-store.ts ← Session persistence
├── pi-embedded-runner/ ← Core embedded runtime (largest)
│ ├── run.ts ← Main orchestrator (6600+ lines)
│ ├── types.ts ← EmbeddedPiRunResult, meta types
│ ├── model.ts ← Model registry & resolution
│ ├── compact.ts ← Adaptive message compaction
│ ├── extra-params.ts ← Provider-specific parameters
│ ├── openai-stream-wrappers.ts ← OpenAI streaming adapter
│ ├── google-stream-wrappers.ts ← Google/Gemini streaming adapter
│ ├── anthropic-cache-retention.ts ← Anthropic cache handling
│ ├── bedrock-stream-wrappers.ts ← AWS Bedrock adapter
│ └── run/ ← Execution sub-pipeline
│ ├── attempt.ts ← Tool execution loop (2300+ lines)
│ ├── setup.ts ← Model & auth resolution
│ ├── payloads.ts ← Payload formatting
│ └── helpers.ts ← Runtime utilities
├── tools/ ← 60+ agent tool implementations
│ ├── common.ts ← ToolInputError, createActionGate
│ ├── web-fetch.ts ← Web fetching with readability
│ ├── web-search.ts ← Web search integration
│ ├── message-tool.ts ← Messaging infrastructure
│ ├── sessions-spawn-tool.ts ← Subagent/ACP spawning tool
│ ├── cron-tool.ts ← Scheduled job management
│ └── image-tool.ts ← Image processing
├── sandbox/ ← Sandboxed execution
│ └── types.ts ← SandboxConfig, SandboxContext
├── schema/ ← Schema validation
│ ├── clean-for-gemini.ts ← Gemini schema sanitization
│ └── typebox.ts ← TypeBox schema utilities
└── skills/ ← Agent skills management
└── types.ts ← SkillSnapshot definitions