google-genai 1.0.0rc0__py3-none-any.whl → 1.1.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.
@@ -99,6 +99,19 @@ class HttpRequest:
99
99
  timeout: Optional[float] = None
100
100
 
101
101
 
102
+ # TODO(b/394358912): Update this class to use a SDKResponse class that can be
103
+ # generated and used for all languages.
104
+ @dataclass
105
+ class BaseResponse:
106
+ http_headers: dict[str, str]
107
+
108
+ @property
109
+ def dict(self) -> dict[str, Any]:
110
+ if isinstance(self, dict):
111
+ return self
112
+ return {'httpHeaders': self.http_headers}
113
+
114
+
102
115
  class HttpResponse:
103
116
 
104
117
  def __init__(
@@ -434,18 +447,12 @@ class ApiClient:
434
447
  http_method, path, request_dict, http_options
435
448
  )
436
449
  response = self._request(http_request, stream=False)
437
- if http_options:
438
- if (
439
- isinstance(http_options, HttpOptions)
440
- and http_options.deprecated_response_payload is not None
441
- ):
442
- response._copy_to_dict(http_options.deprecated_response_payload)
443
- elif (
444
- isinstance(http_options, dict)
445
- and 'deprecated_response_payload' in http_options
446
- ):
447
- response._copy_to_dict(http_options['deprecated_response_payload'])
448
- return response.json
450
+ json_response = response.json
451
+ if not json_response:
452
+ base_response = BaseResponse(response.headers).dict
453
+ return base_response
454
+
455
+ return json_response
449
456
 
450
457
  def request_streamed(
451
458
  self,
@@ -459,10 +466,6 @@ class ApiClient:
459
466
  )
460
467
 
461
468
  session_response = self._request(http_request, stream=True)
462
- if http_options and 'deprecated_response_payload' in http_options:
463
- session_response._copy_to_dict(
464
- http_options['deprecated_response_payload']
465
- )
466
469
  for chunk in session_response.segments():
467
470
  yield chunk
468
471
 
@@ -478,9 +481,11 @@ class ApiClient:
478
481
  )
479
482
 
480
483
  result = await self._async_request(http_request=http_request, stream=False)
481
- if http_options and 'deprecated_response_payload' in http_options:
482
- result._copy_to_dict(http_options['deprecated_response_payload'])
483
- return result.json
484
+ json_response = result.json
485
+ if not json_response:
486
+ base_response = BaseResponse(result.headers).dict
487
+ return base_response
488
+ return json_response
484
489
 
485
490
  async def async_request_streamed(
486
491
  self,
@@ -495,8 +500,6 @@ class ApiClient:
495
500
 
496
501
  response = await self._async_request(http_request=http_request, stream=True)
497
502
 
498
- if http_options and 'deprecated_response_payload' in http_options:
499
- response._copy_to_dict(http_options['deprecated_response_payload'])
500
503
  async def async_generator():
501
504
  async for chunk in response:
502
505
  yield chunk
@@ -17,10 +17,14 @@ import inspect
17
17
  import sys
18
18
  import types as builtin_types
19
19
  import typing
20
- from typing import Any, Callable, Literal, Union, _GenericAlias, get_args, get_origin
20
+ from typing import _GenericAlias, Any, Callable, get_args, get_origin, Literal, Union
21
+
21
22
  import pydantic
23
+
24
+ from . import _extra_utils
22
25
  from . import types
23
26
 
27
+
24
28
  if sys.version_info >= (3, 10):
25
29
  VersionedUnionType = builtin_types.UnionType
26
30
  else:
@@ -58,8 +62,8 @@ def _raise_for_default_if_mldev(schema: types.Schema):
58
62
  )
59
63
 
60
64
 
61
- def _raise_if_schema_unsupported(client, schema: types.Schema):
62
- if not client.vertexai:
65
+ def _raise_if_schema_unsupported(api_option: Literal['VERTEX_AI', 'GEMINI_API'], schema: types.Schema):
66
+ if api_option == 'GEMINI_API':
63
67
  _raise_for_any_of_if_mldev(schema)
