refactor: resolve name via model_validator

This commit is contained in:
Renato Nitta
2026-04-21 12:31:06 -03:00
parent 402f45078a
commit 4b018a2b5b
6 changed files with 26 additions and 28 deletions

View File

@@ -546,6 +546,13 @@ class Crew(FlowTrackable, BaseModel):
# TODO: Improve typing # TODO: Improve typing
return json.loads(v) if isinstance(v, Json) else v # type: ignore return json.loads(v) if isinstance(v, Json) else v # type: ignore
@model_validator(mode="after")
def _resolve_name(self) -> Self:
"""Fall back to the class name when no explicit name is provided."""
if self.name is None:
self.name = type(self).__name__
return self
@model_validator(mode="after") @model_validator(mode="after")
def set_private_attrs(self) -> Crew: def set_private_attrs(self) -> Crew:
"""set private attributes.""" """set private attributes."""
@@ -581,8 +588,8 @@ class Crew(FlowTrackable, BaseModel):
""" """
from crewai.memory.utils import sanitize_scope_name from crewai.memory.utils import sanitize_scope_name
# Compute sanitized crew name for root_scope # `name` is guaranteed non-None by the `_resolve_name` validator.
crew_name = sanitize_scope_name(self.name or "crew") crew_name = sanitize_scope_name(cast(str, self.name))
crew_root_scope = f"/crew/{crew_name}" crew_root_scope = f"/crew/{crew_name}"
if self.memory is True: if self.memory is True:
@@ -786,11 +793,6 @@ class Crew(FlowTrackable, BaseModel):
) )
return self return self
@property
def display_name(self) -> str:
"""Effective crew name for telemetry and UI, falling back to class name."""
return self.name or type(self).__name__
@property @property
def key(self) -> str: def key(self) -> str:
source: list[str] = [agent.key for agent in self.agents] + [ source: list[str] = [agent.key for agent in self.agents] + [
@@ -858,7 +860,7 @@ class Crew(FlowTrackable, BaseModel):
crewai_event_bus.emit( crewai_event_bus.emit(
self, self,
CrewTrainStartedEvent( CrewTrainStartedEvent(
crew_name=self.display_name, crew_name=self.name,
n_iterations=n_iterations, n_iterations=n_iterations,
filename=filename, filename=filename,
inputs=inputs, inputs=inputs,
@@ -886,7 +888,7 @@ class Crew(FlowTrackable, BaseModel):
crewai_event_bus.emit( crewai_event_bus.emit(
self, self,
CrewTrainCompletedEvent( CrewTrainCompletedEvent(
crew_name=self.display_name, crew_name=self.name,
n_iterations=n_iterations, n_iterations=n_iterations,
filename=filename, filename=filename,
), ),
@@ -896,7 +898,7 @@ class Crew(FlowTrackable, BaseModel):
self, self,
CrewTrainFailedEvent( CrewTrainFailedEvent(
error=str(e), error=str(e),
crew_name=self.display_name, crew_name=self.name,
), ),
) )
self._logger.log("error", f"Training failed: {e}", color="red") self._logger.log("error", f"Training failed: {e}", color="red")
@@ -982,7 +984,7 @@ class Crew(FlowTrackable, BaseModel):
self, self,
CrewKickoffFailedEvent( CrewKickoffFailedEvent(
error=str(e), error=str(e),
crew_name=self.display_name, crew_name=self.name,
started_event_id=self._kickoff_event_id, started_event_id=self._kickoff_event_id,
), ),
) )
@@ -1193,7 +1195,7 @@ class Crew(FlowTrackable, BaseModel):
self, self,
CrewKickoffFailedEvent( CrewKickoffFailedEvent(
error=str(e), error=str(e),
crew_name=self.display_name, crew_name=self.name,
started_event_id=self._kickoff_event_id, started_event_id=self._kickoff_event_id,
), ),
) )
@@ -1799,7 +1801,7 @@ class Crew(FlowTrackable, BaseModel):
crewai_event_bus.emit( crewai_event_bus.emit(
self, self,
CrewKickoffCompletedEvent( CrewKickoffCompletedEvent(
crew_name=self.display_name, crew_name=self.name,
output=final_task_output, output=final_task_output,
total_tokens=self.token_usage.total_tokens, total_tokens=self.token_usage.total_tokens,
started_event_id=self._kickoff_event_id, started_event_id=self._kickoff_event_id,
@@ -2061,7 +2063,7 @@ class Crew(FlowTrackable, BaseModel):
crewai_event_bus.emit( crewai_event_bus.emit(
self, self,
CrewTestStartedEvent( CrewTestStartedEvent(
crew_name=self.display_name, crew_name=self.name,
n_iterations=n_iterations, n_iterations=n_iterations,
eval_llm=llm_instance, eval_llm=llm_instance,
inputs=inputs, inputs=inputs,
@@ -2080,7 +2082,7 @@ class Crew(FlowTrackable, BaseModel):
crewai_event_bus.emit( crewai_event_bus.emit(
self, self,
CrewTestCompletedEvent( CrewTestCompletedEvent(
crew_name=self.display_name, crew_name=self.name,
), ),
) )
except Exception as e: except Exception as e:
@@ -2088,7 +2090,7 @@ class Crew(FlowTrackable, BaseModel):
self, self,
CrewTestFailedEvent( CrewTestFailedEvent(
error=str(e), error=str(e),
crew_name=self.display_name, crew_name=self.name,
), ),
) )
raise raise

View File

@@ -5,7 +5,7 @@ from __future__ import annotations
import asyncio import asyncio
from collections.abc import Callable, Coroutine, Iterable, Mapping from collections.abc import Callable, Coroutine, Iterable, Mapping
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any, cast
from opentelemetry import baggage from opentelemetry import baggage
@@ -309,9 +309,10 @@ def prepare_kickoff(
from crewai.events.utils.console_formatter import ConsoleFormatter from crewai.events.utils.console_formatter import ConsoleFormatter
fmt = ConsoleFormatter(verbose=True) fmt = ConsoleFormatter(verbose=True)
# `name` is guaranteed non-None by the `_resolve_name` validator.
content = fmt.create_status_content( content = fmt.create_status_content(
"Resuming from Checkpoint", "Resuming from Checkpoint",
crew.display_name, cast(str, crew.name),
"bright_magenta", "bright_magenta",
ID=str(crew.id), ID=str(crew.id),
) )
@@ -320,7 +321,7 @@ def prepare_kickoff(
) )
else: else:
started_event = CrewKickoffStartedEvent( started_event = CrewKickoffStartedEvent(
crew_name=crew.display_name, crew_name=crew.name,
inputs=normalized, inputs=normalized,
) )
crew._kickoff_event_id = started_event.event_id crew._kickoff_event_id = started_event.event_id

View File

@@ -791,11 +791,7 @@ class TraceCollectionListener(BaseEventListener):
if not self.batch_manager.is_batch_initialized(): if not self.batch_manager.is_batch_initialized():
user_context = self._get_user_context() user_context = self._get_user_context()
execution_metadata = { execution_metadata = {
"crew_name": ( "crew_name": getattr(source, "name", None) or "Unknown Crew",
getattr(source, "display_name", None)
or getattr(source, "name", None)
or "Unknown Crew"
),
"crewai_version": get_crewai_version(), "crewai_version": get_crewai_version(),
} }
self._initialize_batch(user_context, execution_metadata) self._initialize_batch(user_context, execution_metadata)

View File

@@ -238,8 +238,7 @@ def crew(
crew_instance: Crew = _call_method(meth, self, *args, **kwargs) crew_instance: Crew = _call_method(meth, self, *args, **kwargs)
if crew_instance.name is None: crew_instance.name = getattr(self, "_crew_name", None) or crew_instance.name
crew_instance.name = getattr(self, "_crew_name", None)
def callback_wrapper( def callback_wrapper(
hook: Callable[Concatenate[CrewInstance, P2], R2], instance: CrewInstance hook: Callable[Concatenate[CrewInstance, P2], R2], instance: CrewInstance

View File

@@ -213,7 +213,7 @@ class CrewEvaluator:
quality=quality_score, quality=quality_score,
execution_duration=current_task.execution_duration, execution_duration=current_task.execution_duration,
model=getattr(self.llm, "model", str(self.llm)), model=getattr(self.llm, "model", str(self.llm)),
crew_name=self.crew.display_name, crew_name=self.crew.name,
crew=self.crew, crew=self.crew,
), ),
) )

View File

@@ -4740,7 +4740,7 @@ def test_default_crew_name(researcher, writer):
Task(description="Task 2", expected_output="output", agent=writer), Task(description="Task 2", expected_output="output", agent=writer),
], ],
) )
assert crew.name is None assert crew.name == "Crew"
@pytest.mark.parametrize( @pytest.mark.parametrize(