Skip to content

feat(ai_agents): add Plivo SIP telephony integration#2020

Merged
plutoless merged 3 commits intoTEN-framework:mainfrom
navi-:feat/plivo-sip-telephony
Feb 16, 2026
Merged

feat(ai_agents): add Plivo SIP telephony integration#2020
plutoless merged 3 commits intoTEN-framework:mainfrom
navi-:feat/plivo-sip-telephony

Conversation

@navi-
Copy link
Contributor

@navi- navi- commented Jan 25, 2026

Summary

  • Add new voice assistant example with Plivo SIP integration for telephony
  • Implement bidirectional WebSocket audio streaming with μ-law 8kHz codec
  • Create RESTful API for outbound call management (create, list, status, terminate)
  • Mirror existing Twilio integration architecture for consistency

Changes

  • New example: agents/examples/voice-assistant-sip-plivo/
  • PlivoCallServer with FastAPI for webhooks and WebSocket handling
  • Full STT → LLM → TTS voice pipeline integration
  • Frontend UI for call management
  • Docker support and ngrok configuration for local development

Test plan

  • Configure Plivo credentials (Auth ID, Auth Token, phone number)
  • Set up ngrok or public URL for webhooks
  • Configure Deepgram, OpenAI, and ElevenLabs API keys
  • Test outbound call creation via API
  • Verify bidirectional audio streaming works
  • Test call termination

🤖 Generated with Claude Code

Add a new voice assistant example that integrates with Plivo for
telephony, mirroring the existing Twilio SIP integration. This enables
real-time voice AI applications using Plivo's WebSocket-based media
streaming.

Key components:
- PlivoCallServer for handling calls, webhooks, and WebSocket streaming
- Plivo XML generation using plivoxml.ResponseElement
- Bidirectional audio streaming with mu-law 8kHz codec
- RESTful API for outbound call management
- Full STT -> LLM -> TTS voice pipeline integration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@github-actions
Copy link

PR #2020 Review: Plivo SIP Telephony Integration

Thank you for this substantial contribution! This is a well-structured implementation that mirrors the existing Twilio integration. However, I've identified several security and reliability issues that should be addressed before merging.


🔴 CRITICAL ISSUES (Must Fix)

1. WebSocket Resource Leak

File: server/plivo_server.py:326

The WebSocket cleanup in the exception handler doesn't properly remove sessions from active_call_sessions, leading to memory leaks:

except Exception as e:
    self._log_error(f"WebSocket error: {e}")
    try:
        await websocket.close()
    except:
        pass  # Silently ignores errors

Fix: Track and clean up properly:

finally:
    for call_uuid, session in list(self.active_call_sessions.items()):
        if session.get("websocket") == websocket:
            del self.active_call_sessions[call_uuid]
            break
    try:
        await websocket.close(code=1000)
    except Exception as e:
        self._log_error(f"Error closing websocket: {e}")

2. Race Condition in Call Cleanup

File: tenapp/ten_packages/extension/main_python/extension.py:154-188

_end_call_and_cleanup has a race condition where the session dict can be modified between the check and the delete:

if call_uuid in self.server_instance.active_call_sessions:
    # ... API call ...
if call_uuid in self.server_instance.active_call_sessions:
    del self.server_instance.active_call_sessions[call_uuid]

Fix: Use asyncio locks:

async with self.server_instance._call_cleanup_lock:
    if call_uuid in self.active_call_sessions:
        # cleanup
        del self.active_call_sessions[call_uuid]

🟠 HIGH PRIORITY SECURITY ISSUES

3. Overly Permissive CORS Configuration

Files: tenapp/ten_packages/extension/main_python/server.py:34-39, server/plivo_server.py:74-79

CORS allows all origins, exposing the API to cross-origin attacks:

allow_origins=["*"],  # ⚠️ Allows any website to make requests

Fix: Restrict to specific origins:

allow_origins=["http://localhost:3000", os.getenv("ALLOWED_ORIGIN", "")]

4. Missing Input Validation

File: tenapp/ten_packages/extension/main_python/server.py:92-94

Phone numbers and messages lack validation:

phone_number = body.get("phone_number")
if not phone_number:
    raise HTTPException(status_code=400, detail="phone_number is required")
# No format validation, length limits, or sanitization

Fix: Add proper validation:

import re
PHONE_REGEX = re.compile(r'^\+?1?\d{9,15}$')
if not PHONE_REGEX.match(phone_number):
    raise HTTPException(status_code=400, detail="Invalid phone number format")
