@elsium-ai/rag

RAG pipeline, document processing, embeddings, and vector stores for ElsiumAI.

Install

npm install @elsium-ai/rag @elsium-ai/core

What’s Inside

Category Exports
Types Document, DocumentMetadata, Chunk, ChunkMetadata, EmbeddingVector, EmbeddedChunk, RetrievalResult, QueryOptions, LoaderType, ChunkingStrategy, ChunkingConfig, EmbeddingConfig, VectorStoreConfig, RetrievalConfig, PdfLoaderOptions, GoogleEmbeddingsConfig, CohereEmbeddingsConfig, PgVectorStoreConfig, QdrantStoreConfig
Loaders textLoader, markdownLoader, htmlLoader, jsonLoader, csvLoader, pdfLoader, getLoader, DocumentLoader, BinaryDocumentLoader
Chunkers fixedSizeChunker, recursiveChunker, sentenceChunker, getChunker, Chunker
Embeddings createOpenAIEmbeddings, createGoogleEmbeddings, createCohereEmbeddings, createMockEmbeddings, getEmbeddingProvider, EmbeddingProvider
Vector Store createInMemoryStore, createPgVectorStore, createQdrantStore, cosineSimilarity, mmrRerank, VectorStore
Pipeline rag, RAGPipeline, RAGPipelineConfig, IngestResult

Types

Document

Represents a loaded document ready for chunking.

interface Document {
  id: string
  content: string
  metadata: DocumentMetadata
}

DocumentMetadata

Metadata attached to a document. Includes required fields plus arbitrary extra properties.

interface DocumentMetadata {
  source: string
  type: string
  title?: string
  language?: string
  createdAt?: string
  [key: string]: unknown
}

Chunk

A segment of a document produced by a chunker.

interface Chunk {
  id: string
  content: string
  documentId: string
  index: number
  metadata: ChunkMetadata
}

ChunkMetadata

Positional and token metadata for a chunk. Supports arbitrary extra properties.

interface ChunkMetadata {
  startChar: number
  endChar: number
  tokenEstimate: number
  [key: string]: unknown
}

EmbeddingVector

A numeric embedding vector with its dimensionality.

interface EmbeddingVector {
  values: number[]
  dimensions: number
}

EmbeddedChunk

A chunk that has been embedded. Extends Chunk with an embedding field.

interface EmbeddedChunk extends Chunk {
  embedding: EmbeddingVector
}

RetrievalResult

A single result returned from a vector store query, pairing a chunk with its relevance score.

interface RetrievalResult {
  chunk: Chunk
  score: number
  distance: number
}

QueryOptions

Options passed to a vector store query or pipeline query.

interface QueryOptions {
  topK?: number
  minScore?: number
  filter?: Record<string, unknown>
}

LoaderType

Union of supported document loader types.

type LoaderType = 'text' | 'markdown' | 'html' | 'json' | 'csv' | 'pdf'

ChunkingStrategy

Union of supported chunking strategies.

type ChunkingStrategy = 'fixed-size' | 'recursive' | 'sentence'

ChunkingConfig

Configuration object for creating a chunker via getChunker.

interface ChunkingConfig {
  strategy: ChunkingStrategy
  maxChunkSize?: number
  overlap?: number
  separator?: string
}

EmbeddingConfig

Configuration object for creating an embedding provider.

interface EmbeddingConfig {
  provider: string
  model?: string
  apiKey?: string
  baseUrl?: string
  dimensions?: number
  batchSize?: number
}

VectorStoreConfig

Configuration object for specifying a vector store backend.

interface VectorStoreConfig {
  provider: string
  connectionString?: string
  tableName?: string
  dimensions?: number
}

RetrievalConfig

Configuration for retrieval behavior within a RAG pipeline.

interface RetrievalConfig {
  topK?: number
  minScore?: number
  strategy?: 'similarity' | 'mmr'
  mmrLambda?: number
}

Loaders

DocumentLoader

Interface implemented by all document loaders.

interface DocumentLoader {
  load(source: string, content: string): Document
}

BinaryDocumentLoader Interface

pdfLoader reads binary data asynchronously rather than a string, so it implements a separate interface.

interface BinaryDocumentLoader {
  load(source: string, data: Buffer | Uint8Array): Promise<Document>
}

textLoader

Creates a loader for plain text content.

function textLoader(): DocumentLoader

Returns: A DocumentLoader that produces documents with type: 'text'.

import { textLoader } from '@elsium-ai/rag'

const loader = textLoader()
const doc = loader.load('notes.txt', 'Hello, world!')

