ALLM.EmbeddingResponse (allm v0.5.0)

Copy Markdown View Source

A text-embedding response — Layer A serializable data.

iex> resp = ALLM.EmbeddingResponse.new(embeddings: [ALLM.Embedding.new(vector: [0.1, 0.2])])
iex> ALLM.EmbeddingResponse.vectors(resp)
[[0.1, 0.2]]

Invariants

  • Order correspondenceEnum.at(vectors(response), i) is the embedding of Enum.at(request.input, i) for every i. Preserved across chunk merges by index rebasing and by vectors/1's sort.
  • Uniform dimensionality — every vector in :embeddings has the same length. Asserted by the adapter conformance suite, not enforced by the constructor.
  • Cardinalitylength(response.embeddings) == length(request.input) on success.

Usage

:usage is an ALLM.Usage.t/0 and is never nil; a response that carries no counters holds %ALLM.Usage{} with every field nil. Embeddings bill in tokens, so adapters populate :input_tokens and :total_tokens; :output_tokens is always nil. Providers that report only one of the two counters leave the other nil rather than synthesizing a value.

:raw carries the same caller-responsibility contract as ALLM.Response.raw: a non-JSON-encodable :raw raises at encode time.

Summary

Functions

Length of the first vector, or nil when :embeddings is empty. Use to size a vector(N) column.

Build an %EmbeddingResponse{} from keyword opts.

Vectors sorted by :index, flattened for direct insertion into a vector(N) column.

Types

t()

@type t() :: %ALLM.EmbeddingResponse{
  embeddings: [ALLM.Embedding.t()],
  id: String.t() | nil,
  metadata: map(),
  model: String.t() | nil,
  raw: term(),
  request_id: String.t() | nil,
  usage: ALLM.Usage.t()
}

Functions

dimensions(embedding_response)

@spec dimensions(t()) :: non_neg_integer() | nil

Length of the first vector, or nil when :embeddings is empty. Use to size a vector(N) column.

"First" means first in list order, not lowest :index — unlike vectors/1, this function does not sort. The two agree only under the uniform-dimensionality invariant above, which is asserted by the adapter conformance suite rather than by this struct.

The return is non_neg_integer/0, not pos_integer/0: a caller can hand-build %ALLM.Embedding{vector: []}, and this function then returns 0. Adapters cannot — one that would build an empty vector from a provider response returns %ALLM.Error.EmbeddingAdapterError{reason: :malformed_response} instead — so 0 is reachable only through direct struct construction, never from a provider round-trip.

Examples

iex> resp = ALLM.EmbeddingResponse.new(embeddings: [ALLM.Embedding.new(vector: [1.0, 2.0])])
iex> ALLM.EmbeddingResponse.dimensions(resp)
2

iex> ALLM.EmbeddingResponse.dimensions(ALLM.EmbeddingResponse.new())
nil

new(opts \\ [])

@spec new(keyword()) :: t()

Build an %EmbeddingResponse{} from keyword opts.

Unknown keys raise KeyError via struct!/2.

Examples

iex> resp = ALLM.EmbeddingResponse.new(model: "text-embedding-3-small")
iex> resp.embeddings
[]
iex> resp.usage
%ALLM.Usage{}

vectors(embedding_response)

@spec vectors(t()) :: [[float()]]

Vectors sorted by :index, flattened for direct insertion into a vector(N) column.

Sorting is what guarantees the order-correspondence invariant even when a provider returns items out of order or a chunk merge interleaves them.

Examples

iex> resp = ALLM.EmbeddingResponse.new(embeddings: [
...>   ALLM.Embedding.new(vector: [1.0], index: 1),
...>   ALLM.Embedding.new(vector: [0.0], index: 0)
...> ])
iex> ALLM.EmbeddingResponse.vectors(resp)
[[0.0], [1.0]]

iex> ALLM.EmbeddingResponse.vectors(ALLM.EmbeddingResponse.new())
[]