22#
33# SPDX-License-Identifier: Apache-2.0
44
5- from typing import Any , Dict , List , Optional , Union
5+ from typing import Any , Dict , List , Optional
66
77from haystack import component , default_to_dict , logging
88from haystack .components .generators .chat import OpenAIChatGenerator
99from haystack .dataclasses import ChatMessage , StreamingCallbackT
10- from haystack .tools import Tool , Toolset , _check_duplicate_tool_names
10+ from haystack .tools import ToolsType , _check_duplicate_tool_names , flatten_tools_or_toolsets , serialize_tools_or_toolset
1111from haystack .utils import serialize_callable
1212from haystack .utils .auth import Secret
1313
@@ -66,7 +66,7 @@ def __init__(
6666 streaming_callback : Optional [StreamingCallbackT ] = None ,
6767 api_base_url : Optional [str ] = "https://api.aimlapi.com/v1" ,
6868 generation_kwargs : Optional [Dict [str , Any ]] = None ,
69- tools : Optional [Union [ List [ Tool ], Toolset ] ] = None ,
69+ tools : Optional [ToolsType ] = None ,
7070 timeout : Optional [float ] = None ,
7171 extra_headers : Optional [Dict [str , Any ]] = None ,
7272 max_retries : Optional [int ] = None ,
@@ -144,7 +144,7 @@ def to_dict(self) -> Dict[str, Any]:
144144 api_base_url = self .api_base_url ,
145145 generation_kwargs = self .generation_kwargs ,
146146 api_key = self .api_key .to_dict (),
147- tools = [ tool . to_dict () for tool in self .tools ] if self . tools else None ,
147+ tools = serialize_tools_or_toolset ( self .tools ) ,
148148 extra_headers = self .extra_headers ,
149149 timeout = self .timeout ,
150150 max_retries = self .max_retries ,
@@ -157,7 +157,7 @@ def _prepare_api_call(
157157 messages : List [ChatMessage ],
158158 streaming_callback : Optional [StreamingCallbackT ] = None ,
159159 generation_kwargs : Optional [Dict [str , Any ]] = None ,
160- tools : Optional [Union [ List [ Tool ], Toolset ] ] = None ,
160+ tools : Optional [ToolsType ] = None ,
161161 tools_strict : Optional [bool ] = None ,
162162 ) -> Dict [str , Any ]:
163163 # update generation kwargs by merging with the generation kwargs passed to the run method
@@ -167,32 +167,45 @@ def _prepare_api_call(
167167 # adapt ChatMessage(s) to the format expected by the OpenAI API (AIMLAPI uses the same format)
168168 aimlapi_formatted_messages : List [Dict [str , Any ]] = [message .to_openai_dict_format () for message in messages ]
169169
170- tools = tools or self .tools
171- if isinstance (tools , Toolset ):
172- tools = list (tools )
173170 tools_strict = tools_strict if tools_strict is not None else self .tools_strict
174- _check_duplicate_tool_names (list (tools or []))
175-
176- aimlapi_tools = {}
177- if tools :
178- tool_definitions = [
179- {"type" : "function" , "function" : {** t .tool_spec , ** ({"strict" : tools_strict } if tools_strict else {})}}
180- for t in tools
181- ]
182- aimlapi_tools = {"tools" : tool_definitions }
171+ flattened_tools = flatten_tools_or_toolsets (tools or self .tools )
172+ _check_duplicate_tool_names (flattened_tools )
173+
174+ openai_tools = {}
175+ if flattened_tools :
176+ tool_definitions = []
177+ for tool in flattened_tools :
178+ function_spec = {** tool .tool_spec }
179+ if tools_strict :
180+ function_spec ["strict" ] = True
181+ parameters = function_spec .get ("parameters" )
182+ if isinstance (parameters , dict ):
183+ parameters ["additionalProperties" ] = False
184+ tool_definitions .append ({"type" : "function" , "function" : function_spec })
185+ openai_tools = {"tools" : tool_definitions }
183186
184187 is_streaming = streaming_callback is not None
185188 num_responses = generation_kwargs .pop ("n" , 1 )
189+
186190 if is_streaming and num_responses > 1 :
187191 msg = "Cannot stream multiple responses, please set n=1."
188192 raise ValueError (msg )
193+ response_format = generation_kwargs .pop ("response_format" , None )
189194
190- return {
195+ response_format = generation_kwargs .pop ("response_format" , None )
196+
197+ base_args = {
191198 "model" : self .model ,
192199 "messages" : aimlapi_formatted_messages ,
193- "stream" : streaming_callback is not None ,
194200 "n" : num_responses ,
195- ** aimlapi_tools ,
201+ ** openai_tools ,
196202 "extra_body" : {** generation_kwargs },
197203 "extra_headers" : {** extra_headers },
198204 }
205+ if response_format and not is_streaming :
206+ return {** base_args , "response_format" : response_format , "openai_endpoint" : "parse" }
207+
208+ final_args = {** base_args , "stream" : is_streaming , "openai_endpoint" : "create" }
209+ if response_format :
210+ final_args ["response_format" ] = response_format
211+ return final_args
0 commit comments