mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 08:08:32 +00:00
Merge branch 'main' of github.com:joaomdmoura/crewAI into lj/optional-agent-in-task-bug
This commit is contained in:
@@ -16,24 +16,24 @@ description: What are crewAI Agents and how to use them.
|
|||||||
|
|
||||||
## Agent Attributes
|
## Agent Attributes
|
||||||
|
|
||||||
| Attribute | Description |
|
| Attribute | Parameter | Description |
|
||||||
| :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| :------------------------- | :---- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **Role** | Defines the agent's function within the crew. It determines the kind of tasks the agent is best suited for. |
|
| **Role** | `role` | Defines the agent's function within the crew. It determines the kind of tasks the agent is best suited for. |
|
||||||
| **Goal** | The individual objective that the agent aims to achieve. It guides the agent's decision-making process. |
|
| **Goal** | `goal` | The individual objective that the agent aims to achieve. It guides the agent's decision-making process. |
|
||||||
| **Backstory** | Provides context to the agent's role and goal, enriching the interaction and collaboration dynamics. |
|
| **Backstory** | `backstory` | Provides context to the agent's role and goal, enriching the interaction and collaboration dynamics. |
|
||||||
| **LLM** *(optional)* | Represents the language model that will run the agent. It dynamically fetches the model name from the `OPENAI_MODEL_NAME` environment variable, defaulting to "gpt-4" if not specified. |
|
| **LLM** *(optional)* | `llm` | Represents the language model that will run the agent. It dynamically fetches the model name from the `OPENAI_MODEL_NAME` environment variable, defaulting to "gpt-4" if not specified. |
|
||||||
| **Tools** *(optional)* | Set of capabilities or functions that the agent can use to perform tasks. Expected to be instances of custom classes compatible with the agent's execution environment. Tools are initialized with a default value of an empty list. |
|
| **Tools** *(optional)* | `tools` | Set of capabilities or functions that the agent can use to perform tasks. Expected to be instances of custom classes compatible with the agent's execution environment. Tools are initialized with a default value of an empty list. |
|
||||||
| **Function Calling LLM** *(optional)* | Specifies the language model that will handle the tool calling for this agent, overriding the crew function calling LLM if passed. Default is `None`. |
|
| **Function Calling LLM** *(optional)* | `function_calling_llm` | Specifies the language model that will handle the tool calling for this agent, overriding the crew function calling LLM if passed. Default is `None`. |
|
||||||
| **Max Iter** *(optional)* | `max_iter` is the maximum number of iterations the agent can perform before being forced to give its best answer. Default is `25`. |
|
| **Max Iter** *(optional)* | `max_iter` | Max Iter is the maximum number of iterations the agent can perform before being forced to give its best answer. Default is `25`. |
|
||||||
| **Max RPM** *(optional)* | `max_rpm` is Tte maximum number of requests per minute the agent can perform to avoid rate limits. It's optional and can be left unspecified, with a default value of `None`. |
|
| **Max RPM** *(optional)* | `max_rpm` | Max RPM is the maximum number of requests per minute the agent can perform to avoid rate limits. It's optional and can be left unspecified, with a default value of `None`. |
|
||||||
| **Max Execution Time** *(optional)* | `max_execution_time` is the Maximum execution time for an agent to execute a task. It's optional and can be left unspecified, with a default value of `None`, meaning no max execution time. |
|
| **Max Execution Time** *(optional)* | `max_execution_time` | Max Execution Time is the Maximum execution time for an agent to execute a task. It's optional and can be left unspecified, with a default value of `None`, meaning no max execution time. |
|
||||||
| **Verbose** *(optional)* | Setting this to `True` configures the internal logger to provide detailed execution logs, aiding in debugging and monitoring. Default is `False`. |
|
| **Verbose** *(optional)* | `verbose` | Setting this to `True` configures the internal logger to provide detailed execution logs, aiding in debugging and monitoring. Default is `False`. |
|
||||||
| **Allow Delegation** *(optional)* | Agents can delegate tasks or questions to one another, ensuring that each task is handled by the most suitable agent. Default is `True`. |
|
| **Allow Delegation** *(optional)* | `allow_delegation` | Agents can delegate tasks or questions to one another, ensuring that each task is handled by the most suitable agent. Default is `True`. |
|
||||||
| **Step Callback** *(optional)* | A function that is called after each step of the agent. This can be used to log the agent's actions or to perform other operations. It will overwrite the crew `step_callback`. |
|
| **Step Callback** *(optional)* | `step_callback` | A function that is called after each step of the agent. This can be used to log the agent's actions or to perform other operations. It will overwrite the crew `step_callback`. |
|
||||||
| **Cache** *(optional)* | Indicates if the agent should use a cache for tool usage. Default is `True`. |
|
| **Cache** *(optional)* | `cache` | Indicates if the agent should use a cache for tool usage. Default is `True`. |
|
||||||
| **System Template** *(optional)* | Specifies the system format for the agent. Default is `None`. |
|
| **System Template** *(optional)* | `system_template` | Specifies the system format for the agent. Default is `None`. |
|
||||||
| **Prompt Template** *(optional)* | Specifies the prompt format for the agent. Default is `None`. |
|
| **Prompt Template** *(optional)* | `prompt_template` | Specifies the prompt format for the agent. Default is `None`. |
|
||||||
| **Response Template** *(optional)* | Specifies the response format for the agent. Default is `None`. |
|
| **Response Template** *(optional)* | `response_template` | Specifies the response format for the agent. Default is `None`. |
|
||||||
|
|
||||||
## Creating an Agent
|
## Creating an Agent
|
||||||
|
|
||||||
|
|||||||
@@ -8,29 +8,29 @@ A crew in crewAI represents a collaborative group of agents working together to
|
|||||||
|
|
||||||
## Crew Attributes
|
## Crew Attributes
|
||||||
|
|
||||||
| Attribute | Description |
|
| Attribute | Parameters | Description |
|
||||||
| :-------------------------- | :----------------------------------------------------------- |
|
| :-------------------------- | :------------------ | :------------------------------------------------------------------------------------------------------- |
|
||||||
| **Tasks** | A list of tasks assigned to the crew. |
|
| **Tasks** | `tasks` | A list of tasks assigned to the crew. |
|
||||||
| **Agents** | A list of agents that are part of the crew. |
|
| **Agents** | `agents` | A list of agents that are part of the crew. |
|
||||||
| **Process** *(optional)* | The process flow (e.g., sequential, hierarchical) the crew follows. |
|
| **Process** *(optional)* | `process` | The process flow (e.g., sequential, hierarchical) the crew follows. |
|
||||||
| **Verbose** *(optional)* | The verbosity level for logging during execution. |
|
| **Verbose** *(optional)* | `verbose` | The verbosity level for logging during execution. |
|
||||||
| **Manager LLM** *(optional)*| The language model used by the manager agent in a hierarchical process. **Required when using a hierarchical process.** |
|
| **Manager LLM** *(optional)*| `manager_llm` | The language model used by the manager agent in a hierarchical process. **Required when using a hierarchical process.** |
|
||||||
| **Function Calling LLM** *(optional)* | If passed, the crew will use this LLM to do function calling for tools for all agents in the crew. Each agent can have its own LLM, which overrides the crew's LLM for function calling. |
|
| **Function Calling LLM** *(optional)* | `function_calling_llm` | If passed, the crew will use this LLM to do function calling for tools for all agents in the crew. Each agent can have its own LLM, which overrides the crew's LLM for function calling. |
|
||||||
| **Config** *(optional)* | Optional configuration settings for the crew, in `Json` or `Dict[str, Any]` format. |
|
| **Config** *(optional)* | `config` | Optional configuration settings for the crew, in `Json` or `Dict[str, Any]` format. |
|
||||||
| **Max RPM** *(optional)* | Maximum requests per minute the crew adheres to during execution. |
|
| **Max RPM** *(optional)* | `max_rpm` | Maximum requests per minute the crew adheres to during execution. |
|
||||||
| **Language** *(optional)* | Language used for the crew, defaults to English. |
|
| **Language** *(optional)* | `language` | Language used for the crew, defaults to English. |
|
||||||
| **Language File** *(optional)* | Path to the language file to be used for the crew. |
|
| **Language File** *(optional)* | `language_file` | Path to the language file to be used for the crew. |
|
||||||
| **Memory** *(optional)* | Utilized for storing execution memories (short-term, long-term, entity memory). |
|
| **Memory** *(optional)* | `memory` | Utilized for storing execution memories (short-term, long-term, entity memory). |
|
||||||
| **Cache** *(optional)* | Specifies whether to use a cache for storing the results of tools' execution. |
|
| **Cache** *(optional)* | `cache` | Specifies whether to use a cache for storing the results of tools' execution. |
|
||||||
| **Embedder** *(optional)* | Configuration for the embedder to be used by the crew. Mostly used by memory for now. |
|
| **Embedder** *(optional)* | `embedder` | Configuration for the embedder to be used by the crew. Mostly used by memory for now. |
|
||||||
| **Full Output** *(optional)*| Whether the crew should return the full output with all tasks outputs or just the final output. |
|
| **Full Output** *(optional)*| `full_output` | Whether the crew should return the full output with all tasks outputs or just the final output. |
|
||||||
| **Step Callback** *(optional)* | A function that is called after each step of every agent. This can be used to log the agent's actions or to perform other operations; it won't override the agent-specific `step_callback`. |
|
| **Step Callback** *(optional)* | `step_callback` | A function that is called after each step of every agent. This can be used to log the agent's actions or to perform other operations; it won't override the agent-specific `step_callback`. |
|
||||||
| **Task Callback** *(optional)* | A function that is called after the completion of each task. Useful for monitoring or additional operations post-task execution. |
|
| **Task Callback** *(optional)* | `task_callback` | A function that is called after the completion of each task. Useful for monitoring or additional operations post-task execution. |
|
||||||
| **Share Crew** *(optional)* | Whether you want to share the complete crew information and execution with the crewAI team to make the library better, and allow us to train models. |
|
| **Share Crew** *(optional)* | `share_crew` | Whether you want to share the complete crew information and execution with the crewAI team to make the library better, and allow us to train models. |
|
||||||
| **Output Log File** *(optional)* | Whether you want to have a file with the complete crew output and execution. You can set it using True and it will default to the folder you are currently in and it will be called logs.txt or passing a string with the full path and name of the file. |
|
| **Output Log File** *(optional)* | `output_log_file` | Whether you want to have a file with the complete crew output and execution. You can set it using True and it will default to the folder you are currently in and it will be called logs.txt or passing a string with the full path and name of the file. |
|
||||||
| **Manager Agent** *(optional)* | `manager` sets a custom agent that will be used as a manager. |
|
| **Manager Agent** *(optional)* | `manager_agent` | `manager` sets a custom agent that will be used as a manager. |
|
||||||
| **Manager Callbacks** *(optional)* | `manager_callbacks` takes a list of callback handlers to be executed by the manager agent when a hierarchical process is used. |
|
| **Manager Callbacks** *(optional)* | `manager_callbacks` | `manager_callbacks` takes a list of callback handlers to be executed by the manager agent when a hierarchical process is used. |
|
||||||
| **Prompt File** *(optional)* | Path to the prompt JSON file to be used for the crew. |
|
| **Prompt File** *(optional)* | `prompt_file` | Path to the prompt JSON file to be used for the crew. |
|
||||||
|
|
||||||
!!! note "Crew Max RPM"
|
!!! note "Crew Max RPM"
|
||||||
The `max_rpm` attribute sets the maximum number of requests per minute the crew can perform to avoid rate limits and will override individual agents' `max_rpm` settings if you set it.
|
The `max_rpm` attribute sets the maximum number of requests per minute the crew can perform to avoid rate limits and will override individual agents' `max_rpm` settings if you set it.
|
||||||
|
|||||||
@@ -11,20 +11,20 @@ Tasks within crewAI can be collaborative, requiring multiple agents to work toge
|
|||||||
|
|
||||||
## Task Attributes
|
## Task Attributes
|
||||||
|
|
||||||
| Attribute | Description |
|
| Attribute | Parameters | Description |
|
||||||
| :----------------------| :-------------------------------------------------------------------------------------------- |
|
| :----------------------| :------------------- | :-------------------------------------------------------------------------------------------- |
|
||||||
| **Description** | A clear, concise statement of what the task entails. |
|
| **Description** | `description` | A clear, concise statement of what the task entails. |
|
||||||
| **Agent** | The agent responsible for the task, assigned either directly or by the crew's process. |
|
| **Agent** | `agent` | The agent responsible for the task, assigned either directly or by the crew's process. |
|
||||||
| **Expected Output** | A detailed description of what the task's completion looks like. |
|
| **Expected Output** | `expected_output` | A detailed description of what the task's completion looks like. |
|
||||||
| **Tools** *(optional)* | The functions or capabilities the agent can utilize to perform the task. |
|
| **Tools** *(optional)* | `tools` | The functions or capabilities the agent can utilize to perform the task. |
|
||||||
| **Async Execution** *(optional)* | If set, the task executes asynchronously, allowing progression without waiting for completion.|
|
| **Async Execution** *(optional)* | `async_execution` | If set, the task executes asynchronously, allowing progression without waiting for completion.|
|
||||||
| **Context** *(optional)* | Specifies tasks whose outputs are used as context for this task. |
|
| **Context** *(optional)* | `context` | Specifies tasks whose outputs are used as context for this task. |
|
||||||
| **Config** *(optional)* | Additional configuration details for the agent executing the task, allowing further customization. |
|
| **Config** *(optional)* | `config` | Additional configuration details for the agent executing the task, allowing further customization. |
|
||||||
| **Output JSON** *(optional)* | Outputs a JSON object, requiring an OpenAI client. Only one output format can be set. |
|
| **Output JSON** *(optional)* | `output_json` | Outputs a JSON object, requiring an OpenAI client. Only one output format can be set. |
|
||||||
| **Output Pydantic** *(optional)* | Outputs a Pydantic model object, requiring an OpenAI client. Only one output format can be set. |
|
| **Output Pydantic** *(optional)* | `output_pydantic` | Outputs a Pydantic model object, requiring an OpenAI client. Only one output format can be set. |
|
||||||
| **Output File** *(optional)* | Saves the task output to a file. If used with `Output JSON` or `Output Pydantic`, specifies how the output is saved. |
|
| **Output File** *(optional)* | `output_file` | Saves the task output to a file. If used with `Output JSON` or `Output Pydantic`, specifies how the output is saved. |
|
||||||
| **Callback** *(optional)* | A Python callable that is executed with the task's output upon completion. |
|
| **Callback** *(optional)* | `callback` | A Python callable that is executed with the task's output upon completion. |
|
||||||
| **Human Input** *(optional)* | Indicates if the task requires human feedback at the end, useful for tasks needing human oversight. |
|
| **Human Input** *(optional)* | `human_input` | Indicates if the task requires human feedback at the end, useful for tasks needing human oversight. |
|
||||||
|
|
||||||
## Creating a Task
|
## Creating a Task
|
||||||
|
|
||||||
|
|||||||
@@ -37,10 +37,9 @@ writer = Agent(
|
|||||||
backstory='A skilled writer with a talent for crafting compelling narratives'
|
backstory='A skilled writer with a talent for crafting compelling narratives'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Define the tasks in sequence
|
research_task = Task(description='Gather relevant data...', agent=researcher, expected_output='Raw Data')
|
||||||
research_task = Task(description='Gather relevant data...', agent=researcher)
|
analysis_task = Task(description='Analyze the data...', agent=analyst, expected_output='Data Insights')
|
||||||
analysis_task = Task(description='Analyze the data...', agent=analyst)
|
writing_task = Task(description='Compose the report...', agent=writer, expected_output='Final Report')
|
||||||
writing_task = Task(description='Compose the report...', agent=writer)
|
|
||||||
|
|
||||||
# Form the crew with a sequential process
|
# Form the crew with a sequential process
|
||||||
report_crew = Crew(
|
report_crew = Crew(
|
||||||
@@ -83,4 +82,4 @@ CrewAI tracks token usage across all tasks and agents. You can access these metr
|
|||||||
1. **Order Matters**: Arrange tasks in a logical sequence where each task builds upon the previous one.
|
1. **Order Matters**: Arrange tasks in a logical sequence where each task builds upon the previous one.
|
||||||
2. **Clear Task Descriptions**: Provide detailed descriptions for each task to guide the agents effectively.
|
2. **Clear Task Descriptions**: Provide detailed descriptions for each task to guide the agents effectively.
|
||||||
3. **Appropriate Agent Selection**: Match agents' skills and roles to the requirements of each task.
|
3. **Appropriate Agent Selection**: Match agents' skills and roles to the requirements of each task.
|
||||||
4. **Use Context**: Leverage the context from previous tasks to inform subsequent ones
|
4. **Use Context**: Leverage the context from previous tasks to inform subsequent ones
|
||||||
|
|||||||
@@ -26,10 +26,12 @@ click = "^8.1.7"
|
|||||||
python-dotenv = "^1.0.0"
|
python-dotenv = "^1.0.0"
|
||||||
appdirs = "^1.4.4"
|
appdirs = "^1.4.4"
|
||||||
jsonref = "^1.1.0"
|
jsonref = "^1.1.0"
|
||||||
|
agentops = { version = "^0.1.9", optional = true }
|
||||||
embedchain = "^0.1.113"
|
embedchain = "^0.1.113"
|
||||||
|
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
tools = ["crewai-tools"]
|
tools = ["crewai-tools"]
|
||||||
|
agentops = ["agentops"]
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
isort = "^5.13.2"
|
isort = "^5.13.2"
|
||||||
@@ -60,4 +62,4 @@ exclude = ["cli/templates/main.py", "cli/templates/crew.py"]
|
|||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["poetry-core"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|||||||
@@ -19,7 +19,20 @@ from crewai.utilities.token_counter_callback import TokenCalcHandler
|
|||||||
from crewai.agents.agent_builder.base_agent import BaseAgent
|
from crewai.agents.agent_builder.base_agent import BaseAgent
|
||||||
from crewai.utilities.training_handler import CrewTrainingHandler
|
from crewai.utilities.training_handler import CrewTrainingHandler
|
||||||
|
|
||||||
|
agentops = None
|
||||||
|
try:
|
||||||
|
import agentops
|
||||||
|
from agentops import track_agent
|
||||||
|
except ImportError:
|
||||||
|
|
||||||
|
def track_agent():
|
||||||
|
def noop(f):
|
||||||
|
return f
|
||||||
|
|
||||||
|
return noop
|
||||||
|
|
||||||
|
|
||||||
|
@track_agent()
|
||||||
class Agent(BaseAgent):
|
class Agent(BaseAgent):
|
||||||
"""Represents an agent in a system.
|
"""Represents an agent in a system.
|
||||||
|
|
||||||
@@ -48,6 +61,8 @@ class Agent(BaseAgent):
|
|||||||
default=None,
|
default=None,
|
||||||
description="Maximum execution time for an agent to execute a task",
|
description="Maximum execution time for an agent to execute a task",
|
||||||
)
|
)
|
||||||
|
agent_ops_agent_name: str = None
|
||||||
|
agent_ops_agent_id: str = None
|
||||||
cache_handler: InstanceOf[CacheHandler] = Field(
|
cache_handler: InstanceOf[CacheHandler] = Field(
|
||||||
default=None, description="An instance of the CacheHandler class."
|
default=None, description="An instance of the CacheHandler class."
|
||||||
)
|
)
|
||||||
@@ -84,6 +99,7 @@ class Agent(BaseAgent):
|
|||||||
def __init__(__pydantic_self__, **data):
|
def __init__(__pydantic_self__, **data):
|
||||||
config = data.pop("config", {})
|
config = data.pop("config", {})
|
||||||
super().__init__(**config, **data)
|
super().__init__(**config, **data)
|
||||||
|
__pydantic_self__.agent_ops_agent_name = __pydantic_self__.role
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def set_agent_executor(self) -> "Agent":
|
def set_agent_executor(self) -> "Agent":
|
||||||
@@ -101,6 +117,12 @@ class Agent(BaseAgent):
|
|||||||
):
|
):
|
||||||
self.llm.callbacks.append(token_handler)
|
self.llm.callbacks.append(token_handler)
|
||||||
|
|
||||||
|
if agentops and not any(
|
||||||
|
isinstance(handler, agentops.LangchainCallbackHandler) for handler in self.llm.callbacks
|
||||||
|
):
|
||||||
|
agentops.stop_instrumenting()
|
||||||
|
self.llm.callbacks.append(agentops.LangchainCallbackHandler())
|
||||||
|
|
||||||
if not self.agent_executor:
|
if not self.agent_executor:
|
||||||
if not self.cache_handler:
|
if not self.cache_handler:
|
||||||
self.cache_handler = CacheHandler()
|
self.cache_handler = CacheHandler()
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ from pydantic import (
|
|||||||
from pydantic_core import PydanticCustomError
|
from pydantic_core import PydanticCustomError
|
||||||
|
|
||||||
from crewai.utilities import I18N, RPMController, Logger
|
from crewai.utilities import I18N, RPMController, Logger
|
||||||
from crewai.agents import CacheHandler, ToolsHandler
|
from crewai.agents.cache.cache_handler import CacheHandler
|
||||||
|
from crewai.agents.tools_handler import ToolsHandler
|
||||||
from crewai.utilities.token_counter_callback import TokenProcess
|
from crewai.utilities.token_counter_callback import TokenProcess
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,65 +1,109 @@
|
|||||||
import time
|
import time
|
||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from crewai.memory.entity.entity_memory_item import EntityMemoryItem
|
from crewai.memory.entity.entity_memory_item import EntityMemoryItem
|
||||||
from crewai.memory.long_term.long_term_memory_item import LongTermMemoryItem
|
from crewai.memory.long_term.long_term_memory_item import LongTermMemoryItem
|
||||||
from crewai.memory.short_term.short_term_memory_item import ShortTermMemoryItem
|
from crewai.memory.short_term.short_term_memory_item import ShortTermMemoryItem
|
||||||
from crewai.utilities.converter import ConverterError
|
from crewai.utilities.converter import ConverterError
|
||||||
from crewai.utilities.evaluators.task_evaluator import TaskEvaluator
|
from crewai.utilities.evaluators.task_evaluator import TaskEvaluator
|
||||||
|
from crewai.utilities import I18N
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from crewai.crew import Crew
|
||||||
|
from crewai.task import Task
|
||||||
|
from crewai.agents.agent_builder.base_agent import BaseAgent
|
||||||
|
|
||||||
|
|
||||||
class CrewAgentExecutorMixin:
|
class CrewAgentExecutorMixin:
|
||||||
|
crew: Optional["Crew"]
|
||||||
|
crew_agent: Optional["BaseAgent"]
|
||||||
|
task: Optional["Task"]
|
||||||
|
iterations: int
|
||||||
|
force_answer_max_iterations: int
|
||||||
|
have_forced_answer: bool
|
||||||
|
_i18n: I18N
|
||||||
|
|
||||||
def _should_force_answer(self) -> bool:
|
def _should_force_answer(self) -> bool:
|
||||||
|
"""Determine if a forced answer is required based on iteration count."""
|
||||||
return (
|
return (
|
||||||
self.iterations == self.force_answer_max_iterations
|
self.iterations == self.force_answer_max_iterations
|
||||||
) and not self.have_forced_answer
|
) and not self.have_forced_answer
|
||||||
|
|
||||||
def _create_short_term_memory(self, output) -> None:
|
def _create_short_term_memory(self, output) -> None:
|
||||||
|
"""Create and save a short-term memory item if conditions are met."""
|
||||||
|
if (
|
||||||
|
self.crew
|
||||||
|
and self.crew_agent
|
||||||
|
and self.task
|
||||||
|
and "Action: Delegate work to coworker" not in output.log
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
memory = ShortTermMemoryItem(
|
||||||
|
data=output.log,
|
||||||
|
agent=self.crew_agent.role,
|
||||||
|
metadata={
|
||||||
|
"observation": self.task.description,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
hasattr(self.crew, "_short_term_memory")
|
||||||
|
and self.crew._short_term_memory
|
||||||
|
):
|
||||||
|
self.crew._short_term_memory.save(memory)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to add to short term memory: {e}")
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _create_long_term_memory(self, output) -> None:
|
||||||
|
"""Create and save long-term and entity memory items based on evaluation."""
|
||||||
if (
|
if (
|
||||||
self.crew
|
self.crew
|
||||||
and self.crew.memory
|
and self.crew.memory
|
||||||
and "Action: Delegate work to coworker" not in output.log
|
and self.crew._long_term_memory
|
||||||
|
and self.crew._entity_memory
|
||||||
|
and self.task
|
||||||
|
and self.crew_agent
|
||||||
):
|
):
|
||||||
memory = ShortTermMemoryItem(
|
try:
|
||||||
data=output.log,
|
ltm_agent = TaskEvaluator(self.crew_agent)
|
||||||
agent=self.crew_agent.role,
|
evaluation = ltm_agent.evaluate(self.task, output.log)
|
||||||
metadata={
|
|
||||||
"observation": self.task.description,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.crew._short_term_memory.save(memory)
|
|
||||||
|
|
||||||
def _create_long_term_memory(self, output) -> None:
|
if isinstance(evaluation, ConverterError):
|
||||||
if self.crew and self.crew.memory:
|
return
|
||||||
ltm_agent = TaskEvaluator(self.crew_agent)
|
|
||||||
evaluation = ltm_agent.evaluate(self.task, output.log)
|
|
||||||
|
|
||||||
if isinstance(evaluation, ConverterError):
|
long_term_memory = LongTermMemoryItem(
|
||||||
return
|
task=self.task.description,
|
||||||
|
agent=self.crew_agent.role,
|
||||||
long_term_memory = LongTermMemoryItem(
|
quality=evaluation.quality,
|
||||||
task=self.task.description,
|
datetime=str(time.time()),
|
||||||
agent=self.crew_agent.role,
|
expected_output=self.task.expected_output,
|
||||||
quality=evaluation.quality,
|
metadata={
|
||||||
datetime=str(time.time()),
|
"suggestions": evaluation.suggestions,
|
||||||
expected_output=self.task.expected_output,
|
"quality": evaluation.quality,
|
||||||
metadata={
|
},
|
||||||
"suggestions": evaluation.suggestions,
|
|
||||||
"quality": evaluation.quality,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.crew._long_term_memory.save(long_term_memory)
|
|
||||||
|
|
||||||
for entity in evaluation.entities:
|
|
||||||
entity_memory = EntityMemoryItem(
|
|
||||||
name=entity.name,
|
|
||||||
type=entity.type,
|
|
||||||
description=entity.description,
|
|
||||||
relationships="\n".join([f"- {r}" for r in entity.relationships]),
|
|
||||||
)
|
)
|
||||||
self.crew._entity_memory.save(entity_memory)
|
self.crew._long_term_memory.save(long_term_memory)
|
||||||
|
|
||||||
|
for entity in evaluation.entities:
|
||||||
|
entity_memory = EntityMemoryItem(
|
||||||
|
name=entity.name,
|
||||||
|
type=entity.type,
|
||||||
|
description=entity.description,
|
||||||
|
relationships="\n".join(
|
||||||
|
[f"- {r}" for r in entity.relationships]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.crew._entity_memory.save(entity_memory)
|
||||||
|
except AttributeError as e:
|
||||||
|
print(f"Missing attributes for long term memory: {e}")
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to add to long term memory: {e}")
|
||||||
|
pass
|
||||||
|
|
||||||
def _ask_human_input(self, final_answer: dict) -> str:
|
def _ask_human_input(self, final_answer: dict) -> str:
|
||||||
"""Get human input."""
|
"""Prompt human input for final decision making."""
|
||||||
return input(
|
return input(
|
||||||
self._i18n.slice("getting_input").format(final_answer=final_answer)
|
self._i18n.slice("getting_input").format(final_answer=final_answer)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Dict,
|
||||||
|
Iterator,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Tuple,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
from langchain.agents import AgentExecutor
|
from langchain.agents import AgentExecutor
|
||||||
from langchain.agents.agent import ExceptionTool
|
from langchain.agents.agent import ExceptionTool
|
||||||
@@ -11,13 +19,15 @@ from langchain_core.exceptions import OutputParserException
|
|||||||
from langchain_core.tools import BaseTool
|
from langchain_core.tools import BaseTool
|
||||||
from langchain_core.utils.input import get_color_mapping
|
from langchain_core.utils.input import get_color_mapping
|
||||||
from pydantic import InstanceOf
|
from pydantic import InstanceOf
|
||||||
from crewai.agents.agent_builder.base_agent_executor_mixin import CrewAgentExecutorMixin
|
from crewai.agents.agent_builder.base_agent_executor_mixin import (
|
||||||
|
CrewAgentExecutorMixin,
|
||||||
|
)
|
||||||
|
|
||||||
from crewai.agents.tools_handler import ToolsHandler
|
from crewai.agents.tools_handler import ToolsHandler
|
||||||
from crewai.tools.tool_usage import ToolUsage, ToolUsageErrorException
|
from crewai.tools.tool_usage import ToolUsage, ToolUsageErrorException
|
||||||
from crewai.utilities import I18N
|
|
||||||
from crewai.utilities.constants import TRAINING_DATA_FILE
|
from crewai.utilities.constants import TRAINING_DATA_FILE
|
||||||
from crewai.utilities.training_handler import CrewTrainingHandler
|
from crewai.utilities.training_handler import CrewTrainingHandler
|
||||||
|
from crewai.utilities import I18N
|
||||||
|
|
||||||
|
|
||||||
class CrewAgentExecutor(AgentExecutor, CrewAgentExecutorMixin):
|
class CrewAgentExecutor(AgentExecutor, CrewAgentExecutorMixin):
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ from crewai.utilities import I18N, FileHandler, Logger, RPMController
|
|||||||
from crewai.utilities.evaluators.task_evaluator import TaskEvaluator
|
from crewai.utilities.evaluators.task_evaluator import TaskEvaluator
|
||||||
from crewai.utilities.training_handler import CrewTrainingHandler
|
from crewai.utilities.training_handler import CrewTrainingHandler
|
||||||
|
|
||||||
|
try:
|
||||||
|
import agentops
|
||||||
|
except ImportError:
|
||||||
|
agentops = None
|
||||||
|
|
||||||
|
|
||||||
class Crew(BaseModel):
|
class Crew(BaseModel):
|
||||||
"""
|
"""
|
||||||
@@ -556,6 +561,12 @@ class Crew(BaseModel):
|
|||||||
def _finish_execution(self, output) -> None:
|
def _finish_execution(self, output) -> None:
|
||||||
if self.max_rpm:
|
if self.max_rpm:
|
||||||
self._rpm_controller.stop_rpm_counter()
|
self._rpm_controller.stop_rpm_counter()
|
||||||
|
if agentops:
|
||||||
|
agentops.end_session(
|
||||||
|
end_state="Success",
|
||||||
|
end_state_reason="Finished Execution",
|
||||||
|
is_auto_end=True,
|
||||||
|
)
|
||||||
self._telemetry.end_crew(self, output)
|
self._telemetry.end_crew(self, output)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ from crewai.telemetry import Telemetry
|
|||||||
from crewai.tools.tool_calling import InstructorToolCalling, ToolCalling
|
from crewai.tools.tool_calling import InstructorToolCalling, ToolCalling
|
||||||
from crewai.utilities import I18N, Converter, ConverterError, Printer
|
from crewai.utilities import I18N, Converter, ConverterError, Printer
|
||||||
|
|
||||||
|
agentops = None
|
||||||
|
try:
|
||||||
|
import agentops
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
OPENAI_BIGGER_MODELS = ["gpt-4"]
|
OPENAI_BIGGER_MODELS = ["gpt-4"]
|
||||||
|
|
||||||
|
|
||||||
@@ -91,15 +97,16 @@ class ToolUsage:
|
|||||||
self.task.increment_tools_errors()
|
self.task.increment_tools_errors()
|
||||||
self._printer.print(content=f"\n\n{error}\n", color="red")
|
self._printer.print(content=f"\n\n{error}\n", color="red")
|
||||||
return error
|
return error
|
||||||
return f"{self._use(tool_string=tool_string, tool=tool, calling=calling)}" # type: ignore # BUG?: "_use" of "ToolUsage" does not return a value (it only ever returns None)
|
return f"{self._use(tool_string=tool_string, tool=tool, calling=calling)}" # type: ignore # BUG?: "_use" of "ToolUsage" does not return a value (it only ever returns None)
|
||||||
|
|
||||||
def _use(
|
def _use(
|
||||||
self,
|
self,
|
||||||
tool_string: str,
|
tool_string: str,
|
||||||
tool: BaseTool,
|
tool: BaseTool,
|
||||||
calling: Union[ToolCalling, InstructorToolCalling],
|
calling: Union[ToolCalling, InstructorToolCalling],
|
||||||
) -> str: # TODO: Fix this return type --> finecwg : I updated return type to str
|
) -> str: # TODO: Fix this return type
|
||||||
if self._check_tool_repeated_usage(calling=calling): # type: ignore # _check_tool_repeated_usage of "ToolUsage" does not return a value (it only ever returns None)
|
tool_event = agentops.ToolEvent(name=calling.tool_name) if agentops else None
|
||||||
|
if self._check_tool_repeated_usage(calling=calling): # type: ignore # _check_tool_repeated_usage of "ToolUsage" does not return a value (it only ever returns None)
|
||||||
try:
|
try:
|
||||||
result = self._i18n.errors("task_repeated_usage").format(
|
result = self._i18n.errors("task_repeated_usage").format(
|
||||||
tool_names=self.tools_names
|
tool_names=self.tools_names
|
||||||
@@ -110,13 +117,13 @@ class ToolUsage:
|
|||||||
tool_name=tool.name,
|
tool_name=tool.name,
|
||||||
attempts=self._run_attempts,
|
attempts=self._run_attempts,
|
||||||
)
|
)
|
||||||
result = self._format_result(result=result) # type: ignore # "_format_result" of "ToolUsage" does not return a value (it only ever returns None)
|
result = self._format_result(result=result) # type: ignore # "_format_result" of "ToolUsage" does not return a value (it only ever returns None)
|
||||||
return result # type: ignore # Fix the reutrn type of this function
|
return result # type: ignore # Fix the reutrn type of this function
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
self.task.increment_tools_errors()
|
self.task.increment_tools_errors()
|
||||||
|
|
||||||
result = None # type: ignore # Incompatible types in assignment (expression has type "None", variable has type "str")
|
result = None # type: ignore # Incompatible types in assignment (expression has type "None", variable has type "str")
|
||||||
|
|
||||||
if self.tools_handler.cache:
|
if self.tools_handler.cache:
|
||||||
result = self.tools_handler.cache.read( # type: ignore # Incompatible types in assignment (expression has type "str | None", variable has type "str")
|
result = self.tools_handler.cache.read( # type: ignore # Incompatible types in assignment (expression has type "str | None", variable has type "str")
|
||||||
@@ -133,7 +140,7 @@ class ToolUsage:
|
|||||||
|
|
||||||
if calling.arguments:
|
if calling.arguments:
|
||||||
try:
|
try:
|
||||||
acceptable_args = tool.args_schema.schema()["properties"].keys() # type: ignore # Item "None" of "type[BaseModel] | None" has no attribute "schema"
|
acceptable_args = tool.args_schema.schema()["properties"].keys() # type: ignore # Item "None" of "type[BaseModel] | None" has no attribute "schema"
|
||||||
arguments = {
|
arguments = {
|
||||||
k: v
|
k: v
|
||||||
for k, v in calling.arguments.items()
|
for k, v in calling.arguments.items()
|
||||||
@@ -145,7 +152,7 @@ class ToolUsage:
|
|||||||
arguments = calling.arguments
|
arguments = calling.arguments
|
||||||
result = tool._run(**arguments)
|
result = tool._run(**arguments)
|
||||||
else:
|
else:
|
||||||
arguments = calling.arguments.values() # type: ignore # Incompatible types in assignment (expression has type "dict_values[str, Any]", variable has type "dict[str, Any]")
|
arguments = calling.arguments.values() # type: ignore # Incompatible types in assignment (expression has type "dict_values[str, Any]", variable has type "dict[str, Any]")
|
||||||
result = tool._run(*arguments)
|
result = tool._run(*arguments)
|
||||||
else:
|
else:
|
||||||
result = tool._run()
|
result = tool._run()
|
||||||
@@ -164,6 +171,10 @@ class ToolUsage:
|
|||||||
return error # type: ignore # No return value expected
|
return error # type: ignore # No return value expected
|
||||||
|
|
||||||
self.task.increment_tools_errors()
|
self.task.increment_tools_errors()
|
||||||
|
if agentops:
|
||||||
|
agentops.record(
|
||||||
|
agentops.ErrorEvent(exception=e, trigger_event=tool_event)
|
||||||
|
)
|
||||||
return self.use(calling=calling, tool_string=tool_string) # type: ignore # No return value expected
|
return self.use(calling=calling, tool_string=tool_string) # type: ignore # No return value expected
|
||||||
|
|
||||||
if self.tools_handler:
|
if self.tools_handler:
|
||||||
@@ -184,18 +195,20 @@ class ToolUsage:
|
|||||||
)
|
)
|
||||||
|
|
||||||
self._printer.print(content=f"\n\n{result}\n", color="purple")
|
self._printer.print(content=f"\n\n{result}\n", color="purple")
|
||||||
|
if agentops:
|
||||||
|
agentops.record(tool_event)
|
||||||
self._telemetry.tool_usage(
|
self._telemetry.tool_usage(
|
||||||
llm=self.function_calling_llm,
|
llm=self.function_calling_llm,
|
||||||
tool_name=tool.name,
|
tool_name=tool.name,
|
||||||
attempts=self._run_attempts,
|
attempts=self._run_attempts,
|
||||||
)
|
)
|
||||||
result = self._format_result(result=result) # type: ignore # "_format_result" of "ToolUsage" does not return a value (it only ever returns None)
|
result = self._format_result(result=result) # type: ignore # "_format_result" of "ToolUsage" does not return a value (it only ever returns None)
|
||||||
return result # type: ignore # No return value expected
|
return result # type: ignore # No return value expected
|
||||||
|
|
||||||
def _format_result(self, result: Any) -> None:
|
def _format_result(self, result: Any) -> None:
|
||||||
self.task.used_tools += 1
|
self.task.used_tools += 1
|
||||||
if self._should_remember_format(): # type: ignore # "_should_remember_format" of "ToolUsage" does not return a value (it only ever returns None)
|
if self._should_remember_format(): # type: ignore # "_should_remember_format" of "ToolUsage" does not return a value (it only ever returns None)
|
||||||
result = self._remember_format(result=result) # type: ignore # "_remember_format" of "ToolUsage" does not return a value (it only ever returns None)
|
result = self._remember_format(result=result) # type: ignore # "_remember_format" of "ToolUsage" does not return a value (it only ever returns None)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _should_remember_format(self) -> None:
|
def _should_remember_format(self) -> None:
|
||||||
|
|||||||
@@ -5,6 +5,17 @@ from pydantic import BaseModel, Field
|
|||||||
|
|
||||||
from crewai.utilities import Converter
|
from crewai.utilities import Converter
|
||||||
from crewai.utilities.pydantic_schema_parser import PydanticSchemaParser
|
from crewai.utilities.pydantic_schema_parser import PydanticSchemaParser
|
||||||
|
agentops = None
|
||||||
|
try:
|
||||||
|
import agentops
|
||||||
|
from agentops import track_agent
|
||||||
|
except ImportError:
|
||||||
|
|
||||||
|
def track_agent(name):
|
||||||
|
def noop(f):
|
||||||
|
return f
|
||||||
|
|
||||||
|
return noop
|
||||||
|
|
||||||
|
|
||||||
class Entity(BaseModel):
|
class Entity(BaseModel):
|
||||||
@@ -38,6 +49,7 @@ class TrainingTaskEvaluation(BaseModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@track_agent(name="Task Evaluator")
|
||||||
class TaskEvaluator:
|
class TaskEvaluator:
|
||||||
def __init__(self, original_agent):
|
def __init__(self, original_agent):
|
||||||
self.llm = original_agent.llm
|
self.llm = original_agent.llm
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from crewai.utilities.printer import Printer
|
from crewai.utilities.printer import Printer
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
class Logger:
|
class Logger:
|
||||||
_printer = Printer()
|
_printer = Printer()
|
||||||
|
|||||||
Reference in New Issue
Block a user