Настройка Google Chat

Подключите Hermes Agent к Google Chat в качестве бота. Интеграция использует подписки pull Cloud Pub/Sub для входящих событий и REST API Chat для исходящих сообщений. Эргономика эквивалентна Slack Socket Mode или Telegram long-polling: ваш процесс Hermes не нуждается в публичном URL, туннеле или TLS-сертификате. Он подключается, аутентифицируется и слушает подписку — так же, как бот Telegram слушает токен.

📝 Note

Версия Workspace Google Chat является частью Google Workspace. Вы можете использовать эту интеграцию с личным Workspace (@yourdomain.com, зарегистрированным через Google) или рабочим Workspace, где у вас есть права администратора для публикации приложения. Учётные записи только Gmail не могут размещать приложения Chat.

Обзор

Компонент Значение
Библиотеки google-cloud-pubsub, google-api-python-client, google-auth
Входящий транспорт Pull-подписка Cloud Pub/Sub (без публичной конечной точки)
Исходящий транспорт REST API Chat (chat.googleapis.com)
Аутентификация JSON-файл сервисного аккаунта с roles/pubsub.subscriber на подписке
Идентификация пользователя Ресурсные имена Chat (users/{id}) + email

Шаг 1: Создайте или выберите проект GCP

Вам нужен проект Google Cloud для размещения темы Pub/Sub. Если у вас его нет, создайте его в console.cloud.google.com — личные аккаунты получают бесплатный уровень, который легко покрывает трафик бота.

Запомните ID проекта (например, my-chat-bot-123). Вы будете использовать его на каждом последующем шаге.


Шаг 2: Включите два API

В консоли перейдите в APIs & Services → Library и включите:

Оба бесплатны для объёмов, которые генерирует личный бот.


Шаг 3: Создайте сервисный аккаунт

IAM & Admin → Service Accounts → Create Service Account.

После создания откройте SA, перейдите в Keys → Add Key → Create new key → JSON и скачайте файл. Сохраните его в месте, доступном только для чтения Hermes (например, ~/.hermes/google-chat-sa.json, chmod 600).

⚠️ Caution

Роли "Chat Bot Caller" НЕ существует Распространённая ошибка — искать специфическую роль IAM для Chat и предоставлять её на уровне проекта. Такой роли не существует. Полномочия бота Chat исходят из установки в пространстве, а не из IAM. Всё, что нужно вашему SA, — это роль подписчика Pub/Sub на подписке, которую вы создадите на следующем шаге.


Шаг 4: Создайте тему и подписку Pub/Sub

Pub/Sub → Topics → Create topic.

После создания на странице деталей темы есть вкладка Subscriptions. Создайте одну:


Шаг 5: Привязка IAM к теме (критически важно)

На теме (не на подписке) добавьте участника IAM:

Без этого Google Chat не сможет публиковать события в вашу тему, и ваш бот никогда ничего не получит.


Шаг 6: Привязка IAM к подписке

На подписке добавьте ваш собственный сервисный аккаунт в качестве участника:

Также предоставьте Pub/Sub Viewer на той же подписке — Hermes вызывает subscription.get() при запуске для проверки доступности.


Шаг 7: Настройте приложение Chat

Перейдите в APIs & Services → Google Chat API → Configuration.

Сохраните.


Шаг 8: Установите бота в тестовое пространство

Откройте Google Chat в браузере. Начните DM с вашим приложением, найдя его имя в меню + New Chat. При первом сообщении Google отправляет событие ADDED_TO_SPACE, которое Hermes использует для кэширования собственного users/{id} бота для фильтрации собственных сообщений.


Шаг 9: Настройте Hermes

Добавьте раздел Google Chat в ~/.hermes/.env:

# Обязательно
GOOGLE_CHAT_PROJECT_ID=my-chat-bot-123
GOOGLE_CHAT_SUBSCRIPTION_NAME=projects/my-chat-bot-123/subscriptions/hermes-chat-events-sub
GOOGLE_CHAT_SERVICE_ACCOUNT_JSON=/home/you/.hermes/google-chat-sa.json

