mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-02 05:38:12 +00:00
feat: add memory save event handling to activity log
Implemented event handlers for MemorySaveStartedEvent, MemorySaveCompletedEvent, and MemorySaveFailedEvent in the crew_run_tui module. This allows the application to log memory save operations, capturing their status and details in the activity log. Added corresponding tests to verify the correct logging behavior for successful and failed memory saves.
This commit is contained in:
@@ -1923,8 +1923,113 @@ FooterKey .footer-key--key {
|
||||
MemoryRetrievalCompletedEvent,
|
||||
MemoryRetrievalFailedEvent,
|
||||
MemoryRetrievalStartedEvent,
|
||||
MemorySaveCompletedEvent,
|
||||
MemorySaveFailedEvent,
|
||||
MemorySaveStartedEvent,
|
||||
)
|
||||
|
||||
@crewai_event_bus.on(MemorySaveStartedEvent)
|
||||
def on_memory_save_started(
|
||||
source: Any, event: MemorySaveStartedEvent
|
||||
) -> None:
|
||||
with self._lock:
|
||||
for entry in reversed(self._log_entries):
|
||||
if (
|
||||
entry["tool_name"] == "memory_save"
|
||||
and entry.get("started_event_id") == event.event_id
|
||||
):
|
||||
entry["args"] = event.value
|
||||
return
|
||||
self._log_entries.append(
|
||||
{
|
||||
"tool_name": "memory_save",
|
||||
"status": "running",
|
||||
"args": event.value,
|
||||
"result": None,
|
||||
"error": None,
|
||||
"start_time": time.time(),
|
||||
"duration": None,
|
||||
"task_idx": self._current_task_idx,
|
||||
"event_id": event.event_id,
|
||||
}
|
||||
)
|
||||
|
||||
self._register_handler(MemorySaveStartedEvent, on_memory_save_started)
|
||||
|
||||
@crewai_event_bus.on(MemorySaveCompletedEvent)
|
||||
def on_memory_save_completed(
|
||||
source: Any, event: MemorySaveCompletedEvent
|
||||
) -> None:
|
||||
with self._lock:
|
||||
for entry in reversed(self._log_entries):
|
||||
if (
|
||||
entry["tool_name"] == "memory_save"
|
||||
and entry["status"] == "running"
|
||||
and (
|
||||
event.started_event_id is None
|
||||
or entry.get("event_id") == event.started_event_id
|
||||
)
|
||||
):
|
||||
entry["status"] = "success"
|
||||
entry["duration"] = event.save_time_ms / 1000
|
||||
entry["result"] = event.value
|
||||
entry["started_event_id"] = event.started_event_id
|
||||
break
|
||||
else:
|
||||
self._log_entries.append(
|
||||
{
|
||||
"tool_name": "memory_save",
|
||||
"status": "success",
|
||||
"args": None,
|
||||
"result": event.value,
|
||||
"error": None,
|
||||
"start_time": time.time(),
|
||||
"duration": event.save_time_ms / 1000,
|
||||
"task_idx": self._current_task_idx,
|
||||
"started_event_id": event.started_event_id,
|
||||
}
|
||||
)
|
||||
|
||||
self._register_handler(MemorySaveCompletedEvent, on_memory_save_completed)
|
||||
|
||||
@crewai_event_bus.on(MemorySaveFailedEvent)
|
||||
def on_memory_save_failed(
|
||||
source: Any, event: MemorySaveFailedEvent
|
||||
) -> None:
|
||||
with self._lock:
|
||||
for idx, entry in reversed(list(enumerate(self._log_entries))):
|
||||
if (
|
||||
entry["tool_name"] == "memory_save"
|
||||
and entry["status"] == "running"
|
||||
and (
|
||||
event.started_event_id is None
|
||||
or entry.get("event_id") == event.started_event_id
|
||||
)
|
||||
):
|
||||
entry["status"] = "error"
|
||||
entry["error"] = event.error
|
||||
entry["duration"] = time.time() - entry["start_time"]
|
||||
entry["started_event_id"] = event.started_event_id
|
||||
self._log_expanded.add(idx)
|
||||
break
|
||||
else:
|
||||
self._log_entries.append(
|
||||
{
|
||||
"tool_name": "memory_save",
|
||||
"status": "error",
|
||||
"args": event.value,
|
||||
"result": None,
|
||||
"error": event.error,
|
||||
"start_time": time.time(),
|
||||
"duration": 0,
|
||||
"task_idx": self._current_task_idx,
|
||||
"started_event_id": event.started_event_id,
|
||||
}
|
||||
)
|
||||
self._log_expanded.add(len(self._log_entries) - 1)
|
||||
|
||||
self._register_handler(MemorySaveFailedEvent, on_memory_save_failed)
|
||||
|
||||
@crewai_event_bus.on(MemoryRetrievalStartedEvent)
|
||||
def on_memory_retrieval_started(
|
||||
source: Any, event: MemoryRetrievalStartedEvent
|
||||
|
||||
@@ -4,6 +4,11 @@ import time
|
||||
import pytest
|
||||
|
||||
from crewai.events.event_bus import crewai_event_bus
|
||||
from crewai.events.types.memory_events import (
|
||||
MemorySaveCompletedEvent,
|
||||
MemorySaveFailedEvent,
|
||||
MemorySaveStartedEvent,
|
||||
)
|
||||
from crewai.events.types.observation_events import (
|
||||
GoalAchievedEarlyEvent,
|
||||
PlanRefinementEvent,
|
||||
@@ -335,6 +340,67 @@ def test_internal_reasoning_function_call_is_hidden_from_activity_log() -> None:
|
||||
assert app._current_task_steps == []
|
||||
|
||||
|
||||
def test_memory_save_events_are_shown_in_activity_log() -> None:
|
||||
app = _app_with_plan()
|
||||
app._current_task_idx = 1
|
||||
app._subscribe()
|
||||
try:
|
||||
_emit_event(
|
||||
MemorySaveStartedEvent(
|
||||
value="2 memories (background)",
|
||||
metadata={},
|
||||
source_type="unified_memory",
|
||||
)
|
||||
)
|
||||
_emit_event(
|
||||
MemorySaveCompletedEvent(
|
||||
value="2 memories saved",
|
||||
metadata={},
|
||||
save_time_ms=123,
|
||||
source_type="unified_memory",
|
||||
)
|
||||
)
|
||||
finally:
|
||||
app._unsubscribe()
|
||||
|
||||
assert len(app._log_entries) == 1
|
||||
assert app._log_entries[0]["tool_name"] == "memory_save"
|
||||
assert app._log_entries[0]["status"] == "success"
|
||||
assert app._log_entries[0]["args"] == "2 memories (background)"
|
||||
assert app._log_entries[0]["result"] == "2 memories saved"
|
||||
assert app._log_entries[0]["error"] is None
|
||||
assert app._log_entries[0]["duration"] == 0.123
|
||||
assert app._log_entries[0]["task_idx"] == 1
|
||||
|
||||
|
||||
def test_memory_save_failure_is_shown_in_activity_log() -> None:
|
||||
app = _app_with_plan()
|
||||
app._subscribe()
|
||||
try:
|
||||
_emit_event(
|
||||
MemorySaveStartedEvent(
|
||||
value="background save",
|
||||
metadata={},
|
||||
source_type="unified_memory",
|
||||
)
|
||||
)
|
||||
_emit_event(
|
||||
MemorySaveFailedEvent(
|
||||
value="background save",
|
||||
metadata={},
|
||||
error="embedding connection failed",
|
||||
source_type="unified_memory",
|
||||
)
|
||||
)
|
||||
finally:
|
||||
app._unsubscribe()
|
||||
|
||||
assert app._log_entries[0]["tool_name"] == "memory_save"
|
||||
assert app._log_entries[0]["status"] == "error"
|
||||
assert app._log_entries[0]["error"] == "embedding connection failed"
|
||||
assert app._log_expanded == {0}
|
||||
|
||||
|
||||
def test_tool_failure_does_not_override_successful_plan_step_completion() -> None:
|
||||
app = _app_with_plan()
|
||||
app._subscribe()
|
||||
|
||||
Reference in New Issue
Block a user