//! Memory Commands - Tauri commands for persistent memory operations //! //! Phase 1 of Intelligence Layer Migration: //! Provides frontend API for memory storage and retrieval use crate::memory::{PersistentMemory, PersistentMemoryStore, MemorySearchQuery, MemoryStats, generate_memory_id}; use serde::{Deserialize, Serialize}; use std::sync::Arc; use tauri::{AppHandle, Manager, State}; use tokio::sync::Mutex; use chrono::Utc; /// Shared memory store state pub type MemoryStoreState = Arc>>; /// Memory entry for frontend API #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MemoryEntryInput { pub agent_id: String, pub memory_type: String, pub content: String, pub importance: Option, pub source: Option, pub tags: Option>, pub conversation_id: Option, } /// Memory search options for frontend API #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MemorySearchOptions { pub agent_id: Option, pub memory_type: Option, pub tags: Option>, pub query: Option, pub min_importance: Option, pub limit: Option, pub offset: Option, } /// Initialize the memory store #[tauri::command] pub async fn memory_init( app_handle: AppHandle, state: State<'_, MemoryStoreState>, ) -> Result<(), String> { let store = PersistentMemoryStore::new(&app_handle).await?; let mut state_guard = state.lock().await; *state_guard = Some(store); Ok(()) } /// Store a new memory #[tauri::command] pub async fn memory_store( entry: MemoryEntryInput, state: State<'_, MemoryStoreState>, ) -> Result { let state_guard = state.lock().await; let store = state_guard .as_ref() .ok_or_else(|| "Memory store not initialized. Call memory_init first.".to_string())?; let now = Utc::now().to_rfc3339(); let memory = PersistentMemory { id: generate_memory_id(), agent_id: entry.agent_id, memory_type: entry.memory_type, content: entry.content, importance: entry.importance.unwrap_or(5), source: entry.source.unwrap_or_else(|| "auto".to_string()), tags: serde_json::to_string(&entry.tags.unwrap_or_default()) .unwrap_or_else(|_| "[]".to_string()), conversation_id: entry.conversation_id, created_at: now.clone(), last_accessed_at: now, access_count: 0, embedding: None, }; let id = memory.id.clone(); store.store(&memory).await?; Ok(id) } /// Get a memory by ID #[tauri::command] pub async fn memory_get( id: String, state: State<'_, MemoryStoreState>, ) -> Result, String> { let state_guard = state.lock().await; let store = state_guard .as_ref() .ok_or_else(|| "Memory store not initialized".to_string())?; store.get(&id).await } /// Search memories #[tauri::command] pub async fn memory_search( options: MemorySearchOptions, state: State<'_, MemoryStoreState>, ) -> Result, String> { let state_guard = state.lock().await; let store = state_guard .as_ref() .ok_or_else(|| "Memory store not initialized".to_string())?; let query = MemorySearchQuery { agent_id: options.agent_id, memory_type: options.memory_type, tags: options.tags, query: options.query, min_importance: options.min_importance, limit: options.limit, offset: options.offset, }; store.search(query).await } /// Delete a memory by ID #[tauri::command] pub async fn memory_delete( id: String, state: State<'_, MemoryStoreState>, ) -> Result<(), String> { let state_guard = state.lock().await; let store = state_guard .as_ref() .ok_or_else(|| "Memory store not initialized".to_string())?; store.delete(&id).await?; Ok(()) } /// Delete all memories for an agent #[tauri::command] pub async fn memory_delete_all( agent_id: String, state: State<'_, MemoryStoreState>, ) -> Result { let state_guard = state.lock().await; let store = state_guard .as_ref() .ok_or_else(|| "Memory store not initialized".to_string())?; store.delete_by_agent(&agent_id).await } /// Get memory statistics #[tauri::command] pub async fn memory_stats( state: State<'_, MemoryStoreState>, ) -> Result { let state_guard = state.lock().await; let store = state_guard .as_ref() .ok_or_else(|| "Memory store not initialized".to_string())?; store.stats().await } /// Export all memories for backup #[tauri::command] pub async fn memory_export( state: State<'_, MemoryStoreState>, ) -> Result, String> { let state_guard = state.lock().await; let store = state_guard .as_ref() .ok_or_else(|| "Memory store not initialized".to_string())?; store.export_all().await } /// Import memories from backup #[tauri::command] pub async fn memory_import( memories: Vec, state: State<'_, MemoryStoreState>, ) -> Result { let state_guard = state.lock().await; let store = state_guard .as_ref() .ok_or_else(|| "Memory store not initialized".to_string())?; store.import_batch(&memories).await } /// Get the database path #[tauri::command] pub async fn memory_db_path( state: State<'_, MemoryStoreState>, ) -> Result { let state_guard = state.lock().await; let store = state_guard .as_ref() .ok_or_else(|| "Memory store not initialized".to_string())?; Ok(store.path().to_string_lossy().to_string()) }