@tr1v3r/dsh-ltm

memoryinstall failsnpmMIT

Local SQLite long-term memory with CJK-aware search, BM25 and character n-gram cosine reranking, deduplication, and lifecycle management.

下载量 / Downloads
3,187
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add @tr1v3r/dsh-ltm

Sandbox test results

StageResult
1 install✗
2 list—
3 mount—
4 boot—
First error
dsh: initialized profile web at /home/node/.dsh/profiles/web

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

dsh-ltm(中文说明)

本文件是 [README.md](README.md) 的中文对照说明;内容以英文版为准,两者同步更新。

面向 DeepSeek Harness(dsh)的结构化长期记忆插件:

本地 SQLite 存储 + 中文感知分词检索(CJK 二元分词 + FTS5)、BM25 与字符 n-gram 余弦混合重排、

近似重复检测、过期复核、以及从 dsh-memory 的一次性迁移 —— 零强制联网依赖。

为什么需要

  • dsh-memory@0.1.0 是纯文本 + 默认分词器的 FTS5:中文检索基本不可用(整句变成单个 token)。
  • 长期记忆需要追加/检索之外的生命周期管理:结构化 scope 与 tags、重复检测、复核时间戳、有界召回。

安装到 profile

DSH peer 兼容范围在原有 <0.2.0 范围之外,包含实测通过的桌面版 0.2.1-rc.1、0.2.1-rc.3 与 CLI 0.2.1-rc.2。其他 0.2.x 预发布版本仍需单独验证。

@tr1v3r/dsh-ltm 0.1.2 及以上可用一条命令安装并注册 bundle 配置:

dsh plugin --profile web add @tr1v3r/dsh-ltm

把 web 换成你的 profile 名(例如 dsh-tui),然后重启该 profile。bundle 会把数据库路径设为

$DSH_HOME/memory/ltm.db;无需 API key 或 embedding 服务。

替换 dsh-memory 时先禁用其旧条目:两个插件都注册 memory_write / memory_search /

memory_forget。若此前手工插入过 ltm 条目,启用 bundle 前先移除手工 insert,避免重复实例。

