Preparing new version (#1845)
Some checks failed
Mark stale issues and pull requests / stale (push) Has been cancelled

* Preparing new version
This commit is contained in:
João Moura
2025-01-03 21:49:55 -03:00
committed by GitHub
parent 518800239c
commit 7272fd15ac
18 changed files with 72 additions and 57 deletions

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "crewai" name = "crewai"
version = "0.86.0" version = "0.95.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." 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" readme = "README.md"
requires-python = ">=3.10,<3.13" requires-python = ">=3.10,<3.13"

View File

@@ -14,7 +14,7 @@ warnings.filterwarnings(
category=UserWarning, category=UserWarning,
module="pydantic.main", module="pydantic.main",
) )
__version__ = "0.86.0" __version__ = "0.95.0"
__all__ = [ __all__ = [
"Agent", "Agent",
"Crew", "Crew",

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }] authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.13" requires-python = ">=3.10,<3.13"
dependencies = [ dependencies = [
"crewai[tools]>=0.86.0,<1.0.0" "crewai[tools]>=0.95.0,<1.0.0"
] ]
[project.scripts] [project.scripts]

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }] authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.13" requires-python = ">=3.10,<3.13"
dependencies = [ dependencies = [
"crewai[tools]>=0.86.0,<1.0.0", "crewai[tools]>=0.95.0,<1.0.0",
] ]
[project.scripts] [project.scripts]

View File

@@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10,<3.13" requires-python = ">=3.10,<3.13"
dependencies = [ dependencies = [
"crewai[tools]>=0.86.0" "crewai[tools]>=0.95.0"
] ]
[tool.crewai] [tool.crewai]

View File

@@ -4,6 +4,7 @@ import sys
import threading import threading
import warnings import warnings
from contextlib import contextmanager from contextlib import contextmanager
from importlib import resources
from typing import Any, Dict, List, Optional, Union from typing import Any, Dict, List, Optional, Union
with warnings.catch_warnings(): with warnings.catch_warnings():
@@ -78,6 +79,7 @@ CONTEXT_WINDOW_USAGE_RATIO = 0.75
def suppress_warnings(): def suppress_warnings():
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.filterwarnings("ignore") warnings.filterwarnings("ignore")
warnings.filterwarnings("ignore", message="open_text is deprecated*", category=DeprecationWarning)
# Redirect stdout and stderr # Redirect stdout and stderr
old_stdout = sys.stdout old_stdout = sys.stdout
@@ -216,16 +218,17 @@ class LLM:
return self.context_window_size return self.context_window_size
def set_callbacks(self, callbacks: List[Any]): def set_callbacks(self, callbacks: List[Any]):
callback_types = [type(callback) for callback in callbacks] with suppress_warnings():
for callback in litellm.success_callback[:]: callback_types = [type(callback) for callback in callbacks]
if type(callback) in callback_types: for callback in litellm.success_callback[:]:
litellm.success_callback.remove(callback) if type(callback) in callback_types:
litellm.success_callback.remove(callback)
for callback in litellm._async_success_callback[:]: for callback in litellm._async_success_callback[:]:
if type(callback) in callback_types: if type(callback) in callback_types:
litellm._async_success_callback.remove(callback) litellm._async_success_callback.remove(callback)
litellm.callbacks = callbacks litellm.callbacks = callbacks
def set_env_callbacks(self): def set_env_callbacks(self):
""" """
@@ -246,19 +249,20 @@ class LLM:
This will set `litellm.success_callback` to ["langfuse", "langsmith"] and This will set `litellm.success_callback` to ["langfuse", "langsmith"] and
`litellm.failure_callback` to ["langfuse"]. `litellm.failure_callback` to ["langfuse"].
""" """
success_callbacks_str = os.environ.get("LITELLM_SUCCESS_CALLBACKS", "") with suppress_warnings():
success_callbacks = [] success_callbacks_str = os.environ.get("LITELLM_SUCCESS_CALLBACKS", "")
if success_callbacks_str: success_callbacks = []
success_callbacks = [ if success_callbacks_str:
callback.strip() for callback in success_callbacks_str.split(",") success_callbacks = [
] callback.strip() for callback in success_callbacks_str.split(",")
]
failure_callbacks_str = os.environ.get("LITELLM_FAILURE_CALLBACKS", "") failure_callbacks_str = os.environ.get("LITELLM_FAILURE_CALLBACKS", "")
failure_callbacks = [] failure_callbacks = []
if failure_callbacks_str: if failure_callbacks_str:
failure_callbacks = [ failure_callbacks = [
callback.strip() for callback in failure_callbacks_str.split(",") callback.strip() for callback in failure_callbacks_str.split(",")
] ]
litellm.success_callback = success_callbacks litellm.success_callback = success_callbacks
litellm.failure_callback = failure_callbacks litellm.failure_callback = failure_callbacks

