use crate::embedding_profiles::EmbeddingRole;
use crate::errors::Error;
use crate::memory::lifecycle::{MemoryImportance, MemoryStatus, MemoryType};
use crate::memory_types::{AddResult, ConflictMemory, IngestPolicy};
use crate::sqlite::NewRow;
use super::store::MemoryStore;
#[derive(Clone, Copy, Debug)]
pub struct NewMemory<'a> {
pub project_id: &'a str,
pub content: &'a str,
pub metadata: Option<&'a str>,
pub memory_type: MemoryType,
pub status: MemoryStatus,
}
impl MemoryStore {
pub(crate) fn add_impl(
&mut self,
row: &NewMemory<'_>,
force: bool,
importance: Option<MemoryImportance>,
) -> Result<AddResult, Error> {
row.status.ensure_valid_for_insert()?;
Self::validate_input_length(row.content)?;
Self::validate_metadata(row.metadata)?;
let embedding = self.get_embedding(row.content, EmbeddingRole::Passage)?;
if force {
let id = self.insert_row(row, &embedding, importance)?;
return Ok(AddResult::Added { id });
}
let similars =
self.db
.find_similar(row.project_id, &embedding, self.config.similarity_threshold)?;
let conflicts: Vec<ConflictMemory> = similars
.into_iter()
.map(|m| ConflictMemory {
id: m.id,
content: m.content,
similarity: m.similarity.unwrap_or(0.0),
})
.collect();
if conflicts.is_empty() {
let id = self.insert_row(row, &embedding, importance)?;
Ok(AddResult::Added { id })
} else {
Ok(AddResult::Conflicts {
proposed: row.content.to_string(),
conflicts,
})
}
}
#[must_use = "handle the error or results may be lost"]
pub fn ingest_with_importance(
&mut self,
row: &NewMemory<'_>,
policy: IngestPolicy,
importance: MemoryImportance,
) -> Result<AddResult, Error> {
self.add_impl(row, policy == IngestPolicy::Force, Some(importance))
}
fn insert_row(
&self,
row: &NewMemory<'_>,
embedding: &[f32],
importance: Option<MemoryImportance>,
) -> Result<String, Error> {
let (memory_type, status) = (row.memory_type.as_str(), row.status.as_str());
match importance {
Some(level) => Ok(self.db.insert_with_importance(
&NewRow {
project_id: row.project_id,
content: row.content,
metadata: row.metadata,
memory_type,
status,
importance: level.as_str(),
},
embedding,
)?),
None => Ok(self.db.insert(
row.project_id,
row.content,
embedding,
row.metadata,
memory_type,
status,
)?),
}
}
}