@camstack/addon-pipeline 1.2.339 → 1.2.341

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 (34) hide show
  1. package/dist/audio-analyzer/index.js +3 -3
  2. package/dist/audio-analyzer/index.mjs +3 -3
  3. package/dist/{custom-model-catalog-BY35vysX.js → custom-model-catalog-CoJEC8nz.js} +5 -3
  4. package/dist/{custom-model-catalog-B5sCwSgr.mjs → custom-model-catalog-DNSmyZTT.mjs} +5 -3
  5. package/dist/detection-pipeline/index.js +188 -17
  6. package/dist/detection-pipeline/index.mjs +213 -42
  7. package/dist/{dist-BylL-kRe.mjs → dist-B8oPeJDI.mjs} +487 -57
  8. package/dist/{dist-BUqvRc-c.js → dist-PiNPe8uQ.js} +504 -56
  9. package/dist/{model-catalogs-DygV-lXw.js → model-catalogs-CEphd9Va.js} +1 -1
  10. package/dist/{model-catalogs-x1G07ScE.mjs → model-catalogs-RM3pkuZm.mjs} +1 -1
  11. package/dist/motion-wasm/index.js +1 -1
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/{node-r1KgYS72.js → node-CMTBIa3-.js} +1 -1
  14. package/dist/{node-4Vnc6mbI.mjs → node-DFUmMJ_f.mjs} +1 -1
  15. package/dist/pipeline-runner/index.js +3 -3
  16. package/dist/pipeline-runner/index.mjs +3 -3
  17. package/dist/{process-memory-DOX7Esg9.mjs → process-memory-C4v8DBKn.mjs} +1 -1
  18. package/dist/{process-memory-Dr9tFNCX.js → process-memory-CzAfDP9P.js} +1 -1
  19. package/dist/recorder/index.js +12 -2
  20. package/dist/recorder/index.mjs +12 -2
  21. package/dist/{segment-demux-js-5UX_f1ey.js → segment-demux-js-C-n_ZsMK.js} +1 -1
  22. package/dist/{segment-demux-js-Brk0ORQN.mjs → segment-demux-js-CIpCdbx4.mjs} +1 -1
  23. package/dist/stream-broker/_stub.js +2 -2
  24. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-oF4bquCk.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CIDS0Tr9.mjs} +2 -2
  25. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BvfT5BVP.mjs +26 -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-Bt8aa0wk.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-LU_e-xJm.mjs} +1 -1
  27. package/dist/stream-broker/demux-worker-child.js +1 -1
  28. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  29. package/dist/stream-broker/{hostInit-BOteWKrZ.mjs → hostInit-CW_cmeNQ.mjs} +2 -2
  30. package/dist/stream-broker/index.js +3 -3
  31. package/dist/stream-broker/index.mjs +3 -3
  32. package/dist/stream-broker/remoteEntry.js +1 -1
  33. package/package.json +1 -1
  34. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-1Y-WK-Zy.mjs +0 -26
