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.
- google/genai/_api_client.py +24 -21
- google/genai/_automatic_function_calling_util.py +21 -18
- google/genai/_common.py +24 -1
- google/genai/_extra_utils.py +14 -8
- google/genai/_replay_api_client.py +2 -0
- google/genai/_transformers.py +31 -3
- google/genai/chats.py +24 -8
- google/genai/errors.py +4 -0
- google/genai/files.py +18 -12
- google/genai/live.py +5 -0
- google/genai/models.py +311 -10
- google/genai/tunings.py +224 -60
- google/genai/types.py +100 -74
- google/genai/version.py +1 -1
- {google_genai-1.0.0rc0.dist-info → google_genai-1.1.0.dist-info}/METADATA +258 -149
- google_genai-1.1.0.dist-info/RECORD +27 -0
- google_genai-1.0.0rc0.dist-info/RECORD +0 -27
- {google_genai-1.0.0rc0.dist-info → google_genai-1.1.0.dist-info}/LICENSE +0 -0
- {google_genai-1.0.0rc0.dist-info → google_genai-1.1.0.dist-info}/WHEEL +0 -0
- {google_genai-1.0.0rc0.dist-info → google_genai-1.1.0.dist-info}/top_level.txt +0 -0
google/genai/_api_client.py
CHANGED
@@ -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
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
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
|
-
|
482
|
-
|
483
|
-
|
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,
|
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(
|
62
|
-
if
|
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
|
-
|
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(
|
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
|
-
|
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(
|
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(
|
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(
|
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
|
-
|
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(
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
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
|
295
|
+
if api_option == 'VERTEX_AI':
|
293
296
|
schema.required = _get_required_fields(schema)
|
294
|
-
_raise_if_schema_unsupported(
|
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
|
-
|
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
|
+
|
google/genai/_extra_utils.py
CHANGED
@@ -108,16 +108,22 @@ def convert_number_values_for_function_call_args(
|
|
108
108
|
return args
|
109
109
|
|
110
110
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
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
|
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
|
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`.
|
269
|
-
' `automatic_function_calling.maximum_remote_calls` is
|
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
|
)
|
google/genai/_transformers.py
CHANGED
@@ -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
|
-
|
378
|
-
|
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
|
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,
|
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,
|
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,
|
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,
|
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
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
|
-
|
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(
|
861
|
+
response = self._create(
|
862
|
+
file=file_obj, config={'http_options': http_options}
|
863
|
+
)
|
859
864
|
|
860
865
|
if (
|
861
|
-
|
862
|
-
or 'X-Goog-Upload-URL' not in response
|
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['
|
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(
|
1293
|
+
response = await self._create(
|
1294
|
+
file=file_obj, config={'http_options': http_options}
|
1295
|
+
)
|
1296
|
+
|
1291
1297
|
if (
|
1292
|
-
|
1293
|
-
or 'X-Goog-Upload-URL' not in response
|
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['
|
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,
|