Using fingerprints (#2456)

* using fingerprints

* passing fingerptins on tools

* fix

* update lock

* Fix type checker errors

---------

Co-authored-by: Brandon Hancock <brandon@brandonhancock.io>
Co-authored-by: Brandon Hancock (bhancock_ai) <109994880+bhancockio@users.noreply.github.com>
Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com>
This commit is contained in:
João Moura
2025-03-26 14:54:23 -07:00
committed by GitHub
parent 48983773f5
commit e1a73e0c44
10 changed files with 458 additions and 36 deletions

View File

@@ -20,7 +20,6 @@ from crewai.utilities import I18N, Printer
from crewai.utilities.constants import MAX_LLM_RETRY, TRAINING_DATA_FILE from crewai.utilities.constants import MAX_LLM_RETRY, TRAINING_DATA_FILE
from crewai.utilities.events import ( from crewai.utilities.events import (
ToolUsageErrorEvent, ToolUsageErrorEvent,
ToolUsageStartedEvent,
crewai_event_bus, crewai_event_bus,
) )
from crewai.utilities.events.tool_usage_events import ToolUsageStartedEvent from crewai.utilities.events.tool_usage_events import ToolUsageStartedEvent
@@ -153,8 +152,21 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
formatted_answer = self._process_llm_response(answer) formatted_answer = self._process_llm_response(answer)
if isinstance(formatted_answer, AgentAction): if isinstance(formatted_answer, AgentAction):
# Extract agent fingerprint if available
fingerprint_context = {}
if (
self.agent
and hasattr(self.agent, "security_config")
and hasattr(self.agent.security_config, "fingerprint")
):
fingerprint_context = {
"agent_fingerprint": str(
self.agent.security_config.fingerprint
)
}
tool_result = self._execute_tool_and_check_finality( tool_result = self._execute_tool_and_check_finality(
formatted_answer formatted_answer, fingerprint_context=fingerprint_context
) )
formatted_answer = self._handle_agent_action( formatted_answer = self._handle_agent_action(
formatted_answer, tool_result formatted_answer, tool_result
@@ -360,19 +372,35 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
content=f"\033[95m## Final Answer:\033[00m \033[92m\n{formatted_answer.output}\033[00m\n\n" content=f"\033[95m## Final Answer:\033[00m \033[92m\n{formatted_answer.output}\033[00m\n\n"
) )
def _execute_tool_and_check_finality(self, agent_action: AgentAction) -> ToolResult: def _execute_tool_and_check_finality(
self,
agent_action: AgentAction,
fingerprint_context: Optional[Dict[str, str]] = None,
) -> ToolResult:
try: try:
fingerprint_context = fingerprint_context or {}
if self.agent: if self.agent:
# Create tool usage event with fingerprint information
event_data = {
"agent_key": self.agent.key,
"agent_role": self.agent.role,
"tool_name": agent_action.tool,
"tool_args": agent_action.tool_input,
"tool_class": agent_action.tool,
"agent": self.agent, # Pass the agent object for fingerprint extraction
}
# Include fingerprint context
if fingerprint_context:
event_data.update(fingerprint_context)
# Emit the tool usage started event with agent information
crewai_event_bus.emit( crewai_event_bus.emit(
self, self,
event=ToolUsageStartedEvent( event=ToolUsageStartedEvent(**event_data),
agent_key=self.agent.key,
agent_role=self.agent.role,
tool_name=agent_action.tool,
tool_args=agent_action.tool_input,
tool_class=agent_action.tool,
),
) )
tool_usage = ToolUsage( tool_usage = ToolUsage(
tools_handler=self.tools_handler, tools_handler=self.tools_handler,
tools=self.tools, tools=self.tools,
@@ -383,6 +411,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
task=self.task, # type: ignore[arg-type] task=self.task, # type: ignore[arg-type]
agent=self.agent, agent=self.agent,
action=agent_action, action=agent_action,
fingerprint_context=fingerprint_context, # Pass fingerprint context
) )
tool_calling = tool_usage.parse_tool_calling(agent_action.text) tool_calling = tool_usage.parse_tool_calling(agent_action.text)
@@ -411,16 +440,23 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
except Exception as e: except Exception as e:
# TODO: drop # TODO: drop
if self.agent: if self.agent:
error_event_data = {
"agent_key": self.agent.key,
"agent_role": self.agent.role,
"tool_name": agent_action.tool,
"tool_args": agent_action.tool_input,
"tool_class": agent_action.tool,
"error": str(e),
"agent": self.agent, # Pass the agent object for fingerprint extraction
}
# Include fingerprint context
if fingerprint_context:
error_event_data.update(fingerprint_context)
crewai_event_bus.emit( crewai_event_bus.emit(
self, self,
event=ToolUsageErrorEvent( # validation error event=ToolUsageErrorEvent(**error_event_data),
agent_key=self.agent.key,
agent_role=self.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

@@ -388,7 +388,7 @@ class Task(BaseModel):
tools = tools or self.tools or [] tools = tools or self.tools or []
self.processed_by_agents.add(agent.role) self.processed_by_agents.add(agent.role)
crewai_event_bus.emit(self, TaskStartedEvent(context=context)) crewai_event_bus.emit(self, TaskStartedEvent(context=context, task=self))
result = agent.execute_task( result = agent.execute_task(
task=self, task=self,
context=context, context=context,
@@ -464,11 +464,11 @@ class Task(BaseModel):
) )
) )
self._save_file(content) self._save_file(content)
crewai_event_bus.emit(self, TaskCompletedEvent(output=task_output)) crewai_event_bus.emit(self, TaskCompletedEvent(output=task_output, task=self))
return task_output return task_output
except Exception as e: except Exception as e:
self.end_time = datetime.datetime.now() self.end_time = datetime.datetime.now()
crewai_event_bus.emit(self, TaskFailedEvent(error=str(e))) crewai_event_bus.emit(self, TaskFailedEvent(error=str(e), task=self))
raise e # Re-raise the exception after emitting the event raise e # Re-raise the exception after emitting the event
def prompt(self) -> str: def prompt(self) -> str:

View File

@@ -112,6 +112,23 @@ class Telemetry:
self._add_attribute(span, "crew_memory", crew.memory) self._add_attribute(span, "crew_memory", crew.memory)
self._add_attribute(span, "crew_number_of_tasks", len(crew.tasks)) self._add_attribute(span, "crew_number_of_tasks", len(crew.tasks))
self._add_attribute(span, "crew_number_of_agents", len(crew.agents)) self._add_attribute(span, "crew_number_of_agents", len(crew.agents))
# Add fingerprint data
if hasattr(crew, "fingerprint") and crew.fingerprint:
self._add_attribute(span, "crew_fingerprint", crew.fingerprint.uuid_str)
self._add_attribute(
span,
"crew_fingerprint_created_at",
crew.fingerprint.created_at.isoformat(),
)
# Add fingerprint metadata if it exists
if hasattr(crew.fingerprint, "metadata") and crew.fingerprint.metadata:
self._add_attribute(
span,
"crew_fingerprint_metadata",
json.dumps(crew.fingerprint.metadata),
)
if crew.share_crew: if crew.share_crew:
self._add_attribute( self._add_attribute(
span, span,
@@ -129,17 +146,43 @@ class Telemetry:
"max_rpm": agent.max_rpm, "max_rpm": agent.max_rpm,
"i18n": agent.i18n.prompt_file, "i18n": agent.i18n.prompt_file,
"function_calling_llm": ( "function_calling_llm": (
agent.function_calling_llm.model getattr(
if agent.function_calling_llm getattr(agent, "function_calling_llm", None),
"model",
"",
)
if getattr(agent, "function_calling_llm", None)
else "" else ""
), ),
"llm": agent.llm.model, "llm": agent.llm.model,
"delegation_enabled?": agent.allow_delegation, "delegation_enabled?": agent.allow_delegation,
"allow_code_execution?": agent.allow_code_execution, "allow_code_execution?": getattr(
"max_retry_limit": agent.max_retry_limit, agent, "allow_code_execution", False
),
"max_retry_limit": getattr(agent, "max_retry_limit", 3),
"tools_names": [ "tools_names": [
tool.name.casefold() for tool in agent.tools or [] tool.name.casefold() for tool in agent.tools or []
], ],
# Add agent fingerprint data if sharing crew details
"fingerprint": (
getattr(
getattr(agent, "fingerprint", None),
"uuid_str",
None,
)
),
"fingerprint_created_at": (
created_at.isoformat()
if (
created_at := getattr(
getattr(agent, "fingerprint", None),
"created_at",
None,
)
)
is not None
else None
),
} }
for agent in crew.agents for agent in crew.agents
] ]
@@ -169,6 +212,17 @@ class Telemetry:
"tools_names": [ "tools_names": [
tool.name.casefold() for tool in task.tools or [] tool.name.casefold() for tool in task.tools or []
], ],
# Add task fingerprint data if sharing crew details
"fingerprint": (
task.fingerprint.uuid_str
if hasattr(task, "fingerprint") and task.fingerprint
else None
),
"fingerprint_created_at": (
task.fingerprint.created_at.isoformat()
if hasattr(task, "fingerprint") and task.fingerprint
else None
),
} }
for task in crew.tasks for task in crew.tasks
] ]
@@ -196,14 +250,20 @@ class Telemetry:
"max_iter": agent.max_iter, "max_iter": agent.max_iter,
"max_rpm": agent.max_rpm, "max_rpm": agent.max_rpm,
"function_calling_llm": ( "function_calling_llm": (
agent.function_calling_llm.model getattr(
if agent.function_calling_llm getattr(agent, "function_calling_llm", None),
"model",
"",
)
if getattr(agent, "function_calling_llm", None)
else "" else ""
), ),
"llm": agent.llm.model, "llm": agent.llm.model,
"delegation_enabled?": agent.allow_delegation, "delegation_enabled?": agent.allow_delegation,
"allow_code_execution?": agent.allow_code_execution, "allow_code_execution?": getattr(
"max_retry_limit": agent.max_retry_limit, agent, "allow_code_execution", False
),
"max_retry_limit": getattr(agent, "max_retry_limit", 3),
"tools_names": [ "tools_names": [
tool.name.casefold() for tool in agent.tools or [] tool.name.casefold() for tool in agent.tools or []
], ],
@@ -252,6 +312,39 @@ class Telemetry:
self._add_attribute(created_span, "task_key", task.key) self._add_attribute(created_span, "task_key", task.key)
self._add_attribute(created_span, "task_id", str(task.id)) self._add_attribute(created_span, "task_id", str(task.id))
# Add fingerprint data
if hasattr(crew, "fingerprint") and crew.fingerprint:
self._add_attribute(
created_span, "crew_fingerprint", crew.fingerprint.uuid_str
)
if hasattr(task, "fingerprint") and task.fingerprint:
self._add_attribute(
created_span, "task_fingerprint", task.fingerprint.uuid_str
)
self._add_attribute(
created_span,
"task_fingerprint_created_at",
task.fingerprint.created_at.isoformat(),
)
# Add fingerprint metadata if it exists
if hasattr(task.fingerprint, "metadata") and task.fingerprint.metadata:
self._add_attribute(
created_span,
"task_fingerprint_metadata",
json.dumps(task.fingerprint.metadata),
)
# Add agent fingerprint if task has an assigned agent
if hasattr(task, "agent") and task.agent:
agent_fingerprint = getattr(
getattr(task.agent, "fingerprint", None), "uuid_str", None
)
if agent_fingerprint:
self._add_attribute(
created_span, "agent_fingerprint", agent_fingerprint
)
if crew.share_crew: if crew.share_crew:
self._add_attribute( self._add_attribute(
created_span, "formatted_description", task.description created_span, "formatted_description", task.description
@@ -270,6 +363,21 @@ class Telemetry:
self._add_attribute(span, "task_key", task.key) self._add_attribute(span, "task_key", task.key)
self._add_attribute(span, "task_id", str(task.id)) self._add_attribute(span, "task_id", str(task.id))
# Add fingerprint data to execution span
if hasattr(crew, "fingerprint") and crew.fingerprint:
self._add_attribute(span, "crew_fingerprint", crew.fingerprint.uuid_str)
if hasattr(task, "fingerprint") and task.fingerprint:
self._add_attribute(span, "task_fingerprint", task.fingerprint.uuid_str)
# Add agent fingerprint if task has an assigned agent
if hasattr(task, "agent") and task.agent:
agent_fingerprint = getattr(
getattr(task.agent, "fingerprint", None), "uuid_str", None
)
if agent_fingerprint:
self._add_attribute(span, "agent_fingerprint", agent_fingerprint)
if crew.share_crew: if crew.share_crew:
self._add_attribute(span, "formatted_description", task.description) self._add_attribute(span, "formatted_description", task.description)
self._add_attribute( self._add_attribute(
@@ -291,7 +399,12 @@ class Telemetry:
Note: Note:
If share_crew is enabled, this will also record the task output If share_crew is enabled, this will also record the task output
""" """
def operation(): def operation():
# Ensure fingerprint data is present on completion span
if hasattr(task, "fingerprint") and task.fingerprint:
self._add_attribute(span, "task_fingerprint", task.fingerprint.uuid_str)
if crew.share_crew: if crew.share_crew:
self._add_attribute( self._add_attribute(
span, span,
@@ -312,6 +425,7 @@ class Telemetry:
tool_name (str): Name of the tool being repeatedly used tool_name (str): Name of the tool being repeatedly used
attempts (int): Number of attempts made with this tool attempts (int): Number of attempts made with this tool
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Tool Repeated Usage") span = tracer.start_span("Tool Repeated Usage")
@@ -329,14 +443,16 @@ class Telemetry:
self._safe_telemetry_operation(operation) self._safe_telemetry_operation(operation)
def tool_usage(self, llm: Any, tool_name: str, attempts: int): def tool_usage(self, llm: Any, tool_name: str, attempts: int, agent: Any = None):
"""Records the usage of a tool by an agent. """Records the usage of a tool by an agent.
Args: Args:
llm (Any): The language model being used llm (Any): The language model being used
tool_name (str): Name of the tool being used tool_name (str): Name of the tool being used
attempts (int): Number of attempts made with this tool attempts (int): Number of attempts made with this tool
agent (Any, optional): The agent using the tool
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Tool Usage") span = tracer.start_span("Tool Usage")
@@ -349,17 +465,31 @@ class Telemetry:
self._add_attribute(span, "attempts", attempts) self._add_attribute(span, "attempts", attempts)
if llm: if llm:
self._add_attribute(span, "llm", llm.model) self._add_attribute(span, "llm", llm.model)
# Add agent fingerprint data if available
if agent and hasattr(agent, "fingerprint") and agent.fingerprint:
self._add_attribute(
span, "agent_fingerprint", agent.fingerprint.uuid_str
)
if hasattr(agent, "role"):
self._add_attribute(span, "agent_role", agent.role)
span.set_status(Status(StatusCode.OK)) span.set_status(Status(StatusCode.OK))
span.end() span.end()
self._safe_telemetry_operation(operation) self._safe_telemetry_operation(operation)
def tool_usage_error(self, llm: Any): def tool_usage_error(
self, llm: Any, agent: Any = None, tool_name: Optional[str] = None
):
"""Records when a tool usage results in an error. """Records when a tool usage results in an error.
Args: Args:
llm (Any): The language model being used when the error occurred llm (Any): The language model being used when the error occurred
agent (Any, optional): The agent using the tool
tool_name (str, optional): Name of the tool that caused the error
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Tool Usage Error") span = tracer.start_span("Tool Usage Error")
@@ -370,6 +500,18 @@ class Telemetry:
) )
if llm: if llm:
self._add_attribute(span, "llm", llm.model) self._add_attribute(span, "llm", llm.model)
if tool_name:
self._add_attribute(span, "tool_name", tool_name)
# Add agent fingerprint data if available
if agent and hasattr(agent, "fingerprint") and agent.fingerprint:
self._add_attribute(
span, "agent_fingerprint", agent.fingerprint.uuid_str
)
if hasattr(agent, "role"):
self._add_attribute(span, "agent_role", agent.role)
span.set_status(Status(StatusCode.OK)) span.set_status(Status(StatusCode.OK))
span.end() span.end()
@@ -386,6 +528,7 @@ class Telemetry:
exec_time (int): Execution time in seconds exec_time (int): Execution time in seconds
model_name (str): Name of the model used model_name (str): Name of the model used
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Crew Individual Test Result") span = tracer.start_span("Crew Individual Test Result")
@@ -420,6 +563,7 @@ class Telemetry:
inputs (dict[str, Any] | None): Input parameters for the test inputs (dict[str, Any] | None): Input parameters for the test
model_name (str): Name of the model used in testing model_name (str): Name of the model used in testing
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Crew Test Execution") span = tracer.start_span("Crew Test Execution")
@@ -446,6 +590,7 @@ class Telemetry:
def deploy_signup_error_span(self): def deploy_signup_error_span(self):
"""Records when an error occurs during the deployment signup process.""" """Records when an error occurs during the deployment signup process."""
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Deploy Signup Error") span = tracer.start_span("Deploy Signup Error")
@@ -460,6 +605,7 @@ class Telemetry:
Args: Args:
uuid (Optional[str]): Unique identifier for the deployment uuid (Optional[str]): Unique identifier for the deployment
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Start Deployment") span = tracer.start_span("Start Deployment")
@@ -472,6 +618,7 @@ class Telemetry:
def create_crew_deployment_span(self): def create_crew_deployment_span(self):
"""Records the creation of a new crew deployment.""" """Records the creation of a new crew deployment."""
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Create Crew Deployment") span = tracer.start_span("Create Crew Deployment")
@@ -487,6 +634,7 @@ class Telemetry:
uuid (Optional[str]): Unique identifier for the crew uuid (Optional[str]): Unique identifier for the crew
log_type (str, optional): Type of logs being retrieved. Defaults to "deployment". log_type (str, optional): Type of logs being retrieved. Defaults to "deployment".
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Get Crew Logs") span = tracer.start_span("Get Crew Logs")
@@ -504,6 +652,7 @@ class Telemetry:
Args: Args:
uuid (Optional[str]): Unique identifier for the crew being removed uuid (Optional[str]): Unique identifier for the crew being removed
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Remove Crew") span = tracer.start_span("Remove Crew")
@@ -634,6 +783,7 @@ class Telemetry:
Args: Args:
flow_name (str): Name of the flow being created flow_name (str): Name of the flow being created
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Flow Creation") span = tracer.start_span("Flow Creation")
@@ -650,6 +800,7 @@ class Telemetry:
flow_name (str): Name of the flow being plotted flow_name (str): Name of the flow being plotted
node_names (list[str]): List of node names in the flow node_names (list[str]): List of node names in the flow
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Flow Plotting") span = tracer.start_span("Flow Plotting")
@@ -667,6 +818,7 @@ class Telemetry:
flow_name (str): Name of the flow being executed flow_name (str): Name of the flow being executed
node_names (list[str]): List of nodes being executed in the flow node_names (list[str]): List of nodes being executed in the flow
""" """
def operation(): def operation():
tracer = trace.get_tracer("crewai.telemetry") tracer = trace.get_tracer("crewai.telemetry")
span = tracer.start_span("Flow Execution") span = tracer.start_span("Flow Execution")

View File

@@ -22,6 +22,7 @@ from crewai.utilities.events.tool_usage_events import (
ToolSelectionErrorEvent, ToolSelectionErrorEvent,
ToolUsageErrorEvent, ToolUsageErrorEvent,
ToolUsageFinishedEvent, ToolUsageFinishedEvent,
ToolUsageStartedEvent,
ToolValidateInputErrorEvent, ToolValidateInputErrorEvent,
) )
@@ -69,6 +70,7 @@ class ToolUsage:
function_calling_llm: Any, function_calling_llm: Any,
agent: Any, agent: Any,
action: Any, action: Any,
fingerprint_context: Optional[Dict[str, str]] = None,
) -> None: ) -> None:
self._i18n: I18N = agent.i18n self._i18n: I18N = agent.i18n
self._printer: Printer = Printer() self._printer: Printer = Printer()
@@ -85,6 +87,7 @@ class ToolUsage:
self.task = task self.task = task
self.action = action self.action = action
self.function_calling_llm = function_calling_llm self.function_calling_llm = function_calling_llm
self.fingerprint_context = fingerprint_context or {}
# Set the maximum parsing attempts for bigger models # Set the maximum parsing attempts for bigger models
if ( if (
@@ -192,12 +195,18 @@ class ToolUsage:
for k, v in calling.arguments.items() for k, v in calling.arguments.items()
if k in acceptable_args if k in acceptable_args
} }
# Add fingerprint metadata if available
arguments = self._add_fingerprint_metadata(arguments)
result = tool.invoke(input=arguments) result = tool.invoke(input=arguments)
except Exception: except Exception:
arguments = calling.arguments arguments = calling.arguments
# Add fingerprint metadata if available
arguments = self._add_fingerprint_metadata(arguments)
result = tool.invoke(input=arguments) result = tool.invoke(input=arguments)
else: else:
result = tool.invoke(input={}) # Add fingerprint metadata even to empty arguments
arguments = self._add_fingerprint_metadata({})
result = tool.invoke(input=arguments)
except Exception as e: except Exception as e:
self.on_tool_error(tool=tool, tool_calling=calling, e=e) self.on_tool_error(tool=tool, tool_calling=calling, e=e)
self._run_attempts += 1 self._run_attempts += 1
@@ -486,8 +495,13 @@ class ToolUsage:
"tool_name": self.action.tool, "tool_name": self.action.tool,
"tool_args": str(self.action.tool_input), "tool_args": str(self.action.tool_input),
"tool_class": self.__class__.__name__, "tool_class": self.__class__.__name__,
"agent": self.agent, # Adding agent for fingerprint extraction
} }
# Include fingerprint context if available
if self.fingerprint_context:
tool_selection_data.update(self.fingerprint_context)
crewai_event_bus.emit( crewai_event_bus.emit(
self, self,
ToolValidateInputErrorEvent(**tool_selection_data, error=final_error), ToolValidateInputErrorEvent(**tool_selection_data, error=final_error),
@@ -518,7 +532,7 @@ class ToolUsage:
crewai_event_bus.emit(self, ToolUsageFinishedEvent(**event_data)) crewai_event_bus.emit(self, ToolUsageFinishedEvent(**event_data))
def _prepare_event_data(self, tool: Any, tool_calling: ToolCalling) -> dict: def _prepare_event_data(self, tool: Any, tool_calling: ToolCalling) -> dict:
return { event_data = {
"agent_key": self.agent.key, "agent_key": self.agent.key,
"agent_role": (self.agent._original_role or self.agent.role), "agent_role": (self.agent._original_role or self.agent.role),
"run_attempts": self._run_attempts, "run_attempts": self._run_attempts,
@@ -526,4 +540,43 @@ class ToolUsage:
"tool_name": tool.name, "tool_name": tool.name,
"tool_args": tool_calling.arguments, "tool_args": tool_calling.arguments,
"tool_class": tool.__class__.__name__, "tool_class": tool.__class__.__name__,
"agent": self.agent, # Adding agent for fingerprint extraction
} }
# Include fingerprint context if available
if self.fingerprint_context:
event_data.update(self.fingerprint_context)
return event_data
def _add_fingerprint_metadata(self, arguments: dict) -> dict:
"""Add fingerprint metadata to tool arguments if available.
Args:
arguments: The original tool arguments
Returns:
Updated arguments dictionary with fingerprint metadata
"""
# Create a shallow copy to avoid modifying the original
arguments = arguments.copy()
# Add security metadata under a designated key
if not "security_context" in arguments:
arguments["security_context"] = {}
security_context = arguments["security_context"]
# Add agent fingerprint if available
if hasattr(self, "agent") and hasattr(self.agent, "security_config"):
security_context["agent_fingerprint"] = self.agent.security_config.fingerprint.to_dict()
# Add task fingerprint if available
if hasattr(self, "task") and hasattr(self.task, "security_config"):
security_context["task_fingerprint"] = self.task.security_config.fingerprint.to_dict()
# Add crew fingerprint if available
if hasattr(self, "crew") and hasattr(self.crew, "security_config"):
security_context["crew_fingerprint"] = self.crew.security_config.fingerprint.to_dict()
return arguments

View File

@@ -45,7 +45,7 @@ class TaskEvaluator:
def evaluate(self, task, output) -> TaskEvaluation: def evaluate(self, task, output) -> TaskEvaluation:
crewai_event_bus.emit( crewai_event_bus.emit(
self, TaskEvaluationEvent(evaluation_type="task_evaluation") self, TaskEvaluationEvent(evaluation_type="task_evaluation", task=task)
) )
evaluation_query = ( evaluation_query = (
f"Assess the quality of the task completed based on the description, expected output, and actual results.\n\n" f"Assess the quality of the task completed based on the description, expected output, and actual results.\n\n"

View File

@@ -21,6 +21,15 @@ class AgentExecutionStartedEvent(CrewEvent):
model_config = {"arbitrary_types_allowed": True} model_config = {"arbitrary_types_allowed": True}
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the agent
if hasattr(self.agent, 'fingerprint') and self.agent.fingerprint:
self.source_fingerprint = self.agent.fingerprint.uuid_str
self.source_type = "agent"
if hasattr(self.agent.fingerprint, 'metadata') and self.agent.fingerprint.metadata:
self.fingerprint_metadata = self.agent.fingerprint.metadata
class AgentExecutionCompletedEvent(CrewEvent): class AgentExecutionCompletedEvent(CrewEvent):
"""Event emitted when an agent completes executing a task""" """Event emitted when an agent completes executing a task"""
@@ -30,6 +39,15 @@ class AgentExecutionCompletedEvent(CrewEvent):
output: str output: str
type: str = "agent_execution_completed" type: str = "agent_execution_completed"
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the agent
if hasattr(self.agent, 'fingerprint') and self.agent.fingerprint:
self.source_fingerprint = self.agent.fingerprint.uuid_str
self.source_type = "agent"
if hasattr(self.agent.fingerprint, 'metadata') and self.agent.fingerprint.metadata:
self.fingerprint_metadata = self.agent.fingerprint.metadata
class AgentExecutionErrorEvent(CrewEvent): class AgentExecutionErrorEvent(CrewEvent):
"""Event emitted when an agent encounters an error during execution""" """Event emitted when an agent encounters an error during execution"""
@@ -38,3 +56,12 @@ class AgentExecutionErrorEvent(CrewEvent):
task: Any task: Any
error: str error: str
type: str = "agent_execution_error" type: str = "agent_execution_error"
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the agent
if hasattr(self.agent, 'fingerprint') and self.agent.fingerprint:
self.source_fingerprint = self.agent.fingerprint.uuid_str
self.source_type = "agent"
if hasattr(self.agent.fingerprint, 'metadata') and self.agent.fingerprint.metadata:
self.fingerprint_metadata = self.agent.fingerprint.metadata

View File

@@ -1,4 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import Any, Dict, Optional
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@@ -8,3 +9,6 @@ class CrewEvent(BaseModel):
timestamp: datetime = Field(default_factory=datetime.now) timestamp: datetime = Field(default_factory=datetime.now)
type: str type: str
source_fingerprint: Optional[str] = None # UUID string of the source entity
source_type: Optional[str] = None # "agent", "task", "crew"
fingerprint_metadata: Optional[Dict[str, Any]] = None # Any relevant metadata

View File

@@ -11,6 +11,16 @@ class CrewKickoffStartedEvent(CrewEvent):
crew_name: Optional[str] crew_name: Optional[str]
inputs: Optional[Dict[str, Any]] inputs: Optional[Dict[str, Any]]
type: str = "crew_kickoff_started" type: str = "crew_kickoff_started"
crew: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the crew
if self.crew and hasattr(self.crew, 'fingerprint') and self.crew.fingerprint:
self.source_fingerprint = self.crew.fingerprint.uuid_str
self.source_type = "crew"
if hasattr(self.crew.fingerprint, 'metadata') and self.crew.fingerprint.metadata:
self.fingerprint_metadata = self.crew.fingerprint.metadata
class CrewKickoffCompletedEvent(CrewEvent): class CrewKickoffCompletedEvent(CrewEvent):
@@ -19,6 +29,16 @@ class CrewKickoffCompletedEvent(CrewEvent):
crew_name: Optional[str] crew_name: Optional[str]
output: Any output: Any
type: str = "crew_kickoff_completed" type: str = "crew_kickoff_completed"
crew: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the crew
if self.crew and hasattr(self.crew, 'fingerprint') and self.crew.fingerprint:
self.source_fingerprint = self.crew.fingerprint.uuid_str
self.source_type = "crew"
if hasattr(self.crew.fingerprint, 'metadata') and self.crew.fingerprint.metadata:
self.fingerprint_metadata = self.crew.fingerprint.metadata
class CrewKickoffFailedEvent(CrewEvent): class CrewKickoffFailedEvent(CrewEvent):
@@ -27,6 +47,16 @@ class CrewKickoffFailedEvent(CrewEvent):
error: str error: str
crew_name: Optional[str] crew_name: Optional[str]
type: str = "crew_kickoff_failed" type: str = "crew_kickoff_failed"
crew: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the crew
if self.crew and hasattr(self.crew, 'fingerprint') and self.crew.fingerprint:
self.source_fingerprint = self.crew.fingerprint.uuid_str
self.source_type = "crew"
if hasattr(self.crew.fingerprint, 'metadata') and self.crew.fingerprint.metadata:
self.fingerprint_metadata = self.crew.fingerprint.metadata
class CrewTrainStartedEvent(CrewEvent): class CrewTrainStartedEvent(CrewEvent):
@@ -37,6 +67,16 @@ class CrewTrainStartedEvent(CrewEvent):
filename: str filename: str
inputs: Optional[Dict[str, Any]] inputs: Optional[Dict[str, Any]]
type: str = "crew_train_started" type: str = "crew_train_started"
crew: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the crew
if self.crew and hasattr(self.crew, 'fingerprint') and self.crew.fingerprint:
self.source_fingerprint = self.crew.fingerprint.uuid_str
self.source_type = "crew"
if hasattr(self.crew.fingerprint, 'metadata') and self.crew.fingerprint.metadata:
self.fingerprint_metadata = self.crew.fingerprint.metadata
class CrewTrainCompletedEvent(CrewEvent): class CrewTrainCompletedEvent(CrewEvent):
@@ -46,6 +86,16 @@ class CrewTrainCompletedEvent(CrewEvent):
n_iterations: int n_iterations: int
filename: str filename: str
type: str = "crew_train_completed" type: str = "crew_train_completed"
crew: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the crew
if self.crew and hasattr(self.crew, 'fingerprint') and self.crew.fingerprint:
self.source_fingerprint = self.crew.fingerprint.uuid_str
self.source_type = "crew"
if hasattr(self.crew.fingerprint, 'metadata') and self.crew.fingerprint.metadata:
self.fingerprint_metadata = self.crew.fingerprint.metadata
class CrewTrainFailedEvent(CrewEvent): class CrewTrainFailedEvent(CrewEvent):
@@ -54,6 +104,16 @@ class CrewTrainFailedEvent(CrewEvent):
error: str error: str
crew_name: Optional[str] crew_name: Optional[str]
type: str = "crew_train_failed" type: str = "crew_train_failed"
crew: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the crew
if self.crew and hasattr(self.crew, 'fingerprint') and self.crew.fingerprint:
self.source_fingerprint = self.crew.fingerprint.uuid_str
self.source_type = "crew"
if hasattr(self.crew.fingerprint, 'metadata') and self.crew.fingerprint.metadata:
self.fingerprint_metadata = self.crew.fingerprint.metadata
class CrewTestStartedEvent(CrewEvent): class CrewTestStartedEvent(CrewEvent):
@@ -64,6 +124,16 @@ class CrewTestStartedEvent(CrewEvent):
eval_llm: Optional[Union[str, Any]] eval_llm: Optional[Union[str, Any]]
inputs: Optional[Dict[str, Any]] inputs: Optional[Dict[str, Any]]
type: str = "crew_test_started" type: str = "crew_test_started"
crew: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the crew
if self.crew and hasattr(self.crew, 'fingerprint') and self.crew.fingerprint:
self.source_fingerprint = self.crew.fingerprint.uuid_str
self.source_type = "crew"
if hasattr(self.crew.fingerprint, 'metadata') and self.crew.fingerprint.metadata:
self.fingerprint_metadata = self.crew.fingerprint.metadata
class CrewTestCompletedEvent(CrewEvent): class CrewTestCompletedEvent(CrewEvent):
@@ -71,6 +141,16 @@ class CrewTestCompletedEvent(CrewEvent):
crew_name: Optional[str] crew_name: Optional[str]
type: str = "crew_test_completed" type: str = "crew_test_completed"
crew: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the crew
if self.crew and hasattr(self.crew, 'fingerprint') and self.crew.fingerprint:
self.source_fingerprint = self.crew.fingerprint.uuid_str
self.source_type = "crew"
if hasattr(self.crew.fingerprint, 'metadata') and self.crew.fingerprint.metadata:
self.fingerprint_metadata = self.crew.fingerprint.metadata
class CrewTestFailedEvent(CrewEvent): class CrewTestFailedEvent(CrewEvent):
@@ -79,3 +159,13 @@ class CrewTestFailedEvent(CrewEvent):
error: str error: str
crew_name: Optional[str] crew_name: Optional[str]
type: str = "crew_test_failed" type: str = "crew_test_failed"
crew: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the crew
if self.crew and hasattr(self.crew, 'fingerprint') and self.crew.fingerprint:
self.source_fingerprint = self.crew.fingerprint.uuid_str
self.source_type = "crew"
if hasattr(self.crew.fingerprint, 'metadata') and self.crew.fingerprint.metadata:
self.fingerprint_metadata = self.crew.fingerprint.metadata

View File

@@ -1,4 +1,4 @@
from typing import Optional from typing import Any, Optional
from crewai.tasks.task_output import TaskOutput from crewai.tasks.task_output import TaskOutput
from crewai.utilities.events.base_events import CrewEvent from crewai.utilities.events.base_events import CrewEvent
@@ -9,6 +9,16 @@ class TaskStartedEvent(CrewEvent):
type: str = "task_started" type: str = "task_started"
context: Optional[str] context: Optional[str]
task: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the task
if hasattr(self.task, 'fingerprint') and self.task.fingerprint:
self.source_fingerprint = self.task.fingerprint.uuid_str
self.source_type = "task"
if hasattr(self.task.fingerprint, 'metadata') and self.task.fingerprint.metadata:
self.fingerprint_metadata = self.task.fingerprint.metadata
class TaskCompletedEvent(CrewEvent): class TaskCompletedEvent(CrewEvent):
@@ -16,6 +26,16 @@ class TaskCompletedEvent(CrewEvent):
output: TaskOutput output: TaskOutput
type: str = "task_completed" type: str = "task_completed"
task: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the task
if hasattr(self.task, 'fingerprint') and self.task.fingerprint:
self.source_fingerprint = self.task.fingerprint.uuid_str
self.source_type = "task"
if hasattr(self.task.fingerprint, 'metadata') and self.task.fingerprint.metadata:
self.fingerprint_metadata = self.task.fingerprint.metadata
class TaskFailedEvent(CrewEvent): class TaskFailedEvent(CrewEvent):
@@ -23,6 +43,16 @@ class TaskFailedEvent(CrewEvent):
error: str error: str
type: str = "task_failed" type: str = "task_failed"
task: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the task
if hasattr(self.task, 'fingerprint') and self.task.fingerprint:
self.source_fingerprint = self.task.fingerprint.uuid_str
self.source_type = "task"
if hasattr(self.task.fingerprint, 'metadata') and self.task.fingerprint.metadata:
self.fingerprint_metadata = self.task.fingerprint.metadata
class TaskEvaluationEvent(CrewEvent): class TaskEvaluationEvent(CrewEvent):
@@ -30,3 +60,13 @@ class TaskEvaluationEvent(CrewEvent):
type: str = "task_evaluation" type: str = "task_evaluation"
evaluation_type: str evaluation_type: str
task: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the task
if hasattr(self.task, 'fingerprint') and self.task.fingerprint:
self.source_fingerprint = self.task.fingerprint.uuid_str
self.source_type = "task"
if hasattr(self.task.fingerprint, 'metadata') and self.task.fingerprint.metadata:
self.fingerprint_metadata = self.task.fingerprint.metadata

View File

@@ -1,5 +1,5 @@
from datetime import datetime from datetime import datetime
from typing import Any, Callable, Dict from typing import Any, Callable, Dict, Optional
from .base_events import CrewEvent from .base_events import CrewEvent
@@ -14,9 +14,19 @@ class ToolUsageEvent(CrewEvent):
tool_class: str tool_class: str
run_attempts: int | None = None run_attempts: int | None = None
delegations: int | None = None delegations: int | None = None
agent: Optional[Any] = None
model_config = {"arbitrary_types_allowed": True} model_config = {"arbitrary_types_allowed": True}
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the agent
if self.agent and hasattr(self.agent, 'fingerprint') and self.agent.fingerprint:
self.source_fingerprint = self.agent.fingerprint.uuid_str
self.source_type = "agent"
if hasattr(self.agent.fingerprint, 'metadata') and self.agent.fingerprint.metadata:
self.fingerprint_metadata = self.agent.fingerprint.metadata
class ToolUsageStartedEvent(ToolUsageEvent): class ToolUsageStartedEvent(ToolUsageEvent):
"""Event emitted when a tool execution is started""" """Event emitted when a tool execution is started"""
@@ -63,3 +73,13 @@ class ToolExecutionErrorEvent(CrewEvent):
tool_name: str tool_name: str
tool_args: Dict[str, Any] tool_args: Dict[str, Any]
tool_class: Callable tool_class: Callable
agent: Optional[Any] = None
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the agent
if self.agent and hasattr(self.agent, 'fingerprint') and self.agent.fingerprint:
self.source_fingerprint = self.agent.fingerprint.uuid_str
self.source_type = "agent"
if hasattr(self.agent.fingerprint, 'metadata') and self.agent.fingerprint.metadata:
self.fingerprint_metadata = self.agent.fingerprint.metadata