Skip to content

False interruption keeps stale started_speaking_at for next user turn #7063

Description

@peaks-agent

Bug Description

After a confirmed false interruption resumes agent speech, LiveKit Agents keeps the discarded user recognition turn alive. The next real user transcript inherits the false turn's original speech-start anchor, so ChatMessage.metrics.started_speaking_at can predate the actual utterance and be ordered before agent speech that really occurred first.

This reproduces on livekit-agents==1.7.1. The ordering guard from #6093 / #6098 does not cover it because the resulting user metrics remain internally ordered (stopped_speaking_at >= started_speaking_at); the start anchor is stale but not mathematically impossible.

Deterministic timeline

Observed production timeline, UTC:

  1. 19:20:06.481 — VAD opens a user turn; no STT is committed.
  2. 19:20:10.114 — LiveKit confirms a false interruption and resumes the paused agent speech.
  3. 19:20:18.632 — the user actually begins the later utterance.
  4. The committed user ChatMessage reports started_speaking_at = 19:20:06.481, 12.151 seconds before the real utterance.

This incorrectly places the user line before the resumed agent response in timestamp-sorted transcripts.

Deterministic code-path reproduction

On 1.7.1:

  1. Create an AgentActivity with resume_false_interruption=True, paused speech whose agent_state == "speaking", and an active AudioRecognition turn with _speech_start_time set by VAD but no committed transcript.
  2. Trigger _start_false_interruption_timer(0) and let _on_false_interruption(resumed=True) complete.
  3. Observe that agent speech starts/resumes, but AudioRecognition._clear_user_turn() is never called.
  4. Emit a later real user utterance and commit its transcript.
  5. The resulting ChatMessage.metrics.started_speaking_at is the step-1 VAD timestamp, not the later utterance's start.

A deterministic spy around step 2 shows the current resume path lacks recognition cleanup. The local patch changes the event order to:

clear_user_turn -> start_agent_speech -> audio_resume

Expected Behavior

Once a false interruption is confirmed and paused agent audio will resume, the uncommitted recognition turn should be discarded before agent speech resumes. Its logical-turn/span anchor, speech timing anchors, buffered transcript, and related turn state must not survive into the next real user utterance.

Actual Behavior

_on_false_interruption resumes the agent state/audio without clearing the active recognition turn. The next committed user message can inherit the abandoned turn's started_speaking_at.

Proposed Solution

Call the recognition turn's existing full clear/reset path before _on_start_of_agent_speech and audio resume when agent_false_interruption(resumed=True) is accepted. Resetting only _speech_start_time would leave other discarded-turn state behind.

PeakSend has a version- and checksum-pinned 1.7.1 patch implementing and build-verifying this ordering:

Those links are in a private repository, but the complete reproduction timeline and patch boundary are included above.

Package Versions

livekit-agents==1.7.1

The original incident was observed on 1.6.9 and confirmed against the 1.7.1 source.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions