dsh-plugin
DayuanJiang/next-ai-draw-iodsh 的 draw.io 绘图插件:通过 next-ai-drawio MCP 服务器作图,点回复里的链接在右侧栏打开实时预览,可以手动修改图,AI 的每次修改都是可以恢复的版本。需 Node.js 18+,首次使用由 npx 下载 MCP 服务器。
让 DSH agent 提问而不阻塞回合:ask_interactive_question 工具立刻返回待答批次号,答案稍后以普通用户消息送回会话,待答批次显示在浏览器内的待答面板,可选系统通知。
给 DSH Agent 用的"提问桥":Agent 可以在回合中间向人提问,拿到一个批次号后立刻返回;人稍后在原生问题卡片或右下角的待答面板里回答;答案以一条普通的 user/message 回到会话里,Agent 接着干。
它解决的问题很具体:DSH 原生 ask_user_question 是阻塞的——工具不返回,回合就停在那儿,人不在电脑前就等于卡死。这个插件把"提问"和"等待"拆开:
ask_interactive_question 立即返回 { status: "pending", batchId },并明确告诉模型:pending 不是答案、不是授权;agent.steer() 送进会话,只有日志里真的出现那条 user/message 才算 delivered;目标基线是 DSH Desktop 0.2.0-rc.2(宿主 tag dsh-v0.2.0-rc.2)。最短路径:
dsh-question-bridge.tgz,放进 ~/.dsh/plugins/packages/;~/.dsh/profiles/desktop/package.json 的 dependencies 和 dsh.profile.bundles 里各加一条 dsh-question-bridge;pnpm install,然后完全退出并重启 DSH。细节、自检和排错见 docs/installation.md,兼容性与刻意的取舍见 docs/compatibility.md。
装上之后,Agent 会在需要人做决定的地方调用:
{
"questions": [
{
"question": "通知走哪条链路?",
"header": "通知",
"detail": "两条都能离线工作,区别在多窗口时谁来弹。",
"options": [
{ "label": "WebSocket 推送", "recommended": true },
{ "label": "两秒轮询" }
]
}
]
}
工具返回 pending 后回合继续。人回答之后,会话里多一条这样的用户消息:
{
"kind": "answer_to_question_bridge",
"batchId": "…",
"revision": 2,
"questions": [ … ],
"answers": [{ "questionId": "…:q1", "choiceIds": ["…:q1:c1"], "skipped": false }]
}
模型只需认这个 kind;问题文本、推荐项、自动生成的选项都不是用户的决定。
另外两个入口:
AskUserQuestionItem 调 userQuestions.ask(),但不传 wait.callId,所以卡片只是渲染器,答案由插件自己收。classifier: "model" 才会在规则没命中时调用模型判定,且有每小时 30 次的额度。放在 profile 的插件配置里(字段都有默认值):
| 字段 | 默认 | 说明 |
|---|---|---|
enabled | true | 总开关 |
detectPlainText | true | 是否在回合结束时识别普通文本里的提问 |
classifier | "off" | "model" 时才调用模型补判 |
classifierTimeoutMs | 12000 | 单次判定超时 |
maxClassifierCallsPerTurn | 1 | 每个回合最多判定一次 |
maxClassifierCallsPerSessionPerHour | 30 | 额度在发起前预占,失败也计数 |
maxInputChars | 6000 | 送进判定的文本上限 |
maxOpenBatchesPerSession | 5 | 同会话同时开着的批次数上限 |
notifications | true | 是否允许系统通知入口 |
notifyOnlyWhenHidden | true | 页面可见时不弹通知,只显示卡片 |
lib/index.js 宿主端:工具、presenter、批次存储、投递、两条 HTTP 路由、提示词
lib/client.js 浏览器端:shell.overlay 里的待答面板、轮询、系统通知
cordis.patch.yml 把插件插进 DSH 组合
docs/ 安装、兼容性、验收
tests/ 宿主端纯函数的单元测试(node --test)
状态文件在 ~/.dsh/question-bridge/state/<sessionId>.json,一会话一个文件,原子写。没有待答问题时删掉整个目录是安全的。
window.focus() 不保证把窗口从托盘里拉出来——这是浏览器/Electron 的限制,不是插件能补的。npm test,15 项);classifier: "model" 那条模型判定路径没有在本机真实调用过模型,默认也是关的。验收清单见 docs/acceptance.md。A non-blocking way for DSH agents to ask the human a question. The ask_interactive_question tool returns { status: "pending", batchId } immediately; the answer comes back later as an ordinary user/message whose payload is {"kind":"answer_to_question_bridge", ...}. Pending is never treated as approval: closing the card, a notification, or a timeout never marks a question answered.
Batch state lives in $DSH_HOME/question-bridge/state/<sessionId>.json, written atomically. Delivery goes through agent.steer(), and a batch is only delivered once that user message is actually in the session log.
Install: grab dsh-question-bridge.tgz from Releases, add it to your profile's dependencies and dsh.profile.bundles, run pnpm install, restart DSH. Requires DSH Desktop 0.2.0-rc.2.
MIT,见 LICENSE。