安装不会自动迁移旧库;见[从 dsh-memory 迁移](#从-dsh-memory-迁移)。

手工组合(含缺少 bundle manifest 的 0.1.0–0.1.1):安装 npm 依赖后,在 profile 的

cordis.patch.yml 里 insert:

- insert:
    - id: ltm
      name: '@tr1v3r/dsh-ltm'
      config:
        path: !!js dshHomePath('memory/ltm.db')

path 必填,代码侧无默认值。推荐的部署路径是 $DSH_HOME 下的 memory/ltm.db ——

独立新库,本插件绝不写旧 memory/memory.db。

配置

键 · 默认 · 含义

path · (必填) · SQLite 文件,或 :memory:

defaultScope · "" · 兜底 scope;关闭自动检测时作为固定 scope

autoProjectScope · true · 从每个 agent 会话的 cwd/Git 仓库推导当前项目

escapeSequences · [] · 可选:渲染进提示词前以零宽空格打断的输出序列

promptRecentCount · 10 · 召回分节中未置顶的最近记忆数

promptMaxChars · 2000 · 分节硬性 UTF-16 字符预算;置顶记录优先保留

promptMaxTokens · (未设) · 可选的正安全整数硬 token 上限(与字符预算并存)

promptTokenizerPath · (未设) · 本地受支持的 Hugging Face tokenizer.json;与 promptMaxTokens 成对必填

maxTextChars · 2000 · 单条记忆最大字符数

searchLimitDefault / searchLimitMax · 10 / 50 · 检索结果数量限制

promptOrder · 50 · 召回分节顺序

dedupeThreshold · 0.8 · Jaccard 相似度 ≥ 该值判定近似重复

dedupeCosineThreshold · 0.92 · 余弦相似度 ≥ 该值同样判定近似重复

staleAfterDays · 90 · 超过该天数未确认的记忆标记 stale

默认情况下,记忆文本在召回提示词中逐字保留。escapeSequences 是部署级显式开关,

面向把渲染后的提示词再交给其它基于定界符解析器的环境;DSH 本身不需要。

非法值(空路径、非整数边界、阈值超出 [0,1]、短于 2 字符或含零宽空格的转义序列)

在插件加载时即抛错 —— fail loud,而不是等第一次工具调用。

自动项目隔离

autoProjectScope: true 时,每个 agent 解析自己的 session.header.cwd;绝不使用共享的

DSH 进程 cwd。Git 检出以其 canonical common Git directory 识别,因此子目录与 linked

worktree 共享同一项目 scope;非 Git 工作区按 canonical 目录识别。Git scope 名只含 SHA-256

短摘要(各种 linked-worktree 布局保持一致);目录 scope 另带可读 basename。绝不存储绝对路径。

模型面默认刻意收窄:

  • 写入与近似重复检查使用当前项目 scope;
  • 检索与自动召回只看当前项目 + 全局记忆(scope="");
  • update / forget / confirm / merge 拒绝可见 scope 之外的记录,merge 绝不跨 scope;
  • memory_list 与 CLI 保留显式跨项目聚合/管理面。

设 autoProjectScope: false 可只用 defaultScope 作为固定部署 scope("" 即仅全局)。

scope 是上下文隔离边界,不是操作系统权限边界:能直接访问 SQLite 文件或 CLI 的人仍可管理所有记录。

可选离线提示词 token 预算

两个选项默认都不启用:既有纯字符输出保持不变。必须成对设置。可选依赖

@huggingface/tokenizers@0.2.0 只在配置了该功能的插件启动时加载一次;渲染保持同步,

无网络请求、下载或文件读取。CLI doctor 可用显式 JSON 配置渲染诊断投影(绝不读取运行中的

profile)。支持受限且经过保真测试的 ByteLevel/BPE 子集;不支持的管线/选项在启动时失败,

而不是静默近似。上限统计完整的转义后召回分节(含头部、元数据、换行、截断省略号与

省略提示);置顶记录优先,recent 绝不为了省略提示挤掉置顶。离线计数对所选 tokenizer 定义是

精确的,不是服务端用量的承诺。详见 [docs/prompt-token-budget.md](docs/prompt-token-budget.md)。

模型工具

兼容 dsh-memory 习惯:

  • memory_write(text, tags?, pinned?, force?) —— 先做去重检查;近似重复返回候选而非写入,

除非 force: true

  • memory_search(query, limit?) —— 中文感知分词 + 混合重排
  • memory_forget(id, expectedRevision?)

新增:

  • memory_update(id, text?, tags?, pinned?, expectedRevision?) —— 原位修订,保留 id
  • memory_confirm(id | "*", expectedRevision?) —— 刷新复核时间戳、清除 stale
  • memory_list(scope?, tags?, stale?, limit?) —— 过滤浏览(tags AND 语义)
  • memory_merge(targetId, sourceIds[], text?, tags?, expectedRevision?, expectedSourceRevisions?) —— 合并重复;tags 默认取并集

身份未知时先检索既有事实/主题再写入。同一事实的状态变化应走 memory_update,

而不是再写一条或 force 写入近似重复。相似度不能证明等价或矛盾;请审阅候选。这是指引,

不是强制的额外检索调用。

成功的置顶写入与相关更新附带可选 budget 反馈;去重拦截的写入不声明新的置顶预算。

乐观并发(revision CAS,#32 阶段一)

每条存储的记忆都带 revision(正整数,从 1 起,与时钟无关)。所有读取 —— 检索结果、

list、提示行((#id, rev N, …))、去重候选 —— 以及每次成功写入都会报告它。向

memory_update / memory_confirm / memory_forget / memory_merge 传入

expectedRevision(你最近读到的版本)即把该变更变成同一个 BEGIN IMMEDIATE 事务内的

比较交换:若记录在你读取之后发生了变化,操作以结构化 MEMORY_REVISION_CONFLICT

({code, operation, id, expectedRevision, currentRevision})失败且什么都不写 ——

不会自动重试你的旧内容。重新读取记录,用其当前版本重试。

  • 省略版本字段保持旧的、不受保护的行为;不带版本的调用绝不宣称受 CAS 保护。
  • 严格模式的 memory_merge 要求目标的 expectedRevision 加上恰好覆盖唯一源 id 集合的

expectedSourceRevisions;部分/重复/多余/包含目标的声明在任何读取之前即被拒绝。

  • id: "*" 的 memory_confirm 只刷新复核时间戳,不是逐条验证,且拒绝 expectedRevision。
  • 冲突与未知/已删除/越权 id 都是纯元数据失败(错误码:MEMORY_REVISION_CONFLICT、

MEMORY_NOT_FOUND、MEMORY_INVALID_ARGUMENT、MEMORY_SCOPE_MISMATCH、

MEMORY_REVISION_OVERFLOW);错误中绝不包含记忆正文。

  • 成功的 update/confirm/merge 返回新 revision;memory_forget 返回 deletedRevision

(被删除时的版本)。

  • revision 计数有上限(Number.MAX_SAFE_INTEGER);到达上限的记录不能再被更新、确认或

作为 merge 目标 —— 整次操作拒绝,不静默溢出。删除不受上限限制。

阶段一限制(分阶段计划见 issue #32):CAS 只保护你观察到的版本,不证明内容正确;

阶段二至四(provenance/evidence、分层复核状态、历史/回滚)尚未实现;没有跨恢复/导入的

incarnation/tombstone 保护 —— 此类操作后请静默写入者并重新读取。

规模与限制

近似重复检测在每次非 force 的 memory_write 时扫描同 scope 的全部记忆。该设计面向个人

长期事实库而非大型文档集合。写成本随该 scope 内记忆的数量与长度增长;暂无基准支撑的

容量上限。多会话可共享本地 WAL 库:初始化后的兼容打开不抢 schema 写锁;首次初始化、

schema 修复与 token 索引重建仍需写入。SQLite 以 5 秒 busy 超时串行化写入者;SQLITE_BUSY

提示稍后重试,无自动应用层重试。这不是高并发服务,也不是跨机数据库同步。

CLI

npx -p @tr1v3r/dsh-ltm dsh-ltm --db /path/to/ltm.db <command> [--json]

`list / search / show / edit / tag / pin / merge / confirm / forget / upgrade-schema /

export / import —— 每个子命令都支持 --json`。未知 flag、互斥 flag 与多余位置参数一律

拒绝。默认数据库:$DSH_HOME/memory/ltm.db。

edit/tag/pin/confirm <id>/forget 接受 --expected-revision N;merge 另有

--expected-source-revisions id:rev,id:rev(恰好覆盖唯一源集合)。这些 flag 在打开数据库

之前完成校验;confirm --all --expected-revision 拒绝。CAS 失败以退出码 1 结束,--json

输出与工具相同的结构化 error 详情,人类模式只输出错误码/id/版本与重读指引,绝

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::10,最后更新 2026-10-25

Links

GitHub · Homepage · npm

Same category