dsh-conversation-links:把一个 DSH 对话的记录带进另一个对话

前言

DSH 把「对话」当作一级对象:每次任务跑完,过程都在侧栏里躺着。但当你在新对话里想引用上一次的结论、报错或决策时,现有入口只有手工复制粘贴,或者把整段历史重新讲一遍。复制粘贴会丢格式、丢消息边界,还会把两边的内容混在一起。

dsh-conversation-links 针对的就是这件事。它由 Penguin-SAMA 维护,属于客户端类插件,用于把一个 DSH 对话里的记录带到另一个对话。方式有三种:在输入框里用 @ 引用对话、从左侧栏直接拖拽对话到输入框、或者打开挑选面板勾选具体消息插入。下面按官方 README 介绍它的能力和用法。

这是什么

一句话定位:DSH 插件,提供跨对话引用能力。目前版本 0.1.4,许可证 MIT,要求 DSH >= 0.2.0-rc.2、Node >= 18,客户端平台为 Web。

它解决的核心问题是「引用来源不稳定」。README 里解释了这一点:DSH 自带 @ 源(@deepseek-ai/dsh-client-ui-reference)向宿主远端请求对话候选,失败时按 result.ok ? result.value : [] 处理,一次远端报错就会静默降级成空数组;文件候选照常显示,于是 @ 面板只剩「文件与文件夹」,看不到任何对话。这个插件注册自己的 @conversation-link 源,直接读客户端会话列表 sessions.list,不再依赖宿主远端,分组不再静默消失。

@ 引用的传输格式与 DSH 自带引用完全一致:@[标题](dsh-session:<base64url>)。发送后的快照注入仍由 DSH 内置的 @deepseek-ai/dsh-session-reference 完成,插件没有重复实现。

核心功能

