1use crate::verbosity::VerbosityTier;
7
8pub const EVENT_PLAN_CREATED: &str = "soothe.cognition.plan.created";
14pub const EVENT_PLAN_BATCH_STARTED: &str = "soothe.cognition.plan.batch.started";
16pub const EVENT_PLAN_REFLECTED: &str = "soothe.cognition.plan.reflected";
18
19pub const EVENT_GOAL_CREATED: &str = "soothe.cognition.goal.created";
21pub const EVENT_GOAL_COMPLETED: &str = "soothe.cognition.goal.completed";
23pub const EVENT_GOAL_FAILED: &str = "soothe.cognition.goal.failed";
25pub const EVENT_GOAL_DEFERRED: &str = "soothe.cognition.goal.deferred";
27pub const EVENT_GOAL_BATCH_STARTED: &str = "soothe.cognition.goal.batch.started";
29pub const EVENT_GOAL_REPORTED: &str = "soothe.cognition.goal.reported";
31pub const EVENT_GOAL_DIRECTIVES_APPLIED: &str = "soothe.cognition.goal.directives.applied";
33
34pub const EVENT_EXPLORER_STARTED: &str = "soothe.subagent.explorer.started";
40pub const EVENT_EXPLORER_MILESTONE: &str = "soothe.subagent.explorer.milestone";
42pub const EVENT_EXPLORER_STEP_COMPLETED: &str = "soothe.subagent.explorer.step.completed";
44pub const EVENT_EXPLORER_COMPLETED: &str = "soothe.subagent.explorer.completed";
46
47pub const EVENT_DEEP_RESEARCH_STARTED: &str = "soothe.subagent.deep_research.started";
49pub const EVENT_DEEP_RESEARCH_PROGRESS: &str = "soothe.subagent.deep_research.progress";
51pub const EVENT_DEEP_RESEARCH_STEP_COMPLETED: &str = "soothe.subagent.deep_research.step.completed";
53pub const EVENT_DEEP_RESEARCH_GATHER_SUMMARY: &str = "soothe.subagent.deep_research.gather.summary";
55pub const EVENT_DEEP_RESEARCH_CRAWL_SUMMARY: &str = "soothe.subagent.deep_research.crawl.summary";
57pub const EVENT_DEEP_RESEARCH_COMPLETED: &str = "soothe.subagent.deep_research.completed";
59
60pub const EVENT_REPLAY_COMPLETE: &str = "replay_complete";
66pub const EVENT_LOOP_REATTACHED_WIRE: &str = "loop_reattached";
68
69pub const EVENT_CARD_REPLAY_BEGIN: &str = "card.replay_begin";
71pub const EVENT_CARD_CREATED: &str = "card.created";
73pub const EVENT_CARD_REPLAY_END: &str = "card.replay_end";
75
76pub const EVENT_TOOL_STARTED: &str = "soothe.tool.execution.started";
78pub const EVENT_TOOL_COMPLETED: &str = "soothe.tool.execution.completed";
80pub const EVENT_TOOL_ERROR: &str = "soothe.tool.execution.error";
82
83pub const EVENT_STREAM_TOOL_CALL_UPDATE: &str = "soothe.stream.tool_call.update";
85pub const EVENT_TOOL_CALL_UPDATES_BATCH: &str = "tool_call_updates_batch";
87
88pub const EVENT_STRANGE_LOOP_STARTED: &str = "soothe.cognition.strange_loop.started";
94pub const EVENT_STRANGE_LOOP_COMPLETED: &str = "soothe.cognition.strange_loop.completed";
96pub const EVENT_STRANGE_LOOP_PLAN_DECISION: &str = "soothe.cognition.strange_loop.plan.decision";
98pub const EVENT_STRANGE_LOOP_REASONED: &str = "soothe.cognition.strange_loop.reasoned";
100pub const EVENT_STRANGE_LOOP_STEP_STARTED: &str = "soothe.cognition.strange_loop.step.started";
102pub const EVENT_STRANGE_LOOP_STEP_QUEUED: &str = "soothe.cognition.strange_loop.step.queued";
104pub const EVENT_STRANGE_LOOP_STEP_COMPLETED: &str = "soothe.cognition.strange_loop.step.completed";
106pub const EVENT_STRANGE_LOOP_CONTEXT_COMPACTED: &str =
108 "soothe.cognition.strange_loop.context.compacted";
109
110pub const EVENT_BRANCH_CREATED: &str = "soothe.cognition.branch.created";
112pub const EVENT_BRANCH_RETRY_STARTED: &str = "soothe.cognition.branch.retry.started";
114
115pub const EVENT_MESSAGE_RECEIVED: &str = "soothe.protocol.message.received";
117pub const EVENT_MESSAGE_SENT: &str = "soothe.protocol.message.sent";
119
120pub const EVENT_FINAL_REPORT: &str = "soothe.output.autonomous.final_report.reported";
122
123pub const EVENT_AUTOPILOT_STATUS_CHANGED: &str = "soothe.system.autopilot.status.changed";
125pub const EVENT_AUTOPILOT_GOAL_CREATED: &str = "soothe.system.autopilot.goal.created";
127pub const EVENT_AUTOPILOT_GOAL_PROGRESS: &str = "soothe.system.autopilot.goal.reported";
129pub const EVENT_AUTOPILOT_GOAL_COMPLETED: &str = "soothe.system.autopilot.goal.completed";
131pub const EVENT_AUTOPILOT_GOAL_SUSPENDED: &str = "soothe.system.autopilot.goal.suspended";
133pub const EVENT_AUTOPILOT_GOAL_BLOCKED: &str = "soothe.system.autopilot.goal.blocked";
135pub const EVENT_AUTOPILOT_DREAMING_ENTERED: &str = "soothe.system.autopilot.dreaming.started";
137pub const EVENT_AUTOPILOT_DREAMING_EXITED: &str = "soothe.system.autopilot.dreaming.completed";
139
140pub const EVENT_GENERAL_FAILED: &str = "soothe.error.general.failed";
142
143#[derive(Debug, Clone, PartialEq, Eq)]
145pub struct ParsedNamespace {
146 pub domain: String,
148 pub component: String,
150 pub action: String,
152}
153
154pub fn parse_namespace(ns: &str) -> Option<ParsedNamespace> {
158 let parts: Vec<&str> = ns.split('.').collect();
159 if parts.len() < 4 || parts[0] != "soothe" {
160 return None;
161 }
162 if parts[1] == "internal" {
163 return None;
164 }
165 Some(ParsedNamespace {
166 domain: parts[1].to_string(),
167 component: parts[2].to_string(),
168 action: parts[3].to_string(),
169 })
170}
171
172pub fn classify_event_verbosity(event_type_or_namespace: &str) -> VerbosityTier {
174 if let Some(parsed) = parse_namespace(event_type_or_namespace) {
175 return classify_by_domain(&parsed.domain, event_type_or_namespace);
176 }
177 classify_by_event_type_string(event_type_or_namespace)
178}
179
180fn classify_by_domain(domain: &str, full: &str) -> VerbosityTier {
181 match domain {
182 "cognition" => VerbosityTier::Normal,
183 "protocol" => VerbosityTier::Detailed,
184 "tool" => VerbosityTier::Internal,
185 "subagent" => classify_subagent_event(full),
186 "autopilot" | "system" => VerbosityTier::Normal,
187 "output" | "error" => VerbosityTier::Quiet,
188 _ => VerbosityTier::Normal,
189 }
190}
191
192fn classify_subagent_event(full: &str) -> VerbosityTier {
193 let Some(parsed) = parse_namespace(full) else {
194 return VerbosityTier::Normal;
195 };
196 match parsed.action.as_str() {
197 "started" | "completed" => VerbosityTier::Normal,
198 _ => VerbosityTier::Detailed,
199 }
200}
201
202fn classify_by_event_type_string(event_type: &str) -> VerbosityTier {
203 if event_type == EVENT_FINAL_REPORT || event_type == EVENT_GENERAL_FAILED {
204 return VerbosityTier::Quiet;
205 }
206 if event_type == EVENT_TOOL_STARTED {
207 return VerbosityTier::Internal;
208 }
209 VerbosityTier::Normal
210}
211
212pub fn is_completion_event(event_type: &str) -> bool {
214 event_type.ends_with(".completed")
215 || event_type.ends_with(".failed")
216 || event_type == EVENT_GENERAL_FAILED
217}
218
219pub fn is_subagent_progress_event(event_type: &str) -> bool {
221 let Some(parsed) = parse_namespace(event_type) else {
222 return false;
223 };
224 parsed.domain == "subagent" && matches!(parsed.action.as_str(), "started" | "completed")
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230
231 #[test]
232 fn parse_valid() {
233 let p = parse_namespace("soothe.cognition.plan.created").unwrap();
234 assert_eq!(p.domain, "cognition");
235 assert_eq!(p.component, "plan");
236 assert_eq!(p.action, "created");
237 }
238
239 #[test]
240 fn reject_internal() {
241 assert!(parse_namespace("soothe.internal.loop.completed").is_none());
242 }
243
244 #[test]
245 fn classify_quiet() {
246 assert_eq!(
247 classify_event_verbosity(EVENT_FINAL_REPORT),
248 VerbosityTier::Quiet
249 );
250 }
251}