diff --git a/.librarian/state.yaml b/.librarian/state.yaml index c8f1c6f1dcc2..6055130989ac 100644 --- a/.librarian/state.yaml +++ b/.librarian/state.yaml @@ -1960,7 +1960,7 @@ libraries: tag_format: '{id}-v{version}' - id: google-cloud-geminidataanalytics version: 0.5.0 - last_generated_commit: 3322511885371d2b2253f209ccc3aa60d4100cfd + last_generated_commit: cf0434f4bd20618db60ddd16a1e7db2c0dfb9158 apis: - path: google/cloud/geminidataanalytics/v1beta service_config: geminidataanalytics_v1beta.yaml diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics/__init__.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics/__init__.py index 10d0a351e95c..303b62cc4707 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics/__init__.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics/__init__.py @@ -35,6 +35,7 @@ ChartOptions, Context, ConversationOptions, + DatasourceOptions, ExampleQuery, GlossaryTerm, ) @@ -75,6 +76,7 @@ ChartQuery, ChartResult, ChatRequest, + ClientManagedResourceContext, ConversationReference, DataAgentContext, DataMessage, @@ -119,6 +121,7 @@ "ChartOptions", "Context", "ConversationOptions", + "DatasourceOptions", "ExampleQuery", "GlossaryTerm", "Conversation", @@ -149,6 +152,7 @@ "ChartQuery", "ChartResult", "ChatRequest", + "ClientManagedResourceContext", "ConversationReference", "DataAgentContext", "DataMessage", diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/__init__.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/__init__.py index 8dd21f9450cd..1e78c54e8873 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/__init__.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/__init__.py @@ -31,6 +31,7 @@ ChartOptions, Context, ConversationOptions, + DatasourceOptions, ExampleQuery, GlossaryTerm, ) @@ -66,6 +67,7 @@ ChartQuery, ChartResult, ChatRequest, + ClientManagedResourceContext, ConversationReference, DataAgentContext, DataMessage, @@ -117,6 +119,7 @@ "ChartQuery", "ChartResult", "ChatRequest", + "ClientManagedResourceContext", "Context", "Conversation", "ConversationOptions", @@ -135,6 +138,7 @@ "DataQuery", "DataResult", "Datasource", + "DatasourceOptions", "DatasourceReferences", "DeleteConversationRequest", "DeleteDataAgentRequest", diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/__init__.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/__init__.py index 3468c293f49c..9d500fc67339 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/__init__.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/__init__.py @@ -18,6 +18,7 @@ ChartOptions, Context, ConversationOptions, + DatasourceOptions, ExampleQuery, GlossaryTerm, ) @@ -53,6 +54,7 @@ ChartQuery, ChartResult, ChatRequest, + ClientManagedResourceContext, ConversationReference, DataAgentContext, DataMessage, @@ -93,6 +95,7 @@ "ChartOptions", "Context", "ConversationOptions", + "DatasourceOptions", "ExampleQuery", "GlossaryTerm", "Conversation", @@ -123,6 +126,7 @@ "ChartQuery", "ChartResult", "ChatRequest", + "ClientManagedResourceContext", "ConversationReference", "DataAgentContext", "DataMessage", diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/context.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/context.py index af3470fc67d0..ca754c493219 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/context.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/context.py @@ -17,9 +17,10 @@ from typing import MutableMapping, MutableSequence +from google.protobuf import wrappers_pb2 # type: ignore import proto # type: ignore -from google.cloud.geminidataanalytics_v1alpha.types import datasource +from google.cloud.geminidataanalytics_v1alpha.types import datasource as gcg_datasource __protobuf__ = proto.module( package="google.cloud.geminidataanalytics.v1alpha", @@ -28,6 +29,7 @@ "ExampleQuery", "GlossaryTerm", "ConversationOptions", + "DatasourceOptions", "ChartOptions", "AnalysisOptions", }, @@ -163,10 +165,10 @@ class SchemaPaths(proto.Message): proto.STRING, number=1, ) - datasource_references: datasource.DatasourceReferences = proto.Field( + datasource_references: gcg_datasource.DatasourceReferences = proto.Field( proto.MESSAGE, number=7, - message=datasource.DatasourceReferences, + message=gcg_datasource.DatasourceReferences, ) options: "ConversationOptions" = proto.Field( proto.MESSAGE, @@ -265,6 +267,8 @@ class ConversationOptions(proto.Message): Optional. Options for chart generation. analysis (google.cloud.geminidataanalytics_v1alpha.types.AnalysisOptions): Optional. Options for analysis. + datasource (google.cloud.geminidataanalytics_v1alpha.types.DatasourceOptions): + Optional. Options for datasources. """ chart: "ChartOptions" = proto.Field( @@ -277,6 +281,31 @@ class ConversationOptions(proto.Message): number=2, message="AnalysisOptions", ) + datasource: "DatasourceOptions" = proto.Field( + proto.MESSAGE, + number=3, + message="DatasourceOptions", + ) + + +class DatasourceOptions(proto.Message): + r"""Options for datasources configurations. + + Attributes: + big_query_max_billed_bytes (google.protobuf.wrappers_pb2.Int64Value): + Optional. This option applies to datasources + that require BigQuery queries only. Limits the + bytes billed for each BQ query job. Queries that + will have bytes billed beyond this limit will + fail (without incurring a charge). If + unspecified, no limit will be applied. + """ + + big_query_max_billed_bytes: wrappers_pb2.Int64Value = proto.Field( + proto.MESSAGE, + number=1, + message=wrappers_pb2.Int64Value, + ) class ChartOptions(proto.Message): diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/data_chat_service.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/data_chat_service.py index ff81dcf29401..a1be14c04e7a 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/data_chat_service.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/data_chat_service.py @@ -36,6 +36,7 @@ "ChatRequest", "DataAgentContext", "ConversationReference", + "ClientManagedResourceContext", "Message", "UserMessage", "SystemMessage", @@ -184,6 +185,14 @@ class ChatRequest(proto.Message): this to chat with an Agent statelessly, without managed conversation persistence. + This field is a member of `oneof`_ ``context_provider``. + client_managed_resource_context (google.cloud.geminidataanalytics_v1alpha.types.ClientManagedResourceContext): + Optional. Context with client managed + resources. Some clients may not use GDA managed + resources including conversations and agents, + instead they create and manage their own + conversations and agents resources. + This field is a member of `oneof`_ ``context_provider``. project (str): Optional. The Google Cloud project to be used @@ -213,6 +222,12 @@ class ChatRequest(proto.Message): oneof="context_provider", message="DataAgentContext", ) + client_managed_resource_context: "ClientManagedResourceContext" = proto.Field( + proto.MESSAGE, + number=105, + oneof="context_provider", + message="ClientManagedResourceContext", + ) project: str = proto.Field( proto.STRING, number=1, @@ -305,6 +320,39 @@ class ConversationReference(proto.Message): ) +class ClientManagedResourceContext(proto.Message): + r"""Context with client managed resources. + Some clients may not use GDA managed resources including + conversations and agents, instead they create and manage their + own conversations and agents resources. + + Attributes: + inline_context (google.cloud.geminidataanalytics_v1alpha.types.Context): + Required. Context for the chat request. Use + this to chat without GDA API managed + conversation and agent persistence by passing + all context inline. + conversation_id (str): + Optional. The client managed conversation id. + agent_id (str): + Optional. The client managed agent id. + """ + + inline_context: context.Context = proto.Field( + proto.MESSAGE, + number=1, + message=context.Context, + ) + conversation_id: str = proto.Field( + proto.STRING, + number=2, + ) + agent_id: str = proto.Field( + proto.STRING, + number=3, + ) + + class Message(proto.Message): r"""A message from an interaction between the user and the system. @@ -502,10 +550,17 @@ class TextType(proto.Enum): THOUGHT (2): The text is a thinking plan generated by the thinking tool. + PROGRESS (3): + The text is an informational message about the agent's + progress, such as a tool being invoked. This is distinct + from the agent's internal thought process (``THOUGHT``) and + the final answer to the user (``FINAL_RESPONSE``). These + messages provide insight into the agent's actions. """ TEXT_TYPE_UNSPECIFIED = 0 FINAL_RESPONSE = 1 THOUGHT = 2 + PROGRESS = 3 parts: MutableSequence[str] = proto.RepeatedField( proto.STRING, @@ -1112,7 +1167,21 @@ class ChartResult(proto.Message): class ErrorMessage(proto.Message): - r"""An error message. + r"""An error message from a tool call. This message is used to represent + an error that occurred while an agent was trying to use a tool. It's + important to note that not all errors are terminal. Many are + recoverable, and the agent may use the information from this error + message to self-correct and retry the tool call or try a different + approach. + + For example, if a data query fails, the agent might receive an + ``ErrorMessage``, analyze it, and then generate a corrected query. + + Clients should be cautious about interpreting this message as a + definitive failure. It can be part of the agent's normal, iterative + process of completing a task. Surfacing these errors directly to + end-users without context (e.g., as a "hard failure") may be + misleading. Attributes: text (str): diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/datasource.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/datasource.py index df7e6fdc3ea9..d9cbef726be8 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/datasource.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1alpha/types/datasource.py @@ -17,6 +17,7 @@ from typing import MutableMapping, MutableSequence +from google.protobuf import struct_pb2 # type: ignore import proto # type: ignore from google.cloud.geminidataanalytics_v1alpha.types import ( @@ -318,6 +319,14 @@ class Datasource(proto.Message): This field is a member of `oneof`_ ``reference``. schema (google.cloud.geminidataanalytics_v1alpha.types.Schema): Optional. The schema of the datasource. + struct_schema (google.protobuf.struct_pb2.Struct): + Optional. A struct representation of the schema. This is + populated for datasources with schemas that cannot be fully + represented by the strongly-typed ``schema`` field. + + For Looker datasources, this maps to the LookmlModelExplore + type: + https://cloud.google.com/looker/docs/reference/looker-api/latest/types/LookmlModelExplore """ bigquery_table_reference: "BigQueryTableReference" = proto.Field( @@ -342,6 +351,11 @@ class Datasource(proto.Message): number=7, message="Schema", ) + struct_schema: struct_pb2.Struct = proto.Field( + proto.MESSAGE, + number=10, + message=struct_pb2.Struct, + ) class Schema(proto.Message): diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/__init__.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/__init__.py index c697099bc86e..b9dac9880cfc 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/__init__.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/__init__.py @@ -31,11 +31,14 @@ ChartOptions, Context, ConversationOptions, + DatasourceOptions, ExampleQuery, + GlossaryTerm, ) from .types.conversation import ( Conversation, CreateConversationRequest, + DeleteConversationRequest, GetConversationRequest, ListConversationsRequest, ListConversationsResponse, @@ -64,12 +67,14 @@ ChartQuery, ChartResult, ChatRequest, + ClientManagedResourceContext, ConversationReference, DataAgentContext, DataMessage, DataQuery, DataResult, ErrorMessage, + ExampleQueries, ListMessagesRequest, ListMessagesResponse, LookerQuery, @@ -114,6 +119,7 @@ "ChartQuery", "ChartResult", "ChatRequest", + "ClientManagedResourceContext", "Context", "Conversation", "ConversationOptions", @@ -132,13 +138,17 @@ "DataQuery", "DataResult", "Datasource", + "DatasourceOptions", "DatasourceReferences", + "DeleteConversationRequest", "DeleteDataAgentRequest", "ErrorMessage", + "ExampleQueries", "ExampleQuery", "Field", "GetConversationRequest", "GetDataAgentRequest", + "GlossaryTerm", "ListAccessibleDataAgentsRequest", "ListAccessibleDataAgentsResponse", "ListConversationsRequest", diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/gapic_metadata.json b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/gapic_metadata.json index f920d380f3fe..524e15c03fa1 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/gapic_metadata.json +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/gapic_metadata.json @@ -159,6 +159,11 @@ "create_conversation" ] }, + "DeleteConversation": { + "methods": [ + "delete_conversation" + ] + }, "GetConversation": { "methods": [ "get_conversation" @@ -189,6 +194,11 @@ "create_conversation" ] }, + "DeleteConversation": { + "methods": [ + "delete_conversation" + ] + }, "GetConversation": { "methods": [ "get_conversation" @@ -219,6 +229,11 @@ "create_conversation" ] }, + "DeleteConversation": { + "methods": [ + "delete_conversation" + ] + }, "GetConversation": { "methods": [ "get_conversation" diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/async_client.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/async_client.py index 5a699fcb4199..dd7075b1c475 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/async_client.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/async_client.py @@ -539,6 +539,105 @@ async def sample_create_conversation(): # Done; return the response. return response + async def delete_conversation( + self, + request: Optional[Union[conversation.DeleteConversationRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), + ) -> None: + r"""Deletes a conversation. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import geminidataanalytics_v1beta + + async def sample_delete_conversation(): + # Create a client + client = geminidataanalytics_v1beta.DataChatServiceAsyncClient() + + # Initialize request argument(s) + request = geminidataanalytics_v1beta.DeleteConversationRequest( + name="name_value", + ) + + # Make the request + await client.delete_conversation(request=request) + + Args: + request (Optional[Union[google.cloud.geminidataanalytics_v1beta.types.DeleteConversationRequest, dict]]): + The request object. Request for deleting a conversation + based on parent and conversation id. + name (:class:`str`): + Required. Name of the resource. Format: + ``projects/{project}/locations/{location}/conversations/{conversation}`` + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. + """ + # Create or coerce a protobuf request object. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + flattened_params = [name] + has_flattened_params = ( + len([param for param in flattened_params if param is not None]) > 0 + ) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, conversation.DeleteConversationRequest): + request = conversation.DeleteConversationRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._client._transport._wrapped_methods[ + self._client._transport.delete_conversation + ] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Validate the universe domain. + self._client._validate_universe_domain() + + # Send the request. + await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + async def get_conversation( self, request: Optional[Union[conversation.GetConversationRequest, dict]] = None, diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/client.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/client.py index eccbcf66ef24..88f55b009f0f 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/client.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/client.py @@ -976,6 +976,102 @@ def sample_create_conversation(): # Done; return the response. return response + def delete_conversation( + self, + request: Optional[Union[conversation.DeleteConversationRequest, dict]] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), + ) -> None: + r"""Deletes a conversation. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import geminidataanalytics_v1beta + + def sample_delete_conversation(): + # Create a client + client = geminidataanalytics_v1beta.DataChatServiceClient() + + # Initialize request argument(s) + request = geminidataanalytics_v1beta.DeleteConversationRequest( + name="name_value", + ) + + # Make the request + client.delete_conversation(request=request) + + Args: + request (Union[google.cloud.geminidataanalytics_v1beta.types.DeleteConversationRequest, dict]): + The request object. Request for deleting a conversation + based on parent and conversation id. + name (str): + Required. Name of the resource. Format: + ``projects/{project}/locations/{location}/conversations/{conversation}`` + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. + """ + # Create or coerce a protobuf request object. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + flattened_params = [name] + has_flattened_params = ( + len([param for param in flattened_params if param is not None]) > 0 + ) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, conversation.DeleteConversationRequest): + request = conversation.DeleteConversationRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.delete_conversation] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Validate the universe domain. + self._validate_universe_domain() + + # Send the request. + rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + def get_conversation( self, request: Optional[Union[conversation.GetConversationRequest, dict]] = None, diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/base.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/base.py index 3d5f027d24ad..3394f80cdd3c 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/base.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/base.py @@ -26,6 +26,7 @@ from google.longrunning import operations_pb2 # type: ignore from google.oauth2 import service_account # type: ignore import google.protobuf +from google.protobuf import empty_pb2 # type: ignore from google.cloud.geminidataanalytics_v1beta import gapic_version as package_version from google.cloud.geminidataanalytics_v1beta.types import ( @@ -149,6 +150,11 @@ def _prep_wrapped_messages(self, client_info): default_timeout=None, client_info=client_info, ), + self.delete_conversation: gapic_v1.method.wrap_method( + self.delete_conversation, + default_timeout=None, + client_info=client_info, + ), self.get_conversation: gapic_v1.method.wrap_method( self.get_conversation, default_timeout=None, @@ -223,6 +229,15 @@ def create_conversation( ]: raise NotImplementedError() + @property + def delete_conversation( + self, + ) -> Callable[ + [conversation.DeleteConversationRequest], + Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]], + ]: + raise NotImplementedError() + @property def get_conversation( self, diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc.py index 42a17adafa83..d85d84b0d216 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc.py @@ -25,6 +25,7 @@ from google.auth.transport.grpc import SslCredentials # type: ignore from google.cloud.location import locations_pb2 # type: ignore from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore from google.protobuf.json_format import MessageToJson import google.protobuf.message import grpc # type: ignore @@ -387,6 +388,32 @@ def create_conversation( ) return self._stubs["create_conversation"] + @property + def delete_conversation( + self, + ) -> Callable[[conversation.DeleteConversationRequest], empty_pb2.Empty]: + r"""Return a callable for the delete conversation method over gRPC. + + Deletes a conversation. + + Returns: + Callable[[~.DeleteConversationRequest], + ~.Empty]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_conversation" not in self._stubs: + self._stubs["delete_conversation"] = self._logged_channel.unary_unary( + "/google.cloud.geminidataanalytics.v1beta.DataChatService/DeleteConversation", + request_serializer=conversation.DeleteConversationRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_conversation"] + @property def get_conversation( self, diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc_asyncio.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc_asyncio.py index fed2142846e6..b1f968a26fa3 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc_asyncio.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc_asyncio.py @@ -27,6 +27,7 @@ from google.auth.transport.grpc import SslCredentials # type: ignore from google.cloud.location import locations_pb2 # type: ignore from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore from google.protobuf.json_format import MessageToJson import google.protobuf.message import grpc # type: ignore @@ -398,6 +399,32 @@ def create_conversation( ) return self._stubs["create_conversation"] + @property + def delete_conversation( + self, + ) -> Callable[[conversation.DeleteConversationRequest], Awaitable[empty_pb2.Empty]]: + r"""Return a callable for the delete conversation method over gRPC. + + Deletes a conversation. + + Returns: + Callable[[~.DeleteConversationRequest], + Awaitable[~.Empty]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "delete_conversation" not in self._stubs: + self._stubs["delete_conversation"] = self._logged_channel.unary_unary( + "/google.cloud.geminidataanalytics.v1beta.DataChatService/DeleteConversation", + request_serializer=conversation.DeleteConversationRequest.serialize, + response_deserializer=empty_pb2.Empty.FromString, + ) + return self._stubs["delete_conversation"] + @property def get_conversation( self, @@ -498,6 +525,11 @@ def _prep_wrapped_messages(self, client_info): default_timeout=None, client_info=client_info, ), + self.delete_conversation: self._wrap_method( + self.delete_conversation, + default_timeout=None, + client_info=client_info, + ), self.get_conversation: self._wrap_method( self.get_conversation, default_timeout=None, diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/rest.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/rest.py index cf83934ebb25..aaa0549141ba 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/rest.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/rest.py @@ -27,6 +27,7 @@ from google.cloud.location import locations_pb2 # type: ignore from google.longrunning import operations_pb2 # type: ignore import google.protobuf +from google.protobuf import empty_pb2 # type: ignore from google.protobuf import json_format from requests import __version__ as requests_version @@ -94,6 +95,10 @@ def post_create_conversation(self, response): logging.log(f"Received response: {response}") return response + def pre_delete_conversation(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + def pre_get_conversation(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata @@ -221,6 +226,20 @@ def post_create_conversation_with_metadata( """ return response, metadata + def pre_delete_conversation( + self, + request: conversation.DeleteConversationRequest, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + conversation.DeleteConversationRequest, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Pre-rpc interceptor for delete_conversation + + Override in a subclass to manipulate the request or metadata + before they are sent to the DataChatService server. + """ + return request, metadata + def pre_get_conversation( self, request: conversation.GetConversationRequest, @@ -903,6 +922,116 @@ def __call__( ) return resp + class _DeleteConversation( + _BaseDataChatServiceRestTransport._BaseDeleteConversation, + DataChatServiceRestStub, + ): + def __hash__(self): + return hash("DataChatServiceRestTransport.DeleteConversation") + + @staticmethod + def _get_response( + host, + metadata, + query_params, + session, + timeout, + transcoded_request, + body=None, + ): + uri = transcoded_request["uri"] + method = transcoded_request["method"] + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(session, method)( + "{host}{uri}".format(host=host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + ) + return response + + def __call__( + self, + request: conversation.DeleteConversationRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), + ): + r"""Call the delete conversation method over HTTP. + + Args: + request (~.conversation.DeleteConversationRequest): + The request object. Request for deleting a conversation + based on parent and conversation id. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. + """ + + http_options = ( + _BaseDataChatServiceRestTransport._BaseDeleteConversation._get_http_options() + ) + + request, metadata = self._interceptor.pre_delete_conversation( + request, metadata + ) + transcoded_request = _BaseDataChatServiceRestTransport._BaseDeleteConversation._get_transcoded_request( + http_options, request + ) + + # Jsonify the query params + query_params = _BaseDataChatServiceRestTransport._BaseDeleteConversation._get_query_params_json( + transcoded_request + ) + + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = json_format.MessageToJson(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.cloud.geminidataanalytics_v1beta.DataChatServiceClient.DeleteConversation", + extra={ + "serviceName": "google.cloud.geminidataanalytics.v1beta.DataChatService", + "rpcName": "DeleteConversation", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + + # Send the request + response = DataChatServiceRestTransport._DeleteConversation._get_response( + self._host, + metadata, + query_params, + self._session, + timeout, + transcoded_request, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + class _GetConversation( _BaseDataChatServiceRestTransport._BaseGetConversation, DataChatServiceRestStub ): @@ -1367,6 +1496,14 @@ def create_conversation( # In C++ this would require a dynamic_cast return self._CreateConversation(self._session, self._host, self._interceptor) # type: ignore + @property + def delete_conversation( + self, + ) -> Callable[[conversation.DeleteConversationRequest], empty_pb2.Empty]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._DeleteConversation(self._session, self._host, self._interceptor) # type: ignore + @property def get_conversation( self, diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/rest_base.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/rest_base.py index 72f6c38c17df..66efa053783a 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/rest_base.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/rest_base.py @@ -20,6 +20,7 @@ from google.api_core import gapic_v1, path_template from google.cloud.location import locations_pb2 # type: ignore from google.longrunning import operations_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore from google.protobuf import json_format from google.cloud.geminidataanalytics_v1beta.types import ( @@ -207,6 +208,53 @@ def _get_query_params_json(transcoded_request): query_params["$alt"] = "json;enum-encoding=int" return query_params + class _BaseDeleteConversation: + def __hash__(self): # pragma: NO COVER + return NotImplementedError("__hash__ must be implemented.") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + @staticmethod + def _get_http_options(): + http_options: List[Dict[str, str]] = [ + { + "method": "delete", + "uri": "/v1beta/{name=projects/*/locations/*/conversations/*}", + }, + ] + return http_options + + @staticmethod + def _get_transcoded_request(http_options, request): + pb_request = conversation.DeleteConversationRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + return transcoded_request + + @staticmethod + def _get_query_params_json(transcoded_request): + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + use_integers_for_enums=True, + ) + ) + query_params.update( + _BaseDataChatServiceRestTransport._BaseDeleteConversation._get_unset_required_fields( + query_params + ) + ) + + query_params["$alt"] = "json;enum-encoding=int" + return query_params + class _BaseGetConversation: def __hash__(self): # pragma: NO COVER return NotImplementedError("__hash__ must be implemented.") diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/__init__.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/__init__.py index 533167fa6afe..9d500fc67339 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/__init__.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/__init__.py @@ -18,11 +18,14 @@ ChartOptions, Context, ConversationOptions, + DatasourceOptions, ExampleQuery, + GlossaryTerm, ) from .conversation import ( Conversation, CreateConversationRequest, + DeleteConversationRequest, GetConversationRequest, ListConversationsRequest, ListConversationsResponse, @@ -51,12 +54,14 @@ ChartQuery, ChartResult, ChatRequest, + ClientManagedResourceContext, ConversationReference, DataAgentContext, DataMessage, DataQuery, DataResult, ErrorMessage, + ExampleQueries, ListMessagesRequest, ListMessagesResponse, LookerQuery, @@ -90,9 +95,12 @@ "ChartOptions", "Context", "ConversationOptions", + "DatasourceOptions", "ExampleQuery", + "GlossaryTerm", "Conversation", "CreateConversationRequest", + "DeleteConversationRequest", "GetConversationRequest", "ListConversationsRequest", "ListConversationsResponse", @@ -118,12 +126,14 @@ "ChartQuery", "ChartResult", "ChatRequest", + "ClientManagedResourceContext", "ConversationReference", "DataAgentContext", "DataMessage", "DataQuery", "DataResult", "ErrorMessage", + "ExampleQueries", "ListMessagesRequest", "ListMessagesResponse", "LookerQuery", diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/context.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/context.py index 666918ac88bb..d6612de8bb95 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/context.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/context.py @@ -17,16 +17,19 @@ from typing import MutableMapping, MutableSequence +from google.protobuf import wrappers_pb2 # type: ignore import proto # type: ignore -from google.cloud.geminidataanalytics_v1beta.types import datasource +from google.cloud.geminidataanalytics_v1beta.types import datasource as gcg_datasource __protobuf__ = proto.module( package="google.cloud.geminidataanalytics.v1beta", manifest={ "Context", "ExampleQuery", + "GlossaryTerm", "ConversationOptions", + "DatasourceOptions", "ChartOptions", "AnalysisOptions", }, @@ -56,17 +59,116 @@ class Context(proto.Message): Optional. A list of example queries, providing examples of relevant and commonly used SQL queries and their corresponding natural - language queries optionally present. + language queries optionally present. Currently + only used for BigQuery data sources. + glossary_terms (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.GlossaryTerm]): + Optional. Term definitions (currently, only + user authored) + schema_relationships (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.Context.SchemaRelationship]): + Optional. Relationships between table schema, + including referencing and referenced columns. """ + class SchemaRelationship(proto.Message): + r"""The relationship between two tables, including referencing + and referenced columns. This is a derived context retrieved from + Dataplex Dataset Insights. + + Attributes: + left_schema_paths (google.cloud.geminidataanalytics_v1beta.types.Context.SchemaRelationship.SchemaPaths): + An ordered list of fields for the join from the first table. + The size of this list must be the same as + ``right_schema_paths``. Each field at index i in this list + must correspond to a field at the same index in the + ``right_schema_paths`` list. + right_schema_paths (google.cloud.geminidataanalytics_v1beta.types.Context.SchemaRelationship.SchemaPaths): + An ordered list of fields for the join from the second + table. The size of this list must be the same as + ``left_schema_paths``. Each field at index i in this list + must correspond to a field at the same index in the + ``left_schema_paths`` list. + sources (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.Context.SchemaRelationship.Source]): + Sources which generated the schema relation + edge. + confidence_score (float): + A confidence score for the suggested + relationship. Manually added edges have the + highest confidence score. + """ + + class Source(proto.Enum): + r"""Source which generated the schema relation edge. + + Values: + SOURCE_UNSPECIFIED (0): + The source of the schema relationship is + unspecified. + BIGQUERY_JOB_HISTORY (1): + The source of the schema relationship is + BigQuery job history. + LLM_SUGGESTED (2): + The source of the schema relationship is LLM + suggested. + BIGQUERY_TABLE_CONSTRAINTS (3): + The source of the schema relationship is + BigQuery table constraints. + """ + SOURCE_UNSPECIFIED = 0 + BIGQUERY_JOB_HISTORY = 1 + LLM_SUGGESTED = 2 + BIGQUERY_TABLE_CONSTRAINTS = 3 + + class SchemaPaths(proto.Message): + r"""Represents an ordered set of paths within the table schema. + + Attributes: + table_fqn (str): + The service-qualified full resource name of the table Ex: + bigquery.googleapis.com/projects/PROJECT_ID/datasets/DATASET_ID/tables/TABLE_ID + paths (MutableSequence[str]): + The ordered list of paths within the table + schema. + """ + + table_fqn: str = proto.Field( + proto.STRING, + number=1, + ) + paths: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=2, + ) + + left_schema_paths: "Context.SchemaRelationship.SchemaPaths" = proto.Field( + proto.MESSAGE, + number=1, + message="Context.SchemaRelationship.SchemaPaths", + ) + right_schema_paths: "Context.SchemaRelationship.SchemaPaths" = proto.Field( + proto.MESSAGE, + number=2, + message="Context.SchemaRelationship.SchemaPaths", + ) + sources: MutableSequence[ + "Context.SchemaRelationship.Source" + ] = proto.RepeatedField( + proto.ENUM, + number=3, + enum="Context.SchemaRelationship.Source", + ) + confidence_score: float = proto.Field( + proto.FLOAT, + number=4, + ) + system_instruction: str = proto.Field( proto.STRING, number=1, ) - datasource_references: datasource.DatasourceReferences = proto.Field( + datasource_references: gcg_datasource.DatasourceReferences = proto.Field( proto.MESSAGE, number=7, - message=datasource.DatasourceReferences, + message=gcg_datasource.DatasourceReferences, ) options: "ConversationOptions" = proto.Field( proto.MESSAGE, @@ -78,11 +180,22 @@ class Context(proto.Message): number=5, message="ExampleQuery", ) + glossary_terms: MutableSequence["GlossaryTerm"] = proto.RepeatedField( + proto.MESSAGE, + number=8, + message="GlossaryTerm", + ) + schema_relationships: MutableSequence[SchemaRelationship] = proto.RepeatedField( + proto.MESSAGE, + number=9, + message=SchemaRelationship, + ) class ExampleQuery(proto.Message): r"""Example of relevant and commonly used SQL query and its corresponding natural language queries optionally present. + Currently only used for BigQuery data sources. .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields @@ -112,6 +225,40 @@ class ExampleQuery(proto.Message): ) +class GlossaryTerm(proto.Message): + r"""Definition of a term within a specific domain. + + Attributes: + display_name (str): + Required. User friendly display name of the + glossary term being defined. For example: "CTR", + "conversion rate", "pending". + description (str): + Required. The description or meaning of the + term. For example: "Click-through rate", "The + percentage of users who complete a desired + action", "An order that is waiting to be + processed.". + labels (MutableSequence[str]): + Optional. A list of general purpose labels associated to + this term. For example: ["click rate", "clickthrough", + "waiting"] + """ + + display_name: str = proto.Field( + proto.STRING, + number=1, + ) + description: str = proto.Field( + proto.STRING, + number=2, + ) + labels: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=3, + ) + + class ConversationOptions(proto.Message): r"""Options for the conversation. @@ -120,6 +267,8 @@ class ConversationOptions(proto.Message): Optional. Options for chart generation. analysis (google.cloud.geminidataanalytics_v1beta.types.AnalysisOptions): Optional. Options for analysis. + datasource (google.cloud.geminidataanalytics_v1beta.types.DatasourceOptions): + Optional. Options for datasources. """ chart: "ChartOptions" = proto.Field( @@ -132,6 +281,31 @@ class ConversationOptions(proto.Message): number=2, message="AnalysisOptions", ) + datasource: "DatasourceOptions" = proto.Field( + proto.MESSAGE, + number=3, + message="DatasourceOptions", + ) + + +class DatasourceOptions(proto.Message): + r"""Options for datasources configurations. + + Attributes: + big_query_max_billed_bytes (google.protobuf.wrappers_pb2.Int64Value): + Optional. This option applies to datasources + that require BigQuery queries only. Limits the + bytes billed for each BQ query job. Queries that + will have bytes billed beyond this limit will + fail (without incurring a charge). If + unspecified, no limit will be applied. + """ + + big_query_max_billed_bytes: wrappers_pb2.Int64Value = proto.Field( + proto.MESSAGE, + number=1, + message=wrappers_pb2.Int64Value, + ) class ChartOptions(proto.Message): diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/conversation.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/conversation.py index c8dc679d12f9..5f580fe785e0 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/conversation.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/conversation.py @@ -28,6 +28,7 @@ "GetConversationRequest", "ListConversationsRequest", "ListConversationsResponse", + "DeleteConversationRequest", }, ) @@ -45,7 +46,7 @@ class Conversation(proto.Message): https://google.aip.dev/122#resource-id-segments Example: - ``projects/1234567890/locations/us-central1/conversations/my-conversation``. + ``projects/1234567890/locations/global/conversations/my-conversation``. It is recommended to skip setting this field during conversation creation as it will be inferred automatically @@ -172,7 +173,7 @@ class ListConversationsRequest(proto.Message): specified within the filter. ListConversations allows filtering by: - - agent_id + - agents - labels """ @@ -220,4 +221,20 @@ def raw_page(self): ) +class DeleteConversationRequest(proto.Message): + r"""Request for deleting a conversation based on parent and + conversation id. + + Attributes: + name (str): + Required. Name of the resource. Format: + ``projects/{project}/locations/{location}/conversations/{conversation}`` + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_agent.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_agent.py index 9b05a8620108..a7a1f32f4273 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_agent.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_agent.py @@ -51,7 +51,7 @@ class DataAgent(proto.Message): https://google.aip.dev/122#resource-id-segments Example: - ``projects/1234567890/locations/us-central1/dataAgents/my-agent``. + ``projects/1234567890/locations/global/dataAgents/my-agent``. It is recommended to skip setting this field during agent creation as it will be inferred automatically and diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_chat_service.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_chat_service.py index 5078f2ef8053..0393223f14a6 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_chat_service.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_chat_service.py @@ -34,6 +34,7 @@ "ChatRequest", "DataAgentContext", "ConversationReference", + "ClientManagedResourceContext", "Message", "UserMessage", "SystemMessage", @@ -53,6 +54,7 @@ "ChartQuery", "ChartResult", "ErrorMessage", + "ExampleQueries", "Blob", }, ) @@ -181,6 +183,14 @@ class ChatRequest(proto.Message): this to chat with an Agent statelessly, without managed conversation persistence. + This field is a member of `oneof`_ ``context_provider``. + client_managed_resource_context (google.cloud.geminidataanalytics_v1beta.types.ClientManagedResourceContext): + Optional. Context with client managed + resources. Some clients may not use GDA managed + resources including conversations and agents, + instead they create and manage their own + conversations and agents resources. + This field is a member of `oneof`_ ``context_provider``. project (str): Optional. The Google Cloud project to be used @@ -210,6 +220,12 @@ class ChatRequest(proto.Message): oneof="context_provider", message="DataAgentContext", ) + client_managed_resource_context: "ClientManagedResourceContext" = proto.Field( + proto.MESSAGE, + number=105, + oneof="context_provider", + message="ClientManagedResourceContext", + ) project: str = proto.Field( proto.STRING, number=1, @@ -302,6 +318,39 @@ class ConversationReference(proto.Message): ) +class ClientManagedResourceContext(proto.Message): + r"""Context with client managed resources. + Some clients may not use GDA managed resources including + conversations and agents, instead they create and manage their + own conversations and agents resources. + + Attributes: + inline_context (google.cloud.geminidataanalytics_v1beta.types.Context): + Required. Context for the chat request. Use + this to chat without GDA API managed + conversation and agent persistence by passing + all context inline. + conversation_id (str): + Optional. The client managed conversation id. + agent_id (str): + Optional. The client managed agent id. + """ + + inline_context: context.Context = proto.Field( + proto.MESSAGE, + number=1, + message=context.Context, + ) + conversation_id: str = proto.Field( + proto.STRING, + number=2, + ) + agent_id: str = proto.Field( + proto.STRING, + number=3, + ) + + class Message(proto.Message): r"""A message from an interaction between the user and the system. @@ -413,6 +462,11 @@ class SystemMessage(proto.Message): error (google.cloud.geminidataanalytics_v1beta.types.ErrorMessage): An error message. + This field is a member of `oneof`_ ``kind``. + example_queries (google.cloud.geminidataanalytics_v1beta.types.ExampleQueries): + Optional. A message containing example + queries. + This field is a member of `oneof`_ ``kind``. group_id (int): Identifies the group that the event belongs @@ -459,6 +513,12 @@ class SystemMessage(proto.Message): oneof="kind", message="ErrorMessage", ) + example_queries: "ExampleQueries" = proto.Field( + proto.MESSAGE, + number=13, + oneof="kind", + message="ExampleQueries", + ) group_id: int = proto.Field( proto.INT32, number=12, @@ -472,12 +532,43 @@ class TextMessage(proto.Message): Attributes: parts (MutableSequence[str]): Optional. The parts of the message. + text_type (google.cloud.geminidataanalytics_v1beta.types.TextMessage.TextType): + Optional. The type of the text message. """ + class TextType(proto.Enum): + r"""The type of the text message. + + Values: + TEXT_TYPE_UNSPECIFIED (0): + The default text type. + FINAL_RESPONSE (1): + The text is a final response to the user + question. + THOUGHT (2): + The text is a thinking plan generated by the + thinking tool. + PROGRESS (3): + The text is an informational message about the agent's + progress, such as a tool being invoked. This is distinct + from the agent's internal thought process (``THOUGHT``) and + the final answer to the user (``FINAL_RESPONSE``). These + messages provide insight into the agent's actions. + """ + TEXT_TYPE_UNSPECIFIED = 0 + FINAL_RESPONSE = 1 + THOUGHT = 2 + PROGRESS = 3 + parts: MutableSequence[str] = proto.RepeatedField( proto.STRING, number=1, ) + text_type: TextType = proto.Field( + proto.ENUM, + number=2, + enum=TextType, + ) class SchemaMessage(proto.Message): @@ -572,7 +663,8 @@ class DataMessage(proto.Message): This field is a member of `oneof`_ ``kind``. generated_looker_query (google.cloud.geminidataanalytics_v1beta.types.LookerQuery): Looker Query generated by the system to - retrieve data. + retrieve data. DEPRECATED: generated looker + query is now under DataQuery.looker. This field is a member of `oneof`_ ``kind``. big_query_job (google.cloud.geminidataanalytics_v1beta.types.BigQueryJob): @@ -691,7 +783,14 @@ class Filter(proto.Message): class DataQuery(proto.Message): r"""A query for retrieving data. + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + Attributes: + looker (google.cloud.geminidataanalytics_v1beta.types.LookerQuery): + Optional. A query for retrieving data from a + Looker explore. + + This field is a member of `oneof`_ ``query_type``. question (str): Optional. A natural language question to answer. @@ -707,6 +806,12 @@ class DataQuery(proto.Message): the question. """ + looker: "LookerQuery" = proto.Field( + proto.MESSAGE, + number=4, + oneof="query_type", + message="LookerQuery", + ) question: str = proto.Field( proto.STRING, number=1, @@ -1060,7 +1165,21 @@ class ChartResult(proto.Message): class ErrorMessage(proto.Message): - r"""An error message. + r"""An error message from a tool call. This message is used to represent + an error that occurred while an agent was trying to use a tool. It's + important to note that not all errors are terminal. Many are + recoverable, and the agent may use the information from this error + message to self-correct and retry the tool call or try a different + approach. + + For example, if a data query fails, the agent might receive an + ``ErrorMessage``, analyze it, and then generate a corrected query. + + Clients should be cautious about interpreting this message as a + definitive failure. It can be part of the agent's normal, iterative + process of completing a task. Surfacing these errors directly to + end-users without context (e.g., as a "hard failure") may be + misleading. Attributes: text (str): @@ -1073,6 +1192,26 @@ class ErrorMessage(proto.Message): ) +class ExampleQueries(proto.Message): + r"""A message containing derived and authored example queries. + + Attributes: + example_queries (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.ExampleQuery]): + Optional. A list of derived and authored + example queries, providing examples of relevant + and commonly used SQL queries and their + corresponding natural language queries + optionally present. Currently only used for + BigQuery data sources. + """ + + example_queries: MutableSequence[context.ExampleQuery] = proto.RepeatedField( + proto.MESSAGE, + number=1, + message=context.ExampleQuery, + ) + + class Blob(proto.Message): r"""A blob of data with a MIME type. diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/datasource.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/datasource.py index 828259352b49..10099c65f190 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/datasource.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/datasource.py @@ -17,6 +17,7 @@ from typing import MutableMapping, MutableSequence +from google.protobuf import struct_pb2 # type: ignore import proto # type: ignore from google.cloud.geminidataanalytics_v1beta.types import credentials as gcg_credentials @@ -316,6 +317,14 @@ class Datasource(proto.Message): This field is a member of `oneof`_ ``reference``. schema (google.cloud.geminidataanalytics_v1beta.types.Schema): Optional. The schema of the datasource. + struct_schema (google.protobuf.struct_pb2.Struct): + Optional. A struct representation of the schema. This is + populated for datasources with schemas that cannot be fully + represented by the strongly-typed ``schema`` field. + + For Looker datasources, this maps to the LookmlModelExplore + type: + https://cloud.google.com/looker/docs/reference/looker-api/latest/types/LookmlModelExplore """ bigquery_table_reference: "BigQueryTableReference" = proto.Field( @@ -340,6 +349,11 @@ class Datasource(proto.Message): number=7, message="Schema", ) + struct_schema: struct_pb2.Struct = proto.Field( + proto.MESSAGE, + number=10, + message=struct_pb2.Struct, + ) class Schema(proto.Message): @@ -352,15 +366,18 @@ class Schema(proto.Message): Optional. A textual description of the table's content and purpose. For example: "Contains information about customer orders in - our e-commerce store.". + our e-commerce store." Currently only used for + BigQuery data sources. synonyms (MutableSequence[str]): Optional. A list of alternative names or synonyms that can be used to refer to the table. For example: ["sales", - "orders", "purchases"] + "orders", "purchases"]. Currently only used for BigQuery + data sources. tags (MutableSequence[str]): Optional. A list of tags or keywords associated with the table, used for categorization. For example: ["transaction", - "revenue", "customer_data"] + "revenue", "customer_data"]. Currently only used for + BigQuery data sources. display_name (str): Optional. Table display_name (same as label in cloud/data_analytics/anarres/data/looker/proto/model_explore.proto), @@ -415,11 +432,13 @@ class Field(proto.Message): synonyms (MutableSequence[str]): Optional. A list of alternative names or synonyms that can be used to refer to this field. For example: ["id", - "customerid", "cust_id"] + "customerid", "cust_id"]. Currently only used for BigQuery + data sources. tags (MutableSequence[str]): Optional. A list of tags or keywords associated with the field, used for categorization. For example: ["identifier", - "customer", "pii"] + "customer", "pii"]. Currently only used for BigQuery data + sources. display_name (str): Optional. Field display_name (same as label in subfields (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.Field]): diff --git a/packages/google-cloud-geminidataanalytics/samples/generated_samples/geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_async.py b/packages/google-cloud-geminidataanalytics/samples/generated_samples/geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_async.py new file mode 100644 index 000000000000..59c2eb8b07f4 --- /dev/null +++ b/packages/google-cloud-geminidataanalytics/samples/generated_samples/geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_async.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for DeleteConversation +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-geminidataanalytics + + +# [START geminidataanalytics_v1beta_generated_DataChatService_DeleteConversation_async] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import geminidataanalytics_v1beta + + +async def sample_delete_conversation(): + # Create a client + client = geminidataanalytics_v1beta.DataChatServiceAsyncClient() + + # Initialize request argument(s) + request = geminidataanalytics_v1beta.DeleteConversationRequest( + name="name_value", + ) + + # Make the request + await client.delete_conversation(request=request) + + +# [END geminidataanalytics_v1beta_generated_DataChatService_DeleteConversation_async] diff --git a/packages/google-cloud-geminidataanalytics/samples/generated_samples/geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_sync.py b/packages/google-cloud-geminidataanalytics/samples/generated_samples/geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_sync.py new file mode 100644 index 000000000000..f51380f872ce --- /dev/null +++ b/packages/google-cloud-geminidataanalytics/samples/generated_samples/geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_sync.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for DeleteConversation +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-geminidataanalytics + + +# [START geminidataanalytics_v1beta_generated_DataChatService_DeleteConversation_sync] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import geminidataanalytics_v1beta + + +def sample_delete_conversation(): + # Create a client + client = geminidataanalytics_v1beta.DataChatServiceClient() + + # Initialize request argument(s) + request = geminidataanalytics_v1beta.DeleteConversationRequest( + name="name_value", + ) + + # Make the request + client.delete_conversation(request=request) + + +# [END geminidataanalytics_v1beta_generated_DataChatService_DeleteConversation_sync] diff --git a/packages/google-cloud-geminidataanalytics/samples/generated_samples/snippet_metadata_google.cloud.geminidataanalytics.v1beta.json b/packages/google-cloud-geminidataanalytics/samples/generated_samples/snippet_metadata_google.cloud.geminidataanalytics.v1beta.json index ad889a0335a2..dbb87d821127 100644 --- a/packages/google-cloud-geminidataanalytics/samples/generated_samples/snippet_metadata_google.cloud.geminidataanalytics.v1beta.json +++ b/packages/google-cloud-geminidataanalytics/samples/generated_samples/snippet_metadata_google.cloud.geminidataanalytics.v1beta.json @@ -1653,6 +1653,161 @@ ], "title": "geminidataanalytics_v1beta_generated_data_chat_service_create_conversation_sync.py" }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.geminidataanalytics_v1beta.DataChatServiceAsyncClient", + "shortName": "DataChatServiceAsyncClient" + }, + "fullName": "google.cloud.geminidataanalytics_v1beta.DataChatServiceAsyncClient.delete_conversation", + "method": { + "fullName": "google.cloud.geminidataanalytics.v1beta.DataChatService.DeleteConversation", + "service": { + "fullName": "google.cloud.geminidataanalytics.v1beta.DataChatService", + "shortName": "DataChatService" + }, + "shortName": "DeleteConversation" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.geminidataanalytics_v1beta.types.DeleteConversationRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, Union[str, bytes]]]" + } + ], + "shortName": "delete_conversation" + }, + "description": "Sample for DeleteConversation", + "file": "geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "geminidataanalytics_v1beta_generated_DataChatService_DeleteConversation_async", + "segments": [ + { + "end": 49, + "start": 27, + "type": "FULL" + }, + { + "end": 49, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 50, + "type": "RESPONSE_HANDLING" + } + ], + "title": "geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.geminidataanalytics_v1beta.DataChatServiceClient", + "shortName": "DataChatServiceClient" + }, + "fullName": "google.cloud.geminidataanalytics_v1beta.DataChatServiceClient.delete_conversation", + "method": { + "fullName": "google.cloud.geminidataanalytics.v1beta.DataChatService.DeleteConversation", + "service": { + "fullName": "google.cloud.geminidataanalytics.v1beta.DataChatService", + "shortName": "DataChatService" + }, + "shortName": "DeleteConversation" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.geminidataanalytics_v1beta.types.DeleteConversationRequest" + }, + { + "name": "name", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, Union[str, bytes]]]" + } + ], + "shortName": "delete_conversation" + }, + "description": "Sample for DeleteConversation", + "file": "geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "geminidataanalytics_v1beta_generated_DataChatService_DeleteConversation_sync", + "segments": [ + { + "end": 49, + "start": 27, + "type": "FULL" + }, + { + "end": 49, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 50, + "type": "RESPONSE_HANDLING" + } + ], + "title": "geminidataanalytics_v1beta_generated_data_chat_service_delete_conversation_sync.py" + }, { "canonical": true, "clientMethod": { diff --git a/packages/google-cloud-geminidataanalytics/scripts/fixup_geminidataanalytics_v1alpha_keywords.py b/packages/google-cloud-geminidataanalytics/scripts/fixup_geminidataanalytics_v1alpha_keywords.py index a339a2afd4e4..3c06bb5bbcf7 100644 --- a/packages/google-cloud-geminidataanalytics/scripts/fixup_geminidataanalytics_v1alpha_keywords.py +++ b/packages/google-cloud-geminidataanalytics/scripts/fixup_geminidataanalytics_v1alpha_keywords.py @@ -39,7 +39,7 @@ def partition( class geminidataanalyticsCallTransformer(cst.CSTTransformer): CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { - 'chat': ('parent', 'messages', 'inline_context', 'conversation_reference', 'data_agent_context', 'project', ), + 'chat': ('parent', 'messages', 'inline_context', 'conversation_reference', 'data_agent_context', 'client_managed_resource_context', 'project', ), 'create_conversation': ('parent', 'conversation', 'conversation_id', 'request_id', ), 'create_data_agent': ('parent', 'data_agent', 'data_agent_id', 'request_id', ), 'delete_conversation': ('name', ), diff --git a/packages/google-cloud-geminidataanalytics/scripts/fixup_geminidataanalytics_v1beta_keywords.py b/packages/google-cloud-geminidataanalytics/scripts/fixup_geminidataanalytics_v1beta_keywords.py index 0204e8e1aafb..3c06bb5bbcf7 100644 --- a/packages/google-cloud-geminidataanalytics/scripts/fixup_geminidataanalytics_v1beta_keywords.py +++ b/packages/google-cloud-geminidataanalytics/scripts/fixup_geminidataanalytics_v1beta_keywords.py @@ -39,9 +39,10 @@ def partition( class geminidataanalyticsCallTransformer(cst.CSTTransformer): CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { - 'chat': ('parent', 'messages', 'inline_context', 'conversation_reference', 'data_agent_context', 'project', ), + 'chat': ('parent', 'messages', 'inline_context', 'conversation_reference', 'data_agent_context', 'client_managed_resource_context', 'project', ), 'create_conversation': ('parent', 'conversation', 'conversation_id', 'request_id', ), 'create_data_agent': ('parent', 'data_agent', 'data_agent_id', 'request_id', ), + 'delete_conversation': ('name', ), 'delete_data_agent': ('name', 'request_id', ), 'get_conversation': ('name', ), 'get_data_agent': ('name', ), diff --git a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1alpha/test_data_agent_service.py b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1alpha/test_data_agent_service.py index d7663655799f..1e66b28675ff 100644 --- a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1alpha/test_data_agent_service.py +++ b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1alpha/test_data_agent_service.py @@ -68,6 +68,7 @@ from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore +from google.protobuf import wrappers_pb2 # type: ignore from google.type import expr_pb2 # type: ignore from google.cloud.geminidataanalytics_v1alpha.services.data_agent_service import ( @@ -7126,6 +7127,7 @@ def test_create_data_agent_rest_call_success(request_type): "options": { "chart": {"image": {"no_image": {}, "svg": {}}}, "analysis": {"python": {"enabled": True}}, + "datasource": {"big_query_max_billed_bytes": {"value": 541}}, }, "example_queries": [ { @@ -7433,6 +7435,7 @@ def test_update_data_agent_rest_call_success(request_type): "options": { "chart": {"image": {"no_image": {}, "svg": {}}}, "analysis": {"python": {"enabled": True}}, + "datasource": {"big_query_max_billed_bytes": {"value": 541}}, }, "example_queries": [ { diff --git a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1alpha/test_data_chat_service.py b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1alpha/test_data_chat_service.py index 9a0900d08670..17ebc19ccf01 100644 --- a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1alpha/test_data_chat_service.py +++ b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1alpha/test_data_chat_service.py @@ -55,6 +55,7 @@ from google.oauth2 import service_account from google.protobuf import struct_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore +from google.protobuf import wrappers_pb2 # type: ignore from google.cloud.geminidataanalytics_v1alpha.services.data_chat_service import ( DataChatServiceAsyncClient, diff --git a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_agent_service.py b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_agent_service.py index dea759d81f1b..5daa68fed598 100644 --- a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_agent_service.py +++ b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_agent_service.py @@ -68,6 +68,7 @@ from google.protobuf import empty_pb2 # type: ignore from google.protobuf import field_mask_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore +from google.protobuf import wrappers_pb2 # type: ignore from google.type import expr_pb2 # type: ignore from google.cloud.geminidataanalytics_v1beta.services.data_agent_service import ( @@ -7126,6 +7127,7 @@ def test_create_data_agent_rest_call_success(request_type): "options": { "chart": {"image": {"no_image": {}, "svg": {}}}, "analysis": {"python": {"enabled": True}}, + "datasource": {"big_query_max_billed_bytes": {"value": 541}}, }, "example_queries": [ { @@ -7133,6 +7135,24 @@ def test_create_data_agent_rest_call_success(request_type): "natural_language_question": "natural_language_question_value", } ], + "glossary_terms": [ + { + "display_name": "display_name_value", + "description": "description_value", + "labels": ["labels_value1", "labels_value2"], + } + ], + "schema_relationships": [ + { + "left_schema_paths": { + "table_fqn": "table_fqn_value", + "paths": ["paths_value1", "paths_value2"], + }, + "right_schema_paths": {}, + "sources": [1], + "confidence_score": 0.1673, + } + ], }, "published_context": {}, "last_published_context": {}, @@ -7415,6 +7435,7 @@ def test_update_data_agent_rest_call_success(request_type): "options": { "chart": {"image": {"no_image": {}, "svg": {}}}, "analysis": {"python": {"enabled": True}}, + "datasource": {"big_query_max_billed_bytes": {"value": 541}}, }, "example_queries": [ { @@ -7422,6 +7443,24 @@ def test_update_data_agent_rest_call_success(request_type): "natural_language_question": "natural_language_question_value", } ], + "glossary_terms": [ + { + "display_name": "display_name_value", + "description": "description_value", + "labels": ["labels_value1", "labels_value2"], + } + ], + "schema_relationships": [ + { + "left_schema_paths": { + "table_fqn": "table_fqn_value", + "paths": ["paths_value1", "paths_value2"], + }, + "right_schema_paths": {}, + "sources": [1], + "confidence_score": 0.1673, + } + ], }, "published_context": {}, "last_published_context": {}, diff --git a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_chat_service.py b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_chat_service.py index 6704bdf59b21..880718f8178d 100644 --- a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_chat_service.py +++ b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_chat_service.py @@ -55,6 +55,7 @@ from google.oauth2 import service_account from google.protobuf import struct_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore +from google.protobuf import wrappers_pb2 # type: ignore from google.cloud.geminidataanalytics_v1beta.services.data_chat_service import ( DataChatServiceAsyncClient, @@ -1753,6 +1754,335 @@ async def test_create_conversation_flattened_error_async(): ) +@pytest.mark.parametrize( + "request_type", + [ + conversation.DeleteConversationRequest, + dict, + ], +) +def test_delete_conversation(request_type, transport: str = "grpc"): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_conversation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + request = conversation.DeleteConversationRequest() + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_conversation_non_empty_request_with_auto_populated_field(): + # This test is a coverage failsafe to make sure that UUID4 fields are + # automatically populated, according to AIP-4235, with non-empty requests. + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Populate all string fields in the request which are not UUID4 + # since we want to check that UUID4 are populated automatically + # if they meet the requirements of AIP 4235. + request = conversation.DeleteConversationRequest( + name="name_value", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.delete_conversation(request=request) + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == conversation.DeleteConversationRequest( + name="name_value", + ) + + +def test_delete_conversation_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.delete_conversation in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.delete_conversation + ] = mock_rpc + request = {} + client.delete_conversation(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.delete_conversation(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_delete_conversation_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = DataChatServiceAsyncClient( + credentials=async_anonymous_credentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.delete_conversation + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.delete_conversation + ] = mock_rpc + + request = {} + await client.delete_conversation(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.delete_conversation(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_delete_conversation_async( + transport: str = "grpc_asyncio", request_type=conversation.DeleteConversationRequest +): + client = DataChatServiceAsyncClient( + credentials=async_anonymous_credentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_conversation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + request = conversation.DeleteConversationRequest() + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_conversation_async_from_dict(): + await test_delete_conversation_async(request_type=dict) + + +def test_delete_conversation_field_headers(): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = conversation.DeleteConversationRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + call.return_value = None + client.delete_conversation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_conversation_field_headers_async(): + client = DataChatServiceAsyncClient( + credentials=async_anonymous_credentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = conversation.DeleteConversationRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_conversation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +def test_delete_conversation_flattened(): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.delete_conversation( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +def test_delete_conversation_flattened_error(): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_conversation( + conversation.DeleteConversationRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_delete_conversation_flattened_async(): + client = DataChatServiceAsyncClient( + credentials=async_anonymous_credentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.delete_conversation( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_delete_conversation_flattened_error_async(): + client = DataChatServiceAsyncClient( + credentials=async_anonymous_credentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.delete_conversation( + conversation.DeleteConversationRequest(), + name="name_value", + ) + + @pytest.mark.parametrize( "request_type", [ @@ -3263,24 +3593,231 @@ def test_chat_rest_required_fields(request_type=data_chat_service.ChatRequest): assert expected_params == actual_params -def test_chat_rest_unset_required_fields(): - transport = transports.DataChatServiceRestTransport( - credentials=ga_credentials.AnonymousCredentials +def test_chat_rest_unset_required_fields(): + transport = transports.DataChatServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.chat._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "messages", + ) + ) + ) + + +def test_create_conversation_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.create_conversation in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.create_conversation + ] = mock_rpc + + request = {} + client.create_conversation(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.create_conversation(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_create_conversation_rest_required_fields( + request_type=gcg_conversation.CreateConversationRequest, +): + transport_class = transports.DataChatServiceRestTransport + + request_init = {} + request_init["parent"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson(pb_request, use_integers_for_enums=False) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["parent"] = "parent_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_conversation._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set( + ( + "conversation_id", + "request_id", + ) + ) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "parent" in jsonified_request + assert jsonified_request["parent"] == "parent_value" + + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = gcg_conversation.Conversation() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + # Convert return value to protobuf type + return_value = gcg_conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + + response = client.create_conversation(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_conversation_rest_unset_required_fields(): + transport = transports.DataChatServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_conversation._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "conversationId", + "requestId", + ) + ) + & set( + ( + "parent", + "conversation", + ) + ) + ) + + +def test_create_conversation_rest_flattened(): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = gcg_conversation.Conversation() + + # get arguments that satisfy an http rule for this method + sample_request = {"parent": "projects/sample1/locations/sample2"} + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + conversation=gcg_conversation.Conversation(name="name_value"), + conversation_id="conversation_id_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + # Convert return value to protobuf type + return_value = gcg_conversation.Conversation.pb(return_value) + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + + client.create_conversation(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1beta/{parent=projects/*/locations/*}/conversations" + % client.transport._host, + args[1], + ) + + +def test_create_conversation_rest_flattened_error(transport: str = "rest"): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, ) - unset_fields = transport.chat._get_unset_required_fields({}) - assert set(unset_fields) == ( - set(()) - & set( - ( - "parent", - "messages", - ) + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.create_conversation( + gcg_conversation.CreateConversationRequest(), + parent="parent_value", + conversation=gcg_conversation.Conversation(name="name_value"), + conversation_id="conversation_id_value", ) - ) -def test_create_conversation_rest_use_cached_wrapped_rpc(): +def test_delete_conversation_rest_use_cached_wrapped_rpc(): # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, # instead of constructing them on each call with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: @@ -3295,7 +3832,7 @@ def test_create_conversation_rest_use_cached_wrapped_rpc(): # Ensure method has been cached assert ( - client._transport.create_conversation in client._transport._wrapped_methods + client._transport.delete_conversation in client._transport._wrapped_methods ) # Replace cached wrapped function with mock @@ -3304,29 +3841,29 @@ def test_create_conversation_rest_use_cached_wrapped_rpc(): "foo" # operation_request.operation in compute client(s) expect a string. ) client._transport._wrapped_methods[ - client._transport.create_conversation + client._transport.delete_conversation ] = mock_rpc request = {} - client.create_conversation(request) + client.delete_conversation(request) # Establish that the underlying gRPC stub method was called. assert mock_rpc.call_count == 1 - client.create_conversation(request) + client.delete_conversation(request) # Establish that a new wrapper was not created for this call assert wrapper_fn.call_count == 0 assert mock_rpc.call_count == 2 -def test_create_conversation_rest_required_fields( - request_type=gcg_conversation.CreateConversationRequest, +def test_delete_conversation_rest_required_fields( + request_type=conversation.DeleteConversationRequest, ): transport_class = transports.DataChatServiceRestTransport request_init = {} - request_init["parent"] = "" + request_init["name"] = "" request = request_type(**request_init) pb_request = request_type.pb(request) jsonified_request = json.loads( @@ -3337,28 +3874,21 @@ def test_create_conversation_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).create_conversation._get_unset_required_fields(jsonified_request) + ).delete_conversation._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with default values are now present - jsonified_request["parent"] = "parent_value" + jsonified_request["name"] = "name_value" unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).create_conversation._get_unset_required_fields(jsonified_request) - # Check that path parameters and body parameters are not mixing in. - assert not set(unset_fields) - set( - ( - "conversation_id", - "request_id", - ) - ) + ).delete_conversation._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with non-default values are left alone - assert "parent" in jsonified_request - assert jsonified_request["parent"] == "parent_value" + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" client = DataChatServiceClient( credentials=ga_credentials.AnonymousCredentials(), @@ -3367,7 +3897,7 @@ def test_create_conversation_rest_required_fields( request = request_type(**request_init) # Designate an appropriate value for the returned response. - return_value = gcg_conversation.Conversation() + return_value = None # Mock the http request call within the method and fake a response. with mock.patch.object(Session, "request") as req: # We need to mock transcode() because providing default values @@ -3379,53 +3909,36 @@ def test_create_conversation_rest_required_fields( pb_request = request_type.pb(request) transcode_result = { "uri": "v1/sample_method", - "method": "post", + "method": "delete", "query_params": pb_request, } - transcode_result["body"] = pb_request transcode.return_value = transcode_result response_value = Response() response_value.status_code = 200 - - # Convert return value to protobuf type - return_value = gcg_conversation.Conversation.pb(return_value) - json_return_value = json_format.MessageToJson(return_value) + json_return_value = "" response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} - response = client.create_conversation(request) + response = client.delete_conversation(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_create_conversation_rest_unset_required_fields(): +def test_delete_conversation_rest_unset_required_fields(): transport = transports.DataChatServiceRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.create_conversation._get_unset_required_fields({}) - assert set(unset_fields) == ( - set( - ( - "conversationId", - "requestId", - ) - ) - & set( - ( - "parent", - "conversation", - ) - ) - ) + unset_fields = transport.delete_conversation._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) -def test_create_conversation_rest_flattened(): +def test_delete_conversation_rest_flattened(): client = DataChatServiceClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -3434,43 +3947,41 @@ def test_create_conversation_rest_flattened(): # Mock the http request call within the method and fake a response. with mock.patch.object(type(client.transport._session), "request") as req: # Designate an appropriate value for the returned response. - return_value = gcg_conversation.Conversation() + return_value = None # get arguments that satisfy an http rule for this method - sample_request = {"parent": "projects/sample1/locations/sample2"} + sample_request = { + "name": "projects/sample1/locations/sample2/conversations/sample3" + } # get truthy value for each flattened field mock_args = dict( - parent="parent_value", - conversation=gcg_conversation.Conversation(name="name_value"), - conversation_id="conversation_id_value", + name="name_value", ) mock_args.update(sample_request) # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - # Convert return value to protobuf type - return_value = gcg_conversation.Conversation.pb(return_value) - json_return_value = json_format.MessageToJson(return_value) + json_return_value = "" response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} - client.create_conversation(**mock_args) + client.delete_conversation(**mock_args) # Establish that the underlying call was made with the expected # request object values. assert len(req.mock_calls) == 1 _, args, _ = req.mock_calls[0] assert path_template.validate( - "%s/v1beta/{parent=projects/*/locations/*}/conversations" + "%s/v1beta/{name=projects/*/locations/*/conversations/*}" % client.transport._host, args[1], ) -def test_create_conversation_rest_flattened_error(transport: str = "rest"): +def test_delete_conversation_rest_flattened_error(transport: str = "rest"): client = DataChatServiceClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -3479,11 +3990,9 @@ def test_create_conversation_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.create_conversation( - gcg_conversation.CreateConversationRequest(), - parent="parent_value", - conversation=gcg_conversation.Conversation(name="name_value"), - conversation_id="conversation_id_value", + client.delete_conversation( + conversation.DeleteConversationRequest(), + name="name_value", ) @@ -4343,6 +4852,29 @@ def test_create_conversation_empty_call_grpc(): assert args[0] == request_msg +# This test is a coverage failsafe to make sure that totally empty calls, +# i.e. request == None and no flattened fields passed, work. +def test_delete_conversation_empty_call_grpc(): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + call.return_value = None + client.delete_conversation(request=None) + + # Establish that the underlying stub method was called. + call.assert_called() + _, args, _ = call.mock_calls[0] + request_msg = conversation.DeleteConversationRequest() + + assert args[0] == request_msg + + # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. def test_get_conversation_empty_call_grpc(): @@ -4478,6 +5010,31 @@ async def test_create_conversation_empty_call_grpc_asyncio(): assert args[0] == request_msg +# This test is a coverage failsafe to make sure that totally empty calls, +# i.e. request == None and no flattened fields passed, work. +@pytest.mark.asyncio +async def test_delete_conversation_empty_call_grpc_asyncio(): + client = DataChatServiceAsyncClient( + credentials=async_anonymous_credentials(), + transport="grpc_asyncio", + ) + + # Mock the actual call, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_conversation(request=None) + + # Establish that the underlying stub method was called. + call.assert_called() + _, args, _ = call.mock_calls[0] + request_msg = conversation.DeleteConversationRequest() + + assert args[0] == request_msg + + # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. @pytest.mark.asyncio @@ -4902,6 +5459,115 @@ def test_create_conversation_rest_interceptors(null_interceptor): post_with_metadata.assert_called_once() +def test_delete_conversation_rest_bad_request( + request_type=conversation.DeleteConversationRequest, +): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/conversations/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with mock.patch.object(Session, "request") as req, pytest.raises( + core_exceptions.BadRequest + ): + # Wrap the value into a proper Response obj + response_value = mock.Mock() + json_return_value = "" + response_value.json = mock.Mock(return_value={}) + response_value.status_code = 400 + response_value.request = mock.Mock() + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + client.delete_conversation(request) + + +@pytest.mark.parametrize( + "request_type", + [ + conversation.DeleteConversationRequest, + dict, + ], +) +def test_delete_conversation_rest_call_success(request_type): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + # send a request that will satisfy transcoding + request_init = {"name": "projects/sample1/locations/sample2/conversations/sample3"} + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = None + + # Wrap the value into a proper Response obj + response_value = mock.Mock() + response_value.status_code = 200 + json_return_value = "" + response_value.content = json_return_value.encode("UTF-8") + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + response = client.delete_conversation(request) + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_delete_conversation_rest_interceptors(null_interceptor): + transport = transports.DataChatServiceRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.DataChatServiceRestInterceptor(), + ) + client = DataChatServiceClient(transport=transport) + + with mock.patch.object( + type(client.transport._session), "request" + ) as req, mock.patch.object( + path_template, "transcode" + ) as transcode, mock.patch.object( + transports.DataChatServiceRestInterceptor, "pre_delete_conversation" + ) as pre: + pre.assert_not_called() + pb_message = conversation.DeleteConversationRequest.pb( + conversation.DeleteConversationRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = mock.Mock() + req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + + request = conversation.DeleteConversationRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + + client.delete_conversation( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + + def test_get_conversation_rest_bad_request( request_type=conversation.GetConversationRequest, ): @@ -5717,6 +6383,28 @@ def test_create_conversation_empty_call_rest(): assert args[0] == request_msg +# This test is a coverage failsafe to make sure that totally empty calls, +# i.e. request == None and no flattened fields passed, work. +def test_delete_conversation_empty_call_rest(): + client = DataChatServiceClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the actual call, and fake the request. + with mock.patch.object( + type(client.transport.delete_conversation), "__call__" + ) as call: + client.delete_conversation(request=None) + + # Establish that the underlying stub method was called. + call.assert_called() + _, args, _ = call.mock_calls[0] + request_msg = conversation.DeleteConversationRequest() + + assert args[0] == request_msg + + # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. def test_get_conversation_empty_call_rest(): @@ -5814,6 +6502,7 @@ def test_data_chat_service_base_transport(): methods = ( "chat", "create_conversation", + "delete_conversation", "get_conversation", "list_conversations", "list_messages", @@ -6087,6 +6776,9 @@ def test_data_chat_service_client_transport_session_collision(transport_name): session1 = client1.transport.create_conversation._session session2 = client2.transport.create_conversation._session assert session1 != session2 + session1 = client1.transport.delete_conversation._session + session2 = client2.transport.delete_conversation._session + assert session1 != session2 session1 = client1.transport.get_conversation._session session2 = client2.transport.get_conversation._session assert session1 != session2