Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions lib/crewai/src/crewai/agent/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,15 +394,17 @@ def set_skills(
self,
resolved_crew_skills: list[SkillModel] | None = None,
) -> None:
"""Resolve skill paths and activate skills to INSTRUCTIONS level.
"""Resolve skill paths while preserving explicit disclosure levels.

Path entries trigger discovery and activation. Pre-loaded Skill objects
below INSTRUCTIONS level are activated. Crew-level skills are merged in
with event emission so observability is consistent regardless of origin.
Path entries trigger discovery and activation because directory-based
skills opt into eager loading. Pre-loaded Skill objects keep their
current disclosure level so callers can attach METADATA-only skills and
progressively activate them later. Crew-level skills are merged in with
event emission so observability is consistent regardless of origin.

Args:
resolved_crew_skills: Pre-resolved crew skills (already discovered
and activated). When provided, avoids redundant discovery per agent.
resolved_crew_skills: Pre-resolved crew skills. When provided,
avoids redundant discovery per agent.
"""
from crewai.crew import Crew

Expand Down Expand Up @@ -443,8 +445,7 @@ def set_skills(
elif isinstance(item, SkillModel):
if item.name not in seen:
seen.add(item.name)
activated = activate_skill(item, source=self)
if activated is item and item.disclosure_level >= INSTRUCTIONS:
if item.disclosure_level >= INSTRUCTIONS:
crewai_event_bus.emit(
self,
event=SkillActivatedEvent(
Expand All @@ -454,7 +455,7 @@ def set_skills(
disclosure_level=item.disclosure_level,
),
)
resolved.append(activated)
resolved.append(item)

self.skills = resolved if resolved else None

Expand Down
40 changes: 40 additions & 0 deletions lib/crewai/src/crewai/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from crewai.events.event_bus import crewai_event_bus
from crewai.events.handler_graph import CircularDependencyError


if TYPE_CHECKING:
from crewai.events.types.agent_events import (
AgentEvaluationCompletedEvent,
Expand All @@ -33,6 +34,20 @@
LiteAgentExecutionErrorEvent,
LiteAgentExecutionStartedEvent,
)
from crewai.events.types.checkpoint_events import (
CheckpointBaseEvent,
CheckpointCompletedEvent,
CheckpointFailedEvent,
CheckpointForkBaseEvent,
CheckpointForkCompletedEvent,
CheckpointForkStartedEvent,
CheckpointPrunedEvent,
CheckpointRestoreBaseEvent,
CheckpointRestoreCompletedEvent,
CheckpointRestoreFailedEvent,
CheckpointRestoreStartedEvent,
CheckpointStartedEvent,
)
from crewai.events.types.crew_events import (
CrewKickoffCompletedEvent,
CrewKickoffFailedEvent,
Expand Down Expand Up @@ -141,6 +156,19 @@
"LiteAgentExecutionCompletedEvent": "crewai.events.types.agent_events",
"LiteAgentExecutionErrorEvent": "crewai.events.types.agent_events",
"LiteAgentExecutionStartedEvent": "crewai.events.types.agent_events",
# checkpoint_events
"CheckpointBaseEvent": "crewai.events.types.checkpoint_events",
"CheckpointCompletedEvent": "crewai.events.types.checkpoint_events",
"CheckpointFailedEvent": "crewai.events.types.checkpoint_events",
"CheckpointForkBaseEvent": "crewai.events.types.checkpoint_events",
"CheckpointForkCompletedEvent": "crewai.events.types.checkpoint_events",
"CheckpointForkStartedEvent": "crewai.events.types.checkpoint_events",
"CheckpointPrunedEvent": "crewai.events.types.checkpoint_events",
"CheckpointRestoreBaseEvent": "crewai.events.types.checkpoint_events",
"CheckpointRestoreCompletedEvent": "crewai.events.types.checkpoint_events",
"CheckpointRestoreFailedEvent": "crewai.events.types.checkpoint_events",
"CheckpointRestoreStartedEvent": "crewai.events.types.checkpoint_events",
"CheckpointStartedEvent": "crewai.events.types.checkpoint_events",
# crew_events
"CrewKickoffCompletedEvent": "crewai.events.types.crew_events",
"CrewKickoffFailedEvent": "crewai.events.types.crew_events",
Expand Down Expand Up @@ -265,6 +293,18 @@ def __getattr__(name: str) -> Any:
"AgentReasoningFailedEvent",
"AgentReasoningStartedEvent",
"BaseEventListener",
"CheckpointBaseEvent",
"CheckpointCompletedEvent",
"CheckpointFailedEvent",
"CheckpointForkBaseEvent",
"CheckpointForkCompletedEvent",
"CheckpointForkStartedEvent",
"CheckpointPrunedEvent",
"CheckpointRestoreBaseEvent",
"CheckpointRestoreCompletedEvent",
"CheckpointRestoreFailedEvent",
"CheckpointRestoreStartedEvent",
"CheckpointStartedEvent",
"CircularDependencyError",
"CrewKickoffCompletedEvent",
"CrewKickoffFailedEvent",
Expand Down
20 changes: 20 additions & 0 deletions lib/crewai/src/crewai/events/event_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@
AgentExecutionStartedEvent,
LiteAgentExecutionCompletedEvent,
)
from crewai.events.types.checkpoint_events import (
CheckpointCompletedEvent,
CheckpointFailedEvent,
CheckpointForkCompletedEvent,
CheckpointForkStartedEvent,
CheckpointPrunedEvent,
CheckpointRestoreCompletedEvent,
CheckpointRestoreFailedEvent,
CheckpointRestoreStartedEvent,
CheckpointStartedEvent,
)
from crewai.events.types.crew_events import (
CrewKickoffCompletedEvent,
CrewKickoffFailedEvent,
Expand Down Expand Up @@ -183,4 +194,13 @@
| MCPToolExecutionCompletedEvent
| MCPToolExecutionFailedEvent
| MCPConfigFetchFailedEvent
| CheckpointStartedEvent
| CheckpointCompletedEvent
| CheckpointFailedEvent
| CheckpointForkStartedEvent
| CheckpointForkCompletedEvent
| CheckpointRestoreStartedEvent
| CheckpointRestoreCompletedEvent
| CheckpointRestoreFailedEvent
| CheckpointPrunedEvent
)
97 changes: 97 additions & 0 deletions lib/crewai/src/crewai/events/types/checkpoint_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"""Event family for automatic state checkpointing and forking."""

from typing import Literal

from crewai.events.base_events import BaseEvent


class CheckpointBaseEvent(BaseEvent):
"""Base event for checkpoint lifecycle operations."""

type: str
location: str
provider: str
trigger: str | None = None
branch: str | None = None
parent_id: str | None = None


class CheckpointStartedEvent(CheckpointBaseEvent):
"""Event emitted immediately before a checkpoint is written."""

type: Literal["checkpoint_started"] = "checkpoint_started"


class CheckpointCompletedEvent(CheckpointBaseEvent):
"""Event emitted when a checkpoint has been written successfully."""

type: Literal["checkpoint_completed"] = "checkpoint_completed"
checkpoint_id: str
duration_ms: float


class CheckpointFailedEvent(CheckpointBaseEvent):
"""Event emitted when a checkpoint write fails."""

type: Literal["checkpoint_failed"] = "checkpoint_failed"
error: str


class CheckpointPrunedEvent(CheckpointBaseEvent):
"""Event emitted after pruning old checkpoints from a branch."""

type: Literal["checkpoint_pruned"] = "checkpoint_pruned"
removed_count: int
max_checkpoints: int


class CheckpointForkBaseEvent(BaseEvent):
"""Base event for fork lifecycle operations on a RuntimeState."""

type: str
branch: str
parent_branch: str | None = None
parent_checkpoint_id: str | None = None


class CheckpointForkStartedEvent(CheckpointForkBaseEvent):
"""Event emitted immediately before a fork relabels the branch."""

type: Literal["checkpoint_fork_started"] = "checkpoint_fork_started"


class CheckpointForkCompletedEvent(CheckpointForkBaseEvent):
"""Event emitted after a fork has established the new branch."""

type: Literal["checkpoint_fork_completed"] = "checkpoint_fork_completed"


class CheckpointRestoreBaseEvent(BaseEvent):
"""Base event for checkpoint restore lifecycle operations."""

type: str
location: str
provider: str | None = None


class CheckpointRestoreStartedEvent(CheckpointRestoreBaseEvent):
"""Event emitted immediately before a checkpoint restore begins."""

type: Literal["checkpoint_restore_started"] = "checkpoint_restore_started"


class CheckpointRestoreCompletedEvent(CheckpointRestoreBaseEvent):
"""Event emitted when a checkpoint has been restored successfully."""

type: Literal["checkpoint_restore_completed"] = "checkpoint_restore_completed"
checkpoint_id: str
branch: str | None = None
parent_id: str | None = None
duration_ms: float


class CheckpointRestoreFailedEvent(CheckpointRestoreBaseEvent):
"""Event emitted when a checkpoint restore fails."""

type: Literal["checkpoint_restore_failed"] = "checkpoint_restore_failed"
error: str
Loading