DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-task-memory

x

dsh-task-memory

Manifest valid

DeepSeek Harness Plugin: Workspace-level task memory — store completed tasks as memory cards so you don't have to re-analyze them in the next session.

UI (client)hasBundlePatchMachine translated

dsh-task-memory

DeepSeek Harness 插件:工作区级任务记忆。

解决的问题:相似的活会反复出现,而每次会话都从零重新分析一遍。这个插件把"做过的任务"存成一人一张的记忆卡,并且让卡片以两段式被检索——先看索引,命中后才读那一张的正文,所以记忆再长也不需要每次全读。

两段式检索

阶段机制成本
索引一张有界的卡片摘要清单,注入到会话(一行一卡:名字 + 描述 + 触发词)常驻,且按使用频率排序、有硬上限
正文命中后用 task_memory_load 取那一张卡的正文一次调用,只读一张

索引不进对话历史,也不按轮次重复;其余卡片用 task_memory_index / task_memory_search 发现。记忆再长也不需要每次全读。

上架过的卡片(见下)会额外出现在 Harness 的技能目录里,可以用内置 skill 工具加载——但那是可选的,不是索引机制本身。

数据布局

所有工作区共用一个 SQLite 数据库:$DSH_HOME/task-memory/memory.db(默认 ~/.dsh/task-memory/memory.db)。表内用 workspace 列隔离各工作区。

meta     (key, value)                       ← schema 版本等
cards    (workspace, name, description, when_to_use, triggers, tags,
          status, published, revision, created, updated, body, hits, last_used)
assets   (workspace, card, path, bytes)     ← 外键级联,随卡片一起删除

用 node:sqlite(Node 内置)实现,零第三方依赖、无需编译。本机 dsh-memento 已在用同一机制,所以 Electron 宿主也支持。

数据库相对文件存储买到的三个性质:

性质说明
原子性卡片与附件在同一事务里写入,崩溃不会留下"有附件没卡片"
唯一身份卡名是主键列,"一件事只留一张卡"是 schema 保证,不是靠代码反复检查
计数不漂移hits/last_used 是卡片行上的列,不可能与卡片失联

索引仍然永远从行数据现算,不存索引表;## 变更记录 段落承担版本历史,所以也不需要 journal。

工具

工具作用
task_memory_index完整索引,可按 query / status / tag / tier 过滤。索引被上限截断时兜底
task_memory_load按名字取一张卡的正文、元数据与附件清单
task_memory_asset读取某张卡的某个附件(代码片段、补丁等,存于数据库)
task_memory_save落卡。默认 auto 模式会拒绝为已记录的任务再建一张卡,并返回候选卡
task_memory_search跨卡片正文全文检索(带片段),触发词都没命中时兜底

新鲜度分档

记忆库有两种"旧":内容过时(status: verified/draft/stale,人工判断)和久未使用(档位,自动按时间算)。两者正交——一张卡可以既"已确认"又"遗忘"(内容正确但一年没用了)。合成一个字段就再也说不清用户指的是哪种。

五档(天数可配置)

档位默认距离在注入索引里的呈现
近期≤ 7 天名字 + 描述 + 触发词 + 年龄 + 使用次数
之前8–30 天同上
很久之前31–90 天名字 + 描述(去掉触发词)+ 年龄
远古91–365 天只有名字,合并成一行
遗忘> 365 天不列出,只报一行数量

这就是"检索频率不同":越旧的卡越不容易出现在模型眼前,但一次也没丢。

时间基准:max(updated, lastUsed)

  • 刚改写过的卡 = 知识新鲜 → 算活跃
  • 刚被检索过的卡 = 仍被需要 → 算活跃

取较新者。只用 updated 会让"写完再没碰过"的卡一直假装新鲜;只用 lastUsed 会把刚创建、还没被检索过的卡判成遗忘。两者都是 cards 表上的列,所以不可能与卡片失联。

遗忘 ≠ 删除

遗忘档只做三件事:不注入、面板可见并标记、工具仍能检索到。行数据一个字段都不动——一个会自己删记忆的记忆插件比一个拥挤的更糟。

想清理时用面板上的「清理遗忘」按钮:它先列出所有遗忘档卡片让你确认,再删除指定名字的那些。没有自动清理。

档位边界写进配置(tierDays),随时可改;改完不需要迁移任何数据,因为档位永远是算出来的,不存进文件。

筛选

面板顶部有两个筛选器:

控件作用
档位下拉默认(按配置,通常只看近期)/ 全部档位 / 仅近期 / 仅之前 / 仅很久之前 / 仅远古 / 仅遗忘
起止日期按最后活动日期过滤;范围默认取真实数据的最早~最晚,可改
日期条每个「有卡片的日期」一个可点标签(显示月-日与张数),点一下就把范围收到那一天

