gemini_adk_rs/events/
mod.rs

1//! Event system — structured events for agent invocations.
2//!
3//! Mirrors ADK-JS's event types. Each event captures a discrete action
4//! within an agent invocation (user message, model response, tool call, etc.).
5
6pub mod structured;
7pub use structured::*;
8
9use std::collections::HashMap;
10
11use serde::{Deserialize, Serialize};
12
13/// A structured event within an agent invocation.
14///
15/// Events form the audit trail of an agent session. They capture user messages,
16/// model responses, tool calls, state changes, and control flow actions.
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct Event {
19    /// Unique event ID.
20    pub id: String,
21    /// Invocation ID grouping related events.
22    pub invocation_id: String,
23    /// Who authored this event (e.g., "user", agent name, tool name).
24    pub author: String,
25    /// Optional text content of the event.
26    pub content: Option<String>,
27    /// Actions triggered by this event.
28    pub actions: EventActions,
29    /// Unix timestamp (seconds).
30    pub timestamp: u64,
31}
32
33impl Event {
34    /// Create a new event with the given author and optional content.
35    pub fn new(author: impl Into<String>, content: Option<String>) -> Self {
36        let dur = std::time::SystemTime::now()
37            .duration_since(std::time::UNIX_EPOCH)
38            .unwrap_or_default();
39        Self {
40            id: uuid::Uuid::new_v4().to_string(),
41            invocation_id: String::new(),
42            author: author.into(),
43            content,
44            actions: EventActions::default(),
45            timestamp: dur.as_secs(),
46        }
47    }
48
49    /// Set the invocation ID.
50    pub fn with_invocation(mut self, invocation_id: impl Into<String>) -> Self {
51        self.invocation_id = invocation_id.into();
52        self
53    }
54
55    /// Set actions on this event.
56    pub fn with_actions(mut self, actions: EventActions) -> Self {
57        self.actions = actions;
58        self
59    }
60}
61
62/// Actions triggered by an event — control flow and state mutations.
63#[derive(Debug, Clone, Default, Serialize, Deserialize)]
64pub struct EventActions {
65    /// If true, escalate to a human or parent agent.
66    #[serde(default)]
67    pub escalate: bool,
68    /// If true, skip summarization of this event's content.
69    #[serde(default)]
70    pub skip_summarization: bool,
71    /// Transfer control to another agent by name.
72    #[serde(default)]
73    pub transfer_to_agent: Option<String>,
74    /// State mutations (key → new value).
75    #[serde(default)]
76    pub state_delta: HashMap<String, serde_json::Value>,
77}
78
79impl EventActions {
80    /// Create actions that transfer to another agent.
81    pub fn transfer(agent_name: impl Into<String>) -> Self {
82        Self {
83            transfer_to_agent: Some(agent_name.into()),
84            ..Default::default()
85        }
86    }
87
88    /// Create actions that escalate.
89    pub fn escalate() -> Self {
90        Self {
91            escalate: true,
92            ..Default::default()
93        }
94    }
95
96    /// Create actions with a state delta.
97    pub fn state_delta(delta: HashMap<String, serde_json::Value>) -> Self {
98        Self {
99            state_delta: delta,
100            ..Default::default()
101        }
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn event_new() {
111        let event = Event::new("user", Some("Hello!".to_string()));
112        assert_eq!(event.author, "user");
113        assert_eq!(event.content, Some("Hello!".to_string()));
114        assert!(!event.id.is_empty());
115        assert!(event.timestamp > 0);
116    }
117
118    #[test]
119    fn event_with_invocation() {
120        let event = Event::new("agent", None).with_invocation("inv-123");
121        assert_eq!(event.invocation_id, "inv-123");
122    }
123
124    #[test]
125    fn event_actions_transfer() {
126        let actions = EventActions::transfer("helper-agent");
127        assert_eq!(actions.transfer_to_agent, Some("helper-agent".to_string()));
128        assert!(!actions.escalate);
129    }
130
131    #[test]
132    fn event_actions_escalate() {
133        let actions = EventActions::escalate();
134        assert!(actions.escalate);
135        assert!(actions.transfer_to_agent.is_none());
136    }
137
138    #[test]
139    fn event_actions_state_delta() {
140        let mut delta = HashMap::new();
141        delta.insert("topic".to_string(), serde_json::json!("Rust"));
142        let actions = EventActions::state_delta(delta);
143        assert_eq!(
144            actions.state_delta.get("topic"),
145            Some(&serde_json::json!("Rust"))
146        );
147    }
148
149    #[test]
150    fn event_serialization() {
151        let event = Event::new("model", Some("Response text".to_string()));
152        let json = serde_json::to_string(&event).unwrap();
153        let parsed: Event = serde_json::from_str(&json).unwrap();
154        assert_eq!(parsed.author, "model");
155        assert_eq!(parsed.content, Some("Response text".to_string()));
156    }
157}