google-adk 0.5.0__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. google/adk/agents/base_agent.py +76 -30
  2. google/adk/agents/callback_context.py +2 -6
  3. google/adk/agents/llm_agent.py +122 -30
  4. google/adk/agents/loop_agent.py +1 -1
  5. google/adk/agents/parallel_agent.py +7 -0
  6. google/adk/agents/readonly_context.py +8 -0
  7. google/adk/agents/run_config.py +1 -1
  8. google/adk/agents/sequential_agent.py +31 -0
  9. google/adk/agents/transcription_entry.py +4 -2
  10. google/adk/artifacts/gcs_artifact_service.py +1 -1
  11. google/adk/artifacts/in_memory_artifact_service.py +1 -1
  12. google/adk/auth/auth_credential.py +10 -2
  13. google/adk/auth/auth_preprocessor.py +7 -1
  14. google/adk/auth/auth_tool.py +3 -4
  15. google/adk/cli/agent_graph.py +5 -5
  16. google/adk/cli/browser/index.html +4 -4
  17. google/adk/cli/browser/{main-ULN5R5I5.js → main-PKDNKWJE.js} +59 -60
  18. google/adk/cli/browser/polyfills-B6TNHZQ6.js +17 -0
  19. google/adk/cli/cli.py +10 -9
  20. google/adk/cli/cli_deploy.py +7 -2
  21. google/adk/cli/cli_eval.py +109 -115
  22. google/adk/cli/cli_tools_click.py +179 -67
  23. google/adk/cli/fast_api.py +248 -197
  24. google/adk/cli/utils/agent_loader.py +137 -0
  25. google/adk/cli/utils/cleanup.py +40 -0
  26. google/adk/cli/utils/common.py +23 -0
  27. google/adk/cli/utils/evals.py +83 -0
  28. google/adk/cli/utils/logs.py +8 -5
  29. google/adk/code_executors/__init__.py +3 -1
  30. google/adk/code_executors/built_in_code_executor.py +52 -0
  31. google/adk/code_executors/code_execution_utils.py +2 -1
  32. google/adk/code_executors/container_code_executor.py +0 -1
  33. google/adk/code_executors/vertex_ai_code_executor.py +6 -8
  34. google/adk/evaluation/__init__.py +1 -1
  35. google/adk/evaluation/agent_evaluator.py +168 -128
  36. google/adk/evaluation/eval_case.py +104 -0
  37. google/adk/evaluation/eval_metrics.py +74 -0
  38. google/adk/evaluation/eval_result.py +86 -0
  39. google/adk/evaluation/eval_set.py +39 -0
  40. google/adk/evaluation/eval_set_results_manager.py +47 -0
  41. google/adk/evaluation/eval_sets_manager.py +43 -0
  42. google/adk/evaluation/evaluation_generator.py +88 -113
  43. google/adk/evaluation/evaluator.py +58 -0
  44. google/adk/evaluation/local_eval_set_results_manager.py +113 -0
  45. google/adk/evaluation/local_eval_sets_manager.py +264 -0
  46. google/adk/evaluation/response_evaluator.py +106 -1
  47. google/adk/evaluation/trajectory_evaluator.py +84 -2
  48. google/adk/events/event.py +6 -1
  49. google/adk/events/event_actions.py +6 -1
  50. google/adk/examples/base_example_provider.py +1 -0
  51. google/adk/examples/example_util.py +3 -2
  52. google/adk/flows/llm_flows/_code_execution.py +9 -1
  53. google/adk/flows/llm_flows/audio_transcriber.py +4 -3
  54. google/adk/flows/llm_flows/base_llm_flow.py +58 -21
  55. google/adk/flows/llm_flows/contents.py +3 -1
  56. google/adk/flows/llm_flows/functions.py +9 -8
  57. google/adk/flows/llm_flows/instructions.py +18 -80
  58. google/adk/flows/llm_flows/single_flow.py +2 -2
  59. google/adk/memory/__init__.py +1 -1
  60. google/adk/memory/_utils.py +23 -0
  61. google/adk/memory/base_memory_service.py +23 -21
  62. google/adk/memory/in_memory_memory_service.py +57 -25
  63. google/adk/memory/memory_entry.py +37 -0
  64. google/adk/memory/vertex_ai_rag_memory_service.py +38 -15
  65. google/adk/models/anthropic_llm.py +16 -9
  66. google/adk/models/base_llm.py +2 -1
  67. google/adk/models/base_llm_connection.py +2 -0
  68. google/adk/models/gemini_llm_connection.py +11 -11
  69. google/adk/models/google_llm.py +12 -2
  70. google/adk/models/lite_llm.py +80 -23
  71. google/adk/models/llm_response.py +16 -3
  72. google/adk/models/registry.py +1 -1
  73. google/adk/runners.py +98 -42
  74. google/adk/sessions/__init__.py +1 -1
  75. google/adk/sessions/_session_util.py +2 -1
  76. google/adk/sessions/base_session_service.py +6 -33
  77. google/adk/sessions/database_session_service.py +57 -67
  78. google/adk/sessions/in_memory_session_service.py +106 -24
  79. google/adk/sessions/session.py +3 -0
  80. google/adk/sessions/vertex_ai_session_service.py +44 -51
  81. google/adk/telemetry.py +7 -2
  82. google/adk/tools/__init__.py +4 -7
  83. google/adk/tools/_memory_entry_utils.py +30 -0
  84. google/adk/tools/agent_tool.py +10 -10
  85. google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
  86. google/adk/tools/apihub_tool/clients/apihub_client.py +10 -3
  87. google/adk/tools/apihub_tool/clients/secret_client.py +1 -0
  88. google/adk/tools/application_integration_tool/application_integration_toolset.py +111 -85
  89. google/adk/tools/application_integration_tool/clients/connections_client.py +28 -1
  90. google/adk/tools/application_integration_tool/clients/integration_client.py +7 -5
  91. google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
  92. google/adk/tools/base_toolset.py +96 -0
  93. google/adk/tools/bigquery/__init__.py +28 -0
  94. google/adk/tools/bigquery/bigquery_credentials.py +216 -0
  95. google/adk/tools/bigquery/bigquery_tool.py +116 -0
  96. google/adk/tools/{built_in_code_execution_tool.py → enterprise_search_tool.py} +17 -11
  97. google/adk/tools/function_parameter_parse_util.py +9 -2
  98. google/adk/tools/function_tool.py +33 -3
  99. google/adk/tools/get_user_choice_tool.py +1 -0
  100. google/adk/tools/google_api_tool/__init__.py +24 -70
  101. google/adk/tools/google_api_tool/google_api_tool.py +12 -6
  102. google/adk/tools/google_api_tool/{google_api_tool_set.py → google_api_toolset.py} +57 -55
  103. google/adk/tools/google_api_tool/google_api_toolsets.py +108 -0
  104. google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
  105. google/adk/tools/google_search_tool.py +2 -2
  106. google/adk/tools/langchain_tool.py +96 -49
  107. google/adk/tools/load_memory_tool.py +14 -5
  108. google/adk/tools/mcp_tool/__init__.py +3 -2
  109. google/adk/tools/mcp_tool/conversion_utils.py +6 -2
  110. google/adk/tools/mcp_tool/mcp_session_manager.py +80 -69
  111. google/adk/tools/mcp_tool/mcp_tool.py +35 -32
  112. google/adk/tools/mcp_tool/mcp_toolset.py +99 -194
  113. google/adk/tools/openapi_tool/auth/credential_exchangers/base_credential_exchanger.py +1 -3
  114. google/adk/tools/openapi_tool/auth/credential_exchangers/service_account_exchanger.py +6 -7
  115. google/adk/tools/openapi_tool/common/common.py +5 -1
  116. google/adk/tools/openapi_tool/openapi_spec_parser/__init__.py +7 -2
  117. google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +27 -7
  118. google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +36 -32
  119. google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +11 -1
  120. google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
  121. google/adk/tools/preload_memory_tool.py +27 -18
  122. google/adk/tools/retrieval/__init__.py +1 -1
  123. google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
  124. google/adk/tools/toolbox_toolset.py +107 -0
  125. google/adk/tools/transfer_to_agent_tool.py +0 -1
  126. google/adk/utils/__init__.py +13 -0
  127. google/adk/utils/instructions_utils.py +131 -0
  128. google/adk/version.py +1 -1
  129. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/METADATA +18 -19
  130. google_adk-1.1.0.dist-info/RECORD +200 -0
  131. google/adk/agents/remote_agent.py +0 -50
  132. google/adk/cli/browser/polyfills-FFHMD2TL.js +0 -18
  133. google/adk/cli/fast_api.py.orig +0 -728
  134. google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
  135. google/adk/tools/toolbox_tool.py +0 -46
  136. google_adk-0.5.0.dist-info/RECORD +0 -180
  137. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/WHEEL +0 -0
  138. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/entry_points.txt +0 -0
  139. {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -13,19 +13,25 @@
13
13
  # limitations under the License.
14
14
 
15
15
 
16
- from typing import Dict, List, Optional
16
+ from typing import List
17
+ from typing import Optional
18
+ from typing import Union
17
19
 
20
+ from typing_extensions import override
18
21
  import yaml
19
22
 
23
+ from ...agents.readonly_context import ReadonlyContext
20
24
  from ...auth.auth_credential import AuthCredential
21
25
  from ...auth.auth_schemes import AuthScheme
26
+ from ..base_toolset import BaseToolset
27
+ from ..base_toolset import ToolPredicate
22
28
  from ..openapi_tool.common.common import to_snake_case
23
29
  from ..openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset
24
30
  from ..openapi_tool.openapi_spec_parser.rest_api_tool import RestApiTool
25
31
  from .clients.apihub_client import APIHubClient
26
32
 
27
33
 
28
- class APIHubToolset:
34
+ class APIHubToolset(BaseToolset):
29
35
  """APIHubTool generates tools from a given API Hub resource.
30
36
 
31
37
  Examples:
@@ -34,16 +40,13 @@ class APIHubToolset:
34
40
  apihub_toolset = APIHubToolset(
35
41
  apihub_resource_name="projects/test-project/locations/us-central1/apis/test-api",
36
42
  service_account_json="...",
43
+ tool_filter=lambda tool, ctx=None: tool.name in ('my_tool',
44
+ 'my_other_tool')
37
45
  )
38
46
 
39
47
  # Get all available tools
40
- agent = LlmAgent(tools=apihub_toolset.get_tools())
48
+ agent = LlmAgent(tools=apihub_toolset)
41
49
 
42
- # Get a specific tool
43
- agent = LlmAgent(tools=[
44
- ...
45
- apihub_toolset.get_tool('my_tool'),
46
- ])
47
50
  ```
48
51
 
49
52
  **apihub_resource_name** is the resource name from API Hub. It must include
@@ -70,6 +73,7 @@ class APIHubToolset:
70
73
  auth_credential: Optional[AuthCredential] = None,
71
74
  # Optionally, you can provide a custom API Hub client
72
75
  apihub_client: Optional[APIHubClient] = None,
76
+ tool_filter: Optional[Union[ToolPredicate, List[str]]] = None,
73
77
  ):
74
78
  """Initializes the APIHubTool with the given parameters.
75
79
 
@@ -81,12 +85,17 @@ class APIHubToolset:
81
85
  )
