google-genai 1.55.0__py3-none-any.whl → 1.56.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 (241) hide show
  1. google/genai/_interactions/_base_client.py +8 -2
  2. google/genai/_interactions/resources/interactions.py +6 -6
  3. google/genai/_interactions/types/__init__.py +2 -0
  4. google/genai/_interactions/types/audio_content.py +0 -1
  5. google/genai/_interactions/types/audio_content_param.py +0 -1
  6. google/genai/_interactions/types/code_execution_call_content.py +0 -1
  7. google/genai/_interactions/types/code_execution_call_content_param.py +0 -1
  8. google/genai/_interactions/types/code_execution_result_content.py +0 -1
  9. google/genai/_interactions/types/code_execution_result_content_param.py +0 -1
  10. google/genai/_interactions/types/content_delta.py +7 -23
  11. google/genai/_interactions/types/deep_research_agent_config.py +0 -1
  12. google/genai/_interactions/types/deep_research_agent_config_param.py +0 -1
  13. google/genai/_interactions/types/document_content.py +3 -2
  14. google/genai/_interactions/types/document_content_param.py +3 -2
  15. google/genai/{tests/__init__.py → _interactions/types/document_mime_type.py} +5 -3
  16. google/genai/{tests/afc/__init__.py → _interactions/types/document_mime_type_param.py} +8 -4
  17. google/genai/_interactions/types/dynamic_agent_config.py +0 -1
  18. google/genai/_interactions/types/dynamic_agent_config_param.py +0 -1
  19. google/genai/_interactions/types/file_search_result_content.py +0 -1
  20. google/genai/_interactions/types/file_search_result_content_param.py +0 -1
  21. google/genai/_interactions/types/function_call_content.py +0 -1
  22. google/genai/_interactions/types/function_call_content_param.py +0 -1
  23. google/genai/_interactions/types/function_result_content.py +1 -2
  24. google/genai/_interactions/types/function_result_content_param.py +1 -2
  25. google/genai/_interactions/types/google_search_call_content.py +0 -1
  26. google/genai/_interactions/types/google_search_call_content_param.py +0 -1
  27. google/genai/_interactions/types/google_search_result_content.py +0 -1
  28. google/genai/_interactions/types/google_search_result_content_param.py +0 -1
  29. google/genai/_interactions/types/image_content.py +1 -2
  30. google/genai/_interactions/types/image_content_param.py +1 -2
  31. google/genai/_interactions/types/mcp_server_tool_call_content.py +0 -1
  32. google/genai/_interactions/types/mcp_server_tool_call_content_param.py +0 -1
  33. google/genai/_interactions/types/mcp_server_tool_result_content.py +1 -2
  34. google/genai/_interactions/types/mcp_server_tool_result_content_param.py +1 -2
  35. google/genai/_interactions/types/text_content.py +0 -1
  36. google/genai/_interactions/types/text_content_param.py +0 -1
  37. google/genai/_interactions/types/thinking_level.py +1 -1
  38. google/genai/_interactions/types/thought_content.py +0 -1
  39. google/genai/_interactions/types/thought_content_param.py +0 -1
  40. google/genai/_interactions/types/url_context_call_content.py +0 -1
  41. google/genai/_interactions/types/url_context_call_content_param.py +0 -1
  42. google/genai/_interactions/types/url_context_result_content.py +0 -1
  43. google/genai/_interactions/types/url_context_result_content_param.py +0 -1
  44. google/genai/_interactions/types/video_content.py +1 -2
  45. google/genai/_interactions/types/video_content_param.py +1 -2
  46. google/genai/_live_converters.py +2 -30
  47. google/genai/client.py +3 -1
  48. google/genai/models.py +2 -29
  49. google/genai/tunings.py +1 -27
  50. google/genai/types.py +20 -22
  51. google/genai/version.py +1 -1
  52. {google_genai-1.55.0.dist-info → google_genai-1.56.0.dist-info}/METADATA +224 -22
  53. google_genai-1.56.0.dist-info/RECORD +162 -0
  54. google/genai/tests/afc/test_convert_if_exist_pydantic_model.py +0 -309
  55. google/genai/tests/afc/test_convert_number_values_for_function_call_args.py +0 -63
  56. google/genai/tests/afc/test_find_afc_incompatible_tool_indexes.py +0 -240
  57. google/genai/tests/afc/test_generate_content_stream_afc.py +0 -530
  58. google/genai/tests/afc/test_generate_content_stream_afc_thoughts.py +0 -77
  59. google/genai/tests/afc/test_get_function_map.py +0 -176
  60. google/genai/tests/afc/test_get_function_response_parts.py +0 -277
  61. google/genai/tests/afc/test_get_max_remote_calls_for_afc.py +0 -130
  62. google/genai/tests/afc/test_invoke_function_from_dict_args.py +0 -241
  63. google/genai/tests/afc/test_raise_error_for_afc_incompatible_config.py +0 -159
  64. google/genai/tests/afc/test_should_append_afc_history.py +0 -53
  65. google/genai/tests/afc/test_should_disable_afc.py +0 -214
  66. google/genai/tests/batches/__init__.py +0 -17
  67. google/genai/tests/batches/test_cancel.py +0 -77
  68. google/genai/tests/batches/test_create.py +0 -78
  69. google/genai/tests/batches/test_create_with_bigquery.py +0 -113
  70. google/genai/tests/batches/test_create_with_file.py +0 -82
  71. google/genai/tests/batches/test_create_with_gcs.py +0 -125
  72. google/genai/tests/batches/test_create_with_inlined_requests.py +0 -255
  73. google/genai/tests/batches/test_delete.py +0 -86
  74. google/genai/tests/batches/test_embedding.py +0 -157
  75. google/genai/tests/batches/test_get.py +0 -78
  76. google/genai/tests/batches/test_list.py +0 -79
  77. google/genai/tests/caches/__init__.py +0 -17
  78. google/genai/tests/caches/constants.py +0 -29
  79. google/genai/tests/caches/test_create.py +0 -210
  80. google/genai/tests/caches/test_create_custom_url.py +0 -105
  81. google/genai/tests/caches/test_delete.py +0 -54
  82. google/genai/tests/caches/test_delete_custom_url.py +0 -52
  83. google/genai/tests/caches/test_get.py +0 -94
  84. google/genai/tests/caches/test_get_custom_url.py +0 -52
  85. google/genai/tests/caches/test_list.py +0 -68
  86. google/genai/tests/caches/test_update.py +0 -70
  87. google/genai/tests/caches/test_update_custom_url.py +0 -58
  88. google/genai/tests/chats/__init__.py +0 -1
  89. google/genai/tests/chats/test_get_history.py +0 -597
  90. google/genai/tests/chats/test_send_message.py +0 -844
  91. google/genai/tests/chats/test_validate_response.py +0 -90
  92. google/genai/tests/client/__init__.py +0 -17
  93. google/genai/tests/client/test_async_stream.py +0 -427
  94. google/genai/tests/client/test_client_close.py +0 -197
  95. google/genai/tests/client/test_client_initialization.py +0 -1687
  96. google/genai/tests/client/test_client_requests.py +0 -355
  97. google/genai/tests/client/test_custom_client.py +0 -77
  98. google/genai/tests/client/test_http_options.py +0 -178
  99. google/genai/tests/client/test_replay_client_equality.py +0 -168
  100. google/genai/tests/client/test_retries.py +0 -846
  101. google/genai/tests/client/test_upload_errors.py +0 -136
  102. google/genai/tests/common/__init__.py +0 -17
  103. google/genai/tests/common/test_common.py +0 -954
  104. google/genai/tests/conftest.py +0 -162
  105. google/genai/tests/documents/__init__.py +0 -17
  106. google/genai/tests/documents/test_delete.py +0 -51
  107. google/genai/tests/documents/test_get.py +0 -85
  108. google/genai/tests/documents/test_list.py +0 -72
  109. google/genai/tests/errors/__init__.py +0 -1
  110. google/genai/tests/errors/test_api_error.py +0 -417
  111. google/genai/tests/file_search_stores/__init__.py +0 -17
  112. google/genai/tests/file_search_stores/test_create.py +0 -66
  113. google/genai/tests/file_search_stores/test_delete.py +0 -64
  114. google/genai/tests/file_search_stores/test_get.py +0 -94
  115. google/genai/tests/file_search_stores/test_import_file.py +0 -112
  116. google/genai/tests/file_search_stores/test_list.py +0 -57
  117. google/genai/tests/file_search_stores/test_upload_to_file_search_store.py +0 -141
  118. google/genai/tests/files/__init__.py +0 -17
  119. google/genai/tests/files/test_delete.py +0 -46
  120. google/genai/tests/files/test_download.py +0 -85
  121. google/genai/tests/files/test_get.py +0 -46
  122. google/genai/tests/files/test_list.py +0 -72
  123. google/genai/tests/files/test_upload.py +0 -255
  124. google/genai/tests/imports/test_no_optional_imports.py +0 -28
  125. google/genai/tests/interactions/test_integration.py +0 -80
  126. google/genai/tests/live/__init__.py +0 -16
  127. google/genai/tests/live/test_live.py +0 -2177
  128. google/genai/tests/live/test_live_music.py +0 -362
  129. google/genai/tests/live/test_live_response.py +0 -163
  130. google/genai/tests/live/test_send_client_content.py +0 -147
  131. google/genai/tests/live/test_send_realtime_input.py +0 -268
  132. google/genai/tests/live/test_send_tool_response.py +0 -222
  133. google/genai/tests/local_tokenizer/__init__.py +0 -17
  134. google/genai/tests/local_tokenizer/test_local_tokenizer.py +0 -343
  135. google/genai/tests/local_tokenizer/test_local_tokenizer_loader.py +0 -235
  136. google/genai/tests/mcp/__init__.py +0 -17
  137. google/genai/tests/mcp/test_has_mcp_tool_usage.py +0 -89
  138. google/genai/tests/mcp/test_mcp_to_gemini_tools.py +0 -191
  139. google/genai/tests/mcp/test_parse_config_for_mcp_sessions.py +0 -201
  140. google/genai/tests/mcp/test_parse_config_for_mcp_usage.py +0 -130
  141. google/genai/tests/mcp/test_set_mcp_usage_header.py +0 -72
  142. google/genai/tests/models/__init__.py +0 -17
  143. google/genai/tests/models/constants.py +0 -8
  144. google/genai/tests/models/test_compute_tokens.py +0 -120
  145. google/genai/tests/models/test_count_tokens.py +0 -159
  146. google/genai/tests/models/test_delete.py +0 -107
  147. google/genai/tests/models/test_edit_image.py +0 -264
  148. google/genai/tests/models/test_embed_content.py +0 -94
  149. google/genai/tests/models/test_function_call_streaming.py +0 -442
  150. google/genai/tests/models/test_generate_content.py +0 -2502
  151. google/genai/tests/models/test_generate_content_cached_content.py +0 -132
  152. google/genai/tests/models/test_generate_content_config_zero_value.py +0 -103
  153. google/genai/tests/models/test_generate_content_from_apikey.py +0 -44
  154. google/genai/tests/models/test_generate_content_http_options.py +0 -40
  155. google/genai/tests/models/test_generate_content_image_generation.py +0 -143
  156. google/genai/tests/models/test_generate_content_mcp.py +0 -343
  157. google/genai/tests/models/test_generate_content_media_resolution.py +0 -97
  158. google/genai/tests/models/test_generate_content_model.py +0 -139
  159. google/genai/tests/models/test_generate_content_part.py +0 -821
  160. google/genai/tests/models/test_generate_content_thought.py +0 -76
  161. google/genai/tests/models/test_generate_content_tools.py +0 -1761
  162. google/genai/tests/models/test_generate_images.py +0 -191
  163. google/genai/tests/models/test_generate_videos.py +0 -759
  164. google/genai/tests/models/test_get.py +0 -104
  165. google/genai/tests/models/test_list.py +0 -233
  166. google/genai/tests/models/test_recontext_image.py +0 -189
  167. google/genai/tests/models/test_segment_image.py +0 -148
  168. google/genai/tests/models/test_update.py +0 -95
  169. google/genai/tests/models/test_upscale_image.py +0 -157
  170. google/genai/tests/operations/__init__.py +0 -17
  171. google/genai/tests/operations/test_get.py +0 -38
  172. google/genai/tests/public_samples/__init__.py +0 -17
  173. google/genai/tests/public_samples/test_gemini_text_only.py +0 -34
  174. google/genai/tests/pytest_helper.py +0 -229
  175. google/genai/tests/shared/__init__.py +0 -16
  176. google/genai/tests/shared/batches/__init__.py +0 -14
  177. google/genai/tests/shared/batches/test_create_delete.py +0 -57
  178. google/genai/tests/shared/batches/test_create_get_cancel.py +0 -56
  179. google/genai/tests/shared/batches/test_list.py +0 -40
  180. google/genai/tests/shared/caches/__init__.py +0 -14
  181. google/genai/tests/shared/caches/test_create_get_delete.py +0 -67
  182. google/genai/tests/shared/caches/test_create_update_get.py +0 -71
  183. google/genai/tests/shared/caches/test_list.py +0 -40
  184. google/genai/tests/shared/chats/__init__.py +0 -14
  185. google/genai/tests/shared/chats/test_send_message.py +0 -48
  186. google/genai/tests/shared/chats/test_send_message_stream.py +0 -50
  187. google/genai/tests/shared/files/__init__.py +0 -14
  188. google/genai/tests/shared/files/test_list.py +0 -41
  189. google/genai/tests/shared/files/test_upload_get_delete.py +0 -54
  190. google/genai/tests/shared/models/__init__.py +0 -14
  191. google/genai/tests/shared/models/test_compute_tokens.py +0 -41
  192. google/genai/tests/shared/models/test_count_tokens.py +0 -40
  193. google/genai/tests/shared/models/test_edit_image.py +0 -67
  194. google/genai/tests/shared/models/test_embed.py +0 -40
  195. google/genai/tests/shared/models/test_generate_content.py +0 -39
  196. google/genai/tests/shared/models/test_generate_content_stream.py +0 -54
  197. google/genai/tests/shared/models/test_generate_images.py +0 -40
  198. google/genai/tests/shared/models/test_generate_videos.py +0 -38
  199. google/genai/tests/shared/models/test_list.py +0 -37
  200. google/genai/tests/shared/models/test_recontext_image.py +0 -55
  201. google/genai/tests/shared/models/test_segment_image.py +0 -52
  202. google/genai/tests/shared/models/test_upscale_image.py +0 -52
  203. google/genai/tests/shared/tunings/__init__.py +0 -16
  204. google/genai/tests/shared/tunings/test_create.py +0 -46
  205. google/genai/tests/shared/tunings/test_create_get_cancel.py +0 -56
  206. google/genai/tests/shared/tunings/test_list.py +0 -39
  207. google/genai/tests/tokens/__init__.py +0 -16
  208. google/genai/tests/tokens/test_create.py +0 -154
  209. google/genai/tests/transformers/__init__.py +0 -17
  210. google/genai/tests/transformers/test_blobs.py +0 -71
  211. google/genai/tests/transformers/test_bytes.py +0 -15
  212. google/genai/tests/transformers/test_duck_type.py +0 -96
  213. google/genai/tests/transformers/test_function_responses.py +0 -72
  214. google/genai/tests/transformers/test_schema.py +0 -653
  215. google/genai/tests/transformers/test_t_batch.py +0 -286
  216. google/genai/tests/transformers/test_t_content.py +0 -160
  217. google/genai/tests/transformers/test_t_contents.py +0 -398
  218. google/genai/tests/transformers/test_t_part.py +0 -85
  219. google/genai/tests/transformers/test_t_parts.py +0 -87
  220. google/genai/tests/transformers/test_t_tool.py +0 -157
  221. google/genai/tests/transformers/test_t_tools.py +0 -195
  222. google/genai/tests/tunings/__init__.py +0 -16
  223. google/genai/tests/tunings/test_cancel.py +0 -39
  224. google/genai/tests/tunings/test_end_to_end.py +0 -106
  225. google/genai/tests/tunings/test_get.py +0 -67
  226. google/genai/tests/tunings/test_list.py +0 -75
  227. google/genai/tests/tunings/test_tune.py +0 -268
  228. google/genai/tests/types/__init__.py +0 -16
  229. google/genai/tests/types/test_bytes_internal.py +0 -271
  230. google/genai/tests/types/test_bytes_type.py +0 -152
  231. google/genai/tests/types/test_future.py +0 -101
  232. google/genai/tests/types/test_optional_types.py +0 -36
  233. google/genai/tests/types/test_part_type.py +0 -616
  234. google/genai/tests/types/test_schema_from_json_schema.py +0 -417
  235. google/genai/tests/types/test_schema_json_schema.py +0 -468
  236. google/genai/tests/types/test_types.py +0 -2903
  237. google_genai-1.55.0.dist-info/RECORD +0 -345
  238. /google/genai/{tests/interactions/__init__.py → _interactions/py.typed} +0 -0
  239. {google_genai-1.55.0.dist-info → google_genai-1.56.0.dist-info}/WHEEL +0 -0
  240. {google_genai-1.55.0.dist-info → google_genai-1.56.0.dist-info}/licenses/LICENSE +0 -0
  241. {google_genai-1.55.0.dist-info → google_genai-1.56.0.dist-info}/top_level.txt +0 -0
