Stop AI Agent Tool Calls on an Unfinished Turn - Zian AI

Stop AI Agent Tool Calls on an Unfinished Turn

Quick answer

Gate the tool, not the audio. Deepgram Voice Agent holds agent audio until the turn is confirmed but dispatches function calls immediately: its per-function defer_until_eot field defaults to false. Of 6 platforms checked it is the only per-tool gate conditioned on turn state; LiveKit Agents ships preemptive generation on by default. Put every tool on a read list or a commit list, then gate the commit list.

One layer only: what the tool layer does while a turn is still open. Endpointing sits upstream and is ceded – which engine decides a turn, and with what tunable range, is compared across Deepgram Flux, ElevenLabs Scribe and Speechmatics in our comparison of STT endpointing surfaces, and the framework silence timers above the engine are in why your AI voice agent interrupts callers. Assume your endpointing is as good as it will get, and that callers still sometimes carry on after the agent thought they had stopped.

Why did my AI voice agent book the appointment while the caller was still talking?

Because two things happen at different moments and only one of them waits. Deepgram’s documentation names both: the agent starts thinking when speech-to-text is moderately confident the caller has stopped, and is cleared to reply when it is confident. The gap between them is the speculative window, and working inside it is where the latency saving comes from. If the caller turns out not to have finished, the turn resumes and the speculative reply is discarded.

Audio is safe in that window. Deepgram’s three-row table of what waits for turn confirmation gives agent audio Yes and the user’s ConversationText Yes. The third row is the problem: function calls get No, by default, because a tool call is dispatched as soon as the LLM emits it.

So end_call hangs up the line, book_appointment writes the row and send_sms sends the message – on a turn the caller then continued. Deepgram’s own worked example is end_call: the caller says that is all they need, the agent starts thinking, end_call fires, the caller says actually, put me through to a person, and the turn resumes. Deepgram’s verdict on what cancellation achieves at that point is one sentence: cancellation is bookkeeping, and the telephony call is already hung up.

This is not the fault where the agent goes quiet while a tool runs – that is a latency chain, diagnosed in why your AI voice agent goes silent on tool calls. Here the tool ran too early, not too slowly.

Does a tool dispatch before the turn is confirmed? Six platforms, read 20 September 2026

Deepgram publishes three rows for its own stack. The table below extends the question across six platforms. Every cell was read from the named vendor’s own documentation on 20 September 2026; where a vendor publishes no answer, the cell says so rather than guessing.

Platform Does a tool dispatch before the turn is confirmed? Per-tool gate Default What you get when it is cancelled
Deepgram Voice Agent Yes. Deepgram’s own table answers No, by default to whether function calls are gated on confirmation Yes – defer_until_eot on any function in agent.think.functions false FunctionCallCancelled listing the cancelled ids – but only for calls the client already received. A server-side function that reached your endpoint already ran
LiveKit Agents (Python 1.8.2, Node 1.9.0) Preemptive generation starts LLM generation before the turn is confirmed and is on by default; the docs state only that TTS waits. What happens to a tool call emitted in that window is not documented No turn-confirmation gate. Tool flags are NONE, IGNORE_ON_ENTER, CANCELLABLE; the documented remedy for writes is disallow_interruptions(), which protects a tool already running preemptive_generation.enabled True; preemptive_tts False; max_speech_duration 10.0 s Not documented. livekit/agents-js issue 2374, open since 29 August 2026, reports no output record, no span error attribute and no log line
Pipecat (pipecat-ai 1.11.0) Only with the eager window on, and Pipecat does not document the function-call case either way. Pipecat documents that the response is held and the context written from the committed transcript; its eager-turn documentation never mentions function calls No turn-confirmation gate. Per-tool options are cancel_on_interruption, timeout_secs and cancellable_by_llm enable_eager_end_of_turn False; cancel_on_interruption True; cancellable_by_llm False FunctionCallCancelFrame. Issue 5823, open 17 September 2026, reports a result arriving while the user is still speaking is silently dropped with no retry; issue 5779, open 15 September 2026, reports a call stuck in progress
Vapi Not published as a turn-state question. No speculative window is documented: Vapi exposes Deepgram Flux’s committed end-of-turn threshold but no eager-window parameter Yes, but on a different axis – rejectionPlan blocks a tool on regex or Liquid conditions over recent messages conditions: [], and Vapi states that when conditions are empty or omitted the tool always executes Not published
Retell AI Retell answers the barge-in half directly, and the answer is no protection: an interrupted custom function request is not cancelled and runs to completion, so any action it takes still happens No turn-confirmation gate. Per-function timing options are Talk While Waiting and Talk After Action Completed Talk While Waiting off; Talk After Action Completed on; endpoint timeout 120000 ms, range 1000 to 600000 Nothing. Retell’s own guidance is to make side-effecting actions idempotent so a repeat call is safe
ElevenLabs Agents Yes, if you switch it on. ElevenLabs publishes speculative_turn, which starts generating the LLM response before full turn confidence is reached; it defaults to false, so the window is off until you ask for it. What happens to a tool call emitted in that window is not documented Yes, but on a different axis – interruption_mode per tool: allow, disable_during_tool, disable_during_tool_and_turn allow; speculative_turn false Not published

