Skip to main content

エージェント ループ

Copilot CLI がユーザー メッセージをエンド ツー エンドで処理する方法: プロンプトから session.idle

Architecture

図: 説明されたプロセスを示すグラフ図。

SDK はトランスポート層であり、JSON-RPC 経由でプロンプトを Copilot CLI に送信し、イベントをアプリに表示します。 CLI は、エージェント ツール使用ループを実行するオーケストレーターであり、タスクが完了するまで 1 つ以上の LLM API 呼び出しを行います。

ツール使用ループ

session.send({ prompt })を呼び出すと、CLI はループに入ります。

図: 説明されたプロセスを示すフローチャート。

このモデルでは、各呼び出しの 会話履歴 ( システム プロンプト、ユーザー メッセージ、および以前のすべてのツール呼び出しと結果) が表示されます。

主要な分析情報: このループの各イテレーションは、イベント ログ内の 1 つの assistant.turn_start / assistant.turn_end ペアとして表示される、1 つの LLM API 呼び出しです。 非表示の呼び出しはありません。

ターン — それが何であるか

ターンは、単一の LLM API 呼び出しとその結果です。

  1. CLI は会話履歴を LLM に送信します。
  2. LLM が応答する (場合によってはツール要求あり)
  3. ツールが要求された場合、CLI によって実行されます
  4. assistant.turn_end が送出される

通常、1 つのユーザー メッセージは 複数のターンになります。 たとえば、"X はこのコードベースでどのように機能しますか?" のような質問です。 生成される可能性があります:

回転モデルの動作toolRequests?
1
grepglobを呼び出してコードベースを検索する
✅ はい
2検索結果に基づいて特定のファイルを読み取ります
✅ はい
3より深いコンテキストのためにより多くのファイルを読み取ります
✅ はい
4最終的なテキスト回答を生成します
❌ いいえ → ループが終了する

モデルは、各ターンで、より多くのツールを要求するか、最終的な回答を生成するかを決定します。 各呼び出しでは 、蓄積されたコンテキスト全体 (以前のすべてのツール呼び出しと結果) が表示されるため、十分な情報が得られたかどうかに関する情報に基づいて判断できます。

複数ターンにわたる対話のイベントフロー

図: 説明されたプロセスを示すフローチャート。

各ターンをトリガーするのは誰ですか?

俳優責任
お客様のアプリを使用して最初のプロンプトを送信します。 session.send()
Copilot CLIツール使用ループを実行します。ツールを実行し、結果を次のターンの LLM にフィードします
Llmツールを要求するか (ループを続ける)、または最終的な応答を生成するか (停止) を決定します
SDKイベントをそのまま通します。ループは制御しません

CLI は単に機械的です。つまり、「モデルがツールを要求する → 実行する → もう一度モデルを呼び出す」です。 モデルは、停止するタイミングの意思決定者です。

session.idlesession.task_complete

これらは、非常に異なる保証を持つ 2 つの異なる完了信号です。

session.idle

  • ツール使用ループが終了したときに常に出力されます
  • エフェメラル: ディスクに永続化されず、セッションの再開時に再生されない
  • 意味: "エージェントは処理を停止し、次のメッセージの準備ができています"
  • これを 信頼できる "完了" 信号として使用する

SDK の sendAndWait() メソッドは、このイベントを待機します。

// Blocks until session.idle fires
const response = await session.sendAndWait({ prompt: "Fix the bug" });

session.task_complete

  • 必要に応じて出力: モデルに明示的に通知する必要があります
  • 永続化: ディスク上のセッション イベント ログに保存
  • 意味: "エージェントは、タスク全体が満たされたと見なします"
  • 省略可能な summary フィールドを含む
session.on("session.task_complete", (event) => {
    console.log("Task done:", event.data.summary);
});

自動操縦モード: CLI が task_complete を促す

オートパイロット モード (ヘッドレス/自律操作) では、CLI はモデルが task_complete を呼び出したかどうかをアクティブに追跡します。 ツール使用ループがそれなしで終了した場合、CLI はモデルを微調整する合成ユーザー メッセージを挿入します。

"task_complete ツールを使用して、タスクを完了としてまだマークしていません。計画していた場合は、計画を中止し、実装を開始します。タスクが完全に完了するまでは完了しません。

これにより、ツール使用ループが効果的に再開されます。モデルはナッジを新しいユーザー メッセージとして認識し、動作を続けます。 また、ナッジは、**** を途中で呼び出task_completeモデルに指示します。

  • オープンな質問がある場合は呼び出さないでください。意思決定を行い、作業を続ける
  • エラーが発生した場合は呼び出さないでください。解決してみてください
  • 残りの手順がある場合は呼び出さないでください。最初に完了してください

これにより、オートパイロットに 2 レベルの完了メカニズム が作成されます。

  1. モデルが概要付きでtask_completeを呼び出す → CLI がsession.task_completeを出力する → 完了
  2. モデルがそれを呼び出さずに停止する → CLI が促す → モデルが継続するか、task_complete を呼び出す

task_completeが表示されない理由

対話型モード(通常のチャット)では、CLI はtask_completeの入力を促しません。 モデルはそれを完全にスキップする可能性があります。 一般的な理由:

  • 会話型 Q&A: モデルは質問に回答し、単に停止します。完了する個別の "タスク" はありません
  • モデルの裁量: モデルは、タスク完了シグナルを呼び出さずに最終的なテキスト応答を生成します
  • 中断されたセッション: モデルが完了ポイントに達する前にセッションが終了する

CLI は、セマンティック信号ではなく、機械的なシグナル (ループが終了) であるため、 session.idle を出力します (モデルでは完了と見なされます)。

どちらを使用すべきか

利用シーン信号
"エージェントの処理が完了するまで待ちます"
session.idle
"コーディング タスクがいつ完了したかを把握する"
session.task_complete (ベストエフォート)
"タイムアウト/エラー処理"
session.idle

session.error ✅ |

LLM 呼び出しの数え方

イベント ログ内の assistant.turn_start / assistant.turn_end ペアの数は、LLM API 呼び出しの合計数と同じです。 計画、評価、または完了チェックの非表示の呼び出しはありません。

セッションのターン数を調べるには:

# Count turns in a session's event log
grep -c "assistant.turn_start" ~/.copilot/session-state/<sessionId>/events.jsonl

詳細については、次を参照してください。