From dedab16ff160c5b9888a53616011a39f03c48ec7 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Wed, 14 Aug 2024 18:54:53 -0300 Subject: [PATCH] fix: Fix planning_llm issue (#1189) * fix: Fix planning_llm issue * fix: add poetry.lock updated version * fix: type checking issues * fix: tests --- poetry.lock | 61 ++++++++++++++---------- src/crewai/crew.py | 7 ++- src/crewai/telemetry/telemetry.py | 2 +- src/crewai/tools/tool_usage.py | 10 ++-- src/crewai/utilities/planning_handler.py | 15 +++++- tests/utilities/test_planning_handler.py | 17 +++++-- 6 files changed, 72 insertions(+), 40 deletions(-) diff --git a/poetry.lock b/poetry.lock index c811d80a2..701a7e146 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "agentops" @@ -829,29 +829,27 @@ name = "crewai-tools" version = "0.8.3" description = "Set of tools for the crewAI framework" optional = false -python-versions = ">=3.10,<=3.13" -files = [] -develop = false +python-versions = "<=3.13,>=3.10" +files = [ + {file = "crewai_tools-0.8.3-py3-none-any.whl", hash = "sha256:a54a10c36b8403250e13d6594bd37db7e7deb3f9fabc77e8720c081864ae6189"}, + {file = "crewai_tools-0.8.3.tar.gz", hash = "sha256:f0317ea1d926221b22fcf4b816d71916fe870aa66ed7ee2a0067dba42b5634eb"}, +] [package.dependencies] -beautifulsoup4 = "^4.12.3" -chromadb = "^0.4.22" -docker = "^7.1.0" -docx2txt = "^0.8" -embedchain = "^0.1.114" -lancedb = "^0.5.4" +beautifulsoup4 = ">=4.12.3,<5.0.0" +chromadb = ">=0.4.22,<0.5.0" +docker = ">=7.1.0,<8.0.0" +docx2txt = ">=0.8,<0.9" +embedchain = ">=0.1.114,<0.2.0" +lancedb = ">=0.5.4,<0.6.0" langchain = ">0.2,<=0.3" -openai = "^1.12.0" -pydantic = "^2.6.1" -pyright = "^1.1.350" -pytest = "^8.0.0" -pytube = "^15.0.0" -requests = "^2.31.0" -selenium = "^4.18.1" - -[package.source] -type = "directory" -url = "../crewai-tools" +openai = ">=1.12.0,<2.0.0" +pydantic = ">=2.6.1,<3.0.0" +pyright = ">=1.1.350,<2.0.0" +pytest = ">=8.0.0,<9.0.0" +pytube = ">=15.0.0,<16.0.0" +requests = ">=2.31.0,<3.0.0" +selenium = ">=4.18.1,<5.0.0" [[package]] name = "cssselect2" @@ -1321,12 +1319,12 @@ files = [ google-auth = ">=2.14.1,<3.0.dev0" googleapis-common-protos = ">=1.56.2,<2.0.dev0" grpcio = [ - {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, {version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, + {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, ] grpcio-status = [ - {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, + {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, ] proto-plus = ">=1.22.3,<2.0.0dev" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" @@ -3628,8 +3626,8 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" @@ -4027,6 +4025,19 @@ files = [ {file = "pyarrow-17.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:392bc9feabc647338e6c89267635e111d71edad5fcffba204425a7c8d13610d7"}, {file = "pyarrow-17.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:af5ff82a04b2171415f1410cff7ebb79861afc5dae50be73ce06d6e870615204"}, {file = "pyarrow-17.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:edca18eaca89cd6382dfbcff3dd2d87633433043650c07375d095cd3517561d8"}, + {file = "pyarrow-17.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c7916bff914ac5d4a8fe25b7a25e432ff921e72f6f2b7547d1e325c1ad9d155"}, + {file = "pyarrow-17.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f553ca691b9e94b202ff741bdd40f6ccb70cdd5fbf65c187af132f1317de6145"}, + {file = "pyarrow-17.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0cdb0e627c86c373205a2f94a510ac4376fdc523f8bb36beab2e7f204416163c"}, + {file = "pyarrow-17.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:d7d192305d9d8bc9082d10f361fc70a73590a4c65cf31c3e6926cd72b76bc35c"}, + {file = "pyarrow-17.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:02dae06ce212d8b3244dd3e7d12d9c4d3046945a5933d28026598e9dbbda1fca"}, + {file = "pyarrow-17.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:13d7a460b412f31e4c0efa1148e1d29bdf18ad1411eb6757d38f8fbdcc8645fb"}, + {file = "pyarrow-17.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b564a51fbccfab5a04a80453e5ac6c9954a9c5ef2890d1bcf63741909c3f8df"}, + {file = "pyarrow-17.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32503827abbc5aadedfa235f5ece8c4f8f8b0a3cf01066bc8d29de7539532687"}, + {file = "pyarrow-17.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a155acc7f154b9ffcc85497509bcd0d43efb80d6f733b0dc3bb14e281f131c8b"}, + {file = "pyarrow-17.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:dec8d129254d0188a49f8a1fc99e0560dc1b85f60af729f47de4046015f9b0a5"}, + {file = "pyarrow-17.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:a48ddf5c3c6a6c505904545c25a4ae13646ae1f8ba703c4df4a1bfe4f4006bda"}, + {file = "pyarrow-17.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:42bf93249a083aca230ba7e2786c5f673507fa97bbd9725a1e2754715151a204"}, + {file = "pyarrow-17.0.0.tar.gz", hash = "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28"}, ] [package.dependencies] @@ -6062,4 +6073,4 @@ tools = ["crewai-tools"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<=3.13" -content-hash = "fc1b510ea9c814db67ac69d2454071b718cb7f6846bd845f7f48561cb0397ce1" +content-hash = "91ba982ea96ca7be017d536784223d4ef83e86de05d11eb1c3ce0fc1b726f283" diff --git a/src/crewai/crew.py b/src/crewai/crew.py index 948014e0d..5f58e3121 100644 --- a/src/crewai/crew.py +++ b/src/crewai/crew.py @@ -1,9 +1,9 @@ import asyncio import json +import os import uuid from concurrent.futures import Future from hashlib import md5 -import os from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union from langchain_core.callbacks import BaseCallbackHandler @@ -48,11 +48,10 @@ from crewai.utilities.planning_handler import CrewPlanner from crewai.utilities.task_output_storage_handler import TaskOutputStorageHandler from crewai.utilities.training_handler import CrewTrainingHandler - agentops = None if os.environ.get("AGENTOPS_API_KEY"): try: - import agentops + import agentops # type: ignore except ImportError: pass @@ -541,7 +540,7 @@ class Crew(BaseModel): )._handle_crew_planning() for task, step_plan in zip(self.tasks, result.list_of_plans_per_task): - task.description += step_plan + task.description += step_plan.plan def _store_execution_log( self, diff --git a/src/crewai/telemetry/telemetry.py b/src/crewai/telemetry/telemetry.py index 1f86910f3..afff13051 100644 --- a/src/crewai/telemetry/telemetry.py +++ b/src/crewai/telemetry/telemetry.py @@ -295,7 +295,7 @@ class Telemetry: pass def individual_test_result_span( - self, crew: Crew, quality: int, exec_time: int, model_name: str + self, crew: Crew, quality: float, exec_time: int, model_name: str ): if self.ready: try: diff --git a/src/crewai/tools/tool_usage.py b/src/crewai/tools/tool_usage.py index ef0527035..7d2c46634 100644 --- a/src/crewai/tools/tool_usage.py +++ b/src/crewai/tools/tool_usage.py @@ -1,6 +1,6 @@ import ast -from difflib import SequenceMatcher import os +from difflib import SequenceMatcher from textwrap import dedent from typing import Any, List, Union @@ -15,7 +15,7 @@ from crewai.utilities import I18N, Converter, ConverterError, Printer agentops = None if os.environ.get("AGENTOPS_API_KEY"): try: - import agentops + import agentops # type: ignore except ImportError: pass @@ -71,14 +71,14 @@ class ToolUsage: self.task = task self.action = action self.function_calling_llm = function_calling_llm - + # Handling bug (see https://github.com/langchain-ai/langchain/pull/16395): raise an error if tools_names have space for ChatOpenAI if isinstance(self.function_calling_llm, ChatOpenAI): if " " in self.tools_names: raise Exception( "Tools names should not have spaces for ChatOpenAI models." ) - + # Set the maximum parsing attempts for bigger models if (isinstance(self.function_calling_llm, ChatOpenAI)) and ( self.function_calling_llm.openai_api_base is None @@ -118,7 +118,7 @@ class ToolUsage: tool: BaseTool, calling: Union[ToolCalling, InstructorToolCalling], ) -> str: # TODO: Fix this return type - tool_event = agentops.ToolEvent(name=calling.tool_name) if agentops else None + tool_event = agentops.ToolEvent(name=calling.tool_name) if agentops else None # type: ignore if self._check_tool_repeated_usage(calling=calling): # type: ignore # _check_tool_repeated_usage of "ToolUsage" does not return a value (it only ever returns None) try: result = self._i18n.errors("task_repeated_usage").format( diff --git a/src/crewai/utilities/planning_handler.py b/src/crewai/utilities/planning_handler.py index 29b89667e..7b9459adf 100644 --- a/src/crewai/utilities/planning_handler.py +++ b/src/crewai/utilities/planning_handler.py @@ -1,14 +1,25 @@ from typing import Any, List, Optional from langchain_openai import ChatOpenAI -from pydantic import BaseModel +from pydantic import BaseModel, Field from crewai.agent import Agent from crewai.task import Task +class PlanPerTask(BaseModel): + task: str = Field(..., description="The task for which the plan is created") + plan: str = Field( + ..., + description="The step by step plan on how the agents can execute their tasks using the available tools with mastery", + ) + + class PlannerTaskPydanticOutput(BaseModel): - list_of_plans_per_task: List[str] + list_of_plans_per_task: List[PlanPerTask] = Field( + ..., + description="Step by step plan on how the agents can execute their tasks using the available tools with mastery", + ) class CrewPlanner: diff --git a/tests/utilities/test_planning_handler.py b/tests/utilities/test_planning_handler.py index 502398fab..8013e0213 100644 --- a/tests/utilities/test_planning_handler.py +++ b/tests/utilities/test_planning_handler.py @@ -6,7 +6,11 @@ from langchain_openai import ChatOpenAI from crewai.agent import Agent from crewai.task import Task from crewai.tasks.task_output import TaskOutput -from crewai.utilities.planning_handler import CrewPlanner, PlannerTaskPydanticOutput +from crewai.utilities.planning_handler import ( + CrewPlanner, + PlannerTaskPydanticOutput, + PlanPerTask, +) class TestCrewPlanner: @@ -44,12 +48,17 @@ class TestCrewPlanner: return CrewPlanner(tasks, planning_agent_llm) def test_handle_crew_planning(self, crew_planner): + list_of_plans_per_task = [ + PlanPerTask(task="Task1", plan="Plan 1"), + PlanPerTask(task="Task2", plan="Plan 2"), + PlanPerTask(task="Task3", plan="Plan 3"), + ] with patch.object(Task, "execute_sync") as execute: execute.return_value = TaskOutput( description="Description", agent="agent", pydantic=PlannerTaskPydanticOutput( - list_of_plans_per_task=["Plan 1", "Plan 2", "Plan 3"] + list_of_plans_per_task=list_of_plans_per_task ), ) result = crew_planner._handle_crew_planning() @@ -91,7 +100,9 @@ class TestCrewPlanner: execute.return_value = TaskOutput( description="Description", agent="agent", - pydantic=PlannerTaskPydanticOutput(list_of_plans_per_task=["Plan 1"]), + pydantic=PlannerTaskPydanticOutput( + list_of_plans_per_task=[PlanPerTask(task="Task1", plan="Plan 1")] + ), ) result = crew_planner_different_llm._handle_crew_planning()