VS Code Copilot Chat Sessions Provider 深度解析:Agent 会话如何统一到 Sessions 门面架构
2026/9/8 22:29:33 网站建设 项目流程

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

【免费下载链接】vscodeVisual Studio Code项目地址: https://gitcode.com/GitHub_Trending/vscode6/vscode

Copilot Chat Sessions Provider(default-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 的IAgentSessionsServiceIAgentSessionAgentSessionProviders等)包装成 Sessions 层消费的ISessionsProvider接口。

它支持两类会话来源:

  • Copilot Cloud:云端 agent 会话,即CopilotCloudSessionType(id 为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 restoration),DefaultSessionsProviderContribution只注册这一个 provider。落地代码在 copilotChatSessions.contribution.ts:以WorkbenchPhase.AfterRestored阶段创建CopilotChatSessionsProvider实例并调用sessionsProvidersService.registerProvider(provider)

该 provider 的身份契约如下表:

PropertyContract
Provider IDdefault-copilot(源码常量COPILOT_PROVIDER_ID,L168)
LabelCopilot Chat
Cloud session type可用时始终对外广告
Local CLI session type仅当 Agent Host 不拥有它时才广告

源码侧的证据:

  • sessionTypesgetter 总是把 Cloud 类型追加进列表,而 CLI 类型(CopilotCLISessionType,idcopilotcli、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 = true(L1543-L1568)。底层命令是github.copilot.chat.cloudSessions.openRepository/openIssue/openPullRequest

关于"身份"还有一个贯穿全局的细节:会话唯一 ID 使用providerId:resourceUri格式,由toSessionId()统一生成(见 session.ts);provider 的多个缓存(会话适配器缓存、分组缓存)都以 resource 身份为键,这为"元数据变化但身份不变"提供了前提。

草稿(Drafts):本地与云端实现同一份 ISession 契约

规范指出:本地草稿与云端草稿实现同一份ISession契约(契约定义在 session.ts),只是适配不同的后端选项:

  • 本地草稿CopilotCLISession(L230 起)负责解析仓库与本地执行配置。构造函数里异步打开 Git 仓库、加载分支(过滤掉copilot-worktree-前缀的 agent 内部分支)、解析默认分支,并处理isolation 模式的选择与记忆(worktree/workspace两种,把选择存入sessions.isolationPicker.selectedMode存储键)。当仓库没有 HEAD commit(空仓库)或无法打开时自动回退到workspace模式。发送时getAgentHostSessionConfig()isolationbranch及用户的git.branchPrefixgit.worktreeIncludeFiles配置转译为 Agent Host 的 session config。
  • 云端草稿RemoteNewSession(L598 起)暴露 provider 声明的 option group(modelsrepositories等)与远端 workspace 元数据。其可见性还受when上下文约束(_isOptionGroupVisibleContextKeyExpr.deserialize(group.when)计算),并会把"是否使用 GitHub 托管 sandbox"选择持久化到sessions.cloudSandboxPicker.useSandbox

两者都对外暴露可观察IObservable)的 loading、workspace、model、mode、capabilities 等状态,供共享的新会话 UI 消费;共享 UI 只依赖这些契约字段,不按草稿类分支写逻辑。例如buildChatFromSession()从草稿组装出IChat快照并种入mainChat可观察量(L189-L207)。

既有会话(Existing sessions):AgentSessionAdapter 门面

