825 lines
34 KiB
Markdown
825 lines
34 KiB
Markdown
---
|
||
name: clawdtalk-client
|
||
version: 2.0.0
|
||
description: ClawdTalk — Voice calls, SMS, and AI Missions for Clawdbot
|
||
metadata: {"clawdbot":{"emoji":"📞","primaryEnv":"CLAWDTALK_API_KEY","homepage":"https://github.com/team-telnyx/clawdtalk-client","requires":{"env":["CLAWDTALK_API_KEY"],"bins":["bash","node","jq","python3"],"config":["skill-config.json","~/.openclaw/openclaw.json","~/.clawdbot/clawdbot.json"]}}}
|
||
---
|
||
|
||
# ClawdTalk
|
||
|
||
> ⚠️ **First time setup?** Read `SETUP.md` in this directory before anything else. It walks you through the complete configuration flow step by step.
|
||
|
||
Voice calling, SMS messaging, and AI Missions for Clawdbot. Call your bot by phone, send texts, or run autonomous multi-step outreach campaigns — powered by ClawdTalk.
|
||
|
||
> **Trust:** By using this skill, voice transcripts, SMS messages, and mission data are sent to clawdtalk.com (operated by Telnyx). Only install if you trust this service with your conversation data.
|
||
|
||
## External Endpoints
|
||
|
||
| Endpoint | Used by | Data sent |
|
||
|----------|---------|-----------|
|
||
| `https://clawdtalk.com` (WebSocket) | `ws-client.js` | Voice transcripts, tool results, conversation state |
|
||
| `https://clawdtalk.com/v1/*` | `telnyx_api.py` | Mission state, events, scheduled calls/SMS, assistant configs |
|
||
| `http://127.0.0.1:<port>` | `ws-client.js` | Transcribed speech (local gateway only) |
|
||
| `https://raw.githubusercontent.com/team-telnyx/clawdtalk-client/...` | `update.sh` | None (download only) |
|
||
|
||
## Security & Privacy
|
||
|
||
- Voice transcripts and SMS content are transmitted to clawdtalk.com.
|
||
- Mission state and events are stored server-side for tracking and insights.
|
||
- `setup.sh` reads gateway config to extract connection details; with confirmation it adds a voice agent and `sessions_send` to `gateway.tools.allow`.
|
||
- API key is stored in `skill-config.json` — use env var `CLAWDTALK_API_KEY` or a `${CLAWDTALK_API_KEY}` reference to avoid plaintext storage.
|
||
|
||
---
|
||
|
||
# ⚠️ CRITICAL: SLUG CONSISTENCY
|
||
|
||
`init` auto-generates a slug from the mission name (lowercased, spaces → hyphens).
|
||
**Every command that takes a slug (`setup-agent`, `save-memory`, `complete`) MUST use the EXACT same slug.**
|
||
|
||
Mismatched slugs = agent not linked = scheduled events invisible on the frontend.
|
||
|
||
```bash
|
||
# After init, ALWAYS confirm the slug:
|
||
python scripts/telnyx_api.py list-state
|
||
# Output: find-window-washing-contractors: Find window washing contractors [running]
|
||
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ COPY-PASTE THIS. NEVER ABBREVIATE.
|
||
```
|
||
|
||
---
|
||
|
||
# ⚠️ CRITICAL: YOU OWN THE MISSION LIFECYCLE
|
||
|
||
**The server does NOT automatically update plan steps or mission status.** That is YOUR job as the bot. If you don't update steps and complete the mission, the UI will show "Running" forever with all steps "Pending".
|
||
|
||
## Your Responsibilities
|
||
|
||
For every mission, YOU must:
|
||
1. **Update plan steps** — mark each step `in_progress` → `completed` (or `failed`)
|
||
2. **Log events** — after every significant action
|
||
3. **Poll for completion** — check if scheduled calls/SMS finished
|
||
4. **Complete the mission** — mark the run as `succeeded` or `failed`
|
||
5. **Clean up** — remove any polling cron jobs when the mission ends
|
||
|
||
The UI reflects exactly what you tell it. No updates from you = no updates on screen.
|
||
|
||
---
|
||
|
||
# 🚨 MANDATORY: SAVE TO MEMORY AFTER EVERY ACTION
|
||
|
||
**Every significant action MUST be persisted using `save-memory` or `append-memory` IMMEDIATELY after the action succeeds.** The frontend reads from server memory. If you don't save it, it doesn't show up. `log-event` alone is NOT enough.
|
||
|
||
> **Rule: If you did something, save it to memory. No exceptions. No "I'll do it later." Do it NOW.**
|
||
|
||
Example (scheduling an SMS):
|
||
```bash
|
||
# 1. Schedule it
|
||
python scripts/telnyx_api.py schedule-sms $AID "$TO" "$FROM" "$DATETIME" "$MESSAGE" $MID $RID $STEP_ID
|
||
|
||
# 2. IMMEDIATELY save to memory
|
||
python scripts/telnyx_api.py append-memory "$SLUG" "scheduled_events" \
|
||
'{"event_id": "<id>", "type": "sms", "to": "<to>", "message": "<msg>", "scheduled_at": "<dt>", "step_id": "<step>"}'
|
||
|
||
# 3. Then log the event
|
||
python scripts/telnyx_api.py log-event $MID $RID custom "Scheduled SMS event_id=<id>" $STEP_ID
|
||
```
|
||
|
||
**Skipping step 2 is the #1 cause of "nothing shows on the frontend" bugs.**
|
||
|
||
---
|
||
|
||
# 🚨 MANDATORY: CHECK MISSION STATUS AFTER EVERY STEP
|
||
|
||
**After completing or failing ANY step, you MUST check whether the mission should be completed or failed.** Never leave a mission in "running" state when it's actually done or dead.
|
||
|
||
> **Rule: After every step change, ask yourself: is this mission finished?**
|
||
|
||
### Decision tree (run after EVERY step):
|
||
|
||
```
|
||
Step finished →
|
||
├── Succeeded?
|
||
│ ├── All steps done? → COMPLETE MISSION (update-run succeeded)
|
||
│ ├── More steps remain? → Continue to next step
|
||
│ └── Only verify left? → Set up polling cron
|
||
└── Failed?
|
||
├── Recoverable (retry/reschedule)? → Retry
|
||
└── Unrecoverable? → FAIL MISSION NOW:
|
||
1. update-step <step_id> failed
|
||
2. log-event error "Failed: <reason>" <step_id>
|
||
3. save-memory "$SLUG" "error_<step_id>" '{"error": "...", "recoverable": false}'
|
||
4. update-run $MID $RID failed
|
||
5. save-memory "$SLUG" "result" '{"status": "failed", "reason": "...", "failed_step": "..."}'
|
||
6. Clean up any polling cron jobs
|
||
```
|
||
|
||
**A mission stuck in "running" when it's actually done or dead is a bug. The user sees it and thinks work is still happening.**
|
||
|
||
---
|
||
|
||
# Architecture Overview
|
||
|
||
## How It Fits Together
|
||
|
||
```
|
||
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
|
||
│ You (Bot) │────▶│ ClawdTalk Server │────▶│ Telnyx API │
|
||
│ │ │ (dev/prod) │ │ (cloud) │
|
||
│ telnyx_api.py│ │ Local DB + proxy │ │ Executes │
|
||
│ │ │ to Telnyx │ │ calls/SMS │
|
||
└──────────────┘ └──────────────────┘ └──────────────┘
|
||
```
|
||
|
||
- **telnyx_api.py** — Python CLI script. Every command you run goes through this. It talks to the ClawdTalk server, never directly to Telnyx.
|
||
- **ClawdTalk Server** — Node.js backend. Stores missions, assistants, and events in a local Postgres DB. Proxies requests to the Telnyx API.
|
||
- **Telnyx API** — Cloud service. Actually makes the calls and sends the SMS at the scheduled time.
|
||
|
||
## Key Files
|
||
|
||
| File | Purpose |
|
||
|---|---|
|
||
| `scripts/telnyx_api.py` | CLI tool for all mission/assistant/event operations |
|
||
| `scripts/connect.sh` | WebSocket client for inbound voice call routing |
|
||
| `skill-config.json` | API key and server URL |
|
||
| `.missions_state.json` | Local state tracking for active missions |
|
||
| `.connect.log` | WebSocket connection logs |
|
||
|
||
## Two Sets of IDs
|
||
|
||
Every entity exists in two places with different IDs:
|
||
- **Local DB ID** — what the ClawdTalk server returns (e.g. `3df24dde-...`)
|
||
- **Telnyx ID** — what the Telnyx API uses internally
|
||
|
||
The script always works with local IDs. You don't need to worry about Telnyx IDs.
|
||
|
||
---
|
||
|
||
## Quick Start
|
||
|
||
1. **Sign up** at [clawdtalk.com](https://clawdtalk.com)
|
||
2. **Add your phone** in Settings
|
||
3. **Get API key** from Dashboard
|
||
4. **Run setup**: `./setup.sh`
|
||
> `setup.sh` reads your gateway config to extract connection details, adds a voice agent to `agents.list`, and (with confirmation) adds `sessions_send` to `gateway.tools.allow`. Gateway config is at `~/.openclaw/openclaw.json` or `~/.clawdbot/clawdbot.json`.
|
||
5. **Start connection**: `./scripts/connect.sh start`
|
||
|
||
## Voice Calls
|
||
|
||
The WebSocket client routes calls to your gateway's main agent session, giving full access to memory, tools, and context.
|
||
|
||
```bash
|
||
./scripts/connect.sh start # Start connection
|
||
./scripts/connect.sh stop # Stop
|
||
./scripts/connect.sh status # Check status
|
||
```
|
||
|
||
### Outbound Calls
|
||
|
||
Have the bot call you or others:
|
||
|
||
```bash
|
||
./scripts/call.sh # Call your phone
|
||
./scripts/call.sh "Hey, what's up?" # Call with greeting
|
||
./scripts/call.sh --to +15551234567 # Call external number*
|
||
./scripts/call.sh --to +15551234567 "Hello!" # External with greeting
|
||
./scripts/call.sh status <call_id> # Check call status
|
||
./scripts/call.sh end <call_id> # End call
|
||
```
|
||
|
||
*External calls require a paid account with a dedicated number. The AI will operate in privacy mode when calling external numbers (won't reveal your private info).
|
||
|
||
## SMS
|
||
|
||
Send and receive text messages:
|
||
|
||
```bash
|
||
./scripts/sms.sh send +15551234567 "Hello!"
|
||
./scripts/sms.sh list
|
||
./scripts/sms.sh conversations
|
||
```
|
||
|
||
## AI Missions (Full Tracking via Python)
|
||
|
||
For complex, multi-step missions with full tracking, state persistence, retries, and conversation insights, use the Python-based missions API.
|
||
|
||
**Required**: Python 3.7+, `CLAWDTALK_API_KEY` environment variable. Optionally set `CLAWDTALK_API_URL` to override the default endpoint (defaults to `https://clawdtalk.com/v1`).
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py check-key # Verify setup
|
||
```
|
||
|
||
# CRITICAL: SAVE STATE FREQUENTLY
|
||
|
||
**You MUST save your progress after EVERY significant action.** If the session crashes or restarts, unsaved work is LOST.
|
||
|
||
## Two-Layer Persistence: Memory + Events
|
||
|
||
Always save to BOTH:
|
||
1. **Local Memory** (`.missions_state.json`) - Fast, survives restarts
|
||
2. **Events API** (cloud) - Permanent audit trail, survives local file loss
|
||
|
||
## When to Save (After EVERY action!)
|
||
|
||
| Action | Save Memory | Log Event |
|
||
|--------|-------------|-----------|
|
||
| Web search returns results | append-memory | log-event (tool_call) |
|
||
| Found a contractor/lead | append-memory | log-event (custom) |
|
||
| Created assistant | save-memory | log-event (custom) |
|
||
| Assigned phone number | save-memory | log-event (custom) |
|
||
| Scheduled a call/SMS | append-memory | log-event (custom) |
|
||
| Call completed | save-memory | log-event (custom) |
|
||
| Got quote/insight | save-memory | log-event (custom) |
|
||
| Made a decision | save-memory | log-event (message) |
|
||
| Step started | save-memory | update-step (in_progress) + log-event (step_started) |
|
||
| Step completed | save-memory | update-step (completed) + log-event (step_completed) |
|
||
| Step failed | save-memory | update-step (failed) + log-event (error) |
|
||
| Error occurred | save-memory | log-event (error) |
|
||
|
||
## Memory Commands (Local Backup)
|
||
|
||
```bash
|
||
# Save a single value
|
||
python scripts/telnyx_api.py save-memory "<slug>" "key" '{"data": "value"}'
|
||
|
||
# Append to a list (great for collecting multiple items)
|
||
python scripts/telnyx_api.py append-memory "<slug>" "contractors" '{"name": "ABC Co", "phone": "+1234567890"}'
|
||
|
||
# Retrieve memory
|
||
python scripts/telnyx_api.py get-memory "<slug>" # Get all memory
|
||
python scripts/telnyx_api.py get-memory "<slug>" "key" # Get specific key
|
||
```
|
||
|
||
## Event Commands (Cloud Backup)
|
||
|
||
```bash
|
||
# Log an event (step_id is REQUIRED - links event to a plan step)
|
||
python scripts/telnyx_api.py log-event <mission_id> <run_id> <type> "<summary>" <step_id> '[payload_json]'
|
||
|
||
# Event types: tool_call, custom, message, error, step_started, step_completed
|
||
# step_id: Use the step_id from your plan (e.g., "research", "setup", "calls")
|
||
# Use "-" if event doesn't belong to a specific step
|
||
```
|
||
|
||
---
|
||
|
||
## When to Use Missions
|
||
|
||
This skill has two modes: **full missions** (tracked, multi-step) and **simple calls** (one-off, no mission overhead). Pick the right one.
|
||
|
||
### Use a Full Mission When:
|
||
- The task involves **multiple calls or SMS** (batch outreach, surveys, sweeps)
|
||
- You need a **complete audit trail** with events, plans, and state tracking
|
||
- The task is **multi-step** and takes significant effort across phases
|
||
- **Retries and failure tracking** matter
|
||
- You need to **compare results** across multiple calls
|
||
|
||
Examples:
|
||
- "Find me window washing contractors in Chicago, call them and negotiate rates"
|
||
- "Contact all leads in this list and schedule demos"
|
||
- "Call 10 weather stations and find the hottest one"
|
||
|
||
### Do NOT Use a Mission When:
|
||
- The task is a **single outbound call** — just create an assistant (or reuse one) and schedule the call directly
|
||
- It's a **one-off SMS** — schedule it and done
|
||
- The task doesn't need tracking, plans, or state recovery
|
||
- You'd be creating a mission with one step and one call — that's overengineering
|
||
|
||
**For simple calls, just:**
|
||
```bash
|
||
# Reuse or create an assistant
|
||
python scripts/telnyx_api.py list-assistants --name=<relevant>
|
||
# Schedule the call
|
||
python scripts/telnyx_api.py schedule-call <assistant_id> <to> <from> <datetime> <mission_id> <run_id>
|
||
# Poll for completion
|
||
python scripts/telnyx_api.py get-event <assistant_id> <event_id>
|
||
# Get insights
|
||
python scripts/telnyx_api.py get-insights <conversation_id>
|
||
```
|
||
|
||
No mission, no run, no plan. Keep it simple.
|
||
|
||
## State Persistence
|
||
|
||
The script automatically manages state in `.missions_state.json`. This survives restarts and supports multiple concurrent missions.
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py list-state # List all active missions
|
||
python scripts/telnyx_api.py get-state "find-window-washing-contractors" # Get state for specific mission
|
||
python scripts/telnyx_api.py remove-state "find-window-washing-contractors" # Remove mission from state
|
||
```
|
||
|
||
---
|
||
|
||
# Core Workflow
|
||
|
||
## Phase 1: Initialize Tracking
|
||
|
||
### Step 1.1: Create a Mission
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py create-mission "Brief descriptive name" "Full description of the task"
|
||
```
|
||
|
||
**Save the returned `mission_id`** - you'll need it for all subsequent calls.
|
||
|
||
### Step 1.2: Start a Run
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py create-run <mission_id> '{"original_request": "The exact user request", "context": "Any relevant context"}'
|
||
```
|
||
|
||
**Save the returned `run_id`**.
|
||
|
||
### Step 1.3: Create a Plan
|
||
|
||
Before executing, outline your plan:
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py create-plan <mission_id> <run_id> '[
|
||
{"step_id": "step_1", "description": "Research contractors online", "sequence": 1},
|
||
{"step_id": "step_2", "description": "Create voice agent for calls", "sequence": 2},
|
||
{"step_id": "step_3", "description": "Schedule calls to each contractor", "sequence": 3},
|
||
{"step_id": "step_4", "description": "Monitor call completions", "sequence": 4},
|
||
{"step_id": "step_5", "description": "Analyze results and select best options", "sequence": 5}
|
||
]'
|
||
```
|
||
|
||
### Step 1.4: Set Run to Running
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py update-run <mission_id> <run_id> running
|
||
```
|
||
|
||
### High-Level Alternative: Initialize Everything at Once
|
||
|
||
Use the `init` command to create mission, run, plan, and set status in one step:
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py init "Find window washing contractors" "Find contractors in Chicago, call them, negotiate rates" "User wants window washing quotes" '[
|
||
{"step_id": "research", "description": "Find contractors online", "sequence": 1},
|
||
{"step_id": "setup", "description": "Create voice agent", "sequence": 2},
|
||
{"step_id": "calls", "description": "Schedule and make calls", "sequence": 3},
|
||
{"step_id": "analyze", "description": "Analyze results", "sequence": 4}
|
||
]'
|
||
```
|
||
|
||
This also automatically resumes if a mission with the same name already exists.
|
||
|
||
**⚠️ Immediately after `init`, run `list-state` and copy the exact slug. Use it for ALL subsequent commands.**
|
||
|
||
---
|
||
|
||
## Phase 2: Voice/SMS Agent Setup
|
||
|
||
When your task requires making calls or sending SMS, create an AI assistant first.
|
||
|
||
### Step 2.1: Create a Voice/SMS Assistant
|
||
|
||
**For phone calls:**
|
||
```bash
|
||
python scripts/telnyx_api.py create-assistant "Contractor Outreach Agent" "You are calling on behalf of [COMPANY]. Your goal is to [SPECIFIC GOAL]. Be professional and concise. Collect: [WHAT TO COLLECT]. If they cannot talk now, ask for a good callback time." "Hi, this is an AI assistant calling on behalf of [COMPANY]. Is this [BUSINESS NAME]? I am calling to inquire about your services. Do you have a moment?" '["telephony", "messaging"]'
|
||
```
|
||
|
||
**For SMS:**
|
||
```bash
|
||
python scripts/telnyx_api.py create-assistant "SMS Outreach Agent" "You send SMS messages to collect information. Keep messages brief and professional." "Hi! I am reaching out on behalf of [COMPANY] regarding [PURPOSE]. Could you please reply with [REQUESTED INFO]?" '["telephony", "messaging"]'
|
||
```
|
||
|
||
**Save the returned `assistant_id`**.
|
||
|
||
### Step 2.2: Find and Assign a Phone Number
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py get-available-phone # Get first available
|
||
python scripts/telnyx_api.py get-connection-id <assistant_id> telephony # Get connection ID
|
||
python scripts/telnyx_api.py assign-phone <phone_number_id> <connection_id> voice # Assign
|
||
```
|
||
|
||
### High-Level Alternative: Setup Agent in One Step
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py setup-agent "find-window-washing-contractors" "Contractor Caller" "You are calling to get quotes for commercial window washing. Ask about: rates per floor, availability, insurance. Be professional." "Hi, I am calling to inquire about your commercial window washing services. Do you have a moment to discuss rates?"
|
||
```
|
||
|
||
This automatically creates the assistant, links it to the mission run, finds an available phone number, assigns it, and saves all IDs to the state file.
|
||
|
||
**⚠️ The slug MUST match what `init` created. If it doesn't, the agent won't be linked and scheduled events won't appear on the frontend.**
|
||
|
||
**Verify linking worked immediately after:**
|
||
```bash
|
||
python scripts/telnyx_api.py list-linked-agents <mission_id> <run_id>
|
||
# Must show your assistant_id. If empty → slug was wrong. Fix with:
|
||
python scripts/telnyx_api.py link-agent <mission_id> <run_id> <assistant_id>
|
||
```
|
||
|
||
### Step 2.3: Link Agent to Mission Run
|
||
|
||
**If using `setup-agent`**: Linking is done automatically (only if slug matches `init`).
|
||
|
||
**If setting up manually**:
|
||
```bash
|
||
python scripts/telnyx_api.py link-agent <mission_id> <run_id> <assistant_id>
|
||
python scripts/telnyx_api.py list-linked-agents <mission_id> <run_id>
|
||
python scripts/telnyx_api.py unlink-agent <mission_id> <run_id> <assistant_id>
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 3: Scheduling Calls/SMS
|
||
|
||
### Business Hours Consideration
|
||
|
||
**CRITICAL**: Before scheduling calls, consider business hours (9 AM - 5 PM local time). `scheduled_at` must be in the future (at least 1 minute from now).
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py schedule-call <assistant_id> "+15551234567" "+15559876543" "2024-12-01T14:30:00Z" <mission_id> <run_id>
|
||
python scripts/telnyx_api.py schedule-sms <assistant_id> "+15551234567" "+15559876543" "2024-12-01T14:30:00Z" "Your message here"
|
||
```
|
||
|
||
**Save the returned event `id`**.
|
||
|
||
---
|
||
|
||
## Phase 4: Monitoring Call Completion
|
||
|
||
### ⚠️ THIS IS THE MOST IMPORTANT PART
|
||
|
||
After scheduling a call or SMS, **Telnyx executes it autonomously** at the scheduled time. You need to **poll** to find out when it's done, then update the mission accordingly.
|
||
|
||
### Check Scheduled Event Status
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py get-event <assistant_id> <event_id>
|
||
```
|
||
|
||
### Use Cron Jobs to Poll
|
||
|
||
Use your bot's cron system to schedule polling. **Do NOT block the main session waiting.** Match the poll interval to the expected wait time:
|
||
|
||
| Expected completion | Poll interval | Example |
|
||
|---|---|---|
|
||
| < 5 minutes | Every 30 seconds | SMS sent 1 min from now |
|
||
| 5–30 minutes | Every 2–5 minutes | Call scheduled in 15 min |
|
||
| 1–24 hours | Every 15–30 minutes | Call scheduled for tonight |
|
||
| Days/weeks | Every 4–8 hours | Call scheduled for next week |
|
||
|
||
**If you know the exact scheduled time**, don't start polling until after that time. Schedule your first poll for `scheduled_time + 2 minutes`.
|
||
|
||
### Cron Job Pattern
|
||
|
||
When you schedule a call/SMS, create a cron job to poll for it:
|
||
|
||
```
|
||
Create cron: poll at appropriate interval
|
||
→ Run get-event <assistant_id> <event_id>
|
||
→ If completed: update step, log event, complete mission if last step, DELETE THIS CRON
|
||
→ If failed: update step as failed, log error, DELETE THIS CRON
|
||
→ If pending/in_progress: do nothing, cron runs again at next interval
|
||
```
|
||
|
||
**⚠️ ALWAYS clean up cron jobs when a mission reaches a terminal state (completed, failed, cancelled). Never leave polling crons running after a mission ends.**
|
||
|
||
### Adjusting Poll Frequency
|
||
|
||
You can update the cron interval as circumstances change:
|
||
- Scheduled for 2 weeks from now? Start with 8-hour polling.
|
||
- As the scheduled time approaches (within 1 hour), tighten to 5-minute intervals.
|
||
- After the scheduled time passes, tighten to 30-second intervals.
|
||
|
||
### Event Status Values
|
||
|
||
| Status | Meaning | Action |
|
||
|--------|---------|--------|
|
||
| `pending` | Waiting for scheduled time | Keep polling |
|
||
| `in_progress` | Call/SMS in progress | Keep polling |
|
||
| `completed` | Finished successfully | Update step, get insights if call |
|
||
| `failed` | Failed after retries | Update step as failed, consider retry |
|
||
|
||
### Call Status Values (Phone Calls Only)
|
||
|
||
| call_status | Meaning | Action |
|
||
|-------------|---------|--------|
|
||
| `ringing` | Phone is ringing | Poll again in 1-2 minutes |
|
||
| `in-progress` | Call is active | Poll again in 2-3 minutes |
|
||
| `completed` | Call finished normally | Get insights |
|
||
| `no-answer` | Nobody picked up | **Retryable** — reschedule |
|
||
| `busy` | Line is busy | **Retryable** — retry in 10-15 min |
|
||
| `canceled` | Call was canceled | Check if intentional |
|
||
| `failed` | Network/system error | **Retryable** — retry in 5-10 min |
|
||
|
||
---
|
||
|
||
## Phase 5: Getting Conversation Insights
|
||
|
||
Once a call completes with a `conversation_id`, retrieve insights. **Poll until status is "completed"** (wait 10 seconds between retries).
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py get-insights <conversation_id>
|
||
```
|
||
|
||
Telnyx automatically creates default insight templates when an assistant is created. You don't need to manage these — just read the results.
|
||
|
||
---
|
||
|
||
## Phase 6: Complete the Mission
|
||
|
||
```bash
|
||
python scripts/telnyx_api.py update-run <mission_id> <run_id> succeeded
|
||
|
||
# Or with full results:
|
||
python scripts/telnyx_api.py complete "find-window-washing-contractors" <mission_id> <run_id> "Summary of results" '{"key": "payload"}'
|
||
```
|
||
|
||
---
|
||
|
||
# Event Logging Reference
|
||
|
||
**Log EVERY action as an event.** Always update step status via `update-step` AND log corresponding events.
|
||
|
||
```bash
|
||
# When STARTING a step:
|
||
python scripts/telnyx_api.py update-step "$MISSION_ID" "$RUN_ID" "research" "in_progress"
|
||
python scripts/telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" step_started "Starting: Research" "research"
|
||
|
||
# When COMPLETING a step:
|
||
python scripts/telnyx_api.py update-step "$MISSION_ID" "$RUN_ID" "research" "completed"
|
||
python scripts/telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" step_completed "Completed: Research" "research"
|
||
|
||
# When a step FAILS:
|
||
python scripts/telnyx_api.py update-step "$MISSION_ID" "$RUN_ID" "calls" "failed"
|
||
python scripts/telnyx_api.py log-event "$MISSION_ID" "$RUN_ID" error "Failed: Could not reach contractors" "calls"
|
||
```
|
||
|
||
---
|
||
|
||
# Quick Reference: All Python Commands
|
||
|
||
```bash
|
||
# Check setup
|
||
python scripts/telnyx_api.py check-key
|
||
|
||
# Missions
|
||
python scripts/telnyx_api.py create-mission <name> <instructions>
|
||
python scripts/telnyx_api.py get-mission <mission_id>
|
||
python scripts/telnyx_api.py list-missions
|
||
|
||
# Runs
|
||
python scripts/telnyx_api.py create-run <mission_id> <input_json>
|
||
python scripts/telnyx_api.py get-run <mission_id> <run_id>
|
||
python scripts/telnyx_api.py update-run <mission_id> <run_id> <status>
|
||
python scripts/telnyx_api.py list-runs <mission_id>
|
||
|
||
# Plan
|
||
python scripts/telnyx_api.py create-plan <mission_id> <run_id> <steps_json>
|
||
python scripts/telnyx_api.py get-plan <mission_id> <run_id>
|
||
python scripts/telnyx_api.py update-step <mission_id> <run_id> <step_id> <status>
|
||
|
||
# Events
|
||
python scripts/telnyx_api.py log-event <mission_id> <run_id> <type> <summary> <step_id> [payload_json]
|
||
python scripts/telnyx_api.py list-events <mission_id> <run_id>
|
||
|
||
# Assistants
|
||
python scripts/telnyx_api.py list-assistants [--name=<filter>] [--page=<n>] [--size=<n>]
|
||
python scripts/telnyx_api.py create-assistant <name> <instructions> <greeting> [options_json]
|
||
python scripts/telnyx_api.py get-assistant <assistant_id>
|
||
python scripts/telnyx_api.py update-assistant <assistant_id> <updates_json>
|
||
python scripts/telnyx_api.py get-connection-id <assistant_id> [telephony|messaging]
|
||
|
||
# Phone Numbers
|
||
python scripts/telnyx_api.py list-phones [--available]
|
||
python scripts/telnyx_api.py get-available-phone
|
||
python scripts/telnyx_api.py assign-phone <phone_id> <connection_id> [voice|sms]
|
||
|
||
# Scheduled Events
|
||
python scripts/telnyx_api.py schedule-call <assistant_id> <to> <from> <datetime> <mission_id> <run_id>
|
||
python scripts/telnyx_api.py schedule-sms <assistant_id> <to> <from> <datetime> <text>
|
||
python scripts/telnyx_api.py get-event <assistant_id> <event_id>
|
||
python scripts/telnyx_api.py cancel-scheduled-event <assistant_id> <event_id>
|
||
python scripts/telnyx_api.py list-events-assistant <assistant_id>
|
||
|
||
# Insights
|
||
python scripts/telnyx_api.py get-insights <conversation_id>
|
||
|
||
# Mission Run Agents
|
||
python scripts/telnyx_api.py link-agent <mission_id> <run_id> <telnyx_agent_id>
|
||
python scripts/telnyx_api.py list-linked-agents <mission_id> <run_id>
|
||
python scripts/telnyx_api.py unlink-agent <mission_id> <run_id> <telnyx_agent_id>
|
||
|
||
# State Management
|
||
python scripts/telnyx_api.py list-state
|
||
python scripts/telnyx_api.py get-state <slug>
|
||
python scripts/telnyx_api.py remove-state <slug>
|
||
|
||
# Memory
|
||
python scripts/telnyx_api.py save-memory <slug> <key> <value_json>
|
||
python scripts/telnyx_api.py get-memory <slug> [key]
|
||
python scripts/telnyx_api.py append-memory <slug> <key> <item_json>
|
||
|
||
# High-Level Workflows
|
||
python scripts/telnyx_api.py init <name> <instructions> <request> [steps_json]
|
||
python scripts/telnyx_api.py setup-agent <slug> <name> <instructions> <greeting>
|
||
python scripts/telnyx_api.py complete <slug> <mission_id> <run_id> <summary> [payload_json]
|
||
```
|
||
|
||
---
|
||
|
||
# Complete Example: SMS Mission with Cron Polling
|
||
|
||
Here's the full flow for an SMS mission with proper lifecycle tracking and cron-based polling:
|
||
|
||
```bash
|
||
# 1. Init mission
|
||
python scripts/telnyx_api.py init "SMS Test 003" \
|
||
"Send a test SMS to +13322200013" \
|
||
"SMS test with full tracking" \
|
||
'[{"step_id": "setup", "description": "Create SMS agent", "sequence": 1},
|
||
{"step_id": "sms", "description": "Schedule SMS", "sequence": 2},
|
||
{"step_id": "verify", "description": "Verify delivery", "sequence": 3}]'
|
||
# Save: mission_id, run_id
|
||
|
||
# 2. Step 1: Setup agent
|
||
python scripts/telnyx_api.py update-step $MISSION_ID $RUN_ID setup in_progress
|
||
python scripts/telnyx_api.py log-event $MISSION_ID $RUN_ID step_started "Starting: Create SMS agent" setup
|
||
|
||
python scripts/telnyx_api.py setup-agent "sms-test-003" "SMS Agent" "Send test messages" "Test from bot"
|
||
# Save: assistant_id, phone_number
|
||
|
||
python scripts/telnyx_api.py update-step $MISSION_ID $RUN_ID setup completed
|
||
python scripts/telnyx_api.py log-event $MISSION_ID $RUN_ID step_completed "Completed: Created assistant $ASSISTANT_ID" setup
|
||
|
||
# 3. Step 2: Schedule SMS
|
||
python scripts/telnyx_api.py update-step $MISSION_ID $RUN_ID sms in_progress
|
||
python scripts/telnyx_api.py log-event $MISSION_ID $RUN_ID step_started "Starting: Schedule SMS" sms
|
||
|
||
python scripts/telnyx_api.py schedule-sms $ASSISTANT_ID "+13322200013" "$PHONE" "2026-02-19T18:43:00Z" \
|
||
"What do you call a bear with no teeth? A gummy bear!" \
|
||
$MISSION_ID $RUN_ID sms
|
||
# Save: event_id
|
||
|
||
python scripts/telnyx_api.py update-step $MISSION_ID $RUN_ID sms completed
|
||
python scripts/telnyx_api.py log-event $MISSION_ID $RUN_ID step_completed "Completed: SMS scheduled" sms
|
||
|
||
# 4. Step 3: Verify delivery — CREATE A CRON JOB TO POLL
|
||
python scripts/telnyx_api.py update-step $MISSION_ID $RUN_ID verify in_progress
|
||
python scripts/telnyx_api.py log-event $MISSION_ID $RUN_ID step_started "Starting: Poll for delivery" verify
|
||
|
||
# >>> Create a cron job that fires AFTER the scheduled time <<<
|
||
# >>> Cron runs: get-event $ASSISTANT_ID $EVENT_ID <<<
|
||
# >>> On completed: update-step verify completed, log-event, update-run succeeded, DELETE CRON <<<
|
||
# >>> On failed: update-step verify failed, log-event, update-run failed, DELETE CRON <<<
|
||
# >>> On pending/in_progress: do nothing, cron fires again next interval <<<
|
||
|
||
# 5. (Cron fires, detects completion)
|
||
python scripts/telnyx_api.py update-step $MISSION_ID $RUN_ID verify completed
|
||
python scripts/telnyx_api.py log-event $MISSION_ID $RUN_ID step_completed "Completed: SMS delivered" verify
|
||
python scripts/telnyx_api.py update-run $MISSION_ID $RUN_ID succeeded
|
||
# DELETE the polling cron job!
|
||
```
|
||
|
||
---
|
||
|
||
# Mission Classes
|
||
|
||
Not all missions are the same. Identify which class before planning.
|
||
|
||
```
|
||
Does call N depend on results of call N-1?
|
||
YES -> Is it negotiation (leveraging previous results)?
|
||
YES -> Class 3: Sequential Negotiation
|
||
NO -> Does it have distinct rounds with human approval?
|
||
YES -> Class 4: Multi-Round / Follow-up
|
||
NO -> Class 5: Information Gathering -> Action
|
||
NO -> Do you need structured scoring/ranking?
|
||
YES -> Class 2: Parallel Screening with Rubric
|
||
NO -> Class 1: Parallel Sweep
|
||
```
|
||
|
||
## Class 1: Parallel Sweep
|
||
Fan out calls in parallel batches. Same question to many targets. Schedule all calls in one batch (stagger by 1-2 min). Analysis happens after ALL calls complete.
|
||
|
||
## Class 2: Parallel Screening with Rubric
|
||
Fan out calls in parallel with structured scoring criteria. Results are ranked post-hoc via insights.
|
||
|
||
## Class 3: Sequential Negotiation
|
||
Calls MUST run serially. Each call's strategy depends on previous results. Use `update-assistant` between calls to inject context. **Never parallelize these.**
|
||
|
||
## Class 4: Multi-Round / Follow-up
|
||
Two or more distinct phases. Round 1 is broad outreach, human approval gate, then Round 2 targets a subset.
|
||
|
||
## Class 5: Information Gathering -> Action
|
||
Call to find something, then act on it. Early termination when goal is met — cancel remaining calls.
|
||
|
||
---
|
||
|
||
# Operational Guide
|
||
|
||
## Default Tools
|
||
The `send_dtmf` tool is included by default. Most outbound calls hit an IVR first.
|
||
|
||
## IVR Navigation
|
||
Expect IVRs even when calling businesses. Instruct the assistant to press 0 or say 'representative'.
|
||
|
||
## Call Limits and Throttling
|
||
Stagger calls in batches of 5-10, space scheduled times 1-2 minutes apart, monitor for 429 errors.
|
||
|
||
## Answering Machine Detection (AMD)
|
||
- **Enable** for human contacts (leave voicemail or skip machines)
|
||
- **Disable** for IVR systems, businesses with phone trees — set action to `continue_assistant`
|
||
|
||
## Polling for Results: Use Cron Jobs
|
||
After scheduling calls, set up a cron job to poll periodically. Don't block the main session.
|
||
|
||
## Retry Strategy
|
||
Track every number's status in mission memory. Retry based on recipient type:
|
||
- **Automated systems**: retry in 5-15 min, up to 3 times
|
||
- **Service industry**: retry in 30 min - 2 hours, avoid peak hours
|
||
- **Professionals**: retry next business day, leave one voicemail max
|
||
|
||
---
|
||
|
||
## Approval Requests (Sensitive Actions)
|
||
|
||
For destructive or sensitive actions during voice calls, request user approval first:
|
||
|
||
```bash
|
||
./scripts/approval.sh request "Delete GitHub repo myproject"
|
||
./scripts/approval.sh request "Send $500 to John" --biometric
|
||
./scripts/approval.sh request "Post tweet about X" --details "Full text: ..."
|
||
```
|
||
|
||
**When to request approval:**
|
||
- Deleting repos, files, or data
|
||
- Sending money or making purchases
|
||
- Posting to social media
|
||
- Sending emails/messages to others
|
||
- Any irreversible action
|
||
|
||
**Response values:**
|
||
- `approved` → Execute the action, confirm completion
|
||
- `denied` → Tell user "Okay, I won't do that"
|
||
- `timeout` → "I didn't get a response, should I try again?"
|
||
- `no_devices` → Skip approval, action not executed (no mobile app)
|
||
|
||
**Example flow in voice call:**
|
||
1. User: "Delete my test-repo on GitHub"
|
||
2. You: "I'll need your approval for that. Check your phone."
|
||
3. Run: `approval.sh request "Delete GitHub repo test-repo"`
|
||
4. If approved: Delete the repo, then say "Done, test-repo has been deleted"
|
||
5. If denied: "Got it, I won't delete it"
|
||
|
||
## Gateway Requirements
|
||
|
||
Voice calls route requests to the main agent via `sessions_send`. This tool is **blocked by default** on the Gateway HTTP tools API. You must explicitly allow it:
|
||
|
||
```json5
|
||
// In openclaw.json → gateway.tools
|
||
{
|
||
"gateway": {
|
||
"tools": {
|
||
"allow": ["sessions_send"]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
Or via CLI: `openclaw config patch '{"gateway":{"tools":{"allow":["sessions_send"]}}}'`
|
||
|
||
Without this, voice calls will connect but the agent won't be able to process any requests (deep tool calls return 404).
|
||
|
||
> ⚠️ **WARNING:** This MUST go under `gateway.tools.allow`, NOT top-level `tools.allow`. The top-level `tools.allow` is the agent's tool allowlist — putting `sessions_send` there will restrict your agent to ONLY that tool, breaking everything. If you accidentally did this, remove the top-level `tools.allow` entry and restart.
|
||
|
||
## ❌ Common Pitfalls
|
||
|
||
| Mistake | Symptom | Fix |
|
||
|---------|---------|-----|
|
||
| Different slug for `init` vs `setup-agent` | Scheduled events missing from frontend | `list-state` after `init`, copy-paste slug |
|
||
| Forgetting `save-memory` after actions | Frontend shows nothing | Save immediately after every action |
|
||
| Not checking mission status after step changes | Mission stuck "running" forever | Run decision tree after every step |
|
||
| Leaving polling crons running | Wasted resources, stale polls | Delete cron on any terminal state |
|
||
| Not verifying `list-linked-agents` after `setup-agent` | Agent not linked, events invisible | Always verify, fix with `link-agent` |
|
||
|
||
## Configuration
|
||
|
||
Edit `skill-config.json`:
|
||
|
||
| Option | Description |
|
||
|--------|-------------|
|
||
| `api_key` | API key from clawdtalk.com |
|
||
| `server` | Server URL (default: `https://clawdtalk.com`) |
|
||
| `owner_name` | Your name (auto-detected from USER.md) |
|
||
| `agent_name` | Agent name (auto-detected from IDENTITY.md) |
|
||
| `greeting` | Custom greeting for inbound calls |
|
||
|
||
Environment variables for the Python missions API:
|
||
- `CLAWDTALK_API_KEY` — your ClawdTalk API key (required for missions)
|
||
- `CLAWDTALK_API_URL` — override the API endpoint (default: `https://clawdtalk.com/v1`)
|
||
|
||
## Troubleshooting
|
||
|
||
- **Auth failed**: Regenerate API key at clawdtalk.com
|
||
- **Gateway token/port changed**: Re-run `./setup.sh` to update skill-config.json with the new values
|
||
- **Empty responses**: Run `./setup.sh` and restart gateway
|
||
- **Slow responses**: Try a faster model in your gateway config
|
||
- **Debug mode**: `DEBUG=1 ./scripts/connect.sh restart`
|
||
- **Missions API key**: Run `python scripts/telnyx_api.py check-key` to verify
|
||
- **JSON parsing errors**: Use single quotes around JSON arguments
|