Photon iMessage

通过 Photon 把 Hermes 接入 iMessage——Photon 是一项托管服务,替你打理 Apple 线路分配和防滥用层,因此你不必自己跑 Mac 中继。

免费档使用 Photon 共享的 iMessage 线路池——不同收件人可能看到不同的发送号码,但每段对话内部保持稳定。付费 Business 档给每个用户同一个专用号码;插件两者都支持,免费档是推荐的起点。

免费起步

Photon 的共享线路池免费。从 Hermes 发出第一条 iMessage 无需订阅——只需一个我们能绑定到你账号的电话号码。

架构

Photon 是一个长连接通道,类似 Discord 或 Slack——无 webhook、无公网 URL、无签名密钥需要管理。

spectrum-ts SDK 与 Photon 保持一条长寿命的 gRPC 流,双向使用。因为 SDK 只有 TypeScript 版,Hermes 把它跑在一个小型受监管的 Node sidecar 里,通过环回与之通信:

  • 入站——sidecar 消费 SDK 的 app.messages gRPC 流,把每条消息通过环回 GET /inbound(NDJSON)转发给 Python 适配器。适配器去重并派发给 agent,流断开时自动重连。
  • 出站——回复以环回 POST 发给 sidecar,后者在 SDK 上调用 space.send(...)。

Python 插件自动启动、监管并关闭 sidecar。

前置条件

  • 一个 Photon 账号——在 app.photon.codes 注册
  • Node.js:Hermes 可用时使用其托管 Node。hermes pm install node 开通锁定版本;适配器可回退到 PATH。
  • 一个能收 iMessage 的电话号码(用于绑定你的账号)

就这样——没有公网 URL 或隧道要配置。

首次设置

要么运行统一网关向导并选择 Photon iMessage:

hermes gateway setup

……要么直接运行 Photon 设置(向导调用的是同一流程):

# 设备码登录 + 项目 + 用户 + sidecar 依赖,一步到位
hermes photon setup --phone +15551234567

设置按顺序执行:

  1. 设备登录(client_id=photon-cli)——打开 https://app.photon.codes/ 审批并保存 bearer token。
  2. 在你的账号上查找或创建 Hermes Agent 项目。
  3. 启用 Spectrum,读取项目的 Spectrum id,并轮换项目 secret。
  4. 把你的电话号码注册为 Spectrum 用户——若该号码已有用户则跳过,因此重跑是安全的。
  5. 打印你分配到的 iMessage 线路——你给这个号码发短信即可找到你的 agent。
  6. 在插件 sidecar 目录内运行 npm install。在只读/不可变安装树(托管 Docker 镜像、Podman、Nix)上,sidecar 自动回退到 ~/.hermes/photon/sidecar 下的可写镜像;设 PHOTON_SIDECAR_DIR 可固定到明确位置。

运行时凭据写入 ~/.hermes/.env(PHOTON_PROJECT_ID = Spectrum 项目 id,PHOTON_PROJECT_SECRET),与其他所有通道存放 token 的位置相同。管理元数据(设备 token、仪表盘项目 id)位于 ~/.hermes/auth.json 的 credential_pool.photon / credential_pool.photon_project 下。

授权用户

Photon 与其他 Hermes 通道使用相同的授权模型。选一种方式:

DM 配对(默认)。 当未知号码给你的 Photon 线路发消息时,Hermes 回复一个配对码。用以下命令批准:

hermes pairing approve photon <CODE>

用 hermes pairing list 查看待处理码和已批准用户。

预先授权特定号码(在 ~/.hermes/.env 中):

PHOTON_ALLOWED_USERS=+15551234567,+15559876543

开放访问(仅开发用,在 ~/.hermes/.env 中):

PHOTON_ALLOW_ALL_USERS=true

设置了 PHOTON_ALLOWED_USERS 时,未知发送者被静默忽略,而不是收到配对码(允许列表表明你有意限制访问)。

群聊中要求@提及

默认情况下 Hermes 回复每条已授权的私信和群消息。要让群聊改为按需,启用提及门控(私信仍始终工作):

gateway:
  platforms:
    photon:
      enabled: true
      require_mention: true

设了 require_mention: true 时,群聊消息除非匹配唤醒词模式否则被忽略。默认匹配 Hermes 和 @Hermes agent 变体。要自定义 agent 名,设置正则模式:

gateway:
  platforms:
    photon:
      require_mention: true
      mention_patterns:
        - '(?<![\w@])@?amos\b[,:\-]?'

这两个键也接受环境变量(PHOTON_REQUIRE_MENTION、PHOTON_MENTION_PATTERNS)。这与 BlueBubbles iMessage 通道所用的提及门控模型相同。