日期条是必需的补充:原生 <input type="date"> 的日历弹层同样由 Chromium 绘制、CSS 碰不到,而用日期选择器排错时最关键的信息是"哪天有记忆"。所以那个信息放在选择器旁边,而不是指望日历里能标出来。

档位筛选在宿主侧执行(不是浏览器里过滤):列表本身有上限,本地过滤会把本该被查询捞出来的卡藏掉。

工具 task_memory_index 也接受 tier 参数,含义与面板一致。

设置页

「设置 → 任务记忆」区块,改完保存立即生效(不需要重启):

设置说明
面板默认显示哪些档位打开面板时默认勾选的档位;默认只看近期
档位边界(天)四个边界,改完立刻影响分档
注入索引的卡片上限索引里最多列多少张
单张卡正文上限超出截断并给出数据库位置
回合结束自动落卡关掉后只能由你明确要求才记录

设置存在哪里:$DSH_HOME/task-memory/settings.json(默认 ~/.dsh/task-memory/settings.json)。

优先顺序是 设置文件 > cordis.patch.yml 里的 config > 内置默认。设置文件赢,因为它代表你最后一次在界面上做的选择;loader config 仍然是新安装的种子值。

打开设置页会补齐缺失的参数。 页面上每个参数都显示它的有效值,而一个"没有记录"的参数是无法在界面里改的——所以读取设置时会把本地文件缺的字段按当前生效的值写进去(不是写死默认值:通过 loader config 设过 maxCatalogCards: 99 的部署,文件里也该是 99,否则文件与运行中的插件说的不是一回事)。已经写过的值永远不会被覆盖。

为什么不用宿主自己的设置服务:dsh-settings 只渲染插件用 schemastery 声明了 .volatile() 字段的表单,而本插件零依赖、没有 schema。手写 YAML 去改 profile 的 patch 文件则有损坏整个 profile 启动配置的风险——为了一个设置面板不值得。所以设置写进自己的 JSON 文件,原子写(临时文件 + rename),坏文件退化成"没有覆盖"而不是启动失败。

兼容旧版记忆

早期版本把记忆存成 <工作区>/.dsh/task-memory/notes/<卡名>/SKILL.md 加一个 stats.json。那些文件里的知识仍然有效,所以面板上有一个「兼容旧版记忆」按钮,按当前选择的工作区把它搬进数据库。

点击后是三步,每步都有确认:

  1. 预演(不写任何东西)—— 告诉你将导入多少张、其中多少是新建、多少与库里已有卡片同名、多少附件、多少张无法解析。
  2. 导入 —— 已存在的同名卡片不会被覆盖(导入永远不破坏库里更新的版本),然后报告实际写入了什么。
  3. 删除旧文件 —— 这一步单独确认,且在导入成功之后才提出。

导入用 importCard 原样写回:原始日期、revision、hits、last_used 都保留,而不是当作新卡重新推导。删除只动 notes/ 与 stats.json 两项,同目录下别的插件数据不会被碰。

自动落卡

默认不需要你开口。 每个回合结束时,如果这一轮确实做了实事(工具调用 ≥ 3 次)而且还没有存过卡,插件会自动追问模型一次:

任务记忆自动检查:本轮工作已结束。回顾本轮,判断是否产生了值得留存的东西……

模型据此判断本轮是否有非显然结论/踩坑/可复用流程:有就调 task_memory_save,没有就回一句"本轮无需记录"。

为什么要这么做:一段提示词只能"请求"模型记录,而刚干完活的模型不会可靠地执行又一条指令。之前的实测就是——你不主动说"记住这个",卡片永远是零。所以这里用的是真实触发点而不是请求:宿主在关闭回合前会 await agent/turn-stopping,监听器调 agent.steer(...) 就能让机器多跑一步。

为什么是"追问"而不是"直接写":只有模型分得清"可复用的根因"和"一次性的查询结果"。缺的不是判断力,而是提醒自己去判断这件事。

三个防呆:

条件行为
本轮工具调用 < 3 次不提醒(查询、闲聊、小改动)
本轮已经存过卡不提醒(记忆已是最新)
本轮本身就是提醒引发的复查不提醒(防死循环的关键)

模型说"不值得存"时不会硬写。关闭方式:把 autoCapture 设为 false。

上架与不上架

卡片默认只留在本工作区的任务记忆里,不进技能目录。 需要时用 publish: true 单独上架。

为什么默认不上架:本插件的卡片注册成 runtime 技能后,会出现在 Harness 的技能目录里,而技能中心(Skill Center)页面列的就是同一份目录。技能中心是给人挑通用技能的地方,不该被某个工作区的排查记录塞满。而且技能中心虽然能编辑技能,却无法操作 runtime 条目(它列出的 runtime 技能没有文件路径),所以这些卡片在那里只是一排点了没反应的噪声。

