Skip to main content

adk_memory/
service.rs

1use adk_core::{Content, Result};
2use async_trait::async_trait;
3use chrono::{DateTime, Utc};
4
5#[derive(Debug, Clone)]
6pub struct MemoryEntry {
7    pub content: Content,
8    pub author: String,
9    pub timestamp: DateTime<Utc>,
10}
11
12#[derive(Debug, Clone, serde::Deserialize)]
13pub struct SearchRequest {
14    pub query: String,
15    pub user_id: String,
16    pub app_name: String,
17    /// Maximum number of results to return. `None` defaults to 10.
18    pub limit: Option<usize>,
19    /// Minimum similarity score threshold (0.0–1.0). Results below this
20    /// score are excluded. `None` means no threshold.
21    pub min_score: Option<f32>,
22    /// Optional project scope. `None` returns only global entries.
23    /// `Some(id)` returns global entries + entries for that project.
24    #[serde(default)]
25    pub project_id: Option<String>,
26}
27
28#[derive(Debug, Clone)]
29pub struct SearchResponse {
30    pub memories: Vec<MemoryEntry>,
31}
32
33/// Validate a project identifier.
34///
35/// Returns `Ok(())` if the project_id is non-empty and at most 256 characters.
36/// Returns a descriptive error otherwise.
37pub fn validate_project_id(project_id: &str) -> Result<()> {
38    if project_id.is_empty() {
39        return Err(adk_core::AdkError::memory("project_id must not be empty"));
40    }
41    if project_id.len() > 256 {
42        return Err(adk_core::AdkError::memory(format!(
43            "project_id exceeds maximum length of 256 characters (got {})",
44            project_id.len()
45        )));
46    }
47    Ok(())
48}
49
50#[async_trait]
51pub trait MemoryService: Send + Sync {
52    async fn add_session(
53        &self,
54        app_name: &str,
55        user_id: &str,
56        session_id: &str,
57        entries: Vec<MemoryEntry>,
58    ) -> Result<()>;
59    async fn search(&self, req: SearchRequest) -> Result<SearchResponse>;
60
61    /// Delete all memory entries for a specific user.
62    ///
63    /// Required for GDPR right-to-erasure compliance. Removes all stored
64    /// memories (including embeddings) for the given app and user.
65    async fn delete_user(&self, app_name: &str, user_id: &str) -> Result<()> {
66        let _ = (app_name, user_id);
67        Err(adk_core::AdkError::memory("delete_user not implemented"))
68    }
69
70    /// Delete all memory entries for a specific session.
71    async fn delete_session(&self, app_name: &str, user_id: &str, session_id: &str) -> Result<()> {
72        let _ = (app_name, user_id, session_id);
73        Err(adk_core::AdkError::memory("delete_session not implemented"))
74    }
75
76    /// Add a single memory entry directly (not tied to a session).
77    async fn add_entry(&self, app_name: &str, user_id: &str, entry: MemoryEntry) -> Result<()> {
78        let _ = (app_name, user_id, entry);
79        Err(adk_core::AdkError::memory("add_entry not implemented"))
80    }
81
82    /// Delete entries matching a query. Returns count of deleted entries.
83    async fn delete_entries(&self, app_name: &str, user_id: &str, query: &str) -> Result<u64> {
84        let _ = (app_name, user_id, query);
85        Err(adk_core::AdkError::memory("delete_entries not implemented"))
86    }
87
88    /// Verify backend connectivity.
89    ///
90    /// Returns `Ok(())` if the backend is reachable and responsive.
91    /// The default implementation always succeeds (suitable for in-memory).
92    async fn health_check(&self) -> Result<()> {
93        Ok(())
94    }
95
96    /// Add session entries scoped to a project.
97    /// Default delegates to `add_session` (global).
98    async fn add_session_to_project(
99        &self,
100        app_name: &str,
101        user_id: &str,
102        session_id: &str,
103        project_id: &str,
104        entries: Vec<MemoryEntry>,
105    ) -> Result<()> {
106        let _ = project_id;
107        self.add_session(app_name, user_id, session_id, entries).await
108    }
109
110    /// Add a single entry scoped to a project.
111    /// Default delegates to `add_entry` (global).
112    async fn add_entry_to_project(
113        &self,
114        app_name: &str,
115        user_id: &str,
116        project_id: &str,
117        entry: MemoryEntry,
118    ) -> Result<()> {
119        let _ = project_id;
120        self.add_entry(app_name, user_id, entry).await
121    }
122
123    /// Delete entries matching a query within a specific project.
124    /// Default delegates to `delete_entries` (global).
125    async fn delete_entries_in_project(
126        &self,
127        app_name: &str,
128        user_id: &str,
129        project_id: &str,
130        query: &str,
131    ) -> Result<u64> {
132        let _ = project_id;
133        self.delete_entries(app_name, user_id, query).await
134    }
135
136    /// Delete all entries for a specific project.
137    /// Default returns "not implemented" error.
138    async fn delete_project(&self, app_name: &str, user_id: &str, project_id: &str) -> Result<u64> {
139        let _ = (app_name, user_id, project_id);
140        Err(adk_core::AdkError::memory("delete_project not implemented"))
141    }
142}