use async_trait::async_trait;
use crate::error::MemoryError;
use super::advanced_types::{
AdvancedMemoryEntry, AdvancedMemoryQuery, DecayConfig, ExportFilter, MemoryStats,
ProceduralMemory,
};
#[async_trait]
pub trait AdvancedMemory: Send + Sync {
async fn store(&self, entry: AdvancedMemoryEntry) -> Result<(), MemoryError>;
async fn recall(
&self,
query: &AdvancedMemoryQuery,
) -> Result<Vec<AdvancedMemoryEntry>, MemoryError>;
async fn recall_namespaced(
&self,
namespace: &str,
query: &str,
limit: usize,
) -> Result<Vec<AdvancedMemoryEntry>, MemoryError> {
let query = AdvancedMemoryQuery::new(query)
.with_namespace(namespace)
.with_limit(limit);
self.recall(&query).await
}
async fn delete(&self, id: &str) -> Result<bool, MemoryError>;
async fn purge_namespace(&self, namespace: &str) -> Result<usize, MemoryError>;
async fn purge_session(&self, session_id: &str) -> Result<usize, MemoryError>;
async fn store_procedural(
&self,
memory: ProceduralMemory,
session_id: Option<String>,
) -> Result<(), MemoryError>;
async fn recall_procedural(
&self,
scenario: &str,
limit: usize,
) -> Result<Vec<ProceduralMemory>, MemoryError>;
async fn export(&self, filter: &ExportFilter) -> Result<Vec<AdvancedMemoryEntry>, MemoryError>;
async fn stats(&self) -> Result<MemoryStats, MemoryError>;
async fn apply_decay(&self, config: &DecayConfig) -> Result<usize, MemoryError>;
async fn update_importance(&self, id: &str, importance: f64) -> Result<(), MemoryError>;
async fn mark_superseded(&self, old_id: &str, new_id: &str) -> Result<(), MemoryError>;
}
#[async_trait]
pub trait ConsolidatableMemory: AdvancedMemory {
async fn consolidate(&self, namespace: &str) -> Result<Vec<String>, MemoryError>;
async fn find_similar(
&self,
content: &str,
threshold: f64,
limit: usize,
) -> Result<Vec<AdvancedMemoryEntry>, MemoryError>;
}
#[async_trait]
pub trait MemoryFactory: Send + Sync {
async fn create(
&self,
config: &MemoryBackendConfig,
) -> Result<Box<dyn AdvancedMemory>, MemoryError>;
}
#[derive(Debug, Clone)]
pub enum MemoryBackendConfig {
InMemory {
max_capacity: usize,
},
File {
path: std::path::PathBuf,
},
Sqlite {
path: std::path::PathBuf,
},
Qdrant {
url: String,
collection: String,
api_key: Option<String>,
},
}
pub trait ImportanceScorer: Send + Sync {
fn score(&self, content: &str, context: Option<&str>) -> f64;
}
pub struct DefaultImportanceScorer;
impl ImportanceScorer for DefaultImportanceScorer {
fn score(&self, content: &str, _context: Option<&str>) -> f64 {
let mut score: f64 = 0.5;
let len = content.len();
if len > 50 && len < 1000 {
score += 0.1;
}
let important_keywords = [
"重要",
"关键",
"必须",
"务必",
"critical",
"important",
"must",
"key",
];
let content_lower = content.to_lowercase();
for keyword in &important_keywords {
if content_lower.contains(keyword) {
score += 0.05;
}
}
if content.contains("```") || content.contains("`") {
score += 0.05;
}
score.min(1.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_importance_scorer() {
let scorer = DefaultImportanceScorer;
let score1 = scorer.score("这是一段普通的内容", None);
assert!((0.5..=0.7).contains(&score1));
let score2 = scorer.score("这是一个重要的关键信息", None);
assert!(score2 > score1);
let score3 = scorer.score("使用 `code` 函数", None);
assert!(score3 > score1);
}
#[test]
fn test_memory_backend_config() {
let config = MemoryBackendConfig::InMemory { max_capacity: 1000 };
match config {
MemoryBackendConfig::InMemory { max_capacity } => {
assert_eq!(max_capacity, 1000);
}
_ => panic!("错误的配置类型"),
}
}
}