前言¶
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 补上跨对话引用这条链路。如果你的多对话工作流里缺的正是这一环,值得试;如果只是偶尔引用,手工复制也够用。