进阶治理阅读约 9 分钟最后核对 2026-09-20

远程连接

Spark Work 远程连接(Telegram / 飞书):连接配置、配对流程、本地 webhook(127.0.0.1:32178)、内置命令(/help /sessions /models 等)、启动项集成。

远程连接让你从手机或另一台设备继续与本地 Spark Work 里的 Agent 对话。当前真实支持 Telegram、飞书、QQ 三个通道:Telegram 走本地长轮询,飞书与 QQ 走官方 WebSocket 长连接,三者都不需要公网地址;同时保留一个本机 HTTP webhook 服务, 用于本地调试与自建网关(微信 Claw 协议类型仍在,但界面没有新建入口)。 所有配置存在 app_settings的remote-connections/data里, 配对、隔离与转发逻辑在 apps/desktop/src/main/services/RemoteConnectionService.ts。

1. 支持的通道

通道必填凭据连接方式搭建入口
telegramTelegrambotToken本机getUpdates长轮询(不需要公网 webhook)https://t.me/BotFather
feishu飞书机器人appId、appSecret@larksuiteoapi/node-sdk官方 WebSocket 长连接https://open.feishu.cn/page/openclaw?form=multiAgent
qqQQ 机器人qqBotAppId、qqBotSecret官方 WebSocket 网关(api.sgroup.qq.com/bots.qq.com)https://q.qq.com/#/app/bot
wechat-claw微信 ClawclawEndpoint、clawAccessToken自建网关协议:本地 webhook 收消息,出站调<endpoint>/send(失败回退 /message)协议与解析器仍在,但新建连接的平台卡片里不提供该通道

可以同时配置并启用多个连接(每个 Telegram 连接是独立的 botToken 与独立轮询); 界面上的平台入口只有三个:AVAILABLE_REMOTE_CHANNELS = ['telegram', 'feishu', 'qq']。

2. 配置模型:字段、默认值与存储位置

存储位置是app_settings的remote-connections分类、key 为 data,值形如 {global, connections}。

global(全局运行设置),括号内是代码里的默认值:

  • enabled(true):总开关,关闭时运行时会整体停止。
  • requirePairing(true):未配对用户的消息不会被处理。
  • allowQrPairing(true):是否允许生成二维码配对负载。
  • pairingTtlMinutes(10):配对码有效期。
  • localWebhookPort(32178):本机 HTTP 服务端口。
  • publicBaseUrl(未设置):需要外部回调时使用的基础地址。

connection(每条连接):

字段说明
id/channel/name/enabled身份与开关;id形如remote-xxx
statusdisabled/draft/pending-pairing/ connected/error(界面文案:已停用 / 草稿 / 等待配对 / 已连接 / 错误)
credentials按通道取不同字段(见上一节的必填项)
commandPrefix命令前缀,默认/(Telegram 会同步为 bot command)
allowedUserIds/allowedChatIds允许名单(最多各 200 项)
routeBindings按「外部聊天」各自保存的默认会话/项目/Provider/模型/Agent/权限模式/推理强度
defaultSessionId/defaultWorkspaceId/ defaultProviderProfileId/defaultModelId/ defaultAgentId/defaultPermissionMode/ defaultReasoningEffort连接级默认值;有 routeBinding 时以聊天级为准
allowSharedSession是否允许与其他远程连接共享同一会话(默认关闭)
telegramCommands/qqCommands要同步到 Telegram 命令菜单 / QQ 指令面板的命令名清单(默认 14 条,最多 80 条)
capabilities能力开关,见下表
pairing/pairedDevices当前配对码与已配对设备(remoteUserId、displayName、channelThreadId、pairedAt、lastSeenAt)
lastConnectedAt/lastError最近连接时间与最近错误(「测试配置」会写lastError)

能力开关(capabilities)的界面标签与默认值:

字段界面标签默认
sendMessages发送消息到会话true
switchModel切换模型 / Providertrue
switchSession切换会话true
switchAgent切换 Agenttrue
manageWorkspace查看工作区true
runCommands运行内置命令true
approvePermissions远程审批权限true
observeDesktop观察桌面true
controlDesktop控制桌面false
useInternalBrowser使用内置浏览器窗口false
transferFiles传输文件false
manageRuntime管理运行时true
dangerousActions高危动作确认false

安全提醒:远程连接的凭据(bot token / AppSecret 等)以明文 JSON存在 app_settings里,不在系统的 Keychain/vault 中;界面用的是普通文本输入框,已保存的值会明文显示,不做掩码。 共享这台机器数据库的人可以看到这些凭据。