Two readings matter more than the individual cells. First, of the six, Deepgram’s defer_until_eot is the only per-tool gate conditioned on turn state. Vapi’s rejectionPlan is genuinely evaluated before the tool executes, but on what the recent messages say rather than on whether the turn is confirmed – a regex that matches a goodbye will match it mid-sentence too. LiveKit’s disallow_interruptions(), ElevenLabs’ interruption_mode and Pipecat’s cancel_on_interruption all act after dispatch: they protect or cancel a call that is already running, and none of them delays the moment the request leaves. Second, the two vendors that document the cancellation case – Deepgram and Retell AI – reach the same conclusion from opposite directions: the request reached your endpoint, so your endpoint ran.

The read list and commit list rule

Call it the read list / commit list rule.

Every tool the agent can call goes on exactly one of two lists. Read-list tools may dispatch inside the speculative window. Commit-list tools must not dispatch until the turn is confirmed.

The test is one question, stricter than it sounds: if this call runs and the caller then keeps talking, can the agent itself undo it, unprompted, with a tool it already has, leaving nothing the caller will notice? If yes it is a read-list tool; if no it is a commit-list tool. Three things fail that test in ways teams routinely miss:

  • Your API supporting deletion is not the test. The agent must hold the delete tool, be allowed to call it unprompted, and the deletion must leave no trace the caller sees. A cancellation email already in their inbox is a trace.
  • Control-flow tools are commit tools. end_call and transfer-to-number feel like routing rather than writing, which is why they get left off the list. They are the least reversible actions an agent has.
  • A read that reserves is a write. A check_availability call that places a hold on the slot is a commit-list tool wearing a read-list name. Check what the integration does, not what it is called – the subject of whether an AI agent can actually book into your calendar.

The second half keeps the agent fast. Deepgram notes that dispatching most functions early is where the latency advantage comes from, and that deferring one function does not delay the others. Gating your read list buys nothing and costs milliseconds on every lookup.

The five steps, starting on day one

Half a day on a stack you already run, with no new dependency.

  1. Day one, first hour: write the two lists. Open your tool definitions and put every tool on exactly one list, built-ins included – Vapi’s End Call and Transfer Call, Retell’s End Call and Send SMS, ElevenLabs’ end_call system tool, LiveKit’s prebuilt EndCallTool. Step one is finished when you have a file with two lists, no tool on both and none missing.
  2. Find out whether your platform has a speculative window, and whether it is on. On Deepgram Voice Agent it is always on and function calls are not gated. On LiveKit Agents preemptive_generation.enabled defaults to True with max_speech_duration at 10.0 seconds, so it is attempted on nearly every caller turn of a booking call. On Pipecat the eager path is opt-in: enable_eager_end_of_turn on DeepgramFluxSTTService defaults to False. On ElevenLabs Agents it is conversation_config.turn.speculative_turn, which defaults to false, so the window is off until you turn it on. On Vapi and Retell AI it is not published – treat it as unknown and measure.
  3. Gate the commit list with the platform’s own field, if it has one. On Deepgram that is one line per function: "defer_until_eot": true inside agent.think.functions. Read the ordering caveat in Deepgram’s reference first – a function that did not opt in still dispatches immediately even with a deferred call queued ahead of it, so calls within a turn can complete out of order. If your commit tool depends on a read tool’s result, that ordering is yours to enforce.
  4. Where there is no field, move the commit behind a confirmation the turn cannot outrun. Make the in-window tool a proposal: it validates, reserves nothing and returns the arguments it would have used. Your server commits only once your application has seen a confirmed end-of-turn for that turn. Where the platform offers a content gate, use it as a second layer – Vapi’s rejectionPlan documentation carries this pattern as its first example, rejecting endCall unless the caller’s most recent message matches a goodbye. Do not mistake disallow_interruptions() or interruption_mode for this step: they protect a call already in flight.
  5. Make every commit-list endpoint idempotent, then test the resume. Retell AI’s own FAQ says why: the request is not cancelled, so the action still happens, and Deepgram says the same for the server-side case. Then run the one test that reproduces it – a scripted call where the caller pauses about two seconds mid-sentence and then continues, timed to land where the agent would commit. Build it into the pre-launch pass in how to test an AI voice agent before go-live; unscripted test calls do not reproduce it reliably.