# Авторизация — вставьте email людей, которым разрешено общаться с ботом
GOOGLE_CHAT_ALLOWED_USERS=you@yourdomain.com,coworker@yourdomain.com

# Опционально
GOOGLE_CHAT_HOME_CHANNEL=spaces/AAAA...         # канал доставки по умолчанию для cron-задач
GOOGLE_CHAT_MAX_MESSAGES=1                      # Pub/Sub FlowControl; 1 сериализует команды на сессию
GOOGLE_CHAT_MAX_BYTES=16777216                  # 16 MiB — лимит на байты в полёте

Идентификатор проекта также может быть получен из «GOOGLE_CLOUD_PROJECT», а путь к SA — из «GOOGLE_APPLICATION_CREDENTIALS» — соответствует любому соглашению, которое вы настроите.

Установите в зависимости от необходимого адаптера Google Chat (в настоящее время отдельные дополнительные средства для Hermes не опубликованы — установите их напрямую):

pip install google-cloud-pubsub google-api-python-client google-auth google-auth-oauthlib

Запустите шлюз:

hermes gateway

Вы должны увидеть символ вроде:

[GoogleChat] Connected; project=my-chat-bot-123, subscription=<redacted>,
             bot_user_id=users/XXXX, flow_control(msgs=1, bytes=16777216)

Отправьте "hola" в тесты в Директ. Бот опубликует маркер «Гермес думает…», а затем отредактирует то же сообщение на месте с реальным ответом — без надгробия «сообщение удалено».


Форматирование и возможности

Google Chat отображает ограниченное количество уценок:

Поддерживается Нет событий
*bold*, _italic_, ~strike~, `code` Заголовки, управляющие
Встроенные изображения по URL Кнопки интерактивных карточек v2 (v1 этого шлюза)
Нативные вложения файлы (после /setup-files — см. Шаг 10) Нативные голосовые заметки / круговые видео-заметки

Системный агент включает подсказку, специальную для Google Chat, чтобы он знал эти ограничения и избегал форматирования, которого не было в Google Chat.

Лимит размера сообщения: 4000 символов для сообщения. Более длинные ответы агента автоматически раздаются по несколько сообщений.

Поддержка тредов: когда пользователь отвечает внутри треда, Hermes обнаруживает thread.name и публикует свой ответ в том же треде, так что каждый тред получает отдельную сессию Hermes.


Шаг 10: Нативная доставка вложений (опционально)

Бот из коробки может публиковать тексты, встроенные изображения по URL-адресам и карты загрузки для аудио/видео/документов. Чтобы создать нативные приложения в чате — тот же виджет файла, который вы включаете, когда человек перетаскивает файл — каждый пользователь должен один раз авторизовать боту через отдельный OAuth-поток для каждого пользователя.

Зачем отдельный поток

Конечная точка media.upload Google Chat жёстко отклоняет аутентификацию сервисного аккаунта:

Этот метод не поддерживает аутентификацию приложения с помощью учетной записи службы. Выполните аутентификацию с помощью учетной записи пользователя.

Нет ролика IAM или области, которая это исправляет. Конечная точка принимает только учётные данные пользователя. Поэтому бот должен действовать как пользователь всякий раз, когда загружает файл — например, как пользователь, запрашивающий файл.

Одноразовая настройка хоста

  1. Перейдите в API и службы → Учетные данные в том же проекте GCP.
  2. Создайте учетные данные → Идентификатор клиента OAuth → Настольное приложение.
  3. скачайте JSON. Переместите его на хост, где работает Hermes.
  4. На хосте зарегистрируйте клиента в Hermes:
python -m gateway.platforms.google_chat_user_oauth \
    --client-secret /path/to/client_secret.json

Это записывает ~/.hermes/google_chat_user_client_secret.json. Это общая инфраструктура — она идентифицирует OAuth приложение, а не отдельного пользователя. Одного файла на хост достаточно, независимо от того, сколько пользователей авторизуется позже.

Авторизация для каждого пользователя (в чате)

