Skip to main content
H

dsh-suggest-actions

hijoelee/dsh-suggest-actions

在每条回复下方给出可点的下一步建议,点一下就作为你的消息发出去。Clickable next-step suggestions under every reply; one click sends that sentence as your message.

Install

dsh plugin --profile web add github:hijoelee/dsh-suggest-actions

README

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 条,直接铺开(上限调更高时多出的会自动折叠)
内容来源插件猜你想说什么模型按上下文主动给——"重启 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 条),界面上一次全显示。折叠那段逻辑还留着,但阈值(5)与上限相等,正常情况下不会触发;把上限配到 6 时,多出来的那条会自动收进下面一行"还有 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 秒防连点、标了"推荐"的那条会高亮。历史轮次偶尔会跟着多显示一份最新建议——这是有意的取舍:宁可偶发重复,也不能让最新一轮没有按钮。

Related plugins