diff --git a/google/genai/caches.py b/google/genai/caches.py index 75579f57..660acd95 100644 --- a/google/genai/caches.py +++ b/google/genai/caches.py @@ -283,33 +283,6 @@ def _FunctionCallingConfig_to_mldev( return to_object -def _LatLng_to_mldev( - api_client: BaseApiClient, - from_object: Union[dict[str, Any], object], - parent_object: Optional[dict[str, Any]] = None, -) -> dict[str, Any]: - to_object: dict[str, Any] = {} - if getv(from_object, ['latitude']) is not None: - raise ValueError('latitude parameter is not supported in Gemini API.') - - if getv(from_object, ['longitude']) is not None: - raise ValueError('longitude parameter is not supported in Gemini API.') - - return to_object - - -def _RetrievalConfig_to_mldev( - api_client: BaseApiClient, - from_object: Union[dict[str, Any], object], - parent_object: Optional[dict[str, Any]] = None, -) -> dict[str, Any]: - to_object: dict[str, Any] = {} - if getv(from_object, ['lat_lng']) is not None: - raise ValueError('lat_lng parameter is not supported in Gemini API.') - - return to_object - - def _ToolConfig_to_mldev( api_client: BaseApiClient, from_object: Union[dict[str, Any], object], @@ -328,8 +301,8 @@ def _ToolConfig_to_mldev( ) if getv(from_object, ['retrieval_config']) is not None: - raise ValueError( - 'retrieval_config parameter is not supported in Gemini API.' + setv( + to_object, ['retrievalConfig'], getv(from_object, ['retrieval_config']) ) return to_object @@ -815,39 +788,6 @@ def _FunctionCallingConfig_to_vertex( return to_object -def _LatLng_to_vertex( - api_client: BaseApiClient, - from_object: Union[dict[str, Any], object], - parent_object: Optional[dict[str, Any]] = None, -) -> dict[str, Any]: - to_object: dict[str, Any] = {} - if getv(from_object, ['latitude']) is not None: - setv(to_object, ['latitude'], getv(from_object, ['latitude'])) - - if getv(from_object, ['longitude']) is not None: - setv(to_object, ['longitude'], getv(from_object, ['longitude'])) - - return to_object - - -def _RetrievalConfig_to_vertex( - api_client: BaseApiClient, - from_object: Union[dict[str, Any], object], - parent_object: Optional[dict[str, Any]] = None, -) -> dict[str, Any]: - to_object: dict[str, Any] = {} - if getv(from_object, ['lat_lng']) is not None: - setv( - to_object, - ['latLng'], - _LatLng_to_vertex( - api_client, getv(from_object, ['lat_lng']), to_object - ), - ) - - return to_object - - def _ToolConfig_to_vertex( api_client: BaseApiClient, from_object: Union[dict[str, Any], object], @@ -867,11 +807,7 @@ def _ToolConfig_to_vertex( if getv(from_object, ['retrieval_config']) is not None: setv( - to_object, - ['retrievalConfig'], - _RetrievalConfig_to_vertex( - api_client, getv(from_object, ['retrieval_config']), to_object - ), + to_object, ['retrievalConfig'], getv(from_object, ['retrieval_config']) ) return to_object diff --git a/google/genai/models.py b/google/genai/models.py index de1d3552..e9a9cd7c 100644 --- a/google/genai/models.py +++ b/google/genai/models.py @@ -316,33 +316,6 @@ def _FunctionCallingConfig_to_mldev( return to_object -def _LatLng_to_mldev( - api_client: BaseApiClient, - from_object: Union[dict[str, Any], object], - parent_object: Optional[dict[str, Any]] = None, -) -> dict[str, Any]: - to_object: dict[str, Any] = {} - if getv(from_object, ['latitude']) is not None: - raise ValueError('latitude parameter is not supported in Gemini API.') - - if getv(from_object, ['longitude']) is not None: - raise ValueError('longitude parameter is not supported in Gemini API.') - - return to_object - - -def _RetrievalConfig_to_mldev( - api_client: BaseApiClient, - from_object: Union[dict[str, Any], object], - parent_object: Optional[dict[str, Any]] = None, -) -> dict[str, Any]: - to_object: dict[str, Any] = {} - if getv(from_object, ['lat_lng']) is not None: - raise ValueError('lat_lng parameter is not supported in Gemini API.') - - return to_object - - def _ToolConfig_to_mldev( api_client: BaseApiClient, from_object: Union[dict[str, Any], object], @@ -361,8 +334,8 @@ def _ToolConfig_to_mldev( ) if getv(from_object, ['retrieval_config']) is not None: - raise ValueError( - 'retrieval_config parameter is not supported in Gemini API.' + setv( + to_object, ['retrievalConfig'], getv(from_object, ['retrieval_config']) ) return to_object @@ -1458,39 +1431,6 @@ def _FunctionCallingConfig_to_vertex( return to_object -def _LatLng_to_vertex( - api_client: BaseApiClient, - from_object: Union[dict[str, Any], object], - parent_object: Optional[dict[str, Any]] = None, -) -> dict[str, Any]: - to_object: dict[str, Any] = {} - if getv(from_object, ['latitude']) is not None: - setv(to_object, ['latitude'], getv(from_object, ['latitude'])) - - if getv(from_object, ['longitude']) is not None: - setv(to_object, ['longitude'], getv(from_object, ['longitude'])) - - return to_object - - -def _RetrievalConfig_to_vertex( - api_client: BaseApiClient, - from_object: Union[dict[str, Any], object], - parent_object: Optional[dict[str, Any]] = None, -) -> dict[str, Any]: - to_object: dict[str, Any] = {} - if getv(from_object, ['lat_lng']) is not None: - setv( - to_object, - ['latLng'], - _LatLng_to_vertex( - api_client, getv(from_object, ['lat_lng']), to_object - ), - ) - - return to_object - - def _ToolConfig_to_vertex( api_client: BaseApiClient, from_object: Union[dict[str, Any], object], @@ -1510,11 +1450,7 @@ def _ToolConfig_to_vertex( if getv(from_object, ['retrieval_config']) is not None: setv( - to_object, - ['retrievalConfig'], - _RetrievalConfig_to_vertex( - api_client, getv(from_object, ['retrieval_config']), to_object - ), + to_object, ['retrievalConfig'], getv(from_object, ['retrieval_config']) ) return to_object diff --git a/google/genai/tests/models/test_generate_content_tools.py b/google/genai/tests/models/test_generate_content_tools.py index ed9adbc0..0630f8f0 100644 --- a/google/genai/tests/models/test_generate_content_tools.py +++ b/google/genai/tests/models/test_generate_content_tools.py @@ -16,6 +16,7 @@ import logging import sys import typing + import pydantic import pytest @@ -120,7 +121,9 @@ def divide_floats(a: float, b: float) -> float: 'tools': [{ 'retrieval': { 'vertex_ai_search': { - 'datastore': 'projects/vertex-sdk-dev/locations/global/collections/default_collection/dataStores/yvonne_1728691676574' + 'datastore': ( + 'projects/vertex-sdk-dev/locations/global/collections/default_collection/dataStores/yvonne_1728691676574' + ) } } }] @@ -149,7 +152,7 @@ def divide_floats(a: float, b: float) -> float: exception_if_mldev='retrieval', exception_if_vertex='400', ), - pytest_helper.TestTableItem( + pytest_helper.TestTableItem( name='test_vai_search_engine', parameters=types._GenerateContentParameters( model='gemini-2.0-flash-001', @@ -258,6 +261,31 @@ def divide_floats(a: float, b: float) -> float: config={'tools': [{'code_execution': {}}]}, ), ), + pytest_helper.TestTableItem( + name='test_function_google_search_retrieval_with_long_lat', + parameters=types._GenerateContentParameters( + model='gemini-1.5-flash', + contents=t.t_contents(None, 'what is the price of GOOG?'), + config=types.GenerateContentConfig( + tools=[ + types.Tool( + google_search_retrieval=types.GoogleSearchRetrieval( + dynamic_retrieval_config=types.DynamicRetrievalConfig( + mode='MODE_UNSPECIFIED' + ) + ) + ), + ], + tool_config=types.ToolConfig( + retrieval_config=types.RetrievalConfig( + lat_lng=types.GoogleTypeLatLngDict( + latitude=37.7749, longitude=-122.4194 + ) + ) + ), + ), + ), + ), ] @@ -464,7 +492,9 @@ async def test_disable_automatic_function_calling_stream_async(client): @pytest.mark.asyncio -async def test_automatic_function_calling_no_function_response_stream_async(client): +async def test_automatic_function_calling_no_function_response_stream_async( + client, +): response = await client.aio.models.generate_content_stream( model='gemini-1.5-flash', contents='what is the weather in Boston?', @@ -658,7 +688,7 @@ def get_weather_pydantic_model( contents='it is winter now, what is the weather in Boston?', config={ 'tools': [get_weather_pydantic_model], - 'automatic_function_calling': {'ignore_call_history': True} + 'automatic_function_calling': {'ignore_call_history': True}, }, ) @@ -689,8 +719,9 @@ def get_weather_from_list_of_cities( response = client.models.generate_content( model='gemini-1.5-flash', contents='it is winter now, what is the weather in Boston and New York?', - config={'tools': [get_weather_from_list_of_cities], - 'automatic_function_calling': {'ignore_call_history': True}, + config={ + 'tools': [get_weather_from_list_of_cities], + 'automatic_function_calling': {'ignore_call_history': True}, }, ) @@ -736,30 +767,34 @@ def get_information( ), config={ 'tools': [get_information], - 'automatic_function_calling': {'ignore_call_history': True} + 'automatic_function_calling': {'ignore_call_history': True}, }, ) assert 'Sundae' in response.text assert 'cat' in response.text -def test_automatic_function_calling_with_parameterized_generic_union_type(client): +def test_automatic_function_calling_with_parameterized_generic_union_type( + client, +): def describe_cities( country: str, cities: typing.Optional[list[str]] = None, ) -> str: - "Given a country and an optional list of cities, describe the cities." + 'Given a country and an optional list of cities, describe the cities.' if cities is None: return 'There are no cities to describe.' else: - return f'The cities in {country} are: {", ".join(cities)} and they are nice.' + return ( + f'The cities in {country} are: {", ".join(cities)} and they are nice.' + ) response = client.models.generate_content( model='gemini-1.5-flash', - contents=('Can you describe the city of San Francisco?'), + contents='Can you describe the city of San Francisco?', config={ 'tools': [describe_cities], - 'automatic_function_calling': {'ignore_call_history': True} + 'automatic_function_calling': {'ignore_call_history': True}, }, ) assert 'San Francisco' in response.text @@ -794,7 +829,7 @@ def test_with_1_empty_tool(client): contents='What is the price of GOOG?.', config={ 'tools': [{}, get_stock_price], - 'automatic_function_calling': {'ignore_call_history': True} + 'automatic_function_calling': {'ignore_call_history': True}, }, ) @@ -819,7 +854,9 @@ async def test_vai_search_stream_async(client): 'tools': [{ 'retrieval': { 'vertex_ai_search': { - 'datastore': 'projects/vertex-sdk-dev/locations/global/collections/default_collection/dataStores/yvonne_1728691676574' + 'datastore': ( + 'projects/vertex-sdk-dev/locations/global/collections/default_collection/dataStores/yvonne_1728691676574' + ) } } }] @@ -835,7 +872,9 @@ async def test_vai_search_stream_async(client): 'tools': [{ 'retrieval': { 'vertex_ai_search': { - 'datastore': 'projects/vertex-sdk-dev/locations/global/collections/default_collection/dataStores/yvonne_1728691676574' + 'datastore': ( + 'projects/vertex-sdk-dev/locations/global/collections/default_collection/dataStores/yvonne_1728691676574' + ) } } }] @@ -855,7 +894,7 @@ async def divide_integers(a: int, b: int) -> int: contents='what is the result of 1000/2?', config={ 'tools': [divide_integers], - 'automatic_function_calling': {'ignore_call_history': True} + 'automatic_function_calling': {'ignore_call_history': True}, }, ) @@ -868,13 +907,13 @@ async def divide_integers(a: int, b: int) -> int: return a // b response = await client.aio.models.generate_content( - model='gemini-1.5-flash', - contents='what is the result of 1000/2?', - config={ - 'tools': [divide_integers], - 'automatic_function_calling': {'ignore_call_history': True} - }, - ) + model='gemini-1.5-flash', + contents='what is the result of 1000/2?', + config={ + 'tools': [divide_integers], + 'automatic_function_calling': {'ignore_call_history': True}, + }, + ) assert '500' in response.text @@ -889,7 +928,7 @@ def divide_integers(a: int, b: int) -> int: contents='what is the result of 1000/2?', config={ 'tools': [divide_integers], - 'automatic_function_calling': {'ignore_call_history': True} + 'automatic_function_calling': {'ignore_call_history': True}, }, ) @@ -907,7 +946,12 @@ def mystery_function(a: int, b: int) -> int: config={'tools': [divide_integers]}, ) assert response.automatic_function_calling_history - assert response.automatic_function_calling_history[-1].parts[0].function_response.response['error'] + assert ( + response.automatic_function_calling_history[-1] + .parts[0] + .function_response.response['error'] + ) + @pytest.mark.asyncio async def test_automatic_function_calling_async_float_without_decimal(client): @@ -971,7 +1015,9 @@ async def get_current_weather_async(city: str) -> str: @pytest.mark.asyncio -async def test_automatic_function_calling_async_with_async_function_stream(client): +async def test_automatic_function_calling_async_with_async_function_stream( + client, +): async def get_current_weather_async(city: str) -> str: """Returns the current weather in the city.""" @@ -1182,8 +1228,9 @@ def test_code_execution_tool(client): assert response.executable_code assert ( - 'prime' in response.code_execution_result.lower() or - '5117' in response.code_execution_result) + 'prime' in response.code_execution_result.lower() + or '5117' in response.code_execution_result + ) def test_afc_logs_to_logger_instance(client, caplog): diff --git a/google/genai/types.py b/google/genai/types.py index 663c3fd9..be9637be 100644 --- a/google/genai/types.py +++ b/google/genai/types.py @@ -2421,13 +2421,12 @@ class FunctionCallingConfigDict(TypedDict, total=False): ] -class LatLng(_common.BaseModel): +class GoogleTypeLatLng(_common.BaseModel): """An object that represents a latitude/longitude pair. This is expressed as a pair of doubles to represent degrees latitude and degrees longitude. Unless specified otherwise, this object must conform to the - - WGS84 standard. Values must be within normalized ranges. + WGS84 standard. Values must be within normalized ranges. """ latitude: Optional[float] = Field( @@ -2436,42 +2435,47 @@ class LatLng(_common.BaseModel): ) longitude: Optional[float] = Field( default=None, - description="""The longitude in degrees. It must be in the range [-180.0, +180.0]""", + description="""The longitude in degrees. It must be in the range [-180.0, +180.0].""", ) -class LatLngDict(TypedDict, total=False): +class GoogleTypeLatLngDict(TypedDict, total=False): """An object that represents a latitude/longitude pair. This is expressed as a pair of doubles to represent degrees latitude and degrees longitude. Unless specified otherwise, this object must conform to the - - WGS84 standard. Values must be within normalized ranges. + WGS84 standard. Values must be within normalized ranges. """ latitude: Optional[float] """The latitude in degrees. It must be in the range [-90.0, +90.0].""" longitude: Optional[float] - """The longitude in degrees. It must be in the range [-180.0, +180.0]""" + """The longitude in degrees. It must be in the range [-180.0, +180.0].""" -LatLngOrDict = Union[LatLng, LatLngDict] +GoogleTypeLatLngOrDict = Union[GoogleTypeLatLng, GoogleTypeLatLngDict] class RetrievalConfig(_common.BaseModel): """Retrieval config.""" - lat_lng: Optional[LatLng] = Field( - default=None, description="""Optional. The location of the user.""" + language_code: Optional[str] = Field( + default=None, description="""The language code of the user.""" + ) + lat_lng: Optional[GoogleTypeLatLng] = Field( + default=None, description="""The location of the user.""" ) class RetrievalConfigDict(TypedDict, total=False): """Retrieval config.""" - lat_lng: Optional[LatLngDict] - """Optional. The location of the user.""" + language_code: Optional[str] + """The language code of the user.""" + + lat_lng: Optional[GoogleTypeLatLngDict] + """The location of the user.""" RetrievalConfigOrDict = Union[RetrievalConfig, RetrievalConfigDict]