Skip to main content
This document describes how voice agents determine when to end a conversation and the end_conversation tool used in function_call exit mode. Related: Voice Agents & CONNECT_AGENT Node | Agents API

Types


Exit Modes Explained

The LLM is given the end_conversation tool and decides when to call it. This is the most natural exit strategy because the LLM understands conversational context. How it works with maxSteps: 1: Each turn, the LLM produces either:
  • Text response (normal turn) - finishReason: 'stop', text is spoken via TTS
  • Tool call (end conversation) - finishReason: 'tool-calls', farewell_message from tool args is spoken via TTS
The LLM cannot do both in a single step. When it calls end_conversation, the farewell_message arg is used as the spoken response. When the LLM calls end_conversation:
Tool Definition (internal):
Important: The tool’s execute function is a no-op. The actual exit detection happens in the orchestrator by checking finishReason === 'tool-calls' and inspecting toolCalls[0].toolName.

Dynamic Tool (with Resolution Criteria)

When an agent has resolution criteria configured, the tool schema is dynamically extended with a resolution field. The criteria descriptions are injected into the tool’s describe() text so the LLM knows exactly what to evaluate.
Key behaviors:
  • When no criteria are configured, the static tool (without resolution) is used — zero overhead
  • The resolution array length must match the number of criteria — the LLM must evaluate every criterion
  • Evidence is required (min 1 char) — forces the LLM to justify each judgment
  • Criteria are frozen at conversation start — changes mid-conversation have no effect

phrase_match

The system checks the agent’s text response for the literal string [COMPLETE]. If found, the conversation ends with reason completed. How it works:
Important: [COMPLETE] is not stripped from the response before TTS. The agent’s instructions should guide it to place [COMPLETE] at the very end of its farewell so it is less noticeable when spoken. Limitations:
  • Less natural - requires the LLM to include [COMPLETE] in its response
  • [COMPLETE] will be spoken to the caller (it is not stripped)
  • The [COMPLETE] string may occasionally appear in normal conversation
  • No structured reason or summary (unlike function_call mode)

Exit Condition Priority

Exit conditions are checked in this order after every turn. The first matching condition triggers the exit. Key detail: Exit phrase matching (priority 2) is always active, even in function_call mode. This provides a safety net - if the user says “goodbye” but the LLM doesn’t call the tool, the phrase matcher catches it.

Exit Reason to Output Path Mapping


Conversation Data After Exit

After the conversation ends, the ConversationResponse (see conversations.md) is populated with:

Frontend Integration Notes

Call Flow Builder UI

When configuring a CONNECT_AGENT node in the flow builder:
  1. Exit Mode Selection - Offer a dropdown with two options:
    • function_call (default, recommended) - “Agent decides when to end (AI-powered)”
    • phrase_match - “End when agent says [COMPLETE] (pattern-based)”
  2. Exit Phrases - Always show this field regardless of exit mode (it’s checked in both modes as a safety net). Provide defaults: ['goodbye', 'bye', 'thank you goodbye'].
  3. Output Paths - Show all 6 output ports on the node:
    • onComplete (required, always show)
    • onExitPhrase (optional)
    • onMaxTurns (optional)
    • onTimeout (optional)
    • onHangup (optional)
    • onError (optional)
    If an optional output is not connected, the flow falls back to onComplete (or default for errors).
  4. Variable Extraction - When configuring extractVariables:
    • last_response needs no additional config
    • pattern needs a regex input field with validation
    • Do NOT show semantic as an option (it’s not implemented)

Analytics Dashboard

Display exit reason breakdown for each agent/node:
Key metrics to surface:
  • Completion rate: (completed + exit_phrase) / total - higher is better
  • Error rate: error / total - lower is better
  • Hangup rate: user_hangup / total - high values suggest poor agent quality