Skip to content

Commit cbfb749

Browse files
yyyu-googlecopybara-github
authored andcommitted
feat!: remove automatic function calling from Models.generate_content, Models_generate_content_stream, AsyncModels.generate_content, and AsyncModels.generate_content_stream. Automatic Function Calling is only available in Chats.send_message, Chats.send_message_stream, AsyncChats.send_message, AsyncChats.send_message_stream.
PiperOrigin-RevId: 956021887
1 parent 49b730d commit cbfb749

31 files changed

Lines changed: 3111 additions & 6911 deletions

google/genai/_automatic_function_calling_util.py

Lines changed: 12 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
'_add_unevaluated_items_to_fixed_len_tuple_schema',
3939
'_is_builtin_primitive_or_compound',
4040
'_is_default_value_compatible',
41-
'_parse_schema_from_parameter',
4241
'_get_required_fields',
4342
]
4443

@@ -137,189 +136,16 @@ def _is_default_value_compatible(
137136
return False
138137

139138

140-
def _parse_schema_from_parameter( # type: ignore[return]
141-
api_option: Literal['VERTEX_AI', 'GEMINI_API'],
142-
param: inspect.Parameter,
143-
func_name: str,
144-
) -> types.Schema:
145-
"""parse schema from parameter.
146-
147-
from the simplest case to the most complex case.
148-
"""
149-
schema = types.Schema()
150-
default_value_error_msg = (
151-
f'Default value {param.default} of parameter {param} of function'
152-
f' {func_name} is not compatible with the parameter annotation'
153-
f' {param.annotation}.'
154-
)
155-
if _is_builtin_primitive_or_compound(param.annotation):
156-
if param.default is not inspect.Parameter.empty:
157-
if not _is_default_value_compatible(param.default, param.annotation):
158-
raise ValueError(default_value_error_msg)
159-
schema.default = param.default
160-
schema.type = _py_builtin_type_to_schema_type[param.annotation]
161-
return schema
162-
if (
163-
isinstance(param.annotation, VersionedUnionType)
164-
# only parse simple UnionType, example int | str | float | bool
165-
# complex UnionType will be invoked in raise branch
166-
and all(
167-
(_is_builtin_primitive_or_compound(arg) or arg is type(None))
168-
for arg in get_args(param.annotation)
169-
)
170-
):
171-
schema.type = _py_builtin_type_to_schema_type[dict]
172-
schema.any_of = []
173-
unique_types = set()
174-
for arg in get_args(param.annotation):
175-
if arg.__name__ == 'NoneType': # Optional type
176-
schema.nullable = True
177-
continue
178-
schema_in_any_of = _parse_schema_from_parameter(
179-
api_option,
180-
inspect.Parameter(
181-
'item', inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=arg
182-
),
183-
func_name,
184-
)
185-
if (
186-
schema_in_any_of.model_dump_json(exclude_none=True)
187-
not in unique_types
188-
):
189-
schema.any_of.append(schema_in_any_of)
190-
unique_types.add(schema_in_any_of.model_dump_json(exclude_none=True))
191-
if len(schema.any_of) == 1: # param: list | None -> Array
192-
schema.type = schema.any_of[0].type
193-
schema.any_of = None
194-
if (
195-
param.default is not inspect.Parameter.empty
196-
and param.default is not None
197-
):
198-
if not _is_default_value_compatible(param.default, param.annotation):
199-
raise ValueError(default_value_error_msg)
200-
schema.default = param.default
201-
return schema
202-
if isinstance(param.annotation, _GenericAlias) or isinstance(
203-
param.annotation, builtin_types.GenericAlias
204-
):
205-
origin = get_origin(param.annotation)
206-
args = get_args(param.annotation)
207-
if origin is dict:
208-
schema.type = _py_builtin_type_to_schema_type[dict]
209-
if param.default is not inspect.Parameter.empty:
210-
if not _is_default_value_compatible(param.default, param.annotation):
211-
raise ValueError(default_value_error_msg)
212-
schema.default = param.default
213-
return schema
214-
if origin is Literal:
215-
if not all(isinstance(arg, str) for arg in args):
216-
raise ValueError(
217-
f'Literal type {param.annotation} must be a list of strings.'
218-
)
219-
schema.type = _py_builtin_type_to_schema_type[str]
220-
schema.enum = list(args)
221-
if param.default is not inspect.Parameter.empty:
222-
if not _is_default_value_compatible(param.default, param.annotation):
223-
raise ValueError(default_value_error_msg)
224-
schema.default = param.default
225-
return schema
226-
if origin is list:
227-
schema.type = _py_builtin_type_to_schema_type[list]
228-
schema.items = _parse_schema_from_parameter(
229-
api_option,
230-
inspect.Parameter(
231-
'item',
232-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
233-
annotation=args[0],
234-
),
235-
func_name,
236-
)
237-
if param.default is not inspect.Parameter.empty:
238-
if not _is_default_value_compatible(param.default, param.annotation):
239-
raise ValueError(default_value_error_msg)
240-
schema.default = param.default
241-
return schema
242-
if origin is Union:
243-
schema.any_of = []
244-
schema.type = _py_builtin_type_to_schema_type[dict]
245-
unique_types = set()
246-
for arg in args:
247-
# The first check is for NoneType in Python 3.9, since the __name__
248-
# attribute is not available in Python 3.9
249-
if type(arg) is type(None) or (
250-
hasattr(arg, '__name__') and arg.__name__ == 'NoneType'
251-
): # Optional type
252-
schema.nullable = True
253-
continue
254-
schema_in_any_of = _parse_schema_from_parameter(
255-
api_option,
256-
inspect.Parameter(
257-
'item',
258-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
259-
annotation=arg,
260-
),
261-
func_name,
262-
)
263-
if (
264-
len(param.annotation.__args__) == 2
265-
and type(None) in param.annotation.__args__
266-
): # Optional type
267-
for optional_arg in param.annotation.__args__:
268-
if (
269-
hasattr(optional_arg, '__origin__')
270-
and optional_arg.__origin__ is list
271-
):
272-
# Optional type with list, for example Optional[list[str]]
273-
schema.items = schema_in_any_of.items
274-
if (
275-
schema_in_any_of.model_dump_json(exclude_none=True)
276-
not in unique_types
277-
):
278-
schema.any_of.append(schema_in_any_of)
279-
unique_types.add(schema_in_any_of.model_dump_json(exclude_none=True))
280-
if len(schema.any_of) == 1: # param: Union[List, None] -> Array
281-
schema.type = schema.any_of[0].type
282-
schema.any_of = None
283-
if (
284-
param.default is not None
285-
and param.default is not inspect.Parameter.empty
286-
):
287-
if not _is_default_value_compatible(param.default, param.annotation):
288-
raise ValueError(default_value_error_msg)
289-
schema.default = param.default
290-
return schema
291-
# all other generic alias will be invoked in raise branch
292-
if (
293-
# for user defined class, we only support pydantic model
294-
_extra_utils.is_annotation_pydantic_model(param.annotation)
295-
):
296-
if (
297-
param.default is not inspect.Parameter.empty
298-
and param.default is not None
299-
):
300-
schema.default = param.default
301-
schema.type = _py_builtin_type_to_schema_type[dict]
302-
schema.properties = {}
303-
for field_name, field_info in param.annotation.model_fields.items():
304-
schema.properties[field_name] = _parse_schema_from_parameter(
305-
api_option,
306-
inspect.Parameter(
307-
field_name,
308-
inspect.Parameter.POSITIONAL_OR_KEYWORD,
309-
annotation=field_info.annotation,
310-
),
311-
func_name,
312-
)
313-
schema.required = _get_required_fields(schema)
314-
return schema
315-
_raise_for_unsupported_param(param, func_name, ValueError)
316-
317-
318-
def _get_required_fields(schema: types.Schema) -> Optional[list[str]]:
319-
if not schema.properties:
139+
def _get_required_fields(json_schema: dict[str, Any]) -> Optional[list[str]]:
140+
properties = json_schema.get('properties', {})
141+
if not properties:
320142
return None
321-
return [
322-
field_name
323-
for field_name, field_schema in schema.properties.items()
324-
if not field_schema.nullable and field_schema.default is None
325-
]
143+
required_fields = []
144+
for field_name, field_schema in properties.items():
145+
if not field_schema:
146+
continue
147+
if 'nullable' in field_schema and not field_schema['nullable']:
148+
required_fields.append(field_name)
149+
if 'default' not in field_schema and field_name not in required_fields:
150+
required_fields.append(field_name)
151+
return required_fields

0 commit comments

Comments
 (0)