Adds Google Chat as a new gateway platform, shipped under
plugins/platforms/google_chat/ following the canonical bundled-plugin
pattern (Teams, IRC). Rewired from the original PR #18425 to use the
new env_enablement_fn + cron_deliver_env_var plugin interfaces landed
in the preceding commit, so the adapter touches ZERO core files.
What it does:
- Inbound DM + group messages via Cloud Pub/Sub pull subscription (no
public URL needed), with attachments (PDFs, images, audio, video)
downloaded through an SSRF-guarded Google-host allowlist.
- Outbound text replies with the 'Hermes is thinking…' patch-in-place
pattern — no tombstones.
- Native file attachment delivery via per-user OAuth. Google Chat's
media.upload endpoint rejects service-account auth, so each user
runs /setup-files once in their own DM to grant
chat.messages.create for themselves; the adapter then uploads as
them. Tokens stored per email at
~/.hermes/google_chat_user_tokens/<email>.json.
- Thread isolation: side-threads get isolated sessions, top-level DM
messages share one continuous session. Persistent thread-count
store survives gateway restart.
- Supervisor reconnect with exponential backoff.
- Multi-user out of the box.
How it plugs in (no core edits):
- env_enablement_fn seeds PlatformConfig.extra with project_id,
subscription_name, service_account_json, and the home_channel dict
(which the core hook turns into a HomeChannel dataclass). Reads
GOOGLE_CHAT_PROJECT_ID (falls back to GOOGLE_CLOUD_PROJECT),
GOOGLE_CHAT_SUBSCRIPTION_NAME (falls back to GOOGLE_CHAT_SUBSCRIPTION),
GOOGLE_CHAT_SERVICE_ACCOUNT_JSON (falls back to
GOOGLE_APPLICATION_CREDENTIALS), GOOGLE_CHAT_HOME_CHANNEL.
- cron_deliver_env_var='GOOGLE_CHAT_HOME_CHANNEL' gets cron delivery
for free — cron/scheduler.py consults the platform registry for any
name not in its hardcoded built-in sets.
- plugin.yaml's rich requires_env / optional_env blocks auto-populate
OPTIONAL_ENV_VARS via the new hermes_cli/config.py injector, so
'hermes config' UI surfaces them with description / url / prompt /
password metadata.
- Module-level Platform('google_chat') call in adapter.py triggers the
Platform._missing_() registration so Platform.GOOGLE_CHAT attribute
access works without an enum entry.
Distribution: ships inside the existing hermes-agent package. Users
opt in via 'pip install hermes-agent[google_chat]' and follow the
8-step GCP walkthrough at
website/docs/user-guide/messaging/google_chat.md.
Test coverage: 153 tests in tests/gateway/test_google_chat.py, all
passing. Spans platform registration, env config loading, Pub/Sub
envelope routing, outbound send + chunking + typing patch-in-place,
attachment send paths, SSRF guard, thread/session model,
supervisor reconnect, authorization, per-user OAuth, and the new
plugin-registry cron delivery wiring.
Credit: adapter + OAuth + tests + docs authored by @donramon77
(PR #18425). Rewire onto the new plugin hooks + salvage commit by
Teknium.
Co-Authored-By: Ramón Fernández <112875006+donramon77@users.noreply.github.com>