资讯动态

VS Code Agent Host E2E 测试门禁机制:一条命令复现每个已知缺口的完整指南

发布时间:2026/10/20 1:27:11 来源:尧图企业网站定制
VS Code Agent Host E2E 测试门禁机制一条命令复现每个已知缺口的完整指南【免费下载链接】TwitchDropsMinerAn app that allows you to AFK mine timed Twitch drops, with automatic drop claiming and channel switching.项目地址: https://gitcode.com/GitHub_Trending/tw/TwitchDropsMinerVS Code 的 Agent Host 端到端测试套件里藏着一份一直在被更新的缺口登记册KNOWN_ISSUES.md。它记的不是已经修好的缺陷而是此刻仍被门控、没能全量跑起来的用例。这篇文章带你完整拆解VS Code Agent Host E2E 测试门禁机制——为什么这些测试不被删除而是被门控、环境开关如何在注册阶段变成test.skip、一个缺口条目该怎么写以及每个缺口如何靠一条命令精确复现。先把两个词说白E2E端到端测试不是拿假数据糊弄的单测而是真的把 Agent Host 服务器进程、捆绑的 provider SDK/CLI 子进程以及它们之间的 JSON-RPC AHP 协议全拉起来跑只是模型流量先被录制成提交的 YAML fixture回放用的剧本每次运行时确定性重放。**门禁gate**则是一个条件判断——满足它某个测试变体就真正执行不满足就用test.skip跳过。整套机制的巧妙之处就藏在这两个词的配合里。先想清楚为什么留测试、删门禁而不是删测试登记册的头部把自己定位得很清楚这是至少在一个 provider、平台或执行模式下被禁用的 E2E 测试清单。测试是规格本文件只记录活跃的缺口。这里有两个不能丢的原则。第一测试即执行规格the test is the executable specification。一条用例本身就是对系统该怎么做的可执行描述。缺口暴露时声明保留在原 suite 里只是通过平台 / provider / 运行模式条件让受影响的变体去skip。等缺口修好删掉门禁覆盖率立刻回到原位。反过来如果你直接删测试你就把这份规格也删了——bug 哪天回退没有任何东西能替你接住它。第二能力跳过要单独记账。provider 没声明某能力所以这条正路径用例跳过属于预期行为单独列在文末一张预期能力跳过表里跟疑似产品缺陷严格分开。两者混在一处缺陷清单就被污染了。 所以门控的本质是测试一直都在只是暂时被关在某个变体后面。这正是后文所有机制的出发点。把一个缺口走一遍从暴露到关闭的完整旅程抽象讲机制容易悬空不如跟着一个真实缺口走完它的一生。以重复会话创建被接受为例——客户端可以用同一个已存活会话的 URI 重试创建host 本应拒绝却把它当成功处理了。暴露与最小化一条有效的 E2E 场景先暴露它再确定受影响的 provider这里是 conformance 参考 provider、平台全平台、运行模式host-only不碰模型流量。门控场景被要求必须设AGENT_HOST_RUN_KNOWN_ISSUES1才跑也就是挂在RUN_HOST_ONLY_KNOWN_ISSUE_TESTS这道布尔量下。登记先在登记册里写用户面解释再列字段清单下一节讲格式。保留现场对还会再跑的变体保留它生成的 capture快照 / fixture永不手改。关闭host 修到对第二个createSession返回SessionAlreadyExists后一次性移除门禁、登记条目、过时注释和孤儿产物。注意第 5 步的一次性。正如后文会看到的fixture 的文件名是由 provider 测试标题派生的——一旦你改了测试名或移动了它旧的 fixture 和 AHP 快照就成了没人认领的孤儿产物orphaned artifact。残留的孤儿 capture 比缺失更危险它会在没人察觉的情况下滑进覆盖率统计。环境开关如何变成 test.skip登记册里反复出现的门禁不是文档约定而是 suites/agentHostE2ESuites.ts 在 suite 注册阶段算出来的几个布尔量。核心就四行// suites/agentHostE2ESuites.ts节选 const RECORD process.env[AGENT_HOST_REPLAY_RECORD] 1 || process.env[AGENT_HOST_UPDATE_SNAPSHOTS] 1; const RUN_RECORD_ONLY_TESTS process.env[AGENT_HOST_REPLAY_RECORD] 1; const RUN_KNOWN_ISSUE_TESTS RECORD process.env[AGENT_HOST_RUN_KNOWN_ISSUES] 1; const RUN_HOST_ONLY_KNOWN_ISSUE_TESTS process.env[AGENT_HOST_RUN_KNOWN_ISSUES] 1;这四个量随后经IAgentHostE2ETestContext定义在 suites/e2eTestContext.ts分发进每个 suite用例据此决定调test还是test.skip布尔量成立条件它门控谁RECORDAGENT_HOST_REPLAY_RECORD1或AGENT_HOST_UPDATE_SNAPSHOTS1录制态总开关参与派生量RUN_RECORD_ONLY_TESTS仅AGENT_HOST_REPLAY_RECORD1依赖真实流式窗口的仅录制场景RUN_KNOWN_ISSUE_TESTSRECORD且AGENT_HOST_RUN_KNOWN_ISSUES1需要 fixture 录制模式才观测得到症状的缺陷场景RUN_HOST_ONLY_KNOWN_ISSUE_TESTS仅AGENT_HOST_RUN_KNOWN_ISSUES1无模型流量的 conformance 层缺口除了这四个环境开关还有两类声明式门禁平台 / provider 条件直接写在调用点比如 Windows 下把整组插件 hook 用例换成test.skip以及 provider 配置里的一组能力 / 稳定性标志——supportsChatForkE2E、supportsTruncateE2E、supportsPausedTurnCancellationE2E、shellToolReplayUnstableOnLinux、subagentReplayUnstableOnWindows等登记表里的门禁条件大多指向它们。顺带认识一下四种运行模式后文命令会用到模式触发方式它做什么回放默认CI 走这条不设任何开关回放已提交 fixture无 token 无网络没录过的请求直接硬失败只更新 AHP 快照AGENT_HOST_UPDATE_AHP_SNAPSHOTS1回放 LLM fixture就地重写 AHP 快照不需要 token全量重录AGENT_HOST_UPDATE_SNAPSHOTS1同时重写 AHP 快照与 LLM fixture转发到真实 CAPI需要GITHUB_TOKEN或gh auth token只重录 LLMAGENT_HOST_REPLAY_RECORD1遗留聚焦模式只对真实 CAPI 重录归一化 LLM fixture哪些场景只能在录制模式下跑有一类缺口回放模式天生就复现不出来它们依赖命令完成的系统通知是否赶在模型下一次请求之前到达这种真实时序窗口。回放是确定性的它要么把通知包进同一份历史、要么不包取决于进程时序于是严格匹配模型请求的用例就会失配。这类场景被RUN_RECORD_ONLY_TESTS门控写作(context.runRecordOnlyTests ? test : test.skip)(...)只有AGENT_HOST_REPLAY_RECORD1直接录制不含批量更新时才真正执行。以 Copilot 的异步 shell 生命周期为例用户视角你可以在后台启动一条 shell 命令、查看或列出正在跑的 shell、再把它停掉。实时状态下这套生命周期一切正常但确定性回放保证不了完成通知和模型下一次请求的先后捕获下来的请求历史会随进程时序漂移。涉及用例managed shell can be read and stopped after asynchronous execution同组还有managed shell sessions can be listed after asynchronous execution、custom terminal tool manages an asynchronous shell lifecycle应当发生什么同一份 fixture 在命令刚好赶在下一次请求前或刚好赶在其后完成时都能回放实际发生了什么聚焦回放可能含完成通知而共享进程的大范围运行不含导致严格模型请求失配影响范围Copilot 确定性回放当前如何门控仅在AGENT_HOST_REPLAY_RECORD1下经context.runRecordOnlyTests运行一条命令复现AGENT_HOST_REPLAY_RECORD1 ./scripts/test-integration.sh --run \ src/vs/platform/agentHost/test/node/e2e/providers/copilotAgentHostE2E.integrationTest.ts \ --grep managed shell|custom terminal tool manages⚠️ 记住这条边界仅录制不是偷懒而是回放物理上无法稳定复现的那部分行为的专属通道。想验证这类缺口当前是否仍在就得进真实录制模式跑。一个缺口条目长什么样先讲人话再列字段登记册对写作有一条硬性规范疑似产品缺陷的条目必须做到不读测试、不懂 Agent Host 实现术语也能读懂。先用完整句子讲清楚用户在做什么、哪里失败、对用户的影响然后才给技术字段。这就是每个条目叙述 字段列表两段式的由来。看一个 conformance 层的完整示例——重复会话创建被接受用户视角客户端可以用一个已经标识了存活会话的 URI 重试创建会话。host 接受了这个重复请求而不是报告资源已存在。于是客户端分不清幂等重试和意外撞车provider 可能被要求去创建互相冲突的底层状态。涉及用例creating a duplicate session resource is rejected应当发生什么第二个 AHPcreateSession请求以SessionAlreadyExists失败实际发生了什么第二个请求成功返回影响范围conformance 参考 provider全平台当前如何门控场景要求AGENT_HOST_RUN_KNOWN_ISSUES1一条命令复现AGENT_HOST_RUN_KNOWN_ISSUES1 ./scripts/test-integration.sh --run \ src/vs/platform/agentHost/test/node/e2e/conformance/agentHostConformance.integrationTest.ts \ --grep creating a duplicate session resource is rejected注意当前如何门控这一行怎么读它指向的是哪个布尔量 / 哪个标志位让这条用例被拦下而不是重复贴一遍命令。命令永远放在最后一行可复制、可直接跑。反直觉只按平台键控快照名反而比跳过更糟讲完门禁来看一个最容易让人栽跟头的坑。Windows 上的 prompt 快照按构造就是 POSIX-only 的——CLI 在 Windows 会额外携带 PowerShell 专属段落无 here-doc 指引、if ($?) { ... }式的分号串联、.bat里 PATH/LIB 变更不可用的告诫。fixture 用${shell}占位符处理工具名差异但这里的散文本身就是被断言的产物把它投影掉等于删掉快照要固定的工具指令。那能不能按平台键控快照名给 Windows 存一份、给 POSIX 存一份恰恰会更糟。assertSnapshot遇到缺失基线时会自动创建文件并放行——于是 Windows CI 会对着没人写、也没人审查过的文件变绿。你本来想加一道保险结果换来一个永远为真的绿灯。这类结构性盲区有一个更根本的代价它们不会表现为跳过的测试因此极易被遗漏。正是一刀切的!isWindows排除退役之后才看清还剩哪些真正卡住比如成功的 bang 命令有输出但不可靠地完成以及host 终端工具在 Windows 上不发布终端内容——后者从源码结构看尚不能确定是产品缺口还是测试配置差异需要一台 Windows 机器去调查。这条原则本身就是纪律源码上定不下来的就老实写尚不能确定别硬塞一个猜测进去。只记症状、不记猜测写尚不能确定也是纪律回到登记流程里那句只记录症状不记录未经验证的根因假设。它和上一条是同一枚硬币的两面能确定的记症状本身——第二个请求成功返回恢复的responseParts里不含匹配的工具调用。不能确定的明确标注——从源码结构看这尚不能确定是产品缺口还是测试配置差异。反例也很典型CapiReplayProxy在写 fixture之前就检查模型产出的tool_use命令凡是不可移植到 Windows shell 的构造POSIX stderr 重定向、/dev/*、$VAR展开、~/等直接让录制失败。它用的是黑名单而非白名单——因为误报会挡住正确录制把作者推向干脆禁用检查而那比漏掉一个案例更糟。真正的例外被集中收进 harness 的POSIX_COMMAND_EXCEPTIONS保持单处可清点。 换句话说登记册的可信度来自它只说亲眼看到的事以及把我还没看清的事也如实写下来。比被跳过的测试更危险的是不存在的测试前面讲的都是被门控的单个用例。登记册另设一节提醒一种更隐蔽的缺口某个平台或契约完全没有 E2E 覆盖的整片区域。它们不会表现为跳过所以更容易被当成本来就没问题。典型的有几处能力标志关掉的整类正路径。supportsChatForkE2E: false让 Claude 的 fork 用例整组不注册supportsPausedTurnCancellationE2E只对 Copilot 和 Codex 开启Claude 的暂停取消变体干脆缺席。覆盖只落在单一 provider。黑盒重启场景目前只覆盖 Copilot等价的 Claude 与 Codex 配置持久化可能在没有这个 suite 察觉的情况下回退。回放不稳定的平台。shellToolReplayUnstableOnLinux让 Codex 在 Linux 上完成录制 turn 但不发命令执行通知一整片 shell 工具用例被跳过派生量portableShellToolReplayEnabled RECORD || !isLinux || !config.shellToolReplayUnstableOnLinux把录制时放行、回放时才按平台稳定性跳过编码成了语义。这类缺口的复现方式也不同通常是临时清掉某个标志位再跑精确标题。比如验证 Claude 的截断行为AGENT_HOST_REPLAY_RECORD1 ./scripts/test-integration.sh --run \ src/vs/platform/agentHost/test/node/e2e/providers/claudeAgentHostE2E.integrationTest.ts \ --grep truncating a materialized chat或验证 Claude 的 provider fork临时把supportsChatForkE2E打开即可触发./scripts/test-integration.sh --run \ src/vs/platform/agentHost/test/node/e2e/providers/claudeAgentHostE2E.integrationTest.ts \ --grep forked peer chat inherits source history through the provider关闭一个缺口时要一次性清掉的东西旅程的终点值得单独说。缺口关闭时标准动作是一次性移除四样东西门禁、登记条目、过时注释、孤儿产物。为什么要捆在一起因为 fixture 名由 provider 测试标题派生AHP 快照同理。你只删门禁、留着条目登记册就和现实对不上了你只删条目、留着孤儿 capture它会在没人察觉的情况下继续被回放、滑进覆盖率统计。最后再补一个批一次的坑它和缺口关闭无关却常让复现命令莫名超时共享辅助器driveTurnToCompletion与startBackgroundApprovalLoop都是循环驱动批准——对每个到达的未确认chat/toolCallReady即时确认。而只批一次会让后续批准请求悬空turn 卡死在session/inputNeededSet直到超时。这种失败看起来像挂起很容易被误读成这个命令不被支持。记住有文件工具就 steer完全避开批准面确需 shell 就 pin 命令、并用共享循环驱动批准。把这套机制收拢成一句话登记册不是缺陷流水账而是一份只记活跃缺口的活规格——测试永远在场门禁决定谁被放行每个缺口都能靠一条命令精确复现。等你修好一个缺口删掉门禁的那一刻覆盖率自己就回来了。【免费下载链接】TwitchDropsMinerAn app that allows you to AFK mine timed Twitch drops, with automatic drop claiming and channel switching.项目地址: https://gitcode.com/GitHub_Trending/tw/TwitchDropsMiner创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