google-genai 1.55.0__py3-none-any.whl → 1.57.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.
Files changed (88) hide show
  1. google/genai/_api_client.py +37 -18
  2. google/genai/_interactions/_base_client.py +8 -2
  3. google/genai/_interactions/resources/interactions.py +6 -6
  4. google/genai/_interactions/types/__init__.py +4 -0
  5. google/genai/_interactions/types/audio_content.py +0 -1
  6. google/genai/_interactions/types/audio_content_param.py +0 -1
  7. google/genai/_interactions/types/code_execution_call_content.py +0 -1
  8. google/genai/_interactions/types/code_execution_call_content_param.py +0 -1
  9. google/genai/_interactions/types/code_execution_result_content.py +0 -1
  10. google/genai/_interactions/types/code_execution_result_content_param.py +0 -1
  11. google/genai/_interactions/types/content.py +63 -0
  12. google/genai/_interactions/types/content_delta.py +7 -23
  13. google/genai/_interactions/types/content_param.py +61 -0
  14. google/genai/_interactions/types/content_start.py +4 -44
  15. google/genai/_interactions/types/deep_research_agent_config.py +0 -1
  16. google/genai/_interactions/types/deep_research_agent_config_param.py +0 -1
  17. google/genai/_interactions/types/document_content.py +3 -2
  18. google/genai/_interactions/types/document_content_param.py +3 -2
  19. google/genai/_interactions/types/document_mime_type.py +23 -0
  20. google/genai/_interactions/types/document_mime_type_param.py +25 -0
  21. google/genai/_interactions/types/dynamic_agent_config.py +0 -1
  22. google/genai/_interactions/types/dynamic_agent_config_param.py +0 -1
  23. google/genai/_interactions/types/file_search_result_content.py +0 -1
  24. google/genai/_interactions/types/file_search_result_content_param.py +0 -1
  25. google/genai/_interactions/types/function_call_content.py +0 -1
  26. google/genai/_interactions/types/function_call_content_param.py +0 -1
  27. google/genai/_interactions/types/function_result_content.py +1 -2
  28. google/genai/_interactions/types/function_result_content_param.py +1 -2
  29. google/genai/_interactions/types/google_search_call_content.py +0 -1
  30. google/genai/_interactions/types/google_search_call_content_param.py +0 -1
  31. google/genai/_interactions/types/google_search_result_content.py +0 -1
  32. google/genai/_interactions/types/google_search_result_content_param.py +0 -1
  33. google/genai/_interactions/types/image_content.py +1 -2
  34. google/genai/_interactions/types/image_content_param.py +1 -2
  35. google/genai/_interactions/types/interaction.py +4 -52
  36. google/genai/_interactions/types/interaction_create_params.py +2 -22
  37. google/genai/_interactions/types/mcp_server_tool_call_content.py +0 -1
  38. google/genai/_interactions/types/mcp_server_tool_call_content_param.py +0 -1
  39. google/genai/_interactions/types/mcp_server_tool_result_content.py +1 -2
  40. google/genai/_interactions/types/mcp_server_tool_result_content_param.py +1 -2
  41. google/genai/_interactions/types/model.py +1 -0
  42. google/genai/_interactions/types/model_param.py +1 -0
  43. google/genai/_interactions/types/text_content.py +0 -1
  44. google/genai/_interactions/types/text_content_param.py +0 -1
  45. google/genai/_interactions/types/thinking_level.py +1 -1
  46. google/genai/_interactions/types/thought_content.py +0 -1
  47. google/genai/_interactions/types/thought_content_param.py +0 -1
  48. google/genai/_interactions/types/turn.py +3 -44
  49. google/genai/_interactions/types/turn_param.py +4 -40
  50. google/genai/_interactions/types/url_context_call_content.py +0 -1
  51. google/genai/_interactions/types/url_context_call_content_param.py +0 -1
  52. google/genai/_interactions/types/url_context_result_content.py +0 -1
  53. google/genai/_interactions/types/url_context_result_content_param.py +0 -1
  54. google/genai/_interactions/types/usage.py +1 -1
  55. google/genai/_interactions/types/usage_param.py +1 -1
  56. google/genai/_interactions/types/video_content.py +1 -2
  57. google/genai/_interactions/types/video_content_param.py +1 -2
  58. google/genai/_live_converters.py +36 -64
  59. google/genai/_local_tokenizer_loader.py +1 -0
  60. google/genai/_tokens_converters.py +14 -14
  61. google/genai/batches.py +27 -22
  62. google/genai/caches.py +42 -42
  63. google/genai/chats.py +0 -2
  64. google/genai/client.py +3 -1
  65. google/genai/files.py +224 -0
  66. google/genai/models.py +57 -72
  67. google/genai/tests/chats/test_get_history.py +9 -8
  68. google/genai/tests/chats/test_validate_response.py +1 -1
  69. google/genai/tests/client/test_client_requests.py +1 -135
  70. google/genai/tests/files/test_register.py +272 -0
  71. google/genai/tests/files/test_register_table.py +70 -0
  72. google/genai/tests/interactions/test_auth.py +479 -0
  73. google/genai/tests/interactions/test_integration.py +2 -0
  74. google/genai/tests/interactions/test_paths.py +105 -0
  75. google/genai/tests/live/test_live.py +2 -36
  76. google/genai/tests/local_tokenizer/test_local_tokenizer.py +1 -1
  77. google/genai/tests/models/test_function_call_streaming.py +90 -90
  78. google/genai/tests/models/test_generate_content.py +1 -2
  79. google/genai/tests/models/test_recontext_image.py +1 -1
  80. google/genai/tests/pytest_helper.py +17 -0
  81. google/genai/tunings.py +1 -27
  82. google/genai/types.py +603 -518
  83. google/genai/version.py +1 -1
  84. {google_genai-1.55.0.dist-info → google_genai-1.57.0.dist-info}/METADATA +224 -22
  85. {google_genai-1.55.0.dist-info → google_genai-1.57.0.dist-info}/RECORD +88 -80
  86. {google_genai-1.55.0.dist-info → google_genai-1.57.0.dist-info}/WHEEL +0 -0
  87. {google_genai-1.55.0.dist-info → google_genai-1.57.0.dist-info}/licenses/LICENSE +0 -0
  88. {google_genai-1.55.0.dist-info → google_genai-1.57.0.dist-info}/top_level.txt +0 -0
