Development
How do I add a new AI provider (LLM/STT/TTS)?
- Add
livekit-plugins-{provider}dependency torequirements.txt - Update the relevant factory class:
- LLM:
plugins/llm.py→LLMFactory.get_instance() - STT:
plugins/stt.py→STTFactory.get_instance() - TTS:
plugins/tts.py→TTSFactory.get_instance()
- LLM:
- Add a new conditional branch matching the provider name
- Configure the API key in
settings.pyand.env - Update the
Agentsmodel if new config fields are needed - Update UI dropdowns in agent creation forms
How do I add a new API endpoint?
- Create or modify a router file in
app/router/ - Define the endpoint:
@router.get/post/put/delete - Add auth:
workspace_id = Depends(require_workspace_access(WorkspaceRole.developer)) - Create Pydantic schemas in
app/db/schemas/ - Register in
app/main.py:app.include_router(new_router)
How do I add a custom function (tool) to the agent?
Custom functions are configured per-agent via thecustom_functions JSON column:
AgentCaller registers these as @function_tool methods at runtime via utils/dynamic_tools.py.
Architecture
What’s the difference between Batch Jobs and Campaigns?
| Aspect | Batch Jobs | Campaigns (Vaani Dialer) |
|---|---|---|
| Execution | Celery (distributed) | AMQP Dialer (Twisted + RabbitMQ) |
| Prospect Management | Flat phone list | ProspectList → Prospect → ActiveProspect pipeline |
| Scheduling | Celery Beat | Timezone-aware, per-prospect windows |
| DNC | No | Built-in enforcement |
| Dispositions | Basic status | Custom per-campaign with callback/DNC flags |
| Concurrency | Redis semaphore | Call ratio + damper controls |
| Retry | Celery auto-retry | Max calls per prospect + min time between calls |
How does the AMQP dialer pipeline work?
The Ticker emitsCampaignTick events via TickerExchange at each campaign’s dialer_interval. Three consumers process these:
- Hopper fills the prospect queue (filters by timezone, DNC, priority, expiry)
- Dialer originates calls (respects call ratio and damper settings)
- Scheduler manages scheduling requests (callbacks, time-delayed prospects)
VHOSTS.DIALER RabbitMQ vhost with configurable PREFETCH_COUNTS.
How are prospects assigned to live calls?
The Hopper selects prospects from the highest-priority list first. Selected prospects becomeActiveProspect entries (locked via semaphore). The Dialer then picks up ActiveProspects and originates outbound calls through the Vaani backend using the campaign’s assigned agent_id.
How does the hopper fill algorithm work?
On eachCampaignTick, the Hopper:
- Checks if the campaign is active and within its dialing window
- Acquires a campaign-level semaphore to prevent concurrent fills
- Queries prospects filtered by: timezone window (per-prospect local time), DNC list exclusion, list priority, expiry date, and max call attempts
- Selects a batch of prospects (limited by
DIALER_BATCH_SIZE) - Creates
ActiveProspectentries in the queue - Releases the semaphore
Debugging & Support
How do I debug a failed batch job?
- Check status:
GET /batch/{batch_id} - Look at individual item errors in
batch_itemstable - Check Celery logs:
docker-compose logs celery-worker - Common issues: Redis unreachable, capacity limit hit, SIP errors
The agent isn’t picking up calls. What’s wrong?
- Verify agent worker is running and connected to LiveKit
- Check
LIVEKIT_URLand API key configuration - Verify phone number has SIP trunks configured
- Check Redis
livekit:active_calls— might be atMAX_AGENT_SESSIONSlimit - Check agent worker logs for connection errors
How do I reset the active calls counter?
Product
How many concurrent calls can the system handle?
Controlled byMAX_AGENT_SESSIONS environment variable. The webhook handler tracks room events to maintain a count.
What languages are supported?
Depends on the configured STT/TTS providers:- Deepgram: 36+ languages
- Sarvam: Indian languages (Hindi, Tamil, etc.)
- OpenAI: Multiple via TTS, limited STT languages
- Language is configured per-agent via
STT_languagefield
Is there billing/metering?
Basic cost tracking per call (LLM, STT, TTS, platform costs). No integrated billing or payment gateway. Users have acredit field but it’s not actively enforced.