82
86
 
83
87
  # Get all available tools
84
- agent = LlmAgent(tools=apihub_toolset.get_tools())
88
+ agent = LlmAgent(tools=[apihub_toolset])
85
89
 
90
+ apihub_toolset = APIHubToolset(
91
+ apihub_resource_name="projects/test-project/locations/us-central1/apis/test-api",
92
+ service_account_json="...",
93
+ tool_filter = ['my_tool']
94
+ )
86
95
  # Get a specific tool
87
96
  agent = LlmAgent(tools=[
88
- ...
89
- apihub_toolset.get_tool('my_tool'),
97
+ ...,
98
+ apihub_toolset,
90
99
  ])
91
100
  ```
92
101
 
@@ -118,82 +127,49 @@ class APIHubToolset:
118
127
  lazy_load_spec: If True, the spec will be loaded lazily when needed.
119
128
  Otherwise, the spec will be loaded immediately and the tools will be
120
129
  generated during initialization.
130
+ tool_filter: The filter used to filter the tools in the toolset. It can
131
+ be either a tool predicate or a list of tool names of the tools to
132
+ expose.
121
133
  """
134
+ super().__init__(tool_filter=tool_filter)
122
135
  self.name = name
123
136
  self.description = description
124
- self.apihub_resource_name = apihub_resource_name
125
- self.lazy_load_spec = lazy_load_spec
126
- self.apihub_client = apihub_client or APIHubClient(
137
+ self._apihub_resource_name = apihub_resource_name
138
+ self._lazy_load_spec = lazy_load_spec
139
+ self._apihub_client = apihub_client or APIHubClient(
127
140
  access_token=access_token,
128
141
  service_account_json=service_account_json,
129
142
  )
130
143
 
131
- self.generated_tools: Dict[str, RestApiTool] = {}
132
- self.auth_scheme = auth_scheme
133
- self.auth_credential = auth_credential
134
-
135
- if not self.lazy_load_spec:
136
- self._prepare_tools()
137
-
138
- def get_tool(self, name: str) -> Optional[RestApiTool]:
139
- """Retrieves a specific tool by its name.
140
-
141
- Example:
142
- ```
143
- apihub_tool = apihub_toolset.get_tool('my_tool')
144
- ```
145
-
146
- Args:
147
- name: The name of the tool to retrieve.
148
-
149
- Returns:
150
- The tool with the given name, or None if no such tool exists.
151
- """
152
- if not self._are_tools_ready():
153
- self._prepare_tools()
144
+ self._openapi_toolset = None
145
+ self._auth_scheme = auth_scheme
146
+ self._auth_credential = auth_credential
154
147
 
155
- return self.generated_tools[name] if name in self.generated_tools else None
148
+ if not self._lazy_load_spec:
149
+ self._prepare_toolset()
156
150
 
157
- def get_tools(self) -> List[RestApiTool]:
151
+ @override
152
+ async def get_tools(
153
+ self, readonly_context: Optional[ReadonlyContext] = None
154
+ ) -> List[RestApiTool]:
158
155
  """Retrieves all available tools.
159
156
 
160
157
  Returns:
161
158
  A list of all available RestApiTool objects.
162
159
  """
163
- if not self._are_tools_ready():
164
- self._prepare_tools()
165
-
166
- return list(self.generated_tools.values())
167
-
168
- def _are_tools_ready(self) -> bool:
169
- return not self.lazy_load_spec or self.generated_tools
170
-
171
- def _prepare_tools(self) -> str:
172
- """Fetches the spec from API Hub and generates the tools.
160
+ if not self._openapi_toolset:
161
+ self._prepare_toolset()
162
+ if not self._openapi_toolset:
163
+ return []
164
+ return await self._openapi_toolset.get_tools(readonly_context)
173
165
 
174
- Returns:
175
- True if the tools are ready, False otherwise.
176
- """
166
+ def _prepare_toolset(self) -> None:
167
+ """Fetches the spec from API Hub and generates the toolset."""
177
168
  # For each API, get the first version and the first spec of that version.
178
- spec = self.apihub_client.get_spec_content(self.apihub_resource_name)
179
- self.generated_tools: Dict[str, RestApiTool] = {}
180
-
181
- tools = self._parse_spec_to_tools(spec)
182
- for tool in tools:
183
- self.generated_tools[tool.name] = tool
184
-
185
- def _parse_spec_to_tools(self, spec_str: str) -> List[RestApiTool]:
186
- """Parses the spec string to a list of RestApiTool.
187
-
188
- Args:
189
- spec_str: The spec string to parse.
190
-
191
- Returns:
192
- A list of RestApiTool objects.
193
- """
169
+ spec_str = self._apihub_client.get_spec_content(self._apihub_resource_name)
194
170
  spec_dict = yaml.safe_load(spec_str)
195
171
  if not spec_dict:
196
- return []
172
+ return
197
173
 
198
174
  self.name = self.name or to_snake_case(
199
175
  spec_dict.get('info', {}).get('title', 'unnamed')
@@ -201,9 +177,14 @@ class APIHubToolset:
201
177
  self.description = self.description or spec_dict.get('info', {}).get(
202
178
  'description', ''
203
179
  )
204
- tools = OpenAPIToolset(
180
+ self._openapi_toolset = OpenAPIToolset(
205
181
  spec_dict=spec_dict,
206
- auth_credential=self.auth_credential,
207
- auth_scheme=self.auth_scheme,
208
- ).get_tools()
209
- return tools
182
+ auth_credential=self._auth_credential,
183
+ auth_scheme=self._auth_scheme,
184
+ tool_filter=self.tool_filter,
185
+ )
186
+
187
+ @override
188
+ async def close(self):
189
+ if self._openapi_toolset:
190
+ await self._openapi_toolset.close()
@@ -12,11 +12,18 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from abc import ABC, abstractmethod
15
+ from abc import ABC
16
+ from abc import abstractmethod
16
17
  import base64
17
18
  import json
18
- from typing import Any, Dict, List, Optional, Tuple
19
- from urllib.parse import parse_qs, urlparse
19
+ from typing import Any
20
+ from typing import Dict
21
+ from typing import List
22
+ from typing import Optional
23
+ from typing import Tuple
24
+ from urllib.parse import parse_qs
25
+ from urllib.parse import urlparse
26
+
20
27
  from google.auth import default as default_service_credential
21
28
  from google.auth.transport.requests import Request
22
29
  from google.oauth2 import service_account
@@ -14,6 +14,7 @@
14
14
 
15
15
  import json
16
16
  from typing import Optional
17
+
17
18
  import google.auth
18
19
  from google.auth import default as default_service_credential
19
20
  import google.auth.transport.requests
@@ -12,14 +12,22 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from typing import Dict, List, Optional
15
+ import logging
16
+ from typing import List
17
+ from typing import Optional
18
+ from typing import Union
16
19
 
17
20
  from fastapi.openapi.models import HTTPBearer
21
+ from typing_extensions import override
18
22
 
23
+ from ...agents.readonly_context import ReadonlyContext
19
24
  from ...auth.auth_credential import AuthCredential
20
25
  from ...auth.auth_credential import AuthCredentialTypes
21
26
  from ...auth.auth_credential import ServiceAccount
22
27
  from ...auth.auth_credential import ServiceAccountCredential
28
+ from ...auth.auth_schemes import AuthScheme
29
+ from ..base_toolset import BaseToolset
30
+ from ..base_toolset import ToolPredicate
23
31
  from ..openapi_tool.auth.auth_helpers import service_account_scheme_credential
24
32
  from ..openapi_tool.openapi_spec_parser.openapi_spec_parser import OpenApiSpecParser
25
33
  from ..openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset
@@ -28,9 +36,11 @@ from .clients.connections_client import ConnectionsClient
28
36
  from .clients.integration_client import IntegrationClient
29
37
  from .integration_connector_tool import IntegrationConnectorTool
30
38
 
39
+ logger = logging.getLogger("google_adk." + __name__)
40
+
31
41
 
32
42
  # TODO(cheliu): Apply a common toolset interface
33
- class ApplicationIntegrationToolset:
43
+ class ApplicationIntegrationToolset(BaseToolset):
34
44
  """ApplicationIntegrationToolset generates tools from a given Application
35
45
 
36
46
  Integration or Integration Connector resource.
@@ -42,7 +52,7 @@ class ApplicationIntegrationToolset:
42
52
  project="test-project",
43
53
  location="us-central1"
44
54
  integration="test-integration",
45
- trigger="api_trigger/test_trigger",
55
+ triggers=["api_trigger/test_trigger"],
46
56
  service_account_credentials={...},
47
57
  )
48
58
 
@@ -63,10 +73,10 @@ class ApplicationIntegrationToolset:
63
73
  service_account_credentials={...},
64
74
  )
65
75
 
66
- # Get all available tools
76
+ # Feed the toolset to agent
67
77
  agent = LlmAgent(tools=[
68
- ...
69
- *application_integration_toolset.get_tools(),
78
+ ...,
79
+ application_integration_toolset,
70
80
  ])
71
81
  ```
