AI brain
The AI brain is the language model side of a call: it receives what the caller said and returns the reply the gateway speaks. The gateway supports two brains, LiteBot and your own HTTP endpoint. This chapter covers how to choose between them, every variable each one reads, and what callers hear when the brain is slow or fails. Speech in and out is covered in Speech recognition and Text to speech; ready-made combinations are in Configuration recipes.
Choosing
Set LLM_PROVIDER to one of the two values below. Always set it explicitly; leaving it unset is not a supported configuration.
LLM_PROVIDER=litebot
| Brain (LLM_PROVIDER) | Use it when | You get |
|---|---|---|
| litebot | You want a managed bot with prompts, tools and transfers | Bots with tools, transfer and hang-up by tool, end-of-call hooks, session cost reconciliation |
| custom | You already have your own backend or model service | Full control: you receive the message as JSON and return the reply as JSON |
Realtime LiteBot Live is a different mode that replaces the whole speech pipeline; see Realtime mode.
LiteBot
Point the gateway at your LiteBot server and choose a bot.
LLM_PROVIDER=litebot
LITEBOT_API_URL=http://<litebot-host>:3345
LITEBOT_BOT_ID=customer-service
| Variable | Default | What it does |
|---|---|---|
LITEBOT_API_URL |
http://localhost:3000 |
Address of the LiteBot server |
LITEBOT_BOT_ID |
customer-service |
Bot that answers calls |
LITEBOT_TIMEOUT |
30000 |
Request timeout in milliseconds |
LITEBOT_STREAMING |
true |
Speak the answer sentence by sentence as it arrives; false waits for the whole answer |
LITEBOT_HANGUP_TOOLS |
hangupCall |
Comma-separated tool names that end the call |
LITEBOT_TRANSFER_TOOLS |
empty | Comma-separated tool names that trigger a transfer; empty relies on the bot's escalate or transfer flag |
LITEBOT_RECONCILE_COST |
true |
At hang-up, read LiteBot's session total and correct the per-call cost |
LITEBOT_RECONCILE_TIMEOUT_MS |
1500 |
Hard cap on that lookup |
LITEBOT_SESSION_END |
true |
Tell LiteBot the session ended so end-of-session hooks run now |
LITEBOT_SESSION_END_TIMEOUT_MS |
5000 |
Time allowed for that notification |
LITEBOT_ERROR_TEXT_GUARD |
true |
Never speak an error that LiteBot relays as the reply |
LITEBOT_ERROR_TEXT_PATTERN |
empty | Regex override for what counts as a relayed error |
Choosing a bot per call
Post a botId in the session metadata for a call and that bot answers instead of LITEBOT_BOT_ID. The id is case-sensitive; an unknown id falls back to the default bot. The metadata request is described in HTTP API.
What the gateway sends
Each turn the gateway sends LiteBot the following.
| Field | Content |
|---|---|
message |
What the caller said |
sessionId |
Conversation identifier for the call |
botId |
The bot chosen for this call |
userId |
The call UUID |
context |
Language (default en-IN), caller name, caller phone, timestamp, plus any session metadata you posted |
Streaming
With LITEBOT_STREAMING on, the first sentence is spoken while the rest is still being written. Bots that call tools deliver their final answer as one block even with streaming on; that is LiteBot's behaviour, not a gateway setting.
Hang-up, transfer and cost
- A tool named in
LITEBOT_HANGUP_TOOLSends the call after the goodbye is spoken. Add your own tool names, comma-separated. - A tool named in
LITEBOT_TRANSFER_TOOLShands the caller to a human. Transfer set-up and what happens when it fails are in Conversation behaviour. - Per-turn cost can miss turns that finish after the call ends. With
LITEBOT_RECONCILE_COSTon, the gateway reads LiteBot's own total at hang-up and only ever raises the recorded cost to match. Where costs go is covered in Webhooks and billing. - With
LITEBOT_SESSION_ENDon, the bot's end-of-session hooks (a CRM log, for example) run at hang-up instead of at LiteBot's idle sweep. The call is fire-and-forget and never delays hang-up. An older LiteBot without that route returns 404, which is logged once and is harmless.
When LiteBot relays an error
If LiteBot's own model fails (usually an invalid or expired key on the bot), LiteBot may return the failure as the reply text, starting with Error:. With LITEBOT_ERROR_TEXT_GUARD on, the gateway does not speak it. The caller hears the final-timeout message from When the AI is slow or fails, and the log records that LiteBot returned an upstream error as the reply. Fix the cause on the LiteBot side. LITEBOT_ERROR_TEXT_PATTERN replaces the default match, a reply beginning with error: in any case.
Custom HTTP endpoint
The gateway POSTs each turn to your URL and speaks the text in the JSON you return.
LLM_PROVIDER=custom
CUSTOM_LLM_URL=https://your-server.example.com/chat
CUSTOM_LLM_AUTH_TYPE=bearer
CUSTOM_LLM_AUTH_TOKEN=your-secret-token
| Variable | Default | What it does |
|---|---|---|
CUSTOM_LLM_URL |
none | Required. Your HTTP endpoint |
CUSTOM_LLM_TIMEOUT |
30000 |
Request timeout in milliseconds |
CUSTOM_LLM_AUTH_TYPE |
none |
none, bearer or header |
CUSTOM_LLM_AUTH_TOKEN |
empty | Token for bearer or header authentication |
CUSTOM_LLM_AUTH_HEADER |
empty | Header name to carry the token when the type is header |
CUSTOM_LLM_RESPONSE_FIELD |
empty | Dot path to the reply text when your JSON is not an auto-detected shape, for example data.output.message |
CUSTOM_LLM_SESSION_FIELD |
empty | Dot path to your session id in the reply |
Request
Your endpoint receives a POST with this JSON body.
{
"message": "Hello, I need help with my order",
"sessionId": "custom-session-1706234567890-abc123xyz",
"history": [
{ "role": "user", "content": "Hi" },
{ "role": "assistant", "content": "Hello! How can I help you today?" }
],
"context": {
"userId": "550e8400-e29b-41d4-a716-446655440000",
"callerName": "John Doe",
"callerPhone": "+9198xxxxxxxx",
"language": "en-IN",
"timestamp": "2024-01-25T10:30:00.000Z",
"custom_field_1": "value1",
"custom_field_2": "value2"
}
}
| Field | Type | Description |
|---|---|---|
message |
string | The caller's words as text |
sessionId |
string | Identifier for conversation continuity |
history |
array | Earlier messages (optional) |
context.userId |
string | Unique call UUID |
context.callerName |
string | Caller's name, from session metadata |
context.callerPhone |
string | Caller's phone number |
context.language |
string | Language code, such as en-IN or hi-IN |
context.timestamp |
string | ISO 8601 time of the turn |
context.* |
any | Any other metadata you posted for the call |
Response
Return JSON. The recommended shape:
{
"response": "I'd be happy to help you with your order. Can you please provide your order number?",
"sessionId": "your-session-id-123",
"shouldEscalate": false,
"shouldHangup": false
}
The gateway also finds the reply text under any of these field names.
{ "response": "..." }
{ "text": "..." }
{ "message": "..." }
{ "output": "..." }
{ "result": "..." }
{ "answer": "..." }
{ "reply": "..." }
{ "content": "..." }
Nested formats also work:
{ "data": { "response": "..." } }
{ "data": { "text": "..." } }
{ "data": { "message": "..." } }
If your JSON uses another shape, set CUSTOM_LLM_RESPONSE_FIELD.
Flags
All four flags are optional booleans. They are also accepted nested under metadata or data.
| Flag | Effect |
|---|---|
shouldEscalate |
Transfer the call to a human |
shouldHangup |
End the call after the reply is spoken |
shouldWaitForMore |
The caller's sentence seems unfinished; the gateway says nothing and waits for more speech |
shouldGiveTime |
The caller is thinking; wait without speaking |
shouldWaitForMore and shouldGiveTime only take effect when ENABLE_INCOMPLETE_TURN_DETECTION=true.
To transfer, return:
{
"response": "I'll connect you with a customer service representative right away.",
"shouldEscalate": true
}
To end the call, return:
{
"response": "Thank you for calling! Have a great day. Goodbye!",
"shouldHangup": true
}
A transfer that fails or is not configured plays a message and ends the call; see Conversation behaviour.
When the AI is slow or fails
Two messages cover a struggling brain. They play only when the brain is slow or fails.
| Variable | Default | What it does |
|---|---|---|
TIMEOUT_MESSAGE_ENABLED |
false |
When true, a slow reply makes the gateway speak the timeout message while it keeps waiting |
LLM_TIMEOUT_MESSAGE |
built-in English | The slow-reply message |
LLM_TIMEOUT_MESSAGE_ML |
built-in English | The slow-reply message for Malayalam calls |
LLM_FINAL_TIMEOUT_MESSAGE |
built-in English | Spoken on hard failure |
LLM_FINAL_TIMEOUT_MESSAGE_ML |
built-in English | Hard-failure message for Malayalam calls |
Only the _ML variants exist, and they apply only to Malayalam (ml-IN) calls. Every other language uses the base message.
- Slow-reply default: "I'm experiencing some technical difficulties. Please hold on while I try to process your request."
- Hard-failure default: "I'm sorry, I'm having trouble processing your request right now. Please try again in a moment."
The hard-failure message is spoken on a request error, a final timeout, or an error text relayed by LiteBot.
Processing sound
A short filler sound can play while the brain thinks, so the line is not silent.
| Variable | Default | What it does |
|---|---|---|
PROCESSING_SOUND_ENABLED |
false |
Turn the filler on |
PROCESSING_SOUND_TYPE |
chime |
Built-in sound to use |
PROCESSING_SOUND_FILE |
empty | Your own file, absolute or relative to the install directory |
PROCESSING_SOUND_VOLUME |
0.3 |
Playback volume |
PROCESSING_SOUND_START_DELAY |
2000 |
Milliseconds of waiting before the sound starts |
PROCESSING_SOUND_LOOP |
false |
Repeat the sound while waiting |
PROCESSING_SOUND_LOOP_DELAY |
2000 |
Milliseconds between repeats |
PROCESSING_SOUND_HARD_CUT |
true |
Cut the filler the instant speech is ready; false lets the phrase finish |