@utaba/deep-memory 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -49,7 +49,8 @@ __export(src_exports, {
49
49
  VocabularyValidationError: () => VocabularyValidationError,
50
50
  generateId: () => generateId,
51
51
  isValidUuid: () => isValidUuid,
52
- matchesPropertyFilters: () => matchesPropertyFilters
52
+ matchesPropertyFilters: () => matchesPropertyFilters,
53
+ projectEntity: () => projectEntity
53
54
  });
54
55
  module.exports = __toCommonJS(src_exports);
55
56
 
@@ -956,310 +957,6 @@ function validateTraversalSpec(spec, vocabulary, capabilities) {
956
957
  };
957
958
  }
958
959
 
959
- // src/relationships/compilers/GremlinCompiler.ts
960
- var DEFAULT_ESTIMATED_FANOUT_PER_HOP = 10;
961
- var GremlinCompiler = class {
962
- language = "gremlin";
963
- compile(spec, _vocabulary) {
964
- const parts = [];
965
- const params = {};
966
- let paramIndex = 0;
967
- let estimatedFanOut = 1;
968
- const nextParam = (value) => {
969
- const name = `p${paramIndex++}`;
970
- params[name] = value;
971
- return name;
972
- };
973
- parts.push("g.V()");
974
- if (spec.start.entityId) {
975
- const p = nextParam(spec.start.entityId);
976
- parts.push(`.has('id', ${p})`);
977
- } else if (spec.start.entityType) {
978
- const p = nextParam(spec.start.entityType);
979
- parts.push(`.has('entityType', ${p})`);
980
- estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
981
- }
982
- if (spec.start.filter) {
983
- for (const f of spec.start.filter) {
984
- parts.push(compilePropertyFilter(f, nextParam));
985
- }
986
- }
987
- const steps = spec.steps ?? [];
988
- for (const step of steps) {
989
- if (step.repeat) {
990
- parts.push(compileRepeatStep(step, nextParam));
991
- estimatedFanOut *= step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP;
992
- } else if (step.relationshipFilter && step.relationshipFilter.length > 0) {
993
- parts.push(compileEdgeStep(step, nextParam));
994
- estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
995
- } else {
996
- parts.push(compileSimpleStep(step, nextParam));
997
- estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
998
- }
999
- if (step.entityTypes && step.entityTypes.length > 0) {
1000
- const typeParams = step.entityTypes.map((t) => nextParam(t));
1001
- parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
1002
- }
1003
- if (step.entityFilter) {
1004
- for (const f of step.entityFilter) {
1005
- parts.push(compilePropertyFilter(f, nextParam));
1006
- }
1007
- }
1008
- }
1009
- if (spec.returnMode === "all") {
1010
- }
1011
- if (spec.dedup !== false) {
1012
- parts.push(".dedup()");
1013
- }
1014
- const limit = spec.limit ?? 50;
1015
- const offset = spec.offset ?? 0;
1016
- const pOffset = nextParam(offset);
1017
- const pEnd = nextParam(offset + limit);
1018
- parts.push(`.range(${pOffset}, ${pEnd})`);
1019
- params["_limit"] = limit;
1020
- params["_offset"] = offset;
1021
- if (spec.returnMode === "path") {
1022
- parts.push(".path()");
1023
- }
1024
- if (spec.returnMode !== "path") {
1025
- parts.push(".valueMap(true)");
1026
- }
1027
- return {
1028
- query: parts.join(""),
1029
- params,
1030
- estimatedFanOut: Math.min(estimatedFanOut, 1e4)
1031
- };
1032
- }
1033
- };
1034
- function compileSimpleStep(step, nextParam) {
1035
- const types = step.relationshipTypes;
1036
- const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
1037
- switch (step.direction) {
1038
- case "out":
1039
- return types ? `.out(${typeArgs})` : ".out()";
1040
- case "in":
1041
- return types ? `.in(${typeArgs})` : ".in()";
1042
- case "both":
1043
- return types ? `.both(${typeArgs})` : ".both()";
1044
- }
1045
- }
1046
- function compileEdgeStep(step, nextParam) {
1047
- const parts = [];
1048
- const types = step.relationshipTypes;
1049
- const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
1050
- switch (step.direction) {
1051
- case "out":
1052
- parts.push(types ? `.outE(${typeArgs})` : ".outE()");
1053
- break;
1054
- case "in":
1055
- parts.push(types ? `.inE(${typeArgs})` : ".inE()");
1056
- break;
1057
- case "both":
1058
- parts.push(types ? `.bothE(${typeArgs})` : ".bothE()");
1059
- break;
1060
- }
1061
- if (step.relationshipFilter) {
1062
- for (const f of step.relationshipFilter) {
1063
- parts.push(compilePropertyFilter(f, nextParam));
1064
- }
1065
- }
1066
- switch (step.direction) {
1067
- case "out":
1068
- parts.push(".inV()");
1069
- break;
1070
- case "in":
1071
- parts.push(".outV()");
1072
- break;
1073
- case "both":
1074
- parts.push(".otherV()");
1075
- break;
1076
- }
1077
- return parts.join("");
1078
- }
1079
- function compileRepeatStep(step, nextParam) {
1080
- const parts = [];
1081
- const innerStep = step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
1082
- if (step.repeat?.emitIntermediates !== false) {
1083
- parts.push(".emit()");
1084
- }
1085
- parts.push(`.repeat(${innerStep.startsWith(".") ? `__${innerStep}` : innerStep})`);
1086
- if (step.repeat?.until && step.repeat.until.length > 0) {
1087
- const untilParts = step.repeat.until.map((f) => compilePropertyFilter(f, nextParam));
1088
- parts.push(`.until(${untilParts.join("")})`);
1089
- }
1090
- if (step.repeat?.maxDepth) {
1091
- const p = nextParam(step.repeat.maxDepth);
1092
- parts.push(`.times(${p})`);
1093
- }
1094
- if (step.repeat?.emitIntermediates === false) {
1095
- parts.push(".emit()");
1096
- }
1097
- return parts.join("");
1098
- }
1099
- function compilePropertyFilter(filter, nextParam) {
1100
- const key = nextParam(filter.key);
1101
- switch (filter.operator) {
1102
- case "eq": {
1103
- const val = nextParam(filter.value);
1104
- return `.has(${key}, ${val})`;
1105
- }
1106
- case "neq": {
1107
- const val = nextParam(filter.value);
1108
- return `.has(${key}, neq(${val}))`;
1109
- }
1110
- case "gt": {
1111
- const val = nextParam(filter.value);
1112
- return `.has(${key}, gt(${val}))`;
1113
- }
1114
- case "gte": {
1115
- const val = nextParam(filter.value);
1116
- return `.has(${key}, gte(${val}))`;
1117
- }
1118
- case "lt": {
1119
- const val = nextParam(filter.value);
1120
- return `.has(${key}, lt(${val}))`;
1121
- }
1122
- case "lte": {
1123
- const val = nextParam(filter.value);
1124
- return `.has(${key}, lte(${val}))`;
1125
- }
1126
- case "contains": {
1127
- const val = nextParam(filter.value);
1128
- return `.has(${key}, containing(${val}))`;
1129
- }
1130
- case "isNull":
1131
- return `.hasNot(${key})`;
1132
- case "isNotNull":
1133
- return `.has(${key})`;
1134
- }
1135
- }
1136
-
1137
- // src/relationships/compilers/CypherCompiler.ts
1138
- var DEFAULT_ESTIMATED_FANOUT_PER_HOP2 = 10;
1139
- var CypherCompiler = class {
1140
- language = "cypher";
1141
- compile(spec, _vocabulary) {
1142
- const params = {};
1143
- let paramIndex = 0;
1144
- let estimatedFanOut = 1;
1145
- const whereClauses = [];
1146
- let nodeIndex = 0;
1147
- const nextParam = (value) => {
1148
- const name = `p${paramIndex++}`;
1149
- params[name] = value;
1150
- return `$${name}`;
1151
- };
1152
- const startNode = `n${nodeIndex++}`;
1153
- let matchParts = [];
1154
- if (spec.start.entityId) {
1155
- matchParts.push(`(${startNode})`);
1156
- whereClauses.push(`${startNode}.id = ${nextParam(spec.start.entityId)}`);
1157
- } else if (spec.start.entityType) {
1158
- matchParts.push(`(${startNode})`);
1159
- whereClauses.push(`${startNode}.entityType = ${nextParam(spec.start.entityType)}`);
1160
- estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
1161
- } else {
1162
- matchParts.push(`(${startNode})`);
1163
- }
1164
- if (spec.start.filter) {
1165
- for (const f of spec.start.filter) {
1166
- whereClauses.push(compilePropertyFilterCypher(startNode, f, nextParam));
1167
- }
1168
- }
1169
- let lastNode = startNode;
1170
- const steps = spec.steps ?? [];
1171
- for (let i = 0; i < steps.length; i++) {
1172
- const step = steps[i];
1173
- const targetNode = `n${nodeIndex++}`;
1174
- const relAlias = `r${i}`;
1175
- const relTypes = step.relationshipTypes?.length ? step.relationshipTypes.join("|") : "";
1176
- const relTypePattern = relTypes ? `:${relTypes}` : "";
1177
- const depthPattern = step.repeat ? `*1..${step.repeat.maxDepth}` : "";
1178
- let pattern;
1179
- switch (step.direction) {
1180
- case "out":
1181
- pattern = `-[${relAlias}${relTypePattern}${depthPattern}]->(${targetNode})`;
1182
- break;
1183
- case "in":
1184
- pattern = `<-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
1185
- break;
1186
- case "both":
1187
- pattern = `-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
1188
- break;
1189
- }
1190
- matchParts.push(pattern);
1191
- estimatedFanOut *= step.repeat ? step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP2 : DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
1192
- if (step.entityTypes && step.entityTypes.length > 0) {
1193
- const typeParam = nextParam(step.entityTypes);
1194
- whereClauses.push(`${targetNode}.entityType IN ${typeParam}`);
1195
- }
1196
- if (step.entityFilter) {
1197
- for (const f of step.entityFilter) {
1198
- whereClauses.push(compilePropertyFilterCypher(targetNode, f, nextParam));
1199
- }
1200
- }
1201
- if (step.relationshipFilter) {
1202
- for (const f of step.relationshipFilter) {
1203
- whereClauses.push(compilePropertyFilterCypher(relAlias, f, nextParam));
1204
- }
1205
- }
1206
- lastNode = targetNode;
1207
- }
1208
- const matchClause = `MATCH ${matchParts[0]}${matchParts.slice(1).join("")}`;
1209
- const whereClause = whereClauses.length > 0 ? `
1210
- WHERE ${whereClauses.join(" AND ")}` : "";
1211
- let returnClause;
1212
- if (spec.returnMode === "path") {
1213
- const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
1214
- const allRels = steps.map((_, i) => `r${i}`);
1215
- returnClause = `RETURN ${[...allNodes, ...allRels].join(", ")}`;
1216
- } else if (spec.returnMode === "all") {
1217
- const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
1218
- returnClause = spec.dedup !== false ? `RETURN DISTINCT ${allNodes.join(", ")}` : `RETURN ${allNodes.join(", ")}`;
1219
- } else {
1220
- returnClause = spec.dedup !== false ? `RETURN DISTINCT ${lastNode}` : `RETURN ${lastNode}`;
1221
- }
1222
- const offset = spec.offset ?? 0;
1223
- const limit = spec.limit ?? 50;
1224
- const skipClause = offset > 0 ? `
1225
- SKIP ${nextParam(offset)}` : "";
1226
- const limitClause = `
1227
- LIMIT ${nextParam(limit)}`;
1228
- params["_limit"] = limit;
1229
- params["_offset"] = offset;
1230
- const query = `${matchClause}${whereClause}
1231
- ${returnClause}${skipClause}${limitClause}`;
1232
- return {
1233
- query,
1234
- params,
1235
- estimatedFanOut: Math.min(estimatedFanOut, 1e4)
1236
- };
1237
- }
1238
- };
1239
- function compilePropertyFilterCypher(nodeAlias, filter, nextParam) {
1240
- const prop = `${nodeAlias}.${filter.key}`;
1241
- switch (filter.operator) {
1242
- case "eq":
1243
- return `${prop} = ${nextParam(filter.value)}`;
1244
- case "neq":
1245
- return `${prop} <> ${nextParam(filter.value)}`;
1246
- case "gt":
1247
- return `${prop} > ${nextParam(filter.value)}`;
1248
- case "gte":
1249
- return `${prop} >= ${nextParam(filter.value)}`;
1250
- case "lt":
1251
- return `${prop} < ${nextParam(filter.value)}`;
1252
- case "lte":
1253
- return `${prop} <= ${nextParam(filter.value)}`;
1254
- case "contains":
1255
- return `${prop} CONTAINS ${nextParam(filter.value)}`;
1256
- case "isNull":
1257
- return `${prop} IS NULL`;
1258
- case "isNotNull":
1259
- return `${prop} IS NOT NULL`;
1260
- }
1261
- }
1262
-
1263
960
  // src/relationships/PropertyFilterMatcher.ts
