From 07ff9e168ba249330ad56cf1fc03ad32a70dff26 Mon Sep 17 00:00:00 2001 From: Alex Castillo Date: Wed, 21 Oct 2026 04:56:22 -0400 Subject: [PATCH 1/2] fix(mistral): treat model_length as a context window finish reason Mistral stops a response with finish_reason model_length when the request reaches the model's context length. It was passed through as an unknown raw string, so chatlas neither warned about the truncated response nor refused to parse truncated structured data. Map it to "context_window". Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 1 + chatlas/_provider_openai_completions.py | 3 +++ tests/test_provider_openai_completions.py | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c7c6110..1daf544e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `params(top_k=)` is no longer sent as `top_logprobs` for OpenAI-based providers (the two are unrelated; OpenAI has no `top_k` sampling parameter). `top_k` is now dropped with the standard unsupported-parameter warning. (#412) * `Chat.export()` and `interpolate_file()` now always read and write files as UTF-8. Previously they relied on the platform's default locale encoding, so on a non-UTF-8 locale `export()` could raise `UnicodeEncodeError` and `interpolate_file()` could silently return a corrupted (mojibake) prompt instead of the file's contents. (#437) * `ChatAnthropic()` no longer drops assistant turns that have no content; doing so could produce two consecutive user messages, violating the API's user/assistant alternation requirement. A `"[empty string]"` placeholder is sent instead, matching how empty text content is already normalized. (#416) +* `ChatMistral()` now reports `"context_window"` as the finish reason when a response stops with Mistral's `model_length` (the request reached the model's context length), instead of passing the raw string through. As for other providers, this makes chatlas warn about the truncated response (or raise an error when a data model was requested). ## [0.23.0] - 2026-09-04 diff --git a/chatlas/_provider_openai_completions.py b/chatlas/_provider_openai_completions.py index e68805e3..8ebff4c7 100644 --- a/chatlas/_provider_openai_completions.py +++ b/chatlas/_provider_openai_completions.py @@ -150,6 +150,9 @@ def ChatOpenAICompletions( "tool_calls": "tool_use", "length": "max_tokens", "content_filter": "content_filter", + # Mistral: the request ran into the model's context length + # https://docs.mistral.ai/api/endpoint/chat + "model_length": "context_window", } diff --git a/tests/test_provider_openai_completions.py b/tests/test_provider_openai_completions.py index be38b46b..4b9665ff 100644 --- a/tests/test_provider_openai_completions.py +++ b/tests/test_provider_openai_completions.py @@ -44,6 +44,7 @@ def test_normalize_finish_reason_maps_known_reasons(): assert completions_normalize_finish_reason("length") == "max_tokens" assert completions_normalize_finish_reason("content_filter") == "content_filter" assert completions_normalize_finish_reason("tool_calls") == "tool_use" + assert completions_normalize_finish_reason("model_length") == "context_window" def test_normalize_finish_reason_passes_through_unknown(): @@ -564,3 +565,23 @@ def test_azure_completions_opts_into_strict(): api_version="2024-10-21", ) assert provider._strict is True + + +def test_model_length_finish_reason_warns_about_the_context_window(): + completion = ChatCompletion.construct( + id="x", + choices=[ + { + "index": 0, + "finish_reason": "model_length", + "message": {"role": "assistant", "content": "partial"}, + } + ], + ) + provider = OpenAICompletionsProvider(api_key="key", model="m") + + turn = provider.value_turn(completion, has_data_model=False) + assert turn.finish_reason == "context_window" + + with pytest.raises(ValueError, match="context window"): + provider.value_turn(completion, has_data_model=True) From df9b174e824b15df966bad5d1293901bf4fc51ee Mon Sep 17 00:00:00 2001 From: Alex Castillo Date: Wed, 21 Oct 2026 05:06:50 -0400 Subject: [PATCH 2/2] docs: add PR number to the changelog entry Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1daf544e..b145b922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `params(top_k=)` is no longer sent as `top_logprobs` for OpenAI-based providers (the two are unrelated; OpenAI has no `top_k` sampling parameter). `top_k` is now dropped with the standard unsupported-parameter warning. (#412) * `Chat.export()` and `interpolate_file()` now always read and write files as UTF-8. Previously they relied on the platform's default locale encoding, so on a non-UTF-8 locale `export()` could raise `UnicodeEncodeError` and `interpolate_file()` could silently return a corrupted (mojibake) prompt instead of the file's contents. (#437) * `ChatAnthropic()` no longer drops assistant turns that have no content; doing so could produce two consecutive user messages, violating the API's user/assistant alternation requirement. A `"[empty string]"` placeholder is sent instead, matching how empty text content is already normalized. (#416) -* `ChatMistral()` now reports `"context_window"` as the finish reason when a response stops with Mistral's `model_length` (the request reached the model's context length), instead of passing the raw string through. As for other providers, this makes chatlas warn about the truncated response (or raise an error when a data model was requested). +* `ChatMistral()` now reports `"context_window"` as the finish reason when a response stops with Mistral's `model_length` (the request reached the model's context length), instead of passing the raw string through. As for other providers, this makes chatlas warn about the truncated response (or raise an error when a data model was requested). (#477) ## [0.23.0] - 2026-09-04