Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# TinyClaw Environment Variables
# Copy this file to .env and fill in your values

# Discord Bot Token
# Get one at: https://discord.com/developers/applications
DISCORD_BOT_TOKEN=your_discord_bot_token_here

# Telegram Bot Token
# Create a bot via @BotFather on Telegram
TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here

# Telnyx Voice Channel (Optional)
# Get your API key at: https://portal.telnyx.com/#/app/api-keys
TELNYX_API_KEY=your_telnyx_api_key_here
TELNYX_PUBLIC_KEY=your_telnyx_public_key_here
TELNYX_CONNECTION_ID=your_connection_id_here
TELNYX_PHONE_NUMBER=+15551234567

# Voice Webhook Configuration
TELNYX_WEBHOOK_PORT=8080
TELNYX_WEBHOOK_PATH=/telnyx-webhook
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Run multiple AI agents simultaneously with isolated workspaces and conversation
- ✅ **Multi-agent** - Run multiple isolated AI agents with specialized roles
- ✅ **Team collaboration** - Agents hand off work to teammates via chain execution and fan-out
- ✅ **Multiple AI providers** - Anthropic Claude (Sonnet/Opus) and OpenAI (GPT/Codex)
- ✅ **Multi-channel** - Discord, WhatsApp, and Telegram
- ✅ **Multi-channel** - Discord, WhatsApp, Telegram, and Voice (Telnyx/ClawdTalk)
- ✅ **Parallel processing** - Agents process messages concurrently
- ✅ **Live TUI dashboard** - Real-time team visualizer for monitoring agent chains
- ✅ **Persistent sessions** - Conversation context maintained across restarts
Expand Down Expand Up @@ -97,6 +97,16 @@ After starting TinyClaw, scan the QR code:
📱 Settings → Linked Devices → Link a Device
```

### Voice Setup (Telnyx/ClawdTalk)

1. Create a [Telnyx account](https://telnyx.com)
2. Create an API key at [Portal > API Keys](https://portal.telnyx.com/#/app/api-keys)
3. Configure a [Voice Profile](https://portal.telnyx.com/#/app/voice/profiles)
4. Purchase a [Phone Number](https://portal.telnyx.com/#/app/numbers)
5. Set webhook URL in your voice profile

See [docs/VOICE.md](docs/VOICE.md) for detailed setup instructions.

</details>

## 📋 Commands
Expand Down Expand Up @@ -187,7 +197,7 @@ export TINYCLAW_SKIP_UPDATE_CHECK=1

### In-Chat Commands

These commands work in Discord, Telegram, and WhatsApp:
These commands work in Discord, Telegram, WhatsApp, and Voice calls:

| Command | Description | Example |
| ------------------- | -------------------------------------------- | ------------------------------------ |
Expand Down Expand Up @@ -266,7 +276,7 @@ See [docs/AGENTS.md](docs/AGENTS.md) for:
```
┌─────────────────────────────────────────────────────────────┐
│ Message Channels │
(Discord, Telegram, WhatsApp, Heartbeat)
│ (Discord, Telegram, WhatsApp, Voice/Telnyx, Heartbeat) │
└────────────────────┬────────────────────────────────────────┘
│ Write message.json
Expand Down Expand Up @@ -454,6 +464,7 @@ All channels share agent conversations!
- [AGENTS.md](docs/AGENTS.md) - Agent management and routing
- [TEAMS.md](docs/TEAMS.md) - Team collaboration, chain execution, and visualizer
- [QUEUE.md](docs/QUEUE.md) - Queue system and message flow
- [VOICE.md](docs/VOICE.md) - Voice channel setup (Telnyx/ClawdTalk)
- [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) - Common issues and solutions

