fix(stream_consumer): always strip cursor on stream end — never get stuck#7426
fix(stream_consumer): always strip cursor on stream end — never get stuck#7426dangelo352 wants to merge 3 commits into
Conversation
…tuck
When the stream ends, the final flush only ran if _accumulated was
non-empty. If no new text arrived after the last progressive edit
(with cursor appended), _accumulated was empty and the cursor was left
stuck on the Telegram message forever.
Fix: track _last_edit_had_cursor after every successful edit/send.
When the stream ends with _accumulated empty but a stuck cursor,
do one final edit to strip it.
Root cause:
- Progressive edit sends 'Hello...' with cursor
- Stream ends before next token arrives
- got_done: if self._accumulated → empty → skip final flush
- Cursor stays on message forever
Fix:
- Add _last_edit_had_cursor bool, set after every successful edit
- got_done handler now has elif branch: when _accumulated empty
but _last_edit_had_cursor, strip cursor from _last_sent_text
and do one final clean edit
… chat The model's stream can include terminal spinner characters (▍ ▉ █ ░), box-drawing chars, and ANSI escape sequences that render as black rectangles or garbage in Telegram/Discord. Extend _clean_for_display to strip: - Block/quarter-block chars (U+2588..U+258F, U+2591..U+2595) - Box-drawing chars (U+2500..U+257F) - Spinner/progress glyphs (U+25B6..U+25CF, U+2600..U+266F) - Braille patterns (U+2800..U+28FF) - ANSI escape sequences (colors, cursor moves, clears) - Zero-width/control chars (U+200B..U+200F, U+FEFF, etc.) Also update test that now correctly expects cursor chars stripped from all outgoing messages.
…reeze When context compaction fires during a streamed conversation, the compression LLM call would edit the same Telegram message as the agent's response. After compaction completed, the stream consumer still held state pointing at the old message, causing subsequent edits to fail and the chat to appear "stuck" or never finish. Fix: after compression, reset the stream consumer's accumulated text, message ID, and fallback state. The next API response streams to a fresh Telegram message instead of fighting over the old one. Also wire _stream_consumer_instance from the gateway's stream_consumer holder into the agent so _compress_context can access it.
…reeze When context compaction fires during a streamed conversation, the compression LLM call would edit the same Telegram message as the agent's response. After compaction completed, the stream consumer still held state pointing at the old message, causing subsequent edits to fail and the chat to appear "stuck" or never finish. Fix: after compression, reset the stream consumer's accumulated text, message ID, and fallback state. The next API response streams to a fresh Telegram message instead of fighting over the old one. Also wire _stream_consumer_instance from the gateway's stream_consumer holder into the agent so _compress_context can access it. Cherry-picked from PR NousResearch#7426 by @dangelo352.
|
Thanks for the report and for digging into this, D'Angelo — the symptom you identified (agent appearing to stop/freeze mid-session on Telegram) was real and affecting multiple users. The root cause turned out to be different from what the three commits here targeted. The stream consumer state, cursor tracking, and compaction reset paths are all actually correct on current main (we traced every code path in detail). The actual bug was in the gateway's response delivery: when the stream consumer had sent at least one message ( This is gateway-only (never CLI) because CLI has no Fixed in PR #7652. Your report helped us find it — appreciate it. |
Summary
Fix: the streaming message in Telegram gets stuck with the cursor never being removed.
Root cause: When the stream ends,
got_doneonly flushed if_accumulatedwas non-empty. If no new text arrived after the last progressive edit (which appended the cursor),_accumulatedwas empty and the cursor stayed stuck on the Telegram message forever.Fix:
_last_edit_had_cursorbool is set after every successful edit/send — tracks whether the last edit appended the cursor_accumulatedbut_last_edit_had_cursoris True, do one final edit to strip the cursor from_last_sent_textThat's it. No other changes.
Test Plan
Closes: streaming message never stops / cursor stuck forever