72
82
  """
@@ -76,100 +86,74 @@ class ApplicationIntegrationToolset:
76
86
  project: str,
77
87
  location: str,
78
88
  integration: Optional[str] = None,
79
- trigger: Optional[str] = None,
89
+ triggers: Optional[List[str]] = None,
80
90
  connection: Optional[str] = None,
81
91
  entity_operations: Optional[str] = None,
82
92
  actions: Optional[str] = None,
83
93
  # Optional parameter for the toolset. This is prepended to the generated
84
94
  # tool/python function name.
85
- tool_name: Optional[str] = "",
95
+ tool_name_prefix: Optional[str] = "",
86
96
  # Optional parameter for the toolset. This is appended to the generated
87
97
  # tool/python function description.
88
98
  tool_instructions: Optional[str] = "",
89
99
  service_account_json: Optional[str] = None,
100
+ auth_scheme: Optional[AuthScheme] = None,
101
+ auth_credential: Optional[AuthCredential] = None,
102
+ tool_filter: Optional[Union[ToolPredicate, List[str]]] = None,
90
103
  ):
91
- """Initializes the ApplicationIntegrationToolset.
92
-
93
- Example Usage:
94
- ```
95
- # Get all available tools for an integration with api trigger
96
- application_integration_toolset = ApplicationIntegrationToolset(
97
-
98
- project="test-project",
99
- location="us-central1"
100
- integration="test-integration",
101
- trigger="api_trigger/test_trigger",
102
- service_account_credentials={...},
103
- )
104
-
105
- # Get all available tools for a connection using entity operations and
106
- # actions
107
- # Note: Find the list of supported entity operations and actions for a
108
- connection
109
- # using integration connector apis:
110
- #
111
- https://cloud.google.com/integration-connectors/docs/reference/rest/v1/projects.locations.connections.connectionSchemaMetadata
112
- application_integration_toolset = ApplicationIntegrationToolset(
113
- project="test-project",
114
- location="us-central1"
115
- connection="test-connection",
116
- entity_operations=["EntityId1": ["LIST","CREATE"], "EntityId2": []],
117
- #empty list for actions means all operations on the entity are supported
118
- actions=["action1"],
119
- service_account_credentials={...},
120
- )
121
-
122
- # Get all available tools
123
- agent = LlmAgent(tools=[
124
- ...
125
- *application_integration_toolset.get_tools(),
126
- ])
127
- ```
104
+ """Args:
128
105
 
129
106
  Args:
130
107
  project: The GCP project ID.
131
108
  location: The GCP location.
132
109
  integration: The integration name.
133
- trigger: The trigger name.
110
+ triggers: The list of trigger names in the integration.
134
111
  connection: The connection name.
135
112
  entity_operations: The entity operations supported by the connection.
136
113
  actions: The actions supported by the connection.
137
- tool_name: The name of the tool.
114
+ tool_name_prefix: The name prefix of the generated tools.
138
115
  tool_instructions: The instructions for the tool.
139
116
  service_account_json: The service account configuration as a dictionary.
140
117
  Required if not using default service credential. Used for fetching
141
118
  the Application Integration or Integration Connector resource.
119
+ tool_filter: The filter used to filter the tools in the toolset. It can
120
+ be either a tool predicate or a list of tool names of the tools to
121
+ expose.
142
122
 
143
123
  Raises:
144
- ValueError: If neither integration and trigger nor connection and
145
- (entity_operations or actions) is provided.
124
+ ValueError: If none of the following conditions are met:
125
+ - `integration` is provided.
126
+ - `connection` is provided and at least one of `entity_operations`
127
+ or `actions` is provided.
146
128
  Exception: If there is an error during the initialization of the
147
129
  integration or connection client.
148
130
  """
