@opensaas/stack-rag 0.1.6
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/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +10 -0
- package/CLAUDE.md +565 -0
- package/LICENSE +21 -0
- package/README.md +406 -0
- package/dist/config/index.d.ts +63 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +94 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/plugin.d.ts +38 -0
- package/dist/config/plugin.d.ts.map +1 -0
- package/dist/config/plugin.js +215 -0
- package/dist/config/plugin.js.map +1 -0
- package/dist/config/plugin.test.d.ts +2 -0
- package/dist/config/plugin.test.d.ts.map +1 -0
- package/dist/config/plugin.test.js +554 -0
- package/dist/config/plugin.test.js.map +1 -0
- package/dist/config/types.d.ts +249 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +5 -0
- package/dist/config/types.js.map +1 -0
- package/dist/fields/embedding.d.ts +85 -0
- package/dist/fields/embedding.d.ts.map +1 -0
- package/dist/fields/embedding.js +81 -0
- package/dist/fields/embedding.js.map +1 -0
- package/dist/fields/embedding.test.d.ts +2 -0
- package/dist/fields/embedding.test.d.ts.map +1 -0
- package/dist/fields/embedding.test.js +323 -0
- package/dist/fields/embedding.test.js.map +1 -0
- package/dist/fields/index.d.ts +6 -0
- package/dist/fields/index.d.ts.map +1 -0
- package/dist/fields/index.js +5 -0
- package/dist/fields/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +19 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +18 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/providers/index.d.ts +38 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +68 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/ollama.d.ts +49 -0
- package/dist/providers/ollama.d.ts.map +1 -0
- package/dist/providers/ollama.js +151 -0
- package/dist/providers/ollama.js.map +1 -0
- package/dist/providers/openai.d.ts +41 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +126 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/providers.test.d.ts +2 -0
- package/dist/providers/providers.test.d.ts.map +1 -0
- package/dist/providers/providers.test.js +224 -0
- package/dist/providers/providers.test.js.map +1 -0
- package/dist/providers/types.d.ts +88 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/runtime/batch.d.ts +183 -0
- package/dist/runtime/batch.d.ts.map +1 -0
- package/dist/runtime/batch.js +240 -0
- package/dist/runtime/batch.js.map +1 -0
- package/dist/runtime/batch.test.d.ts +2 -0
- package/dist/runtime/batch.test.d.ts.map +1 -0
- package/dist/runtime/batch.test.js +251 -0
- package/dist/runtime/batch.test.js.map +1 -0
- package/dist/runtime/chunking.d.ts +42 -0
- package/dist/runtime/chunking.d.ts.map +1 -0
- package/dist/runtime/chunking.js +264 -0
- package/dist/runtime/chunking.js.map +1 -0
- package/dist/runtime/chunking.test.d.ts +2 -0
- package/dist/runtime/chunking.test.d.ts.map +1 -0
- package/dist/runtime/chunking.test.js +212 -0
- package/dist/runtime/chunking.test.js.map +1 -0
- package/dist/runtime/embeddings.d.ts +147 -0
- package/dist/runtime/embeddings.d.ts.map +1 -0
- package/dist/runtime/embeddings.js +201 -0
- package/dist/runtime/embeddings.js.map +1 -0
- package/dist/runtime/embeddings.test.d.ts +2 -0
- package/dist/runtime/embeddings.test.d.ts.map +1 -0
- package/dist/runtime/embeddings.test.js +366 -0
- package/dist/runtime/embeddings.test.js.map +1 -0
- package/dist/runtime/index.d.ts +14 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +18 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/search.d.ts +135 -0
- package/dist/runtime/search.d.ts.map +1 -0
- package/dist/runtime/search.js +101 -0
- package/dist/runtime/search.js.map +1 -0
- package/dist/storage/index.d.ts +41 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +73 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/json.d.ts +34 -0
- package/dist/storage/json.d.ts.map +1 -0
- package/dist/storage/json.js +82 -0
- package/dist/storage/json.js.map +1 -0
- package/dist/storage/pgvector.d.ts +53 -0
- package/dist/storage/pgvector.d.ts.map +1 -0
- package/dist/storage/pgvector.js +168 -0
- package/dist/storage/pgvector.js.map +1 -0
- package/dist/storage/sqlite-vss.d.ts +49 -0
- package/dist/storage/sqlite-vss.d.ts.map +1 -0
- package/dist/storage/sqlite-vss.js +148 -0
- package/dist/storage/sqlite-vss.js.map +1 -0
- package/dist/storage/storage.test.d.ts +2 -0
- package/dist/storage/storage.test.d.ts.map +1 -0
- package/dist/storage/storage.test.js +440 -0
- package/dist/storage/storage.test.js.map +1 -0
- package/dist/storage/types.d.ts +79 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +49 -0
- package/dist/storage/types.js.map +1 -0
- package/package.json +82 -0
- package/src/config/index.ts +116 -0
- package/src/config/plugin.test.ts +664 -0
- package/src/config/plugin.ts +257 -0
- package/src/config/types.ts +283 -0
- package/src/fields/embedding.test.ts +408 -0
- package/src/fields/embedding.ts +150 -0
- package/src/fields/index.ts +6 -0
- package/src/index.ts +33 -0
- package/src/mcp/index.ts +21 -0
- package/src/providers/index.ts +81 -0
- package/src/providers/ollama.ts +186 -0
- package/src/providers/openai.ts +161 -0
- package/src/providers/providers.test.ts +275 -0
- package/src/providers/types.ts +100 -0
- package/src/runtime/batch.test.ts +332 -0
- package/src/runtime/batch.ts +424 -0
- package/src/runtime/chunking.test.ts +258 -0
- package/src/runtime/chunking.ts +334 -0
- package/src/runtime/embeddings.test.ts +441 -0
- package/src/runtime/embeddings.ts +380 -0
- package/src/runtime/index.ts +51 -0
- package/src/runtime/search.ts +243 -0
- package/src/storage/index.ts +86 -0
- package/src/storage/json.ts +106 -0
- package/src/storage/pgvector.ts +206 -0
- package/src/storage/sqlite-vss.ts +193 -0
- package/src/storage/storage.test.ts +521 -0
- package/src/storage/types.ts +126 -0
- package/tsconfig.json +13 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# @opensaas/stack-rag
|
|
2
|
+
|
|
3
|
+
RAG (Retrieval-Augmented Generation) and AI embeddings integration for OpenSaas Stack.
|
|
4
|
+
|
|
5
|
+
Turn your OpenSaas app into a knowledge base with semantic search capabilities powered by vector embeddings.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 🤖 **Multiple Embedding Providers**: OpenAI, Ollama (local), or bring your own
|
|
10
|
+
- 🗄️ **Flexible Storage**: pgvector, SQLite VSS, or JSON-based (for development)
|
|
11
|
+
- 🔍 **Semantic Search**: Natural language queries with relevance scoring
|
|
12
|
+
- 🔐 **Access Control**: All searches respect your existing access control rules
|
|
13
|
+
- ⚡ **Automatic Embeddings**: Auto-generate embeddings when content changes
|
|
14
|
+
- 🛠️ **MCP Integration**: Semantic search tools for AI assistants
|
|
15
|
+
- 📊 **Multiple Abstraction Levels**: From automatic "magic" to low-level control
|
|
16
|
+
- ✂️ **Text Chunking**: Multiple strategies for splitting long documents
|
|
17
|
+
- 🚀 **Batch Processing**: Rate-limited batch embedding generation with progress tracking
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add @opensaas/stack-rag
|
|
23
|
+
|
|
24
|
+
# Install your chosen embedding provider
|
|
25
|
+
pnpm add openai # For OpenAI embeddings
|
|
26
|
+
# OR use Ollama (no package needed - just run Ollama locally)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
### 1. Configure RAG in your OpenSaas app
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// opensaas.config.ts
|
|
35
|
+
import { config, list } from '@opensaas/stack-core'
|
|
36
|
+
import { text } from '@opensaas/stack-core/fields'
|
|
37
|
+
import { ragPlugin, openaiEmbeddings, pgvectorStorage } from '@opensaas/stack-rag'
|
|
38
|
+
import { embedding } from '@opensaas/stack-rag/fields'
|
|
39
|
+
|
|
40
|
+
export default config({
|
|
41
|
+
plugins: [
|
|
42
|
+
ragPlugin({
|
|
43
|
+
provider: openaiEmbeddings({
|
|
44
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
45
|
+
model: 'text-embedding-3-small',
|
|
46
|
+
}),
|
|
47
|
+
storage: pgvectorStorage(),
|
|
48
|
+
}),
|
|
49
|
+
],
|
|
50
|
+
db: {
|
|
51
|
+
provider: 'postgresql',
|
|
52
|
+
url: process.env.DATABASE_URL!,
|
|
53
|
+
},
|
|
54
|
+
lists: {
|
|
55
|
+
Article: list({
|
|
56
|
+
fields: {
|
|
57
|
+
title: text({ validation: { isRequired: true } }),
|
|
58
|
+
content: text({ validation: { isRequired: true } }),
|
|
59
|
+
// Embedding field with automatic generation
|
|
60
|
+
contentEmbedding: embedding({
|
|
61
|
+
sourceField: 'content', // Auto-embed when content changes
|
|
62
|
+
provider: 'openai',
|
|
63
|
+
dimensions: 1536,
|
|
64
|
+
autoGenerate: true,
|
|
65
|
+
}),
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Generate schema and push to database
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pnpm generate
|
|
76
|
+
pnpm db:push
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Create content (embeddings generated automatically)
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { getContext } from '@/.opensaas/context'
|
|
83
|
+
|
|
84
|
+
const context = await getContext()
|
|
85
|
+
|
|
86
|
+
// Embedding is automatically generated from content
|
|
87
|
+
await context.db.article.create({
|
|
88
|
+
data: {
|
|
89
|
+
title: 'Introduction to AI',
|
|
90
|
+
content: 'Artificial intelligence is...',
|
|
91
|
+
// No need to manually create embedding - it's automatic!
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 4. Perform semantic search
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { createEmbeddingProvider, createVectorStorage } from '@opensaas/stack-rag'
|
|
100
|
+
|
|
101
|
+
export async function searchArticles(query: string) {
|
|
102
|
+
const context = await getContext()
|
|
103
|
+
|
|
104
|
+
// Generate embedding for search query
|
|
105
|
+
const provider = createEmbeddingProvider({
|
|
106
|
+
type: 'openai',
|
|
107
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
108
|
+
})
|
|
109
|
+
const queryVector = await provider.embed(query)
|
|
110
|
+
|
|
111
|
+
// Search for similar articles
|
|
112
|
+
const storage = createVectorStorage({ type: 'json' })
|
|
113
|
+
const results = await storage.search('Article', 'contentEmbedding', queryVector, {
|
|
114
|
+
limit: 10,
|
|
115
|
+
minScore: 0.7,
|
|
116
|
+
context, // Access control enforced
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
return results
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Local Development with Ollama
|
|
124
|
+
|
|
125
|
+
For local development without API costs:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { config, list } from '@opensaas/stack-core'
|
|
129
|
+
import { ragPlugin, ollamaEmbeddings, jsonStorage } from '@opensaas/stack-rag'
|
|
130
|
+
|
|
131
|
+
export default config({
|
|
132
|
+
plugins: [
|
|
133
|
+
ragPlugin({
|
|
134
|
+
provider: ollamaEmbeddings({
|
|
135
|
+
baseURL: 'http://localhost:11434',
|
|
136
|
+
model: 'nomic-embed-text',
|
|
137
|
+
}),
|
|
138
|
+
storage: jsonStorage(), // No database extensions needed
|
|
139
|
+
}),
|
|
140
|
+
],
|
|
141
|
+
// ... rest of config
|
|
142
|
+
})
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
First, install and run Ollama:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Install Ollama from https://ollama.ai
|
|
149
|
+
ollama pull nomic-embed-text
|
|
150
|
+
ollama serve
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Storage Backends
|
|
154
|
+
|
|
155
|
+
### JSON Storage (Development)
|
|
156
|
+
|
|
157
|
+
Good for development and small datasets. No database extensions needed.
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
storage: jsonStorage()
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### pgvector (Production PostgreSQL)
|
|
164
|
+
|
|
165
|
+
Best for production apps using PostgreSQL. Requires pgvector extension.
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
storage: pgvectorStorage({ distanceFunction: 'cosine' })
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Setup:
|
|
172
|
+
|
|
173
|
+
```sql
|
|
174
|
+
CREATE EXTENSION vector;
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### SQLite VSS (SQLite)
|
|
178
|
+
|
|
179
|
+
Good for SQLite-based apps. Requires sqlite-vss extension.
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
storage: sqliteVssStorage({ distanceFunction: 'cosine' })
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## MCP Integration
|
|
186
|
+
|
|
187
|
+
Automatic semantic search tools for AI assistants:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { config, list } from '@opensaas/stack-core'
|
|
191
|
+
import { text } from '@opensaas/stack-core/fields'
|
|
192
|
+
import { ragPlugin, openaiEmbeddings } from '@opensaas/stack-rag'
|
|
193
|
+
import { embedding } from '@opensaas/stack-rag/fields'
|
|
194
|
+
|
|
195
|
+
export default config({
|
|
196
|
+
plugins: [
|
|
197
|
+
ragPlugin({
|
|
198
|
+
provider: openaiEmbeddings({ apiKey: process.env.OPENAI_API_KEY! }),
|
|
199
|
+
enableMcpTools: true, // Enables semantic_search_article tool
|
|
200
|
+
}),
|
|
201
|
+
],
|
|
202
|
+
mcp: {
|
|
203
|
+
enabled: true,
|
|
204
|
+
auth: { type: 'better-auth', loginPage: '/sign-in' },
|
|
205
|
+
},
|
|
206
|
+
lists: {
|
|
207
|
+
Article: list({
|
|
208
|
+
fields: {
|
|
209
|
+
content: text(),
|
|
210
|
+
contentEmbedding: embedding({
|
|
211
|
+
sourceField: 'content',
|
|
212
|
+
autoGenerate: true,
|
|
213
|
+
}),
|
|
214
|
+
},
|
|
215
|
+
}),
|
|
216
|
+
},
|
|
217
|
+
})
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Runtime Utilities
|
|
221
|
+
|
|
222
|
+
The `@opensaas/stack-rag/runtime` package provides high-level utilities for common RAG operations.
|
|
223
|
+
|
|
224
|
+
### Semantic Search
|
|
225
|
+
|
|
226
|
+
Simplified API that handles embedding generation and search in one call:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { semanticSearch } from '@opensaas/stack-rag/runtime'
|
|
230
|
+
import { createEmbeddingProvider, createVectorStorage } from '@opensaas/stack-rag'
|
|
231
|
+
import { getContext } from '@/.opensaas/context'
|
|
232
|
+
|
|
233
|
+
const results = await semanticSearch({
|
|
234
|
+
listKey: 'Article',
|
|
235
|
+
fieldName: 'contentEmbedding',
|
|
236
|
+
query: 'articles about machine learning',
|
|
237
|
+
provider: createEmbeddingProvider({ type: 'openai', apiKey: process.env.OPENAI_API_KEY! }),
|
|
238
|
+
storage: createVectorStorage({ type: 'pgvector' }),
|
|
239
|
+
context: await getContext(),
|
|
240
|
+
limit: 10,
|
|
241
|
+
minScore: 0.7,
|
|
242
|
+
})
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Find Similar Items
|
|
246
|
+
|
|
247
|
+
Find items similar to a given item by ID:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
import { findSimilar } from '@opensaas/stack-rag/runtime'
|
|
251
|
+
|
|
252
|
+
const similar = await findSimilar({
|
|
253
|
+
listKey: 'Article',
|
|
254
|
+
fieldName: 'contentEmbedding',
|
|
255
|
+
itemId: 'article-123',
|
|
256
|
+
storage: createVectorStorage({ type: 'pgvector' }),
|
|
257
|
+
context: await getContext(),
|
|
258
|
+
limit: 5,
|
|
259
|
+
excludeSelf: true, // Don't include the source article
|
|
260
|
+
})
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Text Chunking
|
|
264
|
+
|
|
265
|
+
Split long documents into smaller chunks for embedding:
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { chunkText } from '@opensaas/stack-rag/runtime'
|
|
269
|
+
|
|
270
|
+
// Recursive chunking (respects paragraph/sentence boundaries)
|
|
271
|
+
const chunks = chunkText(longDocument, {
|
|
272
|
+
strategy: 'recursive',
|
|
273
|
+
chunkSize: 1000,
|
|
274
|
+
chunkOverlap: 200,
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
// Sentence-based chunking (preserves sentences)
|
|
278
|
+
const chunks = chunkText(document, {
|
|
279
|
+
strategy: 'sentence',
|
|
280
|
+
chunkSize: 500,
|
|
281
|
+
chunkOverlap: 100,
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
// Token-aware chunking (for token limits)
|
|
285
|
+
const chunks = chunkText(document, {
|
|
286
|
+
strategy: 'token-aware',
|
|
287
|
+
tokenLimit: 500, // ~500 tokens per chunk
|
|
288
|
+
chunkOverlap: 50,
|
|
289
|
+
})
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Batch Processing with Rate Limiting
|
|
293
|
+
|
|
294
|
+
Process large batches of texts with automatic rate limiting:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
import { batchProcess } from '@opensaas/stack-rag/runtime'
|
|
298
|
+
|
|
299
|
+
const result = await batchProcess({
|
|
300
|
+
provider: createEmbeddingProvider({ type: 'openai', apiKey: process.env.OPENAI_API_KEY! }),
|
|
301
|
+
texts: largeArrayOfTexts,
|
|
302
|
+
batchSize: 10,
|
|
303
|
+
rateLimit: 60, // 60 requests per minute
|
|
304
|
+
onProgress: (progress) => {
|
|
305
|
+
console.log(`Progress: ${progress.percentage}% (${progress.processed}/${progress.total})`)
|
|
306
|
+
},
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
console.log(`Successfully processed: ${result.stats.successful}`)
|
|
310
|
+
console.log(`Failed: ${result.stats.failed}`)
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Generate Embeddings with Chunking
|
|
314
|
+
|
|
315
|
+
Generate embeddings for long texts with automatic chunking:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { generateEmbedding } from '@opensaas/stack-rag/runtime'
|
|
319
|
+
|
|
320
|
+
// Single embedding
|
|
321
|
+
const embedding = await generateEmbedding({
|
|
322
|
+
provider: createEmbeddingProvider({ type: 'openai', apiKey: process.env.OPENAI_API_KEY! }),
|
|
323
|
+
text: 'Short text',
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
// Chunked embeddings for long documents
|
|
327
|
+
const chunkedEmbeddings = await generateEmbedding({
|
|
328
|
+
provider: createEmbeddingProvider({ type: 'openai', apiKey: process.env.OPENAI_API_KEY! }),
|
|
329
|
+
text: veryLongDocument,
|
|
330
|
+
enableChunking: true,
|
|
331
|
+
chunking: { chunkSize: 1000, chunkOverlap: 200 },
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
// Each chunk has its embedding
|
|
335
|
+
for (const { chunk, embedding } of chunkedEmbeddings) {
|
|
336
|
+
console.log(`Chunk ${chunk.index}: ${chunk.text.substring(0, 50)}...`)
|
|
337
|
+
await saveChunkEmbedding(chunk, embedding)
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## API Reference
|
|
342
|
+
|
|
343
|
+
### Main Exports (`@opensaas/stack-rag`)
|
|
344
|
+
|
|
345
|
+
- `ragPlugin(config)` - RAG plugin for OpenSaas Stack (v0.2.0+)
|
|
346
|
+
- `openaiEmbeddings(config)` - OpenAI embedding provider helper
|
|
347
|
+
- `ollamaEmbeddings(config)` - Ollama embedding provider helper
|
|
348
|
+
- `pgvectorStorage(config)` - pgvector storage helper
|
|
349
|
+
- `sqliteVssStorage(config)` - SQLite VSS storage helper
|
|
350
|
+
- `jsonStorage()` - JSON-based storage helper
|
|
351
|
+
|
|
352
|
+
### Field Types (`@opensaas/stack-rag/fields`)
|
|
353
|
+
|
|
354
|
+
- `embedding(options)` - Vector embedding field type
|
|
355
|
+
|
|
356
|
+
### Providers (`@opensaas/stack-rag/providers`)
|
|
357
|
+
|
|
358
|
+
- `createEmbeddingProvider(config)` - Factory for creating embedding providers
|
|
359
|
+
- `registerEmbeddingProvider(type, factory)` - Register custom providers
|
|
360
|
+
|
|
361
|
+
### Storage (`@opensaas/stack-rag/storage`)
|
|
362
|
+
|
|
363
|
+
- `createVectorStorage(config)` - Factory for creating storage backends
|
|
364
|
+
- `registerVectorStorage(type, factory)` - Register custom storage backends
|
|
365
|
+
|
|
366
|
+
### Runtime Utilities (`@opensaas/stack-rag/runtime`)
|
|
367
|
+
|
|
368
|
+
- `semanticSearch(options)` - High-level semantic search
|
|
369
|
+
- `findSimilar(options)` - Find similar items by ID
|
|
370
|
+
- `chunkText(text, options)` - Text chunking utilities
|
|
371
|
+
- `generateEmbedding(options)` - Generate embeddings with chunking support
|
|
372
|
+
- `generateEmbeddings(options)` - Batch embedding generation
|
|
373
|
+
- `batchProcess(options)` - Batch processing with rate limiting
|
|
374
|
+
- `RateLimiter` - Rate limiting utility class
|
|
375
|
+
- `ProcessingQueue` - Concurrent processing queue
|
|
376
|
+
|
|
377
|
+
## Documentation
|
|
378
|
+
|
|
379
|
+
See [CLAUDE.md](./CLAUDE.md) for comprehensive documentation including:
|
|
380
|
+
|
|
381
|
+
- All abstraction levels (high-level to low-level)
|
|
382
|
+
- Custom embedding providers
|
|
383
|
+
- Custom storage backends
|
|
384
|
+
- Text chunking strategies
|
|
385
|
+
- Performance optimization
|
|
386
|
+
- Testing patterns
|
|
387
|
+
- Migration guides
|
|
388
|
+
|
|
389
|
+
## Examples
|
|
390
|
+
|
|
391
|
+
See `examples/rag-demo` for a complete working example with:
|
|
392
|
+
|
|
393
|
+
- Document search
|
|
394
|
+
- Chatbot with knowledge base
|
|
395
|
+
- MCP integration
|
|
396
|
+
- Multiple embedding providers
|
|
397
|
+
|
|
398
|
+
## Repository
|
|
399
|
+
|
|
400
|
+
- **GitHub**: https://github.com/OpenSaasAU/stack
|
|
401
|
+
- **Docs**: https://stack.opensaas.au/
|
|
402
|
+
- **Issues**: https://github.com/OpenSaasAU/stack/issues
|
|
403
|
+
|
|
404
|
+
## License
|
|
405
|
+
|
|
406
|
+
MIT
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { RAGConfig, NormalizedRAGConfig, VectorStorageConfig, OpenAIEmbeddingConfig, OllamaEmbeddingConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Normalize RAG configuration with defaults
|
|
4
|
+
*/
|
|
5
|
+
export declare function normalizeRAGConfig(config: RAGConfig): NormalizedRAGConfig;
|
|
6
|
+
/**
|
|
7
|
+
* Helper to create OpenAI embedding provider configuration
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const provider = openaiEmbeddings({
|
|
12
|
+
* apiKey: process.env.OPENAI_API_KEY,
|
|
13
|
+
* model: 'text-embedding-3-small'
|
|
14
|
+
* })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function openaiEmbeddings(config: Omit<OpenAIEmbeddingConfig, 'type'>): OpenAIEmbeddingConfig;
|
|
18
|
+
/**
|
|
19
|
+
* Helper to create Ollama embedding provider configuration
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const provider = ollamaEmbeddings({
|
|
24
|
+
* baseURL: 'http://localhost:11434',
|
|
25
|
+
* model: 'nomic-embed-text'
|
|
26
|
+
* })
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function ollamaEmbeddings(config?: Omit<OllamaEmbeddingConfig, 'type'>): OllamaEmbeddingConfig;
|
|
30
|
+
/**
|
|
31
|
+
* Helper to create pgvector storage configuration
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const storage = pgvectorStorage({ distanceFunction: 'cosine' })
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function pgvectorStorage(config?: {
|
|
39
|
+
distanceFunction?: 'cosine' | 'l2' | 'inner_product';
|
|
40
|
+
}): VectorStorageConfig;
|
|
41
|
+
/**
|
|
42
|
+
* Helper to create SQLite VSS storage configuration
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const storage = sqliteVssStorage({ distanceFunction: 'cosine' })
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function sqliteVssStorage(config?: {
|
|
50
|
+
distanceFunction?: 'cosine' | 'l2';
|
|
51
|
+
}): VectorStorageConfig;
|
|
52
|
+
/**
|
|
53
|
+
* Helper to create JSON-based storage configuration
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const storage = jsonStorage()
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function jsonStorage(): VectorStorageConfig;
|
|
61
|
+
export type { RAGConfig, NormalizedRAGConfig };
|
|
62
|
+
export * from './types.js';
|
|
63
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,YAAY,CAAA;AAEnB;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,mBAAmB,CAczE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC1C,qBAAqB,CAKvB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,qBAAqB,CAMvB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE;IACvC,gBAAgB,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,eAAe,CAAA;CACrD,GAAG,mBAAmB,CAKtB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE;IACxC,gBAAgB,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;CACnC,GAAG,mBAAmB,CAKtB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,IAAI,mBAAmB,CAEjD;AAED,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAA;AAC9C,cAAc,YAAY,CAAA"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize RAG configuration with defaults
|
|
3
|
+
*/
|
|
4
|
+
export function normalizeRAGConfig(config) {
|
|
5
|
+
return {
|
|
6
|
+
provider: config.provider || null,
|
|
7
|
+
providers: config.providers || {},
|
|
8
|
+
storage: config.storage || { type: 'json' },
|
|
9
|
+
chunking: {
|
|
10
|
+
strategy: config.chunking?.strategy || 'recursive',
|
|
11
|
+
maxTokens: config.chunking?.maxTokens || 500,
|
|
12
|
+
overlap: config.chunking?.overlap || 50,
|
|
13
|
+
},
|
|
14
|
+
enableMcpTools: config.enableMcpTools ?? true,
|
|
15
|
+
batchSize: config.batchSize || 10,
|
|
16
|
+
rateLimit: config.rateLimit || 100,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Helper to create OpenAI embedding provider configuration
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const provider = openaiEmbeddings({
|
|
25
|
+
* apiKey: process.env.OPENAI_API_KEY,
|
|
26
|
+
* model: 'text-embedding-3-small'
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function openaiEmbeddings(config) {
|
|
31
|
+
return {
|
|
32
|
+
type: 'openai',
|
|
33
|
+
...config,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Helper to create Ollama embedding provider configuration
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const provider = ollamaEmbeddings({
|
|
42
|
+
* baseURL: 'http://localhost:11434',
|
|
43
|
+
* model: 'nomic-embed-text'
|
|
44
|
+
* })
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function ollamaEmbeddings(config) {
|
|
48
|
+
return {
|
|
49
|
+
type: 'ollama',
|
|
50
|
+
baseURL: config?.baseURL || 'http://localhost:11434',
|
|
51
|
+
model: config?.model || 'nomic-embed-text',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Helper to create pgvector storage configuration
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const storage = pgvectorStorage({ distanceFunction: 'cosine' })
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function pgvectorStorage(config) {
|
|
63
|
+
return {
|
|
64
|
+
type: 'pgvector',
|
|
65
|
+
distanceFunction: config?.distanceFunction || 'cosine',
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Helper to create SQLite VSS storage configuration
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const storage = sqliteVssStorage({ distanceFunction: 'cosine' })
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function sqliteVssStorage(config) {
|
|
77
|
+
return {
|
|
78
|
+
type: 'sqlite-vss',
|
|
79
|
+
distanceFunction: config?.distanceFunction || 'cosine',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Helper to create JSON-based storage configuration
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const storage = jsonStorage()
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export function jsonStorage() {
|
|
91
|
+
return { type: 'json' };
|
|
92
|
+
}
|
|
93
|
+
export * from './types.js';
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;QACjC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;QACjC,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;QAC3C,QAAQ,EAAE;YACR,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,IAAI,WAAW;YAClD,SAAS,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,IAAI,GAAG;YAC5C,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE;SACxC;QACD,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,IAAI;QAC7C,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;QACjC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,GAAG;KACnC,CAAA;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAA2C;IAE3C,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,GAAG,MAAM;KACV,CAAA;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAA4C;IAE5C,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,wBAAwB;QACpD,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,kBAAkB;KAC3C,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,MAE/B;IACC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,IAAI,QAAQ;KACvD,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAEhC;IACC,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,IAAI,QAAQ;KACvD,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACzB,CAAC;AAGD,cAAc,YAAY,CAAA"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Plugin } from '@opensaas/stack-core';
|
|
2
|
+
import type { RAGConfig } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* RAG plugin for OpenSaas Stack
|
|
5
|
+
* Provides vector embeddings, semantic search, and automatic embedding generation
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { config, list } from '@opensaas/stack-core'
|
|
10
|
+
* import { text } from '@opensaas/stack-core/fields'
|
|
11
|
+
* import { ragPlugin, openaiEmbeddings, pgvectorStorage } from '@opensaas/stack-rag'
|
|
12
|
+
* import { embedding } from '@opensaas/stack-rag/fields'
|
|
13
|
+
*
|
|
14
|
+
* export default config({
|
|
15
|
+
* plugins: [
|
|
16
|
+
* ragPlugin({
|
|
17
|
+
* provider: openaiEmbeddings({ apiKey: process.env.OPENAI_API_KEY }),
|
|
18
|
+
* storage: pgvectorStorage()
|
|
19
|
+
* })
|
|
20
|
+
* ],
|
|
21
|
+
* db: { provider: 'postgresql', url: process.env.DATABASE_URL },
|
|
22
|
+
* lists: {
|
|
23
|
+
* Article: list({
|
|
24
|
+
* fields: {
|
|
25
|
+
* content: text(),
|
|
26
|
+
* contentEmbedding: embedding({
|
|
27
|
+
* sourceField: 'content',
|
|
28
|
+
* provider: 'openai',
|
|
29
|
+
* autoGenerate: true
|
|
30
|
+
* })
|
|
31
|
+
* }
|
|
32
|
+
* })
|
|
33
|
+
* }
|
|
34
|
+
* })
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function ragPlugin(config: RAGConfig): Plugin;
|
|
38
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/config/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAuB,MAAM,YAAY,CAAA;AAIhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAkLnD"}
|