Skip to main content

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

EndpointMethodPurpose
/twilio/webhookPOSTTwilio call webhook (returns TwiML)
/twilio/streamWebSocketTwilio Media Streams audio
/healthGETHealth 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

VariableDescription
WEBHOOK_HOSTPublic hostname (telephony.ravenhelm.dev)
NORNS_URLNorns API URL (http://docs/AI-ML-Platform/norns-agent:8000)
NORNS_API_KEYAPI key for Norns authentication
TWILIO_ACCOUNT_SIDTwilio account SID
TWILIO_AUTH_TOKENTwilio auth token
DEEPGRAM_API_KEYDeepgram STT API key
OPENAI_API_KEYOpenAI API key (for GPT-4o-mini)
ELEVENLABS_API_KEYElevenLabs TTS API key
ELEVENLABS_VOICE_IDElevenLabs voice ID

Twilio Configuration

  1. Phone Number: +1 (737) 214-3330
  2. Voice Webhook: https://telephony.ravenhelm.dev/twilio/webhook
  3. 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

FilePurpose
main.pyFastAPI + Pipecat + Twilio webhook
requirements.txtpipecat-ai, twilio, fastapi, httpx
DockerfilePython 3.11 slim
docker-compose.ymlTraefik routing

Outbound Calling

Norns can now make outbound phone calls in two modes:

ModeDescriptionDocumentation
ScriptedDeliver a message and hang upNorns Telephony
InteractiveFull conversation with objectivesNorns 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.