/**
 * embedders — ready-made {@link Embedder} implementations for the
 * embedding-backed scorers (memory retrieval, toolChoiceRecorder / scoreMargin).
 *
 * The core deliberately ships only `mockEmbedder` (bring-your-own). These are
 * OPTIONAL and never pulled into the core: each heavy backend is an OPTIONAL
 * PEER DEPENDENCY, imported LAZILY on first embed, so you install ONLY the one
 * you use and agentfootprint stays dependency-free.
 *
 *   openaiEmbedder()  — hosted; needs OPENAI_API_KEY; no extra install (fetch).
 *   bedrockEmbedder() — hosted on AWS; Titan Text Embeddings and Cohere Embed
 *                       v3 (the model id picks the body shape); credentials
 *                       come from the AWS chain, so no key option at all.
 *                       peer dep: @aws-sdk/client-bedrock-runtime.
 *   geminiEmbedder()  — hosted on Google; Vertex (project + Application
 *                       Default Credentials) or the Gemini API (one key), the
 *                       same two doors as `gemini()`. Matryoshka sizes, real
 *                       task types, and it REFUSES a vector the service admits
 *                       it clipped. peer dep: @google/genai.
 *   localEmbedder()   — on-device sentence-transformer; no key; offline after a
 *                       one-time model fetch. peer dep: @huggingface/transformers.
 *   staticEmbedder()  — pure-JS Model2Vec static vectors; no key, no network
 *                       (weights bundled). peer dep: @yarflam/potion-base-8m.
 *
 * All five satisfy the same `Embedder` shape, so they drop into
 * `toolChoiceRecorder({ embedder })` / `semanticPipeline({ embedder })` etc.
 * unchanged. Dimensions differ per model — never mix two in one store.
 *
 * ─── Bundlers / browsers: pass `backend` ────────────────────────────────
 *
 * The lazy `import(spec)` above keeps the peer deps optional, but a BUNDLER
 * cannot see through a variable specifier: the bare name survives into the
 * output and the browser throws
 * `TypeError: Failed to resolve module specifier '@huggingface/transformers'`
 * at first embed. So both on-device factories also accept an ALREADY-IMPORTED
 * module — a static import your own bundler resolves:
 *
 *   import * as transformers from '@huggingface/transformers';
 *   const embedder = localEmbedder({ backend: transformers });
 *
 * Same mechanism as the `client` option on the store adapters (RedisStore,
 * AgentCoreStore): the library states the surface it needs, the host owns the
 * construction. Nothing changes for Node callers who pass nothing.
 *
 * Not an import path of its own since 9.0.0. This is the implementation barrel
 * behind `agentfootprint/providers`, which re-exports every name here — same
 * symbols, one door. Import from the door.
 */
export type { Embedder } from '../memory/embedding/types.js';
import type { Embedder } from '../memory/embedding/types.js';
import { type GoogleGenAIConnectionOptions } from '../adapters/llm/googleGenAI.js';
export interface OpenAIEmbedderOptions {
    /** Default: process.env.OPENAI_API_KEY. */
    readonly apiKey?: string;
    /** Default: 'text-embedding-3-small'. */
    readonly model?: string;
    /**
     * Shorten the vectors the model returns (OpenAI's Matryoshka truncation).
     *
     * When set, the value is SENT as the `dimensions` request parameter AND
     * reported as `.dimensions` — the two can never disagree. Only supported on
     * `text-embedding-3` and later models; ada-002 rejects it, which is exactly
     * why nothing is sent unless you ask.
     *
     * Leave it unset to get the model's native size (looked up from
     * {@link NATIVE_DIMENSIONS}). Required for a model this library doesn't know
     * — see {@link openaiEmbedder}.
     */
    readonly dimensions?: number;
    /** Override the API base (Azure/OpenAI-compatible gateways). */
    readonly baseURL?: string;
}
/**
 * OpenAI's hosted embeddings endpoint.
 *
 * `.dimensions` is the length callers WILL get back, never an assumption:
 * an explicit `{ dimensions }` is sent to the API and reported; otherwise the
 * model's documented native size is reported. A model outside
 * {@link NATIVE_DIMENSIONS} (a gateway, a self-hosted model behind `baseURL`,
 * an Azure deployment name, a future OpenAI model) has no size this library can
 * know, so it is a construction-time error rather than a guess that a vector
 * store would silently trust.
 *
 * `.maxInputChars` (9.1.0) reports **32,000** for the three models above:
 * their documented 8,191-token window at the stated {@link CHARS_PER_TOKEN}
 * assumption. An indexer reads it in preference to its own 2,000-character
 * default, so a corpus split at 2,500 characters is embedded WHOLE here
 * instead of being clipped by a default measured on an on-device model.
 * An unknown model declares no ceiling — the indexer's default stands, which
 * is conservative rather than wrong.
 *
 * @throws if there is no API key, or if `model` is unknown and `dimensions`
 *         was not supplied.
 */