131
+ super().__init__(tool_filter=tool_filter)
149
132
  self.project = project
150
133
  self.location = location
151
- self.integration = integration
152
- self.trigger = trigger
153
- self.connection = connection
154
- self.entity_operations = entity_operations
155
- self.actions = actions
156
- self.tool_name = tool_name
157
- self.tool_instructions = tool_instructions
158
- self.service_account_json = service_account_json
159
- self.generated_tools: Dict[str, RestApiTool] = {}
134
+ self._integration = integration
135
+ self._triggers = triggers
136
+ self._connection = connection
137
+ self._entity_operations = entity_operations
138
+ self._actions = actions
139
+ self._tool_name_prefix = tool_name_prefix
140
+ self._tool_instructions = tool_instructions
141
+ self._service_account_json = service_account_json
142
+ self._auth_scheme = auth_scheme
143
+ self._auth_credential = auth_credential
160
144
 
161
145
  integration_client = IntegrationClient(
162
146
  project,
163
147
  location,
164
148
  integration,
165
- trigger,
149
+ triggers,
166
150
  connection,
167
151
  entity_operations,
168
152
  actions,
169
153
  service_account_json,
170
154
  )
171
155
  connection_details = {}
172
- if integration and trigger:
156
+ if integration:
173
157
  spec = integration_client.get_openapi_spec_for_integration()
