Skip to main content

uira_core/events/
compat.rs

1use crate::events::{ApprovalDecision, Event, FileChangeType, SessionEndReason};
2use crate::{Item, ThreadEvent, TokenUsage};
3
4impl From<ThreadEvent> for Event {
5    fn from(thread_event: ThreadEvent) -> Self {
6        match thread_event {
7            ThreadEvent::ThreadStarted { thread_id } => Event::SessionStarted {
8                session_id: thread_id,
9                parent_id: None,
10            },
11            ThreadEvent::TurnStarted { turn_number } => Event::TurnStarted {
12                session_id: String::new(),
13                turn_number,
14            },
15            ThreadEvent::TurnCompleted { turn_number, usage } => Event::TurnCompleted {
16                session_id: String::new(),
17                turn_number,
18                usage,
19            },
20            ThreadEvent::ItemStarted { item } => match item {
21                Item::ToolCall { id, name, input } => Event::ToolExecutionStarted {
22                    session_id: String::new(),
23                    tool_call_id: id,
24                    tool_name: name,
25                    input,
26                },
27                Item::ApprovalRequest {
28                    id,
29                    tool_name,
30                    input,
31                    reason,
32                } => Event::ApprovalRequested {
33                    session_id: String::new(),
34                    request_id: id,
35                    tool_name,
36                    input,
37                    reason,
38                },
39                _ => Event::MessagesTransform {
40                    session_id: String::new(),
41                },
42            },
43            ThreadEvent::ItemCompleted { item } => match item {
44                Item::ToolResult {
45                    tool_call_id,
46                    output,
47                    is_error,
48                } => Event::ToolExecutionCompleted {
49                    session_id: String::new(),
50                    tool_call_id: tool_call_id.clone(),
51                    tool_name: String::new(),
52                    output: serde_json::json!({ "output": output, "is_error": is_error }),
53                    error: if is_error { Some(output) } else { None },
54                    duration_ms: 0,
55                },
56                Item::ApprovalDecision {
57                    request_id,
58                    approved,
59                } => Event::ApprovalDecided {
60                    session_id: String::new(),
61                    request_id,
62                    decision: if approved {
63                        ApprovalDecision::Approved
64                    } else {
65                        ApprovalDecision::Denied { reason: None }
66                    },
67                },
68                Item::FileChange {
69                    path,
70                    change_type,
71                    patch,
72                } => Event::FileChanged {
73                    session_id: String::new(),
74                    path,
75                    change_type: match change_type {
76                        crate::protocol::FileChangeType::Create => FileChangeType::Create,
77                        crate::protocol::FileChangeType::Modify => FileChangeType::Modify,
78                        crate::protocol::FileChangeType::Delete => FileChangeType::Delete,
79                        crate::protocol::FileChangeType::Rename => FileChangeType::Rename,
80                    },
81                    patch,
82                },
83                _ => Event::MessagesTransform {
84                    session_id: String::new(),
85                },
86            },
87            ThreadEvent::ContentDelta { delta } => Event::ContentDelta {
88                session_id: String::new(),
89                delta,
90            },
91            ThreadEvent::ThinkingDelta { thinking } => Event::ThinkingDelta {
92                session_id: String::new(),
93                delta: thinking,
94            },
95            ThreadEvent::WaitingForInput { prompt } => Event::UserInputRequested {
96                session_id: String::new(),
97                prompt,
98            },
99            ThreadEvent::Error {
100                message,
101                recoverable,
102            } => Event::Error {
103                session_id: String::new(),
104                message,
105                recoverable,
106            },
107            ThreadEvent::ThreadCompleted { usage: _ } => Event::SessionEnded {
108                session_id: String::new(),
109                reason: SessionEndReason::Completed,
110                last_response: None,
111            },
112            ThreadEvent::ThreadCancelled => Event::SessionEnded {
113                session_id: String::new(),
114                reason: SessionEndReason::Cancelled,
115                last_response: None,
116            },
117            ThreadEvent::GoalVerificationStarted { goals, method } => {
118                Event::GoalVerificationStarted {
119                    session_id: String::new(),
120                    goals,
121                    method,
122                }
123            }
124            ThreadEvent::GoalVerificationResult {
125                goal,
126                score,
127                target,
128                passed,
129                duration_ms,
130            } => Event::GoalVerificationResult {
131                session_id: String::new(),
132                goal,
133                score,
134                target,
135                passed,
136                duration_ms,
137            },
138            ThreadEvent::GoalVerificationCompleted {
139                all_passed,
140                passed_count,
141                total_count,
142            } => Event::GoalVerificationCompleted {
143                session_id: String::new(),
144                all_passed,
145                passed_count,
146                total_count,
147            },
148            ThreadEvent::BackgroundTaskSpawned {
149                task_id,
150                description,
151                agent,
152            } => Event::BackgroundTaskSpawned {
153                task_id,
154                description,
155                agent,
156            },
157            ThreadEvent::BackgroundTaskProgress {
158                task_id,
159                status,
160                message,
161            } => Event::BackgroundTaskProgress {
162                task_id,
163                status,
164                message,
165            },
166            ThreadEvent::BackgroundTaskCompleted {
167                task_id,
168                success,
169                result_preview,
170                duration_secs,
171            } => Event::BackgroundTaskCompleted {
172                task_id,
173                success,
174                result_preview,
175                duration_secs,
176            },
177            ThreadEvent::ModelSwitched { model, provider } => Event::ModelSwitched {
178                session_id: String::new(),
179                model,
180                provider,
181            },
182            ThreadEvent::PermissionEvaluated {
183                permission,
184                path,
185                action,
186                rule_matched,
187            } => Event::PermissionEvaluated {
188                session_id: String::new(),
189                permission,
190                path,
191                action: match action.as_str() {
192                    "allow" => crate::events::PermissionAction::Allow,
193                    "deny" => crate::events::PermissionAction::Deny,
194                    _ => crate::events::PermissionAction::Ask,
195                },
196                rule_matched,
197            },
198            ThreadEvent::ApprovalCached {
199                tool_name,
200                pattern,
201                decision: _,
202            } => Event::ApprovalCached {
203                session_id: String::new(),
204                tool_name,
205                pattern,
206            },
207            ThreadEvent::CompactionStarted {
208                strategy,
209                token_count_before,
210            } => Event::CompactionStarted {
211                session_id: String::new(),
212                strategy,
213                token_count_before,
214            },
215            ThreadEvent::CompactionCompleted {
216                token_count_before,
217                token_count_after,
218                messages_removed,
219            } => Event::CompactionCompleted {
220                session_id: String::new(),
221                token_count_before,
222                token_count_after,
223                messages_removed,
224            },
225            ThreadEvent::TodoUpdated { todos } => Event::TodoUpdated {
226                session_id: String::new(),
227                todos,
228            },
229            _ => Event::MessagesTransform {
230                session_id: String::new(),
231            },
232        }
233    }
234}
235
236impl From<Event> for Option<ThreadEvent> {
237    fn from(event: Event) -> Self {
238        match event {
239            Event::SessionStarted { session_id, .. } => Some(ThreadEvent::ThreadStarted {
240                thread_id: session_id,
241            }),
242            Event::TurnStarted { turn_number, .. } => {
243                Some(ThreadEvent::TurnStarted { turn_number })
244            }
245            Event::TurnCompleted {
246                turn_number, usage, ..
247            } => Some(ThreadEvent::TurnCompleted { turn_number, usage }),
248            Event::ContentDelta { delta, .. } => Some(ThreadEvent::ContentDelta { delta }),
249            Event::ThinkingDelta { delta, .. } => {
250                Some(ThreadEvent::ThinkingDelta { thinking: delta })
251            }
252            Event::UserInputRequested { prompt, .. } => {
253                Some(ThreadEvent::WaitingForInput { prompt })
254            }
255            Event::Error {
256                message,
257                recoverable,
258                ..
259            } => Some(ThreadEvent::Error {
260                message,
261                recoverable,
262            }),
263            Event::SessionEnded { reason, .. } => match reason {
264                SessionEndReason::Completed => Some(ThreadEvent::ThreadCompleted {
265                    usage: TokenUsage::default(),
266                }),
267                SessionEndReason::Cancelled => Some(ThreadEvent::ThreadCancelled),
268                _ => Some(ThreadEvent::ThreadCompleted {
269                    usage: TokenUsage::default(),
270                }),
271            },
272            Event::GoalVerificationStarted { goals, method, .. } => {
273                Some(ThreadEvent::GoalVerificationStarted { goals, method })
274            }
275            Event::GoalVerificationResult {
276                goal,
277                score,
278                target,
279                passed,
280                duration_ms,
281                ..
282            } => Some(ThreadEvent::GoalVerificationResult {
283                goal,
284                score,
285                target,
286                passed,
287                duration_ms,
288            }),
289            Event::GoalVerificationCompleted {
290                all_passed,
291                passed_count,
292                total_count,
293                ..
294            } => Some(ThreadEvent::GoalVerificationCompleted {
295                all_passed,
296                passed_count,
297                total_count,
298            }),
299            Event::BackgroundTaskSpawned {
300                task_id,
301                description,
302                agent,
303            } => Some(ThreadEvent::BackgroundTaskSpawned {
304                task_id,
305                description,
306                agent,
307            }),
308            Event::BackgroundTaskProgress {
309                task_id,
310                status,
311                message,
312            } => Some(ThreadEvent::BackgroundTaskProgress {
313                task_id,
314                status,
315                message,
316            }),
317            Event::BackgroundTaskCompleted {
318                task_id,
319                success,
320                result_preview,
321                duration_secs,
322            } => Some(ThreadEvent::BackgroundTaskCompleted {
323                task_id,
324                success,
325                result_preview,
326                duration_secs,
327            }),
328            Event::ModelSwitched {
329                model, provider, ..
330            } => Some(ThreadEvent::ModelSwitched { model, provider }),
331            Event::PermissionEvaluated {
332                permission,
333                path,
334                action,
335                rule_matched,
336                ..
337            } => Some(ThreadEvent::PermissionEvaluated {
338                permission,
339                path,
340                action: match action {
341                    crate::events::PermissionAction::Allow => "allow".to_string(),
342                    crate::events::PermissionAction::Deny => "deny".to_string(),
343                    crate::events::PermissionAction::Ask => "ask".to_string(),
344                },
345                rule_matched,
346            }),
347            Event::ApprovalCached {
348                tool_name, pattern, ..
349            } => Some(ThreadEvent::ApprovalCached {
350                tool_name,
351                pattern,
352                decision: "cached".to_string(),
353            }),
354            Event::TodoUpdated { todos, .. } => Some(ThreadEvent::TodoUpdated { todos }),
355            Event::CompactionStarted {
356                strategy,
357                token_count_before,
358                ..
359            } => Some(ThreadEvent::CompactionStarted {
360                strategy,
361                token_count_before,
362            }),
363            Event::CompactionCompleted {
364                token_count_before,
365                token_count_after,
366                messages_removed,
367                ..
368            } => Some(ThreadEvent::CompactionCompleted {
369                token_count_before,
370                token_count_after,
371                messages_removed,
372            }),
373            _ => None,
374        }
375    }
376}
377
378#[cfg(test)]
379mod tests {
380    use super::*;
381
382    #[test]
383    fn test_thread_event_to_event() {
384        let thread_event = ThreadEvent::ThreadStarted {
385            thread_id: "test_123".to_string(),
386        };
387        let event: Event = thread_event.into();
388
389        match event {
390            Event::SessionStarted { session_id, .. } => {
391                assert_eq!(session_id, "test_123");
392            }
393            _ => panic!("Wrong event type"),
394        }
395    }
396
397    #[test]
398    fn test_event_to_thread_event() {
399        let event = Event::ContentDelta {
400            session_id: "test".to_string(),
401            delta: "Hello".to_string(),
402        };
403        let thread_event: Option<ThreadEvent> = event.into();
404
405        match thread_event {
406            Some(ThreadEvent::ContentDelta { delta }) => {
407                assert_eq!(delta, "Hello");
408            }
409            _ => panic!("Wrong event type"),
410        }
411    }
412}