1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::core::{MessageRole, ToolCall, ToolResponse};
5use crate::hooks::InlineHookRequest;
6
7#[derive(Debug, Serialize, Deserialize, Clone, Default)]
9pub struct RunUsage {
10 pub total_tokens: u32,
12 pub input_tokens: u32,
13 pub output_tokens: u32,
14 pub estimated_tokens: u32,
16}
17
18#[derive(Debug, Serialize, Deserialize, Clone)]
19#[serde(rename_all = "snake_case")]
20pub struct AgentEvent {
21 pub timestamp: chrono::DateTime<chrono::Utc>,
22 pub thread_id: String,
23 pub run_id: String,
24 pub event: AgentEventType,
25 pub task_id: String,
26 pub agent_id: String,
27 #[serde(default)]
29 pub user_id: Option<String>,
30 #[serde(default)]
32 pub identifier_id: Option<String>,
33 #[serde(default)]
35 pub workspace_id: Option<String>,
36 #[serde(default)]
38 pub channel_id: Option<String>,
39}
40
41#[derive(Debug, Serialize, Deserialize, Clone)]
42#[serde(rename_all = "snake_case", tag = "type")]
43pub enum AgentEventType {
44 RunStarted {},
46 RunFinished {
47 success: bool,
48 total_steps: usize,
49 failed_steps: usize,
50 usage: Option<RunUsage>,
52 },
53 RunError {
54 message: String,
55 code: Option<String>,
56 },
57 PlanStarted {
58 initial_plan: bool,
59 },
60 PlanFinished {
61 total_steps: usize,
62 },
63 PlanPruned {
64 removed_steps: Vec<String>,
65 },
66 StepStarted {
68 step_id: String,
69 step_index: usize,
70 },
71 StepCompleted {
72 step_id: String,
73 success: bool,
74 },
75
76 ToolExecutionStart {
78 step_id: String,
79 tool_call_id: String,
80 tool_call_name: String,
81 input: Value,
82 },
83 ToolExecutionEnd {
84 step_id: String,
85 tool_call_id: String,
86 tool_call_name: String,
87 success: bool,
88 },
89
90 TextMessageStart {
92 message_id: String,
93 step_id: String,
94 role: MessageRole,
95 is_final: Option<bool>,
96 },
97 TextMessageContent {
98 message_id: String,
99 step_id: String,
100 delta: String,
101 stripped_content: Option<Vec<(usize, String)>>,
102 },
103 TextMessageEnd {
104 message_id: String,
105 step_id: String,
106 },
107
108 ToolCalls {
110 step_id: String,
111 parent_message_id: Option<String>,
112 tool_calls: Vec<ToolCall>,
113 },
114 ToolResults {
115 step_id: String,
116 parent_message_id: Option<String>,
117 results: Vec<ToolResponse>,
118 },
119
120 AgentHandover {
122 from_agent: String,
123 to_agent: String,
124 reason: Option<String>,
125 },
126
127 BrowserScreenshot {
128 image: String,
129 format: Option<String>,
130 filename: Option<String>,
131 size: Option<u64>,
132 timestamp_ms: Option<i64>,
133 },
134
135 BrowserSessionStarted {
136 session_id: String,
137 viewer_url: Option<String>,
138 stream_url: Option<String>,
139 },
140
141 InlineHookRequested {
142 request: InlineHookRequest,
143 },
144
145 TodosUpdated {
147 formatted_todos: String,
148 action: String,
149 todo_count: usize,
150 },
151
152 ContextCompaction {
154 tier: CompactionTier,
156 tokens_before: usize,
158 tokens_after: usize,
160 entries_affected: usize,
162 context_limit: usize,
164 usage_ratio: f64,
166 summary: Option<String>,
168 },
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
173#[serde(rename_all = "snake_case")]
174pub enum CompactionTier {
175 Trim,
177 Summarize,
179 Reset,
181}
182
183impl AgentEvent {
184 pub fn new(event: AgentEventType) -> Self {
185 Self {
186 timestamp: chrono::Utc::now(),
187 thread_id: uuid::Uuid::new_v4().to_string(),
188 run_id: uuid::Uuid::new_v4().to_string(),
189 event,
190 task_id: uuid::Uuid::new_v4().to_string(),
191 agent_id: "default".to_string(),
192 user_id: None,
193 identifier_id: None,
194 workspace_id: None,
195 channel_id: None,
196 }
197 }
198
199 pub fn with_context(
200 event: AgentEventType,
201 thread_id: String,
202 run_id: String,
203 task_id: String,
204 agent_id: String,
205 ) -> Self {
206 Self {
207 timestamp: chrono::Utc::now(),
208 thread_id,
209 run_id,
210 task_id,
211 event,
212 agent_id,
213 user_id: None,
214 identifier_id: None,
215 workspace_id: None,
216 channel_id: None,
217 }
218 }
219}