export declare function openaiEmbedder(options?: OpenAIEmbedderOptions): Embedder;
/**
 * The slice of `@aws-sdk/client-bedrock-runtime` {@link bedrockEmbedder} uses.
 *
 * Structural, so the real SDK, a pre-built client shared with the rest of your
 * app, or a test double all satisfy it without this package taking a hard type
 * dependency on the optional peer.
 */
export interface BedrockRuntimeLikeClient {
    /**
     * `send(command, options?)` — the second argument is where the AWS SDK
     * takes an `abortSignal`, and it is passed whenever the caller supplied
     * one, so an aborted indexing run stops paying for embeddings it will
     * throw away.
     */
    send(command: unknown, options?: {
        abortSignal?: AbortSignal;
    }): Promise<unknown>;
}
/** The two SDK constructors this embedder needs. */
export interface BedrockRuntimeSdkModule {
    readonly BedrockRuntimeClient?: new (config: {
        region?: string;
    }) => BedrockRuntimeLikeClient;
    readonly InvokeModelCommand?: new (input: unknown) => unknown;
}
/**
 * The request/response SHAPE a Bedrock embedding model speaks (9.3.0).
 *
 * `InvokeModel` is one operation with a vendor-specific body on both sides:
 * Titan takes `{ inputText }` and answers `{ embedding }`, Cohere takes
 * `{ texts, input_type }` and answers `{ embeddings }`. One model id therefore
 * does not describe one call, and until 9.3.0 this factory sent Titan's body to
 * everything — so a Cohere model id was accepted at construction (with
 * `dimensions`) and failed at the first embed, against the real service, with a
 * validation error from AWS rather than a sentence from here.
 */
export type BedrockEmbeddingFamily = 'titan' | 'cohere';
/**
 * Cohere's `input_type`, which is a real parameter and not a hint: the v3
 * models embed a QUERY and a DOCUMENT into deliberately different places, and
 * the two are meant to be compared with each other. Sending one value for both
 * halves is a measurable loss of retrieval quality, not a style choice — and
 * Cohere requires the field, so there is no "unset" to fall back to.
 */
