diff --git a/haystack/components/generators/chat/openai.py b/haystack/components/generators/chat/openai.py index 251b0b741c..0b699e3bc1 100644 --- a/haystack/components/generators/chat/openai.py +++ b/haystack/components/generators/chat/openai.py @@ -286,12 +286,13 @@ def _prepare_api_call( # noqa: PLR0913 tools_strict = tools_strict if tools_strict is not None else self.tools_strict _check_duplicate_tool_names(tools) - openai_tools = None + openai_tools = {} if tools: - openai_tools = [ + tool_definitions = [ {"type": "function", "function": {**t.tool_spec, **({"strict": tools_strict} if tools_strict else {})}} for t in tools ] + openai_tools = {"tools": tool_definitions} is_streaming = streaming_callback is not None num_responses = generation_kwargs.pop("n", 1) @@ -302,8 +303,8 @@ def _prepare_api_call( # noqa: PLR0913 "model": self.model, "messages": openai_formatted_messages, # type: ignore[arg-type] # openai expects list of specific message types "stream": streaming_callback is not None, - "tools": openai_tools, # type: ignore[arg-type] "n": num_responses, + **openai_tools, **generation_kwargs, } diff --git a/releasenotes/notes/do-not-pass-tools-to-openai-if-none-1fe09e924e7fad7a.yaml b/releasenotes/notes/do-not-pass-tools-to-openai-if-none-1fe09e924e7fad7a.yaml new file mode 100644 index 0000000000..aa309098fa --- /dev/null +++ b/releasenotes/notes/do-not-pass-tools-to-openai-if-none-1fe09e924e7fad7a.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + OpenAIChatGenerator no longer passes tools to the OpenAI client if none are provided. + Previously, a null value was passed. + This change improves compatibility with OpenAI-compatible APIs that do not support tools. diff --git a/test/components/generators/chat/test_openai.py b/test/components/generators/chat/test_openai.py index 8333608ea6..eb50d92739 100644 --- a/test/components/generators/chat/test_openai.py +++ b/test/components/generators/chat/test_openai.py @@ -293,6 +293,9 @@ def test_run_with_params(self, chat_messages, openai_mock_chat_completion): assert kwargs["max_tokens"] == 10 assert kwargs["temperature"] == 0.5 + # check that the tools are not passed to the OpenAI API (the generator is initialized without tools) + assert "tools" not in kwargs + # check that the component returns the correct response assert isinstance(response, dict) assert "replies" in response @@ -400,9 +403,14 @@ def test_run_with_tools(self, tools): mock_chat_completion_create.return_value = completion - component = OpenAIChatGenerator(api_key=Secret.from_token("test-api-key"), tools=tools) + component = OpenAIChatGenerator(api_key=Secret.from_token("test-api-key"), tools=tools, tools_strict=True) response = component.run([ChatMessage.from_user("What's the weather like in Paris?")]) + # ensure that the tools are passed to the OpenAI API + assert mock_chat_completion_create.call_args[1]["tools"] == [ + {"type": "function", "function": {**tools[0].tool_spec, "strict": True}} + ] + assert len(response["replies"]) == 1 message = response["replies"][0]