@camstack/addon-pipeline 1.2.118 → 1.2.119
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/{addon-utils-DJSN5h8c.js → addon-utils-RAHF2hmW.js} +1 -1
- package/dist/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/detection-pipeline/index.js +171 -167
- package/dist/detection-pipeline/index.mjs +169 -165
- package/dist/{dist-BkO76jAp.js → dist-DIsM42Ex.js} +99 -2
- package/dist/{dist-B763E61Y.mjs → dist-Db664g2O.mjs} +94 -3
- package/dist/{event-loop-stall-monitor-28f4R0JN.js → event-loop-stall-monitor-CSpdFZb6.js} +1 -1
- package/dist/{event-loop-stall-monitor-CYEvvp2Z.mjs → event-loop-stall-monitor-DY6339bX.mjs} +1 -1
- package/dist/{lazy-sharp-BaPl5mRa.js → lazy-sharp-LSlEXQe_.js} +1 -1
- package/dist/motion-wasm/index.js +2 -2
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +12 -14
- package/dist/pipeline-runner/index.mjs +11 -13
- package/dist/{process-memory-CK3FnKyZ.mjs → process-memory-CPm5TMBl.mjs} +1 -1
- package/dist/{process-memory-BCQJFZZg.js → process-memory-DpSJQF-p.js} +1 -1
- package/dist/recorder/index.js +2 -2
- package/dist/recorder/index.mjs +1 -1
- package/dist/session-decode/decode-worker-child.js +2 -2
- package/dist/session-decode/decode-worker-child.mjs +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CxgvfkxP.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CstvrzmK.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BiNja8Hw.mjs +26 -0
- package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BAMyzCWw.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-D-NFPV_g.mjs} +1 -1
- package/dist/stream-broker/{hostInit-CTkpxp3w.mjs → hostInit-kHeLqEod.mjs} +2 -2
- package/dist/stream-broker/index.js +8 -6
- package/dist/stream-broker/index.mjs +8 -6
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-owR7WMRP.js → worker-protocol-C1tr8WP3.js} +1 -1
- package/dist/{worker-protocol-D_2QaXYr.mjs → worker-protocol-_zMPqSas.mjs} +1 -1
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CL6Lgzdj.mjs +0 -26
|
@@ -2,9 +2,9 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_process_memory = require("../process-memory-
|
|
7
|
-
const require_addon_utils = require("../addon-utils-
|
|
5
|
+
const require_dist = require("../dist-DIsM42Ex.js");
|
|
6
|
+
const require_process_memory = require("../process-memory-DpSJQF-p.js");
|
|
7
|
+
const require_addon_utils = require("../addon-utils-RAHF2hmW.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_dist.__toESM(node_path);
|
|
10
10
|
let node_fs = require("node:fs");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { A as audioAnalyzerCapability,
|
|
3
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
2
|
+
import { A as audioAnalyzerCapability, Dt as hydrateSchema, J as mapAudioLabelToMacro, St as BaseAddon, _ as HF_BASE_URL, gt as errMsg, k as audioAnalysisCapability, lt as resolvePoolMemoryPolicy, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, x as PoolMemoryWatchdog } from "../dist-Db664g2O.mjs";
|
|
3
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-CPm5TMBl.mjs";
|
|
4
4
|
import { i as downloadFile } from "../addon-utils-CgBCF-mE.mjs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
6
6
|
import * as fs from "node:fs";
|
|
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-
|
|
7
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
8
|
-
const require_process_memory = require("../process-memory-
|
|
9
|
-
const require_addon_utils = require("../addon-utils-
|
|
5
|
+
const require_dist = require("../dist-DIsM42Ex.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-CSpdFZb6.js");
|
|
7
|
+
const require_lazy_sharp = require("../lazy-sharp-LSlEXQe_.js");
|
|
8
|
+
const require_process_memory = require("../process-memory-DpSJQF-p.js");
|
|
9
|
+
const require_addon_utils = require("../addon-utils-RAHF2hmW.js");
|
|
10
10
|
let sharp = require("sharp");
|
|
11
11
|
sharp = require_dist.__toESM(sharp);
|
|
12
12
|
let node_child_process = require("node:child_process");
|
|
@@ -256,6 +256,113 @@ function normalizeEngineNodeId(rawNodeId) {
|
|
|
256
256
|
return raw.includes("/") ? raw.split("/")[0] ?? "hub" : raw;
|
|
257
257
|
}
|
|
258
258
|
//#endregion
|
|
259
|
+
//#region src/shared/cluster-model-source.ts
|
|
260
|
+
/**
|
|
261
|
+
* Where the runner gets the ONE cluster model choice per cluster-scoped step.
|
|
262
|
+
*
|
|
263
|
+
* The sibling of `crop-convention-source.ts`, and deliberately built the same
|
|
264
|
+
* way, because it answers the neighbouring half of the same question: the crop
|
|
265
|
+
* convention decides WHAT pixels the encoder sees, this decides WHICH encoder
|
|
266
|
+
* sees them. Both are cluster-wide, both are read by the runner from the
|
|
267
|
+
* `pipeline-orchestrator` global settings over the hub-routed `addon-settings`
|
|
268
|
+
* cap, both pass NO `nodeId`.
|
|
269
|
+
*
|
|
270
|
+
* ## Deliberately NOT node-scoped, and not on the attach config
|
|
271
|
+
*
|
|
272
|
+
* With a `nodeId` the settings cap would project that node's scoped value and
|
|
273
|
+
* two nodes could embed into one index with two encoders — the original defect,
|
|
274
|
+
* relocated to the transport. And the attach config is the wrong carrier for
|
|
275
|
+
* the same reason it was wrong for the crop: eleven builders construct a
|
|
276
|
+
* `RunnerCameraConfig`, a cluster-wide constant threaded through eleven
|
|
277
|
+
* builders eventually reaches ten of them, and the cameras attached by the
|
|
278
|
+
* forgotten one quietly write a foreign feature space into the shared index.
|
|
279
|
+
*
|
|
280
|
+
* ## Why the failure mode keeps the last value
|
|
281
|
+
*
|
|
282
|
+
* A failed read must never revert to the registry default MID-PASS: that would
|
|
283
|
+
* silently change what every remaining vector of that dispatch means, which is
|
|
284
|
+
* the exact class of harm the scope exists to prevent. So a failure keeps the
|
|
285
|
+
* last known row and says so, loudly, once per failure.
|
|
286
|
+
*/
|
|
287
|
+
/**
|
|
288
|
+
* The addon whose GLOBAL settings own the cluster row. Same owner as the crop
|
|
289
|
+
* convention and the native-frame lease: hub-resident and neutral between the
|
|
290
|
+
* addons that read it (post-analysis pins it for a re-embed pass, the runner
|
|
291
|
+
* enforces it live — neither should own a value the other depends on).
|
|
292
|
+
*/
|
|
293
|
+
var CLUSTER_MODEL_OWNER_ADDON_ID = "pipeline-orchestrator";
|
|
294
|
+
/** TTL-cached read of the cluster model row. */
|
|
295
|
+
var ClusterModelSource = class {
|
|
296
|
+
models = require_dist.DEFAULT_CLUSTER_STEP_MODELS;
|
|
297
|
+
settings = require_dist.DEFAULT_CLUSTER_STEP_SETTINGS;
|
|
298
|
+
lastReadAtMs = Number.NEGATIVE_INFINITY;
|
|
299
|
+
inFlight = null;
|
|
300
|
+
logger;
|
|
301
|
+
now;
|
|
302
|
+
ttlMs;
|
|
303
|
+
constructor(options) {
|
|
304
|
+
this.logger = options.logger;
|
|
305
|
+
this.now = options.now ?? (() => Date.now());
|
|
306
|
+
this.ttlMs = options.ttlMs ?? 6e4;
|
|
307
|
+
}
|
|
308
|
+
/** The row in force right now — the registry defaults until a read lands. */
|
|
309
|
+
current() {
|
|
310
|
+
return this.models;
|
|
311
|
+
}
|
|
312
|
+
/** Cluster-scoped step knobs in force right now (admission floors, …). */
|
|
313
|
+
currentSettings() {
|
|
314
|
+
return this.settings;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Re-read if the cached row has expired. Concurrent callers share one
|
|
318
|
+
* in-flight read; a failure keeps the LAST KNOWN row.
|
|
319
|
+
*/
|
|
320
|
+
async refresh(api) {
|
|
321
|
+
if (api === void 0) return this.models;
|
|
322
|
+
if (this.now() - this.lastReadAtMs < this.ttlMs) return this.models;
|
|
323
|
+
this.inFlight ??= this.read(api).finally(() => {
|
|
324
|
+
this.inFlight = null;
|
|
325
|
+
});
|
|
326
|
+
await this.inFlight;
|
|
327
|
+
return this.models;
|
|
328
|
+
}
|
|
329
|
+
async read(api) {
|
|
330
|
+
try {
|
|
331
|
+
const view = await api.addonSettings.getGlobalSettings.query({ addonId: CLUSTER_MODEL_OWNER_ADDON_ID });
|
|
332
|
+
const next = require_dist.pickClusterStepModels(view);
|
|
333
|
+
const nextSettings = require_dist.pickClusterStepSettings(view);
|
|
334
|
+
this.lastReadAtMs = this.now();
|
|
335
|
+
const changed = Object.keys(next).filter((stepId) => next[stepId] !== this.models[stepId]);
|
|
336
|
+
const settingsChanged = Object.keys(nextSettings).some((stepId) => {
|
|
337
|
+
const from = this.settings[stepId] ?? {};
|
|
338
|
+
const to = nextSettings[stepId] ?? {};
|
|
339
|
+
return [...new Set([...Object.keys(from), ...Object.keys(to)])].some((key) => from[key] !== to[key]);
|
|
340
|
+
});
|
|
341
|
+
if (changed.length > 0) {
|
|
342
|
+
this.logger.info("cluster step model changed — vectors already stored by the previous model need a re-embed pass", { meta: { changed: changed.map((stepId) => ({
|
|
343
|
+
stepId,
|
|
344
|
+
from: this.models[stepId],
|
|
345
|
+
to: next[stepId]
|
|
346
|
+
})) } });
|
|
347
|
+
this.models = next;
|
|
348
|
+
}
|
|
349
|
+
if (settingsChanged) {
|
|
350
|
+
this.logger.info("cluster step settings changed", { meta: {
|
|
351
|
+
from: { ...this.settings },
|
|
352
|
+
to: { ...nextSettings }
|
|
353
|
+
} });
|
|
354
|
+
this.settings = nextSettings;
|
|
355
|
+
}
|
|
356
|
+
} catch (err) {
|
|
357
|
+
this.logger.warn("cluster step model read failed — keeping the last known row", { meta: {
|
|
358
|
+
owner: CLUSTER_MODEL_OWNER_ADDON_ID,
|
|
359
|
+
inUse: { ...this.models },
|
|
360
|
+
error: err instanceof Error ? err.message : String(err)
|
|
361
|
+
} });
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
//#endregion
|
|
259
366
|
//#region src/detection-pipeline/default-detection-model.ts
|
|
260
367
|
/** The object-detection step id — the only slot this resolver applies to. */
|
|
261
368
|
var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
@@ -2601,6 +2708,59 @@ var EngineProvisioner = class {
|
|
|
2601
2708
|
}
|
|
2602
2709
|
};
|
|
2603
2710
|
//#endregion
|
|
2711
|
+
//#region src/session-decode/frame-view-payload.ts
|
|
2712
|
+
var FRAME_VIEW_PAYLOAD_POLICY = "jpeg";
|
|
2713
|
+
//#endregion
|
|
2714
|
+
//#region src/detection-pipeline/root-frame-view.ts
|
|
2715
|
+
/** Resolve the pre-padding content requested from the decode worker for one root. */
|
|
2716
|
+
function resolveRootFrameViewSpec(model, source, crop, format = FRAME_VIEW_PAYLOAD_POLICY) {
|
|
2717
|
+
const sourceWidth = crop?.width ?? source.width;
|
|
2718
|
+
const sourceHeight = crop?.height ?? source.height;
|
|
2719
|
+
if (model.preprocessMode !== "letterbox") return {
|
|
2720
|
+
...crop ? { crop } : {},
|
|
2721
|
+
content: {
|
|
2722
|
+
width: model.inputSize.width,
|
|
2723
|
+
height: model.inputSize.height
|
|
2724
|
+
},
|
|
2725
|
+
fit: "stretch",
|
|
2726
|
+
format
|
|
2727
|
+
};
|
|
2728
|
+
const scale = Math.min(model.inputSize.width / sourceWidth, model.inputSize.height / sourceHeight);
|
|
2729
|
+
return {
|
|
2730
|
+
...crop ? { crop } : {},
|
|
2731
|
+
content: {
|
|
2732
|
+
width: Math.max(1, Math.round(sourceWidth * scale)),
|
|
2733
|
+
height: Math.max(1, Math.round(sourceHeight * scale))
|
|
2734
|
+
},
|
|
2735
|
+
fit: "contain",
|
|
2736
|
+
format
|
|
2737
|
+
};
|
|
2738
|
+
}
|
|
2739
|
+
//#endregion
|
|
2740
|
+
//#region src/detection-pipeline/frame-ref-view-provider.ts
|
|
2741
|
+
var LocalFrameRefMissError = class extends Error {
|
|
2742
|
+
reason;
|
|
2743
|
+
constructor(reason) {
|
|
2744
|
+
super(`local frameRef miss: ${reason}`);
|
|
2745
|
+
this.reason = reason;
|
|
2746
|
+
this.name = "LocalFrameRefMissError";
|
|
2747
|
+
}
|
|
2748
|
+
};
|
|
2749
|
+
/** Bind one registry lease for all heterogeneous roots of a pipeline invocation. */
|
|
2750
|
+
function createRootFrameViewResolver(registry, ref) {
|
|
2751
|
+
const lease = registry.acquire(ref);
|
|
2752
|
+
if (!lease) throw new LocalFrameRefMissError(ref.registryId === registry.registryId ? "stale-ref" : "foreign-registry");
|
|
2753
|
+
const resolve = async (root, crop) => {
|
|
2754
|
+
const model = root.definition.models.find((candidate) => candidate.id === root.modelId);
|
|
2755
|
+
if (!model) throw new Error(`frame view model not found: ${root.modelId}`);
|
|
2756
|
+
const spec = resolveRootFrameViewSpec(model, ref, crop);
|
|
2757
|
+
const result = await lease.resolve(spec);
|
|
2758
|
+
if (result.kind === "miss") throw new LocalFrameRefMissError(result.reason);
|
|
2759
|
+
return result;
|
|
2760
|
+
};
|
|
2761
|
+
return Object.assign(resolve, { release: (reason) => lease.release(reason) });
|
|
2762
|
+
}
|
|
2763
|
+
//#endregion
|
|
2604
2764
|
//#region src/detection-pipeline/pipeline/crop-utils.ts
|
|
2605
2765
|
/**
|
|
2606
2766
|
* Crop utilities — ROI extraction and bbox coordinate transforms.
|
|
@@ -5186,59 +5346,6 @@ function capitalize(s) {
|
|
|
5186
5346
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
5187
5347
|
}
|
|
5188
5348
|
//#endregion
|
|
5189
|
-
//#region src/session-decode/frame-view-payload.ts
|
|
5190
|
-
var FRAME_VIEW_PAYLOAD_POLICY = "jpeg";
|
|
5191
|
-
//#endregion
|
|
5192
|
-
//#region src/detection-pipeline/root-frame-view.ts
|
|
5193
|
-
/** Resolve the pre-padding content requested from the decode worker for one root. */
|
|
5194
|
-
function resolveRootFrameViewSpec(model, source, crop, format = FRAME_VIEW_PAYLOAD_POLICY) {
|
|
5195
|
-
const sourceWidth = crop?.width ?? source.width;
|
|
5196
|
-
const sourceHeight = crop?.height ?? source.height;
|
|
5197
|
-
if (model.preprocessMode !== "letterbox") return {
|
|
5198
|
-
...crop ? { crop } : {},
|
|
5199
|
-
content: {
|
|
5200
|
-
width: model.inputSize.width,
|
|
5201
|
-
height: model.inputSize.height
|
|
5202
|
-
},
|
|
5203
|
-
fit: "stretch",
|
|
5204
|
-
format
|
|
5205
|
-
};
|
|
5206
|
-
const scale = Math.min(model.inputSize.width / sourceWidth, model.inputSize.height / sourceHeight);
|
|
5207
|
-
return {
|
|
5208
|
-
...crop ? { crop } : {},
|
|
5209
|
-
content: {
|
|
5210
|
-
width: Math.max(1, Math.round(sourceWidth * scale)),
|
|
5211
|
-
height: Math.max(1, Math.round(sourceHeight * scale))
|
|
5212
|
-
},
|
|
5213
|
-
fit: "contain",
|
|
5214
|
-
format
|
|
5215
|
-
};
|
|
5216
|
-
}
|
|
5217
|
-
//#endregion
|
|
5218
|
-
//#region src/detection-pipeline/frame-ref-view-provider.ts
|
|
5219
|
-
var LocalFrameRefMissError = class extends Error {
|
|
5220
|
-
reason;
|
|
5221
|
-
constructor(reason) {
|
|
5222
|
-
super(`local frameRef miss: ${reason}`);
|
|
5223
|
-
this.reason = reason;
|
|
5224
|
-
this.name = "LocalFrameRefMissError";
|
|
5225
|
-
}
|
|
5226
|
-
};
|
|
5227
|
-
/** Bind one registry lease for all heterogeneous roots of a pipeline invocation. */
|
|
5228
|
-
function createRootFrameViewResolver(registry, ref) {
|
|
5229
|
-
const lease = registry.acquire(ref);
|
|
5230
|
-
if (!lease) throw new LocalFrameRefMissError(ref.registryId === registry.registryId ? "stale-ref" : "foreign-registry");
|
|
5231
|
-
const resolve = async (root, crop) => {
|
|
5232
|
-
const model = root.definition.models.find((candidate) => candidate.id === root.modelId);
|
|
5233
|
-
if (!model) throw new Error(`frame view model not found: ${root.modelId}`);
|
|
5234
|
-
const spec = resolveRootFrameViewSpec(model, ref, crop);
|
|
5235
|
-
const result = await lease.resolve(spec);
|
|
5236
|
-
if (result.kind === "miss") throw new LocalFrameRefMissError(result.reason);
|
|
5237
|
-
return result;
|
|
5238
|
-
};
|
|
5239
|
-
return Object.assign(resolve, { release: (reason) => lease.release(reason) });
|
|
5240
|
-
}
|
|
5241
|
-
//#endregion
|
|
5242
5349
|
//#region src/detection-pipeline/pipeline/native-crop-compose.ts
|
|
5243
5350
|
/** Clamp `v` into `[lo, hi]`. */
|
|
5244
5351
|
function clamp(v, lo, hi) {
|
|
@@ -5367,7 +5474,10 @@ function mergeCustomModels(staticModels, customModels) {
|
|
|
5367
5474
|
for (const m of customModels) {
|
|
5368
5475
|
if (seen.has(m.id)) continue;
|
|
5369
5476
|
seen.add(m.id);
|
|
5370
|
-
merged.push(
|
|
5477
|
+
merged.push({
|
|
5478
|
+
...m,
|
|
5479
|
+
provider: require_dist.inferModelProvider(m)
|
|
5480
|
+
});
|
|
5371
5481
|
}
|
|
5372
5482
|
return merged;
|
|
5373
5483
|
}
|
|
@@ -5666,113 +5776,6 @@ function applyZoneRuleGate(result, zones, rules) {
|
|
|
5666
5776
|
};
|
|
5667
5777
|
}
|
|
5668
5778
|
//#endregion
|
|
5669
|
-
//#region src/shared/cluster-model-source.ts
|
|
5670
|
-
/**
|
|
5671
|
-
* Where the runner gets the ONE cluster model choice per cluster-scoped step.
|
|
5672
|
-
*
|
|
5673
|
-
* The sibling of `crop-convention-source.ts`, and deliberately built the same
|
|
5674
|
-
* way, because it answers the neighbouring half of the same question: the crop
|
|
5675
|
-
* convention decides WHAT pixels the encoder sees, this decides WHICH encoder
|
|
5676
|
-
* sees them. Both are cluster-wide, both are read by the runner from the
|
|
5677
|
-
* `pipeline-orchestrator` global settings over the hub-routed `addon-settings`
|
|
5678
|
-
* cap, both pass NO `nodeId`.
|
|
5679
|
-
*
|
|
5680
|
-
* ## Deliberately NOT node-scoped, and not on the attach config
|
|
5681
|
-
*
|
|
5682
|
-
* With a `nodeId` the settings cap would project that node's scoped value and
|
|
5683
|
-
* two nodes could embed into one index with two encoders — the original defect,
|
|
5684
|
-
* relocated to the transport. And the attach config is the wrong carrier for
|
|
5685
|
-
* the same reason it was wrong for the crop: eleven builders construct a
|
|
5686
|
-
* `RunnerCameraConfig`, a cluster-wide constant threaded through eleven
|
|
5687
|
-
* builders eventually reaches ten of them, and the cameras attached by the
|
|
5688
|
-
* forgotten one quietly write a foreign feature space into the shared index.
|
|
5689
|
-
*
|
|
5690
|
-
* ## Why the failure mode keeps the last value
|
|
5691
|
-
*
|
|
5692
|
-
* A failed read must never revert to the registry default MID-PASS: that would
|
|
5693
|
-
* silently change what every remaining vector of that dispatch means, which is
|
|
5694
|
-
* the exact class of harm the scope exists to prevent. So a failure keeps the
|
|
5695
|
-
* last known row and says so, loudly, once per failure.
|
|
5696
|
-
*/
|
|
5697
|
-
/**
|
|
5698
|
-
* The addon whose GLOBAL settings own the cluster row. Same owner as the crop
|
|
5699
|
-
* convention and the native-frame lease: hub-resident and neutral between the
|
|
5700
|
-
* addons that read it (post-analysis pins it for a re-embed pass, the runner
|
|
5701
|
-
* enforces it live — neither should own a value the other depends on).
|
|
5702
|
-
*/
|
|
5703
|
-
var CLUSTER_MODEL_OWNER_ADDON_ID = "pipeline-orchestrator";
|
|
5704
|
-
/** TTL-cached read of the cluster model row. */
|
|
5705
|
-
var ClusterModelSource = class {
|
|
5706
|
-
models = require_dist.DEFAULT_CLUSTER_STEP_MODELS;
|
|
5707
|
-
settings = require_dist.DEFAULT_CLUSTER_STEP_SETTINGS;
|
|
5708
|
-
lastReadAtMs = Number.NEGATIVE_INFINITY;
|
|
5709
|
-
inFlight = null;
|
|
5710
|
-
logger;
|
|
5711
|
-
now;
|
|
5712
|
-
ttlMs;
|
|
5713
|
-
constructor(options) {
|
|
5714
|
-
this.logger = options.logger;
|
|
5715
|
-
this.now = options.now ?? (() => Date.now());
|
|
5716
|
-
this.ttlMs = options.ttlMs ?? 6e4;
|
|
5717
|
-
}
|
|
5718
|
-
/** The row in force right now — the registry defaults until a read lands. */
|
|
5719
|
-
current() {
|
|
5720
|
-
return this.models;
|
|
5721
|
-
}
|
|
5722
|
-
/** Cluster-scoped step knobs in force right now (admission floors, …). */
|
|
5723
|
-
currentSettings() {
|
|
5724
|
-
return this.settings;
|
|
5725
|
-
}
|
|
5726
|
-
/**
|
|
5727
|
-
* Re-read if the cached row has expired. Concurrent callers share one
|
|
5728
|
-
* in-flight read; a failure keeps the LAST KNOWN row.
|
|
5729
|
-
*/
|
|
5730
|
-
async refresh(api) {
|
|
5731
|
-
if (api === void 0) return this.models;
|
|
5732
|
-
if (this.now() - this.lastReadAtMs < this.ttlMs) return this.models;
|
|
5733
|
-
this.inFlight ??= this.read(api).finally(() => {
|
|
5734
|
-
this.inFlight = null;
|
|
5735
|
-
});
|
|
5736
|
-
await this.inFlight;
|
|
5737
|
-
return this.models;
|
|
5738
|
-
}
|
|
5739
|
-
async read(api) {
|
|
5740
|
-
try {
|
|
5741
|
-
const view = await api.addonSettings.getGlobalSettings.query({ addonId: CLUSTER_MODEL_OWNER_ADDON_ID });
|
|
5742
|
-
const next = require_dist.pickClusterStepModels(view);
|
|
5743
|
-
const nextSettings = require_dist.pickClusterStepSettings(view);
|
|
5744
|
-
this.lastReadAtMs = this.now();
|
|
5745
|
-
const changed = Object.keys(next).filter((stepId) => next[stepId] !== this.models[stepId]);
|
|
5746
|
-
const settingsChanged = Object.keys(nextSettings).some((stepId) => {
|
|
5747
|
-
const from = this.settings[stepId] ?? {};
|
|
5748
|
-
const to = nextSettings[stepId] ?? {};
|
|
5749
|
-
return [...new Set([...Object.keys(from), ...Object.keys(to)])].some((key) => from[key] !== to[key]);
|
|
5750
|
-
});
|
|
5751
|
-
if (changed.length > 0) {
|
|
5752
|
-
this.logger.info("cluster step model changed — vectors already stored by the previous model need a re-embed pass", { meta: { changed: changed.map((stepId) => ({
|
|
5753
|
-
stepId,
|
|
5754
|
-
from: this.models[stepId],
|
|
5755
|
-
to: next[stepId]
|
|
5756
|
-
})) } });
|
|
5757
|
-
this.models = next;
|
|
5758
|
-
}
|
|
5759
|
-
if (settingsChanged) {
|
|
5760
|
-
this.logger.info("cluster step settings changed", { meta: {
|
|
5761
|
-
from: { ...this.settings },
|
|
5762
|
-
to: { ...nextSettings }
|
|
5763
|
-
} });
|
|
5764
|
-
this.settings = nextSettings;
|
|
5765
|
-
}
|
|
5766
|
-
} catch (err) {
|
|
5767
|
-
this.logger.warn("cluster step model read failed — keeping the last known row", { meta: {
|
|
5768
|
-
owner: CLUSTER_MODEL_OWNER_ADDON_ID,
|
|
5769
|
-
inUse: { ...this.models },
|
|
5770
|
-
error: err instanceof Error ? err.message : String(err)
|
|
5771
|
-
} });
|
|
5772
|
-
}
|
|
5773
|
-
}
|
|
5774
|
-
};
|
|
5775
|
-
//#endregion
|
|
5776
5779
|
//#region src/detection-pipeline/provider.ts
|
|
5777
5780
|
/**
|
|
5778
5781
|
* DetectionPipelineProvider — implements IPipelineExecutorProvider.
|
|
@@ -8763,7 +8766,8 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
|
|
|
8763
8766
|
sizeMB: entry.sizeMB
|
|
8764
8767
|
}])),
|
|
8765
8768
|
...m.group ? { group: m.group } : {},
|
|
8766
|
-
...m.legacy !== void 0 ? { legacy: m.legacy } : {}
|
|
8769
|
+
...m.legacy !== void 0 ? { legacy: m.legacy } : {},
|
|
8770
|
+
provider: m.provider ?? "camstack"
|
|
8767
8771
|
})),
|
|
8768
8772
|
defaultModelId: step.defaultModelId,
|
|
8769
8773
|
...step.defaultModelIdByFormat ? { defaultModelIdByFormat: { ...step.defaultModelIdByFormat } } : {},
|