docs: update conversation routing and group config documentation (#318)
Adds documentation for per-channel conversation routing and updated group configuration options. Fills the gap left by the implementation PRs. Closes #304 Written by Cameron and Letta Code "Documentation is a love letter that you write to your future self." -- Damian Conway
This commit is contained in:
56
README.md
56
README.md
@@ -193,7 +193,7 @@ Then ask your bot things like:
|
|||||||
|
|
||||||
## Channel Setup
|
## Channel Setup
|
||||||
|
|
||||||
LettaBot uses a **single agent with a single conversation** across all channels:
|
By default, LettaBot uses a **single agent with a single shared conversation** across all channels:
|
||||||
|
|
||||||
```
|
```
|
||||||
Telegram ──┐
|
Telegram ──┐
|
||||||
@@ -208,6 +208,35 @@ Signal ────┘
|
|||||||
- Pick it up on WhatsApp
|
- Pick it up on WhatsApp
|
||||||
- The agent remembers everything!
|
- The agent remembers everything!
|
||||||
|
|
||||||
|
You can also enable **per-channel conversations** (one conversation per channel adapter, not per chat/user):
|
||||||
|
|
||||||
|
```
|
||||||
|
Telegram ──→ CONVERSATION (telegram)
|
||||||
|
Slack ─────→ CONVERSATION (slack)
|
||||||
|
Discord ───→ CONVERSATION (discord)
|
||||||
|
WhatsApp ──→ CONVERSATION (whatsapp)
|
||||||
|
Signal ────→ CONVERSATION (signal)
|
||||||
|
(shared agent memory across channels)
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure in `lettabot.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
conversations:
|
||||||
|
mode: shared # default: one conversation across all channels
|
||||||
|
heartbeat: last-active # "dedicated" | "last-active" | "<channel>"
|
||||||
|
```
|
||||||
|
|
||||||
|
For multi-agent configs, the same block lives under each agent:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
agents:
|
||||||
|
- name: MyAgent
|
||||||
|
conversations:
|
||||||
|
mode: per-channel
|
||||||
|
heartbeat: dedicated
|
||||||
|
```
|
||||||
|
|
||||||
| Channel | Guide | Requirements |
|
| Channel | Guide | Requirements |
|
||||||
|---------|-------|--------------|
|
|---------|-------|--------------|
|
||||||
| Telegram | [Setup Guide](docs/getting-started.md) | Bot token from @BotFather |
|
| Telegram | [Setup Guide](docs/getting-started.md) | Bot token from @BotFather |
|
||||||
@@ -226,12 +255,23 @@ Configure group batching and per-group response modes in `lettabot.yaml`:
|
|||||||
channels:
|
channels:
|
||||||
slack:
|
slack:
|
||||||
groupDebounceSec: 5
|
groupDebounceSec: 5
|
||||||
instantGroups: ["C0123456789"]
|
mentionPatterns: ["@mybot", "hey bot"]
|
||||||
groups:
|
groups:
|
||||||
"*": { mode: open }
|
"*": { mode: mention-only } # default for all groups
|
||||||
"C0987654321": { mode: listen } # observe only, reply on mention
|
"C0987654321": { mode: listen } # observe, only reply on mention
|
||||||
|
"C0123456789": { mode: open, allowedUsers: ["U123"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Group modes:
|
||||||
|
- `open`: process + respond to all group messages
|
||||||
|
- `listen`: process for memory, but auto-replies only on mention
|
||||||
|
- `mention-only`: only process when mentioned
|
||||||
|
- `disabled`: ignore all group messages
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- `instantGroups` still bypasses batching (legacy).
|
||||||
|
- `listeningGroups` and `groups.<id>.requireMention` are deprecated; use `groups.<id>.mode`.
|
||||||
|
|
||||||
See `SKILL.md` for the full environment variable list and examples.
|
See `SKILL.md` for the full environment variable list and examples.
|
||||||
|
|
||||||
## Bot Commands
|
## Bot Commands
|
||||||
@@ -244,7 +284,9 @@ See `SKILL.md` for the full environment variable list and examples.
|
|||||||
|
|
||||||
## Background Tasks (Heartbeats & Cron)
|
## Background Tasks (Heartbeats & Cron)
|
||||||
|
|
||||||
Heartbeats and cron jobs run in **Silent Mode** - the agent's text responses are NOT automatically sent to users during these background tasks. This is intentional: the agent decides when something is worth interrupting you for.
|
Heartbeats always run in **Silent Mode**. Cron jobs are **silent by default**, but can auto-deliver responses when created with `--deliver channel:chatId`.
|
||||||
|
|
||||||
|
Silent Mode means the agent's text responses are NOT automatically sent to users during background tasks. This is intentional: the agent decides when something is worth interrupting you for.
|
||||||
|
|
||||||
To send messages during silent mode, the agent must explicitly use the CLI:
|
To send messages during silent mode, the agent must explicitly use the CLI:
|
||||||
|
|
||||||
@@ -254,9 +296,9 @@ lettabot-message send --text "Hey, I found something interesting!"
|
|||||||
|
|
||||||
The agent sees a clear `[SILENT MODE]` banner when triggered by heartbeats/cron, along with instructions on how to use the CLI.
|
The agent sees a clear `[SILENT MODE]` banner when triggered by heartbeats/cron, along with instructions on how to use the CLI.
|
||||||
|
|
||||||
**Requirements for background messaging:**
|
**Requirements for background messaging (silent mode):**
|
||||||
- The **Bash tool must be enabled** for the agent to run the CLI
|
- The **Bash tool must be enabled** for the agent to run the CLI
|
||||||
- A user must have messaged the bot at least once (to establish a delivery target)
|
- A user must have messaged the bot at least once (to establish a delivery target) unless you provide an explicit target
|
||||||
|
|
||||||
If your agent isn't sending messages during heartbeats, check the [ADE](https://app.letta.com) to see what the agent is doing and whether it's attempting to use `lettabot-message`.
|
If your agent isn't sending messages during heartbeats, check the [ADE](https://app.letta.com) to see what the agent is doing and whether it's attempting to use `lettabot-message`.
|
||||||
|
|
||||||
|
|||||||
50
SKILL.md
50
SKILL.md
@@ -176,21 +176,52 @@ Each channel supports three DM policies:
|
|||||||
- **`allowlist`**: Only specified user IDs can message
|
- **`allowlist`**: Only specified user IDs can message
|
||||||
- **`open`**: Anyone can message (not recommended)
|
- **`open`**: Anyone can message (not recommended)
|
||||||
|
|
||||||
|
## Conversation Routing
|
||||||
|
|
||||||
|
By default, all channels share **one conversation**. You can switch to per-channel conversation histories.
|
||||||
|
|
||||||
|
**Single-agent config (top-level):**
|
||||||
|
```yaml
|
||||||
|
conversations:
|
||||||
|
mode: shared # "shared" (default) or "per-channel"
|
||||||
|
heartbeat: last-active # "dedicated" | "last-active" | "<channel>"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multi-agent config (per agent):**
|
||||||
|
```yaml
|
||||||
|
agents:
|
||||||
|
- name: MyAgent
|
||||||
|
conversations:
|
||||||
|
mode: per-channel
|
||||||
|
heartbeat: dedicated
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- `per-channel` means one conversation per **channel adapter** (telegram/slack/discord/etc), not per chat/user.
|
||||||
|
- Agent memory remains shared across channels; only the conversation history is separated.
|
||||||
|
- `heartbeat` controls which conversation background triggers use: a dedicated stream, the last active channel, or an explicit channel name.
|
||||||
|
|
||||||
## Group Settings (Optional)
|
## Group Settings (Optional)
|
||||||
|
|
||||||
Group settings apply to Telegram, Slack, Discord, WhatsApp, and Signal.
|
Group settings apply to Telegram, Slack, Discord, WhatsApp, and Signal.
|
||||||
|
|
||||||
**YAML fields (per channel under `channels.<name>`):**
|
**YAML fields (per channel under `channels.<name>`):**
|
||||||
- `groupDebounceSec`: Debounce seconds for group batching (default: 5)
|
- `groupDebounceSec`: Debounce seconds for group batching (default: 5)
|
||||||
|
- `groups`: Map of group IDs to config (use `*` as the default)
|
||||||
|
- `mode`: `open` | `listen` | `mention-only` | `disabled`
|
||||||
|
- `allowedUsers`: Restrict who can trigger the bot in that group
|
||||||
|
- `receiveBotMessages`: Allow bot/bot messages (default: false)
|
||||||
|
- `mentionPatterns`: Extra regex patterns for mention detection (Telegram/WhatsApp/Signal)
|
||||||
|
- `instantGroups`: Group IDs that bypass batching (**legacy**)
|
||||||
- `groupPollIntervalMin`: Deprecated (minutes)
|
- `groupPollIntervalMin`: Deprecated (minutes)
|
||||||
- `instantGroups`: Group IDs that bypass batching
|
- `listeningGroups`: Deprecated (use `groups.<id>.mode: listen`)
|
||||||
- `listeningGroups`: Group IDs where the bot observes and only replies when mentioned
|
|
||||||
|
|
||||||
**Environment variables (non-interactive onboarding):**
|
**Environment variables (non-interactive onboarding):**
|
||||||
|
Only legacy group options are supported here; prefer editing `lettabot.yaml` for `groups` config.
|
||||||
- `<CHANNEL>_GROUP_DEBOUNCE_SEC` (seconds, e.g. `5`)
|
- `<CHANNEL>_GROUP_DEBOUNCE_SEC` (seconds, e.g. `5`)
|
||||||
- `<CHANNEL>_GROUP_POLL_INTERVAL_MIN` (deprecated, use `_GROUP_DEBOUNCE_SEC` instead)
|
- `<CHANNEL>_GROUP_POLL_INTERVAL_MIN` (deprecated, use `_GROUP_DEBOUNCE_SEC` instead)
|
||||||
- `<CHANNEL>_INSTANT_GROUPS` (comma-separated)
|
- `<CHANNEL>_INSTANT_GROUPS` (comma-separated, legacy)
|
||||||
- `<CHANNEL>_LISTENING_GROUPS` (comma-separated)
|
- `<CHANNEL>_LISTENING_GROUPS` (comma-separated, legacy)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -201,8 +232,11 @@ channels:
|
|||||||
botToken: xoxb-...
|
botToken: xoxb-...
|
||||||
appToken: xapp-...
|
appToken: xapp-...
|
||||||
groupDebounceSec: 5
|
groupDebounceSec: 5
|
||||||
instantGroups: ["C0123456789"]
|
mentionPatterns: ["@mybot", "hey bot"]
|
||||||
listeningGroups: ["C0987654321"]
|
groups:
|
||||||
|
"*": { mode: mention-only }
|
||||||
|
"C0987654321": { mode: listen }
|
||||||
|
"C0123456789": { mode: open, allowedUsers: ["U123"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration File
|
## Configuration File
|
||||||
@@ -215,6 +249,10 @@ server:
|
|||||||
apiKey: letta_...
|
apiKey: letta_...
|
||||||
agentId: agent-...
|
agentId: agent-...
|
||||||
|
|
||||||
|
conversations:
|
||||||
|
mode: shared
|
||||||
|
heartbeat: last-active
|
||||||
|
|
||||||
channels:
|
channels:
|
||||||
telegram:
|
telegram:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ agent:
|
|||||||
# Note: model is configured on the Letta agent server-side.
|
# Note: model is configured on the Letta agent server-side.
|
||||||
# Use `lettabot model set <handle>` to change it.
|
# Use `lettabot model set <handle>` to change it.
|
||||||
|
|
||||||
|
# Conversation routing (optional)
|
||||||
|
conversations:
|
||||||
|
mode: shared # "shared" (default) or "per-channel"
|
||||||
|
heartbeat: last-active # "dedicated" | "last-active" | "<channel>"
|
||||||
|
|
||||||
# Channel configurations
|
# Channel configurations
|
||||||
channels:
|
channels:
|
||||||
telegram:
|
telegram:
|
||||||
@@ -149,6 +154,9 @@ agents:
|
|||||||
# displayName: "🔧 Work" # Optional: prefix outbound messages
|
# displayName: "🔧 Work" # Optional: prefix outbound messages
|
||||||
model: claude-sonnet-4
|
model: claude-sonnet-4
|
||||||
# id: agent-abc123 # Optional: use existing agent
|
# id: agent-abc123 # Optional: use existing agent
|
||||||
|
conversations:
|
||||||
|
mode: shared
|
||||||
|
heartbeat: last-active
|
||||||
channels:
|
channels:
|
||||||
telegram:
|
telegram:
|
||||||
token: ${WORK_TELEGRAM_TOKEN}
|
token: ${WORK_TELEGRAM_TOKEN}
|
||||||
@@ -164,6 +172,9 @@ agents:
|
|||||||
|
|
||||||
- name: personal-assistant
|
- name: personal-assistant
|
||||||
model: claude-sonnet-4
|
model: claude-sonnet-4
|
||||||
|
conversations:
|
||||||
|
mode: per-channel
|
||||||
|
heartbeat: dedicated
|
||||||
channels:
|
channels:
|
||||||
signal:
|
signal:
|
||||||
phone: "+1234567890"
|
phone: "+1234567890"
|
||||||
@@ -187,6 +198,7 @@ Each entry in `agents:` accepts:
|
|||||||
| `id` | string | No | Use existing agent ID (skips creation) |
|
| `id` | string | No | Use existing agent ID (skips creation) |
|
||||||
| `displayName` | string | No | Prefix outbound messages (e.g. `"💜 Signo"`) |
|
| `displayName` | string | No | Prefix outbound messages (e.g. `"💜 Signo"`) |
|
||||||
| `model` | string | No | Model for agent creation |
|
| `model` | string | No | Model for agent creation |
|
||||||
|
| `conversations` | object | No | Conversation routing config (shared vs per-channel) |
|
||||||
| `channels` | object | No | Channel configs (same schema as top-level `channels:`). At least one agent must have channels. |
|
| `channels` | object | No | Channel configs (same schema as top-level `channels:`). At least one agent must have channels. |
|
||||||
| `features` | object | No | Per-agent features (cron, heartbeat, maxToolCalls) |
|
| `features` | object | No | Per-agent features (cron, heartbeat, maxToolCalls) |
|
||||||
| `polling` | object | No | Per-agent polling config (Gmail, etc.) |
|
| `polling` | object | No | Per-agent polling config (Gmail, etc.) |
|
||||||
@@ -243,7 +255,9 @@ All channels share these common options:
|
|||||||
| `dmPolicy` | `'pairing'` \| `'allowlist'` \| `'open'` | Access control mode |
|
| `dmPolicy` | `'pairing'` \| `'allowlist'` \| `'open'` | Access control mode |
|
||||||
| `allowedUsers` | string[] | User IDs/numbers for allowlist mode |
|
| `allowedUsers` | string[] | User IDs/numbers for allowlist mode |
|
||||||
| `groupDebounceSec` | number | Debounce for group messages in seconds (default: 5, 0 = immediate) |
|
| `groupDebounceSec` | number | Debounce for group messages in seconds (default: 5, 0 = immediate) |
|
||||||
| `instantGroups` | string[] | Group/channel IDs that bypass debounce entirely |
|
| `instantGroups` | string[] | Group/channel IDs that bypass debounce entirely (legacy) |
|
||||||
|
| `groups` | object | Per-group configuration map (use `*` as default) |
|
||||||
|
| `mentionPatterns` | string[] | Extra regex patterns for mention detection (Telegram/WhatsApp/Signal) |
|
||||||
|
|
||||||
### Group Message Debouncing
|
### Group Message Debouncing
|
||||||
|
|
||||||
@@ -264,6 +278,31 @@ channels:
|
|||||||
|
|
||||||
The deprecated `groupPollIntervalMin` (minutes) still works for backward compatibility but `groupDebounceSec` takes priority.
|
The deprecated `groupPollIntervalMin` (minutes) still works for backward compatibility but `groupDebounceSec` takes priority.
|
||||||
|
|
||||||
|
### Conversation Routing
|
||||||
|
|
||||||
|
By default, all channels share a single conversation. You can split conversations per channel adapter.
|
||||||
|
|
||||||
|
**Single-agent config:**
|
||||||
|
```yaml
|
||||||
|
conversations:
|
||||||
|
mode: shared # "shared" (default) or "per-channel"
|
||||||
|
heartbeat: last-active # "dedicated" | "last-active" | "<channel>"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multi-agent config:**
|
||||||
|
```yaml
|
||||||
|
agents:
|
||||||
|
- name: work-assistant
|
||||||
|
conversations:
|
||||||
|
mode: per-channel
|
||||||
|
heartbeat: dedicated
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- `per-channel` means one conversation per **channel adapter** (telegram/slack/discord/etc), not per chat/user.
|
||||||
|
- Agent memory remains shared across channels; only the conversation history is separated.
|
||||||
|
- `heartbeat` controls which conversation background triggers use: a dedicated stream, the last active channel, or an explicit channel name.
|
||||||
|
|
||||||
### Group Modes
|
### Group Modes
|
||||||
|
|
||||||
Use `groups.<id>.mode` to control how each group/channel behaves:
|
Use `groups.<id>.mode` to control how each group/channel behaves:
|
||||||
|
|||||||
@@ -14,31 +14,24 @@ server:
|
|||||||
# mode: docker
|
# mode: docker
|
||||||
# baseUrl: http://localhost:8283
|
# baseUrl: http://localhost:8283
|
||||||
|
|
||||||
agent:
|
agents:
|
||||||
name: LettaBot
|
- name: LettaBot
|
||||||
# displayName: "💜 Signo" # Prefix outbound messages (useful in multi-agent group chats)
|
# displayName: "💜 Signo" # Prefix outbound messages (useful in multi-agent group chats)
|
||||||
# Note: model is configured on the Letta agent server-side.
|
# Note: model is configured on the Letta agent server-side.
|
||||||
# Select a model during `lettabot onboard` or change it with `lettabot model set <handle>`.
|
# Select a model during `lettabot onboard` or change it with `lettabot model set <handle>`.
|
||||||
|
|
||||||
# BYOK Providers (optional, api mode only)
|
# Conversation routing (optional)
|
||||||
# These will be synced to Letta API on startup
|
conversations:
|
||||||
# providers:
|
mode: shared # "shared" (default) or "per-channel"
|
||||||
# - id: anthropic
|
heartbeat: last-active # "dedicated" | "last-active" | "<channel>"
|
||||||
# name: lc-anthropic
|
|
||||||
# type: anthropic
|
|
||||||
# apiKey: sk-ant-YOUR-ANTHROPIC-KEY
|
|
||||||
# - id: openai
|
|
||||||
# name: lc-openai
|
|
||||||
# type: openai
|
|
||||||
# apiKey: sk-YOUR-OPENAI-KEY
|
|
||||||
|
|
||||||
channels:
|
channels:
|
||||||
telegram:
|
telegram:
|
||||||
enabled: true
|
enabled: true
|
||||||
token: YOUR-TELEGRAM-BOT-TOKEN
|
token: YOUR-TELEGRAM-BOT-TOKEN
|
||||||
dmPolicy: pairing # 'pairing', 'allowlist', or 'open'
|
dmPolicy: pairing # 'pairing', 'allowlist', or 'open'
|
||||||
# groupPollIntervalMin: 5 # Batch interval for group messages (default: 10)
|
# groupDebounceSec: 5 # Debounce seconds (default: 5, 0 = immediate)
|
||||||
# instantGroups: ["-100123456"] # Groups that bypass batching
|
# instantGroups: ["-100123456"] # Groups that bypass batching (legacy)
|
||||||
# Group access + response mode:
|
# Group access + response mode:
|
||||||
# groups:
|
# groups:
|
||||||
# "*": { mode: listen } # Observe all groups; only reply when @mentioned
|
# "*": { mode: listen } # Observe all groups; only reply when @mentioned
|
||||||
@@ -62,6 +55,18 @@ channels:
|
|||||||
# enabled: true
|
# enabled: true
|
||||||
# selfChat: false
|
# selfChat: false
|
||||||
|
|
||||||
|
# BYOK Providers (optional, api mode only)
|
||||||
|
# These will be synced to Letta API on startup
|
||||||
|
# providers:
|
||||||
|
# - id: anthropic
|
||||||
|
# name: lc-anthropic
|
||||||
|
# type: anthropic
|
||||||
|
# apiKey: sk-ant-YOUR-ANTHROPIC-KEY
|
||||||
|
# - id: openai
|
||||||
|
# name: lc-openai
|
||||||
|
# type: openai
|
||||||
|
# apiKey: sk-YOUR-OPENAI-KEY
|
||||||
|
|
||||||
features:
|
features:
|
||||||
cron: false
|
cron: false
|
||||||
heartbeat:
|
heartbeat:
|
||||||
|
|||||||
Reference in New Issue
Block a user