export type CohereInputType = 'search_document' | 'search_query';
export interface BedrockEmbedderOptions {
    /**
     * Bedrock model id. Default `'amazon.titan-embed-text-v2:0'`.
     *
     * Four are known by name — Titan V2, Titan V1, and Cohere Embed English /
     * Multilingual v3 (see {@link BEDROCK_EMBEDDING_MODELS}) — and each brings
     * its own body shape, vector length and input window. An id that WRAPS one of
     * those (a cross-region inference profile `us.amazon.titan-embed-text-v2:0`,
     * or an ARN ending in the model id) is resolved to the model it names.
     *
     * Anything else is a model this library has never met: pass `dimensions`
     * with it (its vector length is not something this can know) and `family` if
     * it is not Titan-shaped.
     */
    readonly model?: string;
    /**
     * Vector length to request.
     *
     * Titan V2 is the one CONFIGURABLE model — 1024 (default), 512 or 256 — and
     * the value is SENT to the model AND reported as `.dimensions`, so the two
     * can never disagree. Every other known model has ONE size, and asking for a
     * different one is refused rather than reported: `.dimensions` is what a
     * vector store fingerprints on, and a wrong one corrupts it silently.
     *
     * Required for a model outside {@link BEDROCK_EMBEDDING_MODELS}.
     */
    readonly dimensions?: number;
    /**
     * The body shape to speak, when the model id does not say (9.3.0).
     *
     * Inferred for every known model and for anything that wraps one, so this is
     * only for a model id this library has never met — a provisioned-throughput
     * ARN, a custom deployment. Unknown and unstated, the body is **Titan's**,
     * which is the shape every release before 9.3.0 sent to everything.
     *
     * Stating a family that contradicts a known model id is refused by name.
     */
    readonly family?: BedrockEmbeddingFamily;
    /**
     * Pin Cohere's `input_type` instead of deriving it from the call (9.3.0).
     *
     * Unset — the default — `embed()` sends `'search_query'` and `embedBatch()`
     * sends `'search_document'`, because that is what this library's own two
     * call sites are: retrieval embeds ONE question (`loadRelevant`), indexing
     * embeds MANY passages (`indexDocuments`, `embedMessages`). Pin it when your
     * own code uses the two calls differently — embedding a single document, say,
     * or scoring a batch of queries.
     *
     * Ignored by Titan, which has no such parameter.
     */
    readonly inputType?: CohereInputType;
    /**
     * The longest input this model reads whole, in CHARACTERS
     * ({@link Embedder.maxInputChars}). Declared for every known model from its
     * documented token window; this option is how a model this library does not
     * know states its own, rather than declaring none and leaving the indexer's
     * conservative default in place. An explicit value always wins.
     */
    readonly maxInputChars?: number;
    /** AWS region. Passed to the SDK client when this factory builds one. */
    readonly region?: string;
    /** A pre-built Bedrock runtime client, so one SDK config serves the whole app. */
    readonly client?: BedrockRuntimeLikeClient;
    /** @internal Test injection — skips the SDK require entirely. */
    readonly _client?: BedrockRuntimeLikeClient;
    /** @internal Test injection — the AWS SDK module (exercises the real shim with a mock SDK). */
    readonly _sdk?: BedrockRuntimeSdkModule;
}
/**
 * Amazon Bedrock's hosted embeddings, through `InvokeModel`.
 *
 * No API key option, deliberately: Bedrock authenticates through the AWS
 * credential chain (environment, profile, instance role, SSO), and inventing
 * a key parameter would be a second, worse way to configure the same thing.
 *
 * ── Why the id carries the DIMENSION COUNT ───────────────────────────────
 * `openaiEmbedder` deliberately leaves the size out of its id, because a
 * store's fingerprint is `'<id>@<dims>'` and appends it. This one puts it in,
 * and the difference is not an inconsistency — it is the one place the
 * fingerprint cannot reach.
 *
 * `MemoryEntry.embeddingModel` stores the id ALONE, and it is the only thing
 * `SearchOptions.embedderId` filters on: the filter the port describes as
 * preventing "silent cross-model similarity pollution". Titan V2 at 512 and
 * Titan V2 at 1024 are different embedding spaces from one model id, so an id
 * without the size makes those two indistinguishable to that filter — and the
 * size alone cannot separate them either, since V1 and V2 both answer at
 * 1024. Only `'bedrock:<model>:<dims>'` separates all of them. The store's
 * fingerprint then reads `'bedrock:amazon.titan-embed-text-v2:0:512@512'`,
 * which restates the size once; a redundant fingerprint is harmless, and a
 * filter that cannot tell two vector spaces apart is not.
 *
 * (Precedent: `localEmbedder` puts `dtype` in its id for the same reason — a
 * q8 and an fp32 build of one model are near-identical spaces, and "near" is
 * exactly the difference that surfaces as a mysteriously worse ranking.)
 *
 * ── One operation, two body shapes (9.3.0) ───────────────────────────────
 * `InvokeModel` is a single API over vendor-specific JSON. Titan takes
 * `{ inputText }` and answers `{ embedding }`; Cohere takes
 * `{ texts, input_type }` and answers `{ embeddings }`, embeds up to
 * {@link COHERE_MAX_TEXTS_PER_CALL} of them per call, and distinguishes a
 * QUERY from a DOCUMENT. So the model id selects a FAMILY
 * ({@link BedrockEmbeddingFamily}), and the family owns the request, the
 * response and the batching. Before this, one shape was sent to everything —
 * a Cohere id constructed fine and failed at the first embed.
 *
 * ── The input ceiling (9.1.0) ────────────────────────────────────────────
 * `.maxInputChars` is per MODEL, from its documented token window converted at
 * the stated {@link CHARS_PER_TOKEN} assumption of 4 characters per token:
 * **32,000** for both Titan text-embedding models (8,192 tokens — sixteen
 * times the indexer's own default, which was measured on an on-device model),
 * and **2,000** for Cohere Embed v3 (512 tokens). Those two numbers are why the
 * ceiling cannot be a per-vendor constant: the same 2,500-character chunk is
 * read whole by Titan and truncated by Cohere. Dense text (code, tables, CJK)
 * tokenises tighter than the assumption; pass an explicit `maxChunkChars` for
 * such a corpus, and it wins over this number.
 *
 * @throws if `model` is unknown and `dimensions` was not supplied; if
 *         `dimensions` is a size the model does not produce; if `family`
 *         contradicts a known model id; or if the SDK is missing and no
 *         `client` / `_client` / `_sdk` was passed.
 *
 * @example
 * ```ts
 * import { bedrockEmbedder } from 'agentfootprint/providers';
 * import { sqliteVectorStore } from 'agentfootprint/memory';
 * import { indexFolder } from 'agentfootprint/rag';
 *
 * const embedder = bedrockEmbedder({ region: 'us-east-1', dimensions: 512 });
 * await indexFolder('./docs', { to: sqliteVectorStore({ file: './corpus.db' }), embedder });
 * ```
 *
 * @example  A Cohere embedding model on the same runtime
 * ```ts
 * // Body shape, response field, batch size and 512-token window all follow
 * // from the model id — nothing else changes at the call site.
 * const embedder = bedrockEmbedder({ model: 'cohere.embed-english-v3' });
 * ```
 */
