Revert "fix #9783: Retain schema field ordering for google gemini and vertex …" (#10038)

This reverts commit e3729f9855.
This commit is contained in:
Krish Dholakia 2025-04-15 19:21:33 -07:00 committed by GitHub
parent e3729f9855
commit d3e7a137ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 6 additions and 198 deletions

View file

@ -165,18 +165,9 @@ def _check_text_in_content(parts: List[PartType]) -> bool:
return has_text_param
def _build_vertex_schema(parameters: dict, add_property_ordering: bool = False):
def _build_vertex_schema(parameters: dict):
"""
This is a modified version of https://github.com/google-gemini/generative-ai-python/blob/8f77cc6ac99937cd3a81299ecf79608b91b06bbb/google/generativeai/types/content_types.py#L419
Updates the input parameters, removing extraneous fields, adjusting types, unwinding $defs, and adding propertyOrdering if specified, returning the updated parameters.
Parameters:
parameters: dict - the json schema to build from
add_property_ordering: bool - whether to add propertyOrdering to the schema. This is only applicable to schemas for structured outputs. See
set_schema_property_ordering for more details.
Returns:
parameters: dict - the input parameters, modified in place
"""
# Get valid fields from Schema TypedDict
valid_schema_fields = set(get_type_hints(Schema).keys())
@ -195,31 +186,8 @@ def _build_vertex_schema(parameters: dict, add_property_ordering: bool = False):
add_object_type(parameters)
# Postprocessing
# Filter out fields that don't exist in Schema
parameters = filter_schema_fields(parameters, valid_schema_fields)
if add_property_ordering:
set_schema_property_ordering(parameters)
return parameters
def set_schema_property_ordering(schema: Dict[str, Any]) -> Dict[str, Any]:
"""
vertex ai and generativeai apis order output of fields alphabetically, unless you specify the order.
python dicts retain order, so we just use that. Note that this field only applies to structured outputs, and not tools.
Function tools are not afflicted by the same alphabetical ordering issue, (the order of keys returned seems to be arbitrary, up to the model)
https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.cachedContents#Schema.FIELDS.property_ordering
"""
if "properties" in schema and isinstance(schema["properties"], dict):
# retain propertyOrdering as an escape hatch if user already specifies it
if "propertyOrdering" not in schema:
schema["propertyOrdering"] = [k for k, v in schema["properties"].items()]
for k, v in schema["properties"].items():
set_schema_property_ordering(v)
if "items" in schema:
set_schema_property_ordering(schema["items"])
return schema
filtered_parameters = filter_schema_fields(parameters, valid_schema_fields)
return filtered_parameters
def filter_schema_fields(

View file

@ -207,7 +207,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
"extra_headers",
"seed",
"logprobs",
"top_logprobs",
"top_logprobs", # Added this to list of supported openAI params
"modalities",
]
@ -313,10 +313,9 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
if isinstance(old_schema, list):
for item in old_schema:
if isinstance(item, dict):
item = _build_vertex_schema(parameters=item, add_property_ordering=True)
item = _build_vertex_schema(parameters=item)
elif isinstance(old_schema, dict):
old_schema = _build_vertex_schema(parameters=old_schema, add_property_ordering=True)
old_schema = _build_vertex_schema(parameters=old_schema)
return old_schema
def apply_response_schema_transformation(self, value: dict, optional_params: dict):

View file

@ -9,8 +9,6 @@ from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
VertexGeminiConfig,
)
from litellm.types.utils import ChoiceLogprobs
from pydantic import BaseModel
from typing import List, cast
def test_top_logprobs():
@ -64,160 +62,3 @@ def test_get_model_name_from_gemini_spec_model():
model = "gemini/ft-uuid-123"
result = VertexGeminiConfig._get_model_name_from_gemini_spec_model(model)
assert result == "ft-uuid-123"
def test_vertex_ai_response_schema_dict():
v = VertexGeminiConfig()
transformed_request = v.map_openai_params(
non_default_params={
"messages": [{"role": "user", "content": "Hello, world!"}],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "math_reasoning",
"schema": {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"thought": {"type": "string"},
"output": {"type": "string"},
},
"required": ["thought", "output"],
"additionalProperties": False,
},
},
"final_answer": {"type": "string"},
},
"required": ["steps", "final_answer"],
"additionalProperties": False,
},
"strict": False,
},
},
},
optional_params={},
model="gemini-2.0-flash-lite",
drop_params=False,
)
schema = transformed_request["response_schema"]
# should add propertyOrdering
assert schema["propertyOrdering"] == ["steps", "final_answer"]
# should add propertyOrdering (recursively, including array items)
assert schema["properties"]["steps"]["items"]["propertyOrdering"] == [
"thought",
"output",
]
# should strip strict and additionalProperties
assert "strict" not in schema
assert "additionalProperties" not in schema
# validate the whole thing to catch regressions
assert transformed_request["response_schema"] == {
"type": "object",
"properties": {
"steps": {
"type": "array",
"items": {
"type": "object",
"properties": {
"thought": {"type": "string"},
"output": {"type": "string"},
},
"required": ["thought", "output"],
"propertyOrdering": ["thought", "output"],
},
},
"final_answer": {"type": "string"},
},
"required": ["steps", "final_answer"],
"propertyOrdering": ["steps", "final_answer"],
}
class MathReasoning(BaseModel):
steps: List["Step"]
final_answer: str
class Step(BaseModel):
thought: str
output: str
def test_vertex_ai_response_schema_defs():
v = VertexGeminiConfig()
schema = cast(dict, v.get_json_schema_from_pydantic_object(MathReasoning))
# pydantic conversion by default adds $defs to the schema, make sure this is still the case, otherwise this test isn't really testing anything
assert "$defs" in schema["json_schema"]["schema"]
transformed_request = v.map_openai_params(
non_default_params={
"messages": [{"role": "user", "content": "Hello, world!"}],
"response_format": schema,
},
optional_params={},
model="gemini-2.0-flash-lite",
drop_params=False,
)
assert "$defs" not in transformed_request["response_schema"]
assert transformed_request["response_schema"] == {
"title": "MathReasoning",
"type": "object",
"properties": {
"steps": {
"title": "Steps",
"type": "array",
"items": {
"title": "Step",
"type": "object",
"properties": {
"thought": {"title": "Thought", "type": "string"},
"output": {"title": "Output", "type": "string"},
},
"required": ["thought", "output"],
"propertyOrdering": ["thought", "output"],
},
},
"final_answer": {"title": "Final Answer", "type": "string"},
},
"required": ["steps", "final_answer"],
"propertyOrdering": ["steps", "final_answer"],
}
def test_vertex_ai_retain_property_ordering():
v = VertexGeminiConfig()
transformed_request = v.map_openai_params(
non_default_params={
"messages": [{"role": "user", "content": "Hello, world!"}],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "math_reasoning",
"schema": {
"type": "object",
"properties": {
"output": {"type": "string"},
"thought": {"type": "string"},
},
"propertyOrdering": ["thought", "output"],
},
},
},
},
optional_params={},
model="gemini-2.0-flash-lite",
drop_params=False,
)
schema = transformed_request["response_schema"]
# should leave existing value alone, despite dictionary ordering
assert schema["propertyOrdering"] == ["thought", "output"]