@absolutejs/rag 0.8.0-beta.0 → 0.9.0

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +53 -0
  3. package/changelog.json +61 -0
  4. package/dist/adapter-kit/index.js +26 -17
  5. package/dist/adapter-kit/index.js.map +5 -5
  6. package/dist/angular/index.js +3 -3
  7. package/dist/angular/index.js.map +2 -2
  8. package/dist/client/index.js +7 -7
  9. package/dist/client/index.js.map +2 -2
  10. package/dist/client/ui.js +17 -17
  11. package/dist/client/ui.js.map +2 -2
  12. package/dist/index.js +536 -308
  13. package/dist/index.js.map +10 -8
  14. package/dist/manifest.js +127 -127
  15. package/dist/manifest.js.map +1 -1
  16. package/dist/presentation/ui.js +75 -75
  17. package/dist/presentation/ui.js.map +2 -2
  18. package/dist/quality/quality.js +130 -130
  19. package/dist/quality/quality.js.map +2 -2
  20. package/dist/react/index.js +15 -15
  21. package/dist/react/index.js.map +2 -2
  22. package/dist/src/angular/ai-rag-stream.service.d.ts +1 -0
  23. package/dist/src/angular/ai-rag-workflow.service.d.ts +1 -0
  24. package/dist/src/client/createRAGAnswerWorkflow.d.ts +1 -0
  25. package/dist/src/index.d.ts +2 -0
  26. package/dist/src/ingestion/originalText.d.ts +29 -0
  27. package/dist/src/react/useRAG.d.ts +2 -0
  28. package/dist/src/react/useRAGStream.d.ts +1 -0
  29. package/dist/src/react/useRAGWorkflow.d.ts +1 -0
  30. package/dist/src/retrieval/originalTextTools.d.ts +23 -0
  31. package/dist/src/svelte/createRAG.d.ts +2 -0
  32. package/dist/src/svelte/createRAGStream.d.ts +1 -0
  33. package/dist/src/svelte/createRAGWorkflow.d.ts +1 -0
  34. package/dist/src/vue/useRAG.d.ts +2 -0
  35. package/dist/src/vue/useRAGStream.d.ts +1 -0
  36. package/dist/src/vue/useRAGWorkflow.d.ts +1 -0
  37. package/dist/svelte/index.js +15 -15
  38. package/dist/svelte/index.js.map +2 -2
  39. package/dist/vue/index.js +15 -15
  40. package/dist/vue/index.js.map +2 -2
  41. package/package.json +15 -10
