跳转至

消息连接

此计算机的代理可以在外部聊天平台中作答。目前支持 Slack、Discord 和 Telegram。设计说明见 architecture/channels-and-messaging.md, Slack 启动步骤见 apps/slack-app/LAUNCH.md,Discord 应用设置见 apps/discord-app/README.md。

连接 Slack

一个工作区安装唯一的 OpenBot Slack 应用。用户提及 @OpenBot 或向它发送私信, Slack 编排器(OpenBot 添加的一个代理)会询问合适的代理并作答。这需要 OpenBot 账户和此计算机的名称(服务器设置), 因为 Slack 会将工作区事件发送到 OpenBot 的 Signal 服务,再由该服务将其传递到此计算机。

  1. 打开市场 → 应用 → Slack。
  2. 选择连接 Slack,然后选择在 Slack 中连接。Slack 会在浏览器中打开。选择 右上角的工作区,然后选择允许。对话框会自动继续。
  3. 选择 Slack 编排器的模型,然后选择添加代理。OpenBot 会将此代理及其 指令和初始事实添加到侧边栏的集成分区中,该分区初始为折叠状态。 你可以在代理设置中重命名它或更改其模型。
  4. 在 Slack 中,在任何公共频道提及 @OpenBot,或向它发送私信。

要连接另一个工作区,请选择添加工作区。一个 Slack 编排器服务所有 工作区,因此你之后添加的工作区会跳过第 3 步。

OpenBot 在连接时会加入工作区的每个公共频道,也会加入之后创建的每个公共频道。 Slack 会在每个频道中显示“已加入 #channel”。私有频道需要邀请: /invite @OpenBot。

一个工作区由一个 OpenBot 服务器应答。在你的服务器应答某个工作区时,另一个账户无法连接该工作区, 除非你断开连接。断开连接会吊销令牌,将其从此计算机中移除,并取消链接该工作区。 当它是最后一个工作区时,还会删除 Slack 编排器及其对话;当集成分区中没有剩余代理时,也会删除该分区。 当编排器正在处理一轮操作时,断开连接会以错误停止且不改变任何内容:请先停止代理。

只有运行代理的计算机才能连接 Slack,因为 Slack 会返回到该计算机的浏览器。 已加入的服务器不会显示 Slack 页面。

Slack 中会发生什么

  • 在频道中提及会开始或继续该话题中的对话。在该话题中回复 无需提及即可到达同一代理。
  • 私信始终会到达 OpenBot。OpenBot 在私信下方的话题中回复,因此每封私信 都是独立的对话。
  • 新对话会交给 Slack 编排器。它自己回答简短请求,并将其他工作 交给最合适的代理。该代理的回答会回到话题中,然后由编排器发布。 在你添加编排器之前,Slack 会显示“尚无代理可以在此回答”。
  • 每个对话都是该代理自己的 OpenBot 话题,因此不会与该代理自身的聊天混在一起。
  • 代理会将话题中较早的消息作为上下文,并查看消息中的文件。提及某人时, 会显示该人的 Slack 名称。
  • 代理可以保存关于工作区的简短事实,例如某个项目由谁负责。工作区的每个新 对话在每一个频道中都能看到这些事实;代理自身的聊天则看不到。来自私信的事实 不会被保存。参见 工作区记忆。
  • 当消息提到较早的内容时,代理可以阅读更多频道或话题内容。
  • 👀 表示消息已到达。“正在处理中…”会被回答替换。✅、❌ 或 ⏹ 表示结束。 每条发布都来自 OpenBot,不标明具体代理。
  • 审批会出现在话题中,并带有批准和拒绝按钮。只有写下该消息的人 才能在那里回答。OpenBot 主机始终可以回答。
  • 话题中的 stop 或 cancel,或停止按钮,会停止发送者发出的请求。

连接 Discord

