Engineering note / Pipecat / 21 October 2026
The tool returned.
The agent stayed silent.
A successful tool call isn't the end of a voice-agent test. We replayed a reported Pipecat failure where the result arrives, but the next answer never starts within our observation window. Then we checked the proposed fix.
checks passed; 18 produced no answer
checks passed; controls still worked
Eight selected sequences, three fresh-process repeats per revision. These are consistency checks, not independent samples or a production failure-rate estimate. No real model or telephone call was used.
The original report is Shehroze Talat's issue #6201. The correction is Cross2pro's PR #6232, open when checked on 21 October. We didn't discover the original bug or write that patch. Our contribution is the independent replay, nearby cases and recorded output.
The narrow timing window
The setup combines FilterIncompleteUserTurnStrategies with FunctionCallUserMuteStrategy. Inference starts while the logical user turn is still open. The user starts speaking again before the model commits to its tool call.
- Start inference after the first speech segment ends.
- Resume speech while that inference is still running.
- Start the tool, then send the speech-stop event while input is muted.
- Return the tool result. Watch for actual answer text, not just a completed tool.
On the original revision, the muted stop event leaves speaking state stuck. The result reaches the conversation context, but the next inference is held. The watchdog doesn't rescue this sequence.
The patch keeps voice-activity state synchronized during mute and releases the held context when the user turn closes. Both parts matter: our no-mute and stop-after-result cases closed the turn on the original code, yet still produced no answer.
What the replay actually recorded
We used the real pipeline, aggregators, turn controller and function dispatch. Only speech events, model decisions and availability data were scripted. A pass requires the expected pre-TTS text, exactly one tool call, exactly two inference requests and a closed turn before teardown.
Reported sequence, repeat 1: failed original and passing patch
Elapsed seconds from each probe's start. This view is generated from the saved result JSON, not a reconstructed transcript.
Original · no answer
Loading recorded events…
Proposed patch · answer emitted
Loading recorded events…
Recovery isn't necessarily immediate. In the reported sequence, the patched pipeline waits for the watchdog. This check doesn't show that interrupted words are recovered or that stale inference is cancelled.
| Sequence | Original | Patch |
|---|---|---|
| Reported resume-before-tool timing | 0 / 3 | 3 / 3 |
| No resumed speech | 3 / 3 | 3 / 3 |
| Speech stops before tool commitment | 3 / 3 | 3 / 3 |
| Speech stops after the tool result | 0 / 3 | 3 / 3 |
| Function-call mute disabled | 0 / 3 | 3 / 3 |
| Tool slower than the watchdog | 0 / 3 | 3 / 3 |
| Handled application-error result | 0 / 3 | 3 / 3 |
| Two resumed speech bursts | 0 / 3 | 3 / 3 |
Five-second observation per trial. No framework ErrorFrames, process failures or invalid event orders in the final run. No pending asyncio tasks after cleanup. A handled tool error is a test input, not a failed test command.
The controls caught our mistake too
Our first recorder sat after an aggregator that consumes text. It called even the ordinary control silent. We discarded those classifications, moved the recorder before the assistant aggregator and repeated the full matrix. A final run explicitly initialized the scripted service's unsupported settings to remove a startup diagnostic. The cases stayed unchanged.
Four upstream test files also passed: 191 tests on the base and 194 on the patch. Those suites support the check; they don't turn it into a live-call test.
Run it, then test your own call flow
The package includes the frozen cases, probe, all 48 final traces, source hashes, environment and reproduction commands. It pins the base revision and the proposed patch. No customer data is included.
Read the reproduction instructions on GitHub ↗
We haven't tested STT, TTS, SIP, provider latency, disconnects or customer deployments. Speech is synthetic, and the answer is scripted. Don't treat this as evidence about model reasoning or every Pipecat configuration.
A useful handover has a test attached.
That's the work FAULTLINE offers: take one difficult agent failure, reproduce it if possible, check the correction and leave a test your engineers can rerun. For a voice agency, the starting point is one agreed call flow before a client handover.