use enact_core::kernel::{ExecutionEventType, ExecutionId, StepId};
use enact_core::streaming::{EventEmitter, EventLog, StreamEvent};
use enact_core::{EventStore, InMemoryEventStore};
use std::sync::Arc;
use tokio::time::Duration;
#[tokio::test]
async fn test_agentic_loop_event_persistence() {
let event_store = Arc::new(InMemoryEventStore::new());
let event_log = Arc::new(EventLog::new(event_store.clone()));
let execution_id = ExecutionId::new();
let mut emitter = EventEmitter::with_persistence(event_log.clone(), execution_id.clone());
emitter.set_event_log(event_log, execution_id.clone());
let step_id = StepId::new();
let tool_call_id = "call_12345";
let tool_name = "weather_tool";
let input_payload = serde_json::json!({ "city": "San Francisco" });
emitter.emit(StreamEvent::ToolInputAvailable {
tool_call_id: tool_call_id.to_string(),
tool_name: tool_name.to_string(),
input: input_payload.clone(),
});
let output_payload = serde_json::json!({ "temp": 72, "conditions": "Sunny" });
emitter.emit(StreamEvent::ToolOutputAvailable {
tool_call_id: tool_call_id.to_string(),
output: output_payload.clone(),
});
let checkpoint_id = "chk_12345";
emitter.emit(StreamEvent::CheckpointSaved {
execution_id: execution_id.as_str().to_string(),
step_id: Some(step_id.as_str().to_string()),
checkpoint_id: checkpoint_id.to_string(),
state_hash: "hash_abc123".to_string(),
timestamp: 1234567890,
});
emitter.emit(StreamEvent::GoalEvaluated {
execution_id: execution_id.as_str().to_string(),
step_id: Some(step_id.as_str().to_string()),
goal_id: "goal_primary".to_string(),
status: "met".to_string(),
score: Some(1.0),
reason: Some("Task completed successfully".to_string()),
timestamp: 1234567890,
});
tokio::time::sleep(Duration::from_millis(100)).await;
let events = event_store
.get_by_execution(&execution_id)
.await
.expect("Failed to load events");
assert_eq!(
events.len(),
4,
"Expected 4 persisted events, found {}",
events.len()
);
let event1 = &events[0].event;
assert!(
matches!(event1.event_type, ExecutionEventType::ToolCallStart),
"Event 1 should be ToolCallStart"
);
let p1 = event1.payload.as_ref().expect("Payload missing");
assert_eq!(p1["tool_call_id"], tool_call_id);
assert_eq!(p1["tool_name"], tool_name);
assert_eq!(p1["input"], input_payload);
let event2 = &events[1].event;
assert!(
matches!(event2.event_type, ExecutionEventType::ToolCallEnd),
"Event 2 should be ToolCallEnd"
);
let p2 = event2.payload.as_ref().expect("Payload missing");
assert_eq!(p2["tool_call_id"], tool_call_id);
assert_eq!(p2["output"], output_payload);
let event3 = &events[2].event;
assert!(
matches!(event3.event_type, ExecutionEventType::CheckpointSaved),
"Event 3 should be CheckpointSaved"
);
let p3 = event3.payload.as_ref().expect("Payload missing");
assert_eq!(p3["checkpoint_id"], checkpoint_id);
assert_eq!(p3["state_hash"], "hash_abc123");
let event4 = &events[3].event;
assert!(
matches!(event4.event_type, ExecutionEventType::GoalEvaluated),
"Event 4 should be GoalEvaluated"
);
let p4 = event4.payload.as_ref().expect("Payload missing");
assert_eq!(p4["goal_id"], "goal_primary");
assert_eq!(p4["status"], "met");
assert_eq!(p4["score"], 1.0);
println!("✅ All agentic loop events persisted correctly!");
}