一个 Discord 服务器安装唯一的 OpenBot Discord 应用。用户在频道中提及 @OpenBot, Discord 编排器(OpenBot 添加的一个代理)会询问合适的代理并作答。与 Slack 一样, 这需要 OpenBot 账户和此计算机的名称(服务器设置):Signal 保持机器人的 Discord 连接,将服务器的提及传递到此计算机,并代其发布 OpenBot 的 Discord 帖子。

  1. 打开市场 → 应用 → Discord。
  2. 选择连接 Discord,然后选择在 Discord 中连接。Discord 会在浏览器中打开。选择 Discord 服务器,然后选择授权。你必须在其中拥有管理服务器权限。对话框会自动继续。
  3. 选择 Discord 编排器的模型,然后选择添加代理。与 Slack 编排器一样,它会进入 集成侧边栏分区。
  4. 在 Discord 中,在某个频道提及 @OpenBot。

要连接另一个 Discord 服务器,请选择添加 Discord 服务器。一个 Discord 编排器服务所有 Discord 服务器,因此你之后添加的服务器会跳过第 3 步。谁可以使用 OpenBot 为每个 Discord 服务器设置其成员可以提及 OpenBot 的角色。如果没有设置角色,则所有人皆可。

OpenBot 能看到其角色可以查看的每个频道。若要让 OpenBot 不进入某个频道,请移除其角色在该频道的查看权限。

一个 Discord 服务器由一个 OpenBot 服务器应答。在你的服务器应答某个 Discord 服务器时,另一个账户无法连接该服务器, 除非你断开连接。断开连接会取消链接该 Discord 服务器并将其从此计算机中移除。 当它是最后一个 Discord 服务器时,它还会像 Slack 那样删除 Discord 编排器及其对话。 OpenBot 会一直保留为 Discord 服务器成员,直到 Discord 管理员将其移除。当 Discord 管理员移除 OpenBot 时, Signal 会取消链接该服务器,即使此计算机处于关闭状态也会如此;该行会显示令牌不被接受 (对于曾关闭的计算机,会在其重新连接时显示)。之后重新连接会重新开始安装。 如果断开连接无法访问账户服务,则不会改变任何内容;请重试。

Discord 中会发生什么

  • 提到 @OpenBot 的消息会开始一段对话。OpenBot 回复该消息。
  • 对 OpenBot 帖子的回复会继续同一段对话。回复必须保留提及: Discord 回复里的 @ ON 设置会做到这一点,并且默认开启。没有提及, Discord 就不会把文本交给 OpenBot。
  • 对他人消息进行回复的提及会开始一段新对话。
  • 新对话会以它之前 15 分钟内频道中最近 10 条消息作为上下文,因此 在他人截图之后发送的 “@OpenBot make an issue” 指的是那张截图。智能体 会在消息自身文件之后、在附件限制内,随该消息一起获得较早消息的文件。 如果没有 Message Content intent,Discord 只会提供提及 OpenBot 的消息的文本和文件。
  • 发送给 OpenBot 的私信只会得到一个固定回答:请在服务器频道中提及 OpenBot。
  • 其余工作方式与 Slack 相同:Discord Orchestrator 接收每段新对话,👀 表示 消息已到达,“Working on it…” 会被回答替换,✅、❌ 或 ⏹️ 表示结束。 审批有 Approve 和 Deny 按钮,状态帖有 Stop。只有发出 请求的人才能按这些按钮;其他人会收到一条只有自己可见的回复。对 OpenBot 帖子的回复如果只包含 stop 或 cancel,会停止发送者自己的请求。
  • 帖子绝不会提醒任何人,即使提到某人的名字也不会。
  • 超过 2,000 个字符的回答会分多条帖子发送。大于 10 MB 的文件 不会被发送,对话中会说明哪些文件未被发送。

连接 Telegram

一个 OpenBot 机器人服务所有用户。人们在群组中提及它,或回复它的消息,Telegram Orchestrator——OpenBot 添加的一个智能体——会向正确的智能体提问并作出回答。这需要一个 OpenBot 账户和这台计算机的名称(Server settings),因为 Telegram 会将更新发送到 OpenBot 的 Signal 服务,再由 Signal 传递给这台计算机。Signal 持有机器人令牌;这台计算机永远不会持有它。

  1. 打开 Marketplace → Apps → Telegram。
  2. 选择 Add to a group 或 Open a direct chat。Telegram 会打开一个一次性链接(有效期为 15 分钟)。选择群组,或选择 Start。聊天会自动出现在 OpenBot 中。
  3. 选择 Telegram Orchestrator 的模型,然后选择 Add agent。一个编排器会回答所有 Telegram 聊天。它位于侧边栏的 Integrations 部分。
  4. 在群组中提及机器人(@<bot> …),或回复它的某条消息。

