import type { ProviderCallContext } from './lifecycle.js'; import type { CacheConfig, RateLimitConfig, RetryConfig } from './config.js'; import type { ModelStatus } from './providers.js'; import type { ResponseCost, TokenUsage } from './response.js'; import type { AudioContent, BinaryBuffer, DocumentContent, ImageContent, TextContent } from './messages.js'; /** * What the vector will be used for. * * Several providers return a different vector for the same text depending on whether it is being * stored or searched with, and retrieval quality drops when the two are mixed. Providers that make * no such distinction ignore this field. */ export type EmbeddingInputType = 'document' | 'query' | 'classification' | 'clustering'; /** Wire encoding requested from the provider. Both forms are decoded to `number[]`. */ export type EmbeddingEncodingFormat = 'float' | 'base64'; /** How an input longer than the model's limit is handled. */ export type EmbeddingTruncateMode = 'none' | 'start' | 'end'; /** What an embedding input can hold besides text. */ export type EmbeddingModality = 'text' | 'image' | 'audio' | 'video' | 'document'; /** * A video to embed, by its content. A message's video part names a file on disk, which a provider * cannot be sent, so an embedding takes the video itself: its bytes or base64, with its container, * such as `mp4` or `mov`, or a URL a provider reads, such as a Files API URI Google embeds from. */ export interface EmbeddingVideoPart { /** Discriminates this part. */ type: 'video'; /** The video. */ source: { buffer: BinaryBuffer; format?: string; } | { base64: string; format?: string; } | { url: string; format?: string; }; } /** * A part of an embedding input: the same text, image, audio, and document parts a message takes, and * a video by its content. Media must hold its content, as bytes, base64, or a URL; a path or a * transcript is refused. */ export type EmbeddingPart = TextContent | ImageContent | AudioContent | DocumentContent | EmbeddingVideoPart; /** * One input made of parts, such as an image with its caption, embedded as one vector in the same * space as text. Only a model that takes each part's kind is sent it; any other is refused. */ export interface EmbeddingParts { /** The parts, in order. */ parts: readonly EmbeddingPart[]; } /** * One input or many. An input is a text, or `EmbeddingParts` for media. The single-string form exists * so the smallest call stays a one-liner. */ export type EmbeddingInput = string | EmbeddingParts | ReadonlyArray; /** * A request to `ai.embed()`: texts in, vectors out, with routing, batching, caching, and budgets * handled for you. */ export interface EmbeddingRequest { /** One text or a batch. A batch larger than the model's limit is split automatically. */ input: EmbeddingInput; /** Embedding model or alias. Falls back to the configured default. */ model?: string; /** Registered embedding provider to use. Falls back to the provider that owns the model. */ provider?: string; /** * What the vectors will be used for. Store documents with `document` and search with `query` on * providers that distinguish them. */ inputType?: EmbeddingInputType; /** * Truncate the vector to this many dimensions, on models that support it. Refused when the model * declares a fixed size, so a silently mis-sized vector never reaches a vector store. */ dimensions?: number; /** * Wire encoding to request. `base64` is smaller on the wire; the result is decoded to numbers * either way. */ encodingFormat?: EmbeddingEncodingFormat; /** Scale each vector to unit length locally when the provider does not already return one. */ normalize?: boolean; /** * What to do with an input longer than the model accepts: refuse it, or cut from the start or the * end. */ truncate?: EmbeddingTruncateMode; /** Opaque end-user identifier forwarded to providers that accept one for abuse monitoring. */ user?: string; /** Identity used for rate-limit bucketing and audit events. */ userId?: string; /** * The tenant the request runs for: what per-tenant budgets charge, and whose credential a * provider sends when the client resolves credentials per tenant. */ tenantId?: string; /** Identifies the request in records and traces. Generated when omitted. */ requestId?: string; /** Replays an accepted request instead of paying for it twice. */ idempotencyKey?: string; /** Aborts the request and any batches still running. */ signal?: AbortSignal; /** Timeout per provider call, in milliseconds. */ timeoutMs?: number; /** Retries for this call, overriding the configured policy. */ retry?: RetryConfig; /** Overrides the configured cache for this call only. */ cache?: boolean; /** Overrides the configured batch concurrency for this call only. */ concurrency?: number; /** Application data carried through to records and audit events. */ metadata?: Record; /** * Fields merged into the provider request body verbatim. * * The escape hatch for a provider feature the neutral contract does not model yet. Values are * passed through untouched and are never validated. */ providerOptions?: Record; } /** One vector. */ export interface Embedding { /** Position of the source text in the request input. */ index: number; /** The vector's components. */ values: number[]; /** Its length. */ dimensions: number; /** True when the provider reported that the source text was cut to fit the model's limit. */ truncated?: boolean; } /** How an embedding request ran. */ export interface EmbeddingMeta { /** The request's id. */ requestId: string; /** Provider that served it. */ providerUsed: string; /** Model that served it. */ modelUsed: string; /** Length of every vector returned. */ dimensions: number; /** Number of vectors returned. */ count: number; /** Duration in milliseconds. */ latencyMs: number; /** Provider calls made, which is more than one when the input was split. */ batches: number; /** Tokens consumed. */ usage: TokenUsage; /** What it cost, from the model's price. */ cost: ResponseCost; /** * Audio and video parts whose length could not be read from their bytes, such as one given by URL, * and so are not in `cost` for a model that prices them by length. */ unpricedMedia?: number; /** True when every input was served from cache and no provider call was made. */ cacheHit: boolean; /** Inputs served from cache when only part of the batch was. */ cachedInputs?: number; /** Duplicate inputs answered from a single provider call. */ deduplicatedInputs?: number; /** Retries across all batches. */ retries?: number; /** Why the router chose the provider, and how many fallbacks were available. */ routingDecision?: { reason: string; fallbacksConsidered: number; }; } /** The result of `ai.embed()`. */ export interface EmbeddingResponse { /** Each vector with its position and size. */ embeddings: Embedding[]; /** The vectors alone, in input order. `vectors[0]` is the answer for a single-string call. */ vectors: number[][]; /** How the request ran. */ meta: EmbeddingMeta; /** Raw provider payload of the last batch, when the provider supplies one. */ raw?: unknown; } /** A text part, as an adapter receives it. */ export interface EmbeddingProviderTextPart { /** Discriminates this part. */ type: 'text'; /** The text. */ text: string; } /** A media part, as an adapter receives it: its content as base64 data, or the URL that holds it. */ export interface EmbeddingProviderMediaPart { /** What the part is. */ type: Exclude; /** Its MIME type, such as `image/png` or `audio/mpeg`. */ mimeType: string; /** The content, base64, when the part holds it. */ data?: string; /** The URL that holds the content, when the part names one instead. */ url?: string; } /** A part of an embedding input, as an adapter receives it. */ export type EmbeddingProviderPart = EmbeddingProviderTextPart | EmbeddingProviderMediaPart; /** * Request handed to an adapter. * * Aliases, batching, deduplication, and caching are already resolved: `input` is a concrete batch * within the model's limits and `model` is a concrete provider model name. */ export interface EmbeddingProviderRequest { /** A concrete batch, already within the model's limits: each input's text, its text parts joined. */ input: string[]; /** * Each input's parts, in the order of `input`, when any input in the request holds media. A text * input is one text part. Present only for a model whose capabilities take every kind it holds. */ contents?: EmbeddingProviderPart[][]; /** The provider's own model name. */ model: string; /** What the vectors will be used for. */ inputType?: EmbeddingInputType; /** Vector size to return, on models that can shorten theirs. */ dimensions?: number; /** Wire encoding to request. */ encodingFormat?: EmbeddingEncodingFormat; /** What to do with an input that is too long. */ truncate?: EmbeddingTruncateMode; /** End-user identifier, for providers that monitor abuse. */ user?: string; /** Fields merged into the provider request body verbatim. */ providerOptions?: Record; } /** Token usage an adapter reports. */ export interface EmbeddingProviderUsage { /** Input tokens. */ inputTokens?: number; /** Total tokens, when the provider reports it separately. */ totalTokens?: number; } /** What an adapter returns for one batch. */ export interface EmbeddingProviderResult { /** One vector per input, in the same order. */ vectors: number[][]; /** Token usage, when the provider reports it. */ usage?: EmbeddingProviderUsage; /** Concrete model the provider actually used, when it differs from the requested name. */ model?: string; /** True when the provider cut any input to fit. */ truncated?: boolean; /** The provider's response, unmodified. */ raw?: unknown; } /** * What an adapter can do. * * An omitted field means unknown, not unsupported, so an adapter is never restricted by a * capability it simply did not declare. */ export interface EmbeddingProviderCapabilities { /** Models the adapter serves. */ models?: readonly string[]; /** Largest number of inputs accepted in one call. */ maxBatchSize?: number; /** Longest input the adapter accepts, in tokens. */ maxInputTokens?: number; /** `true` for any size up to the model default, or the exact sizes the provider accepts. */ dimensions?: boolean | readonly number[]; /** Input types the provider distinguishes. */ inputTypes?: readonly EmbeddingInputType[]; /** Wire encodings it supports. */ encodingFormats?: readonly EmbeddingEncodingFormat[]; /** Whether it can truncate long inputs itself. */ truncate?: boolean; /** True when the provider already returns unit-length vectors. */ normalized?: boolean; /** * What its inputs can hold. Text only when absent. A model's registry entry, when it has one, * decides for that model. */ inputModalities?: readonly EmbeddingModality[]; } /** Identifies an embeddings adapter and what it supports. */ export interface EmbeddingProviderInfo { /** The adapter's registered name. */ name: string; /** True for an adapter that runs locally, such as Ollama. */ isLocal?: boolean; /** The adapter's version. */ version?: string; /** Model used when the request names none. */ defaultModel?: string; /** What it supports. */ capabilities: EmbeddingProviderCapabilities; } /** * What an adapter receives with every batch besides the request: the context every family's provider * receives, and where this batch sits in the request. */ export interface EmbeddingProviderCallContext extends ProviderCallContext { /** 1 for the first try; higher on a retry. */ attempt: number; /** Index of this batch within the request, starting at 0. */ batchIndex: number; } /** * An embeddings adapter. * * Distinct from the `EmbeddingProvider` function type used by `MemoryVectorStore` and the semantic * cache, which stays supported; `toEmbeddingFunction()` converts this contract into that one. */ export interface EmbeddingsProvider { /** What the adapter is and what it supports. */ readonly info: EmbeddingProviderInfo; /** Embeds one batch. */ embed(request: EmbeddingProviderRequest, context: EmbeddingProviderCallContext): Promise; } /** What the registry knows about an embedding model. */ export interface EmbeddingModelCapabilities { /** Provider that serves it. */ provider: string; /** Model family, for grouping versions. */ family?: string; /** Native vector size. */ dimensions: number; /** Sizes the model can be truncated to, or `true` for any size up to `dimensions`. */ supportedDimensions?: readonly number[] | true; /** Longest input it accepts, in tokens. */ maxInputTokens: number; /** Most inputs per call. */ maxBatchSize?: number; /** Price per 1,000 input tokens, in US dollars. */ costPer1kInput: number; /** Price per image embedded, in US dollars, for a model that takes images. */ costPerImage?: number; /** Price per second of audio embedded, in US dollars, its length read from the audio's own headers. */ costPerAudioSecond?: number; /** Price per frame the model takes from a video, in US dollars. */ costPerVideoFrame?: number; /** * How many frames the model takes from a video, which `costPerVideoFrame` prices: `perSecond`, and * at most `max`. Defaults to one a second, with no most. */ videoFrames?: { perSecond: number; max?: number; }; /** The longest audio part it takes, in seconds. A longer one is refused before it is sent. */ maxAudioSeconds?: number; /** The longest video part it takes, in seconds. A longer one is refused before it is sent. */ maxVideoSeconds?: number; /** What its inputs can hold. Text only when absent. */ inputModalities?: readonly EmbeddingModality[]; /** True when the model already returns unit-length vectors. */ normalized?: boolean; /** Input types the model distinguishes. */ inputTypes?: readonly EmbeddingInputType[]; /** Lifecycle status: `stable`, `preview`, `latest`, or `deprecated`. */ status?: ModelStatus; /** ISO date this entry was last checked against provider documentation. */ verifiedAt?: string; /** Where the entry's details were checked. */ source?: string; /** Anything else worth knowing about the model. */ notes?: string; } /** Embedding models and aliases that extend or replace the bundled registry. */ export interface EmbeddingModelRegistryConfig { /** Alias names mapped to concrete models. */ aliases?: Record; /** Model entries, by name. */ registry?: Record; /** Keeps the bundled entries beside yours. Defaults to true. */ includeDefaults?: boolean; } /** Refuses or flags an embedding request whose estimated cost exceeds a limit. */ export interface EmbeddingCostBudgetConfig { /** Turns the budget check on. */ enabled?: boolean; /** Most a request may cost, in US dollars. */ maxEstimatedCost?: number; /** `error` refuses the request; `warn` sends it and reports the overrun. */ onExceeded?: 'error' | 'warn'; } /** A vector to cache, under its key. */ export interface EmbeddingCacheEntry { /** The entry's key, from `embeddingCacheKey()`. */ key: string; /** The vector. */ vector: readonly number[]; } /** * Where embedding vectors are cached, shared by every process that uses the same store. * * A store reads and writes a whole batch at once, so answering 2,000 texts costs one round trip, not * 2,000. Keys are SHA-256 hashes from `embeddingCacheKey()`, so a text never becomes a key. */ export interface EmbeddingCacheStore { /** The vectors under these keys, in the same order, with `undefined` for each miss. */ getMany(keys: readonly string[]): Promise>; /** Stores vectors, each for `ttlSeconds` when given. */ setMany(entries: readonly EmbeddingCacheEntry[], ttlSeconds?: number): Promise; } /** How embeddings are cached: the options every cache takes, and a shared store. */ export interface EmbeddingCacheConfig extends CacheConfig { /** * A shared vector cache, such as `RedisEmbeddingCache` or `PostgresEmbeddingCache`. It reads and * writes each request's vectors in one round trip, and turns the cache on unless `enabled` is * `false`. It takes the place of `adapter`. A failure of the store fails the request, as an * adapter's does; wrap the store to treat a failure as a miss instead. */ store?: EmbeddingCacheStore; } /** Configuration for `ai.embed()`. */ export interface EmbeddingConfig { /** Adapters registered at construction, keyed by the name requests refer to. */ providers?: Record; /** Adapter used when a request names neither a provider nor a model it owns. */ defaultProvider?: string; /** Model used when a request names none. */ defaultModel?: string; /** Tried in order when the primary attempt fails with a retryable error. */ fallback?: Array<{ provider?: string; model?: string; }>; /** Embedding models and aliases beyond the bundled ones. */ models?: EmbeddingModelRegistryConfig; /** Per-input result caching. Off unless enabled, or given a shared `store`. */ cache?: EmbeddingCacheConfig; /** Rate limiting for embedding calls. */ rateLimit?: RateLimitConfig; /** Retries for failed embedding calls. */ retry?: RetryConfig; /** Cost budget checked before each request. */ costBudget?: EmbeddingCostBudgetConfig; /** Provider calls run in parallel when the input is split. Defaults to 4. */ concurrency?: number; /** Answer repeated identical inputs from one provider call. Defaults to true. */ deduplicate?: boolean; /** Timeout per provider call, in milliseconds. */ timeoutMs?: number; /** * Register adapters for OpenAI, Google, Cohere, Mistral, and Ollama from the provider * credentials already in `providers`. Defaults to true, so a configured chat provider makes * `embed()` work with no extra setup. */ autoRegisterProviders?: boolean; }