注意
Copilot SDK 目前处于公开预览阶段。功能和可用性可能会更改。
自定义代理是可附加到会话的轻量级代理定义。每个代理都有自己的系统提示、工具限制和可选的 MCP 服务器。当用户的请求匹配代理的专长时,Copilot SDK 运行时会自动将其委派为子代理——在隔离的上下文中运行,同时将生命周期事件流式传回父会话。有关委派流程的可视化概览,请参阅 github/copilot-sdk repository。
| 概念 | 描述 |
|---|---|
| 自定义代理 | 具有自定义提示和工具集的具名代理配置 |
| 子代理 | 由运行时调用以处理任务一部分的自定义代理 |
| 推断 | 运行时根据用户意图自动选择代理的能力 |
| 父会话 | 生成子代理的会话;接收所有生命周期事件 |
定义自定义代理
在创建会话时传入 customAgents。至少每个代理需要提供 name 和 prompt。
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
await client.start();
const session = await client.createSession({
model: "gpt-4.1",
customAgents: [
{
name: "researcher",
displayName: "Research Agent",
description: "Explores codebases and answers questions using read-only tools",
tools: ["grep", "glob", "view"],
prompt: "You are a research assistant. Analyze code and answer questions. Do not modify any files.",
},
{
name: "editor",
displayName: "Editor Agent",
description: "Makes targeted code changes",
tools: ["view", "edit", "bash"],
prompt: "You are a code editor. Make minimal, surgical changes to files as requested.",
},
],
onPermissionRequest: async () => ({ kind: "approved" }),
});
有关 Python、Go 和 .NET 的示例,请参阅 github/copilot-sdk 仓库。关于 Java,请参阅 github/copilot-sdk-java 仓库。
配置参考
| 属性 | 类型 | 是否必填 | 描述 |
|---|---|---|---|
name | string | ✅ | 代理的唯一标识符 |
displayName | string | 事件中显示的可读名称 | |
description | string | 代理的功能——帮助运行时进行选择 | |
tools | string[] or null | 代理可使用的工具名称。null 或省略 = 所有工具 | |
prompt | string | ✅ | 代理的系统提示 |
mcpServers | object | 针对该代理的 MCP 服务器配置 | |
infer | boolean | 运行时是否可以自动选择此代理(默认:true) |
提示
良好的 description 有助于运行时将用户意图匹配到正确的代理。请具体说明代理的专长和能力。
除了每个代理的配置外,您还可以在session config 上设置 agent,以预先选择会话启动时激活的自定义代理。
| 会话配置属性 | 类型 | 描述 |
|---|---|---|
agent | string | 会话创建时预先选择的自定义代理名称。必须匹配 customAgents 中的 name。 |
在会话创建时选择代理
您可以在会话配置中传入 agent,以预先选择会话启动时应激活的自定义代理。该值必须匹配 customAgents 中定义的某个代理的 name。
const session = await client.createSession({
customAgents: [
{
name: "researcher",
prompt: "You are a research assistant. Analyze code and answer questions.",
},
{
name: "editor",
prompt: "You are a code editor. Make minimal, surgical changes.",
},
],
agent: "researcher", // Pre-select the researcher agent
});
有关 Python、Go 和 .NET 的示例,请参阅 github/copilot-sdk 仓库。关于 Java,请参阅 github/copilot-sdk-java 仓库。
子代理委托工作原理
当您向包含自定义代理的会话发送提示时,运行时会评估是否委托给子代理。
- 意图匹配—运行时将用户的提示与每个代理的
name和description进行分析 - 代理选择—如果找到匹配且
infer不为false,运行时会选择该代理 - 隔离执行—子代理使用其自己的提示和受限工具集运行
- 事件流式传输—生命周期事件(
subagent.started、subagent.completed等)会流回父会话 - 结果整合—子代理的输出会被合并到父代理的响应中
控制推断
默认情况下,所有自定义代理都可用于自动选择(infer: true)。将 infer: false 设置为阻止运行时自动选择代理——这在仅希望通过明确的用户请求调用的代理中很有用。
{
name: "dangerous-cleanup",
description: "Deletes unused files and dead code",
tools: ["bash", "edit", "view"],
prompt: "You clean up codebases by removing dead code and unused files.",
infer: false, // Only invoked when user explicitly asks for this agent
}
监听子代理事件
子代理运行时,父会话会发出生命周期事件。订阅这些事件以构建可视化代理活动的 UI。
事件类型
| 事件 | 触发时 | 数据 |
|---|---|---|
subagent.selected | 运行时为任务选择了代理 | agentName, agentDisplayName, tools |
subagent.started | 子代理开始执行 | toolCallId, agentName, agentDisplayName, agentDescription |
subagent.completed | 子代理成功完成 | toolCallId, agentName, agentDisplayName |
subagent.failed | 子代理遇到错误 | toolCallId, agentName, agentDisplayName, error |
subagent.deselected | 运行时切换离开子代理 | — |
订阅事件
session.on((event) => {
switch (event.type) {
case "subagent.started":
console.log(`▶ Sub-agent started: ${event.data.agentDisplayName}`);
console.log(` Description: ${event.data.agentDescription}`);
console.log(` Tool call ID: ${event.data.toolCallId}`);
break;
case "subagent.completed":
console.log(`✅ Sub-agent completed: ${event.data.agentDisplayName}`);
break;
case "subagent.failed":
console.log(`❌ Sub-agent failed: ${event.data.agentDisplayName}`);
console.log(` Error: ${event.data.error}`);
break;
case "subagent.selected":
console.log(`🎯 Agent selected: ${event.data.agentDisplayName}`);
console.log(` Tools: ${event.data.tools?.join(", ") ?? "all"}`);
break;
case "subagent.deselected":
console.log("↩ Agent deselected, returning to parent");
break;
}
});
const response = await session.sendAndWait({
prompt: "Research how authentication works in this codebase",
});
有关 Python、Go 和 .NET 的示例,请参阅 github/copilot-sdk 仓库。关于 Java,请参阅 github/copilot-sdk-java 仓库。
构建代理树 UI
子代理事件包含 toolCallId 字段,可帮助您重建执行树。以下是跟踪代理活动的模式。
interface AgentNode {
toolCallId: string;
name: string;
displayName: string;
status: "running" | "completed" | "failed";
error?: string;
startedAt: Date;
completedAt?: Date;
}
const agentTree = new Map<string, AgentNode>();
session.on((event) => {
if (event.type === "subagent.started") {
agentTree.set(event.data.toolCallId, {
toolCallId: event.data.toolCallId,
name: event.data.agentName,
displayName: event.data.agentDisplayName,
status: "running",
startedAt: new Date(event.timestamp),
});
}
if (event.type === "subagent.completed") {
const node = agentTree.get(event.data.toolCallId);
if (node) {
node.status = "completed";
node.completedAt = new Date(event.timestamp);
}
}
if (event.type === "subagent.failed") {
const node = agentTree.get(event.data.toolCallId);
if (node) {
node.status = "failed";
node.error = event.data.error;
node.completedAt = new Date(event.timestamp);
}
}
// Render your UI with the updated tree
renderAgentTree(agentTree);
});
为每个代理限定工具范围
使用 tools 属性来限制代理可以访问的工具。这对于安全性和保持代理专注至关重要。
const session = await client.createSession({
customAgents: [
{
name: "reader",
description: "Read-only exploration of the codebase",
tools: ["grep", "glob", "view"], // No write access
prompt: "You explore and analyze code. Never suggest modifications directly.",
},
{
name: "writer",
description: "Makes code changes",
tools: ["view", "edit", "bash"], // Write access
prompt: "You make precise code changes as instructed.",
},
{
name: "unrestricted",
description: "Full access agent for complex tasks",
tools: null, // All tools available
prompt: "You handle complex multi-step tasks using any available tools.",
},
],
});
注意
当 tools 为 null 或省略时,代理会继承会话上配置的所有工具访问权限。使用显式工具列表以执行最小特权原则。
为代理附加 MCP 服务器
每个自定义代理可以拥有自己的 MCP(模型上下文协议)服务器,从而访问专门的数据源。
const session = await client.createSession({
customAgents: [
{
name: "db-analyst",
description: "Analyzes database schemas and queries",
prompt: "You are a database expert. Use the database MCP server to analyze schemas.",
mcpServers: {
"database": {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-postgres", "postgresql:///mydb"],
},
},
},
],
});
模式和最佳实践
将研究员与编辑器配对
常见模式是定义只读的研究员代理和具备写入能力的编辑器代理。运行时将探索任务委派给研究员,将修改任务委派给编辑器。
customAgents: [
{
name: "researcher",
description: "Analyzes code structure, finds patterns, and answers questions",
tools: ["grep", "glob", "view"],
prompt: "You are a code analyst. Thoroughly explore the codebase to answer questions.",
},
{
name: "implementer",
description: "Implements code changes based on analysis",
tools: ["view", "edit", "bash"],
prompt: "You make minimal, targeted code changes. Always verify changes compile.",
},
]
保持代理描述具体
运行时使用 description 来匹配用户意图。模糊的描述会导致委托不佳。
// ❌ Too vague — runtime can't distinguish from other agents
{ description: "Helps with code" }
// ✅ Specific — runtime knows when to delegate
{ description: "Analyzes Python test coverage and identifies untested code paths" }
优雅地处理失败
子代理可能会失败。始终监听 subagent.failed 事件并在您的应用中处理它们。
session.on((event) => {
if (event.type === "subagent.failed") {
logger.error(`Agent ${event.data.agentName} failed: ${event.data.error}`);
// Show error in UI, retry, or fall back to parent agent
}
});