console.log(doc.metadata.type) // "text"

markdownLoader

Creates a loader for Markdown content. Automatically extracts the first # heading as the document title.

function markdownLoader(): DocumentLoader

Returns: A DocumentLoader that produces documents with type: 'markdown' and an optional title in metadata.

import { markdownLoader } from '@elsium-ai/rag'

const loader = markdownLoader()
const doc = loader.load('readme.md', '# My Project\n\nSome content here.')

console.log(doc.metadata.title) // "My Project"

htmlLoader

Creates a loader for HTML content. Strips tags, scripts, and styles, then extracts the <title> element as the document title.

function htmlLoader(): DocumentLoader

Returns: A DocumentLoader that produces documents with type: 'html', the HTML body converted to plain text, and an optional title in metadata.

import { htmlLoader } from '@elsium-ai/rag'

const loader = htmlLoader()
const doc = loader.load('page.html', '<html><title>Hello</title><body><p>World</p></body></html>')

console.log(doc.metadata.title) // "Hello"
console.log(doc.content)        // "World"

jsonLoader

Creates a loader for JSON content. Extracts text from a configurable content field and can pull additional metadata fields.

function jsonLoader(options?: {
  contentField?: string
  metadataFields?: string[]
}): DocumentLoader
Parameter Type Default Description
options.contentField string 'content' The JSON key to read text content from.
options.metadataFields string[] [] Additional top-level JSON keys to copy into document metadata.

Returns: A DocumentLoader that produces documents with type: 'json'. If the parsed JSON is an array, each item’s content field is joined with double newlines.

import { jsonLoader } from '@elsium-ai/rag'

const loader = jsonLoader({ contentField: 'text', metadataFields: ['author'] })
const doc = loader.load('data.json', JSON.stringify({ text: 'Hello', author: 'Alice' }))

console.log(doc.content)          // "Hello"
console.log(doc.metadata.author)  // "Alice"

csvLoader

Creates a loader for CSV content. Parses headers and rows, optionally selecting specific columns.

function csvLoader(options?: {
  separator?: string
  contentColumns?: string[]
}): DocumentLoader
Parameter Type Default Description
options.separator string ',' Column delimiter character.
options.contentColumns string[] all columns Subset of columns to include in the document text.

Returns: A DocumentLoader that produces documents with type: 'csv'. Metadata includes rowCount and columns.

import { csvLoader } from '@elsium-ai/rag'

const loader = csvLoader({ contentColumns: ['name', 'bio'] })
const doc = loader.load('people.csv', 'name,age,bio\nAlice,30,Engineer\nBob,25,Designer')

console.log(doc.metadata.rowCount) // 2
console.log(doc.metadata.columns)  // ["name", "age", "bio"]

getLoader

Factory function that returns a DocumentLoader for the given LoaderType.

function getLoader(type: LoaderType): DocumentLoader
Parameter Type Description
type LoaderType One of 'text', 'markdown', 'html', 'json', 'csv'.

Returns: The corresponding DocumentLoader with default options.

import { getLoader } from '@elsium-ai/rag'

const loader = getLoader('markdown')
const doc = loader.load('file.md', '# Title\n\nBody text.')

Chunkers

Chunker

Interface implemented by all chunking strategies.

interface Chunker {
  chunk(document: Document): Chunk[]
}

fixedSizeChunker

Creates a chunker that splits documents into fixed-size character windows with optional overlap.

function fixedSizeChunker(options?: {
  maxChunkSize?: number
  overlap?: number
}): Chunker
Parameter Type Default Description
options.maxChunkSize number 512 Maximum number of characters per chunk.
options.overlap number 0 Number of overlapping characters between consecutive chunks. Must be less than maxChunkSize.

Returns: A Chunker that produces fixed-size chunks.

import { fixedSizeChunker } from '@elsium-ai/rag'

const chunker = fixedSizeChunker({ maxChunkSize: 256, overlap: 32 })
// Assuming `doc` is a Document:
const chunks = chunker.chunk(doc)

recursiveChunker

Creates a chunker that recursively splits text using a hierarchy of separators (paragraph breaks, line breaks, sentence endings, spaces), falling back to fixed-size splitting when no separator fits.

function recursiveChunker(options?: {
  maxChunkSize?: number
  overlap?: number
  separators?: string[]
}): Chunker
Parameter Type Default Description
options.maxChunkSize number 512 Maximum number of characters per chunk.
options.overlap number 0 Number of overlapping characters between consecutive chunks. Must be less than maxChunkSize.
options.separators string[] ['\n\n', '\n', '. ', ' ', ''] Ordered list of separators to try.