3. 本地运行时与两个 HTTP 端点

  • 主进程注册远程连接 IPC 时会启动运行时:先跑startRuntime(要求 global.enabled为真),再按每条启用连接启动对应通道的接收端 (Telegram 轮询 / 飞书与 QQ 长连接)。
  • 本机 HTTP 服务监听127.0.0.1:<localWebhookPort>,默认 32178; 如果端口被占用(EADDRINUSE),会退化为让操作系统分配随机端口, 真实端口通过运行态接口回传并在设置页顶部显示。
  • GET /remote/health:返回 {ok: true, ...运行态}。
  • POST /remote/webhook/:channel/:connectionId:找不到连接返回 404; 否则按渠道解析请求体(Telegram 支持callback_query与message; 飞书支持 URL 校验 challenge;QQ 走 dispatch 事件;其余按通用chatId+ text结构解析)。
  • 运行态查询用remote:runtime-status,返回running、port、localBaseUrl、polling[](Telegram)与 longConnections[](飞书/QQ,带lastError)。
  • IPC 全景:remote:list/remote:save/remote:delete/ remote:test/remote:create-bot-draft/ remote:generate-pairing/remote:confirm-pairing/ remote:command-catalog/remote:execute-command/ remote:runtime-status;配置变化会通过stream:remote:changed 推给界面。

4. 配对:6 位数字码与 QR 负载

  1. 在设置页填好凭据并保存(保存后状态通常是「草稿」或「等待配对」)。
  2. 点「生成配对码」或「生成二维码配对」:调用remote:generate-pairing, 服务端生成 6 位数字码(randomInt(100000, 999999)),有效期由 pairingTtlMinutes决定(默认 10 分钟),并把连接状态置为 pending-pairing、自动启用该连接。
  3. QR 负载格式是 spark-agent://remote-pair?connectionId=..&channel=..&code=..&expiresAt=..; 界面上的「复制配对命令」复制的则是/bind <code>。
  4. 在外部聊天里发送/bind <code>(正则接受 6~12 位大写字母数字,实际生成为 6 位数字)。 服务端校验码相等且未过期,然后把该聊天写入pairedDevices、清掉 pairing、 状态置为connected,并在同通道回复结果。
  5. 也可以走remote:confirm-pairing手动确认(设置页的配对区支持手工填入远程用户 ID/名称), 适合自建网关等拿不到入站消息的场景。
  6. 重新生成配对码会让旧码立即失效;requirePairing 为真时,未配对聊天发来的消息会被直接忽略。

5. 内置命令清单(按能力分组)

命令目录来自服务端的COMMAND_CATALOG,可通过remote:command-catalog 查询;每条命令都绑定一个能力开关,能力关闭时执行会返回被拒绝的说明。 前缀默认是/,可用commandPrefix改。

用到的能力命令
system/start、/help、/status
sendMessages/send <message>
switchSession/sessions [all|idle|running|error] [页码]、/use-session <序号|名称|sessionId>、/new-session [序号|名称|workspaceId]
switchModel/models [页码]、/use-model <序号|名称|modelId>、/providers [页码]、/use-provider <序号|名称|providerProfileId>、/channels [页码]、/use-channel <序号|名称|渠道ID>
switchAgent/agents [页码]、/use-agent <序号|名称|agentId>
manageWorkspace/workspaces [页码]、/projects [页码]、/use-project <序号|名称|项目ID>、/open-workspace <path>、/add-project <path>
manageRuntime/reasoning、/use-reasoning <minimal|low|medium|high|xhigh|max>、/progress、/queue、/history、/cancel、/stop
approvePermissions/permissions、/use-permission <manual|auto|plan|full>
observeDesktop/screen、/windows
controlDesktop(默认关闭)/focus <序号|窗口标题>、/click <x> <y>、/type <text>、/hotkey <keys>
dangerousActions(默认关闭)/confirm <code>

新连接默认同步 14 条命令到平台原生菜单:start、help、status、projects、sessions、new-session、channels、models、agents、reasoning、permissions、progress、queue、cancel。Telegram 走setMyCommands(清单为空时改调deleteMyCommands); QQ 注册为「指令面板」,单条面板名超过 14 字符会被跳过。

6. 入站消息:命令、普通消息与会话隔离

