Skip to content

feat(external-context): Add provider extension profile - #9068

Merged
doudouOUC merged 6 commits into
QwenLM:mainfrom
doudouOUC:feat/external-context-provider-profile
Aug 16, 2026
Merged

feat(external-context): Add provider extension profile#9068
doudouOUC merged 6 commits into
QwenLM:mainfrom
doudouOUC:feat/external-context-provider-profile

Conversation

@doudouOUC

Copy link
Copy Markdown
Collaborator

What this PR does

This PR defines an External Context Provider Extension Profile v1 so provider teams can ship independently owned retrieval integrations through the existing Qwen Extension and MCP boundary instead of adding provider-specific adapters to Qwen Core.

It publishes strict, language-neutral context_search input and output schemas with conformance vectors; aligns the existing reference MCP tool with that contract and returns equivalent text and structured results; and adds provider-owned remote OAuth and self-contained local REST adapter examples. The accompanying design and integration documentation defines ownership, authentication, timeout, output-sanitization, trust, packaging, and rollout boundaries.

Why it's needed

The existing Generic HTTP adapter proves that Qwen can retrieve external context, but it is a private compatibility implementation rather than a sustainable integration surface for every provider. Without a portable profile, each new provider would either require a Qwen-maintained adapter or invent an incompatible MCP shape. This profile keeps the integration boundary small, uses Qwen's existing Extension lifecycle, prevents model-selected corpus or endpoint scope, and gives provider teams a concrete contract and copyable starting points.

Reviewer Test Plan

How to verify

Confirm that the reference MCP advertises only the exact query input, rejects undeclared selector fields before calling the provider, declares the bounded output schema, and returns semantically identical JSON through its text and structuredContent results. Validate the published test vectors against both the language-neutral schemas and the reference/local runtime schemas. Build the local example and invoke it against a loopback fake REST provider; it should expose only context_search, send one normalized fixed-limit request with the administrator-bound credential, escape literal angle brackets in text output, and preserve the original content in structured output. Finally, verify the local and parent package dry runs include the intended contracts, source examples, manifests, and self-contained local bundle without credentials.

Local verification completed with 11 external-context test files and 185 tests passing, the external-context and repository build/typecheck/lint commands passing, a real bundled REST-to-stdio-MCP smoke test passing, and both package dry runs containing the expected files.

Evidence (Before & After)

N/A — this PR adds a non-UI interoperability profile, reference behavior, documentation, and examples.

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

Environment (optional)

macOS 26.4.1 (25E253), arm64, Node.js v24.12.0, npm 10.9.8, sandbox disabled for the loopback smoke test.

Risk & Scope

  • Main risk or tradeoff: The existing reference context_search tool now rejects undeclared arguments instead of silently ignoring them, and provider-owned local adapters inherit the security boundary of the Qwen process environment and same-UID code.
  • Not validated / out of scope: Windows and Linux are left to CI; production provider authentication, authorization, availability, logging, and release provenance remain provider responsibilities; writes, Auto Recall, ingestion, resources, prompts, and a public SDK are outside this profile. Persisted Extension settings are not advertised as a credential path because their startup-to-MCP-child hydration still needs a separate Core fix and E2E.
  • Breaking changes / migration notes: Query-only callers are unchanged. Callers that sent undeclared tenant, repository, filter, endpoint, credential, or metadata fields must remove them. Provider extensions must use a provider-specific stable name and keep their profile manifest allowlist restricted to context_search.

Linked Issues

Refs #7585

中文说明

本 PR 的改动

本 PR 定义 External Context Provider Extension Profile v1,使 Provider 团队能够通过现有 Qwen Extension 与 MCP 边界独立发布检索集成,而不需要向 Qwen Core 增加 Provider 专用适配器。

它发布严格、与语言无关的 context_search 输入输出 schema 和一致性测试向量;让现有参考 MCP 工具遵循该契约,并同时返回语义一致的文本结果与结构化结果;同时提供由 Provider 维护的远程 OAuth 示例和自包含本地 REST 适配器示例。配套设计与集成文档明确了所有权、认证、超时、输出净化、信任、打包和灰度边界。

为什么需要

现有 Generic HTTP 适配器证明了 Qwen 可以检索外部上下文,但它是私有兼容性实现,并不是让所有 Provider 持续接入的长期接口。如果没有可移植 profile,每个新 Provider 要么需要 Qwen 维护新的适配器,要么会自行发明不兼容的 MCP 形态。该 profile 保持集成边界最小化,复用 Qwen 现有 Extension 生命周期,禁止模型选择语料库或 endpoint 范围,并为 Provider 团队提供明确契约和可复制起点。

Reviewer 测试计划

验证方式

确认参考 MCP 仅声明精确的 query 输入,在调用 Provider 前拒绝未声明的 selector 字段,声明有界输出 schema,并通过文本和 structuredContent 返回语义完全相同的 JSON。使用已发布测试向量同时验证与语言无关的 schema、参考运行时 schema 和本地示例运行时 schema。构建本地示例并针对回环 Fake REST Provider 调用:它应仅暴露 context_search,携带管理员绑定凭证发送一次规范化且固定结果上限的请求,在文本输出中转义字面量尖括号,并在结构化输出中保留原始内容。最后确认本地包与父包的 dry run 只包含预期契约、源码示例、manifest 和自包含本地 bundle,且不包含凭证。

本地验证结果为:external-context 的 11 个测试文件和 185 个测试全部通过,external-context 与仓库级 build/typecheck/lint 全部通过,真实 bundled REST-to-stdio-MCP smoke test 通过,两个包的 dry run 均包含预期文件。

证据(改动前后)

N/A — 本 PR 添加的是非 UI 互操作 profile、参考行为、文档和示例。

测试平台

OS 状态
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

环境(可选)

macOS 26.4.1 (25E253),arm64,Node.js v24.12.0,npm 10.9.8;回环 smoke test 在禁用 sandbox 的环境中运行。

风险与范围

  • 主要风险或取舍:现有参考 context_search 工具现在会拒绝未声明参数,不再静默忽略;Provider 维护的本地适配器继承 Qwen 进程环境与同 UID 代码的安全边界。
  • 未验证 / 范围外:Windows 和 Linux 留待 CI 验证;生产 Provider 的认证、授权、可用性、日志和发布来源仍由 Provider 负责;写入、Auto Recall、摄取、resources、prompts 和公共 SDK 不属于该 profile。当前不把持久化 Extension settings 宣传为凭证路径,因为其启动到 MCP 子进程的注入仍需独立 Core 修复和 E2E。
  • 破坏性变更 / 迁移说明:仅使用 query 的调用方不受影响。曾发送未声明 tenant、repository、filter、endpoint、credential 或 metadata 字段的调用方必须移除这些字段。Provider Extension 必须使用 Provider 专用的稳定名称,并将 profile manifest allowlist 限制为 context_search

关联 Issue

Refs #7585

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

E2E and final verification report

Validated commit: e41db9211d4563991ce7116eb7e08f26d667b7a1

Platform: macOS 26.4.1 (25E253), arm64, Node.js v24.12.0, npm 10.9.8.

  • External Context workspace: 11 test files / 185 tests passed; build, typecheck, and lint passed.
  • Repository: build, typecheck, and lint passed.
  • Bundled local adapter smoke: a real stdio MCP child connected to a loopback fake REST Provider, advertised exactly context_search, sent exactly one normalized POST /v1/context/search request with fixed limit: 5 and the administrator-bound authorization header, returned no error, escaped literal angle brackets in the text block, and preserved semantically identical content in structuredContent.
  • Packaging: the local example dry run contained only its README, manifest, package metadata, and self-contained dist/main.js; the parent integration dry run contained the published contracts, examples, manifests, and compiled profile artifacts.
  • Credential-path audit: the official Extension install and sensitive-settings commands stored test values in the isolated encrypted settings file, but a fresh Qwen process did not hydrate those persisted values into the MCP child environment. Supplying the same value through the administrator-controlled ambient environment succeeded. This PR therefore intentionally documents environment delivery only and leaves settings hydration to a separate Core fix.
  • Final review: two consecutive open-ended diff audits completed without a new actionable issue; git diff --check passed.

E2E 与最终验证报告

验证提交:e41db9211d4563991ce7116eb7e08f26d667b7a1

平台:macOS 26.4.1 (25E253),arm64,Node.js v24.12.0,npm 10.9.8。

  • External Context workspace:11 个测试文件 / 185 个测试全部通过;build、typecheck 和 lint 通过。
  • 仓库级验证:build、typecheck 和 lint 通过。
  • Bundled 本地适配器 smoke:真实 stdio MCP 子进程连接回环 Fake REST Provider,仅声明 context_search,携带管理员绑定 authorization header 精确发送一次规范化的 POST /v1/context/search 请求和固定 limit: 5,结果无错误;文本块转义字面量尖括号,structuredContent 保留语义完全一致的内容。
  • 打包:本地示例 dry run 仅包含 README、manifest、包元数据和自包含 dist/main.js;父集成包 dry run 包含已发布契约、示例、manifest 与编译后的 profile 产物。
  • 凭证路径审计:官方 Extension 安装和敏感设置命令能将测试值写入隔离的加密设置文件,但新启动的 Qwen 进程没有把持久化值注入 MCP 子进程环境;通过管理员控制的 ambient environment 提供同一值时对照组成功。因此本 PR 有意只记录环境变量交付方式,将 settings hydration 留给独立 Core 修复。
  • 最终审计:完成两轮连续开放式 diff 审计,未发现新的明确可执行问题;git diff --check 通过。

