@easbot/memory
v0.3.23
Published
Memory management library for EASBOT ecosystem - 智能记忆管理库,支持混合搜索、中英文分词、增量索引
Maintainers
Readme
@easbot/memory
English | 中文
EASBOT 生态系统的长期记忆管理库(v0.4.0)。提供分层记忆、KG scope 三档隔离、9 op 统一调度、混合搜索与可观测治理。
特性(v0.4.0)
- 10 op 统一入口(ADR 0069 +1 sync):
recall / remember / forget / extract / consolidate / sync / graph_query / status / doctor / init,MCP / CLI / Agent Tool 三端共享。 - KG scope 三档隔离:每个节点带
owner_agent_id;scope ∈ {agent_only, shared_only, both};MCP 默认agent_only,trusted local 可both。graph_query/status/doctor/init的agentId为 optional,缺省 fallback'default'(ADR 0068 P0-A 反转)。 - 分层记忆:短期 / 可写自记忆 / 历史长期记忆三层,混合搜索(FTS + 向量 + 图)。
- 可观测性:10 op 全部走
Log.create({ service })英文结构化日志;status/doctor提供离线诊断。 - i18n:
zh-CN/en-US双 locale;@easbot/memoryAPI 日志保持英文,文案走t()。 - 可移植:纯 TS 6.x;依赖
better-sqlite3(transitive via@easbot/database)+@easbot/database(sync facade)+@easbot/types/@easbot/utils(决策 0036 统一封装,禁止直接 require better-sqlite3 / @modelcontextprotocol/sdk)。 - 三包统一后台支撑(决策 0036 / 0049 / 0051 / 0052):database 走
@easbot/databasecreateSyncSqliteConnection;MCP 走@easbot/mcpToolRegistry+createAndStartStdioServer;CLI 输出走@easbot/terminalprintHuman+emitJsonOk+COMMANDS_HELP单一数据源。
安装
pnpm add @easbot/memory使用示例
9 op 入口
import { executeOp } from '@easbot/memory';
// v0.4.0 简化:不再有 `createMemorySystem` + `setOpSystem` 主类;
// 全部 op 走 `executeOp(name, args, ctx)` 统一入口(agentId 走 ctx 注入)。
// 1. recall
const recall = await executeOp<{ hits: unknown[] }>(
'recall',
{
// 不再传 agentId 到 args 顶层 —— 走 ctx.agentId
query: 'user preference',
limit: 10,
scope: 'agent_only',
// dbPath / workspaceDir 走 ctx 或 service 配置;可省略
dbPath: '/path/to/memory.db',
workspaceDir: '/path/to/workspace',
rootDir: '/path/to/workspace',
locale: 'en-US',
remote: false,
},
{
agentId: 'agent-1',
isTrustedLocal: true,
},
);
// 2. remember
const saved = await executeOp<{ id: string }>(
'remember',
{
content: 'prefers TypeScript',
category: 'user_preference',
importance: 9,
dbPath: '/path/to/memory.db',
workspaceDir: '/path/to/workspace',
rootDir: '/path/to/workspace',
locale: 'en-US',
remote: false,
},
{ agentId: 'agent-1', isTrustedLocal: true },
);
// 3. forget(按 category 全删)
await executeOp(
'forget',
{
category: 'user_preference',
maxDelete: 1000,
dryRun: false,
dbPath: '/path/to/memory.db',
workspaceDir: '/path/to/workspace',
rootDir: '/path/to/workspace',
locale: 'en-US',
remote: false,
},
{ agentId: 'agent-1', isTrustedLocal: true },
);KG scope 三档
// 只看本 Agent 节点(默认;MCP 入口强制)
await executeOp('graph_query', { agentId: 'agent-1', kind: 'nodes', scope: 'agent_only' }, { agentId: 'agent-1', isTrustedLocal: true });
// 只看共享节点
await executeOp('graph_query', { agentId: 'agent-1', kind: 'nodes', scope: 'shared_only' }, { agentId: 'agent-1', isTrustedLocal: true });
// 本 Agent + 共享(trusted local only;MCP 入口会拒绝)
await executeOp('graph_query', { agentId: 'agent-1', kind: 'nodes', scope: 'both' }, { agentId: 'agent-1', isTrustedLocal: true });
// v0.4.1+:不传 agentId → fallback 'default',全局 KG 视图(trusted local only)
await executeOp('graph_query', { kind: 'nodes', scope: 'both' }, { isTrustedLocal: true });Markdown 渲染
import { renderOperationMarkdown } from '@easbot/memory';
const md = await renderOperationMarkdown('recall', recallResult, { toolName: 'memory_recall' });9 op 清单
| op | trusted local only | agentId | 用途 |
|---|---|---|---|
| recall | ❌ | ✅ 必填 | 混合搜索(FTS + vector + graph) |
| remember | ❌ | ✅ 必填 | 持久化一条 self-memory fact |
| forget | ❌ | ✅ 必填 | 按 factId / category / 时间窗删除(支持 dryRun) |
| extract | ❌ | ✅ 必填 | 从 session 抽取 facts |
| consolidate | ✅ | ✅ 必填 | 整理 / 去重 / 摘要 |
| sync | ✅ | ✅ 必填 | db → .md 兜底生成(幂等)+ active/ 过期文件归档(默认 30 天) |
| graph_query | ❌ (scope=both 时 ✅) | ⚠️ optional,缺省 'default' | KG 节点 / 边 / 邻居查询 |
| status | ❌ | ⚠️ optional,缺省全局聚合 | 系统状态快照 |
| doctor | ✅ | ⚠️ optional,缺省全库扫描 | 数据完整性检查(支持 repair) |
| init | ✅ | ⚠️ optional,缺省 'default' | 初始化 workspace(支持 force) |
P0-A 反转说明(v0.4.1 起):
graph_query / status / doctor / init 四个 op 的 agentId 改为 optional,缺省时 fallback 到固定值 'default',不再因缺失 agentId 抛错。这条决策与 ADR 0055 / 0056 / 0057 中"agent scope 必填"的早期语义相反,目的是让 CLI / 状态查询 / 一次性诊断场景可以无 agent 上下文运行。
graph_query不传 agentId → 全局 KG 视图(scope仍由调用方决定,trusted local 默认'both')status不传 agentId → 跨 agent 聚合统计(不再是单一 agent 视图)doctor/init不传 agentId → 全局默认 agent ='default',与 status / graph_query 口径一致
API 分类
services(9 op 业务层)
import { recall, remember, forget } from '@easbot/memory/services';operations(9 op 注册表 + executeOp)
import { executeOp, OP_REGISTRY, ALL_OPS } from '@easbot/memory/operations';format(schema + markdown + text + truncate + render)
import { renderOperationMarkdown } from '@easbot/memory/format/render';hooks(4 hook 类型)
import type { PreCompactHook, SessionStartHook, SessionEndHook, PostToolFailureHook } from '@easbot/memory/hooks';CLI / MCP 双入口(v0.4 stage 4 落地)
独立 CLI(easbot-memory)
# 安装后即可用(package.json bin: easbot-memory)
easbot-memory init --workspace-dir <dir> [--agent <id>]
easbot-memory status [--agent <id>] [--json]
easbot-memory doctor [--repair] [--agent <id>]
easbot-memory recall --query <q> --agent <id> [--limit <n>] [--json]
easbot-memory remember --content <text> --category <c> --importance <1-10> --agent <id>
easbot-memory forget --agent <id> [--fact-id <id>] [--dry-run]
easbot-memory extract --session <sessionId> [--last-n <n>] --agent <id>
easbot-memory consolidate --agent <id> [--window-days <n>]
easbot-memory sync --agent <id> [--window-days <n>] [--dry-run] [--json]
easbot-memory graph --kind <nodes|edges|neighbors> [--query <q>] [--agent <id>]
easbot-memory config [--json]
easbot-memory mcpStatus / Doctor 统一输出格式(决策 0073 / CLI 规范 v1.4)
memory status / memory doctor 与 codebase / note 三包统一走 @easbot/terminal 的 formatKnowledgeStatus / formatKnowledgeDoctor 渲染,视觉与字段结构完全一致。
status 输出示例
$ easbot memory status
─ memory status ───────────────────────────────────────────────────
Root directory E:/work/my-project
Config ✓ E:/work/my-project/.easbot/memory.json
DB ✓ E:/work/my-project/.easbot/db/memory.db (5242880 bytes)
Index state ready
Schema version 1
Extraction version 1
Backend better-sqlite3
Last sync 2026-08-31T14:23:11.000Z
Vector enabled ✓
Embedding dims 1536
LLM:
Initialized ✓
Provider openai
Capabilities:
Embedding ✓ text-embedding-3-small
Graph LLM ✓ gpt-4o-mini
Rerank LLM ✗
Counts:
facts 256
agent_only 180
shared_only 42
both 34
Healthy ✓doctor 输出示例
$ easbot memory doctor
─ memory doctor ───────────────────────────────────────────────────
Healthy ✓
Duration 98 ms
Backend availability:
- better-sqlite3 ✓
- node:sqlite ✗
- @tursodatabase/database ✗
DB stats:
page_count 320
page_size 4096
freelist_count 0
Checks 10 total (0 error, 0 warn, 1 info, 9 ok)
[ok] ✓ database: database file exists and accessible (12 ms)
[ok] ✓ fts: FTS5 available (8 ms)
[ok] ✓ vector: vector index usable (23 ms)
[ok] ✓ schema: schema version matches (2 ms)
[ok] ✓ lock: no lock contention (1 ms)
[ok] ✓ disk_space: sufficient (156 MB free) (3 ms)
[ok] ✓ orphan: no orphan records (18 ms)
[info] ℹ llm: LLM reachable (ping 42 ms) (42 ms)
[ok] ✓ embedding_cache_unused: no unused embedding cache entries (5 ms)
[ok] ✓ embedding_dims_consistency: meta=1536 probe=1536 config=1536 (35 ms)关键字段说明
| 字段 | 说明 |
|------|------|
| LLM.initialized | LLM 是否已初始化(配置有效且可达) |
| LLM.capabilities | 三大能力:embedding / graphLlm / rerankLlm,各显示模型名或 ✗ |
| Vector enabled | 向量索引是否启用 |
| Embedding dims | 实测 embedding 维度(非仅读 config),status 末尾探测并回填 meta 表 |
| embedding_dims_consistency | doctor 第 9 项检查:对比 meta / probe / config 三方维度是否一致 |
| factsByCategory | memory 独有:按 category 统计的 fact 数量(Counts 段展示) |
JSON 输出(--json)
$ easbot memory status --json
{
"ok": true,
"data": {
"rootDir": "E:/work/my-project",
"configExists": true,
"dbExists": true,
"indexState": "ready",
"schemaVersion": 1,
"llm": {
"initialized": true,
"capabilities": { "embedding": true, "graphLlm": true, "rerankLlm": false },
"embeddingModel": "text-embedding-3-small",
"graphModel": "gpt-4o-mini",
"providerId": "openai"
},
"counts": { "facts": 256, "agent_only": 180, "shared_only": 42, "both": 34 },
"healthy": true
},
"meta": { "scope": "all" }
}兼容 CLI 输出规范 v1.4 / 决策 0040。
v0.4.1 起:
init/status/doctor/graph的--agent为可选,缺省时 fallback 到'default'(CLI / 一次性诊断场景无需 agent 上下文);其余 6 op(recall/remember/forget/extract/consolidate/sync)仍要求显式--agent,缺失时返回非 0 退出码。
Agent 委派模式(v0.4 stage 4 T-M017a)
# @easbot/agent 的 memory 子命令直接委派 handleMemoryCli(决策 0049)
easbot memory recall --query "user preference"
easbot memory remember --content "prefers TypeScript"
easbot memory mcp # 启动 MCP stdio serverMCP stdio server(v0.4 stage 4 T-M013abc)
import { MemoryStdioServer } from '@easbot/memory';
// 启动 9 tool 的 MCP stdio server(Cline / Claude Code / Continue 可调用)
// v0.4.0:start 签名简化(不需要 `memorySystem` 参数,handler 走 executeOp 调度 services)
await MemoryStdioServer.start({
name: 'easbot-memory',
version: '0.4.0',
description: 'EASBot memory MCP server',
});
// 列出 10 个 tool 名(ADR 0069 +1 sync)
const tools = MemoryStdioServer.getToolNames();
// ['memory_recall', 'memory_remember', 'memory_forget', 'memory_extract', 'memory_consolidate', 'memory_sync', 'memory_graph_query', 'memory_status', 'memory_doctor', 'memory_init']10 tool 清单(与 OP_REGISTRY 一一对应):
memory_recall/memory_remember/memory_forget/memory_extract/memory_consolidate/memory_sync/memory_graph_query/memory_status/memory_doctor/memory_init
handleMemoryCli 委派范式
import { handleMemoryCli, setGlobalAdapter, setInstanceAdapter } from '@easbot/memory';
// 1. 注入 adapter(cli 路径 / agent 路径)
setGlobalAdapter({ Path: { /* ... */ } });
setInstanceAdapter({ directory: process.cwd(), worktree: process.cwd() });
// 2. 委派给统一 handler
const result = await handleMemoryCli(['recall', '--query', 'test'], {
version: '0.4.0',
cwd: process.cwd(),
});
if (result.code !== 0) process.exit(result.code);fact → .md 文档同步(v0.5+ ADR 0060)
remember op 在事务提交后会best-effort地将 fact 渲染为 Markdown 文件,便于:
- debug:开发者直接看磁盘上的「人类可读副本」
- 二次开发:未来
note工具可通过 file watcher 检测 memory .md 变化触发 cross-reference 更新 - 灾备:file 失败不阻塞 db 写入(与 v0.3 行为一致)
路径格式(v0.5.1+ 反馈修正)
{workspaceDir}/.easbot/memory/active/{category}/{YYYY-MM-DD}.md- 按 category 分目录(
task_context/workflow/user_preference/ ...) - 按 createdAt 本地日期分文件(一日一文件,append 模式,多 fact 共享)
- 文件名 =
{YYYY-MM-DD}.md(不再含 fact.id) memory_facts.file_path列存相对 workspaceDir 的 POSIX 路径- 归档路径(ADR 0069 sync):
{workspaceDir}/.easbot/memory/archive/{YYYY-MM}/{category}/{YYYY-MM-DD}.md(扁平结构)
Markdown 模板
---
id: mem_xxx
agent_id: easbot-xxx
category: task_context
importance: 7
created_at: 2026-08-22T22:00:00Z
updated_at: 2026-08-22T22:00:00Z
tags: [tag1, tag2]
---
# fact 内容(一行一个)
**category**: task_context | **importance**: 7/10 | **source**: session_self_write编程式调用(高级)
大多数场景不需要直接调 —— 走 executeOp('remember' / 'forget') 即可。需要精细控制时(如批量迁移 / 自定义路径策略):
import { factFileSync } from '@easbot/memory/services';
// 1. 计算路径(不写文件)
const absPath = factFileSync.resolvePath(fact, '/path/to/workspace');
// 2. 渲染 Markdown 字符串(不写文件)
const md = factFileSync.renderMarkdown(fact);
// 3. 写文件(best-effort;失败返回 ok=false + log.warn)
const { ok, relPath, absPath } = await factFileSync.write(fact, '/path/to/workspace');
// 4. 删文件(按 fact.filePath;不存在返回 ok=true,idempotent)
const { ok, absPath } = await factFileSync.delete(fact, '/path/to/workspace');策略与限制
- best-effort:写/删文件失败 → log.warn + 返回
ok=false,不抛错,不阻塞主流程 - 单进程假设:未实现跨进程文件锁(与 v0.3 一致)
- 不做 stale orphan 清理:forget 删 db 后删文件;如 db 删成功文件删失败 → 留 stale .md(doctor 第 9 项「orphan file 检测」后续增强)
详见 docs/decisions/0060-memory-fact-file-sync-restore.md。
数据库位置
默认存储位置:$XDG_DATA_HOME/easbot/memory.db
- Linux:
~/.local/share/easbot/memory.db - macOS:
~/Library/Application Support/easbot/memory.db - Windows:
%APPDATA%/easbot/memory.db
决策与迁移
- ADR 0069(v0.5+ memory sync op:两阶段流水线 —— db → .md 兜底生成(幂等)+ active/ 过期归档):
docs/decisions/0069-memory-sync-op.md - ADR 0068(v0.4.1 P0-A 反转:graph_query / status / doctor / init 的 agentId 改为 optional,缺省 fallback
'default'):docs/decisions/0068-p0a-agent-id-optional.md - ADR 0060(v0.5+ fact → .md 同步恢复):
docs/decisions/0060-memory-fact-file-sync-restore.md - ADR 0055 / 0056 / 0057(v0.4 决策):
.easbot/protocol.json与docs/decisions/00NN-*.md - 迁移脚本:
scripts/migrate/{scan,apply,review}.ts+scripts/db-backup.ts(v0.3 → v0.4owner_agent_id列添加 + 默认 scope = agent_only) - CI guard(v0.4 stage 5 三包统一后台支撑):
scripts/check-database-facade.sh(禁止直接 require better-sqlite3 / node:sqlite / createRequire)scripts/check-mcp-facade.sh(禁止直接 import @modelcontextprotocol/sdk)scripts/check-terminal-facade.sh(CLI 输出走 @easbot/terminal + COMMANDS_HELP 单一数据源)scripts/check-cmd-i18n-coverage.sh(zh-CN / en-US 双 locale 一致性 + switch-case 路由校验)
- L-M13 / L-M14 / L-M15 教训沉淀:
.easbot/knowledge/tasks/memory-v04-refactor/findings.md
开发
# 安装
pnpm install
# 构建
pnpm build
# 测试(vitest 4)
pnpm test:run
# 类型检查
pnpm type-check
# lint(biome 2.x)
pnpm biome-lint许可证
MIT
