Skip to content

Keep null finish reason in streaming conversion - #7866

Open
nurullahturkoglu wants to merge 1 commit into
dotnet:mainfrom
nurullahturkoglu:fix/streaming-finish-reason-7863
Open

nurullahturkoglu wants to merge 1 commit into
dotnet:mainfrom
nurullahturkoglu:fix/streaming-finish-reason-7863

Conversation

@nurullahturkoglu

@nurullahturkoglu nurullahturkoglu commented Oct 20, 2026 •

Copy link
Copy Markdown

Fixes #7863

AsOpenAIStreamingChatCompletionUpdatesAsync passed every update through ToChatFinishReason, whose default arm maps null to Stop. Every content chunk before the last one was written with "finish_reason":"stop", so a client that ends the turn on the first non-null finish reason stops after the first chunk.

The streaming path now passes null when the update has no finish reason. AsOpenAIChatCompletion keeps its Stop default, since a complete response always has a finish reason. The reverse conversion in OpenAIChatClient already maps a missing finish reason to null.

AsOpenAIStreamingChatCompletionUpdatesAsync_WithMultipleUpdates_ProcessesAllCorrectly asserted the old behavior for the first chunk, so I changed that assertion to expect null. It fails without the fix.

I ran Microsoft.Extensions.AI.OpenAI.Tests for net10.0 on macOS arm64: 396 passed, 163 skipped, 0 failed. I didn't run net8.0 or net9.0 locally. I also serialized the two updates from the issue with ModelReaderWriter: the content chunk no longer has a finish_reason property, and the terminal chunk has "length".

Microsoft Reviewers: Open in CodeFlow

AsOpenAIStreamingChatCompletionUpdatesAsync mapped a missing finish
reason to Stop, so every content chunk was written with
"finish_reason":"stop". Pass null on the streaming path instead. The
non-streaming conversion keeps its Stop default.

Fixes dotnet#7863
@nurullahturkoglu
nurullahturkoglu requested a review from a team as a code owner October 20, 2026 19:15
@github-actions github-actions Bot added the area-ai Microsoft.Extensions.AI libraries label Oct 20, 2026
@dotnet-comment-bot

Copy link
Copy Markdown
Collaborator

‼️ Found issues ‼️

Project Coverage Type Expected Actual
Microsoft.Extensions.Diagnostics.Testing Line 99 98.65 🔻
Microsoft.Extensions.Telemetry Line 93 92.75 🔻
Microsoft.Extensions.AI Line 89 88.4 🔻
Microsoft.Extensions.AI.OpenAI Line 75 68.24 🔻
Microsoft.Extensions.AI.OpenAI Branch 75 57.59 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Line 75 4.46 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Branch 75 0 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Line 99 96.07 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Branch 99 92.76 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes Line 99 97.73 🔻
Microsoft.Extensions.ServiceDiscovery.Dns Line 75 69.93 🔻
Microsoft.Extensions.ServiceDiscovery Line 75 68.88 🔻
Microsoft.Extensions.ServiceDiscovery Branch 75 71.43 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Line 75 42.11 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Branch 75 42.86 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Line 75 73.85 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Branch 75 70 🔻
Microsoft.Extensions.VectorData.Abstractions Line 75 37.39 🔻
Microsoft.Extensions.VectorData.Abstractions Branch 75 22.73 🔻

🎉 Good job! The coverage increased 🎉
Update MinCodeCoverage in the project files.

Project Expected Actual
Microsoft.Extensions.Http.Diagnostics 94 95
Microsoft.Gen.BuildMetadata 97 100
Microsoft.Gen.MetadataExtractor 57 73
Microsoft.Gen.MetricsReports 67 69
Microsoft.Extensions.AI.Abstractions 82 86
Microsoft.Extensions.AI.Evaluation.NLP 0 78
Microsoft.Extensions.Caching.Hybrid 82 89
Microsoft.Extensions.DataIngestion 75 89
Microsoft.Extensions.DataIngestion.Markdig 75 90
Microsoft.Extensions.Http.Resilience 97 100

Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1642632&view=codecoverage-tab

@valkiara valkiara left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 555648c. The adapter test project passed on net10.0 with SDK 10.0.401: 396 passed, 163 skipped with live integration tests disabled.

I also ran eight local cases checking serialized finish reasons for stop, length, content_filter, tool_calls and function_call, plus function-call deltas, raw-update passthrough and the completed-response default. Content and trailing usage chunks kept a missing finish reason, terminal chunks retained their explicit reason, and non-streaming responses still defaulted to Stop. All eight passed.

No issues found in the changed conversion path.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-ai Microsoft.Extensions.AI libraries

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Microsoft.Extensions.AI.OpenAI] AsOpenAIStreamingChatCompletionUpdatesAsync writes finish_reason "stop" on every chunk with a null FinishReason

3 participants