fix(bridge): send_to_core als create_task — RVS-recv blockt nicht mehr

Live-Diagnose nach dem Timeout-Bump: Bridge-Brain-Call rennt jetzt zwar
20 Min — aber nach ~4 Min droppt der RVS-Server die WebSocket-Verbindung.
Symptom in App+Diagnostic: "denkt einfach abgebrochen".

Ursache: `async for raw_message in ws: await _handle_rvs_message(...)` —
das await blockt den recv-Loop solange send_to_core laeuft (bis zu 20
Min). Der mobil.hacker-net.de:444 RVS-Server droppt Verbindungen ohne
echte App-Frames nach ~4 Min als idle-Timeout. Die websockets-Lib
beantwortet Pings im Hintergrund, aber das reicht offenbar nicht — der
Server zaehlt nur Application-Frames.

Fix: chat-Handler ruft send_to_core als asyncio.create_task statt await.
Brain laeuft im Hintergrund-Task, RVS-recv-Loop bleibt frei, neue
Messages werden weiter verarbeitet, Verbindung bleibt lebendig. Gleicher
Fix in _flush_pending_files_with_text und file-empty-Edge-Case.

Tradeoff: parallele Brain-Calls wenn der User waehrend einer laufenden
Antwort schnell mehrere Nachrichten schickt. Brain (FastAPI) verarbeitet
beide, conversation.jsonl koennte racen. App macht aber bereits Barge-In
via cancel_request bei Folge-Nachrichten — in der Praxis treffen sich
parallele Calls selten. Wenn doch Probleme: Bridge-Side asyncio.Lock um
send_to_core in einer Folge-Etappe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 08:50:46 +02:00
parent 71fc90fcb8
commit 15facf48eb
+15 -5
View File
@@ -1316,7 +1316,9 @@ class ARIABridge:
self._pending_files_flush_task = None
text = self._build_pending_files_message(user_text)
self._pending_files = []
await self.send_to_core(text, source="app-file+chat")
# create_task statt await — sonst blockt der RVS-recv-Loop bis Brain
# fertig ist (siehe chat-handler oben).
asyncio.create_task(self.send_to_core(text, source="app-file+chat"))
return True
async def send_to_core(self, text: str, source: str = "bridge", client_msg_id: Optional[str] = None) -> None:
@@ -1641,9 +1643,16 @@ class ARIABridge:
" [BARGE-IN]" if interrupted else "",
" [GPS]" if location else "",
text[:80])
await self.send_to_core(core_text,
source="app" + (" [barge-in]" if interrupted else ""),
client_msg_id=client_msg_id)
# KEIN await: send_to_core kann 20 Min dauern. Wenn wir
# hier awaiten, blockt der `async for raw_message in ws`-
# Loop solange → RVS-Server droppt uns nach ~4 Min idle.
# Als Task: Brain laeuft im Hintergrund, RVS-recv bleibt
# bedienbar, Pings werden beantwortet, Verbindung lebt.
asyncio.create_task(self.send_to_core(
core_text,
source="app" + (" [barge-in]" if interrupted else ""),
client_msg_id=client_msg_id,
))
return
if msg_type == "cancel_request":
@@ -1819,7 +1828,8 @@ class ARIABridge:
if not file_b64:
text = f"Stefan hat eine Datei gesendet ({file_name}, {file_type}) aber die Daten sind leer angekommen."
await self.send_to_core(text, source="app-file")
# create_task statt await — RVS-recv darf nicht blocken
asyncio.create_task(self.send_to_core(text, source="app-file"))
return
if file_type.startswith("image/"):