174
158
  elif connection and (entity_operations or actions):
175
159
  connections_client = ConnectionsClient(
@@ -177,21 +161,23 @@ class ApplicationIntegrationToolset:
177
161
  )
178
162
  connection_details = connections_client.get_connection_details()
179
163
  spec = integration_client.get_openapi_spec_for_connection(
180
- tool_name,
164
+ tool_name_prefix,
181
165
  tool_instructions,
182
166
  )
183
167
  else:
184
168
  raise ValueError(
185
- "Either (integration and trigger) or (connection and"
169
+ "Invalid request, Either integration or (connection and"
186
170
  " (entity_operations or actions)) should be provided."
187
171
  )
188
- self._parse_spec_to_tools(spec, connection_details)
172
+ self._openapi_toolset = None
173
+ self._tools = []
174
+ self._parse_spec_to_toolset(spec, connection_details)
189
175
 
190
- def _parse_spec_to_tools(self, spec_dict, connection_details):
191
- """Parses the spec dict to a list of RestApiTool."""
192
- if self.service_account_json:
176
+ def _parse_spec_to_toolset(self, spec_dict, connection_details):
177
+ """Parses the spec dict to OpenAPI toolset."""
178
+ if self._service_account_json:
193
179
  sa_credential = ServiceAccountCredential.model_validate_json(
194
- self.service_account_json
180
+ self._service_account_json
195
181
  )
