Chat memory that archives messages by time and recalls by stated period, widening twice before admitting it forgot.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:Moontail-Ling/dsh-time-memory
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
This plugin publishes its README in Chinese only.
给 DeepSeek Harness 的聊天记忆插件:把对话按发生时间存成事件,提到某段时间时先查那段,没命中就扩大一次、再扩大一次,两次都落空就回「我忘记了」——不编造、不推测。
同时给会话装上一套「时忆」人格:回答前先输出两三行 [调试] 自检,把「时间锚点 → 检索层数 → 命中数 → 判定」摊开给你看。
[记忆检索] 时间锚点:"上周二" → 2026-10-20(周二)全天
[记忆检索] 线索:海边
[记忆检索] 第 0 层(原始时段):2026-10-20(周二)全天 · 库内 3 条 · 命中 0 条 → 扩大
[记忆检索] 第 1 层(扩大 1 次):2026-10-19 至 2026-10-21(3 天) · 库内 9 条 · 命中 1 条
[记忆检索] 说明:原始时段没有命中,扩大 1 次后才找到,引用时要说明大致范围。
[记忆] 2026-10-20 20:14 · 用户:我说想去海边看日出,风很大
目录
为什么需要它
模型的上下文没有「长期记忆」。常见的替代做法是把历史全塞进 prompt,代价是 token 随对话线性增长,几千条之后直接撑爆窗口;另一种是让模型自己「回想」,结果就是编造细节。
这个插件换了一条路:记忆存在磁盘上,只有被点名的那一段时间才会进上下文。
三条规则,全部由代码保证,不靠模型自觉:
- 按时间存 —— 每条真实的用户消息与助手回复,按事件时间写进 jsonl;
- 按时间查 —— 用户提到时间段,强制先调
memory_recall; - 查不到就说忘了 —— 两次扩大仍无结果,「我忘记了」是唯一允许的回答。
检索流程
| 层 | 窗口 | 结果 |
|---|---|---|
| 第 0 层 | 用户指认的时段("上周二" = 10-20 全天) | 命中即返回 |
| 第 1 层 | 以窗口中心等比扩大 ×3(1 天 → 3 天) | 命中即返回,并标注"扩大 1 次" |
| 第 2 层 | 再 ×3(→ 9 天) | 命中即返回 |
| 两次扩大后仍空 | — | 返回 verdict="forgot",人格只能回答「我忘记了」 |
| 时间说法解析不了 | — | 返回 verdict="unparsed",提示改用 2026-10-20 这类写法重试一次 |
time_hint 认这些说法(共 26 种,含区间与时间点):
- 相对:今天 / 昨天 / 前天 / 大前天 / 三天前 / 上个月 / 三个月前 / 去年
- 周历:上周三 / 上上周五 / 本周五 / 周三 / 上星期 / 8月
- 时段:昨天下午 / 今天上午 / 凌晨 / 晚上
- 绝对:
2026-10-20、2026-10-20 14:30、2026-10-01~2026-10-07 - 整句也行:
你还记得上周二我们去海边吗—— 插件自己抠时间
命中与否都用关键词打分(中文按二元组切词),不是语义向量检索,见已知限制。
安装
要求:DeepSeek Harness(Desktop 或源码 checkout)已能正常使用。Node.js 只在跑测试时需要(≥ 22.19)。
git clone https://github.com/Moontail-Ling/dsh-time-memory.git
然后在 DSH 的 Web GUI 里:
- 侧边栏 插件 页 → 安装;
- 粘贴克隆下来的绝对路径,例如
D:\code\dsh-time-memory; - 确认,插件默认启用。
装完即对当前 profile 的所有会话生效(启用 HMR 时热加载,否则重启 DSH)。也可以在 Creator 模式下用 plugin_manager 的 install_bundle,target 填同一个路径。
卸载:插件页里移除该组合包即可,记忆文件不会被删。
使用
装好之后不需要额外操作,正常聊天即可。两件事会自动发生:
- 说起某段时间,模型先调
memory_recall,把命中结果作为「记忆」贴进上下文; - 你讲到值得单独记的事,模型可以调
memory_save把它钉在那一天。
两个工具(也可被 PTC 代码直接调用):
| 工具 | 参数 | 作用 |
|---|---|---|
memory_recall |
time_hint(必填)、query、limit |
按时间段 + 关键词检索,自带三层扩大与忘记判定 |
memory_save |
summary(必填)、happened_at、details、tags |
手工归档一条事件到指定时间点 |
配置
写在 profile 的 cordis.patch.yml,覆盖 time-memory 这一行:
- id: time-memory
name: dsh-time-memory
config:
dataFile: 'D:\my-memories\events.jsonl'
expandFactor: 3
maxExpansions: 2
| 字段 | 默认值 | 含义 |
|---|---|---|
dataFile |
$DSH_HOME/time-memory/events.jsonl |
记忆库文件,一条记忆一行 JSON |
capture |
true |
是否自动把对话按时间入库 |
expandFactor |
3 |
每次扩大窗口的倍数(1 天 → 3 天 → 9 天) |
maxExpansions |
2 |
最多扩大几次;两次后仍无命中即「忘记了」 |
maxResults |
3 |
单次最多返回几条记忆 |
minScore |
2 |
关键词命中阈值(一个两字词 = 2 分) |
maxTextChars |
300 |
入库时单条记忆的截断长度 |
lineChars |
90 |
回显时单条记忆的截断长度,直接决定检索输出的 token |
persona |
内置「时忆」人设 | 整段替换人格文本 |
includePersona |
true |
是否把人设放进 charter;preset 里另有人格时关掉,避免重复 |
cognition |
空 | 内联的「基本认知」文本,接在人格之后 |
cognitionFile |
空 | 基本认知的 markdown 文件,按 mtime 缓存,改完下一轮生效 |
excludePresets |
[] |
这些 agent preset 的会话不写进本实例的记忆库 |
includeProtocol |
true |
是否附带记忆协议(一般不要关) |
token 成本
- 提示词是静态的:人格、认知、协议里不含时间戳和记忆条数,整段系统提示词可以命中前缀缓存,稳态下几乎不额外计费;「现在几点」「库里多少条」由
memory_recall的返回值给出。 - 检索输出有上界:默认 3 条 × 90 字,一次检索约 200 token。
- 成本与库大小无关:1000 条还是 10000 条,单次开销一样;"整卷记忆塞进上下文"则是 O(N)。
- 代价:每次检索多一轮工具调用。记忆库很小、或本来只滚最近几十条时,直接塞上下文反而更便宜 —— 它买的是"按时间精确定位 + 不随库增长"。
记忆文件
默认在 %USERPROFILE%\.dsh\time-memory\events.jsonl($DSH_HOME 未设置时),一行一条:
{"v":1,"id":"m_…","t":1792500000000,"kind":"user","text":"……","session":"…","seq":42,"source":"auto","stored":1792500000123}
- 纯 append;损坏的行读取时跳过,不影响其它记忆。
- 同一会话的同一条事件用
session + seq去重,重启或 resume 不会重复写入。 - 清空记忆:停掉插件后删除该文件即可。
开发与测试
测试不依赖 DSH,只用到 Node 内置模块:
node test/run.mjs # 结果写入 test/last-run.json,失败时退出码非 0
覆盖时间解析(26 种说法)、扩大两次的边界、忘记判定、去重、损坏行容错、插件装配,以及两个工具的真实调用。没有 Node 时也可以用 DSH Desktop 自带的 Electron 运行时:
$env:ELECTRON_RUN_AS_NODE=1; $env:TZ="Asia/Shanghai"
& "<DSH 安装目录>\DeepSeek Harness.exe" "test/run.mjs"
激活自检(排查安装是否成功):把 DSH_TIME_MEMORY_PROBE 指向一个可写文件,插件激活成功会追加一行回执。
$env:DSH_TIME_MEMORY_PROBE = "C:\tmp\time-memory.probe.log"
项目结构
index.js 插件入口:注册提示词段、两个工具、session/event 监听
lib/time.js 时间说法 → 半开区间;窗口扩大与格式化
lib/hint.js 从整句里抠时间片段
lib/recall.js 分词、打分、三层检索
lib/store.js JSONL 记忆库(append、去重、坏行容错)
lib/capture.js 把 session 事件归档成记忆
lib/format.js 工具结果渲染(也就是聊天里看到的 [调试] 输出)
lib/prompt.js 人格与记忆协议文本(静态,便于前缀缓存)
lib/config.js 配置解析与默认值
test/run.mjs 离线测试
publish.cmd/.ps1 作者自用的一键发布脚本,与插件运行无关
插件不导入任何 DSH 包,只依赖 Node 内置模块,因此宿主升级不会带来解析失败。
已知限制
- 人格是 profile 级的:启用后对该 profile 下所有会话生效。只想在某类会话用,把
time-memory那一行放进对应 agent preset 的 patch。 - 检索是「时间窗 + 关键词」,不是语义向量检索:换个说法("看海" vs "海边")可能命中,也可能不中;扩大窗口能兜住时间上的偏差,兜不住词义上的偏差。
- 只归档用户与助手文本,不记工具调用与注入上下文;子代理会话不入库。
- 中文时间解析覆盖常见说法,生僻表达会返回
unparsed并提示改用明确日期。 - 本仓库不含 QQ 桥接层:那份配置带本机路径与个人化认知,留在作者本地。
License
Links
More in this category
vectorize-io/hindsight#coding-agents★ 57722
Hindsight, agent memory that learns: long-term project memory with auto recall and retain, knowledge pages, deep reflection, and per-repo memory banks.
volcengine/OpenViking#examples/dsh-memory-plugin★ 41317
OpenViking memory and context bundle for DeepSeek Harness: pre-step auto-recall and profile injection, session capture, `viking://` URI guarding, and recall/write memory tools backed by an OpenViking server.
MemTensor/MemOS#memos-local-plugin★ 12224
Local-first memory plugin for DeepSeek Harness: layered L1/L2/L3 memory with automatic capture, manual memos_* retrieval tools, and a built-in memory viewer.
agentscope-ai/ReMe#dsh★ 3735
Connects DeepSeek Harness to ReMe's local-first, self-evolving personal knowledge base: automatically captures completed main-agent conversations as user-owned Markdown memory, searches conversations and source material through reme_search with BM25, optional embeddings, and wikilink expansion, and schedules daily memory consolidation.
zilliztech/memsearch#MemSearch★ 2815
Shared Markdown memory for DSH and other coding agents, with automatic capture, pre-step context injection, searchable recall, and memory-to-skill self-evolution through a review panel.
vshulcz/deja-vu#extensions/dsh★ 1352
Reads the session files forty-two other coding agents on this machine already wrote (Claude Code, Codex, Cursor, VS Code Copilot Chat, opencode, OpenClaw, Hermes, Kimi, Cline, Zed and more), including sessions from before it was installed: six tools (deja_recall, deja_session, deja_blame, deja_fix, deja_how, deja_remember), a /deja command, and optional automatic recall added to the runtime context. Local BM25 index, no LLM, no embeddings, no network (dsh plugin --profile web add dsh-deja).
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.