diff --git a/src/mnemosyne/gateway.py b/src/mnemosyne/gateway.py index 998d727..e1a9b4d 100644 --- a/src/mnemosyne/gateway.py +++ b/src/mnemosyne/gateway.py @@ -136,12 +136,17 @@ class SSECleanupFilter: """Process a raw SSE chunk (may contain multiple lines). Returns the (possibly rewritten) chunk to forward downstream. + When a text delta is suppressed (buffering inside a tag), the + preceding ``event:`` header line is also removed to avoid + producing malformed SSE (event header with no data). """ lines = raw_chunk.split(b"\n") out_lines: list[bytes] = [] for line in lines: if not line.startswith(b"data: "): + # Buffer event: lines — only emit them if the next data: line + # is kept. Non-event lines (empty lines, comments) pass through. out_lines.append(line) continue @@ -173,15 +178,18 @@ class SSECleanupFilter: # Feed text into buffer and get cleaned output cleaned = self._feed(text) - if cleaned is None: - # Entire chunk is being buffered (inside a tag) — suppress + if cleaned is None or not cleaned: + # Suppressed — also remove the preceding "event:" line + # to avoid malformed SSE (event header with no data) + if out_lines and out_lines[-1].startswith(b"event:"): + out_lines.pop() + # Also remove trailing empty line if present + if out_lines and out_lines[-1] == b"": + out_lines.pop() continue elif cleaned == text: # No change — pass through original bytes out_lines.append(line) - elif not cleaned: - # Text was entirely a cleanup tag — suppress this event - continue else: # Rewrite the delta with cleaned text delta["text"] = cleaned