Каждый пользователь запускает поток один раз, в своём личном DM с ботом:

  1. Они отправляют /setup-files боту. Он отвечает статусом и следующим шагом.
  2. Они отправляют /setup-files start. Бот отвечает URL OAuth.
  3. Они открывают URL, нажимают Allow и видят, как браузер не может загрузить http://localhost:1/?...&code=.... Этот сбой ожидаем — код авторизации находится в строке URL.
  4. Они копируют неудавшийся URL (или только значение code=...) и вставляют его обратно в чат как /setup-files <PASTED_URL>. Бот обменивает его на refresh token.

Токен сохраняется в ~/.hermes/google_chat_user_tokens/<sanitized_email>.json. Последующие запросы файлов в DM этого пользователя используют его токен, поэтому бот загружает от его имени, и сообщение попадает в его пространство.

Чтобы отозвать позже: /setup-files revoke удаляет только токен этого пользователя. Токены других пользователей не затрагиваются.

Область

Поток запрашивает ровно одну область: chat.messages.create. Она покрывает как media.upload, так и последующий messages.create, который ссылается на загруженный attachmentDataRef. Никакого Drive, никаких более широких областей Chat — это наименьшие привилегии намеренно.

Поведение с несколькими пользователями

Когда у запрашивающего ещё нет токена для конкретного пользователя, бот откатывается к устаревшему однопользовательскому токену в ~/.hermes/google_chat_user_token.json (если он присутствует от установки до поддержки нескольких пользователей). Когда нет ни того, ни другого, бот публикует чёткое текстовое уведомление, предлагающее запрашивающему выполнить /setup-files.

Отзыв пользователем очищает только его слот. 401/403 от токена одного пользователя вытесняет только кэш этого пользователя. Пользователи не мешают друг другу.


Устранение неполадок

Бот молчит после отправки "hola".

  1. Проверьте в консоли, есть ли в подписке Pub/Sub недоставленные сообщения. Если есть, Hermes не аутентифицирован — проверьте GOOGLE_CHAT_SERVICE_ACCOUNT_JSON и что SA указан как Pub/Sub Subscriber на подписке.
  2. Если в подписке ноль сообщений, Google Chat не публикует. Перепроверьте привязку IAM на теме: chat-api-push@system.gserviceaccount.com должен иметь роль Pub/Sub Publisher.
  3. Проверьте логи hermes gateway на наличие [GoogleChat] Connected. Если вы видите [GoogleChat] Config validation failed, сообщение об ошибке подскажет, какую переменную окружения исправить.

Бот отвечает, но вместо ответа агента появляется сообщение об ошибке.

Проверьте логи на наличие [GoogleChat] Pub/Sub stream died — если они повторяются, возможно, ваши учётные данные SA были изменены или подписка удалена. После 10 попыток адаптер помечает себя как фатальный.

"403 Forbidden" на каждом исходящем сообщении.

Бот был удалён из пространства, или вы отозвали его в консоли Chat API. Переустановите его в пространстве (следующее событие ADDED_TO_SPACE автоматически повторно включит обмен сообщениями).

Слишком много предупреждений "Rate limit hit".

Квоты Chat API по умолчанию позволяют 60 сообщений на пространство в минуту. Если ваш агент создаёт длинные потоковые ответы, превышающие это, адаптер повторяет попытку с экспоненциальной задержкой — но вы всё равно увидите заметную задержку для пользователя. Рассмотрите краткие ответы или увеличьте квоту в консоли GCP.

Бот продолжает публиковать уведомление "/setup-files" вместо файлов.

У запрашивающего нет токена OAuth для конкретного пользователя и нет устаревшего запасного варианта. Выполните /setup-files в его DM и следуйте Шагу 10. После завершения обмена следующий запрос файла загрузится нативно без перезапуска шлюза.

/setup-files start говорит "No client credentials stored on the host."

Одноразовая настройка хоста не была выполнена. Из терминала на хосте, где работает Hermes:

python -m gateway.platforms.google_chat_user_oauth \
    --client-secret /path/to/client_secret.json

Затем отформатируйте /setup-files start еще раз.

/setup-files <PASTED_URL> говорит: «Ошибка обмена токенов».

Код авторизации одноразовый и короткоживущий (обычно несколько минут). Отправьте /setup-files start, чтобы получить новый URL-адрес, и повторите.


Замечания по безопасности