mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
fix(core): normalize uppercase types inside a JSON Schema type list
normalize_json_schema_types only lowercased `type` when it was a string, so
a list of types - the standard way to mark a field nullable, e.g.
["STRING", "NULL"] - fell through to the generic list recursion, which
returns bare strings untouched.
Providers that emit uppercase types therefore kept them on every nullable
field while sibling keys were normalized correctly:
normalize_tool_schema({"function": {"parameters": {
"type": "OBJECT",
"properties": {"x": {"type": ["STRING", "NULL"]}}}}})
# -> parameters.type == "object" but x.type == ["STRING", "NULL"]
Normalize each entry of a type list, leaving unrecognised entries alone.
Adds tests for this module, which had none.
This commit is contained in:
parent
ef2062cad3
commit
868608ed4b
2 changed files with 76 additions and 0 deletions
|
|
@ -52,6 +52,15 @@ def normalize_json_schema_types(
|
|||
for key, value in schema.items():
|
||||
if key == "type" and isinstance(value, str) and value in type_mapping:
|
||||
normalized_schema[key] = type_mapping[value]
|
||||
elif key == "type" and isinstance(value, list):
|
||||
# JSON Schema also allows a list of types, which is the usual way
|
||||
# to mark a field nullable (e.g. ["STRING", "NULL"]). Without this
|
||||
# branch those entries fall through to the generic list recursion,
|
||||
# which leaves the bare strings uppercase.
|
||||
normalized_schema[key] = [
|
||||
type_mapping.get(entry, entry) if isinstance(entry, str) else entry
|
||||
for entry in value
|
||||
]
|
||||
elif key == "properties" and isinstance(value, dict):
|
||||
# Recursively normalize properties
|
||||
normalized_schema[key] = {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
from litellm.litellm_core_utils.json_validation_rule import (
|
||||
normalize_json_schema_types,
|
||||
normalize_tool_schema,
|
||||
)
|
||||
|
||||
|
||||
def test_normalizes_a_plain_string_type():
|
||||
assert normalize_json_schema_types({"type": "STRING"}) == {"type": "string"}
|
||||
|
||||
|
||||
def test_normalizes_a_list_of_types():
|
||||
"""A list of types is how a nullable field is expressed.
|
||||
|
||||
Regression: these entries fell through to the generic list recursion, which
|
||||
returns bare strings untouched, so they stayed uppercase.
|
||||
"""
|
||||
assert normalize_json_schema_types({"type": ["STRING", "NULL"]}) == {
|
||||
"type": ["string", "null"]
|
||||
}
|
||||
|
||||
|
||||
def test_normalizes_a_list_of_types_when_nested():
|
||||
schema = {"properties": {"a": {"type": ["INTEGER", "NULL"]}}}
|
||||
|
||||
assert normalize_json_schema_types(schema) == {
|
||||
"properties": {"a": {"type": ["integer", "null"]}}
|
||||
}
|
||||
|
||||
|
||||
def test_leaves_unknown_type_entries_alone():
|
||||
assert normalize_json_schema_types({"type": ["STRING", "custom"]}) == {
|
||||
"type": ["string", "custom"]
|
||||
}
|
||||
|
||||
|
||||
def test_still_normalizes_properties_items_and_anyof():
|
||||
schema = {
|
||||
"type": "OBJECT",
|
||||
"properties": {"xs": {"type": "ARRAY", "items": {"type": "INTEGER"}}},
|
||||
"anyOf": [{"type": "STRING"}],
|
||||
}
|
||||
|
||||
assert normalize_json_schema_types(schema) == {
|
||||
"type": "object",
|
||||
"properties": {"xs": {"type": "array", "items": {"type": "integer"}}},
|
||||
"anyOf": [{"type": "string"}],
|
||||
}
|
||||
|
||||
|
||||
def test_tool_schema_normalizes_a_nullable_parameter():
|
||||
tool = {
|
||||
"function": {
|
||||
"parameters": {
|
||||
"type": "OBJECT",
|
||||
"properties": {"x": {"type": ["STRING", "NULL"]}},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert normalize_tool_schema(tool) == {
|
||||
"function": {
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {"x": {"type": ["string", "null"]}},
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue