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.
- google/adk/agents/base_agent.py +76 -30
- google/adk/agents/callback_context.py +2 -6
- google/adk/agents/llm_agent.py +122 -30
- google/adk/agents/loop_agent.py +1 -1
- google/adk/agents/parallel_agent.py +7 -0
- google/adk/agents/readonly_context.py +8 -0
- google/adk/agents/run_config.py +1 -1
- google/adk/agents/sequential_agent.py +31 -0
- google/adk/agents/transcription_entry.py +4 -2
- google/adk/artifacts/gcs_artifact_service.py +1 -1
- google/adk/artifacts/in_memory_artifact_service.py +1 -1
- google/adk/auth/auth_credential.py +10 -2
- google/adk/auth/auth_preprocessor.py +7 -1
- google/adk/auth/auth_tool.py +3 -4
- google/adk/cli/agent_graph.py +5 -5
- google/adk/cli/browser/index.html +4 -4
- google/adk/cli/browser/{main-ULN5R5I5.js → main-PKDNKWJE.js} +59 -60
- google/adk/cli/browser/polyfills-B6TNHZQ6.js +17 -0
- google/adk/cli/cli.py +10 -9
- google/adk/cli/cli_deploy.py +7 -2
- google/adk/cli/cli_eval.py +109 -115
- google/adk/cli/cli_tools_click.py +179 -67
- google/adk/cli/fast_api.py +248 -197
- google/adk/cli/utils/agent_loader.py +137 -0
- google/adk/cli/utils/cleanup.py +40 -0
- google/adk/cli/utils/common.py +23 -0
- google/adk/cli/utils/evals.py +83 -0
- google/adk/cli/utils/logs.py +8 -5
- google/adk/code_executors/__init__.py +3 -1
- google/adk/code_executors/built_in_code_executor.py +52 -0
- google/adk/code_executors/code_execution_utils.py +2 -1
- google/adk/code_executors/container_code_executor.py +0 -1
- google/adk/code_executors/vertex_ai_code_executor.py +6 -8
- google/adk/evaluation/__init__.py +1 -1
- google/adk/evaluation/agent_evaluator.py +168 -128
- google/adk/evaluation/eval_case.py +104 -0
- google/adk/evaluation/eval_metrics.py +74 -0
- google/adk/evaluation/eval_result.py +86 -0
- google/adk/evaluation/eval_set.py +39 -0
- google/adk/evaluation/eval_set_results_manager.py +47 -0
- google/adk/evaluation/eval_sets_manager.py +43 -0
- google/adk/evaluation/evaluation_generator.py +88 -113
- google/adk/evaluation/evaluator.py +58 -0
- google/adk/evaluation/local_eval_set_results_manager.py +113 -0
- google/adk/evaluation/local_eval_sets_manager.py +264 -0
- google/adk/evaluation/response_evaluator.py +106 -1
- google/adk/evaluation/trajectory_evaluator.py +84 -2
- google/adk/events/event.py +6 -1
- google/adk/events/event_actions.py +6 -1
- google/adk/examples/base_example_provider.py +1 -0
- google/adk/examples/example_util.py +3 -2
- google/adk/flows/llm_flows/_code_execution.py +9 -1
- google/adk/flows/llm_flows/audio_transcriber.py +4 -3
- google/adk/flows/llm_flows/base_llm_flow.py +58 -21
- google/adk/flows/llm_flows/contents.py +3 -1
- google/adk/flows/llm_flows/functions.py +9 -8
- google/adk/flows/llm_flows/instructions.py +18 -80
- google/adk/flows/llm_flows/single_flow.py +2 -2
- google/adk/memory/__init__.py +1 -1
- google/adk/memory/_utils.py +23 -0
- google/adk/memory/base_memory_service.py +23 -21
- google/adk/memory/in_memory_memory_service.py +57 -25
- google/adk/memory/memory_entry.py +37 -0
- google/adk/memory/vertex_ai_rag_memory_service.py +38 -15
- google/adk/models/anthropic_llm.py +16 -9
- google/adk/models/base_llm.py +2 -1
- google/adk/models/base_llm_connection.py +2 -0
- google/adk/models/gemini_llm_connection.py +11 -11
- google/adk/models/google_llm.py +12 -2
- google/adk/models/lite_llm.py +80 -23
- google/adk/models/llm_response.py +16 -3
- google/adk/models/registry.py +1 -1
- google/adk/runners.py +98 -42
- google/adk/sessions/__init__.py +1 -1
- google/adk/sessions/_session_util.py +2 -1
- google/adk/sessions/base_session_service.py +6 -33
- google/adk/sessions/database_session_service.py +57 -67
- google/adk/sessions/in_memory_session_service.py +106 -24
- google/adk/sessions/session.py +3 -0
- google/adk/sessions/vertex_ai_session_service.py +44 -51
- google/adk/telemetry.py +7 -2
- google/adk/tools/__init__.py +4 -7
- google/adk/tools/_memory_entry_utils.py +30 -0
- google/adk/tools/agent_tool.py +10 -10
- google/adk/tools/apihub_tool/apihub_toolset.py +55 -74
- google/adk/tools/apihub_tool/clients/apihub_client.py +10 -3
- google/adk/tools/apihub_tool/clients/secret_client.py +1 -0
- google/adk/tools/application_integration_tool/application_integration_toolset.py +111 -85
- google/adk/tools/application_integration_tool/clients/connections_client.py +28 -1
- google/adk/tools/application_integration_tool/clients/integration_client.py +7 -5
- google/adk/tools/application_integration_tool/integration_connector_tool.py +69 -26
- google/adk/tools/base_toolset.py +96 -0
- google/adk/tools/bigquery/__init__.py +28 -0
- google/adk/tools/bigquery/bigquery_credentials.py +216 -0
- google/adk/tools/bigquery/bigquery_tool.py +116 -0
- google/adk/tools/{built_in_code_execution_tool.py → enterprise_search_tool.py} +17 -11
- google/adk/tools/function_parameter_parse_util.py +9 -2
- google/adk/tools/function_tool.py +33 -3
- google/adk/tools/get_user_choice_tool.py +1 -0
- google/adk/tools/google_api_tool/__init__.py +24 -70
- google/adk/tools/google_api_tool/google_api_tool.py +12 -6
- google/adk/tools/google_api_tool/{google_api_tool_set.py → google_api_toolset.py} +57 -55
- google/adk/tools/google_api_tool/google_api_toolsets.py +108 -0
- google/adk/tools/google_api_tool/googleapi_to_openapi_converter.py +40 -42
- google/adk/tools/google_search_tool.py +2 -2
- google/adk/tools/langchain_tool.py +96 -49
- google/adk/tools/load_memory_tool.py +14 -5
- google/adk/tools/mcp_tool/__init__.py +3 -2
- google/adk/tools/mcp_tool/conversion_utils.py +6 -2
- google/adk/tools/mcp_tool/mcp_session_manager.py +80 -69
- google/adk/tools/mcp_tool/mcp_tool.py +35 -32
- google/adk/tools/mcp_tool/mcp_toolset.py +99 -194
- google/adk/tools/openapi_tool/auth/credential_exchangers/base_credential_exchanger.py +1 -3
- google/adk/tools/openapi_tool/auth/credential_exchangers/service_account_exchanger.py +6 -7
- google/adk/tools/openapi_tool/common/common.py +5 -1
- google/adk/tools/openapi_tool/openapi_spec_parser/__init__.py +7 -2
- google/adk/tools/openapi_tool/openapi_spec_parser/openapi_toolset.py +27 -7
- google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +36 -32
- google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +11 -1
- google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +1 -1
- google/adk/tools/preload_memory_tool.py +27 -18
- google/adk/tools/retrieval/__init__.py +1 -1
- google/adk/tools/retrieval/vertex_ai_rag_retrieval.py +1 -1
- google/adk/tools/toolbox_toolset.py +107 -0
- google/adk/tools/transfer_to_agent_tool.py +0 -1
- google/adk/utils/__init__.py +13 -0
- google/adk/utils/instructions_utils.py +131 -0
- google/adk/version.py +1 -1
- {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/METADATA +18 -19
- google_adk-1.1.0.dist-info/RECORD +200 -0
- google/adk/agents/remote_agent.py +0 -50
- google/adk/cli/browser/polyfills-FFHMD2TL.js +0 -18
- google/adk/cli/fast_api.py.orig +0 -728
- google/adk/tools/google_api_tool/google_api_tool_sets.py +0 -112
- google/adk/tools/toolbox_tool.py +0 -46
- google_adk-0.5.0.dist-info/RECORD +0 -180
- {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/WHEEL +0 -0
- {google_adk-0.5.0.dist-info → google_adk-1.1.0.dist-info}/entry_points.txt +0 -0
- {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
|
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
|
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
|
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
|
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.
|
125
|
-
self.
|
126
|
-
self.
|
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.
|
132
|
-
self.
|
133
|
-
self.
|
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
|
-
|
148
|
+
if not self._lazy_load_spec:
|
149
|
+
self._prepare_toolset()
|
156
150
|
|
157
|
-
|
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.
|
164
|
-
self.
|
165
|
-
|
166
|
-
|
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
|
-
|
175
|
-
|
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
|
-
|
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
|
-
|
180
|
+
self._openapi_toolset = OpenAPIToolset(
|
205
181
|
spec_dict=spec_dict,
|
206
|
-
auth_credential=self.
|
207
|
-
auth_scheme=self.
|
208
|
-
|
209
|
-
|
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
|
15
|
+
from abc import ABC
|
16
|
+
from abc import abstractmethod
|
16
17
|
import base64
|
17
18
|
import json
|
18
|
-
from typing import Any
|
19
|
-
from
|
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
|
@@ -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
|
-
|
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
|
-
|
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
|
-
#
|
76
|
+
# Feed the toolset to agent
|
67
77
|
agent = LlmAgent(tools=[
|
68
|
-
|
69
|
-
|
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
|
-
|
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
|
-
|
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
|
-
"""
|
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
|
-
|
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
|
-
|
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
|
145
|
-
|
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.
|
152
|
-
self.
|
153
|
-
self.
|
154
|
-
self.
|
155
|
-
self.
|
156
|
-
self.
|
157
|
-
self.
|
158
|
-
self.
|
159
|
-
self.
|
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
|
-
|
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
|
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
|
-
|
164
|
+
tool_name_prefix,
|
181
165
|
tool_instructions,
|
182
166
|
)
|
183
167
|
else:
|
184
168
|
raise ValueError(
|
185
|
-
"Either
|
169
|
+
"Invalid request, Either integration or (connection and"
|
186
170
|
" (entity_operations or actions)) should be provided."
|
187
171
|
)
|
188
|
-
self.
|
172
|
+
self._openapi_toolset = None
|
173
|
+
self._tools = []
|
174
|
+
self._parse_spec_to_toolset(spec, connection_details)
|
189
175
|
|
190
|
-
def
|
191
|
-
"""Parses the spec dict to
|
192
|
-
if self.
|
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.
|
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.
|
214
|
-
|
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
|
-
|
219
|
-
|
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
|
-
|
239
|
-
|
240
|
-
|
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
|
-
|
252
|
-
|
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
|
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
|
-
|
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
|
-
|
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.
|
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":
|
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})
|
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:
|