Hermes Agent Wiki 非公式・日本語wiki

Hermes Relay(コネクター)

目次

Hermes Relay それ自体はチャットのプラットフォームではありません。コネクターの仕組みであり、 ゲートウェイが実在するメッセージング基盤(Discord、 Telegram、Slack、WhatsApp など)を プラットフォームの資格情報を一切持たずに代理で扱えるようにします。 資格情報は *コネクター* と呼ばれる別のサービスが持ち、ボットのトークンとソケットを管理します。 ゲートウェイはコネクターに向けて外向きに 1 本の認証済み WebSocket をつなぎ、接続時に「何ができるか」を記した情報を受け取り、 そのソケットの上で正規化されたメッセージのイベント(受信)と操作(送信)をやり取りします。

主な性質は次のとおりです。

  • 通信は外向きだけ。 ゲートウェイは受信用のポートを一切開きません。

受信したメッセージは、ゲートウェイ側からつないだ同じ WebSocket を通って戻ってきます。そのため relay は NAT の内側でも、公開 IP を持たないホストでも動きます。

  • プラットフォームの秘密情報がゲートウェイに置かれない。 ボットのトークンはコネクターにあります。

認証が必要なプラットフォーム上のメディアの URL はコネクター側で置き直されるので、プラットフォームの 資格情報が通信路に流れることはありません。

  • プラットフォームに依存しない。 ゲートウェイは、代理で扱うプラットフォームに何ができるか

(メッセージの長さの上限、markdown の方言、編集・スレッド・逐次表示への対応、そして 対応する操作の正確な一覧)を、ハードコードされた個別の処理ではなく接続時の情報から学びます。

ゲートウェイとコネクターの間の正式な取り決めは、リポジトリの docs/relay-connector-contract.md にあります。

Relay を使う場面

Relay は、ホスティングされた、あるいは共有のコネクターのサービスがプラットフォーム側を まとめて受け持つ構成のためのものです。たとえば 1 つの共有ボットが多数の利用者のエージェントを 代理する複数テナントのホスティングや、ゲートウェイのマシンにボットのトークンを置きたくない構成が該当します。 自分でボットを直接動かすなら、各プラットフォーム向けのアダプター(TelegramDiscord など)を使ってください。

登録

自分で運用するゲートウェイは、ゲートウェイごとの秘密の値でコネクターに認証します。 hermes gateway enroll は、一度だけ使える登録用トークン (テナントの経路が用意されるときにコネクターが発行し、ゲートウェイの設定と一緒に渡されます)を その秘密の値と引き換えます。

hermes gateway enroll \
  --token <enrollment-token> \
  --connector-url wss://connector.example.com/relay

このコマンドは次のことを行います。

  1. すでにログインしている情報(~/.hermes/auth.json)から Nous Portal のアクセストークンを

取り直します。これによって、どの Nous の組織(テナント)に属しているかが証明されます。 gateway.idp.token_url が設定されている場合は、代わりに自前の IdP が使われます(外部と切り離した構成や IdP を自前で持つ場合の経路で、Nous Portal は関与しません)。 client_idclient_secret が設定されていれば一般的な OAuth2 の クライアントクレデンシャルによる認可を行い、どちらも設定されていなければ、その URL は 周囲から自動で取得できるトークンの提供元として扱われます(単純な GET の応答本文がトークンそのものになる、 メタデータサーバー方式です。たとえば Domino の $DOMINO_API_PROXY/access-token)。 2 つの資格情報のうち片方だけを設定するとエラーになります。

  1. 登録用トークンとゲートウェイの id を、TLS 経由でコネクターの

/relay/enroll エンドポイントに POST します。

  1. コネクターがトークンを検証し(署名、一度きりであること、テナントの一致)、

ゲートウェイごとの秘密の値とテナントごとの配信キーを発行して、一度だけ返します。

  1. 受け取った資格情報を ~/.hermes/.env に保存します。

GATEWAY_RELAY_IDGATEWAY_RELAY_SECRETGATEWAY_RELAY_DELIVERY_KEY (加えて、渡された場合は GATEWAY_RELAY_URLGATEWAY_RELAY_WAKE_URL)です。

