Architecture

SDK 是一个传输层,它通过 JSON-RPC 将提示发送到 Copilot CLI,并将事件呈现回应用。 CLI 是运行智能体工具调用循环的编排器,会持续发起一次或多次 LLM API 调用,直到任务完成。
工具使用循环
调用 session.send({ prompt })时,CLI 将进入循环:

该模型查看每个呼叫 的完整对话历史记录 -系统提示、用户消息以及所有以前的工具调用和结果。
关键见解: 此循环的每个迭代都是一个 LLM API 调用,在事件日志中显示为一 assistant.turn_start / assistant.turn_end 对。 没有隐藏调用。
轮次 - 它们是什么
轮次是一次 LLM API 调用及其产生的后果:
- CLI 将会话历史记录发送到 LLM
- LLM 作出响应(可能包含工具请求)
- 如果请求了工具,CLI 会执行它们
assistant.turn_end被发出
单个用户消息通常会导致 多个轮次。 例如,像“X 在这个代码库中是如何工作的?”这样的问题。 可能会生成:
| 转动 | 模型的作用 | toolRequests? |
|---|---|---|
| 1 | 调用 grep 和 glob 搜索代码库 | |
| ✅ 是的 | ||
| 2 | 基于搜索结果读取特定文件 | |
| ✅ 是的 | ||
| 3 | 阅读更多文件以获取更深入的上下文 | |
| ✅ 是的 | ||
| 4 | 生成最终文本答案 | |
| ❌ 否→循环结束 |
模型决定每个轮次是请求更多工具还是生成最终答案。 每个调用都会看到 完整的累积上下文 (所有以前的工具调用和结果),因此它可以就它是否有足够的信息做出明智的决定。
多轮交互的事件流

每一轮由谁触发?
| Actor | 责任 |
|---|---|
| 你的应用 | 通过 session.send() 发送初始提示 |
| Copilot CLI | 运行工具使用循环 - 执行工具和将结果馈送回 LLM 以供下一轮使用 |
| LLM | 决定是否请求工具(继续循环)或生成最终响应(停止) |
| SDK | 传递事件;不控制循环 |
CLI 纯粹是机械性的:“模型要求工具→再次执行→调用模型。 模型是何时停止的决策者。
session.idle 与 session.task_complete
这些是两个不同的完成信号,有非常不同的保证:
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);
});
Autopilot 模式:CLI 提示 task_complete
在 Autopilot 模式 (无外设/自主操作)中,CLI 会主动跟踪模型是否已调用 task_complete。 如果工具使用循环在没有它的情况下结束,CLI 会注入一条合成的用户消息来提示模型:
“你尚未使用 task_complete 工具将该任务标记为完成。如果你还在规划,就停止规划,开始执行。在你彻底完成该任务之前,都不能算完成。”
这实际上会重启工具调用循环——模型会将这一提示视为一条新的用户消息,并继续执行。 该提示还指示模型不要过早调用task_complete:
- 如果你还有未解决的问题,就不要调用它——先做出决定,继续推进工作
- 如果遇到错误,请不要调用它 - 尝试解决它
- 如果还有剩余步骤,请不要调用它——请先完成这些步骤
这将在 Autopilot 中创建两级完成机制:
- 模型使用摘要调用
task_complete→ CLI 输出session.task_complete→ 完成 - 模型停止而未调用它 → CLI 提示一下 → 模型继续或调用
task_complete
为什么 task_complete 可能未出现
在 交互模式(普通聊天)中,CLI 不会提示 task_complete。 模型可能完全跳过它。 常见原因:
- 对话问答:模型回答问题,只是停止 - 没有离散的“任务”来完成
- 模型自由裁量权:模型在不调用任务完成信号的情况下生成最终文本响应
- 中断的会话:会话在模型到达完成点之前结束
不管怎样,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