64
68
  _raise_for_default_if_mldev(schema)
65
69
 
@@ -110,7 +114,7 @@ def _is_default_value_compatible(
110
114
 
111
115
 
112
116
  def _parse_schema_from_parameter(
113
- client,
117
+ api_option: Literal['VERTEX_AI', 'GEMINI_API'],
114
118
  param: inspect.Parameter,
115
119
  func_name: str,
116
120
  ) -> types.Schema:
@@ -130,7 +134,7 @@ def _parse_schema_from_parameter(
130
134
  raise ValueError(default_value_error_msg)
131
135
  schema.default = param.default
132
136
  schema.type = _py_builtin_type_to_schema_type[param.annotation]
133
- _raise_if_schema_unsupported(client, schema)
137
+ _raise_if_schema_unsupported(api_option, schema)
134
138
  return schema
135
139
  if (
136
140
  isinstance(param.annotation, VersionedUnionType)
@@ -149,7 +153,7 @@ def _parse_schema_from_parameter(
149
153
  schema.nullable = True
150
154
  continue
151
155
  schema_in_any_of = _parse_schema_from_parameter(
152
- client,
156
+ api_option,
153
157
  inspect.Parameter(
154
158
  'item', inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=arg
155
159
  ),
@@ -171,7 +175,7 @@ def _parse_schema_from_parameter(
171
175
  if not _is_default_value_compatible(param.default, param.annotation):
172
176
  raise ValueError(default_value_error_msg)
173
177
  schema.default = param.default
174
- _raise_if_schema_unsupported(client, schema)
178
+ _raise_if_schema_unsupported(api_option, schema)
175
179
  return schema
176
180
  if isinstance(param.annotation, _GenericAlias) or isinstance(
177
181
  param.annotation, builtin_types.GenericAlias
@@ -184,7 +188,7 @@ def _parse_schema_from_parameter(
184
188
  if not _is_default_value_compatible(param.default, param.annotation):
185
189
  raise ValueError(default_value_error_msg)
186
190
  schema.default = param.default
187
- _raise_if_schema_unsupported(client, schema)
191
+ _raise_if_schema_unsupported(api_option, schema)
188
192
  return schema
189
193
  if origin is Literal:
190
194
  if not all(isinstance(arg, str) for arg in args):
@@ -197,12 +201,12 @@ def _parse_schema_from_parameter(
197
201
  if not _is_default_value_compatible(param.default, param.annotation):
198
202
  raise ValueError(default_value_error_msg)
199
203
  schema.default = param.default
200
- _raise_if_schema_unsupported(client, schema)
204
+ _raise_if_schema_unsupported(api_option, schema)
201
205
  return schema
202
206
  if origin is list:
203
207
  schema.type = 'ARRAY'
204
208
  schema.items = _parse_schema_from_parameter(
205
- client,
209
+ api_option,
206
210
  inspect.Parameter(
207
211
  'item',
208
212
  inspect.Parameter.POSITIONAL_OR_KEYWORD,
@@ -214,7 +218,7 @@ def _parse_schema_from_parameter(
214
218
  if not _is_default_value_compatible(param.default, param.annotation):
215
219
  raise ValueError(default_value_error_msg)
216
220
  schema.default = param.default
217
- _raise_if_schema_unsupported(client, schema)
221
+ _raise_if_schema_unsupported(api_option, schema)
218
222
  return schema
219
223
  if origin is Union:
220
224
  schema.any_of = []
@@ -229,7 +233,7 @@ def _parse_schema_from_parameter(
229
233
  schema.nullable = True
230
234
  continue
231
235
  schema_in_any_of = _parse_schema_from_parameter(
232
- client,
236
+ api_option,
233
237
  inspect.Parameter(
234
238
  'item',
235
239
  inspect.Parameter.POSITIONAL_OR_KEYWORD,
@@ -264,13 +268,12 @@ def _parse_schema_from_parameter(
264
268
  if not _is_default_value_compatible(param.default, param.annotation):
265
269
  raise ValueError(default_value_error_msg)
266
270
  schema.default = param.default
267
- _raise_if_schema_unsupported(client, schema)
271
+ _raise_if_schema_unsupported(api_option, schema)
268
272
  return schema
269
273
  # all other generic alias will be invoked in raise branch
270
274
  if (
271
- inspect.isclass(param.annotation)
272
275
  # for user defined class, we only support pydantic model
273
- and issubclass(param.annotation, pydantic.BaseModel)
276
+ _extra_utils.is_annotation_pydantic_model(param.annotation)
274
277
  ):
275
278
  if (
276
279
  param.default is not inspect.Parameter.empty
@@ -281,7 +284,7 @@ def _parse_schema_from_parameter(
281
284
  schema.properties = {}
282
285
  for field_name, field_info in param.annotation.model_fields.items():
283
286
  schema.properties[field_name] = _parse_schema_from_parameter(
284
- client,
287
+ api_option,
285
288
  inspect.Parameter(
286
289
  field_name,
287
290
  inspect.Parameter.POSITIONAL_OR_KEYWORD,
@@ -289,9 +292,9 @@ def _parse_schema_from_parameter(
289
292
  ),
290
293
  func_name,
291
294
  )
292
- if client.vertexai:
295
+ if api_option == 'VERTEX_AI':
293
296
  schema.required = _get_required_fields(schema)
294
- _raise_if_schema_unsupported(client, schema)
297
+ _raise_if_schema_unsupported(api_option, schema)
295
298
  return schema
296
299
  raise ValueError(
297
300
  f'Failed to parse the parameter {param} of function {func_name} for'
google/genai/_common.py CHANGED
@@ -18,6 +18,7 @@
18
18
  import base64
19
19
  import datetime
20
20
  import enum
21
+ import functools
21
22
  import typing
22
23
  from typing import Union
23
24
  import uuid
@@ -27,6 +28,7 @@ import pydantic
27
28
  from pydantic import alias_generators
28
29
 
29
30
  from . import _api_client
31
+ from . import errors
30
32
 
31
33
 
32
34
  def set_value_by_path(data, keys, value):
@@ -218,7 +220,8 @@ class CaseInSensitiveEnum(str, enum.Enum):
218
220
  warnings.warn(f"{value} is not a valid {cls.__name__}")
219
221
  try:
220
222
  # Creating a enum instance based on the value
221
- unknown_enum_val = cls._new_member_(cls) # pylint: disable=protected-access,attribute-error
223
+ # We need to use super() to avoid infinite recursion.
224
+ unknown_enum_val = super().__new__(cls, value)
222
225
  unknown_enum_val._name_ = str(value) # pylint: disable=protected-access
223
226
  unknown_enum_val._value_ = value # pylint: disable=protected-access
224
227
  return unknown_enum_val
@@ -273,3 +276,23 @@ def encode_unserializable_types(data: dict[str, object]) -> dict[str, object]:
273
276
  else:
274
277
  processed_data[key] = value
275
278
  return processed_data
279
+
280
+
281
+ def experimental_warning(message: str):
282
+ """Experimental warning, only warns once."""
283
+ def decorator(func):
284
+ warning_done = False
285
+ @functools.wraps(func)
286
+ def wrapper(*args, **kwargs):
287
+ nonlocal warning_done
288
+ if not warning_done:
289
+ warning_done = True
290
+ warnings.warn(
291
+ message=message,
292
+ category=errors.ExperimentalWarning,
293
+ stacklevel=2,
294
+ )
295
+ return func(*args, **kwargs)
296
+ return wrapper
297
+ return decorator
298
+
@@ -108,16 +108,22 @@ def convert_number_values_for_function_call_args(
108
108
  return args
109
109
 
110
110
 
111
- def _is_annotation_pydantic_model(annotation: Any) -> bool:
112
- return inspect.isclass(annotation) and issubclass(
113
- annotation, pydantic.BaseModel
114
- )
111
+ def is_annotation_pydantic_model(annotation: Any) -> bool:
112
+ try:
113
+ return inspect.isclass(annotation) and issubclass(
114
+ annotation, pydantic.BaseModel
115
+ )
116
+ # for python 3.10 and below, inspect.isclass(annotation) has inconsistent
117
+ # results with versions above. for example, inspect.isclass(dict[str, int]) is
118
+ # True in 3.10 and below but False in 3.11 and above.
119
+ except TypeError:
120
+ return False
115
121
 
116
122
 
117
123
  def convert_if_exist_pydantic_model(
118
124
  value: Any, annotation: Any, param_name: str, func_name: str
119
125
  ) -> Any:
120
- if isinstance(value, dict) and _is_annotation_pydantic_model(annotation):
126
+ if isinstance(value, dict) and is_annotation_pydantic_model(annotation):
121
127
  try:
122
128
  return annotation(**value)
123
129
  except pydantic.ValidationError as e:
@@ -146,7 +152,7 @@ def convert_if_exist_pydantic_model(
146
152
  if (
147
153
  (get_args(arg) and get_origin(arg) is list)
148
154
  or isinstance(value, arg)
149
- or (isinstance(value, dict) and _is_annotation_pydantic_model(arg))
155
+ or (isinstance(value, dict) and is_annotation_pydantic_model(arg))
150
156
  ):
151
157
  try:
152
158
  return convert_if_exist_pydantic_model(
@@ -265,8 +271,8 @@ def should_disable_afc(
265
271
  and int(config_model.automatic_function_calling.maximum_remote_calls) > 0
266
272
  ):
267
273
  logging.warning(
268
- '`automatic_function_calling.disable` is set to `True`. But'
269
- ' `automatic_function_calling.maximum_remote_calls` is set to be a'
274
+ '`automatic_function_calling.disable` is set to `True`. And'
275
+ ' `automatic_function_calling.maximum_remote_calls` is a'
270
276
  ' positive number'
271
277
  f' {config_model.automatic_function_calling.maximum_remote_calls}.'
272
278
  ' Disabling automatic function calling. If you want to enable'
@@ -362,6 +362,8 @@ class ReplayApiClient(ApiClient):
362
362
  if self._should_update_replay():
363
363
  if isinstance(response_model, list):
364
364
  response_model = response_model[0]
365
+ if response_model and 'http_headers' in response_model.model_fields:
366
+ response_model.http_headers.pop('Date', None)
365
367
  interaction.response.sdk_response_segments.append(
366
368
  response_model.model_dump(exclude_none=True)
367
369
  )
@@ -374,8 +374,8 @@ def handle_null_fields(schema: dict[str, Any]):
374
374
  schema['anyOf'].remove({'type': 'null'})
375
375
  if len(schema['anyOf']) == 1:
376
376
  # If there is only one type left after removing null, remove the anyOf field.
377
- field_type = schema['anyOf'][0]['type']
378
- schema['type'] = field_type
377
+ for key,val in schema['anyOf'][0].items():
378
+ schema[key] = val
379
379
  del schema['anyOf']
380
380
 
381
381
 
@@ -446,9 +446,17 @@ def process_schema(
446
446
 
447
447
  if schema.get('default') is not None:
448
448
  raise ValueError(
449
- 'Default value is not supported in the response schema for the Gemmini API.'
449
+ 'Default value is not supported in the response schema for the Gemini API.'
450
450
  )
451
451
 
452
+ if schema.get('title') == 'PlaceholderLiteralEnum':
453
+ schema.pop('title', None)
454
+
455
+ # If a dict is provided directly to response_schema, it may use `any_of`
456
+ # instead of `anyOf`. Otherwise model_json_schema() uses `anyOf`
457
+ if schema.get('any_of', None) is not None:
458
+ schema['anyOf'] = schema.pop('any_of')
459
+
452
460
  if defs is None:
453
461
  defs = schema.pop('$defs', {})
454
462
  for _, sub_schema in defs.items():
@@ -456,6 +464,15 @@ def process_schema(
456
464
 
457
465
  handle_null_fields(schema)
458
466
 
467
+ # After removing null fields, Optional fields with only one possible type
468
+ # will have a $ref key that needs to be flattened
469
+ # For example: {'default': None, 'description': 'Name of the person', 'nullable': True, '$ref': '#/$defs/TestPerson'}
470
+ if schema.get('$ref', None):
471
+ ref = defs[schema.get('$ref').split('defs/')[-1]]
472
+ for schema_key in list(ref.keys()):
473
+ schema[schema_key] = ref[schema_key]
474
+ del schema['$ref']
475
+
459
476
  any_of = schema.get('anyOf', None)
460
477
  if any_of is not None:
461
478
  if not client.vertexai:
@@ -478,6 +495,16 @@ def process_schema(
478
495
  schema_type = schema_type.value
479
496
  schema_type = schema_type.upper()
480
497
 
498
+ # model_json_schema() returns a schema with a 'const' field when a Literal with one value is provided as a pydantic field
499
+ # For example `genre: Literal['action']` becomes: {'const': 'action', 'title': 'Genre', 'type': 'string'}
500
+ const = schema.get('const', None)
501
+ if const is not None:
502
+ if schema_type == 'STRING':
503
+ schema['enum'] = [const]
504
+ del schema['const']
505
+ else:
506
+ raise ValueError('Literal values must be strings.')
507
+
481
508
  if schema_type == 'OBJECT':
482
509
  properties = schema.get('properties', None)
483
510
  if properties is None:
@@ -502,6 +529,7 @@ def process_schema(
502
529
  process_schema(ref, client, defs)
503
530
  schema['items'] = ref
504
531
 
532
+
505
533
  def _process_enum(
506
534
  enum: EnumMeta, client: Optional[_api_client.ApiClient] = None
507
535
  ) -> types.Schema:
google/genai/chats.py CHANGED
@@ -57,12 +57,16 @@ class Chat(_BaseChat):
57
57
  """Chat session."""
58
58
 
59
59
  def send_message(
60
- self, message: Union[list[PartUnionDict], PartUnionDict]
60
+ self,
61
+ message: Union[list[PartUnionDict], PartUnionDict],
62
+ config: Optional[GenerateContentConfigOrDict] = None,
61
63
  ) -> GenerateContentResponse:
62
64
  """Sends the conversation history with the additional message and returns the model's response.
63
65
 
64
66
  Args:
65
67
  message: The message to send to the model.
68
+ config: Optional config to override the default Chat config for this
69
+ request.
66
70
 
67
71
  Returns:
68
72
  The model's response.
@@ -79,7 +83,7 @@ class Chat(_BaseChat):
79
83
  response = self._modules.generate_content(
80
84
  model=self._model,
81
85
  contents=self._curated_history + [input_content],
82
- config=self._config,
86
+ config=config if config else self._config,
83
87
  )
84
88
  if _validate_response(response):
85
89
  if response.automatic_function_calling_history:
@@ -92,12 +96,16 @@ class Chat(_BaseChat):
92
96
  return response
93
97
 
94
98
  def send_message_stream(
95
- self, message: Union[list[PartUnionDict], PartUnionDict]
99
+ self,
100
+ message: Union[list[PartUnionDict], PartUnionDict],
101
+ config: Optional[GenerateContentConfigOrDict] = None,
96
102
  ):
97
103
  """Sends the conversation history with the additional message and yields the model's response in chunks.
98
104
 
99
105
  Args:
100
106
  message: The message to send to the model.
107
+ config: Optional config to override the default Chat config for this
108
+ request.
101
109
 
102
110
  Yields:
103
111
  The model's response in chunks.
@@ -117,7 +125,7 @@ class Chat(_BaseChat):
117
125
  for chunk in self._modules.generate_content_stream(
118
126
  model=self._model,
119
127
  contents=self._curated_history + [input_content],
120
- config=self._config,
128
+ config=config if config else self._config,
121
129
  ):
122
130
  if _validate_response(chunk):
123
131
  output_contents.append(chunk.candidates[0].content)
@@ -164,12 +172,16 @@ class AsyncChat(_BaseChat):
164
172
  """Async chat session."""
165
173
 
166
174
  async def send_message(
167
- self, message: Union[list[PartUnionDict], PartUnionDict]
175
+ self,
176
+ message: Union[list[PartUnionDict], PartUnionDict],
177
+ config: Optional[GenerateContentConfigOrDict] = None,
168
178
  ) -> GenerateContentResponse:
169
179
  """Sends the conversation history with the additional message and returns model's response.
170
180
 
171
181
  Args:
172
182
  message: The message to send to the model.
183
+ config: Optional config to override the default Chat config for this
184
+ request.
173
185
 
174
186
  Returns:
175
187
  The model's response.
@@ -186,7 +198,7 @@ class AsyncChat(_BaseChat):
186
198
  response = await self._modules.generate_content(
187
199
  model=self._model,
188
200
  contents=self._curated_history + [input_content],
189
- config=self._config,
201
+ config=config if config else self._config,
190
202
  )
191
203
  if _validate_response(response):
192
204
  if response.automatic_function_calling_history:
@@ -199,12 +211,16 @@ class AsyncChat(_BaseChat):
199
211
  return response
200
212
 
201
213
  async def send_message_stream(
202
- self, message: Union[list[PartUnionDict], PartUnionDict]
214
+ self,
215
+ message: Union[list[PartUnionDict], PartUnionDict],
216
+ config: Optional[GenerateContentConfigOrDict] = None,
203
217
  ) -> Awaitable[AsyncIterator[GenerateContentResponse]]:
204
218
  """Sends the conversation history with the additional message and yields the model's response in chunks.
205
219
 
206
220
  Args:
207
221
  message: The message to send to the model.
222
+ config: Optional config to override the default Chat config for this
223
+ request.
208
224
 
209
225
  Yields:
210
226
  The model's response in chunks.
@@ -225,7 +241,7 @@ class AsyncChat(_BaseChat):
225
241
  async for chunk in await self._modules.generate_content_stream(
226
242
  model=self._model,
227
243
  contents=self._curated_history + [input_content],
228
- config=self._config,
244
+ config=config if config else self._config,
229
245
  ):
230
246
  if _validate_response(chunk):
231
247
  output_contents.append(chunk.candidates[0].content)
google/genai/errors.py CHANGED
@@ -128,3 +128,7 @@ class FunctionInvocationError(ValueError):
128
128
  """Raised when the function cannot be invoked with the given arguments."""
129
129
 
130
130
  pass
131
+
132
+
133
+ class ExperimentalWarning(Warning):
134
+ """Warning for experimental features."""
google/genai/files.py CHANGED
@@ -494,6 +494,8 @@ def _CreateFileResponse_from_mldev(
494
494
  parent_object: dict = None,
495
495
  ) -> dict:
496
496
  to_object = {}
497
+ if getv(from_object, ['httpHeaders']) is not None:
498
+ setv(to_object, ['http_headers'], getv(from_object, ['httpHeaders']))
497
499
 
498
500
  return to_object
499
501
 
@@ -504,6 +506,8 @@ def _CreateFileResponse_from_vertex(
504
506
  parent_object: dict = None,
505
507
  ) -> dict:
506
508
  to_object = {}
509
+ if getv(from_object, ['httpHeaders']) is not None:
510
+ setv(to_object, ['http_headers'], getv(from_object, ['httpHeaders']))
507
511
 
508
512
  return to_object
509
513
 
@@ -840,7 +844,7 @@ class Files(_api_module.BaseModule):
840
844
  'Unknown mime type: Could not determine the mimetype for your'
841
845
  ' file\n please set the `mime_type` argument'
842
846
  )
843
- response = {}
847
+
844
848
  if config_model and config_model.http_options:
845
849
  http_options = config_model.http_options
846
850
  else:
@@ -853,19 +857,20 @@ class Files(_api_module.BaseModule):
853
857
  'X-Goog-Upload-Header-Content-Length': f'{file_obj.size_bytes}',
854
858
  'X-Goog-Upload-Header-Content-Type': f'{file_obj.mime_type}',
855
859
  },
856
- 'deprecated_response_payload': response,
857
860
  }
858
- self._create(file=file_obj, config={'http_options': http_options})
861
+ response = self._create(
862
+ file=file_obj, config={'http_options': http_options}
863
+ )
859
864
 
860
865
  if (
861
- 'headers' not in response
862
- or 'X-Goog-Upload-URL' not in response['headers']
866
+ response.http_headers is None
867
+ or 'X-Goog-Upload-URL' not in response.http_headers
863
868
  ):
864
869
  raise KeyError(
865
870
  'Failed to create file. Upload URL did not returned from the create'
866
871
  ' file request.'
867
872
  )
868
- upload_url = response['headers']['X-Goog-Upload-URL']
873
+ upload_url = response.http_headers['X-Goog-Upload-URL']
869
874
 
870
875
  if isinstance(file, io.IOBase):
871
876
  return_file = self._api_client.upload_file(
@@ -1272,7 +1277,6 @@ class AsyncFiles(_api_module.BaseModule):
1272
1277
  ' file\n please set the `mime_type` argument'
1273
1278
  )
1274
1279
 
1275
- response = {}
1276
1280
  if config_model and config_model.http_options:
1277
1281
  http_options = config_model.http_options
1278
1282
  else:
@@ -1285,18 +1289,20 @@ class AsyncFiles(_api_module.BaseModule):
1285
1289
  'X-Goog-Upload-Header-Content-Length': f'{file_obj.size_bytes}',
1286
1290
  'X-Goog-Upload-Header-Content-Type': f'{file_obj.mime_type}',
1287
1291
  },
1288
- 'deprecated_response_payload': response,
1289
1292
  }
1290
- await self._create(file=file_obj, config={'http_options': http_options})
1293
+ response = await self._create(
1294
+ file=file_obj, config={'http_options': http_options}
1295
+ )
1296
+
1291
1297
  if (
1292
- 'headers' not in response
1293
- or 'X-Goog-Upload-URL' not in response['headers']
1298
+ response.http_headers is None
1299
+ or 'X-Goog-Upload-URL' not in response.http_headers
1294
1300
  ):
1295
1301
  raise KeyError(
1296
1302
  'Failed to create file. Upload URL did not returned from the create'
1297
1303
  ' file request.'
1298
1304
  )
1299
- upload_url = response['headers']['X-Goog-Upload-URL']
1305
+ upload_url = response.http_headers['X-Goog-Upload-URL']
1300
1306
 
1301
1307
  if isinstance(file, io.IOBase):
1302
1308
  return_file = await self._api_client.async_upload_file(
google/genai/live.py CHANGED
@@ -29,8 +29,10 @@ from . import _api_module
29
29
  from . import _common
30
30
  from . import _transformers as t
31
31
  from . import client
32
+ from . import errors
32
33
  from . import types
33
34
  from ._api_client import ApiClient
35
+ from ._common import experimental_warning
34
36
  from ._common import get_value_by_path as getv
35
37
  from ._common import set_value_by_path as setv
36
38
  from .models import _Content_from_mldev
@@ -633,6 +635,9 @@ class AsyncLive(_api_module.BaseModule):
633
635
  return_value['setup'].update(to_object)
634
636
  return return_value
635
637
 
638
+ @experimental_warning(
639
+ "The live API is experimental and may change in future versions.",
640
+ )
636
641
  @contextlib.asynccontextmanager
637
642
  async def connect(
638
643
  self,