Skip to content

fix(inworld-tts): don't poison receive stream with stale-context errors#539

Merged
Nash0x7E2 merged 1 commit into
mainfrom
fix/inworld-tts-keepalive-context
May 8, 2026
Merged

fix(inworld-tts): don't poison receive stream with stale-context errors#539
Nash0x7E2 merged 1 commit into
mainfrom
fix/inworld-tts-keepalive-context

Conversation

@aliev
Copy link
Copy Markdown
Member

@aliev aliev commented May 8, 2026

Why

TTS calls fail with RuntimeError: Inworld TTS websocket error: Context not found during sendText after >60 seconds of inactivity. The LLM still generates a response, but the agent can never speak it. Reproduces reliably with any agent that goes quiet between turns — for example a face-aware agent that re-engages a distracted user with a proactive cue after a pause.

Changes

  1. _keepalive_loop sends send_text without a contextId. When _active_context_id is None, the keepalive payload still contains {"send_text": {"text": ""}} with no contextId. The server cannot route this to a context and responds with an error message. The error then sits in the WebSocket receive buffer and surfaces on the next valid TTS call, breaking it. Fix: skip the keepalive iteration when no active context exists. The websockets library handles TCP-level keepalive via PING/PONG independently.

  2. _receive_audio did not filter errors by contextId. Audio chunks were filtered by msg_context_id != context_id, but the error/status check ran first and raised regardless of which context the message was for. Fix: pull the contextId mismatch check above the status/error checks so messages addressed to a different (or stale) context are dropped early. Server-wide errors with no contextId (e.g. "max contexts limit reached") still pass through.

Two related issues caused TTS calls to fail with `Context  not found
during sendText` after >60 seconds of inactivity, leaving the agent
unable to speak its proactive responses.

1. **`_keepalive_loop` sends `send_text` without a `contextId`.**
   When `_active_context_id` is `None`, the keepalive payload still
   contains `{"send_text": {"text": ""}}` with no `contextId`. The
   server cannot route this to a context and responds with an error
   message. The error then sits in the WebSocket receive buffer and
   surfaces on the next valid TTS call, breaking it. Fix: skip the
   keepalive iteration when no active context exists. The websockets
   library handles TCP-level keepalive via PING/PONG independently.

2. **`_receive_audio` did not filter errors by `contextId`.** Audio
   chunks were filtered by `msg_context_id != context_id`, but the
   error/status check ran first and raised regardless of which context
   the message was for. Fix: pull the `contextId` mismatch check above
   the status/error checks so messages addressed to a different (or
   stale) context are dropped early. Server-wide errors with no
   `contextId` (e.g. "max contexts limit reached") still pass through.
@aliev aliev marked this pull request as ready for review May 8, 2026 15:30
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: edd5bfd7-141b-410b-a22e-c0fcaa9cbe8d

📥 Commits

Reviewing files that changed from the base of the PR and between 57d0923 and 9966357.

📒 Files selected for processing (1)
  • plugins/inworld/vision_agents/plugins/inworld/tts.py

📝 Walkthrough

Walkthrough

The TTS streaming client refactors message handling for concurrent contexts. The receive loop now extracts contextId from incoming messages, filters out stale messages targeting inactive contexts, and allows server-wide messages without contextId to proceed. Status code handling is moved into a local variable. The keepalive loop was updated to include the active contextId in its payload once known, preventing server errors that corrupt subsequent receive streams.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Nash0x7E2 Nash0x7E2 merged commit c24ea70 into main May 8, 2026
6 checks passed
@Nash0x7E2 Nash0x7E2 deleted the fix/inworld-tts-keepalive-context branch May 8, 2026 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants