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
@@ -12,255 +12,160 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from contextlib import AsyncExitStack
15
+ import logging
16
16
  import sys
17
- from types import TracebackType
18
- from typing import List, Optional, TextIO, Tuple, Type
19
-
20
- from .mcp_session_manager import MCPSessionManager, SseServerParams, retry_on_closed_resource
17
+ from typing import List
18
+ from typing import Optional
19
+ from typing import TextIO
20
+ from typing import Union
21
+
22
+ from ...agents.readonly_context import ReadonlyContext
23
+ from ..base_tool import BaseTool
24
+ from ..base_toolset import BaseToolset
25
+ from ..base_toolset import ToolPredicate
26
+ from .mcp_session_manager import MCPSessionManager
27
+ from .mcp_session_manager import retry_on_closed_resource
28
+ from .mcp_session_manager import SseServerParams
21
29
 
22
30
  # Attempt to import MCP Tool from the MCP library, and hints user to upgrade
23
31
  # their Python version to 3.10 if it fails.
24
32
  try:
25
- from mcp import ClientSession, StdioServerParameters
33
+ from mcp import StdioServerParameters
26
34
  from mcp.types import ListToolsResult
27
35
  except ImportError as e:
28
36
  import sys
29
37
 
30
38
  if sys.version_info < (3, 10):
31
39
  raise ImportError(
32
- 'MCP Tool requires Python 3.10 or above. Please upgrade your Python'
33
- ' version.'
40
+ "MCP Tool requires Python 3.10 or above. Please upgrade your Python"
41
+ " version."
34
42
  ) from e
35
43
  else:
36
44
  raise e
37
45
 
38
46
  from .mcp_tool import MCPTool
39
47
 
48
+ logger = logging.getLogger("google_adk." + __name__)
49
+
40
50
 
41
- class MCPToolset:
51
+ class MCPToolset(BaseToolset):
42
52
  """Connects to a MCP Server, and retrieves MCP Tools into ADK Tools.
43
53
 
54
+ This toolset manages the connection to an MCP server and provides tools
55
+ that can be used by an agent. It properly implements the BaseToolset
56
+ interface for easy integration with the agent framework.
57
+
44
58
  Usage:
45
- Example 1: (using from_server helper):
46
- ```
47
- async def load_tools():
48
- return await MCPToolset.from_server(
59
+ ```python
60
+ toolset = MCPToolset(
49
61
  connection_params=StdioServerParameters(
50
62
  command='npx',
51
63
  args=["-y", "@modelcontextprotocol/server-filesystem"],
52
- )
53
- )
64
+ ),
65
+ tool_filter=['read_file', 'list_directory'] # Optional: filter specific tools
66
+ )
54
67
 
55
- # Use the tools in an LLM agent
56
- tools, exit_stack = await load_tools()
68
+ # Use in an agent
57
69
  agent = LlmAgent(
58
- tools=tools
70
+ model='gemini-2.0-flash',
71
+ name='enterprise_assistant',
72
+ instruction='Help user accessing their file systems',
73
+ tools=[toolset],
59
74
  )
60
- ...
61
- await exit_stack.aclose()
62
- ```
63
-
64
- Example 2: (using `async with`):
65
-
66
- ```
67
- async def load_tools():
68
- async with MCPToolset(
69
- connection_params=SseServerParams(url="http://0.0.0.0:8090/sse")
70
- ) as toolset:
71
- tools = await toolset.load_tools()
72
-
73
- agent = LlmAgent(
74
- ...
75
- tools=tools
76
- )
77
- ```
78
-
79
- Example 3: (provide AsyncExitStack):
80
- ```
81
- async def load_tools():
82
- async_exit_stack = AsyncExitStack()
83
- toolset = MCPToolset(
84
- connection_params=StdioServerParameters(...),
85
- )
86
- async_exit_stack.enter_async_context(toolset)
87
- tools = await toolset.load_tools()
88
- agent = LlmAgent(
89
- ...
90
- tools=tools
91
- )
92
- ...
93
- await async_exit_stack.aclose()
94
75
 
76
+ # Cleanup is handled automatically by the agent framework
77
+ # But you can also manually close if needed:
78
+ # await toolset.close()
95
79
  ```
96
-
97
- Attributes:
98
- connection_params: The connection parameters to the MCP server. Can be
99
- either `StdioServerParameters` or `SseServerParams`.
100
- exit_stack: The async exit stack to manage the connection to the MCP server.
101
- session: The MCP session being initialized with the connection.
102
80
  """
