Compare commits

...

7 Commits

Author SHA1 Message Date
Brandon Hancock
78164b4f73 Merge branch 'bugfix/litellm-plus-generic-excpetions' into bugfix/drop-user-warnings 2025-01-24 15:35:13 -05:00
Brandon Hancock
a367a96ab9 clean up test 2025-01-24 15:04:06 -05:00
Brandon Hancock
63ce0c91f9 Fix error 2025-01-24 14:58:04 -05:00
Brandon Hancock
e125b136b9 More clean up 2025-01-24 12:06:50 -05:00
Brandon Hancock
63fcc74faf Merge branch 'main' into bugfix/litellm-plus-generic-excpetions 2025-01-24 11:54:47 -05:00
Brandon Hancock
0cba344976 wip 2025-01-24 11:54:05 -05:00
Brandon Hancock
319da2129a WIP 2025-01-23 23:48:36 -05:00
6 changed files with 70 additions and 22 deletions

View File

@@ -1,15 +1,12 @@
import os
import shutil
import subprocess
from typing import Any, Dict, List, Literal, Optional, Union
from litellm import AuthenticationError as LiteLLMAuthenticationError
from pydantic import Field, InstanceOf, PrivateAttr, model_validator
from crewai.agents import CacheHandler
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.crew_agent_executor import CrewAgentExecutor
from crewai.cli.constants import ENV_VARS, LITELLM_PARAMS
from crewai.knowledge.knowledge import Knowledge
from crewai.knowledge.source.base_knowledge_source import BaseKnowledgeSource
from crewai.knowledge.utils.knowledge_utils import extract_knowledge_context
@@ -262,8 +259,8 @@ class Agent(BaseAgent):
}
)["output"]
except Exception as e:
if isinstance(e, LiteLLMAuthenticationError):
# Do not retry on authentication errors
if e.__class__.__module__.startswith("litellm"):
# Do not retry on litellm errors
raise e
self._times_executed += 1
if self._times_executed > self.max_retry_limit:

View File

@@ -3,8 +3,6 @@ import re
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Optional, Union
from litellm.exceptions import AuthenticationError as LiteLLMAuthenticationError
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.agents.agent_builder.base_agent_executor_mixin import CrewAgentExecutorMixin
from crewai.agents.parser import (
@@ -103,7 +101,12 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
try:
formatted_answer = self._invoke_loop()
except Exception as e:
raise e
if e.__class__.__module__.startswith("litellm"):
# Do not retry on litellm errors
raise e
else:
self._handle_unknown_error(e)
raise e
if self.ask_for_human_input:
formatted_answer = self._handle_human_feedback(formatted_answer)
@@ -146,6 +149,9 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
formatted_answer = self._handle_output_parser_exception(e)
except Exception as e:
if e.__class__.__module__.startswith("litellm"):
# Do not retry on litellm errors
raise e
if self._is_context_length_exceeded(e):
self._handle_context_length()
continue

View File

@@ -1,3 +1,11 @@
import warnings
warnings.filterwarnings(
"ignore",
message="Valid config keys have changed in V2*",
category=UserWarning,
)
import os
from importlib.metadata import version as get_version
from typing import Optional, Tuple

View File

@@ -11,6 +11,7 @@ def run_crew() -> None:
"""
Run the crew by running a command in the UV environment.
"""
click.echo("Running crew hello...")
command = ["uv", "run", "run_crew"]
crewai_version = get_crewai_version()
min_required_version = "0.71.0"

View File

@@ -57,9 +57,6 @@ except ImportError:
agentops = None
warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")
class Crew(BaseModel):
"""
Represents a group of agents, defining how they should collaborate and the tasks they should perform.

View File

@@ -1623,7 +1623,7 @@ def test_litellm_auth_error_handling():
agent=agent,
)
# Mock the LLM call to raise LiteLLMAuthenticationError
# Mock the LLM call to raise AuthenticationError
with (
patch.object(LLM, "call") as mock_llm_call,
pytest.raises(LiteLLMAuthenticationError, match="Invalid API key"),
@@ -1639,7 +1639,7 @@ def test_litellm_auth_error_handling():
def test_crew_agent_executor_litellm_auth_error():
"""Test that CrewAgentExecutor handles LiteLLM authentication errors by raising them."""
from litellm import AuthenticationError as LiteLLMAuthenticationError
from litellm.exceptions import AuthenticationError
from crewai.agents.tools_handler import ToolsHandler
from crewai.utilities import Printer
@@ -1672,13 +1672,13 @@ def test_crew_agent_executor_litellm_auth_error():
tools_handler=ToolsHandler(),
)
# Mock the LLM call to raise LiteLLMAuthenticationError
# Mock the LLM call to raise AuthenticationError
with (
patch.object(LLM, "call") as mock_llm_call,
patch.object(Printer, "print") as mock_printer,
pytest.raises(LiteLLMAuthenticationError, match="Invalid API key"),
pytest.raises(AuthenticationError) as exc_info,
):
mock_llm_call.side_effect = LiteLLMAuthenticationError(
mock_llm_call.side_effect = AuthenticationError(
message="Invalid API key", llm_provider="openai", model="gpt-4"
)
executor.invoke(
@@ -1689,14 +1689,53 @@ def test_crew_agent_executor_litellm_auth_error():
}
)
# Verify error handling
# Verify error handling messages
error_message = f"Error during LLM call: {str(mock_llm_call.side_effect)}"
mock_printer.assert_any_call(
content="An unknown error occurred. Please check the details below.",
color="red",
)
mock_printer.assert_any_call(
content="Error details: litellm.AuthenticationError: Invalid API key",
content=error_message,
color="red",
)
# Verify the call was only made once (no retries)
mock_llm_call.assert_called_once()
# Assert that the exception was raised and has the expected attributes
assert exc_info.type is AuthenticationError
assert "Invalid API key".lower() in exc_info.value.message.lower()
assert exc_info.value.llm_provider == "openai"
assert exc_info.value.model == "gpt-4"
def test_litellm_anthropic_error_handling():
"""Test that AnthropicError from LiteLLM is handled correctly and not retried."""
from litellm.llms.anthropic.common_utils import AnthropicError
# Create an agent with a mocked LLM that uses an Anthropic model
agent = Agent(
role="test role",
goal="test goal",
backstory="test backstory",
llm=LLM(model="claude-3.5-sonnet-20240620"),
max_retry_limit=0,
)
# Create a task
task = Task(
description="Test task",
expected_output="Test output",
agent=agent,
)
# Mock the LLM call to raise AnthropicError
with (
patch.object(LLM, "call") as mock_llm_call,
pytest.raises(AnthropicError, match="Test Anthropic error"),
):
mock_llm_call.side_effect = AnthropicError(
status_code=500,
message="Test Anthropic error",
)
agent.execute_task(task)
# Verify the LLM call was only made once (no retries)
mock_llm_call.assert_called_once()