Conversation behaviour
This chapter describes how a call feels to the person on the line and which settings shape it: who speaks first, whether the caller can interrupt, how the gateway copes with echo and noise, what happens when the AI is slow, and how a call ends or moves to a person. Every behaviour below follows the same pattern: what the caller experiences, what the gateway does, the variables, and the log line that shows it at work.
The settings go in .env; restart the gateway after changing them. Recognition settings live in Speech recognition, voices in Text to speech, and the brain in AI brain.
Greeting
Inbound calls (pipeline mode). The bot speaks first. When the call is answered the gateway sends the brain a fixed opening prompt ("Hello caller_name and language_code, posted before the call connects, shapes the greeting; see Asterisk over AudioSocket.
Inbound calls (realtime mode). Gemini Live and LiteBot Live greet through their own kick-off; see Realtime mode.
Outbound calls. The called party answers first with "hello", so you choose how the bot opens. Set the default with OUTBOUND_GREETING_MODE, or per call with greeting_mode in the session metadata (greetingMode in the /outbound/initiate body).
| Mode | Caller hears |
|---|---|
| static | A recorded WAV straight away. The file is initial_greeting_audio (or audioFile) for the call, else the language's OUTBOUND_STATIC_AUDIO_ML_IN-style file, else a bundled file for the language. If none is found the call falls back to dynamic and logs a warning. |
| dynamic | A greeting generated by the brain from initial_greeting_text (or initialGreeting) plus the call metadata. Without text, the default greeting for the language is used. |
| hybrid | The static WAV first, then the brain's opening line. |
| wait | Silence until the called party speaks. |
| Variable | Default | What it does |
|---|---|---|
| OUTBOUND_GREETING_MODE | static | Default greeting mode for outbound calls |
| OUTBOUND_STATIC_AUDIO_ML_IN | none | WAV played in static and hybrid mode for that language |
| OUTBOUND_DEFAULT_GREETING_ML_IN | built-in text | Greeting text used in dynamic mode when the call supplies none |
The _ML_IN suffix is the language code in upper case with the hyphen replaced by an underscore; use _HI_IN, _EN_IN and so on for other languages. All message files are WAV, 8 kHz, 16-bit PCM, mono. Outbound dialling itself is covered in HTTP API.
Interrupting the bot
A caller who talks over the bot expects it to stop. With barge-in on, playback stops as soon as the caller speaks. Because a speech detector cannot tell a person from hold music, the gateway then holds the part that was not yet played: if real words arrive, the held audio is discarded; if nothing qualifying arrives in time, the bot resumes where it stopped.
| Variable | Default | What it does |
|---|---|---|
| ENABLE_BARGE_IN | false | Master switch. Set true to let callers interrupt |
| BARGE_IN_USE_VAD | true | The speech detector decides, not raw volume |
| BARGE_IN_VAD_THRESHOLD | 0.5 | Detector confidence needed |
| BARGE_IN_THRESHOLD | 500 | Volume threshold used when the detector is off |
| BARGE_IN_DELAY | 200 | Milliseconds at the start of playback during which interruption is ignored |
| BARGE_IN_RESET_HYSTERESIS | 5 | Quiet frames needed before a new interruption can be counted |
| BARGE_IN_RESUME | true | Hold and resume after a false interruption. false discards the tail every time |
| BARGE_IN_MIN_WORDS | 0 | Words needed to confirm. 0 means any transcript that passes the sanity gate confirms, so a bare "yes" counts |
| BARGE_IN_FALSE_TIMEOUT_MS | 1500 | How long to wait for words before resuming. 0 disables holding |
| BARGE_IN_MAX_RESUMES | 2 | Resumes per turn before the tail is discarded instead |
ENABLE_BARGE_IN=true
BARGE_IN_USE_VAD=true
BARGE_IN_RESUME=true
Log lines: BARGE-IN: hold armed, BARGE-IN: false interruption (followed by the resume), and BARGE-IN: confirmed by N word(s), discarding held audio.
Not hearing itself
Some handsets leak the bot's own voice back into the line. Without protection the bot would cut itself off, and a one-word echo transcript would count as the caller interrupting. The echo guard measures how loud the echo is while the bot speaks and only accepts an interruption that is clearly louder. After the bot stops, a transcript that repeats the bot's own words is dropped.
| Variable | Default | What it does |
|---|---|---|
| BARGE_IN_ECHO_GUARD | true | Master switch for the guard |
| BARGE_IN_ECHO_MARGIN_DB | 8 | How many dB louder than the measured echo the caller must be |
| BARGE_IN_ECHO_WINDOW_MS | 4000 | Window over which the echo level is measured, sampled only while the bot plays |
| BARGE_IN_ECHO_WARMUP_PACKETS | 10 | Audio packets at the start of playback in which interruption is ignored |
| BARGE_IN_ECHO_TAIL_MS | 800 | After playback ends, transcripts that are the bot's own words are dropped for this long |
| BARGE_IN_ECHO_MAX_WORDS | 3 | Echo is short. Longer matches, doubled words and yes/no words are treated as the caller |
| BARGE_IN_ECHO_MAX_THRESHOLD | 24000 | Upper limit for the echo-adjusted volume threshold |
| BARGE_IN_ECHO_LOG | true | Log each ignored echo transcript |
Log line: BARGE-IN: echo transcript ignored. If callers report that the bot talks over itself or stops mid-sentence for no reason, look for this line first.
Noisy lines
Street noise and a loud room can make a fixed volume threshold fire constantly. The gateway therefore learns each call's background level. For the first moments of a call (default 1 s) it only listens (no interruption can fire); afterwards it tracks the quiet level over a rolling window and sets the barge-in threshold a fixed margin above it, kept between a minimum and a maximum.
| Variable | Default | What it does |
|---|---|---|
| NOISE_FLOOR_ENABLED | true | Per-call adaptive threshold |
| NOISE_FLOOR_CALIBRATION_MS | 1000 | Listening-only period at the start of the call |
| NOISE_FLOOR_ROLLING_WINDOW_MS | 10000 | Window used to track the quiet level afterwards |
| NOISE_FLOOR_MARGIN_DB | 6 | How far above the quiet level the threshold sits |
| NOISE_FLOOR_MIN_THRESHOLD | 200 | Lowest threshold allowed |
| NOISE_FLOOR_MAX_THRESHOLD | 2000 | Highest threshold allowed |
| NOISE_FLOOR_LOG | true | Log the learned level |
| NOISE_FLOOR_LOG_INTERVAL_MS | 5000 | Interval between those log lines |
For recognisers that work on whole utterances (the batch providers in Speech recognition), a second gate throws away segments that are both short and quiet before they are sent for recognition, so clicks and coughs cost no recognition request.
| Variable | Default | What it does |
|---|---|---|
| VAD_MIN_SPEECH_GATE_ADAPTIVE | true | Enable the short-and-quiet gate |
| VAD_MIN_SPEECH_GATE_DURATION_MS | 500 | Segments shorter than this are candidates for discarding |
| VAD_MIN_SPEECH_GATE_ENERGY_MULT | 2.0 | ...if their peak is also below the noise floor times this value |
| VAD_MIN_SPEECH_FRAMES | 4 | Minimum speech frames for the detector to open a segment |
Sarvam streaming recognition ends turns on the Sarvam side, so these two gates matter most with batch providers. The remaining detector settings are advanced tuning and are listed in the environment reference.
Speech while the bot is busy
If the caller says something while the AI is still thinking, or while the bot is speaking and they did not interrupt, the words are not lost. The gateway keeps them, then answers once the current turn has finished; a bare "okay" said while the bot was still thinking is stale and is dropped. The variables and log lines are in Held transcripts.
Hold music and carrier announcements
When the caller's phone plays hold music or a network announcement, the recogniser can mistake it for speech. A sanity gate between recognition and the AI drops carrier announcements, hallucinated loops and repeated-word runs before they reach the bot. See What never reaches the bot for the gate settings.
Thinking sounds and waiting messages
While the AI works the caller hears a short filler sound instead of silence, and it is cut as soon as the reply audio is ready. If the AI takes unusually long, a spoken waiting message plays; if it fails outright, a final apology is spoken. The gateway ships several filler files in sounds/, chosen with PROCESSING_SOUND_TYPE (default chime); PROCESSING_SOUND_DIR points to your own set and PROCESSING_SOUND_FILE to a single file. PROCESSING_SOUND_HARD_CUT (default true) stops the filler the moment speech is ready, and TTS_TAIL_DELAY_MS (default 40) is the pause after playback before listening resumes. The waiting messages are LLM_TIMEOUT_MESSAGE and LLM_FINAL_TIMEOUT_MESSAGE, with per-language variants, switched by TIMEOUT_MESSAGE_ENABLED. All of these are in When the AI is slow or fails.
Incomplete sentences
Callers pause mid-sentence ("I would like to book... um"). With incomplete-turn detection on, the brain can answer with a flag saying the sentence is unfinished (shouldWaitForMore) or that the caller is thinking (shouldGiveTime). The gateway then stays silent and waits for the next transcript, which is joined to the first. Only brains that return these flags use it: your custom endpoint, and LiteBot where the bot is set up for it. See Flags.
| Variable | Default | What it does |
|---|---|---|
| ENABLE_INCOMPLETE_TURN_DETECTION | false | Honour the wait-for-more and give-time flags |
Transfer to a person
The bot hands the call to a human when the brain sets its escalate flag, or when a tool you listed in LITEBOT_TRANSFER_TOOLS runs. How the call actually moves depends on how it arrived:
- SIP-bridge calls are transferred with a SIP REFER to
TRANSFER_SIP_URI; see SIP trunk. - AudioSocket calls call your
TRANSFER_ENDPOINT, an HTTP webhook that moves the Asterisk channel. It needs thechannelmetadata; see Transfers. - Realtime calls are covered in Realtime mode.
TRANSFER_ENABLED=true
TRANSFER_SIP_URI=sip:7000@pbx.example.com
TRANSFER_MESSAGE_TEXT_EN=Please hold while I transfer you to a human agent.
| Variable | Default | What it does |
|---|---|---|
| TRANSFER_ENABLED | false | Master switch. Set true to allow transfers |
| TRANSFER_SIP_URI | none | REFER target for SIP-bridge calls |
| TRANSFER_ENDPOINT | none | Webhook URL for AudioSocket calls |
| TRANSFER_TIMEOUT | 5000 | Milliseconds to wait for that webhook |
| TRANSFER_MESSAGE | none | WAV played before transferring; a per-language TRANSFER_MESSAGE_ML file overrides it |
| TRANSFER_MESSAGE_TEXT_EN | Please hold while I transfer you to a human agent. | Spoken instead when no WAV exists |
| TRANSFER_ERROR_MESSAGE | none | WAV played when the transfer fails or is disabled; per-language TRANSFER_ERROR_MESSAGE_ML overrides it |
| TRANSFER_ERROR_TEXT_EN | I am sorry, I was unable to transfer you. Please try calling again. | Spoken instead when no WAV exists |
The language suffix is the first segment of the language code in upper case (EN, ML, HI); the same suffix works on the TRANSFER_MESSAGE_TEXT_ and TRANSFER_ERROR_TEXT_ variables. After an error message the call ends. Log line for a SIP transfer: SIP REFER transfer initiated.
Ending the call
When the brain asks to hang up (shouldHangup, or a LiteBot tool named in LITEBOT_HANGUP_TOOLS, default hangupCall), the gateway first finishes speaking the reply, so the caller hears the goodbye in full, and only then ends the call. If the brain gave no closing words, it plays the goodbye message: the GOODBYE_MESSAGE WAV (a per-language GOODBYE_MESSAGE_ML overrides it) or, when no file exists, the spoken text GOODBYE_MESSAGE_TEXT_EN or its language variant.
| Variable | Default | What it does |
|---|---|---|
| GOODBYE_MESSAGE | none | WAV played at a bot-initiated hang-up |
| GOODBYE_MESSAGE_TEXT_EN | Thank you for calling. Goodbye! | Spoken text when no WAV exists |
| LLM_HANGUP_DRAIN_MAX_MS | 15000 | Longest the gateway waits for the goodbye audio to play out |
When the caller hangs up first, the session ends immediately and the end-of-call webhook fires; see Webhooks and billing.