@voltx/rag 0.1.0 → 0.3.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.
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ <p align="center">
2
+ <strong>@voltx/rag</strong><br/>
3
+ <em>RAG pipeline — document loading, chunking, embedding, and retrieval</em>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <a href="https://www.npmjs.com/package/@voltx/rag"><img src="https://img.shields.io/npm/v/@voltx/rag?color=blue" alt="npm" /></a>
8
+ <a href="https://www.npmjs.com/package/@voltx/rag"><img src="https://img.shields.io/npm/dm/@voltx/rag" alt="downloads" /></a>
9
+ <a href="https://github.com/codewithshail/voltx/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@voltx/rag" alt="license" /></a>
10
+ </p>
11
+
12
+ ---
13
+
14
+ Production-ready Retrieval-Augmented Generation pipeline for the [VoltX](https://github.com/codewithshail/voltx) framework. Load documents, split into chunks, generate embeddings, store in a vector database, and retrieve relevant context for LLM prompts.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @voltx/rag
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```ts
25
+ import { createRAGPipeline, createEmbedder } from "@voltx/rag";
26
+ import { createVectorStore } from "@voltx/db";
27
+
28
+ const pipeline = createRAGPipeline({
29
+ embedder: createEmbedder({ model: "openai:text-embedding-3-small" }),
30
+ vectorStore: createVectorStore(),
31
+ });
32
+
33
+ // Ingest documents
34
+ await pipeline.ingest("Your long document text here...");
35
+
36
+ // Query with natural language
37
+ const { sources } = await pipeline.query("What is TypeScript?");
38
+
39
+ // Or get formatted context for an LLM prompt
40
+ const context = await pipeline.getContext("What is TypeScript?");
41
+ ```
42
+
43
+ ## Features
44
+
45
+ ### Document Loaders
46
+
47
+ | Loader | Description |
48
+ |--------|-------------|
49
+ | `TextLoader` | Plain text files or raw strings |
50
+ | `MarkdownLoader` | Markdown files (strips front-matter) |
51
+ | `JSONLoader` | JSON files (extracts text from configurable keys) |
52
+ | `WebLoader` | Fetches and extracts text from URLs |
53
+
54
+ ### Text Splitters
55
+
56
+ | Splitter | Description |
57
+ |----------|-------------|
58
+ | `RecursiveTextSplitter` | Smart splitting with separator hierarchy (recommended) |
59
+ | `MarkdownSplitter` | Heading-aware splitting, preserves header hierarchy |
60
+ | `CharacterSplitter` | Simple character-based splitting with overlap |
61
+
62
+ ### Fluent Document API
63
+
64
+ Inspired by [Mastra](https://mastra.ai)'s MDocument pattern:
65
+
66
+ ```ts
67
+ import { MDocument, createEmbedder } from "@voltx/rag";
68
+
69
+ const doc = MDocument.fromMarkdown("# Title\n\nContent here...");
70
+ const chunks = doc.chunk({ strategy: "markdown", chunkSize: 500 });
71
+ const embedded = await doc.embed(createEmbedder({ model: "openai:text-embedding-3-small" }));
72
+ ```
73
+
74
+ ### Embedder
75
+
76
+ Wraps `@voltx/ai` embedding functions into a simple interface:
77
+
78
+ ```ts
79
+ import { createEmbedder } from "@voltx/rag";
80
+
81
+ const embedder = createEmbedder({ model: "openai:text-embedding-3-small" });
82
+ const vector = await embedder.embed("Hello world");
83
+ const vectors = await embedder.embedBatch(["Hello", "World"]);
84
+ ```
85
+
86
+ ## Pipeline Options
87
+
88
+ ```ts
89
+ const pipeline = createRAGPipeline({
90
+ loader: new WebLoader(), // optional document loader
91
+ splitter: new RecursiveTextSplitter({ // text splitter (default: recursive)
92
+ chunkSize: 1000,
93
+ overlap: 200,
94
+ }),
95
+ embedder: createEmbedder({ model: "openai:text-embedding-3-small" }),
96
+ vectorStore: createVectorStore("pinecone", { indexName: "docs" }),
97
+ });
98
+
99
+ // Query with options
100
+ const results = await pipeline.query("question", { topK: 5, minScore: 0.7 });
101
+ ```
102
+
103
+ ## Part of VoltX
104
+
105
+ This package is part of the [VoltX](https://github.com/codewithshail/voltx) framework. See the [monorepo](https://github.com/codewithshail/voltx) for full documentation.
106
+
107
+ ## License
108
+
109
+ [MIT](https://github.com/codewithshail/voltx/blob/main/LICENSE) — Made by the [Promptly AI Team](https://buymeacoffee.com/promptlyai)
package/dist/index.d.mts CHANGED
@@ -4,53 +4,314 @@ interface DocumentChunk {
4
4
  id: string;
5
5
  content: string;
6
6
  metadata?: Record<string, unknown>;
7
+ embedding?: number[];
7
8
  }
8
9
  interface DocumentLoader {
9
10
  name: string;
10
- /** Load and return raw text from a source */
11
+ /** Load and return raw text from a source (file path, URL, or raw content) */
11
12
  load(source: string): Promise<string>;
12
13
  }
13
14
  interface TextSplitter {
14
15
  /** Split text into chunks */
15
16
  split(text: string): DocumentChunk[];
16
17
  }
18
+ interface CharacterSplitterOptions {
19
+ /** Maximum characters per chunk (default: 1000) */
20
+ chunkSize?: number;
21
+ /** Overlap between chunks in characters (default: 200) */
22
+ overlap?: number;
23
+ }
24
+ interface RecursiveSplitterOptions {
25
+ /** Maximum characters per chunk (default: 1000) */
26
+ chunkSize?: number;
27
+ /** Overlap between chunks in characters (default: 200) */
28
+ overlap?: number;
29
+ /**
30
+ * Separators to try in order of preference.
31
+ * Default: ["\n\n", "\n", ". ", " ", ""]
32
+ */
33
+ separators?: string[];
34
+ }
35
+ interface MarkdownSplitterOptions {
36
+ /** Maximum characters per chunk (default: 1500) */
37
+ chunkSize?: number;
38
+ /** Overlap between chunks in characters (default: 100) */
39
+ overlap?: number;
40
+ /** Whether to include header hierarchy in chunk metadata (default: true) */
41
+ includeHeaders?: boolean;
42
+ }
17
43
  interface Embedder {
18
44
  name: string;
19
- /** Generate embedding vector for text */
45
+ /** Generate embedding vector for a single text */
20
46
  embed(text: string): Promise<number[]>;
21
47
  /** Batch embed multiple texts */
22
48
  embedBatch(texts: string[]): Promise<number[][]>;
23
49
  }
50
+ interface EmbedderConfig {
51
+ /** Model string in "provider:model" format, e.g. "openai:text-embedding-3-small" */
52
+ model: string;
53
+ }
24
54
  interface RAGPipelineConfig {
55
+ /** Document loader (optional — if omitted, source is treated as raw text) */
25
56
  loader?: DocumentLoader;
57
+ /** Text splitter (default: RecursiveTextSplitter) */
26
58
  splitter?: TextSplitter;
59
+ /** Embedder — wraps @voltx/ai embed/embedMany */
27
60
  embedder: Embedder;
61
+ /** Vector store from @voltx/db */
28
62
  vectorStore: VectorStore;
29
63
  }
64
+ interface RAGQueryOptions {
65
+ /** Number of results to return (default: 5) */
66
+ topK?: number;
67
+ /** Minimum similarity score threshold (0-1, default: 0) */
68
+ minScore?: number;
69
+ /** Metadata filter */
70
+ filter?: Record<string, unknown>;
71
+ }
30
72
  interface RAGQueryResult {
31
- answer?: string;
73
+ /** Retrieved source documents */
32
74
  sources: VectorDocument[];
75
+ /** The query embedding (useful for debugging) */
76
+ queryEmbedding?: number[];
33
77
  }
78
+ interface RAGIngestResult {
79
+ /** Number of chunks ingested */
80
+ chunks: number;
81
+ /** Chunk IDs that were stored */
82
+ ids: string[];
83
+ }
84
+
85
+ /**
86
+ * Simple character-based text splitter with smart boundary detection.
87
+ * Tries to split at sentence/paragraph boundaries near the chunk size.
88
+ */
34
89
  declare class CharacterSplitter implements TextSplitter {
35
90
  private chunkSize;
36
91
  private overlap;
37
- constructor(chunkSize?: number, overlap?: number);
92
+ constructor(options?: CharacterSplitterOptions);
93
+ private findBreakPoint;
94
+ split(text: string): DocumentChunk[];
95
+ }
96
+ /**
97
+ * Recursively splits text using a hierarchy of separators.
98
+ * Tries to keep semantically related text together by splitting on
99
+ * paragraph breaks first, then newlines, then sentences, then words.
100
+ *
101
+ * This is the recommended splitter for generic text (same approach as
102
+ * LangChain's RecursiveCharacterTextSplitter).
103
+ */
104
+ declare class RecursiveTextSplitter implements TextSplitter {
105
+ private chunkSize;
106
+ private overlap;
107
+ private separators;
108
+ constructor(options?: RecursiveSplitterOptions);
109
+ split(text: string): DocumentChunk[];
38
110
  /**
39
- * Find the best split point near `pos` by looking for sentence/paragraph
40
- * boundaries first, then word boundaries, falling back to exact position.
111
+ * Recursively split text. Try the first separator; if any resulting piece
112
+ * is still too large, recurse with the next separator in the list.
41
113
  */
42
- private findBreakPoint;
114
+ private splitText;
115
+ /**
116
+ * Merge chunks with overlap to maintain context between adjacent chunks.
117
+ */
118
+ private mergeWithOverlap;
119
+ }
120
+ /**
121
+ * Markdown-aware text splitter that respects heading hierarchy.
122
+ * Splits on headings first, then falls back to paragraph/sentence boundaries
123
+ * within sections that exceed the chunk size.
124
+ */
125
+ declare class MarkdownSplitter implements TextSplitter {
126
+ private chunkSize;
127
+ private overlap;
128
+ private includeHeaders;
129
+ constructor(options?: MarkdownSplitterOptions);
43
130
  split(text: string): DocumentChunk[];
131
+ private splitByHeadings;
132
+ private buildHeaderPrefix;
44
133
  }
134
+
135
+ /**
136
+ * Loads plain text from a file path or treats the source as raw text.
137
+ */
138
+ declare class TextLoader implements DocumentLoader {
139
+ name: string;
140
+ load(source: string): Promise<string>;
141
+ }
142
+ /**
143
+ * Loads markdown files. Strips front-matter (YAML between --- delimiters)
144
+ * and returns the markdown body.
145
+ */
146
+ declare class MarkdownLoader implements DocumentLoader {
147
+ name: string;
148
+ load(source: string): Promise<string>;
149
+ }
150
+ interface JSONLoaderOptions {
151
+ /** JSON path keys to extract text from (e.g. ["content", "text", "body"]) */
152
+ textKeys?: string[];
153
+ /** Separator between extracted values (default: "\n\n") */
154
+ separator?: string;
155
+ }
156
+ /**
157
+ * Loads JSON files and extracts text content from specified keys.
158
+ * Handles both single objects and arrays of objects.
159
+ */
160
+ declare class JSONLoader implements DocumentLoader {
161
+ name: string;
162
+ private textKeys;
163
+ private separator;
164
+ constructor(options?: JSONLoaderOptions);
165
+ load(source: string): Promise<string>;
166
+ private extractTexts;
167
+ }
168
+ /**
169
+ * Fetches text content from a URL. Strips HTML tags for basic text extraction.
170
+ */
171
+ declare class WebLoader implements DocumentLoader {
172
+ name: string;
173
+ load(source: string): Promise<string>;
174
+ private stripHTML;
175
+ }
176
+
177
+ /**
178
+ * Creates an embedder that uses @voltx/ai under the hood.
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * const embedder = createEmbedder({ model: "openai:text-embedding-3-small" });
183
+ * const vector = await embedder.embed("Hello world");
184
+ * const vectors = await embedder.embedBatch(["Hello", "World"]);
185
+ * ```
186
+ */
187
+ declare function createEmbedder(config: EmbedderConfig): Embedder;
188
+
189
+ type ChunkStrategy = "recursive" | "character" | "markdown";
190
+ interface ChunkOptions {
191
+ /** Chunking strategy (default: "recursive") */
192
+ strategy?: ChunkStrategy;
193
+ /** Maximum chunk size in characters */
194
+ chunkSize?: number;
195
+ /** Overlap between chunks in characters */
196
+ overlap?: number;
197
+ /** Custom separators (recursive strategy only) */
198
+ separators?: string[];
199
+ /** Include header hierarchy in metadata (markdown strategy only) */
200
+ includeHeaders?: boolean;
201
+ }
202
+ /**
203
+ * Fluent document processing class.
204
+ * Create from various formats, chunk, and embed in a pipeline.
205
+ *
206
+ * @example
207
+ * ```ts
208
+ * const doc = MDocument.fromText("Your long document...");
209
+ * const chunks = doc.chunk({ strategy: "recursive", chunkSize: 500 });
210
+ *
211
+ * // Or from markdown
212
+ * const mdDoc = MDocument.fromMarkdown("# Title\n\nContent...");
213
+ * const mdChunks = mdDoc.chunk({ strategy: "markdown" });
214
+ * ```
215
+ */
216
+ declare class MDocument {
217
+ private content;
218
+ private format;
219
+ private chunks;
220
+ private constructor();
221
+ /** Create from plain text */
222
+ static fromText(content: string): MDocument;
223
+ /** Create from markdown */
224
+ static fromMarkdown(content: string): MDocument;
225
+ /** Create from JSON string */
226
+ static fromJSON(content: string): MDocument;
227
+ /** Create from HTML (strips tags) */
228
+ static fromHTML(html: string): MDocument;
229
+ /** Get the raw content */
230
+ getContent(): string;
231
+ /** Get the document format */
232
+ getFormat(): string;
233
+ /**
234
+ * Split the document into chunks using the specified strategy.
235
+ * Returns the chunks and caches them for subsequent embed() calls.
236
+ */
237
+ chunk(options?: ChunkOptions): DocumentChunk[];
238
+ /**
239
+ * Embed the chunks using the provided embedder.
240
+ * Must call chunk() first.
241
+ */
242
+ embed(embedder: Embedder): Promise<DocumentChunk[]>;
243
+ /** Get cached chunks (null if chunk() hasn't been called) */
244
+ getChunks(): DocumentChunk[] | null;
245
+ private defaultStrategy;
246
+ private createSplitter;
247
+ }
248
+
249
+ /**
250
+ * Calculate cosine similarity between two embedding vectors.
251
+ * Returns a value between -1 and 1, where 1 means identical direction.
252
+ *
253
+ * @example
254
+ * ```ts
255
+ * const score = cosineSimilarity(embeddingA, embeddingB);
256
+ * // score ≈ 0.95 means very similar
257
+ * ```
258
+ */
259
+ declare function cosineSimilarity(a: number[], b: number[]): number;
260
+
45
261
  declare class RAGPipeline {
46
- private config;
262
+ private loader;
263
+ private splitter;
264
+ private embedder;
265
+ private vectorStore;
47
266
  constructor(config: RAGPipelineConfig);
48
- /** Ingest a document: load → split → embed → store */
49
- ingest(source: string): Promise<number>;
50
- /** Query: embed question → search vector store → return sources */
51
- query(question: string, topK?: number): Promise<RAGQueryResult>;
267
+ /**
268
+ * Ingest a document: load → split → embed (batch) → store in vector DB.
269
+ *
270
+ * @param source - File path, URL, or raw text (depends on loader)
271
+ * @param idPrefix - Optional prefix for chunk IDs (default: "doc")
272
+ * @returns Number of chunks ingested and their IDs
273
+ */
274
+ ingest(source: string, idPrefix?: string): Promise<RAGIngestResult>;
275
+ /**
276
+ * Query: embed question → search vector store → return ranked sources.
277
+ *
278
+ * @param question - The user's question
279
+ * @param options - Query options (topK, minScore)
280
+ */
281
+ query(question: string, options?: RAGQueryOptions): Promise<RAGQueryResult>;
282
+ /**
283
+ * Convenience: query + format sources into a context string for LLM prompts.
284
+ */
285
+ getContext(question: string, options?: RAGQueryOptions): Promise<string>;
286
+ /**
287
+ * Delete documents from the vector store by IDs.
288
+ */
289
+ delete(ids: string[]): Promise<void>;
52
290
  }
291
+ /**
292
+ * Create a RAG pipeline.
293
+ *
294
+ * @example
295
+ * ```ts
296
+ * import { createRAGPipeline, createEmbedder } from "@voltx/rag";
297
+ * import { createVectorStore } from "@voltx/db";
298
+ *
299
+ * const pipeline = createRAGPipeline({
300
+ * embedder: createEmbedder({ model: "openai:text-embedding-3-small" }),
301
+ * vectorStore: createVectorStore("pinecone", { indexName: "my-index" }),
302
+ * });
303
+ *
304
+ * // Ingest documents
305
+ * await pipeline.ingest("Your long document text here...");
306
+ *
307
+ * // Query
308
+ * const { sources } = await pipeline.query("What is TypeScript?");
309
+ *
310
+ * // Or get formatted context for LLM
311
+ * const context = await pipeline.getContext("What is TypeScript?");
312
+ * ```
313
+ */
53
314
  declare function createRAGPipeline(config: RAGPipelineConfig): RAGPipeline;
54
- declare const VERSION = "0.1.0";
315
+ declare const VERSION = "0.3.0";
55
316
 
56
- export { CharacterSplitter, type DocumentChunk, type DocumentLoader, type Embedder, RAGPipeline, type RAGPipelineConfig, type RAGQueryResult, type TextSplitter, VERSION, createRAGPipeline };
317
+ export { CharacterSplitter, type CharacterSplitterOptions, type ChunkOptions, type ChunkStrategy, type DocumentChunk, type DocumentLoader, type Embedder, type EmbedderConfig, JSONLoader, type JSONLoaderOptions, MDocument, MarkdownLoader, MarkdownSplitter, type MarkdownSplitterOptions, type RAGIngestResult, RAGPipeline, type RAGPipelineConfig, type RAGQueryOptions, type RAGQueryResult, type RecursiveSplitterOptions, RecursiveTextSplitter, TextLoader, type TextSplitter, VERSION, WebLoader, cosineSimilarity, createEmbedder, createRAGPipeline };