Returns: A Chunker that recursively splits documents using natural boundaries.

import { recursiveChunker } from '@elsium-ai/rag'

const chunker = recursiveChunker({ maxChunkSize: 512, overlap: 50 })
const chunks = chunker.chunk(doc)

sentenceChunker

Creates a chunker that splits text on sentence boundaries (., !, ? followed by whitespace) and groups sentences into chunks up to maxChunkSize characters with optional sentence-level overlap.

function sentenceChunker(options?: {
  maxChunkSize?: number
  overlap?: number
}): Chunker
Parameter Type Default Description
options.maxChunkSize number 512 Maximum number of characters per chunk.
options.overlap number 1 Number of sentences to overlap between consecutive chunks.

Returns: A Chunker that groups sentences into chunks. Each chunk’s metadata includes sentenceCount.

import { sentenceChunker } from '@elsium-ai/rag'

const chunker = sentenceChunker({ maxChunkSize: 300, overlap: 2 })
const chunks = chunker.chunk(doc)

console.log(chunks[0].metadata.sentenceCount) // number of sentences in the first chunk

getChunker

Factory function that returns a Chunker for the given ChunkingConfig.

function getChunker(config: ChunkingConfig): Chunker
Parameter Type Description
config ChunkingConfig Chunking configuration specifying strategy, maxChunkSize, and overlap.

Returns: The corresponding Chunker instance.

import { getChunker } from '@elsium-ai/rag'

const chunker = getChunker({ strategy: 'recursive', maxChunkSize: 512, overlap: 50 })
const chunks = chunker.chunk(doc)

Embeddings

EmbeddingProvider

Interface implemented by all embedding providers.

interface EmbeddingProvider {
  readonly name: string
  readonly dimensions: number

  embed(text: string): Promise<EmbeddingVector>
  embedBatch(texts: string[]): Promise<EmbeddingVector[]>
}

createOpenAIEmbeddings

Creates an embedding provider backed by the OpenAI embeddings API.

function createOpenAIEmbeddings(config: EmbeddingConfig): EmbeddingProvider
Parameter Type Default Description
config.apiKey string (required) OpenAI API key. Throws if not provided.
config.model string 'text-embedding-3-small' Model name to use.
config.baseUrl string 'https://api.openai.com' API base URL (useful for proxies or compatible APIs).
config.dimensions number 1536 Desired embedding dimensions.
config.batchSize number 100 Maximum number of texts per API call when using embedBatch.

Returns: An EmbeddingProvider with name: 'openai'.

import { createOpenAIEmbeddings } from '@elsium-ai/rag'

const embeddings = createOpenAIEmbeddings({
  provider: 'openai',
  apiKey: process.env.OPENAI_API_KEY,
  model: 'text-embedding-3-small',
  dimensions: 1536,
})

const vector = await embeddings.embed('Hello, world!')
console.log(vector.dimensions) // 1536

createMockEmbeddings

Creates a deterministic mock embedding provider for testing. Produces normalized vectors derived from character codes.

function createMockEmbeddings(dims?: number): EmbeddingProvider
Parameter Type Default Description
dims number 128 Number of dimensions for generated embeddings.

Returns: An EmbeddingProvider with name: 'mock'.

import { createMockEmbeddings } from '@elsium-ai/rag'

const embeddings = createMockEmbeddings(64)
const vector = await embeddings.embed('test input')

console.log(vector.dimensions) // 64

getEmbeddingProvider

Factory function that returns an EmbeddingProvider for the given EmbeddingConfig. Supports 'openai' and 'mock' providers.

function getEmbeddingProvider(config: EmbeddingConfig): EmbeddingProvider
Parameter Type Description
config EmbeddingConfig Configuration specifying provider and provider-specific options.

Returns: The corresponding EmbeddingProvider. Throws an error for unknown providers.

import { getEmbeddingProvider } from '@elsium-ai/rag'

const embeddings = getEmbeddingProvider({ provider: 'mock', dimensions: 256 })
const vector = await embeddings.embed('sample text')

GoogleEmbeddingsConfig

Configuration for createGoogleEmbeddings — Google Generative AI embeddings (default text-embedding-004, 768 dimensions).

interface GoogleEmbeddingsConfig {
  apiKey: string         // required
  model?: string         // default: 'text-embedding-004'
  dimensions?: number    // default: 768 (sent as outputDimensionality)
}

CohereEmbeddingsConfig

Configuration for createCohereEmbeddings — Cohere embeddings (default embed-v4.0, 1024 dimensions).

