@camstack/addon-model-studio 1.1.207 → 1.1.209

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 (20) hide show
  1. package/dist/MotionZonesSettings-DPVW36SY.mjs +310 -0
  2. package/dist/{PrivacyMaskSettings-4VnzM7CJ.mjs → PrivacyMaskSettings-CE3p-uMG.mjs} +5 -5
  3. package/dist/{SceneMonitorEditor-C2DUWSMy.mjs → SceneMonitorEditor-B0ZWDpU7.mjs} +285 -285
  4. package/dist/_stub.js +6563 -5772
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-q5-p_N0m.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-CXndlwsf.mjs} +3 -3
  6. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DMYNiT-L.mjs +26 -0
  7. package/dist/addon-model-studio.css +1 -1
  8. package/dist/{hostInit-De6t1H5z.mjs → hostInit-DpDYa2D-.mjs} +2 -2
  9. package/dist/model-studio.addon.js +354 -9
  10. package/dist/model-studio.addon.mjs +354 -9
  11. package/dist/{player-overlays-DnuiNM0v.mjs → player-overlays-B06LE_Gr.mjs} +5 -5
  12. package/dist/remoteEntry.js +1 -1
  13. package/dist/{responsive-CIrYx2bw.mjs → responsive-BV0NkBXa.mjs} +3 -3
  14. package/dist/{scene-monitor-copy-AfaY2iTT.mjs → scene-monitor-copy-BEsrfWnh.mjs} +1 -1
  15. package/dist/{square-v2U1PMC1.mjs → square-1mDEdKJ6.mjs} +1 -1
  16. package/dist/{trash-2-BQe8qX4b.mjs → trash-2-BJYsA9Vu.mjs} +1 -1
  17. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-H0G7-sT2.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-CmWc3NQd.mjs} +1 -1
  18. package/package.json +1 -1
  19. package/dist/MotionZonesSettings-Dglm7NRe.mjs +0 -310
  20. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-_AxpyMKA.mjs +0 -26
@@ -11099,7 +11099,53 @@ var ModelFormatEntrySchema = object({
11099
11099
  /** Multi-file payload (directory members or sibling files). */
11100
11100
  files: array(string()).readonly().optional(),
11101
11101
  /** Runtime(s) that can use this format. If omitted, inferred from ModelFormat key */
11102
- runtimes: array(_enum(["python"])).readonly().optional()
11102
+ runtimes: array(_enum(["python"])).readonly().optional(),
11103
+ /**
11104
+ * Content revision of the artefact, for one hosted OFF the CamStack mirror.
11105
+ * A format on the mirror leaves it unset: its revision (the sha256 of its
11106
+ * weight file) comes from the downloader's generated table, kept in step
11107
+ * with the mirror by `scripts/check-hosted-model-revisions.ts` (D744). A
11108
+ * node records the revision it downloaded next to the file
11109
+ * (`<file>.revision`); a copy with no record or a different one is stale
11110
+ * unless its weight file hashes to the revision, and a stale copy is
11111
+ * downloaded again, the old one serving until the new one is complete. No
11112
+ * revision at all ⇒ a file on disk is current, whatever it holds (D743).
11113
+ */
11114
+ revision: string().min(1).optional()
11115
+ });
11116
+ /**
11117
+ * What a node holds for one (model, format) (D746). `current` is a complete
11118
+ * copy at its catalog revision — exactly what `downloaded: true` means.
11119
+ * `stale` is bytes on disk that are not (yet) proven current under D743/D744:
11120
+ * no or a different revision record, or a missing sibling. `missing` is no
11121
+ * copy. `downloaded` alone folds `stale` into "not downloaded", which hid
11122
+ * reclaimable bytes and a copy about to be replaced.
11123
+ */
11124
+ var ModelOnDiskStateSchema = _enum([
11125
+ "current",
11126
+ "stale",
11127
+ "missing"
11128
+ ]);
11129
+ /**
11130
+ * The numeric precision of one format's BUILD (D746) — reported only when the
11131
+ * build states it (file-name token, an INT8 variant, an EdgeTPU compile, a
11132
+ * CamStack Core ML export). Absent means "not stated", never "fp32".
11133
+ */
11134
+ var ModelFormatPrecisionSchema = _enum([
11135
+ "fp32",
11136
+ "fp16",
11137
+ "int8"
11138
+ ]);
11139
+ /**
11140
+ * One format of one model as a node's `pipelineExecutor.getSchema` reports it.
11141
+ * `onDisk` / `precision` are optional for version skew: a runner that predates
11142
+ * them omits them, and a reader falls back to `downloaded`.
11143
+ */
11144
+ var PipelineModelFormatStatusSchema = object({
11145
+ downloaded: boolean(),
11146
+ sizeMB: number(),
11147
+ onDisk: ModelOnDiskStateSchema.optional(),
11148
+ precision: ModelFormatPrecisionSchema.optional()
11103
11149
  });
