mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-05-02 07:42:40 +00:00
fix: re-raise OutputParserError in format_answer for retry logic
This commit is contained in:
@@ -157,7 +157,7 @@ def handle_max_iterations_exceeded(
|
|||||||
|
|
||||||
# Perform one more LLM call to get the final answer
|
# Perform one more LLM call to get the final answer
|
||||||
answer = llm.call(
|
answer = llm.call(
|
||||||
messages, # type: ignore[arg-type]
|
messages,
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -197,9 +197,14 @@ def format_answer(answer: str) -> AgentAction | AgentFinish:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Either an AgentAction or AgentFinish
|
Either an AgentAction or AgentFinish
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
OutputParserError: When the LLM response format is invalid, allowing retry logic
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return parse(answer)
|
return parse(answer)
|
||||||
|
except OutputParserError:
|
||||||
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
return AgentFinish(
|
return AgentFinish(
|
||||||
thought="Failed to parse LLM response",
|
thought="Failed to parse LLM response",
|
||||||
@@ -249,10 +254,10 @@ def get_llm_response(
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
answer = llm.call(
|
answer = llm.call(
|
||||||
messages, # type: ignore[arg-type]
|
messages,
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
from_task=from_task,
|
from_task=from_task,
|
||||||
from_agent=from_agent,
|
from_agent=from_agent, # type: ignore[arg-type]
|
||||||
response_model=response_model,
|
response_model=response_model,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -294,8 +299,8 @@ def handle_agent_action_core(
|
|||||||
formatted_answer: AgentAction,
|
formatted_answer: AgentAction,
|
||||||
tool_result: ToolResult,
|
tool_result: ToolResult,
|
||||||
messages: list[LLMMessage] | None = None,
|
messages: list[LLMMessage] | None = None,
|
||||||
step_callback: Callable | None = None,
|
step_callback: Callable[[Any], Any] | None = None,
|
||||||
show_logs: Callable | None = None,
|
show_logs: Callable[[Any], Any] | None = None,
|
||||||
) -> AgentAction | AgentFinish:
|
) -> AgentAction | AgentFinish:
|
||||||
"""Core logic for handling agent actions and tool results.
|
"""Core logic for handling agent actions and tool results.
|
||||||
|
|
||||||
@@ -481,7 +486,7 @@ def summarize_messages(
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
summary = llm.call(
|
summary = llm.call(
|
||||||
messages, # type: ignore[arg-type]
|
messages,
|
||||||
callbacks=callbacks,
|
callbacks=callbacks,
|
||||||
)
|
)
|
||||||
summarized_contents.append({"content": str(summary)})
|
summarized_contents.append({"content": str(summary)})
|
||||||
|
|||||||
69
lib/crewai/tests/utilities/test_agent_utils.py
Normal file
69
lib/crewai/tests/utilities/test_agent_utils.py
Normal 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)
|
||||||
Reference in New Issue
Block a user