@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
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $n as union, Cn as errMsg, Dt as linkedLabelStepId, G as YAMNET_TO_MACRO, Ln as nodePin, N as PoolMemoryWatchdog, Nn as hydrateSchema, O as LABEL_SUPPLY_MACRO, Qn as string, Rn as parseJsonUnknown, Tn as BaseAddon, Un as array, Vn as sleep, Vt as pickClusterStepSettings, Wt as pipelineExecutorCapability, Yn as object, Zt as resolveClusterStepModelId, an as runtimeDevices$1, b as DEVICE_BACKEND_TO_FORMAT, d as CLUSTER_MODEL_SCOPED_STEPS, dn as supportedRuntimes$1, dt as detectionPipelineCapability, er as EventCategory, g as DEFAULT_CLUSTER_STEP_SETTINGS, ht as evaluateZoneRules, in as rootSuppliesOf, kn as createEvent, kt as loadContributionCapability, mt as enumerateInferenceDevices, n as APPLE_SA_TO_MACRO, nt as containingParentIndex, on as stepModelRunsOnFormat, ot as defaultDeviceFor$1, tn as resolvePoolMemoryPolicy, wt as hfModelUrl, zt as overlayClusterStepSettings } from "../dist-BsT15i7i.mjs";
3
- import { s as readProcessCost } from "../node-Crsi_8ea.mjs";
4
- import { _ as getStep, a as buildSubtreeCanRun, b as landmarkPrecisionVerdict, c as macroGateVerdict, g as getDefaultModelForFormat, h as ALL_STEPS, i as mergeCustomModels, m as ALL_PIPELINE_STEPS, n as resolveDefaultDetectionModel, r as CustomModelCatalog, u as localFrameRegistry, v as getStepDefinition, x as resolveModelDefaultConfidence, y as resolveModelForFormat } from "../default-detection-model-CDffuH2m.mjs";
2
+ import { At as loadContributionCapability, Bn as parseJsonUnknown, Bt as overlayClusterStepSettings, Dn as BaseAddon, Fn as hydrateSchema, G as YAMNET_TO_MACRO, Gn as array, Gt as pipelineExecutorCapability, Ht as pickClusterStepSettings, J as applyModelBoundSettings, N as PoolMemoryWatchdog, O as LABEL_SUPPLY_MACRO, Ot as linkedLabelStepId, Qt as resolveClusterStepModelId, Tn as errMsg, Tt as hfModelUrl, Un as sleep, Zn as object, cn as stepModelRunsOnFormat, d as CLUSTER_MODEL_SCOPED_STEPS, er as string, ft as detectionPipelineCapability, g as DEFAULT_CLUSTER_STEP_SETTINGS, gt as evaluateZoneRules, ht as enumerateInferenceDevices, jn as createEvent, n as APPLE_SA_TO_MACRO, nr as EventCategory, on as rootSuppliesOf, pn as supportedRuntimes$1, rn as resolvePoolMemoryPolicy, rt as containingParentIndex, sn as runtimeDevices$1, st as defaultDeviceFor$1, tr as union, zn as nodePin } from "../dist-CPhDwlSN.mjs";
3
+ import { s as readProcessCost } from "../node-DYfEOwjW.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-Buehc666.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-1mAUV8S1.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-WPRYnN8c.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";
@@ -2243,6 +2243,7 @@ function describeCommand(cmd) {
2243
2243
  model: typeof modelPath === "string" && modelPath.length > 0 ? path$1.basename(modelPath, path$1.extname(modelPath)) : null
2244
2244
  };
2245
2245
  }
