Python: Normalize chat finish reasons#7105
Open
eavanvalkenburg wants to merge 3 commits into
Open
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 45b65bfa-8e36-47b0-99d9-ec58ec60ace1
Contributor
Contributor
There was a problem hiding this comment.
Pull request overview
This PR standardizes how Python integrations populate and propagate terminal finish_reason values across providers/clients, ensuring consumers can reliably distinguish normal stops, length truncation, tool calls, and content filtering while avoiding telemetry serialization issues for non-canonical values.
Changes:
- Adds Responses-API finish-reason mapping for
OpenAIChatClient(non-streaming + streaming) and corresponding unit tests. - Normalizes and/or preserves provider finish reason strings across several clients (Chat Completions function-call mapping; Ollama/Claude/Bedrock/Copilot adjustments).
- Updates OTel message capture to only emit canonical finish reasons, and updates AG-UI RUN_ERROR handling to leave
finish_reasonunset.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| python/packages/openai/tests/openai/test_openai_chat_client.py | Adds unit tests covering Responses API status/incomplete-details → finish_reason mapping (streaming + non-streaming). |
| python/packages/openai/agent_framework_openai/_chat_completion_client.py | Normalizes Chat Completions finish_reason "function_call" → "tool_calls". |
| python/packages/openai/agent_framework_openai/_chat_client.py | Implements finish-reason mapping for Responses API terminal states and wires it into parsing. |
| python/packages/ollama/tests/test_ollama_chat_client.py | Updates test to expect unknown provider finish reasons to be preserved. |
| python/packages/ollama/agent_framework_ollama/_chat_client.py | Preserves unknown done_reason values (and maps tool-call presence to "tool_calls"). |
| python/packages/github_copilot/tests/test_github_copilot_agent.py | Updates expectations for content-filter-triggered usage and preservation of provider-specific finish reasons. |
| python/packages/github_copilot/agent_framework_github_copilot/_agent.py | Adjusts how Copilot usage events map content_filter_triggered and finish_reason. |
| python/packages/core/agent_framework/observability.py | Guards OTel output-message finish-reason mapping to avoid non-canonical values causing issues. |
| python/packages/claude/tests/test_claude_agent.py | Updates tests to expect normalized Claude stop reasons (stop/length). |
| python/packages/claude/agent_framework_claude/_agent.py | Introduces a Claude stop-reason → framework finish-reason normalization map (while preserving unknowns). |
| python/packages/bedrock/tests/test_bedrock_settings.py | Adds coverage for Bedrock guardrail intervention mapping to content_filter. |
| python/packages/bedrock/agent_framework_bedrock/_chat_client.py | Maps guardrail_intervened → content_filter and preserves unknown finish-reason strings. |
| python/packages/ag-ui/tests/ag_ui/test_event_converters.py | Updates RUN_ERROR test expectation to leave finish_reason unset. |
| python/packages/ag-ui/agent_framework_ag_ui/_event_converters.py | Stops labeling generic RUN_ERROR events as content_filter. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 45b65bfa-8e36-47b0-99d9-ec58ec60ace1
moonbox3
reviewed
Jul 14, 2026
TaoChenOSU
approved these changes
Jul 14, 2026
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.
Motivation & Context
Responses-based clients and several other Python integrations either dropped terminal finish metadata or exposed incompatible provider-native values. This restores consistent finish-reason propagation and avoids incorrectly reporting generic AG-UI errors as content filtering.
Description & Review Guide
RUN_ERRORchange: generic run errors now leavefinish_reasonunset rather than being labeledcontent_filter.Related Issue
Fixes #7025
Fixes #7051
Fixes #4622
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.