Skip to content

Commit d48d02f

Browse files
committed
chore(prebuilt): rename _get_retry_message to _handle_structured_output_error & update return type to tuple, edit docstrings
1 parent 904dac0 commit d48d02f

File tree

2 files changed

+48
-31
lines changed

2 files changed

+48
-31
lines changed

libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -323,15 +323,13 @@ def _handle_multiple_structured_outputs(
323323
response: AIMessage,
324324
structured_tool_calls: Any,
325325
) -> 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."""
328327
tool_names = [tool_call["name"] for tool_call in structured_tool_calls]
329328
exception = MultipleStructuredOutputsError(tool_names)
330329

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)
333331

334-
if error_message is None:
332+
if not should_retry:
335333
raise exception
336334

337335
tool_messages = [
@@ -353,8 +351,7 @@ def _handle_single_structured_output(
353351
response: AIMessage,
354352
tool_call: Any,
355353
) -> 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."""
358355
structured_tool_binding = self.structured_output_tools[tool_call["name"]]
359356

360357
try:
@@ -390,10 +387,11 @@ def _handle_single_structured_output(
390387
except Exception as parse_error:
391388
exception = StructuredOutputParsingError(tool_call["name"], parse_error)
392389

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+
)
395393

396-
if error_message is None:
394+
if not should_retry:
397395
raise exception
398396

399397
return Command(
@@ -410,30 +408,38 @@ def _handle_single_structured_output(
410408
goto="model",
411409
)
412410

413-
def _get_retry_message(
411+
def _handle_structured_output_error(
414412
self,
415413
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.
421416
422-
Returns None if retry should not happen.
417+
Returns (should_retry, retry_tool_message).
423418
"""
419+
assert isinstance(self.response_format, ToolOutput)
420+
retry_on = self.response_format.retry_on
421+
424422
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):
431435
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, ""
437443

438444
def _apply_native_output_binding(
439445
self, model: LanguageModelLike

libs/prebuilt/langgraph/prebuilt/responses.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,18 @@ class ToolOutput(Generic[SchemaT]):
175175
tool_message_content: str | None
176176
"""The content of the tool message to be returned when the model calls an artificial structured output tool."""
177177

178-
retry_on: Union[bool, str, Callable[[Exception], str], tuple[type[Exception], ...]]
179-
"""Error retry strategy. Default is True.
178+
retry_on: Union[
179+
bool,
180+
str,
181+
type[Exception],
182+
tuple[type[Exception], ...],
183+
Callable[[Exception], str],
184+
]
185+
"""Error retry strategy for structured output via ToolOutput. Default is True.
180186
181187
- True: Catch all errors with default error template
182188
- str: Catch all errors with this custom message
189+
- type[Exception]: Only catch this exception type with default message
183190
- tuple[type[Exception], ...]: Only catch these exception types with default message
184191
- Callable[[Exception], str]: Custom function that returns error message
185192
- False: No retry, let exceptions propagate
@@ -190,7 +197,11 @@ def __init__(
190197
schema: type[SchemaT],
191198
tool_message_content: str | None = None,
192199
retry_on: Union[
193-
bool, str, Callable[[Exception], str], tuple[type[Exception], ...]
200+
bool,
201+
str,
202+
type[Exception],
203+
tuple[type[Exception], ...],
204+
Callable[[Exception], str],
194205
] = True,
195206
) -> None:
196207
"""Initialize ToolOutput with schemas, tool message content, and retry strategy."""

0 commit comments

Comments
 (0)