@camstack/addon-pipeline 1.2.621 → 1.2.622
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/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/{custom-model-catalog-Il8UY4D4.js → custom-model-catalog-CKCK-QcT.js} +7 -7
- package/dist/{custom-model-catalog-0_SnSXzN.mjs → custom-model-catalog-wpMi2U7e.mjs} +7 -7
- package/dist/detection-pipeline/index.js +55 -414
- package/dist/detection-pipeline/index.mjs +79 -438
- package/dist/{dist-DHqkQhTQ.mjs → dist-BF60SjmI.mjs} +76 -226
- package/dist/{dist-ClkumZgv.js → dist-DUFGDd_2.js} +75 -231
- package/dist/{model-catalogs-BagalaYp.js → model-catalogs-CjTm_0O-.js} +1 -1
- package/dist/{model-catalogs-Z1GZAhSb.mjs → model-catalogs-CqFDhb0B.mjs} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-CkJLxlWI.mjs → node-DkphOOM2.mjs} +1 -1
- package/dist/{node-0O_61WVW.js → node-DzGVn7bD.js} +1 -1
- package/dist/pipeline-runner/index.js +18 -4
- package/dist/pipeline-runner/index.mjs +18 -4
- package/dist/{process-memory-DdIOhjYB.js → process-memory-8kKexHYR.js} +1 -1
- package/dist/{process-memory-Dj3UgL1e.mjs → process-memory-CBzfdSvC.mjs} +1 -1
- package/dist/recorder/index.js +2 -2
- package/dist/recorder/index.mjs +2 -2
- package/dist/{segment-demux-js-Bv0t0-tQ.mjs → segment-demux-js-DQNoNSJt.mjs} +1 -1
- package/dist/{segment-demux-js-BePzacki.js → segment-demux-js-DRLQb1pc.js} +1 -1
- package/dist/session-decode/decode-worker-main.js +12 -21
- package/dist/session-decode/decode-worker-main.mjs +12 -21
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-dNk74ahz.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BmANAxAe.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-H6RKsaiZ.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-CNoWeZHH.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-CH5g78CJ.mjs → hostInit-B3hXAfr1.mjs} +2 -2
- package/dist/stream-broker/index.js +3 -3
- package/dist/stream-broker/index.mjs +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-D_NzPcnh.mjs → worker-protocol-DngGEAT2.js} +102 -2
- package/dist/{worker-protocol-C-G8qmye.js → worker-protocol-_avq7y8O.mjs} +67 -25
- package/package.json +1 -1
- package/python/coreml_load_probe.py +105 -15
- package/python/openvino_compile_probe.py +72 -18
- package/python/test_coreml_load_probe.py +83 -0
- package/python/test_openvino_compile_probe.py +114 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-2KkGoQ55.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Dx-WrMx0.mjs +0 -26
|
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_node = require("../node-
|
|
8
|
-
const require_custom_model_catalog = require("../custom-model-catalog-
|
|
6
|
+
const require_dist = require("../dist-DUFGDd_2.js");
|
|
7
|
+
const require_node = require("../node-DzGVn7bD.js");
|
|
8
|
+
const require_custom_model_catalog = require("../custom-model-catalog-CKCK-QcT.js");
|
|
9
9
|
const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
|
|
10
|
-
const require_process_memory = require("../process-memory-
|
|
10
|
+
const require_process_memory = require("../process-memory-8kKexHYR.js");
|
|
11
11
|
let node_os = require("node:os");
|
|
12
12
|
node_os = require_chunk.__toESM(node_os);
|
|
13
13
|
let node_fs = require("node:fs");
|
|
@@ -357,84 +357,6 @@ function normalizeEngineNodeId(rawNodeId) {
|
|
|
357
357
|
return raw.includes("/") ? raw.split("/")[0] ?? "hub" : raw;
|
|
358
358
|
}
|
|
359
359
|
//#endregion
|
|
360
|
-
//#region src/detection-pipeline/model-bound-device-overrides.ts
|
|
361
|
-
/**
|
|
362
|
-
* Auto tune (D745), the executor leg: list — and optionally remove — the
|
|
363
|
-
* MODEL-BOUND thresholds stored in this addon's per-camera settings (the
|
|
364
|
-
* object-detection root's `bindsToModel` keys and their binding keys, D738).
|
|
365
|
-
* Every other key of a camera's store is kept.
|
|
366
|
-
*
|
|
367
|
-
* The device store only MERGES on write, so a removal is clear + write of the
|
|
368
|
-
* kept keys — the idiom `migrate-hardware-state.ts` uses. Both run in this
|
|
369
|
-
* process, serialized per camera; a write that fails after the clear restores
|
|
370
|
-
* the original row, and the camera is reported `refused` rather than clean. A
|
|
371
|
-
* store that cannot be read is `refused` too: a failed read is never "nothing
|
|
372
|
-
* to clear" (D393).
|
|
373
|
-
*/
|
|
374
|
-
function errMsg(err) {
|
|
375
|
-
return err instanceof Error ? err.message : String(err);
|
|
376
|
-
}
|
|
377
|
-
/** The stored keys among `boundKeys` (values and bindings), sorted. */
|
|
378
|
-
function presentBoundKeys(row, boundKeys) {
|
|
379
|
-
return boundKeys.flatMap((k) => [k, require_dist.modelBindingKey(k)]).filter((k) => k in row).toSorted();
|
|
380
|
-
}
|
|
381
|
-
async function clearModelBoundDeviceOverrides(deps, input) {
|
|
382
|
-
const ids = input.deviceIds ?? await deps.listDeviceIds();
|
|
383
|
-
const entries = [];
|
|
384
|
-
const refused = [];
|
|
385
|
-
for (const deviceId of [...ids].toSorted((a, b) => a - b)) {
|
|
386
|
-
let row;
|
|
387
|
-
try {
|
|
388
|
-
row = await deps.readDeviceStore(deviceId);
|
|
389
|
-
} catch (err) {
|
|
390
|
-
refused.push({
|
|
391
|
-
deviceId,
|
|
392
|
-
reason: `read failed: ${errMsg(err)}`
|
|
393
|
-
});
|
|
394
|
-
continue;
|
|
395
|
-
}
|
|
396
|
-
const keys = presentBoundKeys(row, deps.boundKeys);
|
|
397
|
-
if (keys.length === 0) continue;
|
|
398
|
-
if (input.dryRun) {
|
|
399
|
-
entries.push({
|
|
400
|
-
deviceId,
|
|
401
|
-
keys
|
|
402
|
-
});
|
|
403
|
-
continue;
|
|
404
|
-
}
|
|
405
|
-
const kept = { ...row };
|
|
406
|
-
for (const k of keys) delete kept[k];
|
|
407
|
-
try {
|
|
408
|
-
await deps.clearDeviceStore(deviceId);
|
|
409
|
-
} catch (err) {
|
|
410
|
-
refused.push({
|
|
411
|
-
deviceId,
|
|
412
|
-
reason: `clear failed: ${errMsg(err)}`
|
|
413
|
-
});
|
|
414
|
-
continue;
|
|
415
|
-
}
|
|
416
|
-
try {
|
|
417
|
-
if (Object.keys(kept).length > 0) await deps.writeDeviceStore(deviceId, kept);
|
|
418
|
-
entries.push({
|
|
419
|
-
deviceId,
|
|
420
|
-
keys
|
|
421
|
-
});
|
|
422
|
-
} catch (err) {
|
|
423
|
-
await deps.writeDeviceStore(deviceId, row).catch(() => void 0);
|
|
424
|
-
refused.push({
|
|
425
|
-
deviceId,
|
|
426
|
-
reason: `write failed, row restored: ${errMsg(err)}`
|
|
427
|
-
});
|
|
428
|
-
} finally {
|
|
429
|
-
deps.invalidate(deviceId);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
return {
|
|
433
|
-
entries,
|
|
434
|
-
refused
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
//#endregion
|
|
438
360
|
//#region src/detection-pipeline/model-format-facts.ts
|
|
439
361
|
/**
|
|
440
362
|
* Two per-format facts `getSchema` reports beside `downloaded`, for Model
|
|
@@ -769,122 +691,6 @@ var ClusterUnknownRefusalLog = class {
|
|
|
769
691
|
}
|
|
770
692
|
};
|
|
771
693
|
//#endregion
|
|
772
|
-
//#region src/detection-pipeline/device-override-mirror.ts
|
|
773
|
-
/**
|
|
774
|
-
* The per-device detection overrides, kept fresh OFF the frame path.
|
|
775
|
-
*
|
|
776
|
-
* ## The read this replaces
|
|
777
|
-
*
|
|
778
|
-
* `runPipeline` resolved a device's overrides by calling
|
|
779
|
-
* `settings.readDeviceStore(deviceId)` on **every inference frame**. Measured
|
|
780
|
-
* on the live hub 2026-08-25: `get detection-pipeline:addon-devices`, 1 143
|
|
781
|
-
* calls a minute at 0.44 rows per call — the disk asked, nineteen times a
|
|
782
|
-
* second, whether an operator has ever changed a threshold.
|
|
783
|
-
*
|
|
784
|
-
* ## Why this is not "a cache in the consumer" (D224)
|
|
785
|
-
*
|
|
786
|
-
* D224 forbids a SECOND authority over a fact that belongs to somebody else:
|
|
787
|
-
* the failure it records is a consumer caching a value whose write path does
|
|
788
|
-
* not run through that consumer, so an operator's own change is the one read
|
|
789
|
-
* the cache gets wrong.
|
|
790
|
-
*
|
|
791
|
-
* This addon OWNS the row. `<addonId>:addon-devices` is detection-pipeline's
|
|
792
|
-
* own store, and the only writers are this addon's `updateDeviceSettings` and
|
|
793
|
-
* its `clearDeviceOverrides` — both of which call {@link invalidate}. A write
|
|
794
|
-
* is therefore its own invalidation, exactly as D224 requires, and the window
|
|
795
|
-
* below governs only the case nobody writes through this process.
|
|
796
|
-
*
|
|
797
|
-
* ## The window, declared
|
|
798
|
-
*
|
|
799
|
-
* {@link DEVICE_OVERRIDE_STALE_MS} is what an operator's change costs on a node
|
|
800
|
-
* that did NOT serve the write — this addon runs per node, and a settings write
|
|
801
|
-
* lands on one of them. Thirty seconds is the trade: it removes 99.9% of the
|
|
802
|
-
* reads (one per device per window instead of one per frame) and it is short
|
|
803
|
-
* enough that "I moved the threshold and nothing happened" is not a support
|
|
804
|
-
* question. Ten minutes — {@link OPERATOR_WRITTEN_STALE_MS}, the constant for a
|
|
805
|
-
* cap whose value only an operator changes — is right for a POLLED reader that
|
|
806
|
-
* costs a camera round trip; this read costs one local SQLite `get`, and the
|
|
807
|
-
* cheap read buys a short window.
|
|
808
|
-
*
|
|
809
|
-
* A stale entry is SERVED and revalidated behind the caller, never awaited: a
|
|
810
|
-
* frame that waits for the settings store is a frame the pipeline dropped, and
|
|
811
|
-
* the reader is by definition about to ask again.
|
|
812
|
-
*/
|
|
813
|
-
/**
|
|
814
|
-
* How long a mirrored entry is served before a refresh is started behind the
|
|
815
|
-
* next reader. See the module doc for why it is 30 s and not ten minutes.
|
|
816
|
-
*/
|
|
817
|
-
var DEVICE_OVERRIDE_STALE_MS = 3e4;
|
|
818
|
-
/**
|
|
819
|
-
* How long a FAILED refresh is not retried.
|
|
820
|
-
*
|
|
821
|
-
* A refresh that throws leaves `fetchedAt` where it was, so without a cooldown
|
|
822
|
-
* every subsequent frame would start another one — a broken settings store
|
|
823
|
-
* would be hammered at frame rate by the very mechanism built to stop that.
|
|
824
|
-
*/
|
|
825
|
-
var DEVICE_OVERRIDE_MISS_COOLDOWN_MS = 5e3;
|
|
826
|
-
var DeviceOverrideMirror = class {
|
|
827
|
-
deps;
|
|
828
|
-
staleMs;
|
|
829
|
-
missCooldownMs;
|
|
830
|
-
entries = /* @__PURE__ */ new Map();
|
|
831
|
-
/** In-flight reads, so a burst of frames on a cold device costs ONE read and
|
|
832
|
-
* not one per frame — the exact failure this class exists to remove. */
|
|
833
|
-
inFlight = /* @__PURE__ */ new Map();
|
|
834
|
-
now;
|
|
835
|
-
constructor(deps, staleMs = DEVICE_OVERRIDE_STALE_MS, missCooldownMs = DEVICE_OVERRIDE_MISS_COOLDOWN_MS) {
|
|
836
|
-
this.deps = deps;
|
|
837
|
-
this.staleMs = staleMs;
|
|
838
|
-
this.missCooldownMs = missCooldownMs;
|
|
839
|
-
this.now = deps.now ?? (() => Date.now());
|
|
840
|
-
}
|
|
841
|
-
/**
|
|
842
|
-
* The device's overrides.
|
|
843
|
-
*
|
|
844
|
-
* COLD awaits — the first frame on a camera has to get the real answer, and a
|
|
845
|
-
* default is exactly what "the operator lowered this threshold" looks like.
|
|
846
|
-
* WARM returns immediately, stale or not, and starts the refresh behind the
|
|
847
|
-
* caller.
|
|
848
|
-
*/
|
|
849
|
-
async resolve(deviceId) {
|
|
850
|
-
const entry = this.entries.get(deviceId);
|
|
851
|
-
if (entry === void 0) return this.load(deviceId);
|
|
852
|
-
if (this.now() - entry.fetchedAt >= this.staleMs) this.load(deviceId);
|
|
853
|
-
return entry.value;
|
|
854
|
-
}
|
|
855
|
-
/** Drop a device's entry. Called by every writer in this process, so an
|
|
856
|
-
* operator's own change is never served from the mirror. */
|
|
857
|
-
invalidate(deviceId) {
|
|
858
|
-
this.entries.delete(deviceId);
|
|
859
|
-
}
|
|
860
|
-
invalidateAll() {
|
|
861
|
-
this.entries.clear();
|
|
862
|
-
}
|
|
863
|
-
async load(deviceId) {
|
|
864
|
-
const pending = this.inFlight.get(deviceId);
|
|
865
|
-
if (pending !== void 0) return pending;
|
|
866
|
-
const run = this.deps.read(deviceId).then((value) => {
|
|
867
|
-
this.entries.set(deviceId, {
|
|
868
|
-
value,
|
|
869
|
-
fetchedAt: this.now()
|
|
870
|
-
});
|
|
871
|
-
return value;
|
|
872
|
-
}).catch((err) => {
|
|
873
|
-
this.deps.onRefreshFailed?.(deviceId, err);
|
|
874
|
-
const existing = this.entries.get(deviceId);
|
|
875
|
-
if (existing !== void 0) {
|
|
876
|
-
existing.fetchedAt = this.now() - this.staleMs + this.missCooldownMs;
|
|
877
|
-
return existing.value;
|
|
878
|
-
}
|
|
879
|
-
return {};
|
|
880
|
-
}).finally(() => {
|
|
881
|
-
this.inFlight.delete(deviceId);
|
|
882
|
-
});
|
|
883
|
-
this.inFlight.set(deviceId, run);
|
|
884
|
-
return run;
|
|
885
|
-
}
|
|
886
|
-
};
|
|
887
|
-
//#endregion
|
|
888
694
|
//#region src/detection-pipeline/engine/pool-worker-health.ts
|
|
889
695
|
/**
|
|
890
696
|
* The one table of load bounds (D653, fix round 1).
|
|
@@ -4229,6 +4035,29 @@ function benchmarkKeyOf(deviceKey) {
|
|
|
4229
4035
|
function isBenchmarkRun(input) {
|
|
4230
4036
|
return input.frame === void 0 && input.frameRef === void 0 && input.deviceId === void 0 && input.replay !== true;
|
|
4231
4037
|
}
|
|
4038
|
+
/**
|
|
4039
|
+
* Backends whose device opens in ONE process at a time. libedgetpu holds an
|
|
4040
|
+
* Edge TPU exclusively for the process that opened it, so a second pool on a
|
|
4041
|
+
* Coral the cameras' pool already holds cannot open it at all — every
|
|
4042
|
+
* benchmark and auto-benchmark (D913) of an in-use Coral failed that way on
|
|
4043
|
+
* the dev hub (1.2.619). Every other backend this node builds (OpenVINO,
|
|
4044
|
+
* CoreML, CUDA, ONNX, CPU) shares its device between processes.
|
|
4045
|
+
*/
|
|
4046
|
+
var EXCLUSIVE_BACKENDS = new Set(["edgetpu"]);
|
|
4047
|
+
/** True when the device behind `deviceKey` (`<backend>:<device>`) cannot be opened by a second pool. */
|
|
4048
|
+
function isExclusiveDevice(deviceKey) {
|
|
4049
|
+
const colon = deviceKey.indexOf(":");
|
|
4050
|
+
const backend = colon >= 0 ? deviceKey.slice(0, colon) : deviceKey;
|
|
4051
|
+
return EXCLUSIVE_BACKENDS.has(backend);
|
|
4052
|
+
}
|
|
4053
|
+
/**
|
|
4054
|
+
* A benchmark on an EXCLUSIVE device is the one benchmark that goes to the
|
|
4055
|
+
* live pool: the separate pool could not open the device, so the choice is
|
|
4056
|
+
* between measuring through the cameras' pool and not measuring at all.
|
|
4057
|
+
*/
|
|
4058
|
+
function benchmarkPlacementOf(benchmark, deviceKey) {
|
|
4059
|
+
return benchmark && !isExclusiveDevice(deviceKey) ? "benchmark-pool" : "live-pool";
|
|
4060
|
+
}
|
|
4232
4061
|
var BenchmarkPools = class {
|
|
4233
4062
|
options;
|
|
4234
4063
|
pools = /* @__PURE__ */ new Map();
|
|
@@ -4809,14 +4638,15 @@ var PRIMARY_ROOT_STEP = "object-detection";
|
|
|
4809
4638
|
/**
|
|
4810
4639
|
* The same rule over an EXECUTABLE tree's roots (D658): their model ids are the
|
|
4811
4640
|
* pool variants that will run — after resolution, per-step loads and drops —
|
|
4812
|
-
* so this is what a live `runPipeline` stamps
|
|
4813
|
-
* video roots already.
|
|
4814
|
-
*/
|
|
4815
|
-
function
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4641
|
+
* so this is what a live `runPipeline` stamps, with the root's step id beside
|
|
4642
|
+
* the model (D925). The tree holds only enabled video roots already.
|
|
4643
|
+
*/
|
|
4644
|
+
function resolveTreeRoot(roots) {
|
|
4645
|
+
const root = roots.find((s) => s.stepId === PRIMARY_ROOT_STEP) ?? roots[0];
|
|
4646
|
+
return root === void 0 ? void 0 : {
|
|
4647
|
+
stepId: root.stepId,
|
|
4648
|
+
modelId: root.modelId
|
|
4649
|
+
};
|
|
4820
4650
|
}
|
|
4821
4651
|
//#endregion
|
|
4822
4652
|
//#region src/detection-pipeline/engine-provisioner.ts
|
|
@@ -7872,16 +7702,6 @@ function collectSchemaDefaults(schema) {
|
|
|
7872
7702
|
walkFieldsForDefaults(schema, out);
|
|
7873
7703
|
return out;
|
|
7874
7704
|
}
|
|
7875
|
-
/**
|
|
7876
|
-
* The operator settings of `stepId` as the model that RUNS sees them (D738):
|
|
7877
|
-
* a model-bound value made for another model is dropped and binding keys are
|
|
7878
|
-
* stripped. For a settings layer merged AFTER the tree is built (the
|
|
7879
|
-
* executor's per-device store, `applyDeviceOverridesToTree`), so it obeys the
|
|
7880
|
-
* same binding as the layers `buildNode` merges.
|
|
7881
|
-
*/
|
|
7882
|
-
function resolveOperatorSettingsForModel(stepId, settings, runningModelId) {
|
|
7883
|
-
return require_dist.applyModelBoundSettings(settings, require_dist.collectModelBoundKeys(require_custom_model_catalog.getStep(stepId).getConfigSchema()), runningModelId) ?? {};
|
|
7884
|
-
}
|
|
7885
7705
|
function walkFieldsForDefaults(fields, out) {
|
|
7886
7706
|
for (const field of fields) {
|
|
7887
7707
|
if ("type" in field && field.type === "group" && "fields" in field) {
|
|
@@ -8570,7 +8390,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8570
8390
|
* node-default tree against `this.currentEngine.format`. Recomputed
|
|
8571
8391
|
* EAGERLY by {@link recomputeConfigIssues} whenever the engine actually
|
|
8572
8392
|
* changes (see `onEngineSelectionChanged`), rather than relying on a
|
|
8573
|
-
* `
|
|
8393
|
+
* `nodeDefaultSteps()` call that may never happen on a camera-only node.
|
|
8574
8394
|
* Merged into {@link getEngineProvisioning}'s snapshot; never consulted by
|
|
8575
8395
|
* `assertEngineReady` — this gate SURFACES, it does not block inference.
|
|
8576
8396
|
*/
|
|
@@ -8672,20 +8492,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8672
8492
|
readStore;
|
|
8673
8493
|
/** Write a patch to the addon settings store. */
|
|
8674
8494
|
writeStore;
|
|
8675
|
-
/** Read per-device settings. */
|
|
8676
|
-
readDeviceStore;
|
|
8677
|
-
/** Delete all per-device settings for a device (used by `clearDeviceOverrides`). */
|
|
8678
|
-
clearDeviceStore;
|
|
8679
|
-
/** Merge a patch into one device's settings (Auto tune' keep-the-rest rewrite, D745). */
|
|
8680
|
-
writeDeviceStore;
|
|
8681
|
-
/**
|
|
8682
|
-
* The per-device overrides the FRAME path reads, kept fresh off that path.
|
|
8683
|
-
*
|
|
8684
|
-
* Public so the addon class can drop a device on its own
|
|
8685
|
-
* `updateDeviceSettings` — the write and the mirror have to be the same
|
|
8686
|
-
* process's, or the mirror becomes the second authority D224 forbids.
|
|
8687
|
-
*/
|
|
8688
|
-
deviceOverrides;
|
|
8689
8495
|
constructor(settings, modelsDir, logger, eventBus = null, detectionConfigSchemaSource = null, executorOptions = {}) {
|
|
8690
8496
|
this.modelsDir = modelsDir;
|
|
8691
8497
|
this.eventBus = eventBus;
|
|
@@ -8694,18 +8500,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8694
8500
|
this.log = logger;
|
|
8695
8501
|
this.readStore = () => settings.readAddonStore();
|
|
8696
8502
|
this.writeStore = (patch) => settings.writeAddonStore(patch);
|
|
8697
|
-
this.readDeviceStore = settings.readDeviceStore ?? (async () => ({}));
|
|
8698
|
-
const clearDeviceStore = settings.clearDeviceStore;
|
|
8699
|
-
this.clearDeviceStore = clearDeviceStore ? (deviceId) => clearDeviceStore.call(settings, deviceId) : async () => void 0;
|
|
8700
|
-
const writeDeviceStore = settings.writeDeviceStore;
|
|
8701
|
-
this.writeDeviceStore = writeDeviceStore ? (deviceId, patch) => writeDeviceStore.call(settings, deviceId, patch) : async () => void 0;
|
|
8702
|
-
this.deviceOverrides = new DeviceOverrideMirror({
|
|
8703
|
-
read: (deviceId) => this.readDeviceStore(deviceId),
|
|
8704
|
-
onRefreshFailed: (deviceId, err) => this.log.warn("per-device detection overrides refresh failed — serving the last value", {
|
|
8705
|
-
tags: { deviceId },
|
|
8706
|
-
meta: { error: require_dist.errMsg(err) }
|
|
8707
|
-
})
|
|
8708
|
-
});
|
|
8709
8503
|
this.currentEngine = ONNX_FLOOR;
|
|
8710
8504
|
this.log.info("Engine pick pending (placeholder until probe / persisted selection)", { meta: {
|
|
8711
8505
|
runtime: this.currentEngine.runtime,
|
|
@@ -9008,7 +8802,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9008
8802
|
* the node-default step tree for `this.currentEngine.format` and compute
|
|
9009
8803
|
* human-readable config issues from the result:
|
|
9010
8804
|
* - model substitutions (`getActiveModelSubstitutions()`, populated as a
|
|
9011
|
-
* side effect of the `
|
|
8805
|
+
* side effect of the `nodeDefaultSteps()` re-resolve below) — a step's
|
|
9012
8806
|
* chosen model lacks a build for this format, so the format default
|
|
9013
8807
|
* runs instead (degraded but loadable).
|
|
9014
8808
|
* - zero-build steps (`collectZeroBuildIssues`) — a step whose FULL
|
|
@@ -9023,7 +8817,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9023
8817
|
async recomputeConfigIssues() {
|
|
9024
8818
|
this.configIssues = [];
|
|
9025
8819
|
try {
|
|
9026
|
-
const steps = await this.
|
|
8820
|
+
const steps = await this.nodeDefaultSteps();
|
|
9027
8821
|
if (!steps) return;
|
|
9028
8822
|
const format = this.currentEngine.format;
|
|
9029
8823
|
const substitutionIssues = this.getActiveModelSubstitutions().map((s) => `${s.addonId}: chose ${s.chosen}, running ${s.running} (${s.format})`);
|
|
@@ -9071,7 +8865,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9071
8865
|
* `format` for the download fan-out.
|
|
9072
8866
|
*/
|
|
9073
8867
|
async ensureModelsForCurrentSteps(format) {
|
|
9074
|
-
const steps = await this.
|
|
8868
|
+
const steps = await this.nodeDefaultSteps();
|
|
9075
8869
|
if (!steps || steps.length === 0) return;
|
|
9076
8870
|
for (const step of flattenSteps(steps)) {
|
|
9077
8871
|
if (!step.enabled) continue;
|
|
@@ -9244,10 +9038,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9244
9038
|
defaultDevice: e.engine.device
|
|
9245
9039
|
};
|
|
9246
9040
|
}
|
|
9247
|
-
async getDefaultSteps(engine) {
|
|
9248
|
-
const detectionModelId = require_custom_model_catalog.resolveDefaultDetectionModel(engine.backend, engine.device ?? null, engine.format);
|
|
9249
|
-
return buildDefaultStepTree(engine.format, detectionModelId);
|
|
9250
|
-
}
|
|
9251
9041
|
/**
|
|
9252
9042
|
* Resolve every step's model for this node's engine format via the shared
|
|
9253
9043
|
* `resolveModelForFormat`, and surface any substitution. `step.engine?.format`
|
|
@@ -9290,18 +9080,19 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9290
9080
|
return [...this.modelSubstitutions.values()];
|
|
9291
9081
|
}
|
|
9292
9082
|
/**
|
|
9293
|
-
* PURE node-default step tree — computed on demand, never persisted
|
|
9083
|
+
* PURE node-default step tree — computed on demand, never persisted, and
|
|
9084
|
+
* PRIVATE (D927): it is not the model any camera ran, so no caller outside
|
|
9085
|
+
* this provider may read it. It serves Gate A's config-issue probe and the
|
|
9086
|
+
* engine provisioning's model download.
|
|
9294
9087
|
*
|
|
9295
9088
|
* The object-detection default is hardware-aware (this node's resolved
|
|
9296
9089
|
* backend + device via `resolveDefaultDetectionModel`); every other step
|
|
9297
9090
|
* keeps its flat per-format default. The result is cached in
|
|
9298
9091
|
* `currentSteps` only as a memo — the cache is dropped whenever the
|
|
9299
9092
|
* engine (hence model format) changes, so a re-read always reflects the
|
|
9300
|
-
* live engine.
|
|
9301
|
-
* it exists as the benchmark fallback (empty input steps), the Gate-A
|
|
9302
|
-
* config-issue probe, and the "effective post-reset model" probe.
|
|
9093
|
+
* live engine.
|
|
9303
9094
|
*/
|
|
9304
|
-
async
|
|
9095
|
+
async nodeDefaultSteps() {
|
|
9305
9096
|
if (this.currentSteps) return this.currentSteps;
|
|
9306
9097
|
const detectionModelId = require_custom_model_catalog.resolveDefaultDetectionModel(this.currentEngine.backend, this.currentEngine.device ?? null, this.currentEngine.format);
|
|
9307
9098
|
const defaults = buildDefaultStepTree(this.currentEngine.format, detectionModelId);
|
|
@@ -9309,10 +9100,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9309
9100
|
this.currentSteps = this.resolveStepModels(defaults);
|
|
9310
9101
|
return this.currentSteps;
|
|
9311
9102
|
}
|
|
9312
|
-
async getGlobalPipelineConfig() {
|
|
9313
|
-
if (!this.currentSteps) return null;
|
|
9314
|
-
return stepsToPipelineConfig(this.currentSteps, this.currentEngine);
|
|
9315
|
-
}
|
|
9316
9103
|
/**
|
|
9317
9104
|
* Task G5 (Gate B) — pre-init config-correctness gate. PURE COMPUTE
|
|
9318
9105
|
* against `this.currentEngine.format`: resolves `steps` the same way the
|
|
@@ -9895,7 +9682,9 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9895
9682
|
this.executor = executor;
|
|
9896
9683
|
const dispatchEngine = dispatchDeviceKey ? require_custom_model_catalog.resolveDeviceEngine(dispatchDeviceKey) : runEngine;
|
|
9897
9684
|
const benchmark = isBenchmarkRun(input);
|
|
9898
|
-
const
|
|
9685
|
+
const placement = benchmarkPlacementOf(benchmark, require_custom_model_catalog.deviceKeyOf(dispatchEngine));
|
|
9686
|
+
if (benchmark && placement === "live-pool") this.log.info("Benchmark on an exclusive device — served by the live pool", { meta: { deviceKey: require_custom_model_catalog.deviceKeyOf(dispatchEngine) } });
|
|
9687
|
+
const dispatchFactory = placement === "benchmark-pool" ? await this.benchmarkPools.acquire(require_custom_model_catalog.deviceKeyOf(dispatchEngine), dispatchEngine) : dispatchDeviceKey ? await this.resolveDeviceFactory(dispatchDeviceKey) : this.engineFactory;
|
|
9899
9688
|
const needed = enabledSteps.filter((s) => dispatchFactory.needsPoolUpdate(s));
|
|
9900
9689
|
let runSteps = benchmarkSteps;
|
|
9901
9690
|
const loadPolicy = dispatchLoadPolicyOf(input);
|
|
@@ -9936,21 +9725,21 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9936
9725
|
}, dispatchDeviceKeyLabel, [model], model, "not-warm", require_dist.errMsg(failure.error));
|
|
9937
9726
|
}
|
|
9938
9727
|
}
|
|
9939
|
-
const
|
|
9728
|
+
const treeRoot = resolveTreeRoot(tree.roots);
|
|
9940
9729
|
const rootDeviceKey = require_custom_model_catalog.deviceKeyOf(dispatchEngine);
|
|
9941
|
-
const stampRoot = (r) =>
|
|
9730
|
+
const stampRoot = (r) => treeRoot === void 0 ? {
|
|
9942
9731
|
...r,
|
|
9943
9732
|
rootDeviceKey
|
|
9944
9733
|
} : {
|
|
9945
9734
|
...r,
|
|
9946
|
-
rootModelId,
|
|
9735
|
+
rootModelId: treeRoot.modelId,
|
|
9736
|
+
rootStepId: treeRoot.stepId,
|
|
9947
9737
|
rootDeviceKey
|
|
9948
9738
|
};
|
|
9949
9739
|
if (input.replay !== true) this.clusterModelSwitchLog.note(input.deviceId ?? 0, tree);
|
|
9950
9740
|
setupMs = performance.now() - wallT0 - decodeMs;
|
|
9951
9741
|
const effectiveDeviceId = input.deviceId ?? 0;
|
|
9952
|
-
const
|
|
9953
|
-
const effectiveTree = Object.keys(deviceOverrides).length > 0 ? applyDeviceOverridesToTree(tree, "object-detection", deviceOverrides) : tree;
|
|
9742
|
+
const effectiveTree = tree;
|
|
9954
9743
|
const nativeCropProvider = this.buildNativeCropProviderFromRef(input.nativeCropRef) ?? this.buildNativeFaceCropProvider(input.frameHandle);
|
|
9955
9744
|
let cropZoneBbox;
|
|
9956
9745
|
if (appliesCameraGates && effectiveDeviceId > 0 && effectiveTree.roots.some((r) => r.definition.extractMode === "crop-zone")) {
|
|
@@ -11285,102 +11074,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
11285
11074
|
this.log.info("videoPipelineSteps updated", { meta: { addons: Object.keys(sanitized).length } });
|
|
11286
11075
|
return { success: true };
|
|
11287
11076
|
}
|
|
11288
|
-
/**
|
|
11289
|
-
* Clear THIS node's executor-side PER-DEVICE settings stores — the
|
|
11290
|
-
* per-camera step overrides the object-detection root reads via
|
|
11291
|
-
* `applyDeviceOverridesToTree`.
|
|
11292
|
-
*
|
|
11293
|
-
* Node-routed (the cap's default `nodeIdMode: 'routing'`): the generated
|
|
11294
|
-
* cap-router strips `nodeId` and dispatches to the target node, so this
|
|
11295
|
-
* method runs ON the node being cleared and takes no argument.
|
|
11296
|
-
*
|
|
11297
|
-
* This is the slimmed executor leg of the orchestrator's
|
|
11298
|
-
* `resetNodePipelineDefaults` flow. The legacy `resetToDefault` — which
|
|
11299
|
-
* also reset a persisted GLOBAL step-tree seed nothing in the live
|
|
11300
|
-
* per-camera path read — was removed together with that seed
|
|
11301
|
-
* (`getGlobalSteps` is pure now, so there is nothing node-global left to
|
|
11302
|
-
* reset here).
|
|
11303
|
-
*
|
|
11304
|
-
* Idempotent: clearing already-empty per-device stores is a no-op.
|
|
11305
|
-
*/
|
|
11306
|
-
async clearDeviceOverrides() {
|
|
11307
|
-
const clearedDevices = await this.clearAllDeviceOverrides();
|
|
11308
|
-
this.log.info("executor per-device overrides cleared", { meta: { clearedDevices } });
|
|
11309
|
-
return {
|
|
11310
|
-
success: true,
|
|
11311
|
-
clearedDevices
|
|
11312
|
-
};
|
|
11313
|
-
}
|
|
11314
|
-
/**
|
|
11315
|
-
* Auto tune (D745): list — or, unless `dryRun`, remove — the model-bound
|
|
11316
|
-
* thresholds of the per-camera detector store. See
|
|
11317
|
-
* `model-bound-device-overrides.ts`.
|
|
11318
|
-
*/
|
|
11319
|
-
async clearModelBoundDeviceOverrides(input) {
|
|
11320
|
-
const result = await clearModelBoundDeviceOverrides({
|
|
11321
|
-
listDeviceIds: async () => {
|
|
11322
|
-
const api = this.addonCtx?.api;
|
|
11323
|
-
if (!api) throw new Error("clearModelBoundDeviceOverrides: ctx.api unavailable");
|
|
11324
|
-
return (await api.deviceManager.listAll.query({ projection: "slim" })).map((d) => d.id);
|
|
11325
|
-
},
|
|
11326
|
-
readDeviceStore: (deviceId) => this.readDeviceStore(deviceId),
|
|
11327
|
-
clearDeviceStore: (deviceId) => this.clearDeviceStore(deviceId),
|
|
11328
|
-
writeDeviceStore: (deviceId, patch) => this.writeDeviceStore(deviceId, patch),
|
|
11329
|
-
invalidate: (deviceId) => this.deviceOverrides.invalidate(deviceId),
|
|
11330
|
-
boundKeys: require_dist.collectModelBoundKeys(require_custom_model_catalog.getStep("object-detection").getConfigSchema())
|
|
11331
|
-
}, input);
|
|
11332
|
-
if (!input.dryRun) for (const entry of result.entries) this.log.info("auto tune: per-camera detector thresholds cleared", {
|
|
11333
|
-
tags: { deviceId: entry.deviceId },
|
|
11334
|
-
meta: {
|
|
11335
|
-
deviceId: entry.deviceId,
|
|
11336
|
-
keys: entry.keys
|
|
11337
|
-
}
|
|
11338
|
-
});
|
|
11339
|
-
for (const r of result.refused) this.log.warn("auto tune: per-camera detector thresholds not cleared", {
|
|
11340
|
-
tags: { deviceId: r.deviceId },
|
|
11341
|
-
meta: {
|
|
11342
|
-
deviceId: r.deviceId,
|
|
11343
|
-
reason: r.reason,
|
|
11344
|
-
dryRun: input.dryRun
|
|
11345
|
-
}
|
|
11346
|
-
});
|
|
11347
|
-
return result;
|
|
11348
|
-
}
|
|
11349
|
-
/**
|
|
11350
|
-
* Clear the per-device pipeline-step overrides for every known device.
|
|
11351
|
-
* Returns the count of devices whose store was cleared. There is no
|
|
11352
|
-
* bulk-list primitive over the per-device store, so devices are
|
|
11353
|
-
* enumerated via the device-manager and cleared one by one
|
|
11354
|
-
* (`clearDeviceStore` is idempotent — a device with no overrides is a
|
|
11355
|
-
* no-op). Never throws: a device-manager outage degrades to "cleared
|
|
11356
|
-
* nothing" so the reset flow still completes.
|
|
11357
|
-
*/
|
|
11358
|
-
async clearAllDeviceOverrides() {
|
|
11359
|
-
const api = this.addonCtx?.api;
|
|
11360
|
-
if (!api) return 0;
|
|
11361
|
-
let devices = [];
|
|
11362
|
-
try {
|
|
11363
|
-
devices = await api.deviceManager.listAll.query({ projection: "slim" });
|
|
11364
|
-
} catch (err) {
|
|
11365
|
-
this.log.warn("clearDeviceOverrides: device enumeration failed — skipping per-device clear", { meta: { error: require_dist.errMsg(err) } });
|
|
11366
|
-
return 0;
|
|
11367
|
-
}
|
|
11368
|
-
let cleared = 0;
|
|
11369
|
-
for (const device of devices) try {
|
|
11370
|
-
await this.clearDeviceStore(device.id);
|
|
11371
|
-
this.deviceOverrides.invalidate(device.id);
|
|
11372
|
-
cleared++;
|
|
11373
|
-
} catch (err) {
|
|
11374
|
-
this.log.warn("clearDeviceOverrides: failed to clear per-device overrides for device", {
|
|
11375
|
-
tags: { deviceId: device.id },
|
|
11376
|
-
meta: {
|
|
11377
|
-
deviceId: device.id,
|
|
11378
|
-
error: require_dist.errMsg(err)
|
|
11379
|
-
}
|
|
11380
|
-
});
|
|
11381
|
-
}
|
|
11382
|
-
return cleared;
|
|
11383
|
-
}
|
|
11384
11077
|
async listLoadedEngines() {
|
|
11385
11078
|
const out = [];
|
|
11386
11079
|
if (this.engineFactory) {
|
|
@@ -11627,7 +11320,6 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
|
|
|
11627
11320
|
defaultModelId: step.defaultModelId,
|
|
11628
11321
|
...step.defaultModelIdByFormat ? { defaultModelIdByFormat: { ...step.defaultModelIdByFormat } } : {},
|
|
11629
11322
|
...step.enabledByDefault !== void 0 ? { enabledByDefault: step.enabledByDefault } : {},
|
|
11630
|
-
...step.backfillIntoExistingOverrides !== void 0 ? { backfillIntoExistingOverrides: step.backfillIntoExistingOverrides } : {},
|
|
11631
11323
|
defaultConfidence: step.defaultConfidence,
|
|
11632
11324
|
...step.group ? { group: step.group } : {},
|
|
11633
11325
|
...configSchemaWithRoots.length > 0 ? { configSchema: configSchemaWithRoots } : {}
|
|
@@ -11675,7 +11367,7 @@ function resolveChildSlots(slot) {
|
|
|
11675
11367
|
}
|
|
11676
11368
|
/**
|
|
11677
11369
|
* V2 default: the node-default step tree (never persisted — see
|
|
11678
|
-
* `
|
|
11370
|
+
* `nodeDefaultSteps`). The core detection + recognition steps are enabled; every
|
|
11679
11371
|
* optional step is present with its catalog `enabledByDefault` (the animal and
|
|
11680
11372
|
* vehicle classifiers on — their answer comes from the root model when it
|
|
11681
11373
|
* declares them, D736 — the bird classifier and segmentation off).
|
|
@@ -11717,27 +11409,6 @@ function buildDefaultStepTree(format, objectDetectionModelId) {
|
|
|
11717
11409
|
if (audioStep) steps.push(audioStep);
|
|
11718
11410
|
return steps;
|
|
11719
11411
|
}
|
|
11720
|
-
function stepsToPipelineConfig(steps, engine) {
|
|
11721
|
-
const toNode = (step) => ({
|
|
11722
|
-
step: step.addonId,
|
|
11723
|
-
addon: step.addonId,
|
|
11724
|
-
configOverride: {
|
|
11725
|
-
modelId: step.modelId,
|
|
11726
|
-
...step.settings
|
|
11727
|
-
},
|
|
11728
|
-
children: step.children.map(toNode)
|
|
11729
|
-
});
|
|
11730
|
-
const videoSteps = steps.filter((s) => s.slot !== "audio-classifier");
|
|
11731
|
-
const audioStep = steps.find((s) => s.slot === "audio-classifier" && s.enabled);
|
|
11732
|
-
return {
|
|
11733
|
-
engine,
|
|
11734
|
-
video: videoSteps.map(toNode),
|
|
11735
|
-
...audioStep ? {
|
|
11736
|
-
audio: toNode(audioStep),
|
|
11737
|
-
audioEngine: engine
|
|
11738
|
-
} : {}
|
|
11739
|
-
};
|
|
11740
|
-
}
|
|
11741
11412
|
/** Flatten a step tree into a flat list (DFS) — delegates to shared utility. */
|
|
11742
11413
|
function flattenSteps(steps) {
|
|
11743
11414
|
return flattenEnabledVideoSteps(steps);
|
|
@@ -11798,22 +11469,6 @@ function availableFormatsForStep(addonId) {
|
|
|
11798
11469
|
return [];
|
|
11799
11470
|
}
|
|
11800
11471
|
}
|
|
11801
|
-
/**
|
|
11802
|
-
* Return a shallow-cloned executable tree with `rootStepId`'s `settings`
|
|
11803
|
-
* merged with `overrides` (per-device values win). Non-matching root steps
|
|
11804
|
-
* pass through unchanged. Used by `runFrame` to apply per-device detection
|
|
11805
|
-
* settings without rebuilding the tree per frame. A model-bound value (D738)
|
|
11806
|
-
* applies only while the model it was made for is the one the root RUNS.
|
|
11807
|
-
*/
|
|
11808
|
-
function applyDeviceOverridesToTree(tree, rootStepId, overrides) {
|
|
11809
|
-
return { roots: tree.roots.map((root) => root.stepId === rootStepId ? {
|
|
11810
|
-
...root,
|
|
11811
|
-
settings: {
|
|
11812
|
-
...root.settings,
|
|
11813
|
-
...resolveOperatorSettingsForModel(rootStepId, overrides, root.modelId)
|
|
11814
|
-
}
|
|
11815
|
-
} : root) };
|
|
11816
|
-
}
|
|
11817
11472
|
//#endregion
|
|
11818
11473
|
//#region src/detection-pipeline/python-readiness.ts
|
|
11819
11474
|
/**
|
|
@@ -11928,20 +11583,6 @@ function isProfileSliderKey(key) {
|
|
|
11928
11583
|
}
|
|
11929
11584
|
var DetectionPipelineAddon = class extends require_dist.BaseAddon {
|
|
11930
11585
|
provider = null;
|
|
11931
|
-
/**
|
|
11932
|
-
* An operator's own write drops the mirror the frame path reads.
|
|
11933
|
-
*
|
|
11934
|
-
* This override is the half of `device-override-mirror.ts` that keeps it from
|
|
11935
|
-
* being the second authority D224 forbids: `BaseAddon.updateDeviceSettings`
|
|
11936
|
-
* writes THIS addon's `<addonId>:addon-devices` row, so the write and the
|
|
11937
|
-
* mirror are in one process and the write invalidates. Without it the
|
|
11938
|
-
* operator's own change would be the one read the mirror got wrong, which is
|
|
11939
|
-
* the exact failure D224 records.
|
|
11940
|
-
*/
|
|
11941
|
-
async updateDeviceSettings(deviceId, patch) {
|
|
11942
|
-
await super.updateDeviceSettings(deviceId, patch);
|
|
11943
|
-
this.provider?.deviceOverrides.invalidate(deviceId);
|
|
11944
|
-
}
|
|
11945
11586
|
/** Last non-null probed hardware PER NODE — reused when the probe transiently
|
|
11946
11587
|
* returns null so offered backends / device lists don't collapse. Keyed by
|
|
11947
11588
|
* node because the hub addon probes other nodes when serving their config.
|