Repository navigation
fix(local): discard a chat turn that ends with no answer text - #2037
Conversation
A stream that closed cleanly with no text, as a thinking model does when its trace spends the whole answer cap, kept a blank assistant turn and renamed the thread. The discard guard was 'failed and not parts'; it is now 'not parts', and the clean case sends an unknown error so the client knows the question was removed with it. Fixes MODSetter#1942
|
@Cedric921 is attempting to deploy a commit to the Rohan Verma's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What
A chat turn that ends with no answer text is discarded, both halves and the deferred rename, whether generation failed or closed cleanly. The discard guard in
stream()goes fromfailed and not partstonot parts, in thefinallyblock and in the early return, so both still agree.Why
A stream can close cleanly with nothing to say; the usual way on the local runtime is a thinking model whose trace spends the whole answer cap. The turn was kept, leaving a blank assistant bubble, and on a first turn the thread was renamed after a question nothing answered.
Decisions, as the issue asks:
errorwith kindunknown, then[DONE], the same frame order as a failed turn. Deleting the turn also removes the person's own message, so closing in silence would make it vanish unexplained. I reusedunknownrather than adding a kind: its text ("Something went wrong generating a reply. Try again.") is accurate, a retry can succeed since sampling differs between runs, and a new kind would need a translated string in every locale.empty_reply_error()inerrors.pynames that choice in one place.failed andhalf of the guard changed.docs/architecture/chat.md: the stream prose now covers the clean case, and the Known gaps line is removed.Fixes #1942
How to test
test_a_reply_with_no_text_leaves_no_traceis parametrized over no reasoning and reasoning-only; both failed before the change. The stub llama-server gainsset_answer()so a test can make it answer with no deltas.High-level PR Summary
This PR fixes an issue where chat turns that end with no answer text (e.g., when a thinking model exhausts its answer capacity during trace generation) were incorrectly kept in the chat history, resulting in blank assistant bubbles and inappropriate thread renames. The fix ensures these empty turns are discarded regardless of whether generation failed or closed cleanly, by updating the discard guard from
failed and not partstonot parts. Clean closures now send anunknownerror kind before the[DONE]frame to explain why the user's message was removed.⏱️ Estimated Review Time: 5-15 minutes
💡 Review Order Suggestion
docs/architecture/chat.mdsurfsense_local/backend/modules/chat/errors.pysurfsense_local/backend/modules/chat/router.pysurfsense_local/backend/tests/integration/chat/conftest.pysurfsense_local/backend/tests/integration/chat/test_chat.py