Python: preserve unmapped Anthropic and Mistral finish reasons - #7850
Conversation
The Anthropic and Mistral chat clients looked their finish reason maps up without a default, so any provider value the map did not cover was reported to the caller as no finish reason at all. Anthropic's model_context_window_exceeded and Mistral's error both disappeared this way. Fall back to the raw provider value instead, the way the other provider clients have since microsoft#7105. Every already-mapped value keeps mapping as before, and an absent reason stays absent. Fixes microsoft#7849
There was a problem hiding this comment.
Pull request overview
Preserves previously unmapped Anthropic and Mistral finish reasons across standard and streaming responses.
Changes:
- Adds provider-specific finish-reason mapping helpers with raw-value fallbacks.
- Applies fallback mapping across all response paths.
- Adds regression coverage for mapped, unmapped, and absent reasons.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
python/packages/anthropic/agent_framework_anthropic/_chat_client.py |
Preserves unmapped Anthropic stop reasons. |
python/packages/anthropic/tests/test_anthropic_client.py |
Tests Anthropic mapping and streaming behavior. |
python/packages/mistral/agent_framework_mistral/_chat_client.py |
Preserves unmapped Mistral finish reasons. |
python/packages/mistral/tests/mistral/test_mistral_chat_client.py |
Tests Mistral mapped, unmapped, and absent reasons. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
|
/review |
Python Test Coverage Report •
Python Unit Test Overview
|
||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: No findings
Scope: full PR (1 commit(s)): f1c6f571aa84
Model: gpt-5.6-sol
Overview
The PR centralizes finish-reason normalization in both providers, preserving known mappings while passing through non-empty unknown values under the core extensible FinishReason contract. Streaming and non-streaming paths are covered, absent values remain None, and existing aggregation and tool-call behavior are unchanged. The added tests and established provider precedent prevent a publishable compatibility, architectural, or security concern.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.
|
Giles Odigwe (@giles17) can you put this in merge-queue again ? |
Updated [Microsoft.Agents.AI](https://github.com/microsoft/agent-framework) from 1.19.0 to 1.20.0. <details> <summary>Release notes</summary> _Sourced from [Microsoft.Agents.AI's releases](https://github.com/microsoft/agent-framework/releases)._ ## 1.20.0 ## What's Changed * .NET: Bump AWSSDK.Extensions.Bedrock.MEAI from 4.0.6.10 to 4.0.101.8 by @dependabot[bot] in microsoft/agent-framework#7829 * .NET: Stabilize Foundry recovery tests by @rogerbarreto in microsoft/agent-framework#7817 * .NET: fix: preserve Responses logprobs field by @he-yufeng in microsoft/agent-framework#5860 * .NET: Honor cancellation for Foundry-hosted workflow responses by @rogerbarreto with @Copilot in microsoft/agent-framework#7842 * .NET: Use Responses API for hosted web search in AG-UI by @rogerbarreto with @Copilot in microsoft/agent-framework#7843 * .NET: Bump Aspire.Hosting from 13.1.0 to 13.5.2 by @dependabot[bot] in microsoft/agent-framework#7826 * .NET: Suppress false positive Zip Slip alert by @SergeyMenshykh in microsoft/agent-framework#7858 * .NET: added Mem0Sharp integration for in-memory storage in agent samples. by @jihadkhawaja in microsoft/agent-framework#7792 * .NET: Annotate DevUI aggregator static-analysis false positives by @SergeyMenshykh in microsoft/agent-framework#7864 * .NET: Rename CommunityToolkit.VectorData.CosmosNoSql to AzureCosmosDB by @adamsitnik in microsoft/agent-framework#7878 * .NET: chore: upgrades aspnet openapi dependency by @baywet in microsoft/agent-framework#7870 * .NET: Simplify A2A function tool samples by @SergeyMenshykh in microsoft/agent-framework#7861 * .NET: Bump Azure.AI.AgentServer.Invocations from 1.0.0-beta.5 to 1.0.0-beta.6 by @dependabot[bot] in microsoft/agent-framework#7886 * .NET: docs: updates the contributing information for CFS users by @baywet in microsoft/agent-framework#7869 * Bump CommunityToolkit.VectorData.InMemory from 1.0.0 to 1.0.1 by @dependabot[bot] in microsoft/agent-framework#7888 * .NET: Remove retired OpenAI Assistants integration tests by @rogerbarreto in microsoft/agent-framework#7896 * .NET: Simplify A2A client-server sample by @SergeyMenshykh in microsoft/agent-framework#7891 * Bump Dapr.AI.Microsoft.Extensions from 1.18.4 to 1.18.5 by @dependabot[bot] in microsoft/agent-framework#7889 * .NET: docs/workflow fileinput sample dotnet by @baywet in microsoft/agent-framework#7913 * .NET: Add timeout for wait-for-first-completion by @westey-m in microsoft/agent-framework#7911 * .NET: Fix duplicate Foundry AgentHost port binding by @rogerbarreto in microsoft/agent-framework#7932 * .NET: tests: removes dependency on fluent assersion because of licensing concerns by @baywet in microsoft/agent-framework#7938 * .NET: docs(decisions): resolve duplicate ADR sequence numbers (0016, 0021, 0024) by @jluocsa in microsoft/agent-framework#6046 * .NET: Bump Azure.Core from 1.61.0 to 1.62.0 by @dependabot[bot] in microsoft/agent-framework#7954 * .NET: Improve Cosmos DB Emulator startup reliability by @TheovanKraay in microsoft/agent-framework#3932 * .NET: add public API analyzers by @baywet in microsoft/agent-framework#7935 * .NET: Update version for 1.20.0 release by @SergeyMenshykh in microsoft/agent-framework#7972 ## New Contributors * @madanmishra1223 made their first contribution in microsoft/agent-framework#7705 * @YashvantHange made their first contribution in microsoft/agent-framework#7850 * @jihadkhawaja made their first contribution in microsoft/agent-framework#7792 * @adamsitnik made their first contribution in microsoft/agent-framework#7878 * @baywet made their first contribution in microsoft/agent-framework#7870 * @Namraa310806 made their first contribution in microsoft/agent-framework#7901 * @Sweetteabittersugar made their first contribution in microsoft/agent-framework#7903 * @shoemoney made their first contribution in microsoft/agent-framework#7837 * @jluocsa made their first contribution in microsoft/agent-framework#6046 **Full Changelog**: microsoft/agent-framework@dotnet-1.19.0...dotnet-1.20.0 Commits viewable in [compare view](microsoft/agent-framework@dotnet-1.19.0...dotnet-1.20.0). </details> Updated [Microsoft.Agents.AI.OpenAI](https://github.com/microsoft/agent-framework) from 1.19.0 to 1.20.0. <details> <summary>Release notes</summary> _Sourced from [Microsoft.Agents.AI.OpenAI's releases](https://github.com/microsoft/agent-framework/releases)._ ## 1.20.0 ## What's Changed * .NET: Bump AWSSDK.Extensions.Bedrock.MEAI from 4.0.6.10 to 4.0.101.8 by @dependabot[bot] in microsoft/agent-framework#7829 * .NET: Stabilize Foundry recovery tests by @rogerbarreto in microsoft/agent-framework#7817 * .NET: fix: preserve Responses logprobs field by @he-yufeng in microsoft/agent-framework#5860 * .NET: Honor cancellation for Foundry-hosted workflow responses by @rogerbarreto with @Copilot in microsoft/agent-framework#7842 * .NET: Use Responses API for hosted web search in AG-UI by @rogerbarreto with @Copilot in microsoft/agent-framework#7843 * .NET: Bump Aspire.Hosting from 13.1.0 to 13.5.2 by @dependabot[bot] in microsoft/agent-framework#7826 * .NET: Suppress false positive Zip Slip alert by @SergeyMenshykh in microsoft/agent-framework#7858 * .NET: added Mem0Sharp integration for in-memory storage in agent samples. by @jihadkhawaja in microsoft/agent-framework#7792 * .NET: Annotate DevUI aggregator static-analysis false positives by @SergeyMenshykh in microsoft/agent-framework#7864 * .NET: Rename CommunityToolkit.VectorData.CosmosNoSql to AzureCosmosDB by @adamsitnik in microsoft/agent-framework#7878 * .NET: chore: upgrades aspnet openapi dependency by @baywet in microsoft/agent-framework#7870 * .NET: Simplify A2A function tool samples by @SergeyMenshykh in microsoft/agent-framework#7861 * .NET: Bump Azure.AI.AgentServer.Invocations from 1.0.0-beta.5 to 1.0.0-beta.6 by @dependabot[bot] in microsoft/agent-framework#7886 * .NET: docs: updates the contributing information for CFS users by @baywet in microsoft/agent-framework#7869 * Bump CommunityToolkit.VectorData.InMemory from 1.0.0 to 1.0.1 by @dependabot[bot] in microsoft/agent-framework#7888 * .NET: Remove retired OpenAI Assistants integration tests by @rogerbarreto in microsoft/agent-framework#7896 * .NET: Simplify A2A client-server sample by @SergeyMenshykh in microsoft/agent-framework#7891 * Bump Dapr.AI.Microsoft.Extensions from 1.18.4 to 1.18.5 by @dependabot[bot] in microsoft/agent-framework#7889 * .NET: docs/workflow fileinput sample dotnet by @baywet in microsoft/agent-framework#7913 * .NET: Add timeout for wait-for-first-completion by @westey-m in microsoft/agent-framework#7911 * .NET: Fix duplicate Foundry AgentHost port binding by @rogerbarreto in microsoft/agent-framework#7932 * .NET: tests: removes dependency on fluent assersion because of licensing concerns by @baywet in microsoft/agent-framework#7938 * .NET: docs(decisions): resolve duplicate ADR sequence numbers (0016, 0021, 0024) by @jluocsa in microsoft/agent-framework#6046 * .NET: Bump Azure.Core from 1.61.0 to 1.62.0 by @dependabot[bot] in microsoft/agent-framework#7954 * .NET: Improve Cosmos DB Emulator startup reliability by @TheovanKraay in microsoft/agent-framework#3932 * .NET: add public API analyzers by @baywet in microsoft/agent-framework#7935 * .NET: Update version for 1.20.0 release by @SergeyMenshykh in microsoft/agent-framework#7972 ## New Contributors * @madanmishra1223 made their first contribution in microsoft/agent-framework#7705 * @YashvantHange made their first contribution in microsoft/agent-framework#7850 * @jihadkhawaja made their first contribution in microsoft/agent-framework#7792 * @adamsitnik made their first contribution in microsoft/agent-framework#7878 * @baywet made their first contribution in microsoft/agent-framework#7870 * @Namraa310806 made their first contribution in microsoft/agent-framework#7901 * @Sweetteabittersugar made their first contribution in microsoft/agent-framework#7903 * @shoemoney made their first contribution in microsoft/agent-framework#7837 * @jluocsa made their first contribution in microsoft/agent-framework#6046 **Full Changelog**: microsoft/agent-framework@dotnet-1.19.0...dotnet-1.20.0 Commits viewable in [compare view](microsoft/agent-framework@dotnet-1.19.0...dotnet-1.20.0). </details> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Motivation & Context
AnthropicChatClientandMistralChatClientlook their finish reason maps up without a default, so any provider value the map does not cover reaches the caller asfinish_reason=None— indistinguishable from a response that carries no finish reason at all. Anthropic'smodel_context_window_exceededand Mistral'serrorare both lost this way, silently: nothing is logged, no exception is raised, and the OTelgen_aispan records no finish reason for those turns.#7105 already fixed this for
ag-ui,bedrock,claude,core,github_copilot,ollama, andopenai. These two packages were missed. (geminihas the same gap and is covered separately by #7836 / #7837.)Description & Review Guide
What are the major changes?
A module-level
_map_finish_reasonhelper in each of the two clients that falls back to the raw provider value, wrapped inFinishReason(...)so it type-checks under each package's strict Pyright config. It replaces three inline lookups in the Anthropic client (_process_message, and themessage_startandmessage_deltabranches of_process_stream_event) and two in the Mistral client (_parse_response,_parse_chunk). Tests cover the unmapped value in both the non-streaming and streaming paths, plus regressions for the already-mapped values and the absent case.What is the impact of these changes?
Callers that previously saw
finish_reason=Nonefor an unmapped provider value now see the raw provider string. That is the normalization Python: Normalize chat finish reasons #7105 established and it is the documented contract of the type:FinishReasonLiteralis the four known values, whileFinishReasonis aNewType("FinishReason", str)explicitly documented as accepting any string for extensibility, exactly asbedrock,claudeandollamaalready emit. Nothing in the repo branches onfinish_reason,ChatResponsedoes not validate it, andChatTelemetryLayeralready filters non-standard values back out before they reach OTel. Every value currently in the two maps keeps mapping exactly as it does today, and an absent reason staysNone, so no existing behavior narrows.What do you want reviewers to focus on?
Whether the two new helpers should instead be instance methods, to match
bedrock/gemini, rather than module-level functions next to their maps as they are here — and whether Anthropic'smodel_context_window_exceededwould be better mapped explicitly tolengthrather than passed through as the raw value.Verified locally on both packages:
poe syntax,poe pyright,poe test-typing(pyright, pyrefly, ty, mypy, zuban) andpoe testare all clean. The new "unmapped is preserved" tests fail onmainbefore the change.Related Issue
Fixes #7849
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.