Skip to content

feat(assemblyai): warn when audio stops flowing to the WebSocket#5478

Closed
gsharp-aai wants to merge 1 commit intolivekit:mainfrom
gsharp-aai:gsharp/stt-send-side-silence-log
Closed

feat(assemblyai): warn when audio stops flowing to the WebSocket#5478
gsharp-aai wants to merge 1 commit intolivekit:mainfrom
gsharp-aai:gsharp/stt-send-side-silence-log

Conversation

@gsharp-aai
Copy link
Copy Markdown
Contributor

Summary

Complementary to #5476 (recv-side silence warning).

#5476 warns when AssemblyAI sends no messages for 15s+. That's half the diagnostic picture — it can't distinguish "AssemblyAI is stalled" from "the plugin stopped receiving audio from upstream and is correctly silent." When a session appears wedged, both interpretations are on the table and the current logs can't separate them.

This PR adds the symmetric send-side warning: if no audio frames have been written to the WebSocket for 15s+ while the recv loop is also silent, emit AssemblyAI no audio frames sent for Ns session=<id>, re-emitted every 15s while the drought continues.

Together, the two absence-of-activity signals answer the question by elimination:

send-stopped warning recv-silence warning Diagnosis
silent firing AssemblyAI stalled — frames flowing, no response
firing firing Upstream stalled — plugin got no audio
silent silent healthy

Implementation

  • Adds self._last_frame_sent_at: float | None = None, set on every successful ws.send_bytes(...) in send_task.
  • In recv_task, tracks consecutive_timeouts in 5s ticks (matches the cadence feat(assemblyai): log connection lifecycle, silence, and session correlators #5476 introduces on the recv side). Every 3rd tick (15s), check time.time() - _last_frame_sent_at and warn if it exceeds 15s.
  • No separate watchdog coroutine. Overhead on the hot path is one time.time() assignment per frame.
  • Guarded on _last_frame_sent_at is not None so the warning doesn't fire during the initial connect window before any audio has been sent.

Impact

Relationship to #5476

This PR is self-contained and doesn't depend on #5476 being merged first — it introduces its own consecutive_timeouts counter in recv_task. If #5476 lands first, the counter line in this PR becomes a conflict trivially resolvable by keeping the existing one.

Test plan

  • make format lint type-check pass
  • Healthy session: no send-stopped warning emitted
  • Simulated upstream stall (close input_ch while keeping WS open): send-stopped warning fires at 15s, 30s, 45s
  • Simulated AAI stall (mock WS that accepts but never responds): recv-silence warning fires, send-stopped stays silent

When a session appears wedged, a recv-side silence warning alone can't
distinguish "AssemblyAI is stalled" from "the plugin stopped receiving
audio from upstream and is correctly silent." This adds a symmetric
send-side warning: if no audio frames have been written to the WebSocket
for 15s+ while the recv loop is also silent, emit a warning with the
elapsed idle time and session id, re-emitted every 15s while the
drought continues.

The two absence-of-activity signals together make the diagnosis
unambiguous from logs alone, without external instrumentation.
Copy link
Copy Markdown
Contributor

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

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 potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

@gsharp-aai gsharp-aai closed this Apr 17, 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