1use std::sync::Arc;
20
21use async_trait::async_trait;
22use chrono::Utc;
23
24use crate::{MemoryService, SearchRequest};
25
26pub struct MemoryServiceAdapter {
31 inner: Arc<dyn MemoryService>,
32 app_name: String,
33 user_id: String,
34 project_id: Option<String>,
35}
36
37impl MemoryServiceAdapter {
38 pub fn new(
40 inner: Arc<dyn MemoryService>,
41 app_name: impl Into<String>,
42 user_id: impl Into<String>,
43 ) -> Self {
44 Self { inner, app_name: app_name.into(), user_id: user_id.into(), project_id: None }
45 }
46
47 pub fn with_project_id(mut self, project_id: impl Into<String>) -> Self {
52 self.project_id = Some(project_id.into());
53 self
54 }
55}
56
57#[async_trait]
58impl adk_core::Memory for MemoryServiceAdapter {
59 async fn search(&self, query: &str) -> adk_core::Result<Vec<adk_core::MemoryEntry>> {
60 let inner = self.inner.clone();
61 let resp = inner
62 .search(SearchRequest {
63 query: query.to_string(),
64 app_name: self.app_name.clone(),
65 user_id: self.user_id.clone(),
66 limit: None,
67 min_score: None,
68 project_id: self.project_id.clone(),
69 })
70 .await?;
71
72 Ok(resp
73 .memories
74 .into_iter()
75 .map(|m| adk_core::MemoryEntry { content: m.content, author: m.author })
76 .collect())
77 }
78
79 async fn add(&self, entry: adk_core::MemoryEntry) -> adk_core::Result<()> {
80 let inner = self.inner.clone();
81 let mem_entry = crate::MemoryEntry {
82 content: entry.content,
83 author: entry.author,
84 timestamp: Utc::now(),
85 };
86 if let Some(ref pid) = self.project_id {
87 inner.add_entry_to_project(&self.app_name, &self.user_id, pid, mem_entry).await
88 } else {
89 inner.add_entry(&self.app_name, &self.user_id, mem_entry).await
90 }
91 }
92
93 async fn delete(&self, query: &str) -> adk_core::Result<u64> {
94 let inner = self.inner.clone();
95 if let Some(ref pid) = self.project_id {
96 inner.delete_entries_in_project(&self.app_name, &self.user_id, pid, query).await
97 } else {
98 inner.delete_entries(&self.app_name, &self.user_id, query).await
99 }
100 }
101
102 async fn health_check(&self) -> adk_core::Result<()> {
103 let inner = self.inner.clone();
104 inner.health_check().await
105 }
106
107 fn supports_project_scoping(&self) -> bool {
108 self.inner.supports_project_scoping()
109 }
110
111 async fn search_in_project(
112 &self,
113 query: &str,
114 project_id: &str,
115 ) -> adk_core::Result<Vec<adk_core::MemoryEntry>> {
116 let inner = self.inner.clone();
117 let resp = inner
118 .search(SearchRequest {
119 query: query.to_string(),
120 app_name: self.app_name.clone(),
121 user_id: self.user_id.clone(),
122 limit: None,
123 min_score: None,
124 project_id: Some(project_id.to_string()),
125 })
126 .await?;
127
128 Ok(resp
129 .memories
130 .into_iter()
131 .map(|m| adk_core::MemoryEntry { content: m.content, author: m.author })
132 .collect())
133 }
134
135 async fn add_to_project(
136 &self,
137 entry: adk_core::MemoryEntry,
138 project_id: &str,
139 ) -> adk_core::Result<()> {
140 let inner = self.inner.clone();
141 let mem_entry = crate::MemoryEntry {
142 content: entry.content,
143 author: entry.author,
144 timestamp: Utc::now(),
145 };
146 inner.add_entry_to_project(&self.app_name, &self.user_id, project_id, mem_entry).await
147 }
148}