## 🐛 Troubleshooting
Expand Down Expand Up @@ -493,6 +504,7 @@ tinyclaw logs all
- Inspired by [OpenClaw](https://openclaw.ai/) by Peter Steinberger
- Built on [Claude Code](https://claude.com/claude-code) and [Codex CLI](https://docs.openai.com/codex)
- Uses [discord.js](https://discord.js.org/), [whatsapp-web.js](https://github.com/pedroslopez/whatsapp-web.js), [node-telegram-bot-api](https://github.com/yagop/node-telegram-bot-api)
- Voice powered by [Telnyx](https://telnyx.com) and [ClawdTalk](https://clawdtalk.com)

## 📄 License

Expand Down
203 changes: 203 additions & 0 deletions docs/VOICE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# Voice Channel (Telnyx/ClawdTalk)

TinyClaw supports voice calling capabilities through Telnyx, powered by ClawdTalk for AI voice interactions. This channel enables your agents to make and receive phone calls.

## Features

- **Inbound calls**: Receive calls on your Telnyx phone number
- **Outbound calls**: Make calls programmatically from agents
- **Text-to-speech**: Speak responses to callers
- **DTMF gathering**: Collect keypad input from callers
- **Call recording**: Optional recording of conversations
- **Multi-agent routing**: Route calls to specific agents with `@agent_id`

## Setup

### 1. Create a Telnyx Account

1. Sign up at [telnyx.com](https://telnyx.com)
2. Navigate to the [Portal](https://portal.telnyx.com)
3. Complete account verification

### 2. Create an API Key

1. Go to [API Keys](https://portal.telnyx.com/#/app/api-keys)
2. Click "Create API Key"
3. Save the key securely (you will need it for configuration)

### 3. Configure a Voice Profile

1. Go to [Voice > Profiles](https://portal.telnyx.com/#/app/voice/profiles)
2. Create a new voice profile
3. Note the **Connection ID** for configuration

### 4. Purchase a Phone Number

1. Go to [Phone Numbers](https://portal.telnyx.com/#/app/numbers)
2. Search for and purchase a number
3. Assign it to your voice profile
4. Note the number in E.164 format (e.g., `+15551234567`)

### 5. Configure Webhook

1. In your voice profile settings, set the webhook URL:
```
https://your-server.com:8080/telnyx-webhook
```
2. Ensure your server is accessible from the internet
3. Port 8080 is used by default (configurable via `TELNYX_WEBHOOK_PORT`)

### 6. Run Setup Wizard

```bash
tinyclaw setup
```

When prompted:
1. Select "Voice (Telnyx/ClawdTalk)" as a channel
2. Enter your Telnyx API key
3. Enter your Connection ID
4. Enter your phone number

## Environment Variables

The voice channel can also be configured via environment variables:

| Variable | Description | Required |
|----------|-------------|----------|
| `TELNYX_API_KEY` | Your Telnyx API key | Yes |
| `TELNYX_PUBLIC_KEY` | Your Telnyx public key (for webhook verification) | Recommended |
| `TELNYX_CONNECTION_ID` | Voice profile connection ID | For outbound calls |
| `TELNYX_PHONE_NUMBER` | Your Telnyx phone number (E.164) | For outbound calls |
| `TELNYX_WEBHOOK_PORT` | Webhook server port (default: 8080) | No |
| `TELNYX_WEBHOOK_PATH` | Webhook endpoint path (default: `/telnyx-webhook`) | No |

## Usage

### Inbound Calls

When someone calls your Telnyx number:
1. The call is automatically answered
2. A greeting is spoken to the caller
3. The call is routed to the default agent
4. Agent responses are spoken to the caller
5. DTMF input is collected and processed

### Outbound Calls

From the command line:
```bash
node dist/channels/telnyx-voice-client.js call +15551234567 "Hello, this is a test call"
```

From within an agent response:
```
[voice_call: +15551234567]
```

### Agent Routing

Route voice calls to specific agents:
- During a call, say `@agent_id` followed by your request
- Example: "Let me connect you to @coder for that technical question"

### DTMF Input

Callers can use their keypad to provide input:
- Press 1 for sales
- Press 2 for support
- etc.

The DTMF tones are captured and forwarded to the agent as text.

## Response Metadata

Agents can include special metadata in their responses to control the call:

```json
{
"message": "Thank you for calling. Goodbye!",
"metadata": {
"speak": "Thank you for calling. Goodbye!",
"hangup": true
}
}
```

| Field | Description |
|-------|-------------|
| `speak` | Text to speak to the caller |
| `hangup` | Whether to end the call after speaking |
| `gather` | Whether to collect DTMF input after speaking |

## ClawdTalk Integration

[ClawdTalk](https://clawdtalk.com) provides advanced voice AI capabilities for AI agents:

- Natural language understanding
- Real-time transcription
- Conversation flow management
- Multi-language support

To use ClawdTalk with your TinyClaw voice channel:
1. Sign up at [clawdtalk.com](https://clawdtalk.com)
2. Follow the integration guide at [github.com/team-telnyx/clawdtalk-client](https://github.com/team-telnyx/clawdtalk-client)
3. Configure your agent to use ClawdTalk for voice processing

## Troubleshooting

### Webhook Not Receiving Events

1. Verify your webhook URL is publicly accessible
2. Check firewall rules allow inbound connections on the webhook port
3. Verify the webhook URL matches what's configured in Telnyx portal

### Outbound Calls Failing

1. Verify `TELNYX_CONNECTION_ID` and `TELNYX_PHONE_NUMBER` are set
2. Check your Telnyx account has sufficient balance
3. Verify the destination number is in E.164 format

### Signature Verification Failing

1. Ensure `TELNYX_PUBLIC_KEY` is set correctly
2. Verify you're using the correct public key (not the API key)

## Logs

View voice channel logs:
```bash
tinyclaw logs voice
```

Or directly:
```bash
tail -f ~/.tinyclaw/logs/voice.log
```

## API Reference

The voice channel exports the following functions for programmatic use:

```typescript
import { makeOutboundCall, speakOnCall, hangupCall, gatherInput } from './channels/telnyx-voice-client';

// Make an outbound call
const callControlId = await makeOutboundCall('+15551234567', 'Hello from AI');

// Speak on an active call
await speakOnCall(callControlId, 'This is a test message');

// Gather DTMF input
await gatherInput(callControlId);

// Hang up a call
await hangupCall(callControlId);
```

## Resources

- [Telnyx Documentation](https://developers.telnyx.com)
- [Telnyx Node SDK](https://www.npmjs.com/package/@telnyx/node)
- [ClawdTalk](https://clawdtalk.com)
- [ClawdTalk Client](https://github.com/team-telnyx/clawdtalk-client)
13 changes: 11 additions & 2 deletions lib/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,35 @@ NC='\033[0m'
# --- Channel registry ---
# Single source of truth. Add new channels here and everything else adapts.

ALL_CHANNELS=(discord whatsapp telegram)
ALL_CHANNELS=(discord whatsapp telegram voice)

declare -A CHANNEL_DISPLAY=(
[discord]="Discord"
[whatsapp]="WhatsApp"
[telegram]="Telegram"
[voice]="Voice (Telnyx)"
)
declare -A CHANNEL_SCRIPT=(
[discord]="dist/channels/discord-client.js"
[whatsapp]="dist/channels/whatsapp-client.js"
[telegram]="dist/channels/telegram-client.js"
[voice]="dist/channels/telnyx-voice-client.js"
)
declare -A CHANNEL_ALIAS=(
[discord]="dc"
[whatsapp]="wa"
[telegram]="tg"
[voice]="vc"
)
declare -A CHANNEL_TOKEN_KEY=(
[discord]="discord_bot_token"
[telegram]="telegram_bot_token"
[voice]="api_key"
)
declare -A CHANNEL_TOKEN_ENV=(
[discord]="DISCORD_BOT_TOKEN"
[telegram]="TELEGRAM_BOT_TOKEN"
[voice]="TELNYX_API_KEY"
)

# Runtime state: filled by load_settings
Expand Down Expand Up @@ -105,7 +110,11 @@ load_settings() {
for ch in "${ALL_CHANNELS[@]}"; do
local token_key="${CHANNEL_TOKEN_KEY[$ch]:-}"
if [ -n "$token_key" ]; then
CHANNEL_TOKENS[$ch]=$(jq -r ".channels.${ch}.bot_token // empty" "$SETTINGS_FILE" 2>/dev/null)
if [ "$ch" = "voice" ]; then
CHANNEL_TOKENS[$ch]=$(jq -r ".channels.voice.api_key // empty" "$SETTINGS_FILE" 2>/dev/null)
else
CHANNEL_TOKENS[$ch]=$(jq -r ".channels.${ch}.bot_token // empty" "$SETTINGS_FILE" 2>/dev/null)
fi
fi
done

Expand Down
25 changes: 23 additions & 2 deletions lib/setup-wizard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,28 @@ echo ""

# --- Channel registry ---
# To add a new channel, add its ID here and fill in the config arrays below.
ALL_CHANNELS=(telegram discord whatsapp)
ALL_CHANNELS=(telegram discord whatsapp voice)

declare -A CHANNEL_DISPLAY=(
[telegram]="Telegram"
[discord]="Discord"
[whatsapp]="WhatsApp"
[voice]="Voice (Telnyx/ClawdTalk)"
)
declare -A CHANNEL_TOKEN_KEY=(
[discord]="discord_bot_token"
[telegram]="telegram_bot_token"
[voice]="telnyx_api_key"
)
declare -A CHANNEL_TOKEN_PROMPT=(
[discord]="Enter your Discord bot token:"
[telegram]="Enter your Telegram bot token:"
[voice]="Enter your Telnyx API key:"
)
declare -A CHANNEL_TOKEN_HELP=(
[discord]="(Get one at: https://discord.com/developers/applications)"
[telegram]="(Create a bot via @BotFather on Telegram to get a token)"
[voice]="(Get one at: https://portal.telnyx.com/#/app/api-keys)"
)

# Channel selection - simple checklist
Expand Down Expand Up @@ -265,6 +269,18 @@ CHANNELS_JSON="${CHANNELS_JSON}]"
# Build channel configs with tokens
DISCORD_TOKEN="${TOKENS[discord]:-}"
TELEGRAM_TOKEN="${TOKENS[telegram]:-}"
VOICE_API_KEY="${TOKENS[voice]:-}"

# Collect additional voice configuration if voice is enabled
VOICE_CONNECTION_ID=""
VOICE_PHONE_NUMBER=""
if [[ " ${ENABLED_CHANNELS[*]} " =~ " voice " ]] && [ -n "$VOICE_API_KEY" ]; then
echo ""
echo -e "${YELLOW}Voice channel configuration:${NC}"
echo ""
read -rp " Telnyx Connection ID: " VOICE_CONNECTION_ID
read -rp " Telnyx Phone Number (E.164 format, e.g., +15551234567): " VOICE_PHONE_NUMBER
fi

# Write settings.json with layered structure
# Use jq to build valid JSON to avoid escaping issues with agent prompts
Expand All @@ -288,7 +304,12 @@ cat > "$SETTINGS_FILE" <<EOF
"telegram": {
"bot_token": "${TELEGRAM_TOKEN}"
},
"whatsapp": {}
"whatsapp": {},
"voice": {
"api_key": "${VOICE_API_KEY}",
"connection_id": "${VOICE_CONNECTION_ID}",
"phone_number": "${VOICE_PHONE_NUMBER}"
}
},
${AGENTS_JSON}
${MODELS_SECTION},
Expand Down
Loading