@camstack/addon-pipeline 1.1.66 → 1.1.68

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.
Files changed (32) hide show
  1. package/dist/audio-analyzer/index.js +1 -1
  2. package/dist/audio-analyzer/index.mjs +1 -1
  3. package/dist/detection-pipeline/index.js +52 -13
  4. package/dist/detection-pipeline/index.mjs +52 -13
  5. package/dist/{dist-D5o9fGxq.js → dist-BxxVKcnw.js} +43 -5
  6. package/dist/{dist-BpWot5-w.mjs → dist-DkGHtAaK.mjs} +43 -5
  7. package/dist/motion-wasm/index.js +1 -1
  8. package/dist/motion-wasm/index.mjs +1 -1
  9. package/dist/pipeline-runner/index.js +2 -2
  10. package/dist/pipeline-runner/index.mjs +2 -2
  11. package/dist/recorder/index.js +1 -1
  12. package/dist/recorder/index.mjs +1 -1
  13. package/dist/session-decode/decode-worker-child.js +176 -11
  14. package/dist/session-decode/decode-worker-child.mjs +176 -11
  15. package/dist/{step-definitions-81eYyJbW.js → step-definitions-CAs0RD2N.js} +1 -1
  16. package/dist/{step-definitions-D6R9X0V7.mjs → step-definitions-Delhq28w.mjs} +1 -1
  17. package/dist/stream-broker/_stub.js +1 -1
  18. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CIIIVPzB.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BUXIIogo.mjs} +1 -1
  19. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CPbLcza9.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D68Lj69v.mjs} +1 -1
  20. package/dist/stream-broker/{hostInit-CeBNudbY.mjs → hostInit-D7_95hNV.mjs} +1 -1
  21. package/dist/stream-broker/index.js +1 -1
  22. package/dist/stream-broker/index.mjs +1 -1
  23. package/dist/stream-broker/remoteEntry.js +1 -1
  24. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-CbBbcdZb.js → MaskShapeCanvas-DI4BY7W2-CRvzj7Of.js} +1 -1
  25. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-aA6zvms_.js → MotionZonesSettings-NcxxQN8r-CBgvPUB-.js} +1 -1
  26. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-CcGB7iAE.js → PrivacyMaskSettings-APgPLF7p-DH07fe1k.js} +1 -1
  27. package/embed-dist/assets/{index-BRG_Fqb5.js → index-BkoPcGtQ.js} +13 -13
  28. package/embed-dist/index.html +1 -1
  29. package/package.json +1 -1
  30. package/python/inference_pool.py +362 -45
  31. package/python/test_inference_pool_ov_ppp.py +117 -0
  32. package/python/test_inference_pool_preprocess.py +93 -1
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-D6vf50IK.js");
6
- const require_dist = require("../dist-D5o9fGxq.js");
6
+ const require_dist = require("../dist-BxxVKcnw.js");
7
7
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
8
8
  const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-Dv-oFwjN.js");
9
9
  let node_fs = require("node:fs");
@@ -1,5 +1,5 @@
1
1
  import { t as __require } from "../chunk-BdkLduGY.mjs";
2
- import { B as errMsg, K as hydrateSchema, T as mapAudioLabelToMacro, V as BaseAddon, _ as audioAnalyzerCapability, g as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, u as HF_BASE_URL } from "../dist-BpWot5-w.mjs";
2
+ import { B as errMsg, K as hydrateSchema, T as mapAudioLabelToMacro, V as BaseAddon, _ as audioAnalyzerCapability, g as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, u as HF_BASE_URL } from "../dist-DkGHtAaK.mjs";
3
3
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
4
4
  import { i as downloadFile } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
5
5
  import * as fs from "node:fs";
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-D6vf50IK.js");
6
- const require_dist = require("../dist-D5o9fGxq.js");
7
- const require_step_definitions = require("../step-definitions-81eYyJbW.js");
6
+ const require_dist = require("../dist-BxxVKcnw.js");
7
+ const require_step_definitions = require("../step-definitions-CAs0RD2N.js");
8
8
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
9
9
  const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-Dv-oFwjN.js");
10
10
  let node_child_process = require("node:child_process");
@@ -426,6 +426,15 @@ var RAW_FMT_CODE = {
426
426
  bgr: 1,
427
427
  gray: 2
428
428
  };
