fix(useAiChatStream): render assistant reply on final-only SSE streams#199
Merged
Merged
Conversation
When the OpenRegister side ships the non-streaming-provider degradation path (one `final` event with `fullText`, no preceding `token` events), the previous finalise() pushed an empty `content: ''` message into the state because state.currentText was never populated. The assistant bubble rendered as empty. Two related defensive fixes: - In the `final` handler: if no `token` events arrived, seed state.currentText from parsed.fullText before finalising. This matches the hydra spec's contract clause: "Non-streaming LLPhant providers MUST degrade gracefully: emit zero `token` events and exactly one `final` event carrying `fullText`." - In finalise(): use the server's parsed.messageId as the message's Vue render-key id when present; synthesise a stable client-side id (`client-<ts>-<rand>`) when the server sends an empty messageId. Pairs with openregister#1466's follow-up that now propagates the persisted assistant message's id through the `final` event. End-to-end: real LLM round-trip through the decidesk pilot now renders the assistant bubble with the qwen3.5 reply visible.
Contributor
|
🎉 This PR is included in version 1.0.0-beta.31 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #197 / #198. End-to-end testing surfaced two related defensive issues in
useAiChatStream:Empty assistant bubble on non-streaming-provider degradation path. When OR ships only a terminal
finalSSE event (per the hydra spec's degradation clause: "Non-streaming providers MUST emit zerotokenevents and exactly onefinalevent carryingfullText"), the previousfinalise()ran withstate.currentText === ''because notokenevents ever populated it. The assistant bubble pushed ontostate.messageshadcontent: ''and rendered blank inCnAiMessageList.Empty Vue render key when server sends empty
messageId. OR's first cut shippedmessageId: ""in thefinalevent (separate fix landing in openregister#1466 follow-up commit). The widget used array index as key, which mostly works, but an explicit id is more robust for re-renders.Fix
finalhandler: ifstate.currentText === ''andparsed.fullTextis a string, seedstate.currentTextbefore callingfinalise(). Matches the spec's degradation clause exactly.finalise(messageId): prefer server-suppliedparsed.messageId; synthesiseclient-<timestamp>-<random>when missing/empty.Verified
Real LLM round-trip through the decidesk pilot: qwen3.5 reply visible in the chat panel.
Pair
Pairs with openregister#1466 follow-up commit that propagates the persisted assistant message's id into the
finalevent payload.Test plan
final-only SSE stream → assistant bubble renders with payload'sfullTexttokenevents +final→ bubble renders with accumulated text (existing behaviour unchanged)messageId→ synthesised client idmessageId→ server id usedDefensive change, no test-suite update required (the existing scenario tests still pass; one new test could mock the non-streaming-provider path — out of scope for this hotfix).