2246
+ /** The wire form of a model config — the keys the Python pool reads. Exported for tests. */
2246
2247
  function serializeModelConfig(config) {
2247
2248
  const result = {
2248
2249
  path: config.path,
@@ -2254,6 +2255,7 @@ function serializeModelConfig(config) {
2254
2255
  if (config.nmsIouThreshold !== void 0) result["nmsIouThreshold"] = config.nmsIouThreshold;
2255
2256
  if (config.inputNormalization !== void 0) result["inputNormalization"] = config.inputNormalization;
2256
2257
  if (config.outputProbabilities !== void 0) result["outputProbabilities"] = config.outputProbabilities;
2258
+ if (config.gpuInferencePrecision !== void 0) result["gpuInferencePrecision"] = config.gpuInferencePrecision;
2257
2259
  if (config.inputWidth !== void 0) result["inputWidth"] = config.inputWidth;
2258
2260
  if (config.inputHeight !== void 0) result["inputHeight"] = config.inputHeight;
2259
2261
  if (config.inputChannels !== void 0) result["inputChannels"] = config.inputChannels;
@@ -2444,25 +2446,43 @@ function collectClassMapDropWarning(def, entry) {
2444
2446
  function toApplicability(acc) {
2445
2447
  const hasInapplicable = Object.keys(acc.inapplicable).length > 0;
2446
2448
  const hasOptions = Object.keys(acc.optionsByModel).length > 0;
2447
- if (!hasInapplicable && !hasOptions) return void 0;
2449
+ const hasDefaults = Object.keys(acc.defaultByModel).length > 0;
2450
+ if (!hasInapplicable && !hasOptions && !hasDefaults) return void 0;
2448
2451
  return {
2449
2452
  ...hasInapplicable ? { inapplicable: acc.inapplicable } : {},
2450
- ...hasOptions ? { optionsByModel: acc.optionsByModel } : {}
2453
+ ...hasOptions ? { optionsByModel: acc.optionsByModel } : {},
2454
+ ...hasDefaults ? { defaultByModel: acc.defaultByModel } : {}
2451
2455
  };
2452
2456
  }
2457
+ /** The `default` of `key` in a schema, groups flattened; `undefined` when absent. */
2458
+ function defaultOfKey(fields, key) {
2459
+ for (const field of fields) {
2460
+ if (field.type === "group") {
2461
+ const nested = defaultOfKey(field.fields, key);
2462
+ if (nested !== void 0) return nested;
2463
+ continue;
2464
+ }
2465
+ if ("key" in field && field.key === key && "default" in field) return field.default;
2466
+ }
2467
+ }
2453
2468
  function isAnnotatable(field) {
2454
2469
  return field.type === "slider" || field.type === "number" || field.type === "multiselect" || field.type === "select" || field.type === "boolean";
2455
2470
  }
2456
2471
  function annotateField(field, inputs) {
2457
2472
  if (!isAnnotatable(field)) return field;
2458
- const { def, models, customModelIds } = inputs;
2473
+ const { def, models, customModelIds, schemaForModel } = inputs;
2459
2474
  const acc = {
2460
2475
  inapplicable: {},
2461
- optionsByModel: {}
2476
+ optionsByModel: {},
2477
+ defaultByModel: {}
2462
2478
  };
2463
2479
  const macroKey = macroOfMinConfidenceKey(field.key);
2464
2480
  for (const entry of models) {
2465
2481
  const postprocessor = resolveEffectivePostprocessorForEntry(def, entry);
2482
+ if (field.bindsToModel === true && schemaForModel !== void 0) {
2483
+ const modelDefault = defaultOfKey(schemaForModel(entry), field.key);
2484
+ if (modelDefault !== void 0 && modelDefault !== field.default) acc.defaultByModel[entry.id] = modelDefault;
2485
+ }
2466
2486
  if (field.key === "nmsIouThreshold" && !postprocessorConsumesNms(postprocessor)) {
2467
2487
  acc.inapplicable[entry.id] = `NMS is fused inside this model's "${postprocessor}" export — the pipeline IoU threshold is not consulted.`;
2468
2488
  continue;
@@ -2511,6 +2531,55 @@ function annotateField(field, inputs) {
2511
2531
  function annotateConfigSchemaForModels(inputs) {
2512
2532
  return inputs.configSchema.map((field) => annotateField(field, inputs));
2513
2533
  }
2534
+ /** The slider that governs a root-supplied fine label (D741) — the step's own threshold. */
2535
+ var SUPPLIED_LABEL_FLOOR_KEY = "minConfidence";
2536
+ /**
2537
+ * D741 — when a ROOT detector supplies a step's fine label (species, vehicle
2538
+ * type), the step's `minConfidence` slider is the floor on the root's
2539
+ * DETECTION score for that label, bound to the root model. So for each root
2540
+ * model that supplies `stepId`'s labels, the slider's default under that model
2541
+ * is the root's `suppliedLabelFloors[stepId]`, or 0 (no floor beyond the macro
2542
+ * floor). Added to `modelApplicability.defaultByModel`, keyed by root model id,
2543
+ * so the editor — which shows the slider under the ROOT's id while the root
2544
+ * supplies the step — shows the floor the runner applies. A step no root
2545
+ * supplies a fine label for is returned untouched.
2546
+ */
2547
+ function withRootSuppliedLabelDefaults(stepId, configSchema, rootModels) {
2548
+ if (!isFineLabelSupplyStep(stepId)) return [...configSchema];
2549
+ const rootDef = getStepDefinition(ROOT_STEP_ID);
2550
+ const defaults = {};
2551
+ for (const root of rootModels) {
2552
+ if (!rootSuppliesOf(root, {
2553
+ labels: rootDef.labels ?? [],
2554
+ ...rootDef.classMap !== void 0 ? { classMap: rootDef.classMap } : {}
2555
+ }).some((s) => s.kind === "label" && s.stepId === stepId)) continue;
2556
+ defaults[root.id] = root.suppliedLabelFloors?.[stepId] ?? 0;
2557
+ }
2558
+ if (Object.keys(defaults).length === 0) return [...configSchema];
2559
+ return configSchema.map((field) => {
2560
+ if (field.type !== "slider" || field.key !== SUPPLIED_LABEL_FLOOR_KEY) return field;
2561
+ return {
2562
+ ...field,
2563
+ modelApplicability: {
2564
+ ...field.modelApplicability,
2565
+ defaultByModel: {
2566
+ ...field.modelApplicability?.defaultByModel,
2567
+ ...defaults
2568
+ }
2569
+ }
2570
+ };
2571
+ });
2572
+ }
2573
+ /** The camera root the supplies are read from. */
2574
+ var ROOT_STEP_ID = "object-detection";
2575
+ /**
2576
+ * A label-supply step whose effect is FINER than its macro (species, vehicle
2577
+ * type). `package-detection` is a label supply too, but its effect IS its
2578
+ * macro: it has no fine label and its threshold is `minConfidencePackage`.
2579
+ */
2580
+ function isFineLabelSupplyStep(stepId) {
2581
+ return Object.keys(LABEL_SUPPLY_MACRO).includes(stepId) && stepId !== "package-detection";
2582
+ }
2514
2583
  /**
2515
2584
  * A persisted settings blob is external data — it survives schema changes,
2516
2585
  * hand edits and migrations. Accept only a finite IoU in the open (0,1)
@@ -2994,38 +3063,6 @@ var PipelineModelManager = class {
2994
3063
  }
2995
3064
  };
2996
3065
  //#endregion
2997
- //#region src/detection-pipeline/engine/resolve-device-engine.ts
2998
- /**
2999
- * Resolve a Phase-1 device key (`<backend>:<device>`, or bare `cpu`) into the
3000
- * {@link PipelineEngineChoice} used to build that device's inference pool.
3001
- * Throws on an unknown backend token so a bad `deviceKey` fails loud rather
3002
- * than silently building a wrong pool. Format comes from the shared
3003
- * {@link DEVICE_BACKEND_TO_FORMAT} SSOT (`@camstack/types`) — no local copy.
3004
- */
3005
- function resolveDeviceEngine(deviceKey) {
3006
- const colon = deviceKey.indexOf(":");
3007
- const backend = colon >= 0 ? deviceKey.slice(0, colon) : deviceKey;
3008
- const device = colon >= 0 ? deviceKey.slice(colon + 1) : deviceKey;
3009
- const format = DEVICE_BACKEND_TO_FORMAT[backend];
3010
- if (format === void 0) throw new Error(`resolveDeviceEngine: unknown backend "${backend}" in deviceKey "${deviceKey}"`);
3011
- return {
3012
- runtime: "python",
3013
- backend,
3014
- format,
3015
- device
3016
- };
3017
- }
3018
- /**
3019
- * The inverse of {@link resolveDeviceEngine}: the `<backend>:<device>` key that
3020
- * names the pool an engine belongs to. Every pool-level log line carries this —
3021
- * without it a default pool logs anonymously and six hours of logs cannot tell
3022
- * "the NPU is unused" from "the NPU IS the anonymous default pool".
3023
- * Falls back to the bare backend when the engine carries no device.
3024
- */
3025
- function deviceKeyOf(engine) {
3026
- return engine.device ? `${engine.backend}:${engine.device}` : engine.backend;
3027
- }
3028
- //#endregion
3029
3066
  //#region src/detection-pipeline/engine/coral-cocompiled-set.ts
3030
3067
  var ROOT_DETECTOR_STEP_ID = "object-detection";
3031
3068
  /** The models a dispatch places on the pool that runs it: every enabled video step. */
@@ -3720,6 +3757,7 @@ function buildPoolModelConfigForStep(inputs) {
3720
3757
  preprocessMode: modelEntry.preprocessMode ?? "letterbox",
3721
3758
  inputNormalization: modelEntry.inputNormalization,
3722
3759
  outputProbabilities: modelEntry.outputProbabilities,
3760
+ ...modelEntry.gpuInferencePrecision !== void 0 ? { gpuInferencePrecision: modelEntry.gpuInferencePrecision } : {},
3723
3761
  postprocessor: resolveEffectivePostprocessorForEntry(def, modelEntry),
3724
3762
  confidence: resolvePoolConfidenceFloor(stepId, resolveModelDefaultConfidence(def, modelEntry)),
3725
3763
  nmsIouThreshold: resolvePoolDecodeSettings({
@@ -7175,7 +7213,15 @@ var PipelineExecutor = class {
7175
7213
  if (plane === "frame" && child.definition.inputClasses !== null) continue;
7176
7214
  if (!this.matchesInputClasses(parentDetection.macroClass, child.inputClasses)) continue;
7177
7215
  const minParentScore = child.settings?.minParentScore ?? child.definition?.defaultMinParentScore;
7178
- if (typeof minParentScore === "number" && parentDetection.score < minParentScore) continue;
7216
+ if (typeof minParentScore === "number" && parentDetection.score < minParentScore) {
7217
+ 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", {
7218
+ step: child.stepId,
7219
+ model: child.modelId,
7220
+ faceScore: parentDetection.score,
7221
+ minParentScore
7222
+ }, deviceId);
7223
+ continue;
7224
+ }
7179
7225
  if (isBboxDegenerate(parentDetection.bbox)) continue;
7180
7226
  try {
7181
7227
  const childStart = Date.now();
@@ -7466,9 +7512,12 @@ function buildNode(step, getEngine, resolveModel, onMissingVariant, resolved) {
7466
7512
  const variant = resolved ?? getEngine(step.addonId, step.modelId);
7467
7513
  const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildChild(c, step.addonId, getEngine, resolveModel, onMissingVariant)).filter((c) => c !== null);
7468
7514
  const modelEntry = resolveModelEntry(definition, variant.modelId, resolveModel);
7515
+ const schema = getStep(step.addonId).getConfigSchema(modelEntry);
7516
+ const schemaDefaults = collectSchemaDefaults(schema);
7517
+ const operatorSettings = applyModelBoundSettings(step.settings, collectModelBoundKeys(schema), variant.modelId);
7469
7518
  const mergedSettings = {
7470
- ...collectSchemaDefaults(step.addonId, modelEntry),
7471
- ...step.settings
7519
+ ...schemaDefaults,
7520
+ ...operatorSettings
7472
7521
  };
7473
7522
  const effectiveClassMap = modelEntry?.classMap ?? definition.classMap;
7474
7523
  return {
@@ -7494,17 +7543,33 @@ function rootSuppliesField(definition, modelEntry) {
7494
7543
  return supplies.length > 0 ? { rootSupplies: supplies } : {};
7495
7544
  }
7496
7545
  /**
7497
- * Walk the step's declared `getConfigSchema()` and collect every field
7498
- * with a primitive `default` value into a plain record. Group fields
7499
- * are flattened — a nested `{ type: 'group', fields: [...] }` is
7500
- * entered recursively. Fields without a declared default are skipped.
7546
+ * Collect every field of a step's `getConfigSchema(model)` with a primitive
7547
+ * `default` value into a plain record. Group fields are flattened — a nested
7548
+ * `{ type: 'group', fields: [...] }` is entered recursively. Fields without a
7549
+ * declared default are skipped.
7501
7550
  */
7502
- function collectSchemaDefaults(stepId, model) {
7503
- const schema = getStep(stepId).getConfigSchema(model);
7551
+ function collectSchemaDefaults(schema) {
7504
7552
  const out = {};
7505
7553
  walkFieldsForDefaults(schema, out);
7506
7554
  return out;
7507
7555
  }
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
+ /**
7564
+ * The operator settings of `stepId` as the model that RUNS sees them (D738):
7565
+ * a model-bound value made for another model is dropped and binding keys are
7566
+ * stripped. For a settings layer merged AFTER the tree is built (the
7567
+ * executor's per-device store, `applyDeviceOverridesToTree`), so it obeys the
7568
+ * same binding as the layers `buildNode` merges.
7569
+ */
7570
+ function resolveOperatorSettingsForModel(stepId, settings, runningModelId) {
7571
+ return applyModelBoundSettings(settings, collectModelBoundKeys(getStep(stepId).getConfigSchema()), runningModelId) ?? {};
7572
+ }
7508
7573
  function walkFieldsForDefaults(fields, out) {
7509
7574
  for (const field of fields) {
7510
7575
  if ("type" in field && field.type === "group" && "fields" in field) {
@@ -11180,8 +11245,10 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
11180
11245
  def: step,
11181
11246
  configSchema: pipelineStep.getConfigSchema(),
11182
11247
  models: availableModels,
11183
- customModelIds: customIds
11248
+ customModelIds: customIds,
11249
+ schemaForModel: (entry) => pipelineStep.getConfigSchema(entry)
11184
11250
  });
11251
+ const configSchemaWithRoots = withRootSuppliedLabelDefaults(step.id, configSchema, mergeCustomModels(getStepDefinition("object-detection").models, customByStep?.get("object-detection") ?? []));
11185
11252
  slotMap.get(slot).push({
11186
11253
  id: step.id,
11187
11254
  name: step.name,
@@ -11208,7 +11275,7 @@ function buildSchemaSlots(formats, modelsDir, customByStep) {
11208
11275
  ...step.backfillIntoExistingOverrides !== void 0 ? { backfillIntoExistingOverrides: step.backfillIntoExistingOverrides } : {},
11209
11276
  defaultConfidence: step.defaultConfidence,
11210
11277
  ...step.group ? { group: step.group } : {},
11211
- ...configSchema.length > 0 ? { configSchema: [...configSchema] } : {}
11278
+ ...configSchemaWithRoots.length > 0 ? { configSchema: configSchemaWithRoots } : {}
11212
11279
  });
11213
11280
  }
11214
11281
  const slotPriority = {
@@ -11252,16 +11319,11 @@ function resolveChildSlots(slot) {
11252
11319
  }
11253
11320
  }
11254
11321
  /**
11255
- * V2 default: lightweight pipeline with minimal enabled steps.
11256
- *
11257
- * Only object detection (yolov9t, 4-8 MB) + face detection (scrfd, 1.7 MB) enabled.
11258
- * All other steps are present in the tree but DISABLED — user enables via UI.
11259
- * Total model footprint: ~10 MB (CoreML), ~11 MB (ONNX)
11260
- *
11261
- * Why:
11262
- * - Fast startup (seconds, not minutes of model downloads)
11263
- * - Covers 90% of NVR use cases (person/vehicle/animal detection + face detection)
11264
- * - Users opt-in to heavy classifiers (vehicle type, plate OCR, bird species) when needed
11322
+ * V2 default: the node-default step tree (never persisted — see
11323
+ * `getGlobalSteps`). The core detection + recognition steps are enabled; every
11324
+ * optional step is present with its catalog `enabledByDefault` (the animal and
11325
+ * vehicle classifiers on — their answer comes from the root model when it
11326
+ * declares them, D736 — the bird classifier and segmentation off).
11265
11327
  */
11266
11328
  function buildDefaultStepTree(format, objectDetectionModelId) {
11267
11329
  const makeStep = (stepId, children, opts) => {
@@ -11282,14 +11344,17 @@ function buildDefaultStepTree(format, objectDetectionModelId) {
11282
11344
  const faceEmbedding = makeStep("face-embedding", []);
11283
11345
  const faceDetection = makeStep("face-detection", faceEmbedding ? [faceEmbedding] : []);
11284
11346
  const plateOcr = makeStep("plate-ocr", []);
11347
+ const plateDetection = makeStep("plate-detection", plateOcr ? [plateOcr] : []);
11348
+ const clipEmbedding = makeStep("clip-embedding", []);
11349
+ const byCatalogDefault = (stepId) => ({ enabled: getStepDefinition(stepId).enabledByDefault ?? true });
11285
11350
  const root = makeStep("object-detection", [
11286
11351
  faceDetection,
11287
- makeStep("plate-detection", plateOcr ? [plateOcr] : []),
11288
- makeStep("clip-embedding", []),
11289
- makeStep("animal-classifier", [], { enabled: false }),
11290
- makeStep("bird-classifier", [], { enabled: false }),
11291
- makeStep("vehicle-classifier", [], { enabled: false }),
11292
- makeStep("segmentation", [], { enabled: false })
11352
+ plateDetection,
11353
+ clipEmbedding,
11354
+ makeStep("animal-classifier", [], byCatalogDefault("animal-classifier")),
11355
+ makeStep("bird-classifier", [], byCatalogDefault("bird-classifier")),
11356
+ makeStep("vehicle-classifier", [], byCatalogDefault("vehicle-classifier")),
11357
+ makeStep("segmentation", [], byCatalogDefault("segmentation"))
11293
11358
  ].filter((s) => s !== null), objectDetectionModelId !== void 0 ? { modelId: objectDetectionModelId } : void 0);
11294
11359
  const audioStep = makeStep("audio-classifier", []);
11295
11360
  const steps = [];
@@ -11382,14 +11447,15 @@ function availableFormatsForStep(addonId) {
11382
11447
  * Return a shallow-cloned executable tree with `rootStepId`'s `settings`
11383
11448
  * merged with `overrides` (per-device values win). Non-matching root steps
11384
11449
  * pass through unchanged. Used by `runFrame` to apply per-device detection
11385
- * settings without rebuilding the tree per frame.
11450
+ * settings without rebuilding the tree per frame. A model-bound value (D738)
11451
+ * applies only while the model it was made for is the one the root RUNS.
11386
11452
  */
11387
11453
  function applyDeviceOverridesToTree(tree, rootStepId, overrides) {
11388
11454
  return { roots: tree.roots.map((root) => root.stepId === rootStepId ? {
11389
11455
  ...root,
11390
11456
  settings: {
11391
11457
  ...root.settings,
11392
- ...overrides
11458
+ ...resolveOperatorSettingsForModel(rootStepId, overrides, root.modelId)
11393
11459
  }
11394
11460
  } : root) };
11395
11461
  }
@@ -12608,8 +12608,19 @@ var LABEL_SUPPLY_STEP_IDS = [
12608
12608
  ];
12609
12609
  /** Steps whose box a root detection can BE. */
12610
12610
  var CROP_SUPPLY_STEP_IDS = ["plate-detection", "face-detection"];
12611
+ /**
12612
+ * Steps whose per-detection MASK a root detection can carry (D737). The live
12613
+ * mask step is `segmentation` — a frame-plane refiner that runs its own model
12614
+ * once per detection crop. (`instance-segmentation` is a dormant step id that
12615
+ * no camera tree carries.)
12616
+ */
12617
+ var MASK_SUPPLY_STEP_IDS = ["segmentation"];
12611
12618
  /** Every step a root model can supply. */
12612
- var ROOT_SUPPLIABLE_STEP_IDS = [...LABEL_SUPPLY_STEP_IDS, ...CROP_SUPPLY_STEP_IDS];
12619
+ var ROOT_SUPPLIABLE_STEP_IDS = [
12620
+ ...LABEL_SUPPLY_STEP_IDS,
12621
+ ...CROP_SUPPLY_STEP_IDS,
12622
+ ...MASK_SUPPLY_STEP_IDS
12623
+ ];
12613
12624
  /** Narrow a step id to a label-kind one. */
12614
12625
  function isLabelSupplyStepId(value) {
12615
12626
  return LABEL_SUPPLY_STEP_IDS.some((id) => id === value);
@@ -12690,7 +12701,12 @@ var CROP_SUPPLY_SOURCES = {
12690
12701
  * Whether an operator intends a step to take the root's output when the
12691
12702
  * root declares it — the default of the `useRootModel` flag. The label kinds
12692
12703
  * default ON: the detector's answer is the cheaper one and the classifier
12693
- * keeps its model for the day the root changes. The crop kinds default OFF: a
12704
+ * keeps its model for the day the root changes. The animal and vehicle
12705
+ * classifiers are also ENABLED by default (their catalog `enabledByDefault`,
12706
+ * D736), so out of the box a root that declares them names animals and
12707
+ * vehicles and a root that does not runs the classifier; `package-detection`
12708
+ * stays zone-driven and takes this default whenever a zone switches it on.
12709
+ * The crop kinds default OFF: a
12694
12710
  * root plate box has an uncalibrated OCR margin, and root-face refinement has
12695
12711
  * not run on live traffic yet.
12696
12712
  */
@@ -12699,7 +12715,8 @@ var USE_ROOT_MODEL_DEFAULTS = {
12699
12715
  "vehicle-classifier": true,
12700
12716
  "package-detection": true,
12701
12717
  "plate-detection": false,
12702
- "face-detection": false
12718
+ "face-detection": false,
12719
+ segmentation: true
12703
12720
  };
12704
12721
  /** The step-settings key the flag is stored under (DeviceStepConfig.settings, camera overrides). */
12705
12722
  var USE_ROOT_MODEL_SETTING_KEY = "useRootModel";
@@ -12776,13 +12793,32 @@ function deriveRootSupplies(labels, classMap) {
12776
12793
  return supplies;
12777
12794
  }
12778
12795
  /**
12796
+ * The decodes that emit an instance mask with every detection — a fact of the
12797
+ * model's OUTPUT, read from its postprocessor (`yolo-seg`: per-instance mask
12798
+ * coefficients times the prototype masks), never assumed per family.
12799
+ */
12800
+ var MASK_EMITTING_POSTPROCESSORS = ["yolo-seg"];
12801
+ /**
12802
+ * The mask supplies a root declares from its decode: `segmentation` when the
12803
+ * postprocessor emits a mask per detection, nothing otherwise.
12804
+ */
12805
+ function deriveMaskSupplies(postprocessor) {
12806
+ if (postprocessor === void 0 || !MASK_EMITTING_POSTPROCESSORS.includes(postprocessor)) return [];
12807
+ return MASK_SUPPLY_STEP_IDS.map((stepId) => ({
12808
+ kind: "mask",
12809
+ stepId
12810
+ }));
12811
+ }
12812
+ /**
12779
12813
  * The supplies a root model declares. A row registered with a declaration
12780
12814
  * carries it (`suppliesSteps`, computed at import from the model's own
12781
12815
  * labelmap); a row without one — a built-in entry, or a custom row registered
12782
12816
  * before the field existed — is derived here, on read, from the same inputs.
12783
12817
  */
12784
12818
  function rootSuppliesOf(entry, stepDefaults) {
12785
- const declared = entry?.suppliesSteps ?? deriveRootSupplies(entry !== void 0 && entry.labels.length > 0 ? entry.labels.map((l) => l.id) : stepDefaults.labels, entry?.classMap ?? stepDefaults.classMap);
12819
+ const fromLabels = entry?.suppliesSteps ?? deriveRootSupplies(entry !== void 0 && entry.labels.length > 0 ? entry.labels.map((l) => l.id) : stepDefaults.labels, entry?.classMap ?? stepDefaults.classMap);
12820
+ const masks = deriveMaskSupplies(entry?.postprocessor).filter((m) => !fromLabels.some((s) => s.stepId === m.stepId));
12821
+ const declared = masks.length > 0 ? [...fromLabels, ...masks] : fromLabels;
12786
12822
  const inputPx = entry !== void 0 ? Math.min(entry.inputSize.width, entry.inputSize.height) : void 0;
12787
12823
  if (inputPx === void 0) return declared;
12788
12824
  return declared.map((s) => s.kind === "crop" ? {
@@ -13019,25 +13055,36 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
13019
13055
  * - `crop`: the root draws the box the step would have found (`license_plate`
13020
13056
  * for plate-detection, `face` for face-detection). The box becomes a detail
13021
13057
  * child of the `parentMacro` detection that contains it — never a track.
13058
+ * - `mask`: the root's decode emits an instance mask with every detection (a
13059
+ * YOLO26-seg root, D737) — the `segmentation` step's result, carried on the
13060
+ * detection in the shape that step produces. Derived from the model's
13061
+ * postprocessor on read, never stored by an import.
13022
13062
  */
13023
- var RootStepSupplySchema = discriminatedUnion("kind", [object({
13024
- kind: literal("label"),
13025
- stepId: _enum(LABEL_SUPPLY_STEP_IDS),
13026
- labelToEffect: record(string(), string()),
13027
- uncovered: array(string()).readonly()
13028
- }), object({
13029
- kind: literal("crop"),
13030
- stepId: _enum(CROP_SUPPLY_STEP_IDS),
13031
- rootLabels: array(string()).readonly(),
13032
- parentMacro: _enum(["vehicle", "person"]),
13033
- childClass: _enum(["plate", "face"]),
13034
- /**
13035
- * The root's smaller input side, stamped on read by `rootSuppliesOf` from
13036
- * the model entry — what a step's `minRootInputPx` gate judges. Never
13037
- * stored by an import.
13038
- */
13039
- rootInputPx: number().int().positive().optional()
13040
- })]);
13063
+ var RootStepSupplySchema = discriminatedUnion("kind", [
13064
+ object({
13065
+ kind: literal("label"),
13066
+ stepId: _enum(LABEL_SUPPLY_STEP_IDS),
13067
+ labelToEffect: record(string(), string()),
13068
+ uncovered: array(string()).readonly()
13069
+ }),
13070
+ object({
13071
+ kind: literal("crop"),
13072
+ stepId: _enum(CROP_SUPPLY_STEP_IDS),
13073
+ rootLabels: array(string()).readonly(),
13074
+ parentMacro: _enum(["vehicle", "person"]),
13075
+ childClass: _enum(["plate", "face"]),
13076
+ /**
13077
+ * The root's smaller input side, stamped on read by `rootSuppliesOf` from
13078
+ * the model entry — what a step's `minRootInputPx` gate judges. Never
13079
+ * stored by an import.
13080
+ */
13081
+ rootInputPx: number().int().positive().optional()
13082
+ }),
13083
+ object({
13084
+ kind: literal("mask"),
13085
+ stepId: _enum(MASK_SUPPLY_STEP_IDS)
13086
+ })
13087
+ ]);
13041
13088
  var ModelCatalogEntrySchema = object({
13042
13089
  id: string(),
13043
13090
  name: string(),
@@ -13103,6 +13150,35 @@ var ModelCatalogEntrySchema = object({
13103
13150
  */
13104
13151
  defaultConfidence: number().min(0).max(1).optional(),
13105
13152
  /**
13153
+ * Per-MODEL default of the per-class confidence floors (`minConfidence<Macro>`
13154
+ * on a detector step), keyed by macro class: `{ person: 0.45 }`. A class
13155
+ * absent here runs at the step slider's global default. The same row shape
13156
+ * the floor measurement produces (`model-floors.json`: modelId → floors), so
13157
+ * a measured table is copied in as-is. An operator override is bound to the
13158
+ * model it was made for and does not survive a model change (D738). A custom
13159
+ * / imported model may declare it; without it, the global defaults apply.
13160
+ */
13161
+ defaultClassFloors: record(string(), number().min(0).max(1)).optional(),
13162
+ /**
13163
+ * The inference precision this model's OpenVINO IR needs on an Intel GPU.
13164
+ * Absent ⇒ the device default (f16 on a GPU). Set to `'f32'` for an FP32 IR
13165
+ * that produces invalid output at f16 — measured 2026-10-07 for YOLO26
13166
+ * base IRs (`yolo26s`: 0 true / 146 false positives; `yolo26m*`: NaN
13167
+ * scores) on the Core Ultra iGPU and the N100. Threaded to the pool as
13168
+ * `PoolModelConfig.gpuInferencePrecision`; the pool sets
13169
+ * INFERENCE_PRECISION_HINT on a GPU only. Costs ~60% latency on the GPU.
13170
+ */
13171
+ gpuInferencePrecision: _enum(["f32", "f16"]).optional(),
13172
+ /**
13173
+ * ROOT detectors only: per supplied step (`animal-classifier`, …), the
13174
+ * minimum DETECTION score from which this root's own fine label (species,
13175
+ * vehicle type — D736 root supply) is taken (D741). Below it the detection
13176
+ * keeps its macro class without the fine label. `1` = never take it from
13177
+ * this root. Absent ⇒ no floor beyond the macro floor. The supplied step's
13178
+ * `minConfidence` slider, bound to the ROOT model, overrides it.
13179
+ */
13180
+ suppliedLabelFloors: record(string(), number().min(0).max(1)).optional(),
13181
+ /**
13106
13182
  * When true, the executor produces a landmark-aligned crop (similarity warp
13107
13183
  * onto the canonical template) before this step runs, instead of a plain
13108
13184
  * axis-aligned bbox crop. Required for face-recognition embedders (ArcFace):
@@ -41070,6 +41146,16 @@ DeviceType.Camera, method(object({
41070
41146
  package: array(ZoneRuleSchema).readonly()
41071
41147
  });
41072
41148
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
41149
+ Object.freeze({
41150
+ person: .5,
41151
+ vehicle: .5,
41152
+ animal: .5
41153
+ });
41154
+ Object.freeze({
41155
+ person: .65,
41156
+ vehicle: .65,
41157
+ animal: .65
41158
+ });
41073
41159
  var HF_BASE_URL = `https://huggingface.co/camstack/camstack-models/resolve/main`;
41074
41160
  /**
41075
41161
  * Accessory device helpers — shared across drivers.
@@ -53325,6 +53411,100 @@ function stepModelRunsOnFormat(models, modelId, format) {
53325
53411
  }
53326
53412
  return models.some((m) => m.legacy !== true && hasBuild(m, format));
53327
53413
  }
53414
+ /**
53415
+ * Model-bound step settings (D738): an operator value that is only meaningful
53416
+ * for ONE model, stored together with that model's id.
53417
+ *
53418
+ * The per-class confidence floors are the case it exists for. A score is a
53419
+ * property of one detector's output scale — on this hub the median score of a
53420
+ * correct person was 0.78 on `yolov9m-320-int8`, 0.68 on `yolo26s-320-int8`,
53421
+ * 0.40 on `yolo26n-320-int8` and 0.89 on `yolo26s` (640) — so a floor tuned on
53422
+ * one model is wrong on the next. The DEFAULT of such a field belongs to the
53423
+ * model (the catalog entry); an operator OVERRIDE belongs to the model it was
53424
+ * made for.
53425
+ *
53426
+ * The binding is checked at READ time against the model that RUNS, never
53427
+ * enforced by a write on the model-change path: a model can change without any
53428
+ * operator write at all (an unpinned root follows the elected device's
53429
+ * hardware-aware default, D736), and an event-driven reset could be dropped
53430
+ * (events are telemetry, D8/D11). So:
53431
+ *
53432
+ * effective = override when the stored binding names the running model
53433
+ * | override when no binding is stored (a legacy / programmatic
53434
+ * value — it applies to whatever runs, as before D738)
53435
+ * | the running model's default, when it declares one
53436
+ * | the field's global default.
53437
+ *
53438
+ * Storage shape: the value stays a plain number under its own key (every
53439
+ * reader of the raw settings bag keeps working), and the binding is a SIBLING
53440
+ * key, {@link modelBindingKey}. Both are flat so the shallow per-key merges of
53441
+ * the settings layers (node fold, camera override) carry a value and its
53442
+ * binding together whenever one layer writes both — which every writer here
53443
+ * does.
53444
+ *
53445
+ * Lives in the bare `@camstack/types` entry, which every addon bundles, so the
53446
+ * runner (`addon-pipeline`) and the editors (`ui-library`, `addon-admin-ui`)
53447
+ * apply the same rule.
53448
+ */
53449
+ /** Suffix of the sibling key that names the model a stored value was made for. */
53450
+ var MODEL_BINDING_SUFFIX = "ModelId";
53451
+ /** `minConfidencePerson` → `minConfidencePersonModelId`. */
53452
+ function modelBindingKey(key) {
53453
+ return `${key}${MODEL_BINDING_SUFFIX}`;
53454
+ }
53455
+ /** The model a stored value was made for, or `undefined` when unbound. */
53456
+ function storedBinding(settings, key) {
53457
+ const binding = settings?.[modelBindingKey(key)];
53458
+ return typeof binding === "string" && binding.length > 0 ? binding : void 0;
53459
+ }
53460
+ /**
53461
+ * The effective value of `key` for the model that runs (`runningModelId`,
53462
+ * `undefined` when unknown — it then matches no binding).
53463
+ */
53464
+ function resolveModelBoundSetting(settings, key, runningModelId, modelDefault, globalDefault) {
53465
+ const stored = settings?.[key];
53466
+ const binding = storedBinding(settings, key);
53467
+ if (stored !== void 0 && binding === void 0) return {
53468
+ value: stored,
53469
+ source: "override"
53470
+ };
53471
+ if (stored !== void 0 && binding !== void 0 && binding === runningModelId) return {
53472
+ value: stored,
53473
+ source: "override",
53474
+ boundModelId: binding
53475
+ };
53476
+ const inapplicable = stored !== void 0 && binding !== void 0 ? { inapplicableOverride: {
53477
+ value: stored,
53478
+ modelId: binding
53479
+ } } : {};
53480
+ if (modelDefault !== void 0) return {
53481
+ value: modelDefault,
53482
+ source: "model-default",
53483
+ ...inapplicable
53484
+ };
53485
+ return {
53486
+ value: globalDefault,
53487
+ source: "global-default",
53488
+ ...inapplicable
53489
+ };
53490
+ }
53491
+ /**
53492
+ * The OPERATOR layer of a step's settings as the running model sees it: every
53493
+ * model-bound value made for another model is removed (so the default
53494
+ * underneath — the running model's — wins the merge), and every binding key is
53495
+ * stripped. Unbound values are kept. Returns a fresh object; `undefined` stays
53496
+ * `undefined`.
53497
+ */
53498
+ function applyModelBoundSettings(settings, boundKeys, runningModelId) {
53499
+ if (settings === void 0) return void 0;
53500
+ const out = { ...settings };
53501
+ for (const key of boundKeys) {
53502
+ const binding = storedBinding(settings, key);
53503
+ if (binding !== void 0 && binding !== runningModelId) delete out[key];
53504
+ delete out[modelBindingKey(key)];
53505
+ }
53506
+ return out;
53507
+ }
53328
53508
  /** Side of the square, as a multiple of the face box's longer side. */
53329
53509
  var ROOT_FACE_REFINE_SCALE = 1.6;
53330
53510
  /**
@@ -54891,6 +55071,12 @@ Object.defineProperty(exports, "allowedSuppliedEffect", {
54891
55071
  return allowedSuppliedEffect;
54892
55072
  }
54893
55073
  });
55074
+ Object.defineProperty(exports, "applyModelBoundSettings", {
55075
+ enumerable: true,
55076
+ get: function() {
55077
+ return applyModelBoundSettings;
55078
+ }
55079
+ });
54894
55080
  Object.defineProperty(exports, "array", {
54895
55081
  enumerable: true,
54896
55082
  get: function() {
@@ -55413,6 +55599,12 @@ Object.defineProperty(exports, "resolveLocationMode", {
55413
55599
  return resolveLocationMode;
55414
55600
  }
55415
55601
  });
55602
+ Object.defineProperty(exports, "resolveModelBoundSetting", {
55603
+ enumerable: true,
55604
+ get: function() {
55605
+ return resolveModelBoundSetting;
55606
+ }
55607
+ });
55416
55608
  Object.defineProperty(exports, "resolvePoolMemoryPolicy", {
55417
55609
  enumerable: true,
55418
55610
  get: function() {