@unrdf/knowledge-engine 5.0.1
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 +21 -0
- package/README.md +84 -0
- package/package.json +64 -0
- package/src/browser-shims.mjs +343 -0
- package/src/browser.mjs +910 -0
- package/src/canonicalize.mjs +414 -0
- package/src/condition-cache.mjs +109 -0
- package/src/condition-evaluator.mjs +722 -0
- package/src/dark-matter-core.mjs +742 -0
- package/src/define-hook.mjs +213 -0
- package/src/effect-sandbox-browser.mjs +283 -0
- package/src/effect-sandbox-worker.mjs +170 -0
- package/src/effect-sandbox.mjs +517 -0
- package/src/engines/index.mjs +11 -0
- package/src/engines/rdf-engine.mjs +299 -0
- package/src/file-resolver.mjs +387 -0
- package/src/hook-executor-batching.mjs +277 -0
- package/src/hook-executor.mjs +870 -0
- package/src/hook-management.mjs +150 -0
- package/src/index.mjs +93 -0
- package/src/ken-parliment.mjs +119 -0
- package/src/ken.mjs +149 -0
- package/src/knowledge-engine/builtin-rules.mjs +190 -0
- package/src/knowledge-engine/inference-engine.mjs +418 -0
- package/src/knowledge-engine/knowledge-engine.mjs +317 -0
- package/src/knowledge-engine/pattern-dsl.mjs +142 -0
- package/src/knowledge-engine/pattern-matcher.mjs +215 -0
- package/src/knowledge-engine/rules.mjs +184 -0
- package/src/knowledge-engine.mjs +319 -0
- package/src/knowledge-hook-engine.mjs +360 -0
- package/src/knowledge-hook-manager.mjs +469 -0
- package/src/knowledge-substrate-core.mjs +927 -0
- package/src/lite.mjs +222 -0
- package/src/lockchain-writer-browser.mjs +414 -0
- package/src/lockchain-writer.mjs +602 -0
- package/src/monitoring/andon-signals.mjs +775 -0
- package/src/observability.mjs +531 -0
- package/src/parse.mjs +290 -0
- package/src/performance-optimizer.mjs +678 -0
- package/src/policy-pack.mjs +572 -0
- package/src/query-cache.mjs +116 -0
- package/src/query-optimizer.mjs +1051 -0
- package/src/query.mjs +306 -0
- package/src/reason.mjs +350 -0
- package/src/resolution-layer.mjs +506 -0
- package/src/schemas.mjs +1063 -0
- package/src/security/error-sanitizer.mjs +257 -0
- package/src/security/path-validator.mjs +194 -0
- package/src/security/sandbox-restrictions.mjs +331 -0
- package/src/security-validator.mjs +389 -0
- package/src/store-cache.mjs +137 -0
- package/src/telemetry.mjs +167 -0
- package/src/transaction.mjs +810 -0
- package/src/utils/adaptive-monitor.mjs +746 -0
- package/src/utils/circuit-breaker.mjs +513 -0
- package/src/utils/edge-case-handler.mjs +503 -0
- package/src/utils/memory-manager.mjs +498 -0
- package/src/utils/ring-buffer.mjs +282 -0
- package/src/validate.mjs +319 -0
- package/src/validators/index.mjs +338 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Hook Execution Batching Extension
|
|
3
|
+
* @module knowledge-engine/hook-executor-batching
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* Extends hook executor with batching capabilities for 30-50% latency reduction.
|
|
7
|
+
* Analyzes hook dependencies and executes independent hooks in parallel.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { trace, metrics as otelMetrics, SpanStatusCode } from '@opentelemetry/api';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Add batching capabilities to a hook executor instance.
|
|
14
|
+
* @param {Object} executor - Hook executor instance
|
|
15
|
+
* @param {Object} [options] - Batching options
|
|
16
|
+
* @returns {Object} Extended executor with batching
|
|
17
|
+
*/
|
|
18
|
+
export function addBatchingCapabilities(executor, options = {}) {
|
|
19
|
+
const { enableOTEL = true, enableBatching = true } = options;
|
|
20
|
+
|
|
21
|
+
// OTEL instrumentation
|
|
22
|
+
let tracer, meter, batchExecutionCounter, batchDurationHistogram, parallelizationGauge;
|
|
23
|
+
if (enableOTEL) {
|
|
24
|
+
tracer = trace.getTracer('hook-executor-batching');
|
|
25
|
+
meter = otelMetrics.getMeter('hook-executor-batching');
|
|
26
|
+
|
|
27
|
+
batchExecutionCounter = meter.createCounter('hook.batch.executions', {
|
|
28
|
+
description: 'Number of batched hook executions',
|
|
29
|
+
});
|
|
30
|
+
batchDurationHistogram = meter.createHistogram('hook.batch.duration', {
|
|
31
|
+
description: 'Batch execution duration in ms',
|
|
32
|
+
unit: 'ms',
|
|
33
|
+
});
|
|
34
|
+
parallelizationGauge = meter.createUpDownCounter('hook.parallelization.ratio', {
|
|
35
|
+
description: 'Ratio of parallel to sequential executions',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Extended metrics
|
|
40
|
+
const batchMetrics = {
|
|
41
|
+
batchExecutions: 0,
|
|
42
|
+
parallelExecutions: 0,
|
|
43
|
+
sequentialExecutions: 0,
|
|
44
|
+
totalBatchDuration: 0,
|
|
45
|
+
averageBatchSize: 0,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Analyze hook dependencies to determine execution order.
|
|
50
|
+
* @param {Array} hooks - Array of hook definitions
|
|
51
|
+
* @returns {Map} Dependency graph
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
function _analyzeDependencies(hooks) {
|
|
55
|
+
const dependencies = new Map();
|
|
56
|
+
|
|
57
|
+
for (let i = 0; i < hooks.length; i++) {
|
|
58
|
+
const hook = hooks[i];
|
|
59
|
+
const hookName = hook.meta?.name || `hook-${i}`;
|
|
60
|
+
|
|
61
|
+
// Check if hook has explicit dependencies
|
|
62
|
+
const hookDeps = hook.meta?.dependencies || [];
|
|
63
|
+
|
|
64
|
+
// Check if hook modifies state (before/after hooks may have dependencies)
|
|
65
|
+
const modifiesState = !!hook.before || !!hook.after;
|
|
66
|
+
|
|
67
|
+
// If no explicit dependencies and doesn't modify state, it's independent
|
|
68
|
+
if (hookDeps.length === 0 && !modifiesState) {
|
|
69
|
+
dependencies.set(hookName, []);
|
|
70
|
+
} else {
|
|
71
|
+
dependencies.set(hookName, hookDeps);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return dependencies;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Create execution batches based on dependency analysis.
|
|
80
|
+
* Independent hooks are grouped into the same batch for parallel execution.
|
|
81
|
+
* @param {Array} hooks - Array of hook definitions
|
|
82
|
+
* @param {Map} dependencyGraph - Hook dependency graph
|
|
83
|
+
* @returns {Array} Array of batches, each containing independent hooks
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
function _createExecutionBatches(hooks, dependencyGraph) {
|
|
87
|
+
const batches = [];
|
|
88
|
+
const processed = new Set();
|
|
89
|
+
|
|
90
|
+
while (processed.size < hooks.length) {
|
|
91
|
+
const batch = [];
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < hooks.length; i++) {
|
|
94
|
+
const hook = hooks[i];
|
|
95
|
+
const hookName = hook.meta?.name || `hook-${i}`;
|
|
96
|
+
|
|
97
|
+
if (processed.has(hookName)) continue;
|
|
98
|
+
|
|
99
|
+
const deps = dependencyGraph.get(hookName) || [];
|
|
100
|
+
|
|
101
|
+
// Check if all dependencies have been processed
|
|
102
|
+
const allDepsProcessed = deps.every(dep => processed.has(dep));
|
|
103
|
+
|
|
104
|
+
if (allDepsProcessed) {
|
|
105
|
+
batch.push(hook);
|
|
106
|
+
processed.add(hookName);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (batch.length === 0) {
|
|
111
|
+
// Circular dependency or unresolvable - add remaining hooks sequentially
|
|
112
|
+
for (let i = 0; i < hooks.length; i++) {
|
|
113
|
+
const hook = hooks[i];
|
|
114
|
+
const hookName = hook.meta?.name || `hook-${i}`;
|
|
115
|
+
if (!processed.has(hookName)) {
|
|
116
|
+
batch.push(hook);
|
|
117
|
+
processed.add(hookName);
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (batch.length > 0) {
|
|
124
|
+
batches.push(batch);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return batches;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Execute hooks with batching for parallel execution (30-50% latency reduction).
|
|
133
|
+
* Analyzes hook dependencies and batches independent hooks for parallel execution.
|
|
134
|
+
* @param {Array} hooks - Array of hook definitions
|
|
135
|
+
* @param {Object} event - The hook event
|
|
136
|
+
* @param {Object} [executionOptions] - Execution-specific options
|
|
137
|
+
* @returns {Promise<Array>} Array of execution results
|
|
138
|
+
*/
|
|
139
|
+
async function executeBatched(hooks, event, executionOptions = {}) {
|
|
140
|
+
if (!Array.isArray(hooks)) {
|
|
141
|
+
throw new TypeError('executeBatched: hooks must be an array');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const startTime = Date.now();
|
|
145
|
+
const span = enableOTEL
|
|
146
|
+
? tracer.startSpan('hook.batch.execute', {
|
|
147
|
+
attributes: {
|
|
148
|
+
'batch.size': hooks.length,
|
|
149
|
+
'batch.enableBatching': enableBatching,
|
|
150
|
+
},
|
|
151
|
+
})
|
|
152
|
+
: null;
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
if (!enableBatching || hooks.length === 1) {
|
|
156
|
+
// Fall back to sequential execution
|
|
157
|
+
span?.setAttribute('batch.mode', 'sequential');
|
|
158
|
+
const results = await executor.executeSequential(hooks, event, executionOptions);
|
|
159
|
+
batchMetrics.sequentialExecutions += hooks.length;
|
|
160
|
+
span?.end();
|
|
161
|
+
return results;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Analyze hook dependencies
|
|
165
|
+
const dependencyGraph = _analyzeDependencies(hooks);
|
|
166
|
+
|
|
167
|
+
// Create execution batches (independent hooks in same batch)
|
|
168
|
+
const batches = _createExecutionBatches(hooks, dependencyGraph);
|
|
169
|
+
|
|
170
|
+
span?.setAttribute('batch.count', batches.length);
|
|
171
|
+
span?.setAttribute('batch.mode', 'batched');
|
|
172
|
+
|
|
173
|
+
const allResults = [];
|
|
174
|
+
|
|
175
|
+
// Execute batches sequentially, but hooks within each batch in parallel
|
|
176
|
+
for (let i = 0; i < batches.length; i++) {
|
|
177
|
+
const batch = batches[i];
|
|
178
|
+
const batchSpan = enableOTEL
|
|
179
|
+
? tracer.startSpan(`hook.batch.${i}`, {
|
|
180
|
+
attributes: {
|
|
181
|
+
'batch.index': i,
|
|
182
|
+
'batch.hookCount': batch.length,
|
|
183
|
+
'batch.parallelizable': batch.length > 1,
|
|
184
|
+
},
|
|
185
|
+
})
|
|
186
|
+
: null;
|
|
187
|
+
|
|
188
|
+
// Execute all hooks in this batch in parallel
|
|
189
|
+
const batchPromises = batch.map(hook => executor.execute(hook, event, executionOptions));
|
|
190
|
+
|
|
191
|
+
const batchResults = await Promise.all(batchPromises);
|
|
192
|
+
allResults.push(...batchResults);
|
|
193
|
+
|
|
194
|
+
batchSpan?.setAttribute('batch.successCount', batchResults.filter(r => r.success).length);
|
|
195
|
+
batchSpan?.setAttribute('batch.failureCount', batchResults.filter(r => !r.success).length);
|
|
196
|
+
batchSpan?.end();
|
|
197
|
+
|
|
198
|
+
// Stop on first failure in strict mode
|
|
199
|
+
if (executionOptions.strictMode && batchResults.some(r => !r.success)) {
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const duration = Date.now() - startTime;
|
|
205
|
+
batchMetrics.batchExecutions++;
|
|
206
|
+
batchMetrics.parallelExecutions += hooks.length;
|
|
207
|
+
batchMetrics.totalBatchDuration += duration;
|
|
208
|
+
batchMetrics.averageBatchSize =
|
|
209
|
+
batchMetrics.parallelExecutions / batchMetrics.batchExecutions;
|
|
210
|
+
|
|
211
|
+
// Record batch metrics
|
|
212
|
+
if (enableOTEL) {
|
|
213
|
+
batchExecutionCounter.add(1, { 'batch.count': batches.length });
|
|
214
|
+
batchDurationHistogram.record(duration, { 'batch.size': hooks.length });
|
|
215
|
+
|
|
216
|
+
const parallelRatio =
|
|
217
|
+
batchMetrics.parallelExecutions /
|
|
218
|
+
(batchMetrics.parallelExecutions + batchMetrics.sequentialExecutions);
|
|
219
|
+
parallelizationGauge.add(parallelRatio * 100);
|
|
220
|
+
|
|
221
|
+
span.setAttribute('batch.duration', duration);
|
|
222
|
+
span.setAttribute('batch.parallelizationRatio', parallelRatio);
|
|
223
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
span?.end();
|
|
227
|
+
return allResults;
|
|
228
|
+
} catch (error) {
|
|
229
|
+
if (span) {
|
|
230
|
+
span.recordException(error);
|
|
231
|
+
span.setStatus({
|
|
232
|
+
code: SpanStatusCode.ERROR,
|
|
233
|
+
message: error.message,
|
|
234
|
+
});
|
|
235
|
+
span.end();
|
|
236
|
+
}
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get batching metrics.
|
|
243
|
+
* @returns {Object} Batching metrics
|
|
244
|
+
*/
|
|
245
|
+
function getBatchingMetrics() {
|
|
246
|
+
const parallelizationRatio =
|
|
247
|
+
batchMetrics.parallelExecutions /
|
|
248
|
+
(batchMetrics.parallelExecutions + batchMetrics.sequentialExecutions || 1);
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
...batchMetrics,
|
|
252
|
+
parallelizationRatio,
|
|
253
|
+
averageBatchDuration:
|
|
254
|
+
batchMetrics.batchExecutions > 0
|
|
255
|
+
? batchMetrics.totalBatchDuration / batchMetrics.batchExecutions
|
|
256
|
+
: 0,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Extend executor with batching capabilities
|
|
261
|
+
return {
|
|
262
|
+
...executor,
|
|
263
|
+
executeBatched,
|
|
264
|
+
getBatchingMetrics,
|
|
265
|
+
executeWithDependencies: executeBatched, // Override with batching implementation
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Create a hook executor with batching capabilities.
|
|
271
|
+
* @param {Object} executor - Base hook executor
|
|
272
|
+
* @param {Object} [options] - Batching options
|
|
273
|
+
* @returns {Object} Extended executor
|
|
274
|
+
*/
|
|
275
|
+
export function createBatchingExecutor(executor, options = {}) {
|
|
276
|
+
return addBatchingCapabilities(executor, options);
|
|
277
|
+
}
|