- Replace python-dotenv with config.json env.vars block + \ substitution - Add models section for per-task model routing (heartbeat, subagent, default) - Heartbeat/subagent tasks can use different models/providers than main chat - Remove python-dotenv from dependencies - Update all docs to reflect new config approach - Reorganize docs into project/ and research/ subdirectories
327 lines
8.6 KiB
Markdown
327 lines
8.6 KiB
Markdown
# Discord Advanced Features
|
|
|
|
All Discord features are config-driven via `~/.aetheel/config.json` under the `discord` key. No code changes needed.
|
|
|
|
---
|
|
|
|
## Default Config
|
|
|
|
```json
|
|
{
|
|
"discord": {
|
|
"enabled": false,
|
|
"listen_channels": [],
|
|
"reply_to_mode": "first",
|
|
"history_enabled": true,
|
|
"history_limit": 20,
|
|
"channel_overrides": {},
|
|
"ack_reaction": "👀",
|
|
"typing_indicator": true,
|
|
"reaction_mode": "own",
|
|
"exec_approvals": false,
|
|
"exec_approval_tools": ["Bash", "Write", "Edit"],
|
|
"slash_commands": true,
|
|
"components_enabled": true
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Reply Threading
|
|
|
|
Controls whether the bot replies to the user's message using Discord's native reply feature (the quoted message above the response).
|
|
|
|
```json
|
|
"reply_to_mode": "first"
|
|
```
|
|
|
|
| Value | Behavior |
|
|
|-------|----------|
|
|
| `"off"` | Plain messages, no reply reference |
|
|
| `"first"` | First chunk of the response replies to the user's message |
|
|
| `"all"` | Every chunk replies to the user's message |
|
|
|
|
If the original message gets deleted before the bot responds, it falls back to a plain message automatically.
|
|
|
|
---
|
|
|
|
## Channel History Context
|
|
|
|
Injects recent channel messages into the AI's system prompt so it has conversational context beyond the current message.
|
|
|
|
```json
|
|
"history_enabled": true,
|
|
"history_limit": 20
|
|
```
|
|
|
|
- `history_enabled` — global toggle, default `true`
|
|
- `history_limit` — number of recent messages to fetch, default `20`
|
|
- History is only fetched for guild channels, not DMs (DMs already have session continuity)
|
|
- Messages are formatted as `[username]: content` and injected under a "Recent Channel History" section in the system prompt
|
|
- The bot's own messages appear as `[assistant]`
|
|
|
|
### Per-Channel Overrides
|
|
|
|
You can enable, disable, or change the limit per channel:
|
|
|
|
```json
|
|
"channel_overrides": {
|
|
"1234567890": {
|
|
"history_enabled": true,
|
|
"history_limit": 50
|
|
},
|
|
"9876543210": {
|
|
"history_enabled": false
|
|
}
|
|
}
|
|
```
|
|
|
|
Keys are Discord channel IDs (strings). Any field you omit falls back to the global default.
|
|
|
|
Use cases:
|
|
- Disable history in a high-traffic channel to save context window
|
|
- Increase the limit in a project channel where long context matters
|
|
- Disable entirely for a channel where privacy is a concern
|
|
|
|
---
|
|
|
|
## Ack Reactions
|
|
|
|
Adds a reaction emoji to the user's message while the bot is processing, then removes it when the response is sent. Gives immediate visual feedback that the bot received the message.
|
|
|
|
```json
|
|
"ack_reaction": "👀"
|
|
```
|
|
|
|
- Set to any valid emoji: `"👀"`, `"⏳"`, `"🤔"`, etc.
|
|
- Set to `""` (empty string) to disable
|
|
- The reaction is removed automatically after the response is sent
|
|
- If the bot lacks Add Reactions permission in a channel, it silently skips
|
|
|
|
---
|
|
|
|
## Typing Indicator
|
|
|
|
Shows the "Aetheel is typing..." indicator in the channel while the AI processes the message.
|
|
|
|
```json
|
|
"typing_indicator": true
|
|
```
|
|
|
|
- `true` — typing indicator shown during processing (default)
|
|
- `false` — no typing indicator
|
|
|
|
The indicator stays active for the entire duration of the AI call. Combined with ack reactions, users get two layers of feedback: the reaction appears instantly, and the typing indicator persists until the response arrives.
|
|
|
|
---
|
|
|
|
## Reaction Handling
|
|
|
|
Controls whether the bot processes emoji reactions as messages to the AI.
|
|
|
|
```json
|
|
"reaction_mode": "own"
|
|
```
|
|
|
|
| Value | Behavior |
|
|
|-------|----------|
|
|
| `"off"` | Reactions are ignored entirely |
|
|
| `"own"` | Only reactions on the bot's own messages are processed |
|
|
| `"all"` | Reactions on any message in the channel are processed |
|
|
|
|
When a reaction is processed, it's sent to the AI as:
|
|
```
|
|
[Reaction: 👍 on message: <original message text>]
|
|
```
|
|
|
|
The AI can then respond contextually — for example, a 👎 on a suggestion could prompt the bot to offer alternatives.
|
|
|
|
Bot reactions and reactions from other bots are always ignored.
|
|
|
|
---
|
|
|
|
## Slash Commands
|
|
|
|
Registers native Discord slash commands that appear in the `/` menu.
|
|
|
|
```json
|
|
"slash_commands": true
|
|
```
|
|
|
|
### Available Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `/ask <message>` | Ask Aetheel a question. Shows "thinking..." while processing. |
|
|
| `/status` | Check bot status (same as typing `status` in chat) |
|
|
| `/help` | Show help (same as typing `help` in chat) |
|
|
|
|
Commands are synced with Discord on bot startup. First sync can take up to an hour to propagate globally — guild-level commands appear faster.
|
|
|
|
Set to `false` to disable slash command registration entirely.
|
|
|
|
### Bot Permissions
|
|
|
|
For slash commands to work, the bot must be invited with the `applications.commands` OAuth2 scope in addition to `bot`. If you originally invited without it, re-invite using:
|
|
|
|
OAuth2 → URL Generator → Scopes: `bot`, `applications.commands`
|
|
|
|
---
|
|
|
|
## Interactive Components
|
|
|
|
Enables the bot to send messages with buttons and select menus.
|
|
|
|
```json
|
|
"components_enabled": true
|
|
```
|
|
|
|
Components are used internally by:
|
|
- Exec approval prompts (approve/deny buttons)
|
|
- Any future interactive features
|
|
|
|
The adapter exposes `send_components_message()` for programmatic use:
|
|
|
|
```python
|
|
adapter.send_components_message(
|
|
channel_id="123456789",
|
|
text="Choose an option:",
|
|
buttons=[
|
|
{"label": "Option A", "style": "primary", "custom_id": "opt_a"},
|
|
{"label": "Option B", "style": "secondary", "custom_id": "opt_b"},
|
|
{"label": "Delete", "style": "danger", "custom_id": "delete"},
|
|
],
|
|
select_options=[
|
|
{"label": "Python", "value": "python", "description": "Snake language"},
|
|
{"label": "TypeScript", "value": "ts", "description": "JS but typed"},
|
|
],
|
|
callback=my_callback_fn,
|
|
)
|
|
```
|
|
|
|
Button styles: `primary` (blurple), `secondary` (gray), `success` (green), `danger` (red).
|
|
|
|
Set to `false` to disable — approval prompts and interactive messages fall back to plain text.
|
|
|
|
---
|
|
|
|
## Exec Approvals
|
|
|
|
Adds a human-in-the-loop confirmation step for dangerous AI tool use. When the AI tries to use a gated tool, a button prompt appears in the channel asking the user to approve or deny.
|
|
|
|
```json
|
|
"exec_approvals": false,
|
|
"exec_approval_tools": ["Bash", "Write", "Edit"]
|
|
```
|
|
|
|
- `exec_approvals` — master toggle, default `false`
|
|
- `exec_approval_tools` — list of tool names that require approval
|
|
|
|
### How It Works
|
|
|
|
1. AI decides to use a gated tool (e.g. `Bash`)
|
|
2. Bot sends an embed with approve/deny buttons:
|
|
```
|
|
⚠️ Exec Approval Required
|
|
Tool: Bash
|
|
Action: <description of what the AI wants to do>
|
|
[✅ Approve] [❌ Deny]
|
|
```
|
|
3. Only the user who sent the original message can click the buttons
|
|
4. If approved, the tool executes normally
|
|
5. If denied or timed out (2 minutes), the action is blocked
|
|
|
|
### Customizing Gated Tools
|
|
|
|
Add or remove tools from the approval list:
|
|
|
|
```json
|
|
"exec_approval_tools": ["Bash", "Write", "Edit", "WebFetch"]
|
|
```
|
|
|
|
Tools not in this list are auto-approved. Set the list to `[]` to approve everything (while keeping the feature enabled for future use).
|
|
|
|
---
|
|
|
|
## Listen Channels
|
|
|
|
Channels where the bot responds to all messages without requiring an @mention.
|
|
|
|
```json
|
|
"listen_channels": ["1234567890", "9876543210"]
|
|
```
|
|
|
|
In all other guild channels, the bot only responds when @mentioned. DMs always respond to all messages regardless of this setting.
|
|
|
|
You can also set this via environment variable:
|
|
```bash
|
|
DISCORD_LISTEN_CHANNELS=1234567890,9876543210
|
|
```
|
|
|
|
---
|
|
|
|
## Required Bot Permissions
|
|
|
|
For all features to work, invite the bot with these permissions:
|
|
|
|
| Permission | Required For |
|
|
|------------|-------------|
|
|
| Send Messages | Responding to users |
|
|
| Read Message History | History context injection |
|
|
| View Channels | Seeing channels |
|
|
| Add Reactions | Ack reactions |
|
|
| Use External Emojis | Custom ack reaction emojis |
|
|
| Embed Links | Exec approval prompts |
|
|
|
|
OAuth2 scopes: `bot`, `applications.commands`
|
|
|
|
Privileged intents (in Developer Portal → Bot):
|
|
- Message Content Intent (required)
|
|
- Server Members Intent (recommended)
|
|
|
|
---
|
|
|
|
## Example Configs
|
|
|
|
### Minimal (just the basics)
|
|
```json
|
|
{
|
|
"discord": {
|
|
"enabled": true
|
|
}
|
|
}
|
|
```
|
|
Uses all defaults: reply threading on first message, history on, ack 👀, typing on, reactions on own messages, slash commands on.
|
|
|
|
### Privacy-focused
|
|
```json
|
|
{
|
|
"discord": {
|
|
"enabled": true,
|
|
"history_enabled": false,
|
|
"ack_reaction": "",
|
|
"reaction_mode": "off",
|
|
"slash_commands": false
|
|
}
|
|
}
|
|
```
|
|
|
|
### Full control with approvals
|
|
```json
|
|
{
|
|
"discord": {
|
|
"enabled": true,
|
|
"reply_to_mode": "all",
|
|
"history_limit": 50,
|
|
"ack_reaction": "⏳",
|
|
"exec_approvals": true,
|
|
"exec_approval_tools": ["Bash", "Write", "Edit", "WebFetch"],
|
|
"channel_overrides": {
|
|
"123456789": { "history_limit": 100 },
|
|
"987654321": { "history_enabled": false }
|
|
}
|
|
}
|
|
}
|
|
```
|