diff --git a/litellm/llms/azure/chat/gpt_transformation.py b/litellm/llms/azure/chat/gpt_transformation.py index 438766fa52f..1e0877b46dd 100644 --- a/litellm/llms/azure/chat/gpt_transformation.py +++ b/litellm/llms/azure/chat/gpt_transformation.py @@ -175,46 +175,17 @@ class AzureOpenAIConfig(BaseConfig): else: optional_params["tool_choice"] = value elif param == "response_format" and isinstance(value, dict): - json_schema: Optional[dict] = None - if "response_schema" in value: - json_schema = value["response_schema"] - elif "json_schema" in value: - json_schema = value["json_schema"]["schema"] - """ - Follow similar approach to anthropic - translate to a single tool call. - - When using tools in this way: - https://docs.anthropic.com/en/docs/build-with-claude/tool-use#json-mode - - You usually want to provide a single tool - - You should set tool_choice (see Forcing tool use) to instruct the model to explicitly use that tool - - Remember that the model will pass the input to the tool, so the name of the tool and description should be from the model’s perspective. - """ _is_response_format_supported_model = ( self._is_response_format_supported_model(model) ) - if json_schema is not None and ( - (api_version_year <= "2024" and api_version_month < "08") - or not _is_response_format_supported_model - ): # azure api version "2024-08-01-preview" onwards supports 'json_schema' only for gpt-4o/3.5 models - - _tool_choice = ChatCompletionToolChoiceObjectParam( - type="function", - function=ChatCompletionToolChoiceFunctionParam( - name=RESPONSE_FORMAT_TOOL_NAME - ), - ) - - _tool = ChatCompletionToolParam( - type="function", - function=ChatCompletionToolParamFunctionChunk( - name=RESPONSE_FORMAT_TOOL_NAME, parameters=json_schema - ), - ) - - optional_params = self._add_response_format_to_tools( - optional_params, _tool, _tool_choice - ) - else: - optional_params["response_format"] = value + should_convert_response_format_to_tool = ( + api_version_year <= "2024" and api_version_month < "08" + ) or not _is_response_format_supported_model + optional_params = self._add_response_format_to_tools( + optional_params=optional_params, + value=value, + should_convert_response_format_to_tool=should_convert_response_format_to_tool, + ) elif param == "tools" and isinstance(value, list): optional_params.setdefault("tools", []) optional_params["tools"].extend(value) diff --git a/litellm/llms/base_llm/chat/transformation.py b/litellm/llms/base_llm/chat/transformation.py index 23aea313db0..daf8ff225ae 100644 --- a/litellm/llms/base_llm/chat/transformation.py +++ b/litellm/llms/base_llm/chat/transformation.py @@ -19,10 +19,13 @@ import httpx from pydantic import BaseModel from litellm._logging import verbose_logger +from litellm.constants import RESPONSE_FORMAT_TOOL_NAME from litellm.types.llms.openai import ( AllMessageValues, + ChatCompletionToolChoiceFunctionParam, ChatCompletionToolChoiceObjectParam, ChatCompletionToolParam, + ChatCompletionToolParamFunctionChunk, ) from litellm.types.utils import ModelResponse @@ -155,18 +158,48 @@ class BaseConfig(ABC): def _add_response_format_to_tools( self, optional_params: dict, - _tool: ChatCompletionToolParam, - _tool_choice: ChatCompletionToolChoiceObjectParam, + value: dict, + should_convert_response_format_to_tool: bool, ) -> dict: """ + Follow similar approach to anthropic - translate to a single tool call. + + When using tools in this way: - https://docs.anthropic.com/en/docs/build-with-claude/tool-use#json-mode + - You usually want to provide a single tool + - You should set tool_choice (see Forcing tool use) to instruct the model to explicitly use that tool + - Remember that the model will pass the input to the tool, so the name of the tool and description should be from the model’s perspective. + Add response format to tools This is used to translate response_format to a tool call, for models/APIs that don't support response_format directly. """ - optional_params.setdefault("tools", []) - optional_params["tools"].append(_tool) - optional_params["tool_choice"] = _tool_choice - optional_params["json_mode"] = True + json_schema: Optional[dict] = None + if "response_schema" in value: + json_schema = value["response_schema"] + elif "json_schema" in value: + json_schema = value["json_schema"]["schema"] + + if json_schema and should_convert_response_format_to_tool: + _tool_choice = ChatCompletionToolChoiceObjectParam( + type="function", + function=ChatCompletionToolChoiceFunctionParam( + name=RESPONSE_FORMAT_TOOL_NAME + ), + ) + + _tool = ChatCompletionToolParam( + type="function", + function=ChatCompletionToolParamFunctionChunk( + name=RESPONSE_FORMAT_TOOL_NAME, parameters=json_schema + ), + ) + + optional_params.setdefault("tools", []) + optional_params["tools"].append(_tool) + optional_params["tool_choice"] = _tool_choice + optional_params["json_mode"] = True + else: + optional_params["response_format"] = value return optional_params @abstractmethod