docs: add channel integration guide
All checks were successful
Build and Push Docker Image / build (pull_request) Successful in 48s
All checks were successful
Build and Push Docker Image / build (pull_request) Successful in 48s
This commit is contained in:
@@ -16,6 +16,7 @@ You can also keep one-shot mode (`RUN_MODE=single`) for script usage.
|
||||
|
||||
- Gateway internals: `docs/gateway.md`
|
||||
- Web UI internals: `docs/web-ui.md`
|
||||
- Channel integrations (Web UI, Slack, Matrix, custom): `docs/channels.md`
|
||||
|
||||
---
|
||||
|
||||
@@ -135,3 +136,4 @@ The gateway is transport-agnostic. For each upstream client, map its thread iden
|
||||
Then post messages to `/v1/chat` or `/v1/chat/stream` with that `conversationId`.
|
||||
|
||||
This keeps one agent session per thread across transports.
|
||||
For detailed setup guidance per transport, see `docs/channels.md`.
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
|
||||
- [Gateway: how it works](./gateway.md)
|
||||
- [Web UI: how it works](./web-ui.md)
|
||||
- [Channels: Web UI, Slack, Matrix, custom adapters](./channels.md)
|
||||
|
||||
231
docs/channels.md
Normal file
231
docs/channels.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# Channels: Web UI, Slack, Matrix, and custom adapters
|
||||
|
||||
This document explains how **channels** work in the gateway and how to integrate transports like Web UI, Slack, Matrix, or your own chat source.
|
||||
|
||||
---
|
||||
|
||||
## What is a "channel" in this project?
|
||||
|
||||
In this gateway, a channel is not a separate server object you provision.
|
||||
|
||||
A channel is simply an upstream conversation context (for example: a Slack thread, a Matrix room thread, or a browser chat tab) that maps to one stable `conversationId`.
|
||||
|
||||
The gateway uses that `conversationId` to keep one long-lived agent session.
|
||||
|
||||
---
|
||||
|
||||
## How channels are represented internally
|
||||
|
||||
You have two integration options:
|
||||
|
||||
1. **Direct chat endpoints**
|
||||
- `POST /v1/chat`
|
||||
- `POST /v1/chat/stream`
|
||||
- You provide `conversationId` directly.
|
||||
|
||||
2. **Adapter endpoints** (recommended for Slack/Matrix/etc.)
|
||||
- `POST /v1/adapters/chat`
|
||||
- `POST /v1/adapters/chat/stream`
|
||||
- You provide channel/thread fields; the gateway derives `conversationId` for you.
|
||||
|
||||
Adapter ID format:
|
||||
|
||||
- `conversationId = source:workspaceId:channelId:threadId`
|
||||
- `adapterKey = source:workspaceId:channelId:threadId:userId`
|
||||
|
||||
Field behavior on adapter routes:
|
||||
|
||||
- `source` (optional, default: `generic`)
|
||||
- `workspaceId` (optional, default: `default`)
|
||||
- `channelId` (**required**)
|
||||
- `threadId` (optional, default: `root`)
|
||||
- `userId` (optional, default: `anonymous`)
|
||||
|
||||
Important constraints:
|
||||
|
||||
- segment values must be strings
|
||||
- `channelId` must not be empty
|
||||
- segment values must not contain `:`
|
||||
|
||||
If your upstream IDs contain `:` (common in Matrix), sanitize/encode them before sending to adapter routes.
|
||||
|
||||
---
|
||||
|
||||
## Do I need to "create" a channel first?
|
||||
|
||||
Usually: **no**.
|
||||
|
||||
A conversation/session is auto-created on first message. You can optionally pre-create one via:
|
||||
|
||||
- `POST /v1/conversations`
|
||||
|
||||
But for most channel integrations, you just start sending messages to chat endpoints with stable IDs.
|
||||
|
||||
---
|
||||
|
||||
## Requirements checklist (all channels)
|
||||
|
||||
1. Gateway is running (`RUN_MODE=gateway`)
|
||||
2. Model/provider credentials are configured (`PROVIDER`, `MODEL`, `API_KEY` or provider-specific key)
|
||||
3. Your adapter/client can reach the gateway URL
|
||||
4. If `GATEWAY_AUTH_TOKEN` is set, send `Authorization: Bearer <token>`
|
||||
5. For browser apps on another origin, set `GATEWAY_CORS_ORIGIN`
|
||||
6. If you want restart-safe sessions, set `SESSION_PERSIST=true`
|
||||
|
||||
---
|
||||
|
||||
## Web UI channel
|
||||
|
||||
### Built-in UI
|
||||
|
||||
The built-in UI is available at `GET /` when:
|
||||
|
||||
- `GATEWAY_ENABLE_WEB_UI=true`
|
||||
|
||||
How it works:
|
||||
|
||||
- sends messages to `/v1/chat/stream`
|
||||
- stores `conversationId` in browser local storage
|
||||
- "New session" clears local `conversationId` and starts a new thread
|
||||
|
||||
### Custom web app
|
||||
|
||||
If you build your own web frontend, call `/v1/chat` or `/v1/chat/stream` and choose your own ID format, e.g.:
|
||||
|
||||
- `web:<userId>:<chatId>`
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"conversationId": "web:user-42:chat-main",
|
||||
"message": "Summarize the last response"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Slack channel integration
|
||||
|
||||
There is no built-in Slack bot in this repository; you run a small Slack adapter service.
|
||||
|
||||
Typical adapter needs:
|
||||
|
||||
- Slack bot token + app configuration (events/interactions)
|
||||
- webhook/event receiver in your adapter
|
||||
- code that forwards messages to gateway and posts replies back to Slack
|
||||
|
||||
Recommended mapping from Slack event payload:
|
||||
|
||||
- `source`: `"slack"`
|
||||
- `workspaceId`: Slack team/workspace ID (e.g. `T123`)
|
||||
- `channelId`: Slack channel ID (e.g. `C456`) **required**
|
||||
- `threadId`: Slack `thread_ts` (or fallback strategy)
|
||||
- `userId`: Slack user ID (e.g. `U789`)
|
||||
|
||||
Example request to gateway:
|
||||
|
||||
```bash
|
||||
curl -N -X POST http://localhost:8787/v1/adapters/chat/stream \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{
|
||||
"source": "slack",
|
||||
"workspaceId": "T123",
|
||||
"channelId": "C456",
|
||||
"threadId": "1712233.991",
|
||||
"userId": "U789",
|
||||
"message": "Please summarize this thread"
|
||||
}'
|
||||
```
|
||||
|
||||
Threading strategy tip:
|
||||
|
||||
- use a stable `threadId` per Slack thread to keep context isolated per thread
|
||||
- if you omit `threadId`, gateway uses `root` (all messages for that channel collapse into one thread context)
|
||||
|
||||
---
|
||||
|
||||
## Matrix channel integration
|
||||
|
||||
There is no built-in Matrix bot in this repository; use a Matrix bot/bridge process as adapter.
|
||||
|
||||
Typical adapter needs:
|
||||
|
||||
- Matrix bot account + access token
|
||||
- event listener for room messages
|
||||
- logic to send assistant output back into room/thread
|
||||
|
||||
Recommended mapping:
|
||||
|
||||
- `source`: `"matrix"`
|
||||
- `workspaceId`: homeserver or deployment identifier (optional but useful)
|
||||
- `channelId`: Matrix `room_id` (**required**, encoded/sanitized for adapter route)
|
||||
- `threadId`: Matrix thread root event ID (encoded/sanitized, or omit for `root`)
|
||||
- `userId`: Matrix sender ID (encoded/sanitized)
|
||||
|
||||
Because adapter segments cannot contain `:`, Matrix IDs should be encoded in the adapter, e.g.:
|
||||
|
||||
```ts
|
||||
const encodeSegment = (value: string) => encodeURIComponent(value);
|
||||
```
|
||||
|
||||
Example payload (encoded values):
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "matrix",
|
||||
"workspaceId": "matrix.org",
|
||||
"channelId": "%21roomid%3Amatrix.org",
|
||||
"threadId": "%24rootEventId%3Amatrix.org",
|
||||
"userId": "%40alice%3Amatrix.org",
|
||||
"message": "What did we decide in this thread?"
|
||||
}
|
||||
```
|
||||
|
||||
Alternative: call `/v1/chat` directly and provide your own `conversationId` format if you do not want per-segment adapter normalization.
|
||||
|
||||
---
|
||||
|
||||
## Custom channel template (Discord, Telegram, email, etc.)
|
||||
|
||||
For any source, map your upstream identifiers into adapter fields and keep that mapping stable.
|
||||
|
||||
Minimal payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"channelId": "your-channel-id",
|
||||
"message": "Hello"
|
||||
}
|
||||
```
|
||||
|
||||
Full payload template:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "custom",
|
||||
"workspaceId": "tenant-a",
|
||||
"channelId": "channel-123",
|
||||
"threadId": "thread-456",
|
||||
"userId": "user-789",
|
||||
"message": "Hello"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best practices
|
||||
|
||||
- Keep `threadId` stable per thread (do not generate random values per message)
|
||||
- Include `userId` for audit/telemetry (`adapterKey`) even though it does not change `conversationId`
|
||||
- Avoid `:` in any adapter segment value
|
||||
- Use streaming endpoints for better UX (`/stream`)
|
||||
- Persist sessions in production (`SESSION_PERSIST=true`)
|
||||
- Add retry/backoff logic in your adapter for network failures
|
||||
|
||||
---
|
||||
|
||||
## Related docs
|
||||
|
||||
- Gateway internals/API: `docs/gateway.md`
|
||||
- Built-in browser UI: `docs/web-ui.md`
|
||||
@@ -139,6 +139,8 @@ Adapter request fields (`source`, `workspaceId`, `channelId`, `threadId`, `userI
|
||||
|
||||
`channelId` is required. `:` is not allowed inside segment values.
|
||||
|
||||
For practical setup patterns per transport (Web UI, Slack, Matrix, custom), see `docs/channels.md`.
|
||||
|
||||
---
|
||||
|
||||
## Streaming (SSE) behavior
|
||||
|
||||
Reference in New Issue
Block a user