Skip to main content

oris_intake/
lib.rs

1//! Oris Intake - Automatic Issue Intake System for Self-Evolution
2//!
3//! This crate provides automatic issue intake capabilities:
4//! - CI/CD webhook listener (GitHub Actions, GitLab CI)
5//! - Monitoring alert integration (Prometheus, Sentry)
6//! - Error log signal extraction
7//! - Automatic mutation/task creation
8//!
9//! ## Architecture
10//!
11//! ```text
12//! External Source (CI/CD, Monitoring, Logs)
13//!     |
14//!     v
15//! IntakeSource (trait)
16//!     |
17//!     v
18//! SignalExtractor
19//!     |
20//!     v
21//! MutationBuilder -> Evolution Store
22//! ```
23
24mod continuous;
25mod mutation;
26mod prioritize;
27mod rules;
28#[cfg(feature = "webhook")]
29pub mod server;
30mod signal;
31mod source;
32
33pub use continuous::*;
34pub use mutation::*;
35pub use prioritize::*;
36pub use rules::*;
37pub use signal::*;
38pub use source::*;
39
40use serde::{Deserialize, Serialize};
41use thiserror::Error;
42
43/// Errors that can occur during intake processing
44#[derive(Error, Debug)]
45pub enum IntakeError {
46    #[error("Failed to parse webhook payload: {0}")]
47    ParseError(String),
48
49    #[error("Failed to extract signals: {0}")]
50    SignalExtractionError(String),
51
52    #[error("Failed to create mutation: {0}")]
53    MutationError(String),
54
55    #[error("Configuration error: {0}")]
56    ConfigError(String),
57
58    #[error("Storage error: {0}")]
59    StorageError(String),
60}
61
62/// Result type for intake operations
63pub type IntakeResult<T> = Result<T, IntakeError>;
64
65/// Configuration for the intake system
66#[derive(Clone, Debug, Serialize, Deserialize)]
67pub struct IntakeConfig {
68    /// Enable/disable the intake system
69    pub enabled: bool,
70
71    /// Supported intake sources
72    pub sources: Vec<IntakeSourceConfig>,
73
74    /// Signal extraction settings
75    pub signal_extraction: SignalExtractionConfig,
76
77    /// Intake rate limiting
78    pub rate_limit: RateLimitConfig,
79}
80
81impl Default for IntakeConfig {
82    fn default() -> Self {
83        Self {
84            enabled: true,
85            sources: vec![],
86            signal_extraction: SignalExtractionConfig::default(),
87            rate_limit: RateLimitConfig::default(),
88        }
89    }
90}
91
92/// Configuration for a specific intake source
93#[derive(Clone, Debug, Serialize, Deserialize)]
94pub struct IntakeSourceConfig {
95    /// Source type (github, gitlab, prometheus, sentry, etc.)
96    pub source_type: String,
97
98    /// Whether this source is enabled
99    pub enabled: bool,
100
101    /// Source-specific configuration
102    pub config: serde_json::Value,
103}
104
105/// Signal extraction configuration
106#[derive(Clone, Debug, Serialize, Deserialize)]
107pub struct SignalExtractionConfig {
108    /// Minimum confidence threshold for extracted signals
109    pub min_confidence: f32,
110
111    /// Maximum signals per intake event
112    pub max_signals: usize,
113
114    /// Whether to enable automatic pattern learning
115    pub enable_pattern_learning: bool,
116}
117
118impl Default for SignalExtractionConfig {
119    fn default() -> Self {
120        Self {
121            min_confidence: 0.5,
122            max_signals: 10,
123            enable_pattern_learning: false,
124        }
125    }
126}
127
128/// Rate limiting configuration
129#[derive(Clone, Debug, Serialize, Deserialize)]
130pub struct RateLimitConfig {
131    /// Maximum requests per minute
132    pub max_requests_per_minute: usize,
133
134    /// Maximum concurrent intakes
135    pub max_concurrent: usize,
136
137    /// Backoff duration on rate limit (seconds)
138    pub backoff_seconds: u64,
139}
140
141impl Default for RateLimitConfig {
142    fn default() -> Self {
143        Self {
144            max_requests_per_minute: 60,
145            max_concurrent: 10,
146            backoff_seconds: 60,
147        }
148    }
149}
150
151/// Generate a unique ID for intake events
152pub fn generate_intake_id(prefix: &str) -> String {
153    let uuid = uuid::Uuid::new_v4();
154    format!("{}-{}", prefix, uuid)
155}
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160
161    #[test]
162    fn test_generate_intake_id() {
163        let id = generate_intake_id("intake");
164        assert!(id.starts_with("intake-"));
165    }
166
167    #[test]
168    fn test_default_config() {
169        let config = IntakeConfig::default();
170        assert!(config.enabled);
171        assert!(config.sources.is_empty());
172    }
173}