1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15- from typing import Any , Dict , Optional , Callable , Awaitable
16- from typing_extensions import override
15+ from typing import Any , Awaitable , Callable , Dict , Optional
1716
1817import toolbox_core
19- from toolbox_core .tool import ToolboxTool as CoreToolboxTool
20- from google .adk .tools .base_tool import BaseTool
18+ from fastapi .openapi .models import (
19+ OAuth2 ,
20+ OAuthFlowAuthorizationCode ,
21+ OAuthFlows ,
22+ SecurityScheme ,
23+ )
2124from google .adk .agents .readonly_context import ReadonlyContext
22-
25+ from google .adk .auth .auth_credential import (
26+ AuthCredential ,
27+ AuthCredentialTypes ,
28+ OAuth2Auth ,
29+ )
2330from google .adk .auth .auth_tool import AuthConfig
24- from google .adk .auth .auth_credential import AuthCredential , AuthCredentialTypes , OAuth2Auth
25- from fastapi .openapi .models import SecurityScheme , OAuthFlows , OAuthFlowAuthorizationCode , OAuth2
31+ from google .adk .tools .base_tool import BaseTool
32+ from toolbox_core .tool import ToolboxTool as CoreToolboxTool
33+ from typing_extensions import override
2634
27- from .credentials import CredentialConfig , CredentialType
2835from .client import USER_TOKEN_CONTEXT_VAR
29-
36+ from . credentials import CredentialConfig , CredentialType
3037
3138
3239class ToolboxContext :
3340 """Context object passed to pre/post hooks."""
41+
3442 def __init__ (self , arguments : Dict [str , Any ], tool_context : ReadonlyContext ):
3543 self .arguments = arguments
3644 self .tool_context = tool_context
@@ -59,15 +67,18 @@ def __init__(
5967 """
6068 # We act as a proxy.
6169 # We need to extract metadata from the core tool to satisfy BaseTool's contract.
62-
70+
6371 name = getattr (core_tool , "__name__" , "unknown_tool" )
64- description = getattr (core_tool , "__doc__" , "No description provided." ) or "No description provided."
65-
72+ description = (
73+ getattr (core_tool , "__doc__" , "No description provided." )
74+ or "No description provided."
75+ )
76+
6677 super ().__init__ (
6778 name = name ,
6879 description = description ,
6980 # We pass empty custom_metadata or whatever is needed
70- custom_metadata = {}
81+ custom_metadata = {},
7182 )
7283 self ._core_tool = core_tool
7384 self ._pre_hook = pre_hook
@@ -82,30 +93,32 @@ async def run_async(
8293 ) -> Any :
8394 # Create context
8495 ctx = ToolboxContext (arguments = args , tool_context = tool_context )
85-
96+
8697 # 1. Pre-hook
8798 if self ._pre_hook :
8899 await self ._pre_hook (ctx )
89-
100+
90101 # 2. ADK Auth Integration (3LO)
91102 # Check if USER_IDENTITY is configured
92103 reset_token = None
93-
104+
94105 if self ._auth_config and self ._auth_config .type == CredentialType .USER_IDENTITY :
95106 if not self ._auth_config .client_id or not self ._auth_config .client_secret :
96107 raise ValueError ("USER_IDENTITY requires client_id and client_secret" )
97-
108+
98109 # Construct ADK AuthConfig
99- scopes = self ._auth_config .scopes or ["https://www.googleapis.com/auth/cloud-platform" ]
110+ scopes = self ._auth_config .scopes or [
111+ "https://www.googleapis.com/auth/cloud-platform"
112+ ]
100113 scope_dict = {s : "" for s in scopes }
101-
114+
102115 auth_config_adk = AuthConfig (
103116 auth_scheme = OAuth2 (
104117 flows = OAuthFlows (
105118 authorizationCode = OAuthFlowAuthorizationCode (
106119 authorizationUrl = "https://accounts.google.com/o/oauth2/auth" ,
107120 tokenUrl = "https://oauth2.googleapis.com/token" ,
108- scopes = scope_dict
121+ scopes = scope_dict ,
109122 )
110123 )
111124 ),
@@ -114,9 +127,9 @@ async def run_async(
114127 oauth2 = OAuth2Auth (
115128 client_id = self ._auth_config .client_id ,
116129 client_secret = self ._auth_config .client_secret ,
117- scopes = scopes
118- )
119- )
130+ scopes = scopes ,
131+ ),
132+ ),
120133 )
121134
122135 # Check if we already have credentials from a previous exchange
@@ -140,19 +153,21 @@ async def run_async(
140153 # Actually, strictly we should probably request credential if get_auth_response returns nothing
141154 # but get_auth_response typically handles the lookup.
142155 # If exception is unrelated, raise.
143- if "credential" in str (e ).lower () or isinstance (e , ValueError ): # Loose check, but safest is to re-raise
144- raise e
156+ if "credential" in str (e ).lower () or isinstance (
157+ e , ValueError
158+ ): # Loose check, but safest is to re-raise
159+ raise e
145160 # Fallback to request logic if it was a lookup error?
146161 tool_context .request_credential (auth_config_adk )
147162 return None
148163
149164 try :
150165 # Execute the core tool
151166 result = await self ._core_tool (** ctx .arguments )
152-
167+
153168 ctx .result = result
154169 return result
155-
170+
156171 except Exception as e :
157172 ctx .error = e
158173 raise e
@@ -162,13 +177,13 @@ async def run_async(
162177 if self ._post_hook :
163178 await self ._post_hook (ctx )
164179
165- def bind_params (self , bounded_params : Dict [str , Any ]) -> ' ToolboxTool' :
180+ def bind_params (self , bounded_params : Dict [str , Any ]) -> " ToolboxTool" :
166181 """Allows runtime binding of parameters, delegating to core tool."""
167182 new_core_tool = self ._core_tool .bind_params (bounded_params )
168183 # Return a new wrapper
169184 return ToolboxTool (
170- core_tool = new_core_tool ,
171- pre_hook = self ._pre_hook ,
185+ core_tool = new_core_tool ,
186+ pre_hook = self ._pre_hook ,
172187 post_hook = self ._post_hook ,
173- auth_config = self ._auth_config
188+ auth_config = self ._auth_config ,
174189 )
0 commit comments