@camstack/addon-pipeline 1.2.333 → 1.2.335

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 (37) hide show
  1. package/THIRD_PARTY_MODELS.md +3 -8
  2. package/dist/audio-analyzer/index.js +2 -2
  3. package/dist/audio-analyzer/index.mjs +2 -2
  4. package/dist/{default-detection-model-CDffuH2m.mjs → custom-model-catalog-Buehc666.mjs} +518 -179
  5. package/dist/{default-detection-model-Biwf5-ML.js → custom-model-catalog-CL-xJa8w.js} +529 -178
  6. package/dist/detection-pipeline/index.js +186 -120
  7. package/dist/detection-pipeline/index.mjs +135 -69
  8. package/dist/{dist-DJV7Z6Bb.js → dist-C5DlS_lW.js} +214 -22
  9. package/dist/{dist-BsT15i7i.mjs → dist-CPhDwlSN.mjs} +203 -23
  10. package/dist/motion-wasm/index.js +1 -1
  11. package/dist/motion-wasm/index.mjs +1 -1
  12. package/dist/{node-CkmucLYG.js → node-BUafKArW.js} +1 -1
  13. package/dist/{node-Crsi_8ea.mjs → node-DYfEOwjW.mjs} +1 -1
  14. package/dist/pipeline-runner/index.js +248 -44
  15. package/dist/pipeline-runner/index.mjs +226 -22
  16. package/dist/{process-memory-BJb7Ihdp.js → process-memory-DWOQCbg5.js} +1 -1
  17. package/dist/{process-memory-1mAUV8S1.mjs → process-memory-WPRYnN8c.mjs} +1 -1
  18. package/dist/recorder/index.js +2 -2
  19. package/dist/recorder/index.mjs +2 -2
  20. package/dist/{segment-demux-js-mK9IBGLf.js → segment-demux-js-DWIgUPW1.js} +1 -1
  21. package/dist/{segment-demux-js-B_tboBcJ.mjs → segment-demux-js-Kz4EnmOr.mjs} +1 -1
  22. package/dist/stream-broker/_stub.js +1 -1
  23. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-a3HMFtd5.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-RPk9F8CY.mjs} +2 -2
  24. 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 +26 -0
  25. package/dist/stream-broker/demux-worker-child.js +1 -1
  26. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  27. package/dist/stream-broker/{hostInit-DChPnZ5C.mjs → hostInit-DXXdQdLd.mjs} +2 -2
  28. package/dist/stream-broker/index.js +3 -3
  29. package/dist/stream-broker/index.mjs +3 -3
  30. package/dist/stream-broker/remoteEntry.js +1 -1
  31. package/package.json +1 -1
  32. package/python/inference_pool.py +52 -2
  33. package/python/postprocessors/test_yolo_seg_root.py +109 -0
  34. package/python/postprocessors/yolo.py +52 -13
  35. package/python/postprocessors/yolo_seg.py +79 -156
  36. package/python/test_inference_pool_ov_precision.py +98 -0
  37. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DPbj3ML4.mjs +0 -26
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-DJV7Z6Bb.js");
7
- const require_node = require("../node-CkmucLYG.js");
8
- const require_default_detection_model = require("../default-detection-model-Biwf5-ML.js");
6
+ const require_dist = require("../dist-C5DlS_lW.js");
7
+ const require_node = require("../node-BUafKArW.js");
8
+ const require_custom_model_catalog = require("../custom-model-catalog-CL-xJa8w.js");
9
9
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
10
- const require_process_memory = require("../process-memory-BJb7Ihdp.js");
10
+ const require_process_memory = require("../process-memory-DWOQCbg5.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_chunk.__toESM(node_os);
13
13
  let node_fs = require("node:fs");
@@ -2250,6 +2250,7 @@ function describeCommand(cmd) {
2250
2250
  model: typeof modelPath === "string" && modelPath.length > 0 ? node_path.basename(modelPath, node_path.extname(modelPath)) : null
2251
2251
  };
2252
2252
  }
