mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-27 09:08:14 +00:00
refactor: Improve backtick stripping and test coverage
- Extract backtick stripping to _clean_tool_result method - Add docstrings explaining the backtick cleaning logic - Add parameterized tests for various backtick scenarios Co-Authored-By: Joe Moura <joao@crewai.com>
This commit is contained in:
@@ -372,14 +372,29 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
name.casefold().strip() for name in self.tool_name_to_tool_map
|
name.casefold().strip() for name in self.tool_name_to_tool_map
|
||||||
]:
|
]:
|
||||||
tool_result = tool_usage.use(tool_calling, agent_action.text)
|
tool_result = tool_usage.use(tool_calling, agent_action.text)
|
||||||
# Strip any trailing backticks from tool result
|
tool_result = self._clean_tool_result(tool_result)
|
||||||
if isinstance(tool_result, str):
|
|
||||||
tool_result = tool_result.rstrip('`')
|
|
||||||
tool = self.tool_name_to_tool_map.get(tool_calling.tool_name)
|
tool = self.tool_name_to_tool_map.get(tool_calling.tool_name)
|
||||||
if tool:
|
if tool:
|
||||||
return ToolResult(
|
return ToolResult(
|
||||||
result=tool_result, result_as_answer=tool.result_as_answer
|
result=tool_result, result_as_answer=tool.result_as_answer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _clean_tool_result(self, tool_result: Any) -> Any:
|
||||||
|
"""Clean tool result by removing trailing backticks.
|
||||||
|
|
||||||
|
This is particularly important in hierarchical mode where tool outputs
|
||||||
|
might contain markdown formatting that needs to be cleaned up.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tool_result: The result from a tool execution, can be any type
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The cleaned result with any trailing backticks removed if it's a string,
|
||||||
|
otherwise returns the original result unchanged
|
||||||
|
"""
|
||||||
|
if isinstance(tool_result, str):
|
||||||
|
return tool_result.rstrip('`').rstrip('```')
|
||||||
|
return tool_result
|
||||||
else:
|
else:
|
||||||
tool_result = self._i18n.errors("wrong_tool_name").format(
|
tool_result = self._i18n.errors("wrong_tool_name").format(
|
||||||
tool=tool_calling.tool_name,
|
tool=tool_calling.tool_name,
|
||||||
|
|||||||
@@ -317,14 +317,26 @@ def test_sync_task_execution():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_hierarchical_tool_output_formatting():
|
@pytest.mark.parametrize("tool_output,expected", [
|
||||||
"""Test that tool outputs in hierarchical mode don't have extra backticks"""
|
("test result```", "test result"),
|
||||||
|
("test result`", "test result"),
|
||||||
|
("test result``````", "test result"),
|
||||||
|
("test result", "test result"),
|
||||||
|
("test ```result```", "test ```result"), # Only strip trailing backticks
|
||||||
|
])
|
||||||
|
def test_hierarchical_tool_output_formatting(tool_output, expected):
|
||||||
|
"""Test that tool outputs in hierarchical mode don't have extra backticks.
|
||||||
|
|
||||||
|
This test verifies that the tool output cleaning functionality correctly handles
|
||||||
|
various scenarios of backtick formatting, ensuring only trailing backticks are
|
||||||
|
removed while preserving any inline markdown formatting.
|
||||||
|
"""
|
||||||
class TestTool(BaseTool):
|
class TestTool(BaseTool):
|
||||||
name: str = "test_tool"
|
name: str = "test_tool"
|
||||||
description: str = "A test tool"
|
description: str = "A test tool"
|
||||||
|
|
||||||
def _run(self, *args: Any, **kwargs: Any) -> str:
|
def _run(self, *args: Any, **kwargs: Any) -> str:
|
||||||
return "test result```" # Intentionally add backticks to test stripping
|
return tool_output
|
||||||
|
|
||||||
task = Task(
|
task = Task(
|
||||||
description="Test task using test_tool",
|
description="Test task using test_tool",
|
||||||
@@ -341,13 +353,12 @@ def test_hierarchical_tool_output_formatting():
|
|||||||
|
|
||||||
with patch.object(Task, 'execute_sync', return_value=TaskOutput(
|
with patch.object(Task, 'execute_sync', return_value=TaskOutput(
|
||||||
description="Test task",
|
description="Test task",
|
||||||
raw="test result",
|
raw=expected,
|
||||||
agent="researcher"
|
agent="researcher"
|
||||||
)) as mock_execute_sync:
|
)) as mock_execute_sync:
|
||||||
result = crew.kickoff()
|
result = crew.kickoff()
|
||||||
assert mock_execute_sync.called
|
assert mock_execute_sync.called
|
||||||
assert not result.raw.endswith('```')
|
assert result.raw == expected
|
||||||
assert '```\n```' not in result.raw
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_hierarchical_process():
|
def test_hierarchical_process():
|
||||||
|
|||||||
Reference in New Issue
Block a user