Skip to main content

aios_protocol/
memory.rs

1//! Memory types: soul profile, observations, and provenance.
2
3use chrono::{DateTime, Utc};
4use indexmap::IndexMap;
5use serde::{Deserialize, Serialize};
6
7/// Memory scope for scoped storage and retrieval.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub enum MemoryScope {
11    Session,
12    User,
13    Agent,
14    Org,
15}
16
17/// Durable agent identity and preferences.
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct SoulProfile {
20    pub name: String,
21    pub mission: String,
22    pub preferences: IndexMap<String, String>,
23    pub updated_at: DateTime<Utc>,
24}
25
26impl Default for SoulProfile {
27    fn default() -> Self {
28        Self {
29            name: "Agent OS agent".to_owned(),
30            mission: "Run tool-mediated work safely and reproducibly".to_owned(),
31            preferences: IndexMap::new(),
32            updated_at: Utc::now(),
33        }
34    }
35}
36
37/// An extracted observation with provenance linking.
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct Observation {
40    pub observation_id: uuid::Uuid,
41    pub created_at: DateTime<Utc>,
42    pub text: String,
43    pub tags: Vec<String>,
44    pub provenance: Provenance,
45}
46
47/// Links an observation back to its source events and files.
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct Provenance {
50    /// First event sequence in the source range.
51    pub event_start: u64,
52    /// Last event sequence in the source range.
53    pub event_end: u64,
54    /// Files referenced with their content hashes.
55    pub files: Vec<FileProvenance>,
56}
57
58/// A file reference with content hash for provenance tracking.
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct FileProvenance {
61    pub path: String,
62    pub sha256: String,
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn memory_scope_ordering() {
71        assert!(MemoryScope::Session < MemoryScope::User);
72        assert!(MemoryScope::User < MemoryScope::Agent);
73        assert!(MemoryScope::Agent < MemoryScope::Org);
74    }
75
76    #[test]
77    fn memory_scope_serde_roundtrip() {
78        for scope in [
79            MemoryScope::Session,
80            MemoryScope::User,
81            MemoryScope::Agent,
82            MemoryScope::Org,
83        ] {
84            let json = serde_json::to_string(&scope).unwrap();
85            let back: MemoryScope = serde_json::from_str(&json).unwrap();
86            assert_eq!(scope, back);
87        }
88    }
89
90    #[test]
91    fn soul_profile_default() {
92        let soul = SoulProfile::default();
93        assert_eq!(soul.name, "Agent OS agent");
94        assert!(soul.preferences.is_empty());
95    }
96}