diff --git a/gateway/stream_consumer_fallback.py b/gateway/stream_consumer_fallback.py index 44ca80fae5..135915d857 100644 --- a/gateway/stream_consumer_fallback.py +++ b/gateway/stream_consumer_fallback.py @@ -58,7 +58,9 @@ class StreamFallbackMixin: # the continuation re-sends the broken word's tail and reads as an # ordinary continuation. A prefix with no boundary (one very long # token) keeps the original cut rather than re-sending the whole reply. - if cut < len(final_text): + # A prefix that already ends on a whole word needs no back-up: doing it + # re-sent that word at the seam. + if cut < len(final_text) and not final_text[cut].isspace() and not final_text[cut - 1].isspace(): boundary = max( final_text.rfind(" ", 0, cut), final_text.rfind("\n", 0, cut), diff --git a/tests/gateway/test_stream_consumer_continuation_cut.py b/tests/gateway/test_stream_consumer_continuation_cut.py index e17300b27d..6137246ed9 100644 --- a/tests/gateway/test_stream_consumer_continuation_cut.py +++ b/tests/gateway/test_stream_consumer_continuation_cut.py @@ -49,3 +49,9 @@ class TestContinuationWordBoundary: consumer._last_sent_text = "у" * 100 final_text = ("у" * 100) + ("д" * 20) assert consumer._continuation_text(final_text) == "д" * 20 + + def test_whole_word_prefix_is_not_resent(self): + # The preview ends exactly on a word; the continuation must not repeat it. + consumer = _make_consumer() + consumer._last_sent_text = "Here is the answer ▉" + assert consumer._continuation_text("Here is the answer to your question.") == "to your question."