dsh-suggest-actions(建议按钮)
给 DeepSeek Harness 的每条回复末尾加一排可点的下一步建议。点一下,那句话就直接作为你的消息发出去——不用自己打。
它解决的是"我读完了,接下来想让它干 A 还是 B"这件事:与其自己组织语言,不如直接点。
和"输入框补全"不是一回事
生态里已经有几个"下一句建议"插件(dsh-suggest-prompt、dsh-prompt-for-me、dsh-suggest-ghost、dsh-input-assist),它们都是输入框里的 ghost text:靠另跑一次模型调用去猜你要说什么,给一条,按 Tab 采纳,然后还要自己按回车。
这个插件换了个思路:
| 输入框补全类 | 本插件 | |
|---|---|---|
| 位置 | 输入框内 | 回复下方(轮次尾部) |
| 条数 | 1 条 | 默认最多 5 条(先露 3 条,其余点「还有 N 条」展开) |
| 内容来源 | 插件猜你想说什么 | 模型按上下文主动给——"重启 DSH 让按钮生效"这种具体动作,补全类猜不出来 |
| 额外开销 | 要多跑一次模型调用(另起一次请求去猜) | 不额外调用——建议由主模型收尾时顺手给出,这一轮正常结束 |
| 采纳 | Tab,再自己按回车 | 点一下就发出 |
| 不想要它 | 得忽略或按 Esc | 不看就行,它不占输入框 |
安装
dsh plugin --profile desktop add dsh-suggest-actions
装完重启 DSH 并刷新一次页面——host 只在启动时读插件清单,客户端代码也要重新加载。这两步缺一不可(踩过)。
它怎么工作
- Host 侧:注册一个
suggest_actions工具。它不阻塞、立即返回——模型在收尾时调用一次,参数里带 2-5 条建议,这一轮正常结束。 - 客户端侧画两处:
tool.call.toolview挂一个静默采集器:渲染时把建议记进插件内存,不画任何东西;conversation.chat.turnTail(轮次尾部)挂展示器:读内存、画按钮。
- 为什么放轮次尾部:DSH 的"过程组折叠"会把思考与工具调用收成一行,画在工具卡片里的东西默认看不见;轮次尾部在折叠范围之外,所以过程收起来按钮照样露着(这条是读了官方源码才定的,见下)。
- 点按钮走的是
conversation.input.shell(sessionId).actions:写进会话输入框 → 提交。和用户自己敲键盘回车是同一条路。
建议的「立场」和「推荐」
这一轮加了两样东西:一个管"几条建议别是同一个角度",一个管"哪条最该先做"。
立场:每条建议背后都要标一个立场,五档——先验证(更小的一步,先确认再往下)、常规推进(顺这条路的正常下一步)、更用力(还是这条路,但更快、更敢冒险)、换一条路(当前做法不走了)、可以不做(这事本身不必做)。同一轮里一个立场只能出现一次,重复的直接丢掉,空出的位置留给别的角度——所以"三条其实是一回事"这种列表到不了你面前。最多五条(五档立场各一条);只想到两条时就给两条,不硬凑。
立场不会显示在按钮上,它是给模型定的格式约束。为什么不在提示里嘱咐一句"请给不同角度的建议"就算了:嘱咐是可以不听的,格式约束绕不过去。
推荐:哪条最该先做,由模型单独标出来,跟它排在第几位无关——标了的那条会被自动提到第一位,旁边挂一个「推荐」小标签。它的底色和别的按钮一样,只有鼠标停在上面时才变深一点。反过来,「可以不做」那条不管给在第几位,都会被压到最后;其余几条保持模型给的顺序。几条确实差不多时,也可以一个都不标。
把鼠标停在按钮上(键盘操作是聚焦到它),按钮会就地展开,显示点下去真正会发出去的那句话;移开就收回去。这一步是为了让"看到的"和"发出去的"对得上——按钮上是摘要,真正发出去的那句常常更长。这段全文长在按钮外面,所以展开之后点它不会误发,想选中文字复制随便点。
几条按钮一样宽:宽度按最长的那条标签定,不按各自内容伸缩——箭头排成一列好扫读,指令写得长也不会把按钮撑开。
多于三条时:单轮最多收 5 条(默认值,可配),界面上默认只露前三条,其余收在下面一行"还有 N 条"里,点开就地铺开、展开后照样能点。展开状态不记忆——翻回去再回来,它又是收起的。
界面上的几个字(「推荐」「还有 N 条」「收起」)跟着界面语言走:中文界面显示中文,其它语言显示英文。
不带立场的建议照常显示(向后兼容)。
「开新会话」按钮
会话长到该断的时候,与其自己复制结论、手动新建会话、再粘贴过去,不如给一条带 opensNewSession: true 的建议:点一下,新建会话(落在同一个工作目录)→ 切过去 → 把这段文本放进新会话的输入框。
- 只填草稿,不自动发送。自动发送会立刻起一轮模型调用,等于替用户花钱;填进输入框,用户还能补一句再回车。
- 一个会话只保留一条这类建议,给多了也只会剩第一条。
- 按钮上带一个「新会话」小标签,和普通建议区分开。
- 失败会在按钮下方说明原因(会话服务没起来、切不到前台、输入框一直没准备好),不会静默。
和官方「派生会话」(fork)不是一回事:fork 复制的是整段历史前缀,新会话的上下文和原来一样长,省不下 token;这条带过去的只有你写的那段文字。要接着原样跑就用 fork,要省 token 就用它。
已知限制
- 需要 DSH 0.1.7 这一线(用到了
conversation.chat.turnTail、conversation.input.shell、tool.call.toolview)。 - 按钮文字由模型给:太长会显得笨重,建议每条不超过 20 字。
- 点击直接发送,没有二次确认——这是设计意图,不是疏忽。
- 一次点击有约 0.9 秒的防连点。
开发者备注
实现细节、踩过的坑、以及"为什么不用另外三个位置"都在仓库注释里;conversation.chat.turnTail 这个落点是从官方 72 个 slot 扩展点里筛出来的。
许可
MIT
配置
改单轮上限,别写在 profile 的 cordis.patch.yml 里——那份 patch 先于插件的插入行应用,同 id 的行这时还不存在,会被静默忽略(2026-09-26 在另一个插件上实测过)。正确的位置是插件自己的 bundle patch:
- insert:
- id: suggest-actions
name: 'dsh-suggest-actions'
config:
maxActions: 2 # 单轮最多给几条(1–6),超出的丢掉;界面就按这个数显示
不写 config 时用默认值 5(等于立场档数)。改完要重启一次 DSH——配置在启动时读。
2026-09-29 修正:默认值原来是 3,而界面折叠阈值也是 3——两级上限一样,"还有 N 条"永远没东西可展开,模型给出的第四、五个不同动作在 host 侧就被砍了。现在默认 5,折叠那行才真正用得上。
开发
pnpm test # 24 个单测,零外部依赖(node:test)
代码分工:
lib/normalize.js—— 清洗规则全在这里(空白、去重、立场、排序、上限),纯函数、可单测lib/index.js—— 注册工具、读配置;清洗后的名单随工具结果一起交给界面lib/client.js—— 浏览器侧。只管两件事:把 host 交回来的名单记下来、画出来。规则一条都不重复(客户端 bundle 拿不到插件配置,上限只能由 host 给)
边界行为都有测试锁定:非数组、坏 JSON、空白 label、重复 label、重复立场、非法立场、超限条数、maxActions 越界。UI 侧另有:按钮最多 520px 宽、文案最多两行(悬停显示全文)、点击后 0.9 秒防连点、标了"推荐"的那条会高亮。历史轮次偶尔会跟着多显示一份最新建议——这是有意的取舍:宁可偶发重复,也不能让最新一轮没有按钮。
No comments yet. Be the first to write one.