From 5133f0bc2d8d2d2ff915b9704c4d33e28b160bc4 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Fri, 15 May 2026 11:43:04 +0200 Subject: [PATCH] =?UTF-8?q?fix(chat):=20User-Bubble=20=E2=8F=B3=E2=86=92fa?= =?UTF-8?q?iled=20bei=20langsamen=20ARIA-Antworten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symptom: ARIA bearbeitet die Nachricht (im Gedanken-Stream sichtbar), aber unter der User-Bubble bleibt die Sanduhr stehen und nach ~90 s springt sie auf ⚠ failed. ARIA-Antwort kommt trotzdem irgendwann durch — die Bubble war also nie weg, nur visuell schief. Wurzel: chat_ack vom Bridge kam offenbar in manchen Faellen nicht verlaesslich an. ACK-Timer (30 s × 3 Retries) lief durch → 'failed'. Fix: agent_activity = thinking/tool/assistant ist impliziter Beweis, dass das Brain die Nachricht bekommen und angefangen hat zu arbeiten. Beim ersten non-idle Event: - alle laufenden ACK-Timer cancelen - alle 'sending'-User-Bubbles auf 'sent' (✓) setzen ARIA-Reply markiert dann wie gehabt 'delivered' (✓✓). Damit kann keine Bubble mehr auf failed gehen waehrend Brain noch laeuft. Plus: ACK_TIMEOUT_MS 30 → 60 s als Backup-Reserve fuer den Fall dass weder ACK noch agent_activity ankommt (sehr unwahrscheinlich, aber billig). Co-Authored-By: Claude Opus 4.7 (1M context) --- android/src/screens/ChatScreen.tsx | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/android/src/screens/ChatScreen.tsx b/android/src/screens/ChatScreen.tsx index 8d03e80..99d6490 100644 --- a/android/src/screens/ChatScreen.tsx +++ b/android/src/screens/ChatScreen.tsx @@ -324,7 +324,12 @@ const ChatScreen: React.FC = () => { // Wie lange wir auf das ACK warten bevor wir retryen. Bridge sollte // unmittelbar zurueckmelden — 30s ist grosszuegig fuer schlechte Netze. - const ACK_TIMEOUT_MS = 30_000; + // 60s — grosszuegiger als 30s, weil langsame Brain-Calls (Multi-Tool) sonst + // 90s × 3 Retries lang die User-Bubble auf ⏳ stehen lassen wuerden. Der + // wichtige Pfad ist sowieso: agent_activity = thinking → markiert die + // Bubble sofort als 'sent' (siehe handler). Das hier ist Fallback wenn + // weder ACK noch agent_activity ankommt. + const ACK_TIMEOUT_MS = 60_000; // Wie oft re-tryen wir bevor wir "failed" anzeigen. const MAX_SEND_ATTEMPTS = 3; // Pending ACK-Timer pro clientMsgId — fuer cancel beim ACK. @@ -1026,6 +1031,22 @@ const ChatScreen: React.FC = () => { const activity = (message.payload.activity as string) || 'idle'; const tool = (message.payload.tool as string) || ''; setAgentActivity({ activity, tool }); + // Implizite ACK-Bestaetigung: Brain hat angefangen zu arbeiten → + // unsere Nachricht ist offensichtlich angekommen, auch wenn das + // chat_ack aus irgendeinem Grund nicht durchkam. Alle laufenden + // ACK-Timer canceln + sending-Bubbles auf 'sent' setzen. + // Vermeidet das Symptom "Sanduhr bleibt + Timeout" bei langsamen + // Brain-Antworten (>90 s, also nach 3 ACK-Retries auf failed). + if (activity !== 'idle' && ackTimers.current.size > 0) { + for (const cmid of Array.from(ackTimers.current.keys())) { + clearAckTimer(cmid); + } + setMessages(prev => prev.map(m => + m.sender === 'user' && m.deliveryStatus === 'sending' + ? { ...m, deliveryStatus: 'sent' } + : m + )); + } // In den Gedanken-Stream einfuegen. Dedup gegen identische Folge- // Events (z.B. zwei mal 'thinking' direkt hintereinander). Tool- // Events NIE dedupen — wenn ARIA dreimal Bash hintereinander ruft,