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                }
45            })
46        });
47    }
48
49    if let Some(hide_patterns) = filters.hide {
50        filtered.retain(|e| {
51            !hide_patterns.iter().any(|pattern| {
52                let pattern_lower = pattern.to_lowercase();
53                match &e.payload {
54                    EventPayload::User(_) => pattern_lower == "user",
55                    EventPayload::Message(_) => {
56                        pattern_lower == "assistant" || pattern_lower == "message"
57                    }
58                    EventPayload::ToolCall(_) | EventPayload::ToolResult(_) => {
59                        pattern_lower == "tool"
60                    }
61                    EventPayload::Reasoning(_) => pattern_lower == "reasoning",
62                    EventPayload::TokenUsage(_) => {
63                        pattern_lower == "token" || pattern_lower == "tokenusage"
64                    }
65                    EventPayload::Notification(_) => {
66                        pattern_lower == "notification" || pattern_lower == "info"
67                    }
68                    EventPayload::SlashCommand(_) => {
69                        pattern_lower == "slashcommand" || pattern_lower == "command"
70                    }
71                }
72            })
73        });
74    }
75
76    filtered
77}