@@ -19,8 +19,6 @@
19
19
  from ... import _api_client as api_client
20
20
  from ... import Client
21
21
  from ... import types
22
- from unittest import mock
23
- import pytest
24
22
 
25
23
 
26
24
  def build_test_client(monkeypatch):
@@ -220,136 +218,4 @@ def test_build_request_with_custom_base_url_no_env_vars(monkeypatch):
220
218
  'test/path',
221
219
  {'key': 'value'},
222
220
  )
223
- assert request.url == 'https://custom-base-url.com'
224
-
225
-
226
- def test_interactions_vertex_auth_header():
227
- from ..._api_client import BaseApiClient
228
- from ..._interactions._base_client import SyncAPIClient
229
- from httpx import Client as HTTPClient
230
-
231
- creds = mock.Mock()
232
- creds.quota_project_id = "test-quota-project"
233
- client = Client(vertexai=True, project='test-project', location='us-central1', credentials=creds)
234
-
235
- with (
236
- mock.patch.object(
237
- BaseApiClient, "_access_token", return_value='fake-vertex-token'
238
- ) as mock_access_token,
239
- mock.patch.object(
240
- HTTPClient, "send",
241
- return_value=mock.Mock(),
242
- ) as mock_send,
243
- ):
244
-
245
- response = client.interactions.create(
246
- model='gemini-2.5-flash',
247
- input='What is the largest planet in our solar system?',
248
- )
249
-
250
- mock_send.assert_called_once()
251
- mock_access_token.assert_called_once()
252
- args, kwargs = mock_send.call_args
253
- headers = args[0].headers
254
- assert any(
255
- key == "authorization" and value == 'Bearer fake-vertex-token'
256
- for key, value in headers.items())
257
- assert any(
258
- key == "x-goog-user-project" and value == 'test-quota-project'
259
- for key, value in headers.items())
260
-
261
- def test_interactions_vertex_key_no_auth_header():
262
- from ..._api_client import BaseApiClient
263
- from httpx import Client as HTTPClient
264
-
265
- creds = mock.Mock()
266
- client = Client(vertexai=True, api_key='test-api-key')
267
-
268
- with (
269
- mock.patch.object(
270
- BaseApiClient, "_access_token", return_value='fake-vertex-token'
271
- ) as mock_access_token,
272
- mock.patch.object(
273
- HTTPClient, "send",
274
- return_value=mock.Mock(),
275
- ) as mock_send,
276
- ):
277
-
278
- response = client.interactions.create(
279
- model='gemini-2.5-flash',
280
- input='What is the largest planet in our solar system?',
281
- )
282
-
283
- mock_send.assert_called_once()
284
- mock_access_token.assert_not_called()
285
- args, kwargs = mock_send.call_args
286
- headers = args[0].headers
287
- assert any(
288
- key == "x-goog-api-key" and value == 'test-api-key'
289
- for key, value in headers.items())
290
-
291
- @pytest.mark.asyncio
292
- async def test_async_interactions_vertex_auth_header():
293
- from ..._api_client import BaseApiClient
294
- from ..._interactions._base_client import SyncAPIClient
295
- from ..._api_client import AsyncHttpxClient
296
-
297
- creds = mock.Mock()
298
- creds.quota_project_id = "test-quota-project"
299
- client = Client(vertexai=True, project='test-project', location='us-central1', credentials=creds)
300
-
301
- with (
302
- mock.patch.object(
303
- BaseApiClient, "_async_access_token", return_value='fake-vertex-token'
304
- ) as mock_access_token,
305
- mock.patch.object(
306
- AsyncHttpxClient, "send",
307
- return_value=mock.Mock(),
308
- ) as mock_send,
309
- ):
310
-
311
- response = await client.aio.interactions.create(
312
- model='gemini-2.5-flash',
313
- input='What is the largest planet in our solar system?',
314
- )
315
-
316
- mock_send.assert_called_once()
317
- mock_access_token.assert_called_once()
318
- args, kwargs = mock_send.call_args
319
- headers = args[0].headers
320
- assert any(
321
- key == "authorization" and value == 'Bearer fake-vertex-token'
322
- for key, value in headers.items())
323
- assert any(
324
- key == "x-goog-user-project" and value == 'test-quota-project'
325
- for key, value in headers.items())
326
-
327
- @pytest.mark.asyncio
328
- async def test_async_interactions_vertex_key_no_auth_header():
329
- from ..._api_client import BaseApiClient
330
- from ..._api_client import AsyncHttpxClient
331
- creds = mock.Mock()
332
- client = Client(vertexai=True, api_key='test-api-key')
333
-
334
- with (
335
- mock.patch.object(
336
- BaseApiClient, "_async_access_token", return_value='fake-vertex-token'
337
- ) as mock_access_token,
338
- mock.patch.object(
339
- AsyncHttpxClient, "send",
340
- return_value=mock.Mock(),
341
- ) as mock_send,
342
- ):
343
-
344
- response = await client.aio.interactions.create(
345
- model='gemini-2.5-flash',
346
- input='What is the largest planet in our solar system?',
347
- )
348
-
349
- mock_send.assert_called_once()
350
- mock_access_token.assert_not_called()
351
- args, kwargs = mock_send.call_args
352
- headers = args[0].headers
353
- assert any(
354
- key == "x-goog-api-key" and value == 'test-api-key'
355
- for key, value in headers.items())
221
+ assert request.url == 'https://custom-base-url.com'
@@ -0,0 +1,272 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
16
+
17
+ """Test files register method."""
18
+
19
+ import json
20
+ from unittest import mock
21
+
22
+ from google.auth import credentials
23
+ import httpx
24
+ import pytest
25
+
26
+ from ... import _api_client
27
+ from ... import Client
28
+ from ... import types
29
+ from .. import pytest_helper
30
+
31
+
32
+ class FakeCredentials(credentials.Credentials):
33
+
34
+ def __init__(self, token="fake_token", expired=False, quota_project_id=None):
35
+ super().__init__()
36
+ self.token = token
37
+ self._expired = expired
38
+ self._quota_project_id = quota_project_id
39
+ self.refresh_count = 0
40
+
41
+ @property
42
+ def expired(self):
43
+ return self._expired
44
+
45
+ @property
46
+ def quota_project_id(self):
47
+ return self._quota_project_id
48
+
49
+ def refresh(self, request):
50
+ self.refresh_count += 1
51
+ self.token = "refreshed_token"
52
+ self._expired = False
53
+
54
+
55
+ @mock.patch.object(_api_client.BaseApiClient, "_request_once", autospec=True)
56
+ def test_simple_token(mock_request):
57
+ client = Client(api_key="dummy_key")
58
+ captured_request = None
59
+
60
+ def side_effect(self, http_request, stream=False):
61
+ nonlocal captured_request
62
+ captured_request = http_request
63
+ return _api_client.HttpResponse(
64
+ headers={},
65
+ response_stream=[json.dumps({"files": [{"uri": "files/abc"}]})],
66
+ )
67
+
68
+ mock_request.side_effect = side_effect
69
+
70
+ with pytest_helper.exception_if_vertex(client, ValueError):
71
+ response = client.files.register_files(
72
+ auth=FakeCredentials(token="test_token"),
73
+ uris=["gs://test-bucket/test-file-1.txt"],
74
+ )
75
+
76
+ assert len(response.files) == 1
77
+ assert response.files[0].uri == "files/abc"
78
+ assert captured_request.headers["authorization"] == "Bearer test_token"
79
+
80
+
81
+ @mock.patch.object(_api_client.BaseApiClient, "_request_once", autospec=True)
82
+ def test_token_refresh(mock_request):
83
+ client = Client(api_key="dummy_key")
84
+ captured_request = None
85
+
86
+ def side_effect(self, http_request, stream=False):
87
+ nonlocal captured_request
88
+ captured_request = http_request
89
+ return _api_client.HttpResponse(
90
+ headers={},
91
+ response_stream=[json.dumps({"files": [{"uri": "files/abc"}]})],
92
+ )
93
+
94
+ mock_request.side_effect = side_effect
95
+
96
+ with pytest_helper.exception_if_vertex(client, ValueError):
97
+ creds = FakeCredentials(expired=True)
98
+ response = client.files.register_files(
99
+ auth=creds,
100
+ uris=["gs://test-bucket/test-file-1.txt"],
101
+ )
102
+ assert creds.refresh_count == 1
103
+ assert len(response.files) == 1
104
+ assert response.files[0].uri == "files/abc"
105
+ assert captured_request.headers["authorization"] == "Bearer refreshed_token"
106
+
107
+
108
+ @mock.patch.object(_api_client.BaseApiClient, "_request_once", autospec=True)
109
+ def test_quota_project(mock_request):
110
+ client = Client(api_key="dummy_key")
111
+ captured_request = None
112
+
113
+ def side_effect(self, http_request, stream=False):
114
+ nonlocal captured_request
115
+ captured_request = http_request
116
+ return _api_client.HttpResponse(
117
+ headers={},
118
+ response_stream=[json.dumps({"files": [{"uri": "files/abc"}]})],
119
+ )
120
+
121
+ mock_request.side_effect = side_effect
122
+
123
+ with pytest_helper.exception_if_vertex(client, ValueError):
124
+ creds = FakeCredentials(quota_project_id="test_project")
125
+ response = client.files.register_files(
126
+ auth=creds,
127
+ uris=["gs://test-bucket/test-file-1.txt"],
128
+ )
129
+ assert len(response.files) == 1
130
+ assert response.files[0].uri == "files/abc"
131
+ assert captured_request.headers["x-goog-user-project"] == "test_project"
132
+
133
+
134
+ @mock.patch.object(_api_client.BaseApiClient, "_request_once", autospec=True)
135
+ def test_multiple_uris(mock_request):
136
+ client = Client(api_key="dummy_key")
137
+
138
+ def side_effect(self, http_request, stream=False):
139
+ return _api_client.HttpResponse(
140
+ headers={},
141
+ response_stream=[
142
+ json.dumps({"files": [{"uri": "files/abc"}, {"uri": "files/def"}]})
143
+ ],
144
+ )
145
+
146
+ mock_request.side_effect = side_effect
147
+
148
+ with pytest_helper.exception_if_vertex(client, ValueError):
149
+ response = client.files.register_files(
150
+ auth=FakeCredentials(),
151
+ uris=[
152
+ "gs://test-bucket/test-file-1.txt",
153
+ "gs://test-bucket/test-file-2.txt",
154
+ ],
155
+ )
156
+ assert len(response.files) == 2
157
+ assert response.files[0].uri == "files/abc"
158
+ assert response.files[1].uri == "files/def"
159
+
160
+
161
+ @pytest.mark.asyncio
162
+ @mock.patch.object(
163
+ _api_client.BaseApiClient, "_async_request_once", autospec=True
164
+ )
165
+ async def test_async_single(mock_request):
166
+ client = Client(api_key="dummy_key")
167
+
168
+ async def side_effect(self, http_request, stream=False):
169
+ return _api_client.HttpResponse(
170
+ headers={},
171
+ response_stream=[json.dumps({"files": [{"uri": "files/abc"}]})],
172
+ )
173
+
174
+ mock_request.side_effect = side_effect
175
+
176
+ with pytest_helper.exception_if_vertex(client, ValueError):
177
+ response = await client.aio.files.register_files(
178
+ auth=FakeCredentials(),
179
+ uris=["gs://test-bucket/test-file-1.txt"],
180
+ )
181
+
182
+ assert len(response.files) == 1
183
+ assert response.files[0].uri == "files/abc"
184
+
185
+
186
+ @pytest.mark.asyncio
187
+ @mock.patch.object(
188
+ _api_client.BaseApiClient, "_async_request_once", autospec=True
189
+ )
190
+ async def test_async_token_refresh(mock_request):
191
+ client = Client(api_key="dummy_key")
192
+ captured_request = None
193
+
194
+ async def side_effect(self, http_request, stream=False):
195
+ nonlocal captured_request
196
+ captured_request = http_request
197
+ return _api_client.HttpResponse(
198
+ headers={},
199
+ response_stream=[json.dumps({"files": [{"uri": "files/abc"}]})],
200
+ )
201
+
202
+ mock_request.side_effect = side_effect
203
+
204
+ with pytest_helper.exception_if_vertex(client, ValueError):
205
+ creds = FakeCredentials(expired=True)
206
+ response = await client.aio.files.register_files(
207
+ auth=creds,
208
+ uris=["gs://test-bucket/test-file-1.txt"],
209
+ )
210
+ assert creds.refresh_count == 1
211
+ assert len(response.files) == 1
212
+ assert response.files[0].uri == "files/abc"
213
+ assert captured_request.headers["authorization"] == "Bearer refreshed_token"
214
+
215
+
216
+ @pytest.mark.asyncio
217
+ @mock.patch.object(
218
+ _api_client.BaseApiClient, "_async_request_once", autospec=True
219
+ )
220
+ async def test_async_quota_project(mock_request):
221
+ client = Client(api_key="dummy_key")
222
+ captured_request = None
223
+
224
+ async def side_effect(self, http_request, stream=False):
225
+ nonlocal captured_request
226
+ captured_request = http_request
227
+ return _api_client.HttpResponse(
228
+ headers={},
229
+ response_stream=[json.dumps({"files": [{"uri": "files/abc"}]})],
230
+ )
231
+
232
+ mock_request.side_effect = side_effect
233
+
234
+ with pytest_helper.exception_if_vertex(client, ValueError):
235
+ creds = FakeCredentials(quota_project_id="test_project")
236
+ response = await client.aio.files.register_files(
237
+ auth=creds,
238
+ uris=["gs://test-bucket/test-file-1.txt"],
239
+ )
240
+ assert len(response.files) == 1
241
+ assert response.files[0].uri == "files/abc"
242
+ assert captured_request.headers["x-goog-user-project"] == "test_project"
243
+
244
+
245
+ @pytest.mark.asyncio
246
+ @mock.patch.object(
247
+ _api_client.BaseApiClient, "_async_request_once", autospec=True
248
+ )
249
+ async def test_async_multiple_uris(mock_request):
250
+ client = Client(api_key="dummy_key")
251
+
252
+ async def side_effect(self, http_request, stream=False):
253
+ return _api_client.HttpResponse(
254
+ headers={},
255
+ response_stream=[
256
+ json.dumps({"files": [{"uri": "files/abc"}, {"uri": "files/def"}]})
257
+ ],
258
+ )
259
+
260
+ mock_request.side_effect = side_effect
261
+
262
+ with pytest_helper.exception_if_vertex(client, ValueError):
263
+ response = await client.aio.files.register_files(
264
+ auth=FakeCredentials(),
265
+ uris=[
266
+ "gs://test-bucket/test-file-1.txt",
267
+ "gs://test-bucket/test-file-2.txt",
268
+ ],
269
+ )
270
+ assert len(response.files) == 2
271
+ assert response.files[0].uri == "files/abc"
272
+ assert response.files[1].uri == "files/def"
@@ -0,0 +1,70 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
16
+
17
+ """Test files get method."""
18
+
19
+ import pytest
20
+ from ... import types
21
+ from ... import Client
22
+ from ... import _api_client
23
+ from .. import pytest_helper
24
+ import google.auth
25
+
26
+
27
+ # $ gcloud config set project vertex-sdk-dev
28
+ # $ gcloud auth application-default login --no-launch-browser --scopes="https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/devstorage.read_only"
29
+ def get_headers():
30
+ try:
31
+ credentials, _ = google.auth.default()
32
+ token = _api_client.get_token_from_credentials(None, credentials)
33
+ headers = {
34
+ "Authorization": f"Bearer {token}",}
35
+ if credentials.quota_project_id:
36
+ headers["x-goog-user-project"] = credentials.quota_project_id
37
+ except google.auth.exceptions.DefaultCredentialsError:
38
+ # So this can run in replay mode without credentials.
39
+ headers = {}
40
+
41
+
42
+ test_table: list[pytest_helper.TestTableItem] = [
43
+ pytest_helper.TestTableItem(
44
+ name='test_register',
45
+ parameters=types._RegisterFilesParameters(uris=['gs://unified-genai-dev/image.jpg']),
46
+ exception_if_vertex='only supported in the Gemini Developer client',
47
+ skip_in_api_mode=(
48
+ 'The files have a TTL, they cannot be reliably retrieved for a long'
49
+ ' time.'
50
+ ),
51
+ ),
52
+ ]
53
+
54
+ pytestmark = pytest_helper.setup(
55
+ file=__file__,
56
+ globals_for_file=globals(),
57
+ test_method='files._register_files',
58
+ test_table=test_table,
59
+ http_options={
60
+ 'headers': get_headers(),
61
+ },
62
+ )
63
+
64
+
65
+ @pytest.mark.asyncio
66
+ async def test_async(client):
67
+ with pytest_helper.exception_if_vertex(client, ValueError):
68
+ files = await client.aio.files._register_files(uris=['gs://unified-genai-dev/image.jpg'])
69
+ assert files.files
70
+ assert files.files[0].mime_type == 'image/jpeg'