export declare function bedrockEmbedder(options?: BedrockEmbedderOptions): Embedder;
/**
 * The slice of `@google/genai` {@link geminiEmbedder} uses — one method.
 *
 * Structural, so the real `GoogleGenAI`, a client shared with `gemini()`, or a
 * `{ models: { embedContent } }` double all satisfy it without this package
 * taking a hard type dependency on the optional peer. The double is what the
 * Google pin injects.
 */
export interface GeminiEmbedClientLike {
    readonly models: {
        embedContent(params: GeminiEmbedParams): Promise<GeminiEmbedResponse>;
    };
}
/** `EmbedContentParameters`, narrowed to what this adapter sends. */
export interface GeminiEmbedParams {
    readonly model: string;
    readonly contents: readonly string[];
    readonly config?: {
        readonly taskType?: string;
        readonly outputDimensionality?: number;
        readonly abortSignal?: AbortSignal;
    };
}
/** `EmbedContentResponse`, narrowed to what this adapter reads. */
export interface GeminiEmbedResponse {
    readonly embeddings?: readonly {
        readonly values?: readonly number[];
        /**
         * Present on Vertex. `truncated: true` is the service TELLING us it clipped
         * the input — the one signal that turns the silent half of
         * {@link Embedder.maxInputChars} into something an adapter can act on.
         */
        readonly statistics?: {
            readonly truncated?: boolean;
            readonly tokenCount?: number;
        };
    }[];
}
/**
 * Gemini's `task_type` — a real parameter, not a hint.
 *
 * `RETRIEVAL_QUERY` and `RETRIEVAL_DOCUMENT` embed a question and a passage
 * into deliberately different projections that are MEANT to be compared with
 * each other, so using one value for both halves is a measurable loss of
 * retrieval quality. The rest are separate objectives; mixing them in one store
 * is mixing spaces.
 */