interface CohereEmbeddingsConfig {
  apiKey: string         // required
  model?: string         // default: 'embed-v4.0'
  inputType?: string     // default: 'search_document'
}

Vector Store

VectorStore

Interface implemented by all vector store backends.

interface VectorStore {
  readonly name: string

  upsert(chunks: EmbeddedChunk[]): Promise<void>
  query(embedding: EmbeddingVector, options?: QueryOptions): Promise<RetrievalResult[]>
  delete(ids: string[]): Promise<void>
  clear(): Promise<void>
  count(): Promise<number>
}

createInMemoryStore

Creates an in-memory vector store backed by a Map. Supports cosine-similarity search and automatic eviction when exceeding maxChunks.

function createInMemoryStore(options?: {
  maxChunks?: number
}): VectorStore
Parameter Type Default Description
options.maxChunks number 100_000 Maximum number of embedded chunks to store. When exceeded, the oldest entries are evicted.

Returns: A VectorStore with name: 'in-memory'.

import { createInMemoryStore, createMockEmbeddings } from '@elsium-ai/rag'

const store = createInMemoryStore({ maxChunks: 10_000 })
const embeddings = createMockEmbeddings()

// Upsert embedded chunks
await store.upsert(embeddedChunks)

// Query
const queryVector = await embeddings.embed('search query')
const results = await store.query(queryVector, { topK: 5, minScore: 0.5 })

console.log(await store.count()) // number of stored chunks

cosineSimilarity

Computes the cosine similarity between two numeric vectors. Returns 0 if the vectors have different lengths or either has zero magnitude.

function cosineSimilarity(a: number[], b: number[]): number
Parameter Type Description
a number[] First vector.
b number[] Second vector.

Returns: A number between -1 and 1 representing cosine similarity.

import { cosineSimilarity } from '@elsium-ai/rag'

const similarity = cosineSimilarity([1, 0, 0], [1, 0, 0])
console.log(similarity) // 1

const orthogonal = cosineSimilarity([1, 0], [0, 1])
console.log(orthogonal) // 0

mmrRerank

Reranks retrieval results using Maximal Marginal Relevance (MMR) to balance relevance and diversity. Requires that each result includes its embedding field.

function mmrRerank(
  queryEmbedding: EmbeddingVector,
  results: Array<RetrievalResult & { embedding: EmbeddingVector }>,
  options?: { topK?: number; lambda?: number },
): RetrievalResult[]
Parameter Type Default Description
queryEmbedding EmbeddingVector -- The embedding of the query text.
results Array<RetrievalResult & { embedding: EmbeddingVector }> -- Candidate results, each with its embedding attached.
options.topK number 5 Number of results to return.
options.lambda number 0.7 Trade-off between relevance (1.0) and diversity (0.0).

Returns: An array of RetrievalResult objects reranked by MMR.

import { mmrRerank } from '@elsium-ai/rag'

const reranked = mmrRerank(queryEmbedding, candidateResults, {
  topK: 3,
  lambda: 0.5,
})

PgVectorStoreConfig

Configuration for createPgVectorStore — PostgreSQL + pgvector store (requires the pg peer dependency).

interface PgVectorStoreConfig {
  connectionString: string   // required
  tableName?: string         // default: 'vector_chunks' (validated identifier)
  dimensions?: number        // default: 1536
}

QdrantStoreConfig

Configuration for createQdrantStore — Qdrant store over its HTTP API.

interface QdrantStoreConfig {
  url: string                // required
  apiKey?: string
  collectionName: string     // required
  dimensions: number         // required
}

Pipeline

RAGPipelineConfig

Configuration object for creating a RAG pipeline via rag().

interface RAGPipelineConfig {
  loader?: LoaderType
  chunking?: ChunkingConfig
  embeddings: EmbeddingConfig
  store?: VectorStoreConfig
  retrieval?: RetrievalConfig
}

RAGPipeline

Interface representing a fully configured RAG pipeline with ingest and query capabilities.

interface RAGPipeline {
  ingest(source: string, content: string): Promise<IngestResult>
  ingestDocument(document: Document): Promise<IngestResult>
  query(text: string, options?: QueryOptions): Promise<RetrievalResult[]>
  clear(): Promise<void>
  count(): Promise<number>
  readonly embeddingProvider: EmbeddingProvider
  readonly vectorStore: VectorStore
}

IngestResult

Summary returned after ingesting a document into the pipeline.

interface IngestResult {
  documentId: string
  chunkCount: number
  totalTokens: number
}

rag

