use crate::errors::{MemoryToolsError, MemoryToolsResult};
use crate::types::{
MemoryOperationPayload, MemoryOperationResponse, QueryParams,
StoreParams, FilterParams
};
use cortex_mem_core::{
memory::MemoryManager, Memory, MemoryType, MemoryMetadata
};
use serde_json::{json, Value};
use tracing::{error, info};
pub struct MemoryOperations {
memory_manager: std::sync::Arc<MemoryManager>,
default_user_id: Option<String>,
default_agent_id: Option<String>,
default_limit: usize,
}
impl MemoryOperations {
pub fn new(
memory_manager: std::sync::Arc<MemoryManager>,
default_user_id: Option<String>,
default_agent_id: Option<String>,
default_limit: usize,
) -> Self {
Self {
memory_manager,
default_user_id,
default_agent_id,
default_limit,
}
}
pub async fn store_memory(&self, payload: MemoryOperationPayload) -> MemoryToolsResult<MemoryOperationResponse> {
let params = StoreParams::from_payload(
&payload,
self.default_user_id.clone(),
self.default_agent_id.clone(),
)?;
info!("Storing memory for user: {}", params.user_id);
let memory_type = MemoryType::parse_with_result(¶ms.memory_type)
.map_err(|e| MemoryToolsError::InvalidInput(format!("Invalid memory_type: {}", e)))?;
let mut metadata = MemoryMetadata::new(memory_type);
metadata.user_id = Some(params.user_id.clone());
metadata.agent_id = params.agent_id.clone();
if let Some(topics) = params.topics {
metadata.topics = topics;
}
match self.memory_manager.store(params.content, metadata).await {
Ok(memory_id) => {
info!("Memory stored successfully with ID: {}", memory_id);
let data = json!({
"memory_id": memory_id,
"user_id": params.user_id,
"agent_id": params.agent_id
});
Ok(MemoryOperationResponse::success_with_data(
"Memory stored successfully",
data,
))
}
Err(e) => {
error!("Failed to store memory: {}", e);
Err(MemoryToolsError::Runtime(format!("Failed to store memory: {}", e)))
}
}
}
pub async fn query_memory(&self, payload: MemoryOperationPayload) -> MemoryToolsResult<MemoryOperationResponse> {
let params = QueryParams::from_payload(&payload, self.default_limit)?;
info!("Querying memories with query: {}", params.query);
let memory_type = params.memory_type
.map(|t| MemoryType::parse_with_result(&t))
.transpose()
.map_err(|e| MemoryToolsError::InvalidInput(format!("Invalid memory_type: {}", e)))?;
let mut filters = cortex_mem_core::types::Filters::default();
if let Some(user_id) = params.user_id {
filters.user_id = Some(user_id);
}
if let Some(agent_id) = params.agent_id {
filters.agent_id = Some(agent_id);
}
if let Some(memory_type) = memory_type {
filters.memory_type = Some(memory_type);
}
if let Some(topics) = params.topics {
filters.topics = Some(topics);
}
match self.memory_manager.search(
¶ms.query,
&filters,
params.limit,
).await {
Ok(memories) => {
let count = memories.len();
info!("Found {} memories", count);
let memories_json: Vec<Value> = memories
.into_iter()
.map(|scored_memory| memory_to_json(&scored_memory.memory))
.collect();
let data = json!({
"count": count,
"memories": memories_json
});
Ok(MemoryOperationResponse::success_with_data(
"Query completed successfully",
data,
))
}
Err(e) => {
error!("Failed to query memories: {}", e);
Err(MemoryToolsError::Runtime(format!("Failed to query memories: {}", e)))
}
}
}
pub async fn list_memories(&self, payload: MemoryOperationPayload) -> MemoryToolsResult<MemoryOperationResponse> {
let params = FilterParams::from_payload(&payload, self.default_limit)?;
info!("Listing memories with filters");
let mut filters = cortex_mem_core::types::Filters::default();
if let Some(user_id) = params.user_id {
filters.user_id = Some(user_id);
}
if let Some(agent_id) = params.agent_id {
filters.agent_id = Some(agent_id);
}
if let Some(memory_type) = params.memory_type {
if let Ok(mt) = cortex_mem_core::types::MemoryType::parse_with_result(&memory_type) {
filters.memory_type = Some(mt);
}
}
match self.memory_manager.list(&filters, Some(params.limit)).await {
Ok(memories) => {
let count = memories.len();
info!("Listed {} memories", count);
let memories_json: Vec<Value> = memories
.into_iter()
.map(|memory| memory_to_json(&memory))
.collect();
let data = json!({
"count": count,
"memories": memories_json
});
Ok(MemoryOperationResponse::success_with_data(
"List completed successfully",
data,
))
}
Err(e) => {
error!("Failed to list memories: {}", e);
Err(MemoryToolsError::Runtime(format!("Failed to list memories: {}", e)))
}
}
}
pub async fn get_memory(&self, payload: MemoryOperationPayload) -> MemoryToolsResult<MemoryOperationResponse> {
let memory_id = payload.memory_id
.ok_or_else(|| MemoryToolsError::InvalidInput("Memory ID is required".to_string()))?;
info!("Getting memory with ID: {}", memory_id);
match self.memory_manager.get(&memory_id).await {
Ok(Some(memory)) => {
let memory_json = memory_to_json(&memory);
let data = json!({
"memory": memory_json
});
Ok(MemoryOperationResponse::success_with_data(
"Memory retrieved successfully",
data,
))
}
Ok(None) => {
error!("Memory not found: {}", memory_id);
Err(MemoryToolsError::MemoryNotFound(memory_id))
}
Err(e) => {
error!("Failed to get memory: {}", e);
Err(MemoryToolsError::Runtime(format!("Failed to get memory: {}", e)))
}
}
}
}
fn memory_to_json(memory: &Memory) -> Value {
let mut metadata_obj = json!({});
if let Some(user_id) = &memory.metadata.user_id {
metadata_obj["user_id"] = Value::String(user_id.clone());
}
if let Some(agent_id) = &memory.metadata.agent_id {
metadata_obj["agent_id"] = Value::String(agent_id.clone());
}
if let Some(run_id) = &memory.metadata.run_id {
metadata_obj["run_id"] = Value::String(run_id.clone());
}
if let Some(actor_id) = &memory.metadata.actor_id {
metadata_obj["actor_id"] = Value::String(actor_id.clone());
}
if let Some(role) = &memory.metadata.role {
metadata_obj["role"] = Value::String(role.clone());
}
metadata_obj["memory_type"] = Value::String(format!("{:?}", memory.metadata.memory_type));
metadata_obj["hash"] = Value::String(memory.metadata.hash.clone());
metadata_obj["importance_score"] = Value::Number(serde_json::Number::from_f64(memory.metadata.importance_score as f64).unwrap());
if !memory.metadata.entities.is_empty() {
metadata_obj["entities"] = Value::Array(
memory.metadata.entities.iter()
.map(|e| Value::String(e.clone()))
.collect()
);
}
if !memory.metadata.topics.is_empty() {
metadata_obj["topics"] = Value::Array(
memory.metadata.topics.iter()
.map(|t| Value::String(t.clone()))
.collect()
);
}
if !memory.metadata.custom.is_empty() {
metadata_obj["custom"] = Value::Object(
memory.metadata.custom.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect()
);
}
json!({
"id": memory.id,
"content": memory.content,
"created_at": memory.created_at.to_rfc3339(),
"updated_at": memory.updated_at.to_rfc3339(),
"metadata": metadata_obj
})
}