diff --git a/litellm/llms/openai/chat/gpt_transformation.py b/litellm/llms/openai/chat/gpt_transformation.py index 4d7ef833181..e4a7c56ec7a 100644 --- a/litellm/llms/openai/chat/gpt_transformation.py +++ b/litellm/llms/openai/chat/gpt_transformation.py @@ -690,7 +690,11 @@ class OpenAIGPTConfig(BaseLLMModelInfo, BaseConfig): json_mode_content_str: str | None = str(new_tool_calls[0]["function"].get("arguments", "")) or None if json_mode_content_str is not None: translated_message = Message(content=json_mode_content_str) - finish_reason = "stop" + finish_reason = ( + "stop" + if choice["finish_reason"] in ("tool_calls", "function_call") + else choice["finish_reason"] + ) if translated_message is None: ## get the reasoning content @@ -719,7 +723,7 @@ class OpenAIGPTConfig(BaseLLMModelInfo, BaseConfig): ) translated_choice.finish_reason = map_finish_reason( - self._get_finish_reason(translated_message, choice["finish_reason"]) + self._get_finish_reason(translated_message, finish_reason) ) transformed_choices.append(translated_choice) diff --git a/tests/unit/llms/openai/chat/test_openai_gpt_transformation.py b/tests/unit/llms/openai/chat/test_openai_gpt_transformation.py index 76faf338307..8e3cfa56fbe 100644 --- a/tests/unit/llms/openai/chat/test_openai_gpt_transformation.py +++ b/tests/unit/llms/openai/chat/test_openai_gpt_transformation.py @@ -1793,3 +1793,43 @@ class TestToolSchemaCombinatorFlatteningForOpenAI: ) assert request["tools"][0] is tool + + +@pytest.mark.parametrize( + "provider_finish_reason, expected_finish_reason", + [ + ("tool_calls", "stop"), + ("function_call", "stop"), + ("length", "length"), + ("stop", "stop"), + ], +) +def test_transform_choices_json_mode_reports_stop_only_for_tool_call_reasons( + provider_finish_reason, expected_finish_reason +): + """json_mode folds a tool call into JSON content. Only tool-call reasons become + 'stop'; a truncated ('length') or already-final reason must survive untouched.""" + choice = [ + { + "finish_reason": provider_finish_reason, + "index": 0, + "logprobs": None, + "message": { + "content": None, + "role": "assistant", + "tool_calls": [ + { + "id": "call_1", + "type": "function", + "function": {"name": "json_tool_call", "arguments": '{"a": 1}'}, + } + ], + }, + } + ] + + out = OpenAIGPTConfig()._transform_choices(choices=choice, json_mode=True) + + assert out[0].message.content == '{"a": 1}' + assert out[0].message.tool_calls is None + assert out[0].finish_reason == expected_finish_reason