开源TypeScript SDK,为自定义AI Agent提供生产级的持久化记忆管理,支持跨会话知识保留、自动脱敏、任务感知召回,解决手动管理向量数据库的痛点。
大多数开发者在构建自定义 AI Agent 时,都会花数周时间手动解决内存管理问题:
他们搭建向量数据库封装层。
他们编写临时分块逻辑。
他们在记忆时效性、敏感信息过滤和上下文窗口膨胀之间苦苦挣扎。
@memofs/core 提供了一个开源的、生产级可用的 TypeScript SDK,只需几行代码,就能为任何自定义 AI Agent 提供持久化、文件优先的持久记忆能力。
由于 @memofs/core 使用标准的 .memofs/ 工作目录,自定义 TypeScript Agent 持久化的记忆可以与最终用户开发者工具(Claude Code、Cursor、Copilot、Codex 等)无缝共存。开发者可以使用纯文本工具或 npx memofs 检查 Agent 记忆,而自定义 Agent 框架在代码库中共享单一事实来源。
在本教程中,我们将构建一个具备记忆能力的 TypeScript Agent,它能够跨会话保留知识、自动清理敏感数据、执行任务感知召回,并干净地更新过时事实。
将 @memofs/core 添加到你的项目中:
npm install @memofs/core
# or
pnpm add @memofs/core
注意:@memofs/core 需要 Node.js >= 22。
核心引擎使用 MemoFS 类和 Node 文件系统存储(createNodeFsMemoryStore from @memofs/core/node-fs)来实例化。
import { MemoFS } from "@memofs/core";
import { createNodeFsMemoryStore } from "@memofs/core/node-fs";
// 1. 初始化本地文件系统存储根目录
const store = createNodeFsMemoryStore({
rootDir: process.cwd(),
});
// 2. 实例化 MemoFS 记忆引擎
const memo = new MemoFS({
store,
projectId: "my-custom-agent",
mode: "local", // 'local' | 'hybrid'
});
另外,Node 消费者可以使用 createNodeMemoFs 辅助函数:
import { createNodeMemoFs } from "@memofs/core/node-fs";
const memo = createNodeMemoFs({
rootDir: process.cwd(),
projectId: "my-custom-agent",
mode: "local",
});
local:离线存储。记忆的读取和写入直接针对本地 .memofs/ 文件执行,零网络请求。
hybrid:快速写入本地文件,同时异步同步副本到 MemoFS Cloud,实现跨机器访问。
在执行 Agent 任务之前,使用 memo.context() 检索紧凑的、结构化的记忆简报,注入到 LLM 系统提示词中。
async function buildAgentSystemPrompt(userTask: string): Promise<string> {
// 查询 MemoFS 获取任务感知上下文
const contextResult = await memo.context({
query: userTask,
taskType: "refactor", // 'coding' | 'debug' | 'refactor' | 'docs' | 'general'
maxBytes: 12000,
});
return `
You are an autonomous coding agent.
## PROJECT MEMORY BRIEFING
${contextResult.text}
## USER TASK
${userTask}
`;
}
MemoFS 自动格式化简报,将输出分类为核心规则、相关历史记录和活跃约束,同时将总大小保持在指定 maxBytes 上限之下。
当你的 Agent 做出设计决策、发现约束条件或完成任务时,使用 memo.writeMemory() 将其持久化。
async function recordAgentDecision(decisionText: string, category: "decision" | "constraint" | "note") {
const result = await memo.writeMemory({
content: decisionText,
kind: category,
tags: ["architecture", "auth"],
});
if (result.tier !== "durable") {
console.warn(`Memory stored as ${result.tier} (reason: ${result.tierReason}).`);
return;
}
console.log(`✓ Durable memory persisted cleanly with ID: ${result.id}`);
}
// Example invocation:
await recordAgentDecision(
"Database queries must use Drizzle ORM prepared statements for SQL injection safety",
"constraint"
);
在写入 .memofs/memory/notes.md 之前,@memofs/core 会自动执行以下操作:
敏感信息黑名单检查: upfront 拒绝 API keys(sk-...)、JWT 和私有令牌(除非传入 --allow-secrets 或显式标志)。
确定性持久性分类:判断该事实是否具有长期价值(durable)或仅单轮相关性(transient)。
当架构事实发生变化时,避免创建冲突记忆。写入新记忆并通过 memo.graph.upsertEdges() 在实体图中关联关系:
async function updateStaleFact(oldMemoryId: string, newFactText: string) {
// 1. 写入新决策
const result = await memo.writeMemory({
content: newFactText,
kind: "decision",
tags: ["auth"],
});
// 2. 在关系图中将新记忆链接为取代旧记忆
await memo.graph.upsertEdges({
edges: [
{
source: result.id,
target: oldMemoryId,
type: "supersedes",
},
],
});
console.log(`✓ Created new memory ${result.id} superseding ${oldMemoryId}`);
}
MemoFS 更新 .memofs/graph/edges.jsonl。后续查询会自动呈现最新事实,同时保留历史上下文以供审计。
以下是完整的可运行 Agent 循环,演示了记忆感知上下文注入、执行和记忆持久化:
import { MemoFS } from "@memofs/core";
import { createNodeFsMemoryStore } from "@memofs/core/node-fs";
async function runMemoryNativeAgent(userPrompt: string) {
// 1. 初始化记忆引擎
const store = createNodeFsMemoryStore({ rootDir: "." });
const memo = new MemoFS({
store,
projectId: "agent-demo",
mode: "local",
});
// 2. 检索记忆简报
const context = await memo.context({ query: userPrompt, taskType: "coding" });
console.log("--- INJECTED MEMORY BRIEFING ---");
console.log(context.text);
// 3. 执行 Agent 任务(模拟 LLM 响应)
console.log("Executing agent task...");
// 4. 将学到的事实持久化到 MemoFS
const writeResult = await memo.writeMemory({
content: "Session tokens expire in 15 minutes",
kind: "decision",
tags: ["auth", "security"],
});
console.log(`✓ Session complete. Memory persisted to .memofs/ with ID: ${writeResult.id}`);
}
runMemoryNativeAgent("Refactor our user session timeout");