if len(message or "") > 5000:
    raise HTTPException(status_code=400, detail="Message too long")

5. No API Authentication

File: tenapp/ten_packages/extension/main_python/server.py:74-315

All API endpoints lack authentication - anyone can create, list, or terminate calls.

Fix: Implement API key authentication:

from fastapi import Header, HTTPException

async def verify_api_key(x_api_key: str = Header(...)):
    if x_api_key != os.getenv("API_KEY"):
        raise HTTPException(status_code=401, detail="Unauthorized")

@self.app.post("/api/call", dependencies=[Depends(verify_api_key)])
async def create_call(...):
    ...

6. Missing Webhook Signature Validation

File: tenapp/ten_packages/extension/main_python/server.py:203-289

Webhook endpoints don't verify requests are actually from Plivo - attackers can spoof webhook calls.

Fix: Verify Plivo signatures:

import hmac
import hashlib

def verify_plivo_signature(url: str, params: dict, signature: str, auth_token: str) -> bool:
    # Implement Plivo's signature verification
    # https://www.plivo.com/docs/sms/concepts/signature-validation/
    pass

🟡 MEDIUM PRIORITY ISSUES

7. Memory Leak - No Session Cleanup

File: tenapp/ten_packages/extension/main_python/server.py:87-137

Completed calls remain in active_call_sessions indefinitely, causing memory to grow unbounded.

Fix: Implement TTL-based cleanup:

async def _cleanup_old_sessions(self):
    while True:
        await asyncio.sleep(300)
        now = datetime.now()
        for call_uuid, session in list(self.active_call_sessions.items()):
            if session.get("status") in ["completed", "failed"]:
                age = (now - datetime.fromisoformat(session["created_at"])).total_seconds()
                if age > 3600:  # 1 hour TTL
                    del self.active_call_sessions[call_uuid]

8. Overly Broad Exception Handling

File: tenapp/ten_packages/extension/main_python/server.py (multiple locations)

Generic except Exception masks different error types and exposes internal details to users:

except Exception as e:
    raise HTTPException(status_code=500, detail=str(e))  # ⚠️ Leaks internal errors

Fix: Catch specific exceptions and sanitize error messages.

9. Missing Configuration Validation

File: tenapp/ten_packages/extension/main_python/server.py:546-553

Startup validation doesn't check if plivo_public_server_url is set, but it's required for outbound calls.

Fix: Add to startup checks:

if not config.plivo_public_server_url:
    print("Error: plivo_public_server_url is required")
    sys.exit(1)

10. Unpinned Dependencies

File: server/requirements.txt:8

plivo

Fix: Pin to specific version:

plivo==4.3.0

📋 TEST COVERAGE

This PR adds 12,586 lines of code with zero tests. Critical paths that need testing:

  • WebSocket connection/disconnection
  • Audio encoding/decoding (PCM ↔ μ-law)
  • Call creation/deletion API
  • Webhook handling
  • Error scenarios

Recommendation: Add at least basic tests for:

# tests/test_plivo_server.py
@pytest.mark.asyncio
async def test_create_call_missing_phone()
@pytest.mark.asyncio
async def test_websocket_cleanup_on_disconnect()
def test_audio_downsample_maintains_format()

🔍 ADDITIONAL OBSERVATIONS

Code Quality

  • Frontend references "Twilio" in frontend/app/page.tsx:33 - copy-paste error from Twilio example
  • Inconsistent logging - mix of print() and logger usage
  • Missing JSDoc comments in frontend/app/api.ts

Architecture

  • No proper state machine for calls (missing states like "ringing", "answered")
  • No graceful shutdown wait for active calls to complete
  • No rate limiting on any endpoints

✅ WHAT'S GOOD

  • Architecture mirrors existing Twilio integration for consistency
  • Comprehensive README with setup instructions
  • Docker support for easy deployment
  • Proper async/await usage throughout
  • Clean separation between server and extension logic

📊 SUMMARY

Severity Count Must Fix?
Critical 2 ✅ Yes
High 4 ✅ Yes
Medium 6 ⚠️ Recommended
Low 4 💡 Nice to have

Recommendation: Request changes to address Critical and High priority issues before merging. The implementation is solid overall, but the security and reliability gaps need to be closed.


Happy to discuss any of these findings or help with implementations! 🚀

@plutoless
Copy link
Contributor

thanks for the PR! merged.

@plutoless plutoless merged commit aa56aaf into TEN-framework:main Feb 16, 2026
20 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants