skills/telephony-lifecycle/SKILL.md
# Telephony Lifecycle ## Capability Manages the complete lifecycle of voice calls from TwiML webhook initiation through call completion, including call connect, transfer, conference, and disconnect handling with proper session cleanup. ## MCP Tools | Tool | Input Schema | Output | Rate Limit | |------|-------------|--------|------------| | `telephony.generateTwiML` | `z.object({ sessionId: z.string(), wsUrl: z.string().url() })` | `{ twiml: string }` | 100 RPM | | `telephony.handleConnect` |
npx skillsauth add reaatech/voice-agent-kit skills/telephony-lifecycleInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Manages the complete lifecycle of voice calls from TwiML webhook initiation through call completion, including call connect, transfer, conference, and disconnect handling with proper session cleanup.
| Tool | Input Schema | Output | Rate Limit |
|------|-------------|--------|------------|
| telephony.generateTwiML | z.object({ sessionId: z.string(), wsUrl: z.string().url() }) | { twiml: string } | 100 RPM |
| telephony.handleConnect | z.object({ callSid: z.string(), from: z.string(), to: z.string() }) | { twiml: string, sessionId: string } | 100 RPM |
| telephony.handleDisconnect | z.object({ callSid: z.string(), disconnectReason: z.string() }) | { cleaned: boolean, sessionDuration: number } | 100 RPM |
| telephony.transfer | z.object({ callSid: z.string(), target: z.string(), type: z.enum(['warm', 'cold']) }) | { transferred: boolean } | 10 RPM |
| telephony.hangup | z.object({ callSid: z.string(), reason: z.string() }) | { hungup: boolean } | 10 RPM |
{
"name": "telephony.generateTwiML",
"arguments": {
"sessionId": "sess-abc123",
"wsUrl": "wss://voice-agent-kit.example.com/ws"
}
}
{
"twiml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n <Connect>\n <Stream url=\"wss://voice-agent-kit.example.com/ws\" />\n </Connect>\n</Response>"
}
{
"name": "telephony.handleConnect",
"arguments": {
"callSid": "CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"from": "+14155551234",
"to": "+18005551234"
}
}
{
"twiml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n <Connect>\n <Stream url=\"wss://voice-agent-kit.example.com/ws\" />\n </Connect>\n</Response>",
"sessionId": "sess-xyz789"
}
{
"name": "telephony.handleDisconnect",
"arguments": {
"callSid": "CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"disconnectReason": "completed"
}
}
{
"cleaned": true,
"sessionDuration": 125000
}
{
"name": "telephony.transfer",
"arguments": {
"callSid": "CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"target": "+14155559999",
"type": "warm"
}
}
{
"transferred": true
}
| Failure | Cause | Recovery | |---------|-------|----------| | TwiML generation error | Invalid WebSocket URL | Return error with validation details | | Session not found on disconnect | Already cleaned up | Log warning, no action needed | | Transfer failed | Invalid target number | Return error, keep call active | | Hangup failed | Call already ended | Log warning, cleanup session | | Twilio API error | Rate limit, auth failure | Retry with backoff, escalate if persistent |
***-***-1234)1. Inbound call to Twilio number
│
2. Twilio sends webhook to /voice/connect
│
3. Generate TwiML with Media Stream URL
│
4. Twilio connects WebSocket to voice-agent-kit
│
5. Receive 'start' message → create session
│
6. Process media messages (STT → MCP → TTS)
│
7. Handle barge-in events as needed
│
8. Call continues until user hangs up or agent transfers
│
9. Twilio sends 'stop' message
│
10. Twilio sends webhook to /voice/disconnect
│
11. Cleanup session, emit metrics
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Connect>
<Stream url="wss://voice-agent-kit.example.com/ws">
<Parameter name="sessionId" value="sess-abc123" />
</Stream>
</Connect>
</Response>
| Reason | Description |
|--------|-------------|
| completed | Normal call completion |
| answered | Call was answered (outbound) |
| busy | Called number was busy |
| fail | Call failed (invalid number, etc.) |
| no-answer | No one answered |
| canceled | Call was canceled before answer |
| rejected | Call was rejected |
# voice-agent-kit.config.ts
telephony:
# WebSocket endpoint
wsUrl: '${WS_URL}'
# TwiML settings
twiml:
# Add custom parameters to Stream
parameters:
environment: '${ENVIRONMENT}'
# Fallback TwiML on error
fallback: |
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>We're sorry, but we're experiencing technical difficulties. Please try again later.</Say>
<Hangup />
</Response>
# Transfer settings
transfer:
maxDuration: 3600 # Max transfer duration in seconds
requireConfirmation: true # Require agent confirmation
# Call limits
limits:
maxCallDuration: 3600 # 1 hour max
maxConcurrentCalls: 100 # Per instance
// Handle DTMF tones from Twilio
twilioWebSocket.on('dtmf', (event: DTMFEvent) => {
const { digit, duration } = event;
// Emit as pipeline event for menu navigation
pipeline.emit('dtmf', { digit, duration, sessionId });
});
| Metric | Type | Description |
|--------|------|-------------|
| telephony.calls.total | Counter | Total calls by direction (inbound/outbound) |
| telephony.calls.active | Gauge | Currently active calls |
| telephony.calls.duration_seconds | Histogram | Call duration |
| telephony.calls.disconnect_reason | Counter | Disconnect reasons |
| telephony.transfers.total | Counter | Call transfers |
| telephony.errors.total | Counter | Telephony errors |
| Span | Attributes |
|------|------------|
| telephony.connect | call_sid, from, to, direction |
| telephony.twiml.generate | session_id, ws_url |
| telephony.disconnect | call_sid, reason, duration |
| telephony.transfer | call_sid, target, type |
| telephony.hangup | call_sid, reason |
tools
# Twilio Media Streams ## Capability Handles Twilio Media Streams WebSocket connections for real-time bidirectional audio communication, parsing inbound messages, encoding outbound audio, and managing call lifecycle events. ## MCP Tools | Tool | Input Schema | Output | Rate Limit | |------|-------------|--------|------------| | `twilio.handleStart` | `z.object({ message: z.object({ event: z.literal('start'), callSid: z.string(), streamSid: z.string(), format: z.string(), tracks: z.array(z.st
tools
# TTS Provider Interface ## Capability Provides a unified interface for text-to-speech (TTS) providers, enabling streaming audio synthesis with first-byte latency tracking, voice selection, and output format conversion. ## MCP Tools | Tool | Input Schema | Output | Rate Limit | |------|-------------|--------|------------| | `tts.synthesize` | `z.object({ text: z.string(), config: z.object({ provider: z.string(), voice: z.string().optional(), speed: z.number().optional() }) })` | `{ chunks: A
tools
# STT Provider Interface ## Capability Provides a unified interface for speech-to-text (STT) providers, enabling real-time streaming transcription with interim results, endpoint detection, and automatic reconnection handling. ## MCP Tools | Tool | Input Schema | Output | Rate Limit | |------|-------------|--------|------------| | `stt.connect` | `z.object({ provider: z.enum(['deepgram', 'aws-transcribe', 'google-cloud']), config: z.object({ apiKey: z.string().optional(), sampleRate: z.number
tools
# Session Management ## Capability Manages voice call sessions with unique session IDs, conversation history, context preservation across turns, and automatic cleanup on disconnect or timeout. ## MCP Tools | Tool | Input Schema | Output | Rate Limit | |------|-------------|--------|------------| | `session.create` | `z.object({ callSid: z.string(), config: SessionConfig })` | `{ sessionId: string, createdAt: string }` | 100 RPM | | `session.get` | `z.object({ sessionId: z.string() })` | `{ s