package/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@absolutejs/rag`.
4
+
5
+ This file is generated by `absolute-changelog` from the entries in
6
+ `changelog/`. Edit an entry, not this file — and add new ones under
7
+ `changelog/unreleased/`.
8
+
9
+ ## 0.9.0 — 2026-09-16
10
+
11
+ ### Breaking
12
+
13
+ - **Reject unsupported lexical and hybrid retrieval instead of silently omitting keyword results; preserve requested channels for scoped heuristic queries** (`createRAGCollection`, `createHeuristicRAGRetrievalStrategy`)
14
+ _Migration:_ Use a store implementing queryLexical for lexical/hybrid retrieval, or explicitly select vector mode on vector-only stores. Scoped heuristic queries now retain the requested channels; update trace consumers from Scoped direct route to Scoped retrieval route.
15
+
16
+ ### Added
17
+
18
+ - **Allow servers to request a smaller original-source search result set while preserving candidate ranking, authorization, and exact token budgeting** (`createRAGOriginalTextTools`)
19
+ - **Add verbatim versioned text ingestion and authorized hybrid source tools with caller-supplied model token budgets; preserve multilingual keyword matches** (`chunkRAGOriginalText`, `readRAGOriginalText`, `createRAGOriginalTextTools`)
20
+
21
+ ### Changed
22
+
23
+ - **Forward AI context policy through RAG WebSocket and SSE chat; accept the next AI 0.1 release while retaining compatibility with the prior AI peer range** (`ragChat`, `createRAGWorkflow`, `useRAG`, `useRAGWorkflow`, `useRAGStream`, `createRAG`, `RAGWorkflowService`, `RAGStreamService`)
24
+ - **Count a complete authorized source-result envelope once when it fits, avoiding serial tokenizer round trips while retaining exact budget validation and oversized-result packing** (`createRAGOriginalTextTools`)
package/README.md CHANGED
@@ -41,6 +41,19 @@ const results = await searchDocuments(collection, {
41
41
 
42
42
  The built-in memory store supports development and tests. Published adapters provide PostgreSQL with pgvector, SQLite with optional vec0 acceleration, and Pinecone behind the same `RAGVectorStore` contract. Lexical and vector results can be fused, transformed, and reranked with provider or heuristic rerankers.
43
43
 
44
+ ### Retrieval channel requirements
45
+
46
+ Lexical and hybrid retrieval require a store implementing `queryLexical`.
47
+ A backend without that capability raises an actionable error before vector
48
+ embedding/search instead of silently returning vector-only or empty results.
49
+ Explicit vector retrieval remains supported on vector-only backends. Configure
50
+ a lexical-capable adapter before requesting hybrid retrieval; a mode flag does
51
+ not add a missing backend capability.
52
+
53
+ The built-in heuristic strategy preserves the requested retrieval mode when a
54
+ query is scoped by source or document ID. Scope narrows the searchable corpus;
55
+ it does not remove the need for exact keyword matches within that corpus.
56
+
44
57
  ## Ingestion and source sync
45
58
 
46
59
  The ingestion pipeline handles files, directories, uploads, URLs, PDFs, office documents, archives, images, and media transcripts. Scheduled connectors can keep collections synchronized from email, GitHub, sitemaps, feeds, directories, and S3-compatible storage.
@@ -57,3 +70,43 @@ The ingestion pipeline handles files, directories, uploads, URLs, PDFs, office d
57
70
  - `@absolutejs/rag/ui` exposes presentation-neutral UI contracts.
58
71
 
59
72
  Pair the retrieval runtime with `@absolutejs/ai` when retrieved context should feed a model or streaming assistant.
73
+
74
+ ### Verbatim original text evidence
75
+
76
+ Use `chunkRAGOriginalText({ sourceId, version, text }, options)` when citations
77
+ must resolve against an immutable text original. This opt-in path preserves
78
+ whitespace and Unicode instead of normalizing or extracting document formats.
79
+ Each chunk includes `metadata.sourceLocator` with the source ID, immutable
80
+ version and UTF-16 `start`/`end` offsets. `readRAGOriginalText` validates identity,
81
+ version and range before returning the exact original slice. Store and authorize
82
+ the original separately; a locator is not an access grant.
83
+
84
+ `createRAGOriginalTextTools({ collection, filter, loadSource, budget })` provides
85
+ `search_text_source` and `read_text_source` AI tools. It requests real hybrid
86
+ retrieval with diversity and verifies evidence against originals. `filter` is a
87
+ server-owned scope; `loadSource(id, version)` must reauthorize every read and
88
+ return `null` for inaccessible/deleted versions. The tools require
89
+ `budget: { maxTokens, countTokens }` using the model tokenizer and a budget
90
+ reserved by the AI context policy. Whole passages are selected within that
91
+ budget; omitted passages are flagged rather than silently truncated. Add the
92
+ final tools/instructions before budgeting the model request. Search traces are
93
+ available through `onTrace`; they contain retrieval metadata and should not be
94
+ copied wholesale into public logs. Servers may set `searchTopK` to an integer
95
+ from 1 to 48 (default 12) for a smaller initial evidence lookup. Candidate ranking
96
+ still considers up to 48 matches; authorization and token-budget checks are
97
+ unchanged. A small initial result set does not establish that other facts are
98
+ absent: retain broader search/read tools for missing or ambiguous evidence.
99
+
100
+ Keyword matching uses Unicode word segmentation and canonical normalization.
101
+ English suffix rules only apply to ASCII words. This improves multilingual exact
102
+ matches; it does not replace evaluation of the selected embedding model.
103
+
104
+ #### AI context policy compatibility
105
+
106
+ With the AI 0.1 context-policy release, RAG chat validates the final assembled
107
+ retrieval context before every model request. Its `contextPolicy` config is
108
+ forwarded to both WebSocket and SSE generation. Use a working token target or a
109
+ saved-source recovery callback when appropriate. Providers without capacity
110
+ support require an explicit `contextPolicy: false` raw opt-out. Older supported
111
+ AI peers retain their previous behavior; upgrading RAG alone does not add the AI
112
+ 0.1 capacity policy. No model-capacity numbers are defined in RAG.
package/changelog.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "contract": 1,
3
+ "name": "@absolutejs/rag",
4
+ "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "kind": "changed",
9
+ "summary": "Forward AI context policy through RAG WebSocket and SSE chat; accept the next AI 0.1 release while retaining compatibility with the prior AI peer range",
10
+ "symbols": [
11
+ "ragChat",
12
+ "createRAGWorkflow",
13
+ "useRAG",
14
+ "useRAGWorkflow",
15
+ "useRAGStream",
16
+ "createRAG",
17
+ "RAGWorkflowService",
18
+ "RAGStreamService"
19
+ ]
20
+ },
21
+ {
22
+ "kind": "added",
23
+ "summary": "Allow servers to request a smaller original-source search result set while preserving candidate ranking, authorization, and exact token budgeting",
24
+ "symbols": [
25
+ "createRAGOriginalTextTools"
26
+ ]
27
+ },
28
+ {
29
+ "kind": "changed",
30
+ "summary": "Count a complete authorized source-result envelope once when it fits, avoiding serial tokenizer round trips while retaining exact budget validation and oversized-result packing",
31
+ "symbols": [
32
+ "createRAGOriginalTextTools"
33
+ ]
34
+ },
35
+ {
36
+ "kind": "added",
37
+ "summary": "Add verbatim versioned text ingestion and authorized hybrid source tools with caller-supplied model token budgets; preserve multilingual keyword matches",
38
+ "symbols": [
39
+ "chunkRAGOriginalText",
40
+ "readRAGOriginalText",
41
+ "createRAGOriginalTextTools"
42
+ ]
43
+ },
44
+ {
45
+ "kind": "breaking",
46
+ "migration": {
47
+ "instruction": "Use a store implementing queryLexical for lexical/hybrid retrieval, or explicitly select vector mode on vector-only stores. Scoped heuristic queries now retain the requested channels; update trace consumers from Scoped direct route to Scoped retrieval route.",
48
+ "manual": true
49
+ },
50
+ "summary": "Reject unsupported lexical and hybrid retrieval instead of silently omitting keyword results; preserve requested channels for scoped heuristic queries",
51
+ "symbols": [
52
+ "createRAGCollection",
53
+ "createHeuristicRAGRetrievalStrategy"
54
+ ]
55
+ }
56
+ ],
57
+ "date": "2026-09-16",
58
+ "version": "0.9.0"
59
+ }
60
+ ]
61
+ }
@@ -11437,7 +11437,8 @@ var STOP_WORDS = new Set([
11437
11437
  "which",
11438
11438
  "why"
11439
11439
  ]);
11440
- var tokenize = (value) => value.toLowerCase().split(/[^a-z0-9]+/i).map((token) => token.trim()).filter((token) => !STOP_WORDS.has(token)).map((token) => token.endsWith("ies") && token.length > 3 ? `${token.slice(0, -3)}y` : token.endsWith("ing") && token.length > 5 ? token.slice(0, -3) : token.endsWith("ed") && token.length > 4 ? token.slice(0, -2) : token.endsWith("es") && token.length > 4 ? token.slice(0, -2) : token.endsWith("s") && token.length > 3 ? token.slice(0, -1) : token).filter((token) => token.length > 1);
11440
+ var wordSegmenter = new Intl.Segmenter("und", { granularity: "word" });
11441
+ var tokenize = (value) => value.normalize("NFC").toLowerCase().split(/[^\p{L}\p{M}\p{N}]+/u).flatMap((part) => /^[a-z0-9]+$/.test(part) ? [part] : [...wordSegmenter.segment(part)].filter((segment) => segment.isWordLike).map((segment) => segment.segment)).map((token) => token.trim()).filter((token) => !STOP_WORDS.has(token)).map((token) => !/^[a-z]+$/.test(token) ? token : token.endsWith("ies") && token.length > 3 ? `${token.slice(0, -3)}y` : token.endsWith("ing") && token.length > 5 ? token.slice(0, -3) : token.endsWith("ed") && token.length > 4 ? token.slice(0, -2) : token.endsWith("es") && token.length > 4 ? token.slice(0, -2) : token.endsWith("s") && token.length > 3 ? token.slice(0, -1) : token).filter((token) => token.length > 1 || /[^a-z]/.test(token));
11441
11442
  var BM25_K1 = 1.2;
11442
11443
  var BM25_B = 0.75;
11443
11444
  var collectMetadataStrings = (value) => {
@@ -11454,7 +11455,7 @@ var collectMetadataStrings = (value) => {
11454
11455
  };
11455
11456
  var normalizeSourceForLexical = (source) => source.replace(/[#/_.-]+/g, " ").replace(/\bmd\b/g, "markdown").replace(/\bpptx\b/g, "presentation").replace(/\bxlsx\b/g, "spreadsheet workbook sheet").replace(/\bmp3\b/g, "audio transcript media").replace(/\bmp4\b/g, "video transcript media").replace(/\bzip\b/g, "archive bundle");
11456
11457
  var toFieldText = (value) => collectMetadataStrings(value).filter(Boolean).join(" ");
11457
- var normalizeLooseText = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim().replace(/\s+/g, " ");
11458
+ var normalizeLooseText = (value) => value.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, " ").trim().replace(/\s+/g, " ");
11458
11459
  var scoreLoosePhraseMatch = (query, text) => {
11459
11460
  const normalizedQuery = normalizeLooseText(query);
11460
11461
  const normalizedText = normalizeLooseText(text ?? "");
@@ -20788,7 +20789,13 @@ var annotateRetrievalQueryOrigin = (input) => {
20788
20789
  }));
20789
20790
  };
20790
20791
  var shouldRunVectorRetrieval = (mode) => mode === "vector" || mode === "hybrid";
20791
- var shouldRunLexicalRetrieval = (mode, store) => mode === "lexical" || mode === "hybrid" && Boolean(store.queryLexical);
20792
+ var shouldRunLexicalRetrieval = (mode, store) => {
20793
+ if (mode === "vector")
20794
+ return false;
20795
+ if (!store.queryLexical)
20796
+ throw new Error(`Retrieval mode "${mode}" requires a store with queryLexical. Configure a lexical-capable adapter or explicitly request vector retrieval.`);
20797
+ return true;
20798
+ };
20792
20799
  var resolveRAGRetrievalStrategy = (retrievalStrategy) => {
20793
20800
  if (!retrievalStrategy) {
20794
20801
  return null;
@@ -23115,6 +23122,7 @@ var ragChat = (config) => {
23115
23122
  handleRAGRetrieved(ws, conversationId, assistantMessageId, sources, retrievalStartedAt, retrievedAt, retrievalDurationMs, trace);
23116
23123
  await streamAI(ws, conversationId, assistantMessageId, {
23117
23124
  completeMeta: includeCompleteSources ? { sources } : undefined,
23125
+ contextPolicy: config.contextPolicy,
23118
23126
  maxTurns: config.maxTurns,
23119
23127
  messages: [
23120
23128
  ...history,
@@ -29891,6 +29899,7 @@ var ragChat = (config) => {
29891
29899
  const messageWithContext = buildUserMessage(content, lastMessage.attachments, ragContext);
29892
29900
  const sseStream = streamAIToSSE(conversationId, assistantMessageId, {
29893
29901
  completeMeta: includeCompleteSources ? { sources } : undefined,
29902
+ contextPolicy: config.contextPolicy,
29894
29903
  maxTurns: config.maxTurns,
29895
29904
  messages: [...userHistory, messageWithContext],
29896
29905
  model,
@@ -31389,21 +31398,21 @@ var RAG_NATIVE_QUERY_CANDIDATE_LIMIT = 1000;
31389
31398
  var RAG_VECTOR_DIMENSIONS_DEFAULT = 24;
31390
31399
  var TWO_THIRDS = 2 / 3;
31391
31400
  export {
31392
- summarizeSQLiteCandidateCoverage,
31393
- resolveAdaptiveNativeCandidateLimit,
31394
- rankRAGLexicalMatches,
31395
- ragChat as ragPlugin,
31396
- ragChat,
31397
- querySimilarity,
31398
- planNativeCandidateSearchK,
31399
- planNativeCandidateSearchBackfillK,
31400
- normalizeVector,
31401
- matchesMetadataFilterRecord,
31402
- createRAGVector,
31403
- createRAGCollection,
31401
+ RAG_NATIVE_QUERY_CANDIDATE_LIMIT,
31404
31402
  RAG_VECTOR_DIMENSIONS_DEFAULT,
31405
- RAG_NATIVE_QUERY_CANDIDATE_LIMIT
31403
+ createRAGCollection,
31404
+ createRAGVector,
31405
+ matchesMetadataFilterRecord,
31406
+ normalizeVector,
31407
+ planNativeCandidateSearchBackfillK,
31408
+ planNativeCandidateSearchK,
31409
+ querySimilarity,
31410
+ ragChat,
31411
+ ragChat as ragPlugin,
31412
+ rankRAGLexicalMatches,
31413
+ resolveAdaptiveNativeCandidateLimit,
31414
+ summarizeSQLiteCandidateCoverage
31406
31415
  };
31407
31416
 
31408
- //# debugId=D25B3C804028B59464756E2164756E21
31417
+ //# debugId=5D1CC4781115DD5864756E2164756E21
31409
31418
  //# sourceMappingURL=index.js.map