@lunora/ai 1.0.0-alpha.4 → 1.0.0-alpha.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,558 @@
1
+ import { Tool } from 'ai';
2
+ import { E as EmbeddingModelInput, a as LunoraAi } from "../packem_shared/types.d-BcLGTChd.mjs";
3
+ /**
4
+ * Built-in fixed-window chunker: split into `size`-char windows overlapping by
5
+ * `overlap` chars. Deliberately simple and deterministic — the zero-config
6
+ * default. Token-aware / sentence / semantic strategies plug in via
7
+ * `RagConfig.chunk`.
8
+ * @experimental
9
+ */
10
+ declare const fixedWindowChunks: (text: string, size: number, overlap: number) => ReadonlyArray<string>;
11
+ /**
12
+ * `(text) => vector` — the embedder shape `ctx.vectors` accepts on both its
13
+ * write (`upsert`) and read (`query`) inputs. Matches `@lunora/server`'s
14
+ * `VectorEmbedder` and `@lunora/bindings/vectors`' `EmbedFunction&lt;string>`.
15
+ * @experimental
16
+ */
17
+ type RagEmbedder = (input: string) => Promise<ReadonlyArray<number>> | ReadonlyArray<number>;
18
+ /**
19
+ * `RagVectorMatch` is part of the experimental `@lunora/ai` API and may change without a major version bump.
20
+ * @experimental
21
+ */
22
+ interface RagVectorMatch {
23
+ id: string;
24
+ metadata?: Record<string, unknown>;
25
+ score: number;
26
+ }
27
+ /**
28
+ * `RagVectorMatches` is part of the experimental `@lunora/ai` API and may change without a major version bump.
29
+ * @experimental
30
+ */
31
+ interface RagVectorMatches {
32
+ count: number;
33
+ matches: ReadonlyArray<RagVectorMatch>;
34
+ }
35
+ /**
36
+ * `RagVectorQueryInput` is part of the experimental `@lunora/ai` API and may change without a major version bump.
37
+ * @experimental
38
+ */
39
+ interface RagVectorQueryInput {
40
+ /** Embedder used to vectorize `input`. */
41
+ embed?: RagEmbedder;
42
+ filter?: Record<string, unknown>;
43
+ /** Natural-language query text, embedded via `embed`. */
44
+ input?: string;
45
+ namespace?: string;
46
+ /**
47
+ * How much stored metadata to return on matches. The runtime honours it even
48
+ * though `@lunora/server`'s ctx type does not declare it — the helper relies
49
+ * on it to read chunk text back in metadata mode.
50
+ */
51
+ returnMetadata?: "all" | "indexed" | "none";
52
+ topK?: number;
53
+ }
54
+ /**
55
+ * `RagVectorRecord` is part of the experimental `@lunora/ai` API and may change without a major version bump.
56
+ * @experimental
57
+ */
58
+ interface RagVectorRecord {
59
+ id: string;
60
+ metadata?: Record<string, unknown>;
61
+ }
62
+ /**
63
+ * `RagVectorUpsertInput` is part of the experimental `@lunora/ai` API and may change without a major version bump.
64
+ * @experimental
65
+ */
66
+ interface RagVectorUpsertInput {
67
+ /** Embedder used to vectorize `input`. Optional — omitted for text-search indexes. */
68
+ embed?: RagEmbedder;
69
+ id: string;
70
+ input: string;
71
+ metadata?: Record<string, unknown>;
72
+ namespace?: string;
73
+ }
74
+ /**
75
+ * Structural subset of the vector surface the RAG helper needs. Both the
76
+ * `ctx.vectors` facade on Mutation/Action ctx (`@lunora/server`'s
77
+ * `VectorSearch`) and the raw `@lunora/bindings/vectors` `LunoraVectors`
78
+ * satisfy it — declared here so `@lunora/ai` depends on neither package.
79
+ * @experimental
80
+ */
81
+ interface RagVectors {
82
+ deleteByIds: (indexName: string, ids: ReadonlyArray<string>, namespace?: string) => Promise<unknown>;
83
+ getByIds: (indexName: string, ids: ReadonlyArray<string>, namespace?: string) => Promise<ReadonlyArray<RagVectorRecord>>;
84
+ query: (indexName: string, input: RagVectorQueryInput) => Promise<RagVectorMatches>;
85
+ upsert: (indexName: string, input: RagVectorUpsertInput) => Promise<unknown>;
86
+ }
87
+ /**
88
+ * The two facades `defineRag` binds. An `ActionCtx` satisfies this directly
89
+ * (`ctx.ai` is action-only, so RAG methods run inside actions); any object
90
+ * carrying the two facades works in tests.
91
+ * @experimental
92
+ */
93
+ interface RagContext {
94
+ /**
95
+ * Resolves a Workers AI embedding-model id (or the omitted default) — an
96
+ * `ActionCtx`'s `ctx.ai` satisfies it. OPTIONAL: when
97
+ * {@link RagConfig.embeddingModel} is a direct AI SDK `EmbeddingModel` object
98
+ * (bring-your-own embeddings, e.g. `@ai-sdk/openai`), the helper uses that
99
+ * object as-is and never reads `ai`, so a hand-built context may omit it and
100
+ * no `env.AI` binding is needed. A model-id string (or an omitted model) with
101
+ * no `ai` present throws a directed error.
102
+ */
103
+ ai?: Pick<LunoraAi, "embeddingModel">;
104
+ /**
105
+ * The verified retrieval identity, read by {@link RagConfig.rlsFilter} to
106
+ * derive a per-request row filter. An `ActionCtx` carrying `ctx.auth`
107
+ * satisfies this structurally, so `docs(ctx)` picks the identity up
108
+ * automatically; tests pass any value. `unknown` on purpose — `@lunora/ai`
109
+ * stays decoupled from `@lunora/server`'s identity type; `rlsFilter` narrows.
110
+ */
111
+ auth?: unknown;
112
+ /**
113
+ * Optional conversation / session id. When set (and `trace` is present), each
114
+ * embedding-model span additionally carries `gen_ai.conversation.id`, so a
115
+ * RAG embed done inside a multi-turn conversation groups with that
116
+ * conversation's other generation spans in the trace store. Omitted → the
117
+ * attribute is absent (backward-compatible).
118
+ */
119
+ conversationId?: string;
120
+ /**
121
+ * Optional `ctx.trace` span factory — an `ActionCtx`'s `ctx.trace` satisfies
122
+ * it structurally. When present, `defineRag` wraps each embedding-model
123
+ * call in a `generation` span carrying `gen_ai.operation.name: "embeddings"`
124
+ * and `gen_ai.request.model` up front, plus — attached post-hoc through the
125
+ * span handle the tracer hands the body — `gen_ai.usage.input_tokens` (from
126
+ * the embed result's token usage) and `gen_ai.usage.cost` (probed from the
127
+ * embed result's provider metadata, e.g. AI Gateway) when those are present.
128
+ * So the embed shows up on the trace waterfall with its usage like any other
129
+ * instrumented model call. `unknown` on purpose — the same decoupling
130
+ * rationale as `auth`: `defineRag` narrows it to a callable and runs embeds
131
+ * untraced when it is absent (a hand-built context / test).
132
+ */
133
+ trace?: unknown;
134
+ vectors: RagVectors;
135
+ }
136
+ /**
137
+ * Pluggable chunk-text storage. By default chunk text is stored in vector
138
+ * metadata (`__ragText`), which forces `returnMetadata: "all"` on retrieval and
139
+ * caps `topK` at 20 (the Vectorize full-metadata ceiling) — and each vector's
140
+ * metadata must stay under the ~10 KiB Vectorize cap. Supplying a text store
141
+ * (a DO table, KV, …) moves the text out of metadata: retrieval queries with
142
+ * `returnMetadata: "indexed"` (topK up to 100) and hydrates text by chunk id.
143
+ * @experimental
144
+ */
145
+ interface RagTextStore {
146
+ /** Fetch chunk texts by id, aligned with the input order; `undefined` for misses. */
147
+ getMany: (ids: ReadonlyArray<string>, options: {
148
+ namespace?: string;
149
+ }) => Promise<ReadonlyArray<string | undefined>>;
150
+ /** Persist chunk texts. Must be idempotent by chunk `id` (re-index re-puts). */
151
+ put: (chunks: ReadonlyArray<StoredRagChunk>, options: {
152
+ namespace?: string;
153
+ }) => Promise<void>;
154
+ /** Optional cleanup hook, invoked when a source's chunks are deleted. */
155
+ remove?: (ids: ReadonlyArray<string>, options: {
156
+ namespace?: string;
157
+ }) => Promise<void>;
158
+ }
159
+ /**
160
+ * A chunk handed to {@link RagTextStore.put} / {@link RagLexicalStore.index}.
161
+ * @experimental
162
+ */
163
+ interface StoredRagChunk {
164
+ chunkIndex: number;
165
+ id: string;
166
+ sourceId: string;
167
+ text: string;
168
+ }
169
+ /**
170
+ * One lexical (BM25) hit returned by {@link RagLexicalStore.search}.
171
+ * @experimental
172
+ */
173
+ interface LexicalMatch {
174
+ /** The chunk vector id — the same id scheme the vector leg uses, so RRF can fuse the two. */
175
+ id: string;
176
+ /** BM25 relevance score (higher = better). Used only for the leg's internal ranking; RRF fuses by rank. */
177
+ score: number;
178
+ /** The chunk text, returned so a fused lexical-only hit needs no extra hydration round-trip. */
179
+ text: string;
180
+ }
181
+ /**
182
+ * Pluggable lexical (BM25 / keyword) store — the production seam for hybrid
183
+ * retrieval. When {@link RagConfig.lexicalStore} is set, `index()` mirrors each
184
+ * chunk's text here and `retrieve()` fuses this store's keyword ranking with the
185
+ * vector store's semantic ranking via Reciprocal Rank Fusion. Mirrors the
186
+ * {@link RagTextStore} shape (idempotent by chunk `id`, namespace-partitioned).
187
+ *
188
+ * `@lunora/ai/rag` ships `bm25LexicalStore()`, an in-memory reference adapter;
189
+ * production deployments plug a durable one (DO SQLite inverted index, D1,
190
+ * Vectorize-adjacent search service, …) behind this same interface.
191
+ * @experimental
192
+ */
193
+ interface RagLexicalStore {
194
+ /** Index chunk texts for keyword search. Must be idempotent by chunk `id` (re-index re-puts). */
195
+ index: (chunks: ReadonlyArray<StoredRagChunk>, options: {
196
+ namespace?: string;
197
+ }) => Promise<void>;
198
+ /** Optional cleanup hook, invoked when a source's chunks are deleted or a re-index shrinks it. */
199
+ remove?: (ids: ReadonlyArray<string>, options: {
200
+ namespace?: string;
201
+ }) => Promise<void>;
202
+ /**
203
+ * Rank chunks by lexical relevance to `query`. `filter` carries the same
204
+ * (RLS-merged) metadata predicate handed to the vector leg — a store that
205
+ * indexes metadata MUST honour it so hybrid retrieval can't surface a row
206
+ * the RLS filter would exclude; a namespace-only store (the reference
207
+ * adapter) isolates by `namespace` and documents that it ignores `filter`.
208
+ */
209
+ search: (query: string, options: {
210
+ filter?: Record<string, unknown>;
211
+ namespace?: string;
212
+ topK: number;
213
+ }) => Promise<ReadonlyArray<LexicalMatch>>;
214
+ }
215
+ /**
216
+ * A pre-defined, reusable filter expression. Declared on `RagConfig.filters`
217
+ * (keyed by name) and referenced by name from `RetrieveOptions.filter` — avoids
218
+ * repeating the same tenant/RBAC filter shape across every retrieval site.
219
+ * @example
220
+ * ```ts
221
+ * const docs = defineRag({
222
+ * index: "docs",
223
+ * filters: {
224
+ * published: { filter: { status: "published", deleted: false }, description: "Only published content" },
225
+ * },
226
+ * });
227
+ * // Later — reference by name:
228
+ * docs(ctx).retrieve("query", { filter: "published" });
229
+ * ```
230
+ * @experimental
231
+ */
232
+ interface RagNamedFilter {
233
+ /** Optional human-readable description for observability / Studio display. */
234
+ description?: string;
235
+ /** The filter expression passed verbatim to Vectorize's `filter` parameter. */
236
+ filter: Record<string, unknown>;
237
+ }
238
+ /**
239
+ * `RagConfig` is part of the experimental `@lunora/ai` API and may change without a major version bump.
240
+ * @experimental
241
+ */
242
+ interface RagConfig {
243
+ /**
244
+ * Suppress the one-time dev warning emitted when `index`/`retrieve` run
245
+ * without a `namespace`. Only appropriate for genuinely single-tenant apps —
246
+ * Vectorize indexes are account-global, so a namespace-less index shares
247
+ * vectors across every tenant.
248
+ */
249
+ allowSharedNamespace?: boolean;
250
+ /** Custom chunker; overrides the built-in fixed-window splitter. */
251
+ chunk?: (text: string) => ReadonlyArray<string>;
252
+ /** Overlap (chars) between adjacent chunks. Default 200. Must be < `chunkSize`. */
253
+ chunkOverlap?: number;
254
+ /** Target chunk size (chars). Default 1000. */
255
+ chunkSize?: number;
256
+ /**
257
+ * Embedding model, declared once so index + retrieve embed identically: a
258
+ * Workers AI id (e.g. `@cf/baai/bge-base-en-v1.5`) or any AI SDK
259
+ * `EmbeddingModel`. Falls back to `createAi`'s `defaultModel` when omitted.
260
+ */
261
+ embeddingModel?: EmbeddingModelInput;
262
+ /**
263
+ * Embedding-model version tag — an opt-in discriminator that partitions the
264
+ * vector space so a model swap can never silently return garbage. Vectors
265
+ * embedded by one model live in a different space from another's, and
266
+ * querying across the two returns meaningless neighbours. When set, the tag
267
+ * is folded into the effective Vectorize namespace (and chunk-id prefix) of
268
+ * every index/retrieve/remove, so bumping it re-partitions cleanly: old
269
+ * vectors become unreachable to new queries (empty ≫ wrong) until sources
270
+ * are re-indexed under the new tag.
271
+ *
272
+ * Set + bump this whenever you change {@link RagConfig.embeddingModel} (or
273
+ * its dimensions). Opt-in and non-breaking — omitting it keeps the exact
274
+ * chunk-id/namespace scheme of un-versioned indexes. Must match
275
+ * `^[A-Za-z0-9._-]{1,40}$` (e.g. `"bge-v1.5"`, `"v2"`).
276
+ */
277
+ embeddingModelVersion?: string;
278
+ /**
279
+ * Pre-defined named filter expressions. Each key is a filter name users
280
+ * pass through `RetrieveOptions.filter`. Throws at retrieve-time if the
281
+ * name is not found here — catches spelling mistakes early.
282
+ */
283
+ filters?: Record<string, RagNamedFilter>;
284
+ /** The Vectorize index name (a `ctx.vectors` index binding key). */
285
+ index: string;
286
+ /**
287
+ * Pluggable lexical (BM25) store for hybrid retrieval. When set, `index()`
288
+ * mirrors chunk text into it and `retrieve()` fuses the vector (semantic)
289
+ * and lexical (keyword) rankings via Reciprocal Rank Fusion — recovering the
290
+ * exact-term / rare-token matches a pure-embedding search misses. Use the
291
+ * shipped `bm25LexicalStore()` reference adapter or plug your own durable
292
+ * one. See {@link RagLexicalStore}.
293
+ */
294
+ lexicalStore?: RagLexicalStore;
295
+ /** Retrieval depth for the lexical leg of hybrid search. Defaults to the effective `topK`. */
296
+ lexicalTopK?: number;
297
+ /**
298
+ * Enforce tenant isolation: throw (instead of the one-time dev warning)
299
+ * when `index`/`retrieve`/`remove` run without a `namespace`. Recommended
300
+ * for every multi-tenant app — Vectorize indexes are account-global, and
301
+ * in metadata mode the leaked payload includes raw chunk text.
302
+ */
303
+ requireNamespace?: boolean;
304
+ /**
305
+ * Row-level-security filter derived from the retrieval identity. Called once
306
+ * per `retrieve()` with {@link RagContext.auth} (the bound ctx's `auth`); the
307
+ * returned Vectorize metadata filter is merged over the caller's `filter`
308
+ * with **RLS keys winning** (a caller can never widen past what RLS allows),
309
+ * then applied to both the vector and the lexical legs. Return `undefined` to
310
+ * add no constraint (e.g. an admin identity). Runs on retrieval only —
311
+ * indexing is a trusted server path.
312
+ * @example
313
+ * ```ts
314
+ * const docs = defineRag({
315
+ * index: "docs",
316
+ * // only ever return the caller's own org, whatever else they ask for:
317
+ * rlsFilter: (auth) => ({ orgId: (auth as { orgId: string }).orgId }),
318
+ * });
319
+ * ```
320
+ */
321
+ rlsFilter?: (auth: unknown) => Promise<Record<string, unknown> | undefined> | Record<string, unknown> | undefined;
322
+ /** Chunk-text storage override — see {@link RagTextStore}. */
323
+ textStore?: RagTextStore;
324
+ /** Default retrieval depth. Default 5. Capped at 20 (metadata mode) / 100 (text-store mode). */
325
+ topK?: number;
326
+ }
327
+ /**
328
+ * `IndexInput` is part of the experimental `@lunora/ai` API and may change without a major version bump.
329
+ * @experimental
330
+ */
331
+ interface IndexInput {
332
+ /**
333
+ * When `false`, throws if the source text produces zero chunks (e.g. empty
334
+ * or whitespace-only text). Default `true` (silently produces zero chunks).
335
+ */
336
+ allowEmptySources?: boolean;
337
+ /** Source document id — chunk ids derive from it as `${id}#${chunkIndex}`. */
338
+ id: string;
339
+ /**
340
+ * Relative weight in `[0, 1]` multiplied into this source's match scores at
341
+ * retrieval time (default 1). Lets canonical docs outrank incidental ones.
342
+ */
343
+ importance?: number;
344
+ /** Source metadata copied onto every chunk vector (e.g. title, url). */
345
+ metadata?: Record<string, unknown>;
346
+ /** Tenant/shard key. Required for multi-tenant apps — Vectorize is account-global. */
347
+ namespace?: string;
348
+ /**
349
+ * Called after each chunk is successfully upserted. Useful for progress
350
+ * tracking during large indexing operations — e.g. updating a UI progress
351
+ * bar or logging per-chunk status.
352
+ */
353
+ onChunk?: (info: {
354
+ chunkIndex: number;
355
+ id: string;
356
+ text: string;
357
+ total: number;
358
+ }) => void;
359
+ /** The document body to chunk + embed + upsert. */
360
+ text: string;
361
+ }
362
+ /**
363
+ * `IndexResult` is part of the experimental `@lunora/ai` API and may change without a major version bump.
364
+ * @experimental
365
+ */
366
+ interface IndexResult {
367
+ /** Number of chunks the source is indexed into. */
368
+ chunks: number;
369
+ /** The deterministic chunk vector ids, in chunk order. */
370
+ ids: ReadonlyArray<string>;
371
+ /**
372
+ * True when the source's content hash matched the previously indexed hash —
373
+ * chunking/embedding/upserts were skipped entirely (a no-op re-sync).
374
+ */
375
+ unchanged: boolean;
376
+ }
377
+ /**
378
+ * `RemoveInput` is part of the experimental `@lunora/ai` API and may change without a major version bump.
379
+ * @experimental
380
+ */
381
+ interface RemoveInput {
382
+ /** The source document id whose chunks are removed. */
383
+ id: string;
384
+ namespace?: string;
385
+ }
386
+ /**
387
+ * `RetrieveOptions` is part of the experimental `@lunora/ai` API and may change without a major version bump.
388
+ * @experimental
389
+ */
390
+ interface RetrieveOptions {
391
+ /**
392
+ * Also return this many neighbouring chunks around each match (fetched by
393
+ * deterministic id, not re-queried) — "embed small, retrieve big". Neighbour
394
+ * text is stitched into the chunk's `text` in document order. Best combined
395
+ * with `chunkOverlap: 0`, since overlapping windows repeat boundary text.
396
+ */
397
+ chunkContext?: {
398
+ after?: number;
399
+ before?: number;
400
+ };
401
+ /**
402
+ * Vectorize filter expression — or the name of a pre-defined filter declared
403
+ * in `RagConfig.filters`. Passing a name that is not registered throws at
404
+ * call time, catching spelling mistakes early.
405
+ */
406
+ filter?: Record<string, unknown> | string;
407
+ /** Drop matches whose (importance-adjusted) score falls below this threshold. */
408
+ minScore?: number;
409
+ namespace?: string;
410
+ /**
411
+ * Fires after retrieval completes, before chunk expansion. Useful for
412
+ * observability — logging query latency, hit counts, etc.
413
+ */
414
+ onRetrieve?: (info: {
415
+ matches: number;
416
+ query: string;
417
+ }) => void;
418
+ topK?: number;
419
+ }
420
+ /**
421
+ * `RetrievedChunk` is part of the experimental `@lunora/ai` API and may change without a major version bump.
422
+ * @experimental
423
+ */
424
+ interface RetrievedChunk {
425
+ chunkIndex: number;
426
+ id: string;
427
+ /**
428
+ * The source-level importance weight that was multiplied into this chunk's
429
+ * score. `1` when no importance was set at index time.
430
+ */
431
+ importance: number;
432
+ /** Caller metadata stored on the vector (internal `__rag*` keys stripped). */
433
+ metadata?: Record<string, unknown>;
434
+ /** Cosine similarity, multiplied by the source's `importance` when one was set. */
435
+ score: number;
436
+ sourceId: string;
437
+ text: string;
438
+ }
439
+ /**
440
+ * `RagSource` is part of the experimental `@lunora/ai` API and may change without a major version bump.
441
+ * @experimental
442
+ */
443
+ interface RagSource {
444
+ id: string;
445
+ /** Caller metadata from the source's first-seen chunk (internal keys stripped). */
446
+ metadata?: Record<string, unknown>;
447
+ /**
448
+ * The source's importance weight (the `importance` value passed at index
449
+ * time, default 1), propagated so downstream consumers can factor it into
450
+ * their own ranking or UI.
451
+ */
452
+ weight?: number;
453
+ }
454
+ /**
455
+ * The retrieve return shape — designed so an agent memory step consumes it directly.
456
+ * @experimental
457
+ */
458
+ interface RetrieveResult {
459
+ /** Ranked chunks (best first). */
460
+ chunks: ReadonlyArray<RetrievedChunk>;
461
+ /** Ready-to-inject prompt context: chunks joined under `[source:&lt;id>#&lt;n>]` headers. */
462
+ context: string;
463
+ /** Deduped source references, in first-seen (best) order. */
464
+ sources: ReadonlyArray<RagSource>;
465
+ }
466
+ /**
467
+ * `RagToolOptions` is part of the experimental `@lunora/ai` API and may change without a major version bump.
468
+ * @experimental
469
+ */
470
+ interface RagToolOptions {
471
+ /** Tool description shown to the model. Defaults to a search description naming the index. */
472
+ description?: string;
473
+ /** Namespace applied to every tool-invoked retrieval (the tenant key). */
474
+ namespace?: string;
475
+ /** Retrieval depth for tool-invoked retrievals. */
476
+ topK?: number;
477
+ }
478
+ /**
479
+ * The per-request RAG surface returned by binding a ctx: `docs(ctx)`.
480
+ * @experimental
481
+ */
482
+ interface Rag {
483
+ /**
484
+ * Expose `retrieve` as an AI SDK tool (for `generateText`/`streamText`
485
+ * `tools:` maps), so a model can decide to search the index itself.
486
+ */
487
+ asTool: (options?: RagToolOptions) => Tool<{
488
+ query: string;
489
+ }, RetrieveResult>;
490
+ /**
491
+ * Chunk + embed + upsert one source document. Re-indexing the same `id` is
492
+ * an atomic-enough replace: unchanged content short-circuits via content
493
+ * hash, and stale chunks beyond the new count are deleted automatically.
494
+ */
495
+ index: (input: IndexInput) => Promise<IndexResult>;
496
+ /** Delete every chunk of a previously indexed source. */
497
+ remove: (input: RemoveInput) => Promise<void>;
498
+ /** Embed the query and return ranked chunks + prompt-ready context. */
499
+ retrieve: (query: string, options?: RetrieveOptions) => Promise<RetrieveResult>;
500
+ }
501
+ declare const defineRag: (config: RagConfig) => ((context: RagContext) => Rag);
502
+ /**
503
+ * Guess a MIME type from a file extension. Lowercases and strips a leading `.`
504
+ * from `extension`; returns `"application/octet-stream"` for unknown extensions.
505
+ *
506
+ * Covers the broad set of extensions users are likely to encounter in a web /
507
+ * document-processing context — images, video, audio, office docs, PDF, text,
508
+ * archives, and source code. Follows the same approach as Convex's
509
+ * `guessMimeType` helper.
510
+ * @experimental
511
+ */
512
+ declare const guessMimeTypeFromExtension: (extension: string) => string;
513
+ /**
514
+ * SHA-256 hex digest of binary data. Accepts a `BufferSource` (`ArrayBuffer` or
515
+ * `ArrayBufferView` such as `Uint8Array`). Useful for content-addressable
516
+ * storage — pair with `IndexInput.text` to detect duplicates across re-indexes.
517
+ * @experimental
518
+ */
519
+ declare const contentHash: (data: BufferSource) => Promise<string>;
520
+ /**
521
+ * Reciprocal Rank Fusion (RRF): merge two ranked lists of chunks by their
522
+ * _rank position_ rather than their absolute scores, which are not comparable
523
+ * across different search methods (cosine vs BM25).
524
+ *
525
+ * Each result set contributes `1 / (k + rank)` to each chunk's fused score,
526
+ * where `rank` is 0-based position in the list. The constant `k` (default 60)
527
+ * dampens the influence of high ranks — the standard value from the RRF
528
+ * literature that works well across domains.
529
+ *
530
+ * The fused list is sorted descending by fused score. Ties are broken by
531
+ * preferring the chunk ranked higher in the vector search result (typically
532
+ * the more semantically accurate of the two methods).
533
+ *
534
+ * Callers MUST ensure every chunk in both lists carries a unique, comparable
535
+ * `id` — this is guaranteed by the chunk-id scheme `${sourceId}#${chunkIndex}`.
536
+ * @experimental
537
+ */
538
+ declare const hybridRank: (vectorResults: ReadonlyArray<RetrievedChunk>, textResults: ReadonlyArray<RetrievedChunk>, k?: number) => ReadonlyArray<RetrievedChunk>;
539
+ /**
540
+ * An **in-memory** Okapi BM25 lexical store — the reference adapter behind
541
+ * `RagConfig.lexicalStore`, giving hybrid retrieval its keyword leg with zero
542
+ * infrastructure. State lives in the worker isolate: it is **not durable and not
543
+ * shared across isolates**, so it is intended for tests, local development, and
544
+ * single-isolate workloads. Production deployments plug a durable
545
+ * {@link RagLexicalStore} (a DO-SQLite inverted index, D1, or an external search
546
+ * service) behind the same seam.
547
+ *
548
+ * Tenant isolation is by `namespace` (each namespace keeps its own index). This
549
+ * store holds **no metadata**, so it cannot evaluate a metadata `filter`
550
+ * (including an `rlsFilter` result): when `search` is called with a non-empty
551
+ * filter it **fails closed** — returns no lexical hits and warns once — rather
552
+ * than risk surfacing a row the filter would exclude. If your RLS is
553
+ * metadata-based (not namespace-based) and you want a lexical leg, fold the RLS
554
+ * dimension into the `namespace` or plug a filter-aware store.
555
+ * @experimental
556
+ */
557
+ declare const bm25LexicalStore: () => RagLexicalStore;
558
+ export { type IndexInput, type IndexResult, type LexicalMatch, type Rag, type RagConfig, type RagContext, type RagEmbedder, type RagLexicalStore, type RagNamedFilter, type RagSource, type RagTextStore, type RagToolOptions, type RagVectorMatch, type RagVectorMatches, type RagVectorQueryInput, type RagVectorRecord, type RagVectorUpsertInput, type RagVectors, type RemoveInput, type RetrieveOptions, type RetrieveResult, type RetrievedChunk, type StoredRagChunk, bm25LexicalStore, contentHash, defineRag, fixedWindowChunks, guessMimeTypeFromExtension, hybridRank };