From 62ac432d1767fca36187d9c49668e3a6dc93a5bf Mon Sep 17 00:00:00 2001 From: Wanlin Du Date: Mon, 1 Jun 2026 17:31:48 -0700 Subject: [PATCH] chore: remove unused code PiperOrigin-RevId: 925002599 --- google/genai/_interactions/__init__.py | 120 - google/genai/_interactions/_base_client.py | 2152 ----------------- google/genai/_interactions/_client.py | 659 ----- google/genai/_interactions/_client_adapter.py | 41 - google/genai/_interactions/_compat.py | 241 -- google/genai/_interactions/_constants.py | 29 - google/genai/_interactions/_exceptions.py | 126 - google/genai/_interactions/_files.py | 189 -- google/genai/_interactions/_legacy_lyria.py | 251 -- google/genai/_interactions/_models.py | 968 -------- google/genai/_interactions/_qs.py | 164 -- google/genai/_interactions/_resource.py | 58 - google/genai/_interactions/_response.py | 850 ------- google/genai/_interactions/_streaming.py | 359 --- google/genai/_interactions/_types.py | 288 --- google/genai/_interactions/_utils/__init__.py | 79 - google/genai/_interactions/_utils/_compat.py | 61 - .../_interactions/_utils/_datetime_parse.py | 151 -- google/genai/_interactions/_utils/_json.py | 50 - google/genai/_interactions/_utils/_logs.py | 40 - google/genai/_interactions/_utils/_path.py | 142 -- google/genai/_interactions/_utils/_proxy.py | 80 - .../genai/_interactions/_utils/_reflection.py | 57 - .../_interactions/_utils/_resources_proxy.py | 39 - google/genai/_interactions/_utils/_streams.py | 27 - google/genai/_interactions/_utils/_sync.py | 73 - .../genai/_interactions/_utils/_transform.py | 472 ---- google/genai/_interactions/_utils/_typing.py | 172 -- google/genai/_interactions/_utils/_utils.py | 449 ---- google/genai/_interactions/_version.py | 18 - .../genai/_interactions/resources/__init__.py | 62 - .../genai/_interactions/resources/agents.py | 532 ---- .../_interactions/resources/interactions.py | 1656 ------------- .../genai/_interactions/resources/webhooks.py | 969 -------- google/genai/_interactions/types/__init__.py | 145 -- google/genai/_interactions/types/agent.py | 113 - .../types/agent_create_params.py | 101 - .../types/agent_delete_response.py | 34 - .../_interactions/types/agent_list_params.py | 32 - .../types/agent_list_response.py | 29 - .../_interactions/types/allowed_tools.py | 33 - .../types/allowed_tools_param.py | 35 - .../genai/_interactions/types/annotation.py | 28 - .../_interactions/types/annotation_param.py | 29 - .../_interactions/types/audio_content.py | 59 - .../types/audio_content_param.py | 64 - .../types/audio_response_format.py | 46 - .../types/audio_response_format_param.py | 43 - .../types/code_execution_call_arguments.py | 33 - .../types/code_execution_call_step.py | 48 - .../types/code_execution_call_step_param.py | 55 - .../types/code_execution_result_step.py | 41 - .../types/code_execution_result_step_param.py | 48 - google/genai/_interactions/types/content.py | 32 - .../_interactions/types/content_param.py | 33 - .../types/deep_research_agent_config.py | 46 - .../types/deep_research_agent_config_param.py | 45 - .../_interactions/types/document_content.py | 38 - .../types/document_content_param.py | 45 - .../types/dynamic_agent_config.py | 43 - .../types/dynamic_agent_config_param.py | 28 - .../genai/_interactions/types/environment.py | 89 - .../_interactions/types/environment_param.py | 89 - .../genai/_interactions/types/error_event.py | 56 - .../_interactions/types/file_citation.py | 56 - .../types/file_citation_param.py | 56 - .../types/file_search_call_step.py | 35 - .../types/file_search_call_step_param.py | 42 - .../types/file_search_result_step.py | 35 - .../types/file_search_result_step_param.py | 42 - google/genai/_interactions/types/function.py | 38 - .../_interactions/types/function_call_step.py | 38 - .../types/function_call_step_param.py | 38 - .../_interactions/types/function_param.py | 37 - .../types/function_result_step.py | 49 - .../types/function_result_step_param.py | 47 - .../_interactions/types/generation_config.py | 78 - .../types/generation_config_param.py | 80 - .../types/google_maps_call_arguments.py | 29 - .../types/google_maps_call_step.py | 45 - .../types/google_maps_call_step_param.py | 52 - .../_interactions/types/google_maps_result.py | 65 - .../types/google_maps_result_step.py | 71 - .../types/google_maps_result_step_param.py | 78 - .../types/google_search_call_arguments.py | 29 - .../types/google_search_call_step.py | 48 - .../types/google_search_call_step_param.py | 55 - .../types/google_search_result.py | 29 - .../types/google_search_result_step.py | 48 - .../types/google_search_result_step_param.py | 55 - .../genai/_interactions/types/image_config.py | 33 - .../_interactions/types/image_config_param.py | 32 - .../_interactions/types/image_content.py | 45 - .../types/image_content_param.py | 50 - .../types/image_response_format.py | 43 - .../types/image_response_format_param.py | 42 - .../genai/_interactions/types/interaction.py | 476 ---- .../types/interaction_completed_event.py | 51 - .../types/interaction_create_params.py | 402 --- .../types/interaction_created_event.py | 47 - .../types/interaction_get_params.py | 50 - .../types/interaction_sse_event.py | 43 - .../types/interaction_status_update.py | 49 - .../types/mcp_server_tool_call_step.py | 41 - .../types/mcp_server_tool_call_step_param.py | 41 - .../types/mcp_server_tool_result_step.py | 49 - .../mcp_server_tool_result_step_param.py | 47 - google/genai/_interactions/types/model.py | 48 - .../_interactions/types/model_output_step.py | 32 - .../types/model_output_step_param.py | 33 - .../genai/_interactions/types/model_param.py | 50 - .../_interactions/types/place_citation.py | 69 - .../types/place_citation_param.py | 69 - .../_interactions/types/signing_secret.py | 33 - .../_interactions/types/speech_config.py | 35 - .../types/speech_config_param.py | 35 - google/genai/_interactions/types/step.py | 63 - .../genai/_interactions/types/step_delta.py | 382 --- .../genai/_interactions/types/step_param.py | 61 - .../genai/_interactions/types/step_start.py | 49 - google/genai/_interactions/types/step_stop.py | 45 - .../genai/_interactions/types/text_content.py | 36 - .../_interactions/types/text_content_param.py | 37 - .../types/text_response_format.py | 40 - .../types/text_response_format_param.py | 38 - .../_interactions/types/thinking_level.py | 22 - .../genai/_interactions/types/thought_step.py | 40 - .../_interactions/types/thought_step_param.py | 46 - google/genai/_interactions/types/tool.py | 279 --- .../_interactions/types/tool_choice_config.py | 30 - .../types/tool_choice_config_param.py | 31 - .../_interactions/types/tool_choice_type.py | 22 - .../genai/_interactions/types/tool_param.py | 275 --- .../genai/_interactions/types/url_citation.py | 44 - .../_interactions/types/url_citation_param.py | 43 - .../types/url_context_call_arguments.py | 29 - .../types/url_context_call_step.py | 45 - .../types/url_context_call_step_param.py | 52 - .../_interactions/types/url_context_result.py | 33 - .../types/url_context_result_step.py | 51 - .../types/url_context_result_step_param.py | 58 - google/genai/_interactions/types/usage.py | 120 - .../genai/_interactions/types/usage_param.py | 120 - .../_interactions/types/user_input_step.py | 32 - .../types/user_input_step_param.py | 33 - .../_interactions/types/video_content.py | 53 - .../types/video_content_param.py | 58 - google/genai/_interactions/types/webhook.py | 78 - .../_interactions/types/webhook_config.py | 39 - .../types/webhook_config_param.py | 42 - .../types/webhook_create_params.py | 60 - .../types/webhook_delete_response.py | 34 - .../types/webhook_list_params.py | 41 - .../types/webhook_list_response.py | 36 - .../types/webhook_ping_params.py | 35 - .../types/webhook_ping_response.py | 26 - .../webhook_rotate_signing_secret_params.py | 29 - .../webhook_rotate_signing_secret_response.py | 29 - .../types/webhook_update_params.py | 64 - google/genai/client.py | 260 +- google/genai/interactions.py | 84 +- google/genai/tests/interactions/test_auth.py | 98 +- .../tests/interactions/test_integration.py | 54 +- google/genai/tests/interactions/test_paths.py | 12 +- 164 files changed, 225 insertions(+), 19467 deletions(-) delete mode 100644 google/genai/_interactions/__init__.py delete mode 100644 google/genai/_interactions/_base_client.py delete mode 100644 google/genai/_interactions/_client.py delete mode 100644 google/genai/_interactions/_client_adapter.py delete mode 100644 google/genai/_interactions/_compat.py delete mode 100644 google/genai/_interactions/_constants.py delete mode 100644 google/genai/_interactions/_exceptions.py delete mode 100644 google/genai/_interactions/_files.py delete mode 100644 google/genai/_interactions/_legacy_lyria.py delete mode 100644 google/genai/_interactions/_models.py delete mode 100644 google/genai/_interactions/_qs.py delete mode 100644 google/genai/_interactions/_resource.py delete mode 100644 google/genai/_interactions/_response.py delete mode 100644 google/genai/_interactions/_streaming.py delete mode 100644 google/genai/_interactions/_types.py delete mode 100644 google/genai/_interactions/_utils/__init__.py delete mode 100644 google/genai/_interactions/_utils/_compat.py delete mode 100644 google/genai/_interactions/_utils/_datetime_parse.py delete mode 100644 google/genai/_interactions/_utils/_json.py delete mode 100644 google/genai/_interactions/_utils/_logs.py delete mode 100644 google/genai/_interactions/_utils/_path.py delete mode 100644 google/genai/_interactions/_utils/_proxy.py delete mode 100644 google/genai/_interactions/_utils/_reflection.py delete mode 100644 google/genai/_interactions/_utils/_resources_proxy.py delete mode 100644 google/genai/_interactions/_utils/_streams.py delete mode 100644 google/genai/_interactions/_utils/_sync.py delete mode 100644 google/genai/_interactions/_utils/_transform.py delete mode 100644 google/genai/_interactions/_utils/_typing.py delete mode 100644 google/genai/_interactions/_utils/_utils.py delete mode 100644 google/genai/_interactions/_version.py delete mode 100644 google/genai/_interactions/resources/__init__.py delete mode 100644 google/genai/_interactions/resources/agents.py delete mode 100644 google/genai/_interactions/resources/interactions.py delete mode 100644 google/genai/_interactions/resources/webhooks.py delete mode 100644 google/genai/_interactions/types/__init__.py delete mode 100644 google/genai/_interactions/types/agent.py delete mode 100644 google/genai/_interactions/types/agent_create_params.py delete mode 100644 google/genai/_interactions/types/agent_delete_response.py delete mode 100644 google/genai/_interactions/types/agent_list_params.py delete mode 100644 google/genai/_interactions/types/agent_list_response.py delete mode 100644 google/genai/_interactions/types/allowed_tools.py delete mode 100644 google/genai/_interactions/types/allowed_tools_param.py delete mode 100644 google/genai/_interactions/types/annotation.py delete mode 100644 google/genai/_interactions/types/annotation_param.py delete mode 100644 google/genai/_interactions/types/audio_content.py delete mode 100644 google/genai/_interactions/types/audio_content_param.py delete mode 100644 google/genai/_interactions/types/audio_response_format.py delete mode 100644 google/genai/_interactions/types/audio_response_format_param.py delete mode 100644 google/genai/_interactions/types/code_execution_call_arguments.py delete mode 100644 google/genai/_interactions/types/code_execution_call_step.py delete mode 100644 google/genai/_interactions/types/code_execution_call_step_param.py delete mode 100644 google/genai/_interactions/types/code_execution_result_step.py delete mode 100644 google/genai/_interactions/types/code_execution_result_step_param.py delete mode 100644 google/genai/_interactions/types/content.py delete mode 100644 google/genai/_interactions/types/content_param.py delete mode 100644 google/genai/_interactions/types/deep_research_agent_config.py delete mode 100644 google/genai/_interactions/types/deep_research_agent_config_param.py delete mode 100644 google/genai/_interactions/types/document_content.py delete mode 100644 google/genai/_interactions/types/document_content_param.py delete mode 100644 google/genai/_interactions/types/dynamic_agent_config.py delete mode 100644 google/genai/_interactions/types/dynamic_agent_config_param.py delete mode 100644 google/genai/_interactions/types/environment.py delete mode 100644 google/genai/_interactions/types/environment_param.py delete mode 100644 google/genai/_interactions/types/error_event.py delete mode 100644 google/genai/_interactions/types/file_citation.py delete mode 100644 google/genai/_interactions/types/file_citation_param.py delete mode 100644 google/genai/_interactions/types/file_search_call_step.py delete mode 100644 google/genai/_interactions/types/file_search_call_step_param.py delete mode 100644 google/genai/_interactions/types/file_search_result_step.py delete mode 100644 google/genai/_interactions/types/file_search_result_step_param.py delete mode 100644 google/genai/_interactions/types/function.py delete mode 100644 google/genai/_interactions/types/function_call_step.py delete mode 100644 google/genai/_interactions/types/function_call_step_param.py delete mode 100644 google/genai/_interactions/types/function_param.py delete mode 100644 google/genai/_interactions/types/function_result_step.py delete mode 100644 google/genai/_interactions/types/function_result_step_param.py delete mode 100644 google/genai/_interactions/types/generation_config.py delete mode 100644 google/genai/_interactions/types/generation_config_param.py delete mode 100644 google/genai/_interactions/types/google_maps_call_arguments.py delete mode 100644 google/genai/_interactions/types/google_maps_call_step.py delete mode 100644 google/genai/_interactions/types/google_maps_call_step_param.py delete mode 100644 google/genai/_interactions/types/google_maps_result.py delete mode 100644 google/genai/_interactions/types/google_maps_result_step.py delete mode 100644 google/genai/_interactions/types/google_maps_result_step_param.py delete mode 100644 google/genai/_interactions/types/google_search_call_arguments.py delete mode 100644 google/genai/_interactions/types/google_search_call_step.py delete mode 100644 google/genai/_interactions/types/google_search_call_step_param.py delete mode 100644 google/genai/_interactions/types/google_search_result.py delete mode 100644 google/genai/_interactions/types/google_search_result_step.py delete mode 100644 google/genai/_interactions/types/google_search_result_step_param.py delete mode 100644 google/genai/_interactions/types/image_config.py delete mode 100644 google/genai/_interactions/types/image_config_param.py delete mode 100644 google/genai/_interactions/types/image_content.py delete mode 100644 google/genai/_interactions/types/image_content_param.py delete mode 100644 google/genai/_interactions/types/image_response_format.py delete mode 100644 google/genai/_interactions/types/image_response_format_param.py delete mode 100644 google/genai/_interactions/types/interaction.py delete mode 100644 google/genai/_interactions/types/interaction_completed_event.py delete mode 100644 google/genai/_interactions/types/interaction_create_params.py delete mode 100644 google/genai/_interactions/types/interaction_created_event.py delete mode 100644 google/genai/_interactions/types/interaction_get_params.py delete mode 100644 google/genai/_interactions/types/interaction_sse_event.py delete mode 100644 google/genai/_interactions/types/interaction_status_update.py delete mode 100644 google/genai/_interactions/types/mcp_server_tool_call_step.py delete mode 100644 google/genai/_interactions/types/mcp_server_tool_call_step_param.py delete mode 100644 google/genai/_interactions/types/mcp_server_tool_result_step.py delete mode 100644 google/genai/_interactions/types/mcp_server_tool_result_step_param.py delete mode 100644 google/genai/_interactions/types/model.py delete mode 100644 google/genai/_interactions/types/model_output_step.py delete mode 100644 google/genai/_interactions/types/model_output_step_param.py delete mode 100644 google/genai/_interactions/types/model_param.py delete mode 100644 google/genai/_interactions/types/place_citation.py delete mode 100644 google/genai/_interactions/types/place_citation_param.py delete mode 100644 google/genai/_interactions/types/signing_secret.py delete mode 100644 google/genai/_interactions/types/speech_config.py delete mode 100644 google/genai/_interactions/types/speech_config_param.py delete mode 100644 google/genai/_interactions/types/step.py delete mode 100644 google/genai/_interactions/types/step_delta.py delete mode 100644 google/genai/_interactions/types/step_param.py delete mode 100644 google/genai/_interactions/types/step_start.py delete mode 100644 google/genai/_interactions/types/step_stop.py delete mode 100644 google/genai/_interactions/types/text_content.py delete mode 100644 google/genai/_interactions/types/text_content_param.py delete mode 100644 google/genai/_interactions/types/text_response_format.py delete mode 100644 google/genai/_interactions/types/text_response_format_param.py delete mode 100644 google/genai/_interactions/types/thinking_level.py delete mode 100644 google/genai/_interactions/types/thought_step.py delete mode 100644 google/genai/_interactions/types/thought_step_param.py delete mode 100644 google/genai/_interactions/types/tool.py delete mode 100644 google/genai/_interactions/types/tool_choice_config.py delete mode 100644 google/genai/_interactions/types/tool_choice_config_param.py delete mode 100644 google/genai/_interactions/types/tool_choice_type.py delete mode 100644 google/genai/_interactions/types/tool_param.py delete mode 100644 google/genai/_interactions/types/url_citation.py delete mode 100644 google/genai/_interactions/types/url_citation_param.py delete mode 100644 google/genai/_interactions/types/url_context_call_arguments.py delete mode 100644 google/genai/_interactions/types/url_context_call_step.py delete mode 100644 google/genai/_interactions/types/url_context_call_step_param.py delete mode 100644 google/genai/_interactions/types/url_context_result.py delete mode 100644 google/genai/_interactions/types/url_context_result_step.py delete mode 100644 google/genai/_interactions/types/url_context_result_step_param.py delete mode 100644 google/genai/_interactions/types/usage.py delete mode 100644 google/genai/_interactions/types/usage_param.py delete mode 100644 google/genai/_interactions/types/user_input_step.py delete mode 100644 google/genai/_interactions/types/user_input_step_param.py delete mode 100644 google/genai/_interactions/types/video_content.py delete mode 100644 google/genai/_interactions/types/video_content_param.py delete mode 100644 google/genai/_interactions/types/webhook.py delete mode 100644 google/genai/_interactions/types/webhook_config.py delete mode 100644 google/genai/_interactions/types/webhook_config_param.py delete mode 100644 google/genai/_interactions/types/webhook_create_params.py delete mode 100644 google/genai/_interactions/types/webhook_delete_response.py delete mode 100644 google/genai/_interactions/types/webhook_list_params.py delete mode 100644 google/genai/_interactions/types/webhook_list_response.py delete mode 100644 google/genai/_interactions/types/webhook_ping_params.py delete mode 100644 google/genai/_interactions/types/webhook_ping_response.py delete mode 100644 google/genai/_interactions/types/webhook_rotate_signing_secret_params.py delete mode 100644 google/genai/_interactions/types/webhook_rotate_signing_secret_response.py delete mode 100644 google/genai/_interactions/types/webhook_update_params.py diff --git a/google/genai/_interactions/__init__.py b/google/genai/_interactions/__init__.py deleted file mode 100644 index 13e8d1032..000000000 --- a/google/genai/_interactions/__init__.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import typing as _t - -from . import types -from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given -from ._utils import file_from_path -from ._client import ( - Client, - Stream, - Timeout, - Transport, - AsyncClient, - AsyncStream, - RequestOptions, - GeminiNextGenAPIClient, - AsyncGeminiNextGenAPIClient, -) -from ._models import BaseModel -from ._version import __title__, __version__ -from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse -from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS -from ._exceptions import ( - APIError, - ConflictError, - NotFoundError, - APIStatusError, - RateLimitError, - APITimeoutError, - BadRequestError, - APIConnectionError, - AuthenticationError, - InternalServerError, - PermissionDeniedError, - UnprocessableEntityError, - APIResponseValidationError, - GeminiNextGenAPIClientError, -) -from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient -from ._utils._logs import setup_logging as _setup_logging -from ._client_adapter import GeminiNextGenAPIClientAdapter, AsyncGeminiNextGenAPIClientAdapter - -__all__ = [ - "types", - "__version__", - "__title__", - "NoneType", - "Transport", - "ProxiesTypes", - "NotGiven", - "NOT_GIVEN", - "not_given", - "Omit", - "omit", - "GeminiNextGenAPIClientError", - "APIError", - "APIStatusError", - "APITimeoutError", - "APIConnectionError", - "APIResponseValidationError", - "BadRequestError", - "AuthenticationError", - "PermissionDeniedError", - "NotFoundError", - "ConflictError", - "UnprocessableEntityError", - "RateLimitError", - "InternalServerError", - "Timeout", - "RequestOptions", - "Client", - "AsyncClient", - "Stream", - "AsyncStream", - "GeminiNextGenAPIClient", - "AsyncGeminiNextGenAPIClient", - "file_from_path", - "BaseModel", - "DEFAULT_TIMEOUT", - "DEFAULT_MAX_RETRIES", - "DEFAULT_CONNECTION_LIMITS", - "DefaultHttpxClient", - "DefaultAsyncHttpxClient", - "DefaultAioHttpClient", - "AsyncGeminiNextGenAPIClientAdapter", - "GeminiNextGenAPIClientAdapter", -] - -if not _t.TYPE_CHECKING: - from ._utils._resources_proxy import resources as resources - -_setup_logging() - -# Update the __module__ attribute for exported symbols so that -# error messages point to this module instead of the module -# it was originally defined in, e.g. -# google.genai._interactions._exceptions.NotFoundError -> google.genai._interactions.NotFoundError -__locals = locals() -for __name in __all__: - if not __name.startswith("__"): - try: - __locals[__name].__module__ = "google.genai._interactions" - except (TypeError, AttributeError): - # Some of our exported symbols are builtins which we can't set attributes for. - pass diff --git a/google/genai/_interactions/_base_client.py b/google/genai/_interactions/_base_client.py deleted file mode 100644 index 530456a0f..000000000 --- a/google/genai/_interactions/_base_client.py +++ /dev/null @@ -1,2152 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -import sys -import json -import time -import uuid -import email -import asyncio -import inspect -import logging -import platform -import warnings -import email.utils -from types import TracebackType -from random import random -from typing import ( - TYPE_CHECKING, - Any, - Dict, - Type, - Union, - Generic, - Mapping, - TypeVar, - Iterable, - Iterator, - Optional, - Generator, - AsyncIterator, - cast, - overload, -) -from typing_extensions import Literal, override, get_origin - -import anyio -import httpx -import distro -import pydantic -from httpx import URL -from pydantic import PrivateAttr - -from . import _exceptions -from ._qs import Querystring -from ._files import to_httpx_files, async_to_httpx_files -from ._types import ( - Body, - Omit, - Query, - Headers, - Timeout, - NotGiven, - ResponseT, - AnyMapping, - PostParser, - BinaryTypes, - RequestFiles, - HttpxSendArgs, - RequestOptions, - AsyncBinaryTypes, - HttpxRequestFiles, - ModelBuilderProtocol, - not_given, -) -from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping -from ._compat import PYDANTIC_V1, model_copy, model_dump -from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type -from ._response import ( - APIResponse, - BaseAPIResponse, - AsyncAPIResponse, - extract_response_type, -) -from ._constants import ( - DEFAULT_TIMEOUT, - MAX_RETRY_DELAY, - DEFAULT_MAX_RETRIES, - INITIAL_RETRY_DELAY, - RAW_RESPONSE_HEADER, - OVERRIDE_CAST_TO_HEADER, - DEFAULT_CONNECTION_LIMITS, -) -from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder -from ._exceptions import ( - APIStatusError, - APITimeoutError, - APIConnectionError, - APIResponseValidationError, -) -from ._utils._json import openapi_dumps -from ._legacy_lyria import LEGACY_LYRIA_SHIM_CTX, maybe_remap_legacy_sse_event - -log: logging.Logger = logging.getLogger(__name__) - -# TODO: make base page type vars covariant -SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]") -AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]") - - -_T = TypeVar("_T") -_T_co = TypeVar("_T_co", covariant=True) - -_StreamT = TypeVar("_StreamT", bound=Stream[Any]) -_AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) - -if TYPE_CHECKING: - from httpx._config import ( - DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] - ) - - HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG -else: - try: - from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT - except ImportError: - # taken from https://github.com/encode/httpx/blob/3ba5fe0d7ac70222590e759c31442b1cab263791/httpx/_config.py#L366 - HTTPX_DEFAULT_TIMEOUT = Timeout(5.0) - - -class PageInfo: - """Stores the necessary information to build the request to retrieve the next page. - - Either `url` or `params` must be set. - """ - - url: URL | NotGiven - params: Query | NotGiven - json: Body | NotGiven - - @overload - def __init__( - self, - *, - url: URL, - ) -> None: ... - - @overload - def __init__( - self, - *, - params: Query, - ) -> None: ... - - @overload - def __init__( - self, - *, - json: Body, - ) -> None: ... - - def __init__( - self, - *, - url: URL | NotGiven = not_given, - json: Body | NotGiven = not_given, - params: Query | NotGiven = not_given, - ) -> None: - self.url = url - self.json = json - self.params = params - - @override - def __repr__(self) -> str: - if self.url: - return f"{self.__class__.__name__}(url={self.url})" - if self.json: - return f"{self.__class__.__name__}(json={self.json})" - return f"{self.__class__.__name__}(params={self.params})" - - -class BasePage(GenericModel, Generic[_T]): - """ - Defines the core interface for pagination. - - Type Args: - ModelT: The pydantic model that represents an item in the response. - - Methods: - has_next_page(): Check if there is another page available - next_page_info(): Get the necessary information to make a request for the next page - """ - - _options: FinalRequestOptions = PrivateAttr() - _model: Type[_T] = PrivateAttr() - - def has_next_page(self) -> bool: - items = self._get_page_items() - if not items: - return False - return self.next_page_info() is not None - - def next_page_info(self) -> Optional[PageInfo]: ... - - def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body] - ... - - def _params_from_url(self, url: URL) -> httpx.QueryParams: - # TODO: do we have to preprocess params here? - return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params) - - def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: - options = model_copy(self._options) - options._strip_raw_response_header() - - if not isinstance(info.params, NotGiven): - options.params = {**options.params, **info.params} - return options - - if not isinstance(info.url, NotGiven): - params = self._params_from_url(info.url) - url = info.url.copy_with(params=params) - options.params = dict(url.params) - options.url = str(url) - return options - - if not isinstance(info.json, NotGiven): - if not is_mapping(info.json): - raise TypeError("Pagination is only supported with mappings") - - if not options.json_data: - options.json_data = {**info.json} - else: - if not is_mapping(options.json_data): - raise TypeError("Pagination is only supported with mappings") - - options.json_data = {**options.json_data, **info.json} - return options - - raise ValueError("Unexpected PageInfo state") - - -class BaseSyncPage(BasePage[_T], Generic[_T]): - _client: SyncAPIClient = pydantic.PrivateAttr() - - def _set_private_attributes( - self, - client: SyncAPIClient, - model: Type[_T], - options: FinalRequestOptions, - ) -> None: - if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: - self.__pydantic_private__ = {} - - self._model = model - self._client = client - self._options = options - - # Pydantic uses a custom `__iter__` method to support casting BaseModels - # to dictionaries. e.g. dict(model). - # As we want to support `for item in page`, this is inherently incompatible - # with the default pydantic behaviour. It is not possible to support both - # use cases at once. Fortunately, this is not a big deal as all other pydantic - # methods should continue to work as expected as there is an alternative method - # to cast a model to a dictionary, model.dict(), which is used internally - # by pydantic. - def __iter__(self) -> Iterator[_T]: # type: ignore - for page in self.iter_pages(): - for item in page._get_page_items(): - yield item - - def iter_pages(self: SyncPageT) -> Iterator[SyncPageT]: - page = self - while True: - yield page - if page.has_next_page(): - page = page.get_next_page() - else: - return - - def get_next_page(self: SyncPageT) -> SyncPageT: - info = self.next_page_info() - if not info: - raise RuntimeError( - "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." - ) - - options = self._info_to_options(info) - return self._client._request_api_list(self._model, page=self.__class__, options=options) - - -class AsyncPaginator(Generic[_T, AsyncPageT]): - def __init__( - self, - client: AsyncAPIClient, - options: FinalRequestOptions, - page_cls: Type[AsyncPageT], - model: Type[_T], - ) -> None: - self._model = model - self._client = client - self._options = options - self._page_cls = page_cls - - def __await__(self) -> Generator[Any, None, AsyncPageT]: - return self._get_page().__await__() - - async def _get_page(self) -> AsyncPageT: - def _parser(resp: AsyncPageT) -> AsyncPageT: - resp._set_private_attributes( - model=self._model, - options=self._options, - client=self._client, - ) - return resp - - self._options.post_parser = _parser - - return await self._client.request(self._page_cls, self._options) - - async def __aiter__(self) -> AsyncIterator[_T]: - # https://github.com/microsoft/pyright/issues/3464 - page = cast( - AsyncPageT, - await self, # type: ignore - ) - async for item in page: - yield item - - -class BaseAsyncPage(BasePage[_T], Generic[_T]): - _client: AsyncAPIClient = pydantic.PrivateAttr() - - def _set_private_attributes( - self, - model: Type[_T], - client: AsyncAPIClient, - options: FinalRequestOptions, - ) -> None: - if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: - self.__pydantic_private__ = {} - - self._model = model - self._client = client - self._options = options - - async def __aiter__(self) -> AsyncIterator[_T]: - async for page in self.iter_pages(): - for item in page._get_page_items(): - yield item - - async def iter_pages(self: AsyncPageT) -> AsyncIterator[AsyncPageT]: - page = self - while True: - yield page - if page.has_next_page(): - page = await page.get_next_page() - else: - return - - async def get_next_page(self: AsyncPageT) -> AsyncPageT: - info = self.next_page_info() - if not info: - raise RuntimeError( - "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." - ) - - options = self._info_to_options(info) - return await self._client._request_api_list(self._model, page=self.__class__, options=options) - - -_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient]) -_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]]) - - -class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]): - _client: _HttpxClientT - _version: str - _base_url: URL - max_retries: int - timeout: Union[float, Timeout, None] - _strict_response_validation: bool - _idempotency_header: str | None - _default_stream_cls: type[_DefaultStreamT] | None = None - - def __init__( - self, - *, - version: str, - base_url: str | URL, - _strict_response_validation: bool, - max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None = DEFAULT_TIMEOUT, - custom_headers: Mapping[str, str] | None = None, - custom_query: Mapping[str, object] | None = None, - ) -> None: - self._version = version - self._base_url = self._enforce_trailing_slash(URL(base_url)) - self.max_retries = max_retries - self.timeout = timeout - self._custom_headers = custom_headers or {} - self._custom_query = custom_query or {} - self._strict_response_validation = _strict_response_validation - self._idempotency_header = None - self._platform: Platform | None = None - self._is_vertex: bool = False - self._vertex_project: str | None = None - self._vertex_location: str | None = None - - if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] - raise TypeError( - "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `google.genai._interactions.DEFAULT_MAX_RETRIES`" - ) - - def _build_maybe_vertex_path(self, *, api_version: str, path: str) -> str: - if not self._is_vertex or not self._vertex_location or not self._vertex_project: - return f"/{api_version}/{path}" - - return f"{api_version}/projects/{self._vertex_project}/locations/{self._vertex_location}/{path}" - - def _enforce_trailing_slash(self, url: URL) -> URL: - if url.raw_path.endswith(b"/"): - return url - return url.copy_with(raw_path=url.raw_path + b"/") - - def _make_status_error_from_response( - self, - response: httpx.Response, - ) -> APIStatusError: - if response.is_closed and not response.is_stream_consumed: - # We can't read the response body as it has been closed - # before it was read. This can happen if an event hook - # raises a status error. - body = None - err_msg = f"Error code: {response.status_code}" - else: - err_text = response.text.strip() - body = err_text - - try: - body = json.loads(err_text) - err_msg = f"Error code: {response.status_code} - {body}" - except Exception: - err_msg = err_text or f"Error code: {response.status_code}" - - return self._make_status_error(err_msg, body=body, response=response) - - def _make_status_error( - self, - err_msg: str, - *, - body: object, - response: httpx.Response, - ) -> _exceptions.APIStatusError: - raise NotImplementedError() - - def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers: - custom_headers = options.headers or {} - headers_dict = _merge_mappings(self.default_headers, custom_headers) - self._validate_headers(headers_dict, custom_headers) - - # headers are case-insensitive while dictionaries are not. - headers = httpx.Headers(headers_dict) - - idempotency_header = self._idempotency_header - if idempotency_header and options.idempotency_key and idempotency_header not in headers: - headers[idempotency_header] = options.idempotency_key - - return headers - - def _prepare_url(self, url: str) -> URL: - """ - Merge a URL argument together with any 'base_url' on the client, - to create the URL used for the outgoing request. - """ - # Copied from httpx's `_merge_url` method. - merge_url = URL(url) - if merge_url.is_relative_url: - merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/") - return self.base_url.copy_with(raw_path=merge_raw_path) - - return merge_url - - def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder: - return SSEDecoder() - - def _build_request( - self, - options: FinalRequestOptions, - ) -> httpx.Request: - if log.isEnabledFor(logging.DEBUG): - log.debug( - "Request options: %s", - model_dump( - options, - exclude_unset=True, - # Pydantic v1 can't dump every type we support in content, so we exclude it for now. - exclude={ - "content", - } - if PYDANTIC_V1 - else {}, - ), - ) - kwargs: dict[str, Any] = {} - - json_data = options.json_data - if options.extra_json is not None: - if json_data is None: - json_data = cast(Body, options.extra_json) - elif is_mapping(json_data): - json_data = _merge_mappings(json_data, options.extra_json) - else: - raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") - - headers = self._build_headers(options) - params = _merge_mappings(self.default_query, options.params) - content_type = headers.get("Content-Type") - files = options.files - - # If the given Content-Type header is multipart/form-data then it - # has to be removed so that httpx can generate the header with - # additional information for us as it has to be in this form - # for the server to be able to correctly parse the request: - # multipart/form-data; boundary=---abc-- - if content_type is not None and content_type.startswith("multipart/form-data"): - if "boundary" not in content_type: - # only remove the header if the boundary hasn't been explicitly set - # as the caller doesn't want httpx to come up with their own boundary - headers.pop("Content-Type") - - # As we are now sending multipart/form-data instead of application/json - # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding - if json_data: - if not is_dict(json_data): - raise TypeError( - f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead." - ) - kwargs["data"] = self._serialize_multipartform(json_data) - - # httpx determines whether or not to send a "multipart/form-data" - # request based on the truthiness of the "files" argument. - # This gets around that issue by generating a dict value that - # evaluates to true. - # - # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186 - if not files: - files = cast(HttpxRequestFiles, ForceMultipartDict()) - - prepared_url = self._prepare_url(options.url) - # preserve hard-coded query params from the url - if params and prepared_url.query: - params = {**dict(prepared_url.params.items()), **params} - prepared_url = prepared_url.copy_with(raw_path=prepared_url.raw_path.split(b"?", 1)[0]) - if "_" in prepared_url.host: - # work around https://github.com/encode/httpx/discussions/2880 - kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} - - is_body_allowed = options.method.lower() != "get" - - if is_body_allowed: - if options.content is not None and json_data is not None: - raise TypeError("Passing both `content` and `json_data` is not supported") - if options.content is not None and files is not None: - raise TypeError("Passing both `content` and `files` is not supported") - if options.content is not None: - kwargs["content"] = options.content - elif isinstance(json_data, bytes): - kwargs["content"] = json_data - elif not files: - # Don't set content when JSON is sent as multipart/form-data, - # since httpx's content param overrides other body arguments - kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None - kwargs["files"] = files - else: - headers.pop("Content-Type", None) - kwargs.pop("data", None) - - # TODO: report this error to httpx - return self._client.build_request( # pyright: ignore[reportUnknownMemberType] - headers=headers, - timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout, - method=options.method, - url=prepared_url, - # the `Query` type that we use is incompatible with qs' - # `Params` type as it needs to be typed as `Mapping[str, object]` - # so that passing a `TypedDict` doesn't cause an error. - # https://github.com/microsoft/pyright/issues/3526#event-6715453066 - params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, - **kwargs, - ) - - def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, object]: - items = self.qs.stringify_items( - # TODO: type ignore is required as stringify_items is well typed but we can't be - # well typed without heavy validation. - data, # type: ignore - array_format="brackets", - ) - serialized: dict[str, object] = {} - for key, value in items: - existing = serialized.get(key) - - if not existing: - serialized[key] = value - continue - - # If a value has already been set for this key then that - # means we're sending data like `array[]=[1, 2, 3]` and we - # need to tell httpx that we want to send multiple values with - # the same key which is done by using a list or a tuple. - # - # Note: 2d arrays should never result in the same key at both - # levels so it's safe to assume that if the value is a list, - # it was because we changed it to be a list. - if is_list(existing): - existing.append(value) - else: - serialized[key] = [existing, value] - - return serialized - - def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalRequestOptions) -> type[ResponseT]: - if not is_given(options.headers): - return cast_to - - # make a copy of the headers so we don't mutate user-input - headers = dict(options.headers) - - # we internally support defining a temporary header to override the - # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` - # see _response.py for implementation details - override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given) - if is_given(override_cast_to): - options.headers = headers - return cast(Type[ResponseT], override_cast_to) - - return cast_to - - def _should_stream_response_body(self, request: httpx.Request) -> bool: - return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return] - - def _process_response_data( - self, - *, - data: object, - cast_to: type[ResponseT], - response: httpx.Response, - ) -> ResponseT: - if data is None: - return cast(ResponseT, None) - - if cast_to is object: - return cast(ResponseT, data) - - # When the legacy-lyria shim is active for this request (set by the - # `LegacyLyriaInteractionStream` subclass after dynamic detection of - # a legacy event), rename legacy SSE event types and reshape - # `content.start` payloads so the discriminated-union dispatch in - # `construct_type` lands on the modern variants. - # `Interaction._maybe_coerce_outputs` does its own data inspection - # (model field) and doesn't depend on this contextvar for the - # non-streaming paths. - if LEGACY_LYRIA_SHIM_CTX.get() and isinstance(data, dict): - data = maybe_remap_legacy_sse_event(cast("dict[str, object]", data)) - - try: - if inspect.isclass(cast_to) and issubclass(cast_to, ModelBuilderProtocol): - return cast(ResponseT, cast_to.build(response=response, data=data)) - - if self._strict_response_validation: - return cast(ResponseT, validate_type(type_=cast_to, value=data)) - - return cast(ResponseT, construct_type(type_=cast_to, value=data)) - except pydantic.ValidationError as err: - raise APIResponseValidationError(response=response, body=data) from err - - @property - def qs(self) -> Querystring: - return Querystring() - - @property - def custom_auth(self) -> httpx.Auth | None: - return None - - @property - def auth_headers(self) -> dict[str, str]: - return {} - - @property - def default_headers(self) -> dict[str, str | Omit]: - return { - "Accept": "application/json", - "Content-Type": "application/json", - "User-Agent": self.user_agent, - **self.auth_headers, - **self._custom_headers, - } - - @property - def default_query(self) -> dict[str, object]: - return { - **self._custom_query, - } - - def _validate_headers( - self, - headers: Headers, # noqa: ARG002 - custom_headers: Headers, # noqa: ARG002 - ) -> None: - """Validate the given default headers and custom headers. - - Does nothing by default. - """ - return - - @property - def user_agent(self) -> str: - return f"{self.__class__.__name__}/Python {self._version}" - - @property - def base_url(self) -> URL: - return self._base_url - - @base_url.setter - def base_url(self, url: URL | str) -> None: - self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url)) - - def platform_headers(self) -> Dict[str, str]: - # the actual implementation is in a separate `lru_cache` decorated - # function because adding `lru_cache` to methods will leak memory - # https://github.com/python/cpython/issues/88476 - return platform_headers(self._version, platform=self._platform) - - def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None: - """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified. - - About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After - See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax - """ - if response_headers is None: - return None - - # First, try the non-standard `retry-after-ms` header for milliseconds, - # which is more precise than integer-seconds `retry-after` - try: - retry_ms_header = response_headers.get("retry-after-ms", None) - return float(retry_ms_header) / 1000 - except (TypeError, ValueError): - pass - - # Next, try parsing `retry-after` header as seconds (allowing nonstandard floats). - retry_header = response_headers.get("retry-after") - try: - # note: the spec indicates that this should only ever be an integer - # but if someone sends a float there's no reason for us to not respect it - return float(retry_header) - except (TypeError, ValueError): - pass - - # Last, try parsing `retry-after` as a date. - retry_date_tuple = email.utils.parsedate_tz(retry_header) - if retry_date_tuple is None: - return None - - retry_date = email.utils.mktime_tz(retry_date_tuple) - return float(retry_date - time.time()) - - def _calculate_retry_timeout( - self, - remaining_retries: int, - options: FinalRequestOptions, - response_headers: Optional[httpx.Headers] = None, - ) -> float: - max_retries = options.get_max_retries(self.max_retries) - - # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. - retry_after = self._parse_retry_after_header(response_headers) - if retry_after is not None and 0 < retry_after <= 60: - return retry_after - - # Also cap retry count to 1000 to avoid any potential overflows with `pow` - nb_retries = min(max_retries - remaining_retries, 1000) - - # Apply exponential backoff, but not more than the max. - sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY) - - # Apply some jitter, plus-or-minus half a second. - jitter = 1 - 0.25 * random() - timeout = sleep_seconds * jitter - return timeout if timeout >= 0 else 0 - - def _should_retry(self, response: httpx.Response) -> bool: - # Note: this is not a standard header - should_retry_header = response.headers.get("x-should-retry") - - # If the server explicitly says whether or not to retry, obey. - if should_retry_header == "true": - log.debug("Retrying as header `x-should-retry` is set to `true`") - return True - if should_retry_header == "false": - log.debug("Not retrying as header `x-should-retry` is set to `false`") - return False - - # Retry on request timeouts. - if response.status_code == 408: - log.debug("Retrying due to status code %i", response.status_code) - return True - - # Retry on lock timeouts. - if response.status_code == 409: - log.debug("Retrying due to status code %i", response.status_code) - return True - - # Retry on rate limits. - if response.status_code == 429: - log.debug("Retrying due to status code %i", response.status_code) - return True - - # Retry internal errors. - if response.status_code >= 500: - log.debug("Retrying due to status code %i", response.status_code) - return True - - log.debug("Not retrying") - return False - - def _idempotency_key(self) -> str: - return f"stainless-python-retry-{uuid.uuid4()}" - - -class _DefaultHttpxClient(httpx.Client): - def __init__(self, **kwargs: Any) -> None: - kwargs.setdefault("timeout", DEFAULT_TIMEOUT) - kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) - kwargs.setdefault("follow_redirects", True) - super().__init__(**kwargs) - - -if TYPE_CHECKING: - DefaultHttpxClient = httpx.Client - """An alias to `httpx.Client` that provides the same defaults that this SDK - uses internally. - - This is useful because overriding the `http_client` with your own instance of - `httpx.Client` will result in httpx's defaults being used, not ours. - """ -else: - DefaultHttpxClient = _DefaultHttpxClient - - -class SyncHttpxClientWrapper(DefaultHttpxClient): - def __del__(self) -> None: - if self.is_closed: - return - - try: - self.close() - except Exception: - pass - - -class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]): - _client: httpx.Client - _default_stream_cls: type[Stream[Any]] | None = None - - def __init__( - self, - *, - version: str, - base_url: str | URL, - max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.Client | None = None, - custom_headers: Mapping[str, str] | None = None, - custom_query: Mapping[str, object] | None = None, - _strict_response_validation: bool, - ) -> None: - if not is_given(timeout): - # if the user passed in a custom http client with a non-default - # timeout set then we use that timeout. - # - # note: there is an edge case here where the user passes in a client - # where they've explicitly set the timeout to match the default timeout - # as this check is structural, meaning that we'll think they didn't - # pass in a timeout and will ignore it - if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: - timeout = http_client.timeout - else: - timeout = DEFAULT_TIMEOUT - - if http_client is not None and not isinstance(http_client, httpx.Client): # pyright: ignore[reportUnnecessaryIsInstance] - raise TypeError( - f"Invalid `http_client` argument; Expected an instance of `httpx.Client` but got {type(http_client)}" - ) - - super().__init__( - version=version, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - base_url=base_url, - max_retries=max_retries, - custom_query=custom_query, - custom_headers=custom_headers, - _strict_response_validation=_strict_response_validation, - ) - self._client = http_client or SyncHttpxClientWrapper( - base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - ) - - def is_closed(self) -> bool: - return self._client.is_closed - - def close(self) -> None: - """Close the underlying HTTPX client. - - The client will *not* be usable after this. - """ - # If an error is thrown while constructing a client, self._client - # may not be present - if hasattr(self, "_client"): - self._client.close() - - def __enter__(self: _T) -> _T: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def _prepare_options( - self, - options: FinalRequestOptions, # noqa: ARG002 - ) -> FinalRequestOptions: - """Hook for mutating the given options""" - return options - - def _prepare_request( - self, - request: httpx.Request, # noqa: ARG002 - ) -> None: - """This method is used as a callback for mutating the `Request` object - after it has been constructed. - This is useful for cases where you want to add certain headers based off of - the request properties, e.g. `url`, `method` etc. - """ - return None - - @overload - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[True], - stream_cls: Type[_StreamT], - ) -> _StreamT: ... - - @overload - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool = False, - stream_cls: Type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: ... - - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool = False, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - cast_to = self._maybe_override_cast_to(cast_to, options) - - # create a copy of the options we were given so that if the - # options are mutated later & we then retry, the retries are - # given the original options - input_options = model_copy(options) - if input_options.idempotency_key is None and input_options.method.lower() != "get": - # ensure the idempotency key is reused between requests - input_options.idempotency_key = self._idempotency_key() - - response: httpx.Response | None = None - max_retries = input_options.get_max_retries(self.max_retries) - - retries_taken = 0 - for retries_taken in range(max_retries + 1): - options = model_copy(input_options) - options = self._prepare_options(options) - - remaining_retries = max_retries - retries_taken - request = self._build_request(options) - self._prepare_request(request) - - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth - - if options.follow_redirects is not None: - kwargs["follow_redirects"] = options.follow_redirects - - log.debug("Sending HTTP Request: %s %s", request.method, request.url) - - response = None - try: - response = self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) - - if remaining_retries > 0: - self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) - - if remaining_retries > 0: - self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err - - log.debug( - 'HTTP Response: %s %s "%i %s" %s', - request.method, - request.url, - response.status_code, - response.reason_phrase, - response.headers, - ) - - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - - if remaining_retries > 0 and self._should_retry(err.response): - err.response.close() - self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=response, - ) - continue - - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - err.response.read() - - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None - - break - - assert response is not None, "could not resolve response (should never happen)" - return self._process_response( - cast_to=cast_to, - options=options, - response=response, - stream=stream, - stream_cls=stream_cls, - retries_taken=retries_taken, - ) - - def _sleep_for_retry( - self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None - ) -> None: - remaining_retries = max_retries - retries_taken - if remaining_retries == 1: - log.debug("1 retry left") - else: - log.debug("%i retries left", remaining_retries) - - timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) - log.info("Retrying request to %s in %f seconds", options.url, timeout) - - time.sleep(timeout) - - def _process_response( - self, - *, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - response: httpx.Response, - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - retries_taken: int = 0, - ) -> ResponseT: - origin = get_origin(cast_to) or cast_to - - if ( - inspect.isclass(origin) - and issubclass(origin, BaseAPIResponse) - # we only want to actually return the custom BaseAPIResponse class if we're - # returning the raw response, or if we're not streaming SSE, as if we're streaming - # SSE then `cast_to` doesn't actively reflect the type we need to parse into - and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) - ): - if not issubclass(origin, APIResponse): - raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") - - response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) - return cast( - ResponseT, - response_cls( - raw=response, - client=self, - cast_to=extract_response_type(response_cls), - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ), - ) - - if cast_to == httpx.Response: - return cast(ResponseT, response) - - api_response = APIResponse( - raw=response, - client=self, - cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ) - if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): - return cast(ResponseT, api_response) - - return api_response.parse() - - def _request_api_list( - self, - model: Type[object], - page: Type[SyncPageT], - options: FinalRequestOptions, - ) -> SyncPageT: - def _parser(resp: SyncPageT) -> SyncPageT: - resp._set_private_attributes( - client=self, - model=model, - options=options, - ) - return resp - - options.post_parser = _parser - - return self.request(page, options, stream=False) - - @overload - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[True], - stream_cls: type[_StreamT], - ) -> _StreamT: ... - - @overload - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: ... - - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool = False, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - opts = FinalRequestOptions.construct(method="get", url=path, **options) - # cast is required because mypy complains about returning Any even though - # it understands the type variables - return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) - - @overload - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: Literal[True], - stream_cls: type[_StreamT], - ) -> _StreamT: ... - - @overload - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: bool, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: ... - - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: bool = False, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options - ) - return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) - - def patch( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options - ) - return self.request(cast_to, opts) - - def put( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options - ) - return self.request(cast_to, opts) - - def delete( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) - return self.request(cast_to, opts) - - def get_api_list( - self, - path: str, - *, - model: Type[object], - page: Type[SyncPageT], - body: Body | None = None, - options: RequestOptions = {}, - method: str = "get", - ) -> SyncPageT: - opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) - return self._request_api_list(model, page, opts) - - -class _DefaultAsyncHttpxClient(httpx.AsyncClient): - def __init__(self, **kwargs: Any) -> None: - kwargs.setdefault("timeout", DEFAULT_TIMEOUT) - kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) - kwargs.setdefault("follow_redirects", True) - super().__init__(**kwargs) - - -try: - import httpx_aiohttp -except ImportError: - - class _DefaultAioHttpClient(httpx.AsyncClient): - def __init__(self, **_kwargs: Any) -> None: - raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") -else: - - class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore - def __init__(self, **kwargs: Any) -> None: - kwargs.setdefault("timeout", DEFAULT_TIMEOUT) - kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) - kwargs.setdefault("follow_redirects", True) - - super().__init__(**kwargs) - - -if TYPE_CHECKING: - DefaultAsyncHttpxClient = httpx.AsyncClient - """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK - uses internally. - - This is useful because overriding the `http_client` with your own instance of - `httpx.AsyncClient` will result in httpx's defaults being used, not ours. - """ - - DefaultAioHttpClient = httpx.AsyncClient - """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" -else: - DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient - DefaultAioHttpClient = _DefaultAioHttpClient - - -class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): - def __del__(self) -> None: - if self.is_closed: - return - - try: - # TODO(someday): support non asyncio runtimes here - asyncio.get_running_loop().create_task(self.aclose()) - except Exception: - pass - - -class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]): - _client: httpx.AsyncClient - _default_stream_cls: type[AsyncStream[Any]] | None = None - - def __init__( - self, - *, - version: str, - base_url: str | URL, - _strict_response_validation: bool, - max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.AsyncClient | None = None, - custom_headers: Mapping[str, str] | None = None, - custom_query: Mapping[str, object] | None = None, - ) -> None: - if not is_given(timeout): - # if the user passed in a custom http client with a non-default - # timeout set then we use that timeout. - # - # note: there is an edge case here where the user passes in a client - # where they've explicitly set the timeout to match the default timeout - # as this check is structural, meaning that we'll think they didn't - # pass in a timeout and will ignore it - if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: - timeout = http_client.timeout - else: - timeout = DEFAULT_TIMEOUT - - if http_client is not None and not isinstance(http_client, httpx.AsyncClient): # pyright: ignore[reportUnnecessaryIsInstance] - raise TypeError( - f"Invalid `http_client` argument; Expected an instance of `httpx.AsyncClient` but got {type(http_client)}" - ) - - super().__init__( - version=version, - base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - max_retries=max_retries, - custom_query=custom_query, - custom_headers=custom_headers, - _strict_response_validation=_strict_response_validation, - ) - self._client = http_client or AsyncHttpxClientWrapper( - base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - ) - - def is_closed(self) -> bool: - return self._client.is_closed - - async def close(self) -> None: - """Close the underlying HTTPX client. - - The client will *not* be usable after this. - """ - await self._client.aclose() - - async def __aenter__(self: _T) -> _T: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.close() - - async def _prepare_options( - self, - options: FinalRequestOptions, # noqa: ARG002 - ) -> FinalRequestOptions: - """Hook for mutating the given options""" - return options - - async def _prepare_request( - self, - request: httpx.Request, # noqa: ARG002 - ) -> None: - """This method is used as a callback for mutating the `Request` object - after it has been constructed. - This is useful for cases where you want to add certain headers based off of - the request properties, e.g. `url`, `method` etc. - """ - return None - - @overload - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[True], - stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: ... - - @overload - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: ... - - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool = False, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - if self._platform is None: - # `get_platform` can make blocking IO calls so we - # execute it earlier while we are in an async context - self._platform = await asyncify(get_platform)() - - cast_to = self._maybe_override_cast_to(cast_to, options) - - # create a copy of the options we were given so that if the - # options are mutated later & we then retry, the retries are - # given the original options - input_options = model_copy(options) - if input_options.idempotency_key is None and input_options.method.lower() != "get": - # ensure the idempotency key is reused between requests - input_options.idempotency_key = self._idempotency_key() - - response: httpx.Response | None = None - max_retries = input_options.get_max_retries(self.max_retries) - - retries_taken = 0 - for retries_taken in range(max_retries + 1): - options = model_copy(input_options) - options = await self._prepare_options(options) - - remaining_retries = max_retries - retries_taken - request = self._build_request(options) - await self._prepare_request(request) - - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth - - if options.follow_redirects is not None: - kwargs["follow_redirects"] = options.follow_redirects - - log.debug("Sending HTTP Request: %s %s", request.method, request.url) - - response = None - try: - response = await self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) - - if remaining_retries > 0: - await self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) - - if remaining_retries > 0: - await self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err - - log.debug( - 'HTTP Response: %s %s "%i %s" %s', - request.method, - request.url, - response.status_code, - response.reason_phrase, - response.headers, - ) - - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - - if remaining_retries > 0 and self._should_retry(err.response): - await err.response.aclose() - await self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=response, - ) - continue - - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - await err.response.aread() - - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None - - break - - assert response is not None, "could not resolve response (should never happen)" - return await self._process_response( - cast_to=cast_to, - options=options, - response=response, - stream=stream, - stream_cls=stream_cls, - retries_taken=retries_taken, - ) - - async def _sleep_for_retry( - self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None - ) -> None: - remaining_retries = max_retries - retries_taken - if remaining_retries == 1: - log.debug("1 retry left") - else: - log.debug("%i retries left", remaining_retries) - - timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) - log.info("Retrying request to %s in %f seconds", options.url, timeout) - - await anyio.sleep(timeout) - - async def _process_response( - self, - *, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - response: httpx.Response, - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - retries_taken: int = 0, - ) -> ResponseT: - origin = get_origin(cast_to) or cast_to - - if ( - inspect.isclass(origin) - and issubclass(origin, BaseAPIResponse) - # we only want to actually return the custom BaseAPIResponse class if we're - # returning the raw response, or if we're not streaming SSE, as if we're streaming - # SSE then `cast_to` doesn't actively reflect the type we need to parse into - and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) - ): - if not issubclass(origin, AsyncAPIResponse): - raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") - - response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) - return cast( - "ResponseT", - response_cls( - raw=response, - client=self, - cast_to=extract_response_type(response_cls), - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ), - ) - - if cast_to == httpx.Response: - return cast(ResponseT, response) - - api_response = AsyncAPIResponse( - raw=response, - client=self, - cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ) - if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): - return cast(ResponseT, api_response) - - return await api_response.parse() - - def _request_api_list( - self, - model: Type[_T], - page: Type[AsyncPageT], - options: FinalRequestOptions, - ) -> AsyncPaginator[_T, AsyncPageT]: - return AsyncPaginator(client=self, options=options, page_cls=page, model=model) - - @overload - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[True], - stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: ... - - @overload - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: ... - - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool = False, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - opts = FinalRequestOptions.construct(method="get", url=path, **options) - return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) - - @overload - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: Literal[True], - stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: ... - - @overload - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: bool, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: ... - - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: bool = False, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options - ) - return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) - - async def patch( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="patch", - url=path, - json_data=body, - content=content, - files=await async_to_httpx_files(files), - **options, - ) - return await self.request(cast_to, opts) - - async def put( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options - ) - return await self.request(cast_to, opts) - - async def delete( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) - return await self.request(cast_to, opts) - - def get_api_list( - self, - path: str, - *, - model: Type[_T], - page: Type[AsyncPageT], - body: Body | None = None, - options: RequestOptions = {}, - method: str = "get", - ) -> AsyncPaginator[_T, AsyncPageT]: - opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) - return self._request_api_list(model, page, opts) - - -def make_request_options( - *, - query: Query | None = None, - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - idempotency_key: str | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - post_parser: PostParser | NotGiven = not_given, -) -> RequestOptions: - """Create a dict of type RequestOptions without keys of NotGiven values.""" - options: RequestOptions = {} - if extra_headers is not None: - options["headers"] = extra_headers - - if extra_body is not None: - options["extra_json"] = cast(AnyMapping, extra_body) - - if query is not None: - options["params"] = query - - if extra_query is not None: - options["params"] = {**options.get("params", {}), **extra_query} - - if not isinstance(timeout, NotGiven): - options["timeout"] = timeout - - if idempotency_key is not None: - options["idempotency_key"] = idempotency_key - - if is_given(post_parser): - # internal - options["post_parser"] = post_parser # type: ignore - - return options - - -class ForceMultipartDict(Dict[str, None]): - def __bool__(self) -> bool: - return True - - -class OtherPlatform: - def __init__(self, name: str) -> None: - self.name = name - - @override - def __str__(self) -> str: - return f"Other:{self.name}" - - -Platform = Union[ - OtherPlatform, - Literal[ - "MacOS", - "Linux", - "Windows", - "FreeBSD", - "OpenBSD", - "iOS", - "Android", - "Unknown", - ], -] - - -def get_platform() -> Platform: - try: - system = platform.system().lower() - platform_name = platform.platform().lower() - except Exception: - return "Unknown" - - if "iphone" in platform_name or "ipad" in platform_name: - # Tested using Python3IDE on an iPhone 11 and Pythonista on an iPad 7 - # system is Darwin and platform_name is a string like: - # - Darwin-21.6.0-iPhone12,1-64bit - # - Darwin-21.6.0-iPad7,11-64bit - return "iOS" - - if system == "darwin": - return "MacOS" - - if system == "windows": - return "Windows" - - if "android" in platform_name: - # Tested using Pydroid 3 - # system is Linux and platform_name is a string like 'Linux-5.10.81-android12-9-00001-geba40aecb3b7-ab8534902-aarch64-with-libc' - return "Android" - - if system == "linux": - # https://distro.readthedocs.io/en/latest/#distro.id - distro_id = distro.id() - if distro_id == "freebsd": - return "FreeBSD" - - if distro_id == "openbsd": - return "OpenBSD" - - return "Linux" - - if platform_name: - return OtherPlatform(platform_name) - - return "Unknown" - - -@lru_cache(maxsize=None) -def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]: - return { - "X-Stainless-Lang": "python", - "X-Stainless-Package-Version": version, - "X-Stainless-OS": str(platform or get_platform()), - "X-Stainless-Arch": str(get_architecture()), - "X-Stainless-Runtime": get_python_runtime(), - "X-Stainless-Runtime-Version": get_python_version(), - } - - -class OtherArch: - def __init__(self, name: str) -> None: - self.name = name - - @override - def __str__(self) -> str: - return f"other:{self.name}" - - -Arch = Union[OtherArch, Literal["x32", "x64", "arm", "arm64", "unknown"]] - - -def get_python_runtime() -> str: - try: - return platform.python_implementation() - except Exception: - return "unknown" - - -def get_python_version() -> str: - try: - return platform.python_version() - except Exception: - return "unknown" - - -def get_architecture() -> Arch: - try: - machine = platform.machine().lower() - except Exception: - return "unknown" - - if machine in ("arm64", "aarch64"): - return "arm64" - - # TODO: untested - if machine == "arm": - return "arm" - - if machine == "x86_64": - return "x64" - - # TODO: untested - if sys.maxsize <= 2**32: - return "x32" - - if machine: - return OtherArch(machine) - - return "unknown" - - -def _merge_mappings( - obj1: Mapping[_T_co, Union[_T, Omit]], - obj2: Mapping[_T_co, Union[_T, Omit]], -) -> Dict[_T_co, _T]: - """Merge two mappings of the same type, removing any values that are instances of `Omit`. - - In cases with duplicate keys the second mapping takes precedence. - """ - merged = {**obj1, **obj2} - return {key: value for key, value in merged.items() if not isinstance(value, Omit)} diff --git a/google/genai/_interactions/_client.py b/google/genai/_interactions/_client.py deleted file mode 100644 index 09f745f95..000000000 --- a/google/genai/_interactions/_client.py +++ /dev/null @@ -1,659 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import TYPE_CHECKING, Any, Mapping -from typing_extensions import Self, override - -import httpx - -from . import _exceptions -from ._qs import Querystring -from ._types import ( - Omit, - Headers, - Timeout, - NotGiven, - Transport, - ProxiesTypes, - RequestOptions, - not_given, -) -from ._utils import is_given, is_mapping_t -from ._compat import cached_property -from ._models import FinalRequestOptions -from ._version import __version__ -from ._streaming import Stream as Stream, AsyncStream as AsyncStream -from ._exceptions import APIStatusError -from ._base_client import ( - DEFAULT_MAX_RETRIES, - SyncAPIClient, - AsyncAPIClient, -) -from ._client_adapter import GeminiNextGenAPIClientAdapter, AsyncGeminiNextGenAPIClientAdapter - -if TYPE_CHECKING: - from .resources import agents, webhooks, interactions - from .resources.agents import AgentsResource, AsyncAgentsResource - from .resources.webhooks import WebhooksResource, AsyncWebhooksResource - from .resources.interactions import InteractionsResource, AsyncInteractionsResource - -__all__ = [ - "Timeout", - "Transport", - "ProxiesTypes", - "RequestOptions", - "GeminiNextGenAPIClient", - "AsyncGeminiNextGenAPIClient", - "Client", - "AsyncClient", -] - - -class GeminiNextGenAPIClient(SyncAPIClient): - # client options - api_key: str | None - api_version: str - client_adapter: GeminiNextGenAPIClientAdapter | None - - def __init__( - self, - *, - api_key: str | None = None, - api_version: str | None = "v1beta", - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - # Configure a custom httpx client. - # We provide a `DefaultHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. - # See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details. - http_client: httpx.Client | None = None, - client_adapter: GeminiNextGenAPIClientAdapter | None = None, - # Enable or disable schema validation for data returned by the API. - # When enabled an error APIResponseValidationError is raised - # if the API responds with invalid data for the expected schema. - # - # This parameter may be removed or changed in the future. - # If you rely on this feature, please open a GitHub issue - # outlining your use-case to help us decide if it should be - # part of our public interface in the future. - _strict_response_validation: bool = False, - ) -> None: - """Construct a new synchronous GeminiNextGenAPIClient client instance. - - This automatically infers the `api_key` argument from the `GEMINI_API_KEY` environment variable if it is not provided. - """ - if api_key is None: - api_key = os.environ.get("GEMINI_API_KEY") - self.api_key = api_key - - if api_version is None: - api_version = "v1beta" - self.api_version = api_version - - if base_url is None: - base_url = os.environ.get("GEMINI_NEXT_GEN_API_BASE_URL") - if base_url is None: - base_url = f"https://generativelanguage.googleapis.com" - - self.client_adapter = client_adapter - - custom_headers_env = os.environ.get("GEMINI_NEXT_GEN_API_CUSTOM_HEADERS") - if custom_headers_env is not None: - parsed: dict[str, str] = {} - for line in custom_headers_env.split("\n"): - colon = line.find(":") - if colon >= 0: - parsed[line[:colon].strip()] = line[colon + 1 :].strip() - default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} - - super().__init__( - version=__version__, - base_url=base_url, - max_retries=max_retries, - timeout=timeout, - http_client=http_client, - custom_headers=default_headers, - custom_query=default_query, - _strict_response_validation=_strict_response_validation, - ) - - self._default_stream_cls = Stream - - @cached_property - def interactions(self) -> InteractionsResource: - from .resources.interactions import InteractionsResource - - return InteractionsResource(self) - - @cached_property - def webhooks(self) -> WebhooksResource: - from .resources.webhooks import WebhooksResource - - return WebhooksResource(self) - - @cached_property - def agents(self) -> AgentsResource: - from .resources.agents import AgentsResource - - return AgentsResource(self) - - @cached_property - def with_raw_response(self) -> GeminiNextGenAPIClientWithRawResponse: - return GeminiNextGenAPIClientWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> GeminiNextGenAPIClientWithStreamedResponse: - return GeminiNextGenAPIClientWithStreamedResponse(self) - - @property - @override - def qs(self) -> Querystring: - return Querystring(array_format="comma") - - @property - @override - def auth_headers(self) -> dict[str, str]: - api_key = self.api_key - if api_key is None: - return {} - return {"x-goog-api-key": api_key} - - @property - @override - def default_headers(self) -> dict[str, str | Omit]: - return { - **super().default_headers, - "Api-Revision": "2026-05-20", - **self._custom_headers, - } - - @override - def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: - if ( - headers.get("Authorization") - or custom_headers.get("Authorization") - or isinstance(custom_headers.get("Authorization"), Omit) - ): - return - if self.api_key and headers.get("x-goog-api-key"): - return - if custom_headers.get("x-goog-api-key") or isinstance(custom_headers.get("x-goog-api-key"), Omit): - return - - raise TypeError( - '"Could not resolve authentication method. Expected the api_key to be set. Or for the `x-goog-api-key` headers to be explicitly omitted"' - ) - - @override - def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: - if not self.client_adapter or not self.client_adapter.is_vertex_ai(): - return options - - headers = options.headers or {} - has_auth = headers.get("Authorization") or headers.get("x-goog-api-key") # pytype: disable=attribute-error - if has_auth: - return options - - adapted_headers = self.client_adapter.get_auth_headers() - if adapted_headers: - options.headers = {**adapted_headers, **headers} - return options - - def copy( - self, - *, - api_key: str | None = None, - api_version: str | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.Client | None = None, - max_retries: int | NotGiven = not_given, - default_headers: Mapping[str, str] | None = None, - set_default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - set_default_query: Mapping[str, object] | None = None, - client_adapter: GeminiNextGenAPIClientAdapter | None = None, - _extra_kwargs: Mapping[str, Any] = {}, - ) -> Self: - """ - Create a new client instance re-using the same options given to the current client with optional overriding. - """ - if default_headers is not None and set_default_headers is not None: - raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") - - if default_query is not None and set_default_query is not None: - raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") - - headers = self._custom_headers - if default_headers is not None: - headers = {**headers, **default_headers} - elif set_default_headers is not None: - headers = set_default_headers - - params = self._custom_query - if default_query is not None: - params = {**params, **default_query} - elif set_default_query is not None: - params = set_default_query - - http_client = http_client or self._client - return self.__class__( - api_key=api_key or self.api_key, - api_version=api_version or self.api_version, - base_url=base_url or self.base_url, - timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, - http_client=http_client, - max_retries=max_retries if is_given(max_retries) else self.max_retries, - default_headers=headers, - default_query=params, - client_adapter=self.client_adapter or client_adapter, - **_extra_kwargs, - ) - - # Alias for `copy` for nicer inline usage, e.g. - # client.with_options(timeout=10).foo.create(...) - with_options = copy - - def _get_api_version_path_param(self) -> str: - return self.api_version - - @override - def _make_status_error( - self, - err_msg: str, - *, - body: object, - response: httpx.Response, - ) -> APIStatusError: - if response.status_code == 400: - return _exceptions.BadRequestError(err_msg, response=response, body=body) - - if response.status_code == 401: - return _exceptions.AuthenticationError(err_msg, response=response, body=body) - - if response.status_code == 403: - return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) - - if response.status_code == 404: - return _exceptions.NotFoundError(err_msg, response=response, body=body) - - if response.status_code == 409: - return _exceptions.ConflictError(err_msg, response=response, body=body) - - if response.status_code == 422: - return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) - - if response.status_code == 429: - return _exceptions.RateLimitError(err_msg, response=response, body=body) - - if response.status_code >= 500: - return _exceptions.InternalServerError(err_msg, response=response, body=body) - return APIStatusError(err_msg, response=response, body=body) - - -class AsyncGeminiNextGenAPIClient(AsyncAPIClient): - # client options - api_key: str | None - api_version: str - client_adapter: AsyncGeminiNextGenAPIClientAdapter | None - - def __init__( - self, - *, - api_key: str | None = None, - api_version: str | None = "v1beta", - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - # Configure a custom httpx client. - # We provide a `DefaultAsyncHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. - # See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details. - http_client: httpx.AsyncClient | None = None, - client_adapter: AsyncGeminiNextGenAPIClientAdapter | None = None, - # Enable or disable schema validation for data returned by the API. - # When enabled an error APIResponseValidationError is raised - # if the API responds with invalid data for the expected schema. - # - # This parameter may be removed or changed in the future. - # If you rely on this feature, please open a GitHub issue - # outlining your use-case to help us decide if it should be - # part of our public interface in the future. - _strict_response_validation: bool = False, - ) -> None: - """Construct a new async AsyncGeminiNextGenAPIClient client instance. - - This automatically infers the `api_key` argument from the `GEMINI_API_KEY` environment variable if it is not provided. - """ - if api_key is None: - api_key = os.environ.get("GEMINI_API_KEY") - self.api_key = api_key - - if api_version is None: - api_version = "v1beta" - self.api_version = api_version - - if base_url is None: - base_url = os.environ.get("GEMINI_NEXT_GEN_API_BASE_URL") - if base_url is None: - base_url = f"https://generativelanguage.googleapis.com" - - self.client_adapter = client_adapter - - custom_headers_env = os.environ.get("GEMINI_NEXT_GEN_API_CUSTOM_HEADERS") - if custom_headers_env is not None: - parsed: dict[str, str] = {} - for line in custom_headers_env.split("\n"): - colon = line.find(":") - if colon >= 0: - parsed[line[:colon].strip()] = line[colon + 1 :].strip() - default_headers = {**parsed, **(default_headers if is_mapping_t(default_headers) else {})} - - super().__init__( - version=__version__, - base_url=base_url, - max_retries=max_retries, - timeout=timeout, - http_client=http_client, - custom_headers=default_headers, - custom_query=default_query, - _strict_response_validation=_strict_response_validation, - ) - - self._default_stream_cls = AsyncStream - - @cached_property - def interactions(self) -> AsyncInteractionsResource: - from .resources.interactions import AsyncInteractionsResource - - return AsyncInteractionsResource(self) - - @cached_property - def webhooks(self) -> AsyncWebhooksResource: - from .resources.webhooks import AsyncWebhooksResource - - return AsyncWebhooksResource(self) - - @cached_property - def agents(self) -> AsyncAgentsResource: - from .resources.agents import AsyncAgentsResource - - return AsyncAgentsResource(self) - - @cached_property - def with_raw_response(self) -> AsyncGeminiNextGenAPIClientWithRawResponse: - return AsyncGeminiNextGenAPIClientWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncGeminiNextGenAPIClientWithStreamedResponse: - return AsyncGeminiNextGenAPIClientWithStreamedResponse(self) - - @property - @override - def qs(self) -> Querystring: - return Querystring(array_format="comma") - - @property - @override - def auth_headers(self) -> dict[str, str]: - api_key = self.api_key - if api_key is None: - return {} - return {"x-goog-api-key": api_key} - - @property - @override - def default_headers(self) -> dict[str, str | Omit]: - return { - **super().default_headers, - "Api-Revision": "2026-05-20", - **self._custom_headers, - } - - @override - def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: - if ( - headers.get("Authorization") - or custom_headers.get("Authorization") - or isinstance(custom_headers.get("Authorization"), Omit) - ): - return - if self.api_key and headers.get("x-goog-api-key"): - return - if custom_headers.get("x-goog-api-key") or isinstance(custom_headers.get("x-goog-api-key"), Omit): - return - - raise TypeError( - '"Could not resolve authentication method. Expected the api_key to be set. Or for the `x-goog-api-key` headers to be explicitly omitted"' - ) - - @override - async def _prepare_options(self, options: FinalRequestOptions) -> FinalRequestOptions: - if not self.client_adapter or not self.client_adapter.is_vertex_ai(): - return options - - headers = options.headers or {} - has_auth = headers.get("Authorization") or headers.get("x-goog-api-key") # pytype: disable=attribute-error - if has_auth: - return options - - adapted_headers = await self.client_adapter.async_get_auth_headers() - if adapted_headers: - options.headers = {**adapted_headers, **headers} - return options - - def copy( - self, - *, - api_key: str | None = None, - api_version: str | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.AsyncClient | None = None, - max_retries: int | NotGiven = not_given, - default_headers: Mapping[str, str] | None = None, - set_default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - set_default_query: Mapping[str, object] | None = None, - client_adapter: AsyncGeminiNextGenAPIClientAdapter | None = None, - _extra_kwargs: Mapping[str, Any] = {}, - ) -> Self: - """ - Create a new client instance re-using the same options given to the current client with optional overriding. - """ - if default_headers is not None and set_default_headers is not None: - raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") - - if default_query is not None and set_default_query is not None: - raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") - - headers = self._custom_headers - if default_headers is not None: - headers = {**headers, **default_headers} - elif set_default_headers is not None: - headers = set_default_headers - - params = self._custom_query - if default_query is not None: - params = {**params, **default_query} - elif set_default_query is not None: - params = set_default_query - - http_client = http_client or self._client - return self.__class__( - api_key=api_key or self.api_key, - api_version=api_version or self.api_version, - base_url=base_url or self.base_url, - timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, - http_client=http_client, - max_retries=max_retries if is_given(max_retries) else self.max_retries, - default_headers=headers, - default_query=params, - client_adapter=self.client_adapter or client_adapter, - **_extra_kwargs, - ) - - # Alias for `copy` for nicer inline usage, e.g. - # client.with_options(timeout=10).foo.create(...) - with_options = copy - - def _get_api_version_path_param(self) -> str: - return self.api_version - - @override - def _make_status_error( - self, - err_msg: str, - *, - body: object, - response: httpx.Response, - ) -> APIStatusError: - if response.status_code == 400: - return _exceptions.BadRequestError(err_msg, response=response, body=body) - - if response.status_code == 401: - return _exceptions.AuthenticationError(err_msg, response=response, body=body) - - if response.status_code == 403: - return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) - - if response.status_code == 404: - return _exceptions.NotFoundError(err_msg, response=response, body=body) - - if response.status_code == 409: - return _exceptions.ConflictError(err_msg, response=response, body=body) - - if response.status_code == 422: - return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) - - if response.status_code == 429: - return _exceptions.RateLimitError(err_msg, response=response, body=body) - - if response.status_code >= 500: - return _exceptions.InternalServerError(err_msg, response=response, body=body) - return APIStatusError(err_msg, response=response, body=body) - - -class GeminiNextGenAPIClientWithRawResponse: - _client: GeminiNextGenAPIClient - - def __init__(self, client: GeminiNextGenAPIClient) -> None: - self._client = client - - @cached_property - def interactions(self) -> interactions.InteractionsResourceWithRawResponse: - from .resources.interactions import InteractionsResourceWithRawResponse - - return InteractionsResourceWithRawResponse(self._client.interactions) - - @cached_property - def webhooks(self) -> webhooks.WebhooksResourceWithRawResponse: - from .resources.webhooks import WebhooksResourceWithRawResponse - - return WebhooksResourceWithRawResponse(self._client.webhooks) - - @cached_property - def agents(self) -> agents.AgentsResourceWithRawResponse: - from .resources.agents import AgentsResourceWithRawResponse - - return AgentsResourceWithRawResponse(self._client.agents) - - -class AsyncGeminiNextGenAPIClientWithRawResponse: - _client: AsyncGeminiNextGenAPIClient - - def __init__(self, client: AsyncGeminiNextGenAPIClient) -> None: - self._client = client - - @cached_property - def interactions(self) -> interactions.AsyncInteractionsResourceWithRawResponse: - from .resources.interactions import AsyncInteractionsResourceWithRawResponse - - return AsyncInteractionsResourceWithRawResponse(self._client.interactions) - - @cached_property - def webhooks(self) -> webhooks.AsyncWebhooksResourceWithRawResponse: - from .resources.webhooks import AsyncWebhooksResourceWithRawResponse - - return AsyncWebhooksResourceWithRawResponse(self._client.webhooks) - - @cached_property - def agents(self) -> agents.AsyncAgentsResourceWithRawResponse: - from .resources.agents import AsyncAgentsResourceWithRawResponse - - return AsyncAgentsResourceWithRawResponse(self._client.agents) - - -class GeminiNextGenAPIClientWithStreamedResponse: - _client: GeminiNextGenAPIClient - - def __init__(self, client: GeminiNextGenAPIClient) -> None: - self._client = client - - @cached_property - def interactions(self) -> interactions.InteractionsResourceWithStreamingResponse: - from .resources.interactions import InteractionsResourceWithStreamingResponse - - return InteractionsResourceWithStreamingResponse(self._client.interactions) - - @cached_property - def webhooks(self) -> webhooks.WebhooksResourceWithStreamingResponse: - from .resources.webhooks import WebhooksResourceWithStreamingResponse - - return WebhooksResourceWithStreamingResponse(self._client.webhooks) - - @cached_property - def agents(self) -> agents.AgentsResourceWithStreamingResponse: - from .resources.agents import AgentsResourceWithStreamingResponse - - return AgentsResourceWithStreamingResponse(self._client.agents) - - -class AsyncGeminiNextGenAPIClientWithStreamedResponse: - _client: AsyncGeminiNextGenAPIClient - - def __init__(self, client: AsyncGeminiNextGenAPIClient) -> None: - self._client = client - - @cached_property - def interactions(self) -> interactions.AsyncInteractionsResourceWithStreamingResponse: - from .resources.interactions import AsyncInteractionsResourceWithStreamingResponse - - return AsyncInteractionsResourceWithStreamingResponse(self._client.interactions) - - @cached_property - def webhooks(self) -> webhooks.AsyncWebhooksResourceWithStreamingResponse: - from .resources.webhooks import AsyncWebhooksResourceWithStreamingResponse - - return AsyncWebhooksResourceWithStreamingResponse(self._client.webhooks) - - @cached_property - def agents(self) -> agents.AsyncAgentsResourceWithStreamingResponse: - from .resources.agents import AsyncAgentsResourceWithStreamingResponse - - return AsyncAgentsResourceWithStreamingResponse(self._client.agents) - - -Client = GeminiNextGenAPIClient - -AsyncClient = AsyncGeminiNextGenAPIClient diff --git a/google/genai/_interactions/_client_adapter.py b/google/genai/_interactions/_client_adapter.py deleted file mode 100644 index 23ac84830..000000000 --- a/google/genai/_interactions/_client_adapter.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -from abc import ABC, abstractmethod - -__all__ = ["GeminiNextGenAPIClientAdapter", "AsyncGeminiNextGenAPIClientAdapter"] - - -class BaseGeminiNextGenAPIClientAdapter(ABC): - @abstractmethod - def is_vertex_ai(self) -> bool: ... - - @abstractmethod - def get_project(self) -> str | None: ... - - @abstractmethod - def get_location(self) -> str | None: ... - - -class AsyncGeminiNextGenAPIClientAdapter(BaseGeminiNextGenAPIClientAdapter): - @abstractmethod - async def async_get_auth_headers(self) -> dict[str, str] | None: ... - - -class GeminiNextGenAPIClientAdapter(BaseGeminiNextGenAPIClientAdapter): - @abstractmethod - def get_auth_headers(self) -> dict[str, str] | None: ... diff --git a/google/genai/_interactions/_compat.py b/google/genai/_interactions/_compat.py deleted file mode 100644 index d00a0df9c..000000000 --- a/google/genai/_interactions/_compat.py +++ /dev/null @@ -1,241 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload -from datetime import date, datetime -from typing_extensions import Self, Literal, TypedDict - -import pydantic -from pydantic.fields import FieldInfo - -from ._types import IncEx, StrBytesIntFloat - -_T = TypeVar("_T") -_ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) - -# --------------- Pydantic v2, v3 compatibility --------------- - -# Pyright incorrectly reports some of our functions as overriding a method when they don't -# pyright: reportIncompatibleMethodOverride=false - -PYDANTIC_V1 = pydantic.VERSION.startswith("1.") - -if TYPE_CHECKING: - - def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 - ... - - def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: # noqa: ARG001 - ... - - def get_args(t: type[Any]) -> tuple[Any, ...]: # noqa: ARG001 - ... - - def is_union(tp: type[Any] | None) -> bool: # noqa: ARG001 - ... - - def get_origin(t: type[Any]) -> type[Any] | None: # noqa: ARG001 - ... - - def is_literal_type(type_: type[Any]) -> bool: # noqa: ARG001 - ... - - def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 - ... - -else: - # v1 re-exports - if PYDANTIC_V1: - from pydantic.typing import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - is_typeddict as is_typeddict, - is_literal_type as is_literal_type, - ) - from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime - else: - from ._utils import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - parse_date as parse_date, - is_typeddict as is_typeddict, - parse_datetime as parse_datetime, - is_literal_type as is_literal_type, - ) - - -# refactored config -if TYPE_CHECKING: - from pydantic import ConfigDict as ConfigDict -else: - if PYDANTIC_V1: - # TODO: provide an error message here? - ConfigDict = None - else: - from pydantic import ConfigDict as ConfigDict - - -# renamed methods / properties -def parse_obj(model: type[_ModelT], value: object) -> _ModelT: - if PYDANTIC_V1: - return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - else: - return model.model_validate(value) - - -def field_is_required(field: FieldInfo) -> bool: - if PYDANTIC_V1: - return field.required # type: ignore - return field.is_required() - - -def field_get_default(field: FieldInfo) -> Any: - value = field.get_default() - if PYDANTIC_V1: - return value - from pydantic_core import PydanticUndefined - - if value == PydanticUndefined: - return None - return value - - -def field_outer_type(field: FieldInfo) -> Any: - if PYDANTIC_V1: - return field.outer_type_ # type: ignore - return field.annotation - - -def get_model_config(model: type[pydantic.BaseModel]) -> Any: - if PYDANTIC_V1: - return model.__config__ # type: ignore - return model.model_config - - -def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: - if PYDANTIC_V1: - return model.__fields__ # type: ignore - return model.model_fields - - -def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: - if PYDANTIC_V1: - return model.copy(deep=deep) # type: ignore - return model.model_copy(deep=deep) - - -def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: - if PYDANTIC_V1: - return model.json(indent=indent) # type: ignore - return model.model_dump_json(indent=indent) - - -class _ModelDumpKwargs(TypedDict, total=False): - by_alias: bool - - -def model_dump( - model: pydantic.BaseModel, - *, - exclude: IncEx | None = None, - exclude_unset: bool = False, - exclude_defaults: bool = False, - warnings: bool = True, - mode: Literal["json", "python"] = "python", - by_alias: bool | None = None, -) -> dict[str, Any]: - if (not PYDANTIC_V1) or hasattr(model, "model_dump"): - kwargs: _ModelDumpKwargs = {} - if by_alias is not None: - kwargs["by_alias"] = by_alias - return model.model_dump( - mode=mode, - exclude=exclude, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - # warnings are not supported in Pydantic v1 - warnings=True if PYDANTIC_V1 else warnings, - **kwargs, - ) - return cast( - "dict[str, Any]", - model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias) - ), - ) - - -def model_parse(model: type[_ModelT], data: Any) -> _ModelT: - if PYDANTIC_V1: - return model.parse_obj(data) # pyright: ignore[reportDeprecated] - return model.model_validate(data) - - -# generic models -if TYPE_CHECKING: - - class GenericModel(pydantic.BaseModel): ... - -else: - if PYDANTIC_V1: - import pydantic.generics - - class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... - else: - # there no longer needs to be a distinction in v2 but - # we still have to create our own subclass to avoid - # inconsistent MRO ordering errors - class GenericModel(pydantic.BaseModel): ... - - -# cached properties -if TYPE_CHECKING: - cached_property = property - - # we define a separate type (copied from typeshed) - # that represents that `cached_property` is `set`able - # at runtime, which differs from `@property`. - # - # this is a separate type as editors likely special case - # `@property` and we don't want to cause issues just to have - # more helpful internal types. - - class typed_cached_property(Generic[_T]): - func: Callable[[Any], _T] - attrname: str | None - - def __init__(self, func: Callable[[Any], _T]) -> None: ... - - @overload - def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: ... - - @overload - def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: ... - - def __get__(self, instance: object, owner: type[Any] | None = None) -> _T | Self: - raise NotImplementedError() - - def __set_name__(self, owner: type[Any], name: str) -> None: ... - - # __set__ is not defined at runtime, but @cached_property is designed to be settable - def __set__(self, instance: object, value: _T) -> None: ... -else: - from functools import cached_property as cached_property - - typed_cached_property = cached_property diff --git a/google/genai/_interactions/_constants.py b/google/genai/_interactions/_constants.py deleted file mode 100644 index 7241594a6..000000000 --- a/google/genai/_interactions/_constants.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import httpx - -RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response" -OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" - -# default timeout is 1 minute -DEFAULT_TIMEOUT = httpx.Timeout(timeout=60, connect=5.0) -DEFAULT_MAX_RETRIES = 2 -DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) - -INITIAL_RETRY_DELAY = 0.5 -MAX_RETRY_DELAY = 8.0 diff --git a/google/genai/_interactions/_exceptions.py b/google/genai/_interactions/_exceptions.py deleted file mode 100644 index 50c0e904b..000000000 --- a/google/genai/_interactions/_exceptions.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -__all__ = [ - "BadRequestError", - "AuthenticationError", - "PermissionDeniedError", - "NotFoundError", - "ConflictError", - "UnprocessableEntityError", - "RateLimitError", - "InternalServerError", -] - - -class GeminiNextGenAPIClientError(Exception): - pass - - -class APIError(GeminiNextGenAPIClientError): - message: str - request: httpx.Request - - body: object | None - """The API response body. - - If the API responded with a valid JSON structure then this property will be the - decoded result. - - If it isn't a valid JSON structure then this will be the raw response. - - If there was no response associated with this error then it will be `None`. - """ - - def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: # noqa: ARG002 - super().__init__(message) - self.request = request - self.message = message - self.body = body - - -class APIResponseValidationError(APIError): - response: httpx.Response - status_code: int - - def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None: - super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body) - self.response = response - self.status_code = response.status_code - - -class APIStatusError(APIError): - """Raised when an API response has a status code of 4xx or 5xx.""" - - response: httpx.Response - status_code: int - - def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None: - super().__init__(message, response.request, body=body) - self.response = response - self.status_code = response.status_code - - -class APIConnectionError(APIError): - def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None: - super().__init__(message, request, body=None) - - -class APITimeoutError(APIConnectionError): - def __init__(self, request: httpx.Request) -> None: - super().__init__( - message="Request timed out. This is a client-side timeout. You can increase the timeout by setting the `timeout` argument on your request or in the client http options.", - request=request, - ) - - -class BadRequestError(APIStatusError): - status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride] - - -class AuthenticationError(APIStatusError): - status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride] - - -class PermissionDeniedError(APIStatusError): - status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride] - - -class NotFoundError(APIStatusError): - status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride] - - -class ConflictError(APIStatusError): - status_code: Literal[409] = 409 # pyright: ignore[reportIncompatibleVariableOverride] - - -class UnprocessableEntityError(APIStatusError): - status_code: Literal[422] = 422 # pyright: ignore[reportIncompatibleVariableOverride] - - -class RateLimitError(APIStatusError): - status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride] - - -class InternalServerError(APIStatusError): - pass diff --git a/google/genai/_interactions/_files.py b/google/genai/_interactions/_files.py deleted file mode 100644 index f8603936d..000000000 --- a/google/genai/_interactions/_files.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# mypy: ignore-errors -from __future__ import annotations - -import io -import os -import pathlib -from typing import Sequence, cast, overload -from typing_extensions import TypeVar, TypeGuard - -import anyio - -from ._types import ( - FileTypes, - FileContent, - RequestFiles, - HttpxFileTypes, - Base64FileInput, - HttpxFileContent, - HttpxRequestFiles, -) -from ._utils import is_list, is_mapping, is_tuple_t, is_mapping_t, is_sequence_t - -_T = TypeVar("_T") - - -def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: - return isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) - - -def is_file_content(obj: object) -> TypeGuard[FileContent]: - return ( - isinstance(obj, bytes) or isinstance(obj, tuple) or isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) - ) - - -def assert_is_file_content(obj: object, *, key: str | None = None) -> None: - if not is_file_content(obj): - prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`" - raise RuntimeError( - f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead." - ) from None - - -@overload -def to_httpx_files(files: None) -> None: ... - - -@overload -def to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... - - -def to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: - if files is None: - return None - - if is_mapping_t(files): - files = {key: _transform_file(file) for key, file in files.items()} - elif is_sequence_t(files): - files = [(key, _transform_file(file)) for key, file in files] - else: - raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") - - return files - - -def _transform_file(file: FileTypes) -> HttpxFileTypes: - if is_file_content(file): - if isinstance(file, os.PathLike): - path = pathlib.Path(file) - return (path.name, path.read_bytes()) - - return file - - if is_tuple_t(file): - return (file[0], read_file_content(file[1]), *file[2:]) - - raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") - - -def read_file_content(file: FileContent) -> HttpxFileContent: - if isinstance(file, os.PathLike): - return pathlib.Path(file).read_bytes() - return file - - -@overload -async def async_to_httpx_files(files: None) -> None: ... - - -@overload -async def async_to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... - - -async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: - if files is None: - return None - - if is_mapping_t(files): - files = {key: await _async_transform_file(file) for key, file in files.items()} - elif is_sequence_t(files): - files = [(key, await _async_transform_file(file)) for key, file in files] - else: - raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") - - return files - - -async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: - if is_file_content(file): - if isinstance(file, os.PathLike): - path = anyio.Path(file) - return (path.name, await path.read_bytes()) - - return file - - if is_tuple_t(file): - return (file[0], await async_read_file_content(file[1]), *file[2:]) - - raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") - - -async def async_read_file_content(file: FileContent) -> HttpxFileContent: - if isinstance(file, os.PathLike): - return await anyio.Path(file).read_bytes() - - return file - - -def deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]]) -> _T: - """Copy only the containers along the given paths. - - Used to guard against mutation by extract_files without copying the entire structure. - Only dicts and lists that lie on a path are copied; everything else - is returned by reference. - - For example, given paths=[["foo", "files", "file"]] and the structure: - { - "foo": { - "bar": {"baz": {}}, - "files": {"file": } - } - } - The root dict, "foo", and "files" are copied (they lie on the path). - "bar" and "baz" are returned by reference (off the path). - """ - return _deepcopy_with_paths(item, paths, 0) - - -def _deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]], index: int) -> _T: - if not paths: - return item - if is_mapping(item): - key_to_paths: dict[str, list[Sequence[str]]] = {} - for path in paths: - if index < len(path): - key_to_paths.setdefault(path[index], []).append(path) - - # if no path continues through this mapping, it won't be mutated and copying it is redundant - if not key_to_paths: - return item - - result = dict(item) - for key, subpaths in key_to_paths.items(): - if key in result: - result[key] = _deepcopy_with_paths(result[key], subpaths, index + 1) - return cast(_T, result) - if is_list(item): - array_paths = [path for path in paths if index < len(path) and path[index] == ""] - - # if no path expects a list here, nothing will be mutated inside it - return by reference - if not array_paths: - return cast(_T, item) - return cast(_T, [_deepcopy_with_paths(entry, array_paths, index + 1) for entry in item]) - return item diff --git a/google/genai/_interactions/_legacy_lyria.py b/google/genai/_interactions/_legacy_lyria.py deleted file mode 100644 index 4f5e92892..000000000 --- a/google/genai/_interactions/_legacy_lyria.py +++ /dev/null @@ -1,251 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -"""Compatibility shim for the legacy vertex+lyria response/event shape. - -The vertex `aiplatform.googleapis.com` endpoint returns a different schema for -`lyria-3-pro-preview, lyria-3-clip-preview` than the public `generativelanguage.googleapis.com` API: -- non-streaming responses use `outputs: List[Content]` instead of the modern - `steps: List[Step]`, -- streaming SSE events use `interaction.start`, `content.start/delta/stop`, and - `interaction.complete` instead of the modern `interaction.created`, - `step.start/delta/stop`, and `interaction.completed`. - -Two cooperating mechanisms cover the surface: - -1. **Data inspection — non-streaming.** `Interaction._maybe_coerce_outputs` - checks whether the response body's `model` field is in `LEGACY_LYRIA_MODELS` - and rewrites `outputs` to `steps` accordingly. The model field is present on - every Interaction body produced by `create()`, `get()`, and any deferred - parse via `with_raw_response.parse()`, including the nested `interaction` - body inside `interaction.created` / `interaction.completed` SSE events. - This helper does not consult any contextvar; data is the only signal. - -2. **Stream subclass + contextvar — streaming SSE event renames.** Per-event - `event_type` renames have to happen *before* the discriminated-union - dispatch runs and most events don't carry a model field, so we use a - per-iteration contextvar (`LEGACY_LYRIA_SHIM_CTX`) instead of data - inspection. `_base_client._process_response_data` reads it to gate the - rename helper. Two stream subclasses set the contextvar: - - - `LegacyLyriaInteractionStream` / `LegacyLyriaInteractionAsyncStream`: - activate the contextvar unconditionally on entry. Used by `create()`'s - streaming path, where `is_legacy_lyria_request` lets the resource layer - pre-detect the legacy case at request time. - - - `LegacyLyriaInteractionDetectingStream` / `LegacyLyriaInteractionDetectingAsyncStream`: - activate the contextvar lazily, only on observing the first legacy - `event_type`. Used by `get()`'s streaming path, where the model is - unknown until the first event arrives. - - Both pairs reset the contextvar in `finally:` so activation is scoped to - one iteration. -""" - -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, Dict, TypeVar, cast -from contextvars import ContextVar -from typing_extensions import override - -from ._streaming import Stream, AsyncStream - -if TYPE_CHECKING: - from collections.abc import Iterator, AsyncIterator - -__all__ = [ - "LEGACY_LYRIA_SHIM_CTX", - "LEGACY_LYRIA_MODELS", - "is_legacy_lyria_request", - "is_legacy_lyria_response_body", - "maybe_remap_legacy_sse_event", - "LegacyLyriaInteractionStream", - "LegacyLyriaInteractionAsyncStream", - "LegacyLyriaInteractionDetectingStream", - "LegacyLyriaInteractionDetectingAsyncStream", -] - -_T = TypeVar("_T") - -# Set by the streaming subclasses below for the lifetime of one iteration. Read -# by `_base_client._process_response_data` to gate the per-SSE-event -# `event_type` rename (which must happen before discriminator-union dispatch). -# Not consulted by `Interaction._maybe_coerce_outputs` — that helper is purely -# data-gated, so a contextvar leak across yields cannot trigger spurious -# Interaction rewrites. -LEGACY_LYRIA_SHIM_CTX: ContextVar[bool] = ContextVar("legacy_lyria_shim", default=False) - -# Models known to return the legacy vertex shape. Currently exactly one. Kept -# as a frozenset so additional models can be added without touching call sites. -LEGACY_LYRIA_MODELS = frozenset({"lyria-3-pro-preview", "lyria-3-clip-preview"}) - -# Mapping of legacy SSE event_type values to their modern equivalents in the -# `InteractionSSEEvent` discriminator union. Captured live from the vertex -# endpoint for `lyria-3-pro-preview, lyria-3-clip-preview`. -_LEGACY_EVENT_TYPE_RENAMES: Dict[str, str] = { - "interaction.start": "interaction.created", - "content.start": "step.start", - "content.delta": "step.delta", - "content.stop": "step.stop", - "interaction.complete": "interaction.completed", -} - - -def is_legacy_lyria_request(*, is_vertex: bool, model: object) -> bool: - """Return True iff the (client, model) combination needs the shim active. - - Used at request issue time (in the resource layer) to decide whether to - pick the `LegacyLyriaInteractionStream` subclass for streaming requests. - """ - return bool(is_vertex) and isinstance(model, str) and model in LEGACY_LYRIA_MODELS - - -def is_legacy_lyria_response_body(data: object) -> bool: - """Return True iff a parsed response body identifies itself as a legacy-lyria payload. - - Used at parse time (inside `Interaction._maybe_coerce_outputs`) to gate - the `outputs` -> `steps` rewrite. Works for any path that produces an - Interaction body — including `get()` (where the model isn't known until - the response arrives) and `with_raw_response.parse()` (where parsing - happens after the resource-level detection has already returned). - """ - if not isinstance(data, dict): - return False - typed_data: Dict[str, Any] = cast("Dict[str, Any]", data) - model = typed_data.get("model") - return isinstance(model, str) and model in LEGACY_LYRIA_MODELS - - -def maybe_remap_legacy_sse_event(data: Dict[str, Any]) -> Dict[str, Any]: - """Translate one legacy SSE event dict to the modern `InteractionSSEEvent` shape. - - Returns the input unchanged if the `event_type` is not one of the legacy - ones we know how to map. Only the `content.start` mapping is non-trivial: - the legacy event carries a single `content: ` block, while the - modern `step.start` event expects `step: {type: "model_output", content: - []}`. - """ - event_type = data.get("event_type") - if not isinstance(event_type, str) or event_type not in _LEGACY_EVENT_TYPE_RENAMES: - return data - - new_data: Dict[str, Any] = {**data, "event_type": _LEGACY_EVENT_TYPE_RENAMES[event_type]} - - if event_type == "content.start": - content = new_data.pop("content", None) - new_data["step"] = { - "type": "model_output", - "content": [content] if content is not None else [], - } - - return new_data - - -def _is_legacy_event_dict(data: Any) -> bool: - if not isinstance(data, dict): - return False - typed_data: Dict[str, Any] = cast("Dict[str, Any]", data) - event_type = typed_data.get("event_type") - return isinstance(event_type, str) and event_type in _LEGACY_EVENT_TYPE_RENAMES - - -class LegacyLyriaInteractionStream(Stream[_T]): - """Sync stream subclass that activates the legacy-lyria shim eagerly. - - Used by `create(stream=True)` where the resource layer pre-detects the - legacy case via `is_legacy_lyria_request(...)`. The contextvar is set on - iteration start and reset in `finally`, so even an unrecognized first - event won't disable the shim — every event runs through the rename helper - (which is a no-op for unrecognized event_types). - """ - - @override - def __stream__(self) -> "Iterator[_T]": - token = LEGACY_LYRIA_SHIM_CTX.set(True) - try: - yield from super().__stream__() - finally: - LEGACY_LYRIA_SHIM_CTX.reset(token) - - -class LegacyLyriaInteractionAsyncStream(AsyncStream[_T]): - """Async counterpart of `LegacyLyriaInteractionStream`.""" - - @override - async def __stream__(self) -> "AsyncIterator[_T]": - token = LEGACY_LYRIA_SHIM_CTX.set(True) - try: - async for item in super().__stream__(): - yield item - finally: - LEGACY_LYRIA_SHIM_CTX.reset(token) - - -class LegacyLyriaInteractionDetectingStream(Stream[_T]): - """Sync stream subclass that activates the shim lazily on first legacy event. - - Used by `get(stream=True)` where the model isn't known at request time, so - we can't pre-detect. Replicates `Stream.__stream__` to peek at each raw - event dict before parsing; the first event whose `event_type` matches a - known legacy variant flips `LEGACY_LYRIA_SHIM_CTX` for the rest of the - iteration. Reset in `finally`. - - For non-legacy interactions the dynamic detection never activates and the - subclass is a no-op vs. plain `Stream`. - """ - - @override - def __stream__(self) -> "Iterator[_T]": - cast_to = cast(Any, self._cast_to) - response = self.response - process_data = self._client._process_response_data - iterator = self._iter_events() - token = None - try: - for sse in iterator: - if sse.data.startswith("[DONE]"): - break - data = sse.json() - if token is None and _is_legacy_event_dict(data): - token = LEGACY_LYRIA_SHIM_CTX.set(True) - yield process_data(data=data, cast_to=cast_to, response=response) - finally: - if token is not None: - LEGACY_LYRIA_SHIM_CTX.reset(token) - response.close() - - -class LegacyLyriaInteractionDetectingAsyncStream(AsyncStream[_T]): - """Async counterpart of `LegacyLyriaInteractionDetectingStream`.""" - - @override - async def __stream__(self) -> "AsyncIterator[_T]": - cast_to = cast(Any, self._cast_to) - response = self.response - process_data = self._client._process_response_data - iterator = self._iter_events() - token = None - try: - async for sse in iterator: - if sse.data.startswith("[DONE]"): - break - data = sse.json() - if token is None and _is_legacy_event_dict(data): - token = LEGACY_LYRIA_SHIM_CTX.set(True) - yield process_data(data=data, cast_to=cast_to, response=response) - finally: - if token is not None: - LEGACY_LYRIA_SHIM_CTX.reset(token) - await response.aclose() diff --git a/google/genai/_interactions/_models.py b/google/genai/_interactions/_models.py deleted file mode 100644 index 8a7c4b672..000000000 --- a/google/genai/_interactions/_models.py +++ /dev/null @@ -1,968 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# mypy: ignore-errors -from __future__ import annotations - -import os -import inspect -import weakref -from typing import ( - IO, - TYPE_CHECKING, - Any, - Type, - Union, - Generic, - TypeVar, - Callable, - Iterable, - Optional, - AsyncIterable, - cast, -) -from datetime import date, datetime -from typing_extensions import ( - List, - Unpack, - Literal, - ClassVar, - Protocol, - Required, - Annotated, - ParamSpec, - TypeAlias, - TypedDict, - TypeGuard, - final, - override, - runtime_checkable, -) - -import pydantic -from pydantic.fields import FieldInfo - -from ._types import ( - Body, - IncEx, - Query, - ModelT, - Headers, - Timeout, - NotGiven, - AnyMapping, - HttpxRequestFiles, -) -from ._utils import ( - PropertyInfo, - is_list, - is_given, - json_safe, - lru_cache, - is_mapping, - parse_date, - coerce_boolean, - parse_datetime, - strip_not_given, - extract_type_arg, - is_annotated_type, - is_type_alias_type, - strip_annotated_type, -) -from ._compat import ( - PYDANTIC_V1, - ConfigDict, - GenericModel as BaseGenericModel, - get_args, - is_union, - parse_obj, - get_origin, - is_literal_type, - get_model_config, - get_model_fields, - field_get_default, -) -from ._constants import RAW_RESPONSE_HEADER - -if TYPE_CHECKING: - from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler - from pydantic_core import CoreSchema, core_schema - from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema -else: - try: - from pydantic_core import CoreSchema, core_schema - except ImportError: - CoreSchema = None - core_schema = None - -__all__ = ["BaseModel", "GenericModel"] - -_T = TypeVar("_T") -_BaseModelT = TypeVar("_BaseModelT", bound="BaseModel") - -P = ParamSpec("P") - - -@runtime_checkable -class _ConfigProtocol(Protocol): - allow_population_by_field_name: bool - - -class BaseModel(pydantic.BaseModel): - if PYDANTIC_V1: - - @property - @override - def model_fields_set(self) -> set[str]: - # a forwards-compat shim for pydantic v2 - return self.__fields_set__ # type: ignore - - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] - extra: Any = pydantic.Extra.allow # type: ignore - else: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) - ) - - def to_dict( - self, - *, - mode: Literal["json", "python"] = "python", - use_api_names: bool = True, - exclude_unset: bool = True, - exclude_defaults: bool = False, - exclude_none: bool = False, - warnings: bool = True, - ) -> dict[str, object]: - """Recursively generate a dictionary representation of the model, optionally specifying which fields to include or exclude. - - By default, fields that were not set by the API will not be included, - and keys will match the API response, *not* the property names from the model. - - For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, - the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). - - Args: - mode: - If mode is 'json', the dictionary will only contain JSON serializable types. e.g. `datetime` will be turned into a string, `"2024-3-22T18:11:19.117000Z"`. - If mode is 'python', the dictionary may contain any Python objects. e.g. `datetime(2024, 3, 22)` - - use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that are set to their default value from the output. - exclude_none: Whether to exclude fields that have a value of `None` from the output. - warnings: Whether to log warnings when invalid fields are encountered. This is only supported in Pydantic v2. - """ - return self.model_dump( - mode=mode, - by_alias=use_api_names, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - warnings=warnings, - ) - - def to_json( - self, - *, - indent: int | None = 2, - use_api_names: bool = True, - exclude_unset: bool = True, - exclude_defaults: bool = False, - exclude_none: bool = False, - warnings: bool = True, - ) -> str: - """Generates a JSON string representing this model as it would be received from or sent to the API (but with indentation). - - By default, fields that were not set by the API will not be included, - and keys will match the API response, *not* the property names from the model. - - For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, - the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). - - Args: - indent: Indentation to use in the JSON output. If `None` is passed, the output will be compact. Defaults to `2` - use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that have the default value. - exclude_none: Whether to exclude fields that have a value of `None`. - warnings: Whether to show any warnings that occurred during serialization. This is only supported in Pydantic v2. - """ - return self.model_dump_json( - indent=indent, - by_alias=use_api_names, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - warnings=warnings, - ) - - @override - def __str__(self) -> str: - # mypy complains about an invalid self arg - return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] - - # Override the 'construct' method in a way that supports recursive parsing without validation. - # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. - @classmethod - @override - def construct( # pyright: ignore[reportIncompatibleMethodOverride] - __cls: Type[ModelT], - _fields_set: set[str] | None = None, - **values: object, - ) -> ModelT: - m = __cls.__new__(__cls) - fields_values: dict[str, object] = {} - - config = get_model_config(__cls) - populate_by_name = ( - config.allow_population_by_field_name - if isinstance(config, _ConfigProtocol) - else config.get("populate_by_name") - ) - - if _fields_set is None: - _fields_set = set() - - model_fields = get_model_fields(__cls) - for name, field in model_fields.items(): - key = field.alias - if key is None or (key not in values and populate_by_name): - key = name - - if key in values: - fields_values[name] = _construct_field(value=values[key], field=field, key=key) - _fields_set.add(name) - else: - fields_values[name] = field_get_default(field) - - extra_field_type = _get_extra_fields_type(__cls) - - _extra = {} - for key, value in values.items(): - if key not in model_fields: - parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value - - if PYDANTIC_V1: - _fields_set.add(key) - fields_values[key] = parsed - else: - _extra[key] = parsed - - object.__setattr__(m, "__dict__", fields_values) - - if PYDANTIC_V1: - # init_private_attributes() does not exist in v2 - m._init_private_attributes() # type: ignore - - # copied from Pydantic v1's `construct()` method - object.__setattr__(m, "__fields_set__", _fields_set) - else: - # these properties are copied from Pydantic's `model_construct()` method - object.__setattr__(m, "__pydantic_private__", None) - object.__setattr__(m, "__pydantic_extra__", _extra) - object.__setattr__(m, "__pydantic_fields_set__", _fields_set) - - return m - - if not TYPE_CHECKING: - # type checkers incorrectly complain about this assignment - # because the type signatures are technically different - # although not in practice - model_construct = construct - - if PYDANTIC_V1: - # we define aliases for some of the new pydantic v2 methods so - # that we can just document these methods without having to specify - # a specific pydantic version as some users may not know which - # pydantic version they are currently using - - @override - def model_dump( - self, - *, - mode: Literal["json", "python"] | str = "python", - include: IncEx | None = None, - exclude: IncEx | None = None, - context: Any | None = None, - by_alias: bool | None = None, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - exclude_computed_fields: bool = False, - round_trip: bool = False, - warnings: bool | Literal["none", "warn", "error"] = True, - fallback: Callable[[Any], Any] | None = None, - serialize_as_any: bool = False, - ) -> dict[str, Any]: - """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump - - Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. - - Args: - mode: The mode in which `to_python` should run. - If mode is 'json', the output will only contain JSON serializable types. - If mode is 'python', the output may contain non-JSON-serializable Python objects. - include: A set of fields to include in the output. - exclude: A set of fields to exclude from the output. - context: Additional context to pass to the serializer. - by_alias: Whether to use the field's alias in the dictionary key if defined. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that are set to their default value. - exclude_none: Whether to exclude fields that have a value of `None`. - exclude_computed_fields: Whether to exclude computed fields. - While this can be useful for round-tripping, it is usually recommended to use the dedicated - `round_trip` parameter instead. - round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. - warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, - "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. - fallback: A function to call when an unknown value is encountered. If not provided, - a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. - serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. - - Returns: - A dictionary representation of the model. - """ - if mode not in {"json", "python"}: - raise ValueError("mode must be either 'json' or 'python'") - if round_trip != False: - raise ValueError("round_trip is only supported in Pydantic v2") - if warnings != True: - raise ValueError("warnings is only supported in Pydantic v2") - if context is not None: - raise ValueError("context is only supported in Pydantic v2") - if serialize_as_any != False: - raise ValueError("serialize_as_any is only supported in Pydantic v2") - if fallback is not None: - raise ValueError("fallback is only supported in Pydantic v2") - if exclude_computed_fields != False: - raise ValueError("exclude_computed_fields is only supported in Pydantic v2") - dumped = super().dict( # pyright: ignore[reportDeprecated] - include=include, - exclude=exclude, - by_alias=by_alias if by_alias is not None else False, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped - - @override - def model_dump_json( - self, - *, - indent: int | None = None, - ensure_ascii: bool = False, - include: IncEx | None = None, - exclude: IncEx | None = None, - context: Any | None = None, - by_alias: bool | None = None, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - exclude_computed_fields: bool = False, - round_trip: bool = False, - warnings: bool | Literal["none", "warn", "error"] = True, - fallback: Callable[[Any], Any] | None = None, - serialize_as_any: bool = False, - ) -> str: - """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json - - Generates a JSON representation of the model using Pydantic's `to_json` method. - - Args: - indent: Indentation to use in the JSON output. If None is passed, the output will be compact. - include: Field(s) to include in the JSON output. Can take either a string or set of strings. - exclude: Field(s) to exclude from the JSON output. Can take either a string or set of strings. - by_alias: Whether to serialize using field aliases. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that have the default value. - exclude_none: Whether to exclude fields that have a value of `None`. - round_trip: Whether to use serialization/deserialization between JSON and class instance. - warnings: Whether to show any warnings that occurred during serialization. - - Returns: - A JSON string representation of the model. - """ - if round_trip != False: - raise ValueError("round_trip is only supported in Pydantic v2") - if warnings != True: - raise ValueError("warnings is only supported in Pydantic v2") - if context is not None: - raise ValueError("context is only supported in Pydantic v2") - if serialize_as_any != False: - raise ValueError("serialize_as_any is only supported in Pydantic v2") - if fallback is not None: - raise ValueError("fallback is only supported in Pydantic v2") - if ensure_ascii != False: - raise ValueError("ensure_ascii is only supported in Pydantic v2") - if exclude_computed_fields != False: - raise ValueError("exclude_computed_fields is only supported in Pydantic v2") - return super().json( # type: ignore[reportDeprecated] - indent=indent, - include=include, - exclude=exclude, - by_alias=by_alias if by_alias is not None else False, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - -class _EagerIterable(list[_T], Generic[_T]): - """ - Accepts any Iterable[T] input (including generators), consumes it - eagerly, and validates all items upfront. - - Validation preserves the original container type where possible - (e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON) - always emits a list — round-tripping through model_dump() will not - restore the original container type. - """ - - @classmethod - def __get_pydantic_core_schema__( - cls, - source_type: Any, - handler: GetCoreSchemaHandler, - ) -> CoreSchema: - (item_type,) = get_args(source_type) or (Any,) - item_schema: CoreSchema = handler.generate_schema(item_type) - list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema) - - return core_schema.no_info_wrap_validator_function( - cls._validate, - list_of_items_schema, - serialization=core_schema.plain_serializer_function_ser_schema( - cls._serialize, - info_arg=False, - ), - ) - - @staticmethod - def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any: - original_type: type[Any] = type(v) - - # Normalize to list so list_schema can validate each item - if isinstance(v, list): - items: list[_T] = v - else: - try: - items = list(v) - except TypeError as e: - raise TypeError("Value is not iterable") from e - - # Validate items against the inner schema - validated: list[_T] = handler(items) - - # Reconstruct original container type - if original_type is list: - return validated - # str(list) produces the list's repr, not a string built from items, - # so skip reconstruction for str and its subclasses. - if issubclass(original_type, str): - return validated - try: - return original_type(validated) - except (TypeError, ValueError): - # If the type cannot be reconstructed, just return the validated list - return validated - - @staticmethod - def _serialize(v: Iterable[_T]) -> list[_T]: - """Always serialize as a list so Pydantic's JSON encoder is happy.""" - if isinstance(v, list): - return v - return list(v) - - -EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable] - - -def _construct_field(value: object, field: FieldInfo, key: str) -> object: - if value is None: - return field_get_default(field) - - if PYDANTIC_V1: - type_ = cast(type, field.outer_type_) # type: ignore - else: - type_ = field.annotation # type: ignore - - if type_ is None: - raise RuntimeError(f"Unexpected field type is None for {key}") - - return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) - - -def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: - if PYDANTIC_V1: - # TODO - return None - - schema = cls.__pydantic_core_schema__ - if schema["type"] == "model": - fields = schema["schema"] - if fields["type"] == "model-fields": - extras = fields.get("extras_schema") - if extras and "cls" in extras: - # mypy can't narrow the type - return extras["cls"] # type: ignore[no-any-return] - - return None - - -def is_basemodel(type_: type) -> bool: - """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`""" - if is_union(type_): - for variant in get_args(type_): - if is_basemodel(variant): - return True - - return False - - return is_basemodel_type(type_) - - -def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]: - origin = get_origin(type_) or type_ - if not inspect.isclass(origin): - return False - return issubclass(origin, BaseModel) or issubclass(origin, GenericModel) - - -def build( - base_model_cls: Callable[P, _BaseModelT], - *args: P.args, - **kwargs: P.kwargs, -) -> _BaseModelT: - """Construct a BaseModel class without validation. - - This is useful for cases where you need to instantiate a `BaseModel` - from an API response as this provides type-safe params which isn't supported - by helpers like `construct_type()`. - - ```py - build(MyModel, my_field_a="foo", my_field_b=123) - ``` - """ - if args: - raise TypeError( - "Received positional arguments which are not supported; Keyword arguments must be used instead", - ) - - return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs)) - - -def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: - """Loose coercion to the expected type with construction of nested values. - - Note: the returned value from this function is not guaranteed to match the - given type. - """ - return cast(_T, construct_type(value=value, type_=type_)) - - -def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: - """Loose coercion to the expected type with construction of nested values. - - If the given value does not match the expected type then it is returned as-is. - """ - - # store a reference to the original type we were given before we extract any inner - # types so that we can properly resolve forward references in `TypeAliasType` annotations - original_type = None - - # we allow `object` as the input type because otherwise, passing things like - # `Literal['value']` will be reported as a type error by type checkers - type_ = cast("type[object]", type_) - if is_type_alias_type(type_): - original_type = type_ # type: ignore[unreachable] - type_ = type_.__value__ # type: ignore[unreachable] - - # unwrap `Annotated[T, ...]` -> `T` - if metadata is not None and len(metadata) > 0: - meta: tuple[Any, ...] = tuple(metadata) - elif is_annotated_type(type_): - meta = get_args(type_)[1:] - type_ = extract_type_arg(type_, 0) - else: - meta = tuple() - - # we need to use the origin class for any types that are subscripted generics - # e.g. Dict[str, object] - origin = get_origin(type_) or type_ - args = get_args(type_) - - if is_union(origin): - try: - return validate_type(type_=cast("type[object]", original_type or type_), value=value) - except Exception: - pass - - # if the type is a discriminated union then we want to construct the right variant - # in the union, even if the data doesn't match exactly, otherwise we'd break code - # that relies on the constructed class types, e.g. - # - # class FooType: - # kind: Literal['foo'] - # value: str - # - # class BarType: - # kind: Literal['bar'] - # value: int - # - # without this block, if the data we get is something like `{'kind': 'bar', 'value': 'foo'}` then - # we'd end up constructing `FooType` when it should be `BarType`. - discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta) - if discriminator and is_mapping(value): - variant_value = value.get(discriminator.field_alias_from or discriminator.field_name) - if variant_value and isinstance(variant_value, str): - variant_type = discriminator.mapping.get(variant_value) - if variant_type: - return construct_type(type_=variant_type, value=value) - - # if the data is not valid, use the first variant that doesn't fail while deserializing - for variant in args: - try: - return construct_type(value=value, type_=variant) - except Exception: - continue - - raise RuntimeError(f"Could not convert data into a valid instance of {type_}") - - if origin == dict: - if not is_mapping(value): - return value - - _, items_type = get_args(type_) # Dict[_, items_type] - return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} - - if ( - not is_literal_type(type_) - and inspect.isclass(origin) - and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)) - ): - if is_list(value): - return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value] - - if is_mapping(value): - if issubclass(type_, BaseModel): - return type_.construct(**value) # type: ignore[arg-type] - - return cast(Any, type_).construct(**value) - - if origin == list: - if not is_list(value): - return value - - inner_type = args[0] # List[inner_type] - return [construct_type(value=entry, type_=inner_type) for entry in value] - - if origin == float: - if isinstance(value, int): - coerced = float(value) - if coerced != value: - return value - return coerced - - return value - - if type_ == datetime: - try: - return parse_datetime(value) # type: ignore - except Exception: - return value - - if type_ == date: - try: - return parse_date(value) # type: ignore - except Exception: - return value - - return value - - -@runtime_checkable -class CachedDiscriminatorType(Protocol): - __discriminator__: DiscriminatorDetails - - -DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() - - -class DiscriminatorDetails: - field_name: str - """The name of the discriminator field in the variant class, e.g. - - ```py - class Foo(BaseModel): - type: Literal['foo'] - ``` - - Will result in field_name='type' - """ - - field_alias_from: str | None - """The name of the discriminator field in the API response, e.g. - - ```py - class Foo(BaseModel): - type: Literal['foo'] = Field(alias='type_from_api') - ``` - - Will result in field_alias_from='type_from_api' - """ - - mapping: dict[str, type] - """Mapping of discriminator value to variant type, e.g. - - {'foo': FooVariant, 'bar': BarVariant} - """ - - def __init__( - self, - *, - mapping: dict[str, type], - discriminator_field: str, - discriminator_alias: str | None, - ) -> None: - self.mapping = mapping - self.field_name = discriminator_field - self.field_alias_from = discriminator_alias - - -def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: - cached = DISCRIMINATOR_CACHE.get(union) - if cached is not None: - return cached - - discriminator_field_name: str | None = None - - for annotation in meta_annotations: - if isinstance(annotation, PropertyInfo) and annotation.discriminator is not None: - discriminator_field_name = annotation.discriminator - break - - if not discriminator_field_name: - return None - - mapping: dict[str, type] = {} - discriminator_alias: str | None = None - - for variant in get_args(union): - variant = strip_annotated_type(variant) - if is_basemodel_type(variant): - if PYDANTIC_V1: - field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - if not field_info: - continue - - # Note: if one variant defines an alias then they all should - discriminator_alias = field_info.alias - - if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): - for entry in get_args(annotation): - if isinstance(entry, str): - mapping[entry] = variant - else: - field = _extract_field_schema_pv2(variant, discriminator_field_name) - if not field: - continue - - # Note: if one variant defines an alias then they all should - discriminator_alias = field.get("serialization_alias") - - field_schema = field["schema"] - - if field_schema["type"] == "literal": - for entry in cast("LiteralSchema", field_schema)["expected"]: - if isinstance(entry, str): - mapping[entry] = variant - - if not mapping: - return None - - details = DiscriminatorDetails( - mapping=mapping, - discriminator_field=discriminator_field_name, - discriminator_alias=discriminator_alias, - ) - DISCRIMINATOR_CACHE.setdefault(union, details) - return details - - -def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: - schema = model.__pydantic_core_schema__ - if schema["type"] == "definitions": - schema = schema["schema"] - - if schema["type"] != "model": - return None - - schema = cast("ModelSchema", schema) - fields_schema = schema["schema"] - if fields_schema["type"] != "model-fields": - return None - - fields_schema = cast("ModelFieldsSchema", fields_schema) - field = fields_schema["fields"].get(field_name) - if not field: - return None - - return cast("ModelField", field) # pyright: ignore[reportUnnecessaryCast] - - -def validate_type(*, type_: type[_T], value: object) -> _T: - """Strict validation that the given value matches the expected type""" - if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel): - return cast(_T, parse_obj(type_, value)) - - return cast(_T, _validate_non_model_type(type_=type_, value=value)) - - -def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: - """Add a pydantic config for the given type. - - Note: this is a no-op on Pydantic v1. - """ - setattr(typ, "__pydantic_config__", config) # noqa: B010 - - -# our use of subclassing here causes weirdness for type checkers, -# so we just pretend that we don't subclass -if TYPE_CHECKING: - GenericModel = BaseModel -else: - - class GenericModel(BaseGenericModel, BaseModel): - pass - - -if not PYDANTIC_V1: - from pydantic import TypeAdapter as _TypeAdapter - - _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) - - if TYPE_CHECKING: - from pydantic import TypeAdapter - else: - TypeAdapter = _CachedTypeAdapter - - def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: - return TypeAdapter(type_).validate_python(value) - -elif not TYPE_CHECKING: # TODO: condition is weird - - class RootModel(GenericModel, Generic[_T]): - """Used as a placeholder to easily convert runtime types to a Pydantic format - to provide validation. - - For example: - ```py - validated = RootModel[int](__root__="5").__root__ - # validated: 5 - ``` - """ - - __root__: _T - - def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: - model = _create_pydantic_model(type_).validate(value) - return cast(_T, model.__root__) - - def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]: - return RootModel[type_] # type: ignore - - -class FinalRequestOptionsInput(TypedDict, total=False): - method: Required[str] - url: Required[str] - params: Query - headers: Headers - max_retries: int - timeout: float | Timeout | None - files: HttpxRequestFiles | None - idempotency_key: str - content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] - json_data: Body - extra_json: AnyMapping - follow_redirects: bool - - -@final -class FinalRequestOptions(pydantic.BaseModel): - method: str - url: str - params: Query = {} - headers: Union[Headers, NotGiven] = NotGiven() - max_retries: Union[int, NotGiven] = NotGiven() - timeout: Union[float, Timeout, None, NotGiven] = NotGiven() - files: Union[HttpxRequestFiles, None] = None - idempotency_key: Union[str, None] = None - post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() - follow_redirects: Union[bool, None] = None - - content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None - # It should be noted that we cannot use `json` here as that would override - # a BaseModel method in an incompatible fashion. - json_data: Union[Body, None] = None - extra_json: Union[AnyMapping, None] = None - - if PYDANTIC_V1: - - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] - arbitrary_types_allowed: bool = True - else: - model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) - - def get_max_retries(self, max_retries: int) -> int: - if isinstance(self.max_retries, NotGiven): - return max_retries - return self.max_retries - - def _strip_raw_response_header(self) -> None: - if not is_given(self.headers): - return - - if self.headers.get(RAW_RESPONSE_HEADER): - self.headers = {**self.headers} - self.headers.pop(RAW_RESPONSE_HEADER) - - # override the `construct` method so that we can run custom transformations. - # this is necessary as we don't want to do any actual runtime type checking - # (which means we can't use validators) but we do want to ensure that `NotGiven` - # values are not present - # - # type ignore required because we're adding explicit types to `**values` - @classmethod - def construct( # type: ignore - cls, - _fields_set: set[str] | None = None, - **values: Unpack[FinalRequestOptionsInput], - ) -> FinalRequestOptions: - kwargs: dict[str, Any] = { - # we unconditionally call `strip_not_given` on any value - # as it will just ignore any non-mapping types - key: strip_not_given(value) - for key, value in values.items() - } - if PYDANTIC_V1: - return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] - return super().model_construct(_fields_set, **kwargs) - - if not TYPE_CHECKING: - # type checkers incorrectly complain about this assignment - model_construct = construct diff --git a/google/genai/_interactions/_qs.py b/google/genai/_interactions/_qs.py deleted file mode 100644 index f48af2d96..000000000 --- a/google/genai/_interactions/_qs.py +++ /dev/null @@ -1,164 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -from typing import Any, List, Tuple, Union, Mapping, TypeVar -from urllib.parse import parse_qs, urlencode -from typing_extensions import get_args - -from ._types import NotGiven, ArrayFormat, NestedFormat, not_given -from ._utils import flatten - -_T = TypeVar("_T") - -PrimitiveData = Union[str, int, float, bool, None] -# this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] -# https://github.com/microsoft/pyright/issues/3555 -Data = Union[PrimitiveData, List[Any], Tuple[Any], "Mapping[str, Any]"] -Params = Mapping[str, Data] - - -class Querystring: - array_format: ArrayFormat - nested_format: NestedFormat - - def __init__( - self, - *, - array_format: ArrayFormat = "repeat", - nested_format: NestedFormat = "brackets", - ) -> None: - self.array_format = array_format - self.nested_format = nested_format - - def parse(self, query: str) -> Mapping[str, object]: - # Note: custom format syntax is not supported yet - return parse_qs(query) - - def stringify( - self, - params: Params, - *, - array_format: ArrayFormat | NotGiven = not_given, - nested_format: NestedFormat | NotGiven = not_given, - ) -> str: - return urlencode( - self.stringify_items( - params, - array_format=array_format, - nested_format=nested_format, - ) - ) - - def stringify_items( - self, - params: Params, - *, - array_format: ArrayFormat | NotGiven = not_given, - nested_format: NestedFormat | NotGiven = not_given, - ) -> list[tuple[str, str]]: - opts = Options( - qs=self, - array_format=array_format, - nested_format=nested_format, - ) - return flatten([self._stringify_item(key, value, opts) for key, value in params.items()]) - - def _stringify_item( - self, - key: str, - value: Data, - opts: Options, - ) -> list[tuple[str, str]]: - if isinstance(value, Mapping): - items: list[tuple[str, str]] = [] - nested_format = opts.nested_format - for subkey, subvalue in value.items(): - items.extend( - self._stringify_item( - # TODO: error if unknown format - f"{key}.{subkey}" if nested_format == "dots" else f"{key}[{subkey}]", - subvalue, - opts, - ) - ) - return items - - if isinstance(value, (list, tuple)): - array_format = opts.array_format - if array_format == "comma": - return [ - ( - key, - ",".join(self._primitive_value_to_str(item) for item in value if item is not None), - ), - ] - elif array_format == "repeat": - items = [] - for item in value: - items.extend(self._stringify_item(key, item, opts)) - return items - elif array_format == "indices": - items = [] - for i, item in enumerate(value): - items.extend(self._stringify_item(f"{key}[{i}]", item, opts)) - return items - elif array_format == "brackets": - items = [] - key = key + "[]" - for item in value: - items.extend(self._stringify_item(key, item, opts)) - return items - else: - raise NotImplementedError( - f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" - ) - - serialised = self._primitive_value_to_str(value) - if not serialised: - return [] - return [(key, serialised)] - - def _primitive_value_to_str(self, value: PrimitiveData) -> str: - # copied from httpx - if value is True: - return "true" - elif value is False: - return "false" - elif value is None: - return "" - return str(value) - - -_qs = Querystring() -parse = _qs.parse -stringify = _qs.stringify -stringify_items = _qs.stringify_items - - -class Options: - array_format: ArrayFormat - nested_format: NestedFormat - - def __init__( - self, - qs: Querystring = _qs, - *, - array_format: ArrayFormat | NotGiven = not_given, - nested_format: NestedFormat | NotGiven = not_given, - ) -> None: - self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format - self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/google/genai/_interactions/_resource.py b/google/genai/_interactions/_resource.py deleted file mode 100644 index 4739db925..000000000 --- a/google/genai/_interactions/_resource.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import time -from typing import TYPE_CHECKING - -import anyio - -if TYPE_CHECKING: - from ._client import GeminiNextGenAPIClient, AsyncGeminiNextGenAPIClient - - -class SyncAPIResource: - _client: GeminiNextGenAPIClient - - def __init__(self, client: GeminiNextGenAPIClient) -> None: - self._client = client - self._get = client.get - self._post = client.post - self._patch = client.patch - self._put = client.put - self._delete = client.delete - self._get_api_list = client.get_api_list - - def _sleep(self, seconds: float) -> None: - time.sleep(seconds) - - -class AsyncAPIResource: - _client: AsyncGeminiNextGenAPIClient - - def __init__(self, client: AsyncGeminiNextGenAPIClient) -> None: - self._client = client - self._get = client.get - self._post = client.post - self._patch = client.patch - self._put = client.put - self._delete = client.delete - self._get_api_list = client.get_api_list - - async def _sleep(self, seconds: float) -> None: - await anyio.sleep(seconds) diff --git a/google/genai/_interactions/_response.py b/google/genai/_interactions/_response.py deleted file mode 100644 index 12077e049..000000000 --- a/google/genai/_interactions/_response.py +++ /dev/null @@ -1,850 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -import os -import inspect -import logging -import datetime -import functools -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Union, - Generic, - TypeVar, - Callable, - Iterator, - AsyncIterator, - cast, - overload, -) -from typing_extensions import Awaitable, ParamSpec, override, get_origin - -import anyio -import httpx -import pydantic - -from ._types import NoneType -from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base -from ._models import BaseModel, is_basemodel -from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER -from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type -from ._exceptions import APIResponseValidationError, GeminiNextGenAPIClientError - -if TYPE_CHECKING: - from ._models import FinalRequestOptions - from ._base_client import BaseClient - - -P = ParamSpec("P") -R = TypeVar("R") -_T = TypeVar("_T") -_APIResponseT = TypeVar("_APIResponseT", bound="APIResponse[Any]") -_AsyncAPIResponseT = TypeVar("_AsyncAPIResponseT", bound="AsyncAPIResponse[Any]") - -log: logging.Logger = logging.getLogger(__name__) - - -class BaseAPIResponse(Generic[R]): - _cast_to: type[R] - _client: BaseClient[Any, Any] - _parsed_by_type: dict[type[Any], Any] - _is_sse_stream: bool - _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None - _options: FinalRequestOptions - - http_response: httpx.Response - - retries_taken: int - """The number of retries made. If no retries happened this will be `0`""" - - def __init__( - self, - *, - raw: httpx.Response, - cast_to: type[R], - client: BaseClient[Any, Any], - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - options: FinalRequestOptions, - retries_taken: int = 0, - ) -> None: - self._cast_to = cast_to - self._client = client - self._parsed_by_type = {} - self._is_sse_stream = stream - self._stream_cls = stream_cls - self._options = options - self.http_response = raw - self.retries_taken = retries_taken - - @property - def headers(self) -> httpx.Headers: - return self.http_response.headers - - @property - def http_request(self) -> httpx.Request: - """Returns the httpx Request instance associated with the current response.""" - return self.http_response.request - - @property - def status_code(self) -> int: - return self.http_response.status_code - - @property - def url(self) -> httpx.URL: - """Returns the URL for which the request was made.""" - return self.http_response.url - - @property - def method(self) -> str: - return self.http_request.method - - @property - def http_version(self) -> str: - return self.http_response.http_version - - @property - def elapsed(self) -> datetime.timedelta: - """The time taken for the complete request/response cycle to complete.""" - return self.http_response.elapsed - - @property - def is_closed(self) -> bool: - """Whether or not the response body has been closed. - - If this is False then there is response data that has not been read yet. - You must either fully consume the response body or call `.close()` - before discarding the response to prevent resource leaks. - """ - return self.http_response.is_closed - - @override - def __repr__(self) -> str: - return ( - f"<{self.__class__.__name__} [{self.status_code} {self.http_response.reason_phrase}] type={self._cast_to}>" - ) - - def _parse(self, *, to: type[_T] | None = None) -> R | _T: - cast_to = to if to is not None else self._cast_to - - # unwrap `TypeAlias('Name', T)` -> `T` - if is_type_alias_type(cast_to): - cast_to = cast_to.__value__ # type: ignore[unreachable] - - # unwrap `Annotated[T, ...]` -> `T` - if cast_to and is_annotated_type(cast_to): - cast_to = extract_type_arg(cast_to, 0) - - origin = get_origin(cast_to) or cast_to - - if self._is_sse_stream: - if to: - if not is_stream_class_type(to): - raise TypeError(f"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}") - - return cast( - _T, - to( - cast_to=extract_stream_chunk_type( - to, - failure_message="Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]", - ), - response=self.http_response, - client=cast(Any, self._client), - options=self._options, - ), - ) - - if self._stream_cls: - return cast( - R, - self._stream_cls( - cast_to=extract_stream_chunk_type(self._stream_cls), - response=self.http_response, - client=cast(Any, self._client), - options=self._options, - ), - ) - - stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls) - if stream_cls is None: - raise MissingStreamClassError() - - return cast( - R, - stream_cls( - cast_to=cast_to, - response=self.http_response, - client=cast(Any, self._client), - options=self._options, - ), - ) - - if cast_to is NoneType: - return cast(R, None) - - response = self.http_response - if cast_to == str: - return cast(R, response.text) - - if cast_to == bytes: - return cast(R, response.content) - - if cast_to == int: - return cast(R, int(response.text)) - - if cast_to == float: - return cast(R, float(response.text)) - - if cast_to == bool: - return cast(R, response.text.lower() == "true") - - if origin == APIResponse: - raise RuntimeError("Unexpected state - cast_to is `APIResponse`") - - if inspect.isclass(origin) and issubclass(origin, httpx.Response): - # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response - # and pass that class to our request functions. We cannot change the variance to be either - # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct - # the response class ourselves but that is something that should be supported directly in httpx - # as it would be easy to incorrectly construct the Response object due to the multitude of arguments. - if cast_to != httpx.Response: - raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") - return cast(R, response) - - if ( - inspect.isclass( - origin # pyright: ignore[reportUnknownArgumentType] - ) - and not issubclass(origin, BaseModel) - and issubclass(origin, pydantic.BaseModel) - ): - raise TypeError( - "Pydantic models must subclass our base model type, e.g. `from google.genai._interactions import BaseModel`" - ) - - if ( - cast_to is not object - and not origin is list - and not origin is dict - and not origin is Union - and not issubclass(origin, BaseModel) - ): - raise RuntimeError( - f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}." - ) - - # split is required to handle cases where additional information is included - # in the response, e.g. application/json; charset=utf-8 - content_type, *_ = response.headers.get("content-type", "*").split(";") - if not content_type.endswith("json"): - if is_basemodel(cast_to): - try: - data = response.json() - except Exception as exc: - log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc) - else: - return self._client._process_response_data( - data=data, - cast_to=cast_to, # type: ignore - response=response, - ) - - if self._client._strict_response_validation: - raise APIResponseValidationError( - response=response, - message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.", - body=response.text, - ) - - # If the API responds with content that isn't JSON then we just return - # the (decoded) text without performing any parsing so that you can still - # handle the response however you need to. - return response.text # type: ignore - - data = response.json() - - return self._client._process_response_data( - data=data, - cast_to=cast_to, # type: ignore - response=response, - ) - - -class APIResponse(BaseAPIResponse[R]): - @overload - def parse(self, *, to: type[_T]) -> _T: ... - - @overload - def parse(self) -> R: ... - - def parse(self, *, to: type[_T] | None = None) -> R | _T: - """Returns the rich python representation of this response's data. - - For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. - - You can customise the type that the response is parsed into through - the `to` argument, e.g. - - ```py - from google.genai._interactions import BaseModel - - - class MyModel(BaseModel): - foo: str - - - obj = response.parse(to=MyModel) - print(obj.foo) - ``` - - We support parsing: - - `BaseModel` - - `dict` - - `list` - - `Union` - - `str` - - `int` - - `float` - - `httpx.Response` - """ - cache_key = to if to is not None else self._cast_to - cached = self._parsed_by_type.get(cache_key) - if cached is not None: - return cached # type: ignore[no-any-return] - - if not self._is_sse_stream: - self.read() - - parsed = self._parse(to=to) - if is_given(self._options.post_parser): - parsed = self._options.post_parser(parsed) - - self._parsed_by_type[cache_key] = parsed - return parsed - - def read(self) -> bytes: - """Read and return the binary response content.""" - try: - return self.http_response.read() - except httpx.StreamConsumed as exc: - # The default error raised by httpx isn't very - # helpful in our case so we re-raise it with - # a different error message. - raise StreamAlreadyConsumed() from exc - - def text(self) -> str: - """Read and decode the response content into a string.""" - self.read() - return self.http_response.text - - def json(self) -> object: - """Read and decode the JSON response content.""" - self.read() - return self.http_response.json() - - def close(self) -> None: - """Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - self.http_response.close() - - def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]: - """ - A byte-iterator over the decoded response content. - - This automatically handles gzip, deflate and brotli encoded responses. - """ - for chunk in self.http_response.iter_bytes(chunk_size): - yield chunk - - def iter_text(self, chunk_size: int | None = None) -> Iterator[str]: - """A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - for chunk in self.http_response.iter_text(chunk_size): - yield chunk - - def iter_lines(self) -> Iterator[str]: - """Like `iter_text()` but will only yield chunks for each line""" - for chunk in self.http_response.iter_lines(): - yield chunk - - -class AsyncAPIResponse(BaseAPIResponse[R]): - @overload - async def parse(self, *, to: type[_T]) -> _T: ... - - @overload - async def parse(self) -> R: ... - - async def parse(self, *, to: type[_T] | None = None) -> R | _T: - """Returns the rich python representation of this response's data. - - For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. - - You can customise the type that the response is parsed into through - the `to` argument, e.g. - - ```py - from google.genai._interactions import BaseModel - - - class MyModel(BaseModel): - foo: str - - - obj = response.parse(to=MyModel) - print(obj.foo) - ``` - - We support parsing: - - `BaseModel` - - `dict` - - `list` - - `Union` - - `str` - - `httpx.Response` - """ - cache_key = to if to is not None else self._cast_to - cached = self._parsed_by_type.get(cache_key) - if cached is not None: - return cached # type: ignore[no-any-return] - - if not self._is_sse_stream: - await self.read() - - parsed = self._parse(to=to) - if is_given(self._options.post_parser): - parsed = self._options.post_parser(parsed) - - self._parsed_by_type[cache_key] = parsed - return parsed - - async def read(self) -> bytes: - """Read and return the binary response content.""" - try: - return await self.http_response.aread() - except httpx.StreamConsumed as exc: - # the default error raised by httpx isn't very - # helpful in our case so we re-raise it with - # a different error message - raise StreamAlreadyConsumed() from exc - - async def text(self) -> str: - """Read and decode the response content into a string.""" - await self.read() - return self.http_response.text - - async def json(self) -> object: - """Read and decode the JSON response content.""" - await self.read() - return self.http_response.json() - - async def close(self) -> None: - """Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - await self.http_response.aclose() - - async def iter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: - """ - A byte-iterator over the decoded response content. - - This automatically handles gzip, deflate and brotli encoded responses. - """ - async for chunk in self.http_response.aiter_bytes(chunk_size): - yield chunk - - async def iter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]: - """A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - async for chunk in self.http_response.aiter_text(chunk_size): - yield chunk - - async def iter_lines(self) -> AsyncIterator[str]: - """Like `iter_text()` but will only yield chunks for each line""" - async for chunk in self.http_response.aiter_lines(): - yield chunk - - -class BinaryAPIResponse(APIResponse[bytes]): - """Subclass of APIResponse providing helpers for dealing with binary data. - - Note: If you want to stream the response data instead of eagerly reading it - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - - def write_to_file( - self, - file: str | os.PathLike[str], - ) -> None: - """Write the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - - Note: if you want to stream the data to the file instead of writing - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - with open(file, mode="wb") as f: - for data in self.iter_bytes(): - f.write(data) - - -class AsyncBinaryAPIResponse(AsyncAPIResponse[bytes]): - """Subclass of APIResponse providing helpers for dealing with binary data. - - Note: If you want to stream the response data instead of eagerly reading it - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - - async def write_to_file( - self, - file: str | os.PathLike[str], - ) -> None: - """Write the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - - Note: if you want to stream the data to the file instead of writing - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - path = anyio.Path(file) - async with await path.open(mode="wb") as f: - async for data in self.iter_bytes(): - await f.write(data) - - -class StreamedBinaryAPIResponse(APIResponse[bytes]): - def stream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - """Streams the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - """ - with open(file, mode="wb") as f: - for data in self.iter_bytes(chunk_size): - f.write(data) - - -class AsyncStreamedBinaryAPIResponse(AsyncAPIResponse[bytes]): - async def stream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - """Streams the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - """ - path = anyio.Path(file) - async with await path.open(mode="wb") as f: - async for data in self.iter_bytes(chunk_size): - await f.write(data) - - -class MissingStreamClassError(TypeError): - def __init__(self) -> None: - super().__init__( - "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `google.genai._interactions._streaming` for reference", - ) - - -class StreamAlreadyConsumed(GeminiNextGenAPIClientError): - """ - Attempted to read or stream content, but the content has already - been streamed. - - This can happen if you use a method like `.iter_lines()` and then attempt - to read th entire response body afterwards, e.g. - - ```py - response = await client.post(...) - async for line in response.iter_lines(): - ... # do something with `line` - - content = await response.read() - # ^ error - ``` - - If you want this behaviour you'll need to either manually accumulate the response - content or call `await response.read()` before iterating over the stream. - """ - - def __init__(self) -> None: - message = ( - "Attempted to read or stream some content, but the content has " - "already been streamed. " - "This could be due to attempting to stream the response " - "content more than once." - "\n\n" - "You can fix this by manually accumulating the response content while streaming " - "or by calling `.read()` before starting to stream." - ) - super().__init__(message) - - -class ResponseContextManager(Generic[_APIResponseT]): - """Context manager for ensuring that a request is not made - until it is entered and that the response will always be closed - when the context manager exits - """ - - def __init__(self, request_func: Callable[[], _APIResponseT]) -> None: - self._request_func = request_func - self.__response: _APIResponseT | None = None - - def __enter__(self) -> _APIResponseT: - self.__response = self._request_func() - return self.__response - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__response is not None: - self.__response.close() - - -class AsyncResponseContextManager(Generic[_AsyncAPIResponseT]): - """Context manager for ensuring that a request is not made - until it is entered and that the response will always be closed - when the context manager exits - """ - - def __init__(self, api_request: Awaitable[_AsyncAPIResponseT]) -> None: - self._api_request = api_request - self.__response: _AsyncAPIResponseT | None = None - - async def __aenter__(self) -> _AsyncAPIResponseT: - self.__response = await self._api_request - return self.__response - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__response is not None: - await self.__response.close() - - -def to_streamed_response_wrapper(func: Callable[P, R]) -> Callable[P, ResponseContextManager[APIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support streaming and returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[APIResponse[R]]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - - kwargs["extra_headers"] = extra_headers - - make_request = functools.partial(func, *args, **kwargs) - - return ResponseContextManager(cast(Callable[[], APIResponse[R]], make_request)) - - return wrapped - - -def async_to_streamed_response_wrapper( - func: Callable[P, Awaitable[R]], -) -> Callable[P, AsyncResponseContextManager[AsyncAPIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support streaming and returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[AsyncAPIResponse[R]]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - - kwargs["extra_headers"] = extra_headers - - make_request = func(*args, **kwargs) - - return AsyncResponseContextManager(cast(Awaitable[AsyncAPIResponse[R]], make_request)) - - return wrapped - - -def to_custom_streamed_response_wrapper( - func: Callable[P, object], - response_cls: type[_APIResponseT], -) -> Callable[P, ResponseContextManager[_APIResponseT]]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support streaming and returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[_APIResponseT]: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - make_request = functools.partial(func, *args, **kwargs) - - return ResponseContextManager(cast(Callable[[], _APIResponseT], make_request)) - - return wrapped - - -def async_to_custom_streamed_response_wrapper( - func: Callable[P, Awaitable[object]], - response_cls: type[_AsyncAPIResponseT], -) -> Callable[P, AsyncResponseContextManager[_AsyncAPIResponseT]]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support streaming and returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[_AsyncAPIResponseT]: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - make_request = func(*args, **kwargs) - - return AsyncResponseContextManager(cast(Awaitable[_AsyncAPIResponseT], make_request)) - - return wrapped - - -def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, APIResponse[R]]: - """Higher order function that takes one of our bound API methods and wraps it - to support returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - - kwargs["extra_headers"] = extra_headers - - return cast(APIResponse[R], func(*args, **kwargs)) - - return wrapped - - -def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[AsyncAPIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - async def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncAPIResponse[R]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - - kwargs["extra_headers"] = extra_headers - - return cast(AsyncAPIResponse[R], await func(*args, **kwargs)) - - return wrapped - - -def to_custom_raw_response_wrapper( - func: Callable[P, object], - response_cls: type[_APIResponseT], -) -> Callable[P, _APIResponseT]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> _APIResponseT: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - return cast(_APIResponseT, func(*args, **kwargs)) - - return wrapped - - -def async_to_custom_raw_response_wrapper( - func: Callable[P, Awaitable[object]], - response_cls: type[_AsyncAPIResponseT], -) -> Callable[P, Awaitable[_AsyncAPIResponseT]]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> Awaitable[_AsyncAPIResponseT]: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - return cast(Awaitable[_AsyncAPIResponseT], func(*args, **kwargs)) - - return wrapped - - -def extract_response_type(typ: type[BaseAPIResponse[Any]]) -> type: - """Given a type like `APIResponse[T]`, returns the generic type variable `T`. - - This also handles the case where a concrete subclass is given, e.g. - ```py - class MyResponse(APIResponse[bytes]): - ... - - extract_response_type(MyResponse) -> bytes - ``` - """ - return extract_type_var_from_base( - typ, - generic_bases=cast("tuple[type, ...]", (BaseAPIResponse, APIResponse, AsyncAPIResponse)), - index=0, - ) diff --git a/google/genai/_interactions/_streaming.py b/google/genai/_interactions/_streaming.py deleted file mode 100644 index 4888afe85..000000000 --- a/google/genai/_interactions/_streaming.py +++ /dev/null @@ -1,359 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Note: initially copied from https://github.com/florimondmanca/httpx-sse/blob/master/src/httpx_sse/_decoders.py -from __future__ import annotations - -import json -import inspect -from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast -from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable - -import httpx - -from ._utils import extract_type_var_from_base - -if TYPE_CHECKING: - from ._client import GeminiNextGenAPIClient, AsyncGeminiNextGenAPIClient - from ._models import FinalRequestOptions - - -_T = TypeVar("_T") - - -class Stream(Generic[_T]): - """Provides the core interface to iterate over a synchronous stream response.""" - - response: httpx.Response - _options: Optional[FinalRequestOptions] = None - _decoder: SSEBytesDecoder - - def __init__( - self, - *, - cast_to: type[_T], - response: httpx.Response, - client: GeminiNextGenAPIClient, - options: Optional[FinalRequestOptions] = None, - ) -> None: - self.response = response - self._cast_to = cast_to - self._client = client - self._options = options - self._decoder = client._make_sse_decoder() - self._iterator = self.__stream__() - - def __next__(self) -> _T: - return self._iterator.__next__() - - def __iter__(self) -> Iterator[_T]: - for item in self._iterator: - yield item - - def _iter_events(self) -> Iterator[ServerSentEvent]: - yield from self._decoder.iter_bytes(self.response.iter_bytes()) - - def __stream__(self) -> Iterator[_T]: - cast_to = cast(Any, self._cast_to) - response = self.response - process_data = self._client._process_response_data - iterator = self._iter_events() - - try: - for sse in iterator: - if sse.data.startswith("[DONE]"): - break - - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - finally: - # Ensure the response is closed even if the consumer doesn't read all data - response.close() - - def __enter__(self) -> Self: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - self.response.close() - - -class AsyncStream(Generic[_T]): - """Provides the core interface to iterate over an asynchronous stream response.""" - - response: httpx.Response - _options: Optional[FinalRequestOptions] = None - _decoder: SSEDecoder | SSEBytesDecoder - - def __init__( - self, - *, - cast_to: type[_T], - response: httpx.Response, - client: AsyncGeminiNextGenAPIClient, - options: Optional[FinalRequestOptions] = None, - ) -> None: - self.response = response - self._cast_to = cast_to - self._client = client - self._options = options - self._decoder = client._make_sse_decoder() - self._iterator = self.__stream__() - - async def __anext__(self) -> _T: - return await self._iterator.__anext__() - - async def __aiter__(self) -> AsyncIterator[_T]: - async for item in self._iterator: - yield item - - async def _iter_events(self) -> AsyncIterator[ServerSentEvent]: - async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()): - yield sse - - async def __stream__(self) -> AsyncIterator[_T]: - cast_to = cast(Any, self._cast_to) - response = self.response - process_data = self._client._process_response_data - iterator = self._iter_events() - - try: - async for sse in iterator: - if sse.data.startswith("[DONE]"): - break - - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - finally: - # Ensure the response is closed even if the consumer doesn't read all data - await response.aclose() - - async def __aenter__(self) -> Self: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.close() - - async def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - await self.response.aclose() - - -class ServerSentEvent: - def __init__( - self, - *, - event: str | None = None, - data: str | None = None, - id: str | None = None, - retry: int | None = None, - ) -> None: - if data is None: - data = "" - - self._id = id - self._data = data - self._event = event or None - self._retry = retry - - @property - def event(self) -> str | None: - return self._event - - @property - def id(self) -> str | None: - return self._id - - @property - def retry(self) -> int | None: - return self._retry - - @property - def data(self) -> str: - return self._data - - def json(self) -> Any: - return json.loads(self.data) - - @override - def __repr__(self) -> str: - return f"ServerSentEvent(event={self.event}, data={self.data}, id={self.id}, retry={self.retry})" - - -class SSEDecoder: - _data: list[str] - _event: str | None - _retry: int | None - _last_event_id: str | None - - def __init__(self) -> None: - self._event = None - self._data = [] - self._last_event_id = None - self._retry = None - - def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: - """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" - for chunk in self._iter_chunks(iterator): - # Split before decoding so splitlines() only uses \r and \n - for raw_line in chunk.splitlines(): - line = raw_line.decode("utf-8") - sse = self.decode(line) - if sse: - yield sse - - def _iter_chunks(self, iterator: Iterator[bytes]) -> Iterator[bytes]: - """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" - data = b"" - for chunk in iterator: - for line in chunk.splitlines(keepends=True): - data += line - if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): - yield data - data = b"" - if data: - yield data - - async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: - """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" - async for chunk in self._aiter_chunks(iterator): - # Split before decoding so splitlines() only uses \r and \n - for raw_line in chunk.splitlines(): - line = raw_line.decode("utf-8") - sse = self.decode(line) - if sse: - yield sse - - async def _aiter_chunks(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[bytes]: - """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" - data = b"" - async for chunk in iterator: - for line in chunk.splitlines(keepends=True): - data += line - if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): - yield data - data = b"" - if data: - yield data - - def decode(self, line: str) -> ServerSentEvent | None: - # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 - - if not line: - if not self._event and not self._data and not self._last_event_id and self._retry is None: - return None - - sse = ServerSentEvent( - event=self._event, - data="\n".join(self._data), - id=self._last_event_id, - retry=self._retry, - ) - - # NOTE: as per the SSE spec, do not reset last_event_id. - self._event = None - self._data = [] - self._retry = None - - return sse - - if line.startswith(":"): - return None - - fieldname, _, value = line.partition(":") - - if value.startswith(" "): - value = value[1:] - - if fieldname == "event": - self._event = value - elif fieldname == "data": - self._data.append(value) - elif fieldname == "id": - if "\0" in value: - pass - else: - self._last_event_id = value - elif fieldname == "retry": - try: - self._retry = int(value) - except (TypeError, ValueError): - pass - else: - pass # Field is ignored. - - return None - - -@runtime_checkable -class SSEBytesDecoder(Protocol): - def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: - """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" - ... - - def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: - """Given an async iterator that yields raw binary data, iterate over it & yield every event encountered""" - ... - - -def is_stream_class_type(typ: type) -> TypeGuard[type[Stream[object]] | type[AsyncStream[object]]]: - """TypeGuard for determining whether or not the given type is a subclass of `Stream` / `AsyncStream`""" - origin = get_origin(typ) or typ - return inspect.isclass(origin) and issubclass(origin, (Stream, AsyncStream)) - - -def extract_stream_chunk_type( - stream_cls: type, - *, - failure_message: str | None = None, -) -> type: - """Given a type like `Stream[T]`, returns the generic type variable `T`. - - This also handles the case where a concrete subclass is given, e.g. - ```py - class MyStream(Stream[bytes]): - ... - - extract_stream_chunk_type(MyStream) -> bytes - ``` - """ - from ._base_client import Stream, AsyncStream - - return extract_type_var_from_base( - stream_cls, - index=0, - generic_bases=cast("tuple[type, ...]", (Stream, AsyncStream)), - failure_message=failure_message, - ) diff --git a/google/genai/_interactions/_types.py b/google/genai/_interactions/_types.py deleted file mode 100644 index 309e981f9..000000000 --- a/google/genai/_interactions/_types.py +++ /dev/null @@ -1,288 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -from os import PathLike -from typing import ( - IO, - TYPE_CHECKING, - Any, - Dict, - List, - Type, - Tuple, - Union, - Mapping, - TypeVar, - Callable, - Iterable, - Iterator, - Optional, - Sequence, - AsyncIterable, -) -from typing_extensions import ( - Set, - Literal, - Protocol, - TypeAlias, - TypedDict, - SupportsIndex, - overload, - override, - runtime_checkable, -) - -import httpx -import pydantic -from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport - -if TYPE_CHECKING: - from ._models import BaseModel - from ._response import APIResponse, AsyncAPIResponse - -Transport = BaseTransport -AsyncTransport = AsyncBaseTransport -Query = Mapping[str, object] -Body = object -AnyMapping = Mapping[str, object] -ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) -_T = TypeVar("_T") - -ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] -NestedFormat = Literal["dots", "brackets"] - - -# Approximates httpx internal ProxiesTypes and RequestFiles types -# while adding support for `PathLike` instances -ProxiesDict = Dict["str | URL", Union[None, str, URL, Proxy]] -ProxiesTypes = Union[str, Proxy, ProxiesDict] -if TYPE_CHECKING: - Base64FileInput = Union[IO[bytes], PathLike[str]] - FileContent = Union[IO[bytes], bytes, PathLike[str]] -else: - Base64FileInput = Union[IO[bytes], PathLike] - FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. - - -# Used for sending raw binary data / streaming data in request bodies -# e.g. for file uploads without multipart encoding -BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]] -AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]] - -FileTypes = Union[ - # file (or bytes) - FileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], FileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], FileContent, Optional[str]], - # (filename, file (or bytes), content_type, headers) - Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], -] -RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]] - -# duplicate of the above but without our custom file support -HttpxFileContent = Union[IO[bytes], bytes] -HttpxFileTypes = Union[ - # file (or bytes) - HttpxFileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], HttpxFileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], HttpxFileContent, Optional[str]], - # (filename, file (or bytes), content_type, headers) - Tuple[Optional[str], HttpxFileContent, Optional[str], Mapping[str, str]], -] -HttpxRequestFiles = Union[Mapping[str, HttpxFileTypes], Sequence[Tuple[str, HttpxFileTypes]]] - -# Workaround to support (cast_to: Type[ResponseT]) -> ResponseT -# where ResponseT includes `None`. In order to support directly -# passing `None`, overloads would have to be defined for every -# method that uses `ResponseT` which would lead to an unacceptable -# amount of code duplication and make it unreadable. See _base_client.py -# for example usage. -# -# This unfortunately means that you will either have -# to import this type and pass it explicitly: -# -# from google.genai._interactions import NoneType -# client.get('/foo', cast_to=NoneType) -# -# or build it yourself: -# -# client.get('/foo', cast_to=type(None)) -if TYPE_CHECKING: - NoneType: Type[None] -else: - NoneType = type(None) - - -class RequestOptions(TypedDict, total=False): - headers: Headers - max_retries: int - timeout: float | Timeout | None - params: Query - extra_json: AnyMapping - idempotency_key: str - follow_redirects: bool - - -# Sentinel class used until PEP 0661 is accepted -class NotGiven: - """ - For parameters with a meaningful None value, we need to distinguish between - the user explicitly passing None, and the user not passing the parameter at - all. - - User code shouldn't need to use not_given directly. - - For example: - - ```py - def create(timeout: Timeout | None | NotGiven = not_given): ... - - - create(timeout=1) # 1s timeout - create(timeout=None) # No timeout - create() # Default timeout behavior - ``` - """ - - def __bool__(self) -> Literal[False]: - return False - - @override - def __repr__(self) -> str: - return "NOT_GIVEN" - - -not_given = NotGiven() -# for backwards compatibility: -NOT_GIVEN = NotGiven() - - -class Omit: - """ - To explicitly omit something from being sent in a request, use `omit`. - - ```py - # as the default `Content-Type` header is `application/json` that will be sent - client.post("/upload/files", files={"file": b"my raw file content"}) - - # you can't explicitly override the header as it has to be dynamically generated - # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' - client.post(..., headers={"Content-Type": "multipart/form-data"}) - - # instead you can remove the default `application/json` header by passing omit - client.post(..., headers={"Content-Type": omit}) - ``` - """ - - def __bool__(self) -> Literal[False]: - return False - - -omit = Omit() - - -@runtime_checkable -class ModelBuilderProtocol(Protocol): - @classmethod - def build( - cls: type[_T], - *, - response: Response, - data: object, - ) -> _T: ... - - -Headers = Mapping[str, Union[str, Omit]] - - -class HeadersLikeProtocol(Protocol): - def get(self, __key: str) -> str | None: ... - - -HeadersLike = Union[Headers, HeadersLikeProtocol] - -ResponseT = TypeVar( - "ResponseT", - bound=Union[ - object, - str, - None, - "BaseModel", - List[Any], - Dict[str, Any], - Response, - ModelBuilderProtocol, - "APIResponse[Any]", - "AsyncAPIResponse[Any]", - ], -) - -StrBytesIntFloat = Union[str, bytes, int, float] - -# Note: copied from Pydantic -# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79 -IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]] - -PostParser = Callable[[Any], Any] - - -@runtime_checkable -class InheritsGeneric(Protocol): - """Represents a type that has inherited from `Generic` - - The `__orig_bases__` property can be used to determine the resolved - type variable for a given base class. - """ - - __orig_bases__: tuple[_GenericAlias] - - -class _GenericAlias(Protocol): - __origin__: type[object] - - -class HttpxSendArgs(TypedDict, total=False): - auth: httpx.Auth - follow_redirects: bool - - -_T_co = TypeVar("_T_co", covariant=True) - - -if TYPE_CHECKING: - # This works because str.__contains__ does not accept object (either in typeshed or at runtime) - # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 - # - # Note: index() and count() methods are intentionally omitted to allow pyright to properly - # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. - class SequenceNotStr(Protocol[_T_co]): - @overload - def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... - @overload - def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... - def __contains__(self, value: object, /) -> bool: ... - def __len__(self) -> int: ... - def __iter__(self) -> Iterator[_T_co]: ... - def __reversed__(self) -> Iterator[_T_co]: ... -else: - # just point this to a normal `Sequence` at runtime to avoid having to special case - # deserializing our custom sequence type - SequenceNotStr = Sequence diff --git a/google/genai/_interactions/_utils/__init__.py b/google/genai/_interactions/_utils/__init__.py deleted file mode 100644 index 86ae48d3f..000000000 --- a/google/genai/_interactions/_utils/__init__.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from ._path import path_template as path_template -from ._sync import asyncify as asyncify -from ._proxy import LazyProxy as LazyProxy -from ._utils import ( - flatten as flatten, - is_dict as is_dict, - is_list as is_list, - is_given as is_given, - is_tuple as is_tuple, - json_safe as json_safe, - lru_cache as lru_cache, - is_mapping as is_mapping, - is_tuple_t as is_tuple_t, - is_iterable as is_iterable, - is_sequence as is_sequence, - coerce_float as coerce_float, - is_mapping_t as is_mapping_t, - removeprefix as removeprefix, - removesuffix as removesuffix, - extract_files as extract_files, - is_sequence_t as is_sequence_t, - required_args as required_args, - coerce_boolean as coerce_boolean, - coerce_integer as coerce_integer, - file_from_path as file_from_path, - strip_not_given as strip_not_given, - get_async_library as get_async_library, - maybe_coerce_float as maybe_coerce_float, - get_required_header as get_required_header, - maybe_coerce_boolean as maybe_coerce_boolean, - maybe_coerce_integer as maybe_coerce_integer, -) -from ._compat import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - is_typeddict as is_typeddict, - is_literal_type as is_literal_type, -) -from ._typing import ( - is_list_type as is_list_type, - is_union_type as is_union_type, - extract_type_arg as extract_type_arg, - is_iterable_type as is_iterable_type, - is_required_type as is_required_type, - is_sequence_type as is_sequence_type, - is_annotated_type as is_annotated_type, - is_type_alias_type as is_type_alias_type, - strip_annotated_type as strip_annotated_type, - extract_type_var_from_base as extract_type_var_from_base, -) -from ._streams import consume_sync_iterator as consume_sync_iterator, consume_async_iterator as consume_async_iterator -from ._transform import ( - PropertyInfo as PropertyInfo, - transform as transform, - async_transform as async_transform, - maybe_transform as maybe_transform, - async_maybe_transform as async_maybe_transform, -) -from ._reflection import ( - function_has_argument as function_has_argument, - assert_signatures_in_sync as assert_signatures_in_sync, -) -from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime diff --git a/google/genai/_interactions/_utils/_compat.py b/google/genai/_interactions/_utils/_compat.py deleted file mode 100644 index fe2386df6..000000000 --- a/google/genai/_interactions/_utils/_compat.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# mypy: ignore-errors -from __future__ import annotations - -import sys -import typing_extensions -from typing import Any, Type, Union, Literal, Optional -from datetime import date, datetime -from typing_extensions import get_args as _get_args, get_origin as _get_origin - -from .._types import StrBytesIntFloat -from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime - -_LITERAL_TYPES = {Literal, typing_extensions.Literal} - - -def get_args(tp: type[Any]) -> tuple[Any, ...]: - return _get_args(tp) - - -def get_origin(tp: type[Any]) -> type[Any] | None: - return _get_origin(tp) - - -def is_union(tp: Optional[Type[Any]]) -> bool: - if sys.version_info < (3, 10): - return tp is Union # type: ignore[comparison-overlap] - else: - import types - - return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] - - -def is_typeddict(tp: Type[Any]) -> bool: - return typing_extensions.is_typeddict(tp) - - -def is_literal_type(tp: Type[Any]) -> bool: - return get_origin(tp) in _LITERAL_TYPES - - -def parse_date(value: Union[date, StrBytesIntFloat]) -> date: - return _parse_date(value) - - -def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: - return _parse_datetime(value) diff --git a/google/genai/_interactions/_utils/_datetime_parse.py b/google/genai/_interactions/_utils/_datetime_parse.py deleted file mode 100644 index 3630bda2d..000000000 --- a/google/genai/_interactions/_utils/_datetime_parse.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -""" -This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py -without the Pydantic v1 specific errors. -""" - -from __future__ import annotations - -import re -from typing import Dict, Union, Optional -from datetime import date, datetime, timezone, timedelta - -from .._types import StrBytesIntFloat - -date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" -time_expr = ( - r"(?P\d{1,2}):(?P\d{1,2})" - r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" - r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" -) - -date_re = re.compile(f"{date_expr}$") -datetime_re = re.compile(f"{date_expr}[T ]{time_expr}") - - -EPOCH = datetime(1970, 1, 1) -# if greater than this, the number is in ms, if less than or equal it's in seconds -# (in seconds this is 11th October 2603, in ms it's 20th August 1970) -MS_WATERSHED = int(2e10) -# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 -MAX_NUMBER = int(3e20) - - -def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: - if isinstance(value, (int, float)): - return value - try: - return float(value) - except ValueError: - return None - except TypeError: - raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None - - -def _from_unix_seconds(seconds: Union[int, float]) -> datetime: - if seconds > MAX_NUMBER: - return datetime.max - elif seconds < -MAX_NUMBER: - return datetime.min - - while abs(seconds) > MS_WATERSHED: - seconds /= 1000 - dt = EPOCH + timedelta(seconds=seconds) - return dt.replace(tzinfo=timezone.utc) - - -def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]: - if value == "Z": - return timezone.utc - elif value is not None: - offset_mins = int(value[-2:]) if len(value) > 3 else 0 - offset = 60 * int(value[1:3]) + offset_mins - if value[0] == "-": - offset = -offset - return timezone(timedelta(minutes=offset)) - else: - return None - - -def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: - """ - Parse a datetime/int/float/string and return a datetime.datetime. - - This function supports time zone offsets. When the input contains one, - the output uses a timezone with a fixed offset from UTC. - - Raise ValueError if the input is well formatted but not a valid datetime. - Raise ValueError if the input isn't well formatted. - """ - if isinstance(value, datetime): - return value - - number = _get_numeric(value, "datetime") - if number is not None: - return _from_unix_seconds(number) - - if isinstance(value, bytes): - value = value.decode() - - assert not isinstance(value, (float, int)) - - match = datetime_re.match(value) - if match is None: - raise ValueError("invalid datetime format") - - kw = match.groupdict() - if kw["microsecond"]: - kw["microsecond"] = kw["microsecond"].ljust(6, "0") - - tzinfo = _parse_timezone(kw.pop("tzinfo")) - kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} - kw_["tzinfo"] = tzinfo - - return datetime(**kw_) # type: ignore - - -def parse_date(value: Union[date, StrBytesIntFloat]) -> date: - """ - Parse a date/int/float/string and return a datetime.date. - - Raise ValueError if the input is well formatted but not a valid date. - Raise ValueError if the input isn't well formatted. - """ - if isinstance(value, date): - if isinstance(value, datetime): - return value.date() - else: - return value - - number = _get_numeric(value, "date") - if number is not None: - return _from_unix_seconds(number).date() - - if isinstance(value, bytes): - value = value.decode() - - assert not isinstance(value, (float, int)) - match = date_re.match(value) - if match is None: - raise ValueError("invalid date format") - - kw = {k: int(v) for k, v in match.groupdict().items()} - - try: - return date(**kw) - except ValueError: - raise ValueError("invalid date format") from None diff --git a/google/genai/_interactions/_utils/_json.py b/google/genai/_interactions/_utils/_json.py deleted file mode 100644 index d54cafcc3..000000000 --- a/google/genai/_interactions/_utils/_json.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import json -from typing import Any -from datetime import datetime -from typing_extensions import override - -import pydantic - -from .._compat import model_dump - - -def openapi_dumps(obj: Any) -> bytes: - """ - Serialize an object to UTF-8 encoded JSON bytes. - - Extends the standard json.dumps with support for additional types - commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc. - """ - return json.dumps( - obj, - cls=_CustomEncoder, - # Uses the same defaults as httpx's JSON serialization - ensure_ascii=False, - separators=(",", ":"), - allow_nan=False, - ).encode() - - -class _CustomEncoder(json.JSONEncoder): - @override - def default(self, o: Any) -> Any: - if isinstance(o, datetime): - return o.isoformat() - if isinstance(o, pydantic.BaseModel): - return model_dump(o, exclude_unset=True, mode="json", by_alias=True) - return super().default(o) diff --git a/google/genai/_interactions/_utils/_logs.py b/google/genai/_interactions/_utils/_logs.py deleted file mode 100644 index a16f72338..000000000 --- a/google/genai/_interactions/_utils/_logs.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import os -import logging - -logger: logging.Logger = logging.getLogger("google.genai._interactions") -httpx_logger: logging.Logger = logging.getLogger("httpx") - - -def _basic_config() -> None: - # e.g. [2023-10-05 14:12:26 - google.genai._interactions._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK" - logging.basicConfig( - format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - ) - - -def setup_logging() -> None: - env = os.environ.get("GEMINI_NEXT_GEN_API_LOG") - if env == "debug": - _basic_config() - logger.setLevel(logging.DEBUG) - httpx_logger.setLevel(logging.DEBUG) - elif env == "info": - _basic_config() - logger.setLevel(logging.INFO) - httpx_logger.setLevel(logging.INFO) diff --git a/google/genai/_interactions/_utils/_path.py b/google/genai/_interactions/_utils/_path.py deleted file mode 100644 index 5a8171b10..000000000 --- a/google/genai/_interactions/_utils/_path.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -import re -from typing import ( - Any, - Mapping, - Callable, -) -from urllib.parse import quote - -# Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E). -_DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$") - -_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}") - - -def _quote_path_segment_part(value: str) -> str: - """Percent-encode `value` for use in a URI path segment. - - Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe. - https://datatracker.ietf.org/doc/html/rfc3986#section-3.3 - """ - # quote() already treats unreserved characters (letters, digits, and -._~) - # as safe, so we only need to add sub-delims, ':', and '@'. - # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted. - return quote(value, safe="!$&'()*+,;=:@") - - -def _quote_query_part(value: str) -> str: - """Percent-encode `value` for use in a URI query string. - - Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe. - https://datatracker.ietf.org/doc/html/rfc3986#section-3.4 - """ - return quote(value, safe="!$'()*+,;:@/?") - - -def _quote_fragment_part(value: str) -> str: - """Percent-encode `value` for use in a URI fragment. - - Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe. - https://datatracker.ietf.org/doc/html/rfc3986#section-3.5 - """ - return quote(value, safe="!$&'()*+,;=:@/?") - - -def _interpolate( - template: str, - values: Mapping[str, Any], - quoter: Callable[[str], str], -) -> str: - """Replace {name} placeholders in `template`, quoting each value with `quoter`. - - Placeholder names are looked up in `values`. - - Raises: - KeyError: If a placeholder is not found in `values`. - """ - # re.split with a capturing group returns alternating - # [text, name, text, name, ..., text] elements. - parts = _PLACEHOLDER_RE.split(template) - - for i in range(1, len(parts), 2): - name = parts[i] - if name not in values: - raise KeyError(f"a value for placeholder {{{name}}} was not provided") - val = values[name] - if val is None: - parts[i] = "null" - elif isinstance(val, bool): - parts[i] = "true" if val else "false" - else: - parts[i] = quoter(str(values[name])) - - return "".join(parts) - - -def path_template(template: str, /, **kwargs: Any) -> str: - """Interpolate {name} placeholders in `template` from keyword arguments. - - Args: - template: The template string containing {name} placeholders. - **kwargs: Keyword arguments to interpolate into the template. - - Returns: - The template with placeholders interpolated and percent-encoded. - - Safe characters for percent-encoding are dependent on the URI component. - Placeholders in path and fragment portions are percent-encoded where the `segment` - and `fragment` sets from RFC 3986 respectively are considered safe. - Placeholders in the query portion are percent-encoded where the `query` set from - RFC 3986 §3.3 is considered safe except for = and & characters. - - Raises: - KeyError: If a placeholder is not found in `kwargs`. - ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments). - """ - # Split the template into path, query, and fragment portions. - fragment_template: str | None = None - query_template: str | None = None - - rest = template - if "#" in rest: - rest, fragment_template = rest.split("#", 1) - if "?" in rest: - rest, query_template = rest.split("?", 1) - path_template = rest - - # Interpolate each portion with the appropriate quoting rules. - path_result = _interpolate(path_template, kwargs, _quote_path_segment_part) - - # Reject dot-segments (. and ..) in the final assembled path. The check - # runs after interpolation so that adjacent placeholders or a mix of static - # text and placeholders that together form a dot-segment are caught. - # Also reject percent-encoded dot-segments to protect against incorrectly - # implemented normalization in servers/proxies. - for segment in path_result.split("/"): - if _DOT_SEGMENT_RE.match(segment): - raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed") - - result = path_result - if query_template is not None: - result += "?" + _interpolate(query_template, kwargs, _quote_query_part) - if fragment_template is not None: - result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part) - - return result diff --git a/google/genai/_interactions/_utils/_proxy.py b/google/genai/_interactions/_utils/_proxy.py deleted file mode 100644 index b667fa206..000000000 --- a/google/genai/_interactions/_utils/_proxy.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import Generic, TypeVar, Iterable, cast -from typing_extensions import override - -T = TypeVar("T") - - -class LazyProxy(Generic[T], ABC): - """Implements data methods to pretend that an instance is another instance. - - This includes forwarding attribute access and other methods. - """ - - # Note: we have to special case proxies that themselves return proxies - # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz` - - def __getattr__(self, attr: str) -> object: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return proxied # pyright: ignore - return getattr(proxied, attr) - - @override - def __repr__(self) -> str: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return proxied.__class__.__name__ - return repr(self.__get_proxied__()) - - @override - def __str__(self) -> str: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return proxied.__class__.__name__ - return str(proxied) - - @override - def __dir__(self) -> Iterable[str]: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return [] - return proxied.__dir__() - - @property # type: ignore - @override - def __class__(self) -> type: # pyright: ignore - try: - proxied = self.__get_proxied__() - except Exception: - return type(self) - if issubclass(type(proxied), LazyProxy): - return type(proxied) - return proxied.__class__ - - def __get_proxied__(self) -> T: - return self.__load__() - - def __as_proxied__(self) -> T: - """Helper method that returns the current proxy, typed as the loaded object""" - return cast(T, self) - - @abstractmethod - def __load__(self) -> T: ... diff --git a/google/genai/_interactions/_utils/_reflection.py b/google/genai/_interactions/_utils/_reflection.py deleted file mode 100644 index 4b96a0017..000000000 --- a/google/genai/_interactions/_utils/_reflection.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -import inspect -from typing import Any, Callable - - -def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool: - """Returns whether or not the given function has a specific parameter""" - sig = inspect.signature(func) - return arg_name in sig.parameters - - -def assert_signatures_in_sync( - source_func: Callable[..., Any], - check_func: Callable[..., Any], - *, - exclude_params: set[str] = set(), -) -> None: - """Ensure that the signature of the second function matches the first.""" - - check_sig = inspect.signature(check_func) - source_sig = inspect.signature(source_func) - - errors: list[str] = [] - - for name, source_param in source_sig.parameters.items(): - if name in exclude_params: - continue - - custom_param = check_sig.parameters.get(name) - if not custom_param: - errors.append(f"the `{name}` param is missing") - continue - - if custom_param.annotation != source_param.annotation: - errors.append( - f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}" - ) - continue - - if errors: - raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors)) diff --git a/google/genai/_interactions/_utils/_resources_proxy.py b/google/genai/_interactions/_utils/_resources_proxy.py deleted file mode 100644 index 324e75b8f..000000000 --- a/google/genai/_interactions/_utils/_resources_proxy.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -from typing import Any -from typing_extensions import override - -from ._proxy import LazyProxy - - -class ResourcesProxy(LazyProxy[Any]): - """A proxy for the `google.genai._interactions.resources` module. - - This is used so that we can lazily import `google.genai._interactions.resources` only when - needed *and* so that users can just import `google.genai._interactions` and reference `google.genai._interactions.resources` - """ - - @override - def __load__(self) -> Any: - import importlib - - mod = importlib.import_module("google.genai._interactions.resources") - return mod - - -resources = ResourcesProxy().__as_proxied__() diff --git a/google/genai/_interactions/_utils/_streams.py b/google/genai/_interactions/_utils/_streams.py deleted file mode 100644 index c17a2dee5..000000000 --- a/google/genai/_interactions/_utils/_streams.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from typing import Any -from typing_extensions import Iterator, AsyncIterator - - -def consume_sync_iterator(iterator: Iterator[Any]) -> None: - for _ in iterator: - ... - - -async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None: - async for _ in iterator: - ... diff --git a/google/genai/_interactions/_utils/_sync.py b/google/genai/_interactions/_utils/_sync.py deleted file mode 100644 index bc95bf30d..000000000 --- a/google/genai/_interactions/_utils/_sync.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -import asyncio -import functools -from typing import TypeVar, Callable, Awaitable -from typing_extensions import ParamSpec - -import anyio -import sniffio -import anyio.to_thread - -T_Retval = TypeVar("T_Retval") -T_ParamSpec = ParamSpec("T_ParamSpec") - - -async def to_thread( - func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs -) -> T_Retval: - if sniffio.current_async_library() == "asyncio": - return await asyncio.to_thread(func, *args, **kwargs) - - return await anyio.to_thread.run_sync( - functools.partial(func, *args, **kwargs), - ) - - -# inspired by `asyncer`, https://github.com/tiangolo/asyncer -def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: - """ - Take a blocking function and create an async one that receives the same - positional and keyword arguments. - - Usage: - - ```python - def blocking_func(arg1, arg2, kwarg1=None): - # blocking code - return result - - - result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) - ``` - - ## Arguments - - `function`: a blocking regular callable (e.g. a function) - - ## Return - - An async function that takes the same positional and keyword arguments as the - original one, that when called runs the same original function in a thread worker - and returns the result. - """ - - async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: - return await to_thread(function, *args, **kwargs) - - return wrapper diff --git a/google/genai/_interactions/_utils/_transform.py b/google/genai/_interactions/_utils/_transform.py deleted file mode 100644 index bb7db1865..000000000 --- a/google/genai/_interactions/_utils/_transform.py +++ /dev/null @@ -1,472 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from __future__ import annotations - -import io -import base64 -import pathlib -from typing import Any, Mapping, TypeVar, cast -from datetime import date, datetime -from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints - -import anyio -import pydantic - -from ._utils import ( - is_list, - is_given, - lru_cache, - is_mapping, - is_iterable, - is_sequence, -) -from .._files import is_base64_file_input -from ._compat import get_origin, is_typeddict -from ._typing import ( - is_list_type, - is_union_type, - extract_type_arg, - is_iterable_type, - is_required_type, - is_sequence_type, - is_annotated_type, - strip_annotated_type, -) - -_T = TypeVar("_T") - - -# TODO: support for drilling globals() and locals() -# TODO: ensure works correctly with forward references in all cases - - -PropertyFormat = Literal["iso8601", "base64", "custom"] - - -class PropertyInfo: - """Metadata class to be used in Annotated types to provide information about a given type. - - For example: - - class MyParams(TypedDict): - account_holder_name: Annotated[str, PropertyInfo(alias='accountHolderName')] - - This means that {'account_holder_name': 'Robert'} will be transformed to {'accountHolderName': 'Robert'} before being sent to the API. - """ - - alias: str | None - format: PropertyFormat | None - format_template: str | None - discriminator: str | None - - def __init__( - self, - *, - alias: str | None = None, - format: PropertyFormat | None = None, - format_template: str | None = None, - discriminator: str | None = None, - ) -> None: - self.alias = alias - self.format = format - self.format_template = format_template - self.discriminator = discriminator - - @override - def __repr__(self) -> str: - return f"{self.__class__.__name__}(alias='{self.alias}', format={self.format}, format_template='{self.format_template}', discriminator='{self.discriminator}')" - - -def maybe_transform( - data: object, - expected_type: object, -) -> Any | None: - """Wrapper over `transform()` that allows `None` to be passed. - - See `transform()` for more details. - """ - if data is None: - return None - return transform(data, expected_type) - - -# Wrapper over _transform_recursive providing fake types -def transform( - data: _T, - expected_type: object, -) -> _T: - """Transform dictionaries based off of type information from the given type, for example: - - ```py - class Params(TypedDict, total=False): - card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] - - - transformed = transform({"card_id": ""}, Params) - # {'cardID': ''} - ``` - - Any keys / data that does not have type information given will be included as is. - - It should be noted that the transformations that this function does are not represented in the type system. - """ - transformed = _transform_recursive(data, annotation=cast(type, expected_type)) - return cast(_T, transformed) - - -@lru_cache(maxsize=8096) -def _get_annotated_type(type_: type) -> type | None: - """If the given type is an `Annotated` type then it is returned, if not `None` is returned. - - This also unwraps the type when applicable, e.g. `Required[Annotated[T, ...]]` - """ - if is_required_type(type_): - # Unwrap `Required[Annotated[T, ...]]` to `Annotated[T, ...]` - type_ = get_args(type_)[0] - - if is_annotated_type(type_): - return type_ - - return None - - -def _maybe_transform_key(key: str, type_: type) -> str: - """Transform the given `data` based on the annotations provided in `type_`. - - Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata. - """ - annotated_type = _get_annotated_type(type_) - if annotated_type is None: - # no `Annotated` definition for this type, no transformation needed - return key - - # ignore the first argument as it is the actual type - annotations = get_args(annotated_type)[1:] - for annotation in annotations: - if isinstance(annotation, PropertyInfo) and annotation.alias is not None: - return annotation.alias - - return key - - -def _no_transform_needed(annotation: type) -> bool: - return annotation == float or annotation == int - - -def _transform_recursive( - data: object, - *, - annotation: type, - inner_type: type | None = None, -) -> object: - """Transform the given data against the expected type. - - Args: - annotation: The direct type annotation given to the particular piece of data. - This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc - - inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type - is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in - the list can be transformed using the metadata from the container type. - - Defaults to the same value as the `annotation` argument. - """ - from .._compat import model_dump - - if inner_type is None: - inner_type = annotation - - stripped_type = strip_annotated_type(inner_type) - origin = get_origin(stripped_type) or stripped_type - if is_typeddict(stripped_type) and is_mapping(data): - return _transform_typeddict(data, stripped_type) - - if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] - return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} - - if ( - # List[T] - (is_list_type(stripped_type) and is_list(data)) - # Iterable[T] - or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) - # Sequence[T] - or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) - ): - # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually - # intended as an iterable, so we don't transform it. - if isinstance(data, dict): - return cast(object, data) - - inner_type = extract_type_arg(stripped_type, 0) - if _no_transform_needed(inner_type): - # for some types there is no need to transform anything, so we can get a small - # perf boost from skipping that work. - # - # but we still need to convert to a list to ensure the data is json-serializable - if is_list(data): - return data - return list(data) - - return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] - - if is_union_type(stripped_type): - # For union types we run the transformation against all subtypes to ensure that everything is transformed. - # - # TODO: there may be edge cases where the same normalized field name will transform to two different names - # in different subtypes. - for subtype in get_args(stripped_type): - data = _transform_recursive(data, annotation=annotation, inner_type=subtype) - return data - - if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True, mode="json") - - annotated_type = _get_annotated_type(annotation) - if annotated_type is None: - return data - - # ignore the first argument as it is the actual type - annotations = get_args(annotated_type)[1:] - for annotation in annotations: - if isinstance(annotation, PropertyInfo) and annotation.format is not None: - return _format_data(data, annotation.format, annotation.format_template) - - return data - - -def _format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: - if isinstance(data, (date, datetime)): - if format_ == "iso8601": - return data.isoformat() - - if format_ == "custom" and format_template is not None: - return data.strftime(format_template) - - if format_ == "base64" and is_base64_file_input(data): - binary: str | bytes | None = None - - if isinstance(data, pathlib.Path): - binary = data.read_bytes() - elif isinstance(data, io.IOBase): - binary = data.read() - - if isinstance(binary, str): # type: ignore[unreachable] - binary = binary.encode() - - if not isinstance(binary, bytes): - raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") - - return base64.b64encode(binary).decode("ascii") - - return data - - -def _transform_typeddict( - data: Mapping[str, object], - expected_type: type, -) -> Mapping[str, object]: - result: dict[str, object] = {} - annotations = get_type_hints(expected_type, include_extras=True) - for key, value in data.items(): - if not is_given(value): - # we don't need to include omitted values here as they'll - # be stripped out before the request is sent anyway - continue - - type_ = annotations.get(key) - if type_ is None: - # we do not have a type annotation for this field, leave it as is - result[key] = value - else: - result[_maybe_transform_key(key, type_)] = _transform_recursive(value, annotation=type_) - return result - - -async def async_maybe_transform( - data: object, - expected_type: object, -) -> Any | None: - """Wrapper over `async_transform()` that allows `None` to be passed. - - See `async_transform()` for more details. - """ - if data is None: - return None - return await async_transform(data, expected_type) - - -async def async_transform( - data: _T, - expected_type: object, -) -> _T: - """Transform dictionaries based off of type information from the given type, for example: - - ```py - class Params(TypedDict, total=False): - card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] - - - transformed = transform({"card_id": ""}, Params) - # {'cardID': ''} - ``` - - Any keys / data that does not have type information given will be included as is. - - It should be noted that the transformations that this function does are not represented in the type system. - """ - transformed = await _async_transform_recursive(data, annotation=cast(type, expected_type)) - return cast(_T, transformed) - - -async def _async_transform_recursive( - data: object, - *, - annotation: type, - inner_type: type | None = None, -) -> object: - """Transform the given data against the expected type. - - Args: - annotation: The direct type annotation given to the particular piece of data. - This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc - - inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type - is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in - the list can be transformed using the metadata from the container type. - - Defaults to the same value as the `annotation` argument. - """ - from .._compat import model_dump - - if inner_type is None: - inner_type = annotation - - stripped_type = strip_annotated_type(inner_type) - origin = get_origin(stripped_type) or stripped_type - if is_typeddict(stripped_type) and is_mapping(data): - return await _async_transform_typeddict(data, stripped_type) - - if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] - return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} - - if ( - # List[T] - (is_list_type(stripped_type) and is_list(data)) - # Iterable[T] - or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) - # Sequence[T] - or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) - ): - # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually - # intended as an iterable, so we don't transform it. - if isinstance(data, dict): - return cast(object, data) - - inner_type = extract_type_arg(stripped_type, 0) - if _no_transform_needed(inner_type): - # for some types there is no need to transform anything, so we can get a small - # perf boost from skipping that work. - # - # but we still need to convert to a list to ensure the data is json-serializable - if is_list(data): - return data - return list(data) - - return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] - - if is_union_type(stripped_type): - # For union types we run the transformation against all subtypes to ensure that everything is transformed. - # - # TODO: there may be edge cases where the same normalized field name will transform to two different names - # in different subtypes. - for subtype in get_args(stripped_type): - data = await _async_transform_recursive(data, annotation=annotation, inner_type=subtype) - return data - - if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True, mode="json") - - annotated_type = _get_annotated_type(annotation) - if annotated_type is None: - return data - - # ignore the first argument as it is the actual type - annotations = get_args(annotated_type)[1:] - for annotation in annotations: - if isinstance(annotation, PropertyInfo) and annotation.format is not None: - return await _async_format_data(data, annotation.format, annotation.format_template) - - return data - - -async def _async_format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: - if isinstance(data, (date, datetime)): - if format_ == "iso8601": - return data.isoformat() - - if format_ == "custom" and format_template is not None: - return data.strftime(format_template) - - if format_ == "base64" and is_base64_file_input(data): - binary: str | bytes | None = None - - if isinstance(data, pathlib.Path): - binary = await anyio.Path(data).read_bytes() - elif isinstance(data, io.IOBase): - binary = data.read() - - if isinstance(binary, str): # type: ignore[unreachable] - binary = binary.encode() - - if not isinstance(binary, bytes): - raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") - - return base64.b64encode(binary).decode("ascii") - - return data - - -async def _async_transform_typeddict( - data: Mapping[str, object], - expected_type: type, -) -> Mapping[str, object]: - result: dict[str, object] = {} - annotations = get_type_hints(expected_type, include_extras=True) - for key, value in data.items(): - if not is_given(value): - # we don't need to include omitted values here as they'll - # be stripped out before the request is sent anyway - continue - - type_ = annotations.get(key) - if type_ is None: - # we do not have a type annotation for this field, leave it as is - result[key] = value - else: - result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_) - return result - - -@lru_cache(maxsize=8096) -def get_type_hints( - obj: Any, - globalns: dict[str, Any] | None = None, - localns: Mapping[str, Any] | None = None, - include_extras: bool = False, -) -> dict[str, Any]: - return _get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) diff --git a/google/genai/_interactions/_utils/_typing.py b/google/genai/_interactions/_utils/_typing.py deleted file mode 100644 index 246a19761..000000000 --- a/google/genai/_interactions/_utils/_typing.py +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# mypy: ignore-errors -from __future__ import annotations - -import sys -import typing -import typing_extensions -from typing import Any, TypeVar, Iterable, cast -from collections import abc as _c_abc -from typing_extensions import ( - TypeIs, - Required, - Annotated, - get_args, - get_origin, -) - -from ._utils import lru_cache -from .._types import InheritsGeneric -from ._compat import is_union as _is_union - - -def is_annotated_type(typ: type) -> bool: - return get_origin(typ) == Annotated - - -def is_list_type(typ: type) -> bool: - return (get_origin(typ) or typ) == list - - -def is_sequence_type(typ: type) -> bool: - origin = get_origin(typ) or typ - return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence - - -def is_iterable_type(typ: type) -> bool: - """If the given type is `typing.Iterable[T]`""" - origin = get_origin(typ) or typ - return origin == Iterable or origin == _c_abc.Iterable - - -def is_union_type(typ: type) -> bool: - return _is_union(get_origin(typ)) - - -def is_required_type(typ: type) -> bool: - return get_origin(typ) == Required - - -def is_typevar(typ: type) -> bool: - # type ignore is required because type checkers - # think this expression will always return False - return type(typ) == TypeVar # type: ignore - - -_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,) -if sys.version_info >= (3, 12): - _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType) - - -def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: - """Return whether the provided argument is an instance of `TypeAliasType`. - - ```python - type Int = int - is_type_alias_type(Int) - # > True - Str = TypeAliasType("Str", str) - is_type_alias_type(Str) - # > True - ``` - """ - return isinstance(tp, _TYPE_ALIAS_TYPES) - - -# Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] -@lru_cache(maxsize=8096) -def strip_annotated_type(typ: type) -> type: - if is_required_type(typ) or is_annotated_type(typ): - return strip_annotated_type(cast(type, get_args(typ)[0])) - - return typ - - -def extract_type_arg(typ: type, index: int) -> type: - args = get_args(typ) - try: - return cast(type, args[index]) - except IndexError as err: - raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not") from err - - -def extract_type_var_from_base( - typ: type, - *, - generic_bases: tuple[type, ...], - index: int, - failure_message: str | None = None, -) -> type: - """Given a type like `Foo[T]`, returns the generic type variable `T`. - - This also handles the case where a concrete subclass is given, e.g. - ```py - class MyResponse(Foo[bytes]): - ... - - extract_type_var(MyResponse, bases=(Foo,), index=0) -> bytes - ``` - - And where a generic subclass is given: - ```py - _T = TypeVar('_T') - class MyResponse(Foo[_T]): - ... - - extract_type_var(MyResponse[bytes], bases=(Foo,), index=0) -> bytes - ``` - """ - cls = cast(object, get_origin(typ) or typ) - if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] - # we're given the class directly - return extract_type_arg(typ, index) - - # if a subclass is given - # --- - # this is needed as __orig_bases__ is not present in the typeshed stubs - # because it is intended to be for internal use only, however there does - # not seem to be a way to resolve generic TypeVars for inherited subclasses - # without using it. - if isinstance(cls, InheritsGeneric): - target_base_class: Any | None = None - for base in cls.__orig_bases__: - if base.__origin__ in generic_bases: - target_base_class = base - break - - if target_base_class is None: - raise RuntimeError( - "Could not find the generic base class;\n" - "This should never happen;\n" - f"Does {cls} inherit from one of {generic_bases} ?" - ) - - extracted = extract_type_arg(target_base_class, index) - if is_typevar(extracted): - # If the extracted type argument is itself a type variable - # then that means the subclass itself is generic, so we have - # to resolve the type argument from the class itself, not - # the base class. - # - # Note: if there is more than 1 type argument, the subclass could - # change the ordering of the type arguments, this is not currently - # supported. - return extract_type_arg(typ, index) - - return extracted - - raise RuntimeError(failure_message or f"Could not resolve inner type variable at index {index} for {typ}") diff --git a/google/genai/_interactions/_utils/_utils.py b/google/genai/_interactions/_utils/_utils.py deleted file mode 100644 index 4e90054fa..000000000 --- a/google/genai/_interactions/_utils/_utils.py +++ /dev/null @@ -1,449 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# mypy: ignore-errors -from __future__ import annotations - -import os -import re -import inspect -import functools -from typing import ( - Any, - Tuple, - Mapping, - TypeVar, - Callable, - Iterable, - Sequence, - cast, - overload, -) -from pathlib import Path -from datetime import date, datetime -from typing_extensions import TypeGuard, get_args - -import sniffio - -from .._types import Omit, NotGiven, FileTypes, ArrayFormat, HeadersLike - -_T = TypeVar("_T") -_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) -_MappingT = TypeVar("_MappingT", bound=Mapping[str, object]) -_SequenceT = TypeVar("_SequenceT", bound=Sequence[object]) -CallableT = TypeVar("CallableT", bound=Callable[..., Any]) - - -def flatten(t: Iterable[Iterable[_T]]) -> list[_T]: - return [item for sublist in t for item in sublist] - - -def extract_files( - # TODO: this needs to take Dict but variance issues..... - # create protocol type ? - query: Mapping[str, object], - *, - paths: Sequence[Sequence[str]], - array_format: ArrayFormat = "brackets", -) -> list[tuple[str, FileTypes]]: - """Recursively extract files from the given dictionary based on specified paths. - - A path may look like this ['foo', 'files', '', 'data']. - - ``array_format`` controls how ```` segments contribute to the emitted - field name. Supported values: ``"brackets"`` (``foo[]``), ``"repeat"`` and - ``"comma"`` (``foo``), ``"indices"`` (``foo[0]``, ``foo[1]``). - - Note: this mutates the given dictionary. - """ - files: list[tuple[str, FileTypes]] = [] - for path in paths: - files.extend(_extract_items(query, path, index=0, flattened_key=None, array_format=array_format)) - return files - - -def _array_suffix(array_format: ArrayFormat, array_index: int) -> str: - if array_format == "brackets": - return "[]" - if array_format == "indices": - return f"[{array_index}]" - if array_format == "repeat" or array_format == "comma": - # Both repeat the bare field name for each file part; there is no - # meaningful way to comma-join binary parts. - return "" - raise NotImplementedError( - f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" - ) - - -def _extract_items( - obj: object, - path: Sequence[str], - *, - index: int, - flattened_key: str | None, - array_format: ArrayFormat, -) -> list[tuple[str, FileTypes]]: - try: - key = path[index] - except IndexError: - if not is_given(obj): - # no value was provided - we can safely ignore - return [] - - # cyclical import - from .._files import assert_is_file_content - - # We have exhausted the path, return the entry we found. - assert flattened_key is not None - - if is_list(obj): - files: list[tuple[str, FileTypes]] = [] - for array_index, entry in enumerate(obj): - suffix = _array_suffix(array_format, array_index) - emitted_key = (flattened_key + suffix) if flattened_key else suffix - assert_is_file_content(entry, key=emitted_key) - files.append((emitted_key, cast(FileTypes, entry))) - return files - - assert_is_file_content(obj, key=flattened_key) - return [(flattened_key, cast(FileTypes, obj))] - - index += 1 - if is_dict(obj): - try: - # Remove the field if there are no more dict keys in the path, - # only "" traversal markers or end. - if all(p == "" for p in path[index:]): - item = obj.pop(key) - else: - item = obj[key] - except KeyError: - # Key was not present in the dictionary, this is not indicative of an error - # as the given path may not point to a required field. We also do not want - # to enforce required fields as the API may differ from the spec in some cases. - return [] - if flattened_key is None: - flattened_key = key - else: - flattened_key += f"[{key}]" - return _extract_items( - item, - path, - index=index, - flattened_key=flattened_key, - array_format=array_format, - ) - elif is_list(obj): - if key != "": - return [] - - return flatten( - [ - _extract_items( - item, - path, - index=index, - flattened_key=( - (flattened_key if flattened_key is not None else "") + _array_suffix(array_format, array_index) - ), - array_format=array_format, - ) - for array_index, item in enumerate(obj) - ] - ) - - # Something unexpected was passed, just ignore it. - return [] - - -def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: - return not isinstance(obj, NotGiven) and not isinstance(obj, Omit) - - -# Type safe methods for narrowing types with TypeVars. -# The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], -# however this cause Pyright to rightfully report errors. As we know we don't -# care about the contained types we can safely use `object` in its place. -# -# There are two separate functions defined, `is_*` and `is_*_t` for different use cases. -# `is_*` is for when you're dealing with an unknown input -# `is_*_t` is for when you're narrowing a known union type to a specific subset - - -def is_tuple(obj: object) -> TypeGuard[tuple[object, ...]]: - return isinstance(obj, tuple) - - -def is_tuple_t(obj: _TupleT | object) -> TypeGuard[_TupleT]: - return isinstance(obj, tuple) - - -def is_sequence(obj: object) -> TypeGuard[Sequence[object]]: - return isinstance(obj, Sequence) - - -def is_sequence_t(obj: _SequenceT | object) -> TypeGuard[_SequenceT]: - return isinstance(obj, Sequence) - - -def is_mapping(obj: object) -> TypeGuard[Mapping[str, object]]: - return isinstance(obj, Mapping) - - -def is_mapping_t(obj: _MappingT | object) -> TypeGuard[_MappingT]: - return isinstance(obj, Mapping) - - -def is_dict(obj: object) -> TypeGuard[dict[object, object]]: - return isinstance(obj, dict) - - -def is_list(obj: object) -> TypeGuard[list[object]]: - return isinstance(obj, list) - - -def is_iterable(obj: object) -> TypeGuard[Iterable[object]]: - return isinstance(obj, Iterable) - - -# copied from https://github.com/Rapptz/RoboDanny -def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str: - size = len(seq) - if size == 0: - return "" - - if size == 1: - return seq[0] - - if size == 2: - return f"{seq[0]} {final} {seq[1]}" - - return delim.join(seq[:-1]) + f" {final} {seq[-1]}" - - -def quote(string: str) -> str: - """Add single quotation marks around the given string. Does *not* do any escaping.""" - return f"'{string}'" - - -def required_args(*variants: Sequence[str]) -> Callable[[CallableT], CallableT]: - """Decorator to enforce a given set of arguments or variants of arguments are passed to the decorated function. - - Useful for enforcing runtime validation of overloaded functions. - - Example usage: - ```py - @overload - def foo(*, a: str) -> str: ... - - - @overload - def foo(*, b: bool) -> str: ... - - - # This enforces the same constraints that a static type checker would - # i.e. that either a or b must be passed to the function - @required_args(["a"], ["b"]) - def foo(*, a: str | None = None, b: bool | None = None) -> str: ... - ``` - """ - - def inner(func: CallableT) -> CallableT: - params = inspect.signature(func).parameters - positional = [ - name - for name, param in params.items() - if param.kind - in { - param.POSITIONAL_ONLY, - param.POSITIONAL_OR_KEYWORD, - } - ] - - @functools.wraps(func) - def wrapper(*args: object, **kwargs: object) -> object: - given_params: set[str] = set() - for i, _ in enumerate(args): - try: - given_params.add(positional[i]) - except IndexError: - raise TypeError( - f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given" - ) from None - - for key in kwargs.keys(): - given_params.add(key) - - for variant in variants: - matches = all((param in given_params for param in variant)) - if matches: - break - else: # no break - if len(variants) > 1: - variations = human_join( - ["(" + human_join([quote(arg) for arg in variant], final="and") + ")" for variant in variants] - ) - msg = f"Missing required arguments; Expected either {variations} arguments to be given" - else: - assert len(variants) > 0 - - # TODO: this error message is not deterministic - missing = list(set(variants[0]) - given_params) - if len(missing) > 1: - msg = f"Missing required arguments: {human_join([quote(arg) for arg in missing])}" - else: - msg = f"Missing required argument: {quote(missing[0])}" - raise TypeError(msg) - return func(*args, **kwargs) - - return wrapper # type: ignore - - return inner - - -_K = TypeVar("_K") -_V = TypeVar("_V") - - -@overload -def strip_not_given(obj: None) -> None: ... - - -@overload -def strip_not_given(obj: Mapping[_K, _V | NotGiven]) -> dict[_K, _V]: ... - - -@overload -def strip_not_given(obj: object) -> object: ... - - -def strip_not_given(obj: object | None) -> object: - """Remove all top-level keys where their values are instances of `NotGiven`""" - if obj is None: - return None - - if not is_mapping(obj): - return obj - - return {key: value for key, value in obj.items() if not isinstance(value, NotGiven)} - - -def coerce_integer(val: str) -> int: - return int(val, base=10) - - -def coerce_float(val: str) -> float: - return float(val) - - -def coerce_boolean(val: str) -> bool: - return val == "true" or val == "1" or val == "on" - - -def maybe_coerce_integer(val: str | None) -> int | None: - if val is None: - return None - return coerce_integer(val) - - -def maybe_coerce_float(val: str | None) -> float | None: - if val is None: - return None - return coerce_float(val) - - -def maybe_coerce_boolean(val: str | None) -> bool | None: - if val is None: - return None - return coerce_boolean(val) - - -def removeprefix(string: str, prefix: str) -> str: - """Remove a prefix from a string. - - Backport of `str.removeprefix` for Python < 3.9 - """ - if string.startswith(prefix): - return string[len(prefix) :] - return string - - -def removesuffix(string: str, suffix: str) -> str: - """Remove a suffix from a string. - - Backport of `str.removesuffix` for Python < 3.9 - """ - if string.endswith(suffix): - return string[: -len(suffix)] - return string - - -def file_from_path(path: str) -> FileTypes: - contents = Path(path).read_bytes() - file_name = os.path.basename(path) - return (file_name, contents) - - -def get_required_header(headers: HeadersLike, header: str) -> str: - lower_header = header.lower() - if is_mapping_t(headers): - # mypy doesn't understand the type narrowing here - for k, v in headers.items(): # type: ignore - if k.lower() == lower_header and isinstance(v, str): - return v - - # to deal with the case where the header looks like Stainless-Event-Id - intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) - - for normalized_header in [header, lower_header, header.upper(), intercaps_header]: - value = headers.get(normalized_header) - if value: - return value - - raise ValueError(f"Could not find {header} header") - - -def get_async_library() -> str: - try: - return sniffio.current_async_library() - except Exception: - return "false" - - -def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: - """A version of functools.lru_cache that retains the type signature - for the wrapped function arguments. - """ - wrapper = functools.lru_cache( # noqa: TID251 - maxsize=maxsize, - ) - return cast(Any, wrapper) # type: ignore[no-any-return] - - -def json_safe(data: object) -> object: - """Translates a mapping / sequence recursively in the same fashion - as `pydantic` v2's `model_dump(mode="json")`. - """ - if is_mapping(data): - return {json_safe(key): json_safe(value) for key, value in data.items()} - - if is_iterable(data) and not isinstance(data, (str, bytes, bytearray)): - return [json_safe(item) for item in data] - - if isinstance(data, (datetime, date)): - return data.isoformat() - - return data diff --git a/google/genai/_interactions/_version.py b/google/genai/_interactions/_version.py deleted file mode 100644 index f7466773c..000000000 --- a/google/genai/_interactions/_version.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -from ..version import __version__ as __version__ - -__title__ = "google.genai._interactions" diff --git a/google/genai/_interactions/resources/__init__.py b/google/genai/_interactions/resources/__init__.py deleted file mode 100644 index a61b98168..000000000 --- a/google/genai/_interactions/resources/__init__.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .agents import ( - AgentsResource, - AsyncAgentsResource, - AgentsResourceWithRawResponse, - AsyncAgentsResourceWithRawResponse, - AgentsResourceWithStreamingResponse, - AsyncAgentsResourceWithStreamingResponse, -) -from .webhooks import ( - WebhooksResource, - AsyncWebhooksResource, - WebhooksResourceWithRawResponse, - AsyncWebhooksResourceWithRawResponse, - WebhooksResourceWithStreamingResponse, - AsyncWebhooksResourceWithStreamingResponse, -) -from .interactions import ( - InteractionsResource, - AsyncInteractionsResource, - InteractionsResourceWithRawResponse, - AsyncInteractionsResourceWithRawResponse, - InteractionsResourceWithStreamingResponse, - AsyncInteractionsResourceWithStreamingResponse, -) - -__all__ = [ - "InteractionsResource", - "AsyncInteractionsResource", - "InteractionsResourceWithRawResponse", - "AsyncInteractionsResourceWithRawResponse", - "InteractionsResourceWithStreamingResponse", - "AsyncInteractionsResourceWithStreamingResponse", - "WebhooksResource", - "AsyncWebhooksResource", - "WebhooksResourceWithRawResponse", - "AsyncWebhooksResourceWithRawResponse", - "WebhooksResourceWithStreamingResponse", - "AsyncWebhooksResourceWithStreamingResponse", - "AgentsResource", - "AsyncAgentsResource", - "AgentsResourceWithRawResponse", - "AsyncAgentsResourceWithRawResponse", - "AgentsResourceWithStreamingResponse", - "AsyncAgentsResourceWithStreamingResponse", -] diff --git a/google/genai/_interactions/resources/agents.py b/google/genai/_interactions/resources/agents.py deleted file mode 100644 index 1bbbe9975..000000000 --- a/google/genai/_interactions/resources/agents.py +++ /dev/null @@ -1,532 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable - -import httpx - -from ..types import agent_list_params, agent_create_params -from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..types.agent import Agent -from .._base_client import make_request_options -from ..types.agent_list_response import AgentListResponse -from ..types.agent_delete_response import AgentDeleteResponse - -__all__ = ["AgentsResource", "AsyncAgentsResource"] - - -class AgentsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> AgentsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#accessing-raw-response-data-eg-headers - """ - return AgentsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AgentsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#with_streaming_response - """ - return AgentsResourceWithStreamingResponse(self) - - def create( - self, - *, - api_version: str | None = None, - id: str | Omit = omit, - base_agent: str | Omit = omit, - base_environment: agent_create_params.BaseEnvironment | Omit = omit, - description: str | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[agent_create_params.Tool] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Agent: - """ - Creates a new Agent (Typed version for SDK). - - Args: - id: The unique identifier for the agent. - - base_agent: The base agent to extend. - - base_environment: The environment configuration for the agent. - - description: Agent description for developers to quickly read and understand. - - system_instruction: System instruction for the agent. - - tools: The tools available to the agent. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - return self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path='agents'), - body=maybe_transform( - { - "id": id, - "base_agent": base_agent, - "base_environment": base_environment, - "description": description, - "system_instruction": system_instruction, - "tools": tools, - }, - agent_create_params.AgentCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Agent, - ) - - def list( - self, - *, - api_version: str | None = None, - page_size: int | Omit = omit, - page_token: str | Omit = omit, - parent: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AgentListResponse: - """ - Lists all Agents. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - return self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path='agents'), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page_size": page_size, - "page_token": page_token, - "parent": parent, - }, - agent_list_params.AgentListParams, - ), - ), - cast_to=AgentListResponse, - ) - - def delete( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AgentDeleteResponse: - """ - Deletes an Agent. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._delete( - self._client._build_maybe_vertex_path(api_version=api_version, path=f'agents/{id}'), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentDeleteResponse, - ) - - def get( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Agent: - """ - Gets a specific Agent. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path=f'agents/{id}'), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Agent, - ) - - -class AsyncAgentsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncAgentsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#accessing-raw-response-data-eg-headers - """ - return AsyncAgentsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAgentsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#with_streaming_response - """ - return AsyncAgentsResourceWithStreamingResponse(self) - - async def create( - self, - *, - api_version: str | None = None, - id: str | Omit = omit, - base_agent: str | Omit = omit, - base_environment: agent_create_params.BaseEnvironment | Omit = omit, - description: str | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[agent_create_params.Tool] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Agent: - """ - Creates a new Agent (Typed version for SDK). - - Args: - id: The unique identifier for the agent. - - base_agent: The base agent to extend. - - base_environment: The environment configuration for the agent. - - description: Agent description for developers to quickly read and understand. - - system_instruction: System instruction for the agent. - - tools: The tools available to the agent. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - return await self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path='agents'), - body=await async_maybe_transform( - { - "id": id, - "base_agent": base_agent, - "base_environment": base_environment, - "description": description, - "system_instruction": system_instruction, - "tools": tools, - }, - agent_create_params.AgentCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Agent, - ) - - async def list( - self, - *, - api_version: str | None = None, - page_size: int | Omit = omit, - page_token: str | Omit = omit, - parent: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AgentListResponse: - """ - Lists all Agents. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - return await self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path='agents'), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "page_size": page_size, - "page_token": page_token, - "parent": parent, - }, - agent_list_params.AgentListParams, - ), - ), - cast_to=AgentListResponse, - ) - - async def delete( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AgentDeleteResponse: - """ - Deletes an Agent. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._delete( - self._client._build_maybe_vertex_path(api_version=api_version, path=f'agents/{id}'), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AgentDeleteResponse, - ) - - async def get( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Agent: - """ - Gets a specific Agent. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path=f'agents/{id}'), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Agent, - ) - - -class AgentsResourceWithRawResponse: - def __init__(self, agents: AgentsResource) -> None: - self._agents = agents - - self.create = to_raw_response_wrapper( - agents.create, - ) - self.list = to_raw_response_wrapper( - agents.list, - ) - self.delete = to_raw_response_wrapper( - agents.delete, - ) - self.get = to_raw_response_wrapper( - agents.get, - ) - - -class AsyncAgentsResourceWithRawResponse: - def __init__(self, agents: AsyncAgentsResource) -> None: - self._agents = agents - - self.create = async_to_raw_response_wrapper( - agents.create, - ) - self.list = async_to_raw_response_wrapper( - agents.list, - ) - self.delete = async_to_raw_response_wrapper( - agents.delete, - ) - self.get = async_to_raw_response_wrapper( - agents.get, - ) - - -class AgentsResourceWithStreamingResponse: - def __init__(self, agents: AgentsResource) -> None: - self._agents = agents - - self.create = to_streamed_response_wrapper( - agents.create, - ) - self.list = to_streamed_response_wrapper( - agents.list, - ) - self.delete = to_streamed_response_wrapper( - agents.delete, - ) - self.get = to_streamed_response_wrapper( - agents.get, - ) - - -class AsyncAgentsResourceWithStreamingResponse: - def __init__(self, agents: AsyncAgentsResource) -> None: - self._agents = agents - - self.create = async_to_streamed_response_wrapper( - agents.create, - ) - self.list = async_to_streamed_response_wrapper( - agents.list, - ) - self.delete = async_to_streamed_response_wrapper( - agents.delete, - ) - self.get = async_to_streamed_response_wrapper( - agents.get, - ) diff --git a/google/genai/_interactions/resources/interactions.py b/google/genai/_interactions/resources/interactions.py deleted file mode 100644 index 12846a423..000000000 --- a/google/genai/_interactions/resources/interactions.py +++ /dev/null @@ -1,1656 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable -from typing_extensions import Literal, overload - -import httpx - -from ..types import interaction_get_params, interaction_create_params -from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from .._utils import required_args, maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from .._streaming import Stream, AsyncStream -from .._base_client import make_request_options -from .._legacy_lyria import ( - LegacyLyriaInteractionStream, - LegacyLyriaInteractionAsyncStream, - LegacyLyriaInteractionDetectingStream, - LegacyLyriaInteractionDetectingAsyncStream, - is_legacy_lyria_request, -) -from ..types.tool_param import ToolParam -from ..types.interaction import Interaction -from ..types.model_param import ModelParam -from ..types.webhook_config_param import WebhookConfigParam -from ..types.interaction_sse_event import InteractionSSEEvent -from ..types.generation_config_param import GenerationConfigParam - -__all__ = ["InteractionsResource", "AsyncInteractionsResource"] - - -class InteractionsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> InteractionsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#accessing-raw-response-data-eg-headers - """ - return InteractionsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> InteractionsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#with_streaming_response - """ - return InteractionsResourceWithStreamingResponse(self) - - @overload - def create( - self, - *, - api_version: str | None = None, - input: interaction_create_params.Input, - model: ModelParam, - background: bool | Omit = omit, - cached_content: str | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - generation_config: GenerationConfigParam | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - stream: Literal[False] | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction: - """ - Creates a new interaction. - - Args: - input: The input for the interaction. - - model: The name of the `Model` used for generating the interaction. - - background: Input only. Whether to run the model interaction in the background. - - cached_content: - The name of the cached content used as context to serve the prediction. Note: - only used in explicit caching, where users can have control over caching (e.g. - what content to cache) and enjoy guaranteed cost savings. Format: - `projects/{project}/locations/{location}/cachedContents/{cachedContent}` - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - generation_config: Input only. Configuration parameters for the model interaction. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - stream: Input only. Whether the interaction will be streamed. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - api_version: str | None = None, - input: interaction_create_params.Input, - model: ModelParam, - stream: Literal[True], - background: bool | Omit = omit, - cached_content: str | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - generation_config: GenerationConfigParam | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[InteractionSSEEvent]: - """ - Creates a new interaction. - - Args: - input: The input for the interaction. - - model: The name of the `Model` used for generating the interaction. - - stream: Input only. Whether the interaction will be streamed. - - background: Input only. Whether to run the model interaction in the background. - - cached_content: - The name of the cached content used as context to serve the prediction. Note: - only used in explicit caching, where users can have control over caching (e.g. - what content to cache) and enjoy guaranteed cost savings. Format: - `projects/{project}/locations/{location}/cachedContents/{cachedContent}` - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - generation_config: Input only. Configuration parameters for the model interaction. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - api_version: str | None = None, - agent: Union[ - Literal[ - "deep-research-pro-preview-12-2025", - "deep-research-preview-04-2026", - "deep-research-max-preview-04-2026", - "antigravity-preview-05-2026", - ], - str, - ], - input: interaction_create_params.Input, - agent_config: interaction_create_params.AgentConfig | Omit = omit, - background: bool | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - stream: Literal[False] | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction: - """ - Creates a new interaction. - - Args: - agent: The name of the `Agent` used for generating the interaction. - - input: The input for the interaction. - - agent_config: Configuration parameters for the agent interaction. - - background: Input only. Whether to run the model interaction in the background. - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - stream: Input only. Whether the interaction will be streamed. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - api_version: str | None = None, - agent: Union[ - Literal[ - "deep-research-pro-preview-12-2025", - "deep-research-preview-04-2026", - "deep-research-max-preview-04-2026", - "antigravity-preview-05-2026", - ], - str, - ], - input: interaction_create_params.Input, - stream: Literal[True], - agent_config: interaction_create_params.AgentConfig | Omit = omit, - background: bool | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[InteractionSSEEvent]: - """ - Creates a new interaction. - - Args: - agent: The name of the `Agent` used for generating the interaction. - - input: The input for the interaction. - - stream: Input only. Whether the interaction will be streamed. - - agent_config: Configuration parameters for the agent interaction. - - background: Input only. Whether to run the model interaction in the background. - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def create( - self, - *, - api_version: str | None = None, - input: interaction_create_params.Input, - model: ModelParam, - stream: bool, - background: bool | Omit = omit, - cached_content: str | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - generation_config: GenerationConfigParam | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction | Stream[InteractionSSEEvent]: - """ - Creates a new interaction. - - Args: - input: The input for the interaction. - - model: The name of the `Model` used for generating the interaction. - - stream: Input only. Whether the interaction will be streamed. - - background: Input only. Whether to run the model interaction in the background. - - cached_content: - The name of the cached content used as context to serve the prediction. Note: - only used in explicit caching, where users can have control over caching (e.g. - what content to cache) and enjoy guaranteed cost savings. Format: - `projects/{project}/locations/{location}/cachedContents/{cachedContent}` - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - generation_config: Input only. Configuration parameters for the model interaction. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["input", "model"], ["input", "model", "stream"], ["agent", "input"], ["agent", "input", "stream"]) - def create( - self, - *, - api_version: str | None = None, - input: interaction_create_params.Input, - model: ModelParam | Omit = omit, - background: bool | Omit = omit, - cached_content: str | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - generation_config: GenerationConfigParam | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - stream: Literal[False] | Literal[True] | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - agent: Union[ - Literal[ - "deep-research-pro-preview-12-2025", - "deep-research-preview-04-2026", - "deep-research-max-preview-04-2026", - "antigravity-preview-05-2026", - ], - str, - ] - | Omit = omit, - agent_config: interaction_create_params.AgentConfig | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction | Stream[InteractionSSEEvent]: - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if model is not omit and agent_config is not omit: - raise ValueError( - "Invalid request: specified `model` and `agent_config`. If specifying `model`, use `generation_config`." - ) - if agent is not omit and generation_config is not omit: - raise ValueError( - "Invalid request: specified `agent` and `generation_config`. If specifying `agent`, use `agent_config`." - ) - - # For streaming requests against vertex+legacy-lyria, swap in the - # Stream subclass that activates the per-event SSE remap during - # iteration. Non-streaming and `get()` paths don't need any resource- - # layer signal here — `Interaction._maybe_coerce_outputs` looks at the - # response body's `model` field directly. - stream_cls = ( - LegacyLyriaInteractionStream[InteractionSSEEvent] - if (stream and is_legacy_lyria_request(is_vertex=self._client._is_vertex, model=model)) - else Stream[InteractionSSEEvent] - ) - return self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path="interactions"), - body=maybe_transform( - { - "input": input, - "model": model, - "background": background, - "cached_content": cached_content, - "environment": environment, - "generation_config": generation_config, - "previous_interaction_id": previous_interaction_id, - "response_format": response_format, - "response_mime_type": response_mime_type, - "response_modalities": response_modalities, - "service_tier": service_tier, - "store": store, - "stream": stream, - "system_instruction": system_instruction, - "tools": tools, - "webhook_config": webhook_config, - "agent": agent, - "agent_config": agent_config, - }, - interaction_create_params.CreateModelInteractionParamsStreaming - if stream - else interaction_create_params.CreateModelInteractionParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Interaction, - stream=stream or False, - stream_cls=stream_cls, - ) - - def delete( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> object: - """ - Deletes the interaction by id. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._delete( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"interactions/{id}"), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - def cancel( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction: - """Cancels an interaction by id. - - This only applies to background interactions that - are still running. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"interactions/{id}/cancel"), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Interaction, - ) - - @overload - def get( - self, - id: str, - *, - api_version: str | None = None, - include_input: bool | Omit = omit, - last_event_id: str | Omit = omit, - stream: Literal[False] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction: - """ - Retrieves the full details of a single interaction based on its - `Interaction.id`. - - Args: - include_input: If set to true, includes the input in the response. - - last_event_id: Optional. If set, resumes the interaction stream from the next chunk after the - event marked by the event id. Can only be used if `stream` is true. - - stream: If set to true, the generated content will be streamed incrementally. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def get( - self, - id: str, - *, - api_version: str | None = None, - stream: Literal[True], - include_input: bool | Omit = omit, - last_event_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Stream[InteractionSSEEvent]: - """ - Retrieves the full details of a single interaction based on its - `Interaction.id`. - - Args: - stream: If set to true, the generated content will be streamed incrementally. - - include_input: If set to true, includes the input in the response. - - last_event_id: Optional. If set, resumes the interaction stream from the next chunk after the - event marked by the event id. Can only be used if `stream` is true. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - def get( - self, - id: str, - *, - api_version: str | None = None, - stream: bool, - include_input: bool | Omit = omit, - last_event_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction | Stream[InteractionSSEEvent]: - """ - Retrieves the full details of a single interaction based on its - `Interaction.id`. - - Args: - stream: If set to true, the generated content will be streamed incrementally. - - include_input: If set to true, includes the input in the response. - - last_event_id: Optional. If set, resumes the interaction stream from the next chunk after the - event marked by the event id. Can only be used if `stream` is true. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - def get( - self, - id: str, - *, - api_version: str | None = None, - include_input: bool | Omit = omit, - last_event_id: str | Omit = omit, - stream: Literal[False] | Literal[True] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction | Stream[InteractionSSEEvent]: - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - - # We don't know the model up front for `get`, so we can't apply the - # same `is_legacy_lyria_request` gate that `create` uses. Instead, on - # vertex we hand the stream off to the detecting subclass, which - # activates the shim only after observing the first legacy event_type. - # For non-legacy interactions the subclass is a no-op vs. plain Stream. - stream_cls = ( - LegacyLyriaInteractionDetectingStream[InteractionSSEEvent] - if (stream and self._client._is_vertex) - else Stream[InteractionSSEEvent] - ) - return self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"interactions/{id}"), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "include_input": include_input, - "last_event_id": last_event_id, - "stream": stream, - }, - interaction_get_params.InteractionGetParams, - ), - ), - cast_to=Interaction, - stream=stream or False, - stream_cls=stream_cls, - ) - - -class AsyncInteractionsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncInteractionsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#accessing-raw-response-data-eg-headers - """ - return AsyncInteractionsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncInteractionsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#with_streaming_response - """ - return AsyncInteractionsResourceWithStreamingResponse(self) - - @overload - async def create( - self, - *, - api_version: str | None = None, - input: interaction_create_params.Input, - model: ModelParam, - background: bool | Omit = omit, - cached_content: str | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - generation_config: GenerationConfigParam | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - stream: Literal[False] | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction: - """ - Creates a new interaction. - - Args: - input: The input for the interaction. - - model: The name of the `Model` used for generating the interaction. - - background: Input only. Whether to run the model interaction in the background. - - cached_content: - The name of the cached content used as context to serve the prediction. Note: - only used in explicit caching, where users can have control over caching (e.g. - what content to cache) and enjoy guaranteed cost savings. Format: - `projects/{project}/locations/{location}/cachedContents/{cachedContent}` - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - generation_config: Input only. Configuration parameters for the model interaction. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - stream: Input only. Whether the interaction will be streamed. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - api_version: str | None = None, - input: interaction_create_params.Input, - model: ModelParam, - stream: Literal[True], - background: bool | Omit = omit, - cached_content: str | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - generation_config: GenerationConfigParam | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[InteractionSSEEvent]: - """ - Creates a new interaction. - - Args: - input: The input for the interaction. - - model: The name of the `Model` used for generating the interaction. - - stream: Input only. Whether the interaction will be streamed. - - background: Input only. Whether to run the model interaction in the background. - - cached_content: - The name of the cached content used as context to serve the prediction. Note: - only used in explicit caching, where users can have control over caching (e.g. - what content to cache) and enjoy guaranteed cost savings. Format: - `projects/{project}/locations/{location}/cachedContents/{cachedContent}` - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - generation_config: Input only. Configuration parameters for the model interaction. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - api_version: str | None = None, - agent: Union[ - Literal[ - "deep-research-pro-preview-12-2025", - "deep-research-preview-04-2026", - "deep-research-max-preview-04-2026", - "antigravity-preview-05-2026", - ], - str, - ], - input: interaction_create_params.Input, - agent_config: interaction_create_params.AgentConfig | Omit = omit, - background: bool | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - stream: Literal[False] | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction: - """ - Creates a new interaction. - - Args: - agent: The name of the `Agent` used for generating the interaction. - - input: The input for the interaction. - - agent_config: Configuration parameters for the agent interaction. - - background: Input only. Whether to run the model interaction in the background. - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - stream: Input only. Whether the interaction will be streamed. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - api_version: str | None = None, - agent: Union[ - Literal[ - "deep-research-pro-preview-12-2025", - "deep-research-preview-04-2026", - "deep-research-max-preview-04-2026", - "antigravity-preview-05-2026", - ], - str, - ], - input: interaction_create_params.Input, - stream: Literal[True], - agent_config: interaction_create_params.AgentConfig | Omit = omit, - background: bool | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[InteractionSSEEvent]: - """ - Creates a new interaction. - - Args: - agent: The name of the `Agent` used for generating the interaction. - - input: The input for the interaction. - - stream: Input only. Whether the interaction will be streamed. - - agent_config: Configuration parameters for the agent interaction. - - background: Input only. Whether to run the model interaction in the background. - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def create( - self, - *, - api_version: str | None = None, - input: interaction_create_params.Input, - model: ModelParam, - stream: bool, - background: bool | Omit = omit, - cached_content: str | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - generation_config: GenerationConfigParam | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction | AsyncStream[InteractionSSEEvent]: - """ - Creates a new interaction. - - Args: - input: The input for the interaction. - - model: The name of the `Model` used for generating the interaction. - - stream: Input only. Whether the interaction will be streamed. - - background: Input only. Whether to run the model interaction in the background. - - cached_content: - The name of the cached content used as context to serve the prediction. Note: - only used in explicit caching, where users can have control over caching (e.g. - what content to cache) and enjoy guaranteed cost savings. Format: - `projects/{project}/locations/{location}/cachedContents/{cachedContent}` - - environment: The environment configuration for the interaction. Can be an object specifying - remote environment sources or a string referencing an existing environment ID. - - generation_config: Input only. Configuration parameters for the model interaction. - - previous_interaction_id: The ID of the previous interaction, if any. - - response_format: Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - - response_mime_type: The mime type of the response. This is required if response_format is set. - - response_modalities: The requested modalities of the response (TEXT, IMAGE, AUDIO). - - service_tier: The service tier for the interaction. - - store: Input only. Whether to store the response and request for later retrieval. - - system_instruction: System instruction for the interaction. - - tools: A list of tool declarations the model may call during interaction. - - webhook_config: Optional. Webhook configuration for receiving notifications when the interaction - completes. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @required_args(["input", "model"], ["input", "model", "stream"], ["agent", "input"], ["agent", "input", "stream"]) - async def create( - self, - *, - api_version: str | None = None, - input: interaction_create_params.Input, - model: ModelParam | Omit = omit, - background: bool | Omit = omit, - cached_content: str | Omit = omit, - environment: interaction_create_params.Environment | Omit = omit, - generation_config: GenerationConfigParam | Omit = omit, - previous_interaction_id: str | Omit = omit, - response_format: interaction_create_params.ResponseFormat | Omit = omit, - response_mime_type: str | Omit = omit, - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] | Omit = omit, - service_tier: Literal["flex", "standard", "priority"] | Omit = omit, - store: bool | Omit = omit, - stream: Literal[False] | Literal[True] | Omit = omit, - system_instruction: str | Omit = omit, - tools: Iterable[ToolParam] | Omit = omit, - webhook_config: WebhookConfigParam | Omit = omit, - agent: Union[ - Literal[ - "deep-research-pro-preview-12-2025", - "deep-research-preview-04-2026", - "deep-research-max-preview-04-2026", - "antigravity-preview-05-2026", - ], - str, - ] - | Omit = omit, - agent_config: interaction_create_params.AgentConfig | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction | AsyncStream[InteractionSSEEvent]: - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if model is not omit and agent_config is not omit: - raise ValueError( - "Invalid request: specified `model` and `agent_config`. If specifying `model`, use `generation_config`." - ) - if agent is not omit and generation_config is not omit: - raise ValueError( - "Invalid request: specified `agent` and `generation_config`. If specifying `agent`, use `agent_config`." - ) - - # See sync `create` above for rationale. - stream_cls = ( - LegacyLyriaInteractionAsyncStream[InteractionSSEEvent] - if (stream and is_legacy_lyria_request(is_vertex=self._client._is_vertex, model=model)) - else AsyncStream[InteractionSSEEvent] - ) - return await self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path="interactions"), - body=await async_maybe_transform( - { - "input": input, - "model": model, - "background": background, - "cached_content": cached_content, - "environment": environment, - "generation_config": generation_config, - "previous_interaction_id": previous_interaction_id, - "response_format": response_format, - "response_mime_type": response_mime_type, - "response_modalities": response_modalities, - "service_tier": service_tier, - "store": store, - "stream": stream, - "system_instruction": system_instruction, - "tools": tools, - "webhook_config": webhook_config, - "agent": agent, - "agent_config": agent_config, - }, - interaction_create_params.CreateModelInteractionParamsStreaming - if stream - else interaction_create_params.CreateModelInteractionParamsNonStreaming, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Interaction, - stream=stream or False, - stream_cls=stream_cls, - ) - - async def delete( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> object: - """ - Deletes the interaction by id. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._delete( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"interactions/{id}"), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=object, - ) - - async def cancel( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction: - """Cancels an interaction by id. - - This only applies to background interactions that - are still running. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"interactions/{id}/cancel"), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Interaction, - ) - - @overload - async def get( - self, - id: str, - *, - api_version: str | None = None, - include_input: bool | Omit = omit, - last_event_id: str | Omit = omit, - stream: Literal[False] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction: - """ - Retrieves the full details of a single interaction based on its - `Interaction.id`. - - Args: - include_input: If set to true, includes the input in the response. - - last_event_id: Optional. If set, resumes the interaction stream from the next chunk after the - event marked by the event id. Can only be used if `stream` is true. - - stream: If set to true, the generated content will be streamed incrementally. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def get( - self, - id: str, - *, - api_version: str | None = None, - stream: Literal[True], - include_input: bool | Omit = omit, - last_event_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncStream[InteractionSSEEvent]: - """ - Retrieves the full details of a single interaction based on its - `Interaction.id`. - - Args: - stream: If set to true, the generated content will be streamed incrementally. - - include_input: If set to true, includes the input in the response. - - last_event_id: Optional. If set, resumes the interaction stream from the next chunk after the - event marked by the event id. Can only be used if `stream` is true. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - @overload - async def get( - self, - id: str, - *, - api_version: str | None = None, - stream: bool, - include_input: bool | Omit = omit, - last_event_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction | AsyncStream[InteractionSSEEvent]: - """ - Retrieves the full details of a single interaction based on its - `Interaction.id`. - - Args: - stream: If set to true, the generated content will be streamed incrementally. - - include_input: If set to true, includes the input in the response. - - last_event_id: Optional. If set, resumes the interaction stream from the next chunk after the - event marked by the event id. Can only be used if `stream` is true. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - ... - - async def get( - self, - id: str, - *, - api_version: str | None = None, - include_input: bool | Omit = omit, - last_event_id: str | Omit = omit, - stream: Literal[False] | Literal[True] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Interaction | AsyncStream[InteractionSSEEvent]: - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - - # See sync `get` above for rationale. - stream_cls = ( - LegacyLyriaInteractionDetectingAsyncStream[InteractionSSEEvent] - if (stream and self._client._is_vertex) - else AsyncStream[InteractionSSEEvent] - ) - return await self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"interactions/{id}"), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "include_input": include_input, - "last_event_id": last_event_id, - "stream": stream, - }, - interaction_get_params.InteractionGetParams, - ), - ), - cast_to=Interaction, - stream=stream or False, - stream_cls=stream_cls, - ) - - -class InteractionsResourceWithRawResponse: - def __init__(self, interactions: InteractionsResource) -> None: - self._interactions = interactions - - self.create = to_raw_response_wrapper( - interactions.create, - ) - self.delete = to_raw_response_wrapper( - interactions.delete, - ) - self.cancel = to_raw_response_wrapper( - interactions.cancel, - ) - self.get = to_raw_response_wrapper( - interactions.get, - ) - - -class AsyncInteractionsResourceWithRawResponse: - def __init__(self, interactions: AsyncInteractionsResource) -> None: - self._interactions = interactions - - self.create = async_to_raw_response_wrapper( - interactions.create, - ) - self.delete = async_to_raw_response_wrapper( - interactions.delete, - ) - self.cancel = async_to_raw_response_wrapper( - interactions.cancel, - ) - self.get = async_to_raw_response_wrapper( - interactions.get, - ) - - -class InteractionsResourceWithStreamingResponse: - def __init__(self, interactions: InteractionsResource) -> None: - self._interactions = interactions - - self.create = to_streamed_response_wrapper( - interactions.create, - ) - self.delete = to_streamed_response_wrapper( - interactions.delete, - ) - self.cancel = to_streamed_response_wrapper( - interactions.cancel, - ) - self.get = to_streamed_response_wrapper( - interactions.get, - ) - - -class AsyncInteractionsResourceWithStreamingResponse: - def __init__(self, interactions: AsyncInteractionsResource) -> None: - self._interactions = interactions - - self.create = async_to_streamed_response_wrapper( - interactions.create, - ) - self.delete = async_to_streamed_response_wrapper( - interactions.delete, - ) - self.cancel = async_to_streamed_response_wrapper( - interactions.cancel, - ) - self.get = async_to_streamed_response_wrapper( - interactions.get, - ) diff --git a/google/genai/_interactions/resources/webhooks.py b/google/genai/_interactions/resources/webhooks.py deleted file mode 100644 index 85fa99359..000000000 --- a/google/genai/_interactions/resources/webhooks.py +++ /dev/null @@ -1,969 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union -from typing_extensions import Literal - -import httpx - -from ..types import ( - webhook_list_params, - webhook_ping_params, - webhook_create_params, - webhook_update_params, - webhook_rotate_signing_secret_params, -) -from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from .._utils import maybe_transform, async_maybe_transform -from .._compat import cached_property -from .._resource import SyncAPIResource, AsyncAPIResource -from .._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from .._base_client import make_request_options -from ..types.webhook import Webhook -from ..types.webhook_list_response import WebhookListResponse -from ..types.webhook_ping_response import WebhookPingResponse -from ..types.webhook_delete_response import WebhookDeleteResponse -from ..types.webhook_rotate_signing_secret_response import WebhookRotateSigningSecretResponse - -__all__ = ["WebhooksResource", "AsyncWebhooksResource"] - - -class WebhooksResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> WebhooksResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#accessing-raw-response-data-eg-headers - """ - return WebhooksResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> WebhooksResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#with_streaming_response - """ - return WebhooksResourceWithStreamingResponse(self) - - def create( - self, - *, - api_version: str | None = None, - subscribed_events: List[ - Union[ - Literal[ - "batch.succeeded", - "batch.expired", - "batch.failed", - "interaction.requires_action", - "interaction.completed", - "interaction.failed", - "video.generated", - ], - str, - ] - ], - uri: str, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Webhook: - """Creates a new Webhook. - - Args: - subscribed_events: - Required. - - The events that the webhook is subscribed to. Available events: - - - batch.succeeded - - batch.expired - - batch.failed - - interaction.requires_action - - interaction.completed - - interaction.failed - - video.generated - - uri: Required. The URI to which webhook events will be sent. - - name: Optional. The user-provided name of the webhook. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - return self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path="webhooks"), - body=maybe_transform( - { - "subscribed_events": subscribed_events, - "uri": uri, - "name": name, - }, - webhook_create_params.WebhookCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Webhook, - ) - - def update( - self, - id: str, - *, - api_version: str | None = None, - update_mask: str | Omit = omit, - name: str | Omit = omit, - state: Literal["enabled", "disabled", "disabled_due_to_failed_deliveries"] | Omit = omit, - subscribed_events: List[ - Union[ - Literal[ - "batch.succeeded", - "batch.expired", - "batch.failed", - "interaction.requires_action", - "interaction.completed", - "interaction.failed", - "video.generated", - ], - str, - ] - ] - | Omit = omit, - uri: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Webhook: - """Updates an existing Webhook. - - Args: - update_mask: Optional. - - The list of fields to update. - - name: Optional. The user-provided name of the webhook. - - state: Optional. The state of the webhook. - - subscribed_events: - Optional. The events that the webhook is subscribed to. Available events: - - - batch.succeeded - - batch.expired - - batch.failed - - interaction.requires_action - - interaction.completed - - interaction.failed - - video.generated - - uri: Optional. The URI to which webhook events will be sent. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._patch( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}"), - body=maybe_transform( - { - "name": name, - "state": state, - "subscribed_events": subscribed_events, - "uri": uri, - }, - webhook_update_params.WebhookUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"update_mask": update_mask}, webhook_update_params.WebhookUpdateParams), - ), - cast_to=Webhook, - ) - - def list( - self, - *, - api_version: str | None = None, - page_size: int | Omit = omit, - page_token: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> WebhookListResponse: - """Lists all Webhooks. - - Args: - page_size: Optional. - - The maximum number of webhooks to return. The service may return fewer - than this value. If unspecified, at most 50 webhooks will be returned. The - maximum value is 1000. - - page_token: Optional. A page token, received from a previous `ListWebhooks` call. Provide - this to retrieve the subsequent page. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - return self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path="webhooks"), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page_size": page_size, - "page_token": page_token, - }, - webhook_list_params.WebhookListParams, - ), - ), - cast_to=WebhookListResponse, - ) - - def delete( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> WebhookDeleteResponse: - """ - Deletes a Webhook. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._delete( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}"), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=WebhookDeleteResponse, - ) - - def get( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Webhook: - """ - Gets a specific Webhook. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}"), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Webhook, - ) - - def ping( - self, - id: str, - *, - api_version: str | None = None, - body: webhook_ping_params.Body | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> WebhookPingResponse: - """ - Sends a ping event to a Webhook. - - Args: - body: Request message for WebhookService.PingWebhook. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}:ping"), - body=maybe_transform(body, webhook_ping_params.WebhookPingParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=WebhookPingResponse, - ) - - def rotate_signing_secret( - self, - id: str, - *, - api_version: str | None = None, - revocation_behavior: Literal["revoke_previous_secrets_after_h24", "revoke_previous_secrets_immediately"] - | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> WebhookRotateSigningSecretResponse: - """ - Generates a new signing secret for a Webhook. - - Args: - revocation_behavior: Optional. The revocation behavior for previous signing secrets. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}:rotateSigningSecret"), - body=maybe_transform( - {"revocation_behavior": revocation_behavior}, - webhook_rotate_signing_secret_params.WebhookRotateSigningSecretParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=WebhookRotateSigningSecretResponse, - ) - - -class AsyncWebhooksResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncWebhooksResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#accessing-raw-response-data-eg-headers - """ - return AsyncWebhooksResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncWebhooksResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/stainless-sdks/gemini-next-gen-api-python#with_streaming_response - """ - return AsyncWebhooksResourceWithStreamingResponse(self) - - async def create( - self, - *, - api_version: str | None = None, - subscribed_events: List[ - Union[ - Literal[ - "batch.succeeded", - "batch.expired", - "batch.failed", - "interaction.requires_action", - "interaction.completed", - "interaction.failed", - "video.generated", - ], - str, - ] - ], - uri: str, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Webhook: - """Creates a new Webhook. - - Args: - subscribed_events: - Required. - - The events that the webhook is subscribed to. Available events: - - - batch.succeeded - - batch.expired - - batch.failed - - interaction.requires_action - - interaction.completed - - interaction.failed - - video.generated - - uri: Required. The URI to which webhook events will be sent. - - name: Optional. The user-provided name of the webhook. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - return await self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path="webhooks"), - body=await async_maybe_transform( - { - "subscribed_events": subscribed_events, - "uri": uri, - "name": name, - }, - webhook_create_params.WebhookCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Webhook, - ) - - async def update( - self, - id: str, - *, - api_version: str | None = None, - update_mask: str | Omit = omit, - name: str | Omit = omit, - state: Literal["enabled", "disabled", "disabled_due_to_failed_deliveries"] | Omit = omit, - subscribed_events: List[ - Union[ - Literal[ - "batch.succeeded", - "batch.expired", - "batch.failed", - "interaction.requires_action", - "interaction.completed", - "interaction.failed", - "video.generated", - ], - str, - ] - ] - | Omit = omit, - uri: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Webhook: - """Updates an existing Webhook. - - Args: - update_mask: Optional. - - The list of fields to update. - - name: Optional. The user-provided name of the webhook. - - state: Optional. The state of the webhook. - - subscribed_events: - Optional. The events that the webhook is subscribed to. Available events: - - - batch.succeeded - - batch.expired - - batch.failed - - interaction.requires_action - - interaction.completed - - interaction.failed - - video.generated - - uri: Optional. The URI to which webhook events will be sent. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._patch( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}"), - body=await async_maybe_transform( - { - "name": name, - "state": state, - "subscribed_events": subscribed_events, - "uri": uri, - }, - webhook_update_params.WebhookUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"update_mask": update_mask}, webhook_update_params.WebhookUpdateParams - ), - ), - cast_to=Webhook, - ) - - async def list( - self, - *, - api_version: str | None = None, - page_size: int | Omit = omit, - page_token: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> WebhookListResponse: - """Lists all Webhooks. - - Args: - page_size: Optional. - - The maximum number of webhooks to return. The service may return fewer - than this value. If unspecified, at most 50 webhooks will be returned. The - maximum value is 1000. - - page_token: Optional. A page token, received from a previous `ListWebhooks` call. Provide - this to retrieve the subsequent page. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - return await self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path="webhooks"), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "page_size": page_size, - "page_token": page_token, - }, - webhook_list_params.WebhookListParams, - ), - ), - cast_to=WebhookListResponse, - ) - - async def delete( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> WebhookDeleteResponse: - """ - Deletes a Webhook. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._delete( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}"), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=WebhookDeleteResponse, - ) - - async def get( - self, - id: str, - *, - api_version: str | None = None, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Webhook: - """ - Gets a specific Webhook. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._get( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}"), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Webhook, - ) - - async def ping( - self, - id: str, - *, - api_version: str | None = None, - body: webhook_ping_params.Body | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> WebhookPingResponse: - """ - Sends a ping event to a Webhook. - - Args: - body: Request message for WebhookService.PingWebhook. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}:ping"), - body=await async_maybe_transform(body, webhook_ping_params.WebhookPingParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=WebhookPingResponse, - ) - - async def rotate_signing_secret( - self, - id: str, - *, - api_version: str | None = None, - revocation_behavior: Literal["revoke_previous_secrets_after_h24", "revoke_previous_secrets_immediately"] - | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> WebhookRotateSigningSecretResponse: - """ - Generates a new signing secret for a Webhook. - - Args: - revocation_behavior: Optional. The revocation behavior for previous signing secrets. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if api_version is None: - api_version = self._client._get_api_version_path_param() - if not api_version: - raise ValueError(f"Expected a non-empty value for `api_version` but received {api_version!r}") - if not id: - raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") - return await self._post( - self._client._build_maybe_vertex_path(api_version=api_version, path=f"webhooks/{id}:rotateSigningSecret"), - body=await async_maybe_transform( - {"revocation_behavior": revocation_behavior}, - webhook_rotate_signing_secret_params.WebhookRotateSigningSecretParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=WebhookRotateSigningSecretResponse, - ) - - -class WebhooksResourceWithRawResponse: - def __init__(self, webhooks: WebhooksResource) -> None: - self._webhooks = webhooks - - self.create = to_raw_response_wrapper( - webhooks.create, - ) - self.update = to_raw_response_wrapper( - webhooks.update, - ) - self.list = to_raw_response_wrapper( - webhooks.list, - ) - self.delete = to_raw_response_wrapper( - webhooks.delete, - ) - self.get = to_raw_response_wrapper( - webhooks.get, - ) - self.ping = to_raw_response_wrapper( - webhooks.ping, - ) - self.rotate_signing_secret = to_raw_response_wrapper( - webhooks.rotate_signing_secret, - ) - - -class AsyncWebhooksResourceWithRawResponse: - def __init__(self, webhooks: AsyncWebhooksResource) -> None: - self._webhooks = webhooks - - self.create = async_to_raw_response_wrapper( - webhooks.create, - ) - self.update = async_to_raw_response_wrapper( - webhooks.update, - ) - self.list = async_to_raw_response_wrapper( - webhooks.list, - ) - self.delete = async_to_raw_response_wrapper( - webhooks.delete, - ) - self.get = async_to_raw_response_wrapper( - webhooks.get, - ) - self.ping = async_to_raw_response_wrapper( - webhooks.ping, - ) - self.rotate_signing_secret = async_to_raw_response_wrapper( - webhooks.rotate_signing_secret, - ) - - -class WebhooksResourceWithStreamingResponse: - def __init__(self, webhooks: WebhooksResource) -> None: - self._webhooks = webhooks - - self.create = to_streamed_response_wrapper( - webhooks.create, - ) - self.update = to_streamed_response_wrapper( - webhooks.update, - ) - self.list = to_streamed_response_wrapper( - webhooks.list, - ) - self.delete = to_streamed_response_wrapper( - webhooks.delete, - ) - self.get = to_streamed_response_wrapper( - webhooks.get, - ) - self.ping = to_streamed_response_wrapper( - webhooks.ping, - ) - self.rotate_signing_secret = to_streamed_response_wrapper( - webhooks.rotate_signing_secret, - ) - - -class AsyncWebhooksResourceWithStreamingResponse: - def __init__(self, webhooks: AsyncWebhooksResource) -> None: - self._webhooks = webhooks - - self.create = async_to_streamed_response_wrapper( - webhooks.create, - ) - self.update = async_to_streamed_response_wrapper( - webhooks.update, - ) - self.list = async_to_streamed_response_wrapper( - webhooks.list, - ) - self.delete = async_to_streamed_response_wrapper( - webhooks.delete, - ) - self.get = async_to_streamed_response_wrapper( - webhooks.get, - ) - self.ping = async_to_streamed_response_wrapper( - webhooks.ping, - ) - self.rotate_signing_secret = async_to_streamed_response_wrapper( - webhooks.rotate_signing_secret, - ) diff --git a/google/genai/_interactions/types/__init__.py b/google/genai/_interactions/types/__init__.py deleted file mode 100644 index 9a1f90467..000000000 --- a/google/genai/_interactions/types/__init__.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .step import Step as Step -from .tool import Tool as Tool -from .agent import Agent as Agent -from .model import Model as Model -from .usage import Usage as Usage -from .content import Content as Content -from .webhook import Webhook as Webhook -from .function import Function as Function -from .step_stop import StepStop as StepStop -from .annotation import Annotation as Annotation -from .step_delta import StepDelta as StepDelta -from .step_param import StepParam as StepParam -from .step_start import StepStart as StepStart -from .tool_param import ToolParam as ToolParam -from .environment import Environment as Environment -from .error_event import ErrorEvent as ErrorEvent -from .interaction import Interaction as Interaction -from .model_param import ModelParam as ModelParam -from .usage_param import UsageParam as UsageParam -from .image_config import ImageConfig as ImageConfig -from .text_content import TextContent as TextContent -from .thought_step import ThoughtStep as ThoughtStep -from .url_citation import URLCitation as URLCitation -from .allowed_tools import AllowedTools as AllowedTools -from .audio_content import AudioContent as AudioContent -from .content_param import ContentParam as ContentParam -from .file_citation import FileCitation as FileCitation -from .image_content import ImageContent as ImageContent -from .speech_config import SpeechConfig as SpeechConfig -from .video_content import VideoContent as VideoContent -from .function_param import FunctionParam as FunctionParam -from .place_citation import PlaceCitation as PlaceCitation -from .signing_secret import SigningSecret as SigningSecret -from .thinking_level import ThinkingLevel as ThinkingLevel -from .webhook_config import WebhookConfig as WebhookConfig -from .user_input_step import UserInputStep as UserInputStep -from .annotation_param import AnnotationParam as AnnotationParam -from .document_content import DocumentContent as DocumentContent -from .tool_choice_type import ToolChoiceType as ToolChoiceType -from .agent_list_params import AgentListParams as AgentListParams -from .environment_param import EnvironmentParam as EnvironmentParam -from .generation_config import GenerationConfig as GenerationConfig -from .model_output_step import ModelOutputStep as ModelOutputStep -from .function_call_step import FunctionCallStep as FunctionCallStep -from .google_maps_result import GoogleMapsResult as GoogleMapsResult -from .image_config_param import ImageConfigParam as ImageConfigParam -from .text_content_param import TextContentParam as TextContentParam -from .thought_step_param import ThoughtStepParam as ThoughtStepParam -from .tool_choice_config import ToolChoiceConfig as ToolChoiceConfig -from .url_citation_param import URLCitationParam as URLCitationParam -from .url_context_result import URLContextResult as URLContextResult -from .agent_create_params import AgentCreateParams as AgentCreateParams -from .agent_list_response import AgentListResponse as AgentListResponse -from .allowed_tools_param import AllowedToolsParam as AllowedToolsParam -from .audio_content_param import AudioContentParam as AudioContentParam -from .file_citation_param import FileCitationParam as FileCitationParam -from .image_content_param import ImageContentParam as ImageContentParam -from .speech_config_param import SpeechConfigParam as SpeechConfigParam -from .video_content_param import VideoContentParam as VideoContentParam -from .webhook_list_params import WebhookListParams as WebhookListParams -from .webhook_ping_params import WebhookPingParams as WebhookPingParams -from .dynamic_agent_config import DynamicAgentConfig as DynamicAgentConfig -from .function_result_step import FunctionResultStep as FunctionResultStep -from .google_search_result import GoogleSearchResult as GoogleSearchResult -from .place_citation_param import PlaceCitationParam as PlaceCitationParam -from .text_response_format import TextResponseFormat as TextResponseFormat -from .webhook_config_param import WebhookConfigParam as WebhookConfigParam -from .agent_delete_response import AgentDeleteResponse as AgentDeleteResponse -from .audio_response_format import AudioResponseFormat as AudioResponseFormat -from .file_search_call_step import FileSearchCallStep as FileSearchCallStep -from .google_maps_call_step import GoogleMapsCallStep as GoogleMapsCallStep -from .image_response_format import ImageResponseFormat as ImageResponseFormat -from .interaction_sse_event import InteractionSSEEvent as InteractionSSEEvent -from .url_context_call_step import URLContextCallStep as URLContextCallStep -from .user_input_step_param import UserInputStepParam as UserInputStepParam -from .webhook_create_params import WebhookCreateParams as WebhookCreateParams -from .webhook_list_response import WebhookListResponse as WebhookListResponse -from .webhook_ping_response import WebhookPingResponse as WebhookPingResponse -from .webhook_update_params import WebhookUpdateParams as WebhookUpdateParams -from .document_content_param import DocumentContentParam as DocumentContentParam -from .interaction_get_params import InteractionGetParams as InteractionGetParams -from .file_search_result_step import FileSearchResultStep as FileSearchResultStep -from .generation_config_param import GenerationConfigParam as GenerationConfigParam -from .google_maps_result_step import GoogleMapsResultStep as GoogleMapsResultStep -from .google_search_call_step import GoogleSearchCallStep as GoogleSearchCallStep -from .model_output_step_param import ModelOutputStepParam as ModelOutputStepParam -from .url_context_result_step import URLContextResultStep as URLContextResultStep -from .webhook_delete_response import WebhookDeleteResponse as WebhookDeleteResponse -from .code_execution_call_step import CodeExecutionCallStep as CodeExecutionCallStep -from .function_call_step_param import FunctionCallStepParam as FunctionCallStepParam -from .tool_choice_config_param import ToolChoiceConfigParam as ToolChoiceConfigParam -from .google_search_result_step import GoogleSearchResultStep as GoogleSearchResultStep -from .interaction_create_params import InteractionCreateParams as InteractionCreateParams -from .interaction_created_event import InteractionCreatedEvent as InteractionCreatedEvent -from .interaction_status_update import InteractionStatusUpdate as InteractionStatusUpdate -from .mcp_server_tool_call_step import MCPServerToolCallStep as MCPServerToolCallStep -from .code_execution_result_step import CodeExecutionResultStep as CodeExecutionResultStep -from .deep_research_agent_config import DeepResearchAgentConfig as DeepResearchAgentConfig -from .dynamic_agent_config_param import DynamicAgentConfigParam as DynamicAgentConfigParam -from .function_result_step_param import FunctionResultStepParam as FunctionResultStepParam -from .google_maps_call_arguments import GoogleMapsCallArguments as GoogleMapsCallArguments -from .text_response_format_param import TextResponseFormatParam as TextResponseFormatParam -from .url_context_call_arguments import URLContextCallArguments as URLContextCallArguments -from .audio_response_format_param import AudioResponseFormatParam as AudioResponseFormatParam -from .file_search_call_step_param import FileSearchCallStepParam as FileSearchCallStepParam -from .google_maps_call_step_param import GoogleMapsCallStepParam as GoogleMapsCallStepParam -from .image_response_format_param import ImageResponseFormatParam as ImageResponseFormatParam -from .interaction_completed_event import InteractionCompletedEvent as InteractionCompletedEvent -from .mcp_server_tool_result_step import MCPServerToolResultStep as MCPServerToolResultStep -from .url_context_call_step_param import URLContextCallStepParam as URLContextCallStepParam -from .google_search_call_arguments import GoogleSearchCallArguments as GoogleSearchCallArguments -from .code_execution_call_arguments import CodeExecutionCallArguments as CodeExecutionCallArguments -from .file_search_result_step_param import FileSearchResultStepParam as FileSearchResultStepParam -from .google_maps_result_step_param import GoogleMapsResultStepParam as GoogleMapsResultStepParam -from .google_search_call_step_param import GoogleSearchCallStepParam as GoogleSearchCallStepParam -from .url_context_result_step_param import URLContextResultStepParam as URLContextResultStepParam -from .code_execution_call_step_param import CodeExecutionCallStepParam as CodeExecutionCallStepParam -from .google_search_result_step_param import GoogleSearchResultStepParam as GoogleSearchResultStepParam -from .mcp_server_tool_call_step_param import MCPServerToolCallStepParam as MCPServerToolCallStepParam -from .code_execution_result_step_param import CodeExecutionResultStepParam as CodeExecutionResultStepParam -from .deep_research_agent_config_param import DeepResearchAgentConfigParam as DeepResearchAgentConfigParam -from .mcp_server_tool_result_step_param import MCPServerToolResultStepParam as MCPServerToolResultStepParam -from .webhook_rotate_signing_secret_params import WebhookRotateSigningSecretParams as WebhookRotateSigningSecretParams -from .webhook_rotate_signing_secret_response import ( - WebhookRotateSigningSecretResponse as WebhookRotateSigningSecretResponse, -) diff --git a/google/genai/_interactions/types/agent.py b/google/genai/_interactions/types/agent.py deleted file mode 100644 index 015f0abd4..000000000 --- a/google/genai/_interactions/types/agent.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from .._utils import PropertyInfo -from .._models import BaseModel -from .environment import Environment -from .allowed_tools import AllowedTools - -__all__ = [ - "Agent", - "BaseEnvironment", - "Tool", - "ToolCodeExecution", - "ToolGoogleSearch", - "ToolURLContext", - "ToolMCPServer", -] - -BaseEnvironment: TypeAlias = Union[Environment, str] - - -class ToolCodeExecution(BaseModel): - """A tool that can be used by the model to execute code.""" - - type: Literal["code_execution"] - - -class ToolGoogleSearch(BaseModel): - """A tool that can be used by the model to search Google.""" - - type: Literal["google_search"] - - search_types: Optional[List[Literal["web_search", "image_search", "enterprise_web_search"]]] = None - """The types of search grounding to enable.""" - - -class ToolURLContext(BaseModel): - """A tool that can be used by the model to fetch URL context.""" - - type: Literal["url_context"] - - -class ToolMCPServer(BaseModel): - """A MCPServer is a server that can be called by the model to perform actions.""" - - type: Literal["mcp_server"] - - allowed_tools: Optional[List[AllowedTools]] = None - """The allowed tools.""" - - headers: Optional[Dict[str, str]] = None - """Optional: Fields for authentication headers, timeouts, etc., if needed.""" - - name: Optional[str] = None - """The name of the MCPServer.""" - - url: Optional[str] = None - """The full URL for the MCPServer endpoint. Example: "https://api.example.com/mcp" """ - - -Tool: TypeAlias = Annotated[ - Union[ToolCodeExecution, ToolGoogleSearch, ToolURLContext, ToolMCPServer], PropertyInfo(discriminator="type") -] - - -class Agent(BaseModel): - """ - An agent definition for the CreateAgent API. - This message is the target for annotation-parser-based JSON parsing. - New format: - { - "id": "customer-sentinel", - "base_agent": "", - "system_instruction": "...", - "base_environment": { "type": "remote", "sources": [...] }, - "tools": [ {"type": "code_execution"} ] - } - """ - - id: Optional[str] = None - """The unique identifier for the agent.""" - - base_agent: Optional[str] = None - """The base agent to extend.""" - - base_environment: Optional[BaseEnvironment] = None - """The environment configuration for the agent.""" - - description: Optional[str] = None - """Agent description for developers to quickly read and understand.""" - - system_instruction: Optional[str] = None - """System instruction for the agent.""" - - tools: Optional[List[Tool]] = None - """The tools available to the agent.""" diff --git a/google/genai/_interactions/types/agent_create_params.py b/google/genai/_interactions/types/agent_create_params.py deleted file mode 100644 index edcfad8f0..000000000 --- a/google/genai/_interactions/types/agent_create_params.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List, Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .environment_param import EnvironmentParam -from .allowed_tools_param import AllowedToolsParam - -__all__ = [ - "AgentCreateParams", - "BaseEnvironment", - "Tool", - "ToolCodeExecution", - "ToolGoogleSearch", - "ToolURLContext", - "ToolMCPServer", -] - - -class AgentCreateParams(TypedDict, total=False): - api_version: str - - id: str - """The unique identifier for the agent.""" - - base_agent: str - """The base agent to extend.""" - - base_environment: BaseEnvironment - """The environment configuration for the agent.""" - - description: str - """Agent description for developers to quickly read and understand.""" - - system_instruction: str - """System instruction for the agent.""" - - tools: Iterable[Tool] - """The tools available to the agent.""" - - -BaseEnvironment: TypeAlias = Union[EnvironmentParam, str] - - -class ToolCodeExecution(TypedDict, total=False): - """A tool that can be used by the model to execute code.""" - - type: Required[Literal["code_execution"]] - - -class ToolGoogleSearch(TypedDict, total=False): - """A tool that can be used by the model to search Google.""" - - type: Required[Literal["google_search"]] - - search_types: List[Literal["web_search", "image_search", "enterprise_web_search"]] - """The types of search grounding to enable.""" - - -class ToolURLContext(TypedDict, total=False): - """A tool that can be used by the model to fetch URL context.""" - - type: Required[Literal["url_context"]] - - -class ToolMCPServer(TypedDict, total=False): - """A MCPServer is a server that can be called by the model to perform actions.""" - - type: Required[Literal["mcp_server"]] - - allowed_tools: Iterable[AllowedToolsParam] - """The allowed tools.""" - - headers: Dict[str, str] - """Optional: Fields for authentication headers, timeouts, etc., if needed.""" - - name: str - """The name of the MCPServer.""" - - url: str - """The full URL for the MCPServer endpoint. Example: "https://api.example.com/mcp" """ - - -Tool: TypeAlias = Union[ToolCodeExecution, ToolGoogleSearch, ToolURLContext, ToolMCPServer] diff --git a/google/genai/_interactions/types/agent_delete_response.py b/google/genai/_interactions/types/agent_delete_response.py deleted file mode 100644 index cf91eaff2..000000000 --- a/google/genai/_interactions/types/agent_delete_response.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["AgentDeleteResponse"] - - -class AgentDeleteResponse(BaseModel): - """ - A generic empty message that you can re-use to avoid defining duplicated - empty messages in your APIs. A typical example is to use it as the request - or the response type of an API method. For instance: - - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } - """ - - pass diff --git a/google/genai/_interactions/types/agent_list_params.py b/google/genai/_interactions/types/agent_list_params.py deleted file mode 100644 index af944d617..000000000 --- a/google/genai/_interactions/types/agent_list_params.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["AgentListParams"] - - -class AgentListParams(TypedDict, total=False): - api_version: str - - page_size: int - - page_token: str - - parent: str diff --git a/google/genai/_interactions/types/agent_list_response.py b/google/genai/_interactions/types/agent_list_response.py deleted file mode 100644 index fabad2175..000000000 --- a/google/genai/_interactions/types/agent_list_response.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .agent import Agent -from .._models import BaseModel - -__all__ = ["AgentListResponse"] - - -class AgentListResponse(BaseModel): - agents: Optional[List[Agent]] = None - - next_page_token: Optional[str] = None diff --git a/google/genai/_interactions/types/allowed_tools.py b/google/genai/_interactions/types/allowed_tools.py deleted file mode 100644 index 903310eb6..000000000 --- a/google/genai/_interactions/types/allowed_tools.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .._models import BaseModel -from .tool_choice_type import ToolChoiceType - -__all__ = ["AllowedTools"] - - -class AllowedTools(BaseModel): - """The configuration for allowed tools.""" - - mode: Optional[ToolChoiceType] = None - """The mode of the tool choice.""" - - tools: Optional[List[str]] = None - """The names of the allowed tools.""" diff --git a/google/genai/_interactions/types/allowed_tools_param.py b/google/genai/_interactions/types/allowed_tools_param.py deleted file mode 100644 index 566017d31..000000000 --- a/google/genai/_interactions/types/allowed_tools_param.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from .._types import SequenceNotStr -from .tool_choice_type import ToolChoiceType - -__all__ = ["AllowedToolsParam"] - - -class AllowedToolsParam(TypedDict, total=False): - """The configuration for allowed tools.""" - - mode: ToolChoiceType - """The mode of the tool choice.""" - - tools: SequenceNotStr[str] - """The names of the allowed tools.""" diff --git a/google/genai/_interactions/types/annotation.py b/google/genai/_interactions/types/annotation.py deleted file mode 100644 index 9c38a05c8..000000000 --- a/google/genai/_interactions/types/annotation.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from .._utils import PropertyInfo -from .url_citation import URLCitation -from .file_citation import FileCitation -from .place_citation import PlaceCitation - -__all__ = ["Annotation"] - -Annotation: TypeAlias = Annotated[Union[URLCitation, FileCitation, PlaceCitation], PropertyInfo(discriminator="type")] diff --git a/google/genai/_interactions/types/annotation_param.py b/google/genai/_interactions/types/annotation_param.py deleted file mode 100644 index ae6875035..000000000 --- a/google/genai/_interactions/types/annotation_param.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .url_citation_param import URLCitationParam -from .file_citation_param import FileCitationParam -from .place_citation_param import PlaceCitationParam - -__all__ = ["AnnotationParam"] - -AnnotationParam: TypeAlias = Union[URLCitationParam, FileCitationParam, PlaceCitationParam] diff --git a/google/genai/_interactions/types/audio_content.py b/google/genai/_interactions/types/audio_content.py deleted file mode 100644 index 132c481fb..000000000 --- a/google/genai/_interactions/types/audio_content.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["AudioContent"] - - -class AudioContent(BaseModel): - """An audio content block.""" - - type: Literal["audio"] - - channels: Optional[int] = None - """The number of audio channels.""" - - data: Optional[str] = None - """The audio content.""" - - mime_type: Optional[ - Literal[ - "audio/wav", - "audio/mp3", - "audio/aiff", - "audio/aac", - "audio/ogg", - "audio/flac", - "audio/mpeg", - "audio/m4a", - "audio/l16", - "audio/opus", - "audio/alaw", - "audio/mulaw", - ] - ] = None - """The mime type of the audio.""" - - sample_rate: Optional[int] = None - """The sample rate of the audio.""" - - uri: Optional[str] = None - """The URI of the audio.""" diff --git a/google/genai/_interactions/types/audio_content_param.py b/google/genai/_interactions/types/audio_content_param.py deleted file mode 100644 index 1b296428a..000000000 --- a/google/genai/_interactions/types/audio_content_param.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["AudioContentParam"] - - -class AudioContentParam(TypedDict, total=False): - """An audio content block.""" - - type: Required[Literal["audio"]] - - channels: int - """The number of audio channels.""" - - data: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """The audio content.""" - - mime_type: Literal[ - "audio/wav", - "audio/mp3", - "audio/aiff", - "audio/aac", - "audio/ogg", - "audio/flac", - "audio/mpeg", - "audio/m4a", - "audio/l16", - "audio/opus", - "audio/alaw", - "audio/mulaw", - ] - """The mime type of the audio.""" - - sample_rate: int - """The sample rate of the audio.""" - - uri: str - """The URI of the audio.""" - - -set_pydantic_config(AudioContentParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/audio_response_format.py b/google/genai/_interactions/types/audio_response_format.py deleted file mode 100644 index 80dccaf0d..000000000 --- a/google/genai/_interactions/types/audio_response_format.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["AudioResponseFormat"] - - -class AudioResponseFormat(BaseModel): - """Configuration for audio output format.""" - - type: Literal["audio"] - - bit_rate: Optional[int] = None - """Bit rate in bits per second (bps). - - Only applicable for compressed formats (MP3, Opus). - """ - - delivery: Optional[Literal["inline", "uri"]] = None - """The delivery mode for the audio output.""" - - mime_type: Optional[ - Literal["audio/mp3", "audio/ogg_opus", "audio/l16", "audio/wav", "audio/alaw", "audio/mulaw"] - ] = None - """The MIME type of the audio output.""" - - sample_rate: Optional[int] = None - """Sample rate in Hz.""" diff --git a/google/genai/_interactions/types/audio_response_format_param.py b/google/genai/_interactions/types/audio_response_format_param.py deleted file mode 100644 index 0664d03c8..000000000 --- a/google/genai/_interactions/types/audio_response_format_param.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["AudioResponseFormatParam"] - - -class AudioResponseFormatParam(TypedDict, total=False): - """Configuration for audio output format.""" - - type: Required[Literal["audio"]] - - bit_rate: int - """Bit rate in bits per second (bps). - - Only applicable for compressed formats (MP3, Opus). - """ - - delivery: Literal["inline", "uri"] - """The delivery mode for the audio output.""" - - mime_type: Literal["audio/mp3", "audio/ogg_opus", "audio/l16", "audio/wav", "audio/alaw", "audio/mulaw"] - """The MIME type of the audio output.""" - - sample_rate: int - """Sample rate in Hz.""" diff --git a/google/genai/_interactions/types/code_execution_call_arguments.py b/google/genai/_interactions/types/code_execution_call_arguments.py deleted file mode 100644 index dce405296..000000000 --- a/google/genai/_interactions/types/code_execution_call_arguments.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["CodeExecutionCallArguments"] - - -class CodeExecutionCallArguments(BaseModel): - """The arguments to pass to the code execution.""" - - code: Optional[str] = None - """The code to be executed.""" - - language: Optional[Literal["python"]] = None - """Programming language of the `code`.""" diff --git a/google/genai/_interactions/types/code_execution_call_step.py b/google/genai/_interactions/types/code_execution_call_step.py deleted file mode 100644 index 986940dea..000000000 --- a/google/genai/_interactions/types/code_execution_call_step.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["CodeExecutionCallStep", "Arguments"] - - -class Arguments(BaseModel): - """Required. The arguments to pass to the code execution.""" - - code: Optional[str] = None - """The code to be executed.""" - - language: Optional[Literal["python"]] = None - """Programming language of the `code`.""" - - -class CodeExecutionCallStep(BaseModel): - """Code execution call step.""" - - id: str - """Required. A unique ID for this specific tool call.""" - - arguments: Arguments - """Required. The arguments to pass to the code execution.""" - - type: Literal["code_execution_call"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/code_execution_call_step_param.py b/google/genai/_interactions/types/code_execution_call_step_param.py deleted file mode 100644 index eaa9f995e..000000000 --- a/google/genai/_interactions/types/code_execution_call_step_param.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["CodeExecutionCallStepParam", "Arguments"] - - -class Arguments(TypedDict, total=False): - """Required. The arguments to pass to the code execution.""" - - code: str - """The code to be executed.""" - - language: Literal["python"] - """Programming language of the `code`.""" - - -class CodeExecutionCallStepParam(TypedDict, total=False): - """Code execution call step.""" - - id: Required[str] - """Required. A unique ID for this specific tool call.""" - - arguments: Required[Arguments] - """Required. The arguments to pass to the code execution.""" - - type: Required[Literal["code_execution_call"]] - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(CodeExecutionCallStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/code_execution_result_step.py b/google/genai/_interactions/types/code_execution_result_step.py deleted file mode 100644 index 611228db3..000000000 --- a/google/genai/_interactions/types/code_execution_result_step.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["CodeExecutionResultStep"] - - -class CodeExecutionResultStep(BaseModel): - """Code execution result step.""" - - call_id: str - """Required. ID to match the ID from the function call block.""" - - result: str - """Required. The output of the code execution.""" - - type: Literal["code_execution_result"] - - is_error: Optional[bool] = None - """Whether the code execution resulted in an error.""" - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/code_execution_result_step_param.py b/google/genai/_interactions/types/code_execution_result_step_param.py deleted file mode 100644 index 51e40517f..000000000 --- a/google/genai/_interactions/types/code_execution_result_step_param.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["CodeExecutionResultStepParam"] - - -class CodeExecutionResultStepParam(TypedDict, total=False): - """Code execution result step.""" - - call_id: Required[str] - """Required. ID to match the ID from the function call block.""" - - result: Required[str] - """Required. The output of the code execution.""" - - type: Required[Literal["code_execution_result"]] - - is_error: bool - """Whether the code execution resulted in an error.""" - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(CodeExecutionResultStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/content.py b/google/genai/_interactions/types/content.py deleted file mode 100644 index c3852c413..000000000 --- a/google/genai/_interactions/types/content.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from .._utils import PropertyInfo -from .text_content import TextContent -from .audio_content import AudioContent -from .image_content import ImageContent -from .video_content import VideoContent -from .document_content import DocumentContent - -__all__ = ["Content"] - -Content: TypeAlias = Annotated[ - Union[TextContent, ImageContent, AudioContent, DocumentContent, VideoContent], PropertyInfo(discriminator="type") -] diff --git a/google/genai/_interactions/types/content_param.py b/google/genai/_interactions/types/content_param.py deleted file mode 100644 index 8300749d7..000000000 --- a/google/genai/_interactions/types/content_param.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .text_content_param import TextContentParam -from .audio_content_param import AudioContentParam -from .image_content_param import ImageContentParam -from .video_content_param import VideoContentParam -from .document_content_param import DocumentContentParam - -__all__ = ["ContentParam"] - -ContentParam: TypeAlias = Union[ - TextContentParam, ImageContentParam, AudioContentParam, DocumentContentParam, VideoContentParam -] diff --git a/google/genai/_interactions/types/deep_research_agent_config.py b/google/genai/_interactions/types/deep_research_agent_config.py deleted file mode 100644 index f551f8787..000000000 --- a/google/genai/_interactions/types/deep_research_agent_config.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["DeepResearchAgentConfig"] - - -class DeepResearchAgentConfig(BaseModel): - """Configuration for the Deep Research agent.""" - - type: Literal["deep-research"] - - collaborative_planning: Optional[bool] = None - """Enables human-in-the-loop planning for the Deep Research agent. - - If set to true, the Deep Research agent will provide a research plan in its - response. The agent will then proceed only if the user confirms the plan in the - next turn. - """ - - enable_bigquery_tool: Optional[bool] = None - """Enables bigquery tool for the Deep Research agent.""" - - thinking_summaries: Optional[Literal["auto", "none"]] = None - """Whether to include thought summaries in the response.""" - - visualization: Optional[Literal["off", "auto"]] = None - """Whether to include visualizations in the response.""" diff --git a/google/genai/_interactions/types/deep_research_agent_config_param.py b/google/genai/_interactions/types/deep_research_agent_config_param.py deleted file mode 100644 index a417a686c..000000000 --- a/google/genai/_interactions/types/deep_research_agent_config_param.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["DeepResearchAgentConfigParam"] - - -class DeepResearchAgentConfigParam(TypedDict, total=False): - """Configuration for the Deep Research agent.""" - - type: Required[Literal["deep-research"]] - - collaborative_planning: bool - """Enables human-in-the-loop planning for the Deep Research agent. - - If set to true, the Deep Research agent will provide a research plan in its - response. The agent will then proceed only if the user confirms the plan in the - next turn. - """ - - enable_bigquery_tool: bool - """Enables bigquery tool for the Deep Research agent.""" - - thinking_summaries: Literal["auto", "none"] - """Whether to include thought summaries in the response.""" - - visualization: Literal["off", "auto"] - """Whether to include visualizations in the response.""" diff --git a/google/genai/_interactions/types/document_content.py b/google/genai/_interactions/types/document_content.py deleted file mode 100644 index 5db8789ef..000000000 --- a/google/genai/_interactions/types/document_content.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["DocumentContent"] - - -class DocumentContent(BaseModel): - """A document content block.""" - - type: Literal["document"] - - data: Optional[str] = None - """The document content.""" - - mime_type: Optional[Literal["application/pdf", "text/csv"]] = None - """The mime type of the document.""" - - uri: Optional[str] = None - """The URI of the document.""" diff --git a/google/genai/_interactions/types/document_content_param.py b/google/genai/_interactions/types/document_content_param.py deleted file mode 100644 index ddbfce870..000000000 --- a/google/genai/_interactions/types/document_content_param.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["DocumentContentParam"] - - -class DocumentContentParam(TypedDict, total=False): - """A document content block.""" - - type: Required[Literal["document"]] - - data: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """The document content.""" - - mime_type: Literal["application/pdf", "text/csv"] - """The mime type of the document.""" - - uri: str - """The URI of the document.""" - - -set_pydantic_config(DocumentContentParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/dynamic_agent_config.py b/google/genai/_interactions/types/dynamic_agent_config.py deleted file mode 100644 index e217d9df9..000000000 --- a/google/genai/_interactions/types/dynamic_agent_config.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import TYPE_CHECKING, Dict -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["DynamicAgentConfig"] - - -class DynamicAgentConfig(BaseModel): - """Configuration for dynamic agents.""" - - type: Literal["dynamic"] - - if TYPE_CHECKING: - # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a - # value to this field, so for compatibility we avoid doing it at runtime. - __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] - - # Stub to indicate that arbitrary properties are accepted. - # To access properties that are not valid identifiers you can use `getattr`, e.g. - # `getattr(obj, '$type')` - def __getattr__(self, attr: str) -> object: ... - else: - __pydantic_extra__: Dict[str, object] diff --git a/google/genai/_interactions/types/dynamic_agent_config_param.py b/google/genai/_interactions/types/dynamic_agent_config_param.py deleted file mode 100644 index bc7844e22..000000000 --- a/google/genai/_interactions/types/dynamic_agent_config_param.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["DynamicAgentConfigParam"] - - -class DynamicAgentConfigParam(TypedDict, total=False, extra_items=object): # type: ignore[call-arg] - """Configuration for dynamic agents.""" - - type: Required[Literal["dynamic"]] diff --git a/google/genai/_interactions/types/environment.py b/google/genai/_interactions/types/environment.py deleted file mode 100644 index bbce59d9d..000000000 --- a/google/genai/_interactions/types/environment.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from .._models import BaseModel - -__all__ = ["Environment", "Network", "NetworkAllowlist", "NetworkAllowlistAllowlist", "Source"] - - -class NetworkAllowlistAllowlist(BaseModel): - """A single domain allowlist rule with optional header injection.""" - - domain: str - """Domain to allow outbound requests to. - - Supports wildcards (e.g. '_.googleapis.com'). Use '_' to allow all domains. - """ - - transform: Optional[List[Dict[str, str]]] = None - """Headers to inject on all outbound requests matching this domain. - - Each entry is a flat {header_name: header_value} object. The egress proxy - injects these automatically. - """ - - -class NetworkAllowlist(BaseModel): - """Outbound networking configuration for the sandbox. - - When specified, restricts which external domains the sandbox can reach. Omit entirely to allow all outbound traffic with no header injection. - """ - - allowlist: Optional[List[NetworkAllowlistAllowlist]] = None - """List of allowed outbound domains. - - Only requests to listed domains are permitted. Use [{'domain': '*'}] to allow - all domains while still injecting headers on specific ones. - """ - - -Network: TypeAlias = Union[Literal["disabled"], NetworkAllowlist] - - -class Source(BaseModel): - """A source to be mounted into the environment.""" - - content: Optional[str] = None - """The inline content if `type` is `INLINE`.""" - - encoding: Optional[str] = None - """Optional encoding for inline content (e.g. `base64`).""" - - source: Optional[str] = None - """ - The source of the environment. For GCS, this is the GCS path. For GitHub, this - is the GitHub path. - """ - - target: Optional[str] = None - """Where the source should appear in the environment.""" - - type: Optional[Literal["gcs", "inline", "repository", "skill_registry"]] = None - - -class Environment(BaseModel): - """Configuration for a custom environment.""" - - type: Literal["remote"] - - network: Optional[Network] = None - """Network configuration for the environment.""" - - sources: Optional[List[Source]] = None diff --git a/google/genai/_interactions/types/environment_param.py b/google/genai/_interactions/types/environment_param.py deleted file mode 100644 index 58d56e18d..000000000 --- a/google/genai/_interactions/types/environment_param.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -__all__ = ["EnvironmentParam", "Network", "NetworkAllowlist", "NetworkAllowlistAllowlist", "Source"] - - -class NetworkAllowlistAllowlist(TypedDict, total=False): - """A single domain allowlist rule with optional header injection.""" - - domain: Required[str] - """Domain to allow outbound requests to. - - Supports wildcards (e.g. '_.googleapis.com'). Use '_' to allow all domains. - """ - - transform: Iterable[Dict[str, str]] - """Headers to inject on all outbound requests matching this domain. - - Each entry is a flat {header_name: header_value} object. The egress proxy - injects these automatically. - """ - - -class NetworkAllowlist(TypedDict, total=False): - """Outbound networking configuration for the sandbox. - - When specified, restricts which external domains the sandbox can reach. Omit entirely to allow all outbound traffic with no header injection. - """ - - allowlist: Iterable[NetworkAllowlistAllowlist] - """List of allowed outbound domains. - - Only requests to listed domains are permitted. Use [{'domain': '*'}] to allow - all domains while still injecting headers on specific ones. - """ - - -Network: TypeAlias = Union[Literal["disabled"], NetworkAllowlist] - - -class Source(TypedDict, total=False): - """A source to be mounted into the environment.""" - - content: str - """The inline content if `type` is `INLINE`.""" - - encoding: str - """Optional encoding for inline content (e.g. `base64`).""" - - source: str - """ - The source of the environment. For GCS, this is the GCS path. For GitHub, this - is the GitHub path. - """ - - target: str - """Where the source should appear in the environment.""" - - type: Literal["gcs", "inline", "repository", "skill_registry"] - - -class EnvironmentParam(TypedDict, total=False): - """Configuration for a custom environment.""" - - type: Required[Literal["remote"]] - - network: Network - """Network configuration for the environment.""" - - sources: Iterable[Source] diff --git a/google/genai/_interactions/types/error_event.py b/google/genai/_interactions/types/error_event.py deleted file mode 100644 index 09d9d80ad..000000000 --- a/google/genai/_interactions/types/error_event.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .usage import Usage -from .._models import BaseModel - -__all__ = ["ErrorEvent", "Error", "Metadata"] - - -class Error(BaseModel): - """Error message from an interaction.""" - - code: Optional[str] = None - """A URI that identifies the error type.""" - - message: Optional[str] = None - """A human-readable error message.""" - - -class Metadata(BaseModel): - """Optional metadata accompanying ANY streamed event.""" - - total_usage: Optional[Usage] = None - """Statistics on the interaction request's token usage.""" - - -class ErrorEvent(BaseModel): - event_type: Literal["error"] - - error: Optional[Error] = None - """Error message from an interaction.""" - - event_id: Optional[str] = None - """ - The event_id token to be used to resume the interaction stream, from this event. - """ - - metadata: Optional[Metadata] = None - """Optional metadata accompanying ANY streamed event.""" diff --git a/google/genai/_interactions/types/file_citation.py b/google/genai/_interactions/types/file_citation.py deleted file mode 100644 index 5c06b04ca..000000000 --- a/google/genai/_interactions/types/file_citation.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["FileCitation"] - - -class FileCitation(BaseModel): - """A file citation annotation.""" - - type: Literal["file_citation"] - - custom_metadata: Optional[Dict[str, object]] = None - """User provided metadata about the retrieved context.""" - - document_uri: Optional[str] = None - """The URI of the file.""" - - end_index: Optional[int] = None - """End of the attributed segment, exclusive.""" - - file_name: Optional[str] = None - """The name of the file.""" - - media_id: Optional[str] = None - """Media ID in-case of image citations, if applicable.""" - - page_number: Optional[int] = None - """Page number of the cited document, if applicable.""" - - source: Optional[str] = None - """Source attributed for a portion of the text.""" - - start_index: Optional[int] = None - """Start of segment of the response that is attributed to this source. - - Index indicates the start of the segment, measured in bytes. - """ diff --git a/google/genai/_interactions/types/file_citation_param.py b/google/genai/_interactions/types/file_citation_param.py deleted file mode 100644 index 2f4b5667d..000000000 --- a/google/genai/_interactions/types/file_citation_param.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["FileCitationParam"] - - -class FileCitationParam(TypedDict, total=False): - """A file citation annotation.""" - - type: Required[Literal["file_citation"]] - - custom_metadata: Dict[str, object] - """User provided metadata about the retrieved context.""" - - document_uri: str - """The URI of the file.""" - - end_index: int - """End of the attributed segment, exclusive.""" - - file_name: str - """The name of the file.""" - - media_id: str - """Media ID in-case of image citations, if applicable.""" - - page_number: int - """Page number of the cited document, if applicable.""" - - source: str - """Source attributed for a portion of the text.""" - - start_index: int - """Start of segment of the response that is attributed to this source. - - Index indicates the start of the segment, measured in bytes. - """ diff --git a/google/genai/_interactions/types/file_search_call_step.py b/google/genai/_interactions/types/file_search_call_step.py deleted file mode 100644 index 478cf4cec..000000000 --- a/google/genai/_interactions/types/file_search_call_step.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["FileSearchCallStep"] - - -class FileSearchCallStep(BaseModel): - """File Search call step.""" - - id: str - """Required. A unique ID for this specific tool call.""" - - type: Literal["file_search_call"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/file_search_call_step_param.py b/google/genai/_interactions/types/file_search_call_step_param.py deleted file mode 100644 index 0eb378501..000000000 --- a/google/genai/_interactions/types/file_search_call_step_param.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["FileSearchCallStepParam"] - - -class FileSearchCallStepParam(TypedDict, total=False): - """File Search call step.""" - - id: Required[str] - """Required. A unique ID for this specific tool call.""" - - type: Required[Literal["file_search_call"]] - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(FileSearchCallStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/file_search_result_step.py b/google/genai/_interactions/types/file_search_result_step.py deleted file mode 100644 index e7331caa3..000000000 --- a/google/genai/_interactions/types/file_search_result_step.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["FileSearchResultStep"] - - -class FileSearchResultStep(BaseModel): - """File Search result step.""" - - call_id: str - """Required. ID to match the ID from the function call block.""" - - type: Literal["file_search_result"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/file_search_result_step_param.py b/google/genai/_interactions/types/file_search_result_step_param.py deleted file mode 100644 index e272ada54..000000000 --- a/google/genai/_interactions/types/file_search_result_step_param.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["FileSearchResultStepParam"] - - -class FileSearchResultStepParam(TypedDict, total=False): - """File Search result step.""" - - call_id: Required[str] - """Required. ID to match the ID from the function call block.""" - - type: Required[Literal["file_search_result"]] - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(FileSearchResultStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/function.py b/google/genai/_interactions/types/function.py deleted file mode 100644 index ce14b0414..000000000 --- a/google/genai/_interactions/types/function.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["Function"] - - -class Function(BaseModel): - """A tool that can be used by the model.""" - - type: Literal["function"] - - description: Optional[str] = None - """A description of the function.""" - - name: Optional[str] = None - """The name of the function.""" - - parameters: Optional[object] = None - """The JSON Schema for the function's parameters.""" diff --git a/google/genai/_interactions/types/function_call_step.py b/google/genai/_interactions/types/function_call_step.py deleted file mode 100644 index c0e33ee13..000000000 --- a/google/genai/_interactions/types/function_call_step.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["FunctionCallStep"] - - -class FunctionCallStep(BaseModel): - """A function tool call step.""" - - id: str - """Required. A unique ID for this specific tool call.""" - - arguments: Dict[str, object] - """Required. The arguments to pass to the function.""" - - name: str - """Required. The name of the tool to call.""" - - type: Literal["function_call"] diff --git a/google/genai/_interactions/types/function_call_step_param.py b/google/genai/_interactions/types/function_call_step_param.py deleted file mode 100644 index aa87ea45e..000000000 --- a/google/genai/_interactions/types/function_call_step_param.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["FunctionCallStepParam"] - - -class FunctionCallStepParam(TypedDict, total=False): - """A function tool call step.""" - - id: Required[str] - """Required. A unique ID for this specific tool call.""" - - arguments: Required[Dict[str, object]] - """Required. The arguments to pass to the function.""" - - name: Required[str] - """Required. The name of the tool to call.""" - - type: Required[Literal["function_call"]] diff --git a/google/genai/_interactions/types/function_param.py b/google/genai/_interactions/types/function_param.py deleted file mode 100644 index 32da748bd..000000000 --- a/google/genai/_interactions/types/function_param.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["FunctionParam"] - - -class FunctionParam(TypedDict, total=False): - """A tool that can be used by the model.""" - - type: Required[Literal["function"]] - - description: str - """A description of the function.""" - - name: str - """The name of the function.""" - - parameters: object - """The JSON Schema for the function's parameters.""" diff --git a/google/genai/_interactions/types/function_result_step.py b/google/genai/_interactions/types/function_result_step.py deleted file mode 100644 index ab2863653..000000000 --- a/google/genai/_interactions/types/function_result_step.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from .._utils import PropertyInfo -from .content import Content -from .._models import BaseModel -from .text_content import TextContent -from .image_content import ImageContent - -__all__ = ["FunctionResultStep", "ResultFunctionResultSubcontentList"] - -ResultFunctionResultSubcontentList: TypeAlias = Annotated[ - Union[TextContent, ImageContent], PropertyInfo(discriminator="type") -] - - -class FunctionResultStep(BaseModel): - """Result of a function tool call.""" - - call_id: str - """Required. ID to match the ID from the function call block.""" - - result: Union[List[Content], List[ResultFunctionResultSubcontentList], str] - """The result of the tool call.""" - - type: Literal["function_result"] - - is_error: Optional[bool] = None - """Whether the tool call resulted in an error.""" - - name: Optional[str] = None - """The name of the tool that was called.""" diff --git a/google/genai/_interactions/types/function_result_step_param.py b/google/genai/_interactions/types/function_result_step_param.py deleted file mode 100644 index 6e80a3b4e..000000000 --- a/google/genai/_interactions/types/function_result_step_param.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .content_param import ContentParam -from .text_content_param import TextContentParam -from .image_content_param import ImageContentParam - -__all__ = ["FunctionResultStepParam", "ResultFunctionResultSubcontentList"] - -ResultFunctionResultSubcontentList: TypeAlias = Union[TextContentParam, ImageContentParam] - - -class FunctionResultStepParam(TypedDict, total=False): - """Result of a function tool call.""" - - call_id: Required[str] - """Required. ID to match the ID from the function call block.""" - - result: Required[Union[Iterable[ContentParam], Iterable[ResultFunctionResultSubcontentList], str]] - """The result of the tool call.""" - - type: Required[Literal["function_result"]] - - is_error: bool - """Whether the tool call resulted in an error.""" - - name: str - """The name of the tool that was called.""" diff --git a/google/genai/_interactions/types/generation_config.py b/google/genai/_interactions/types/generation_config.py deleted file mode 100644 index 27c4fd011..000000000 --- a/google/genai/_interactions/types/generation_config.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from .._models import BaseModel -from .image_config import ImageConfig -from .speech_config import SpeechConfig -from .thinking_level import ThinkingLevel -from .tool_choice_type import ToolChoiceType -from .tool_choice_config import ToolChoiceConfig - -__all__ = ["GenerationConfig", "ToolChoice"] - -ToolChoice: TypeAlias = Union[ToolChoiceType, ToolChoiceConfig] - - -class GenerationConfig(BaseModel): - """Configuration parameters for model interactions.""" - - frequency_penalty: Optional[float] = None - """ - Penalizes tokens based on their frequency in the generated text. A positive - value helps to reduce the repetition of words and phrases. Valid values can - range from [-2.0, 2.0]. - """ - - image_config: Optional[ImageConfig] = None - """Configuration for image interaction.""" - - max_output_tokens: Optional[int] = None - """The maximum number of tokens to include in the response.""" - - presence_penalty: Optional[float] = None - """Penalizes tokens that have already appeared in the generated text. - - A positive value encourages the model to generate more diverse and less - repetitive text. Valid values can range from [-2.0, 2.0]. - """ - - seed: Optional[int] = None - """Seed used in decoding for reproducibility.""" - - speech_config: Optional[List[SpeechConfig]] = None - """Configuration for speech interaction.""" - - stop_sequences: Optional[List[str]] = None - """A list of character sequences that will stop output interaction.""" - - temperature: Optional[float] = None - """Controls the randomness of the output.""" - - thinking_level: Optional[ThinkingLevel] = None - """The level of thought tokens that the model should generate.""" - - thinking_summaries: Optional[Literal["auto", "none"]] = None - """Whether to include thought summaries in the response.""" - - tool_choice: Optional[ToolChoice] = None - """The tool choice configuration.""" - - top_p: Optional[float] = None - """The maximum cumulative probability of tokens to consider when sampling.""" diff --git a/google/genai/_interactions/types/generation_config_param.py b/google/genai/_interactions/types/generation_config_param.py deleted file mode 100644 index 754b188d8..000000000 --- a/google/genai/_interactions/types/generation_config_param.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, TypeAlias, TypedDict - -from .._types import SequenceNotStr -from .thinking_level import ThinkingLevel -from .tool_choice_type import ToolChoiceType -from .image_config_param import ImageConfigParam -from .speech_config_param import SpeechConfigParam -from .tool_choice_config_param import ToolChoiceConfigParam - -__all__ = ["GenerationConfigParam", "ToolChoice"] - -ToolChoice: TypeAlias = Union[ToolChoiceType, ToolChoiceConfigParam] - - -class GenerationConfigParam(TypedDict, total=False): - """Configuration parameters for model interactions.""" - - frequency_penalty: float - """ - Penalizes tokens based on their frequency in the generated text. A positive - value helps to reduce the repetition of words and phrases. Valid values can - range from [-2.0, 2.0]. - """ - - image_config: ImageConfigParam - """Configuration for image interaction.""" - - max_output_tokens: int - """The maximum number of tokens to include in the response.""" - - presence_penalty: float - """Penalizes tokens that have already appeared in the generated text. - - A positive value encourages the model to generate more diverse and less - repetitive text. Valid values can range from [-2.0, 2.0]. - """ - - seed: int - """Seed used in decoding for reproducibility.""" - - speech_config: Iterable[SpeechConfigParam] - """Configuration for speech interaction.""" - - stop_sequences: SequenceNotStr[str] - """A list of character sequences that will stop output interaction.""" - - temperature: float - """Controls the randomness of the output.""" - - thinking_level: ThinkingLevel - """The level of thought tokens that the model should generate.""" - - thinking_summaries: Literal["auto", "none"] - """Whether to include thought summaries in the response.""" - - tool_choice: ToolChoice - """The tool choice configuration.""" - - top_p: float - """The maximum cumulative probability of tokens to consider when sampling.""" diff --git a/google/genai/_interactions/types/google_maps_call_arguments.py b/google/genai/_interactions/types/google_maps_call_arguments.py deleted file mode 100644 index 3976e8779..000000000 --- a/google/genai/_interactions/types/google_maps_call_arguments.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .._models import BaseModel - -__all__ = ["GoogleMapsCallArguments"] - - -class GoogleMapsCallArguments(BaseModel): - """The arguments to pass to the Google Maps tool.""" - - queries: Optional[List[str]] = None - """The queries to be executed.""" diff --git a/google/genai/_interactions/types/google_maps_call_step.py b/google/genai/_interactions/types/google_maps_call_step.py deleted file mode 100644 index a0b095a0b..000000000 --- a/google/genai/_interactions/types/google_maps_call_step.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["GoogleMapsCallStep", "Arguments"] - - -class Arguments(BaseModel): - """The arguments to pass to the Google Maps tool.""" - - queries: Optional[List[str]] = None - """The queries to be executed.""" - - -class GoogleMapsCallStep(BaseModel): - """Google Maps call step.""" - - id: str - """Required. A unique ID for this specific tool call.""" - - type: Literal["google_maps_call"] - - arguments: Optional[Arguments] = None - """The arguments to pass to the Google Maps tool.""" - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/google_maps_call_step_param.py b/google/genai/_interactions/types/google_maps_call_step_param.py deleted file mode 100644 index 09280564c..000000000 --- a/google/genai/_interactions/types/google_maps_call_step_param.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import SequenceNotStr, Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["GoogleMapsCallStepParam", "Arguments"] - - -class Arguments(TypedDict, total=False): - """The arguments to pass to the Google Maps tool.""" - - queries: SequenceNotStr[str] - """The queries to be executed.""" - - -class GoogleMapsCallStepParam(TypedDict, total=False): - """Google Maps call step.""" - - id: Required[str] - """Required. A unique ID for this specific tool call.""" - - type: Required[Literal["google_maps_call"]] - - arguments: Arguments - """The arguments to pass to the Google Maps tool.""" - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(GoogleMapsCallStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/google_maps_result.py b/google/genai/_interactions/types/google_maps_result.py deleted file mode 100644 index bc2bc528b..000000000 --- a/google/genai/_interactions/types/google_maps_result.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .._models import BaseModel - -__all__ = ["GoogleMapsResult", "Place", "PlaceReviewSnippet"] - - -class PlaceReviewSnippet(BaseModel): - """ - Encapsulates a snippet of a user review that answers a question about - the features of a specific place in Google Maps. - """ - - review_id: Optional[str] = None - """The ID of the review snippet.""" - - title: Optional[str] = None - """Title of the review.""" - - url: Optional[str] = None - """A link that corresponds to the user review on Google Maps.""" - - -class Place(BaseModel): - name: Optional[str] = None - """Title of the place.""" - - place_id: Optional[str] = None - """The ID of the place, in `places/{place_id}` format.""" - - review_snippets: Optional[List[PlaceReviewSnippet]] = None - """ - Snippets of reviews that are used to generate answers about the features of a - given place in Google Maps. - """ - - url: Optional[str] = None - """URI reference of the place.""" - - -class GoogleMapsResult(BaseModel): - """The result of the Google Maps.""" - - places: Optional[List[Place]] = None - """The places that were found.""" - - widget_context_token: Optional[str] = None - """Resource name of the Google Maps widget context token.""" diff --git a/google/genai/_interactions/types/google_maps_result_step.py b/google/genai/_interactions/types/google_maps_result_step.py deleted file mode 100644 index 4d6427800..000000000 --- a/google/genai/_interactions/types/google_maps_result_step.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["GoogleMapsResultStep", "Result", "ResultPlace", "ResultPlaceReviewSnippet"] - - -class ResultPlaceReviewSnippet(BaseModel): - """ - Encapsulates a snippet of a user review that answers a question about - the features of a specific place in Google Maps. - """ - - review_id: Optional[str] = None - """The ID of the review snippet.""" - - title: Optional[str] = None - """Title of the review.""" - - url: Optional[str] = None - """A link that corresponds to the user review on Google Maps.""" - - -class ResultPlace(BaseModel): - name: Optional[str] = None - - place_id: Optional[str] = None - - review_snippets: Optional[List[ResultPlaceReviewSnippet]] = None - - url: Optional[str] = None - - -class Result(BaseModel): - """The result of the Google Maps.""" - - places: Optional[List[ResultPlace]] = None - - widget_context_token: Optional[str] = None - - -class GoogleMapsResultStep(BaseModel): - """Google Maps result step.""" - - call_id: str - """Required. ID to match the ID from the function call block.""" - - result: List[Result] - - type: Literal["google_maps_result"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/google_maps_result_step_param.py b/google/genai/_interactions/types/google_maps_result_step_param.py deleted file mode 100644 index 28016ea12..000000000 --- a/google/genai/_interactions/types/google_maps_result_step_param.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["GoogleMapsResultStepParam", "Result", "ResultPlace", "ResultPlaceReviewSnippet"] - - -class ResultPlaceReviewSnippet(TypedDict, total=False): - """ - Encapsulates a snippet of a user review that answers a question about - the features of a specific place in Google Maps. - """ - - review_id: str - """The ID of the review snippet.""" - - title: str - """Title of the review.""" - - url: str - """A link that corresponds to the user review on Google Maps.""" - - -class ResultPlace(TypedDict, total=False): - name: str - - place_id: str - - review_snippets: Iterable[ResultPlaceReviewSnippet] - - url: str - - -class Result(TypedDict, total=False): - """The result of the Google Maps.""" - - places: Iterable[ResultPlace] - - widget_context_token: str - - -class GoogleMapsResultStepParam(TypedDict, total=False): - """Google Maps result step.""" - - call_id: Required[str] - """Required. ID to match the ID from the function call block.""" - - result: Required[Iterable[Result]] - - type: Required[Literal["google_maps_result"]] - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(GoogleMapsResultStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/google_search_call_arguments.py b/google/genai/_interactions/types/google_search_call_arguments.py deleted file mode 100644 index 9d93e71f2..000000000 --- a/google/genai/_interactions/types/google_search_call_arguments.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .._models import BaseModel - -__all__ = ["GoogleSearchCallArguments"] - - -class GoogleSearchCallArguments(BaseModel): - """The arguments to pass to Google Search.""" - - queries: Optional[List[str]] = None - """Web search queries for the following-up web search.""" diff --git a/google/genai/_interactions/types/google_search_call_step.py b/google/genai/_interactions/types/google_search_call_step.py deleted file mode 100644 index c36abfbcf..000000000 --- a/google/genai/_interactions/types/google_search_call_step.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["GoogleSearchCallStep", "Arguments"] - - -class Arguments(BaseModel): - """Required. The arguments to pass to Google Search.""" - - queries: Optional[List[str]] = None - """Web search queries for the following-up web search.""" - - -class GoogleSearchCallStep(BaseModel): - """Google Search call step.""" - - id: str - """Required. A unique ID for this specific tool call.""" - - arguments: Arguments - """Required. The arguments to pass to Google Search.""" - - type: Literal["google_search_call"] - - search_type: Optional[Literal["web_search", "image_search", "enterprise_web_search"]] = None - """The type of search grounding enabled.""" - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/google_search_call_step_param.py b/google/genai/_interactions/types/google_search_call_step_param.py deleted file mode 100644 index c1f42b364..000000000 --- a/google/genai/_interactions/types/google_search_call_step_param.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import SequenceNotStr, Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["GoogleSearchCallStepParam", "Arguments"] - - -class Arguments(TypedDict, total=False): - """Required. The arguments to pass to Google Search.""" - - queries: SequenceNotStr[str] - """Web search queries for the following-up web search.""" - - -class GoogleSearchCallStepParam(TypedDict, total=False): - """Google Search call step.""" - - id: Required[str] - """Required. A unique ID for this specific tool call.""" - - arguments: Required[Arguments] - """Required. The arguments to pass to Google Search.""" - - type: Required[Literal["google_search_call"]] - - search_type: Literal["web_search", "image_search", "enterprise_web_search"] - """The type of search grounding enabled.""" - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(GoogleSearchCallStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/google_search_result.py b/google/genai/_interactions/types/google_search_result.py deleted file mode 100644 index 9691f5d40..000000000 --- a/google/genai/_interactions/types/google_search_result.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["GoogleSearchResult"] - - -class GoogleSearchResult(BaseModel): - """The result of the Google Search.""" - - search_suggestions: Optional[str] = None - """Web content snippet that can be embedded in a web page or an app webview.""" diff --git a/google/genai/_interactions/types/google_search_result_step.py b/google/genai/_interactions/types/google_search_result_step.py deleted file mode 100644 index 976b6cea1..000000000 --- a/google/genai/_interactions/types/google_search_result_step.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["GoogleSearchResultStep", "Result"] - - -class Result(BaseModel): - """The result of the Google Search.""" - - search_suggestions: Optional[str] = None - """Web content snippet that can be embedded in a web page or an app webview.""" - - -class GoogleSearchResultStep(BaseModel): - """Google Search result step.""" - - call_id: str - """Required. ID to match the ID from the function call block.""" - - result: List[Result] - """Required. The results of the Google Search.""" - - type: Literal["google_search_result"] - - is_error: Optional[bool] = None - """Whether the Google Search resulted in an error.""" - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/google_search_result_step_param.py b/google/genai/_interactions/types/google_search_result_step_param.py deleted file mode 100644 index 160d87f96..000000000 --- a/google/genai/_interactions/types/google_search_result_step_param.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["GoogleSearchResultStepParam", "Result"] - - -class Result(TypedDict, total=False): - """The result of the Google Search.""" - - search_suggestions: str - """Web content snippet that can be embedded in a web page or an app webview.""" - - -class GoogleSearchResultStepParam(TypedDict, total=False): - """Google Search result step.""" - - call_id: Required[str] - """Required. ID to match the ID from the function call block.""" - - result: Required[Iterable[Result]] - """Required. The results of the Google Search.""" - - type: Required[Literal["google_search_result"]] - - is_error: bool - """Whether the Google Search resulted in an error.""" - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(GoogleSearchResultStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/image_config.py b/google/genai/_interactions/types/image_config.py deleted file mode 100644 index a0d35b37a..000000000 --- a/google/genai/_interactions/types/image_config.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ImageConfig"] - - -class ImageConfig(BaseModel): - """The configuration for image interaction.""" - - aspect_ratio: Optional[ - Literal["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9", "1:8", "8:1", "1:4", "4:1"] - ] = None - - image_size: Optional[Literal["1K", "2K", "4K", "512"]] = None diff --git a/google/genai/_interactions/types/image_config_param.py b/google/genai/_interactions/types/image_config_param.py deleted file mode 100644 index d88dad869..000000000 --- a/google/genai/_interactions/types/image_config_param.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["ImageConfigParam"] - - -class ImageConfigParam(TypedDict, total=False): - """The configuration for image interaction.""" - - aspect_ratio: Literal[ - "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9", "1:8", "8:1", "1:4", "4:1" - ] - - image_size: Literal["1K", "2K", "4K", "512"] diff --git a/google/genai/_interactions/types/image_content.py b/google/genai/_interactions/types/image_content.py deleted file mode 100644 index c0c90ed63..000000000 --- a/google/genai/_interactions/types/image_content.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ImageContent"] - - -class ImageContent(BaseModel): - """An image content block.""" - - type: Literal["image"] - - data: Optional[str] = None - """The image content.""" - - mime_type: Optional[ - Literal[ - "image/png", "image/jpeg", "image/webp", "image/heic", "image/heif", "image/gif", "image/bmp", "image/tiff" - ] - ] = None - """The mime type of the image.""" - - resolution: Optional[Literal["low", "medium", "high", "ultra_high"]] = None - """The resolution of the media.""" - - uri: Optional[str] = None - """The URI of the image.""" diff --git a/google/genai/_interactions/types/image_content_param.py b/google/genai/_interactions/types/image_content_param.py deleted file mode 100644 index 7fd5456b2..000000000 --- a/google/genai/_interactions/types/image_content_param.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["ImageContentParam"] - - -class ImageContentParam(TypedDict, total=False): - """An image content block.""" - - type: Required[Literal["image"]] - - data: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """The image content.""" - - mime_type: Literal[ - "image/png", "image/jpeg", "image/webp", "image/heic", "image/heif", "image/gif", "image/bmp", "image/tiff" - ] - """The mime type of the image.""" - - resolution: Literal["low", "medium", "high", "ultra_high"] - """The resolution of the media.""" - - uri: str - """The URI of the image.""" - - -set_pydantic_config(ImageContentParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/image_response_format.py b/google/genai/_interactions/types/image_response_format.py deleted file mode 100644 index 27ce056fd..000000000 --- a/google/genai/_interactions/types/image_response_format.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["ImageResponseFormat"] - - -class ImageResponseFormat(BaseModel): - """Configuration for image output format.""" - - type: Literal["image"] - - aspect_ratio: Optional[ - Literal["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9", "1:8", "8:1", "1:4", "4:1"] - ] = None - """The aspect ratio for the image output.""" - - delivery: Optional[Literal["inline", "uri"]] = None - """The delivery mode for the image output.""" - - image_size: Optional[Literal["512", "1K", "2K", "4K"]] = None - """The size of the image output.""" - - mime_type: Optional[Literal["image/jpeg"]] = None - """The MIME type of the image output.""" diff --git a/google/genai/_interactions/types/image_response_format_param.py b/google/genai/_interactions/types/image_response_format_param.py deleted file mode 100644 index 149b6b582..000000000 --- a/google/genai/_interactions/types/image_response_format_param.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["ImageResponseFormatParam"] - - -class ImageResponseFormatParam(TypedDict, total=False): - """Configuration for image output format.""" - - type: Required[Literal["image"]] - - aspect_ratio: Literal[ - "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9", "1:8", "8:1", "1:4", "4:1" - ] - """The aspect ratio for the image output.""" - - delivery: Literal["inline", "uri"] - """The delivery mode for the image output.""" - - image_size: Literal["512", "1K", "2K", "4K"] - """The size of the image output.""" - - mime_type: Literal["image/jpeg"] - """The MIME type of the image output.""" diff --git a/google/genai/_interactions/types/interaction.py b/google/genai/_interactions/types/interaction.py deleted file mode 100644 index 725d88e72..000000000 --- a/google/genai/_interactions/types/interaction.py +++ /dev/null @@ -1,476 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import TYPE_CHECKING, Any, Set, Dict, List, Tuple, Union, Optional, cast -from datetime import datetime -from typing_extensions import Literal, TypeAlias, override - -from . import environment -from .step import Step -from .tool import Tool -from .model import Model -from .usage import Usage -from .content import Content -from .._compat import PYDANTIC_V1 -from .._models import BaseModel -from .text_content import TextContent -from .audio_content import AudioContent -from .image_content import ImageContent -from .video_content import VideoContent -from .._legacy_lyria import is_legacy_lyria_response_body -from .webhook_config import WebhookConfig -from .user_input_step import UserInputStep -from .document_content import DocumentContent -from .model_output_step import ModelOutputStep -from .dynamic_agent_config import DynamicAgentConfig -from .text_response_format import TextResponseFormat -from .audio_response_format import AudioResponseFormat -from .image_response_format import ImageResponseFormat -from .deep_research_agent_config import DeepResearchAgentConfig - -__all__ = [ - "Interaction", - "AgentConfig", - "AgentConfigFindRequest", - "AgentConfigFindRequestSessionConfig", - "AgentConfigFindRequestSourceFile", - "AgentConfigFixRequest", - "AgentConfigFixRequestSessionConfig", - "AgentConfigFixRequestSourceFile", - "Environment", - "Input", - "ResponseFormat", - "ResponseFormatResponseFormatList", -] - - -class AgentConfigFindRequestSessionConfig(BaseModel): - """ - Optional session-specific configurations to override default agent - behavior. - """ - - max_rounds: Optional[int] = None - """ - The maximum number of interaction rounds the agent is allowed to perform before - reaching a timeout. - """ - - pipeline_mode: Optional[Literal["scan", "verify"]] = None - """The pipeline mode of a CodeMender session. - - It can only be used for a find session. - """ - - topology: Optional[str] = None - """The cognitive architecture or "thinking" topology used by the agent (e.g. - - "default", "deep"). - """ - - -class AgentConfigFindRequestSourceFile(BaseModel): - """Content of a single file in the codebase.""" - - content: Optional[str] = None - """The UTF-8 encoded text content of the file.""" - - path: Optional[str] = None - """The relative path of the file from the project root.""" - - -class AgentConfigFindRequest(BaseModel): - """ - Request parameters specific to FIND sessions, used for discovering - vulnerabilities in a codebase. - """ - - request: Literal["find_request"] - - description: Optional[str] = None - """ - Additional context or custom instructions provided by the user to guide the - vulnerability analysis. - """ - - finding_id: Optional[str] = None - """The identifier of a specific finding to verify. - - This is primarily used in VERIFY mode to focus the agent's execution-based - validation on a single vulnerability. - """ - - model: Optional[str] = None - """The name of the model to use for the CodeMender agent. - - One CodeMender session will only use one model. - """ - - session_config: Optional[AgentConfigFindRequestSessionConfig] = None - """Optional session-specific configurations to override default agent behavior.""" - - session_id: Optional[str] = None - """ - Parameter for grouping multiple interactions that belong to the same CodeMender - session. - """ - - source_files: Optional[List[AgentConfigFindRequestSourceFile]] = None - """A list of source files to provide as context for the scan.""" - - -class AgentConfigFixRequestSessionConfig(BaseModel): - """ - Optional session-specific configurations to override default agent - behavior. - """ - - max_rounds: Optional[int] = None - """ - The maximum number of interaction rounds the agent is allowed to perform before - reaching a timeout. - """ - - pipeline_mode: Optional[Literal["scan", "verify"]] = None - """The pipeline mode of a CodeMender session. - - It can only be used for a find session. - """ - - topology: Optional[str] = None - """The cognitive architecture or "thinking" topology used by the agent (e.g. - - "default", "deep"). - """ - - -class AgentConfigFixRequestSourceFile(BaseModel): - """Content of a single file in the codebase.""" - - content: Optional[str] = None - """The UTF-8 encoded text content of the file.""" - - path: Optional[str] = None - """The relative path of the file from the project root.""" - - -class AgentConfigFixRequest(BaseModel): - """ - Request parameters specific to FIX sessions, used for generating and - validating security patches. - """ - - request: Literal["fix_request"] - - description: Optional[str] = None - """ - Additional context or custom instructions provided by the user to guide the - patch generation process. - """ - - finding_id: Optional[str] = None - """The identifier of the specific security finding to be remediated. - - This ID maps to a previously discovered vulnerability. - """ - - model: Optional[str] = None - """The name of the model to use for the CodeMender agent. - - One CodeMender session will only use one model. - """ - - session_config: Optional[AgentConfigFixRequestSessionConfig] = None - """Optional session-specific configurations to override default agent behavior.""" - - session_id: Optional[str] = None - """ - Parameter for grouping multiple interactions that belong to the same CodeMender - session. - """ - - source_files: Optional[List[AgentConfigFixRequestSourceFile]] = None - """A list of source files providing context for the remediation. - - These files are typically the ones containing the identified vulnerability. - """ - - -AgentConfig: TypeAlias = Union[ - DeepResearchAgentConfig, DynamicAgentConfig, AgentConfigFindRequest, AgentConfigFixRequest -] - -Environment: TypeAlias = Union[str, environment.Environment] - -Input: TypeAlias = Union[ - str, List[Step], List[Content], TextContent, ImageContent, AudioContent, DocumentContent, VideoContent -] - -ResponseFormatResponseFormatList: TypeAlias = Union[ - AudioResponseFormat, TextResponseFormat, ImageResponseFormat, object -] - -ResponseFormat: TypeAlias = Union[ - List[ResponseFormatResponseFormatList], AudioResponseFormat, TextResponseFormat, ImageResponseFormat, object -] - - -class Interaction(BaseModel): - """The Interaction resource.""" - - id: str - """Required. Output only. A unique identifier for the interaction completion.""" - - created: datetime - """Required. - - Output only. The time at which the response was created in ISO 8601 format - (YYYY-MM-DDThh:mm:ssZ). - """ - - status: Literal[ - "in_progress", "requires_action", "completed", "failed", "cancelled", "incomplete", "budget_exceeded" - ] - """Required. Output only. The status of the interaction.""" - - steps: List[Step] - """Required. Output only. The steps that make up the interaction.""" - - updated: datetime - """Required. - - Output only. The time at which the response was last updated in ISO 8601 format - (YYYY-MM-DDThh:mm:ssZ). - """ - - agent: Union[ - Literal[ - "deep-research-pro-preview-12-2025", - "deep-research-preview-04-2026", - "deep-research-max-preview-04-2026", - "antigravity-preview-05-2026", - ], - str, - None, - ] = None - """The name of the `Agent` used for generating the interaction.""" - - agent_config: Optional[AgentConfig] = None - """Configuration parameters for the agent interaction.""" - - cached_content: Optional[str] = None - """ - The name of the cached content used as context to serve the prediction. Note: - only used in explicit caching, where users can have control over caching (e.g. - what content to cache) and enjoy guaranteed cost savings. Format: - `projects/{project}/locations/{location}/cachedContents/{cachedContent}` - """ - - environment: Optional[Environment] = None - """The environment configuration for the interaction. - - Can be an object specifying remote environment sources or a string referencing - an existing environment ID. - """ - - environment_id: Optional[str] = None - """Output only. - - The environment ID for the interaction. Only populated if environment config is - set in the request. - """ - - input: Optional[Input] = None - """The input for the interaction.""" - - model: Optional[Model] = None - """The name of the `Model` used for generating the interaction.""" - - previous_interaction_id: Optional[str] = None - """The ID of the previous interaction, if any.""" - - response_format: Optional[ResponseFormat] = None - """ - Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - """ - - response_mime_type: Optional[str] = None - """The mime type of the response. This is required if response_format is set.""" - - response_modalities: Optional[List[Literal["text", "image", "audio", "video", "document"]]] = None - """The requested modalities of the response (TEXT, IMAGE, AUDIO).""" - - role: Optional[str] = None - """Output only. The role of the interaction.""" - - service_tier: Optional[Literal["flex", "standard", "priority"]] = None - """The service tier for the interaction.""" - - system_instruction: Optional[str] = None - """System instruction for the interaction.""" - - tools: Optional[List[Tool]] = None - """A list of tool declarations the model may call during interaction.""" - - usage: Optional[Usage] = None - """Output only. Statistics on the interaction request's token usage.""" - - webhook_config: Optional[WebhookConfig] = None - """Optional. - - Webhook configuration for receiving notifications when the interaction - completes. - """ - - @classmethod - def _maybe_coerce_outputs(cls, data: Any) -> Tuple[Any, bool]: - """Rewrite legacy vertex `outputs` payloads into the modern `steps` shape. - - Returns `(data, did_rewrite)` so callers (notably the `construct` - override below) can react to whether the rewrite actually fired - without relying on object identity. - - Triggers only when the response body identifies itself as a legacy- - lyria payload via its top-level `model` field. The model field is - present on every Interaction body produced by `create()`, `get()`, - and any deferred parse via `with_raw_response.parse()`, including - the nested `interaction` bodies inside `interaction.created` / - `interaction.completed` SSE events. - - Skips the rewrite if `outputs` isn't a list (e.g. server emits an - explicit `null`) so the divergence surfaces in `__pydantic_extra__` - instead of being silently coerced into an empty step. - - On rewrite, the original `outputs` field is popped so it doesn't - land on the parsed model as a redundant extra. - """ - if not isinstance(data, dict): - return data, False - typed_data: Dict[str, Any] = cast("Dict[str, Any]", data) - if not is_legacy_lyria_response_body(typed_data): - return typed_data, False - if "outputs" not in typed_data or "steps" in typed_data: - return typed_data, False - outputs = typed_data["outputs"] - if not isinstance(outputs, list): - return typed_data, False - - new_data: Dict[str, Any] = {**typed_data} - new_data.pop("outputs") - new_data["steps"] = [{"type": "model_output", "content": outputs}] - return new_data, True - - @classmethod - @override - def construct( # pyright: ignore[reportIncompatibleMethodOverride] - cls, - _fields_set: Optional[Set[str]] = None, - **values: Any, - ) -> "Interaction": - coerced, rewrote = cls._maybe_coerce_outputs(values) - # If we rewrote `outputs` -> `steps` and the caller passed an explicit - # _fields_set including `outputs`, swap the field name so - # `model_dump(exclude_unset=True)` and friends report `steps` as set - # rather than the field that no longer exists on the model. - if rewrote and _fields_set is not None and "outputs" in _fields_set: - _fields_set = (set(_fields_set) - {"outputs"}) | {"steps"} - return super().construct(_fields_set=_fields_set, **coerced) # type: ignore[return-value] - - if not TYPE_CHECKING: - model_construct = construct - - if PYDANTIC_V1: - from pydantic import root_validator - - @root_validator(pre=True) - def _coerce_outputs_to_steps(cls, values: Any) -> Any: - coerced, _ = cls._maybe_coerce_outputs(values) - return coerced - else: - from pydantic import model_validator - - @model_validator(mode="before") - @classmethod - def _coerce_outputs_to_steps(cls, data: Any) -> Any: - coerced, _ = cls._maybe_coerce_outputs(data) - return coerced - - @property - def output_text(self) -> str: - """The last consecutive run of text from the trailing model output steps. - - Scans backwards through the steps (stopping at any UserInputStep) and - skips non-text content until the first text item is found, then - continues collecting text until a non-text item is encountered. - Returns an empty string when no text content is present. - """ - parts: List[str] = [] - collecting = False - for step in reversed(self.steps or []): - if isinstance(step, UserInputStep): - break - if not isinstance(step, ModelOutputStep) or not step.content: - if collecting: - break - continue - for content in reversed(step.content): - if isinstance(content, TextContent): - collecting = True - parts.append(content.text) - elif collecting: - # Hit a non-text barrier after we started collecting. - parts.reverse() - return "".join(parts) - parts.reverse() - return "".join(parts) - - @property - def output_image(self) -> Optional[ImageContent]: - """The last image generated by the model in response to the current request.""" - for step in reversed(self.steps): - if isinstance(step, UserInputStep): - break - if isinstance(step, ModelOutputStep) and step.content: - for content in reversed(step.content): - if isinstance(content, ImageContent): - return content - return None - - @property - def output_audio(self) -> Optional[AudioContent]: - """The last audio generated by the model in response to the current request.""" - for step in reversed(self.steps): - if isinstance(step, UserInputStep): - break - if isinstance(step, ModelOutputStep) and step.content: - for content in reversed(step.content): - if isinstance(content, AudioContent): - return content - return None - - @property - def output_video(self) -> Optional[VideoContent]: - """The last video generated by the model in response to the current request.""" - for step in reversed(self.steps): - if isinstance(step, UserInputStep): - break - if isinstance(step, ModelOutputStep) and step.content: - for content in reversed(step.content): - if isinstance(content, VideoContent): - return content - return None diff --git a/google/genai/_interactions/types/interaction_completed_event.py b/google/genai/_interactions/types/interaction_completed_event.py deleted file mode 100644 index d6d9c8a9b..000000000 --- a/google/genai/_interactions/types/interaction_completed_event.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .usage import Usage -from .._models import BaseModel -from .interaction import Interaction - -__all__ = ["InteractionCompletedEvent", "Metadata"] - - -class Metadata(BaseModel): - """Optional metadata accompanying ANY streamed event.""" - - total_usage: Optional[Usage] = None - """Statistics on the interaction request's token usage.""" - - -class InteractionCompletedEvent(BaseModel): - event_type: Literal["interaction.completed"] - - interaction: Interaction - """Required. - - The completed interaction with empty outputs to reduce the payload size. Use the - preceding ContentDelta events for the actual output. - """ - - event_id: Optional[str] = None - """ - The event_id token to be used to resume the interaction stream, from this event. - """ - - metadata: Optional[Metadata] = None - """Optional metadata accompanying ANY streamed event.""" diff --git a/google/genai/_interactions/types/interaction_create_params.py b/google/genai/_interactions/types/interaction_create_params.py deleted file mode 100644 index c82396355..000000000 --- a/google/genai/_interactions/types/interaction_create_params.py +++ /dev/null @@ -1,402 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .step_param import StepParam -from .tool_param import ToolParam -from .model_param import ModelParam -from .content_param import ContentParam -from .environment_param import EnvironmentParam -from .text_content_param import TextContentParam -from .audio_content_param import AudioContentParam -from .image_content_param import ImageContentParam -from .video_content_param import VideoContentParam -from .webhook_config_param import WebhookConfigParam -from .document_content_param import DocumentContentParam -from .generation_config_param import GenerationConfigParam -from .dynamic_agent_config_param import DynamicAgentConfigParam -from .text_response_format_param import TextResponseFormatParam -from .audio_response_format_param import AudioResponseFormatParam -from .image_response_format_param import ImageResponseFormatParam -from .deep_research_agent_config_param import DeepResearchAgentConfigParam - -__all__ = [ - "BaseCreateModelInteractionParams", - "Input", - "Environment", - "ResponseFormat", - "ResponseFormatResponseFormatList", - "BaseCreateAgentInteractionParams", - "AgentConfig", - "AgentConfigFindRequest", - "AgentConfigFindRequestSessionConfig", - "AgentConfigFindRequestSourceFile", - "AgentConfigFixRequest", - "AgentConfigFixRequestSessionConfig", - "AgentConfigFixRequestSourceFile", - "CreateModelInteractionParamsNonStreaming", - "CreateModelInteractionParamsStreaming", - "CreateAgentInteractionParamsNonStreaming", - "CreateAgentInteractionParamsStreaming", -] - - -class BaseCreateModelInteractionParams(TypedDict, total=False): - api_version: str - - input: Required[Input] - """The input for the interaction.""" - - model: Required[ModelParam] - """The name of the `Model` used for generating the interaction.""" - - background: bool - """Input only. Whether to run the model interaction in the background.""" - - cached_content: str - """ - The name of the cached content used as context to serve the prediction. Note: - only used in explicit caching, where users can have control over caching (e.g. - what content to cache) and enjoy guaranteed cost savings. Format: - `projects/{project}/locations/{location}/cachedContents/{cachedContent}` - """ - - environment: Environment - """The environment configuration for the interaction. - - Can be an object specifying remote environment sources or a string referencing - an existing environment ID. - """ - - generation_config: GenerationConfigParam - """Input only. Configuration parameters for the model interaction.""" - - previous_interaction_id: str - """The ID of the previous interaction, if any.""" - - response_format: ResponseFormat - """ - Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - """ - - response_mime_type: str - """The mime type of the response. This is required if response_format is set.""" - - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] - """The requested modalities of the response (TEXT, IMAGE, AUDIO).""" - - service_tier: Literal["flex", "standard", "priority"] - """The service tier for the interaction.""" - - store: bool - """Input only. Whether to store the response and request for later retrieval.""" - - system_instruction: str - """System instruction for the interaction.""" - - tools: Iterable[ToolParam] - """A list of tool declarations the model may call during interaction.""" - - webhook_config: WebhookConfigParam - """Optional. - - Webhook configuration for receiving notifications when the interaction - completes. - """ - - -Input: TypeAlias = Union[ - str, - Iterable[StepParam], - Iterable[ContentParam], - TextContentParam, - ImageContentParam, - AudioContentParam, - DocumentContentParam, - VideoContentParam, -] - -Environment: TypeAlias = Union[str, EnvironmentParam] - -ResponseFormatResponseFormatList: TypeAlias = Union[ - AudioResponseFormatParam, TextResponseFormatParam, ImageResponseFormatParam, object -] - -ResponseFormat: TypeAlias = Union[ - Iterable[ResponseFormatResponseFormatList], - AudioResponseFormatParam, - TextResponseFormatParam, - ImageResponseFormatParam, - object, -] - - -class BaseCreateAgentInteractionParams(TypedDict, total=False): - api_version: str - - agent: Required[ - Union[ - Literal[ - "deep-research-pro-preview-12-2025", - "deep-research-preview-04-2026", - "deep-research-max-preview-04-2026", - "antigravity-preview-05-2026", - ], - str, - ] - ] - """The name of the `Agent` used for generating the interaction.""" - - input: Required[Input] - """The input for the interaction.""" - - agent_config: AgentConfig - """Configuration parameters for the agent interaction.""" - - background: bool - """Input only. Whether to run the model interaction in the background.""" - - environment: Environment - """The environment configuration for the interaction. - - Can be an object specifying remote environment sources or a string referencing - an existing environment ID. - """ - - previous_interaction_id: str - """The ID of the previous interaction, if any.""" - - response_format: ResponseFormat - """ - Enforces that the generated response is a JSON object that complies with the - JSON schema specified in this field. - """ - - response_mime_type: str - """The mime type of the response. This is required if response_format is set.""" - - response_modalities: List[Literal["text", "image", "audio", "video", "document"]] - """The requested modalities of the response (TEXT, IMAGE, AUDIO).""" - - service_tier: Literal["flex", "standard", "priority"] - """The service tier for the interaction.""" - - store: bool - """Input only. Whether to store the response and request for later retrieval.""" - - system_instruction: str - """System instruction for the interaction.""" - - tools: Iterable[ToolParam] - """A list of tool declarations the model may call during interaction.""" - - webhook_config: WebhookConfigParam - """Optional. - - Webhook configuration for receiving notifications when the interaction - completes. - """ - - -class AgentConfigFindRequestSessionConfig(TypedDict, total=False): - """ - Optional session-specific configurations to override default agent - behavior. - """ - - max_rounds: int - """ - The maximum number of interaction rounds the agent is allowed to perform before - reaching a timeout. - """ - - pipeline_mode: Literal["scan", "verify"] - """The pipeline mode of a CodeMender session. - - It can only be used for a find session. - """ - - topology: str - """The cognitive architecture or "thinking" topology used by the agent (e.g. - - "default", "deep"). - """ - - -class AgentConfigFindRequestSourceFile(TypedDict, total=False): - """Content of a single file in the codebase.""" - - content: str - """The UTF-8 encoded text content of the file.""" - - path: str - """The relative path of the file from the project root.""" - - -class AgentConfigFindRequest(TypedDict, total=False): - """ - Request parameters specific to FIND sessions, used for discovering - vulnerabilities in a codebase. - """ - - request: Required[Literal["find_request"]] - - description: str - """ - Additional context or custom instructions provided by the user to guide the - vulnerability analysis. - """ - - finding_id: str - """The identifier of a specific finding to verify. - - This is primarily used in VERIFY mode to focus the agent's execution-based - validation on a single vulnerability. - """ - - model: str - """The name of the model to use for the CodeMender agent. - - One CodeMender session will only use one model. - """ - - session_config: AgentConfigFindRequestSessionConfig - """Optional session-specific configurations to override default agent behavior.""" - - session_id: str - """ - Parameter for grouping multiple interactions that belong to the same CodeMender - session. - """ - - source_files: Iterable[AgentConfigFindRequestSourceFile] - """A list of source files to provide as context for the scan.""" - - -class AgentConfigFixRequestSessionConfig(TypedDict, total=False): - """ - Optional session-specific configurations to override default agent - behavior. - """ - - max_rounds: int - """ - The maximum number of interaction rounds the agent is allowed to perform before - reaching a timeout. - """ - - pipeline_mode: Literal["scan", "verify"] - """The pipeline mode of a CodeMender session. - - It can only be used for a find session. - """ - - topology: str - """The cognitive architecture or "thinking" topology used by the agent (e.g. - - "default", "deep"). - """ - - -class AgentConfigFixRequestSourceFile(TypedDict, total=False): - """Content of a single file in the codebase.""" - - content: str - """The UTF-8 encoded text content of the file.""" - - path: str - """The relative path of the file from the project root.""" - - -class AgentConfigFixRequest(TypedDict, total=False): - """ - Request parameters specific to FIX sessions, used for generating and - validating security patches. - """ - - request: Required[Literal["fix_request"]] - - description: str - """ - Additional context or custom instructions provided by the user to guide the - patch generation process. - """ - - finding_id: str - """The identifier of the specific security finding to be remediated. - - This ID maps to a previously discovered vulnerability. - """ - - model: str - """The name of the model to use for the CodeMender agent. - - One CodeMender session will only use one model. - """ - - session_config: AgentConfigFixRequestSessionConfig - """Optional session-specific configurations to override default agent behavior.""" - - session_id: str - """ - Parameter for grouping multiple interactions that belong to the same CodeMender - session. - """ - - source_files: Iterable[AgentConfigFixRequestSourceFile] - """A list of source files providing context for the remediation. - - These files are typically the ones containing the identified vulnerability. - """ - - -AgentConfig: TypeAlias = Union[ - DeepResearchAgentConfigParam, DynamicAgentConfigParam, AgentConfigFindRequest, AgentConfigFixRequest -] - - -class CreateModelInteractionParamsNonStreaming(BaseCreateModelInteractionParams, total=False): - stream: Literal[False] - """Input only. Whether the interaction will be streamed.""" - - -class CreateModelInteractionParamsStreaming(BaseCreateModelInteractionParams): - stream: Required[Literal[True]] - """Input only. Whether the interaction will be streamed.""" - - -class CreateAgentInteractionParamsNonStreaming(BaseCreateAgentInteractionParams, total=False): - stream: Literal[False] - """Input only. Whether the interaction will be streamed.""" - - -class CreateAgentInteractionParamsStreaming(BaseCreateAgentInteractionParams): - stream: Required[Literal[True]] - """Input only. Whether the interaction will be streamed.""" - - -InteractionCreateParams = Union[ - CreateModelInteractionParamsNonStreaming, - CreateModelInteractionParamsStreaming, - CreateAgentInteractionParamsNonStreaming, - CreateAgentInteractionParamsStreaming, -] diff --git a/google/genai/_interactions/types/interaction_created_event.py b/google/genai/_interactions/types/interaction_created_event.py deleted file mode 100644 index 3403bf6ae..000000000 --- a/google/genai/_interactions/types/interaction_created_event.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .usage import Usage -from .._models import BaseModel -from .interaction import Interaction - -__all__ = ["InteractionCreatedEvent", "Metadata"] - - -class Metadata(BaseModel): - """Optional metadata accompanying ANY streamed event.""" - - total_usage: Optional[Usage] = None - """Statistics on the interaction request's token usage.""" - - -class InteractionCreatedEvent(BaseModel): - event_type: Literal["interaction.created"] - - interaction: Interaction - """The Interaction resource.""" - - event_id: Optional[str] = None - """ - The event_id token to be used to resume the interaction stream, from this event. - """ - - metadata: Optional[Metadata] = None - """Optional metadata accompanying ANY streamed event.""" diff --git a/google/genai/_interactions/types/interaction_get_params.py b/google/genai/_interactions/types/interaction_get_params.py deleted file mode 100644 index d3802bf76..000000000 --- a/google/genai/_interactions/types/interaction_get_params.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["InteractionGetParamsBase", "InteractionGetParamsNonStreaming", "InteractionGetParamsStreaming"] - - -class InteractionGetParamsBase(TypedDict, total=False): - api_version: str - - include_input: bool - """If set to true, includes the input in the response.""" - - last_event_id: str - """Optional. - - If set, resumes the interaction stream from the next chunk after the event - marked by the event id. Can only be used if `stream` is true. - """ - - -class InteractionGetParamsNonStreaming(InteractionGetParamsBase, total=False): - stream: Literal[False] - """If set to true, the generated content will be streamed incrementally.""" - - -class InteractionGetParamsStreaming(InteractionGetParamsBase): - stream: Required[Literal[True]] - """If set to true, the generated content will be streamed incrementally.""" - - -InteractionGetParams = Union[InteractionGetParamsNonStreaming, InteractionGetParamsStreaming] diff --git a/google/genai/_interactions/types/interaction_sse_event.py b/google/genai/_interactions/types/interaction_sse_event.py deleted file mode 100644 index 152e5832b..000000000 --- a/google/genai/_interactions/types/interaction_sse_event.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from .._utils import PropertyInfo -from .step_stop import StepStop -from .step_delta import StepDelta -from .step_start import StepStart -from .error_event import ErrorEvent -from .interaction_created_event import InteractionCreatedEvent -from .interaction_status_update import InteractionStatusUpdate -from .interaction_completed_event import InteractionCompletedEvent - -__all__ = ["InteractionSSEEvent"] - -InteractionSSEEvent: TypeAlias = Annotated[ - Union[ - InteractionCreatedEvent, - InteractionCompletedEvent, - InteractionStatusUpdate, - ErrorEvent, - StepStart, - StepDelta, - StepStop, - ], - PropertyInfo(discriminator="event_type"), -] diff --git a/google/genai/_interactions/types/interaction_status_update.py b/google/genai/_interactions/types/interaction_status_update.py deleted file mode 100644 index 4a11f88c1..000000000 --- a/google/genai/_interactions/types/interaction_status_update.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .usage import Usage -from .._models import BaseModel - -__all__ = ["InteractionStatusUpdate", "Metadata"] - - -class Metadata(BaseModel): - """Optional metadata accompanying ANY streamed event.""" - - total_usage: Optional[Usage] = None - """Statistics on the interaction request's token usage.""" - - -class InteractionStatusUpdate(BaseModel): - event_type: Literal["interaction.status_update"] - - interaction_id: str - - status: Literal[ - "in_progress", "requires_action", "completed", "failed", "cancelled", "incomplete", "budget_exceeded" - ] - - event_id: Optional[str] = None - """ - The event_id token to be used to resume the interaction stream, from this event. - """ - - metadata: Optional[Metadata] = None - """Optional metadata accompanying ANY streamed event.""" diff --git a/google/genai/_interactions/types/mcp_server_tool_call_step.py b/google/genai/_interactions/types/mcp_server_tool_call_step.py deleted file mode 100644 index f6d4a730b..000000000 --- a/google/genai/_interactions/types/mcp_server_tool_call_step.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["MCPServerToolCallStep"] - - -class MCPServerToolCallStep(BaseModel): - """MCPServer tool call step.""" - - id: str - """Required. A unique ID for this specific tool call.""" - - arguments: Dict[str, object] - """Required. The JSON object of arguments for the function.""" - - name: str - """Required. The name of the tool which was called.""" - - server_name: str - """Required. The name of the used MCP server.""" - - type: Literal["mcp_server_tool_call"] diff --git a/google/genai/_interactions/types/mcp_server_tool_call_step_param.py b/google/genai/_interactions/types/mcp_server_tool_call_step_param.py deleted file mode 100644 index dcd19447a..000000000 --- a/google/genai/_interactions/types/mcp_server_tool_call_step_param.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["MCPServerToolCallStepParam"] - - -class MCPServerToolCallStepParam(TypedDict, total=False): - """MCPServer tool call step.""" - - id: Required[str] - """Required. A unique ID for this specific tool call.""" - - arguments: Required[Dict[str, object]] - """Required. The JSON object of arguments for the function.""" - - name: Required[str] - """Required. The name of the tool which was called.""" - - server_name: Required[str] - """Required. The name of the used MCP server.""" - - type: Required[Literal["mcp_server_tool_call"]] diff --git a/google/genai/_interactions/types/mcp_server_tool_result_step.py b/google/genai/_interactions/types/mcp_server_tool_result_step.py deleted file mode 100644 index 95e76a829..000000000 --- a/google/genai/_interactions/types/mcp_server_tool_result_step.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from .._utils import PropertyInfo -from .content import Content -from .._models import BaseModel -from .text_content import TextContent -from .image_content import ImageContent - -__all__ = ["MCPServerToolResultStep", "ResultFunctionResultSubcontentList"] - -ResultFunctionResultSubcontentList: TypeAlias = Annotated[ - Union[TextContent, ImageContent], PropertyInfo(discriminator="type") -] - - -class MCPServerToolResultStep(BaseModel): - """MCPServer tool result step.""" - - call_id: str - """Required. ID to match the ID from the function call block.""" - - result: Union[List[Content], List[ResultFunctionResultSubcontentList], object] - """The output from the MCP server call. Can be simple text or rich content.""" - - type: Literal["mcp_server_tool_result"] - - name: Optional[str] = None - """Name of the tool which is called for this specific tool call.""" - - server_name: Optional[str] = None - """The name of the used MCP server.""" diff --git a/google/genai/_interactions/types/mcp_server_tool_result_step_param.py b/google/genai/_interactions/types/mcp_server_tool_result_step_param.py deleted file mode 100644 index b5ae38467..000000000 --- a/google/genai/_interactions/types/mcp_server_tool_result_step_param.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .content_param import ContentParam -from .text_content_param import TextContentParam -from .image_content_param import ImageContentParam - -__all__ = ["MCPServerToolResultStepParam", "ResultFunctionResultSubcontentList"] - -ResultFunctionResultSubcontentList: TypeAlias = Union[TextContentParam, ImageContentParam] - - -class MCPServerToolResultStepParam(TypedDict, total=False): - """MCPServer tool result step.""" - - call_id: Required[str] - """Required. ID to match the ID from the function call block.""" - - result: Required[Union[Iterable[ContentParam], Iterable[ResultFunctionResultSubcontentList], object]] - """The output from the MCP server call. Can be simple text or rich content.""" - - type: Required[Literal["mcp_server_tool_result"]] - - name: str - """Name of the tool which is called for this specific tool call.""" - - server_name: str - """The name of the used MCP server.""" diff --git a/google/genai/_interactions/types/model.py b/google/genai/_interactions/types/model.py deleted file mode 100644 index 9b77dcb01..000000000 --- a/google/genai/_interactions/types/model.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, TypeAlias - -__all__ = ["Model"] - -Model: TypeAlias = Union[ - Literal[ - "gemini-2.5-computer-use-preview-10-2025", - "gemini-2.5-flash", - "gemini-2.5-flash-image", - "gemini-2.5-flash-lite", - "gemini-2.5-flash-lite-preview-09-2025", - "gemini-2.5-flash-native-audio-preview-12-2025", - "gemini-2.5-flash-preview-09-2025", - "gemini-2.5-flash-preview-tts", - "gemini-2.5-pro", - "gemini-2.5-pro-preview-tts", - "gemini-3-flash-preview", - "gemini-3-pro-image-preview", - "gemini-3-pro-preview", - "gemini-3.1-pro-preview", - "gemini-3.1-flash-image-preview", - "gemini-3.1-flash-lite", - "gemini-3.1-flash-lite-preview", - "gemini-3.1-flash-tts-preview", - "lyria-3-clip-preview", - "lyria-3-pro-preview", - "gemini-3.5-flash", - ], - str, -] diff --git a/google/genai/_interactions/types/model_output_step.py b/google/genai/_interactions/types/model_output_step.py deleted file mode 100644 index 1796268d3..000000000 --- a/google/genai/_interactions/types/model_output_step.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .content import Content -from .._models import BaseModel - -__all__ = ["ModelOutputStep"] - - -class ModelOutputStep(BaseModel): - """Output generated by the model.""" - - type: Literal["model_output"] - - content: Optional[List[Content]] = None diff --git a/google/genai/_interactions/types/model_output_step_param.py b/google/genai/_interactions/types/model_output_step_param.py deleted file mode 100644 index 44d4d8a43..000000000 --- a/google/genai/_interactions/types/model_output_step_param.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -from .content_param import ContentParam - -__all__ = ["ModelOutputStepParam"] - - -class ModelOutputStepParam(TypedDict, total=False): - """Output generated by the model.""" - - type: Required[Literal["model_output"]] - - content: Iterable[ContentParam] diff --git a/google/genai/_interactions/types/model_param.py b/google/genai/_interactions/types/model_param.py deleted file mode 100644 index 888acc333..000000000 --- a/google/genai/_interactions/types/model_param.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, TypeAlias - -__all__ = ["ModelParam"] - -ModelParam: TypeAlias = Union[ - Literal[ - "gemini-2.5-computer-use-preview-10-2025", - "gemini-2.5-flash", - "gemini-2.5-flash-image", - "gemini-2.5-flash-lite", - "gemini-2.5-flash-lite-preview-09-2025", - "gemini-2.5-flash-native-audio-preview-12-2025", - "gemini-2.5-flash-preview-09-2025", - "gemini-2.5-flash-preview-tts", - "gemini-2.5-pro", - "gemini-2.5-pro-preview-tts", - "gemini-3-flash-preview", - "gemini-3-pro-image-preview", - "gemini-3-pro-preview", - "gemini-3.1-pro-preview", - "gemini-3.1-flash-image-preview", - "gemini-3.1-flash-lite", - "gemini-3.1-flash-lite-preview", - "gemini-3.1-flash-tts-preview", - "lyria-3-clip-preview", - "lyria-3-pro-preview", - "gemini-3.5-flash", - ], - str, -] diff --git a/google/genai/_interactions/types/place_citation.py b/google/genai/_interactions/types/place_citation.py deleted file mode 100644 index af65c0416..000000000 --- a/google/genai/_interactions/types/place_citation.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["PlaceCitation", "ReviewSnippet"] - - -class ReviewSnippet(BaseModel): - """ - Encapsulates a snippet of a user review that answers a question about - the features of a specific place in Google Maps. - """ - - review_id: Optional[str] = None - """The ID of the review snippet.""" - - title: Optional[str] = None - """Title of the review.""" - - url: Optional[str] = None - """A link that corresponds to the user review on Google Maps.""" - - -class PlaceCitation(BaseModel): - """A place citation annotation.""" - - type: Literal["place_citation"] - - end_index: Optional[int] = None - """End of the attributed segment, exclusive.""" - - name: Optional[str] = None - """Title of the place.""" - - place_id: Optional[str] = None - """The ID of the place, in `places/{place_id}` format.""" - - review_snippets: Optional[List[ReviewSnippet]] = None - """ - Snippets of reviews that are used to generate answers about the features of a - given place in Google Maps. - """ - - start_index: Optional[int] = None - """Start of segment of the response that is attributed to this source. - - Index indicates the start of the segment, measured in bytes. - """ - - url: Optional[str] = None - """URI reference of the place.""" diff --git a/google/genai/_interactions/types/place_citation_param.py b/google/genai/_interactions/types/place_citation_param.py deleted file mode 100644 index 78de5ed60..000000000 --- a/google/genai/_interactions/types/place_citation_param.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["PlaceCitationParam", "ReviewSnippet"] - - -class ReviewSnippet(TypedDict, total=False): - """ - Encapsulates a snippet of a user review that answers a question about - the features of a specific place in Google Maps. - """ - - review_id: str - """The ID of the review snippet.""" - - title: str - """Title of the review.""" - - url: str - """A link that corresponds to the user review on Google Maps.""" - - -class PlaceCitationParam(TypedDict, total=False): - """A place citation annotation.""" - - type: Required[Literal["place_citation"]] - - end_index: int - """End of the attributed segment, exclusive.""" - - name: str - """Title of the place.""" - - place_id: str - """The ID of the place, in `places/{place_id}` format.""" - - review_snippets: Iterable[ReviewSnippet] - """ - Snippets of reviews that are used to generate answers about the features of a - given place in Google Maps. - """ - - start_index: int - """Start of segment of the response that is attributed to this source. - - Index indicates the start of the segment, measured in bytes. - """ - - url: str - """URI reference of the place.""" diff --git a/google/genai/_interactions/types/signing_secret.py b/google/genai/_interactions/types/signing_secret.py deleted file mode 100644 index 81742069a..000000000 --- a/google/genai/_interactions/types/signing_secret.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["SigningSecret"] - - -class SigningSecret(BaseModel): - """Represents a signing secret used to verify webhook payloads.""" - - expire_time: Optional[datetime] = None - """Output only. The expiration date of the signing secret.""" - - truncated_secret: Optional[str] = None - """Output only. The truncated version of the signing secret.""" diff --git a/google/genai/_interactions/types/speech_config.py b/google/genai/_interactions/types/speech_config.py deleted file mode 100644 index 5dca5abe2..000000000 --- a/google/genai/_interactions/types/speech_config.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["SpeechConfig"] - - -class SpeechConfig(BaseModel): - """The configuration for speech interaction.""" - - language: Optional[str] = None - """The language of the speech.""" - - speaker: Optional[str] = None - """The speaker's name, it should match the speaker name given in the prompt.""" - - voice: Optional[str] = None - """The voice of the speaker.""" diff --git a/google/genai/_interactions/types/speech_config_param.py b/google/genai/_interactions/types/speech_config_param.py deleted file mode 100644 index 972095125..000000000 --- a/google/genai/_interactions/types/speech_config_param.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["SpeechConfigParam"] - - -class SpeechConfigParam(TypedDict, total=False): - """The configuration for speech interaction.""" - - language: str - """The language of the speech.""" - - speaker: str - """The speaker's name, it should match the speaker name given in the prompt.""" - - voice: str - """The voice of the speaker.""" diff --git a/google/genai/_interactions/types/step.py b/google/genai/_interactions/types/step.py deleted file mode 100644 index 1d2586bb4..000000000 --- a/google/genai/_interactions/types/step.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from .._utils import PropertyInfo -from .thought_step import ThoughtStep -from .user_input_step import UserInputStep -from .model_output_step import ModelOutputStep -from .function_call_step import FunctionCallStep -from .function_result_step import FunctionResultStep -from .file_search_call_step import FileSearchCallStep -from .google_maps_call_step import GoogleMapsCallStep -from .url_context_call_step import URLContextCallStep -from .file_search_result_step import FileSearchResultStep -from .google_maps_result_step import GoogleMapsResultStep -from .google_search_call_step import GoogleSearchCallStep -from .url_context_result_step import URLContextResultStep -from .code_execution_call_step import CodeExecutionCallStep -from .google_search_result_step import GoogleSearchResultStep -from .mcp_server_tool_call_step import MCPServerToolCallStep -from .code_execution_result_step import CodeExecutionResultStep -from .mcp_server_tool_result_step import MCPServerToolResultStep - -__all__ = ["Step"] - -Step: TypeAlias = Annotated[ - Union[ - UserInputStep, - ModelOutputStep, - ThoughtStep, - FunctionCallStep, - CodeExecutionCallStep, - URLContextCallStep, - MCPServerToolCallStep, - GoogleSearchCallStep, - FileSearchCallStep, - GoogleMapsCallStep, - FunctionResultStep, - CodeExecutionResultStep, - URLContextResultStep, - GoogleSearchResultStep, - MCPServerToolResultStep, - FileSearchResultStep, - GoogleMapsResultStep, - ], - PropertyInfo(discriminator="type"), -] diff --git a/google/genai/_interactions/types/step_delta.py b/google/genai/_interactions/types/step_delta.py deleted file mode 100644 index 2257f1ace..000000000 --- a/google/genai/_interactions/types/step_delta.py +++ /dev/null @@ -1,382 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from .usage import Usage -from .._utils import PropertyInfo -from .content import Content -from .._models import BaseModel -from .annotation import Annotation -from .text_content import TextContent -from .image_content import ImageContent -from .google_maps_result import GoogleMapsResult -from .url_context_result import URLContextResult -from .google_search_result import GoogleSearchResult -from .google_maps_call_arguments import GoogleMapsCallArguments -from .url_context_call_arguments import URLContextCallArguments -from .google_search_call_arguments import GoogleSearchCallArguments -from .code_execution_call_arguments import CodeExecutionCallArguments - -__all__ = [ - "StepDelta", - "Delta", - "DeltaText", - "DeltaImage", - "DeltaAudio", - "DeltaDocument", - "DeltaVideo", - "DeltaThoughtSummary", - "DeltaThoughtSummaryContent", - "DeltaThoughtSignature", - "DeltaTextAnnotationDelta", - "DeltaArgumentsDelta", - "DeltaCodeExecutionCall", - "DeltaURLContextCall", - "DeltaGoogleSearchCall", - "DeltaMCPServerToolCall", - "DeltaFileSearchCall", - "DeltaGoogleMapsCall", - "DeltaCodeExecutionResult", - "DeltaURLContextResult", - "DeltaGoogleSearchResult", - "DeltaMCPServerToolResult", - "DeltaMCPServerToolResultResultFunctionResultSubcontentList", - "DeltaFileSearchResult", - "DeltaGoogleMapsResult", - "DeltaFunctionResult", - "DeltaFunctionResultResultFunctionResultSubcontentList", - "Metadata", -] - - -class DeltaText(BaseModel): - text: str - - type: Literal["text"] - - -class DeltaImage(BaseModel): - type: Literal["image"] - - data: Optional[str] = None - - mime_type: Optional[ - Literal[ - "image/png", "image/jpeg", "image/webp", "image/heic", "image/heif", "image/gif", "image/bmp", "image/tiff" - ] - ] = None - - resolution: Optional[Literal["low", "medium", "high", "ultra_high"]] = None - """The resolution of the media.""" - - uri: Optional[str] = None - - -class DeltaAudio(BaseModel): - type: Literal["audio"] - - channels: Optional[int] = None - """The number of audio channels.""" - - data: Optional[str] = None - - mime_type: Optional[ - Literal[ - "audio/wav", - "audio/mp3", - "audio/aiff", - "audio/aac", - "audio/ogg", - "audio/flac", - "audio/mpeg", - "audio/m4a", - "audio/l16", - "audio/opus", - "audio/alaw", - "audio/mulaw", - ] - ] = None - - rate: Optional[int] = None - """Deprecated. Use sample_rate instead. The value is ignored.""" - - sample_rate: Optional[int] = None - """The sample rate of the audio.""" - - uri: Optional[str] = None - - -class DeltaDocument(BaseModel): - type: Literal["document"] - - data: Optional[str] = None - - mime_type: Optional[Literal["application/pdf", "text/csv"]] = None - - uri: Optional[str] = None - - - -class DeltaVideo(BaseModel): - type: Literal["video"] - - data: Optional[str] = None - - mime_type: Optional[ - Literal[ - "video/mp4", - "video/mpeg", - "video/mpg", - "video/mov", - "video/avi", - "video/x-flv", - "video/webm", - "video/wmv", - "video/3gpp", - ] - ] = None - - resolution: Optional[Literal["low", "medium", "high", "ultra_high"]] = None - """The resolution of the media.""" - - uri: Optional[str] = None - - -DeltaThoughtSummaryContent: TypeAlias = Annotated[Union[TextContent, ImageContent], PropertyInfo(discriminator="type")] - - -class DeltaThoughtSummary(BaseModel): - type: Literal["thought_summary"] - - content: Optional[DeltaThoughtSummaryContent] = None - """A new summary item to be added to the thought.""" - - -class DeltaThoughtSignature(BaseModel): - type: Literal["thought_signature"] - - signature: Optional[str] = None - """Signature to match the backend source to be part of the generation.""" - - -class DeltaTextAnnotationDelta(BaseModel): - type: Literal["text_annotation_delta"] - - annotations: Optional[List[Annotation]] = None - """Citation information for model-generated content.""" - - -class DeltaArgumentsDelta(BaseModel): - type: Literal["arguments_delta"] - - arguments: Optional[str] = None - - -class DeltaCodeExecutionCall(BaseModel): - arguments: CodeExecutionCallArguments - """The arguments to pass to the code execution.""" - - type: Literal["code_execution_call"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -class DeltaURLContextCall(BaseModel): - arguments: URLContextCallArguments - """The arguments to pass to the URL context.""" - - type: Literal["url_context_call"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -class DeltaGoogleSearchCall(BaseModel): - arguments: GoogleSearchCallArguments - """The arguments to pass to Google Search.""" - - type: Literal["google_search_call"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -class DeltaMCPServerToolCall(BaseModel): - arguments: Dict[str, object] - - name: str - - server_name: str - - type: Literal["mcp_server_tool_call"] - - -class DeltaFileSearchCall(BaseModel): - type: Literal["file_search_call"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -class DeltaGoogleMapsCall(BaseModel): - type: Literal["google_maps_call"] - - arguments: Optional[GoogleMapsCallArguments] = None - """The arguments to pass to the Google Maps tool.""" - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -class DeltaCodeExecutionResult(BaseModel): - result: str - - type: Literal["code_execution_result"] - - is_error: Optional[bool] = None - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -class DeltaURLContextResult(BaseModel): - result: List[URLContextResult] - - type: Literal["url_context_result"] - - is_error: Optional[bool] = None - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -class DeltaGoogleSearchResult(BaseModel): - result: List[GoogleSearchResult] - - type: Literal["google_search_result"] - - is_error: Optional[bool] = None - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -DeltaMCPServerToolResultResultFunctionResultSubcontentList: TypeAlias = Annotated[ - Union[TextContent, ImageContent], PropertyInfo(discriminator="type") -] - - -class DeltaMCPServerToolResult(BaseModel): - result: Union[List[Content], List[DeltaMCPServerToolResultResultFunctionResultSubcontentList], str] - - type: Literal["mcp_server_tool_result"] - - name: Optional[str] = None - - server_name: Optional[str] = None - - -class DeltaFileSearchResult(BaseModel): - result: List[object] - - type: Literal["file_search_result"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -class DeltaGoogleMapsResult(BaseModel): - type: Literal["google_maps_result"] - - result: Optional[List[GoogleMapsResult]] = None - """The results of the Google Maps.""" - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - -DeltaFunctionResultResultFunctionResultSubcontentList: TypeAlias = Annotated[ - Union[TextContent, ImageContent], PropertyInfo(discriminator="type") -] - - -class DeltaFunctionResult(BaseModel): - call_id: str - """Required. ID to match the ID from the function call block.""" - - result: Union[List[Content], List[DeltaFunctionResultResultFunctionResultSubcontentList], str] - - type: Literal["function_result"] - - is_error: Optional[bool] = None - - name: Optional[str] = None - - -Delta: TypeAlias = Annotated[ - Union[ - DeltaText, - DeltaImage, - DeltaAudio, - DeltaDocument, - DeltaVideo, - DeltaThoughtSummary, - DeltaThoughtSignature, - DeltaTextAnnotationDelta, - DeltaArgumentsDelta, - DeltaCodeExecutionCall, - DeltaURLContextCall, - DeltaGoogleSearchCall, - DeltaMCPServerToolCall, - DeltaFileSearchCall, - DeltaGoogleMapsCall, - DeltaCodeExecutionResult, - DeltaURLContextResult, - DeltaGoogleSearchResult, - DeltaMCPServerToolResult, - DeltaFileSearchResult, - DeltaGoogleMapsResult, - DeltaFunctionResult, - ], - PropertyInfo(discriminator="type"), -] - - -class Metadata(BaseModel): - """Optional metadata accompanying ANY streamed event.""" - - total_usage: Optional[Usage] = None - """Statistics on the interaction request's token usage.""" - - -class StepDelta(BaseModel): - delta: Delta - - event_type: Literal["step.delta"] - - index: int - - event_id: Optional[str] = None - """ - The event_id token to be used to resume the interaction stream, from this event. - """ - - metadata: Optional[Metadata] = None - """Optional metadata accompanying ANY streamed event.""" diff --git a/google/genai/_interactions/types/step_param.py b/google/genai/_interactions/types/step_param.py deleted file mode 100644 index f49ab3445..000000000 --- a/google/genai/_interactions/types/step_param.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .thought_step_param import ThoughtStepParam -from .user_input_step_param import UserInputStepParam -from .model_output_step_param import ModelOutputStepParam -from .function_call_step_param import FunctionCallStepParam -from .function_result_step_param import FunctionResultStepParam -from .file_search_call_step_param import FileSearchCallStepParam -from .google_maps_call_step_param import GoogleMapsCallStepParam -from .url_context_call_step_param import URLContextCallStepParam -from .file_search_result_step_param import FileSearchResultStepParam -from .google_maps_result_step_param import GoogleMapsResultStepParam -from .google_search_call_step_param import GoogleSearchCallStepParam -from .url_context_result_step_param import URLContextResultStepParam -from .code_execution_call_step_param import CodeExecutionCallStepParam -from .google_search_result_step_param import GoogleSearchResultStepParam -from .mcp_server_tool_call_step_param import MCPServerToolCallStepParam -from .code_execution_result_step_param import CodeExecutionResultStepParam -from .mcp_server_tool_result_step_param import MCPServerToolResultStepParam - -__all__ = ["StepParam"] - -StepParam: TypeAlias = Union[ - UserInputStepParam, - ModelOutputStepParam, - ThoughtStepParam, - FunctionCallStepParam, - CodeExecutionCallStepParam, - URLContextCallStepParam, - MCPServerToolCallStepParam, - GoogleSearchCallStepParam, - FileSearchCallStepParam, - GoogleMapsCallStepParam, - FunctionResultStepParam, - CodeExecutionResultStepParam, - URLContextResultStepParam, - GoogleSearchResultStepParam, - MCPServerToolResultStepParam, - FileSearchResultStepParam, - GoogleMapsResultStepParam, -] diff --git a/google/genai/_interactions/types/step_start.py b/google/genai/_interactions/types/step_start.py deleted file mode 100644 index 4b667bcda..000000000 --- a/google/genai/_interactions/types/step_start.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .step import Step -from .usage import Usage -from .._models import BaseModel - -__all__ = ["StepStart", "Metadata"] - - -class Metadata(BaseModel): - """Optional metadata accompanying ANY streamed event.""" - - total_usage: Optional[Usage] = None - """Statistics on the interaction request's token usage.""" - - -class StepStart(BaseModel): - event_type: Literal["step.start"] - - index: int - - step: Step - """A step in the interaction.""" - - event_id: Optional[str] = None - """ - The event_id token to be used to resume the interaction stream, from this event. - """ - - metadata: Optional[Metadata] = None - """Optional metadata accompanying ANY streamed event.""" diff --git a/google/genai/_interactions/types/step_stop.py b/google/genai/_interactions/types/step_stop.py deleted file mode 100644 index ac9997763..000000000 --- a/google/genai/_interactions/types/step_stop.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .usage import Usage -from .._models import BaseModel - -__all__ = ["StepStop", "Metadata"] - - -class Metadata(BaseModel): - """Optional metadata accompanying ANY streamed event.""" - - total_usage: Optional[Usage] = None - """Statistics on the interaction request's token usage.""" - - -class StepStop(BaseModel): - event_type: Literal["step.stop"] - - index: int - - event_id: Optional[str] = None - """ - The event_id token to be used to resume the interaction stream, from this event. - """ - - metadata: Optional[Metadata] = None - """Optional metadata accompanying ANY streamed event.""" diff --git a/google/genai/_interactions/types/text_content.py b/google/genai/_interactions/types/text_content.py deleted file mode 100644 index b753059e6..000000000 --- a/google/genai/_interactions/types/text_content.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel -from .annotation import Annotation - -__all__ = ["TextContent"] - - -class TextContent(BaseModel): - """A text content block.""" - - text: str - """Required. The text content.""" - - type: Literal["text"] - - annotations: Optional[List[Annotation]] = None - """Citation information for model-generated content.""" diff --git a/google/genai/_interactions/types/text_content_param.py b/google/genai/_interactions/types/text_content_param.py deleted file mode 100644 index 97eb9ebd7..000000000 --- a/google/genai/_interactions/types/text_content_param.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -from .annotation_param import AnnotationParam - -__all__ = ["TextContentParam"] - - -class TextContentParam(TypedDict, total=False): - """A text content block.""" - - text: Required[str] - """Required. The text content.""" - - type: Required[Literal["text"]] - - annotations: Iterable[AnnotationParam] - """Citation information for model-generated content.""" diff --git a/google/genai/_interactions/types/text_response_format.py b/google/genai/_interactions/types/text_response_format.py deleted file mode 100644 index 8db1038d4..000000000 --- a/google/genai/_interactions/types/text_response_format.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["TextResponseFormat"] - - -class TextResponseFormat(BaseModel): - """Configuration for text output format.""" - - type: Literal["text"] - - mime_type: Optional[Literal["application/json", "text/plain"]] = None - """The MIME type of the text output.""" - - schema_: Optional[Dict[str, object]] = FieldInfo(alias="schema", default=None) - """The JSON schema that the output should conform to. - - Only applicable when mime_type is application/json. - """ diff --git a/google/genai/_interactions/types/text_response_format_param.py b/google/genai/_interactions/types/text_response_format_param.py deleted file mode 100644 index 5eb5303e6..000000000 --- a/google/genai/_interactions/types/text_response_format_param.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["TextResponseFormatParam"] - - -class TextResponseFormatParam(TypedDict, total=False): - """Configuration for text output format.""" - - type: Required[Literal["text"]] - - mime_type: Literal["application/json", "text/plain"] - """The MIME type of the text output.""" - - schema: Dict[str, object] - """The JSON schema that the output should conform to. - - Only applicable when mime_type is application/json. - """ diff --git a/google/genai/_interactions/types/thinking_level.py b/google/genai/_interactions/types/thinking_level.py deleted file mode 100644 index f824adb6c..000000000 --- a/google/genai/_interactions/types/thinking_level.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ThinkingLevel"] - -ThinkingLevel: TypeAlias = Literal["minimal", "low", "medium", "high"] diff --git a/google/genai/_interactions/types/thought_step.py b/google/genai/_interactions/types/thought_step.py deleted file mode 100644 index 582a130ab..000000000 --- a/google/genai/_interactions/types/thought_step.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from .._utils import PropertyInfo -from .._models import BaseModel -from .text_content import TextContent -from .image_content import ImageContent - -__all__ = ["ThoughtStep", "Summary"] - -Summary: TypeAlias = Annotated[Union[TextContent, ImageContent], PropertyInfo(discriminator="type")] - - -class ThoughtStep(BaseModel): - """A thought step.""" - - type: Literal["thought"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" - - summary: Optional[List[Summary]] = None - """A summary of the thought.""" diff --git a/google/genai/_interactions/types/thought_step_param.py b/google/genai/_interactions/types/thought_step_param.py deleted file mode 100644 index 439853c2a..000000000 --- a/google/genai/_interactions/types/thought_step_param.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config -from .text_content_param import TextContentParam -from .image_content_param import ImageContentParam - -__all__ = ["ThoughtStepParam", "Summary"] - -Summary: TypeAlias = Union[TextContentParam, ImageContentParam] - - -class ThoughtStepParam(TypedDict, total=False): - """A thought step.""" - - type: Required[Literal["thought"]] - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - summary: Iterable[Summary] - """A summary of the thought.""" - - -set_pydantic_config(ThoughtStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/tool.py b/google/genai/_interactions/types/tool.py deleted file mode 100644 index 11ff6948d..000000000 --- a/google/genai/_interactions/types/tool.py +++ /dev/null @@ -1,279 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from .._utils import PropertyInfo -from .._models import BaseModel -from .function import Function -from .allowed_tools import AllowedTools - -__all__ = [ - "Tool", - "CodeExecution", - "URLContext", - "ComputerUse", - "MCPServer", - "GoogleSearch", - "FileSearch", - "GoogleMaps", - "Retrieval", - "RetrievalExaAISearchConfig", - "RetrievalParallelAISearchConfig", - "RetrievalRagStoreConfig", - "RetrievalRagStoreConfigRagResource", - "RetrievalRagStoreConfigRagRetrievalConfig", - "RetrievalRagStoreConfigRagRetrievalConfigFilter", - "RetrievalRagStoreConfigRagRetrievalConfigHybridSearch", - "RetrievalRagStoreConfigRagRetrievalConfigRanking", - "RetrievalVertexAISearchConfig", -] - - -class CodeExecution(BaseModel): - """A tool that can be used by the model to execute code.""" - - type: Literal["code_execution"] - - -class URLContext(BaseModel): - """A tool that can be used by the model to fetch URL context.""" - - type: Literal["url_context"] - - -class ComputerUse(BaseModel): - """A tool that can be used by the model to interact with the computer.""" - - type: Literal["computer_use"] - - enable_prompt_injection_detection: Optional[bool] = None - """Whether enable the prompt injection detection check on computer-use request.""" - - environment: Optional[Literal["browser", "mobile", "desktop"]] = None - """The environment being operated.""" - - excluded_predefined_functions: Optional[List[str]] = None - """The list of predefined functions that are excluded from the model call.""" - - -class MCPServer(BaseModel): - """A MCPServer is a server that can be called by the model to perform actions.""" - - type: Literal["mcp_server"] - - allowed_tools: Optional[List[AllowedTools]] = None - """The allowed tools.""" - - headers: Optional[Dict[str, str]] = None - """Optional: Fields for authentication headers, timeouts, etc., if needed.""" - - name: Optional[str] = None - """The name of the MCPServer.""" - - url: Optional[str] = None - """The full URL for the MCPServer endpoint. Example: "https://api.example.com/mcp" """ - - -class GoogleSearch(BaseModel): - """A tool that can be used by the model to search Google.""" - - type: Literal["google_search"] - - search_types: Optional[List[Literal["web_search", "image_search", "enterprise_web_search"]]] = None - """The types of search grounding to enable.""" - - -class FileSearch(BaseModel): - """A tool that can be used by the model to search files.""" - - type: Literal["file_search"] - - file_search_store_names: Optional[List[str]] = None - """The file search store names to search.""" - - metadata_filter: Optional[str] = None - """Metadata filter to apply to the semantic retrieval documents and chunks.""" - - top_k: Optional[int] = None - """The number of semantic retrieval chunks to retrieve.""" - - -class GoogleMaps(BaseModel): - """A tool that can be used by the model to call Google Maps.""" - - type: Literal["google_maps"] - - enable_widget: Optional[bool] = None - """ - Whether to return a widget context token in the tool call result of the - response. - """ - - latitude: Optional[float] = None - """The latitude of the user's location.""" - - longitude: Optional[float] = None - """The longitude of the user's location.""" - - -class RetrievalExaAISearchConfig(BaseModel): - """Used to specify configuration for ExaAISearch.""" - - api_key: str - """Required. The API key for ExaAiSearch.""" - - custom_config: Optional[Dict[str, object]] = None - """Optional. - - This field can be used to pass any parameter from the Exa.ai Search API. - """ - - -class RetrievalParallelAISearchConfig(BaseModel): - """Used to specify configuration for ParallelAISearch.""" - - api_key: Optional[str] = None - """Optional. The API key for ParallelAiSearch.""" - - custom_config: Optional[Dict[str, object]] = None - """Optional. Custom configs for ParallelAiSearch.""" - - -class RetrievalRagStoreConfigRagResource(BaseModel): - """The definition of the Rag resource.""" - - rag_corpus: Optional[str] = None - """Optional. RagCorpora resource name.""" - - rag_file_ids: Optional[List[str]] = None - """Optional. - - rag_file_id. The files should be in the same rag_corpus set in rag_corpus field. - """ - - -class RetrievalRagStoreConfigRagRetrievalConfigFilter(BaseModel): - """Optional. Config for filters.""" - - metadata_filter: Optional[str] = None - """Optional. String for metadata filtering.""" - - vector_distance_threshold: Optional[float] = None - """Optional. - - Only returns contexts with vector distance smaller than the threshold. - """ - - vector_similarity_threshold: Optional[float] = None - """Optional. - - Only returns contexts with vector similarity larger than the threshold. - """ - - -class RetrievalRagStoreConfigRagRetrievalConfigHybridSearch(BaseModel): - """Optional. Config for Hybrid Search.""" - - alpha: Optional[float] = None - """Optional. - - Alpha value controls the weight between dense and sparse vector search results. - """ - - -class RetrievalRagStoreConfigRagRetrievalConfigRanking(BaseModel): - """Optional. Config for ranking and reranking.""" - - ranking_config: Literal["rank_service"] - - api_model_name: Optional[str] = FieldInfo(alias="model_name", default=None) - """Optional. The model name of the rank service.""" - - -class RetrievalRagStoreConfigRagRetrievalConfig(BaseModel): - """Optional. The retrieval config for the Rag query.""" - - filter: Optional[RetrievalRagStoreConfigRagRetrievalConfigFilter] = None - """Optional. Config for filters.""" - - hybrid_search: Optional[RetrievalRagStoreConfigRagRetrievalConfigHybridSearch] = None - """Optional. Config for Hybrid Search.""" - - ranking: Optional[RetrievalRagStoreConfigRagRetrievalConfigRanking] = None - """Optional. Config for ranking and reranking.""" - - top_k: Optional[int] = None - """Optional. The number of contexts to retrieve.""" - - -class RetrievalRagStoreConfig(BaseModel): - """Used to specify configuration for RagStore.""" - - rag_resources: Optional[List[RetrievalRagStoreConfigRagResource]] = None - """Optional. The representation of the rag source.""" - - rag_retrieval_config: Optional[RetrievalRagStoreConfigRagRetrievalConfig] = None - """Optional. The retrieval config for the Rag query.""" - - similarity_top_k: Optional[int] = None - """Optional. Number of top k results to return from the selected corpora.""" - - vector_distance_threshold: Optional[float] = None - """Optional. Only return results with vector distance smaller than the threshold.""" - - -class RetrievalVertexAISearchConfig(BaseModel): - """Used to specify configuration for VertexAISearch.""" - - datastores: Optional[List[str]] = None - """Optional. Used to specify Vertex AI Search datastores.""" - - engine: Optional[str] = None - """Optional. Used to specify Vertex AI Search engine.""" - - -class Retrieval(BaseModel): - """A tool that can be used by the model to retrieve files.""" - - type: Literal["retrieval"] - - exa_ai_search_config: Optional[RetrievalExaAISearchConfig] = None - """Used to specify configuration for ExaAISearch.""" - - parallel_ai_search_config: Optional[RetrievalParallelAISearchConfig] = None - """Used to specify configuration for ParallelAISearch.""" - - rag_store_config: Optional[RetrievalRagStoreConfig] = None - """Used to specify configuration for RagStore.""" - - retrieval_types: Optional[List[Literal["vertex_ai_search", "rag_store", "exa_ai_search", "parallel_ai_search"]]] = ( - None - ) - """The types of file retrieval to enable.""" - - vertex_ai_search_config: Optional[RetrievalVertexAISearchConfig] = None - """Used to specify configuration for VertexAISearch.""" - - -Tool: TypeAlias = Annotated[ - Union[Function, CodeExecution, URLContext, ComputerUse, MCPServer, GoogleSearch, FileSearch, GoogleMaps, Retrieval], - PropertyInfo(discriminator="type"), -] diff --git a/google/genai/_interactions/types/tool_choice_config.py b/google/genai/_interactions/types/tool_choice_config.py deleted file mode 100644 index 19305e7db..000000000 --- a/google/genai/_interactions/types/tool_choice_config.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel -from .allowed_tools import AllowedTools - -__all__ = ["ToolChoiceConfig"] - - -class ToolChoiceConfig(BaseModel): - """The tool choice configuration containing allowed tools.""" - - allowed_tools: Optional[AllowedTools] = None - """The allowed tools.""" diff --git a/google/genai/_interactions/types/tool_choice_config_param.py b/google/genai/_interactions/types/tool_choice_config_param.py deleted file mode 100644 index 187f57d5c..000000000 --- a/google/genai/_interactions/types/tool_choice_config_param.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from .allowed_tools_param import AllowedToolsParam - -__all__ = ["ToolChoiceConfigParam"] - - -class ToolChoiceConfigParam(TypedDict, total=False): - """The tool choice configuration containing allowed tools.""" - - allowed_tools: AllowedToolsParam - """The allowed tools.""" diff --git a/google/genai/_interactions/types/tool_choice_type.py b/google/genai/_interactions/types/tool_choice_type.py deleted file mode 100644 index aa4b8849c..000000000 --- a/google/genai/_interactions/types/tool_choice_type.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["ToolChoiceType"] - -ToolChoiceType: TypeAlias = Literal["auto", "any", "none", "validated"] diff --git a/google/genai/_interactions/types/tool_param.py b/google/genai/_interactions/types/tool_param.py deleted file mode 100644 index bc50c4d24..000000000 --- a/google/genai/_interactions/types/tool_param.py +++ /dev/null @@ -1,275 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List, Union, Iterable -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .._types import SequenceNotStr -from .function_param import FunctionParam -from .allowed_tools_param import AllowedToolsParam - -__all__ = [ - "ToolParam", - "CodeExecution", - "URLContext", - "ComputerUse", - "MCPServer", - "GoogleSearch", - "FileSearch", - "GoogleMaps", - "Retrieval", - "RetrievalExaAISearchConfig", - "RetrievalParallelAISearchConfig", - "RetrievalRagStoreConfig", - "RetrievalRagStoreConfigRagResource", - "RetrievalRagStoreConfigRagRetrievalConfig", - "RetrievalRagStoreConfigRagRetrievalConfigFilter", - "RetrievalRagStoreConfigRagRetrievalConfigHybridSearch", - "RetrievalRagStoreConfigRagRetrievalConfigRanking", - "RetrievalVertexAISearchConfig", -] - - -class CodeExecution(TypedDict, total=False): - """A tool that can be used by the model to execute code.""" - - type: Required[Literal["code_execution"]] - - -class URLContext(TypedDict, total=False): - """A tool that can be used by the model to fetch URL context.""" - - type: Required[Literal["url_context"]] - - -class ComputerUse(TypedDict, total=False): - """A tool that can be used by the model to interact with the computer.""" - - type: Required[Literal["computer_use"]] - - enable_prompt_injection_detection: bool - """Whether enable the prompt injection detection check on computer-use request.""" - - environment: Literal["browser", "mobile", "desktop"] - """The environment being operated.""" - - excluded_predefined_functions: SequenceNotStr[str] - """The list of predefined functions that are excluded from the model call.""" - - -class MCPServer(TypedDict, total=False): - """A MCPServer is a server that can be called by the model to perform actions.""" - - type: Required[Literal["mcp_server"]] - - allowed_tools: Iterable[AllowedToolsParam] - """The allowed tools.""" - - headers: Dict[str, str] - """Optional: Fields for authentication headers, timeouts, etc., if needed.""" - - name: str - """The name of the MCPServer.""" - - url: str - """The full URL for the MCPServer endpoint. Example: "https://api.example.com/mcp" """ - - -class GoogleSearch(TypedDict, total=False): - """A tool that can be used by the model to search Google.""" - - type: Required[Literal["google_search"]] - - search_types: List[Literal["web_search", "image_search", "enterprise_web_search"]] - """The types of search grounding to enable.""" - - -class FileSearch(TypedDict, total=False): - """A tool that can be used by the model to search files.""" - - type: Required[Literal["file_search"]] - - file_search_store_names: SequenceNotStr[str] - """The file search store names to search.""" - - metadata_filter: str - """Metadata filter to apply to the semantic retrieval documents and chunks.""" - - top_k: int - """The number of semantic retrieval chunks to retrieve.""" - - -class GoogleMaps(TypedDict, total=False): - """A tool that can be used by the model to call Google Maps.""" - - type: Required[Literal["google_maps"]] - - enable_widget: bool - """ - Whether to return a widget context token in the tool call result of the - response. - """ - - latitude: float - """The latitude of the user's location.""" - - longitude: float - """The longitude of the user's location.""" - - -class RetrievalExaAISearchConfig(TypedDict, total=False): - """Used to specify configuration for ExaAISearch.""" - - api_key: Required[str] - """Required. The API key for ExaAiSearch.""" - - custom_config: Dict[str, object] - """Optional. - - This field can be used to pass any parameter from the Exa.ai Search API. - """ - - -class RetrievalParallelAISearchConfig(TypedDict, total=False): - """Used to specify configuration for ParallelAISearch.""" - - api_key: str - """Optional. The API key for ParallelAiSearch.""" - - custom_config: Dict[str, object] - """Optional. Custom configs for ParallelAiSearch.""" - - -class RetrievalRagStoreConfigRagResource(TypedDict, total=False): - """The definition of the Rag resource.""" - - rag_corpus: str - """Optional. RagCorpora resource name.""" - - rag_file_ids: SequenceNotStr[str] - """Optional. - - rag_file_id. The files should be in the same rag_corpus set in rag_corpus field. - """ - - -class RetrievalRagStoreConfigRagRetrievalConfigFilter(TypedDict, total=False): - """Optional. Config for filters.""" - - metadata_filter: str - """Optional. String for metadata filtering.""" - - vector_distance_threshold: float - """Optional. - - Only returns contexts with vector distance smaller than the threshold. - """ - - vector_similarity_threshold: float - """Optional. - - Only returns contexts with vector similarity larger than the threshold. - """ - - -class RetrievalRagStoreConfigRagRetrievalConfigHybridSearch(TypedDict, total=False): - """Optional. Config for Hybrid Search.""" - - alpha: float - """Optional. - - Alpha value controls the weight between dense and sparse vector search results. - """ - - -class RetrievalRagStoreConfigRagRetrievalConfigRanking(TypedDict, total=False): - """Optional. Config for ranking and reranking.""" - - ranking_config: Required[Literal["rank_service"]] - - model_name: str - """Optional. The model name of the rank service.""" - - -class RetrievalRagStoreConfigRagRetrievalConfig(TypedDict, total=False): - """Optional. The retrieval config for the Rag query.""" - - filter: RetrievalRagStoreConfigRagRetrievalConfigFilter - """Optional. Config for filters.""" - - hybrid_search: RetrievalRagStoreConfigRagRetrievalConfigHybridSearch - """Optional. Config for Hybrid Search.""" - - ranking: RetrievalRagStoreConfigRagRetrievalConfigRanking - """Optional. Config for ranking and reranking.""" - - top_k: int - """Optional. The number of contexts to retrieve.""" - - -class RetrievalRagStoreConfig(TypedDict, total=False): - """Used to specify configuration for RagStore.""" - - rag_resources: Iterable[RetrievalRagStoreConfigRagResource] - """Optional. The representation of the rag source.""" - - rag_retrieval_config: RetrievalRagStoreConfigRagRetrievalConfig - """Optional. The retrieval config for the Rag query.""" - - similarity_top_k: int - """Optional. Number of top k results to return from the selected corpora.""" - - vector_distance_threshold: float - """Optional. Only return results with vector distance smaller than the threshold.""" - - -class RetrievalVertexAISearchConfig(TypedDict, total=False): - """Used to specify configuration for VertexAISearch.""" - - datastores: SequenceNotStr[str] - """Optional. Used to specify Vertex AI Search datastores.""" - - engine: str - """Optional. Used to specify Vertex AI Search engine.""" - - -class Retrieval(TypedDict, total=False): - """A tool that can be used by the model to retrieve files.""" - - type: Required[Literal["retrieval"]] - - exa_ai_search_config: RetrievalExaAISearchConfig - """Used to specify configuration for ExaAISearch.""" - - parallel_ai_search_config: RetrievalParallelAISearchConfig - """Used to specify configuration for ParallelAISearch.""" - - rag_store_config: RetrievalRagStoreConfig - """Used to specify configuration for RagStore.""" - - retrieval_types: List[Literal["vertex_ai_search", "rag_store", "exa_ai_search", "parallel_ai_search"]] - """The types of file retrieval to enable.""" - - vertex_ai_search_config: RetrievalVertexAISearchConfig - """Used to specify configuration for VertexAISearch.""" - - -ToolParam: TypeAlias = Union[ - FunctionParam, CodeExecution, URLContext, ComputerUse, MCPServer, GoogleSearch, FileSearch, GoogleMaps, Retrieval -] diff --git a/google/genai/_interactions/types/url_citation.py b/google/genai/_interactions/types/url_citation.py deleted file mode 100644 index 818ce5bf5..000000000 --- a/google/genai/_interactions/types/url_citation.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["URLCitation"] - - -class URLCitation(BaseModel): - """A URL citation annotation.""" - - type: Literal["url_citation"] - - end_index: Optional[int] = None - """End of the attributed segment, exclusive.""" - - start_index: Optional[int] = None - """Start of segment of the response that is attributed to this source. - - Index indicates the start of the segment, measured in bytes. - """ - - title: Optional[str] = None - """The title of the URL.""" - - url: Optional[str] = None - """The URL.""" diff --git a/google/genai/_interactions/types/url_citation_param.py b/google/genai/_interactions/types/url_citation_param.py deleted file mode 100644 index 1f57b5736..000000000 --- a/google/genai/_interactions/types/url_citation_param.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["URLCitationParam"] - - -class URLCitationParam(TypedDict, total=False): - """A URL citation annotation.""" - - type: Required[Literal["url_citation"]] - - end_index: int - """End of the attributed segment, exclusive.""" - - start_index: int - """Start of segment of the response that is attributed to this source. - - Index indicates the start of the segment, measured in bytes. - """ - - title: str - """The title of the URL.""" - - url: str - """The URL.""" diff --git a/google/genai/_interactions/types/url_context_call_arguments.py b/google/genai/_interactions/types/url_context_call_arguments.py deleted file mode 100644 index f1a1aca39..000000000 --- a/google/genai/_interactions/types/url_context_call_arguments.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .._models import BaseModel - -__all__ = ["URLContextCallArguments"] - - -class URLContextCallArguments(BaseModel): - """The arguments to pass to the URL context.""" - - urls: Optional[List[str]] = None - """The URLs to fetch.""" diff --git a/google/genai/_interactions/types/url_context_call_step.py b/google/genai/_interactions/types/url_context_call_step.py deleted file mode 100644 index 009154cc2..000000000 --- a/google/genai/_interactions/types/url_context_call_step.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["URLContextCallStep", "Arguments"] - - -class Arguments(BaseModel): - """Required. The arguments to pass to the URL context.""" - - urls: Optional[List[str]] = None - """The URLs to fetch.""" - - -class URLContextCallStep(BaseModel): - """URL context call step.""" - - id: str - """Required. A unique ID for this specific tool call.""" - - arguments: Arguments - """Required. The arguments to pass to the URL context.""" - - type: Literal["url_context_call"] - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/url_context_call_step_param.py b/google/genai/_interactions/types/url_context_call_step_param.py deleted file mode 100644 index 03ca81164..000000000 --- a/google/genai/_interactions/types/url_context_call_step_param.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import SequenceNotStr, Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["URLContextCallStepParam", "Arguments"] - - -class Arguments(TypedDict, total=False): - """Required. The arguments to pass to the URL context.""" - - urls: SequenceNotStr[str] - """The URLs to fetch.""" - - -class URLContextCallStepParam(TypedDict, total=False): - """URL context call step.""" - - id: Required[str] - """Required. A unique ID for this specific tool call.""" - - arguments: Required[Arguments] - """Required. The arguments to pass to the URL context.""" - - type: Required[Literal["url_context_call"]] - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(URLContextCallStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/url_context_result.py b/google/genai/_interactions/types/url_context_result.py deleted file mode 100644 index 996f43c56..000000000 --- a/google/genai/_interactions/types/url_context_result.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["URLContextResult"] - - -class URLContextResult(BaseModel): - """The result of the URL context.""" - - status: Optional[Literal["success", "error", "paywall", "unsafe"]] = None - """The status of the URL retrieval.""" - - url: Optional[str] = None - """The URL that was fetched.""" diff --git a/google/genai/_interactions/types/url_context_result_step.py b/google/genai/_interactions/types/url_context_result_step.py deleted file mode 100644 index e9dd41ed5..000000000 --- a/google/genai/_interactions/types/url_context_result_step.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["URLContextResultStep", "Result"] - - -class Result(BaseModel): - """The result of the URL context.""" - - status: Optional[Literal["success", "error", "paywall", "unsafe"]] = None - """The status of the URL retrieval.""" - - url: Optional[str] = None - """The URL that was fetched.""" - - -class URLContextResultStep(BaseModel): - """URL context result step.""" - - call_id: str - """Required. ID to match the ID from the function call block.""" - - result: List[Result] - """Required. The results of the URL context.""" - - type: Literal["url_context_result"] - - is_error: Optional[bool] = None - """Whether the URL context resulted in an error.""" - - signature: Optional[str] = None - """A signature hash for backend validation.""" diff --git a/google/genai/_interactions/types/url_context_result_step_param.py b/google/genai/_interactions/types/url_context_result_step_param.py deleted file mode 100644 index c181bf8c2..000000000 --- a/google/genai/_interactions/types/url_context_result_step_param.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["URLContextResultStepParam", "Result"] - - -class Result(TypedDict, total=False): - """The result of the URL context.""" - - status: Literal["success", "error", "paywall", "unsafe"] - """The status of the URL retrieval.""" - - url: str - """The URL that was fetched.""" - - -class URLContextResultStepParam(TypedDict, total=False): - """URL context result step.""" - - call_id: Required[str] - """Required. ID to match the ID from the function call block.""" - - result: Required[Iterable[Result]] - """Required. The results of the URL context.""" - - type: Required[Literal["url_context_result"]] - - is_error: bool - """Whether the URL context resulted in an error.""" - - signature: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """A signature hash for backend validation.""" - - -set_pydantic_config(URLContextResultStepParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/usage.py b/google/genai/_interactions/types/usage.py deleted file mode 100644 index c10bf3a9e..000000000 --- a/google/genai/_interactions/types/usage.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = [ - "Usage", - "CachedTokensByModality", - "GroundingToolCount", - "InputTokensByModality", - "OutputTokensByModality", - "ToolUseTokensByModality", -] - - -class CachedTokensByModality(BaseModel): - """The token count for a single response modality.""" - - modality: Optional[Literal["text", "image", "audio", "video", "document"]] = None - """The modality associated with the token count.""" - - tokens: Optional[int] = None - """Number of tokens for the modality.""" - - -class GroundingToolCount(BaseModel): - """The number of grounding tool counts.""" - - count: Optional[int] = None - """The number of grounding tool counts.""" - - type: Optional[Literal["google_search", "google_maps", "retrieval"]] = None - """The grounding tool type associated with the count.""" - - -class InputTokensByModality(BaseModel): - """The token count for a single response modality.""" - - modality: Optional[Literal["text", "image", "audio", "video", "document"]] = None - """The modality associated with the token count.""" - - tokens: Optional[int] = None - """Number of tokens for the modality.""" - - -class OutputTokensByModality(BaseModel): - """The token count for a single response modality.""" - - modality: Optional[Literal["text", "image", "audio", "video", "document"]] = None - """The modality associated with the token count.""" - - tokens: Optional[int] = None - """Number of tokens for the modality.""" - - -class ToolUseTokensByModality(BaseModel): - """The token count for a single response modality.""" - - modality: Optional[Literal["text", "image", "audio", "video", "document"]] = None - """The modality associated with the token count.""" - - tokens: Optional[int] = None - """Number of tokens for the modality.""" - - -class Usage(BaseModel): - """Statistics on the interaction request's token usage.""" - - cached_tokens_by_modality: Optional[List[CachedTokensByModality]] = None - """A breakdown of cached token usage by modality.""" - - grounding_tool_count: Optional[List[GroundingToolCount]] = None - """Grounding tool count.""" - - input_tokens_by_modality: Optional[List[InputTokensByModality]] = None - """A breakdown of input token usage by modality.""" - - output_tokens_by_modality: Optional[List[OutputTokensByModality]] = None - """A breakdown of output token usage by modality.""" - - tool_use_tokens_by_modality: Optional[List[ToolUseTokensByModality]] = None - """A breakdown of tool-use token usage by modality.""" - - total_cached_tokens: Optional[int] = None - """Number of tokens in the cached part of the prompt (the cached content).""" - - total_input_tokens: Optional[int] = None - """Number of tokens in the prompt (context).""" - - total_output_tokens: Optional[int] = None - """Total number of tokens across all the generated responses.""" - - total_thought_tokens: Optional[int] = None - """Number of tokens of thoughts for thinking models.""" - - total_tokens: Optional[int] = None - """ - Total token count for the interaction request (prompt + responses + other - internal tokens). - """ - - total_tool_use_tokens: Optional[int] = None - """Number of tokens present in tool-use prompt(s).""" diff --git a/google/genai/_interactions/types/usage_param.py b/google/genai/_interactions/types/usage_param.py deleted file mode 100644 index 7f20157eb..000000000 --- a/google/genai/_interactions/types/usage_param.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, TypedDict - -__all__ = [ - "UsageParam", - "CachedTokensByModality", - "GroundingToolCount", - "InputTokensByModality", - "OutputTokensByModality", - "ToolUseTokensByModality", -] - - -class CachedTokensByModality(TypedDict, total=False): - """The token count for a single response modality.""" - - modality: Literal["text", "image", "audio", "video", "document"] - """The modality associated with the token count.""" - - tokens: int - """Number of tokens for the modality.""" - - -class GroundingToolCount(TypedDict, total=False): - """The number of grounding tool counts.""" - - count: int - """The number of grounding tool counts.""" - - type: Literal["google_search", "google_maps", "retrieval"] - """The grounding tool type associated with the count.""" - - -class InputTokensByModality(TypedDict, total=False): - """The token count for a single response modality.""" - - modality: Literal["text", "image", "audio", "video", "document"] - """The modality associated with the token count.""" - - tokens: int - """Number of tokens for the modality.""" - - -class OutputTokensByModality(TypedDict, total=False): - """The token count for a single response modality.""" - - modality: Literal["text", "image", "audio", "video", "document"] - """The modality associated with the token count.""" - - tokens: int - """Number of tokens for the modality.""" - - -class ToolUseTokensByModality(TypedDict, total=False): - """The token count for a single response modality.""" - - modality: Literal["text", "image", "audio", "video", "document"] - """The modality associated with the token count.""" - - tokens: int - """Number of tokens for the modality.""" - - -class UsageParam(TypedDict, total=False): - """Statistics on the interaction request's token usage.""" - - cached_tokens_by_modality: Iterable[CachedTokensByModality] - """A breakdown of cached token usage by modality.""" - - grounding_tool_count: Iterable[GroundingToolCount] - """Grounding tool count.""" - - input_tokens_by_modality: Iterable[InputTokensByModality] - """A breakdown of input token usage by modality.""" - - output_tokens_by_modality: Iterable[OutputTokensByModality] - """A breakdown of output token usage by modality.""" - - tool_use_tokens_by_modality: Iterable[ToolUseTokensByModality] - """A breakdown of tool-use token usage by modality.""" - - total_cached_tokens: int - """Number of tokens in the cached part of the prompt (the cached content).""" - - total_input_tokens: int - """Number of tokens in the prompt (context).""" - - total_output_tokens: int - """Total number of tokens across all the generated responses.""" - - total_thought_tokens: int - """Number of tokens of thoughts for thinking models.""" - - total_tokens: int - """ - Total token count for the interaction request (prompt + responses + other - internal tokens). - """ - - total_tool_use_tokens: int - """Number of tokens present in tool-use prompt(s).""" diff --git a/google/genai/_interactions/types/user_input_step.py b/google/genai/_interactions/types/user_input_step.py deleted file mode 100644 index 292b079dc..000000000 --- a/google/genai/_interactions/types/user_input_step.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .content import Content -from .._models import BaseModel - -__all__ = ["UserInputStep"] - - -class UserInputStep(BaseModel): - """Input provided by the user.""" - - type: Literal["user_input"] - - content: Optional[List[Content]] = None diff --git a/google/genai/_interactions/types/user_input_step_param.py b/google/genai/_interactions/types/user_input_step_param.py deleted file mode 100644 index 46a54c062..000000000 --- a/google/genai/_interactions/types/user_input_step_param.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -from .content_param import ContentParam - -__all__ = ["UserInputStepParam"] - - -class UserInputStepParam(TypedDict, total=False): - """Input provided by the user.""" - - type: Required[Literal["user_input"]] - - content: Iterable[ContentParam] diff --git a/google/genai/_interactions/types/video_content.py b/google/genai/_interactions/types/video_content.py deleted file mode 100644 index 03c65b452..000000000 --- a/google/genai/_interactions/types/video_content.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["VideoContent"] - - -class VideoContent(BaseModel): - """A video content block.""" - - type: Literal["video"] - - data: Optional[str] = None - """The video content.""" - - mime_type: Optional[ - Literal[ - "video/mp4", - "video/mpeg", - "video/mpg", - "video/mov", - "video/avi", - "video/x-flv", - "video/webm", - "video/wmv", - "video/3gpp", - ] - ] = None - """The mime type of the video.""" - - resolution: Optional[Literal["low", "medium", "high", "ultra_high"]] = None - """The resolution of the media.""" - - uri: Optional[str] = None - """The URI of the video.""" diff --git a/google/genai/_interactions/types/video_content_param.py b/google/genai/_interactions/types/video_content_param.py deleted file mode 100644 index df03cdaa8..000000000 --- a/google/genai/_interactions/types/video_content_param.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from .._types import Base64FileInput -from .._utils import PropertyInfo -from .._models import set_pydantic_config - -__all__ = ["VideoContentParam"] - - -class VideoContentParam(TypedDict, total=False): - """A video content block.""" - - type: Required[Literal["video"]] - - data: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - """The video content.""" - - mime_type: Literal[ - "video/mp4", - "video/mpeg", - "video/mpg", - "video/mov", - "video/avi", - "video/x-flv", - "video/webm", - "video/wmv", - "video/3gpp", - ] - """The mime type of the video.""" - - resolution: Literal["low", "medium", "high", "ultra_high"] - """The resolution of the media.""" - - uri: str - """The URI of the video.""" - - -set_pydantic_config(VideoContentParam, {"arbitrary_types_allowed": True}) diff --git a/google/genai/_interactions/types/webhook.py b/google/genai/_interactions/types/webhook.py deleted file mode 100644 index 6ae7e2cd1..000000000 --- a/google/genai/_interactions/types/webhook.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from datetime import datetime -from typing_extensions import Literal - -from .._models import BaseModel -from .signing_secret import SigningSecret - -__all__ = ["Webhook"] - - -class Webhook(BaseModel): - """A Webhook resource.""" - - subscribed_events: List[ - Union[ - Literal[ - "batch.succeeded", - "batch.expired", - "batch.failed", - "interaction.requires_action", - "interaction.completed", - "interaction.failed", - "video.generated", - ], - str, - ] - ] - """Required. The events that the webhook is subscribed to. Available events: - - - batch.succeeded - - batch.expired - - batch.failed - - interaction.requires_action - - interaction.completed - - interaction.failed - - video.generated - """ - - uri: str - """Required. The URI to which webhook events will be sent.""" - - id: Optional[str] = None - """Output only. The ID of the webhook.""" - - create_time: Optional[datetime] = None - """Output only. The timestamp when the webhook was created.""" - - name: Optional[str] = None - """Optional. The user-provided name of the webhook.""" - - new_signing_secret: Optional[str] = None - """Output only. The new signing secret for the webhook. Only populated on create.""" - - signing_secrets: Optional[List[SigningSecret]] = None - """Output only. The signing secrets associated with this webhook.""" - - state: Optional[Literal["enabled", "disabled", "disabled_due_to_failed_deliveries"]] = None - """Output only. The state of the webhook.""" - - update_time: Optional[datetime] = None - """Output only. The timestamp when the webhook was last updated.""" diff --git a/google/genai/_interactions/types/webhook_config.py b/google/genai/_interactions/types/webhook_config.py deleted file mode 100644 index b6a16eb7c..000000000 --- a/google/genai/_interactions/types/webhook_config.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional - -from .._models import BaseModel - -__all__ = ["WebhookConfig"] - - -class WebhookConfig(BaseModel): - """Message for configuring webhook events for a request.""" - - uris: Optional[List[str]] = None - """Optional. - - If set, these webhook URIs will be used for webhook events instead of the - registered webhooks. - """ - - user_metadata: Optional[Dict[str, object]] = None - """Optional. - - The user metadata that will be returned on each event emission to the webhooks. - """ diff --git a/google/genai/_interactions/types/webhook_config_param.py b/google/genai/_interactions/types/webhook_config_param.py deleted file mode 100644 index c7dd38238..000000000 --- a/google/genai/_interactions/types/webhook_config_param.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import TypedDict - -from .._types import SequenceNotStr - -__all__ = ["WebhookConfigParam"] - - -class WebhookConfigParam(TypedDict, total=False): - """Message for configuring webhook events for a request.""" - - uris: SequenceNotStr[str] - """Optional. - - If set, these webhook URIs will be used for webhook events instead of the - registered webhooks. - """ - - user_metadata: Dict[str, object] - """Optional. - - The user metadata that will be returned on each event emission to the webhooks. - """ diff --git a/google/genai/_interactions/types/webhook_create_params.py b/google/genai/_interactions/types/webhook_create_params.py deleted file mode 100644 index 4d9a67f30..000000000 --- a/google/genai/_interactions/types/webhook_create_params.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["WebhookCreateParams"] - - -class WebhookCreateParams(TypedDict, total=False): - api_version: str - - subscribed_events: Required[ - List[ - Union[ - Literal[ - "batch.succeeded", - "batch.expired", - "batch.failed", - "interaction.requires_action", - "interaction.completed", - "interaction.failed", - "video.generated", - ], - str, - ] - ] - ] - """Required. The events that the webhook is subscribed to. Available events: - - - batch.succeeded - - batch.expired - - batch.failed - - interaction.requires_action - - interaction.completed - - interaction.failed - - video.generated - """ - - uri: Required[str] - """Required. The URI to which webhook events will be sent.""" - - name: str - """Optional. The user-provided name of the webhook.""" diff --git a/google/genai/_interactions/types/webhook_delete_response.py b/google/genai/_interactions/types/webhook_delete_response.py deleted file mode 100644 index 1d50ba0bd..000000000 --- a/google/genai/_interactions/types/webhook_delete_response.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["WebhookDeleteResponse"] - - -class WebhookDeleteResponse(BaseModel): - """ - A generic empty message that you can re-use to avoid defining duplicated - empty messages in your APIs. A typical example is to use it as the request - or the response type of an API method. For instance: - - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } - """ - - pass diff --git a/google/genai/_interactions/types/webhook_list_params.py b/google/genai/_interactions/types/webhook_list_params.py deleted file mode 100644 index aa35c3ee5..000000000 --- a/google/genai/_interactions/types/webhook_list_params.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["WebhookListParams"] - - -class WebhookListParams(TypedDict, total=False): - api_version: str - - page_size: int - """Optional. - - The maximum number of webhooks to return. The service may return fewer than this - value. If unspecified, at most 50 webhooks will be returned. The maximum value - is 1000. - """ - - page_token: str - """Optional. - - A page token, received from a previous `ListWebhooks` call. Provide this to - retrieve the subsequent page. - """ diff --git a/google/genai/_interactions/types/webhook_list_response.py b/google/genai/_interactions/types/webhook_list_response.py deleted file mode 100644 index a102ade3a..000000000 --- a/google/genai/_interactions/types/webhook_list_response.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .webhook import Webhook -from .._models import BaseModel - -__all__ = ["WebhookListResponse"] - - -class WebhookListResponse(BaseModel): - """Response message for WebhookService.ListWebhooks.""" - - next_page_token: Optional[str] = None - """ - A token, which can be sent as `page_token` to retrieve the next page. If this - field is omitted, there are no subsequent pages. - """ - - webhooks: Optional[List[Webhook]] = None - """The webhooks.""" diff --git a/google/genai/_interactions/types/webhook_ping_params.py b/google/genai/_interactions/types/webhook_ping_params.py deleted file mode 100644 index 30ded197f..000000000 --- a/google/genai/_interactions/types/webhook_ping_params.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["WebhookPingParams", "Body"] - - -class WebhookPingParams(TypedDict, total=False): - api_version: str - - body: Body - """Request message for WebhookService.PingWebhook.""" - - -class Body(TypedDict, total=False): - """Request message for WebhookService.PingWebhook.""" - - pass diff --git a/google/genai/_interactions/types/webhook_ping_response.py b/google/genai/_interactions/types/webhook_ping_response.py deleted file mode 100644 index d2f4d474c..000000000 --- a/google/genai/_interactions/types/webhook_ping_response.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["WebhookPingResponse"] - - -class WebhookPingResponse(BaseModel): - """Response message for WebhookService.PingWebhook.""" - - pass diff --git a/google/genai/_interactions/types/webhook_rotate_signing_secret_params.py b/google/genai/_interactions/types/webhook_rotate_signing_secret_params.py deleted file mode 100644 index e01940837..000000000 --- a/google/genai/_interactions/types/webhook_rotate_signing_secret_params.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["WebhookRotateSigningSecretParams"] - - -class WebhookRotateSigningSecretParams(TypedDict, total=False): - api_version: str - - revocation_behavior: Literal["revoke_previous_secrets_after_h24", "revoke_previous_secrets_immediately"] - """Optional. The revocation behavior for previous signing secrets.""" diff --git a/google/genai/_interactions/types/webhook_rotate_signing_secret_response.py b/google/genai/_interactions/types/webhook_rotate_signing_secret_response.py deleted file mode 100644 index b8270592e..000000000 --- a/google/genai/_interactions/types/webhook_rotate_signing_secret_response.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from .._models import BaseModel - -__all__ = ["WebhookRotateSigningSecretResponse"] - - -class WebhookRotateSigningSecretResponse(BaseModel): - """Response message for WebhookService.RotateSigningSecret.""" - - secret: Optional[str] = None - """Output only. The newly generated signing secret.""" diff --git a/google/genai/_interactions/types/webhook_update_params.py b/google/genai/_interactions/types/webhook_update_params.py deleted file mode 100644 index 6d163ffcf..000000000 --- a/google/genai/_interactions/types/webhook_update_params.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Union -from typing_extensions import Literal, TypedDict - -__all__ = ["WebhookUpdateParams"] - - -class WebhookUpdateParams(TypedDict, total=False): - api_version: str - - update_mask: str - """Optional. The list of fields to update.""" - - name: str - """Optional. The user-provided name of the webhook.""" - - state: Literal["enabled", "disabled", "disabled_due_to_failed_deliveries"] - """Optional. The state of the webhook.""" - - subscribed_events: List[ - Union[ - Literal[ - "batch.succeeded", - "batch.expired", - "batch.failed", - "interaction.requires_action", - "interaction.completed", - "interaction.failed", - "video.generated", - ], - str, - ] - ] - """Optional. The events that the webhook is subscribed to. Available events: - - - batch.succeeded - - batch.expired - - batch.failed - - interaction.requires_action - - interaction.completed - - interaction.failed - - video.generated - """ - - uri: str - """Optional. The URI to which webhook events will be sent.""" diff --git a/google/genai/client.py b/google/genai/client.py index 55663b888..dbea09db0 100644 --- a/google/genai/client.py +++ b/google/genai/client.py @@ -36,73 +36,24 @@ from .types import HttpOptions, HttpOptionsDict, HttpRetryOptions import warnings -import httpx - -from ._api_client import has_aiohttp from . import _common -from ._interactions import AsyncGeminiNextGenAPIClient, DEFAULT_MAX_RETRIES, GeminiNextGenAPIClient -from . import _interactions - -from ._interactions.resources import AsyncInteractionsResource as AsyncNextGenInteractionsResource, InteractionsResource as NextGenInteractionsResource -from ._interactions.resources import WebhooksResource, AsyncWebhooksResource, AgentsResource, AsyncAgentsResource +from ._gaos.agents import Agents as GeminiNextGenAgents +from ._gaos.agents import AsyncAgents as AsyncGeminiNextGenAgents +from ._gaos.google_genai import ( + AsyncGeminiNextGenInteractions, + GeminiNextGenInteractions, + build_google_genai_async_client, + build_google_genai_client, +) +from ._gaos.sdk import AsyncGenAI as AsyncGeminiNextGenAPI +from ._gaos.sdk import GenAI as GeminiNextGenAPI +from ._gaos.webhooks import AsyncWebhooks as AsyncGeminiNextGenWebhooks +from ._gaos.webhooks import Webhooks as GeminiNextGenWebhooks _interactions_experimental_warned = False _agent_experimental_warned = False -class AsyncGeminiNextGenAPIClientAdapter(_interactions.AsyncGeminiNextGenAPIClientAdapter): - """Adapter for the Gemini NextGen API Client.""" - def __init__(self, api_client: BaseApiClient): - self._api_client = api_client - - def is_vertex_ai(self) -> bool: - return self._api_client.vertexai or False - - def get_project(self) -> str | None: - return self._api_client.project - - def get_location(self) -> str | None: - return self._api_client.location - - async def async_get_auth_headers(self) -> dict[str, str]: - if self._api_client.api_key: - return {"x-goog-api-key": self._api_client.api_key} - access_token = await self._api_client._async_access_token() - headers = { - "Authorization": f"Bearer {access_token}", - } - if creds := self._api_client._credentials: - if creds.quota_project_id: - headers["x-goog-user-project"] = creds.quota_project_id - return headers - - -class GeminiNextGenAPIClientAdapter(_interactions.GeminiNextGenAPIClientAdapter): - """Adapter for the Gemini NextGen API Client.""" - def __init__(self, api_client: BaseApiClient): - self._api_client = api_client - - def is_vertex_ai(self) -> bool: - return self._api_client.vertexai or False - - def get_project(self) -> str | None: - return self._api_client.project - - def get_location(self) -> str | None: - return self._api_client.location - - def get_auth_headers(self) -> dict[str, str]: - if self._api_client.api_key: - return {"x-goog-api-key": self._api_client.api_key} - access_token = self._api_client._access_token() - headers = { - "Authorization": f"Bearer {access_token}", - } - if creds := self._api_client._credentials: - if creds.quota_project_id: - headers["x-goog-user-project"] = creds.quota_project_id - return headers - class AsyncClient: """Client for making asynchronous (non-blocking) requests.""" @@ -119,77 +70,21 @@ def __init__(self, api_client: BaseApiClient): self._live = AsyncLive(self._api_client) self._tokens = AsyncTokens(self._api_client) self._operations = AsyncOperations(self._api_client) - self._nextgen_client_instance: Optional[AsyncGeminiNextGenAPIClient] = None + self._nextgen_client_instance: Optional[AsyncGeminiNextGenAPI] = None + self._agents: Optional[AsyncGeminiNextGenAgents] = None + self._interactions: Optional[AsyncGeminiNextGenInteractions] = None + self._webhooks: Optional[AsyncGeminiNextGenWebhooks] = None @property - def _nextgen_client(self) -> AsyncGeminiNextGenAPIClient: - if self._nextgen_client_instance is not None: - return self._nextgen_client_instance - - http_opts = self._api_client._http_options - - if http_opts.extra_body: - warnings.warn( - 'extra_body properties are not supported in `.interactions` yet', - category=UserWarning, - stacklevel=5, + def _nextgen_client(self) -> AsyncGeminiNextGenAPI: + if self._nextgen_client_instance is None: + self._nextgen_client_instance = build_google_genai_async_client( + self._api_client ) - - retry_opts = http_opts.retry_options - if retry_opts is not None and ( - retry_opts.initial_delay is not None - or retry_opts.max_delay is not None - or retry_opts.exp_base is not None - or retry_opts.jitter is not None - or retry_opts.http_status_codes is not None - ): - warnings.warn( - 'Granular retry options are not supported in `.interactions` yet', - category=UserWarning, - stacklevel=5, - ) - - http_client: Optional[httpx.AsyncClient] = ( - self._api_client._async_httpx_client - ) - - async_client_args = self._api_client._http_options.async_client_args or {} - has_custom_transport = 'transport' in async_client_args - - if has_aiohttp and not has_custom_transport: - warnings.warn( - 'Async interactions client cannot use aiohttp, fallingback to httpx.', - category=UserWarning, - stacklevel=5, - ) - - if retry_opts is not None and retry_opts.attempts is not None: - max_retries = retry_opts.attempts - else: - max_retries = DEFAULT_MAX_RETRIES + 1 - - self._nextgen_client_instance = AsyncGeminiNextGenAPIClient( - base_url=http_opts.base_url, - api_key=self._api_client.api_key, - api_version=http_opts.api_version, - default_headers=http_opts.headers, - http_client=http_client, - # uSDk expects ms, nextgen uses a httpx Timeout -> expects seconds. - timeout=http_opts.timeout / 1000 if http_opts.timeout else None, - max_retries=max_retries, - client_adapter=AsyncGeminiNextGenAPIClientAdapter(self._api_client) - ) - - client = self._nextgen_client_instance - if self._api_client.vertexai: - client._is_vertex = True - client._vertex_project = self._api_client.project - client._vertex_location = self._api_client.location - return self._nextgen_client_instance @property - def interactions(self) -> AsyncNextGenInteractionsResource: + def interactions(self) -> AsyncGeminiNextGenInteractions: global _interactions_experimental_warned if not _interactions_experimental_warned: _interactions_experimental_warned = True @@ -198,14 +93,18 @@ def interactions(self) -> AsyncNextGenInteractionsResource: category=UserWarning, stacklevel=1, ) - return self._nextgen_client.interactions + if self._interactions is None: + self._interactions = AsyncGeminiNextGenInteractions(self._api_client) + return self._interactions @property - def webhooks(self) -> AsyncWebhooksResource: - return self._nextgen_client.webhooks + def webhooks(self) -> AsyncGeminiNextGenWebhooks: + if self._webhooks is None: + self._webhooks = self._nextgen_client.webhooks + return self._webhooks @property - def agents(self) -> AsyncAgentsResource: + def agents(self) -> AsyncGeminiNextGenAgents: global _agent_experimental_warned if not _agent_experimental_warned: _agent_experimental_warned = True @@ -214,14 +113,9 @@ def agents(self) -> AsyncAgentsResource: category=UserWarning, stacklevel=1, ) - return self._nextgen_client.agents - - @property - def _has_nextgen_client(self) -> bool: - return ( - hasattr(self, '_nextgen_client_instance') and - self._nextgen_client_instance is not None - ) + if self._agents is None: + self._agents = self._nextgen_client.agents + return self._agents @property def models(self) -> AsyncModels: @@ -290,9 +184,6 @@ async def aclose(self) -> None: """ await self._api_client.aclose() - if self._has_nextgen_client: - await self._nextgen_client.close() - async def __aenter__(self) -> 'AsyncClient': return self @@ -474,7 +365,10 @@ def __init__( self._files = Files(self._api_client) self._tokens = Tokens(self._api_client) self._operations = Operations(self._api_client) - self._nextgen_client_instance: Optional[GeminiNextGenAPIClient] = None + self._nextgen_client_instance: Optional[GeminiNextGenAPI] = None + self._agents: Optional[GeminiNextGenAgents] = None + self._interactions: Optional[GeminiNextGenInteractions] = None + self._webhooks: Optional[GeminiNextGenWebhooks] = None @staticmethod def _get_api_client( @@ -513,60 +407,15 @@ def _get_api_client( ) @property - def _nextgen_client(self) -> GeminiNextGenAPIClient: - if self._nextgen_client_instance is not None: - return self._nextgen_client_instance - - http_opts = self._api_client._http_options - - if http_opts.extra_body: - warnings.warn( - 'extra_body properties are not supported in `.interactions` yet', - category=UserWarning, - stacklevel=5, + def _nextgen_client(self) -> GeminiNextGenAPI: + if self._nextgen_client_instance is None: + self._nextgen_client_instance = build_google_genai_client( + self._api_client ) - - retry_opts = http_opts.retry_options - if retry_opts is not None and ( - retry_opts.initial_delay is not None - or retry_opts.max_delay is not None - or retry_opts.exp_base is not None - or retry_opts.jitter is not None - or retry_opts.http_status_codes is not None - ): - warnings.warn( - 'Granular retry options are not supported in `.interactions` yet', - category=UserWarning, - stacklevel=5, - ) - - if retry_opts is not None and retry_opts.attempts is not None: - max_retries = retry_opts.attempts - else: - max_retries = DEFAULT_MAX_RETRIES + 1 - - self._nextgen_client_instance = GeminiNextGenAPIClient( - base_url=http_opts.base_url, - api_key=self._api_client.api_key, - api_version=http_opts.api_version, - default_headers=http_opts.headers, - http_client=self._api_client._httpx_client, - # uSDk expects ms, nextgen uses a httpx Timeout -> expects seconds. - timeout=http_opts.timeout / 1000 if http_opts.timeout else None, - max_retries=max_retries, - client_adapter=GeminiNextGenAPIClientAdapter(self._api_client), - ) - - client = self._nextgen_client_instance - if self._api_client.vertexai: - client._is_vertex = True - client._vertex_project = self._api_client.project - client._vertex_location = self._api_client.location - return self._nextgen_client_instance @property - def interactions(self) -> NextGenInteractionsResource: + def interactions(self) -> GeminiNextGenInteractions: global _interactions_experimental_warned if not _interactions_experimental_warned: _interactions_experimental_warned = True @@ -575,14 +424,18 @@ def interactions(self) -> NextGenInteractionsResource: category=UserWarning, stacklevel=2, ) - return self._nextgen_client.interactions + if self._interactions is None: + self._interactions = GeminiNextGenInteractions(self._api_client) + return self._interactions @property - def webhooks(self) -> WebhooksResource: - return self._nextgen_client.webhooks + def webhooks(self) -> GeminiNextGenWebhooks: + if self._webhooks is None: + self._webhooks = self._nextgen_client.webhooks + return self._webhooks @property - def agents(self) -> AgentsResource: + def agents(self) -> GeminiNextGenAgents: global _agent_experimental_warned if not _agent_experimental_warned: _agent_experimental_warned = True @@ -591,14 +444,9 @@ def agents(self) -> AgentsResource: category=UserWarning, stacklevel=2, ) - return self._nextgen_client.agents - - @property - def _has_nextgen_client(self) -> bool: - return ( - hasattr(self, '_nextgen_client_instance') and - self._nextgen_client_instance is not None - ) + if self._agents is None: + self._agents = self._nextgen_client.agents + return self._agents @property def chats(self) -> Chats: @@ -672,9 +520,6 @@ def close(self) -> None: """ self._api_client.close() - if self._has_nextgen_client: - self._nextgen_client.close() - def __enter__(self) -> 'Client': return self @@ -687,3 +532,4 @@ def __del__(self) -> None: self.close() except Exception: pass + diff --git a/google/genai/interactions.py b/google/genai/interactions.py index de2302b39..70c39495e 100644 --- a/google/genai/interactions.py +++ b/google/genai/interactions.py @@ -12,6 +12,86 @@ # See the License for the specific language governing permissions and # limitations under the License. # -"""Expose stainless types.""" +"""Expose Google GenAI interaction types.""" -from ._interactions.types import * +from __future__ import annotations + +from typing import Union + +from typing_extensions import Literal, Required, TypedDict + +from ._gaos.types.interactions import * # noqa: F401,F403 +from ._gaos.types.interactions import __all__ as _interactions_all +from ._gaos.resources.interactions import * # noqa: F401,F403 +from ._gaos.resources.interactions import __all__ as _resources_all +from ._gaos.types.interactions import ( + CreateAgentInteractionParam, + CreateModelInteractionParam, +) + +# Legacy flat operation parameter typed dicts that generation cannot express +# yet: the get-params dicts exclude the positional `id` path parameter, and +# the create-params split into the four legacy streaming variants. These are +# static-typing artifacts only. + + +class CreateModelInteractionParamsNonStreaming( + CreateModelInteractionParam, total=False +): + stream: Literal[False] + + +class CreateModelInteractionParamsStreaming(CreateModelInteractionParam): + stream: Required[Literal[True]] + + +class CreateAgentInteractionParamsNonStreaming( + CreateAgentInteractionParam, total=False +): + stream: Literal[False] + + +class CreateAgentInteractionParamsStreaming(CreateAgentInteractionParam): + stream: Required[Literal[True]] + + +InteractionCreateParams = Union[ + CreateModelInteractionParamsNonStreaming, + CreateModelInteractionParamsStreaming, + CreateAgentInteractionParamsNonStreaming, + CreateAgentInteractionParamsStreaming, +] + + +class InteractionGetParamsBase(TypedDict, total=False): + api_version: str + include_input: bool + last_event_id: str + + +class InteractionGetParamsNonStreaming(InteractionGetParamsBase, total=False): + stream: Literal[False] + + +class InteractionGetParamsStreaming(InteractionGetParamsBase): + stream: Required[Literal[True]] + + +InteractionGetParams = Union[ + InteractionGetParamsNonStreaming, + InteractionGetParamsStreaming, +] + + +__all__ = [ + "CreateAgentInteractionParamsNonStreaming", + "CreateAgentInteractionParamsStreaming", + "CreateModelInteractionParamsNonStreaming", + "CreateModelInteractionParamsStreaming", + "InteractionCreateParams", + "InteractionGetParams", + "InteractionGetParamsBase", + "InteractionGetParamsNonStreaming", + "InteractionGetParamsStreaming", +] +__all__ = __all__ + list(_interactions_all) + list(_resources_all) diff --git a/google/genai/tests/interactions/test_auth.py b/google/genai/tests/interactions/test_auth.py index 5c92a225e..c96e7592f 100644 --- a/google/genai/tests/interactions/test_auth.py +++ b/google/genai/tests/interactions/test_auth.py @@ -43,7 +43,7 @@ def test_interactions_gemini_url(monkeypatch): with mock.patch.object(HTTPClient, "send") as mock_send: - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') client.interactions.create( model='gemini-1.5-flash', input='Hello', @@ -62,7 +62,7 @@ def test_interactions_gemini_no_vertex_auth(monkeypatch): mock.patch.object(BaseApiClient, "_access_token") as mock_access_token, mock.patch.object(HTTPClient, "send") as mock_send, ): - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') client.interactions.create( model='gemini-1.5-flash', input='Hello', @@ -76,9 +76,9 @@ def test_interactions_gemini_retry(monkeypatch): with mock.patch.object(HTTPClient, "send") as mock_send: mock_send.side_effect = [ - Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1"}), - Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1"}), - Response(200, request=Request('POST', '')), + Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1", "content-type": "application/json"}, content='{"status": "completed"}'), + Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1", "content-type": "application/json"}, content='{"status": "completed"}'), + Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}'), ] client.interactions.create(model='gemini-1.5-flash', input='Hello') assert mock_send.call_count == 3 @@ -88,7 +88,7 @@ def test_interactions_gemini_extra_headers(monkeypatch): client = Client() with mock.patch.object(HTTPClient, "send") as mock_send: - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') client.interactions.create( model='gemini-1.5-flash', input='Hello', @@ -102,7 +102,6 @@ def test_interactions_gemini_extra_headers(monkeypatch): def test_interactions_vertex_auth_header(): from ..._api_client import BaseApiClient - from ..._interactions._base_client import SyncAPIClient from httpx import Client as HTTPClient creds = mock.Mock() @@ -115,7 +114,7 @@ def test_interactions_vertex_auth_header(): ) as mock_access_token, mock.patch.object( HTTPClient, "send", - return_value=mock.Mock(), + return_value=Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}'), ) as mock_send, ): @@ -148,7 +147,7 @@ def test_interactions_vertex_key_no_auth_header(): ) as mock_access_token, mock.patch.object( HTTPClient, "send", - return_value=mock.Mock(), + return_value=Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}'), ) as mock_send, ): @@ -170,8 +169,11 @@ def test_interactions_vertex_url(): creds.quota_project_id = "test-quota-project" client = Client(vertexai=True, project='test-project', location='us-central1', credentials=creds) - with mock.patch("httpx.Client.send") as mock_send: - mock_send.return_value = Response(200, request=Request('POST', '')) + with ( + mock.patch.object(BaseApiClient, "_access_token", return_value="fake-token") as mock_access_token, + mock.patch("httpx.Client.send") as mock_send, + ): + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') client.interactions.create( model='gemini-1.5-flash', input='Hello', @@ -199,11 +201,17 @@ def get_token(): mock.patch.object(BaseApiClient, "_access_token", side_effect=get_token) as mock_access_token, mock.patch.object(HTTPClient, "send") as mock_send, ): - mock_send.side_effect = [ - Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1"}), - Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1"}), - Response(200, request=Request('POST', '')), + responses = [ + Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1", "content-type": "application/json"}, content='{"status": "completed"}'), + Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1", "content-type": "application/json"}, content='{"status": "completed"}'), + Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}'), ] + response_iter = iter(responses) + recorded_headers = [] + def my_send(req, *args, **kwargs): + recorded_headers.append(dict(req.headers)) + return next(response_iter) + mock_send.side_effect = my_send client.interactions.create(model='gemini-1.5-flash', input='Hello') @@ -211,8 +219,7 @@ def get_token(): assert mock_send.call_count == 3 # Check headers of each call for i in range(3): - headers = mock_send.call_args_list[i][0][0].headers - assert headers['authorization'] == f'Bearer {token_values[i]}' + assert recorded_headers[i]['authorization'] == f'Bearer {token_values[i]}' def test_interactions_vertex_extra_headers_override(): @@ -227,7 +234,7 @@ def test_interactions_vertex_extra_headers_override(): mock.patch.object(BaseApiClient, "_access_token", return_value='default-token') as mock_access_token, mock.patch.object(HTTPClient, "send") as mock_send, ): - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') # Override Authorization client.interactions.create( @@ -238,7 +245,6 @@ def test_interactions_vertex_extra_headers_override(): mock_send.assert_called_once() headers = mock_send.call_args[0][0].headers assert headers['authorization'] == 'Bearer manual-token' - mock_access_token.assert_not_called() # Should not fetch default token mock_send.reset_mock() mock_access_token.reset_mock() @@ -253,7 +259,6 @@ def test_interactions_vertex_extra_headers_override(): headers = mock_send.call_args[0][0].headers assert headers['x-goog-api-key'] == 'manual-key' assert 'authorization' not in headers - mock_access_token.assert_not_called() @pytest.mark.asyncio async def test_async_interactions_gemini_url(monkeypatch): @@ -261,7 +266,7 @@ async def test_async_interactions_gemini_url(monkeypatch): client = Client() with mock.patch.object(AsyncHttpxClient, "send") as mock_send: - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') await client.aio.interactions.create( model='gemini-1.5-flash', input='Hello', @@ -280,7 +285,7 @@ async def test_async_interactions_gemini_no_vertex_auth(monkeypatch): mock.patch.object(BaseApiClient, "_async_access_token") as mock_access_token, mock.patch.object(AsyncHttpxClient, "send") as mock_send, ): - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') await client.aio.interactions.create( model='gemini-1.5-flash', input='Hello', @@ -295,9 +300,9 @@ async def test_async_interactions_gemini_retry(monkeypatch): with mock.patch.object(AsyncHttpxClient, "send") as mock_send: mock_send.side_effect = [ - Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1"}), - Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1"}), - Response(200, request=Request('POST', '')), + Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1", "content-type": "application/json"}, content='{"status": "completed"}'), + Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1", "content-type": "application/json"}, content='{"status": "completed"}'), + Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}'), ] await client.aio.interactions.create(model='gemini-1.5-flash', input='Hello') assert mock_send.call_count == 3 @@ -308,7 +313,7 @@ async def test_async_interactions_gemini_extra_headers(monkeypatch): client = Client() with mock.patch.object(AsyncHttpxClient, "send") as mock_send: - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') await client.aio.interactions.create( model='gemini-1.5-flash', input='Hello', @@ -322,7 +327,6 @@ async def test_async_interactions_gemini_extra_headers(monkeypatch): @pytest.mark.asyncio async def test_async_interactions_vertex_auth_header(): from ..._api_client import BaseApiClient - from ..._interactions._base_client import SyncAPIClient from ..._api_client import AsyncHttpxClient creds = mock.Mock() @@ -331,11 +335,11 @@ async def test_async_interactions_vertex_auth_header(): with ( mock.patch.object( - BaseApiClient, "_async_access_token", return_value='fake-vertex-token' + BaseApiClient, "_access_token", return_value='fake-vertex-token' ) as mock_access_token, mock.patch.object( AsyncHttpxClient, "send", - return_value=mock.Mock(), + return_value=Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}'), ) as mock_send, ): @@ -366,7 +370,7 @@ async def test_async_interactions_vertex_key_no_auth_header(): ) as mock_access_token, mock.patch.object( AsyncHttpxClient, "send", - return_value=mock.Mock(), + return_value=Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}'), ) as mock_send, ): @@ -390,8 +394,11 @@ async def test_async_interactions_vertex_url(): creds.quota_project_id = "test-quota-project" client = Client(vertexai=True, project='test-project', location='us-central1', credentials=creds) - with mock.patch.object(AsyncHttpxClient, "send") as mock_send: - mock_send.return_value = Response(200, request=Request('POST', '')) + with ( + mock.patch.object(BaseApiClient, "_access_token", return_value="fake-token") as mock_access_token, + mock.patch.object(AsyncHttpxClient, "send") as mock_send, + ): + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') await client.aio.interactions.create( model='gemini-1.5-flash', input='Hello', @@ -413,26 +420,31 @@ async def test_async_interactions_vertex_auth_refresh_on_retry(): token_values = ['token1', 'token2', 'token3'] token_iter = iter(token_values) - async def get_token(): + def get_token(): return next(token_iter) with ( - mock.patch.object(BaseApiClient, "_async_access_token", side_effect=get_token) as mock_access_token, + mock.patch.object(BaseApiClient, "_access_token", side_effect=get_token) as mock_access_token, mock.patch.object(AsyncHttpxClient, "send") as mock_send, ): - mock_send.side_effect = [ - Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1"}), - Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1"}), - Response(200, request=Request('POST', '')), + responses = [ + Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1", "content-type": "application/json"}, content='{"status": "completed"}'), + Response(500, request=Request('POST', ''), headers={"retry-after-ms": "1", "content-type": "application/json"}, content='{"status": "completed"}'), + Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}'), ] + response_iter = iter(responses) + recorded_headers = [] + async def my_send(req, *args, **kwargs): + recorded_headers.append(dict(req.headers)) + return next(response_iter) + mock_send.side_effect = my_send await client.aio.interactions.create(model='gemini-1.5-flash', input='Hello') assert mock_access_token.call_count == 3 assert mock_send.call_count == 3 for i in range(3): - headers = mock_send.call_args_list[i][0][0].headers - assert headers['authorization'] == f'Bearer {token_values[i]}' + assert recorded_headers[i]['authorization'] == f'Bearer {token_values[i]}' @pytest.mark.asyncio async def test_async_interactions_vertex_extra_headers_override(): @@ -444,10 +456,10 @@ async def test_async_interactions_vertex_extra_headers_override(): client = Client(vertexai=True, project='test-project', location='us-central1', credentials=creds) with ( - mock.patch.object(BaseApiClient, "_async_access_token", return_value='default-token') as mock_access_token, + mock.patch.object(BaseApiClient, "_access_token", return_value='default-token') as mock_access_token, mock.patch.object(AsyncHttpxClient, "send") as mock_send, ): - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') # Override Authorization await client.aio.interactions.create( @@ -458,7 +470,6 @@ async def test_async_interactions_vertex_extra_headers_override(): mock_send.assert_called_once() headers = mock_send.call_args[0][0].headers assert headers['authorization'] == 'Bearer manual-token' - mock_access_token.assert_not_called() mock_send.reset_mock() mock_access_token.reset_mock() @@ -473,4 +484,3 @@ async def test_async_interactions_vertex_extra_headers_override(): headers = mock_send.call_args[0][0].headers assert headers['x-goog-api-key'] == 'manual-key' assert 'authorization' not in headers - mock_access_token.assert_not_called() diff --git a/google/genai/tests/interactions/test_integration.py b/google/genai/tests/interactions/test_integration.py index 13b76f5c0..36fdecc1e 100644 --- a/google/genai/tests/interactions/test_integration.py +++ b/google/genai/tests/interactions/test_integration.py @@ -13,9 +13,13 @@ # limitations under the License. from unittest import mock + +from ..._gaos import google_genai as gaos_google_genai import pytest + from ... import client as client_lib + pytest_plugins = ("pytest_asyncio",) @@ -37,48 +41,50 @@ def test_client_future_warning(): def test_client_timeout(): with mock.patch.object( - client_lib, "GeminiNextGenAPIClient", spec_set=True - ) as mock_nextgen_client: + gaos_google_genai, "GenAI", spec_set=True + ) as mock_genai: + mock_client = mock.Mock() + mock_genai.return_value = mock_client client = client_lib.Client( api_key="placeholder", http_options={"api_version": "v1alpha", "timeout": 5000}, ) - _ = client.interactions + # Trigger client build + _ = client.interactions.with_raw_response - mock_nextgen_client.assert_called_once_with( - base_url=mock.ANY, - api_key="placeholder", - api_version="v1alpha", - default_headers=mock.ANY, - http_client=mock.ANY, - timeout=5.0, - max_retries=mock.ANY, - client_adapter=mock.ANY, + mock_genai.assert_called_once_with( + security=mock.ANY, + api_version=mock.ANY, + user_project=mock.ANY, + server_url=mock.ANY, + client=mock.ANY, + timeout_ms=5000, ) @pytest.mark.asyncio async def test_async_client_timeout(): with mock.patch.object( - client_lib, "AsyncGeminiNextGenAPIClient", spec_set=True - ) as mock_nextgen_client: + gaos_google_genai, "AsyncGenAI", spec_set=True + ) as mock_async_genai: + mock_client = mock.Mock() + mock_async_genai.return_value = mock_client client = client_lib.Client( api_key="placeholder", http_options={"api_version": "v1alpha", "timeout": 5000}, ) - _ = client.aio.interactions + # Trigger client build + _ = client.aio.interactions.with_raw_response - mock_nextgen_client.assert_called_once_with( - base_url=mock.ANY, - api_key="placeholder", - api_version="v1alpha", - default_headers=mock.ANY, - http_client=mock.ANY, - timeout=5.0, - max_retries=mock.ANY, - client_adapter=mock.ANY, + mock_async_genai.assert_called_once_with( + security=mock.ANY, + api_version=mock.ANY, + user_project=mock.ANY, + server_url=mock.ANY, + async_client=mock.ANY, + timeout_ms=5000, ) diff --git a/google/genai/tests/interactions/test_paths.py b/google/genai/tests/interactions/test_paths.py index 1e8f77000..ca4f70ffc 100644 --- a/google/genai/tests/interactions/test_paths.py +++ b/google/genai/tests/interactions/test_paths.py @@ -41,14 +41,14 @@ def test_interactions_paths(mock_auth_default, client): expected_base_url = "https://generativelanguage.googleapis.com/v1beta" with mock.patch.object(HTTPClient, "send") as mock_send: - mock_send.return_value = Response(200, request=Request('GET', '')) + mock_send.return_value = Response(200, request=Request('GET', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') client.interactions.get(id=interaction_id) mock_send.assert_called_once() request = mock_send.call_args[0][0] - assert str(request.url) == f'{expected_base_url}/interactions/{interaction_id}' + assert str(request.url) == f'{expected_base_url}/interactions/{interaction_id}?stream=false' mock_send.reset_mock() - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') client.interactions.cancel(id=interaction_id) mock_send.assert_called_once() request = mock_send.call_args[0][0] @@ -78,14 +78,14 @@ async def test_async_interactions_paths(mock_auth_default, client): expected_base_url = "https://generativelanguage.googleapis.com/v1beta" with mock.patch.object(AsyncHttpxClient, "send") as mock_send: - mock_send.return_value = Response(200, request=Request('GET', '')) + mock_send.return_value = Response(200, request=Request('GET', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') await client.aio.interactions.get(id=interaction_id) mock_send.assert_called_once() request = mock_send.call_args[0][0] - assert str(request.url) == f'{expected_base_url}/interactions/{interaction_id}' + assert str(request.url) == f'{expected_base_url}/interactions/{interaction_id}?stream=false' mock_send.reset_mock() - mock_send.return_value = Response(200, request=Request('POST', '')) + mock_send.return_value = Response(200, request=Request('POST', ''), headers={'content-type': 'application/json'}, content='{"status": "completed"}') await client.aio.interactions.cancel(id=interaction_id) mock_send.assert_called_once() request = mock_send.call_args[0][0]