103
81
 
104
82
  def __init__(
105
83
  self,
106
84
  *,
107
85
  connection_params: StdioServerParameters | SseServerParams,
86
+ tool_filter: Optional[Union[ToolPredicate, List[str]]] = None,
108
87
  errlog: TextIO = sys.stderr,
109
- exit_stack=AsyncExitStack(),
110
88
  ):
111
89
  """Initializes the MCPToolset.
112
90
 
113
- Usage:
114
- Example 1: (using from_server helper):
115
- ```
116
- async def load_tools():
117
- return await MCPToolset.from_server(
118
- connection_params=StdioServerParameters(
119
- command='npx',
120
- args=["-y", "@modelcontextprotocol/server-filesystem"],
121
- )
122
- )
123
-
124
- # Use the tools in an LLM agent
125
- tools, exit_stack = await load_tools()
126
- agent = LlmAgent(
127
- tools=tools
128
- )
129
- ...
130
- await exit_stack.aclose()
131
- ```
132
-
133
- Example 2: (using `async with`):
134
-
135
- ```
136
- async def load_tools():
137
- async with MCPToolset(
138
- connection_params=SseServerParams(url="http://0.0.0.0:8090/sse")
139
- ) as toolset:
140
- tools = await toolset.load_tools()
141
-
142
- agent = LlmAgent(
143
- ...
144
- tools=tools
145
- )
146
- ```
147
-
148
- Example 3: (provide AsyncExitStack):
149
- ```
150
- async def load_tools():
151
- async_exit_stack = AsyncExitStack()
152
- toolset = MCPToolset(
153
- connection_params=StdioServerParameters(...),
154
- )
155
- async_exit_stack.enter_async_context(toolset)
156
- tools = await toolset.load_tools()
157
- agent = LlmAgent(
158
- ...
159
- tools=tools
160
- )
161
- ...
162
- await async_exit_stack.aclose()
163
-
164
- ```
165
-
166
91
  Args:
167
- connection_params: The connection parameters to the MCP server. Can be:
168
- `StdioServerParameters` for using local mcp server (e.g. using `npx` or
169
- `python3`); or `SseServerParams` for a local/remote SSE server.
92
+ connection_params: The connection parameters to the MCP server. Can be:
93
+ `StdioServerParameters` for using local mcp server (e.g. using `npx` or
94
+ `python3`); or `SseServerParams` for a local/remote SSE server.
95
+ tool_filter: Optional filter to select specific tools. Can be either:
96
+ - A list of tool names to include
97
+ - A ToolPredicate function for custom filtering logic
98
+ errlog: TextIO stream for error logging.
170
99
  """
100
+ super().__init__(tool_filter=tool_filter)
101
+
171
102
  if not connection_params:
172
- raise ValueError('Missing connection params in MCPToolset.')
173
- self.connection_params = connection_params
174
- self.errlog = errlog
175
- self.exit_stack = exit_stack
103
+ raise ValueError("Missing connection params in MCPToolset.")
176
104
 
177
- self.session_manager = MCPSessionManager(
178
- connection_params=self.connection_params,
179
- exit_stack=self.exit_stack,
180
- errlog=self.errlog,
181
- )
105
+ self._connection_params = connection_params
106
+ self._errlog = errlog
182
107
 