@@ -1,16 +1,16 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $n as string, An as createEvent, D as LABEL_SUPPLY_MACRO, Dt as linkedLabelStepId, En as BaseAddon, Hn as sleep, M as PoolMemoryWatchdog, Pn as hydrateSchema, Rn as nodePin, Vt as pickClusterStepSettings, W as YAMNET_TO_MACRO, Wn as array, Wt as pipelineExecutorCapability, Xn as object, Zt as resolveClusterStepModelId, an as rootSuppliesOf, d as CLUSTER_MODEL_SCOPED_STEPS, dt as detectionPipelineCapability, er as union, fn as supportedRuntimes$1, g as DEFAULT_CLUSTER_STEP_SETTINGS, ht as evaluateZoneRules, kt as loadContributionCapability, mt as enumerateInferenceDevices, n as APPLE_SA_TO_MACRO, nn as resolvePoolMemoryPolicy, nt as containingParentIndex, on as runtimeDevices$1, ot as defaultDeviceFor$1, q as applyModelBoundSettings, sn as stepModelRunsOnFormat, tr as EventCategory, wn as errMsg, wt as hfModelUrl, zn as parseJsonUnknown, zt as overlayClusterStepSettings } from "../dist-BylL-kRe.mjs";
3
- import { s as readProcessCost } from "../node-4Vnc6mbI.mjs";
4
- import { C as resolveModelDefaultConfidence, S as landmarkPrecisionVerdict, _ as ALL_STEPS, b as getStepDefinition, f as localFrameRegistry, g as ALL_PIPELINE_STEPS, l as resolveDefaultDetectionModel, n as mergeCustomModels, o as deviceKeyOf, r as buildSubtreeCanRun, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, v as getDefaultModelForFormat, x as resolveModelForFormat, y as getStep } from "../custom-model-catalog-B5sCwSgr.mjs";
2
+ import { $n as object, Bt as modelBindingKey, Dn as errMsg$1, Et as hfModelUrl, G as YAMNET_TO_MACRO, Gn as sleep, Hn as parseJsonUnknown, Ht as overlayClusterStepSettings, J as applyModelBoundSettings, Ln as hydrateSchema, N as PoolMemoryWatchdog, Nn as createEvent, O as LABEL_SUPPLY_MACRO, Vn as nodePin, Wt as pickClusterStepSettings, _t as evaluateZoneRules, an as resolvePoolMemoryPolicy, cn as rootSuppliesOf, ct as defaultDeviceFor$1, d as CLUSTER_MODEL_SCOPED_STEPS, en as resolveClusterStepModelId, g as DEFAULT_CLUSTER_STEP_SETTINGS, gt as enumerateInferenceDevices, hn as supportedRuntimes$1, ir as EventCategory, it as containingParentIndex, jt as loadContributionCapability, kn as BaseAddon, kt as linkedLabelStepId, ln as runtimeDevices$1, n as APPLE_SA_TO_MACRO, nr as string, pt as detectionPipelineCapability, qn as array, qt as pipelineExecutorCapability, rr as union, rt as collectModelBoundKeys, un as stepModelRunsOnFormat } from "../dist-B8oPeJDI.mjs";
3
+ import { s as readProcessCost } from "../node-DFUmMJ_f.mjs";
4
+ import { C as resolveModelDefaultConfidence, S as landmarkPrecisionVerdict, _ as ALL_STEPS, b as getStepDefinition, f as localFrameRegistry, g as ALL_PIPELINE_STEPS, l as resolveDefaultDetectionModel, n as mergeCustomModels, o as deviceKeyOf, r as buildSubtreeCanRun, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, v as getDefaultModelForFormat, x as resolveModelForFormat, y as getStep } from "../custom-model-catalog-DNSmyZTT.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DOX7Esg9.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-C4v8DBKn.mjs";
7
7
  import * as os from "node:os";
8
8
  import * as fs from "node:fs";
9
9
  import * as path$1 from "node:path";
10
10
  import { dirname, join } from "node:path";
11
11
  import { spawn } from "node:child_process";
12
12
  import sharp from "sharp";
13
- import { adoptModelRevisions, deleteModelFromDisk, ensureModel, isModelDownloaded, startEventLoopStallMonitor } from "@camstack/system/addon-utils";
13
+ import { adoptModelRevisions, deleteModelFromDisk, ensureModel, getModelFilePath, isModelDownloaded, startEventLoopStallMonitor } from "@camstack/system/addon-utils";
14
14
  //#region src/detection-pipeline/runtimes.ts