状态出现在任务记忆索引出现在技能目录/技能中心加载方式
未上架(默认)✅❌task_memory_load / task_memory_search
已上架(publish: true)✅✅上面两种,外加内置 skill 工具

上架与否不影响可检索性:未上架的卡一样会被注入索引、一样能被工具检索和加载,只是不会污染面向人的技能列表。上架状态是粘性的——一次 update 不会把它悄悄取消,只有显式传 publish: false 才撤下。

判断标准:跨任务复用的通用方法论才值得上架;某个项目的排查记录、一次性结论留在工作区即可。

上架后立即生效,不用等

技能的收集结果在注册表里是按 revision 缓存的,所以"改了卡片"本身不会让目录刷新。本插件在每次写入后主动调 control.invalidate() —— 它把 revision 加一、清掉缓存并通知观察者,于是下一次收集必然重新读取。

关键在于宿主侧的消费方式:@deepseek-ai/dsh-tool-skill 在每一步(agent/pre-step)都会 snapshot() 一次并比对摘要,摘要变了才推送新目录。所以 invalidate 之后的下一个步骤就会看到新卡片。

这对模型侧的技能列表是立即的。技能中心页面是浏览器里的列表,点一下刷新即可看到;它读的是同一份已失效的缓存,不会再拿到旧数据。

只记一份

task_memory_save 的三种模式:

  • auto(默认):先用本地相似度(字符 trigram + 触发词重合 + 标签重合)比对已有卡片。判定为同一件事时不创建,直接返回那张卡的 name 与匹配理由,让模型改用 update。
  • update:合并进指定卡。合并按 ## 段落进行——模型这次写到的段落被替换,没提到的段落原样保留,因此后一次保存不会悄悄抹掉先前的结论。revision 递增,triggers / tags 取并集。
  • force-create:确实是一个不同任务时才用。

索引有硬上限(默认 50 张,按加载次数→更新时间排序)。被截断的卡仍然可以通过 task_memory_index / task_memory_search 找到——这是"记忆可以很长,但每次不必全读"的落地方式。

记忆面板(P3)

Harness 侧边栏里的「任务记忆」入口,中间列打开面板。左侧是卡片列表、右侧是详情/编辑区,两列各自滚动——详情不会因为你记忆变多而被推得越来越远。

操作说明
浏览顶部选工作区(带卡片数),左栏列表:名字、状态、描述、更新时间、revision、加载次数、触发词
查看点左栏卡片,右栏显示正文与元数据
新建点右上角「新建卡片」,在右栏填写;勾选**「作为技能上架」**(默认不勾)
编辑右栏直接改字段与正文后保存;上架开关也在这里
删除二次确认,删掉卡片及其全部附件(外键级联)
检索按正文全文过滤左栏列表

状态显示中文:「已确认 / 草稿 / 可能过时」。存储里仍然是 verified / draft / stale 标识符 —— 面板只翻译显示,因为那三个词是工具 schema 和数据库列使用的值,就地改写会破坏与模型的契约。

人工编辑与模型写入的语义不同:模型 update 是按 ## 段落合并,而面板保存是逐字替换——你在编辑器里写的就是最终内容,删掉的段落和触发词不会自己回来。