183
- @classmethod
184
- async def from_server(
185
- cls,
186
- *,
187
- connection_params: StdioServerParameters | SseServerParams,
188
- async_exit_stack: Optional[AsyncExitStack] = None,
189
- errlog: TextIO = sys.stderr,
190
- ) -> Tuple[List[MCPTool], AsyncExitStack]:
191
- """Retrieve all tools from the MCP connection.
108
+ # Create the session manager that will handle the MCP connection
109
+ self._mcp_session_manager = MCPSessionManager(
110
+ connection_params=self._connection_params,
111
+ errlog=self._errlog,
112
+ )
113
+ self._session = None
192
114
 
193
- Usage:
194
- ```
195
- async def load_tools():
196
- tools, exit_stack = await MCPToolset.from_server(
197
- connection_params=StdioServerParameters(
198
- command='npx',
199
- args=["-y", "@modelcontextprotocol/server-filesystem"],
200
- )
201
- )
202
- ```
115
+ @retry_on_closed_resource("_reinitialize_session")
116
+ async def get_tools(
117
+ self,
118
+ readonly_context: Optional[ReadonlyContext] = None,
119
+ ) -> List[BaseTool]:
120
+ """Return all tools in the toolset based on the provided context.
203
121
 
204
122
  Args:
205
- connection_params: The connection parameters to the MCP server.
206
- async_exit_stack: The async exit stack to use. If not provided, a new
207
- AsyncExitStack will be created.
123
+ readonly_context: Context used to filter tools available to the agent.
124
+ If None, all tools in the toolset are returned.
208
125
 
209
126
  Returns:
210
- A tuple of the list of MCPTools and the AsyncExitStack.
211
- - tools: The list of MCPTools.
212
- - async_exit_stack: The AsyncExitStack used to manage the connection to
213
- the MCP server. Use `await async_exit_stack.aclose()` to close the
214
- connection when server shuts down.
127
+ List[BaseTool]: A list of tools available under the specified context.
215
128
  """
216
- async_exit_stack = async_exit_stack or AsyncExitStack()
217
- toolset = cls(
218
- connection_params=connection_params,
219
- exit_stack=async_exit_stack,
220
- errlog=errlog,
221
- )
129
+ # Get session from session manager
130
+ if not self._session:
131
+ self._session = await self._mcp_session_manager.create_session()
132
+
133
+ # Fetch available tools from the MCP server
134
+ tools_response: ListToolsResult = await self._session.list_tools()
135
+
136
+ # Apply filtering based on context and tool_filter
137
+ tools = []
138
+ for tool in tools_response.tools:
139
+ mcp_tool = MCPTool(
140
+ mcp_tool=tool,
141
+ mcp_session_manager=self._mcp_session_manager,
142
+ )
222
143
 
223
- await async_exit_stack.enter_async_context(toolset)
224
- tools = await toolset.load_tools()
225
- return (tools, async_exit_stack)
144
+ if self._is_tool_selected(mcp_tool, readonly_context):
145
+ tools.append(mcp_tool)
146
+ return tools
226
147
 
227
- async def _initialize(self) -> ClientSession:
228
- """Connects to the MCP Server and initializes the ClientSession."""
229
- self.session = await self.session_manager.create_session()
230
- return self.session
148
+ async def _reinitialize_session(self):
149
+ """Reinitializes the session when connection is lost."""
150
+ # Close the old session and clear cache
151
+ await self._mcp_session_manager.close()
152
+ self._session = await self._mcp_session_manager.create_session()
231
153
 
232
- async def _exit(self):
233
- """Closes the connection to MCP Server."""
234
- await self.exit_stack.aclose()
154
+ # Tools will be reloaded on next get_tools call
235
155
 
236
- @retry_on_closed_resource('_initialize')
237
- async def load_tools(self) -> List[MCPTool]:
238
- """Loads all tools from the MCP Server.
156
+ async def close(self) -> None:
157
+ """Performs cleanup and releases resources held by the toolset.
239
158
 
240
- Returns:
241
- A list of MCPTools imported from the MCP Server.
159
+ This method closes the MCP session and cleans up all associated resources.
160
+ It's designed to be safe to call multiple times and handles cleanup errors
161
+ gracefully to avoid blocking application shutdown.
242
162
  """