对已经提交(committed)的 agent 会话,AgentSessionAdapter(L925 起)把它投影成一个稳定的ISession门面。要点:

  • 初始化时从IAgentSession抽取 title、status、file changes、checkpoints、description、GitHub 信息等,并以独立可观察量承载;update()方法在一个**事务(transaction)**里批量刷新这些值,配合setIfChanged与各类相等比较器(sessionWorkspaceEqualsessionFileChangesEqualgitHubInfoEqualstructuralEqualsdateEquals等),只有当真实变化时才触发通知。
  • 资源身份在元数据变化期间保持不变——门面被缓存于以 resource URI 字符串为键的_sessionCache(L1451-L1452)。后台 agent 会话列表刷新时(_refreshSessionCache,L3016),既有 adapter 被update()复用;新增/消失/变化则相应发出 added / removed / changed 目录通知;当多聊天分组开启时,还有专门的 replacement 语义与"组内某聊天被删除但组仍存在"的降级处理(_refreshSessionCacheMultiChat,L3105)。
  • Provider 相关的元数据翻译留在 adapter 内部:包括仓库/工作树解析(_buildWorkspace)、GitHub owner/repo 提取(支持metadata.owner/namerepositoryNwogithub-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 创建CopilotCLISessionRemoteNewSession,resource 采用untitled-<uuid>形式的临时 URI(L1654-L1678)。createQuickChat/forkChat/createSideChat明确抛错——本 provider 是工作区绑定的,不支持这些形态。
  • 发送sendRequest区分"新会话首条请求"与"既有 chat 请求"。首条请求走_sendFirstChat:立即把临时会话放入缓存并广播 added,随后构建IChatSendRequestOptions(携带用户选择的模型、mode、permission level、agentHostSessionConfig等),经chatService.sendRequest投递给底层 chat 服务。已提交会话则走_sendExistingChat对着自己既有的 chat resource 发送,不会再创建新资源。
  • 提交与替换:临时(untitled)resource 在首条请求后提交为正式 resource。_waitForCommittedSession通过监听IChatSessionsService.onDidCommitSession事件等待提交结果——默认与"响应完成"竞争,5 秒兜底;云端会话因需确认往返与网络委派而标记deferred,改用 5 分钟的超时(L2622-L2682)。提交后用_waitForSessionInCache(30 秒上限)等 adapter 进入缓存,最后以_onDidReplaceSession.fire({ from: 临时会话, to: 提交会话 })发布草稿身份变化时的替换事件。进行中的提交还受_inFlightCommits保护,避免并发刷新误删(L1454-L1461)。
  • 取消与失败:若responseCreatedPromise报告取消,则抛CancellationError,会话回到 Completed 并保留供用户查看;若请求被拒或出现意外错误,则清理临时会话并广播 removed。
  • 云端新会话还可选择走 GitHub 托管 sandbox:_sendFirstChatToSandboxprovisionSession,把用户在 composer 中选择的模型带到沙箱(_carryModelToSandbox,等待模型目录最长 5 秒),并在跨 provider 切换时也通过onDidReplaceSession发布替换(L2171-L2214)。

规范强调两条边界:provider 从不直接打开 chat UI——展示与聚焦归ISessionsService所有;多聊天创建受 capability 门控,并遵循共享管理生命周期(createNewChat在非多聊天模式下会拒绝额外创建)。

选择器贡献(Picker contributions)

provider 特有的新会话控件通过共享 Sessions 菜单与作用域化的 picker 服务注入。一个 picker contribution 由三部分构成:

  1. 带 provider 中立 enablement 的菜单 action
  2. 一个 action view item
  3. 一个作用域化的 widget / controller

实例集中在 copilotChatSessionsActions.ts:sessions.defaultCopilot.branchPickersandboxPickermodePickerpermissionPicker等 action 分别挂到Menus.NewSessionRepositoryConfigMenus.NewSessionConfigMenus.NewSessionControl菜单,并用when上下文约束到正确的会话类型与 provider。这些上下文由SessionTypeContextSessionProviderIdContextSessionHasGitRepositoryContextIsNewChatSessionContextChatContextKeys.enabled组合而成(例如 Cloud 会话才显示 Sandbox picker,CLI 会话才显示 Branch/Mode/Permissions)。PickerActionViewItem把独立 picker widget 包装成BaseActionViewItem供菜单工具栏渲染。

作用域 widget/controller 本身位于同目录的 modePicker.ts(ModePicker/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 session(L1896-L1930)。
  • 已读状态:分组会话的已读状态要跨组内所有 chat 聚合,因此setSessionReadState先取整组 chat 逐个更新(L1932-L1944)。
  • 删除deleteSession/deleteSessions会先收集主会话及其组内成员再统一删除;单个 chat 的删除(deleteChat)在仅剩一个 chat 时退化为删除整组,多 chat 时先删底层 agent session 并在确认对话框(deleteChat.confirm)通过后执行,skipConfirmation选项供丢弃临时草稿这类场景使用(L1946-L2075)。底层删除按类型分派:CLI 会话执行agents.github.copilot.cli.deleteSessions,Cloud 会话调用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()_sandboxModelWaitMs(L2151-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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询