Concept

Flow nodes

Deep dive into FlowNodeModel — the building blocks of every conversation flow.

Overview

Each node in a template’s flow represents a distinct phase of the conversation. The agent enters the initial_node at the start and transitions between nodes via function calls. Nodes define what the LLM should do (task messages), what happens on entry/exit (pre/post actions), and what tools the LLM can invoke (functions).

Enter Node
Run pre_actions
LLM processes task_messages
LLM calls function
Run hooks + post_actions
Transition to next node

FlowNodeModel fields

FieldTypeDescription
node_namestringUnique identifier for this node within the flow
task_messagesList[TaskMessage]System/user messages that instruct the LLM
role_messagesList[TaskMessage]Additional role-specific messages (persona, tone)
pre_actionsList[FlowAction]Actions executed before the LLM processes task messages
post_actionsList[FlowAction]Actions executed after leaving the node
functionsList[FlowFunction]Node-scoped functions the LLM can call
vad_configOptional[VadConfig]Node-level VAD override
interruptionOptional[InterruptionConfig]Node-level interruption override
input_collectionOptional[InputCollectionConfig]DTMF/speech input collection config

Task messages

Task messages are the LLM instructions for a node. They follow the standard chat-completion message format and support {'{variable}'} placeholder syntax.

FieldTypeDescription
rolestringMessage role — typically "system" or "user"
contentstringMessage content — supports {'{variable}'} placeholders
task-message-example.json
json
{
  "task_messages": [
    {
      "role": "system",
      "content": "You are calling {customer_name} about their appointment on {appointment_date} with {doctor_name}. Be polite and professional."
    }
  ],
  "role_messages": [
    {
      "role": "system",
      "content": "Speak in a warm, conversational Indian English tone. Keep responses under 2 sentences."
    }
  ]
}

Variable Placeholders

Any {placeholder} in message content is resolved from the lead payload, template secrets, or credential secrets at call time. See Variable Substitution for details.

Flow actions (pre & post)

Actions execute at specific lifecycle points. pre_actions run before the LLM; post_actions run after exiting the node.

FieldTypeDescription
type"tts_say" \| "end_conversation" \| "function"The action type
textOptional[string]Text to speak (for tts_say)
handlerOptional[string]Handler function name (for function type)
argsOptional[object]Arguments to pass to the handler

Action Types

tts_say — Speaks text immediately via TTS. Supports {'{variable}'} substitution.

json
{
  "type": "tts_say",
  "text": "Hello {customer_name}! Please hold for just a moment."
}

end_conversation — Ends the conversation immediately.

json
{ "type": "end_conversation" }

function — Calls an internal handler function with optional arguments.

json
{
  "type": "function",
  "handler": "mute_stt",
  "args": { "duration": 3 }
}

Node transition patterns

Nodes transition through functions. When the LLM calls a function with transition_to, the conversation moves to that node.

greeting
collect_details
confirm_order
farewell

Common patterns:

  • Linear flow: greeting → collect → confirm → farewell
  • Branching: greeting → (confirm OR reschedule) → farewell
  • Loopback: collect_details → (insufficient data? stay) → confirm
  • Hub-and-spoke: main_menu → (billing | support | orders) → main_menu

Stay on Current Node

Set transition_to: null on a function to stay on the current node after execution. Useful for data collection without changing phases.

Per-Node configuration overrides

Nodes can override template-level VAD, interruption, and input collection settings. These overrides follow the reset-then-apply pattern.

Reset-then-Apply Pattern

On every node transition, VAD, interruption, and input collection configs are reset to template defaults first, then node-level overrides apply. This prevents configuration bleed between nodes.

OverrideReset BehaviorUse Case
vad_configReset to template VADIncrease silence threshold for thinking time
interruptionReset to template interruptionDisable interruption during critical info
input_collectionReset to null (disabled)Enable multi-segment capture for specific nodes
is_activeSet false to silently exclude the node at load time (no validation error; just removed).
node-override-examples.json
json
{
  "vad_config": { "stop_secs": 2.0 },
  "interruption": { "mode": "disabled_discard" },
  "input_collection": {
    "enabled": true,
    "user_speech_timeout": 3.0
  }
}

interruption.mode accepts "enabled" or "disabled_discard". input_collection has only enabled and user_speech_timeout — there is no DTMF support today. See Interruption control and Input collection for full semantics.

Complete flowNode example

collect-details-node.json
json
{
  "node_name": "collect_details",
  "task_messages": [
    {
      "role": "system",
      "content": "You are collecting delivery details from {customer_name}. Ask for their preferred delivery date and time slot."
    }
  ],
  "role_messages": [
    {
      "role": "system",
      "content": "Speak in a friendly, conversational tone. Keep responses concise."
    }
  ],
  "pre_actions": [
    { "type": "tts_say", "text": "Great, let me help you schedule your delivery." }
  ],
  "post_actions": [],
  "functions": [
    {
      "name": "delivery_scheduled",
      "description": "Customer has confirmed a delivery date and time slot",
      "properties": {
        "delivery_date": { "type": "string", "description": "YYYY-MM-DD format" },
        "time_slot": { "type": "string", "enum": ["morning", "afternoon", "evening"] }
      },
      "required": ["delivery_date", "time_slot"],
      "transition_to": "farewell",
      "hooks": [
        {
          "name": "update_outcome_in_database",
          "expected_fields": {
            "outcome": { "source": "static", "value": "scheduled" },
            "delivery_date": { "source": "llm" },
            "time_slot": { "source": "llm" }
          }
        }
      ]
    }
  ],
  "vad_config": { "stop_secs": 1.5 },
  "interruption": { "mode": "disabled_discard" },
  "is_active": true
}

Design Tip

Keep nodes focused on a single task. A node that tries to do too much leads to confused LLM behavior. Break complex workflows into multiple small, well-defined nodes.

Was this helpful?