11104
11150
  /**
11105
11151
  * Extra file that must be downloaded alongside the model (e.g., labels JSON, dict.txt).
@@ -11321,6 +11367,35 @@ var ModelCatalogEntrySchema = object({
11321
11367
  */
11322
11368
  defaultConfidence: number().min(0).max(1).optional(),
11323
11369
  /**
11370
+ * Per-MODEL default of the per-class confidence floors (`minConfidence<Macro>`
11371
+ * on a detector step), keyed by macro class: `{ person: 0.45 }`. A class
11372
+ * absent here runs at the step slider's global default. The same row shape
11373
+ * the floor measurement produces (`model-floors.json`: modelId → floors), so
11374
+ * a measured table is copied in as-is. An operator override is bound to the
11375
+ * model it was made for and does not survive a model change (D738). A custom
11376
+ * / imported model may declare it; without it, the global defaults apply.
11377
+ */
11378
+ defaultClassFloors: record(string(), number().min(0).max(1)).optional(),
11379
+ /**
11380
+ * The inference precision this model's OpenVINO IR needs on an Intel GPU.
11381
+ * Absent ⇒ the device default (f16 on a GPU). Set to `'f32'` for an FP32 IR
11382
+ * that produces invalid output at f16 — measured 2026-10-07 for YOLO26
11383
+ * base IRs (`yolo26s`: 0 true / 146 false positives; `yolo26m*`: NaN
11384
+ * scores) on the Core Ultra iGPU and the N100. Threaded to the pool as
11385
+ * `PoolModelConfig.gpuInferencePrecision`; the pool sets
11386
+ * INFERENCE_PRECISION_HINT on a GPU only. Costs ~60% latency on the GPU.
11387
+ */
11388
+ gpuInferencePrecision: _enum(["f32", "f16"]).optional(),
11389
+ /**
11390
+ * ROOT detectors only: per supplied step (`animal-classifier`, …), the
11391
+ * minimum DETECTION score from which this root's own fine label (species,
11392
+ * vehicle type — D736 root supply) is taken (D741). Below it the detection
11393
+ * keeps its macro class without the fine label. `1` = never take it from
11394
+ * this root. Absent ⇒ no floor beyond the macro floor. The supplied step's
11395
+ * `minConfidence` slider, bound to the ROOT model, overrides it.
11396
+ */
11397
+ suppliedLabelFloors: record(string(), number().min(0).max(1)).optional(),
11398
+ /**
11324
11399
  * When true, the executor produces a landmark-aligned crop (similarity warp
11325
11400
  * onto the canonical template) before this step runs, instead of a plain
11326
11401
  * axis-aligned bbox crop. Required for face-recognition embedders (ArcFace):
@@ -23762,7 +23837,7 @@ var FrameRefSchema = object({
23762
23837
  timestamp: number(),
23763
23838
  capturedAt: number().optional()
23764
23839
  });
23765
- var ModelFormatSchema$1 = _enum([
23840
+ var ModelFormatSchema$2 = _enum([
23766
23841
  "onnx",
23767
23842
  "coreml",
23768
23843
  "openvino",
@@ -23780,7 +23855,7 @@ var PipelineSlotSchema = _enum([
23780
23855
  var PipelineEngineChoiceSchema = object({
23781
23856
  runtime: literal("python"),
23782
23857
  backend: string(),
23783
- format: ModelFormatSchema$1,
23858
+ format: ModelFormatSchema$2,
23784
23859
  device: string().optional()
23785
23860
  });
23786
23861
  /**
@@ -23837,10 +23912,7 @@ var PipelineTemplateSchema$1 = object({
23837
23912
  var PipelineModelOptionSchema = object({
23838
23913
  id: string(),
23839
23914
  name: string(),
23840
- formats: record(string(), object({
23841
- downloaded: boolean(),
23842
- sizeMB: number()
23843
- })),
23915
+ formats: record(string(), PipelineModelFormatStatusSchema),
23844
23916
  group: ModelVariantGroupSchema.optional(),
23845
23917
  legacy: boolean().optional(),
23846
23918
  provider: ModelProviderIdSchema.optional(),
@@ -24007,6 +24079,22 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
24007
24079
  }), {
24008
24080
  kind: "mutation",
24009
24081
  auth: "admin"
24082
+ }), method(object({
24083
+ nodeId: string(),
24084
+ deviceIds: array(number()).readonly().optional(),
24085
+ dryRun: boolean()
24086
+ }), object({
24087
+ entries: array(object({
24088
+ deviceId: number(),
24089
+ keys: array(string()).readonly()
24090
+ })).readonly(),
24091
+ refused: array(object({
24092
+ deviceId: number(),
24093
+ reason: string()
24094
+ })).readonly()
24095
+ }), {
24096
+ kind: "mutation",
24097
+ auth: "admin"
24010
24098
  }), method(object({ nodeId: string() }), object({ unhealthy: array(object({
24011
24099
  /** `<backend>:<device>`, e.g. `openvino:gpu`. */
