DeepSeek Harness Hub
← 返回列表

navid-kianfar/dsh-memory

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

@achasoft/dsh-memory

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/16 · 已提供中文文档

为 DeepSeek Harness 提供持久化、可搜索、按项目隔离的记忆:将决策、规则和会话上下文存储在可查询的 DuckDB 文件中,并将规则集注入到每次模型请求中——同时在 Web Client 中提供完整的管理 UI。

综合分
29.7
GitHub 分
29.7
用户评分
★ Stars
0
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add navid-kianfar/dsh-memory
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-api-remotes@deepseek-ai/dsh-brand@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-runtime@deepseek-ai/dsh-client-ui-conversation@deepseek-ai/dsh-client-ui-primitives@deepseek-ai/dsh-client-ui-settings@deepseek-ai/dsh-client-ui-settings-plugins@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-credentials
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

@achasoft/dsh-memory

为 DeepSeek Harness(dsh)提供持久化的、按项目隔离的记忆功能。每个项目都会在 /.dsh/memory.db 获得一个 DuckDB 文件,用于保存决策、架构说明、冲刺目标、会话摘要以及约束性规则。强制规则和禁止规则构成系统提示词的一个部分,在每次模型请求时都会重新读取,因此它们能够在上下文压缩后依然保留。记忆会按关键词(BM25F)排序,并且在配置了嵌入端点时,还会按向量相似度排序。Web 客户端会获得一个 Memory 标签页,用于浏览和编辑所有这些内容。

Chat 旁边的 Memory 标签页,显示某个项目的记忆,头部包含数据库路径以及活跃和已嵌入计数

功能

Memory 标签页

每个会话中,Chat 旁边都有一个 Memory 标签页。它始终显示该会话所属项目的记忆。头部会显示数据库路径、有多少条记忆处于活跃状态、有多少条拥有向量,以及当前是否注入了规则。该标签页有三个窗格:

- Memories:搜索框(标记为 Semantic + keyword 或 Keyword only)、类别和状态筛选器(Active、Archived、Expired、All),以及操作:New、New rule、Import instructions file、Export JSON、Rebuild vectors。
- Rules:当前生效的强制规则和禁止规则,以及一个 Show the injected text 开关,用于按模型接收到的原样显示规则块。
- Sessions:最近 50 个记忆会话,包含摘要以及每个会话写入和读取了多少条记忆。

每张记忆卡片都提供 Edit、Archive 或 Restore、Delete permanently(确认后删除该行及其审计记录),以及 History:创建、编辑、读取、归档、恢复、导入和过期的审计记录。

一张决策卡片,其 History 已展开

约束每个请求的规则