You are finished when, for every commit-list tool, you can name the mechanism holding it, produce one log line showing it dispatched after turn confirmation, and the scripted resume test leaves one record in the booking system rather than two or zero.

One caveat on that log line: livekit/agents-js issue 2374, open since 29 August 2026, reports that a cancelled function tool leaves no output record, no span error or output attribute and no log entry. An empty log is not evidence that nothing ran. Query the booking system for records created in the window instead.

Work out your own exposure before you change anything

Four numbers give the size of the problem. None of the rates below is a measurement of ours; they come from your own logs.

  • Resumed turns per 100 caller turns. On Deepgram, turns where UserStartedSpeaking arrives after the agent began thinking; on Pipecat, EagerEndOfTurnCancelFrame events; on LiveKit, discarded preemptive attempts, capped at max_retries 3 per turn.
  • Caller turns per call, from your transcripts, and calls per day.
  • The share of resumed turns where a commit-list call had already been emitted. Almost nobody has this one, which is why the arithmetic is worth doing before the fix.

Worked through with illustrative inputs, so you can substitute yours: 400 calls a day at 8 caller turns each is 3,200 caller turns. At 6 resumed turns per 100, that is 192 resumed turns a day. If 1 in 25 of those had already emitted a commit-list call, roughly 8 irreversible actions a day fired on a turn the caller then continued – 54 a week on the unrounded 7.68. Then price one: a double booking costs a slot, a call and a rebooking, and an end_call at the wrong moment costs the enquiry outright.

Below about one a week, gate the commit list anyway – on Deepgram it is a one-line change – and leave the rest alone. Above roughly ten a week, step four is worth building properly.

What gating the commit list costs to run

The method is complete and a competent engineer can run it in a day. What it costs to keep running is the honest part.

Your situation Do it yourself Hand it over
One platform, one agent, read-only tools only Yes – the two lists take an hour and nothing needs gating Not worth it
LiveKit Agents or Pipecat with bookings, payments or transfers Workable, but you are building step four yourself and maintaining it Reasonable
Two or more platforms, or a platform change mid-quarter Costly – every default in the table above is per platform and moves without notice Reasonable
Outbound booking at volume across several countries and languages Ongoing – resumed-turn rates differ by language and pause habit, so the arithmetic is per route Reasonable
Audio and caller data cannot leave your infrastructure Only if you can self-host every layer Only with private model deployment on your own infrastructure

The arithmetic is yours. A single-platform agent with a short commit list is a day of work and then it is done. At the volume Zian AI reports – 50,769+ qualified sales appointments set – the commit list has to be re-checked against each vendor’s defaults every time a platform ships, which is the real cost the table measures. Zian AI runs booking agents of exactly this shape – the Outbound Appointment Setter and the Appointment Show-Specialist – and supports private model deployment on customer infrastructure where audio cannot leave. Zian publishes no turn-gating field of its own, so put step one and step five to us the same way you would put them to any vendor on your shortlist. If you would rather own it, the five steps are the whole method; our comparison of AI appointment setting software covers what to look for in a platform that already does it.

Where every figure on this page comes from

