google-genai 1.16.1__py3-none-any.whl → 1.18.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google/genai/__init__.py +1 -2
- google/genai/_api_client.py +10 -0
- google/genai/_automatic_function_calling_util.py +1 -0
- google/genai/_common.py +36 -1
- google/genai/_live_converters.py +134 -31
- google/genai/_mcp_utils.py +3 -6
- google/genai/_replay_api_client.py +51 -1
- google/genai/_tokens_converters.py +75 -13
- google/genai/_transformers.py +22 -3
- google/genai/caches.py +74 -6
- google/genai/chats.py +6 -3
- google/genai/live.py +39 -101
- google/genai/models.py +349 -17
- google/genai/tunings.py +6 -0
- google/genai/types.py +333 -162
- google/genai/version.py +1 -1
- {google_genai-1.16.1.dist-info → google_genai-1.18.0.dist-info}/METADATA +2 -2
- google_genai-1.18.0.dist-info/RECORD +35 -0
- {google_genai-1.16.1.dist-info → google_genai-1.18.0.dist-info}/WHEEL +1 -1
- google_genai-1.16.1.dist-info/RECORD +0 -35
- {google_genai-1.16.1.dist-info → google_genai-1.18.0.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.16.1.dist-info → google_genai-1.18.0.dist-info}/top_level.txt +0 -0
google/genai/caches.py
CHANGED
@@ -66,6 +66,24 @@ def _Blob_to_mldev(
|
|
66
66
|
return to_object
|
67
67
|
|
68
68
|
|
69
|
+
def _FileData_to_mldev(
|
70
|
+
api_client: BaseApiClient,
|
71
|
+
from_object: Union[dict[str, Any], object],
|
72
|
+
parent_object: Optional[dict[str, Any]] = None,
|
73
|
+
) -> dict[str, Any]:
|
74
|
+
to_object: dict[str, Any] = {}
|
75
|
+
if getv(from_object, ['display_name']) is not None:
|
76
|
+
raise ValueError('display_name parameter is not supported in Gemini API.')
|
77
|
+
|
78
|
+
if getv(from_object, ['file_uri']) is not None:
|
79
|
+
setv(to_object, ['fileUri'], getv(from_object, ['file_uri']))
|
80
|
+
|
81
|
+
if getv(from_object, ['mime_type']) is not None:
|
82
|
+
setv(to_object, ['mimeType'], getv(from_object, ['mime_type']))
|
83
|
+
|
84
|
+
return to_object
|
85
|
+
|
86
|
+
|
69
87
|
def _Part_to_mldev(
|
70
88
|
api_client: BaseApiClient,
|
71
89
|
from_object: Union[dict[str, Any], object],
|
@@ -93,6 +111,22 @@ def _Part_to_mldev(
|
|
93
111
|
),
|
94
112
|
)
|
95
113
|
|
114
|
+
if getv(from_object, ['file_data']) is not None:
|
115
|
+
setv(
|
116
|
+
to_object,
|
117
|
+
['fileData'],
|
118
|
+
_FileData_to_mldev(
|
119
|
+
api_client, getv(from_object, ['file_data']), to_object
|
120
|
+
),
|
121
|
+
)
|
122
|
+
|
123
|
+
if getv(from_object, ['thought_signature']) is not None:
|
124
|
+
setv(
|
125
|
+
to_object,
|
126
|
+
['thoughtSignature'],
|
127
|
+
getv(from_object, ['thought_signature']),
|
128
|
+
)
|
129
|
+
|
96
130
|
if getv(from_object, ['code_execution_result']) is not None:
|
97
131
|
setv(
|
98
132
|
to_object,
|
@@ -103,9 +137,6 @@ def _Part_to_mldev(
|
|
103
137
|
if getv(from_object, ['executable_code']) is not None:
|
104
138
|
setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
|
105
139
|
|
106
|
-
if getv(from_object, ['file_data']) is not None:
|
107
|
-
setv(to_object, ['fileData'], getv(from_object, ['file_data']))
|
108
|
-
|
109
140
|
if getv(from_object, ['function_call']) is not None:
|
110
141
|
setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
|
111
142
|
|
@@ -428,6 +459,9 @@ def _RetrievalConfig_to_mldev(
|
|
428
459
|
_LatLng_to_mldev(api_client, getv(from_object, ['lat_lng']), to_object),
|
429
460
|
)
|
430
461
|
|
462
|
+
if getv(from_object, ['language_code']) is not None:
|
463
|
+
setv(to_object, ['languageCode'], getv(from_object, ['language_code']))
|
464
|
+
|
431
465
|
return to_object
|
432
466
|
|
433
467
|
|
@@ -704,6 +738,24 @@ def _Blob_to_vertex(
|
|
704
738
|
return to_object
|
705
739
|
|
706
740
|
|
741
|
+
def _FileData_to_vertex(
|
742
|
+
api_client: BaseApiClient,
|
743
|
+
from_object: Union[dict[str, Any], object],
|
744
|
+
parent_object: Optional[dict[str, Any]] = None,
|
745
|
+
) -> dict[str, Any]:
|
746
|
+
to_object: dict[str, Any] = {}
|
747
|
+
if getv(from_object, ['display_name']) is not None:
|
748
|
+
setv(to_object, ['displayName'], getv(from_object, ['display_name']))
|
749
|
+
|
750
|
+
if getv(from_object, ['file_uri']) is not None:
|
751
|
+
setv(to_object, ['fileUri'], getv(from_object, ['file_uri']))
|
752
|
+
|
753
|
+
if getv(from_object, ['mime_type']) is not None:
|
754
|
+
setv(to_object, ['mimeType'], getv(from_object, ['mime_type']))
|
755
|
+
|
756
|
+
return to_object
|
757
|
+
|
758
|
+
|
707
759
|
def _Part_to_vertex(
|
708
760
|
api_client: BaseApiClient,
|
709
761
|
from_object: Union[dict[str, Any], object],
|
@@ -731,6 +783,22 @@ def _Part_to_vertex(
|
|
731
783
|
),
|
732
784
|
)
|
733
785
|
|
786
|
+
if getv(from_object, ['file_data']) is not None:
|
787
|
+
setv(
|
788
|
+
to_object,
|
789
|
+
['fileData'],
|
790
|
+
_FileData_to_vertex(
|
791
|
+
api_client, getv(from_object, ['file_data']), to_object
|
792
|
+
),
|
793
|
+
)
|
794
|
+
|
795
|
+
if getv(from_object, ['thought_signature']) is not None:
|
796
|
+
setv(
|
797
|
+
to_object,
|
798
|
+
['thoughtSignature'],
|
799
|
+
getv(from_object, ['thought_signature']),
|
800
|
+
)
|
801
|
+
|
734
802
|
if getv(from_object, ['code_execution_result']) is not None:
|
735
803
|
setv(
|
736
804
|
to_object,
|
@@ -741,9 +809,6 @@ def _Part_to_vertex(
|
|
741
809
|
if getv(from_object, ['executable_code']) is not None:
|
742
810
|
setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
|
743
811
|
|
744
|
-
if getv(from_object, ['file_data']) is not None:
|
745
|
-
setv(to_object, ['fileData'], getv(from_object, ['file_data']))
|
746
|
-
|
747
812
|
if getv(from_object, ['function_call']) is not None:
|
748
813
|
setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
|
749
814
|
|
@@ -1084,6 +1149,9 @@ def _RetrievalConfig_to_vertex(
|
|
1084
1149
|
),
|
1085
1150
|
)
|
1086
1151
|
|
1152
|
+
if getv(from_object, ['language_code']) is not None:
|
1153
|
+
setv(to_object, ['languageCode'], getv(from_object, ['language_code']))
|
1154
|
+
|
1087
1155
|
return to_object
|
1088
1156
|
|
1089
1157
|
|
google/genai/chats.py
CHANGED
@@ -160,7 +160,7 @@ class _BaseChat:
|
|
160
160
|
# Because the AFC input contains the entire curated chat history in
|
161
161
|
# addition to the new user input, we need to truncate the AFC history
|
162
162
|
# to deduplicate the existing chat history.
|
163
|
-
automatic_function_calling_history[len(self._curated_history):]
|
163
|
+
automatic_function_calling_history[len(self._curated_history) :]
|
164
164
|
if automatic_function_calling_history
|
165
165
|
else [user_input]
|
166
166
|
)
|
@@ -328,7 +328,7 @@ class Chat(_BaseChat):
|
|
328
328
|
yield chunk
|
329
329
|
automatic_function_calling_history = (
|
330
330
|
chunk.automatic_function_calling_history
|
331
|
-
if chunk.automatic_function_calling_history
|
331
|
+
if chunk is not None and chunk.automatic_function_calling_history
|
332
332
|
else []
|
333
333
|
)
|
334
334
|
self.record_history(
|
@@ -495,9 +495,12 @@ class AsyncChat(_BaseChat):
|
|
495
495
|
self.record_history(
|
496
496
|
user_input=input_content,
|
497
497
|
model_output=output_contents,
|
498
|
-
automatic_function_calling_history=chunk.automatic_function_calling_history
|
498
|
+
automatic_function_calling_history=chunk.automatic_function_calling_history
|
499
|
+
if chunk is not None and chunk.automatic_function_calling_history
|
500
|
+
else [],
|
499
501
|
is_valid=is_valid,
|
500
502
|
)
|
503
|
+
|
501
504
|
return async_generator() # type: ignore[no-untyped-call, no-any-return]
|
502
505
|
|
503
506
|
|
google/genai/live.py
CHANGED
@@ -34,6 +34,7 @@ from . import _live_converters as live_converters
|
|
34
34
|
from . import _mcp_utils
|
35
35
|
from . import _transformers as t
|
36
36
|
from . import client
|
37
|
+
from . import errors
|
37
38
|
from . import types
|
38
39
|
from ._api_client import BaseApiClient
|
39
40
|
from ._common import get_value_by_path as getv
|
@@ -78,10 +79,6 @@ _FUNCTION_RESPONSE_REQUIRES_ID = (
|
|
78
79
|
' response of a ToolCall.FunctionalCalls in Google AI.'
|
79
80
|
)
|
80
81
|
|
81
|
-
|
82
|
-
_DUMMY_KEY = 'dummy_key'
|
83
|
-
|
84
|
-
|
85
82
|
class AsyncSession:
|
86
83
|
"""[Preview] AsyncSession."""
|
87
84
|
|
@@ -912,25 +909,10 @@ class AsyncLive(_api_module.BaseModule):
|
|
912
909
|
Yields:
|
913
910
|
An AsyncSession object.
|
914
911
|
"""
|
915
|
-
async with self._connect(
|
916
|
-
model=model,
|
917
|
-
config=config,
|
918
|
-
) as session:
|
919
|
-
yield session
|
920
|
-
|
921
|
-
@contextlib.asynccontextmanager
|
922
|
-
async def _connect(
|
923
|
-
self,
|
924
|
-
*,
|
925
|
-
model: Optional[str] = None,
|
926
|
-
config: Optional[types.LiveConnectConfigOrDict] = None,
|
927
|
-
uri: Optional[str] = None,
|
928
|
-
) -> AsyncIterator[AsyncSession]:
|
929
|
-
|
930
912
|
# TODO(b/404946570): Support per request http options.
|
931
913
|
if isinstance(config, dict):
|
932
914
|
config = types.LiveConnectConfig(**config)
|
933
|
-
if config and config.http_options
|
915
|
+
if config and config.http_options:
|
934
916
|
raise ValueError(
|
935
917
|
'google.genai.client.aio.live.connect() does not support'
|
936
918
|
' http_options at request-level in LiveConnectConfig yet. Please use'
|
@@ -944,11 +926,23 @@ class AsyncLive(_api_module.BaseModule):
|
|
944
926
|
|
945
927
|
parameter_model = await _t_live_connect_config(self._api_client, config)
|
946
928
|
|
947
|
-
if self._api_client.api_key:
|
948
|
-
api_key = self._api_client.api_key
|
929
|
+
if self._api_client.api_key and not self._api_client.vertexai:
|
949
930
|
version = self._api_client._http_options.api_version
|
950
|
-
|
951
|
-
|
931
|
+
api_key = self._api_client.api_key
|
932
|
+
method = 'BidiGenerateContent'
|
933
|
+
key_name = 'key'
|
934
|
+
if api_key.startswith('auth_tokens/'):
|
935
|
+
warnings.warn(
|
936
|
+
message=(
|
937
|
+
"The SDK's ephemeral token support is experimental, and may"
|
938
|
+
' change in future versions.'
|
939
|
+
),
|
940
|
+
category=errors.ExperimentalWarning,
|
941
|
+
)
|
942
|
+
method = 'BidiGenerateContentConstrained'
|
943
|
+
key_name = 'access_token'
|
944
|
+
|
945
|
+
uri = f'{base_url}/ws/google.ai.generativelanguage.{version}.GenerativeService.{method}?{key_name}={api_key}'
|
952
946
|
headers = self._api_client._http_options.headers
|
953
947
|
|
954
948
|
request_dict = _common.convert_to_dict(
|
@@ -964,6 +958,27 @@ class AsyncLive(_api_module.BaseModule):
|
|
964
958
|
|
965
959
|
setv(request_dict, ['setup', 'model'], transformed_model)
|
966
960
|
|
961
|
+
request = json.dumps(request_dict)
|
962
|
+
elif self._api_client.api_key and self._api_client.vertexai:
|
963
|
+
# Headers already contains api key for express mode.
|
964
|
+
api_key = self._api_client.api_key
|
965
|
+
version = self._api_client._http_options.api_version
|
966
|
+
uri = f'{base_url}/ws/google.cloud.aiplatform.{version}.LlmBidiService/BidiGenerateContent'
|
967
|
+
headers = self._api_client._http_options.headers
|
968
|
+
|
969
|
+
request_dict = _common.convert_to_dict(
|
970
|
+
live_converters._LiveConnectParameters_to_vertex(
|
971
|
+
api_client=self._api_client,
|
972
|
+
from_object=types.LiveConnectParameters(
|
973
|
+
model=transformed_model,
|
974
|
+
config=parameter_model,
|
975
|
+
).model_dump(exclude_none=True),
|
976
|
+
)
|
977
|
+
)
|
978
|
+
del request_dict['config']
|
979
|
+
|
980
|
+
setv(request_dict, ['setup', 'model'], transformed_model)
|
981
|
+
|
967
982
|
request = json.dumps(request_dict)
|
968
983
|
else:
|
969
984
|
if not self._api_client._credentials:
|
@@ -1038,83 +1053,6 @@ class AsyncLive(_api_module.BaseModule):
|
|
1038
1053
|
yield AsyncSession(api_client=self._api_client, websocket=ws)
|
1039
1054
|
|
1040
1055
|
|
1041
|
-
@_common.experimental_warning(
|
1042
|
-
"The SDK's Live API connection with ephemeral token implementation is"
|
1043
|
-
' experimental, and may change in future versions.',
|
1044
|
-
)
|
1045
|
-
@contextlib.asynccontextmanager
|
1046
|
-
async def live_ephemeral_connect(
|
1047
|
-
access_token: str,
|
1048
|
-
model: Optional[str] = None,
|
1049
|
-
config: Optional[types.LiveConnectConfigOrDict] = None,
|
1050
|
-
) -> AsyncIterator[AsyncSession]:
|
1051
|
-
"""[Experimental] Connect to the live server using ephermeral token (Gemini Developer API only).
|
1052
|
-
|
1053
|
-
Note: the live API is currently in experimental.
|
1054
|
-
|
1055
|
-
Usage:
|
1056
|
-
|
1057
|
-
.. code-block:: python
|
1058
|
-
from google import genai
|
1059
|
-
|
1060
|
-
config = {}
|
1061
|
-
async with genai.live_ephemeral_connect(
|
1062
|
-
access_token='auth_tokens/12345',
|
1063
|
-
model='...',
|
1064
|
-
config=config,
|
1065
|
-
http_options=types.HttpOptions(api_version='v1beta'),
|
1066
|
-
) as session:
|
1067
|
-
await session.send_client_content(
|
1068
|
-
turns=types.Content(
|
1069
|
-
role='user',
|
1070
|
-
parts=[types.Part(text='hello!')]
|
1071
|
-
),
|
1072
|
-
turn_complete=True
|
1073
|
-
)
|
1074
|
-
|
1075
|
-
async for message in session.receive():
|
1076
|
-
print(message)
|
1077
|
-
|
1078
|
-
Args:
|
1079
|
-
access_token: The access token to use for the Live session. It can be
|
1080
|
-
generated by the `client.tokens.create` method.
|
1081
|
-
model: The model to use for the Live session.
|
1082
|
-
config: The configuration for the Live session.
|
1083
|
-
|
1084
|
-
Yields:
|
1085
|
-
An AsyncSession object.
|
1086
|
-
"""
|
1087
|
-
if isinstance(config, dict):
|
1088
|
-
config = types.LiveConnectConfig(**config)
|
1089
|
-
|
1090
|
-
http_options = config.http_options if config else None
|
1091
|
-
|
1092
|
-
base_url = (
|
1093
|
-
http_options.base_url
|
1094
|
-
if http_options and http_options.base_url
|
1095
|
-
else 'https://generativelanguage.googleapis.com/'
|
1096
|
-
)
|
1097
|
-
api_version = (
|
1098
|
-
http_options.api_version
|
1099
|
-
if http_options and http_options.api_version
|
1100
|
-
else 'v1beta'
|
1101
|
-
)
|
1102
|
-
internal_client = client.Client(
|
1103
|
-
api_key=_DUMMY_KEY, # Can't be None during initialization
|
1104
|
-
http_options=types.HttpOptions(
|
1105
|
-
base_url=base_url,
|
1106
|
-
api_version=api_version,
|
1107
|
-
),
|
1108
|
-
)
|
1109
|
-
websocket_base_url = internal_client._api_client._websocket_base_url()
|
1110
|
-
uri = f'{websocket_base_url}/ws/google.ai.generativelanguage.{api_version}.GenerativeService.BidiGenerateContentConstrained?access_token={access_token}'
|
1111
|
-
|
1112
|
-
async with internal_client.aio.live._connect(
|
1113
|
-
model=model, config=config, uri=uri
|
1114
|
-
) as session:
|
1115
|
-
yield session
|
1116
|
-
|
1117
|
-
|
1118
1056
|
async def _t_live_connect_config(
|
1119
1057
|
api_client: BaseApiClient,
|
1120
1058
|
config: Optional[types.LiveConnectConfigOrDict],
|