1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct IdleEvent {
7 pub idle_duration_ms: u64,
9 pub idle_reason: String,
11 #[serde(skip_serializing_if = "Option::is_none")]
13 pub last_event_type: Option<String>,
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub suggested_action: Option<String>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct HeartbeatEvent {
22 pub uptime_ms: u64,
24 pub total_events_processed: u64,
26 pub current_state: String,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub cpu_percent: Option<f32>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub memory_bytes: Option<u64>,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub active_tools: Option<usize>,
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub pending_actions: Option<usize>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub queue_depth: Option<usize>,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub tokens_used: Option<i32>,
46}
47
48#[derive(Debug, Clone, Default, Serialize, Deserialize)]
53pub struct EventContext {
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub recent_facts: Option<Vec<Fact>>,
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub memory_summary: Option<MemorySummary>,
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub session_stats: Option<SessionStats>,
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub current_task: Option<String>,
66 #[serde(skip_serializing_if = "Option::is_none")]
68 pub capabilities: Option<HashMap<String, serde_json::Value>>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct Fact {
74 pub content: String,
75 pub source: String,
76 pub confidence: f32,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct MemorySummary {
82 pub memory_type: String,
83 pub total_items: usize,
84 pub recent_topics: Vec<String>,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct SessionStats {
90 pub total_actions: usize,
91 pub total_tokens: i32,
92 pub duration_ms: u64,
93 pub error_count: usize,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98#[serde(tag = "decision", rename_all = "lowercase")]
99pub enum IdleDecision {
100 Allow,
102 Defer {
104 #[serde(skip_serializing_if = "Option::is_none")]
105 reason: Option<String>,
106 },
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(rename_all = "snake_case")]
112pub enum PerceptionIntent {
113 Recognize,
115 Understand,
117 Locate,
119 Retrieve,
121 Explore,
123 Reason,
125 Validate,
127 Compare,
129 Track,
131}
132
133impl std::fmt::Display for PerceptionIntent {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 match self {
136 PerceptionIntent::Recognize => write!(f, "recognize"),
137 PerceptionIntent::Understand => write!(f, "understand"),
138 PerceptionIntent::Locate => write!(f, "locate"),
139 PerceptionIntent::Retrieve => write!(f, "retrieve"),
140 PerceptionIntent::Explore => write!(f, "explore"),
141 PerceptionIntent::Reason => write!(f, "reason"),
142 PerceptionIntent::Validate => write!(f, "validate"),
143 PerceptionIntent::Compare => write!(f, "compare"),
144 PerceptionIntent::Track => write!(f, "track"),
145 }
146 }
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
151#[serde(rename_all = "snake_case")]
152pub enum PerceptionTarget {
153 Entity {
155 name: String,
156 entity_type: String,
158 identifier: Option<String>,
160 },
161 Location {
163 path: String,
164 location_type: String,
166 },
167 Event {
169 description: String,
170 event_type: String,
172 time_range: Option<TimeRange>,
174 },
175 Relation {
177 entities: Vec<String>,
178 relation_type: String,
180 },
181 Rule {
183 name: String,
184 rule_type: String,
186 scope: Option<String>,
188 },
189 State {
191 target: String,
192 aspect: String,
193 include_history: bool,
194 },
195 Resource {
197 name: String,
198 resource_type: String,
200 constraints: Option<serde_json::Value>,
201 },
202 Pattern {
204 pattern: String,
205 pattern_type: String,
207 },
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct TimeRange {
213 pub from: Option<i64>,
214 pub to: Option<i64>,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub relative: Option<String>,
217}
218
219#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
221#[serde(rename_all = "snake_case")]
222pub enum PerceptionDomain {
223 Coding,
224 Writing,
225 DataAnalysis,
226 Research,
227 ProjectManagement,
228 Conversation,
229 Operations,
230 Security,
231 General,
232}
233
234impl Default for PerceptionDomain {
235 fn default() -> Self {
236 PerceptionDomain::General
237 }
238}
239
240#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
242#[serde(rename_all = "snake_case")]
243pub enum PerceptionModality {
244 Text,
245 Code,
246 StructuredData,
247 Table,
248 Chart,
249 Image,
250 Audio,
251 Video,
252 Any,
253}
254
255impl Default for PerceptionModality {
256 fn default() -> Self {
257 PerceptionModality::Any
258 }
259}
260
261#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
263#[serde(rename_all = "snake_case")]
264pub enum PerceptionUrgency {
265 Critical,
267 High,
269 Normal,
271 Low,
273}
274
275impl Default for PerceptionUrgency {
276 fn default() -> Self {
277 PerceptionUrgency::Normal
278 }
279}
280
281#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
283#[serde(rename_all = "snake_case")]
284pub enum PerceptionFreshness {
285 Realtime,
287 Recent,
289 Static,
291}
292
293impl Default for PerceptionFreshness {
294 fn default() -> Self {
295 PerceptionFreshness::Static
296 }
297}
298
299#[derive(Debug, Clone, Serialize, Deserialize)]
301pub struct PerceptionConstraints {
302 #[serde(default)]
303 pub max_results: Option<usize>,
304 #[serde(default)]
305 pub max_context_length: Option<usize>,
306 #[serde(default = "default_include_sources")]
307 pub include_sources: bool,
308}
309
310fn default_include_sources() -> bool {
311 true
312}
313
314impl Default for PerceptionConstraints {
315 fn default() -> Self {
316 Self {
317 max_results: None,
318 max_context_length: None,
319 include_sources: true,
320 }
321 }
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize)]
326pub struct PerceptionContext {
327 pub workspace: String,
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub current_task: Option<String>,
330 #[serde(skip_serializing_if = "Option::is_none")]
331 pub query: Option<String>,
332 #[serde(skip_serializing_if = "Option::is_none")]
333 pub relevant_history: Option<Vec<HistoryItem>>,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct HistoryItem {
339 pub item_type: String,
340 pub content: String,
341 pub timestamp: i64,
342}
343
344#[derive(Debug, Clone, Serialize, Deserialize)]
346pub struct ContextPerceptionEvent {
347 pub session_id: String,
348 pub intent: PerceptionIntent,
349 pub target: PerceptionTarget,
350 #[serde(default)]
351 pub domain: PerceptionDomain,
352 #[serde(default)]
353 pub preferred_modality: PerceptionModality,
354 #[serde(default)]
355 pub urgency: PerceptionUrgency,
356 #[serde(default)]
357 pub freshness: PerceptionFreshness,
358 pub context: PerceptionContext,
359 #[serde(default)]
360 pub constraints: PerceptionConstraints,
361 #[serde(skip_serializing_if = "Option::is_none")]
362 pub metadata: Option<HashMap<String, serde_json::Value>>,
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct InjectedContext {
368 pub facts: Vec<Fact>,
369 #[serde(skip_serializing_if = "Option::is_none")]
370 pub file_contents: Option<Vec<FileContentSnippet>>,
371 #[serde(skip_serializing_if = "Option::is_none")]
372 pub project_summary: Option<ProjectSummary>,
373 #[serde(skip_serializing_if = "Option::is_none")]
374 pub knowledge: Option<Vec<String>>,
375 #[serde(skip_serializing_if = "Option::is_none")]
376 pub suggestions: Option<Vec<String>>,
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize)]
381pub struct FileContentSnippet {
382 pub path: String,
383 pub snippet: String,
384 pub relevance_score: f32,
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize)]
389pub struct ProjectSummary {
390 pub project_name: String,
391 #[serde(skip_serializing_if = "Option::is_none")]
392 pub language: Option<String>,
393 #[serde(skip_serializing_if = "Option::is_none")]
394 pub key_files: Option<Vec<String>>,
395 pub structure_description: String,
396}
397
398#[derive(Debug, Clone, Serialize, Deserialize)]
400#[serde(tag = "decision", rename_all = "lowercase")]
401pub enum ContextPerceptionDecision {
402 Allow {
404 injected_context: InjectedContext,
405 #[serde(skip_serializing_if = "Option::is_none")]
406 metadata: Option<HashMap<String, serde_json::Value>>,
407 },
408 Block {
410 reason: String,
411 #[serde(skip_serializing_if = "Option::is_none")]
412 metadata: Option<HashMap<String, serde_json::Value>>,
413 },
414 Refine {
416 refined_intent: Option<PerceptionIntent>,
417 refined_target: Option<PerceptionTarget>,
418 scope_hints: Vec<String>,
419 },
420}