fact_wasm_core/
lib.rs

1//! FACT - Fast Augmented Context Tools
2//! 
3//! A high-performance context processing engine with WebAssembly support.
4
5use wasm_bindgen::prelude::*;
6use serde::{Serialize, Deserialize};
7use std::collections::HashMap;
8
9// Re-export for library usage
10pub use crate::cache::FastCache;
11pub use crate::processor::QueryProcessor;
12
13mod cache;
14mod processor;
15#[cfg(feature = "optimizations")]
16mod optimizations;
17
18/// Initialize the WASM module
19#[wasm_bindgen(start)]
20pub fn init() {
21    // Set panic hook for better error messages in WASM
22    #[cfg(feature = "console_error_panic_hook")]
23    console_error_panic_hook::set_once();
24}
25
26/// Main FACT interface for WebAssembly
27#[wasm_bindgen]
28pub struct Fact {
29    cache: FastCache,
30    processor: QueryProcessor,
31}
32
33#[wasm_bindgen]
34impl Fact {
35    /// Create a new FACT instance
36    #[wasm_bindgen(constructor)]
37    pub fn new() -> Self {
38        Self {
39            cache: FastCache::new(),
40            processor: QueryProcessor::new(),
41        }
42    }
43
44    /// Process a query with optional caching
45    #[wasm_bindgen]
46    pub fn process(&mut self, query: &str, use_cache: bool) -> String {
47        if use_cache {
48            if let Some(cached) = self.cache.get(&query.to_string()) {
49                return cached;
50            }
51        }
52
53        let result = self.processor.process(&query.to_string());
54        
55        if use_cache {
56            self.cache.put(query.to_string(), result.clone());
57        }
58
59        result
60    }
61
62    /// Get cache statistics
63    #[wasm_bindgen]
64    pub fn get_cache_stats(&self) -> JsValue {
65        self.cache.get_stats()
66    }
67
68    /// Clear the cache
69    #[wasm_bindgen]
70    pub fn clear_cache(&mut self) {
71        self.cache.clear();
72    }
73
74    /// Optimize performance
75    #[wasm_bindgen]
76    pub fn optimize(&mut self, mode: &str) -> String {
77        match mode {
78            "aggressive" => {
79                self.cache.optimize_aggressive();
80                r#"{"optimized": true, "mode": "aggressive"}"#.to_string()
81            }
82            "memory" => {
83                self.cache.optimize_memory();
84                r#"{"optimized": true, "mode": "memory"}"#.to_string()
85            }
86            _ => {
87                self.cache.optimize();
88                r#"{"optimized": true, "mode": "standard"}"#.to_string()
89            }
90        }
91    }
92}
93
94/// Enhanced cognitive template definition with versioning and metadata
95#[derive(Serialize, Deserialize, Debug, Clone)]
96pub struct CognitiveTemplate {
97    pub id: String,
98    pub name: String, 
99    pub description: String,
100    pub version: String,
101    pub pattern: TemplatePattern,
102    pub cache_ttl: Option<u64>,
103    pub priority: TemplatePriority,
104    pub tags: Vec<String>,
105    pub created_at: String,
106    pub updated_at: String,
107    pub usage_count: u64,
108    pub success_rate: f64,
109    pub metadata: HashMap<String, serde_json::Value>,
110}
111
112/// Template priority levels for processing optimization
113#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
114pub enum TemplatePriority {
115    Critical,
116    High,
117    Medium,
118    Low,
119    Background,
120}
121
122/// Enhanced template pattern definition with optimization hints
123#[derive(Serialize, Deserialize, Debug, Clone)]
124pub struct TemplatePattern {
125    pub pattern_type: String,
126    pub steps: Vec<ProcessingStep>,
127    pub parallel_execution: bool,
128    pub optimization_hints: Vec<OptimizationHint>,
129    pub dependencies: Vec<String>,
130    pub expected_execution_time_ms: Option<f64>,
131    pub memory_requirements: Option<usize>,
132}
133
134/// Optimization hints for the template engine
135#[derive(Serialize, Deserialize, Debug, Clone)]
136pub enum OptimizationHint {
137    CacheAggressive,
138    ParallelProcessing,
139    MemoryOptimized,
140    SIMDVectorized,
141    BatchProcessing,
142    StreamProcessing,
143}
144
145/// Enhanced processing step with execution metadata
146#[derive(Serialize, Deserialize, Debug, Clone)]
147pub struct ProcessingStep {
148    pub step_type: String,
149    pub config: HashMap<String, serde_json::Value>,
150    pub step_id: String,
151    pub depends_on: Vec<String>,
152    pub retry_policy: RetryPolicy,
153    pub timeout_ms: Option<u64>,
154    pub validation_rules: Vec<ValidationRule>,
155    pub performance_metrics: Option<StepMetrics>,
156}
157
158/// Retry policy for failed processing steps
159#[derive(Serialize, Deserialize, Debug, Clone)]
160pub struct RetryPolicy {
161    pub max_attempts: u32,
162    pub backoff_strategy: BackoffStrategy,
163    pub retry_conditions: Vec<String>,
164}
165
166/// Backoff strategy for retries
167#[derive(Serialize, Deserialize, Debug, Clone)]
168pub enum BackoffStrategy {
169    Linear { delay_ms: u64 },
170    Exponential { base_delay_ms: u64, max_delay_ms: u64 },
171    Fixed { delay_ms: u64 },
172}
173
174/// Validation rules for processing steps
175#[derive(Serialize, Deserialize, Debug, Clone)]
176pub struct ValidationRule {
177    pub rule_type: String,
178    pub condition: String,
179    pub error_message: String,
180}
181
182/// Performance metrics for processing steps
183#[derive(Serialize, Deserialize, Debug, Clone)]
184pub struct StepMetrics {
185    pub execution_count: u64,
186    pub total_time_ms: f64,
187    pub average_time_ms: f64,
188    pub success_rate: f64,
189    pub error_count: u64,
190}
191
192/// Process a cognitive template (exposed to WASM)
193#[wasm_bindgen]
194pub fn process_template(template_json: &str, context_json: &str) -> String {
195    match (
196        serde_json::from_str::<CognitiveTemplate>(template_json),
197        serde_json::from_str::<serde_json::Value>(context_json),
198    ) {
199        (Ok(template), Ok(context)) => {
200            // Process the template with context
201            let result = apply_template(&template, &context);
202            serde_json::to_string(&result).unwrap_or_else(|e| {
203                format!(r#"{{"error": "Serialization failed: {}"}}"#, e)
204            })
205        }
206        (Err(e1), _) => format!(r#"{{"error": "Invalid template: {}"}}"#, e1),
207        (_, Err(e2)) => format!(r#"{{"error": "Invalid context: {}"}}"#, e2),
208    }
209}
210
211/// Apply a cognitive template to context with enhanced processing
212fn apply_template(template: &CognitiveTemplate, context: &serde_json::Value) -> serde_json::Value {
213    let start_time = js_sys::Date::now();
214    let mut result = context.clone();
215    let mut step_results = Vec::new();
216    let mut execution_metrics = HashMap::new();
217    
218    // Check if parallel execution is enabled
219    if template.pattern.parallel_execution && template.pattern.steps.len() > 1 {
220        result = process_steps_parallel(&template.pattern.steps, &result, &mut step_results);
221    } else {
222        result = process_steps_sequential(&template.pattern.steps, &result, &mut step_results);
223    }
224    
225    let execution_time = js_sys::Date::now() - start_time;
226    
227    // Apply optimization hints
228    for hint in &template.pattern.optimization_hints {
229        result = apply_optimization_hint(hint, &result);
230    }
231    
232    execution_metrics.insert("total_execution_time_ms".to_string(), serde_json::Value::Number(
233        serde_json::Number::from_f64(execution_time).unwrap()
234    ));
235    execution_metrics.insert("steps_executed".to_string(), serde_json::Value::Number(
236        serde_json::Number::from(template.pattern.steps.len())
237    ));
238    
239    serde_json::json!({
240        "template_id": template.id,
241        "template_version": template.version,
242        "result": result,
243        "step_results": step_results,
244        "execution_metrics": execution_metrics,
245        "processed_at": chrono::Utc::now().to_rfc3339(),
246        "success": true,
247        "cache_key": generate_cache_key(&template.id, context)
248    })
249}
250
251/// Process steps in parallel (simplified for WASM)
252fn process_steps_parallel(
253    steps: &[ProcessingStep], 
254    context: &serde_json::Value,
255    step_results: &mut Vec<serde_json::Value>
256) -> serde_json::Value {
257    // In a real implementation, this would use Web Workers or similar
258    // For now, we'll simulate parallel processing with optimized sequential execution
259    let mut result = context.clone();
260    
261    for step in steps {
262        let step_start = js_sys::Date::now();
263        let step_result = process_step(step, &result);
264        let step_time = js_sys::Date::now() - step_start;
265        
266        step_results.push(serde_json::json!({
267            "step_id": step.step_id,
268            "execution_time_ms": step_time,
269            "result": step_result
270        }));
271        
272        result = step_result;
273    }
274    
275    result
276}
277
278/// Process steps sequentially with dependency resolution
279fn process_steps_sequential(
280    steps: &[ProcessingStep], 
281    context: &serde_json::Value,
282    step_results: &mut Vec<serde_json::Value>
283) -> serde_json::Value {
284    let mut result = context.clone();
285    let mut completed_steps: HashMap<String, serde_json::Value> = HashMap::new();
286    
287    for step in steps {
288        // Check dependencies
289        if !step.depends_on.is_empty() {
290            for dep in &step.depends_on {
291                if !completed_steps.contains_key(dep) {
292                    // Dependency not met, skip this step or handle error
293                    continue;
294                }
295            }
296        }
297        
298        let step_start = js_sys::Date::now();
299        let step_result = process_step_with_retry(step, &result);
300        let step_time = js_sys::Date::now() - step_start;
301        
302        step_results.push(serde_json::json!({
303            "step_id": step.step_id,
304            "execution_time_ms": step_time,
305            "result": step_result
306        }));
307        
308        completed_steps.insert(step.step_id.clone(), step_result.clone());
309        result = step_result;
310    }
311    
312    result
313}
314
315/// Process a step with retry logic
316fn process_step_with_retry(step: &ProcessingStep, data: &serde_json::Value) -> serde_json::Value {
317    let mut attempt = 0;
318    let max_attempts = step.retry_policy.max_attempts;
319    
320    loop {
321        attempt += 1;
322        
323        // Validate input data
324        if let Err(validation_error) = validate_step_input(step, data) {
325            if attempt >= max_attempts {
326                return serde_json::json!({
327                    "error": "Validation failed",
328                    "message": validation_error,
329                    "step_id": step.step_id
330                });
331            }
332            continue;
333        }
334        
335        let result = process_step(step, data);
336        
337        // Check if result indicates success
338        if is_step_successful(&result) {
339            return result;
340        }
341        
342        if attempt >= max_attempts {
343            return serde_json::json!({
344                "error": "Max retry attempts exceeded",
345                "step_id": step.step_id,
346                "attempts": attempt
347            });
348        }
349        
350        // Apply backoff strategy
351        apply_backoff(&step.retry_policy.backoff_strategy, attempt);
352    }
353}
354
355/// Validate step input according to validation rules
356fn validate_step_input(step: &ProcessingStep, data: &serde_json::Value) -> Result<(), String> {
357    for rule in &step.validation_rules {
358        match rule.rule_type.as_str() {
359            "required_field" => {
360                if data.get(&rule.condition).is_none() {
361                    return Err(rule.error_message.clone());
362                }
363            },
364            "type_check" => {
365                // Implement type checking logic
366            },
367            "range_check" => {
368                // Implement range checking logic
369            },
370            _ => {}
371        }
372    }
373    Ok(())
374}
375
376/// Check if step execution was successful
377fn is_step_successful(result: &serde_json::Value) -> bool {
378    !result.get("error").is_some()
379}
380
381/// Apply backoff strategy for retry delays
382fn apply_backoff(strategy: &BackoffStrategy, _attempt: u32) {
383    // In WASM, we can't actually sleep, but we can simulate delay
384    // This would be implemented with actual async delays in a real system
385    match strategy {
386        BackoffStrategy::Linear { delay_ms: _ } => {
387            // Linear backoff: delay_ms * attempt
388        },
389        BackoffStrategy::Exponential { base_delay_ms: _, max_delay_ms: _ } => {
390            // Exponential backoff: min(base_delay_ms * 2^attempt, max_delay_ms)
391        },
392        BackoffStrategy::Fixed { delay_ms: _ } => {
393            // Fixed delay
394        }
395    }
396}
397
398/// Apply optimization hints to the result
399fn apply_optimization_hint(hint: &OptimizationHint, result: &serde_json::Value) -> serde_json::Value {
400    match hint {
401        OptimizationHint::CacheAggressive => {
402            // Add cache metadata
403            let mut optimized = result.clone();
404            if let serde_json::Value::Object(ref mut map) = optimized {
405                map.insert("_cache_hint".to_string(), serde_json::Value::String("aggressive".to_string()));
406            }
407            optimized
408        },
409        OptimizationHint::MemoryOptimized => {
410            // Compress or optimize data structure
411            compress_result(result)
412        },
413        OptimizationHint::SIMDVectorized => {
414            // Apply SIMD optimizations where possible
415            vectorize_result(result)
416        },
417        _ => result.clone()
418    }
419}
420
421/// Generate cache key for template and context
422fn generate_cache_key(template_id: &str, context: &serde_json::Value) -> String {
423    use std::collections::hash_map::DefaultHasher;
424    use std::hash::{Hash, Hasher};
425    
426    let context_str = serde_json::to_string(context).unwrap_or_default();
427    let mut hasher = DefaultHasher::new();
428    template_id.hash(&mut hasher);
429    context_str.hash(&mut hasher);
430    format!("tpl_{}_{:x}", template_id, hasher.finish())
431}
432
433/// Compress result for memory optimization
434fn compress_result(result: &serde_json::Value) -> serde_json::Value {
435    // Implement result compression logic
436    result.clone()
437}
438
439/// Vectorize result for SIMD optimization
440fn vectorize_result(result: &serde_json::Value) -> serde_json::Value {
441    // Implement vectorization logic
442    result.clone()
443}
444
445/// Process a single step in a template
446fn process_step(step: &ProcessingStep, data: &serde_json::Value) -> serde_json::Value {
447    match step.step_type.as_str() {
448        "transform" => transform_data(data, &step.config),
449        "analyze" => analyze_data(data, &step.config),
450        "synthesize" => synthesize_data(data, &step.config),
451        _ => data.clone(),
452    }
453}
454
455fn transform_data(data: &serde_json::Value, config: &HashMap<String, serde_json::Value>) -> serde_json::Value {
456    // Implement transformation logic based on config
457    let mut transformed = data.clone();
458    
459    if let Some(mode) = config.get("mode").and_then(|v| v.as_str()) {
460        match mode {
461            "expand" => {
462                // Expand the data structure
463                transformed = serde_json::json!({
464                    "original": data,
465                    "expanded": true,
466                    "timestamp": chrono::Utc::now().to_rfc3339(),
467                });
468            }
469            "compress" => {
470                // Compress the data structure
471                if let Some(obj) = data.as_object() {
472                    let compressed: serde_json::Map<String, serde_json::Value> = obj
473                        .iter()
474                        .filter(|(k, _)| !k.starts_with('_'))
475                        .map(|(k, v)| (k.clone(), v.clone()))
476                        .collect();
477                    transformed = serde_json::Value::Object(compressed);
478                }
479            }
480            _ => {}
481        }
482    }
483    
484    transformed
485}
486
487fn analyze_data(data: &serde_json::Value, config: &HashMap<String, serde_json::Value>) -> serde_json::Value {
488    let depth = config.get("depth")
489        .and_then(|v| v.as_str())
490        .unwrap_or("shallow");
491    
492    let analysis = match depth {
493        "deep" => {
494            serde_json::json!({
495                "data": data,
496                "analysis": {
497                    "type": detect_data_type(data),
498                    "complexity": calculate_complexity(data),
499                    "patterns": extract_patterns(data),
500                    "insights": generate_insights(data),
501                }
502            })
503        }
504        _ => {
505            serde_json::json!({
506                "data": data,
507                "analysis": {
508                    "type": detect_data_type(data),
509                    "summary": "Basic analysis completed",
510                }
511            })
512        }
513    };
514    
515    analysis
516}
517
518fn synthesize_data(data: &serde_json::Value, config: &HashMap<String, serde_json::Value>) -> serde_json::Value {
519    let format = config.get("format")
520        .and_then(|v| v.as_str())
521        .unwrap_or("summary");
522    
523    match format {
524        "insights" => {
525            serde_json::json!({
526                "insights": generate_insights(data),
527                "recommendations": generate_recommendations(data),
528                "confidence": 0.85,
529            })
530        }
531        "solution" => {
532            serde_json::json!({
533                "solution": "Optimized solution based on constraints",
534                "metrics": {
535                    "efficiency": 0.92,
536                    "cost": 0.78,
537                    "quality": 0.88,
538                },
539                "steps": ["Step 1", "Step 2", "Step 3"],
540            })
541        }
542        _ => {
543            serde_json::json!({
544                "summary": "Processing completed successfully",
545                "key_points": extract_key_points(data),
546            })
547        }
548    }
549}
550
551// Helper functions for analysis
552
553fn detect_data_type(data: &serde_json::Value) -> &'static str {
554    match data {
555        serde_json::Value::Object(_) => "object",
556        serde_json::Value::Array(_) => "array",
557        serde_json::Value::String(_) => "string",
558        serde_json::Value::Number(_) => "number",
559        serde_json::Value::Bool(_) => "boolean",
560        serde_json::Value::Null => "null",
561    }
562}
563
564fn calculate_complexity(data: &serde_json::Value) -> f64 {
565    let size = serde_json::to_string(data).unwrap_or_default().len();
566    let depth = calculate_depth(data, 0);
567    
568    (size as f64).log2() * (depth as f64)
569}
570
571fn calculate_depth(data: &serde_json::Value, current: usize) -> usize {
572    match data {
573        serde_json::Value::Object(map) => {
574            map.values()
575                .map(|v| calculate_depth(v, current + 1))
576                .max()
577                .unwrap_or(current + 1)
578        }
579        serde_json::Value::Array(arr) => {
580            arr.iter()
581                .map(|v| calculate_depth(v, current + 1))
582                .max()
583                .unwrap_or(current + 1)
584        }
585        _ => current,
586    }
587}
588
589fn extract_patterns(data: &serde_json::Value) -> Vec<String> {
590    let mut patterns = Vec::new();
591    
592    if let serde_json::Value::Object(map) = data {
593        if map.contains_key("query") || map.contains_key("question") {
594            patterns.push("inquiry".to_string());
595        }
596        if map.contains_key("data") || map.contains_key("dataset") {
597            patterns.push("analysis".to_string());
598        }
599        if map.contains_key("goal") || map.contains_key("objective") {
600            patterns.push("planning".to_string());
601        }
602    }
603    
604    patterns
605}
606
607fn generate_insights(_data: &serde_json::Value) -> Vec<String> {
608    vec![
609        "Pattern detected in data structure".to_string(),
610        "Optimization opportunity identified".to_string(),
611        "Potential for parallel processing".to_string(),
612    ]
613}
614
615fn generate_recommendations(_data: &serde_json::Value) -> Vec<String> {
616    vec![
617        "Consider caching for improved performance".to_string(),
618        "Implement batch processing for large datasets".to_string(),
619        "Use template specialization for common patterns".to_string(),
620    ]
621}
622
623fn extract_key_points(data: &serde_json::Value) -> Vec<String> {
624    vec![
625        format!("Data type: {}", detect_data_type(data)),
626        format!("Complexity score: {:.2}", calculate_complexity(data)),
627        "Processing completed successfully".to_string(),
628    ]
629}
630
631// External dependency for time operations in WASM
632mod chrono {
633    pub struct Utc;
634    
635    impl Utc {
636        pub fn now() -> DateTime {
637            DateTime
638        }
639    }
640    
641    pub struct DateTime;
642    
643    impl DateTime {
644        pub fn to_rfc3339(&self) -> String {
645            "2024-01-01T00:00:00Z".to_string()
646        }
647    }
648}
649
650#[cfg(test)]
651mod tests {
652    use super::*;
653
654    #[test]
655    fn test_fact_creation() {
656        let fact = Fact::new();
657        let stats = fact.get_cache_stats();
658        assert!(!stats.is_null());
659    }
660
661    #[test]
662    fn test_template_processing() {
663        let template = CognitiveTemplate {
664            id: "test".to_string(),
665            name: "Test Template".to_string(),
666            description: "Test".to_string(),
667            version: "1.0.0".to_string(),
668            pattern: TemplatePattern {
669                pattern_type: "sequential".to_string(),
670                steps: vec![],
671                parallel_execution: false,
672                optimization_hints: vec![],
673                dependencies: vec![],
674                expected_execution_time_ms: None,
675                memory_requirements: None,
676            },
677            cache_ttl: None,
678            priority: TemplatePriority::Medium,
679            tags: vec![],
680            created_at: "2024-01-01T00:00:00Z".to_string(),
681            updated_at: "2024-01-01T00:00:00Z".to_string(),
682            usage_count: 0,
683            success_rate: 1.0,
684            metadata: HashMap::new(),
685        };
686        
687        let context = serde_json::json!({"test": "data"});
688        let result = apply_template(&template, &context);
689        
690        assert!(result.get("template_id").is_some());
691        assert!(result.get("result").is_some());
692    }
693}