diff --git a/src/crewai/agents/crew_agent_executor.py b/src/crewai/agents/crew_agent_executor.py index ed89008fd..1937d4bc2 100644 --- a/src/crewai/agents/crew_agent_executor.py +++ b/src/crewai/agents/crew_agent_executor.py @@ -372,6 +372,9 @@ class CrewAgentExecutor(CrewAgentExecutorMixin): name.casefold().strip() for name in self.tool_name_to_tool_map ]: tool_result = tool_usage.use(tool_calling, agent_action.text) + # Strip any trailing backticks from tool result + if isinstance(tool_result, str): + tool_result = tool_result.rstrip('`') tool = self.tool_name_to_tool_map.get(tool_calling.tool_name) if tool: return ToolResult( diff --git a/tests/crew_test.py b/tests/crew_test.py index 0539ea347..783cb999b 100644 --- a/tests/crew_test.py +++ b/tests/crew_test.py @@ -3,6 +3,7 @@ import hashlib import json from concurrent.futures import Future +from typing import Any from unittest import mock from unittest.mock import MagicMock, patch @@ -14,6 +15,7 @@ from crewai.agent import Agent from crewai.agents.cache import CacheHandler from crewai.crew import Crew from crewai.crews.crew_output import CrewOutput +from crewai.tools.base_tool import BaseTool from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource from crewai.memory.contextual.contextual_memory import ContextualMemory from crewai.process import Process @@ -315,6 +317,39 @@ def test_sync_task_execution(): assert mock_execute_sync.call_count == len(tasks) +@pytest.mark.vcr(filter_headers=["authorization"]) +def test_hierarchical_tool_output_formatting(): + """Test that tool outputs in hierarchical mode don't have extra backticks""" + class TestTool(BaseTool): + name: str = "test_tool" + description: str = "A test tool" + + def _run(self, *args: Any, **kwargs: Any) -> str: + return "test result```" # Intentionally add backticks to test stripping + + task = Task( + description="Test task using test_tool", + expected_output="Test output", + ) + + crew = Crew( + agents=[researcher], + process=Process.hierarchical, + manager_llm="gpt-4o", + tasks=[task], + tools=[TestTool()], + ) + + with patch.object(Task, 'execute_sync', return_value=TaskOutput( + description="Test task", + raw="test result", + agent="researcher" + )) as mock_execute_sync: + result = crew.kickoff() + assert mock_execute_sync.called + assert not result.raw.endswith('```') + assert '```\n```' not in result.raw + @pytest.mark.vcr(filter_headers=["authorization"]) def test_hierarchical_process(): task = Task(