mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 16:18:30 +00:00
@@ -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"
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user