mcpField
M
mem0-test-integration

mem0-test-integration

github.com/mem0ai测试与质量68.0k328 次安装2 天前更新
代码仓库

关于 mem0-test-integration

mem0-test-integration 是用于验证 mem0 集成的技能,在同一工作区和功能分支中运行。它结合静态检查、双阶段测试、API 冒烟测试、可选端到端验证和评分报告。

主要功能

  1. 01集成前置条件检查
  2. 02静态导入与版本检查
  3. 03功能标志开关双阶段测试
  4. 04真实 API 冒烟测试
  5. 05可选端到端验证
  6. 06生成 Markdown 和 JSON 评分报告

适用场景

  1. 01验证新生成的 mem0 集成
  2. 02检查功能标志关闭时既有测试是否通过
  3. 03使用一次性用户 ID 验证 API 调用

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mem0ai/mem0 --skill mem0-test-integration

安装后在 Claude Code 中输入/mem0-test-integration确认已加载。

附带文件LICENSEREADME.md

详细介绍

mem0-test-integration

验证 /mem0-integrate 的产出。在同一工作区、同一功能分支中运行。耦合松散——速度快,可捕获编译和运行时错误,但无法捕获逻辑错误。

权威来源(使用以下来源,不要依赖已有知识)

所有静态检查和冒烟测试形式都以这些 URL 为准。 运行第 3 步前,先对每个 URL 执行 WebFetch。

读取 .mem0-integration/plan.md 中的 Delegated skill: 字段——如果其中指定了技能 URL,就获取该技能,并将其示例代码块用作静态检查(第 3 步)和冒烟测试(第 5 步)的参考。

非侵入性约定

本技能中的每项检查都假设集成是增量式且由功能标志控制的(参见 /mem0-integrate 中的“集成原则”)。 具体来说:

  • product.json 必须包含 feature_flag 字段。
  • 第 4–6 步分两轮执行:
    • 第 A 轮——未设置标志。 所有已有测试必须通过,冒烟测试/E2E 必须跳过。仓库的行为必须与 main 相同。此处任何失败都属于硬性失败——不得让自修复循环尝试修补。
    • 第 B 轮——已设置标志。 新测试必须通过,并运行冒烟测试和 E2E。
  • 如果第 A 轮失败,记分卡会将 non_invasive: false 标记为非侵入性检查未通过,并将 overall: fail 设为失败,同时附带一个不同的原因代码,集成器的修复循环会拒绝处理该代码。

前置条件

除非以下条件全部满足,否则拒绝启动:

  • 仓库根目录中存在 .mem0-integration/ 目录。
  • .mem0-integration/product.json、goal.md 和 plan.md 可读且内容一致(JSON 可解析,文档非空)。
  • 当前分支名称以 mem0-integrate/ 开头(由配套技能设置)。这样可以防止在无关分支上意外运行。
  • 工作树干净。此技能不会修改源文件;任何未提交的改动都意味着集成仍在编辑中,尚未准备好验证。
  • 环境中可使用集成所用的同一个 API 密钥(Platform 使用 MEM0_API_KEY,OSS 使用 OPENAI_API_KEY——根据 product.json 确认)。交互模式会在缺少密钥时询问;CI 模式以状态码 2 退出。

任何前置条件失败时,都要写明原因并退出。绝不要尝试“修复”状态。

流程

1. 阅读约定

加载:

  • product.json → 使用哪种语言、哪款产品(Platform 还是 OSS)、哪个 mem0 版本,以及 write_site、read_site。
  • plan.md → 机械约定(写入模式、读取模式、保留的行为)。
  • goal.md → 目标(仅显示在记分卡中;不进行测试)。
2. 安装依赖项

根据 product.json 中的语言选择对应流程:

语言命令
Python如果支持可编辑安装,则运行 pip install -e .;否则运行 pip install -r requirements.txt。然后,如果尚未安装固定版本,则运行 pip install mem0ai。
TypeScript / JavaScript运行 npm install(如果根据锁文件检测到使用 pnpm 或 yarn,则运行 pnpm install 或 yarn install)。

如果安装失败 → 携带 stderr 末尾内容以状态码 2 退出。依赖项未成功解析时,绝不进入测试阶段。

