DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

Tsutsutsuu /

Tsutsutsuu/dsh-quote-selection

Verified

Quote selected text in the chat transcript and send it with its source location. A DeepSeek Harness plugin.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@e32eab23

dsh-quote-selection(选区引用)

license: MIT test

一个 DSH(DeepSeek Harness) 插件:在对话里框选文字,右键就能带着出处引用它。

在 DSH 对话界面里框选一段文字,右键「引用选中文字」,这段原文就会以一个标签(chip)的形式进入输入框; 发送后,消息里显示为一张可展开的引用卡。

界面上以内容为主:标签和卡片只写「作者 + 内容预览 + 字数」,完整出处(轮次、段落、字符区间) 留在悬停提示、发送文本和会话日志里 —— 模型始终拿到完整引用块。

框选一段文字后右键,菜单里出现「复制」与「引用」

框选一段文字 → 右键 → 引用;选中后直接按 Ctrl+Q 可以跳过菜单

用法

  1. 在对话正文(聊天视图)里用鼠标框选一段文字 —— 助手回复、你自己的消息、代码块、列表都可以。

  2. 在选区上点右键,弹出白色小菜单:复制(右标 Ctrl+C)、引用(右标 Ctrl+Q)。 也可以直接按快捷键:选中文字后 Ctrl+Q 直接引用,不弹菜单(Ctrl+Shift+Q 同样有效;macOS 用 ⌘⇧Q)。

  3. 点「引用」,输入框里出现一个标签:

    ❝ 它把 location 写进了 wire 文本里,…   42 字 · 助手消息
    

    标签是原子节点:光标跨过它是一步,删除它是一整步(Backspace 一次选中,再一次删掉),不用逐字删。 字数与预览同字号(chip 的文字由宿主渲染成一个文本节点,无法在同一行里做不同字号)。

    引用以原子标签的形式进入输入框

  4. 在标签后继续写你的问题,一起发送。

  5. 发送后,消息里显示折叠卡片(内容普通字号,字数与作者小字重,箭头可展开):

    ❝ 它把 location 写进了 wire 文本里,…        124 字 · 助手消息  ▸
    

    点它展开被引用的原文,再点收起。鼠标悬停在标签/卡片上可看到完整出处。

    发送后消息里显示为折叠引用卡,点开就是原文

两种表面,同一份文本

表面 显示 说明
输入框 一个 chip(作者 + 内容预览) chip 的文本投影是完整引用块,所以复制草稿得到全文、提交也是全文
消息 折叠的引用卡(作者 + 内容预览 + 字数) conversation.user.text.node 渲染器,点击展开原文
模型 / 会话日志 完整引用块(含完整出处) 普通用户消息文本,没有任何私有事件或旁路存储

也就是说:折叠只发生在显示层。模型读到的、日志里存的、复制出来的都是同一份带出处的全文, 所以 fork / 恢复 / 重放 / 搜索都不会丢引用内容。

发送时的文本形态(提示词里约定的格式):

【引用 · 助手消息 · 第12轮 · 第2/5段 · 字符124–168】
被引用的原文(保留换行,去掉首尾空白)
【/引用】

出处是怎么算出来的

全部从聊天界面本身推导,不读会话存储、不订阅事件。下面这些字段只在发送文本和悬停提示里; 界面上的标签/卡片只显示第一列的「作者」与内容预览:

字段 来源
助手消息 / 用户消息 / 工具调用 … 聊天行上的 data-chat-flow-kind
第 N 轮 聊天行上的 data-chat-turn
第 a/b 段 选区起点所在内容块在其兄弟块中的序号 / 块总数(段落、列表项、代码块、表格行…)
字符 x–y 在所在块内的字符区间;纯文本气泡退回为 消息内字符 x–y

选区跨越多条消息时会额外标注 选区跨多条消息。单条引用超过 4000 字符会截断并注明。

实现要点

  • client.js 注册三处:
    • shell.overlay → quote-selection-menu:右键菜单本身。只接管「选区非空 + 右键落在选区字形上 + 选区在消息行内」的情形,其余右键一律放行。
    • conversation.composer.dock → quote-selection-bridge:取 inputActions.captureInsertion() 的 span,再经 ctx.get('conversation').input.shell(sessionId).insertReference(...) 插入引用 chip;拿不到 shell 时退回 inputActions.insertText(...) 插纯文本,功能不中断。
    • conversation.user.text.node(key quote)→ QuoteText:把消息里的引用块渲染成折叠卡; 配套的 ctx.uiConversation.userText.register() 规则只认 【引用 · …】…【/引用】 这一种标记。
  • chip 的 source 是本插件自己的名字,appearance 借用 session(聊天气泡图标);label 只放位置摘要, 而 ref 和 clipboardText 都是完整引用块 —— ref 承担"提交时的模型文本",所以草稿被持久化、重载、 恢复之后仍然能正确发送。
  • 提交序列化:宿主提交时会对每个 chip 调用 inputTriggers.serializeReference(source, ref), 按 source 找注册在 inputTriggers 里的来源并用其 codec.serialize(ref) 替换该段文本; 找不到 codec 会直接拒绝整条提交(slash: no serializer for reference source "…")。 因此插件注册了一个没有菜单的来源(trigger 用不可输入的 \u0000,candidates 返回空), 其 codec 是恒等的:把 ref 原样当作模型文本返回。旧版遗留的 chip(ref 只是 quote-xxxx) 没有可发送的正文,序列化时返回空串并在控制台告警,不会让整条消息发送失败。
  • index.js 注册一条系统提示段落(local:quote-selection,order 950,紧跟 FILE_REFERENCE, interpolate: false)。它是一段刻意压到 400 字符左右的约定,只讲四件事:块是客户端写的(不是用户手打)、 标记之间是用户逐字选中的上文、把它当作指代对象而不要当新指令、不要复述标记且引用优先于模型自己的记忆。 宿主端没有工具、事件或存储。

