dsh-flywheel
面向 DeepSeek Harness(DSH) 的「会话飞轮」插件 。在单会话隔离下,让一条龙长会话接近当前句只带工作集;用项目级产物图 + 倒排在会话之间传递短卡。
- Stars
- 0
- Language
- TypeScript
- Created
- Sep 3, 2026
- Updated
- Sep 4, 2026
Introduction
dsh-flywheel
English | 中文
面向 DeepSeek Harness(DSH) 的「会话飞轮」插件 —— 仓外独立仓库(v1),与 Cursor 侧共用同一套索引与检索协议。
一句话目标:在单会话隔离下,让一条龙长会话接近 Cursor 的「当前句只带工作集」;用项目级产物图 + 倒排在会话之间传递短卡,而不是把 transcript 糊在一起。
仓库结构
packages/core/ # 协议 + 检索编排(不绑定 sqlite / 不依赖任何 DSH 运行时包)
packages/lexical-sqlite/ # v1 LexicalIndex + GraphStore:SQLite FTS5 + 边表(node:sqlite, WAL)
packages/dsh-bundle/ # DSH 侧 bundle:Host 插件 + Web 设置卡片(./client)
计划书全文见 _docs/flywheel-plugin-plan.md(本仓库不再复述设计细节)。
包职责(对应设计 §6.1)
| Cordis name | 入口 | 职责 |
|---|---|---|
flywheel-store | @dsh-flywheel/dsh-bundle/store | 注册 flywheel 设置 namespace,提供 ctx.flywheel,按设置组装 Provider |
flywheel-lexical-sqlite | @dsh-flywheel/dsh-bundle/lexical-sqlite | 挂载 sqlite-fts(v1 必装) |
flywheel-inject | @dsh-flywheel/dsh-bundle/inject | agent/pre-step 注入工作集(step 1 + 真人句,digest 去重) |
flywheel-index | @dsh-flywheel/dsh-bundle/index | 文件事件 + 用途句入库 + 纠正作废 |
flywheel-window | @dsh-flywheel/dsh-bundle/window | idle 换窗 compactNow |
flywheel-trim | @dsh-flywheel/dsh-bundle/trim | tools/post-execute 截断超大工具结果(含 read,默认 4000 字) |
tool-flywheel | @dsh-flywheel/dsh-bundle/tools | project_search / session_search / session_read |
flywheel-web | @dsh-flywheel/dsh-bundle | 空 Host apply,让 Web 扫描到包根上的 dsh.client |
| (浏览器) | @dsh-flywheel/dsh-bundle/client | 设置左侧「会话飞轮」栏目(中英字典) |
服务面保持小:ctx.flywheel.retrieve / ingest / queueClaimExtract / config()。
安装(本地 dev 实例,离线)
@dsh-flywheel/* 尚未发布,三个包之间通过 link: 相对依赖相互引用,因此离线只能用目录 link 安装(tarball 之间离线无法解析传递依赖,已实证不可行)。装进正在运行的 dsh(本例 profile web):
cd /Users/zhaoshuxian/Desktop/myproject/dsh-flywheel
# 1) 等当前 dsh 任务结束后再构建(运行中不要改 lib/)
pnpm --filter @dsh-flywheel/core build
pnpm --filter @dsh-flywheel/lexical-sqlite build
pnpm --filter @dsh-flywheel/dsh-bundle build # host:lib/*.js(含包根空 apply)
pnpm --filter @dsh-flywheel/dsh-bundle bundle # 浏览器:lib/client.js
# 2) 三个包一起以 link 加进 profile(core / lexical-sqlite 是普通依赖,
# dsh-bundle 因声明 dsh.bundle 自动进入 profile layers)
npx @deepseek-ai/dsh plugin --profile web add \
link:./packages/core link:./packages/lexical-sqlite link:./packages/dsh-bundle
# 3) 验证 layer 挂载(可先 --dump-config 看 flywheel 层)
npx @deepseek-ai/dsh --profile web --dump-config
# 4) 重启实例使新增 bundle 层生效
npx @deepseek-ai/dsh web --no-open
说明:
- 运行时
@deepseek-ai/*从 dsh 安装目录的共享 module fallback 解析(无需 registry)。 - 卸载:
npx @deepseek-ai/dsh plugin --profile web remove @dsh-flywheel/dsh-bundle(再 remove 另外两个包)。 - 设置卡片需要
lib/client.js(pnpm --filter @dsh-flywheel/dsh-bundle bundle)以及 patch 里的包根行flywheel-web。首次 bundle 前在本仓执行一次pnpm install以安装tsdown/lightningcss。 - 发布到 npm 后可用
dsh plugin --profile web add dsh-flywheel-dsh-bundle一步安装;届时把三个包的link:依赖改回版本号即可。
安装后:
- 设置 左侧导航出现独立栏目「会话飞轮」(不是插件配置里的卡片,也不是 Flywheel / 包名)。
- 首步真人消息注入 ≤
ftsK张节点卡 + 1 跳 ≤hopExtra张;digest 相同不重复注入。 - 工具结果(含
read)超过maxToolResultChars(默认 4000)时截成首尾预览;后续步骤不再整文件回放。read截的是官方结构化 value(卡片 meta 一并缩小);trim 在 spill 内侧先截断;若官方 spill 仍写出文件,会去掉read结果里的 spill 路径。 - 工具循环 / 子代理不重复检索;写出的 pptx/pdf/xlsx/… 落
PRODUCED边。 - 用户纠正(
不对|不是|改成|作废…,大小写/中英均可)把最近 3 条 active claim/change 标superseded。 - 规则命中后,后台用
summarizationModel(默认deepseek-v4-flash)把用途句改成 ≤80 字目的 + 绑定路径;超时 8s 或失败保留规则摘录,绝不 await 在 pre-step(§7.3 claim flash)。
配置(schema = 设置页 = CLI JSON,禁止硬编码 K)
字段与默认值见 packages/core/src/config.ts 的 DEFAULT_CONFIG;DSH 侧的 schemastery 镜像见 packages/dsh-bundle/src/config.ts。关键约束:
ftsK/hopExtra/vectorK正整数;hop只能是1(v1 不开放多跳)。maxChars500–8000。maxToolResultChars1000–32000;trimToolResults默认开,默认 4000。这只截断当轮写入历史的工具结果,不会少一次模型 API 调用。lexicalBackend必须已挂载;v1 只挂载sqlite-fts。选elasticsearch但未装 Provider 时保存被拒绝(fail loud),sqlite 检索不受损。vectorBackend: off(默认)时热路径零 embedding;v1 不实现 ES / 云向量,接口与卡片字段已留位(P6/P7)。- 密钥走
role('secret'),不出现在 settings 读取响应。
当轮为什么还是贵
工具循环里每一步都是一次 Messages。飞轮不能把 142 次调用合成 1 次。账单是两笔:
- 调用次数:模型每
read一个文件就停下来再请求。persona 已要求同一轮并行grep/glob/read,不要每读完一个文件就复述。 - 提示词体积:
flywheel-trim在 spill 内侧把工具结果(含read)截到maxToolResultChars,避免官方 spill 把大read写成文件再被模型读回去。compaction 默认要到窗口约 80% 才因压力触发;换窗在本轮第一步先试compactIfNeeded('forced'),官方包则回退到'context-overflow'(同样绕过压力阈值)。compactNow仅 idle。这不打断前缀缓存的追加语义。 - 首次思考回传:DeepSeek 会把每一步的
reasoning_content原样塞进后续请求。High 下一开场中英混写的长调查会同时当 output 计费、再当后面每一步的 input。飞轮不能截断这段(官方 passback 规则);真正有效的是把 reasoning 调到off/low。persona 只约束「用用户语言、先要点再动手」,压不住 High。
飞轮管不了的杠杆(P0 用户配置,不在本仓):瘦 preset(coding-search 含 /plan 与受限 web)、spill maxInlineBytes: 12000、compaction thresholdRatio: 0.5 + retainTokens: 16384、逛代码不要用 High reasoning。换 Exa/Perplexity 搜索后端仍属后续 Host 项。
检索协议(热路径唯一算法,§4.3)
倒排 search(query, { k: ftsK })(active、当前项目)→ 可选向量 RRF(默认关)→ 恰好 1 跳(边集 PRODUCED/DESCRIBES/CITES/SUPERSEDES/CONTINUES/PART_OF)→ 展开 ≤ hopExtra → 丢弃仍 active 的 SUPERSEDES dst → 其它会话节点只留 title+summary(≤200 字)→ 渲染 ≤ maxChars → digest = sha256(sorted ids + query + lexicalBackend),相同则 unchanged。全程零 LLM。
同会话一条龙
新开会话选「编码检索」。简单修直接改。复杂任务先 /plan,把方案写到 docs/changes/<slug>.md 再批准;用户说「开始实现」时本轮第一步会尝试压缩旧历史,并注入该方案卡。工具表开局就有 web_search,但仓库事实先 grep,只有当前外部文档才搜。要换题说「另外…」。
开发
pnpm install
pnpm -r test # core(fake index 换 sqlite 仍绿)+ lexical-sqlite(真实 in-memory FTS5)+ claim-flash 解析
pnpm -r typecheck
pnpm -r build
v1 未实现(已留接口,不做 P6/P7)
- Elasticsearch
LexicalIndexProvider(packages/lexical-elasticsearch/) - 云向量
VectorIndexProvider + 查询期 embedding(packages/vector-cloud/) - Cursor hooks / CLI(
packages/cli/、packages/cursor-hooks/) - 领域抽取器
java-symbols/office-names/media-caption(packages/extractors/)
对照计划书验收(§14 完成定义)
- 同一
.dsh/flywheel/index.sqlite可被 CLI / DSH / Cursor hook 读写 —— core 不绑 sqlite,lexical-sqlite是唯一读写该文件的 Provider。 - 换题后工作集卡片跟着变、不出现上一题 superseded 卡 —— 见
core/retrieve.ts+flywheel-window。 - 「生成 Q3 预算 PPT」在落盘 / 用途句后,新会话可 FTS 到 artifact/claim —— 见
flywheel-index。 - 其它会话原文默认不进自动注入,
session_search能搜到标题 —— 见retrieve的 foreign-session 截断 +tool-flywheel。 - 开局
coding-search(bash + 检索 +/plan+ 受限 web)+ 12k spill;换窗在 step 1 先forced再回退context-overflow,compactNow仅 idle —— preset 在~/.dsh/.agent-presets/coding-search/。 - 财务 / 人力零额外抽取器也能靠 claim 工作 ——
generic抽取器内置。 - 设置左侧导航出现「会话飞轮」栏目、改「注入字数上限」下一轮生效 —— 见
dsh-bundleclient + store。 - v1 未装 ES / 云向量时保存失败、sqlite 检索不受损 —— 见 store
validate。