Skip to content

Commit 2a23742

Browse files
committed
Fixed api python and rust
1 parent c5fd48e commit 2a23742

3 files changed

Lines changed: 38 additions & 15 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,15 @@ db.load("document.pdf", strategy="recursive")
214214
| `.delete_memory(id)` | Permanently removes a memory and updates all indexes. |
215215
| `.compact()` | Reclaims space by removing deleted entries from disk. |
216216
| `.checkpoint()` | Truncates the WAL and snapshots the current state for fast startup. |
217+
| `.export_replay(path)` | Exports current state to a replay log (NDJSON). |
218+
| `CortexaDB.replay(log_path, db_path)` | Rebuilds a database from a replay log. |
217219

218220
### Configuration Options
219221
When calling `CortexaDB.open()`, you can tune the behavior:
220222
- `sync`: `"strict"` (safest), `"async"` (fastest), or `"batch"` (balanced).
221223
- `max_entries`: Limits the total number of memories (triggers auto-eviction).
224+
- `max_bytes`: Limits total stored bytes (triggers auto-eviction).
225+
- `index_mode`: `"exact"`, `"hnsw"`, or an HNSW config dict.
222226
- `record`: Path to a log file for capturing the entire session for replay.
223227

224228
---

crates/cortexadb-py/cortexadb/client.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ def __init__(
153153
embedder: t.Optional[Embedder] = None,
154154
sync: str = "strict",
155155
max_entries: t.Optional[int] = None,
156-
index_mode: str = "exact",
156+
max_bytes: t.Optional[int] = None,
157+
index_mode: t.Union[str, t.Dict[str, t.Any]] = "exact",
157158
_recorder: t.Optional[ReplayWriter] = None,
158159
):
159160
self._embedder = embedder
@@ -164,6 +165,7 @@ def __init__(
164165
dimension=dimension,
165166
sync=sync,
166167
max_entries=max_entries,
168+
max_bytes=max_bytes,
167169
index_mode=index_mode,
168170
)
169171
except Exception as e:
@@ -180,7 +182,8 @@ def open(
180182
embedder: t.Optional[Embedder] = None,
181183
sync: str = "strict",
182184
max_entries: t.Optional[int] = None,
183-
index_mode: str = "exact",
185+
max_bytes: t.Optional[int] = None,
186+
index_mode: t.Union[str, t.Dict[str, t.Any]] = "exact",
184187
record: t.Optional[str] = None,
185188
) -> "CortexaDB":
186189
"""
@@ -196,6 +199,8 @@ def open(
196199
inferred from ``embedder.dimension`` automatically.
197200
sync: Write durability policy: ``"strict"`` (default),
198201
``"async"``, or ``"batch"``.
202+
max_entries: Optional entry-count limit for automatic eviction.
203+
max_bytes: Optional byte-size limit for automatic eviction.
199204
index_mode: Search index mode: ``"exact"`` (default) or ``"hnsw"``.
200205
Can also be a dict with HNSW parameters.
201206
record: Optional path to a replay log file. When set, every write
@@ -225,6 +230,7 @@ def open(
225230
embedder=embedder,
226231
sync=sync,
227232
max_entries=max_entries,
233+
max_bytes=max_bytes,
228234
index_mode=index_mode,
229235
_recorder=recorder,
230236
)
@@ -311,6 +317,11 @@ def replay(
311317
db._inner.checkpoint()
312318
except Exception:
313319
pass # non-fatal on fresh DB
320+
elif op == "compact":
321+
try:
322+
db._inner.compact()
323+
except Exception:
324+
pass # non-fatal on fresh DB
314325

315326
return db
316327

@@ -680,20 +691,23 @@ def export_replay(self, log_path: str) -> None:
680691
while found < target and checked < target * 4:
681692
try:
682693
mem = self._inner.get(candidate)
683-
# Retrieve the stored embedding via ask with dimension probe
684-
hits = self._inner.ask_in_namespace(
685-
namespace=mem.namespace,
686-
embedding=mem.embedding
687-
if hasattr(mem, "embedding")
688-
else [0.0] * dim,
689-
top_k=1,
690-
)
694+
embedding = getattr(mem, "embedding", None)
695+
if not embedding:
696+
candidate += 1
697+
checked += 1
698+
continue
699+
content = getattr(mem, "content", b"")
700+
if isinstance(content, bytes):
701+
text = content.decode("utf-8", errors="replace")
702+
else:
703+
text = str(content)
704+
metadata = dict(mem.metadata) if hasattr(mem, "metadata") else None
691705
writer.record_remember(
692706
id=mem.id,
693-
text=mem.content if hasattr(mem, "content") else "",
694-
embedding=mem.embedding if hasattr(mem, "embedding") else [],
707+
text=text,
708+
embedding=embedding,
695709
namespace=mem.namespace,
696-
metadata=None,
710+
metadata=metadata,
697711
)
698712
found += 1
699713
except Exception:

crates/cortexadb-py/src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ impl PyHit {
146146
/// Attributes:
147147
/// id (int): Memory identifier.
148148
/// namespace (str): Namespace this memory belongs to.
149+
/// embedding (list[float] | None): Stored embedding vector.
149150
/// metadata (dict[str, str]): Key-value metadata.
150151
/// created_at (int): Unix timestamp when the memory was created.
151152
/// importance (float): Importance score.
@@ -163,6 +164,8 @@ struct PyMemory {
163164
importance: f32,
164165
#[pyo3(get)]
165166
content: Vec<u8>,
167+
#[pyo3(get)]
168+
embedding: Option<Vec<f32>>,
166169
metadata_inner: HashMap<String, String>,
167170
}
168171

@@ -259,14 +262,15 @@ impl PyCortexaDB {
259262
/// mismatches an existing database.
260263
#[staticmethod]
261264
#[pyo3(
262-
text_signature = "(path, *, dimension, sync='strict', index_mode='exact', max_entries=None)"
265+
text_signature = "(path, *, dimension, sync='strict', index_mode='exact', max_entries=None, max_bytes=None)"
263266
)]
264267
fn open(
265268
path: &str,
266269
dimension: usize,
267270
sync: String,
268271
index_mode: Bound<'_, PyAny>,
269272
max_entries: Option<usize>,
273+
max_bytes: Option<u64>,
270274
) -> PyResult<Self> {
271275
if dimension == 0 {
272276
return Err(CortexaDBConfigError::new_err("dimension must be > 0"));
@@ -294,7 +298,7 @@ impl PyCortexaDB {
294298
// few entries. Disabling checkpoint avoids WAL truncation on Drop;
295299
// the user can still call checkpoint() explicitly when safe.
296300
checkpoint_policy: CheckpointPolicy::Disabled,
297-
capacity_policy: CapacityPolicy::new(max_entries, None),
301+
capacity_policy: CapacityPolicy::new(max_entries, max_bytes),
298302
index_mode,
299303
};
300304

@@ -457,6 +461,7 @@ impl PyCortexaDB {
457461
created_at: entry.created_at,
458462
importance: entry.importance,
459463
content: entry.content.clone(),
464+
embedding: entry.embedding.clone(),
460465
metadata_inner: entry.metadata.clone(),
461466
})
462467
}

0 commit comments

Comments
 (0)