@doudouOUC doudouOUC self-assigned this Aug 13, 2026
@doudouOUC
doudouOUC marked this pull request as ready for review August 14, 2026 03:26
@doudouOUC
doudouOUC enabled auto-merge August 14, 2026 03:26
@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Gate re-run at the current head — conclusions unchanged, the gate passes.

Template looks good ✓

Problem: Unchanged from prior passes — this is the next planned increment of the Direct External Context roadmap (#7585), with five prior increments already merged. The gap it addresses (without a portable profile, every provider needs a Qwen-maintained adapter or invents an incompatible MCP shape) is documented and real, not theoretical.

Direction: Aligned, for the same reasons as before — provider integrations stay on the existing Extension + MCP surface, and the diff still carries zero packages/** changes, so the "no Qwen Core change" rollout step holds at this head too.

Size: Not applicable — no core paths touched (docs, integrations/external-context/, and lockfile only).

Approach: Scope still right. The five fix commits since the first pass are all hardening within the stated scope — contract bounds, packaging, and proxy semantics. The last commit swaps the example's HTTP proxying from default CONNECT tunneling to forward-proxy semantics, which is exactly the regression round 5 flagged; no drive-by changes spotted.

Risk: No elevated risk signals — none of the changed files match the revert-correlated paths.

Moving on to code review. 🔍

中文说明

在当前 head 上重新准入门禁——结论不变,门禁通过。

模板完整 ✓

问题:与之前各轮一致——这是 Direct External Context 路线图(#7585)的下一个既定增量,此前五个增量已合并。它解决的缺口(没有可移植 profile,每个 provider 都要 Qwen 维护适配器或自造不兼容的 MCP 形态)有记录且真实,不是理论性问题。

方向:对齐,理由不变——provider 集成保持在现有 Extension + MCP 边界上,diff 依然零 packages/** 改动,"不改 Qwen Core" 的灰度承诺在当前 head 依然成立。

规模:不适用——未触及核心路径(仅 docs、integrations/external-context/ 与 lockfile)。

方案:范围依然合理。首轮之后的五个 fix commit 全部是既定范围内的加固——契约边界、打包、代理语义。最后一个 commit 把示例的 HTTP 代理从默认 CONNECT 隧道改为正向代理语义,正是第 5 轮指出的回归;未发现夹带改动。

风险:无升级风险信号——改动文件均未命中与 revert 相关的高风险路径。

进入代码审查 🔍

Qwen Code · qwen3.8-max

Reviewed at a41ed5f9833a446cfc5b95559f52627ed37c5862 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Code review

Re-run at the new head, five fix commits after the pass that requested changes. Both prior blockers are resolved, and I verified each statically at this exact commit rather than taking the round summaries on faith:

  • The packaging defect is fixed. integrations/external-context/package.json's files allowlist now carries examples/provider-extension-local/dist/main.js, and the new pack-content test (packs an executable that fails fast without provider configuration) runs npm pack --dry-run --json on the parent package, asserts that exact path is packed, and asserts the manifest's launch args point at it. CI runs it green. The packed archive now ships what the manifest declares — the profile's core promise.
  • The round-5 Critical (proxy CONNECT regression) is fixed — I verified the semantics against upstream source. The example now installs new EnvHttpProxyAgent({ proxyTunnel: false }). I read undici 7.29.0's proxy-agent.js (the version this package locks): with proxyTunnel false, an http: origin through an http: proxy routes to Http1ProxyWrapper — classic absolute-form forward proxying — while every other case, including all https: origins, still tunnels via CONNECT; EnvHttpProxyAgent forwards the option into both protocol agents. So HTTP providers get forward-proxy semantics and HTTPS providers keep CONNECT, exactly as the author claims. The new regression test pins the HTTP path with a real local proxy socket — it asserts the absolute-form POST arrives at the proxy and zero CONNECT requests do — and the fail-fast test covers an invalid proxy URL (Provider proxy configuration is invalid., exit 1).

Everything the earlier passes credited still holds at this head:

  • Contract enforcement is real. Strict zod input (.strict(), so the MCP SDK rejects undeclared fields before the handler runs), declared bounded output schema, structuredContent returned as JSON.parse of the rendered text so both results are semantically identical; mcp.test.ts drives all of it through a real MCP client.
  • Bounds have a single source of truth. provider-profile.ts imports the item/query/render limits from context.ts, and the new guards there (skip items missing id/content, drop non-finite score) keep the rendered envelope inside the strict output schema. The language-neutral JSON Schemas and test vectors under contracts/v1/ match those bounds.
  • The example stays self-contained by design. It re-implements the bounds/rendering instead of importing the private package, has zero runtime dependencies (pinned by manifest.test.ts), and the conformance tests keep the copy aligned.

Non-blocking observations, for the record:

  • The dead examples/*.json entry in files (matches nothing — manifests live one level deeper) survived this round. Cosmetic; npm ignores it.
  • The bundled example grew from ~942 KB to ~1.9 MB because undici is now bundled into dist/main.js — a forced consequence of the no-runtime-dependency constraint above, so a tradeoff, not a defect. CI's esbuild ⚠️ is the size warning, not an error.
  • R6-1 from the latest /review round stands as a suggestion: the example's malformed-response branches (Provider response is invalid. for non-JSON / wrong-shape bodies) have no dedicated test — the 1 MiB bound and redirect paths do.
  • R5-2…R5-6 remain deferred under the five-round cap and are recorded in the author's round-5 summary comment, per policy — nothing silently dropped.

Test evidence (this PR's own CI, via API)

Unattended run — per the static-review rule I did not build or execute PR code; the evidence below is the PR's own CI on the reviewed commit, read through the API. Nothing here is TUI-visible, so no live product run applies.

All 226 check runs on this commit settled: 22 success, 199 skipped, 0 failure (the 5 cancelled entries are all route jobs of the Qwen Autofix orchestration workflow — superseded runs, not PR CI). From the Test (ubuntu-latest, Node 22.x) job log:

> npm run clean && tsc --build && npm --prefix examples/provider-extension-local run build
  dist/main.js  1.9mb ⚠️
...
 ✓ src/provider-extension-local.test.ts (15 tests) 6428ms
   ✓ local provider extension example > serves the exact profile tool with stable failure and cancellation semantics
   ✓ local provider extension example > packs an executable that fails fast without provider configuration
 Test Files  12 passed (12)
      Tests  201 passed (201)

That suite includes the new real-socket proxy test and the pack-content test, plus the repo's core suite (53 files / 1150 passed, 9 skipped) in the same job. The macOS/Windows Test jobs and the CLI integration job are skipped by workflow design (merge queue only), not a gap caused by this PR.

Check Conclusion
Test (ubuntu-latest, Node 22.x) ✅ success
Test (macos-latest, Node 22.x) ⏭️ skipped (merge queue only)
Test (windows-latest, Node 22.x) ⏭️ skipped (merge queue only)
Integration Tests (CLI, No Sandbox) ⏭️ skipped (merge queue only)
precheck-pr / precheck ✅ success
Desktop Shell (ubuntu-22.04 / windows-2022) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Real daemon E2E / Java 11 ✅ success
SDK Java (ubuntu / macos / windows, Java 21) ✅ success
Security Checks (TruffleHog, dependency CVE audit) ✅ success

Sandboxed verification is in flight on this exact head as part of the current triage run (run 31938434218); its report will post here when it completes. What it will settle that CI does not: the bundled example driven end-to-end against a loopback provider on this head, and the A/B wire-level proof of the rejection-before-provider behavior — the earlier ✅ verify report was run against the first commit e41db921, before the five hardening commits, and should not be read as covering the current head. CI's own tests already pin the proxy semantics and the pack contents with real sockets and a real npm pack, so the in-flight run is confirmation, not the only evidence.

中文说明

代码审查:在请求修改之后的五个 fix commit 基础上,于新 head 重新审查。此前两个阻塞项均已解决,且我是在本 commit 上静态核实、而非轻信轮次汇总:

  • 打包缺陷已修复。 files 白名单现已包含 examples/provider-extension-local/dist/main.js,新增的包内容测试对父包执行 npm pack --dry-run --json,断言该路径被打包、且 manifest 的启动 args 指向它。CI 中该测试为绿。打包归档现在确实携带 manifest 所声明的产物——这正是 profile 的核心承诺。
  • 第 5 轮的 Critical(代理 CONNECT 回归)已修复——我对照上游源码核实了语义。 示例现在安装 new EnvHttpProxyAgent({ proxyTunnel: false })。我读了本包锁定的 undici 7.29.0 的 proxy-agent.jsproxyTunnel 为 false 时,经 http: 代理的 http: 目标走 Http1ProxyWrapper——经典绝对形式正向代理——其余所有情形(包括全部 https: 目标)仍走 CONNECT 隧道;EnvHttpProxyAgent 会把该选项传给两个协议的 agent。即 HTTP provider 获得正向代理语义、HTTPS provider 保持 CONNECT,与作者所述一致。新回归测试用真实本地代理 socket 钉住 HTTP 路径——断言代理收到绝对形式 POST 且 CONNECT 数为零——fail-fast 测试覆盖非法代理 URL(Provider proxy configuration is invalid.,退出码 1)。

此前各轮认可的结论在当前 head 依然成立:

  • 契约强制执行真实落地。 严格 zod 输入(.strict(),未声明字段在 MCP SDK 层即被拒绝)、声明的有界输出 schema、structuredContent 由渲染文本 JSON.parse 得到从而语义一致;mcp.test.ts 通过真实 MCP 客户端全链路驱动。
  • 边界只有一份真源。 provider-profile.tscontext.ts 导入条目/query/渲染上限;context.ts 新增守卫(跳过缺 id/content 的条目、丢弃非有限 score)保证渲染结果不越出严格输出 schema。contracts/v1/ 的 JSON Schema 与测试向量与这些边界一致。
  • 示例按设计保持自包含。 重新实现边界/渲染而不导入私有包、零运行时依赖(由 manifest.test.ts 钉住)、一致性测试防止两份实现走样。

非阻塞观察项,留档:

  • files 中无效的 examples/*.json 条目(匹配不到任何文件——manifest 在更深一层)本轮仍在。纯外观问题,npm 会忽略。
  • bundled 示例从约 942 KB 增至约 1.9 MB,因为 undici 现在被打包进 dist/main.js——这是上述"零运行时依赖"约束的必然结果,属取舍而非缺陷。CI 里 esbuild 的 ⚠️ 是体积警告,不是错误。
  • 最新一轮 /review 的 R6-1 仍属建议级:示例的畸形响应分支(非 JSON / 形状错误的 Provider response is invalid.)没有专门测试——1 MiB 边界与 redirect 路径有。
  • R5-2…R5-6 按五轮上限规则延期,并已记录在作者的第 5 轮处理汇总评论中——没有静默丢弃。

测试证据(本 PR 自己的 CI,通过 API 读取):无人值守运行——按静态审查规则未构建或执行 PR 代码;以上证据是被审 commit 上本 PR 自己的 CI。本 PR 无 TUI 可见变化,无需真机操作。

被审 commit 上 226 个 check run 全部落定:22 成功、199 跳过、0 失败(5 个 cancelled 均为 Qwen Autofix 编排工作流的 route 任务——被取代的运行,不是 PR CI)。Test (ubuntu-latest, Node 22.x) 任务日志显示 workspace 构建(示例 esbuild bundle,1.9 MB)成功,external-context 12 个测试文件 / 201 个测试全部通过,其中包含新的真实 socket 代理测试与包内容测试;同一任务中仓库核心套件 53 文件 / 1150 通过、9 跳过。macOS/Windows Test 与 CLI 集成任务为 skipped——按工作流设计仅在 merge queue 运行,不是本 PR 造成的缺口。

沙箱验证正在当前 head 上随本次 triage 运行进行(run 31938434218),完成后报告会发布在本线程。它将补足 CI 未覆盖的部分:在当前 head 上对 bundled 示例做回环 provider 端到端驱动,以及"触达 provider 前拒绝"的 A/B 线级证明——此前的 ✅ verify 报告运行在第一个 commit e41db921 上(早于五个加固 commit),不应视为覆盖当前 head。CI 自己的测试已用真实 socket 和真实 npm pack 钉住代理语义与打包内容,因此在途运行是确认,而非唯一证据。

Qwen Code · qwen3.8-max

Reviewed at a41ed5f9833a446cfc5b95559f52627ed37c5862 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — six rounds in, both blockers are fixed and test-pinned, CI is green on the head, and what remains is nits; the last point is withheld only because the sandboxed re-verification of this exact head is still in flight.

Honest reflection:

  • This PR is the clearest case I've seen of the review loop working: the first pass approved too early, the packaging defect caught that, the proxy regression caught a real undici behavior change that would have broken HTTP providers behind corporate proxies — and every one of those findings landed as a small, pinned fix rather than scope growth. Five hardening commits, zero drive-by changes, and the deferred round-5 suggestions are recorded in the thread instead of being silently dropped.
  • Against my independent baseline (published contract + reference alignment + two copyable examples + design doc, nothing more), the PR still matches — I looked for a smaller version again and the strictness is the point; cutting it would reintroduce the model-selected-scope hole the profile exists to close.
  • The two prior blockers are resolved in the strongest form available to a static review: the packaging fix is asserted by a pack-content test that CI runs green, and the proxy fix I verified against undici 7.29.0's own source plus a real-socket regression test. I am not approving on the author's word for either.
  • Residual nits, none blocking: the dead examples/*.json files entry, the 1.9 MB bundle (forced by the self-containment constraint), and R6-1's untested malformed-response branches in the example.
  • One honest caveat: the earlier ✅ sandboxed verify ran against the first commit, before the hardening rounds; the fresh run on this head is in flight and will post its report here. CI's own real-socket and real-pack tests already pin the changed behavior, so this approval does not rest on that report — but a maintainer reading this before the report lands should know it is coming.

Approving, pinned to the reviewed commit. @wenshao's first-round review is the remaining human thread — main needs two approvals, so a maintainer re-review stands regardless of this vote.

中文说明

信心:4/5 —— 六轮之后,两个阻塞项均已修复并被测试钉住,当前 head 的 CI 为绿,剩余只有小问题;扣掉的一分仅因为针对当前 head 的沙箱复验仍在运行中。

如实反思:

  • 这个 PR 是审查闭环运作最清楚的案例:首轮过早批准、打包缺陷拦住那一漏、代理回归拦住一个真实的 undici 行为变化(它本会让企业代理后的 HTTP provider 失效)——每一个发现都落为小而钉得住的修复,而不是范围膨胀。五个加固 commit、零夹带改动,延期的第 5 轮建议记录在线程里而非静默丢弃。
  • 对照我的独立基线(发布契约 + 参考实现对齐 + 两个可复制示例 + 设计文档,仅此而已),本 PR 依然吻合——我再次找过更小的版本,但严格性正是重点;砍掉它会重新打开 profile 要封堵的"模型选择范围"漏洞。
  • 两个阻塞项以静态审查所能达到的最强方式解决:打包修复由 CI 跑绿的包内容测试断言;代理修复我对照 undici 7.29.0 源码加真实 socket 回归测试核实。这两点我都不是凭作者陈述而批准。
  • 剩余小问题,均不阻塞:无效的 examples/*.json 条目、1.9 MB 的 bundle(自包含约束所致)、R6-1 中示例未测的畸形响应分支。
  • 一个如实的提醒:此前的 ✅ 沙箱 verify 运行在第一个 commit 上(早于加固各轮);针对当前 head 的新运行在途,报告会发布在本线程。CI 自己的真实 socket 与真实打包测试已钉住变更行为,因此本批准不依赖该报告——但在报告落地前读到这里的 maintainer 应知道它即将到来。

批准,钉在被审 commit 上。@wenshao 的首轮审查是剩余的人类审查线——main 需要两个批准,无论如何都还需 maintainer 复审。

Qwen Code · qwen3.8-max

Reviewed at a41ed5f9833a446cfc5b95559f52627ed37c5862 · re-run with @qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed. Suggestions are inline.

Not explored to full depth (tool budget reached): "PR 9068 adds an External Context Provider Extension…": did not trace whether the native extension-manifest parser strips/ignores a trust field on mcpServers entries (the doc's "ordinary Extension manifests canno…; "PR 9068 adds an External Context Provider Extension…": the design doc's "Qwen's conservative MCP connection replay requires server trust, workspace trust, and explicit safe annotations" — I verified the trust mechan…; "PR 9068 adds an External Context Provider Extension…": the design doc's "conservative MCP connection replay requires server trust, workspace trust, and explicit safe annotations" — verified the trust machinery exist…; "PR 9068 adds an External Context Provider Extension…": none — all checks I started were completed within budget.; "PR 9068 adds an External Context Provider Extension…": none — all planned checks completed within budget..

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未探索到全部深度(达到工具调用预算):"PR 9068 adds an External Context Provider Extension…"did not trace whether the native extension-manifest parser strips/ignores a trust field on mcpServers entries (the doc's "ordinary Extension manifests canno…"PR 9068 adds an External Context Provider Extension…"the design doc's "Qwen's conservative MCP connection replay requires server trust, workspace trust, and explicit safe annotations" — I verified the trust mechan…"PR 9068 adds an External Context Provider Extension…"the design doc's "conservative MCP connection replay requires server trust, workspace trust, and explicit safe annotations" — verified the trust machinery exist…"PR 9068 adds an External Context Provider Extension…"none — all checks I started were completed within budget."PR 9068 adds an External Context Provider Extension…"none — all planned checks completed within budget.

未审查:反向审计——在 5 轮的反审轮数上限内未收敛。

— qwen3.8-max via Qwen Code /review (v0.21.11)

Comment thread integrations/external-context/contracts/v1/test-vectors.json
Comment thread integrations/external-context/src/provider-profile.test.ts Outdated

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its platform-specific suite did not run locally.

中文说明

仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its platform-specific suite did not run locally。

— Qwen via Qwen Code /review (v0.21.11)

Comment thread integrations/external-context/package.json
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check.

Scripted assertions: 175 passed · 0 failed · 175 total

中文 — 判定:✅ 通过 · 可合入(agent 判定)

沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查

脚本断言:175 通过 · 0 失败 · 175 总计

Verification report

PR 9068 — feat(external-context): Add provider extension profile

Verdict: merge-ready — 175/175 scripted assertions passed, 0 failed. Verified head: e41db9211d4563991ce7116eb7e08f26d667b7a1 (merge base 9b392800781cc6b6a3817fd084a9347e4c4c6acb).

中文摘要
  • 结论: merge-ready。175 条脚本化断言全部通过,0 失败;无阻塞性发现。
  • A/B 结论: 核心行为变更(load-bearing)已证明。对同一 loopback 假 provider 的 stdio MCP 线级 A/B:HEAD 构建对带未声明选择器字段(tenant/repository/filter/endpoint/credential/metadata)的 context_search 调用在调用 provider 之前拒绝(fake 收到 0 个请求),base 构建静默接受并调用 provider(1 个请求,字段被丢弃不透传)。query-only 正向控制两臂一致(各 1 次请求、归一化 query、固定 limit 5、Bearer 凭据)。HEAD 额外返回 structuredContent 且与 text 的 JSON 语义一致;</> 转义两臂均有(系既有渲染器)。
  • 本地示例: 对 loopback 假 REST provider 的 E2E 全绿(仅暴露 context_search、单次归一化固定 limit 请求、管理员凭据、text 转义/structured 保留原文);捆绑 dist/main.js无 node_modules 可达的隔离目录中同样 22/22 通过,自包含成立;非 loopback base URL 与缺失 token 均 fail-closed。
  • 契约: test-vectors 对发布 JSON Schema(ajv strict)与运行时 zod 双向分类一致(40 条);astral 边界(2000/2001 code points)两验证器一致;新边界正则对 65k code points 敌对 surrogate-pair 输入保持线性(≤0.6 ms),无 ReDoS。
  • 测试非空: 三个单点突变(strict→strip、删 structuredContent、删 outputSchema 声明)均被其意图行为测试杀死;未突变控制 185/185 绿。
  • 未覆盖: 远程示例仅校验 manifest 形状(OAuth 流程未执行);Mem0/Auto-Recall 路径未被本 PR 修改,仅由套件覆盖;设计文档未行为化验证;Linux 容器环境(未测 Windows/macOS)。

Scope

Central claim: the reference context_search MCP tool now enforces the published v1 profile — undeclared selector fields are rejected at the MCP boundary before any provider call (base silently ignored them), the bounded output schema is declared, and text/structuredContent results are semantically identical JSON.

Secondary claims: (1) the local example adapter behaves per the contract against a loopback REST provider and ships as a self-contained bundle; (2) the published test vectors validate against both the language-neutral JSON Schemas and the runtime schemas.

Central claim — A/B wire oracle

Harness ab-reference.mjs: raw JSON-RPC stdio client drives the compiled dist/main.js of each arm, configured with a generic-http-search-v1 provider pointed at a loopback fake that records every request (method, path, auth header, body). Head arm = repo build at verified head; base arm = scratch worktree at HEAD^1 rebuilt with the same third-party deps (realpath-asserted: zod/SDK/undici resolve to identical versions; the only lockfile delta is test-only ajv, never loaded by the server). Witness: evidence/01-ab-reference-head-vs-base.png.

cell args head (strict) base (lax)
C1 positive control query with whitespace success; 1 provider request; query normalized; limit: 5; Bearer <env token> identical
C2 undeclared fields query + tenant, repository, filter, endpoint, credential, metadata isError; 0 provider requests success; 1 provider request; fields dropped, not forwarded
C3 astral bound 2000 🙂 success; 1 request identical
C4 astral bound+1 2001 🙂 rejected; 0 requests identical
C5 blank query " \t\n " rejected; 0 requests identical
output shape structuredContent present; JSON.parse(text) deep-equals it; </> escaped in text (\u003c), original preserved in structured; validates vs published output schema structuredContent absent; wire outputSchema null; escaping already present

Head 27/27, base 22/22 (base assertions encode the predicted lax behavior; all held). The base wire inputSchema already advertised additionalProperties: false while the call path accepted extra fields — the advertised contract and the enforcement diverged at base; this PR closes that gap (correction to any reading that the PR changed the advertised schema: only enforcement and the output side changed).

Secondary claims

Local example E2E (example-e2e.mjs, witness evidence/02-example-e2e-happy.png): 22/22 — only context_search exposed; exactly one POST /v1/context/search with normalized query, fixed limit: 5, Bearer credential from env; text escapes </>, structuredContent preserves them; undeclared fields rejected with 0 provider calls; 2000/2001 astral bound enforced. Fail-closed cells: non-loopback base URL (4/4) and missing token (4/4) both error with zero requests. Self-containment (evidence/05-example-bundle-isolated.png): the bundled dist/main.js copied to a directory with no node_modules anywhere up-tree passes the identical 22/22 matrix — the require("ajv/dist/runtime/…") strings in the bundle resolve via esbuild's internal module map, not the host.

Contract vectors (vectors-check.mjs, witness evidence/03-vectors-contract-check.png): 40/40 — all 10 published vectors classified identically by ajv (strict, draft-07) and by the runtime zod schemas; astral bounds (2000/2001 query, 1000/1001 content) agree on both validators; adversarial siblings (numeric/null/array query, extra item field, 6 items, wrong notice, missing id) rejected by both. ajv 8.17.1 counts maxLength in code points, matching the runtime regex — no contract/runtime divergence on astral content.

Scaling ladder (regex-ladder.mjs, witness evidence/06-regex-ladder.png): the new unicodeBoundPattern now validates caller-written query text where base used a linear Array.from().length check. Ladder of hostile concatenated-surrogate-pair strings (2k→65k code points, 130k UTF-16 units): every rung ≤ 0.6 ms, no superlinear curve; base-style check on the same input is 4.4 ms. No ReDoS introduced.

Findings

No blocking findings. Informational:

  1. Base advertised strictness it did not enforce (see A/B note). The PR's "breaking change" note ("callers that sent undeclared fields must remove them") is accurate for the enforced boundary; query-only callers verified unchanged (C1 identical on both arms).
  2. Parent tarball ships the example as source (src/*.ts, tsconfig) while the example's own npm pack ships the bundle (dist/main.js, 3 files). This matches the PR text's "local and parent package dry runs" reading; verified by pack-check.sh (15/15), including "no credential/env files" in either tarball.

Vacuity / mutation matrix

Scratch copy of the package; control unmutated 185/185 green (matches author's claim: 11 files, 185 tests). Witness evidence/04-mutation-matrix.png.

mutant result killed by
control (none) 33/33 green (2 files)
M1 inputSchema .strict().strip() 2 red rejects model-selected retrieval scope without calling the provider; keeps runtime schemas aligned with the published vectors
M2 drop structuredContent 3 red parity + astral-bounds tests, via the SDK's own outputSchema enforcement
M3 drop outputSchema declaration 1 red registers only a provider-bound retrieval tool (advertised schema)

Notable: M1 left the wire-schema/ajv vector test green (zod-to-json-schema emits additionalProperties:false even for non-strict shapes) — only the live tools/call test pins enforcement. The new tests are not vacuous.

Targeted gates (head)

  • npm test (package): 11 files / 185 tests passed.
  • npm run typecheck (incl. example): clean.
  • npm run lint: clean; liveness proven by planting an any/unused-var probe (2 errors: @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any), then restoring to green.

Not covered

  • Remote example OAuth flow: manifest-only assertions (shape, scopes, no credential material); no live remote server exercised.
  • Mem0 provider and Auto-Recall hook paths: unchanged by this PR; covered only by the package suite.
  • Design-doc prose (docs/design/external-context-provider-extensions.md): not behaviorally verified.
  • Windows/macOS (Linux node:22-bookworm container only).
  • Metadata snapshot baseRefOid (52cfb189…) predates the merge; A/B used the actual merge base HEAD^1 (9b392800…). Single PR commit reachable locally and matches the snapshot's commits array.
  • Whether the SDK validates tool input via the zod object or the converted JSON Schema was not attributed; behavior verified at the wire, which is what the contract claims.

Methodology

Environment: CI merge-ref checkout (depth 2), pre-built at head; all harnesses drove compiled dist/ output over real stdio sockets and real loopback HTTP (no mocks of the code under test). Raw logs in logs/ (ab-head.txt, ab-base.txt, example-*.txt, vectors.txt, regex-ladder.txt, pack-check.txt, gate logs); harnesses and capture scripts are in this directory (ab-reference.mjs, example-e2e.mjs, vectors-check.mjs, regex-ladder.mjs, pack-check.sh, capture-ab.sh, mutation-matrix.sh). Assertion totals count only executed scripted checks; expected base-arm reds are encoded as passing assertions.

Evidence images

01-ab-reference-head-vs-base

02-example-e2e-happy

03-vectors-contract-check

04-mutation-matrix

05-example-bundle-isolated

06-regex-ladder

Harness scripts and raw logs are in the workflow run artifacts (7-day retention).

Qwen Code · sandboxed verification

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs one fix before merge: the parent package's files allowlist packs the local example's manifest but not the dist/main.js that manifest launches — a packed archive ships an example extension that cannot start. Details and the suggested fix (plus a package-content test to keep it pinned) are in my Stage 2 comment. This supersedes my earlier approval of this commit. 🙏

合并前需要一处修复:父包的 files 白名单打包了本地示例的 manifest,却没有打包该 manifest 启动所需的 dist/main.js——打包归档会携带一个无法启动的示例扩展。详情与建议修复(并加一个包内容测试保持钉住)见我的 Stage 2 评论。本评审取代我此前在同一 commit 上的批准。

Qwen Code · qwen3.8-max

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Review fixes pushed

Commit: 0c9931bde204e798511cdc6a847475e4a621cda8

Feedback Action
Parent package omitted the local example executable Fixed: the bundle is explicitly packed and a package-content regression test verifies the manifest target.
Published conformance vectors left contract constraints unpinned Fixed: added complete negative vectors, including the additional missing-ID and empty optional-field cases found during independent verification.
Copyable example runtime lacked CI coverage Partially accepted: added focused coverage for normalization, rendering, request/redirect guards, and packaging; the existing real stdio smoke remains E2E evidence.
Empty required fields produced contract-invalid output Fixed in both the copyable and reference renderers with regression coverage.
Non-finite scores produced divergent invalid output Fixed in both renderers with regression coverage.
Example-schema failures omitted vector names Fixed: all aligned assertions now identify the failing vector.

Validation: External Context 12 files / 191 tests passed; External Context build, typecheck, and lint passed; repository build, typecheck, and lint passed; independent test-engineer reproduction and post-fix verification passed; two consecutive open-ended audits were clean.

中文说明

评审修复已推送

提交:0c9931bde204e798511cdc6a847475e4a621cda8

反馈 处理
父包遗漏本地示例可执行文件 已修复:显式打包 bundle,并增加 package-content 回归测试验证 manifest 目标。
已发布一致性向量未覆盖全部契约约束 已修复:补齐完整反向向量,并加入独立复核发现的 missing-ID 和空可选字段场景。
Copyable 示例运行时缺少 CI 覆盖 部分采纳:增加 normalization、rendering、请求/重定向防护和打包的定向覆盖;真实 stdio smoke 继续由现有 E2E 证据覆盖。
空必填字段产生契约非法输出 已在 copyable renderer 与 reference renderer 中修复并增加回归覆盖。
非有限分数产生分歧且非法的输出 已在两个 renderer 中修复并增加回归覆盖。
Example schema 失败不包含向量名 已修复:所有对齐断言现在都会标识失败向量。

验证:External Context 12 个文件 / 191 项测试通过;External Context build、typecheck、lint 通过;仓库 build、typecheck、lint 通过;独立 test-engineer 复现和修复后验证通过;两轮连续开放式审计清洁。

@doudouOUC
doudouOUC requested a review from wenshao August 15, 2026 14:42
@doudouOUC

doudouOUC commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Not reviewed: reverse audit — stopped at the 5-round cap without converging (round 5 still reported a finding; every reported finding was probe-verified).

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its platform-specific suite did not run locally.

Not explored to full depth (tool budget reached): "agent 1b": could not run src/provider-extension-local.test.ts (pack regression test) or src/manifest.test.ts — a concurrent pipeline job on this shared runner was mid-….

中文说明

仅完成部分审查,审查缺口已披露。

未审查:reverse audit — stopped at the 5-round cap without converging (round 5 still reported a finding; every reported finding was probe-verified)。

未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its platform-specific suite did not run locally。

未探索到全部深度(达到工具调用预算):"agent 1b"could not run src/provider-extension-local.test.ts (pack regression test) or src/manifest.test.ts — a concurrent pipeline job on this shared runner was mid-…

— qwen3.8-max via Qwen Code /review (v0.21.12)

Comment thread integrations/external-context/src/provider-profile.ts
Comment thread integrations/external-context/src/mcp.test.ts Outdated
Comment thread integrations/external-context/src/provider-extension-local.test.ts Outdated
Comment thread integrations/external-context/src/provider-extension-local.test.ts
Comment thread integrations/external-context/src/mcp.test.ts
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Review round 2 follow-up

Pushed 711caff5d3 to address the new review batch.

  • Replaced the ambiguous Unicode-bound pattern in both profile copies with a flag-independent, non-overlapping surrogate decomposition. The real MCP-advertised pattern now rejects 2001 emoji without flags in about 0.014 ms instead of exponential backtracking, while preserving ASCII, astral, and lone-surrogate semantics.
  • Added regression coverage for the example renderer's best === 0 budget branch, fail-closed provider configuration, unresolved placeholders, the 1 MiB streamed response cap, exact authorization and cancellation propagation, astral-bound field preservation, npm-less test execution, and contract-vector cardinalities.
  • Kept the conservative three-literal HTTP loopback allowlist unchanged. Broader 127/8 and mapped-IPv6 parsing is outside this hardening scope and the current policy matches the existing private reference.

Validation: External Context 196/196 tests; focused 43/43 tests; bare Vitest 9 passed/1 npm-dependent pack test skipped; External Context build/typecheck/lint; repository build/typecheck/lint; independent no-flags regex probes; two clean diff audits.

中文说明

第二轮评审跟进

已推送 711caff5d3,处理本轮新增评审意见。

  • 将两处 profile 副本中的歧义 Unicode 边界正则替换为与 flags 无关、分支不重叠的代理项分解。真实 MCP 对外广播的正则现在在无 flags 下约 0.014 ms 即可拒绝 2001 个 emoji,不再指数回溯,同时保持 ASCII、astral 与孤立 surrogate 的语义一致。
  • 补充示例 renderer 的 best === 0 预算分支、fail-closed Provider 配置、未解析占位符、1 MiB 流式响应上限、Authorization 与取消信号精确转发、astral 边界字段完整保留、无 npm 环境测试执行,以及契约向量基数的回归覆盖。
  • 保持保守的三个 HTTP 回环字面量白名单不变。扩展到完整 127/8 与 IPv4-mapped IPv6 需要额外解析和安全设计,超出本次 hardening 范围;当前策略也与既有私有参考实现一致。

验证:External Context 196/196 测试;定向测试 43/43;裸 Vitest 9 通过、仅跳过 1 个依赖 npm 的打包测试;External Context build/typecheck/lint;仓库级 build/typecheck/lint;独立无 flags 正则探测;两轮干净 diff 审计。

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: reverse audit — stopped at the 5-round cap without converging (round 5 still reported a finding; every reported finding was probe-verified).

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) and Test (macos-latest, Node 22.x) were skipped in CI (merge queue only) and their platform-specific suites did not run locally.

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:reverse audit — stopped at the 5-round cap without converging (round 5 still reported a finding; every reported finding was probe-verified)。

未审查:build-and-test — Test (windows-latest, Node 22.x) and Test (macos-latest, Node 22.x) were skipped in CI (merge queue only) and their platform-specific suites did not run locally。

— qwen3.8-max via Qwen Code /review (v0.21.12)

Comment thread integrations/external-context/src/provider-profile.test.ts Outdated
Comment thread integrations/external-context/src/mcp.test.ts Outdated
Comment thread integrations/external-context/contracts/v1/test-vectors.json
Comment thread integrations/external-context/src/provider-extension-local.test.ts
Comment thread integrations/external-context/src/provider-extension-local.test.ts Outdated
Comment thread integrations/external-context/src/provider-extension-local.test.ts
Comment thread integrations/external-context/src/provider-profile.test.ts
Comment thread integrations/external-context/src/provider-extension-local.test.ts
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Review round 3 follow-up

Pushed a0755c58de to address all 11 new review suggestions.

Action Result
Fixed Added provider-item mapping coverage for snake/camel timestamps, title/URI passthrough, and wrong-type dropping.
Fixed Replaced both latent NodeNext-incompatible Ajv default imports with the named export.
Fixed Expanded the published conformance vectors to pin minimal items, exactly five items, Unicode code-point limits, and over-bound input/output rejection.
Fixed Added fail-fast, sanitized startup validation for missing and malformed local-provider configuration.
Fixed Pinned exact query bounds, all three existing loopback origins, POST request shape, both Ajv and runtime Zod render validation, and exact-1-MiB response acceptance.
Rejected / deferred None. No provider behavior, allowlist, configuration surface, or profile scope was broadened.

Validation: External Context 199/199 tests; focused 46/46 tests; package build/typecheck/lint; repository build/typecheck/lint; published-vector schema sweep; two consecutive clean diff audits; independent read-only test-engineer verification.

中文说明

第三轮评审跟进

已推送 a0755c58de,处理全部 11 条新增评审建议。

操作 结果
已修复 补充 Provider item 映射覆盖,包括 snake/camel 时间戳、title/URI 透传和错误类型丢弃。
已修复 将两处 NodeNext 下潜在不可构造的 Ajv 默认导入改为命名导出。
已修复 扩展公开一致性向量,钉住最小 item、恰好 5 个 item、Unicode 码点边界以及输入/输出越界拒绝。
已修复 为缺失或格式错误的本地 Provider 配置增加启动前校验,并仅输出脱敏错误。
已修复 钉住精确查询边界、三个既有 loopback origin、POST 请求形状、Ajv 与运行时 Zod 双重渲染校验,以及恰好 1 MiB 响应的接受行为。
拒绝 / 延期 无。未扩大 Provider 行为、白名单、配置面或 Profile 范围。

验证:External Context 199/199 测试;定向 46/46 测试;包级 build/typecheck/lint;仓库级 build/typecheck/lint;公开向量 schema 扫描;连续两轮干净 diff 审计;独立只读测试工程师验证。

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) and Test (macos-latest, Node 22.x) were skipped in CI (merge queue only) and their platform-specific suites did not run locally.

Not explored to full depth (tool budget reached): "agent reverse-audit (round 4)": tracing the exact merge point where extension-contributed MCP servers reach the effective server map, to rule out a process.env-based ${VAR} resolution pass o…; "agent reverse-audit (round 4)": tracing the extension-MCP-server merge point end-to-end to rule out (or confirm) a process.env-based ${VAR} resolution pass over manifest env values.; "agent reverse-audit (round 4)": verifying the doc's "the provider receives the normalized query" claim against the example's tool handler ( examples/provider-extension-local/src/provider.ts ) ….

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:build-and-test — Test (windows-latest, Node 22.x) and Test (macos-latest, Node 22.x) were skipped in CI (merge queue only) and their platform-specific suites did not run locally。

未探索到全部深度(达到工具调用预算):"agent reverse-audit (round 4)"tracing the exact merge point where extension-contributed MCP servers reach the effective server map, to rule out a process.env-based ${VAR} resolution pass o…"agent reverse-audit (round 4)"tracing the extension-MCP-server merge point end-to-end to rule out (or confirm) a process.env-based ${VAR} resolution pass over manifest env values."agent reverse-audit (round 4)"verifying the doc's "the provider receives the normalized query" claim against the example's tool handler ( examples/provider-extension-local/src/provider.ts ) …

未审查:反向审计——在 5 轮的反审轮数上限内未收敛。

— qwen3.8-max via Qwen Code /review (v0.21.12)

Comment thread integrations/external-context/src/provider-extension-local.test.ts Outdated
Comment thread integrations/external-context/src/provider-extension-local.test.ts
Comment thread integrations/external-context/src/provider-extension-local.test.ts
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Review round 4 fixes are available in f6741c13f1.

Item Decision Action
Environment proxy support Fixed Installed an environment-aware undici dispatcher in the copyable local example, sanitized invalid proxy configuration, documented proxy variables, and preserved ESM bundle startup with a createRequire banner.
Real MCP failure/cancellation/timeout coverage Fixed Added a stdio MCP child test covering exact tool exposure, redacted provider failures, cancellation propagation, and the approximately five-second provider timeout.
Fail-fast child exit Fixed Asserted exit code 1 and killed: false for missing, invalid, and invalid-proxy configuration.
Manifest/tool-name pairing Fixed Asserted the built server exposes exactly context_search.
Metadata-before-content budget behavior Fixed Added a regression case proving optional metadata is stripped before content truncation.

Rejected or deferred: none.

Verification: Node 22 bundle/startup smoke, Prettier check, package typecheck, lint, build, and all 200 external-context tests passed. Independent isolated mutation and stdio probes confirmed all five findings and the selected remedies.


第 4 轮评审修复已包含在 f6741c13f1

项目 决策 处理
环境代理支持 已修复 在可复制的本地示例中安装支持环境变量的 undici dispatcher,对非法代理配置返回脱敏启动错误,补充代理变量说明,并通过 createRequire banner 保证 ESM bundle 可正常启动。
真实 MCP 失败/取消/超时覆盖 已修复 新增真实 stdio MCP 子进程测试,覆盖精确工具暴露、Provider 失败脱敏、取消传播和约 5 秒 Provider 超时。
快速失败子进程退出 已修复 对缺失配置、非法配置和非法代理配置断言退出码为 1killed: false
Manifest 与工具名配对 已修复 断言构建后的服务器只暴露 context_search
预算压力下先删元数据 已修复 新增回归用例,证明在截断正文前先移除可选元数据。

拒绝或延期:无。

验证:Node 22 bundle/启动冒烟、Prettier、包级 typecheck、lint、build,以及 external-context 全部 200 项测试均通过。独立隔离变异测试和 stdio 探针确认了五条问题及所选修复方案。

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) were skipped in CI (merge queue only) and their platform-specific suites did not run locally.

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.

中文说明

仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) were skipped in CI (merge queue only) and their platform-specific suites did not run locally。

未审查:反向审计——在 5 轮的反审轮数上限内未收敛。

— qwen3.8-max via Qwen Code /review (v0.21.12)

Comment thread integrations/external-context/src/provider-extension-local.test.ts
Comment thread integrations/external-context/src/provider-extension-local.test.ts
Comment thread integrations/external-context/src/provider-profile.ts
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Round 5 review handling summary / 第 5 轮审查处理汇总

Commit: a41ed5f

Item Judgment Action
R5-1 HTTP proxy CONNECT behavior Agree — Critical correctness regression Fixed: EnvHttpProxyAgent now uses forward-proxy semantics for HTTP targets; added a real local proxy regression test. Independent verification confirms HTTPS targets still use CONNECT.
R5-2 lowercase proxy env test isolation Agree — Suggestion Deferred under the round-5 cap; this is test hermeticity, not a production correctness regression.
R5-3 successful real-MCP call coverage Agree — Suggestion Deferred under the round-5 cap; coverage-only, with the component behavior already covered in layers.
R5-4 README environment-file wording Agree — Suggestion Deferred under the round-5 cap; documentation-only.
R5-5 JSON Schema length units Partially agree — Suggestion Deferred: a description can document intent but is non-enforcing and cannot standardize validator implementations.
R5-6 empty bounded-string diagnostic Partially agree — Suggestion Deferred: the diagnostic can improve, but the proposed chained validation may emit duplicate issues; this is non-Critical.

Verification: Prettier check, package typecheck, lint, build, and all external-context tests passed (12 files, 201 tests). Independent probes observed absolute-form POST for HTTP proxying and CONNECT for HTTPS proxying.

After roughly five review rounds, repository policy limits this round to Critical correctness, security, data-loss, and regression fixes; all deferred Suggestions are recorded above rather than silently dropped.


第 5 轮中,R5-1 被确认是生产正确性回归并已修复:HTTP Provider 通过代理时使用经典正向代理请求,同时 HTTPS Provider 仍使用 CONNECT;新增了真实本地代理回归测试。R5-2 至 R5-6 均已独立评估并按约第 5 轮的收敛规则延期:分别属于测试隔离、覆盖补充、文档修正、非强制性的 Schema 说明及非关键诊断改进。

验证已通过:Prettier、包级 typecheck、lint、build,以及 external-context 全部测试(12 个文件、201 个测试)。独立探测也确认 HTTP 使用绝对形式 POST,HTTPS 使用 CONNECT。

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) and Test (macos-latest, Node 22.x) were skipped in CI (merge queue only) and their platform-specific suites did not run locally.

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:build-and-test — Test (windows-latest, Node 22.x) and Test (macos-latest, Node 22.x) were skipped in CI (merge queue only) and their platform-specific suites did not run locally。

— qwen3.8-max via Qwen Code /review (v0.21.12)

@doudouOUC

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check.

Scripted assertions: 445 passed · 0 failed · 445 total

中文 — 判定:✅ 通过 · 可合入(agent 判定)

沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查

脚本断言:445 通过 · 0 失败 · 445 总计

Verification report

PR 9068 — feat(external-context): Add provider extension profile

Verdict: merge-ready — 445/445 scripted assertions passed, 0 failed. Verified head: a41ed5f9833a446cfc5b95559f52627ed37c5862 (merge base 337da2143c8d3139c4789e054d3ddfc667e2c3fd). Follow-up round: previous verification ran at head e41db921… (first PR commit); five hardening commits have landed since (0c9931ba41ed5f). All carried-forward measurements were re-run at the new head — none carried by shortcut.

中文摘要
  • 结论: merge-ready。445 条脚本化断言全部通过,0 失败;无阻塞性发现。
  • 上一轮发现状态: 上轮两条信息级发现均已复核(见状态表)——"base 宣称严格却未执行"已被本 PR 修复并经 A/B 重测;父包/示例包的打包内容划分维持原设计。
  • A/B 结论: 核心行为变更(load-bearing)在新 head 上再次证明。对同一 loopback 假 provider 的 stdio MCP 线级 A/B:HEAD 构建对带未声明选择器字段(tenant/repository/filter/endpoint/credential/metadata)的 context_search 调用在调用 provider 之前拒绝(fake 收到 0 个请求),base 构建静默接受并调用 provider(1 个请求,字段被丢弃不透传)。query-only 正向控制两臂一致。HEAD 额外返回 structuredContent 且与 text 的 JSON 深度相等、保留字面 <>、并通过发布 output schema 校验;base 无 structuredContent/outputSchema
  • 增量(5 个加固提交): 两个新渲染守卫(丢弃空 id/content 条目、丢弃非有限 score)经突变体 M4/M5 证明被测试钉住,且单元探针证明 base 对同样输入渲染出不符合发布 schema 的输出(NaN score 被 base 序列化为 "score":null);本地示例的 proxyTunnel: false 经突变体 M7 钉住,线级单元证明 HTTP_PROXY 时请求以绝对形式转发经代理(非 CONNECT)、NO_PROXY 正确旁路、非法代理配置启动即失败。https 目标仍走 CONNECT 且失败时稳定收敛(信息级说明,见 Findings)。
  • 契约与规模: 28 条发布向量 + 8 条合成边界探针在 ajv(strict) 与参考/示例两个 zod 运行时之间 36/36 一致;判别单元(1000 code points = 2000 UTF-16 units)证明 ajv 按 code point 计数,与运行时正则一致;正则阶梯 2k→65k code points 全部 ≤0.31ms,无 ReDoS。
  • 测试非空: 未突变控制 12 文件 / 201 测试全绿(较上轮 185 增加 16,系加固提交新增);7/7 单点突变体全部被其意图测试杀死,失败消息均为期望-实际行为断言。
  • 门禁: 包级测试 201/201、typecheck(含示例)干净、lint 干净(以植入 any 探针证明存活)。
  • 未覆盖: 远程示例 OAuth 流程(仅 manifest 形状)、Mem0/Auto-Recall 路径(本 PR 未改动)、设计文档文字、Windows/macOS、逐提交归属(depth-2 浅克隆仅可达 1/6 提交)。

Previous-finding status (follow-up round)

# previous finding severity status at new head a41ed5f
1 Base advertised strictness it did not enforce (wire inputSchema had additionalProperties:false while the call path accepted extra fields) informational fixed — re-measured: head rejects undeclared fields with 0 provider requests (C2); base still advertises-and-accepts, confirming the PR closes the enforcement gap. The "breaking change" note remains accurate: query-only callers verified byte-equivalent on both arms (C1).
2 Parent tarball ships the example as source while the example's own pack ships the bundle informational stands (as designed) — re-measured with npm pack --dry-run: parent ships contracts + reference dist + example source + example bundle + manifests (67 files, no credentials/tests/node_modules); example tarball ships exactly README.md, dist/main.js, qwen-extension.json (+ mandatory package.json).

Carried-forward measurements (A/B cells, example E2E, vectors, ladder, mutation matrix, gates, pack) were all re-run at the new head; the base arm was rebuilt at the new merge base 337da21 (previous round used 9b39280). No measurement was carried by shortcut.

Scope

Central claim: the reference context_search MCP tool enforces the published v1 profile — undeclared selector fields are rejected at the MCP boundary before any provider call, the bounded output schema is declared, and text/structuredContent results are semantically identical JSON.

Secondary claims: (1) the local example adapter behaves per contract against a loopback REST provider and ships as a self-contained bundle; (2) published test vectors validate against both the language-neutral JSON Schemas and both runtime schema copies.

Delta since the previous round (5 commits, individually unreachable in the depth-2 checkout — verified as aggregate HEAD^1..HEAD): two renderer guards in context.ts (skip empty id/content; drop non-finite score), bounds/renames, and the latest commit switching the example to forward-proxy semantics (EnvHttpProxyAgent({ proxyTunnel: false })). The reference-side src/proxy.ts is unchanged by this PR (pre-existing at base).

Central claim — A/B wire oracle

Harness ab-reference.mjs: raw JSON-RPC stdio client drives the compiled dist/main.js of each arm against a loopback fake provider that records every request (method, path, auth, body). Base arm = scratch worktree at HEAD^1 rebuilt there; dependency control realpath-asserted (undici 7.29.0 via the package-local node_modules — the same version the base lockfile pins; zod 3.25.76 / MCP SDK 1.30.0 hoisted root copies shared by both arms; the only lockfile delta is test-only ajv, never loaded by the server). Witness: evidence/01-ab-reference-head-vs-base.png.

cell args head (strict) base (lax)
C1 positive control query with whitespace success; 1 provider request; normalized query; limit: 5; Bearer <env token>; POST /v1/context/search identical
C2 undeclared fields query + tenant, repository, filter, endpoint, credential, metadata isError; 0 provider requests success; 1 request; body contains only {query, limit} — fields dropped, not forwarded
C3 astral bound 2000 🙂-scale code points success; 1 request identical
C4 astral bound+1 2001 code points rejected; 0 requests identical
C5 blank query " \t\n " rejected; 0 requests identical
unknown tool rejected; 0 requests identical
C6 oversized items provider returns 5000-char content, 300-char title success; content ≤1000 / title ≤200 code points; ≤5 items; text escapes <>; envelope ≤4000 chars; structuredContent present, deep-equals JSON.parse(text), preserves literal <>, validates vs published output schema same text pipeline (escaping pre-existing); no structuredContent, wire outputSchema absent

Head 30/30, base 28/28 (base assertions encode the predicted lax behavior; all held). Both arms advertise additionalProperties:false on the wire — only enforcement and the output side changed (re-confirms the previous round's correction).

Delta probes

Hardening guards (bounds-probes.mjs, unit level on both arms' compiled dist/context.js; witness evidence/05-bounds-guards-head-vs-base.png): 16/16. Head skips empty-id and empty-content items and drops NaN/Infinity scores, so every rendered envelope validates against the published output schema; base keeps those shapes — and its envelope fails the published schema for each (NaN serializes as "score":null). These guards are defense-in-depth on the reference path (its providers already filter), but they are what keeps the renderer's output schema-valid for any future or direct caller — the exact property the new outputSchema declaration depends on.

Forward proxy (example-e2e.mjs cells E10–E12 + proxy-https-probe.mjs; witness evidence/02-example-e2e-incl-forward-proxy.png):

cell setup observation
E10 HTTP_PROXY → fake proxy success; proxy saw exactly one absolute-form POST http://127.0.0.1:<port>/v1/context/search (not CONNECT, not origin-form); credential carried through; provider saw zero requests; response flowed back
E11 HTTP_PROXY + NO_PROXY=127.0.0.1 success; proxy saw 0; provider saw 1 direct request
E12 HTTPS_PROXY only, http origin success; proxy saw 0 (correctly not applied); provider saw 1
https boundary https: origin + HTTPS_PROXY undici still issues CONNECT provider.example:443 despite proxyTunnel:false; against a CONNECT-refusing proxy the tool fails closed with the stable message, no leak, no crash

Fail-closed boot cells (4/4): non-loopback http base URL, base URL with path, missing token, and invalid HTTP_PROXY each exit 1 with their specific stderr message before serving.

Local example E2E: 43/43 in-place and 43/43 with the bundle copied to a directory with no node_modules anywhere up-tree (self-containment re-proven at the new head). Includes: only context_search exposed; one normalized fixed-limit:5 request with the env credential; text escapes <> while structuredContent preserves them; invalid provider items (empty id/content, string score) dropped; ≤5 items.

Contract vectors and scaling

vectors-check.mts (witness evidence/04-vectors-contract-check.png): 36/36 — all 28 published vectors classified identically by ajv (strict, draft-07), the reference runtime (dist/provider-profile.js), and the example runtime (src/profile.ts); plus synthetic boundaries (content 1000/1001 code points, id 128/129, six items, astral queries 1000/2001). The discriminator cell — 1000 astral code points = 2000 UTF-16 units — passed ajv at maxLength: 1000, proving ajv counts code points, matching the runtime regexes. NaN scores: rejected by all three validators (no divergence; JSON cannot carry NaN anyway).

regex-ladder.mjs (witness evidence/06-regex-ladder.png): 22/22 — hostile shapes (astral pairs, lone surrogates, mixed, spaces-then-stars) at 2k/3k/5k/20k/65k code points: every rung ≤ 0.31 ms, no superlinear curve; base-style Array.from().length on the same 65k input took 2.0 ms. No ReDoS introduced; the new pattern is faster than the check it replaced.

Vacuity / mutation matrix

Scratch copies of the package; control unmutated 201/201 green (12 files) — the suite grew +16 tests since the previous round (185 at e41db92), added by the hardening commits. Witness evidence/03-mutation-matrix.png.

mutant result killed by
control (none) 201/201 green
M1 inputSchema .strict().strip() 2 red rejects model-selected retrieval scope without calling the provider; keeps runtime schemas aligned with the published vectors
M2 drop structuredContent 3 red returns normalized context from the bound search provider; accepts 2000 astral Unicode characters and rejects 2001; accepts rendered output at astral Unicode field bounds (SDK outputSchema enforcement)
M3 drop outputSchema declaration 1 red registers only a provider-bound retrieval tool
M4 drop empty-id/content guard in context.ts (delta) 1 red drops contract-invalid required fields and non-finite scores — expected/actual diff shows the empty-id/content items leaking
M5 drop Number.isFinite score guard (delta) 1 red same test
M6 drop empty-id/content guard in example profile.ts (delta) 1 red renders bounded contract-valid output with matching representations
M7 example proxyTunnel: false→default (latest commit) 1 red uses forward-proxy semantics for HTTP providers — mutant CONNECTs, fake proxy answers CONNECT with 502, fetch failed

7/7 mutants killed by their intended tests; every failure message is a behavioral expected/actual assertion (spot-checked M4 and M7). The latest commit's change is pinned by name (M7). No survivors; the M1 observation from the previous round still holds (wire-schema/ajv vector test cannot see strict-vs-strip — only the live tools/call test pins enforcement).

Targeted gates (head)

  • npm test (package, unmutated control): 12 files / 201 tests passed.
  • npm run typecheck (incl. example): clean.
  • npm run lint: clean; liveness proven by planting an any probe (@typescript-eslint/no-explicit-any fired, exit 1), then restoring to green.
  • npm pack --dry-run both packages: parent 67 files (contracts, dist, example source + bundle, manifests, no credentials/tests/node_modules — 9/9); example exactly README.md, dist/main.js, qwen-extension.json, package.json (3/3).

Findings

No blocking findings. Informational:

  1. Forward-proxy semantics, precisely. proxyTunnel: false converts http: origins from CONNECT tunneling to absolute-form forwarding (proven by E10/M7), but undici still uses CONNECT for https: origins regardless of the option (probed: CONNECT provider.example:443 observed). The example's config validator admits arbitrary https: base URLs, so a provider team copying this example gets tunneling for https providers and forwarding for http ones — the commit title "Use forward proxy for HTTP providers" is literally accurate, and the CONNECT-refusing case fails closed with the stable error. No code change needed; noted so reviewers don't read the option as global.
  2. ajv version drift is cosmetic. package.json declares ^8.17.1; the lockfile resolves 8.20.0 (the previous report cited 8.17.1). Behavioral agreement re-verified at 8.20.0 (code-point maxLength, NaN rejection).
  3. PR body test count is stale, not wrong. The body says "11 test files and 185 tests"; the head now has 12 files / 201 tests (hardening commits added tests). Reviewers should read the body's numbers as first-commit state.
  4. Reaffirmed from the previous round: the base wire schema advertised strictness the call path never enforced; the PR's breaking-change note is accurate for the enforced boundary, and query-only callers are unchanged (C1 identical on both arms).

Not covered

  • Remote example OAuth flow: manifest-shape assertions only (httpUrl, oauth.enabled, scopes context.read, audiences, no credential material — covered by the package suite); no live remote server or token exchange exercised.
  • Mem0 provider / Auto-Recall hook paths: unchanged by this PR; covered only by the package suite.
  • Design-doc prose (docs/design/external-context-provider-extensions.md): not behaviorally verified.
  • Windows/macOS: Linux node:22-bookworm container only.
  • Per-commit attribution: 6 commits in the metadata snapshot, 1 reachable locally (depth-2 shallow checkout; git rev-list HEAD^1..HEAD^2 = 1). Verified the aggregate HEAD^1..HEAD diff; the five intermediate commits (0c9931bf6741c1) could not be exercised individually.
  • https: origin through a real CONNECT-supporting proxy: only the CONNECT-refusing fake was exercised (fail-closed path). Happy-path https tunneling is undici behavior, not this PR's code.
  • The metadata snapshot's baseRefOid (52cfb18…) predates the merge; the A/B used the actual merge base HEAD^1 (337da21…), which is also newer than the previous round's base (9b39280…).
  • Two harness fixture bugs were found and fixed during the round (a synthetic astral vector built with the wrong code-point count, and an example-pack expectation that omitted npm's mandatory package.json); both were re-run green after the fix and are excluded from the totals. No PR code was implicated by either.

Methodology

Environment: CI merge-ref checkout (depth 2), pre-built at head (npm ci + npm run build before the agent clock). All harnesses drove compiled dist/ output (and the esbuild example bundle) over real stdio sockets and real loopback HTTP/forward-proxy servers — no mocks of the code under test; fake peers record wire traffic and encode refusal semantics (CONNECT 502, absolute-form accept). Base arm: git worktree at HEAD^1 with its integration package rebuilt; node_modules realpath/version-asserted so the control shares byte-identical third-party deps (only lockfile delta is test-only ajv, never imported by the server). Mutation matrix ran in scratch copies with single-point edits; every mutant run included its unmutated-suite context. Raw logs in logs/ (ab-head.txt, ab-base.txt, example-e2e.txt, example-bundle-isolated.txt, proxy-https-probe.txt, vectors.txt, bounds.txt, regex-ladder.txt, mutant-*.txt, mutation-matrix-summary.txt, typecheck.txt, lint*.txt, pack-*.json, build-base.txt); harnesses in this directory (ab-reference.mjs, example-e2e.mjs, proxy-https-probe.mjs, vectors-check.mts, bounds-probes.mjs, regex-ladder.mjs, mutation-matrix.sh). Assertion totals count only executed scripted checks; expected base-arm behaviors and mutant-kill expectations are encoded as passing assertions.

Evidence images

01-ab-reference-head-vs-base

02-example-e2e-incl-forward-proxy

03-mutation-matrix

04-vectors-contract-check

05-bounds-guards-head-vs-base

06-regex-ladder

Harness scripts and raw logs are in the workflow run artifacts (7-day retention).

Qwen Code · sandboxed verification

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — both prior blockers are resolved and test-pinned at this commit (pack-content test green in CI; proxy semantics verified against undici 7.29.0 source plus a real-socket regression test). Approving pinned to the reviewed commit. ✅

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving after a full read of the diff at a41ed5f.

Verified:

  • All 37 review threads are resolved, and the prior blockers are genuinely fixed at this head: R1-1 (parent files now packs examples/provider-extension-local/dist/main.js, build/typecheck/lint chain the example, and the pack-content test pins the npm pack --dry-run listing) and R5-1 (EnvHttpProxyAgent({ proxyTunnel: false }) with a forward-proxy test proving no CONNECT tunnel).
  • Security of the external-input surface: context_search input schema is strict (rejects model-selected scope before the provider is called, test-proven); output is bounded (5 items, per-field code-point limits, 4000-unit budget) with structuredContent semantically equal to the escaped text JSON; the local example enforces https-or-loopback origins with no subpath/userinfo, redirect: 'manual', a 1 MiB declared+streamed body cap, placeholder-token detection, redacted errors, 5s<8s timeout budget, and cancellation propagation — all covered by the stdio E2E.
  • CI on this exact head: ubuntu test suite, secret scan, dependency audit, and E2E smoke are green; macOS/Windows test skips are merge_group-only by ci.yml design, and the five cancelled route checks are duplicate-run scheduling noise — no PR-caused failures.
  • Scope matches the PR description: contracts + vectors, reference MCP alignment, two examples, docs, and dev-only ajv addition; no Qwen Core change.

Only non-blocking nits: the status >= 300 && < 400 clause in searchProvider is redundant after !response.ok, and the remote example's oauth.audiences is pinned only by manifest-shape tests.

@doudouOUC
doudouOUC dismissed wenshao’s stale review August 16, 2026 15:50

Already have 2 approves,3ks.

@doudouOUC
doudouOUC added this pull request to the merge queue Aug 16, 2026
Merged via the queue into QwenLM:main with commit c488093 Aug 16, 2026
256 of 261 checks passed
@doudouOUC
doudouOUC deleted the feat/external-context-provider-profile branch August 16, 2026 15:51
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.13.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants