Telephony Service
Phone voice interface via Pipecat + Twilio Media Streams.
Last updated: 2026-01-03 Status: ✅ Production
Verified 2026-01-03
Test call from +15127812507:
- ✅ Caller identified: Nathan Walker
- ✅ User ID resolved: 701973d2-57e4-4c84-a2ec-ded996dcf676
- ✅ Task creation: "Add five trash bags to the shopping list"
- ✅ Task stored in PostgreSQL with domain: Household Operations
Overview
The telephony service enables phone calls to Norns using:
- Twilio - PSTN connectivity and phone number
- Pipecat - Voice AI pipeline framework
- Deepgram - Speech-to-text (STT)
- GPT-4o-mini - Lightweight routing LLM
- ElevenLabs - Text-to-speech (TTS)
Architecture
Phone Call --> Twilio PSTN --> HTTPS Webhook --> telephony service
|
+------------------------+
|
Twilio Media Streams (WebSocket)
|
v
+-------------------+
| Pipecat |
| Voice Pipeline |
+-------------------+
|
+-----------------+-----------------+
| | |
v v v
Deepgram STT GPT-4o-mini ElevenLabs TTS
| | ^
+--------> delegate_to_norns -------+
|
v
Norns Agent
Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/twilio/webhook | POST | Twilio call webhook (returns TwiML) |
/twilio/stream | WebSocket | Twilio Media Streams audio |
/health | GET | Health check |
Caller Identification
The service identifies callers by looking up their phone number:
async def get_user_for_call(caller_phone: str) -> tuple[str, str]:
user = await lookup_user_by_phone(caller_phone)
if user:
return user["user_id"], user["display_name"]
return DEFAULT_USER_ID, "Unknown Caller"
This calls the Norns API endpoint:
GET /api/users/by-phone/{phone_number}
Environment Variables
| Variable | Description |
|---|---|
WEBHOOK_HOST | Public hostname (telephony.ravenhelm.dev) |
NORNS_URL | Norns API URL (http://docs/AI-ML-Platform/norns-agent:8000) |
NORNS_API_KEY | API key for Norns authentication |
TWILIO_ACCOUNT_SID | Twilio account SID |
TWILIO_AUTH_TOKEN | Twilio auth token |
DEEPGRAM_API_KEY | Deepgram STT API key |
OPENAI_API_KEY | OpenAI API key (for GPT-4o-mini) |
ELEVENLABS_API_KEY | ElevenLabs TTS API key |
ELEVENLABS_VOICE_ID | ElevenLabs voice ID |
Twilio Configuration
- Phone Number: +1 (737) 214-3330
- Voice Webhook:
https://telephony.ravenhelm.dev/twilio/webhook - Method: POST
Delegate Function
The GPT-4o-mini uses a single tool to delegate to Norns:
delegate_function = FunctionSchema(
name="delegate_to_norns",
description="Delegate any request to Norns. Pass the user exact words verbatim.",
properties={
"request": {
"type": "string",
"description": "The user exact words verbatim - do not rephrase",
},
},
required=["request"],
)
Deployment
cd /Users/ravenhelm/ravenhelm/services/telephony
docker compose build
docker compose up -d
Logs
# View logs
docker logs -f telephony
# Check health
curl https://telephony.ravenhelm.dev/health
Files
| File | Purpose |
|---|---|
main.py | FastAPI + Pipecat + Twilio webhook |
requirements.txt | pipecat-ai, twilio, fastapi, httpx |
Dockerfile | Python 3.11 slim |
docker-compose.yml | Traefik routing |
Outbound Calling
Norns can now make outbound phone calls in two modes:
| Mode | Description | Documentation |
|---|---|---|
| Scripted | Deliver a message and hang up | Norns Telephony |
| Interactive | Full conversation with objectives | Norns Telephony |
Key Features:
- Initiate calls via Norns tools (
make_phone_call,check_call_status) - Full conversation history passed to Norns for context
- Objective-based system prompts keep calls focused
- Automatic delegation to Norns for task/calendar/home operations
Example Usage:
# Via API
curl -X POST https://telephony.ravenhelm.dev/api/call/outbound \
-H "X-API-Key: $NORNS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"to_number": "+15551234567", "mode": "interactive", "user_id": "...", "objective": "Ask about project status"}'
# Via Slack
"Call John and ask about the quarterly report"
See Norns Telephony for complete documentation.