google-genai 1.33.0__py3-none-any.whl → 1.53.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 +361 -208
- google/genai/_common.py +260 -69
- google/genai/_extra_utils.py +142 -12
- google/genai/_live_converters.py +691 -2746
- google/genai/_local_tokenizer_loader.py +0 -9
- google/genai/_operations_converters.py +186 -99
- google/genai/_replay_api_client.py +48 -51
- google/genai/_tokens_converters.py +169 -489
- google/genai/_transformers.py +193 -90
- google/genai/batches.py +1014 -1307
- google/genai/caches.py +458 -1107
- google/genai/client.py +101 -0
- google/genai/documents.py +532 -0
- google/genai/errors.py +58 -4
- google/genai/file_search_stores.py +1296 -0
- google/genai/files.py +108 -358
- google/genai/live.py +90 -32
- google/genai/live_music.py +24 -27
- google/genai/local_tokenizer.py +36 -3
- google/genai/models.py +2308 -3375
- google/genai/operations.py +129 -21
- google/genai/pagers.py +7 -1
- google/genai/tokens.py +2 -12
- google/genai/tunings.py +770 -436
- google/genai/types.py +4341 -1218
- google/genai/version.py +1 -1
- {google_genai-1.33.0.dist-info → google_genai-1.53.0.dist-info}/METADATA +359 -201
- google_genai-1.53.0.dist-info/RECORD +41 -0
- google_genai-1.33.0.dist-info/RECORD +0 -39
- {google_genai-1.33.0.dist-info → google_genai-1.53.0.dist-info}/WHEEL +0 -0
- {google_genai-1.33.0.dist-info → google_genai-1.53.0.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.33.0.dist-info → google_genai-1.53.0.dist-info}/top_level.txt +0 -0
google/genai/_extra_utils.py
CHANGED
|
@@ -15,12 +15,15 @@
|
|
|
15
15
|
|
|
16
16
|
"""Extra utils depending on types that are shared between sync and async modules."""
|
|
17
17
|
|
|
18
|
+
import asyncio
|
|
18
19
|
import inspect
|
|
20
|
+
import io
|
|
19
21
|
import logging
|
|
20
22
|
import sys
|
|
21
23
|
import typing
|
|
22
24
|
from typing import Any, Callable, Dict, Optional, Union, get_args, get_origin
|
|
23
|
-
|
|
25
|
+
import mimetypes
|
|
26
|
+
import os
|
|
24
27
|
import pydantic
|
|
25
28
|
|
|
26
29
|
from . import _common
|
|
@@ -90,14 +93,12 @@ def _get_bigquery_uri(
|
|
|
90
93
|
|
|
91
94
|
|
|
92
95
|
def format_destination(
|
|
93
|
-
src: Union[str, types.
|
|
94
|
-
config: Optional[types.
|
|
96
|
+
src: Union[str, types.BatchJobSource],
|
|
97
|
+
config: Optional[types.CreateBatchJobConfig] = None,
|
|
95
98
|
) -> types.CreateBatchJobConfig:
|
|
96
99
|
"""Formats the destination uri based on the source uri for Vertex AI."""
|
|
97
|
-
config
|
|
98
|
-
|
|
99
|
-
or types.CreateBatchJobConfig()
|
|
100
|
-
)
|
|
100
|
+
if config is None:
|
|
101
|
+
config = types.CreateBatchJobConfig()
|
|
101
102
|
|
|
102
103
|
unique_name = None
|
|
103
104
|
if not config.display_name:
|
|
@@ -113,11 +114,39 @@ def format_destination(
|
|
|
113
114
|
elif bigquery_source_uri:
|
|
114
115
|
unique_name = unique_name or _common.timestamped_unique_name()
|
|
115
116
|
config.dest = f'{bigquery_source_uri}_dest_{unique_name}'
|
|
116
|
-
|
|
117
|
-
raise ValueError(f'The source {src} is not supported.')
|
|
117
|
+
|
|
118
118
|
return config
|
|
119
119
|
|
|
120
120
|
|
|
121
|
+
def find_afc_incompatible_tool_indexes(
|
|
122
|
+
config: Optional[types.GenerateContentConfigOrDict] = None,
|
|
123
|
+
) -> list[int]:
|
|
124
|
+
"""Checks if the config contains any AFC incompatible tools.
|
|
125
|
+
|
|
126
|
+
A `types.Tool` object that contains `function_declarations` is considered a
|
|
127
|
+
non-AFC tool for this execution path.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
config: The GenerateContentConfig to check for incompatible tools.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
A list of indexes of the incompatible tools in the config.
|
|
134
|
+
"""
|
|
135
|
+
if not config:
|
|
136
|
+
return []
|
|
137
|
+
config_model = _create_generate_content_config_model(config)
|
|
138
|
+
incompatible_tools_indexes: list[int] = []
|
|
139
|
+
|
|
140
|
+
if not config_model or not config_model.tools:
|
|
141
|
+
return incompatible_tools_indexes
|
|
142
|
+
|
|
143
|
+
for index, tool in enumerate(config_model.tools):
|
|
144
|
+
if isinstance(tool, types.Tool) and tool.function_declarations:
|
|
145
|
+
incompatible_tools_indexes.append(index)
|
|
146
|
+
|
|
147
|
+
return incompatible_tools_indexes
|
|
148
|
+
|
|
149
|
+
|
|
121
150
|
def get_function_map(
|
|
122
151
|
config: Optional[types.GenerateContentConfigOrDict] = None,
|
|
123
152
|
mcp_to_genai_tool_adapters: Optional[
|
|
@@ -372,7 +401,9 @@ async def get_function_response_parts_async(
|
|
|
372
401
|
}
|
|
373
402
|
else:
|
|
374
403
|
func_response = {
|
|
375
|
-
'result':
|
|
404
|
+
'result': await asyncio.to_thread(
|
|
405
|
+
invoke_function_from_dict_args, args, func
|
|
406
|
+
)
|
|
376
407
|
}
|
|
377
408
|
except Exception as e: # pylint: disable=broad-except
|
|
378
409
|
func_response = {'error': str(e)}
|
|
@@ -458,6 +489,31 @@ def get_max_remote_calls_afc(
|
|
|
458
489
|
return int(config_model.automatic_function_calling.maximum_remote_calls)
|
|
459
490
|
|
|
460
491
|
|
|
492
|
+
def raise_error_for_afc_incompatible_config(config: Optional[types.GenerateContentConfig]
|
|
493
|
+
) -> None:
|
|
494
|
+
"""Raises an error if the config is not compatible with AFC."""
|
|
495
|
+
if (
|
|
496
|
+
not config
|
|
497
|
+
or not config.tool_config
|
|
498
|
+
or not config.tool_config.function_calling_config
|
|
499
|
+
):
|
|
500
|
+
return
|
|
501
|
+
afc_config = config.automatic_function_calling
|
|
502
|
+
disable_afc_config = afc_config.disable if afc_config else False
|
|
503
|
+
stream_function_call = (
|
|
504
|
+
config.tool_config.function_calling_config.stream_function_call_arguments
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
if stream_function_call and not disable_afc_config:
|
|
508
|
+
raise ValueError(
|
|
509
|
+
'Running in streaming mode with stream_function_call_arguments'
|
|
510
|
+
' enabled, this feature is not compatible with automatic function'
|
|
511
|
+
' calling (AFC). Please set config.automatic_function_calling.disable'
|
|
512
|
+
' to True to disable AFC or leave config.tool_config.'
|
|
513
|
+
' function_calling_config.stream_function_call_arguments to be empty'
|
|
514
|
+
' or set to False to disable streaming function call arguments.'
|
|
515
|
+
)
|
|
516
|
+
|
|
461
517
|
def should_append_afc_history(
|
|
462
518
|
config: Optional[types.GenerateContentConfigOrDict] = None,
|
|
463
519
|
) -> bool:
|
|
@@ -537,10 +593,84 @@ async def parse_config_for_mcp_sessions(
|
|
|
537
593
|
def append_chunk_contents(
|
|
538
594
|
contents: Union[types.ContentListUnion, types.ContentListUnionDict],
|
|
539
595
|
chunk: types.GenerateContentResponse,
|
|
540
|
-
) ->
|
|
541
|
-
"""Appends the contents of the chunk to the contents list."""
|
|
596
|
+
) -> Union[types.ContentListUnion, types.ContentListUnionDict]:
|
|
597
|
+
"""Appends the contents of the chunk to the contents list and returns it."""
|
|
542
598
|
if chunk is not None and chunk.candidates is not None:
|
|
543
599
|
chunk_content = chunk.candidates[0].content
|
|
544
600
|
contents = t.t_contents(contents) # type: ignore[assignment]
|
|
545
601
|
if isinstance(contents, list) and chunk_content is not None:
|
|
546
602
|
contents.append(chunk_content) # type: ignore[arg-type]
|
|
603
|
+
return contents
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
def prepare_resumable_upload(
|
|
607
|
+
file: Union[str, os.PathLike[str], io.IOBase],
|
|
608
|
+
user_http_options: Optional[types.HttpOptionsOrDict] = None,
|
|
609
|
+
user_mime_type: Optional[str] = None,
|
|
610
|
+
) -> tuple[
|
|
611
|
+
types.HttpOptions,
|
|
612
|
+
int,
|
|
613
|
+
str,
|
|
614
|
+
]:
|
|
615
|
+
"""Prepares the HTTP options, file bytes size and mime type for a resumable upload.
|
|
616
|
+
|
|
617
|
+
This function inspects a file (from a path or an in-memory object) to
|
|
618
|
+
determine its size and MIME type. It then constructs the necessary HTTP
|
|
619
|
+
headers and options required to initiate a resumable upload session.
|
|
620
|
+
"""
|
|
621
|
+
size_bytes = None
|
|
622
|
+
mime_type = user_mime_type
|
|
623
|
+
if isinstance(file, io.IOBase):
|
|
624
|
+
if mime_type is None:
|
|
625
|
+
raise ValueError(
|
|
626
|
+
'Unknown mime type: Could not determine the mimetype for your'
|
|
627
|
+
' file\n please set the `mime_type` argument'
|
|
628
|
+
)
|
|
629
|
+
if hasattr(file, 'mode'):
|
|
630
|
+
if 'b' not in file.mode:
|
|
631
|
+
raise ValueError('The file must be opened in binary mode.')
|
|
632
|
+
offset = file.tell()
|
|
633
|
+
file.seek(0, os.SEEK_END)
|
|
634
|
+
size_bytes = file.tell() - offset
|
|
635
|
+
file.seek(offset, os.SEEK_SET)
|
|
636
|
+
else:
|
|
637
|
+
fs_path = os.fspath(file)
|
|
638
|
+
if not fs_path or not os.path.isfile(fs_path):
|
|
639
|
+
raise FileNotFoundError(f'{file} is not a valid file path.')
|
|
640
|
+
size_bytes = os.path.getsize(fs_path)
|
|
641
|
+
if mime_type is None:
|
|
642
|
+
mime_type, _ = mimetypes.guess_type(fs_path)
|
|
643
|
+
if mime_type is None:
|
|
644
|
+
raise ValueError(
|
|
645
|
+
'Unknown mime type: Could not determine the mimetype for your'
|
|
646
|
+
' file\n please set the `mime_type` argument'
|
|
647
|
+
)
|
|
648
|
+
http_options: types.HttpOptions
|
|
649
|
+
if user_http_options:
|
|
650
|
+
if isinstance(user_http_options, dict):
|
|
651
|
+
user_http_options = types.HttpOptions(**user_http_options)
|
|
652
|
+
http_options = user_http_options
|
|
653
|
+
http_options.api_version = ''
|
|
654
|
+
http_options.headers = {
|
|
655
|
+
'Content-Type': 'application/json',
|
|
656
|
+
'X-Goog-Upload-Protocol': 'resumable',
|
|
657
|
+
'X-Goog-Upload-Command': 'start',
|
|
658
|
+
'X-Goog-Upload-Header-Content-Length': f'{size_bytes}',
|
|
659
|
+
'X-Goog-Upload-Header-Content-Type': f'{mime_type}',
|
|
660
|
+
}
|
|
661
|
+
else:
|
|
662
|
+
http_options = types.HttpOptions(
|
|
663
|
+
api_version='',
|
|
664
|
+
headers={
|
|
665
|
+
'Content-Type': 'application/json',
|
|
666
|
+
'X-Goog-Upload-Protocol': 'resumable',
|
|
667
|
+
'X-Goog-Upload-Command': 'start',
|
|
668
|
+
'X-Goog-Upload-Header-Content-Length': f'{size_bytes}',
|
|
669
|
+
'X-Goog-Upload-Header-Content-Type': f'{mime_type}',
|
|
670
|
+
},
|
|
671
|
+
)
|
|
672
|
+
if isinstance(file, (str, os.PathLike)):
|
|
673
|
+
if http_options.headers is None:
|
|
674
|
+
http_options.headers = {}
|
|
675
|
+
http_options.headers['X-Goog-Upload-File-Name'] = os.path.basename(file)
|
|
676
|
+
return http_options, size_bytes, mime_type
|