@exellix/graph-engine 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/.env.example +3 -0
  2. package/CHANGELOG.md +208 -0
  3. package/README.md +827 -0
  4. package/dist/src/errors/ExellixGraphError.d.ts +38 -0
  5. package/dist/src/errors/ExellixGraphError.js +21 -0
  6. package/dist/src/errors/exellixGraphErrorCodes.d.ts +31 -0
  7. package/dist/src/errors/exellixGraphErrorCodes.js +32 -0
  8. package/dist/src/index.d.ts +100 -0
  9. package/dist/src/index.js +75 -0
  10. package/dist/src/inspection/contractInspection.d.ts +21 -0
  11. package/dist/src/inspection/contractInspection.js +526 -0
  12. package/dist/src/inspection/contractTypes.d.ts +137 -0
  13. package/dist/src/inspection/contractTypes.js +1 -0
  14. package/dist/src/inspection/controlInspection.d.ts +22 -0
  15. package/dist/src/inspection/controlInspection.js +130 -0
  16. package/dist/src/inspection/graphInspection.d.ts +51 -0
  17. package/dist/src/inspection/graphInspection.js +467 -0
  18. package/dist/src/inspection/index.d.ts +21 -0
  19. package/dist/src/inspection/index.js +17 -0
  20. package/dist/src/inspection/nodeInspection.d.ts +42 -0
  21. package/dist/src/inspection/nodeInspection.js +474 -0
  22. package/dist/src/inspection/types.d.ts +321 -0
  23. package/dist/src/inspection/types.js +14 -0
  24. package/dist/src/inspection/validateAiTasksNodeExtensions.d.ts +12 -0
  25. package/dist/src/inspection/validateAiTasksNodeExtensions.js +119 -0
  26. package/dist/src/inspection/validateCatalogPlanning.d.ts +21 -0
  27. package/dist/src/inspection/validateCatalogPlanning.js +187 -0
  28. package/dist/src/integrations/ActivityTrackerIntegration.d.ts +86 -0
  29. package/dist/src/integrations/ActivityTrackerIntegration.js +134 -0
  30. package/dist/src/integrations/ActivixGraphRunIntegration.d.ts +34 -0
  31. package/dist/src/integrations/ActivixGraphRunIntegration.js +338 -0
  32. package/dist/src/integrations/ActivixNodeActivityIntegration.d.ts +33 -0
  33. package/dist/src/integrations/ActivixNodeActivityIntegration.js +220 -0
  34. package/dist/src/integrations/cataloxGraphCatalog.d.ts +21 -0
  35. package/dist/src/integrations/cataloxGraphCatalog.js +30 -0
  36. package/dist/src/integrations/createActivixExellixIntegration.d.ts +14 -0
  37. package/dist/src/integrations/createActivixExellixIntegration.js +16 -0
  38. package/dist/src/integrations/createActivixFromEnv.d.ts +31 -0
  39. package/dist/src/integrations/createActivixFromEnv.js +53 -0
  40. package/dist/src/loaders/FileGraphLoader.d.ts +23 -0
  41. package/dist/src/loaders/FileGraphLoader.js +31 -0
  42. package/dist/src/playground/PlaygroundReporter.d.ts +40 -0
  43. package/dist/src/playground/PlaygroundReporter.js +480 -0
  44. package/dist/src/playground/index.d.ts +1 -0
  45. package/dist/src/playground/index.js +1 -0
  46. package/dist/src/runtime/ExellixGraphRuntime.d.ts +263 -0
  47. package/dist/src/runtime/ExellixGraphRuntime.js +1716 -0
  48. package/dist/src/runtime/GraphEngine.d.ts +33 -0
  49. package/dist/src/runtime/GraphEngine.js +4 -0
  50. package/dist/src/runtime/aiTasksObservability.d.ts +6 -0
  51. package/dist/src/runtime/aiTasksObservability.js +37 -0
  52. package/dist/src/runtime/aiTasksStrategyPhases.d.ts +46 -0
  53. package/dist/src/runtime/aiTasksStrategyPhases.js +93 -0
  54. package/dist/src/runtime/applyAiTaskProfileWebScopingToNarrix.d.ts +17 -0
  55. package/dist/src/runtime/applyAiTaskProfileWebScopingToNarrix.js +46 -0
  56. package/dist/src/runtime/buildAiTasksRunTaskRequest.d.ts +67 -0
  57. package/dist/src/runtime/buildAiTasksRunTaskRequest.js +164 -0
  58. package/dist/src/runtime/buildRunLog.d.ts +27 -0
  59. package/dist/src/runtime/buildRunLog.js +234 -0
  60. package/dist/src/runtime/buildRunTaskTaskConfigurationForward.d.ts +9 -0
  61. package/dist/src/runtime/buildRunTaskTaskConfigurationForward.js +80 -0
  62. package/dist/src/runtime/buildTaskNodeJobContext.d.ts +11 -0
  63. package/dist/src/runtime/buildTaskNodeJobContext.js +30 -0
  64. package/dist/src/runtime/canonicalModelUsed.d.ts +6 -0
  65. package/dist/src/runtime/canonicalModelUsed.js +36 -0
  66. package/dist/src/runtime/contextualScope.d.ts +7 -0
  67. package/dist/src/runtime/contextualScope.js +121 -0
  68. package/dist/src/runtime/dataFiltersEvaluation.d.ts +60 -0
  69. package/dist/src/runtime/dataFiltersEvaluation.js +169 -0
  70. package/dist/src/runtime/deepMerge.d.ts +5 -0
  71. package/dist/src/runtime/deepMerge.js +22 -0
  72. package/dist/src/runtime/events.d.ts +92 -0
  73. package/dist/src/runtime/events.js +122 -0
  74. package/dist/src/runtime/executionMatrixHost.d.ts +98 -0
  75. package/dist/src/runtime/executionMatrixHost.js +134 -0
  76. package/dist/src/runtime/executionVariableBuckets.d.ts +67 -0
  77. package/dist/src/runtime/executionVariableBuckets.js +96 -0
  78. package/dist/src/runtime/finalizers/errors.d.ts +9 -0
  79. package/dist/src/runtime/finalizers/errors.js +10 -0
  80. package/dist/src/runtime/finalizers/executeFinalizer.d.ts +40 -0
  81. package/dist/src/runtime/finalizers/executeFinalizer.js +471 -0
  82. package/dist/src/runtime/finalizers/schema.d.ts +18 -0
  83. package/dist/src/runtime/finalizers/schema.js +63 -0
  84. package/dist/src/runtime/finalizers/validateFinalizer.d.ts +16 -0
  85. package/dist/src/runtime/finalizers/validateFinalizer.js +534 -0
  86. package/dist/src/runtime/graphDocumentFingerprint.d.ts +8 -0
  87. package/dist/src/runtime/graphDocumentFingerprint.js +21 -0
  88. package/dist/src/runtime/graphEngineMemoryPaths.d.ts +12 -0
  89. package/dist/src/runtime/graphEngineMemoryPaths.js +55 -0
  90. package/dist/src/runtime/graphResponseMapping.d.ts +23 -0
  91. package/dist/src/runtime/graphResponseMapping.js +156 -0
  92. package/dist/src/runtime/graphResponseMigration.d.ts +7 -0
  93. package/dist/src/runtime/graphResponseMigration.js +44 -0
  94. package/dist/src/runtime/graphRunExecutionSeed.d.ts +29 -0
  95. package/dist/src/runtime/graphRunExecutionSeed.js +61 -0
  96. package/dist/src/runtime/graphRunIdentity.d.ts +7 -0
  97. package/dist/src/runtime/graphRunIdentity.js +18 -0
  98. package/dist/src/runtime/localSkills/deterministicRule.d.ts +137 -0
  99. package/dist/src/runtime/localSkills/deterministicRule.js +196 -0
  100. package/dist/src/runtime/localSkills/index.d.ts +12 -0
  101. package/dist/src/runtime/localSkills/index.js +14 -0
  102. package/dist/src/runtime/localSkills/memorixItemToScopedOutput.d.ts +7 -0
  103. package/dist/src/runtime/localSkills/memorixItemToScopedOutput.js +104 -0
  104. package/dist/src/runtime/localSkills/memorixRuntime.d.ts +9 -0
  105. package/dist/src/runtime/localSkills/memorixRuntime.js +70 -0
  106. package/dist/src/runtime/localSkills/memorixScopedConfig.d.ts +16 -0
  107. package/dist/src/runtime/localSkills/memorixScopedConfig.js +18 -0
  108. package/dist/src/runtime/localSkills/scopedAnswerAssembler.d.ts +23 -0
  109. package/dist/src/runtime/localSkills/scopedAnswerAssembler.js +35 -0
  110. package/dist/src/runtime/localSkills/scopedAnswerFields.d.ts +12 -0
  111. package/dist/src/runtime/localSkills/scopedAnswerFields.js +66 -0
  112. package/dist/src/runtime/localSkills/scopedAnswerWriter.d.ts +32 -0
  113. package/dist/src/runtime/localSkills/scopedAnswerWriter.js +156 -0
  114. package/dist/src/runtime/localSkills/scopedDataReader.d.ts +47 -0
  115. package/dist/src/runtime/localSkills/scopedDataReader.js +89 -0
  116. package/dist/src/runtime/localSkills/utils.d.ts +12 -0
  117. package/dist/src/runtime/localSkills/utils.js +39 -0
  118. package/dist/src/runtime/materializeStructuredRunTaskInput.d.ts +9 -0
  119. package/dist/src/runtime/materializeStructuredRunTaskInput.js +34 -0
  120. package/dist/src/runtime/memory.d.ts +51 -0
  121. package/dist/src/runtime/memory.js +250 -0
  122. package/dist/src/runtime/mergeExellixGraphRuntimeInvocation.d.ts +18 -0
  123. package/dist/src/runtime/mergeExellixGraphRuntimeInvocation.js +32 -0
  124. package/dist/src/runtime/modelConfigSelection.d.ts +7 -0
  125. package/dist/src/runtime/modelConfigSelection.js +37 -0
  126. package/dist/src/runtime/narrixIngestEnv.d.ts +9 -0
  127. package/dist/src/runtime/narrixIngestEnv.js +18 -0
  128. package/dist/src/runtime/pathExpr.d.ts +36 -0
  129. package/dist/src/runtime/pathExpr.js +131 -0
  130. package/dist/src/runtime/predicates.d.ts +14 -0
  131. package/dist/src/runtime/predicates.js +86 -0
  132. package/dist/src/runtime/readTaskNodeInputsConfig.d.ts +23 -0
  133. package/dist/src/runtime/readTaskNodeInputsConfig.js +27 -0
  134. package/dist/src/runtime/resolveExecutionPipelineForTaskNode.d.ts +11 -0
  135. package/dist/src/runtime/resolveExecutionPipelineForTaskNode.js +93 -0
  136. package/dist/src/runtime/resolveGraphEngineMemoryPaths.d.ts +63 -0
  137. package/dist/src/runtime/resolveGraphEngineMemoryPaths.js +213 -0
  138. package/dist/src/runtime/resolveModelConfigForNode.d.ts +20 -0
  139. package/dist/src/runtime/resolveModelConfigForNode.js +69 -0
  140. package/dist/src/runtime/resolveNarrixForTaskNode.d.ts +14 -0
  141. package/dist/src/runtime/resolveNarrixForTaskNode.js +19 -0
  142. package/dist/src/runtime/resolveTaskKey.d.ts +11 -0
  143. package/dist/src/runtime/resolveTaskKey.js +28 -0
  144. package/dist/src/runtime/resolveTaskNodeInputs.d.ts +25 -0
  145. package/dist/src/runtime/resolveTaskNodeInputs.js +140 -0
  146. package/dist/src/runtime/runTaskAugments.d.ts +17 -0
  147. package/dist/src/runtime/runTaskAugments.js +37 -0
  148. package/dist/src/runtime/runTaskResponse.d.ts +4 -0
  149. package/dist/src/runtime/runTaskResponse.js +13 -0
  150. package/dist/src/runtime/runtimeObjects.d.ts +85 -0
  151. package/dist/src/runtime/runtimeObjects.js +50 -0
  152. package/dist/src/runtime/smartInputPaths.d.ts +13 -0
  153. package/dist/src/runtime/smartInputPaths.js +38 -0
  154. package/dist/src/runtime/stepRetry.d.ts +21 -0
  155. package/dist/src/runtime/stepRetry.js +238 -0
  156. package/dist/src/runtime/synthesizedContextPipeline.d.ts +12 -0
  157. package/dist/src/runtime/synthesizedContextPipeline.js +28 -0
  158. package/dist/src/runtime/taskNodeConditionsEvaluation.d.ts +27 -0
  159. package/dist/src/runtime/taskNodeConditionsEvaluation.js +140 -0
  160. package/dist/src/runtime/taskNodeMainReadiness.d.ts +45 -0
  161. package/dist/src/runtime/taskNodeMainReadiness.js +164 -0
  162. package/dist/src/runtime/taskNodeRunTaskPreflight.d.ts +89 -0
  163. package/dist/src/runtime/taskNodeRunTaskPreflight.js +204 -0
  164. package/dist/src/runtime/validateCanonicalGraphDocument.d.ts +25 -0
  165. package/dist/src/runtime/validateCanonicalGraphDocument.js +567 -0
  166. package/dist/src/runtime/variables.d.ts +2 -0
  167. package/dist/src/runtime/variables.js +1 -0
  168. package/dist/src/runtime/withTimeout.d.ts +5 -0
  169. package/dist/src/runtime/withTimeout.js +20 -0
  170. package/dist/src/types/aiTaskProfile.d.ts +41 -0
  171. package/dist/src/types/aiTaskProfile.js +6 -0
  172. package/dist/src/types/aiTasksDerivedTypes.d.ts +5 -0
  173. package/dist/src/types/aiTasksDerivedTypes.js +1 -0
  174. package/dist/src/types/events.d.ts +23 -0
  175. package/dist/src/types/events.js +1 -0
  176. package/dist/src/types/job.d.ts +9 -0
  177. package/dist/src/types/job.js +1 -0
  178. package/dist/src/types/narrix.d.ts +60 -0
  179. package/dist/src/types/narrix.js +1 -0
  180. package/dist/src/types/options.d.ts +122 -0
  181. package/dist/src/types/options.js +1 -0
  182. package/dist/src/types/refs.d.ts +747 -0
  183. package/dist/src/types/refs.js +12 -0
  184. package/dist/src/types/results.d.ts +103 -0
  185. package/dist/src/types/results.js +1 -0
  186. package/dist/src/types/runLog.d.ts +72 -0
  187. package/dist/src/types/runLog.js +18 -0
  188. package/dist/src/types/taskNodeConfiguration.d.ts +95 -0
  189. package/dist/src/types/taskNodeConfiguration.js +3 -0
  190. package/dist/src/util/packageVersion.d.ts +2 -0
  191. package/dist/src/util/packageVersion.js +12 -0
  192. package/dist/testkit/RealTasksClient.d.ts +16 -0
  193. package/dist/testkit/RealTasksClient.js +143 -0
  194. package/dist/testkit/depGraphEngineFactory.d.ts +6 -0
  195. package/dist/testkit/depGraphEngineFactory.js +54 -0
  196. package/dist/testkit/exellixRuntimeObjects.d.ts +7 -0
  197. package/dist/testkit/exellixRuntimeObjects.js +25 -0
  198. package/dist/testkit/inMemoryGraphLoader.d.ts +6 -0
  199. package/dist/testkit/inMemoryGraphLoader.js +12 -0
  200. package/dist/testkit/index.d.ts +4 -0
  201. package/dist/testkit/index.js +4 -0
  202. package/package.json +70 -0
