Skip to content

Commit 252553c

Browse files
committed
Update docs and tests
1 parent fd0c7ef commit 252553c

7 files changed

Lines changed: 61 additions & 54 deletions

File tree

crates/cortexadb-py/cortexadb/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .client import CortexaDB, Namespace
1+
from .client import CortexaDB, Collection
22
from ._cortexadb import (
33
Hit,
44
Memory,
@@ -15,7 +15,7 @@
1515

1616
__all__ = [
1717
"CortexaDB",
18-
"Namespace",
18+
"Collection",
1919
"Hit",
2020
"Memory",
2121
"Stats",

crates/cortexadb-py/cortexadb/client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def replay(cls, log_path: str, db_path: str, **kwargs) -> "CortexaDB":
208208
text=op.get("text"),
209209
vector=op.get("embedding"),
210210
metadata=op.get("metadata"),
211-
collection=op.get("namespace", "default")
211+
collection=op.get("collection") or op.get("namespace", "default")
212212
)
213213
id_map[op.get("id")] = new_id
214214
report["exported"] += 1
@@ -246,7 +246,7 @@ def add(self, text=None, vector=None, metadata=None, collection=None, **kwargs)
246246
content = text or ""
247247
mid = self._inner.remember_embedding(vec, metadata=metadata, collection=collection, content=content)
248248
if self._recorder:
249-
self._recorder.record_remember(id=mid, text=content, embedding=vec, namespace=collection, metadata=metadata)
249+
self._recorder.record_remember(id=mid, text=content, embedding=vec, collection=collection, metadata=metadata)
250250
return mid
251251

252252
def search(
@@ -331,7 +331,7 @@ def export_replay(self, path: str):
331331
id=mem.id,
332332
text=bytes(mem.content).decode("utf-8") if mem.content else "",
333333
embedding=mem.embedding,
334-
namespace=mem.collection,
334+
collection=mem.collection,
335335
metadata=mem.metadata
336336
)
337337
report["exported"] += 1

crates/cortexadb-py/cortexadb/replay.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
1717
Lines 2..N — operation records (one JSON object per line):
1818
19-
{"op": "remember", "id": 1, "text": "...", "embedding": [...], "namespace": "default", "metadata": null}
19+
{"op": "remember", "id": 1, "text": "...", "embedding": [...], "collection": "default", "metadata": null}
2020
{"op": "connect", "from_id": 1, "to_id": 2, "relation": "caused_by"}
2121
{"op": "compact"}
2222
@@ -56,7 +56,7 @@ class ReplayWriter:
5656
Example::
5757
5858
writer = ReplayWriter("session.log", dimension=128, sync="strict")
59-
writer.record_remember(id=1, text="hello", embedding=[...], namespace="default")
59+
writer.record_remember(id=1, text="hello", embedding=[...], collection="default")
6060
writer.close()
6161
"""
6262

@@ -84,7 +84,7 @@ def record_remember(
8484
id: int,
8585
text: str,
8686
embedding: List[float],
87-
namespace: str,
87+
collection: str,
8888
metadata: Optional[Dict[str, str]],
8989
) -> None:
9090
"""Append a ``remember`` operation."""
@@ -93,7 +93,7 @@ def record_remember(
9393
"id": id,
9494
"text": text,
9595
"embedding": embedding,
96-
"namespace": namespace,
96+
"collection": collection,
9797
"metadata": metadata,
9898
})
9999

crates/cortexadb-py/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ struct PyMemory {
209209
#[pyo3(get)]
210210
collection: String,
211211
#[pyo3(get)]
212+
namespace: String,
213+
#[pyo3(get)]
212214
created_at: u64,
213215
#[pyo3(get)]
214216
importance: f32,
@@ -545,6 +547,7 @@ impl PyCortexaDB {
545547
Ok(PyMemory {
546548
id: entry.id,
547549
collection: entry.namespace.clone(),
550+
namespace: entry.namespace.clone(),
548551
created_at: entry.created_at,
549552
importance: entry.importance,
550553
content: entry.content.clone(),

crates/cortexadb-py/test_smoke.py

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ def test_cortexadb_basic_flow():
2222
mid = db.remember("Hello world", embedding=[1.0, 0.0, 0.0])
2323

2424
# 3. Ask
25-
hits = db.ask("world", embedding=[1.0, 0.0, 0.0])
25+
hits = db.search("world", embedding=[1.0, 0.0, 0.0])
2626
assert len(hits) == 1
2727
assert hits[0].id == mid
2828

2929
# 4. Get full memory
3030
mem = db.get(mid)
31-
assert mem.namespace == "default"
31+
assert mem.collection == "default"
3232
assert mem.id == mid
3333
assert bytes(mem.content).decode("utf-8") == "Hello world"
3434

@@ -56,10 +56,10 @@ def test_cortexadb_namespaces():
5656
id_a = agent_a.remember("I am Agent A", embedding=[1.0, 0.0, 0.0])
5757
agent_b.remember("I am Agent B", embedding=[0.0, 1.0, 0.0])
5858

59-
assert db.get(id_a).namespace == "agent_a"
59+
assert db.get(id_a).collection == "agent_a"
6060

6161
# Test ask filters by namespace using the wrapper
62-
hits_a = agent_a.ask("Agent A", embedding=[1.0, 0.0, 0.0])
62+
hits_a = agent_a.search("Agent A", embedding=[1.0, 0.0, 0.0])
6363
assert len(hits_a) == 1
6464
assert hits_a[0].id == id_a
6565

@@ -125,7 +125,7 @@ def test_open_with_embedder():
125125
# remember without explicit embedding
126126
mid = db.remember("Auto-embedded text")
127127
assert mid > 0
128-
hits = db.ask("Auto-embedded text")
128+
hits = db.search("Auto-embedded text")
129129
assert len(hits) >= 1
130130

131131
def test_open_requires_one_of_dimension_or_embedder():
@@ -144,23 +144,23 @@ def test_ingest_document():
144144
emb = HashEmbedder(dimension=32)
145145
db = CortexaDB.open(DB_PATH, embedder=emb)
146146
long_text = ("The quick brown fox jumps over the lazy dog. " * 30).strip()
147-
ids = db.ingest_document(long_text, chunk_size=100, overlap=20)
147+
ids = db.ingest(long_text, chunk_size=100, overlap=20)
148148
assert len(ids) > 1
149149
assert len(set(ids)) == len(ids) # all IDs unique
150150
assert db.stats().entries == len(ids)
151151

152152
def test_ingest_document_requires_embedder():
153153
db = CortexaDB.open(DB_PATH, dimension=16)
154154
with pytest.raises(CortexaDBError, match="ingest_document"):
155-
db.ingest_document("some text")
155+
db.ingest("some text")
156156

157157
def test_namespace_auto_embed():
158158
emb = HashEmbedder(dimension=32)
159159
db = CortexaDB.open(DB_PATH, embedder=emb)
160160
ns = db.namespace("agent_a")
161161
mid = ns.remember("I am agent A")
162-
assert db.get(mid).namespace == "agent_a"
163-
hits = ns.ask("agent A")
162+
assert db.get(mid).collection == "agent_a"
163+
hits = ns.search("agent A")
164164
assert any(h.id == mid for h in hits)
165165

166166
# Namespace Model
@@ -175,8 +175,8 @@ def test_namespace_isolation():
175175
mid_a = agent_a.remember("I am agent A, secret info")
176176
mid_b = agent_b.remember("I am agent B, different info")
177177

178-
hits_a = agent_a.ask("agent A", top_k=10)
179-
hits_b = agent_b.ask("agent B", top_k=10)
178+
hits_a = agent_a.search("agent A", top_k=10)
179+
hits_b = agent_b.search("agent B", top_k=10)
180180

181181
a_ids = {h.id for h in hits_a}
182182
b_ids = {h.id for h in hits_b}
@@ -188,32 +188,32 @@ def test_namespace_isolation():
188188

189189

190190
def test_namespaced_ask_param():
191-
"""db.ask(query, namespaces=[...]) should scope results correctly."""
191+
"""db.search(query, collections=[...]) should scope results correctly."""
192192
emb = HashEmbedder(dimension=32)
193193
db = CortexaDB.open(DB_PATH, embedder=emb)
194194

195-
mid_a = db.remember("Agent A private", namespace="agent_a")
196-
mid_b = db.remember("Agent B private", namespace="agent_b")
197-
mid_s = db.remember("Shared knowledge", namespace="shared")
195+
mid_a = db.remember("Agent A private", collection="agent_a")
196+
mid_b = db.remember("Agent B private", collection="agent_b")
197+
mid_s = db.remember("Shared knowledge", collection="shared")
198198

199-
# Single namespace via namespaces= param
200-
hits = db.ask("knowledge", namespaces=["shared"])
199+
# Single namespace via collections= param
200+
hits = db.search("knowledge", collections=["shared"])
201201
ids = {h.id for h in hits}
202202
assert mid_s in ids
203203
assert mid_a not in ids
204204
assert mid_b not in ids
205205

206206

207207
def test_cross_namespace_fan_out():
208-
"""namespaces=[a, b] should return merged re-ranked results from both."""
208+
"""collections=[a, b] should return merged re-ranked results from both."""
209209
emb = HashEmbedder(dimension=32)
210210
db = CortexaDB.open(DB_PATH, embedder=emb)
211211

212-
mid_a = db.remember("Agent A knowledge", namespace="agent_a")
213-
mid_s = db.remember("Shared knowledge", namespace="shared")
214-
db.remember("Agent B only", namespace="agent_b")
212+
mid_a = db.remember("Agent A knowledge", collection="agent_a")
213+
mid_s = db.remember("Shared knowledge", collection="shared")
214+
db.remember("Agent B only", collection="agent_b")
215215

216-
hits = db.ask("knowledge", namespaces=["agent_a", "shared"], top_k=10)
216+
hits = db.search("knowledge", collections=["agent_a", "shared"], top_k=10)
217217
ids = {h.id for h in hits}
218218

219219
# Both agent_a and shared results must be present.
@@ -222,23 +222,23 @@ def test_cross_namespace_fan_out():
222222

223223

224224
def test_global_ask_returns_all_namespaces():
225-
"""db.ask(query) with no namespaces= should search globally."""
225+
"""db.search(query) with no collections= should search globally."""
226226
emb = HashEmbedder(dimension=32)
227227
db = CortexaDB.open(DB_PATH, embedder=emb)
228228

229-
mid_a = db.remember("Agent A fact", namespace="agent_a")
230-
mid_b = db.remember("Agent B fact", namespace="agent_b")
231-
mid_s = db.remember("Shared fact", namespace="shared")
229+
mid_a = db.remember("Agent A fact", collection="agent_a")
230+
mid_b = db.remember("Agent B fact", collection="agent_b")
231+
mid_s = db.remember("Shared fact", collection="shared")
232232

233-
hits = db.ask("fact", top_k=10)
233+
hits = db.search("fact", top_k=10)
234234
ids = {h.id for h in hits}
235235
assert mid_a in ids
236236
assert mid_b in ids
237237
assert mid_s in ids
238238

239239

240240
def test_readonly_namespace():
241-
"""A readonly namespace should allow ask() but reject remember()."""
241+
"""A readonly namespace should allow search() but reject remember()."""
242242
emb = HashEmbedder(dimension=32)
243243
db = CortexaDB.open(DB_PATH, embedder=emb)
244244

@@ -247,7 +247,7 @@ def test_readonly_namespace():
247247

248248
# Read from a readonly view.
249249
ro = db.namespace("shared", readonly=True)
250-
hits = ro.ask("Public knowledge")
250+
hits = ro.search("Public knowledge")
251251
assert any(h.id == mid for h in hits)
252252

253253
# Writes must be rejected.
@@ -304,14 +304,14 @@ def test_replay_recording_creates_ndjson(cleanup_replay):
304304
def test_replay_round_trip(cleanup_replay):
305305
"""Replaying a log into a new DB should recreate the same memories."""
306306
with CortexaDB.open(DB_PATH, dimension=3, record=LOG_PATH) as db:
307-
mid1 = db.remember("Alpha", embedding=[1.0, 0.0, 0.0], namespace="agent_a")
308-
mid2 = db.remember("Beta", embedding=[0.0, 1.0, 0.0], namespace="agent_b")
307+
mid1 = db.remember("Alpha", embedding=[1.0, 0.0, 0.0], collection="agent_a")
308+
mid2 = db.remember("Beta", embedding=[0.0, 1.0, 0.0], collection="agent_b")
309309

310310
db2 = CortexaDB.replay(LOG_PATH, REPLAY_DB)
311311

312312
assert len(db2) == 2
313313

314-
hits = db2.ask("query", embedding=[1.0, 0.0, 0.0], top_k=2)
314+
hits = db2.search("query", embedding=[1.0, 0.0, 0.0], top_k=2)
315315
texts = {db2.get(h.id).content.decode() if isinstance(db2.get(h.id).content, bytes) else db2.get(h.id).content for h in hits}
316316
assert "Alpha" in texts
317317
assert "Beta" in texts
@@ -332,13 +332,13 @@ def test_replay_connect_id_mapping(cleanup_replay):
332332
def test_replay_namespace_preserved(cleanup_replay):
333333
"""Replay should preserve original namespaces."""
334334
with CortexaDB.open(DB_PATH, dimension=3, record=LOG_PATH) as db:
335-
db.remember("In A", embedding=[1.0, 0.0, 0.0], namespace="agent_a")
336-
db.remember("In B", embedding=[0.0, 1.0, 0.0], namespace="agent_b")
335+
db.remember("In A", embedding=[1.0, 0.0, 0.0], collection="agent_a")
336+
db.remember("In B", embedding=[0.0, 1.0, 0.0], collection="agent_b")
337337

338338
db2 = CortexaDB.replay(LOG_PATH, REPLAY_DB)
339339

340-
hits_a = db2.ask("query", embedding=[1.0, 0.0, 0.0], namespaces=["agent_a"])
341-
hits_b = db2.ask("query", embedding=[0.0, 1.0, 0.0], namespaces=["agent_b"])
340+
hits_a = db2.search("query", embedding=[1.0, 0.0, 0.0], collections=["agent_a"])
341+
hits_b = db2.search("query", embedding=[0.0, 1.0, 0.0], collections=["agent_b"])
342342

343343
assert len(hits_a) == 1
344344
assert len(hits_b) == 1
@@ -457,14 +457,14 @@ def test_hybrid_use_graph():
457457
db.connect(id1, id2, "links_to")
458458

459459
# Vector only: expects id1 with high score, id2 with score ~0
460-
hits_normal = db.ask("test", embedding=[1.0, 0.0], top_k=2)
460+
hits_normal = db.search("test", embedding=[1.0, 0.0], top_k=2)
461461
assert hits_normal[0].id == id1
462462
assert hits_normal[1].id == id2
463463
assert hits_normal[0].score > 0.9
464464
assert hits_normal[1].score <= 0.501
465465

466466
# Graph mixed query: id2 gets pulled up via id1's edge (score * 0.9)
467-
hits_graph = db.ask("test", embedding=[1.0, 0.0], top_k=2, use_graph=True)
467+
hits_graph = db.search("test", embedding=[1.0, 0.0], top_k=2, use_graph=True)
468468
assert hits_graph[0].id == id1
469469
assert hits_graph[1].id == id2
470470
# The score of id2 should be updated because of graph neighbor logic
@@ -475,20 +475,20 @@ def test_hybrid_use_graph_respects_namespaces(monkeypatch):
475475
import cortexadb
476476

477477
db = cortexadb.CortexaDB.open(DB_PATH, dimension=2, sync="strict")
478-
id_a = db.remember("Node A", embedding=[1.0, 0.0], namespace="agent_a")
479-
id_b = db.remember("Node B", embedding=[0.0, 1.0], namespace="agent_b")
478+
id_a = db.remember("Node A", embedding=[1.0, 0.0], collection="agent_a")
479+
id_b = db.remember("Node B", embedding=[0.0, 1.0], collection="agent_b")
480480

481481
def fake_get_neighbors(_mid):
482482
# Simulate an unexpected backend neighbor response across namespaces.
483483
return [(id_b, "forced")]
484484

485485
monkeypatch.setattr(type(db._inner), "get_neighbors", lambda self, mid: fake_get_neighbors(mid))
486486

487-
scoped_hits = db.ask(
487+
scoped_hits = db.search(
488488
"test",
489489
embedding=[1.0, 0.0],
490490
top_k=5,
491-
namespaces=["agent_a"],
491+
collections=["agent_a"],
492492
use_graph=True,
493493
)
494494
scoped_ids = {h.id for h in scoped_hits}
@@ -500,8 +500,8 @@ def test_hybrid_recency_bias():
500500
db = cortexadb.CortexaDB.open(DB_PATH, dimension=2, sync="strict")
501501
id1 = db.remember("Node A", embedding=[1.0, 0.0])
502502

503-
hits_normal = db.ask("test", embedding=[1.0, 0.0], top_k=1)
504-
hits_recent = db.ask("test", embedding=[1.0, 0.0], top_k=1, recency_bias=True)
503+
hits_normal = db.search("test", embedding=[1.0, 0.0], top_k=1)
504+
hits_recent = db.search("test", embedding=[1.0, 0.0], top_k=1, recency_bias=True)
505505

506506
# With exactly 0 delay, the boost is exactly 1.2x.
507507
assert hits_recent[0].score > hits_normal[0].score

crates/cortexadb-py/test_stress.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def test_concurrent_compaction(clean_db_path):
6565
# Delete 300 entries to exceed the 20% threshold in segment 0 (if rotation happened)
6666
# Actually, let's just make sure we have enough deleted entries.
6767
for i in range(300):
68-
db.delete_memory(i + 1) # IDs start at 1
68+
db.delete(i + 1) # IDs start at 1
6969

7070
assert len(db) == 700
7171

docs/mdx-components.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import defaultMdxComponents from 'fumadocs-ui/mdx';
22
import type { MDXComponents } from 'mdx/types';
3+
import { Shield, Zap, TrendingUp } from 'lucide-react';
34

45
export function getMDXComponents(components?: MDXComponents): MDXComponents {
56
return {
67
...defaultMdxComponents,
8+
Shield,
9+
Zap,
10+
TrendingUp,
711
...components,
812
};
913
}

0 commit comments

Comments
 (0)