Skip to content
Merged

Dev #18

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions CHANGELOG.md

This file was deleted.

4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions benchmark/cortexadb_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def run_benchmark(
db = CortexaDB.open(db_path, dimension=len(embeddings[0]))

for i, emb in enumerate(embeddings):
db.remember(f"memory_{i}", embedding=emb)
db.add(f"memory_{i}", embedding=emb)

# Force checkpoint to flush
db.checkpoint()
Expand All @@ -108,7 +108,7 @@ def run_benchmark(
# === WARMUP ===
print(f"Warming up with {warmup_queries} queries...")
for i in range(warmup_queries):
_ = db._inner.ask_embedding(
_ = db._inner.search_embedding(
embedding=queries[i % len(queries)], top_k=top_k
)

Expand All @@ -120,7 +120,7 @@ def run_benchmark(
query = queries[i % len(queries)]

start = time.perf_counter()
hits = db._inner.ask_embedding(embedding=query, top_k=top_k)
hits = db._inner.search_embedding(embedding=query, top_k=top_k)
elapsed = (time.perf_counter() - start) * 1000 # ms

latencies.append(elapsed)
Expand Down Expand Up @@ -151,7 +151,7 @@ def run_benchmark(
exact_ids = exact_search(embeddings, query, top_k)

# Get HNSW results
hits = db._inner.ask_embedding(embedding=query, top_k=top_k)
hits = db._inner.search_embedding(embedding=query, top_k=top_k)
hnsw_ids = [hit.id for hit in hits]

# Calculate recall
Expand Down
2 changes: 1 addition & 1 deletion crates/cortexadb-core/benches/storage_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn bench_ingestion(c: &mut Criterion) {

c.bench_function("ingest_single_memory", |b| {
b.iter(|| {
db.remember(embedding.clone(), None).unwrap();
db.add(embedding.clone(), None).unwrap();
})
});
}
Expand Down
2 changes: 1 addition & 1 deletion crates/cortexadb-core/src/bin/manual_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
store.add_edge(MemoryId(1), MemoryId(2), "relates_to".to_string())?;

let mut options = QueryOptions::with_top_k(5);
options.namespace = Some("agent1".to_string());
options.collection = Some("agent1".to_string());

let out = store.query("rust", options, &DemoEmbedder)?;

Expand Down
4 changes: 2 additions & 2 deletions crates/cortexadb-core/src/bin/startup_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
for i in 0..entry_count {
let embedding: Vec<f32> =
(0..vector_dim).map(|d| ((i * 7 + d * 13) % 100) as f32 / 100.0).collect();
db.remember(embedding, None)?;
db.add(embedding, None)?;
}
}
let seed_elapsed = seed_start.elapsed();
Expand Down Expand Up @@ -105,7 +105,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
for i in 0..tail_count {
let embedding: Vec<f32> =
(0..vector_dim).map(|d| ((i * 11 + d * 3) % 100) as f32 / 100.0).collect();
db.remember(embedding, None)?;
db.add(embedding, None)?;
}
}

Expand Down
14 changes: 7 additions & 7 deletions crates/cortexadb-core/src/bin/sync_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
for i in 0..cfg.ops {
let entry = MemoryEntry::new(
MemoryId(i),
cfg.namespace.clone(),
cfg.collection.clone(),
format!("bench_mem_{}", i).into_bytes(),
1_700_000_000 + i,
)
Expand Down Expand Up @@ -76,7 +76,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
struct BenchConfig {
ops: u64,
vector_dim: usize,
namespace: String,
collection: String,
data_dir: PathBuf,
policy: SyncPolicy,
}
Expand All @@ -85,7 +85,7 @@ impl BenchConfig {
fn from_args(args: Vec<String>) -> Result<Self, Box<dyn std::error::Error>> {
let mut ops: u64 = 20_000;
let mut vector_dim: usize = 3;
let mut namespace = "bench".to_string();
let mut collection = "bench".to_string();
let mut data_dir = std::env::temp_dir().join("cortexadb_sync_bench");

let mut mode = "strict".to_string();
Expand All @@ -104,9 +104,9 @@ impl BenchConfig {
i += 1;
vector_dim = args.get(i).ok_or("missing value for --vector-dim")?.parse()?;
}
"--namespace" => {
"--collection" => {
i += 1;
namespace = args.get(i).ok_or("missing value for --namespace")?.clone();
collection = args.get(i).ok_or("missing value for --collection")?.clone();
}
"--data-dir" => {
i += 1;
Expand Down Expand Up @@ -151,7 +151,7 @@ impl BenchConfig {
_ => return Err(format!("invalid mode: {} (use strict|batch|async)", mode).into()),
};

Ok(Self { ops, vector_dim, namespace, data_dir, policy })
Ok(Self { ops, vector_dim, collection, data_dir, policy })
}
}

Expand All @@ -169,7 +169,7 @@ fn print_help() {
--mode strict|batch|async\n\
--ops <u64> (default: 20000)\n\
--vector-dim <usize> (default: 3)\n\
--namespace <string> (default: bench)\n\
--collection <string> (default: bench)\n\
--data-dir <path> (default: /tmp/cortexadb_sync_bench)\n\
--batch-max-ops <usize> (default: 64)\n\
--batch-max-delay-ms <u64> (default: 25)\n\
Expand Down
10 changes: 5 additions & 5 deletions crates/cortexadb-core/src/core/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub enum Command {
/// Insert or update a memory entry
InsertMemory(MemoryEntry),
/// Delete a memory entry by ID
DeleteMemory(MemoryId),
Delete(MemoryId),
/// Add an edge between two memories with a relation type
AddEdge { from: MemoryId, to: MemoryId, relation: String },
/// Remove an edge between two memories
Expand All @@ -20,8 +20,8 @@ impl Command {
Command::InsertMemory(entry)
}

pub fn delete_memory(id: MemoryId) -> Self {
Command::DeleteMemory(id)
pub fn delete(id: MemoryId) -> Self {
Command::Delete(id)
}

pub fn add_edge(from: MemoryId, to: MemoryId, relation: String) -> Self {
Expand Down Expand Up @@ -49,9 +49,9 @@ mod tests {

#[test]
fn test_delete_command() {
let cmd = Command::delete_memory(MemoryId(1));
let cmd = Command::delete(MemoryId(1));
match cmd {
Command::DeleteMemory(id) => assert_eq!(id, MemoryId(1)),
Command::Delete(id) => assert_eq!(id, MemoryId(1)),
_ => panic!("Expected DeleteMemory"),
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The panic message in this test still says "Expected DeleteMemory" even though the variant is now Command::Delete. Updating the message will make failures less confusing.

Suggested change
_ => panic!("Expected DeleteMemory"),
_ => panic!("Expected Delete"),

Copilot uses AI. Check for mistakes.
}
}
Expand Down
8 changes: 4 additions & 4 deletions crates/cortexadb-core/src/core/memory_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub struct MemoryId(pub u64);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MemoryEntry {
pub id: MemoryId,
pub namespace: String,
pub collection: String,
pub content: Vec<u8>,
pub embedding: Option<Vec<f32>>,
pub metadata: HashMap<String, String>,
Expand All @@ -18,10 +18,10 @@ pub struct MemoryEntry {
}

impl MemoryEntry {
pub fn new(id: MemoryId, namespace: String, content: Vec<u8>, created_at: u64) -> Self {
pub fn new(id: MemoryId, collection: String, content: Vec<u8>, created_at: u64) -> Self {
Self {
id,
namespace,
collection,
content,
embedding: None,
metadata: HashMap::new(),
Expand Down Expand Up @@ -50,7 +50,7 @@ mod tests {
let entry =
MemoryEntry::new(MemoryId(1), "default".to_string(), b"test content".to_vec(), 1000);
assert_eq!(entry.id, MemoryId(1));
assert_eq!(entry.namespace, "default");
assert_eq!(entry.collection, "default");
assert_eq!(entry.importance, 0.0);
assert_eq!(entry.embedding, None);
}
Expand Down
44 changes: 22 additions & 22 deletions crates/cortexadb-core/src/core/state_machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ pub enum StateMachineError {
MemoryNotFound(MemoryId),
#[error("Invalid state: {0}")]
InvalidState(String),
#[error("Cross-namespace edge is not allowed: from={from:?} ({from_ns}) to={to:?} ({to_ns})")]
CrossNamespaceEdge { from: MemoryId, from_ns: String, to: MemoryId, to_ns: String },
#[error("Cross-collection edge is not allowed: from={from:?} ({from_col}) to={to:?} ({to_col})")]
CrossCollectionEdge { from: MemoryId, from_col: String, to: MemoryId, to_col: String },
}

pub type Result<T> = std::result::Result<T, StateMachineError>;
Expand Down Expand Up @@ -44,7 +44,7 @@ impl StateMachine {
pub fn apply_command(&mut self, cmd: Command) -> Result<()> {
match cmd {
Command::InsertMemory(entry) => self.insert_memory(entry),
Command::DeleteMemory(id) => self.delete_memory(id),
Command::Delete(id) => self.delete(id),
Command::AddEdge { from, to, relation } => self.add_edge(from, to, relation),
Command::RemoveEdge { from, to } => self.remove_edge(from, to),
}
Expand Down Expand Up @@ -83,7 +83,7 @@ impl StateMachine {
}

/// Delete a memory entry and its edges
pub fn delete_memory(&mut self, id: MemoryId) -> Result<()> {
pub fn delete(&mut self, id: MemoryId) -> Result<()> {
if !self.memories.contains_key(&id) {
return Err(StateMachineError::MemoryNotFound(id));
}
Expand All @@ -109,12 +109,12 @@ impl StateMachine {
let from_entry = self.memories.get(&from).ok_or(StateMachineError::MemoryNotFound(from))?;
let to_entry = self.memories.get(&to).ok_or(StateMachineError::MemoryNotFound(to))?;

if from_entry.namespace != to_entry.namespace {
return Err(StateMachineError::CrossNamespaceEdge {
if from_entry.collection != to_entry.collection {
return Err(StateMachineError::CrossCollectionEdge {
from,
from_ns: from_entry.namespace.clone(),
from_col: from_entry.collection.clone(),
to,
to_ns: to_entry.namespace.clone(),
to_col: to_entry.collection.clone(),
});
}

Expand All @@ -129,10 +129,10 @@ impl StateMachine {
Ok(())
}

pub fn namespace_of(&self, id: MemoryId) -> Result<&str> {
pub fn collection_of(&self, id: MemoryId) -> Result<&str> {
self.memories
.get(&id)
.map(|e| e.namespace.as_str())
.map(|e| e.collection.as_str())
.ok_or(StateMachineError::MemoryNotFound(id))
}

Expand All @@ -149,10 +149,10 @@ impl StateMachine {
self.memories.get(&id).ok_or(StateMachineError::MemoryNotFound(id))
}

/// Get all memories in a namespace
pub fn get_memories_in_namespace(&self, namespace: &str) -> Vec<&MemoryEntry> {
/// Get all memories in a collection
pub fn get_memories_in_collection(&self, collection: &str) -> Vec<&MemoryEntry> {
let mut entries: Vec<_> =
self.memories.values().filter(|e| e.namespace == namespace).collect();
self.memories.values().filter(|e| e.collection == collection).collect();
entries.sort_by_key(|e| e.id);
entries
}
Expand Down Expand Up @@ -210,10 +210,10 @@ impl Default for StateMachine {
mod tests {
use super::*;

fn create_test_entry(id: u64, namespace: &str, timestamp: u64) -> MemoryEntry {
fn create_test_entry(id: u64, collection: &str, timestamp: u64) -> MemoryEntry {
MemoryEntry::new(
MemoryId(id),
namespace.to_string(),
collection.to_string(),
format!("content_{}", id).into_bytes(),
timestamp,
)
Expand All @@ -238,13 +238,13 @@ mod tests {
}

#[test]
fn test_delete_memory() {
fn test_delete() {
let mut sm = StateMachine::new();
let entry = create_test_entry(1, "default", 1000);
sm.insert_memory(entry).unwrap();
assert_eq!(sm.len(), 1);

sm.delete_memory(MemoryId(1)).unwrap();
sm.delete(MemoryId(1)).unwrap();
assert_eq!(sm.len(), 0);
assert!(sm.get_memory(MemoryId(1)).is_err());
}
Expand Down Expand Up @@ -309,13 +309,13 @@ mod tests {
}

#[test]
fn test_namespace_filtering() {
fn test_collection_filtering() {
let mut sm = StateMachine::new();
sm.insert_memory(create_test_entry(1, "ns1", 1000)).unwrap();
sm.insert_memory(create_test_entry(2, "ns2", 1000)).unwrap();
sm.insert_memory(create_test_entry(3, "ns1", 1000)).unwrap();

let ns1_entries = sm.get_memories_in_namespace("ns1");
let ns1_entries = sm.get_memories_in_collection("ns1");
assert_eq!(ns1_entries.len(), 2);
assert_eq!(ns1_entries[0].id, MemoryId(1));
assert_eq!(ns1_entries[1].id, MemoryId(3));
Expand Down Expand Up @@ -365,20 +365,20 @@ mod tests {
sm.add_edge(MemoryId(1), MemoryId(2), "refers".to_string()).unwrap();

// Delete memory 2
sm.delete_memory(MemoryId(2)).unwrap();
sm.delete(MemoryId(2)).unwrap();

// Edge should be cleaned up
let neighbors = sm.get_neighbors(MemoryId(1)).unwrap();
assert!(neighbors.is_empty());
}

#[test]
fn test_cross_namespace_edge_rejected() {
fn test_cross_collection_edge_rejected() {
let mut sm = StateMachine::new();
sm.insert_memory(create_test_entry(1, "ns1", 1000)).unwrap();
sm.insert_memory(create_test_entry(2, "ns2", 1000)).unwrap();

let result = sm.add_edge(MemoryId(1), MemoryId(2), "bad".to_string());
assert!(matches!(result, Err(StateMachineError::CrossNamespaceEdge { .. })));
assert!(matches!(result, Err(StateMachineError::CrossCollectionEdge { .. })));
}
}
Loading