docs: add Google Chat setup guide, update NC Talk for per-user routing
- docs/GOOGLE_CHAT_BOT.md: new step-by-step guide covering channels.json,
Google Cloud Console config, JWT audience, and troubleshooting
- docs/NEXTCLOUD_TALK_BOT.md: updated for per-user endpoints
(/webhook/nextcloud/{username}), channels.json config, removed old
server-level .env references, updated Multi-User note
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
100
docs/GOOGLE_CHAT_BOT.md
Normal file
100
docs/GOOGLE_CHAT_BOT.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Google Chat Bot Integration
|
||||
|
||||
Cortex connects to Google Chat as a **Workspace Add-on** — each Cortex user gets their own webhook endpoint routed to their chosen persona.
|
||||
|
||||
**Status:** Live and confirmed working (2026-03-27)
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Google Cloud project with **Google Chat API** enabled
|
||||
- The Cortex server reachable at a public HTTPS URL
|
||||
- The user pre-registered in Cortex (`manage_passwords.py invite` or `google-add`)
|
||||
|
||||
---
|
||||
|
||||
## Per-User Setup
|
||||
|
||||
### 1. Create the user's `channels.json`
|
||||
|
||||
Create `home/{username}/channels.json` on the Cortex server:
|
||||
|
||||
```json
|
||||
{
|
||||
"google_chat": {
|
||||
"persona": "inara",
|
||||
"audience": "https://cortex.dgrzone.com/channels/google-chat/{username}",
|
||||
"backend": "claude",
|
||||
"timeout": 25
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **`persona`** — which persona responds (must exist under `home/{username}/persona/`)
|
||||
- **`audience`** — must exactly match the HTTP endpoint URL you set in Google Cloud Console (Google uses this as the JWT `aud` claim)
|
||||
- **`backend`** — `"claude"` recommended; Google Chat requires a response within 30s
|
||||
- **`timeout`** — keep at 25 (Google's hard limit is 30s; this leaves a 5s buffer)
|
||||
|
||||
### 2. Configure Google Chat API in Google Cloud Console
|
||||
|
||||
1. Go to [console.cloud.google.com](https://console.cloud.google.com) and select the project
|
||||
2. **APIs & Services → Enabled APIs & services → Google Chat API**
|
||||
3. Click the **Configuration** tab
|
||||
4. Fill in **Application info:**
|
||||
- App name: `Cortex` (or your persona name)
|
||||
- Avatar URL: optional
|
||||
- Description: optional
|
||||
5. Under **Interactive features:**
|
||||
- Enable **"Join spaces and group conversations"** if you want the bot in group chats, or leave it off for DM-only
|
||||
6. Under **Connection settings:**
|
||||
- Select **HTTP endpoint URL**
|
||||
- Enter: `https://cortex.dgrzone.com/channels/google-chat/{username}`
|
||||
7. Under **Visibility:**
|
||||
- Add the specific Google accounts that should be able to use this bot
|
||||
- For One Sky IT Workspace users: add individuals or the whole domain
|
||||
8. Click **Save**
|
||||
|
||||
> **Important:** The URL in step 6 must exactly match the `audience` value in `channels.json`. Google includes this URL as the JWT `aud` claim on every request, and Cortex rejects any request where they don't match.
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
1. User sends a message in Google Chat → Google POSTs a signed JSON payload to `/channels/google-chat/{username}`
|
||||
2. Cortex reads the user's `channels.json`, verifies the JWT `systemIdToken` from `authorizationEventObject`
|
||||
3. Sets the persona context, builds the system prompt, calls the LLM
|
||||
4. Returns the response wrapped in `hostAppDataAction → chatDataAction → createMessageAction`
|
||||
|
||||
The response must be returned synchronously (Google Chat does not support async/background replies like NC Talk does). The 25s timeout is a hard constraint.
|
||||
|
||||
---
|
||||
|
||||
## JWT Verification
|
||||
|
||||
Google Chat Workspace Add-ons send a `systemIdToken` in the request body at:
|
||||
`body["authorizationEventObject"]["systemIdToken"]`
|
||||
|
||||
Claims verified by Cortex:
|
||||
- `iss` = `https://accounts.google.com`
|
||||
- `aud` = the value of `audience` in `channels.json`
|
||||
|
||||
If `audience` is empty, verification is skipped (useful for local testing, never in production).
|
||||
|
||||
---
|
||||
|
||||
## Nginx
|
||||
|
||||
The `/channels/` prefix is already public in `auth_middleware.py` — no Nginx changes needed if you're already proxying all traffic to Cortex. Verify the path isn't blocked by basic auth or IP restrictions.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Cause | Fix |
|
||||
|---|---|---|
|
||||
| 404 on the webhook | `channels.json` missing or no `google_chat` key | Create/check `home/{username}/channels.json` |
|
||||
| 401 Invalid token | `audience` in `channels.json` doesn't match the endpoint URL | Make them identical — copy the URL exactly |
|
||||
| 401 Missing token | No `systemIdToken` in request | Bot may not be a Workspace Add-on; check connection settings type |
|
||||
| Timeout / no response | LLM too slow | `backend: "claude"` recommended; reduce context tier if needed |
|
||||
| Bot not receiving messages | Visibility not configured | Add the user's Google account under Visibility in Cloud Console |
|
||||
Reference in New Issue
Block a user