From f880ea537f3dc44ce4a8e1f3a5e3ca25b24ae3c3 Mon Sep 17 00:00:00 2001 From: Rayan Pal <90289028+theonlypal@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:13:35 -0800 Subject: [PATCH] fix(vertex): add type object to tool schemas missing type field (#19103) Tools with no parameters (like EnterPlanMode from Anthropic Agents SDK) send schemas with only $schema and no type field. Gemini rejects these with "functionDeclaration parameters schema should be of type OBJECT". Adds type: object when schema has no type and no anyOf/oneOf/allOf. --- litellm/llms/vertex_ai/common_utils.py | 5 ++ .../vertex_ai/test_vertex_ai_common_utils.py | 62 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/litellm/llms/vertex_ai/common_utils.py b/litellm/llms/vertex_ai/common_utils.py index 2aa6a00c72b..1864ef734c0 100644 --- a/litellm/llms/vertex_ai/common_utils.py +++ b/litellm/llms/vertex_ai/common_utils.py @@ -655,6 +655,11 @@ def convert_anyof_null_to_nullable(schema, depth=0): def add_object_type(schema): + # Gemini requires all function parameters to be type OBJECT + # Handle case where schema has no properties and no type (e.g. tools with no arguments) + if "type" not in schema and "anyOf" not in schema and "oneOf" not in schema and "allOf" not in schema: + schema["type"] = "object" + properties = schema.get("properties", None) if properties is not None: if "required" in schema and schema["required"] is None: diff --git a/tests/test_litellm/llms/vertex_ai/test_vertex_ai_common_utils.py b/tests/test_litellm/llms/vertex_ai/test_vertex_ai_common_utils.py index b5637db3e52..bb810abc86e 100644 --- a/tests/test_litellm/llms/vertex_ai/test_vertex_ai_common_utils.py +++ b/tests/test_litellm/llms/vertex_ai/test_vertex_ai_common_utils.py @@ -1267,3 +1267,65 @@ def test_build_vertex_schema_empty_properties(): parent_schema = result["properties"]["action"]["items"]["anyOf"][0] assert parent_schema["type"] == "object", "Parent schema should still have object type" assert "go_back" in parent_schema["properties"], "go_back should still be in parent properties" + + +def test_add_object_type_schema_with_no_properties_and_no_type(): + """ + Test that add_object_type adds type: object when schema has no properties and no type. + Fixes issue where tools with no arguments (e.g. EnterPlanMode) fail on Gemini. + """ + from litellm.llms.vertex_ai.common_utils import add_object_type + + # Input: Schema with no properties and no type (the problematic case) + input_schema = { + "$schema": "https://json-schema.org/draft/2020-12/schema" + } + + # Apply the transformation + add_object_type(input_schema) + + # Verify type: object was added + assert input_schema.get("type") == "object", "type: object should be added" + + # Verify $schema is preserved + assert input_schema.get("$schema") == "https://json-schema.org/draft/2020-12/schema" + + +def test_add_object_type_does_not_override_existing_type(): + """ + Test add_object_type does not override existing type field. + """ + from litellm.llms.vertex_ai.common_utils import add_object_type + + # Input: Schema with existing type + input_schema = { + "type": "string", + "description": "A string field" + } + + # Apply the transformation + add_object_type(input_schema) + + # Verify type was not changed + assert input_schema.get("type") == "string", "Existing type should not be changed" + + +def test_add_object_type_does_not_add_type_when_anyof_present(): + """ + Test add_object_type does not add type: object when anyOf is present. + """ + from litellm.llms.vertex_ai.common_utils import add_object_type + + # Input: Schema with anyOf but no type + input_schema = { + "anyOf": [ + {"type": "string"}, + {"type": "null"} + ] + } + + # Apply the transformation + add_object_type(input_schema) + + # Verify type was not added (anyOf handles the type) + assert "type" not in input_schema, "type should not be added when anyOf is present"