mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-10 00:28:31 +00:00
Better agent execution error handling (#54)
A few quality of life improvements around cache handling and repeated tool usage
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
from .cache_handler import CacheHandler
|
from .cache.cache_handler import CacheHandler
|
||||||
from .executor import CrewAgentExecutor
|
from .executor import CrewAgentExecutor
|
||||||
from .output_parser import CrewAgentOutputParser
|
from .output_parser import CrewAgentOutputParser
|
||||||
from .tools_handler import ToolsHandler
|
from .tools_handler import ToolsHandler
|
||||||
|
|||||||
2
crewai/agents/cache/__init__.py
vendored
Normal file
2
crewai/agents/cache/__init__.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from .cache_handler import CacheHandler
|
||||||
|
from .cache_hit import CacheHit
|
||||||
20
crewai/agents/exceptions.py
Normal file
20
crewai/agents/exceptions.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from langchain_core.exceptions import OutputParserException
|
||||||
|
|
||||||
|
|
||||||
|
class TaskRepeatedUsageException(OutputParserException):
|
||||||
|
"""Exception raised when a task is used twice in a roll."""
|
||||||
|
|
||||||
|
error: str = "TaskRepeatedUsageException"
|
||||||
|
message: str = "\nI just used the {tool} tool with input {tool_input}. So I already know the result of that.\n"
|
||||||
|
|
||||||
|
def __init__(self, tool: str, tool_input: str):
|
||||||
|
self.tool = tool
|
||||||
|
self.tool_input = tool_input
|
||||||
|
self.message = self.message.format(tool=tool, tool_input=tool_input)
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
error=self.error, observation=self.message, send_to_llm=True, llm_output=""
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.message
|
||||||
@@ -9,7 +9,7 @@ from langchain_core.exceptions import OutputParserException
|
|||||||
from langchain_core.tools import BaseTool
|
from langchain_core.tools import BaseTool
|
||||||
|
|
||||||
from ..tools.cache_tools import CacheTools
|
from ..tools.cache_tools import CacheTools
|
||||||
from .cache_hit import CacheHit
|
from .cache.cache_hit import CacheHit
|
||||||
|
|
||||||
|
|
||||||
class CrewAgentExecutor(AgentExecutor):
|
class CrewAgentExecutor(AgentExecutor):
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ from typing import Union
|
|||||||
|
|
||||||
from langchain.agents.output_parsers import ReActSingleInputOutputParser
|
from langchain.agents.output_parsers import ReActSingleInputOutputParser
|
||||||
from langchain_core.agents import AgentAction, AgentFinish
|
from langchain_core.agents import AgentAction, AgentFinish
|
||||||
from langchain_core.exceptions import OutputParserException
|
|
||||||
|
|
||||||
from .cache_handler import CacheHandler
|
from .cache import CacheHandler, CacheHit
|
||||||
from .cache_hit import CacheHit
|
from .exceptions import TaskRepeatedUsageException
|
||||||
from .tools_handler import ToolsHandler
|
from .tools_handler import ToolsHandler
|
||||||
|
|
||||||
FINAL_ANSWER_ACTION = "Final Answer:"
|
FINAL_ANSWER_ACTION = "Final Answer:"
|
||||||
@@ -67,9 +66,7 @@ class CrewAgentOutputParser(ReActSingleInputOutputParser):
|
|||||||
"input": tool_input,
|
"input": tool_input,
|
||||||
}
|
}
|
||||||
if usage == last_tool_usage:
|
if usage == last_tool_usage:
|
||||||
raise OutputParserException(
|
raise TaskRepeatedUsageException(tool=action, tool_input=tool_input)
|
||||||
f"""\nI just used the {action} tool with input {tool_input}. So I already know the result of that."""
|
|
||||||
)
|
|
||||||
|
|
||||||
result = self.cache.read(action, tool_input)
|
result = self.cache.read(action, tool_input)
|
||||||
if result:
|
if result:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from typing import Any, Dict
|
|||||||
from langchain.callbacks.base import BaseCallbackHandler
|
from langchain.callbacks.base import BaseCallbackHandler
|
||||||
|
|
||||||
from ..tools.cache_tools import CacheTools
|
from ..tools.cache_tools import CacheTools
|
||||||
from .cache_handler import CacheHandler
|
from .cache.cache_handler import CacheHandler
|
||||||
|
|
||||||
|
|
||||||
class ToolsHandler(BaseCallbackHandler):
|
class ToolsHandler(BaseCallbackHandler):
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
import uuid
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from pydantic import UUID4, BaseModel, Field, field_validator
|
|
||||||
from pydantic_core import PydanticCustomError
|
|
||||||
|
|
||||||
|
|
||||||
class CrewAIBaseModel(BaseModel):
|
|
||||||
"""Base model with unique identifier."""
|
|
||||||
|
|
||||||
__hash__ = object.__hash__
|
|
||||||
id: UUID4 = Field(
|
|
||||||
default_factory=uuid.uuid4,
|
|
||||||
frozen=True,
|
|
||||||
description="Unique identifier for the object, not set by user.",
|
|
||||||
)
|
|
||||||
|
|
||||||
@field_validator("id", mode="before")
|
|
||||||
@classmethod
|
|
||||||
def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
|
|
||||||
if v:
|
|
||||||
raise PydanticCustomError(
|
|
||||||
"may_not_set_field", "This field is not to be set by the user.", {}
|
|
||||||
)
|
|
||||||
@@ -15,7 +15,7 @@ from pydantic import (
|
|||||||
from pydantic_core import PydanticCustomError
|
from pydantic_core import PydanticCustomError
|
||||||
|
|
||||||
from crewai.agent import Agent
|
from crewai.agent import Agent
|
||||||
from crewai.agents import CacheHandler
|
from crewai.agents.cache import CacheHandler
|
||||||
from crewai.process import Process
|
from crewai.process import Process
|
||||||
from crewai.task import Task
|
from crewai.task import Task
|
||||||
from crewai.tools.agent_tools import AgentTools
|
from crewai.tools.agent_tools import AgentTools
|
||||||
|
|||||||
@@ -53,10 +53,10 @@ class AgentTools(BaseModel):
|
|||||||
try:
|
try:
|
||||||
agent, task, information = command.split("|")
|
agent, task, information = command.split("|")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`."
|
return "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`.\n"
|
||||||
|
|
||||||
if not agent or not task or not information:
|
if not agent or not task or not information:
|
||||||
return "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|question|information`."
|
return "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|question|information`.\n"
|
||||||
|
|
||||||
agent = [
|
agent = [
|
||||||
available_agent
|
available_agent
|
||||||
@@ -65,7 +65,7 @@ class AgentTools(BaseModel):
|
|||||||
]
|
]
|
||||||
|
|
||||||
if len(agent) == 0:
|
if len(agent) == 0:
|
||||||
return f"\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: {', '.join([agent.role for agent in self.agents])}."
|
return f"\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: {', '.join([agent.role for agent in self.agents])}.\n"
|
||||||
|
|
||||||
agent = agent[0]
|
agent = agent[0]
|
||||||
result = agent.execute_task(task, information)
|
result = agent.execute_task(task, information)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from langchain.tools import Tool
|
from langchain.tools import Tool
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
|
||||||
from crewai.agents import CacheHandler
|
from crewai.agents.cache import CacheHandler
|
||||||
|
|
||||||
|
|
||||||
class CacheTools(BaseModel):
|
class CacheTools(BaseModel):
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import pytest
|
|||||||
from langchain.chat_models import ChatOpenAI as OpenAI
|
from langchain.chat_models import ChatOpenAI as OpenAI
|
||||||
|
|
||||||
from crewai.agent import Agent
|
from crewai.agent import Agent
|
||||||
from crewai.agents import CacheHandler
|
from crewai.agents.cache import CacheHandler
|
||||||
|
|
||||||
|
|
||||||
def test_agent_creation():
|
def test_agent_creation():
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ def test_delegate_work_with_wrong_input():
|
|||||||
|
|
||||||
assert (
|
assert (
|
||||||
result
|
result
|
||||||
== "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`."
|
== "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`.\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ def test_delegate_work_to_wrong_agent():
|
|||||||
|
|
||||||
assert (
|
assert (
|
||||||
result
|
result
|
||||||
== "\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: researcher."
|
== "\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: researcher.\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -70,5 +70,5 @@ def test_ask_question_to_wrong_agent():
|
|||||||
|
|
||||||
assert (
|
assert (
|
||||||
result
|
result
|
||||||
== "\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: researcher."
|
== "\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: researcher.\n"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import json
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from crewai.agent import Agent
|
from crewai.agent import Agent
|
||||||
from crewai.agents import CacheHandler
|
from crewai.agents.cache import CacheHandler
|
||||||
from crewai.crew import Crew
|
from crewai.crew import Crew
|
||||||
from crewai.process import Process
|
from crewai.process import Process
|
||||||
from crewai.task import Task
|
from crewai.task import Task
|
||||||
|
|||||||
Reference in New Issue
Block a user