feat(dsh): adapt to DSH 0.1.5 via the official SDK runtime; add QQ commands and bot interop - #4
Open
RickyidRickyid wants to merge 1 commit into
Conversation
…mmands and bot interop DSH 0.1.5-rc.1 replaced the host-apiproxy HTTP/WS transport this bridge was built on: /api gained a browser-session auth fence, the dot-named RPC endpoints are gone, and the shipped 0.1.1-rc.2 apiproxy cannot even be loaded against 0.1.5 (it imports ApiRemoteSessionNotFound, which no longer exists). This moves the bridge onto the official SDK surface instead. DSH transport - new src/dsh-sdk-client.js: spawns `dsh --profile sdk` as a child process and speaks the documented newline-delimited JSON-RPC protocol over stdio (initialize / session/prompt / shutdown + session.event notifications) - an adapter reshapes that transport back into the api.* surface bridge.js already used, so only two lines changed outside the adapter - the SDK runtime cannot resume an existing session, and reusing an id already present in DSH's shared session store fails with `session "..." already exists`; the bridge now drops stale mappings on boot and allocates fresh run-scoped ids - adapter return shapes are pinned by scripts/test-adapter-contract.mjs (a silent shape mismatch is what broke the first attempt) - config: dsh.provider/model -> deepseek-official/deepseek-flash (the sdk profile only mounts built-in adapters), plus dsh.sdkProfile - the SDK profile needs ~/.dsh/profiles/sdk/cordis.patch.yml with agent-presets default=qq-chat-v2 and the three qq MCP servers QQ commands (answered locally, no model tokens) - new src/qq-commands.js + a router in bridge.js: /指令 /状态 /ping /机器人 /我是谁 for everyone; /潜水 /唤醒 /暂停 /继续 /重置 /模型 /角色 /静默 /活跃 /调机器人 for the owner - unknown "/xxx" no longer gets a blanket "admin only" reply: the owner's is forwarded to DSH, everyone else's continues as ordinary chat - rate limiting is per conversation+sender so one person cannot starve others Bot interop - new src/bot-registry.js: SnowLuma returns is_robot in the group member list (message events carry no bot flag), so the bridge caches a per-group robot roster (state/bots.json) with a nickname heuristic as fallback - other bots' messages are tagged isBot and marked in the sender label; the wake prompt lists the group's robots - qq_list_group_bots / qq_call_bot let the agent invoke another bot's commands Quote replies - qq_reply and qq_send_group_message take an optional atUserId - qq_send_burst now accepts replyToMessageId + atUserId (first message only) - responses carry the resolved quoted sender Tests: 16 command-parser assertions, 13 bot-registry assertions, and a 23-check end-to-end suite that drives a real bridge against a fake OneBot gateway.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
适配 DSH 0.1.5:改走官方 SDK stdio 运行时,并补上 QQ 指令系统 / 机器人互认 / 引用回复增强。
关联 #3 —— 那条 issue 描述的正是这个问题(401 BrowserAuth、
host.describe等端点 404、连接 DSH 事件流…每 3 秒重试)。issue 里给出的斜杠式端点协议是准确的,本 PR 走的是另一条并行路线(官方 SDK),原因见下。为什么不用 /api 斜杠式端点
session/list、session/create(支持 agentPreset)、session/prompt、session/selectModel确实可用,控制面能力更全。events.mux/events.host已不存在,实时事件需要session/page轮询或session/follow流载体;另外 web 端/api的 BrowserAuth 需要注入浏览器会话 cookie。dsh --profile sdk,stdio 上的换行分隔 JSON-RPC)没有 HTTP、cookie、WS,事件流是干净的原生通知,所以先走它把服务恢复起来。斜杠式端点更适合作为后续方案,因为它能拿回审批回传与 per-session 换模型。改动
DSH 传输
src/dsh-sdk-client.js:以子进程方式拉起dsh --profile sdk,按官方协议通信(initialize/session/prompt/shutdown+session.event等通知)。api.*形状,因此适配器之外只改了 2 行。session "..." already exists(实测与 cwd 无关,全新空 cwd 一样报)。现在启动时丢弃陈旧映射,并使用带随机 runId 的全新 id。scripts/test-adapter-contract.mjs钉住适配器返回形状——第一次尝试正是因为形状静默不匹配(value.sessionId拿到 undefined)而失败。dsh.provider/model改为deepseek-official/deepseek-flash(sdk profile 只挂内置适配器),新增dsh.sdkProfile。~/.dsh/profiles/sdk/cordis.patch.yml里把agent-presets.default设为qq-chat-v2并挂三个 qq MCP server(README 有说明)。QQ 指令(本地应答,不消耗模型 token)
src/qq-commands.js+ bridge.js 里的路由:/指令 /状态 /ping /机器人 /我是谁所有人可用;/潜水 /唤醒 /暂停 /继续 /重置 /模型 /角色 /静默 /活跃 /调机器人仅管理员。/xxx不再统一回"仅管理员可用":管理员的原样转给 DSH,其他人的当普通聊天继续走 AI。机器人互认
src/bot-registry.js:消息事件里没有机器人标识,但 SnowLuma 的群成员列表带is_robot,据此缓存每群机器人名册(state/bots.json),网关不支持时退化为昵称启发式。isBot、发送者名字也会标出;唤醒提示里会列出本群机器人。qq_list_group_bots/qq_call_bot,可让 agent 以你的身份调用别的机器人的指令。引用回复
qq_reply/qq_send_group_message支持可选atUserId。qq_send_burst支持replyToMessageId+atUserId(只作用于第一条)。其他
src/sticker-lib.js补一条收藏表情的行为约束(说过"我收下了"就必须真的调用qq_collect_sticker)。测试
scripts/test-qq-commands.mjs:16 项(指令解析/权限/帮助渲染/别名冲突)scripts/test-bot-registry.mjs:13 项(权威 is_robot / 启发式兜底 / 手工名单 / 缓存 / 持久化)scripts/test-adapter-contract.mjs:适配器返回形状契约scripts/test-e2e-qq-commands.mjs:23 项,用假 OneBot 网关驱动真实 bridge 进程(需 3001/3002 空闲;跑完自动还原state/)已知取舍
sessions.selectModel也无法真正切换(provider/model 是每进程一次)。这两点是斜杠式端点方案的优势所在。