1010import outlines
1111
1212from google import genai
13+ from pydantic import BaseModel
1314
1415from ..exceptions import DataSetGeneratorError
1516from .errors import handle_provider_error
@@ -33,6 +34,71 @@ def _raise_generation_error(max_retries: int, error: Exception) -> None:
3334 raise DataSetGeneratorError (msg ) from error
3435
3536
37+ def _strip_additional_properties (schema_dict : dict ) -> dict :
38+ """
39+ Recursively remove additionalProperties from JSON schema.
40+
41+ Gemini doesn't support additionalProperties field in JSON schemas.
42+ This function strips it out from the schema and all nested definitions.
43+
44+ Args:
45+ schema_dict: JSON schema dictionary
46+
47+ Returns:
48+ Modified schema dict without additionalProperties
49+ """
50+ if not isinstance (schema_dict , dict ):
51+ return schema_dict
52+
53+ # Remove additionalProperties from current level
54+ schema_dict .pop ("additionalProperties" , None )
55+
56+ # Recursively process nested structures
57+ if "$defs" in schema_dict :
58+ for def_name , def_schema in schema_dict ["$defs" ].items ():
59+ schema_dict ["$defs" ][def_name ] = _strip_additional_properties (def_schema )
60+
61+ # Process properties
62+ if "properties" in schema_dict :
63+ for prop_name , prop_schema in schema_dict ["properties" ].items ():
64+ schema_dict ["properties" ][prop_name ] = _strip_additional_properties (prop_schema )
65+
66+ # Process items (for arrays)
67+ if "items" in schema_dict :
68+ schema_dict ["items" ] = _strip_additional_properties (schema_dict ["items" ])
69+
70+ return schema_dict
71+
72+
73+ def _create_gemini_compatible_schema (schema : type [BaseModel ]) -> type [BaseModel ]:
74+ """
75+ Create a Gemini-compatible version of a Pydantic schema.
76+
77+ Gemini doesn't support additionalProperties. This function creates a wrapper
78+ that generates schemas without this field.
79+
80+ Args:
81+ schema: Original Pydantic model
82+
83+ Returns:
84+ Wrapper model that generates Gemini-compatible schemas
85+ """
86+ # Create a new model class that overrides model_json_schema
87+ class GeminiCompatModel (schema ): # type: ignore[misc,valid-type]
88+ @classmethod
89+ def model_json_schema (cls , ** kwargs ):
90+ # Get the original schema
91+ original_schema = super ().model_json_schema (** kwargs )
92+ # Strip additionalProperties
93+ return _strip_additional_properties (original_schema )
94+
95+ # Set name and docstring
96+ GeminiCompatModel .__name__ = f"{ schema .__name__ } GeminiCompat"
97+ GeminiCompatModel .__doc__ = schema .__doc__
98+
99+ return GeminiCompatModel
100+
101+
36102def make_outlines_model (provider : str , model_name : str , ** kwargs ) -> Any :
37103 """Create an Outlines model for the specified provider and model.
38104
@@ -170,12 +236,18 @@ def generate(self, prompt: str, schema: Any, max_retries: int = 3, **kwargs) ->
170236 # Convert provider-specific parameters
171237 kwargs = self ._convert_generation_params (** kwargs )
172238
239+ # For Gemini, use compatible schema without additionalProperties
240+ generation_schema = schema
241+ if self .provider == "gemini" and isinstance (schema , type ) and issubclass (schema , BaseModel ):
242+ generation_schema = _create_gemini_compatible_schema (schema )
243+
173244 for attempt in range (max_retries ):
174245 try :
175246 # Generate JSON string with Outlines using the schema as output type
176- json_output = self .model (prompt , schema , ** kwargs )
247+ json_output = self .model (prompt , generation_schema , ** kwargs )
177248
178- # Parse and validate the JSON response with Pydantic
249+ # Parse and validate the JSON response with the ORIGINAL schema
250+ # This ensures we still get proper validation
179251 return schema .model_validate_json (json_output )
180252
181253 except Exception as e :
@@ -198,9 +270,15 @@ async def generate_async(self, prompt: str, schema: Any, max_retries: int = 3, *
198270 last_error : Exception | None = None
199271 kwargs = self ._convert_generation_params (** kwargs )
200272
273+ # For Gemini, use compatible schema without additionalProperties
274+ generation_schema = schema
275+ if self .provider == "gemini" and isinstance (schema , type ) and issubclass (schema , BaseModel ):
276+ generation_schema = _create_gemini_compatible_schema (schema )
277+
201278 for attempt in range (max_retries ):
202279 try :
203- json_output = await self .async_model (prompt , schema , ** kwargs )
280+ json_output = await self .async_model (prompt , generation_schema , ** kwargs )
281+ # Validate with original schema to ensure proper validation
204282 return schema .model_validate_json (json_output )
205283 except Exception as e :
206284 last_error = e
0 commit comments