1use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use std::collections::HashMap;
7use std::path::PathBuf;
8use std::time::{Duration, SystemTime};
9use uuid::Uuid;
10
11use crate::types::AgentId;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub struct SessionId(pub Uuid);
16
17impl SessionId {
18 pub fn new() -> Self {
19 Self(Uuid::new_v4())
20 }
21}
22
23impl std::fmt::Display for SessionId {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 write!(f, "{}", self.0)
26 }
27}
28
29impl Default for SessionId {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
37pub struct ContextId(pub Uuid);
38
39impl ContextId {
40 pub fn new() -> Self {
41 Self(Uuid::new_v4())
42 }
43}
44
45impl std::fmt::Display for ContextId {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 write!(f, "{}", self.0)
48 }
49}
50
51impl Default for ContextId {
52 fn default() -> Self {
53 Self::new()
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
59pub struct KnowledgeId(pub Uuid);
60
61impl KnowledgeId {
62 pub fn new() -> Self {
63 Self(Uuid::new_v4())
64 }
65}
66
67impl std::fmt::Display for KnowledgeId {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 write!(f, "{}", self.0)
70 }
71}
72
73impl Default for KnowledgeId {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
81pub struct VectorId(pub Uuid);
82
83impl VectorId {
84 pub fn new() -> Self {
85 Self(Uuid::new_v4())
86 }
87}
88
89impl Default for VectorId {
90 fn default() -> Self {
91 Self::new()
92 }
93}
94
95impl std::fmt::Display for VectorId {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 write!(f, "{}", self.0)
98 }
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct AgentContext {
104 pub agent_id: AgentId,
105 pub session_id: SessionId,
106 pub memory: HierarchicalMemory,
107 pub knowledge_base: KnowledgeBase,
108 pub conversation_history: Vec<ConversationItem>,
109 pub metadata: HashMap<String, String>,
110 pub created_at: SystemTime,
111 pub updated_at: SystemTime,
112 pub retention_policy: RetentionPolicy,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize, Default)]
117pub struct HierarchicalMemory {
118 pub working_memory: WorkingMemory,
119 pub short_term: Vec<MemoryItem>,
120 pub long_term: Vec<MemoryItem>,
121 pub episodic_memory: Vec<Episode>,
122 pub semantic_memory: Vec<SemanticMemoryItem>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize, Default)]
127pub struct WorkingMemory {
128 pub variables: HashMap<String, Value>,
129 pub active_goals: Vec<String>,
130 pub current_context: Option<String>,
131 pub attention_focus: Vec<String>,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct MemoryItem {
137 pub id: ContextId,
138 pub content: String,
139 pub memory_type: MemoryType,
140 pub importance: f32,
141 pub access_count: u32,
142 pub last_accessed: SystemTime,
143 pub created_at: SystemTime,
144 pub embedding: Option<Vec<f32>>,
145 pub metadata: HashMap<String, String>,
146}
147
148#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
150pub enum MemoryType {
151 Factual,
152 Procedural,
153 Episodic,
154 Semantic,
155 Working,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct SemanticMemoryItem {
161 pub id: ContextId,
162 pub concept: String,
163 pub relationships: Vec<ConceptRelationship>,
164 pub properties: HashMap<String, Value>,
165 pub confidence: f32,
166 pub created_at: SystemTime,
167 pub updated_at: SystemTime,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct ConceptRelationship {
173 pub relation_type: RelationType,
174 pub target_concept: String,
175 pub strength: f32,
176 pub bidirectional: bool,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
181pub enum RelationType {
182 IsA,
183 PartOf,
184 RelatedTo,
185 Causes,
186 Enables,
187 Requires,
188 Similar,
189 Opposite,
190 Custom(String),
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct Episode {
196 pub id: ContextId,
197 pub title: String,
198 pub description: String,
199 pub events: Vec<EpisodeEvent>,
200 pub outcome: Option<String>,
201 pub lessons_learned: Vec<String>,
202 pub timestamp: SystemTime,
203 pub importance: f32,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct EpisodeEvent {
209 pub action: String,
210 pub result: String,
211 pub timestamp: SystemTime,
212 pub context: HashMap<String, String>,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize, Default)]
217pub struct KnowledgeBase {
218 pub facts: Vec<KnowledgeFact>,
219 pub procedures: Vec<Procedure>,
220 pub learned_patterns: Vec<Pattern>,
221 pub shared_knowledge: Vec<SharedKnowledgeRef>,
222 pub domain_expertise: HashMap<String, ExpertiseLevel>,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct KnowledgeFact {
228 pub id: KnowledgeId,
229 pub subject: String,
230 pub predicate: String,
231 pub object: String,
232 pub confidence: f32,
233 pub source: KnowledgeSource,
234 pub created_at: SystemTime,
235 pub verified: bool,
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize)]
240pub struct Procedure {
241 pub id: KnowledgeId,
242 pub name: String,
243 pub description: String,
244 pub steps: Vec<ProcedureStep>,
245 pub preconditions: Vec<String>,
246 pub postconditions: Vec<String>,
247 pub success_rate: f32,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct ProcedureStep {
253 pub order: u32,
254 pub action: String,
255 pub expected_result: String,
256 pub error_handling: Option<String>,
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize)]
261pub struct Pattern {
262 pub id: KnowledgeId,
263 pub name: String,
264 pub description: String,
265 pub conditions: Vec<String>,
266 pub outcomes: Vec<String>,
267 pub confidence: f32,
268 pub occurrences: u32,
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
273pub struct SharedKnowledgeRef {
274 pub knowledge_id: KnowledgeId,
275 pub source_agent: AgentId,
276 pub shared_at: SystemTime,
277 pub access_level: AccessLevel,
278 pub trust_score: f32,
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize)]
283pub enum KnowledgeSource {
284 Experience,
285 Learning,
286 SharedFromAgent(AgentId),
287 ExternalDocument(String),
288 UserProvided,
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize)]
293pub enum ExpertiseLevel {
294 Novice,
295 Intermediate,
296 Advanced,
297 Expert,
298}
299
300#[derive(Debug, Clone, Serialize, Deserialize)]
302pub enum AccessLevel {
303 Public,
304 Restricted,
305 Confidential,
306 Secret,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct ConversationItem {
312 pub id: ContextId,
313 pub role: ConversationRole,
314 pub content: String,
315 pub timestamp: SystemTime,
316 pub context_used: Vec<ContextId>,
317 pub knowledge_used: Vec<KnowledgeId>,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
322pub enum ConversationRole {
323 User,
324 Agent,
325 System,
326 Tool,
327}
328
329#[derive(Debug, Clone, Serialize, Deserialize)]
331pub struct RetentionPolicy {
332 pub session_retention: Duration,
333 pub memory_retention: Duration,
334 pub knowledge_retention: Duration,
335 pub auto_archive: bool,
336 pub encryption_required: bool,
337}
338
339impl Default for RetentionPolicy {
340 fn default() -> Self {
341 Self {
342 session_retention: Duration::from_secs(86400), memory_retention: Duration::from_secs(604800), knowledge_retention: Duration::from_secs(2592000), auto_archive: true,
346 encryption_required: true,
347 }
348 }
349}
350
351#[derive(Debug, Clone, Serialize, Deserialize)]
353pub struct ContextQuery {
354 pub query_type: QueryType,
355 pub search_terms: Vec<String>,
356 pub time_range: Option<TimeRange>,
357 pub memory_types: Vec<MemoryType>,
358 pub relevance_threshold: f32,
359 pub max_results: usize,
360 pub include_embeddings: bool,
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
365pub enum QueryType {
366 Semantic,
367 Keyword,
368 Temporal,
369 Similarity,
370 Hybrid,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
375pub struct TimeRange {
376 pub start: SystemTime,
377 pub end: SystemTime,
378}
379
380#[derive(Debug, Clone, Serialize, Deserialize)]
382pub struct ContextItem {
383 pub id: ContextId,
384 pub content: String,
385 pub item_type: ContextItemType,
386 pub relevance_score: f32,
387 pub timestamp: SystemTime,
388 pub metadata: HashMap<String, String>,
389}
390
391#[derive(Debug, Clone, Serialize, Deserialize)]
393pub enum ContextItemType {
394 Memory(MemoryType),
395 Knowledge(KnowledgeType),
396 Conversation,
397 Episode,
398}
399
400#[derive(Debug, Clone, Serialize, Deserialize)]
402pub enum KnowledgeType {
403 Fact,
404 Procedure,
405 Pattern,
406 Shared,
407}
408
409#[derive(Debug, Clone, Serialize, Deserialize)]
411pub struct MemoryUpdate {
412 pub operation: UpdateOperation,
413 pub target: MemoryTarget,
414 pub data: Value,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
419pub enum UpdateOperation {
420 Add,
421 Update,
422 Delete,
423 Increment,
424}
425
426#[derive(Debug, Clone, Serialize, Deserialize)]
428pub enum MemoryTarget {
429 ShortTerm(ContextId),
430 LongTerm(ContextId),
431 Working(String),
432 Episodic(ContextId),
433 Semantic(ContextId),
434}
435
436#[derive(Debug, Clone, Serialize, Deserialize)]
438pub struct KnowledgeItem {
439 pub id: KnowledgeId,
440 pub content: String,
441 pub knowledge_type: KnowledgeType,
442 pub confidence: f32,
443 pub relevance_score: f32,
444 pub source: KnowledgeSource,
445 pub created_at: SystemTime,
446}
447
448#[derive(Debug, Clone, Serialize, Deserialize)]
450pub enum Knowledge {
451 Fact(KnowledgeFact),
452 Procedure(Procedure),
453 Pattern(Pattern),
454}
455
456#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct ContextStats {
459 pub total_memory_items: usize,
460 pub total_knowledge_items: usize,
461 pub total_conversations: usize,
462 pub total_episodes: usize,
463 pub memory_size_bytes: usize,
464 pub last_activity: SystemTime,
465 pub retention_status: RetentionStatus,
466}
467
468#[derive(Debug, Clone, Serialize, Deserialize)]
470pub struct RetentionStatus {
471 pub items_to_archive: usize,
472 pub items_to_delete: usize,
473 pub next_cleanup: SystemTime,
474}
475
476#[derive(Debug, Clone, Serialize, Deserialize)]
478pub struct VectorSearchResult {
479 pub id: VectorId,
480 pub content: String,
481 pub score: f32,
482 pub metadata: HashMap<String, String>,
483 pub embedding: Option<Vec<f32>>,
484}
485
486#[derive(Debug, Clone, Serialize, Deserialize)]
488pub struct VectorMetadata {
489 pub agent_id: AgentId,
490 pub content_type: VectorContentType,
491 pub source_id: String,
492 pub created_at: SystemTime,
493 pub updated_at: SystemTime,
494 pub tags: Vec<String>,
495 pub custom_fields: HashMap<String, String>,
496}
497
498#[derive(Debug, Clone, Serialize, Deserialize)]
500pub enum VectorContentType {
501 Memory(MemoryType),
502 Knowledge(KnowledgeType),
503 Conversation,
504 Document,
505 Custom(String),
506}
507
508#[derive(Debug, Clone, Serialize, Deserialize)]
510pub struct VectorBatchOperation {
511 pub operation_type: VectorOperationType,
512 pub items: Vec<VectorBatchItem>,
513}
514
515#[derive(Debug, Clone, Serialize, Deserialize)]
517pub enum VectorOperationType {
518 Insert,
519 Update,
520 Delete,
521 Search,
522}
523
524#[derive(Debug, Clone, Serialize, Deserialize)]
526pub struct VectorBatchItem {
527 pub id: Option<VectorId>,
528 pub content: String,
529 pub embedding: Option<Vec<f32>>,
530 pub metadata: VectorMetadata,
531}
532
533#[derive(Debug, Clone, Serialize, Deserialize)]
535pub struct VectorDatabaseConfig {
536 pub provider: VectorDatabaseProvider,
537 pub connection_string: String,
538 pub collection_name: String,
539 pub vector_dimension: usize,
540 pub distance_metric: String,
541 pub batch_size: usize,
542 pub max_connections: usize,
543 pub timeout_seconds: u64,
544}
545
546#[derive(Debug, Clone, Serialize, Deserialize)]
548pub enum VectorDatabaseProvider {
549 Qdrant,
550 ChromaDB,
551 Pinecone,
552 Weaviate,
553}
554
555#[derive(Debug, Clone, thiserror::Error)]
557pub enum ContextError {
558 #[error("Context not found: {id}")]
559 NotFound { id: ContextId },
560
561 #[error("Knowledge not found: {id}")]
562 KnowledgeNotFound { id: KnowledgeId },
563
564 #[error("Session not found: {id}")]
565 SessionNotFound { id: SessionId },
566
567 #[error("Storage error: {reason}")]
568 StorageError { reason: String },
569
570 #[error("Serialization error: {reason}")]
571 SerializationError { reason: String },
572
573 #[error("Query error: {reason}")]
574 QueryError { reason: String },
575
576 #[error("Policy violation: {reason}")]
577 PolicyViolation { reason: String },
578
579 #[error("Access denied: {reason}")]
580 AccessDenied { reason: String },
581
582 #[error("Invalid operation: {reason}")]
583 InvalidOperation { reason: String },
584
585 #[error("System error: {reason}")]
586 SystemError { reason: String },
587
588 #[error("Vector database error: {reason}")]
589 VectorDatabaseError { reason: String },
590
591 #[error("Embedding generation error: {reason}")]
592 EmbeddingError { reason: String },
593
594 #[error("Batch operation error: {reason}")]
595 BatchOperationError { reason: String },
596
597 #[error("Vector not found: {id}")]
598 VectorNotFound { id: VectorId },
599}
600
601impl Default for ContextQuery {
602 fn default() -> Self {
603 Self {
604 query_type: QueryType::Semantic,
605 search_terms: Vec::new(),
606 time_range: None,
607 memory_types: Vec::new(),
608 relevance_threshold: 0.7,
609 max_results: 10,
610 include_embeddings: false,
611 }
612 }
613}
614
615#[async_trait]
617pub trait ContextPersistence: Send + Sync {
618 async fn save_context(
620 &self,
621 agent_id: AgentId,
622 context: &AgentContext,
623 ) -> Result<(), ContextError>;
624
625 async fn load_context(&self, agent_id: AgentId) -> Result<Option<AgentContext>, ContextError>;
627
628 async fn delete_context(&self, agent_id: AgentId) -> Result<(), ContextError>;
630
631 async fn list_agent_contexts(&self) -> Result<Vec<AgentId>, ContextError>;
633
634 async fn context_exists(&self, agent_id: AgentId) -> Result<bool, ContextError>;
636
637 async fn get_storage_stats(&self) -> Result<StorageStats, ContextError>;
639
640 fn as_any(&self) -> &dyn std::any::Any;
642}
643
644#[derive(Debug, Clone, Serialize, Deserialize)]
646pub struct StorageStats {
647 pub total_contexts: usize,
648 pub total_size_bytes: u64,
649 pub last_cleanup: SystemTime,
650 pub storage_path: PathBuf,
651}
652
653#[derive(Debug, Clone, Serialize, Deserialize)]
655pub struct FilePersistenceConfig {
656 pub root_data_dir: PathBuf,
658
659 pub state_dir: PathBuf,
661 pub logs_dir: PathBuf,
662 pub prompts_dir: PathBuf,
663 pub vector_db_dir: PathBuf,
664
665 pub enable_compression: bool,
667 pub enable_encryption: bool,
668 pub backup_count: usize,
669 pub auto_save_interval: u64,
670
671 pub auto_create_dirs: bool,
673 pub dir_permissions: Option<u32>,
674}
675
676impl Default for FilePersistenceConfig {
677 fn default() -> Self {
678 let mut root_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
679 root_dir.push(".symbiont");
680 root_dir.push("data");
681
682 Self {
683 root_data_dir: root_dir,
684 state_dir: PathBuf::from("state"),
685 logs_dir: PathBuf::from("logs"),
686 prompts_dir: PathBuf::from("prompts"),
687 vector_db_dir: PathBuf::from("vector_db"),
688 enable_compression: true,
689 enable_encryption: false,
690 backup_count: 3,
691 auto_save_interval: 300,
692 auto_create_dirs: true,
693 dir_permissions: Some(0o755),
694 }
695 }
696}
697
698#[derive(Debug, Clone, thiserror::Error)]
700pub enum MigrationError {
701 #[error("IO error during migration: {reason}")]
702 IOError { reason: String },
703
704 #[error("Context error during migration: {error}")]
705 ContextError { error: ContextError },
706
707 #[error("Migration validation failed: {reason}")]
708 ValidationError { reason: String },
709}
710
711impl From<std::io::Error> for MigrationError {
712 fn from(error: std::io::Error) -> Self {
713 MigrationError::IOError {
714 reason: error.to_string(),
715 }
716 }
717}
718
719impl From<ContextError> for MigrationError {
720 fn from(error: ContextError) -> Self {
721 MigrationError::ContextError { error }
722 }
723}
724
725impl FilePersistenceConfig {
726 pub fn state_path(&self) -> PathBuf {
728 self.root_data_dir.join(&self.state_dir)
729 }
730
731 pub fn logs_path(&self) -> PathBuf {
733 self.root_data_dir.join(&self.logs_dir)
734 }
735
736 pub fn prompts_path(&self) -> PathBuf {
738 self.root_data_dir.join(&self.prompts_dir)
739 }
740
741 pub fn vector_db_path(&self) -> PathBuf {
743 self.root_data_dir.join(&self.vector_db_dir)
744 }
745
746 pub fn agent_contexts_path(&self) -> PathBuf {
748 self.state_path().join("agents")
749 }
750
751 pub fn sessions_path(&self) -> PathBuf {
753 self.state_path().join("sessions")
754 }
755
756 pub async fn ensure_directories(&self) -> Result<(), std::io::Error> {
758 if self.auto_create_dirs {
759 tokio::fs::create_dir_all(self.state_path()).await?;
760 tokio::fs::create_dir_all(self.logs_path()).await?;
761 tokio::fs::create_dir_all(self.prompts_path()).await?;
762 tokio::fs::create_dir_all(self.vector_db_path()).await?;
763
764 tokio::fs::create_dir_all(self.agent_contexts_path()).await?;
766 tokio::fs::create_dir_all(self.sessions_path()).await?;
767 tokio::fs::create_dir_all(self.logs_path().join("system")).await?;
768 tokio::fs::create_dir_all(self.logs_path().join("agents")).await?;
769 tokio::fs::create_dir_all(self.logs_path().join("audit")).await?;
770 tokio::fs::create_dir_all(self.prompts_path().join("templates")).await?;
771 tokio::fs::create_dir_all(self.prompts_path().join("history")).await?;
772 tokio::fs::create_dir_all(self.prompts_path().join("cache")).await?;
773 tokio::fs::create_dir_all(self.vector_db_path().join("collections")).await?;
774 tokio::fs::create_dir_all(self.vector_db_path().join("indexes")).await?;
775 tokio::fs::create_dir_all(self.vector_db_path().join("metadata")).await?;
776 }
777 Ok(())
778 }
779
780 pub async fn migrate_from_legacy(legacy_path: PathBuf) -> Result<Self, MigrationError> {
782 let config = Self::default();
783
784 if legacy_path.exists() {
786 let agents_path = config.agent_contexts_path();
787 config.ensure_directories().await?;
788
789 let mut entries = tokio::fs::read_dir(&legacy_path).await?;
791 while let Some(entry) = entries.next_entry().await? {
792 let file_path = entry.path();
793 if file_path
794 .extension()
795 .is_some_and(|ext| ext == "json" || ext == "gz")
796 {
797 let dest_path = agents_path.join(entry.file_name());
798 tokio::fs::copy(&file_path, &dest_path).await?;
799 }
800 }
801 }
802
803 Ok(config)
804 }
805
806 pub fn is_legacy(&self) -> bool {
808 false
812 }
813}