Summary
brainctl vec reindex crashes immediately with an ImportError for every user. The command imports sample_db_embedding_widths from agentmemory.embeddings, but that function is not defined anywhere in the codebase.
This matters because vec reindex is the documented migration path when switching embedding models — pyproject.toml (the [vec] extra docstring) instructs: "When changing models on an existing brain.db, run brainctl vec reindex --model <name> to migrate the vector index." That path is currently dead.
Environment
- brainctl
main @ c634808 (version = "2.8.0"); also reproduces on the PyPI 2.8.0 wheel
brainctl[vec] installed, sqlite-vec present, Ollama reachable
Reproduction
brainctl init
brainctl memory add "the deploy key rotates every 90 days" --category ops
brainctl vec reindex
Result:
{
"error": "ImportError: cannot import name 'sample_db_embedding_widths' from 'agentmemory.embeddings' (.../agentmemory/embeddings.py)"
}
Root cause
src/agentmemory/_impl.py:7855 (inside cmd_vec_reindex) imports the symbol:
from agentmemory.embeddings import (
...
sample_db_embedding_widths,
...
)
and calls it at _impl.py:7873:
width_probe = sample_db_embedding_widths(db_vec, sample_size=8)
But grep -rn "def sample_db_embedding_widths" src returns nothing — the function is referenced but never implemented. The import is at the top of the function body, so the command fails before doing any work.
The surrounding comment (_impl.py:7868-7872, "audit H4") makes the intended contract clear: probe the actual byte width of a sample of stored embeddings and cross-check it against the dim declared in the vec_memories DDL, so the destructive DROP+CREATE refuses to run on a corrupted/mixed-width index unless --force is passed.
The callsite expects a dict with keys: ok, sample_count, consistent, declared_dim, observed_dims, message.
Suggested fix
Implement sample_db_embedding_widths(conn, sample_size=8) in embeddings.py next to get_db_embedding_dim. It should:
- read up to
sample_size rows from vec_memories (SELECT embedding ...),
- compute each vector's float width as
len(blob) // 4 (float32),
- compare the observed width(s) against
get_db_embedding_dim(conn),
- return
{"ok": False, "sample_count": 0, ...} when the table is absent/unreadable (so the reindex guard treats it as "nothing to check" and proceeds to build a fresh index),
- return
consistent=False only when sampled rows disagree with each other or with the declared dim.
I have a working implementation + unit tests and will open a PR.
Summary
brainctl vec reindexcrashes immediately with anImportErrorfor every user. The command importssample_db_embedding_widthsfromagentmemory.embeddings, but that function is not defined anywhere in the codebase.This matters because
vec reindexis the documented migration path when switching embedding models —pyproject.toml(the[vec]extra docstring) instructs: "When changing models on an existing brain.db, runbrainctl vec reindex --model <name>to migrate the vector index." That path is currently dead.Environment
main@c634808(version = "2.8.0"); also reproduces on the PyPI2.8.0wheelbrainctl[vec]installed, sqlite-vec present, Ollama reachableReproduction
brainctl init brainctl memory add "the deploy key rotates every 90 days" --category ops brainctl vec reindexResult:
{ "error": "ImportError: cannot import name 'sample_db_embedding_widths' from 'agentmemory.embeddings' (.../agentmemory/embeddings.py)" }Root cause
src/agentmemory/_impl.py:7855(insidecmd_vec_reindex) imports the symbol:and calls it at
_impl.py:7873:But
grep -rn "def sample_db_embedding_widths" srcreturns nothing — the function is referenced but never implemented. The import is at the top of the function body, so the command fails before doing any work.The surrounding comment (
_impl.py:7868-7872, "audit H4") makes the intended contract clear: probe the actual byte width of a sample of stored embeddings and cross-check it against the dim declared in thevec_memoriesDDL, so the destructive DROP+CREATE refuses to run on a corrupted/mixed-width index unless--forceis passed.The callsite expects a dict with keys:
ok,sample_count,consistent,declared_dim,observed_dims,message.Suggested fix
Implement
sample_db_embedding_widths(conn, sample_size=8)inembeddings.pynext toget_db_embedding_dim. It should:sample_sizerows fromvec_memories(SELECT embedding ...),len(blob) // 4(float32),get_db_embedding_dim(conn),{"ok": False, "sample_count": 0, ...}when the table is absent/unreadable (so the reindex guard treats it as "nothing to check" and proceeds to build a fresh index),consistent=Falseonly when sampled rows disagree with each other or with the declared dim.I have a working implementation + unit tests and will open a PR.