feat(external-context): Support configurable Mem0 providers - #9952
feat(external-context): Support configurable Mem0 providers#9952yiliang114 wants to merge 16 commits into
Conversation
Add a mem0 provider type to the external-context integration that speaks the open-source Mem0 REST API (POST /v2/memories/search for on-demand recall, POST /v1/memories with infer:false for exact direct-import writes), so self-hosted mem0 servers and managed OSS-protocol services such as Aliyun PolarDB Mem0 can serve as the external context corpus. The tenant identity (user_id, optional app_id) is fixed in the administrator-managed configuration and is never supplied by the model. A new allowInsecureHttp opt-in permits plain-HTTP endpoints such as PolarDB Mem0 while credentials-in-URL remain rejected. Refs #9951
|
E2E verification report (local, protocol-level) End-to-end smoke against a mock server implementing the open-source Mem0 API shape (
Live verification against a real Aliyun PolarDB Mem0 instance is pending and tracked in #9951. |
|
Thanks for the PR! Template looks good ✓ Problem: this is an observed gap, not theoretical hardening. Tracked in #9951 and verifiable in source — Direction: aligned with the existing mem0 investment in this integration (platform writes, auto-recall), and the security posture is the right shape — tenant Size: no core paths touched — everything lives in Approach: scope feels right. One new adapter reusing the existing zod discriminated union, Risk: no elevated risk signals — none of the changed files match the revert-correlated high-risk paths. Moving on to code review, with the design-doc question flagged above. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:这是已观测到的缺口,不是理论性加固。#9951 跟踪,且可在源码中核实—— 方向:与该集成已有的 mem0 投入(平台写入、auto-recall)一致,安全姿态也正确——租户 规模:未触及核心路径——全部改动都在 方案:范围合适。一个新适配器,复用现有 zod 可辨识联合、 风险:无升级风险信号——改动文件均未命中与 revert 相关的高风险路径。 进入代码审查,同时保留上面提出的设计文档问题。🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewBefore reading the diff I sketched my own proposal — a third
One non-blocking question: search responses are parsed with the shared Testing evidenceUnattended CI run — I did not build or execute any PR code; the evidence below is the PR's own CI on the reviewed commit, read through the API. The unit suite on Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 The suite itself is the substantive evidence here: the new tests stand up a real local HTTP server and assert the exact wire shape — request path ( 中文说明代码审查读 diff 之前我先独立起草了方案——新增第三个
一个非阻塞问题:检索响应复用 测试证据无人值守 CI 运行——我未构建或执行任何 PR 代码;以下证据是被审提交上 PR 自身 CI 的结果,通过 API 读取。 测试套件本身就是实质证据:新测试启动真实本地 HTTP 服务器,断言精确的报文形状——请求路径( — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 3/5 — clean, well-tested implementation with no code reservations; the one open item is a human decision, not a defect — the design-doc exception note that the #9951 triage asked the implementing PR to carry. Stepping back: I drafted my own proposal before reading the diff (new provider case, optional flag on the shared URL validator, adapter reusing the existing parsing/write infrastructure), and this PR lands that shape — I didn't find a simpler path it missed. The problem is real and verified, the security posture is conservative in exactly the ways this integration demands (tenant pinned in config, insecure HTTP opt-in default-false, What keeps this from an approval is not the code. The #9951 triage accepted the direction on a defensible reading — open protocol family rather than a single third-party service, and no extension route for the write path — but asked that the exception to the provider-extensions design doc be recorded in the same PR. Not approving, not requesting changes — deferring for that human call. (Separately, the ubuntu unit suite was still in flight at review time; the deferral is about the design-doc question, not CI.) 中文说明置信度:3/5 —— 实现干净、测试充分,代码层面没有任何保留意见;唯一的未决项是一个需要人来拍板的问题,而不是缺陷——#9951 分诊要求实现 PR 附带的设计文档例外说明。 退一步看整体:我在读 diff 之前先独立起草了方案(新 provider case、共享 URL 校验器的可选参数、复用现有解析/写入基础设施的适配器),本 PR 正是这个形状——我没有找到它遗漏的更简路径。问题真实且已核实,安全姿态恰好是该集成要求的保守方式(租户固定在配置、不安全 HTTP 显式开关默认关闭、写入宁可报 让它没有直接通过的不是代码。#9951 的分诊基于一个站得住的解读接受了方向——这是开放协议族而非单个第三方服务,且写入路径没有扩展路线——但要求把对 provider-extensions 设计文档的例外记录在同一 PR 中。本 PR 没有改动 不批准、也不要求修改——就这个问题转交人工决定。(另:评审时 ubuntu 单元测试仍在运行中;暂缓与 CI 无关,仅因设计文档问题。) — Qwen Code · qwen3.8-max Reviewed at |
|
⏸️ Deferring to @yiliang114 — the code review is clean (see the stage comments above), but the #9951 triage asked the implementing PR to record the provider-extensions design-doc exception in 中文说明⏸️ 暂缓,转交 @yiliang114 —— 代码审查是干净的(见上方各阶段评论),但 #9951 的分诊要求实现 PR 在 — Qwen Code · qwen3.8-max |
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
Assert the exact example structure and that it loads through loadConfig once the endpoint and user placeholders are substituted, so the shipped sample cannot drift from the provider schema.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
Test Plan (not a blocker): src/main.ts — no such file or directory; 229 passing — this review observed 230 passed.
中文说明
已审查——无阻断问题。 建议见行内评论。
Test Plan(非阻断):src/main.ts — no such file or directory; 229 passing — this review observed 230 passed。
— qwen3.8-max via Qwen Code /review (v0.22.0)
Enforce the OSS baseUrl policy only in the adapter constructor, matching the sibling providers, and have the rejection message point at the allowInsecureHttp opt-in. Extract the shared write-rejection classifier used by both Mem0 adapters, pin localhost and IPv6 loopback acceptance, cover non-HTTP write failures mapping to unknown, clean up the example test's temp directory, and correct the README rollout guarantees and the OSS write-enablement guidance.
The example pre-enabled allowInsecureHttp, inverting the README guidance it is cited by. Default to an HTTPS baseUrl without the flag; the hinted validation error and the README paragraph lead plain-HTTP whitelist deployments to the explicit opt-in.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed. Suggestions are inline.
Not reviewed: verification and reverse audit — each ran and opened its brief, but neither was launched with the prompt the CLI built — the launches were written by hand, so the posted findings cannot be counted as verified, and what the agents were actually asked is not what this skill certifies.
Test Plan (not a blocker): src/main.ts — no such file or directory.
Deferred under the convergence posture (round 2, not a blocker) — recorded, not requested in this round:
integrations/external-context/src/auto-recall.ts:232 — [probe] providerCredential's mem0 branch is untested; a credential-leak mutation survives the whole suiteintegrations/external-context/src/providers.ts:246 — [probe] parseOssRememberResult's multi-item scan is unpinned; a first-item-only mutant survives
中文说明
仅完成部分审查,审查缺口已披露。 建议见行内评论。
未审查:验证与反向审计——两者都运行并打开了各自的 brief,但都不是用 CLI 构建的 prompt 启动的——启动 prompt 是手写的,发布的发现不能算作已验证,agent 实际被要求做的也不是本 skill 所认证的内容。
Test Plan(非阻断):src/main.ts — no such file or directory。
收敛姿态下延后(第 2 轮,非阻断)——已记录,本轮不要求修改:共 2 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.0)
…te arms, gate HTTP hint, fix README wording
The open-source mem0 v1.0.1 REST protocol (implemented by Aliyun PolarDB Mem0) scopes memories by user_id / agent_id / run_id; app_id is a hosted-platform-only field these endpoints do not accept. Rename the optional mem0 provider field to agentId, send it as agent_id, and place it top-level in the v2 search request (filters carry user_id) to match the protocol. Verified live against a PolarDB Mem0 instance: add and search accept agent_id, infer:false is honored for direct import, and the MCP chain works end to end.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Test Plan (not a blocker): src/main.ts — no such file or directory; 231 passing — this review observed 232 passed.
Deferred under the convergence posture (round 3, not a blocker) — recorded, not requested in this round:
integrations/external-context/src/providers.ts:240 — [review] parseOssRememberResult's triple-nested ternary drifts from the flat early-return style of its sibling parserintegrations/external-context/src/providers.test.ts:712 — [probe] Write path's agent_id-omission branch is never asserted; a wrong-binding mutation survives the whole suiteintegrations/external-context/src/auto-recall.ts:233 — [probe] The new mem0 case in providerCredential (auto-recall credential scrubbing) has no test; a credential-leak mutation survivesintegrations/external-context/src/providers.ts:178 — [review] Architecture design doc direct-external-context-provider.md is stale: two explicit read adapters claimed, no allowInsecureHttp carve-outintegrations/external-context/src/providers.ts:217 — [review] Write design doc direct-external-context-mem0-write.md is falsified: V3-only enablement, /v3 protocol, accepted as expected successintegrations/external-context/README.md:396 — [probe] OSS section recommends a loopback relay but the README's only NO_PROXY instruction is scoped to the Generic HTTP provider
中文说明
Test Plan(非阻断):src/main.ts — no such file or directory; 231 passing — this review observed 232 passed。
收敛姿态下延后(第 3 轮,非阻断)——已记录,本轮不要求修改:共 6 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.0)
|
Addressed the blocking protocol-scope review in a381a6f. The provider is now explicitly Verification: external-context typecheck and lint pass; all 232 package tests pass. All existing review threads are now resolved. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No blocking issues. LGTM! ✅
Test Plan (not a blocker): 232 passing — this review observed 223 passed.
Deferred under the convergence posture (round 4, not a blocker) — recorded, not requested in this round:
integrations/external-context/src/auto-recall.ts:231 — [probe] providerCredential's polardb-mem0 branch is untested; a wrong-field credential mutation survives the whole suiteintegrations/external-context/src/providers.ts:250 — [probe] parsePolarDbRememberResult's multi-item scan is unpinned; a first-item-only mutant survives
中文说明
无阻断问题。LGTM!✅
Test Plan(非阻断):232 passing — this review observed 223 passed。
收敛姿态下延后(第 4 轮,非阻断)——已记录,本轮不要求修改:共 2 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.0)
|
Verified the current head (5702f63) end-to-end against a live Aliyun PolarDB Mem0 instance. REST probes (direct, isolating provider behavior):
MCP chain ( Two protocol points confirmed against the instance:
CI is green and there are no unresolved review threads. Ready for a maintainer look. |
|
Design follow-up: I checked whether this could be reduced to exposing The original PR adapter already exposed |
Replace the protocol-specific draft provider with a generic Mem0 provider backed by reviewed, immutable presets for Mem0 Platform, stock Mem0 REST, and PolarDB. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed. Suggestions are inline.
Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.
中文说明
仅完成部分审查,审查缺口已披露。 建议见行内评论。
未审查:反向审计——在 5 轮的反审轮数上限内未收敛。
— qwen3.8-max via Qwen Code /review (v0.22.2)
The endpoint is operator-supplied and its build is not guaranteed - these services are self-hosted or vendor-packaged, and the stock Mem0 REST server carries no API version in its paths at all. A preset is therefore a claim about what is deployed, and it can be wrong. Nothing here probes or falls back; instead a mismatch is kept from passing silently. Send session identity at both the request root and under `filters` for the Mem0 server preset. `_build_filters_and_metadata` seeds the effective filters from `filters` and then overwrites each identity key with the root value, so one request resolves to a byte-equal scope on builds that read either position. A filters-only search is rejected outright by builds predating that move, which surfaced as a 500 rather than as an unscoped search. Claim `stored` for a direct import only when the echoed `memory` matches the submitted text and the event is not a delete. `infer: false` is what makes the stored memory the exact text approved at the confirmation Hook, but a build whose request model predates the field drops it silently, runs fact extraction, and returns a rewritten memory with a valid identifier - reported until now as `stored`. Write provider failures to stderr with the HTTP status, which separates a contract mismatch from an outage. The model-facing error stays opaque, and no provider response body is ever written. Rename the preset to `mem0-server-rest-2026-08`: "OSS" names an object storage service in some of the clouds these deployments run in, and the preset list it sits in already names one of those clouds. Report which scope key and which basePath rule a configuration broke, narrow the preset unions to the members a shipped preset uses, and cover the write result classes, basePath rules, both scope rules in isolation, the identifier bound, the direct-import basePath join, the Platform V3 preset write request, and the mem0 arm of auto-recall credential scrubbing.
Every other field of a `mem0` block is a fact the administrator already holds. `preset` is not: it is a claim about which wire contract the deployment implements, and these services are self-hosted or vendor-packaged, so the answer is not visible from the configuration side. The configuration made that claim mandatory without offering any way to check it. The probe runs a candidate preset through the real adapter against the real endpoint, so a preset that reaches the service but whose items the parser discards is reported as the mismatch it is. It also reads the declared search schema when one is served, and compares scope placements so a preset can be moved to `body-and-filters` on evidence rather than on assumption. An empty corpus is reported as inconclusive rather than as a pass: three equally empty result sets look like agreement and are not. Read-only. It issues search requests and one `GET /openapi.json`, never writes, and never renders the credential.
…reset PolarDB Mem0 is offered by more than one cloud, so an identifier scoped to one of them reads as inapplicable to an operator running the same contract elsewhere - the preset names a wire contract, not a vendor. The mapping's verification evidence came from an Aliyun deployment, which the design doc now says explicitly rather than encoding in the identifier. Record who controls the build behind each preset, and probe placements only where that is the operator. A vendor-operated service has one published contract and no version skew to hedge against, so reporting that a different request shape also works would invite a deviation with a cost and no benefit. A skipped comparison no longer stands in for a working preset: when the baseline search fails, the verdict is the mismatch, not "see the baseline".
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
Closeout at Deferred after review round 5: the broader basePath mutation matrix, opaque-ID boundary pin, isolated scope-branch tests, exact example snapshot, separate write/basePath pin, default-value pin, and malformed direct-write envelope matrix. These are test-hardening suggestions; the production guards remain fail-closed, and expanding them now would widen the PR without changing its shipped contract. Verification: 225/225 tests, lint, typecheck, and build all pass. |
…ipped The console hands out a plain-HTTP address and port, while the shipped example carries an `https://` origin with no port - the shape the endpoint should have, not the shape it arrives in. Pasting the console address into that example fails the URL policy, and nothing tells the operator which of the legitimate resolutions their deployment wants. Add a loopback example instead of loosening the policy. An `ssh -L` relay carries the credential and the memories, loopback HTTP loads with no opt-in, and only the user id has to be substituted, so the path from a new instance to a working search is one relay command and one copied file. The HTTPS example is unchanged: pre-enabling the opt-in in a shipped file would invert the posture the surrounding section asks operators to keep. The loopback example omits `agentId`, which the preset sends at the request root - a placement no PolarDB document confirms, and an optional field is not worth staking a first connection on.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers.
2 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:
- D6-2 trailing-slash basePath normalization untested — already reported (R5-3, comment 3869715095)
- D6-3 parseProviderId rejection guards unexercised — already reported (R5-4, comment 3869715108)
Deferred under the convergence posture (round 6, not a blocker) — recorded, not requested in this round:
integrations/external-context/README.md:455 — [review] README claims "Both shipped examples use HTTPS and omit the flag", but the PR ships three examples and the new loopback example uses plain http://127.0.0.1:8080integrations/external-context/src/providers.ts:345 — [probe] R5-3 still stands: validateMem0BasePath has nine rejection conditions but tests exercise only two, and buildUrl's trailing-slash normalization is untestedintegrations/external-context/src/providers.ts:171 — [probe] R5-4 still stands: the 256-code-point bound on the provider operation id (now parseProviderId) has no test anywhereintegrations/external-context/src/providers.ts:255 — [probe] R5-5 still stands: Mem0CompatibleAdapter.remember's definitive write-rejection branch (HTTP 400/401/403/404 → failed) is pinned only through the legacy Mem0PlatformV3Adapter testsintegrations/external-context/src/mem0-presets.ts:127 — [probe] R5-6 still stands: neither branch of isValidMem0Scope is pinned in isolation — the scope-rejection tests violate both rules simultaneouslyintegrations/external-context/src/manifest.test.ts:332 — [probe] R5-8 still stands: the mem0-oss example-loadability test never pins the example's content (toMatchObject only, unlike the PolarDB toEqual pins)integrations/external-context/src/providers.test.ts:791 — [probe] R5-9 still stands: no Mem0CompatibleAdapter write test exercises a non-empty endpoint.basePath — every remember call site uses the default ''integrations/external-context/src/config.ts:37 — [probe] R5-10 still stands: the basePath default '' is pinned by nothing — every fixture and all three shipped examples supply basePath explicitlyintegrations/external-context/src/providers.test.ts:785 — [probe] R5-11 still stands: parseDirectWriteResult's envelope guard is the only result class with zero coverage — alternate root objects and root arrays are untested
中文说明
已审查——无阻断问题。
本轮确认的 2 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。
收敛姿态下延后(第 6 轮,非阻断)——已记录,本轮不要求修改:共 9 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.2)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers.
1 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:
- R5-8 mem0-oss example-loadability test never pins the example's content — already reported (comment 3869715134)
Deferred under the convergence posture (round 7, not a blocker) — recorded, not requested in this round:
integrations/external-context/src/manifest.test.ts:262 — [review] example-loadability scaffolding pasted three times instead of one file-local helper
中文说明
已审查——无阻断问题。
本轮确认的 1 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。
收敛姿态下延后(第 7 轮,非阻断)——已记录,本轮不要求修改:共 1 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.2)
|
Re-reviewing this at The remaining blocker is architectural, not another adapter fix. #10113 and #10149 now establish Ponytail recommendation: stop expanding this PR after seven review rounds and make the maintainer choice explicit: either merge it knowingly as a temporary backward-compatible path, or supersede it with a narrow PR2 from current |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed.
3 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:
- R5-11 parseDirectWriteResult envelope guard unpinned — already reported (comment 3869715157)
- R5-4 parseProviderId rejection branches untested — already reported (comment 3869715108)
- R5-3 buildUrl trailing-slash basePath normalization untested — already reported (comment 3869715095)
Unresolved, please confirm:
- [Critical] Issue-level comment 5461035058 (@yiliang114): the author asserts the remaining blocker is architectural — this PR adds Mem0 variants and writes to the older private external-context provider union, while (per the comment) #10113/#10149 esta…
Deferred under the convergence posture (round 8, not a blocker) — recorded, not requested in this round:
integrations/external-context/src/providers.test.ts:689 — [review] R8-1 OSS preset search contract test never pins the memory field the stock server returns; deleting 'memory' from contentFields leaves 96/96 tests green (probe-verified)integrations/external-context/src/providers.ts:378 — [review] R8-2 parseMem0Items dead optional defaults and unused 'text' content-field member widen the reviewed preset grammarintegrations/external-context/src/config.ts:148 — [review] R8-3 the three coordinated fail-closed guards for write-less presets have no test; negative branches unreachable with all shipped presets
中文说明
已审查。
本轮确认的 3 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。
未决,请确认:共 1 条(原文未翻译,列表见上方英文部分)。
收敛姿态下延后(第 8 轮,非阻断)——已记录,本轮不要求修改:共 3 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.3)
What this PR does
This PR adds a configurable Mem0-compatible provider to the private External Context integration. New configurations use one
mem0provider type and select a reviewed, immutable wire contract through a versioned built-in preset. The initial presets cover Mem0 Platform V3, the stock self-hosted Mem0 REST server, and Aliyun PolarDB Mem0.Instance configuration supplies only the endpoint origin and optional base path, credential environment-variable name, and fixed scope. The selected preset owns authentication, search and direct-import paths, scope placement, result-limit field, response normalization, and write outcome semantics. The model-facing contract remains
context_search({ query });context_remember({ content })remains available only for an explicitly write-enabled version 1 configuration.The existing
mem0-platform-v3configuration remains supported. The earlier unmergedpolardb-mem0shape is replaced bytype: "mem0"with thealiyun-polardb-mysql-2026-08preset.Why it's needed
A product name is not a sufficient protocol boundary. PolarDB search and direct import use different versioned paths, while the stock Mem0 server uses unversioned paths and different authentication. A scalar
apiVersionalso cannot describe authentication, scope placement, trailing-slash requirements, response fields, or synchronous versus asynchronous write semantics.Versioned presets make those differences explicit without exposing arbitrary request templates, JSONPath, dynamic modules, protocol probing, or silent fallback. Provider-specific integrations that do not fit the bounded preset grammar still use their own local or remote MCP Extension.
Reviewer Test Plan
How to verify
context_rememberby default.POST /v3/memories/search/withAuthorization: Tokenand fixedapp_id; stock Mem0 usesPOST /searchwithX-API-Keyand fixeduser_id/optionalagent_idunderfilters; PolarDB usesPOST /v2/memories/searchwithAuthorization: Token, fixeduser_idunderfilters, optional top-levelagent_id, andtop_k.originandbasePathjoin without dropping a reverse-proxy prefix, while credentials in the URL, traversal, encoded path material, whitespace, and non-loopback HTTP without explicit opt-in fail before tool exposure.infer: falsedirect-import request and never retries. PlatformPENDINGplus a UUIDevent_idmust returnaccepted; PolarDB and stock Mem0 returnstoredonly for a validresults[].id; a bareevent_idremainsunknown.npm test --workspace @qwen-code/external-context,npm run lint --workspace @qwen-code/external-context,npm run typecheck --workspace @qwen-code/external-context, andnpm run build --workspace @qwen-code/external-context.Evidence (Before & After)
N/A — no user-visible UI change.
Tested on
Environment (optional)
The External Context workspace passes 225/225 unit and integration-style tests, lint, typecheck, and its self-contained build on macOS.
Risk & Scope
mem0-platform-v3configurations are unchanged. The unmerged draftpolardb-mem0configuration is replaced bytype: "mem0",preset: "aliyun-polardb-mysql-2026-08",endpoint,credentialEnv, andscope.Linked Issues
Refs #9951 and #10113.
中文说明
这个 PR 做了什么
本 PR 为私有 External Context 集成新增可配置的 Mem0 兼容 provider。新配置统一使用
mem0provider 类型,并通过带版本的内置 preset 选择经过评审且不可变的报文协议。首批 preset 覆盖 Mem0 Platform V3、标准自托管 Mem0 REST server 和阿里云 PolarDB Mem0。实例配置只提供 endpoint origin、可选 base path、credential 环境变量名和固定 scope。认证方式、检索与精确写入路径、scope 放置位置、结果数量字段、响应归一化和写入结果语义都由所选 preset 决定。模型侧契约仍是
context_search({ query });context_remember({ content })仍只会在显式开启写入的 version 1 配置中出现。现有
mem0-platform-v3配置继续兼容。此前尚未合并的polardb-mem0配置形态改为type: "mem0"搭配aliyun-polardb-mysql-2026-08preset。为什么需要
产品名称不足以作为协议边界。PolarDB 的检索和精确写入使用不同版本的路径,而标准 Mem0 server 使用无版本前缀的路径和不同的认证方式。单独一个
apiVersion也无法描述认证、scope 放置位置、尾斜杠要求、响应字段以及同步/异步写入语义。版本化 preset 可以明确这些差异,同时不暴露任意请求模板、JSONPath、动态模块、协议探测或静默降级。不符合受限 preset 语法的 provider 集成仍通过独立的本地或远程 MCP Extension 接入。
评审验证计划
如何验证
context_remember。POST /v3/memories/search/、Authorization: Token和固定app_id;标准 Mem0 使用POST /search、X-API-Key,并把固定user_id与可选agent_id放入filters;PolarDB 使用POST /v2/memories/search、Authorization: Token,把固定user_id放入filters、可选agent_id放在顶层,并发送top_k。origin与basePath拼接后不会丢失反向代理前缀;URL 内嵌 credential、路径穿越、编码路径材料、空白字符,以及未显式允许的非回环 HTTP 都应在工具暴露前失败。infer: false的精确写入请求且从不重试。Platform 的PENDING加 UUIDevent_id必须返回accepted;PolarDB 与标准 Mem0 只有在返回有效results[].id时才返回stored;只有event_id时仍返回unknown。npm test --workspace @qwen-code/external-context、npm run lint --workspace @qwen-code/external-context、npm run typecheck --workspace @qwen-code/external-context和npm run build --workspace @qwen-code/external-context。前后对比证据
N/A —— 没有用户可见 UI 变化。
测试平台
环境
External Context workspace 在 macOS 上通过 225/225 单元与集成式测试、lint、typecheck 和自包含 build。
风险与范围
mem0-platform-v3配置不变。尚未合并的草稿polardb-mem0配置改为type: "mem0"、preset: "aliyun-polardb-mysql-2026-08"、endpoint、credentialEnv和scope。关联 Issue
Refs #9951 和 #10113。