fix: re-raise OutputParserError in format_answer for retry logic

This commit is contained in:
Greyson LaLonde
2025-11-04 14:37:29 -05:00
parent 5abf976373
commit 76f9d505ad
2 changed files with 80 additions and 6 deletions

View File

@@ -157,7 +157,7 @@ def handle_max_iterations_exceeded(
# Perform one more LLM call to get the final answer
answer = llm.call(
messages, # type: ignore[arg-type]
messages,
callbacks=callbacks,
)
@@ -197,9 +197,14 @@ def format_answer(answer: str) -> AgentAction | AgentFinish:
Returns:
Either an AgentAction or AgentFinish
Raises:
OutputParserError: When the LLM response format is invalid, allowing retry logic
"""
try:
return parse(answer)
except OutputParserError:
raise
except Exception:
return AgentFinish(
thought="Failed to parse LLM response",
@@ -249,10 +254,10 @@ def get_llm_response(
"""
try:
answer = llm.call(
messages, # type: ignore[arg-type]
messages,
callbacks=callbacks,
from_task=from_task,
from_agent=from_agent,
from_agent=from_agent, # type: ignore[arg-type]
response_model=response_model,
)
except Exception as e:
@@ -294,8 +299,8 @@ def handle_agent_action_core(
formatted_answer: AgentAction,
tool_result: ToolResult,
messages: list[LLMMessage] | None = None,
step_callback: Callable | None = None,
show_logs: Callable | None = None,
step_callback: Callable[[Any], Any] | None = None,
show_logs: Callable[[Any], Any] | None = None,
) -> AgentAction | AgentFinish:
"""Core logic for handling agent actions and tool results.
@@ -481,7 +486,7 @@ def summarize_messages(
),
]
summary = llm.call(
messages, # type: ignore[arg-type]
messages,
callbacks=callbacks,
)
summarized_contents.append({"content": str(summary)})

View File

@@ -0,0 +1,69 @@
"""Tests for agent_utils module."""
import pytest
from crewai.agents.parser import AgentFinish, OutputParserError
from crewai.utilities.agent_utils import format_answer
class TestFormatAnswer:
"""Tests for the format_answer function."""
def test_format_answer_with_valid_final_answer(self) -> None:
"""Test that format_answer correctly parses a valid final answer."""
answer = """Thought: I have completed the task.
Final Answer: The result is 42."""
result = format_answer(answer)
assert isinstance(result, AgentFinish)
assert result.output == "The result is 42."
def test_format_answer_reraises_output_parser_error(self) -> None:
"""Test that format_answer re-raises OutputParserError for retry logic."""
# Malformed output missing colons after "Thought", "Action", and "Action Input"
malformed_answer = """Thought
The user wants to verify something.
Action
Video Analysis Tool
Action Input:
{"query": "Is there something?"}"""
with pytest.raises(OutputParserError) as exc_info:
format_answer(malformed_answer)
# Verify that the error message contains helpful information
assert exc_info.value.error is not None
def test_format_answer_with_missing_action_colon(self) -> None:
"""Test that format_answer raises OutputParserError when Action colon is missing."""
malformed_answer = """Thought: I need to search for information.
Action
Search Tool
Action Input: {"query": "test"}"""
with pytest.raises(OutputParserError):
format_answer(malformed_answer)
def test_format_answer_with_missing_action_input_colon(self) -> None:
"""Test that format_answer raises OutputParserError when Action Input colon is missing."""
malformed_answer = """Thought: I need to search for information.
Action: Search Tool
Action Input
{"query": "test"}"""
with pytest.raises(OutputParserError):
format_answer(malformed_answer)
def test_format_answer_with_valid_action(self) -> None:
"""Test that format_answer correctly parses a valid action format."""
valid_action = """Thought: I need to search for information.
Action: Search Tool
Action Input: {"query": "test"}"""
# This should parse successfully without raising an exception
result = format_answer(valid_action)
# The result should be an AgentAction (not AgentFinish)
assert result is not None
assert not isinstance(result, AgentFinish)