注意
Copilot SDK 目前处于公开预览阶段。功能和可用性可能会更改。
有两种交互模式允许用户在代理已经工作时发送消息:steering 在回合进行中重定向代理,queueing 则在当前回合完成后,将消息缓冲起来按顺序(先进先出(FIFO))处理。
当会话正在积极处理一个回合时,传入的消息可以通过 MessageOptions 上的 mode 字段以两种模式之一进行投递。
| 模式 | 行为 | 使用场景 |
|---|---|---|
"immediate"(steering) | 注入到 当前 LLM 回合中 | "Actually, don't create that file—use a different approach" |
"enqueue"(queueing) | 在当前回合结束后 排队并处理 | "After this, also fix the tests" |
有关 steering 与 queueing 流程的时序图,请参阅 github/copilot-sdk 仓库。
Steering(即时模式)
Steering 发送的消息会直接注入到代理当前的回合中。代理实时看到该消息并相应地调整其响应——这对于在不中止回合的情况下进行方向校正非常有用。
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
await client.start();
const session = await client.createSession({
model: "gpt-4.1",
onPermissionRequest: async () => ({ kind: "approved" }),
});
// Start a long-running task
const msgId = await session.send({
prompt: "Refactor the authentication module to use sessions",
});
// While the agent is working, steer it
await session.send({
prompt: "Actually, use JWT tokens instead of sessions",
mode: "immediate",
});
关于 Python、Go 和 .NET 的示例,请参阅 github/copilot-sdk 仓库。Java 示例请参阅 github/copilot-sdk-java 仓库。
Steering 的内部工作原理
- 该消息被添加到运行时的
ImmediatePromptProcessor队列中。 - 在当前回合的下一个 LLM 请求之前,处理器会将该消息注入对话中。
- 代理将 steering 消息视为新的用户消息并调整其响应。
- 如果回合在 steering 消息处理之前完成,它会自动移至常规队列,等待下一个回合。
注意
Steering 消息在当前回合内以尽力而为的方式处理。如果代理已经提交了工具调用,steering 会在该调用完成后生效,但仍然在同一回合内。
Queueing(入队模式)
Queueing 将消息缓冲,以在当前回合结束后顺序处理。每条排队的消息都会启动其自己的完整回合。这是默认模式——如果省略 mode,SDK 将使用 "enqueue"。
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
await client.start();
const session = await client.createSession({
model: "gpt-4.1",
onPermissionRequest: async () => ({ kind: "approved" }),
});
// Send an initial task
await session.send({ prompt: "Set up the project structure" });
// Queue follow-up tasks while the agent is busy
await session.send({
prompt: "Add unit tests for the auth module",
mode: "enqueue",
});
await session.send({
prompt: "Update the README with setup instructions",
mode: "enqueue",
});
// Messages are processed in FIFO order after each turn completes
关于 Python、Go 和 .NET 的示例,请参阅 github/copilot-sdk 仓库。Java 示例请参阅 github/copilot-sdk-java 仓库。
Queueing 的内部工作原理
- 该消息作为
QueuedItem被添加到会话的itemQueue中。 - 当当前回合完成且会话进入空闲状态时,
processQueuedItems()将运行。 - 项目按 FIFO 顺序出队——每条消息都会触发一次完整的代理回合。
- 如果回合结束时有 pending 的 steering 消息,它会被移动到队列前端。
- 处理将持续进行,直至队列为空,此后会话会发出空闲事件。
组合 Steering 与 Queueing
可以在同一会话中同时使用这两种模式。Steering 影响当前回合,而排队的消息则等待它们各自的回合。
const session = await client.createSession({
model: "gpt-4.1",
onPermissionRequest: async () => ({ kind: "approved" }),
});
// Start a task
await session.send({ prompt: "Refactor the database layer" });
// Steer the current work
await session.send({
prompt: "Make sure to keep backwards compatibility with the v1 API",
mode: "immediate",
});
// Queue a follow-up for after this turn
await session.send({
prompt: "Now add migration scripts for the schema changes",
mode: "enqueue",
});
以下是 Python 示例,请参阅 github/copilot-sdk 仓库。Java 示例请参阅 github/copilot-sdk-java 仓库。
在 Steering 与 Queueing 之间的选择
| 情形 | 模式 | 为什么 |
|---|---|---|
| 代理走上了错误的路径 | Steering | 在不丢失进度的情况下重定向当前回合 |
| 你想到了一件代理也应该做的事 | Queueing | 不干扰当前工作;随即在之后执行 |
| 代理即将犯错 | Steering | 在错误提交前进行干预 |
| 你想要串联多个任务 | Queueing | FIFO 顺序确保可预测的执行 |
| 你想为当前任务添加上下文 | Steering | 代理将其纳入当前推理中 |
| 你想批量处理不相关的请求 | Queueing | 每个请求都有自己的完整回合和干净的上下文 |
使用 Steering 与 Queueing 构建 UI
以下是构建支持两种模式的交互式 UI 的模式示例
import { CopilotClient, CopilotSession } from "@github/copilot-sdk";
interface PendingMessage {
prompt: string;
mode: "immediate" | "enqueue";
sentAt: Date;
}
class InteractiveChat {
private session: CopilotSession;
private isProcessing = false;
private pendingMessages: PendingMessage[] = [];
constructor(session: CopilotSession) {
this.session = session;
session.on((event) => {
if (event.type === "session.idle") {
this.isProcessing = false;
this.onIdle();
}
if (event.type === "assistant.message") {
this.renderMessage(event);
}
});
}
async sendMessage(prompt: string): Promise<void> {
if (!this.isProcessing) {
this.isProcessing = true;
await this.session.send({ prompt });
return;
}
// Session is busy — let the user choose how to deliver
// Your UI would present this choice (e.g., buttons, keyboard shortcuts)
}
async steer(prompt: string): Promise<void> {
this.pendingMessages.push({
prompt,
mode: "immediate",
sentAt: new Date(),
});
await this.session.send({ prompt, mode: "immediate" });
}
async enqueue(prompt: string): Promise<void> {
this.pendingMessages.push({
prompt,
mode: "enqueue",
sentAt: new Date(),
});
await this.session.send({ prompt, mode: "enqueue" });
}
private onIdle(): void {
this.pendingMessages = [];
// Update UI to show session is ready for new input
}
private renderMessage(event: unknown): void {
// Render assistant message in your UI
}
}
API 参考
您可以使用 Copilot SDK 会话 API 对会话进行 steering 与 queueing。
MessageOptions
| 语言 | 字段 | 类型 | 默认值 | 描述 |
|---|---|---|---|---|
| Node.js | mode | "enqueue" | "immediate" | "enqueue" | 消息投递模式 |
| Python | mode | Literal["enqueue", "immediate"] | "enqueue" | 消息投递模式 |
| Go | 模式 | string | "enqueue" | 消息投递模式 |
| .NET | 模式 | string? | "enqueue" | 消息投递模式 |
投递模式
| 模式 | 效果 | 在活跃回合期间 | 在空闲期间 |
|---|---|---|---|
"enqueue" | 排队等待下一个回合 | 在 FIFO 队列中等待 | 立即启动新回合 |
"immediate" | 注入到当前回合 | 在下一个 LLM 调用前注入 | 立即启动新回合 |
注意
当会话处于空闲(未处理)状态时,两种模式表现相同——消息会立即启动新回合。
最佳实践
- 默认使用 queueing——对大多数消息使用
"enqueue"(或省略mode)。这种方式可预测且不会冒险中断正在进行的工作。 - 将 steering 留给纠正使用——当代理正在执行错误操作且需要在其进一步进行之前进行重定向时,使用
"immediate"。 - 保持 steering 消息简洁——代理需要快速理解方向校正。过长或复杂的 steering 消息可能会扰乱当前上下文。
- 避免过度 steering——频繁的快速 steering 消息会降低回合质量。如果需要显著改变方向,考虑中止当前回合并重新开始。
- 在 UI 中显示队列状态——展示排队消息的数量,让用户了解待处理内容。监听空闲事件以清除显示。
- 处理 steering 转为 queue 的回退情况——如果在回合完成后收到 steering 消息,它会自动转入队列。请在 UI 设计中体现此转变。