Skip to content

完成度验证器 ​

本文引用的源码文件

本文引用的文件

目录 ​

  1. 引言
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能与可观测性
  8. 故障排查指南
  9. 结论
  10. 附录:扩展与自定义实践

引言 ​

本文件面向“完成度验证器”这一子系统,系统性说明任务完成判断的算法原理、证据收集机制、评分与阈值判定逻辑、执行结果验证流程,以及与 ReAct 循环的集成方式。该子系统位于 Chrome 扩展背景页(background)中,通过内容脚本在真实页面 DOM 上取证,并通过本地 Agent 执行只读命令或文件检查,最终产出结构化验证结果与面向父模型的提示文案,供上层决策是否继续处理或重试。

项目结构 ​

完成度验证相关代码横跨 background、content、shared 三层:

  • background/completion-verifier.js:编排层,负责断言归一、异步取证、纯判定、重跑门控、缺项指令与文案生成。
  • background/react-loop.js:ReAct 子任务执行后触发完成度验证,注入路由取证器与重跑回调。
  • content/advanced-tools.js + index.js:内容脚本侧对真实 DOM 求值 doneCriteria,并注册 EVALUATE_DONE_CRITERIA 消息路由。
  • shared/verify-command-safety.js:完成度校验命令的只读安全白名单与参数转义。
  • shared/locales/en.js:完成度校验相关英文 i18n 文案。
  • test/unit/*:覆盖路由、注解、集成、连线等关键路径的单测。
graph TB
subgraph "Background"
CV["completion-verifier.js<br/>编排层"]
RL["react-loop.js<br/>ReAct 子任务循环"]
end
subgraph "Content"
AT["advanced-tools.js<br/>DOM 判据求值"]
CI["index.js<br/>EVALUATE_DONE_CRITERIA 路由"]
end
subgraph "Shared"
VCS["verify-command-safety.js<br/>只读命令白名单"]
EN["en.js<br/>i18n 文案"]
end
RL --> CV
CV --> AT
AT --> CI
CV --> VCS
CV --> EN

图示来源

章节来源

核心组件 ​

  • verifySubtaskCompletion:完成度判定内核入口。将原始 doneCriteria 归一化,调用 gatherEvidence 逐条取证,再交由 classifyVerdict 输出 verdict、missing、reason,并决定是否 rerun 与构造 directive。
  • createRoutingEvidenceCollector:按 check 类型路由到 DOM 取证或命令/文件取证;支持动态 tab 解析与超时控制。
  • createContentEvidenceCollector:向内容脚本发送 EVALUATE_DONE_CRITERIA,在真实 DOM 上求值,返回 {available, pass, reason}。
  • createCommandEvidenceCollector:编译 shell 命令,经只读安全门与 agent execWait 执行,以退出码/输出取证。
  • annotateOneSubtaskCompletion / annotateSubtaskCompletion:对单个/批量子任务结果即时取证并写回 verification/completionNote;Phase A 不重跑,Phase B 支持带门控的重跑回路。
  • buildMissingCriteriaDirective / buildCompletionNote:根据 missing 与 reason 生成面向父模型的可读指令与文案。

章节来源

架构总览 ​

完成度验证的整体流程如下:

  1. ReAct 子任务成功执行后,react-loop 构建 doneResult 并调用 onDone 持久化进度。
  2. 若 completionVerification.enabled=true,则创建 createRoutingEvidenceCollector 并调用 annotateOneSubtaskCompletion。
  3. annotateOneSubtaskCompletion 根据 config.rerunEnabled 选择 Phase A(仅标注)或 Phase B(可重跑)。
  4. verifySubtaskCompletion 对每条 doneCriteria 调用 gatherEvidence:
    • DOM 类 → createContentEvidenceCollector → 内容脚本 evaluateDoneCriteria。
    • 命令/文件类 → createCommandEvidenceCollector → 只读安全门 → execWait → 退出码/输出取证。
  5. classifyVerdict 综合 available/pass/judge 与四闸门得出 verdict,并决定 rerun/directive。
  6. annotateOneSubtaskCompletion 写回 r.verification 与 r.completionNote;Phase B 下可能调用 rerun 回调驱动下一轮内层 reactLoop。
sequenceDiagram
participant RL as "react-loop.js"
participant CV as "completion-verifier.js"
participant CC as "createContentEvidenceCollector"
participant CT as "content/index.js"
participant AT as "advanced-tools.js"
participant CE as "createCommandEvidenceCollector"
participant AG as "Agent execWait"
RL->>CV : annotateOneSubtaskCompletion(doneResult, [subtask], deps)
CV->>CV : verifySubtaskCompletion(gatherEvidence)
alt DOM 类
CV->>CC : gatherEvidence(criterion)
CC->>CT : sendMessage(tabId, {type : EVALUATE_DONE_CRITERIA})
CT->>AT : evaluateDoneCriteria(criteria)
AT-->>CT : [{id,check,pass,available,reason}]
CT-->>CC : results
CC-->>CV : {available,pass,reason}
else 命令/文件类
CV->>CE : gatherEvidence(criterion)
CE->>AG : execWait(command, force=false, timeout)
AG-->>CE : {exitCode|level|error}
CE-->>CV : {available,pass,reason}
end
CV-->>RL : verification + completionNote
opt Phase B 且需重跑
RL->>RL : rerun(directive) 追加 user 上下文并再跑一轮
end

图示来源

详细组件分析 ​

证据收集机制与路由 ​

  • createRoutingEvidenceCollector 依据 criterion.check 分类:
    • DOM 类:element_exists、element_absent、text_contains、url_matches、attribute_equals → 走内容脚本。
    • 命令/文件类:command_exit_zero、command_output_matches、file_exists、file_absent、file_contains → 走命令取证。
    • 未知 check → 返回 {available:false, reason:'unknown_check'},保守不派发。
  • DOM 取证:
    • createContentEvidenceCollector 通过 chrome.tabs.sendMessage 发送 EVALUATE_DONE_CRITERIA,并在内容脚本中 evaluateDoneCriteria 求值。
    • 响应形状容错:数组或 {results:[...]};无有效结果视为不可用。
    • 超时保护:默认 3s,区分 channel_timeout/channel_no_receiver/page_unreachable/channel_error 等 reason。
  • 命令取证:
    • buildVerifyCommand 将判据编译为 shell 命令;非法 target/expected/bad_path 直接返回 reason,绝不拼接执行。
    • 只读安全门:readOnlyGate=true(重跑关闭)时,isReadOnlyVerifyCommand 拒绝非只读命令;重打开时由 agent 三档门控(allow/confirm/deny)解释。
    • execWait 强制 force=false;agent 离线/超时/执行异常均返回 available:false,绝不折成 pass:false。
flowchart TD
Start(["收到 criterion"]) --> CheckType{"check 类型?"}
CheckType --> |DOM| DOMPath["createContentEvidenceCollector<br/>sendMessage(EVALUATE_DONE_CRITERIA)"]
CheckType --> |命令/文件| CmdPath["buildVerifyCommand + isReadOnlyVerifyCommand<br/>execWait(force=false)"]
CheckType --> |未知| Unknown["返回 {available:false, reason:'unknown_check'}"]
DOMPath --> DOMResp{"响应有效?"}
DOMResp --> |否| DOMUnavailable["{available:false, reason:...}"]
DOMResp --> |是| DOMPass["{available:true, pass:!!r.pass}"]
CmdPath --> BuildCmd{"命令合法?"}
BuildCmd --> |否| CmdUnavailable["{available:false, reason:...}"]
BuildCmd --> ExecCmd["execWait(command, force=false)"]
ExecCmd --> Level{"res.level?"}
Level --> |confirm/deny| CmdPolicy["{available:false, reason:policy}"]
Level --> |allow| ExitCode{"exitCode 存在?"}
ExitCode --> |否| CmdError["{available:false, reason:command_error}"]
ExitCode --> |是| PassCheck{"command_output_matches?"}
PassCheck --> |是| OutMatch["pass = stdout/stderr.includes(expected)"]
PassCheck --> |否| ExitZero["pass = exitCode === 0"]

图示来源

章节来源

完成度评分模型与阈值判定 ​

  • verifySubtaskCompletion 将每条判据的取证结果汇总为 checkResults,并传入 classifyVerdict(来自 shared/completion-verdict.js),结合以下维度判定:
    • objectiveChecksEnabled:是否启用客观取证。
    • lowConfidence:开放任务 judge 的低置信策略。
    • 四闸门 gates:failureRetryable、progressMade、budgetLeft、attemptsUnderLimit。
  • 返回值包含:
    • verdict:SATISFIED / UNMET_RETRYABLE / UNMET_PERMANENT / INDETERMINATE。
    • missing:未达标的判据 id 列表(仅包含 available!==false 且 !pass 的项)。
    • reason:evidence_partial / evidence_unavailable / no_criteria 等。
    • rerun:仅在 UNMET_RETRYABLE 时为 true。
    • directive:当 rerun=true 时,基于 missing 构造纠正指令。
flowchart TD
A["normalizeDoneCriteria"] --> B["逐条 gatherEvidence"]
B --> C["classifyVerdict(checkResults, judge, gates, config)"]
C --> D{"verdict"}
D --> |SATISFIED| E["rerun=false, directive=null"]
D --> |UNMET_RETRYABLE| F["rerun=true, directive=buildMissingCriteriaDirective"]
D --> |UNMET_PERMANENT| G["rerun=false, directive=null"]
D --> |INDETERMINATE| H["rerun=false, directive=null"]

图示来源

章节来源

子任务标注与重跑门控 ​

  • annotateOneSubtaskCompletion:
    • Phase A(config.rerunEnabled=false 或未提供 rerun):四闸门全 false,永不重跑;任何未达标一律落 unmet_permanent,仅用于如实上报。
    • Phase B(config.rerunEnabled=true 且提供 rerun):进入 while 循环,逐轮取证→计算四闸门→若 wantRerun 则调用 rerun 回调追加 user 上下文并再跑一轮。
    • 防振荡:isStrictSubset 要求 missing 严格收缩才认为有进展;否则降级为 UNMET_PERMANENT。
    • shouldStop/budgetLeft:取消/超时早停;预算不足停止重跑。
  • annotateSubtaskCompletion:批量包装,逐个调用 annotateOneSubtaskCompletion。
flowchart TD
S(["annotateOneSubtaskCompletion"]) --> CheckPlan{"有 doneCriteria?"}
CheckPlan --> |否| ReturnA["返回原结果"]
CheckPlan --> |是| Mode{"rerunEnabled?"}
Mode --> |否| PhaseA["Phase A:四闸门全 false,仅标注"]
Mode --> |是| Loop["Phase B:while(true)"]
Loop --> Gates["计算四闸门<br/>attemptsUnderLimit, budgetLeft, progressMade"]
Gates --> Verdict["verifySubtaskCompletion"]
Verdict --> WantRerun{"wantRerun?"}
WantRerun --> |否| Downgrade{"降级检查"}
Downgrade --> |true| Permanent["降级为 UNMET_PERMANENT"]
Downgrade --> |false| ReturnB["返回结果"]
WantRerun --> |是| Rerun["rerun(directive) 追加 user 上下文并重跑"]
Rerun --> Loop

图示来源

章节来源

与 ReAct 循环的集成 ​

  • 触发时机:子任务成功执行后,先调用 progressHooks.onDone 持久化进度,再进入完成度验证(Phase B)。
  • 路由取证器注入:
    • tabId:当前标签页。
    • resolveTabId:优先使用子任务的 lastOperatedTab,避免取证打到非工作 tab。
    • execWait:execCommandWait。
    • isOnline:getAgentConfig().connected。
    • commandReadOnlyGate:!cvCfg.rerunEnabled(重跑关=Phase A 只读硬拦;开重跑=交由 agent 三档门控)。
  • 重跑回调:
    • 将 directive 作为 user 消息追加到 subtaskMessages。
    • 调用 reactLoop 重新执行子任务,合并日志与结果,但不重复 onDone 与 checkpoint。
  • 失败处理:
    • 验证异常被 try/catch 吞掉,不影响子任务结果与主循环。
    • 子任务本身失败按既有重试/失败策略处理。
sequenceDiagram
participant RL as "react-loop.js"
participant CV as "completion-verifier.js"
RL->>RL : onDone(doneResult)
RL->>RL : if cvCfg.enabled
RL->>CV : annotateOneSubtaskCompletion(doneResult, [subtask], {gatherEvidence, config, shouldStop, budgetLeft, rerun})
CV-->>RL : r.verification + r.completionNote
opt rerun=true
RL->>RL : subtaskMessages.push(user directive)
RL->>RL : reactLoop(subtaskMessages, ...)
RL->>RL : merge executionLog & result
end

图示来源

章节来源

多模态证据处理 ​

  • 文本证据:text_contains 在页面全文中查找子串;url_matches 匹配当前 URL 子串;attribute_equals 比较元素属性。
  • 结构化数据:command_output_matches 读取 stdout/stderr 并包含 expected;file_contains 在文件中 grep 固定字符串。
  • 截图分析:当前实现未直接进行截图视觉分析;如需扩展,可在 gatherEvidence 中接入截图工具,将截图描述或 OCR 结果作为额外证据输入 judge 或自定义规则。

章节来源

依赖关系分析 ​

  • completion-verifier.js 依赖:
    • shared/completion-verdict.js:normalizeDoneCriteria、classifyVerdict、VERDICTS。
    • shared/i18n.js:t() 与 registerTranslations。
    • shared/logger.js:debug 级诊断日志。
    • shared/verify-command-safety.js:isReadOnlyVerifyCommand、shQuoteArg。
  • react-loop.js 依赖:
    • completion-verifier.js:createRoutingEvidenceCollector、annotateOneSubtaskCompletion。
    • 本地 Agent:execCommandWait、getAgentConfig。
    • 内容脚本:chrome.tabs.sendMessage(间接通过 createContentEvidenceCollector)。
  • content/index.js 与 advanced-tools.js:
    • 注册 EVALUATE_DONE_CRITERIA 路由,调用 evaluateDoneCriteria 在真实 DOM 上求值。
graph LR
CV["completion-verifier.js"] --> VERDICT["completion-verdict.js"]
CV --> I18N["i18n.js"]
CV --> LOG["logger.js"]
CV --> VCS["verify-command-safety.js"]
RL["react-loop.js"] --> CV
CV --> CONTENT["content/index.js"]
CONTENT --> ADV["advanced-tools.js"]

图示来源

章节来源

性能与可观测性 ​

  • 超时控制:
    • DOM 取证默认 3s(EVIDENCE_TIMEOUT_MS),命令取证默认 15s(COMMAND_EVIDENCE_TIMEOUT_MS)。
    • 超时统一归类为 channel/command timeout,返回 available:false,避免阻塞渲染进程。
  • 缓存优化:
    • DOM 取证器按 tabId 缓存,减少重复创建开销。
  • 日志诊断:
    • 取证不可用路径打 debug 日志,含 reason/tabId/check/target 等字段,便于定位问题。
  • 预算门控:
    • Phase B 支持 perSubtaskTokenBudget 与剩余时间检查,防止无限重跑。

章节来源

故障排查指南 ​

  • 常见现象与原因:
    • 全部不可评估:通道不可达、目标页不可访问、命令需确认或被拒、命令非法等,返回 INDETERMINATE 与 detailMixed/detailChannel/detailCommandPolicy。
    • 部分不可评估:部分判据可达但另有不可评估项,返回 INDETERMINATE 与 evidence_partial。
    • 未达标:客观取证确证未达成,返回 UNMET_PERMANENT 或 UNMET_RETRYABLE(取决于 gates)。
  • 排查步骤:
    1. 查看 completionNote 中的 reason 与 detail 分桶信息。
    2. 检查 content/index.js 是否注册 EVALUATE_DONE_CRITERIA,且 TOP_FRAME_ONLY_TYPES 包含该类型。
    3. 检查 advanced-tools.js 中对应 check 的实现是否符合预期(selector/query/text/url/attribute)。
    4. 对于命令/文件类,检查 buildVerifyCommand 生成的命令是否合法,以及 isReadOnlyVerifyCommand 是否放行。
    5. 检查 agent 连接状态与 execWait 返回结构(exitCode/level/error)。
  • 单测参考:

章节来源

结论 ​

完成度验证器通过“客观取证 + 纯判定 + 门控重跑”的分层设计,在保证安全与稳定性的前提下,提供了可扩展的证据收集能力与清晰的失败反馈。其核心优势包括:

  • 证据与判定解耦:gatherEvidence 与 judge 由调用方注入,便于替换与扩展。
  • 安全优先:命令取证采用只读白名单与 agent 三档门控,避免绕过 agent_exec 的安全风险。
  • 稳健降级:不可评估与部分不可评估均归为 INDETERMINATE,不谎报未达标。
  • 与 ReAct 无缝集成:在子任务成功后即时取证,必要时驱动轻量重试,同时保持进度与日志一致性。

附录:扩展与自定义实践 ​

  • 自定义验证规则:
    • 在 verifySubtaskCompletion 中注入 judge 回调,用于开放任务的主观评审;结合 lowConfidence 控制置信度策略。
    • 在 createRoutingEvidenceCollector 中扩展 check 类型映射,新增多模态证据(如截图分析)分支。
  • 扩展证据类型:
    • DOM 类:在 advanced-tools.js 的 evalOneDoneCriterion 中添加新 check 分支,返回 {available, pass}。
    • 命令/文件类:在 buildVerifyCommand 中新增命令模板,并确保 isReadOnlyVerifyCommand 放行或交由 agent 三档门控。
  • 优化验证性能:
    • 调整 EVIDENCE_TIMEOUT_MS 与 COMMAND_EVIDENCE_TIMEOUT_MS 以适应不同场景。
    • 利用 tab 缓存减少 DOM 取证器创建开销。
    • 配置 perSubtaskTokenBudget 与剩余时间检查,限制重跑成本。
  • 调试方法:
    • 开启 logger.debug 观察取证不可用的 reason 分类。
    • 使用单测用例快速验证路由、注解与集成链路。
    • 在 react-loop 中打印 cvCfg 与 gates 状态,确认开关与预算门控生效。

章节来源