@larkup/vector-stores 0.1.14
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/package.json +27 -0
- package/src/adapters/base.ts +48 -0
- package/src/adapters/chroma.ts +402 -0
- package/src/adapters/lancedb.ts +220 -0
- package/src/adapters/pinecone.ts +487 -0
- package/src/factory.ts +55 -0
- package/src/registry.ts +414 -0
- package/test-chroma-cloud.js +21 -0
- package/test-chroma-cloud.mjs +15 -0
- package/tsconfig.json +22 -0
- package/tsconfig.tsbuildinfo +1 -0
package/src/registry.ts
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import type { IndexType, VectorStoreDescriptor, VectorStoreId } from "@larkup/core/types"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Declarative registry of supported vector stores.
|
|
5
|
+
*
|
|
6
|
+
* This single object powers two very different consumers:
|
|
7
|
+
* 1. The Configuration form — renders `fields` dynamically so each store
|
|
8
|
+
* asks for *exactly* the credentials/config it needs.
|
|
9
|
+
* 2. The Phase 4 dependency resolver — reads `serverDependencies` so the
|
|
10
|
+
* GENERATED server only ships the deps for the selected store
|
|
11
|
+
* (pick Pinecone => no LanceDB in the output package.json).
|
|
12
|
+
*
|
|
13
|
+
* Adding a new store later = adding one entry here. No UI changes needed.
|
|
14
|
+
*/
|
|
15
|
+
export const VECTOR_STORES: Record<VectorStoreId, VectorStoreDescriptor> = {
|
|
16
|
+
lancedb: {
|
|
17
|
+
id: "lancedb",
|
|
18
|
+
label: "LanceDB",
|
|
19
|
+
description:
|
|
20
|
+
"Embedded, file-based vector DB. Runs fully local for dev or against LanceDB Cloud for production.",
|
|
21
|
+
runtime: "both",
|
|
22
|
+
installStatus: "installed",
|
|
23
|
+
docsUrl: "https://lancedb.github.io/lancedb/",
|
|
24
|
+
serverDependencies: {
|
|
25
|
+
"@lancedb/lancedb": "^0.30.0",
|
|
26
|
+
},
|
|
27
|
+
fields: [
|
|
28
|
+
{
|
|
29
|
+
key: "mode",
|
|
30
|
+
label: "Mode",
|
|
31
|
+
type: "select",
|
|
32
|
+
required: true,
|
|
33
|
+
defaultValue: "local",
|
|
34
|
+
help: "Local writes to disk on the toolkit host. Cloud connects to LanceDB Cloud.",
|
|
35
|
+
options: [
|
|
36
|
+
{ label: "Local (on-disk)", value: "local" },
|
|
37
|
+
{ label: "Cloud", value: "cloud" },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
key: "dbPath",
|
|
42
|
+
label: "Database path",
|
|
43
|
+
type: "path",
|
|
44
|
+
required: true,
|
|
45
|
+
defaultValue: "./.larkup/lancedb",
|
|
46
|
+
placeholder: "./.larkup/lancedb",
|
|
47
|
+
help: "Directory where the LanceDB tables are stored.",
|
|
48
|
+
showWhen: { key: "mode", equals: ["local"] },
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
key: "uri",
|
|
52
|
+
label: "Cloud URI",
|
|
53
|
+
type: "text",
|
|
54
|
+
required: true,
|
|
55
|
+
placeholder: "db://my-database",
|
|
56
|
+
help: "Your LanceDB Cloud database URI.",
|
|
57
|
+
showWhen: { key: "mode", equals: ["cloud"] },
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
key: "apiKey",
|
|
61
|
+
label: "API key",
|
|
62
|
+
type: "password",
|
|
63
|
+
required: true,
|
|
64
|
+
secret: true,
|
|
65
|
+
placeholder: "sk_...",
|
|
66
|
+
help: "LanceDB Cloud API key. Stored as an env var in the generated server.",
|
|
67
|
+
showWhen: { key: "mode", equals: ["cloud"] },
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
key: "tableName",
|
|
71
|
+
label: "Table name",
|
|
72
|
+
type: "text",
|
|
73
|
+
required: true,
|
|
74
|
+
defaultValue: "documents",
|
|
75
|
+
help: "The table that holds your embedded chunks.",
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
pinecone: {
|
|
81
|
+
id: "pinecone",
|
|
82
|
+
label: "Pinecone",
|
|
83
|
+
description:
|
|
84
|
+
"Fully-managed cloud vector database. Cloud-only — requires an API key and an existing index.",
|
|
85
|
+
runtime: "cloud",
|
|
86
|
+
installStatus: "installed",
|
|
87
|
+
docsUrl: "https://docs.pinecone.io/",
|
|
88
|
+
serverDependencies: {
|
|
89
|
+
"@pinecone-database/pinecone": "^6.0.0",
|
|
90
|
+
},
|
|
91
|
+
fields: [
|
|
92
|
+
{
|
|
93
|
+
key: "apiKey",
|
|
94
|
+
label: "API key",
|
|
95
|
+
type: "password",
|
|
96
|
+
required: true,
|
|
97
|
+
secret: true,
|
|
98
|
+
placeholder: "pcsk_...",
|
|
99
|
+
help: "Pinecone API key. Stored as an env var in the generated server.",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
key: "indexName",
|
|
103
|
+
label: "Index name",
|
|
104
|
+
type: "text",
|
|
105
|
+
required: true,
|
|
106
|
+
placeholder: "rag-index",
|
|
107
|
+
help: "Name of the Pinecone index to upsert into / query. For hybrid/lexical mode this index must use the 'dotproduct' metric.",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
key: "namespace",
|
|
111
|
+
label: "Namespace",
|
|
112
|
+
type: "text",
|
|
113
|
+
required: false,
|
|
114
|
+
placeholder: "default",
|
|
115
|
+
help: "Optional namespace to isolate this dataset within the index.",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
key: "sparseModel",
|
|
119
|
+
label: "Sparse model",
|
|
120
|
+
type: "text",
|
|
121
|
+
required: true,
|
|
122
|
+
defaultValue: "pinecone-sparse-english-v0",
|
|
123
|
+
help: "Pinecone-hosted sparse model used to generate keyword vectors via the Inference API. Both dense and sparse vectors are stored in the same index.",
|
|
124
|
+
showWhenIndexType: ["lexical", "hybrid"],
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
weaviate: {
|
|
130
|
+
id: "weaviate",
|
|
131
|
+
label: "Weaviate",
|
|
132
|
+
description:
|
|
133
|
+
"Open-source AI-native vector database with built-in hybrid search, BM25, and multi-tenancy.",
|
|
134
|
+
runtime: "both",
|
|
135
|
+
installStatus: "coming-soon",
|
|
136
|
+
docsUrl: "https://weaviate.io/developers/weaviate",
|
|
137
|
+
serverDependencies: {
|
|
138
|
+
weaviate: "^3.0.0",
|
|
139
|
+
},
|
|
140
|
+
fields: [
|
|
141
|
+
{
|
|
142
|
+
key: "host",
|
|
143
|
+
label: "Host URL",
|
|
144
|
+
type: "text",
|
|
145
|
+
required: true,
|
|
146
|
+
placeholder: "https://my-cluster.weaviate.network",
|
|
147
|
+
help: "Weaviate Cloud URL or self-hosted host address.",
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
key: "apiKey",
|
|
151
|
+
label: "API key",
|
|
152
|
+
type: "password",
|
|
153
|
+
required: false,
|
|
154
|
+
secret: true,
|
|
155
|
+
placeholder: "weaviate-api-key",
|
|
156
|
+
help: "Weaviate Cloud API key (optional for self-hosted).",
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
key: "className",
|
|
160
|
+
label: "Collection name",
|
|
161
|
+
type: "text",
|
|
162
|
+
required: true,
|
|
163
|
+
defaultValue: "Documents",
|
|
164
|
+
help: "The Weaviate collection (class) that holds your embedded chunks.",
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
qdrant: {
|
|
170
|
+
id: "qdrant",
|
|
171
|
+
label: "Qdrant",
|
|
172
|
+
description:
|
|
173
|
+
"High-performance vector search engine with rich filtering, built for production-scale RAG.",
|
|
174
|
+
runtime: "both",
|
|
175
|
+
installStatus: "coming-soon",
|
|
176
|
+
docsUrl: "https://qdrant.tech/documentation/",
|
|
177
|
+
serverDependencies: {
|
|
178
|
+
"@qdrant/js-client-rest": "^1.9.0",
|
|
179
|
+
},
|
|
180
|
+
fields: [
|
|
181
|
+
{
|
|
182
|
+
key: "url",
|
|
183
|
+
label: "Host URL",
|
|
184
|
+
type: "text",
|
|
185
|
+
required: true,
|
|
186
|
+
placeholder: "http://localhost:6333",
|
|
187
|
+
help: "Qdrant server URL (local or Qdrant Cloud endpoint).",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
key: "apiKey",
|
|
191
|
+
label: "API key",
|
|
192
|
+
type: "password",
|
|
193
|
+
required: false,
|
|
194
|
+
secret: true,
|
|
195
|
+
placeholder: "qdrant-api-key",
|
|
196
|
+
help: "Qdrant Cloud API key (leave blank for local).",
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
key: "collectionName",
|
|
200
|
+
label: "Collection name",
|
|
201
|
+
type: "text",
|
|
202
|
+
required: true,
|
|
203
|
+
defaultValue: "documents",
|
|
204
|
+
help: "Qdrant collection to upsert into and query.",
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
chroma: {
|
|
210
|
+
id: "chroma",
|
|
211
|
+
label: "Chroma",
|
|
212
|
+
description:
|
|
213
|
+
"Open-source, developer-friendly embedding database. Great for rapid local prototyping.",
|
|
214
|
+
runtime: "both",
|
|
215
|
+
installStatus: "installable",
|
|
216
|
+
docsUrl: "https://docs.trychroma.com/",
|
|
217
|
+
serverDependencies: {
|
|
218
|
+
chromadb: "^1.9.0",
|
|
219
|
+
},
|
|
220
|
+
fields: [
|
|
221
|
+
{
|
|
222
|
+
key: "mode",
|
|
223
|
+
label: "Mode",
|
|
224
|
+
type: "select",
|
|
225
|
+
required: true,
|
|
226
|
+
defaultValue: "server",
|
|
227
|
+
help: "Server connects to a self-hosted Chroma instance. Cloud connects to Chroma Cloud.",
|
|
228
|
+
options: [
|
|
229
|
+
{ label: "Server (Self-hosted)", value: "server" },
|
|
230
|
+
{ label: "Cloud (Chroma Cloud)", value: "cloud" },
|
|
231
|
+
],
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
key: "host",
|
|
235
|
+
label: "Server URL",
|
|
236
|
+
type: "text",
|
|
237
|
+
required: true,
|
|
238
|
+
placeholder: "http://localhost:8000",
|
|
239
|
+
defaultValue: "http://localhost:8000",
|
|
240
|
+
help: "Chroma server URL (local Docker or remote).",
|
|
241
|
+
showWhen: { key: "mode", equals: ["server"] },
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
key: "authToken",
|
|
245
|
+
label: "Auth Token",
|
|
246
|
+
type: "password",
|
|
247
|
+
required: false,
|
|
248
|
+
secret: true,
|
|
249
|
+
placeholder: "chroma-token",
|
|
250
|
+
help: "Optional static auth token for Chroma server.",
|
|
251
|
+
showWhen: { key: "mode", equals: ["server"] },
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
key: "apiKey",
|
|
255
|
+
label: "API Key",
|
|
256
|
+
type: "password",
|
|
257
|
+
required: true,
|
|
258
|
+
secret: true,
|
|
259
|
+
placeholder: "sk_...",
|
|
260
|
+
help: "Chroma Cloud API Key.",
|
|
261
|
+
showWhen: { key: "mode", equals: ["cloud"] },
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
key: "tenant",
|
|
265
|
+
label: "Tenant",
|
|
266
|
+
type: "text",
|
|
267
|
+
required: true,
|
|
268
|
+
defaultValue: "default_tenant",
|
|
269
|
+
help: "Tenant name for Chroma Cloud.",
|
|
270
|
+
showWhen: { key: "mode", equals: ["cloud"] },
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
key: "database",
|
|
274
|
+
label: "Database",
|
|
275
|
+
type: "text",
|
|
276
|
+
required: true,
|
|
277
|
+
defaultValue: "default_database",
|
|
278
|
+
help: "Database name for Chroma Cloud.",
|
|
279
|
+
showWhen: { key: "mode", equals: ["cloud"] },
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
key: "collectionName",
|
|
283
|
+
label: "Collection name",
|
|
284
|
+
type: "text",
|
|
285
|
+
required: true,
|
|
286
|
+
defaultValue: "documents",
|
|
287
|
+
help: "Chroma collection to store and retrieve embeddings.",
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
pgvector: {
|
|
293
|
+
id: "pgvector",
|
|
294
|
+
label: "pgvector",
|
|
295
|
+
description:
|
|
296
|
+
"PostgreSQL extension for vector similarity search. Self-host vectors alongside your relational data.",
|
|
297
|
+
runtime: "both",
|
|
298
|
+
installStatus: "coming-soon",
|
|
299
|
+
docsUrl: "https://github.com/pgvector/pgvector",
|
|
300
|
+
serverDependencies: {
|
|
301
|
+
pg: "^8.11.0",
|
|
302
|
+
pgvector: "^0.2.0",
|
|
303
|
+
},
|
|
304
|
+
fields: [
|
|
305
|
+
{
|
|
306
|
+
key: "connectionString",
|
|
307
|
+
label: "Connection string",
|
|
308
|
+
type: "password",
|
|
309
|
+
required: true,
|
|
310
|
+
secret: true,
|
|
311
|
+
placeholder: "postgresql://user:pass@localhost:5432/db",
|
|
312
|
+
help: "Full PostgreSQL connection string.",
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
key: "tableName",
|
|
316
|
+
label: "Table name",
|
|
317
|
+
type: "text",
|
|
318
|
+
required: true,
|
|
319
|
+
defaultValue: "embeddings",
|
|
320
|
+
help: "The table used to store vector embeddings. Created automatically if absent.",
|
|
321
|
+
},
|
|
322
|
+
],
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
supabase: {
|
|
326
|
+
id: "supabase",
|
|
327
|
+
label: "Supabase",
|
|
328
|
+
description:
|
|
329
|
+
"Postgres-backed vector store via the pgvector extension with Supabase's managed infrastructure.",
|
|
330
|
+
runtime: "cloud",
|
|
331
|
+
installStatus: "coming-soon",
|
|
332
|
+
docsUrl: "https://supabase.com/docs/guides/ai",
|
|
333
|
+
serverDependencies: {
|
|
334
|
+
"@supabase/supabase-js": "^2.43.0",
|
|
335
|
+
},
|
|
336
|
+
fields: [
|
|
337
|
+
{
|
|
338
|
+
key: "url",
|
|
339
|
+
label: "Project URL",
|
|
340
|
+
type: "text",
|
|
341
|
+
required: true,
|
|
342
|
+
placeholder: "https://xyz.supabase.co",
|
|
343
|
+
help: "Your Supabase project URL.",
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
key: "serviceKey",
|
|
347
|
+
label: "Service role key",
|
|
348
|
+
type: "password",
|
|
349
|
+
required: true,
|
|
350
|
+
secret: true,
|
|
351
|
+
placeholder: "eyJhbGci...",
|
|
352
|
+
help: "Supabase service_role key (not the anon key). Stored as an env var.",
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
key: "tableName",
|
|
356
|
+
label: "Table name",
|
|
357
|
+
type: "text",
|
|
358
|
+
required: true,
|
|
359
|
+
defaultValue: "documents",
|
|
360
|
+
help: "Supabase table with a vector column for embeddings.",
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
},
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export const VECTOR_STORE_LIST: VectorStoreDescriptor[] =
|
|
367
|
+
Object.values(VECTOR_STORES)
|
|
368
|
+
|
|
369
|
+
export function getVectorStore(id: VectorStoreId): VectorStoreDescriptor {
|
|
370
|
+
return VECTOR_STORES[id]
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Returns the fields that should currently be visible for a store given the
|
|
375
|
+
* values already entered (handles `showWhen` dependencies like LanceDB
|
|
376
|
+
* local-vs-cloud) and the current `indexType` (handles `showWhenIndexType`
|
|
377
|
+
* for Pinecone sparse model).
|
|
378
|
+
*/
|
|
379
|
+
export function visibleFields(
|
|
380
|
+
store: VectorStoreDescriptor,
|
|
381
|
+
values: Record<string, string>,
|
|
382
|
+
indexType?: IndexType,
|
|
383
|
+
): import("@larkup/core/types").StoreField[] {
|
|
384
|
+
return store.fields.filter((field) => {
|
|
385
|
+
// Sibling-field dependency (e.g. LanceDB mode → local/cloud fields)
|
|
386
|
+
if (field.showWhen) {
|
|
387
|
+
const current = values[field.showWhen.key] ?? ""
|
|
388
|
+
if (!field.showWhen.equals.includes(current)) return false
|
|
389
|
+
}
|
|
390
|
+
// Cross-concern dependency (e.g. indexType → sparse model)
|
|
391
|
+
if (field.showWhenIndexType && indexType) {
|
|
392
|
+
if (!field.showWhenIndexType.includes(indexType)) return false
|
|
393
|
+
}
|
|
394
|
+
return true
|
|
395
|
+
})
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Validates store config against the registry. Returns a map of
|
|
400
|
+
* field key -> error message for any missing required (visible) field.
|
|
401
|
+
*/
|
|
402
|
+
export function validateStoreConfig(
|
|
403
|
+
store: VectorStoreDescriptor,
|
|
404
|
+
values: Record<string, string>,
|
|
405
|
+
indexType?: IndexType,
|
|
406
|
+
): Record<string, string> {
|
|
407
|
+
const errors: Record<string, string> = {}
|
|
408
|
+
for (const field of visibleFields(store, values, indexType)) {
|
|
409
|
+
if (field.required && !values[field.key]?.trim()) {
|
|
410
|
+
errors[field.key] = `${field.label} is required`
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return errors
|
|
414
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const { CloudClient } = require("chromadb");
|
|
2
|
+
|
|
3
|
+
async function run() {
|
|
4
|
+
const client = new CloudClient({
|
|
5
|
+
apiKey: "wrong-key-1234",
|
|
6
|
+
tenant: "bogus-tenant-123",
|
|
7
|
+
database: "bogus-db-123"
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
console.log("heartbeat:", await client.heartbeat());
|
|
12
|
+
console.log("getOrCreateCollection...");
|
|
13
|
+
await client.getOrCreateCollection({
|
|
14
|
+
name: "documents"
|
|
15
|
+
});
|
|
16
|
+
console.log("Success!");
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.error("Error:", err.message);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
run();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ChromaClient, CloudClient, AdminClient } from "chromadb";
|
|
2
|
+
|
|
3
|
+
async function run() {
|
|
4
|
+
const adminClient = new AdminClient({
|
|
5
|
+
path: "http://localhost:8000"
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
const tenant = await adminClient.getTenant({ name: "bogus-tenant" });
|
|
10
|
+
console.log("Tenant:", tenant);
|
|
11
|
+
} catch (err) {
|
|
12
|
+
console.error("AdminClient error:", err.message);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
run();
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["esnext"],
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"module": "esnext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"composite": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"declarationMap": true,
|
|
16
|
+
"paths": {
|
|
17
|
+
"@larkup/core/*": ["../core/src/*"]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*.ts"],
|
|
21
|
+
"exclude": ["node_modules"]
|
|
22
|
+
}
|