mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 08:08:32 +00:00
Merge pull request #15 from greysonlalonde/gl/devops/ci-code-formatting-enhancements
Update Python to 3.9, Add Code Quality Tools, & Update Lockfile
This commit is contained in:
21
.pre-commit-config.yaml
Normal file
21
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
repos:
|
||||||
|
|
||||||
|
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||||
|
rev: 23.12.1
|
||||||
|
hooks:
|
||||||
|
- id: black
|
||||||
|
language_version: python3.11
|
||||||
|
files: \.(py)$
|
||||||
|
|
||||||
|
- repo: https://github.com/pycqa/isort
|
||||||
|
rev: 5.13.2
|
||||||
|
hooks:
|
||||||
|
- id: isort
|
||||||
|
name: isort (python)
|
||||||
|
args: ["--profile", "black", "--filter-files"]
|
||||||
|
|
||||||
|
- repo: https://github.com/PyCQA/autoflake
|
||||||
|
rev: v2.2.1
|
||||||
|
hooks:
|
||||||
|
- id: autoflake
|
||||||
|
args: ['--in-place', '--remove-all-unused-imports', '--remove-unused-variables', '--ignore-init-module-imports']
|
||||||
@@ -144,6 +144,12 @@ poetry install
|
|||||||
poetry shell
|
poetry shell
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Pre-commit hooks
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pre-commit install
|
||||||
|
```
|
||||||
|
|
||||||
### Running Tests
|
### Running Tests
|
||||||
```bash
|
```bash
|
||||||
poetry run pytest
|
poetry run pytest
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from .task import Task
|
|
||||||
from .crew import Crew
|
|
||||||
from .agent import Agent
|
from .agent import Agent
|
||||||
from .process import Process
|
from .crew import Crew
|
||||||
|
from .process import Process
|
||||||
|
from .task import Task
|
||||||
|
|||||||
204
crewai/agent.py
204
crewai/agent.py
@@ -1,128 +1,120 @@
|
|||||||
"""Generic agent."""
|
"""Generic agent."""
|
||||||
|
|
||||||
from typing import List, Any, Optional
|
from typing import Any, List, Optional
|
||||||
from pydantic.v1 import BaseModel, PrivateAttr, Field, root_validator
|
|
||||||
|
|
||||||
from langchain.agents import AgentExecutor
|
from langchain.agents import AgentExecutor
|
||||||
from langchain.chat_models import ChatOpenAI
|
|
||||||
from langchain.tools.render import render_text_description
|
|
||||||
from langchain.agents.format_scratchpad import format_log_to_str
|
from langchain.agents.format_scratchpad import format_log_to_str
|
||||||
from langchain.agents.output_parsers import ReActSingleInputOutputParser
|
from langchain.agents.output_parsers import ReActSingleInputOutputParser
|
||||||
|
from langchain.chat_models import ChatOpenAI
|
||||||
from langchain.memory import ConversationSummaryMemory
|
from langchain.memory import ConversationSummaryMemory
|
||||||
|
from langchain.tools.render import render_text_description
|
||||||
|
from pydantic.v1 import BaseModel, Field, PrivateAttr, root_validator
|
||||||
|
|
||||||
from .prompts import Prompts
|
from .prompts import Prompts
|
||||||
|
|
||||||
|
|
||||||
class Agent(BaseModel):
|
class Agent(BaseModel):
|
||||||
"""
|
"""
|
||||||
Represents an agent in a system.
|
Represents an agent in a system.
|
||||||
|
|
||||||
Each agent has a role, a goal, a backstory, and an optional language model (llm).
|
Each agent has a role, a goal, a backstory, and an optional language model (llm).
|
||||||
The agent can also have memory, can operate in verbose mode, and can delegate tasks to other agents.
|
The agent can also have memory, can operate in verbose mode, and can delegate tasks to other agents.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
agent_executor: An instance of the AgentExecutor class.
|
agent_executor: An instance of the AgentExecutor class.
|
||||||
role: The role of the agent.
|
role: The role of the agent.
|
||||||
goal: The objective of the agent.
|
goal: The objective of the agent.
|
||||||
backstory: The backstory of the agent.
|
backstory: The backstory of the agent.
|
||||||
llm: The language model that will run the agent.
|
llm: The language model that will run the agent.
|
||||||
memory: Whether the agent should have memory or not.
|
memory: Whether the agent should have memory or not.
|
||||||
verbose: Whether the agent execution should be in verbose mode.
|
verbose: Whether the agent execution should be in verbose mode.
|
||||||
allow_delegation: Whether the agent is allowed to delegate tasks to other agents.
|
allow_delegation: Whether the agent is allowed to delegate tasks to other agents.
|
||||||
"""
|
"""
|
||||||
agent_executor: AgentExecutor = None
|
|
||||||
role: str = Field(description="Role of the agent")
|
|
||||||
goal: str = Field(description="Objective of the agent")
|
|
||||||
backstory: str = Field(description="Backstory of the agent")
|
|
||||||
llm: Optional[Any] = Field(description="LLM that will run the agent")
|
|
||||||
memory: bool = Field(
|
|
||||||
description="Whether the agent should have memory or not",
|
|
||||||
default=True
|
|
||||||
)
|
|
||||||
verbose: bool = Field(
|
|
||||||
description="Verbose mode for the Agent Execution",
|
|
||||||
default=False
|
|
||||||
)
|
|
||||||
allow_delegation: bool = Field(
|
|
||||||
description="Allow delegation of tasks to agents",
|
|
||||||
default=True
|
|
||||||
)
|
|
||||||
tools: List[Any] = Field(
|
|
||||||
description="Tools at agents disposal",
|
|
||||||
default=[]
|
|
||||||
)
|
|
||||||
_task_calls: List[Any] = PrivateAttr()
|
|
||||||
|
|
||||||
@root_validator(pre=True)
|
agent_executor: AgentExecutor = None
|
||||||
def check_llm(_cls, values):
|
role: str = Field(description="Role of the agent")
|
||||||
if not values.get('llm'):
|
goal: str = Field(description="Objective of the agent")
|
||||||
values['llm'] = ChatOpenAI(
|
backstory: str = Field(description="Backstory of the agent")
|
||||||
temperature=0.7,
|
llm: Optional[Any] = Field(description="LLM that will run the agent")
|
||||||
model_name="gpt-4"
|
memory: bool = Field(
|
||||||
)
|
description="Whether the agent should have memory or not", default=True
|
||||||
return values
|
)
|
||||||
|
verbose: bool = Field(
|
||||||
|
description="Verbose mode for the Agent Execution", default=False
|
||||||
|
)
|
||||||
|
allow_delegation: bool = Field(
|
||||||
|
description="Allow delegation of tasks to agents", default=True
|
||||||
|
)
|
||||||
|
tools: List[Any] = Field(description="Tools at agents disposal", default=[])
|
||||||
|
_task_calls: List[Any] = PrivateAttr()
|
||||||
|
|
||||||
def __init__(self, **data):
|
@root_validator(pre=True)
|
||||||
super().__init__(**data)
|
def check_llm(_cls, values):
|
||||||
agent_args = {
|
if not values.get("llm"):
|
||||||
"input": lambda x: x["input"],
|
values["llm"] = ChatOpenAI(temperature=0.7, model_name="gpt-4")
|
||||||
"tools": lambda x: x["tools"],
|
return values
|
||||||
"tool_names": lambda x: x["tool_names"],
|
|
||||||
"agent_scratchpad": lambda x: format_log_to_str(x['intermediate_steps']),
|
|
||||||
}
|
|
||||||
executor_args = {
|
|
||||||
"tools": self.tools,
|
|
||||||
"verbose": self.verbose,
|
|
||||||
"handle_parsing_errors": True,
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.memory:
|
def __init__(self, **data):
|
||||||
summary_memory = ConversationSummaryMemory(
|
super().__init__(**data)
|
||||||
llm=self.llm,
|
agent_args = {
|
||||||
memory_key='chat_history',
|
"input": lambda x: x["input"],
|
||||||
input_key="input"
|
"tools": lambda x: x["tools"],
|
||||||
)
|
"tool_names": lambda x: x["tool_names"],
|
||||||
executor_args['memory'] = summary_memory
|
"agent_scratchpad": lambda x: format_log_to_str(x["intermediate_steps"]),
|
||||||
agent_args['chat_history'] = lambda x: x["chat_history"]
|
}
|
||||||
prompt = Prompts.TASK_EXECUTION_WITH_MEMORY_PROMPT
|
executor_args = {
|
||||||
else:
|
"tools": self.tools,
|
||||||
prompt = Prompts.TASK_EXECUTION_PROMPT
|
"verbose": self.verbose,
|
||||||
|
"handle_parsing_errors": True,
|
||||||
|
}
|
||||||
|
|
||||||
execution_prompt = prompt.partial(
|
if self.memory:
|
||||||
goal=self.goal,
|
summary_memory = ConversationSummaryMemory(
|
||||||
role=self.role,
|
llm=self.llm, memory_key="chat_history", input_key="input"
|
||||||
backstory=self.backstory,
|
)
|
||||||
)
|
executor_args["memory"] = summary_memory
|
||||||
|
agent_args["chat_history"] = lambda x: x["chat_history"]
|
||||||
|
prompt = Prompts.TASK_EXECUTION_WITH_MEMORY_PROMPT
|
||||||
|
else:
|
||||||
|
prompt = Prompts.TASK_EXECUTION_PROMPT
|
||||||
|
|
||||||
bind = self.llm.bind(stop=["\nObservation"])
|
execution_prompt = prompt.partial(
|
||||||
inner_agent = agent_args | execution_prompt | bind | ReActSingleInputOutputParser()
|
goal=self.goal,
|
||||||
|
role=self.role,
|
||||||
|
backstory=self.backstory,
|
||||||
|
)
|
||||||
|
|
||||||
self.agent_executor = AgentExecutor(
|
bind = self.llm.bind(stop=["\nObservation"])
|
||||||
agent=inner_agent,
|
inner_agent = (
|
||||||
**executor_args
|
agent_args | execution_prompt | bind | ReActSingleInputOutputParser()
|
||||||
)
|
)
|
||||||
|
|
||||||
def execute_task(self, task: str, context: str = None, tools: List[Any] = None) -> str:
|
self.agent_executor = AgentExecutor(agent=inner_agent, **executor_args)
|
||||||
"""
|
|
||||||
Execute a task with the agent.
|
|
||||||
Parameters:
|
|
||||||
task (str): Task to execute
|
|
||||||
Returns:
|
|
||||||
output (str): Output of the agent
|
|
||||||
"""
|
|
||||||
if context:
|
|
||||||
task = "\n".join([
|
|
||||||
task,
|
|
||||||
"\nThis is the context you are working with:",
|
|
||||||
context
|
|
||||||
])
|
|
||||||
|
|
||||||
tools = tools or self.tools
|
def execute_task(
|
||||||
self.agent_executor.tools = tools
|
self, task: str, context: str = None, tools: List[Any] = None
|
||||||
return self.agent_executor.invoke({
|
) -> str:
|
||||||
"input": task,
|
"""
|
||||||
"tool_names": self.__tools_names(tools),
|
Execute a task with the agent.
|
||||||
"tools": render_text_description(tools),
|
Parameters:
|
||||||
})['output']
|
task (str): Task to execute
|
||||||
|
Returns:
|
||||||
|
output (str): Output of the agent
|
||||||
|
"""
|
||||||
|
if context:
|
||||||
|
task = "\n".join(
|
||||||
|
[task, "\nThis is the context you are working with:", context]
|
||||||
|
)
|
||||||
|
|
||||||
def __tools_names(self, tools) -> str:
|
tools = tools or self.tools
|
||||||
return ", ".join([t.name for t in tools])
|
self.agent_executor.tools = tools
|
||||||
|
return self.agent_executor.invoke(
|
||||||
|
{
|
||||||
|
"input": task,
|
||||||
|
"tool_names": self.__tools_names(tools),
|
||||||
|
"tools": render_text_description(tools),
|
||||||
|
}
|
||||||
|
)["output"]
|
||||||
|
|
||||||
|
def __tools_names(self, tools) -> str:
|
||||||
|
return ", ".join([t.name for t in tools])
|
||||||
|
|||||||
147
crewai/crew.py
147
crewai/crew.py
@@ -1,89 +1,88 @@
|
|||||||
import json
|
import json
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pydantic.v1 import BaseModel, Field, Json, root_validator
|
from pydantic.v1 import BaseModel, Field, Json, root_validator
|
||||||
|
|
||||||
from .process import Process
|
|
||||||
from .agent import Agent
|
from .agent import Agent
|
||||||
|
from .process import Process
|
||||||
from .task import Task
|
from .task import Task
|
||||||
from .tools.agent_tools import AgentTools
|
from .tools.agent_tools import AgentTools
|
||||||
|
|
||||||
|
|
||||||
class Crew(BaseModel):
|
class Crew(BaseModel):
|
||||||
"""
|
"""
|
||||||
Class that represents a group of agents, how they should work together and
|
Class that represents a group of agents, how they should work together and
|
||||||
their tasks.
|
their tasks.
|
||||||
"""
|
"""
|
||||||
tasks: Optional[List[Task]] = Field(description="List of tasks")
|
|
||||||
agents: Optional[List[Agent]] = Field(description="List of agents in this crew.")
|
|
||||||
process: Process = Field(
|
|
||||||
description="Process that the crew will follow.",
|
|
||||||
default=Process.sequential
|
|
||||||
)
|
|
||||||
verbose: bool = Field(
|
|
||||||
description="Verbose mode for the Agent Execution",
|
|
||||||
default=False
|
|
||||||
)
|
|
||||||
config: Optional[Json] = Field(
|
|
||||||
description="Configuration of the crew.",
|
|
||||||
default=None
|
|
||||||
)
|
|
||||||
|
|
||||||
@root_validator(pre=True)
|
tasks: Optional[List[Task]] = Field(description="List of tasks")
|
||||||
def check_config(_cls, values):
|
agents: Optional[List[Agent]] = Field(description="List of agents in this crew.")
|
||||||
if (
|
process: Process = Field(
|
||||||
not values.get('config')
|
description="Process that the crew will follow.", default=Process.sequential
|
||||||
and (
|
)
|
||||||
not values.get('agents') and not values.get('tasks')
|
verbose: bool = Field(
|
||||||
)
|
description="Verbose mode for the Agent Execution", default=False
|
||||||
):
|
)
|
||||||
raise ValueError('Either agents and task need to be set or config.')
|
config: Optional[Json] = Field(
|
||||||
|
description="Configuration of the crew.", default=None
|
||||||
if values.get('config'):
|
)
|
||||||
config = json.loads(values.get('config'))
|
|
||||||
if not config.get('agents') or not config.get('tasks'):
|
|
||||||
raise ValueError('Config should have agents and tasks.')
|
|
||||||
|
|
||||||
values['agents'] = [Agent(**agent) for agent in config['agents']]
|
|
||||||
|
|
||||||
tasks = []
|
|
||||||
for task in config['tasks']:
|
|
||||||
task_agent = [agt for agt in values['agents'] if agt.role == task['agent']][0]
|
|
||||||
del task['agent']
|
|
||||||
tasks.append(Task(**task, agent=task_agent))
|
|
||||||
|
|
||||||
values['tasks'] = tasks
|
|
||||||
return values
|
|
||||||
|
|
||||||
def kickoff(self) -> str:
|
@root_validator(pre=True)
|
||||||
"""
|
def check_config(_cls, values):
|
||||||
Kickoff the crew to work on it's tasks.
|
if not values.get("config") and (
|
||||||
Returns:
|
not values.get("agents") and not values.get("tasks")
|
||||||
output (List[str]): Output of the crew for each task.
|
):
|
||||||
"""
|
raise ValueError("Either agents and task need to be set or config.")
|
||||||
if self.process == Process.sequential:
|
|
||||||
return self.__sequential_loop()
|
|
||||||
|
|
||||||
def __sequential_loop(self) -> str:
|
if values.get("config"):
|
||||||
"""
|
config = json.loads(values.get("config"))
|
||||||
Loop that executes the sequential process.
|
if not config.get("agents") or not config.get("tasks"):
|
||||||
Returns:
|
raise ValueError("Config should have agents and tasks.")
|
||||||
output (str): Output of the crew.
|
|
||||||
"""
|
|
||||||
task_outcome = None
|
|
||||||
for task in self.tasks:
|
|
||||||
# Add delegation tools to the task if the agent allows it
|
|
||||||
if task.agent.allow_delegation:
|
|
||||||
tools = AgentTools(agents=self.agents).tools()
|
|
||||||
task.tools += tools
|
|
||||||
|
|
||||||
self.__log(f"\nWorking Agent: {task.agent.role}")
|
values["agents"] = [Agent(**agent) for agent in config["agents"]]
|
||||||
self.__log(f"Starting Task: {task.description} ...")
|
|
||||||
|
|
||||||
task_outcome = task.execute(task_outcome)
|
tasks = []
|
||||||
|
for task in config["tasks"]:
|
||||||
|
task_agent = [
|
||||||
|
agt for agt in values["agents"] if agt.role == task["agent"]
|
||||||
|
][0]
|
||||||
|
del task["agent"]
|
||||||
|
tasks.append(Task(**task, agent=task_agent))
|
||||||
|
|
||||||
self.__log(f"Task output: {task_outcome}")
|
values["tasks"] = tasks
|
||||||
|
return values
|
||||||
return task_outcome
|
|
||||||
|
def kickoff(self) -> str:
|
||||||
def __log(self, message):
|
"""
|
||||||
if self.verbose:
|
Kickoff the crew to work on it's tasks.
|
||||||
print(message)
|
Returns:
|
||||||
|
output (List[str]): Output of the crew for each task.
|
||||||
|
"""
|
||||||
|
if self.process == Process.sequential:
|
||||||
|
return self.__sequential_loop()
|
||||||
|
|
||||||
|
def __sequential_loop(self) -> str:
|
||||||
|
"""
|
||||||
|
Loop that executes the sequential process.
|
||||||
|
Returns:
|
||||||
|
output (str): Output of the crew.
|
||||||
|
"""
|
||||||
|
task_outcome = None
|
||||||
|
for task in self.tasks:
|
||||||
|
# Add delegation tools to the task if the agent allows it
|
||||||
|
if task.agent.allow_delegation:
|
||||||
|
tools = AgentTools(agents=self.agents).tools()
|
||||||
|
task.tools += tools
|
||||||
|
|
||||||
|
self.__log(f"\nWorking Agent: {task.agent.role}")
|
||||||
|
self.__log(f"Starting Task: {task.description} ...")
|
||||||
|
|
||||||
|
task_outcome = task.execute(task_outcome)
|
||||||
|
|
||||||
|
self.__log(f"Task output: {task_outcome}")
|
||||||
|
|
||||||
|
return task_outcome
|
||||||
|
|
||||||
|
def __log(self, message):
|
||||||
|
if self.verbose:
|
||||||
|
print(message)
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class Process(str, Enum):
|
class Process(str, Enum):
|
||||||
"""
|
"""
|
||||||
Class representing the different processes that can be used to tackle tasks
|
Class representing the different processes that can be used to tackle tasks
|
||||||
"""
|
"""
|
||||||
sequential = 'sequential'
|
|
||||||
# TODO: consensual = 'consensual'
|
sequential = "sequential"
|
||||||
# TODO: hierarchical = 'hierarchical'
|
# TODO: consensual = 'consensual'
|
||||||
|
# TODO: hierarchical = 'hierarchical'
|
||||||
|
|||||||
@@ -2,32 +2,41 @@
|
|||||||
|
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from typing import ClassVar
|
from typing import ClassVar
|
||||||
from pydantic.v1 import BaseModel
|
|
||||||
from langchain.prompts import PromptTemplate
|
from langchain.prompts import PromptTemplate
|
||||||
|
from pydantic.v1 import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class Prompts(BaseModel):
|
class Prompts(BaseModel):
|
||||||
"""Prompts for generic agent."""
|
"""Prompts for generic agent."""
|
||||||
|
|
||||||
TASK_SLICE: ClassVar[str] = dedent("""\
|
TASK_SLICE: ClassVar[str] = dedent(
|
||||||
|
"""\
|
||||||
Begin! This is VERY important to you, your job depends on it!
|
Begin! This is VERY important to you, your job depends on it!
|
||||||
|
|
||||||
Current Task: {input}
|
Current Task: {input}
|
||||||
{agent_scratchpad}
|
{agent_scratchpad}
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
MEMORY_SLICE: ClassVar[str] = dedent("""\
|
MEMORY_SLICE: ClassVar[str] = dedent(
|
||||||
|
"""\
|
||||||
This is the summary of your work so far:
|
This is the summary of your work so far:
|
||||||
{chat_history}
|
{chat_history}
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
ROLE_PLAYING_SLICE: ClassVar[str] = dedent("""\
|
ROLE_PLAYING_SLICE: ClassVar[str] = dedent(
|
||||||
|
"""\
|
||||||
You are {role}.
|
You are {role}.
|
||||||
{backstory}
|
{backstory}
|
||||||
|
|
||||||
Your personal goal is: {goal}
|
Your personal goal is: {goal}
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
TOOLS_SLICE: ClassVar[str] = dedent("""\
|
TOOLS_SLICE: ClassVar[str] = dedent(
|
||||||
|
"""\
|
||||||
|
|
||||||
TOOLS:
|
TOOLS:
|
||||||
------
|
------
|
||||||
@@ -50,9 +59,11 @@ class Prompts(BaseModel):
|
|||||||
Thought: Do I need to use a tool? No
|
Thought: Do I need to use a tool? No
|
||||||
Final Answer: [your response here]
|
Final Answer: [your response here]
|
||||||
```
|
```
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
VOTING_SLICE: ClassVar[str] = dedent("""\
|
VOTING_SLICE: ClassVar[str] = dedent(
|
||||||
|
"""\
|
||||||
You are working on a crew with your co-workers and need to decide who will execute the task.
|
You are working on a crew with your co-workers and need to decide who will execute the task.
|
||||||
|
|
||||||
These are your format instructions:
|
These are your format instructions:
|
||||||
@@ -60,16 +71,17 @@ class Prompts(BaseModel):
|
|||||||
|
|
||||||
These are your co-workers and their roles:
|
These are your co-workers and their roles:
|
||||||
{coworkers}
|
{coworkers}
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
TASK_EXECUTION_WITH_MEMORY_PROMPT: ClassVar[str] = PromptTemplate.from_template(
|
TASK_EXECUTION_WITH_MEMORY_PROMPT: ClassVar[str] = PromptTemplate.from_template(
|
||||||
ROLE_PLAYING_SLICE + TOOLS_SLICE + MEMORY_SLICE + TASK_SLICE
|
ROLE_PLAYING_SLICE + TOOLS_SLICE + MEMORY_SLICE + TASK_SLICE
|
||||||
)
|
)
|
||||||
|
|
||||||
TASK_EXECUTION_PROMPT: ClassVar[str] = PromptTemplate.from_template(
|
TASK_EXECUTION_PROMPT: ClassVar[str] = PromptTemplate.from_template(
|
||||||
ROLE_PLAYING_SLICE + TOOLS_SLICE + TASK_SLICE
|
ROLE_PLAYING_SLICE + TOOLS_SLICE + TASK_SLICE
|
||||||
)
|
)
|
||||||
|
|
||||||
CONSENSUNS_VOTING_PROMPT: ClassVar[str] = PromptTemplate.from_template(
|
CONSENSUNS_VOTING_PROMPT: ClassVar[str] = PromptTemplate.from_template(
|
||||||
ROLE_PLAYING_SLICE + VOTING_SLICE + TASK_SLICE
|
ROLE_PLAYING_SLICE + VOTING_SLICE + TASK_SLICE
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,42 +1,41 @@
|
|||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from pydantic.v1 import BaseModel, Field, root_validator
|
|
||||||
|
|
||||||
from langchain.tools import Tool
|
from langchain.tools import Tool
|
||||||
|
from pydantic.v1 import BaseModel, Field, root_validator
|
||||||
|
|
||||||
from .agent import Agent
|
from .agent import Agent
|
||||||
|
|
||||||
|
|
||||||
class Task(BaseModel):
|
class Task(BaseModel):
|
||||||
"""
|
"""
|
||||||
Class that represent a task to be executed.
|
Class that represent a task to be executed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
description: str = Field(description="Description of the actual task.")
|
|
||||||
agent: Optional[Agent] = Field(
|
|
||||||
description="Agent responsible for the task.",
|
|
||||||
default=None
|
|
||||||
)
|
|
||||||
tools: Optional[List[Tool]] = Field(
|
|
||||||
description="Tools the agent are limited to use for this task.",
|
|
||||||
default=[]
|
|
||||||
)
|
|
||||||
|
|
||||||
@root_validator(pre=False)
|
description: str = Field(description="Description of the actual task.")
|
||||||
def _set_tools(_cls, values):
|
agent: Optional[Agent] = Field(
|
||||||
if (values.get('agent')) and not (values.get('tools')):
|
description="Agent responsible for the task.", default=None
|
||||||
values['tools'] = values.get('agent').tools
|
)
|
||||||
return values
|
tools: Optional[List[Tool]] = Field(
|
||||||
|
description="Tools the agent are limited to use for this task.", default=[]
|
||||||
|
)
|
||||||
|
|
||||||
def execute(self, context: str = None) -> str:
|
@root_validator(pre=False)
|
||||||
"""
|
def _set_tools(_cls, values):
|
||||||
Execute the task.
|
if (values.get("agent")) and not (values.get("tools")):
|
||||||
Returns:
|
values["tools"] = values.get("agent").tools
|
||||||
output (str): Output of the task.
|
return values
|
||||||
"""
|
|
||||||
if self.agent:
|
def execute(self, context: str = None) -> str:
|
||||||
return self.agent.execute_task(
|
"""
|
||||||
task = self.description,
|
Execute the task.
|
||||||
context = context,
|
Returns:
|
||||||
tools = self.tools
|
output (str): Output of the task.
|
||||||
)
|
"""
|
||||||
else:
|
if self.agent:
|
||||||
raise Exception(f"The task '{self.description}' has no agent assigned, therefore it can't be executed directly and should be executed in a Crew using a specific process that support that, either consensual or hierarchical.")
|
return self.agent.execute_task(
|
||||||
|
task=self.description, context=context, tools=self.tools
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise Exception(
|
||||||
|
f"The task '{self.description}' has no agent assigned, therefore it can't be executed directly and should be executed in a Crew using a specific process that support that, either consensual or hierarchical."
|
||||||
|
)
|
||||||
|
|||||||
0
crewai/tools/__init__.py
Normal file
0
crewai/tools/__init__.py
Normal file
@@ -1,61 +1,74 @@
|
|||||||
from typing import List, Any
|
|
||||||
from pydantic.v1 import BaseModel, Field
|
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from langchain.tools import Tool
|
from langchain.tools import Tool
|
||||||
|
from pydantic.v1 import BaseModel, Field
|
||||||
|
|
||||||
from ..agent import Agent
|
from ..agent import Agent
|
||||||
|
|
||||||
class AgentTools(BaseModel):
|
|
||||||
"""Tools for generic agent."""
|
|
||||||
agents: List[Agent] = Field(description="List of agents in this crew.")
|
|
||||||
|
|
||||||
def tools(self):
|
class AgentTools(BaseModel):
|
||||||
return [
|
"""Tools for generic agent."""
|
||||||
Tool.from_function(
|
|
||||||
func=self.delegate_work,
|
agents: List[Agent] = Field(description="List of agents in this crew.")
|
||||||
name="Delegate Work to Co-Worker",
|
|
||||||
description=dedent(f"""Useful to delegate a specific task to one of the
|
def tools(self):
|
||||||
|
return [
|
||||||
|
Tool.from_function(
|
||||||
|
func=self.delegate_work,
|
||||||
|
name="Delegate Work to Co-Worker",
|
||||||
|
description=dedent(
|
||||||
|
f"""Useful to delegate a specific task to one of the
|
||||||
following co-workers: [{', '.join([agent.role for agent in self.agents])}].
|
following co-workers: [{', '.join([agent.role for agent in self.agents])}].
|
||||||
The input to this tool should be a pipe (|) separated text of length
|
The input to this tool should be a pipe (|) separated text of length
|
||||||
three, representing the role you want to delegate it to, the task and
|
three, representing the role you want to delegate it to, the task and
|
||||||
information necessary. For example, `coworker|task|information`.
|
information necessary. For example, `coworker|task|information`.
|
||||||
""")
|
"""
|
||||||
),
|
),
|
||||||
Tool.from_function(
|
),
|
||||||
func=self.ask_question,
|
Tool.from_function(
|
||||||
name="Ask Question to Co-Worker",
|
func=self.ask_question,
|
||||||
description=dedent(f"""Useful to ask a question, opinion or take from on
|
name="Ask Question to Co-Worker",
|
||||||
|
description=dedent(
|
||||||
|
f"""Useful to ask a question, opinion or take from on
|
||||||
of the following co-workers: [{', '.join([agent.role for agent in self.agents])}].
|
of the following co-workers: [{', '.join([agent.role for agent in self.agents])}].
|
||||||
The input to this tool should be a pipe (|) separated text of length
|
The input to this tool should be a pipe (|) separated text of length
|
||||||
three, representing the role you want to ask it to, the question and
|
three, representing the role you want to ask it to, the question and
|
||||||
information necessary. For example, `coworker|question|information`.
|
information necessary. For example, `coworker|question|information`.
|
||||||
""")
|
"""
|
||||||
),
|
),
|
||||||
]
|
),
|
||||||
|
]
|
||||||
|
|
||||||
def delegate_work(self, command):
|
def delegate_work(self, command):
|
||||||
"""Useful to delegate a specific task to a coworker."""
|
"""Useful to delegate a specific task to a coworker."""
|
||||||
return self.__execute(command)
|
return self.__execute(command)
|
||||||
|
|
||||||
def ask_question(self, command):
|
def ask_question(self, command):
|
||||||
"""Useful to ask a question, opinion or take from a coworker."""
|
"""Useful to ask a question, opinion or take from a coworker."""
|
||||||
return self.__execute(command)
|
return self.__execute(command)
|
||||||
|
|
||||||
def __execute(self, command):
|
def __execute(self, command):
|
||||||
"""Execute the command."""
|
"""Execute the command."""
|
||||||
try:
|
try:
|
||||||
agent, task, information = command.split("|")
|
agent, task, information = command.split("|")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return "Error executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`."
|
return "Error executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`."
|
||||||
|
|
||||||
if not agent or not task or not information:
|
if not agent or not task or not information:
|
||||||
return "Error executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|question|information`."
|
return "Error executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|question|information`."
|
||||||
|
|
||||||
agent = [available_agent for available_agent in self.agents if available_agent.role == agent]
|
agent = [
|
||||||
|
available_agent
|
||||||
|
for available_agent in self.agents
|
||||||
|
if available_agent.role == agent
|
||||||
|
]
|
||||||
|
|
||||||
if len(agent) == 0:
|
if len(agent) == 0:
|
||||||
return "Error executing tool. Co-worker not found, double check the co-worker."
|
return (
|
||||||
|
"Error executing tool. Co-worker not found, double check the co-worker."
|
||||||
|
)
|
||||||
|
|
||||||
agent = agent[0]
|
agent = agent[0]
|
||||||
result = agent.execute_task(task, information)
|
result = agent.execute_task(task, information)
|
||||||
return result
|
return result
|
||||||
|
|||||||
321
poetry.lock
generated
321
poetry.lock
generated
@@ -121,9 +121,6 @@ files = [
|
|||||||
{file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"},
|
{file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""}
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.2.0"
|
version = "4.2.0"
|
||||||
@@ -175,6 +172,67 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-
|
|||||||
tests = ["attrs[tests-no-zope]", "zope-interface"]
|
tests = ["attrs[tests-no-zope]", "zope-interface"]
|
||||||
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autoflake"
|
||||||
|
version = "2.2.1"
|
||||||
|
description = "Removes unused imports and unused variables"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "autoflake-2.2.1-py3-none-any.whl", hash = "sha256:265cde0a43c1f44ecfb4f30d95b0437796759d07be7706a2f70e4719234c0f79"},
|
||||||
|
{file = "autoflake-2.2.1.tar.gz", hash = "sha256:62b7b6449a692c3c9b0c916919bbc21648da7281e8506bcf8d3f8280e431ebc1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pyflakes = ">=3.0.0"
|
||||||
|
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "black"
|
||||||
|
version = "23.12.1"
|
||||||
|
description = "The uncompromising code formatter."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"},
|
||||||
|
{file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"},
|
||||||
|
{file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"},
|
||||||
|
{file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"},
|
||||||
|
{file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"},
|
||||||
|
{file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"},
|
||||||
|
{file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"},
|
||||||
|
{file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"},
|
||||||
|
{file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"},
|
||||||
|
{file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"},
|
||||||
|
{file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"},
|
||||||
|
{file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"},
|
||||||
|
{file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"},
|
||||||
|
{file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"},
|
||||||
|
{file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"},
|
||||||
|
{file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"},
|
||||||
|
{file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"},
|
||||||
|
{file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"},
|
||||||
|
{file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"},
|
||||||
|
{file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"},
|
||||||
|
{file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"},
|
||||||
|
{file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
click = ">=8.0.0"
|
||||||
|
mypy-extensions = ">=0.4.3"
|
||||||
|
packaging = ">=22.0"
|
||||||
|
pathspec = ">=0.9.0"
|
||||||
|
platformdirs = ">=2"
|
||||||
|
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||||
|
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
colorama = ["colorama (>=0.4.3)"]
|
||||||
|
d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
|
||||||
|
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||||
|
uvloop = ["uvloop (>=0.15.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2023.11.17"
|
version = "2023.11.17"
|
||||||
@@ -186,6 +244,17 @@ files = [
|
|||||||
{file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
|
{file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfgv"
|
||||||
|
version = "3.4.0"
|
||||||
|
description = "Validate configuration and produce human readable error messages."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
|
||||||
|
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "charset-normalizer"
|
name = "charset-normalizer"
|
||||||
version = "3.3.2"
|
version = "3.3.2"
|
||||||
@@ -285,6 +354,20 @@ files = [
|
|||||||
{file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
|
{file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.1.7"
|
||||||
|
description = "Composable command line interface toolkit"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||||
|
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@@ -311,6 +394,17 @@ files = [
|
|||||||
marshmallow = ">=3.18.0,<4.0.0"
|
marshmallow = ">=3.18.0,<4.0.0"
|
||||||
typing-inspect = ">=0.4.0,<1"
|
typing-inspect = ">=0.4.0,<1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "distlib"
|
||||||
|
version = "0.3.8"
|
||||||
|
description = "Distribution utilities"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
|
||||||
|
{file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "distro"
|
name = "distro"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@@ -336,6 +430,22 @@ files = [
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
test = ["pytest (>=6)"]
|
test = ["pytest (>=6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "filelock"
|
||||||
|
version = "3.13.1"
|
||||||
|
description = "A platform independent file lock."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"},
|
||||||
|
{file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"]
|
||||||
|
testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
|
||||||
|
typing = ["typing-extensions (>=4.8)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frozenlist"
|
name = "frozenlist"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@@ -549,6 +659,20 @@ cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
|
|||||||
http2 = ["h2 (>=3,<5)"]
|
http2 = ["h2 (>=3,<5)"]
|
||||||
socks = ["socksio (==1.*)"]
|
socks = ["socksio (==1.*)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "identify"
|
||||||
|
version = "2.5.33"
|
||||||
|
description = "File identification library for Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"},
|
||||||
|
{file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
license = ["ukkonen"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.6"
|
version = "3.6"
|
||||||
@@ -571,6 +695,20 @@ files = [
|
|||||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "isort"
|
||||||
|
version = "5.13.2"
|
||||||
|
description = "A Python utility / library to sort Python imports."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8.0"
|
||||||
|
files = [
|
||||||
|
{file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
|
||||||
|
{file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
colors = ["colorama (>=0.4.6)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonpatch"
|
name = "jsonpatch"
|
||||||
version = "1.33"
|
version = "1.33"
|
||||||
@@ -815,41 +953,63 @@ files = [
|
|||||||
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nodeenv"
|
||||||
|
version = "1.8.0"
|
||||||
|
description = "Node.js virtual environment builder"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
|
||||||
|
files = [
|
||||||
|
{file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"},
|
||||||
|
{file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
setuptools = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "1.24.4"
|
version = "1.26.2"
|
||||||
description = "Fundamental package for array computing in Python"
|
description = "Fundamental package for array computing in Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"},
|
{file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"},
|
||||||
{file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"},
|
{file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"},
|
||||||
{file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"},
|
{file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"},
|
||||||
{file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"},
|
{file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"},
|
||||||
{file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"},
|
{file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"},
|
||||||
{file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"},
|
{file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"},
|
||||||
{file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"},
|
{file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"},
|
||||||
{file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"},
|
{file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"},
|
||||||
{file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"},
|
{file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"},
|
||||||
{file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"},
|
{file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"},
|
||||||
{file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"},
|
{file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"},
|
||||||
{file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"},
|
{file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"},
|
||||||
{file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"},
|
{file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"},
|
||||||
{file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"},
|
{file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"},
|
||||||
{file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"},
|
{file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"},
|
||||||
{file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"},
|
{file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"},
|
||||||
{file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"},
|
{file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"},
|
||||||
{file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"},
|
{file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"},
|
||||||
{file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"},
|
{file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"},
|
||||||
{file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"},
|
{file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"},
|
||||||
{file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"},
|
{file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"},
|
||||||
{file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"},
|
{file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"},
|
||||||
{file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"},
|
{file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"},
|
||||||
{file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"},
|
{file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"},
|
||||||
{file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"},
|
{file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"},
|
||||||
{file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"},
|
{file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"},
|
||||||
{file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"},
|
{file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"},
|
||||||
{file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"},
|
{file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"},
|
||||||
|
{file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"},
|
||||||
|
{file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"},
|
||||||
|
{file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"},
|
||||||
|
{file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"},
|
||||||
|
{file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"},
|
||||||
|
{file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"},
|
||||||
|
{file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"},
|
||||||
|
{file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -886,6 +1046,32 @@ files = [
|
|||||||
{file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
|
{file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pathspec"
|
||||||
|
version = "0.12.1"
|
||||||
|
description = "Utility library for gitignore style pattern matching of file paths."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
|
||||||
|
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "platformdirs"
|
||||||
|
version = "4.1.0"
|
||||||
|
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"},
|
||||||
|
{file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
|
||||||
|
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pluggy"
|
name = "pluggy"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -901,6 +1087,24 @@ files = [
|
|||||||
dev = ["pre-commit", "tox"]
|
dev = ["pre-commit", "tox"]
|
||||||
testing = ["pytest", "pytest-benchmark"]
|
testing = ["pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pre-commit"
|
||||||
|
version = "3.6.0"
|
||||||
|
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
files = [
|
||||||
|
{file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"},
|
||||||
|
{file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
cfgv = ">=2.0.0"
|
||||||
|
identify = ">=1.0.0"
|
||||||
|
nodeenv = ">=0.11.1"
|
||||||
|
pyyaml = ">=5.1"
|
||||||
|
virtualenv = ">=20.10.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.5.3"
|
version = "2.5.3"
|
||||||
@@ -1037,6 +1241,17 @@ files = [
|
|||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyflakes"
|
||||||
|
version = "3.1.0"
|
||||||
|
description = "passive checker of Python programs"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"},
|
||||||
|
{file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest"
|
name = "pytest"
|
||||||
version = "7.4.3"
|
version = "7.4.3"
|
||||||
@@ -1168,6 +1383,22 @@ urllib3 = ">=1.21.1,<3"
|
|||||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "setuptools"
|
||||||
|
version = "69.0.3"
|
||||||
|
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"},
|
||||||
|
{file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
||||||
|
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||||
|
testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sniffio"
|
name = "sniffio"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -1370,6 +1601,26 @@ urllib3 = {version = "<2", markers = "python_version < \"3.10\""}
|
|||||||
wrapt = "*"
|
wrapt = "*"
|
||||||
yarl = "*"
|
yarl = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "virtualenv"
|
||||||
|
version = "20.25.0"
|
||||||
|
description = "Virtual Python Environment builder"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"},
|
||||||
|
{file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
distlib = ">=0.3.7,<1"
|
||||||
|
filelock = ">=3.12.2,<4"
|
||||||
|
platformdirs = ">=3.9.1,<5"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
||||||
|
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wrapt"
|
name = "wrapt"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@@ -1554,5 +1805,5 @@ multidict = ">=4.0"
|
|||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.8.1,<4.0"
|
python-versions = ">=3.9,<4.0"
|
||||||
content-hash = "d4b313f67f1942e153e515c12288b3252f955e1ebf75b4b7b28aa0c0f9dd4bd7"
|
content-hash = "6518523eef59e35f89783fbdd92ff6f06a5a1b0d32c3d4241b5cce9713c84e47"
|
||||||
|
|||||||
@@ -12,11 +12,20 @@ Documentation = "https://github.com/joaomdmoura/CrewAI/wiki/Index"
|
|||||||
Repository = "https://github.com/joaomdmoura/crewai"
|
Repository = "https://github.com/joaomdmoura/crewai"
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = ">=3.8.1,<4.0"
|
python = ">=3.9,<4.0"
|
||||||
pydantic = "^2.4.2"
|
pydantic = "^2.4.2"
|
||||||
langchain = "^0.0.351"
|
langchain = "^0.0.351"
|
||||||
openai = "^1.5.0"
|
openai = "^1.5.0"
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
isort = "^5.13.2"
|
||||||
|
black = "^23.12.1"
|
||||||
|
autoflake = "^2.2.1"
|
||||||
|
pre-commit = "^3.6.0"
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
|
||||||
[tool.poetry.group.test.dependencies]
|
[tool.poetry.group.test.dependencies]
|
||||||
pytest = "^7.4"
|
pytest = "^7.4"
|
||||||
pytest-vcr = "^1.0.2"
|
pytest-vcr = "^1.0.2"
|
||||||
|
|||||||
@@ -1,139 +1,125 @@
|
|||||||
"""Test Agent creation and execution basic functionality."""
|
"""Test Agent creation and execution basic functionality."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from langchain.chat_models import ChatOpenAI as OpenAI
|
from langchain.chat_models import ChatOpenAI as OpenAI
|
||||||
|
|
||||||
from ..crewai import Agent
|
from ..crewai import Agent
|
||||||
|
|
||||||
def test_agent_creation():
|
|
||||||
agent = Agent(
|
|
||||||
role="test role",
|
|
||||||
goal="test goal",
|
|
||||||
backstory="test backstory"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert agent.role == "test role"
|
def test_agent_creation():
|
||||||
assert agent.goal == "test goal"
|
agent = Agent(role="test role", goal="test goal", backstory="test backstory")
|
||||||
assert agent.backstory == "test backstory"
|
|
||||||
assert agent.tools == []
|
assert agent.role == "test role"
|
||||||
|
assert agent.goal == "test goal"
|
||||||
|
assert agent.backstory == "test backstory"
|
||||||
|
assert agent.tools == []
|
||||||
|
|
||||||
|
|
||||||
def test_agent_default_values():
|
def test_agent_default_values():
|
||||||
agent = Agent(
|
agent = Agent(role="test role", goal="test goal", backstory="test backstory")
|
||||||
role="test role",
|
|
||||||
goal="test goal",
|
assert isinstance(agent.llm, OpenAI)
|
||||||
backstory="test backstory"
|
assert agent.llm.model_name == "gpt-4"
|
||||||
)
|
assert agent.llm.temperature == 0.7
|
||||||
|
assert agent.llm.verbose == False
|
||||||
|
assert agent.allow_delegation == True
|
||||||
|
|
||||||
assert isinstance(agent.llm, OpenAI)
|
|
||||||
assert agent.llm.model_name == "gpt-4"
|
|
||||||
assert agent.llm.temperature == 0.7
|
|
||||||
assert agent.llm.verbose == False
|
|
||||||
assert agent.allow_delegation == True
|
|
||||||
|
|
||||||
def test_custom_llm():
|
def test_custom_llm():
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
role="test role",
|
role="test role",
|
||||||
goal="test goal",
|
goal="test goal",
|
||||||
backstory="test backstory",
|
backstory="test backstory",
|
||||||
llm=OpenAI(
|
llm=OpenAI(temperature=0, model="gpt-4"),
|
||||||
temperature=0,
|
)
|
||||||
model="gpt-4"
|
|
||||||
)
|
assert isinstance(agent.llm, OpenAI)
|
||||||
)
|
assert agent.llm.model_name == "gpt-4"
|
||||||
|
assert agent.llm.temperature == 0
|
||||||
|
|
||||||
assert isinstance(agent.llm, OpenAI)
|
|
||||||
assert agent.llm.model_name == "gpt-4"
|
|
||||||
assert agent.llm.temperature == 0
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_agent_without_memory():
|
def test_agent_without_memory():
|
||||||
no_memory_agent = Agent(
|
no_memory_agent = Agent(
|
||||||
role="test role",
|
role="test role",
|
||||||
goal="test goal",
|
goal="test goal",
|
||||||
backstory="test backstory",
|
backstory="test backstory",
|
||||||
memory=False,
|
memory=False,
|
||||||
llm=OpenAI(
|
llm=OpenAI(temperature=0, model="gpt-4"),
|
||||||
temperature=0,
|
)
|
||||||
model="gpt-4"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
memory_agent = Agent(
|
memory_agent = Agent(
|
||||||
role="test role",
|
role="test role",
|
||||||
goal="test goal",
|
goal="test goal",
|
||||||
backstory="test backstory",
|
backstory="test backstory",
|
||||||
memory=True,
|
memory=True,
|
||||||
llm=OpenAI(
|
llm=OpenAI(temperature=0, model="gpt-4"),
|
||||||
temperature=0,
|
)
|
||||||
model="gpt-4"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
result = no_memory_agent.execute_task("How much is 1 + 1?")
|
result = no_memory_agent.execute_task("How much is 1 + 1?")
|
||||||
|
|
||||||
|
assert result == "1 + 1 equals 2."
|
||||||
|
assert no_memory_agent.agent_executor.memory is None
|
||||||
|
assert memory_agent.agent_executor.memory is not None
|
||||||
|
|
||||||
assert result == "1 + 1 equals 2."
|
|
||||||
assert no_memory_agent.agent_executor.memory is None
|
|
||||||
assert memory_agent.agent_executor.memory is not None
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_agent_execution():
|
def test_agent_execution():
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
role="test role",
|
role="test role",
|
||||||
goal="test goal",
|
goal="test goal",
|
||||||
backstory="test backstory",
|
backstory="test backstory",
|
||||||
allow_delegation=False
|
allow_delegation=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
output = agent.execute_task("How much is 1 + 1?")
|
||||||
|
assert output == "2"
|
||||||
|
|
||||||
output = agent.execute_task("How much is 1 + 1?")
|
|
||||||
assert output == "2"
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_agent_execution_with_tools():
|
def test_agent_execution_with_tools():
|
||||||
from langchain.tools import tool
|
from langchain.tools import tool
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def multiplier(numbers) -> float:
|
def multiplier(numbers) -> float:
|
||||||
"""Useful for when you need to multiply two numbers together.
|
"""Useful for when you need to multiply two numbers together.
|
||||||
The input to this tool should be a comma separated list of numbers of
|
The input to this tool should be a comma separated list of numbers of
|
||||||
length two, representing the two numbers you want to multiply together.
|
length two, representing the two numbers you want to multiply together.
|
||||||
For example, `1,2` would be the input if you wanted to multiply 1 by 2."""
|
For example, `1,2` would be the input if you wanted to multiply 1 by 2."""
|
||||||
a, b = numbers.split(',')
|
a, b = numbers.split(",")
|
||||||
return int(a) * int(b)
|
return int(a) * int(b)
|
||||||
|
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
role="test role",
|
role="test role",
|
||||||
goal="test goal",
|
goal="test goal",
|
||||||
backstory="test backstory",
|
backstory="test backstory",
|
||||||
tools=[multiplier],
|
tools=[multiplier],
|
||||||
allow_delegation=False
|
allow_delegation=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
output = agent.execute_task("What is 3 times 4")
|
||||||
|
assert output == "12"
|
||||||
|
|
||||||
output = agent.execute_task("What is 3 times 4")
|
|
||||||
assert output == "12"
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_agent_execution_with_specific_tools():
|
def test_agent_execution_with_specific_tools():
|
||||||
from langchain.tools import tool
|
from langchain.tools import tool
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def multiplier(numbers) -> float:
|
def multiplier(numbers) -> float:
|
||||||
"""Useful for when you need to multiply two numbers together.
|
"""Useful for when you need to multiply two numbers together.
|
||||||
The input to this tool should be a comma separated list of numbers of
|
The input to this tool should be a comma separated list of numbers of
|
||||||
length two, representing the two numbers you want to multiply together.
|
length two, representing the two numbers you want to multiply together.
|
||||||
For example, `1,2` would be the input if you wanted to multiply 1 by 2."""
|
For example, `1,2` would be the input if you wanted to multiply 1 by 2."""
|
||||||
a, b = numbers.split(',')
|
a, b = numbers.split(",")
|
||||||
return int(a) * int(b)
|
return int(a) * int(b)
|
||||||
|
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
role="test role",
|
role="test role",
|
||||||
goal="test goal",
|
goal="test goal",
|
||||||
backstory="test backstory",
|
backstory="test backstory",
|
||||||
allow_delegation=False
|
allow_delegation=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
output = agent.execute_task(
|
output = agent.execute_task(task="What is 3 times 4", tools=[multiplier])
|
||||||
task="What is 3 times 4",
|
assert output == "3 times 4 is 12."
|
||||||
tools=[multiplier]
|
|
||||||
)
|
|
||||||
assert output == "3 times 4 is 12."
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
# conftest.py
|
# conftest.py
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
load_result = load_dotenv(override=True)
|
|
||||||
|
load_result = load_dotenv(override=True)
|
||||||
|
|||||||
@@ -1,114 +1,131 @@
|
|||||||
"""Test Agent creation and execution basic functionality."""
|
"""Test Agent creation and execution basic functionality."""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from ..crewai import Agent, Crew, Task, Process
|
|
||||||
|
from ..crewai import Agent, Crew, Process, Task
|
||||||
|
|
||||||
ceo = Agent(
|
ceo = Agent(
|
||||||
role="CEO",
|
role="CEO",
|
||||||
goal="Make sure the writers in your company produce amazing content.",
|
goal="Make sure the writers in your company produce amazing content.",
|
||||||
backstory="You're an long time CEO of a content creation agency with a Senior Writer on the team. You're now working on a new project and want to make sure the content produced is amazing.",
|
backstory="You're an long time CEO of a content creation agency with a Senior Writer on the team. You're now working on a new project and want to make sure the content produced is amazing.",
|
||||||
allow_delegation=True
|
allow_delegation=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
researcher = Agent(
|
researcher = Agent(
|
||||||
role="Researcher",
|
role="Researcher",
|
||||||
goal="Make the best research and analysis on content about AI and AI agents",
|
goal="Make the best research and analysis on content about AI and AI agents",
|
||||||
backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
||||||
allow_delegation=False
|
allow_delegation=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
writer = Agent(
|
writer = Agent(
|
||||||
role="Senior Writer",
|
role="Senior Writer",
|
||||||
goal="Write the best content about AI and AI agents.",
|
goal="Write the best content about AI and AI agents.",
|
||||||
backstory="You're a senior writer, specialized in technology, software engineering, AI and startups. You work as a freelancer and are now working on writing content for a new customer.",
|
backstory="You're a senior writer, specialized in technology, software engineering, AI and startups. You work as a freelancer and are now working on writing content for a new customer.",
|
||||||
allow_delegation=False
|
allow_delegation=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_crew_config_conditional_requirement():
|
def test_crew_config_conditional_requirement():
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
Crew(process=Process.sequential)
|
Crew(process=Process.sequential)
|
||||||
|
|
||||||
config = json.dumps({
|
config = json.dumps(
|
||||||
"agents": [
|
{
|
||||||
{
|
"agents": [
|
||||||
"role": "Senior Researcher",
|
{
|
||||||
"goal": "Make the best research and analysis on content about AI and AI agents",
|
"role": "Senior Researcher",
|
||||||
"backstory": "You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer."
|
"goal": "Make the best research and analysis on content about AI and AI agents",
|
||||||
},
|
"backstory": "You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
||||||
{
|
},
|
||||||
"role": "Senior Writer",
|
{
|
||||||
"goal": "Write the best content about AI and AI agents.",
|
"role": "Senior Writer",
|
||||||
"backstory": "You're a senior writer, specialized in technology, software engineering, AI and startups. You work as a freelancer and are now working on writing content for a new customer."
|
"goal": "Write the best content about AI and AI agents.",
|
||||||
}
|
"backstory": "You're a senior writer, specialized in technology, software engineering, AI and startups. You work as a freelancer and are now working on writing content for a new customer.",
|
||||||
],
|
},
|
||||||
"tasks": [
|
],
|
||||||
{
|
"tasks": [
|
||||||
"description": "Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
{
|
||||||
"agent": "Senior Researcher"
|
"description": "Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
||||||
},
|
"agent": "Senior Researcher",
|
||||||
{
|
},
|
||||||
"description": "Write a 1 amazing paragraph highlight for each idead that showcases how good an article about this topic could be, check references if necessary or search for more content but make sure it's unique, interesting and well written. Return the list of ideas with their paragraph and your notes.",
|
{
|
||||||
"agent": "Senior Writer"
|
"description": "Write a 1 amazing paragraph highlight for each idead that showcases how good an article about this topic could be, check references if necessary or search for more content but make sure it's unique, interesting and well written. Return the list of ideas with their paragraph and your notes.",
|
||||||
}
|
"agent": "Senior Writer",
|
||||||
]
|
},
|
||||||
})
|
],
|
||||||
parsed_config = json.loads(config)
|
}
|
||||||
|
)
|
||||||
|
parsed_config = json.loads(config)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
crew = Crew(process=Process.sequential, config=config)
|
crew = Crew(process=Process.sequential, config=config)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pytest.fail("Unexpected ValidationError raised")
|
pytest.fail("Unexpected ValidationError raised")
|
||||||
|
|
||||||
|
assert [agent.role for agent in crew.agents] == [
|
||||||
|
agent["role"] for agent in parsed_config["agents"]
|
||||||
|
]
|
||||||
|
assert [task.description for task in crew.tasks] == [
|
||||||
|
task["description"] for task in parsed_config["tasks"]
|
||||||
|
]
|
||||||
|
|
||||||
assert [agent.role for agent in crew.agents] == [agent['role'] for agent in parsed_config['agents']]
|
|
||||||
assert [task.description for task in crew.tasks] == [task['description'] for task in parsed_config['tasks']]
|
|
||||||
|
|
||||||
def test_crew_config_with_wrong_keys():
|
def test_crew_config_with_wrong_keys():
|
||||||
no_tasks_config = json.dumps({
|
no_tasks_config = json.dumps(
|
||||||
"agents": [
|
{
|
||||||
{
|
"agents": [
|
||||||
"role": "Senior Researcher",
|
{
|
||||||
"goal": "Make the best research and analysis on content about AI and AI agents",
|
"role": "Senior Researcher",
|
||||||
"backstory": "You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer."
|
"goal": "Make the best research and analysis on content about AI and AI agents",
|
||||||
}
|
"backstory": "You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
||||||
]
|
}
|
||||||
})
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
no_agents_config = json.dumps(
|
||||||
|
{
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"description": "Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
||||||
|
"agent": "Senior Researcher",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Crew(process=Process.sequential, config='{"wrong_key": "wrong_value"}')
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Crew(process=Process.sequential, config=no_tasks_config)
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
Crew(process=Process.sequential, config=no_agents_config)
|
||||||
|
|
||||||
no_agents_config = json.dumps({
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"description": "Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
|
||||||
"agent": "Senior Researcher"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
Crew(process=Process.sequential, config='{"wrong_key": "wrong_value"}')
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
Crew(process=Process.sequential, config=no_tasks_config)
|
|
||||||
with pytest.raises(ValueError):
|
|
||||||
Crew(process=Process.sequential, config=no_agents_config)
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_crew_creation():
|
def test_crew_creation():
|
||||||
tasks = [
|
tasks = [
|
||||||
Task(
|
Task(
|
||||||
description="Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
description="Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
||||||
agent=researcher
|
agent=researcher,
|
||||||
),
|
),
|
||||||
Task(
|
Task(
|
||||||
description="Write a 1 amazing paragraph highlight for each idea that showcases how good an article about this topic could be. Return the list of ideas with their paragraph and your notes.",
|
description="Write a 1 amazing paragraph highlight for each idea that showcases how good an article about this topic could be. Return the list of ideas with their paragraph and your notes.",
|
||||||
agent=writer
|
agent=writer,
|
||||||
)
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
crew = Crew(
|
crew = Crew(
|
||||||
agents=[researcher, writer],
|
agents=[researcher, writer],
|
||||||
process=Process.sequential,
|
process=Process.sequential,
|
||||||
tasks=tasks,
|
tasks=tasks,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert crew.kickoff() == """1. **The Evolution of AI: From Old Concepts to New Frontiers** - Journey with us as we traverse the fascinating timeline of artificial intelligence - from its philosophical and mathematical infancy to the sophisticated, problem-solving tool it has become today. This riveting account will not only educate but also inspire, as we delve deep into the milestones that brought us here and shine a beacon on the potential that lies ahead.
|
assert (
|
||||||
|
crew.kickoff()
|
||||||
|
== """1. **The Evolution of AI: From Old Concepts to New Frontiers** - Journey with us as we traverse the fascinating timeline of artificial intelligence - from its philosophical and mathematical infancy to the sophisticated, problem-solving tool it has become today. This riveting account will not only educate but also inspire, as we delve deep into the milestones that brought us here and shine a beacon on the potential that lies ahead.
|
||||||
|
|
||||||
2. **AI Agents in Healthcare: The Future of Medicine** - Imagine a world where illnesses are diagnosed before symptoms appear, where patient outcomes are not mere guesses but accurate predictions. This is the world AI is crafting in healthcare - a revolution that's saving lives and changing the face of medicine as we know it. This article will spotlight this transformative journey, underlining the profound impact AI is having on our health and well-being.
|
2. **AI Agents in Healthcare: The Future of Medicine** - Imagine a world where illnesses are diagnosed before symptoms appear, where patient outcomes are not mere guesses but accurate predictions. This is the world AI is crafting in healthcare - a revolution that's saving lives and changing the face of medicine as we know it. This article will spotlight this transformative journey, underlining the profound impact AI is having on our health and well-being.
|
||||||
|
|
||||||
@@ -117,60 +134,60 @@ def test_crew_creation():
|
|||||||
4. **Demystifying AI Algorithms: A Deep Dive into Machine Learning** - Ever wondered what goes on behind the scenes of AI? This enlightening article will break down the complex world of machine learning algorithms into digestible insights, unraveling the mystery of AI's 'black box'. It's a rare opportunity for the non-technical audience to appreciate the inner workings of AI, fostering a deeper understanding of this revolutionary technology.
|
4. **Demystifying AI Algorithms: A Deep Dive into Machine Learning** - Ever wondered what goes on behind the scenes of AI? This enlightening article will break down the complex world of machine learning algorithms into digestible insights, unraveling the mystery of AI's 'black box'. It's a rare opportunity for the non-technical audience to appreciate the inner workings of AI, fostering a deeper understanding of this revolutionary technology.
|
||||||
|
|
||||||
5. **AI Startups: The Game Changers of the Tech Industry** - In the world of tech, AI startups are the bold pioneers charting new territories. This article will spotlight these game changers, showcasing how their innovative products and services are driving the AI revolution. It's a unique opportunity to catch a glimpse of the entrepreneurial side of AI, offering inspiration for the tech enthusiasts and dreamers alike."""
|
5. **AI Startups: The Game Changers of the Tech Industry** - In the world of tech, AI startups are the bold pioneers charting new territories. This article will spotlight these game changers, showcasing how their innovative products and services are driving the AI revolution. It's a unique opportunity to catch a glimpse of the entrepreneurial side of AI, offering inspiration for the tech enthusiasts and dreamers alike."""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_crew_with_delegating_agents():
|
def test_crew_with_delegating_agents():
|
||||||
tasks = [
|
tasks = [
|
||||||
Task(
|
Task(
|
||||||
description="Produce and amazing 1 paragraph draft of an article about AI Agents.",
|
description="Produce and amazing 1 paragraph draft of an article about AI Agents.",
|
||||||
agent=ceo
|
agent=ceo,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
crew = Crew(
|
crew = Crew(
|
||||||
agents=[ceo, writer],
|
agents=[ceo, writer],
|
||||||
process=Process.sequential,
|
process=Process.sequential,
|
||||||
tasks=tasks,
|
tasks=tasks,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
crew.kickoff()
|
||||||
|
== "The Senior Writer has created a compelling and engaging 1 paragraph draft about AI agents. The paragraph provides a brief yet comprehensive overview of AI agents, their uses, and implications in the current world. It emphasizes their potential and the role they can play in the future. The tone is informative but captivating, meeting the objectives of the task."
|
||||||
|
)
|
||||||
|
|
||||||
assert crew.kickoff() == 'The Senior Writer has created a compelling and engaging 1 paragraph draft about AI agents. The paragraph provides a brief yet comprehensive overview of AI agents, their uses, and implications in the current world. It emphasizes their potential and the role they can play in the future. The tone is informative but captivating, meeting the objectives of the task.'
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
@pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_crew_verbose_output(capsys):
|
def test_crew_verbose_output(capsys):
|
||||||
tasks = [
|
tasks = [
|
||||||
Task(
|
Task(description="Research AI advancements.", agent=researcher),
|
||||||
description="Research AI advancements.",
|
Task(description="Write about AI in healthcare.", agent=writer),
|
||||||
agent=researcher
|
]
|
||||||
),
|
|
||||||
Task(
|
|
||||||
description="Write about AI in healthcare.",
|
|
||||||
agent=writer
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
crew = Crew(
|
crew = Crew(
|
||||||
agents=[researcher, writer],
|
agents=[researcher, writer],
|
||||||
tasks=tasks,
|
tasks=tasks,
|
||||||
process=Process.sequential,
|
process=Process.sequential,
|
||||||
verbose=True
|
verbose=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
crew.kickoff()
|
crew.kickoff()
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
expected_strings = [
|
expected_strings = [
|
||||||
"Working Agent: Researcher",
|
"Working Agent: Researcher",
|
||||||
"Starting Task: Research AI advancements. ...",
|
"Starting Task: Research AI advancements. ...",
|
||||||
"Task output:",
|
"Task output:",
|
||||||
"Working Agent: Senior Writer",
|
"Working Agent: Senior Writer",
|
||||||
"Starting Task: Write about AI in healthcare. ...",
|
"Starting Task: Write about AI in healthcare. ...",
|
||||||
"Task output:"
|
"Task output:",
|
||||||
]
|
]
|
||||||
|
|
||||||
for expected_string in expected_strings:
|
for expected_string in expected_strings:
|
||||||
assert expected_string in captured.out
|
assert expected_string in captured.out
|
||||||
|
|
||||||
# Now test with verbose set to False
|
# Now test with verbose set to False
|
||||||
crew.verbose = False
|
crew.verbose = False
|
||||||
crew.kickoff()
|
crew.kickoff()
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
assert captured.out == ""
|
assert captured.out == ""
|
||||||
|
|||||||
@@ -1,57 +1,56 @@
|
|||||||
"""Test Agent creation and execution basic functionality."""
|
"""Test Agent creation and execution basic functionality."""
|
||||||
|
|
||||||
import pytest
|
|
||||||
from ..crewai import Agent, Task
|
from ..crewai import Agent, Task
|
||||||
|
|
||||||
|
|
||||||
def test_task_tool_reflect_agent_tools():
|
def test_task_tool_reflect_agent_tools():
|
||||||
from langchain.tools import tool
|
from langchain.tools import tool
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def fake_tool() -> None:
|
def fake_tool() -> None:
|
||||||
"Fake tool"
|
"Fake tool"
|
||||||
pass
|
|
||||||
|
researcher = Agent(
|
||||||
researcher = Agent(
|
role="Researcher",
|
||||||
role="Researcher",
|
goal="Make the best research and analysis on content about AI and AI agents",
|
||||||
goal="Make the best research and analysis on content about AI and AI agents",
|
backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
||||||
backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
tools=[fake_tool],
|
||||||
tools=[fake_tool],
|
allow_delegation=False,
|
||||||
allow_delegation=False
|
)
|
||||||
)
|
|
||||||
|
task = Task(
|
||||||
|
description="Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
||||||
|
agent=researcher,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert task.tools == [fake_tool]
|
||||||
|
|
||||||
task = Task(
|
|
||||||
description="Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
|
||||||
agent=researcher
|
|
||||||
)
|
|
||||||
|
|
||||||
assert task.tools == [fake_tool]
|
|
||||||
|
|
||||||
def test_task_tool_takes_precedence_ove_agent_tools():
|
def test_task_tool_takes_precedence_ove_agent_tools():
|
||||||
from langchain.tools import tool
|
from langchain.tools import tool
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def fake_tool() -> None:
|
def fake_tool() -> None:
|
||||||
"Fake tool"
|
"Fake tool"
|
||||||
pass
|
|
||||||
|
|
||||||
@tool
|
@tool
|
||||||
def fake_task_tool() -> None:
|
def fake_task_tool() -> None:
|
||||||
"Fake tool"
|
"Fake tool"
|
||||||
pass
|
|
||||||
|
|
||||||
researcher = Agent(
|
|
||||||
role="Researcher",
|
|
||||||
goal="Make the best research and analysis on content about AI and AI agents",
|
|
||||||
backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
|
||||||
tools=[fake_tool],
|
|
||||||
allow_delegation=False
|
|
||||||
)
|
|
||||||
|
|
||||||
task = Task(
|
researcher = Agent(
|
||||||
description="Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
role="Researcher",
|
||||||
agent=researcher,
|
goal="Make the best research and analysis on content about AI and AI agents",
|
||||||
tools=[fake_task_tool],
|
backstory="You're an expert researcher, specialized in technology, software engineering, AI and startups. You work as a freelancer and is now working on doing research and analysis for a new customer.",
|
||||||
allow_delegation=False
|
tools=[fake_tool],
|
||||||
)
|
allow_delegation=False,
|
||||||
|
)
|
||||||
assert task.tools == [fake_task_tool]
|
|
||||||
|
task = Task(
|
||||||
|
description="Give me a list of 5 interesting ideas to explore for na article, what makes them unique and interesting.",
|
||||||
|
agent=researcher,
|
||||||
|
tools=[fake_task_tool],
|
||||||
|
allow_delegation=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert task.tools == [fake_task_tool]
|
||||||
|
|||||||
Reference in New Issue
Block a user