NemoClaw Advisor 共享工具库解析:PR Review Advisor 的确定性审查基础设施
【免费下载链接】NemoClawRun agents like Hermes, LangChain Deep Agents, and OpenClaw more securely inside NVIDIA OpenShell with managed inference项目地址: https://gitcode.com/gh_mirrors/ne/NemoClaw
导读
tools/advisors/是 NemoClaw 仓库中为"模型驱动的审查顾问(model-backed advisor)"提供共享实现工具包的目录,其消费方是tools/pr-review-advisor/下的 PR Review Advisor 专家入口。本文基于仓库中的 tools/advisors/README.md 与该目录源码,梳理这套基础设施的职责边界、核心模块与信任模型,重点讲解仓库受限只读工具、确定性回合协议、风险计划与 E2E 推荐机制,以及staging-brev-launchable焦点映射的行为所有者规则。读完本文,你将理解 NemoClaw 如何在不授予顾问任意写权限、不依赖仓库开发依赖的前提下,让 LLM 顾问产出可审计、可复现的 PR 审查结论。
目录定位与职责边界
tools/advisors/本身不提供独立的命令行入口,它是被tools/pr-review-advisor/(PR Review Advisor 专家入口)复用的共享层。README 明确列出该目录提供的七类能力:
- 仓库受限、只读的 Pi SDK 会话工具(repository-confined, read-only Pi SDK session tools);
- 确定性回合作用域上下文工具与回合校验(deterministic turn-scoped context tools and turn validation);
- Git diff 与元数据辅助(Git diff and metadata helpers);
- JSON 提取与净化辅助(JSON extraction and sanitization helpers);
- 产物与文件 I/O 辅助(artifact and file I/O helpers);
- GitHub API 与粘性评论辅助(GitHub API and sticky-comment helpers);
- 提供给 PR Review Advisor 专家的受信任 E2E 清单(trusted E2E inventory)。
目录下共 13 个 TypeScript 模块,与上述能力一一对应:
| 模块 | 职责 |
|---|---|
repo-read-only-tools.mts | 仓库受限只读工具(read/grep/find/ls)与结果字节上限控制 |
turn-protocol.mts | 回合类型定义、工具清单解析、回合流校验与修复提示 |
risk-plan.mts | 风险计划(RiskPlan)构建:风险族、必选 Job/Target 映射 |
e2e-recommendations.mts | 受信任 E2E 推荐清单与结果归一化 |
e2e-text.mts | E2E 相关文本形状识别 |
git.mts | diff、diff-stat、commit 列表、head SHA 读取 |
github.mts | GitHub REST/GraphQL 客户端与粘性评论 upsert/删除 |
json.mts | JSON 提取、枚举校验、记录/字符串数组净化 |
canonical-json.mts | 规范化 JSON 序列化 |
http-dispatcher.mts | HTTP 调度辅助 |
io.mts | 参数解析、产物路径规划、JSON 读写 |
session.mts | 会话相关辅助 |
provider-constants.mts | 提供商常量定义 |
从源码结构可以推断,这套库的设计目标有两个:一是把"模型可能出错的部分"(自由文本、任意文件访问、任意工具调用)约束到确定性代码的边界之内;二是让生产环境的顾问运行不依赖仓库的开发依赖。
职责边界:只推荐,不派发
README 特别强调了一个关键边界:E2E 清单(inventory)只是给 PR Review Advisor 专家提供审查上下文的,它不会派发任务,也不会决定合并就绪与否。当维护者需要为一个 PR 运行真实 E2E 时,需要通过 .github/workflows/e2e.yaml 显式运行,并遵循维护者 E2E 流程处理候选资格、凭据、部署与清理。以往 PR 上的 E2E 检查上下文仍然只具有建议性质(advisory)。
这一点在代码层面有直接体现:e2e-recommendations.mts 中normalizeE2eCoverageResult对模型输出做了严格的净化(sanitize):自由格式的模型散文永远不会被保留在归一化结果中(源码注释明确写道"Free-form model prose is never retained in the normalized E2E result"),模型只能从受信任标识符集合中挑选;newE2eRecommendations始终返回空数组;置信度low在存在必选测试或风险族时会被强制提升为medium。
仓库受限只读工具:repo-read-only-tools.mts
该模块是顾问会话安全的基石。它基于@earendil-works/pi-coding-agent(Pi SDK)提供的read/grep/find/ls四个工具定义做二次封装,核心逻辑是createRepoConfinedReadOnlyTools(cwd, onRead?, additionalRoots?):
- 路径守卫(RepoPathGuard):
createRepoPathGuard将候选路径解析为词法路径与真实路径(realpath),同时校验候选路径必须落在工作区根(以及显式声明的附加根)之内。守卫会拒绝@前缀、Unicode 空白字符、~展开后越界以及符号链接重定向到工作区之外的路径(对应canonicalRepoReadPath)。 - 字节上限:
MAX_ADVISOR_TOOL_RESULT_JSON_BYTES = 16 * 1024(16 KiB),boundAdvisorToolResult对序列化后的工具结果做二分截断,并在截断提示中给出offset续读指引(如[Advisor session limit reached. Use offset=N to continue.]),确保每次工具返回都落在会话安全上限内。 - 只读观察回调:
onRead回调会记录读取的路径、起始 offset、结束 offset、文件大小与是否读到文件末尾(AdvisorReadObservation),这些观测事件是回合流校验的输入之一。
从代码可以推断,onRead产生的观测会被上层session/turn逻辑消费,用于实现"必须先读取指定证据文件再输出分析"之类的硬性回合约束。
确定性回合协议:turn-protocol.mts
turn-protocol.mts定义了顾问与模型之间单次"回合(turn)"的确定性契约,核心类型是AdvisorPromptTurn,其字段构成了一套可组合的约束语言:
| 字段 | 含义 |
|---|---|
name/prompt | 回合名与提示词 |
contextToolResults | 本回合暴露的确定性上下文工具(零参数必调工具),内容来自受信任代码而非模型 |
activeToolNames/requiredToolNames | 本回合可用的附加工具 / 必须成功完成的工具 |
requireToolsBeforeText | 必须先完成才能输出文本的工具(含上下文工具) |
requiredReadOneOfPaths | 输出分析前必须真实读取的路径之一 |
requireAssistantText | 回合结束时必须存在非空分析文本 |
atomicTerminalToolName | 原子终结工具:必须是本回合唯一的活动与必选工具,禁止上下文、文本要求与其他工具 |
terminalSubmitToolName | 终态提交工具:可跟随上下文、读取、散文与其他草稿工具,最多一次成功 |
resolveAdvisorTurnTools会对回合配置做编译期式校验:未注册工具、原子终结工具与终态提交工具同时出现、原子终结工具附带上下文或文本要求等都会直接抛错。advisorTurnFlowErrors则基于事件流(text/read/tool_start/tool_end)做运行时校验,例如:
- 必须提交的分析缺失(
omitted required analysis); - 在必调工具完成前输出了文本(
emitted text before ... completed); - 终态提交工具的成功次数不是恰好 1 次、成功后仍有活动(
non-submit activity after successful ...)。
模块还提供三类"修复(repair)"协议:assistantTextRepairPrompt(纯散文续写)、atomicTerminalRepairPrompt(纯工具续写)、terminalSubmitRepairPrompt(恰好一次成功提交续写)。README 对此的概括是:修复尽可能保留已完成的回合——缺散文给一次纯散文续写,缺原子提交给一次纯工具续写,终态提交允许围绕一次成功存在已了结的失败尝试或给予一次续写。这把"模型行为不可控"压缩成了有限、可审计的修复路径。
风险计划与确定性 E2E 推荐:risk-plan.mts与e2e-recommendations.mts
RiskPlan 结构
risk-plan.mts导出版本号为RISK_PLAN_VERSION = 25,buildRiskPlan接受headSha与changedFiles,输出包含以下字段的RiskPlan:
version/headSha/planHash:版本、提交 SHA 与 SHA-256 计划摘要(planDigest对除 hash 外的全部字段做 SHA-256);changedFiles/tier:变更文件集合与整体风险层级(RiskTier = 0 | 1 | 2 | 3);families:命中的风险族(RiskPlanFamily),每个族携带summary、tier、matchedFiles、invariants(不变量)、requiredJobs与requiredTargets;requiredJobs/requiredTargets:汇总后的必选 Job 与 Target 列表。
风险规则(RISK_RULES)是声明式的:每条规则定义匹配函数、风险层级、不变量与必选 Job。例如:
lifecycle-state(tier 2):onboarding/sandbox 状态必须在持久化元数据、上报状态与真实运行时之间收敛,必选onboard-resume、onboard-repair;gateway-topology(tier 2):网关拓扑变化必须保持沙箱可见主机地址位于沙箱网络子网之外,并使用单一地址权威;inference-policy(tier 2):推理选择、可达性与网络策略必须在真实主机到沙箱边界一致,必选inference-routing、network-policy;credentials-security(tier 3):凭据与安全边界变化必须保持保密、净化与失败关闭(fail-closed)策略;e2e-control-plane(tier 3):E2E 选择、执行与证据变化必须保持可信派发与失败关闭的结果分类,缺失/跳过/畸形/不匹配的证据都不能产生通过的闸门;managed-image-multiarch与managed-image-protected-runtime(tier 3):受保护托管镜像必须在每个支持架构上以精确的 base 与候选 digest 构建并直接启动全部发货 Agent。
受信任 E2E 清单与归一化
e2e-recommendations.mts从受信任的.github/workflows/e2e.yaml、E2E 目标目录(E2E_TARGET_CATALOGUE,来自 tools/e2e/target-catalogue.mts)与免凭据测试清单(tools/e2e/credential-free-tests.mts)构建trustedE2eRecommendationInventory(),输出:
workflow: "e2e.yaml"、fanoutId: "e2e-all";selectorTypes: ["all", "target", "job"];allowedJobIds:可从E2E_JOB: "1"注释等信号提取的、可被 PR 计划自动选中的 Job;manualOnlyJobIds:仅限人工控制的 Job(如inference-routing、managed-image-protected-runtime,定义于PR_E2E_MANUAL_CONTROLLER_JOB_IDS);liveSupportedTargetIds:注册表中受支持的真实运行目标。
关键的信任设计在归一化路径中:normalizeE2eTargetAdvisorResult中,被分析的 PR 工作流文本被视为不可信输入——它可以解释"为什么某个变更测试没有可信选择器",但绝不能引入受信任工作流与目录之外的 Job(源码注释:"The analyzed workflow is untrusted input... it must never introduce one absent from the trusted workflow or catalogue")。同时 README 强调,清单读取器只使用 Node.js 内建模块与仓库内已检入的 TypeScript 模块,因此生产顾问不需要 TypeScript、Vitest 等仓库开发依赖。
未接线测试的兜底
e2e-recommendations.mts还实现了"未接线 live 测试"检测:如果变更中的test/e2e/live/*.test.ts既没有对应 Job 接线、也没有出现在工作流文本中,则findUnwiredFreeStandingLiveTests会将其识别出来,missingLiveWiringReason会给出提示——例如新 E2E 测试未接入 e2e 工作流,无法被派发,需要先添加免凭据标签、独立 Job 或类型化 live 目标,才能把 PR 视为可运行 E2E。
staging-brev-launchable焦点映射详解
README 花费最多篇幅描述的,是确定性焦点映射对staging-brev-launchable行为所有者的推荐规则,这些规则全部实现在risk-plan.mts的BREV_LAUNCHABLE_FILES、BREV_LAUNCHABLE_MODULE_PREFIXES与BREV_LAUNCHABLE_SCENARIO_FILE中:
1. 网关发现与所有权、共享转发恢复或启动、连接/探针入口(文件级精确匹配)
BREV_LAUNCHABLE_FILES是一个显式文件集合,包括:
- 网关绑定与管理:
src/lib/onboard/gateway-binding.ts、gateway-management.ts、gateway-ownership.ts、gateway-teardown-authority.ts、gateway-host-runtime.ts; - 仪表盘转发:
src/lib/onboard/agent-dashboard-forward.ts、dashboard-forward-control.ts、dashboard.ts; - OpenShell 适配器:
src/lib/adapters/openshell/command-execution.ts、forward-cli.ts、forward-runtime.ts、forward.ts; - 转发恢复与进程恢复:
src/lib/actions/sandbox/forward-recovery.ts、process-recovery.ts、status/process-recovery.ts; - 连接与启动就绪:
src/lib/actions/sandbox/connect.ts、terminal-connect-probe.ts、launch-readiness.ts; - 端到端场景文件:
test/e2e/live/launch-agent-turn.ts与tools/e2e/brev-launchable-e2e.sh。
2. 运行时模块前缀(含新增嵌套 helper)
BREV_LAUNCHABLE_MODULE_PREFIXES包含两个前缀,凡是变更文件以这些前缀开头且通过isRuntimeRelevant过滤(排除单元测试、文档、支持单元测试等),即视为命中:
src/lib/onboard/gateway-binding/src/lib/actions/sandbox/launch-readiness/
3.full-e2e场景与配套源文件
BREV_LAUNCHABLE_SCENARIO_FILE是一个正则:
/^test\/e2e\/(?:fixtures|live)\/full-e2e(?:[./-].*)?\.[cm]?[jt]s$/它匹配test/e2e/live/与test/e2e/fixtures/下以full-e2e开头的场景及其配套文件,包括full-e2e/目录中的新增 helper。
匹配边界与不可移除性
README 明确了几条边界规则,代码中同样可见:
- 模块匹配排除source-unit tests 与文档;场景匹配包含live tests 与 source helpers,但排除文档与支持单元测试(
isRuntimeRelevant的实现:docs/、fern/、测试目录、*.test.*、*.md/*.mdx/*.txt一律不视为运行时相关); - 同名兄弟模块与 Hermes-only 相邻实现不触发映射——README 写明 "Similarly named sibling modules and Hermes-only neighboring implementations do not trigger this mapping";
- 现有生命周期推荐保持选中,且顾问(specialist)输出不能从确定性计划中移除 Brev。在
buildRiskPlan中,焦点映射产生的 Job 以focused-e2e风险族身份合入requiredJobs,而normalizeFocusedE2eJobs对选择器的 id 有正则约束(/^[A-Za-z0-9][A-Za-z0-9_-]*$/u),且要求每个匹配文件必须真实存在于changedFiles中,否则抛错——这保证了映射结果始终是受信、确定的。
运行前提与操作约束
README 特别提醒:staging-brev-launchable推荐需要完整运行时场景,而staging-brev-launchable-identity只能证明镜像身份(image identity)。因此实际运行时:
- 由已授权的维护者在
main上通过受信任工作流选择jobs=staging-brev-launchable,且targets必须为空; - 不要将
jobs=staging-brev-launchable与其他 Job ID 组合("Do not combine that selector with other job IDs"); - 候选资格、凭据、部署与清理遵循维护者 E2E 流程;
- 该推荐本身不派发运行、不授权部署——它只回答"这个 PR 应该跑什么 E2E 覆盖"。
Git、GitHub、JSON 与 I/O 辅助
Git 辅助(git.mts)
getChangedFiles、getDiff、getDiffStat、getCommits在git diff上采用双形式容错:先尝试三原点形式${base}...${head}(需要本地 merge base),失败后再尝试两点形式${base}..${head},以兼容缺少本地 merge base 的检出环境。getDiff使用--find-renames --find-copies --unified=80以保留足够的重命名/复制与上下文信息;getHeadSha通过git rev-parse获取精确提交 SHA。
GitHub 辅助(github.mts)
提供 REST 与 GraphQL 客户端,以及两个高价值操作:
upsertStickyComment:按 marker 在 PR 上查找既有评论并更新(PATCH),不存在则创建(POST)——这就是"粘性评论"机制,用于让顾问结论在同一位置持续更新而非不断新增评论;deleteBotOwnedStickyComments:仅删除github-actions[bot]所有、首行匹配指定 marker 的评论,避免误删人工评论。
所有请求携带X-GitHub-Api-Version: 2022-11-28,错误处理区分http(非 2xx)与decode(响应不是合法 JSON),并附带x-github-request-id便于排障。
JSON 与 I/O 辅助
json.mts的extractJson按四种候选依次尝试解析:原始文本、```json 围栏块、<tag>标签块、首尾花括号平衡截取,这覆盖了 LLM 输出中最常见的 JSON 包裹形式;enumValue、recordItems、stringArray、stringOrUndefined提供类型安全的净化入口。io.mts的advisorArtifactPaths规划了六类产物路径(prompt、raw、result、finalResult、summary、sessionHtml),parseArgs将--kebab-case参数规范化为驼峰键,parsePositiveInt提供正整数回退。
信任模型与工作流集成
README 给出了两条重要的运维约定:
- GitHub workflows 必须从受信任的
ADVISOR_DIR检出执行顾问入口,而 PR 工作区只是惰性的分析数据("PR workspaces remain inert analysis data only")。这保证了顾问代码(包括上述所有辅助模块)永远来自仓库可信检出,而不是来自被分析 PR 的内容——在e2e-recommendations.mts中这一点体现为TRUSTED_REPO_ROOT与process.cwd()的区分:读取受信任工作流用前者,读取 PR 变更来源用后者。 - 生产顾问不依赖仓库开发依赖(TypeScript、Vitest 等),清单读取器只用 Node.js 内建模块与已检入模块。这与仓库中 tools/pr-review-advisor/ 的专家入口(
specialists/下 9 个专家定义、blocker-gate.mts、deterministic-context.mts、specialist-catalog.mts等)配合,构成了"确定性外壳 + 模型推理内核"的整体架构。
与这套顾问基础设施配套的工作流包括 .github/workflows/pr-review-advisor.yaml(顾问执行入口)与 .github/workflows/e2e.yaml(维护者显式运行 live E2E 的受信任工作流);风险计划本身的正确性由 test/automation/pull-requests/ 下的测试保障(risk-plan.mts源码注释提到test/automation/pull-requests/pr-risk-plan.test.ts持续守护清单的"有意且有界")。
小结
tools/advisors/用约 13 个 TypeScript 模块,为 NemoClaw 的模型驱动审查体系提供了四层确定性保障:
- 访问边界:只读工具被路径守卫与 16 KiB 字节上限双重约束,顾问无法越出仓库、无法产生失控输出;
- 行为边界:回合协议把"读证据 → 调工具 → 输出分析 → 终态提交"编排为可校验的事件流,并提供三类有限修复通道;
- 内容边界:风险计划与 E2E 清单由受信任代码确定性地从变更文件推导,模型只能从受信标识符中挑选,且无法移除 Brev 等确定性推荐;
- 运行边界:生产执行不依赖开发依赖,工作流只从可信检出运行顾问代码。
这套设计回答了"如何让 LLM 参与代码审查而不失可控性"的问题:模型的自由度被严格限定在"分析"与"选择受信标识符"之内,凡是可能影响正确性、安全性与可审计性的环节,全部由确定性代码接管。
【免费下载链接】NemoClawRun agents like Hermes, LangChain Deep Agents, and OpenClaw more securely inside NVIDIA OpenShell with managed inference项目地址: https://gitcode.com/gh_mirrors/ne/NemoClaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考