The MCP server was created but never mounted — no client could reach
it. Mount it at /mcp/ over streamable HTTP with a combined lifespan,
resolving the gateway lazily so mounting happens at app construction.
Security and safety for the agent surface:
- One static API_TOKEN (SecretStr) enforced across REST (dependency),
WebSocket (query param/header before accept), and MCP
(StaticTokenVerifier). Startup refuses tokenless non-loopback binds.
- Emergency numbers (911/9911/112) always refused on make_call, plus a
MAX_CONCURRENT_CALLS cap; ValueError surfaces as 400/ToolError.
- Safe defaults: debug off, no credential in default DATABASE_URL,
SIP/LLM/TTS secrets as SecretStr.
Cleanups:
- Delete broken learn_call_flow tool (wrong ctor args, nonexistent
method) and the never-fed CallAnalytics service; keep
call_flow_learner for proper wiring later.
- Trim dial_plan to what is actually used (emergency guard, extension
allocation); delete the unreferenced matcher/normaliser.
- Register call_history before calls so /api/calls/history is no
longer shadowed by /api/calls/{call_id}.
- fastmcp pinned >=3.0 (http_app + StaticTokenVerifier).
New tests: MCP in-memory client (tool surface, lazy gateway, emergency
refusal, call cap) and API security (401 paths, route order, mount).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
71 lines
2.0 KiB
Plaintext
71 lines
2.0 KiB
Plaintext
# ============================================================
|
|
# Hold Slayer Gateway Configuration
|
|
# ============================================================
|
|
# Copy to .env and fill in your values
|
|
|
|
# --- Database (required) ---
|
|
DATABASE_URL=postgresql+asyncpg://holdslayer:<db-password>@localhost:5432/holdslayer
|
|
|
|
# --- API auth (required unless HOST=127.0.0.1) ---
|
|
# One static bearer token shared by REST, WebSocket (?token=...), and MCP.
|
|
# Generate with: openssl rand -hex 32
|
|
API_TOKEN=
|
|
|
|
# --- SIP Trunk ---
|
|
SIP_TRUNK_HOST=sip.yourprovider.com
|
|
SIP_TRUNK_PORT=5060
|
|
SIP_TRUNK_USERNAME=your_sip_username
|
|
SIP_TRUNK_PASSWORD=your_sip_password
|
|
SIP_TRUNK_TRANSPORT=udp
|
|
# Your phone number on the trunk (E.164)
|
|
SIP_TRUNK_DID=+15551234567
|
|
|
|
# --- Gateway SIP Listener ---
|
|
# Port for devices (softphones/hardphones) to register to
|
|
GATEWAY_SIP_HOST=0.0.0.0
|
|
GATEWAY_SIP_PORT=5080
|
|
GATEWAY_SIP_DOMAIN=gateway.helu.ca
|
|
|
|
# --- Speaches STT ---
|
|
SPEACHES_URL=http://localhost:22070
|
|
SPEACHES_MODEL=whisper-large-v3
|
|
|
|
# --- Audio Classifier ---
|
|
# Thresholds for hold music detection (0.0 - 1.0)
|
|
CLASSIFIER_MUSIC_THRESHOLD=0.7
|
|
CLASSIFIER_SPEECH_THRESHOLD=0.6
|
|
CLASSIFIER_SILENCE_THRESHOLD=0.85
|
|
# Analysis window in seconds
|
|
CLASSIFIER_WINDOW_SECONDS=3.0
|
|
|
|
# --- LLM (OpenAI-compatible API) ---
|
|
# Ollama, LM Studio, vLLM, or OpenAI — any OpenAI-compatible endpoint
|
|
LLM_BASE_URL=http://localhost:11434/v1
|
|
LLM_MODEL=llama3
|
|
LLM_API_KEY=not-needed
|
|
LLM_TIMEOUT=30.0
|
|
LLM_MAX_TOKENS=1024
|
|
LLM_TEMPERATURE=0.3
|
|
|
|
# --- Hold Slayer ---
|
|
# Default device to transfer to when human detected
|
|
DEFAULT_TRANSFER_DEVICE=sip_phone
|
|
# Max hold time before giving up (seconds)
|
|
MAX_HOLD_TIME=7200
|
|
# How often to check classification while on hold (seconds)
|
|
HOLD_CHECK_INTERVAL=2.0
|
|
|
|
# --- Notifications ---
|
|
# SMS notification number (optional)
|
|
NOTIFY_SMS_NUMBER=+15559876543
|
|
|
|
# --- Server ---
|
|
HOST=0.0.0.0
|
|
PORT=8000
|
|
DEBUG=false
|
|
LOG_LEVEL=info
|
|
|
|
# --- Safety ---
|
|
# Max simultaneous calls the gateway will place (REST + MCP)
|
|
MAX_CONCURRENT_CALLS=4
|