已配对聊天的消息按下面的顺序处理:

  1. 以命令前缀开头的消息→ 走内置命令目录;先检查该命令所需能力是否开启, 再执行会话/项目/模型/Agent/推理/权限等操作。Telegram 与 QQ 支持分页与按钮式选择, 点击按钮会原位更新消息(Telegram 用editMessageText)而不是刷屏。
  2. 普通消息→ 包装成一次远程 turn 后提交给SessionService。 包装内容是【本轮远程渠道:X】+ 渠道约束 + 文件能力说明(开启「传输文件」时要求用 mcp__spark_files__present_files 提交真实文件,未开启时明确禁止声称已发送文件); 会话与桌面端界面里只显示你的原话,不显示这段内置说明。
  3. 新聊天没有绑定会话→ 用defaultWorkspaceId(或该聊天的 routeBinding) 在对应项目里新建会话;没有项目时创建「不使用项目」的会话, 并把这个绑定写回该聊天的 routeBinding。
  4. 新建会话的权限模式:优先用连接/聊天配置的 defaultPermissionMode, 否则按适配器取默认的自动审批档(Claude claude-auto、Codexcodex-auto-review、Spark spark-auto)。 「完全访问」档仍需在连接里显式配置,并且高危操作仍受权限层保护。
  5. 配置了默认 Provider / 模型 / Agent / 推理强度时,这些值在发送时应用; 每条远程回复只会发回本轮来源渠道,历史消息里提到的其他渠道不会改变发送目标。

会话隔离的真实规则:

  • 同一条机器人下的私聊与群聊是不同聊天(connectionId+externalId 组成唯一路由键),各自保存默认会话、项目、模型与选择状态,互不覆盖。
  • 一个会话已被其他连接/聊天绑定时,新连接不能直接复用:/use-session会返回 「会话已绑定到其他远程聊天」或「会话已被其他远程连接占用」。
  • 只有所有相关连接都显式开启「跨连接共享会话」(allowSharedSession)时, 才允许共享;/status会明示「会话隔离:独立 / 与 X、Y 显式共享」。
  • 定时任务的结果只在「该会话恰好由一个已启用聊天拥有」时回传 (resolveScheduledRemoteRoute:路由数不等于 1 就返回 null,不猜接收者)。

7. 平台运行时要点

Telegram

  • 接收:getUpdates长轮询,timeout=25,allowed_updates=["message","callback_query"];按 offset 递增确认。
  • 收到已配对用户消息后优先给原消息加 👀 反应(setMessageReaction); 群组禁用反应时静默跳过,不影响后续处理。
  • 输入状态:长任务期间每 4 秒续期一次sendChatAction(typing); 正文以「草稿」形式在同一条消息里增量编辑,编辑节流 1 秒,单条最长 3900 字符(超出保留尾部)。
  • Markdown 会转换为 Telegram HTML 富文本,解析失败自动回退纯文本; 出站文本按 3900 字符分片发送。
  • 图片:入站图片经getFile下载到 {userData}/attachments/remote/telegram/<日期>/后作为附件提交给会话; 出站先尝试sendPhoto(本地文件走 multipart 直传),被拒或失败时改用 sendDocument,直传失败还会经临时存储中转。

飞书

  • 用 App ID / App Secret 换tenant_access_token(带缓存与过期时间)。
  • 回复走im/v1/messages,receive_id_type由会话 id 形态推导 (chat_id/open_id);消息体是 interactive 卡片,文本按 10000 字符分片。
  • 收到配对消息后给源消息加Typing表情反应。
  • 图片:入站从消息资源接口下载并提交会话;出站先上传到im/v1/images, 再用 image_key发送原生图片消息。

QQ

  • 鉴权:POST https://bots.qq.com/app/getAppAccessToken取 access_token, 后续请求头是Authorization: QQBot <token>。
  • 长连接:先取网关地址再连 WebSocket,支持 Resume;当服务端拒绝订阅(op:9 或关闭码 4013/4014)时会逐级降低 intents 后重连。
  • 消息 API:频道用/channels/<id>/messages,群聊用 /v2/groups/<id>/messages,单聊用 /v2/users/<id>/messages; 文本msg_type: 0,按字节分片(频道 1900、群聊/单聊 1000),优先被动回复(引用msg_id+ 递增msg_seq), 超窗后退化为主动消息。
  • 图片:入站从腾讯图片 CDN 下载;频道出站用 multipart 的file_image字段, 单聊/群聊先上传拿到file_info再发msg_type: 7富媒体消息。
  • 配对的 QQ 机器人会把qqCommands同步为指令面板(超 14 字符的面板名跳过)。

三个渠道的入站图片都在配对鉴权之后下载,统一限制 20 MB,并按文件头(magic bytes)校验, 只接受 PNG / JPEG / WebP;不合法会报「仅支持 PNG、JPEG 或 WebP 图片」。 出站图片如果给的是网络 URL,会先做公开地址校验再下载。此能力需要连接里开启「传输文件」。

8. 设置 UI 结构

  • 入口:设置 → 远程连接(左栏「生态」分组)。页面说明文案是 「通过 Telegram、飞书、QQ 从远程桌面或移动端与 Spark Work 通信」。
  • 运行态条:左侧显示localBaseUrl(未启动时显示「本地 webhook 服务未启动」), 下方提示「N 个渠道已启用,远程消息会进入各聊天独立绑定的会话」或「启用任一渠道后,远程消息才会被接收」; 右上角徽标显示「运行中 / 未运行」与「已连接 / 总数」。右侧有「刷新」。
  • 平台入口卡:Telegram / 飞书 / QQ 三个图标卡,点头部按钮会创建草稿并打开对应平台控制台。
  • 连接列表卡:平台图标、名称、通道、状态标签、启用状态、已配对设备数、默认会话。
  • 编辑模态:宽 980、高度min(68dvh, 680px),左侧段导航固定五段——基础、凭证、授权、配对、命令;右侧可滚动内容,底部固定操作栏:删除、取消、测试配置、保存连接(未保存过的新连接不能测试/生成配对)。
  • 窄窗口下自动切单列布局。

注意:远程连接页不控制开机自启。开机自启动在设置 → 通用页(开关文案「开机自启动 · 登录系统后自动启动 Spark Work」), 底层走 app:get-startup-settings/app:set-startup-settings(openAtLogin+openAsHidden),平台不支持时会提示「当前系统环境不支持读取登录项」。

9. 一键创建 Bot

每个通道都有remote:create-bot-draft:创建一个草稿连接(status: draft), 返回consoleUrl与instructions,需要时同时打开控制台。 真实返回内容:

通道默认名称控制台地址要点摘录
telegramTelegram Bothttps://t.me/BotFather创建 bot 复制 token → 填回 Spark Work → 生成配对码发给 bot
feishu飞书机器人https://open.feishu.cn/page/openclaw?form=multiAgent用 openclaw 快捷入口创建自建应用并预选机器人能力,复制 App ID / App Secret
qqQQ 机器人https://q.qq.com/#/app/bot在 QQ 开放平台申请「群聊」与「单聊」消息能力;单聊加好友即可,群聊需 @机器人;保存后命令自动注册为指令面板
wechat-claw微信 Claw远程连接文档页自建网关协议,没有官方统一搭建入口(界面也不提供新建)

平台侧授权、审核与复制凭据仍然要你手动完成;「一键」只做本地草稿 + 打开控制台。 保存后务必点「测试配置」:它会校验必填字段是否齐全, 缺少字段会把状态置为error、停用连接,并写入lastError(形如「缺少字段:appId, appSecret」)。

10. 常见坑与排查

  • **需要公网 IP 吗?**不需要。Telegram 是本机出站长轮询,飞书/QQ 是官方 WebSocket 长连接;本地 HTTP 服务只监听127.0.0.1,用于本地调试与自建网关。
  • 发消息没反应:先看设置页顶部是否「运行中」,再看该连接状态是不是connected;如果状态是pending-pairing,说明还没完成 /bind。QQ 群聊还需要 @机器人(或走指令面板)。
  • 「会话已绑定到其他远程聊天」:这是有意的隔离。选择另一个会话、/new-session新建,或在所有相关连接里都开启「跨连接共享会话」。
  • 配对码过期:默认 10 分钟,重新生成即可(旧码立即失效)。
  • 图片发不出去 / 收不到:确认连接里开启了「传输文件」能力; 入站图片限 20 MB 且只支持 PNG/JPEG/WebP;出站图片被平台拒绝时会自动降级(Telegram 图片→文件、 飞书上传失败会报错、QQ 大图可用临时 URL 中转)。
  • 改了localWebhookPort但 URL 还是老的: 端口被占用时会退化成随机端口,以运行态回传的localBaseUrl 为准;改端口后要重启运行时 (保存配置会触发运行态同步)。
  • 想让远程只能发消息、不能切模型/看桌面:在「授权」段关掉对应能力开关即可—— 命令目录里每条命令都绑定能力,关闭后会直接返回拒绝说明。
  • 安全提醒:凭据在 SQLite 里是明文;requirePairing 建议保持开启; 桌面控制类能力(controlDesktop、dangerousActions)默认关闭,开启前请确认你信任这些聊天的使用者。
  • 微信 Claw 找不到入口:协议类型与 webhook 解析仍然存在(clawEndpoint+clawAccessToken),但当前界面白名单只有 Telegram / 飞书 / QQ;它依赖一个外部自建网关, 目前不在新建入口里暴露。

