use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IdleEvent {
pub idle_duration_ms: u64,
pub idle_reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_event_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub suggested_action: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HeartbeatEvent {
pub uptime_ms: u64,
pub total_events_processed: u64,
pub current_state: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpu_percent: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub memory_bytes: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub active_tools: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pending_actions: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub queue_depth: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tokens_used: Option<i32>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EventContext {
#[serde(skip_serializing_if = "Option::is_none")]
pub recent_facts: Option<Vec<Fact>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub memory_summary: Option<MemorySummary>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_stats: Option<SessionStats>,
#[serde(skip_serializing_if = "Option::is_none")]
pub current_task: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub capabilities: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Fact {
pub content: String,
pub source: String,
pub confidence: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemorySummary {
pub memory_type: String,
pub total_items: usize,
pub recent_topics: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionStats {
pub total_actions: usize,
pub total_tokens: i32,
pub duration_ms: u64,
pub error_count: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "decision", rename_all = "lowercase")]
pub enum IdleDecision {
Allow,
Defer {
#[serde(skip_serializing_if = "Option::is_none")]
reason: Option<String>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PerceptionIntent {
Recognize,
Understand,
Locate,
Retrieve,
Explore,
Reason,
Validate,
Compare,
Track,
}
impl std::fmt::Display for PerceptionIntent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PerceptionIntent::Recognize => write!(f, "recognize"),
PerceptionIntent::Understand => write!(f, "understand"),
PerceptionIntent::Locate => write!(f, "locate"),
PerceptionIntent::Retrieve => write!(f, "retrieve"),
PerceptionIntent::Explore => write!(f, "explore"),
PerceptionIntent::Reason => write!(f, "reason"),
PerceptionIntent::Validate => write!(f, "validate"),
PerceptionIntent::Compare => write!(f, "compare"),
PerceptionIntent::Track => write!(f, "track"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PerceptionTarget {
Entity {
name: String,
entity_type: String,
identifier: Option<String>,
},
Location {
path: String,
location_type: String,
},
Event {
description: String,
event_type: String,
time_range: Option<TimeRange>,
},
Relation {
entities: Vec<String>,
relation_type: String,
},
Rule {
name: String,
rule_type: String,
scope: Option<String>,
},
State {
target: String,
aspect: String,
include_history: bool,
},
Resource {
name: String,
resource_type: String,
constraints: Option<serde_json::Value>,
},
Pattern {
pattern: String,
pattern_type: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeRange {
pub from: Option<i64>,
pub to: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub relative: Option<String>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PerceptionDomain {
Coding,
Writing,
DataAnalysis,
Research,
ProjectManagement,
Conversation,
Operations,
Security,
General,
}
impl Default for PerceptionDomain {
fn default() -> Self {
PerceptionDomain::General
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PerceptionModality {
Text,
Code,
StructuredData,
Table,
Chart,
Image,
Audio,
Video,
Any,
}
impl Default for PerceptionModality {
fn default() -> Self {
PerceptionModality::Any
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PerceptionUrgency {
Critical,
High,
Normal,
Low,
}
impl Default for PerceptionUrgency {
fn default() -> Self {
PerceptionUrgency::Normal
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PerceptionFreshness {
Realtime,
Recent,
Static,
}
impl Default for PerceptionFreshness {
fn default() -> Self {
PerceptionFreshness::Static
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerceptionConstraints {
#[serde(default)]
pub max_results: Option<usize>,
#[serde(default)]
pub max_context_length: Option<usize>,
#[serde(default = "default_include_sources")]
pub include_sources: bool,
}
fn default_include_sources() -> bool {
true
}
impl Default for PerceptionConstraints {
fn default() -> Self {
Self {
max_results: None,
max_context_length: None,
include_sources: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerceptionContext {
pub workspace: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub current_task: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub relevant_history: Option<Vec<HistoryItem>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryItem {
pub item_type: String,
pub content: String,
pub timestamp: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContextPerceptionEvent {
pub session_id: String,
pub intent: PerceptionIntent,
pub target: PerceptionTarget,
#[serde(default)]
pub domain: PerceptionDomain,
#[serde(default)]
pub preferred_modality: PerceptionModality,
#[serde(default)]
pub urgency: PerceptionUrgency,
#[serde(default)]
pub freshness: PerceptionFreshness,
pub context: PerceptionContext,
#[serde(default)]
pub constraints: PerceptionConstraints,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InjectedContext {
pub facts: Vec<Fact>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_contents: Option<Vec<FileContentSnippet>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub project_summary: Option<ProjectSummary>,
#[serde(skip_serializing_if = "Option::is_none")]
pub knowledge: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub suggestions: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileContentSnippet {
pub path: String,
pub snippet: String,
pub relevance_score: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectSummary {
pub project_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub key_files: Option<Vec<String>>,
pub structure_description: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "decision", rename_all = "lowercase")]
pub enum ContextPerceptionDecision {
Allow {
injected_context: InjectedContext,
#[serde(skip_serializing_if = "Option::is_none")]
metadata: Option<HashMap<String, serde_json::Value>>,
},
Block {
reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
metadata: Option<HashMap<String, serde_json::Value>>,
},
Refine {
refined_intent: Option<PerceptionIntent>,
refined_target: Option<PerceptionTarget>,
scope_hints: Vec<String>,
},
}