Skip to main content

Agent loop

This page explains how Copilot CLI processes a user message end-to-end, from prompt submission to session.idle.

Architecture

The SDK is the transport layer. It sends prompts to Copilot CLI over JSON-RPC and relays events to your app. The CLI runs the agentic tool-use loop and orchestrates one or more LLM API calls until the task is done.

Tool-use loop

When you call session.send({ prompt }), the CLI enters this loop: On every call, the model sees the full conversation history (system prompt, user message, and all prior tool calls and results). Important: One loop iteration exactly matches one LLM API call and appears as one assistant.turn_start / assistant.turn_end pair in the event log. There are no hidden calls.

Multiple tool calls

You can set allowMultipleToolCalls when creating or resuming a session. When you omit it or set it to true, the default behavior applies: the model can request several tools in one response, and the runtime can run their handlers in parallel. Set it to false to ask the provider for at most one tool call per response. This is a hint to the provider, not an execution guarantee. If the provider still returns several calls, the runtime handles all of them with its existing execution policy.

What a turn means

A turn is one LLM API call and its result.
  1. The CLI sends conversation history to the LLM.
  2. The LLM responds, sometimes with tool requests.
  3. If tool requests exist, the CLI executes them.
  4. assistant.turn_end is emitted.
A single user message usually triggers multiple turns. For example, a prompt like “How does X work in this codebase?” often looks like this: On each turn, the model decides whether to continue with tools or finish with a final response.

Event flow across multiple turns

Who starts each turn

CLI behavior is mechanical (“model requests tools → execute tools → call model again”). The model decides when to stop.

session.idle vs session.task_complete

Both are completion signals, but they have different guarantees.

session.idle

  • Always emitted when the tool-use loop ends
  • Ephemeral (not persisted, not replayed on resume)
  • Means: “The agent has stopped processing and is ready for the next message”
  • Use this as your reliable completion signal
For normal requests, sendAndWait() waits for the session.idle event that arrives after the target message starts. A preceding session.idle from a different request is not treated as completion. In Autopilot mode, sendAndWait() waits for session.autopilot_stopped with the target requestId instead of session.idle.

session.task_complete

  • Optional (only emitted if the model explicitly signals it)
  • Persisted in session logs
  • Means: “The agent judged the overall task as complete”
  • Can include an optional summary

Autopilot mode and task_complete

In autopilot mode (headless/autonomous), the CLI tracks whether the model called task_complete. If the loop ends without it, the CLI injects a synthetic user message:
“You have not yet marked the task as complete using the task_complete tool. If you were planning, stop planning and start implementing. You aren’t done until you have fully completed the task.”
This effectively restarts the loop. The model then continues work or calls task_complete. In autopilot, completion is effectively two-stage:
  1. The model calls task_complete (with summary) → CLI emits session.task_complete.
  2. If not called, CLI nudges the model → model continues or calls task_complete.

Why task_complete may be missing

In interactive mode (normal chat), the CLI does not nudge for task_complete. So it may be absent when:
  • The interaction is conversational Q&A without a discrete “task done” state.
  • The model returns final text without calling task_complete.
  • The session ends before reaching completion.
By contrast, session.idle is always emitted as a mechanical loop-end signal.

Which signal to use

Count LLM calls

The number of assistant.turn_start / assistant.turn_end pairs equals total LLM API calls. There are no hidden planning/evaluation calls. Example:
Last modified on November 9, 2026