fix(streaming): don't attach finish_reason to content-bearing chunk - #462
Conversation
|
Warning Review limit reached
More reviews will be available in 3 minutes and 23 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR nullifies ChangesStream finish reason handling fix
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
4a18e95 to
7d45bd2
Compare
stream_with_source_filtering builds the final content chunk by deep-copying chunk_template, which at end-of-stream is the upstream *finish* chunk and so carries finish_reason. The emitted tail chunk therefore contained both content and finish_reason=stop. Spec-compliant OpenAI streaming clients treat a chunk with a non-null finish_reason as terminal and ignore its delta. Such clients (e.g. the Twake Workplace RAG integration) drop the tail content: short answers render blank, long answers lose their final ~lookahead-window of text. The server still returns 200, so the regression is invisible server-side. Clear finish_reason on the content-bearing tail chunk; the separate finish chunk that follows still emits finish_reason with an empty delta, matching the OpenAI streaming contract.
7d45bd2 to
714f2a8
Compare
Problem
stream_with_source_filtering(openrag/components/utils.py) emits the finalcontent of a streamed chat completion in a chunk that also carries
finish_reason: "stop".At end-of-stream the function builds the tail chunk via
copy.deepcopy(chunk_template), andchunk_templateat that point is theupstream finish chunk (the one whose
choices[0].finish_reasonis set).The resulting tail chunk therefore contains both the remaining
delta.contentand
finish_reason: "stop":Spec-compliant OpenAI streaming clients treat a chunk with a non-null
finish_reasonas terminal and ignore itsdelta. Such clients (e.g. theTwake Workplace RAG integration) therefore drop the tail content:
look-ahead window and is flushed only in the finish-tagged tail chunk);
truncation).
The HTTP response is still
200, so the regression is invisible server-side.Behaviour was correct in 1.1.7, which emitted content chunks with
finish_reason: nulland a separate empty finish chunk.Fix
Clear
finish_reasonon the content-bearing tail chunk. The separate finishchunk that immediately follows still emits
finish_reasonwith an emptydelta, matching the OpenAI streaming contract.Verification
finish chunk, complete text (no truncation), sources still delivered in
extra.Summary by CodeRabbit