Skip to main content

Development

How do I add a new AI provider (LLM/STT/TTS)?

  1. Add livekit-plugins-{provider} dependency to requirements.txt
  2. Update the relevant factory class:
    • LLM: plugins/llm.pyLLMFactory.get_instance()
    • STT: plugins/stt.pySTTFactory.get_instance()
    • TTS: plugins/tts.pyTTSFactory.get_instance()
  3. Add a new conditional branch matching the provider name
  4. Configure the API key in settings.py and .env
  5. Update the Agents model if new config fields are needed
  6. Update UI dropdowns in agent creation forms

How do I add a new API endpoint?

  1. Create or modify a router file in app/router/
  2. Define the endpoint: @router.get/post/put/delete
  3. Add auth: workspace_id = Depends(require_workspace_access(WorkspaceRole.developer))
  4. Create Pydantic schemas in app/db/schemas/
  5. 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 the custom_functions JSON column:
{
  "name": "check_inventory",
  "description": "Check if a product is in stock",
  "url": "https://api.example.com/check",
  "method": "POST",
  "parameters": {
    "product_id": {"type": "string", "description": "Product ID"}
  },
  "speak_during": "Let me check that for you",
  "speak_after": "I have the result"
}
The AgentCaller registers these as @function_tool methods at runtime via utils/dynamic_tools.py.

Architecture

What’s the difference between Batch Jobs and Campaigns?

AspectBatch JobsCampaigns (Vaani Dialer)
ExecutionCelery (distributed)AMQP Dialer (Twisted + RabbitMQ)
Prospect ManagementFlat phone listProspectList → Prospect → ActiveProspect pipeline
SchedulingCelery BeatTimezone-aware, per-prospect windows
DNCNoBuilt-in enforcement
DispositionsBasic statusCustom per-campaign with callback/DNC flags
ConcurrencyRedis semaphoreCall ratio + damper controls
RetryCelery auto-retryMax calls per prospect + min time between calls

How does the AMQP dialer pipeline work?

The Ticker emits CampaignTick 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)
All operate within a dedicated 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 become ActiveProspect 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 each CampaignTick, the Hopper:
  1. Checks if the campaign is active and within its dialing window
  2. Acquires a campaign-level semaphore to prevent concurrent fills
  3. Queries prospects filtered by: timezone window (per-prospect local time), DNC list exclusion, list priority, expiry date, and max call attempts
  4. Selects a batch of prospects (limited by DIALER_BATCH_SIZE)
  5. Creates ActiveProspect entries in the queue
  6. Releases the semaphore

Debugging & Support

How do I debug a failed batch job?

  1. Check status: GET /batch/{batch_id}
  2. Look at individual item errors in batch_items table
  3. Check Celery logs: docker-compose logs celery-worker
  4. Common issues: Redis unreachable, capacity limit hit, SIP errors

The agent isn’t picking up calls. What’s wrong?

  1. Verify agent worker is running and connected to LiveKit
  2. Check LIVEKIT_URL and API key configuration
  3. Verify phone number has SIP trunks configured
  4. Check Redis livekit:active_calls — might be at MAX_AGENT_SESSIONS limit
  5. Check agent worker logs for connection errors

How do I reset the active calls counter?

redis-cli SET livekit:active_calls 0
This key has a 600-second TTL as a safety net.

Product

How many concurrent calls can the system handle?

Controlled by MAX_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_language field

Is there billing/metering?

Basic cost tracking per call (LLM, STT, TTS, platform costs). No integrated billing or payment gateway. Users have a credit field but it’s not actively enforced.