1264
961
  function matchesPropertyFilters(properties, filters) {
1265
962
  return filters.every((filter) => matchesSingleFilter(properties, filter));
@@ -1792,8 +1489,9 @@ var GraphTraversal = class {
1792
1489
  }
1793
1490
  /**
1794
1491
  * Execute a structured traversal.
1795
- * Validates the spec, compiles to native query if a provider exists,
1796
- * falls back to application-level BFS otherwise.
1492
+ * Validates the spec, delegates to the GraphTraversalProvider if one is
1493
+ * registered (the provider owns native compilation), or falls back to
1494
+ * application-level BFS over StorageProvider.
1797
1495
  */
1798
1496
  async traverse(spec) {
1799
1497
  const capabilities = this.graphTraversalProvider?.getCapabilities();
@@ -1808,19 +1506,8 @@ var GraphTraversal = class {
1808
1506
  }
1809
1507
  throw new TraversalValidationError(structErrors.length > 0 ? structErrors : validation.errors);
1810
1508
  }
1811
- if (this.graphTraversalProvider && vocabulary) {
1812
- const language = capabilities.nativeQueryLanguage;
1813
- let compiledQuery;
1814
- if (language === "gremlin") {
1815
- const compiler = new GremlinCompiler();
1816
- const compiled = compiler.compile(spec, vocabulary);
1817
- compiledQuery = compiled.query;
1818
- } else if (language === "cypher") {
1819
- const compiler = new CypherCompiler();
1820
- const compiled = compiler.compile(spec, vocabulary);
1821
- compiledQuery = compiled.query;
1822
- }
1823
- return this.graphTraversalProvider.traverse(this.repositoryId, spec, compiledQuery);
1509
+ if (this.graphTraversalProvider) {
1510
+ return this.graphTraversalProvider.traverse(this.repositoryId, spec);
1824
1511
  }
1825
1512
  return executeFallbackTraversal(this.repositoryId, this.storage, spec);
1826
1513
  }
@@ -3407,7 +3094,7 @@ var EventBus = class {
3407
3094
  };
3408
3095
 
3409
3096
  // src/portability/RepositoryExporter.ts
3410
- var LIBRARY_VERSION = true ? "0.5.0" : "0.1.0";
3097
+ var LIBRARY_VERSION = true ? "0.6.0" : "0.1.0";
3411
3098
  var RepositoryExporter = class {
3412
3099
  storage;
3413
3100
  provenance;
@@ -4373,54 +4060,358 @@ var DeepMemory = class {
4373
4060
  relationshipCount
4374
4061
  });
4375
4062
  }
