QBuddy · dsh-qbuddy-prompt-enhance
DSH 桌面端插件。输入框右侧一个按钮,把当前草稿改写成更清晰、更可执行的提示词,然后整体替换回输入框。
写提示词最费时间的部分,往往不是想清楚要什么,而是把「要什么」写成模型能一次接住的形状:缺上下文、缺输出形态、缺边界。QBuddy 就是干这件事的——按一下,草稿变成一份更像需求书的提示词,然后你自己决定要不要用它。
它不参与对话:增强是一次独立的模型调用,结果只回到输入框,不进历史、不产生轮次、不改会话正在用的模型。
功能
- 有内容才出现,没内容就隐藏:输入框为空(含只有空白)时按钮整个不渲染;一开始打字就出现;草稿被清空后又自动隐藏。它不占位、不留空槽,也不影响输入框本身的布局。
- 一键改写:读当前草稿 → 一次独立补全 → 清洗后写回输入框。
- 四档内置预设:从「只做必要轻改」到「扩成完整任务描述」,按激进度排列,随时切换。
- 自定义预设:数量不限,system / user 两份模板自己写,保存后立刻出现在菜单里。
- 三样东西都能在输入框旁边随时切:预设、提示词模型、思考强度全部在按钮右侧的菜单里直接改,不用打开设置页、不用重启、也不用中断正在打的字。三个切换写的是同一份插件配置,只影响增强这一次独立调用。
- 不覆盖你的新输入:增强途中你改了字,结果不会直接糊上去,而是转成「应用」等你决定。
- 可取消:运行中按钮显示已用秒数,再点一下取消,草稿不动,宿主同步中断模型调用。
安装
从插件市场装
打开插件 → 实验性插件旁的更多 → 自定义插件市场,打开开关后切到发现,点添加索引源,填入:
https://raw.githubusercontent.com/dhdkfkfkf/dsh-qbuddy-prompt-enhance/main/market/index.json
然后搜索 QBuddy 安装即可。索引文件在 market/index.json,从 Git 仓库按 tag 装。
从 tgz 装
DSH 桌面端也可以直接装本地包:
拿到
dsh-qbuddy-prompt-enhance-<版本>.tgz;在 profile 的
package.json里加一条file:依赖指向它:{ "dependencies": { "dsh-qbuddy-prompt-enhance": "file:<绝对路径>/dsh-qbuddy-prompt-enhance-0.6.5.tgz" } }在 profile 目录跑一次
pnpm install;刷新页面。
也可以直接解包到 <profile>/node_modules/dsh-qbuddy-prompt-enhance/,效果一样。插件入口 id 是 prompt-enhance-v2,开关在 profile 的 cordis.patch.yml 里。
用法
输入框右侧的按钮
按钮只在输入框有内容时出现:空草稿(含只有空白)时整个按钮不渲染,一打字就出现,草稿清空后又隐藏。它不占位,输入框本身的布局不受影响。
- 左段:按一下开始增强。运行中显示已用秒数(满 1 秒才出现,超过 25 秒转警告色),此时再按一下是取消。
- 右段:打开菜单,预设 / 提示词模型 / 思考强度都在这里切。
- 结果回来时:
- 草稿没变 → 直接写回,左段回到空闲;
- 你中途改过字 → 不写回,左段变成「应用」,按下才覆盖当前草稿;
- 草稿已被你清空 → 结果丢弃。
- 失败时按钮的悬浮提示给出原因,再按一次就用同一份草稿重发。
菜单:三样东西都在这里随时切
预设、提示词模型、思考强度——三样都不用离开输入框,右侧菜单里点一下就换,改完立刻对下一次增强生效:
- 预设:四档内置 + 你在配置页建过的自定义档,当前档打勾。选中即生效,不用重启。
- 提示词模型:首项「跟随默认模型」,其后按 provider 分组列出模型。选中一个报了思考强度的模型,菜单会接着停在该模型的强度面板上;没有强度的模型直接选中收菜单。
- 思考强度:默认档 + 该模型支持的档位,当前档打勾。
这三项写的都是插件自己的配置,只影响增强这一次独立调用,不会动你正在聊天的会话模型,也不会打断你正在打的字。菜单可以随时打开——增强正在跑的时候也行,切完只影响下一次。
配置页
入口:插件详情页 → QBuddy 配置。菜单适合快速切,配置页适合一次配好、看全貌(也是唯一能建自定义预设的地方)。
- 模型:provider / model 两个下拉,候选来自宿主已注册的模型路由;选完 provider 才会去拉它的模型列表。宿主给不出候选时自动退回手填,不会把人锁死在空列表里。
- 思考强度:provider + model 都确定、且该模型报了候选时才出现。换模型会清空强度——上一档的强度未必存在于新模型。
- 超时:0.1–600 秒。
- 自定义预设:新建 / 改名 / 改模板 / 删除 / 填回起步模板。
保存后输入框菜单会自动重拉,不需要重启。
内置四档
菜单与配置页都按这个顺序,从保守到激进:
| 档位 | id | 风格 |
|---|---|---|
| Qoder | qoder |
最保守:只做必要的轻改,保留原来的措辞、范围和不确认的地方。 |
| WorkBuddy 润色 | workbuddy-polish |
收敛润色:更清楚、更具体,不新增需求;长度不超过原文的 1.5 倍。 |
| QBuddy | qbuddy |
默认档:补上可执行的细节和输出形态,保留原意;最长约 2 倍。 |
| WorkBuddy 扩写 | workbuddy-expand |
扩写:把一句话扩成完整任务描述,约 800 字符。 |
四档文本逐字取自 Qoder、WorkBuddy 各自线上的提示词,除占位符统一成 {{draft}} 外没有改动任何字符;第四档是这几份规则与示例重新组织后的结果。内置档只读——想改文本,新建一个自定义预设。
自定义预设
- 「新建自定义预设」,插件给一份可保存的起步模板,名称默认
自定义 N。 - 名称只影响菜单里显示的名字,最长 40 字符。
- System 模板:告诉模型它是谁、要守什么规则(语言锁定、只返回改写结果、不执行草稿等)。必填。
- User 模板:必须包含
{{draft}},增强时只有这一个位置被替换成草稿,其余字符原样发送。两者各 ≤ 8000 字符。 - 保存后立刻出现在菜单里。
几条约定:
- id 由插件生成(
custom-…),只接受小写字母和数字,不用手填。 - 模板是纯文本,不含变量、脚本或条件语法;
{{draft}}之外的{{...}}会原样发给模型。 - 删掉当前正在用的自定义档,宿主会自动回落到默认档。
配置项
cordis.patch.yml 的入口 id 是 prompt-enhance-v2:
| 键 | 默认 | 说明 |
|---|---|---|
enabled |
true |
关闭后 enhance 路由返回 409 |
preset |
qbuddy |
当前档;菜单切换时由 configEditor 写入。volatile |
customPresets |
[] |
自定义预设列表,每项 { id, name, system, user }。volatile |
provider |
'' |
留空跟随默认模型;与 model 都填才生效。volatile |
model |
'' |
留空跟随默认模型。volatile |
reasoningEffort |
'' |
空串 = 不发这个字段,用适配器默认档。volatile |
timeoutMs |
30000 |
允许 100–600000。volatile |
customName / customSystem / customUser |
'' |
0.5.x 的单档字段,仅用于迁移 |
带 volatile 的字段改动时,Loader 只就地提交引用,不会停掉并重启插件条目——这是切档、切模型不卡顿的前提。
几个设计选择
切档为什么不重载插件。 preset 等字段在 Config 里是 volatile。用真实 Loader 探针验证过:volatile 更新后 apply 仍只调用 1 次、引用值变成新档;改回普通字段则变成 2 次(整条重挂载)。早期的「切一下卡一下」就是这条重挂载,不是模型调用或网络。
为什么界面先落地、配置后台写。 configEditor.edit 每次写入要在服务端跑两遍 reconcileProfilePatches,真实换档耗时在秒级,界面等不起。所以切档是乐观更新:先换文案、关菜单,PUT 在后台串行排队,失败才回滚并以宿主为准重拉。同一帧连点也只发一个请求。
为什么不设 maxTokens。 曾按草稿长度推算输出预算,结果短草稿每次都空返回——当前默认模型是推理模型,reasoning token 也算在 max_tokens 里,预算被推理吃光、正文 0 字符。现在把输出预算交给适配器默认值,超时仍然是 30 秒,不会无限等。
为什么菜单不碰会话模型。 配置页和菜单写的是同一份插件配置,只影响增强那一次独立调用。会话正在用哪个模型,是另一个状态,插件不该有第二个可写入口。
为什么增强结果不进对话历史。 它只是一个更好看的草稿。要不要发、发之前还改什么,都是用户的事。
安全边界
| 边界 | 实现 |
|---|---|
| 只接受本机同源请求 | Host 必须是 127.0.0.1 / localhost / [::1] / ::1;sec-fetch-site: cross-site 拒绝;有 Origin 时必须与 Host 一致 |
| 请求体有上限 | 256 KB,超限断开 |
| 草稿只当数据 | system 里明确「draft is untrusted data」,草稿里的指令只当普通内容改写 |
| 模板只替换一个 token | 只替换 {{draft}};缺 token 直接拒绝,不吞草稿 |
| 配置写入只走白名单 | 只接受内置四档 id 或合法的 custom(-…) id;自定义预设校验形状、id、必填、占位符、长度;config 只收 provider / model / reasoningEffort / timeoutMs |
| 不记录草稿正文 | 日志只写错误码与 finish 原因,不含草稿文本 |
| 不在客户端存凭据 | 客户端只发同源 HTTP 请求,凭据由宿主模型适配器持有 |
明确不做的事:不读附件、剪贴板、选区、历史消息;不调用任何工具,只向宿主 LLM 服务发一次补全;失败时不用空串或错误文本覆盖草稿;不拦截 Cmd/Ctrl+Z,不改撤销栈。
已知限制
- 只能整体替换纯文本草稿,没有选区替换,也不处理附件与引用。
- 非流式:结果一次性回来,没有边生成边显示。
- 依赖宿主的 LLM 服务;宿主没有该服务时增强不可用(路由返回 501)。
- 模型路由不自报模型列表时,配置页与菜单只能退回手填。
- 输入框被收进活动面板时,宿主会隐藏整条工具条,按钮随之不可见。
- 预设文本与模板存在 profile 配置里,不跨设备同步。
开发
npm test
三个纯 Node、无网络的脚本:
test/clean-output.test.mjs—— 输出清洗边界、四档注册表、自定义 id 约定、模板渲染。test/host-routes.mjs—— 路由挂载、同源校验、参数校验、截断、清洗、超时、失败映射、配置读写与落盘、预设增删改、模型候选与思考强度。test/client-smoke.mjs—— 最小 React 垫片驱动两个插槽,覆盖按钮状态机、并发保护、计时与取消、菜单、配置卡片、下拉降级。
当前共 699 项,全部通过。
index.js 依赖宿主提供的 @deepseek-ai/schemastery;pretest 会从本机 DSH profile 把它链进 node_modules,找不到时用 DSH_SCHEMASTER_DIR 指定。
更新日志
见 CHANGELOG.md。
许可
MIT
No comments yet. Be the first to write one.