196
182
  service_account = ServiceAccount(
197
183
  service_account_credential=sa_credential,
@@ -210,14 +196,13 @@ class ApplicationIntegrationToolset:
210
196
  )
211
197
  auth_scheme = HTTPBearer(bearerFormat="JWT")
212
198
 
213
- if self.integration and self.trigger:
214
- tools = OpenAPIToolset(
199
+ if self._integration:
200
+ self._openapi_toolset = OpenAPIToolset(
215
201
  spec_dict=spec_dict,
216
202
  auth_credential=auth_credential,
217
203
  auth_scheme=auth_scheme,
218
- ).get_tools()
219
- for tool in tools:
220
- self.generated_tools[tool.name] = tool
204
+ tool_filter=self.tool_filter,
205
+ )
221
206
  return
222
207
 
223
208
  operations = OpenApiSpecParser().parse(spec_dict)
@@ -235,18 +220,59 @@ class ApplicationIntegrationToolset:
235
220
  rest_api_tool.configure_auth_scheme(auth_scheme)
236
221
  if auth_credential:
237
222
  rest_api_tool.configure_auth_credential(auth_credential)
238
- tool = IntegrationConnectorTool(
239
- name=rest_api_tool.name,
240
- description=rest_api_tool.description,
241
- connection_name=connection_details["name"],
242
- connection_host=connection_details["host"],
243
- connection_service_name=connection_details["serviceName"],
244
- entity=entity,
245
- action=action,
246
- operation=operation,
247
- rest_api_tool=rest_api_tool,
223
+
224
+ auth_override_enabled = connection_details.get(
225
+ "authOverrideEnabled", False
248
226
  )
249
- self.generated_tools[tool.name] = tool
250
227
 
251
- def get_tools(self) -> List[RestApiTool]:
252
- return list(self.generated_tools.values())
228
+ if (
229
+ self._auth_scheme
230
+ and self._auth_credential
231
+ and not auth_override_enabled
232
+ ):
233
+ # Case: Auth provided, but override is OFF. Don't use provided auth.
234
+ logger.warning(
235
+ "Authentication schema and credentials are not used because"
236
+ " authOverrideEnabled is not enabled in the connection."
237
+ )
238
+ connector_auth_scheme = None
239
+ connector_auth_credential = None
240
+ else:
241
+ connector_auth_scheme = self._auth_scheme
242
+ connector_auth_credential = self._auth_credential
243
+
244
+ self._tools.append(
245
+ IntegrationConnectorTool(
246
+ name=rest_api_tool.name,
247
+ description=rest_api_tool.description,
248
+ connection_name=connection_details["name"],
249
+ connection_host=connection_details["host"],
250
+ connection_service_name=connection_details["serviceName"],
251
+ entity=entity,
252
+ action=action,
253
+ operation=operation,
254
+ rest_api_tool=rest_api_tool,
255
+ auth_scheme=connector_auth_scheme,
256
+ auth_credential=connector_auth_credential,
257
+ )
258
+ )
259
+
260
+ @override
261
+ async def get_tools(
262
+ self,
263
+ readonly_context: Optional[ReadonlyContext] = None,
264
+ ) -> List[RestApiTool]:
265
+ return (
266
+ [
267
+ tool
268
+ for tool in self._tools
269
+ if self._is_tool_selected(tool, readonly_context)
270
+ ]
271
+ if self._openapi_toolset is None
272
+ else await self._openapi_toolset.get_tools(readonly_context)
273
+ )
274
+
275
+ @override
276
+ async def close(self) -> None:
277
+ if self._openapi_toolset:
278
+ await self._openapi_toolset.close()
@@ -14,7 +14,11 @@
14
14
 
15
15
  import json
16
16
  import time
17
- from typing import Any, Dict, List, Optional, Tuple
17
+ from typing import Any
18
+ from typing import Dict
19
+ from typing import List
20
+ from typing import Optional
21
+ from typing import Tuple
18
22
 
19
23
  import google.auth
20
24
  from google.auth import default as default_service_credential
@@ -554,6 +558,9 @@ class ConnectionsClient:
554
558
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
555
559
  "host": {"$ref": "#/components/schemas/host"},
556
560
  "entity": {"$ref": "#/components/schemas/entity"},
561
+ "dynamicAuthConfig": {
562
+ "$ref": "#/components/schemas/dynamicAuthConfig"
563
+ },
557
564
  },