View File

@@ -1,12 +1,23 @@
import warnings
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from inspect import signature from inspect import signature
from typing import Any, Callable, Type, get_args, get_origin from typing import Any, Callable, Type, get_args, get_origin
from pydantic import BaseModel, ConfigDict, Field, create_model, validator from pydantic import (
BaseModel,
ConfigDict,
Field,
PydanticDeprecatedSince20,
create_model,
validator,
)
from pydantic import BaseModel as PydanticBaseModel from pydantic import BaseModel as PydanticBaseModel
from crewai.tools.structured_tool import CrewStructuredTool from crewai.tools.structured_tool import CrewStructuredTool
# Ignore all "PydanticDeprecatedSince20" warnings globally
warnings.filterwarnings("ignore", category=PydanticDeprecatedSince20)
class BaseTool(BaseModel, ABC): class BaseTool(BaseModel, ABC):
class _ArgsSchemaPlaceholder(PydanticBaseModel): class _ArgsSchemaPlaceholder(PydanticBaseModel):

View File

@@ -31,10 +31,10 @@ class InternalInstructor:
import instructor import instructor
from litellm import completion from litellm import completion
self._client = instructor.from_litellm( self._client = instructor.from_litellm(
completion, completion,
mode=instructor.Mode.TOOLS, mode=instructor.Mode.TOOLS,
) )
def to_json(self): def to_json(self):
model = self.to_pydantic() model = self.to_pydantic()

View File

@@ -7,7 +7,7 @@ from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.tools.base_tool import BaseTool from crewai.tools.base_tool import BaseTool
class TestAgent(BaseAgent): class MockAgent(BaseAgent):
def execute_task( def execute_task(
self, self,
task: Any, task: Any,
@@ -29,7 +29,7 @@ class TestAgent(BaseAgent):
def test_key(): def test_key():
agent = TestAgent( agent = MockAgent(
role="test role", role="test role",
goal="test goal", goal="test goal",
backstory="test backstory", backstory="test backstory",

View File

@@ -177,12 +177,12 @@ class TestDeployCommand(unittest.TestCase):
def test_get_crew_status(self): def test_get_crew_status(self):
mock_response = MagicMock() mock_response = MagicMock()
mock_response.status_code = 200 mock_response.status_code = 200
mock_response.json.return_value = {"name": "TestCrew", "status": "active"} mock_response.json.return_value = {"name": "InternalCrew", "status": "active"}
self.mock_client.crew_status_by_name.return_value = mock_response self.mock_client.crew_status_by_name.return_value = mock_response
with patch("sys.stdout", new=StringIO()) as fake_out: with patch("sys.stdout", new=StringIO()) as fake_out:
self.deploy_command.get_crew_status() self.deploy_command.get_crew_status()
self.assertIn("TestCrew", fake_out.getvalue()) self.assertIn("InternalCrew", fake_out.getvalue())
self.assertIn("active", fake_out.getvalue()) self.assertIn("active", fake_out.getvalue())
def test_get_crew_logs(self): def test_get_crew_logs(self):

View File

@@ -27,7 +27,7 @@ class SimpleCrew:
@CrewBase @CrewBase
class TestCrew: class InternalCrew:
agents_config = "config/agents.yaml" agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml" tasks_config = "config/tasks.yaml"
@@ -84,7 +84,7 @@ def test_task_memoization():
def test_crew_memoization(): def test_crew_memoization():
crew = TestCrew() crew = InternalCrew()
first_call_result = crew.crew() first_call_result = crew.crew()
second_call_result = crew.crew() second_call_result = crew.crew()
@@ -107,7 +107,7 @@ def test_task_name():
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])
def test_before_kickoff_modification(): def test_before_kickoff_modification():
crew = TestCrew() crew = InternalCrew()
inputs = {"topic": "LLMs"} inputs = {"topic": "LLMs"}
result = crew.crew().kickoff(inputs=inputs) result = crew.crew().kickoff(inputs=inputs)
assert "bicycles" in result.raw, "Before kickoff function did not modify inputs" assert "bicycles" in result.raw, "Before kickoff function did not modify inputs"
@@ -115,7 +115,7 @@ def test_before_kickoff_modification():
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])
def test_after_kickoff_modification(): def test_after_kickoff_modification():
crew = TestCrew() crew = InternalCrew()
# Assuming the crew execution returns a dict # Assuming the crew execution returns a dict
result = crew.crew().kickoff({"topic": "LLMs"}) result = crew.crew().kickoff({"topic": "LLMs"})
@@ -126,7 +126,7 @@ def test_after_kickoff_modification():
@pytest.mark.vcr(filter_headers=["authorization"]) @pytest.mark.vcr(filter_headers=["authorization"])
def test_before_kickoff_with_none_input(): def test_before_kickoff_with_none_input():
crew = TestCrew() crew = InternalCrew()
crew.crew().kickoff(None) crew.crew().kickoff(None)
# Test should pass without raising exceptions # Test should pass without raising exceptions

