Настройка 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 и включите:
- Google Chat API
- Cloud Pub/Sub API
Оба бесплатны для объёмов, которые генерирует личный бот.
Шаг 3: Создайте сервисный аккаунт
IAM & Admin → Service Accounts → Create Service Account.
- Имя:
hermes-chat-bot - Пропустите шаг "Grant this service account access to project". IAM на конкретной подписке — это всё, что вам нужно — НЕ предоставляйте роли Pub/Sub на уровне проекта.
После создания откройте 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.
- Topic ID:
hermes-chat-events - Оставьте значения по умолчанию для всего остального.
После создания на странице деталей темы есть вкладка Subscriptions. Создайте одну:
- Subscription ID:
hermes-chat-events-sub - Delivery type: Pull
- Message retention: 7 days (чтобы backlog пережил перезапуск hermes)
- Остальное оставьте по умолчанию.
Шаг 5: Привязка IAM к теме (критически важно)
На теме (не на подписке) добавьте участника IAM:
- Principal:
chat-api-push@system.gserviceaccount.com - Role:
Pub/Sub Publisher
Без этого Google Chat не сможет публиковать события в вашу тему, и ваш бот никогда ничего не получит.
Шаг 6: Привязка IAM к подписке
На подписке добавьте ваш собственный сервисный аккаунт в качестве участника:
- Principal:
hermes-chat-bot@<your-project>.iam.gserviceaccount.com - Role:
Pub/Sub Subscriber
Также предоставьте Pub/Sub Viewer на той же подписке — Hermes вызывает subscription.get() при запуске для проверки доступности.
Шаг 7: Настройте приложение Chat
Перейдите в APIs & Services → Google Chat API → Configuration.
- App name: как вы хотите, чтобы пользователи видели ("Hermes" — разумно).
- Avatar URL: любой публичный PNG (у Google есть несколько по умолчанию).
- Description: короткое предложение, отображаемое в каталоге приложений.
- Functionality: включите Receive 1:1 messages и Join spaces and group conversations.
- Connection settings: выберите Cloud Pub/Sub, введите имя темы
projects/<your-project>/topics/hermes-chat-events. - Visibility: ограничьте вашим рабочим пространством (или конкретными пользователями) — не публикуйте для всех, пока тестируете.
Сохраните.
Шаг 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 или области, которая это исправляет. Конечная точка принимает только учётные данные пользователя. Поэтому бот должен действовать как пользователь всякий раз, когда загружает файл — например, как пользователь, запрашивающий файл.
Одноразовая настройка хоста
- Перейдите в API и службы → Учетные данные в том же проекте GCP.
- Создайте учетные данные → Идентификатор клиента OAuth → Настольное приложение.
- скачайте JSON. Переместите его на хост, где работает Hermes.
- На хосте зарегистрируйте клиента в 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 с ботом:
- Они отправляют
/setup-filesботу. Он отвечает статусом и следующим шагом. - Они отправляют
/setup-files start. Бот отвечает URL OAuth. - Они открывают URL, нажимают Allow и видят, как браузер не может загрузить
http://localhost:1/?...&code=.... Этот сбой ожидаем — код авторизации находится в строке URL. - Они копируют неудавшийся 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".
- Проверьте в консоли, есть ли в подписке Pub/Sub недоставленные сообщения. Если есть, Hermes не аутентифицирован — проверьте
GOOGLE_CHAT_SERVICE_ACCOUNT_JSONи что SA указан какPub/Sub Subscriberна подписке. - Если в подписке ноль сообщений, Google Chat не публикует. Перепроверьте привязку IAM на теме:
chat-api-push@system.gserviceaccount.comдолжен иметь рольPub/Sub Publisher. - Проверьте логи
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-адрес, и повторите.
Замечания по безопасности
- Область сервисного аккаунта: адаптер запрашивает области
chat.botиpubsub. IAM должен быть реальным средством контроля — предоставьте вашему SA минимум (roles/pubsub.subscriber+roles/pubsub.viewerна подписке), а не катайте Pub/Sub на уровне проекта или организации. - Защита загрузки вложений: Hermes будет прикреплять токен носителя SA только к URL-адресу, каждый хост соответствует короткому белому списку доменов, поддерживающих Google (
googleapis.com,drive.google.com,lh[3-6].googleusercontent.comи несколько других). Любой другой хост отклоняется до HTTP-запроса, чтобы защититься от проявлений SSRF, где сфабрикованное событие может перенаправить носитель токена в метаданные GCE. - Редактирование: почтовые сервисные аккаунты, пути подписок и пути тем удаляются из результатов журналов с помощью
agent/redact.py. Дамп отладочного конверта (GOOGLE_CHAT_DEBUG_RAW=1) проходит через тот же фильтр редактирования и регистрируется на уровне DEBUG. - Соответствие: если вы планируете подключить эту боту к регулируемому рабочему пространству (с политикой хранения данных или управления AI), предоставить предоставление одобрения до первой установки.
- Область пользователя OAuth: поток вложений для каждого пользователя запрашивает только
chat.messages.create— минимум, который раскрываетmedia.uploadплюс следующийmessages.create. Токены определяются как простой JSON в~/.hermes/google_chat_user_tokens/<sanitized_email>.json(защита на уровне файловой системы — та же модель, что и для файла переключения SA). Каждый жетон принадлежит ровно одному гостю; отзыв ограничен этим пользователем.