@@ -323,15 +323,13 @@ def _handle_multiple_structured_outputs(
323
323
response : AIMessage ,
324
324
structured_tool_calls : Any ,
325
325
) -> Command :
326
- """Handle error case when multiple structured output tools are called."""
327
- assert isinstance (self .response_format , ToolOutput )
326
+ """Handle multiple structured output tool calls."""
328
327
tool_names = [tool_call ["name" ] for tool_call in structured_tool_calls ]
329
328
exception = MultipleStructuredOutputsError (tool_names )
330
329
331
- retry_on = self .response_format .retry_on
332
- error_message = self ._get_retry_message (exception , retry_on )
330
+ should_retry , error_message = self ._handle_structured_output_error (exception )
333
331
334
- if error_message is None :
332
+ if not should_retry :
335
333
raise exception
336
334
337
335
tool_messages = [
@@ -353,8 +351,7 @@ def _handle_single_structured_output(
353
351
response : AIMessage ,
354
352
tool_call : Any ,
355
353
) -> Command :
356
- """Handle parsing and returning a single structured output tool call."""
357
- assert isinstance (self .response_format , ToolOutput )
354
+ """Handle a single structured output tool call."""
358
355
structured_tool_binding = self .structured_output_tools [tool_call ["name" ]]
359
356
360
357
try :
@@ -390,10 +387,11 @@ def _handle_single_structured_output(
390
387
except Exception as parse_error :
391
388
exception = StructuredOutputParsingError (tool_call ["name" ], parse_error )
392
389
393
- retry_on = self .response_format .retry_on
394
- error_message = self ._get_retry_message (exception , retry_on )
390
+ should_retry , error_message = self ._handle_structured_output_error (
391
+ exception
392
+ )
395
393
396
- if error_message is None :
394
+ if not should_retry :
397
395
raise exception
398
396
399
397
return Command (
@@ -410,30 +408,38 @@ def _handle_single_structured_output(
410
408
goto = "model" ,
411
409
)
412
410
413
- def _get_retry_message (
411
+ def _handle_structured_output_error (
414
412
self ,
415
413
exception : Exception ,
416
- retry_on : Union [
417
- bool , str , Callable [[Exception ], str ], tuple [type [Exception ], ...]
418
- ],
419
- ) -> Optional [str ]:
420
- """Get retry message based on retry_on configuration.
414
+ ) -> tuple [bool , str ]:
415
+ """Handle structured output error based on retry_on configuration.
421
416
422
- Returns None if retry should not happen .
417
+ Returns (should_retry, retry_tool_message) .
423
418
"""
419
+ assert isinstance (self .response_format , ToolOutput )
420
+ retry_on = self .response_format .retry_on
421
+
424
422
if retry_on is False :
425
- return None
426
- if retry_on is True :
427
- return STRUCTURED_OUTPUT_ERROR_TEMPLATE .format (error = repr (exception ))
428
- if isinstance (retry_on , str ):
429
- return retry_on
430
- if isinstance (retry_on , tuple ):
423
+ return False , ""
424
+ elif retry_on is True :
425
+ return True , STRUCTURED_OUTPUT_ERROR_TEMPLATE .format (error = str (exception ))
426
+ elif isinstance (retry_on , str ):
427
+ return True , retry_on
428
+ elif isinstance (retry_on , type ) and issubclass (retry_on , Exception ):
429
+ if isinstance (exception , retry_on ):
430
+ return True , STRUCTURED_OUTPUT_ERROR_TEMPLATE .format (
431
+ error = str (exception )
432
+ )
433
+ return False , ""
434
+ elif isinstance (retry_on , tuple ):
431
435
if any (isinstance (exception , exc_type ) for exc_type in retry_on ):
432
- return STRUCTURED_OUTPUT_ERROR_TEMPLATE .format (error = repr (exception ))
433
- return None
434
- if callable (retry_on ):
435
- return retry_on (exception )
436
- return None
436
+ return True , STRUCTURED_OUTPUT_ERROR_TEMPLATE .format (
437
+ error = str (exception )
438
+ )
439
+ return False , ""
440
+ elif callable (retry_on ):
441
+ return True , retry_on (exception ) # type: ignore[call-arg]
442
+ return False , ""
437
443
438
444
def _apply_native_output_binding (
439
445
self , model : LanguageModelLike
0 commit comments