# 在 DeepSeek Harness 里安装 ai-memory(5 分钟) 中文。[English](INSTALL_DSH.md) 一条命令把本仓库 **根目录** 加成 dsh 插件。长对话把回合存进 **Rust + SQLite**,再注入一段 **有 token 预算** 的切片(`## Memory (project: …)`),而不是整段 transcript。 这是套在 `ai-memory` crate 上的 Cordis Host —— **不是**用 TypeScript 重写记忆,**也不是**自动让 LLM「抽事实」的插件。 --- ## 5 分钟路径(只走成功路径) 按顺序做。全程使用 **同一个** profile 名(下面用 `web`)。若第 3 步因 *Ignored build scripts* 失败,这是第一次的常见情况 —— 做第 4 步,再重跑第 3 步。 ### 1. 工具 ```bash node -v # v20 或更新 pnpm -v # dsh plugin add 会转发给 pnpm dsh --help # DeepSeek Harness CLI cargo --version # rustc 1.74+(prepare 会编 Rust) ``` 没有 `dsh`?先装 [deepseek-ai/deepseek-harness](https://github.com/deepseek-ai/deepseek-harness)。没有 `cargo`?用 [rustup.rs](https://rustup.rs/)。 ### 2. 钉死 commit SHA ```bash git ls-remote https://github.com/zzjzzb/ai-memory.git refs/heads/main ``` **应看到**(SHA 会变;复制 **左列** 40 位十六进制): ```text f3ce0b5c1a2b3c4d5e6f7890aabbccddeeff0011 refs/heads/main ``` 把这个值叫 `COMMIT`,贴进下一条命令。不要在你在意的机器上跟踪浮动的 `main`。 ### 3. 添加插件 ```bash dsh plugin --profile web add github:zzjzzb/ai-memory#COMMIT ``` 把 `COMMIT` 换成第 2 步的 SHA(不要写成两个 `#`)。 **成功时应看到**(第一次 cargo 可能要几分钟;日志会和 pnpm 交错): ```text [dsh-ai-memory] building ai-memory CLI (Rust source of truth)… [dsh-ai-memory] wrote bin/ai-memory [dsh-ai-memory] building napi addon… [dsh-ai-memory] wrote ai-memory.node (from libai_memory_node.so) [dsh-ai-memory] prepare: using napi (CLI also built) ``` macOS 可能是 `libai_memory_node.dylib`,Windows 是 `ai_memory_node.dll`。都算成功。 **napi 失败但仍算成功:** 插件编失败、CLI 写成功时: ```text [dsh-ai-memory] napi crate build failed — plugin will use the CLI fallback if present [dsh-ai-memory] prepare: using CLI fallback (napi addon not built). Runtime still uses the Rust crate, not a JS store. ``` **第一次常见失败(pnpm ≥10 拦住 `prepare`):** ```text [ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: dsh-ai-memory Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts. ``` dsh 也可能提示:把该包名键写进 profile 的 `pnpm-workspace.yaml`。去做第 4 步,然后 **原样重跑** 本步的 add。 ### 4. 允许 `prepare`(仅当第 3 步打印了 Ignored build scripts) profile 文件(没有就新建): ```text ~/.dsh/profiles/web/pnpm-workspace.yaml ``` 若设置了 `DSH_HOME`,则用 `$DSH_HOME/profiles/web/pnpm-workspace.yaml`。 **文件还不存在时,整份可贴:** ```yaml packages: - '.' allowBuilds: dsh-ai-memory: true ``` 若文件 **已存在**,把 `allowBuilds` 加在 **顶层**(和 `packages` 并列,不要嵌进 `packages`)。保留其它键。包名键必须是 pnpm 打印的 `dsh-ai-memory`,不是 GitHub URL。 然后重跑第 3 步的 add(同一个 `COMMIT`)。 把 `allowBuilds` 理解成:允许这个包在安装时在你的机器上执行代码,而且不在 agent 沙箱里。官方规则:[打包与安装插件](https://deepseek-harness.github.io/deepseek-harness/develop/basic/publish)。 ### 5. 确认层已激活 `--profile` 必须和 `plugin add` **相同**: ```bash dsh --profile web --dump-config ``` **应看到**(搜这个标题;周围 YAML 可能略有不同): ```text # == dsh-ai-memory ``` 还应看到类似: ```yaml - id: dsh-ai-memory name: dsh-ai-memory config: projectId: dsh tokenBudget: 8192 policy: chat prefetchEnabled: true ``` 若没有 `# == dsh-ai-memory`,说明包装上了但只是普通依赖,**没有**激活层 —— 见 [故障排除](#troubleshooting)。 重启以使层生效:`dsh --profile web` 或 `dsh web`。 ### 6. 第一次使用:记住一条事实 + 预算 pack 用 `--profile web` 启动 dsh。在对话里粘贴: ```text Call tool memory_remember with text "User prefers dark mode" and tier "profile". Then call tool memory_recall with text "dark mode". ``` 代理应调用 **这些工具名**: | 步骤 | 工具 | 参数 | |------|------|------| | 1 | `memory_remember` | `{ "text": "User prefers dark mode", "tier": "profile" }` | | 2 | `memory_recall` | `{ "text": "dark mode" }` | 其它 crate 工具(以后用):`memory_forget`、`memory_pin`、`memory_consolidate`、`memory_compact`。 **下一轮** 模型调用时,系统提示应含 Cordis 段 `ai-memory:pack`,形如: ```text ## Memory (project: dsh, 1 hits) - [profile id=mem-… score=…] User prefers dark mode ``` 这是 `prefetch_within_budget`,不是整段聊天。若看到完整 transcript,那是别处在倒历史 —— 不是本插件。 没有网页?做 [旗舰无头模拟](#flagship-sim)。 --- ## 你装上了什么(30 秒) 一条很长的支持会话(侧栏 bug,然后重复发票)若倒进模型,会撑爆约 100 万(或更小)的窗口。本插件会: 1. 用 `memory_remember` / `memory_pin` 落盘。 2. 下一轮模型调用前注入 Rust `prefetch_within_budget` 的 `ai-memory:pack`。 3. 按 `projectId` 隔离。同一个 `.db` 上两个项目,召回不会串。 根目录 `package.json` 的 npm 名是 **`dsh-ai-memory`**。`Cargo.toml` 的 crate 名是 **`ai-memory`**。同一个仓库。 --- ## 前置条件(第 1 步检查失败时) | 需要 | 为什么 | 怎么确认 | |------|--------|----------| | **Node.js 20+** | 插件 `engines`;Node 不对常常加载不了 `.node` | `node -v` | | **pnpm** | `dsh plugin add` = 在 profile 目录里跑 pnpm | `pnpm -v` | | **dsh CLI** | 写 profile 和 bundle 列表 | `dsh --help` | | **Git** | `github:zzjzzb/ai-memory` 是 git 拉取 | `git --version` | | **Rust `cargo`** | `prepare` 编 napi 和/或 CLI | `cargo --version`(MSRV **1.74+**) | | **网络** | 公开 GitHub | [github.com/zzjzzb/ai-memory](https://github.com/zzjzzb/ai-memory) | 若 CLI 不在 PATH,可用 `npx @deepseek-ai/dsh --help`。`dsh plugin add` 仍然需要 `pnpm`。 **profile** 一般在 `~/.dsh/profiles//`(或 `$DSH_HOME/profiles//`)。`web` 是常用 UI profile;第一次 `dsh plugin --profile web …` 会创建它。 不拉 GitHub、用本地 clone: ```bash git clone https://github.com/zzjzzb/ai-memory.git cd ai-memory dsh plugin --profile web add . dsh --profile web --dump-config ``` **不要**把 `github:zzjzzb/ai-memory#path:integrations/dsh-ai-memory` 当作用户路径 —— 那种 git 拉取带不上 `prepare` 必须编译的 Rust crate。 --- ## 配置旋钮(可复制) 后写的层覆盖先写的。补丁会 **整份替换 `config` 对象**(不按 key 深合并)。改 **profile** 的 `cordis.patch.yml`,不要改本仓库。 ```yaml # ~/.dsh/profiles/web/cordis.patch.yml - insert: - id: dsh-ai-memory name: dsh-ai-memory config: dbPath: ~/.local/share/ai-memory/dsh.db projectId: sme-support tokenBudget: 8192 policy: chat prefetchEnabled: true sectionOrder: 40 # cliPath: /usr/local/bin/ai-memory ``` | 字段 | 默认 | 含义 | |------|------|------| | `dbPath` | `~/.local/share/ai-memory/dsh.db` | SQLite 文件。空则用 `AI_MEMORY_DB` 或上述默认。`:memory:` 只给测试。 | | `projectId` | `dsh` | 隔离键。支持 vs 人事要用不同 id。 | | `tokenBudget` | `8192` | `prefetch_within_budget` 上限(`ceil(字符/4)`)。`256` 对齐旗舰模拟。 | | `policy` | `chat` | `chat` / `journal` / `default` —— **仅在创建项目时** 使用。 | | `prefetchEnabled` | `true` | 注册 `ai-memory:pack`。 | | `sectionOrder` | `40` | 提示段顺序(persona 一般是 0)。 | | `cliPath` | (自动) | napi 的 `.node` 没加载时强制走 `ai-memory` CLI。 | **不要**在组合包层之外再插一条 `id: dsh-ai-memory` —— 重复 `id` 可能让启动崩溃。要覆盖配置,只用上面这一行。 --- ## 和扎堆的 Memory 插件有何不同 | 常见 Memory 插件 | 本插件 | |------------------|--------| | 再调一次 LLM 自动抽事实 | 工具 + **显式** compact / consolidate | | 用 JS/Python 再实现一套记忆 | **Rust crate** 才是真相源 | | 「支持 100 万 token prompt」 | 长 session 存在盘上;每次只 **打包切片** | | 全局一个事实袋子 | `projectId` 隔离 | --- ## 绑定(napi vs CLI) 1. **napi-rs** —— 首选。同进程 `HostSession.dispatch`。 2. **`ai-memory` CLI** —— 同一套 JSON 信封,子进程;当 `ai-memory.node` 缺失或加载失败时用。 `prepare` 会两样都试,**有一样成功就算成功**。不会在 JavaScript 里重写召回。 --- ## 旗舰场景(无头) 工单 **T-1042**(侧栏)、**T-1088**(重复发票),pin Ada Chen,项目 `sme-hr` 不得泄漏 T-1042。 ```bash cargo build --bin ai-memory node scenarios/dsh-support-agent/sim/run.mjs npm test --prefix scenarios/dsh-support-agent cargo test --test dsh_support_scenario ``` **应看到:** `tokens <= tokenBudget`;`## Memory (project: sme-support, …)`;紧 pack 仍含 `PINNED-BILLING-OWNER-ADA`;`sme-hr` 的 pack **没有** T-1042。细节:[scenarios/dsh-support-agent/README.zh-CN.md](../scenarios/dsh-support-agent/README.zh-CN.md)。 映射到真 profile:同样 `github:zzjzzb/ai-memory#COMMIT`,在 profile 补丁里设 `projectId: sme-support`,把 [`seed/tickets.json`](../scenarios/dsh-support-agent/seed/tickets.json) 当用户句。 --- ## 故障排除 | 现象 | 常见原因 | 怎么办 | |------|----------|--------| | `Ignored build scripts: dsh-ai-memory` / `ERR_PNPM_IGNORED_BUILDS` | pnpm ≥10 拦住了 `prepare` | 把 [第 4 步](#allow-prepare) 贴进 **该 profile** 的 `pnpm-workspace.yaml`,再跑 **同一条** `add` | | 写了 `allowBuilds` 但 add 仍忽略脚本 | 改错文件 / 嵌进了 `packages` / 键名不对 | 必须是 **该 profile** 的 `pnpm-workspace.yaml`。顶层 `dsh-ai-memory: true`。不要写进 `ignoredBuiltDependencies` | | prepare 时 `cargo: command not found` / 没有 `rustc` | 没有 Rust 工具链 | [rustup](https://rustup.rs/) 后重新 add。只跑 JS 测试:`DSH_AI_MEMORY_SKIP_NATIVE=1` | | napi 编译失败,随后 `prepare: using CLI fallback` | 插件失败;CLI 编出来了 | **可以。** 插件走 CLI。确认 `--dump-config` 仍有 `# == dsh-ai-memory` | | prepare:napi 和 CLI 都没有 | 两次 Rust 构建都失败 | `rustc` **1.74+**(`rustup update`)。重新 add。检查磁盘空间 | | 加载插件时 `SyntaxError` / `Unexpected token` | **Node 不对** | `node -v` 必须 **≥ 20**。在这个 Node 上重新 `prepare` 编 `.node` | | 有 `.node` 但 `invalid ELF` / `wrong architecture` | 插件是在别的 OS/CPU 上编的 | 在本机重新编。或走 CLI 回退(`bin/ai-memory`)/ 设 `cliPath` | | `ai-memory CLI failed to start` | `.node` 没有 **而且** CLI 没有或不可执行 | `allowBuilds` 后重新 add,或在 clone 里 `npm run prepare`。在已安装包下找 `ai-memory.node` 和 `bin/ai-memory` | | `dsh: command not found` | CLI 不在 PATH | 用已经能跑 `dsh web` 的那个环境 | | Git 401 / `Repository not found` | 写错或私有 fork 没登录 | 公开 spec 是 `github:zzjzzb/ai-memory`。只有私有 fork 才需要 `gh auth login` | | `pnpm: command not found` | dsh plugin add 需要 pnpm | [pnpm.io/installation](https://pnpm.io/installation) | | `--dump-config` **没有** `# == dsh-ai-memory` | 层没激活 | 加的是 **根** `github:zzjzzb/ai-memory`,不是子目录 URL?`dsh plugin --profile web list`。写完 `allowBuilds` 再 add。确认根 `package.json` 有 `dsh.bundle.patch` | | 加了插件但 dump-config 是空的 / 旧的 | **profile 名不一致** | `dsh plugin --profile web add` 之后必须是 **`dsh --profile web --dump-config`**。光写 `dsh --dump-config` 是另一个 profile。注意 `web` / `Web` / `default` | | 有层标题但没有工具 | 没重启 profile;inject 失败 | 重启 `dsh --profile web`。启动日志:无法解析 `dsh-ai-memory` | | 重复 loader `id: dsh-ai-memory` | 组合包层 **和** 手动 insert 了同一个 id | 只走一条路:要么 `dsh plugin add`,要么手动补丁行 | | 记忆是空的 / 工单不对 | `projectId` 或 `dbPath` 不对 | 默认库 `~/.local/share/ai-memory/dsh.db`。按项目隔离 | | pack 看起来像整段聊天 | 别处在倒 prompt,或你没看 `ai-memory:pack` | 搜 `## Memory (project:`。不要自己把 transcript 贴进去 | --- ## 下一步:dsh.pub(可选) **不必**上目录也能用插件。Topic **`dsh-plugin`** 已经打在仓库上。 若要目录条目,请自行提交仓库 URL: - [https://dsh.pub/zh/submit/](https://dsh.pub/zh/submit/) - [https://dsh.pub/en/submit/](https://dsh.pub/en/submit/) 本指南不会替你提交。 --- ## 相关文档 - 背书 / 架构:[INTEGRATION_DSH.zh-CN.md](INTEGRATION_DSH.zh-CN.md) - 插件内部:[integrations/dsh-ai-memory/README.md](../integrations/dsh-ai-memory/README.md) - Crate 用法:[USAGE.zh-CN.md](USAGE.zh-CN.md)