mockforge_intelligence/behavioral_economics/
engine.rs1use crate::behavioral_economics::actions::ActionExecutor;
7use crate::behavioral_economics::conditions::ConditionEvaluator;
8use crate::behavioral_economics::config::BehavioralEconomicsConfig;
9use crate::behavioral_economics::rules::BehaviorRule;
10use mockforge_foundation::Result;
11use std::sync::Arc;
12use tokio::sync::RwLock;
13use tracing::{debug, info, warn};
14
15pub struct BehavioralEconomicsEngine {
21 config: BehavioralEconomicsConfig,
23 condition_evaluator: Arc<RwLock<ConditionEvaluator>>,
25 action_executor: ActionExecutor,
27 rules: Vec<BehaviorRule>,
29}
30
31impl BehavioralEconomicsEngine {
32 pub fn new(config: BehavioralEconomicsConfig) -> Result<Self> {
34 for rule in &config.rules {
36 rule.validate()?;
37 }
38
39 let mut rules = config.rules.clone();
41 rules.sort_by(|a, b| b.priority.cmp(&a.priority));
42
43 Ok(Self {
44 config,
45 condition_evaluator: Arc::new(RwLock::new(ConditionEvaluator::new())),
46 action_executor: ActionExecutor::new(),
47 rules,
48 })
49 }
50
51 #[allow(clippy::should_implement_trait)]
53 pub fn default() -> Self {
54 Self::new(BehavioralEconomicsConfig::default()).expect("Failed to create default engine")
55 }
56
57 pub fn condition_evaluator(&self) -> Arc<RwLock<ConditionEvaluator>> {
59 Arc::clone(&self.condition_evaluator)
60 }
61
62 pub async fn evaluate(&self) -> Result<Vec<String>> {
66 if !self.config.enabled {
67 return Ok(Vec::new());
68 }
69
70 let evaluator = self.condition_evaluator.read().await;
71 let mut executed_actions = Vec::new();
72
73 for rule in &self.rules {
75 match evaluator.evaluate(&rule.condition) {
76 Ok(true) => {
77 debug!("Rule '{}' condition met, executing action", rule.name);
78 match self.action_executor.execute(&rule.action) {
79 Ok(action_desc) => {
80 info!("Executed action for rule '{}': {}", rule.name, action_desc);
81 executed_actions.push(format!("{}: {}", rule.name, action_desc));
82 }
83 Err(e) => {
84 warn!("Failed to execute action for rule '{}': {}", rule.name, e);
85 }
86 }
87 }
88 Ok(false) => {
89 debug!("Rule '{}' condition not met", rule.name);
90 }
91 Err(e) => {
92 warn!("Failed to evaluate condition for rule '{}': {}", rule.name, e);
93 }
94 }
95 }
96
97 Ok(executed_actions)
98 }
99
100 pub fn add_rule(&mut self, rule: BehaviorRule) -> Result<()> {
102 rule.validate()?;
103 self.rules.push(rule);
104 self.rules.sort_by(|a, b| b.priority.cmp(&a.priority));
106 Ok(())
107 }
108
109 pub fn remove_rule(&mut self, name: &str) -> bool {
111 let initial_len = self.rules.len();
112 self.rules.retain(|r| r.name != name);
113 self.rules.len() < initial_len
114 }
115
116 pub fn rules(&self) -> &[BehaviorRule] {
118 &self.rules
119 }
120
121 pub fn update_config(&mut self, config: BehavioralEconomicsConfig) -> Result<()> {
123 for rule in &config.rules {
125 rule.validate()?;
126 }
127
128 let mut rules = config.rules.clone();
130 rules.sort_by(|a, b| b.priority.cmp(&a.priority));
131
132 self.config = config;
133 self.rules = rules;
134 Ok(())
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use crate::behavioral_economics::actions::BehaviorAction;
142 use crate::behavioral_economics::conditions::BehaviorCondition;
143 use crate::behavioral_economics::rules::BehaviorRule;
144
145 #[tokio::test]
146 async fn test_engine_creation() {
147 let config = BehavioralEconomicsConfig::new();
148 let engine = BehavioralEconomicsEngine::new(config).unwrap();
149 assert!(engine.rules().is_empty());
150 }
151
152 #[tokio::test]
153 async fn test_engine_evaluation() {
154 let rule = BehaviorRule::declarative(
155 "test-rule".to_string(),
156 BehaviorCondition::Always,
157 BehaviorAction::NoOp,
158 100,
159 );
160 let config = BehavioralEconomicsConfig::new().enable().with_rule(rule);
161 let engine = BehavioralEconomicsEngine::new(config).unwrap();
162 let results = engine.evaluate().await.unwrap();
163 assert!(!results.is_empty());
164 }
165
166 #[tokio::test]
167 async fn test_engine_disabled() {
168 let rule = BehaviorRule::declarative(
169 "test-rule".to_string(),
170 BehaviorCondition::Always,
171 BehaviorAction::NoOp,
172 100,
173 );
174 let config = BehavioralEconomicsConfig::new().disable().with_rule(rule);
175 let engine = BehavioralEconomicsEngine::new(config).unwrap();
176 let results = engine.evaluate().await.unwrap();
177 assert!(results.is_empty());
178 }
179}