243
- tools_response: ListToolsResult = await self.session.list_tools()
244
- return [
245
- MCPTool(
246
- mcp_tool=tool,
247
- mcp_session=self.session,
248
- mcp_session_manager=self.session_manager,
249
- )
250
- for tool in tools_response.tools
251
- ]
252
-
253
- async def __aenter__(self):
254
163
  try:
255
- await self._initialize()
256
- return self
164
+ await self._mcp_session_manager.close()
257
165
  except Exception as e:
258
- raise e
259
-
260
- async def __aexit__(
261
- self,
262
- exc_type: Optional[Type[BaseException]],
263
- exc: Optional[BaseException],
264
- tb: Optional[TracebackType],
265
- ) -> None:
266
- await self._exit()
166
+ # Log the error but don't re-raise to avoid blocking shutdown
167
+ print(f"Warning: Error during MCPToolset cleanup: {e}", file=self._errlog)
168
+ finally:
169
+ # Clear cached tools
170
+ self._tools_cache = None
171
+ self._tools_loaded = False
@@ -15,9 +15,7 @@
15
15
  import abc
16
16
  from typing import Optional
17
17
 
18
- from .....auth.auth_credential import (
19
- AuthCredential,
20
- )
18
+ from .....auth.auth_credential import AuthCredential
21
19
  from .....auth.auth_schemes import AuthScheme
22
20
 
23
21
 
@@ -21,14 +21,13 @@ from google.auth.transport.requests import Request
21
21
  from google.oauth2 import service_account
22
22
  import google.oauth2.credentials
23
23
 
24
- from .....auth.auth_credential import (
25
- AuthCredential,
26
- AuthCredentialTypes,
27
- HttpAuth,
28
- HttpCredentials,
29
- )
24
+ from .....auth.auth_credential import AuthCredential
25
+ from .....auth.auth_credential import AuthCredentialTypes
26
+ from .....auth.auth_credential import HttpAuth
27
+ from .....auth.auth_credential import HttpCredentials
30
28
  from .....auth.auth_schemes import AuthScheme
31
- from .base_credential_exchanger import AuthCredentialMissingError, BaseAuthCredentialExchanger
29
+ from .base_credential_exchanger import AuthCredentialMissingError
30
+ from .base_credential_exchanger import BaseAuthCredentialExchanger
32
31
 
33
32
 
34
33
  class ServiceAccountCredentialExchanger(BaseAuthCredentialExchanger):
@@ -14,7 +14,11 @@
14
14
 
15
15
  import keyword
16
16
  import re
17
- from typing import Any, Dict, List, Optional, Union
17
+ from typing import Any
18
+ from typing import Dict
19
+ from typing import List
20
+ from typing import Optional
21
+ from typing import Union
18
22
 
19
23
  from fastapi.openapi.models import Response
20
24
  from fastapi.openapi.models import Schema
@@ -12,10 +12,15 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from .openapi_spec_parser import OpenApiSpecParser, OperationEndpoint, ParsedOperation
15
+ from .openapi_spec_parser import OpenApiSpecParser
16
+ from .openapi_spec_parser import OperationEndpoint
17
+ from .openapi_spec_parser import ParsedOperation
16
18
  from .openapi_toolset import OpenAPIToolset
17
19
  from .operation_parser import OperationParser
18
- from .rest_api_tool import AuthPreparationState, RestApiTool, snake_to_lower_camel, to_gemini_schema
20
+ from .rest_api_tool import AuthPreparationState
21
+ from .rest_api_tool import RestApiTool
22
+ from .rest_api_tool import snake_to_lower_camel
23
+ from .rest_api_tool import to_gemini_schema
19
24
  from .tool_auth_handler import ToolAuthHandler
20
25
 