Creates a complete RAG pipeline that handles loading, chunking, embedding, storing, and querying documents in a single unified API.

function rag(config: RAGPipelineConfig): RAGPipeline
Parameter Type Default Description
config.loader LoaderType 'text' Document loader type.
config.chunking ChunkingConfig { strategy: 'recursive', maxChunkSize: 512, overlap: 50 } Chunking configuration.
config.embeddings EmbeddingConfig (required) Embedding provider configuration.
config.store VectorStoreConfig in-memory store Vector store configuration. External stores are not yet supported.
config.retrieval RetrievalConfig { topK: 5, minScore: 0, strategy: 'similarity' } Retrieval configuration.

Returns: A RAGPipeline instance.

import { rag } from '@elsium-ai/rag'

const pipeline = rag({
  loader: 'markdown',
  chunking: { strategy: 'recursive', maxChunkSize: 512, overlap: 50 },
  embeddings: { provider: 'openai', apiKey: process.env.OPENAI_API_KEY },
  retrieval: { topK: 5, minScore: 0.5 },
})

// Ingest a document
const result = await pipeline.ingest('docs/guide.md', markdownContent)
console.log(result.chunkCount)  // number of chunks created
console.log(result.totalTokens) // estimated total tokens

// Query the pipeline
const hits = await pipeline.query('How do I configure the pipeline?')
for (const hit of hits) {
  console.log(hit.score, hit.chunk.content)
}

// Pipeline also exposes its internals
console.log(pipeline.embeddingProvider.name) // "openai"
console.log(await pipeline.count())          // total chunks stored

Keyword Search (BM25)

In-memory lexical index using Okapi BM25 scoring, for keyword-based retrieval over chunks.

Export Signature Description
createBM25Index createBM25Index(opts?): BM25Index Create a BM25 keyword index.

BM25Index Interface

interface BM25Index {
  index(chunks: Chunk[]): void
  search(query: string, topK?: number): RetrievalResult[]  // topK default: 5
}

Options

createBM25Index({
  k1?: number,  // Term-frequency saturation (default: 1.2)
  b?: number,   // Length normalization (default: 0.75)
})

Example

import { createBM25Index } from '@elsium-ai/rag'

const bm25 = createBM25Index()
bm25.index(chunks)
const results = bm25.search('vector database', 5)
// => [{ chunk, score, distance: 0 }, ...]

Combine dense vector retrieval with BM25 keyword retrieval using Reciprocal Rank Fusion (RRF).

Export Signature Description
createHybridSearch createHybridSearch(vectorStore: VectorStore, bm25Index: BM25Index, config?: HybridSearchConfig): HybridSearch Fuse vector and BM25 results via RRF.

HybridSearch Interface

interface HybridSearch {
  search(
    query: string,
    queryEmbedding: EmbeddingVector,
    topK?: number,
  ): Promise<RetrievalResult[]>
}

HybridSearchConfig

interface HybridSearchConfig {
  k?: number             // RRF rank constant (default: 60)
  vectorWeight?: number  // Weight for vector results (default: 1)
  bm25Weight?: number    // Weight for BM25 results (default: 1)
  topK?: number          // Default result count (default: 10)
}

Example

import { createHybridSearch, createBM25Index, createInMemoryStore } from '@elsium-ai/rag'

const hybrid = createHybridSearch(vectorStore, bm25Index, {
  vectorWeight: 1,
  bm25Weight: 1,
})

const results = await hybrid.search('how to configure providers', queryEmbedding, 5)

Registries

Global registries let custom embedding providers and vector stores be selected by name (the built-in google, cohere, and qdrant integrations auto-register themselves).

Export Type Description
embeddingProviderRegistry Registry<EmbeddingProviderFactory> Name-keyed embedding provider factories.
vectorStoreRegistry Registry<VectorStoreFactory> Name-keyed vector store factories.
interface Registry<T> {
  register(name: string, factory: T): void
  get(name: string): T | undefined
  list(): string[]
}

type EmbeddingProviderFactory = (config: EmbeddingConfig) => EmbeddingProvider
type VectorStoreFactory = (config: Record<string, unknown>) => VectorStore

Example

import { embeddingProviderRegistry, vectorStoreRegistry } from '@elsium-ai/rag'

embeddingProviderRegistry.register('my-provider', (config) => createMyEmbeddings(config))
embeddingProviderRegistry.list() // => ['google', 'cohere', 'my-provider']

Part of ElsiumAI

This package is the RAG pipeline layer of the ElsiumAI framework. See the Getting Started guide or the Fundamentals for comprehensive coverage of every feature.

License

MIT