From 5f0af16616f125d7651e363241d5e1a7b1e6b97f Mon Sep 17 00:00:00 2001 From: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:16:26 -0700 Subject: [PATCH] fixed mixin (#831) * fixed mixin * WIP: fixing types * type fixes on mixin --- src/crewai/agents/agent_builder/base_agent.py | 3 +- .../base_agent_executor_mixin.py | 118 ++++++++++++------ src/crewai/agents/executor.py | 16 ++- 3 files changed, 96 insertions(+), 41 deletions(-) diff --git a/src/crewai/agents/agent_builder/base_agent.py b/src/crewai/agents/agent_builder/base_agent.py index 81375cdb8..65c9b661c 100644 --- a/src/crewai/agents/agent_builder/base_agent.py +++ b/src/crewai/agents/agent_builder/base_agent.py @@ -15,7 +15,8 @@ from pydantic import ( from pydantic_core import PydanticCustomError 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 diff --git a/src/crewai/agents/agent_builder/base_agent_executor_mixin.py b/src/crewai/agents/agent_builder/base_agent_executor_mixin.py index 7d31defaf..e3c0aa211 100644 --- a/src/crewai/agents/agent_builder/base_agent_executor_mixin.py +++ b/src/crewai/agents/agent_builder/base_agent_executor_mixin.py @@ -1,65 +1,109 @@ import time +from typing import TYPE_CHECKING, Optional from crewai.memory.entity.entity_memory_item import EntityMemoryItem from crewai.memory.long_term.long_term_memory_item import LongTermMemoryItem from crewai.memory.short_term.short_term_memory_item import ShortTermMemoryItem from crewai.utilities.converter import ConverterError 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: + 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: + """Determine if a forced answer is required based on iteration count.""" return ( self.iterations == self.force_answer_max_iterations ) and not self.have_forced_answer 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 ( self.crew 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( - data=output.log, - agent=self.crew_agent.role, - metadata={ - "observation": self.task.description, - }, - ) - self.crew._short_term_memory.save(memory) + try: + ltm_agent = TaskEvaluator(self.crew_agent) + evaluation = ltm_agent.evaluate(self.task, output.log) - def _create_long_term_memory(self, output) -> None: - if self.crew and self.crew.memory: - ltm_agent = TaskEvaluator(self.crew_agent) - evaluation = ltm_agent.evaluate(self.task, output.log) + if isinstance(evaluation, ConverterError): + return - if isinstance(evaluation, ConverterError): - return - - long_term_memory = LongTermMemoryItem( - task=self.task.description, - agent=self.crew_agent.role, - quality=evaluation.quality, - datetime=str(time.time()), - expected_output=self.task.expected_output, - 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]), + long_term_memory = LongTermMemoryItem( + task=self.task.description, + agent=self.crew_agent.role, + quality=evaluation.quality, + datetime=str(time.time()), + expected_output=self.task.expected_output, + metadata={ + "suggestions": evaluation.suggestions, + "quality": evaluation.quality, + }, ) - 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: - """Get human input.""" + """Prompt human input for final decision making.""" return input( self._i18n.slice("getting_input").format(final_answer=final_answer) ) diff --git a/src/crewai/agents/executor.py b/src/crewai/agents/executor.py index 365d04f78..192dc190e 100644 --- a/src/crewai/agents/executor.py +++ b/src/crewai/agents/executor.py @@ -1,6 +1,14 @@ import threading 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.agent import ExceptionTool @@ -11,13 +19,15 @@ from langchain_core.exceptions import OutputParserException from langchain_core.tools import BaseTool from langchain_core.utils.input import get_color_mapping 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.tools.tool_usage import ToolUsage, ToolUsageErrorException -from crewai.utilities import I18N from crewai.utilities.constants import TRAINING_DATA_FILE from crewai.utilities.training_handler import CrewTrainingHandler +from crewai.utilities import I18N class CrewAgentExecutor(AgentExecutor, CrewAgentExecutorMixin):