Skip to main content

agtrace_engine/domain/
events.rs

1use agtrace_types::{AgentEvent, EventPayload};
2
3/// Filters for including/excluding event types.
4///
5/// Supports both allowlist (`only`) and blocklist (`hide`) patterns
6/// for event type filtering.
7pub struct EventFilters {
8    /// Event types to exclude (blocklist).
9    pub hide: Option<Vec<String>>,
10    /// Event types to include exclusively (allowlist).
11    pub only: Option<Vec<String>>,
12}
13
14/// Filter events by type using inclusion/exclusion patterns.
15///
16/// Applies `only` filter first (if present), then `hide` filter.
17/// Supported patterns: "user", "assistant"/"message", "tool",
18/// "reasoning", "token"/"tokenusage", "notification"/"info".
19pub fn filter_events(events: &[AgentEvent], filters: EventFilters) -> Vec<AgentEvent> {
20    let mut filtered = events.to_vec();
21
22    if let Some(only_patterns) = filters.only {
23        filtered.retain(|e| {
24            only_patterns.iter().any(|pattern| {
25                let pattern_lower = pattern.to_lowercase();
26                match &e.payload {
27                    EventPayload::User(_) => pattern_lower == "user",
28                    EventPayload::Message(_) => {
29                        pattern_lower == "assistant" || pattern_lower == "message"
30                    }
31                    EventPayload::ToolCall(_) | EventPayload::ToolResult(_) => {
32                        pattern_lower == "tool"
33                    }
34                    EventPayload::Reasoning(_) => pattern_lower == "reasoning",
35                    EventPayload::TokenUsage(_) => {
36                        pattern_lower == "token" || pattern_lower == "tokenusage"
37                    }
38                    EventPayload::Notification(_) => {
39                        pattern_lower == "notification" || pattern_lower == "info"
40                    }
41                    EventPayload::SlashCommand(_) => {
42                        pattern_lower == "slashcommand" || pattern_lower == "command"
43                    }
44                    EventPayload::QueueOperation(_) => {
45                        pattern_lower == "queueoperation" || pattern_lower == "queue"
46                    }
47                    EventPayload::Summary(_) => pattern_lower == "summary",
48                }
49            })
50        });
51    }
52
53    if let Some(hide_patterns) = filters.hide {
54        filtered.retain(|e| {
55            !hide_patterns.iter().any(|pattern| {
56                let pattern_lower = pattern.to_lowercase();
57                match &e.payload {
58                    EventPayload::User(_) => pattern_lower == "user",
59                    EventPayload::Message(_) => {
60                        pattern_lower == "assistant" || pattern_lower == "message"
61                    }
62                    EventPayload::ToolCall(_) | EventPayload::ToolResult(_) => {
63                        pattern_lower == "tool"
64                    }
65                    EventPayload::Reasoning(_) => pattern_lower == "reasoning",
66                    EventPayload::TokenUsage(_) => {
67                        pattern_lower == "token" || pattern_lower == "tokenusage"
68                    }
69                    EventPayload::Notification(_) => {
70                        pattern_lower == "notification" || pattern_lower == "info"
71                    }
72                    EventPayload::SlashCommand(_) => {
73                        pattern_lower == "slashcommand" || pattern_lower == "command"
74                    }
75                    EventPayload::QueueOperation(_) => {
76                        pattern_lower == "queueoperation" || pattern_lower == "queue"
77                    }
78                    EventPayload::Summary(_) => pattern_lower == "summary",
79                }
80            })
81        });
82    }
83
84    filtered
85}