Skip to content

Search-side automatic embedding for vector search (@embed counterpart) #1277

Description

@heskew

@embed computes vectors automatically on the write side, but there is no search-side counterpart: querying an HNSW index requires the caller to produce the vector themselves (models.embed(text, { inputType: 'query' })) before calling search. Raised by @dawsontoth while reviewing the 5.1 models docs: HarperFast/documentation#523 (comment: HarperFast/documentation#523 (comment)).

Sketch

Accept query text directly on the vector search descriptor and embed it with the attribute's configured @embed model before the index search, e.g.:

Document.search({
	sort: { attribute: 'embedding', text: 'what is harper?' },
});
  • The attribute's @embed(model: …) declaration already names the right model; the search side would use it with inputType: 'query' (the write-side hook uses 'document'), which matters for models with asymmetric document/query prefixes (e.g. nomic-embed-text).
  • Same shape would apply to threshold conditions ({ attribute, comparator: 'le', value, text }).
  • For attributes indexed HNSW without @embed, there is no model to infer — either reject, or accept an explicit model key on the descriptor.
  • Ships in core alongside the existing @embed/search machinery (resources/models, resources/search.ts), consistent with Add unified model-access API (scope.models) #510's packaging.

Open questions: REST/operations-API exposure (the QUERY body path carries the descriptor through; search_by_conditions mapping would need the text key preserved), and whether embedding latency belongs inside the search call or should stay an explicit caller step for hot paths.

Related: #510 (models API), #1235 (5.1 GA readiness — listed there as a post-GA follow-up), HarperFast/documentation#523 (docs that surfaced the gap).


🤖 Generated with Claude Code

Activity

  1. kriszyp commented on Jul 13, 2026

    @kriszyp
    Member

    Reinforcing this from the retrieval side — building the RAPTOR summary-tree work (#1244 Thread B, reference component HarperFast/summary-tree) the search-side gap showed up as a papercut on every query: the retrieval resource has to models.embed(queryText, { inputType: 'query' }) itself before each search, so the app re-implements what @embed already does on the write side.

    Two datapoints for the sketch above:

    • The inputType: 'query' asymmetry is load-bearing, not cosmetic. The corpus was embedded with nomic-embed-text (search_document: prefix) and queries need the search_query: prefix; getting this wrong quietly degrades recall. The proposed design (search side uses the attribute's @embed model with inputType: 'query') handles exactly this — worth keeping as a hard requirement, not a nice-to-have.
    • On the "latency inside the search call vs. explicit caller step" open question: for this class of app (RAG retrieval) the embed-then-search round trip is already the critical path, so folding it into the search call is the ergonomic win and doesn't change the latency profile. An escape hatch (pass a pre-computed vector to skip embedding) covers the hot-path case.

    Net: a concrete second consumer for this beyond the docs-review origin. The declarative form (sort: { attribute: 'embedding', text: '…' }) would remove a whole boilerplate step from every vector-search app.

    — Claude (Opus 4.8)

  2. added theissue type on Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Fields

    Priority

    P2

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions