> ## Documentation Index
> Fetch the complete documentation index at: https://daily-docs-pr-4815.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Filter Incomplete User Turns

> Use LLM-based detection to suppress responses when users are cut off mid-thought

## 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

## How It Works

When enabled, the LLM outputs a turn completion marker as the first character of every response:

| Marker | Meaning                                              | Bot Behavior                             |
| ------ | ---------------------------------------------------- | ---------------------------------------- |
| `✓`    | **Complete** - User finished their thought           | Respond normally                         |
| `○`    | **Incomplete Short** - User was cut off mid-sentence | Suppress response, wait 5s, then prompt  |
| `◐`    | **Incomplete Long** - User needs time to think       | Suppress response, wait 10s, then prompt |

The system automatically:

1. Injects turn completion instructions into the LLM's system prompt
2. Detects markers in the LLM's streaming response
3. Suppresses bot speech for incomplete turns
4. Starts a timeout based on the incomplete type
5. Re-prompts the LLM when the timeout expires

<Note>
  The public
  [`on_user_turn_stopped`](/api-reference/server/utilities/turn-management/turn-events#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 fires
  [`on_user_turn_inference_triggered`](/api-reference/server/utilities/turn-management/turn-events#on_user_turn_inference_triggered),
  which kicks LLM inference. Observers, transcript appenders, and UI indicators
  that should react to a finalized turn stay quiet on `○` / `◐` markers.
</Note>

## Configuration

Enable the feature by passing `FilterIncompleteUserTurnStrategies` as the `user_turn_strategies` on `LLMUserAggregatorParams` when creating an `LLMContextAggregatorPair`:

```python theme={null}
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import (
    LLMContextAggregatorPair,
    LLMUserAggregatorParams,
)
from pipecat.turns.user_turn_strategies import FilterIncompleteUserTurnStrategies

context = LLMContext(messages)
user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=FilterIncompleteUserTurnStrategies(),
    ),
)
```

### FilterIncompleteUserTurnStrategies

`FilterIncompleteUserTurnStrategies` is a [`UserTurnStrategies`](/api-reference/server/utilities/turn-management/user-turn-strategies) specialization. It keeps your detector chain (the defaults, or any strategies you pass via `start`/`stop`) for triggering LLM inference, and appends an `LLMTurnCompletionUserTurnStopStrategy` that gates the public `on_user_turn_stopped` event on the LLM's `✓` verdict. The detector stop strategies are wrapped with `deferred(...)` automatically, so they trigger inference but leave turn finalization to the LLM gate.

<ParamField path="config" type="UserTurnCompletionConfig" default="None">
  Optional configuration object for customizing turn completion behavior
  (instructions, incomplete-turn timeouts, and re-prompts). If not provided,
  default values are used.
</ParamField>

<ParamField path="start" type="List[BaseUserTurnStartStrategy]" default="[VADUser...(), TranscriptionUser...()]">
  Start strategies for detecting when the user begins speaking. Defaults to the
  standard start strategies.
</ParamField>

<ParamField path="stop" type="List[BaseUserTurnStopStrategy]" default="[TurnAnalyzerUserTurnStopStrategy(LocalSmartTurnAnalyzerV3())]">
  Detector stop strategies that trigger LLM inference. They are wrapped with
  `deferred(...)` automatically and the LLM gate is appended as the finalizer.
  Defaults to AI-powered smart turn detection.
</ParamField>

### Deprecated parameters

The following `LLMUserAggregatorParams` 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.

<ParamField path="filter_incomplete_user_turns" type="bool" default="False" deprecated>
  Enable LLM-based turn completion detection. When `True`, the system
  automatically appends turn completion instructions to the LLM's system prompt
  and configures the LLM service to process turn markers. *Deprecated in v1.2.0.
  Use `user_turn_strategies=FilterIncompleteUserTurnStrategies()` instead. Will
  be removed in v2.0.0.*
</ParamField>

<ParamField path="user_turn_completion_config" type="UserTurnCompletionConfig" default="None" deprecated>
  Optional configuration object for customizing turn completion behavior. If not
  provided, default values are used. *Deprecated in v1.2.0. Pass the config
  directly to `FilterIncompleteUserTurnStrategies(config=...)` instead. Will be
  removed in v2.0.0.*
</ParamField>

## UserTurnCompletionConfig

Use `UserTurnCompletionConfig` to customize timeouts, prompts, and instructions. Pass it to `FilterIncompleteUserTurnStrategies` via `config`:

```python theme={null}
from pipecat.turns.user_turn_completion_mixin import UserTurnCompletionConfig
from pipecat.turns.user_turn_strategies import FilterIncompleteUserTurnStrategies

user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=FilterIncompleteUserTurnStrategies(
            config=UserTurnCompletionConfig(
                incomplete_short_timeout=5.0,
                incomplete_long_timeout=10.0,
                incomplete_short_prompt="Custom prompt for short pauses...",
                incomplete_long_prompt="Custom prompt for long pauses...",
                instructions="Custom turn completion instructions...",
            ),
        ),
    ),
)
```

### Parameters

<ParamField path="incomplete_short_timeout" type="float" default="5.0">
  Seconds to wait after detecting `○` (incomplete short) before re-prompting the
  LLM. Use shorter values for more responsive re-engagement.
</ParamField>

<ParamField path="incomplete_long_timeout" type="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.
</ParamField>

<ParamField path="incomplete_short_prompt" type="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.
</ParamField>

<ParamField path="incomplete_long_prompt" type="str" default="...">
  System prompt sent to the LLM when the long timeout expires. Should instruct
  the LLM to generate a friendly check-in message.
</ParamField>

<ParamField path="instructions" type="str" default="...">
  Complete turn completion instructions appended to the system prompt. Override
  this to customize how the LLM determines turn completeness.
</ParamField>

## Markers Explained

### Complete (✓)

The user has provided enough information for a meaningful response:

```
User: "I'd go to Japan because I love the culture and food."
LLM: "✓ Japan is a wonderful choice! The blend of ancient traditions..."
```

The `✓` 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:

```
User: "I'd go to Japan because I love"
LLM: "○"
```

The `○` 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:

```
User: "That's a good question. Let me think..."
LLM: "◐"
```

The `◐` 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:

```python theme={null}
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import (
    LLMContextAggregatorPair,
    LLMUserAggregatorParams,
)
from pipecat.turns.user_turn_strategies import FilterIncompleteUserTurnStrategies

messages = [
    {
        "role": "developer",
        "content": "You are a helpful assistant...",
    }
]

context = LLMContext(messages)
user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=FilterIncompleteUserTurnStrategies(),
    ),
)
```

<Note>
  You don't need to modify your system prompt. Turn completion instructions are
  automatically appended when `FilterIncompleteUserTurnStrategies` is
  configured.
</Note>

### Custom Timeouts

Adjust timeouts for your use case:

```python theme={null}
from pipecat.turns.user_turn_completion_mixin import UserTurnCompletionConfig
from pipecat.turns.user_turn_strategies import FilterIncompleteUserTurnStrategies

user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=FilterIncompleteUserTurnStrategies(
            config=UserTurnCompletionConfig(
                incomplete_short_timeout=3.0,  # More responsive
                incomplete_long_timeout=20.0,  # More patient
            ),
        ),
    ),
)
```

### Custom Prompts

Customize what the LLM says when re-engaging:

```python theme={null}
from pipecat.turns.user_turn_completion_mixin import UserTurnCompletionConfig
from pipecat.turns.user_turn_strategies import FilterIncompleteUserTurnStrategies

user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=FilterIncompleteUserTurnStrategies(
            config=UserTurnCompletionConfig(
                incomplete_short_prompt="""The user paused briefly.
Generate a contextual prompt to encourage them to continue.
Respond with ✓ followed by your message.""",
                incomplete_long_prompt="""The user has been quiet for a while.
Generate a friendly check-in.
Respond with ✓ followed by your message.""",
            ),
        ),
    ),
)
```

<Warning>
  Custom prompts must instruct the LLM to respond with `✓` followed by the
  message. This ensures the re-engagement message is spoken normally.
</Warning>

### With Smart Turn Detection

Combine with smart turn detection for better end-of-turn detection:

Smart turn detection is the default detector chain, so `FilterIncompleteUserTurnStrategies()` already uses it. To configure the analyzer explicitly, pass it as a `stop` strategy — it's wrapped as an inference trigger automatically:

```python theme={null}
from pipecat.audio.turn.smart_turn.local_smart_turn_v3 import LocalSmartTurnAnalyzerV3
from pipecat.turns.user_stop import TurnAnalyzerUserTurnStopStrategy
from pipecat.turns.user_turn_strategies import FilterIncompleteUserTurnStrategies

user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
    context,
    user_params=LLMUserAggregatorParams(
        user_turn_strategies=FilterIncompleteUserTurnStrategies(
            stop=[
                TurnAnalyzerUserTurnStopStrategy(
                    turn_analyzer=LocalSmartTurnAnalyzerV3()
                )
            ],
        ),
    ),
)
```

<Tip>
  Smart turn detection helps determine when the user stops speaking, while turn
  completion filtering determines whether to respond. They work well together
  for natural conversations.
</Tip>

## Transcripts

Turn completion markers are automatically stripped from assistant transcripts emitted via the `on_assistant_turn_stopped` event. Your transcript handlers will receive clean text without markers:

```python theme={null}
@assistant_aggregator.event_handler("on_assistant_turn_stopped")
async def on_assistant_turn_stopped(aggregator, message: AssistantTurnStoppedMessage):
    # message.content will be "Japan is a wonderful choice!"
    # NOT "✓ Japan is a wonderful choice!"
    # Markers are automatically stripped from transcripts
    if message.content:
        print(f"Assistant: {message.content}")
    if message.interrupted:
        print("(Turn was interrupted)")
```

## Supported LLM Services

Turn completion detection works with any LLM service that inherits from `LLMService`:

* OpenAI (`OpenAILLMService`)
* Anthropic (`AnthropicLLMService`)
* Google Gemini (`GoogleLLMService`)
* AWS Bedrock (`AWSLLMService`)
* And other compatible services

## Graceful Degradation

If the LLM fails to output a turn marker:

1. The system logs a warning indicating markers were expected but not found
2. The buffered text is pushed normally to avoid losing the response
3. The conversation continues without interruption

This ensures the feature doesn't break conversations if the LLM occasionally disobeys instructions.

## Related

* [User Turn Strategies](/api-reference/server/utilities/turn-management/user-turn-strategies) - Configure turn detection
* [Smart Turn Detection](/api-reference/server/utilities/turn-detection/smart-turn-overview) - AI-powered end-of-turn detection
* [Transcriptions](/api-reference/server/utilities/turn-management/transcriptions) - Working with conversation transcripts