3. 静态健全性检查(快速、本地运行、不调用 API)
  • 导入检查:写入位置文件是否导入了预期的 Mem0 接口。权威列表来自 https://docs.mem0.ai/llms.txt 中的 ## Identify the User's Setup:

    • Platform Python → from mem0 import MemoryClient
    • Platform TS → import MemoryClient from "mem0ai"
    • OSS Python → from mem0 import Memory
    • OSS TS → import { Memory } from "mem0ai/oss"

    如果 plan.md 指定了委派技能(例如 Vercel AI),则使用该 技能的导入签名,而非上述列表。不匹配 → 报错并指出行号。

  • 版本检查:已安装的 mem0ai 版本是否在此技能的 mem0_tested_versions 范围内。不在范围内 → 发出警告,但继续。

  • 类型检查(仅限 TS 跟踪):运行 tsc --noEmit 或 tsup --dts。 返回非零 → 失败。

  • Lint(如果仓库已配置 lint 工具):运行仓库自身的 lint 命令。由此技能的改动导致的 lint 失败 → 失败;预先存在的 lint 失败 → 作为警告报告。

  • 急切初始化检查:在 product.json 中指定的路径下,对 write_site 和 read_site 文件执行 grep,查找模块级作用域中的 MemoryClient( 或 Memory( — 即不在函数、方法或类主体内的位置。MemoryClient() 会在 __init__ 中验证 API 密钥(Python 会 ping API,TS 在密钥 为空时抛出异常,并在后台 ping),而 OSS Memory() 可能会急切初始化嵌入/LLM 提供方 — 在模块级实例化会在导入时发起网络请求,并在密钥未设置时导致 Pass A 的测试收集失败。命中 → 失败,并提供 file:line,以及 /mem0-integrate 第 8 步约束 #7 中的延迟初始化指南。

4. 运行仓库原生测试套件(两轮)
语言测试命令(按优先级排序)
Python使用伴随技能第 7 步中的测试文件运行 pytest;否则运行 python -m unittest discover。
TypeScript / JavaScript如果 package.json 中定义了 npm test,则运行该命令;否则自动检测 vitest 或 jest。

Pass A — 未设置 feature_flag。 运行所有预先存在的测试套件 (排除新的 test_mem0_* 文件)。必须 100% 通过。 此处任何 失败都会在评分卡中将 non_invasive: false 标记为 硬性失败 — 集成者的自我修复循环不会处理此问题。

Pass B — 已设置 feature_flag(使用 product.json 中的值)。运行 包含新测试在内的完整测试套件。所有测试都必须通过。

使用 git diff main..HEAD --name-only 隔离由集成引入的失败。在 main 上已存在、且仅在集成分支(标志已设置 或未设置)下失败的测试文件,都会计入评分卡,无论通过与否。在 main 上已经失败的测试文件会标记为 pre_existing_unrelated,不计入评分卡 — 但仍会报告,以便用户清理。

将输出保存到 .mem0-integration/test-stdout-flag-off.log 和 .mem0-integration/test-stdout-flag-on.log。评分卡会报告每轮的通过/失败情况。

5. 冒烟测试(真实 API 调用,最短往返)

针对 product.json 定制的脚本端到端流程。以下调用形式是最简形式;如果 plan.md 指定了委派技能,请直接使用该技能的最简示例,这是检测到的技术栈的规范形式。

Platform(Python):

import os
import time
from mem0 import MemoryClient
c = MemoryClient()                               # uses MEM0_API_KEY
uid = f"mem0-test-integration-{os.urandom(4).hex()}"
c.add([{"role": "user", "content": "I prefer aisle seats"}], user_id=uid)
for _ in range(10):
    hits = c.search("seat preference", filters={"user_id": uid})["results"]
    if hits:
        break
    time.sleep(2)
assert any("aisle" in h.get("memory", "") for h in hits), hits
c.delete_all(user_id=uid)                        # clean up

Platform 上的 add 是异步的(它会返回 status: "PENDING" 和一个 event_id),因此搜索会在限定时间内重试。实体 ID 放在 filters 中,结果通过 ["results"] 返回。

Platform(TS): 使用 "mem0ai" 中的 new MemoryClient({ apiKey: process.env.MEM0_API_KEY }),调用形式相同(TS 客户端不会自行读取环境变量);client.search("seat preference", { filters: { user_id: uid } }) 的匹配项位于 .results 中,清理时调用 client.deleteAll({ userId: uid })。

OSS(Python / TS): 使用默认配置的 Memory() / new Memory()(通过 OPENAI_API_KEY 使用 OpenAI LLM;Python 默认使用嵌入式磁盘 Qdrant,TS 默认使用内存向量存储,因此除非仓库自身配置指向某个服务,否则无需服务)。如果仓库提供了包含已配置向量存储服务的 docker-compose.yml,该技能会先启动服务,并在之后将其关闭。如果无法访问已配置的后端存储 → 失败并给出明确说明,指出如何修复。

冒烟测试始终使用带有 mem0-test-integration- 前缀的一次性随机 user_id,避免清理失败时污染用户的真实数据。后台清理步骤会通过 client.users() 列出 Platform 实体,筛选 type: "user"、name 以此前缀开头且 created_at 早于 24 小时的条目,并在下次运行时对每个条目调用 delete_all(user_id=...)(服务端不支持按前缀删除)。

将输出捕获到 .mem0-integration/smoke-stdout.log。

6. E2E 集成测试(运行应用并验证流程)

单元测试和冒烟测试证明 SDK 可独立运行。此步骤才是真正的检验:集成端到端运行时,记忆是否确实出现在应用中用户可见的输出里?

要求 plan.md 包含 E2E recipe: 部分(由 /mem0-integrate 步骤 6 编写)。如果缺少该部分 → 状态为 skipped(而非 fail), 并在评分卡中注明仓库没有可运行的入口点。

技能会读取以下配方字段:

  • start — 用于启动应用的 shell 命令,任何网络端口都使用 $PORT。 在后台运行,并将 stdout/stderr 通过 tee 写入 .mem0-integration/e2e-app.log。
  • ready_probe — 用于检测是否就绪的方式。url=... status=... 会轮询 HTTP 端点;log="..." 会等待 e2e-app.log 中出现指定子字符串; sleep=N 会等待 N 秒(最后手段)。硬超时时间为 60 秒。
  • compose_services — 可选。如果设置,则在 start 之前通过 docker compose up -d <services> 启动服务,并在结束时通过 docker compose down 拆除服务。
  • write_call — 恰好触发一次 Mem0 写入路径。输出会被捕获,并在失败时显示。硬超时时间为 60 秒。
  • write_async_wait_ms — 在 write_call 之后暂停一段时间,让异步记忆 刷新完成。默认值为 0。
  • read_call — 触发 Mem0 读取路径。通常使用新会话或新请求,以显示已存储的记忆。
  • read_assert — 必须出现在 read_call 标准输出中的子字符串、regex=... 或 jsonpath=<expr>=<value>。 这是 E2E 通过条件。

执行顺序:

  1. 分配一个临时 TCP 端口;将其导出为 PORT。
  2. 将 MEM0_USER_ID 设置为一个一次性值 mem0-test-integration-<rand>, 并将其导出,这样应用就能使用与冒烟测试相同的范围设置(如果配方需要清理)。
  3. 如果指定了 compose_services,则启动它们。
  4. 在后台运行 start。
  5. 轮询 ready_probe,直到成功或超时 60 秒。超时 → 失败。
  6. 运行 write_call。退出码非零 → 失败(但继续清理)。
  7. 等待 write_async_wait_ms。
  8. 运行 read_call。
  9. 根据 read_call 的标准输出评估 read_assert。未匹配 → 失败。
  10. 清理(始终执行,即使失败也不例外):向应用发送 SIGTERM,5 秒后发送 SIGKILL;如果启动了服务,则运行 docker compose down;对于 Platform 场景,针对一次性 MEM0_USER_ID 执行 delete_all。

发生任何失败时,评分卡中会包含:

  • e2e-app.log 的最后 40 行
  • write_call 的完整输出
  • read_call 的完整输出
  • read_assert 的预期值与实际值
7. 评分卡

编写 .mem0-integration/scorecard.md 和 .mem0-integration/scorecard.json:

{
  "timestamp": "2026-04-20T14:03:11Z",
  "branch": "mem0-integrate/remember-user-preferences",
  "product": "platform",
  "language": "python",
  "mem0_version": "2.0.0",
  "non_invasive": true,
  "feature_flag": "MEM0_ENABLED",
  "results": {
    "install":      {"status": "pass", "duration_ms": 12043},
    "static_checks":{"status": "pass", "duration_ms": 812},
    "unit_tests_flag_off": {"status": "pass", "duration_ms": 3920, "count": 47,
                            "reason": "all pre-existing tests green with flag unset"},
    "unit_tests_flag_on":  {"status": "pass", "duration_ms": 4321, "count": 49},
    "smoke_test":   {"status": "pass", "duration_ms": 2890, "memory_id": "mem_..."},
    "e2e_test":     {"status": "pass", "duration_ms": 14200,
                     "ready_probe_ms": 3100, "write_exit": 0,
                     "read_assert_matched": true}
  },
  "friction": {
    "dependency_install_retries": 0,
    "pre_existing_test_failures": 0,
    "warnings": ["mem0ai 2.0.0 pinned; consider 2.0.1 for fix X"]
  },
  "overall": "pass"
}

Markdown 版本便于人类阅读,并包含:

  • 顶部重新列出目标文档和计划文档(方便审核者查阅)。
  • 每项检查均注明通过/失败,并附上日志摘录。
  • 摩擦因素摘要。
  • mem0 SDK 的原文警告(如有,例如使用了已弃用字段)。
  • 明确的“未检查”部分,列出松散耦合未覆盖的内容: “存储的数据是否符合用户的预期。搜索是否在恰当的时机运行。user_id 是否与实际会话范围匹配。需要人工审核。”
8. 报告 + 退出
  • 在 stdout 中打印评分卡路径和整体通过/失败状态。
  • 不要提交评分卡文件。 它们位于 .mem0-integration/ 中,该目录已加入 gitignore。用户可以检查并选择性地固定这些文件。
  • 失败时:打印第一个失败步骤的日志末尾(最后 40 行)并停止。不要尝试修复任何问题。

产物(均位于 .mem0-integration/ 下)

文件用途保留方式
scorecard.md人类可读的结论。每次运行时覆盖。
scorecard.json机器可读的结论。供之后的 CI 评分卡工作流使用。每次运行时覆盖。
test-stdout-flag-off.log步骤 4 Pass A(已有测试套件,未设置标志)。每次运行时覆盖。
test-stdout-flag-on.log步骤 4 Pass B(完整测试套件,已设置标志)。每次运行时覆盖。
smoke-stdout.log步骤 5 的完整输出。每次运行时覆盖。
e2e-app.log步骤 6 后台应用的 stdout/stderr。每次运行时覆盖。
e2e-calls.logwrite_call + read_call 调用及其输出。每次运行时覆盖。

模式

模式触发条件行为
交互式(默认)存在 TTY,且未设置 MEM0_TEST_CI提示输入缺失的密钥,并打印易读的摘要。
CIMEM0_TEST_CI=1密钥必须位于环境变量中,不显示提示,任何失败都会以非零状态退出。JSON 评分卡会输出到 stdout 末尾,供工作流解析。

调用方式

/mem0-test-integration                       # 交互式,执行所有步骤
/mem0-test-integration --ci                  # 非交互式
/mem0-test-integration --skip-smoke          # 不调用 API,不执行 E2E
/mem0-test-integration --skip-e2e            # 仅运行单元测试和冒烟测试(更适合快速 CI)
/mem0-test-integration --only-smoke          # 仅运行冒烟测试
/mem0-test-integration --only-e2e            # 仅运行 E2E(假设依赖已安装)

组合方式:--skip-* 可叠加使用(--skip-smoke --skip-e2e = 仅运行静态检查和单元测试,不产生 API 费用)。--only-* 不能与任何其他标志同时使用。

退出代码

代码含义
0所有检查均已通过。
1前置条件未满足(没有 .mem0-integration/、分支错误、工作树不干净)。
2缺少环境变量键(CI 模式)或依赖安装失败。
3静态健全性检查失败(导入错误、类型错误)。
4单元测试失败(Pass B — 集成自身已损坏)。
5冒烟测试失败。
6E2E 测试失败(ready_probe 超时、写入/读取调用失败或 read_assert 未命中)。
7违反非侵入性:Pass A 失败(已有测试被破坏)。集成器的修复循环拒绝处理此问题。
8内部错误(技能缺陷 — 请报告)。

明确不在范围内

  • 修改源文件。 此技能对代码仓库只读。 如果验证发现错误,请针对相同的目标 + 计划重新运行 /mem0-integrate; 不要手动打补丁。
  • 修复损坏的测试。 单元测试失败说明集成有误,而不是测试有误。此技能不会 “尝试不同的测试”。
  • 深入的逻辑正确性。 E2E 步骤证明“用户之前说过的某件事之后会再次出现”, 这是有用但浅层的信号。 它不能证明集成会选择正确的事实进行存储、能在真实用户之间正确 限定 user_id 的范围,或能妥善处理冲突解决。这些需要人工审查。
  • 自我修复。 此技能绝不会修改源文件。配套的 /mem0-integrate 技能在默认的 --heal 模式下会使用此处生成的评分卡,并驱动自己的补救循环。退出代码 7 (违反非侵入性)是明确的信号,表示修复循环必须停止并向用户报告。
  • 跨分支比较。 不会与 main 的基线进行差异比较。评分卡仅反映此分支。
  • 针对生产数据运行。 每项冒烟测试都会使用随机生成的一次性 user_id,并在完成后清理。绝不会触及任何其他用户的数据。

评论

支持 Markdown