@wiscale/velesdb-sdk 1.4.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +480 -185
- package/dist/index.d.mts +367 -40
- package/dist/index.d.ts +367 -40
- package/dist/index.js +1283 -456
- package/dist/index.mjs +1281 -456
- package/package.json +5 -2
package/dist/index.mjs
CHANGED
|
@@ -25,6 +25,44 @@ var NotFoundError = class extends VelesDBError {
|
|
|
25
25
|
this.name = "NotFoundError";
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
|
+
var BackpressureError = class extends VelesDBError {
|
|
29
|
+
constructor(message = "Server backpressure: too many requests") {
|
|
30
|
+
super(message, "BACKPRESSURE");
|
|
31
|
+
this.name = "BackpressureError";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/backends/shared.ts
|
|
36
|
+
function throwOnError(response, resourceLabel) {
|
|
37
|
+
if (!response.error) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (response.error.code === "NOT_FOUND" && resourceLabel !== void 0) {
|
|
41
|
+
throw new NotFoundError(resourceLabel);
|
|
42
|
+
}
|
|
43
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
44
|
+
}
|
|
45
|
+
function returnNullOnNotFound(response) {
|
|
46
|
+
if (!response.error) {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
if (response.error.code === "NOT_FOUND") {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
53
|
+
}
|
|
54
|
+
function collectionPath(collection) {
|
|
55
|
+
return `/collections/${encodeURIComponent(collection)}`;
|
|
56
|
+
}
|
|
57
|
+
function toNumberArray(v) {
|
|
58
|
+
return v instanceof Float32Array ? Array.from(v) : v;
|
|
59
|
+
}
|
|
60
|
+
function wasmNotSupported(feature) {
|
|
61
|
+
throw new VelesDBError(
|
|
62
|
+
`${feature}: not supported in WASM backend. Use REST backend.`,
|
|
63
|
+
"NOT_SUPPORTED"
|
|
64
|
+
);
|
|
65
|
+
}
|
|
28
66
|
|
|
29
67
|
// src/backends/wasm.ts
|
|
30
68
|
var WasmBackend = class {
|
|
@@ -56,6 +94,33 @@ var WasmBackend = class {
|
|
|
56
94
|
throw new ConnectionError("WASM backend not initialized");
|
|
57
95
|
}
|
|
58
96
|
}
|
|
97
|
+
normalizeIdString(id) {
|
|
98
|
+
const trimmed = id.trim();
|
|
99
|
+
return /^\d+$/.test(trimmed) ? trimmed : null;
|
|
100
|
+
}
|
|
101
|
+
canonicalPayloadKeyFromResultId(id) {
|
|
102
|
+
if (typeof id === "bigint") {
|
|
103
|
+
return id.toString();
|
|
104
|
+
}
|
|
105
|
+
if (typeof id === "number") {
|
|
106
|
+
return String(Math.trunc(id));
|
|
107
|
+
}
|
|
108
|
+
const normalized = this.normalizeIdString(id);
|
|
109
|
+
if (normalized !== null) {
|
|
110
|
+
return normalized.replace(/^0+(?=\d)/, "");
|
|
111
|
+
}
|
|
112
|
+
return String(this.toNumericId(id));
|
|
113
|
+
}
|
|
114
|
+
canonicalPayloadKey(id) {
|
|
115
|
+
if (typeof id === "number") {
|
|
116
|
+
return String(Math.trunc(id));
|
|
117
|
+
}
|
|
118
|
+
const normalized = this.normalizeIdString(id);
|
|
119
|
+
if (normalized !== null) {
|
|
120
|
+
return normalized.replace(/^0+(?=\d)/, "");
|
|
121
|
+
}
|
|
122
|
+
return String(this.toNumericId(id));
|
|
123
|
+
}
|
|
59
124
|
async createCollection(name, config) {
|
|
60
125
|
this.ensureInitialized();
|
|
61
126
|
if (this.collections.has(name)) {
|
|
@@ -121,9 +186,13 @@ var WasmBackend = class {
|
|
|
121
186
|
"DIMENSION_MISMATCH"
|
|
122
187
|
);
|
|
123
188
|
}
|
|
124
|
-
collection.store.insert(BigInt(id), vector);
|
|
125
189
|
if (doc.payload) {
|
|
126
|
-
collection.
|
|
190
|
+
collection.store.insert_with_payload(BigInt(id), vector, doc.payload);
|
|
191
|
+
} else {
|
|
192
|
+
collection.store.insert(BigInt(id), vector);
|
|
193
|
+
}
|
|
194
|
+
if (doc.payload) {
|
|
195
|
+
collection.payloads.set(this.canonicalPayloadKey(doc.id), doc.payload);
|
|
127
196
|
}
|
|
128
197
|
}
|
|
129
198
|
async insertBatch(collectionName, docs) {
|
|
@@ -142,24 +211,32 @@ var WasmBackend = class {
|
|
|
142
211
|
}
|
|
143
212
|
}
|
|
144
213
|
collection.store.reserve(docs.length);
|
|
145
|
-
const batch =
|
|
146
|
-
BigInt(this.toNumericId(doc.id)),
|
|
147
|
-
Array.isArray(doc.vector) ? doc.vector : Array.from(doc.vector)
|
|
148
|
-
]);
|
|
149
|
-
collection.store.insert_batch(batch);
|
|
214
|
+
const batch = [];
|
|
150
215
|
for (const doc of docs) {
|
|
216
|
+
const id = BigInt(this.toNumericId(doc.id));
|
|
217
|
+
const vector = doc.vector instanceof Float32Array ? doc.vector : new Float32Array(doc.vector);
|
|
151
218
|
if (doc.payload) {
|
|
152
|
-
collection.
|
|
219
|
+
collection.store.insert_with_payload(id, vector, doc.payload);
|
|
220
|
+
} else {
|
|
221
|
+
batch.push([id, Array.from(vector)]);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (batch.length > 0) {
|
|
225
|
+
collection.store.insert_batch(batch);
|
|
226
|
+
}
|
|
227
|
+
for (const doc of docs) {
|
|
228
|
+
if (doc.payload) {
|
|
229
|
+
collection.payloads.set(this.canonicalPayloadKey(doc.id), doc.payload);
|
|
153
230
|
}
|
|
154
231
|
}
|
|
155
232
|
}
|
|
156
|
-
async search(collectionName,
|
|
233
|
+
async search(collectionName, query2, options) {
|
|
157
234
|
this.ensureInitialized();
|
|
158
235
|
const collection = this.collections.get(collectionName);
|
|
159
236
|
if (!collection) {
|
|
160
237
|
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
161
238
|
}
|
|
162
|
-
const queryVector =
|
|
239
|
+
const queryVector = query2 instanceof Float32Array ? query2 : new Float32Array(query2);
|
|
163
240
|
if (queryVector.length !== collection.config.dimension) {
|
|
164
241
|
throw new VelesDBError(
|
|
165
242
|
`Query dimension mismatch: expected ${collection.config.dimension}, got ${queryVector.length}`,
|
|
@@ -167,12 +244,43 @@ var WasmBackend = class {
|
|
|
167
244
|
);
|
|
168
245
|
}
|
|
169
246
|
const k = options?.k ?? 10;
|
|
247
|
+
if (options?.sparseVector) {
|
|
248
|
+
const { indices, values } = this.sparseVectorToArrays(options.sparseVector);
|
|
249
|
+
if (queryVector.length > 0 && collection.config.dimension && collection.config.dimension > 0) {
|
|
250
|
+
const denseResults = collection.store.search(queryVector, k);
|
|
251
|
+
const sparseResults = collection.store.sparse_search(
|
|
252
|
+
new Uint32Array(indices),
|
|
253
|
+
new Float32Array(values),
|
|
254
|
+
k
|
|
255
|
+
);
|
|
256
|
+
const sparseArray = sparseResults;
|
|
257
|
+
const denseForFuse = denseResults.map(([id, score]) => [Number(id), score]);
|
|
258
|
+
const sparseForFuse = sparseArray.map((r) => [Number(r.doc_id), r.score]);
|
|
259
|
+
const fused = this.wasmModule.hybrid_search_fuse(denseForFuse, sparseForFuse, 60);
|
|
260
|
+
return fused.slice(0, k).map((r) => ({
|
|
261
|
+
id: String(r.doc_id),
|
|
262
|
+
score: r.score,
|
|
263
|
+
payload: collection.payloads.get(this.canonicalPayloadKeyFromResultId(r.doc_id))
|
|
264
|
+
}));
|
|
265
|
+
} else {
|
|
266
|
+
const sparseResults = collection.store.sparse_search(
|
|
267
|
+
new Uint32Array(indices),
|
|
268
|
+
new Float32Array(values),
|
|
269
|
+
k
|
|
270
|
+
);
|
|
271
|
+
return sparseResults.map((r) => ({
|
|
272
|
+
id: String(r.doc_id),
|
|
273
|
+
score: r.score,
|
|
274
|
+
payload: collection.payloads.get(this.canonicalPayloadKeyFromResultId(r.doc_id))
|
|
275
|
+
}));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
170
278
|
if (options?.filter) {
|
|
171
279
|
const results = collection.store.search_with_filter(queryVector, k, options.filter);
|
|
172
280
|
return results.map((r) => ({
|
|
173
281
|
id: String(r.id),
|
|
174
282
|
score: r.score,
|
|
175
|
-
payload: r.payload || collection.payloads.get(
|
|
283
|
+
payload: r.payload || collection.payloads.get(this.canonicalPayloadKeyFromResultId(r.id))
|
|
176
284
|
}));
|
|
177
285
|
}
|
|
178
286
|
const rawResults = collection.store.search(queryVector, k);
|
|
@@ -182,7 +290,7 @@ var WasmBackend = class {
|
|
|
182
290
|
id: stringId,
|
|
183
291
|
score
|
|
184
292
|
};
|
|
185
|
-
const payload = collection.payloads.get(
|
|
293
|
+
const payload = collection.payloads.get(this.canonicalPayloadKeyFromResultId(id));
|
|
186
294
|
if (payload) {
|
|
187
295
|
result.payload = payload;
|
|
188
296
|
}
|
|
@@ -206,7 +314,7 @@ var WasmBackend = class {
|
|
|
206
314
|
const numericId = this.toNumericId(id);
|
|
207
315
|
const removed = collection.store.remove(BigInt(numericId));
|
|
208
316
|
if (removed) {
|
|
209
|
-
collection.payloads.delete(
|
|
317
|
+
collection.payloads.delete(this.canonicalPayloadKey(id));
|
|
210
318
|
}
|
|
211
319
|
return removed;
|
|
212
320
|
}
|
|
@@ -216,40 +324,129 @@ var WasmBackend = class {
|
|
|
216
324
|
if (!collection) {
|
|
217
325
|
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
218
326
|
}
|
|
219
|
-
const
|
|
220
|
-
|
|
327
|
+
const numericId = this.toNumericId(id);
|
|
328
|
+
const point = collection.store.get(BigInt(numericId));
|
|
329
|
+
if (!point) {
|
|
221
330
|
return null;
|
|
222
331
|
}
|
|
332
|
+
const payload = point.payload ?? collection.payloads.get(this.canonicalPayloadKey(numericId));
|
|
223
333
|
return {
|
|
224
|
-
id,
|
|
225
|
-
vector:
|
|
226
|
-
// Not available in current WASM impl
|
|
334
|
+
id: String(point.id),
|
|
335
|
+
vector: Array.isArray(point.vector) ? point.vector : Array.from(point.vector),
|
|
227
336
|
payload
|
|
228
337
|
};
|
|
229
338
|
}
|
|
230
339
|
async textSearch(_collection, _query, _options) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
340
|
+
this.ensureInitialized();
|
|
341
|
+
const collection = this.collections.get(_collection);
|
|
342
|
+
if (!collection) {
|
|
343
|
+
throw new NotFoundError(`Collection '${_collection}'`);
|
|
344
|
+
}
|
|
345
|
+
const k = _options?.k ?? 10;
|
|
346
|
+
const field = void 0;
|
|
347
|
+
const raw = collection.store.text_search(_query, k, field);
|
|
348
|
+
return raw.map((r) => {
|
|
349
|
+
if (Array.isArray(r)) {
|
|
350
|
+
const key2 = this.canonicalPayloadKeyFromResultId(r[0]);
|
|
351
|
+
return { id: String(r[0]), score: r[1], payload: collection.payloads.get(key2) };
|
|
352
|
+
}
|
|
353
|
+
const key = this.canonicalPayloadKeyFromResultId(r.id);
|
|
354
|
+
return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
|
|
355
|
+
});
|
|
235
356
|
}
|
|
236
357
|
async hybridSearch(_collection, _vector, _textQuery, _options) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
358
|
+
this.ensureInitialized();
|
|
359
|
+
const collection = this.collections.get(_collection);
|
|
360
|
+
if (!collection) {
|
|
361
|
+
throw new NotFoundError(`Collection '${_collection}'`);
|
|
362
|
+
}
|
|
363
|
+
const queryVector = _vector instanceof Float32Array ? _vector : new Float32Array(_vector);
|
|
364
|
+
const k = _options?.k ?? 10;
|
|
365
|
+
const vectorWeight = _options?.vectorWeight ?? 0.5;
|
|
366
|
+
const raw = collection.store.hybrid_search(queryVector, _textQuery, k, vectorWeight);
|
|
367
|
+
return raw.map((r) => {
|
|
368
|
+
const key = this.canonicalPayloadKeyFromResultId(r.id);
|
|
369
|
+
return {
|
|
370
|
+
id: String(r.id),
|
|
371
|
+
score: r.score,
|
|
372
|
+
payload: r.payload ?? collection.payloads.get(key)
|
|
373
|
+
};
|
|
374
|
+
});
|
|
241
375
|
}
|
|
242
376
|
async query(_collection, _queryString, _params, _options) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
377
|
+
this.ensureInitialized();
|
|
378
|
+
const collection = this.collections.get(_collection);
|
|
379
|
+
if (!collection) {
|
|
380
|
+
throw new NotFoundError(`Collection '${_collection}'`);
|
|
381
|
+
}
|
|
382
|
+
const paramsVector = _params?.q;
|
|
383
|
+
if (!Array.isArray(paramsVector) && !(paramsVector instanceof Float32Array)) {
|
|
384
|
+
throw new VelesDBError(
|
|
385
|
+
"WASM query() expects params.q to contain the query embedding vector.",
|
|
386
|
+
"BAD_REQUEST"
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
const requestedK = _params?.k;
|
|
390
|
+
const k = typeof requestedK === "number" && Number.isInteger(requestedK) && requestedK > 0 ? requestedK : 10;
|
|
391
|
+
const raw = collection.store.query(
|
|
392
|
+
paramsVector instanceof Float32Array ? paramsVector : new Float32Array(paramsVector),
|
|
393
|
+
k
|
|
246
394
|
);
|
|
395
|
+
return {
|
|
396
|
+
results: raw,
|
|
397
|
+
stats: {
|
|
398
|
+
executionTimeMs: 0,
|
|
399
|
+
strategy: "wasm-query",
|
|
400
|
+
scannedNodes: raw.length
|
|
401
|
+
}
|
|
402
|
+
};
|
|
247
403
|
}
|
|
248
404
|
async multiQuerySearch(_collection, _vectors, _options) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
405
|
+
this.ensureInitialized();
|
|
406
|
+
const collection = this.collections.get(_collection);
|
|
407
|
+
if (!collection) {
|
|
408
|
+
throw new NotFoundError(`Collection '${_collection}'`);
|
|
409
|
+
}
|
|
410
|
+
if (_vectors.length === 0) {
|
|
411
|
+
return [];
|
|
412
|
+
}
|
|
413
|
+
const numVectors = _vectors.length;
|
|
414
|
+
const dimension = collection.config.dimension ?? 0;
|
|
415
|
+
const flat = new Float32Array(numVectors * dimension);
|
|
416
|
+
_vectors.forEach((vector, idx) => {
|
|
417
|
+
const src = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
418
|
+
flat.set(src, idx * dimension);
|
|
419
|
+
});
|
|
420
|
+
const strategy = _options?.fusion ?? "rrf";
|
|
421
|
+
if (strategy === "weighted") {
|
|
422
|
+
throw new VelesDBError(
|
|
423
|
+
"Fusion strategy 'weighted' is not supported in WASM backend.",
|
|
424
|
+
"NOT_SUPPORTED"
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
const raw = collection.store.multi_query_search(
|
|
428
|
+
flat,
|
|
429
|
+
numVectors,
|
|
430
|
+
_options?.k ?? 10,
|
|
431
|
+
strategy,
|
|
432
|
+
_options?.fusionParams?.k ?? 60
|
|
252
433
|
);
|
|
434
|
+
return raw.map((r) => {
|
|
435
|
+
if (Array.isArray(r)) {
|
|
436
|
+
const key2 = this.canonicalPayloadKeyFromResultId(r[0]);
|
|
437
|
+
return { id: String(r[0]), score: r[1], payload: collection.payloads.get(key2) };
|
|
438
|
+
}
|
|
439
|
+
const key = this.canonicalPayloadKeyFromResultId(r.id);
|
|
440
|
+
return { id: String(r.id), score: r.score, payload: r.payload ?? collection.payloads.get(key) };
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
async queryExplain(_queryString, _params) {
|
|
444
|
+
this.ensureInitialized();
|
|
445
|
+
wasmNotSupported("Query explain");
|
|
446
|
+
}
|
|
447
|
+
async collectionSanity(_collection) {
|
|
448
|
+
this.ensureInitialized();
|
|
449
|
+
wasmNotSupported("Collection sanity endpoint");
|
|
253
450
|
}
|
|
254
451
|
async isEmpty(collectionName) {
|
|
255
452
|
this.ensureInitialized();
|
|
@@ -273,13 +470,25 @@ var WasmBackend = class {
|
|
|
273
470
|
this.collections.clear();
|
|
274
471
|
this._initialized = false;
|
|
275
472
|
}
|
|
473
|
+
sparseVectorToArrays(sv) {
|
|
474
|
+
const indices = [];
|
|
475
|
+
const values = [];
|
|
476
|
+
for (const [k, v] of Object.entries(sv)) {
|
|
477
|
+
indices.push(Number(k));
|
|
478
|
+
values.push(v);
|
|
479
|
+
}
|
|
480
|
+
return { indices, values };
|
|
481
|
+
}
|
|
276
482
|
toNumericId(id) {
|
|
277
483
|
if (typeof id === "number") {
|
|
278
484
|
return id;
|
|
279
485
|
}
|
|
280
|
-
const
|
|
281
|
-
if (
|
|
282
|
-
|
|
486
|
+
const normalized = this.normalizeIdString(id);
|
|
487
|
+
if (normalized !== null) {
|
|
488
|
+
const parsed = Number(normalized);
|
|
489
|
+
if (Number.isSafeInteger(parsed)) {
|
|
490
|
+
return parsed;
|
|
491
|
+
}
|
|
283
492
|
}
|
|
284
493
|
let hash = 0;
|
|
285
494
|
for (let i = 0; i < id.length; i++) {
|
|
@@ -317,34 +526,715 @@ var WasmBackend = class {
|
|
|
317
526
|
// ========================================================================
|
|
318
527
|
async addEdge(_collection, _edge) {
|
|
319
528
|
this.ensureInitialized();
|
|
320
|
-
|
|
321
|
-
"Knowledge Graph operations are not supported in WASM backend. Use REST backend for graph features.",
|
|
322
|
-
"NOT_SUPPORTED"
|
|
323
|
-
);
|
|
529
|
+
wasmNotSupported("Knowledge Graph operations");
|
|
324
530
|
}
|
|
325
531
|
async getEdges(_collection, _options) {
|
|
326
532
|
this.ensureInitialized();
|
|
327
|
-
|
|
328
|
-
"Knowledge Graph operations are not supported in WASM backend. Use REST backend for graph features.",
|
|
329
|
-
"NOT_SUPPORTED"
|
|
330
|
-
);
|
|
533
|
+
wasmNotSupported("Knowledge Graph operations");
|
|
331
534
|
}
|
|
332
535
|
async traverseGraph(_collection, _request) {
|
|
333
536
|
this.ensureInitialized();
|
|
334
|
-
|
|
335
|
-
"Graph traversal is not supported in WASM backend. Use REST backend for graph features.",
|
|
336
|
-
"NOT_SUPPORTED"
|
|
337
|
-
);
|
|
537
|
+
wasmNotSupported("Graph traversal");
|
|
338
538
|
}
|
|
339
539
|
async getNodeDegree(_collection, _nodeId) {
|
|
340
540
|
this.ensureInitialized();
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
541
|
+
wasmNotSupported("Graph degree query");
|
|
542
|
+
}
|
|
543
|
+
// ========================================================================
|
|
544
|
+
// Sparse / PQ / Streaming (v1.5)
|
|
545
|
+
// ========================================================================
|
|
546
|
+
async trainPq(_collection, _options) {
|
|
547
|
+
this.ensureInitialized();
|
|
548
|
+
wasmNotSupported("PQ training");
|
|
549
|
+
}
|
|
550
|
+
async streamInsert(_collection, _docs) {
|
|
551
|
+
this.ensureInitialized();
|
|
552
|
+
wasmNotSupported("Streaming insert");
|
|
553
|
+
}
|
|
554
|
+
// ========================================================================
|
|
555
|
+
// Graph Collection / Stats / Agent Memory (Phase 8) - WASM stubs
|
|
556
|
+
// ========================================================================
|
|
557
|
+
async createGraphCollection(_name, _config) {
|
|
558
|
+
this.ensureInitialized();
|
|
559
|
+
wasmNotSupported("Graph collections");
|
|
560
|
+
}
|
|
561
|
+
async getCollectionStats(_collection) {
|
|
562
|
+
this.ensureInitialized();
|
|
563
|
+
wasmNotSupported("Collection stats");
|
|
564
|
+
}
|
|
565
|
+
async analyzeCollection(_collection) {
|
|
566
|
+
this.ensureInitialized();
|
|
567
|
+
wasmNotSupported("Collection analyze");
|
|
568
|
+
}
|
|
569
|
+
async getCollectionConfig(_collection) {
|
|
570
|
+
this.ensureInitialized();
|
|
571
|
+
wasmNotSupported("Collection config");
|
|
572
|
+
}
|
|
573
|
+
async searchIds(_collection, _query, _options) {
|
|
574
|
+
this.ensureInitialized();
|
|
575
|
+
wasmNotSupported("searchIds");
|
|
576
|
+
}
|
|
577
|
+
async storeSemanticFact(_collection, _entry) {
|
|
578
|
+
this.ensureInitialized();
|
|
579
|
+
wasmNotSupported("Agent memory");
|
|
580
|
+
}
|
|
581
|
+
async searchSemanticMemory(_collection, _embedding, _k) {
|
|
582
|
+
this.ensureInitialized();
|
|
583
|
+
wasmNotSupported("Agent memory");
|
|
584
|
+
}
|
|
585
|
+
async recordEpisodicEvent(_collection, _event) {
|
|
586
|
+
this.ensureInitialized();
|
|
587
|
+
wasmNotSupported("Agent memory");
|
|
588
|
+
}
|
|
589
|
+
async recallEpisodicEvents(_collection, _embedding, _k) {
|
|
590
|
+
this.ensureInitialized();
|
|
591
|
+
wasmNotSupported("Agent memory");
|
|
592
|
+
}
|
|
593
|
+
async storeProceduralPattern(_collection, _pattern) {
|
|
594
|
+
this.ensureInitialized();
|
|
595
|
+
wasmNotSupported("Agent memory");
|
|
596
|
+
}
|
|
597
|
+
async matchProceduralPatterns(_collection, _embedding, _k) {
|
|
598
|
+
this.ensureInitialized();
|
|
599
|
+
wasmNotSupported("Agent memory");
|
|
345
600
|
}
|
|
346
601
|
};
|
|
347
602
|
|
|
603
|
+
// src/backends/agent-memory-backend.ts
|
|
604
|
+
var _idCounter = 0;
|
|
605
|
+
var _lastTimestamp = 0;
|
|
606
|
+
function generateUniqueId() {
|
|
607
|
+
let now = Date.now();
|
|
608
|
+
if (now <= _lastTimestamp) {
|
|
609
|
+
_idCounter++;
|
|
610
|
+
if (_idCounter >= 1e3) {
|
|
611
|
+
_lastTimestamp++;
|
|
612
|
+
_idCounter = 0;
|
|
613
|
+
}
|
|
614
|
+
} else {
|
|
615
|
+
_lastTimestamp = now;
|
|
616
|
+
_idCounter = 0;
|
|
617
|
+
}
|
|
618
|
+
return _lastTimestamp * 1e3 + _idCounter;
|
|
619
|
+
}
|
|
620
|
+
async function storeSemanticFact(transport, collection, entry) {
|
|
621
|
+
const response = await transport.requestJson(
|
|
622
|
+
"POST",
|
|
623
|
+
`${collectionPath(collection)}/points`,
|
|
624
|
+
{
|
|
625
|
+
points: [{
|
|
626
|
+
id: entry.id,
|
|
627
|
+
vector: entry.embedding,
|
|
628
|
+
payload: {
|
|
629
|
+
_memory_type: "semantic",
|
|
630
|
+
text: entry.text,
|
|
631
|
+
...entry.metadata
|
|
632
|
+
}
|
|
633
|
+
}]
|
|
634
|
+
}
|
|
635
|
+
);
|
|
636
|
+
throwOnError(response);
|
|
637
|
+
}
|
|
638
|
+
async function searchSemanticMemory(transport, collection, embedding, k = 5) {
|
|
639
|
+
return transport.searchVectors(collection, embedding, k, { _memory_type: "semantic" });
|
|
640
|
+
}
|
|
641
|
+
async function recordEpisodicEvent(transport, collection, event) {
|
|
642
|
+
const id = generateUniqueId();
|
|
643
|
+
const response = await transport.requestJson(
|
|
644
|
+
"POST",
|
|
645
|
+
`${collectionPath(collection)}/points`,
|
|
646
|
+
{
|
|
647
|
+
points: [{
|
|
648
|
+
id,
|
|
649
|
+
vector: event.embedding,
|
|
650
|
+
payload: {
|
|
651
|
+
_memory_type: "episodic",
|
|
652
|
+
event_type: event.eventType,
|
|
653
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
654
|
+
...event.data,
|
|
655
|
+
...event.metadata
|
|
656
|
+
}
|
|
657
|
+
}]
|
|
658
|
+
}
|
|
659
|
+
);
|
|
660
|
+
throwOnError(response);
|
|
661
|
+
}
|
|
662
|
+
async function recallEpisodicEvents(transport, collection, embedding, k = 5) {
|
|
663
|
+
return transport.searchVectors(collection, embedding, k, { _memory_type: "episodic" });
|
|
664
|
+
}
|
|
665
|
+
async function storeProceduralPattern(transport, collection, pattern) {
|
|
666
|
+
const id = generateUniqueId();
|
|
667
|
+
const response = await transport.requestJson(
|
|
668
|
+
"POST",
|
|
669
|
+
`${collectionPath(collection)}/points`,
|
|
670
|
+
{
|
|
671
|
+
points: [{
|
|
672
|
+
id,
|
|
673
|
+
payload: {
|
|
674
|
+
_memory_type: "procedural",
|
|
675
|
+
name: pattern.name,
|
|
676
|
+
steps: pattern.steps,
|
|
677
|
+
...pattern.metadata
|
|
678
|
+
}
|
|
679
|
+
}]
|
|
680
|
+
}
|
|
681
|
+
);
|
|
682
|
+
throwOnError(response);
|
|
683
|
+
}
|
|
684
|
+
async function matchProceduralPatterns(transport, collection, embedding, k = 5) {
|
|
685
|
+
return transport.searchVectors(collection, embedding, k, { _memory_type: "procedural" });
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// src/backends/search-backend.ts
|
|
689
|
+
async function search(transport, collection, query2, options) {
|
|
690
|
+
const queryVector = toNumberArray(query2);
|
|
691
|
+
const body = {
|
|
692
|
+
vector: queryVector,
|
|
693
|
+
top_k: options?.k ?? 10,
|
|
694
|
+
filter: options?.filter,
|
|
695
|
+
include_vectors: options?.includeVectors ?? false
|
|
696
|
+
};
|
|
697
|
+
if (options?.sparseVector) {
|
|
698
|
+
body.sparse_vector = transport.sparseToRest(options.sparseVector);
|
|
699
|
+
}
|
|
700
|
+
const response = await transport.requestJson(
|
|
701
|
+
"POST",
|
|
702
|
+
`${collectionPath(collection)}/search`,
|
|
703
|
+
body
|
|
704
|
+
);
|
|
705
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
706
|
+
return response.data?.results ?? [];
|
|
707
|
+
}
|
|
708
|
+
async function searchBatch(transport, collection, searches) {
|
|
709
|
+
const formattedSearches = searches.map((s) => ({
|
|
710
|
+
vector: toNumberArray(s.vector),
|
|
711
|
+
top_k: s.k ?? 10,
|
|
712
|
+
filter: s.filter
|
|
713
|
+
}));
|
|
714
|
+
const response = await transport.requestJson(
|
|
715
|
+
"POST",
|
|
716
|
+
`${collectionPath(collection)}/search/batch`,
|
|
717
|
+
{ searches: formattedSearches }
|
|
718
|
+
);
|
|
719
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
720
|
+
return response.data?.results.map((r) => r.results) ?? [];
|
|
721
|
+
}
|
|
722
|
+
async function textSearch(transport, collection, query2, options) {
|
|
723
|
+
const response = await transport.requestJson(
|
|
724
|
+
"POST",
|
|
725
|
+
`${collectionPath(collection)}/search/text`,
|
|
726
|
+
{
|
|
727
|
+
query: query2,
|
|
728
|
+
top_k: options?.k ?? 10,
|
|
729
|
+
filter: options?.filter
|
|
730
|
+
}
|
|
731
|
+
);
|
|
732
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
733
|
+
return response.data?.results ?? [];
|
|
734
|
+
}
|
|
735
|
+
async function hybridSearch(transport, collection, vector, textQuery, options) {
|
|
736
|
+
const queryVector = toNumberArray(vector);
|
|
737
|
+
const response = await transport.requestJson(
|
|
738
|
+
"POST",
|
|
739
|
+
`${collectionPath(collection)}/search/hybrid`,
|
|
740
|
+
{
|
|
741
|
+
vector: queryVector,
|
|
742
|
+
query: textQuery,
|
|
743
|
+
top_k: options?.k ?? 10,
|
|
744
|
+
vector_weight: options?.vectorWeight ?? 0.5,
|
|
745
|
+
filter: options?.filter
|
|
746
|
+
}
|
|
747
|
+
);
|
|
748
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
749
|
+
return response.data?.results ?? [];
|
|
750
|
+
}
|
|
751
|
+
async function multiQuerySearch(transport, collection, vectors, options) {
|
|
752
|
+
const formattedVectors = vectors.map(toNumberArray);
|
|
753
|
+
const response = await transport.requestJson(
|
|
754
|
+
"POST",
|
|
755
|
+
`${collectionPath(collection)}/search/multi`,
|
|
756
|
+
{
|
|
757
|
+
vectors: formattedVectors,
|
|
758
|
+
top_k: options?.k ?? 10,
|
|
759
|
+
strategy: options?.fusion ?? "rrf",
|
|
760
|
+
rrf_k: options?.fusionParams?.k ?? 60,
|
|
761
|
+
avg_weight: options?.fusionParams?.avgWeight,
|
|
762
|
+
max_weight: options?.fusionParams?.maxWeight,
|
|
763
|
+
hit_weight: options?.fusionParams?.hitWeight,
|
|
764
|
+
filter: options?.filter
|
|
765
|
+
}
|
|
766
|
+
);
|
|
767
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
768
|
+
return response.data?.results ?? [];
|
|
769
|
+
}
|
|
770
|
+
async function searchIds(transport, collection, query2, options) {
|
|
771
|
+
const queryVector = toNumberArray(query2);
|
|
772
|
+
const response = await transport.requestJson(
|
|
773
|
+
"POST",
|
|
774
|
+
`${collectionPath(collection)}/search/ids`,
|
|
775
|
+
{
|
|
776
|
+
vector: queryVector,
|
|
777
|
+
top_k: options?.k ?? 10,
|
|
778
|
+
filter: options?.filter
|
|
779
|
+
}
|
|
780
|
+
);
|
|
781
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
782
|
+
return response.data?.results ?? [];
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/backends/graph-backend.ts
|
|
786
|
+
async function addEdge(transport, collection, edge) {
|
|
787
|
+
const response = await transport.requestJson(
|
|
788
|
+
"POST",
|
|
789
|
+
`${collectionPath(collection)}/graph/edges`,
|
|
790
|
+
{
|
|
791
|
+
id: edge.id,
|
|
792
|
+
source: edge.source,
|
|
793
|
+
target: edge.target,
|
|
794
|
+
label: edge.label,
|
|
795
|
+
properties: edge.properties ?? {}
|
|
796
|
+
}
|
|
797
|
+
);
|
|
798
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
799
|
+
}
|
|
800
|
+
async function getEdges(transport, collection, options) {
|
|
801
|
+
const queryParams = options?.label ? `?label=${encodeURIComponent(options.label)}` : "";
|
|
802
|
+
const response = await transport.requestJson(
|
|
803
|
+
"GET",
|
|
804
|
+
`${collectionPath(collection)}/graph/edges${queryParams}`
|
|
805
|
+
);
|
|
806
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
807
|
+
return response.data?.edges ?? [];
|
|
808
|
+
}
|
|
809
|
+
async function traverseGraph(transport, collection, request) {
|
|
810
|
+
const response = await transport.requestJson(
|
|
811
|
+
"POST",
|
|
812
|
+
`${collectionPath(collection)}/graph/traverse`,
|
|
813
|
+
{
|
|
814
|
+
source: request.source,
|
|
815
|
+
strategy: request.strategy ?? "bfs",
|
|
816
|
+
max_depth: request.maxDepth ?? 3,
|
|
817
|
+
limit: request.limit ?? 100,
|
|
818
|
+
cursor: request.cursor,
|
|
819
|
+
rel_types: request.relTypes ?? []
|
|
820
|
+
}
|
|
821
|
+
);
|
|
822
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
823
|
+
const data = response.data;
|
|
824
|
+
return {
|
|
825
|
+
results: data.results.map((r) => ({
|
|
826
|
+
targetId: r.target_id,
|
|
827
|
+
depth: r.depth,
|
|
828
|
+
path: r.path
|
|
829
|
+
})),
|
|
830
|
+
nextCursor: data.next_cursor ?? void 0,
|
|
831
|
+
hasMore: data.has_more,
|
|
832
|
+
stats: {
|
|
833
|
+
visited: data.stats.visited,
|
|
834
|
+
depthReached: data.stats.depth_reached
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
async function getNodeDegree(transport, collection, nodeId) {
|
|
839
|
+
const response = await transport.requestJson(
|
|
840
|
+
"GET",
|
|
841
|
+
`${collectionPath(collection)}/graph/nodes/${nodeId}/degree`
|
|
842
|
+
);
|
|
843
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
844
|
+
return {
|
|
845
|
+
inDegree: response.data?.in_degree ?? 0,
|
|
846
|
+
outDegree: response.data?.out_degree ?? 0
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
async function createGraphCollection(transport, name, config) {
|
|
850
|
+
const response = await transport.requestJson("POST", "/collections", {
|
|
851
|
+
name,
|
|
852
|
+
collection_type: "graph",
|
|
853
|
+
dimension: config?.dimension,
|
|
854
|
+
metric: config?.metric ?? "cosine",
|
|
855
|
+
schema_mode: config?.schemaMode ?? "schemaless"
|
|
856
|
+
});
|
|
857
|
+
throwOnError(response);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// src/backends/query-backend.ts
|
|
861
|
+
function isLikelyAggregationQuery(queryString) {
|
|
862
|
+
return /\bGROUP\s+BY\b|\bHAVING\b|\bCOUNT\s*\(|\bSUM\s*\(|\bAVG\s*\(|\bMIN\s*\(|\bMAX\s*\(/i.test(
|
|
863
|
+
queryString
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
async function query(transport, collection, queryString, params, options) {
|
|
867
|
+
const endpoint = isLikelyAggregationQuery(queryString) ? "/aggregate" : "/query";
|
|
868
|
+
const response = await transport.requestJson(
|
|
869
|
+
"POST",
|
|
870
|
+
endpoint,
|
|
871
|
+
{
|
|
872
|
+
query: queryString,
|
|
873
|
+
params: params ?? {},
|
|
874
|
+
collection,
|
|
875
|
+
timeout_ms: options?.timeoutMs,
|
|
876
|
+
stream: options?.stream ?? false
|
|
877
|
+
}
|
|
878
|
+
);
|
|
879
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
880
|
+
const rawData = response.data;
|
|
881
|
+
if (rawData && Object.prototype.hasOwnProperty.call(rawData, "result")) {
|
|
882
|
+
return {
|
|
883
|
+
result: rawData.result,
|
|
884
|
+
stats: {
|
|
885
|
+
executionTimeMs: rawData.timing_ms ?? 0,
|
|
886
|
+
strategy: "aggregation",
|
|
887
|
+
scannedNodes: 0
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
return {
|
|
892
|
+
results: rawData?.results ?? [],
|
|
893
|
+
stats: {
|
|
894
|
+
executionTimeMs: rawData?.timing_ms ?? 0,
|
|
895
|
+
strategy: "select",
|
|
896
|
+
scannedNodes: rawData?.rows_returned ?? 0
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
async function queryExplain(transport, queryString, params) {
|
|
901
|
+
const response = await transport.requestJson(
|
|
902
|
+
"POST",
|
|
903
|
+
"/query/explain",
|
|
904
|
+
{
|
|
905
|
+
query: queryString,
|
|
906
|
+
params: params ?? {}
|
|
907
|
+
}
|
|
908
|
+
);
|
|
909
|
+
throwOnError(response);
|
|
910
|
+
const data = response.data;
|
|
911
|
+
return {
|
|
912
|
+
query: data.query,
|
|
913
|
+
queryType: data.query_type,
|
|
914
|
+
collection: data.collection,
|
|
915
|
+
plan: data.plan.map((step) => ({
|
|
916
|
+
step: step.step,
|
|
917
|
+
operation: step.operation,
|
|
918
|
+
description: step.description,
|
|
919
|
+
estimatedRows: step.estimated_rows
|
|
920
|
+
})),
|
|
921
|
+
estimatedCost: {
|
|
922
|
+
usesIndex: data.estimated_cost.uses_index,
|
|
923
|
+
indexName: data.estimated_cost.index_name,
|
|
924
|
+
selectivity: data.estimated_cost.selectivity,
|
|
925
|
+
complexity: data.estimated_cost.complexity
|
|
926
|
+
},
|
|
927
|
+
features: {
|
|
928
|
+
hasVectorSearch: data.features.has_vector_search,
|
|
929
|
+
hasFilter: data.features.has_filter,
|
|
930
|
+
hasOrderBy: data.features.has_order_by,
|
|
931
|
+
hasGroupBy: data.features.has_group_by,
|
|
932
|
+
hasAggregation: data.features.has_aggregation,
|
|
933
|
+
hasJoin: data.features.has_join,
|
|
934
|
+
hasFusion: data.features.has_fusion,
|
|
935
|
+
limit: data.features.limit,
|
|
936
|
+
offset: data.features.offset
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
async function collectionSanity(transport, collection) {
|
|
941
|
+
const response = await transport.requestJson(
|
|
942
|
+
"GET",
|
|
943
|
+
`${collectionPath(collection)}/sanity`
|
|
944
|
+
);
|
|
945
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
946
|
+
const data = response.data;
|
|
947
|
+
return {
|
|
948
|
+
collection: data.collection,
|
|
949
|
+
dimension: data.dimension,
|
|
950
|
+
metric: data.metric,
|
|
951
|
+
pointCount: data.point_count,
|
|
952
|
+
isEmpty: data.is_empty,
|
|
953
|
+
checks: {
|
|
954
|
+
hasVectors: data.checks.has_vectors,
|
|
955
|
+
searchReady: data.checks.search_ready,
|
|
956
|
+
dimensionConfigured: data.checks.dimension_configured
|
|
957
|
+
},
|
|
958
|
+
diagnostics: {
|
|
959
|
+
searchRequestsTotal: data.diagnostics.search_requests_total,
|
|
960
|
+
dimensionMismatchTotal: data.diagnostics.dimension_mismatch_total,
|
|
961
|
+
emptySearchResultsTotal: data.diagnostics.empty_search_results_total,
|
|
962
|
+
filterParseErrorsTotal: data.diagnostics.filter_parse_errors_total
|
|
963
|
+
},
|
|
964
|
+
hints: data.hints ?? []
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/backends/admin-backend.ts
|
|
969
|
+
function mapStatsResponse(data) {
|
|
970
|
+
return {
|
|
971
|
+
totalPoints: data.total_points,
|
|
972
|
+
totalSizeBytes: data.total_size_bytes,
|
|
973
|
+
rowCount: data.row_count,
|
|
974
|
+
deletedCount: data.deleted_count,
|
|
975
|
+
avgRowSizeBytes: data.avg_row_size_bytes,
|
|
976
|
+
payloadSizeBytes: data.payload_size_bytes,
|
|
977
|
+
lastAnalyzedEpochMs: data.last_analyzed_epoch_ms
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
async function getCollectionStats(transport, collection) {
|
|
981
|
+
const response = await transport.requestJson(
|
|
982
|
+
"GET",
|
|
983
|
+
`${collectionPath(collection)}/stats`
|
|
984
|
+
);
|
|
985
|
+
if (returnNullOnNotFound(response)) {
|
|
986
|
+
return null;
|
|
987
|
+
}
|
|
988
|
+
return mapStatsResponse(response.data);
|
|
989
|
+
}
|
|
990
|
+
async function analyzeCollection(transport, collection) {
|
|
991
|
+
const response = await transport.requestJson(
|
|
992
|
+
"POST",
|
|
993
|
+
`${collectionPath(collection)}/analyze`
|
|
994
|
+
);
|
|
995
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
996
|
+
return mapStatsResponse(response.data);
|
|
997
|
+
}
|
|
998
|
+
async function getCollectionConfig(transport, collection) {
|
|
999
|
+
const response = await transport.requestJson("GET", `${collectionPath(collection)}/config`);
|
|
1000
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1001
|
+
const data = response.data;
|
|
1002
|
+
return {
|
|
1003
|
+
name: data.name,
|
|
1004
|
+
dimension: data.dimension,
|
|
1005
|
+
metric: data.metric,
|
|
1006
|
+
storageMode: data.storage_mode,
|
|
1007
|
+
pointCount: data.point_count,
|
|
1008
|
+
metadataOnly: data.metadata_only,
|
|
1009
|
+
graphSchema: data.graph_schema,
|
|
1010
|
+
embeddingDimension: data.embedding_dimension
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// src/backends/index-backend.ts
|
|
1015
|
+
async function createIndex(transport, collection, options) {
|
|
1016
|
+
const response = await transport.requestJson(
|
|
1017
|
+
"POST",
|
|
1018
|
+
`${collectionPath(collection)}/indexes`,
|
|
1019
|
+
{
|
|
1020
|
+
label: options.label,
|
|
1021
|
+
property: options.property,
|
|
1022
|
+
index_type: options.indexType ?? "hash"
|
|
1023
|
+
}
|
|
1024
|
+
);
|
|
1025
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1026
|
+
}
|
|
1027
|
+
async function listIndexes(transport, collection) {
|
|
1028
|
+
const response = await transport.requestJson(
|
|
1029
|
+
"GET",
|
|
1030
|
+
`${collectionPath(collection)}/indexes`
|
|
1031
|
+
);
|
|
1032
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1033
|
+
return (response.data?.indexes ?? []).map((idx) => ({
|
|
1034
|
+
label: idx.label,
|
|
1035
|
+
property: idx.property,
|
|
1036
|
+
indexType: idx.index_type,
|
|
1037
|
+
cardinality: idx.cardinality,
|
|
1038
|
+
memoryBytes: idx.memory_bytes
|
|
1039
|
+
}));
|
|
1040
|
+
}
|
|
1041
|
+
async function hasIndex(transport, collection, label, property) {
|
|
1042
|
+
const indexes = await listIndexes(transport, collection);
|
|
1043
|
+
return indexes.some((idx) => idx.label === label && idx.property === property);
|
|
1044
|
+
}
|
|
1045
|
+
async function dropIndex(transport, collection, label, property) {
|
|
1046
|
+
const response = await transport.requestJson(
|
|
1047
|
+
"DELETE",
|
|
1048
|
+
`${collectionPath(collection)}/indexes/${encodeURIComponent(label)}/${encodeURIComponent(property)}`
|
|
1049
|
+
);
|
|
1050
|
+
if (returnNullOnNotFound(response)) {
|
|
1051
|
+
return false;
|
|
1052
|
+
}
|
|
1053
|
+
return response.data?.dropped ?? true;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// src/backends/streaming-backend.ts
|
|
1057
|
+
async function trainPq(transport, collection, options) {
|
|
1058
|
+
const m = options?.m ?? 8;
|
|
1059
|
+
const k = options?.k ?? 256;
|
|
1060
|
+
const withClause = options?.opq ? `WITH (m=${m}, k=${k}, opq=true)` : `WITH (m=${m}, k=${k})`;
|
|
1061
|
+
const queryString = `TRAIN QUANTIZER ON ${collection} ${withClause}`;
|
|
1062
|
+
const response = await transport.requestJson(
|
|
1063
|
+
"POST",
|
|
1064
|
+
"/query",
|
|
1065
|
+
{ query: queryString }
|
|
1066
|
+
);
|
|
1067
|
+
throwOnError(response);
|
|
1068
|
+
return response.data?.message ?? "PQ training initiated";
|
|
1069
|
+
}
|
|
1070
|
+
async function streamInsert(transport, collection, docs) {
|
|
1071
|
+
for (const doc of docs) {
|
|
1072
|
+
const restId = transport.parseRestPointId(doc.id);
|
|
1073
|
+
const vector = toNumberArray(doc.vector);
|
|
1074
|
+
const body = {
|
|
1075
|
+
id: restId,
|
|
1076
|
+
vector,
|
|
1077
|
+
payload: doc.payload
|
|
1078
|
+
};
|
|
1079
|
+
if (doc.sparseVector) {
|
|
1080
|
+
body.sparse_vector = transport.sparseVectorToRestFormat(doc.sparseVector);
|
|
1081
|
+
}
|
|
1082
|
+
const url = `${transport.baseUrl}${collectionPath(collection)}/stream/insert`;
|
|
1083
|
+
const headers = {
|
|
1084
|
+
"Content-Type": "application/json"
|
|
1085
|
+
};
|
|
1086
|
+
if (transport.apiKey) {
|
|
1087
|
+
headers["Authorization"] = `Bearer ${transport.apiKey}`;
|
|
1088
|
+
}
|
|
1089
|
+
const controller = new AbortController();
|
|
1090
|
+
const timeoutId = setTimeout(() => controller.abort(), transport.timeout);
|
|
1091
|
+
try {
|
|
1092
|
+
const response = await fetch(url, {
|
|
1093
|
+
method: "POST",
|
|
1094
|
+
headers,
|
|
1095
|
+
body: JSON.stringify(body),
|
|
1096
|
+
signal: controller.signal
|
|
1097
|
+
});
|
|
1098
|
+
clearTimeout(timeoutId);
|
|
1099
|
+
if (response.status === 429) {
|
|
1100
|
+
throw new BackpressureError();
|
|
1101
|
+
}
|
|
1102
|
+
if (!response.ok && response.status !== 202) {
|
|
1103
|
+
const data = await response.json().catch(() => ({}));
|
|
1104
|
+
const errorPayload = transport.extractErrorPayload(data);
|
|
1105
|
+
throw new VelesDBError(
|
|
1106
|
+
errorPayload.message ?? `HTTP ${response.status}`,
|
|
1107
|
+
errorPayload.code ?? transport.mapStatusToErrorCode(response.status)
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
} catch (error) {
|
|
1111
|
+
clearTimeout(timeoutId);
|
|
1112
|
+
if (error instanceof BackpressureError || error instanceof VelesDBError) {
|
|
1113
|
+
throw error;
|
|
1114
|
+
}
|
|
1115
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1116
|
+
throw new ConnectionError("Request timeout");
|
|
1117
|
+
}
|
|
1118
|
+
throw new ConnectionError(
|
|
1119
|
+
`Stream insert failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1120
|
+
error instanceof Error ? error : void 0
|
|
1121
|
+
);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// src/backends/crud-backend.ts
|
|
1127
|
+
function parseRestPointId(id) {
|
|
1128
|
+
if (typeof id !== "number" || !Number.isFinite(id) || id < 0 || !Number.isInteger(id) || id > Number.MAX_SAFE_INTEGER) {
|
|
1129
|
+
throw new ValidationError(
|
|
1130
|
+
`REST backend requires numeric u64-compatible IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER}). Received: ${String(id)}`
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
return id;
|
|
1134
|
+
}
|
|
1135
|
+
function sparseVectorToRestFormat(sv) {
|
|
1136
|
+
const result = {};
|
|
1137
|
+
for (const [k, v] of Object.entries(sv)) {
|
|
1138
|
+
result[String(k)] = v;
|
|
1139
|
+
}
|
|
1140
|
+
return result;
|
|
1141
|
+
}
|
|
1142
|
+
async function createCollection(transport, name, config) {
|
|
1143
|
+
const response = await transport.requestJson("POST", "/collections", {
|
|
1144
|
+
name,
|
|
1145
|
+
dimension: config.dimension,
|
|
1146
|
+
metric: config.metric ?? "cosine",
|
|
1147
|
+
storage_mode: config.storageMode ?? "full",
|
|
1148
|
+
collection_type: config.collectionType ?? "vector",
|
|
1149
|
+
description: config.description,
|
|
1150
|
+
hnsw_m: config.hnsw?.m,
|
|
1151
|
+
hnsw_ef_construction: config.hnsw?.efConstruction
|
|
1152
|
+
});
|
|
1153
|
+
throwOnError(response);
|
|
1154
|
+
}
|
|
1155
|
+
async function deleteCollection(transport, name) {
|
|
1156
|
+
const response = await transport.requestJson(
|
|
1157
|
+
"DELETE",
|
|
1158
|
+
collectionPath(name)
|
|
1159
|
+
);
|
|
1160
|
+
throwOnError(response, `Collection '${name}'`);
|
|
1161
|
+
}
|
|
1162
|
+
async function getCollection(transport, name) {
|
|
1163
|
+
const response = await transport.requestJson(
|
|
1164
|
+
"GET",
|
|
1165
|
+
collectionPath(name)
|
|
1166
|
+
);
|
|
1167
|
+
if (returnNullOnNotFound(response)) {
|
|
1168
|
+
return null;
|
|
1169
|
+
}
|
|
1170
|
+
return response.data ?? null;
|
|
1171
|
+
}
|
|
1172
|
+
async function listCollections(transport) {
|
|
1173
|
+
const response = await transport.requestJson("GET", "/collections");
|
|
1174
|
+
throwOnError(response);
|
|
1175
|
+
return response.data ?? [];
|
|
1176
|
+
}
|
|
1177
|
+
async function insert(transport, collection, doc) {
|
|
1178
|
+
const restId = parseRestPointId(doc.id);
|
|
1179
|
+
const vector = toNumberArray(doc.vector);
|
|
1180
|
+
const response = await transport.requestJson(
|
|
1181
|
+
"POST",
|
|
1182
|
+
`${collectionPath(collection)}/points`,
|
|
1183
|
+
{ points: [{ id: restId, vector, payload: doc.payload }] }
|
|
1184
|
+
);
|
|
1185
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1186
|
+
}
|
|
1187
|
+
async function insertBatch(transport, collection, docs) {
|
|
1188
|
+
const vectors = docs.map((doc) => ({
|
|
1189
|
+
id: parseRestPointId(doc.id),
|
|
1190
|
+
vector: toNumberArray(doc.vector),
|
|
1191
|
+
payload: doc.payload
|
|
1192
|
+
}));
|
|
1193
|
+
const response = await transport.requestJson(
|
|
1194
|
+
"POST",
|
|
1195
|
+
`${collectionPath(collection)}/points`,
|
|
1196
|
+
{ points: vectors }
|
|
1197
|
+
);
|
|
1198
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1199
|
+
}
|
|
1200
|
+
async function deletePoint(transport, collection, id) {
|
|
1201
|
+
const restId = parseRestPointId(id);
|
|
1202
|
+
const response = await transport.requestJson(
|
|
1203
|
+
"DELETE",
|
|
1204
|
+
`${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
|
|
1205
|
+
);
|
|
1206
|
+
if (returnNullOnNotFound(response)) {
|
|
1207
|
+
return false;
|
|
1208
|
+
}
|
|
1209
|
+
return response.data?.deleted ?? false;
|
|
1210
|
+
}
|
|
1211
|
+
async function get(transport, collection, id) {
|
|
1212
|
+
const restId = parseRestPointId(id);
|
|
1213
|
+
const response = await transport.requestJson(
|
|
1214
|
+
"GET",
|
|
1215
|
+
`${collectionPath(collection)}/points/${encodeURIComponent(String(restId))}`
|
|
1216
|
+
);
|
|
1217
|
+
if (returnNullOnNotFound(response)) {
|
|
1218
|
+
return null;
|
|
1219
|
+
}
|
|
1220
|
+
return response.data ?? null;
|
|
1221
|
+
}
|
|
1222
|
+
async function isEmpty(transport, collection) {
|
|
1223
|
+
const response = await transport.requestJson(
|
|
1224
|
+
"GET",
|
|
1225
|
+
`${collectionPath(collection)}/empty`
|
|
1226
|
+
);
|
|
1227
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1228
|
+
return response.data?.is_empty ?? true;
|
|
1229
|
+
}
|
|
1230
|
+
async function flush(transport, collection) {
|
|
1231
|
+
const response = await transport.requestJson(
|
|
1232
|
+
"POST",
|
|
1233
|
+
`${collectionPath(collection)}/flush`
|
|
1234
|
+
);
|
|
1235
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1236
|
+
}
|
|
1237
|
+
|
|
348
1238
|
// src/backends/rest.ts
|
|
349
1239
|
var RestBackend = class {
|
|
350
1240
|
constructor(url, apiKey, timeout = 3e4) {
|
|
@@ -405,15 +1295,13 @@ var RestBackend = class {
|
|
|
405
1295
|
return {};
|
|
406
1296
|
}
|
|
407
1297
|
const payload = data;
|
|
408
|
-
const
|
|
409
|
-
const
|
|
1298
|
+
const nestedError = payload.error && typeof payload.error === "object" ? payload.error : void 0;
|
|
1299
|
+
const codeField = nestedError?.code ?? payload.code;
|
|
1300
|
+
const code = typeof codeField === "string" ? codeField : void 0;
|
|
1301
|
+
const messageField = nestedError?.message ?? payload.message ?? payload.error;
|
|
410
1302
|
const message = typeof messageField === "string" ? messageField : void 0;
|
|
411
1303
|
return { code, message };
|
|
412
1304
|
}
|
|
413
|
-
/**
|
|
414
|
-
* Parse node ID safely to handle u64 values above Number.MAX_SAFE_INTEGER.
|
|
415
|
-
* Returns bigint for large values, number for safe values.
|
|
416
|
-
*/
|
|
417
1305
|
parseNodeId(value) {
|
|
418
1306
|
if (value === null || value === void 0) {
|
|
419
1307
|
return 0;
|
|
@@ -423,24 +1311,16 @@ var RestBackend = class {
|
|
|
423
1311
|
}
|
|
424
1312
|
if (typeof value === "string") {
|
|
425
1313
|
const num = Number(value);
|
|
426
|
-
|
|
427
|
-
return BigInt(value);
|
|
428
|
-
}
|
|
429
|
-
return num;
|
|
1314
|
+
return num > Number.MAX_SAFE_INTEGER ? BigInt(value) : num;
|
|
430
1315
|
}
|
|
431
1316
|
if (typeof value === "number") {
|
|
432
|
-
if (value > Number.MAX_SAFE_INTEGER) {
|
|
433
|
-
return value;
|
|
434
|
-
}
|
|
435
1317
|
return value;
|
|
436
1318
|
}
|
|
437
1319
|
return 0;
|
|
438
1320
|
}
|
|
439
1321
|
async request(method, path, body) {
|
|
440
1322
|
const url = `${this.baseUrl}${path}`;
|
|
441
|
-
const headers = {
|
|
442
|
-
"Content-Type": "application/json"
|
|
443
|
-
};
|
|
1323
|
+
const headers = { "Content-Type": "application/json" };
|
|
444
1324
|
if (this.apiKey) {
|
|
445
1325
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
446
1326
|
}
|
|
@@ -476,445 +1356,259 @@ var RestBackend = class {
|
|
|
476
1356
|
);
|
|
477
1357
|
}
|
|
478
1358
|
}
|
|
1359
|
+
// ==========================================================================
|
|
1360
|
+
// Transport adapters
|
|
1361
|
+
// ==========================================================================
|
|
1362
|
+
asCrudTransport() {
|
|
1363
|
+
return {
|
|
1364
|
+
requestJson: (m, p, b) => this.request(m, p, b)
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
asSearchTransport() {
|
|
1368
|
+
return {
|
|
1369
|
+
requestJson: (m, p, b) => this.request(m, p, b),
|
|
1370
|
+
sparseToRest: (sv) => sparseVectorToRestFormat(sv)
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
asAgentMemoryTransport() {
|
|
1374
|
+
return {
|
|
1375
|
+
requestJson: (m, p, b) => this.request(m, p, b),
|
|
1376
|
+
searchVectors: (c, e, k, f) => this.search(c, e, { k, filter: f })
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
asQueryTransport() {
|
|
1380
|
+
return {
|
|
1381
|
+
requestJson: (m, p, b) => this.request(m, p, b),
|
|
1382
|
+
parseNodeId: (v) => this.parseNodeId(v)
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
asStreamingTransport() {
|
|
1386
|
+
return {
|
|
1387
|
+
requestJson: (m, p, b) => this.request(m, p, b),
|
|
1388
|
+
baseUrl: this.baseUrl,
|
|
1389
|
+
apiKey: this.apiKey,
|
|
1390
|
+
timeout: this.timeout,
|
|
1391
|
+
parseRestPointId,
|
|
1392
|
+
sparseVectorToRestFormat,
|
|
1393
|
+
mapStatusToErrorCode: (s) => this.mapStatusToErrorCode(s),
|
|
1394
|
+
extractErrorPayload: (d) => this.extractErrorPayload(d)
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
// ==========================================================================
|
|
1398
|
+
// Collection CRUD — delegates to crud-backend.ts
|
|
1399
|
+
// ==========================================================================
|
|
479
1400
|
async createCollection(name, config) {
|
|
480
1401
|
this.ensureInitialized();
|
|
481
|
-
|
|
482
|
-
name,
|
|
483
|
-
dimension: config.dimension,
|
|
484
|
-
metric: config.metric ?? "cosine",
|
|
485
|
-
storage_mode: config.storageMode ?? "full",
|
|
486
|
-
collection_type: config.collectionType ?? "vector",
|
|
487
|
-
description: config.description
|
|
488
|
-
});
|
|
489
|
-
if (response.error) {
|
|
490
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
491
|
-
}
|
|
1402
|
+
return createCollection(this.asCrudTransport(), name, config);
|
|
492
1403
|
}
|
|
493
1404
|
async deleteCollection(name) {
|
|
494
1405
|
this.ensureInitialized();
|
|
495
|
-
|
|
496
|
-
if (response.error) {
|
|
497
|
-
if (response.error.code === "NOT_FOUND") {
|
|
498
|
-
throw new NotFoundError(`Collection '${name}'`);
|
|
499
|
-
}
|
|
500
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
501
|
-
}
|
|
1406
|
+
return deleteCollection(this.asCrudTransport(), name);
|
|
502
1407
|
}
|
|
503
1408
|
async getCollection(name) {
|
|
504
1409
|
this.ensureInitialized();
|
|
505
|
-
|
|
506
|
-
"GET",
|
|
507
|
-
`/collections/${encodeURIComponent(name)}`
|
|
508
|
-
);
|
|
509
|
-
if (response.error) {
|
|
510
|
-
if (response.error.code === "NOT_FOUND") {
|
|
511
|
-
return null;
|
|
512
|
-
}
|
|
513
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
514
|
-
}
|
|
515
|
-
return response.data ?? null;
|
|
1410
|
+
return getCollection(this.asCrudTransport(), name);
|
|
516
1411
|
}
|
|
517
1412
|
async listCollections() {
|
|
518
1413
|
this.ensureInitialized();
|
|
519
|
-
|
|
520
|
-
if (response.error) {
|
|
521
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
522
|
-
}
|
|
523
|
-
return response.data ?? [];
|
|
1414
|
+
return listCollections(this.asCrudTransport());
|
|
524
1415
|
}
|
|
525
1416
|
async insert(collection, doc) {
|
|
526
1417
|
this.ensureInitialized();
|
|
527
|
-
|
|
528
|
-
const response = await this.request(
|
|
529
|
-
"POST",
|
|
530
|
-
`/collections/${encodeURIComponent(collection)}/points`,
|
|
531
|
-
{
|
|
532
|
-
points: [{
|
|
533
|
-
id: doc.id,
|
|
534
|
-
vector,
|
|
535
|
-
payload: doc.payload
|
|
536
|
-
}]
|
|
537
|
-
}
|
|
538
|
-
);
|
|
539
|
-
if (response.error) {
|
|
540
|
-
if (response.error.code === "NOT_FOUND") {
|
|
541
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
542
|
-
}
|
|
543
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
544
|
-
}
|
|
1418
|
+
return insert(this.asCrudTransport(), collection, doc);
|
|
545
1419
|
}
|
|
546
1420
|
async insertBatch(collection, docs) {
|
|
547
1421
|
this.ensureInitialized();
|
|
548
|
-
|
|
549
|
-
id: doc.id,
|
|
550
|
-
vector: doc.vector instanceof Float32Array ? Array.from(doc.vector) : doc.vector,
|
|
551
|
-
payload: doc.payload
|
|
552
|
-
}));
|
|
553
|
-
const response = await this.request(
|
|
554
|
-
"POST",
|
|
555
|
-
`/collections/${encodeURIComponent(collection)}/points`,
|
|
556
|
-
{ points: vectors }
|
|
557
|
-
);
|
|
558
|
-
if (response.error) {
|
|
559
|
-
if (response.error.code === "NOT_FOUND") {
|
|
560
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
561
|
-
}
|
|
562
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
563
|
-
}
|
|
1422
|
+
return insertBatch(this.asCrudTransport(), collection, docs);
|
|
564
1423
|
}
|
|
565
|
-
async
|
|
1424
|
+
async delete(collection, id) {
|
|
566
1425
|
this.ensureInitialized();
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
1426
|
+
return deletePoint(this.asCrudTransport(), collection, id);
|
|
1427
|
+
}
|
|
1428
|
+
async get(collection, id) {
|
|
1429
|
+
this.ensureInitialized();
|
|
1430
|
+
return get(this.asCrudTransport(), collection, id);
|
|
1431
|
+
}
|
|
1432
|
+
async isEmpty(collection) {
|
|
1433
|
+
this.ensureInitialized();
|
|
1434
|
+
return isEmpty(this.asCrudTransport(), collection);
|
|
1435
|
+
}
|
|
1436
|
+
async flush(collection) {
|
|
1437
|
+
this.ensureInitialized();
|
|
1438
|
+
return flush(this.asCrudTransport(), collection);
|
|
1439
|
+
}
|
|
1440
|
+
async close() {
|
|
1441
|
+
this._initialized = false;
|
|
1442
|
+
}
|
|
1443
|
+
// ==========================================================================
|
|
1444
|
+
// Search — delegates to search-backend.ts
|
|
1445
|
+
// ==========================================================================
|
|
1446
|
+
async search(c, q, o) {
|
|
1447
|
+
this.ensureInitialized();
|
|
1448
|
+
return search(this.asSearchTransport(), c, q, o);
|
|
585
1449
|
}
|
|
586
1450
|
async searchBatch(collection, searches) {
|
|
587
1451
|
this.ensureInitialized();
|
|
588
|
-
|
|
589
|
-
vector: s.vector instanceof Float32Array ? Array.from(s.vector) : s.vector,
|
|
590
|
-
top_k: s.k ?? 10,
|
|
591
|
-
filter: s.filter
|
|
592
|
-
}));
|
|
593
|
-
const response = await this.request(
|
|
594
|
-
"POST",
|
|
595
|
-
`/collections/${encodeURIComponent(collection)}/search/batch`,
|
|
596
|
-
{ searches: formattedSearches }
|
|
597
|
-
);
|
|
598
|
-
if (response.error) {
|
|
599
|
-
if (response.error.code === "NOT_FOUND") {
|
|
600
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
601
|
-
}
|
|
602
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
603
|
-
}
|
|
604
|
-
return response.data?.results.map((r) => r.results) ?? [];
|
|
1452
|
+
return searchBatch(this.asSearchTransport(), collection, searches);
|
|
605
1453
|
}
|
|
606
|
-
async
|
|
1454
|
+
async textSearch(c, q, o) {
|
|
607
1455
|
this.ensureInitialized();
|
|
608
|
-
|
|
609
|
-
"DELETE",
|
|
610
|
-
`/collections/${encodeURIComponent(collection)}/points/${encodeURIComponent(String(id))}`
|
|
611
|
-
);
|
|
612
|
-
if (response.error) {
|
|
613
|
-
if (response.error.code === "NOT_FOUND") {
|
|
614
|
-
return false;
|
|
615
|
-
}
|
|
616
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
617
|
-
}
|
|
618
|
-
return response.data?.deleted ?? false;
|
|
1456
|
+
return textSearch(this.asSearchTransport(), c, q, o);
|
|
619
1457
|
}
|
|
620
|
-
async
|
|
1458
|
+
async hybridSearch(c, v, t, o) {
|
|
621
1459
|
this.ensureInitialized();
|
|
622
|
-
|
|
623
|
-
"GET",
|
|
624
|
-
`/collections/${encodeURIComponent(collection)}/points/${encodeURIComponent(String(id))}`
|
|
625
|
-
);
|
|
626
|
-
if (response.error) {
|
|
627
|
-
if (response.error.code === "NOT_FOUND") {
|
|
628
|
-
return null;
|
|
629
|
-
}
|
|
630
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
631
|
-
}
|
|
632
|
-
return response.data ?? null;
|
|
1460
|
+
return hybridSearch(this.asSearchTransport(), c, v, t, o);
|
|
633
1461
|
}
|
|
634
|
-
async
|
|
1462
|
+
async multiQuerySearch(c, v, o) {
|
|
635
1463
|
this.ensureInitialized();
|
|
636
|
-
|
|
637
|
-
"POST",
|
|
638
|
-
`/collections/${encodeURIComponent(collection)}/search/text`,
|
|
639
|
-
{
|
|
640
|
-
query,
|
|
641
|
-
top_k: options?.k ?? 10,
|
|
642
|
-
filter: options?.filter
|
|
643
|
-
}
|
|
644
|
-
);
|
|
645
|
-
if (response.error) {
|
|
646
|
-
if (response.error.code === "NOT_FOUND") {
|
|
647
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
648
|
-
}
|
|
649
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
650
|
-
}
|
|
651
|
-
return response.data?.results ?? [];
|
|
1464
|
+
return multiQuerySearch(this.asSearchTransport(), c, v, o);
|
|
652
1465
|
}
|
|
653
|
-
async
|
|
1466
|
+
async searchIds(c, q, o) {
|
|
654
1467
|
this.ensureInitialized();
|
|
655
|
-
|
|
656
|
-
const response = await this.request(
|
|
657
|
-
"POST",
|
|
658
|
-
`/collections/${encodeURIComponent(collection)}/search/hybrid`,
|
|
659
|
-
{
|
|
660
|
-
vector: queryVector,
|
|
661
|
-
query: textQuery,
|
|
662
|
-
top_k: options?.k ?? 10,
|
|
663
|
-
vector_weight: options?.vectorWeight ?? 0.5,
|
|
664
|
-
filter: options?.filter
|
|
665
|
-
}
|
|
666
|
-
);
|
|
667
|
-
if (response.error) {
|
|
668
|
-
if (response.error.code === "NOT_FOUND") {
|
|
669
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
670
|
-
}
|
|
671
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
672
|
-
}
|
|
673
|
-
return response.data?.results ?? [];
|
|
1468
|
+
return searchIds(this.asSearchTransport(), c, q, o);
|
|
674
1469
|
}
|
|
675
|
-
|
|
1470
|
+
// ==========================================================================
|
|
1471
|
+
// Query — delegates to query-backend.ts
|
|
1472
|
+
// ==========================================================================
|
|
1473
|
+
async query(c, q, p, o) {
|
|
676
1474
|
this.ensureInitialized();
|
|
677
|
-
|
|
678
|
-
"POST",
|
|
679
|
-
"/query",
|
|
680
|
-
{
|
|
681
|
-
query: queryString,
|
|
682
|
-
params: params ?? {}
|
|
683
|
-
}
|
|
684
|
-
);
|
|
685
|
-
if (response.error) {
|
|
686
|
-
if (response.error.code === "NOT_FOUND") {
|
|
687
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
688
|
-
}
|
|
689
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
690
|
-
}
|
|
691
|
-
const rawData = response.data;
|
|
692
|
-
return {
|
|
693
|
-
results: (rawData?.results ?? []).map((r) => ({
|
|
694
|
-
// Server returns `id` (u64), map to nodeId with precision handling
|
|
695
|
-
nodeId: this.parseNodeId(r.id ?? r.node_id ?? r.nodeId),
|
|
696
|
-
// Server returns `score`, map to vectorScore (primary score for SELECT queries)
|
|
697
|
-
vectorScore: r.score ?? r.vector_score ?? r.vectorScore,
|
|
698
|
-
// graph_score not returned by SELECT queries, only by future MATCH queries
|
|
699
|
-
graphScore: r.graph_score ?? r.graphScore,
|
|
700
|
-
// Use score as fusedScore for compatibility
|
|
701
|
-
fusedScore: r.score ?? r.fused_score ?? r.fusedScore ?? 0,
|
|
702
|
-
// payload maps to bindings for compatibility
|
|
703
|
-
bindings: r.payload ?? r.bindings ?? {},
|
|
704
|
-
columnData: r.column_data ?? r.columnData
|
|
705
|
-
})),
|
|
706
|
-
stats: {
|
|
707
|
-
executionTimeMs: rawData?.timing_ms ?? 0,
|
|
708
|
-
strategy: "select",
|
|
709
|
-
scannedNodes: rawData?.rows_returned ?? 0
|
|
710
|
-
}
|
|
711
|
-
};
|
|
1475
|
+
return query(this.asQueryTransport(), c, q, p, o);
|
|
712
1476
|
}
|
|
713
|
-
async
|
|
1477
|
+
async queryExplain(q, p) {
|
|
714
1478
|
this.ensureInitialized();
|
|
715
|
-
|
|
716
|
-
(v) => v instanceof Float32Array ? Array.from(v) : v
|
|
717
|
-
);
|
|
718
|
-
const response = await this.request(
|
|
719
|
-
"POST",
|
|
720
|
-
`/collections/${encodeURIComponent(collection)}/search/multi`,
|
|
721
|
-
{
|
|
722
|
-
vectors: formattedVectors,
|
|
723
|
-
top_k: options?.k ?? 10,
|
|
724
|
-
strategy: options?.fusion ?? "rrf",
|
|
725
|
-
rrf_k: options?.fusionParams?.k ?? 60,
|
|
726
|
-
filter: options?.filter
|
|
727
|
-
}
|
|
728
|
-
);
|
|
729
|
-
if (response.error) {
|
|
730
|
-
if (response.error.code === "NOT_FOUND") {
|
|
731
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
732
|
-
}
|
|
733
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
734
|
-
}
|
|
735
|
-
return response.data?.results ?? [];
|
|
1479
|
+
return queryExplain(this.asQueryTransport(), q, p);
|
|
736
1480
|
}
|
|
737
|
-
async
|
|
1481
|
+
async collectionSanity(collection) {
|
|
738
1482
|
this.ensureInitialized();
|
|
739
|
-
|
|
740
|
-
"GET",
|
|
741
|
-
`/collections/${encodeURIComponent(collection)}/empty`
|
|
742
|
-
);
|
|
743
|
-
if (response.error) {
|
|
744
|
-
if (response.error.code === "NOT_FOUND") {
|
|
745
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
746
|
-
}
|
|
747
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
748
|
-
}
|
|
749
|
-
return response.data?.is_empty ?? true;
|
|
1483
|
+
return collectionSanity(this.asQueryTransport(), collection);
|
|
750
1484
|
}
|
|
751
|
-
|
|
1485
|
+
// ==========================================================================
|
|
1486
|
+
// Graph — delegates to graph-backend.ts
|
|
1487
|
+
// ==========================================================================
|
|
1488
|
+
async addEdge(collection, edge) {
|
|
752
1489
|
this.ensureInitialized();
|
|
753
|
-
|
|
754
|
-
"POST",
|
|
755
|
-
`/collections/${encodeURIComponent(collection)}/flush`
|
|
756
|
-
);
|
|
757
|
-
if (response.error) {
|
|
758
|
-
if (response.error.code === "NOT_FOUND") {
|
|
759
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
760
|
-
}
|
|
761
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
762
|
-
}
|
|
1490
|
+
return addEdge(this.asCrudTransport(), collection, edge);
|
|
763
1491
|
}
|
|
764
|
-
async
|
|
765
|
-
this.
|
|
1492
|
+
async getEdges(collection, options) {
|
|
1493
|
+
this.ensureInitialized();
|
|
1494
|
+
return getEdges(this.asCrudTransport(), collection, options);
|
|
766
1495
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
1496
|
+
async traverseGraph(collection, req) {
|
|
1497
|
+
this.ensureInitialized();
|
|
1498
|
+
return traverseGraph(this.asCrudTransport(), collection, req);
|
|
1499
|
+
}
|
|
1500
|
+
async getNodeDegree(collection, nodeId) {
|
|
1501
|
+
this.ensureInitialized();
|
|
1502
|
+
return getNodeDegree(this.asCrudTransport(), collection, nodeId);
|
|
1503
|
+
}
|
|
1504
|
+
async createGraphCollection(name, config) {
|
|
1505
|
+
this.ensureInitialized();
|
|
1506
|
+
return createGraphCollection(this.asCrudTransport(), name, config);
|
|
1507
|
+
}
|
|
1508
|
+
// ==========================================================================
|
|
1509
|
+
// Index — delegates to index-backend.ts
|
|
1510
|
+
// ==========================================================================
|
|
770
1511
|
async createIndex(collection, options) {
|
|
771
1512
|
this.ensureInitialized();
|
|
772
|
-
|
|
773
|
-
"POST",
|
|
774
|
-
`/collections/${encodeURIComponent(collection)}/indexes`,
|
|
775
|
-
{
|
|
776
|
-
label: options.label,
|
|
777
|
-
property: options.property,
|
|
778
|
-
index_type: options.indexType ?? "hash"
|
|
779
|
-
}
|
|
780
|
-
);
|
|
781
|
-
if (response.error) {
|
|
782
|
-
if (response.error.code === "NOT_FOUND") {
|
|
783
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
784
|
-
}
|
|
785
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
786
|
-
}
|
|
1513
|
+
return createIndex(this.asCrudTransport(), collection, options);
|
|
787
1514
|
}
|
|
788
1515
|
async listIndexes(collection) {
|
|
789
1516
|
this.ensureInitialized();
|
|
790
|
-
|
|
791
|
-
"GET",
|
|
792
|
-
`/collections/${encodeURIComponent(collection)}/indexes`
|
|
793
|
-
);
|
|
794
|
-
if (response.error) {
|
|
795
|
-
if (response.error.code === "NOT_FOUND") {
|
|
796
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
797
|
-
}
|
|
798
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
799
|
-
}
|
|
800
|
-
return (response.data?.indexes ?? []).map((idx) => ({
|
|
801
|
-
label: idx.label,
|
|
802
|
-
property: idx.property,
|
|
803
|
-
indexType: idx.index_type,
|
|
804
|
-
cardinality: idx.cardinality,
|
|
805
|
-
memoryBytes: idx.memory_bytes
|
|
806
|
-
}));
|
|
1517
|
+
return listIndexes(this.asCrudTransport(), collection);
|
|
807
1518
|
}
|
|
808
1519
|
async hasIndex(collection, label, property) {
|
|
809
|
-
|
|
810
|
-
return
|
|
1520
|
+
this.ensureInitialized();
|
|
1521
|
+
return hasIndex(this.asCrudTransport(), collection, label, property);
|
|
811
1522
|
}
|
|
812
1523
|
async dropIndex(collection, label, property) {
|
|
813
1524
|
this.ensureInitialized();
|
|
814
|
-
|
|
815
|
-
"DELETE",
|
|
816
|
-
`/collections/${encodeURIComponent(collection)}/indexes/${encodeURIComponent(label)}/${encodeURIComponent(property)}`
|
|
817
|
-
);
|
|
818
|
-
if (response.error) {
|
|
819
|
-
if (response.error.code === "NOT_FOUND") {
|
|
820
|
-
return false;
|
|
821
|
-
}
|
|
822
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
823
|
-
}
|
|
824
|
-
return response.data?.dropped ?? true;
|
|
1525
|
+
return dropIndex(this.asCrudTransport(), collection, label, property);
|
|
825
1526
|
}
|
|
826
|
-
//
|
|
827
|
-
//
|
|
828
|
-
//
|
|
829
|
-
async
|
|
1527
|
+
// ==========================================================================
|
|
1528
|
+
// Admin — delegates to admin-backend.ts
|
|
1529
|
+
// ==========================================================================
|
|
1530
|
+
async getCollectionStats(collection) {
|
|
830
1531
|
this.ensureInitialized();
|
|
831
|
-
|
|
832
|
-
"POST",
|
|
833
|
-
`/collections/${encodeURIComponent(collection)}/graph/edges`,
|
|
834
|
-
{
|
|
835
|
-
id: edge.id,
|
|
836
|
-
source: edge.source,
|
|
837
|
-
target: edge.target,
|
|
838
|
-
label: edge.label,
|
|
839
|
-
properties: edge.properties ?? {}
|
|
840
|
-
}
|
|
841
|
-
);
|
|
842
|
-
if (response.error) {
|
|
843
|
-
if (response.error.code === "NOT_FOUND") {
|
|
844
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
845
|
-
}
|
|
846
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
847
|
-
}
|
|
1532
|
+
return getCollectionStats(this.asCrudTransport(), collection);
|
|
848
1533
|
}
|
|
849
|
-
async
|
|
1534
|
+
async analyzeCollection(collection) {
|
|
850
1535
|
this.ensureInitialized();
|
|
851
|
-
|
|
852
|
-
const response = await this.request(
|
|
853
|
-
"GET",
|
|
854
|
-
`/collections/${encodeURIComponent(collection)}/graph/edges${queryParams}`
|
|
855
|
-
);
|
|
856
|
-
if (response.error) {
|
|
857
|
-
if (response.error.code === "NOT_FOUND") {
|
|
858
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
859
|
-
}
|
|
860
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
861
|
-
}
|
|
862
|
-
return response.data?.edges ?? [];
|
|
1536
|
+
return analyzeCollection(this.asCrudTransport(), collection);
|
|
863
1537
|
}
|
|
864
|
-
|
|
865
|
-
// Graph Traversal (EPIC-016 US-050)
|
|
866
|
-
// ========================================================================
|
|
867
|
-
async traverseGraph(collection, request) {
|
|
1538
|
+
async getCollectionConfig(collection) {
|
|
868
1539
|
this.ensureInitialized();
|
|
869
|
-
|
|
870
|
-
"POST",
|
|
871
|
-
`/collections/${encodeURIComponent(collection)}/graph/traverse`,
|
|
872
|
-
{
|
|
873
|
-
source: request.source,
|
|
874
|
-
strategy: request.strategy ?? "bfs",
|
|
875
|
-
max_depth: request.maxDepth ?? 3,
|
|
876
|
-
limit: request.limit ?? 100,
|
|
877
|
-
cursor: request.cursor,
|
|
878
|
-
rel_types: request.relTypes ?? []
|
|
879
|
-
}
|
|
880
|
-
);
|
|
881
|
-
if (response.error) {
|
|
882
|
-
if (response.error.code === "NOT_FOUND") {
|
|
883
|
-
throw new NotFoundError(`Collection '${collection}'`);
|
|
884
|
-
}
|
|
885
|
-
throw new VelesDBError(response.error.message, response.error.code);
|
|
886
|
-
}
|
|
887
|
-
const data = response.data;
|
|
888
|
-
return {
|
|
889
|
-
results: data.results.map((r) => ({
|
|
890
|
-
targetId: r.target_id,
|
|
891
|
-
depth: r.depth,
|
|
892
|
-
path: r.path
|
|
893
|
-
})),
|
|
894
|
-
nextCursor: data.next_cursor ?? void 0,
|
|
895
|
-
hasMore: data.has_more,
|
|
896
|
-
stats: {
|
|
897
|
-
visited: data.stats.visited,
|
|
898
|
-
depthReached: data.stats.depth_reached
|
|
899
|
-
}
|
|
900
|
-
};
|
|
1540
|
+
return getCollectionConfig(this.asCrudTransport(), collection);
|
|
901
1541
|
}
|
|
902
|
-
|
|
1542
|
+
// ==========================================================================
|
|
1543
|
+
// Streaming / PQ — delegates to streaming-backend.ts
|
|
1544
|
+
// ==========================================================================
|
|
1545
|
+
async trainPq(collection, options) {
|
|
903
1546
|
this.ensureInitialized();
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
);
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1547
|
+
return trainPq(this.asStreamingTransport(), collection, options);
|
|
1548
|
+
}
|
|
1549
|
+
async streamInsert(collection, docs) {
|
|
1550
|
+
this.ensureInitialized();
|
|
1551
|
+
return streamInsert(this.asStreamingTransport(), collection, docs);
|
|
1552
|
+
}
|
|
1553
|
+
// ==========================================================================
|
|
1554
|
+
// Agent Memory — delegates to agent-memory-backend.ts
|
|
1555
|
+
// ==========================================================================
|
|
1556
|
+
async storeSemanticFact(collection, entry) {
|
|
1557
|
+
this.ensureInitialized();
|
|
1558
|
+
return storeSemanticFact(this.asAgentMemoryTransport(), collection, entry);
|
|
1559
|
+
}
|
|
1560
|
+
async searchSemanticMemory(collection, embedding, k = 5) {
|
|
1561
|
+
return searchSemanticMemory(this.asAgentMemoryTransport(), collection, embedding, k);
|
|
1562
|
+
}
|
|
1563
|
+
async recordEpisodicEvent(collection, event) {
|
|
1564
|
+
this.ensureInitialized();
|
|
1565
|
+
return recordEpisodicEvent(this.asAgentMemoryTransport(), collection, event);
|
|
1566
|
+
}
|
|
1567
|
+
async recallEpisodicEvents(collection, embedding, k = 5) {
|
|
1568
|
+
return recallEpisodicEvents(this.asAgentMemoryTransport(), collection, embedding, k);
|
|
1569
|
+
}
|
|
1570
|
+
async storeProceduralPattern(collection, pattern) {
|
|
1571
|
+
this.ensureInitialized();
|
|
1572
|
+
return storeProceduralPattern(this.asAgentMemoryTransport(), collection, pattern);
|
|
1573
|
+
}
|
|
1574
|
+
async matchProceduralPatterns(collection, embedding, k = 5) {
|
|
1575
|
+
return matchProceduralPatterns(this.asAgentMemoryTransport(), collection, embedding, k);
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
|
|
1579
|
+
// src/agent-memory.ts
|
|
1580
|
+
var AgentMemoryClient = class {
|
|
1581
|
+
constructor(backend, config) {
|
|
1582
|
+
this.backend = backend;
|
|
1583
|
+
this.config = config;
|
|
1584
|
+
}
|
|
1585
|
+
/** Configured embedding dimension (default: 384) */
|
|
1586
|
+
get dimension() {
|
|
1587
|
+
return this.config?.dimension ?? 384;
|
|
1588
|
+
}
|
|
1589
|
+
/** Store a semantic fact */
|
|
1590
|
+
async storeFact(collection, entry) {
|
|
1591
|
+
return this.backend.storeSemanticFact(collection, entry);
|
|
1592
|
+
}
|
|
1593
|
+
/** Search semantic memory */
|
|
1594
|
+
async searchFacts(collection, embedding, k = 5) {
|
|
1595
|
+
return this.backend.searchSemanticMemory(collection, embedding, k);
|
|
1596
|
+
}
|
|
1597
|
+
/** Record an episodic event */
|
|
1598
|
+
async recordEvent(collection, event) {
|
|
1599
|
+
return this.backend.recordEpisodicEvent(collection, event);
|
|
1600
|
+
}
|
|
1601
|
+
/** Recall episodic events */
|
|
1602
|
+
async recallEvents(collection, embedding, k = 5) {
|
|
1603
|
+
return this.backend.recallEpisodicEvents(collection, embedding, k);
|
|
1604
|
+
}
|
|
1605
|
+
/** Store a procedural pattern */
|
|
1606
|
+
async learnProcedure(collection, pattern) {
|
|
1607
|
+
return this.backend.storeProceduralPattern(collection, pattern);
|
|
1608
|
+
}
|
|
1609
|
+
/** Match procedural patterns */
|
|
1610
|
+
async recallProcedures(collection, embedding, k = 5) {
|
|
1611
|
+
return this.backend.matchProceduralPatterns(collection, embedding, k);
|
|
918
1612
|
}
|
|
919
1613
|
};
|
|
920
1614
|
|
|
@@ -1077,6 +1771,18 @@ var VelesDB = class {
|
|
|
1077
1771
|
if (!Array.isArray(doc.vector) && !(doc.vector instanceof Float32Array)) {
|
|
1078
1772
|
throw new ValidationError("Vector must be an array or Float32Array");
|
|
1079
1773
|
}
|
|
1774
|
+
if (this.config.backend === "rest" && (typeof doc.id !== "number" || !Number.isInteger(doc.id) || doc.id < 0 || doc.id > Number.MAX_SAFE_INTEGER)) {
|
|
1775
|
+
throw new ValidationError(
|
|
1776
|
+
`REST backend requires numeric u64-compatible document IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER})`
|
|
1777
|
+
);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
validateRestPointId(id) {
|
|
1781
|
+
if (this.config.backend === "rest" && (typeof id !== "number" || !Number.isInteger(id) || id < 0 || id > Number.MAX_SAFE_INTEGER)) {
|
|
1782
|
+
throw new ValidationError(
|
|
1783
|
+
`REST backend requires numeric u64-compatible document IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER})`
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1080
1786
|
}
|
|
1081
1787
|
/**
|
|
1082
1788
|
* Search for similar vectors
|
|
@@ -1086,12 +1792,12 @@ var VelesDB = class {
|
|
|
1086
1792
|
* @param options - Search options
|
|
1087
1793
|
* @returns Search results sorted by relevance
|
|
1088
1794
|
*/
|
|
1089
|
-
async search(collection,
|
|
1795
|
+
async search(collection, query2, options) {
|
|
1090
1796
|
this.ensureInitialized();
|
|
1091
|
-
if (!
|
|
1797
|
+
if (!query2 || !Array.isArray(query2) && !(query2 instanceof Float32Array)) {
|
|
1092
1798
|
throw new ValidationError("Query must be an array or Float32Array");
|
|
1093
1799
|
}
|
|
1094
|
-
return this.backend.search(collection,
|
|
1800
|
+
return this.backend.search(collection, query2, options);
|
|
1095
1801
|
}
|
|
1096
1802
|
/**
|
|
1097
1803
|
* Search for multiple vectors in parallel
|
|
@@ -1121,6 +1827,7 @@ var VelesDB = class {
|
|
|
1121
1827
|
*/
|
|
1122
1828
|
async delete(collection, id) {
|
|
1123
1829
|
this.ensureInitialized();
|
|
1830
|
+
this.validateRestPointId(id);
|
|
1124
1831
|
return this.backend.delete(collection, id);
|
|
1125
1832
|
}
|
|
1126
1833
|
/**
|
|
@@ -1132,6 +1839,7 @@ var VelesDB = class {
|
|
|
1132
1839
|
*/
|
|
1133
1840
|
async get(collection, id) {
|
|
1134
1841
|
this.ensureInitialized();
|
|
1842
|
+
this.validateRestPointId(id);
|
|
1135
1843
|
return this.backend.get(collection, id);
|
|
1136
1844
|
}
|
|
1137
1845
|
/**
|
|
@@ -1142,12 +1850,12 @@ var VelesDB = class {
|
|
|
1142
1850
|
* @param options - Search options (k, filter)
|
|
1143
1851
|
* @returns Search results sorted by BM25 score
|
|
1144
1852
|
*/
|
|
1145
|
-
async textSearch(collection,
|
|
1853
|
+
async textSearch(collection, query2, options) {
|
|
1146
1854
|
this.ensureInitialized();
|
|
1147
|
-
if (!
|
|
1855
|
+
if (!query2 || typeof query2 !== "string") {
|
|
1148
1856
|
throw new ValidationError("Query must be a non-empty string");
|
|
1149
1857
|
}
|
|
1150
|
-
return this.backend.textSearch(collection,
|
|
1858
|
+
return this.backend.textSearch(collection, query2, options);
|
|
1151
1859
|
}
|
|
1152
1860
|
/**
|
|
1153
1861
|
* Perform hybrid search combining vector similarity and BM25 text search
|
|
@@ -1186,7 +1894,7 @@ var VelesDB = class {
|
|
|
1186
1894
|
* `, { q: queryVector });
|
|
1187
1895
|
*
|
|
1188
1896
|
* for (const r of response.results) {
|
|
1189
|
-
* console.log(`
|
|
1897
|
+
* console.log(`ID ${r.id}, title: ${r.title}`);
|
|
1190
1898
|
* }
|
|
1191
1899
|
* ```
|
|
1192
1900
|
*/
|
|
@@ -1227,6 +1935,20 @@ var VelesDB = class {
|
|
|
1227
1935
|
* });
|
|
1228
1936
|
* ```
|
|
1229
1937
|
*/
|
|
1938
|
+
async queryExplain(queryString, params) {
|
|
1939
|
+
this.ensureInitialized();
|
|
1940
|
+
if (!queryString || typeof queryString !== "string") {
|
|
1941
|
+
throw new ValidationError("Query string must be a non-empty string");
|
|
1942
|
+
}
|
|
1943
|
+
return this.backend.queryExplain(queryString, params);
|
|
1944
|
+
}
|
|
1945
|
+
async collectionSanity(collection) {
|
|
1946
|
+
this.ensureInitialized();
|
|
1947
|
+
if (!collection || typeof collection !== "string") {
|
|
1948
|
+
throw new ValidationError("Collection name must be a non-empty string");
|
|
1949
|
+
}
|
|
1950
|
+
return this.backend.collectionSanity(collection);
|
|
1951
|
+
}
|
|
1230
1952
|
async multiQuerySearch(collection, vectors, options) {
|
|
1231
1953
|
this.ensureInitialized();
|
|
1232
1954
|
if (!Array.isArray(vectors) || vectors.length === 0) {
|
|
@@ -1239,9 +1961,39 @@ var VelesDB = class {
|
|
|
1239
1961
|
}
|
|
1240
1962
|
return this.backend.multiQuerySearch(collection, vectors, options);
|
|
1241
1963
|
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Train Product Quantization on a collection
|
|
1966
|
+
*
|
|
1967
|
+
* @param collection - Collection name
|
|
1968
|
+
* @param options - PQ training options (m, k, opq)
|
|
1969
|
+
* @returns Server response message
|
|
1970
|
+
*/
|
|
1971
|
+
async trainPq(collection, options) {
|
|
1972
|
+
this.ensureInitialized();
|
|
1973
|
+
return this.backend.trainPq(collection, options);
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Stream-insert documents with backpressure support
|
|
1977
|
+
*
|
|
1978
|
+
* Sends documents sequentially to respect server backpressure.
|
|
1979
|
+
* Throws BackpressureError on 429 responses.
|
|
1980
|
+
*
|
|
1981
|
+
* @param collection - Collection name
|
|
1982
|
+
* @param docs - Documents to insert
|
|
1983
|
+
*/
|
|
1984
|
+
async streamInsert(collection, docs) {
|
|
1985
|
+
this.ensureInitialized();
|
|
1986
|
+
if (!Array.isArray(docs)) {
|
|
1987
|
+
throw new ValidationError("Documents must be an array");
|
|
1988
|
+
}
|
|
1989
|
+
for (const doc of docs) {
|
|
1990
|
+
this.validateDocument(doc);
|
|
1991
|
+
}
|
|
1992
|
+
await this.backend.streamInsert(collection, docs);
|
|
1993
|
+
}
|
|
1242
1994
|
/**
|
|
1243
1995
|
* Check if a collection is empty
|
|
1244
|
-
*
|
|
1996
|
+
*
|
|
1245
1997
|
* @param collection - Collection name
|
|
1246
1998
|
* @returns true if empty, false otherwise
|
|
1247
1999
|
*/
|
|
@@ -1435,6 +2187,77 @@ var VelesDB = class {
|
|
|
1435
2187
|
}
|
|
1436
2188
|
return this.backend.getNodeDegree(collection, nodeId);
|
|
1437
2189
|
}
|
|
2190
|
+
// ========================================================================
|
|
2191
|
+
// Graph Collection Management (Phase 8)
|
|
2192
|
+
// ========================================================================
|
|
2193
|
+
/**
|
|
2194
|
+
* Create a graph collection
|
|
2195
|
+
*
|
|
2196
|
+
* @param name - Collection name
|
|
2197
|
+
* @param config - Optional graph collection configuration
|
|
2198
|
+
*/
|
|
2199
|
+
async createGraphCollection(name, config) {
|
|
2200
|
+
this.ensureInitialized();
|
|
2201
|
+
if (!name || typeof name !== "string") {
|
|
2202
|
+
throw new ValidationError("Collection name must be a non-empty string");
|
|
2203
|
+
}
|
|
2204
|
+
await this.backend.createGraphCollection(name, config);
|
|
2205
|
+
}
|
|
2206
|
+
/**
|
|
2207
|
+
* Get collection statistics (requires prior analyze)
|
|
2208
|
+
*
|
|
2209
|
+
* @param collection - Collection name
|
|
2210
|
+
* @returns Statistics or null if not yet analyzed
|
|
2211
|
+
*/
|
|
2212
|
+
async getCollectionStats(collection) {
|
|
2213
|
+
this.ensureInitialized();
|
|
2214
|
+
return this.backend.getCollectionStats(collection);
|
|
2215
|
+
}
|
|
2216
|
+
/**
|
|
2217
|
+
* Analyze a collection to compute statistics
|
|
2218
|
+
*
|
|
2219
|
+
* @param collection - Collection name
|
|
2220
|
+
* @returns Computed statistics
|
|
2221
|
+
*/
|
|
2222
|
+
async analyzeCollection(collection) {
|
|
2223
|
+
this.ensureInitialized();
|
|
2224
|
+
return this.backend.analyzeCollection(collection);
|
|
2225
|
+
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Get collection configuration
|
|
2228
|
+
*
|
|
2229
|
+
* @param collection - Collection name
|
|
2230
|
+
* @returns Collection configuration details
|
|
2231
|
+
*/
|
|
2232
|
+
async getCollectionConfig(collection) {
|
|
2233
|
+
this.ensureInitialized();
|
|
2234
|
+
return this.backend.getCollectionConfig(collection);
|
|
2235
|
+
}
|
|
2236
|
+
/**
|
|
2237
|
+
* Search returning only IDs and scores (lightweight)
|
|
2238
|
+
*
|
|
2239
|
+
* @param collection - Collection name
|
|
2240
|
+
* @param query - Query vector
|
|
2241
|
+
* @param options - Search options
|
|
2242
|
+
* @returns Array of id/score pairs
|
|
2243
|
+
*/
|
|
2244
|
+
async searchIds(collection, query2, options) {
|
|
2245
|
+
this.ensureInitialized();
|
|
2246
|
+
return this.backend.searchIds(collection, query2, options);
|
|
2247
|
+
}
|
|
2248
|
+
// ========================================================================
|
|
2249
|
+
// Agent Memory (Phase 8)
|
|
2250
|
+
// ========================================================================
|
|
2251
|
+
/**
|
|
2252
|
+
* Create an agent memory interface
|
|
2253
|
+
*
|
|
2254
|
+
* @param config - Optional agent memory configuration
|
|
2255
|
+
* @returns AgentMemoryClient instance
|
|
2256
|
+
*/
|
|
2257
|
+
agentMemory(config) {
|
|
2258
|
+
this.ensureInitialized();
|
|
2259
|
+
return new AgentMemoryClient(this.backend, config);
|
|
2260
|
+
}
|
|
1438
2261
|
};
|
|
1439
2262
|
|
|
1440
2263
|
// src/query-builder.ts
|
|
@@ -1739,6 +2562,8 @@ function velesql() {
|
|
|
1739
2562
|
return new VelesQLBuilder();
|
|
1740
2563
|
}
|
|
1741
2564
|
export {
|
|
2565
|
+
AgentMemoryClient,
|
|
2566
|
+
BackpressureError,
|
|
1742
2567
|
ConnectionError,
|
|
1743
2568
|
NotFoundError,
|
|
1744
2569
|
RestBackend,
|