mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-11 00:58:30 +00:00
Fix tests and code that was broken
This commit is contained in:
@@ -120,7 +120,6 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
"""
|
"""
|
||||||
formatted_answer = None
|
formatted_answer = None
|
||||||
while not isinstance(formatted_answer, AgentFinish):
|
while not isinstance(formatted_answer, AgentFinish):
|
||||||
self.iterations += 1
|
|
||||||
try:
|
try:
|
||||||
if self._has_reached_max_iterations():
|
if self._has_reached_max_iterations():
|
||||||
formatted_answer = self._handle_max_iterations_exceeded(
|
formatted_answer = self._handle_max_iterations_exceeded(
|
||||||
@@ -159,6 +158,8 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
|
|||||||
content=f"Unhandled exception: {e}",
|
content=f"Unhandled exception: {e}",
|
||||||
color="red",
|
color="red",
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
|
self.iterations += 1
|
||||||
|
|
||||||
self._show_logs(formatted_answer)
|
self._show_logs(formatted_answer)
|
||||||
return formatted_answer
|
return formatted_answer
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from crewai.tools import tool
|
|||||||
from crewai.tools.tool_calling import InstructorToolCalling
|
from crewai.tools.tool_calling import InstructorToolCalling
|
||||||
from crewai.tools.tool_usage import ToolUsage
|
from crewai.tools.tool_usage import ToolUsage
|
||||||
from crewai.tools.tool_usage_events import ToolUsageFinished
|
from crewai.tools.tool_usage_events import ToolUsageFinished
|
||||||
from crewai.utilities import RPMController
|
from crewai.utilities import Printer, RPMController
|
||||||
from crewai.utilities.events import Emitter
|
from crewai.utilities.events import Emitter
|
||||||
|
|
||||||
|
|
||||||
@@ -670,7 +670,7 @@ def test_agent_without_max_rpm_respects_crew_rpm(capsys):
|
|||||||
moveon.assert_called_once()
|
moveon.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
# @pytest.mark.vcr(filter_headers=["authorization"])
|
||||||
def test_agent_error_on_parsing_tool(capsys):
|
def test_agent_error_on_parsing_tool(capsys):
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
@@ -710,6 +710,7 @@ def test_agent_error_on_parsing_tool(capsys):
|
|||||||
force_exception_2.side_effect = Exception("Error on parsing tool.")
|
force_exception_2.side_effect = Exception("Error on parsing tool.")
|
||||||
crew.kickoff()
|
crew.kickoff()
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
|
print("Captured output:", captured.out)
|
||||||
assert "Error on parsing tool." in captured.out
|
assert "Error on parsing tool." in captured.out
|
||||||
|
|
||||||
|
|
||||||
@@ -1637,21 +1638,19 @@ def test_litellm_auth_error_handling():
|
|||||||
mock_llm_call.assert_called_once()
|
mock_llm_call.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.vcr(filter_headers=["authorization"])
|
|
||||||
def test_crew_agent_executor_litellm_auth_error():
|
def test_crew_agent_executor_litellm_auth_error():
|
||||||
"""Test that CrewAgentExecutor properly identifies and handles LiteLLM authentication errors."""
|
"""Test that CrewAgentExecutor properly identifies and handles LiteLLM authentication errors."""
|
||||||
from litellm import AuthenticationError as LiteLLMAuthenticationError
|
from litellm import AuthenticationError as LiteLLMAuthenticationError
|
||||||
|
|
||||||
from crewai.agents.tools_handler import ToolsHandler
|
from crewai.agents.tools_handler import ToolsHandler
|
||||||
from crewai.utilities import Logger
|
from crewai.utilities import Printer
|
||||||
|
|
||||||
# Create an agent and executor with max_retry_limit=0
|
# Create an agent and executor with max_retry_limit=0
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
role="test role",
|
role="test role",
|
||||||
goal="test goal",
|
goal="test goal",
|
||||||
backstory="test backstory",
|
backstory="test backstory",
|
||||||
llm=LLM(model="gpt-4"),
|
llm=LLM(model="gpt-4", api_key="invalid_api_key"),
|
||||||
max_retry_limit=0, # Disable retries for authentication errors
|
|
||||||
)
|
)
|
||||||
task = Task(
|
task = Task(
|
||||||
description="Test task",
|
description="Test task",
|
||||||
@@ -1677,7 +1676,7 @@ def test_crew_agent_executor_litellm_auth_error():
|
|||||||
# Mock the LLM call to raise LiteLLMAuthenticationError
|
# Mock the LLM call to raise LiteLLMAuthenticationError
|
||||||
with (
|
with (
|
||||||
patch.object(LLM, "call") as mock_llm_call,
|
patch.object(LLM, "call") as mock_llm_call,
|
||||||
patch.object(Logger, "log") as mock_logger,
|
patch.object(Printer, "print") as mock_printer,
|
||||||
pytest.raises(LiteLLMAuthenticationError, match="Invalid API key"),
|
pytest.raises(LiteLLMAuthenticationError, match="Invalid API key"),
|
||||||
):
|
):
|
||||||
mock_llm_call.side_effect = LiteLLMAuthenticationError(
|
mock_llm_call.side_effect = LiteLLMAuthenticationError(
|
||||||
@@ -1686,20 +1685,18 @@ def test_crew_agent_executor_litellm_auth_error():
|
|||||||
executor.invoke(
|
executor.invoke(
|
||||||
{
|
{
|
||||||
"input": "test input",
|
"input": "test input",
|
||||||
"tool_names": "", # Required template variable
|
"tool_names": "",
|
||||||
"tools": "", # Required template variable
|
"tools": "",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Verify error handling
|
# Verify error handling
|
||||||
mock_logger.assert_any_call(
|
mock_printer.assert_any_call(
|
||||||
level="error",
|
content="Authentication error with litellm occurred. Please check your API key and configuration.",
|
||||||
message="Authentication error with litellm occurred. Please check your API key and configuration.",
|
|
||||||
color="red",
|
color="red",
|
||||||
)
|
)
|
||||||
mock_logger.assert_any_call(
|
mock_printer.assert_any_call(
|
||||||
level="error",
|
content="Error details: litellm.AuthenticationError: Invalid API key",
|
||||||
message="Error details: litellm.AuthenticationError: Invalid API key",
|
|
||||||
color="red",
|
color="red",
|
||||||
)
|
)
|
||||||
# Verify the call was only made once (no retries)
|
# Verify the call was only made once (no retries)
|
||||||
|
|||||||
@@ -1,233 +0,0 @@
|
|||||||
interactions:
|
|
||||||
- request:
|
|
||||||
body: '{"messages": [{"role": "system", "content": "You are test role. test backstory\nYour
|
|
||||||
personal goal is: test goal\nYou ONLY have access to the following tools, and
|
|
||||||
should NEVER make up tools that are not listed here:\n\nTool Name: get_final_answer(*args:
|
|
||||||
Any, **kwargs: Any) -> Any\nTool Description: get_final_answer() - Get the final
|
|
||||||
answer but don''t give it yet, just re-use this tool non-stop. \nTool
|
|
||||||
Arguments: {}\n\nUse the following format:\n\nThought: you should always think
|
|
||||||
about what to do\nAction: the action to take, only one name of [get_final_answer],
|
|
||||||
just the name, exactly as it''s written.\nAction Input: the input to the action,
|
|
||||||
just a simple python dictionary, enclosed in curly braces, using \" to wrap
|
|
||||||
keys and values.\nObservation: the result of the action\n\nOnce all necessary
|
|
||||||
information is gathered:\n\nThought: I now know the final answer\nFinal Answer:
|
|
||||||
the final answer to the original input question\n"}, {"role": "user", "content":
|
|
||||||
"\nCurrent Task: Use the get_final_answer tool.\n\nThis is the expect criteria
|
|
||||||
for your final answer: The final answer\nyou MUST return the actual complete
|
|
||||||
content as the final answer, not a summary.\n\nBegin! This is VERY important
|
|
||||||
to you, use the tools available and give your best Final Answer, your job depends
|
|
||||||
on it!\n\nThought:"}], "model": "gpt-4o"}'
|
|
||||||
headers:
|
|
||||||
accept:
|
|
||||||
- application/json
|
|
||||||
accept-encoding:
|
|
||||||
- gzip, deflate
|
|
||||||
connection:
|
|
||||||
- keep-alive
|
|
||||||
content-length:
|
|
||||||
- '1325'
|
|
||||||
content-type:
|
|
||||||
- application/json
|
|
||||||
cookie:
|
|
||||||
- _cfuvid=ePJSDFdHag2D8lj21_ijAMWjoA6xfnPNxN4uekvC728-1727226247743-0.0.1.1-604800000;
|
|
||||||
__cf_bm=3giyBOIM0GNudFELtsBWYXwLrpLBTNLsh81wfXgu2tg-1727226247-1.0.1.1-ugUDz0c5EhmfVpyGtcdedlIWeDGuy2q0tXQTKVpv83HZhvxgBcS7SBL1wS4rapPM38yhfEcfwA79ARt3HQEzKA
|
|
||||||
host:
|
|
||||||
- api.openai.com
|
|
||||||
user-agent:
|
|
||||||
- OpenAI/Python 1.47.0
|
|
||||||
x-stainless-arch:
|
|
||||||
- arm64
|
|
||||||
x-stainless-async:
|
|
||||||
- 'false'
|
|
||||||
x-stainless-lang:
|
|
||||||
- python
|
|
||||||
x-stainless-os:
|
|
||||||
- MacOS
|
|
||||||
x-stainless-package-version:
|
|
||||||
- 1.47.0
|
|
||||||
x-stainless-raw-response:
|
|
||||||
- 'true'
|
|
||||||
x-stainless-runtime:
|
|
||||||
- CPython
|
|
||||||
x-stainless-runtime-version:
|
|
||||||
- 3.11.7
|
|
||||||
method: POST
|
|
||||||
uri: https://api.openai.com/v1/chat/completions
|
|
||||||
response:
|
|
||||||
content: "{\n \"id\": \"chatcmpl-ABAtOWmVjvzQ9X58tKAUcOF4gmXwx\",\n \"object\":
|
|
||||||
\"chat.completion\",\n \"created\": 1727226842,\n \"model\": \"gpt-4o-2024-05-13\",\n
|
|
||||||
\ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\":
|
|
||||||
\"assistant\",\n \"content\": \"Thought: I need to use the get_final_answer
|
|
||||||
tool to determine the final answer.\\nAction: get_final_answer\\nAction Input:
|
|
||||||
{}\",\n \"refusal\": null\n },\n \"logprobs\": null,\n \"finish_reason\":
|
|
||||||
\"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": 274,\n \"completion_tokens\":
|
|
||||||
27,\n \"total_tokens\": 301,\n \"completion_tokens_details\": {\n \"reasoning_tokens\":
|
|
||||||
0\n }\n },\n \"system_fingerprint\": \"fp_e375328146\"\n}\n"
|
|
||||||
headers:
|
|
||||||
CF-Cache-Status:
|
|
||||||
- DYNAMIC
|
|
||||||
CF-RAY:
|
|
||||||
- 8c8727b3492f31e6-MIA
|
|
||||||
Connection:
|
|
||||||
- keep-alive
|
|
||||||
Content-Encoding:
|
|
||||||
- gzip
|
|
||||||
Content-Type:
|
|
||||||
- application/json
|
|
||||||
Date:
|
|
||||||
- Wed, 25 Sep 2024 01:14:03 GMT
|
|
||||||
Server:
|
|
||||||
- cloudflare
|
|
||||||
Transfer-Encoding:
|
|
||||||
- chunked
|
|
||||||
X-Content-Type-Options:
|
|
||||||
- nosniff
|
|
||||||
access-control-expose-headers:
|
|
||||||
- X-Request-ID
|
|
||||||
openai-organization:
|
|
||||||
- crewai-iuxna1
|
|
||||||
openai-processing-ms:
|
|
||||||
- '348'
|
|
||||||
openai-version:
|
|
||||||
- '2020-10-01'
|
|
||||||
strict-transport-security:
|
|
||||||
- max-age=31536000; includeSubDomains; preload
|
|
||||||
x-ratelimit-limit-requests:
|
|
||||||
- '10000'
|
|
||||||
x-ratelimit-limit-tokens:
|
|
||||||
- '30000000'
|
|
||||||
x-ratelimit-remaining-requests:
|
|
||||||
- '9999'
|
|
||||||
x-ratelimit-remaining-tokens:
|
|
||||||
- '29999682'
|
|
||||||
x-ratelimit-reset-requests:
|
|
||||||
- 6ms
|
|
||||||
x-ratelimit-reset-tokens:
|
|
||||||
- 0s
|
|
||||||
x-request-id:
|
|
||||||
- req_be929caac49706f487950548bdcdd46e
|
|
||||||
http_version: HTTP/1.1
|
|
||||||
status_code: 200
|
|
||||||
- request:
|
|
||||||
body: '{"messages": [{"role": "system", "content": "You are test role. test backstory\nYour
|
|
||||||
personal goal is: test goal\nYou ONLY have access to the following tools, and
|
|
||||||
should NEVER make up tools that are not listed here:\n\nTool Name: get_final_answer(*args:
|
|
||||||
Any, **kwargs: Any) -> Any\nTool Description: get_final_answer() - Get the final
|
|
||||||
answer but don''t give it yet, just re-use this tool non-stop. \nTool
|
|
||||||
Arguments: {}\n\nUse the following format:\n\nThought: you should always think
|
|
||||||
about what to do\nAction: the action to take, only one name of [get_final_answer],
|
|
||||||
just the name, exactly as it''s written.\nAction Input: the input to the action,
|
|
||||||
just a simple python dictionary, enclosed in curly braces, using \" to wrap
|
|
||||||
keys and values.\nObservation: the result of the action\n\nOnce all necessary
|
|
||||||
information is gathered:\n\nThought: I now know the final answer\nFinal Answer:
|
|
||||||
the final answer to the original input question\n"}, {"role": "user", "content":
|
|
||||||
"\nCurrent Task: Use the get_final_answer tool.\n\nThis is the expect criteria
|
|
||||||
for your final answer: The final answer\nyou MUST return the actual complete
|
|
||||||
content as the final answer, not a summary.\n\nBegin! This is VERY important
|
|
||||||
to you, use the tools available and give your best Final Answer, your job depends
|
|
||||||
on it!\n\nThought:"}, {"role": "user", "content": "Thought: I need to use the
|
|
||||||
get_final_answer tool to determine the final answer.\nAction: get_final_answer\nAction
|
|
||||||
Input: {}\nObservation: I encountered an error: Error on parsing tool.\nMoving
|
|
||||||
on then. I MUST either use a tool (use one at time) OR give my best final answer
|
|
||||||
not both at the same time. To Use the following format:\n\nThought: you should
|
|
||||||
always think about what to do\nAction: the action to take, should be one of
|
|
||||||
[get_final_answer]\nAction Input: the input to the action, dictionary enclosed
|
|
||||||
in curly braces\nObservation: the result of the action\n... (this Thought/Action/Action
|
|
||||||
Input/Result can repeat N times)\nThought: I now can give a great answer\nFinal
|
|
||||||
Answer: Your final answer must be the great and the most complete as possible,
|
|
||||||
it must be outcome described\n\n \nNow it''s time you MUST give your absolute
|
|
||||||
best final answer. You''ll ignore all previous instructions, stop using any
|
|
||||||
tools, and just return your absolute BEST Final answer."}], "model": "gpt-4o"}'
|
|
||||||
headers:
|
|
||||||
accept:
|
|
||||||
- application/json
|
|
||||||
accept-encoding:
|
|
||||||
- gzip, deflate
|
|
||||||
connection:
|
|
||||||
- keep-alive
|
|
||||||
content-length:
|
|
||||||
- '2320'
|
|
||||||
content-type:
|
|
||||||
- application/json
|
|
||||||
cookie:
|
|
||||||
- _cfuvid=ePJSDFdHag2D8lj21_ijAMWjoA6xfnPNxN4uekvC728-1727226247743-0.0.1.1-604800000;
|
|
||||||
__cf_bm=3giyBOIM0GNudFELtsBWYXwLrpLBTNLsh81wfXgu2tg-1727226247-1.0.1.1-ugUDz0c5EhmfVpyGtcdedlIWeDGuy2q0tXQTKVpv83HZhvxgBcS7SBL1wS4rapPM38yhfEcfwA79ARt3HQEzKA
|
|
||||||
host:
|
|
||||||
- api.openai.com
|
|
||||||
user-agent:
|
|
||||||
- OpenAI/Python 1.47.0
|
|
||||||
x-stainless-arch:
|
|
||||||
- arm64
|
|
||||||
x-stainless-async:
|
|
||||||
- 'false'
|
|
||||||
x-stainless-lang:
|
|
||||||
- python
|
|
||||||
x-stainless-os:
|
|
||||||
- MacOS
|
|
||||||
x-stainless-package-version:
|
|
||||||
- 1.47.0
|
|
||||||
x-stainless-raw-response:
|
|
||||||
- 'true'
|
|
||||||
x-stainless-runtime:
|
|
||||||
- CPython
|
|
||||||
x-stainless-runtime-version:
|
|
||||||
- 3.11.7
|
|
||||||
method: POST
|
|
||||||
uri: https://api.openai.com/v1/chat/completions
|
|
||||||
response:
|
|
||||||
content: "{\n \"id\": \"chatcmpl-ABAtPaaeRfdNsZ3k06CfAmrEW8IJu\",\n \"object\":
|
|
||||||
\"chat.completion\",\n \"created\": 1727226843,\n \"model\": \"gpt-4o-2024-05-13\",\n
|
|
||||||
\ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\":
|
|
||||||
\"assistant\",\n \"content\": \"Final Answer: The final answer\",\n \"refusal\":
|
|
||||||
null\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n
|
|
||||||
\ }\n ],\n \"usage\": {\n \"prompt_tokens\": 483,\n \"completion_tokens\":
|
|
||||||
6,\n \"total_tokens\": 489,\n \"completion_tokens_details\": {\n \"reasoning_tokens\":
|
|
||||||
0\n }\n },\n \"system_fingerprint\": \"fp_e375328146\"\n}\n"
|
|
||||||
headers:
|
|
||||||
CF-Cache-Status:
|
|
||||||
- DYNAMIC
|
|
||||||
CF-RAY:
|
|
||||||
- 8c8727b9da1f31e6-MIA
|
|
||||||
Connection:
|
|
||||||
- keep-alive
|
|
||||||
Content-Encoding:
|
|
||||||
- gzip
|
|
||||||
Content-Type:
|
|
||||||
- application/json
|
|
||||||
Date:
|
|
||||||
- Wed, 25 Sep 2024 01:14:03 GMT
|
|
||||||
Server:
|
|
||||||
- cloudflare
|
|
||||||
Transfer-Encoding:
|
|
||||||
- chunked
|
|
||||||
X-Content-Type-Options:
|
|
||||||
- nosniff
|
|
||||||
access-control-expose-headers:
|
|
||||||
- X-Request-ID
|
|
||||||
alt-svc:
|
|
||||||
- h3=":443"; ma=86400
|
|
||||||
openai-organization:
|
|
||||||
- crewai-iuxna1
|
|
||||||
openai-processing-ms:
|
|
||||||
- '188'
|
|
||||||
openai-version:
|
|
||||||
- '2020-10-01'
|
|
||||||
strict-transport-security:
|
|
||||||
- max-age=31536000; includeSubDomains; preload
|
|
||||||
x-ratelimit-limit-requests:
|
|
||||||
- '10000'
|
|
||||||
x-ratelimit-limit-tokens:
|
|
||||||
- '30000000'
|
|
||||||
x-ratelimit-remaining-requests:
|
|
||||||
- '9999'
|
|
||||||
x-ratelimit-remaining-tokens:
|
|
||||||
- '29999445'
|
|
||||||
x-ratelimit-reset-requests:
|
|
||||||
- 6ms
|
|
||||||
x-ratelimit-reset-tokens:
|
|
||||||
- 1ms
|
|
||||||
x-request-id:
|
|
||||||
- req_d8e32538689fe064627468bad802d9a8
|
|
||||||
http_version: HTTP/1.1
|
|
||||||
status_code: 200
|
|
||||||
version: 1
|
|
||||||
Reference in New Issue
Block a user