规则通过系统提示词注入,而不是通过消息注入,因此每个请求都会携带当前规则集,并且在标签页中的编辑会从下一个请求开始生效。规则文本会原样传递给模型:字面量 {{,例如 ${{ secrets.GITHUB_TOKEN }} 中的那样,会被转义,这样 harness 的提示词渲染器就不会将其视为模板变量。

由 agent 记录的规则会在标签页中带有 Added by an agent 徽章,并在提示词中带有 [added by an agent] 标签。当存在由 agent 添加的规则时,该块还会告诉模型,在发生冲突时以用户自己的规则为准。
每条规则在提示词和 memory_rules 输出中都恰好渲染为一行。换行符(CR、LF、U+2028、U+2029)、其他控制字符以及不可见的格式字符(如双向覆盖符和零宽空格)在标题和正文中都会被折叠为单个空格,因此规则无法自行添加标题或未标记的规则。ZWNJ 和 ZWJ 会被保留。存储的文本保持不变;Memory 标签页按原样显示。

Rules 面板列出强制规则,其中一条标记为“由代理添加”

注入的文本是有上限的,因为每次请求都要为其付出代价:

| 限制 | 值 | 何时触发 |
| --- | --- | --- |
| 块中的单条规则 | 2,000 个字符 | 规则被截断,并带有指向 memory_rules 的标记。 |
| 整个规则块 | 24,000 个字符 | 代理添加的规则会先于用户规则被省略,且一旦有任何用户规则被省略,就不再显示任何代理添加的规则;有一行会说明省略了多少条。 |
| 会话上下文中的单个冲刺目标或决策 | 1,000 个字符 | 截断并带有标记。 |
| 整个会话上下文 | 12,000 个字符 | 较晚的条目会被省略;有一行会说明省略了多少条。 |

会话连续性

每个顶层代理都有自己的记忆会话。当它启动时,模型会收到一条消息,其中包含上一次真实会话摘要(最多 1,500 个字符)、最多 10 个冲刺目标,以及过去 7 天内的最多 20 个决策。冲刺目标和决策遵循规则块的格式:每行一条,由代理记录的会标记为 [added by an agent],并附有说明:发生冲突时以用户为准。由子代理创建或编辑的条目会从此消息中排除;它们仍可通过搜索和回忆找到。因崩溃或被处置的代理而保持打开的会话会以 [auto-closed: …] 摘要关闭,在选取上一次摘要时会跳过该摘要。在一轮结束时,模型会被提醒调用 memory_session_end(参见 remind)。

子代理(其标头包含 origin: 'subagent' 或 delegationDepth > 0 的会话)受相同规则约束,但不会获得记忆会话、会话上下文和提醒。用户对会话的分叉不是子代理。

保留

每条非规则记忆在写入时都会获得一个到期日期。一旦该日期过去,该记忆就会从搜索、会话上下文、按标题回忆和 Active 列表中消失,并被列为和报告为 expired。其存储状态会在该项目下一次顶层会话启动时变为 expired。

| 类别 | 默认天数 |
| --- | --- |
| session | 30 |
| sprint、feedback | 90 |
| devops、developer_docs | 180 |
| decision、project_plan、architecture、reference | 365 |
| mandatory_rules、forbidden_rules | 永不 |

优先级 1 会将生命周期乘以 1.5。优先级 2 和 3 永不过期。规则始终会被提升到至少优先级 2。恢复已归档或已过期的记忆会开启新的保留窗口。
导入与导出

导入指令文件接受 .md、.markdown 或 .txt(例如 CLAUDE.md 或 AGENTS.md)。标题决定类别;规则类标题(“Never”、“Always”、“Rules”、“Conventions”等)下的列表项各成为一条规则。一次导入最多创建 1,000 个条目,并在写入任何内容之前进行完整验证。导入的条目计为用户编写。

导出 JSON 将项目中的所有记忆(无论状态如何)下载为 -memory.json。没有 JSON 导入。

设置卡片

设置 → 插件 → 记忆显示语义召回是否就绪,并允许你更改配置中标记的字段。

展开的“记忆”设置卡片,显示语义召回状态、注入开关、提醒和工具集选择器、排序字段以及数据库路径

要求

- Harness: 已使用 @deepseek-ai/dsh 0.1.5-rc.2 测试。
- Node.js: ^22.19 || >=24(package.json 中的 engines)。
- PATH 中的 pnpm:dsh plugin 会转发给它。
- DuckDB: @duckdb/node-api 1.5.5-r.4 是常规依赖项。其绑定以预构建的可选包形式提供,适用于 macOS(arm64、x64)、Linux(arm64、x64、glibc 和 musl)以及 Windows(arm64、x64);安装时不编译任何内容。不支持其他平台。
- Harness 服务: 对等依赖项为 @deepseek-ai/cordis、dsh-agent、dsh-credentials、dsh-llm、dsh-session、dsh-system-prompt、dsh-tools、dsh-typert-protocol 和 schemastery,均由标准 dsh-base 配置文件提供。宿主部分需要 agents 服务;settings(用于设置卡片和实时编辑)和 memoryEmbedding 是可选的。浏览器部分需要 Web Client 配置文件(dsh-api-remotes、dsh-client-locale、dsh-client-ui-conversation、dsh-client-ui-settings、dsh-client-ui-settings-plugins)。
- 嵌入(可选): 任何实现 OpenAI 的 POST /v1/embeddings 的端点,例如托管 API、本地推理服务器或 Ollama。没有它时,排序仅基于关键词,其他所有功能均可正常工作。

安装

dsh plugin --profile web add @achasoft/dsh-memory
dsh web

dsh plugin --profile   在 $DSH_HOME/profiles/ 中运行 pnpm ($DSH_HOME 默认为 ~/.dsh),并在首次使用时创建配置文件。成功执行 add 后,任何在其 package.json 中声明了 dsh.bundle 的依赖项都会被追加到配置文件的 dsh.profile.bundles 中。无需手动编辑。

启动时,harness 按以下顺序从补丁层组合配置文件:每个 bundle 的 cordis.patch.yml(按 bundles 顺序)、配置文件自身的 cordis.patch.yml、$DSH_HOME/cordis.patch.yml,然后是任何 --patch  覆盖。此包的补丁插入四行:

| 行 id | 加载 | 默认值 |
| --- | --- | --- |
| memory | @achasoft/dsh-memory/host:存储、提示钩子、RPC、设置 | 开启 |
| memory-tools | @achasoft/dsh-memory/tools:面向模型的工具 | 开启 |
| memory-ui | @achasoft/dsh-memory:浏览器端部分 | 开启 |
| memory-embeddings-openai | @achasoft/dsh-memory/embeddings-openai | disabled: true |

卸载:

dsh plugin --profile web remove @achasoft/dsh-memory

这会移除该依赖及其 bundle 条目。请删除你自己的 patch 文件中针对上述 id 的任何行。你项目中的 .dsh/memory.db 文件会保留在原处。

配置

通过 id 从你的 profile 的 cordis.patch.yml 中覆盖某一行。patch 会替换该行的整个 config,因此需要重新声明该行所需的每一个键:

- id: memory
config:
databasePath: .dsh/memory.db
injectRules: true
injectSessionContext: true
autoSession: true
remind: once
vectorWeight: 0.6
minSimilarity: 0.3
searchLimit: 10
candidateLimit: 1000
embedBatch: 64
retentionDays:
sprint: 30
decision: 0
relevanceWeights:
similarity: 0.7
recency: 0.15
access: 0.15

patch 行是基础层。从 Settings 卡片保存的值会写入 harness 设置层($DSH_HOME/settings.yaml 的 memory: 部分),并优先于它。已提交的更改会在下一个请求或调用时生效,无需重启。

memory 行

| 键 | 默认值 | 在 Settings 卡片中 | 作用 |
| --- | --- | --- | --- |
| databasePath | .dsh/memory.db | 是 | 相对路径会针对每个项目目录解析。绝对路径会让所有项目共用一个文件。更改它会把打开的项目和正在运行的 agent 迁移到新文件。 |
| injectRules | true | 是 | 将规则块注入每个请求。关闭后规则仍会存储,但不会强制执行。 |
| injectSessionContext | true | 是 | 当顶层会话启动时,发送最近的摘要、sprint 目标和近期决策。 |
| autoSession | true | 是 | 为每个顶层 agent 打开一个 memory 会话。关闭后也会禁用提醒。 |
| remind | once | 是 | never、once(存在打开会话时的第一个停止边界)或 every-turn。 |
| toolset | core | 是 | core 或 full 工具。只有保存在设置层(卡片或 settings.yaml)中的值才有效,并且它会实时覆盖 memory-tools 行。在 patch 文件中对该行设置它没有效果。 |
| vectorWeight | 0.6 | 是 | 混合相似度中向量得分的占比,0–1。 |
| minSimilarity | 0.05 | 是 | 未设置相似度下限的搜索所使用的相似度下限,0–1。 |
| searchLimit | 10 | 是 | 未设置限制的 Memory 标签页搜索的结果数,1–100。 |
| candidateLimit | 1000 | 否 | 每次搜索探测(关键词和向量)所考虑的行数。 |
| embedBatch | 64 | 否 | 每轮后台处理嵌入的 memory 数量。 |
| retentionDays | {} | 否 | 每个类别的天数。缺失的类别使用上方的默认表;0 表示永不过期。规则永不过期。 |
| relevanceWeights | { similarity: 0.7, recency: 0.15, access: 0.15 } | 否 | 匹配度、新近度和读取次数如何组合成最终排序。 |

随附的 cordis.patch.yml 使用这些默认值重新声明了 retentionDays 和 relevanceWeights。省略它们的旧覆盖配置仍可加载;schema 会提供相同的默认值。

memory-tools 行

| 键 | 默认值 | 作用 |
| --- | --- | --- |
| toolset | core | core 注册六个工具;full 再增加四个。这是默认值:从设置卡片保存的工具集会覆盖它而无需重启,并且卡片会显示当前生效的工具集。 |

memory-embeddings-openai 行

启用该行并重新声明其配置:

- id: memory-embeddings-openai
disabled: false
config:
baseUrl: http://127.0.0.1:11434/v1
model: nomic-embed-text
timeoutMs: 30000
batchSize: 64

| 键 | 补丁中的默认值 | 必需 | 作用 |
| --- | --- | --- | --- |
| baseUrl | https://api.openai.com/v1 | 是 | 端点前缀;会追加 /embeddings。 |
| model | text-embedding-3-small | 是 | 作为 model 发送,并标记在每个存储的向量上。 |
| apiKeyEnv | OPENAI_API_KEY | 否 | 作为 bearer token 发送的凭据名称,每次调用时通过 harness 凭据服务解析。对于不需要密钥的端点,请省略它。 |
| timeoutMs | 30000 | 是 | 每个请求的截止时间。 |
| batchSize | 64 | 是 | 每个 HTTP 请求的文本数。 |
| dimensions | 未设置 | 否 | 作为 dimensions 发送,用于支持缩短向量的端点。 |

向量存储时会带上模型名称和向量长度。当模型或长度发生变化时,旧向量会被排除在比较之外,并在后台重新嵌入。如果提供程序无法描述自身,插件不会附加它,而是按关键字排序。如果嵌入调用失败,该搜索会回退到关键字排序。重建向量 会立即运行回填,并报告还有多少记忆缺少当前向量。

面向模型的工具

每个工具都会根据调用代理的会话工作目录解析项目。写入会标记为 source: assistant。

| 工具 | 工具集 | 作用 |
| --- | --- | --- |
| memory_search | core | 按关键字排序搜索,并在有嵌入时按含义搜索。默认 8 个结果。 |
| memory_store | core | 存储非规则记忆(decision、architecture、devops、sprint、project_plan、developer_docs、feedback、reference、session),优先级 0–3。 |
| memory_recall | core | 按 id 或精确标题读取一条记忆,并计入读取次数。 |
| memory_rules | core | 返回完整的实时规则集,代理添加的规则会带有标记。 |
| memory_add_rule | core | 添加一条 mandatory 或 forbidden 规则。 |
| memory_session_end | core | 将摘要归档到调用者自己打开的会话中。任何其他 session_id 都会被拒绝。 |
| memory_list | full | 按类别、状态、标签或子字符串筛选并分页列出记忆。 |
| memory_update | full | 更改标题、内容、标签、优先级或类别。 |
| memory_archive | full | 归档一条记忆,可选在历史记录中记录原因。 |
| memory_provenance | full | 读取某条记忆最近 25 条历史记录。 |

没有任何工具会硬删除记忆或恢复已归档的记忆;这些操作只能在 Memory 标签页中进行。

RPC

浏览器端调用一个名为 memory 的 Typert 远程命名空间。该契约生成到 generated/ 中,并随包一起发布。每个端点都接受一个可选的 project(一个绝对目录;省略时,使用宿主进程的工作目录),并返回 { ok: true, … } 或 { ok: false, code: 'invalid' | 'not-found' | 'unavailable', message }。

| 端点 | 用途 |
| --- | --- |
| describe | 计数、嵌入状态、生效规则、渲染后的规则块,以及当前生效的工具集。 |
| list | 经过筛选、排序、分页的列表。 |
| search | 排序后的搜索。 |
| create、update | 以用户身份写入。 |
| discard | 归档(hard: false)或永久删除(hard: true)。 |
| sessions | 最近 50 个会话。 |
| provenance | 某条记忆最近 100 条历史记录。 |
| importInstructions | 解析并导入一个 Markdown 指令文件。 |
| exportAll | 将所有记忆导出为 JSON 文本。 |
| reembed | 立即运行一次嵌入回填。 |

数据与存储

- 位置: /.dsh/memory.db,其中  是会话的工作目录。.dsh 目录以 0700 模式创建。
- 提交或忽略: 它是一个普通文件。将其提交以与团队共享规则,或将其添加到 .gitignore。
- 布局: 版本 1,存储在 meta 表中。任何其他版本的文件都会被拒绝并给出提示;没有迁移。
- 表和视图: memories、sessions、provenance、meta,外加两个用于手动读取的视图:

duckdb .dsh/memory.db "select kind, title, content from rules"
duckdb .dsh/memory.db "select category, title, source, updated, expires from memory"

- 锁定: DuckDB 会对文件加排他锁。当 dsh 保持某个项目打开时,另一个进程(第二个 dsh,或 duckdb shell)无法打开它,并会收到“locked by another process”错误。在手动查询之前请停止 dsh。
- 每个文件、每个进程只打开一次: 一个进程对每个数据库文件只打开一次,无论以何种路径拼写或插件重新加载方式访问它。此前在同一进程中打开同一文件两次并导致其损坏的 bug 已修复。不要针对同一个 $DSH_HOME 运行两个 dsh 服务器。
- 事务: 每次写入、其作者身份检查及其审计条目都在一个事务中运行,因此编辑始终应用于该行当前的状态。
- 备份: 停止 dsh 并复制 .dsh/memory.db,或使用 导出 JSON 获得可读副本,但无法重新导入。

安全与信任模型

规则会在每次请求时向模型重复,因此插件限制了谁可以更改规则集:

- 用户规则属于用户。 在 Memory 标签页中编写或从文件导入的规则,只能从 Memory 标签页编辑、归档或删除。尝试这样做的工具调用会被拒绝,并给出相应消息。代理也不能将用户编写的记忆变成规则。
- 代理可以添加规则并管理自己的规则。 使用 toolset: full 时,代理可以编辑或归档代理添加的规则。它还可以编辑或归档任何非规则记忆,包括你编写的记忆。
- 代理规则上限: 代理编写的规则最多 4,000 个字符,一个项目最多保留 100 条有效的代理添加规则。用户的规则不计入这两个限制。
- 子代理完全不能更改规则。 它们可以搜索、存储非规则记忆并读取规则。它们的写入会以操作者 subagent 记录在历史中,任何带有此类创建或编辑条目的内容都会被排除在下一会话的初始上下文之外。
- 会话按代理划分。 memory_session_end 只关闭调用代理自己打开的会话。指定另一个代理的会话、由另一个进程或更早运行打开的会话,或已经结束的会话的 session_id 会被拒绝。此类打开的会话会在下一次会话开始时作为孤儿会话关闭。
- 作者身份由 source 列表示。 只有精确值 assistant 才算作代理编写。任何能写入 DuckDB 文件的人都可以更改它。
- 嵌入的凭据通过名称(apiKeyEnv)引用,绝不会存储在数据库中,也不会在 UI 中显示。

已知限制

- RPC 接受任何项目路径。 任何经过身份验证的 Web Client 调用者都可以将任何绝对目录指定为 project。然后插件会在那里创建 .dsh/memory.db 并读取或写入它。
- memory_rules 输出没有上限。 与注入块不同,它会完整返回每条规则。
- 早期版本记录的子代理写入无法识别。 它们以操作者 agent 记录,因此在会话上下文中被标记为代理添加,但不会被排除在外。
- 代理对你编写的记忆的编辑没有标记。 作者身份取决于谁创建了条目,因此你编写的决策以及后来被顶层代理重写的内容会显示为未标记。
- 最后一个会话摘要按原样保留,包括换行符。只有顶层代理会提交摘要。
- 更改保留期不会重新计算现有到期日期。 新值会在创建记忆时,或其类别或优先级发生变化时,或恢复记忆时生效。
- 每个文件单写入者。 参见锁定。

开发

devDependencies 链接到相对于此仓库的 ../../deepseek-harness 处的 deepseek-harness 检出,用于类型和测试。pnpm install 期望它在那里。

bash
pnpm install
pnpm run typecheck
pnpm test             # 检查 generated/ 与 src/host,然后运行 vitest
pnpm run build        # 写入 generated/,然后 tsc,然后 tsdown

generated/ 保存 Typert RPC 契约,由 scripts/typert-endpoints.mjs 渲染生成。当 src/host/index.ts、src/host/types.ts、端点表或渲染器自契约上次记录以来发生变更时,或者当 generated/ 下的某个文件与端点表渲染出的内容不一致时,pnpm test(scripts/check-typert.mjs)会失败。在更新端点表以匹配 src/host/ 之后,运行:
bash
pnpm run regen:typert

build 会写入 generated/,但不会记录指纹;只有 regen:typert 会记录。

要在本地 profile 中运行某个检出,请按路径添加它并重启 web 服务器:
bash
dsh plugin --profile web add link:/absolute/path/to/dsh-memory
dsh web

链接的包会从其自身目录解析其导入,因此它所导入的 harness 包必须在那里解析到与正在运行的 harness 所使用的相同副本。维护者的工作区通过父级 dsh-plugins 目录中的 publish-plugins.sh 和 .dsh-compat/install-plugins.sh 来实现这一点,而不是在本仓库中。重新构建后,重启 dsh web。

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群