UserBotLatencyObserver measures the time between when a user stops speaking and when the bot starts responding, emitting events for custom handling and optional OpenTelemetry tracing integration. It also tracks first-bot-speech latency and provides detailed latency breakdowns when metrics are enabled, including per-service metrics and contributions that name every part of the interval.
Features
- Tracks user speech start/stop timing using VAD frames
- Measures bot response latency from the actual moment the user started speaking
- Measures first bot speech latency (client connection to first speech)
- Provides detailed latency breakdown with per-service TTFB, text aggregation, user turn duration, and function call metrics
- Provides contributions timeline that names every part of the user-to-bot interval, including time no service measures
- Emits
on_latency_measuredevents for custom processing - Emits
on_latency_breakdownevents with detailed per-service metrics - Emits
on_first_bot_speech_latencyevent for greeting latency measurement - Automatically records latency as OpenTelemetry span attributes when tracing is enabled
- Automatically resets between conversation turns
Usage
Basic Latency Monitoring
Add latency monitoring to your pipeline and handle the event:Detailed Latency Breakdown
Enable metrics to collect per-service latency breakdown:OpenTelemetry Integration
When tracing is enabled, latency measurements are automatically recorded asturn.user_bot_latency_seconds attributes on OpenTelemetry turn spans. No additional configuration is needed.
How It Works
The observer tracks conversation flow through these key events:- Client connects (
ClientConnectedFrame) → Records timestamp for first-bot-speech measurement - User starts speaking (
VADUserStartedSpeakingFrame) → Resets latency tracking - User stops speaking (
VADUserStoppedSpeakingFrame) → Records timestamp, accounting for VADstop_secsdelay - Bot starts speaking (
BotStartedSpeakingFrame) → Calculates latency and emitson_latency_measuredandon_latency_breakdownevents
enable_metrics=True in PipelineParams, the observer also collects per-service metrics (TTFB, text aggregation, function call latency) from MetricsFrame instances and builds a contributions timeline that names every part of the user-to-bot interval, including the parts no service measures (VAD silence, turn detection, turn-completion markers).
Event Handlers
on_latency_measured
Called each time a user-to-bot latency measurement is captured.on_latency_breakdown
Called alongsideon_latency_measured with detailed per-service metrics collected during the user→bot cycle. The breakdown includes TTFB from each service, text aggregation latency, user turn duration, and function call timings.
LatencyContribution fields:
Each contribution names one part of the user-to-bot interval:
Methods:
turn_contribution_lines(by_cost=False)— Format contributions for logging, one per line plus a total. Passby_cost=Trueto order by duration rather than chronologically.chronological_events()— Deprecated since 1.9.0. Useturn_contribution_lines()instead, which names every part of the interval. Will be removed in 2.0.0.
on_first_bot_speech_latency
Called once when the bot first speaks after client connection. Measures the time fromClientConnectedFrame to the first BotStartedSpeakingFrame. This is particularly useful for measuring greeting latency.
The
on_latency_breakdown event is also emitted for the first bot speech,
allowing you to see the detailed breakdown of what contributed to the greeting
latency.Configuration
Constructor Parameters
int
default:"100"
Maximum number of frame IDs to keep in history for duplicate detection.
Prevents unbounded memory growth in long conversations.
float
default:"0.005"
Contributions shorter than this are rolled into the single pipeline entry
rather than listed separately. Pass
0 to list every contribution, including
individual frame hops.Callable[[], float]
default:"time.time"
Reads the current time in seconds. Supplying one lets a test drive a cycle
without waiting out the intervals it describes.
Limitations
- Requires proper frame sequencing to work accurately
- Per-service metrics are only collected when
enable_metrics=TrueinPipelineParams