15
15
  var KNOWN_PLATFORMS = [
16
16
  "darwin",
@@ -339,6 +339,138 @@ function normalizeEngineNodeId(rawNodeId) {
339
339
  return raw.includes("/") ? raw.split("/")[0] ?? "hub" : raw;
340
340
  }
341
341
  //#endregion
342
+ //#region src/detection-pipeline/model-bound-device-overrides.ts
343
+ /**
344
+ * Auto tune (D745), the executor leg: list — and optionally remove — the
345
+ * MODEL-BOUND thresholds stored in this addon's per-camera settings (the
346
+ * object-detection root's `bindsToModel` keys and their binding keys, D738).
347
+ * Every other key of a camera's store is kept.
348
+ *
349
+ * The device store only MERGES on write, so a removal is clear + write of the
350
+ * kept keys — the idiom `migrate-hardware-state.ts` uses. Both run in this
351
+ * process, serialized per camera; a write that fails after the clear restores
352
+ * the original row, and the camera is reported `refused` rather than clean. A
353
+ * store that cannot be read is `refused` too: a failed read is never "nothing
354
+ * to clear" (D393).
355
+ */
356
+ function errMsg(err) {
357
+ return err instanceof Error ? err.message : String(err);
358
+ }
359
+ /** The stored keys among `boundKeys` (values and bindings), sorted. */
360
+ function presentBoundKeys(row, boundKeys) {
361
+ return boundKeys.flatMap((k) => [k, modelBindingKey(k)]).filter((k) => k in row).toSorted();
362
+ }
363
+ async function clearModelBoundDeviceOverrides(deps, input) {
364
+ const ids = input.deviceIds ?? await deps.listDeviceIds();
365
+ const entries = [];
366
+ const refused = [];
367
+ for (const deviceId of [...ids].toSorted((a, b) => a - b)) {
368
+ let row;
369
+ try {
370
+ row = await deps.readDeviceStore(deviceId);
371
+ } catch (err) {
372
+ refused.push({
373
+ deviceId,
374
+ reason: `read failed: ${errMsg(err)}`
375
+ });
376
+ continue;
377
+ }
378
+ const keys = presentBoundKeys(row, deps.boundKeys);
379
+ if (keys.length === 0) continue;
380
+ if (input.dryRun) {
381
+ entries.push({
382
+ deviceId,
383
+ keys
384
+ });
385
+ continue;
386
+ }
387
+ const kept = { ...row };
388
+ for (const k of keys) delete kept[k];
389
+ try {
390
+ await deps.clearDeviceStore(deviceId);
391
+ } catch (err) {
392
+ refused.push({
393
+ deviceId,
394
+ reason: `clear failed: ${errMsg(err)}`
395
+ });
396
+ continue;
397
+ }
398
+ try {
399
+ if (Object.keys(kept).length > 0) await deps.writeDeviceStore(deviceId, kept);
400
+ entries.push({
401
+ deviceId,
402
+ keys
403
+ });
404
+ } catch (err) {
405
+ await deps.writeDeviceStore(deviceId, row).catch(() => void 0);
406
+ refused.push({
407
+ deviceId,
408
+ reason: `write failed, row restored: ${errMsg(err)}`
409
+ });
410
+ } finally {
411
+ deps.invalidate(deviceId);
412
+ }
413
+ }
414
+ return {
415
+ entries,
416
+ refused
417
+ };
418
+ }
419
+ //#endregion
420
+ //#region src/detection-pipeline/model-format-facts.ts
421
+ /**
422
+ * Two per-format facts `getSchema` reports beside `downloaded`, for Model
423
+ * Studio → Installed (one row per model × format on a node).
424
+ *
425
+ * - {@link modelOnDiskState} — `current` / `stale` / `missing`. `downloaded`
426
+ * alone is `current`; it cannot tell a copy that is on disk but not proven
427
+ * at its catalog revision (D743/D744) from no copy at all, and those are
428
+ * different answers to "what does this node hold" — a stale copy is still
429
+ * bytes on the disk, still reclaimable, and is replaced on its next ensure.
430
+ * - {@link formatPrecision} — the numeric precision of the BUILD, only when
431
+ * the build says so. An unsuffixed OpenVINO IR is FP16 for one family and
432
+ * FP32 for another (`scripts/build-camstack-models.py`), so this answers
433
+ * `undefined` rather than guess.
434
+ *
435
+ * Kept in the addon, not in `@camstack/system` / `@camstack/types`: both are
436
+ * host-resolved at runtime, so a new value there would reach an addon only
437
+ * with a server release, and this addon would fail to load on an older hub.
438
+ */
439
+ /** What this node holds for one (model, format). */
440
+ function modelOnDiskState(modelsDir, entry, format) {
441
+ if (entry.formats[format] === void 0) return "missing";
442
+ if (isModelDownloaded(modelsDir, entry, format)) return "current";
443
+ const modelPath = getModelFilePath(modelsDir, entry, format);
444
+ return modelPath !== null && fs.existsSync(modelPath) ? "stale" : "missing";
445
+ }
446
+ var PRECISION_TOKEN = /(?:^|[-_.])(int8|fp16|fp32)(?=[-_.]|$)/i;
447
+ /** The artefact's file name, without the directory. */
448
+ function artefactName(url) {
449
+ return url.split("/").pop() ?? url;
450
+ }
451
+ /** Precision a token in the artefact name states (`…-int8.xml`, `…_int8_edgetpu.tflite`). */
452
+ function precisionFromName(name) {
453
+ const token = PRECISION_TOKEN.exec(name)?.[1]?.toLowerCase();
454
+ if (token === "int8" || token === "fp16" || token === "fp32") return token;
455
+ }
456
+ /**
457
+ * The precision of one format's build, or `undefined` when nothing states it.
458
+ * In order: a token in the file name; an `int8` variant group (every format of
459
+ * an INT8 variant is quantised); an EdgeTPU build (the compiler accepts only
460
+ * full-integer models); a Core ML build hosted on the CamStack mirror (every
461
+ * CamStack Core ML export is FP16 — D743). Nothing else is assumed.
462
+ */
463
+ function formatPrecision(entry, format) {
464
+ const formatEntry = entry.formats[format];
465
+ if (formatEntry === void 0) return void 0;
466
+ const name = artefactName(formatEntry.url);
467
+ const named = precisionFromName(name);
468
+ if (named !== void 0) return named;
469
+ if (entry.group?.precision === "int8") return "int8";
470
+ if (format === "tflite" && /edgetpu/i.test(name)) return "int8";
471
+ if (format === "coreml" && formatEntry.url.startsWith(hfModelUrl("camstack/camstack-models", ""))) return "fp16";
472
+ }
473
+ //#endregion
342
474
  //#region src/shared/cluster-model-source.ts
343
475
  /**
344
476
  * Where the runner gets the ONE cluster model choice per cluster-scoped step.
@@ -6877,7 +7009,7 @@ var PipelineExecutor = class {
6877
7009
  rootStepId: rootStep.stepId,
6878
7010
  parentClass: mutable.macroClass,
6879
7011
  parentScore: mutable.score,
6880
- error: errMsg(err)
7012
+ error: errMsg$1(err)
6881
7013
  }
6882
7014
  });
6883
7015
  }
@@ -7008,7 +7140,7 @@ var PipelineExecutor = class {
7008
7140
  rootStepId: rootStep.stepId,
7009
7141
  parentClass: mutable.macroClass,
7010
7142
  parentScore: mutable.score,
7011
- error: errMsg(err)
7143
+ error: errMsg$1(err)
7012
7144
  }
7013
7145
  });
7014
7146
  }
@@ -7107,7 +7239,7 @@ var PipelineExecutor = class {
7107
7239
  ]
7108
7240
  };
7109
7241
  } catch (err) {
7110
- this.throttledWarn(`crop-zone-prep:${deviceId}`, 3e4, "crop-zone frame preparation failed — running package-detection full-frame", { error: errMsg(err) }, deviceId);
7242
+ this.throttledWarn(`crop-zone-prep:${deviceId}`, 3e4, "crop-zone frame preparation failed — running package-detection full-frame", { error: errMsg$1(err) }, deviceId);
7111
7243
  return null;
7112
7244
  }
7113
7245
  }
@@ -7119,7 +7251,7 @@ var PipelineExecutor = class {
7119
7251
  try {
7120
7252
  engineOutput = await step.engine.infer(input);
7121
7253
  } catch (err) {
7122
- const errorMsg = errMsg(err);
7254
+ const errorMsg = errMsg$1(err);
7123
7255
  const errorOutput = {
7124
7256
  kind: "detections",
7125
7257
  detections: []
@@ -7406,7 +7538,7 @@ var PipelineExecutor = class {
7406
7538
  this.throttledWarn(`child-fail:${child.stepId}:${deviceId}`, 15e3, "pipeline child step failed", {
7407
7539
  step: child.stepId,
7408
7540
  model: child.modelId,
7409
- error: errMsg(err)
7541
+ error: errMsg$1(err)
7410
7542
  }, deviceId);
7411
7543
  }
7412
7544
  }
@@ -7553,13 +7685,6 @@ function collectSchemaDefaults(schema) {
7553
7685
  walkFieldsForDefaults(schema, out);
7554
7686
  return out;
7555
7687
  }
7556
- /** The keys of every `bindsToModel` field of a schema, groups flattened (D738). */
7557
- function collectModelBoundKeys(fields) {
7558
- return fields.flatMap((field) => {
7559
- if (field.type === "group") return collectModelBoundKeys(field.fields);
7560
- return "key" in field && "bindsToModel" in field && field.bindsToModel === true ? [field.key] : [];
7561
- });
7562
- }
7563
7688
  /**
7564
7689
  * The operator settings of `stepId` as the model that RUNS sees them (D738):
7565
7690
  * a model-bound value made for another model is dropped and binding keys are
@@ -8422,6 +8547,8 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8422
8547
  readDeviceStore;
8423
8548
  /** Delete all per-device settings for a device (used by `clearDeviceOverrides`). */
8424
8549
  clearDeviceStore;
8550
+ /** Merge a patch into one device's settings (Auto tune' keep-the-rest rewrite, D745). */
8551
+ writeDeviceStore;
8425
8552
  /**
8426
8553
  * The per-device overrides the FRAME path reads, kept fresh off that path.
8427
8554
  *
@@ -8441,11 +8568,13 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8441
8568
  this.readDeviceStore = settings.readDeviceStore ?? (async () => ({}));
8442
8569
  const clearDeviceStore = settings.clearDeviceStore;
8443
8570
  this.clearDeviceStore = clearDeviceStore ? (deviceId) => clearDeviceStore.call(settings, deviceId) : async () => void 0;
8571
+ const writeDeviceStore = settings.writeDeviceStore;
8572
+ this.writeDeviceStore = writeDeviceStore ? (deviceId, patch) => writeDeviceStore.call(settings, deviceId, patch) : async () => void 0;
8444
8573
  this.deviceOverrides = new DeviceOverrideMirror({
8445
8574
  read: (deviceId) => this.readDeviceStore(deviceId),
8446
8575
  onRefreshFailed: (deviceId, err) => this.log.warn("per-device detection overrides refresh failed — serving the last value", {
8447
8576
  tags: { deviceId },
8448
- meta: { error: errMsg(err) }
8577
+ meta: { error: errMsg$1(err) }
8449
8578
  })
8450
8579
  });
8451
8580
  this.currentEngine = ONNX_FLOOR;
@@ -8471,7 +8600,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8471
8600
  stale: report.stale
8472
8601
  } });
8473
8602
  }, (err) => {
8474
- this.log.warn("Model revision check failed — copies are proven on their next download", { meta: { error: errMsg(err) } });
8603
+ this.log.warn("Model revision check failed — copies are proven on their next download", { meta: { error: errMsg$1(err) } });
8475
8604
  });
8476
8605
  }
8477
8606
  /**
@@ -8581,14 +8710,14 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8581
8710
  else this.log.warn("platform-probe readiness gate timed out — conservative engine pick (floor is not persisted)", { meta: {
8582
8711
  nodeId,
8583
8712
  timeoutMs: PROBE_READY_TIMEOUT_MS,
8584
- error: errMsg(err)
8713
+ error: errMsg$1(err)
8585
8714
  } });
8586
8715
  }
8587
8716
  await this.resolveAutoEngine();
8588
8717
  this.needsAutoPick = false;
8589
8718
  this.startProvisioningForCurrentEngine();
8590
8719
  await this.recomputeConfigIssues().catch((err) => {
8591
- this.log.warn("config-issue recompute failed after node-default derive", { meta: { error: errMsg(err) } });
8720
+ this.log.warn("config-issue recompute failed after node-default derive", { meta: { error: errMsg$1(err) } });
8592
8721
  });
8593
8722
  }
8594
8723
  /**
@@ -8773,7 +8902,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8773
8902
  this.configIssues = [...substitutionIssues, ...zeroBuildIssues];
8774
8903
  } catch (err) {
8775
8904
  this.configIssues = [];
8776
- this.log.warn("engine-change config gate failed — no config issues surfaced", { meta: { error: errMsg(err) } });
8905
+ this.log.warn("engine-change config gate failed — no config issues surfaced", { meta: { error: errMsg$1(err) } });
8777
8906
  }
8778
8907
  }
8779
8908
  /**
@@ -9098,7 +9227,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9098
9227
  issues: [{
9099
9228
  addonId: "*",
9100
9229
  kind: "unknown-device",
9101
- detail: errMsg(err)
9230
+ detail: errMsg$1(err)
9102
9231
  }],
9103
9232
  substitutions: [],
9104
9233
  format
@@ -9125,7 +9254,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9125
9254
  format
9126
9255
  };
9127
9256
  } catch (err) {
9128
- this.log.warn("validatePipeline failed — reporting a clean result", { meta: { error: errMsg(err) } });
9257
+ this.log.warn("validatePipeline failed — reporting a clean result", { meta: { error: errMsg$1(err) } });
9129
9258
  return {
9130
9259
  ok: true,
9131
9260
  issues: [],
@@ -9317,7 +9446,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9317
9446
  durationMs
9318
9447
  };
9319
9448
  } catch (err) {
9320
- const msg = errMsg(err);
9449
+ const msg = errMsg$1(err);
9321
9450
  this.log.error("Model download failed", { meta: {
9322
9451
  error: msg,
9323
9452
  modelId,
@@ -9673,7 +9802,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9673
9802
  ...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
9674
9803
  deviceKey: dispatchDeviceKeyLabel,
9675
9804
  outcome: "step-dropped"
9676
- }, dispatchDeviceKeyLabel, [model], model, "not-warm", errMsg(failure.error));
9805
+ }, dispatchDeviceKeyLabel, [model], model, "not-warm", errMsg$1(failure.error));
9677
9806
  }
9678
9807
  }
9679
9808
  const rootModelId = resolveTreeRootModelId(tree.roots);
@@ -10081,7 +10210,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10081
10210
  ...tags,
10082
10211
  meta: {
10083
10212
  deviceKey,
10084
- error: errMsg(err)
10213
+ error: errMsg$1(err)
10085
10214
  }
10086
10215
  });
10087
10216
  });
@@ -10118,7 +10247,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10118
10247
  throw err;
10119
10248
  }
10120
10249
  const failed = failedModelOf(err) ?? models[0] ?? "";
10121
- this.reportDispatchLoadLoss(context, deviceKey, models, failed, `failed:${flight.generation ?? "unknown"}`, errMsg(err));
10250
+ this.reportDispatchLoadLoss(context, deviceKey, models, failed, `failed:${flight.generation ?? "unknown"}`, errMsg$1(err));
10122
10251
  throw err;
10123
10252
  }
10124
10253
  }
@@ -10215,13 +10344,13 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10215
10344
  const poolModel = err instanceof StepVariantLoadError ? err.poolModel : null;
10216
10345
  let generation = 0;
10217
10346
  for (const model of failedModels) {
10218
- const outcome = this.loadGovernor.recordFailure(pool, deviceKey, model, errMsg(err), compileTimeout, Date.now(), poolModel, err instanceof StepVariantLoadError ? err.reason : null);
10347
+ const outcome = this.loadGovernor.recordFailure(pool, deviceKey, model, errMsg$1(err), compileTimeout, Date.now(), poolModel, err instanceof StepVariantLoadError ? err.reason : null);
10219
10348
  generation = outcome.generation;
10220
10349
  if (outcome.refusedNow) this.log.error("model REFUSED on this device — its compile timed out repeatedly", { meta: {
10221
10350
  deviceKey,
10222
10351
  model,
10223
10352
  compileTimeouts: outcome.compileTimeouts,
10224
- error: errMsg(err),
10353
+ error: errMsg$1(err),
10225
10354
  device: "keeps serving every other model",
10226
10355
  rearm: "pipelineExecutor.rearmInferenceDevice"
10227
10356
  } });
@@ -10282,7 +10411,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10282
10411
  this.log.info("Model downloaded successfully", { meta: { modelId: entry.id } });
10283
10412
  return;
10284
10413
  } catch (err) {
10285
- const msg = errMsg(err);
10414
+ const msg = errMsg$1(err);
10286
10415
  if (attempt < maxRetries) {
10287
10416
  const delayMs = 2e3 * Math.pow(2, attempt - 1);
10288
10417
  this.log.warn("Model download failed — retrying", { meta: {
@@ -10358,7 +10487,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10358
10487
  try {
10359
10488
  return await this.runPipelineBatchImpl(input);
10360
10489
  } catch (err) {
10361
- const msg = errMsg(err);
10490
+ const msg = errMsg$1(err);
10362
10491
  const stack = err instanceof Error ? err.stack : void 0;
10363
10492
  this.log.error("runPipelineBatch failed", { meta: {
10364
10493
  phase: "batch",
@@ -10686,9 +10815,9 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10686
10815
  deviceKey: defaultDeviceKey,
10687
10816
  backend: this.currentEngine.backend,
10688
10817
  device: this.currentEngine.device ?? null,
10689
- error: errMsg(err)
10818
+ error: errMsg$1(err)
10690
10819
  } });
10691
- this.noteDeviceDeath(defaultDeviceKey, errMsg(err));
10820
+ this.noteDeviceDeath(defaultDeviceKey, errMsg$1(err));
10692
10821
  throw err;
10693
10822
  }
10694
10823
  this.engineFactory = factory;
@@ -10926,7 +11055,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10926
11055
  error: err instanceof Error ? err.message : String(err)
10927
11056
  } });
10928
11057
  await factory.dispose().catch(() => void 0);
10929
- this.noteDeviceDeath(deviceKey, errMsg(err));
11058
+ this.noteDeviceDeath(deviceKey, errMsg$1(err));
10930
11059
  throw err;
10931
11060
  }
10932
11061
  this.factoriesByDevice.set(deviceKey, factory);
@@ -11019,6 +11148,41 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
11019
11148
  };
11020
11149
  }
11021
11150
  /**
11151
+ * Auto tune (D745): list — or, unless `dryRun`, remove — the model-bound
11152
+ * thresholds of the per-camera detector store. See
11153
+ * `model-bound-device-overrides.ts`.
11154
+ */
11155
+ async clearModelBoundDeviceOverrides(input) {
11156
+ const result = await clearModelBoundDeviceOverrides({
11157
+ listDeviceIds: async () => {
11158
+ const api = this.addonCtx?.api;
11159
+ if (!api) throw new Error("clearModelBoundDeviceOverrides: ctx.api unavailable");
11160
+ return (await api.deviceManager.listAll.query({ projection: "slim" })).map((d) => d.id);
11161
+ },
11162
+ readDeviceStore: (deviceId) => this.readDeviceStore(deviceId),
11163
+ clearDeviceStore: (deviceId) => this.clearDeviceStore(deviceId),
11164
+ writeDeviceStore: (deviceId, patch) => this.writeDeviceStore(deviceId, patch),
11165
+ invalidate: (deviceId) => this.deviceOverrides.invalidate(deviceId),
11166
+ boundKeys: collectModelBoundKeys(getStep("object-detection").getConfigSchema())
11167
+ }, input);
11168
+ if (!input.dryRun) for (const entry of result.entries) this.log.info("auto tune: per-camera detector thresholds cleared", {
11169
+ tags: { deviceId: entry.deviceId },
11170
+ meta: {
11171
+ deviceId: entry.deviceId,
11172
+ keys: entry.keys
11173
+ }
11174
+ });
11175
+ for (const r of result.refused) this.log.warn("auto tune: per-camera detector thresholds not cleared", {
11176
+ tags: { deviceId: r.deviceId },
11177
+ meta: {
11178
+ deviceId: r.deviceId,
11179
+ reason: r.reason,
11180
+ dryRun: input.dryRun
11181
+ }
11182
+ });
11183
+ return result;
11184
+ }
11185
+ /**
11022
11186
  * Clear the per-device pipeline-step overrides for every known device.
11023
11187
  * Returns the count of devices whose store was cleared. There is no
11024
11188
  * bulk-list primitive over the per-device store, so devices are
@@ -11034,7 +11198,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
11034
11198
  try {
11035
11199
  devices = await api.deviceManager.listAll.query({ projection: "slim" });
11036
11200
  } catch (err) {
11037
- this.log.warn("clearDeviceOverrides: device enumeration failed — skipping per-device clear", { meta: { error: errMsg(err) } });
11201
+ this.log.warn("clearDeviceOverrides: device enumeration failed — skipping per-device clear", { meta: { error: errMsg$1(err) } });
11038
11202
  return 0;
11039
11203
  }
11040
11204
  let cleared = 0;
@@ -11047,7 +11211,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
11047
11211
  tags: { deviceId: device.id },
11048
11212
  meta: {
11049
11213
  deviceId: device.id,
11050
- error: errMsg(err)
11214
+ error: errMsg$1(err)
11051
11215
  }
11052
11216
  });
11053
11217
  }
@@ -11239,7 +11403,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
11239
11403
  frame
11240
11404
  };
11241
11405
  } catch (err) {
11242
- const msg = errMsg(err);
11406
+ const msg = errMsg$1(err);
11243
11407
  this.log.error("failed", { meta: {
11244
11408
  phase: "audio-test",
11245
11409
  error: msg
@@ -11279,10 +11443,17 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
11279
11443
  models: availableModels.map((m) => ({
11280
11444
  id: m.id,
11281
11445
  name: m.name,
11282
- formats: Object.fromEntries(Object.entries(m.formats).map(([f, entry]) => [f, {
11283
- downloaded: isModelDownloaded(modelsDir, m, f),
11284
- sizeMB: entry.sizeMB
11285
- }])),
11446
+ formats: Object.fromEntries(Object.entries(m.formats).map(([f, entry]) => {
11447
+ const format = f;
11448
+ const onDisk = modelOnDiskState(modelsDir, m, format);
11449
+ const precision = formatPrecision(m, format);
11450
+ return [f, {
11451
+ downloaded: onDisk === "current",
11452
+ sizeMB: entry.sizeMB,
11453
+ onDisk,
11454
+ ...precision !== void 0 ? { precision } : {}
11455
+ }];
11456
+ })),
11286
11457
  ...m.group ? { group: m.group } : {},
11287
11458
  ...m.legacy !== void 0 ? { legacy: m.legacy } : {},
11288
11459
  provider: m.provider ?? "camstack",