@@ -0,0 +1,196 @@
1
+ /**
2
+ * deterministic-rule — local deterministic skill.
3
+ *
4
+ * Evaluates a rule table against executionMemory (or a custom root path) and returns
5
+ * the first matching rule's output, a full evaluation trace, and optional sensitivity
6
+ * analysis for UNKNOWN-tagged inputs (DQ-1 swing calculation).
7
+ *
8
+ * Node config (in node.taskConfiguration):
9
+ * rules : Rule[] — ordered list of rules
10
+ * firstMatchWins : boolean — default true; when false all matching rules fire
11
+ * defaultOutput : object? — emitted when no rule matches
12
+ * sensitivityAnalysis : SensitivityAnalysisConfig? — only used by DQ-1
13
+ *
14
+ * Each rule:
15
+ * id : string
16
+ * label? : string — human-readable description
17
+ * condition : Condition — nested logical condition
18
+ * output : Record<string,unknown> — merged into result when this rule fires
19
+ * stopOnMatch? : boolean — default true (respected when firstMatchWins=true)
20
+ *
21
+ * Condition operators (leaf):
22
+ * { path, eq } — strict equality
23
+ * { path, in } — value in array
24
+ * { path, gte } — >= number
25
+ * { path, gt } — > number
26
+ * { path, lte } — <= number
27
+ * { path, lt } — < number
28
+ * { path, exists } — boolean (truthy check when true, falsy check when false)
29
+ * { path, contains } — string or array contains value
30
+ * { path, regex } — string matches pattern
31
+ * Compound:
32
+ * { all: Condition[] }
33
+ * { any: Condition[] }
34
+ * { not: Condition }
35
+ *
36
+ * Output:
37
+ * {
38
+ * matched : boolean
39
+ * rule_id : string | null
40
+ * rule_label : string | null
41
+ * output : Record<string,unknown>
42
+ * evaluation_trace : { ruleId, matched, shortCircuited }[]
43
+ * sensitivity? : SensitivityResult — only when sensitivityAnalysis is configured
44
+ * }
45
+ */
46
+ import { resolveDotPath } from './utils.js';
47
+ // ─── Condition evaluation ──────────────────────────────────────────────────────
48
+ function evalCondition(cond, root, pathOpts) {
49
+ if ('all' in cond) {
50
+ return cond.all.every((c) => evalCondition(c, root, pathOpts));
51
+ }
52
+ if ('any' in cond) {
53
+ return cond.any.some((c) => evalCondition(c, root, pathOpts));
54
+ }
55
+ if ('not' in cond) {
56
+ return !evalCondition(cond.not, root, pathOpts);
57
+ }
58
+ const leaf = cond;
59
+ const val = resolveDotPath(root, leaf.path, pathOpts);
60
+ if ('exists' in leaf) {
61
+ const e = leaf.exists;
62
+ return e ? val != null : val == null;
63
+ }
64
+ if ('eq' in leaf)
65
+ return val === leaf.eq;
66
+ if ('in' in leaf) {
67
+ const arr = leaf.in;
68
+ return Array.isArray(arr) && arr.includes(val);
69
+ }
70
+ if ('gte' in leaf)
71
+ return typeof val === 'number' && val >= leaf.gte;
72
+ if ('gt' in leaf)
73
+ return typeof val === 'number' && val > leaf.gt;
74
+ if ('lte' in leaf)
75
+ return typeof val === 'number' && val <= leaf.lte;
76
+ if ('lt' in leaf)
77
+ return typeof val === 'number' && val < leaf.lt;
78
+ if ('contains' in leaf) {
79
+ const target = leaf.contains;
80
+ if (Array.isArray(val))
81
+ return val.includes(target);
82
+ if (typeof val === 'string' && typeof target === 'string')
83
+ return val.includes(target);
84
+ return false;
85
+ }
86
+ if ('regex' in leaf) {
87
+ if (typeof val !== 'string')
88
+ return false;
89
+ return new RegExp(leaf.regex).test(val);
90
+ }
91
+ return false;
92
+ }
93
+ // ─── Rule evaluation (single pass) ────────────────────────────────────────────
94
+ function evaluateRules(rules, root, firstMatchWins, pathOpts) {
95
+ const trace = [];
96
+ let mergedOutput = {};
97
+ let matchedId = null;
98
+ let matchedLabel = null;
99
+ let anyMatched = false;
100
+ for (const rule of rules) {
101
+ const hit = evalCondition(rule.condition, root, pathOpts);
102
+ trace.push({ ruleId: rule.id, matched: hit });
103
+ if (hit) {
104
+ anyMatched = true;
105
+ matchedId = rule.id;
106
+ matchedLabel = rule.label ?? null;
107
+ mergedOutput = { ...mergedOutput, ...rule.output };
108
+ if (firstMatchWins) {
109
+ // Mark remaining rules as short-circuited
110
+ for (let i = trace.length; i < rules.length; i++) {
111
+ trace.push({ ruleId: rules[i].id, matched: false, shortCircuited: true });
112
+ }
113
+ break;
114
+ }
115
+ }
116
+ }
117
+ return {
118
+ matched: anyMatched,
119
+ rule_id: matchedId,
120
+ rule_label: matchedLabel,
121
+ output: mergedOutput,
122
+ trace,
123
+ };
124
+ }
125
+ // ─── Sensitivity analysis ──────────────────────────────────────────────────────
126
+ function runSensitivity(cfg, rules, baseRoot, firstMatchWins, basePriority, pathOpts) {
127
+ const unknowns = (resolveDotPath(baseRoot, cfg.unknownsPath, pathOpts) ?? []);
128
+ const rankOf = (p) => {
129
+ if (p == null)
130
+ return cfg.priorityRank.length;
131
+ const idx = cfg.priorityRank.indexOf(p);
132
+ return idx === -1 ? cfg.priorityRank.length : idx;
133
+ };
134
+ const entries = [];
135
+ for (const u of unknowns) {
136
+ if (u.tag !== 'UNKNOWN' || !u.path)
137
+ continue;
138
+ const rootStr = JSON.stringify(baseRoot);
139
+ const applySubstitute = (rootObj, path, value) => {
140
+ const parts = path.split('.');
141
+ const clone = JSON.parse(JSON.stringify(rootObj));
142
+ let cur = clone;
143
+ for (let i = 0; i < parts.length - 1; i++) {
144
+ if (cur[parts[i]] == null)
145
+ cur[parts[i]] = {};
146
+ cur = cur[parts[i]];
147
+ }
148
+ cur[parts[parts.length - 1]] = value;
149
+ return clone;
150
+ };
151
+ const upRoot = applySubstitute(JSON.parse(rootStr), u.path, u.up_substitute);
152
+ const downRoot = applySubstitute(JSON.parse(rootStr), u.path, u.down_substitute);
153
+ const upResult = evaluateRules(rules, upRoot, firstMatchWins, pathOpts);
154
+ const downResult = evaluateRules(rules, downRoot, firstMatchWins, pathOpts);
155
+ const upPriority = upResult.matched
156
+ ? (String(upResult.output[cfg.priorityField] ?? '') || null)
157
+ : null;
158
+ const downPriority = downResult.matched
159
+ ? (String(downResult.output[cfg.priorityField] ?? '') || null)
160
+ : null;
161
+ const swing = Math.abs(rankOf(upPriority) - rankOf(downPriority));
162
+ entries.push({
163
+ unknown_id: u.id,
164
+ up_substitute: u.up_substitute,
165
+ down_substitute: u.down_substitute,
166
+ up_priority: upPriority,
167
+ down_priority: downPriority,
168
+ swing,
169
+ });
170
+ }
171
+ return {
172
+ any_high_swing: entries.some((e) => e.swing >= 2),
173
+ entries,
174
+ };
175
+ }
176
+ // ─── Public entry point ────────────────────────────────────────────────────────
177
+ export function runDeterministicRule(cfg, executionMemory, pathOpts) {
178
+ const rules = Array.isArray(cfg.rules) ? cfg.rules : [];
179
+ const firstMatchWins = cfg.firstMatchWins !== false;
180
+ const { matched, rule_id, rule_label, output, trace } = evaluateRules(rules, executionMemory, firstMatchWins, pathOpts);
181
+ const finalOutput = matched ? output : (cfg.defaultOutput ?? {});
182
+ const result = {
183
+ matched,
184
+ rule_id,
185
+ rule_label,
186
+ output: finalOutput,
187
+ evaluation_trace: trace,
188
+ };
189
+ if (cfg.sensitivityAnalysis) {
190
+ const basePriority = matched
191
+ ? (String(output[cfg.sensitivityAnalysis.priorityField] ?? '') || null)
192
+ : null;
193
+ result.sensitivity = runSensitivity(cfg.sensitivityAnalysis, rules, executionMemory, firstMatchWins, basePriority, pathOpts);
194
+ }
195
+ return result;
196
+ }
@@ -0,0 +1,12 @@
1
+ export { resolveDotPath } from './utils.js';
2
+ export { runScopedDataReader, scopedAnswerDocToFlatFields, runScopedDataReaderPack } from './scopedDataReader.js';
3
+ export type { ScopedDataReaderConfig, ScopedDataReaderOutput, ScopedDataReaderPackOutput, ScopedDataReaderPackSlot, } from './scopedDataReader.js';
4
+ export { runDeterministicRule } from './deterministicRule.js';
5
+ export type { DeterministicRuleConfig, DeterministicRuleOutput, Rule, Condition, SensitivityAnalysisConfig, SensitivityResult, } from './deterministicRule.js';
6
+ export { runScopedAnswerWriter } from './scopedAnswerWriter.js';
7
+ export type { ScopedAnswerWriterConfig, ScopedAnswerWriterOutput, } from './scopedAnswerWriter.js';
8
+ export { runScopedAnswerAssembler } from './scopedAnswerAssembler.js';
9
+ export type { ScopedAnswerAssemblerConfig, ScopedAnswerAssemblerOutput, } from './scopedAnswerAssembler.js';
10
+ export declare const LOCAL_SKILL_KEYS: readonly ["scoped-data-reader", "deterministic-rule", "scoped-answer-writer", "scoped-answer-assembler"];
11
+ export type LocalSkillKey = (typeof LOCAL_SKILL_KEYS)[number];
12
+ export declare function isLocalSkillKey(key: string): key is LocalSkillKey;
@@ -0,0 +1,14 @@
1
+ export { resolveDotPath } from './utils.js';
2
+ export { runScopedDataReader, scopedAnswerDocToFlatFields, runScopedDataReaderPack } from './scopedDataReader.js';
3
+ export { runDeterministicRule } from './deterministicRule.js';
4
+ export { runScopedAnswerWriter } from './scopedAnswerWriter.js';
5
+ export { runScopedAnswerAssembler } from './scopedAnswerAssembler.js';
6
+ export const LOCAL_SKILL_KEYS = [
7
+ 'scoped-data-reader',
8
+ 'deterministic-rule',
9
+ 'scoped-answer-writer',
10
+ 'scoped-answer-assembler',
11
+ ];
12
+ export function isLocalSkillKey(key) {
13
+ return LOCAL_SKILL_KEYS.includes(key);
14
+ }
@@ -0,0 +1,7 @@
1
+ import type { FetchMemorixItemResponse } from '@x12i/memorix-retrieval';
2
+ import type { ScopedDataReaderOutput } from './scopedDataReader.js';
3
+ /**
4
+ * Flatten {@link fetchMemorixItem} sections into graph `fields.*` paths.
5
+ * Works across content types — whatever the item descriptor surfaces in sections.
6
+ */
7
+ export declare function memorixItemToScopedOutput(item: FetchMemorixItemResponse, entityId: string): ScopedDataReaderOutput;
@@ -0,0 +1,104 @@
1
+ function isPlainObject(v) {
2
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
3
+ }
4
+ function looksLikeFieldEnvelope(v) {
5
+ return isPlainObject(v) && 'value' in v;
6
+ }
7
+ /** Expand a Memorix content-type object map into flat execution fields. */
8
+ function mergeContentTypeBucket(bucketName, raw, fields, unknowns) {
9
+ for (const [leafKey, leafVal] of Object.entries(raw)) {
10
+ const outKey = `${bucketName}.${leafKey}`;
11
+ if (looksLikeFieldEnvelope(leafVal)) {
12
+ const f = leafVal;
13
+ fields[outKey] = {
14
+ value: f.value,
15
+ fieldPath: typeof f.fieldPath === 'string' ? f.fieldPath : outKey,
16
+ ...(f.description != null ? { description: f.description } : {}),
17
+ ...(f.reasoning != null ? { reasoning: f.reasoning } : {}),
18
+ ...(f.linked != null ? { linked: f.linked } : {}),
19
+ };
20
+ if (f.value == null)
21
+ unknowns.push(outKey);
22
+ }
23
+ else if (leafVal !== undefined) {
24
+ fields[outKey] = { value: leafVal, fieldPath: outKey };
25
+ if (leafVal == null)
26
+ unknowns.push(outKey);
27
+ }
28
+ }
29
+ }
30
+ function addScalarOrEnvelope(key, raw, fields, unknowns) {
31
+ if (looksLikeFieldEnvelope(raw)) {
32
+ const f = raw;
33
+ fields[key] = {
34
+ value: f.value,
35
+ fieldPath: typeof f.fieldPath === 'string' ? f.fieldPath : '',
36
+ ...(f.description != null ? { description: f.description } : {}),
37
+ ...(f.reasoning != null ? { reasoning: f.reasoning } : {}),
38
+ ...(f.linked != null ? { linked: f.linked } : {}),
39
+ };
40
+ if (f.value == null)
41
+ unknowns.push(key);
42
+ return;
43
+ }
44
+ if (raw !== undefined) {
45
+ fields[key] = { value: raw, fieldPath: '' };
46
+ if (raw == null)
47
+ unknowns.push(key);
48
+ }
49
+ }
50
+ /**
51
+ * Flatten {@link fetchMemorixItem} sections into graph `fields.*` paths.
52
+ * Works across content types — whatever the item descriptor surfaces in sections.
53
+ */
54
+ export function memorixItemToScopedOutput(item, entityId) {
55
+ const errors = item.issues?.filter((i) => i.severity === 'error') ?? [];
56
+ if (errors.length > 0) {
57
+ return {
58
+ answer_status: 'error',
59
+ fields: {},
60
+ freshness: null,
61
+ unknowns: [],
62
+ entity_id: entityId,
63
+ error: errors.map((e) => e.message).join('; '),
64
+ };
65
+ }
66
+ const fields = {};
67
+ const unknowns = [];
68
+ for (const section of item.sections) {
69
+ for (const [key, raw] of Object.entries(section.fields)) {
70
+ if (isPlainObject(raw) && !looksLikeFieldEnvelope(raw)) {
71
+ const keys = Object.keys(raw);
72
+ const looksLikeBucket = keys.length > 0 &&
73
+ (key === 'inferences' ||
74
+ key === 'decisions' ||
75
+ keys.every((k) => looksLikeFieldEnvelope(raw[k]) || raw[k] === null || typeof raw[k] !== 'object'));
76
+ if (looksLikeBucket) {
77
+ mergeContentTypeBucket(key, raw, fields, unknowns);
78
+ continue;
79
+ }
80
+ }
81
+ addScalarOrEnvelope(key, raw, fields, unknowns);
82
+ }
83
+ }
84
+ const hasData = Object.keys(fields).length > 0;
85
+ if (!hasData) {
86
+ return {
87
+ answer_status: 'not_found',
88
+ fields: {},
89
+ freshness: null,
90
+ unknowns: [],
91
+ entity_id: entityId,
92
+ };
93
+ }
94
+ const flat = item.sections.flatMap((s) => Object.entries(s.fields));
95
+ const scopedAtRaw = flat.find(([k]) => k === 'scopedAt')?.[1] ?? flat.find(([k]) => k === 'modifiedAt')?.[1];
96
+ const scopedAt = typeof scopedAtRaw === 'string' ? scopedAtRaw : undefined;
97
+ return {
98
+ answer_status: 'answered',
99
+ fields,
100
+ freshness: scopedAt ? { scopedAt } : null,
101
+ unknowns,
102
+ entity_id: entityId,
103
+ };
104
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Lazy Memorix retrieval + writer clients for local scoped-data skills.
3
+ */
4
+ import { type MemorixRetrievalClient } from '@x12i/memorix-retrieval';
5
+ import { type MemorixWriterClient } from '@x12i/memorix-writer';
6
+ export declare function getMemorixRetrievalClient(): Promise<MemorixRetrievalClient>;
7
+ export declare function getMemorixWriterClient(): Promise<MemorixWriterClient>;
8
+ /** Closes Memorix retrieval + writer clients. Call on shutdown. */
9
+ export declare function shutdownMemorixRuntime(): Promise<void>;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Lazy Memorix retrieval + writer clients for local scoped-data skills.
3
+ */
4
+ import { applyMemorixEnvBridgeToProcess, createMemorixRetrievalStackFromEnv, fetchMemorixItem, } from '@x12i/memorix-retrieval';
5
+ import { createMemorixWriterFromEnv, } from '@x12i/memorix-writer';
6
+ function cataloxForWriter(retrievalCatalox, appId) {
7
+ return {
8
+ async getCatalogItem(catalogId, itemId) {
9
+ const result = await retrievalCatalox.getCatalogItem({ appId }, catalogId, itemId);
10
+ if (result.outcome !== 'found')
11
+ return null;
12
+ return { data: result.item.data };
13
+ },
14
+ };
15
+ }
16
+ let _stack = null;
17
+ let _stackPromise = null;
18
+ let _writer = null;
19
+ let _writerPromise = null;
20
+ async function getOrInitStack() {
21
+ if (_stack)
22
+ return _stack;
23
+ if (_stackPromise)
24
+ return _stackPromise;
25
+ _stackPromise = (async () => {
26
+ applyMemorixEnvBridgeToProcess();
27
+ const stack = await createMemorixRetrievalStackFromEnv();
28
+ _stack = stack;
29
+ _stackPromise = null;
30
+ return stack;
31
+ })();
32
+ return _stackPromise;
33
+ }
34
+ export async function getMemorixRetrievalClient() {
35
+ const stack = await getOrInitStack();
36
+ return stack.client;
37
+ }
38
+ export async function getMemorixWriterClient() {
39
+ if (_writer)
40
+ return _writer;
41
+ if (_writerPromise)
42
+ return _writerPromise;
43
+ _writerPromise = (async () => {
44
+ const stack = await getOrInitStack();
45
+ const retrievalClient = stack.client;
46
+ const writer = await createMemorixWriterFromEnv({
47
+ appId: stack.appId,
48
+ catalox: cataloxForWriter(stack.catalox, stack.appId),
49
+ processEnv: stack.client.processEnv,
50
+ retrieval: {
51
+ fetchMemorixItem: (args) => fetchMemorixItem(retrievalClient, args),
52
+ },
53
+ });
54
+ _writer = writer;
55
+ _writerPromise = null;
56
+ return writer;
57
+ })();
58
+ return _writerPromise;
59
+ }
60
+ /** Closes Memorix retrieval + writer clients. Call on shutdown. */
61
+ export async function shutdownMemorixRuntime() {
62
+ const writer = _writer;
63
+ const stack = _stack;
64
+ _writer = null;
65
+ _writerPromise = null;
66
+ _stack = null;
67
+ _stackPromise = null;
68
+ await writer?.close?.().catch(() => undefined);
69
+ await stack?.client.close?.().catch(() => undefined);
70
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Memorix descriptor ids for scoped local skills (Catalox-backed).
3
+ */
4
+ export declare const DEFAULT_SCOPED_CONTENT_TYPES: readonly ["inferences", "decisions"];
5
+ export type ScopedContentType = (typeof DEFAULT_SCOPED_CONTENT_TYPES)[number];
6
+ export type MemorixScopedSkillConfig = {
7
+ memorixItemDescriptorId?: string;
8
+ itemDescriptorId?: string;
9
+ /** Per content-type write descriptor ids (default: content type name, e.g. `inferences`). */
10
+ memorixWriteDescriptors?: Partial<Record<string, string>>;
11
+ /** @deprecated Use {@link memorixWriteDescriptors}. */
12
+ memorixWriteDescriptorId?: string;
13
+ writeDescriptorId?: string;
14
+ };
15
+ export declare function resolveMemorixItemDescriptorId(cfg: MemorixScopedSkillConfig): string | undefined;
16
+ export declare function resolveMemorixWriteDescriptorId(cfg: MemorixScopedSkillConfig, contentType: string): string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Memorix descriptor ids for scoped local skills (Catalox-backed).
3
+ */
4
+ export const DEFAULT_SCOPED_CONTENT_TYPES = ['inferences', 'decisions'];
5
+ export function resolveMemorixItemDescriptorId(cfg) {
6
+ return cfg.memorixItemDescriptorId?.trim() || cfg.itemDescriptorId?.trim() || undefined;
7
+ }
8
+ export function resolveMemorixWriteDescriptorId(cfg, contentType) {
9
+ const mapped = cfg.memorixWriteDescriptors?.[contentType]?.trim();
10
+ if (mapped)
11
+ return mapped;
12
+ if (contentType === 'inferences' || contentType === 'decisions') {
13
+ const legacy = cfg.memorixWriteDescriptorId?.trim() || cfg.writeDescriptorId?.trim();
14
+ if (legacy && contentType === 'inferences')
15
+ return legacy;
16
+ }
17
+ return contentType;
18
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * scoped-answer-assembler — local skill.
3
+ *
4
+ * Builds the object **`{ inferences, decisions }`** from executionMemory paths
5
+ * before **`scoped-answer-writer`** persists it to Memorix entity content types. Names reflect
6
+ * that we store **learned inferences** and **decisions**, not “verdicts” alone.
7
+ *
8
+ * Metadata:
9
+ * mergeInferencePaths?: string[] — dot-paths to plain objects (shallow-merge keys into inferences)
10
+ * mergeDecisionPaths?: string[] — same for decisions (later paths win on key collision)
11
+ *
12
+ * Skill key: **`scoped-answer-assembler`**.
13
+ */
14
+ import { type ResolveDotPathOpts } from './utils.js';
15
+ export type ScopedAnswerAssemblerConfig = {
16
+ mergeInferencePaths?: string[];
17
+ mergeDecisionPaths?: string[];
18
+ };
19
+ export type ScopedAnswerAssemblerOutput = {
20
+ inferences: Record<string, unknown>;
21
+ decisions: Record<string, unknown>;
22
+ };
23
+ export declare function runScopedAnswerAssembler(cfg: ScopedAnswerAssemblerConfig, executionMemory: unknown, pathOpts?: ResolveDotPathOpts): ScopedAnswerAssemblerOutput;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * scoped-answer-assembler — local skill.
3
+ *
4
+ * Builds the object **`{ inferences, decisions }`** from executionMemory paths
5
+ * before **`scoped-answer-writer`** persists it to Memorix entity content types. Names reflect
6
+ * that we store **learned inferences** and **decisions**, not “verdicts” alone.
7
+ *
8
+ * Metadata:
9
+ * mergeInferencePaths?: string[] — dot-paths to plain objects (shallow-merge keys into inferences)
10
+ * mergeDecisionPaths?: string[] — same for decisions (later paths win on key collision)
11
+ *
12
+ * Skill key: **`scoped-answer-assembler`**.
13
+ */
14
+ import { resolveDotPath } from './utils.js';
15
+ function isPlainObject(v) {
16
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
17
+ }
18
+ function mergeFromPaths(executionMemory, paths, bucket, pathOpts) {
19
+ for (const p of paths ?? []) {
20
+ const v = resolveDotPath(executionMemory, p, pathOpts);
21
+ if (!isPlainObject(v))
22
+ continue;
23
+ for (const [k, val] of Object.entries(v)) {
24
+ if (val !== undefined)
25
+ bucket[k] = val;
26
+ }
27
+ }
28
+ }
29
+ export function runScopedAnswerAssembler(cfg, executionMemory, pathOpts) {
30
+ const inferences = {};
31
+ const decisions = {};
32
+ mergeFromPaths(executionMemory, cfg.mergeInferencePaths, inferences, pathOpts);
33
+ mergeFromPaths(executionMemory, cfg.mergeDecisionPaths, decisions, pathOpts);
34
+ return { inferences, decisions };
35
+ }
@@ -0,0 +1,12 @@
1
+ export type ScopedAnswerField = {
2
+ value: unknown;
3
+ fieldPath: string;
4
+ description?: string;
5
+ reasoning?: string;
6
+ linked?: boolean;
7
+ };
8
+ /** Flatten nested or legacy `answer` documents into graph execution field maps. */
9
+ export declare function scopedAnswerDocToFlatFields(rawAnswer: Record<string, unknown>): {
10
+ fields: Record<string, ScopedAnswerField>;
11
+ unknowns: string[];
12
+ };
@@ -0,0 +1,66 @@
1
+ function isPlainObject(v) {
2
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
3
+ }
4
+ function looksLikeFieldEnvelope(v) {
5
+ return isPlainObject(v) && 'value' in v;
6
+ }
7
+ function isNestedAnswerShape(raw) {
8
+ const inf = raw.inferences;
9
+ const dec = raw.decisions;
10
+ if (inf !== undefined && isPlainObject(inf))
11
+ return true;
12
+ if (dec !== undefined && isPlainObject(dec))
13
+ return true;
14
+ return false;
15
+ }
16
+ function mergeBucketIntoFields(fields, unknowns, bucket, bucketObj) {
17
+ const disambig = new Set(Object.keys(fields));
18
+ for (const [leafKey, field] of Object.entries(bucketObj)) {
19
+ if (!looksLikeFieldEnvelope(field))
20
+ continue;
21
+ const f = field;
22
+ let outKey = leafKey;
23
+ if (disambig.has(leafKey)) {
24
+ outKey = `${bucket}_${leafKey}`;
25
+ }
26
+ disambig.add(outKey);
27
+ fields[outKey] = {
28
+ value: f.value,
29
+ fieldPath: typeof f.fieldPath === 'string' ? f.fieldPath : '',
30
+ ...(f.description != null ? { description: f.description } : {}),
31
+ ...(f.reasoning != null ? { reasoning: f.reasoning } : {}),
32
+ ...(f.linked != null ? { linked: f.linked } : {}),
33
+ };
34
+ if (f.value == null) {
35
+ unknowns.push(outKey);
36
+ }
37
+ }
38
+ }
39
+ /** Flatten nested or legacy `answer` documents into graph execution field maps. */
40
+ export function scopedAnswerDocToFlatFields(rawAnswer) {
41
+ const fields = {};
42
+ const unknowns = [];
43
+ if (isNestedAnswerShape(rawAnswer)) {
44
+ const inf = isPlainObject(rawAnswer.inferences) ? rawAnswer.inferences : {};
45
+ const dec = isPlainObject(rawAnswer.decisions) ? rawAnswer.decisions : {};
46
+ mergeBucketIntoFields(fields, unknowns, 'decisions', dec);
47
+ mergeBucketIntoFields(fields, unknowns, 'inferences', inf);
48
+ return { fields, unknowns };
49
+ }
50
+ for (const [key, field] of Object.entries(rawAnswer)) {
51
+ if (!looksLikeFieldEnvelope(field))
52
+ continue;
53
+ const f = field;
54
+ fields[key] = {
55
+ value: f.value,
56
+ fieldPath: typeof f.fieldPath === 'string' ? f.fieldPath : '',
57
+ ...(f.description != null ? { description: f.description } : {}),
58
+ ...(f.reasoning != null ? { reasoning: f.reasoning } : {}),
59
+ ...(f.linked != null ? { linked: f.linked } : {}),
60
+ };
61
+ if (f.value == null) {
62
+ unknowns.push(key);
63
+ }
64
+ }
65
+ return { fields, unknowns };
66
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * scoped-answer-writer — local skill.
3
+ *
4
+ * Persists execution-memory payloads into Memorix **entity** collections, one
5
+ * **content type** per write (`inferences`, `decisions`, …) via `writeMemorixRecord`.
6
+ *
7
+ * Node config:
8
+ * entityIdPath — required
9
+ * payloadPath — dot-path to `{ inferences?, decisions? }` or flat decisions map
10
+ * memorixWriteDescriptors — optional map of contentType → Catalox write descriptor id
11
+ * (default: descriptor id equals content type name)
12
+ */
13
+ import { type MemorixScopedSkillConfig } from './memorixScopedConfig.js';
14
+ import { type ResolveDotPathOpts } from './utils.js';
15
+ export type ScopedAnswerWriterConfig = MemorixScopedSkillConfig & {
16
+ entityIdPath: string;
17
+ entityTypePath?: string;
18
+ staticEntityType?: string;
19
+ payloadPath?: string;
20
+ questionTitle?: string;
21
+ phase?: 'A' | 'B';
22
+ /** Content types to persist when present in payload (default: inferences, decisions). */
23
+ memorixContentTypes?: string[];
24
+ };
25
+ export type ScopedAnswerWriterOutput = {
26
+ write_status: 'ok' | 'error';
27
+ entity_id: string;
28
+ content_types_written: string[];
29
+ written_keys: string[];
30
+ error?: string;
31
+ };
32
+ export declare function runScopedAnswerWriter(cfg: ScopedAnswerWriterConfig, executionMemory: unknown, pathOpts?: ResolveDotPathOpts): Promise<ScopedAnswerWriterOutput>;