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}
37
38#[derive(Debug, Serialize, Deserialize, Clone)]
39#[serde(rename_all = "snake_case", tag = "type")]
40pub enum AgentEventType {
41 RunStarted {},
43 RunFinished {
44 success: bool,
45 total_steps: usize,
46 failed_steps: usize,
47 usage: Option<RunUsage>,
49 },
50 RunError {
51 message: String,
52 code: Option<String>,
53 },
54 PlanStarted {
55 initial_plan: bool,
56 },
57 PlanFinished {
58 total_steps: usize,
59 },
60 PlanPruned {
61 removed_steps: Vec<String>,
62 },
63 StepStarted {
65 step_id: String,
66 step_index: usize,
67 },
68 StepCompleted {
69 step_id: String,
70 success: bool,
71 },
72
73 ToolExecutionStart {
75 step_id: String,
76 tool_call_id: String,
77 tool_call_name: String,
78 input: Value,
79 },
80 ToolExecutionEnd {
81 step_id: String,
82 tool_call_id: String,
83 tool_call_name: String,
84 success: bool,
85 },
86
87 TextMessageStart {
89 message_id: String,
90 step_id: String,
91 role: MessageRole,
92 is_final: Option<bool>,
93 },
94 TextMessageContent {
95 message_id: String,
96 step_id: String,
97 delta: String,
98 stripped_content: Option<Vec<(usize, String)>>,
99 },
100 TextMessageEnd {
101 message_id: String,
102 step_id: String,
103 },
104
105 ToolCalls {
107 step_id: String,
108 parent_message_id: Option<String>,
109 tool_calls: Vec<ToolCall>,
110 },
111 ToolResults {
112 step_id: String,
113 parent_message_id: Option<String>,
114 results: Vec<ToolResponse>,
115 },
116
117 AgentHandover {
119 from_agent: String,
120 to_agent: String,
121 reason: Option<String>,
122 },
123
124 WorkflowStarted {
126 workflow_name: String,
127 total_steps: usize,
128 },
129 NodeStarted {
130 node_id: String,
131 node_name: String,
132 step_type: String,
133 },
134 NodeCompleted {
135 node_id: String,
136 node_name: String,
137 success: bool,
138 error: Option<String>,
139 },
140 RunCompleted {
141 workflow_name: String,
142 success: bool,
143 total_steps: usize,
144 },
145 RunFailed {
146 workflow_name: String,
147 error: String,
148 failed_at_step: Option<String>,
149 },
150
151 BrowserScreenshot {
152 image: String,
153 format: Option<String>,
154 filename: Option<String>,
155 size: Option<u64>,
156 timestamp_ms: Option<i64>,
157 },
158
159 BrowserSessionStarted {
160 session_id: String,
161 viewer_url: Option<String>,
162 stream_url: Option<String>,
163 },
164
165 InlineHookRequested {
166 request: InlineHookRequest,
167 },
168
169 TodosUpdated {
171 formatted_todos: String,
172 action: String,
173 todo_count: usize,
174 },
175}
176
177impl AgentEvent {
178 pub fn new(event: AgentEventType) -> Self {
179 Self {
180 timestamp: chrono::Utc::now(),
181 thread_id: uuid::Uuid::new_v4().to_string(),
182 run_id: uuid::Uuid::new_v4().to_string(),
183 event,
184 task_id: uuid::Uuid::new_v4().to_string(),
185 agent_id: "default".to_string(),
186 user_id: None,
187 identifier_id: None,
188 workspace_id: None,
189 }
190 }
191
192 pub fn with_context(
193 event: AgentEventType,
194 thread_id: String,
195 run_id: String,
196 task_id: String,
197 agent_id: String,
198 ) -> Self {
199 Self {
200 timestamp: chrono::Utc::now(),
201 thread_id,
202 run_id,
203 task_id,
204 event,
205 agent_id,
206 user_id: None,
207 identifier_id: None,
208 workspace_id: None,
209 }
210 }
211}