DSH Web UI 的跨会话能力插件:在两个普通会话之间引用、检索和传递内容,全部走 dsh 的 Cordis 服务与组合哲学(不修改核心仓库任何代码)。
在 DeepSeek Harness 终端运行:
dsh plugin --profile web add Happy2Git/dsh-web-cross-sessionDSH Web UI 的跨会话能力插件:在两个普通会话之间引用、检索和传递内容,全部走 dsh 的 Cordis 服务与组合哲学(不修改核心仓库任何代码)。
| 能力 | 触发方式 | 机制 |
|---|---|---|
| 侧边栏内容搜索 | Web 侧边栏搜索框直接搜消息正文 | 覆盖 session-query-sqlite 行为 openAt: first-search;核心 session.search 返回每条命中的 seq,点击结果会跳转并高亮到匹配消息。搜索范围是用户对话与模型输出——工具调用与结果(命令、代码片段)不参与匹配 |
composer @ 引用会话 |
输入框打 @,从会话候选中选择 |
复用 dsh-session-reference 服务的快照投影,提交时把带 untrusted 警告的快照插入消息 |
/xsend <text> 选择器转发 |
输入 /xsend <文本> 回车 → 弹出目标会话选择器(live 会话列表) |
agent.inject() 非唤醒注入;/xsend <sessionId> <text> 直发形式仍可用 |
| 模型会话查询工具 | 模型自行调用 | 挂载 dsh-tool-session-query 的五个工具(session_search 等),config 可关 |
npx -y @deepseek-ai/dsh plugin --profile web add dsh-web-cross-session
npx -y @deepseek-ai/dsh --profile web
插件包需可解析(npm 发布或本地 link: 安装)。插件自己的 cordis.patch.yml 在 bundle 层生效(排在 base / web-app 之后),自动完成两件事:
session-query-sqlite 行覆盖为持久化 FTS 索引(openAt: first-search,路径 $DSH_HOME/session-query.db);搜索面板是宿主 Web 侧边栏自带的系统搜索框,插件负责解锁它的内容搜索能力:覆盖 session-query-sqlite 为持久化 FTS 索引 + trigram 分词,并挂载后台预热。装完即用:侧边栏搜索框匹配标题/工作区(本地)和消息正文(FTS 索引,250ms 防抖),结果按会话展示、每条带一行 snippet。
点击结果跳转定位(滚动到匹配消息 + 行闪光 + 命中词高亮)需要宿主 core 合并搜索增强——见下"依赖宿主 core 增强"一节。上游原版 core 的系统搜索只打开会话、不定位;两者都是可用状态,差别在于是否定位到具体消息。
全新部署的第一次搜索需要为全部历史会话构建一次 FTS 索引(约百会话 ≈ 半分钟,千会话级更久),仅此一次——索引持久化在 $DSH_HOME/session-query.db,之后每次启动只做增量核对,搜索稳定在亚秒级。插件默认在启动 10 秒后自动于后台完成这次构建(warmupDelayMs 可调),多数情况下你的第一次搜索已经是热的;若在后台构建完成前就搜索,该次请求会等待构建结束,请保持页面打开——中途刷新或退出会回滚未完成的构建,下次从头再来。
中文搜索:插件把核心 session-query-sqlite 的 tokenize 覆盖为 trigram,任意长度的中文子串都能命中——"搜索"可以命中"会话搜索功能",无需词组空格。该键是核心 SqliteSessionQueryEngine 提供的配置(默认 unicode61),需要宿主核心版本带 tokenize 支持;旧版核心不认识该键时插件会以默认分词器继续运行(中文子串限制仍在)。切换分词器会重建一次派生索引(与首次构建同价,仅一次)。
搜索按调用方工作区过滤:核心 session.search 只返回与当前工作区 cwd 精确相等的会话(外加自身)。跨工作区的命中连 snippet 正文都不会下发。
系统侧边栏搜索的事件级跳转定位(点击结果滚动到匹配消息 + 行闪光 + 命中词高亮)由宿主 core 提供,不是插件实现的——侧边栏搜索框是 core 的 ui-workspace 组件,插件作为 cordis 插件无法修改它的行为。插件负责的是数据侧:解锁内容搜索(FTS + trigram)、预热索引、以及 session.search 返回命中 seq(定位坐标由 core 的搜索链路携带)。
feat/sidebar-search-locate,含 session.search 返回 seq + 侧边栏点击 reveal):搜索并定位——滚动到命中消息、行闪光约 3 秒、命中词高亮约 5 秒。插件对两种宿主都兼容:检测到宿主支持 locate 则完整定位,否则退化为只打开会话。要在你的部署里获得完整定位能力,需将上述 core 增强分支合并进宿主 core。
@ 引用会话@,菜单出现 sessions 分组(候选来自 dsh-session-reference 的 listCandidates,按工作区亲缘排序);prepare(),把快照渲染成 untrusted 快照文本(## Referenced sessions + 固定警告 + tag-safe JSON)插入消息——模型只把它当背景信息,不执行其中的指令;引用形态(/xssn/serialize,host 侧按工作区决定):
Referenced session: <label> (<id>) + 检索指令(几 token),模型用 session_event_search / session_search 自己取内容;cwd 相等授权,跨区目标模型读不到,自动回退 untrusted 内联快照(有 65KB/源的硬上限),引用仍然可用;inlineSnapshot: true 强制全部内联(旧行为)。注意"工作区"是精确字符串:agent-architectures 与 agent-architectures/deepseek-harness 是两个工作区。限制:一次最多引用 3 个会话;内联快照文本会直接显示在输入框(可编辑、可删除)。
候选列表由服务端按 caller 工作区过滤后再返回(cwd 精确相等 + 自身),子代理行挂在父会话下的二级菜单里,装配与候选交付顺序无关;同一份全量 corpus 观察有 1.5s 缓存,@ 逐键输入不会每次都打穿会话列表。
/xsend <sessionId> <text> 转发消息把一段文本作为 relay 消息投递到另一个会话的 inbox:
(Forwarded from session <来源>) 前缀开头,source 记录为 {kind: 'plugin', form: 'relay'};@ 打开会话选择菜单,每条候选的 description 行就显示会话 id(子代理会话带 [subagent] 标记);会话列表/恢复面板也显示 id;默认挂载 session_search / session_event_search / session_trace / session_event_trace / session_event_read 五个只读工具,模型可自行搜索历史会话。关闭:在 ~/.dsh/profiles/web/cordis.patch.yml 里加一行
- id: cross-session
config:
mountModelTools: false
(config 覆盖是整行替换——上例只覆盖了这一个键,其余键会回到默认值。)
| 键 | 默认 | 含义 |
|---|---|---|
mountModelTools |
true |
是否全局挂载模型侧五个会话查询工具 |
maxReferences |
3 |
一条消息最多引用几个会话(核心硬上限 3) |
candidateLimit |
50 |
@ 候选发现上限 |
maxReferenceBytes |
65536 |
每个来源快照的 UTF-8 字节上限 |
inlineSnapshot |
false |
true 强制引用内联为快照;false 时同工作区引用用指针、跨工作区自动回退内联 |
/xssn/* 仅 loopback 可达,调用方是本机用户自己打开的页面;模型侧工具的授权与此独立、始终生效。/xssn/candidates 在服务端执行与 dsh-tool-session-query/workspace-access 相同的规则——caller 无条件可见自身;其他会话要求 caller 有 cwd 且目标记录 cwd 与之精确相等,cwd 未知的持久会话一律不可见。知道别的会话 id 也无法通过本路由枚举它。prepare / serialize 读取的是用户在 picker 里明确选中的目标,允许离开 caller 工作区(这就是跨工作区内联快照功能)。同区引用默认走指针模式;指针只对模型工具实际可读的同区目标发出。/xssn/send 要求来源与目标都是 live 会话且互不相同;relay 前缀里的来源 id 来自服务端验证过的 live 记录,不是调用方可随意伪造的字符串。{来源会话, 目标会话, 标签} 编码进 ref 本身(dsh-session:<base64url(JSON)>),序列化时从 ref 解码,浏览器端没有跨 composer 共享的可变会话状态;chip 粘贴到另一会话后仍按挑选时的来源会话解析。XSSN_INTERNAL / internal error,原始堆栈进服务端日志;RouteError 的精确文案原样透出。application/json(跨站写围栏)+ 1 MiB 上限;断连即 abort 后端工作。RpcMethodMap 是编译期固定表),全部走自有物理路由 + 现有 session.* RPC + agent.inject()。cordis.patch.yml 组合层:覆盖 session-query-sqlite(openAt)+ insert 本插件行
src/index.ts host 半:装配 SessionReferenceResolver、条件装配模型工具、
/xsend 命令、绑定路由依赖
src/routes.ts /xssn/* HTTP 接线(loopback 守卫 + JSON 围栏 + 错误映射)
src/routes-core.ts 纯逻辑(依赖注入,可单测):candidates / prepare /
serialize / send
src/client/index.ts 浏览器半:@ sessions trigger + /xsend 触发器
+ ReferenceCodec(提交时快照化)
src/client/picker.tsx 二级 picker overlay(@ 主会话 + 子代理 / /xsend 目标)
设计要点(对应 dsh 的 cordis 哲学):
dsh-session-reference 服务;插件只做 host 适配(路由 + 命令)与浏览器适配(trigger + codec);agent.inject(),与 TUI 的引用事务同一语义,不产生 turn、不自动续跑;serialize 异步调用、失败阻止发送——模型永远看不到"半准备"的引用;pnpm install # devDependencies 中公开可装的依赖;宿主类型包见下文
pnpm typecheck # tsc --noEmit(类型来自 ../deepseek-harness 的 lib/types,见下文)
pnpm build # tsdown:lib/index.js(node ESM)+ lib/client.js(浏览器 closure factory)
pnpm test # vitest:路由逻辑单测 + patch 组合测试 + 浏览器 jsdom 测试
类型依赖:插件的类型检查引用宿主 @deepseek-ai/* 包的类型(dsh-agent、dsh-session、dsh-session-query、dsh-client-runtime、dsh-client-ui-input-trigger 等),这些包的部分传递依赖(如 dsh-compact)不在公共 registry,因此完整 pnpm typecheck 需要一份宿主类型来源——tsconfig.json 的 paths 指向相邻的 ../deepseek-harness 仓库副本(开发机的标准布局);没有它时 typecheck 会因类型模块缺失而失败,但构建与运行不受影响(运行时依赖由宿主 dsh 在挂载时提供,见 peerDependencies;lib/ 产物是自包含的)。挂载时若 dsh-tool-session-query 不在依赖闭包内,host 半会 warn 并继续提供引用/搜索/转发(warn 里带补救指引),mountModelTools: false 可消除告警。
测试覆盖:candidates 的工作区授权(跨区剔除、无 cwd caller 仅见自身)、与顺序无关的两级装配(child 先于 parent、父/子成环均不丢行)、id 字母表门卫、sanitizeLabel 清洗;prepare/serialize 的指针 vs 快照判定与委托;send 的双 live 校验、自转发拒绝、字节上限;error 映射对未知异常的脱敏;cordis.patch.yml 组合测试;浏览器 trigger 的候选映射、复合 ref 编解码往返、每个 chip 绑定各自 composer、无法识别 ref 阻断发送、serialize 成功/失败路径。
@ trigger 与 ui-subagent 的 @ 并存(同名分组会注册失败——本插件分组名是 sessions);/xsend 目标必须是 live 会话;冷会话请先在 Web 侧边栏打开;trigram(插件在 patch 层覆盖核心配置),任意长度子串可召回;核心不支持该键时降级为 unicode61 的整词匹配。登录后即可为该插件评分和评价。
还没有人评价这个插件,来抢个沙发吧!