From cfcd0cda8abda0cca045fef3fd2c2a6a6fa7f47e Mon Sep 17 00:00:00 2001 From: Mateo Wang <277851410+mateo-berri@users.noreply.github.com> Date: Wed, 12 Aug 2026 00:28:15 -0700 Subject: [PATCH] fix(responses): leave namespace unset on non-namespace tool calls --- .../transformation.py | 3 +- .../test_litellm_completion_responses.py | 58 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/litellm/responses/litellm_completion_transformation/transformation.py b/litellm/responses/litellm_completion_transformation/transformation.py index 2a253eae0ac..0377996021c 100644 --- a/litellm/responses/litellm_completion_transformation/transformation.py +++ b/litellm/responses/litellm_completion_transformation/transformation.py @@ -1708,7 +1708,8 @@ class LiteLLMCompletionResponsesConfig: type="function_call", status=function_definition.get("status") or "completed", ) - output_tool_call.namespace = namespace + if namespace: + output_tool_call.namespace = namespace # Pass through provider_specific_fields as-is if present if provider_specific_fields: diff --git a/tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py b/tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py index 6a89e02aac8..d3aa8eddf45 100644 --- a/tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py +++ b/tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py @@ -670,6 +670,64 @@ class TestLiteLLMCompletionResponsesConfig: assert tool_calls[0].namespace == "collaboration" assert tool_calls[0].arguments == '{"message":"hello"}' + def test_transform_chat_completion_response_plain_tool_call_has_no_namespace(self): + """A non-namespace function call must not gain a namespace attribute, matching + the streaming path which only sets it when a namespace was restored.""" + tool_call_id = "call_plain_no_namespace" + chat_completion_response = ModelResponse( + id="test-response-id", + created=1234567890, + model="gpt-4o", + object="chat.completion", + choices=[ + Choices( + finish_reason="tool_calls", + index=0, + message=Message( + content=None, + role="assistant", + tool_calls=[ + ChatCompletionMessageToolCall( + id=tool_call_id, + type="function", + function=Function( + name="get_weather", + arguments='{"city":"Paris"}', + ), + ) + ], + ), + ) + ], + ) + + try: + responses_api_response = LiteLLMCompletionResponsesConfig.transform_chat_completion_response_to_responses_api_response( + request_input="What is the weather in Paris?", + responses_api_request={ + "tools": [ + { + "type": "function", + "name": "get_weather", + "parameters": {"type": "object", "properties": {}}, + } + ] + }, + chat_completion_response=chat_completion_response, + ) + finally: + TOOL_CALLS_CACHE.delete_cache(key=tool_call_id) + + tool_calls = [ + item + for item in responses_api_response.output + if item.type == "function_call" + ] + assert len(tool_calls) == 1 + assert tool_calls[0].name == "get_weather" + assert tool_calls[0].namespace is None + assert "namespace" not in tool_calls[0].model_fields_set + def test_transform_top_level_function_collision_stays_unnamespaced(self): tool_call_id = "call_top_level_collision"