4376
- /**
4377
- * Import a repository from a stream of chunks.
4378
- * Use for large repositories to avoid loading everything into memory.
4379
- */
4380
- async importRepositoryStream(header, chunks, options) {
4381
- await this.ensureInitialized();
4382
- const importer = new RepositoryImporter({
4383
- storage: this.storage,
4384
- actorId: this.provenance.getContext().actorId,
4385
- onProgress: (progress) => this.globalEventBus.emit("import:progress", progress)
4386
- });
4387
- await this.globalEventBus.emit("import:started", { repositoryId: options.target.repositoryId });
4388
- const result = await importer.importStream(header, chunks, options);
4389
- if (result.success) {
4390
- await this.globalEventBus.emit("import:completed", {
4391
- repositoryId: result.repositoryId,
4392
- entitiesImported: result.statistics.entitiesImported,
4393
- relationshipsImported: result.statistics.relationshipsImported
4394
- });
4395
- } else {
4396
- await this.globalEventBus.emit("import:failed", {
4397
- repositoryId: result.repositoryId,
4398
- error: result.warnings.map((w) => w.message).join("; ")
4399
- });
4063
+ /**
4064
+ * Import a repository from a stream of chunks.
4065
+ * Use for large repositories to avoid loading everything into memory.
4066
+ */
4067
+ async importRepositoryStream(header, chunks, options) {
4068
+ await this.ensureInitialized();
4069
+ const importer = new RepositoryImporter({
4070
+ storage: this.storage,
4071
+ actorId: this.provenance.getContext().actorId,
4072
+ onProgress: (progress) => this.globalEventBus.emit("import:progress", progress)
4073
+ });
4074
+ await this.globalEventBus.emit("import:started", { repositoryId: options.target.repositoryId });
4075
+ const result = await importer.importStream(header, chunks, options);
4076
+ if (result.success) {
4077
+ await this.globalEventBus.emit("import:completed", {
4078
+ repositoryId: result.repositoryId,
4079
+ entitiesImported: result.statistics.entitiesImported,
4080
+ relationshipsImported: result.statistics.relationshipsImported
4081
+ });
4082
+ } else {
4083
+ await this.globalEventBus.emit("import:failed", {
4084
+ repositoryId: result.repositoryId,
4085
+ error: result.warnings.map((w) => w.message).join("; ")
4086
+ });
4087
+ }
4088
+ return result;
4089
+ }
4090
+ /** Subscribe to global events */
4091
+ on(event, handler) {
4092
+ return this.globalEventBus.on(event, handler);
4093
+ }
4094
+ /** Update the provenance context (e.g., new conversation) */
4095
+ updateProvenance(context) {
4096
+ this.provenance.updateContext(context);
4097
+ this.globalEventBus.updateProvenance(this.provenance.getContext());
4098
+ }
4099
+ /** Dispose of all resources */
4100
+ async dispose() {
4101
+ this.globalEventBus.removeAllListeners();
4102
+ if (this.graphTraversalProvider?.dispose) {
4103
+ await this.graphTraversalProvider.dispose();
4104
+ }
4105
+ if (this.storage.dispose) {
4106
+ await this.storage.dispose();
4107
+ }
4108
+ this.initialized = false;
4109
+ }
4110
+ };
4111
+
4112
+ // src/relationships/compilers/GremlinCompiler.ts
4113
+ var DEFAULT_ESTIMATED_FANOUT_PER_HOP = 10;
4114
+ var GremlinCompiler = class {
4115
+ language = "gremlin";
4116
+ compile(spec, _vocabulary) {
4117
+ const parts = [];
4118
+ const params = {};
4119
+ let paramIndex = 0;
4120
+ let estimatedFanOut = 1;
4121
+ const nextParam = (value) => {
4122
+ const name = `p${paramIndex++}`;
4123
+ params[name] = value;
4124
+ return name;
4125
+ };
4126
+ parts.push("g.V()");
4127
+ if (spec.start.entityId) {
4128
+ const p = nextParam(spec.start.entityId);
4129
+ parts.push(`.has('id', ${p})`);
4130
+ } else if (spec.start.entityType) {
4131
+ const p = nextParam(spec.start.entityType);
4132
+ parts.push(`.has('entityType', ${p})`);
4133
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4134
+ }
4135
+ if (spec.start.filter) {
4136
+ for (const f of spec.start.filter) {
4137
+ parts.push(compilePropertyFilter(f, nextParam));
4138
+ }
4139
+ }
4140
+ const steps = spec.steps ?? [];
4141
+ for (const step of steps) {
4142
+ if (step.repeat) {
4143
+ parts.push(compileRepeatStep(step, nextParam));
4144
+ estimatedFanOut *= step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4145
+ } else if (step.relationshipFilter && step.relationshipFilter.length > 0) {
4146
+ parts.push(compileEdgeStep(step, nextParam));
4147
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4148
+ } else {
4149
+ parts.push(compileSimpleStep(step, nextParam));
4150
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP;
4151
+ }
4152
+ if (step.entityTypes && step.entityTypes.length > 0) {
4153
+ const typeParams = step.entityTypes.map((t) => nextParam(t));
4154
+ parts.push(`.has('entityType', within(${typeParams.join(", ")}))`);
4155
+ }
4156
+ if (step.entityFilter) {
4157
+ for (const f of step.entityFilter) {
4158
+ parts.push(compilePropertyFilter(f, nextParam));
4159
+ }
4160
+ }
4161
+ }
4162
+ if (spec.returnMode === "all") {
4163
+ }
4164
+ if (spec.dedup !== false) {
4165
+ parts.push(".dedup()");
4166
+ }
4167
+ const limit = spec.limit ?? 50;
4168
+ const offset = spec.offset ?? 0;
4169
+ const pOffset = nextParam(offset);
4170
+ const pEnd = nextParam(offset + limit);
4171
+ parts.push(`.range(${pOffset}, ${pEnd})`);
4172
+ params["_limit"] = limit;
4173
+ params["_offset"] = offset;
4174
+ if (spec.returnMode === "path") {
4175
+ parts.push(".path()");
4176
+ }
4177
+ if (spec.returnMode !== "path") {
4178
+ parts.push(".valueMap(true)");
4179
+ }
4180
+ return {
4181
+ query: parts.join(""),
4182
+ params,
4183
+ estimatedFanOut: Math.min(estimatedFanOut, 1e4)
4184
+ };
4185
+ }
4186
+ };
4187
+ function compileSimpleStep(step, nextParam) {
4188
+ const types = step.relationshipTypes;
4189
+ const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
4190
+ switch (step.direction) {
4191
+ case "out":
4192
+ return types ? `.out(${typeArgs})` : ".out()";
4193
+ case "in":
4194
+ return types ? `.in(${typeArgs})` : ".in()";
4195
+ case "both":
4196
+ return types ? `.both(${typeArgs})` : ".both()";
4197
+ }
4198
+ }
4199
+ function compileEdgeStep(step, nextParam) {
4200
+ const parts = [];
4201
+ const types = step.relationshipTypes;
4202
+ const typeArgs = types ? types.map((t) => nextParam(t)).join(", ") : "";
4203
+ switch (step.direction) {
4204
+ case "out":
4205
+ parts.push(types ? `.outE(${typeArgs})` : ".outE()");
4206
+ break;
4207
+ case "in":
4208
+ parts.push(types ? `.inE(${typeArgs})` : ".inE()");
4209
+ break;
4210
+ case "both":
4211
+ parts.push(types ? `.bothE(${typeArgs})` : ".bothE()");
4212
+ break;
4213
+ }
4214
+ if (step.relationshipFilter) {
4215
+ for (const f of step.relationshipFilter) {
4216
+ parts.push(compilePropertyFilter(f, nextParam));
4400
4217
  }
4401
- return result;
4402
4218
  }
4403
- /** Subscribe to global events */
4404
- on(event, handler) {
4405
- return this.globalEventBus.on(event, handler);
4219
+ switch (step.direction) {
4220
+ case "out":
4221
+ parts.push(".inV()");
4222
+ break;
4223
+ case "in":
4224
+ parts.push(".outV()");
4225
+ break;
4226
+ case "both":
4227
+ parts.push(".otherV()");
4228
+ break;
4406
4229
  }
4407
- /** Update the provenance context (e.g., new conversation) */
4408
- updateProvenance(context) {
4409
- this.provenance.updateContext(context);
4410
- this.globalEventBus.updateProvenance(this.provenance.getContext());
4230
+ return parts.join("");
4231
+ }
4232
+ function compileRepeatStep(step, nextParam) {
4233
+ const parts = [];
4234
+ const innerStep = step.relationshipFilter?.length ? compileEdgeStep({ ...step, repeat: void 0 }, nextParam) : compileSimpleStep(step, nextParam);
4235
+ if (step.repeat?.emitIntermediates !== false) {
4236
+ parts.push(".emit()");
4411
4237
  }
4412
- /** Dispose of all resources */
4413
- async dispose() {
4414
- this.globalEventBus.removeAllListeners();
4415
- if (this.graphTraversalProvider?.dispose) {
4416
- await this.graphTraversalProvider.dispose();
4238
+ parts.push(`.repeat(${innerStep.startsWith(".") ? `__${innerStep}` : innerStep})`);
4239
+ if (step.repeat?.until && step.repeat.until.length > 0) {
4240
+ const untilParts = step.repeat.until.map((f) => compilePropertyFilter(f, nextParam));
4241
+ parts.push(`.until(${untilParts.join("")})`);
4242
+ }
4243
+ if (step.repeat?.maxDepth) {
4244
+ const p = nextParam(step.repeat.maxDepth);
4245
+ parts.push(`.times(${p})`);
4246
+ }
4247
+ if (step.repeat?.emitIntermediates === false) {
4248
+ parts.push(".emit()");
4249
+ }
4250
+ return parts.join("");
4251
+ }
4252
+ function compilePropertyFilter(filter, nextParam) {
4253
+ const key = nextParam(filter.key);
4254
+ switch (filter.operator) {
4255
+ case "eq": {
4256
+ const val = nextParam(filter.value);
4257
+ return `.has(${key}, ${val})`;
4417
4258
  }
4418
- if (this.storage.dispose) {
4419
- await this.storage.dispose();
4259
+ case "neq": {
4260
+ const val = nextParam(filter.value);
4261
+ return `.has(${key}, neq(${val}))`;
4420
4262
  }
4421
- this.initialized = false;
4263
+ case "gt": {
4264
+ const val = nextParam(filter.value);
4265
+ return `.has(${key}, gt(${val}))`;
4266
+ }
4267
+ case "gte": {
4268
+ const val = nextParam(filter.value);
4269
+ return `.has(${key}, gte(${val}))`;
4270
+ }
4271
+ case "lt": {
4272
+ const val = nextParam(filter.value);
4273
+ return `.has(${key}, lt(${val}))`;
4274
+ }
4275
+ case "lte": {
4276
+ const val = nextParam(filter.value);
4277
+ return `.has(${key}, lte(${val}))`;
4278
+ }
4279
+ case "contains": {
4280
+ const val = nextParam(filter.value);
4281
+ return `.has(${key}, containing(${val}))`;
4282
+ }
4283
+ case "isNull":
4284
+ return `.hasNot(${key})`;
4285
+ case "isNotNull":
4286
+ return `.has(${key})`;
4287
+ }
4288
+ }
4289
+
4290
+ // src/relationships/compilers/CypherCompiler.ts
4291
+ var DEFAULT_ESTIMATED_FANOUT_PER_HOP2 = 10;
4292
+ var CypherCompiler = class {
4293
+ language = "cypher";
4294
+ compile(spec, _vocabulary) {
4295
+ const params = {};
4296
+ let paramIndex = 0;
4297
+ let estimatedFanOut = 1;
4298
+ const whereClauses = [];
4299
+ let nodeIndex = 0;
4300
+ const nextParam = (value) => {
4301
+ const name = `p${paramIndex++}`;
4302
+ params[name] = value;
4303
+ return `$${name}`;
4304
+ };
4305
+ const startNode = `n${nodeIndex++}`;
4306
+ let matchParts = [];
4307
+ if (spec.start.entityId) {
4308
+ matchParts.push(`(${startNode})`);
4309
+ whereClauses.push(`${startNode}.id = ${nextParam(spec.start.entityId)}`);
4310
+ } else if (spec.start.entityType) {
4311
+ matchParts.push(`(${startNode})`);
4312
+ whereClauses.push(`${startNode}.entityType = ${nextParam(spec.start.entityType)}`);
4313
+ estimatedFanOut *= DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
4314
+ } else {
4315
+ matchParts.push(`(${startNode})`);
4316
+ }
4317
+ if (spec.start.filter) {
4318
+ for (const f of spec.start.filter) {
4319
+ whereClauses.push(compilePropertyFilterCypher(startNode, f, nextParam));
4320
+ }
4321
+ }
4322
+ let lastNode = startNode;
4323
+ const steps = spec.steps ?? [];
4324
+ for (let i = 0; i < steps.length; i++) {
4325
+ const step = steps[i];
4326
+ const targetNode = `n${nodeIndex++}`;
4327
+ const relAlias = `r${i}`;
4328
+ const relTypes = step.relationshipTypes?.length ? step.relationshipTypes.join("|") : "";
4329
+ const relTypePattern = relTypes ? `:${relTypes}` : "";
4330
+ const depthPattern = step.repeat ? `*1..${step.repeat.maxDepth}` : "";
4331
+ let pattern;
4332
+ switch (step.direction) {
4333
+ case "out":
4334
+ pattern = `-[${relAlias}${relTypePattern}${depthPattern}]->(${targetNode})`;
4335
+ break;
4336
+ case "in":
4337
+ pattern = `<-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
4338
+ break;
4339
+ case "both":
4340
+ pattern = `-[${relAlias}${relTypePattern}${depthPattern}]-(${targetNode})`;
4341
+ break;
4342
+ }
4343
+ matchParts.push(pattern);
4344
+ estimatedFanOut *= step.repeat ? step.repeat.maxDepth * DEFAULT_ESTIMATED_FANOUT_PER_HOP2 : DEFAULT_ESTIMATED_FANOUT_PER_HOP2;
4345
+ if (step.entityTypes && step.entityTypes.length > 0) {
4346
+ const typeParam = nextParam(step.entityTypes);
4347
+ whereClauses.push(`${targetNode}.entityType IN ${typeParam}`);
4348
+ }
4349
+ if (step.entityFilter) {
4350
+ for (const f of step.entityFilter) {
4351
+ whereClauses.push(compilePropertyFilterCypher(targetNode, f, nextParam));
4352
+ }
4353
+ }
4354
+ if (step.relationshipFilter) {
4355
+ for (const f of step.relationshipFilter) {
4356
+ whereClauses.push(compilePropertyFilterCypher(relAlias, f, nextParam));
4357
+ }
4358
+ }
4359
+ lastNode = targetNode;
4360
+ }
4361
+ const matchClause = `MATCH ${matchParts[0]}${matchParts.slice(1).join("")}`;
4362
+ const whereClause = whereClauses.length > 0 ? `
4363
+ WHERE ${whereClauses.join(" AND ")}` : "";
4364
+ let returnClause;
4365
+ if (spec.returnMode === "path") {
4366
+ const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
4367
+ const allRels = steps.map((_, i) => `r${i}`);
4368
+ returnClause = `RETURN ${[...allNodes, ...allRels].join(", ")}`;
4369
+ } else if (spec.returnMode === "all") {
4370
+ const allNodes = Array.from({ length: nodeIndex }, (_, i) => `n${i}`);
4371
+ returnClause = spec.dedup !== false ? `RETURN DISTINCT ${allNodes.join(", ")}` : `RETURN ${allNodes.join(", ")}`;
4372
+ } else {
4373
+ returnClause = spec.dedup !== false ? `RETURN DISTINCT ${lastNode}` : `RETURN ${lastNode}`;
4374
+ }
4375
+ const offset = spec.offset ?? 0;
4376
+ const limit = spec.limit ?? 50;
4377
+ const skipClause = offset > 0 ? `
4378
+ SKIP ${nextParam(offset)}` : "";
4379
+ const limitClause = `
4380
+ LIMIT ${nextParam(limit)}`;
4381
+ params["_limit"] = limit;
4382
+ params["_offset"] = offset;
4383
+ const query = `${matchClause}${whereClause}
4384
+ ${returnClause}${skipClause}${limitClause}`;
4385
+ return {
4386
+ query,
4387
+ params,
4388
+ estimatedFanOut: Math.min(estimatedFanOut, 1e4)
4389
+ };
4422
4390
  }
4423
4391
  };
4392
+ function compilePropertyFilterCypher(nodeAlias, filter, nextParam) {
4393
+ const prop = `${nodeAlias}.${filter.key}`;
4394
+ switch (filter.operator) {
4395
+ case "eq":
4396
+ return `${prop} = ${nextParam(filter.value)}`;
4397
+ case "neq":
4398
+ return `${prop} <> ${nextParam(filter.value)}`;
4399
+ case "gt":
4400
+ return `${prop} > ${nextParam(filter.value)}`;
4401
+ case "gte":
4402
+ return `${prop} >= ${nextParam(filter.value)}`;
4403
+ case "lt":
4404
+ return `${prop} < ${nextParam(filter.value)}`;
4405
+ case "lte":
4406
+ return `${prop} <= ${nextParam(filter.value)}`;
4407
+ case "contains":
4408
+ return `${prop} CONTAINS ${nextParam(filter.value)}`;
4409
+ case "isNull":
4410
+ return `${prop} IS NULL`;
4411
+ case "isNotNull":
4412
+ return `${prop} IS NOT NULL`;
4413
+ }
4414
+ }
4424
4415
 
4425
4416
  // src/providers-builtin/InMemoryStorageProvider.ts
4426
4417
  var InMemoryStorageProvider = class {
@@ -5155,6 +5146,7 @@ var NoOpEmbeddingProvider = class {
5155
5146
  VocabularyValidationError,
5156
5147
  generateId,
5157
5148
  isValidUuid,
5158
- matchesPropertyFilters
5149
+ matchesPropertyFilters,
5150
+ projectEntity
5159
5151
  });
5160
5152
  //# sourceMappingURL=index.cjs.map