558
565
  }
559
566
 
@@ -580,6 +587,10 @@ class ConnectionsClient:
580
587
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
581
588
  "host": {"$ref": "#/components/schemas/host"},
582
589
  "entity": {"$ref": "#/components/schemas/entity"},
590
+ "dynamicAuthConfig": {
591
+ "$ref": "#/components/schemas/dynamicAuthConfig"
592
+ },
593
+ "filterClause": {"$ref": "#/components/schemas/filterClause"},
583
594
  },
584
595
  }
585
596
 
@@ -602,6 +613,9 @@ class ConnectionsClient:
602
613
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
603
614
  "host": {"$ref": "#/components/schemas/host"},
604
615
  "entity": {"$ref": "#/components/schemas/entity"},
616
+ "dynamicAuthConfig": {
617
+ "$ref": "#/components/schemas/dynamicAuthConfig"
618
+ },
605
619
  },
606
620
  }
607
621
 
@@ -624,6 +638,10 @@ class ConnectionsClient:
624
638
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
625
639
  "host": {"$ref": "#/components/schemas/host"},
626
640
  "entity": {"$ref": "#/components/schemas/entity"},
641
+ "dynamicAuthConfig": {
642
+ "$ref": "#/components/schemas/dynamicAuthConfig"
643
+ },
644
+ "filterClause": {"$ref": "#/components/schemas/filterClause"},
627
645
  },