一段聊天归一个 OpenBot 服务器处理。在你的服务器处理某个聊天期间,其他账户无法关联该聊天,直到你断开它。Disconnect 会让机器人离开聊天并解除关联。如果这是最后一个关联的聊天,它还会像 Slack 那样删除 Telegram Orchestrator 及其对话。否则对话会保留在 OpenBot 中,之后再次关联同一聊天时,这些对话会重新分配给它们的智能体。

Telegram 中会发生什么

  • 提及会开始或继续其回复链中的对话。在超级群组中,Telegram 会给每个回复链一个独立线程,因此回复机器人或回复链中的消息时,无需提及即可到达同一个智能体。在论坛中,每个主题是一段对话。私聊是一段对话。
  • 在隐私模式开启(Telegram 的默认设置)的情况下,Telegram 只向机器人发送提及它、回复它和命令的消息。聊天的其他消息不会到达这台计算机。
  • 👀 表示消息已到达。“Working on it…” 会被回答替换。👌、💔 或 🫡 表示结束。
  • 审批会显示 Approve 和 Deny。只有写消息的人才能在那里回答。当其他人按下按钮时,机器人会在聊天中回复说只有请求者才能这样做。
  • @<bot> stop、向机器人回复 stop,或 Stop 按钮,都会停止请求。
  • 最多 20 MB 的文件可以双向发送。

在本地测试 Telegram

Telegram 必须通过公共 HTTPS 访问 Signal。

  1. 用 @BotFather 创建一个开发机器人。保持隐私模式开启。
  2. 启动一个指向本地 Signal 的隧道,例如 cloudflared tunnel --url http://127.0.0.1:<signal port>。
  3. 为 Signal 提供 TELEGRAM_BOT_TOKENS(机器人令牌)、TELEGRAM_WEBHOOK_SECRET(至少 32 字节)和 TELEGRAM_WEBHOOK_ORIGIN(隧道地址)。Signal 会在启动时设置机器人的 webhook。
  4. 在 apps/auth-api/.env.dev 中,设置 TELEGRAM_BOT_ID(令牌中 : 之前的部分)、TELEGRAM_BOT_USERNAME,以及 Slack 路由密钥(见下文):它也会为 Telegram 路由票据签名。

尚未确认:此流程能否端到端对接 Telegram。测试使用模拟的 Signal 和模拟的 Bot API。

在本地测试 Slack

Slack 必须通过公共 HTTPS 访问 Signal 和账户 API。bun run dev:slack 会打开两个 cloudflared 隧道,一个指向本地 Signal,一个指向本地账户 API,并把开发应用的签名密钥提供给 Signal。

  1. 安装 cloudflared(brew install cloudflared)。
  2. 在工作树根目录写入 .env.slack-dev。Git 会忽略它。
    OPENBOT_DEV_SLACK_SIGNING_SECRET='…'
    
    该值是 OpenBot (dev)(A0C5G5XGS83)的签名密钥,位于 https://api.slack.com/apps 的 Basic Information 下。
  3. 在 shell 中导出 SLACK_ROUTE_PRIVATE_JWK,其值与 .openbot/dev-state.json 中的 REMOTE_TICKET_PRIVATE_JWK 相同,并导出 SLACK_ROUTE_KEY_ID=openbot-remote-1。仅限开发:票据密钥的公钥已经在 Signal 加载的 JWKS 中。
  4. 运行 bun run dev:slack(为共享的 OpenBot Dev 配置添加 --shared)。将打印出的地址设置为开发应用的事件和交互的请求 URL,以及其重定向 URL。这些地址每次启动都会变化。

安装流程通过账户 API 隧道返回。本地账户 API 需要在本地开发状态中拥有开发应用的 SLACK_CLIENT_ID、SLACK_CLIENT_SECRET 和 SLACK_STATE_SECRET。开发应用在回环端口上获得授权,而不是通过 openbot://,因此同一台计算机上已安装的 OpenBot 不会获得它。尚未确认:此安装流程能否端到端运行。

故障排查

工作区行会指出问题所在。

