From 172157e8d5fa32958086f76de6187c7a9272f994 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 10:34:19 +0000 Subject: [PATCH] feat: enhance manager coworker context - Add coworker goals and backstories to delegation tool descriptions - Update i18n templates to support multiline coworker descriptions - Add tests for similar role scenarios Fixes #2095 Co-Authored-By: Joe Moura --- src/crewai/tools/agent_tools/agent_tools.py | 15 +++- src/crewai/translations/en.json | 4 +- tests/crew_test.py | 80 ++++++++++++++++----- tests/tools/agent_tools/agent_tools_test.py | 33 +++++++++ 4 files changed, 108 insertions(+), 24 deletions(-) diff --git a/src/crewai/tools/agent_tools/agent_tools.py b/src/crewai/tools/agent_tools/agent_tools.py index 77d3c2d89..2d91ba08a 100644 --- a/src/crewai/tools/agent_tools/agent_tools.py +++ b/src/crewai/tools/agent_tools/agent_tools.py @@ -15,18 +15,27 @@ class AgentTools: def tools(self) -> list[BaseTool]: """Get all available agent tools""" - coworkers = ", ".join([f"{agent.role}" for agent in self.agents]) + coworkers = [] + for agent in self.agents: + coworker_desc = f"{agent.role} (Goal: {agent.goal})" + if agent.backstory: + # Truncate backstory to first sentence for brevity + first_sentence = agent.backstory.split('.')[0] + coworker_desc += f" - {first_sentence}" + coworkers.append(coworker_desc) + + coworkers_str = "\n- ".join(coworkers) delegate_tool = DelegateWorkTool( agents=self.agents, i18n=self.i18n, - description=self.i18n.tools("delegate_work").format(coworkers=coworkers), # type: ignore + description=self.i18n.tools("delegate_work").format(coworkers=coworkers_str), # type: ignore ) ask_tool = AskQuestionTool( agents=self.agents, i18n=self.i18n, - description=self.i18n.tools("ask_question").format(coworkers=coworkers), # type: ignore + description=self.i18n.tools("ask_question").format(coworkers=coworkers_str), # type: ignore ) return [delegate_tool, ask_tool] diff --git a/src/crewai/translations/en.json b/src/crewai/translations/en.json index f09f1dba0..4b8264312 100644 --- a/src/crewai/translations/en.json +++ b/src/crewai/translations/en.json @@ -40,8 +40,8 @@ "validation_error": "### Previous attempt failed validation: {guardrail_result_error}\n\n\n### Previous result:\n{task_output}\n\n\nTry again, making sure to address the validation error." }, "tools": { - "delegate_work": "Delegate a specific task to one of the following coworkers: {coworkers}\nThe input to this tool should be the coworker, the task you want them to do, and ALL necessary context to execute the task, they know nothing about the task, so share absolute everything you know, don't reference things but instead explain them.", - "ask_question": "Ask a specific question to one of the following coworkers: {coworkers}\nThe input to this tool should be the coworker, the question you have for them, and ALL necessary context to ask the question properly, they know nothing about the question, so share absolute everything you know, don't reference things but instead explain them.", + "delegate_work": "Delegate a specific task to one of the following coworkers:\n{coworkers}\nThe input to this tool should be the coworker, the task you want them to do, and ALL necessary context to execute the task, they know nothing about the task, so share absolute everything you know, don't reference things but instead explain them.", + "ask_question": "Ask a specific question to one of the following coworkers:\n{coworkers}\nThe input to this tool should be the coworker, the question you have for them, and ALL necessary context to ask the question properly, they know nothing about the question, so share absolute everything you know, don't reference things but instead explain them.", "add_image": { "name": "Add image to content", "description": "See image to understand its content, you can optionally ask a question about the image", diff --git a/tests/crew_test.py b/tests/crew_test.py index 0539ea347..8b65c2265 100644 --- a/tests/crew_test.py +++ b/tests/crew_test.py @@ -351,6 +351,38 @@ def test_manager_llm_requirement_for_hierarchical_process(): ) +@pytest.mark.vcr(filter_headers=["authorization"]) +def test_hierarchical_crew_with_similar_roles(): + """Test that manager can effectively delegate to agents with similar roles using enhanced context.""" + quick_researcher = Agent( + role="Quick Researcher", + goal="Find information quickly, prioritizing speed over depth", + backstory="Specialist in rapid information gathering and quick insights" + ) + deep_researcher = Agent( + role="Deep Researcher", + goal="Find detailed and thorough information through comprehensive analysis", + backstory="Expert in comprehensive research and in-depth investigation" + ) + + task = Task( + description="Research the impact of AI on healthcare. Quick researcher should focus on recent developments, while deep researcher should analyze long-term implications.", + expected_output="A comprehensive analysis combining quick insights and deep research." + ) + + crew = Crew( + agents=[quick_researcher, deep_researcher], + tasks=[task], + process=Process.hierarchical, + manager_llm="gpt-4" + ) + + result = crew.kickoff() + assert result # Verify crew execution completes + assert isinstance(result, CrewOutput) # Verify output type + assert len(result.tasks_output) == 1 # Verify task was completed + + @pytest.mark.vcr(filter_headers=["authorization"]) def test_manager_agent_delegating_to_assigned_task_agent(): """ @@ -392,12 +424,12 @@ def test_manager_agent_delegating_to_assigned_task_agent(): # Verify the delegation tools were passed correctly assert len(tools) == 2 assert any( - "Delegate a specific task to one of the following coworkers: Researcher" + "Researcher (Goal: Make the best research and analysis on content about AI and AI agents)" in tool.description for tool in tools ) assert any( - "Ask a specific question to one of the following coworkers: Researcher" + "Researcher (Goal: Make the best research and analysis on content about AI and AI agents)" in tool.description for tool in tools ) @@ -426,13 +458,15 @@ def test_manager_agent_delegating_to_all_agents(): assert crew.manager_agent.tools is not None assert len(crew.manager_agent.tools) == 2 - assert ( - "Delegate a specific task to one of the following coworkers: Researcher, Senior Writer\n" - in crew.manager_agent.tools[0].description + assert any( + "Researcher (Goal: Make the best research and analysis on content about AI and AI agents)" + in tool.description + for tool in crew.manager_agent.tools ) - assert ( - "Ask a specific question to one of the following coworkers: Researcher, Senior Writer\n" - in crew.manager_agent.tools[1].description + assert any( + "Senior Writer (Goal: Write the best content about AI and AI agents.)" + in tool.description + for tool in crew.manager_agent.tools ) @@ -1731,13 +1765,11 @@ def test_hierarchical_crew_creation_tasks_with_agents(): # Verify the delegation tools were passed correctly assert len(tools) == 2 assert any( - "Delegate a specific task to one of the following coworkers: Senior Writer" - in tool.description + "Senior Writer (Goal: Write the best content about AI and AI agents.)" in tool.description for tool in tools ) assert any( - "Ask a specific question to one of the following coworkers: Senior Writer" - in tool.description + "Senior Writer (Goal: Write the best content about AI and AI agents.)" in tool.description for tool in tools ) @@ -1788,13 +1820,15 @@ def test_hierarchical_crew_creation_tasks_with_async_execution(): # Verify the delegation tools were passed correctly assert len(tools) == 2 assert any( - "Delegate a specific task to one of the following coworkers: Senior Writer\n" - in tool.description + "Senior Writer (Goal: Write the best content about AI and AI agents.)" in tool.description for tool in tools ) assert any( - "Ask a specific question to one of the following coworkers: Senior Writer\n" - in tool.description + "Researcher (Goal: Make the best research and analysis on content about AI and AI agents)" in tool.description + for tool in tools + ) + assert any( + "CEO (Goal: Make sure the writers in your company produce amazing content.)" in tool.description for tool in tools ) @@ -1827,9 +1861,17 @@ def test_hierarchical_crew_creation_tasks_with_sync_last(): crew.kickoff() assert crew.manager_agent is not None assert crew.manager_agent.tools is not None - assert ( - "Delegate a specific task to one of the following coworkers: Senior Writer, Researcher, CEO\n" - in crew.manager_agent.tools[0].description + assert any( + "Senior Writer (Goal: Write the best content about AI and AI agents.)" in tool.description + for tool in crew.manager_agent.tools + ) + assert any( + "Researcher (Goal: Make the best research and analysis on content about AI and AI agents)" in tool.description + for tool in crew.manager_agent.tools + ) + assert any( + "CEO (Goal: Make sure the writers in your company produce amazing content.)" in tool.description + for tool in crew.manager_agent.tools ) diff --git a/tests/tools/agent_tools/agent_tools_test.py b/tests/tools/agent_tools/agent_tools_test.py index 9aea7b4bc..3a9933c7b 100644 --- a/tests/tools/agent_tools/agent_tools_test.py +++ b/tests/tools/agent_tools/agent_tools_test.py @@ -124,3 +124,36 @@ def test_ask_question_to_wrong_agent(): result == "\nError executing tool. coworker mentioned not found, it must be one of the following options:\n- researcher\n" ) + + +def test_delegate_work_with_similar_roles(): + """Test that delegation tools show rich context for similar roles.""" + researcher1 = Agent( + role="Quick Researcher", + goal="Find information quickly, prioritizing speed", + backstory="Specialist in rapid information gathering" + ) + researcher2 = Agent( + role="Deep Researcher", + goal="Find detailed and thorough information", + backstory="Expert in comprehensive research" + ) + tools = AgentTools(agents=[researcher1, researcher2]).tools() + delegate_tool = tools[0] + ask_tool = tools[1] + + # Verify tool descriptions include goals and backstories + assert "Quick Researcher (Goal: Find information quickly" in delegate_tool.description + assert "Deep Researcher (Goal: Find detailed" in delegate_tool.description + assert "Specialist in rapid information gathering" in delegate_tool.description + assert "Expert in comprehensive research" in delegate_tool.description + + # Verify ask tool also has the enhanced descriptions + assert "Quick Researcher (Goal: Find information quickly" in ask_tool.description + assert "Deep Researcher (Goal: Find detailed" in ask_tool.description + assert "Specialist in rapid information gathering" in ask_tool.description + assert "Expert in comprehensive research" in ask_tool.description + + # Verify multiline formatting + assert "\n- " in delegate_tool.description + assert "\n- " in ask_tool.description