aether_core/events/
agent_event.rs1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use super::{ContextEvent, MessageEvent, ModelEvent, ToolEvent, TurnEvent, TurnOutcome};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
8#[serde(tag = "category", content = "event", rename_all = "snake_case")]
9pub enum AgentEvent {
10 Message(MessageEvent),
11 Tool(ToolEvent),
12 Turn(TurnEvent),
13 Context(ContextEvent),
14 Model(ModelEvent),
15}
16
17impl AgentEvent {
18 pub fn text(message_id: &str, chunk: &str, is_complete: bool) -> Self {
19 Self::Message(MessageEvent::Text { message_id: message_id.into(), chunk: chunk.into(), is_complete })
20 }
21
22 pub fn thought(message_id: &str, chunk: &str, is_complete: bool) -> Self {
23 Self::Message(MessageEvent::Thought { message_id: message_id.into(), chunk: chunk.into(), is_complete })
24 }
25
26 pub fn turn_ended(outcome: TurnOutcome) -> Self {
27 Self::Turn(TurnEvent::Ended { outcome })
28 }
29
30 pub fn turn_outcome(&self) -> Option<&TurnOutcome> {
32 match self {
33 Self::Turn(TurnEvent::Ended { outcome }) => Some(outcome),
34 _ => None,
35 }
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42 use crate::events::{ContextUsage, LlmCallOutcome, LlmCallPurpose};
43
44 #[test]
45 fn serializes_nested_event_contract() {
46 let event = AgentEvent::text("m1", "hello", true);
47 assert_eq!(
48 serde_json::to_value(event).unwrap(),
49 serde_json::json!({"category":"message","event":{"type":"text","message_id":"m1","chunk":"hello","is_complete":true}})
50 );
51 }
52
53 #[test]
54 fn nested_events_roundtrip() {
55 let events = [
56 AgentEvent::text("m", "text", true),
57 AgentEvent::Tool(ToolEvent::DefinitionsUpdated { tools: vec![] }),
58 AgentEvent::Turn(TurnEvent::LlmCallEnded {
59 purpose: LlmCallPurpose::Chat,
60 outcome: LlmCallOutcome::Cancelled,
61 }),
62 AgentEvent::Context(ContextEvent::UsageUpdated { usage: ContextUsage::default() }),
63 AgentEvent::Model(ModelEvent::Switched { previous: "a".into(), new: "b".into() }),
64 ];
65 for event in events {
66 let json = serde_json::to_string(&event).unwrap();
67 assert_eq!(serde_json::from_str::<AgentEvent>(&json).unwrap(), event);
68 }
69 }
70
71 #[test]
72 fn turn_outcome_returns_outcome_only_for_turn_end() {
73 assert_eq!(AgentEvent::turn_ended(TurnOutcome::Completed).turn_outcome(), Some(&TurnOutcome::Completed));
74 assert_eq!(AgentEvent::text("m", "text", true).turn_outcome(), None);
75 assert_eq!(AgentEvent::Turn(TurnEvent::Started { content: vec![] }).turn_outcome(), None);
76 }
77}