From 3e88eecd9c8bc2d952c8bf61e5b5a99a9caf4a4c Mon Sep 17 00:00:00 2001 From: duffyduck Date: Mon, 6 Jul 2026 00:31:48 +0200 Subject: [PATCH] fix(voice): Sprach-Nachricht landet im richtigen Projekt (Registry-Race) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: bei manuellem Stop landete die Sprachnachricht (und ARIAs Antwort) im Hauptchat statt im fokussierten Projekt — mal so, mal so, je nachdem ob der Endpoint natuerlich kam oder man den Stop-Button drueckte. Ursache: stt_stream_end popte die Focus-projectId-Registry SOFORT. Nach einem manuellen Stop folgt aber noch der finale stt_endpoint (Whisper-Final- Transcribe), der die projectId aus genau dieser Registry braucht. War sie schon weg → focused_pid="" → Voice-Router faellt auf Hauptchat zurueck. Die User-Bubble (lokal getaggt) blieb im Projekt, ARIAs Antwort kam aber mit project_id="" → nur in EINEM Kontext sichtbar. Fix: stt_stream_end raeumt die Registry nicht mehr sofort auf, sondern per verzoegertem call_later(20s) als Leak-Schutz. Der stt_endpoint-Handler popt selbst wenn er zuerst kommt. Co-Authored-By: Claude Opus 4.8 (1M context) --- bridge/aria_bridge.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/bridge/aria_bridge.py b/bridge/aria_bridge.py index db688a0..2f39744 100644 --- a/bridge/aria_bridge.py +++ b/bridge/aria_bridge.py @@ -2811,9 +2811,25 @@ class ARIABridge: return elif msg_type == "stt_stream_end": - # Session vorbei — Focus-Tracking fuer diese requestId aufraeumen. + # Session vorbei — ABER nicht sofort aufraeumen: nach einem manuellen + # Stop folgt noch der finale stt_endpoint (Whisper-Final-Transcribe), + # der die Focus-projectId aus dieser Registry braucht. Wuerden wir hier + # sofort poppen, bekaeme der Endpoint "" → die Nachricht (und ARIA's + # Antwort) landet im Hauptchat statt im fokussierten Projekt. Der + # stt_endpoint-Handler popt selbst; hier nur ein verzoegerter Cleanup + # als Leak-Schutz, falls gar kein Endpoint mehr kommt. req_id = payload.get("requestId", "") or "" - self._stt_stream_projects.pop(req_id, None) + if req_id: + try: + loop = asyncio.get_event_loop() + loop.call_later( + 20.0, + lambda rid=req_id: self._stt_stream_projects.pop(rid, None), + ) + except Exception: + # Kein laufender Loop (sollte im ws-Handler nie passieren) — + # dann lieber gar nicht aufraeumen als crashen. + pass return elif msg_type == "stt_endpoint":