1use crate::engine::{
2 agenda::{ActivationGroupManager, AgendaManager},
3 analytics::RuleAnalytics,
4 facts::Facts,
5 knowledge_base::KnowledgeBase,
6 plugin::{PluginConfig, PluginHealth, PluginInfo, PluginManager, PluginStats, RulePlugin},
7 workflow::WorkflowEngine,
8};
9use crate::errors::{Result, RuleEngineError};
10use crate::types::{ActionType, Value};
11use chrono::{DateTime, Utc};
12use std::collections::HashMap;
13use std::sync::Arc;
14use std::time::{Duration, Instant};
15
16pub type CustomFunction = Box<dyn Fn(&[Value], &Facts) -> Result<Value> + Send + Sync>;
18
19pub type ActionHandler = Box<dyn Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync>;
21
22#[derive(Debug, Clone)]
24pub struct EngineConfig {
25 pub max_cycles: usize,
27 pub timeout: Option<Duration>,
29 pub enable_stats: bool,
31 pub debug_mode: bool,
33}
34
35impl Default for EngineConfig {
36 fn default() -> Self {
37 Self {
38 max_cycles: 100,
39 timeout: Some(Duration::from_secs(30)),
40 enable_stats: true,
41 debug_mode: false,
42 }
43 }
44}
45
46#[derive(Debug, Clone)]
48pub struct GruleExecutionResult {
49 pub cycle_count: usize,
51 pub rules_evaluated: usize,
53 pub rules_fired: usize,
55 pub execution_time: Duration,
57}
58
59pub struct RustRuleEngine {
61 knowledge_base: KnowledgeBase,
62 config: EngineConfig,
63 custom_functions: HashMap<String, CustomFunction>,
64 action_handlers: HashMap<String, ActionHandler>,
65 analytics: Option<RuleAnalytics>,
66 agenda_manager: AgendaManager,
67 activation_group_manager: ActivationGroupManager,
68 fired_rules_global: std::collections::HashSet<String>,
70 workflow_engine: WorkflowEngine,
72 plugin_manager: PluginManager,
74}
75
76impl RustRuleEngine {
77 pub fn execute_with_callback<F>(&mut self, facts: &Facts, mut on_rule_fired: F) -> Result<GruleExecutionResult>
79 where
80 F: FnMut(&str, &str),
81 {
82 use chrono::Utc;
83 let timestamp = Utc::now();
84 let start_time = std::time::Instant::now();
85 let mut cycle_count = 0;
86 let mut rules_evaluated = 0;
87 let mut rules_fired = 0;
88
89 self.sync_workflow_agenda_activations();
90
91 for cycle in 0..self.config.max_cycles {
92 cycle_count = cycle + 1;
93 let mut any_rule_fired = false;
94 let mut fired_rules_in_cycle = std::collections::HashSet::new();
95 self.activation_group_manager.reset_cycle();
96
97 if let Some(timeout) = self.config.timeout {
98 if start_time.elapsed() > timeout {
99 return Err(crate::errors::RuleEngineError::EvaluationError {
100 message: "Execution timeout exceeded".to_string(),
101 });
102 }
103 }
104
105 let mut rules = self.knowledge_base.get_rules().clone();
106 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
107 let rules: Vec<_> = rules
108 .iter()
109 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
110 .collect();
111
112 for rule in &rules {
113 if !rule.enabled {
114 continue;
115 }
116 if !rule.is_active_at(timestamp) {
117 continue;
118 }
119 if !self.agenda_manager.can_fire_rule(rule) {
120 continue;
121 }
122 if !self.activation_group_manager.can_fire(rule) {
123 continue;
124 }
125 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
126 continue;
127 }
128 rules_evaluated += 1;
129 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
130 if condition_result {
131 for action in &rule.actions {
132 self.execute_action(action, facts)?;
133 }
134 rules_fired += 1;
135 any_rule_fired = true;
136 fired_rules_in_cycle.insert(rule.name.clone());
137 if rule.no_loop {
138 self.fired_rules_global.insert(rule.name.clone());
139 }
140 self.agenda_manager.mark_rule_fired(rule);
141 self.activation_group_manager.mark_fired(rule);
142 on_rule_fired(&rule.name, "facts"); }
145 }
146 if !any_rule_fired {
147 break;
148 }
149 self.sync_workflow_agenda_activations();
150 }
151 let execution_time = start_time.elapsed();
152 Ok(crate::engine::GruleExecutionResult {
153 cycle_count,
154 rules_evaluated,
155 rules_fired,
156 execution_time,
157 })
158 }
159 pub fn new(knowledge_base: KnowledgeBase) -> Self {
161 Self {
162 knowledge_base,
163 config: EngineConfig::default(),
164 custom_functions: HashMap::new(),
165 action_handlers: HashMap::new(),
166 analytics: None,
167 agenda_manager: AgendaManager::new(),
168 activation_group_manager: ActivationGroupManager::new(),
169 fired_rules_global: std::collections::HashSet::new(),
170 workflow_engine: WorkflowEngine::new(),
171 plugin_manager: PluginManager::with_default_config(),
172 }
173 }
174
175 pub fn with_config(knowledge_base: KnowledgeBase, config: EngineConfig) -> Self {
177 Self {
178 knowledge_base,
179 config,
180 custom_functions: HashMap::new(),
181 action_handlers: HashMap::new(),
182 analytics: None,
183 agenda_manager: AgendaManager::new(),
184 activation_group_manager: ActivationGroupManager::new(),
185 fired_rules_global: std::collections::HashSet::new(),
186 workflow_engine: WorkflowEngine::new(),
187 plugin_manager: PluginManager::with_default_config(),
188 }
189 }
190
191 pub fn register_function<F>(&mut self, name: &str, func: F)
193 where
194 F: Fn(&[Value], &Facts) -> Result<Value> + Send + Sync + 'static,
195 {
196 self.custom_functions
197 .insert(name.to_string(), Box::new(func));
198 }
199
200 pub fn register_action_handler<F>(&mut self, action_type: &str, handler: F)
202 where
203 F: Fn(&HashMap<String, Value>, &Facts) -> Result<()> + Send + Sync + 'static,
204 {
205 self.action_handlers
206 .insert(action_type.to_string(), Box::new(handler));
207 }
208
209 pub fn enable_analytics(&mut self, analytics: RuleAnalytics) {
211 self.analytics = Some(analytics);
212 }
213
214 pub fn reset_no_loop_tracking(&mut self) {
216 self.fired_rules_global.clear();
217 }
218
219 pub fn disable_analytics(&mut self) {
221 self.analytics = None;
222 }
223
224 pub fn analytics(&self) -> Option<&RuleAnalytics> {
226 self.analytics.as_ref()
227 }
228
229 pub fn has_function(&self, name: &str) -> bool {
231 self.custom_functions.contains_key(name)
232 }
233
234 pub fn has_action_handler(&self, action_type: &str) -> bool {
236 self.action_handlers.contains_key(action_type)
237 }
238
239 pub fn get_ready_tasks(&mut self) -> Vec<crate::engine::workflow::ScheduledTask> {
241 self.workflow_engine.get_ready_tasks()
242 }
243
244 pub fn execute_scheduled_tasks(&mut self, facts: &Facts) -> Result<()> {
246 let ready_tasks = self.get_ready_tasks();
247 for task in ready_tasks {
248 if let Some(rule) = self
249 .knowledge_base
250 .get_rules()
251 .iter()
252 .find(|r| r.name == task.rule_name)
253 {
254 if self.config.debug_mode {
255 println!("⚡ Executing scheduled task: {}", task.rule_name);
256 }
257
258 if self.evaluate_conditions(&rule.conditions, facts)? {
260 for action in &rule.actions {
261 self.execute_action(action, facts)?;
262 }
263 }
264 }
265 }
266 Ok(())
267 }
268
269 pub fn activate_agenda_group(&mut self, group: String) {
271 self.workflow_engine.activate_agenda_group(group.clone());
272 self.agenda_manager.set_focus(&group);
273 }
274
275 pub fn knowledge_base(&self) -> &KnowledgeBase {
277 &self.knowledge_base
278 }
279
280 pub fn knowledge_base_mut(&mut self) -> &mut KnowledgeBase {
282 &mut self.knowledge_base
283 }
284
285 fn sync_workflow_agenda_activations(&mut self) {
287 while let Some(agenda_group) = self.workflow_engine.get_next_pending_agenda_activation() {
289 if self.config.debug_mode {
290 println!("🔄 Syncing workflow agenda activation: {}", agenda_group);
291 }
292 self.agenda_manager.set_focus(&agenda_group);
293 }
294 }
295
296 pub fn set_agenda_focus(&mut self, group: &str) {
298 self.agenda_manager.set_focus(group);
299 }
300
301 pub fn get_active_agenda_group(&self) -> &str {
303 self.agenda_manager.get_active_group()
304 }
305
306 pub fn pop_agenda_focus(&mut self) -> Option<String> {
308 self.agenda_manager.pop_focus()
309 }
310
311 pub fn clear_agenda_focus(&mut self) {
313 self.agenda_manager.clear_focus();
314 }
315
316 pub fn get_agenda_groups(&self) -> Vec<String> {
318 self.agenda_manager
319 .get_agenda_groups(&self.knowledge_base.get_rules())
320 }
321
322 pub fn get_activation_groups(&self) -> Vec<String> {
324 self.activation_group_manager
325 .get_activation_groups(&self.knowledge_base.get_rules())
326 }
327
328 pub fn start_workflow(&mut self, workflow_name: Option<String>) -> String {
332 self.workflow_engine.start_workflow(workflow_name)
333 }
334
335 pub fn get_workflow_stats(&self) -> crate::engine::workflow::WorkflowStats {
337 self.workflow_engine.get_workflow_stats()
338 }
339
340 pub fn get_workflow(
342 &self,
343 workflow_id: &str,
344 ) -> Option<&crate::engine::workflow::WorkflowState> {
345 self.workflow_engine.get_workflow(workflow_id)
346 }
347
348 pub fn cleanup_completed_workflows(&mut self, older_than: Duration) {
350 self.workflow_engine.cleanup_completed_workflows(older_than);
351 }
352
353 pub fn execute_workflow_step(
355 &mut self,
356 agenda_group: &str,
357 facts: &Facts,
358 ) -> Result<GruleExecutionResult> {
359 self.set_agenda_focus(agenda_group);
361
362 let result = self.execute(facts)?;
364
365 self.process_workflow_actions(facts)?;
367
368 Ok(result)
369 }
370
371 pub fn execute_workflow(
373 &mut self,
374 agenda_groups: Vec<&str>,
375 facts: &Facts,
376 ) -> Result<crate::engine::workflow::WorkflowResult> {
377 let start_time = Instant::now();
378 let mut total_steps = 0;
379
380 if self.config.debug_mode {
381 println!(
382 "🔄 Starting workflow execution with {} steps",
383 agenda_groups.len()
384 );
385 }
386
387 for (i, group) in agenda_groups.iter().enumerate() {
388 if self.config.debug_mode {
389 println!("📋 Executing workflow step {}: {}", i + 1, group);
390 }
391
392 let step_result = self.execute_workflow_step(group, facts)?;
393 total_steps += 1;
394
395 if step_result.rules_fired == 0 {
396 if self.config.debug_mode {
397 println!("⏸️ No rules fired in step '{}', stopping workflow", group);
398 }
399 break;
400 }
401 }
402
403 let execution_time = start_time.elapsed();
404
405 Ok(crate::engine::workflow::WorkflowResult::success(
406 total_steps,
407 execution_time,
408 ))
409 }
410
411 fn process_workflow_actions(&mut self, facts: &Facts) -> Result<()> {
413 while let Some(group) = self.workflow_engine.get_next_agenda_group() {
415 self.set_agenda_focus(&group);
416 }
417
418 let ready_tasks = self.workflow_engine.get_ready_tasks();
420 for task in ready_tasks {
421 if self.config.debug_mode {
422 println!("⚡ Executing scheduled task: {}", task.rule_name);
423 }
424
425 if let Some(rule) = self
427 .knowledge_base
428 .get_rules()
429 .iter()
430 .find(|r| r.name == task.rule_name)
431 {
432 if self.evaluate_conditions(&rule.conditions, facts)? {
434 for action in &rule.actions {
435 self.execute_action(action, facts)?;
436 }
437 }
438 }
439 }
440
441 Ok(())
442 }
443
444 pub fn execute(&mut self, facts: &Facts) -> Result<GruleExecutionResult> {
446 self.execute_at_time(facts, Utc::now())
447 }
448
449 pub fn execute_at_time(
451 &mut self,
452 facts: &Facts,
453 timestamp: DateTime<Utc>,
454 ) -> Result<GruleExecutionResult> {
455 let start_time = Instant::now();
456 let mut cycle_count = 0;
457 let mut rules_evaluated = 0;
458 let mut rules_fired = 0;
459
460 self.sync_workflow_agenda_activations();
462
463 if self.config.debug_mode {
464 println!(
465 "🚀 Starting rule execution with {} rules (agenda group: {})",
466 self.knowledge_base.get_rules().len(),
467 self.agenda_manager.get_active_group()
468 );
469 }
470
471 for cycle in 0..self.config.max_cycles {
472 cycle_count = cycle + 1;
473 let mut any_rule_fired = false;
474 let mut fired_rules_in_cycle = std::collections::HashSet::new();
475
476 self.activation_group_manager.reset_cycle();
478
479 if let Some(timeout) = self.config.timeout {
481 if start_time.elapsed() > timeout {
482 return Err(RuleEngineError::EvaluationError {
483 message: "Execution timeout exceeded".to_string(),
484 });
485 }
486 }
487
488 let mut rules = self.knowledge_base.get_rules().clone();
490 rules.sort_by(|a, b| b.salience.cmp(&a.salience));
491
492 let rules: Vec<_> = rules
494 .iter()
495 .filter(|rule| self.agenda_manager.should_evaluate_rule(rule))
496 .collect();
497
498 for rule in &rules {
499 if !rule.enabled {
500 continue;
501 }
502
503 if !rule.is_active_at(timestamp) {
505 continue;
506 }
507
508 if !self.agenda_manager.can_fire_rule(rule) {
510 continue;
511 }
512
513 if !self.activation_group_manager.can_fire(rule) {
515 continue;
516 }
517
518 if rule.no_loop && self.fired_rules_global.contains(&rule.name) {
520 continue;
521 }
522
523 rules_evaluated += 1;
524 let rule_start = Instant::now();
525
526 if self.config.debug_mode {
527 println!("📝 Evaluating rule: {}", rule.name);
528 }
529
530 let condition_result = self.evaluate_conditions(&rule.conditions, facts)?;
532 if self.config.debug_mode {
533 println!(
534 " 🔍 Condition result for '{}': {}",
535 rule.name, condition_result
536 );
537 }
538
539 if condition_result {
540 if self.config.debug_mode {
541 println!(
542 "🔥 Rule '{}' fired (salience: {})",
543 rule.name, rule.salience
544 );
545 }
546
547 for action in &rule.actions {
549 self.execute_action(action, facts)?;
550 }
551
552 let rule_duration = rule_start.elapsed();
553
554 if let Some(analytics) = &mut self.analytics {
556 analytics.record_execution(&rule.name, rule_duration, true, true, None, 0);
557 }
558
559 rules_fired += 1;
560 any_rule_fired = true;
561
562 fired_rules_in_cycle.insert(rule.name.clone());
564
565 if rule.no_loop {
567 self.fired_rules_global.insert(rule.name.clone());
568 }
569
570 self.agenda_manager.mark_rule_fired(rule);
572 self.activation_group_manager.mark_fired(rule);
573 } else {
574 let rule_duration = rule_start.elapsed();
575
576 if let Some(analytics) = &mut self.analytics {
578 analytics.record_execution(
579 &rule.name,
580 rule_duration,
581 false,
582 false,
583 None,
584 0,
585 );
586 }
587 }
588 }
589
590 if !any_rule_fired {
592 break;
593 }
594
595 self.sync_workflow_agenda_activations();
597 }
598
599 let execution_time = start_time.elapsed();
600
601 Ok(GruleExecutionResult {
602 cycle_count,
603 rules_evaluated,
604 rules_fired,
605 execution_time,
606 })
607 }
608
609 fn evaluate_conditions(
611 &self,
612 conditions: &crate::engine::rule::ConditionGroup,
613 facts: &Facts,
614 ) -> Result<bool> {
615 use crate::engine::pattern_matcher::PatternMatcher;
616 use crate::engine::rule::ConditionGroup;
617
618 match conditions {
619 ConditionGroup::Single(condition) => self.evaluate_single_condition(condition, facts),
620 ConditionGroup::Compound {
621 left,
622 operator,
623 right,
624 } => {
625 let left_result = self.evaluate_conditions(left, facts)?;
626 let right_result = self.evaluate_conditions(right, facts)?;
627
628 match operator {
629 crate::types::LogicalOperator::And => Ok(left_result && right_result),
630 crate::types::LogicalOperator::Or => Ok(left_result || right_result),
631 crate::types::LogicalOperator::Not => Err(RuleEngineError::EvaluationError {
632 message: "NOT operator should not appear in compound conditions"
633 .to_string(),
634 }),
635 }
636 }
637 ConditionGroup::Not(condition) => {
638 let result = self.evaluate_conditions(condition, facts)?;
639 Ok(!result)
640 }
641 ConditionGroup::Exists(condition) => {
643 Ok(PatternMatcher::evaluate_exists(condition, facts))
644 }
645 ConditionGroup::Forall(condition) => {
646 Ok(PatternMatcher::evaluate_forall(condition, facts))
647 }
648 ConditionGroup::Accumulate {
649 result_var,
650 source_pattern,
651 extract_field,
652 source_conditions,
653 function,
654 function_arg,
655 } => {
656 self.evaluate_accumulate(
658 result_var,
659 source_pattern,
660 extract_field,
661 source_conditions,
662 function,
663 function_arg,
664 facts,
665 )?;
666 Ok(true)
668 }
669 }
670 }
671
672 fn evaluate_accumulate(
674 &self,
675 result_var: &str,
676 source_pattern: &str,
677 extract_field: &str,
678 source_conditions: &[String],
679 function: &str,
680 function_arg: &str,
681 facts: &Facts,
682 ) -> Result<()> {
683 use crate::rete::accumulate::*;
684
685 let all_facts = facts.get_all_facts();
687 let mut matching_values = Vec::new();
688
689 let pattern_prefix = format!("{}.", source_pattern);
691
692 let mut instances: HashMap<String, HashMap<String, Value>> = HashMap::new();
694
695 for (key, value) in &all_facts {
696 if key.starts_with(&pattern_prefix) {
697 let parts: Vec<&str> = key.strip_prefix(&pattern_prefix).unwrap().split('.').collect();
699
700 if parts.len() >= 2 {
701 let instance_id = parts[0];
703 let field_name = parts[1..].join(".");
704
705 instances
706 .entry(instance_id.to_string())
707 .or_insert_with(HashMap::new)
708 .insert(field_name, value.clone());
709 } else if parts.len() == 1 {
710 instances
712 .entry("default".to_string())
713 .or_insert_with(HashMap::new)
714 .insert(parts[0].to_string(), value.clone());
715 }
716 }
717 }
718
719 for (_instance_id, instance_facts) in instances {
721 let mut matches = true;
723
724 for condition_str in source_conditions {
725 if !self.evaluate_condition_string(condition_str, &instance_facts) {
727 matches = false;
728 break;
729 }
730 }
731
732 if matches {
733 if let Some(value) = instance_facts.get(extract_field) {
735 matching_values.push(value.clone());
736 }
737 }
738 }
739
740 let result = match function {
742 "sum" => {
743 let mut state = SumFunction.init();
744 for value in &matching_values {
745 state.accumulate(&self.value_to_fact_value(value));
746 }
747 self.fact_value_to_value(&state.get_result())
748 }
749 "count" => {
750 let mut state = CountFunction.init();
751 for value in &matching_values {
752 state.accumulate(&self.value_to_fact_value(value));
753 }
754 self.fact_value_to_value(&state.get_result())
755 }
756 "average" | "avg" => {
757 let mut state = AverageFunction.init();
758 for value in &matching_values {
759 state.accumulate(&self.value_to_fact_value(value));
760 }
761 self.fact_value_to_value(&state.get_result())
762 }
763 "min" => {
764 let mut state = MinFunction.init();
765 for value in &matching_values {
766 state.accumulate(&self.value_to_fact_value(value));
767 }
768 self.fact_value_to_value(&state.get_result())
769 }
770 "max" => {
771 let mut state = MaxFunction.init();
772 for value in &matching_values {
773 state.accumulate(&self.value_to_fact_value(value));
774 }
775 self.fact_value_to_value(&state.get_result())
776 }
777 _ => {
778 return Err(RuleEngineError::EvaluationError {
779 message: format!("Unknown accumulate function: {}", function),
780 });
781 }
782 };
783
784 let result_key = format!("{}.{}", source_pattern, function);
787
788 facts.set(&result_key, result);
789
790 if self.config.debug_mode {
791 println!(" 🧮 Accumulate result: {} = {:?}", result_key, facts.get(&result_key));
792 }
793
794 Ok(())
795 }
796
797 fn value_to_fact_value(&self, value: &Value) -> crate::rete::facts::FactValue {
799 use crate::rete::facts::FactValue;
800 match value {
801 Value::Integer(i) => FactValue::Integer(*i),
802 Value::Number(n) => FactValue::Float(*n),
803 Value::String(s) => FactValue::String(s.clone()),
804 Value::Boolean(b) => FactValue::Boolean(*b),
805 _ => FactValue::String(value.to_string()),
806 }
807 }
808
809 fn fact_value_to_value(&self, fact_value: &crate::rete::facts::FactValue) -> Value {
811 use crate::rete::facts::FactValue;
812 match fact_value {
813 FactValue::Integer(i) => Value::Integer(*i),
814 FactValue::Float(f) => Value::Number(*f),
815 FactValue::String(s) => Value::String(s.clone()),
816 FactValue::Boolean(b) => Value::Boolean(*b),
817 FactValue::Array(_) => Value::String(format!("{:?}", fact_value)),
818 FactValue::Null => Value::String("null".to_string()),
819 }
820 }
821
822 fn evaluate_condition_string(&self, condition: &str, facts: &HashMap<String, Value>) -> bool {
824 let condition = condition.trim();
826
827 let operators = ["==", "!=", ">=", "<=", ">", "<"];
829
830 for op in &operators {
831 if let Some(pos) = condition.find(op) {
832 let field = condition[..pos].trim();
833 let value_str = condition[pos + op.len()..].trim()
834 .trim_matches('"')
835 .trim_matches('\'');
836
837 if let Some(field_value) = facts.get(field) {
838 return self.compare_values(field_value, op, value_str);
839 } else {
840 return false;
841 }
842 }
843 }
844
845 false
846 }
847
848 fn compare_values(&self, field_value: &Value, operator: &str, value_str: &str) -> bool {
850 match field_value {
851 Value::String(s) => {
852 match operator {
853 "==" => s == value_str,
854 "!=" => s != value_str,
855 _ => false,
856 }
857 }
858 Value::Integer(i) => {
859 if let Ok(num) = value_str.parse::<i64>() {
860 match operator {
861 "==" => *i == num,
862 "!=" => *i != num,
863 ">" => *i > num,
864 "<" => *i < num,
865 ">=" => *i >= num,
866 "<=" => *i <= num,
867 _ => false,
868 }
869 } else {
870 false
871 }
872 }
873 Value::Number(n) => {
874 if let Ok(num) = value_str.parse::<f64>() {
875 match operator {
876 "==" => (*n - num).abs() < f64::EPSILON,
877 "!=" => (*n - num).abs() >= f64::EPSILON,
878 ">" => *n > num,
879 "<" => *n < num,
880 ">=" => *n >= num,
881 "<=" => *n <= num,
882 _ => false,
883 }
884 } else {
885 false
886 }
887 }
888 Value::Boolean(b) => {
889 if let Ok(bool_val) = value_str.parse::<bool>() {
890 match operator {
891 "==" => *b == bool_val,
892 "!=" => *b != bool_val,
893 _ => false,
894 }
895 } else {
896 false
897 }
898 }
899 _ => false,
900 }
901 }
902
903 fn evaluate_rule_conditions(
905 &self,
906 rule: &crate::engine::rule::Rule,
907 facts: &Facts,
908 ) -> Result<bool> {
909 self.evaluate_conditions(&rule.conditions, facts)
910 }
911
912 fn is_retracted(&self, object_name: &str, facts: &Facts) -> bool {
914 let retract_key = format!("_retracted_{}", object_name);
915 matches!(facts.get(&retract_key), Some(Value::Boolean(true)))
916 }
917
918 fn evaluate_single_condition(
920 &self,
921 condition: &crate::engine::rule::Condition,
922 facts: &Facts,
923 ) -> Result<bool> {
924 use crate::engine::rule::ConditionExpression;
925
926 let result = match &condition.expression {
927 ConditionExpression::Field(field_name) => {
928 if let Some(object_name) = field_name.split('.').next() {
931 if self.is_retracted(object_name, facts) {
932 if self.config.debug_mode {
933 println!(" 🗑️ Skipping retracted fact: {}", object_name);
934 }
935 return Ok(false);
936 }
937 }
938
939 let field_value = facts
941 .get_nested(field_name)
942 .or_else(|| facts.get(field_name));
943
944 if self.config.debug_mode {
945 println!(
946 " 🔎 Evaluating field condition: {} {} {:?}",
947 field_name,
948 format!("{:?}", condition.operator).to_lowercase(),
949 condition.value
950 );
951 println!(" Field value: {:?}", field_value);
952 }
953
954 if let Some(value) = field_value {
955 let rhs = match &condition.value {
961 crate::types::Value::String(s) => {
962 facts
964 .get_nested(s)
965 .or_else(|| facts.get(s))
966 .unwrap_or(crate::types::Value::String(s.clone()))
967 }
968 _ => condition.value.clone(),
969 };
970
971 if self.config.debug_mode {
972 println!(" Resolved RHS for comparison: {:?}", rhs);
973 }
974
975 condition.operator.evaluate(&value, &rhs)
976 } else {
977 false
978 }
979 }
980 ConditionExpression::FunctionCall { name, args } => {
981 if self.config.debug_mode {
983 println!(
984 " 🔎 Evaluating function condition: {}({:?}) {} {:?}",
985 name,
986 args,
987 format!("{:?}", condition.operator).to_lowercase(),
988 condition.value
989 );
990 }
991
992 if let Some(function) = self.custom_functions.get(name) {
993 let arg_values: Vec<Value> = args
995 .iter()
996 .map(|arg| {
997 facts
998 .get_nested(arg)
999 .or_else(|| facts.get(arg))
1000 .unwrap_or(Value::String(arg.clone()))
1001 })
1002 .collect();
1003
1004 match function(&arg_values, facts) {
1006 Ok(result_value) => {
1007 if self.config.debug_mode {
1008 println!(" Function result: {:?}", result_value);
1009 }
1010 condition.operator.evaluate(&result_value, &condition.value)
1011 }
1012 Err(e) => {
1013 if self.config.debug_mode {
1014 println!(" Function error: {}", e);
1015 }
1016 false
1017 }
1018 }
1019 } else {
1020 if self.config.debug_mode {
1021 println!(" Function '{}' not found", name);
1022 }
1023 false
1024 }
1025 }
1026 ConditionExpression::Test { name, args } => {
1027 if self.config.debug_mode {
1029 println!(" 🧪 Evaluating test CE: test({}({:?}))", name, args);
1030 }
1031
1032 if let Some(function) = self.custom_functions.get(name) {
1033 let arg_values: Vec<Value> = args
1035 .iter()
1036 .map(|arg| {
1037 let resolved = facts
1038 .get_nested(arg)
1039 .or_else(|| facts.get(arg))
1040 .unwrap_or(Value::String(arg.clone()));
1041 if self.config.debug_mode {
1042 println!(" Resolving arg '{}' -> {:?}", arg, resolved);
1043 }
1044 resolved
1045 })
1046 .collect();
1047
1048 match function(&arg_values, facts) {
1050 Ok(result_value) => {
1051 if self.config.debug_mode {
1052 println!(" Test result: {:?}", result_value);
1053 }
1054 match result_value {
1056 Value::Boolean(b) => b,
1057 Value::Integer(i) => i != 0,
1058 Value::Number(f) => f != 0.0,
1059 Value::String(s) => !s.is_empty(),
1060 _ => false,
1061 }
1062 }
1063 Err(e) => {
1064 if self.config.debug_mode {
1065 println!(" Test function error: {}", e);
1066 }
1067 false
1068 }
1069 }
1070 } else {
1071 if self.config.debug_mode {
1072 println!(" Test function '{}' not found", name);
1073 }
1074 false
1075 }
1076 }
1077 };
1078
1079 if self.config.debug_mode {
1080 println!(" Result: {}", result);
1081 }
1082
1083 Ok(result)
1084 }
1085
1086 fn execute_action(&mut self, action: &ActionType, facts: &Facts) -> Result<()> {
1088 match action {
1089 ActionType::Set { field, value } => {
1090 if let Err(_) = facts.set_nested(field, value.clone()) {
1092 facts.set(field, value.clone());
1094 }
1095 if self.config.debug_mode {
1096 println!(" ✅ Set {field} = {value:?}");
1097 }
1098 }
1099 ActionType::Log { message } => {
1100 println!("📋 LOG: {}", message);
1101 }
1102 ActionType::Call { function, args } => {
1103 let result = self.execute_function_call(function, args, facts)?;
1104 if self.config.debug_mode {
1105 println!(" 📞 Called {function}({args:?}) -> {result}");
1106 }
1107 }
1108 ActionType::MethodCall {
1109 object,
1110 method,
1111 args,
1112 } => {
1113 let result = self.execute_method_call(object, method, args, facts)?;
1114 if self.config.debug_mode {
1115 println!(" 🔧 Called {object}.{method}({args:?}) -> {result}");
1116 }
1117 }
1118 ActionType::Update { object } => {
1119 if self.config.debug_mode {
1120 println!(" 🔄 Updated {object}");
1121 }
1122 }
1125 ActionType::Retract { object } => {
1126 if self.config.debug_mode {
1127 println!(" 🗑️ Retracted {object}");
1128 }
1129 facts.set(&format!("_retracted_{}", object), Value::Boolean(true));
1131 }
1132 ActionType::Custom {
1133 action_type,
1134 params,
1135 } => {
1136 if let Some(handler) = self.action_handlers.get(action_type) {
1137 if self.config.debug_mode {
1138 println!(
1139 " 🎯 Executing custom action: {action_type} with params: {params:?}"
1140 );
1141 }
1142
1143 let resolved_params = self.resolve_action_parameters(params, facts)?;
1145
1146 handler(&resolved_params, facts)?;
1148 } else {
1149 if self.config.debug_mode {
1150 println!(" ⚠️ No handler registered for custom action: {action_type}");
1151 println!(
1152 " Available handlers: {:?}",
1153 self.action_handlers.keys().collect::<Vec<_>>()
1154 );
1155 }
1156
1157 return Err(RuleEngineError::EvaluationError {
1159 message: format!(
1160 "No action handler registered for '{action_type}'. Use engine.register_action_handler() to add custom action handlers."
1161 ),
1162 });
1163 }
1164 }
1165 ActionType::ActivateAgendaGroup { group } => {
1167 if self.config.debug_mode {
1168 println!(" 🎯 Activating agenda group: {}", group);
1169 }
1170 self.workflow_engine.activate_agenda_group(group.clone());
1172 self.agenda_manager.set_focus(group);
1173 }
1174 ActionType::ScheduleRule {
1175 rule_name,
1176 delay_ms,
1177 } => {
1178 if self.config.debug_mode {
1179 println!(
1180 " ⏰ Scheduling rule '{}' to execute in {}ms",
1181 rule_name, delay_ms
1182 );
1183 }
1184 self.workflow_engine
1185 .schedule_rule(rule_name.clone(), *delay_ms, None);
1186 }
1187 ActionType::CompleteWorkflow { workflow_name } => {
1188 if self.config.debug_mode {
1189 println!(" ✅ Completing workflow: {}", workflow_name);
1190 }
1191 self.workflow_engine
1192 .complete_workflow(workflow_name.clone());
1193 }
1194 ActionType::SetWorkflowData { key, value } => {
1195 if self.config.debug_mode {
1196 println!(" 💾 Setting workflow data: {} = {:?}", key, value);
1197 }
1198 let workflow_id = "default_workflow";
1201 self.workflow_engine
1202 .set_workflow_data(workflow_id, key.clone(), value.clone());
1203 }
1204 }
1205 Ok(())
1206 }
1207
1208 fn execute_function_call(
1210 &self,
1211 function: &str,
1212 args: &[Value],
1213 facts: &Facts,
1214 ) -> Result<String> {
1215 let function_lower = function.to_lowercase();
1216
1217 match function_lower.as_str() {
1219 "log" | "print" | "println" => self.handle_log_function(args),
1220 "update" | "refresh" => self.handle_update_function(args),
1221 "now" | "timestamp" => self.handle_timestamp_function(),
1222 "random" => self.handle_random_function(args),
1223 "format" | "sprintf" => self.handle_format_function(args),
1224 "length" | "size" | "count" => self.handle_length_function(args),
1225 "sum" | "add" => self.handle_sum_function(args),
1226 "max" | "maximum" => self.handle_max_function(args),
1227 "min" | "minimum" => self.handle_min_function(args),
1228 "avg" | "average" => self.handle_average_function(args),
1229 "round" => self.handle_round_function(args),
1230 "floor" => self.handle_floor_function(args),
1231 "ceil" | "ceiling" => self.handle_ceil_function(args),
1232 "abs" | "absolute" => self.handle_abs_function(args),
1233 "contains" | "includes" => self.handle_contains_function(args),
1234 "startswith" | "begins_with" => self.handle_starts_with_function(args),
1235 "endswith" | "ends_with" => self.handle_ends_with_function(args),
1236 "lowercase" | "tolower" => self.handle_lowercase_function(args),
1237 "uppercase" | "toupper" => self.handle_uppercase_function(args),
1238 "trim" | "strip" => self.handle_trim_function(args),
1239 "split" => self.handle_split_function(args),
1240 "join" => self.handle_join_function(args),
1241 _ => {
1242 self.handle_custom_function(function, args, facts)
1244 }
1245 }
1246 }
1247
1248 fn handle_log_function(&self, args: &[Value]) -> Result<String> {
1250 let message = if args.is_empty() {
1251 "".to_string()
1252 } else if args.len() == 1 {
1253 args[0].to_string()
1254 } else {
1255 args.iter()
1256 .map(|v| v.to_string())
1257 .collect::<Vec<_>>()
1258 .join(" ")
1259 };
1260
1261 println!("📋 {}", message);
1262 Ok(message)
1263 }
1264
1265 fn handle_update_function(&self, args: &[Value]) -> Result<String> {
1267 if let Some(arg) = args.first() {
1268 Ok(format!("Updated: {}", arg.to_string()))
1269 } else {
1270 Ok("Updated".to_string())
1271 }
1272 }
1273
1274 fn handle_timestamp_function(&self) -> Result<String> {
1276 use std::time::{SystemTime, UNIX_EPOCH};
1277 let timestamp = SystemTime::now()
1278 .duration_since(UNIX_EPOCH)
1279 .map_err(|e| RuleEngineError::EvaluationError {
1280 message: format!("Failed to get timestamp: {}", e),
1281 })?
1282 .as_secs();
1283 Ok(timestamp.to_string())
1284 }
1285
1286 fn handle_random_function(&self, args: &[Value]) -> Result<String> {
1288 use std::collections::hash_map::DefaultHasher;
1289 use std::hash::{Hash, Hasher};
1290
1291 let mut hasher = DefaultHasher::new();
1293 std::time::SystemTime::now().hash(&mut hasher);
1294 let random_value = hasher.finish();
1295
1296 if args.is_empty() {
1297 Ok((random_value % 100).to_string()) } else if let Some(Value::Number(max)) = args.first() {
1299 let max_val = *max as u64;
1300 Ok((random_value % max_val).to_string())
1301 } else {
1302 Ok(random_value.to_string())
1303 }
1304 }
1305
1306 fn handle_format_function(&self, args: &[Value]) -> Result<String> {
1308 if args.is_empty() {
1309 return Ok("".to_string());
1310 }
1311
1312 let template = args[0].to_string();
1313 let values: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1314
1315 let mut result = template;
1317 for (i, value) in values.iter().enumerate() {
1318 result = result.replace(&format!("{{{}}}", i), value);
1319 }
1320
1321 Ok(result)
1322 }
1323
1324 fn handle_length_function(&self, args: &[Value]) -> Result<String> {
1326 if let Some(arg) = args.first() {
1327 match arg {
1328 Value::String(s) => Ok(s.len().to_string()),
1329 Value::Array(arr) => Ok(arr.len().to_string()),
1330 Value::Object(obj) => Ok(obj.len().to_string()),
1331 _ => Ok("1".to_string()), }
1333 } else {
1334 Ok("0".to_string())
1335 }
1336 }
1337
1338 fn handle_sum_function(&self, args: &[Value]) -> Result<String> {
1340 let sum = args.iter().fold(0.0, |acc, val| match val {
1341 Value::Number(n) => acc + n,
1342 Value::Integer(i) => acc + (*i as f64),
1343 _ => acc,
1344 });
1345 Ok(sum.to_string())
1346 }
1347
1348 fn handle_max_function(&self, args: &[Value]) -> Result<String> {
1350 let max = args.iter().fold(f64::NEG_INFINITY, |acc, val| match val {
1351 Value::Number(n) => acc.max(*n),
1352 Value::Integer(i) => acc.max(*i as f64),
1353 _ => acc,
1354 });
1355 Ok(max.to_string())
1356 }
1357
1358 fn handle_min_function(&self, args: &[Value]) -> Result<String> {
1360 let min = args.iter().fold(f64::INFINITY, |acc, val| match val {
1361 Value::Number(n) => acc.min(*n),
1362 Value::Integer(i) => acc.min(*i as f64),
1363 _ => acc,
1364 });
1365 Ok(min.to_string())
1366 }
1367
1368 fn handle_average_function(&self, args: &[Value]) -> Result<String> {
1370 if args.is_empty() {
1371 return Ok("0".to_string());
1372 }
1373
1374 let (sum, count) = args.iter().fold((0.0, 0), |(sum, count), val| match val {
1375 Value::Number(n) => (sum + n, count + 1),
1376 Value::Integer(i) => (sum + (*i as f64), count + 1),
1377 _ => (sum, count),
1378 });
1379
1380 if count > 0 {
1381 Ok((sum / count as f64).to_string())
1382 } else {
1383 Ok("0".to_string())
1384 }
1385 }
1386
1387 fn handle_round_function(&self, args: &[Value]) -> Result<String> {
1389 if let Some(Value::Number(n)) = args.first() {
1390 Ok(n.round().to_string())
1391 } else if let Some(Value::Integer(i)) = args.first() {
1392 Ok(i.to_string())
1393 } else {
1394 Err(RuleEngineError::EvaluationError {
1395 message: "round() requires a numeric argument".to_string(),
1396 })
1397 }
1398 }
1399
1400 fn handle_floor_function(&self, args: &[Value]) -> Result<String> {
1401 if let Some(Value::Number(n)) = args.first() {
1402 Ok(n.floor().to_string())
1403 } else if let Some(Value::Integer(i)) = args.first() {
1404 Ok(i.to_string())
1405 } else {
1406 Err(RuleEngineError::EvaluationError {
1407 message: "floor() requires a numeric argument".to_string(),
1408 })
1409 }
1410 }
1411
1412 fn handle_ceil_function(&self, args: &[Value]) -> Result<String> {
1413 if let Some(Value::Number(n)) = args.first() {
1414 Ok(n.ceil().to_string())
1415 } else if let Some(Value::Integer(i)) = args.first() {
1416 Ok(i.to_string())
1417 } else {
1418 Err(RuleEngineError::EvaluationError {
1419 message: "ceil() requires a numeric argument".to_string(),
1420 })
1421 }
1422 }
1423
1424 fn handle_abs_function(&self, args: &[Value]) -> Result<String> {
1425 if let Some(Value::Number(n)) = args.first() {
1426 Ok(n.abs().to_string())
1427 } else if let Some(Value::Integer(i)) = args.first() {
1428 Ok(i.abs().to_string())
1429 } else {
1430 Err(RuleEngineError::EvaluationError {
1431 message: "abs() requires a numeric argument".to_string(),
1432 })
1433 }
1434 }
1435
1436 fn handle_contains_function(&self, args: &[Value]) -> Result<String> {
1438 if args.len() >= 2 {
1439 let haystack = args[0].to_string();
1440 let needle = args[1].to_string();
1441 Ok(haystack.contains(&needle).to_string())
1442 } else {
1443 Err(RuleEngineError::EvaluationError {
1444 message: "contains() requires 2 arguments".to_string(),
1445 })
1446 }
1447 }
1448
1449 fn handle_starts_with_function(&self, args: &[Value]) -> Result<String> {
1450 if args.len() >= 2 {
1451 let text = args[0].to_string();
1452 let prefix = args[1].to_string();
1453 Ok(text.starts_with(&prefix).to_string())
1454 } else {
1455 Err(RuleEngineError::EvaluationError {
1456 message: "startswith() requires 2 arguments".to_string(),
1457 })
1458 }
1459 }
1460
1461 fn handle_ends_with_function(&self, args: &[Value]) -> Result<String> {
1462 if args.len() >= 2 {
1463 let text = args[0].to_string();
1464 let suffix = args[1].to_string();
1465 Ok(text.ends_with(&suffix).to_string())
1466 } else {
1467 Err(RuleEngineError::EvaluationError {
1468 message: "endswith() requires 2 arguments".to_string(),
1469 })
1470 }
1471 }
1472
1473 fn handle_lowercase_function(&self, args: &[Value]) -> Result<String> {
1474 if let Some(arg) = args.first() {
1475 Ok(arg.to_string().to_lowercase())
1476 } else {
1477 Err(RuleEngineError::EvaluationError {
1478 message: "lowercase() requires 1 argument".to_string(),
1479 })
1480 }
1481 }
1482
1483 fn handle_uppercase_function(&self, args: &[Value]) -> Result<String> {
1484 if let Some(arg) = args.first() {
1485 Ok(arg.to_string().to_uppercase())
1486 } else {
1487 Err(RuleEngineError::EvaluationError {
1488 message: "uppercase() requires 1 argument".to_string(),
1489 })
1490 }
1491 }
1492
1493 fn handle_trim_function(&self, args: &[Value]) -> Result<String> {
1494 if let Some(arg) = args.first() {
1495 Ok(arg.to_string().trim().to_string())
1496 } else {
1497 Err(RuleEngineError::EvaluationError {
1498 message: "trim() requires 1 argument".to_string(),
1499 })
1500 }
1501 }
1502
1503 fn handle_split_function(&self, args: &[Value]) -> Result<String> {
1504 if args.len() >= 2 {
1505 let text = args[0].to_string();
1506 let delimiter = args[1].to_string();
1507 let parts: Vec<String> = text.split(&delimiter).map(|s| s.to_string()).collect();
1508 Ok(format!("{:?}", parts)) } else {
1510 Err(RuleEngineError::EvaluationError {
1511 message: "split() requires 2 arguments".to_string(),
1512 })
1513 }
1514 }
1515
1516 fn handle_join_function(&self, args: &[Value]) -> Result<String> {
1517 if args.len() >= 2 {
1518 let delimiter = args[0].to_string();
1519 let parts: Vec<String> = args[1..].iter().map(|v| v.to_string()).collect();
1520 Ok(parts.join(&delimiter))
1521 } else {
1522 Err(RuleEngineError::EvaluationError {
1523 message: "join() requires at least 2 arguments".to_string(),
1524 })
1525 }
1526 }
1527
1528 fn handle_custom_function(
1530 &self,
1531 function: &str,
1532 args: &[Value],
1533 facts: &Facts,
1534 ) -> Result<String> {
1535 if let Some(custom_func) = self.custom_functions.get(function) {
1537 if self.config.debug_mode {
1538 println!("🎯 Calling registered function: {}({:?})", function, args);
1539 }
1540
1541 match custom_func(args, facts) {
1542 Ok(result) => Ok(result.to_string()),
1543 Err(e) => Err(e),
1544 }
1545 } else {
1546 if self.config.debug_mode {
1548 println!("⚠️ Custom function '{}' not registered", function);
1549 }
1550
1551 Err(RuleEngineError::EvaluationError {
1552 message: format!("Function '{}' is not registered. Use engine.register_function() to add custom functions.", function),
1553 })
1554 }
1555 }
1556
1557 fn execute_method_call(
1559 &self,
1560 object_name: &str,
1561 method: &str,
1562 args: &[Value],
1563 facts: &Facts,
1564 ) -> Result<String> {
1565 let Some(object_value) = facts.get(object_name) else {
1567 return Err(RuleEngineError::EvaluationError {
1568 message: format!("Object '{}' not found in facts", object_name),
1569 });
1570 };
1571
1572 let method_lower = method.to_lowercase();
1573
1574 if method_lower.starts_with("set") && args.len() == 1 {
1576 return self.handle_setter_method(object_name, method, &args[0], object_value, facts);
1577 }
1578
1579 if method_lower.starts_with("get") && args.is_empty() {
1581 return self.handle_getter_method(object_name, method, &object_value);
1582 }
1583
1584 match method_lower.as_str() {
1586 "tostring" => Ok(object_value.to_string()),
1587 "update" => {
1588 facts.add_value(object_name, object_value)?;
1589 Ok(format!("Updated {}", object_name))
1590 }
1591 "reset" => self.handle_reset_method(object_name, object_value, facts),
1592 _ => self.handle_property_access_or_fallback(
1593 object_name,
1594 method,
1595 args.len(),
1596 &object_value,
1597 ),
1598 }
1599 }
1600
1601 fn handle_setter_method(
1603 &self,
1604 object_name: &str,
1605 method: &str,
1606 new_value: &Value,
1607 mut object_value: Value,
1608 facts: &Facts,
1609 ) -> Result<String> {
1610 let property_name = Self::extract_property_name_from_setter(method);
1611
1612 match object_value {
1613 Value::Object(ref mut obj) => {
1614 obj.insert(property_name.clone(), new_value.clone());
1615 facts.add_value(object_name, object_value)?;
1616 Ok(format!(
1617 "Set {} to {}",
1618 property_name,
1619 new_value.to_string()
1620 ))
1621 }
1622 _ => Err(RuleEngineError::EvaluationError {
1623 message: format!("Cannot call setter on non-object type: {}", object_name),
1624 }),
1625 }
1626 }
1627
1628 fn handle_getter_method(
1630 &self,
1631 object_name: &str,
1632 method: &str,
1633 object_value: &Value,
1634 ) -> Result<String> {
1635 let property_name = Self::extract_property_name_from_getter(method);
1636
1637 match object_value {
1638 Value::Object(obj) => {
1639 if let Some(value) = obj.get(&property_name) {
1640 Ok(value.to_string())
1641 } else {
1642 Err(RuleEngineError::EvaluationError {
1643 message: format!(
1644 "Property '{}' not found on object '{}'",
1645 property_name, object_name
1646 ),
1647 })
1648 }
1649 }
1650 _ => Err(RuleEngineError::EvaluationError {
1651 message: format!("Cannot call getter on non-object type: {}", object_name),
1652 }),
1653 }
1654 }
1655
1656 fn handle_reset_method(
1658 &self,
1659 object_name: &str,
1660 mut object_value: Value,
1661 facts: &Facts,
1662 ) -> Result<String> {
1663 match object_value {
1664 Value::Object(ref mut obj) => {
1665 obj.clear();
1666 facts.add_value(object_name, object_value)?;
1667 Ok(format!("Reset {}", object_name))
1668 }
1669 _ => Err(RuleEngineError::EvaluationError {
1670 message: format!("Cannot reset non-object type: {}", object_name),
1671 }),
1672 }
1673 }
1674
1675 fn handle_property_access_or_fallback(
1677 &self,
1678 object_name: &str,
1679 method: &str,
1680 arg_count: usize,
1681 object_value: &Value,
1682 ) -> Result<String> {
1683 if let Value::Object(obj) = object_value {
1684 if let Some(value) = obj.get(method) {
1686 return Ok(value.to_string());
1687 }
1688
1689 let capitalized_method = Self::capitalize_first_letter(method);
1691 if let Some(value) = obj.get(&capitalized_method) {
1692 return Ok(value.to_string());
1693 }
1694 }
1695
1696 Ok(format!(
1698 "Called {}.{} with {} args",
1699 object_name, method, arg_count
1700 ))
1701 }
1702
1703 fn extract_property_name_from_setter(method: &str) -> String {
1705 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1707 }
1708
1709 fn extract_property_name_from_getter(method: &str) -> String {
1711 let property_name = &method[3..]; Self::capitalize_first_letter(property_name)
1713 }
1714
1715 fn capitalize_first_letter(s: &str) -> String {
1717 if s.is_empty() {
1718 return String::new();
1719 }
1720 let mut chars = s.chars();
1721 match chars.next() {
1722 None => String::new(),
1723 Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
1724 }
1725 }
1726
1727 fn resolve_action_parameters(
1729 &self,
1730 params: &HashMap<String, Value>,
1731 facts: &Facts,
1732 ) -> Result<HashMap<String, Value>> {
1733 let mut resolved = HashMap::new();
1734
1735 for (key, value) in params {
1736 let resolved_value = match value {
1737 Value::String(s) => {
1738 if s.contains('.') {
1740 if let Some(fact_value) = facts.get_nested(s) {
1742 fact_value
1743 } else {
1744 value.clone()
1746 }
1747 } else {
1748 value.clone()
1749 }
1750 }
1751 _ => value.clone(),
1752 };
1753 resolved.insert(key.clone(), resolved_value);
1754 }
1755
1756 Ok(resolved)
1757 }
1758
1759 pub fn load_plugin(
1763 &mut self,
1764 plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1765 ) -> Result<()> {
1766 plugin.register_actions(self)?;
1768 plugin.register_functions(self)?;
1769
1770 self.plugin_manager.load_plugin(plugin)
1772 }
1773
1774 pub fn unload_plugin(&mut self, name: &str) -> Result<()> {
1776 self.plugin_manager.unload_plugin(name)
1777 }
1778
1779 pub fn hot_reload_plugin(
1781 &mut self,
1782 name: &str,
1783 new_plugin: std::sync::Arc<dyn crate::engine::plugin::RulePlugin>,
1784 ) -> Result<()> {
1785 self.plugin_manager.unload_plugin(name)?;
1787
1788 new_plugin.register_actions(self)?;
1790 new_plugin.register_functions(self)?;
1791
1792 self.plugin_manager.load_plugin(new_plugin)
1794 }
1795
1796 pub fn get_plugin_info(&self, name: &str) -> Option<&crate::engine::plugin::PluginMetadata> {
1798 self.plugin_manager.get_plugin_info(name)
1799 }
1800
1801 pub fn list_plugins(&self) -> Vec<PluginInfo> {
1803 self.plugin_manager.list_plugins()
1804 }
1805
1806 pub fn get_plugin_stats(&self) -> PluginStats {
1808 self.plugin_manager.get_stats()
1809 }
1810
1811 pub fn plugin_health_check(&mut self) -> HashMap<String, crate::engine::plugin::PluginHealth> {
1813 self.plugin_manager.plugin_health_check()
1814 }
1815
1816 pub fn configure_plugins(&mut self, config: PluginConfig) {
1818 self.plugin_manager = PluginManager::new(config);
1819 }
1820}