use memvid_core::PutOptions;
use rig::memory::MemoryError;
use crate::dedup::{DedupSet, compute_key, hex_encode_key};
use crate::hook::MemoryConfig;
use crate::metadata::{FrameKind, MemvidFrameMetadata};
use crate::store::MemvidStore;
pub(crate) fn write_frame(
store: &MemvidStore,
config: &MemoryConfig,
dedup: &DedupSet,
kind: FrameKind,
conversation_id: &str,
chat_role: &str,
text: &str,
) -> Result<bool, MemoryError> {
if text.is_empty() {
return Ok(false);
}
let scope = config.scope.as_deref();
let key = compute_key(kind.as_str(), conversation_id, chat_role, scope, text);
if dedup
.contains(&key)
.map_err(|err| MemoryError::backend(Box::new(err)))?
{
tracing::debug!(
target: "rig_memvid::frame_writer",
conversation_id,
role = chat_role,
kind = kind.as_str(),
"skipping duplicate frame",
);
return Ok(false);
}
let key_hex = hex_encode_key(&key);
let opts = build_put_options(config, kind, conversation_id, chat_role, &key_hex);
if let Err(err) = store.put_text_uncommitted(text, opts) {
tracing::warn!(
target: "rig_memvid::frame_writer",
error = %err,
conversation_id,
role = chat_role,
kind = kind.as_str(),
"failed to persist frame into memvid",
);
return Err(MemoryError::backend(Box::new(err)));
}
dedup
.insert(key)
.map_err(|err| MemoryError::backend(Box::new(err)))?;
#[cfg(feature = "observe")]
rig_tap::emit_kind(
conversation_id,
rig_tap::EventKind::MemoryFrameWritten {
frame_kind: kind.as_str().to_string(),
frame_count_after: None,
bytes_written: text.len(),
},
);
Ok(true)
}
pub(crate) fn commit_if_each_turn(
store: &MemvidStore,
config: &MemoryConfig,
) -> Result<(), MemoryError> {
if config.commit_each_turn {
store
.commit()
.map_err(|err| MemoryError::backend(Box::new(err)))?;
}
Ok(())
}
fn build_put_options(
config: &MemoryConfig,
kind: FrameKind,
conversation_id: &str,
chat_role: &str,
dedup_key_hex: &str,
) -> PutOptions {
let mut opts = PutOptions {
tags: config.default_tags.clone(),
auto_tag: config.auto_tag,
extract_dates: config.extract_dates,
extract_triplets: config.extract_triplets,
..PutOptions::default()
};
if let Some(scope) = config.scope.as_deref() {
opts.uri = Some(scope.to_string());
}
let metadata = MemvidFrameMetadata {
schema_version: 1,
kind,
conversation_id: conversation_id.to_string(),
chat_role: chat_role.to_string(),
dedup_key: dedup_key_hex.to_string(),
scope: config.scope.clone(),
};
opts.extra_metadata = metadata.into_map();
opts
}