Show HN: Self-hosted voice AI agent for Asterisk/FreePBX
Quick Start
Get the Admin UI running in 2 minutes. For a complete first successful call walkthrough (dialplan + transport selection + verification), see the documentation.
# Clone repository
git clone https://github.com/hkjarral/AVA-AI-Voice-Agent-for-Asterisk.git
cd AVA-AI-Voice-Agent-for-Asterisk
# Run preflight with auto-fix (creates .env, generates JWT_SECRET)
sudo ./preflight.sh --apply-fixes
Important: Preflight creates your .env file and generates a secure JWT_SECRET. Always run this first!
# Start the Admin UI container
docker compose -p asterisk-ai-voice-agent up -d --build --force-recreate admin_ui
Open in your browser:
- Local:
http://localhost:3003 - Remote server:
http://<your-server-ip>:3003
Default Login: On first start, a one-time admin password is printed to the container logs. Retrieve it with:
docker compose -p asterisk-ai-voice-agent logs admin_ui | grep -i password
You must change it at first login. Restrict port 3003 via firewall, VPN, or reverse proxy for production use. Follow the Setup Wizard to configure your providers and make a test call.
β οΈ Security: The Admin UI is accessible on the network. Restrict port 3003 via firewall, VPN, or reverse proxy for production use.
GPU users: If you have an NVIDIA GPU for local AI inference, see docs/LOCAL_ONLY_SETUP.md for the GPU compose overlay (docker-compose.gpu.yml) before building.
# Start ai_engine (required for health checks)
docker compose -p asterisk-ai-voice-agent up -d --build ai_engine
# Check ai_engine health
curl http://localhost:15000/health
# Expected: {"status":"healthy"} ("degraded" is also possible if a subsystem is unhealthy)
# View logs for any errors
docker compose -p asterisk-ai-voice-agent logs ai_engine | tail -20
The wizard will generate the necessary dialplan configuration for your Asterisk server. Transport selection is configuration-dependent (not strictly "pipelines vs full agents"). Use the validated matrix in the documentation.
Headless Setup
For users who prefer the command line or need headless setup:
./install.sh agent setup
Note: Legacy commands agent init, agent quickstart, agent doctor, agent troubleshoot, and agent demo remain as hidden compatibility aliases. New workflows should use the visible commands documented in docs/CLI_TOOLS_GUIDE.md.
# Configure environment
cp .env.example .env
# Edit .env with your API keys
# Start services
docker compose -p asterisk-ai-voice-agent up -d
FreePBX Integration
Add this to your FreePBX (extensions_custom.conf):
[from-ai-agent]
exten => s,1,NoOp(Asterisk AI Voice Agent)
; AI_AGENT selects an operator-managed agent by slug.
same => n,Set(AI_AGENT=sales-agent)
; Optional: override that agent's configured provider/pipeline for this call.
; same => n,Set(AI_PROVIDER=google_live)
same => n,Stasis(asterisk-ai-voice-agent)
same => n,Hangup()
Notes:
- Use
AI_AGENTto select an operator-managed agent. Its configured target is authoritative unlessAI_PROVIDERis intentionally set as a per-call override. - Generate a current snippet with
agent dialplan --agent <name>. - See
docs/FreePBX-Integration-Guide.mdfor channel variable precedence and examples.
Agent CLI Tools
# Health check
agent check
# View logs
docker compose -p asterisk-ai-voice-agent logs -f ai_engine
Release Notes
v7.3.3 - Local AI stabilization π§
v7.3.3 is a Local-AI-only stabilization release. It adds no providers and keeps the cloud-provider call paths unchanged.
- Calls are isolated by session - agent prompts and conversation state no longer mutate shared Local AI Server configuration or leak across reused WebSocket connections. AI Engine and Local AI Server should be upgraded together; the legacy unscoped switch remains temporarily compatible.
- Barge-in abandons interrupted output - late LLM/TTS work is quarantined, the interrupted exchange is removed from weak-model history, and the replacement turn stays focused on what the caller just said.
- Farewells finish exactly once - Local hangup_call speaks the selected Kokoro/Piper/etc. farewell without a second LLM rewrite, drains partial AudioSocket or RTP tails, records
agent_hangup, and then disconnects. - CPU/GPU deployment is safer - dependency pins, CUDA/cuDNN validation, optional llama.cpp architecture targeting, and idempotent preflight checks reduce first-build and rerun failures.
- Community GPU evidence - Tesla V100S testing passed Faster-Whisper CUDA float16, Llama 3.1 8B Q4_K_M, Kokoro, AudioSocket, ExternalMedia, barge-in, terminal hangup, concurrent session isolation, and restart recovery.
See the Local AI community test matrix and the Unreleased changelog for the complete scope.
v7.3.2 - stabilization release π‘οΈ
v7.3.2 is a stabilization-only patch release built from the supervised AudioSocket and ExternalMedia validation cycle.
- No new providers - scope is limited to reliability, deployment safety, documentation, and contributor-facing CI.
- Grok ExternalMedia repaired - clean barge-in, cancelled-output quarantine, named-instance runtime inheritance, complete replacement turns, and exact inactivity announcements through xAI
force_message. - AudioSocket and modular pipelines hardened - terminal playback, pipeline producer ownership, talk-detect echo, and inactivity-grace regressions are covered by focused tests and supervised calls.
- Updater and provider-failure recovery hardened - safer ownership, rollback/stash handling, readiness validation, and an opt-in dialplan redirect.
- PR quality gates expanded - Admin backend/frontend checks and CLI cross-compilation now run before merge.
Release evidence and remaining gates are tracked in the v7.3.2 validation matrix.
v7.3.1 - Silence watchdog & safe call endings βοΈ
AVA now protects silent calls and finishes every terminal message before disconnecting.
- 30-second inbound inactivity protection by default - AVA asks "Are you still there?", waits 15 seconds for a reply, then speaks a configurable final warning and ends the call. Outbound agents remain opt-in.
- The agent keeps its configured voice - check-ins and final warnings are synthesized by the active Google Live, OpenAI Realtime, Grok, Deepgram, ElevenLabs, local full-agent, or pipeline voice.
- Transport-safe hangup - watchdog and hangup_call farewells drain AudioSocket or ExternalMedia/RTP streaming buffers and ARI file playback before ARI disconnects the caller. Fixed sleeps no longer clip long final sentences.
- Deepgram and ElevenLabs lifecycle fixes - Deepgram control frames no longer split greetings, and ElevenLabs response-completion plus hosted-silence handling keeps AVA's watchdog authoritative.
- Global and per-agent controls - configure defaults under Advanced Settings β Voice Activity Detection β Caller Inactivity, then optionally override them per agent. Call History labels watchdog endings as "No input timeout".
See Caller inactivity configuration, ElevenLabs setup, and the full v7.3.1 changelog.
v7.3.0 - Per-agent voices ποΈ
Voice now belongs to agents. Configure one provider, create multiple agents that share it - each with its own voice.
- Provider-aware voice picker in the Agent form: a dropdown of OpenAI's 10 GA voices, suggestions + custom clone IDs for Grok, Google Live's 30 prebuilt voices, Deepgram's Aura models - the control adapts to the agent's selected AI Engine.
- Safe by default - the provider-level voice becomes the default voice; agents without one behave exactly as before. Unrecognized values (OpenAI/Google/Deepgram catalogs are validated) log a warning and fall back - a bad voice value never fails a call.
- Observable - every call logs the resolved voice and its source, and Call History shows "Voice: marin (from agent)" per call.
- Agent voice changes apply instantly - no engine restart. Thanks @foytech for seeding this feature (#497).
Full guide: docs/VOICE_SELECTION.md.
v7.2.0 - Live-status dashboard π‘
Real-time system status for the Admin UI - pushed, not polled.
- Live-status hub - a single
/api/live-statussnapshot endpoint plus an SSE stream (/api/live-status/stream) aggregates AI Engine health, Local AI connectivity, active sessions, audio directories, platform checks, and Asterisk ARI into one normalized status feed. - Push-first -
ai_engineandlocal_ai_serverpush their own readiness to the Admin UI (POST /api/live-status/publish, authenticated withLIVE_STATUS_PUSH_TOKEN), so the dashboard converges in sub-second time after a restart instead of waiting on staggered polls. Legacy/api/system/*probes remain as fallback/enrichment. - Configurable -
LIVE_STATUS_POLL_INTERVAL_SECONDS(default 30 s, min 2 s) andLIVE_STATUS_INITIAL_PROBE_TIMEOUT_SECONDS(default 2 s), read live from.env.
Full notes in CHANGELOG.md.
v7.1.1 - Dashboard reliability & Admin UI polish π οΈ
A focused quality release across the Admin UI - no call-path changes.
- Dashboard reliability - the Asterisk status pill no longer flaps on a transient ARI blip: it reads the engine's authoritative, reconnect-supervised ARI state and applies hysteresis. The system endpoints the Dashboard polls every 5s no longer block the admin event loop, the heaviest is TTL-cached, polling backs off on errors, failed polls surface in the error banner, and a single bad poll no longer flashes cards to "Loadingβ¦".
- No more "Loading configurationβ¦" flash - ~11 config pages now seed from a shared stale-while-revalidate cache of the config document, so revisiting a settings page is instant.
- Accessibility (WCAG AA) - form labels programmatically associated with inputs, a focus-trapping modal, a navigation landmark + "skip to content" link, accessible names on icon-only buttons, non-colour status cues on the topology, a visible dark-mode toggle on-state, and light-mode contrast fixes. Debug
console.logs (including one that leaked the auth token to the browser console) were removed. - Prompt editor - configured tool names are colour-coded by their in-call status (enabled / global / not-enabled) as you type.
- Fix (#436) - a canonical
google_live: { type: full }provider can be edited and saved again.
Full notes in CHANGELOG.md.
v7.0.0 - the Agents release π―
The biggest release yet: manage your AI agents from the Admin UI, not a config file.
- π€ Agents tab - create, edit, and manage agents in the UI. Start from a template (receptionist, after-hours, appointment booker, and more), set the prompt and provider, and copy a ready-to-paste dialplan snippet. (Voice is configured on the provider, not per agent.)
- π Multi-agent dashboard - live KPIs (active agents, active calls, calls routed, transfers), per-agent stats, and routing breakdowns at a glance.
- βοΈ New
AI_AGENTdialplan variable - route a call to an agent by name. Your existingAI_CONTEXTdialplans keep working unchanged. - π Automatic migration - your existing contexts move into a local agents database on first start. Nothing to do, and rollback is one command.
- π Security hardening - no more
admin/admin: a one-time admin password is generated and must be changed at first login. Config exports no longer bundle your.envby default.
v6.5.4 (2026-05-25) - OpenAI Realtime GA cleanup across every code path
Follow-up to the v6.5.3 hotfix. v6.5.3 only flipped config/ai-agent.yaml; v6.5.4 brings the rest of the codebase in line:
- Pydantic defaults in
src/config.pynow default toapi_version: ga+model: gpt-realtime(so fresh wizard installs are correct). - Admin UI "Add Provider" template for OpenAI Realtime no longer seeds the sunset preview model.
- Model dropdown removes the 5 sunset preview options and adds 3 new GA models -
gpt-realtime-1.5(best audio-in/audio-out quality),gpt-realtime-2(reasoning voice model, GPT-5-class), andgpt-realtime-mini(cost-optimized) - alongside the existinggpt-realtime. - Legacy preview values in operator YAML now render in a "Custom (legacy - will not connect)" optgroup with a yellow warning banner above the form so the broken state is visible without silently swapping the operator's config.
- Engine emits a one-shot warning when
api_version: betais detected in config (exactly once per provider lifetime, not per reconnect attempt). - Docs: full rewrite of
docs/Provider-OpenAI-Setup.mdmodel section + fix todocs/TROUBLESHOOTING_GUIDE.md.
v6.5.3 hotfix (2026-05-25) - OpenAI Realtime restored
OpenAI sunset the Realtime Beta API on 2026-05-12 and removed the gpt-4o-realtime-preview-2024-12-17 model on 2026-05-07. Shipped config/ai-agent.yaml still pinned api_version: beta + that preview model, so every operator using OpenAI Realtime hit error.code: beta_api_shape_disabled and the WebSocket closed immediately.
Two-line config flip - no code change required. The provider's GA wire-protocol path has shipped since v6.0.0; v6.5.3 just makes it the default everyone gets:
api_version: ga # was beta
model: gpt-realtime # was gpt-4o-realtime-preview-2024-12-17
If you have an ai-agent.local.yaml that explicitly pins api_version: beta, remove the override or change it to ga.
Refs: OpenAI deprecations, gpt-realtime.
v6.5.2 (2026-05-24) - xAI Grok + multi-instance full-agent providers
- Fifth full-agent realtime provider - structurally parallel to OpenAI Realtime and Google Live, built on a multi-instance foundation from day one.
- ΞΌ-law @ 8 kHz caller input with no input resampling; observed xAI output is PCM16 @ 24 kHz and AAVA converts it to the configured Asterisk transport format.
- Five named voices (
eve,ara,rex,sal,leo) plus custom voice ID free-text for cloned voices. - Custom function-tools identical to OpenAI Realtime; xAI-native tools (
web_search,x_search,file_search,mcp) accepted via YAMLextra_toolsescape hatch.
Comments
No comments yet. Start the discussion.