1use crate::EvaluationRequest;
4use std::collections::HashMap;
5
6pub struct EvaluationContext {
8 fields: HashMap<String, FieldValue>,
10}
11
12impl EvaluationContext {
13 pub fn from_request(request: &EvaluationRequest) -> Self {
15 let mut ctx = EvaluationContext {
16 fields: HashMap::new(),
17 };
18
19 ctx.set_field("agent.id", FieldValue::String(request.agent_id.clone()));
21 ctx.set_field("agent.org", FieldValue::String(request.agent_org.clone()));
22 ctx.set_field(
23 "agent.level",
24 FieldValue::String(request.agent_level.clone()),
25 );
26 ctx.set_field(
27 "agent.requests_last_hour",
28 FieldValue::Number(request.requests_last_hour as i64),
29 );
30 ctx.set_field(
31 "agent.requests_last_24h",
32 FieldValue::Number(request.requests_last_24h as i64),
33 );
34
35 if let Some(mission_id) = &request.mission_id {
37 ctx.set_field("mission.id", FieldValue::String(mission_id.clone()));
38 }
39 if let Some(mission_type) = &request.mission_type {
40 ctx.set_field("mission.type", FieldValue::String(mission_type.clone()));
41 }
42
43 if let Some(query_type) = &request.query_type {
45 ctx.set_field("request.query_type", FieldValue::String(query_type.clone()));
46 }
47 if let Some(justification) = &request.justification {
48 ctx.set_field(
49 "request.justification",
50 FieldValue::String(justification.clone()),
51 );
52 ctx.set_field(
53 "request.justification_length",
54 FieldValue::Number(justification.len() as i64),
55 );
56 }
57 if let Some(export_format) = &request.export_format {
58 ctx.set_field(
59 "request.export_format",
60 FieldValue::String(export_format.clone()),
61 );
62 }
63 if let Some(limit) = request.result_limit {
64 ctx.set_field("request.result_limit", FieldValue::Number(limit as i64));
65 }
66
67 ctx.set_field(
69 "request.results_last_query",
70 FieldValue::Number(request.results_last_query as i64),
71 );
72
73 if let Some(dept) = &request.account_department {
75 ctx.set_field("account.department", FieldValue::String(dept.clone()));
76 }
77
78 for (i, dept) in request.allowed_departments.iter().enumerate() {
80 ctx.set_field(
81 &format!("agent.allowed_departments[{}]", i),
82 FieldValue::Number(*dept as i64),
83 );
84 }
85
86 ctx.set_field(
88 "context.request_hour",
89 FieldValue::Number(request.request_hour as i64),
90 );
91 ctx.set_field(
92 "context.is_within_mission_hours",
93 FieldValue::Boolean(request.is_within_mission_hours),
94 );
95
96 ctx
97 }
98
99 pub fn get_field(&self, path: &str) -> Option<&FieldValue> {
101 self.fields.get(path)
102 }
103
104 pub fn set_field(&mut self, path: &str, value: FieldValue) {
106 self.fields.insert(path.to_string(), value);
107 }
108
109 pub fn fields(&self) -> &HashMap<String, FieldValue> {
111 &self.fields
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
117pub enum FieldValue {
118 Number(i64),
119 Float(f64),
120 String(String),
121 Boolean(bool),
122}
123
124impl FieldValue {
125 pub fn compare(&self, op: &str, other: &FieldValue) -> bool {
127 match (self, other) {
128 (FieldValue::Number(a), FieldValue::Number(b)) => match op {
129 ">" => a > b,
130 "<" => a < b,
131 ">=" => a >= b,
132 "<=" => a <= b,
133 "==" => a == b,
134 "!=" => a != b,
135 _ => false,
136 },
137 (FieldValue::String(a), FieldValue::String(b)) => match op {
138 "==" => a == b,
139 "!=" => a != b,
140 _ => false,
141 },
142 (FieldValue::Boolean(a), FieldValue::Boolean(b)) => match op {
143 "==" => a == b,
144 "!=" => a != b,
145 _ => false,
146 },
147 _ => false,
148 }
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn test_context_creation() {
158 let request = EvaluationRequest {
159 request_id: "test".to_string(),
160 agent_id: "AGENT_001".to_string(),
161 agent_org: "DGFiP".to_string(),
162 agent_level: "standard".to_string(),
163 mission_id: Some("MIS_001".to_string()),
164 mission_type: None,
165 query_type: None,
166 justification: None,
167 export_format: None,
168 result_limit: None,
169 requests_last_hour: 10,
170 requests_last_24h: 100,
171 results_last_query: 5,
172 account_department: None,
173 allowed_departments: vec![],
174 request_hour: 14,
175 is_within_mission_hours: true,
176 };
177
178 let ctx = EvaluationContext::from_request(&request);
179
180 assert_eq!(
181 ctx.get_field("agent.id"),
182 Some(&FieldValue::String("AGENT_001".to_string()))
183 );
184 assert_eq!(
185 ctx.get_field("agent.requests_last_hour"),
186 Some(&FieldValue::Number(10))
187 );
188 }
189
190 #[test]
191 fn test_field_comparison() {
192 assert!(FieldValue::Number(10).compare(">", &FieldValue::Number(5)));
193 assert!(FieldValue::Number(10).compare(">=", &FieldValue::Number(10)));
194 assert!(FieldValue::String("test".to_string())
195 .compare("==", &FieldValue::String("test".to_string())));
196 }
197}