@@ -157,6 +157,9 @@ async def load_tool(
157
157
for execution. The specific arguments and behavior of the callable
158
158
depend on the tool itself.
159
159
160
+ Raises:
161
+ ValueError: If the loaded tool instance fails to utilize at least
162
+ one provided parameter or auth token (if any provided).
160
163
"""
161
164
# Resolve client headers
162
165
resolved_headers = {
@@ -174,55 +177,133 @@ async def load_tool(
174
177
if name not in manifest .tools :
175
178
# TODO: Better exception
176
179
raise Exception (f"Tool '{ name } ' not found!" )
177
- tool , _ , _ = self .__parse_tool (
180
+ tool , used_auth_keys , used_bound_keys = self .__parse_tool (
178
181
name ,
179
182
manifest .tools [name ],
180
183
auth_token_getters ,
181
184
bound_params ,
182
185
self .__client_headers ,
183
186
)
184
187
188
+ provided_auth_keys = set (auth_token_getters .keys ())
189
+ provided_bound_keys = set (bound_params .keys ())
190
+
191
+ unused_auth = provided_auth_keys - used_auth_keys
192
+ unused_bound = provided_bound_keys - used_bound_keys
193
+
194
+ if unused_auth or unused_bound :
195
+ error_messages = []
196
+ if unused_auth :
197
+ error_messages .append (
198
+ f"unused auth tokens: { ', ' .join (unused_auth )} "
199
+ )
200
+ if unused_bound :
201
+ error_messages .append (
202
+ f"unused bound parameters: { ', ' .join (unused_bound )} "
203
+ )
204
+ raise ValueError (
205
+ f"Validation failed for tool '{ name } ': { '; ' .join (error_messages ) } ."
206
+ )
207
+
185
208
return tool
186
209
187
210
async def load_toolset (
188
211
self ,
189
212
name : Optional [str ] = None ,
190
213
auth_token_getters : dict [str , Callable [[], str ]] = {},
191
214
bound_params : Mapping [str , Union [Callable [[], Any ], Any ]] = {},
215
+ strict : bool = False ,
192
216
) -> list [ToolboxTool ]:
193
217
"""
194
218
Asynchronously fetches a toolset and loads all tools defined within it.
195
219
196
220
Args:
197
- name: Name of the toolset to load tools .
221
+ name: Name of the toolset to load. If None, loads the default toolset .
198
222
auth_token_getters: A mapping of authentication service names to
199
223
callables that return the corresponding authentication token.
200
224
bound_params: A mapping of parameter names to bind to specific values or
201
225
callables that are called to produce values as needed.
226
+ strict: If True, raises an error if *any* loaded tool instance fails
227
+ to utilize at least one provided parameter or auth token (if any
228
+ provided). If False (default), raises an error only if a
229
+ user-provided parameter or auth token cannot be applied to *any*
230
+ loaded tool across the set.
202
231
203
232
Returns:
204
233
list[ToolboxTool]: A list of callables, one for each tool defined
205
234
in the toolset.
235
+
236
+ Raises:
237
+ ValueError: If validation fails based on the `strict` flag.
206
238
"""
239
+
207
240
# Resolve client headers
208
241
original_headers = self .__client_headers
209
242
resolved_headers = {
210
243
header_name : await resolve_value (original_headers [header_name ])
211
244
for header_name in original_headers
212
245
}
213
- # Request the definition of the tool from the server
246
+ # Request the definition of the toolset from the server
214
247
url = f"{ self .__base_url } /api/toolset/{ name or '' } "
215
248
async with self .__session .get (url , headers = resolved_headers ) as response :
216
249
json = await response .json ()
217
250
manifest : ManifestSchema = ManifestSchema (** json )
218
251
219
- # parse each tools name and schema into a list of ToolboxTools
220
- tools = [
221
- self .__parse_tool (
222
- n , s , auth_token_getters , bound_params , self .__client_headers
223
- )[0 ]
224
- for n , s in manifest .tools .items ()
225
- ]
252
+ tools : list [ToolboxTool ] = []
253
+ overall_used_auth_keys : set [str ] = set ()
254
+ overall_used_bound_params : set [str ] = set ()
255
+ provided_auth_keys = set (auth_token_getters .keys ())
256
+ provided_bound_keys = set (bound_params .keys ())
257
+
258
+ # parse each tool's name and schema into a list of ToolboxTools
259
+ for tool_name , schema in manifest .tools .items ():
260
+ tool , used_auth_keys , used_bound_keys = self .__parse_tool (
261
+ tool_name ,
262
+ schema ,
263
+ auth_token_getters ,
264
+ bound_params ,
265
+ self .__client_headers ,
266
+ )
267
+ tools .append (tool )
268
+
269
+ if strict :
270
+ unused_auth = provided_auth_keys - used_auth_keys
271
+ unused_bound = provided_bound_keys - used_bound_keys
272
+ if unused_auth or unused_bound :
273
+ error_messages = []
274
+ if unused_auth :
275
+ error_messages .append (
276
+ f"unused auth tokens: { ', ' .join (unused_auth )} "
277
+ )
278
+ if unused_bound :
279
+ error_messages .append (
280
+ f"unused bound parameters: { ', ' .join (unused_bound )} "
281
+ )
282
+ raise ValueError (
283
+ f"Validation failed for tool '{ name } ': { '; ' .join (error_messages ) } ."
284
+ )
285
+ else :
286
+ overall_used_auth_keys .update (used_auth_keys )
287
+ overall_used_bound_params .update (used_bound_keys )
288
+
289
+ if not strict :
290
+ unused_auth = provided_auth_keys - overall_used_auth_keys
291
+ unused_bound = provided_bound_keys - overall_used_bound_params
292
+
293
+ if unused_auth or unused_bound :
294
+ error_messages = []
295
+ if unused_auth :
296
+ error_messages .append (
297
+ f"unused auth tokens could not be applied to any tool: { ', ' .join (unused_auth )} "
298
+ )
299
+ if unused_bound :
300
+ error_messages .append (
301
+ f"unused bound parameters could not be applied to any tool: { ', ' .join (unused_bound )} "
302
+ )
303
+ raise ValueError (
304
+ f"Validation failed for toolset '{ name or 'default' } ': { '; ' .join (error_messages ) } ."
305
+ )
306
+
226
307
return tools
227
308
228
309
async def add_headers (
0 commit comments