@camstack/addon-provider-onvif 1.1.30 → 1.2.1

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 (3) hide show
  1. package/dist/addon.js +213 -106
  2. package/dist/addon.mjs +213 -106
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -7083,6 +7083,17 @@ var ModelCatalogEntrySchema = object({
7083
7083
  "imagenet",
7084
7084
  "none"
7085
7085
  ]).optional(),
7086
+ /**
7087
+ * The model already applies softmax IN-GRAPH — its raw output is a
7088
+ * probability distribution, not logits. When set, the `softmax`
7089
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7090
+ * probability vector collapses it toward uniform (top-1 score craters far
7091
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7092
+ * the output is raw logits and the postprocessor applies softmax (the normal
7093
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7094
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7095
+ */
7096
+ outputProbabilities: boolean().optional(),
7086
7097
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7087
7098
  /**
7088
7099
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11266,10 +11277,7 @@ var ConfigUISchemaNullableBridge = custom();
11266
11277
  var InferenceCapabilitiesBridge = custom();
11267
11278
  var ModelAvailabilityListBridge = custom();
11268
11279
  var PipelineRunResultBridge = custom();
11269
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11270
- kind: "mutation",
11271
- auth: "admin"
11272
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11280
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11273
11281
  modelId: string(),
11274
11282
  settings: record(string(), unknown()).readonly()
11275
11283
  }))), method(object({ steps: record(string(), object({
@@ -11329,13 +11337,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11329
11337
  * (inputClasses ≠ null) are skipped and served per-track via
11330
11338
  * pipelineRunner.runDetailSubtree (two-plane design).
11331
11339
  */
11332
- plane: _enum(["full", "frame"]).optional()
11340
+ plane: _enum(["full", "frame"]).optional(),
11341
+ /**
11342
+ * Inference-device selector (Phase 2 multi-device). Format
11343
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11344
+ * Omitted ⇒ the runner's default device (current single-engine
11345
+ * behaviour). Selects WHICH device pool of the node runs the call.
11346
+ */
11347
+ deviceKey: string().optional()
11333
11348
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11334
11349
  engine: PipelineEngineChoiceSchema.optional(),
11335
11350
  steps: array(PipelineStepInputSchema).min(1),
11336
11351
  frames: array(FrameInputSchema).min(1).max(255),
11337
11352
  deviceId: number().optional(),
11338
- sessionId: string().optional()
11353
+ sessionId: string().optional(),
11354
+ /**
11355
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11356
+ * the batch to the Python pool's bench preprocess cache
11357
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11358
+ * preprocessed ONCE and every later inference is a pure-inference cache
11359
+ * hit — the sustained-throughput run measures inference, not
11360
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11361
+ * full preprocess every call, correct). Fresh per sustained run;
11362
+ * released via `uncacheFrame`.
11363
+ */
11364
+ frameId: number().int().nonnegative().optional(),
11365
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11366
+ deviceKey: string().optional()
11339
11367
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11340
11368
  data: _instanceof(Uint8Array),
11341
11369
  width: number().int().positive(),
@@ -11367,8 +11395,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11367
11395
  * - `runtime` — main camera-serving engine (no idle TTL).
11368
11396
  * - `warm-override` — benchmark/test override held in the warm
11369
11397
  * cache; auto-disposed after the idle TTL.
11398
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11399
+ * multi-device, keyed by `deviceKey`) resolved
11400
+ * via `resolveDeviceFactory`. Runs alongside the
11401
+ * `runtime` engine on a DIFFERENT accelerator
11402
+ * (NPU / iGPU / Coral) — this is how the
11403
+ * Engines tab shows all pools running at once.
11370
11404
  */
11371
- kind: _enum(["runtime", "warm-override"]),
11405
+ kind: _enum([
11406
+ "runtime",
11407
+ "warm-override",
11408
+ "device-pool"
11409
+ ]),
11372
11410
  /** Native pid of the underlying Python pool (null when no pool). */
11373
11411
  poolPid: number().nullable(),
11374
11412
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11470,7 +11508,21 @@ var NativeCropResultSchema = object({
11470
11508
  /** Packed rgb (24-bit) pixels of the crop. */
11471
11509
  bytes: _instanceof(Uint8Array),
11472
11510
  width: number().int().positive(),
11473
- height: number().int().positive()
11511
+ height: number().int().positive(),
11512
+ /**
11513
+ * Which source served this crop, so a quality-sensitive consumer (the native
11514
+ * `keyFrame`) can reject a degraded fallback:
11515
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11516
+ * quality path).
11517
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11518
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11519
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11520
+ *
11521
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11522
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11523
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11524
+ */
11525
+ tier: _enum(["native", "ram-fullframe"]).optional()
11474
11526
  });
11475
11527
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11476
11528
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11710,7 +11762,14 @@ var RunnerCameraConfigSchema = object({
11710
11762
  * camera's detect node differs from its source-owner (P2d, gated by the
11711
11763
  * `remoteSourcingNodes` rollout setting).
11712
11764
  */
11713
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11765
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11766
+ /**
11767
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11768
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11769
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11770
+ * this only selects WHICH device pool of that node runs the session.
11771
+ */
11772
+ deviceKey: string().optional()
11714
11773
  });
11715
11774
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
11716
11775
  /**
@@ -11731,6 +11790,19 @@ var RunnerLocalLoadSchema = object({
11731
11790
  avgInferenceTimeMs: number(),
11732
11791
  /** Total queue depth across motion + detection queues. */
11733
11792
  queueDepthTotal: number(),
11793
+ /**
11794
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11795
+ * this runner currently has attached cameras on, so the orchestrator's second
11796
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11797
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11798
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11799
+ */
11800
+ devices: array(object({
11801
+ deviceKey: string(),
11802
+ backend: string(),
11803
+ attachedCameras: number(),
11804
+ queueDepthTotal: number()
11805
+ })).default([]),
11734
11806
  /** Hardware capability flags reported by this node. */
