@utaba/deep-memory 0.16.0 → 0.17.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-DDTLUcuj.d.ts} +32 -8
- package/dist/{StorageProvider-D_o2Hksf.d.ts → StorageProvider-DGH7bVuK.d.cts} +32 -8
- package/dist/index.cjs +342 -95
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -13
- package/dist/index.d.ts +62 -13
- package/dist/index.js +337 -95
- package/dist/index.js.map +1 -1
- package/dist/{portability-P1hL-bOa.d.cts → portability-Dbm6vCdD.d.cts} +15 -3
- package/dist/{portability-P1hL-bOa.d.ts → portability-Dbm6vCdD.d.ts} +15 -3
- package/dist/providers/index.cjs.map +1 -1
- package/dist/providers/index.d.cts +3 -3
- package/dist/providers/index.d.ts +3 -3
- package/dist/testing/conformance.cjs +10 -0
- 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 +10 -0
- package/dist/testing/conformance.js.map +1 -1
- package/dist/{traversal-CBE5h5ob.d.cts → traversal-1f35drOx.d.cts} +24 -3
- package/dist/{traversal-B_84kGaO.d.ts → traversal-OkXViSTI.d.ts} +24 -3
- package/dist/types/index.d.cts +3 -3
- package/dist/types/index.d.ts +3 -3
- package/package.json +2 -3
package/dist/index.cjs
CHANGED
|
@@ -29,6 +29,8 @@ __export(src_exports, {
|
|
|
29
29
|
EmbeddingProviderRequiredError: () => EmbeddingProviderRequiredError,
|
|
30
30
|
EntityNotFoundError: () => EntityNotFoundError,
|
|
31
31
|
ExportError: () => ExportError,
|
|
32
|
+
GREMLIN_EDGE_PROJECTION_FIELDS: () => GREMLIN_EDGE_PROJECTION_FIELDS,
|
|
33
|
+
GREMLIN_VERTEX_PROJECTION_FIELDS: () => GREMLIN_VERTEX_PROJECTION_FIELDS,
|
|
32
34
|
GovernanceDeniedError: () => GovernanceDeniedError,
|
|
33
35
|
GraphTraversalProviderRequiredError: () => GraphTraversalProviderRequiredError,
|
|
34
36
|
GremlinCompiler: () => GremlinCompiler,
|
|
@@ -50,7 +52,10 @@ __export(src_exports, {
|
|
|
50
52
|
TraversalTimeoutError: () => TraversalTimeoutError,
|
|
51
53
|
TraversalValidationError: () => TraversalValidationError,
|
|
52
54
|
TraversalVocabularyError: () => TraversalVocabularyError,
|
|
55
|
+
UnsupportedQueryError: () => UnsupportedQueryError,
|
|
53
56
|
VocabularyValidationError: () => VocabularyValidationError,
|
|
57
|
+
buildEdgeProjectChain: () => buildEdgeProjectChain,
|
|
58
|
+
buildVertexProjectChain: () => buildVertexProjectChain,
|
|
54
59
|
createSafeSink: () => createSafeSink,
|
|
55
60
|
generateId: () => generateId,
|
|
56
61
|
isValidUuid: () => isValidUuid,
|
|
@@ -341,6 +346,14 @@ var TraversalTimeoutError = class extends DeepMemoryError {
|
|
|
341
346
|
this.timeoutMs = timeoutMs;
|
|
342
347
|
}
|
|
343
348
|
};
|
|
349
|
+
var UnsupportedQueryError = class extends DeepMemoryError {
|
|
350
|
+
provider;
|
|
351
|
+
constructor(provider, message, suggestion) {
|
|
352
|
+
super("UNSUPPORTED_QUERY", message, suggestion);
|
|
353
|
+
this.name = "UnsupportedQueryError";
|
|
354
|
+
this.provider = provider;
|
|
355
|
+
}
|
|
356
|
+
};
|
|
344
357
|
|
|
345
358
|
// src/core/DeepMemory.ts
|
|
346
359
|
var import_node_crypto = require("crypto");
|
|
@@ -959,7 +972,7 @@ var EntityManager = class {
|
|
|
959
972
|
let totalFailed = 0;
|
|
960
973
|
const allErrors = [];
|
|
961
974
|
let offset = 0;
|
|
962
|
-
while (offset < total) {
|
|
975
|
+
while (total === void 0 || offset < total) {
|
|
963
976
|
if (signal?.aborted) {
|
|
964
977
|
throw new OperationAbortedError("reembedAll");
|
|
965
978
|
}
|
|
@@ -986,7 +999,8 @@ var EntityManager = class {
|
|
|
986
999
|
throw new OperationAbortedError("reembedAll");
|
|
987
1000
|
}
|
|
988
1001
|
const delayMs = options?.delayBetweenBatchesMs ?? 0;
|
|
989
|
-
|
|
1002
|
+
const moreLikely = total === void 0 ? page.items.length === batchSize : offset < total;
|
|
1003
|
+
if (delayMs > 0 && moreLikely) {
|
|
990
1004
|
await new Promise((resolve) => {
|
|
991
1005
|
setTimeout(resolve, delayMs);
|
|
992
1006
|
});
|
|
@@ -1415,22 +1429,29 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1415
1429
|
const dedup = spec.dedup !== false;
|
|
1416
1430
|
const limit = spec.limit ?? 50;
|
|
1417
1431
|
const offset = spec.offset ?? 0;
|
|
1418
|
-
let
|
|
1432
|
+
let paged;
|
|
1433
|
+
let pagedAllRels = [];
|
|
1434
|
+
let total;
|
|
1435
|
+
let unionFullLength = 0;
|
|
1419
1436
|
if (spec.returnMode === "all") {
|
|
1420
|
-
|
|
1437
|
+
const unionElements = buildAllModeUnion(allCollected);
|
|
1438
|
+
unionFullLength = unionElements.length;
|
|
1439
|
+
const pageSlice = unionElements.slice(offset, offset + limit);
|
|
1440
|
+
const pageEntries = [];
|
|
1441
|
+
for (const element of pageSlice) {
|
|
1442
|
+
if (element.kind === "entity") {
|
|
1443
|
+
pageEntries.push(element.entry);
|
|
1444
|
+
} else {
|
|
1445
|
+
pagedAllRels.push(element.rel);
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
paged = pageEntries;
|
|
1449
|
+
total = pageEntries.length + pagedAllRels.length;
|
|
1421
1450
|
} else {
|
|
1422
|
-
resultEntries = frontier;
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1426
|
-
resultEntries = resultEntries.filter((entry) => {
|
|
1427
|
-
if (seen.has(entry.entity.id)) return false;
|
|
1428
|
-
seen.add(entry.entity.id);
|
|
1429
|
-
return true;
|
|
1430
|
-
});
|
|
1451
|
+
const resultEntries = dedup && spec.returnMode !== "path" ? dedupEntriesById(frontier) : frontier;
|
|
1452
|
+
total = resultEntries.length;
|
|
1453
|
+
paged = resultEntries.slice(offset, offset + limit);
|
|
1431
1454
|
}
|
|
1432
|
-
const total = resultEntries.length;
|
|
1433
|
-
const paged = resultEntries.slice(offset, offset + limit);
|
|
1434
1455
|
const suppressEntities = spec.projection !== void 0 && spec.projection.includeEntities !== true;
|
|
1435
1456
|
let entities;
|
|
1436
1457
|
if (suppressEntities) {
|
|
@@ -1471,7 +1492,8 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1471
1492
|
const propNames = spec.projection.properties;
|
|
1472
1493
|
const mode = spec.projection.mode ?? "values";
|
|
1473
1494
|
const distinct = spec.projection.distinct ?? false;
|
|
1474
|
-
const
|
|
1495
|
+
const aggregateDedup = spec.returnMode === "all" || dedup && spec.returnMode !== "path";
|
|
1496
|
+
const sourceEntries = aggregateDedup ? (() => {
|
|
1475
1497
|
const seen = /* @__PURE__ */ new Set();
|
|
1476
1498
|
return (spec.returnMode === "all" ? allCollected : frontier).filter((e) => {
|
|
1477
1499
|
if (seen.has(e.entity.id)) return false;
|
|
@@ -1513,17 +1535,28 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1513
1535
|
}
|
|
1514
1536
|
let relationships;
|
|
1515
1537
|
let paths;
|
|
1516
|
-
if (!suppressEntities &&
|
|
1538
|
+
if (!suppressEntities && spec.returnMode === "all") {
|
|
1539
|
+
relationships = pagedAllRels.map((rel) => ({
|
|
1540
|
+
id: rel.id,
|
|
1541
|
+
type: rel.relationshipType,
|
|
1542
|
+
sourceEntityId: rel.sourceEntityId,
|
|
1543
|
+
targetEntityId: rel.targetEntityId,
|
|
1544
|
+
direction: "outbound",
|
|
1545
|
+
properties: rel.properties
|
|
1546
|
+
}));
|
|
1547
|
+
} else if (!suppressEntities && spec.returnMode === "path") {
|
|
1517
1548
|
const relMap = /* @__PURE__ */ new Map();
|
|
1518
1549
|
for (const entry of paged) {
|
|
1519
|
-
for (
|
|
1550
|
+
for (let i = 0; i < entry.relationshipPath.length; i++) {
|
|
1551
|
+
const rel = entry.relationshipPath[i];
|
|
1520
1552
|
if (!relMap.has(rel.id)) {
|
|
1553
|
+
const fromId = entry.entityPath[i];
|
|
1521
1554
|
relMap.set(rel.id, {
|
|
1522
1555
|
id: rel.id,
|
|
1523
1556
|
type: rel.relationshipType,
|
|
1524
1557
|
sourceEntityId: rel.sourceEntityId,
|
|
1525
1558
|
targetEntityId: rel.targetEntityId,
|
|
1526
|
-
direction: "outbound",
|
|
1559
|
+
direction: fromId === rel.sourceEntityId ? "outbound" : "inbound",
|
|
1527
1560
|
properties: rel.properties
|
|
1528
1561
|
});
|
|
1529
1562
|
}
|
|
@@ -1532,39 +1565,61 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1532
1565
|
relationships = Array.from(relMap.values());
|
|
1533
1566
|
}
|
|
1534
1567
|
if (!suppressEntities && spec.returnMode === "path") {
|
|
1568
|
+
const pathEntityIds = /* @__PURE__ */ new Set();
|
|
1569
|
+
for (const entry of paged) {
|
|
1570
|
+
for (const id of entry.entityPath) {
|
|
1571
|
+
pathEntityIds.add(id);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
const pathEntityMap = pathEntityIds.size > 0 ? await storage.getEntities(repositoryId, [...pathEntityIds]) : /* @__PURE__ */ new Map();
|
|
1575
|
+
if (pathEntityIds.size > 0) {
|
|
1576
|
+
storageCalls++;
|
|
1577
|
+
}
|
|
1535
1578
|
paths = paged.map((entry) => ({
|
|
1536
1579
|
length: entry.entityPath.length - 1,
|
|
1537
|
-
entities:
|
|
1538
|
-
const
|
|
1539
|
-
if (!
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1580
|
+
entities: entry.entityPath.map((id) => {
|
|
1581
|
+
const stored = pathEntityMap.get(id);
|
|
1582
|
+
if (!stored) {
|
|
1583
|
+
throw new EntityNotFoundError(id);
|
|
1584
|
+
}
|
|
1585
|
+
const projected = projectEntity(stored, detailLevel);
|
|
1586
|
+
if (!spec.includeProvenance) {
|
|
1587
|
+
delete projected["provenance"];
|
|
1588
|
+
}
|
|
1589
|
+
return projected;
|
|
1590
|
+
}),
|
|
1591
|
+
relationships: entry.relationshipPath.map((rel, i) => {
|
|
1592
|
+
const fromId = entry.entityPath[i];
|
|
1593
|
+
return {
|
|
1594
|
+
id: rel.id,
|
|
1595
|
+
type: rel.relationshipType,
|
|
1596
|
+
sourceEntityId: rel.sourceEntityId,
|
|
1597
|
+
targetEntityId: rel.targetEntityId,
|
|
1598
|
+
direction: fromId === rel.sourceEntityId ? "outbound" : "inbound",
|
|
1599
|
+
properties: rel.properties
|
|
1600
|
+
};
|
|
1601
|
+
})
|
|
1550
1602
|
}));
|
|
1551
1603
|
}
|
|
1552
1604
|
const executionTimeMs = Date.now() - startTime;
|
|
1605
|
+
const returned = spec.returnMode === "all" ? total : paged.length;
|
|
1606
|
+
const hasMore = spec.returnMode === "all" ? offset + limit < unionFullLength : offset + limit < total;
|
|
1607
|
+
const truncated = spec.returnMode === "all" ? unionFullLength > limit + offset : total > limit + offset;
|
|
1553
1608
|
return {
|
|
1554
1609
|
entities,
|
|
1555
1610
|
relationships,
|
|
1556
1611
|
paths,
|
|
1557
1612
|
aggregations,
|
|
1558
1613
|
total,
|
|
1559
|
-
returned
|
|
1560
|
-
hasMore
|
|
1614
|
+
returned,
|
|
1615
|
+
hasMore,
|
|
1561
1616
|
queryMetadata: {
|
|
1562
1617
|
executionTimeMs,
|
|
1563
1618
|
appliedLimits: {
|
|
1564
1619
|
maxResults: limit
|
|
1565
1620
|
},
|
|
1566
|
-
truncated
|
|
1567
|
-
truncationReason:
|
|
1621
|
+
truncated,
|
|
1622
|
+
truncationReason: truncated ? "result_limit" : void 0
|
|
1568
1623
|
}
|
|
1569
1624
|
};
|
|
1570
1625
|
}
|
|
@@ -1680,6 +1735,58 @@ function getTargetId(rel, currentEntityId) {
|
|
|
1680
1735
|
}
|
|
1681
1736
|
return rel.sourceEntityId;
|
|
1682
1737
|
}
|
|
1738
|
+
function dedupEntriesById(entries) {
|
|
1739
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1740
|
+
const result = [];
|
|
1741
|
+
for (const entry of entries) {
|
|
1742
|
+
if (!seen.has(entry.entity.id)) {
|
|
1743
|
+
seen.add(entry.entity.id);
|
|
1744
|
+
result.push(entry);
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
return result;
|
|
1748
|
+
}
|
|
1749
|
+
function buildAllModeUnion(entries) {
|
|
1750
|
+
if (entries.length === 0) return [];
|
|
1751
|
+
let maxDepth = 0;
|
|
1752
|
+
const byDepth = /* @__PURE__ */ new Map();
|
|
1753
|
+
for (const entry of entries) {
|
|
1754
|
+
const depth = entry.relationshipPath.length;
|
|
1755
|
+
if (depth > maxDepth) maxDepth = depth;
|
|
1756
|
+
let bucket = byDepth.get(depth);
|
|
1757
|
+
if (!bucket) {
|
|
1758
|
+
bucket = [];
|
|
1759
|
+
byDepth.set(depth, bucket);
|
|
1760
|
+
}
|
|
1761
|
+
bucket.push(entry);
|
|
1762
|
+
}
|
|
1763
|
+
const seenEntities = /* @__PURE__ */ new Set();
|
|
1764
|
+
const seenRels = /* @__PURE__ */ new Set();
|
|
1765
|
+
const result = [];
|
|
1766
|
+
for (const entry of byDepth.get(0) ?? []) {
|
|
1767
|
+
if (!seenEntities.has(entry.entity.id)) {
|
|
1768
|
+
seenEntities.add(entry.entity.id);
|
|
1769
|
+
result.push({ kind: "entity", entry });
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
for (let depth = 1; depth <= maxDepth; depth++) {
|
|
1773
|
+
const bucket = byDepth.get(depth) ?? [];
|
|
1774
|
+
for (const entry of bucket) {
|
|
1775
|
+
const newRel = entry.relationshipPath[depth - 1];
|
|
1776
|
+
if (newRel && !seenRels.has(newRel.id)) {
|
|
1777
|
+
seenRels.add(newRel.id);
|
|
1778
|
+
result.push({ kind: "relationship", rel: newRel });
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
for (const entry of bucket) {
|
|
1782
|
+
if (!seenEntities.has(entry.entity.id)) {
|
|
1783
|
+
seenEntities.add(entry.entity.id);
|
|
1784
|
+
result.push({ kind: "entity", entry });
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
return result;
|
|
1789
|
+
}
|
|
1683
1790
|
|
|
1684
1791
|
// src/relationships/GraphTraversal.ts
|
|
1685
1792
|
var GraphTraversal = class {
|
|
@@ -1940,11 +2047,15 @@ var SearchOrchestrator = class {
|
|
|
1940
2047
|
const offset = options?.offset ?? 0;
|
|
1941
2048
|
const threshold = options?.similarityThreshold ?? this.defaultSimilarityThreshold;
|
|
1942
2049
|
const queryEmbedding = await this.embedding.embed(query);
|
|
1943
|
-
const allEntities = await this.storage.findEntities(
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
2050
|
+
const allEntities = await this.storage.findEntities(
|
|
2051
|
+
this.repositoryId,
|
|
2052
|
+
{
|
|
2053
|
+
entityTypes: options?.entityTypes,
|
|
2054
|
+
limit: this.conceptSearchScanLimit,
|
|
2055
|
+
offset: 0
|
|
2056
|
+
},
|
|
2057
|
+
{ loadEmbeddings: true }
|
|
2058
|
+
);
|
|
1948
2059
|
const scored = [];
|
|
1949
2060
|
for (const entity of allEntities.items) {
|
|
1950
2061
|
let score;
|
|
@@ -3327,7 +3438,14 @@ var VocabularyEngine = class {
|
|
|
3327
3438
|
async proposeExtension(proposal, proposedBy) {
|
|
3328
3439
|
return this.proposeChange(proposal, proposedBy);
|
|
3329
3440
|
}
|
|
3330
|
-
/**
|
|
3441
|
+
/**
|
|
3442
|
+
* Cascade-delete all data for a deleted vocabulary type.
|
|
3443
|
+
*
|
|
3444
|
+
* `deletedRelationships` may be `undefined` when the underlying provider
|
|
3445
|
+
* does not count cascaded edges (see StorageProvider.deleteEntitiesByType).
|
|
3446
|
+
* The return value is currently discarded by the only caller; the type is
|
|
3447
|
+
* preserved for symmetry with the storage contract.
|
|
3448
|
+
*/
|
|
3331
3449
|
async cascadeDeleteData(proposal) {
|
|
3332
3450
|
if (proposal.proposalType === "delete_entity_type" && proposal.deleteEntityType) {
|
|
3333
3451
|
return this.storage.deleteEntitiesByType(
|
|
@@ -3525,7 +3643,7 @@ var EventBus = class {
|
|
|
3525
3643
|
};
|
|
3526
3644
|
|
|
3527
3645
|
// src/portability/RepositoryExporter.ts
|
|
3528
|
-
var LIBRARY_VERSION = true ? "0.
|
|
3646
|
+
var LIBRARY_VERSION = true ? "0.17.0" : "0.1.0";
|
|
3529
3647
|
var RepositoryExporter = class {
|
|
3530
3648
|
storage;
|
|
3531
3649
|
provenance;
|
|
@@ -4628,10 +4746,15 @@ var DeepMemory = class {
|
|
|
4628
4746
|
try {
|
|
4629
4747
|
const result = await repo.reembedAll({
|
|
4630
4748
|
...options,
|
|
4749
|
+
// The repo signature widens `totalEntities` to `number | undefined`
|
|
4750
|
+
// because PaginatedResult.total may be undefined under some provider/
|
|
4751
|
+
// query combinations. The `reembed:progress` event contract is
|
|
4752
|
+
// `totalEntities: number`, so fall back to the cached stats count
|
|
4753
|
+
// when the inner layer doesn't supply one.
|
|
4631
4754
|
onProgress: (progress) => this.globalEventBus.emit("reembed:progress", {
|
|
4632
4755
|
repositoryId,
|
|
4633
4756
|
processed: progress.processed,
|
|
4634
|
-
totalEntities: progress.totalEntities,
|
|
4757
|
+
totalEntities: progress.totalEntities ?? stats.entityCount,
|
|
4635
4758
|
failed: progress.failed
|
|
4636
4759
|
}),
|
|
4637
4760
|
onItemFailed: (failure) => this.globalEventBus.emit("reembed:item-failed", {
|
|
@@ -4690,6 +4813,69 @@ function createSafeSink(sink) {
|
|
|
4690
4813
|
|
|
4691
4814
|
// src/relationships/compilers/GremlinCompiler.ts
|
|
4692
4815
|
var DEFAULT_ESTIMATED_FANOUT_PER_HOP = 10;
|
|
4816
|
+
var VERTEX_PROJECTION = [
|
|
4817
|
+
["__kind", `.by(constant('v'))`],
|
|
4818
|
+
["id", `.by(id)`],
|
|
4819
|
+
["entityType", `.by('entityType')`],
|
|
4820
|
+
["entityLabel", `.by('entityLabel')`],
|
|
4821
|
+
["slug", `.by('slug')`],
|
|
4822
|
+
["summary", `.by(coalesce(values('summary'), constant('')))`],
|
|
4823
|
+
["properties", `.by(coalesce(values('properties'), constant('{}')))`],
|
|
4824
|
+
["data", `.by(coalesce(values('data'), constant('')))`],
|
|
4825
|
+
["dataFormat", `.by(coalesce(values('dataFormat'), constant('')))`],
|
|
4826
|
+
["createdBy", `.by('createdBy')`],
|
|
4827
|
+
["createdByType", `.by('createdByType')`],
|
|
4828
|
+
["createdAt", `.by('createdAt')`],
|
|
4829
|
+
["createdInConversation", `.by(coalesce(values('createdInConversation'), constant('')))`],
|
|
4830
|
+
["createdFromMessage", `.by(coalesce(values('createdFromMessage'), constant('')))`],
|
|
4831
|
+
["modifiedBy", `.by('modifiedBy')`],
|
|
4832
|
+
["modifiedByType", `.by('modifiedByType')`],
|
|
4833
|
+
["modifiedAt", `.by('modifiedAt')`],
|
|
4834
|
+
["modifiedInConversation", `.by(coalesce(values('modifiedInConversation'), constant('')))`],
|
|
4835
|
+
["modifiedFromMessage", `.by(coalesce(values('modifiedFromMessage'), constant('')))`]
|
|
4836
|
+
];
|
|
4837
|
+
var EDGE_PROJECTION = [
|
|
4838
|
+
["__kind", `.by(constant('e'))`],
|
|
4839
|
+
["id", `.by(id)`],
|
|
4840
|
+
["relationshipType", `.by('relationshipType')`],
|
|
4841
|
+
["sourceEntityId", `.by('sourceEntityId')`],
|
|
4842
|
+
["targetEntityId", `.by('targetEntityId')`],
|
|
4843
|
+
["properties", `.by(coalesce(values('properties'), constant('{}')))`],
|
|
4844
|
+
["bidirectional", `.by(coalesce(values('bidirectional'), constant(false)))`],
|
|
4845
|
+
["createdBy", `.by('createdBy')`],
|
|
4846
|
+
["createdByType", `.by('createdByType')`],
|
|
4847
|
+
["createdAt", `.by('createdAt')`],
|
|
4848
|
+
["createdInConversation", `.by(coalesce(values('createdInConversation'), constant('')))`],
|
|
4849
|
+
["createdFromMessage", `.by(coalesce(values('createdFromMessage'), constant('')))`],
|
|
4850
|
+
["modifiedBy", `.by('modifiedBy')`],
|
|
4851
|
+
["modifiedByType", `.by('modifiedByType')`],
|
|
4852
|
+
["modifiedAt", `.by('modifiedAt')`],
|
|
4853
|
+
["modifiedInConversation", `.by(coalesce(values('modifiedInConversation'), constant('')))`],
|
|
4854
|
+
["modifiedFromMessage", `.by(coalesce(values('modifiedFromMessage'), constant('')))`]
|
|
4855
|
+
];
|
|
4856
|
+
var EMBEDDING_PROJECTION_ENTRY = [
|
|
4857
|
+
"embedding",
|
|
4858
|
+
`.by(coalesce(values('embedding'), constant('')))`
|
|
4859
|
+
];
|
|
4860
|
+
function buildProjectExpression(entries) {
|
|
4861
|
+
const keys = entries.map(([k]) => `'${k}'`).join(",");
|
|
4862
|
+
const bys = entries.map(([, by]) => by).join("");
|
|
4863
|
+
return `project(${keys})${bys}`;
|
|
4864
|
+
}
|
|
4865
|
+
var VERTEX_PROJECT_EXPR = buildProjectExpression(VERTEX_PROJECTION);
|
|
4866
|
+
var VERTEX_PROJECT_EXPR_WITH_EMBEDDING = buildProjectExpression([
|
|
4867
|
+
...VERTEX_PROJECTION,
|
|
4868
|
+
EMBEDDING_PROJECTION_ENTRY
|
|
4869
|
+
]);
|
|
4870
|
+
var EDGE_PROJECT_EXPR = buildProjectExpression(EDGE_PROJECTION);
|
|
4871
|
+
var GREMLIN_VERTEX_PROJECTION_FIELDS = VERTEX_PROJECTION.map(([k]) => k).filter((k) => k !== "__kind");
|
|
4872
|
+
var GREMLIN_EDGE_PROJECTION_FIELDS = EDGE_PROJECTION.map(([k]) => k).filter((k) => k !== "__kind");
|
|
4873
|
+
function buildVertexProjectChain(opts) {
|
|
4874
|
+
return opts?.withEmbedding ? VERTEX_PROJECT_EXPR_WITH_EMBEDDING : VERTEX_PROJECT_EXPR;
|
|
4875
|
+
}
|
|
4876
|
+
function buildEdgeProjectChain() {
|
|
4877
|
+
return EDGE_PROJECT_EXPR;
|
|
4878
|
+
}
|
|
4693
4879
|
var GremlinCompiler = class {
|
|
4694
4880
|
language = "gremlin";
|
|
4695
4881
|
compile(spec, _vocabulary) {
|
|
@@ -4705,7 +4891,7 @@ var GremlinCompiler = class {
|
|
|
4705
4891
|
parts.push("g.V()");
|
|
4706
4892
|
if (spec.start.entityId) {
|
|
4707
4893
|
const p = nextParam(spec.start.entityId);
|
|
4708
|
-
parts.push(`.
|
|
4894
|
+
parts.push(`.hasId(${p})`);
|
|
4709
4895
|
} else if (spec.start.entityType) {
|
|
4710
4896
|
const p = nextParam(spec.start.entityType);
|
|
4711
4897
|
parts.push(`.has('entityType', ${p})`);
|
|
@@ -4717,44 +4903,79 @@ var GremlinCompiler = class {
|
|
|
4717
4903
|
}
|
|
4718
4904
|
}
|
|
4719
4905
|
const steps = spec.steps ?? [];
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4727
|
-
} else {
|
|
4728
|
-
parts.push(compileSimpleStep(step, nextParam));
|
|
4729
|
-
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4906
|
+
const returnMode = spec.returnMode ?? "terminal";
|
|
4907
|
+
if (returnMode === "all") {
|
|
4908
|
+
if (steps.some((s) => s.repeat)) {
|
|
4909
|
+
throw new Error(
|
|
4910
|
+
"GremlinCompiler: 'all' returnMode does not support repeat steps. Use 'terminal' or 'path' mode, or unroll the repeat into explicit steps."
|
|
4911
|
+
);
|
|
4730
4912
|
}
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4913
|
+
const compiledSteps = steps.map((step) => ({
|
|
4914
|
+
edge: compileEdgeOnly(step, nextParam),
|
|
4915
|
+
vertex: compileVertexHop(step),
|
|
4916
|
+
// Per plan §3: entity-type/property filters apply only on branches
|
|
4917
|
+
// ending at that depth's vertex. They are NOT included in the prefix
|
|
4918
|
+
// that deeper branches traverse through.
|
|
4919
|
+
entityFilters: compileEntityFilters(step, nextParam)
|
|
4920
|
+
}));
|
|
4921
|
+
const branches = [`__.identity().${VERTEX_PROJECT_EXPR}`];
|
|
4922
|
+
let prefix = "";
|
|
4923
|
+
for (const { edge, vertex, entityFilters } of compiledSteps) {
|
|
4924
|
+
branches.push(`__${prefix}${edge}.${EDGE_PROJECT_EXPR}`);
|
|
4925
|
+
branches.push(`__${prefix}${edge}${vertex}${entityFilters}.${VERTEX_PROJECT_EXPR}`);
|
|
4926
|
+
prefix = `${prefix}${edge}${vertex}`;
|
|
4927
|
+
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4734
4928
|
}
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4929
|
+
parts.push(`.union(${branches.join(", ")})`);
|
|
4930
|
+
parts.push(`.dedup().by(select('id'))`);
|
|
4931
|
+
const limit = spec.limit ?? 50;
|
|
4932
|
+
const offset = spec.offset ?? 0;
|
|
4933
|
+
const pOffset = nextParam(offset);
|
|
4934
|
+
const pEnd = nextParam(offset + limit);
|
|
4935
|
+
parts.push(`.range(${pOffset}, ${pEnd})`);
|
|
4936
|
+
params["_limit"] = limit;
|
|
4937
|
+
params["_offset"] = offset;
|
|
4938
|
+
} else {
|
|
4939
|
+
const useEdgeEmission = returnMode === "path";
|
|
4940
|
+
for (const step of steps) {
|
|
4941
|
+
if (step.repeat) {
|
|
4942
|
+
parts.push(compileRepeatStep(step, nextParam, useEdgeEmission));
|
|
4943
|
+
estimatedFanOut *= step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4944
|
+
} else if (useEdgeEmission || step.relationshipFilter && step.relationshipFilter.length > 0) {
|
|
4945
|
+
parts.push(compileEdgeStep(step, nextParam));
|
|
4946
|
+
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4947
|
+
} else {
|
|
4948
|
+
parts.push(compileSimpleStep(step, nextParam));
|
|
4949
|
+
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4950
|
+
}
|
|
4951
|
+
if (step.entityTypes && step.entityTypes.length > 0) {
|
|
4952
|
+
const typeParams = step.entityTypes.map((t) => nextParam(t));
|
|
4953
|
+
parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
|
|
4954
|
+
}
|
|
4955
|
+
if (step.entityFilter) {
|
|
4956
|
+
for (const f of step.entityFilter) {
|
|
4957
|
+
parts.push(compilePropertyFilter(f, nextParam));
|
|
4958
|
+
}
|
|
4738
4959
|
}
|
|
4739
4960
|
}
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4961
|
+
if (returnMode === "terminal" && spec.dedup !== false) {
|
|
4962
|
+
parts.push(".dedup()");
|
|
4963
|
+
}
|
|
4964
|
+
if (returnMode === "path") {
|
|
4965
|
+
parts.push(".simplePath()");
|
|
4966
|
+
}
|
|
4967
|
+
const limit = spec.limit ?? 50;
|
|
4968
|
+
const offset = spec.offset ?? 0;
|
|
4969
|
+
const pOffset = nextParam(offset);
|
|
4970
|
+
const pEnd = nextParam(offset + limit);
|
|
4971
|
+
parts.push(`.range(${pOffset}, ${pEnd})`);
|
|
4972
|
+
params["_limit"] = limit;
|
|
4973
|
+
params["_offset"] = offset;
|
|
4974
|
+
if (returnMode === "terminal") {
|
|
4975
|
+
parts.push(`.${VERTEX_PROJECT_EXPR}`);
|
|
4976
|
+
} else {
|
|
4977
|
+
parts.push(`.path().by(${VERTEX_PROJECT_EXPR}).by(${EDGE_PROJECT_EXPR})`);
|
|
4978
|
+
}
|
|
4758
4979
|
}
|
|
4759
4980
|
return {
|
|
4760
4981
|
query: parts.join(""),
|
|
@@ -4775,7 +4996,7 @@ function compileSimpleStep(step, nextParam) {
|
|
|
4775
4996
|
return types ? `.both(${typeArgs})` : ".both()";
|
|
4776
4997
|
}
|
|
4777
4998
|
}
|
|
4778
|
-
function
|
|
4999
|
+
function compileEdgeOnly(step, nextParam) {
|
|
4779
5000
|
const parts = [];
|
|
4780
5001
|
const types = step.relationshipTypes;
|
|
4781
5002
|
const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
|
|
@@ -4795,22 +5016,37 @@ function compileEdgeStep(step, nextParam) {
|
|
|
4795
5016
|
parts.push(compilePropertyFilter(f, nextParam));
|
|
4796
5017
|
}
|
|
4797
5018
|
}
|
|
5019
|
+
return parts.join("");
|
|
5020
|
+
}
|
|
5021
|
+
function compileVertexHop(step) {
|
|
4798
5022
|
switch (step.direction) {
|
|
4799
5023
|
case "out":
|
|
4800
|
-
|
|
4801
|
-
break;
|
|
5024
|
+
return ".inV()";
|
|
4802
5025
|
case "in":
|
|
4803
|
-
|
|
4804
|
-
break;
|
|
5026
|
+
return ".outV()";
|
|
4805
5027
|
case "both":
|
|
4806
|
-
|
|
4807
|
-
|
|
5028
|
+
return ".otherV()";
|
|
5029
|
+
}
|
|
5030
|
+
}
|
|
5031
|
+
function compileEntityFilters(step, nextParam) {
|
|
5032
|
+
const parts = [];
|
|
5033
|
+
if (step.entityTypes && step.entityTypes.length > 0) {
|
|
5034
|
+
const typeParams = step.entityTypes.map((t) => nextParam(t));
|
|
5035
|
+
parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
|
|
5036
|
+
}
|
|
5037
|
+
if (step.entityFilter) {
|
|
5038
|
+
for (const f of step.entityFilter) {
|
|
5039
|
+
parts.push(compilePropertyFilter(f, nextParam));
|
|
5040
|
+
}
|
|
4808
5041
|
}
|
|
4809
5042
|
return parts.join("");
|
|
4810
5043
|
}
|
|
4811
|
-
function
|
|
5044
|
+
function compileEdgeStep(step, nextParam) {
|
|
5045
|
+
return compileEdgeOnly(step, nextParam) + compileVertexHop(step);
|
|
5046
|
+
}
|
|
5047
|
+
function compileRepeatStep(step, nextParam, useEdgeEmission) {
|
|
4812
5048
|
const parts = [];
|
|
4813
|
-
const innerStep = step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
|
|
5049
|
+
const innerStep = useEdgeEmission || step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
|
|
4814
5050
|
if (step.repeat?.emitIntermediates !== false) {
|
|
4815
5051
|
parts.push(".emit()");
|
|
4816
5052
|
}
|
|
@@ -4819,10 +5055,13 @@ function compileRepeatStep(step, nextParam) {
|
|
|
4819
5055
|
const untilParts = step.repeat.until.map((f) => compilePropertyFilter(f, nextParam));
|
|
4820
5056
|
parts.push(`.until(${untilParts.join("")})`);
|
|
4821
5057
|
}
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
5058
|
+
const n = step.repeat.maxDepth;
|
|
5059
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
5060
|
+
throw new Error(
|
|
5061
|
+
`GremlinCompiler: repeat.maxDepth must be a positive integer; got ${n}`
|
|
5062
|
+
);
|
|
4825
5063
|
}
|
|
5064
|
+
parts.push(`.times(${n})`);
|
|
4826
5065
|
if (step.repeat?.emitIntermediates === false) {
|
|
4827
5066
|
parts.push(".emit()");
|
|
4828
5067
|
}
|
|
@@ -5141,17 +5380,20 @@ var InMemoryStorageProvider = class {
|
|
|
5141
5380
|
store.slugIndex.set(entity.slug, entity.id);
|
|
5142
5381
|
return entity;
|
|
5143
5382
|
}
|
|
5144
|
-
|
|
5383
|
+
// The in-memory provider always carries the full entity (embedding and all).
|
|
5384
|
+
// The `loadEmbeddings` option is accepted for interface symmetry but ignored —
|
|
5385
|
+
// there is no light/full split to switch between when entities live in a Map.
|
|
5386
|
+
async getEntity(repositoryId, entityId, _options) {
|
|
5145
5387
|
const store = this.getStore(repositoryId);
|
|
5146
5388
|
return store.entities.get(entityId) ?? null;
|
|
5147
5389
|
}
|
|
5148
|
-
async getEntityBySlug(repositoryId, slug) {
|
|
5390
|
+
async getEntityBySlug(repositoryId, slug, _options) {
|
|
5149
5391
|
const store = this.getStore(repositoryId);
|
|
5150
5392
|
const id = store.slugIndex.get(slug);
|
|
5151
5393
|
if (!id) return null;
|
|
5152
5394
|
return store.entities.get(id) ?? null;
|
|
5153
5395
|
}
|
|
5154
|
-
async getEntities(repositoryId, entityIds) {
|
|
5396
|
+
async getEntities(repositoryId, entityIds, _options) {
|
|
5155
5397
|
const store = this.getStore(repositoryId);
|
|
5156
5398
|
const result = /* @__PURE__ */ new Map();
|
|
5157
5399
|
for (const id of entityIds) {
|
|
@@ -5222,7 +5464,7 @@ var InMemoryStorageProvider = class {
|
|
|
5222
5464
|
}
|
|
5223
5465
|
return { deletedEntities: entityIds.size, deletedRelationships };
|
|
5224
5466
|
}
|
|
5225
|
-
async findEntities(repositoryId, query) {
|
|
5467
|
+
async findEntities(repositoryId, query, _options) {
|
|
5226
5468
|
const store = this.getStore(repositoryId);
|
|
5227
5469
|
let matches = Array.from(store.entities.values());
|
|
5228
5470
|
if (query.entityTypes && query.entityTypes.length > 0) {
|
|
@@ -5745,6 +5987,8 @@ var NoOpEmbeddingProvider = class {
|
|
|
5745
5987
|
EmbeddingProviderRequiredError,
|
|
5746
5988
|
EntityNotFoundError,
|
|
5747
5989
|
ExportError,
|
|
5990
|
+
GREMLIN_EDGE_PROJECTION_FIELDS,
|
|
5991
|
+
GREMLIN_VERTEX_PROJECTION_FIELDS,
|
|
5748
5992
|
GovernanceDeniedError,
|
|
5749
5993
|
GraphTraversalProviderRequiredError,
|
|
5750
5994
|
GremlinCompiler,
|
|
@@ -5766,7 +6010,10 @@ var NoOpEmbeddingProvider = class {
|
|
|
5766
6010
|
TraversalTimeoutError,
|
|
5767
6011
|
TraversalValidationError,
|
|
5768
6012
|
TraversalVocabularyError,
|
|
6013
|
+
UnsupportedQueryError,
|
|
5769
6014
|
VocabularyValidationError,
|
|
6015
|
+
buildEdgeProjectChain,
|
|
6016
|
+
buildVertexProjectChain,
|
|
5770
6017
|
createSafeSink,
|
|
5771
6018
|
generateId,
|
|
5772
6019
|
isValidUuid,
|