Compare commits

...

10 Commits

Author SHA1 Message Date
Eduardo Chiarotti
59fb59a397 Merge branch 'main' into feat/trace-ui-exec-3 2025-04-11 13:08:56 -04:00
Eduardo Chiarotti
12054b63db Merge branch 'main' into feat/trace-ui-exec-3 2025-04-11 12:06:31 -04:00
Eduardo Chiarotti
aa9f35bdbc feat: remove cassete 2025-04-11 13:06:09 -03:00
Eduardo Chiarotti
9435ede5ff feat: remove test from tool execution erro: 2025-04-11 09:01:59 -03:00
Eduardo Chiarotti
e3e2e24110 feat: Remove not needed event 2025-04-11 08:58:27 -03:00
Eduardo Chiarotti
a65b58a44a Merge branch 'main' into feat/trace-ui-exec-3 2025-04-10 15:05:55 -04:00
Eduardo Chiarotti
a557d43b64 feat: remove unused logic 2025-04-10 15:59:43 -03:00
Eduardo Chiarotti
b0e63bd78e feat: add agent refernece inside liteagent 2025-04-10 15:57:57 -03:00
Eduardo Chiarotti
5e4a8ca987 feat: run lint 2025-04-10 15:17:30 -03:00
Eduardo Chiarotti
4b9be2fc26 feat: remove unused code and change ToolUsageStarted event place 2025-04-10 15:14:43 -03:00
8 changed files with 23 additions and 251 deletions

View File

@@ -482,6 +482,7 @@ class Agent(BaseAgent):
verbose=self.verbose, verbose=self.verbose,
response_format=response_format, response_format=response_format,
i18n=self.i18n, i18n=self.i18n,
original_agent=self,
) )
return lite_agent.kickoff(messages) return lite_agent.kickoff(messages)

View File

