use crate::error::Result;
use crate::framework_events::MemoryEvent;
use crate::hyperdim::HVec10240;
use crate::metadata_filter::MetadataFilter;
use crate::singularity::ConceptBuilder;
use std::collections::HashMap;
use tracing::instrument;
impl crate::framework::ChaoticSemanticFramework {
#[instrument(err, skip(self, id, vector))]
pub async fn inject_concept_with_ttl(
&self,
id: impl Into<String>,
vector: HVec10240,
ttl_seconds: u64,
) -> Result<()> {
let id = id.into();
Self::validate_concept_id(&id)?;
let concept = ConceptBuilder::new(id.clone())
.with_vector(vector)
.with_ttl(ttl_seconds)
.build()?;
{
let mut sing = self.singularity.write().await;
let ns = self.namespace.read().await;
sing.inject(&ns, concept.clone())?;
}
if let Some(ref persistence) = self.persistence {
let p_start = std::time::Instant::now();
let ns = self.namespace.read().await;
persistence.save_concept(&ns, &concept).await?;
self.metrics.observe_persist_latency_ms(
u64::try_from(p_start.elapsed().as_millis()).unwrap_or(u64::MAX),
"save",
);
}
self.metrics.inc_concepts_injected(1);
self.emit_event(MemoryEvent::ConceptInjected {
id,
timestamp: concept.modified_at,
})
.await;
Ok(())
}
#[instrument(err, skip(self, text))]
pub async fn inject_text_with_ttl(&self, id: &str, text: &str, ttl_seconds: u64) -> Result<()> {
let embedding = self.embedding_provider.embed(text).await?;
let vector = self
.embedding_provider
.project(&embedding, &self.projection);
self.inject_concept_with_ttl(id, vector, ttl_seconds).await
}
#[instrument(err, skip(self))]
pub async fn purge_expired(&self) -> Result<usize> {
#[cfg(not(target_arch = "wasm32"))]
let start = std::time::Instant::now();
let count = {
let mut sing = self.singularity.write().await;
let ns = self.namespace.read().await;
sing.purge_expired(&ns)
};
if count > 0 {
#[cfg(not(target_arch = "wasm32"))]
let duration_ms = start.elapsed().as_millis() as u64;
#[cfg(target_arch = "wasm32")]
let duration_ms = 0;
self.emit_chaotic_event(
crate::framework_events_ce::ChaoticEvent::MemoryConsolidated {
episode_count: count,
duration_ms,
},
)
.await;
}
Ok(count)
}
pub async fn inject_text(&self, id: &str, text: &str) -> Result<()> {
let embedding = self.embedding_provider.embed(text).await?;
let vector = self
.embedding_provider
.project(&embedding, &self.projection);
self.inject_concept(id, vector).await
}
pub async fn inject_text_with_metadata(
&self,
id: &str,
text: &str,
metadata: HashMap<String, serde_json::Value>,
) -> Result<()> {
let embedding = self.embedding_provider.embed(text).await?;
let vector = self
.embedding_provider
.project(&embedding, &self.projection);
self.inject_concept_with_metadata(id, vector, metadata)
.await
}
pub async fn probe_text(&self, query: &str, top_k: usize) -> Result<Vec<(String, f32)>> {
let embedding = self.embedding_provider.embed(query).await?;
let vector = self
.embedding_provider
.project(&embedding, &self.projection);
self.probe(vector, top_k).await
}
pub async fn probe_text_filtered(
&self,
query: &str,
top_k: usize,
filter: &MetadataFilter,
) -> Result<Vec<(String, f32)>> {
let embedding = self.embedding_provider.embed(query).await?;
let vector = self
.embedding_provider
.project(&embedding, &self.projection);
self.probe_filtered(&vector, top_k, filter).await
}
pub async fn query_in_session(
&self,
query: &str,
session_id: &str,
top_k: usize,
) -> Result<Vec<(String, f32)>> {
let filter = MetadataFilter::eq("session_id", session_id);
self.probe_text_filtered(query, top_k, &filter).await
}
}