速查表

项目内容
可新建通道telegram / feishu / qq(wechat-claw 协议保留但无界面入口)
配置存储app_settings → remote-connections/data(凭据为明文 JSON)
本地服务127.0.0.1:32178(占用则随机端口),仅本机可访问
端点GET /remote/health · POST /remote/webhook/:channel/:connectionId
配对6 位数字码,默认 10 分钟;QR 负载 spark-agent://remote-pair?connectionId&channel&code&expiresAt
命令前缀默认 /(commandPrefix 可改)
默认同步命令start help status projects sessions new-session channels models agents reasoning permissions progress queue cancel
图片限制20 MB,仅 PNG / JPEG / WebP,需要开启「传输文件」能力
桌面控制observeDesktop 默认开;controlDesktop / useInternalBrowser / transferFiles / dangerousActions 默认关
运行态接口remote:runtime-status(polling[] 与 longConnections[])
变化推送stream:remote:changed

上手清单:用 Telegram 远程控制 Spark Work

从创建 Bot 到完成配对并发第一条消息

  1. 在 Telegram 里用 BotFather(https://t.me/BotFather)创建 Bot,复制 bot token
  2. 打开设置 → 远程连接,点 Telegram 平台卡创建草稿,进入「凭证」段粘贴 Bot Token
  3. 在「授权」段按需开关能力(默认已开:发送消息、切换会话/模型/Agent、观察桌面;默认关闭:控制桌面、传输文件、高危动作确认)
  4. 保存连接并点「测试配置」,确认状态不再是「错误」且没有缺少字段的提示
  5. 在「配对」段点「生成配对码」(或二维码配对),然后在 Telegram 里给 Bot 发 /bind <配对码>
  6. 状态变为「已连接」后,直接发普通消息即可提交任务;也可以用 /sessions 选会话、/models 换模型、/status 看当前绑定
  7. 如果列表很长,用消息下方的分页/选择按钮而不是手动输入序号;需要清空当前任务时发 /cancel

常见问题

需要公网 IP 或反向代理吗?

不需要。Telegram 用本机 getUpdates 长轮询,飞书与 QQ 用官方 WebSocket 长连接;本地 HTTP 服务只监听 127.0.0.1(默认 32178,端口占用时退化为随机端口),供本地调试与自建网关使用。

配对码怎么生成、多久过期?

在设置页点「生成配对码」或「生成二维码配对」,服务端生成 6 位数字码,有效期由 global.pairingTtlMinutes 决定(默认 10 分钟)。在外部聊天发送 /bind 加配对码完成配对,也可以用手动确认入口。

一个 Telegram 机器人能同时给多个人用吗?

可以,但每个聊天是独立路由(connectionId + externalId),各自绑定自己的会话、项目、模型与选择状态。只有所有相关连接都开启「跨连接共享会话」时才会共用一个会话。

远程会话默认什么权限?

优先用连接或聊天级的 defaultPermissionMode;未配置时按适配器取自动审批档:Claude claude-auto、Codex codex-auto-review、Spark spark-auto。完全访问档需要显式配置,且高危操作仍受权限层保护。

凭据存在哪里?安全吗?

远程连接的 botToken / AppSecret 以明文 JSON 存在 SQLite 的 app_settings(remote-connections/data)里,不在系统 Keychain 或加密 vault 中,设置页用的是普通文本输入框,已保存的值会明文显示。请确保只有你信任的人能访问这台机器的用户数据目录。

支持微信吗?

协议里保留 wechat-claw(clawEndpoint + clawAccessToken,可经本地 webhook 收发),但当前新建连接的平台卡片只提供 Telegram / 飞书 / QQ,因为微信通道依赖一个尚未内置的自建网关。

相关文档