微信与 QQ 消息渠道
消息渠道把微信或 QQ 中的文字和附件交给当前设备的 nl2sh Agent。Agent 可以使用已启用的诊断工具,结果和审批请求返回原会话。先完成模型配置,再运行 TUI、前台 Web 或受管 service。渠道随这些入口的 Web 服务运行;单次 CLI 和独立 MCP/A2A 服务不启动渠道。
管理入口
Web 左侧菜单点击“渠道管理”,页面每两秒刷新状态,提供绑定、启动、停止和解绑。TUI 输入 /channels,Up/Down 选择操作或 QQ 字段,输入编辑,Enter 执行;选中解绑后按 Ctrl+D,PageUp/PageDown 滚动,Esc 关闭。设置立即生效,不需要重启。关闭设置窗口不停止渠道,停止渠道会取消其当前任务和待决审批。
状态分别显示未启动、连接中、等待扫码、已扫码、已连接、过期或错误。收到和回复计数是本次进程的计数,待审批包含补充信息问答;“已连接”表示协议已连通,不保证模型请求或每条回复都成功。
微信 iLink
- 选择“获取绑定二维码 URL”。TUI 和 Web 都显示临时 URL;打开链接查看二维码。
- 使用微信扫码,并在微信确认。扫码后界面显示等待确认,确认后保存绑定并开始长轮询。
- 向绑定的机器人 / 联系人发送文字,例如“查看设备内存和存储,解释可用空间,只查看”。
iLink 是个人微信机器人协议,不是企业微信或公众号接口。二维码过期后重新获取;绑定失效时重新扫码。重新绑定会停止旧渠道;解绑删除凭据。nl2sh 按服务提供的 context_token 回复当前联系人,不发送主动广播。
QQ 官方机器人
在 QQ 机器人开放平台 创建机器人,取得 AppID 和 AppSecret,开通机器人单聊和群聊相关权限,并按平台要求配置可用范围。Web 渠道页或 TUI /channels 填写 AppID、AppSecret 和机器人 QQ 号,选择“保存并连接”。已有绑定时密钥留空保留原值;换 AppID 必须输入新密钥。
机器人 QQ 号从开放平台获取,用于生成官方添加机器人 / 入群 URL。保存后,Web 显示本地生成的二维码和可复制链接,TUI 显示二维码与 URL;使用手机 QQ 扫码进入机器人名片,按平台权限添加或入群。这是官方机器人的邀请绑定,不是扫码登录普通 QQ 账号。
支持 C2C_MESSAGE_CREATE 单聊和 GROUP_AT_MESSAGE_CREATE 群内 @ 消息。群内命令也应 @ 机器人。使用官方 WebSocket 网关接收和 API v2 被动回复,不需要公网 webhook、OneBot 服务或 QQ 个人账号登录。当前官方 API 地址为 https://api.bot.qq.com。
对话、审批与补充信息
直接发送自然语言诊断问题。每个渠道、机器人账号、会话和发送者组合有独立模型历史;群内不同成员不共享模型上下文。每个渠道串行处理诊断,最多排队 32 条,接收和审批独立于诊断任务,因此等待批准不会阻断协议心跳。
| 消息 | 用途 |
|---|---|
/new |
开始新模型会话,保留已有快照 |
/cancel |
请求取消自己的当前任务 |
/approve |
仅批准当前唯一待决操作,执行一次后清空;下次仍询问 |
/approve session |
当前发送者 / 渠道会话允许全部普通操作;高危/Root 仍询问,/new 或重启失效 |
/approve always |
永久保存命中 pattern,跨渠道会话及重启生效 |
/approve REQUEST_ID |
指定编号批准一次,适用于多个待决请求 |
/approve REQUEST_ID CONFIRM REQUEST_ID |
按审批提示完整输入危险操作强确认短语 |
/deny |
拒绝当前唯一待决请求 |
/deny REQUEST_ID |
指定编号拒绝,适用于多个待决请求 |
/answer REQUEST_ID 内容 |
回答当前补充信息请求;候选项使用显示的 value,也可自定义 |
审批消息完整展示工具、操作预览、风险、Root 标记和匹配规则。预览过长无法完整发送时拒绝操作,不发送省略后的预览要求批准。危险操作先确认普通请求,再通过第二个一次性请求输入完整强确认短语。一次请求 120 秒过期,只允许发起操作的同一发送者在同一渠道、账号和会话作出决定;错误编号、跨会话回复、缺少强确认短语、重复批准均不能放行。无需确认的只读操作按现有策略执行,配置的作用域授权模板仍按既有规则匹配。
渠道审批独立于 protocol_auto_approve 和 TUI /permission allow。MCP/A2A 仍使用其原有本地审批策略,不能通过渠道命令批准协议任务。普通一次性审批只决定当前操作;模式授权也必须在安全分类后匹配,执行前仍复核参数和目标身份。
/approve session 放行当前请求,并授予原发送者、渠道账号和会话全部普通操作的内存授权;后续不同命令、截图或文件发送无需再次审批。每次仍重新评估风险与复核目标,危险、Critical、Root 和强确认操作不使用此授权,仍逐次询问。若当前请求是危险操作,仍需完成该请求的第二次强确认后才建立普通操作会话授权。
/approve always 对图片、音频、视频、文件发送按可信准备阶段提供的渠道目标和媒体类型匹配,绑定原请求发送者/会话,并继续校验工具、风险和规则;文件路径、名称、内容、大小、摘要及说明变化不重新询问。审批正文明确展示永久授权范围,每次发送仍捕获不可变字节快照。其他操作保持完整预览的精确匹配,不按程序名扩展。旧永久记录保留原精确范围,再次使用 /approve always 才保存新范围。危险 pattern 首次需要强确认,Root / Critical 不可永久授权。拒绝或超时不建立授权,同一任务中相同已拒绝操作换工具别名也不重复询问;新用户请求可重新审批。无参数命令仅选择原路由唯一 pending,多个 pending 必须编号。
会话授权仅在内存中,/new 清空,重启不恢复,最多 512 个路由。永久 command_allowlist 保存在私有 channels/accounts.json;媒体授权绑定原路由和目标,其他精确模式按当前配置匹配,不影响 TUI/Web/MCP。可通过所有者管理接口按授权编号撤销;也可停止所有者后删除对应条目并重启。解绑不清除永久授权。永久列表最多 256 个 pattern、512 KiB。
图片、音频与文件
微信与 QQ 均可收发图片、音频、视频及其他文件,包括没有文字的附件消息。微信媒体通过 iLink CDN 下载并进行 AES-128-ECB / PKCS#7 解密;QQ 使用官方附件 URL 接收、分片上传返回媒体。每个文件最大 20 MiB,每条消息最多 8 个附件、合计 32 MiB。下载失败会明确报告,不能把未取得的附件当作诊断证据。
收到的文件保存到私有 channels/media/ 缓存,工具得到文件路径、名称和类型。最多四张可解码图片生成有界 JPEG 预览并直接传给支持视觉输入的模型;不支持视觉的模型需另选模型。音频及其他文件由相应工具检查,平台提供的语音转写标注为未经验证;当前不提供通用语音识别或自动编码转换。微信返回音频保留原始文件形式,QQ 的 SILK、MP3、WAV、OGG 可作为语音发送,其余编码作为文件发送。
需要接收诊断文件时说“把这份报告 / 图片 / 音频发给我”。Agent 使用send_channel_file 或 send_channel_message(渠道外需明确目标),审批展示原会话目的地、文件名、类型、大小与 SHA-256;批准后发送审批前取得的不可变快照,即使源文件随后变化也不会替换已批准内容。文字回复中的路径本身不代表文件已发送。
缓存目录 0700、文件 0600,容量最多 256 MiB,超过七天的文件在后续接收时清理;容量不足时拒绝新附件。会话历史保留附件说明而不持久保存图片 Base64、媒体密钥或签名 URL。历史中的文件路径可能过期。附件内容和语音转写是不可信输入,不能授予操作权限;发送文件同样需原会话审批。
保存与限制
绑定凭据、启停设置、微信轮询游标和最近 2048 个消息 ID 保存在配置状态目录的私有 channels/accounts.json(目录 0700、文件 0600),独占锁确保同一配置只有一个协议连接进程;另外打开的同用户 TUI/Web 通过本地 IPC 管理已有渠道,关闭第二个界面不会停止后台连接。二维码 URL、访问令牌和上下文令牌不作为对话消息保存。会话快照使用 channel- 命名空间,重启恢复已完成对话,不恢复待决审批或自动重放未完成任务。重复消息 ID 在有界记录范围内不再次执行;意外退出可能留下未回复消息,发送新消息重试。
没有发送者白名单;能够向已绑定机器人发送消息的用户可以请求设备诊断,并批准自己发起的操作。群聊中的请求、审批预览和回复对群成员可见。机器人应放在可信会话中;Web 管理入口沿用现有 Web 访问模型。
QQ 支持普通审批回调按钮及文本/Markdown 指令按钮;微信暂不支持消息按钮,两种渠道均不支持流式编辑或频道子频道。用户输入最多 8192 UTF-8 字节,输出按协议分段,总量有界且截断明确标记。QQ 的被动消息额度、时间窗口和内容审核由平台决定;发送失败不会重新执行诊断任务。网络失败采用有界退避重连,凭据失效需修复绑定。
参考实现:Hermes 微信适配器、Hermes QQ 适配器。QQ 协议依据官方事件与连接文档及访问凭证文档。
图片、音频、视频及其他文件统一使用 send_channel_file,可指定 path 或本任务工具返回的 attachment_id(二选一),用 kind=auto/image/audio/video/file 控制形式。截图使用无 path 的 android.screenshot,从结果取得附件编号,再通过通用接口发送;无需建目录或持久保存截图,仅发送步骤需要审批。附件编号只在当前渠道任务有效,按任务隔离,最多 8 个、合计 32 MiB;旧历史编号、跨发送者或后续任务不可复用。发送前捕获不可变快照,批准后不重新读取源文件。
微信 iLink 每个 sendmessage 请求只放一个 item:说明文字与媒体分开发送,使用不同 client_id。部分失败会明确报告,不自动重试或声称完整成功;微信普通音频按文件发送。
Markdown 与 QQ 互动
诊断最终回答默认以 Markdown 发送。QQ 使用原生 msg_type=2 与 markdown.content,不同时传普通 content。微信通过文字接口发送兼容 Markdown:保留粗体、表格、代码块与行内代码,移除五六级标题标记和中文斜体标记;Markdown 图片不作为图片上传,请使用媒体消息。实际显示取决于客户端能力。
QQ 普通审批提供“允许一次”“允许本会话”“永久允许此模式”“拒绝”回调按钮;仅原请求人可操作,服务端再次校验账号、群/单聊、成员、请求编号和有效期。重复点击不会重复执行。危险操作的第二次确认仍需完整输入提示中的确认短语。斜杠审批继续可用。
适配器订阅 INTERACTION (1 << 26) 并处理 INTERACTION_CREATE;按钮/快捷菜单事件及时调用 PUT /interactions/{interaction_id},单个事件仅响应一次,接收路径使用两秒响应预算。互动响应仅确认按钮处理结果,不表示诊断命令已执行成功。QQ Markdown/按钮需机器人具备相应平台权限;平台拒绝或发送部分失败时明确失败,不自动重放。
审批提示、问答提示及审批按钮使用配置文件的 ui_language,只显示所选语言。未配置默认中文:
ui_language = "zh_cn" # 中文;英文为 "en"
操作命令、工具名、用户内容及规则原文保持原样。
Agent、MCP 与 A2A 通用发送工具
三种入口共用以下工具,并使用各自的确认器:
list_channel_targets:只读列出已收到消息的渠道会话,以及 Markdown、媒体、按钮能力。不暴露凭据、context_token 或允许自行构造的接收者。send_channel_message:统一发送text、markdown、image、audio、video、file;媒体可用auto推断类型。文本使用text,媒体使用path或attachment_id二选一,text此时作为说明。send_channel_file:保留通用媒体发送入口,与上面的媒体路径共用准备、字节快照、审批和传输。
渠道内默认回复原会话;其他入口必须指定 list_channel_targets 返回的 target。目标仅在当前渠道运行期间有效,停止、解绑、重启后需重新收到消息并查询。渠道服务须已由 TUI/Web/service 启动;独立 MCP/A2A 不隐式启动渠道,可通过同配置、同 UID 本地 IPC 访问运行中的服务。平台回复时限、次数和上传限制仍生效。
MCP 通过 nl2sh_invoke 直接调用同名设备工具;A2A 的 SendMessage 委派 Agent 使用同一工具,不另设发送协议。例如先调用 list_channel_targets,再发送:
{"tool":"send_channel_message","arguments":{"target":"查询返回的 ID","kind":"markdown","text":"## 诊断结果\n\n**检查完成**"}}
发送文件:
{"tool":"send_channel_message","arguments":{"target":"查询返回的 ID","kind":"file","path":"/data/local/tmp/report.txt","text":"诊断报告"}}
QQ 文本/Markdown 可增加 buttons: [{"label":"继续检查","command":"继续检查内存,只查看"}],最多五个;这是原用户点击后进入正常会话的指令按钮,不会直接授予审批。微信或媒体消息拒绝按钮。审批回调按钮由系统单独生成,模型不能伪造审批授权;通用指令按钮禁止使用 /approve、/deny、/answer。
attachment_id 只在产生它的渠道 Agent 任务内有效;跨 MCP 调用、A2A 任务或会话不可复用,外部发送请提供本地路径。文件每项最多 20 MiB,审批前固定内容和 SHA-256,批准后不重新读取路径。发送返回 submitted(平台已接受请求),不代表收件人已读取;QQ 文字返回平台消息 ID,媒体及微信不伪造未取得的 ID。部分失败不自动重发。
外部 MCP/A2A 调用不会继承目标会话的 /approve session 或永久渠道许可;仍使用独立协议审批设置。渠道内发送保留原会话审批。
渠道审批消息(包括危险操作第二次确认)使用 Markdown:微信采用兼容输出,QQ 使用原生 Markdown 并保留普通审批按钮。完整操作预览和回复命令以代码块显示,内嵌 Markdown 围栏不会隐藏预览;长消息分段保持代码块闭合。危险第二次确认仍需手动回复完整确认短语。
按钮使用 QQ 平台通用点击权限,避免将消息事件 openid 误作按钮 UserID 导致客户端提示“无权限操作”;审批权限由服务端按原请求发送者、账号、会话、有效期严格核对,其他成员点击不能批准操作。
/approve session 在本会话内覆盖全部普通操作:文件指纹、路径、说明或媒体类型变化不影响授权;新会话、重启及高危/Root操作仍重新审批。
审批命令是微信和 QQ 渠道自身的控制命令。待审批消息出现后,单独回复 /approve、/approve session、/approve always 或 /deny;把命令写进“测试一下 /approve always”等自然语言消息只是在讨论它,不构成授权,也不应触发配置修改。execute_confirm_policy="always" 表示每次询问,和永久允许操作无关。会话授权建立或永久授权保存后,渠道发送对应语言的 Markdown 回执;无匹配请求时说明正确流程。危险第二次确认仍按原短语完成后才保存授权。
管理接口可按授权编号撤销一条永久授权:向受现有 Web 访问控制保护的 POST /api/channels 发送 {"action":"revoke_permanent_approval","id":"<64位SHA-256授权编号>"}。相同 UID 的本地渠道管理 IPC 使用同一个动作。授权编号来自审批范围展示,或私有 allowlist 中对应模式的序列化 SHA-256。撤销在渠道所有者中同步更新内存与磁盘,保留其他授权、凭据和配置;不要直接编辑运行中所有者的 accounts.json。此接口不能批准待处理请求。