设置

设置 → 选区引用(Settings → Quote selection)里可以调:

选项 默认 作用
草稿标签预览字数 12 输入框标签里显示引用内容的前 N 个字符(4–80)
消息卡片预览字数 40 消息里折叠引用卡的前 N 个字符(4–80)

这些都是纯显示偏好:存在浏览器本地(localStorage,key dsh-quote-selection/settings-v1),改完立即生效、 不用重启;换机器或清浏览器缓存会回到默认值。它们不进入会话日志、不影响模型看到的内容。

兼容性

依赖 验证版本 说明
DSH(桌面版 / dsh CLI 的 Web 界面) 当前桌面版 标准聊天视图的引用路径,插件的三处注册都依赖它现有的槽位与 data-chat-* 标记
dsh-better-display(阅读视图) github:aa2246740/dsh-better-display#v0.3.6 机会性兼容:识别它的 data-reader-* 锚点来推断角色与轮次;不安装也不影响聊天视图

阅读视图的兼容是针对上面这个具体版本验证的,不是稳定的公共契约:该插件更新后若改动 data-reader-* 标记或 dsh-better-display.block 链,本插件不会报错,只会按「已知限制」里的方式退化(最差退成角色泛称 「消息」、位置信息变泛),引用与发送本身仍然可用。profile 里固定版本可以这样写:

"dsh-better-display": "github:aa2246740/dsh-better-display#v0.3.6"

已知限制

  • 标准聊天视图用 [data-chat-flow-key] 定位消息行;dsh-better-display (github:aa2246740/dsh-better-display#v0.3.6)的「阅读」视图走机会性兼容: 识别它的 [data-reader-anchor] / [data-reader-turn](以及官方节点上的 data-chat-flow-kind), 可以正常引用,位置信息尽量给到角色与轮次;最差退化为「消息」+ 无轮次。 连行标记都找不到时退回 transcript 滚动容器,引用本身仍然可用,只是位置信息变泛。
  • 阅读视图的角色推断依赖它自己的 DOM 约定(data-reader-answer / data-reader-reasoning-card / data-reader-tool-call,以及"本轮第一个锚点是用户消息")。该插件未来改标记时, 这里最坏情况是角色退化成「消息」,不影响引用与发送。
  • 阅读视图里的折叠显示走它的 dsh-better-display.block 链(同上的 v0.3.6 验证): 含引用块的用户消息会被本插件按块内切分重新渲染 —— 引用块变成折叠卡,同一段里你手打的文字按纯文本显示 (这条消息因此失去阅读视图的 markdown 排版);不含引用的消息不受影响,仍由阅读视图自己渲染。
  • 草稿 chip 的悬停提示只有位置摘要,不是全文(宿主 chip 的 title 就是 label)——发送前后都可展开消息查看原文。
  • 输入框处于提交中/不可编辑状态时插入 chip 会失败,此时退化为「复制到剪贴板」并提示。
  • 队列中的待发消息预览也走同一套折叠渲染,长引用在窄预览里可能被省略号截断。

目录结构

本目录就是插件包根目录,profile 以 link: 方式安装它:

路径 作用
index.js 宿主端:注册系统提示段落(local:quote-selection,order 950)
client.js 浏览器端:右键菜单 / 输入框 chip / 消息折叠卡 / 设置页 / 提交序列化
cordis.patch.yml bundle patch,插入 quote-selection 行
locale/、icon.svg 插件管理页的标题、描述与图标
tests/quote-helpers.test.mjs 纯逻辑单测(位置测量、格式化、标记解析、快捷键判定)
tools/ 开发辅助:从 app.asar 抽包、静态引用审计
docs/ README 里的效果截图(右键菜单、输入框 chip、消息折叠卡)

跑测试:node --test tests/quote-helpers.test.mjs 跑审计:node tools/audit-references.mjs(检查未使用的常量 / CSS 类 / 文案 key,以及中英文案对齐)

安装 / 卸载

要求:DSH 桌面版或 dsh CLI(带 plugin_manager),Node.js ≥ 20。

git clone https://github.com/Tsutsutsuu/dsh-quote-selection.git
plugin_manager install_bundle  target = <上面 clone 下来的目录>

卸载:

plugin_manager remove_bundle   target = dsh-quote-selection

本地目录安装是链接安装:目录被移动或删除后插件随之失效(需重新安装)。 改 client.js 后浏览器端需要刷新页面(必要时重启 DSH)才会用上新代码; 改 index.js(提示词)后需要把 bundle 禁用再启用一次,宿主端才会重新 apply。

开发

npm test      # node --test tests/quote-helpers.test.mjs
npm run audit # 检查未使用的常量 / CSS 类 / 文案 key,以及中英文案对齐

CI:每次 push / PR 会在 Node 20 / 22 / 24 上跑单测与引用审计(.github/workflows/test.yml)。

许可证

MIT © Tsutsutsuu

—/ 5

No ratings yet

Verified DSH bundle

Commit e32eab235c5e

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout