@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
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import type { Plugin } from '@opensaas/stack-core'
|
|
2
|
+
import type { RAGConfig, NormalizedRAGConfig } from './types.js'
|
|
3
|
+
import { normalizeRAGConfig } from './index.js'
|
|
4
|
+
import { createEmbeddingProvider } from '../providers/index.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* RAG plugin for OpenSaas Stack
|
|
8
|
+
* Provides vector embeddings, semantic search, and automatic embedding generation
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { config, list } from '@opensaas/stack-core'
|
|
13
|
+
* import { text } from '@opensaas/stack-core/fields'
|
|
14
|
+
* import { ragPlugin, openaiEmbeddings, pgvectorStorage } from '@opensaas/stack-rag'
|
|
15
|
+
* import { embedding } from '@opensaas/stack-rag/fields'
|
|
16
|
+
*
|
|
17
|
+
* export default config({
|
|
18
|
+
* plugins: [
|
|
19
|
+
* ragPlugin({
|
|
20
|
+
* provider: openaiEmbeddings({ apiKey: process.env.OPENAI_API_KEY }),
|
|
21
|
+
* storage: pgvectorStorage()
|
|
22
|
+
* })
|
|
23
|
+
* ],
|
|
24
|
+
* db: { provider: 'postgresql', url: process.env.DATABASE_URL },
|
|
25
|
+
* lists: {
|
|
26
|
+
* Article: list({
|
|
27
|
+
* fields: {
|
|
28
|
+
* content: text(),
|
|
29
|
+
* contentEmbedding: embedding({
|
|
30
|
+
* sourceField: 'content',
|
|
31
|
+
* provider: 'openai',
|
|
32
|
+
* autoGenerate: true
|
|
33
|
+
* })
|
|
34
|
+
* }
|
|
35
|
+
* })
|
|
36
|
+
* }
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function ragPlugin(config: RAGConfig): Plugin {
|
|
41
|
+
const normalized = normalizeRAGConfig(config)
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
name: 'rag',
|
|
45
|
+
version: '0.1.0',
|
|
46
|
+
|
|
47
|
+
init: async (context) => {
|
|
48
|
+
// Find all embedding fields with autoGenerate enabled
|
|
49
|
+
for (const [listName, listConfig] of Object.entries(context.config.lists)) {
|
|
50
|
+
for (const [fieldName, fieldConfig] of Object.entries(listConfig.fields)) {
|
|
51
|
+
if (
|
|
52
|
+
fieldConfig.type === 'embedding' &&
|
|
53
|
+
(fieldConfig as { autoGenerate?: boolean }).autoGenerate
|
|
54
|
+
) {
|
|
55
|
+
const embeddingConfig = fieldConfig as {
|
|
56
|
+
sourceField?: string
|
|
57
|
+
provider?: string
|
|
58
|
+
dimensions?: number
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const sourceField = embeddingConfig.sourceField
|
|
62
|
+
if (!sourceField) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`RAG plugin: Field "${listName}.${fieldName}" has autoGenerate enabled but no sourceField specified`,
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Inject afterOperation hook to auto-generate embeddings
|
|
69
|
+
context.extendList(listName, {
|
|
70
|
+
hooks: {
|
|
71
|
+
resolveInput: async (args) => {
|
|
72
|
+
// Skip if item is missing
|
|
73
|
+
if (!args.resolvedData)
|
|
74
|
+
throw new Error('RAG plugin: Missing resolvedData in resolveInput hook')
|
|
75
|
+
|
|
76
|
+
const sourceText = args.resolvedData[sourceField] as string | undefined
|
|
77
|
+
const currentEmbedding = args.resolvedData[fieldName] as {
|
|
78
|
+
vector: number[]
|
|
79
|
+
metadata: { sourceHash?: string }
|
|
80
|
+
} | null
|
|
81
|
+
|
|
82
|
+
// Skip if source text is empty
|
|
83
|
+
if (!sourceText) return args.resolvedData
|
|
84
|
+
|
|
85
|
+
// Check if we need to regenerate (source text changed)
|
|
86
|
+
const sourceHash = await hashText(sourceText)
|
|
87
|
+
if (currentEmbedding && currentEmbedding.metadata.sourceHash === sourceHash) {
|
|
88
|
+
// Source text hasn't changed, skip regeneration
|
|
89
|
+
return args.resolvedData
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Get provider for this field
|
|
93
|
+
const providerName = embeddingConfig.provider || 'default'
|
|
94
|
+
const providerConfig =
|
|
95
|
+
providerName === 'default'
|
|
96
|
+
? normalized.provider
|
|
97
|
+
: normalized.providers[providerName] || normalized.provider
|
|
98
|
+
|
|
99
|
+
if (!providerConfig) {
|
|
100
|
+
console.warn(
|
|
101
|
+
`RAG plugin: No provider configured for field "${listName}.${fieldName}"`,
|
|
102
|
+
)
|
|
103
|
+
return args.resolvedData
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Generate embedding
|
|
107
|
+
const provider = createEmbeddingProvider(providerConfig)
|
|
108
|
+
const vector = await provider.embed(sourceText)
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
...args.resolvedData,
|
|
112
|
+
[fieldName]: {
|
|
113
|
+
vector,
|
|
114
|
+
metadata: {
|
|
115
|
+
model: provider.model,
|
|
116
|
+
provider: provider.type,
|
|
117
|
+
dimensions: provider.dimensions,
|
|
118
|
+
generatedAt: new Date().toISOString(),
|
|
119
|
+
sourceHash,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Register MCP tools if enabled
|
|
131
|
+
if (normalized.enableMcpTools && context.registerMcpTool) {
|
|
132
|
+
// Find all lists with embedding fields
|
|
133
|
+
for (const [listName, listConfig] of Object.entries(context.config.lists)) {
|
|
134
|
+
const embeddingFields = Object.entries(listConfig.fields).filter(
|
|
135
|
+
([, fieldConfig]) => fieldConfig.type === 'embedding',
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if (embeddingFields.length > 0) {
|
|
139
|
+
// Register semantic search tool for this list
|
|
140
|
+
const toolName = `semantic_search_${listName.toLowerCase()}`
|
|
141
|
+
|
|
142
|
+
context.registerMcpTool({
|
|
143
|
+
name: toolName,
|
|
144
|
+
description: `Search ${listName} using natural language (semantic search)`,
|
|
145
|
+
inputSchema: {
|
|
146
|
+
type: 'object',
|
|
147
|
+
properties: {
|
|
148
|
+
query: { type: 'string', description: 'Natural language search query' },
|
|
149
|
+
limit: { type: 'number', description: 'Maximum results', default: 10 },
|
|
150
|
+
minScore: {
|
|
151
|
+
type: 'number',
|
|
152
|
+
description: 'Minimum similarity score (0-1)',
|
|
153
|
+
default: 0.5,
|
|
154
|
+
},
|
|
155
|
+
field: {
|
|
156
|
+
type: 'string',
|
|
157
|
+
description: 'Embedding field to search',
|
|
158
|
+
default: embeddingFields[0][0],
|
|
159
|
+
enum: embeddingFields.map(([name]) => name),
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
required: ['query'],
|
|
163
|
+
},
|
|
164
|
+
handler: async ({ input, context }) => {
|
|
165
|
+
const { query, limit = 10, minScore = 0.5, field = embeddingFields[0][0] } = input
|
|
166
|
+
|
|
167
|
+
// Get provider
|
|
168
|
+
const providerConfig = normalized.provider
|
|
169
|
+
if (!providerConfig) {
|
|
170
|
+
throw new Error('RAG plugin: No default provider configured')
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Generate query embedding
|
|
174
|
+
const provider = createEmbeddingProvider(providerConfig)
|
|
175
|
+
const queryVector = await provider.embed(query)
|
|
176
|
+
|
|
177
|
+
// Search using configured storage backend
|
|
178
|
+
// Note: This is a simplified implementation
|
|
179
|
+
// Full implementation would use VectorStorage interface
|
|
180
|
+
const dbKey = listName.charAt(0).toLowerCase() + listName.slice(1)
|
|
181
|
+
const allItems = await context.db[dbKey].findMany()
|
|
182
|
+
|
|
183
|
+
// Calculate cosine similarity for each item
|
|
184
|
+
const results = allItems
|
|
185
|
+
.map((item: { [key: string]: { vector: number[] } | null }) => {
|
|
186
|
+
const embedding = item[field]
|
|
187
|
+
if (!embedding || !embedding.vector) return null
|
|
188
|
+
|
|
189
|
+
const score = cosineSimilarity(queryVector, embedding.vector)
|
|
190
|
+
return { item, score }
|
|
191
|
+
})
|
|
192
|
+
.filter((r: { score: number } | null) => r !== null && r.score >= minScore)
|
|
193
|
+
.sort((a: { score: number }, b: { score: number }) => b.score - a.score)
|
|
194
|
+
.slice(0, limit)
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
results: results.map((r: { item: unknown; score: number }) => {
|
|
198
|
+
// Ensure item is an object before spreading
|
|
199
|
+
const item = r.item as Record<string, unknown>
|
|
200
|
+
return {
|
|
201
|
+
...item,
|
|
202
|
+
_similarity: r.score,
|
|
203
|
+
}
|
|
204
|
+
}),
|
|
205
|
+
count: results.length,
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Store RAG config for runtime access
|
|
214
|
+
// Access at runtime via: config._pluginData.rag
|
|
215
|
+
context.setPluginData<NormalizedRAGConfig>('rag', normalized)
|
|
216
|
+
},
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Hash text using SHA-256 for change detection
|
|
222
|
+
*/
|
|
223
|
+
async function hashText(text: string): Promise<string> {
|
|
224
|
+
// Simple hash implementation
|
|
225
|
+
// In production, could use crypto.subtle.digest for better performance
|
|
226
|
+
let hash = 0
|
|
227
|
+
for (let i = 0; i < text.length; i++) {
|
|
228
|
+
const char = text.charCodeAt(i)
|
|
229
|
+
hash = (hash << 5) - hash + char
|
|
230
|
+
hash = hash & hash // Convert to 32-bit integer
|
|
231
|
+
}
|
|
232
|
+
return hash.toString(36)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Calculate cosine similarity between two vectors
|
|
237
|
+
*/
|
|
238
|
+
function cosineSimilarity(a: number[], b: number[]): number {
|
|
239
|
+
if (a.length !== b.length) {
|
|
240
|
+
throw new Error('Vectors must have same dimensions')
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let dotProduct = 0
|
|
244
|
+
let normA = 0
|
|
245
|
+
let normB = 0
|
|
246
|
+
|
|
247
|
+
for (let i = 0; i < a.length; i++) {
|
|
248
|
+
dotProduct += a[i] * b[i]
|
|
249
|
+
normA += a[i] * a[i]
|
|
250
|
+
normB += b[i] * b[i]
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const denominator = Math.sqrt(normA) * Math.sqrt(normB)
|
|
254
|
+
if (denominator === 0) return 0
|
|
255
|
+
|
|
256
|
+
return dotProduct / denominator
|
|
257
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RAG (Retrieval-Augmented Generation) configuration types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Text chunking strategies for splitting documents
|
|
7
|
+
*/
|
|
8
|
+
export type ChunkingStrategy = 'none' | 'recursive' | 'sentence' | 'sliding-window'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Chunking configuration options
|
|
12
|
+
*/
|
|
13
|
+
export type ChunkingConfig = {
|
|
14
|
+
/**
|
|
15
|
+
* Chunking strategy to use
|
|
16
|
+
* @default 'recursive'
|
|
17
|
+
*/
|
|
18
|
+
strategy?: ChunkingStrategy
|
|
19
|
+
/**
|
|
20
|
+
* Maximum tokens per chunk
|
|
21
|
+
* @default 500
|
|
22
|
+
*/
|
|
23
|
+
maxTokens?: number
|
|
24
|
+
/**
|
|
25
|
+
* Overlap between chunks (tokens)
|
|
26
|
+
* Only applies to 'recursive' and 'sliding-window' strategies
|
|
27
|
+
* @default 50
|
|
28
|
+
*/
|
|
29
|
+
overlap?: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Embedding provider names
|
|
34
|
+
*/
|
|
35
|
+
export type EmbeddingProviderName = 'openai' | 'ollama' | string
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* OpenAI embedding model options
|
|
39
|
+
*/
|
|
40
|
+
export type OpenAIEmbeddingModel =
|
|
41
|
+
| 'text-embedding-3-small'
|
|
42
|
+
| 'text-embedding-3-large'
|
|
43
|
+
| 'text-embedding-ada-002'
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* OpenAI embedding provider configuration
|
|
47
|
+
*/
|
|
48
|
+
export type OpenAIEmbeddingConfig = {
|
|
49
|
+
type: 'openai'
|
|
50
|
+
/**
|
|
51
|
+
* OpenAI API key
|
|
52
|
+
*/
|
|
53
|
+
apiKey: string
|
|
54
|
+
/**
|
|
55
|
+
* Model to use for embeddings
|
|
56
|
+
* @default 'text-embedding-3-small'
|
|
57
|
+
*/
|
|
58
|
+
model?: OpenAIEmbeddingModel
|
|
59
|
+
/**
|
|
60
|
+
* Organization ID (optional)
|
|
61
|
+
*/
|
|
62
|
+
organization?: string
|
|
63
|
+
/**
|
|
64
|
+
* Base URL for API requests (optional, for Azure or custom endpoints)
|
|
65
|
+
*/
|
|
66
|
+
baseURL?: string
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Ollama embedding provider configuration
|
|
71
|
+
*/
|
|
72
|
+
export type OllamaEmbeddingConfig = {
|
|
73
|
+
type: 'ollama'
|
|
74
|
+
/**
|
|
75
|
+
* Ollama API endpoint
|
|
76
|
+
* @default 'http://localhost:11434'
|
|
77
|
+
*/
|
|
78
|
+
baseURL?: string
|
|
79
|
+
/**
|
|
80
|
+
* Model to use for embeddings
|
|
81
|
+
* @default 'nomic-embed-text'
|
|
82
|
+
*/
|
|
83
|
+
model?: string
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Generic embedding provider configuration
|
|
88
|
+
* For custom or third-party providers
|
|
89
|
+
*/
|
|
90
|
+
export type CustomEmbeddingConfig = {
|
|
91
|
+
type: string
|
|
92
|
+
[key: string]: unknown
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Embedding provider configuration union
|
|
97
|
+
*/
|
|
98
|
+
export type EmbeddingProviderConfig =
|
|
99
|
+
| OpenAIEmbeddingConfig
|
|
100
|
+
| OllamaEmbeddingConfig
|
|
101
|
+
| CustomEmbeddingConfig
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Vector storage backend types
|
|
105
|
+
*/
|
|
106
|
+
export type VectorStorageBackend = 'pgvector' | 'sqlite-vss' | 'json' | string
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* pgvector storage configuration
|
|
110
|
+
*/
|
|
111
|
+
export type PgVectorStorageConfig = {
|
|
112
|
+
type: 'pgvector'
|
|
113
|
+
/**
|
|
114
|
+
* Distance function for similarity search
|
|
115
|
+
* @default 'cosine'
|
|
116
|
+
*/
|
|
117
|
+
distanceFunction?: 'cosine' | 'l2' | 'inner_product'
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* SQLite VSS storage configuration
|
|
122
|
+
*/
|
|
123
|
+
export type SqliteVssStorageConfig = {
|
|
124
|
+
type: 'sqlite-vss'
|
|
125
|
+
/**
|
|
126
|
+
* Distance function for similarity search
|
|
127
|
+
* @default 'cosine'
|
|
128
|
+
*/
|
|
129
|
+
distanceFunction?: 'cosine' | 'l2'
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* JSON-based storage (in-memory search)
|
|
134
|
+
* Stores vectors as JSON and uses JavaScript for similarity search
|
|
135
|
+
* Good for development and small datasets
|
|
136
|
+
*/
|
|
137
|
+
export type JsonStorageConfig = {
|
|
138
|
+
type: 'json'
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Generic storage configuration for custom backends
|
|
143
|
+
*/
|
|
144
|
+
export type CustomStorageConfig = {
|
|
145
|
+
type: string
|
|
146
|
+
[key: string]: unknown
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Vector storage configuration union
|
|
151
|
+
*/
|
|
152
|
+
export type VectorStorageConfig =
|
|
153
|
+
| PgVectorStorageConfig
|
|
154
|
+
| SqliteVssStorageConfig
|
|
155
|
+
| JsonStorageConfig
|
|
156
|
+
| CustomStorageConfig
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Main RAG configuration
|
|
160
|
+
*/
|
|
161
|
+
export type RAGConfig = {
|
|
162
|
+
/**
|
|
163
|
+
* Default embedding provider
|
|
164
|
+
* Can be overridden per field
|
|
165
|
+
*/
|
|
166
|
+
provider?: EmbeddingProviderConfig
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Named embedding providers
|
|
170
|
+
* Allows using different providers for different fields
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* providers: {
|
|
175
|
+
* openai: openaiEmbeddings({ apiKey: '...' }),
|
|
176
|
+
* ollama: ollamaEmbeddings({ model: 'nomic-embed-text' })
|
|
177
|
+
* }
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
providers?: Record<string, EmbeddingProviderConfig>
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Vector storage backend
|
|
184
|
+
* @default { type: 'json' }
|
|
185
|
+
*/
|
|
186
|
+
storage?: VectorStorageConfig
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Default chunking configuration
|
|
190
|
+
* Can be overridden per field
|
|
191
|
+
*/
|
|
192
|
+
chunking?: ChunkingConfig
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Whether to enable MCP tools for semantic search
|
|
196
|
+
* Requires MCP to be enabled in main config
|
|
197
|
+
* @default true
|
|
198
|
+
*/
|
|
199
|
+
enableMcpTools?: boolean
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Batch size for embedding generation
|
|
203
|
+
* @default 10
|
|
204
|
+
*/
|
|
205
|
+
batchSize?: number
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Rate limit (requests per minute) for embedding API calls
|
|
209
|
+
* @default 100
|
|
210
|
+
*/
|
|
211
|
+
rateLimit?: number
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Normalized RAG configuration with defaults applied
|
|
216
|
+
*/
|
|
217
|
+
export type NormalizedRAGConfig = {
|
|
218
|
+
provider: EmbeddingProviderConfig | null
|
|
219
|
+
providers: Record<string, EmbeddingProviderConfig>
|
|
220
|
+
storage: VectorStorageConfig
|
|
221
|
+
chunking: Required<ChunkingConfig>
|
|
222
|
+
enableMcpTools: boolean
|
|
223
|
+
batchSize: number
|
|
224
|
+
rateLimit: number
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Embedding metadata stored alongside vectors
|
|
229
|
+
*/
|
|
230
|
+
export type EmbeddingMetadata = {
|
|
231
|
+
/**
|
|
232
|
+
* Embedding model used
|
|
233
|
+
*/
|
|
234
|
+
model: string
|
|
235
|
+
/**
|
|
236
|
+
* Provider type (openai, ollama, etc.)
|
|
237
|
+
*/
|
|
238
|
+
provider: string
|
|
239
|
+
/**
|
|
240
|
+
* Vector dimensions
|
|
241
|
+
*/
|
|
242
|
+
dimensions: number
|
|
243
|
+
/**
|
|
244
|
+
* When the embedding was generated
|
|
245
|
+
*/
|
|
246
|
+
generatedAt: string
|
|
247
|
+
/**
|
|
248
|
+
* Hash of source text (for detecting changes)
|
|
249
|
+
*/
|
|
250
|
+
sourceHash?: string
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Stored embedding with vector and metadata
|
|
255
|
+
*/
|
|
256
|
+
export type StoredEmbedding = {
|
|
257
|
+
/**
|
|
258
|
+
* The embedding vector
|
|
259
|
+
*/
|
|
260
|
+
vector: number[]
|
|
261
|
+
/**
|
|
262
|
+
* Metadata about the embedding
|
|
263
|
+
*/
|
|
264
|
+
metadata: EmbeddingMetadata
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Semantic search result
|
|
269
|
+
*/
|
|
270
|
+
export type SearchResult<T = unknown> = {
|
|
271
|
+
/**
|
|
272
|
+
* The matching item
|
|
273
|
+
*/
|
|
274
|
+
item: T
|
|
275
|
+
/**
|
|
276
|
+
* Similarity score (0-1, higher is more similar)
|
|
277
|
+
*/
|
|
278
|
+
score: number
|
|
279
|
+
/**
|
|
280
|
+
* Distance metric (depends on storage backend)
|
|
281
|
+
*/
|
|
282
|
+
distance: number
|
|
283
|
+
}
|