export type GeminiEmbeddingTaskType = 'RETRIEVAL_QUERY' | 'RETRIEVAL_DOCUMENT' | 'SEMANTIC_SIMILARITY' | 'CLASSIFICATION' | 'CLUSTERING' | 'CODE_RETRIEVAL_QUERY' | 'QUESTION_ANSWERING' | 'FACT_VERIFICATION';
/** What this adapter does when the service says it clipped the input. */
export type GeminiTruncationPolicy = 'refuse' | 'allow';
export interface GeminiEmbedderOptions extends GoogleGenAIConnectionOptions {
    /**
     * Embedding model id. Default `'gemini-embedding-001'`.
     *
     * Two are known by name (see {@link GEMINI_EMBEDDING_MODELS}); anything else
     * is a model this library has never met, so pass `dimensions` with it — its
     * vector length is not something this can know, and a wrong `.dimensions`
     * corrupts a vector store in silence.
     */
    readonly model?: string;
    /**
     * Vector length to request (`outputDimensionality`).
     *
     * Both known models are Matryoshka models: they emit 3072 numbers and can be
     * asked for fewer, and the shorter vector is a genuinely usable embedding
     * rather than a slice of a longer one. The value is SENT to the model AND
     * reported as `.dimensions`, so the two can never disagree. Google recommends
     * 768, 1536 or 3072; any length up to the model's native size is accepted.
     *
     * Required for a model outside {@link GEMINI_EMBEDDING_MODELS}.
     *
     * Note for stores that rank by DOT PRODUCT or euclidean distance: Google's
     * shortened vectors are not re-normalised, and Google recommends normalising
     * them yourself. Nothing in this library needs it — `cosineSimilarity`
     * divides by both magnitudes — so this adapter returns the model's numbers
     * unchanged rather than quietly rescaling what you store.
     */
    readonly dimensions?: number;
    /**
     * Pin `task_type` instead of deriving it from the call.
     *
     * Unset — the default — `embed()` sends `RETRIEVAL_QUERY` and `embedBatch()`
     * sends `RETRIEVAL_DOCUMENT`, because that is what this library's own two
     * call sites are: retrieval embeds ONE question (`loadRelevant`), indexing
     * embeds MANY passages (`indexDocuments`, `embedMessages`). Pin it when your
     * own code uses the two calls differently, or when the objective is
     * classification or clustering rather than search.
     *
     * Refused by name on a model that does not take the parameter.
     */
    readonly taskType?: GeminiEmbeddingTaskType;
    /**
     * What to do when the service reports it CLIPPED the input. Default
     * `'refuse'`.
     *
     * Over-long input is not rejected by Gemini — it is silently truncated, and a
     * full-looking vector comes back for the opening of the passage. An indexer
     * then stores the whole chunk as the passage and the clipped vector as its
     * index, so retrieval cannot find text that is visibly present in the passage
     * it later serves. Nothing throws, nothing scores zero; the corpus is quietly,
     * partially indexed.
     *
     * `.maxInputChars` exists to stop that BEFORE the call, and it is an
     * assumption (see {@link CHARS_PER_TOKEN}) — dense text tokenises tighter.
     * `statistics.truncated` is the service saying it happened anyway, and this
     * adapter is the only thing that sees it. `'refuse'` turns it into an error
     * naming the fix; `'allow'` returns the clipped vector, which is what every
     * library that does not look at the field already does.
     *
     * Detection depends on the service RETURNING `statistics` — Vertex does. When
     * it is absent this adapter cannot tell, and says so here rather than
     * implying a guarantee.
     */
    readonly onTruncation?: GeminiTruncationPolicy;
    /**
     * The longest input this model reads whole, in CHARACTERS
     * ({@link Embedder.maxInputChars}). Declared for every known model from its
     * documented token window; this option is how a model this library does not
     * know states its own. An explicit value always wins.
     */
    readonly maxInputChars?: number;
    /** @internal Test injection — skips the SDK require entirely. */
    readonly _client?: GeminiEmbedClientLike;
}
/**
 * Google's hosted embeddings, through `models.embedContent` — on Vertex or on
 * the Gemini API.
 *
 * The door is chosen exactly as `gemini()` chooses it: `{ project, location }`
 * is Vertex with Application Default Credentials, `{ apiKey }` is the Gemini
 * API, and neither is guessed. One `GoogleGenAI` client serves both this and
 * the LLM provider, so an app that talks to both can build the client once and
 * pass it as `_client`.
 *
 * ── Why the id carries the DIMENSION COUNT ───────────────────────────────
 * `'gemini:<model>:<dims>'`, for the reason `bedrockEmbedder` gives at length:
 * `MemoryEntry.embeddingModel` stores the id ALONE and it is the only thing
 * `SearchOptions.embedderId` filters on. One model id at 768 and the same model
 * id at 3072 are different embedding spaces, so an id without the size cannot
 * tell them apart — and neither can the size alone, since both known models are
 * 3072 natively.
 *
 * The `taskType` is deliberately NOT in the id, matching `bedrockEmbedder`'s
 * treatment of Cohere's `input_type`: the default query/document pair is ONE
 * space by construction (the two projections exist to be compared with each
 * other), and a pinned value pins both call sites at once, so the store stays
 * self-consistent either way.
 *
 * ── The input ceiling, and the service telling on itself (9.1.0) ─────────
 * `.maxInputChars` is per MODEL, from its documented token window at the stated
 * {@link CHARS_PER_TOKEN} assumption: **8,000** for `gemini-embedding-001`
 * (2,048 tokens) and **32,000** for `gemini-embedding-2` (8,192). A quarter of
 * the newer model's window is not a rounding difference — it is the whole
 * reason the ceiling is per-model. Past the ceiling Gemini CLIPS rather than
 * refuses, so `onTruncation` decides what happens when the response admits it.
 *
 * @throws if `model` is unknown and `dimensions` was not supplied; if
 *         `dimensions` exceeds what the model can produce; if `taskType` is set
 *         on a model that takes none; if neither a project nor an API key is
 *         resolvable; or if `@google/genai` is not installed and no `_client`
 *         was passed.
 *
 * @example
 * ```ts
 * import { geminiEmbedder } from 'agentfootprint/providers';
 * import { sqliteVectorStore } from 'agentfootprint/memory';
 * import { indexFolder } from 'agentfootprint/rag';
 *
 * const embedder = geminiEmbedder({ project: 'my-project', dimensions: 768 });
 * await indexFolder('./docs', { to: sqliteVectorStore({ file: './corpus.db' }), embedder });
 * ```
 *
 * @example  The Gemini API door, and a store that must never hold a clipped vector
 * ```ts
 * const embedder = geminiEmbedder({
 *   apiKey: process.env.GEMINI_API_KEY,
 *   onTruncation: 'refuse', // the default — stated here because it is the point
 * });
 * ```
 */