11735
11807
  hardware: object({
11736
11808
  hasGpu: boolean(),
@@ -13500,6 +13572,8 @@ var BaseDeviceProvider = class extends BaseAddon {
13500
13572
  return toDeviceSummary(device, this.addonId);
13501
13573
  }
13502
13574
  };
13575
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
13576
+ new Set(Object.values(DeviceType));
13503
13577
  /**
13504
13578
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13505
13579
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -15073,7 +15147,8 @@ var LinkedDeviceSchema = object({
15073
15147
  deviceId: number(),
15074
15148
  name: string(),
15075
15149
  location: string().nullable(),
15076
- features: array(string())
15150
+ features: array(string()),
15151
+ producesTrackedEvents: boolean().optional()
15077
15152
  });
15078
15153
  var SavedDeviceRowSchema = object({
15079
15154
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16703,6 +16778,7 @@ var TrackSchema = object({
16703
16778
  deviceId: number(),
16704
16779
  className: string(),
16705
16780
  label: string().optional(),
16781
+ producingDeviceName: string().optional(),
16706
16782
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16707
16783
  source: TrackSourceSchema.optional(),
16708
16784
  firstSeen: number(),
@@ -16840,7 +16916,8 @@ var MediaFileKindEnum = _enum([
16840
16916
  "fullFrameBoxed",
16841
16917
  "faceCrop",
16842
16918
  "plateCrop",
16843
- "keyFrame"
16919
+ "keyFrame",
16920
+ "keyFrameSmall"
16844
16921
  ]);
16845
16922
  var MediaFileSchema = object({
16846
16923
  key: string(),
@@ -17169,13 +17246,11 @@ var PipelineTemplateSchema = object({
17169
17246
  createdAt: string(),
17170
17247
  updatedAt: string()
17171
17248
  });
17172
- var AgentAddonConfigSchema = object({
17173
- enabled: boolean(),
17249
+ var DeviceStepConfigSchema = object({
17174
17250
  modelId: string().optional(),
17175
- settings: record(string(), unknown()).readonly()
17251
+ settings: record(string(), unknown()).optional()
17176
17252
  });
17177
17253
  var AgentPipelineSettingsSchema = object({
17178
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
17179
17254
  maxCameras: number().int().nonnegative().nullable().default(null),
17180
17255
  /** Per-node detection weight (relative share for the quota balancer). */
17181
17256
  detectWeight: number().positive().optional(),
@@ -17199,7 +17274,22 @@ var AgentPipelineSettingsSchema = object({
17199
17274
  * it already uses to reach the hub). Set this only when the auto-detected
17200
17275
  * address is wrong (multi-homed host, NAT, custom interface).
17201
17276
  */
17202
- reachableHost: string().optional()
17277
+ reachableHost: string().optional(),
17278
+ /**
17279
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
17280
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
17281
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
17282
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
17283
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
17284
+ * the default model/settings for every camera landing on that accelerator;
17285
+ * a stepId absent ⇒ the step uses that device's format default.
17286
+ */
17287
+ inferenceDevices: record(string(), object({
17288
+ enabled: boolean(),
17289
+ weight: number().positive().optional(),
17290
+ maxSessions: number().int().positive().optional(),
17291
+ steps: record(string(), DeviceStepConfigSchema).optional()
17292
+ })).optional()
17203
17293
  });
17204
17294
  var CameraPipelineForAgentSchema = object({
17205
17295
  steps: array(PipelineStepInputSchema).readonly(),
@@ -17209,14 +17299,13 @@ var CameraPipelineForAgentSchema = object({
17209
17299
  }).nullable()
17210
17300
  });
17211
17301
  var CameraStepOverridePatchSchema = object({
17212
- enabled: boolean().optional(),
17213
17302
  modelId: string().optional(),
17214
17303
  settings: record(string(), unknown()).readonly().optional()
17215
17304
  });
17216
17305
  var CameraPipelineSettingsSchema = object({
17217
17306
  pinnedAgentNodeId: string().optional(),
17218
17307
  stepToggles: record(string(), boolean()).optional(),
17219
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
17308
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
17220
17309
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
17221
17310
  });