View File

@@ -6,7 +6,7 @@ from crewai import Agent, Task
from crewai.tools.agent_tools.base_agent_tools import BaseAgentTool from crewai.tools.agent_tools.base_agent_tools import BaseAgentTool
class TestAgentTool(BaseAgentTool): class InternalAgentTool(BaseAgentTool):
"""Concrete implementation of BaseAgentTool for testing.""" """Concrete implementation of BaseAgentTool for testing."""
def _run(self, *args, **kwargs): def _run(self, *args, **kwargs):
@@ -39,7 +39,7 @@ def test_agent_tool_role_matching(role_name, should_match):
) )
# Create test agent tool # Create test agent tool
agent_tool = TestAgentTool( agent_tool = InternalAgentTool(
name="test_tool", description="Test tool", agents=[test_agent] name="test_tool", description="Test tool", agents=[test_agent]
) )

View File

@@ -15,7 +15,7 @@ def test_creating_a_tool_using_annotation():
my_tool.description my_tool.description
== "Tool Name: Name of my tool\nTool Arguments: {'question': {'description': None, 'type': 'str'}}\nTool Description: Clear description for what this tool is useful for, your agent will need this information to use it." == "Tool Name: Name of my tool\nTool Arguments: {'question': {'description': None, 'type': 'str'}}\nTool Description: Clear description for what this tool is useful for, your agent will need this information to use it."
) )
assert my_tool.args_schema.schema()["properties"] == { assert my_tool.args_schema.model_json_schema()["properties"] == {
"question": {"title": "Question", "type": "string"} "question": {"title": "Question", "type": "string"}
} }
assert ( assert (
@@ -29,7 +29,7 @@ def test_creating_a_tool_using_annotation():
converted_tool.description converted_tool.description
== "Tool Name: Name of my tool\nTool Arguments: {'question': {'description': None, 'type': 'str'}}\nTool Description: Clear description for what this tool is useful for, your agent will need this information to use it." == "Tool Name: Name of my tool\nTool Arguments: {'question': {'description': None, 'type': 'str'}}\nTool Description: Clear description for what this tool is useful for, your agent will need this information to use it."
) )
assert converted_tool.args_schema.schema()["properties"] == { assert converted_tool.args_schema.model_json_schema()["properties"] == {
"question": {"title": "Question", "type": "string"} "question": {"title": "Question", "type": "string"}
} }
assert ( assert (
@@ -54,7 +54,7 @@ def test_creating_a_tool_using_baseclass():
my_tool.description my_tool.description
== "Tool Name: Name of my tool\nTool Arguments: {'question': {'description': None, 'type': 'str'}}\nTool Description: Clear description for what this tool is useful for, your agent will need this information to use it." == "Tool Name: Name of my tool\nTool Arguments: {'question': {'description': None, 'type': 'str'}}\nTool Description: Clear description for what this tool is useful for, your agent will need this information to use it."
) )
assert my_tool.args_schema.schema()["properties"] == { assert my_tool.args_schema.model_json_schema()["properties"] == {
"question": {"title": "Question", "type": "string"} "question": {"title": "Question", "type": "string"}
} }
assert my_tool.run("What is the meaning of life?") == "What is the meaning of life?" assert my_tool.run("What is the meaning of life?") == "What is the meaning of life?"
@@ -66,7 +66,7 @@ def test_creating_a_tool_using_baseclass():
converted_tool.description converted_tool.description
== "Tool Name: Name of my tool\nTool Arguments: {'question': {'description': None, 'type': 'str'}}\nTool Description: Clear description for what this tool is useful for, your agent will need this information to use it." == "Tool Name: Name of my tool\nTool Arguments: {'question': {'description': None, 'type': 'str'}}\nTool Description: Clear description for what this tool is useful for, your agent will need this information to use it."
) )
assert converted_tool.args_schema.schema()["properties"] == { assert converted_tool.args_schema.model_json_schema()["properties"] == {
"question": {"title": "Question", "type": "string"} "question": {"title": "Question", "type": "string"}
} }
assert ( assert (

View File

@@ -25,7 +25,7 @@ def schema_class():
return TestSchema return TestSchema
class TestCrewStructuredTool: class InternalCrewStructuredTool:
def test_initialization(self, basic_function, schema_class): def test_initialization(self, basic_function, schema_class):
"""Test basic initialization of CrewStructuredTool""" """Test basic initialization of CrewStructuredTool"""
tool = CrewStructuredTool( tool = CrewStructuredTool(

View File

@@ -12,7 +12,7 @@ from crewai.utilities.evaluators.crew_evaluator_handler import (
) )
class TestCrewEvaluator: class InternalCrewEvaluator:
@pytest.fixture @pytest.fixture
def crew_planner(self): def crew_planner(self):
agent = Agent(role="Agent 1", goal="Goal 1", backstory="Backstory 1") agent = Agent(role="Agent 1", goal="Goal 1", backstory="Backstory 1")

View File

@@ -16,7 +16,7 @@ from crewai.utilities.planning_handler import (
) )
class TestCrewPlanner: class InternalCrewPlanner:
@pytest.fixture @pytest.fixture
def crew_planner(self): def crew_planner(self):
tasks = [ tasks = [
@@ -115,13 +115,13 @@ class TestCrewPlanner:
def __init__(self, name: str, description: str): def __init__(self, name: str, description: str):
tool_data = {"name": name, "description": description} tool_data = {"name": name, "description": description}
super().__init__(**tool_data) super().__init__(**tool_data)
def __str__(self): def __str__(self):
return self.name return self.name
def __repr__(self): def __repr__(self):
return self.name return self.name
def to_structured_tool(self): def to_structured_tool(self):
return self return self
@@ -149,11 +149,11 @@ class TestCrewPlanner:
] ]
) )
) )
# Create planner with the new task # Create planner with the new task
planner = CrewPlanner([task], None) planner = CrewPlanner([task], None)
tasks_summary = planner._create_tasks_summary() tasks_summary = planner._create_tasks_summary()
# Verify task summary content # Verify task summary content
assert isinstance(tasks_summary, str) assert isinstance(tasks_summary, str)
assert task.description in tasks_summary assert task.description in tasks_summary

View File

@@ -4,7 +4,7 @@ import unittest
from crewai.utilities.training_handler import CrewTrainingHandler from crewai.utilities.training_handler import CrewTrainingHandler
class TestCrewTrainingHandler(unittest.TestCase): class InternalCrewTrainingHandler(unittest.TestCase):
def setUp(self): def setUp(self):
self.handler = CrewTrainingHandler("trained_data.pkl") self.handler = CrewTrainingHandler("trained_data.pkl")

2
uv.lock generated
View File

@@ -631,7 +631,7 @@ wheels = [
[[package]] [[package]]
name = "crewai" name = "crewai"
version = "0.86.0" version = "0.95.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "appdirs" }, { name = "appdirs" },