export declare function geminiEmbedder(options?: GeminiEmbedderOptions): Embedder;
/**
 * The slice of `@huggingface/transformers` {@link localEmbedder} uses.
 *
 * Structural, so `await import('@huggingface/transformers')` (or a stub, or a
 * pinned fork) satisfies it without this package taking a hard type dependency
 * on the optional peer.
 */
export interface TransformersBackend {
    /** transformers.js `pipeline(task, model, options)`. */
    pipeline(task: string, model?: string, options?: Record<string, unknown>): Promise<unknown>;
    /** transformers.js `env` — mutated only when `cacheDir` is set. */
    env?: unknown;
}
export interface LocalEmbedderOptions {
    /** ONNX model id. Default 'Xenova/all-MiniLM-L6-v2' (384-dim). */
    readonly model?: string;
    /** Vector length of the model. Default 384. */
    readonly dimensions?: number;
    /** Quantization. Default 'q8' (smallest); use 'fp32' for max fidelity. */
    readonly dtype?: string;
    /** On-disk model cache directory. */
    readonly cacheDir?: string;
    /**
     * Longest input this model reads whole, in characters (9.1.0). Default
     * {@link LOCAL_MAX_INPUT_CHARS} — the MEASURED cliff of the default model.
     *
     * The option exists because `model` is swappable and the cliff belongs to
     * the MODEL, not to this factory. A long-context embedding model (one of the
     * 8k-token sentence-transformer builds) reads far more than the default
     * says, and without a way to state that, an indexer would keep cutting its
     * corpus into pieces a quarter the size the model can take. Nothing verifies
     * it — it is your model's documented window, declared for the indexer to
     * read.
     */
    readonly maxInputChars?: number;
    /**
     * An ALREADY-IMPORTED `@huggingface/transformers`. Supply this and the lazy
     * `import('@huggingface/transformers')` never happens — which is what makes
     * the embedder work in a BUNDLED app, where a bare specifier reaches the
     * browser unresolved:
     *
     *   import * as transformers from '@huggingface/transformers';
     *   localEmbedder({ backend: transformers });
     *
     * Your bundler resolves that static import; the peer dep stays optional for
     * everyone who doesn't.
     */
    readonly backend?: TransformersBackend;
}
export declare function localEmbedder(options?: LocalEmbedderOptions): Embedder;
/**
 * The slice of a Model2Vec package {@link staticEmbedder} uses: a batch
 * `embed`/`encode`, on the module or on its default export.
 *
 * Structural, so `await import('@yarflam/potion-base-8m')` — or any other
 * Model2Vec build with one of those shapes — satisfies it.
 */
export interface Model2VecBackend {
    /** Batch embed: `embed(texts) => vectors` (may be async). */
    embed?(texts: readonly string[]): unknown;
    /** Alternative name some builds use. */
    encode?(texts: readonly string[]): unknown;
    /** A default export that is the fn, or carries `embed`/`encode`. */
    readonly default?: unknown;
}
export interface StaticEmbedderOptions {
    /** Vector length of the bundled model. Default 256 (potion-base-8m). */
    readonly dimensions?: number;
    /** Override the package specifier for a different Model2Vec build. */
    readonly module?: string;
    /**
     * An ALREADY-IMPORTED Model2Vec module. Supply this and no dynamic import
     * happens — the only way this embedder can run in a BUNDLED app, since a
     * bundler cannot resolve the specifier `module` names:
     *
     *   import * as potion from '@yarflam/potion-base-8m';
     *   staticEmbedder({ backend: potion });
     *
     * Takes precedence over `module`. (The potion backend itself is Node-only
     * today — see the embedders guide.)
     */
    readonly backend?: Model2VecBackend;
}
export declare function staticEmbedder(options?: StaticEmbedderOptions): Embedder;
