@camstack/addon-pipeline 1.2.621 → 1.2.623
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-BTBdgN2p.js} +29 -16
- package/dist/{custom-model-catalog-0_SnSXzN.mjs → custom-model-catalog-D5zTw1LU.mjs} +29 -10
- package/dist/detection-pipeline/index.js +67 -416
- package/dist/detection-pipeline/index.mjs +91 -440
- package/dist/{dist-ClkumZgv.js → dist-BVo3wa7s.js} +711 -302
- package/dist/{dist-DHqkQhTQ.mjs → dist-opSx6v5i.mjs} +651 -296
- package/dist/{model-catalogs-BagalaYp.js → model-catalogs-CQytR2AN.js} +1 -1
- package/dist/{model-catalogs-Z1GZAhSb.mjs → model-catalogs-rIvLUVlw.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-CGIYuJMN.mjs} +1 -1
- package/dist/{node-0O_61WVW.js → node-DqLsuN_A.js} +1 -1
- package/dist/pipeline-runner/index.js +115 -460
- package/dist/pipeline-runner/index.mjs +108 -453
- package/dist/{process-memory-Dj3UgL1e.mjs → process-memory-Bd-TuWfM.mjs} +1 -1
- package/dist/{process-memory-DdIOhjYB.js → process-memory-DyxG-0mG.js} +1 -1
- package/dist/recorder/index.js +2 -2
- package/dist/recorder/index.mjs +2 -2
- package/dist/{segment-demux-js-BePzacki.js → segment-demux-js-B4bfTQpK.js} +1 -1
- package/dist/{segment-demux-js-Bv0t0-tQ.mjs → segment-demux-js-CdVRzwSd.mjs} +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-DF3FGCR8.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-oUZNn2Kr.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-Bb-ETNGC.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-BiyFzSqq.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/accelerator_facts.py +275 -0
- package/python/coreml_load_probe.py +105 -15
- package/python/inference_pool.py +19 -2
- package/python/openvino_compile_probe.py +72 -18
- package/python/postprocessors/ssd.py +12 -4
- package/python/postprocessors/test_ssd.py +64 -0
- package/python/test_accelerator_facts.py +105 -0
- package/python/test_coreml_load_probe.py +83 -0
- package/python/test_openvino_compile_probe.py +114 -0
- package/python/webgpu_isolated.py +19 -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
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { $
|
|
3
|
-
import { c as readProcessCost } from "../node-
|
|
4
|
-
import {
|
|
2
|
+
import { $ as applyModelBoundSettings, Cn as runtimeDevices$1, Dt as enumerateInferenceDevices, En as stepModelRunsOnFormat, Er as EventCategory, Gn as BaseAddon, I as PoolMemoryWatchdog, O as LABEL_SUPPLY_MACRO, Ot as evaluateZoneRules, Qt as overlayClusterStepSettings, Sn as rootSuppliesOf, Tr as union, Un as errMsg, Ut as loadContributionCapability, Vt as linkedLabelStepId, Y as YAMNET_TO_MACRO, Zn as createEvent, d as CLUSTER_MODEL_SCOPED_STEPS, dt as containingParentIndex, en as pickClusterStepSettings, fr as sleep, g as DEFAULT_CLUSTER_STEP_SETTINGS, gt as defaultDeviceFor$1, hr as array, jn as supportedRuntimes$1, lr as nodePin, mn as resolveClusterStepModelId, n as APPLE_SA_TO_MACRO, nr as hfModelUrl, rn as pipelineExecutorCapability, rr as hydrateSchema, ut as collectModelBoundKeys, wr as string, wt as edgetpuDelegateDevice, xr as object, xt as detectionPipelineCapability, yn as resolvePoolMemoryPolicy } from "../dist-opSx6v5i.mjs";
|
|
3
|
+
import { c as readProcessCost } from "../node-CGIYuJMN.mjs";
|
|
4
|
+
import { S as resolveModelDefaultConfidence, _ as getDefaultModelForFormat, b as resolveModelForFormat, c as resolveDefaultDetectionModel, d as localFrameRegistry, g as ALL_STEPS, h as ALL_PIPELINE_STEPS, l as macroGateVerdict, n as mergeCustomModels, o as deviceKeyOf, r as buildSubtreeCanRun, s as resolveDeviceEngine, t as CustomModelCatalog, v as getStep, x as landmarkPrecisionVerdict, y as getStepDefinition } from "../custom-model-catalog-D5zTw1LU.mjs";
|
|
5
5
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
6
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
6
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-Bd-TuWfM.mjs";
|
|
7
7
|
import * as os$1 from "node:os";
|
|
8
8
|
import * as fs from "node:fs";
|
|
9
9
|
import * as path$1 from "node:path";
|
|
@@ -350,84 +350,6 @@ function normalizeEngineNodeId(rawNodeId) {
|
|
|
350
350
|
return raw.includes("/") ? raw.split("/")[0] ?? "hub" : raw;
|
|
351
351
|
}
|
|
352
352
|
//#endregion
|
|
353
|
-
//#region src/detection-pipeline/model-bound-device-overrides.ts
|
|
354
|
-
/**
|
|
355
|
-
* Auto tune (D745), the executor leg: list — and optionally remove — the
|
|
356
|
-
* MODEL-BOUND thresholds stored in this addon's per-camera settings (the
|
|
357
|
-
* object-detection root's `bindsToModel` keys and their binding keys, D738).
|
|
358
|
-
* Every other key of a camera's store is kept.
|
|
359
|
-
*
|
|
360
|
-
* The device store only MERGES on write, so a removal is clear + write of the
|
|
361
|
-
* kept keys — the idiom `migrate-hardware-state.ts` uses. Both run in this
|
|
362
|
-
* process, serialized per camera; a write that fails after the clear restores
|
|
363
|
-
* the original row, and the camera is reported `refused` rather than clean. A
|
|
364
|
-
* store that cannot be read is `refused` too: a failed read is never "nothing
|
|
365
|
-
* to clear" (D393).
|
|
366
|
-
*/
|
|
367
|
-
function errMsg(err) {
|
|
368
|
-
return err instanceof Error ? err.message : String(err);
|
|
369
|
-
}
|
|
370
|
-
/** The stored keys among `boundKeys` (values and bindings), sorted. */
|
|
371
|
-
function presentBoundKeys(row, boundKeys) {
|
|
372
|
-
return boundKeys.flatMap((k) => [k, modelBindingKey(k)]).filter((k) => k in row).toSorted();
|
|
373
|
-
}
|
|
374
|
-
async function clearModelBoundDeviceOverrides(deps, input) {
|
|
375
|
-
const ids = input.deviceIds ?? await deps.listDeviceIds();
|
|
376
|
-
const entries = [];
|
|
377
|
-
const refused = [];
|
|
378
|
-
for (const deviceId of [...ids].toSorted((a, b) => a - b)) {
|
|
379
|
-
let row;
|
|
380
|
-
try {
|
|
381
|
-
row = await deps.readDeviceStore(deviceId);
|
|
382
|
-
} catch (err) {
|
|
383
|
-
refused.push({
|
|
384
|
-
deviceId,
|
|
385
|
-
reason: `read failed: ${errMsg(err)}`
|
|
386
|
-
});
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
const keys = presentBoundKeys(row, deps.boundKeys);
|
|
390
|
-
if (keys.length === 0) continue;
|
|
391
|
-
if (input.dryRun) {
|
|
392
|
-
entries.push({
|
|
393
|
-
deviceId,
|
|
394
|
-
keys
|
|
395
|
-
});
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
const kept = { ...row };
|
|
399
|
-
for (const k of keys) delete kept[k];
|
|
400
|
-
try {
|
|
401
|
-
await deps.clearDeviceStore(deviceId);
|
|
402
|
-
} catch (err) {
|
|
403
|
-
refused.push({
|
|
404
|
-
deviceId,
|
|
405
|
-
reason: `clear failed: ${errMsg(err)}`
|
|
406
|
-
});
|
|
407
|
-
continue;
|
|
408
|
-
}
|
|
409
|
-
try {
|
|
410
|
-
if (Object.keys(kept).length > 0) await deps.writeDeviceStore(deviceId, kept);
|
|
411
|
-
entries.push({
|
|
412
|
-
deviceId,
|
|
413
|
-
keys
|
|
414
|
-
});
|
|
415
|
-
} catch (err) {
|
|
416
|
-
await deps.writeDeviceStore(deviceId, row).catch(() => void 0);
|
|
417
|
-
refused.push({
|
|
418
|
-
deviceId,
|
|
419
|
-
reason: `write failed, row restored: ${errMsg(err)}`
|
|
420
|
-
});
|
|
421
|
-
} finally {
|
|
422
|
-
deps.invalidate(deviceId);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
return {
|
|
426
|
-
entries,
|
|
427
|
-
refused
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
//#endregion
|
|
431
353
|
//#region src/detection-pipeline/model-format-facts.ts
|
|
432
354
|
/**
|
|
433
355
|
* Two per-format facts `getSchema` reports beside `downloaded`, for Model
|
|
@@ -762,122 +684,6 @@ var ClusterUnknownRefusalLog = class {
|
|
|
762
684
|
}
|
|
763
685
|
};
|
|
764
686
|
//#endregion
|
|
765
|
-
//#region src/detection-pipeline/device-override-mirror.ts
|
|
766
|
-
/**
|
|
767
|
-
* The per-device detection overrides, kept fresh OFF the frame path.
|
|
768
|
-
*
|
|
769
|
-
* ## The read this replaces
|
|
770
|
-
*
|
|
771
|
-
* `runPipeline` resolved a device's overrides by calling
|
|
772
|
-
* `settings.readDeviceStore(deviceId)` on **every inference frame**. Measured
|
|
773
|
-
* on the live hub 2026-08-25: `get detection-pipeline:addon-devices`, 1 143
|
|
774
|
-
* calls a minute at 0.44 rows per call — the disk asked, nineteen times a
|
|
775
|
-
* second, whether an operator has ever changed a threshold.
|
|
776
|
-
*
|
|
777
|
-
* ## Why this is not "a cache in the consumer" (D224)
|
|
778
|
-
*
|
|
779
|
-
* D224 forbids a SECOND authority over a fact that belongs to somebody else:
|
|
780
|
-
* the failure it records is a consumer caching a value whose write path does
|
|
781
|
-
* not run through that consumer, so an operator's own change is the one read
|
|
782
|
-
* the cache gets wrong.
|
|
783
|
-
*
|
|
784
|
-
* This addon OWNS the row. `<addonId>:addon-devices` is detection-pipeline's
|
|
785
|
-
* own store, and the only writers are this addon's `updateDeviceSettings` and
|
|
786
|
-
* its `clearDeviceOverrides` — both of which call {@link invalidate}. A write
|
|
787
|
-
* is therefore its own invalidation, exactly as D224 requires, and the window
|
|
788
|
-
* below governs only the case nobody writes through this process.
|
|
789
|
-
*
|
|
790
|
-
* ## The window, declared
|
|
791
|
-
*
|
|
792
|
-
* {@link DEVICE_OVERRIDE_STALE_MS} is what an operator's change costs on a node
|
|
793
|
-
* that did NOT serve the write — this addon runs per node, and a settings write
|
|
794
|
-
* lands on one of them. Thirty seconds is the trade: it removes 99.9% of the
|
|
795
|
-
* reads (one per device per window instead of one per frame) and it is short
|
|
796
|
-
* enough that "I moved the threshold and nothing happened" is not a support
|
|
797
|
-
* question. Ten minutes — {@link OPERATOR_WRITTEN_STALE_MS}, the constant for a
|
|
798
|
-
* cap whose value only an operator changes — is right for a POLLED reader that
|
|
799
|
-
* costs a camera round trip; this read costs one local SQLite `get`, and the
|
|
800
|
-
* cheap read buys a short window.
|
|
801
|
-
*
|
|
802
|
-
* A stale entry is SERVED and revalidated behind the caller, never awaited: a
|
|
803
|
-
* frame that waits for the settings store is a frame the pipeline dropped, and
|
|
804
|
-
* the reader is by definition about to ask again.
|
|
805
|
-
*/
|
|
806
|
-
/**
|
|
807
|
-
* How long a mirrored entry is served before a refresh is started behind the
|
|
808
|
-
* next reader. See the module doc for why it is 30 s and not ten minutes.
|
|
809
|
-
*/
|
|
810
|
-
var DEVICE_OVERRIDE_STALE_MS = 3e4;
|
|
811
|
-
/**
|
|
812
|
-
* How long a FAILED refresh is not retried.
|
|
813
|
-
*
|
|
814
|
-
* A refresh that throws leaves `fetchedAt` where it was, so without a cooldown
|
|
815
|
-
* every subsequent frame would start another one — a broken settings store
|
|
816
|
-
* would be hammered at frame rate by the very mechanism built to stop that.
|
|
817
|
-
*/
|
|
818
|
-
var DEVICE_OVERRIDE_MISS_COOLDOWN_MS = 5e3;
|
|
819
|
-
var DeviceOverrideMirror = class {
|
|
820
|
-
deps;
|
|
821
|
-
staleMs;
|
|
822
|
-
missCooldownMs;
|
|
823
|
-
entries = /* @__PURE__ */ new Map();
|
|
824
|
-
/** In-flight reads, so a burst of frames on a cold device costs ONE read and
|
|
825
|
-
* not one per frame — the exact failure this class exists to remove. */
|
|
826
|
-
inFlight = /* @__PURE__ */ new Map();
|
|
827
|
-
now;
|
|
828
|
-
constructor(deps, staleMs = DEVICE_OVERRIDE_STALE_MS, missCooldownMs = DEVICE_OVERRIDE_MISS_COOLDOWN_MS) {
|
|
829
|
-
this.deps = deps;
|
|
830
|
-
this.staleMs = staleMs;
|
|
831
|
-
this.missCooldownMs = missCooldownMs;
|
|
832
|
-
this.now = deps.now ?? (() => Date.now());
|
|
833
|
-
}
|
|
834
|
-
/**
|
|
835
|
-
* The device's overrides.
|
|
836
|
-
*
|
|
837
|
-
* COLD awaits — the first frame on a camera has to get the real answer, and a
|
|
838
|
-
* default is exactly what "the operator lowered this threshold" looks like.
|
|
839
|
-
* WARM returns immediately, stale or not, and starts the refresh behind the
|
|
840
|
-
* caller.
|
|
841
|
-
*/
|
|
842
|
-
async resolve(deviceId) {
|
|
843
|
-
const entry = this.entries.get(deviceId);
|
|
844
|
-
if (entry === void 0) return this.load(deviceId);
|
|
845
|
-
if (this.now() - entry.fetchedAt >= this.staleMs) this.load(deviceId);
|
|
846
|
-
return entry.value;
|
|
847
|
-
}
|
|
848
|
-
/** Drop a device's entry. Called by every writer in this process, so an
|
|
849
|
-
* operator's own change is never served from the mirror. */
|
|
850
|
-
invalidate(deviceId) {
|
|
851
|
-
this.entries.delete(deviceId);
|
|
852
|
-
}
|
|
853
|
-
invalidateAll() {
|
|
854
|
-
this.entries.clear();
|
|
855
|
-
}
|
|
856
|
-
async load(deviceId) {
|
|
857
|
-
const pending = this.inFlight.get(deviceId);
|
|
858
|
-
if (pending !== void 0) return pending;
|
|
859
|
-
const run = this.deps.read(deviceId).then((value) => {
|
|
860
|
-
this.entries.set(deviceId, {
|
|
861
|
-
value,
|
|
862
|
-
fetchedAt: this.now()
|
|
863
|
-
});
|
|
864
|
-
return value;
|
|
865
|
-
}).catch((err) => {
|
|
866
|
-
this.deps.onRefreshFailed?.(deviceId, err);
|
|
867
|
-
const existing = this.entries.get(deviceId);
|
|
868
|
-
if (existing !== void 0) {
|
|
869
|
-
existing.fetchedAt = this.now() - this.staleMs + this.missCooldownMs;
|
|
870
|
-
return existing.value;
|
|
871
|
-
}
|
|
872
|
-
return {};
|
|
873
|
-
}).finally(() => {
|
|
874
|
-
this.inFlight.delete(deviceId);
|
|
875
|
-
});
|
|
876
|
-
this.inFlight.set(deviceId, run);
|
|
877
|
-
return run;
|
|
878
|
-
}
|
|
879
|
-
};
|
|
880
|
-
//#endregion
|
|
881
687
|
//#region src/detection-pipeline/engine/pool-worker-health.ts
|
|
882
688
|
/**
|
|
883
689
|
* The one table of load bounds (D653, fix round 1).
|
|
@@ -3262,6 +3068,14 @@ var PipelineModelManager = class {
|
|
|
3262
3068
|
}
|
|
3263
3069
|
};
|
|
3264
3070
|
//#endregion
|
|
3071
|
+
//#region src/detection-pipeline/engine/labels-for-decoder.ts
|
|
3072
|
+
/** Labels forwarded to the Python pool — SSD stock Coral keeps COCO-90 in Python. */
|
|
3073
|
+
function labelsForDecoder(postprocessor, modelLabels, stepLabels) {
|
|
3074
|
+
if (modelLabels !== void 0 && modelLabels.length > 0) return modelLabels;
|
|
3075
|
+
if (postprocessor === "ssd") return;
|
|
3076
|
+
return stepLabels;
|
|
3077
|
+
}
|
|
3078
|
+
//#endregion
|
|
3265
3079
|
//#region src/detection-pipeline/engine/coral-cocompiled-set.ts
|
|
3266
3080
|
var ROOT_DETECTOR_STEP_ID = "object-detection";
|
|
3267
3081
|
/** The models a dispatch places on the pool that runs it: every enabled video step. */
|
|
@@ -3946,7 +3760,9 @@ function buildPoolModelConfigForStep(inputs) {
|
|
|
3946
3760
|
const inputSize = Math.max(inputWidth, inputHeight);
|
|
3947
3761
|
const inputChannels = modelEntry.inputChannels ?? 3;
|
|
3948
3762
|
const entryLabels = modelEntry.labels.length > 0 ? modelEntry.labels.map((l) => l.id) : void 0;
|
|
3949
|
-
const
|
|
3763
|
+
const modelLabels = readModelLabels(modelsDir, modelEntry) ?? entryLabels;
|
|
3764
|
+
const effectivePostprocessor = resolveEffectivePostprocessorForEntry(def, modelEntry);
|
|
3765
|
+
const labels = labelsForDecoder(effectivePostprocessor, modelLabels, def.labels);
|
|
3950
3766
|
return {
|
|
3951
3767
|
path: modelPath,
|
|
3952
3768
|
inputSize,
|
|
@@ -3957,7 +3773,7 @@ function buildPoolModelConfigForStep(inputs) {
|
|
|
3957
3773
|
inputNormalization: modelEntry.inputNormalization,
|
|
3958
3774
|
outputProbabilities: modelEntry.outputProbabilities,
|
|
3959
3775
|
...modelEntry.gpuInferencePrecision !== void 0 ? { gpuInferencePrecision: modelEntry.gpuInferencePrecision } : {},
|
|
3960
|
-
postprocessor:
|
|
3776
|
+
postprocessor: effectivePostprocessor,
|
|
3961
3777
|
confidence: resolvePoolConfidenceFloor(stepId, resolveModelDefaultConfidence(def, modelEntry)),
|
|
3962
3778
|
nmsIouThreshold: resolvePoolDecodeSettings({
|
|
3963
3779
|
def,
|
|
@@ -4222,6 +4038,29 @@ function benchmarkKeyOf(deviceKey) {
|
|
|
4222
4038
|
function isBenchmarkRun(input) {
|
|
4223
4039
|
return input.frame === void 0 && input.frameRef === void 0 && input.deviceId === void 0 && input.replay !== true;
|
|
4224
4040
|
}
|
|
4041
|
+
/**
|
|
4042
|
+
* Backends whose device opens in ONE process at a time. libedgetpu holds an
|
|
4043
|
+
* Edge TPU exclusively for the process that opened it, so a second pool on a
|
|
4044
|
+
* Coral the cameras' pool already holds cannot open it at all — every
|
|
4045
|
+
* benchmark and auto-benchmark (D913) of an in-use Coral failed that way on
|
|
4046
|
+
* the dev hub (1.2.619). Every other backend this node builds (OpenVINO,
|
|
4047
|
+
* CoreML, CUDA, ONNX, CPU) shares its device between processes.
|
|
4048
|
+
*/
|
|
4049
|
+
var EXCLUSIVE_BACKENDS = new Set(["edgetpu"]);
|
|
4050
|
+
/** True when the device behind `deviceKey` (`<backend>:<device>`) cannot be opened by a second pool. */
|
|
4051
|
+
function isExclusiveDevice(deviceKey) {
|
|
4052
|
+
const colon = deviceKey.indexOf(":");
|
|
4053
|
+
const backend = colon >= 0 ? deviceKey.slice(0, colon) : deviceKey;
|
|
4054
|
+
return EXCLUSIVE_BACKENDS.has(backend);
|
|
4055
|
+
}
|
|
4056
|
+
/**
|
|
4057
|
+
* A benchmark on an EXCLUSIVE device is the one benchmark that goes to the
|
|
4058
|
+
* live pool: the separate pool could not open the device, so the choice is
|
|
4059
|
+
* between measuring through the cameras' pool and not measuring at all.
|
|
4060
|
+
*/
|
|
4061
|
+
function benchmarkPlacementOf(benchmark, deviceKey) {
|
|
4062
|
+
return benchmark && !isExclusiveDevice(deviceKey) ? "benchmark-pool" : "live-pool";
|
|
4063
|
+
}
|
|
4225
4064
|
var BenchmarkPools = class {
|
|
4226
4065
|
options;
|
|
4227
4066
|
pools = /* @__PURE__ */ new Map();
|
|
@@ -4802,14 +4641,15 @@ var PRIMARY_ROOT_STEP = "object-detection";
|
|
|
4802
4641
|
/**
|
|
4803
4642
|
* The same rule over an EXECUTABLE tree's roots (D658): their model ids are the
|
|
4804
4643
|
* pool variants that will run — after resolution, per-step loads and drops —
|
|
4805
|
-
* so this is what a live `runPipeline` stamps
|
|
4806
|
-
* video roots already.
|
|
4807
|
-
*/
|
|
4808
|
-
function
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4644
|
+
* so this is what a live `runPipeline` stamps, with the root's step id beside
|
|
4645
|
+
* the model (D925). The tree holds only enabled video roots already.
|
|
4646
|
+
*/
|
|
4647
|
+
function resolveTreeRoot(roots) {
|
|
4648
|
+
const root = roots.find((s) => s.stepId === PRIMARY_ROOT_STEP) ?? roots[0];
|
|
4649
|
+
return root === void 0 ? void 0 : {
|
|
4650
|
+
stepId: root.stepId,
|
|
4651
|
+
modelId: root.modelId
|
|
4652
|
+
};
|
|
4813
4653
|
}
|
|
4814
4654
|
//#endregion
|
|
4815
4655
|
//#region src/detection-pipeline/engine-provisioner.ts
|
|
@@ -7189,7 +7029,7 @@ var PipelineExecutor = class {
|
|
|
7189
7029
|
rootStepId: rootStep.stepId,
|
|
7190
7030
|
parentClass: mutable.macroClass,
|
|
7191
7031
|
parentScore: mutable.score,
|
|
7192
|
-
error: errMsg
|
|
7032
|
+
error: errMsg(err)
|
|
7193
7033
|
}
|
|
7194
7034
|
});
|
|
7195
7035
|
}
|
|
@@ -7320,7 +7160,7 @@ var PipelineExecutor = class {
|
|
|
7320
7160
|
rootStepId: rootStep.stepId,
|
|
7321
7161
|
parentClass: mutable.macroClass,
|
|
7322
7162
|
parentScore: mutable.score,
|
|
7323
|
-
error: errMsg
|
|
7163
|
+
error: errMsg(err)
|
|
7324
7164
|
}
|
|
7325
7165
|
});
|
|
7326
7166
|
}
|
|
@@ -7419,7 +7259,7 @@ var PipelineExecutor = class {
|
|
|
7419
7259
|
]
|
|
7420
7260
|
};
|
|
7421
7261
|
} catch (err) {
|
|
7422
|
-
this.throttledWarn(`crop-zone-prep:${deviceId}`, 3e4, "crop-zone frame preparation failed — running package-detection full-frame", { error: errMsg
|
|
7262
|
+
this.throttledWarn(`crop-zone-prep:${deviceId}`, 3e4, "crop-zone frame preparation failed — running package-detection full-frame", { error: errMsg(err) }, deviceId);
|
|
7423
7263
|
return null;
|
|
7424
7264
|
}
|
|
7425
7265
|
}
|
|
@@ -7431,7 +7271,7 @@ var PipelineExecutor = class {
|
|
|
7431
7271
|
try {
|
|
7432
7272
|
engineOutput = await step.engine.infer(input);
|
|
7433
7273
|
} catch (err) {
|
|
7434
|
-
const errorMsg = errMsg
|
|
7274
|
+
const errorMsg = errMsg(err);
|
|
7435
7275
|
const errorOutput = {
|
|
7436
7276
|
kind: "detections",
|
|
7437
7277
|
detections: []
|
|
@@ -7718,7 +7558,7 @@ var PipelineExecutor = class {
|
|
|
7718
7558
|
this.throttledWarn(`child-fail:${child.stepId}:${deviceId}`, 15e3, "pipeline child step failed", {
|
|
7719
7559
|
step: child.stepId,
|
|
7720
7560
|
model: child.modelId,
|
|
7721
|
-
error: errMsg
|
|
7561
|
+
error: errMsg(err)
|
|
7722
7562
|
}, deviceId);
|
|
7723
7563
|
}
|
|
7724
7564
|
}
|
|
@@ -7865,16 +7705,6 @@ function collectSchemaDefaults(schema) {
|
|
|
7865
7705
|
walkFieldsForDefaults(schema, out);
|
|
7866
7706
|
return out;
|
|
7867
7707
|
}
|
|
7868
|
-
/**
|
|
7869
|
-
* The operator settings of `stepId` as the model that RUNS sees them (D738):
|
|
7870
|
-
* a model-bound value made for another model is dropped and binding keys are
|
|
7871
|
-
* stripped. For a settings layer merged AFTER the tree is built (the
|
|
7872
|
-
* executor's per-device store, `applyDeviceOverridesToTree`), so it obeys the
|
|
7873
|
-
* same binding as the layers `buildNode` merges.
|
|
7874
|
-
*/
|
|
7875
|
-
function resolveOperatorSettingsForModel(stepId, settings, runningModelId) {
|
|
7876
|
-
return applyModelBoundSettings(settings, collectModelBoundKeys(getStep(stepId).getConfigSchema()), runningModelId) ?? {};
|
|
7877
|
-
}
|
|
7878
7708
|
function walkFieldsForDefaults(fields, out) {
|
|
7879
7709
|
for (const field of fields) {
|
|
7880
7710
|
if ("type" in field && field.type === "group" && "fields" in field) {
|
|
@@ -8563,7 +8393,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8563
8393
|
* node-default tree against `this.currentEngine.format`. Recomputed
|
|
8564
8394
|
* EAGERLY by {@link recomputeConfigIssues} whenever the engine actually
|
|
8565
8395
|
* changes (see `onEngineSelectionChanged`), rather than relying on a
|
|
8566
|
-
* `
|
|
8396
|
+
* `nodeDefaultSteps()` call that may never happen on a camera-only node.
|
|
8567
8397
|
* Merged into {@link getEngineProvisioning}'s snapshot; never consulted by
|
|
8568
8398
|
* `assertEngineReady` — this gate SURFACES, it does not block inference.
|
|
8569
8399
|
*/
|
|
@@ -8665,20 +8495,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8665
8495
|
readStore;
|
|
8666
8496
|
/** Write a patch to the addon settings store. */
|
|
8667
8497
|
writeStore;
|
|
8668
|
-
/** Read per-device settings. */
|
|
8669
|
-
readDeviceStore;
|
|
8670
|
-
/** Delete all per-device settings for a device (used by `clearDeviceOverrides`). */
|
|
8671
|
-
clearDeviceStore;
|
|
8672
|
-
/** Merge a patch into one device's settings (Auto tune' keep-the-rest rewrite, D745). */
|
|
8673
|
-
writeDeviceStore;
|
|
8674
|
-
/**
|
|
8675
|
-
* The per-device overrides the FRAME path reads, kept fresh off that path.
|
|
8676
|
-
*
|
|
8677
|
-
* Public so the addon class can drop a device on its own
|
|
8678
|
-
* `updateDeviceSettings` — the write and the mirror have to be the same
|
|
8679
|
-
* process's, or the mirror becomes the second authority D224 forbids.
|
|
8680
|
-
*/
|
|
8681
|
-
deviceOverrides;
|
|
8682
8498
|
constructor(settings, modelsDir, logger, eventBus = null, detectionConfigSchemaSource = null, executorOptions = {}) {
|
|
8683
8499
|
this.modelsDir = modelsDir;
|
|
8684
8500
|
this.eventBus = eventBus;
|
|
@@ -8687,18 +8503,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8687
8503
|
this.log = logger;
|
|
8688
8504
|
this.readStore = () => settings.readAddonStore();
|
|
8689
8505
|
this.writeStore = (patch) => settings.writeAddonStore(patch);
|
|
8690
|
-
this.readDeviceStore = settings.readDeviceStore ?? (async () => ({}));
|
|
8691
|
-
const clearDeviceStore = settings.clearDeviceStore;
|
|
8692
|
-
this.clearDeviceStore = clearDeviceStore ? (deviceId) => clearDeviceStore.call(settings, deviceId) : async () => void 0;
|
|
8693
|
-
const writeDeviceStore = settings.writeDeviceStore;
|
|
8694
|
-
this.writeDeviceStore = writeDeviceStore ? (deviceId, patch) => writeDeviceStore.call(settings, deviceId, patch) : async () => void 0;
|
|
8695
|
-
this.deviceOverrides = new DeviceOverrideMirror({
|
|
8696
|
-
read: (deviceId) => this.readDeviceStore(deviceId),
|
|
8697
|
-
onRefreshFailed: (deviceId, err) => this.log.warn("per-device detection overrides refresh failed — serving the last value", {
|
|
8698
|
-
tags: { deviceId },
|
|
8699
|
-
meta: { error: errMsg$1(err) }
|
|
8700
|
-
})
|
|
8701
|
-
});
|
|
8702
8506
|
this.currentEngine = ONNX_FLOOR;
|
|
8703
8507
|
this.log.info("Engine pick pending (placeholder until probe / persisted selection)", { meta: {
|
|
8704
8508
|
runtime: this.currentEngine.runtime,
|
|
@@ -8722,7 +8526,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8722
8526
|
stale: report.stale
|
|
8723
8527
|
} });
|
|
8724
8528
|
}, (err) => {
|
|
8725
|
-
this.log.warn("Model revision check failed — copies are proven on their next download", { meta: { error: errMsg
|
|
8529
|
+
this.log.warn("Model revision check failed — copies are proven on their next download", { meta: { error: errMsg(err) } });
|
|
8726
8530
|
});
|
|
8727
8531
|
}
|
|
8728
8532
|
/**
|
|
@@ -8832,14 +8636,14 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
8832
8636
|
else this.log.warn("platform-probe readiness gate timed out — conservative engine pick (floor is not persisted)", { meta: {
|
|
8833
8637
|
nodeId,
|
|
8834
8638
|
timeoutMs: PROBE_READY_TIMEOUT_MS,
|
|
8835
|
-
error: errMsg
|
|
8639
|
+
error: errMsg(err)
|
|
8836
8640
|
} });
|
|
8837
8641
|
}
|
|
8838
8642
|
await this.resolveAutoEngine();
|
|
8839
8643
|
this.needsAutoPick = false;
|
|
8840
8644
|
this.startProvisioningForCurrentEngine();
|
|
8841
8645
|
await this.recomputeConfigIssues().catch((err) => {
|
|
8842
|
-
this.log.warn("config-issue recompute failed after node-default derive", { meta: { error: errMsg
|
|
8646
|
+
this.log.warn("config-issue recompute failed after node-default derive", { meta: { error: errMsg(err) } });
|
|
8843
8647
|
});
|
|
8844
8648
|
}
|
|
8845
8649
|
/**
|
|
@@ -9001,7 +8805,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9001
8805
|
* the node-default step tree for `this.currentEngine.format` and compute
|
|
9002
8806
|
* human-readable config issues from the result:
|
|
9003
8807
|
* - model substitutions (`getActiveModelSubstitutions()`, populated as a
|
|
9004
|
-
* side effect of the `
|
|
8808
|
+
* side effect of the `nodeDefaultSteps()` re-resolve below) — a step's
|
|
9005
8809
|
* chosen model lacks a build for this format, so the format default
|
|
9006
8810
|
* runs instead (degraded but loadable).
|
|
9007
8811
|
* - zero-build steps (`collectZeroBuildIssues`) — a step whose FULL
|
|
@@ -9016,7 +8820,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9016
8820
|
async recomputeConfigIssues() {
|
|
9017
8821
|
this.configIssues = [];
|
|
9018
8822
|
try {
|
|
9019
|
-
const steps = await this.
|
|
8823
|
+
const steps = await this.nodeDefaultSteps();
|
|
9020
8824
|
if (!steps) return;
|
|
9021
8825
|
const format = this.currentEngine.format;
|
|
9022
8826
|
const substitutionIssues = this.getActiveModelSubstitutions().map((s) => `${s.addonId}: chose ${s.chosen}, running ${s.running} (${s.format})`);
|
|
@@ -9024,7 +8828,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9024
8828
|
this.configIssues = [...substitutionIssues, ...zeroBuildIssues];
|
|
9025
8829
|
} catch (err) {
|
|
9026
8830
|
this.configIssues = [];
|
|
9027
|
-
this.log.warn("engine-change config gate failed — no config issues surfaced", { meta: { error: errMsg
|
|
8831
|
+
this.log.warn("engine-change config gate failed — no config issues surfaced", { meta: { error: errMsg(err) } });
|
|
9028
8832
|
}
|
|
9029
8833
|
}
|
|
9030
8834
|
/**
|
|
@@ -9064,7 +8868,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9064
8868
|
* `format` for the download fan-out.
|
|
9065
8869
|
*/
|
|
9066
8870
|
async ensureModelsForCurrentSteps(format) {
|
|
9067
|
-
const steps = await this.
|
|
8871
|
+
const steps = await this.nodeDefaultSteps();
|
|
9068
8872
|
if (!steps || steps.length === 0) return;
|
|
9069
8873
|
for (const step of flattenSteps(steps)) {
|
|
9070
8874
|
if (!step.enabled) continue;
|
|
@@ -9237,10 +9041,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9237
9041
|
defaultDevice: e.engine.device
|
|
9238
9042
|
};
|
|
9239
9043
|
}
|
|
9240
|
-
async getDefaultSteps(engine) {
|
|
9241
|
-
const detectionModelId = resolveDefaultDetectionModel(engine.backend, engine.device ?? null, engine.format);
|
|
9242
|
-
return buildDefaultStepTree(engine.format, detectionModelId);
|
|
9243
|
-
}
|
|
9244
9044
|
/**
|
|
9245
9045
|
* Resolve every step's model for this node's engine format via the shared
|
|
9246
9046
|
* `resolveModelForFormat`, and surface any substitution. `step.engine?.format`
|
|
@@ -9283,18 +9083,19 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9283
9083
|
return [...this.modelSubstitutions.values()];
|
|
9284
9084
|
}
|
|
9285
9085
|
/**
|
|
9286
|
-
* PURE node-default step tree — computed on demand, never persisted
|
|
9086
|
+
* PURE node-default step tree — computed on demand, never persisted, and
|
|
9087
|
+
* PRIVATE (D927): it is not the model any camera ran, so no caller outside
|
|
9088
|
+
* this provider may read it. It serves Gate A's config-issue probe and the
|
|
9089
|
+
* engine provisioning's model download.
|
|
9287
9090
|
*
|
|
9288
9091
|
* The object-detection default is hardware-aware (this node's resolved
|
|
9289
9092
|
* backend + device via `resolveDefaultDetectionModel`); every other step
|
|
9290
9093
|
* keeps its flat per-format default. The result is cached in
|
|
9291
9094
|
* `currentSteps` only as a memo — the cache is dropped whenever the
|
|
9292
9095
|
* engine (hence model format) changes, so a re-read always reflects the
|
|
9293
|
-
* live engine.
|
|
9294
|
-
* it exists as the benchmark fallback (empty input steps), the Gate-A
|
|
9295
|
-
* config-issue probe, and the "effective post-reset model" probe.
|
|
9096
|
+
* live engine.
|
|
9296
9097
|
*/
|
|
9297
|
-
async
|
|
9098
|
+
async nodeDefaultSteps() {
|
|
9298
9099
|
if (this.currentSteps) return this.currentSteps;
|
|
9299
9100
|
const detectionModelId = resolveDefaultDetectionModel(this.currentEngine.backend, this.currentEngine.device ?? null, this.currentEngine.format);
|
|
9300
9101
|
const defaults = buildDefaultStepTree(this.currentEngine.format, detectionModelId);
|
|
@@ -9302,10 +9103,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9302
9103
|
this.currentSteps = this.resolveStepModels(defaults);
|
|
9303
9104
|
return this.currentSteps;
|
|
9304
9105
|
}
|
|
9305
|
-
async getGlobalPipelineConfig() {
|
|
9306
|
-
if (!this.currentSteps) return null;
|
|
9307
|
-
return stepsToPipelineConfig(this.currentSteps, this.currentEngine);
|
|
9308
|
-
}
|
|
9309
9106
|
/**
|
|
9310
9107
|
* Task G5 (Gate B) — pre-init config-correctness gate. PURE COMPUTE
|
|
9311
9108
|
* against `this.currentEngine.format`: resolves `steps` the same way the
|
|
@@ -9349,7 +9146,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9349
9146
|
issues: [{
|
|
9350
9147
|
addonId: "*",
|
|
9351
9148
|
kind: "unknown-device",
|
|
9352
|
-
detail: errMsg
|
|
9149
|
+
detail: errMsg(err)
|
|
9353
9150
|
}],
|
|
9354
9151
|
substitutions: [],
|
|
9355
9152
|
format
|
|
@@ -9376,7 +9173,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9376
9173
|
format
|
|
9377
9174
|
};
|
|
9378
9175
|
} catch (err) {
|
|
9379
|
-
this.log.warn("validatePipeline failed — reporting a clean result", { meta: { error: errMsg
|
|
9176
|
+
this.log.warn("validatePipeline failed — reporting a clean result", { meta: { error: errMsg(err) } });
|
|
9380
9177
|
return {
|
|
9381
9178
|
ok: true,
|
|
9382
9179
|
issues: [],
|
|
@@ -9568,7 +9365,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9568
9365
|
durationMs
|
|
9569
9366
|
};
|
|
9570
9367
|
} catch (err) {
|
|
9571
|
-
const msg = errMsg
|
|
9368
|
+
const msg = errMsg(err);
|
|
9572
9369
|
this.log.error("Model download failed", { meta: {
|
|
9573
9370
|
error: msg,
|
|
9574
9371
|
modelId,
|
|
@@ -9888,7 +9685,9 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9888
9685
|
this.executor = executor;
|
|
9889
9686
|
const dispatchEngine = dispatchDeviceKey ? resolveDeviceEngine(dispatchDeviceKey) : runEngine;
|
|
9890
9687
|
const benchmark = isBenchmarkRun(input);
|
|
9891
|
-
const
|
|
9688
|
+
const placement = benchmarkPlacementOf(benchmark, deviceKeyOf(dispatchEngine));
|
|
9689
|
+
if (benchmark && placement === "live-pool") this.log.info("Benchmark on an exclusive device — served by the live pool", { meta: { deviceKey: deviceKeyOf(dispatchEngine) } });
|
|
9690
|
+
const dispatchFactory = placement === "benchmark-pool" ? await this.benchmarkPools.acquire(deviceKeyOf(dispatchEngine), dispatchEngine) : dispatchDeviceKey ? await this.resolveDeviceFactory(dispatchDeviceKey) : this.engineFactory;
|
|
9892
9691
|
const needed = enabledSteps.filter((s) => dispatchFactory.needsPoolUpdate(s));
|
|
9893
9692
|
let runSteps = benchmarkSteps;
|
|
9894
9693
|
const loadPolicy = dispatchLoadPolicyOf(input);
|
|
@@ -9926,24 +9725,24 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
9926
9725
|
...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
|
|
9927
9726
|
deviceKey: dispatchDeviceKeyLabel,
|
|
9928
9727
|
outcome: "step-dropped"
|
|
9929
|
-
}, dispatchDeviceKeyLabel, [model], model, "not-warm", errMsg
|
|
9728
|
+
}, dispatchDeviceKeyLabel, [model], model, "not-warm", errMsg(failure.error));
|
|
9930
9729
|
}
|
|
9931
9730
|
}
|
|
9932
|
-
const
|
|
9731
|
+
const treeRoot = resolveTreeRoot(tree.roots);
|
|
9933
9732
|
const rootDeviceKey = deviceKeyOf(dispatchEngine);
|
|
9934
|
-
const stampRoot = (r) =>
|
|
9733
|
+
const stampRoot = (r) => treeRoot === void 0 ? {
|
|
9935
9734
|
...r,
|
|
9936
9735
|
rootDeviceKey
|
|
9937
9736
|
} : {
|
|
9938
9737
|
...r,
|
|
9939
|
-
rootModelId,
|
|
9738
|
+
rootModelId: treeRoot.modelId,
|
|
9739
|
+
rootStepId: treeRoot.stepId,
|
|
9940
9740
|
rootDeviceKey
|
|
9941
9741
|
};
|
|
9942
9742
|
if (input.replay !== true) this.clusterModelSwitchLog.note(input.deviceId ?? 0, tree);
|
|
9943
9743
|
setupMs = performance.now() - wallT0 - decodeMs;
|
|
9944
9744
|
const effectiveDeviceId = input.deviceId ?? 0;
|
|
9945
|
-
const
|
|
9946
|
-
const effectiveTree = Object.keys(deviceOverrides).length > 0 ? applyDeviceOverridesToTree(tree, "object-detection", deviceOverrides) : tree;
|
|
9745
|
+
const effectiveTree = tree;
|
|
9947
9746
|
const nativeCropProvider = this.buildNativeCropProviderFromRef(input.nativeCropRef) ?? this.buildNativeFaceCropProvider(input.frameHandle);
|
|
9948
9747
|
let cropZoneBbox;
|
|
9949
9748
|
if (appliesCameraGates && effectiveDeviceId > 0 && effectiveTree.roots.some((r) => r.definition.extractMode === "crop-zone")) {
|
|
@@ -10339,7 +10138,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
10339
10138
|
...tags,
|
|
10340
10139
|
meta: {
|
|
10341
10140
|
deviceKey,
|
|
10342
|
-
error: errMsg
|
|
10141
|
+
error: errMsg(err)
|
|
10343
10142
|
}
|
|
10344
10143
|
});
|
|
10345
10144
|
});
|
|
@@ -10376,7 +10175,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
10376
10175
|
throw err;
|
|
10377
10176
|
}
|
|
10378
10177
|
const failed = failedModelOf(err) ?? models[0] ?? "";
|
|
10379
|
-
this.reportDispatchLoadLoss(context, deviceKey, models, failed, `failed:${flight.generation ?? "unknown"}`, errMsg
|
|
10178
|
+
this.reportDispatchLoadLoss(context, deviceKey, models, failed, `failed:${flight.generation ?? "unknown"}`, errMsg(err));
|
|
10380
10179
|
throw err;
|
|
10381
10180
|
}
|
|
10382
10181
|
}
|
|
@@ -10473,13 +10272,13 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
10473
10272
|
const poolModel = err instanceof StepVariantLoadError ? err.poolModel : null;
|
|
10474
10273
|
let generation = 0;
|
|
10475
10274
|
for (const model of failedModels) {
|
|
10476
|
-
const outcome = this.loadGovernor.recordFailure(pool, deviceKey, model, errMsg
|
|
10275
|
+
const outcome = this.loadGovernor.recordFailure(pool, deviceKey, model, errMsg(err), compileTimeout, Date.now(), poolModel, err instanceof StepVariantLoadError ? err.reason : null);
|
|
10477
10276
|
generation = outcome.generation;
|
|
10478
10277
|
if (outcome.refusedNow) this.log.error("model REFUSED on this device — its compile timed out repeatedly", { meta: {
|
|
10479
10278
|
deviceKey,
|
|
10480
10279
|
model,
|
|
10481
10280
|
compileTimeouts: outcome.compileTimeouts,
|
|
10482
|
-
error: errMsg
|
|
10281
|
+
error: errMsg(err),
|
|
10483
10282
|
device: "keeps serving every other model",
|
|
10484
10283
|
rearm: "pipelineExecutor.rearmInferenceDevice"
|
|
10485
10284
|
} });
|
|
@@ -10540,7 +10339,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
10540
10339
|
this.log.info("Model downloaded successfully", { meta: { modelId: entry.id } });
|
|
10541
10340
|
return;
|
|
10542
10341
|
} catch (err) {
|
|
10543
|
-
const msg = errMsg
|
|
10342
|
+
const msg = errMsg(err);
|
|
10544
10343
|
if (attempt < maxRetries) {
|
|
10545
10344
|
const delayMs = 2e3 * Math.pow(2, attempt - 1);
|
|
10546
10345
|
this.log.warn("Model download failed — retrying", { meta: {
|
|
@@ -10616,7 +10415,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
10616
10415
|
try {
|
|
10617
10416
|
return await this.runPipelineBatchImpl(input);
|
|
10618
10417
|
} catch (err) {
|
|
10619
|
-
const msg = errMsg
|
|
10418
|
+
const msg = errMsg(err);
|
|
10620
10419
|
const stack = err instanceof Error ? err.stack : void 0;
|
|
10621
10420
|
this.log.error("runPipelineBatch failed", { meta: {
|
|
10622
10421
|
phase: "batch",
|
|
@@ -10901,9 +10700,9 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
10901
10700
|
deviceKey: defaultDeviceKey,
|
|
10902
10701
|
backend: this.currentEngine.backend,
|
|
10903
10702
|
device: this.currentEngine.device ?? null,
|
|
10904
|
-
error: errMsg
|
|
10703
|
+
error: errMsg(err)
|
|
10905
10704
|
} });
|
|
10906
|
-
this.noteDeviceDeath(defaultDeviceKey, errMsg
|
|
10705
|
+
this.noteDeviceDeath(defaultDeviceKey, errMsg(err));
|
|
10907
10706
|
throw err;
|
|
10908
10707
|
}
|
|
10909
10708
|
this.engineFactory = factory;
|
|
@@ -11165,7 +10964,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
11165
10964
|
await factory.dispose().catch(() => void 0);
|
|
11166
10965
|
this.log.error("Benchmark pool failed to initialize", { meta: {
|
|
11167
10966
|
deviceKey,
|
|
11168
|
-
error: errMsg
|
|
10967
|
+
error: errMsg(err)
|
|
11169
10968
|
} });
|
|
11170
10969
|
throw err;
|
|
11171
10970
|
}
|
|
@@ -11212,7 +11011,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
11212
11011
|
error: err instanceof Error ? err.message : String(err)
|
|
11213
11012
|
} });
|
|
11214
11013
|
await factory.dispose().catch(() => void 0);
|
|
11215
|
-
this.noteDeviceDeath(deviceKey, errMsg
|
|
11014
|
+
this.noteDeviceDeath(deviceKey, errMsg(err));
|
|
11216
11015
|
throw err;
|
|
11217
11016
|
}
|
|
11218
11017
|
this.factoriesByDevice.set(deviceKey, factory);
|
|
@@ -11278,102 +11077,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
11278
11077
|
this.log.info("videoPipelineSteps updated", { meta: { addons: Object.keys(sanitized).length } });
|
|
11279
11078
|
return { success: true };
|
|
11280
11079
|
}
|
|
11281
|
-
/**
|
|
11282
|
-
* Clear THIS node's executor-side PER-DEVICE settings stores — the
|
|
11283
|
-
* per-camera step overrides the object-detection root reads via
|
|
11284
|
-
* `applyDeviceOverridesToTree`.
|
|
11285
|
-
*
|
|
11286
|
-
* Node-routed (the cap's default `nodeIdMode: 'routing'`): the generated
|
|
11287
|
-
* cap-router strips `nodeId` and dispatches to the target node, so this
|
|
11288
|
-
* method runs ON the node being cleared and takes no argument.
|
|
11289
|
-
*
|
|
11290
|
-
* This is the slimmed executor leg of the orchestrator's
|
|
11291
|
-
* `resetNodePipelineDefaults` flow. The legacy `resetToDefault` — which
|
|
11292
|
-
* also reset a persisted GLOBAL step-tree seed nothing in the live
|
|
11293
|
-
* per-camera path read — was removed together with that seed
|
|
11294
|
-
* (`getGlobalSteps` is pure now, so there is nothing node-global left to
|
|
11295
|
-
* reset here).
|
|
11296
|
-
*
|
|
11297
|
-
* Idempotent: clearing already-empty per-device stores is a no-op.
|
|
11298
|
-
*/
|
|
11299
|
-
async clearDeviceOverrides() {
|
|
11300
|
-
const clearedDevices = await this.clearAllDeviceOverrides();
|
|
11301
|
-
this.log.info("executor per-device overrides cleared", { meta: { clearedDevices } });
|
|
11302
|
-
return {
|
|
11303
|
-
success: true,
|
|
11304
|
-
clearedDevices
|
|
11305
|
-
};
|
|
11306
|
-
}
|
|
11307
|
-
/**
|
|
11308
|
-
* Auto tune (D745): list — or, unless `dryRun`, remove — the model-bound
|
|
11309
|
-
* thresholds of the per-camera detector store. See
|
|
11310
|
-
* `model-bound-device-overrides.ts`.
|
|
11311
|
-
*/
|
|
11312
|
-
async clearModelBoundDeviceOverrides(input) {
|
|
11313
|
-
const result = await clearModelBoundDeviceOverrides({
|
|
11314
|
-
listDeviceIds: async () => {
|
|
11315
|
-
const api = this.addonCtx?.api;
|
|
11316
|
-
if (!api) throw new Error("clearModelBoundDeviceOverrides: ctx.api unavailable");
|
|
11317
|
-
return (await api.deviceManager.listAll.query({ projection: "slim" })).map((d) => d.id);
|
|
11318
|
-
},
|
|
11319
|
-
readDeviceStore: (deviceId) => this.readDeviceStore(deviceId),
|
|
11320
|
-
clearDeviceStore: (deviceId) => this.clearDeviceStore(deviceId),
|
|
11321
|
-
writeDeviceStore: (deviceId, patch) => this.writeDeviceStore(deviceId, patch),
|
|
11322
|
-
invalidate: (deviceId) => this.deviceOverrides.invalidate(deviceId),
|
|
11323
|
-
boundKeys: collectModelBoundKeys(getStep("object-detection").getConfigSchema())
|
|
11324
|
-
}, input);
|
|
11325
|
-
if (!input.dryRun) for (const entry of result.entries) this.log.info("auto tune: per-camera detector thresholds cleared", {
|
|
11326
|
-
tags: { deviceId: entry.deviceId },
|
|
11327
|
-
meta: {
|
|
11328
|
-
deviceId: entry.deviceId,
|
|
11329
|
-
keys: entry.keys
|
|
11330
|
-
}
|
|
11331
|
-
});
|
|
11332
|
-
for (const r of result.refused) this.log.warn("auto tune: per-camera detector thresholds not cleared", {
|
|
11333
|
-
tags: { deviceId: r.deviceId },
|
|
11334
|
-
meta: {
|
|
11335
|
-
deviceId: r.deviceId,
|
|
11336
|
-
reason: r.reason,
|
|
11337
|
-
dryRun: input.dryRun
|
|
11338
|
-
}
|
|
11339
|
-
});
|
|
11340
|
-
return result;
|
|
11341
|
-
}
|
|
11342
|
-
/**
|
|
11343
|
-
* Clear the per-device pipeline-step overrides for every known device.
|
|
11344
|
-
* Returns the count of devices whose store was cleared. There is no
|
|
11345
|
-
* bulk-list primitive over the per-device store, so devices are
|
|
11346
|
-
* enumerated via the device-manager and cleared one by one
|
|
11347
|
-
* (`clearDeviceStore` is idempotent — a device with no overrides is a
|
|
11348
|
-
* no-op). Never throws: a device-manager outage degrades to "cleared
|
|
11349
|
-
* nothing" so the reset flow still completes.
|
|
11350
|
-
*/
|
|
11351
|
-
async clearAllDeviceOverrides() {
|
|
11352
|
-
const api = this.addonCtx?.api;
|
|
11353
|
-
if (!api) return 0;
|
|
11354
|
-
let devices = [];
|
|
11355
|
-
try {
|
|
11356
|
-
devices = await api.deviceManager.listAll.query({ projection: "slim" });
|
|
11357
|
-
} catch (err) {
|
|
11358
|
-
this.log.warn("clearDeviceOverrides: device enumeration failed — skipping per-device clear", { meta: { error: errMsg$1(err) } });
|
|
11359
|
-
return 0;
|
|
11360
|
-
}
|
|
11361
|
-
let cleared = 0;
|
|
11362
|
-
for (const device of devices) try {
|
|
11363
|
-
await this.clearDeviceStore(device.id);
|
|
11364
|
-
this.deviceOverrides.invalidate(device.id);
|
|
11365
|
-
cleared++;
|
|
11366
|
-
} catch (err) {
|
|
11367
|
-
this.log.warn("clearDeviceOverrides: failed to clear per-device overrides for device", {
|
|
11368
|
-
tags: { deviceId: device.id },
|
|
11369
|
-
meta: {
|
|
11370
|
-
deviceId: device.id,
|
|
11371
|
-
error: errMsg$1(err)
|
|
11372
|
-
}
|
|
11373
|
-
});
|
|
11374
|
-
}
|
|
11375
|
-
return cleared;
|
|
11376
|
-
}
|
|
11377
11080
|
async listLoadedEngines() {
|
|
11378
11081
|
const out = [];
|
|
11379
11082
|
if (this.engineFactory) {
|
|
@@ -11560,7 +11263,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
11560
11263
|
frame
|
|
11561
11264
|
};
|
|
11562
11265
|
} catch (err) {
|
|
11563
|
-
const msg = errMsg
|
|
11266
|
+
const msg = errMsg(err);
|
|
11564
11267
|
this.log.error("failed", { meta: {
|
|
11565
11268
|
phase: "audio-test",
|
|
11566
11269
|
error: msg
|
|
@@ -11620,7 +11323,6 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
|
|
|
11620
11323
|
defaultModelId: step.defaultModelId,
|
|
11621
11324
|
...step.defaultModelIdByFormat ? { defaultModelIdByFormat: { ...step.defaultModelIdByFormat } } : {},
|
|
11622
11325
|
...step.enabledByDefault !== void 0 ? { enabledByDefault: step.enabledByDefault } : {},
|
|
11623
|
-
...step.backfillIntoExistingOverrides !== void 0 ? { backfillIntoExistingOverrides: step.backfillIntoExistingOverrides } : {},
|
|
11624
11326
|
defaultConfidence: step.defaultConfidence,
|
|
11625
11327
|
...step.group ? { group: step.group } : {},
|
|
11626
11328
|
...configSchemaWithRoots.length > 0 ? { configSchema: configSchemaWithRoots } : {}
|
|
@@ -11668,7 +11370,7 @@ function resolveChildSlots(slot) {
|
|
|
11668
11370
|
}
|
|
11669
11371
|
/**
|
|
11670
11372
|
* V2 default: the node-default step tree (never persisted — see
|
|
11671
|
-
* `
|
|
11373
|
+
* `nodeDefaultSteps`). The core detection + recognition steps are enabled; every
|
|
11672
11374
|
* optional step is present with its catalog `enabledByDefault` (the animal and
|
|
11673
11375
|
* vehicle classifiers on — their answer comes from the root model when it
|
|
11674
11376
|
* declares them, D736 — the bird classifier and segmentation off).
|
|
@@ -11710,27 +11412,6 @@ function buildDefaultStepTree(format, objectDetectionModelId) {
|
|
|
11710
11412
|
if (audioStep) steps.push(audioStep);
|
|
11711
11413
|
return steps;
|
|
11712
11414
|
}
|
|
11713
|
-
function stepsToPipelineConfig(steps, engine) {
|
|
11714
|
-
const toNode = (step) => ({
|
|
11715
|
-
step: step.addonId,
|
|
11716
|
-
addon: step.addonId,
|
|
11717
|
-
configOverride: {
|
|
11718
|
-
modelId: step.modelId,
|
|
11719
|
-
...step.settings
|
|
11720
|
-
},
|
|
11721
|
-
children: step.children.map(toNode)
|
|
11722
|
-
});
|
|
11723
|
-
const videoSteps = steps.filter((s) => s.slot !== "audio-classifier");
|
|
11724
|
-
const audioStep = steps.find((s) => s.slot === "audio-classifier" && s.enabled);
|
|
11725
|
-
return {
|
|
11726
|
-
engine,
|
|
11727
|
-
video: videoSteps.map(toNode),
|
|
11728
|
-
...audioStep ? {
|
|
11729
|
-
audio: toNode(audioStep),
|
|
11730
|
-
audioEngine: engine
|
|
11731
|
-
} : {}
|
|
11732
|
-
};
|
|
11733
|
-
}
|
|
11734
11415
|
/** Flatten a step tree into a flat list (DFS) — delegates to shared utility. */
|
|
11735
11416
|
function flattenSteps(steps) {
|
|
11736
11417
|
return flattenEnabledVideoSteps(steps);
|
|
@@ -11791,22 +11472,6 @@ function availableFormatsForStep(addonId) {
|
|
|
11791
11472
|
return [];
|
|
11792
11473
|
}
|
|
11793
11474
|
}
|
|
11794
|
-
/**
|
|
11795
|
-
* Return a shallow-cloned executable tree with `rootStepId`'s `settings`
|
|
11796
|
-
* merged with `overrides` (per-device values win). Non-matching root steps
|
|
11797
|
-
* pass through unchanged. Used by `runFrame` to apply per-device detection
|
|
11798
|
-
* settings without rebuilding the tree per frame. A model-bound value (D738)
|
|
11799
|
-
* applies only while the model it was made for is the one the root RUNS.
|
|
11800
|
-
*/
|
|
11801
|
-
function applyDeviceOverridesToTree(tree, rootStepId, overrides) {
|
|
11802
|
-
return { roots: tree.roots.map((root) => root.stepId === rootStepId ? {
|
|
11803
|
-
...root,
|
|
11804
|
-
settings: {
|
|
11805
|
-
...root.settings,
|
|
11806
|
-
...resolveOperatorSettingsForModel(rootStepId, overrides, root.modelId)
|
|
11807
|
-
}
|
|
11808
|
-
} : root) };
|
|
11809
|
-
}
|
|
11810
11475
|
//#endregion
|
|
11811
11476
|
//#region src/detection-pipeline/python-readiness.ts
|
|
11812
11477
|
/**
|
|
@@ -11921,20 +11586,6 @@ function isProfileSliderKey(key) {
|
|
|
11921
11586
|
}
|
|
11922
11587
|
var DetectionPipelineAddon = class extends BaseAddon {
|
|
11923
11588
|
provider = null;
|
|
11924
|
-
/**
|
|
11925
|
-
* An operator's own write drops the mirror the frame path reads.
|
|
11926
|
-
*
|
|
11927
|
-
* This override is the half of `device-override-mirror.ts` that keeps it from
|
|
11928
|
-
* being the second authority D224 forbids: `BaseAddon.updateDeviceSettings`
|
|
11929
|
-
* writes THIS addon's `<addonId>:addon-devices` row, so the write and the
|
|
11930
|
-
* mirror are in one process and the write invalidates. Without it the
|
|
11931
|
-
* operator's own change would be the one read the mirror got wrong, which is
|
|
11932
|
-
* the exact failure D224 records.
|
|
11933
|
-
*/
|
|
11934
|
-
async updateDeviceSettings(deviceId, patch) {
|
|
11935
|
-
await super.updateDeviceSettings(deviceId, patch);
|
|
11936
|
-
this.provider?.deviceOverrides.invalidate(deviceId);
|
|
11937
|
-
}
|
|
11938
11589
|
/** Last non-null probed hardware PER NODE — reused when the probe transiently
|
|
11939
11590
|
* returns null so offered backends / device lists don't collapse. Keyed by
|
|
11940
11591
|
* node because the hub addon probes other nodes when serving their config.
|