@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.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,29 @@ 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
|
+
for (const element of pageSlice) {
|
|
1376
|
+
if (element.kind === "entity") {
|
|
1377
|
+
pageEntries.push(element.entry);
|
|
1378
|
+
} else {
|
|
1379
|
+
pagedAllRels.push(element.rel);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
paged = pageEntries;
|
|
1383
|
+
total = pageEntries.length + pagedAllRels.length;
|
|
1360
1384
|
} 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
|
-
});
|
|
1385
|
+
const resultEntries = dedup && spec.returnMode !== "path" ? dedupEntriesById(frontier) : frontier;
|
|
1386
|
+
total = resultEntries.length;
|
|
1387
|
+
paged = resultEntries.slice(offset, offset + limit);
|
|
1370
1388
|
}
|
|
1371
|
-
const total = resultEntries.length;
|
|
1372
|
-
const paged = resultEntries.slice(offset, offset + limit);
|
|
1373
1389
|
const suppressEntities = spec.projection !== void 0 && spec.projection.includeEntities !== true;
|
|
1374
1390
|
let entities;
|
|
1375
1391
|
if (suppressEntities) {
|
|
@@ -1410,7 +1426,8 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1410
1426
|
const propNames = spec.projection.properties;
|
|
1411
1427
|
const mode = spec.projection.mode ?? "values";
|
|
1412
1428
|
const distinct = spec.projection.distinct ?? false;
|
|
1413
|
-
const
|
|
1429
|
+
const aggregateDedup = spec.returnMode === "all" || dedup && spec.returnMode !== "path";
|
|
1430
|
+
const sourceEntries = aggregateDedup ? (() => {
|
|
1414
1431
|
const seen = /* @__PURE__ */ new Set();
|
|
1415
1432
|
return (spec.returnMode === "all" ? allCollected : frontier).filter((e) => {
|
|
1416
1433
|
if (seen.has(e.entity.id)) return false;
|
|
@@ -1452,17 +1469,28 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1452
1469
|
}
|
|
1453
1470
|
let relationships;
|
|
1454
1471
|
let paths;
|
|
1455
|
-
if (!suppressEntities &&
|
|
1472
|
+
if (!suppressEntities && spec.returnMode === "all") {
|
|
1473
|
+
relationships = pagedAllRels.map((rel) => ({
|
|
1474
|
+
id: rel.id,
|
|
1475
|
+
type: rel.relationshipType,
|
|
1476
|
+
sourceEntityId: rel.sourceEntityId,
|
|
1477
|
+
targetEntityId: rel.targetEntityId,
|
|
1478
|
+
direction: "outbound",
|
|
1479
|
+
properties: rel.properties
|
|
1480
|
+
}));
|
|
1481
|
+
} else if (!suppressEntities && spec.returnMode === "path") {
|
|
1456
1482
|
const relMap = /* @__PURE__ */ new Map();
|
|
1457
1483
|
for (const entry of paged) {
|
|
1458
|
-
for (
|
|
1484
|
+
for (let i = 0; i < entry.relationshipPath.length; i++) {
|
|
1485
|
+
const rel = entry.relationshipPath[i];
|
|
1459
1486
|
if (!relMap.has(rel.id)) {
|
|
1487
|
+
const fromId = entry.entityPath[i];
|
|
1460
1488
|
relMap.set(rel.id, {
|
|
1461
1489
|
id: rel.id,
|
|
1462
1490
|
type: rel.relationshipType,
|
|
1463
1491
|
sourceEntityId: rel.sourceEntityId,
|
|
1464
1492
|
targetEntityId: rel.targetEntityId,
|
|
1465
|
-
direction: "outbound",
|
|
1493
|
+
direction: fromId === rel.sourceEntityId ? "outbound" : "inbound",
|
|
1466
1494
|
properties: rel.properties
|
|
1467
1495
|
});
|
|
1468
1496
|
}
|
|
@@ -1471,39 +1499,61 @@ async function executeFallbackTraversal(repositoryId, storage, spec) {
|
|
|
1471
1499
|
relationships = Array.from(relMap.values());
|
|
1472
1500
|
}
|
|
1473
1501
|
if (!suppressEntities && spec.returnMode === "path") {
|
|
1502
|
+
const pathEntityIds = /* @__PURE__ */ new Set();
|
|
1503
|
+
for (const entry of paged) {
|
|
1504
|
+
for (const id of entry.entityPath) {
|
|
1505
|
+
pathEntityIds.add(id);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
const pathEntityMap = pathEntityIds.size > 0 ? await storage.getEntities(repositoryId, [...pathEntityIds]) : /* @__PURE__ */ new Map();
|
|
1509
|
+
if (pathEntityIds.size > 0) {
|
|
1510
|
+
storageCalls++;
|
|
1511
|
+
}
|
|
1474
1512
|
paths = paged.map((entry) => ({
|
|
1475
1513
|
length: entry.entityPath.length - 1,
|
|
1476
|
-
entities:
|
|
1477
|
-
const
|
|
1478
|
-
if (!
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1514
|
+
entities: entry.entityPath.map((id) => {
|
|
1515
|
+
const stored = pathEntityMap.get(id);
|
|
1516
|
+
if (!stored) {
|
|
1517
|
+
throw new EntityNotFoundError(id);
|
|
1518
|
+
}
|
|
1519
|
+
const projected = projectEntity(stored, detailLevel);
|
|
1520
|
+
if (!spec.includeProvenance) {
|
|
1521
|
+
delete projected["provenance"];
|
|
1522
|
+
}
|
|
1523
|
+
return projected;
|
|
1524
|
+
}),
|
|
1525
|
+
relationships: entry.relationshipPath.map((rel, i) => {
|
|
1526
|
+
const fromId = entry.entityPath[i];
|
|
1527
|
+
return {
|
|
1528
|
+
id: rel.id,
|
|
1529
|
+
type: rel.relationshipType,
|
|
1530
|
+
sourceEntityId: rel.sourceEntityId,
|
|
1531
|
+
targetEntityId: rel.targetEntityId,
|
|
1532
|
+
direction: fromId === rel.sourceEntityId ? "outbound" : "inbound",
|
|
1533
|
+
properties: rel.properties
|
|
1534
|
+
};
|
|
1535
|
+
})
|
|
1489
1536
|
}));
|
|
1490
1537
|
}
|
|
1491
1538
|
const executionTimeMs = Date.now() - startTime;
|
|
1539
|
+
const returned = spec.returnMode === "all" ? total : paged.length;
|
|
1540
|
+
const hasMore = spec.returnMode === "all" ? offset + limit < unionFullLength : offset + limit < total;
|
|
1541
|
+
const truncated = spec.returnMode === "all" ? unionFullLength > limit + offset : total > limit + offset;
|
|
1492
1542
|
return {
|
|
1493
1543
|
entities,
|
|
1494
1544
|
relationships,
|
|
1495
1545
|
paths,
|
|
1496
1546
|
aggregations,
|
|
1497
1547
|
total,
|
|
1498
|
-
returned
|
|
1499
|
-
hasMore
|
|
1548
|
+
returned,
|
|
1549
|
+
hasMore,
|
|
1500
1550
|
queryMetadata: {
|
|
1501
1551
|
executionTimeMs,
|
|
1502
1552
|
appliedLimits: {
|
|
1503
1553
|
maxResults: limit
|
|
1504
1554
|
},
|
|
1505
|
-
truncated
|
|
1506
|
-
truncationReason:
|
|
1555
|
+
truncated,
|
|
1556
|
+
truncationReason: truncated ? "result_limit" : void 0
|
|
1507
1557
|
}
|
|
1508
1558
|
};
|
|
1509
1559
|
}
|
|
@@ -1619,6 +1669,58 @@ function getTargetId(rel, currentEntityId) {
|
|
|
1619
1669
|
}
|
|
1620
1670
|
return rel.sourceEntityId;
|
|
1621
1671
|
}
|
|
1672
|
+
function dedupEntriesById(entries) {
|
|
1673
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1674
|
+
const result = [];
|
|
1675
|
+
for (const entry of entries) {
|
|
1676
|
+
if (!seen.has(entry.entity.id)) {
|
|
1677
|
+
seen.add(entry.entity.id);
|
|
1678
|
+
result.push(entry);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
return result;
|
|
1682
|
+
}
|
|
1683
|
+
function buildAllModeUnion(entries) {
|
|
1684
|
+
if (entries.length === 0) return [];
|
|
1685
|
+
let maxDepth = 0;
|
|
1686
|
+
const byDepth = /* @__PURE__ */ new Map();
|
|
1687
|
+
for (const entry of entries) {
|
|
1688
|
+
const depth = entry.relationshipPath.length;
|
|
1689
|
+
if (depth > maxDepth) maxDepth = depth;
|
|
1690
|
+
let bucket = byDepth.get(depth);
|
|
1691
|
+
if (!bucket) {
|
|
1692
|
+
bucket = [];
|
|
1693
|
+
byDepth.set(depth, bucket);
|
|
1694
|
+
}
|
|
1695
|
+
bucket.push(entry);
|
|
1696
|
+
}
|
|
1697
|
+
const seenEntities = /* @__PURE__ */ new Set();
|
|
1698
|
+
const seenRels = /* @__PURE__ */ new Set();
|
|
1699
|
+
const result = [];
|
|
1700
|
+
for (const entry of byDepth.get(0) ?? []) {
|
|
1701
|
+
if (!seenEntities.has(entry.entity.id)) {
|
|
1702
|
+
seenEntities.add(entry.entity.id);
|
|
1703
|
+
result.push({ kind: "entity", entry });
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
for (let depth = 1; depth <= maxDepth; depth++) {
|
|
1707
|
+
const bucket = byDepth.get(depth) ?? [];
|
|
1708
|
+
for (const entry of bucket) {
|
|
1709
|
+
const newRel = entry.relationshipPath[depth - 1];
|
|
1710
|
+
if (newRel && !seenRels.has(newRel.id)) {
|
|
1711
|
+
seenRels.add(newRel.id);
|
|
1712
|
+
result.push({ kind: "relationship", rel: newRel });
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
for (const entry of bucket) {
|
|
1716
|
+
if (!seenEntities.has(entry.entity.id)) {
|
|
1717
|
+
seenEntities.add(entry.entity.id);
|
|
1718
|
+
result.push({ kind: "entity", entry });
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
return result;
|
|
1723
|
+
}
|
|
1622
1724
|
|
|
1623
1725
|
// src/relationships/GraphTraversal.ts
|
|
1624
1726
|
var GraphTraversal = class {
|
|
@@ -1879,11 +1981,15 @@ var SearchOrchestrator = class {
|
|
|
1879
1981
|
const offset = options?.offset ?? 0;
|
|
1880
1982
|
const threshold = options?.similarityThreshold ?? this.defaultSimilarityThreshold;
|
|
1881
1983
|
const queryEmbedding = await this.embedding.embed(query);
|
|
1882
|
-
const allEntities = await this.storage.findEntities(
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1984
|
+
const allEntities = await this.storage.findEntities(
|
|
1985
|
+
this.repositoryId,
|
|
1986
|
+
{
|
|
1987
|
+
entityTypes: options?.entityTypes,
|
|
1988
|
+
limit: this.conceptSearchScanLimit,
|
|
1989
|
+
offset: 0
|
|
1990
|
+
},
|
|
1991
|
+
{ loadEmbeddings: true }
|
|
1992
|
+
);
|
|
1887
1993
|
const scored = [];
|
|
1888
1994
|
for (const entity of allEntities.items) {
|
|
1889
1995
|
let score;
|
|
@@ -3266,7 +3372,14 @@ var VocabularyEngine = class {
|
|
|
3266
3372
|
async proposeExtension(proposal, proposedBy) {
|
|
3267
3373
|
return this.proposeChange(proposal, proposedBy);
|
|
3268
3374
|
}
|
|
3269
|
-
/**
|
|
3375
|
+
/**
|
|
3376
|
+
* Cascade-delete all data for a deleted vocabulary type.
|
|
3377
|
+
*
|
|
3378
|
+
* `deletedRelationships` may be `undefined` when the underlying provider
|
|
3379
|
+
* does not count cascaded edges (see StorageProvider.deleteEntitiesByType).
|
|
3380
|
+
* The return value is currently discarded by the only caller; the type is
|
|
3381
|
+
* preserved for symmetry with the storage contract.
|
|
3382
|
+
*/
|
|
3270
3383
|
async cascadeDeleteData(proposal) {
|
|
3271
3384
|
if (proposal.proposalType === "delete_entity_type" && proposal.deleteEntityType) {
|
|
3272
3385
|
return this.storage.deleteEntitiesByType(
|
|
@@ -3464,7 +3577,7 @@ var EventBus = class {
|
|
|
3464
3577
|
};
|
|
3465
3578
|
|
|
3466
3579
|
// src/portability/RepositoryExporter.ts
|
|
3467
|
-
var LIBRARY_VERSION = true ? "0.
|
|
3580
|
+
var LIBRARY_VERSION = true ? "0.17.0" : "0.1.0";
|
|
3468
3581
|
var RepositoryExporter = class {
|
|
3469
3582
|
storage;
|
|
3470
3583
|
provenance;
|
|
@@ -4567,10 +4680,15 @@ var DeepMemory = class {
|
|
|
4567
4680
|
try {
|
|
4568
4681
|
const result = await repo.reembedAll({
|
|
4569
4682
|
...options,
|
|
4683
|
+
// The repo signature widens `totalEntities` to `number | undefined`
|
|
4684
|
+
// because PaginatedResult.total may be undefined under some provider/
|
|
4685
|
+
// query combinations. The `reembed:progress` event contract is
|
|
4686
|
+
// `totalEntities: number`, so fall back to the cached stats count
|
|
4687
|
+
// when the inner layer doesn't supply one.
|
|
4570
4688
|
onProgress: (progress) => this.globalEventBus.emit("reembed:progress", {
|
|
4571
4689
|
repositoryId,
|
|
4572
4690
|
processed: progress.processed,
|
|
4573
|
-
totalEntities: progress.totalEntities,
|
|
4691
|
+
totalEntities: progress.totalEntities ?? stats.entityCount,
|
|
4574
4692
|
failed: progress.failed
|
|
4575
4693
|
}),
|
|
4576
4694
|
onItemFailed: (failure) => this.globalEventBus.emit("reembed:item-failed", {
|
|
@@ -4629,6 +4747,69 @@ function createSafeSink(sink) {
|
|
|
4629
4747
|
|
|
4630
4748
|
// src/relationships/compilers/GremlinCompiler.ts
|
|
4631
4749
|
var DEFAULT_ESTIMATED_FANOUT_PER_HOP = 10;
|
|
4750
|
+
var VERTEX_PROJECTION = [
|
|
4751
|
+
["__kind", `.by(constant('v'))`],
|
|
4752
|
+
["id", `.by(id)`],
|
|
4753
|
+
["entityType", `.by('entityType')`],
|
|
4754
|
+
["entityLabel", `.by('entityLabel')`],
|
|
4755
|
+
["slug", `.by('slug')`],
|
|
4756
|
+
["summary", `.by(coalesce(values('summary'), constant('')))`],
|
|
4757
|
+
["properties", `.by(coalesce(values('properties'), constant('{}')))`],
|
|
4758
|
+
["data", `.by(coalesce(values('data'), constant('')))`],
|
|
4759
|
+
["dataFormat", `.by(coalesce(values('dataFormat'), constant('')))`],
|
|
4760
|
+
["createdBy", `.by('createdBy')`],
|
|
4761
|
+
["createdByType", `.by('createdByType')`],
|
|
4762
|
+
["createdAt", `.by('createdAt')`],
|
|
4763
|
+
["createdInConversation", `.by(coalesce(values('createdInConversation'), constant('')))`],
|
|
4764
|
+
["createdFromMessage", `.by(coalesce(values('createdFromMessage'), constant('')))`],
|
|
4765
|
+
["modifiedBy", `.by('modifiedBy')`],
|
|
4766
|
+
["modifiedByType", `.by('modifiedByType')`],
|
|
4767
|
+
["modifiedAt", `.by('modifiedAt')`],
|
|
4768
|
+
["modifiedInConversation", `.by(coalesce(values('modifiedInConversation'), constant('')))`],
|
|
4769
|
+
["modifiedFromMessage", `.by(coalesce(values('modifiedFromMessage'), constant('')))`]
|
|
4770
|
+
];
|
|
4771
|
+
var EDGE_PROJECTION = [
|
|
4772
|
+
["__kind", `.by(constant('e'))`],
|
|
4773
|
+
["id", `.by(id)`],
|
|
4774
|
+
["relationshipType", `.by('relationshipType')`],
|
|
4775
|
+
["sourceEntityId", `.by('sourceEntityId')`],
|
|
4776
|
+
["targetEntityId", `.by('targetEntityId')`],
|
|
4777
|
+
["properties", `.by(coalesce(values('properties'), constant('{}')))`],
|
|
4778
|
+
["bidirectional", `.by(coalesce(values('bidirectional'), constant(false)))`],
|
|
4779
|
+
["createdBy", `.by('createdBy')`],
|
|
4780
|
+
["createdByType", `.by('createdByType')`],
|
|
4781
|
+
["createdAt", `.by('createdAt')`],
|
|
4782
|
+
["createdInConversation", `.by(coalesce(values('createdInConversation'), constant('')))`],
|
|
4783
|
+
["createdFromMessage", `.by(coalesce(values('createdFromMessage'), constant('')))`],
|
|
4784
|
+
["modifiedBy", `.by('modifiedBy')`],
|
|
4785
|
+
["modifiedByType", `.by('modifiedByType')`],
|
|
4786
|
+
["modifiedAt", `.by('modifiedAt')`],
|
|
4787
|
+
["modifiedInConversation", `.by(coalesce(values('modifiedInConversation'), constant('')))`],
|
|
4788
|
+
["modifiedFromMessage", `.by(coalesce(values('modifiedFromMessage'), constant('')))`]
|
|
4789
|
+
];
|
|
4790
|
+
var EMBEDDING_PROJECTION_ENTRY = [
|
|
4791
|
+
"embedding",
|
|
4792
|
+
`.by(coalesce(values('embedding'), constant('')))`
|
|
4793
|
+
];
|
|
4794
|
+
function buildProjectExpression(entries) {
|
|
4795
|
+
const keys = entries.map(([k]) => `'${k}'`).join(",");
|
|
4796
|
+
const bys = entries.map(([, by]) => by).join("");
|
|
4797
|
+
return `project(${keys})${bys}`;
|
|
4798
|
+
}
|
|
4799
|
+
var VERTEX_PROJECT_EXPR = buildProjectExpression(VERTEX_PROJECTION);
|
|
4800
|
+
var VERTEX_PROJECT_EXPR_WITH_EMBEDDING = buildProjectExpression([
|
|
4801
|
+
...VERTEX_PROJECTION,
|
|
4802
|
+
EMBEDDING_PROJECTION_ENTRY
|
|
4803
|
+
]);
|
|
4804
|
+
var EDGE_PROJECT_EXPR = buildProjectExpression(EDGE_PROJECTION);
|
|
4805
|
+
var GREMLIN_VERTEX_PROJECTION_FIELDS = VERTEX_PROJECTION.map(([k]) => k).filter((k) => k !== "__kind");
|
|
4806
|
+
var GREMLIN_EDGE_PROJECTION_FIELDS = EDGE_PROJECTION.map(([k]) => k).filter((k) => k !== "__kind");
|
|
4807
|
+
function buildVertexProjectChain(opts) {
|
|
4808
|
+
return opts?.withEmbedding ? VERTEX_PROJECT_EXPR_WITH_EMBEDDING : VERTEX_PROJECT_EXPR;
|
|
4809
|
+
}
|
|
4810
|
+
function buildEdgeProjectChain() {
|
|
4811
|
+
return EDGE_PROJECT_EXPR;
|
|
4812
|
+
}
|
|
4632
4813
|
var GremlinCompiler = class {
|
|
4633
4814
|
language = "gremlin";
|
|
4634
4815
|
compile(spec, _vocabulary) {
|
|
@@ -4644,7 +4825,7 @@ var GremlinCompiler = class {
|
|
|
4644
4825
|
parts.push("g.V()");
|
|
4645
4826
|
if (spec.start.entityId) {
|
|
4646
4827
|
const p = nextParam(spec.start.entityId);
|
|
4647
|
-
parts.push(`.
|
|
4828
|
+
parts.push(`.hasId(${p})`);
|
|
4648
4829
|
} else if (spec.start.entityType) {
|
|
4649
4830
|
const p = nextParam(spec.start.entityType);
|
|
4650
4831
|
parts.push(`.has('entityType', ${p})`);
|
|
@@ -4656,44 +4837,79 @@ var GremlinCompiler = class {
|
|
|
4656
4837
|
}
|
|
4657
4838
|
}
|
|
4658
4839
|
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;
|
|
4840
|
+
const returnMode = spec.returnMode ?? "terminal";
|
|
4841
|
+
if (returnMode === "all") {
|
|
4842
|
+
if (steps.some((s) => s.repeat)) {
|
|
4843
|
+
throw new Error(
|
|
4844
|
+
"GremlinCompiler: 'all' returnMode does not support repeat steps. Use 'terminal' or 'path' mode, or unroll the repeat into explicit steps."
|
|
4845
|
+
);
|
|
4669
4846
|
}
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4847
|
+
const compiledSteps = steps.map((step) => ({
|
|
4848
|
+
edge: compileEdgeOnly(step, nextParam),
|
|
4849
|
+
vertex: compileVertexHop(step),
|
|
4850
|
+
// Per plan §3: entity-type/property filters apply only on branches
|
|
4851
|
+
// ending at that depth's vertex. They are NOT included in the prefix
|
|
4852
|
+
// that deeper branches traverse through.
|
|
4853
|
+
entityFilters: compileEntityFilters(step, nextParam)
|
|
4854
|
+
}));
|
|
4855
|
+
const branches = [`__.identity().${VERTEX_PROJECT_EXPR}`];
|
|
4856
|
+
let prefix = "";
|
|
4857
|
+
for (const { edge, vertex, entityFilters } of compiledSteps) {
|
|
4858
|
+
branches.push(`__${prefix}${edge}.${EDGE_PROJECT_EXPR}`);
|
|
4859
|
+
branches.push(`__${prefix}${edge}${vertex}${entityFilters}.${VERTEX_PROJECT_EXPR}`);
|
|
4860
|
+
prefix = `${prefix}${edge}${vertex}`;
|
|
4861
|
+
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4673
4862
|
}
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4863
|
+
parts.push(`.union(${branches.join(", ")})`);
|
|
4864
|
+
parts.push(`.dedup().by(select('id'))`);
|
|
4865
|
+
const limit = spec.limit ?? 50;
|
|
4866
|
+
const offset = spec.offset ?? 0;
|
|
4867
|
+
const pOffset = nextParam(offset);
|
|
4868
|
+
const pEnd = nextParam(offset + limit);
|
|
4869
|
+
parts.push(`.range(${pOffset}, ${pEnd})`);
|
|
4870
|
+
params["_limit"] = limit;
|
|
4871
|
+
params["_offset"] = offset;
|
|
4872
|
+
} else {
|
|
4873
|
+
const useEdgeEmission = returnMode === "path";
|
|
4874
|
+
for (const step of steps) {
|
|
4875
|
+
if (step.repeat) {
|
|
4876
|
+
parts.push(compileRepeatStep(step, nextParam, useEdgeEmission));
|
|
4877
|
+
estimatedFanOut *= step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4878
|
+
} else if (useEdgeEmission || step.relationshipFilter && step.relationshipFilter.length > 0) {
|
|
4879
|
+
parts.push(compileEdgeStep(step, nextParam));
|
|
4880
|
+
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4881
|
+
} else {
|
|
4882
|
+
parts.push(compileSimpleStep(step, nextParam));
|
|
4883
|
+
estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
|
|
4884
|
+
}
|
|
4885
|
+
if (step.entityTypes && step.entityTypes.length > 0) {
|
|
4886
|
+
const typeParams = step.entityTypes.map((t) => nextParam(t));
|
|
4887
|
+
parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
|
|
4888
|
+
}
|
|
4889
|
+
if (step.entityFilter) {
|
|
4890
|
+
for (const f of step.entityFilter) {
|
|
4891
|
+
parts.push(compilePropertyFilter(f, nextParam));
|
|
4892
|
+
}
|
|
4677
4893
|
}
|
|
4678
4894
|
}
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4895
|
+
if (returnMode === "terminal" && spec.dedup !== false) {
|
|
4896
|
+
parts.push(".dedup()");
|
|
4897
|
+
}
|
|
4898
|
+
if (returnMode === "path") {
|
|
4899
|
+
parts.push(".simplePath()");
|
|
4900
|
+
}
|
|
4901
|
+
const limit = spec.limit ?? 50;
|
|
4902
|
+
const offset = spec.offset ?? 0;
|
|
4903
|
+
const pOffset = nextParam(offset);
|
|
4904
|
+
const pEnd = nextParam(offset + limit);
|
|
4905
|
+
parts.push(`.range(${pOffset}, ${pEnd})`);
|
|
4906
|
+
params["_limit"] = limit;
|
|
4907
|
+
params["_offset"] = offset;
|
|
4908
|
+
if (returnMode === "terminal") {
|
|
4909
|
+
parts.push(`.${VERTEX_PROJECT_EXPR}`);
|
|
4910
|
+
} else {
|
|
4911
|
+
parts.push(`.path().by(${VERTEX_PROJECT_EXPR}).by(${EDGE_PROJECT_EXPR})`);
|
|
4912
|
+
}
|
|
4697
4913
|
}
|
|
4698
4914
|
return {
|
|
4699
4915
|
query: parts.join(""),
|
|
@@ -4714,7 +4930,7 @@ function compileSimpleStep(step, nextParam) {
|
|
|
4714
4930
|
return types ? `.both(${typeArgs})` : ".both()";
|
|
4715
4931
|
}
|
|
4716
4932
|
}
|
|
4717
|
-
function
|
|
4933
|
+
function compileEdgeOnly(step, nextParam) {
|
|
4718
4934
|
const parts = [];
|
|
4719
4935
|
const types = step.relationshipTypes;
|
|
4720
4936
|
const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
|
|
@@ -4734,22 +4950,37 @@ function compileEdgeStep(step, nextParam) {
|
|
|
4734
4950
|
parts.push(compilePropertyFilter(f, nextParam));
|
|
4735
4951
|
}
|
|
4736
4952
|
}
|
|
4953
|
+
return parts.join("");
|
|
4954
|
+
}
|
|
4955
|
+
function compileVertexHop(step) {
|
|
4737
4956
|
switch (step.direction) {
|
|
4738
4957
|
case "out":
|
|
4739
|
-
|
|
4740
|
-
break;
|
|
4958
|
+
return ".inV()";
|
|
4741
4959
|
case "in":
|
|
4742
|
-
|
|
4743
|
-
break;
|
|
4960
|
+
return ".outV()";
|
|
4744
4961
|
case "both":
|
|
4745
|
-
|
|
4746
|
-
|
|
4962
|
+
return ".otherV()";
|
|
4963
|
+
}
|
|
4964
|
+
}
|
|
4965
|
+
function compileEntityFilters(step, nextParam) {
|
|
4966
|
+
const parts = [];
|
|
4967
|
+
if (step.entityTypes && step.entityTypes.length > 0) {
|
|
4968
|
+
const typeParams = step.entityTypes.map((t) => nextParam(t));
|
|
4969
|
+
parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
|
|
4970
|
+
}
|
|
4971
|
+
if (step.entityFilter) {
|
|
4972
|
+
for (const f of step.entityFilter) {
|
|
4973
|
+
parts.push(compilePropertyFilter(f, nextParam));
|
|
4974
|
+
}
|
|
4747
4975
|
}
|
|
4748
4976
|
return parts.join("");
|
|
4749
4977
|
}
|
|
4750
|
-
function
|
|
4978
|
+
function compileEdgeStep(step, nextParam) {
|
|
4979
|
+
return compileEdgeOnly(step, nextParam) + compileVertexHop(step);
|
|
4980
|
+
}
|
|
4981
|
+
function compileRepeatStep(step, nextParam, useEdgeEmission) {
|
|
4751
4982
|
const parts = [];
|
|
4752
|
-
const innerStep = step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
|
|
4983
|
+
const innerStep = useEdgeEmission || step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
|
|
4753
4984
|
if (step.repeat?.emitIntermediates !== false) {
|
|
4754
4985
|
parts.push(".emit()");
|
|
4755
4986
|
}
|
|
@@ -4758,10 +4989,13 @@ function compileRepeatStep(step, nextParam) {
|
|
|
4758
4989
|
const untilParts = step.repeat.until.map((f) => compilePropertyFilter(f, nextParam));
|
|
4759
4990
|
parts.push(`.until(${untilParts.join("")})`);
|
|
4760
4991
|
}
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4992
|
+
const n = step.repeat.maxDepth;
|
|
4993
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
4994
|
+
throw new Error(
|
|
4995
|
+
`GremlinCompiler: repeat.maxDepth must be a positive integer; got ${n}`
|
|
4996
|
+
);
|
|
4764
4997
|
}
|
|
4998
|
+
parts.push(`.times(${n})`);
|
|
4765
4999
|
if (step.repeat?.emitIntermediates === false) {
|
|
4766
5000
|
parts.push(".emit()");
|
|
4767
5001
|
}
|
|
@@ -5080,17 +5314,20 @@ var InMemoryStorageProvider = class {
|
|
|
5080
5314
|
store.slugIndex.set(entity.slug, entity.id);
|
|
5081
5315
|
return entity;
|
|
5082
5316
|
}
|
|
5083
|
-
|
|
5317
|
+
// The in-memory provider always carries the full entity (embedding and all).
|
|
5318
|
+
// The `loadEmbeddings` option is accepted for interface symmetry but ignored —
|
|
5319
|
+
// there is no light/full split to switch between when entities live in a Map.
|
|
5320
|
+
async getEntity(repositoryId, entityId, _options) {
|
|
5084
5321
|
const store = this.getStore(repositoryId);
|
|
5085
5322
|
return store.entities.get(entityId) ?? null;
|
|
5086
5323
|
}
|
|
5087
|
-
async getEntityBySlug(repositoryId, slug) {
|
|
5324
|
+
async getEntityBySlug(repositoryId, slug, _options) {
|
|
5088
5325
|
const store = this.getStore(repositoryId);
|
|
5089
5326
|
const id = store.slugIndex.get(slug);
|
|
5090
5327
|
if (!id) return null;
|
|
5091
5328
|
return store.entities.get(id) ?? null;
|
|
5092
5329
|
}
|
|
5093
|
-
async getEntities(repositoryId, entityIds) {
|
|
5330
|
+
async getEntities(repositoryId, entityIds, _options) {
|
|
5094
5331
|
const store = this.getStore(repositoryId);
|
|
5095
5332
|
const result = /* @__PURE__ */ new Map();
|
|
5096
5333
|
for (const id of entityIds) {
|
|
@@ -5161,7 +5398,7 @@ var InMemoryStorageProvider = class {
|
|
|
5161
5398
|
}
|
|
5162
5399
|
return { deletedEntities: entityIds.size, deletedRelationships };
|
|
5163
5400
|
}
|
|
5164
|
-
async findEntities(repositoryId, query) {
|
|
5401
|
+
async findEntities(repositoryId, query, _options) {
|
|
5165
5402
|
const store = this.getStore(repositoryId);
|
|
5166
5403
|
let matches = Array.from(store.entities.values());
|
|
5167
5404
|
if (query.entityTypes && query.entityTypes.length > 0) {
|
|
@@ -5683,6 +5920,8 @@ export {
|
|
|
5683
5920
|
EmbeddingProviderRequiredError,
|
|
5684
5921
|
EntityNotFoundError,
|
|
5685
5922
|
ExportError,
|
|
5923
|
+
GREMLIN_EDGE_PROJECTION_FIELDS,
|
|
5924
|
+
GREMLIN_VERTEX_PROJECTION_FIELDS,
|
|
5686
5925
|
GovernanceDeniedError,
|
|
5687
5926
|
GraphTraversalProviderRequiredError,
|
|
5688
5927
|
GremlinCompiler,
|
|
@@ -5704,7 +5943,10 @@ export {
|
|
|
5704
5943
|
TraversalTimeoutError,
|
|
5705
5944
|
TraversalValidationError,
|
|
5706
5945
|
TraversalVocabularyError,
|
|
5946
|
+
UnsupportedQueryError,
|
|
5707
5947
|
VocabularyValidationError,
|
|
5948
|
+
buildEdgeProjectChain,
|
|
5949
|
+
buildVertexProjectChain,
|
|
5708
5950
|
createSafeSink,
|
|
5709
5951
|
generateId,
|
|
5710
5952
|
isValidUuid,
|