From 682550dfa73910affa377e7d08cd99241e608b69 Mon Sep 17 00:00:00 2001 From: Anubhav Dhawan Date: Wed, 10 Dec 2025 17:18:58 +0530 Subject: [PATCH 1/4] feat: Modify the ADK ToolboxToolset --- src/google/adk/tools/toolbox_toolset.py | 88 ++++++++++++------------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/src/google/adk/tools/toolbox_toolset.py b/src/google/adk/tools/toolbox_toolset.py index 51c50d194d..1384d996d7 100644 --- a/src/google/adk/tools/toolbox_toolset.py +++ b/src/google/adk/tools/toolbox_toolset.py @@ -19,22 +19,27 @@ from typing import Optional from typing import Union -import toolbox_core as toolbox from typing_extensions import override from ..agents.readonly_context import ReadonlyContext from .base_tool import BaseTool from .base_toolset import BaseToolset -from .function_tool import FunctionTool class ToolboxToolset(BaseToolset): """A class that provides access to toolbox toolsets. + This class acts as a bridge to the `toolbox-adk` package. + You must install `toolbox-adk` to use this class. + Example: ```python - toolbox_toolset = ToolboxToolset("http://127.0.0.1:5000", - toolset_name="my-toolset") + from toolbox_adk import CredentialStrategy + + toolbox_toolset = ToolboxToolset( + server_url="http://127.0.0.1:5000", + # toolset_name and tool_names are optional. If omitted, all tools are loaded. + credentials=CredentialStrategy.toolbox_identity() ) ``` """ @@ -48,60 +53,51 @@ def __init__( bound_params: Optional[ Mapping[str, Union[Callable[[], Any], Any]] ] = None, + # New args mapping to toolbox-adk + credentials: Optional[Any] = None, + additional_headers: Optional[dict[str, str]] = None, + **kwargs, ): """Args: - server_url: The URL of the toolbox server. toolset_name: The name of the toolbox toolset to load. tool_names: The names of the tools to load. - auth_token_getters: A mapping of authentication service names to - callables that return the corresponding authentication token. see: - https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main/packages/toolbox-core#authenticating-tools - for details. - bound_params: A mapping of parameter names to bind to specific values or - callables that are called to produce values as needed. see: - https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main/packages/toolbox-core#binding-parameter-values - for details. - The resulting ToolboxToolset will contain both tools loaded by tool_names - and toolset_name. + auth_token_getters: (Deprecated) Map of auth token getters. + bound_params: Parameters to bind to the tools. + credentials: (Optional) toolbox_adk.CredentialConfig object. + additional_headers: (Optional) Static headers dictionary. + **kwargs: Additional arguments passed to the underlying toolbox_adk.ToolboxToolset. """ - if not tool_names and not toolset_name: - raise ValueError("tool_names and toolset_name cannot both be None") + try: + from toolbox_adk import ToolboxToolset as RealToolboxToolset # pylint: disable=import-outside-toplevel + except ImportError as exc: + raise ImportError( + "ToolboxToolset requires the 'toolbox-adk' package. " + "Please install it using `pip install toolbox-adk`." + ) from exc + super().__init__() - self._server_url = server_url - self._toolbox_client = toolbox.ToolboxClient(server_url) - self._toolset_name = toolset_name - self._tool_names = tool_names - self._auth_token_getters = auth_token_getters or {} - self._bound_params = bound_params or {} + + # Delegate to the real implementation in toolbox-adk. + + self._delegate = RealToolboxToolset( + server_url=server_url, + toolset_name=toolset_name, + tool_names=tool_names, + credentials=credentials, + additional_headers=additional_headers, + bound_params=bound_params, + # Backward compatibility: Pass legacy args via kwargs. + auth_token_getters=auth_token_getters, + **kwargs + ) @override async def get_tools( self, readonly_context: Optional[ReadonlyContext] = None ) -> list[BaseTool]: - tools = [] - if self._toolset_name: - tools.extend([ - FunctionTool(tool) - for tool in await self._toolbox_client.load_toolset( - self._toolset_name, - auth_token_getters=self._auth_token_getters, - bound_params=self._bound_params, - ) - ]) - if self._tool_names: - tools.extend([ - FunctionTool( - await self._toolbox_client.load_tool( - tool_name, - auth_token_getters=self._auth_token_getters, - bound_params=self._bound_params, - ) - ) - for tool_name in self._tool_names - ]) - return tools + return await self._delegate.get_tools(readonly_context) @override async def close(self): - self._toolbox_client.close() + await self._delegate.close() From a7b573b49c3a6f075ffd70501b957805bda8855a Mon Sep 17 00:00:00 2001 From: Anubhav Dhawan Date: Thu, 18 Dec 2025 19:27:01 +0530 Subject: [PATCH 2/4] refactor(tools): address PR feedback for ToolboxToolset Removes verbose comments, improves type hints (dict -> Mapping), and restores validation check for toolset/tool names. --- src/google/adk/tools/toolbox_toolset.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/google/adk/tools/toolbox_toolset.py b/src/google/adk/tools/toolbox_toolset.py index 1384d996d7..5c07cf2bfd 100644 --- a/src/google/adk/tools/toolbox_toolset.py +++ b/src/google/adk/tools/toolbox_toolset.py @@ -49,13 +49,12 @@ def __init__( server_url: str, toolset_name: Optional[str] = None, tool_names: Optional[List[str]] = None, - auth_token_getters: Optional[dict[str, Callable[[], str]]] = None, + auth_token_getters: Optional[Mapping[str, Callable[[], str]]] = None, bound_params: Optional[ Mapping[str, Union[Callable[[], Any], Any]] ] = None, - # New args mapping to toolbox-adk credentials: Optional[Any] = None, - additional_headers: Optional[dict[str, str]] = None, + additional_headers: Optional[Mapping[str, str]] = None, **kwargs, ): """Args: @@ -68,6 +67,9 @@ def __init__( additional_headers: (Optional) Static headers dictionary. **kwargs: Additional arguments passed to the underlying toolbox_adk.ToolboxToolset. """ + if not toolset_name and not tool_names: + raise ValueError("Either 'toolset_name' or 'tool_names' must be provided.") + try: from toolbox_adk import ToolboxToolset as RealToolboxToolset # pylint: disable=import-outside-toplevel except ImportError as exc: @@ -75,11 +77,9 @@ def __init__( "ToolboxToolset requires the 'toolbox-adk' package. " "Please install it using `pip install toolbox-adk`." ) from exc - + super().__init__() - - # Delegate to the real implementation in toolbox-adk. - + self._delegate = RealToolboxToolset( server_url=server_url, toolset_name=toolset_name, @@ -87,8 +87,7 @@ def __init__( credentials=credentials, additional_headers=additional_headers, bound_params=bound_params, - # Backward compatibility: Pass legacy args via kwargs. - auth_token_getters=auth_token_getters, + auth_token_getters=auth_token_getters, **kwargs ) From 60d4ffdc9de2a6889a6f56d96e0879f9cc4f9b33 Mon Sep 17 00:00:00 2001 From: Anubhav Dhawan Date: Thu, 18 Dec 2025 19:39:38 +0530 Subject: [PATCH 3/4] style: fix pyink formatting and missing future import Adds 'from __future__ import annotations' and fixes Pyink formatting validation errors (docstring Indentation, trailing comma, line wrapping). --- src/google/adk/tools/toolbox_toolset.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/google/adk/tools/toolbox_toolset.py b/src/google/adk/tools/toolbox_toolset.py index 5c07cf2bfd..6af24080bf 100644 --- a/src/google/adk/tools/toolbox_toolset.py +++ b/src/google/adk/tools/toolbox_toolset.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + from typing import Any from typing import Callable from typing import List @@ -58,17 +60,19 @@ def __init__( **kwargs, ): """Args: - server_url: The URL of the toolbox server. - toolset_name: The name of the toolbox toolset to load. - tool_names: The names of the tools to load. - auth_token_getters: (Deprecated) Map of auth token getters. - bound_params: Parameters to bind to the tools. - credentials: (Optional) toolbox_adk.CredentialConfig object. - additional_headers: (Optional) Static headers dictionary. - **kwargs: Additional arguments passed to the underlying toolbox_adk.ToolboxToolset. + server_url: The URL of the toolbox server. + toolset_name: The name of the toolbox toolset to load. + tool_names: The names of the tools to load. + auth_token_getters: (Deprecated) Map of auth token getters. + bound_params: Parameters to bind to the tools. + credentials: (Optional) toolbox_adk.CredentialConfig object. + additional_headers: (Optional) Static headers dictionary. + **kwargs: Additional arguments passed to the underlying toolbox_adk.ToolboxToolset. """ if not toolset_name and not tool_names: - raise ValueError("Either 'toolset_name' or 'tool_names' must be provided.") + raise ValueError( + "Either 'toolset_name' or 'tool_names' must be provided." + ) try: from toolbox_adk import ToolboxToolset as RealToolboxToolset # pylint: disable=import-outside-toplevel @@ -88,7 +92,7 @@ def __init__( additional_headers=additional_headers, bound_params=bound_params, auth_token_getters=auth_token_getters, - **kwargs + **kwargs, ) @override From 8619dcaa2935d48dc5288ddbfde0e4dbe1b504c2 Mon Sep 17 00:00:00 2001 From: Anubhav Dhawan Date: Thu, 18 Dec 2025 23:05:29 +0530 Subject: [PATCH 4/4] refactor(tools): improve type hinting for credentials Uses TYPE_CHECKING import to reference toolset_adk.CredentialConfig for the credentials parameter, improving static analysis without adding runtime dependencies. --- src/google/adk/tools/toolbox_toolset.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/google/adk/tools/toolbox_toolset.py b/src/google/adk/tools/toolbox_toolset.py index 6af24080bf..78eadd7f66 100644 --- a/src/google/adk/tools/toolbox_toolset.py +++ b/src/google/adk/tools/toolbox_toolset.py @@ -19,6 +19,7 @@ from typing import List from typing import Mapping from typing import Optional +from typing import TYPE_CHECKING from typing import Union from typing_extensions import override @@ -27,6 +28,9 @@ from .base_tool import BaseTool from .base_toolset import BaseToolset +if TYPE_CHECKING: + from toolbox_adk import CredentialConfig + class ToolboxToolset(BaseToolset): """A class that provides access to toolbox toolsets. @@ -55,7 +59,7 @@ def __init__( bound_params: Optional[ Mapping[str, Union[Callable[[], Any], Any]] ] = None, - credentials: Optional[Any] = None, + credentials: Optional[CredentialConfig] = None, additional_headers: Optional[Mapping[str, str]] = None, **kwargs, ):