@wiscale/velesdb-sdk 1.17.0 → 2.0.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/LICENSE +356 -20
- package/README.md +169 -11
- package/dist/index.d.mts +203 -44
- package/dist/index.d.ts +203 -44
- package/dist/index.js +391 -97
- package/dist/index.mjs +391 -97
- package/package.json +5 -4
package/dist/index.mjs
CHANGED
|
@@ -60,7 +60,7 @@ var WASM_CAPABILITIES = Object.freeze({
|
|
|
60
60
|
agentMemory: false,
|
|
61
61
|
streamInsert: false,
|
|
62
62
|
pqTraining: false,
|
|
63
|
-
velesqlQuery:
|
|
63
|
+
velesqlQuery: false,
|
|
64
64
|
collectionIntrospection: false
|
|
65
65
|
});
|
|
66
66
|
|
|
@@ -298,20 +298,47 @@ async function wasmMultiQuerySearch(ctx, collectionName, vectors, options) {
|
|
|
298
298
|
);
|
|
299
299
|
return raw.map((r) => mapWasmResult(ctx, collection, r));
|
|
300
300
|
}
|
|
301
|
-
|
|
301
|
+
var PURE_NEAR_QUERY = /^\s*select\s+\*\s+from\s+([a-z_]\w*)\s+where\s+vector\s+near\s+\$([a-z_]\w*)\s*(?:limit\s+(\d+))?\s*;?\s*$/i;
|
|
302
|
+
function parsePureNearQuery(queryString) {
|
|
303
|
+
const match = PURE_NEAR_QUERY.exec(queryString);
|
|
304
|
+
if (!match) {
|
|
305
|
+
throw new VelesDBError(
|
|
306
|
+
`The WASM backend only executes pure top-k NEAR queries of the form "SELECT * FROM <collection> WHERE vector NEAR $param [LIMIT n]". WHERE predicates, JOIN, GROUP BY, MATCH, set operations and FUSION are not evaluated in WASM \u2014 use the REST backend (velesdb-server) for full VelesQL. Received: ${queryString}`,
|
|
307
|
+
"NOT_SUPPORTED"
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
const parsed = { from: match[1], param: match[2] };
|
|
311
|
+
if (match[3] !== void 0) {
|
|
312
|
+
parsed.limit = Number(match[3]);
|
|
313
|
+
}
|
|
314
|
+
return parsed;
|
|
315
|
+
}
|
|
316
|
+
function resolveQueryK(limit, requestedK) {
|
|
317
|
+
if (limit !== void 0) {
|
|
318
|
+
return limit;
|
|
319
|
+
}
|
|
320
|
+
return typeof requestedK === "number" && Number.isInteger(requestedK) && requestedK > 0 ? requestedK : 10;
|
|
321
|
+
}
|
|
322
|
+
async function wasmQuery(ctx, collectionName, queryString, params, _options) {
|
|
302
323
|
const collection = ctx.getCollection(collectionName);
|
|
303
324
|
if (!collection) {
|
|
304
325
|
throw new NotFoundError(`Collection '${collectionName}'`);
|
|
305
326
|
}
|
|
306
|
-
const
|
|
327
|
+
const parsed = parsePureNearQuery(queryString);
|
|
328
|
+
if (parsed.from !== collectionName) {
|
|
329
|
+
throw new VelesDBError(
|
|
330
|
+
`Query targets collection '${parsed.from}' but was executed against '${collectionName}'.`,
|
|
331
|
+
"BAD_REQUEST"
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
const paramsVector = params?.[parsed.param];
|
|
307
335
|
if (!Array.isArray(paramsVector) && !(paramsVector instanceof Float32Array)) {
|
|
308
336
|
throw new VelesDBError(
|
|
309
|
-
|
|
337
|
+
`WASM query() expects params.${parsed.param} to contain the query embedding vector.`,
|
|
310
338
|
"BAD_REQUEST"
|
|
311
339
|
);
|
|
312
340
|
}
|
|
313
|
-
const
|
|
314
|
-
const k = typeof requestedK === "number" && Number.isInteger(requestedK) && requestedK > 0 ? requestedK : 10;
|
|
341
|
+
const k = resolveQueryK(parsed.limit, params?.k);
|
|
315
342
|
const raw = collection.store.query(
|
|
316
343
|
paramsVector instanceof Float32Array ? paramsVector : new Float32Array(paramsVector),
|
|
317
344
|
k
|
|
@@ -811,6 +838,12 @@ async function wasmRecordEpisodicEvent(_collection, _event) {
|
|
|
811
838
|
async function wasmRecallEpisodicEvents(_collection, _embedding, _k) {
|
|
812
839
|
wasmNotSupported("Agent memory");
|
|
813
840
|
}
|
|
841
|
+
async function wasmRecallRecentEvents(_collection, _since) {
|
|
842
|
+
wasmNotSupported("Agent memory");
|
|
843
|
+
}
|
|
844
|
+
async function wasmRecallOlderThanEvents(_collection, _before) {
|
|
845
|
+
wasmNotSupported("Agent memory");
|
|
846
|
+
}
|
|
814
847
|
async function wasmStoreProceduralPattern(_collection, _pattern) {
|
|
815
848
|
wasmNotSupported("Agent memory");
|
|
816
849
|
}
|
|
@@ -858,6 +891,18 @@ function wasmUpsertNodePayload(_c, _id, _p) {
|
|
|
858
891
|
function wasmGraphSearch(_c, _r) {
|
|
859
892
|
return Promise.resolve(wasmNotSupported("Graph search"));
|
|
860
893
|
}
|
|
894
|
+
function wasmRelate(_c, _req) {
|
|
895
|
+
return Promise.resolve(wasmNotSupported("Relation edges"));
|
|
896
|
+
}
|
|
897
|
+
function wasmUnrelate(_c, _id) {
|
|
898
|
+
return Promise.resolve(wasmNotSupported("Relation edge removal"));
|
|
899
|
+
}
|
|
900
|
+
function wasmGetRelations(_c, _id) {
|
|
901
|
+
return Promise.resolve(wasmNotSupported("Relation edges"));
|
|
902
|
+
}
|
|
903
|
+
function wasmSetTtlDurable(_c, _id, _ttl) {
|
|
904
|
+
return Promise.resolve(wasmNotSupported("Durable TTL"));
|
|
905
|
+
}
|
|
861
906
|
|
|
862
907
|
// src/backends/wasm.ts
|
|
863
908
|
var WasmBackend = class {
|
|
@@ -1212,6 +1257,14 @@ var WasmBackend = class {
|
|
|
1212
1257
|
this.ensureInitialized();
|
|
1213
1258
|
return wasmRecallEpisodicEvents(c, e, k);
|
|
1214
1259
|
}
|
|
1260
|
+
async recallRecentEvents(c, since) {
|
|
1261
|
+
this.ensureInitialized();
|
|
1262
|
+
return wasmRecallRecentEvents(c, since);
|
|
1263
|
+
}
|
|
1264
|
+
async recallOlderThanEvents(c, before) {
|
|
1265
|
+
this.ensureInitialized();
|
|
1266
|
+
return wasmRecallOlderThanEvents(c, before);
|
|
1267
|
+
}
|
|
1215
1268
|
async storeProceduralPattern(c, p) {
|
|
1216
1269
|
this.ensureInitialized();
|
|
1217
1270
|
return wasmStoreProceduralPattern(c, p);
|
|
@@ -1273,16 +1326,43 @@ var WasmBackend = class {
|
|
|
1273
1326
|
this.ensureInitialized();
|
|
1274
1327
|
return wasmSparseSearchNamed(c, q, idx, o);
|
|
1275
1328
|
}
|
|
1329
|
+
async relate(c, req) {
|
|
1330
|
+
this.ensureInitialized();
|
|
1331
|
+
return wasmRelate(c, req);
|
|
1332
|
+
}
|
|
1333
|
+
async unrelate(c, edgeId) {
|
|
1334
|
+
this.ensureInitialized();
|
|
1335
|
+
return wasmUnrelate(c, edgeId);
|
|
1336
|
+
}
|
|
1337
|
+
async getRelations(c, pointId) {
|
|
1338
|
+
this.ensureInitialized();
|
|
1339
|
+
return wasmGetRelations(c, pointId);
|
|
1340
|
+
}
|
|
1341
|
+
async setTtlDurable(c, pointId, ttlSeconds) {
|
|
1342
|
+
this.ensureInitialized();
|
|
1343
|
+
return wasmSetTtlDurable(c, pointId, ttlSeconds);
|
|
1344
|
+
}
|
|
1276
1345
|
};
|
|
1277
1346
|
|
|
1278
1347
|
// src/backends/crud-backend.ts
|
|
1348
|
+
var U64_MAX = 18446744073709551615n;
|
|
1349
|
+
function coerceDecimalStringId(id) {
|
|
1350
|
+
if (!/^\d+$/.test(id)) return NaN;
|
|
1351
|
+
const big = BigInt(id);
|
|
1352
|
+
if (big > U64_MAX) return NaN;
|
|
1353
|
+
return big > BigInt(Number.MAX_SAFE_INTEGER) ? id : Number(id);
|
|
1354
|
+
}
|
|
1279
1355
|
function parseRestPointId(id) {
|
|
1280
|
-
|
|
1356
|
+
const coerced = typeof id === "string" ? coerceDecimalStringId(id) : id;
|
|
1357
|
+
if (typeof coerced === "string") {
|
|
1358
|
+
return coerced;
|
|
1359
|
+
}
|
|
1360
|
+
if (!Number.isFinite(coerced) || coerced < 0 || !Number.isInteger(coerced) || coerced > Number.MAX_SAFE_INTEGER) {
|
|
1281
1361
|
throw new ValidationError(
|
|
1282
|
-
`REST backend requires numeric u64-compatible IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER}). Received: ${String(id)}`
|
|
1362
|
+
`REST backend requires numeric u64-compatible IDs: a non-negative integer in the JS safe integer range (0..${Number.MAX_SAFE_INTEGER}) or a decimal string up to u64::MAX (${U64_MAX}). Received: ${String(id)}`
|
|
1283
1363
|
);
|
|
1284
1364
|
}
|
|
1285
|
-
return
|
|
1365
|
+
return coerced;
|
|
1286
1366
|
}
|
|
1287
1367
|
function sparseVectorToRestFormat(sv) {
|
|
1288
1368
|
const result = {};
|
|
@@ -1676,16 +1756,13 @@ async function getEdgeCount(transport, collection) {
|
|
|
1676
1756
|
return response.data?.count ?? 0;
|
|
1677
1757
|
}
|
|
1678
1758
|
async function listNodes(transport, collection) {
|
|
1679
|
-
const response = await transport.requestJson(
|
|
1680
|
-
"GET",
|
|
1681
|
-
`${collectionPath(collection)}/graph/nodes`
|
|
1682
|
-
);
|
|
1759
|
+
const response = await transport.requestJson("GET", `${collectionPath(collection)}/graph/nodes`);
|
|
1683
1760
|
throwOnError(response, `Collection '${collection}'`);
|
|
1684
1761
|
const data = response.data;
|
|
1685
1762
|
return { nodeIds: data.node_ids, count: data.count };
|
|
1686
1763
|
}
|
|
1687
|
-
function
|
|
1688
|
-
return
|
|
1764
|
+
function idToGraphId(id) {
|
|
1765
|
+
return id;
|
|
1689
1766
|
}
|
|
1690
1767
|
async function getNodeEdges(transport, collection, nodeId, options) {
|
|
1691
1768
|
const params = new URLSearchParams();
|
|
@@ -1696,9 +1773,9 @@ async function getNodeEdges(transport, collection, nodeId, options) {
|
|
|
1696
1773
|
const response = await transport.requestJson("GET", url);
|
|
1697
1774
|
throwOnError(response, `Collection '${collection}'`);
|
|
1698
1775
|
return (response.data?.edges ?? []).map((e) => ({
|
|
1699
|
-
id:
|
|
1700
|
-
source:
|
|
1701
|
-
target:
|
|
1776
|
+
id: e.id,
|
|
1777
|
+
source: e.source,
|
|
1778
|
+
target: e.target,
|
|
1702
1779
|
label: e.label,
|
|
1703
1780
|
properties: e.properties
|
|
1704
1781
|
}));
|
|
@@ -1708,7 +1785,7 @@ async function getNodePayload(transport, collection, nodeId) {
|
|
|
1708
1785
|
throwOnError(response, `Collection '${collection}'`);
|
|
1709
1786
|
const data = response.data;
|
|
1710
1787
|
return {
|
|
1711
|
-
nodeId:
|
|
1788
|
+
nodeId: idToGraphId(data.node_id),
|
|
1712
1789
|
payload: data.payload
|
|
1713
1790
|
};
|
|
1714
1791
|
}
|
|
@@ -1732,7 +1809,7 @@ async function graphSearch(transport, collection, request2) {
|
|
|
1732
1809
|
throwOnError(response, `Collection '${collection}'`);
|
|
1733
1810
|
const items = (response.data?.results ?? []).map(
|
|
1734
1811
|
(r) => ({
|
|
1735
|
-
id:
|
|
1812
|
+
id: idToGraphId(r.id),
|
|
1736
1813
|
score: r.score,
|
|
1737
1814
|
payload: r.payload
|
|
1738
1815
|
})
|
|
@@ -1740,6 +1817,31 @@ async function graphSearch(transport, collection, request2) {
|
|
|
1740
1817
|
return { results: items };
|
|
1741
1818
|
}
|
|
1742
1819
|
|
|
1820
|
+
// src/backends/scroll-backend.ts
|
|
1821
|
+
async function scroll(transport, collection, request2) {
|
|
1822
|
+
const body = {};
|
|
1823
|
+
if (request2?.cursor !== void 0) {
|
|
1824
|
+
body.cursor = request2.cursor;
|
|
1825
|
+
}
|
|
1826
|
+
if (request2?.batchSize !== void 0) {
|
|
1827
|
+
body.batch_size = request2.batchSize;
|
|
1828
|
+
}
|
|
1829
|
+
if (request2?.filter !== void 0) {
|
|
1830
|
+
body.filter = request2.filter;
|
|
1831
|
+
}
|
|
1832
|
+
const response = await transport.requestJson(
|
|
1833
|
+
"POST",
|
|
1834
|
+
`${collectionPath(collection)}/points/scroll`,
|
|
1835
|
+
body
|
|
1836
|
+
);
|
|
1837
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
1838
|
+
const data = response.data;
|
|
1839
|
+
return {
|
|
1840
|
+
points: data.points,
|
|
1841
|
+
nextCursor: data.next_cursor
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1743
1845
|
// src/backends/agent-memory-backend.ts
|
|
1744
1846
|
var _idCounter = 0;
|
|
1745
1847
|
var _lastTimestamp = 0;
|
|
@@ -1757,18 +1859,28 @@ function generateUniqueId() {
|
|
|
1757
1859
|
}
|
|
1758
1860
|
return _lastTimestamp * 1e3 + _idCounter;
|
|
1759
1861
|
}
|
|
1862
|
+
function memoryIdToString(id) {
|
|
1863
|
+
return String(id);
|
|
1864
|
+
}
|
|
1865
|
+
function nowUnixSeconds() {
|
|
1866
|
+
return Math.floor(Date.now() / 1e3);
|
|
1867
|
+
}
|
|
1760
1868
|
async function storeSemanticFact(transport, collection, entry) {
|
|
1761
1869
|
const response = await transport.requestJson(
|
|
1762
1870
|
"POST",
|
|
1763
1871
|
`${collectionPath(collection)}/points`,
|
|
1764
1872
|
{
|
|
1765
1873
|
points: [{
|
|
1766
|
-
id: entry.id,
|
|
1874
|
+
id: parseRestPointId(entry.id),
|
|
1767
1875
|
vector: entry.embedding,
|
|
1768
1876
|
payload: {
|
|
1877
|
+
// Caller metadata is spread first so the reserved keys below
|
|
1878
|
+
// (`_memory_type`, `content`) always win and cannot be clobbered.
|
|
1879
|
+
...entry.metadata,
|
|
1769
1880
|
_memory_type: "semantic",
|
|
1770
|
-
|
|
1771
|
-
|
|
1881
|
+
// `content` matches the core semantic store and the server/Python
|
|
1882
|
+
// payload field (BREAKING: was `text` before this change).
|
|
1883
|
+
content: entry.text
|
|
1772
1884
|
}
|
|
1773
1885
|
}]
|
|
1774
1886
|
}
|
|
@@ -1779,7 +1891,8 @@ async function searchSemanticMemory(transport, collection, embedding, k = 5) {
|
|
|
1779
1891
|
return transport.searchVectors(collection, embedding, k, { _memory_type: "semantic" });
|
|
1780
1892
|
}
|
|
1781
1893
|
async function recordEpisodicEvent(transport, collection, event) {
|
|
1782
|
-
const id = generateUniqueId();
|
|
1894
|
+
const id = event.id !== void 0 ? parseRestPointId(event.id) : generateUniqueId();
|
|
1895
|
+
const timestamp = event.timestamp ?? nowUnixSeconds();
|
|
1783
1896
|
const response = await transport.requestJson(
|
|
1784
1897
|
"POST",
|
|
1785
1898
|
`${collectionPath(collection)}/points`,
|
|
@@ -1788,42 +1901,83 @@ async function recordEpisodicEvent(transport, collection, event) {
|
|
|
1788
1901
|
id,
|
|
1789
1902
|
vector: event.embedding,
|
|
1790
1903
|
payload: {
|
|
1904
|
+
// Caller-supplied data/metadata is spread first so the reserved
|
|
1905
|
+
// keys below (`_memory_type`, `event_type`, `timestamp`) always
|
|
1906
|
+
// win and cannot be clobbered.
|
|
1907
|
+
...event.data,
|
|
1908
|
+
...event.metadata,
|
|
1791
1909
|
_memory_type: "episodic",
|
|
1792
1910
|
event_type: event.eventType,
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1911
|
+
// NUMERIC unix-seconds, mirroring the core episodic store so
|
|
1912
|
+
// recallRecent/recallOlderThan can range-filter on it.
|
|
1913
|
+
timestamp
|
|
1796
1914
|
}
|
|
1797
1915
|
}]
|
|
1798
1916
|
}
|
|
1799
1917
|
);
|
|
1800
1918
|
throwOnError(response);
|
|
1919
|
+
return memoryIdToString(id);
|
|
1801
1920
|
}
|
|
1802
1921
|
async function recallEpisodicEvents(transport, collection, embedding, k = 5) {
|
|
1803
1922
|
return transport.searchVectors(collection, embedding, k, { _memory_type: "episodic" });
|
|
1804
1923
|
}
|
|
1805
1924
|
async function storeProceduralPattern(transport, collection, pattern) {
|
|
1806
|
-
const id = generateUniqueId();
|
|
1925
|
+
const id = pattern.id !== void 0 ? parseRestPointId(pattern.id) : generateUniqueId();
|
|
1807
1926
|
const response = await transport.requestJson(
|
|
1808
1927
|
"POST",
|
|
1809
1928
|
`${collectionPath(collection)}/points`,
|
|
1810
1929
|
{
|
|
1811
1930
|
points: [{
|
|
1812
1931
|
id,
|
|
1932
|
+
vector: pattern.embedding,
|
|
1813
1933
|
payload: {
|
|
1934
|
+
// Caller metadata is spread first so the reserved keys below
|
|
1935
|
+
// (`_memory_type`, `name`, `steps`) always win and cannot be
|
|
1936
|
+
// clobbered.
|
|
1937
|
+
...pattern.metadata,
|
|
1814
1938
|
_memory_type: "procedural",
|
|
1815
1939
|
name: pattern.name,
|
|
1816
|
-
steps: pattern.steps
|
|
1817
|
-
...pattern.metadata
|
|
1940
|
+
steps: pattern.steps
|
|
1818
1941
|
}
|
|
1819
1942
|
}]
|
|
1820
1943
|
}
|
|
1821
1944
|
);
|
|
1822
1945
|
throwOnError(response);
|
|
1946
|
+
return memoryIdToString(id);
|
|
1823
1947
|
}
|
|
1824
1948
|
async function matchProceduralPatterns(transport, collection, embedding, k = 5) {
|
|
1825
1949
|
return transport.searchVectors(collection, embedding, k, { _memory_type: "procedural" });
|
|
1826
1950
|
}
|
|
1951
|
+
function toEpisodicRecord(point) {
|
|
1952
|
+
const payload = point.payload ?? {};
|
|
1953
|
+
if (payload._memory_type !== "episodic") return void 0;
|
|
1954
|
+
if (typeof payload.timestamp !== "number") return void 0;
|
|
1955
|
+
return { id: String(point.id), timestamp: payload.timestamp, payload };
|
|
1956
|
+
}
|
|
1957
|
+
async function scrollEpisodicRecords(transport, collection) {
|
|
1958
|
+
const records = [];
|
|
1959
|
+
let cursor = null;
|
|
1960
|
+
do {
|
|
1961
|
+
const page = await scroll(transport, collection, {
|
|
1962
|
+
cursor: cursor ?? void 0,
|
|
1963
|
+
filter: { _memory_type: "episodic" }
|
|
1964
|
+
});
|
|
1965
|
+
for (const point of page.points) {
|
|
1966
|
+
const record = toEpisodicRecord(point);
|
|
1967
|
+
if (record !== void 0) records.push(record);
|
|
1968
|
+
}
|
|
1969
|
+
cursor = page.nextCursor;
|
|
1970
|
+
} while (cursor !== null && cursor !== void 0);
|
|
1971
|
+
return records;
|
|
1972
|
+
}
|
|
1973
|
+
async function recallRecentEvents(transport, collection, since) {
|
|
1974
|
+
const records = await scrollEpisodicRecords(transport, collection);
|
|
1975
|
+
return records.filter((r) => since === void 0 || r.timestamp >= since).sort((a, b) => b.timestamp - a.timestamp);
|
|
1976
|
+
}
|
|
1977
|
+
async function recallOlderThanEvents(transport, collection, before) {
|
|
1978
|
+
const records = await scrollEpisodicRecords(transport, collection);
|
|
1979
|
+
return records.filter((r) => r.timestamp < before).sort((a, b) => b.timestamp - a.timestamp);
|
|
1980
|
+
}
|
|
1827
1981
|
|
|
1828
1982
|
// src/search-quality.ts
|
|
1829
1983
|
function searchQualityToMode(quality) {
|
|
@@ -1973,15 +2127,29 @@ async function addEdge(transport, collection, edge) {
|
|
|
1973
2127
|
throwOnError(response, `Collection '${collection}'`);
|
|
1974
2128
|
}
|
|
1975
2129
|
function toGraphEdge(e) {
|
|
1976
|
-
const toNum = (v) => typeof v === "string" ? Number(v) : v;
|
|
1977
2130
|
return {
|
|
1978
|
-
id:
|
|
1979
|
-
source:
|
|
1980
|
-
target:
|
|
2131
|
+
id: e.id,
|
|
2132
|
+
source: e.source,
|
|
2133
|
+
target: e.target,
|
|
1981
2134
|
label: e.label,
|
|
1982
2135
|
properties: e.properties
|
|
1983
2136
|
};
|
|
1984
2137
|
}
|
|
2138
|
+
function toTraverseResponse(data) {
|
|
2139
|
+
return {
|
|
2140
|
+
results: data.results.map((r) => ({
|
|
2141
|
+
targetId: r.target_id,
|
|
2142
|
+
depth: r.depth,
|
|
2143
|
+
path: r.path
|
|
2144
|
+
})),
|
|
2145
|
+
nextCursor: data.next_cursor ?? void 0,
|
|
2146
|
+
hasMore: data.has_more,
|
|
2147
|
+
stats: {
|
|
2148
|
+
visited: data.stats.visited,
|
|
2149
|
+
depthReached: data.stats.depth_reached
|
|
2150
|
+
}
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
1985
2153
|
async function getEdges(transport, collection, options) {
|
|
1986
2154
|
const queryParams = options?.label ? `?label=${encodeURIComponent(options.label)}` : "";
|
|
1987
2155
|
const response = await transport.requestJson(
|
|
@@ -2005,20 +2173,7 @@ async function traverseGraph(transport, collection, request2) {
|
|
|
2005
2173
|
}
|
|
2006
2174
|
);
|
|
2007
2175
|
throwOnError(response, `Collection '${collection}'`);
|
|
2008
|
-
|
|
2009
|
-
return {
|
|
2010
|
-
results: data.results.map((r) => ({
|
|
2011
|
-
targetId: r.target_id,
|
|
2012
|
-
depth: r.depth,
|
|
2013
|
-
path: r.path
|
|
2014
|
-
})),
|
|
2015
|
-
nextCursor: data.next_cursor ?? void 0,
|
|
2016
|
-
hasMore: data.has_more,
|
|
2017
|
-
stats: {
|
|
2018
|
-
visited: data.stats.visited,
|
|
2019
|
-
depthReached: data.stats.depth_reached
|
|
2020
|
-
}
|
|
2021
|
-
};
|
|
2176
|
+
return toTraverseResponse(response.data);
|
|
2022
2177
|
}
|
|
2023
2178
|
async function getNodeDegree(transport, collection, nodeId) {
|
|
2024
2179
|
const response = await transport.requestJson(
|
|
@@ -2053,21 +2208,66 @@ async function traverseParallel(transport, collection, request2) {
|
|
|
2053
2208
|
}
|
|
2054
2209
|
);
|
|
2055
2210
|
throwOnError(response, `Collection '${collection}'`);
|
|
2056
|
-
|
|
2211
|
+
return toTraverseResponse(response.data);
|
|
2212
|
+
}
|
|
2213
|
+
async function relate(transport, collection, req) {
|
|
2214
|
+
const response = await transport.requestJson(
|
|
2215
|
+
"POST",
|
|
2216
|
+
`${collectionPath(collection)}/relations`,
|
|
2217
|
+
{
|
|
2218
|
+
source: req.source,
|
|
2219
|
+
target: req.target,
|
|
2220
|
+
rel_type: req.relType,
|
|
2221
|
+
properties: req.properties ?? {}
|
|
2222
|
+
}
|
|
2223
|
+
);
|
|
2224
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
2225
|
+
return { edgeId: response.data.edge_id };
|
|
2226
|
+
}
|
|
2227
|
+
async function unrelate(transport, collection, edgeId) {
|
|
2228
|
+
const response = await transport.requestJson(
|
|
2229
|
+
"DELETE",
|
|
2230
|
+
`${collectionPath(collection)}/relations/${encodeURIComponent(String(edgeId))}`
|
|
2231
|
+
);
|
|
2232
|
+
if (response.error !== void 0) {
|
|
2233
|
+
const { code, message } = response.error;
|
|
2234
|
+
const err = parseVelesError(code, message);
|
|
2235
|
+
if (err instanceof EdgeNotFoundError) {
|
|
2236
|
+
return false;
|
|
2237
|
+
}
|
|
2238
|
+
if (code === "NOT_FOUND") {
|
|
2239
|
+
return false;
|
|
2240
|
+
}
|
|
2241
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
2242
|
+
}
|
|
2243
|
+
return true;
|
|
2244
|
+
}
|
|
2245
|
+
async function getRelations(transport, collection, pointId) {
|
|
2246
|
+
const response = await transport.requestJson(
|
|
2247
|
+
"GET",
|
|
2248
|
+
`${collectionPath(collection)}/points/${encodeURIComponent(String(pointId))}/relations`
|
|
2249
|
+
);
|
|
2250
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
2251
|
+
const raw = response.data;
|
|
2057
2252
|
return {
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2253
|
+
edges: raw.edges.map((e) => ({
|
|
2254
|
+
id: e.id,
|
|
2255
|
+
source: e.source,
|
|
2256
|
+
target: e.target,
|
|
2257
|
+
relType: e.rel_type,
|
|
2258
|
+
properties: e.properties
|
|
2062
2259
|
})),
|
|
2063
|
-
|
|
2064
|
-
hasMore: data.has_more,
|
|
2065
|
-
stats: {
|
|
2066
|
-
visited: data.stats.visited,
|
|
2067
|
-
depthReached: data.stats.depth_reached
|
|
2068
|
-
}
|
|
2260
|
+
count: raw.count
|
|
2069
2261
|
};
|
|
2070
2262
|
}
|
|
2263
|
+
async function setTtlDurable(transport, collection, pointId, ttlSeconds) {
|
|
2264
|
+
const response = await transport.requestJson(
|
|
2265
|
+
"PATCH",
|
|
2266
|
+
`${collectionPath(collection)}/points/${encodeURIComponent(String(pointId))}/ttl`,
|
|
2267
|
+
{ ttl_seconds: ttlSeconds }
|
|
2268
|
+
);
|
|
2269
|
+
throwOnError(response, `Collection '${collection}'`);
|
|
2270
|
+
}
|
|
2071
2271
|
|
|
2072
2272
|
// src/backends/query-backend.ts
|
|
2073
2273
|
function isLikelyAggregationQuery(queryString) {
|
|
@@ -2200,31 +2400,6 @@ async function collectionSanity(transport, collection) {
|
|
|
2200
2400
|
};
|
|
2201
2401
|
}
|
|
2202
2402
|
|
|
2203
|
-
// src/backends/scroll-backend.ts
|
|
2204
|
-
async function scroll(transport, collection, request2) {
|
|
2205
|
-
const body = {};
|
|
2206
|
-
if (request2?.cursor !== void 0) {
|
|
2207
|
-
body.cursor = request2.cursor;
|
|
2208
|
-
}
|
|
2209
|
-
if (request2?.batchSize !== void 0) {
|
|
2210
|
-
body.batch_size = request2.batchSize;
|
|
2211
|
-
}
|
|
2212
|
-
if (request2?.filter !== void 0) {
|
|
2213
|
-
body.filter = request2.filter;
|
|
2214
|
-
}
|
|
2215
|
-
const response = await transport.requestJson(
|
|
2216
|
-
"POST",
|
|
2217
|
-
`${collectionPath(collection)}/points/scroll`,
|
|
2218
|
-
body
|
|
2219
|
-
);
|
|
2220
|
-
throwOnError(response, `Collection '${collection}'`);
|
|
2221
|
-
const data = response.data;
|
|
2222
|
-
return {
|
|
2223
|
-
points: data.points,
|
|
2224
|
-
nextCursor: data.next_cursor
|
|
2225
|
-
};
|
|
2226
|
-
}
|
|
2227
|
-
|
|
2228
2403
|
// src/backends/admin-backend.ts
|
|
2229
2404
|
function mapStatsResponse(data) {
|
|
2230
2405
|
let columnStats;
|
|
@@ -2410,9 +2585,17 @@ async function streamInsert(transport, collection, docs) {
|
|
|
2410
2585
|
}
|
|
2411
2586
|
}
|
|
2412
2587
|
}
|
|
2588
|
+
function requireSafeRangeId(restId) {
|
|
2589
|
+
if (typeof restId === "string") {
|
|
2590
|
+
throw new ValidationError(
|
|
2591
|
+
`streamUpsertPoints requires ids in the JS safe integer range (0..${Number.MAX_SAFE_INTEGER}); use upsert/upsertBatch for string ids above it. Received: ${restId}`
|
|
2592
|
+
);
|
|
2593
|
+
}
|
|
2594
|
+
return restId;
|
|
2595
|
+
}
|
|
2413
2596
|
async function streamUpsertPoints(transport, collection, docs) {
|
|
2414
2597
|
const ndjsonLines = docs.map((doc) => {
|
|
2415
|
-
const restId = transport.parseRestPointId(doc.id);
|
|
2598
|
+
const restId = requireSafeRangeId(transport.parseRestPointId(doc.id));
|
|
2416
2599
|
const vector = toNumberArray(doc.vector);
|
|
2417
2600
|
const point = {
|
|
2418
2601
|
id: restId,
|
|
@@ -2603,6 +2786,22 @@ var RestBackend = class {
|
|
|
2603
2786
|
this.ensureInitialized();
|
|
2604
2787
|
return graphSearch(buildBaseTransport(this.httpConfig), c, r);
|
|
2605
2788
|
}
|
|
2789
|
+
async relate(c, req) {
|
|
2790
|
+
this.ensureInitialized();
|
|
2791
|
+
return relate(buildCrudTransport(this.httpConfig), c, req);
|
|
2792
|
+
}
|
|
2793
|
+
async unrelate(c, edgeId) {
|
|
2794
|
+
this.ensureInitialized();
|
|
2795
|
+
return unrelate(buildCrudTransport(this.httpConfig), c, edgeId);
|
|
2796
|
+
}
|
|
2797
|
+
async getRelations(c, pointId) {
|
|
2798
|
+
this.ensureInitialized();
|
|
2799
|
+
return getRelations(buildCrudTransport(this.httpConfig), c, pointId);
|
|
2800
|
+
}
|
|
2801
|
+
async setTtlDurable(c, pointId, ttlSeconds) {
|
|
2802
|
+
this.ensureInitialized();
|
|
2803
|
+
return setTtlDurable(buildCrudTransport(this.httpConfig), c, pointId, ttlSeconds);
|
|
2804
|
+
}
|
|
2606
2805
|
// Search
|
|
2607
2806
|
async search(c, q, o) {
|
|
2608
2807
|
this.ensureInitialized();
|
|
@@ -2735,6 +2934,14 @@ var RestBackend = class {
|
|
|
2735
2934
|
this.ensureInitialized();
|
|
2736
2935
|
return recallEpisodicEvents(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, e, k);
|
|
2737
2936
|
}
|
|
2937
|
+
async recallRecentEvents(c, since) {
|
|
2938
|
+
this.ensureInitialized();
|
|
2939
|
+
return recallRecentEvents(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, since);
|
|
2940
|
+
}
|
|
2941
|
+
async recallOlderThanEvents(c, before) {
|
|
2942
|
+
this.ensureInitialized();
|
|
2943
|
+
return recallOlderThanEvents(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, before);
|
|
2944
|
+
}
|
|
2738
2945
|
async storeProceduralPattern(c, p) {
|
|
2739
2946
|
this.ensureInitialized();
|
|
2740
2947
|
return storeProceduralPattern(buildAgentMemoryTransport(this.httpConfig, (col, emb, opts) => this.search(col, emb, opts)), c, p);
|
|
@@ -2751,7 +2958,16 @@ var AgentMemoryClient = class {
|
|
|
2751
2958
|
this.backend = backend;
|
|
2752
2959
|
this.config = config;
|
|
2753
2960
|
}
|
|
2754
|
-
/**
|
|
2961
|
+
/**
|
|
2962
|
+
* Advisory embedding dimension passed at construction (default: 384).
|
|
2963
|
+
*
|
|
2964
|
+
* This value is **not** enforced and does not create or size any
|
|
2965
|
+
* collection — the dimension that actually governs storage and search
|
|
2966
|
+
* is the one fixed when the collection was created
|
|
2967
|
+
* (`db.createCollection(name, { dimension, metric: 'cosine' })`).
|
|
2968
|
+
* Embeddings you pass to `storeFact` / `recordEvent` / `learnProcedure`
|
|
2969
|
+
* must match that collection dimension.
|
|
2970
|
+
*/
|
|
2755
2971
|
get dimension() {
|
|
2756
2972
|
return this.config?.dimension ?? 384;
|
|
2757
2973
|
}
|
|
@@ -2763,15 +2979,29 @@ var AgentMemoryClient = class {
|
|
|
2763
2979
|
async searchFacts(collection, embedding, k = 5) {
|
|
2764
2980
|
return this.backend.searchSemanticMemory(collection, embedding, k);
|
|
2765
2981
|
}
|
|
2766
|
-
/** Record an episodic event */
|
|
2982
|
+
/** Record an episodic event. Returns the point ID (string, u64-safe). */
|
|
2767
2983
|
async recordEvent(collection, event) {
|
|
2768
2984
|
return this.backend.recordEpisodicEvent(collection, event);
|
|
2769
2985
|
}
|
|
2770
|
-
/** Recall episodic events */
|
|
2986
|
+
/** Recall episodic events by vector similarity. */
|
|
2771
2987
|
async recallEvents(collection, embedding, k = 5) {
|
|
2772
2988
|
return this.backend.recallEpisodicEvents(collection, embedding, k);
|
|
2773
2989
|
}
|
|
2774
|
-
/**
|
|
2990
|
+
/**
|
|
2991
|
+
* Recall episodic events most-recent-first, optionally bounded below by
|
|
2992
|
+
* `since` (inclusive unix-seconds). Mirrors core `episodic.recent(since)`.
|
|
2993
|
+
*/
|
|
2994
|
+
async recallRecent(collection, since) {
|
|
2995
|
+
return this.backend.recallRecentEvents(collection, since);
|
|
2996
|
+
}
|
|
2997
|
+
/**
|
|
2998
|
+
* Recall episodic events strictly older than `before` (unix-seconds),
|
|
2999
|
+
* most-recent-first. Mirrors core `episodic.older_than(before)`.
|
|
3000
|
+
*/
|
|
3001
|
+
async recallOlderThan(collection, before) {
|
|
3002
|
+
return this.backend.recallOlderThanEvents(collection, before);
|
|
3003
|
+
}
|
|
3004
|
+
/** Store a procedural pattern. Returns the point ID (string, u64-safe). */
|
|
2775
3005
|
async learnProcedure(collection, pattern) {
|
|
2776
3006
|
return this.backend.storeProceduralPattern(collection, pattern);
|
|
2777
3007
|
}
|
|
@@ -2779,6 +3009,15 @@ var AgentMemoryClient = class {
|
|
|
2779
3009
|
async recallProcedures(collection, embedding, k = 5) {
|
|
2780
3010
|
return this.backend.matchProceduralPatterns(collection, embedding, k);
|
|
2781
3011
|
}
|
|
3012
|
+
/**
|
|
3013
|
+
* Delete a memory entry (fact, event, or procedure) by its point ID.
|
|
3014
|
+
*
|
|
3015
|
+
* Accepts the `string` ids returned by `recordEvent` / `learnProcedure`
|
|
3016
|
+
* (u64-safe decimal strings) as well as numeric ids.
|
|
3017
|
+
*/
|
|
3018
|
+
async deleteMemory(collection, id) {
|
|
3019
|
+
return this.backend.delete(collection, id);
|
|
3020
|
+
}
|
|
2782
3021
|
};
|
|
2783
3022
|
|
|
2784
3023
|
// src/client/validation.ts
|
|
@@ -2809,11 +3048,10 @@ function validateDocument(doc, config) {
|
|
|
2809
3048
|
validateRestPointId(doc.id, config);
|
|
2810
3049
|
}
|
|
2811
3050
|
function validateRestPointId(id, config) {
|
|
2812
|
-
if (config.backend
|
|
2813
|
-
|
|
2814
|
-
`REST backend requires numeric u64-compatible document IDs in JS safe integer range (0..${Number.MAX_SAFE_INTEGER})`
|
|
2815
|
-
);
|
|
3051
|
+
if (config.backend !== "rest") {
|
|
3052
|
+
return;
|
|
2816
3053
|
}
|
|
3054
|
+
parseRestPointId(id);
|
|
2817
3055
|
}
|
|
2818
3056
|
|
|
2819
3057
|
// src/client/search-methods.ts
|
|
@@ -2918,12 +3156,15 @@ function aggregate2(backend, queryString, params, options) {
|
|
|
2918
3156
|
}
|
|
2919
3157
|
|
|
2920
3158
|
// src/client/graph-methods.ts
|
|
3159
|
+
function isGraphNodeId(value) {
|
|
3160
|
+
return typeof value === "number" || typeof value === "string";
|
|
3161
|
+
}
|
|
2921
3162
|
function addEdge2(backend, collection, edge) {
|
|
2922
3163
|
if (!edge.label || typeof edge.label !== "string") {
|
|
2923
3164
|
throw new ValidationError("Edge label is required and must be a string");
|
|
2924
3165
|
}
|
|
2925
|
-
if (
|
|
2926
|
-
throw new ValidationError("Edge source and target must be numbers");
|
|
3166
|
+
if (!isGraphNodeId(edge.source) || !isGraphNodeId(edge.target)) {
|
|
3167
|
+
throw new ValidationError("Edge source and target must be numbers or strings");
|
|
2927
3168
|
}
|
|
2928
3169
|
return backend.addEdge(collection, edge);
|
|
2929
3170
|
}
|
|
@@ -2931,8 +3172,8 @@ function getEdges2(backend, collection, options) {
|
|
|
2931
3172
|
return backend.getEdges(collection, options);
|
|
2932
3173
|
}
|
|
2933
3174
|
function traverseGraph2(backend, collection, request2) {
|
|
2934
|
-
if (
|
|
2935
|
-
throw new ValidationError("Source node ID must be a number");
|
|
3175
|
+
if (!isGraphNodeId(request2.source)) {
|
|
3176
|
+
throw new ValidationError("Source node ID must be a number or string");
|
|
2936
3177
|
}
|
|
2937
3178
|
if (request2.strategy && !["bfs", "dfs"].includes(request2.strategy)) {
|
|
2938
3179
|
throw new ValidationError("Strategy must be 'bfs' or 'dfs'");
|
|
@@ -2943,6 +3184,9 @@ function traverseParallel2(backend, collection, request2) {
|
|
|
2943
3184
|
if (!Array.isArray(request2.sources) || request2.sources.length === 0) {
|
|
2944
3185
|
throw new ValidationError("At least one source node ID is required");
|
|
2945
3186
|
}
|
|
3187
|
+
if (!request2.sources.every(isGraphNodeId)) {
|
|
3188
|
+
throw new ValidationError("Source node IDs must be numbers or strings");
|
|
3189
|
+
}
|
|
2946
3190
|
return backend.traverseParallel(collection, request2);
|
|
2947
3191
|
}
|
|
2948
3192
|
function getNodeDegree2(backend, collection, nodeId) {
|
|
@@ -2988,6 +3232,40 @@ function graphSearch2(backend, collection, request2) {
|
|
|
2988
3232
|
requireNonEmptyString(collection, "Collection");
|
|
2989
3233
|
return backend.graphSearch(collection, request2);
|
|
2990
3234
|
}
|
|
3235
|
+
function relate2(backend, collection, req) {
|
|
3236
|
+
requireNonEmptyString(collection, "Collection");
|
|
3237
|
+
if (!req.relType || typeof req.relType !== "string") {
|
|
3238
|
+
throw new ValidationError("Relation type is required and must be a string");
|
|
3239
|
+
}
|
|
3240
|
+
if (!isGraphNodeId(req.source) || !isGraphNodeId(req.target)) {
|
|
3241
|
+
throw new ValidationError("Source and target must be numbers or strings");
|
|
3242
|
+
}
|
|
3243
|
+
return backend.relate(collection, req);
|
|
3244
|
+
}
|
|
3245
|
+
function unrelate2(backend, collection, edgeId) {
|
|
3246
|
+
requireNonEmptyString(collection, "Collection");
|
|
3247
|
+
if (!isGraphNodeId(edgeId)) {
|
|
3248
|
+
throw new ValidationError("Edge ID must be a number or string");
|
|
3249
|
+
}
|
|
3250
|
+
return backend.unrelate(collection, edgeId);
|
|
3251
|
+
}
|
|
3252
|
+
function getRelations2(backend, collection, pointId) {
|
|
3253
|
+
requireNonEmptyString(collection, "Collection");
|
|
3254
|
+
if (!isGraphNodeId(pointId)) {
|
|
3255
|
+
throw new ValidationError("Point ID must be a number or string");
|
|
3256
|
+
}
|
|
3257
|
+
return backend.getRelations(collection, pointId);
|
|
3258
|
+
}
|
|
3259
|
+
function setTtlDurable2(backend, collection, pointId, ttlSeconds) {
|
|
3260
|
+
requireNonEmptyString(collection, "Collection");
|
|
3261
|
+
if (!isGraphNodeId(pointId)) {
|
|
3262
|
+
throw new ValidationError("Point ID must be a number or string");
|
|
3263
|
+
}
|
|
3264
|
+
if (typeof ttlSeconds !== "number" || ttlSeconds < 0) {
|
|
3265
|
+
throw new ValidationError("ttlSeconds must be a non-negative number");
|
|
3266
|
+
}
|
|
3267
|
+
return backend.setTtlDurable(collection, pointId, ttlSeconds);
|
|
3268
|
+
}
|
|
2991
3269
|
|
|
2992
3270
|
// src/client.ts
|
|
2993
3271
|
var VelesDB = class {
|
|
@@ -3285,6 +3563,22 @@ var VelesDB = class {
|
|
|
3285
3563
|
this.ensureInitialized();
|
|
3286
3564
|
return graphSearch2(this.backend, collection, request2);
|
|
3287
3565
|
}
|
|
3566
|
+
async relate(collection, req) {
|
|
3567
|
+
this.ensureInitialized();
|
|
3568
|
+
return relate2(this.backend, collection, req);
|
|
3569
|
+
}
|
|
3570
|
+
async unrelate(collection, edgeId) {
|
|
3571
|
+
this.ensureInitialized();
|
|
3572
|
+
return unrelate2(this.backend, collection, edgeId);
|
|
3573
|
+
}
|
|
3574
|
+
async getRelations(collection, pointId) {
|
|
3575
|
+
this.ensureInitialized();
|
|
3576
|
+
return getRelations2(this.backend, collection, pointId);
|
|
3577
|
+
}
|
|
3578
|
+
async setTtlDurable(collection, pointId, ttlSeconds) {
|
|
3579
|
+
this.ensureInitialized();
|
|
3580
|
+
return setTtlDurable2(this.backend, collection, pointId, ttlSeconds);
|
|
3581
|
+
}
|
|
3288
3582
|
// ========================================================================
|
|
3289
3583
|
// Capabilities & Backend Info
|
|
3290
3584
|
// ========================================================================
|