Skip to main content
Audact
See the offer

End-of-call detection

Two independent mechanisms to end a call from the agent side: the end_call tool for model judgement, and deterministic trigger_phrases and silence detection.

An Audact voice agent can end a call itself. There are two independent mechanisms, and they are configured in different places. Both converge on the same teardown choreography (disclosure gate → idempotency → optional closing line → hang up → evidence + call_end_detected webhook), so an agent-initiated hangup has exactly the same side effects however it was triggered.

1. The end_call tool (model judgement)

When you attach an end_call tool to an agent, the model is offered a function it may call when it judges the conversation to be complete (the caller said goodbye, the task is resolved, nothing is left to do).

  • What the model sees. A function-calling tool whose name is the name you gave the tool when you attached it — it is not automatically called end_call or hangup. end_call (provider) and hangup (provider-tool) are Audact-internal identifiers that bind the tool to the hang-up behaviour; the LLM only ever sees your tool's configured name and its description. If your agent prompt refers to the tool by name, use the name you configured.
  • Arguments. The tool takes a single optional free-text reason (the model's own note, e.g. "caller said goodbye"); it is never required and the model is told never to ask the caller for it.
  • When it fires. Entirely at the model's discretion. The tool's description instructs it to call it only when the conversation is done and never before the mandatory disclosure has been delivered — and the disclosure gate below enforces that regardless of what the model does.
  • This tool is independent of the end_call configuration object below: it works even if no trigger_phrases are configured.

2. The end_call configuration (deterministic detection)

The end_call object on an agent's configuration ends the call without the model, by watching the caller's speech:

  • trigger_phrases — goodbye phrases matched at the end of the caller's utterance (terminal position). "goodbye" at the end of a turn ends the call; "goodbye and one more thing…" does not. Matching is case-insensitive, ignores trailing punctuation, and has a diacritics-stripped fallback.
  • silence — ends the call after the caller goes quiet, re-prompting up to max_reprompts times each window_ms of silence first.

Minimum configuration to turn it on

A merely non-empty end_call object is not enough. Deterministic detection does something only when:

  • trigger_phrases has at least one phrase for the call's locale (enables goodbye-phrase detection), and/or
  • silence.window_ms is greater than 0 (enables the silence timeout).

closing_line on its own does nothing — it is only spoken once a trigger (or the end_call tool) fires. The zero/empty object means the deterministic policy is off.

Recommended trigger_phrases for a receptionist (en): goodbye, bye, bye bye, that's all, that's everything, that will be all, nothing else, no that's it, thank you goodbye.

3. Locale keys

All locale-keyed maps in end_call (trigger_phrases, closing_line, silence.reprompt_text) use tolerant key resolution:

  1. exact match on the call's language tag (en-GB), then
  2. primary-subtag match (en-GB ↔ en ↔ en-IE), then
  3. if the map has exactly one entry, that entry is used regardless of locale.

So use en — you do not need separate en-GB/en-IE keys. The examples in this spec use en and nl for this reason.

4. closing_line vs the model's own goodbye

closing_line is a fixed line the agent speaks in addition to whatever the model already said — a separate scripted TTS line, not a replacement. If your agent prompt already scripts a goodbye (e.g. "Thanks for calling. Bye.") and you set a closing_line, the caller hears two goodbyes.

Pick one:

  • leave closing_line empty and let the model say goodbye, or
  • set closing_line and instruct the prompt not to say its own goodbye.

5. Timing of the hang-up

  • Disclosure gate. Termination is suppressed until the mandatory disclosure has been delivered for the call (the sole exemption is voicemail). Until then, an end_call tool call or a trigger phrase is a no-op and the call continues.
  • Idempotency. Only the first termination for a call proceeds; duplicate or concurrent triggers (the model calling the tool twice, a phrase firing right after the tool) are no-ops.
  • Closing line is awaited. When a closing_line is set, Audact waits for it to finish playing and then holds a short additional drain before deleting the media room, so the line is not clipped mid-word. A closing_line is therefore the reliable way to guarantee a complete spoken goodbye before hang-up.
  • Without a closing_line, teardown proceeds as soon as the trigger fires; the model's own final sentence is ordinary conversational audio and is not specially drained, so if you rely on the model's scripted goodbye make sure it has finished before the tool call — or use closing_line instead.

Source updated: October 19, 2026