问题 原因 操作
Token 未被接受 Slack 拒绝了该 Token,或者 OpenBot 已从工作区卸载。 重新连接 Slack。
缺少权限 安装的权限范围少于 OpenBot 要求的范围。 先断开连接,再重新连接 Slack。
正在等待 Slack Slack 对 OpenBot 实施了速率限制。 无需操作。主机会在显示的时间重试。
Token 无法读取 主机无法解密存储的 Token。 先断开连接,再重新连接 Slack。
正在重新连接 主机丢失了连接。 无需操作,或网络恢复后重新连接。
无法接收事件 这台计算机无法访问 Signal:它已退出登录、没有名称,或 Signal 已关闭。 登录,在服务器设置中为这台计算机命名,并保持 OpenBot 运行。
“另一个 OpenBot 服务器已在应答此 Slack 工作区” 另一个账户已连接该工作区。 在该服务器上断开它,然后重试。

工作区记忆

每个连接(一个 Slack 工作区、一个 Discord 服务器或一个 Telegram 聊天)都有自己的事实列表。应答的代理使用 openbot.messaging_remember 保存事实,并使用 openbot.messaging_forget_memory 删除事实。该连接的每个对话中的每个 Prompt 都会显示整个列表,并带有每个事实的 ID。该 Prompt 将这些事实标记为数据,而非指令。

  • 一个连接最多保存 32 条事实,每条 500 个字符。
  • 直接消息中的事实不会被保存,因为工作区的每个频道都会看到它。在私密频道中保存的事实不会被拒绝:工作区的每个频道和直接消息也都会看到它。任何能在工作区中(包括直接消息中)触达 OpenBot 的人,都可以让代理忘记某条事实。
  • 代理自己的记忆(openbot.remember)保持独立,仅对 OpenBot 用户私密。
  • 断开连接会保留这些事实。当你再次连接同一工作区时,代理会再次看到它们。
  • OpenBot 目前还没有这些事实的界面。请在工作区中让代理忘记某条事实。

openbot.messaging_history 读取会话自身频道或线程中的最新消息:默认 30 条,最多 100 条。它不读取其他地方。Slack 可能将其限制为每分钟读取一次;此时会立即失败,代理可以重试。Discord 只提供提及 OpenBot 的消息和机器人帖子的文本。Discord 消息会注明其文件名。Telegram 提供这台计算机启动以来所看到的内容。

代理发送的帖子

任何代理都可以主动向已连接的位置发帖,可在任意回合中:在用户自己的聊天中、在例行任务运行时,或在应答平台消息的回合中。在请求或例行任务 Prompt 中告知它位置,例如“把摘要发到 Discord 的 #bot-inflow”。

  • openbot.messaging_list_places 不带参数时列出已启用的连接及其 ID。使用 connection 参数时,它列出 OpenBot 可以发帖的位置:它所属的 Slack 频道、其权限允许查看和发帖的 Discord 文本与公告频道及活跃主题,或 Telegram 聊天本身。
  • openbot.messaging_post 以 OpenBot 身份将 Markdown 发布到 place。replyTo 将帖子放入线程:Slack 线程 ts、Discord 消息 ID、Telegram 消息 ID,或用于 Telegram 论坛主题的 t<topic ID>。文本在离开这台计算机之前会进行脱敏处理。Discord 帖子不会通知任何人;Telegram 的 @username 会通知该用户。Telegram 连接只能在其自己的聊天中发帖。结果包含 messageId(第一个帖子的 ID),对于 Discord 还有指向它的 url。
  • 长文本会分成多条帖子发送。当后面的部分失败时,之前的部分仍保持已发布状态。
  • 例行任务仅在其运行调用该工具时发帖。调度器不会发布运行的结果。
  • 对帖子的回复只会像往常一样到达代理:它必须提及 OpenBot,并且会进入 Orchestrator。
  • 没有允许的频道列表,也没有审批流程。任何能给代理分派工作的人都可以让它们在任何 OpenBot 可见的位置发帖。Slack 私密频道需要 /invite。
  • Discord 列表需要一个支持 listChannels 调用的 Signal。较旧版本的 Signal 会以 invalid_request 拒绝该调用;发帖功能则适用于任何 Signal。

限制

