From fbb156b9de7e0598bdbb4090ed989d31fbe7b2c0 Mon Sep 17 00:00:00 2001 From: Tony Kipkemboi Date: Wed, 9 Apr 2025 14:14:03 -0700 Subject: [PATCH 01/11] Docs: Alphabetize sections, add YouTube video, improve layout (#2560) --- docs/docs.json | 13 +++++++++---- docs/installation.mdx | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/docs.json b/docs/docs.json index 52ae283fe..4ea940973 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -76,9 +76,7 @@ "concepts/testing", "concepts/cli", "concepts/tools", - "concepts/event-listener", - "concepts/langchain-tools", - "concepts/llamaindex-tools" + "concepts/event-listener" ] }, { @@ -97,7 +95,9 @@ "how-to/kickoff-async", "how-to/kickoff-for-each", "how-to/replay-tasks-from-latest-crew-kickoff", - "how-to/conditional-tasks" + "how-to/conditional-tasks", + "how-to/langchain-tools", + "how-to/llamaindex-tools" ] }, { @@ -196,6 +196,11 @@ "anchor": "Community", "href": "https://community.crewai.com", "icon": "discourse" + }, + { + "anchor": "Tutorials", + "href": "https://www.youtube.com/@crewAIInc", + "icon": "youtube" } ] } diff --git a/docs/installation.mdx b/docs/installation.mdx index a1fba2d64..7c1e09a3b 100644 --- a/docs/installation.mdx +++ b/docs/installation.mdx @@ -4,6 +4,21 @@ description: Get started with CrewAI - Install, configure, and build your first icon: wrench --- +## Video Tutorial +Watch this video tutorial for a step-by-step demonstration of the installation process: + + + +## Text Tutorial **Python Version Requirements** From 98ccbeb4bdae59cd84088d79235845a4f2d10fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moura?= Date: Wed, 9 Apr 2025 18:13:41 -0700 Subject: [PATCH 02/11] new version --- pyproject.toml | 2 +- src/crewai/__init__.py | 2 +- src/crewai/cli/templates/crew/pyproject.toml | 2 +- src/crewai/cli/templates/flow/pyproject.toml | 2 +- src/crewai/cli/templates/tool/pyproject.toml | 2 +- uv.lock | 102 ++++++++++++------- 6 files changed, 68 insertions(+), 44 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c6c32e2d6..d85c43c93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "crewai" -version = "0.108.0" +version = "0.114.0" description = "Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks." readme = "README.md" requires-python = ">=3.10,<3.13" diff --git a/src/crewai/__init__.py b/src/crewai/__init__.py index 565f89065..a10760eeb 100644 --- a/src/crewai/__init__.py +++ b/src/crewai/__init__.py @@ -17,7 +17,7 @@ warnings.filterwarnings( category=UserWarning, module="pydantic.main", ) -__version__ = "0.108.0" +__version__ = "0.114.0" __all__ = [ "Agent", "Crew", diff --git a/src/crewai/cli/templates/crew/pyproject.toml b/src/crewai/cli/templates/crew/pyproject.toml index 54a6e82f9..4e848ce15 100644 --- a/src/crewai/cli/templates/crew/pyproject.toml +++ b/src/crewai/cli/templates/crew/pyproject.toml @@ -5,7 +5,7 @@ description = "{{name}} using crewAI" authors = [{ name = "Your Name", email = "you@example.com" }] requires-python = ">=3.10,<3.13" dependencies = [ - "crewai[tools]>=0.108.0,<1.0.0" + "crewai[tools]>=0.114.0,<1.0.0" ] [project.scripts] diff --git a/src/crewai/cli/templates/flow/pyproject.toml b/src/crewai/cli/templates/flow/pyproject.toml index 93e7c1de7..900ea9681 100644 --- a/src/crewai/cli/templates/flow/pyproject.toml +++ b/src/crewai/cli/templates/flow/pyproject.toml @@ -5,7 +5,7 @@ description = "{{name}} using crewAI" authors = [{ name = "Your Name", email = "you@example.com" }] requires-python = ">=3.10,<3.13" dependencies = [ - "crewai[tools]>=0.108.0,<1.0.0", + "crewai[tools]>=0.114.0,<1.0.0", ] [project.scripts] diff --git a/src/crewai/cli/templates/tool/pyproject.toml b/src/crewai/cli/templates/tool/pyproject.toml index e96ef65df..9edc8ac29 100644 --- a/src/crewai/cli/templates/tool/pyproject.toml +++ b/src/crewai/cli/templates/tool/pyproject.toml @@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}" readme = "README.md" requires-python = ">=3.10,<3.13" dependencies = [ - "crewai[tools]>=0.108.0" + "crewai[tools]>=0.114.0" ] [tool.crewai] diff --git a/uv.lock b/uv.lock index 7da642db8..21c8445f0 100644 --- a/uv.lock +++ b/uv.lock @@ -1,19 +1,42 @@ version = 1 -revision = 1 requires-python = ">=3.10, <3.13" resolution-markers = [ - "python_full_version < '3.11' and sys_platform == 'darwin'", - "python_full_version < '3.11' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "(python_full_version < '3.11' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')", - "python_full_version == '3.11.*' and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'linux')", - "python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform == 'darwin'", - "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')", - "python_full_version >= '3.12.4' and sys_platform == 'darwin'", - "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'", - "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'", + "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version < '3.11' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'", + "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version < '3.11' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'", + "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version == '3.11.*' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'", + "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version == '3.11.*' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'", + "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'", + "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version >= '3.12.4' and platform_system == 'Darwin' and sys_platform == 'darwin'", + "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'", + "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version >= '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')", + "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'", + "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'", + "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12.4' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", ] [[package]] @@ -321,7 +344,7 @@ name = "build" version = "1.2.2.post1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "colorama", marker = "os_name == 'nt'" }, { name = "importlib-metadata", marker = "python_full_version < '3.10.2'" }, { name = "packaging" }, { name = "pyproject-hooks" }, @@ -556,7 +579,7 @@ name = "click" version = "8.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } wheels = [ @@ -607,7 +630,7 @@ wheels = [ [[package]] name = "crewai" -version = "0.108.0" +version = "0.114.0" source = { editable = "." } dependencies = [ { name = "appdirs" }, @@ -722,7 +745,6 @@ requires-dist = [ { name = "tomli-w", specifier = ">=1.1.0" }, { name = "uv", specifier = ">=0.4.25" }, ] -provides-extras = ["tools", "embeddings", "agentops", "fastembed", "pdfplumber", "pandas", "openpyxl", "mem0", "docling", "aisuite"] [package.metadata.requires-dev] dev = [ @@ -2496,7 +2518,7 @@ version = "1.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, { name = "ghp-import" }, { name = "jinja2" }, { name = "markdown" }, @@ -2677,7 +2699,7 @@ version = "2.10.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pygments" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "pywin32", marker = "platform_system == 'Windows'" }, { name = "tqdm" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/93/80ac75c20ce54c785648b4ed363c88f148bf22637e10c9863db4fbe73e74/mpire-2.10.2.tar.gz", hash = "sha256:f66a321e93fadff34585a4bfa05e95bd946cf714b442f51c529038eb45773d97", size = 271270 } @@ -2924,7 +2946,7 @@ name = "nvidia-cudnn-cu12" version = "9.1.0.70" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741 }, @@ -2951,9 +2973,9 @@ name = "nvidia-cusolver-cu12" version = "11.4.5.107" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, - { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" }, + { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/bc/1d/8de1e5c67099015c834315e333911273a8c6aaba78923dd1d1e25fc5f217/nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd", size = 124161928 }, @@ -2964,7 +2986,7 @@ name = "nvidia-cusparse-cu12" version = "12.1.0.106" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/65/5b/cfaeebf25cd9fdec14338ccb16f6b2c4c7fa9163aefcf057d86b9cc248bb/nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c", size = 195958278 }, @@ -2975,6 +2997,7 @@ name = "nvidia-nccl-cu12" version = "2.20.5" source = { registry = "https://pypi.org/simple" } wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/bb/d09dda47c881f9ff504afd6f9ca4f502ded6d8fc2f572cacc5e39da91c28/nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1fc150d5c3250b170b29410ba682384b14581db722b2531b0d8d33c595f33d01", size = 176238458 }, { url = "https://files.pythonhosted.org/packages/4b/2a/0a131f572aa09f741c30ccd45a8e56316e8be8dfc7bc19bf0ab7cfef7b19/nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:057f6bf9685f75215d0c53bf3ac4a10b3e6578351de307abad9e18a99182af56", size = 176249402 }, ] @@ -2984,6 +3007,7 @@ version = "12.6.85" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/9d/d7/c5383e47c7e9bf1c99d5bd2a8c935af2b6d705ad831a7ec5c97db4d82f4f/nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:eedc36df9e88b682efe4309aa16b5b4e78c2407eac59e8c10a6a47535164369a", size = 19744971 }, + { url = "https://files.pythonhosted.org/packages/31/db/dc71113d441f208cdfe7ae10d4983884e13f464a6252450693365e166dcf/nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cf4eaa7d4b6b543ffd69d6abfb11efdeb2db48270d94dfd3a452c24150829e41", size = 19270338 }, ] [[package]] @@ -3501,7 +3525,7 @@ name = "portalocker" version = "2.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "pywin32", marker = "platform_system == 'Windows'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 } wheels = [ @@ -5008,19 +5032,19 @@ dependencies = [ { name = "fsspec" }, { name = "jinja2" }, { name = "networkx" }, - { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, { name = "typing-extensions" }, ] wheels = [ @@ -5067,7 +5091,7 @@ name = "tqdm" version = "4.66.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 } wheels = [ @@ -5109,7 +5133,7 @@ name = "triton" version = "3.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filelock", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "filelock", marker = "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'linux')" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/45/27/14cc3101409b9b4b9241d2ba7deaa93535a217a211c86c4cc7151fb12181/triton-3.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e1efef76935b2febc365bfadf74bcb65a6f959a9872e5bddf44cc9e0adce1e1a", size = 209376304 }, From 5780c3147afd2db9be5cd7eb88450a0f04f12977 Mon Sep 17 00:00:00 2001 From: x1x2 <96424373+bitstreamshaman@users.noreply.github.com> Date: Thu, 10 Apr 2025 15:51:10 +0300 Subject: [PATCH 03/11] fix: correct parameter name in crew template test function (#2567) This commit resolves an issue in the crew template generator where the test() function incorrectly uses 'openai_model_name' as a parameter name when calling Crew.test(), while the actual implementation expects 'eval_llm'. The mismatch causes a TypeError when users run the generated test command: "Crew.test() got an unexpected keyword argument 'openai_model_name'" This change ensures that templates generated with 'crewai create crew' will produce code that aligns with the framework's API. --- src/crewai/cli/templates/crew/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crewai/cli/templates/crew/main.py b/src/crewai/cli/templates/crew/main.py index d9fe85d42..454d28ee6 100644 --- a/src/crewai/cli/templates/crew/main.py +++ b/src/crewai/cli/templates/crew/main.py @@ -60,7 +60,7 @@ def test(): "current_year": str(datetime.now().year) } try: - {{crew_name}}().crew().test(n_iterations=int(sys.argv[1]), openai_model_name=sys.argv[2], inputs=inputs) + {{crew_name}}().crew().test(n_iterations=int(sys.argv[1]), eval_llm=sys.argv[2], inputs=inputs) except Exception as e: raise Exception(f"An error occurred while testing the crew: {e}") From c9f47e6a37617576ac48913e7c4fcec39018d1af Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 09:01:26 -0400 Subject: [PATCH 04/11] Add result_as_answer parameter to @tool decorator (Fixes #2561) (#2562) Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Joe Moura --- src/crewai/tools/base_tool.py | 7 ++++++- tests/tools/test_base_tool.py | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/crewai/tools/base_tool.py b/src/crewai/tools/base_tool.py index dc69b02a2..2d6526266 100644 --- a/src/crewai/tools/base_tool.py +++ b/src/crewai/tools/base_tool.py @@ -244,9 +244,13 @@ def to_langchain( return [t.to_structured_tool() if isinstance(t, BaseTool) else t for t in tools] -def tool(*args): +def tool(*args, result_as_answer=False): """ Decorator to create a tool from a function. + + Args: + *args: Positional arguments, either the function to decorate or the tool name. + result_as_answer: Flag to indicate if the tool result should be used as the final agent answer. """ def _make_with_name(tool_name: str) -> Callable: @@ -272,6 +276,7 @@ def tool(*args): description=f.__doc__, func=f, args_schema=args_schema, + result_as_answer=result_as_answer, ) return _make_tool diff --git a/tests/tools/test_base_tool.py b/tests/tools/test_base_tool.py index 51eb05b75..a1eb7a407 100644 --- a/tests/tools/test_base_tool.py +++ b/tests/tools/test_base_tool.py @@ -100,3 +100,25 @@ def test_default_cache_function_is_true(): my_tool = MyCustomTool() # Assert all the right attributes were defined assert my_tool.cache_function() + + +def test_result_as_answer_in_tool_decorator(): + @tool("Tool with result as answer", result_as_answer=True) + def my_tool_with_result_as_answer(question: str) -> str: + """This tool will return its result as the final answer.""" + return question + + assert my_tool_with_result_as_answer.result_as_answer is True + + converted_tool = my_tool_with_result_as_answer.to_structured_tool() + assert converted_tool.result_as_answer is True + + @tool("Tool with default result_as_answer") + def my_tool_with_default(question: str) -> str: + """This tool uses the default result_as_answer value.""" + return question + + assert my_tool_with_default.result_as_answer is False + + converted_tool = my_tool_with_default.to_structured_tool() + assert converted_tool.result_as_answer is False From 37979a0ca1ab7c657ed005fdfeabacaa1a7a3568 Mon Sep 17 00:00:00 2001 From: Vini Brasil Date: Thu, 10 Apr 2025 13:08:32 -0400 Subject: [PATCH 05/11] Raise exception when flow fails (#2579) --- src/crewai/flow/flow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crewai/flow/flow.py b/src/crewai/flow/flow.py index 3b6e81293..99ae82c96 100644 --- a/src/crewai/flow/flow.py +++ b/src/crewai/flow/flow.py @@ -1043,6 +1043,7 @@ class Flow(Generic[T], metaclass=FlowMeta): import traceback traceback.print_exc() + raise def _log_flow_event( self, message: str, color: str = "yellow", level: str = "info" From d2caf11191bc0f641db4111d67b30dcba1cd3e78 Mon Sep 17 00:00:00 2001 From: Lucas Gomide Date: Thu, 10 Apr 2025 15:37:24 -0300 Subject: [PATCH 06/11] Support Python 3.10+ (on CI) and remove redundant Self imports (#2553) * ci(workflows): add Python version matrix (3.10-3.12) for tests * refactor: remove explicit Self import from typing Python 3.10+ natively supports Self type annotation without explicit imports * chore: rename external_memory file test --------- Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com> --- .github/workflows/tests.yml | 8 +++++--- src/crewai/memory/external/external_memory.py | 4 ++-- src/crewai/memory/memory.py | 4 ++-- .../{test_external_memory.py => external_memory_test.py} | 0 4 files changed, 9 insertions(+), 7 deletions(-) rename tests/memory/external/{test_external_memory.py => external_memory_test.py} (100%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f655dcc64..9ee0e999a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,6 +12,9 @@ jobs: tests: runs-on: ubuntu-latest timeout-minutes: 15 + strategy: + matrix: + python-version: ['3.10', '3.11', '3.12'] steps: - name: Checkout code uses: actions/checkout@v4 @@ -21,9 +24,8 @@ jobs: with: enable-cache: true - - - name: Set up Python - run: uv python install 3.12.8 + - name: Set up Python ${{ matrix.python-version }} + run: uv python install ${{ matrix.python-version }} - name: Install the project run: uv sync --dev --all-extras diff --git a/src/crewai/memory/external/external_memory.py b/src/crewai/memory/external/external_memory.py index 4ecf3d065..be35f513b 100644 --- a/src/crewai/memory/external/external_memory.py +++ b/src/crewai/memory/external/external_memory.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, Dict, Optional, Self +from typing import TYPE_CHECKING, Any, Dict, Optional from crewai.memory.external.external_memory_item import ExternalMemoryItem from crewai.memory.memory import Memory @@ -52,7 +52,7 @@ class ExternalMemory(Memory): def reset(self) -> None: self.storage.reset() - def set_crew(self, crew: Any) -> Self: + def set_crew(self, crew: Any) -> "ExternalMemory": super().set_crew(crew) if not self.storage: diff --git a/src/crewai/memory/memory.py b/src/crewai/memory/memory.py index ba8c10a29..20538a186 100644 --- a/src/crewai/memory/memory.py +++ b/src/crewai/memory/memory.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Self +from typing import Any, Dict, List, Optional from pydantic import BaseModel @@ -38,6 +38,6 @@ class Memory(BaseModel): query=query, limit=limit, score_threshold=score_threshold ) - def set_crew(self, crew: Any) -> Self: + def set_crew(self, crew: Any) -> "Memory": self.crew = crew return self diff --git a/tests/memory/external/test_external_memory.py b/tests/memory/external/external_memory_test.py similarity index 100% rename from tests/memory/external/test_external_memory.py rename to tests/memory/external/external_memory_test.py From 4bff5408d870249271d69f4c7f4e82634e61a3d6 Mon Sep 17 00:00:00 2001 From: Jesse R Weigel Date: Fri, 11 Apr 2025 09:14:05 -0400 Subject: [PATCH 07/11] Create output folder if it doesn't exits (#2573) When running this project, I got an error because the output folder had not been created. I added a line to check if the output folder exists and create it if needed. --- docs/guides/flows/first-flow.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/guides/flows/first-flow.mdx b/docs/guides/flows/first-flow.mdx index ab03693b9..cb10de275 100644 --- a/docs/guides/flows/first-flow.mdx +++ b/docs/guides/flows/first-flow.mdx @@ -263,6 +263,7 @@ Let's create our flow in the `main.py` file: ```python #!/usr/bin/env python import json +import os from typing import List, Dict from pydantic import BaseModel, Field from crewai import LLM @@ -341,6 +342,9 @@ class GuideCreatorFlow(Flow[GuideCreatorState]): outline_dict = json.loads(response) self.state.guide_outline = GuideOutline(**outline_dict) + # Ensure output directory exists before saving + os.makedirs("output", exist_ok=True) + # Save the outline to a file with open("output/guide_outline.json", "w") as f: json.dump(outline_dict, f, indent=2) From 0cd524af86e3e6b3abdd6b5157196c8efc9b4f4f Mon Sep 17 00:00:00 2001 From: Cypher Pepe <125112044+cypherpepe@users.noreply.github.com> Date: Fri, 11 Apr 2025 18:58:01 +0300 Subject: [PATCH 08/11] fixed broken link in `docs/tools/weaviatevectorsearchtool.mdx` (#2569) --- docs/tools/weaviatevectorsearchtool.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tools/weaviatevectorsearchtool.mdx b/docs/tools/weaviatevectorsearchtool.mdx index 53922e4e2..d17bcfef5 100644 --- a/docs/tools/weaviatevectorsearchtool.mdx +++ b/docs/tools/weaviatevectorsearchtool.mdx @@ -25,7 +25,7 @@ uv add weaviate-client To effectively use the `WeaviateVectorSearchTool`, follow these steps: 1. **Package Installation**: Confirm that the `crewai[tools]` and `weaviate-client` packages are installed in your Python environment. -2. **Weaviate Setup**: Set up a Weaviate cluster. You can follow the [Weaviate documentation](https://weaviate.io/developers/wcs/connect) for instructions. +2. **Weaviate Setup**: Set up a Weaviate cluster. You can follow the [Weaviate documentation](https://weaviate.io/developers/wcs/manage-clusters/connect) for instructions. 3. **API Keys**: Obtain your Weaviate cluster URL and API key. 4. **OpenAI API Key**: Ensure you have an OpenAI API key set in your environment variables as `OPENAI_API_KEY`. @@ -161,4 +161,4 @@ rag_agent = Agent( ## Conclusion -The `WeaviateVectorSearchTool` provides a powerful way to search for semantically similar documents in a Weaviate vector database. By leveraging vector embeddings, it enables more accurate and contextually relevant search results compared to traditional keyword-based searches. This tool is particularly useful for applications that require finding information based on meaning rather than exact matches. \ No newline at end of file +The `WeaviateVectorSearchTool` provides a powerful way to search for semantically similar documents in a Weaviate vector database. By leveraging vector embeddings, it enables more accurate and contextually relevant search results compared to traditional keyword-based searches. This tool is particularly useful for applications that require finding information based on meaning rather than exact matches. From ea5ae9086a18af11fde25cf68f96197f726e6479 Mon Sep 17 00:00:00 2001 From: Vidit Ostwal <110953813+Vidit-Ostwal@users.noreply.github.com> Date: Fri, 11 Apr 2025 22:26:37 +0530 Subject: [PATCH 09/11] =?UTF-8?q?added=20condition=20to=20check=20whether?= =?UTF-8?q?=20=5Frun=20function=20returns=20a=20coroutine=20ob=E2=80=A6=20?= =?UTF-8?q?(#2570)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added condition to check whether _run function returns a coroutine object * Cleaned the code * Fixed the test modules, Class -> Functions --- src/crewai/tools/base_tool.py | 9 ++++- tests/tools/test_base_tool.py | 72 ++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/crewai/tools/base_tool.py b/src/crewai/tools/base_tool.py index 2d6526266..0e8a7a22b 100644 --- a/src/crewai/tools/base_tool.py +++ b/src/crewai/tools/base_tool.py @@ -1,3 +1,4 @@ +import asyncio import warnings from abc import ABC, abstractmethod from inspect import signature @@ -65,7 +66,13 @@ class BaseTool(BaseModel, ABC): **kwargs: Any, ) -> Any: print(f"Using Tool: {self.name}") - return self._run(*args, **kwargs) + result = self._run(*args, **kwargs) + + # If _run is async, we safely run it + if asyncio.iscoroutine(result): + return asyncio.run(result) + + return result @abstractmethod def _run( diff --git a/tests/tools/test_base_tool.py b/tests/tools/test_base_tool.py index a1eb7a407..b4f3d2488 100644 --- a/tests/tools/test_base_tool.py +++ b/tests/tools/test_base_tool.py @@ -1,4 +1,8 @@ -from typing import Callable +import asyncio +import inspect +import unittest +from typing import Any, Callable, Dict, List +from unittest.mock import patch from crewai.tools import BaseTool, tool @@ -122,3 +126,69 @@ def test_result_as_answer_in_tool_decorator(): converted_tool = my_tool_with_default.to_structured_tool() assert converted_tool.result_as_answer is False + + +class SyncTool(BaseTool): + """Test implementation with a synchronous _run method""" + name: str = "sync_tool" + description: str = "A synchronous tool for testing" + + def _run(self, input_text: str) -> str: + """Process input text synchronously.""" + return f"Processed {input_text} synchronously" + + +class AsyncTool(BaseTool): + """Test implementation with an asynchronous _run method""" + name: str = "async_tool" + description: str = "An asynchronous tool for testing" + + async def _run(self, input_text: str) -> str: + """Process input text asynchronously.""" + await asyncio.sleep(0.1) # Simulate async operation + return f"Processed {input_text} asynchronously" + + +def test_sync_run_returns_direct_result(): + """Test that _run in a synchronous tool returns a direct result, not a coroutine.""" + tool = SyncTool() + result = tool._run(input_text="hello") + + assert not asyncio.iscoroutine(result) + assert result == "Processed hello synchronously" + + run_result = tool.run(input_text="hello") + assert run_result == "Processed hello synchronously" + + +def test_async_run_returns_coroutine(): + """Test that _run in an asynchronous tool returns a coroutine object.""" + tool = AsyncTool() + result = tool._run(input_text="hello") + + assert asyncio.iscoroutine(result) + result.close() # Clean up the coroutine + + +def test_run_calls_asyncio_run_for_async_tools(): + """Test that asyncio.run is called when using async tools.""" + async_tool = AsyncTool() + + with patch('asyncio.run') as mock_run: + mock_run.return_value = "Processed test asynchronously" + async_result = async_tool.run(input_text="test") + + mock_run.assert_called_once() + assert async_result == "Processed test asynchronously" + + +def test_run_does_not_call_asyncio_run_for_sync_tools(): + """Test that asyncio.run is NOT called when using sync tools.""" + sync_tool = SyncTool() + + with patch('asyncio.run') as mock_run: + sync_result = sync_tool.run(input_text="test") + + mock_run.assert_not_called() + assert sync_result == "Processed test synchronously" + From 40a441f30eebce88b928db875e4309b892a9ac11 Mon Sep 17 00:00:00 2001 From: Eduardo Chiarotti Date: Fri, 11 Apr 2025 14:26:59 -0400 Subject: [PATCH 10/11] feat: remove unused code and change ToolUsageStarted event place (#2581) * feat: remove unused code and change ToolUsageStarted event place * feat: run lint * feat: add agent refernece inside liteagent * feat: remove unused logic * feat: Remove not needed event * feat: remove test from tool execution erro: * feat: remove cassete --- src/crewai/agent.py | 1 + src/crewai/lite_agent.py | 50 +------- src/crewai/llm.py | 9 -- src/crewai/tools/tool_usage.py | 17 ++- src/crewai/utilities/agent_utils.py | 1 - src/crewai/utilities/tool_utils.py | 36 ------ .../test_tool_execution_error_event.yaml | 112 ------------------ tests/llm_test.py | 48 -------- 8 files changed, 23 insertions(+), 251 deletions(-) delete mode 100644 tests/cassettes/test_tool_execution_error_event.yaml diff --git a/src/crewai/agent.py b/src/crewai/agent.py index a265f4d52..4ddd20e21 100644 --- a/src/crewai/agent.py +++ b/src/crewai/agent.py @@ -482,6 +482,7 @@ class Agent(BaseAgent): verbose=self.verbose, response_format=response_format, i18n=self.i18n, + original_agent=self, ) return lite_agent.kickoff(messages) diff --git a/src/crewai/lite_agent.py b/src/crewai/lite_agent.py index e63a2320d..d458e6de0 100644 --- a/src/crewai/lite_agent.py +++ b/src/crewai/lite_agent.py @@ -47,11 +47,6 @@ from crewai.utilities.events.llm_events import ( LLMCallStartedEvent, LLMCallType, ) -from crewai.utilities.events.tool_usage_events import ( - ToolUsageErrorEvent, - ToolUsageFinishedEvent, - ToolUsageStartedEvent, -) from crewai.utilities.llm_utils import create_llm from crewai.utilities.printer import Printer from crewai.utilities.token_counter_callback import TokenCalcHandler @@ -155,6 +150,10 @@ class LiteAgent(BaseModel): default=[], description="Results of the tools used by the agent." ) + # Reference of Agent + original_agent: Optional[BaseAgent] = Field( + default=None, description="Reference to the agent that created this LiteAgent" + ) # Private Attributes _parsed_tools: List[CrewStructuredTool] = PrivateAttr(default_factory=list) _token_process: TokenProcess = PrivateAttr(default_factory=TokenProcess) @@ -163,7 +162,7 @@ class LiteAgent(BaseModel): _messages: List[Dict[str, str]] = PrivateAttr(default_factory=list) _iterations: int = PrivateAttr(default=0) _printer: Printer = PrivateAttr(default_factory=Printer) - + @model_validator(mode="after") def setup_llm(self): """Set up the LLM and other components after initialization.""" @@ -412,18 +411,6 @@ class LiteAgent(BaseModel): formatted_answer = process_llm_response(answer, self.use_stop_words) if isinstance(formatted_answer, AgentAction): - # Emit tool usage started event - crewai_event_bus.emit( - self, - event=ToolUsageStartedEvent( - agent_key=self.key, - agent_role=self.role, - tool_name=formatted_answer.tool, - tool_args=formatted_answer.tool_input, - tool_class=formatted_answer.tool, - ), - ) - try: tool_result = execute_tool_and_check_finality( agent_action=formatted_answer, @@ -431,34 +418,9 @@ class LiteAgent(BaseModel): i18n=self.i18n, agent_key=self.key, agent_role=self.role, - ) - # Emit tool usage finished event - crewai_event_bus.emit( - self, - event=ToolUsageFinishedEvent( - agent_key=self.key, - agent_role=self.role, - tool_name=formatted_answer.tool, - tool_args=formatted_answer.tool_input, - tool_class=formatted_answer.tool, - started_at=datetime.now(), - finished_at=datetime.now(), - output=tool_result.result, - ), + agent=self.original_agent, ) except Exception as e: - # Emit tool usage error event - crewai_event_bus.emit( - self, - event=ToolUsageErrorEvent( - agent_key=self.key, - agent_role=self.role, - tool_name=formatted_answer.tool, - tool_args=formatted_answer.tool_input, - tool_class=formatted_answer.tool, - error=str(e), - ), - ) raise e formatted_answer = handle_agent_action_core( diff --git a/src/crewai/llm.py b/src/crewai/llm.py index 741544662..25b798a6d 100644 --- a/src/crewai/llm.py +++ b/src/crewai/llm.py @@ -707,15 +707,6 @@ class LLM(BaseLLM): function_name, lambda: None ) # Ensure fn is always a callable logging.error(f"Error executing function '{function_name}': {e}") - crewai_event_bus.emit( - self, - event=ToolExecutionErrorEvent( - tool_name=function_name, - tool_args=function_args, - tool_class=fn, - error=str(e), - ), - ) crewai_event_bus.emit( self, event=LLMCallFailedEvent(error=f"Tool execution error: {str(e)}"), diff --git a/src/crewai/tools/tool_usage.py b/src/crewai/tools/tool_usage.py index 8c6862e0d..dc5f8f29a 100644 --- a/src/crewai/tools/tool_usage.py +++ b/src/crewai/tools/tool_usage.py @@ -2,7 +2,6 @@ import ast import datetime import json import time -from dataclasses import dataclass from difflib import SequenceMatcher from json import JSONDecodeError from textwrap import dedent @@ -26,6 +25,7 @@ from crewai.utilities.events.tool_usage_events import ( ToolSelectionErrorEvent, ToolUsageErrorEvent, ToolUsageFinishedEvent, + ToolUsageStartedEvent, ToolValidateInputErrorEvent, ) @@ -166,6 +166,21 @@ class ToolUsage: if self.task: self.task.increment_tools_errors() + if self.agent: + event_data = { + "agent_key": self.agent.key, + "agent_role": self.agent.role, + "tool_name": self.action.tool, + "tool_args": self.action.tool_input, + "tool_class": self.action.tool, + "agent": self.agent, + } + + if self.agent.fingerprint: + event_data.update(self.agent.fingerprint) + + crewai_event_bus.emit(self,ToolUsageStartedEvent(**event_data)) + started_at = time.time() from_cache = False result = None # type: ignore diff --git a/src/crewai/utilities/agent_utils.py b/src/crewai/utilities/agent_utils.py index e9389eb0e..8af665140 100644 --- a/src/crewai/utilities/agent_utils.py +++ b/src/crewai/utilities/agent_utils.py @@ -16,7 +16,6 @@ from crewai.tools.base_tool import BaseTool from crewai.tools.structured_tool import CrewStructuredTool from crewai.tools.tool_types import ToolResult from crewai.utilities import I18N, Printer -from crewai.utilities.events.tool_usage_events import ToolUsageStartedEvent from crewai.utilities.exceptions.context_window_exceeding_exception import ( LLMContextLengthExceededException, ) diff --git a/src/crewai/utilities/tool_utils.py b/src/crewai/utilities/tool_utils.py index 2b26ca83b..eaf065477 100644 --- a/src/crewai/utilities/tool_utils.py +++ b/src/crewai/utilities/tool_utils.py @@ -5,11 +5,6 @@ from crewai.security import Fingerprint from crewai.tools.structured_tool import CrewStructuredTool from crewai.tools.tool_types import ToolResult from crewai.tools.tool_usage import ToolUsage, ToolUsageErrorException -from crewai.utilities.events import crewai_event_bus -from crewai.utilities.events.tool_usage_events import ( - ToolUsageErrorEvent, - ToolUsageStartedEvent, -) from crewai.utilities.i18n import I18N @@ -42,10 +37,8 @@ def execute_tool_and_check_finality( ToolResult containing the execution result and whether it should be treated as a final answer """ try: - # Create tool name to tool map tool_name_to_tool_map = {tool.name: tool for tool in tools} - # Emit tool usage event if agent info is available if agent_key and agent_role and agent: fingerprint_context = fingerprint_context or {} if agent: @@ -59,22 +52,6 @@ def execute_tool_and_check_finality( except Exception as e: raise ValueError(f"Failed to set fingerprint: {e}") - event_data = { - "agent_key": agent_key, - "agent_role": agent_role, - "tool_name": agent_action.tool, - "tool_args": agent_action.tool_input, - "tool_class": agent_action.tool, - "agent": agent, - } - event_data.update(fingerprint_context) - crewai_event_bus.emit( - agent, - event=ToolUsageStartedEvent( - **event_data, - ), - ) - # Create tool usage instance tool_usage = ToolUsage( tools_handler=tools_handler, @@ -110,17 +87,4 @@ def execute_tool_and_check_finality( return ToolResult(tool_result, False) except Exception as e: - # Emit error event if agent info is available - if agent_key and agent_role and agent: - crewai_event_bus.emit( - agent, - event=ToolUsageErrorEvent( - agent_key=agent_key, - agent_role=agent_role, - tool_name=agent_action.tool, - tool_args=agent_action.tool_input, - tool_class=agent_action.tool, - error=str(e), - ), - ) raise e diff --git a/tests/cassettes/test_tool_execution_error_event.yaml b/tests/cassettes/test_tool_execution_error_event.yaml deleted file mode 100644 index 61583726a..000000000 --- a/tests/cassettes/test_tool_execution_error_event.yaml +++ /dev/null @@ -1,112 +0,0 @@ -interactions: -- request: - body: '{"messages": [{"role": "user", "content": "Use the failing tool"}], "model": - "gpt-4o-mini", "stop": [], "tools": [{"type": "function", "function": {"name": - "failing_tool", "description": "This tool always fails.", "parameters": {"type": - "object", "properties": {"param": {"type": "string", "description": "A test - parameter"}}, "required": ["param"]}}}]}' - headers: - accept: - - application/json - accept-encoding: - - gzip, deflate - connection: - - keep-alive - content-length: - - '353' - content-type: - - application/json - host: - - api.openai.com - user-agent: - - OpenAI/Python 1.61.0 - x-stainless-arch: - - arm64 - x-stainless-async: - - 'false' - x-stainless-lang: - - python - x-stainless-os: - - MacOS - x-stainless-package-version: - - 1.61.0 - x-stainless-raw-response: - - 'true' - x-stainless-retry-count: - - '0' - x-stainless-runtime: - - CPython - x-stainless-runtime-version: - - 3.12.8 - method: POST - uri: https://api.openai.com/v1/chat/completions - response: - content: "{\n \"id\": \"chatcmpl-B2P4zoJZuES7Aom8ugEq1modz5Vsl\",\n \"object\": - \"chat.completion\",\n \"created\": 1739912761,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n - \ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": - \"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n - \ \"id\": \"call_F6fJxISpMKUBIGV6dd2vjRNG\",\n \"type\": - \"function\",\n \"function\": {\n \"name\": \"failing_tool\",\n - \ \"arguments\": \"{\\\"param\\\":\\\"test\\\"}\"\n }\n - \ }\n ],\n \"refusal\": null\n },\n \"logprobs\": - null,\n \"finish_reason\": \"tool_calls\"\n }\n ],\n \"usage\": {\n - \ \"prompt_tokens\": 51,\n \"completion_tokens\": 15,\n \"total_tokens\": - 66,\n \"prompt_tokens_details\": {\n \"cached_tokens\": 0,\n \"audio_tokens\": - 0\n },\n \"completion_tokens_details\": {\n \"reasoning_tokens\": - 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": 0,\n \"rejected_prediction_tokens\": - 0\n }\n },\n \"service_tier\": \"default\",\n \"system_fingerprint\": - \"fp_00428b782a\"\n}\n" - headers: - CF-RAY: - - 9140fa827f38eb1e-SJC - Connection: - - keep-alive - Content-Encoding: - - gzip - Content-Type: - - application/json - Date: - - Tue, 18 Feb 2025 21:06:02 GMT - Server: - - cloudflare - Set-Cookie: - - __cf_bm=xbuu3IQpCMh.43ZrqL1TRMECOc6QldgHV0hzOX1GrWI-1739912762-1.0.1.1-t7iyq5xMioPrwfeaHLvPT9rwRPp7Q9A9uIm69icH9dPxRD4xMA3cWqb1aXj1_e2IyAEQQWFe1UWjlmJ22aHh3Q; - path=/; expires=Tue, 18-Feb-25 21:36:02 GMT; domain=.api.openai.com; HttpOnly; - Secure; SameSite=None - - _cfuvid=x9l.Rhja8_wXDN.j8qcEU1PvvEqAwZp4Fd3s_aj4qwM-1739912762161-0.0.1.1-604800000; - path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None - Transfer-Encoding: - - chunked - X-Content-Type-Options: - - nosniff - access-control-expose-headers: - - X-Request-ID - alt-svc: - - h3=":443"; ma=86400 - cf-cache-status: - - DYNAMIC - openai-organization: - - crewai-iuxna1 - openai-processing-ms: - - '861' - openai-version: - - '2020-10-01' - strict-transport-security: - - max-age=31536000; includeSubDomains; preload - x-ratelimit-limit-requests: - - '30000' - x-ratelimit-limit-tokens: - - '150000000' - x-ratelimit-remaining-requests: - - '29999' - x-ratelimit-remaining-tokens: - - '149999978' - x-ratelimit-reset-requests: - - 2ms - x-ratelimit-reset-tokens: - - 0s - x-request-id: - - req_8666ec3aa6677cb346ba00993556051d - http_version: HTTP/1.1 - status_code: 200 -version: 1 diff --git a/tests/llm_test.py b/tests/llm_test.py index c674b623b..65cc75bab 100644 --- a/tests/llm_test.py +++ b/tests/llm_test.py @@ -395,51 +395,3 @@ def test_deepseek_r1_with_open_router(): result = llm.call("What is the capital of France?") assert isinstance(result, str) assert "Paris" in result - - -@pytest.mark.vcr(filter_headers=["authorization"]) -def test_tool_execution_error_event(): - llm = LLM(model="gpt-4o-mini") - - def failing_tool(param: str) -> str: - """This tool always fails.""" - raise Exception("Tool execution failed!") - - tool_schema = { - "type": "function", - "function": { - "name": "failing_tool", - "description": "This tool always fails.", - "parameters": { - "type": "object", - "properties": { - "param": {"type": "string", "description": "A test parameter"} - }, - "required": ["param"], - }, - }, - } - - received_events = [] - - @crewai_event_bus.on(ToolExecutionErrorEvent) - def event_handler(source, event): - received_events.append(event) - - available_functions = {"failing_tool": failing_tool} - - messages = [{"role": "user", "content": "Use the failing tool"}] - - llm.call( - messages, - tools=[tool_schema], - available_functions=available_functions, - ) - - assert len(received_events) == 1 - event = received_events[0] - assert isinstance(event, ToolExecutionErrorEvent) - assert event.tool_name == "failing_tool" - assert event.tool_args == {"param": "test"} - assert event.tool_class == failing_tool - assert "Tool execution failed!" in event.error From 10edde100e535dd04a26856344d83baf72f85846 Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 08:55:23 -0400 Subject: [PATCH 11/11] Fix: Use mem0_local_config instead of config in Memory.from_config (#2588) * fix: use mem0_local_config instead of config in Memory.from_config (#2587) Co-Authored-By: Joe Moura * refactor: consolidate tests as per PR feedback Co-Authored-By: Joe Moura --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Joe Moura --- src/crewai/memory/storage/mem0_storage.py | 2 +- tests/storage/test_mem0_storage.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/crewai/memory/storage/mem0_storage.py b/src/crewai/memory/storage/mem0_storage.py index ccf8cc810..835788727 100644 --- a/src/crewai/memory/storage/mem0_storage.py +++ b/src/crewai/memory/storage/mem0_storage.py @@ -48,7 +48,7 @@ class Mem0Storage(Storage): self.memory = MemoryClient(api_key=mem0_api_key) else: if mem0_local_config and len(mem0_local_config): - self.memory = Memory.from_config(config) + self.memory = Memory.from_config(mem0_local_config) else: self.memory = Memory() diff --git a/tests/storage/test_mem0_storage.py b/tests/storage/test_mem0_storage.py index f9e56739f..f0c62d480 100644 --- a/tests/storage/test_mem0_storage.py +++ b/tests/storage/test_mem0_storage.py @@ -29,7 +29,7 @@ def mem0_storage_with_mocked_config(mock_mem0_memory): """Fixture to create a Mem0Storage instance with mocked dependencies""" # Patch the Memory class to return our mock - with patch("mem0.memory.main.Memory.from_config", return_value=mock_mem0_memory): + with patch("mem0.memory.main.Memory.from_config", return_value=mock_mem0_memory) as mock_from_config: config = { "vector_store": { "provider": "mock_vector_store", @@ -66,13 +66,15 @@ def mem0_storage_with_mocked_config(mock_mem0_memory): ) mem0_storage = Mem0Storage(type="short_term", crew=crew) - return mem0_storage + return mem0_storage, mock_from_config, config def test_mem0_storage_initialization(mem0_storage_with_mocked_config, mock_mem0_memory): """Test that Mem0Storage initializes correctly with the mocked config""" - assert mem0_storage_with_mocked_config.memory_type == "short_term" - assert mem0_storage_with_mocked_config.memory is mock_mem0_memory + mem0_storage, mock_from_config, config = mem0_storage_with_mocked_config + assert mem0_storage.memory_type == "short_term" + assert mem0_storage.memory is mock_mem0_memory + mock_from_config.assert_called_once_with(config) @pytest.fixture