AMD screens a just-answered call for a few seconds to decide whether a human or an answering machine picked up, before the call is attached to a CXB Core bot. It protects bot/conversation cost from being spent on voicemail greetings.
Where it sits in the flow
When AMD is enabled, an answered call transitions ringing → amd_screening before attaching. A lightweight screener joins the LiveKit room, listens briefly, classifies, then either attaches the call or tears it down.
ringing → amd_screening → attaching → in_progress
↓ (machine/unknown, per action)
torn down
If AMD is disabled, answered calls go straight ringing → attaching.
Configuration
AMD is configured in system settings under dialler.amd (the AMDConfig block). Common fields:
| Setting | Default | Meaning |
|---|
enabled | false | Turn AMD on for the deployment. |
total_analysis_ms | 2000 | How long to listen before deciding (clamped 0.25–5s). |
initial_silence_ms | 2000 | Silence before any speech that implies a machine. |
greeting_ms | 2000 | Greeting length threshold for “long greeting” → machine. |
max_words | 4 | More words than this in the greeting → machine. |
beep_detection_enabled | true | Detect the voicemail beep tone (~850–1500 Hz) → machine. |
action_on_machine | teardown | What to do when a machine is detected. |
action_on_unknown | continue | What to do when the result is uncertain. |
The detector is a deterministic audio-energy model (Asterisk/VICIdial-style timings) — it counts words, greeting length, silence, and beep tone.
Outcomes
The screen returns one of three decisions, which the loop maps to a campaign-call state:
| Decision | Cause examples | Default action | Resulting state |
|---|
human | Short greeting then silence (a person saying “hello?”). | Attach to bot. | attaching → in_progress |
machine | Beep, too many greeting words, very long greeting, initial silence. | action_on_machine (teardown). | amd_machine (terminal) when torn down. |
unknown | Listen window elapsed without a confident decision. | action_on_unknown (continue). | Attaches when continue; closes as exhausted when teardown. |
Actions are configurable. With action_on_machine = continue, a detected machine is still attached to the bot (no teardown). With action_on_unknown = teardown, uncertain results are closed instead of attached. Choose based on how aggressive you want machine suppression to be versus the risk of dropping real humans.
Metrics
| Metric / stat | Meaning |
|---|
machine_detected_count | Campaign-level count of calls torn down as amd_machine. |
amd_result / amd_cause | Per-attempt decision and reason (e.g. machine / BEEP), stored on the attempt and call docs. |
amd_duration_ms | How long screening took for that attempt. |
Review machine_detected_count against expectations: a very high rate may mean AMD is too aggressive (dropping humans); a near-zero rate on a list with many landlines/voicemail may mean it is too lax.
Stale safety
AMD screening should last ~2 seconds. If the dialler dies mid-screen, a stale reaper closes any amd_screening row older than ~15s, tearing down the LiveKit room first so an answered call is never left stranded billing minutes.
Ops notes
- AMD is a deployment-level setting (system settings), not a per-campaign toggle in the wizard.
- AMD adds a short delay to every answered call before the bot speaks — keep
total_analysis_ms modest.
- Callback calls are screened too; a callback detected as a machine is closed like any other machine answer and its callback counters update.