这些限制适用于 Slack。Discord 的限制见 apps/discord-app/README.md,以下限制同样适用于 Discord:主机必须运行、队列限制、谁可以分派工作,以及休眠的托管服务器会因一条消息而启动。Discord 每个事件只发送一次:当这台计算机没有 Signal 连接时到达的事件会丢失,但如果一台托管服务器会因该事件而启动,则该事件不会丢失。

  • 主机必须运行。当这台计算机未应答时,Slack 会在约 1 分钟和 5 分钟后再次发送事件,然后丢弃它。
  • 代理一次运行一个回合。Slack 请求会排在代理自身工作和频道工作之后,线程会显示它在等待。一个代理最多保留 20 个等待中的 Slack 请求,一个人最多 2 个。
  • Slack 会通过 Signal 将 OpenBot 所在每个频道的每条消息发送到这台计算机。由于 OpenBot 在所有公共频道中,繁忙的工作区会发送大量事件。主机只保留那些指向 OpenBot 或延续已有对话的消息。
  • 在 Slack Marketplace 批准 OpenBot 之前,Slack 将线程读取限制为每分钟 1 个请求和 15 条消息,因此代理能看到的上下文较少。
  • 任何能在工作区发帖的人(包括访客和 Slack Connect 成员)都可以给代理分派工作。它们会以你授予的权限运行。在完全访问权限下,它们会直接运行命令而不会询问。
  • 托管服务器在 15 分钟无使用后休眠,即使连接仍处于活动状态。提及、直接消息、线程回复或按下按钮都会启动它。Signal 会将那条消息加密保留最多 10 分钟,并在服务器连接时交给它,因此答案会在服务器启动后(几分钟后)到来。在此期间重启 Signal 会丢失该消息。Signal 重启后,发送到休眠服务器的 Telegram 或 Discord 消息会启动它,但该消息会丢失;请在服务器开启时重新发送。Slack 会自动重新发送其消息。
  • 当代理在 Slack 对话中向另一个 OpenBot 代理询问某事时,回复会回到该对话。然后该代理会在同一线程中发布其答案,原始消息会保留其表情回应。
  • 代理提出的问题会在主机上得到回答。Slack 不会显示任何相关内容。
  • Telegram 不会再次发送更新。当这台计算机处于关闭状态或无法访问 Signal 时到达的更新会丢失。休眠的托管服务器会因消息或按下按钮而启动,并在连接时获取该更新。
  • 在基本 Telegram 群组(非超级群组)中,OpenBot 会在内存中找到回复链。重启后,对较旧消息的回复会开始新的对话。
  • 当 Telegram 群组变为超级群组时,它会获得新的 ID。OpenBot 会将聊天显示为已移除:断开连接,然后重新添加机器人。
  • Telegram 没有历史记录 API。代理只能把这台计算机启动以来看到的消息,以及请求所应答的那条消息,作为上下文。

添加平台

一个平台就是一个 MessagingDriver(src/backend/messaging/messaging-types.ts),核心部分无需任何改动:

  • createAdapter 实现 MessagingAdapter:发布、编辑、回应、上传、下载、历史记录、最近(用于历史工具)、作者和地点名称,以及提及。
  • createTransport 实现 MessagingTransport,将平台的事件转换为 InboundMessage 和 InboundAction 值。它不需要主机上的公共地址。InboundMessage.mentionedUserIds 列出文本中以 @<id> 提及的用户,以便核心能够称呼他们。
  • requiredCredential 指明所需的存储值,没有它连接就不会启动。
平台 传输 会话键 备注
Slack 通过 Signal 的 Events API thread_ts,或开启线程的消息 ts 已实现。
Discord Signal 中的 Gateway(@discordjs/ws),将提及传递给主机;调用通过 Signal 进行 回复链中第一条消息的 id 已实现。无需 privileged intent。
Telegram 通过 Signal 的那个 OpenBot bot 的 webhook,由 Signal 持有 token message_thread_id,论坛中的话题,私聊中的 dm 已实现。没有历史 API:主机在内存中保留机器人所看到的内容。

然后将该平台添加到 MESSAGING_PLATFORMS、Marketplace → Apps 中的一个页面,以及其 i18n 键。数据库无需迁移:platform 没有 CHECK 约束。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 openbo/openbot