From 4f7f73b57ef07332ca83dc31342a9537f42878d8 Mon Sep 17 00:00:00 2001 From: Meryem Sakin Date: Thu, 10 Sep 2026 20:55:59 +0300 Subject: [PATCH] refactor(ollama): remove the JSON prompt tool-calling emulation With ollama/ tool requests going through /api/chat, nothing reaches the emulation anymore. The removed block in get_optional_params only ever ran for ollama (the long != chain was dead after its first == check), and it also flipped the global litellm.add_function_to_prompt on the first tool request. function_call_prompt mutated the caller's system message in place, so a reused message list picked up another copy of the prompt on every turn --- .../prompt_templates/factory.py | 21 -------- litellm/main.py | 7 --- litellm/utils.py | 48 ------------------- 3 files changed, 76 deletions(-) diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py index ece619e3883..e303a18962f 100644 --- a/litellm/litellm_core_utils/prompt_templates/factory.py +++ b/litellm/litellm_core_utils/prompt_templates/factory.py @@ -5130,27 +5130,6 @@ def _bedrock_tools_pt(tools: list, model: str | None = None) -> list[BedrockTool return tool_block_list -# Function call template -def function_call_prompt(messages: list, functions: list): - function_prompt = """Produce JSON OUTPUT ONLY! Adhere to this format {"name": "function_name", "arguments":{"argument_name": "argument_value"}} The following functions are available to you:""" - for function in functions: - function_prompt += f"""\n{function}\n""" - - function_added_to_prompt = False - for message in messages: - if "system" in message["role"]: - if isinstance(message["content"], str): - message["content"] += f""" {function_prompt}""" - else: - message["content"].append({"type": "text", "text": f""" {function_prompt}"""}) - function_added_to_prompt = True - - if function_added_to_prompt is False: - messages.append({"role": "system", "content": f"""{function_prompt}"""}) - - return messages - - def response_schema_prompt(model: str, response_schema: dict) -> str: """ Decides if a user-defined custom prompt or default needs to be used diff --git a/litellm/main.py b/litellm/main.py index 90a9961a384..d69b737ce04 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -180,7 +180,6 @@ from .litellm_core_utils.prompt_templates.common_utils import ( ) from .litellm_core_utils.prompt_templates.factory import ( custom_prompt, - function_call_prompt, map_system_message_pt, ollama_pt, prompt_factory, @@ -5467,12 +5466,6 @@ def completion( provider_config=provider_config, ) - if litellm.add_function_to_prompt and optional_params.get( - "functions_unsupported_model", None - ): # if user opts to add it to prompt, when API doesn't support function calling - functions_unsupported_model: Final = optional_params.pop("functions_unsupported_model") - messages = function_call_prompt(messages=messages, functions=functions_unsupported_model) - # For logging - save the values of the litellm-specific params passed in litellm_params = get_litellm_params( acompletion=acompletion, diff --git a/litellm/utils.py b/litellm/utils.py index 917af2b89d4..f13d2c80964 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -4098,54 +4098,6 @@ def pre_process_optional_params(passed_params: dict, non_default_params: dict, c non_default_params=passed_params, optional_params=optional_params ) - ## raise exception if function calling passed in for a provider that doesn't support it - if "functions" in non_default_params or "function_call" in non_default_params or "tools" in non_default_params: - if ( - custom_llm_provider == "ollama" - and custom_llm_provider != "text-completion-openai" - and custom_llm_provider != "azure" - and custom_llm_provider != "vertex_ai" - and custom_llm_provider != "anyscale" - and custom_llm_provider != "together_ai" - and custom_llm_provider != "groq" - and custom_llm_provider != "nvidia_nim" - and custom_llm_provider != "cerebras" - and custom_llm_provider != "xai" - and custom_llm_provider != "ai21_chat" - and custom_llm_provider != "volcengine" - and custom_llm_provider != "deepseek" - and custom_llm_provider != "codestral" - and custom_llm_provider != "mistral" - and custom_llm_provider != "anthropic" - and custom_llm_provider != "cohere_chat" - and custom_llm_provider != "cohere" - and custom_llm_provider != "bedrock" - and custom_llm_provider != "ollama_chat" - and custom_llm_provider != "openrouter" - and custom_llm_provider != "vercel_ai_gateway" - and custom_llm_provider != "nebius" - and custom_llm_provider != "wandb" - and custom_llm_provider not in litellm.openai_compatible_providers - ): - if custom_llm_provider == "ollama": - # ollama actually supports json output - optional_params["format"] = "json" - litellm.add_function_to_prompt = True # so that main.py adds the function call to the prompt - if "tools" in non_default_params: - optional_params["functions_unsupported_model"] = non_default_params.pop("tools") - non_default_params.pop("tool_choice", None) # causes ollama requests to hang - elif "functions" in non_default_params: - optional_params["functions_unsupported_model"] = non_default_params.pop("functions") - elif litellm.add_function_to_prompt: # if user opts to add it to prompt instead - optional_params["functions_unsupported_model"] = non_default_params.pop( - "tools", non_default_params.pop("functions", None) - ) - else: - raise UnsupportedParamsError( - status_code=500, - message=f"Function calling is not supported by {custom_llm_provider}.", - ) - return optional_params