24012
24100
  deviceKey: string(),
@@ -24043,11 +24131,11 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
24043
24131
  }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({ id: string() }), _void(), { kind: "mutation" }), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
24044
24132
  addonId: string(),
24045
24133
  modelId: string(),
24046
- format: ModelFormatSchema$1
24134
+ format: ModelFormatSchema$2
24047
24135
  }), DownloadModelResultSchema, { kind: "mutation" }), method(object({
24048
24136
  addonId: string(),
24049
24137
  modelId: string(),
24050
- format: ModelFormatSchema$1
24138
+ format: ModelFormatSchema$2
24051
24139
  }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
24052
24140
  steps: array(PipelineStepInputSchema).min(1),
24053
24141
  frame: FrameInputSchema.optional(),
@@ -24204,6 +24292,204 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
24204
24292
  filename: string().optional(),
24205
24293
  settings: record(string(), unknown()).optional()
24206
24294
  }), AudioTestResultSchema, { kind: "mutation" }), method(_void(), ConfigUISchemaNullableBridge);
24295
+ /**
24296
+ * The wire shapes of the Best settings plan and apply (D745), used by the
24297
+ * `pipeline-orchestrator` cap. The recommender's own types
24298
+ * (`recommend.ts`, `demand.ts`) are the TS face of the same data; these
24299
+ * schemas are what crosses the cap boundary.
24300
+ */
24301
+ var ModelFormatSchema$1 = _enum(MODEL_FORMATS);
24302
+ var HardwareClassIdSchema = _enum([
24303
+ "intel-core-ultra",
24304
+ "intel-n-series",
24305
+ "apple-m-base",
24306
+ "apple-m-pro",
24307
+ "unknown"
24308
+ ]);
24309
+ var AcceleratorKindSchema = _enum([
24310
+ "intel-npu",
24311
+ "intel-igpu",
24312
+ "x86-cpu",
24313
+ "arm-cpu",
24314
+ "apple-ane",
24315
+ "coral"
24316
+ ]);
24317
+ var RecommendationReasonSchema = discriminatedUnion("kind", [
24318
+ object({
24319
+ kind: literal("fits"),
24320
+ utilisation: number()
24321
+ }),
24322
+ object({
24323
+ kind: literal("tie-faster"),
24324
+ over: string(),
24325
+ recallDelta: number()
24326
+ }),
24327
+ object({
24328
+ kind: literal("stepped-down"),
24329
+ from: string(),
24330
+ to: string(),
24331
+ limitedBy: string()
24332
+ }),
24333
+ object({
24334
+ kind: literal("no-fit-lightest"),
24335
+ utilisation: number()
24336
+ }),
24337
+ object({
24338
+ kind: literal("derived-latency"),
24339
+ modelId: string()
24340
+ }),
24341
+ object({
24342
+ kind: literal("estimated-load"),
24343
+ observedForMs: number().nullable()
24344
+ }),
24345
+ object({ kind: literal("cpu-device") }),
24346
+ object({ kind: literal("coral-untouched") }),
24347
+ object({ kind: literal("device-disabled") }),
24348
+ object({ kind: literal("device-unavailable") }),
24349
+ object({ kind: literal("node-offline") }),
24350
+ object({ kind: literal("no-hardware-facts") }),
24351
+ object({
24352
+ kind: literal("no-measured-data"),
24353
+ hardwareClass: HardwareClassIdSchema
24354
+ }),
24355
+ object({
24356
+ kind: literal("no-family-build"),
24357
+ format: ModelFormatSchema$1
24358
+ })
24359
+ ]);
24360
+ var DeviceDemandSchema = object({
24361
+ nodeId: string(),
24362
+ deviceKey: string(),
24363
+ demandFps: number(),
24364
+ maxCameraFps: number(),
24365
+ alwaysOnCameras: number(),
24366
+ onMotionSessions: number(),
24367
+ onMotionSource: _enum([
24368
+ "observed-24h",
24369
+ "estimate",
24370
+ "none"
24371
+ ]),
24372
+ observedForMs: number().nullable()
24373
+ });
24374
+ var DeviceModelChoiceSchema = object({
24375
+ modelId: string(),
24376
+ p50Ms: number(),
24377
+ fps: number(),
24378
+ measured: boolean(),
24379
+ utilisation: number(),
24380
+ personRecall: number()
24381
+ });
24382
+ var DeviceRecommendationSchema = object({
24383
+ deviceKey: string(),
24384
+ accelerator: AcceleratorKindSchema.nullable(),
24385
+ enabled: boolean(),
24386
+ available: boolean(),
24387
+ demand: DeviceDemandSchema.nullable(),
24388
+ chosen: DeviceModelChoiceSchema.nullable(),
24389
+ reasons: array(RecommendationReasonSchema).readonly()
24390
+ });
24391
+ var NodeRecommendationSchema = object({
24392
+ nodeId: string(),
24393
+ reachable: boolean(),
24394
+ hardwareClass: HardwareClassIdSchema.nullable(),
24395
+ cpuModel: string().nullable(),
24396
+ skipped: boolean(),
24397
+ acceleratorModelId: string().nullable(),
24398
+ devices: array(DeviceRecommendationSchema).readonly(),
24399
+ reasons: array(RecommendationReasonSchema).readonly()
24400
+ });
24401
+ var ModelPinChangeSchema = object({
24402
+ stepId: string(),
24403
+ before: string().nullable(),
24404
+ after: string().nullable()
24405
+ });
24406
+ var NodeDeviceChangeSchema = object({
24407
+ nodeId: string(),
24408
+ deviceKey: string(),
24409
+ madeExplicit: boolean(),
24410
+ modelPins: array(ModelPinChangeSchema).readonly(),
24411
+ thresholds: array(object({
24412
+ stepId: string(),
24413
+ keys: array(string()).readonly()
24414
+ })).readonly()
24415
+ });
24416
+ var CameraOverrideClearSchema = object({
24417
+ deviceId: number(),
24418
+ source: _enum(["step-override", "wholesale"]),
24419
+ nodeId: string(),
24420
+ deviceKey: string().nullable(),
24421
+ stepId: string(),
24422
+ modelIdBefore: string().nullable(),
24423
+ keys: array(string()).readonly()
24424
+ });
24425
+ var DetectorStoreClearSchema = object({
24426
+ deviceId: number(),
24427
+ keys: array(string()).readonly()
24428
+ });
24429
+ var BestSettingsWarningSchema = discriminatedUnion("kind", [
24430
+ object({
24431
+ kind: literal("detector-store-cluster-wide"),
24432
+ skippedNodes: array(string()).readonly()
24433
+ }),
24434
+ object({
24435
+ kind: literal("detector-store-unreadable"),
24436
+ error: string()
24437
+ }),
24438
+ object({
24439
+ kind: literal("coral-enabled"),
24440
+ nodeId: string(),
24441
+ deviceKey: string()
24442
+ })
24443
+ ]);
24444
+ var BestSettingsOptionsSchema = object({
24445
+ /** Share of each accelerator's throughput kept free (0.3–0.5). */
24446
+ headroom: number().min(.3).max(.5).default(.4) });
24447
+ var BestSettingsPlanSchema = object({
24448
+ /** Hash of everything the apply will write — the apply refuses a different one. */
24449
+ planHash: string(),
24450
+ family: literal("yolov9"),
24451
+ headroom: number(),
24452
+ generatedAt: number(),
24453
+ nodes: array(NodeRecommendationSchema).readonly(),
24454
+ nodeChanges: array(NodeDeviceChangeSchema).readonly(),
24455
+ cameraClears: array(CameraOverrideClearSchema).readonly(),
24456
+ detectorStoreClears: array(DetectorStoreClearSchema).readonly(),
24457
+ warnings: array(BestSettingsWarningSchema).readonly()
24458
+ });
24459
+ var BestSettingsApplyInputSchema = object({
24460
+ planHash: string(),
24461
+ headroom: number().min(.3).max(.5).default(.4)
24462
+ });
24463
+ var BestSettingsPhaseResultSchema = object({
24464
+ phase: _enum([
24465
+ "download",
24466
+ "camera-overrides",
24467
+ "detector-thresholds",
24468
+ "node-models",
24469
+ "redispatch"
24470
+ ]),
24471
+ ok: boolean(),
24472
+ detail: string()
24473
+ });
24474
+ var BestSettingsApplyResultSchema = discriminatedUnion("kind", [
24475
+ object({
24476
+ kind: literal("applied"),
24477
+ planHash: string(),
24478
+ phases: array(BestSettingsPhaseResultSchema).readonly()
24479
+ }),
24480
+ object({
24481
+ kind: literal("aborted"),
24482
+ phases: array(BestSettingsPhaseResultSchema).readonly()
24483
+ }),
24484
+ object({
24485
+ kind: literal("stale"),
24486
+ plan: BestSettingsPlanSchema
24487
+ }),
24488
+ object({
24489
+ kind: literal("refused"),
24490
+ reason: _enum(["apply-in-progress"])
24491
+ })
24492
+ ]);
24207
24493
  object({
24208
24494
  activeCameras: number(),
24209
24495
  throttledCameras: number(),
@@ -25930,6 +26216,9 @@ method(object({
25930
26216
  }), {
25931
26217
  kind: "mutation",
25932
26218
  auth: "admin"
26219
+ }), method(BestSettingsOptionsSchema, BestSettingsPlanSchema, { auth: "admin" }), method(BestSettingsApplyInputSchema, BestSettingsApplyResultSchema, {
26220
+ kind: "mutation",
26221
+ auth: "admin"
25933
26222
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
25934
26223
  deviceId: number(),
25935
26224
  addonId: string(),
@@ -37055,6 +37344,37 @@ function frigateLabelFields(labels) {
37055
37344
  } : { classMap };
37056
37345
  }
37057
37346
  /**
37347
+ * Per-class confidence-floor defaults of an imported stock Frigate detector
37348
+ * (D738): its per-detection `min_score` default, 0.5, for every class. Its
37349
+ * track-level `threshold` (the median of a track's recent scores) has no
37350
+ * counterpart in CamStack's per-detection floors and is not carried.
37351
+ */
37352
+ var FRIGATE_STOCK_CLASS_FLOORS = Object.freeze({
37353
+ person: .5,
37354
+ vehicle: .5,
37355
+ animal: .5
37356
+ });
37357
+ /**
37358
+ * Per-class floor defaults of an imported Frigate+ detector (D738): the
37359
+ * documented starting `min_score` values for Frigate+ models, which score
37360
+ * higher than the stock ones (person 0.65, car 0.65, cat 0.65, dog 0.70). The
37361
+ * macro `animal` takes the lower of its classes, so no class is cut above its
37362
+ * documented value.
37363
+ */
37364
+ var FRIGATE_PLUS_CLASS_FLOORS = Object.freeze({
37365
+ person: .65,
37366
+ vehicle: .65,
37367
+ animal: .65
37368
+ });
37369
+ /**
37370
+ * The `defaultClassFloors` an imported Frigate entry carries: the import's
37371
+ * own, when it states them, else the defaults of its kind. A fresh object.
37372
+ */
37373
+ function frigateDefaultClassFloors(kind, carried) {
37374
+ if (carried !== void 0) return { ...carried };
37375
+ return { ...kind === "plus" ? FRIGATE_PLUS_CLASS_FLOORS : FRIGATE_STOCK_CLASS_FLOORS };
37376
+ }
37377
+ /**
37058
37378
  * Accessory device helpers — shared across drivers.
37059
37379
  *
37060
37380
  * Many vendor-specific drivers register accessory child devices on
@@ -41572,6 +41892,12 @@ Object.freeze({
41572
41892
  addonId: null,
41573
41893
  access: "delete"
41574
41894
  },
41895
+ "pipelineExecutor.clearModelBoundDeviceOverrides": {
41896
+ capName: "pipeline-executor",
41897
+ capScope: "system",
41898
+ addonId: null,
41899
+ access: "delete"
41900
+ },
41575
41901
  "pipelineExecutor.deleteModel": {
41576
41902
  capName: "pipeline-executor",
41577
41903
  capScope: "system",
@@ -41788,6 +42114,12 @@ Object.freeze({
41788
42114
  addonId: null,
41789
42115
  access: "view"
41790
42116
  },
42117
+ "pipelineOrchestrator.applyBestSettings": {
42118
+ capName: "pipeline-orchestrator",
42119
+ capScope: "system",
42120
+ addonId: null,
42121
+ access: "create"
42122
+ },
41791
42123
  "pipelineOrchestrator.applyDeviceSettingsPatch": {
41792
42124
  capName: "pipeline-orchestrator",
41793
42125
  capScope: "system",
@@ -41962,6 +42294,12 @@ Object.freeze({
41962
42294
  addonId: null,
41963
42295
  access: "create"
41964
42296
  },
42297
+ "pipelineOrchestrator.planBestSettings": {
42298
+ capName: "pipeline-orchestrator",
42299
+ capScope: "system",
42300
+ addonId: null,
42301
+ access: "view"
42302
+ },
41965
42303
  "pipelineOrchestrator.rebalance": {
41966
42304
  capName: "pipeline-orchestrator",
41967
42305
  capScope: "system",
@@ -47384,6 +47722,11 @@ Object.freeze({
47384
47722
  form: "single",
47385
47723
  optional: false
47386
47724
  }],
47725
+ "pipelineExecutor.clearModelBoundDeviceOverrides": [{
47726
+ name: "deviceIds",
47727
+ form: "array",
47728
+ optional: true
47729
+ }],
47387
47730
  "pipelineExecutor.runPipeline": [{
47388
47731
  name: "deviceId",
47389
47732
  form: "single",
@@ -49912,6 +50255,7 @@ function buildFrigateCatalogDescriptor(catalogId, overrides) {
49912
50255
  name
49913
50256
  })),
49914
50257
  ...frigateLabelFields(cat.labels),
50258
+ defaultClassFloors: frigateDefaultClassFloors("stock"),
49915
50259
  preprocessMode: "letterbox",
49916
50260
  provider: "frigate",
49917
50261
  license: cat.license,
@@ -50254,6 +50598,7 @@ function plusInfoToDescriptor(info, opts) {
50254
50598
  name
50255
50599
  })),
50256
50600
  ...frigateLabelFields(labels),
50601
+ defaultClassFloors: frigateDefaultClassFloors("plus"),
50257
50602
  preprocessMode: "letterbox",
50258
50603
  provider: "frigate",
50259
50604
  group: frigateVariantGroup(info.type, info.width),