Overview
Filter Incomplete Turns is an LLM-powered feature that detects when a user’s conversational turn was incomplete (they were cut off or need time to think) and suppresses the bot’s response accordingly. Instead of responding to partial input, the bot waits for the user to continue, then automatically re-engages if they remain silent. This creates more natural conversations by:- Preventing the bot from responding to incomplete thoughts
- Giving users time to finish speaking without interruption
- Automatically prompting users to continue after pauses
ClassifierUserTurnStrategies.
How It Works
When enabled, the LLM outputs a turn completion marker as the first character of every response:
The system automatically:
- Injects turn completion instructions into the LLM’s system prompt
- Detects markers in the LLM’s streaming response
- Suppresses bot speech for incomplete turns
- Starts a timeout based on the incomplete type
- Re-prompts the LLM when the timeout expires
LLMSwitcher, the startup configuration reaches every LLM the switcher manages, ensuring that whichever LLM becomes active later is already configured to output turn markers.
The public
on_user_turn_stopped
event fires only after the LLM confirms the turn is complete (●). The
detector that ends speech (e.g. smart turn) instead runs LLM inference.
Observers, transcript appenders, and UI indicators that should react to a
finalized turn stay quiet on ◐ / ○ markers. A turn marked ◐ or ○ stays
open until the user is re-prompted, after incomplete_short_timeout or
incomplete_long_timeout, rather than ending on user_turn_stop_timeout.Configuration
Enable the feature by passingFilterIncompleteUserTurnStrategies as the user_turn_strategies on LLMUserAggregatorParams when creating an LLMContextAggregatorPair:
FilterIncompleteUserTurnStrategies
FilterIncompleteUserTurnStrategies is a UserTurnStrategies specialization. It keeps your detector chain (the defaults, or any strategies you pass via start/stop) and appends an LLMTurnCompletionUserTurnStopStrategy that gates the public on_user_turn_stopped event on the LLM’s ● verdict. Once the detector stop strategies have decided the user stopped, the turn’s inference runs and the LLM gate decides from it. It works with either stop_mode.
To use it on top of the stop strategies a service recommends, such as an STT service’s own turn detection, pass UserTurnStrategiesParams(stop_merge_mode=MergeMode.EXTEND) as user_turn_strategies_params. With an eager end of turn, the speculative answer goes out once the transcript commits and the LLM marks the turn complete, in either order, and ◐ or ○ withdraws it.
UserTurnCompletionConfig | None
default:"None"
Optional configuration object for customizing turn completion behavior
(instructions, incomplete-turn timeouts, and re-prompts). If not provided,
default values are used.
list[BaseUserTurnStartStrategy] | None
default:"None"
Start strategies for detecting when the user begins speaking.
None uses the
standard start strategies.list[BaseUserTurnStopStrategy] | None
default:"None"
Detector stop strategies that decide the user stopped, which runs the turn’s
inference. The LLM gate is appended after them.
None uses AI-powered smart
turn detection.Deprecated parameters
The followingLLMUserAggregatorParams fields predate FilterIncompleteUserTurnStrategies. They still work for one release — setting either auto-translates to FilterIncompleteUserTurnStrategies and emits a DeprecationWarning — but new code should configure the feature via user_turn_strategies instead.
bool
default:"False"
deprecated
Deprecated since 1.2.0, removed in 2.0.0. Use
user_turn_strategies=FilterIncompleteUserTurnStrategies() instead. Setting
only this field turns on the markers but doesn’t re-prompt a user who goes
quiet after ◐ or ○.UserTurnCompletionConfig
default:"None"
deprecated
Deprecated since 1.2.0, removed in 2.0.0. Pass the config directly to
FilterIncompleteUserTurnStrategies(config=...) instead.UserTurnCompletionConfig
UseUserTurnCompletionConfig to customize timeouts, prompts, and instructions. Pass it to FilterIncompleteUserTurnStrategies via config:
Parameters
str
default:"●"
Marker the LLM emits when the user turn is complete. It is generated before
any speakable text, so prefer a character that is a single token in the
model’s tokenizer.
str
default:"◐"
Marker for a turn cut off mid-thought.
str
default:"○"
Marker for a user who needs more time.
float
default:"5.0"
Seconds to wait after detecting
◐ (incomplete short) before re-prompting the
LLM. Use shorter values for more responsive re-engagement.float
default:"10.0"
Seconds to wait after detecting
○ (incomplete long) before re-prompting the
LLM. Use longer values to give users more time to think.str
default:"..."
System prompt sent to the LLM when the short timeout expires. Should instruct
the LLM to generate a brief, natural prompt encouraging the user to continue.
str
default:"..."
System prompt sent to the LLM when the long timeout expires. Should instruct
the LLM to generate a friendly check-in message.
str
default:"..."
Complete turn completion instructions appended to the system prompt. Override
this to customize how the LLM determines turn completeness. If not provided,
the default instructions are rendered from the configured markers.
Markers Explained
Complete (●)
The user has provided enough information for a meaningful response:● marker tells the system to push the response normally. The marker itself is persisted to the conversation context (so the LLM stays consistent on later turns) but is not spoken or included in transcripts.
Incomplete Short (◐)
The user was cut off mid-sentence and will likely continue soon:◐ marker suppresses the bot’s response entirely. After 5 seconds (configurable), the LLM is prompted to re-engage with something like “Go ahead, I’m listening.”
Incomplete Long (○)
The user needs more time to think or explicitly asked for time:○ marker also suppresses the response, but waits 10 seconds (configurable) before prompting. This handles cases like:
- “Hold on a second”
- “Let me think about that”
- “Hmm, that’s interesting…”
Usage Examples
Basic Usage
Enable turn completion with default settings:You don’t need to modify your system prompt. Turn completion instructions are
automatically appended when
FilterIncompleteUserTurnStrategies is
configured.Custom Timeouts
Adjust timeouts for your use case:Custom Prompts
Customize what the LLM says when re-engaging:With Smart Turn Detection
Combine with smart turn detection for better end-of-turn detection: Smart turn detection is the default detector chain, soFilterIncompleteUserTurnStrategies() already uses it. To configure the analyzer explicitly, pass it as a stop strategy — it’s wrapped as an inference trigger automatically:
Transcripts
Turn completion markers are automatically stripped from assistant transcripts emitted via theon_assistant_turn_stopped event. Your transcript handlers will receive clean text without markers:
Supported LLM Services
Turn completion detection works with any LLM service that inherits fromLLMService:
- OpenAI (
OpenAILLMService) - Anthropic (
AnthropicLLMService) - Google Gemini (
GoogleLLMService) - AWS Bedrock (
AWSBedrockLLMService) - And other compatible services
LLMService, but they never read the turn markers, so the feature doesn’t work with them.
Graceful Degradation
If the LLM fails to output a turn marker:- The system logs a warning indicating markers were expected but not found
- The buffered text is pushed normally to avoid losing the response
- The conversation continues without interruption
Related
- User Turn Strategies - Configure turn detection
- Smart Turn Detection - AI-powered end-of-turn detection
- Transcriptions - Working with conversation transcripts