628
646
  }
629
647
 
@@ -647,6 +665,9 @@ class ConnectionsClient:
647
665
  "serviceName": {"$ref": "#/components/schemas/serviceName"},
648
666
  "host": {"$ref": "#/components/schemas/host"},
649
667
  "entity": {"$ref": "#/components/schemas/entity"},
668
+ "dynamicAuthConfig": {
669
+ "$ref": "#/components/schemas/dynamicAuthConfig"
670
+ },
650
671
  },
651
672
  }
652
673
 
@@ -671,6 +692,9 @@ class ConnectionsClient:
671
692
  "connectorInputPayload": {
672
693
  "$ref": f"#/components/schemas/connectorInputPayload_{action}"
673
694
  },
695
+ "dynamicAuthConfig": {
696
+ "$ref": "#/components/schemas/dynamicAuthConfig"
697
+ },
674
698
  },
675
699
  }
676
700
 
@@ -708,6 +732,9 @@ class ConnectionsClient:
708
732
  "query": {"$ref": "#/components/schemas/query"},
709
733
  "timeout": {"$ref": "#/components/schemas/timeout"},
710
734
  "pageSize": {"$ref": "#/components/schemas/pageSize"},
735
+ "dynamicAuthConfig": {
736
+ "$ref": "#/components/schemas/dynamicAuthConfig"
737
+ },
711
738
  },
712
739
  }
713
740
 
@@ -13,7 +13,9 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import json
16
+ from typing import List
16
17
  from typing import Optional
18
+
17
19
  from google.adk.tools.application_integration_tool.clients.connections_client import ConnectionsClient
18
20
  import google.auth
19
21
  from google.auth import default as default_service_credential
@@ -35,7 +37,7 @@ class IntegrationClient:
35
37
  project: str,
36
38
  location: str,
37
39
  integration: Optional[str] = None,
38
- trigger: Optional[str] = None,
40
+ triggers: Optional[List[str]] = None,
39
41
  connection: Optional[str] = None,
40
42
  entity_operations: Optional[dict[str, list[str]]] = None,
41
43
  actions: Optional[list[str]] = None,
@@ -47,7 +49,7 @@ class IntegrationClient:
47
49
  project: The Google Cloud project ID.
48
50
  location: The Google Cloud location (e.g., us-central1).
49
51
  integration: The integration name.
50
- trigger: The trigger ID for the integration.
52
+ triggers: The list of trigger IDs for the integration.
51
53
  connection: The connection name.
52
54
  entity_operations: A dictionary mapping entity names to a list of
53
55
  operations (e.g., LIST, CREATE, UPDATE, DELETE, GET).
@@ -59,7 +61,7 @@ class IntegrationClient:
59
61
  self.project = project
60
62
  self.location = location
61
63
  self.integration = integration
62
- self.trigger = trigger
64
+ self.triggers = triggers
63
65
  self.connection = connection
64
66
  self.entity_operations = (
65
67
  entity_operations if entity_operations is not None else {}
@@ -88,7 +90,7 @@ class IntegrationClient:
88
90
  "apiTriggerResources": [
89
91
  {
90
92
  "integrationResource": self.integration,
91
- "triggerId": [self.trigger],
93
+ "triggerId": self.triggers,
92
94
  },
93
95
  ],
94
96
  "fileFormat": "JSON",
@@ -109,7 +111,7 @@ class IntegrationClient:
109
111
  raise ValueError(
110
112
  "Invalid request. Please check the provided values of"
111
113
  f" project({self.project}), location({self.location}),"
112
- f" integration({self.integration}) and trigger({self.trigger})."
114
+ f" integration({self.integration})."
113
115
  ) from e
114
116
  raise ValueError(f"Request error: {e}") from e
115
117
  except Exception as e: