lean_ctx/core/agents/
shared.rs1use super::{AgentRegistry, ScratchpadEntry};
2use crate::core::a2a::message::{MessagePriority, PrivacyLevel};
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::path::PathBuf;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct SharedFact {
10 pub from_agent: String,
11 pub category: String,
12 pub key: String,
13 pub value: String,
14 pub timestamp: DateTime<Utc>,
15 #[serde(default)]
16 pub received_by: Vec<String>,
17}
18
19impl AgentRegistry {
20 pub fn share_knowledge(&mut self, from: &str, category: &str, facts: &[(String, String)]) {
21 for (key, value) in facts {
22 self.scratchpad.push(ScratchpadEntry {
23 id: format!("knowledge-{}", chrono::Utc::now().timestamp_millis()),
24 from_agent: from.to_string(),
25 to_agent: None,
26 task_id: None,
27 category: category.to_string(),
28 priority: MessagePriority::default(),
29 privacy: PrivacyLevel::Team,
30 message: format!("[knowledge] {key}={value}"),
31 metadata: HashMap::new(),
32 project_root: None,
33 timestamp: Utc::now(),
34 read_by: Vec::new(),
35 expires_at: None,
36 });
37 }
38 let shared_path = Self::shared_knowledge_path();
39 let mut existing: Vec<SharedFact> = std::fs::read_to_string(&shared_path)
40 .ok()
41 .and_then(|s| serde_json::from_str(&s).ok())
42 .unwrap_or_default();
43
44 for (key, value) in facts {
45 existing.push(SharedFact {
46 from_agent: from.to_string(),
47 category: category.to_string(),
48 key: key.clone(),
49 value: value.clone(),
50 timestamp: Utc::now(),
51 received_by: Vec::new(),
52 });
53 }
54
55 if existing.len() > 500 {
56 existing.drain(..existing.len() - 500);
57 }
58 if let Ok(json) = serde_json::to_string_pretty(&existing) {
59 let _ = std::fs::write(&shared_path, json);
60 }
61 }
62
63 pub fn receive_shared_knowledge(&mut self, agent_id: &str) -> Vec<SharedFact> {
64 let shared_path = Self::shared_knowledge_path();
65 let mut all: Vec<SharedFact> = std::fs::read_to_string(&shared_path)
66 .ok()
67 .and_then(|s| serde_json::from_str(&s).ok())
68 .unwrap_or_default();
69
70 let mut new_facts = Vec::new();
71 for fact in &mut all {
72 if fact.from_agent != agent_id && !fact.received_by.contains(&agent_id.to_string()) {
73 fact.received_by.push(agent_id.to_string());
74 new_facts.push(fact.clone());
75 }
76 }
77
78 if !new_facts.is_empty()
79 && let Ok(json) = serde_json::to_string_pretty(&all)
80 {
81 let _ = std::fs::write(&shared_path, json);
82 }
83 new_facts
84 }
85
86 fn shared_knowledge_path() -> PathBuf {
87 crate::core::paths::data_dir()
90 .unwrap_or_else(|_| PathBuf::from("."))
91 .join("shared_knowledge.json")
92 }
93}