Files
hold-slayer/.env.example
Robert Helewka 4048ce1db6 Stage 4: honest health, explicit error policy, event-bus integrity
Engine mode is now explicit: USE_MOCK_SIP=true is the only way to get
the mock engine; an unconfigured trunk fails startup with guidance
instead of silently degrading. Root-caused why the engine always ran
mock: nested pydantic-settings never read .env (no env_file on the
sub-settings classes) — all 8 now declare it.

/health stops lying: reports engine mode (sippy|mock), a live DB
SELECT 1, trunk registration state with reason, and TTS/STT
availability from their last real request; "healthy" now requires
ready + db + sippy + registered trunk.

Error policy: leaf services (tts/transcription/llm_client) raise and
track availability; call-loop callers catch, publish EventType.ERROR
naming the failed service, and apply an explicit fallback. Persistence
writes get one bounded 3x exponential retry, then an ERROR log — no
more silent data loss.

Event bus: a full subscriber queue drops its oldest event (counted)
instead of silently evicting the subscription; subscribe(replay_last=N)
delivers the advertised history replay, used by /ws/events (25).

Receptionist correctness: a matched TAKE_MESSAGE rule beats the LLM;
voicemail polls for early hangup and stops/transcribes/hangs up in
finally; RecordingSession finally keeps its leg_ids so taps detach.

Dead code removed: models/contact.py + Contact table, dtmf_buffer,
transcribe_stream stub, SMS stub in notification.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 07:01:45 -04:00

74 lines
2.1 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 ---
# The mock engine must be requested explicitly; an unconfigured trunk
# without USE_MOCK_SIP=true refuses to start.
USE_MOCK_SIP=false
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