Skip to main content

Understanding the agent loop

Learn how Copilot 命令行界面(CLI) processes a user message end-to-end, from prompt to session.idle.

谁可以使用此功能?

GitHub Copilot SDK 适用于所有 Copilot 计划。

注意

Copilot SDK 当前处于 公开预览. 功能和可用性可能会发生更改。

Architecture

Diagram showing the flow from your app to the SDK session, to the Copilot CLI, to the LLM, and back.

The Copilot SDK is a transport layer—it sends your prompt to Copilot 命令行界面(CLI) over JSON-RPC and surfaces events back to your app. The CLI is the orchestrator that runs the agentic tool-use loop, making one or more LLM API calls until the task is done.

The tool-use loop

When you call session.send({ prompt }), Copilot 命令行界面(CLI) enters a loop:

Diagram of the tool-use loop: prompt to LLM call, tool execution if requested, otherwise session.idle.

The model sees the full conversation history on each call—system prompt, user message, and all prior tool calls and results.

Each iteration of this loop is exactly one LLM API call, visible as one assistant.turn_start / assistant.turn_end pair in the event log. There are no hidden calls.

Turns

A turn is a single LLM API call and its consequences:

  1. Copilot 命令行界面(CLI) sends the conversation history to the LLM
  2. The LLM responds (possibly with tool requests)
  3. If tools were requested, Copilot 命令行界面(CLI) executes them
  4. assistant.turn_end is emitted

A single user message typically results in multiple turns. For example, a question like "how does X work in this codebase?" might produce:

TurnWhat the model doestoolRequests?
1Calls grep and glob to search the codebaseYes
2Reads specific files based on search resultsYes
3Reads more files for deeper contextYes
4Produces the final text answerNo (loop ends)

The model decides on each turn whether to request more tools or produce a final answer. Each call sees the full accumulated context (all prior tool calls and results), so it can make an informed decision about whether it has enough information.

Event flow for a multi-turn interaction

Diagram of three turns in an agent interaction, each with start, message, tool, and end events, ending in session.idle.

Who triggers each turn

ActorResponsibility
Your appSends the initial prompt via session.send()
Copilot 命令行界面(CLI)Runs the tool-use loop—executes tools and feeds results back to the LLM for the next turn
LLMDecides whether to request tools (continue looping) or produce a final response (stop)
Copilot SDKPasses events through; does not control the loop

Copilot 命令行界面(CLI) is purely mechanical: "model asked for tools → execute → call model again." The model is the decision-maker for when to stop.

session.idle vs session.task_complete

These are two different completion signals with very different guarantees.

session.idle

  • Always emitted when the tool-use loop ends
  • Ephemeral: not persisted to disk, not replayed on session resume
  • Means: "the agent has stopped processing and is ready for the next message"
  • Use this as your reliable "done" signal

The Copilot SDK's sendAndWait() method waits for this event:

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

session.task_complete

  • Optionally emitted: requires the model to explicitly signal it
  • Persisted: saved to the session event log on disk
  • Means: "the agent considers the overall task fulfilled"
  • Carries an optional summary field
session.on("session.task_complete", (event) => {
    console.log("Task done:", event.data.summary);
});

Autopilot mode

In autopilot mode (headless or autonomous operation), Copilot 命令行界面(CLI) actively tracks whether the model has called task_complete. If the tool-use loop ends without it, Copilot 命令行界面(CLI) injects a synthetic user message nudging the model to continue working.

This creates a two-level completion mechanism in autopilot:

  1. The model calls task_complete with a summary → Copilot 命令行界面(CLI) emits session.task_complete → done
  2. The model stops without calling it → Copilot 命令行界面(CLI) nudges → model continues or calls task_complete

Why task_complete might not appear

In interactive mode (normal chat), Copilot 命令行界面(CLI) does not nudge for task_complete. The model may skip it entirely. Common reasons:

  • Conversational Q&A: the model answers a question and simply stops—there's no discrete "task" to complete
  • Model discretion: the model produces a final text response without calling the task-complete signal
  • Interrupted sessions: the session ends before the model reaches a completion point

Copilot 命令行界面(CLI) emits session.idle regardless, because it's a mechanical signal (the loop ended), not a semantic one (the model thinks it's done).

Which signal to use

Use caseSignal
Wait for the agent to finish processingsession.idle
Know when a coding task is donesession.task_complete (best-effort)
Timeout and error handlingsession.idle + session.error

Counting LLM calls

The number of assistant.turn_start / assistant.turn_end pairs in the event log equals the total number of LLM API calls made. There are no hidden calls for planning, evaluation, or completion checking.

Further reading