fix: Fix issue with MCP tools throwing an error

Fixes: https://github.com/google/adk-python/issues/3082
PiperOrigin-RevId: 824620839
This commit is contained in:
Google Team Member
2025-10-27 12:07:11 -07:00
committed by Copybara-Service
parent 36ca4f1204
commit 1a4261ad4b
2 changed files with 54 additions and 14 deletions
+14 -12
View File
@@ -75,20 +75,15 @@ def _to_snake_case(text: str) -> str:
def _sanitize_schema_type(schema: dict[str, Any]) -> dict[str, Any]:
if ("type" not in schema or not schema["type"]) and schema.keys().isdisjoint(
schema
):
if not schema:
schema["type"] = "object"
if isinstance(schema.get("type"), list):
nullable = False
non_null_type = None
for t in schema["type"]:
if t == "null":
nullable = True
elif not non_null_type:
non_null_type = t
if not non_null_type:
non_null_type = "object"
types_no_null = [t for t in schema["type"] if t != "null"]
nullable = len(types_no_null) != len(schema["type"])
if "array" in types_no_null:
non_null_type = "array"
else:
non_null_type = types_no_null[0] if types_no_null else "object"
if nullable:
schema["type"] = [non_null_type, "null"]
else:
@@ -96,6 +91,13 @@ def _sanitize_schema_type(schema: dict[str, Any]) -> dict[str, Any]:
elif schema.get("type") == "null":
schema["type"] = ["object", "null"]
schema_type = schema.get("type")
is_array = schema_type == "array" or (
isinstance(schema_type, list) and "array" in schema_type
)
if is_array and "items" not in schema:
schema["items"] = {"type": "string"}
return schema
@@ -68,6 +68,11 @@ class TestToGeminiSchema:
"object_nullable": {"type": "null"},
"multi_types_nullable": {"type": ["string", "null", "integer"]},
"empty_default_object": {},
"empty_list_type": {"type": []},
"multi_type_with_array_nullable": {
"type": ["string", "array", "null"]
},
"multi_type_with_array_nonnullable": {"type": ["integer", "array"]},
},
}
gemini_schema = _to_gemini_schema(openapi_schema)
@@ -93,6 +98,23 @@ class TestToGeminiSchema:
assert gemini_schema.properties["empty_default_object"].type == Type.OBJECT
assert gemini_schema.properties["empty_default_object"].nullable is None
assert gemini_schema.properties["empty_list_type"].type == Type.OBJECT
assert not gemini_schema.properties["empty_list_type"].nullable
assert (
gemini_schema.properties["multi_type_with_array_nullable"].type
== Type.ARRAY
)
assert gemini_schema.properties["multi_type_with_array_nullable"].nullable
assert (
gemini_schema.properties["multi_type_with_array_nonnullable"].type
== Type.ARRAY
)
assert not gemini_schema.properties[
"multi_type_with_array_nonnullable"
].nullable
def test_to_gemini_schema_nested_objects(self):
openapi_schema = {
"type": "object",
@@ -137,6 +159,20 @@ class TestToGeminiSchema:
gemini_schema = _to_gemini_schema(openapi_schema)
assert gemini_schema.items.properties["name"].type == Type.STRING
def test_to_gemini_schema_array_without_items_gets_default(self):
openapi_schema = {"type": "array"}
gemini_schema = _to_gemini_schema(openapi_schema)
assert gemini_schema.type == Type.ARRAY
assert not gemini_schema.nullable
assert gemini_schema.items.type == Type.STRING
def test_to_gemini_schema_nullable_array_without_items_gets_default(self):
openapi_schema = {"type": ["array", "null"]}
gemini_schema = _to_gemini_schema(openapi_schema)
assert gemini_schema.type == Type.ARRAY
assert gemini_schema.nullable
assert gemini_schema.items.type == Type.STRING
def test_to_gemini_schema_any_of(self):
openapi_schema = {
"anyOf": [{"type": "string"}, {"type": "integer"}],
@@ -533,8 +569,10 @@ class TestToGeminiSchema:
"type": "string",
},
"next_page_token": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": None,
"any_of": [
{"type": "string"},
{"type": ["object", "null"]},
],
"description": (
"The nextPageToken to fetch the next page of results."
),