google-genai 1.56.0__py3-none-any.whl → 1.58.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 (246) hide show
  1. google/genai/_api_client.py +49 -26
  2. google/genai/_interactions/__init__.py +3 -0
  3. google/genai/_interactions/_base_client.py +1 -1
  4. google/genai/_interactions/_client.py +57 -3
  5. google/genai/_interactions/_client_adapter.py +48 -0
  6. google/genai/_interactions/types/__init__.py +6 -0
  7. google/genai/_interactions/types/audio_content.py +2 -0
  8. google/genai/_interactions/types/audio_content_param.py +2 -0
  9. google/genai/_interactions/types/content.py +65 -0
  10. google/genai/_interactions/types/content_delta.py +10 -2
  11. google/genai/_interactions/types/content_param.py +63 -0
  12. google/genai/_interactions/types/content_start.py +5 -46
  13. google/genai/_interactions/types/content_stop.py +1 -2
  14. google/genai/_interactions/types/document_content.py +2 -0
  15. google/genai/_interactions/types/document_content_param.py +2 -0
  16. google/genai/_interactions/types/error_event.py +1 -2
  17. google/genai/_interactions/types/file_search_call_content.py +32 -0
  18. google/genai/_interactions/types/file_search_call_content_param.py +31 -0
  19. google/genai/_interactions/types/generation_config.py +4 -0
  20. google/genai/_interactions/types/generation_config_param.py +4 -0
  21. google/genai/_interactions/types/image_config.py +31 -0
  22. google/genai/_interactions/types/image_config_param.py +30 -0
  23. google/genai/_interactions/types/image_content.py +2 -0
  24. google/genai/_interactions/types/image_content_param.py +2 -0
  25. google/genai/_interactions/types/interaction.py +6 -52
  26. google/genai/_interactions/types/interaction_create_params.py +4 -22
  27. google/genai/_interactions/types/interaction_event.py +1 -2
  28. google/genai/_interactions/types/interaction_sse_event.py +5 -3
  29. google/genai/_interactions/types/interaction_status_update.py +1 -2
  30. google/genai/_interactions/types/model.py +1 -0
  31. google/genai/_interactions/types/model_param.py +1 -0
  32. google/genai/_interactions/types/turn.py +3 -44
  33. google/genai/_interactions/types/turn_param.py +4 -40
  34. google/genai/_interactions/types/usage.py +1 -1
  35. google/genai/_interactions/types/usage_param.py +1 -1
  36. google/genai/_interactions/types/video_content.py +2 -0
  37. google/genai/_interactions/types/video_content_param.py +2 -0
  38. google/genai/_live_converters.py +118 -34
  39. google/genai/_local_tokenizer_loader.py +1 -0
  40. google/genai/_tokens_converters.py +14 -14
  41. google/genai/_transformers.py +15 -21
  42. google/genai/batches.py +27 -22
  43. google/genai/caches.py +42 -42
  44. google/genai/chats.py +0 -2
  45. google/genai/client.py +61 -55
  46. google/genai/files.py +224 -0
  47. google/genai/live.py +1 -1
  48. google/genai/models.py +56 -44
  49. google/genai/tests/__init__.py +21 -0
  50. google/genai/tests/afc/__init__.py +21 -0
  51. google/genai/tests/afc/test_convert_if_exist_pydantic_model.py +309 -0
  52. google/genai/tests/afc/test_convert_number_values_for_function_call_args.py +63 -0
  53. google/genai/tests/afc/test_find_afc_incompatible_tool_indexes.py +240 -0
  54. google/genai/tests/afc/test_generate_content_stream_afc.py +530 -0
  55. google/genai/tests/afc/test_generate_content_stream_afc_thoughts.py +77 -0
  56. google/genai/tests/afc/test_get_function_map.py +176 -0
  57. google/genai/tests/afc/test_get_function_response_parts.py +277 -0
  58. google/genai/tests/afc/test_get_max_remote_calls_for_afc.py +130 -0
  59. google/genai/tests/afc/test_invoke_function_from_dict_args.py +241 -0
  60. google/genai/tests/afc/test_raise_error_for_afc_incompatible_config.py +159 -0
  61. google/genai/tests/afc/test_should_append_afc_history.py +53 -0
  62. google/genai/tests/afc/test_should_disable_afc.py +214 -0
  63. google/genai/tests/batches/__init__.py +17 -0
  64. google/genai/tests/batches/test_cancel.py +77 -0
  65. google/genai/tests/batches/test_create.py +78 -0
  66. google/genai/tests/batches/test_create_with_bigquery.py +113 -0
  67. google/genai/tests/batches/test_create_with_file.py +82 -0
  68. google/genai/tests/batches/test_create_with_gcs.py +125 -0
  69. google/genai/tests/batches/test_create_with_inlined_requests.py +255 -0
  70. google/genai/tests/batches/test_delete.py +86 -0
  71. google/genai/tests/batches/test_embedding.py +157 -0
  72. google/genai/tests/batches/test_get.py +78 -0
  73. google/genai/tests/batches/test_list.py +79 -0
  74. google/genai/tests/caches/__init__.py +17 -0
  75. google/genai/tests/caches/constants.py +29 -0
  76. google/genai/tests/caches/test_create.py +210 -0
  77. google/genai/tests/caches/test_create_custom_url.py +105 -0
  78. google/genai/tests/caches/test_delete.py +54 -0
  79. google/genai/tests/caches/test_delete_custom_url.py +52 -0
  80. google/genai/tests/caches/test_get.py +94 -0
  81. google/genai/tests/caches/test_get_custom_url.py +52 -0
  82. google/genai/tests/caches/test_list.py +68 -0
  83. google/genai/tests/caches/test_update.py +70 -0
  84. google/genai/tests/caches/test_update_custom_url.py +58 -0
  85. google/genai/tests/chats/__init__.py +1 -0
  86. google/genai/tests/chats/test_get_history.py +598 -0
  87. google/genai/tests/chats/test_send_message.py +844 -0
  88. google/genai/tests/chats/test_validate_response.py +90 -0
  89. google/genai/tests/client/__init__.py +17 -0
  90. google/genai/tests/client/test_async_stream.py +427 -0
  91. google/genai/tests/client/test_client_close.py +197 -0
  92. google/genai/tests/client/test_client_initialization.py +1687 -0
  93. google/genai/tests/client/test_client_requests.py +221 -0
  94. google/genai/tests/client/test_custom_client.py +104 -0
  95. google/genai/tests/client/test_http_options.py +178 -0
  96. google/genai/tests/client/test_replay_client_equality.py +168 -0
  97. google/genai/tests/client/test_retries.py +846 -0
  98. google/genai/tests/client/test_upload_errors.py +136 -0
  99. google/genai/tests/common/__init__.py +17 -0
  100. google/genai/tests/common/test_common.py +954 -0
  101. google/genai/tests/conftest.py +162 -0
  102. google/genai/tests/documents/__init__.py +17 -0
  103. google/genai/tests/documents/test_delete.py +51 -0
  104. google/genai/tests/documents/test_get.py +85 -0
  105. google/genai/tests/documents/test_list.py +72 -0
  106. google/genai/tests/errors/__init__.py +1 -0
  107. google/genai/tests/errors/test_api_error.py +417 -0
  108. google/genai/tests/file_search_stores/__init__.py +17 -0
  109. google/genai/tests/file_search_stores/test_create.py +66 -0
  110. google/genai/tests/file_search_stores/test_delete.py +64 -0
  111. google/genai/tests/file_search_stores/test_get.py +94 -0
  112. google/genai/tests/file_search_stores/test_import_file.py +112 -0
  113. google/genai/tests/file_search_stores/test_list.py +57 -0
  114. google/genai/tests/file_search_stores/test_upload_to_file_search_store.py +141 -0
  115. google/genai/tests/files/__init__.py +17 -0
  116. google/genai/tests/files/test_delete.py +46 -0
  117. google/genai/tests/files/test_download.py +85 -0
  118. google/genai/tests/files/test_get.py +46 -0
  119. google/genai/tests/files/test_list.py +72 -0
  120. google/genai/tests/files/test_register.py +272 -0
  121. google/genai/tests/files/test_register_table.py +70 -0
  122. google/genai/tests/files/test_upload.py +255 -0
  123. google/genai/tests/imports/test_no_optional_imports.py +28 -0
  124. google/genai/tests/interactions/test_auth.py +476 -0
  125. google/genai/tests/interactions/test_integration.py +84 -0
  126. google/genai/tests/interactions/test_paths.py +105 -0
  127. google/genai/tests/live/__init__.py +16 -0
  128. google/genai/tests/live/test_live.py +2143 -0
  129. google/genai/tests/live/test_live_music.py +362 -0
  130. google/genai/tests/live/test_live_response.py +163 -0
  131. google/genai/tests/live/test_send_client_content.py +147 -0
  132. google/genai/tests/live/test_send_realtime_input.py +268 -0
  133. google/genai/tests/live/test_send_tool_response.py +222 -0
  134. google/genai/tests/local_tokenizer/__init__.py +17 -0
  135. google/genai/tests/local_tokenizer/test_local_tokenizer.py +343 -0
  136. google/genai/tests/local_tokenizer/test_local_tokenizer_loader.py +235 -0
  137. google/genai/tests/mcp/__init__.py +17 -0
  138. google/genai/tests/mcp/test_has_mcp_tool_usage.py +89 -0
  139. google/genai/tests/mcp/test_mcp_to_gemini_tools.py +191 -0
  140. google/genai/tests/mcp/test_parse_config_for_mcp_sessions.py +201 -0
  141. google/genai/tests/mcp/test_parse_config_for_mcp_usage.py +130 -0
  142. google/genai/tests/mcp/test_set_mcp_usage_header.py +72 -0
  143. google/genai/tests/models/__init__.py +17 -0
  144. google/genai/tests/models/constants.py +8 -0
  145. google/genai/tests/models/test_compute_tokens.py +120 -0
  146. google/genai/tests/models/test_count_tokens.py +159 -0
  147. google/genai/tests/models/test_delete.py +107 -0
  148. google/genai/tests/models/test_edit_image.py +264 -0
  149. google/genai/tests/models/test_embed_content.py +94 -0
  150. google/genai/tests/models/test_function_call_streaming.py +442 -0
  151. google/genai/tests/models/test_generate_content.py +2501 -0
  152. google/genai/tests/models/test_generate_content_cached_content.py +132 -0
  153. google/genai/tests/models/test_generate_content_config_zero_value.py +103 -0
  154. google/genai/tests/models/test_generate_content_from_apikey.py +44 -0
  155. google/genai/tests/models/test_generate_content_http_options.py +40 -0
  156. google/genai/tests/models/test_generate_content_image_generation.py +143 -0
  157. google/genai/tests/models/test_generate_content_mcp.py +343 -0
  158. google/genai/tests/models/test_generate_content_media_resolution.py +97 -0
  159. google/genai/tests/models/test_generate_content_model.py +139 -0
  160. google/genai/tests/models/test_generate_content_part.py +821 -0
  161. google/genai/tests/models/test_generate_content_thought.py +76 -0
  162. google/genai/tests/models/test_generate_content_tools.py +1761 -0
  163. google/genai/tests/models/test_generate_images.py +191 -0
  164. google/genai/tests/models/test_generate_videos.py +759 -0
  165. google/genai/tests/models/test_get.py +104 -0
  166. google/genai/tests/models/test_list.py +233 -0
  167. google/genai/tests/models/test_recontext_image.py +189 -0
  168. google/genai/tests/models/test_segment_image.py +148 -0
  169. google/genai/tests/models/test_update.py +95 -0
  170. google/genai/tests/models/test_upscale_image.py +157 -0
  171. google/genai/tests/operations/__init__.py +17 -0
  172. google/genai/tests/operations/test_get.py +38 -0
  173. google/genai/tests/public_samples/__init__.py +17 -0
  174. google/genai/tests/public_samples/test_gemini_text_only.py +34 -0
  175. google/genai/tests/pytest_helper.py +246 -0
  176. google/genai/tests/shared/__init__.py +16 -0
  177. google/genai/tests/shared/batches/__init__.py +14 -0
  178. google/genai/tests/shared/batches/test_create_delete.py +57 -0
  179. google/genai/tests/shared/batches/test_create_get_cancel.py +56 -0
  180. google/genai/tests/shared/batches/test_list.py +40 -0
  181. google/genai/tests/shared/caches/__init__.py +14 -0
  182. google/genai/tests/shared/caches/test_create_get_delete.py +67 -0
  183. google/genai/tests/shared/caches/test_create_update_get.py +71 -0
  184. google/genai/tests/shared/caches/test_list.py +40 -0
  185. google/genai/tests/shared/chats/__init__.py +14 -0
  186. google/genai/tests/shared/chats/test_send_message.py +48 -0
  187. google/genai/tests/shared/chats/test_send_message_stream.py +50 -0
  188. google/genai/tests/shared/files/__init__.py +14 -0
  189. google/genai/tests/shared/files/test_list.py +41 -0
  190. google/genai/tests/shared/files/test_upload_get_delete.py +54 -0
  191. google/genai/tests/shared/models/__init__.py +14 -0
  192. google/genai/tests/shared/models/test_compute_tokens.py +41 -0
  193. google/genai/tests/shared/models/test_count_tokens.py +40 -0
  194. google/genai/tests/shared/models/test_edit_image.py +67 -0
  195. google/genai/tests/shared/models/test_embed.py +40 -0
  196. google/genai/tests/shared/models/test_generate_content.py +39 -0
  197. google/genai/tests/shared/models/test_generate_content_stream.py +54 -0
  198. google/genai/tests/shared/models/test_generate_images.py +40 -0
  199. google/genai/tests/shared/models/test_generate_videos.py +38 -0
  200. google/genai/tests/shared/models/test_list.py +37 -0
  201. google/genai/tests/shared/models/test_recontext_image.py +55 -0
  202. google/genai/tests/shared/models/test_segment_image.py +52 -0
  203. google/genai/tests/shared/models/test_upscale_image.py +52 -0
  204. google/genai/tests/shared/tunings/__init__.py +16 -0
  205. google/genai/tests/shared/tunings/test_create.py +46 -0
  206. google/genai/tests/shared/tunings/test_create_get_cancel.py +56 -0
  207. google/genai/tests/shared/tunings/test_list.py +39 -0
  208. google/genai/tests/tokens/__init__.py +16 -0
  209. google/genai/tests/tokens/test_create.py +154 -0
  210. google/genai/tests/transformers/__init__.py +17 -0
  211. google/genai/tests/transformers/test_blobs.py +84 -0
  212. google/genai/tests/transformers/test_bytes.py +15 -0
  213. google/genai/tests/transformers/test_duck_type.py +96 -0
  214. google/genai/tests/transformers/test_function_responses.py +72 -0
  215. google/genai/tests/transformers/test_schema.py +653 -0
  216. google/genai/tests/transformers/test_t_batch.py +286 -0
  217. google/genai/tests/transformers/test_t_content.py +160 -0
  218. google/genai/tests/transformers/test_t_contents.py +398 -0
  219. google/genai/tests/transformers/test_t_part.py +85 -0
  220. google/genai/tests/transformers/test_t_parts.py +87 -0
  221. google/genai/tests/transformers/test_t_tool.py +157 -0
  222. google/genai/tests/transformers/test_t_tools.py +195 -0
  223. google/genai/tests/tunings/__init__.py +16 -0
  224. google/genai/tests/tunings/test_cancel.py +39 -0
  225. google/genai/tests/tunings/test_end_to_end.py +106 -0
  226. google/genai/tests/tunings/test_get.py +67 -0
  227. google/genai/tests/tunings/test_list.py +75 -0
  228. google/genai/tests/tunings/test_tune.py +268 -0
  229. google/genai/tests/types/__init__.py +16 -0
  230. google/genai/tests/types/test_bytes_internal.py +271 -0
  231. google/genai/tests/types/test_bytes_type.py +152 -0
  232. google/genai/tests/types/test_future.py +101 -0
  233. google/genai/tests/types/test_optional_types.py +36 -0
  234. google/genai/tests/types/test_part_type.py +616 -0
  235. google/genai/tests/types/test_schema_from_json_schema.py +417 -0
  236. google/genai/tests/types/test_schema_json_schema.py +468 -0
  237. google/genai/tests/types/test_types.py +2903 -0
  238. google/genai/types.py +631 -488
  239. google/genai/version.py +1 -1
  240. {google_genai-1.56.0.dist-info → google_genai-1.58.0.dist-info}/METADATA +6 -11
  241. google_genai-1.58.0.dist-info/RECORD +358 -0
  242. google_genai-1.56.0.dist-info/RECORD +0 -162
  243. /google/genai/{_interactions/py.typed → tests/interactions/__init__.py} +0 -0
  244. {google_genai-1.56.0.dist-info → google_genai-1.58.0.dist-info}/WHEEL +0 -0
  245. {google_genai-1.56.0.dist-info → google_genai-1.58.0.dist-info}/licenses/LICENSE +0 -0
  246. {google_genai-1.56.0.dist-info → google_genai-1.58.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,191 @@
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
+ from ... import _mcp_utils
17
+ from ... import types
18
+
19
+ try:
20
+ from mcp import types as mcp_types
21
+ except ImportError as e:
22
+ import sys
23
+
24
+ if sys.version_info < (3, 10):
25
+ raise ImportError(
26
+ 'MCP Tool requires Python 3.10 or above. Please upgrade your Python'
27
+ ' version.'
28
+ ) from e
29
+ else:
30
+ raise e
31
+
32
+
33
+ def test_empty_mcp_tools_list():
34
+ """Test conversion of empty MCP tools list to Gemini tools list."""
35
+ result = _mcp_utils.mcp_to_gemini_tools([])
36
+
37
+ assert result == []
38
+
39
+
40
+ def test_unknown_field_conversion():
41
+ """Test conversion of MCP tools with unknown fields to Gemini tools."""
42
+ mcp_tools = [
43
+ mcp_types.Tool(
44
+ name='tool',
45
+ description='tool-description',
46
+ inputSchema={
47
+ 'type': 'object',
48
+ 'properties': {},
49
+ 'unknown_field': 'unknownField',
50
+ 'unknown_object': {},
51
+ },
52
+ ),
53
+ ]
54
+ result = _mcp_utils.mcp_to_gemini_tools(mcp_tools)
55
+ assert result == [
56
+ types.Tool(
57
+ function_declarations=[
58
+ types.FunctionDeclaration(
59
+ name='tool',
60
+ description='tool-description',
61
+ parameters=types.Schema(
62
+ type='OBJECT',
63
+ properties={},
64
+ ),
65
+ ),
66
+ ],
67
+ ),
68
+ ]
69
+
70
+
71
+ def test_items_conversion():
72
+ """Test conversion of MCP tools with items to Gemini tools."""
73
+ mcp_tools = [
74
+ mcp_types.Tool(
75
+ name='tool',
76
+ description='tool-description',
77
+ inputSchema={
78
+ 'type': 'array',
79
+ 'items': {
80
+ 'type': 'object',
81
+ 'properties': {
82
+ 'key1': {
83
+ 'type': 'string',
84
+ },
85
+ 'key2': {
86
+ 'type': 'number',
87
+ },
88
+ },
89
+ },
90
+ },
91
+ ),
92
+ ]
93
+ result = _mcp_utils.mcp_to_gemini_tools(mcp_tools)
94
+ assert result == [
95
+ types.Tool(
96
+ function_declarations=[
97
+ types.FunctionDeclaration(
98
+ name='tool',
99
+ description='tool-description',
100
+ parameters=types.Schema(
101
+ type='ARRAY',
102
+ items=types.Schema(
103
+ type='OBJECT',
104
+ properties={
105
+ 'key1': types.Schema(type='STRING'),
106
+ 'key2': types.Schema(type='NUMBER'),
107
+ },
108
+ ),
109
+ ),
110
+ ),
111
+ ],
112
+ ),
113
+ ]
114
+
115
+
116
+ def test_any_of_conversion():
117
+ """Test conversion of MCP tools with any_of to Gemini tools."""
118
+ mcp_tools = [
119
+ mcp_types.Tool(
120
+ name='tool',
121
+ description='tool-description',
122
+ inputSchema={
123
+ 'type': 'object',
124
+ 'any_of': [
125
+ {
126
+ 'type': 'string',
127
+ },
128
+ {
129
+ 'type': 'number',
130
+ },
131
+ ],
132
+ },
133
+ ),
134
+ ]
135
+ result = _mcp_utils.mcp_to_gemini_tools(mcp_tools)
136
+ assert result == [
137
+ types.Tool(
138
+ function_declarations=[
139
+ types.FunctionDeclaration(
140
+ name='tool',
141
+ description='tool-description',
142
+ parameters=types.Schema(
143
+ type='OBJECT',
144
+ any_of=[
145
+ types.Schema(type='STRING'),
146
+ types.Schema(type='NUMBER'),
147
+ ],
148
+ ),
149
+ ),
150
+ ],
151
+ ),
152
+ ]
153
+
154
+
155
+ def test_properties_conversion():
156
+ """Test conversion of MCP tools with properties to Gemini tools."""
157
+ mcp_tools = [
158
+ mcp_types.Tool(
159
+ name='tool',
160
+ description='tool-description',
161
+ inputSchema={
162
+ 'type': 'object',
163
+ 'properties': {
164
+ 'key1': {
165
+ 'type': 'string',
166
+ },
167
+ 'key2': {
168
+ 'type': 'number',
169
+ },
170
+ },
171
+ },
172
+ ),
173
+ ]
174
+ result = _mcp_utils.mcp_to_gemini_tools(mcp_tools)
175
+ assert result == [
176
+ types.Tool(
177
+ function_declarations=[
178
+ types.FunctionDeclaration(
179
+ name='tool',
180
+ description='tool-description',
181
+ parameters=types.Schema(
182
+ type='OBJECT',
183
+ properties={
184
+ 'key1': types.Schema(type='STRING'),
185
+ 'key2': types.Schema(type='NUMBER'),
186
+ },
187
+ ),
188
+ ),
189
+ ],
190
+ ),
191
+ ]
@@ -0,0 +1,201 @@
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
+ import _asyncio
17
+ import pytest
18
+ from ... import _extra_utils
19
+ from ... import types
20
+ from ..._adapters import McpToGenAiToolAdapter
21
+
22
+ try:
23
+ from mcp import types as mcp_types
24
+ from mcp import ClientSession as McpClientSession
25
+ except ImportError as e:
26
+ import sys
27
+
28
+ if sys.version_info < (3, 10):
29
+ raise ImportError(
30
+ 'MCP Tool requires Python 3.10 or above. Please upgrade your Python'
31
+ ' version.'
32
+ ) from e
33
+ else:
34
+ raise e
35
+
36
+
37
+ @pytest.mark.asyncio
38
+ async def test_parse_empty_config_dict():
39
+ """Test conversion of empty GenerateContentConfigDict to parsed config."""
40
+ config = {}
41
+ parsed_config, mcp_to_genai_tool_adapters = (
42
+ await _extra_utils.parse_config_for_mcp_sessions(config)
43
+ )
44
+ assert parsed_config == None
45
+ assert not mcp_to_genai_tool_adapters
46
+
47
+
48
+ @pytest.mark.asyncio
49
+ async def test_parse_empty_config_object():
50
+ """Test conversion of empty GenerateContentConfig to parsed config."""
51
+ config = types.GenerateContentConfig()
52
+ parsed_config, mcp_to_genai_tool_adapters = (
53
+ await _extra_utils.parse_config_for_mcp_sessions(config)
54
+ )
55
+ assert config is not parsed_config # config is not modified
56
+ assert not mcp_to_genai_tool_adapters
57
+
58
+
59
+ @pytest.mark.asyncio
60
+ async def test_parse_config_object_with_tools():
61
+ """Test conversion of GenerateContentConfig with tools to parsed config."""
62
+
63
+ class MockMcpClientSession(McpClientSession):
64
+
65
+ def __init__(self):
66
+ self._read_stream = None
67
+ self._write_stream = None
68
+
69
+ async def list_tools(self):
70
+ return mcp_types.ListToolsResult(
71
+ tools=[
72
+ mcp_types.Tool(
73
+ name='get_weather',
74
+ description='Get the weather in a city.',
75
+ inputSchema={
76
+ 'type': 'object',
77
+ 'properties': {'location': {'type': 'string'}},
78
+ },
79
+ ),
80
+ mcp_types.Tool(
81
+ name='get_weather_2',
82
+ description='Different tool to get the weather.',
83
+ inputSchema={
84
+ 'type': 'object',
85
+ 'properties': {'location': {'type': 'string'}},
86
+ },
87
+ ),
88
+ ]
89
+ )
90
+
91
+ mock_session_instance = MockMcpClientSession()
92
+ config = types.GenerateContentConfig(tools=[mock_session_instance])
93
+ parsed_config, mcp_to_genai_tool_adapters = (
94
+ await _extra_utils.parse_config_for_mcp_sessions(config)
95
+ )
96
+ assert len(config.tools) == 1
97
+ assert config.tools[0] is mock_session_instance
98
+ assert config is not parsed_config # config is not modified
99
+ assert len(mcp_to_genai_tool_adapters) == 2
100
+ assert mcp_to_genai_tool_adapters.keys() == {
101
+ 'get_weather',
102
+ 'get_weather_2',
103
+ }
104
+ assert isinstance(
105
+ mcp_to_genai_tool_adapters['get_weather'], McpToGenAiToolAdapter
106
+ )
107
+ assert isinstance(
108
+ mcp_to_genai_tool_adapters['get_weather_2'], McpToGenAiToolAdapter
109
+ )
110
+
111
+
112
+ @pytest.mark.asyncio
113
+ async def test_parse_config_object_with_tools_complex_type():
114
+ """Test conversion of GenerateContentConfig with tools to parsed config."""
115
+
116
+ class MockMcpClientSession(McpClientSession):
117
+
118
+ def __init__(self):
119
+ self._read_stream = None
120
+ self._write_stream = None
121
+ self._future = _asyncio.Future() # This object cannot be pickled.
122
+
123
+ async def list_tools(self):
124
+ return mcp_types.ListToolsResult(
125
+ tools=[
126
+ mcp_types.Tool(
127
+ name='get_weather',
128
+ description='Get the weather in a city.',
129
+ inputSchema={
130
+ 'type': 'object',
131
+ 'properties': {'location': {'type': 'string'}},
132
+ },
133
+ ),
134
+ mcp_types.Tool(
135
+ name='get_weather_2',
136
+ description='Different tool to get the weather.',
137
+ inputSchema={
138
+ 'type': 'object',
139
+ 'properties': {'location': {'type': 'string'}},
140
+ },
141
+ ),
142
+ ]
143
+ )
144
+
145
+ mock_session_instance = MockMcpClientSession()
146
+ config = types.GenerateContentConfig(tools=[mock_session_instance])
147
+ parsed_config, mcp_to_genai_tool_adapters = (
148
+ await _extra_utils.parse_config_for_mcp_sessions(config)
149
+ )
150
+ assert len(config.tools) == 1
151
+ assert config.tools[0] is mock_session_instance
152
+ assert config is not parsed_config # config is not modified
153
+ assert len(mcp_to_genai_tool_adapters) == 2
154
+ assert mcp_to_genai_tool_adapters.keys() == {
155
+ 'get_weather',
156
+ 'get_weather_2',
157
+ }
158
+ assert isinstance(
159
+ mcp_to_genai_tool_adapters['get_weather'], McpToGenAiToolAdapter
160
+ )
161
+ assert isinstance(
162
+ mcp_to_genai_tool_adapters['get_weather_2'], McpToGenAiToolAdapter
163
+ )
164
+
165
+
166
+ @pytest.mark.asyncio
167
+ async def test_parse_config_object_with_non_mcp_tools():
168
+ """Test conversion of GenerateContentConfig with regular tools to parsed config."""
169
+
170
+ config = types.GenerateContentConfig(
171
+ tools=[
172
+ types.Tool(
173
+ function_declarations=[
174
+ {'name': 'tool-1', 'description': 'tool-1-description'}
175
+ ]
176
+ ),
177
+ types.Tool(
178
+ function_declarations=[
179
+ {'name': 'tool-2', 'description': 'tool-2-description'}
180
+ ]
181
+ ),
182
+ ]
183
+ )
184
+ parsed_config, mcp_to_genai_tool_adapters = (
185
+ await _extra_utils.parse_config_for_mcp_sessions(config)
186
+ )
187
+ assert len(config.tools) == 2
188
+ assert config is not parsed_config # config is not modified
189
+ assert mcp_to_genai_tool_adapters == {}
190
+ assert parsed_config.tools == [
191
+ types.Tool(
192
+ function_declarations=[
193
+ {'name': 'tool-1', 'description': 'tool-1-description'}
194
+ ]
195
+ ),
196
+ types.Tool(
197
+ function_declarations=[
198
+ {'name': 'tool-2', 'description': 'tool-2-description'}
199
+ ]
200
+ ),
201
+ ]
@@ -0,0 +1,130 @@
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
+ import re
17
+ import pytest
18
+ from ... import _extra_utils
19
+ from ... import types
20
+ from ..._adapters import McpToGenAiToolAdapter
21
+
22
+ try:
23
+ from mcp import types as mcp_types
24
+ from mcp import ClientSession as McpClientSession
25
+ except ImportError as e:
26
+ import sys
27
+
28
+ if sys.version_info < (3, 10):
29
+ raise ImportError(
30
+ 'MCP Tool requires Python 3.10 or above. Please upgrade your Python'
31
+ ' version.'
32
+ ) from e
33
+ else:
34
+ raise e
35
+
36
+
37
+ def test_parse_empty_config_dict():
38
+ """Test conversion of empty GenerateContentConfigDict to parsed config."""
39
+ config = {}
40
+ parsed_config = _extra_utils.parse_config_for_mcp_usage(config)
41
+ assert parsed_config == None
42
+
43
+
44
+ def test_parse_empty_config_object():
45
+ """Test conversion of empty GenerateContentConfig to parsed config."""
46
+ config = types.GenerateContentConfig()
47
+ parsed_config = _extra_utils.parse_config_for_mcp_usage(config)
48
+ assert config is not parsed_config # config is not modified
49
+
50
+
51
+ def test_parse_config_object_with_tools():
52
+ """Test conversion of GenerateContentConfig with tools to parsed config."""
53
+
54
+ class MockMcpClientSession(McpClientSession):
55
+
56
+ def __init__(self):
57
+ self._read_stream = None
58
+ self._write_stream = None
59
+
60
+ async def list_tools(self):
61
+ return mcp_types.ListToolsResult(
62
+ tools=[
63
+ mcp_types.Tool(
64
+ name='get_weather',
65
+ description='Get the weather in a city.',
66
+ inputSchema={
67
+ 'type': 'object',
68
+ 'properties': {'location': {'type': 'string'}},
69
+ },
70
+ ),
71
+ mcp_types.Tool(
72
+ name='get_weather_2',
73
+ description='Different tool to get the weather.',
74
+ inputSchema={
75
+ 'type': 'object',
76
+ 'properties': {'location': {'type': 'string'}},
77
+ },
78
+ ),
79
+ ]
80
+ )
81
+
82
+ mock_session_instance = MockMcpClientSession()
83
+ config = types.GenerateContentConfig(tools=[mock_session_instance])
84
+ parsed_config = _extra_utils.parse_config_for_mcp_usage(config)
85
+ assert config.http_options is None
86
+ assert config is not parsed_config # config is not modified
87
+ assert re.match(
88
+ r'mcp_used/\d+\.\d+\.\d+',
89
+ parsed_config.http_options.headers['x-goog-api-client'],
90
+ )
91
+
92
+
93
+ def test_parse_config_object_with_tools_and_existing_headers():
94
+ """Test conversion of GenerateContentConfig with tools and existing headers to parsed config."""
95
+
96
+ config = types.GenerateContentConfig(
97
+ tools=[
98
+ mcp_types.Tool(
99
+ name='get_weather',
100
+ description='Get the weather in a city.',
101
+ inputSchema={
102
+ 'type': 'object',
103
+ 'properties': {'location': {'type': 'string'}},
104
+ },
105
+ ),
106
+ mcp_types.Tool(
107
+ name='get_weather_2',
108
+ description='Different tool to get the weather.',
109
+ inputSchema={
110
+ 'type': 'object',
111
+ 'properties': {'location': {'type': 'string'}},
112
+ },
113
+ ),
114
+ ],
115
+ http_options=types.HttpOptions(
116
+ headers={
117
+ 'x-goog-api-client': 'google-genai-sdk/1.0.0 gl-python/1.0.0'
118
+ }
119
+ ),
120
+ )
121
+ parsed_config = _extra_utils.parse_config_for_mcp_usage(config)
122
+ assert not re.match(
123
+ r'mcp_used/\d+\.\d+\.\d+',
124
+ config.http_options.headers['x-goog-api-client'],
125
+ )
126
+ assert config is not parsed_config # config is not modified
127
+ assert re.match(
128
+ r'google-genai-sdk/1.0.0 gl-python/1.0.0 mcp_used/\d+\.\d+\.\d+',
129
+ parsed_config.http_options.headers['x-goog-api-client'],
130
+ )
@@ -0,0 +1,72 @@
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
+ from importlib.metadata import version
17
+ import re
18
+ import typing
19
+ from typing import Any
20
+
21
+ from ... import _mcp_utils
22
+ from ... import types
23
+
24
+ _is_mcp_imported = False
25
+ if typing.TYPE_CHECKING:
26
+ import mcp
27
+
28
+ _is_mcp_imported = True
29
+ else:
30
+ try:
31
+ import mcp
32
+
33
+ _is_mcp_imported = True
34
+ except ImportError:
35
+ _is_mcp_imported = False
36
+
37
+
38
+ def test_set_mcp_usage_header_from_empty_dict():
39
+ if not _is_mcp_imported:
40
+ return
41
+ """Test whether the MCP usage header is set correctly from an empty dict."""
42
+ headers = {}
43
+ _mcp_utils.set_mcp_usage_header(headers)
44
+ assert re.match(r'mcp_used/\d+\.\d+\.\d+', headers['x-goog-api-client'])
45
+
46
+
47
+ def test_set_mcp_usage_header_with_existing_header():
48
+ if not _is_mcp_imported:
49
+ return
50
+ """Test whether the MCP usage header is set correctly from an existing header."""
51
+ headers = {'x-goog-api-client': 'google-genai-sdk/1.0.0 gl-python/1.0.0'}
52
+ _mcp_utils.set_mcp_usage_header(headers)
53
+ assert re.match(
54
+ r'google-genai-sdk/1.0.0 gl-python/1.0.0 mcp_used/\d+\.\d+\.\d+',
55
+ headers['x-goog-api-client'],
56
+ )
57
+
58
+
59
+ def test_set_mcp_usage_header_with_existing_mcp_header():
60
+ if not _is_mcp_imported:
61
+ return
62
+ """Test whether the MCP usage header is set correctly from an existing MCP header."""
63
+ headers = {
64
+ 'x-goog-api-client': (
65
+ 'google-genai-sdk/1.0.0 gl-python/1.0.0 mcp_used/1.0.0'
66
+ )
67
+ }
68
+ _mcp_utils.set_mcp_usage_header(headers)
69
+ assert re.match(
70
+ r'google-genai-sdk/1.0.0 gl-python/1.0.0 mcp_used/\d+\.\d+\.\d+',
71
+ headers['x-goog-api-client'],
72
+ )
@@ -0,0 +1,17 @@
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 models module."""
@@ -0,0 +1,8 @@
1
+ VERTEX_HTTP_OPTIONS = {
2
+ 'api_version': 'v1beta1',
3
+ 'base_url': 'https://us-central1-aiplatform.googleapis.com/',
4
+ }
5
+ MLDEV_HTTP_OPTIONS = {
6
+ 'api_version': 'v1beta',
7
+ 'base_url': 'https://generativelanguage.googleapis.com/',
8
+ }