Skip to content

Commit 057c611

Browse files
committed
fix(models): Correctly serialize nested schema types in LiteLlm adapter
Fixes conversion of Gemini Type enums within the recursive _schema_to_dict function to ensure valid JSON Schema types ('string', 'object', etc.) are generated, resolving errors with complex tools like Google Calendar. Fixes google#171
1 parent b691904 commit 057c611

File tree

1 file changed

+43
-37
lines changed

1 file changed

+43
-37
lines changed

src/google/adk/models/lite_llm.py

+43-37
Original file line numberDiff line numberDiff line change
@@ -262,48 +262,54 @@ def _to_litellm_role(role: Optional[str]) -> Literal["user", "assistant"]:
262262

263263

264264
TYPE_LABELS = {
265-
"STRING": "string",
266-
"NUMBER": "number",
267-
"BOOLEAN": "boolean",
268-
"OBJECT": "object",
269-
"ARRAY": "array",
270-
"INTEGER": "integer",
265+
types.Type.STRING: "string",
266+
types.Type.NUMBER: "number",
267+
types.Type.BOOLEAN: "boolean",
268+
types.Type.OBJECT: "object",
269+
types.Type.ARRAY: "array",
270+
types.Type.INTEGER: "integer",
271+
types.Type.TYPE_UNSPECIFIED: "null",
271272
}
272273

273-
274274
def _schema_to_dict(schema: types.Schema) -> dict:
275-
"""Recursively converts a types.Schema to a dictionary.
276-
277-
Args:
278-
schema: The schema to convert.
275+
"""Recursively converts a types.Schema to a JSON schema compliant dictionary."""
279276

280-
Returns:
281-
The dictionary representation of the schema.
282-
"""
277+
result_dict = {}
283278

284-
schema_dict = schema.model_dump(exclude_none=True)
285-
if "type" in schema_dict:
286-
schema_dict["type"] = schema_dict["type"].lower()
287-
if "items" in schema_dict:
288-
if isinstance(schema_dict["items"], dict):
289-
schema_dict["items"] = _schema_to_dict(
290-
types.Schema.model_validate(schema_dict["items"])
291-
)
292-
elif isinstance(schema_dict["items"]["type"], types.Type):
293-
schema_dict["items"]["type"] = TYPE_LABELS[
294-
schema_dict["items"]["type"].value
295-
]
296-
if "properties" in schema_dict:
297-
properties = {}
298-
for key, value in schema_dict["properties"].items():
299-
if isinstance(value, types.Schema):
300-
properties[key] = _schema_to_dict(value)
301-
else:
302-
properties[key] = value
303-
if "type" in properties[key]:
304-
properties[key]["type"] = properties[key]["type"].lower()
305-
schema_dict["properties"] = properties
306-
return schema_dict
279+
schema_type = getattr(schema, 'type', types.Type.TYPE_UNSPECIFIED)
280+
if isinstance(schema_type, types.Type):
281+
result_dict['type'] = TYPE_LABELS.get(schema_type, "null")
282+
else:
283+
result_dict['type'] = str(schema_type).lower() if schema_type else "null"
284+
285+
dumped = schema.model_dump(exclude={'type', 'items', 'properties'}, exclude_none=True)
286+
result_dict.update(dumped)
287+
288+
if result_dict.get('type') == 'array':
289+
items_schema = getattr(schema, 'items', None)
290+
if isinstance(items_schema, types.Schema):
291+
result_dict['items'] = _schema_to_dict(items_schema) # Рекурсия
292+
elif isinstance(items_schema, dict):
293+
if 'type' in items_schema and isinstance(items_schema['type'], types.Type):
294+
items_schema['type'] = TYPE_LABELS.get(items_schema['type'], "null")
295+
result_dict['items'] = items_schema
296+
297+
if result_dict.get('type') == 'object':
298+
properties_schema = getattr(schema, 'properties', None)
299+
if isinstance(properties_schema, dict):
300+
converted_properties = {}
301+
for key, value_schema in properties_schema.items():
302+
if isinstance(value_schema, types.Schema):
303+
converted_properties[key] = _schema_to_dict(value_schema)
304+
elif isinstance(value_schema, dict):
305+
if 'type' in value_schema and isinstance(value_schema['type'], types.Type):
306+
value_schema['type'] = TYPE_LABELS.get(value_schema['type'], "null")
307+
converted_properties[key] = value_schema
308+
result_dict['properties'] = converted_properties
309+
required_list = getattr(schema, 'required', None)
310+
if required_list:
311+
result_dict['required'] = required_list
312+
return result_dict
307313

308314

309315
def _function_declaration_to_tool_param(

0 commit comments

Comments
 (0)