实现要点:Host 侧用 ctx.webServer.register 挂 /api/task-memory/* 六条路由,客户端用 fetch 调用,两个 slot(sidebar.panellist + main)提供入口和页面。样式只用主题 token,明暗主题都跟随宿主。

界面里的下拉框是自绘的,不是原生 <select>:后者的展开弹层由 Chromium/OS 绘制、CSS 碰不到,在暗色主题下会是白底黑字,与其余控件格格不入。自绘版直接采用宿主菜单的配方(--dsw-menu-surface-fill + --dsw-menu-backdrop-filter + --dsw-elevation-prominent),并保留原生控件的全部键盘与无障碍行为(方向键、Home/End、Enter/Space、Escape、点外部关闭、焦点回到触发器)。

安装

本插件不使用 npm 安装、没有 node_modules、不依赖任何 @deepseek-ai/* 包——link: 安装的插件是从真实路径加载的,Node 的解析走不到 profile 的 node_modules,所以裸包名会失败。lib/schema.js 因此自己实现了注册契约。

  1. 加依赖(link: 指向本目录):
    "dependencies": { "dsh-task-memory": "link:D:/AI/dsh-task-memory" }
    
  2. 加进 bundles:
    "bundles": [ ..., "dsh-task-memory" ]
    
  3. 建 junction,让 Node 能解析到它:
    New-Item -ItemType Junction `
      -Path "$env:USERPROFILE\.dsh\profiles\<profile>\node_modules\dsh-task-memory" `
      -Target "D:\AI\dsh-task-memory"
    

配置

- id: dsh-task-memory
  name: dsh-task-memory
  config:
    maxCatalogCards: 50     # 注入索引的卡片上限
    maxBodyChars: 24000     # 单张卡正文的读取上限,超出截断并给出数据库位置
    includeSystemPrompt: true
    autoCapture: true       # 回合结束自动追问是否落卡;设 false 关闭
    defaultTiers: [recent]  # 面板默认显示哪些档位
    tierDays:               # 新鲜度档位的天数边界,必须递增
      past: 7               # ≤7 天算「近期」
      old: 30               # ≤30 天算「之前」
      ancient: 90           # ≤90 天算「很久之前」
      forgotten: 365        # ≤365 天算「远古」,超过则「遗忘」

这些都可以在「设置 → 任务记忆」里改,改完立即生效并存进设置文件(优先于这里的 loader config)。

测试

node test/all.test.js

node --test 会为每个文件 spawn 子进程(在受限沙箱下会被拒),test/all.test.js 把十组用例导入同一进程执行,断言完全相同。

test/setup.js 在任何测试运行前把 DSH_HOME 指向临时目录,所以跑测试绝不会创建或改动你真实的 ~/.dsh/task-memory/。每个用例还各自开 :memory: 库,互不干扰。每个测试文件都单独引入它,这样一个套件被单独运行时同样安全。

另有一个真实 Cordis 运行时的集成测试(test/integration.cordis.mjs:装配、通过真实注册表读写、上架语义、写入触发目录重扫、面板路由、回合结束追问及其防循环、卸载清理)。它必须在 profile 目录下运行——插件是 junction 安装的,从 D:\AI\dsh-task-memory 里跑会解析不到 @deepseek-ai/*。运行方式见该文件头部注释。

限制

  • 卡片按会话工作目录隔离(数据库里是 workspace 列),不跨工作区共享。面板顶部的选择器可以在工作区间切换查看。
  • 去重是启发式:它宁可拒绝新建也不轻易产生第二张卡,但最终判断在模型;工具会给出匹配理由,模型可以据此改用 force-create。
  • 删除卡片不提供模型工具——模型能自行删除的记忆就是会消失的记忆。删除只在面板里由人操作。
  • 自动落卡是追问而非直接写入:模型判断不值得存就不会存。这保住了判断质量,代价是它偶尔会漏存——想确保记下来时,直接说"记住这个"。
  • 改用数据库后,卡片不再能直接用 read/edit 工具改;附件也用 task_memory_asset 读,而不是给一个文件路径。
  • 改动插件的 JS 代码后需要重启 Harness 才会加载(patchReload: live 只覆盖新增插件与配置改动)。

Comments

Loading…

Similar plugins

dsh-plugin-vault-memory

by zhaoxuejie

让 DeepSeek Harness agent 把本地 Obsidian 知识库当作长期记忆与工作台:全文/语义检索、会话记忆注入、一键捕获、巡检管家(只建议不擅改)

Development & InfrastructureManifest valid

★ 1

MIT

JavaScript

Sep 7, 2026

dsh plugin --profile web add dsh-plugin-vault-memory

by Scorp1o117

Agent memory for DeepSeek Harness | DeepSeek Harness 记忆插件

Memory & ContextManifest valid

★ 7

↓ 753/wk

MIT

JavaScript

Oct 4, 2026

dsh plugin --profile web add dsh-tdai-memory

by sikwoxy

DeepSeek Harness 插件:跨会话持久记忆(Hermes 式)

Manifest valid

★ 4

↓ 130/wk

MIT

TypeScript

Aug 14, 2026

dsh plugin --profile web add dsh-tool-memory

by 1304836815

DSH 会话级记忆插件:收尾提醒 + MEMORY.md 记忆索引维护 + 实时对话日志 + LLM 摘要压缩,配置面板在 设置→插件。Session memory for DeepSeek Harness.

Manifest valid

★ 0

MIT

JavaScript

Aug 21, 2026

dsh plugin --profile web add @dsh-external/dsh-auto-memory

by rebron1900

Mnemosyne 记忆层在 DeepSeek Harness 中的插件 — 本地优先、SQLite 支持的跨会话记忆。

Memory & ContextTools & CapabilitiesManifest valid

★ 1

↓ 97/wk

MIT

JavaScript

Sep 30, 2026

dsh plugin --profile web add dsh-mnemosyne

Layered file memory for DeepSeek Harness with workspace-scoped USER/MEMORY notes, background consolidation, and hybrid session recall.

Memory & ContextTerminal & ClientsManifest valid

★ 0

↓ 55/wk

dsh plugin --profile web add dsh-file-memory