Add send-file directive and Discord/CLI file support (#319)

Co-authored-by: Jason Carreira <jason@visotrust.com>
Co-authored-by: Cameron <cameron@pfiffer.org>
Co-authored-by: Charles Packer <packercharles@gmail.com>
Co-authored-by: Sarah Wooders <sarahwooders@gmail.com>
Co-authored-by: Letta <noreply@letta.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Carreira
2026-02-23 18:44:34 -05:00
committed by GitHub
parent ad4c22ba54
commit 1fbd6d5a2e
14 changed files with 364 additions and 22 deletions

View File

@@ -10,6 +10,7 @@ Send a message to the most recent chat, or target a specific channel/chat.
```bash
lettabot-message send --text "Hello from a background task"
lettabot-message send --text "Hello" --channel slack --chat C123456
lettabot-message send --file /tmp/report.pdf --text "Report attached" --channel discord --chat 123456789
```
## lettabot-react
@@ -34,3 +35,4 @@ Notes:
- History fetch is not supported by the Telegram Bot API, Signal, or WhatsApp.
- If you omit `--channel` or `--chat`, the CLI falls back to the last message target stored in `lettabot-agent.json`.
- You need the channel-specific bot token set (`DISCORD_BOT_TOKEN` or `SLACK_BOT_TOKEN`).
- File sending uses the API server and requires `LETTABOT_API_KEY` (supported: telegram, slack, discord, whatsapp).

View File

@@ -455,6 +455,21 @@ Precedence: `prompt` (inline YAML) > `HEARTBEAT_PROMPT` (env var) > `promptFile`
| `features.heartbeat.prompt` | string | _(none)_ | Custom heartbeat prompt text |
| `features.heartbeat.promptFile` | string | _(none)_ | Path to prompt file (relative to working dir) |
### Send-File Directory
The `<send-file>` [response directive](./directives.md) allows the agent to send files to channels. For security, file paths are restricted to a configurable directory:
```yaml
features:
sendFileDir: ./data/outbound # Default: agent working directory
```
Only files inside this directory (and its subdirectories) can be sent. Paths that resolve outside it are blocked. This prevents prompt injection attacks from exfiltrating sensitive files.
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `features.sendFileDir` | string | _(workingDir)_ | Directory that `<send-file>` paths must be inside |
### Cron Jobs
```yaml

View File

@@ -41,6 +41,28 @@ Adds an emoji reaction to a message.
- Unicode emoji: direct characters like `👍`
- `message` (optional) -- Target message ID. Defaults to the message that triggered the response.
### `<send-file>`
Sends a file or image to the same channel/chat as the triggering message.
```xml
<send-file path="/tmp/report.pdf" caption="Report attached" />
<send-file path="/tmp/photo.png" kind="image" caption="Look!" />
<send-file path="/tmp/temp-export.csv" cleanup="true" />
```
**Attributes:**
- `path` / `file` (required) -- Local file path on the LettaBot server
- `caption` / `text` (optional) -- Caption text for the file
- `kind` (optional) -- `image` or `file` (defaults to auto-detect based on extension)
- `cleanup` (optional) -- `true` to delete the file after sending (default: false)
**Security:**
- File paths are restricted to the configured `sendFileDir` directory (defaults to `data/outbound/` under the agent's working directory). Paths outside this directory are blocked and logged.
- Symlinks that resolve outside the allowed directory are also blocked.
- File size is limited to `sendFileMaxSize` (default: 50MB).
- The `cleanup` attribute only works when `sendFileCleanup: true` is set in the agent's features config (disabled by default).
### `<no-reply/>`
Suppresses response delivery entirely. The agent's text is discarded.
@@ -66,13 +88,13 @@ Backslash-escaped quotes (common when LLMs generate XML inside a JSON context) a
## Channel Support
| Channel | `addReaction` | Notes |
|-----------|:---:|-------|
| Telegram | Yes | Limited to Telegram's [allowed reaction set](https://core.telegram.org/bots/api#reactiontype) (~75 emoji) |
| Slack | Yes | Uses Slack emoji names (`:thumbsup:` style). Custom workspace emoji supported. |
| Discord | Yes | Unicode emoji and common aliases. Custom server emoji not yet supported. |
| WhatsApp | No | Directive is skipped with a warning |
| Signal | No | Directive is skipped with a warning |
| Channel | `addReaction` | `send-file` | Notes |
|-----------|:---:|:---:|-------|
| Telegram | Yes | Yes | Reactions limited to Telegram's [allowed reaction set](https://core.telegram.org/bots/api#reactiontype). |
| Slack | Yes | Yes | Reactions use Slack emoji names (`:thumbsup:` style). |
| Discord | Yes | Yes | Custom server emoji not yet supported. |
| WhatsApp | No | Yes | Reactions skipped with a warning. |
| Signal | No | No | Directive skipped with a warning. |
When a channel doesn't implement `addReaction`, the directive is silently skipped and a warning is logged. This never blocks message delivery.
@@ -112,7 +134,7 @@ The parser (`src/core/directives.ts`) is designed to be extensible. Adding a new
3. Add a parsing case in `parseChildDirectives()`
4. Add an execution case in `executeDirectives()` in `bot.ts`
See issue [#240](https://github.com/letta-ai/lettabot/issues/240) for planned directives like `<send-file>`.
See issue [#240](https://github.com/letta-ai/lettabot/issues/240) for planned directives.
## Source