@trillboards/edge-core 0.2.1 → 0.2.3
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/JsonFileStore.d.ts +33 -0
- package/dist/JsonFileStore.d.ts.map +1 -0
- package/dist/JsonFileStore.js +210 -0
- package/dist/JsonFileStore.js.map +1 -0
- package/dist/MemoryAttenuationManager.d.ts +164 -0
- package/dist/MemoryAttenuationManager.d.ts.map +1 -0
- package/dist/MemoryAttenuationManager.js +400 -0
- package/dist/MemoryAttenuationManager.js.map +1 -0
- package/dist/ModelManager.d.ts +166 -0
- package/dist/ModelManager.d.ts.map +1 -0
- package/dist/ModelManager.js +580 -0
- package/dist/ModelManager.js.map +1 -0
- package/dist/SignalBuffer.d.ts +20 -12
- package/dist/SignalBuffer.d.ts.map +1 -1
- package/dist/SignalBuffer.js +56 -71
- package/dist/SignalBuffer.js.map +1 -1
- package/dist/SignalStore.d.ts +35 -0
- package/dist/SignalStore.d.ts.map +1 -0
- package/dist/SignalStore.js +13 -0
- package/dist/SignalStore.js.map +1 -0
- package/dist/SqliteStore.d.ts +41 -0
- package/dist/SqliteStore.d.ts.map +1 -0
- package/dist/SqliteStore.js +162 -0
- package/dist/SqliteStore.js.map +1 -0
- package/dist/StatusServer.d.ts +99 -0
- package/dist/StatusServer.d.ts.map +1 -0
- package/dist/StatusServer.js +262 -0
- package/dist/StatusServer.js.map +1 -0
- package/dist/ZKAudienceProver.d.ts +137 -0
- package/dist/ZKAudienceProver.d.ts.map +1 -0
- package/dist/ZKAudienceProver.js +321 -0
- package/dist/ZKAudienceProver.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +40 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MemoryAttenuationManager — Monitors V8 heap and OS memory, applies tiered
|
|
4
|
+
* shedding to keep edge devices stable under pressure.
|
|
5
|
+
*
|
|
6
|
+
* Port of CTV agent's MemoryAttenuationManager.kt, adapted for the V8 heap
|
|
7
|
+
* model. Uses `process.memoryUsage()` for heap metrics and `os.freemem()` /
|
|
8
|
+
* `os.totalmem()` for system-level awareness.
|
|
9
|
+
*
|
|
10
|
+
* Tiers (based on heap usage percentage = heapUsed / heapTotal):
|
|
11
|
+
* GREEN — Normal operation, all systems active
|
|
12
|
+
* YELLOW — >70% heap — disable cloud inference
|
|
13
|
+
* ORANGE — >80% heap — disable federated learning, reduce FPS
|
|
14
|
+
* RED — >90% heap — shed lowest-priority models (one per cycle)
|
|
15
|
+
* CRITICAL — >95% heap — camera-only emergency mode, force GC
|
|
16
|
+
*
|
|
17
|
+
* Hysteresis prevents oscillation: a tier is only restored when usage drops
|
|
18
|
+
* a configurable percentage (default 15%) below the threshold that triggered
|
|
19
|
+
* escalation. For example, YELLOW triggers at 70% but only restores to GREEN
|
|
20
|
+
* when usage falls below 55%.
|
|
21
|
+
*/
|
|
22
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
25
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
26
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
27
|
+
}
|
|
28
|
+
Object.defineProperty(o, k2, desc);
|
|
29
|
+
}) : (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
o[k2] = m[k];
|
|
32
|
+
}));
|
|
33
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
34
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
35
|
+
}) : function(o, v) {
|
|
36
|
+
o["default"] = v;
|
|
37
|
+
});
|
|
38
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.MemoryAttenuationManager = exports.MemoryTier = void 0;
|
|
47
|
+
const events_1 = require("events");
|
|
48
|
+
const os = __importStar(require("os"));
|
|
49
|
+
// ─── Public Types ───────────────────────────────────────────────────────────
|
|
50
|
+
var MemoryTier;
|
|
51
|
+
(function (MemoryTier) {
|
|
52
|
+
MemoryTier["GREEN"] = "GREEN";
|
|
53
|
+
MemoryTier["YELLOW"] = "YELLOW";
|
|
54
|
+
MemoryTier["ORANGE"] = "ORANGE";
|
|
55
|
+
MemoryTier["RED"] = "RED";
|
|
56
|
+
MemoryTier["CRITICAL"] = "CRITICAL";
|
|
57
|
+
})(MemoryTier || (exports.MemoryTier = MemoryTier = {}));
|
|
58
|
+
// ─── Internal Constants ─────────────────────────────────────────────────────
|
|
59
|
+
const MB = 1024 * 1024;
|
|
60
|
+
const MAX_HISTORY = 100;
|
|
61
|
+
const MAX_ACTIONS = 200;
|
|
62
|
+
const DEFAULT_CHECK_INTERVAL_MS = 10000;
|
|
63
|
+
const DEFAULT_YELLOW_THRESHOLD = 0.70;
|
|
64
|
+
const DEFAULT_ORANGE_THRESHOLD = 0.80;
|
|
65
|
+
const DEFAULT_RED_THRESHOLD = 0.90;
|
|
66
|
+
const DEFAULT_CRITICAL_THRESHOLD = 0.95;
|
|
67
|
+
const DEFAULT_HYSTERESIS_PERCENT = 0.15;
|
|
68
|
+
const DEFAULT_NORMAL_FPS = 8;
|
|
69
|
+
const DEFAULT_REDUCED_FPS = 2;
|
|
70
|
+
const DEFAULT_SHED_ORDER = [
|
|
71
|
+
'yamnet',
|
|
72
|
+
'whisperAsr',
|
|
73
|
+
'ferEmotion',
|
|
74
|
+
'poseEngagement',
|
|
75
|
+
'ageGender',
|
|
76
|
+
'gazeTracking',
|
|
77
|
+
];
|
|
78
|
+
/**
|
|
79
|
+
* Ordered tier list from lowest severity to highest. Used for comparison
|
|
80
|
+
* and iteration when escalating or restoring.
|
|
81
|
+
*/
|
|
82
|
+
const TIER_SEVERITY = [
|
|
83
|
+
MemoryTier.GREEN,
|
|
84
|
+
MemoryTier.YELLOW,
|
|
85
|
+
MemoryTier.ORANGE,
|
|
86
|
+
MemoryTier.RED,
|
|
87
|
+
MemoryTier.CRITICAL,
|
|
88
|
+
];
|
|
89
|
+
function tierIndex(tier) {
|
|
90
|
+
return TIER_SEVERITY.indexOf(tier);
|
|
91
|
+
}
|
|
92
|
+
// ─── Implementation ─────────────────────────────────────────────────────────
|
|
93
|
+
class MemoryAttenuationManager extends events_1.EventEmitter {
|
|
94
|
+
constructor(options) {
|
|
95
|
+
super();
|
|
96
|
+
// Runtime state
|
|
97
|
+
this.currentTier = MemoryTier.GREEN;
|
|
98
|
+
this.intervalHandle = null;
|
|
99
|
+
this.history = [];
|
|
100
|
+
this.actions = [];
|
|
101
|
+
// Tracked attenuation state — what we have already told callers to do
|
|
102
|
+
this.cloudInferenceDisabled = false;
|
|
103
|
+
this.federatedLearningDisabled = false;
|
|
104
|
+
this.fpsReduced = false;
|
|
105
|
+
this.shedModels = new Set();
|
|
106
|
+
this.emergencyModeActive = false;
|
|
107
|
+
this.callbacks = options.callbacks;
|
|
108
|
+
this.checkIntervalMs = options.checkIntervalMs ?? DEFAULT_CHECK_INTERVAL_MS;
|
|
109
|
+
this.yellowThreshold = options.yellowThreshold ?? DEFAULT_YELLOW_THRESHOLD;
|
|
110
|
+
this.orangeThreshold = options.orangeThreshold ?? DEFAULT_ORANGE_THRESHOLD;
|
|
111
|
+
this.redThreshold = options.redThreshold ?? DEFAULT_RED_THRESHOLD;
|
|
112
|
+
this.criticalThreshold = options.criticalThreshold ?? DEFAULT_CRITICAL_THRESHOLD;
|
|
113
|
+
this.hysteresisPercent = options.hysteresisPercent ?? DEFAULT_HYSTERESIS_PERCENT;
|
|
114
|
+
this.normalFps = options.normalFps ?? DEFAULT_NORMAL_FPS;
|
|
115
|
+
this.reducedFps = options.reducedFps ?? DEFAULT_REDUCED_FPS;
|
|
116
|
+
this.shedOrder = options.shedOrder ? [...options.shedOrder] : [...DEFAULT_SHED_ORDER];
|
|
117
|
+
}
|
|
118
|
+
// ─── Public API ─────────────────────────────────────────────────────────
|
|
119
|
+
/**
|
|
120
|
+
* Start the periodic memory monitoring interval. The timer is `unref()`'d
|
|
121
|
+
* so it will not keep the Node.js event loop alive on its own.
|
|
122
|
+
*/
|
|
123
|
+
start() {
|
|
124
|
+
if (this.intervalHandle !== null)
|
|
125
|
+
return;
|
|
126
|
+
this.intervalHandle = setInterval(() => this.check(), this.checkIntervalMs);
|
|
127
|
+
this.intervalHandle.unref();
|
|
128
|
+
}
|
|
129
|
+
/** Stop the periodic monitoring interval. */
|
|
130
|
+
stop() {
|
|
131
|
+
if (this.intervalHandle !== null) {
|
|
132
|
+
clearInterval(this.intervalHandle);
|
|
133
|
+
this.intervalHandle = null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** Return the current memory tier. */
|
|
137
|
+
getCurrentTier() {
|
|
138
|
+
return this.currentTier;
|
|
139
|
+
}
|
|
140
|
+
/** Take a point-in-time memory snapshot (does NOT trigger actions). */
|
|
141
|
+
getSnapshot() {
|
|
142
|
+
return this.takeSnapshot();
|
|
143
|
+
}
|
|
144
|
+
/** Return the last N snapshots (up to 100). */
|
|
145
|
+
getHistory() {
|
|
146
|
+
return [...this.history];
|
|
147
|
+
}
|
|
148
|
+
/** Return the list of model names currently shed. */
|
|
149
|
+
getShedModels() {
|
|
150
|
+
return [...this.shedModels];
|
|
151
|
+
}
|
|
152
|
+
/** Return the full log of attenuation actions taken. */
|
|
153
|
+
getActions() {
|
|
154
|
+
return [...this.actions];
|
|
155
|
+
}
|
|
156
|
+
// ─── Core Check Loop ───────────────────────────────────────────────────
|
|
157
|
+
/**
|
|
158
|
+
* Single check cycle. Exposed as package-internal so tests can drive it
|
|
159
|
+
* deterministically without timers.
|
|
160
|
+
*/
|
|
161
|
+
check() {
|
|
162
|
+
const snapshot = this.takeSnapshot();
|
|
163
|
+
// Record history (ring buffer, capped at MAX_HISTORY)
|
|
164
|
+
this.history.push(snapshot);
|
|
165
|
+
if (this.history.length > MAX_HISTORY) {
|
|
166
|
+
this.history.shift();
|
|
167
|
+
}
|
|
168
|
+
const newTier = this.classifyTier(snapshot.heapUsedPercent);
|
|
169
|
+
if (newTier !== this.currentTier) {
|
|
170
|
+
const previousTier = this.currentTier;
|
|
171
|
+
this.currentTier = newTier;
|
|
172
|
+
snapshot.tier = newTier;
|
|
173
|
+
// Apply actions for every step between old and new tier
|
|
174
|
+
const oldIdx = tierIndex(previousTier);
|
|
175
|
+
const newIdx = tierIndex(newTier);
|
|
176
|
+
if (newIdx > oldIdx) {
|
|
177
|
+
// Escalating — apply each step from old+1 up to new
|
|
178
|
+
for (let i = oldIdx + 1; i <= newIdx; i++) {
|
|
179
|
+
this.applyEscalation(TIER_SEVERITY[i]);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// Restoring — apply each step from old-1 down to new
|
|
184
|
+
for (let i = oldIdx - 1; i >= newIdx; i--) {
|
|
185
|
+
this.applyRestoration(TIER_SEVERITY[i]);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
this.emit('tierChanged', {
|
|
189
|
+
from: previousTier,
|
|
190
|
+
to: newTier,
|
|
191
|
+
snapshot,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
else if (newTier === MemoryTier.RED) {
|
|
195
|
+
// While staying in RED, shed one more model per cycle if available
|
|
196
|
+
this.shedNextModel();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// ─── Tier Classification (with hysteresis) ─────────────────────────────
|
|
200
|
+
/**
|
|
201
|
+
* Classify a heap usage percentage into a MemoryTier, applying hysteresis
|
|
202
|
+
* to prevent oscillation at tier boundaries.
|
|
203
|
+
*
|
|
204
|
+
* Escalation uses the raw threshold (jumps to the highest applicable tier).
|
|
205
|
+
* Restoration requires the usage to drop below `threshold - hysteresisPercent`
|
|
206
|
+
* at each boundary, and walks down through all qualifying tiers in a single
|
|
207
|
+
* check. For example with default settings:
|
|
208
|
+
* - Escalate to YELLOW at 70%, restore to GREEN below 55% (70 - 15)
|
|
209
|
+
* - Escalate to ORANGE at 80%, restore to YELLOW below 65% (80 - 15)
|
|
210
|
+
* - Escalate to RED at 90%, restore to ORANGE below 75% (90 - 15)
|
|
211
|
+
* - Escalate to CRITICAL at 95%, restore to RED below 80% (95 - 15)
|
|
212
|
+
*/
|
|
213
|
+
classifyTier(heapUsedPercent) {
|
|
214
|
+
const currentIdx = tierIndex(this.currentTier);
|
|
215
|
+
// Check for escalation (use raw thresholds, jump to highest applicable)
|
|
216
|
+
if (heapUsedPercent >= this.criticalThreshold * 100 && currentIdx < tierIndex(MemoryTier.CRITICAL)) {
|
|
217
|
+
return MemoryTier.CRITICAL;
|
|
218
|
+
}
|
|
219
|
+
if (heapUsedPercent >= this.redThreshold * 100 && currentIdx < tierIndex(MemoryTier.RED)) {
|
|
220
|
+
return MemoryTier.RED;
|
|
221
|
+
}
|
|
222
|
+
if (heapUsedPercent >= this.orangeThreshold * 100 && currentIdx < tierIndex(MemoryTier.ORANGE)) {
|
|
223
|
+
return MemoryTier.ORANGE;
|
|
224
|
+
}
|
|
225
|
+
if (heapUsedPercent >= this.yellowThreshold * 100 && currentIdx < tierIndex(MemoryTier.YELLOW)) {
|
|
226
|
+
return MemoryTier.YELLOW;
|
|
227
|
+
}
|
|
228
|
+
// Check for restoration — walk downward through each tier boundary,
|
|
229
|
+
// applying hysteresis at each step. This allows multi-step drops in a
|
|
230
|
+
// single check when memory falls far enough.
|
|
231
|
+
const hysteresisThresholds = [
|
|
232
|
+
{ tier: MemoryTier.CRITICAL, restoreBelow: (this.criticalThreshold - this.hysteresisPercent) * 100 },
|
|
233
|
+
{ tier: MemoryTier.RED, restoreBelow: (this.redThreshold - this.hysteresisPercent) * 100 },
|
|
234
|
+
{ tier: MemoryTier.ORANGE, restoreBelow: (this.orangeThreshold - this.hysteresisPercent) * 100 },
|
|
235
|
+
{ tier: MemoryTier.YELLOW, restoreBelow: (this.yellowThreshold - this.hysteresisPercent) * 100 },
|
|
236
|
+
];
|
|
237
|
+
let resolvedTier = this.currentTier;
|
|
238
|
+
for (const { tier, restoreBelow } of hysteresisThresholds) {
|
|
239
|
+
if (resolvedTier === tier && heapUsedPercent < restoreBelow) {
|
|
240
|
+
// Drop one level
|
|
241
|
+
const idx = tierIndex(tier);
|
|
242
|
+
resolvedTier = TIER_SEVERITY[idx - 1];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return resolvedTier;
|
|
246
|
+
}
|
|
247
|
+
// ─── Escalation Actions ────────────────────────────────────────────────
|
|
248
|
+
/** Apply the actions for entering a given tier (escalating). */
|
|
249
|
+
applyEscalation(tier) {
|
|
250
|
+
switch (tier) {
|
|
251
|
+
case MemoryTier.YELLOW:
|
|
252
|
+
if (!this.cloudInferenceDisabled) {
|
|
253
|
+
this.cloudInferenceDisabled = true;
|
|
254
|
+
this.callbacks.onDisableCloudInference();
|
|
255
|
+
this.recordAction(tier, 'disable_cloud_inference');
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
case MemoryTier.ORANGE:
|
|
259
|
+
if (!this.federatedLearningDisabled) {
|
|
260
|
+
this.federatedLearningDisabled = true;
|
|
261
|
+
this.callbacks.onDisableFederatedLearning();
|
|
262
|
+
this.recordAction(tier, 'disable_federated_learning');
|
|
263
|
+
}
|
|
264
|
+
if (!this.fpsReduced) {
|
|
265
|
+
this.fpsReduced = true;
|
|
266
|
+
this.callbacks.onReduceSensingFps(this.reducedFps);
|
|
267
|
+
this.recordAction(tier, `reduce_fps_to_${this.reducedFps}`);
|
|
268
|
+
}
|
|
269
|
+
break;
|
|
270
|
+
case MemoryTier.RED:
|
|
271
|
+
this.shedNextModel();
|
|
272
|
+
break;
|
|
273
|
+
case MemoryTier.CRITICAL:
|
|
274
|
+
if (!this.emergencyModeActive) {
|
|
275
|
+
this.emergencyModeActive = true;
|
|
276
|
+
this.callbacks.onEmergencyMode();
|
|
277
|
+
this.recordAction(tier, 'emergency_mode');
|
|
278
|
+
}
|
|
279
|
+
// Attempt GC if exposed via --expose-gc
|
|
280
|
+
if (typeof global.gc === 'function') {
|
|
281
|
+
global.gc();
|
|
282
|
+
}
|
|
283
|
+
this.callbacks.onForceGC();
|
|
284
|
+
this.recordAction(tier, 'force_gc');
|
|
285
|
+
break;
|
|
286
|
+
case MemoryTier.GREEN:
|
|
287
|
+
// No escalation action for GREEN
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// ─── Restoration Actions ───────────────────────────────────────────────
|
|
292
|
+
/**
|
|
293
|
+
* Apply the restoration actions for entering a given tier (de-escalating).
|
|
294
|
+
* `tier` is the tier we are *entering* on the way down.
|
|
295
|
+
*/
|
|
296
|
+
applyRestoration(tier) {
|
|
297
|
+
switch (tier) {
|
|
298
|
+
case MemoryTier.RED:
|
|
299
|
+
// Leaving CRITICAL → RED: restore emergency mode
|
|
300
|
+
if (this.emergencyModeActive) {
|
|
301
|
+
this.emergencyModeActive = false;
|
|
302
|
+
this.recordAction(tier, 'exit_emergency_mode');
|
|
303
|
+
}
|
|
304
|
+
break;
|
|
305
|
+
case MemoryTier.ORANGE:
|
|
306
|
+
// Leaving RED → ORANGE: restore all shed models in reverse order
|
|
307
|
+
this.restoreAllShedModels();
|
|
308
|
+
break;
|
|
309
|
+
case MemoryTier.YELLOW:
|
|
310
|
+
// Leaving ORANGE → YELLOW: restore FPS and federated learning
|
|
311
|
+
if (this.fpsReduced) {
|
|
312
|
+
this.fpsReduced = false;
|
|
313
|
+
this.callbacks.onRestoreSensingFps(this.normalFps);
|
|
314
|
+
this.recordAction(tier, `restore_fps_to_${this.normalFps}`);
|
|
315
|
+
}
|
|
316
|
+
if (this.federatedLearningDisabled) {
|
|
317
|
+
this.federatedLearningDisabled = false;
|
|
318
|
+
this.callbacks.onEnableFederatedLearning();
|
|
319
|
+
this.recordAction(tier, 'enable_federated_learning');
|
|
320
|
+
}
|
|
321
|
+
break;
|
|
322
|
+
case MemoryTier.GREEN:
|
|
323
|
+
// Leaving YELLOW → GREEN: restore cloud inference
|
|
324
|
+
if (this.cloudInferenceDisabled) {
|
|
325
|
+
this.cloudInferenceDisabled = false;
|
|
326
|
+
this.callbacks.onEnableCloudInference();
|
|
327
|
+
this.recordAction(tier, 'enable_cloud_inference');
|
|
328
|
+
}
|
|
329
|
+
this.callbacks.onRestoreNormal();
|
|
330
|
+
this.recordAction(tier, 'restore_normal');
|
|
331
|
+
break;
|
|
332
|
+
case MemoryTier.CRITICAL:
|
|
333
|
+
// No restoration for entering CRITICAL (only escalation)
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// ─── Model Shedding ───────────────────────────────────────────────────
|
|
338
|
+
/**
|
|
339
|
+
* Shed the next model in the shed order. Models are shed from the *end*
|
|
340
|
+
* of `shedOrder` (lowest priority) toward the beginning (highest priority).
|
|
341
|
+
* One model per call.
|
|
342
|
+
*/
|
|
343
|
+
shedNextModel() {
|
|
344
|
+
// Walk backwards from end of shedOrder, skipping already-shed models
|
|
345
|
+
for (let i = this.shedOrder.length - 1; i >= 0; i--) {
|
|
346
|
+
const model = this.shedOrder[i];
|
|
347
|
+
if (!this.shedModels.has(model)) {
|
|
348
|
+
this.shedModels.add(model);
|
|
349
|
+
this.callbacks.onShedModel(model);
|
|
350
|
+
this.recordAction(MemoryTier.RED, `shed_model_${model}`);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// All models already shed — nothing more to do
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Restore all shed models in reverse order (highest priority first,
|
|
358
|
+
* i.e., from the beginning of `shedOrder`).
|
|
359
|
+
*/
|
|
360
|
+
restoreAllShedModels() {
|
|
361
|
+
// Restore in forward order through shedOrder (most important first)
|
|
362
|
+
for (const model of this.shedOrder) {
|
|
363
|
+
if (this.shedModels.has(model)) {
|
|
364
|
+
this.shedModels.delete(model);
|
|
365
|
+
this.callbacks.onRestoreModel(model);
|
|
366
|
+
this.recordAction(MemoryTier.ORANGE, `restore_model_${model}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// ─── Snapshot / Recording ──────────────────────────────────────────────
|
|
371
|
+
takeSnapshot() {
|
|
372
|
+
const mem = process.memoryUsage();
|
|
373
|
+
const osTotalBytes = os.totalmem();
|
|
374
|
+
const osFreeBytes = os.freemem();
|
|
375
|
+
const osUsedBytes = osTotalBytes - osFreeBytes;
|
|
376
|
+
return {
|
|
377
|
+
heapUsedMb: Math.round((mem.heapUsed / MB) * 100) / 100,
|
|
378
|
+
heapTotalMb: Math.round((mem.heapTotal / MB) * 100) / 100,
|
|
379
|
+
heapUsedPercent: Math.round((mem.heapUsed / mem.heapTotal) * 10000) / 100,
|
|
380
|
+
rssUsedMb: Math.round((mem.rss / MB) * 100) / 100,
|
|
381
|
+
osFreeMemMb: Math.round((osFreeBytes / MB) * 100) / 100,
|
|
382
|
+
osTotalMemMb: Math.round((osTotalBytes / MB) * 100) / 100,
|
|
383
|
+
osUsedPercent: Math.round((osUsedBytes / osTotalBytes) * 10000) / 100,
|
|
384
|
+
tier: this.currentTier,
|
|
385
|
+
timestamp: Date.now(),
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
recordAction(tier, action) {
|
|
389
|
+
this.actions.push({
|
|
390
|
+
tier,
|
|
391
|
+
action,
|
|
392
|
+
timestamp: Date.now(),
|
|
393
|
+
});
|
|
394
|
+
if (this.actions.length > MAX_ACTIONS) {
|
|
395
|
+
this.actions.shift();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
exports.MemoryAttenuationManager = MemoryAttenuationManager;
|
|
400
|
+
//# sourceMappingURL=MemoryAttenuationManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MemoryAttenuationManager.js","sourceRoot":"","sources":["../src/MemoryAttenuationManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelManager — Model lifecycle management with OTA (over-the-air) updates.
|
|
3
|
+
* Port of CTV agent's ModelManager.kt (387 lines), adapted for Node.js/ONNX.
|
|
4
|
+
*
|
|
5
|
+
* Manages registration, version-checking, and atomic download of ML model files.
|
|
6
|
+
* Downloads use a .tmp + rename pattern to prevent corrupted model loads.
|
|
7
|
+
* The version check timer is unref()'d so it does not keep the process alive.
|
|
8
|
+
*
|
|
9
|
+
* Events emitted:
|
|
10
|
+
* 'modelUpdated' — { name, oldVersion, newVersion, path }
|
|
11
|
+
* 'updateAvailable' — { name, currentVersion, availableVersion }
|
|
12
|
+
* 'downloadProgress' — { name, bytesDownloaded, totalBytes, percent }
|
|
13
|
+
* 'downloadError' — { name, error }
|
|
14
|
+
* 'checkComplete' — { checkedCount, updatesAvailable }
|
|
15
|
+
*/
|
|
16
|
+
/// <reference types="node" />
|
|
17
|
+
import { EventEmitter } from 'events';
|
|
18
|
+
export interface ModelInfo {
|
|
19
|
+
/** Model identifier, e.g. 'blazeface', 'yamnet', 'ageGender'. */
|
|
20
|
+
name: string;
|
|
21
|
+
/** Semver version string, e.g. '1.2.0'. */
|
|
22
|
+
version: string;
|
|
23
|
+
/** Absolute path to the .onnx file on disk. */
|
|
24
|
+
filePath: string;
|
|
25
|
+
/** SHA-256 hex digest of the current file. */
|
|
26
|
+
sha256: string;
|
|
27
|
+
/** File size in bytes. */
|
|
28
|
+
sizeBytes: number;
|
|
29
|
+
/** Timestamp (ms) of last version check against the API. */
|
|
30
|
+
lastChecked: number;
|
|
31
|
+
/** Timestamp (ms) of last successful download. */
|
|
32
|
+
lastUpdated: number;
|
|
33
|
+
}
|
|
34
|
+
export interface ModelVersionResponse {
|
|
35
|
+
name: string;
|
|
36
|
+
version: string;
|
|
37
|
+
sha256: string;
|
|
38
|
+
downloadUrl: string;
|
|
39
|
+
sizeBytes: number;
|
|
40
|
+
releaseNotes?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ModelManagerOptions {
|
|
43
|
+
/** Directory for storing model files and manifest. */
|
|
44
|
+
modelsDir: string;
|
|
45
|
+
/** Backend API base URL (e.g. 'https://api.trillboards.com'). */
|
|
46
|
+
apiBaseUrl: string;
|
|
47
|
+
/** Device fingerprint for the version-check API call. */
|
|
48
|
+
deviceFingerprint: string;
|
|
49
|
+
/** Interval between automatic version checks. Default: 3600000 (1 hour). */
|
|
50
|
+
checkIntervalMs?: number;
|
|
51
|
+
/** Maximum concurrent model downloads. Default: 1. */
|
|
52
|
+
maxConcurrentDownloads?: number;
|
|
53
|
+
/** Whether to auto-download discovered updates. Default: true. */
|
|
54
|
+
autoUpdate?: boolean;
|
|
55
|
+
/** Request timeout for API calls in milliseconds. Default: 30000. */
|
|
56
|
+
requestTimeoutMs?: number;
|
|
57
|
+
/** Request timeout for file downloads in milliseconds. Default: 300000 (5 min). */
|
|
58
|
+
downloadTimeoutMs?: number;
|
|
59
|
+
/** Maximum number of HTTP redirects to follow. Default: 5. */
|
|
60
|
+
maxRedirects?: number;
|
|
61
|
+
}
|
|
62
|
+
export declare class ModelManager extends EventEmitter {
|
|
63
|
+
private models;
|
|
64
|
+
private readonly options;
|
|
65
|
+
private checkTimer;
|
|
66
|
+
private downloading;
|
|
67
|
+
private readonly manifestPath;
|
|
68
|
+
constructor(options: ModelManagerOptions);
|
|
69
|
+
/**
|
|
70
|
+
* Initialize — ensure models directory exists, load manifest, compute
|
|
71
|
+
* hashes for any registered model files already on disk.
|
|
72
|
+
*/
|
|
73
|
+
initialize(): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Start periodic version checking. The timer is unref()'d so it does not
|
|
76
|
+
* prevent the Node.js process from exiting naturally.
|
|
77
|
+
*/
|
|
78
|
+
start(): void;
|
|
79
|
+
/**
|
|
80
|
+
* Stop periodic checking and cancel any in-flight state tracking.
|
|
81
|
+
*/
|
|
82
|
+
stop(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Register a model to track. Called during EdgeAgent init for each model type.
|
|
85
|
+
* If the file exists on disk, its SHA-256 is computed immediately.
|
|
86
|
+
* If the manifest already has version info for this name, it is merged.
|
|
87
|
+
*/
|
|
88
|
+
registerModel(name: string, filePath: string): void;
|
|
89
|
+
/**
|
|
90
|
+
* Check for updates for all registered models by calling the backend API.
|
|
91
|
+
* Endpoint: GET /v1/federated/models?deviceFingerprint=X&modelType=Y
|
|
92
|
+
*
|
|
93
|
+
* Returns the list of ModelVersionResponse objects for which a newer
|
|
94
|
+
* version is available. If autoUpdate is enabled, downloads are
|
|
95
|
+
* initiated automatically (respecting maxConcurrentDownloads).
|
|
96
|
+
*/
|
|
97
|
+
checkForUpdates(): Promise<ModelVersionResponse[]>;
|
|
98
|
+
/**
|
|
99
|
+
* Download a specific model update.
|
|
100
|
+
*
|
|
101
|
+
* 1. Download to a .tmp file alongside the target path
|
|
102
|
+
* 2. Verify SHA-256 checksum matches the expected value
|
|
103
|
+
* 3. Atomic swap: rename .tmp -> target .onnx path
|
|
104
|
+
* 4. Update manifest with new version info
|
|
105
|
+
* 5. Emit 'modelUpdated' event
|
|
106
|
+
*
|
|
107
|
+
* Returns true if the model was successfully downloaded and verified.
|
|
108
|
+
*/
|
|
109
|
+
downloadUpdate(update: ModelVersionResponse): Promise<boolean>;
|
|
110
|
+
/**
|
|
111
|
+
* Get info about a registered model. Returns null if not registered.
|
|
112
|
+
*/
|
|
113
|
+
getModel(name: string): ModelInfo | null;
|
|
114
|
+
/**
|
|
115
|
+
* Get all registered models.
|
|
116
|
+
*/
|
|
117
|
+
getModels(): ModelInfo[];
|
|
118
|
+
/**
|
|
119
|
+
* Check if a model's file exists on disk.
|
|
120
|
+
*/
|
|
121
|
+
hasModel(name: string): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Check if a download is currently in progress for a model.
|
|
124
|
+
*/
|
|
125
|
+
isDownloading(name: string): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Compute the SHA-256 hex digest of a file using a streaming reader.
|
|
128
|
+
*/
|
|
129
|
+
private computeFileHash;
|
|
130
|
+
/**
|
|
131
|
+
* Download a file from a URL to a local destination path.
|
|
132
|
+
* Follows HTTP redirects (up to maxRedirects), emits progress events,
|
|
133
|
+
* and enforces a download timeout.
|
|
134
|
+
*/
|
|
135
|
+
private downloadFile;
|
|
136
|
+
private downloadFileWithRedirects;
|
|
137
|
+
/**
|
|
138
|
+
* Load model manifest from disk. If the file does not exist or is corrupt,
|
|
139
|
+
* start with an empty manifest — never crash.
|
|
140
|
+
*/
|
|
141
|
+
private loadManifest;
|
|
142
|
+
/**
|
|
143
|
+
* Save the current model state to the manifest file on disk.
|
|
144
|
+
* Uses atomic write: write to .tmp, then rename.
|
|
145
|
+
*/
|
|
146
|
+
private saveManifest;
|
|
147
|
+
/**
|
|
148
|
+
* Make an HTTPS GET request to the backend API and return parsed JSON.
|
|
149
|
+
*/
|
|
150
|
+
private apiGet;
|
|
151
|
+
/**
|
|
152
|
+
* Verify that a model file exists on disk, recompute its hash if present,
|
|
153
|
+
* or clear stale info if the file has been deleted.
|
|
154
|
+
*/
|
|
155
|
+
private verifyModelOnDisk;
|
|
156
|
+
/**
|
|
157
|
+
* Semver comparison: returns true if `available` is strictly newer than `current`.
|
|
158
|
+
* Handles non-semver gracefully by falling back to string comparison.
|
|
159
|
+
*/
|
|
160
|
+
private isNewerVersion;
|
|
161
|
+
/**
|
|
162
|
+
* Safely remove a .tmp file if it exists. Never throws.
|
|
163
|
+
*/
|
|
164
|
+
private cleanupTmpFile;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=ModelManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelManager.d.ts","sourceRoot":"","sources":["../src/ModelManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAStC,MAAM,WAAW,SAAS;IACxB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAiBD,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,OAAO,EAAE,mBAAmB;IAkBxC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAajC;;;OAGG;IACH,KAAK,IAAI,IAAI;IAgBb;;OAEG;IACH,IAAI,IAAI,IAAI;IASZ;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAyBnD;;;;;;;OAOG;IACG,eAAe,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAwDxD;;;;;;;;;;OAUG;IACG,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;IA6EpE;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAIxC;;OAEG;IACH,SAAS,IAAI,SAAS,EAAE;IAIxB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAM/B;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAMpC;;OAEG;IACH,OAAO,CAAC,eAAe;IAYvB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,yBAAyB;IA0GjC;;;OAGG;IACH,OAAO,CAAC,YAAY;IAsCpB;;;OAGG;IACH,OAAO,CAAC,YAAY;IA6BpB;;OAEG;IACH,OAAO,CAAC,MAAM;IAmDd;;;OAGG;YACW,iBAAiB;IAmB/B;;;OAGG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;IACH,OAAO,CAAC,cAAc;CASvB"}
|