mem0 TypeScript SDK 工程实践:从双入口构建到 ts-v 标签发布的完整工作流
本篇基于 mem0 仓库中的 TypeScript SDK 说明文档(mem0-ts/CLAUDE.md),系统讲解 mem0ai npm 包的工程组织方式:pnpm 命令体系、tsup 双入口(CJS + ESM)构建、jest 测试分层、TypeScript 严格模式约定,以及 ts-v* 标签触发 OIDC 发布到 npm 的完整链路。读完本文,你可以直接参与该 SDK 的二次开发、本地构建与版本发布流程。
定位:一个包,两种记忆入口
mem0-ts 目录承载的就是发布到 npm 的 mem0ai 包(见 mem0-ts/package.json),当前版本为 3.1.7,声明 node >= 18 运行环境(engines 字段),并通过 packageManager 字段锁定 pnpm@10.5.2。该包同时提供两条能力线:
- 托管平台客户端:
MemoryClient,对接 Mem0 托管服务; - 自托管 OSS 记忆:
Memory,以及全部 OSS 构建块(Provider)。
对应的公共 API 导出如下(继承自原文档,并与 mem0-ts/package.json 的 exports/typesVersions 字段相互印证):
| 导出 | 用途 | 导入方式 |
|---|---|---|
MemoryClient |
托管平台客户端 | import { MemoryClient } from 'mem0ai' |
Memory |
自托管 OSS 记忆 | import { Memory } from 'mem0ai/oss' |
| Providers | OSS 构建块 | import { OpenAIEmbedding } from 'mem0ai/oss' |
包的两个入口点在构建配置中一一对应:. 映射到 src/client/index.ts 的产物,./oss 映射到 src/oss/src/index.ts 的产物(下节详述)。
目录结构:client 与 oss 的二元划分
原文档给出的源码布局如下:
mem0-ts/src/
├── client/ MemoryClient (hosted platform)
└── oss/ Memory (self-hosted)
├── llms/
├── embeddings/
├── vector_stores/
└── graphs/
从 OSS 入口文件 的实际导出看,mem0ai/oss 以桶导出(barrel export)方式暴露了 Memory、memory.types、通用 types,以及 embeddings(OpenAI、Ollama、Google、Azure、AWS Bedrock、HuggingFace、Together、FastEmbed、VertexAI、LangChain、LM Studio 等)与 llms(OpenAI、Anthropic、Groq、Google、Ollama、LM Studio、Mistral、LangChain、LiteLLM、vLLM、AWS Bedrock 等)目录下的全部 Provider 实现,vector_stores 基类与实现同样经由该入口统一导出。这种"单一入口 + 全量桶导出"的结构,使得业务侧只需 import { ... } from 'mem0ai/oss' 即可完成组装,无需深入子路径。
构建体系:tsup 双入口、CJS + ESM 双格式
pnpm run build 背后是 tsup(构建工具),而真正的构建配置写在 mem0-ts/tsup.config.ts 中。该配置以"多入口"方式定义了两个独立的构建任务:
- client 入口:
entry: ["src/client/index.ts"],输出format: ["cjs", "esm"],开启dts: true生成类型声明; - oss 入口:
entry: ["src/oss/src/index.ts"],outDir: "dist/oss",同样 CJS + ESM 双格式并生成类型。
几个对使用者有实际影响的细节:
external列表显式列出了openai、@anthropic-ai/sdk、pg、redis、better-sqlite3、chromadb、@pinecone-database/pinecone、@qdrant/js-client-rest等几十个 Provider SDK。它们与 package.json 中的peerDependencies一致,且绝大部分在peerDependenciesMeta中标记为optional: true——即 SDK 本体只强制依赖axios、openai、uuid、zod四个包,其余向量库/LLM 驱动按需安装,避免不必要的依赖膨胀。define注入版本号:构建时把__MEM0_SDK_VERSION__全局常量替换为package.json的version,供运行时(如遥测、User-Agent)读取。- 产物结构与
package.json的main(./dist/index.js)、module(./dist/index.mjs)、types(./dist/index.d.ts)及exports子路径映射严格对应,typesVersions同时为mem0ai/oss提供类型解析。 pnpm run build实际展开为npm run clean && npx prettier --check . && npx tsup:先清理dist,再做 Prettier 格式检查,最后执行 tsup。也就是说格式检查是构建前置门禁,与 CI 中的 Lint 步骤(ts-sdk-ci.yml 中的npx prettier --check .)保持一致。
开发命令速查(pnpm only)
原文档约定:只使用 pnpm,绝不用 npm 或 yarn。以下是完整命令表,括号内为 package.json 中的实际脚本定义:
pnpm install
pnpm run build # tsup (CJS + ESM)
pnpm run test # jest, all tests
pnpm run test:unit # jest --coverage
pnpm run test:integration # jest, needs MEM0_API_KEY
pnpm run test:ci # jest --coverage --ci
pnpm run test:watch
pnpm run typecheck # tsc --noEmit
对照 scripts 字段可以补充几点实操细节:
test:unit的真实定义是jest --coverage --ci --testPathIgnorePatterns='/node_modules/' '/dist/' 'integration',即排除集成测试后跑全量单测并生成覆盖率;test:integration使用独立的 jest.integration.config.js 并附加--forceExit,运行前必须配置MEM0_API_KEY(CI 中通过secrets.MEM0_API_KEY注入);test是裸jest,test:ts显式指定jest.config.js;CI 的"验证包导出"步骤会用node -e分别requiredist/index.js与dist/oss/index.js,确认两个入口都能正常加载并统计导出数量;- 另有
pnpm run dev(nodemon 热重载)与pnpm start(运行 OSS 向量库示例脚本src/oss/examples/vector-stores/index.ts)可用于本地快速验证。
每一次改动之后都应运行 pnpm run typecheck(tsc --noEmit),这是文档强调的硬性纪律。
约定与工具链:与仓库其他子项目互不干扰
原文档列出的一系列约定,均可在仓库中逐条验证:
| 约定 | 仓库证据 |
|---|---|
| Node 20 和 22 为 CI 测试版本 | ts-sdk-ci.yml 中 matrix.node-version: [20, 22] |
| 构建:tsup,CJS + ESM 双输出 | tsup.config.ts 中两个 entry 均为 format: ["cjs", "esm"] |
| 格式化:Prettier,本包未配置 linter | package.json devDependencies 仅有 prettier;CI 的 Lint 步骤即 prettier --check |
| 测试:jest | jest.config.js 使用 ts-jest preset |
| TypeScript strict 模式 | tsconfig.json 中 "strict": true |
仅使用 ESM import 语法,禁止 require() |
源码入口文件均为 export 形式(见 OSS 入口) |
源码文件 snake_case.ts,测试 <module>.test.ts |
如 src/oss/src/ 下的 memory.types.ts 等命名 |
需要特别留意的是文档中的提醒:不要假设全仓库共享同一套 lint 配置。mem0-ts 用 Prettier + jest,而 cli/node/ 使用 Biome + vitest,integrations/vercel-ai-sdk/ 使用 ESLint,integrations/openclaw/ 使用 vitest。跨目录迁移代码或复制配置时,必须先确认目标子项目的工具链。
测试体系:ts-jest、路径映射与集成测试隔离
jest.config.js 的关键配置:
preset: "ts-jest",测试通过tsconfig.test.json转译(主tsconfig.json的exclude明确排除了**/*.test.ts,测试与构建两套编译配置分离);roots: ["<rootDir>/src", "<rootDir>/tests"],即测试既可与源码同目录(*.test.ts),也可集中放在tests/目录,对应原文档"<module>.test.ts"的命名约定;moduleNameMapper将^@/(.*)$映射到<rootDir>/src/$1,与 tsconfig 的paths: { "@/*": ["./src/*"] }保持一致,源码中可用@/...别名导入;setupFiles加载dotenv/config与jest.setup.ts,意味着单测中可直接读取.env中的环境变量;testPathIgnorePatterns排除/node_modules/与/dist/。
CI 流程(ts-sdk-ci.yml)对测试的编排是:仅在 mem0-ts/** 路径变化时触发,依次执行 Prettier 检查、构建、pnpm run test:unit、包导出验证,随后在 Node 20/22 双矩阵上运行 pnpm run test:integration(max-parallel: 1),覆盖率产物在 Node 20 节点上传为 coverage-report。
公共 API 面与文档同步纪律
原文档指出,Memory 的方法面与 Python SDK 保持一致:add、search、get、getAll、update、delete、deleteAll、history。并明确了一条跨仓库的硬性规则:
任何公共签名的变更,必须在同一个 PR 中更新
docs/。
这条约定被 CI 强制执行:ts-sdk-ci.yml 的 changelog_check 任务会在 PR 中比对 base 与 head 两个 SHA 的 mem0-ts/package.json 版本号,一旦发现版本 bump 而 docs/changelog/sdk.mdx 未变更,就会以错误信息终止流水线,要求"在 TypeScript tab 下为 v<新版本> 添加一条新的 <Update> 条目"。因此,改签名/升版本与更新 SDK 变更日志是不可拆分的原子操作。
发布流程:ts-v* 标签 + OIDC 发布 npm
原文档"Releasing"一节的完整描述为:
Tag 前缀
ts-v*触发ts-sdk-cd.yml,通过 OIDC 发布到 npm。先 bumppackage.json中的版本号。
对照 .github/workflows/ts-sdk-cd.yml 可以看到完整链路:
- 触发方式:该工作流由 release 路由器在
ts-v*标签发布后以workflow_call派发,也支持workflow_dispatch手动重发(输入tag,如ts-v2.1.0,并可选prerelease布尔值);作业入口有if: startsWith(inputs.tag, 'ts-v')的前缀校验。 - 环境:pnpm 10 + Node 22,
pnpm install --frozen-lockfile(cache-dependency-path指向mem0-ts/pnpm-lock.yaml),工作目录固定为mem0-ts。 - 构建:
pnpm run build(含 Prettier 门禁)。 - 发布:
npx npm@latest publish --provenance --access public,依赖permissions.id-token: write启用 GitHub OIDC 短期凭证,无长期 npm token 入库;--provenance保证包可溯源到具体构建。 - 预发布处理:当
prerelease=true时,脚本从package.json版本号的preid(例如x.y.z-beta中的beta)提取 dist-tag,改为--tag "$PREID"发布,避免预发布版本抢占latest。
因此发布顺序是:先改 package.json 的 version(并按需更新 docs/changelog/sdk.mdx)→ 打 ts-v<版本> 标签 → CI 自动构建并经 OIDC 发布,本地不需要执行 npm publish。
小结:参与该 SDK 开发前的检查清单
- 工具链:pnpm(勿用 npm/yarn)、Node 20 或 22、Prettier、jest、TypeScript 5.5(
strict开启); - 每次改动后:
pnpm run typecheck,必要时pnpm run build与pnpm run test; - 集成测试前:配置
MEM0_API_KEY,然后pnpm run test:integration; - 改公共签名:同 PR 内更新
docs/; - 升版本:bump mem0-ts/package.json 的
version+ 更新 docs/changelog/sdk.mdx,打ts-v*标签交由 ts-sdk-cd.yml 完成 OIDC 发布。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0625
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00