Skip to content

v0.3.0 — voyage-4 migration

Choose a tag to compare

@supostat supostat released this 15 May 04:52
· 18 commits to main since this release

Embedding-model migration release. Default provider model switches from voyage-code-3 to voyage-4; existing databases keep working but the daemon now refuses to start with a stored vector / configured model mismatch until embeddings are recomputed.

Breaking changes

  • Default embedding model is now voyage-4. Databases populated with voyage-code-3 vectors trip the new [6020] EmbeddingModelMismatch guard at server start. Run `engram reembed` once after upgrading, then restart the daemon.
  • `EmbeddingProvider::embed` trait signature gained an `input_type: Option<&str>` parameter. Internal trait with a single real implementor (Voyage); deterministic test fixtures ignore the value. Pre-1.0 deliberate break — out-of-tree implementors must update their method signature.
  • `EmbeddingCache::{get, insert}` signatures changed to accept `input_type`. Internal API.

Dimension stays at `1024` — `voyage-4` API default matches, on-disk HNSW geometry is unchanged. Within the voyage-4 family (`voyage-4-large` / `voyage-4` / `voyage-4-lite` / `voyage-4-nano`) embeddings share one space, so future in-family switches won't require another reembed.

New features

  • `engram reembed [--force]` CLI recomputes embeddings for every stored memory under the active provider. Replaces vectors in HNSW (delete + insert per memory), writes fresh BLOBs to SQLite with `indexed=true`, clears the in-memory cache at the start, and records the active model in `schema_meta.embedding_model` only when every memory succeeded. Per-memory provider/HNSW failure flips `indexed=0` for retry and the first failure is surfaced to stderr; database write failures abort the run.
  • Server startup guard against silent model drift. `server::run` compares the configured `embedding.model` against `schema_meta.embedding_model` after state init and refuses to start with `[6020]` on mismatch. Bootstrap on an empty marker writes the configured model; a stderr warning fires if memories already exist (legacy upgrade path).
  • `embedding.output_dimension` config knob for Voyage-4 Matryoshka truncation (256 / 512 / 1024 / 2048). Omit to use the API default (1024). Must match `[hnsw].dimension` when set.
  • `EmbeddingCache` keyed by `(text, input_type)` instead of text alone, so a memory stored as a document and a query of the same text no longer collide on a single cache slot.

Migration recipe

```bash

1. update binary (release build)

cargo install --path crates/engram-core --force

or once 0.3.0 hits crates.io: cargo install engram-memory

2. switch the model in your global config

sed -i '' 's/voyage-code-3/voyage-4/' ~/.engram/engram.toml

3. in each project that has memories

cd
engram server # fails fast with [6020] EmbeddingModelMismatch — expected
engram reembed # recomputes every memory with voyage-4
engram server # now starts cleanly
```

Reembed runs at roughly `50ms × 3 fields × N memories` under Voyage API latency. Budget a few minutes for a thousand records. Partial failures (e.g. a transient rate-limit on some rows) leave their `indexed=0` so a rerun retries only the leftovers — `schema_meta` is only updated on a clean run.

Users who want to stay on `voyage-code-3` can set `embedding.model = "voyage-code-3"` in `engram.toml` — the guard compares against the configured model, not against the bundled default.

Notes

  • Error codes 6001-6019 were already in use; this release adds 6020 EmbeddingModelMismatch.
  • Coverage instrumentation (`cargo tarpaulin`) breaks the parallelism overlap windows that two RwLock tests assert on. Both tests now skip cleanly when `ENGRAM_SKIP_TIMING_TESTS=1` is set; local `cargo test` keeps the strict assertion.
  • MCP server entry point no longer runs `main()` on import — `resolveProjectDir` can be imported from tests without spawning the engram binary. Fixes a long-standing `spawn engram ENOENT` in CI environments that don't have the binary on PATH.

Full changelog

See `CHANGELOG.md` in the repository.