2253
+ /** The wire form of a model config — the keys the Python pool reads. Exported for tests. */
2253
2254
  function serializeModelConfig(config) {
2254
2255
  const result = {
2255
2256
  path: config.path,
@@ -2261,6 +2262,7 @@ function serializeModelConfig(config) {
2261
2262
  if (config.nmsIouThreshold !== void 0) result["nmsIouThreshold"] = config.nmsIouThreshold;
2262
2263
  if (config.inputNormalization !== void 0) result["inputNormalization"] = config.inputNormalization;
2263
2264
  if (config.outputProbabilities !== void 0) result["outputProbabilities"] = config.outputProbabilities;
2265
+ if (config.gpuInferencePrecision !== void 0) result["gpuInferencePrecision"] = config.gpuInferencePrecision;
2264
2266
  if (config.inputWidth !== void 0) result["inputWidth"] = config.inputWidth;
2265
2267
  if (config.inputHeight !== void 0) result["inputHeight"] = config.inputHeight;
2266
2268
  if (config.inputChannels !== void 0) result["inputChannels"] = config.inputChannels;
@@ -2451,25 +2453,43 @@ function collectClassMapDropWarning(def, entry) {
2451
2453
  function toApplicability(acc) {
2452
2454
  const hasInapplicable = Object.keys(acc.inapplicable).length > 0;
2453
2455
  const hasOptions = Object.keys(acc.optionsByModel).length > 0;
2454
- if (!hasInapplicable && !hasOptions) return void 0;
2456
+ const hasDefaults = Object.keys(acc.defaultByModel).length > 0;
2457
+ if (!hasInapplicable && !hasOptions && !hasDefaults) return void 0;
2455
2458
  return {
2456
2459
  ...hasInapplicable ? { inapplicable: acc.inapplicable } : {},
2457
- ...hasOptions ? { optionsByModel: acc.optionsByModel } : {}
2460
+ ...hasOptions ? { optionsByModel: acc.optionsByModel } : {},
2461
+ ...hasDefaults ? { defaultByModel: acc.defaultByModel } : {}
2458
2462
  };
2459
2463
  }
2464
+ /** The `default` of `key` in a schema, groups flattened; `undefined` when absent. */
2465
+ function defaultOfKey(fields, key) {
2466
+ for (const field of fields) {
2467
+ if (field.type === "group") {
2468
+ const nested = defaultOfKey(field.fields, key);
2469
+ if (nested !== void 0) return nested;
2470
+ continue;
2471
+ }
2472
+ if ("key" in field && field.key === key && "default" in field) return field.default;
2473
+ }
2474
+ }
2460
2475
  function isAnnotatable(field) {
2461
2476
  return field.type === "slider" || field.type === "number" || field.type === "multiselect" || field.type === "select" || field.type === "boolean";
2462
2477
  }
2463
2478
  function annotateField(field, inputs) {
2464
2479
  if (!isAnnotatable(field)) return field;
2465
- const { def, models, customModelIds } = inputs;
2480
+ const { def, models, customModelIds, schemaForModel } = inputs;
2466
2481
  const acc = {
2467
2482
  inapplicable: {},
2468
- optionsByModel: {}
2483
+ optionsByModel: {},
2484
+ defaultByModel: {}
2469
2485
  };
2470
2486
  const macroKey = macroOfMinConfidenceKey(field.key);
2471
2487
  for (const entry of models) {
2472
2488
  const postprocessor = resolveEffectivePostprocessorForEntry(def, entry);
2489
+ if (field.bindsToModel === true && schemaForModel !== void 0) {
2490
+ const modelDefault = defaultOfKey(schemaForModel(entry), field.key);
2491
+ if (modelDefault !== void 0 && modelDefault !== field.default) acc.defaultByModel[entry.id] = modelDefault;
2492
+ }
2473
2493
  if (field.key === "nmsIouThreshold" && !postprocessorConsumesNms(postprocessor)) {
2474
2494
  acc.inapplicable[entry.id] = `NMS is fused inside this model's "${postprocessor}" export — the pipeline IoU threshold is not consulted.`;
2475
2495
  continue;
@@ -2518,6 +2538,55 @@ function annotateField(field, inputs) {
2518
2538
  function annotateConfigSchemaForModels(inputs) {
2519
2539
  return inputs.configSchema.map((field) => annotateField(field, inputs));
2520
2540
  }
2541
+ /** The slider that governs a root-supplied fine label (D741) — the step's own threshold. */
2542
+ var SUPPLIED_LABEL_FLOOR_KEY = "minConfidence";
2543
+ /**
2544
+ * D741 — when a ROOT detector supplies a step's fine label (species, vehicle
2545
+ * type), the step's `minConfidence` slider is the floor on the root's
2546
+ * DETECTION score for that label, bound to the root model. So for each root
2547
+ * model that supplies `stepId`'s labels, the slider's default under that model
2548
+ * is the root's `suppliedLabelFloors[stepId]`, or 0 (no floor beyond the macro
2549
+ * floor). Added to `modelApplicability.defaultByModel`, keyed by root model id,
2550
+ * so the editor — which shows the slider under the ROOT's id while the root
2551
+ * supplies the step — shows the floor the runner applies. A step no root
2552
+ * supplies a fine label for is returned untouched.
2553
+ */
2554
+ function withRootSuppliedLabelDefaults(stepId, configSchema, rootModels) {
2555
+ if (!isFineLabelSupplyStep(stepId)) return [...configSchema];
2556
+ const rootDef = require_custom_model_catalog.getStepDefinition(ROOT_STEP_ID);
2557
+ const defaults = {};
2558
+ for (const root of rootModels) {
2559
+ if (!require_dist.rootSuppliesOf(root, {
2560
+ labels: rootDef.labels ?? [],
2561
+ ...rootDef.classMap !== void 0 ? { classMap: rootDef.classMap } : {}
2562
+ }).some((s) => s.kind === "label" && s.stepId === stepId)) continue;
2563
+ defaults[root.id] = root.suppliedLabelFloors?.[stepId] ?? 0;
2564
+ }
2565
+ if (Object.keys(defaults).length === 0) return [...configSchema];
2566
+ return configSchema.map((field) => {
2567
+ if (field.type !== "slider" || field.key !== SUPPLIED_LABEL_FLOOR_KEY) return field;
2568
+ return {
2569
+ ...field,
2570
+ modelApplicability: {
2571
+ ...field.modelApplicability,
2572
+ defaultByModel: {
2573
+ ...field.modelApplicability?.defaultByModel,
2574
+ ...defaults
2575
+ }
2576
+ }
2577
+ };
2578
+ });
2579
+ }
2580
+ /** The camera root the supplies are read from. */
2581
+ var ROOT_STEP_ID = "object-detection";
2582
+ /**
2583
+ * A label-supply step whose effect is FINER than its macro (species, vehicle
2584
+ * type). `package-detection` is a label supply too, but its effect IS its
2585
+ * macro: it has no fine label and its threshold is `minConfidencePackage`.
2586
+ */
2587
+ function isFineLabelSupplyStep(stepId) {
2588
+ return Object.keys(require_dist.LABEL_SUPPLY_MACRO).includes(stepId) && stepId !== "package-detection";
2589
+ }
2521
2590
  /**
2522
2591
  * A persisted settings blob is external data — it survives schema changes,
2523
2592
  * hand edits and migrations. Accept only a finite IoU in the open (0,1)
@@ -3001,38 +3070,6 @@ var PipelineModelManager = class {
3001
3070
  }
3002
3071
  };
3003
3072
  //#endregion
3004
- //#region src/detection-pipeline/engine/resolve-device-engine.ts
3005
- /**
3006
- * Resolve a Phase-1 device key (`<backend>:<device>`, or bare `cpu`) into the
3007
- * {@link PipelineEngineChoice} used to build that device's inference pool.
3008
- * Throws on an unknown backend token so a bad `deviceKey` fails loud rather
3009
- * than silently building a wrong pool. Format comes from the shared
3010
- * {@link DEVICE_BACKEND_TO_FORMAT} SSOT (`@camstack/types`) — no local copy.
3011
- */
3012
- function resolveDeviceEngine(deviceKey) {
3013
- const colon = deviceKey.indexOf(":");
3014
- const backend = colon >= 0 ? deviceKey.slice(0, colon) : deviceKey;
3015
- const device = colon >= 0 ? deviceKey.slice(colon + 1) : deviceKey;
3016
- const format = require_dist.DEVICE_BACKEND_TO_FORMAT[backend];
3017
- if (format === void 0) throw new Error(`resolveDeviceEngine: unknown backend "${backend}" in deviceKey "${deviceKey}"`);
3018
- return {
3019
- runtime: "python",
3020
- backend,
3021
- format,
3022
- device
3023
- };
3024
- }
3025
- /**
3026
- * The inverse of {@link resolveDeviceEngine}: the `<backend>:<device>` key that
3027
- * names the pool an engine belongs to. Every pool-level log line carries this —
3028
- * without it a default pool logs anonymously and six hours of logs cannot tell
3029
- * "the NPU is unused" from "the NPU IS the anonymous default pool".
3030
- * Falls back to the bare backend when the engine carries no device.
3031
- */
3032
- function deviceKeyOf(engine) {
3033
- return engine.device ? `${engine.backend}:${engine.device}` : engine.backend;
3034
- }
3035
- //#endregion
3036
3073
  //#region src/detection-pipeline/engine/coral-cocompiled-set.ts
3037
3074
  var ROOT_DETECTOR_STEP_ID = "object-detection";
3038
3075
  /** The models a dispatch places on the pool that runs it: every enabled video step. */
@@ -3380,7 +3417,7 @@ var EngineFactory = class {
3380
3417
  constructor(opts) {
3381
3418
  this.opts = opts;
3382
3419
  this.log = opts.logger;
3383
- this.deviceKey = deviceKeyOf(opts.engine);
3420
+ this.deviceKey = require_custom_model_catalog.deviceKeyOf(opts.engine);
3384
3421
  this.resolvedProvisioning = resolvePoolProvisioning(opts.engine, opts.provisioning);
3385
3422
  this.coralSets = BACKEND_TO_POOL_RUNTIME[opts.engine.backend] === "edgetpu" ? new CoralSetPlanner(opts.coCompiledSets ?? EDGETPU_COCOMPILED_SETS) : null;
3386
3423
  }
@@ -3651,7 +3688,7 @@ var EngineFactory = class {
3651
3688
  * to `buildConfig`, which throws the message naming the step and the model.
3652
3689
  */
3653
3690
  resolveDecode(stepId, modelId, settings) {
3654
- const def = require_default_detection_model.getStepDefinition(stepId);
3691
+ const def = require_custom_model_catalog.getStepDefinition(stepId);
3655
3692
  const modelEntry = def.models.find((m) => m.id === modelId) ?? this.opts.resolveCustomModel?.(stepId, modelId);
3656
3693
  if (!modelEntry) return null;
3657
3694
  return resolvePoolDecodeSettings({
@@ -3696,7 +3733,7 @@ var EngineFactory = class {
3696
3733
  */
3697
3734
  function buildPoolModelConfigForStep(inputs) {
3698
3735
  const { stepId, modelId, poolRuntime, modelsDir } = inputs;
3699
- const def = require_default_detection_model.getStepDefinition(stepId);
3736
+ const def = require_custom_model_catalog.getStepDefinition(stepId);
3700
3737
  const resolvedEntry = def.models.find((m) => m.id === modelId) ?? inputs.resolveCustomModel?.(stepId, modelId);
3701
3738
  if (!resolvedEntry) throw new Error(`Model "${modelId}" not found in step "${stepId}" catalog (static or custom registry)`);
3702
3739
  const modelEntry = inputs.entryForPool?.(stepId, resolvedEntry) ?? resolvedEntry;
@@ -3727,8 +3764,9 @@ function buildPoolModelConfigForStep(inputs) {
3727
3764
  preprocessMode: modelEntry.preprocessMode ?? "letterbox",
3728
3765
  inputNormalization: modelEntry.inputNormalization,
3729
3766
  outputProbabilities: modelEntry.outputProbabilities,
3767
+ ...modelEntry.gpuInferencePrecision !== void 0 ? { gpuInferencePrecision: modelEntry.gpuInferencePrecision } : {},
3730
3768
  postprocessor: resolveEffectivePostprocessorForEntry(def, modelEntry),
3731
- confidence: resolvePoolConfidenceFloor(stepId, require_default_detection_model.resolveModelDefaultConfidence(def, modelEntry)),
3769
+ confidence: resolvePoolConfidenceFloor(stepId, require_custom_model_catalog.resolveModelDefaultConfidence(def, modelEntry)),
3732
3770
  nmsIouThreshold: resolvePoolDecodeSettings({
3733
3771
  def,
3734
3772
  modelEntry,
@@ -6586,7 +6624,7 @@ function linkedLabelsFor(supplies, rawClass, macroClass, modelId) {
6586
6624
  if (require_dist.LABEL_SUPPLY_MACRO[supply.stepId] !== macroClass) continue;
6587
6625
  const effect = supply.labelToEffect[rawClass];
6588
6626
  if (effect === void 0 || effect === macroClass) continue;
6589
- const tier = require_default_detection_model.getStepDefinition(supply.stepId).labelTier;
6627
+ const tier = require_custom_model_catalog.getStepDefinition(supply.stepId).labelTier;
6590
6628
  out.push({
6591
6629
  label: effect,
6592
6630
  score: 0,
@@ -7182,7 +7220,15 @@ var PipelineExecutor = class {
7182
7220
  if (plane === "frame" && child.definition.inputClasses !== null) continue;
7183
7221
  if (!this.matchesInputClasses(parentDetection.macroClass, child.inputClasses)) continue;
7184
7222
  const minParentScore = child.settings?.minParentScore ?? child.definition?.defaultMinParentScore;
7185
- if (typeof minParentScore === "number" && parentDetection.score < minParentScore) continue;
7223
+ if (typeof minParentScore === "number" && parentDetection.score < minParentScore) {
7224
+ if (child.definition.models.find((m) => m.id === child.modelId)?.faceAlignment === true) this.throttledWarn(`face-embed-score-floor:${child.stepId}:${deviceId}`, 3e4, "face detected but below the embedding score floor — no embedding", {
7225
+ step: child.stepId,
7226
+ model: child.modelId,
7227
+ faceScore: parentDetection.score,
7228
+ minParentScore
7229
+ }, deviceId);
7230
+ continue;
7231
+ }
7186
7232
  if (isBboxDegenerate(parentDetection.bbox)) continue;
7187
7233
  try {
7188
7234
  const childStart = Date.now();
@@ -7198,7 +7244,7 @@ var PipelineExecutor = class {
7198
7244
  this.warnFaceTooSmall(child, detShortSide, minFaceSize, void 0, deviceId);
7199
7245
  continue;
7200
7246
  }
7201
- const precision = require_default_detection_model.landmarkPrecisionVerdict({
7247
+ const precision = require_custom_model_catalog.landmarkPrecisionVerdict({
7202
7248
  detectionShortSidePx: detShortSide,
7203
7249
  floorPx: numericSetting(child.settings, "minLandmarkFaceSize", 24)
7204
7250
  });
@@ -7391,7 +7437,7 @@ var PipelineExecutor = class {
7391
7437
  * - `minConfidence<Macro>`: number (e.g. `minConfidencePerson: 0.5`)
7392
7438
  */
7393
7439
  macroFilterVerdict(macroClass, score, settings) {
7394
- return require_default_detection_model.macroGateVerdict(macroClass, score, settings);
7440
+ return require_custom_model_catalog.macroGateVerdict(macroClass, score, settings);
7395
7441
  }
7396
7442
  };
7397
7443
  //#endregion
@@ -7469,13 +7515,16 @@ function buildChild(child, parentStepId, getEngine, resolveModel, onMissingVaria
7469
7515
  return buildNode(child, getEngine, resolveModel, onMissingVariant, variant);
7470
7516
  }
7471
7517
  function buildNode(step, getEngine, resolveModel, onMissingVariant, resolved) {
7472
- const definition = require_default_detection_model.getStepDefinition(step.addonId);
7518
+ const definition = require_custom_model_catalog.getStepDefinition(step.addonId);
7473
7519
  const variant = resolved ?? getEngine(step.addonId, step.modelId);
7474
7520
  const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildChild(c, step.addonId, getEngine, resolveModel, onMissingVariant)).filter((c) => c !== null);
7475
7521
  const modelEntry = resolveModelEntry(definition, variant.modelId, resolveModel);
7522
+ const schema = require_custom_model_catalog.getStep(step.addonId).getConfigSchema(modelEntry);
7523
+ const schemaDefaults = collectSchemaDefaults(schema);
7524
+ const operatorSettings = require_dist.applyModelBoundSettings(step.settings, collectModelBoundKeys(schema), variant.modelId);
7476
7525
  const mergedSettings = {
7477
- ...collectSchemaDefaults(step.addonId, modelEntry),
7478
- ...step.settings
7526
+ ...schemaDefaults,
7527
+ ...operatorSettings
7479
7528
  };
7480
7529
  const effectiveClassMap = modelEntry?.classMap ?? definition.classMap;
7481
7530
  return {
@@ -7501,17 +7550,33 @@ function rootSuppliesField(definition, modelEntry) {
7501
7550
  return supplies.length > 0 ? { rootSupplies: supplies } : {};
7502
7551
  }
7503
7552
  /**
7504
- * Walk the step's declared `getConfigSchema()` and collect every field
7505
- * with a primitive `default` value into a plain record. Group fields
7506
- * are flattened — a nested `{ type: 'group', fields: [...] }` is
7507
- * entered recursively. Fields without a declared default are skipped.
7553
+ * Collect every field of a step's `getConfigSchema(model)` with a primitive
7554
+ * `default` value into a plain record. Group fields are flattened — a nested
7555
+ * `{ type: 'group', fields: [...] }` is entered recursively. Fields without a
7556
+ * declared default are skipped.
7508
7557
  */
7509
- function collectSchemaDefaults(stepId, model) {
7510
- const schema = require_default_detection_model.getStep(stepId).getConfigSchema(model);
7558
+ function collectSchemaDefaults(schema) {
7511
7559
  const out = {};
7512
7560
  walkFieldsForDefaults(schema, out);
7513
7561
  return out;
7514
7562
  }
7563
+ /** The keys of every `bindsToModel` field of a schema, groups flattened (D738). */
7564
+ function collectModelBoundKeys(fields) {
7565
+ return fields.flatMap((field) => {
7566
+ if (field.type === "group") return collectModelBoundKeys(field.fields);
7567
+ return "key" in field && "bindsToModel" in field && field.bindsToModel === true ? [field.key] : [];
7568
+ });
7569
+ }
7570
+ /**
7571
+ * The operator settings of `stepId` as the model that RUNS sees them (D738):
7572
+ * a model-bound value made for another model is dropped and binding keys are
7573
+ * stripped. For a settings layer merged AFTER the tree is built (the
7574
+ * executor's per-device store, `applyDeviceOverridesToTree`), so it obeys the
7575
+ * same binding as the layers `buildNode` merges.
7576
+ */
7577
+ function resolveOperatorSettingsForModel(stepId, settings, runningModelId) {
7578
+ return require_dist.applyModelBoundSettings(settings, collectModelBoundKeys(require_custom_model_catalog.getStep(stepId).getConfigSchema()), runningModelId) ?? {};
7579
+ }
7515
7580
  function walkFieldsForDefaults(fields, out) {
7516
7581
  for (const field of fields) {
7517
7582
  if ("type" in field && field.type === "group" && "fields" in field) {
@@ -7564,7 +7629,7 @@ function walkFieldsForDefaults(fields, out) {
7564
7629
  */
7565
7630
  var defaultLookup = (stepId) => {
7566
7631
  try {
7567
- return require_default_detection_model.getStepDefinition(stepId);
7632
+ return require_custom_model_catalog.getStepDefinition(stepId);
7568
7633
  } catch {
7569
7634
  return null;
7570
7635
  }
@@ -7613,7 +7678,7 @@ function collectSubstitutions(steps, format) {
7613
7678
  for (const step of steps) {
7614
7679
  const chosen = step.modelId;
7615
7680
  if (chosen != null) {
7616
- const running = require_default_detection_model.resolveModelForFormat(step.addonId, chosen, format);
7681
+ const running = require_custom_model_catalog.resolveModelForFormat(step.addonId, chosen, format);
7617
7682
  if (running !== chosen) result.push({
7618
7683
  addonId: step.addonId,
7619
7684
  chosen,
@@ -7641,7 +7706,7 @@ function collectSubstitutions(steps, format) {
7641
7706
  * black-box test. Unknown/custom addonIds (no registered `StepDefinition`)
7642
7707
  * are skipped, never thrown.
7643
7708
  */
7644
- function collectZeroBuildIssues(steps, format, getStepDef = require_default_detection_model.getStepDefinition) {
7709
+ function collectZeroBuildIssues(steps, format, getStepDef = require_custom_model_catalog.getStepDefinition) {
7645
7710
  const result = [];
7646
7711
  for (const step of steps) {
7647
7712
  let def;
@@ -7667,7 +7732,7 @@ function collectZeroBuildIssues(steps, format, getStepDef = require_default_dete
7667
7732
  * tests can exercise the unknown-addon branch with a fabricated resolver
7668
7733
  * without `vi.mock`.
7669
7734
  */
7670
- function collectUnknownAddonIssues(steps, getStepDef = require_default_detection_model.getStepDefinition) {
7735
+ function collectUnknownAddonIssues(steps, getStepDef = require_custom_model_catalog.getStepDefinition) {
7671
7736
  const result = [];
7672
7737
  for (const step of steps) {
7673
7738
  try {
@@ -7717,7 +7782,7 @@ function resolveInputSteps(steps, format, engine, clusterModels, clusterSettings
7717
7782
  for (const s of steps) {
7718
7783
  let def;
7719
7784
  try {
7720
- def = require_default_detection_model.getStepDefinition(s.addonId);
7785
+ def = require_custom_model_catalog.getStepDefinition(s.addonId);
7721
7786
  } catch {
7722
7787
  unknownAddonIds.push(s.addonId);
7723
7788
  continue;
@@ -7752,7 +7817,7 @@ function resolveInputSteps(steps, format, engine, clusterModels, clusterSettings
7752
7817
  }
7753
7818
  }
7754
7819
  const chosenModelId = s.modelId ?? null;
7755
- const runningModelId = chosenModelId === null && engine !== void 0 && s.addonId === "object-detection" ? require_default_detection_model.resolveDefaultDetectionModel(engine.backend, engine.device, format) : require_default_detection_model.resolveModelForFormat(s.addonId, chosenModelId, format);
7820
+ const runningModelId = chosenModelId === null && engine !== void 0 && s.addonId === "object-detection" ? require_custom_model_catalog.resolveDefaultDetectionModel(engine.backend, engine.device, format) : require_custom_model_catalog.resolveModelForFormat(s.addonId, chosenModelId, format);
7756
7821
  if (chosenModelId !== null && runningModelId !== chosenModelId) substitutions.push({
7757
7822
  addonId: s.addonId,
7758
7823
  chosen: chosenModelId,
@@ -8185,7 +8250,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8185
8250
  * paths don't issue a cap round-trip on every call. Empty map = no provider
8186
8251
  * (or a query failure) → behaviour identical to the static-catalog-only path.
8187
8252
  */
8188
- customModels = new require_default_detection_model.CustomModelCatalog({ warn: (message, extras) => this.log.warn(message, extras) });
8253
+ customModels = new require_custom_model_catalog.CustomModelCatalog({ warn: (message, extras) => this.log.warn(message, extras) });
8189
8254
  /**
8190
8255
  * SYNC custom-model lookup handed to every live {@link EngineFactory} so
8191
8256
  * `buildPoolModelConfigForStep` can resolve an operator-registered model at
@@ -8323,7 +8388,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8323
8388
  listGuardedPools() {
8324
8389
  const pools = [];
8325
8390
  if (this.engineFactory) pools.push({
8326
- key: `default:${deviceKeyOf(this.currentEngine)}`,
8391
+ key: `default:${require_custom_model_catalog.deviceKeyOf(this.currentEngine)}`,
8327
8392
  factory: this.engineFactory
8328
8393
  });
8329
8394
  for (const [deviceKey, factory] of this.factoriesByDevice) pools.push({
@@ -8585,7 +8650,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8585
8650
  } catch {}
8586
8651
  const devices = require_dist.enumerateInferenceDevices(envToHardwareInfo(runtimeEnvFromProcess(hardware ? toProbedHardware(hardware) : null)));
8587
8652
  const top = devices.find((d) => d.available) ?? devices[0];
8588
- this.currentEngine = top ? resolveDeviceEngine(top.key) : ONNX_FLOOR;
8653
+ this.currentEngine = top ? require_custom_model_catalog.resolveDeviceEngine(top.key) : ONNX_FLOOR;
8589
8654
  this.log.info("Derived node-default engine (local kernel)", { meta: {
8590
8655
  deviceKey: top?.key ?? "onnx:cpu(floor)",
8591
8656
  backend: this.currentEngine.backend,
@@ -8844,7 +8909,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8844
8909
  * first, then the custom registry. Returns undefined if neither has it.
8845
8910
  */
8846
8911
  async resolveModelEntry(addonId, modelId) {
8847
- const fromCatalog = require_default_detection_model.getStepDefinition(addonId).models.find((m) => m.id === modelId);
8912
+ const fromCatalog = require_custom_model_catalog.getStepDefinition(addonId).models.find((m) => m.id === modelId);
8848
8913
  if (fromCatalog) return fromCatalog;
8849
8914
  return (await this.getCustomModels()).get(addonId)?.find((m) => m.id === modelId);
8850
8915
  }
@@ -8909,7 +8974,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8909
8974
  };
8910
8975
  }
8911
8976
  async getDefaultSteps(engine) {
8912
- const detectionModelId = require_default_detection_model.resolveDefaultDetectionModel(engine.backend, engine.device ?? null, engine.format);
8977
+ const detectionModelId = require_custom_model_catalog.resolveDefaultDetectionModel(engine.backend, engine.device ?? null, engine.format);
8913
8978
  return buildDefaultStepTree(engine.format, detectionModelId);
8914
8979
  }
8915
8980
  /**
@@ -8940,7 +9005,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8940
9005
  /** Pure recursive resolver — builds the resolved step tree without touching `modelSubstitutions`. */
8941
9006
  resolveStepModelTree(steps, format) {
8942
9007
  return steps.map((step) => {
8943
- const resolved = require_default_detection_model.resolveModelForFormat(step.addonId, step.modelId ?? null, format);
9008
+ const resolved = require_custom_model_catalog.resolveModelForFormat(step.addonId, step.modelId ?? null, format);
8944
9009
  const children = step.children?.length ? this.resolveStepModelTree([...step.children], format) : step.children;
8945
9010
  return resolved === step.modelId && children === step.children ? step : {
8946
9011
  ...step,
@@ -8967,7 +9032,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
8967
9032
  */
8968
9033
  async getGlobalSteps() {
8969
9034
  if (this.currentSteps) return this.currentSteps;
8970
- const detectionModelId = require_default_detection_model.resolveDefaultDetectionModel(this.currentEngine.backend, this.currentEngine.device ?? null, this.currentEngine.format);
9035
+ const detectionModelId = require_custom_model_catalog.resolveDefaultDetectionModel(this.currentEngine.backend, this.currentEngine.device ?? null, this.currentEngine.format);
8971
9036
  const defaults = buildDefaultStepTree(this.currentEngine.format, detectionModelId);
8972
9037
  if (defaults.length === 0) return null;
8973
9038
  this.currentSteps = this.resolveStepModels(defaults);
@@ -9013,7 +9078,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9013
9078
  let format = this.currentEngine.format;
9014
9079
  try {
9015
9080
  if (input.deviceKey !== void 0) try {
9016
- format = resolveDeviceEngine(input.deviceKey).format;
9081
+ format = require_custom_model_catalog.resolveDeviceEngine(input.deviceKey).format;
9017
9082
  } catch (err) {
9018
9083
  return {
9019
9084
  ok: false,
@@ -9102,7 +9167,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9102
9167
  for (const step of nodes) {
9103
9168
  if (!step.enabled) continue;
9104
9169
  try {
9105
- if (require_default_detection_model.getStepDefinition(step.addonId).slot === "audio-classifier") continue;
9170
+ if (require_custom_model_catalog.getStepDefinition(step.addonId).slot === "audio-classifier") continue;
9106
9171
  } catch {
9107
9172
  continue;
9108
9173
  }
@@ -9122,7 +9187,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9122
9187
  async getCapabilities(_forceRefresh) {
9123
9188
  const agentId = (this.addonCtx?.kernel?.cluster?.broker)?.nodeID ?? node_os.hostname();
9124
9189
  const agentName = agentId;
9125
- const addons = require_default_detection_model.ALL_PIPELINE_STEPS.map((s) => ({
9190
+ const addons = require_custom_model_catalog.ALL_PIPELINE_STEPS.map((s) => ({
9126
9191
  id: s.definition.id,
9127
9192
  name: s.definition.name,
9128
9193
  models: s.definition.models.filter((m) => m.legacy !== true).map((m) => {
@@ -9524,7 +9589,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9524
9589
  executing: input.plane === "frame" ? collectFramePlaneSteps(benchmarkSteps, isDetailPlaneStep) : enabledSteps,
9525
9590
  requestedDeviceKey: input.deviceKey,
9526
9591
  dispatchDeviceKey,
9527
- format: dispatchDeviceKey ? resolveDeviceEngine(dispatchDeviceKey).format : this.currentEngine.format
9592
+ format: dispatchDeviceKey ? require_custom_model_catalog.resolveDeviceEngine(dispatchDeviceKey).format : this.currentEngine.format
9528
9593
  });
9529
9594
  if (verdict.kind === "refused") {
9530
9595
  this.log.warn("replay refused — the node cannot run exactly what was pinned", {
@@ -9556,13 +9621,13 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9556
9621
  logger: this.log
9557
9622
  });
9558
9623
  this.executor = executor;
9559
- const dispatchEngine = dispatchDeviceKey ? resolveDeviceEngine(dispatchDeviceKey) : runEngine;
9624
+ const dispatchEngine = dispatchDeviceKey ? require_custom_model_catalog.resolveDeviceEngine(dispatchDeviceKey) : runEngine;
9560
9625
  const dispatchFactory = dispatchDeviceKey ? await this.resolveDeviceFactory(dispatchDeviceKey) : this.engineFactory;
9561
9626
  const needed = enabledSteps.filter((s) => dispatchFactory.needsPoolUpdate(s));
9562
9627
  let runSteps = benchmarkSteps;
9563
9628
  const loadPolicy = dispatchLoadPolicyOf(input);
9564
9629
  if (needed.length > 0) {
9565
- const dispatchDeviceKeyLabel = deviceKeyOf(dispatchEngine);
9630
+ const dispatchDeviceKeyLabel = require_custom_model_catalog.deviceKeyOf(dispatchEngine);
9566
9631
  const toIssue = needed.filter((s) => this.loadGovernor.check(dispatchFactory, dispatchDeviceKeyLabel, [stepModelKey(s)]).kind === "go");
9567
9632
  if (toIssue.length > 0) this.log.info("Benchmark: models to load", { meta: {
9568
9633
  count: toIssue.length,
@@ -9588,7 +9653,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9588
9653
  }));
9589
9654
  if (notWarm.length > 0) {
9590
9655
  if (loadPolicy === "all-or-nothing") throw new DispatchStepsNotLoadedError(notWarm);
9591
- const dispatchDeviceKeyLabel = deviceKeyOf(dispatchEngine);
9656
+ const dispatchDeviceKeyLabel = require_custom_model_catalog.deviceKeyOf(dispatchEngine);
9592
9657
  for (const failure of notWarm) {
9593
9658
  const model = stepModelKey(failure.step);
9594
9659
  this.reportDispatchLoadLoss({
@@ -9618,7 +9683,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9618
9683
  let frameViewResolver;
9619
9684
  let rootInputViewProvider;
9620
9685
  if (runtimeFrameRef) {
9621
- frameViewResolver = createRootFrameViewResolver(require_default_detection_model.localFrameRegistry, runtimeFrameRef);
9686
+ frameViewResolver = createRootFrameViewResolver(require_custom_model_catalog.localFrameRegistry, runtimeFrameRef);
9622
9687
  rootInputViewProvider = async (root, crop) => {
9623
9688
  const view = await frameViewResolver(root, crop ? {
9624
9689
  left: crop[0],
@@ -9804,7 +9869,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9804
9869
  device: this.currentEngine.device ?? null
9805
9870
  };
9806
9871
  const nodeEngineLabel = `${nodeEngine.backend}/${nodeEngine.device ?? "default"} (${nodeFormat})`;
9807
- const deviceEngine = deviceKey ? resolveDeviceEngine(deviceKey) : void 0;
9872
+ const deviceEngine = deviceKey ? require_custom_model_catalog.resolveDeviceEngine(deviceKey) : void 0;
9808
9873
  if (deviceKey === void 0 || deviceEngine === void 0) {
9809
9874
  const refusals = [];
9810
9875
  const steps = this.inputStepsToPipelineSteps(args.steps, nodeFormat, nodeEngine, refusals);
@@ -9832,7 +9897,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9832
9897
  steps
9833
9898
  };
9834
9899
  }
9835
- const pruneResult = pruneUnrunnableDetailSteps(steps, isDetailPlaneStep, (subtree) => !require_default_detection_model.buildSubtreeCanRun(subtree, this.mergedStepDef)(deviceFormat));
9900
+ const pruneResult = pruneUnrunnableDetailSteps(steps, isDetailPlaneStep, (subtree) => !require_custom_model_catalog.buildSubtreeCanRun(subtree, this.mergedStepDef)(deviceFormat));
9836
9901
  if (pruneResult.prunedAddonIds.length > 0) {
9837
9902
  const prunedList = pruneResult.prunedAddonIds.join(",");
9838
9903
  this.logLiveDispatchIssueOnce(`detail-defer:${deviceKey}:${deviceFormat}:${prunedList}`, () => this.log.info("Detail steps have no model build for the dispatch device format — deferred to the detail-plane device jump", {
@@ -9957,7 +10022,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
9957
10022
  async noteCoralPlacement(steps, factory, format, context) {
9958
10023
  const change = factory.notePlacement(placedModelsOf(steps));
9959
10024
  if (change.kind === "unchanged") return;
9960
- const deviceKey = context.deviceKey ?? deviceKeyOf(this.currentEngine);
10025
+ const deviceKey = context.deviceKey ?? require_custom_model_catalog.deviceKeyOf(this.currentEngine);
9961
10026
  const tags = context.deviceId !== void 0 ? { tags: { deviceId: context.deviceId } } : {};
9962
10027
  const placed = change.placed.map((p) => `${p.stepId}/${p.modelId}`);
9963
10028
  if (change.to.kind === "set") this.log.info("Coral pool loads a co-compiled set — the models placed on it share the parameter cache", {
@@ -10018,7 +10083,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10018
10083
  const needed = this.stepsNeedingLoad(steps, factory);
10019
10084
  if (needed.length === 0) return;
10020
10085
  const pool = factory ?? this.nullPoolKey;
10021
- const deviceKey = context.deviceKey ?? deviceKeyOf(this.currentEngine);
10086
+ const deviceKey = context.deviceKey ?? require_custom_model_catalog.deviceKeyOf(this.currentEngine);
10022
10087
  const models = needed.map(stepModelKey);
10023
10088
  const refusal = this.loadRefusal(pool, deviceKey, models);
10024
10089
  if (refusal !== null) {
@@ -10300,7 +10365,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10300
10365
  plane: void 0
10301
10366
  });
10302
10367
  const dispatchDeviceKey = dispatchResolution.deviceKey;
10303
- const resolveFormat = dispatchDeviceKey ? resolveDeviceEngine(dispatchDeviceKey).format : this.currentEngine.format;
10368
+ const resolveFormat = dispatchDeviceKey ? require_custom_model_catalog.resolveDeviceEngine(dispatchDeviceKey).format : this.currentEngine.format;
10304
10369
  const benchmarkSteps = dispatchResolution.steps;
10305
10370
  const enabledSteps = flattenEnabledVideoSteps(benchmarkSteps);
10306
10371
  if (enabledSteps.length === 0) throw new Error("runPipelineBatch: no enabled steps");
@@ -10323,7 +10388,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10323
10388
  await this.ensureEngineFactory();
10324
10389
  const factory = dispatchDeviceKey ? await this.resolveDeviceFactory(dispatchDeviceKey) : this.engineFactory;
10325
10390
  if (!factory) throw new Error("runPipelineBatch: factory not initialised");
10326
- if (enabledSteps.filter((s) => factory.needsPoolUpdate(s)).length > 0) await this.ensureModelsForSteps(benchmarkSteps, factory, resolveFormat, { deviceKey: dispatchDeviceKey ?? deviceKeyOf(this.currentEngine) });
10391
+ if (enabledSteps.filter((s) => factory.needsPoolUpdate(s)).length > 0) await this.ensureModelsForSteps(benchmarkSteps, factory, resolveFormat, { deviceKey: dispatchDeviceKey ?? require_custom_model_catalog.deviceKeyOf(this.currentEngine) });
10327
10392
  const canFastPath = singleRoot && allRaw && uniformDims && factory.supportsBatch();
10328
10393
  this.log.info("runPipelineBatch path decision", { meta: {
10329
10394
  phase: "batch",
@@ -10556,7 +10621,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10556
10621
  * pool that ran the work (D646).
10557
10622
  */
10558
10623
  async getEffectiveTuning(input = {}) {
10559
- const p = resolvePoolProvisioning(input.deviceKey !== void 0 ? resolveDeviceEngine(input.deviceKey) : this.currentEngine, this.executorOptions.provisioning);
10624
+ const p = resolvePoolProvisioning(input.deviceKey !== void 0 ? require_custom_model_catalog.resolveDeviceEngine(input.deviceKey) : this.currentEngine, this.executorOptions.provisioning);
10560
10625
  return {
10561
10626
  deviceKey: input.deviceKey ?? null,
10562
10627
  runtime: p.runtime,
@@ -10573,7 +10638,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10573
10638
  * If global steps exist, initializes with them. Otherwise, creates an empty pool.
10574
10639
  */
10575
10640
  async ensureEngineFactory() {
10576
- const defaultDeviceKey = deviceKeyOf(this.currentEngine);
10641
+ const defaultDeviceKey = require_custom_model_catalog.deviceKeyOf(this.currentEngine);
10577
10642
  this.refuseIfDeviceUnusable(defaultDeviceKey);
10578
10643
  if (this.engineFactory) {
10579
10644
  if (this.engineFactory.isReady()) return;
@@ -10773,7 +10838,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10773
10838
  async getInferenceDeviceHealth() {
10774
10839
  const byKey = /* @__PURE__ */ new Map();
10775
10840
  for (const entry of this.deviceLiveness.unhealthy()) byKey.set(entry.deviceKey, entry);
10776
- const live = [...this.factoriesByDevice, ...this.engineFactory ? [[deviceKeyOf(this.currentEngine), this.engineFactory]] : []];
10841
+ const live = [...this.factoriesByDevice, ...this.engineFactory ? [[require_custom_model_catalog.deviceKeyOf(this.currentEngine), this.engineFactory]] : []];
10777
10842
  for (const [deviceKey, factory] of live) {
10778
10843
  if (factory.isReady() || byKey.has(deviceKey)) continue;
10779
10844
  byKey.set(deviceKey, {
@@ -10809,7 +10874,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10809
10874
  return { rearmed };
10810
10875
  }
10811
10876
  async resolveDeviceFactory(deviceKey) {
10812
- const engine = resolveDeviceEngine(deviceKey);
10877
+ const engine = require_custom_model_catalog.resolveDeviceEngine(deviceKey);
10813
10878
  if (enginesEqual(engine, this.currentEngine)) {
10814
10879
  await this.ensureEngineFactory();
10815
10880
  return this.engineFactory;
@@ -10993,7 +11058,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
10993
11058
  });
10994
11059
  }
10995
11060
  for (const [deviceKey, factory] of this.factoriesByDevice) {
10996
- const eng = resolveDeviceEngine(deviceKey);
11061
+ const eng = require_custom_model_catalog.resolveDeviceEngine(deviceKey);
10997
11062
  const loaded = factory.listLoaded();
10998
11063
  out.push({
10999
11064
  engineKey: `${eng.runtime}/${eng.backend}/${eng.device ?? "default"} [${deviceKey}]`,
@@ -11176,9 +11241,9 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
11176
11241
  function buildSchemaSlots(formats, modelsDir, customByStep) {
11177
11242
  const slotMap = /* @__PURE__ */ new Map();
11178
11243
  const formatList = [...formats];
11179
- for (const pipelineStep of require_default_detection_model.ALL_PIPELINE_STEPS) {
11244
+ for (const pipelineStep of require_custom_model_catalog.ALL_PIPELINE_STEPS) {
11180
11245
  const step = pipelineStep.definition;
11181
- const availableModels = require_default_detection_model.mergeCustomModels(step.models, customByStep?.get(step.id) ?? []).filter((m) => m.legacy !== true && formatList.some((f) => m.formats[f]));
11246
+ const availableModels = require_custom_model_catalog.mergeCustomModels(step.models, customByStep?.get(step.id) ?? []).filter((m) => m.legacy !== true && formatList.some((f) => m.formats[f]));
11182
11247
  if (availableModels.length === 0) continue;
11183
11248
  const slot = step.slot;
11184
11249
  if (!slotMap.has(slot)) slotMap.set(slot, []);
@@ -11187,8 +11252,10 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
11187
11252
  def: step,
11188
11253
  configSchema: pipelineStep.getConfigSchema(),
11189
11254
  models: availableModels,
11190
- customModelIds: customIds
11255
+ customModelIds: customIds,
11256
+ schemaForModel: (entry) => pipelineStep.getConfigSchema(entry)
11191
11257
  });
11258
+ const configSchemaWithRoots = withRootSuppliedLabelDefaults(step.id, configSchema, require_custom_model_catalog.mergeCustomModels(require_custom_model_catalog.getStepDefinition("object-detection").models, customByStep?.get("object-detection") ?? []));
11192
11259
  slotMap.get(slot).push({
11193
11260
  id: step.id,
11194
11261
  name: step.name,
@@ -11206,7 +11273,7 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
11206
11273
  ...m.group ? { group: m.group } : {},
11207
11274
  ...m.legacy !== void 0 ? { legacy: m.legacy } : {},
11208
11275
  provider: m.provider ?? "camstack",
11209
- defaultConfidence: require_default_detection_model.resolveModelDefaultConfidence(step, m),
11276
+ defaultConfidence: require_custom_model_catalog.resolveModelDefaultConfidence(step, m),
11210
11277
  ...modelSuppliesField(step, m)
11211
11278
  })),
11212
11279
  defaultModelId: step.defaultModelId,
@@ -11215,7 +11282,7 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
11215
11282
  ...step.backfillIntoExistingOverrides !== void 0 ? { backfillIntoExistingOverrides: step.backfillIntoExistingOverrides } : {},
11216
11283
  defaultConfidence: step.defaultConfidence,
11217
11284
  ...step.group ? { group: step.group } : {},
11218
- ...configSchema.length > 0 ? { configSchema: [...configSchema] } : {}
11285
+ ...configSchemaWithRoots.length > 0 ? { configSchema: configSchemaWithRoots } : {}
11219
11286
  });
11220
11287
  }
11221
11288
  const slotPriority = {
@@ -11259,20 +11326,15 @@ function resolveChildSlots(slot) {
11259
11326
  }
11260
11327
  }
11261
11328
  /**
11262
- * V2 default: lightweight pipeline with minimal enabled steps.
11263
- *
11264
- * Only object detection (yolov9t, 4-8 MB) + face detection (scrfd, 1.7 MB) enabled.
11265
- * All other steps are present in the tree but DISABLED — user enables via UI.
11266
- * Total model footprint: ~10 MB (CoreML), ~11 MB (ONNX)
11267
- *
11268
- * Why:
11269
- * - Fast startup (seconds, not minutes of model downloads)
11270
- * - Covers 90% of NVR use cases (person/vehicle/animal detection + face detection)
11271
- * - Users opt-in to heavy classifiers (vehicle type, plate OCR, bird species) when needed
11329
+ * V2 default: the node-default step tree (never persisted — see
11330
+ * `getGlobalSteps`). The core detection + recognition steps are enabled; every
11331
+ * optional step is present with its catalog `enabledByDefault` (the animal and
11332
+ * vehicle classifiers on — their answer comes from the root model when it
11333
+ * declares them, D736 — the bird classifier and segmentation off).
11272
11334
  */
11273
11335
  function buildDefaultStepTree(format, objectDetectionModelId) {
11274
11336
  const makeStep = (stepId, children, opts) => {
11275
- const def = require_default_detection_model.getStepDefinition(stepId);
11337
+ const def = require_custom_model_catalog.getStepDefinition(stepId);
11276
11338
  if (!def.models.some((m) => m.formats[format])) return null;
11277
11339
  return {
11278
11340
  addonId: def.id,
@@ -11281,7 +11343,7 @@ function buildDefaultStepTree(format, objectDetectionModelId) {
11281
11343
  inputClasses: def.inputClasses ?? [],
11282
11344
  outputClasses: def.outputClasses,
11283
11345
  enabled: opts?.enabled ?? true,
11284
- modelId: opts?.modelId ?? require_default_detection_model.getDefaultModelForFormat(stepId, format),
11346
+ modelId: opts?.modelId ?? require_custom_model_catalog.getDefaultModelForFormat(stepId, format),
11285
11347
  children,
11286
11348
  ...def.group ? { group: def.group } : {}
11287
11349
  };
@@ -11289,14 +11351,17 @@ function buildDefaultStepTree(format, objectDetectionModelId) {
11289
11351
  const faceEmbedding = makeStep("face-embedding", []);
11290
11352
  const faceDetection = makeStep("face-detection", faceEmbedding ? [faceEmbedding] : []);
11291
11353
  const plateOcr = makeStep("plate-ocr", []);
11354
+ const plateDetection = makeStep("plate-detection", plateOcr ? [plateOcr] : []);
11355
+ const clipEmbedding = makeStep("clip-embedding", []);
11356
+ const byCatalogDefault = (stepId) => ({ enabled: require_custom_model_catalog.getStepDefinition(stepId).enabledByDefault ?? true });
11292
11357
  const root = makeStep("object-detection", [
11293
11358
  faceDetection,
11294
- makeStep("plate-detection", plateOcr ? [plateOcr] : []),
11295
- makeStep("clip-embedding", []),
11296
- makeStep("animal-classifier", [], { enabled: false }),
11297
- makeStep("bird-classifier", [], { enabled: false }),
11298
- makeStep("vehicle-classifier", [], { enabled: false }),
11299
- makeStep("segmentation", [], { enabled: false })
11359
+ plateDetection,
11360
+ clipEmbedding,
11361
+ makeStep("animal-classifier", [], byCatalogDefault("animal-classifier")),
11362
+ makeStep("bird-classifier", [], byCatalogDefault("bird-classifier")),
11363
+ makeStep("vehicle-classifier", [], byCatalogDefault("vehicle-classifier")),
11364
+ makeStep("segmentation", [], byCatalogDefault("segmentation"))
11300
11365
  ].filter((s) => s !== null), objectDetectionModelId !== void 0 ? { modelId: objectDetectionModelId } : void 0);
11301
11366
  const audioStep = makeStep("audio-classifier", []);
11302
11367
  const steps = [];
@@ -11338,7 +11403,7 @@ function flattenSteps(steps) {
11338
11403
  */
11339
11404
  function isDetailPlaneStep(addonId) {
11340
11405
  try {
11341
- return require_default_detection_model.getStepDefinition(addonId).inputClasses !== null;
11406
+ return require_custom_model_catalog.getStepDefinition(addonId).inputClasses !== null;
11342
11407
  } catch {
11343
11408
  return false;
11344
11409
  }
@@ -11377,7 +11442,7 @@ function stepsSurvivingLoad(steps, failures, policy) {
11377
11442
  */
11378
11443
  function availableFormatsForStep(addonId) {
11379
11444
  try {
11380
- const def = require_default_detection_model.getStepDefinition(addonId);
11445
+ const def = require_custom_model_catalog.getStepDefinition(addonId);
11381
11446
  const formats = /* @__PURE__ */ new Set();
11382
11447
  for (const model of def.models) for (const format of Object.keys(model.formats)) formats.add(format);
11383
11448
  return Array.from(formats).toSorted();
@@ -11389,14 +11454,15 @@ function availableFormatsForStep(addonId) {
11389
11454
  * Return a shallow-cloned executable tree with `rootStepId`'s `settings`
11390
11455
  * merged with `overrides` (per-device values win). Non-matching root steps
11391
11456
  * pass through unchanged. Used by `runFrame` to apply per-device detection
11392
- * settings without rebuilding the tree per frame.
11457
+ * settings without rebuilding the tree per frame. A model-bound value (D738)
11458
+ * applies only while the model it was made for is the one the root RUNS.
11393
11459
  */
11394
11460
  function applyDeviceOverridesToTree(tree, rootStepId, overrides) {
11395
11461
  return { roots: tree.roots.map((root) => root.stepId === rootStepId ? {
11396
11462
  ...root,
11397
11463
  settings: {
11398
11464
  ...root.settings,
11399
- ...overrides
11465
+ ...resolveOperatorSettingsForModel(rootStepId, overrides, root.modelId)
11400
11466
  }
11401
11467
  } : root) };
11402
11468
  }
@@ -11946,7 +12012,7 @@ var DetectionPipelineAddon = class extends require_dist.BaseAddon {
11946
12012
  }).catch(() => {});
11947
12013
  }
11948
12014
  getModelCatalog() {
11949
- return require_default_detection_model.ALL_STEPS.flatMap((s) => s.models.filter((m) => m.legacy !== true));
12015
+ return require_custom_model_catalog.ALL_STEPS.flatMap((s) => s.models.filter((m) => m.legacy !== true));
11950
12016
  }
11951
12017
  /**
11952
12018
  * Proactively install the OpenVINO Python package when Intel hardware
@@ -12032,9 +12098,9 @@ var DetectionPipelineAddon = class extends require_dist.BaseAddon {
12032
12098
  }
12033
12099
  };
12034
12100
  //#endregion
12035
- exports.ALL_STEPS = require_default_detection_model.ALL_STEPS;
12101
+ exports.ALL_STEPS = require_custom_model_catalog.ALL_STEPS;
12036
12102
  exports.DetectionPipelineProvider = DetectionPipelineProvider;
12037
12103
  exports.default = DetectionPipelineAddon;
12038
- exports.getDefaultModelForFormat = require_default_detection_model.getDefaultModelForFormat;
12039
- exports.getStepDefinition = require_default_detection_model.getStepDefinition;
12104
+ exports.getDefaultModelForFormat = require_custom_model_catalog.getDefaultModelForFormat;
12105
+ exports.getStepDefinition = require_custom_model_catalog.getStepDefinition;
12040
12106
  exports.shouldInstallOpenvino = shouldInstallOpenvino;