エージェントループ(OpenClaw)
エージェントループとは、エージェントの一連の処理を最初から最後まで通す本流のことです。メッセージ受信からコンテキスト構築、モデル推論、ツール実行、ストリーミング応答、永続化までを一気通貫で処理し、セッション状態の一貫性を維持しながらメッセージをアクションと最終応答へ変換します。
OpenClawでは、ループはセッションごとにシリアライズされた単一の実行単位であり、モデルが思考しツールを呼び出しながら出力をストリーミングする過程で、ライフサイクルイベントやストリームイベントを発行します。このドキュメントでは、このループがエンドツーエンドでどのように組み上がっているかを解説します。
エントリーポイント
- Gateway RPC:
agentおよびagent.wait - CLI:
agentコマンド
全体の流れ(ハイレベル)
agentRPCがパラメータを検証し、セッション(sessionKey/sessionId)を解決してセッションメタデータを永続化した後、{ runId, acceptedAt }を即座に返します。agentCommandがエージェントを実行します:- モデルとthinking/verboseのデフォルトを解決
- スキルスナップショットを読み込み
runEmbeddedPiAgent(pi-agent-coreランタイム)を呼び出し- 組み込みループがライフサイクルイベントを発行しなかった場合、ライフサイクル end/error を発行
runEmbeddedPiAgent:- セッション単位+グローバルキューでランをシリアライズ
- モデル+認証プロファイルを解決してpiセッションを構築
- piイベントを購読し、assistant/toolのデルタをストリーミング
- タイムアウトを強制し、超過時にランを中断
- ペイロード+使用量メタデータを返却
subscribeEmbeddedPiSessionがpi-agent-coreのイベントをOpenClawのagentストリームにブリッジ:- ツールイベント =>
stream: "tool" - アシスタントデルタ =>
stream: "assistant" - ライフサイクルイベント =>
stream: "lifecycle"(phase: "start" | "end" | "error")
- ツールイベント =>
agent.waitはwaitForAgentJobを使用:runIdに対するライフサイクル end/error を待機{ status: ok|error|timeout, startedAt, endedAt, error? }を返却
キューイングと並行性
- ランはセッションキー(セッションレーン)ごとにシリアライズされ、オプションでグローバルレーンも通過します。
- これによりツール/セッションの競合を防ぎ、セッション履歴の一貫性を維持します。
- メッセージングチャネルはキューモード(collect/steer/followup)を選択でき、このレーンシステムに投入されます。 コマンドキューを参照してください。
セッション+ワークスペースの準備
- ワークスペースが解決・作成されます。サンドボックス実行ではサンドボックスワークスペースルートにリダイレクトされる場合があります。
- スキルが読み込まれ(またはスナップショットから再利用され)、envとプロンプトに注入されます。
- ブートストラップ/コンテキストファイルが解決され、システムプロンプトレポートに注入されます。
- セッション書き込みロックが取得され、ストリーミング前に
SessionManagerがオープン・準備されます。
プロンプト組み立てとシステムプロンプト
- システムプロンプトは、OpenClawのベースプロンプト、スキルプロンプト、ブートストラップコンテキスト、ラン単位のオーバーライドから構築されます。
- モデル固有の制限やコンパクション予約トークンが適用されます。
- モデルに何が見えるかについてはシステムプロンプトを参照してください。
フックポイント(介入可能な箇所)
OpenClawには2つのフックシステムがあります:
- 内部フック(Gatewayフック): コマンドやライフサイクルイベントに対するイベント駆動スクリプト
- プラグインフック: エージェント/ツールのライフサイクルおよびGatewayパイプライン内の拡張ポイント
内部フック(Gatewayフック)
agent:bootstrap: システムプロンプト確定前のブートストラップファイル構築中に実行。ブートストラップコンテキストファイルの追加・削除に使用します。- コマンドフック:
/new、/reset、/stop、その他のコマンドイベント(Hooksドキュメント参照)。
セットアップと例についてはHooksを参照してください。
プラグインフック(エージェント+Gatewayライフサイクル)
エージェントループまたはGatewayパイプライン内で実行されるフック:
before_model_resolve: セッション前(messagesなし)に実行され、モデル解決前にプロバイダー/モデルを決定的にオーバーライドします。before_prompt_build: セッション読み込み後(messagesあり)に実行され、プロンプト送信前にprependContext、systemPrompt、prependSystemContext、appendSystemContextを注入します。ターンごとの動的テキストにはprependContextを、安定したガイダンスにはシステムコンテキストフィールドを使用してください。before_agent_start: レガシー互換フック。どちらのフェーズでも実行される可能性があります。上記の明示的なフックの使用を推奨します。agent_end: 完了後の最終メッセージリストとランメタデータを検査します。before_compaction/after_compaction: コンパクションサイクルの監視またはアノテーション。before_tool_call/after_tool_call: ツールのパラメータ/結果のインターセプト。tool_result_persist: ツール結果がセッショントランスクリプトに書き込まれる前に同期的に変換します。message_received/message_sending/message_sent: 受信+送信メッセージフック。session_start/session_end: セッションライフサイクルの境界。gateway_start/gateway_stop: Gatewayライフサイクルイベント。
フックAPIと登録の詳細についてはPluginsを参照してください。
ストリーミングと部分応答
- アシスタントのデルタはpi-agent-coreからストリーミングされ、
assistantイベントとして発行されます。 - ブロックストリーミングは
text_endまたはmessage_endのタイミングで部分応答を発行できます。 - 推論ストリーミングは別ストリームとして、またはブロック応答として発行されます。
- チャンキングとブロック応答の動作についてはStreamingを参照してください。
ツール実行とメッセージングツール
- ツールのstart/update/endイベントが
toolストリームで発行されます。 - ツール結果はログ/発行前にサイズと画像ペイロードがサニタイズされます。
- メッセージングツールの送信はトラッキングされ、重複するアシスタント確認を抑制します。
応答の整形と抑制
- 最終ペイロードは以下から組み立てられます:
- アシスタントテキスト(およびオプションの推論)
- インラインツールサマリー(verboseかつ許可されている場合)
- モデルエラー時のアシスタントエラーテキスト
NO_REPLYはサイレントトークンとして扱われ、送信ペイロードからフィルタリングされます。- メッセージングツールの重複は最終ペイロードリストから除去されます。
- レンダリング可能なペイロードが残らずツールがエラーになった場合、フォールバックのツールエラー応答が発行されます(メッセージングツールがすでにユーザーに見える応答を送信済みの場合を除く)。
コンパクションとリトライ
- 自動コンパクションは
compactionストリームイベントを発行し、リトライをトリガーできます。 - リトライ時には、重複出力を避けるためインメモリバッファとツールサマリーがリセットされます。
- コンパクションパイプラインの詳細はCompactionを参照してください。
イベントストリーム(現状)
lifecycle:subscribeEmbeddedPiSessionが発行(フォールバックとしてagentCommandも)assistant: pi-agent-coreからのストリーミングデルタtool: pi-agent-coreからのストリーミングツールイベント
チャットチャネルの処理
- アシスタントのデルタはチャット
deltaメッセージにバッファリングされます。 - ライフサイクル end/error でチャット
finalが発行されます。
タイムアウト
agent.waitのデフォルト: 30秒(待機のみ)。timeoutMsパラメータでオーバーライド可能。- エージェントランタイム:
agents.defaults.timeoutSecondsデフォルト600秒。runEmbeddedPiAgentの中断タイマーで強制。
早期終了が起こりうる箇所
- エージェントタイムアウト(中断)
- AbortSignal(キャンセル)
- Gateway切断またはRPCタイムアウト
agent.waitタイムアウト(待機のみ、エージェントは停止しない)