@utaba/deep-memory 0.16.0 → 0.18.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 +1 -1
- package/dist/{StorageProvider-BGtKZZt4.d.cts → StorageProvider-B2p_XThQ.d.ts} +32 -8
- package/dist/{StorageProvider-D_o2Hksf.d.ts → StorageProvider-CadKZ85j.d.cts} +32 -8
- package/dist/index.cjs +381 -120
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -14
- package/dist/index.d.ts +63 -14
- package/dist/index.js +376 -120
- package/dist/index.js.map +1 -1
- package/dist/{portability-P1hL-bOa.d.cts → portability-CAeyzSCx.d.cts} +30 -8
- package/dist/{portability-P1hL-bOa.d.ts → portability-CAeyzSCx.d.ts} +30 -8
- package/dist/providers/index.cjs.map +1 -1
- package/dist/providers/index.d.cts +4 -4
- package/dist/providers/index.d.ts +4 -4
- package/dist/testing/conformance.cjs +12 -2
- package/dist/testing/conformance.cjs.map +1 -1
- package/dist/testing/conformance.d.cts +2 -2
- package/dist/testing/conformance.d.ts +2 -2
- package/dist/testing/conformance.js +12 -2
- package/dist/testing/conformance.js.map +1 -1
- package/dist/{traversal-B_84kGaO.d.ts → traversal-Dql81Wh4.d.ts} +32 -6
- package/dist/{traversal-CBE5h5ob.d.cts → traversal-WLcdLN-Z.d.cts} +32 -6
- package/dist/types/index.d.cts +3 -3
- package/dist/types/index.d.ts +3 -3
- package/package.json +3 -4
package/dist/index.js
CHANGED
|
@@ -280,6 +280,14 @@ var TraversalTimeoutError = class extends DeepMemoryError {
|
|
|
280
280
|
this.timeoutMs = timeoutMs;
|
|
281
281
|
}
|
|
282
282
|
};
|
|
283
|
+
var UnsupportedQueryError = class extends DeepMemoryError {
|
|
284
|
+
provider;
|
|
285
|
+
constructor(provider, message, suggestion) {
|
|
286
|
+
super("UNSUPPORTED_QUERY", message, suggestion);
|
|
287
|
+
this.name = "UnsupportedQueryError";
|
|
288
|
+
this.provider = provider;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
283
291
|
|
|
284
292
|
// src/core/DeepMemory.ts
|
|
285
293
|
import { randomUUID } from "crypto";
|
|
@@ -898,7 +906,7 @@ var EntityManager = class {
|
|
|
898
906
|
let totalFailed = 0;
|
|
899
907
|
const allErrors = [];
|
|
900
908
|
let offset = 0;
|
|
901
|
-
while (offset < total) {
|
|
909
|
+
while (total === void 0 || offset < total) {
|
|
902
910
|
if (signal?.aborted) {
|
|
903
911
|
throw new OperationAbortedError("reembedAll");
|
|
904
912
|
}
|
|
@@ -925,7 +933,8 @@ var EntityManager = class {
|
|
|
925
933
|
throw new OperationAbortedError("reembedAll");
|
|
926
934
|
}
|
|
927
935
|
const delayMs = options?.delayBetweenBatchesMs ?? 0;
|
|
928
|
-
|
|
936
|
+
const moreLikely = total === void 0 ? page.items.length === batchSize : offset < total;
|
|
937
|
+
if (delayMs > 0 && moreLikely) {
|
|
929
938
|
await new Promise((resolve) => {
|
|
930
939
|
setTimeout(resolve, delayMs);
|
|
931
940
|
});
|
|
@@ -1354,22 +1363,52 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1354
1363
|
const dedup = spec.dedup !== false;
|
|
1355
1364
|
const limit = spec.limit ?? 50;
|
|
1356
1365
|
const offset = spec.offset ?? 0;
|
|
1357
|
-
let
|
|
1366
|
+
let paged;
|
|
1367
|
+
let pagedAllRels = [];
|
|
1368
|
+
let total;
|
|
1369
|
+
let unionFullLength = 0;
|
|
1358
1370
|
if (spec.returnMode === "all") {
|
|
1359
|
-
|
|
1371
|
+
const unionElements = buildAllModeUnion(allCollected);
|
|
1372
|
+
unionFullLength = unionElements.length;
|
|
1373
|
+
const pageSlice = unionElements.slice(offset, offset + limit);
|
|
1374
|
+
const pageEntries = [];
|
|
1375
|
+
const pageEntityIds = /* @__PURE__ */ new Set();
|
|
1376
|
+
for (const element of pageSlice) {
|
|
1377
|
+
if (element.kind === "entity") {
|
|
1378
|
+
if (!pageEntityIds.has(element.entry.entity.id)) {
|
|
1379
|
+
pageEntityIds.add(element.entry.entity.id);
|
|
1380
|
+
pageEntries.push(element.entry);
|
|
1381
|
+
}
|
|
1382
|
+
} else {
|
|
1383
|
+
pagedAllRels.push(element.rel);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
if (pagedAllRels.length > 0) {
|
|
1387
|
+
const entityIndex = /* @__PURE__ */ new Map();
|
|
1388
|
+
for (const el of unionElements) {
|
|
1389
|
+
if (el.kind === "entity" && !entityIndex.has(el.entry.entity.id)) {
|
|
1390
|
+
entityIndex.set(el.entry.entity.id, el.entry);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
for (const rel of pagedAllRels) {
|
|
1394
|
+
for (const endpointId of [rel.sourceEntityId, rel.targetEntityId]) {
|
|
1395
|
+
if (!pageEntityIds.has(endpointId)) {
|
|
1396
|
+
const entry = entityIndex.get(endpointId);
|
|
1397
|
+
if (entry) {
|
|
1398
|
+
pageEntityIds.add(endpointId);
|
|
1399
|
+
pageEntries.push(entry);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
paged = pageEntries;
|
|
1406
|
+
total = pageEntries.length + pagedAllRels.length;
|
|
1360
1407
|
} else {
|
|
1361
|
-
resultEntries = frontier;
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1365
|
-
resultEntries = resultEntries.filter((entry) => {
|
|
1366
|
-
if (seen.has(entry.entity.id)) return false;
|
|
1367
|
-
seen.add(entry.entity.id);
|
|
1368
|
-
return true;
|
|
1369
|
-
});
|
|
1408
|
+
const resultEntries = dedup && spec.returnMode !== "path" ? dedupEntriesById(frontier) : frontier;
|
|
1409
|
+
total = resultEntries.length;
|
|
1410
|
+
paged = resultEntries.slice(offset, offset + limit);
|
|
1370
1411
|
}
|
|
1371
|
-
const total = resultEntries.length;
|
|
1372
|
-
const paged = resultEntries.slice(offset, offset + limit);
|
|
1373
1412
|
const suppressEntities = spec.projection !== void 0 && spec.projection.includeEntities !== true;
|
|
1374
1413
|
let entities;
|
|
1375
1414
|
if (suppressEntities) {
|
|
@@ -1390,13 +1429,13 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1390
1429
|
direction: "both",
|
|
1391
1430
|
limit: 1e4
|
|
1392
1431
|
});
|
|
1393
|
-
const summary = {
|
|
1432
|
+
const summary = { out: {}, in: {} };
|
|
1394
1433
|
for (const rel of result.items) {
|
|
1395
1434
|
if (rel.sourceEntityId === entry.entity.id) {
|
|
1396
|
-
summary.
|
|
1435
|
+
summary.out[rel.relationshipType] = (summary.out[rel.relationshipType] ?? 0) + 1;
|
|
1397
1436
|
}
|
|
1398
1437
|
if (rel.targetEntityId === entry.entity.id) {
|
|
1399
|
-
summary.
|
|
1438
|
+
summary.in[rel.relationshipType] = (summary.in[rel.relationshipType] ?? 0) + 1;
|
|
1400
1439
|
}
|
|
1401
1440
|
}
|
|
1402
1441
|
return summary;
|
|
@@ -1410,7 +1449,8 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1410
1449
|
const propNames = spec.projection.properties;
|
|
1411
1450
|
const mode = spec.projection.mode ?? "values";
|
|
1412
1451
|
const distinct = spec.projection.distinct ?? false;
|
|
1413
|
-
const
|
|
1452
|
+
const aggregateDedup = spec.returnMode === "all" || dedup && spec.returnMode !== "path";
|
|
1453
|
+
const sourceEntries = aggregateDedup ? (() => {
|
|
1414
1454
|
const seen = /* @__PURE__ */ new Set();
|
|
1415
1455
|
return (spec.returnMode === "all" ? allCollected : frontier).filter((e) => {
|
|
1416
1456
|
if (seen.has(e.entity.id)) return false;
|
|
@@ -1452,17 +1492,28 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1452
1492
|
}
|
|
1453
1493
|
let relationships;
|
|
1454
1494
|
let paths;
|
|
1455
|
-
if (!suppressEntities &&
|
|
1495
|
+
if (!suppressEntities && spec.returnMode === "all") {
|
|
1496
|
+
relationships = pagedAllRels.map((rel) => ({
|
|
1497
|
+
id: rel.id,
|
|
1498
|
+
type: rel.relationshipType,
|
|
1499
|
+
sourceEntityId: rel.sourceEntityId,
|
|
1500
|
+
targetEntityId: rel.targetEntityId,
|
|
1501
|
+
direction: "out",
|
|
1502
|
+
properties: rel.properties
|
|
1503
|
+
}));
|
|
1504
|
+
} else if (!suppressEntities && spec.returnMode === "path") {
|
|
1456
1505
|
const relMap = /* @__PURE__ */ new Map();
|
|
1457
1506
|
for (const entry of paged) {
|
|
1458
|
-
for (
|
|
1507
|
+
for (let i = 0; i < entry.relationshipPath.length; i++) {
|
|
1508
|
+
const rel = entry.relationshipPath[i];
|
|
1459
1509
|
if (!relMap.has(rel.id)) {
|
|
1510
|
+
const fromId = entry.entityPath[i];
|
|
1460
1511
|
relMap.set(rel.id, {
|
|
1461
1512
|
id: rel.id,
|
|
1462
1513
|
type: rel.relationshipType,
|
|
1463
1514
|
sourceEntityId: rel.sourceEntityId,
|
|
1464
1515
|
targetEntityId: rel.targetEntityId,
|
|
1465
|
-
direction: "
|
|
1516
|
+
direction: fromId === rel.sourceEntityId ? "out" : "in",
|
|
1466
1517
|
properties: rel.properties
|
|
1467
1518
|
});
|
|
1468
1519
|
}
|
|
@@ -1471,44 +1522,66 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1471
1522
|
relationships = Array.from(relMap.values());
|
|
1472
1523
|
}
|
|
1473
1524
|
if (!suppressEntities && spec.returnMode === "path") {
|
|
1525
|
+
const pathEntityIds = /* @__PURE__ */ new Set();
|
|
1526
|
+
for (const entry of paged) {
|
|
1527
|
+
for (const id of entry.entityPath) {
|
|
1528
|
+
pathEntityIds.add(id);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
const pathEntityMap = pathEntityIds.size > 0 ? await storage.getEntities(repositoryId, [...pathEntityIds]) : /* @__PURE__ */ new Map();
|
|
1532
|
+
if (pathEntityIds.size > 0) {
|
|
1533
|
+
storageCalls++;
|
|
1534
|
+
}
|
|
1474
1535
|
paths = paged.map((entry) => ({
|
|
1475
1536
|
length: entry.entityPath.length - 1,
|
|
1476
|
-
entities:
|
|
1477
|
-
const
|
|
1478
|
-
if (!
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1537
|
+
entities: entry.entityPath.map((id) => {
|
|
1538
|
+
const stored = pathEntityMap.get(id);
|
|
1539
|
+
if (!stored) {
|
|
1540
|
+
throw new EntityNotFoundError(id);
|
|
1541
|
+
}
|
|
1542
|
+
const projected = projectEntity(stored, detailLevel);
|
|
1543
|
+
if (!spec.includeProvenance) {
|
|
1544
|
+
delete projected["provenance"];
|
|
1545
|
+
}
|
|
1546
|
+
return projected;
|
|
1547
|
+
}),
|
|
1548
|
+
relationships: entry.relationshipPath.map((rel, i) => {
|
|
1549
|
+
const fromId = entry.entityPath[i];
|
|
1550
|
+
return {
|
|
1551
|
+
id: rel.id,
|
|
1552
|
+
type: rel.relationshipType,
|
|
1553
|
+
sourceEntityId: rel.sourceEntityId,
|
|
1554
|
+
targetEntityId: rel.targetEntityId,
|
|
1555
|
+
direction: fromId === rel.sourceEntityId ? "out" : "in",
|
|
1556
|
+
properties: rel.properties
|
|
1557
|
+
};
|
|
1558
|
+
})
|
|
1489
1559
|
}));
|
|
1490
1560
|
}
|
|
1491
1561
|
const executionTimeMs = Date.now() - startTime;
|
|
1562
|
+
const returned = spec.returnMode === "all" ? total : paged.length;
|
|
1563
|
+
const hasMore = spec.returnMode === "all" ? offset + limit < unionFullLength : offset + limit < total;
|
|
1564
|
+
const truncated = spec.returnMode === "all" ? unionFullLength > limit + offset : total > limit + offset;
|
|
1492
1565
|
return {
|
|
1493
1566
|
entities,
|
|
1494
1567
|
relationships,
|
|
1495
1568
|
paths,
|
|
1496
1569
|
aggregations,
|
|
1497
1570
|
total,
|
|
1498
|
-
returned
|
|
1499
|
-
hasMore
|
|
1571
|
+
returned,
|
|
1572
|
+
hasMore,
|
|
1500
1573
|
queryMetadata: {
|
|
1501
1574
|
executionTimeMs,
|
|
1502
1575
|
appliedLimits: {
|
|
1503
1576
|
maxResults: limit
|
|
1504
1577
|
},
|
|
1505
|
-
truncated
|
|
1506
|
-
truncationReason:
|
|
1578
|
+
truncated,
|
|
1579
|
+
truncationReason: truncated ? "result_limit" : void 0
|
|
1507
1580
|
}
|
|
1508
1581
|
};
|
|
1509
1582
|
}
|
|
1510
1583
|
async function executeSingleStep(repositoryId, storage, frontier, step, onStorageCall) {
|
|
1511
|
-
const direction =
|
|
1584
|
+
const direction = step.direction;
|
|
1512
1585
|
const pendingEdges = [];
|
|
1513
1586
|
for (const entry of frontier) {
|
|
1514
1587
|
const rels = await storage.getEntityRelationships(repositoryId, entry.entity.id, {
|
|
@@ -1603,22 +1676,64 @@ async function resolveEntity(repositoryId, storage, idOrSlug) {
|
|
|
1603
1676
|
if (byId) return byId;
|
|
1604
1677
|
return storage.getEntityBySlug(repositoryId, idOrSlug);
|
|
1605
1678
|
}
|
|
1606
|
-
function mapDirection(direction) {
|
|
1607
|
-
switch (direction) {
|
|
1608
|
-
case "out":
|
|
1609
|
-
return "outbound";
|
|
1610
|
-
case "in":
|
|
1611
|
-
return "inbound";
|
|
1612
|
-
case "both":
|
|
1613
|
-
return "both";
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
1679
|
function getTargetId(rel, currentEntityId) {
|
|
1617
1680
|
if (rel.sourceEntityId === currentEntityId) {
|
|
1618
1681
|
return rel.targetEntityId;
|
|
1619
1682
|
}
|
|
1620
1683
|
return rel.sourceEntityId;
|
|
1621
1684
|
}
|
|
1685
|
+
function dedupEntriesById(entries) {
|
|
1686
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1687
|
+
const result = [];
|
|
1688
|
+
for (const entry of entries) {
|
|
1689
|
+
if (!seen.has(entry.entity.id)) {
|
|
1690
|
+
seen.add(entry.entity.id);
|
|
1691
|
+
result.push(entry);
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
return result;
|
|
1695
|
+
}
|
|
1696
|
+
function buildAllModeUnion(entries) {
|
|
1697
|
+
if (entries.length === 0) return [];
|
|
1698
|
+
let maxDepth = 0;
|
|
1699
|
+
const byDepth = /* @__PURE__ */ new Map();
|
|
1700
|
+
for (const entry of entries) {
|
|
1701
|
+
const depth = entry.relationshipPath.length;
|
|
1702
|
+
if (depth > maxDepth) maxDepth = depth;
|
|
1703
|
+
let bucket = byDepth.get(depth);
|
|
1704
|
+
if (!bucket) {
|
|
1705
|
+
bucket = [];
|
|
1706
|
+
byDepth.set(depth, bucket);
|
|
1707
|
+
}
|
|
1708
|
+
bucket.push(entry);
|
|
1709
|
+
}
|
|
1710
|
+
const seenEntities = /* @__PURE__ */ new Set();
|
|
1711
|
+
const seenRels = /* @__PURE__ */ new Set();
|
|
1712
|
+
const result = [];
|
|
1713
|
+
for (const entry of byDepth.get(0) ?? []) {
|
|
1714
|
+
if (!seenEntities.has(entry.entity.id)) {
|
|
1715
|
+
seenEntities.add(entry.entity.id);
|
|
1716
|
+
result.push({ kind: "entity", entry });
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
for (let depth = 1; depth <= maxDepth; depth++) {
|
|
1720
|
+
const bucket = byDepth.get(depth) ?? [];
|
|
1721
|
+
for (const entry of bucket) {
|
|
1722
|
+
if (!seenEntities.has(entry.entity.id)) {
|
|
1723
|
+
seenEntities.add(entry.entity.id);
|
|
1724
|
+
result.push({ kind: "entity", entry });
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
for (const entry of bucket) {
|
|
1728
|
+
const newRel = entry.relationshipPath[depth - 1];
|
|
1729
|
+
if (newRel && !seenRels.has(newRel.id)) {
|
|
1730
|
+
seenRels.add(newRel.id);
|
|
1731
|
+
result.push({ kind: "relationship", rel: newRel });
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
return result;
|
|
1736
|
+
}
|
|
1622
1737
|
|
|
1623
1738
|
// src/relationships/GraphTraversal.ts
|
|
1624
1739
|
var GraphTraversal = class {
|
|
@@ -1755,7 +1870,7 @@ var GraphTraversal = class {
|
|
|
1755
1870
|
return {
|
|
1756
1871
|
id: rid,
|
|
1757
1872
|
type: r?.type ?? "unknown",
|
|
1758
|
-
direction: r?.sourceEntityId === currentEntityId ? "
|
|
1873
|
+
direction: r?.sourceEntityId === currentEntityId ? "out" : "in",
|
|
1759
1874
|
properties: r?.properties ?? {}
|
|
1760
1875
|
};
|
|
1761
1876
|
})
|
|
@@ -1879,11 +1994,15 @@ var SearchOrchestrator = class {
|
|
|
1879
1994
|
const offset = options?.offset ?? 0;
|
|
1880
1995
|
const threshold = options?.similarityThreshold ?? this.defaultSimilarityThreshold;
|
|
1881
1996
|
const queryEmbedding = await this.embedding.embed(query);
|
|
1882
|
-
const allEntities = await this.storage.findEntities(
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1997
|
+
const allEntities = await this.storage.findEntities(
|
|
1998
|
+
this.repositoryId,
|
|
1999
|
+
{
|
|
2000
|
+
entityTypes: options?.entityTypes,
|
|
2001
|
+
limit: this.conceptSearchScanLimit,
|
|
2002
|
+
offset: 0
|
|
2003
|
+
},
|
|
2004
|
+
{ loadEmbeddings: true }
|
|
2005
|
+
);
|
|
1887
2006
|
const scored = [];
|
|
1888
2007
|
for (const entity of allEntities.items) {
|
|
1889
2008
|
let score;
|
|
@@ -2378,7 +2497,7 @@ var MemoryRepository = class {
|
|
|
2378
2497
|
inbound[rel.relationshipType] = (inbound[rel.relationshipType] ?? 0) + 1;
|
|
2379
2498
|
}
|
|
2380
2499
|
}
|
|
2381
|
-
return { outbound, inbound };
|
|
2500
|
+
return { out: outbound, in: inbound };
|
|
2382
2501
|
}
|
|
2383
2502
|
async getRelationshipsForEntities(entityIds) {
|
|
2384
2503
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2586,9 +2705,10 @@ var MemoryRepository = class {
|
|
|
2586
2705
|
### Step 1 \u2014 Discover before you traverse
|
|
2587
2706
|
|
|
2588
2707
|
Before following relationships from an entity, check that it actually has relationships.
|
|
2589
|
-
Graph queries include \`relationshipSummary\` on every returned entity by default
|
|
2590
|
-
(
|
|
2591
|
-
zero
|
|
2708
|
+
Graph queries include \`relationshipSummary\` on every returned entity by default \u2014
|
|
2709
|
+
\`out\` (entity is source) and \`in\` (entity is target) counts by relationship type.
|
|
2710
|
+
Inspect this before traversing: entities with zero counts for the relationship type
|
|
2711
|
+
you need have no connections to follow.
|
|
2592
2712
|
To skip summaries and reduce response size, set \`includeRelationshipSummary: false\`.
|
|
2593
2713
|
|
|
2594
2714
|
### Step 2 \u2014 Use projection for aggregation
|
|
@@ -3266,7 +3386,14 @@ var VocabularyEngine = class {
|
|
|
3266
3386
|
async proposeExtension(proposal, proposedBy) {
|
|
3267
3387
|
return this.proposeChange(proposal, proposedBy);
|
|
3268
3388
|
}
|
|
3269
|
-
/**
|
|
3389
|
+
/**
|
|
3390
|
+
* Cascade-delete all data for a deleted vocabulary type.
|
|
3391
|
+
*
|
|
3392
|
+
* `deletedRelationships` may be `undefined` when the underlying provider
|
|
3393
|
+
* does not count cascaded edges (see StorageProvider.deleteEntitiesByType).
|
|
3394
|
+
* The return value is currently discarded by the only caller; the type is
|
|
3395
|
+
* preserved for symmetry with the storage contract.
|
|
3396
|
+
*/
|
|
3270
3397
|
async cascadeDeleteData(proposal) {
|
|
3271
3398
|
if (proposal.proposalType === "delete_entity_type" && proposal.deleteEntityType) {
|
|
3272
3399
|
return this.storage.deleteEntitiesByType(
|
|
@@ -3464,7 +3591,7 @@ var EventBus = class {
|
|
|
3464
3591
|
};
|
|
3465
3592
|
|
|
3466
3593
|
// src/portability/RepositoryExporter.ts
|
|
3467
|
-
var LIBRARY_VERSION = true ? "0.
|
|
3594
|
+
var LIBRARY_VERSION = true ? "0.18.0" : "0.1.0";
|
|
3468
3595
|
var RepositoryExporter = class {
|
|
3469
3596
|
storage;
|
|
3470
3597
|
provenance;
|
|
@@ -4567,10 +4694,15 @@ var DeepMemory = class {
|
|
|
4567
4694
|
try {
|
|
4568
4695
|
const result = await repo.reembedAll({
|
|
4569
4696
|
...options,
|
|
4697
|
+
// The repo signature widens `totalEntities` to `number | undefined`
|
|
4698
|
+
// because PaginatedResult.total may be undefined under some provider/
|
|
4699
|
+
// query combinations. The `reembed:progress` event contract is
|
|
4700
|
+
// `totalEntities: number`, so fall back to the cached stats count
|
|
4701
|
+
// when the inner layer doesn't supply one.
|
|
4570
4702
|
onProgress: (progress) => this.globalEventBus.emit("reembed:progress", {
|
|
4571
4703
|
repositoryId,
|
|
4572
4704
|
processed: progress.processed,
|
|
4573
|
-
totalEntities: progress.totalEntities,
|
|
4705
|
+
totalEntities: progress.totalEntities ?? stats.entityCount,
|
|
4574
4706
|
failed: progress.failed
|
|
4575
4707
|
}),
|
|
4576
4708
|
onItemFailed: (failure) => this.globalEventBus.emit("reembed:item-failed", {
|
|
@@ -4629,6 +4761,69 @@ function createSafeSink(sink) {
|
|
|
4629
4761
|
|
|
4630
4762
|
// src/relationships/compilers/GremlinCompiler.ts
|
|
4631
4763
|
var DEFAULT_ESTIMATED_FANOUT_PER_HOP = 10;
|
|
4764
|
+
var VERTEX_PROJECTION = [
|
|
4765
|
+
["__kind", `.by(constant('v'))`],
|
|
4766
|
+
["id", `.by(id)`],
|
|
4767
|
+
["entityType", `.by('entityType')`],
|
|
4768
|
+
["entityLabel", `.by('entityLabel')`],
|
|
4769
|
+
["slug", `.by('slug')`],
|
|
4770
|
+
["summary", `.by(coalesce(values('summary'), constant('')))`],
|
|
4771
|
+
["properties", `.by(coalesce(values('properties'), constant('{}')))`],
|
|
4772
|
+
["data", `.by(coalesce(values('data'), constant('')))`],
|
|
4773
|
+
["dataFormat", `.by(coalesce(values('dataFormat'), constant('')))`],
|
|
4774
|
+
["createdBy", `.by('createdBy')`],
|
|
4775
|
+
["createdByType", `.by('createdByType')`],
|
|
4776
|
+
["createdAt", `.by('createdAt')`],
|
|
4777
|
+
["createdInConversation", `.by(coalesce(values('createdInConversation'), constant('')))`],
|
|
4778
|
+
["createdFromMessage", `.by(coalesce(values('createdFromMessage'), constant('')))`],
|
|
4779
|
+
["modifiedBy", `.by('modifiedBy')`],
|
|
4780
|
+
["modifiedByType", `.by('modifiedByType')`],
|
|
4781
|
+
["modifiedAt", `.by('modifiedAt')`],
|
|
4782
|
+
["modifiedInConversation", `.by(coalesce(values('modifiedInConversation'), constant('')))`],
|
|
4783
|
+
["modifiedFromMessage", `.by(coalesce(values('modifiedFromMessage'), constant('')))`]
|
|
4784
|
+
];
|
|
4785
|
+
var EDGE_PROJECTION = [
|
|
4786
|
+
["__kind", `.by(constant('e'))`],
|
|
4787
|
+
["id", `.by(id)`],
|
|
4788
|
+
["relationshipType", `.by('relationshipType')`],
|
|
4789
|
+
["sourceEntityId", `.by('sourceEntityId')`],
|
|
4790
|
+
["targetEntityId", `.by('targetEntityId')`],
|
|
4791
|
+
["properties", `.by(coalesce(values('properties'), constant('{}')))`],
|
|
4792
|
+
["bidirectional", `.by(coalesce(values('bidirectional'), constant(false)))`],
|
|
4793
|
+
["createdBy", `.by('createdBy')`],
|
|
4794
|
+
["createdByType", `.by('createdByType')`],
|
|
4795
|
+
["createdAt", `.by('createdAt')`],
|
|
4796
|
+
["createdInConversation", `.by(coalesce(values('createdInConversation'), constant('')))`],
|
|
4797
|
+
["createdFromMessage", `.by(coalesce(values('createdFromMessage'), constant('')))`],
|
|
4798
|
+
["modifiedBy", `.by('modifiedBy')`],
|
|
4799
|
+
["modifiedByType", `.by('modifiedByType')`],
|
|
4800
|
+
["modifiedAt", `.by('modifiedAt')`],
|
|
4801
|
+
["modifiedInConversation", `.by(coalesce(values('modifiedInConversation'), constant('')))`],
|
|
4802
|
+
["modifiedFromMessage", `.by(coalesce(values('modifiedFromMessage'), constant('')))`]
|
|
4803
|
+
];
|
|
4804
|
+
var EMBEDDING_PROJECTION_ENTRY = [
|
|
4805
|
+
"embedding",
|
|
4806
|
+
`.by(coalesce(values('embedding'), constant('')))`
|
|
4807
|
+
];
|
|
4808
|
+
function buildProjectExpression(entries) {
|
|
4809
|
+
const keys = entries.map(([k]) => `'${k}'`).join(",");
|
|
4810
|
+
const bys = entries.map(([, by]) => by).join("");
|
|
4811
|
+
return `project(${keys})${bys}`;
|
|
4812
|
+
}
|
|
4813
|
+
var VERTEX_PROJECT_EXPR = buildProjectExpression(VERTEX_PROJECTION);
|
|
4814
|
+
var VERTEX_PROJECT_EXPR_WITH_EMBEDDING = buildProjectExpression([
|
|
4815
|
+
...VERTEX_PROJECTION,
|
|
4816
|
+
EMBEDDING_PROJECTION_ENTRY
|
|
4817
|
+
]);
|
|
4818
|
+
var EDGE_PROJECT_EXPR = buildProjectExpression(EDGE_PROJECTION);
|
|
4819
|
+
var GREMLIN_VERTEX_PROJECTION_FIELDS = VERTEX_PROJECTION.map(([k]) => k).filter((k) => k !== "__kind");
|
|
4820
|
+
var GREMLIN_EDGE_PROJECTION_FIELDS = EDGE_PROJECTION.map(([k]) => k).filter((k) => k !== "__kind");
|
|
4821
|
+
function buildVertexProjectChain(opts) {
|
|
4822
|
+
return opts?.withEmbedding ? VERTEX_PROJECT_EXPR_WITH_EMBEDDING : VERTEX_PROJECT_EXPR;
|
|
4823
|
+
}
|
|
4824
|
+
function buildEdgeProjectChain() {
|
|
4825
|
+
return EDGE_PROJECT_EXPR;
|
|
4826
|
+
}
|
|
4632
4827
|
var GremlinCompiler = class {
|
|
4633
4828
|
language = "gremlin";
|
|
4634
4829
|
compile(spec, _vocabulary) {
|
|
@@ -4644,7 +4839,7 @@ var GremlinCompiler = class {
|
|
|
4644
4839
|
parts.push("g.V()");
|
|
4645
4840
|
if (spec.start.entityId) {
|
|
4646
4841
|
const p = nextParam(spec.start.entityId);
|
|
4647
|
-
parts.push(`.
|
|
4842
|
+
parts.push(`.hasId(${p})`);
|
|
4648
4843
|
} else if (spec.start.entityType) {
|
|
4649
4844
|
const p = nextParam(spec.start.entityType);
|
|
4650
4845
|
parts.push(`.has('entityType', ${p})`);
|
|
@@ -4656,44 +4851,79 @@ var GremlinCompiler = class {
|
|
|
4656
4851
|
}
|
|
4657
4852
|
}
|
|
4658
4853
|
const steps = spec.steps ?? [];
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4666
|
-
} else {
|
|
4667
|
-
parts.push(compileSimpleStep(step, nextParam));
|
|
4668
|
-
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4854
|
+
const returnMode = spec.returnMode ?? "terminal";
|
|
4855
|
+
if (returnMode === "all") {
|
|
4856
|
+
if (steps.some((s) => s.repeat)) {
|
|
4857
|
+
throw new Error(
|
|
4858
|
+
"GremlinCompiler: 'all' returnMode does not support repeat steps. Use 'terminal' or 'path' mode, or unroll the repeat into explicit steps."
|
|
4859
|
+
);
|
|
4669
4860
|
}
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4861
|
+
const compiledSteps = steps.map((step) => ({
|
|
4862
|
+
edge: compileEdgeOnly(step, nextParam),
|
|
4863
|
+
vertex: compileVertexHop(step),
|
|
4864
|
+
// Per plan §3: entity-type/property filters apply only on branches
|
|
4865
|
+
// ending at that depth's vertex. They are NOT included in the prefix
|
|
4866
|
+
// that deeper branches traverse through.
|
|
4867
|
+
entityFilters: compileEntityFilters(step, nextParam)
|
|
4868
|
+
}));
|
|
4869
|
+
const branches = [`__.identity().${VERTEX_PROJECT_EXPR}`];
|
|
4870
|
+
let prefix = "";
|
|
4871
|
+
for (const { edge, vertex, entityFilters } of compiledSteps) {
|
|
4872
|
+
branches.push(`__${prefix}${edge}${vertex}${entityFilters}.${VERTEX_PROJECT_EXPR}`);
|
|
4873
|
+
branches.push(`__${prefix}${edge}.${EDGE_PROJECT_EXPR}`);
|
|
4874
|
+
prefix = `${prefix}${edge}${vertex}`;
|
|
4875
|
+
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4673
4876
|
}
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4877
|
+
parts.push(`.union(${branches.join(", ")})`);
|
|
4878
|
+
parts.push(`.dedup().by(select('id'))`);
|
|
4879
|
+
const limit = spec.limit ?? 50;
|
|
4880
|
+
const offset = spec.offset ?? 0;
|
|
4881
|
+
const pOffset = nextParam(offset);
|
|
4882
|
+
const pEnd = nextParam(offset + limit);
|
|
4883
|
+
parts.push(`.range(${pOffset}, ${pEnd})`);
|
|
4884
|
+
params["_limit"] = limit;
|
|
4885
|
+
params["_offset"] = offset;
|
|
4886
|
+
} else {
|
|
4887
|
+
const useEdgeEmission = returnMode === "path";
|
|
4888
|
+
for (const step of steps) {
|
|
4889
|
+
if (step.repeat) {
|
|
4890
|
+
parts.push(compileRepeatStep(step, nextParam, useEdgeEmission));
|
|
4891
|
+
estimatedFanOut *= step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4892
|
+
} else if (useEdgeEmission || step.relationshipFilter && step.relationshipFilter.length > 0) {
|
|
4893
|
+
parts.push(compileEdgeStep(step, nextParam));
|
|
4894
|
+
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4895
|
+
} else {
|
|
4896
|
+
parts.push(compileSimpleStep(step, nextParam));
|
|
4897
|
+
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4898
|
+
}
|
|
4899
|
+
if (step.entityTypes && step.entityTypes.length > 0) {
|
|
4900
|
+
const typeParams = step.entityTypes.map((t) => nextParam(t));
|
|
4901
|
+
parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
|
|
4902
|
+
}
|
|
4903
|
+
if (step.entityFilter) {
|
|
4904
|
+
for (const f of step.entityFilter) {
|
|
4905
|
+
parts.push(compilePropertyFilter(f, nextParam));
|
|
4906
|
+
}
|
|
4677
4907
|
}
|
|
4678
4908
|
}
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4909
|
+
if (returnMode === "terminal" && spec.dedup !== false) {
|
|
4910
|
+
parts.push(".dedup()");
|
|
4911
|
+
}
|
|
4912
|
+
if (returnMode === "path") {
|
|
4913
|
+
parts.push(".simplePath()");
|
|
4914
|
+
}
|
|
4915
|
+
const limit = spec.limit ?? 50;
|
|
4916
|
+
const offset = spec.offset ?? 0;
|
|
4917
|
+
const pOffset = nextParam(offset);
|
|
4918
|
+
const pEnd = nextParam(offset + limit);
|
|
4919
|
+
parts.push(`.range(${pOffset}, ${pEnd})`);
|
|
4920
|
+
params["_limit"] = limit;
|
|
4921
|
+
params["_offset"] = offset;
|
|
4922
|
+
if (returnMode === "terminal") {
|
|
4923
|
+
parts.push(`.${VERTEX_PROJECT_EXPR}`);
|
|
4924
|
+
} else {
|
|
4925
|
+
parts.push(`.path().by(${VERTEX_PROJECT_EXPR}).by(${EDGE_PROJECT_EXPR})`);
|
|
4926
|
+
}
|
|
4697
4927
|
}
|
|
4698
4928
|
return {
|
|
4699
4929
|
query: parts.join(""),
|
|
@@ -4714,7 +4944,7 @@ function compileSimpleStep(step, nextParam) {
|
|
|
4714
4944
|
return types ? `.both(${typeArgs})` : ".both()";
|
|
4715
4945
|
}
|
|
4716
4946
|
}
|
|
4717
|
-
function
|
|
4947
|
+
function compileEdgeOnly(step, nextParam) {
|
|
4718
4948
|
const parts = [];
|
|
4719
4949
|
const types = step.relationshipTypes;
|
|
4720
4950
|
const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
|
|
@@ -4734,22 +4964,37 @@ function compileEdgeStep(step, nextParam) {
|
|
|
4734
4964
|
parts.push(compilePropertyFilter(f, nextParam));
|
|
4735
4965
|
}
|
|
4736
4966
|
}
|
|
4967
|
+
return parts.join("");
|
|
4968
|
+
}
|
|
4969
|
+
function compileVertexHop(step) {
|
|
4737
4970
|
switch (step.direction) {
|
|
4738
4971
|
case "out":
|
|
4739
|
-
|
|
4740
|
-
break;
|
|
4972
|
+
return ".inV()";
|
|
4741
4973
|
case "in":
|
|
4742
|
-
|
|
4743
|
-
break;
|
|
4974
|
+
return ".outV()";
|
|
4744
4975
|
case "both":
|
|
4745
|
-
|
|
4746
|
-
|
|
4976
|
+
return ".otherV()";
|
|
4977
|
+
}
|
|
4978
|
+
}
|
|
4979
|
+
function compileEntityFilters(step, nextParam) {
|
|
4980
|
+
const parts = [];
|
|
4981
|
+
if (step.entityTypes && step.entityTypes.length > 0) {
|
|
4982
|
+
const typeParams = step.entityTypes.map((t) => nextParam(t));
|
|
4983
|
+
parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
|
|
4984
|
+
}
|
|
4985
|
+
if (step.entityFilter) {
|
|
4986
|
+
for (const f of step.entityFilter) {
|
|
4987
|
+
parts.push(compilePropertyFilter(f, nextParam));
|
|
4988
|
+
}
|
|
4747
4989
|
}
|
|
4748
4990
|
return parts.join("");
|
|
4749
4991
|
}
|
|
4750
|
-
function
|
|
4992
|
+
function compileEdgeStep(step, nextParam) {
|
|
4993
|
+
return compileEdgeOnly(step, nextParam) + compileVertexHop(step);
|
|
4994
|
+
}
|
|
4995
|
+
function compileRepeatStep(step, nextParam, useEdgeEmission) {
|
|
4751
4996
|
const parts = [];
|
|
4752
|
-
const innerStep = step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
|
|
4997
|
+
const innerStep = useEdgeEmission || step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
|
|
4753
4998
|
if (step.repeat?.emitIntermediates !== false) {
|
|
4754
4999
|
parts.push(".emit()");
|
|
4755
5000
|
}
|
|
@@ -4758,10 +5003,13 @@ function compileRepeatStep(step, nextParam) {
|
|
|
4758
5003
|
const untilParts = step.repeat.until.map((f) => compilePropertyFilter(f, nextParam));
|
|
4759
5004
|
parts.push(`.until(${untilParts.join("")})`);
|
|
4760
5005
|
}
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
5006
|
+
const n = step.repeat.maxDepth;
|
|
5007
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
5008
|
+
throw new Error(
|
|
5009
|
+
`GremlinCompiler: repeat.maxDepth must be a positive integer; got ${n}`
|
|
5010
|
+
);
|
|
4764
5011
|
}
|
|
5012
|
+
parts.push(`.times(${n})`);
|
|
4765
5013
|
if (step.repeat?.emitIntermediates === false) {
|
|
4766
5014
|
parts.push(".emit()");
|
|
4767
5015
|
}
|
|
@@ -5080,17 +5328,20 @@ var InMemoryStorageProvider = class {
|
|
|
5080
5328
|
store.slugIndex.set(entity.slug, entity.id);
|
|
5081
5329
|
return entity;
|
|
5082
5330
|
}
|
|
5083
|
-
|
|
5331
|
+
// The in-memory provider always carries the full entity (embedding and all).
|
|
5332
|
+
// The `loadEmbeddings` option is accepted for interface symmetry but ignored —
|
|
5333
|
+
// there is no light/full split to switch between when entities live in a Map.
|
|
5334
|
+
async getEntity(repositoryId, entityId, _options) {
|
|
5084
5335
|
const store = this.getStore(repositoryId);
|
|
5085
5336
|
return store.entities.get(entityId) ?? null;
|
|
5086
5337
|
}
|
|
5087
|
-
async getEntityBySlug(repositoryId, slug) {
|
|
5338
|
+
async getEntityBySlug(repositoryId, slug, _options) {
|
|
5088
5339
|
const store = this.getStore(repositoryId);
|
|
5089
5340
|
const id = store.slugIndex.get(slug);
|
|
5090
5341
|
if (!id) return null;
|
|
5091
5342
|
return store.entities.get(id) ?? null;
|
|
5092
5343
|
}
|
|
5093
|
-
async getEntities(repositoryId, entityIds) {
|
|
5344
|
+
async getEntities(repositoryId, entityIds, _options) {
|
|
5094
5345
|
const store = this.getStore(repositoryId);
|
|
5095
5346
|
const result = /* @__PURE__ */ new Map();
|
|
5096
5347
|
for (const id of entityIds) {
|
|
@@ -5161,7 +5412,7 @@ var InMemoryStorageProvider = class {
|
|
|
5161
5412
|
}
|
|
5162
5413
|
return { deletedEntities: entityIds.size, deletedRelationships };
|
|
5163
5414
|
}
|
|
5164
|
-
async findEntities(repositoryId, query) {
|
|
5415
|
+
async findEntities(repositoryId, query, _options) {
|
|
5165
5416
|
const store = this.getStore(repositoryId);
|
|
5166
5417
|
let matches = Array.from(store.entities.values());
|
|
5167
5418
|
if (query.entityTypes && query.entityTypes.length > 0) {
|
|
@@ -5214,9 +5465,9 @@ var InMemoryStorageProvider = class {
|
|
|
5214
5465
|
const isTarget = rel.targetEntityId === entityId;
|
|
5215
5466
|
const isBidirectionalTarget = rel.bidirectional && isTarget;
|
|
5216
5467
|
switch (direction) {
|
|
5217
|
-
case "
|
|
5468
|
+
case "out":
|
|
5218
5469
|
return isSource || isBidirectionalTarget;
|
|
5219
|
-
case "
|
|
5470
|
+
case "in":
|
|
5220
5471
|
return isTarget || rel.bidirectional && isSource;
|
|
5221
5472
|
case "both":
|
|
5222
5473
|
default:
|
|
@@ -5314,17 +5565,17 @@ var InMemoryStorageProvider = class {
|
|
|
5314
5565
|
const isTarget = rel.targetEntityId === frontierEntityId;
|
|
5315
5566
|
let matchesDirection = false;
|
|
5316
5567
|
let connectedEntityId;
|
|
5317
|
-
if (isSource && (options.direction === "
|
|
5568
|
+
if (isSource && (options.direction === "out" || options.direction === "both")) {
|
|
5318
5569
|
matchesDirection = true;
|
|
5319
5570
|
connectedEntityId = rel.targetEntityId;
|
|
5320
|
-
} else if (isTarget && (options.direction === "
|
|
5571
|
+
} else if (isTarget && (options.direction === "in" || options.direction === "both")) {
|
|
5321
5572
|
matchesDirection = true;
|
|
5322
5573
|
connectedEntityId = rel.sourceEntityId;
|
|
5323
5574
|
} else if (rel.bidirectional) {
|
|
5324
|
-
if (isSource && options.direction === "
|
|
5575
|
+
if (isSource && options.direction === "in") {
|
|
5325
5576
|
matchesDirection = true;
|
|
5326
5577
|
connectedEntityId = rel.targetEntityId;
|
|
5327
|
-
} else if (isTarget && options.direction === "
|
|
5578
|
+
} else if (isTarget && options.direction === "out") {
|
|
5328
5579
|
matchesDirection = true;
|
|
5329
5580
|
connectedEntityId = rel.sourceEntityId;
|
|
5330
5581
|
}
|
|
@@ -5683,6 +5934,8 @@ export {
|
|
|
5683
5934
|
EmbeddingProviderRequiredError,
|
|
5684
5935
|
EntityNotFoundError,
|
|
5685
5936
|
ExportError,
|
|
5937
|
+
GREMLIN_EDGE_PROJECTION_FIELDS,
|
|
5938
|
+
GREMLIN_VERTEX_PROJECTION_FIELDS,
|
|
5686
5939
|
GovernanceDeniedError,
|
|
5687
5940
|
GraphTraversalProviderRequiredError,
|
|
5688
5941
|
GremlinCompiler,
|
|
@@ -5704,7 +5957,10 @@ export {
|
|
|
5704
5957
|
TraversalTimeoutError,
|
|
5705
5958
|
TraversalValidationError,
|
|
5706
5959
|
TraversalVocabularyError,
|
|
5960
|
+
UnsupportedQueryError,
|
|
5707
5961
|
VocabularyValidationError,
|
|
5962
|
+
buildEdgeProjectChain,
|
|
5963
|
+
buildVertexProjectChain,
|
|
5708
5964
|
createSafeSink,
|
|
5709
5965
|
generateId,
|
|
5710
5966
|
isValidUuid,
|