-
Notifications
You must be signed in to change notification settings - Fork 1.1k
docs: add agent-loop.md explaining the tool-use loop and completion signals #1010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,188 @@ | ||||||||||||||||||||||||||||||
| # The Agent Loop | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| How the Copilot CLI processes a user message end-to-end: from prompt to `session.idle`. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ## Architecture | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ```mermaid | ||||||||||||||||||||||||||||||
| graph LR | ||||||||||||||||||||||||||||||
| App["Your App"] -->|send prompt| SDK["SDK Session"] | ||||||||||||||||||||||||||||||
| SDK -->|JSON-RPC| CLI["Copilot CLI"] | ||||||||||||||||||||||||||||||
| CLI -->|API calls| LLM["LLM"] | ||||||||||||||||||||||||||||||
| LLM -->|response| CLI | ||||||||||||||||||||||||||||||
| CLI -->|events| SDK | ||||||||||||||||||||||||||||||
| SDK -->|events| App | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| The **SDK** is a transport layer — it sends your prompt to the **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 })`, the CLI enters a loop: | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| ```mermaid | ||||||||||||||||||||||||||||||
| flowchart TD | ||||||||||||||||||||||||||||||
| A["User prompt"] --> B["LLM API call\n(= one turn)"] | ||||||||||||||||||||||||||||||
| B --> C{"toolRequests\nin response?"} | ||||||||||||||||||||||||||||||
| C -->|Yes| D["Execute tools\nCollect results"] | ||||||||||||||||||||||||||||||
| D -->|"Results fed back\nas next turn input"| B | ||||||||||||||||||||||||||||||
| C -->|No| E["Final text\nresponse"] | ||||||||||||||||||||||||||||||
| E --> F(["session.idle"]) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| style B fill:#1a1a2e,stroke:#58a6ff,color:#c9d1d9 | ||||||||||||||||||||||||||||||
| style D fill:#1a1a2e,stroke:#3fb950,color:#c9d1d9 | ||||||||||||||||||||||||||||||
| style F fill:#0d1117,stroke:#f0883e,color:#f0883e | ||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| The model sees the **full conversation history** on each call — system prompt, user message, and all prior tool calls and results. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
| The model sees the **full conversation history** on each call — system prompt, user message, and all prior tool calls and results. | |
| On each call, the model sees whatever conversation state the CLI includes in the current context window — typically the system prompt, user message, and prior tool calls and results, but potentially a compacted or summarized version of earlier history if the context window fills. |
Copilot
AI
Apr 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The autopilot “nudge” is presented as an exact quoted synthetic user message. Since this wording is CLI-implementation detail and may change between CLI versions, it’s likely to become stale. Consider marking it explicitly as an example/approximation (or linking to a versioned source) rather than quoting a fixed string.
| In **autopilot mode** (headless/autonomous operation), the CLI actively tracks whether the model has called `task_complete`. If the tool-use loop ends without it, the CLI injects a synthetic user message nudging the model: | |
| > *"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 tool-use loop — the model sees the nudge as a new user message and continues working. The nudge also instructs the model **not** to call `task_complete` prematurely: | |
| In **autopilot mode** (headless/autonomous operation), the CLI actively tracks whether the model has called `task_complete`. If the tool-use loop ends without it, the CLI injects a synthetic user message nudging the model. The exact wording is a CLI implementation detail and may vary by version; conceptually, it looks something like: | |
| > *For example: "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 tool-use loop — the model sees the synthetic follow-up as a new user message and continues working. That follow-up also instructs the model **not** to call `task_complete` prematurely: |
Copilot
AI
Apr 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The “no hidden calls” / “turn pairs == total LLM API calls” claim looks inaccurate: the CLI can make additional LLM calls outside assistant turns (e.g., context compaction is tracked via session.compaction_complete.compactionTokensUsed). Consider scoping this section to assistant response turns only, or update the counting guidance to include other LLM-call sources (compaction, etc.).
| 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. | |
| To inspect turn count for a session: | |
| ```bash | |
| # Count turns in a session's event log | |
| The number of `assistant.turn_start` / `assistant.turn_end` pairs in the event log equals the number of **assistant response turns** in the session. | |
| This is a useful way to count how many times the CLI asked the model to produce an assistant turn, but it is not a complete accounting of every model-related operation in the session. For example, the CLI may perform work outside assistant turns, such as context compaction, so you should not treat turn pairs as the total number of all LLM calls or token-consuming operations. | |
| To inspect assistant turn count for a session: | |
| ```bash | |
| # Count assistant turns in a session's event log |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file appears to be committed with CRLF line endings (visible as
\rin the diff/context), while other docs in this repo use LF. Please normalize this file to LF to avoid noisy diffs and inconsistent formatting across platforms.