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.