Bundle
dsh-session-index
会话全文索引插件:监听 session/event 构建跨会话索引,提供 session_search / session_index_stats 工具,优先使用框架自带 ctx.sessionQuery (SQLite FTS5)
- Source
- longyu065
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 6 days ago
Readme
# dsh-session-index DeepSeek Harness 的**会话全文索引插件**(组合包 / `dsh.bundle`)。 监听 `session/event` 事件流,把每一段会话里的**用户消息、助手回复、工具调用/结果、会话标题** 抽取成可检索文档,构建跨会话倒排索引,并通过 `session_search` / `session_index_stats` 两个工具暴露给模型 —— 让 agent 能"回忆"之前任何一次对话里说过什么、做过什么。 ## 功能 | 能力 | 说明 | |---|---| | 实时增量 | 每个 `session/event` 追加立即入索引(按 `sessionId#seq` 幂等去重) | | 历史回填 | 启动时先索引内存活动会话,再按水位线用 `ctx.sessionPersistence.readFrom(id, fromSeq)` 增量补全落盘旧会话 —— 弥补 `session/event` 不重放已恢复会话历史事件的缺口 | | 混合检索 | `preferFts` 开启时,**FTS5 + 内存索引并跑、按会话去重合并**:框架 `ctx.sessionQuery`(SQLite FTS5)负责英文/词级召回,内置二元组索引补足中文召回(FTS5 unicode61 不做中文切词) | | 富卡片 | `presentCall`/`presentResult` + `output.presentationMeta` 投影成 Web UI 的 `card:'search'` 卡片:按会话分组的可展开命中列表(组头=会话 id+标题,组内=命中片段) | | 持久化 | 索引文档按 JSONL 追加到 `$DSH_HOME/session-index/<sessionId>.jsonl`,重启只补增量 | | 会话销毁清理 | `session/disposed` 时同步移除该会话全部文档与索引文件 | | 隐私开关 | `indexReasoning`(默认关,不索引 CoT 思考文本)、`indexToolResults`(默认开) | 索引内容:`user/message`、`assistant/message` 的 text(reasoning 可选)、`tool/call`(工具名+参数)、`tool/result`、`session/title`。 ## 仓库结构 ``` dsh-session-index/ # 包根 = 仓库根(组合包,dsh.bundle) ├── src/session-index.ts # 插件源码(单文件,可擦除 TS,Node 22.18+ 原生类型剥离即可加载) ├── index.js # 编译产物(build 生成,随包分发) ├── cordis.patch.yml # ① 挂载插件 ② 把框架自带 FTS5 从 openAt:never 启用为 first-search ├── test-index.mjs # 引擎独立测试(不启动 dsh):65 项断言 ├── tsconfig.json / package.json / LICENSE / .gitignore └── README.md ``` ## 安装 ```sh # ① 打包(在仓库根目录) pnpm pack # 产出 dsh-session-index-0.1.0.tgz # ② 装进 profile(web = 桌面端用的 profile) dsh plugin --profile web add ./dsh-session-index-0.1.0.tgz # ③ 重启桌面应用 / dsh web ``` 组合包自带 patch 层会额外**覆盖 dsh-base 里 `session-query-sqlite` 行的配置**: 把框架自带 FTS5 从默认的 `openAt: never` 改成 `openAt: first-search` + 持久化路径 `$DSH_HOME/session-query.sqlite`,从而 `session_search` 自动进入混合检索。 想关掉就在自己 profile 的 `cordis.patch.yml` 里再覆盖该行(patch 按层后写覆盖前写)。 > **为什么用 tarball 而不是 `add ./目录`**:pnpm 对 `link:` 协议的本地目录包 > **不会安装它的 dependencies**(实测);`pnpm pack` 出的 tarball 是普通包,依赖正常装进 > profile 的 `.pnpm` 子树,bundle 内 `@deepseek-ai/*` 导入才能解析。 ## 开发与测试 ```sh # 依赖:@deepseek-ai/* 解析需要本地符号链接(不入库) mkdir -p node_modules && ln -sfn <dsh安装目录>/node_modules/@deepseek-ai node_modules/@deepseek-ai # 其中 <dsh安装目录> 通常是 ~/.npm/_npx/<hash>/;桌面端与 dsh web 共用同一份。 # tsc 类型检查还需要 @types/node(npm i -D 或复用本机已有安装) node test-index.mjs # 65 项引擎单测 pnpm run build # tsc 编译 src → dist/ → index.js ``` ## 配置项 | 键 | 默认 | 说明 | |---|---|---| | `dataDir` | `''`(自动 = `$DSH_HOME/session-index`) | 索引落盘目录;填自定义路径可改位置 | | `maxResults` | `20` | `session_search` 默认最大命中数 | | `maxSnippetChars` | `240` | 摘要片段最大字符数(Unicode 码点) | | `maxDocChars` | `4000` | 单条文档索引的最大字符数(工具结果可能很大,截断防膨胀) | | `indexReasoning` | `false` | 是否索引 assistant 的 reasoning 思考文本 | | `indexToolResults` | `true` | 是否索引工具返回结果 | | `preferFts` | `true` | 是否优先使用框架 `ctx.sessionQuery` FTS5(并跑混合检索);false 则纯内存索引 | ## 设计要点 - **为什么需要回填**:`session/event` 是"提交后追加"事件流,**恢复(resume)的会话不会重放 seed 历史事件**(`constructor seeds do not emit`)。插件启动时 ① 用 `ctx.sessions.list()` 索引内存活动会话,② 用 `ctx.sessionPersistence.list() + readFrom(id, watermark+1)` 按水位线 增量补全落盘旧会话。水位线存在内存 + 持久化索引文件里,重启后只补增量。 - **幂等**:`sessionId#seq` 做文档主键,重复 ingest(回填与实时事件重叠)不重复计数。 - **为什么混合**:FTS5 `unicode61` 分词器不做中文切词,整串 CJK 是单个 token("可以跨会话 搜索历史了"匹配不到"跨会话搜索");内存索引的二元组召回互补。`engine` 字段报告实际引擎: `memory` / `fts5` / `hybrid`。 - **富卡片数据流**:`execute` 返回规范值 → `output.presentationMeta` 投影出纯 JSON 卡片数据 (随 `tool/result` 事件持久化,可回放)→ `presentResult` 把它还原成 `card:'search'` 视图, Web UI 按会话分组渲染成可展开卡片。 ## 已知限制 - 索引目录应由单个 dsh 进程独占(与框架 session-query 的派生索引一致);多进程共享同一 `dataDir` 未做并发保护。 - 中文按二元组召回:单字查询(如"插")只能命中孤立单字文档,建议至少输入两字。 - 框架 FTS5 不索引 `session/title`,`kind='title'` 过滤走内存索引。 - 卡片内暂无"跳转原会话"交互(框架 wire format 无 link/action 块,前端无会话跳转 URL), 卡片携带会话 id + 标题,配合侧边栏定位。 - `session/disposed` 只清理内存与自己的 JSONL 文件,不影响原始会话日志。 ## License MIT
Install
dsh plugin --profile web add github:longyu065/dsh-session-index#cc24204b10d56af4a5589fb530003620c1567868
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-session-index from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.