拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Copilot CLI Agent 扩展编写指南:使用 @github/copilot-sdk 编程式创建扩展

Copilot CLI Agent 扩展编写指南使用 github/copilot-sdk 编程式创建扩展【免费下载链接】copilot-sdkMulti-platform SDK for integrating GitHub Copilot Agent into apps and services项目地址: https://gitcode.com/GitHub_Trending/co/copilot-sdk本指南面向希望在 Copilot CLI 中以编程方式编写扩展的 Agent 与开发者完整讲解从脚手架搭建、工具与钩子注册、会话 API 使用到调试验证的全流程。读完本文你将掌握extensions_manage/extensions_reload工具驱动的工作流、github/copilot-sdk扩展 API 的核心契约工具、钩子、事件、结构化结果并能基于仓库源码理解其底层运行机制写出可稳定运行、可被 Agent 自动复用的 Copilot CLI 扩展。扩展的运行机制总览扩展并非插件库而是以独立 Node.js 子进程形式运行的程序它与 Copilot CLI 通过JSON-RPC over stdio通信。扩展机制文档 将整个生命周期归纳为五个阶段发现DiscoveryCLI 扫描项目.github/extensions/目录与用户级 Copilot 配置扩展目录寻找包含extension.mjs的子目录启动Launch每个扩展被 fork 为子进程github/copilot-sdk通过自动模块解析器直接可用无需手动安装连接Connection扩展调用joinSession()建立到 CLI 的 JSON-RPC 连接并附着到用户当前的前台会话注册Registration会话配置中声明的工具与钩子注册到 CLI立即对 Agent 可见生命周期Lifecycle扩展在/clear或前台会话被替换时重载CLI 退出时停止先 SIGTERM5 秒后 SIGKILL。从源码看joinSession()通过读取process.env.SESSION_ID判断自己是否运行在 CLI 子进程中——若该环境变量缺失会直接抛出错误提示该 API 仅面向 CLI 的扩展子进程见 extension.ts。连接成功后SDK 内部以parent-process方式建立连接并调用resumeSessionForExtension()完成附着。四步工作流Agent 如何编程式编写扩展agent-author.md 给出了一套精确、逐步可执行的参考流程Agent如 Copilot 自身可以完全通过工具调用完成扩展的创建与加载。Step 1脚手架Scaffold调用extensions_manage工具并指定operation: scaffoldextensions_manage({ operation: scaffold, name: my-extension })该操作会在.github/extensions/my-extension/下生成一个带可用骨架的extension.mjs文件。若希望扩展为用户级作用域跨所有仓库持久生效追加location: userextensions_manage({ operation: scaffold, name: my-extension, location: user })Step 2编辑扩展文件使用edit或create工具修改生成的extension.mjs。该文件必须满足三个硬性要求文件名必须为extension.mjs当前仅支持.mjs使用 ES Module 语法import/export必须调用joinSession({ ... })完成会话附着。Step 3重载扩展extensions_reload({})此操作会停止所有正在运行的扩展并重新发现、重新启动它们。重载后新注册的工具在同一轮对话中立即生效即 mid-turn 刷新无需重启 CLI。Step 4验证extensions_manage({ operation: list }) extensions_manage({ operation: inspect, name: my-extension })检查扩展是否成功加载、是否未被标记为failed状态。list用于查看全部扩展inspect用于查看单个扩展的详细加载状态。文件结构与发现规则扩展目录结构固定为.github/extensions/name/extension.mjs发现规则务必遵守否则扩展不会被加载CLI 扫描相对于git 根目录的.github/extensions/目录同时扫描用户 Copilot 配置中的扩展目录仅检查直接子目录不递归每个子目录内必须包含名为extension.mjs的文件项目级扩展在名称冲突时覆盖用户级扩展。最小骨架与 joinSession 解析一个可运行的最小扩展只有几行import { joinSession } from github/copilot-sdk/extension; await joinSession({ tools: [], // 可选 —— 自定义工具 hooks: {}, // 可选 —— 生命周期钩子 });joinSession(config)接受一个JoinSessionConfig见 extension.ts除tools、hooks外还支持onPermissionRequest权限处理、requestedEnvironmentVariables敏感环境变量申请、factoriesAgent Factories 句柄实验性等选项。它返回一个CopilotSession对象可用于发送消息、订阅事件、日志输出与底层 RPC 访问。注册自定义工具工具是 Agent 可调用的函数在joinSession的tools数组中声明tools: [ { name: tool_name, // 必填。必须在所有扩展间全局唯一。 description: What it does, // 必填。会展示给 Agent 的工具描述。 parameters: { // 可选。参数的 JSON Schema。 type: object, properties: { arg1: { type: string, description: ... }, }, required: [arg1], }, handler: async (args, invocation) { // args: 符合 schema 的解析后参数 // invocation.sessionId: 当前会话 ID // invocation.toolCallId: 唯一的工具调用 ID // invocation.toolName: 本工具名称 // // 返回值: string 或 ToolResultObject // string → 视为成功 // { textResultForLlm, resultType } → 结构化结果 // resultType: success | failure | rejected | denied return Result: ${args.arg1}; }, }, ];结构化返回 ToolResultObject除了返回纯字符串handler 还可返回结构化对象。源码 types.ts 定义了完整的ToolResultObject字段类型说明textResultForLlmstring必填喂给大模型的结果文本binaryResultsForLlmToolBinaryResult[]可选图片/资源等二进制结果含data、mimeType、typeresultTypesuccess \| failure \| rejected \| denied \| timeout结果类型errorstring可选错误信息sessionLogstring可选写入会话日志toolTelemetryRecordstring, ...可选工具遥测数据toolReferencesstring[]可选工具搜索工具返回的工具名列表硬性约束工具名必须在所有已加载扩展中全局唯一。冲突会导致后加载的扩展初始化失败handler 必须返回string或{ textResultForLlm: string, resultType?: string }handler 的第二个参数invocation携带sessionId、toolCallId、toolName源码 types.ts 还补充了arguments、traceparent/tracestate、signal等字段向用户展示消息必须使用session.log()切勿使用console.log()stdout 被保留给 JSON-RPC 协议。从源码执行路径看session.tshandler 的返回值会被规范化undefined/null转为空字符串成功结果字符串原样透传合法的ToolResultObject直接透传其他对象则被JSON.stringify若 handler 抛出异常则错误消息会通过 RPC 作为失败结果返回给 CLI。注册生命周期钩子钩子用于在关键生命周期节点拦截与修改行为在hooks对象中注册hooks: { onUserPromptSubmitted: async (input, invocation) { ... }, onPreToolUse: async (input, invocation) { ... }, onPostToolUse: async (input, invocation) { ... }, onPostToolUseFailure: async (input, invocation) { ... }, onSessionStart: async (input, invocation) { ... }, onSessionEnd: async (input, invocation) { ... }, onErrorOccurred: async (input, invocation) { ... }, }所有钩子输入均包含timestampDate类型与workingDirectory。所有处理器都以invocation: { sessionId: string }作为第二个参数。所有处理器均可返回void/undefined表示无操作或一个输出对象。源码中session.ts会将在线上收到的 Unix 毫秒时间戳反序列化为Date并把 wire 层的cwd字段映射为workingDirectory。onUserPromptSubmitted —— 改写或增强用户提示输入{ prompt: string, timestamp, workingDirectory }输出所有字段可选字段类型作用modifiedPromptstring替换用户的提示词additionalContextstring以隐藏上下文追加Agent 可见典型用法是重写提示词、或向每条消息注入团队规范等隐藏指令可参考 examples.md 中的“修改用户消息”“注入额外上下文”示例。onPreToolUse —— 工具执行前拦截输入{ toolName: string, toolArgs: unknown, timestamp, workingDirectory }输出所有字段可选字段类型作用permissionDecisionallow \| deny \| ask覆盖权限检查permissionDecisionReasonstring拒绝时展示给用户的原因modifiedArgsunknown替换工具参数additionalContextstring注入到对话中这是实现安全策略的关键位置例如拦截bash工具中rm -rf等危险命令并返回permissionDecision: deny。onPostToolUse —— 工具成功执行后输入{ toolName: string, toolArgs: unknown, toolResult: ToolResultObject, timestamp, workingDirectory }仅在工具返回成功结果时触发。若要观察非成功结果必须同时注册onPostToolUseFailure。输出所有字段可选字段类型作用modifiedResultToolResultObject替换工具结果additionalContextstring注入到对话中典型用途文件创建/编辑后自动打开编辑器、运行 linter 等副作用。onPostToolUseFailure —— 工具失败后输入{ toolName: string, toolArgs: unknown, error: string, timestamp, workingDirectory }当工具执行结果为failure时触发。此时onPostToolUse不会触发因此注册此处理器可观察或响应失败场景——非常适合遥测、重放缓冲、故障注入测试或原本会因工具失败而漏配的 pre/post 工具配对追踪。注意输入形态与onPostToolUse不同只提供error字符串化的失败消息不提供完整的toolResult。输出所有字段可选字段类型作用additionalContextstring以隐藏指导追加模型将结合失败的工具结果看到注意只有failure结果会触发此钩子。其他非成功resultType值rejected、denied、timeout当前不会触发它。onSessionStart —— 会话启动输入{ source: startup \| resume \| new, initialPrompt?: string, timestamp, workingDirectory }输出所有字段可选字段类型作用additionalContextstring作为初始上下文注入onSessionEnd —— 会话结束输入{ reason: complete \| error \| abort \| timeout \| user_exit, finalMessage?: string, error?: string, timestamp, workingDirectory }输出所有字段可选字段类型作用sessionSummarystring用于会话持久化的摘要cleanupActionsstring[]清理动作描述onErrorOccurred —— 错误处理输入{ error: string, errorContext: model_call \| tool_execution \| system \| user_input, recoverable: boolean, timestamp, workingDirectory }输出所有字段可选字段类型作用errorHandlingretry \| skip \| abort如何处理错误retryCountnumber最大重试次数当errorHandling为retry时userNotificationstring展示给用户的消息典型的错误策略组合可恢复的模型调用错误返回{ errorHandling: retry, retryCount: 2 }其余情况返回{ errorHandling: abort, userNotification: ... }。Session 对象 APIjoinSession()返回的sessionCopilotSession提供以下核心 APIsession.send(options)编程式发送消息await session.send({ prompt: Analyze the test results. }); await session.send({ prompt: Review this file, attachments: [{ type: file, path: ./src/index.ts }], });从源码实现看session.tssend通过session.sendRPC 请求将prompt、source、displayPrompt、attachments、mode、agentMode、requestHeaders等选项传给 CLI并返回响应的messageId。session.sendAndWait(options, timeout?)发送并阻塞直到 Agent 完成解析于session.idle事件const response await session.sendAndWait({ prompt: What is 22? }); // response?.data.content 包含 Agent 的回复源码中该方法默认超时60000mssession.ts超时只控制等待时长、不会中止 Agent 正在进行的任务等待期间已注册的事件处理器仍会正常收到事件。session.log(message, options?)向 CLI 时间线输出日志await session.log(Extension ready); await session.log(Rate limit approaching, { level: warning }); await session.log(Connection failed, { level: error }); await session.log(Processing..., { ephemeral: true }); // 瞬时消息不持久化日志级别支持info默认、warning、errorephemeral: true表示瞬时消息、不会被持久化。这是扩展向用户展示消息的唯一推荐通道。session.on(eventType, handler)订阅会话事件返回取消订阅函数const unsub session.on(tool.execution_complete, (event) { // event.data.success, event.data.result });也支持通配订阅不传事件类型则接收全部事件。源码中 session.ts 实现了双模式注册指定事件类型走类型化 handler 集合通配则走全局 handler 集合两者都会收到完整事件对象。关键事件类型事件关键数据字段assistant.messagecontent,messageIdtool.execution_starttoolCallId,toolName,argumentstool.execution_completetoolCallId,success,result,erroruser.messagecontent,attachments,sourcesession.idleabortedsession.errorerrorType,message,stackpermission.requestedrequestId,permissionRequest.kindsession.shutdownshutdownType,totalPremiumRequestssession.workspacePath会话工作区目录路径包含checkpoints/、plan.md、files/等。若禁用无限会话则为undefined。可用于监听plan.md变化等场景examples.md 提供了完整的 plan 文件监听示例。session.rpc访问所有会话 APImodel、mode、plan、workspace 等的底层类型化 RPC 接口。其类型由代码生成器生成见 generated/rpc.ts通过createSessionRpc基于 JSON-RPC 连接创建session.ts。请求敏感环境变量CLI 会在启动扩展进程前剥离所有敏感环境变量如GITHUB_TOKEN。需要这些变量的扩展必须按名称显式申请import { joinSession } from github/copilot-sdk/extension; const session await joinSession({ requestedEnvironmentVariables: [GITHUB_TOKEN], }); // 获准后值已写入 process.env const token process.env.GITHUB_TOKEN;行为契约源码注释见 extension.tsCLI 会向用户展示扩展名与申请变量清单用户批准后被授予的值在joinSession()resolve 之前写入process.env之后即可读取用户拒绝则joinSession()reject、扩展不加载其工具永远不会到达模型批准按用户所见的确切变量集合记忆后续申请额外变量会再次弹窗未设置或 CLI 不会过滤的变量名不会触发弹窗空列表等价于省略该选项不申请任何变量需要支持扩展环境访问的 Copilot CLI旧版 CLI 会忽略该请求且不授予任何值。仓库测试 extension.test.ts 验证了SESSION_ID缺失时joinSession报错、requestedEnvironmentVariables被正确转发且不会泄漏到会话配置等关键行为。常见坑位Gotchasstdout 保留给 JSON-RPC不要使用console.log()它会破坏协议。向用户展示消息请使用session.log()工具名冲突是致命的若两个扩展注册了相同工具名第二个扩展会初始化失败不要在onUserPromptSubmitted中同步调用session.send()应使用setTimeout(() session.send(...), 0)避免无限循环扩展会在/clear时重载会话间的内存状态会丢失仅支持.mjsTypeScript.ts暂不支持handler 的返回值即工具结果返回undefined发送空成功抛出异常发送包含错误消息的失败。扩展实战与调试建议编写扩展时可以借助 examples.md 中的完整示例注册调用外部 shell 命令/外部 API 的工具、按关键字触发后续消息、拦截危险命令、修改工具参数、文件变更监听fs.watch 事件关联、自动复制回复到剪贴板等均包含可直接复制运行的可执行代码。跨平台时注意用process.platform win32检测 Windows.cmd脚本使用exec()而非execFile()PowerShell 的 stderr 重定向用*1而非21。若需进一步编写可运行的 Agent Factories实验性可参考 factories.md。调试时结合extensions_manage({ operation: list })与inspect确认加载状态用session.log(..., { level: error })输出错误细节即可快速定位问题。【免费下载链接】copilot-sdkMulti-platform SDK for integrating GitHub Copilot Agent into apps and services项目地址: https://gitcode.com/GitHub_Trending/co/copilot-sdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门