429
+ /**
430
+ * Per-inference-request reply timeout (ms). Turns a wedged request (worker
431
+ * alive but no reply) into a rejection so every caller settles — runtime frame
432
+ * dispatch drops the frame; the benchmark full-tree run rejects the wedged
433
+ * child (its enclosing try/catch keeps the root detections) instead of hanging
434
+ * the UI on "loading" forever. Generous so legitimate slow inference (cold JIT,
435
+ * large frame) never trips; override via env for constrained hardware.
436
+ */
437
+ var POOL_INFER_TIMEOUT_MS = Math.max(1e3, Number(process.env["CAMSTACK_POOL_INFER_TIMEOUT_MS"]) || 6e4);
429
438
  var PoolHandle = class {
430
439
  pool;
431
440
  modelIndex;
@@ -608,15 +617,16 @@ var PoolWorker = class {
608
617
  rawHeader[9] = fmtCode;
609
618
  return this.dispatchMulti(MSG_INFER_RAW, rawHeader.length + raw.length, [rawHeader, raw]);
610
619
  }
611
- async inferBatch(modelByte, items) {
620
+ async inferBatch(modelByte, items, frameId = 0) {
612
621
  this.ensureReady();
613
622
  if (items.length === 0) return [];
614
- const headerSize = 2 + items.length * 13;
623
+ const headerSize = 6 + items.length * 13;
615
624
  const totalRawSize = items.reduce((sum, it) => sum + it.raw.length, 0);
616
625
  const payload = Buffer.allocUnsafe(headerSize + totalRawSize);
617
626
  payload[0] = modelByte;
618
627
  payload[1] = items.length;
619
- let offset = 2;
628
+ payload.writeUInt32LE(frameId >>> 0, 2);
629
+ let offset = 6;
620
630
  for (const item of items) {
621
631
  payload.writeUInt32LE(item.width, offset);
622
632
  payload.writeUInt32LE(item.height, offset + 4);
@@ -665,24 +675,48 @@ var PoolWorker = class {
665
675
  dispatch(msgType, payload) {
666
676
  const reqId = this.allocRequestId();
667
677
  return new Promise((resolve, reject) => {
678
+ const timer = this.armRequestTimeout(reqId, reject);
668
679
  this.pending.set(reqId, {
669
680
  resolve,
670
- reject
681
+ reject,
682
+ timer
671
683
  });
672
684
  try {
673
685
  this.writeFrame(reqId, msgType, payload);
674
686
  } catch (err) {
687
+ clearTimeout(timer);
675
688
  this.pending.delete(reqId);
676
689
  reject(err instanceof Error ? err : new Error(String(err)));
677
690
  }
678
691
  });
679
692
  }
693
+ /**
694
+ * Arm a watchdog that rejects a still-pending inference request after
695
+ * `POOL_INFER_TIMEOUT_MS`. `unref` so it never keeps the event loop alive.
696
+ * The normal response + `rejectAll` paths clear it via `PendingRequest.timer`.
697
+ */
698
+ armRequestTimeout(reqId, reject) {
699
+ const timer = setTimeout(() => {
700
+ if (this.pending.delete(reqId)) {
701
+ this.log.error("inference request timed out", { meta: {
702
+ worker: this.opts.workerLabel,
703
+ reqId,
704
+ timeoutMs: POOL_INFER_TIMEOUT_MS
705
+ } });
706
+ reject(/* @__PURE__ */ new Error(`PoolWorker[${this.opts.workerLabel}]: inference request ${reqId} timed out after ${POOL_INFER_TIMEOUT_MS}ms (worker alive, no reply)`));
707
+ }
708
+ }, POOL_INFER_TIMEOUT_MS);
709
+ timer.unref?.();
710
+ return timer;
711
+ }
680
712
  dispatchMulti(msgType, payloadLen, parts) {
681
713
  const reqId = this.allocRequestId();
682
714
  return new Promise((resolve, reject) => {
715
+ const timer = this.armRequestTimeout(reqId, reject);
683
716
  this.pending.set(reqId, {
684
717
  resolve,
685
- reject
718
+ reject,
719
+ timer
686
720
  });
687
721
  try {
688
722
  if (!this.process?.stdin) throw new Error("PoolWorker: not initialized");
@@ -693,6 +727,7 @@ var PoolWorker = class {
693
727
  this.process.stdin.write(prefix);
694
728
  for (const part of parts) this.process.stdin.write(part);
695
729
  } catch (err) {
730
+ clearTimeout(timer);
696
731
  this.pending.delete(reqId);
697
732
  reject(err instanceof Error ? err : new Error(String(err)));
698
733
  }
@@ -736,6 +771,7 @@ var PoolWorker = class {
736
771
  continue;
737
772
  }
738
773
  this.pending.delete(reqId);
774
+ if (entry.timer) clearTimeout(entry.timer);
739
775
  try {
740
776
  const parsed = JSON.parse(jsonBytes.toString("utf8"));
741
777
  entry.resolve(parsed);
@@ -747,7 +783,10 @@ var PoolWorker = class {
747
783
  rejectAll(err) {
748
784
  const entries = [...this.pending.values()];
749
785
  this.pending.clear();
750
- for (const entry of entries) entry.reject(err);
786
+ for (const entry of entries) {
787
+ if (entry.timer) clearTimeout(entry.timer);
788
+ entry.reject(err);
789
+ }
751
790
  }
752
791
  };
753
792
  var SharedInferencePool = class {
@@ -827,9 +866,9 @@ var SharedInferencePool = class {
827
866
  const w = this.pickWorker();
828
867
  return this.trackDroppedResponse(await w.inferRaw(this.encodeModelByte(modelIndex), raw, width, height, format), modelIndex);
829
868
  }
830
- async inferBatch(modelIndex, items) {
869
+ async inferBatch(modelIndex, items, frameId = 0) {
831
870
  if (items.length > 255) throw new Error(`SharedInferencePool.inferBatch: max 255 items per call, got ${items.length}`);
832
- return this.pickWorker().inferBatch(this.encodeModelByte(modelIndex), items);
871
+ return this.pickWorker().inferBatch(this.encodeModelByte(modelIndex), items, frameId);
833
872
  }
834
873
  async inferCached(modelIndex, frameId) {
835
874
  const w = this.pickWorker();
@@ -1387,11 +1426,11 @@ var EngineFactory = class {
1387
1426
  * Used by `runPipelineBatch` for fair batched benchmarking — N frames
1388
1427
  * in one IPC round-trip, amortising the per-call envelope overhead.
1389
1428
  */
1390
- async batchInferRaw(stepId, items, modelId) {
1429
+ async batchInferRaw(stepId, items, modelId, frameId = 0) {
1391
1430
  if (!this.poolManager) throw new Error("EngineFactory.batchInferRaw: pool not initialized");
1392
1431
  const idx = this.poolManager.getPoolIndex(stepId, modelId);
1393
1432
  if (idx === null) throw new Error(`EngineFactory.batchInferRaw: step "${stepId}"${modelId ? ` (model "${modelId}")` : ""} is not loaded`);
1394
- return this.poolManager.getPool().inferBatch(idx, items);
1433
+ return this.poolManager.getPool().inferBatch(idx, items, frameId);
1395
1434
  }
1396
1435
  async cacheFrameInPool(raw, width, height, format) {
1397
1436
  if (!this.poolManager) throw new Error("cacheFrameInPool: pool not available");
@@ -5573,7 +5612,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5573
5612
  totalRawBytes: items.reduce((s, it) => s + it.raw.length, 0)
5574
5613
  } });
5575
5614
  const start = performance.now();
5576
- const rawResults = await factory.batchInferRaw(rootStep.addonId, items, rootStep.modelId);
5615
+ const rawResults = await factory.batchInferRaw(rootStep.addonId, items, rootStep.modelId, input.frameId ?? 0);
5577
5616
  const totalMs = performance.now() - start;
5578
5617
  this.log.info("runPipelineBatch fast path returned", { meta: {
5579
5618
  phase: "batch",
@@ -1,6 +1,6 @@
1
1
  import { t as __require } from "../chunk-BdkLduGY.mjs";
2
- import { $ as sleep, A as pipelineExecutorCapability, B as errMsg, C as evaluateZoneRules, F as runtimeDevices$1, G as createEvent, K as hydrateSchema, R as supportedRuntimes$1, S as detectionPipelineCapability, V as BaseAddon, X as parseJsonUnknown, b as defaultDeviceFor$1, dt as EventCategory, k as nodePin, lt as string, m as YAMNET_TO_MACRO, st as object, t as APPLE_SA_TO_MACRO, tt as array, ut as union } from "../dist-BpWot5-w.mjs";
3
- import { a as getStepDefinition, i as getStep, n as ALL_STEPS, o as resolveModelForFormat, r as getDefaultModelForFormat, t as ALL_PIPELINE_STEPS } from "../step-definitions-D6R9X0V7.mjs";
2
+ import { $ as sleep, A as pipelineExecutorCapability, B as errMsg, C as evaluateZoneRules, F as runtimeDevices$1, G as createEvent, K as hydrateSchema, R as supportedRuntimes$1, S as detectionPipelineCapability, V as BaseAddon, X as parseJsonUnknown, b as defaultDeviceFor$1, dt as EventCategory, k as nodePin, lt as string, m as YAMNET_TO_MACRO, st as object, t as APPLE_SA_TO_MACRO, tt as array, ut as union } from "../dist-DkGHtAaK.mjs";
3
+ import { a as getStepDefinition, i as getStep, n as ALL_STEPS, o as resolveModelForFormat, r as getDefaultModelForFormat, t as ALL_PIPELINE_STEPS } from "../step-definitions-Delhq28w.mjs";
4
4
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
5
5
  import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
6
6
  import { spawn } from "node:child_process";
@@ -418,6 +418,15 @@ var RAW_FMT_CODE = {
418
418
  bgr: 1,
419
419
  gray: 2
420
420
  };
421
+ /**
422
+ * Per-inference-request reply timeout (ms). Turns a wedged request (worker
423
+ * alive but no reply) into a rejection so every caller settles — runtime frame
424
+ * dispatch drops the frame; the benchmark full-tree run rejects the wedged
425
+ * child (its enclosing try/catch keeps the root detections) instead of hanging
426
+ * the UI on "loading" forever. Generous so legitimate slow inference (cold JIT,
427
+ * large frame) never trips; override via env for constrained hardware.
428
+ */
429
+ var POOL_INFER_TIMEOUT_MS = Math.max(1e3, Number(process.env["CAMSTACK_POOL_INFER_TIMEOUT_MS"]) || 6e4);
421
430
  var PoolHandle = class {
422
431
  pool;
423
432
  modelIndex;
@@ -600,15 +609,16 @@ var PoolWorker = class {
600
609
  rawHeader[9] = fmtCode;
601
610
  return this.dispatchMulti(MSG_INFER_RAW, rawHeader.length + raw.length, [rawHeader, raw]);
602
611
  }
603
- async inferBatch(modelByte, items) {
612
+ async inferBatch(modelByte, items, frameId = 0) {
604
613
  this.ensureReady();
605
614
  if (items.length === 0) return [];
606
- const headerSize = 2 + items.length * 13;
615
+ const headerSize = 6 + items.length * 13;
607
616
  const totalRawSize = items.reduce((sum, it) => sum + it.raw.length, 0);
608
617
  const payload = Buffer.allocUnsafe(headerSize + totalRawSize);
609
618
  payload[0] = modelByte;
610
619
  payload[1] = items.length;
611
- let offset = 2;
620
+ payload.writeUInt32LE(frameId >>> 0, 2);
621
+ let offset = 6;
612
622
  for (const item of items) {
613
623
  payload.writeUInt32LE(item.width, offset);
614
624
  payload.writeUInt32LE(item.height, offset + 4);
@@ -657,24 +667,48 @@ var PoolWorker = class {
657
667
  dispatch(msgType, payload) {
658
668
  const reqId = this.allocRequestId();
659
669
  return new Promise((resolve, reject) => {
670
+ const timer = this.armRequestTimeout(reqId, reject);
660
671
  this.pending.set(reqId, {
661
672
  resolve,
662
- reject
673
+ reject,
674
+ timer
663
675
  });
664
676
  try {
665
677
  this.writeFrame(reqId, msgType, payload);
666
678
  } catch (err) {
679
+ clearTimeout(timer);
667
680
  this.pending.delete(reqId);
668
681
  reject(err instanceof Error ? err : new Error(String(err)));
669
682
  }
670
683
  });
671
684
  }
685
+ /**
686
+ * Arm a watchdog that rejects a still-pending inference request after
687
+ * `POOL_INFER_TIMEOUT_MS`. `unref` so it never keeps the event loop alive.
688
+ * The normal response + `rejectAll` paths clear it via `PendingRequest.timer`.
689
+ */
690
+ armRequestTimeout(reqId, reject) {
691
+ const timer = setTimeout(() => {
692
+ if (this.pending.delete(reqId)) {
693
+ this.log.error("inference request timed out", { meta: {
694
+ worker: this.opts.workerLabel,
695
+ reqId,
696
+ timeoutMs: POOL_INFER_TIMEOUT_MS
697
+ } });
698
+ reject(/* @__PURE__ */ new Error(`PoolWorker[${this.opts.workerLabel}]: inference request ${reqId} timed out after ${POOL_INFER_TIMEOUT_MS}ms (worker alive, no reply)`));
699
+ }
700
+ }, POOL_INFER_TIMEOUT_MS);
701
+ timer.unref?.();
702
+ return timer;
703
+ }
672
704
  dispatchMulti(msgType, payloadLen, parts) {
673
705
  const reqId = this.allocRequestId();
674
706
  return new Promise((resolve, reject) => {
707
+ const timer = this.armRequestTimeout(reqId, reject);
675
708
  this.pending.set(reqId, {
676
709
  resolve,
677
- reject
710
+ reject,
711
+ timer
678
712
  });
679
713
  try {
680
714
  if (!this.process?.stdin) throw new Error("PoolWorker: not initialized");
@@ -685,6 +719,7 @@ var PoolWorker = class {
685
719
  this.process.stdin.write(prefix);
686
720
  for (const part of parts) this.process.stdin.write(part);
687
721
  } catch (err) {
722
+ clearTimeout(timer);
688
723
  this.pending.delete(reqId);
689
724
  reject(err instanceof Error ? err : new Error(String(err)));
690
725
  }
@@ -728,6 +763,7 @@ var PoolWorker = class {
728
763
  continue;
729
764
  }
730
765
  this.pending.delete(reqId);
766
+ if (entry.timer) clearTimeout(entry.timer);
731
767
  try {
732
768
  const parsed = JSON.parse(jsonBytes.toString("utf8"));
733
769
  entry.resolve(parsed);
@@ -739,7 +775,10 @@ var PoolWorker = class {
739
775
  rejectAll(err) {
740
776
  const entries = [...this.pending.values()];
741
777
  this.pending.clear();
742
- for (const entry of entries) entry.reject(err);
778
+ for (const entry of entries) {
779
+ if (entry.timer) clearTimeout(entry.timer);
780
+ entry.reject(err);
781
+ }
743
782
  }
744
783
  };
745
784
  var SharedInferencePool = class {
@@ -819,9 +858,9 @@ var SharedInferencePool = class {
819
858
  const w = this.pickWorker();
820
859
  return this.trackDroppedResponse(await w.inferRaw(this.encodeModelByte(modelIndex), raw, width, height, format), modelIndex);
821
860
  }
822
- async inferBatch(modelIndex, items) {
861
+ async inferBatch(modelIndex, items, frameId = 0) {
823
862
  if (items.length > 255) throw new Error(`SharedInferencePool.inferBatch: max 255 items per call, got ${items.length}`);
824
- return this.pickWorker().inferBatch(this.encodeModelByte(modelIndex), items);
863
+ return this.pickWorker().inferBatch(this.encodeModelByte(modelIndex), items, frameId);
825
864
  }
826
865
  async inferCached(modelIndex, frameId) {
827
866
  const w = this.pickWorker();
@@ -1379,11 +1418,11 @@ var EngineFactory = class {
1379
1418
  * Used by `runPipelineBatch` for fair batched benchmarking — N frames
1380
1419
  * in one IPC round-trip, amortising the per-call envelope overhead.
1381
1420
  */
1382
- async batchInferRaw(stepId, items, modelId) {
1421
+ async batchInferRaw(stepId, items, modelId, frameId = 0) {
1383
1422
  if (!this.poolManager) throw new Error("EngineFactory.batchInferRaw: pool not initialized");
1384
1423
  const idx = this.poolManager.getPoolIndex(stepId, modelId);
1385
1424
  if (idx === null) throw new Error(`EngineFactory.batchInferRaw: step "${stepId}"${modelId ? ` (model "${modelId}")` : ""} is not loaded`);
1386
- return this.poolManager.getPool().inferBatch(idx, items);
1425
+ return this.poolManager.getPool().inferBatch(idx, items, frameId);
1387
1426
  }
1388
1427
  async cacheFrameInPool(raw, width, height, format) {
1389
1428
  if (!this.poolManager) throw new Error("cacheFrameInPool: pool not available");
@@ -5565,7 +5604,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5565
5604
  totalRawBytes: items.reduce((s, it) => s + it.raw.length, 0)
5566
5605
  } });
5567
5606
  const start = performance.now();
5568
- const rawResults = await factory.batchInferRaw(rootStep.addonId, items, rootStep.modelId);
5607
+ const rawResults = await factory.batchInferRaw(rootStep.addonId, items, rootStep.modelId, input.frameId ?? 0);
5569
5608
  const totalMs = performance.now() - start;
5570
5609
  this.log.info("runPipelineBatch fast path returned", { meta: {
5571
5610
  phase: "batch",
@@ -12092,7 +12092,14 @@ var pipelineExecutorCapability = {
12092
12092
  * (inputClasses ≠ null) are skipped and served per-track via
12093
12093
  * pipelineRunner.runDetailSubtree (two-plane design).
12094
12094
  */
12095
- plane: _enum(["full", "frame"]).optional()
12095
+ plane: _enum(["full", "frame"]).optional(),
12096
+ /**
12097
+ * Inference-device selector (Phase 2 multi-device). Format
12098
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12099
+ * Omitted ⇒ the runner's default device (current single-engine
12100
+ * behaviour). Selects WHICH device pool of the node runs the call.
12101
+ */
12102
+ deviceKey: string().optional()
12096
12103
  }), PipelineRunResultBridge, { kind: "mutation" }),
12097
12104
  /**
12098
12105
  * Batched run — N raw frames packed into one cap call. The provider
@@ -12110,7 +12117,20 @@ var pipelineExecutorCapability = {
12110
12117
  steps: array(PipelineStepInputSchema).min(1),
12111
12118
  frames: array(FrameInputSchema).min(1).max(255),
12112
12119
  deviceId: number().optional(),
12113
- sessionId: string().optional()
12120
+ sessionId: string().optional(),
12121
+ /**
12122
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12123
+ * the batch to the Python pool's bench preprocess cache
12124
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12125
+ * preprocessed ONCE and every later inference is a pure-inference cache
12126
+ * hit — the sustained-throughput run measures inference, not
12127
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12128
+ * full preprocess every call, correct). Fresh per sustained run;
12129
+ * released via `uncacheFrame`.
12130
+ */
12131
+ frameId: number().int().nonnegative().optional(),
12132
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12133
+ deviceKey: string().optional()
12114
12134
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }),
12115
12135
  /**
12116
12136
  * Cache a raw frame inside the Python inference pool's memory.
@@ -12527,7 +12547,14 @@ var RunnerCameraConfigSchema = object({
12527
12547
  * camera's detect node differs from its source-owner (P2d, gated by the
12528
12548
  * `remoteSourcingNodes` rollout setting).
12529
12549
  */
12530
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12550
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12551
+ /**
12552
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12553
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12554
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12555
+ * this only selects WHICH device pool of that node runs the session.
12556
+ */
12557
+ deviceKey: string().optional()
12531
12558
  });
12532
12559
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
12533
12560
  /**
@@ -21013,17 +21040,28 @@ var PlatformScoreSchema = object({
21013
21040
  format: _enum([
21014
21041
  "onnx",
21015
21042
  "coreml",
21016
- "openvino"
21043
+ "openvino",
21044
+ "tflite"
21017
21045
  ]),
21018
21046
  score: number(),
21019
21047
  reason: string(),
21020
21048
  available: boolean()
21021
21049
  });
21050
+ var InferenceDeviceDescriptorSchema = object({
21051
+ key: string(),
21052
+ backend: string(),
21053
+ device: string(),
21054
+ format: ModelFormatSchema,
21055
+ runtime: literal("python"),
21056
+ score: number(),
21057
+ available: boolean()
21058
+ });
21022
21059
  var PlatformCapabilitiesSchema = object({
21023
21060
  hardware: HardwareInfoSchema,
21024
21061
  scores: array(PlatformScoreSchema).readonly(),
21025
21062
  bestScore: PlatformScoreSchema,
21026
- pythonPath: string().nullable()
21063
+ pythonPath: string().nullable(),
21064
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
21027
21065
  });
21028
21066
  var ModelRequirementSchema = object({
21029
21067
  modelId: string(),
@@ -12092,7 +12092,14 @@ var pipelineExecutorCapability = {
12092
12092
  * (inputClasses ≠ null) are skipped and served per-track via
12093
12093
  * pipelineRunner.runDetailSubtree (two-plane design).
12094
12094
  */
12095
- plane: _enum(["full", "frame"]).optional()
12095
+ plane: _enum(["full", "frame"]).optional(),
12096
+ /**
12097
+ * Inference-device selector (Phase 2 multi-device). Format
12098
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12099
+ * Omitted ⇒ the runner's default device (current single-engine
12100
+ * behaviour). Selects WHICH device pool of the node runs the call.
12101
+ */
12102
+ deviceKey: string().optional()
12096
12103
  }), PipelineRunResultBridge, { kind: "mutation" }),
12097
12104
  /**
12098
12105
  * Batched run — N raw frames packed into one cap call. The provider
@@ -12110,7 +12117,20 @@ var pipelineExecutorCapability = {
12110
12117
  steps: array(PipelineStepInputSchema).min(1),
12111
12118
  frames: array(FrameInputSchema).min(1).max(255),
12112
12119
  deviceId: number().optional(),
12113
- sessionId: string().optional()
12120
+ sessionId: string().optional(),
12121
+ /**
12122
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12123
+ * the batch to the Python pool's bench preprocess cache
12124
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12125
+ * preprocessed ONCE and every later inference is a pure-inference cache
12126
+ * hit — the sustained-throughput run measures inference, not
12127
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12128
+ * full preprocess every call, correct). Fresh per sustained run;
12129
+ * released via `uncacheFrame`.
12130
+ */
12131
+ frameId: number().int().nonnegative().optional(),
12132
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12133
+ deviceKey: string().optional()
12114
12134
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }),
12115
12135
  /**
12116
12136
  * Cache a raw frame inside the Python inference pool's memory.
@@ -12527,7 +12547,14 @@ var RunnerCameraConfigSchema = object({
12527
12547
  * camera's detect node differs from its source-owner (P2d, gated by the
12528
12548
  * `remoteSourcingNodes` rollout setting).
12529
12549
  */
12530
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12550
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12551
+ /**
12552
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12553
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12554
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12555
+ * this only selects WHICH device pool of that node runs the session.
12556
+ */
12557
+ deviceKey: string().optional()
12531
12558
  });
12532
12559
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
12533
12560
  /**
@@ -21013,17 +21040,28 @@ var PlatformScoreSchema = object({
21013
21040
  format: _enum([
21014
21041
  "onnx",
21015
21042
  "coreml",
21016
- "openvino"
21043
+ "openvino",
21044
+ "tflite"
21017
21045
  ]),
21018
21046
  score: number(),
21019
21047
  reason: string(),
21020
21048
  available: boolean()
21021
21049
  });
21050
+ var InferenceDeviceDescriptorSchema = object({
21051
+ key: string(),
21052
+ backend: string(),
21053
+ device: string(),
21054
+ format: ModelFormatSchema,
21055
+ runtime: literal("python"),
21056
+ score: number(),
21057
+ available: boolean()
21058
+ });
21022
21059
  var PlatformCapabilitiesSchema = object({
21023
21060
  hardware: HardwareInfoSchema,
21024
21061
  scores: array(PlatformScoreSchema).readonly(),
21025
21062
  bestScore: PlatformScoreSchema,
21026
- pythonPath: string().nullable()
21063
+ pythonPath: string().nullable(),
21064
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
21027
21065
  });
21028
21066
  var ModelRequirementSchema = object({
21029
21067
  modelId: string(),
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-D5o9fGxq.js");
5
+ const require_dist = require("../dist-BxxVKcnw.js");
6
6
  let node_fs = require("node:fs");
7
7
  let node_path = require("node:path");
8
8
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -1,4 +1,4 @@
1
- import { C as evaluateZoneRules, K as hydrateSchema, O as motionDetectionCapability, V as BaseAddon, W as DeviceType } from "../dist-BpWot5-w.mjs";
1
+ import { C as evaluateZoneRules, K as hydrateSchema, O as motionDetectionCapability, V as BaseAddon, W as DeviceType } from "../dist-DkGHtAaK.mjs";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-D6vf50IK.js");
6
- const require_dist = require("../dist-D5o9fGxq.js");
6
+ const require_dist = require("../dist-BxxVKcnw.js");
7
7
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
8
8
  const require_sheet_geometry = require("../sheet-geometry-BR-ip0CP.js");
9
9
  const require_worker_protocol = require("../worker-protocol-PP4jKHHJ.js");
10
- const require_step_definitions = require("../step-definitions-81eYyJbW.js");
10
+ const require_step_definitions = require("../step-definitions-CAs0RD2N.js");
11
11
  let node_child_process = require("node:child_process");
12
12
  let node_url = require("node:url");
13
13
  let sharp = require("sharp");
@@ -1,8 +1,8 @@
1
- import { B as errMsg, G as createEvent, V as BaseAddon, dt as EventCategory, et as _enum, it as lazy, j as pipelineRunnerCapability, k as nodePin, lt as string, nt as boolean, ot as number, st as object, tt as array, x as defineCustomActions, y as customAction } from "../dist-BpWot5-w.mjs";
1
+ import { B as errMsg, G as createEvent, V as BaseAddon, dt as EventCategory, et as _enum, it as lazy, j as pipelineRunnerCapability, k as nodePin, lt as string, nt as boolean, ot as number, st as object, tt as array, x as defineCustomActions, y as customAction } from "../dist-DkGHtAaK.mjs";
2
2
  import { n as profileForStreamId, t as isRemoteRestream } from "../remote-restream-BeHi78PZ.mjs";
3
3
  import { r as resolveHubHostname } from "../sheet-geometry-DcpuGTCm.mjs";
4
4
  import { t as isWorkerReply } from "../worker-protocol-CyVJTZEO.mjs";
5
- import { a as getStepDefinition } from "../step-definitions-D6R9X0V7.mjs";
5
+ import { a as getStepDefinition } from "../step-definitions-Delhq28w.mjs";
6
6
  import { fork } from "node:child_process";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import sharp from "sharp";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("../chunk-D6vf50IK.js");
2
- const require_dist = require("../dist-D5o9fGxq.js");
2
+ const require_dist = require("../dist-BxxVKcnw.js");
3
3
  const require_sheet_geometry = require("../sheet-geometry-BR-ip0CP.js");
4
4
  const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-Dv-oFwjN.js");
5
5
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { B as errMsg, D as migrateConfigToBands, I as storageEvictableCapability, K as hydrateSchema, M as recordingCapability, N as recordingExportCapability, P as resolveScrubThumbnailGeometry, Q as selectAssignedProfileSlots, V as BaseAddon, W as DeviceType, ct as record, d as OpsLogEntrySchema, dt as EventCategory, f as RecordingConfigSchema, k as nodePin, l as ExportRecordSchema, lt as string, q as isEvent, s as EVENT_PAD_MS, tt as array } from "../dist-BpWot5-w.mjs";
1
+ import { B as errMsg, D as migrateConfigToBands, I as storageEvictableCapability, K as hydrateSchema, M as recordingCapability, N as recordingExportCapability, P as resolveScrubThumbnailGeometry, Q as selectAssignedProfileSlots, V as BaseAddon, W as DeviceType, ct as record, d as OpsLogEntrySchema, dt as EventCategory, f as RecordingConfigSchema, k as nodePin, l as ExportRecordSchema, lt as string, q as isEvent, s as EVENT_PAD_MS, tt as array } from "../dist-DkGHtAaK.mjs";
2
2
  import { n as computeSheetGeometry, r as resolveHubHostname, t as allTilePlacements } from "../sheet-geometry-DcpuGTCm.mjs";
3
3
  import { n as createFileDataPlaneHandler, s as parseRangeHeader, t as contentTypeFor } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
4
4
  import { spawn } from "node:child_process";