このあとゲートウェイを再起動すると、新しい環境変数が読み込まれます。

指定できるフラグは次のとおりです。

フラグ 説明
--token 一度だけ使える登録用トークン。GATEWAY_RELAY_ENROLL_TOKEN でも指定できます。
--connector-url コネクターのベース URL、または relay の URL(wss://…/relayhttps://…)。GATEWAY_RELAY_URLconfig.yamlgateway.relay_url でも指定できます。
--gateway-id このゲートウェイのインスタンスを表す変わらない id(緊急停止をどの単位でかけるかに使われます)。既定は gw-<hostname> です。
--wake-url 任意。ゲートウェイが休んでいる間に処理待ちのものが届いたとき、コネクターがつつくための到達可能な URL です(本文のない GET)。GATEWAY_RELAY_WAKE_URL として保存されます。設定しなくても、次に再接続したときに溜まっていたメッセージは受け取れます。

設定

Relay は、コネクターの relay の URL を設定した時点で有効になります。専用の オンオフの切り替えはありません。設定していない構成には何の影響もありません。

設定 場所 意味
GATEWAY_RELAY_URL 環境変数(~/.hermes/.env コネクターの relay の WebSocket の URL。設定されていること自体が relay を有効にします。
gateway.relay_url config.yaml 上と同じものを設定ファイルに書く形(環境変数が優先されます)。
GATEWAY_RELAY_ID 環境変数 このゲートウェイのインスタンスの id(enroll が書き込みます)。
GATEWAY_RELAY_SECRET 環境変数 WebSocket の接続時の認証に使う、ゲートウェイごとの秘密の値(enroll が書き込みます)。
GATEWAY_RELAY_DELIVERY_KEY 環境変数 テナントごとの配信キー(enroll が書き込みます。今後の互換性のために保持されます)。
GATEWAY_RELAY_WAKE_URL / gateway.relay_wake_url 環境変数 / config.yaml 任意。休止中や一時停止中のゲートウェイをつつく先。
GATEWAY_RELAY_PLATFORMS 環境変数 このゲートウェイが 1 本の接続で代理するプラットフォームをカンマ区切りで並べたもの(例: discord,telegram)。ふつうは配備側や管理の仕組みが設定します。
GATEWAY_RELAY_BOT_IDS 環境変数 プラットフォームごとのボットの識別情報を表す JSON の対応表。例: {"discord": {"botId": "…"}}GATEWAY_RELAY_PLATFORMS と対で使います。
gateway.idp.token_url config.yaml 設定すると、登録や払い出しの認証先が Nous Portal ではなく自前の IdP になります。gateway.idp.client_idclient_secret も設定されていれば OAuth2 のクライアントクレデンシャル方式、そうでなければ周囲から自動で取得できるトークンの提供元(単純な GET でトークンそのもの、または {"access_token": …} が返る形)として扱われます。

対応していること

relay の接続で実際に何ができるかは、接続時のやり取りで決まります。コネクターが supported_ops の一覧を提示し、ゲートウェイはコネクターが明示した操作しか使いません (古いコネクターの場合は、従来の send/edit/typing/follow_up の組に落とします)。プラットフォームごとの できること(編集による逐次表示、スレッド、下書きの逐次表示、markdown の方言、メッセージの 長さの上限)も、接続時に受け取る情報から決まります。そのやり取りの範囲で、relay は次に対応します。

  • テキストのメッセージと逐次表示 — 送信、返信、そして代理するプラットフォームが

メッセージの編集に対応している場合は編集による逐次表示ができます。 対応していない場合は、区切りごとに 1 通ずつ送る形になります。

  • メディアの送受信 — 送信する画像、音声、オーディオ、動画、

文書は、コネクターにアップロードするか公開 URL で参照する形で、各プラットフォーム本来の アップロード経路を通り、説明文も一緒に届けられます。 受信した添付はエージェント向けにファイルとして手元に取り込まれます。認証が必要な プラットフォームの URL はコネクター側で置き直されるので、プラットフォームの資格情報が ゲートウェイに届くことはありません。置き直せるメディアは 25 MB までで、およそ 1 時間で期限切れになります。

  • プラットフォーム本来の対話的な確認画面 — コマンド実行の承認、確認、内容を明確にするための

質問が、番号を振ったテキストの代わりにそのプラットフォーム本来の操作部品(Discord のボタン、 Telegram のインラインキーボード、Slack の Block Kit のアクション、WhatsApp のボタンやリストの メッセージ)で表示されます。ボタンを押した結果は、実際に押した利用者からの認証済みの応答として 返るので、ゲートウェイの認可の判定は、打ち込まれた返信とまったく同じように働きます。応答の 期限切れはゲートウェイ側で管理されます。

  • リアクションによる受付の表し方 — 処理の状態を表すボットのリアクション

(作業中は 👀、完了時は ✅ か ❌)が relay 越しでも働きます。リアクションは できる範囲での対応で、失敗しても処理そのものは失敗しません。

  • スレッドの扱い — 引き継ぎ用のスレッドの作成と、スレッド名の変更

(LLM が内容から付け直す名前も含みます)を、プラットフォームに依存しない thread_create / thread_rename の操作で行えます。人が手で付けた名前を上書きしない 仕組みも入っています。利用できるかどうかはプラットフォーム次第です(Slack のスレッドは 名前を変えられませんし、WhatsApp にはスレッドがありません)。

  • 入力中の表示 — ゲートウェイは処理の間、入力中(およびその解除)をコネクター経由で

送り出します。

  • チャットの情報get_chat_info の問い合わせは、コネクターが対応を示していれば

そちらに取り次がれます。

  • 溜め置きの配信と起こす仕組み — ゲートウェイが休止したり切断したりしている間、

コネクターは受信したメッセージを確実に溜めておき、再接続時に順序どおりに流し直します(受け取りの確認を 伴うので、取りこぼしも重複も起きません)。起こすための URL が登録されていれば、 眠っているゲートウェイ宛ての処理待ちが届いたときにコネクターがそこをつつきます。

複数のプラットフォームの代理にも対応しています。1 つのゲートウェイが複数のプラットフォーム (Discord *と* Telegram など)を 1 本の relay の接続で代理でき、送信するメッセージには それぞれ宛先のプラットフォームの印が付きます。

困ったときは

登録が 401 で失敗する — コネクターが本人確認のトークンを検証できませんでした。 hermes auth add nous(または hermes setup)でログインし直してから、もう一度試してください。

登録が 403 で失敗する — 登録用トークンが無効か、期限切れか、 すでに使用済みか、別のテナントのものです。登録用トークンは 一度きりです。テナントの経路を用意した相手に、新しいものを発行してもらってください。

「Could not reach the connector」と出る — コネクターの URL を確認してください。wss://…/relay の 接続用 URL でも https://… のベース URL でも貼り付けられます。CLI が 自動で読み替えます。

enroll が実行を拒む — ホスティング事業者が管理する環境にいます。そこでは relay の秘密の値はホスティング側が用意します。自分で登録できるのは 自分で運用するゲートウェイだけです。

動いていた relay が無効と表示されるようになった — 接続が成立した*あとで* WebSocket が 4401 で閉じられた場合、そのゲートウェイの秘密の値が失効しています (インスタンスが撤去されたときなど)。ゲートウェイは意図的に再接続をやめ、 やり直すのではなく relay を無効として報告します。接続が一度も成立していない状態での 4401 は、 まだ準備が整っていないだけの一時的な行き違いとみなして、通常どおり再試行します。

登録したのに何も変わらない — ゲートウェイは GATEWAY_RELAY_* を 起動時に読み込みます。再起動してください(hermes gateway restart)。

ボタン・メディア・スレッドなどが黙って素のテキストに落ちる — その プラットフォームのコネクターが、接続時の supported_ops にその操作を示していません。 ゲートウェイは、コネクターが扱えない操作を送るのではなく、意図的にテキストでの動きに 落とすようになっています。