17222
17311
  /**
@@ -17430,6 +17519,44 @@ var CameraStatusSchema = object({
17430
17519
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17431
17520
  fetchedAt: number()
17432
17521
  });
17522
+ var NodeInferenceDeviceSchema = object({
17523
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17524
+ key: string(),
17525
+ backend: string(),
17526
+ device: string(),
17527
+ format: _enum(MODEL_FORMATS),
17528
+ /** Whether the node's live probe reports the device as usable right now. */
17529
+ available: boolean(),
17530
+ /**
17531
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17532
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17533
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17534
+ * not a balanced target). An explicit stored value always wins; a stored-only
17535
+ * (unavailable) key keeps its stored value.
17536
+ */
17537
+ enabled: boolean(),
17538
+ /** Relative balancer weight for the enabled device (default 1). */
17539
+ weight: number(),
17540
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17541
+ maxSessions: number().nullable(),
17542
+ /** Object-detection model the executor defaults to for this deviceKey. */
17543
+ defaultModelId: string(),
17544
+ /**
17545
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17546
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17547
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17548
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17549
+ * available per format; this is the stored selection that becomes the
17550
+ * default for EVERY camera landing on this accelerator.
17551
+ */
17552
+ steps: record(string(), DeviceStepConfigSchema).optional()
17553
+ });
17554
+ var NodeInferenceDevicesSchema = object({
17555
+ nodeId: string(),
17556
+ /** False when the node's platform-probe was unreachable (no live device set). */
17557
+ reachable: boolean(),
17558
+ devices: array(NodeInferenceDeviceSchema).readonly()
17559
+ });
17433
17560
  method(object({
17434
17561
  deviceId: number(),
17435
17562
  agentNodeId: string()
@@ -17439,7 +17566,13 @@ method(object({
17439
17566
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17440
17567
  kind: "mutation",
17441
17568
  auth: "admin"
17442
- }), method(_void(), object({ migrated: number() }), {
17569
+ }), method(object({
17570
+ deviceId: number(),
17571
+ deviceKey: string()
17572
+ }), object({ success: literal(true) }), {
17573
+ kind: "mutation",
17574
+ auth: "admin"
17575
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17443
17576
  kind: "mutation",
17444
17577
  auth: "admin"
17445
17578
  }), method(_void(), array(PipelineAssignmentSchema).readonly()), method(object({ deviceId: number() }), PipelineAssignmentSchema.nullable()), method(_void(), array(AgentLoadSummarySchema).readonly()), method(_void(), GlobalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(object({ nodeId: string() }), CapabilityBindingsSchema), method(object({
@@ -17473,13 +17606,7 @@ method(object({
17473
17606
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17474
17607
  nodeId: string(),
17475
17608
  settings: AgentPipelineSettingsSchema
17476
- })).readonly()), method(object({
17477
- agentNodeId: string(),
17478
- defaults: record(string(), AgentAddonConfigSchema)
17479
- }), object({ success: literal(true) }), {
17480
- kind: "mutation",
17481
- auth: "admin"
17482
- }), method(object({ agentNodeId: string() }), object({
17609
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17483
17610
  success: boolean(),
17484
17611
  removed: boolean()
17485
17612
  }), {
@@ -17511,7 +17638,18 @@ method(object({
17511
17638
  }), object({ success: literal(true) }), {
17512
17639
  kind: "mutation",
17513
17640
  auth: "admin"
17514
- }), method(object({ agentNodeId: string() }), object({
17641
+ }), method(object({
17642
+ agentNodeId: string(),
17643
+ inferenceDevices: record(string(), object({
17644
+ enabled: boolean(),
17645
+ weight: number().positive().optional(),
17646
+ maxSessions: number().int().positive().optional(),
17647
+ steps: record(string(), DeviceStepConfigSchema).optional()
17648
+ }))
17649
+ }), object({ success: literal(true) }), {
17650
+ kind: "mutation",
17651
+ auth: "admin"
17652
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17515
17653
  success: literal(true),
17516
17654
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17517
17655
  effectiveModelId: string().nullable(),
@@ -17527,9 +17665,10 @@ method(object({
17527
17665
  }), object({ success: literal(true) }), {
17528
17666
  kind: "mutation",
17529
17667
  auth: "admin"
17530
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17668
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17531
17669
  deviceId: number(),
17532
17670
  agentNodeId: string(),
17671
+ deviceKey: string(),
17533
17672
  addonId: string(),
17534
17673
  patch: CameraStepOverridePatchSchema.nullable()
17535
17674
  }), object({ success: literal(true) }), {
@@ -17566,14 +17705,13 @@ method(object({
17566
17705
  });
17567
17706
  /**
17568
17707
  * server-management — per-NODE singleton capability for a node's ROOT
17569
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17570
- * agents).
17708
+ * package lifecycle (runtime-updatable node packages).
17571
17709
  *
17572
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17573
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17574
- * version describes the node. Updates install into
17575
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17576
- * starter (probation boot + auto-rollback to N-1).
17710
+ * Every node role runs the SAME root package (`@camstack/server`), which
17711
+ * carries the whole software stack in its npm dep tree, so ONE version
17712
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17713
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17714
+ * no auto-rollback).
17577
17715
  *
17578
17716
  * Providers:
17579
17717
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17681,7 +17819,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17681
17819
  /** Explicit target version; omitted = latest from the registry. */
17682
17820
  version: string().optional() }), ServerUpdateActionResultSchema, {
17683
17821
  kind: "mutation",
17684
- auth: "admin"
17822
+ auth: "admin",
17823
+ timeoutMs: 16 * 6e4
17685
17824
  }), method(_void(), ServerUpdateActionResultSchema, {
17686
17825
  kind: "mutation",
17687
17826
  auth: "admin"
@@ -18776,22 +18915,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18776
18915
  var RestartAddonResultSchema = unknown();
18777
18916
  var InstallPackageResultSchema = unknown();
18778
18917
  var ReloadPackagesResultSchema = unknown();
18779
- /**
18780
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18781
- * server restarts so the admin UI can react to the `restartingAt`
18782
- * timestamp (shows reconnect overlay). The transition from
18783
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18784
- * `system.restart-completed` event after the new process boots.
18785
- *
18786
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18787
- */
18788
- var UpdateFrameworkPackageResultSchema = object({
18789
- packageName: string(),
18790
- fromVersion: string(),
18791
- toVersion: string(),
18792
- /** Ms-epoch the server scheduled its self-restart. */
18793
- restartingAt: number()
18794
- });
18795
18918
  var BulkUpdateItemStatusSchema = _enum([
18796
18919
  "queued",
18797
18920
  "updating",
@@ -18919,13 +19042,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18919
19042
  }), object({ success: literal(true) }), {
18920
19043
  kind: "mutation",
18921
19044
  auth: "admin"
18922
- }), method(object({
18923
- packageName: string().min(1),
18924
- version: string().optional(),
18925
- deferRestart: boolean().optional()
18926
- }), UpdateFrameworkPackageResultSchema, {
18927
- kind: "mutation",
18928
- auth: "admin"
18929
19045
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18930
19046
  kind: "mutation",
18931
19047
  auth: "admin"
@@ -19791,10 +19907,10 @@ var TopologyCategorySchema = object({
19791
19907
  addons: array(TopologyCategoryAddonSchema).readonly()
19792
19908
  });
19793
19909
  /**
19794
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19795
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19796
- * version visibility for the Server management surface. Nullable: offline
19797
- * rows and pre-phase-2 nodes report none.
19910
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19911
+ * root package for every node role) as reported by its `registerNode`
19912
+ * manifest — version visibility for the Server management surface. Nullable:
19913
+ * offline rows and nodes that never reported one.
19798
19914
  */
19799
19915
  var TopologyRootPackageSchema = object({
19800
19916
  name: string(),
@@ -20182,17 +20298,28 @@ var PlatformScoreSchema = object({
20182
20298
  format: _enum([
20183
20299
  "onnx",
20184
20300
  "coreml",
20185
- "openvino"
20301
+ "openvino",
20302
+ "tflite"
20186
20303
  ]),
20187
20304
  score: number(),
20188
20305
  reason: string(),
20189
20306
  available: boolean()
20190
20307
  });
20308
+ var InferenceDeviceDescriptorSchema = object({
20309
+ key: string(),
20310
+ backend: string(),
20311
+ device: string(),
20312
+ format: ModelFormatSchema,
20313
+ runtime: literal("python"),
20314
+ score: number(),
20315
+ available: boolean()
20316
+ });
20191
20317
  var PlatformCapabilitiesSchema = object({
20192
20318
  hardware: HardwareInfoSchema,
20193
20319
  scores: array(PlatformScoreSchema).readonly(),
20194
20320
  bestScore: PlatformScoreSchema,
20195
- pythonPath: string().nullable()
20321
+ pythonPath: string().nullable(),
20322
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
20196
20323
  });
20197
20324
  var ModelRequirementSchema = object({
20198
20325
  modelId: string(),
@@ -21113,12 +21240,6 @@ Object.freeze({
21113
21240
  addonId: null,
21114
21241
  access: "delete"
21115
21242
  },
21116
- "addons.updateFrameworkPackage": {
21117
- capName: "addons",
21118
- capScope: "system",
21119
- addonId: null,
21120
- access: "create"
21121
- },
21122
21243
  "addons.updatePackage": {
21123
21244
  capName: "addons",
21124
21245
  capScope: "system",
@@ -23891,12 +24012,6 @@ Object.freeze({
23891
24012
  addonId: null,
23892
24013
  access: "view"
23893
24014
  },
23894
- "pipelineExecutor.reprobeEngine": {
23895
- capName: "pipeline-executor",
23896
- capScope: "system",
23897
- addonId: null,
23898
- access: "create"
23899
- },
23900
24015
  "pipelineExecutor.runAudioTest": {
23901
24016
  capName: "pipeline-executor",
23902
24017
  capScope: "system",
@@ -24047,6 +24162,12 @@ Object.freeze({
24047
24162
  addonId: null,
24048
24163
  access: "view"
24049
24164
  },
24165
+ "pipelineOrchestrator.getNodeInferenceDevices": {
24166
+ capName: "pipeline-orchestrator",
24167
+ capScope: "system",
24168
+ addonId: null,
24169
+ access: "view"
24170
+ },
24050
24171
  "pipelineOrchestrator.getPipelineAssignment": {
24051
24172
  capName: "pipeline-orchestrator",
24052
24173
  capScope: "system",
@@ -24059,6 +24180,12 @@ Object.freeze({
24059
24180
  addonId: null,
24060
24181
  access: "view"
24061
24182
  },
24183
+ "pipelineOrchestrator.getPipelineDevicePin": {
24184
+ capName: "pipeline-orchestrator",
24185
+ capScope: "system",
24186
+ addonId: null,
24187
+ access: "view"
24188
+ },
24062
24189
  "pipelineOrchestrator.listAgentSettings": {
24063
24190
  capName: "pipeline-orchestrator",
24064
24191
  capScope: "system",
@@ -24101,19 +24228,19 @@ Object.freeze({
24101
24228
  addonId: null,
24102
24229
  access: "create"
24103
24230
  },
24104
- "pipelineOrchestrator.setAgentAddonDefaults": {
24231
+ "pipelineOrchestrator.setAgentCapabilities": {
24105
24232
  capName: "pipeline-orchestrator",
24106
24233
  capScope: "system",
24107
24234
  addonId: null,
24108
24235
  access: "create"
24109
24236
  },
24110
- "pipelineOrchestrator.setAgentCapabilities": {
24237
+ "pipelineOrchestrator.setAgentDetectWeight": {
24111
24238
  capName: "pipeline-orchestrator",
24112
24239
  capScope: "system",
24113
24240
  addonId: null,
24114
24241
  access: "create"
24115
24242
  },
24116
- "pipelineOrchestrator.setAgentDetectWeight": {
24243
+ "pipelineOrchestrator.setAgentInferenceDevices": {
24117
24244
  capName: "pipeline-orchestrator",
24118
24245
  capScope: "system",
24119
24246
  addonId: null,
@@ -24155,6 +24282,12 @@ Object.freeze({
24155
24282
  addonId: null,
24156
24283
  access: "create"
24157
24284
  },
24285
+ "pipelineOrchestrator.setPipelineDevicePin": {
24286
+ capName: "pipeline-orchestrator",
24287
+ capScope: "system",
24288
+ addonId: null,
24289
+ access: "create"
24290
+ },
24158
24291
  "pipelineOrchestrator.unassignAudio": {
24159
24292
  capName: "pipeline-orchestrator",
24160
24293
  capScope: "system",
@@ -25707,32 +25840,6 @@ Object.freeze({
25707
25840
  "network-access": "ingress",
25708
25841
  "smtp-provider": "email"
25709
25842
  });
25710
- var frameworkSwapPackageSchema = object({
25711
- name: string(),
25712
- stagedPath: string(),
25713
- backupPath: string(),
25714
- toVersion: string(),
25715
- fromVersion: string().nullable()
25716
- });
25717
- object({
25718
- jobId: string(),
25719
- taskId: string(),
25720
- packages: array(frameworkSwapPackageSchema),
25721
- requestedAtMs: number(),
25722
- schemaVersion: literal(1)
25723
- });
25724
- object({
25725
- jobId: string(),
25726
- taskId: string(),
25727
- backups: array(object({
25728
- name: string(),
25729
- backupPath: string(),
25730
- livePath: string()
25731
- })),
25732
- appliedAtMs: number(),
25733
- bootAttempts: number(),
25734
- schemaVersion: literal(1)
25735
- });
25736
25843
  //#endregion
25737
25844
  //#region src/onvif-camera.ts
25738
25845
  var onvifCameraSchema = object({
package/dist/addon.mjs CHANGED
@@ -7084,6 +7084,17 @@ var ModelCatalogEntrySchema = object({
7084
7084
  "imagenet",
7085
7085
  "none"
7086
7086
  ]).optional(),
7087
+ /**
7088
+ * The model already applies softmax IN-GRAPH — its raw output is a
7089
+ * probability distribution, not logits. When set, the `softmax`
7090
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7091
+ * probability vector collapses it toward uniform (top-1 score craters far
7092
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7093
+ * the output is raw logits and the postprocessor applies softmax (the normal
7094
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7095
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7096
+ */
7097
+ outputProbabilities: boolean().optional(),
7087
7098
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7088
7099
  /**
7089
7100
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11267,10 +11278,7 @@ var ConfigUISchemaNullableBridge = custom();
11267
11278
  var InferenceCapabilitiesBridge = custom();
11268
11279
  var ModelAvailabilityListBridge = custom();
11269
11280
  var PipelineRunResultBridge = custom();
11270
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11271
- kind: "mutation",
11272
- auth: "admin"
11273
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11281
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11274
11282
  modelId: string(),
11275
11283
  settings: record(string(), unknown()).readonly()
11276
11284
  }))), method(object({ steps: record(string(), object({
@@ -11330,13 +11338,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11330
11338
  * (inputClasses ≠ null) are skipped and served per-track via
11331
11339
  * pipelineRunner.runDetailSubtree (two-plane design).
11332
11340
  */
11333
- plane: _enum(["full", "frame"]).optional()
11341
+ plane: _enum(["full", "frame"]).optional(),
11342
+ /**
11343
+ * Inference-device selector (Phase 2 multi-device). Format
11344
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11345
+ * Omitted ⇒ the runner's default device (current single-engine
11346
+ * behaviour). Selects WHICH device pool of the node runs the call.
11347
+ */
11348
+ deviceKey: string().optional()
11334
11349
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11335
11350
  engine: PipelineEngineChoiceSchema.optional(),
11336
11351
  steps: array(PipelineStepInputSchema).min(1),
11337
11352
  frames: array(FrameInputSchema).min(1).max(255),
11338
11353
  deviceId: number().optional(),
11339
- sessionId: string().optional()
11354
+ sessionId: string().optional(),
11355
+ /**
11356
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11357
+ * the batch to the Python pool's bench preprocess cache
11358
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11359
+ * preprocessed ONCE and every later inference is a pure-inference cache
11360
+ * hit — the sustained-throughput run measures inference, not
11361
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11362
+ * full preprocess every call, correct). Fresh per sustained run;
11363
+ * released via `uncacheFrame`.
11364
+ */
11365
+ frameId: number().int().nonnegative().optional(),
11366
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11367
+ deviceKey: string().optional()
11340
11368
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11341
11369
  data: _instanceof(Uint8Array),
11342
11370
  width: number().int().positive(),
@@ -11368,8 +11396,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11368
11396
  * - `runtime` — main camera-serving engine (no idle TTL).
11369
11397
  * - `warm-override` — benchmark/test override held in the warm
11370
11398
  * cache; auto-disposed after the idle TTL.
11399
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11400
+ * multi-device, keyed by `deviceKey`) resolved
11401
+ * via `resolveDeviceFactory`. Runs alongside the
11402
+ * `runtime` engine on a DIFFERENT accelerator
11403
+ * (NPU / iGPU / Coral) — this is how the
11404
+ * Engines tab shows all pools running at once.
11371
11405
  */
11372
- kind: _enum(["runtime", "warm-override"]),
11406
+ kind: _enum([
11407
+ "runtime",
11408
+ "warm-override",
11409
+ "device-pool"
11410
+ ]),
11373
11411
  /** Native pid of the underlying Python pool (null when no pool). */
11374
11412
  poolPid: number().nullable(),
11375
11413
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11471,7 +11509,21 @@ var NativeCropResultSchema = object({
11471
11509
  /** Packed rgb (24-bit) pixels of the crop. */
11472
11510
  bytes: _instanceof(Uint8Array),
11473
11511
  width: number().int().positive(),
11474
- height: number().int().positive()
11512
+ height: number().int().positive(),
11513
+ /**
11514
+ * Which source served this crop, so a quality-sensitive consumer (the native
11515
+ * `keyFrame`) can reject a degraded fallback:
11516
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11517
+ * quality path).
11518
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11519
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11520
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11521
+ *
11522
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11523
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11524
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11525
+ */
11526
+ tier: _enum(["native", "ram-fullframe"]).optional()
11475
11527
  });
11476
11528
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11477
11529
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11711,7 +11763,14 @@ var RunnerCameraConfigSchema = object({
11711
11763
  * camera's detect node differs from its source-owner (P2d, gated by the
11712
11764
  * `remoteSourcingNodes` rollout setting).
11713
11765
  */
11714
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11766
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11767
+ /**
11768
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11769
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11770
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11771
+ * this only selects WHICH device pool of that node runs the session.
11772
+ */
11773
+ deviceKey: string().optional()
11715
11774
  });
11716
11775
  motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
11717
11776
  /**
@@ -11732,6 +11791,19 @@ var RunnerLocalLoadSchema = object({
11732
11791
  avgInferenceTimeMs: number(),
11733
11792
  /** Total queue depth across motion + detection queues. */
11734
11793
  queueDepthTotal: number(),
11794
+ /**
11795
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11796
+ * this runner currently has attached cameras on, so the orchestrator's second
11797
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11798
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11799
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11800
+ */
11801
+ devices: array(object({
11802
+ deviceKey: string(),
11803
+ backend: string(),
11804
+ attachedCameras: number(),
11805
+ queueDepthTotal: number()
11806
+ })).default([]),
11735
11807
  /** Hardware capability flags reported by this node. */
11736
11808
  hardware: object({
11737
11809
  hasGpu: boolean(),
@@ -13501,6 +13573,8 @@ var BaseDeviceProvider = class extends BaseAddon {
13501
13573
  return toDeviceSummary(device, this.addonId);
13502
13574
  }
13503
13575
  };
13576
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
13577
+ new Set(Object.values(DeviceType));
13504
13578
  /**
13505
13579
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13506
13580
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -15074,7 +15148,8 @@ var LinkedDeviceSchema = object({
15074
15148
  deviceId: number(),
15075
15149
  name: string(),
15076
15150
  location: string().nullable(),
15077
- features: array(string())
15151
+ features: array(string()),
15152
+ producesTrackedEvents: boolean().optional()
15078
15153
  });
15079
15154
  var SavedDeviceRowSchema = object({
15080
15155
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16704,6 +16779,7 @@ var TrackSchema = object({
16704
16779
  deviceId: number(),
16705
16780
  className: string(),
16706
16781
  label: string().optional(),
16782
+ producingDeviceName: string().optional(),
16707
16783
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16708
16784
  source: TrackSourceSchema.optional(),
16709
16785
  firstSeen: number(),
@@ -16841,7 +16917,8 @@ var MediaFileKindEnum = _enum([
16841
16917
  "fullFrameBoxed",
16842
16918
  "faceCrop",
16843
16919
  "plateCrop",
16844
- "keyFrame"
16920
+ "keyFrame",
16921
+ "keyFrameSmall"
16845
16922
  ]);
16846
16923
  var MediaFileSchema = object({
16847
16924
  key: string(),
@@ -17170,13 +17247,11 @@ var PipelineTemplateSchema = object({
17170
17247
  createdAt: string(),
17171
17248
  updatedAt: string()
17172
17249
  });
17173
- var AgentAddonConfigSchema = object({
17174
- enabled: boolean(),
17250
+ var DeviceStepConfigSchema = object({
17175
17251
  modelId: string().optional(),
17176
- settings: record(string(), unknown()).readonly()
17252
+ settings: record(string(), unknown()).optional()
17177
17253
  });
17178
17254
  var AgentPipelineSettingsSchema = object({
17179
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
17180
17255
  maxCameras: number().int().nonnegative().nullable().default(null),
17181
17256
  /** Per-node detection weight (relative share for the quota balancer). */
17182
17257
  detectWeight: number().positive().optional(),
@@ -17200,7 +17275,22 @@ var AgentPipelineSettingsSchema = object({
17200
17275
  * it already uses to reach the hub). Set this only when the auto-detected
17201
17276
  * address is wrong (multi-homed host, NAT, custom interface).
17202
17277
  */
17203
- reachableHost: string().optional()
17278
+ reachableHost: string().optional(),
17279
+ /**
17280
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
17281
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
17282
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
17283
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
17284
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
17285
+ * the default model/settings for every camera landing on that accelerator;
17286
+ * a stepId absent ⇒ the step uses that device's format default.
17287
+ */
17288
+ inferenceDevices: record(string(), object({
17289
+ enabled: boolean(),
17290
+ weight: number().positive().optional(),
17291
+ maxSessions: number().int().positive().optional(),
17292
+ steps: record(string(), DeviceStepConfigSchema).optional()
17293
+ })).optional()
17204
17294
  });
17205
17295
  var CameraPipelineForAgentSchema = object({
17206
17296
  steps: array(PipelineStepInputSchema).readonly(),
@@ -17210,14 +17300,13 @@ var CameraPipelineForAgentSchema = object({
17210
17300
  }).nullable()
17211
17301
  });
17212
17302
  var CameraStepOverridePatchSchema = object({
17213
- enabled: boolean().optional(),
17214
17303
  modelId: string().optional(),
17215
17304
  settings: record(string(), unknown()).readonly().optional()
17216
17305
  });
17217
17306
  var CameraPipelineSettingsSchema = object({
17218
17307
  pinnedAgentNodeId: string().optional(),
17219
17308
  stepToggles: record(string(), boolean()).optional(),
17220
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
17309
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
17221
17310
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
17222
17311
  });
17223
17312
  /**
@@ -17431,6 +17520,44 @@ var CameraStatusSchema = object({
17431
17520
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17432
17521
  fetchedAt: number()
17433
17522
  });
17523
+ var NodeInferenceDeviceSchema = object({
17524
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17525
+ key: string(),
17526
+ backend: string(),
17527
+ device: string(),
17528
+ format: _enum(MODEL_FORMATS),
17529
+ /** Whether the node's live probe reports the device as usable right now. */
17530
+ available: boolean(),
17531
+ /**
17532
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17533
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17534
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17535
+ * not a balanced target). An explicit stored value always wins; a stored-only
17536
+ * (unavailable) key keeps its stored value.
17537
+ */
17538
+ enabled: boolean(),
17539
+ /** Relative balancer weight for the enabled device (default 1). */
17540
+ weight: number(),
17541
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17542
+ maxSessions: number().nullable(),
17543
+ /** Object-detection model the executor defaults to for this deviceKey. */
17544
+ defaultModelId: string(),
17545
+ /**
17546
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17547
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17548
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17549
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17550
+ * available per format; this is the stored selection that becomes the
17551
+ * default for EVERY camera landing on this accelerator.
17552
+ */
17553
+ steps: record(string(), DeviceStepConfigSchema).optional()
17554
+ });
17555
+ var NodeInferenceDevicesSchema = object({
17556
+ nodeId: string(),
17557
+ /** False when the node's platform-probe was unreachable (no live device set). */
17558
+ reachable: boolean(),
17559
+ devices: array(NodeInferenceDeviceSchema).readonly()
17560
+ });
17434
17561
  method(object({
17435
17562
  deviceId: number(),
17436
17563
  agentNodeId: string()
@@ -17440,7 +17567,13 @@ method(object({
17440
17567
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17441
17568
  kind: "mutation",
17442
17569
  auth: "admin"
17443
- }), method(_void(), object({ migrated: number() }), {
17570
+ }), method(object({
17571
+ deviceId: number(),
17572
+ deviceKey: string()
17573
+ }), object({ success: literal(true) }), {
17574
+ kind: "mutation",
17575
+ auth: "admin"
17576
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17444
17577
  kind: "mutation",
17445
17578
  auth: "admin"
17446
17579
  }), method(_void(), array(PipelineAssignmentSchema).readonly()), method(object({ deviceId: number() }), PipelineAssignmentSchema.nullable()), method(_void(), array(AgentLoadSummarySchema).readonly()), method(_void(), GlobalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(object({ nodeId: string() }), CapabilityBindingsSchema), method(object({
@@ -17474,13 +17607,7 @@ method(object({
17474
17607
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17475
17608
  nodeId: string(),
17476
17609
  settings: AgentPipelineSettingsSchema
17477
- })).readonly()), method(object({
17478
- agentNodeId: string(),
17479
- defaults: record(string(), AgentAddonConfigSchema)
17480
- }), object({ success: literal(true) }), {
17481
- kind: "mutation",
17482
- auth: "admin"
17483
- }), method(object({ agentNodeId: string() }), object({
17610
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17484
17611
  success: boolean(),
17485
17612
  removed: boolean()
17486
17613
  }), {
@@ -17512,7 +17639,18 @@ method(object({
17512
17639
  }), object({ success: literal(true) }), {
17513
17640
  kind: "mutation",
17514
17641
  auth: "admin"
17515
- }), method(object({ agentNodeId: string() }), object({
17642
+ }), method(object({
17643
+ agentNodeId: string(),
17644
+ inferenceDevices: record(string(), object({
17645
+ enabled: boolean(),
17646
+ weight: number().positive().optional(),
17647
+ maxSessions: number().int().positive().optional(),
17648
+ steps: record(string(), DeviceStepConfigSchema).optional()
17649
+ }))
17650
+ }), object({ success: literal(true) }), {
17651
+ kind: "mutation",
17652
+ auth: "admin"
17653
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17516
17654
  success: literal(true),
17517
17655
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17518
17656
  effectiveModelId: string().nullable(),
@@ -17528,9 +17666,10 @@ method(object({
17528
17666
  }), object({ success: literal(true) }), {
17529
17667
  kind: "mutation",
17530
17668
  auth: "admin"
17531
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17669
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17532
17670
  deviceId: number(),
17533
17671
  agentNodeId: string(),
17672
+ deviceKey: string(),
17534
17673
  addonId: string(),
17535
17674
  patch: CameraStepOverridePatchSchema.nullable()
17536
17675
  }), object({ success: literal(true) }), {
@@ -17567,14 +17706,13 @@ method(object({
17567
17706
  });
17568
17707
  /**
17569
17708
  * server-management — per-NODE singleton capability for a node's ROOT
17570
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17571
- * agents).
17709
+ * package lifecycle (runtime-updatable node packages).
17572
17710
  *
17573
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17574
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17575
- * version describes the node. Updates install into
17576
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17577
- * starter (probation boot + auto-rollback to N-1).
17711
+ * Every node role runs the SAME root package (`@camstack/server`), which
17712
+ * carries the whole software stack in its npm dep tree, so ONE version
17713
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17714
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17715
+ * no auto-rollback).
17578
17716
  *
17579
17717
  * Providers:
17580
17718
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17682,7 +17820,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17682
17820
  /** Explicit target version; omitted = latest from the registry. */
17683
17821
  version: string().optional() }), ServerUpdateActionResultSchema, {
17684
17822
  kind: "mutation",
17685
- auth: "admin"
17823
+ auth: "admin",
17824
+ timeoutMs: 16 * 6e4
17686
17825
  }), method(_void(), ServerUpdateActionResultSchema, {
17687
17826
  kind: "mutation",
17688
17827
  auth: "admin"
@@ -18777,22 +18916,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18777
18916
  var RestartAddonResultSchema = unknown();
18778
18917
  var InstallPackageResultSchema = unknown();
18779
18918
  var ReloadPackagesResultSchema = unknown();
18780
- /**
18781
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18782
- * server restarts so the admin UI can react to the `restartingAt`
18783
- * timestamp (shows reconnect overlay). The transition from
18784
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18785
- * `system.restart-completed` event after the new process boots.
18786
- *
18787
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18788
- */
18789
- var UpdateFrameworkPackageResultSchema = object({
18790
- packageName: string(),
18791
- fromVersion: string(),
18792
- toVersion: string(),
18793
- /** Ms-epoch the server scheduled its self-restart. */
18794
- restartingAt: number()
18795
- });
18796
18919
  var BulkUpdateItemStatusSchema = _enum([
18797
18920
  "queued",
18798
18921
  "updating",
@@ -18920,13 +19043,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18920
19043
  }), object({ success: literal(true) }), {
18921
19044
  kind: "mutation",
18922
19045
  auth: "admin"
18923
- }), method(object({
18924
- packageName: string().min(1),
18925
- version: string().optional(),
18926
- deferRestart: boolean().optional()
18927
- }), UpdateFrameworkPackageResultSchema, {
18928
- kind: "mutation",
18929
- auth: "admin"
18930
19046
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18931
19047
  kind: "mutation",
18932
19048
  auth: "admin"
@@ -19792,10 +19908,10 @@ var TopologyCategorySchema = object({
19792
19908
  addons: array(TopologyCategoryAddonSchema).readonly()
19793
19909
  });
19794
19910
  /**
19795
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19796
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19797
- * version visibility for the Server management surface. Nullable: offline
19798
- * rows and pre-phase-2 nodes report none.
19911
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19912
+ * root package for every node role) as reported by its `registerNode`
19913
+ * manifest — version visibility for the Server management surface. Nullable:
19914
+ * offline rows and nodes that never reported one.
19799
19915
  */
19800
19916
  var TopologyRootPackageSchema = object({
19801
19917
  name: string(),
@@ -20183,17 +20299,28 @@ var PlatformScoreSchema = object({
20183
20299
  format: _enum([
20184
20300
  "onnx",
20185
20301
  "coreml",
20186
- "openvino"
20302
+ "openvino",
20303
+ "tflite"
20187
20304
  ]),
20188
20305
  score: number(),
20189
20306
  reason: string(),
20190
20307
  available: boolean()
20191
20308
  });
20309
+ var InferenceDeviceDescriptorSchema = object({
20310
+ key: string(),
20311
+ backend: string(),
20312
+ device: string(),
20313
+ format: ModelFormatSchema,
20314
+ runtime: literal("python"),
20315
+ score: number(),
20316
+ available: boolean()
20317
+ });
20192
20318
  var PlatformCapabilitiesSchema = object({
20193
20319
  hardware: HardwareInfoSchema,
20194
20320
  scores: array(PlatformScoreSchema).readonly(),
20195
20321
  bestScore: PlatformScoreSchema,
20196
- pythonPath: string().nullable()
20322
+ pythonPath: string().nullable(),
20323
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
20197
20324
  });
20198
20325
  var ModelRequirementSchema = object({
20199
20326
  modelId: string(),
@@ -21114,12 +21241,6 @@ Object.freeze({
21114
21241
  addonId: null,
21115
21242
  access: "delete"
21116
21243
  },
21117
- "addons.updateFrameworkPackage": {
21118
- capName: "addons",
21119
- capScope: "system",
21120
- addonId: null,
21121
- access: "create"
21122
- },
21123
21244
  "addons.updatePackage": {
21124
21245
  capName: "addons",
21125
21246
  capScope: "system",
@@ -23892,12 +24013,6 @@ Object.freeze({
23892
24013
  addonId: null,
23893
24014
  access: "view"
23894
24015
  },
23895
- "pipelineExecutor.reprobeEngine": {
23896
- capName: "pipeline-executor",
23897
- capScope: "system",
23898
- addonId: null,
23899
- access: "create"
23900
- },
23901
24016
  "pipelineExecutor.runAudioTest": {
23902
24017
  capName: "pipeline-executor",
23903
24018
  capScope: "system",
@@ -24048,6 +24163,12 @@ Object.freeze({
24048
24163
  addonId: null,
24049
24164
  access: "view"
24050
24165
  },
24166
+ "pipelineOrchestrator.getNodeInferenceDevices": {
24167
+ capName: "pipeline-orchestrator",
24168
+ capScope: "system",
24169
+ addonId: null,
24170
+ access: "view"
24171
+ },
24051
24172
  "pipelineOrchestrator.getPipelineAssignment": {
24052
24173
  capName: "pipeline-orchestrator",
24053
24174
  capScope: "system",
@@ -24060,6 +24181,12 @@ Object.freeze({
24060
24181
  addonId: null,
24061
24182
  access: "view"
24062
24183
  },
24184
+ "pipelineOrchestrator.getPipelineDevicePin": {
24185
+ capName: "pipeline-orchestrator",
24186
+ capScope: "system",
24187
+ addonId: null,
24188
+ access: "view"
24189
+ },
24063
24190
  "pipelineOrchestrator.listAgentSettings": {
24064
24191
  capName: "pipeline-orchestrator",
24065
24192
  capScope: "system",
@@ -24102,19 +24229,19 @@ Object.freeze({
24102
24229
  addonId: null,
24103
24230
  access: "create"
24104
24231
  },
24105
- "pipelineOrchestrator.setAgentAddonDefaults": {
24232
+ "pipelineOrchestrator.setAgentCapabilities": {
24106
24233
  capName: "pipeline-orchestrator",
24107
24234
  capScope: "system",
24108
24235
  addonId: null,
24109
24236
  access: "create"
24110
24237
  },
24111
- "pipelineOrchestrator.setAgentCapabilities": {
24238
+ "pipelineOrchestrator.setAgentDetectWeight": {
24112
24239
  capName: "pipeline-orchestrator",
24113
24240
  capScope: "system",
24114
24241
  addonId: null,
24115
24242
  access: "create"
24116
24243
  },
24117
- "pipelineOrchestrator.setAgentDetectWeight": {
24244
+ "pipelineOrchestrator.setAgentInferenceDevices": {
24118
24245
  capName: "pipeline-orchestrator",
24119
24246
  capScope: "system",
24120
24247
  addonId: null,
@@ -24156,6 +24283,12 @@ Object.freeze({
24156
24283
  addonId: null,
24157
24284
  access: "create"
24158
24285
  },
24286
+ "pipelineOrchestrator.setPipelineDevicePin": {
24287
+ capName: "pipeline-orchestrator",
24288
+ capScope: "system",
24289
+ addonId: null,
24290
+ access: "create"
24291
+ },
24159
24292
  "pipelineOrchestrator.unassignAudio": {
24160
24293
  capName: "pipeline-orchestrator",
24161
24294
  capScope: "system",
@@ -25708,32 +25841,6 @@ Object.freeze({
25708
25841
  "network-access": "ingress",
25709
25842
  "smtp-provider": "email"
25710
25843
  });
25711
- var frameworkSwapPackageSchema = object({
25712
- name: string(),
25713
- stagedPath: string(),
25714
- backupPath: string(),
25715
- toVersion: string(),
25716
- fromVersion: string().nullable()
25717
- });
25718
- object({
25719
- jobId: string(),
25720
- taskId: string(),
25721
- packages: array(frameworkSwapPackageSchema),
25722
- requestedAtMs: number(),
25723
- schemaVersion: literal(1)
25724
- });
25725
- object({
25726
- jobId: string(),
25727
- taskId: string(),
25728
- backups: array(object({
25729
- name: string(),
25730
- backupPath: string(),
25731
- livePath: string()
25732
- })),
25733
- appliedAtMs: number(),
25734
- bootAttempts: number(),
25735
- schemaVersion: literal(1)
25736
- });
25737
25844
  //#endregion
25738
25845
  //#region src/onvif-camera.ts
25739
25846
  var onvifCameraSchema = object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-onvif",
3
- "version": "1.1.30",
3
+ "version": "1.2.1",
4
4
  "description": "ONVIF camera device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",