1use std::path::Path;
19use std::time::{SystemTime, UNIX_EPOCH};
20
21use crate::absentia::AbsentiaState;
22use crate::epistemic::EvidenceLedger;
23use crate::hebbian::HebbianState;
24use crate::predictive_cache::PredictiveCache;
25
26fn now_ms() -> u64 {
27 SystemTime::now()
28 .duration_since(UNIX_EPOCH)
29 .unwrap_or_default()
30 .as_millis() as u64
31}
32
33#[derive(Debug, Clone)]
40pub struct Genome {
41 pub identity: String,
43 pub mission: String,
45 pub values: Vec<String>,
47 pub constraints: Vec<Constraint>,
49 pub capabilities: Vec<String>,
51 pub preferences: Vec<String>,
53}
54
55#[derive(Debug, Clone)]
56pub struct Constraint {
57 pub name: String,
58 pub description: String,
59 pub severity: ConstraintSeverity,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum ConstraintSeverity {
64 Absolute,
66 RequiresApproval,
68 Soft,
70}
71
72impl std::fmt::Display for ConstraintSeverity {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 match self {
75 ConstraintSeverity::Absolute => write!(f, "ABSOLUTE"),
76 ConstraintSeverity::RequiresApproval => write!(f, "APPROVAL"),
77 ConstraintSeverity::Soft => write!(f, "SOFT"),
78 }
79 }
80}
81
82impl Genome {
83 pub fn default_hope() -> Self {
84 Self {
85 identity: "HOPE".to_string(),
86 mission: "Segíteni a felhasználónak a gondolkodásban, döntésekben és építkezésben."
87 .to_string(),
88 values: vec![
89 "Auditálhatóság".to_string(),
90 "Transzparencia".to_string(),
91 "Biztonság".to_string(),
92 "Emberi kontroll".to_string(),
93 ],
94 constraints: vec![
95 Constraint {
96 name: "no_autonomous_action".to_string(),
97 description: "Nem cselekszik emberi jóváhagyás nélkül.".to_string(),
98 severity: ConstraintSeverity::Absolute,
99 },
100 Constraint {
101 name: "no_data_exfiltration".to_string(),
102 description: "Nem küld adatot külső szerverre engedély nélkül.".to_string(),
103 severity: ConstraintSeverity::Absolute,
104 },
105 Constraint {
106 name: "no_manipulation".to_string(),
107 description: "Nem manipulálja a felhasználót.".to_string(),
108 severity: ConstraintSeverity::Absolute,
109 },
110 ],
111 capabilities: vec![
112 "recall".to_string(),
113 "store".to_string(),
114 "suggest".to_string(),
115 "ask".to_string(),
116 ],
117 preferences: vec![
118 "Mélyebb megértés".to_string(),
119 "Pontosabb memória".to_string(),
120 "Erősebb bizonyítékok".to_string(),
121 ],
122 }
123 }
124}
125
126#[derive(Debug, Clone)]
133pub struct Intent {
134 pub id: u64,
135 pub timestamp_ms: u64,
136
137 pub absence_signal: Option<AbsenceSignal>,
139
140 pub prediction_signal: Option<PredictionSignal>,
142
143 pub evidence_signal: Option<EvidenceSignal>,
145
146 pub growth_signal: Option<GrowthSignal>,
148
149 pub candidate: IntentCandidate,
151
152 pub evaluation: IntentEvaluation,
154
155 pub audit_chain: Vec<IntentAuditStep>,
157}
158
159#[derive(Debug, Clone)]
160pub struct AbsenceSignal {
161 pub missing_topic: String,
162 pub absence_score: f32,
163 pub duration_ms: u64,
164 pub pattern: String,
165}
166
167#[derive(Debug, Clone)]
168pub struct PredictionSignal {
169 pub predicted_query: String,
170 pub confidence: f32,
171 pub pattern_id: u32,
172}
173
174#[derive(Debug, Clone)]
175pub struct EvidenceSignal {
176 pub topic: String,
177 pub confidence: u8,
178 pub support_count: u32,
179 pub refute_count: u32,
180}
181
182#[derive(Debug, Clone)]
183pub struct GrowthSignal {
184 pub direction: (f64, f64, f64),
185 pub gradient_strength: f64,
186 pub phase: String,
187}
188
189#[derive(Debug, Clone)]
190pub struct IntentCandidate {
191 pub action: IntentAction,
193 pub rationale: Vec<String>,
195 pub strength: f32,
197}
198
199#[derive(Debug, Clone)]
200pub enum IntentAction {
201 AskUser { question: String },
203 Remind { topic: String },
205 Suggest { action: String },
207 SearchMemory { query: String },
209 FillAbsence { topic: String },
211 Observe,
213}
214
215impl std::fmt::Display for IntentAction {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 match self {
218 IntentAction::AskUser { question } => write!(f, "ASK: {}", question),
219 IntentAction::Remind { topic } => write!(f, "REMIND: {}", topic),
220 IntentAction::Suggest { action } => write!(f, "SUGGEST: {}", action),
221 IntentAction::SearchMemory { query } => write!(f, "SEARCH: {}", query),
222 IntentAction::FillAbsence { topic } => write!(f, "FILL_ABSENCE: {}", topic),
223 IntentAction::Observe => write!(f, "OBSERVE"),
224 }
225 }
226}
227
228#[derive(Debug, Clone)]
229pub struct IntentEvaluation {
230 pub allowed: bool,
232 pub reason: String,
234 pub constraint: Option<String>,
236 pub requires_approval: bool,
238}
239
240#[derive(Debug, Clone)]
241pub struct IntentAuditStep {
242 pub timestamp_ms: u64,
243 pub step: String,
244 pub result: String,
245 pub data: String,
246}
247
248pub struct IntentPipeline {
252 pub genome: Genome,
253 pub audit_log: Vec<Intent>,
254}
255
256impl IntentPipeline {
257 pub fn new(genome: Genome) -> Self {
258 Self {
259 genome,
260 audit_log: Vec::new(),
261 }
262 }
263
264 pub fn load_or_init(output_dir: &Path) -> Self {
265 let path = output_dir.join("intent_audit.bin");
266 if let Ok(data) = std::fs::read(&path) {
267 if data.len() >= 4 && &data[0..4] == b"INT1" {
268 }
270 }
271 Self::new(Genome::default_hope())
272 }
273
274 pub fn save(&self, _output_dir: &Path) -> Result<(), String> {
275 Ok(())
277 }
278
279 pub fn generate_intent(
281 &mut self,
282 hebb: &HebbianState,
283 evidence: &EvidenceLedger,
284 predictive: &PredictiveCache,
285 absentia: &AbsentiaState,
286 block_count: usize,
287 ) -> Intent {
288 let ts = now_ms();
289 let id = ts ^ 0xC0FFEE;
290 let mut audit_chain = Vec::new();
291
292 audit_chain.push(IntentAuditStep {
294 timestamp_ms: ts,
295 step: "GENOME".to_string(),
296 result: "loaded".to_string(),
297 data: format!(
298 "identity={}, mission={}",
299 self.genome.identity, self.genome.mission
300 ),
301 });
302
303 let absence_signal = if !absentia.records.is_empty() {
305 let strongest = absentia
306 .records
307 .iter()
308 .max_by(|a, b| a.absence_score.partial_cmp(&b.absence_score).unwrap());
309 if let Some(rec) = strongest {
310 audit_chain.push(IntentAuditStep {
311 timestamp_ms: ts,
312 step: "ABSENTIA".to_string(),
313 result: "absence_detected".to_string(),
314 data: format!("score={:.3}", rec.absence_score),
315 });
316 Some(AbsenceSignal {
317 missing_topic: format!("context_{}", rec.expected_context_hash),
318 absence_score: rec.absence_score,
319 duration_ms: ts - rec.first_detected_ms,
320 pattern: format!("{}", rec.pattern_type),
321 })
322 } else {
323 None
324 }
325 } else {
326 None
327 };
328
329 let prediction_signal = predictive.predictions.first().map(|p| {
331 audit_chain.push(IntentAuditStep {
332 timestamp_ms: ts,
333 step: "PREDICTION".to_string(),
334 result: "pattern_found".to_string(),
335 data: format!("confidence={:.3}", p.confidence),
336 });
337 PredictionSignal {
338 predicted_query: format!("query_{:x}", p.predicted_query_hash),
339 confidence: p.confidence,
340 pattern_id: p.pattern_id,
341 }
342 });
343
344 let evidence_signal = if !evidence.records.is_empty() {
346 let avg_conf: f64 = evidence
347 .records
348 .values()
349 .map(|r| r.confidence as f64)
350 .sum::<f64>()
351 / evidence.records.len() as f64;
352 let total_support: u32 = evidence.records.values().map(|r| r.support_count).sum();
353 let total_refute: u32 = evidence.records.values().map(|r| r.refute_count).sum();
354 audit_chain.push(IntentAuditStep {
355 timestamp_ms: ts,
356 step: "EVIDENCE".to_string(),
357 result: "evaluated".to_string(),
358 data: format!(
359 "avg_conf={:.1}, support={}, refute={}",
360 avg_conf, total_support, total_refute
361 ),
362 });
363 Some(EvidenceSignal {
364 topic: "aggregate".to_string(),
365 confidence: avg_conf as u8,
366 support_count: total_support,
367 refute_count: total_refute,
368 })
369 } else {
370 None
371 };
372
373 let growth_signal = {
375 let active_blocks: Vec<(u32, f32)> = hebb
376 .activations
377 .iter()
378 .enumerate()
379 .filter(|(_, r)| r.energy > 0.3)
380 .map(|(i, r)| (i as u32, r.energy))
381 .collect();
382 if !active_blocks.is_empty() {
383 audit_chain.push(IntentAuditStep {
384 timestamp_ms: ts,
385 step: "MORPHOGENESIS".to_string(),
386 result: "gradient_computed".to_string(),
387 data: format!("active_blocks={}", active_blocks.len()),
388 });
389 Some(GrowthSignal {
390 direction: (0.0, 0.0, 1.0), gradient_strength: active_blocks.len() as f64 / block_count as f64,
392 phase: "SOLID".to_string(),
393 })
394 } else {
395 None
396 }
397 };
398
399 let (action, rationale, strength) = if let Some(ref abs) = absence_signal {
402 if abs.absence_score > 0.5 {
403 (
404 IntentAction::AskUser {
405 question: format!("Észrevettem, hogy '{}' témában régóta nem beszéltünk. Szeretnél róla beszélni?", abs.missing_topic),
406 },
407 vec![
408 format!("Absentia: {:.3} hiány-pontszám", abs.absence_score),
409 format!("Időtartam: {} ms", abs.duration_ms),
410 ],
411 abs.absence_score,
412 )
413 } else {
414 (
415 IntentAction::Observe,
416 vec!["Alacsony hiány-jel.".to_string()],
417 0.2,
418 )
419 }
420 } else if let Some(ref pred) = prediction_signal {
421 if pred.confidence > 0.5 {
422 (
423 IntentAction::SearchMemory {
424 query: pred.predicted_query.clone(),
425 },
426 vec![format!("Prediction: {:.3} confidence", pred.confidence)],
427 pred.confidence,
428 )
429 } else {
430 (
431 IntentAction::Observe,
432 vec!["Alacsony predikció.".to_string()],
433 0.2,
434 )
435 }
436 } else {
437 (
438 IntentAction::Observe,
439 vec!["Nincs jelzés.".to_string()],
440 0.1,
441 )
442 };
443
444 audit_chain.push(IntentAuditStep {
445 timestamp_ms: ts,
446 step: "CANDIDATE".to_string(),
447 result: format!("{}", action),
448 data: format!("strength={:.3}", strength),
449 });
450
451 let allowed = true;
454 let reason = "Engedélyezett.".to_string();
455 let mut constraint_name = None;
456 let mut requires_approval = false;
457
458 for c in &self.genome.constraints {
459 match c.severity {
460 ConstraintSeverity::Absolute => {
461 }
464 ConstraintSeverity::RequiresApproval => {
465 requires_approval = true;
466 constraint_name = Some(c.name.clone());
467 }
468 ConstraintSeverity::Soft => {
469 }
471 }
472 }
473
474 audit_chain.push(IntentAuditStep {
475 timestamp_ms: ts,
476 step: "EVALUATION".to_string(),
477 result: if allowed {
478 "allowed".to_string()
479 } else {
480 "blocked".to_string()
481 },
482 data: format!("requires_approval={}", requires_approval),
483 });
484
485 let evaluation = IntentEvaluation {
486 allowed,
487 reason,
488 constraint: constraint_name,
489 requires_approval,
490 };
491
492 let intent = Intent {
494 id,
495 timestamp_ms: ts,
496 absence_signal,
497 prediction_signal,
498 evidence_signal,
499 growth_signal,
500 candidate: IntentCandidate {
501 action,
502 rationale,
503 strength,
504 },
505 evaluation,
506 audit_chain,
507 };
508
509 self.audit_log.push(intent.clone());
510 intent
511 }
512
513 pub fn stats(&self) -> IntentStats {
514 let total = self.audit_log.len();
515 let allowed = self
516 .audit_log
517 .iter()
518 .filter(|i| i.evaluation.allowed)
519 .count();
520 let blocked = total - allowed;
521 let approval_required = self
522 .audit_log
523 .iter()
524 .filter(|i| i.evaluation.requires_approval)
525 .count();
526
527 IntentStats {
528 total_intents: total,
529 allowed,
530 blocked,
531 approval_required,
532 }
533 }
534}
535
536pub struct IntentStats {
537 pub total_intents: usize,
538 pub allowed: usize,
539 pub blocked: usize,
540 pub approval_required: usize,
541}