21
26
  __all__ = [
@@ -20,18 +20,23 @@ from typing import Final
20
20
  from typing import List
21
21
  from typing import Literal
22
22
  from typing import Optional
23
+ from typing import Union
23
24
 
25
+ from typing_extensions import override
24
26
  import yaml
25
27
 
28
+ from ....agents.readonly_context import ReadonlyContext
26
29
  from ....auth.auth_credential import AuthCredential
27
30
  from ....auth.auth_schemes import AuthScheme
31
+ from ...base_toolset import BaseToolset
32
+ from ...base_toolset import ToolPredicate
28
33
  from .openapi_spec_parser import OpenApiSpecParser
29
34
  from .rest_api_tool import RestApiTool
30
35
 
31
- logger = logging.getLogger(__name__)
36
+ logger = logging.getLogger("google_adk." + __name__)
32
37
 
33
38
 
34
- class OpenAPIToolset:
39
+ class OpenAPIToolset(BaseToolset):
35
40
  """Class for parsing OpenAPI spec into a list of RestApiTool.
36
41
 
37
42
  Usage:
@@ -61,6 +66,7 @@ class OpenAPIToolset:
61
66
  spec_str_type: Literal["json", "yaml"] = "json",
62
67
  auth_scheme: Optional[AuthScheme] = None,
63
68
  auth_credential: Optional[AuthCredential] = None,
69
+ tool_filter: Optional[Union[ToolPredicate, List[str]]] = None,
64
70
  ):
65
71
  """Initializes the OpenAPIToolset.
66
72
 
@@ -94,10 +100,13 @@ class OpenAPIToolset:
94
100
  auth_credential: The auth credential to use for all tools. Use
95
101
  AuthCredential or use helpers in
96
102
  `google.adk.tools.openapi_tool.auth.auth_helpers`
103
+ tool_filter: The filter used to filter the tools in the toolset. It can be
104
+ either a tool predicate or a list of tool names of the tools to expose.
97
105
  """
106
+ super().__init__(tool_filter=tool_filter)
98
107
  if not spec_dict:
99
108
  spec_dict = self._load_spec(spec_str, spec_str_type)
100
- self.tools: Final[List[RestApiTool]] = list(self._parse(spec_dict))
109
+ self._tools: Final[List[RestApiTool]] = list(self._parse(spec_dict))
101
110
  if auth_scheme or auth_credential:
102
111
  self._configure_auth_all(auth_scheme, auth_credential)
103
112
 
@@ -106,19 +115,26 @@ class OpenAPIToolset:
106
115
  ):
107
116
  """Configure auth scheme and credential for all tools."""
108
117
 
109
- for tool in self.tools:
118
+ for tool in self._tools:
110
119
  if auth_scheme:
111
120
  tool.configure_auth_scheme(auth_scheme)
112
121
  if auth_credential:
113
122
  tool.configure_auth_credential(auth_credential)
114
123
 
115
- def get_tools(self) -> List[RestApiTool]:
124
+ @override
125
+ async def get_tools(
126
+ self, readonly_context: Optional[ReadonlyContext] = None
127
+ ) -> List[RestApiTool]:
116
128
  """Get all tools in the toolset."""
117
- return self.tools
129
+ return [
130
+ tool
131
+ for tool in self._tools
132
+ if self._is_tool_selected(tool, readonly_context)
133
+ ]
118
134
 
119
135
  def get_tool(self, tool_name: str) -> Optional[RestApiTool]:
120
136
  """Get a tool by name."""
121
- matching_tool = filter(lambda t: t.name == tool_name, self.tools)
137
+ matching_tool = filter(lambda t: t.name == tool_name, self._tools)
122
138
  return next(matching_tool, None)
123
139
 
124
140
  def _load_spec(
@@ -142,3 +158,7 @@ class OpenAPIToolset:
142
158
  logger.info("Parsed tool: %s", tool.name)
143
159
  tools.append(tool)
144
160
  return tools
161
+
162
+ @override
163
+ async def close(self):
164
+ pass