@@ -47,11 +47,6 @@ from crewai.utilities.events.llm_events import (
LLMCallStartedEvent, LLMCallStartedEvent,
LLMCallType, LLMCallType,
) )
from crewai.utilities.events.tool_usage_events import (
ToolUsageErrorEvent,
ToolUsageFinishedEvent,
ToolUsageStartedEvent,
)
from crewai.utilities.llm_utils import create_llm from crewai.utilities.llm_utils import create_llm
from crewai.utilities.printer import Printer from crewai.utilities.printer import Printer
from crewai.utilities.token_counter_callback import TokenCalcHandler from crewai.utilities.token_counter_callback import TokenCalcHandler
@@ -155,6 +150,10 @@ class LiteAgent(BaseModel):
default=[], description="Results of the tools used by the agent." default=[], description="Results of the tools used by the agent."
) )
# Reference of Agent
original_agent: Optional[BaseAgent] = Field(
default=None, description="Reference to the agent that created this LiteAgent"
)
# Private Attributes # Private Attributes
_parsed_tools: List[CrewStructuredTool] = PrivateAttr(default_factory=list) _parsed_tools: List[CrewStructuredTool] = PrivateAttr(default_factory=list)
_token_process: TokenProcess = PrivateAttr(default_factory=TokenProcess) _token_process: TokenProcess = PrivateAttr(default_factory=TokenProcess)
@@ -163,7 +162,7 @@ class LiteAgent(BaseModel):
_messages: List[Dict[str, str]] = PrivateAttr(default_factory=list) _messages: List[Dict[str, str]] = PrivateAttr(default_factory=list)
_iterations: int = PrivateAttr(default=0) _iterations: int = PrivateAttr(default=0)
_printer: Printer = PrivateAttr(default_factory=Printer) _printer: Printer = PrivateAttr(default_factory=Printer)
@model_validator(mode="after") @model_validator(mode="after")
def setup_llm(self): def setup_llm(self):
"""Set up the LLM and other components after initialization.""" """Set up the LLM and other components after initialization."""
@@ -412,18 +411,6 @@ class LiteAgent(BaseModel):
formatted_answer = process_llm_response(answer, self.use_stop_words) formatted_answer = process_llm_response(answer, self.use_stop_words)
if isinstance(formatted_answer, AgentAction): if isinstance(formatted_answer, AgentAction):
# Emit tool usage started event
crewai_event_bus.emit(
self,
event=ToolUsageStartedEvent(
agent_key=self.key,
agent_role=self.role,
tool_name=formatted_answer.tool,
tool_args=formatted_answer.tool_input,
tool_class=formatted_answer.tool,
),
)
try: try:
tool_result = execute_tool_and_check_finality( tool_result = execute_tool_and_check_finality(
agent_action=formatted_answer, agent_action=formatted_answer,
@@ -431,34 +418,9 @@ class LiteAgent(BaseModel):
i18n=self.i18n, i18n=self.i18n,
agent_key=self.key, agent_key=self.key,
agent_role=self.role, agent_role=self.role,
) agent=self.original_agent,
# Emit tool usage finished event
crewai_event_bus.emit(
self,
event=ToolUsageFinishedEvent(
agent_key=self.key,
agent_role=self.role,
tool_name=formatted_answer.tool,
tool_args=formatted_answer.tool_input,
tool_class=formatted_answer.tool,
started_at=datetime.now(),
finished_at=datetime.now(),
output=tool_result.result,
),
) )
except Exception as e: except Exception as e:
# Emit tool usage error event
crewai_event_bus.emit(
self,
event=ToolUsageErrorEvent(
agent_key=self.key,
agent_role=self.role,
tool_name=formatted_answer.tool,
tool_args=formatted_answer.tool_input,
tool_class=formatted_answer.tool,
error=str(e),
),
)
raise e raise e
formatted_answer = handle_agent_action_core( formatted_answer = handle_agent_action_core(

View File

@@ -707,15 +707,6 @@ class LLM(BaseLLM):
function_name, lambda: None function_name, lambda: None
) # Ensure fn is always a callable ) # Ensure fn is always a callable
logging.error(f"Error executing function '{function_name}': {e}") logging.error(f"Error executing function '{function_name}': {e}")
crewai_event_bus.emit(
self,
event=ToolExecutionErrorEvent(
tool_name=function_name,
tool_args=function_args,
tool_class=fn,
error=str(e),
),
)
crewai_event_bus.emit( crewai_event_bus.emit(
self, self,
event=LLMCallFailedEvent(error=f"Tool execution error: {str(e)}"), event=LLMCallFailedEvent(error=f"Tool execution error: {str(e)}"),

View File

@@ -2,7 +2,6 @@ import ast
import datetime import datetime
import json import json
import time import time
from dataclasses import dataclass
from difflib import SequenceMatcher from difflib import SequenceMatcher
from json import JSONDecodeError from json import JSONDecodeError
from textwrap import dedent from textwrap import dedent
@@ -26,6 +25,7 @@ from crewai.utilities.events.tool_usage_events import (
ToolSelectionErrorEvent, ToolSelectionErrorEvent,
ToolUsageErrorEvent, ToolUsageErrorEvent,
ToolUsageFinishedEvent, ToolUsageFinishedEvent,
ToolUsageStartedEvent,
ToolValidateInputErrorEvent, ToolValidateInputErrorEvent,
) )
@@ -166,6 +166,21 @@ class ToolUsage:
if self.task: if self.task:
self.task.increment_tools_errors() self.task.increment_tools_errors()
if self.agent:
event_data = {
"agent_key": self.agent.key,
"agent_role": self.agent.role,
"tool_name": self.action.tool,
"tool_args": self.action.tool_input,
"tool_class": self.action.tool,
"agent": self.agent,
}
if self.agent.fingerprint:
event_data.update(self.agent.fingerprint)
crewai_event_bus.emit(self,ToolUsageStartedEvent(**event_data))
started_at = time.time() started_at = time.time()
from_cache = False from_cache = False
result = None # type: ignore result = None # type: ignore

View File

@@ -16,7 +16,6 @@ from crewai.tools.base_tool import BaseTool
from crewai.tools.structured_tool import CrewStructuredTool from crewai.tools.structured_tool import CrewStructuredTool
from crewai.tools.tool_types import ToolResult from crewai.tools.tool_types import ToolResult
from crewai.utilities import I18N, Printer from crewai.utilities import I18N, Printer
from crewai.utilities.events.tool_usage_events import ToolUsageStartedEvent
from crewai.utilities.exceptions.context_window_exceeding_exception import ( from crewai.utilities.exceptions.context_window_exceeding_exception import (
LLMContextLengthExceededException, LLMContextLengthExceededException,
) )

View File

@@ -5,11 +5,6 @@ from crewai.security import Fingerprint
from crewai.tools.structured_tool import CrewStructuredTool from crewai.tools.structured_tool import CrewStructuredTool
from crewai.tools.tool_types import ToolResult from crewai.tools.tool_types import ToolResult
from crewai.tools.tool_usage import ToolUsage, ToolUsageErrorException from crewai.tools.tool_usage import ToolUsage, ToolUsageErrorException
from crewai.utilities.events import crewai_event_bus
from crewai.utilities.events.tool_usage_events import (
ToolUsageErrorEvent,
ToolUsageStartedEvent,
)
from crewai.utilities.i18n import I18N from crewai.utilities.i18n import I18N
@@ -42,10 +37,8 @@ def execute_tool_and_check_finality(
ToolResult containing the execution result and whether it should be treated as a final answer ToolResult containing the execution result and whether it should be treated as a final answer
""" """
try: try:
# Create tool name to tool map
tool_name_to_tool_map = {tool.name: tool for tool in tools} tool_name_to_tool_map = {tool.name: tool for tool in tools}
# Emit tool usage event if agent info is available
if agent_key and agent_role and agent: if agent_key and agent_role and agent:
fingerprint_context = fingerprint_context or {} fingerprint_context = fingerprint_context or {}
if agent: if agent:
@@ -59,22 +52,6 @@ def execute_tool_and_check_finality(
except Exception as e: except Exception as e:
raise ValueError(f"Failed to set fingerprint: {e}") raise ValueError(f"Failed to set fingerprint: {e}")
event_data = {
"agent_key": agent_key,
"agent_role": agent_role,
"tool_name": agent_action.tool,
"tool_args": agent_action.tool_input,
"tool_class": agent_action.tool,
"agent": agent,
}
event_data.update(fingerprint_context)
crewai_event_bus.emit(
agent,
event=ToolUsageStartedEvent(
**event_data,
),
)
# Create tool usage instance # Create tool usage instance
tool_usage = ToolUsage( tool_usage = ToolUsage(
tools_handler=tools_handler, tools_handler=tools_handler,
@@ -110,17 +87,4 @@ def execute_tool_and_check_finality(
return ToolResult(tool_result, False) return ToolResult(tool_result, False)
except Exception as e: except Exception as e:
# Emit error event if agent info is available
if agent_key and agent_role and agent:
crewai_event_bus.emit(
agent,
event=ToolUsageErrorEvent(
agent_key=agent_key,
agent_role=agent_role,
tool_name=agent_action.tool,
tool_args=agent_action.tool_input,
tool_class=agent_action.tool,
error=str(e),
),
)
raise e raise e

View File

@@ -1,112 +0,0 @@
interactions:
- request:
body: '{"messages": [{"role": "user", "content": "Use the failing tool"}], "model":
"gpt-4o-mini", "stop": [], "tools": [{"type": "function", "function": {"name":
"failing_tool", "description": "This tool always fails.", "parameters": {"type":
"object", "properties": {"param": {"type": "string", "description": "A test
parameter"}}, "required": ["param"]}}}]}'
headers:
accept:
- application/json
accept-encoding:
- gzip, deflate
connection:
- keep-alive
content-length:
- '353'
content-type:
- application/json
host:
- api.openai.com
user-agent:
- OpenAI/Python 1.61.0
x-stainless-arch:
- arm64
x-stainless-async:
- 'false'
x-stainless-lang:
- python
x-stainless-os:
- MacOS
x-stainless-package-version:
- 1.61.0
x-stainless-raw-response:
- 'true'
x-stainless-retry-count:
- '0'
x-stainless-runtime:
- CPython
x-stainless-runtime-version:
- 3.12.8
method: POST
uri: https://api.openai.com/v1/chat/completions
response:
content: "{\n \"id\": \"chatcmpl-B2P4zoJZuES7Aom8ugEq1modz5Vsl\",\n \"object\":
\"chat.completion\",\n \"created\": 1739912761,\n \"model\": \"gpt-4o-mini-2024-07-18\",\n
\ \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\":
\"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n
\ \"id\": \"call_F6fJxISpMKUBIGV6dd2vjRNG\",\n \"type\":
\"function\",\n \"function\": {\n \"name\": \"failing_tool\",\n
\ \"arguments\": \"{\\\"param\\\":\\\"test\\\"}\"\n }\n
\ }\n ],\n \"refusal\": null\n },\n \"logprobs\":
null,\n \"finish_reason\": \"tool_calls\"\n }\n ],\n \"usage\": {\n
\ \"prompt_tokens\": 51,\n \"completion_tokens\": 15,\n \"total_tokens\":
66,\n \"prompt_tokens_details\": {\n \"cached_tokens\": 0,\n \"audio_tokens\":
0\n },\n \"completion_tokens_details\": {\n \"reasoning_tokens\":
0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": 0,\n \"rejected_prediction_tokens\":
0\n }\n },\n \"service_tier\": \"default\",\n \"system_fingerprint\":
\"fp_00428b782a\"\n}\n"
headers:
CF-RAY:
- 9140fa827f38eb1e-SJC
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Tue, 18 Feb 2025 21:06:02 GMT
Server:
- cloudflare
Set-Cookie:
- __cf_bm=xbuu3IQpCMh.43ZrqL1TRMECOc6QldgHV0hzOX1GrWI-1739912762-1.0.1.1-t7iyq5xMioPrwfeaHLvPT9rwRPp7Q9A9uIm69icH9dPxRD4xMA3cWqb1aXj1_e2IyAEQQWFe1UWjlmJ22aHh3Q;
path=/; expires=Tue, 18-Feb-25 21:36:02 GMT; domain=.api.openai.com; HttpOnly;
Secure; SameSite=None
- _cfuvid=x9l.Rhja8_wXDN.j8qcEU1PvvEqAwZp4Fd3s_aj4qwM-1739912762161-0.0.1.1-604800000;
path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
Transfer-Encoding:
- chunked
X-Content-Type-Options:
- nosniff
access-control-expose-headers:
- X-Request-ID
alt-svc:
- h3=":443"; ma=86400
cf-cache-status:
- DYNAMIC
openai-organization:
- crewai-iuxna1
openai-processing-ms:
- '861'
openai-version:
- '2020-10-01'
strict-transport-security:
- max-age=31536000; includeSubDomains; preload
x-ratelimit-limit-requests:
- '30000'
x-ratelimit-limit-tokens:
- '150000000'
x-ratelimit-remaining-requests:
- '29999'
x-ratelimit-remaining-tokens:
- '149999978'
x-ratelimit-reset-requests:
- 2ms
x-ratelimit-reset-tokens:
- 0s
x-request-id:
- req_8666ec3aa6677cb346ba00993556051d
http_version: HTTP/1.1
status_code: 200
version: 1

View File

@@ -395,51 +395,3 @@ def test_deepseek_r1_with_open_router():
result = llm.call("What is the capital of France?") result = llm.call("What is the capital of France?")
assert isinstance(result, str) assert isinstance(result, str)
assert "Paris" in result assert "Paris" in result
@pytest.mark.vcr(filter_headers=["authorization"])
def test_tool_execution_error_event():
llm = LLM(model="gpt-4o-mini")
def failing_tool(param: str) -> str:
"""This tool always fails."""
raise Exception("Tool execution failed!")
tool_schema = {
"type": "function",
"function": {
"name": "failing_tool",
"description": "This tool always fails.",
"parameters": {
"type": "object",
"properties": {
"param": {"type": "string", "description": "A test parameter"}
},
"required": ["param"],
},
},
}
received_events = []
@crewai_event_bus.on(ToolExecutionErrorEvent)
def event_handler(source, event):
received_events.append(event)
available_functions = {"failing_tool": failing_tool}
messages = [{"role": "user", "content": "Use the failing tool"}]
llm.call(
messages,
tools=[tool_schema],
available_functions=available_functions,
)
assert len(received_events) == 1
event = received_events[0]
assert isinstance(event, ToolExecutionErrorEvent)
assert event.tool_name == "failing_tool"
assert event.tool_args == {"param": "test"}
assert event.tool_class == failing_tool
assert "Tool execution failed!" in event.error