启动网关

hermes gateway start

你会看到类似:

[photon] connected — sidecar on 127.0.0.1:8789, streaming inbound over gRPC

给你分配的号码发一条 iMessage,Hermes 就会回复。

状态与故障排查

hermes photon status

打印已保存凭据、sidecar 健康状况、你注册的号码,以及 Hermes 使用的分配 iMessage 线路。当 Photon token 和仪表盘项目可用时,status 会从仪表盘刷新缺失的号码行,而不开通新线路。

Photon iMessage 状态
──────────────────────
  device token        : ✓ 已保存
  dashboard project   : 3c90c3cc-0d44-4b50-...
  spectrum project id : sp-...
  project secret      : ✓ 已保存
  my number           : +15551234567
  assigned number     : +16282679185
  node binary         : /usr/bin/node
  sidecar deps        : ✓ 已安装

常见问题:

  • sidecar deps : ✗ run hermes photon install-sidecar——Node 已装但 spectrum-ts 没装。运行提示的命令。
  • device token : ✗ missing——运行 hermes photon setup 登录。
  • No iMessage line assigned yet——Spectrum 已启用但还没开通线路;重跑 hermes photon setup 或查看仪表盘。
  • Sidecar 起不来——确认 node --version 为 18.17+,且 hermes photon install-sidecar 无错完成。

目前的限制

  • 入站附件仅元数据。 入站事件携带文件名 + MIME 类型;agent 看到一个标记但还读不到字节。SDK 通过 content.read() 暴露附件字节,因此这是 sidecar 的后续工作。
  • 出站附件受支持。 Hermes 通过 sidecar 的 /send-attachment 端点,用 spectrum-ts 的 attachment() / voice() 内容构建器发送图片、语音备忘录、视频和文档。说明文字作为媒体之后单独的 iMessage 气泡到达。
  • 原生投票受支持。 Hermes 通过 sidecar 的 /send-poll 端点,用 spectrum-ts 的 poll() 构建器发送投票内容。
  • 已读回执受支持。 sidecar 把入站 iMessage 转发给 Hermes 后标记为已读,因此发送者看到 已读 而不必等一轮模型/工具。Hermes 发出消息的入站回执作为在线状态遥测消费,绝不产生 agent 轮次。设 PHOTON_READ_RECEIPTS=false 让消息停在 已送达。
  • 消息特效受支持。 Hermes 通过 sidecar 的 /send-effect 端点,用 spectrum-ts 的 iMessage effect() 构建器发送带原生 iMessage 气泡/屏幕特效的文本。
  • Photon 免费额度: 每服务器每天 5,000 条消息,每条共享线路每天 50 次新对话发起。可申请提升——邮件 help@photon.codes。
  • cron 和独立发送需要网关在运行。 进程外发送者(cron 任务、hermes send、仪表盘)复用网关派生的 sidecar——它们从 <hermes-home>/runtime/photon-sidecar.json 读取其端口/token,该文件在 sidecar 通过健康检查后写入、停止时移除。如果独立发送报告网关似乎已宕,请先启动(或重启)网关。
  • 共享/免费档线路不能向新目标发起对话。 Photon 侧策略:共享线路只能在某号码先给它发短信后再给该号码发消息。即使 Hermes 配置正确,向全新收件人的 cron/独立发送也会被 Photon 拒绝——要么让收件人先给线路发一条,要么改用专用线路。

环境变量

变量默认值说明
PHOTON_PROJECT_ID来自 .envSpectrum 项目 id(SDK 的 projectId);由 setup 设置
PHOTON_PROJECT_SECRET来自 .env项目 secret;由 setup 设置
PHOTON_SIDECAR_PORT8789sidecar 控制 + 入站通道的环回端口
PHOTON_SIDECAR_AUTOSTARTtrue适配器是否派生 sidecar
PHOTON_HOME_CHANNEL(未设置)cron / 通知的默认 space id
PHOTON_HOME_CHANNEL_NAME(未设置)主频道的人类可读标签
PHOTON_ALLOWED_USERS(未设置)逗号分隔的 E.164 允许列表
PHOTON_ALLOW_ALL_USERSfalse仅开发用——接受任何发送者
PHOTON_REQUIRE_MENTIONfalse群里回复前需要唤醒词
PHOTON_MENTION_PATTERNSHermes 唤醒词群提及的 JSON 列表 / 逗号 / 换行正则模式
PHOTON_DASHBOARD_HOSTapp.photon.codes覆盖仪表盘 / 设备登录主机
PHOTON_SPECTRUM_HOSTspectrum.photon.codes覆盖 Spectrum API 主机