Skip to content

fix(cartesia): ignore stale frames from previous contexts on pooled websockets - #2401

Merged
chenghao-mou merged 2 commits into
mainfrom
derricks-jugging-sculled
Sep 2, 2026
Merged

fix(cartesia): ignore stale frames from previous contexts on pooled websockets#2401
chenghao-mou merged 2 commits into
mainfrom
derricks-jugging-sculled

Conversation

@rosetta-livekit-bot

@rosetta-livekit-bot rosetta-livekit-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Ports livekit/agents#7081.

A reused Cartesia WebSocket can retain unread audio and completion messages from an interrupted synthesis context. Filter messages by the active request context before processing them so stale audio is not emitted and stale completion cannot truncate the current synthesis.

Adds the source-equivalent local WebSocket regression test and a patch changeset for @livekit/agents-plugin-cartesia.

Source diff coverage

Source diff coverage

  • Adapted: livekit-plugins/livekit-plugins-cartesia/livekit/plugins/cartesia/tts.py -> plugins/cartesia/src/tts.ts. The Python context_id guard is applied before all TypeScript message handling, using the active requestId; target Cartesia message schemas require context_id, so the source optional-presence check reduces to direct mismatch filtering.
  • Adapted: tests/test_plugin_cartesia_tts.py -> plugins/cartesia/src/tts.test.ts. The source fake pooled socket scenario is expressed with the target existing local WebSocket server harness: stale audio and done are sent before current-context audio and done, and only current audio is asserted.
  • Not applicable: none. Every source diff file has a target counterpart and is covered.

Verification

  • pnpm test plugins/cartesia (11 passed, 2 credential-gated skipped)
  • pnpm build
  • pnpm exec prettier --check "plugins/cartesia/src/tts.ts" "plugins/cartesia/src/tts.test.ts" ".changeset/fresh-cartesia-contexts.md"
  • pnpm exec eslint -f unix "plugins/cartesia/src/tts.ts" "plugins/cartesia/src/tts.test.ts"
  • pnpm lint attempted; blocked by an unchanged Prettier error in plugins/baseten/src/stt.test.ts
  • pnpm --filter @livekit/agents-plugin-cartesia lint attempted; blocked by an unchanged Prettier error in plugins/cartesia/src/models.ts

A provider-path cue-cli run was not possible because CARTESIA_API_KEY is not configured in the environment. The deterministic local WebSocket test exercises the affected runtime receive path without provider credentials.


Ported from livekit/agents#7081

Original PR description

When the ConnectionPool returns a previously-used websocket, the socket buffer may still contain unread audio frames / done from the abandoned context (occurring when a SynthesizeStream was interrupted before the frames were fully consumed). The _recv_task did not validate the context_id on received messages, so stale audio was pushed into the new output and a stale "done" could prematurely truncate the new synthesis.

Changes

  • tts.py (_recv_task): skip any message whose context_id is present but does not match the current cartesia_context_id. Messages without a context_id (e.g. server errors) are not affected.
  • test_plugin_cartesia_tts.py: new test that simulates a reused socket where stale audio + done arrive before the legitimate frames, and asserts they are silently dropped.

Reproduction

Without the fix, sending a stale-context audio frame + done then current-context audio + done:

frames = [stale b"""*160, current b"\x01"*160]   # stale audio played

With the fix:

frames = [current b"\x01"*160]                     # stale frame silently dropped

Related

Root cause analysis: In the production session, 27 consecutive say() calls had ttfb≈0.002s (impossible over a fresh connection) and duration≈0.01s, confirming the socket was replaying stale frames instead of performing fresh synthesis. The "..." SPEAK text that triggered the visible symptom was just the most obvious case — any text sent through a pooled socket after an interrupted stream would exhibit the same corruption.

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from a team as a code owner September 1, 2026 12:07
@changeset-bot

changeset-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6a8ab5e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 39 packages
Name Type
@livekit/agents-plugin-cartesia Patch
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-anthropic Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-azure Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-did Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-krisp Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-protoface Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-soniox Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugins-test Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@chenghao-mou
chenghao-mou merged commit 453f82a into main Sep 2, 2026
6 checks passed
@chenghao-mou
chenghao-mou deleted the derricks-jugging-sculled branch September 2, 2026 17:41
@github-actions github-actions Bot mentioned this pull request Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant