Cron、ハートビート、Auto-Reply、フック、サブエージェント
OpenClawが「パーソナルアシスタント」たる最大の特徴は、ユーザーの指示を待たずに 能動的にタスクを実行する能力です。この自律的行動は、5つのサブシステムが 連携することで実現されています。
src/cron/service.ts
完全なジョブスケジューラで、時間ベースの自律的エージェント実行を可能にします。
| 種類 | 説明 | 例 |
|---|---|---|
at | 一回限りの実行(絶対時刻指定) | 「15:00にリマインダー」 |
every | 固定間隔(everyMs + anchorMs) | 「30分ごとにチェック」 |
cron | 標準cron式(タイムゾーン対応) | 0 9 * * *(毎朝9時) |
| モード | 動作 |
|---|---|
| メインセッション | システムイベントテキストをキューに入れ、ハートビートを起動してメインエージェントを呼び出す |
| 分離セッション | 独立したPIエージェントをスポーンし、独自のセッション・ツール・モデルで実行。結果はアナウンス/Webhook/なしで配信 |
| メカニズム | 設定 |
|---|---|
| 指数バックオフ | 30秒 → 1分 → 5分 → 15分 → 60分(連続エラー時) |
| 最小再発火間隔 | 2秒(スピンループ防止) |
| ジョブタイムアウト | 10分(デフォルト) |
| スケジュールエラー上限 | 3回連続でジョブ自動無効化 |
| スタックラン検出 | 2時間で古いrunningマーカーをクリア |
| ワンショット自動無効化 | atジョブは任意の終了状態後に無効化 |
src/auto-reply/heartbeat.ts
HEARTBEAT_OK を返却 → ユーザーには通知されないisHeartbeatContentEffectivelyEmpty(): HEARTBEAT.mdにアクション可能なコンテンツがない場合、API呼び出しをスキップstripHeartbeatToken(): HEARTBEAT_OK応答を検出し、ユーザーへの送信を抑制src/auto-reply/
src/auto-reply/inbound-debounce.ts
チャンネルごとに設定可能なデバウンスで、連続メッセージをバッチ処理します。
src/auto-reply/group-activation.ts
| モード | 動作 |
|---|---|
mention | @メンションされた場合のみ応答 |
always | グループ内の全メッセージに応答 |
| モード | 動作 |
|---|---|
steer | 実行中のエージェントセッションにメッセージを注入 |
followup | 次のターンにキュー |
collect | メッセージをバッチ収集 |
steer-backlog | steerを試行、失敗時にキュー |
interrupt | 現在の処理を中断 |
src/hooks/internal-hooks.ts
| タイプ | 発火タイミング |
|---|---|
agent:bootstrap | エージェント初期化時(ワークスペースDir、ブートストラップファイル、設定を含む) |
gateway:startup | Gateway起動時 |
message:received | 受信メッセージ(from、content、channelId等) |
message:sent | 送信後(to、content、success/error) |
command | コマンド実行時 |
session | セッションイベント |
agent | エージェントイベント |
registerInternalHook(eventKey, handler) — タイプレベル(command)と具体的アクション(command:new)の両方をサポートtriggerInternalHook(event) — タイプレベルと具体的キーの両方のハンドラを発火src/hooks/config.ts
shouldIncludeHook(): 明示的無効化、OS要件、プラットフォームチェック、バイナリ可用性、環境変数、設定パスに基づいてフック実行を制御always: true フラグですべてのチェックをバイパス可能src/agents/subagent-spawn.ts、src/agents/subagent-registry.ts
src/agents/subagent-registry.ts
SubagentRunRecord: runId、childSessionKey、requesterSessionKey、タスク、モデル、タイムアウト、結果、アナウンス状態を追跡lifecycle:start、lifecycle:end、lifecycle:error を監視src/agents/subagent-announce.ts:710-991
steered: アクティブセッションに注入queued: 後で処理するためにキューdirect: Gateway直接呼び出し| メカニズム | 場所 | 目的 |
|---|---|---|
| スポーン深度制限 | subagent-spawn.ts | 無限エージェント生成の防止(デフォルト最大1) |
| エージェントあたり最大子数 | subagent-spawn.ts | 同時子エージェントの制限(デフォルト最大5) |
| エージェント許可リスト | subagent-spawn.ts | スポーン可能エージェントの制御 |
| Cronエラーバックオフ | timer.ts | 指数バックオフ 30秒→60分 |
| Cron自動無効化 | jobs.ts | 3回のスケジュールエラーでジョブ無効化 |
| ジョブタイムアウト | timer.ts | 10分の実行上限 |
| スタック検出 | jobs.ts | 2時間で古いマーカーをクリア |
| アナウンスリトライ上限 | subagent-registry.ts | 最大3回リトライ |
| アナウンス期限 | subagent-registry.ts | 5分で古いアナウンスを強制期限切れ |
| ハートビートスキップ | heartbeat.ts | 空のHEARTBEAT.mdでAPI呼び出しスキップ |
| サブエージェント制約 | subagent-announce.ts | Cron/能動的行動/副次クエスト禁止 |
| デバウンス | inbound-debounce.ts | 連射メッセージ処理の防止 |
| 送信ポリシー | send-policy.ts | 自動応答のallow/denyオーバーライド |
| フックエラー分離 | internal-hooks.ts | ハンドラごとのtry/catchでカスケード障害防止 |