ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

VS Code Copilot Chat Sessions Provider 深度解析:Agent 会话如何统一到 Sessions 门面架构

VS Code Copilot Chat Sessions Provider 深度解析:Agent 会话如何统一到 Sessions 门面架构 VS Code Copilot Chat Sessions Provider 深度解析Agent 会话如何统一到 Sessions 门面架构【免费下载链接】vscodeVisual Studio Code项目地址: https://gitcode.com/GitHub_Trending/vscode6/vscodeCopilot Chat Sessions Providerdefault-copilot是 VS Code Sessions 会话体系把既有 Copilot Agent 会话基建适配进统一ISessionsProvider契约的桥接层。本文以其规范文档 COPILOT_CHAT_SESSIONS_PROVIDER.md 为主体骨架结合同目录源码、注册入口与测试讲清注册身份、草稿与既有会话两类实现、请求生命周期、选择器贡献、删除归档以及该规范的变更门禁。读完你能掌握一条独立会话 provider 在该架构下需要遵守的身份、缓存、生命周期与契约边界。文档定位一份带规范变更门禁的设计规约文件开头的声明决定了本文档的写法和使用方式Specification change gate:Do not update this document for provider bug fixes, option details, picker behavior, or timing. Update it only when provider ownership, identity, cache semantics, or request lifecycle changes.即这不是操作手册而是一份架构契约它只应随 provider 的属主权ownership、身份identity、缓存语义cache semantics或请求生命周期request lifecycle的变化而更新具体选项细节、picker 行为、超时值与 bug 修复叙述都属于代码与针对性测试的范畴不应回流进文档。这与文档结尾 Change policy 一节前后呼应写作与审阅此组件时应把这条门禁当作最低门槛。Scope把 Copilot Agent 会话基建适配进 Sessions 契约CopilotChatSessionsProvider的目标不是另起炉灶实现一套会话而是适配adapts将既有的 Copilot agent-session 基础设施位于 src/vs/workbench/contrib/chat/browser/agentSessions 的IAgentSessionsService、IAgentSession、AgentSessionProviders等包装成 Sessions 层消费的ISessionsProvider接口。它支持两类会话来源Copilot Cloud云端 agent 会话即CopilotCloudSessionTypeid 为copilot-cloud-agent见 copilotChatSessionsProvider.ts本地 Copilot CLI仅当 Agent Host 运行时不可用时才启用本地路径代码里对应_isCopilotCliAvailable()检查agentHostEnablementService.enabled的反向值见同文件 L1507-L1509。ISessionsProvider本身被定义为封装一个计算环境compute environment负责工作区发现、会话创建、会话列举与 picker 贡献一个 provider 可服务多种 session type多个 provider 实例也可服务同一种 session type例如每个远程 Agent Host 一个。该接口的完整契约定义在 sessionsProvider.ts。注册与身份Registration and identity规范明确工作台恢复之后after workbench restorationDefaultSessionsProviderContribution只注册这一个 provider。落地代码在 copilotChatSessions.contribution.ts以WorkbenchPhase.AfterRestored阶段创建CopilotChatSessionsProvider实例并调用sessionsProvidersService.registerProvider(provider)。该 provider 的身份契约如下表PropertyContractProvider IDdefault-copilot源码常量COPILOT_PROVIDER_IDL168LabelCopilot ChatCloud session type可用时始终对外广告Local CLI session type仅当 Agent Host 不拥有它时才广告源码侧的证据sessionTypesgetter 总是把 Cloud 类型追加进列表而 CLI 类型CopilotCLISessionTypeidcopilotcli、label Copilot、支持 worktree 配置见 baseAgentHostSessionsProvider.ts只在 Agent Host enablement 被关闭时出现L1433-L1440。按工作区 URI 精确选择getSessionTypes(workspaceUri)对github-remote-file://GITHUB_REMOTE_FILE_SCHEME工作区只返回 Cloud 类型本地file://工作区则返回可用的CLI 类型L1581-L1590。工作区 URI scheme 直接决定采用哪一份草稿实现。provider 可暴露本地文件夹local-folder与远程仓库remote-repository浏览动作构造函数里注册了Repository...、Issue...、Pull Request...三个 browse action均落在 GitHub 工作区组并声明supportsLocalWorkspaces trueL1543-L1568。底层命令是github.copilot.chat.cloudSessions.openRepository/openIssue/openPullRequest。关于身份还有一个贯穿全局的细节会话唯一 ID 使用providerId:resourceUri格式由toSessionId()统一生成见 session.tsprovider 的多个缓存会话适配器缓存、分组缓存都以 resource 身份为键这为元数据变化但身份不变提供了前提。草稿Drafts本地与云端实现同一份 ISession 契约规范指出本地草稿与云端草稿实现同一份ISession契约契约定义在 session.ts只是适配不同的后端选项本地草稿CopilotCLISessionL230 起负责解析仓库与本地执行配置。构造函数里异步打开 Git 仓库、加载分支过滤掉copilot-worktree-前缀的 agent 内部分支、解析默认分支并处理isolation 模式的选择与记忆worktree/workspace两种把选择存入sessions.isolationPicker.selectedMode存储键。当仓库没有 HEAD commit空仓库或无法打开时自动回退到workspace模式。发送时getAgentHostSessionConfig()把isolation、branch及用户的git.branchPrefix、git.worktreeIncludeFiles配置转译为 Agent Host 的 session config。云端草稿RemoteNewSessionL598 起暴露 provider 声明的 option groupmodels、repositories等与远端 workspace 元数据。其可见性还受when上下文约束_isOptionGroupVisible用ContextKeyExpr.deserialize(group.when)计算并会把是否使用 GitHub 托管 sandbox选择持久化到sessions.cloudSandboxPicker.useSandbox。两者都对外暴露可观察IObservable的 loading、workspace、model、mode、capabilities 等状态供共享的新会话 UI 消费共享 UI 只依赖这些契约字段不按草稿类分支写逻辑。例如buildChatFromSession()从草稿组装出IChat快照并种入mainChat可观察量L189-L207。既有会话Existing sessionsAgentSessionAdapter 门面对已经提交committed的 agent 会话AgentSessionAdapterL925 起把它投影成一个稳定的ISession门面。要点初始化时从IAgentSession抽取 title、status、file changes、checkpoints、description、GitHub 信息等并以独立可观察量承载update()方法在一个**事务transaction**里批量刷新这些值配合setIfChanged与各类相等比较器sessionWorkspaceEqual、sessionFileChangesEqual、gitHubInfoEqual、structuralEquals、dateEquals等只有当真实变化时才触发通知。资源身份在元数据变化期间保持不变——门面被缓存于以 resource URI 字符串为键的_sessionCacheL1451-L1452。后台 agent 会话列表刷新时_refreshSessionCacheL3016既有 adapter 被update()复用新增/消失/变化则相应发出 added / removed / changed 目录通知当多聊天分组开启时还有专门的 replacement 语义与组内某聊天被删除但组仍存在的降级处理_refreshSessionCacheMultiChatL3105。Provider 相关的元数据翻译留在 adapter 内部包括仓库/工作树解析_buildWorkspace、GitHub owner/repo 提取支持metadata.owner/name、repositoryNwo、github-remote-fileURI 三种来源、Pull Request 编号探测与图标状态展示。adapter 同时把 workspace 划分到本地组SESSION_WORKSPACE_GROUP_LOCAL或 GitHub 组SESSION_WORKSPACE_GROUP_GITHUB。共享 Sessions 代码只消费 provider 中立的 workspace、changes、status 与 GitHub 信息。关于多聊天的开关是配置项sessions.github.copilot.multiChatSessions常量COPILOT_MULTI_CHAT_SETTING默认为true、标记为 preview注册于同一 contribution 文件L16-L26。开启后provider 依据sessionParentId元数据草稿阶段则是parentSessionIdoption把多个 chat 归并为会话组_chatToSession再从组内主 chat 构建对外ISession并通过 capabilitysupportsMultipleChats通告能力。请求生命周期创建与发送严格分离规范给出了核心的流程分层createNewChat - return the provider chat resource - Sessions presents the chat sendRequest - send through the backing chat service - commit or update the session - publish replacement when draft identity changes源码中的关键落点创建createNewSession(workspaceUri, sessionTypeId)先用resolveWorkspace解析工作区再按 scheme 创建CopilotCLISession或RemoteNewSessionresource 采用untitled-uuid形式的临时 URIL1654-L1678。createQuickChat/forkChat/createSideChat明确抛错——本 provider 是工作区绑定的不支持这些形态。发送sendRequest区分新会话首条请求与既有 chat 请求。首条请求走_sendFirstChat立即把临时会话放入缓存并广播 added随后构建IChatSendRequestOptions携带用户选择的模型、mode、permission level、agentHostSessionConfig等经chatService.sendRequest投递给底层 chat 服务。已提交会话则走_sendExistingChat对着自己既有的 chat resource 发送不会再创建新资源。提交与替换临时untitledresource 在首条请求后提交为正式 resource。_waitForCommittedSession通过监听IChatSessionsService.onDidCommitSession事件等待提交结果——默认与响应完成竞争5 秒兜底云端会话因需确认往返与网络委派而标记deferred改用 5 分钟的超时L2622-L2682。提交后用_waitForSessionInCache30 秒上限等 adapter 进入缓存最后以_onDidReplaceSession.fire({ from: 临时会话, to: 提交会话 })发布草稿身份变化时的替换事件。进行中的提交还受_inFlightCommits保护避免并发刷新误删L1454-L1461。取消与失败若responseCreatedPromise报告取消则抛CancellationError会话回到 Completed 并保留供用户查看若请求被拒或出现意外错误则清理临时会话并广播 removed。云端新会话还可选择走 GitHub 托管 sandbox_sendFirstChatToSandbox先provisionSession把用户在 composer 中选择的模型带到沙箱_carryModelToSandbox等待模型目录最长 5 秒并在跨 provider 切换时也通过onDidReplaceSession发布替换L2171-L2214。规范强调两条边界provider 从不直接打开 chat UI——展示与聚焦归ISessionsService所有多聊天创建受 capability 门控并遵循共享管理生命周期createNewChat在非多聊天模式下会拒绝额外创建。选择器贡献Picker contributionsprovider 特有的新会话控件通过共享 Sessions 菜单与作用域化的 picker 服务注入。一个 picker contribution 由三部分构成带 provider 中立 enablement 的菜单 action一个 action view item一个作用域化的 widget / controller。实例集中在 copilotChatSessionsActions.tssessions.defaultCopilot.branchPicker、sandboxPicker、modePicker、permissionPicker等 action 分别挂到Menus.NewSessionRepositoryConfig、Menus.NewSessionConfig、Menus.NewSessionControl菜单并用when上下文约束到正确的会话类型与 provider。这些上下文由SessionTypeContext、SessionProviderIdContext、SessionHasGitRepositoryContext、IsNewChatSessionContext、ChatContextKeys.enabled组合而成例如 Cloud 会话才显示 Sandbox pickerCLI 会话才显示 Branch/Mode/Permissions。PickerActionViewItem把独立 picker widget 包装成BaseActionViewItem供菜单工具栏渲染。作用域 widget/controller 本身位于同目录的 modePicker.tsModePicker/ModePickerModel、permissionPicker.ts、branchPicker.ts、sandboxPicker.ts另有面向 Web 端的 mobilePermissionPicker.contribution.ts 复用同一包装器。关于模型选择规范强调了两条设计纪律模型选择策略与 Workbench Chat 共享。本 provider 只负责供给模型快照getModelsSnapshot、呈现选项getModelPickerOptions与写入选择setModel云端模型的元数据由扩展宿主下发的modelsoption group 合成_toSyntheticModel不实现第二套优先级策略。上下文键从作用域化的会话与 provider capabilities 派生在其它会话 surface 里被调用的 action 不得读取窗口全局的 active session。contextkey文件位于 src/vs/sessions/common/contextkeys.ts。删除与归档Deletion and archive删除、归档、重命名与已读状态操作都委托给底层的 agent 会话基础设施provider 只做编排归档/取消归档对未提交NEW/untitled会话直接调用草稿的setArchived并广播 changed因为其 agent-host 条目是Local类型会被缓存刷新过滤直接走agentSession.setArchived无法回流到 UI对已提交会话则委托_findAgentSession找到的 agent sessionL1896-L1930。已读状态分组会话的已读状态要跨组内所有 chat 聚合因此setSessionReadState先取整组 chat 逐个更新L1932-L1944。删除deleteSession/deleteSessions会先收集主会话及其组内成员再统一删除单个 chat 的删除deleteChat在仅剩一个 chat 时退化为删除整组多 chat 时先删底层 agent session 并在确认对话框deleteChat.confirm通过后执行skipConfirmation选项供丢弃临时草稿这类场景使用L1946-L2075。底层删除按类型分派CLI 会话执行agents.github.copilot.cli.deleteSessionsCloud 会话调用chatService.removeHistoryEntry。重命名仅 Copilot CLI 后端暴露github.copilot.cli.sessions.setTitle命令其余类型直接抛不支持因此ISessionCapabilities.supportsRename/supportsDelete也只对 CLI 会话为真L3421-L3431。provider 特有的确认元数据由操作负载operation payload携带共享服务不会下探到扩展宿主的内部实现保持层间解耦。测试与共享生命周期覆盖的划分规范给出一条清晰的测试职责边界provider 自身的测试只负责本地/云端具体 option 行为、提交时序、元数据翻译与回归共享的 provider 生命周期行为则由 Sessions 管理测试覆盖。对应地该目录维护了一批聚焦的测试copilotChatSessionsProvider.test.ts——provider 主体行为branchPicker.test.ts、modePicker.test.ts、permissionPicker.test.ts、sandboxPicker.test.ts——各作用域 picker。provider 代码里也为此保留了显式测试缝隙test seam例如_getCloudSandboxContribution()与_sandboxModelWaitMsL2151-L2159让测试不必真的等待 5 秒沙箱模型超时或依赖全局注册表。Change policy这份文档什么时候该动作为收尾规范要求维护者仅当以下维度之一发生变化时才更新本文档provider 属主权ownership会话/草稿身份identity语义草稿类draft classes结构缓存cache语义请求生命周期request lifecycle。而 picker 细节、选项列表、超时值与 bug 叙事应留在代码与聚焦测试中正如上文在请求生命周期、模型快照、沙箱等待超时等处看到的那样——它们都以源码注释与测试的形式沉淀而不是写在 spec 里。【免费下载链接】vscodeVisual Studio Code项目地址: https://gitcode.com/GitHub_Trending/vscode6/vscode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进