Files
ajarbot/docs/README_ADAPTERS.md
Jordan Ramos a99799bf3d Initial commit: Ajarbot with optimizations
Features:
- Multi-platform bot (Slack, Telegram)
- Memory system with SQLite FTS
- Tool use capabilities (file ops, commands)
- Scheduled tasks system
- Dynamic model switching (/sonnet, /haiku)
- Prompt caching for cost optimization

Optimizations:
- Default to Haiku 4.5 (12x cheaper)
- Reduced context: 3 messages, 2 memory results
- Optimized SOUL.md (48% smaller)
- Automatic caching when using Sonnet (90% savings)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-13 19:06:28 -07:00

387 lines
11 KiB
Markdown

# Ajarbot Multi-Platform Adapters
This document describes the adapter system that allows ajarbot to run on multiple messaging platforms simultaneously (Slack, Telegram, and more).
## Architecture Overview
The adapter system is inspired by [OpenClaw's](https://github.com/chloebt/openclaw) sophisticated plugin-based architecture but simplified for ajarbot's needs:
```
┌─────────────────────────────────────────────────────────┐
│ Bot Runner │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Adapter Runtime │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Slack │ │ Telegram │ ... │ │
│ │ │ Adapter │ │ Adapter │ │ │
│ │ └──────┬───────┘ └──────┬───────┘ │ │
│ │ │ │ │ │
│ │ └────────┬────────┘ │ │
│ │ │ │ │
│ │ ┌───────▼───────┐ │ │
│ │ │ Agent Core │ │ │
│ │ │ (Memory+LLM) │ │ │
│ │ └───────────────┘ │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### Key Components
1. **BaseAdapter** (`adapters/base.py`)
- Abstract interface that all platform adapters implement
- Defines capabilities (threads, reactions, media, markdown, etc.)
- Handles message chunking based on platform limits
- Manages message handler registration
2. **AdapterRuntime** (`adapters/runtime.py`)
- Connects messaging adapters to the Agent
- Manages message queue and async processing
- Handles user ID mapping (platform → ajarbot username)
- Supports preprocessors and postprocessors
3. **AdapterRegistry** (`adapters/base.py`)
- Manages multiple adapter instances
- Provides lookup by platform name
- Handles bulk start/stop operations
4. **ConfigLoader** (`config/config_loader.py`)
- Loads adapter configuration from YAML
- Supports environment variable overrides
- Separates secrets (`.local.yaml`) from templates
## Supported Platforms
### ✅ Slack (Socket Mode)
**Features:**
- Socket Mode (no webhooks needed)
- Thread support
- Reactions
- Media/file attachments
- Markdown (mrkdwn)
- 4000 character limit
**Configuration:**
```yaml
slack:
enabled: true
credentials:
bot_token: "xoxb-..."
app_token: "xapp-..."
settings:
auto_react_emoji: "thinking_face" # Optional
```
**Setup Steps:**
1. Go to https://api.slack.com/apps
2. Create new app → "From scratch"
3. Enable **Socket Mode** (Settings → Socket Mode)
4. Generate **App-Level Token** with `connections:write` scope
5. Add **Bot Token Scopes**:
- `chat:write`
- `channels:history`
- `groups:history`
- `im:history`
- `mpim:history`
- `app_mentions:read`
6. Install app to workspace
7. Copy **Bot User OAuth Token** (xoxb-...) and **App-Level Token** (xapp-...)
### ✅ Telegram
**Features:**
- Direct polling (no webhooks)
- Reactions (new API)
- Media/file attachments
- Markdown or HTML
- 4096 character limit
- User allowlist support
**Configuration:**
```yaml
telegram:
enabled: true
credentials:
bot_token: "123456:ABC-DEF..."
settings:
allowed_users: [] # Optional: [123456789]
parse_mode: "Markdown" # or "HTML"
```
**Setup Steps:**
1. Open Telegram and message [@BotFather](https://t.me/botfather)
2. Send `/newbot`
3. Follow prompts (choose name and username)
4. Copy the bot token
5. (Optional) Configure privacy settings with `/setprivacy`
## Quick Start
### 1. Install Dependencies
```bash
pip install -r requirements.txt
```
### 2. Generate Configuration Template
```bash
python bot_runner.py --init
```
This creates `config/adapters.local.yaml` with a template.
### 3. Edit Configuration
Edit `config/adapters.local.yaml`:
```yaml
adapters:
slack:
enabled: true # Change to true
credentials:
bot_token: "xoxb-YOUR-ACTUAL-TOKEN"
app_token: "xapp-YOUR-ACTUAL-TOKEN"
telegram:
enabled: true # Change to true
credentials:
bot_token: "YOUR-ACTUAL-BOT-TOKEN"
```
### 4. Run the Bot
```bash
python bot_runner.py
```
**Output:**
```
============================================================
🤖 Ajarbot Multi-Platform Runner
============================================================
[Setup] Initializing agent...
[Setup] ✓ Agent initialized
[Setup] Loading Slack adapter...
[Setup] ✓ Slack adapter loaded
[Setup] Loading Telegram adapter...
[Setup] ✓ Telegram adapter loaded
[Setup] ✓ 2 adapter(s) configured
============================================================
🚀 Starting bot...
============================================================
[Slack] Starting Socket Mode connection...
[Slack] ✓ Connected and listening for messages
[Telegram] Starting bot...
[Telegram] ✓ Bot started: @your_bot (Your Bot Name)
[Runtime] Message processing loop started
============================================================
✓ Bot is running! Press Ctrl+C to stop.
============================================================
```
## Environment Variables (Alternative to YAML)
You can use environment variables instead of or in addition to the YAML config:
```bash
export AJARBOT_SLACK_BOT_TOKEN="xoxb-..."
export AJARBOT_SLACK_APP_TOKEN="xapp-..."
export AJARBOT_TELEGRAM_BOT_TOKEN="123456:ABC..."
python bot_runner.py
```
Environment variables take precedence over YAML configuration.
## User Mapping
Map platform user IDs to ajarbot usernames for memory consistency:
```yaml
user_mapping:
slack:U12345ABCDE: "alice"
telegram:123456789: "alice"
```
Now when Alice messages from either Slack or Telegram, the bot will use the same memory profile.
## Advanced Usage
### Custom Preprocessors
Add custom logic before messages reach the Agent:
```python
from adapters.runtime import AdapterRuntime
from adapters.base import InboundMessage
def my_preprocessor(message: InboundMessage) -> InboundMessage:
# Example: Auto-expand abbreviations
if message.text == "status":
message.text = "What is your current status?"
return message
runtime.add_preprocessor(my_preprocessor)
```
### Custom Postprocessors
Modify responses before sending to platforms:
```python
def my_postprocessor(response: str, original: InboundMessage) -> str:
# Example: Add platform-specific formatting
if original.platform == "slack":
response = response.replace("**", "*") # Bold
return response
runtime.add_postprocessor(my_postprocessor)
```
### Health Checks
```bash
python bot_runner.py --health
```
Output:
```
============================================================
Health Check
============================================================
Runtime running: True
Adapters:
SLACK:
platform: slack
running: True
healthy: True
bot_id: B12345
team: T12345
connected: True
TELEGRAM:
platform: telegram
running: True
healthy: True
bot_id: 123456789
username: your_bot
connected: True
```
## Adding New Adapters
To add support for a new platform (Discord, WhatsApp, etc.):
1. **Create adapter file** `adapters/newplatform/adapter.py`
2. **Inherit from BaseAdapter** and implement required methods:
- `platform_name` property
- `capabilities` property
- `validate_config()`
- `start()` / `stop()`
- `send_message()`
3. **Register in bot_runner.py**
4. **Add config section** to `adapters.yaml`
Example skeleton:
```python
from adapters.base import BaseAdapter, AdapterConfig, AdapterCapabilities
class NewPlatformAdapter(BaseAdapter):
@property
def platform_name(self) -> str:
return "newplatform"
@property
def capabilities(self) -> AdapterCapabilities:
return AdapterCapabilities(
supports_threads=True,
max_message_length=2000
)
def validate_config(self) -> bool:
return bool(self.config.credentials.get("api_key"))
async def start(self):
# Initialize connection
self.is_running = True
async def stop(self):
# Cleanup
self.is_running = False
async def send_message(self, message: OutboundMessage):
# Send message to platform
return {"success": True, "message_id": "123"}
```
## Comparison with OpenClaw
| Feature | OpenClaw | Ajarbot Adapters |
|---------|----------|------------------|
| **Architecture** | Plugin-based with 12+ sub-adapters per channel | Simplified single-adapter per platform |
| **Type System** | TypeScript with structural typing | Python with ABC/dataclasses |
| **Adapters** | config, gateway, outbound, status, security, pairing, etc. | Combined into BaseAdapter |
| **Registry** | Two-tier (DOCKS + plugin registry) | Single AdapterRegistry |
| **Scope** | 20+ platforms, enterprise features | Core platforms, essential features |
| **Complexity** | High (production-grade) | Medium (developer-friendly) |
### What We Adopted from OpenClaw
**Plugin-based architecture** - Each platform is self-contained
**Capability declarations** - Platforms declare what they support
**Consistent interfaces** - All adapters implement the same contract
**Gateway pattern** - start/stop lifecycle management
**Outbound adapter** - Message sending abstraction
**Status/health checks** - Monitoring and diagnostics
**Chunking strategies** - Platform-aware text splitting
### What We Simplified
🔄 **Single adapter class** instead of 12+ sub-adapters
🔄 **Python dataclasses** instead of TypeScript interfaces
🔄 **YAML config** instead of complex config system
🔄 **Direct integration** instead of full plugin loading system
## Troubleshooting
### "No adapters enabled"
- Check that `enabled: true` in your config
- Verify credentials are set correctly
- Try running with `--init` to regenerate template
### Slack: "invalid_auth"
- Ensure `bot_token` starts with `xoxb-`
- Ensure `app_token` starts with `xapp-`
- Verify app is installed to workspace
### Telegram: Bot not responding
- Check bot token is correct (from @BotFather)
- Ensure no other instance is polling the same bot
- Check `allowed_users` setting isn't blocking you
### Import errors
```bash
pip install -r requirements.txt --upgrade
```
## License
Same as ajarbot (check main repository).
## Credits
Adapter architecture inspired by [OpenClaw](https://github.com/chloebt/openclaw) by Chloe.