@@ -232,24 +232,27 @@ def _process_actions(
232
232
233
233
# call tool with input
234
234
reasoning_step = cast (ActionReasoningStep , current_reasoning [- 1 ])
235
- tool = tools_dict [reasoning_step .action ]
236
- with self .callback_manager .event (
237
- CBEventType .FUNCTION_CALL ,
238
- payload = {
239
- EventPayload .FUNCTION_CALL : reasoning_step .action_input ,
240
- EventPayload .TOOL : tool .metadata ,
241
- },
242
- ) as event :
243
- try :
244
- tool_output = tool .call (** reasoning_step .action_input )
245
- except Exception as e :
246
- tool_output = ToolOutput (
247
- content = f"Error: { e !s} " ,
248
- tool_name = tool .metadata .name ,
249
- raw_input = {"kwargs" : reasoning_step .action_input },
250
- raw_output = e ,
251
- )
252
- event .on_end (payload = {EventPayload .FUNCTION_OUTPUT : str (tool_output )})
235
+ if reasoning_step .action in tools_dict :
236
+ tool = tools_dict [reasoning_step .action ]
237
+ with self .callback_manager .event (
238
+ CBEventType .FUNCTION_CALL ,
239
+ payload = {
240
+ EventPayload .FUNCTION_CALL : reasoning_step .action_input ,
241
+ EventPayload .TOOL : tool .metadata ,
242
+ },
243
+ ) as event :
244
+ try :
245
+ tool_output = tool .call (** reasoning_step .action_input )
246
+ except Exception as e :
247
+ tool_output = ToolOutput (
248
+ content = f"Error: { e !s} " ,
249
+ tool_name = tool .metadata .name ,
250
+ raw_input = {"kwargs" : reasoning_step .action_input },
251
+ raw_output = e ,
252
+ )
253
+ event .on_end (payload = {EventPayload .FUNCTION_OUTPUT : str (tool_output )})
254
+ else :
255
+ tool_output = self ._handle_nonexistent_tool_name (reasoning_step )
253
256
254
257
task .extra_state ["sources" ].append (tool_output )
255
258
@@ -276,24 +279,27 @@ async def _aprocess_actions(
276
279
277
280
# call tool with input
278
281
reasoning_step = cast (ActionReasoningStep , current_reasoning [- 1 ])
279
- tool = tools_dict [reasoning_step .action ]
280
- with self .callback_manager .event (
281
- CBEventType .FUNCTION_CALL ,
282
- payload = {
283
- EventPayload .FUNCTION_CALL : reasoning_step .action_input ,
284
- EventPayload .TOOL : tool .metadata ,
285
- },
286
- ) as event :
287
- try :
288
- tool_output = await tool .acall (** reasoning_step .action_input )
289
- except Exception as e :
290
- tool_output = ToolOutput (
291
- content = f"Error: { e !s} " ,
292
- tool_name = tool .metadata .name ,
293
- raw_input = {"kwargs" : reasoning_step .action_input },
294
- raw_output = e ,
295
- )
296
- event .on_end (payload = {EventPayload .FUNCTION_OUTPUT : str (tool_output )})
282
+ if reasoning_step .action in tools_dict :
283
+ tool = tools_dict [reasoning_step .action ]
284
+ with self .callback_manager .event (
285
+ CBEventType .FUNCTION_CALL ,
286
+ payload = {
287
+ EventPayload .FUNCTION_CALL : reasoning_step .action_input ,
288
+ EventPayload .TOOL : tool .metadata ,
289
+ },
290
+ ) as event :
291
+ try :
292
+ tool_output = await tool .acall (** reasoning_step .action_input )
293
+ except Exception as e :
294
+ tool_output = ToolOutput (
295
+ content = f"Error: { e !s} " ,
296
+ tool_name = tool .metadata .name ,
297
+ raw_input = {"kwargs" : reasoning_step .action_input },
298
+ raw_output = e ,
299
+ )
300
+ event .on_end (payload = {EventPayload .FUNCTION_OUTPUT : str (tool_output )})
301
+ else :
302
+ tool_output = self ._handle_nonexistent_tool_name (reasoning_step )
297
303
298
304
task .extra_state ["sources" ].append (tool_output )
299
305
@@ -303,6 +309,26 @@ async def _aprocess_actions(
303
309
print_text (f"{ observation_step .get_content ()} \n " , color = "blue" )
304
310
return current_reasoning , False
305
311
312
+ def _handle_nonexistent_tool_name (self , reasoning_step ):
313
+ # We still emit a `tool_output` object to the task, so that the LLM can know
314
+ # it has hallucinated in the next reasoning step.
315
+ with self .callback_manager .event (
316
+ CBEventType .FUNCTION_CALL ,
317
+ payload = {
318
+ EventPayload .FUNCTION_CALL : reasoning_step .action_input ,
319
+ },
320
+ ) as event :
321
+ # TODO(L10N): This should be localized.
322
+ content = f"Error: No such tool named `{ reasoning_step .action } `."
323
+ tool_output = ToolOutput (
324
+ content = content ,
325
+ tool_name = reasoning_step .action ,
326
+ raw_input = {"kwargs" : reasoning_step .action_input },
327
+ raw_output = content ,
328
+ )
329
+ event .on_end (payload = {EventPayload .FUNCTION_OUTPUT : str (tool_output )})
330
+ return tool_output
331
+
306
332
def _get_response (
307
333
self ,
308
334
current_reasoning : List [BaseReasoningStep ],
0 commit comments