Semantic Memory Search
POST /api/v1/memory/search retrieves current memories by cosine similarity of
model-generated embeddings. It complements the substring/tag/type query at
/api/v1/memory/query. This endpoint returns scores and model-bound provenance;
it does not use substring matching as a substitute for vector similarity.
Embeddings are generated by the client's configured model service. The database does not call a paid provider or load a model onto the user's machine. Generate both document and query vectors with the same provider, model, immutable model revision and dimensionality. Their semantic quality depends on that model and its task-specific evaluation. The platform verifies identities and vectors, not whether a provider really produced them.
Attach an embedding to current memory#
Create or read a memory through the versioned memory API and preserve its UUID and current revision. Generate a vector from that revision's text, then post:
{
"contract_version": 1,
"scope": {"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},
"idempotency_key": "embedding-request-v1",
"record_id": "11111111-1111-4111-8111-111111111111",
"record_revision": 1,
"space": {
"provider": "fixture",
"model": "fixture-embedding",
"revision": "v1",
"dimensions": 3
},
"vector": [1.0, 0.0, 0.0]
}
Endpoint: POST /api/v1/memory/embeddings. Requires memory_write and an exact
scope grant. This three-dimensional fixture demonstrates the wire contract; it
is not a real language embedding or a benchmark of semantic relevance.
The response is {contract_version: 1, receipt: EmbeddingReceipt}. The receipt
contains the request key, source record UUID/revision, complete model space,
vector_digest, author and commit timestamp. The digest is SHA-256 of the Rust
serializer's JSON representation of the validated float32 vector. Preserve the
returned digest; hashing differently formatted or higher-precision client JSON
may give a different result.
Embedding binding and receipt synchronize the WAL in one atomic batch. The request key is scoped to namespace and authenticated subject, independently of memory-command keys. Identical retries return the original receipt, including after source updates/deletion; they do not recreate an old binding. Changed retries conflict. Vectors are immutable within a record revision and model space, even under another request key. An identical vector under a new key gets a new command receipt while retaining the original binding provenance.
Attachments do not change the memory's content revision. Updating a memory makes
its old embeddings ineligible immediately. Generate and attach an embedding for
the new revision. If the source changes before attachment, the server returns a
revision conflict. Different model spaces can coexist for the same memory;
model migrations require explicitly generating/attaching the new vectors.
Existing anonymous content.embedding values are retained for compatibility but
are not silently assigned a model or searched by this endpoint.
Search by meaning through query embeddings#
Generate the query embedding externally, then post to
POST /api/v1/memory/search using memory_read and the same scope:
{
"contract_version": 1,
"scope": {"project_id":"project","mission_id":null,"agent_id":"agent","visibility":"shared"},
"query": {
"space": {"provider":"fixture","model":"fixture-embedding","revision":"v1","dimensions":3},
"vector": [0.9, 0.1, 0.0],
"limit": 10,
"min_score": 0.0,
"scan_limit": 10000,
"after": null,
"episode_type": null,
"tag": null
}
}
The response remains {contract_version: 1, scope, page}, preserving the 0.4.0
JSON envelope and cosine score semantics. X-Qilbee-Ranking-Version identifies
cosine_exact_v1 without adding fields to that legacy envelope. For text plus vector retrieval, use
the separate experimental hybrid endpoint:
| Page field | Meaning |
|---|---|
hits |
At most limit records ranked by descending cosine similarity, then ascending UUID for deterministic ties |
hits[].record |
Current visible MemoryRecord, including author, revision, payload and validity |
hits[].score |
Cosine similarity in [-1, 1]; a similarity value, not a probability or calibrated confidence |
hits[].embedding |
Original embedding receipt linking model space, vector digest and exact source revision |
scanned_embeddings |
Number of bindings examined in this authorized model-space page, including stale/expired/filtered bindings |
matched_records |
Number of eligible records meeting filters and score threshold in the scanned page, before top-k truncation |
next_after |
Last scanned UUID when another binding remains, otherwise null |
exhaustive |
True only when this request started without a cursor and scanned the whole authorized model space |
No result can come from another tenant, ungranted scope or another subject's private namespace. Missing/mismatched model spaces return an empty page. A shared scope must be granted explicitly to each participating subject. Deleted, expired and stale source revisions are excluded; tag/type filters apply before ranking.
Bounded exact retrieval#
The implementation uses an exact cosine scan of durable vectors in the selected scope and model space, with float64 accumulation for float32 inputs. It does not claim ANN index scale or benchmarked language-model relevance. Each request reads records, integrity indexes and embeddings through one RocksDB snapshot, using one visibility timestamp. Retrieval does not hold the memory mutation lock, so writers can commit while a search runs. A result describes the source revision at that snapshot; it may be superseded immediately afterward. The scan budget bounds work and should be tuned for latency; large indexes need a dedicated ANN/search-index increment.
If next_after is not null, the returned hits are the best within that scanned
page, not a guaranteed global top-k. Continue with that cursor and identical
space/query/filters, then merge page candidates by score and UUID. A continued
request always reports exhaustive: false. Continuations do not hold a snapshot
across requests; concurrent writes can change later pages. Completeness refers
to registered bindings in the selected space, not memories without embeddings.
Validation and errors#
Model identity fields support 1–256 UTF-8 bytes without control characters.
Dimensions are 1–32768, subject to the server's configured ceiling; both document and query vectors must match exactly,
contain only finite float32 values and have nonzero norm. Empty, zero, NaN,
infinite or dimension-mismatched vectors are rejected. Normalization is handled
by cosine computation; callers need not pre-normalize. limit is 1–100,
scan_limit is 1–10000 (default 10000) and min_score is finite in [-1, 1]
(default -1). Vector attachment and search requests reject unknown fields and have a 2097152-byte
(2 MiB) HTTP body limit, including JSON formatting and every field. Other platform
routes retain their 65536-byte limit. See retrieval capacity
for operator configuration, concurrent admission and support for 1536, 3072, 8192
and 32768 dimensions. Vectors are never resized or assigned a model implicitly.
Use the existing platform error envelope. Invalid vectors,
limits or fields return 400; missing/invalid credentials 401; missing capability
or scope 403; absent/expired/deleted attachment source 404; source revision
conflicts or immutable-vector/request-key changes 409; oversized requests 413;
inconsistent stored identities, records, indexes or vector digests 500; and a busy
retrieval admission gate 503 (retrieval_busy). Invalid operator dimension limits
return 400 (embedding_dimension_limit).
A read-only credential cannot attach embeddings. Credential rotation and
revocation retain the existing live authorization behavior.
OpenAPI includes EmbeddingSpace, EmbeddingCommandRequest,
EmbeddingReceipt, SemanticQuery, SemanticHit, SemanticPage and their
response envelopes. Use /docs from a browser on
the Docker host to inspect the complete contract.
Measure retrieval time#
The X-Qilbee-Retrieval-Micros response header measures server wall time spent in
the retrieval method. It excludes authentication, blocking-pool queueing, JSON
serialization, transport and external embedding generation. Measure the client
round trip separately. See the reproducible evaluation workflow
for frozen corpora, graded relevance, category regressions and timing limits.