@@ -1,268 +0,0 @@
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
- """Tests for live.py."""
18
- import json
19
- import os
20
- from unittest import mock
21
-
22
- import pytest
23
- from websockets import client
24
-
25
- from ... import client as gl_client
26
- from ... import live
27
- from ... import types
28
- from .. import pytest_helper
29
-
30
-
31
- IMAGE_FILE_PATH = os.path.abspath(
32
- os.path.join(os.path.dirname(__file__), '../data/google.jpg')
33
- )
34
-
35
-
36
- def mock_api_client(vertexai=False):
37
- api_client = mock.MagicMock(spec=gl_client.BaseApiClient)
38
- api_client.api_key = 'TEST_API_KEY'
39
- api_client._host = lambda: 'test_host'
40
- api_client._http_options = {'headers': {}} # Ensure headers exist
41
- api_client.vertexai = vertexai
42
- api_client._api_client = api_client
43
- return api_client
44
-
45
-
46
- @pytest.fixture
47
- def mock_websocket():
48
- websocket = mock.AsyncMock(spec=client.ClientConnection)
49
- websocket.send = mock.AsyncMock()
50
- websocket.recv = mock.AsyncMock(
51
- return_value='{"serverContent": {"turnComplete": true}}'
52
- ) # Default response
53
- websocket.close = mock.AsyncMock()
54
- return websocket
55
-
56
-
57
- @pytest.mark.parametrize('vertexai', [True, False])
58
- @pytest.mark.asyncio
59
- async def test_send_media_blob_dict(mock_websocket, vertexai):
60
- session = live.AsyncSession(
61
- api_client=mock_api_client(vertexai=vertexai), websocket=mock_websocket
62
- )
63
- content = {'data': bytes([0, 0, 0, 0, 0, 0]), 'mime_type': 'audio/pcm'}
64
-
65
- await session.send_realtime_input(media=content)
66
- mock_websocket.send.assert_called_once()
67
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
68
- assert 'realtime_input' in sent_data
69
-
70
- assert sent_data['realtime_input']['mediaChunks'][0]['data'] == 'AAAAAAAA'
71
- assert pytest_helper.get_value_ignore_key_case(
72
- sent_data['realtime_input']['mediaChunks'][0], 'mime_type'
73
- ) == 'audio/pcm'
74
-
75
-
76
- @pytest.mark.parametrize('vertexai', [True, False])
77
- @pytest.mark.asyncio
78
- async def test_send_media_blob(mock_websocket, vertexai):
79
- session = live.AsyncSession(
80
- api_client=mock_api_client(vertexai=vertexai), websocket=mock_websocket
81
- )
82
- content = types.Blob(data=bytes([0, 0, 0, 0, 0, 0]), mime_type='audio/pcm')
83
-
84
- await session.send_realtime_input(media=content)
85
- mock_websocket.send.assert_called_once()
86
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
87
- assert 'realtime_input' in sent_data
88
-
89
- assert sent_data['realtime_input']['mediaChunks'][0]['data'] == 'AAAAAAAA'
90
- assert pytest_helper.get_value_ignore_key_case(
91
- sent_data['realtime_input']['mediaChunks'][0], 'mime_type'
92
- ) == 'audio/pcm'
93
-
94
-
95
- @pytest.mark.parametrize('vertexai', [True, False])
96
- @pytest.mark.asyncio
97
- async def test_send_media_image(mock_websocket, vertexai, image_jpeg):
98
- session = live.AsyncSession(
99
- api_client=mock_api_client(vertexai=vertexai), websocket=mock_websocket
100
- )
101
-
102
- await session.send_realtime_input(media=image_jpeg)
103
- mock_websocket.send.assert_called_once()
104
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
105
- assert 'realtime_input' in sent_data
106
-
107
- assert pytest_helper.get_value_ignore_key_case(
108
- sent_data['realtime_input']['mediaChunks'][0], 'mime_type'
109
- ) == 'image/jpeg'
110
-
111
-
112
- @pytest.mark.parametrize('vertexai', [True, False])
113
- @pytest.mark.parametrize(
114
- 'content',
115
- [
116
- {'data': bytes([0, 0, 0, 0, 0, 0]), 'mime_type': 'audio/pcm'},
117
- types.Blob(data=bytes([0, 0, 0, 0, 0, 0]), mime_type='audio/pcm'),
118
- ],
119
- )
120
- @pytest.mark.asyncio
121
- async def test_send_audio(mock_websocket, vertexai, content):
122
- api_client = mock_api_client(vertexai=vertexai)
123
- session = live.AsyncSession(api_client=api_client, websocket=mock_websocket)
124
-
125
- await session.send_realtime_input(audio=content)
126
- mock_websocket.send.assert_called_once()
127
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
128
- assert 'realtime_input' in sent_data
129
-
130
- assert sent_data['realtime_input']['audio']['data'] == 'AAAAAAAA'
131
- assert pytest_helper.get_value_ignore_key_case(
132
- sent_data['realtime_input']['audio'], 'mime_type'
133
- ) == 'audio/pcm'
134
-
135
-
136
- @pytest.mark.parametrize('vertexai', [True, False])
137
- @pytest.mark.asyncio
138
- async def test_send_bad_audio_blob(mock_websocket, vertexai):
139
- api_client = mock_api_client(vertexai=vertexai)
140
- session = live.AsyncSession(api_client=api_client, websocket=mock_websocket)
141
- content = types.Blob(data=bytes([0, 0, 0, 0, 0, 0]), mime_type='image/png')
142
-
143
- with pytest.raises(ValueError, match='.*Unsupported mime type.*'):
144
- await session.send_realtime_input(audio=content)
145
-
146
-
147
- @pytest.mark.parametrize('vertexai', [True, False])
148
- @pytest.mark.asyncio
149
- async def test_send_bad_video_blob(mock_websocket, vertexai):
150
- api_client = mock_api_client(vertexai=vertexai)
151
- session = live.AsyncSession(api_client=api_client, websocket=mock_websocket)
152
- content = types.Blob(data=bytes([0, 0, 0, 0, 0, 0]), mime_type='audio/pcm')
153
-
154
- with pytest.raises(ValueError, match='.*Unsupported mime type.*'):
155
- await session.send_realtime_input(video=content)
156
-
157
-
158
- @pytest.mark.parametrize('vertexai', [True, False])
159
- @pytest.mark.asyncio
160
- async def test_send_audio_stream_end(mock_websocket, vertexai):
161
- session = live.AsyncSession(
162
- api_client=mock_api_client(vertexai=vertexai), websocket=mock_websocket
163
- )
164
-
165
- await session.send_realtime_input(audio_stream_end=True)
166
- mock_websocket.send.assert_called_once()
167
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
168
- assert 'realtime_input' in sent_data
169
-
170
- assert sent_data['realtime_input']['audioStreamEnd'] == True
171
-
172
-
173
- @pytest.mark.parametrize('vertexai', [True, False])
174
- @pytest.mark.parametrize(
175
- 'content',
176
- [
177
- {'data': bytes([0, 0, 0, 0, 0, 0]), 'mime_type': 'image/png'},
178
- types.Blob(data=bytes([0, 0, 0, 0, 0, 0]), mime_type='image/png'),
179
- ],
180
- )
181
- @pytest.mark.asyncio
182
- async def test_send_video(mock_websocket, vertexai, content):
183
- api_client = mock_api_client(vertexai=vertexai)
184
- session = live.AsyncSession(api_client=api_client, websocket=mock_websocket)
185
-
186
- await session.send_realtime_input(video=content)
187
- mock_websocket.send.assert_called_once()
188
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
189
- assert 'realtime_input' in sent_data
190
-
191
- assert sent_data['realtime_input']['video']['data'] == 'AAAAAAAA'
192
- assert pytest_helper.get_value_ignore_key_case(
193
- sent_data['realtime_input']['video'], 'mime_type'
194
- ) == 'image/png'
195
-
196
-
197
- @pytest.mark.parametrize('vertexai', [True, False])
198
- @pytest.mark.asyncio
199
- async def test_send_video_image(mock_websocket, vertexai, image_jpeg):
200
- api_client = mock_api_client(vertexai=vertexai)
201
- session = live.AsyncSession(api_client=api_client, websocket=mock_websocket)
202
-
203
- await session.send_realtime_input(video=image_jpeg)
204
- mock_websocket.send.assert_called_once()
205
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
206
- assert 'realtime_input' in sent_data
207
-
208
- assert pytest_helper.get_value_ignore_key_case(
209
- sent_data['realtime_input']['video'], 'mime_type'
210
- ) == 'image/jpeg'
211
-
212
-
213
- @pytest.mark.parametrize('vertexai', [True, False])
214
- @pytest.mark.asyncio
215
- async def test_send_text(mock_websocket, vertexai):
216
- api_client = mock_api_client(vertexai=vertexai)
217
- session = live.AsyncSession(api_client=api_client, websocket=mock_websocket)
218
-
219
- await session.send_realtime_input(text='Hello?')
220
- mock_websocket.send.assert_called_once()
221
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
222
- assert 'realtime_input' in sent_data
223
-
224
- assert sent_data['realtime_input']['text'] == 'Hello?'
225
-
226
-
227
- @pytest.mark.parametrize('vertexai', [True, False])
228
- @pytest.mark.parametrize('activity', [{}, types.ActivityStart()])
229
- @pytest.mark.asyncio
230
- async def test_send_activity_start(mock_websocket, vertexai, activity):
231
- session = live.AsyncSession(
232
- api_client=mock_api_client(vertexai=vertexai), websocket=mock_websocket
233
- )
234
-
235
- await session.send_realtime_input(activity_start=activity)
236
- mock_websocket.send.assert_called_once()
237
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
238
- assert 'realtime_input' in sent_data
239
-
240
- assert sent_data['realtime_input']['activityStart'] == {}
241
-
242
-
243
- @pytest.mark.parametrize('vertexai', [True, False])
244
- @pytest.mark.parametrize('activity', [{}, types.ActivityEnd()])
245
- @pytest.mark.asyncio
246
- async def test_send_activity_end(mock_websocket, vertexai, activity):
247
- session = live.AsyncSession(
248
- api_client=mock_api_client(vertexai=vertexai), websocket=mock_websocket
249
- )
250
-
251
- await session.send_realtime_input(activity_end=activity)
252
- mock_websocket.send.assert_called_once()
253
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
254
- assert 'realtime_input' in sent_data
255
-
256
- assert sent_data['realtime_input']['activityEnd'] == {}
257
-
258
-
259
- @pytest.mark.parametrize('vertexai', [True, False])
260
- @pytest.mark.asyncio
261
- async def test_send_multiple_args(mock_websocket, vertexai):
262
- session = live.AsyncSession(
263
- api_client=mock_api_client(vertexai=vertexai), websocket=mock_websocket
264
- )
265
- with pytest.raises(ValueError, match='.*one argument.*'):
266
- await session.send_realtime_input(
267
- text='Hello?', activity_start=types.ActivityStart()
268
- )
@@ -1,222 +0,0 @@
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
- """Tests for live.py."""
18
-
19
- import contextlib
20
- import json
21
- from unittest import mock
22
-
23
- import pytest
24
- from websockets import client
25
-
26
- from .. import pytest_helper
27
- from ... import client as gl_client
28
- from ... import live
29
- from ... import types
30
-
31
-
32
- def exception_if_mldev(vertexai, exception_type: type[Exception]):
33
- if vertexai:
34
- return contextlib.nullcontext()
35
- else:
36
- return pytest.raises(exception_type)
37
-
38
-
39
- def mock_api_client(vertexai=False):
40
- api_client = mock.MagicMock(spec=gl_client.BaseApiClient)
41
- api_client.api_key = 'TEST_API_KEY'
42
- api_client._host = lambda: 'test_host'
43
- api_client._http_options = {'headers': {}} # Ensure headers exist
44
- api_client.vertexai = vertexai
45
- api_client._api_client = api_client
46
- return api_client
47
-
48
-
49
- @pytest.fixture
50
- def mock_websocket():
51
- websocket = mock.AsyncMock(spec=client.ClientConnection)
52
- websocket.send = mock.AsyncMock()
53
- websocket.recv = mock.AsyncMock(
54
- return_value='{"serverContent": {"turnComplete": true}}'
55
- ) # Default response
56
- websocket.close = mock.AsyncMock()
57
- return websocket
58
-
59
-
60
- @pytest.mark.parametrize('vertexai', [True, False])
61
- @pytest.mark.asyncio
62
- async def test_function_response_dict(mock_websocket, vertexai):
63
- api_client = mock_api_client(vertexai=vertexai)
64
- session = live.AsyncSession(
65
- api_client=api_client, websocket=mock_websocket
66
- )
67
-
68
- input = {
69
- 'name': 'get_current_weather',
70
- 'response': {'temperature': 14.5, 'unit': 'C'},
71
- }
72
-
73
- if not vertexai:
74
- input['id'] = 'some-id'
75
-
76
- await session.send_tool_response(function_responses=input)
77
-
78
- mock_websocket.send.assert_called_once()
79
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
80
- assert 'tool_response' in sent_data
81
-
82
- assert (
83
- sent_data['tool_response']['functionResponses'][0]['name']
84
- == 'get_current_weather'
85
- )
86
- assert (
87
- sent_data['tool_response']['functionResponses'][0]['response'][
88
- 'temperature'
89
- ]
90
- == 14.5
91
- )
92
- assert (
93
- sent_data['tool_response']['functionResponses'][0]['response']['unit']
94
- == 'C'
95
- )
96
-
97
-
98
- @pytest.mark.parametrize('vertexai', [True, False])
99
- @pytest.mark.asyncio
100
- async def test_function_response(mock_websocket, vertexai):
101
- session = live.AsyncSession(
102
- api_client=mock_api_client(vertexai=vertexai), websocket=mock_websocket
103
- )
104
-
105
- input = types.FunctionResponse(
106
- name='get_current_weather',
107
- response={
108
- 'temperature': 14.5,
109
- 'unit': 'C',
110
- 'user_name': 'test_user_name',
111
- 'userEmail': 'test_user_email',
112
- },
113
- )
114
- if not vertexai:
115
- input.id = 'some-id'
116
-
117
- await session.send_tool_response(function_responses=input)
118
- mock_websocket.send.assert_called_once()
119
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
120
- assert 'tool_response' in sent_data
121
-
122
- assert (
123
- sent_data['tool_response']['functionResponses'][0]['name']
124
- == 'get_current_weather'
125
- )
126
- assert (
127
- sent_data['tool_response']['functionResponses'][0]['response']
128
- == input.response
129
- )
130
-
131
-
132
- @pytest.mark.parametrize('vertexai', [True, False])
133
- @pytest.mark.asyncio
134
- async def test_function_response_scheduling(mock_websocket, vertexai):
135
- api_client = mock_api_client(vertexai=vertexai)
136
- session = live.AsyncSession(api_client=api_client, websocket=mock_websocket)
137
-
138
- input = types.FunctionResponse(
139
- name='get_current_weather',
140
- response={'temperature': 14.5, 'unit': 'C'},
141
- will_continue=True,
142
- scheduling=types.FunctionResponseScheduling.SILENT,
143
- )
144
- if not vertexai:
145
- input.id = 'some-id'
146
-
147
- await session.send_tool_response(function_responses=input)
148
-
149
- mock_websocket.send.assert_called_once()
150
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
151
- assert 'tool_response' in sent_data
152
-
153
- assert pytest_helper.get_value_ignore_key_case(
154
- sent_data['tool_response']['functionResponses'][0], 'will_continue'
155
- )
156
- assert (
157
- sent_data['tool_response']['functionResponses'][0]['scheduling']
158
- == 'SILENT'
159
- )
160
-
161
-
162
- @pytest.mark.parametrize('vertexai', [True, False])
163
- @pytest.mark.asyncio
164
- async def test_function_response_list(mock_websocket, vertexai):
165
- session = live.AsyncSession(
166
- api_client=mock_api_client(vertexai=vertexai), websocket=mock_websocket
167
- )
168
-
169
- input1 = {
170
- 'name': 'get_current_weather',
171
- 'response': {'temperature': 14.5, 'unit': 'C'},
172
- }
173
- input2 = {
174
- 'name': 'get_current_weather',
175
- 'response': {'temperature': 99.9, 'unit': 'C'},
176
- }
177
-
178
- if not vertexai:
179
- input1['id'] = '1'
180
- input2['id'] = '2'
181
-
182
- await session.send_tool_response(function_responses=[input1, input2])
183
- mock_websocket.send.assert_called_once()
184
- sent_data = json.loads(mock_websocket.send.call_args[0][0])
185
- assert 'tool_response' in sent_data
186
-
187
- assert len(sent_data['tool_response']['functionResponses']) == 2
188
- assert (
189
- sent_data['tool_response']['functionResponses'][0]['response'][
190
- 'temperature'
191
- ]
192
- == 14.5
193
- )
194
- assert (
195
- sent_data['tool_response']['functionResponses'][1]['response'][
196
- 'temperature'
197
- ]
198
- == 99.9
199
- )
200
-
201
-
202
- @pytest.mark.parametrize('vertexai', [True, False])
203
- @pytest.mark.asyncio
204
- async def test_missing_id(mock_websocket, vertexai):
205
- api_client = mock_api_client(vertexai=vertexai)
206
- session = live.AsyncSession(
207
- api_client=api_client, websocket=mock_websocket
208
- )
209
-
210
- input1 = {
211
- 'name': 'get_current_weather',
212
- 'response': {'temperature': 14.5, 'unit': 'C'},
213
- 'id': '1',
214
- }
215
- input2 = {
216
- 'name': 'get_current_weather',
217
- 'response': {'temperature': 99.9, 'unit': 'C'},
218
- }
219
-
220
- if not vertexai:
221
- with pytest.raises(ValueError, match=".*must have.*"):
222
- await session.send_tool_response(function_responses=[input1, input2])
@@ -1,17 +0,0 @@
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
- """Tests for the Google GenAI SDK's local_tokenizer module."""