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.

1083
Source Files
12+
LLM Providers
60+
Agent Tools
TypeScript
Language

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:

  1. Command Entry — The user message arrives as an AgentCommandOpts object in agent-command.ts. This includes the message text, optional images, provider/model overrides, and delivery target.
  2. Session Resolution — command/session.ts resolves 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).
  3. Model Selection — run/setup.ts calls resolveHookModelSelection() which checks agent config, then plugin hooks, then falls back to the default model. The effective context window is calculated here.
  4. Auth Profile Ordering — auth-profiles.ts loads stored API credentials, filters out expired/cooldown profiles, and sorts by recency. External CLI credentials are synced with a 15-minute TTL.
  5. Runner Initialization — pi-embedded-runner/run.ts initializes the SessionManager from @mariozechner/pi-coding-agent, prepares tool runtimes (LSP, MCP, codex), and builds the system prompt from workspace files (SOUL, AGENTS, TOOLS, IDENTITY).
  6. Payload Building — payloads.ts constructs provider-specific payloads. Anthropic gets cache-retention headers; Google gets schema sanitization via clean-for-gemini.ts; OpenRouter gets capability flags.
  7. 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.
  8. Tool Execution Loop — If the LLM requests a tool call, attempt.ts validates arguments (with tool-call-argument-repair.ts for malformed JSON), executes the tool, and feeds the result back to the LLM. This loop continues until the LLM stops requesting tools.
  9. Context Compaction — If the conversation history exceeds the context window minus reserves (20K tokens floor), compact.ts triggers 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.
  10. Model Fallback — If the provider returns an error, model-fallback.ts categorizes 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.
  11. Result Assembly — The EmbeddedPiRunResult is assembled with payloads, usage metrics (input/output tokens), metadata (model used, duration, stop reason), and any pending tool sends.
  12. Delivery — command/delivery.ts routes the output to the target channel (webchat, WhatsApp, Slack thread, etc.). Session state and transcript are persisted to disk.

Key Components

ComponentFilePurpose
AgentCommandOptscommand/types.tsMain input type for agent command execution — message, images, provider, model, delivery target
runEmbeddedPiAgent()pi-embedded-runner/run.tsCore orchestrator (6600+ lines) — manages model resolution, auth, tool loops, compaction
resolveSession()command/session.tsSession creation/lookup by composite key; loads persisted thinking/verbose levels
buildEmbeddedRunPayloads()pi-embedded-runner/run/payloads.tsConstructs provider-specific LLM payloads from assistant texts and tool metadata
resolveHookModelSelection()pi-embedded-runner/run/setup.tsModel resolution through hook system with effective context window calculation
FallbackSummaryErrormodel-fallback.tsError thrown when all fallback models exhausted; carries per-attempt details and cooldown expiry
ToolInputErrortools/common.tsTyped error for tool parameter validation failures (HTTP 400)
ToolAuthorizationErrortools/common.tsTyped error for tool access control violations (HTTP 403)
SpawnAcpParamsacp-spawn.tsParameters for spawning autonomous child processes with mode, sandbox, and stream config
EmbeddedPiRunResultpi-embedded-runner/types.tsComplete result from agent execution — payloads, usage, metadata, tool sends, compaction status
SandboxConfigsandbox/types.tsStatic sandbox configuration: mode, backend (Docker/SSH), workspace root, image, tool policies
splitMessagesByTokenShare()compact.tsSplits message history by token ratio for adaptive compaction (40% base, 15% min)
resolveAuthProfileOrder()auth-profiles.tsAuth credential ordering with cooldown tracking and external CLI sync
createActionGate()tools/common.tsFactory for tool-level action allow/deny policy gates
cleanForGemini()schema/clean-for-gemini.tsStrips 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

ModuleInteraction
../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-agentSessionManager, prompt formatting, token estimation, summarization

Configuration

ParameterDefaultDescription
agents.list[].model—Primary model reference (provider/model format, e.g. anthropic/claude-3-5-sonnet)
agents.list[].thinkingDefaultoffDefault thinking level: off, minimal, low, medium, high, xhigh, adaptive
agents.defaults.compaction.reserveTokens20000Floor for compaction reserve tokens
agents.defaults.compaction.keepRecentTokens—Number of recent tokens to preserve during compaction
EXTERNAL_CLI_SYNC_TTL_MS900000External CLI auth sync timeout (15 minutes)
AUTH_STORE_LOCK_OPTIONS.retries10File lock retry count with 2x exponential backoff
DEFAULT_SANDBOX_IDLE_HOURS24Container idle cleanup threshold
DEFAULT_SANDBOX_IMAGEopenclaw-sandbox:bookworm-slimDefault Docker image for sandboxed execution
ACP_SPAWN_MODES["run","session"]Available ACP execution lifecycle modes
STEER_ABORT_SETTLE_TIMEOUT_MS5000Abort 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