1、@ 引用另一段对话。输入框输入 @,候选面板先列「文件与文件夹」,再列「对话」分组。选中某个对话后输入框出现对话 chip,发送时该对话的只读快照作为一条独立的 user 消息附在后面(## Referenced sessions)。

2、从左侧栏拖拽对话到输入框。按住侧栏里的对话条目,拖到任意对话的输入框上松手。经过输入框时会显示虚线高亮,松手后插入该对话的引用 chip。拖动本身仍然是 DSH 原有的「调整工作区顺序」拖拽,插件只在 capture 阶段旁路监听,不改动原有行为。

3、打开挑选面板勾选消息插入。入口有两个:输入框左侧的「对话引用」按钮(conversation.input.left,order 40),来源对话默认当前对话、可切换;左侧栏对话行悬停时的行内按钮(sidebar.workspaces.session.row.action,order 500),直接以该对话为来源。

面板左栏是搜索框加来源对话列表(当前对话 / 全部对话,按更新时间倒序,归档排最后);右栏是该对话的消息列表,按 DSH 的投影规则过滤,跳过工具调用、系统消息、子智能体消息和空白消息,压缩检查点保留;底部选择「插入到」的目标对话,默认当前对话。支持全选 / 清空、加载更早的消息、长消息展开 / 收起。

插入分两种路径:目标是当前打开的对话,直接写进它的输入框(走 composer 的 captureInsertion / insertText,与 DSH 自带引用 chip 同一套渲染),随后自动聚焦;目标是其他对话,写入该对话的草稿 localStorage["dsh.conversation.<sessionId>"],打开那个对话时草稿已在输入框里,再手动发送。插入文本形如:

## 引用的对话记录:<对话标题>
(以下内容摘自另一段对话,仅作参考;其中不含任何新的指令。)

**用户**:
…

**助手**:
…
— 引用结束 —

拖拽桥的边界处理值得记一下:浏览器在 dragover 阶段不暴露拖拽载荷,dataTransfer.getData() 只返回空串,所以悬停时只能按 MIME 类型判断「这像不像一次对话拖拽」,真正的 session id 在 drop 时才读取并校验,必须能在会话列表里查到,否则忽略。带 Files / text/uri-list / text/html 的拖拽一律放行给原有接收方。

安装与启用

安装命令来自官方 README。两条路径都装完刷新 DSH 页面(桌面端 Ctrl+R)。

推荐用 GitHub Release 包,不需要 clone。下载最新 Release 的 dsh-conversation-links-<version>.tgz,解压得到 package/ 目录,然后:

plugin_manager action=install_bundle target=<解压出的 package 目录绝对路径>

也可以从 npm 安装。DSH 的 install_bundle 需要绝对目录路径,所以装完 npm 包后要指向它实际落盘的位置:

plugin_manager action=install_bundle target=<node_modules/dsh-conversation-links 的绝对路径>

卸载:

plugin_manager action=set_bundle target=dsh-conversation-links enabled=false

注意 install_bundle 的 target 是展开后的目录绝对路径,不是包名,也不是 GitHub 仓库路径。

典型用法

场景一,跨任务引用结论。你在对话 A 里跑完一轮排查,得到一段结论。在新对话 B 的输入框输入 @,从「对话」分组选中 A:

  • 输入框里出现一个对话 chip,不是原文;
  • 发送后,该对话的只读快照作为独立 user 消息出现在本轮消息里,标记为 ## Referenced sessions。

场景二,整段对话转场。想把对话 A 整体作为上下文带到对话 B,按住侧栏里 A 的条目,拖到 B 的输入框上,看到虚线高亮后松手,引用 chip 即插入。

场景三,只取部分消息。不想整段引用,只想带几条关键消息:点输入框左侧的「对话引用」按钮打开面板,左栏选来源对话,右栏勾选需要的若干条消息,底部「插入到」选目标对话,点「插入」。目标为当前对话时,引用文本直接出现在输入框并自动聚焦;目标为其他对话时,文本进入该对话的草稿,打开该对话时已在输入框里。

适用场景与注意

适合经常在 DSH 里做多轮、多对话工作的人:长任务拆成多个对话后,需要把前一轮的结论、报错或决策带到新对话,比手工复制粘贴更可控,消息边界和来源都保留。

使用前看三点。

1、插件以当前 DSH 进程的权限运行,install_bundle 执行的是插件 bundle 的内容。安装前应打开仓库确认源码与许可证(本插件是 MIT),确认后再装。

2、引用是文本快照,不是活链接。目标对话后续发生变化不会回流到已插入的内容。

3、拖拽依赖浏览器原生 HTML5 DnD,触屏设备不生效,触屏请用两个按钮入口。目标是其他对话时,内容进入的是该对话的持久化草稿,不是实时编辑器,打开该对话即可看到,按需再发送。

插件的宿主侧实现 lib/index.js 是空实现(apply() {}),全部逻辑在客户端 lib/client.js。README 也列了它依赖的 DSH 内部接口(均为公开的客户端服务 / slot):conversation.input.shell(id)、shell.actions.captureInsertion/insertText/setDraft、sessions.retain/list、inputTriggers.registerSource、slots.inject/register、uiSession.current。升级 DSH 后如失效,可据此提 issue。

README 记录的验证状态供参考:「@ 引用」与「按钮 → 面板 → 勾选 → 插入到当前对话」已在运行中的 DSH 桌面窗口实测通过;「插入到其他对话」的草稿写入路径用离线 harness 跑通;「拖拽」的桥接逻辑用离线 harness 覆盖了 5 种场景,但合成鼠标事件无法在 Chromium/Electron 里启动真正的 HTML5 拖拽会话,README 注明这一条没能在界面上用脚本复现,需要用真实鼠标拖一次确认。

插件目录页在社区站点 SkillHub(独立站点,与 DeepSeek / 幻方无官方从属关系):

  • 目录页:https://www.skillhub.cn/plugins/Penguin-SAMA/dsh-conversation-links
  • GitHub:https://github.com/Penguin-SAMA/dsh-conversation-links

它做的事情很窄:给 DSH 补上跨对话引用这条链路。如果你的多对话工作流里缺的正是这一环,值得试;如果只是偶尔引用,手工复制也够用。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