Figure Who published it Link (their own page) Date read
defer_until_eot exists, and the default is false Deepgram developers.deepgram.com changelog, 8 September 2026 20 September 2026
Function calls are not gated on turn confirmation (No, by default); and a server-side function that reached your endpoint already ran, so defer rather than rely on cancellation Deepgram Speculative Replies and Turn Confirmation 20 September 2026
Out-of-order completion when one function defers and another does not Deepgram Configure the Voice Agent 20 September 2026
FunctionCallCancelled covers only calls the client already received Deepgram Function Call Cancelled 20 September 2026
preemptive_generation.enabled True, preemptive_tts False, max_speech_duration 10.0 s, max_retries 3 LiveKit TurnHandlingOptions reference 20 September 2026
Only the LLM runs preemptively; TTS waits for turn confirmation LiveKit Preemptive speech generation 20 September 2026
Tool flags NONE, IGNORE_ON_ENTER, CANCELLABLE; disallow_interruptions() for mutating calls LiveKit Function tools 20 September 2026
enable_eager_end_of_turn defaults to False Pipecat Deepgram Speech-to-Text service 20 September 2026
Nothing the speculation produces reaches the user or the context; the response is held until confirmation Pipecat User turn strategies 20 September 2026
cancel_on_interruption True, cancellable_by_llm False Pipecat Function Calling 20 September 2026
With empty or omitted conditions the tool always executes; the first example rejects endCall unless the caller says goodbye Vapi Tool rejection plan 20 September 2026
An interrupted custom function request is not cancelled and runs to completion; make such actions idempotent Retell AI Integrate any system with custom function 20 September 2026
interruption_mode per tool, default allow; disable_interruptions deprecated ElevenLabs Tool interruptions 20 September 2026
conversation_config.turn.speculative_turn starts LLM generation before full turn confidence is reached, and defaults to false ElevenLabs Create agent API reference 20 September 2026
Issue 5823, open, opened 17 September 2026 – a result arriving while the user is still speaking is dropped, no retry pipecat-ai on GitHub pipecat-ai/pipecat issue 5823 20 September 2026
Issue 5779, open, opened 15 September 2026 – an interrupted tool call stuck in progress pipecat-ai on GitHub pipecat-ai/pipecat issue 5779 20 September 2026
Issue 2374, open, opened 29 August 2026 – a cancelled tool leaves no output, no span attribute and no log livekit on GitHub livekit/agents-js issue 2374 20 September 2026
Current releases: pipecat-ai 1.11.0 (18 September 2026), livekit-agents 1.8.2 (15 September 2026), @livekit/agents 1.9.0 (15 September 2026) PyPI and npm pypi.org/project/pipecat-ai, pypi.org/project/livekit-agents, registry.npmjs.org @livekit/agents 20 September 2026

Frequently asked questions

Does my AI agent book the appointment if the caller keeps talking?

On most stacks, yes. Deepgram states in its own documentation that function calls are not gated on turn confirmation by default, so a booking call dispatches as soon as the model emits it. Setting defer_until_eot to true on that one function holds it until the turn is confirmed and discards it if the caller resumes, per the Deepgram changelog entry of 8 September 2026.

What causes AI voice agent double booking?

Two causes needing two fixes. The first is a retracted turn: the agent emits book_appointment, the caller carries on and amends the slot, and a second booking follows the first. The second is a tool call interrupted rather than stopped. Retell AI documents that an interrupted custom function request is not cancelled and runs to completion, which is why its own guidance is to make such actions idempotent.

Can I stop a tool call after it has already fired?

Not reliably, and the clearest statement of why comes from the vendor that built the gate. Deepgram notes that a server-side function which already reached your endpoint is a different matter, because Deepgram discards the response but your endpoint ran; see Speculative Replies and Turn Confirmation. Cancellation is an accounting entry, not a rollback.

Do LiveKit Agents or Pipecat have a defer-until-end-of-turn setting?

Neither documents one as at 20 September 2026. LiveKit offers disallow_interruptions, which protects a tool already running, and Pipecat offers cancel_on_interruption, which cancels one. Both act after dispatch, not before it. Open issues on both trackers describe the gap: pipecat 5823 and 5779, and livekit agents-js 2374.

Should read-only tools wait for turn confirmation too?

No, and holding them is the main cost of getting the split wrong. Deepgram notes that dispatching most functions early is where the latency advantage comes from, and that deferring one function does not delay the others. A lookup that only reads can run inside the speculative window and be thrown away for nothing.

A tool call is the only part of a voice agent that touches the real world, and it is the one part most platforms do not hold back. If you would rather have the commit list gated, tested and re-checked against each vendor’s defaults than own that yourself, Zian AI is in partnership-application beta. Apply For Partnership.

Related Blogs

Related from Zian AI