@camstack/addon-provider-hikvision 1.1.29 → 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
@@ -7079,6 +7079,17 @@ var ModelCatalogEntrySchema = object({
7079
7079
  "imagenet",
7080
7080
  "none"
7081
7081
  ]).optional(),
7082
+ /**
7083
+ * The model already applies softmax IN-GRAPH — its raw output is a
7084
+ * probability distribution, not logits. When set, the `softmax`
7085
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7086
+ * probability vector collapses it toward uniform (top-1 score craters far
7087
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7088
+ * the output is raw logits and the postprocessor applies softmax (the normal
7089
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7090
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7091
+ */
7092
+ outputProbabilities: boolean().optional(),
7082
7093
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7083
7094
  /**
7084
7095
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12649,10 +12660,7 @@ var ConfigUISchemaNullableBridge = custom();
12649
12660
  var InferenceCapabilitiesBridge = custom();
12650
12661
  var ModelAvailabilityListBridge = custom();
12651
12662
  var PipelineRunResultBridge = custom();
12652
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12653
- kind: "mutation",
12654
- auth: "admin"
12655
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12663
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12656
12664
  modelId: string(),
12657
12665
  settings: record(string(), unknown()).readonly()
12658
12666
  }))), method(object({ steps: record(string(), object({
@@ -12712,13 +12720,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12712
12720
  * (inputClasses ≠ null) are skipped and served per-track via
12713
12721
  * pipelineRunner.runDetailSubtree (two-plane design).
12714
12722
  */
12715
- plane: _enum(["full", "frame"]).optional()
12723
+ plane: _enum(["full", "frame"]).optional(),
12724
+ /**
12725
+ * Inference-device selector (Phase 2 multi-device). Format
12726
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12727
+ * Omitted ⇒ the runner's default device (current single-engine
12728
+ * behaviour). Selects WHICH device pool of the node runs the call.
12729
+ */
12730
+ deviceKey: string().optional()
12716
12731
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12717
12732
  engine: PipelineEngineChoiceSchema.optional(),
12718
12733
  steps: array(PipelineStepInputSchema).min(1),
12719
12734
  frames: array(FrameInputSchema).min(1).max(255),
12720
12735
  deviceId: number().optional(),
12721
- sessionId: string().optional()
12736
+ sessionId: string().optional(),
12737
+ /**
12738
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12739
+ * the batch to the Python pool's bench preprocess cache
12740
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12741
+ * preprocessed ONCE and every later inference is a pure-inference cache
12742
+ * hit — the sustained-throughput run measures inference, not
12743
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12744
+ * full preprocess every call, correct). Fresh per sustained run;
12745
+ * released via `uncacheFrame`.
12746
+ */
12747
+ frameId: number().int().nonnegative().optional(),
12748
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12749
+ deviceKey: string().optional()
12722
12750
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12723
12751
  data: _instanceof(Uint8Array),
12724
12752
  width: number().int().positive(),
@@ -12750,8 +12778,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12750
12778
  * - `runtime` — main camera-serving engine (no idle TTL).
12751
12779
  * - `warm-override` — benchmark/test override held in the warm
12752
12780
  * cache; auto-disposed after the idle TTL.
12781
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12782
+ * multi-device, keyed by `deviceKey`) resolved
12783
+ * via `resolveDeviceFactory`. Runs alongside the
12784
+ * `runtime` engine on a DIFFERENT accelerator
12785
+ * (NPU / iGPU / Coral) — this is how the
12786
+ * Engines tab shows all pools running at once.
12753
12787
  */
12754
- kind: _enum(["runtime", "warm-override"]),
12788
+ kind: _enum([
12789
+ "runtime",
12790
+ "warm-override",
12791
+ "device-pool"
12792
+ ]),
12755
12793
  /** Native pid of the underlying Python pool (null when no pool). */
12756
12794
  poolPid: number().nullable(),
12757
12795
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12886,7 +12924,21 @@ var NativeCropResultSchema = object({
12886
12924
  /** Packed rgb (24-bit) pixels of the crop. */
12887
12925
  bytes: _instanceof(Uint8Array),
12888
12926
  width: number().int().positive(),
12889
- height: number().int().positive()
12927
+ height: number().int().positive(),
12928
+ /**
12929
+ * Which source served this crop, so a quality-sensitive consumer (the native
12930
+ * `keyFrame`) can reject a degraded fallback:
12931
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
12932
+ * quality path).
12933
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
12934
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
12935
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
12936
+ *
12937
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
12938
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
12939
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
12940
+ */
12941
+ tier: _enum(["native", "ram-fullframe"]).optional()
12890
12942
  });
12891
12943
  /** Parent detection context passed to `runDetailSubtree` — the crop's
12892
12944
  * originating detection, in FRAME-space coordinates. Reuses
@@ -13126,7 +13178,14 @@ var RunnerCameraConfigSchema = object({
13126
13178
  * camera's detect node differs from its source-owner (P2d, gated by the
13127
13179
  * `remoteSourcingNodes` rollout setting).
13128
13180
  */
13129
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13181
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13182
+ /**
13183
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13184
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13185
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13186
+ * this only selects WHICH device pool of that node runs the session.
13187
+ */
13188
+ deviceKey: string().optional()
13130
13189
  });
13131
13190
  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;
13132
13191
  /**
@@ -13147,6 +13206,19 @@ var RunnerLocalLoadSchema = object({
13147
13206
  avgInferenceTimeMs: number(),
13148
13207
  /** Total queue depth across motion + detection queues. */
13149
13208
  queueDepthTotal: number(),
13209
+ /**
13210
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13211
+ * this runner currently has attached cameras on, so the orchestrator's second
13212
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13213
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13214
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13215
+ */
13216
+ devices: array(object({
13217
+ deviceKey: string(),
13218
+ backend: string(),
13219
+ attachedCameras: number(),
13220
+ queueDepthTotal: number()
13221
+ })).default([]),
13150
13222
  /** Hardware capability flags reported by this node. */
13151
13223
  hardware: object({
13152
13224
  hasGpu: boolean(),
@@ -16295,6 +16367,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16295
16367
  return toDeviceSummary(device, this.addonId);
16296
16368
  }
16297
16369
  };
16370
+ 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;
16371
+ new Set(Object.values(DeviceType));
16298
16372
  /**
16299
16373
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16300
16374
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -17880,7 +17954,8 @@ var LinkedDeviceSchema = object({
17880
17954
  deviceId: number(),
17881
17955
  name: string(),
17882
17956
  location: string().nullable(),
17883
- features: array(string())
17957
+ features: array(string()),
17958
+ producesTrackedEvents: boolean().optional()
17884
17959
  });
17885
17960
  var SavedDeviceRowSchema = object({
17886
17961
  /** Numeric id reserved at allocateDeviceId time. */
@@ -19510,6 +19585,7 @@ var TrackSchema = object({
19510
19585
  deviceId: number(),
19511
19586
  className: string(),
19512
19587
  label: string().optional(),
19588
+ producingDeviceName: string().optional(),
19513
19589
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
19514
19590
  source: TrackSourceSchema.optional(),
19515
19591
  firstSeen: number(),
@@ -19647,7 +19723,8 @@ var MediaFileKindEnum = _enum([
19647
19723
  "fullFrameBoxed",
19648
19724
  "faceCrop",
19649
19725
  "plateCrop",
19650
- "keyFrame"
19726
+ "keyFrame",
19727
+ "keyFrameSmall"
19651
19728
  ]);
19652
19729
  var MediaFileSchema = object({
19653
19730
  key: string(),
@@ -19976,13 +20053,11 @@ var PipelineTemplateSchema = object({
19976
20053
  createdAt: string(),
19977
20054
  updatedAt: string()
19978
20055
  });
19979
- var AgentAddonConfigSchema = object({
19980
- enabled: boolean(),
20056
+ var DeviceStepConfigSchema = object({
19981
20057
  modelId: string().optional(),
19982
- settings: record(string(), unknown()).readonly()
20058
+ settings: record(string(), unknown()).optional()
19983
20059
  });
19984
20060
  var AgentPipelineSettingsSchema = object({
19985
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19986
20061
  maxCameras: number().int().nonnegative().nullable().default(null),
19987
20062
  /** Per-node detection weight (relative share for the quota balancer). */
19988
20063
  detectWeight: number().positive().optional(),
@@ -20006,7 +20081,22 @@ var AgentPipelineSettingsSchema = object({
20006
20081
  * it already uses to reach the hub). Set this only when the auto-detected
20007
20082
  * address is wrong (multi-homed host, NAT, custom interface).
20008
20083
  */
20009
- reachableHost: string().optional()
20084
+ reachableHost: string().optional(),
20085
+ /**
20086
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20087
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20088
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20089
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20090
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20091
+ * the default model/settings for every camera landing on that accelerator;
20092
+ * a stepId absent ⇒ the step uses that device's format default.
20093
+ */
20094
+ inferenceDevices: record(string(), object({
20095
+ enabled: boolean(),
20096
+ weight: number().positive().optional(),
20097
+ maxSessions: number().int().positive().optional(),
20098
+ steps: record(string(), DeviceStepConfigSchema).optional()
20099
+ })).optional()
20010
20100
  });
20011
20101
  var CameraPipelineForAgentSchema = object({
20012
20102
  steps: array(PipelineStepInputSchema).readonly(),
@@ -20016,14 +20106,13 @@ var CameraPipelineForAgentSchema = object({
20016
20106
  }).nullable()
20017
20107
  });
20018
20108
  var CameraStepOverridePatchSchema = object({
20019
- enabled: boolean().optional(),
20020
20109
  modelId: string().optional(),
20021
20110
  settings: record(string(), unknown()).readonly().optional()
20022
20111
  });
20023
20112
  var CameraPipelineSettingsSchema = object({
20024
20113
  pinnedAgentNodeId: string().optional(),
20025
20114
  stepToggles: record(string(), boolean()).optional(),
20026
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20115
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
20027
20116
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
20028
20117
  });
20029
20118
  /**
@@ -20237,6 +20326,44 @@ var CameraStatusSchema = object({
20237
20326
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20238
20327
  fetchedAt: number()
20239
20328
  });
20329
+ var NodeInferenceDeviceSchema = object({
20330
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20331
+ key: string(),
20332
+ backend: string(),
20333
+ device: string(),
20334
+ format: _enum(MODEL_FORMATS),
20335
+ /** Whether the node's live probe reports the device as usable right now. */
20336
+ available: boolean(),
20337
+ /**
20338
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20339
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20340
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20341
+ * not a balanced target). An explicit stored value always wins; a stored-only
20342
+ * (unavailable) key keeps its stored value.
20343
+ */
20344
+ enabled: boolean(),
20345
+ /** Relative balancer weight for the enabled device (default 1). */
20346
+ weight: number(),
20347
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20348
+ maxSessions: number().nullable(),
20349
+ /** Object-detection model the executor defaults to for this deviceKey. */
20350
+ defaultModelId: string(),
20351
+ /**
20352
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20353
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20354
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20355
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20356
+ * available per format; this is the stored selection that becomes the
20357
+ * default for EVERY camera landing on this accelerator.
20358
+ */
20359
+ steps: record(string(), DeviceStepConfigSchema).optional()
20360
+ });
20361
+ var NodeInferenceDevicesSchema = object({
20362
+ nodeId: string(),
20363
+ /** False when the node's platform-probe was unreachable (no live device set). */
20364
+ reachable: boolean(),
20365
+ devices: array(NodeInferenceDeviceSchema).readonly()
20366
+ });
20240
20367
  method(object({
20241
20368
  deviceId: number(),
20242
20369
  agentNodeId: string()
@@ -20246,7 +20373,13 @@ method(object({
20246
20373
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20247
20374
  kind: "mutation",
20248
20375
  auth: "admin"
20249
- }), method(_void(), object({ migrated: number() }), {
20376
+ }), method(object({
20377
+ deviceId: number(),
20378
+ deviceKey: string()
20379
+ }), object({ success: literal(true) }), {
20380
+ kind: "mutation",
20381
+ auth: "admin"
20382
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20250
20383
  kind: "mutation",
20251
20384
  auth: "admin"
20252
20385
  }), 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({
@@ -20280,13 +20413,7 @@ method(object({
20280
20413
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20281
20414
  nodeId: string(),
20282
20415
  settings: AgentPipelineSettingsSchema
20283
- })).readonly()), method(object({
20284
- agentNodeId: string(),
20285
- defaults: record(string(), AgentAddonConfigSchema)
20286
- }), object({ success: literal(true) }), {
20287
- kind: "mutation",
20288
- auth: "admin"
20289
- }), method(object({ agentNodeId: string() }), object({
20416
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20290
20417
  success: boolean(),
20291
20418
  removed: boolean()
20292
20419
  }), {
@@ -20318,7 +20445,18 @@ method(object({
20318
20445
  }), object({ success: literal(true) }), {
20319
20446
  kind: "mutation",
20320
20447
  auth: "admin"
20321
- }), method(object({ agentNodeId: string() }), object({
20448
+ }), method(object({
20449
+ agentNodeId: string(),
20450
+ inferenceDevices: record(string(), object({
20451
+ enabled: boolean(),
20452
+ weight: number().positive().optional(),
20453
+ maxSessions: number().int().positive().optional(),
20454
+ steps: record(string(), DeviceStepConfigSchema).optional()
20455
+ }))
20456
+ }), object({ success: literal(true) }), {
20457
+ kind: "mutation",
20458
+ auth: "admin"
20459
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20322
20460
  success: literal(true),
20323
20461
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20324
20462
  effectiveModelId: string().nullable(),
@@ -20334,9 +20472,10 @@ method(object({
20334
20472
  }), object({ success: literal(true) }), {
20335
20473
  kind: "mutation",
20336
20474
  auth: "admin"
20337
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20475
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20338
20476
  deviceId: number(),
20339
20477
  agentNodeId: string(),
20478
+ deviceKey: string(),
20340
20479
  addonId: string(),
20341
20480
  patch: CameraStepOverridePatchSchema.nullable()
20342
20481
  }), object({ success: literal(true) }), {
@@ -20373,14 +20512,13 @@ method(object({
20373
20512
  });
20374
20513
  /**
20375
20514
  * server-management — per-NODE singleton capability for a node's ROOT
20376
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20377
- * agents).
20515
+ * package lifecycle (runtime-updatable node packages).
20378
20516
  *
20379
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20380
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20381
- * version describes the node. Updates install into
20382
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20383
- * starter (probation boot + auto-rollback to N-1).
20517
+ * Every node role runs the SAME root package (`@camstack/server`), which
20518
+ * carries the whole software stack in its npm dep tree, so ONE version
20519
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20520
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20521
+ * no auto-rollback).
20384
20522
  *
20385
20523
  * Providers:
20386
20524
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20488,7 +20626,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20488
20626
  /** Explicit target version; omitted = latest from the registry. */
20489
20627
  version: string().optional() }), ServerUpdateActionResultSchema, {
20490
20628
  kind: "mutation",
20491
- auth: "admin"
20629
+ auth: "admin",
20630
+ timeoutMs: 16 * 6e4
20492
20631
  }), method(_void(), ServerUpdateActionResultSchema, {
20493
20632
  kind: "mutation",
20494
20633
  auth: "admin"
@@ -21583,22 +21722,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21583
21722
  var RestartAddonResultSchema = unknown();
21584
21723
  var InstallPackageResultSchema = unknown();
21585
21724
  var ReloadPackagesResultSchema = unknown();
21586
- /**
21587
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21588
- * server restarts so the admin UI can react to the `restartingAt`
21589
- * timestamp (shows reconnect overlay). The transition from
21590
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21591
- * `system.restart-completed` event after the new process boots.
21592
- *
21593
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21594
- */
21595
- var UpdateFrameworkPackageResultSchema = object({
21596
- packageName: string(),
21597
- fromVersion: string(),
21598
- toVersion: string(),
21599
- /** Ms-epoch the server scheduled its self-restart. */
21600
- restartingAt: number()
21601
- });
21602
21725
  var BulkUpdateItemStatusSchema = _enum([
21603
21726
  "queued",
21604
21727
  "updating",
@@ -21726,13 +21849,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21726
21849
  }), object({ success: literal(true) }), {
21727
21850
  kind: "mutation",
21728
21851
  auth: "admin"
21729
- }), method(object({
21730
- packageName: string().min(1),
21731
- version: string().optional(),
21732
- deferRestart: boolean().optional()
21733
- }), UpdateFrameworkPackageResultSchema, {
21734
- kind: "mutation",
21735
- auth: "admin"
21736
21852
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21737
21853
  kind: "mutation",
21738
21854
  auth: "admin"
@@ -22649,10 +22765,10 @@ var TopologyCategorySchema = object({
22649
22765
  addons: array(TopologyCategoryAddonSchema).readonly()
22650
22766
  });
22651
22767
  /**
22652
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22653
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22654
- * version visibility for the Server management surface. Nullable: offline
22655
- * rows and pre-phase-2 nodes report none.
22768
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22769
+ * root package for every node role) as reported by its `registerNode`
22770
+ * manifest — version visibility for the Server management surface. Nullable:
22771
+ * offline rows and nodes that never reported one.
22656
22772
  */
22657
22773
  var TopologyRootPackageSchema = object({
22658
22774
  name: string(),
@@ -23086,17 +23202,28 @@ var PlatformScoreSchema = object({
23086
23202
  format: _enum([
23087
23203
  "onnx",
23088
23204
  "coreml",
23089
- "openvino"
23205
+ "openvino",
23206
+ "tflite"
23090
23207
  ]),
23091
23208
  score: number(),
23092
23209
  reason: string(),
23093
23210
  available: boolean()
23094
23211
  });
23212
+ var InferenceDeviceDescriptorSchema = object({
23213
+ key: string(),
23214
+ backend: string(),
23215
+ device: string(),
23216
+ format: ModelFormatSchema,
23217
+ runtime: literal("python"),
23218
+ score: number(),
23219
+ available: boolean()
23220
+ });
23095
23221
  var PlatformCapabilitiesSchema = object({
23096
23222
  hardware: HardwareInfoSchema,
23097
23223
  scores: array(PlatformScoreSchema).readonly(),
23098
23224
  bestScore: PlatformScoreSchema,
23099
- pythonPath: string().nullable()
23225
+ pythonPath: string().nullable(),
23226
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
23100
23227
  });
23101
23228
  var ModelRequirementSchema = object({
23102
23229
  modelId: string(),
@@ -24253,12 +24380,6 @@ Object.freeze({
24253
24380
  addonId: null,
24254
24381
  access: "delete"
24255
24382
  },
24256
- "addons.updateFrameworkPackage": {
24257
- capName: "addons",
24258
- capScope: "system",
24259
- addonId: null,
24260
- access: "create"
24261
- },
24262
24383
  "addons.updatePackage": {
24263
24384
  capName: "addons",
24264
24385
  capScope: "system",
@@ -27031,12 +27152,6 @@ Object.freeze({
27031
27152
  addonId: null,
27032
27153
  access: "view"
27033
27154
  },
27034
- "pipelineExecutor.reprobeEngine": {
27035
- capName: "pipeline-executor",
27036
- capScope: "system",
27037
- addonId: null,
27038
- access: "create"
27039
- },
27040
27155
  "pipelineExecutor.runAudioTest": {
27041
27156
  capName: "pipeline-executor",
27042
27157
  capScope: "system",
@@ -27187,6 +27302,12 @@ Object.freeze({
27187
27302
  addonId: null,
27188
27303
  access: "view"
27189
27304
  },
27305
+ "pipelineOrchestrator.getNodeInferenceDevices": {
27306
+ capName: "pipeline-orchestrator",
27307
+ capScope: "system",
27308
+ addonId: null,
27309
+ access: "view"
27310
+ },
27190
27311
  "pipelineOrchestrator.getPipelineAssignment": {
27191
27312
  capName: "pipeline-orchestrator",
27192
27313
  capScope: "system",
@@ -27199,6 +27320,12 @@ Object.freeze({
27199
27320
  addonId: null,
27200
27321
  access: "view"
27201
27322
  },
27323
+ "pipelineOrchestrator.getPipelineDevicePin": {
27324
+ capName: "pipeline-orchestrator",
27325
+ capScope: "system",
27326
+ addonId: null,
27327
+ access: "view"
27328
+ },
27202
27329
  "pipelineOrchestrator.listAgentSettings": {
27203
27330
  capName: "pipeline-orchestrator",
27204
27331
  capScope: "system",
@@ -27241,19 +27368,19 @@ Object.freeze({
27241
27368
  addonId: null,
27242
27369
  access: "create"
27243
27370
  },
27244
- "pipelineOrchestrator.setAgentAddonDefaults": {
27371
+ "pipelineOrchestrator.setAgentCapabilities": {
27245
27372
  capName: "pipeline-orchestrator",
27246
27373
  capScope: "system",
27247
27374
  addonId: null,
27248
27375
  access: "create"
27249
27376
  },
27250
- "pipelineOrchestrator.setAgentCapabilities": {
27377
+ "pipelineOrchestrator.setAgentDetectWeight": {
27251
27378
  capName: "pipeline-orchestrator",
27252
27379
  capScope: "system",
27253
27380
  addonId: null,
27254
27381
  access: "create"
27255
27382
  },
27256
- "pipelineOrchestrator.setAgentDetectWeight": {
27383
+ "pipelineOrchestrator.setAgentInferenceDevices": {
27257
27384
  capName: "pipeline-orchestrator",
27258
27385
  capScope: "system",
27259
27386
  addonId: null,
@@ -27295,6 +27422,12 @@ Object.freeze({
27295
27422
  addonId: null,
27296
27423
  access: "create"
27297
27424
  },
27425
+ "pipelineOrchestrator.setPipelineDevicePin": {
27426
+ capName: "pipeline-orchestrator",
27427
+ capScope: "system",
27428
+ addonId: null,
27429
+ access: "create"
27430
+ },
27298
27431
  "pipelineOrchestrator.unassignAudio": {
27299
27432
  capName: "pipeline-orchestrator",
27300
27433
  capScope: "system",
@@ -28847,32 +28980,6 @@ Object.freeze({
28847
28980
  "network-access": "ingress",
28848
28981
  "smtp-provider": "email"
28849
28982
  });
28850
- var frameworkSwapPackageSchema = object({
28851
- name: string(),
28852
- stagedPath: string(),
28853
- backupPath: string(),
28854
- toVersion: string(),
28855
- fromVersion: string().nullable()
28856
- });
28857
- object({
28858
- jobId: string(),
28859
- taskId: string(),
28860
- packages: array(frameworkSwapPackageSchema),
28861
- requestedAtMs: number(),
28862
- schemaVersion: literal(1)
28863
- });
28864
- object({
28865
- jobId: string(),
28866
- taskId: string(),
28867
- backups: array(object({
28868
- name: string(),
28869
- backupPath: string(),
28870
- livePath: string()
28871
- })),
28872
- appliedAtMs: number(),
28873
- bootAttempts: number(),
28874
- schemaVersion: literal(1)
28875
- });
28876
28983
  //#endregion
28877
28984
  //#region src/schema.ts
28878
28985
  /**
package/dist/addon.mjs CHANGED
@@ -7080,6 +7080,17 @@ var ModelCatalogEntrySchema = object({
7080
7080
  "imagenet",
7081
7081
  "none"
7082
7082
  ]).optional(),
7083
+ /**
7084
+ * The model already applies softmax IN-GRAPH — its raw output is a
7085
+ * probability distribution, not logits. When set, the `softmax`
7086
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7087
+ * probability vector collapses it toward uniform (top-1 score craters far
7088
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7089
+ * the output is raw logits and the postprocessor applies softmax (the normal
7090
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7091
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7092
+ */
7093
+ outputProbabilities: boolean().optional(),
7083
7094
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7084
7095
  /**
7085
7096
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12650,10 +12661,7 @@ var ConfigUISchemaNullableBridge = custom();
12650
12661
  var InferenceCapabilitiesBridge = custom();
12651
12662
  var ModelAvailabilityListBridge = custom();
12652
12663
  var PipelineRunResultBridge = custom();
12653
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12654
- kind: "mutation",
12655
- auth: "admin"
12656
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12664
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12657
12665
  modelId: string(),
12658
12666
  settings: record(string(), unknown()).readonly()
12659
12667
  }))), method(object({ steps: record(string(), object({
@@ -12713,13 +12721,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12713
12721
  * (inputClasses ≠ null) are skipped and served per-track via
12714
12722
  * pipelineRunner.runDetailSubtree (two-plane design).
12715
12723
  */
12716
- plane: _enum(["full", "frame"]).optional()
12724
+ plane: _enum(["full", "frame"]).optional(),
12725
+ /**
12726
+ * Inference-device selector (Phase 2 multi-device). Format
12727
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12728
+ * Omitted ⇒ the runner's default device (current single-engine
12729
+ * behaviour). Selects WHICH device pool of the node runs the call.
12730
+ */
12731
+ deviceKey: string().optional()
12717
12732
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12718
12733
  engine: PipelineEngineChoiceSchema.optional(),
12719
12734
  steps: array(PipelineStepInputSchema).min(1),
12720
12735
  frames: array(FrameInputSchema).min(1).max(255),
12721
12736
  deviceId: number().optional(),
12722
- sessionId: string().optional()
12737
+ sessionId: string().optional(),
12738
+ /**
12739
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12740
+ * the batch to the Python pool's bench preprocess cache
12741
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12742
+ * preprocessed ONCE and every later inference is a pure-inference cache
12743
+ * hit — the sustained-throughput run measures inference, not
12744
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12745
+ * full preprocess every call, correct). Fresh per sustained run;
12746
+ * released via `uncacheFrame`.
12747
+ */
12748
+ frameId: number().int().nonnegative().optional(),
12749
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12750
+ deviceKey: string().optional()
12723
12751
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12724
12752
  data: _instanceof(Uint8Array),
12725
12753
  width: number().int().positive(),
@@ -12751,8 +12779,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12751
12779
  * - `runtime` — main camera-serving engine (no idle TTL).
12752
12780
  * - `warm-override` — benchmark/test override held in the warm
12753
12781
  * cache; auto-disposed after the idle TTL.
12782
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12783
+ * multi-device, keyed by `deviceKey`) resolved
12784
+ * via `resolveDeviceFactory`. Runs alongside the
12785
+ * `runtime` engine on a DIFFERENT accelerator
12786
+ * (NPU / iGPU / Coral) — this is how the
12787
+ * Engines tab shows all pools running at once.
12754
12788
  */
12755
- kind: _enum(["runtime", "warm-override"]),
12789
+ kind: _enum([
12790
+ "runtime",
12791
+ "warm-override",
12792
+ "device-pool"
12793
+ ]),
12756
12794
  /** Native pid of the underlying Python pool (null when no pool). */
12757
12795
  poolPid: number().nullable(),
12758
12796
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12887,7 +12925,21 @@ var NativeCropResultSchema = object({
12887
12925
  /** Packed rgb (24-bit) pixels of the crop. */
12888
12926
  bytes: _instanceof(Uint8Array),
12889
12927
  width: number().int().positive(),
12890
- height: number().int().positive()
12928
+ height: number().int().positive(),
12929
+ /**
12930
+ * Which source served this crop, so a quality-sensitive consumer (the native
12931
+ * `keyFrame`) can reject a degraded fallback:
12932
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
12933
+ * quality path).
12934
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
12935
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
12936
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
12937
+ *
12938
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
12939
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
12940
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
12941
+ */
12942
+ tier: _enum(["native", "ram-fullframe"]).optional()
12891
12943
  });
12892
12944
  /** Parent detection context passed to `runDetailSubtree` — the crop's
12893
12945
  * originating detection, in FRAME-space coordinates. Reuses
@@ -13127,7 +13179,14 @@ var RunnerCameraConfigSchema = object({
13127
13179
  * camera's detect node differs from its source-owner (P2d, gated by the
13128
13180
  * `remoteSourcingNodes` rollout setting).
13129
13181
  */
13130
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13182
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13183
+ /**
13184
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13185
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13186
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13187
+ * this only selects WHICH device pool of that node runs the session.
13188
+ */
13189
+ deviceKey: string().optional()
13131
13190
  });
13132
13191
  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;
13133
13192
  /**
@@ -13148,6 +13207,19 @@ var RunnerLocalLoadSchema = object({
13148
13207
  avgInferenceTimeMs: number(),
13149
13208
  /** Total queue depth across motion + detection queues. */
13150
13209
  queueDepthTotal: number(),
13210
+ /**
13211
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13212
+ * this runner currently has attached cameras on, so the orchestrator's second
13213
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13214
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13215
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13216
+ */
13217
+ devices: array(object({
13218
+ deviceKey: string(),
13219
+ backend: string(),
13220
+ attachedCameras: number(),
13221
+ queueDepthTotal: number()
13222
+ })).default([]),
13151
13223
  /** Hardware capability flags reported by this node. */
13152
13224
  hardware: object({
13153
13225
  hasGpu: boolean(),
@@ -16296,6 +16368,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16296
16368
  return toDeviceSummary(device, this.addonId);
16297
16369
  }
16298
16370
  };
16371
+ 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;
16372
+ new Set(Object.values(DeviceType));
16299
16373
  /**
16300
16374
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16301
16375
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -17881,7 +17955,8 @@ var LinkedDeviceSchema = object({
17881
17955
  deviceId: number(),
17882
17956
  name: string(),
17883
17957
  location: string().nullable(),
17884
- features: array(string())
17958
+ features: array(string()),
17959
+ producesTrackedEvents: boolean().optional()
17885
17960
  });
17886
17961
  var SavedDeviceRowSchema = object({
17887
17962
  /** Numeric id reserved at allocateDeviceId time. */
@@ -19511,6 +19586,7 @@ var TrackSchema = object({
19511
19586
  deviceId: number(),
19512
19587
  className: string(),
19513
19588
  label: string().optional(),
19589
+ producingDeviceName: string().optional(),
19514
19590
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
19515
19591
  source: TrackSourceSchema.optional(),
19516
19592
  firstSeen: number(),
@@ -19648,7 +19724,8 @@ var MediaFileKindEnum = _enum([
19648
19724
  "fullFrameBoxed",
19649
19725
  "faceCrop",
19650
19726
  "plateCrop",
19651
- "keyFrame"
19727
+ "keyFrame",
19728
+ "keyFrameSmall"
19652
19729
  ]);
19653
19730
  var MediaFileSchema = object({
19654
19731
  key: string(),
@@ -19977,13 +20054,11 @@ var PipelineTemplateSchema = object({
19977
20054
  createdAt: string(),
19978
20055
  updatedAt: string()
19979
20056
  });
19980
- var AgentAddonConfigSchema = object({
19981
- enabled: boolean(),
20057
+ var DeviceStepConfigSchema = object({
19982
20058
  modelId: string().optional(),
19983
- settings: record(string(), unknown()).readonly()
20059
+ settings: record(string(), unknown()).optional()
19984
20060
  });
19985
20061
  var AgentPipelineSettingsSchema = object({
19986
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19987
20062
  maxCameras: number().int().nonnegative().nullable().default(null),
19988
20063
  /** Per-node detection weight (relative share for the quota balancer). */
19989
20064
  detectWeight: number().positive().optional(),
@@ -20007,7 +20082,22 @@ var AgentPipelineSettingsSchema = object({
20007
20082
  * it already uses to reach the hub). Set this only when the auto-detected
20008
20083
  * address is wrong (multi-homed host, NAT, custom interface).
20009
20084
  */
20010
- reachableHost: string().optional()
20085
+ reachableHost: string().optional(),
20086
+ /**
20087
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20088
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20089
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20090
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20091
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20092
+ * the default model/settings for every camera landing on that accelerator;
20093
+ * a stepId absent ⇒ the step uses that device's format default.
20094
+ */
20095
+ inferenceDevices: record(string(), object({
20096
+ enabled: boolean(),
20097
+ weight: number().positive().optional(),
20098
+ maxSessions: number().int().positive().optional(),
20099
+ steps: record(string(), DeviceStepConfigSchema).optional()
20100
+ })).optional()
20011
20101
  });
20012
20102
  var CameraPipelineForAgentSchema = object({
20013
20103
  steps: array(PipelineStepInputSchema).readonly(),
@@ -20017,14 +20107,13 @@ var CameraPipelineForAgentSchema = object({
20017
20107
  }).nullable()
20018
20108
  });
20019
20109
  var CameraStepOverridePatchSchema = object({
20020
- enabled: boolean().optional(),
20021
20110
  modelId: string().optional(),
20022
20111
  settings: record(string(), unknown()).readonly().optional()
20023
20112
  });
20024
20113
  var CameraPipelineSettingsSchema = object({
20025
20114
  pinnedAgentNodeId: string().optional(),
20026
20115
  stepToggles: record(string(), boolean()).optional(),
20027
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20116
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
20028
20117
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
20029
20118
  });
20030
20119
  /**
@@ -20238,6 +20327,44 @@ var CameraStatusSchema = object({
20238
20327
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20239
20328
  fetchedAt: number()
20240
20329
  });
20330
+ var NodeInferenceDeviceSchema = object({
20331
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20332
+ key: string(),
20333
+ backend: string(),
20334
+ device: string(),
20335
+ format: _enum(MODEL_FORMATS),
20336
+ /** Whether the node's live probe reports the device as usable right now. */
20337
+ available: boolean(),
20338
+ /**
20339
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20340
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20341
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20342
+ * not a balanced target). An explicit stored value always wins; a stored-only
20343
+ * (unavailable) key keeps its stored value.
20344
+ */
20345
+ enabled: boolean(),
20346
+ /** Relative balancer weight for the enabled device (default 1). */
20347
+ weight: number(),
20348
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20349
+ maxSessions: number().nullable(),
20350
+ /** Object-detection model the executor defaults to for this deviceKey. */
20351
+ defaultModelId: string(),
20352
+ /**
20353
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20354
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20355
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20356
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20357
+ * available per format; this is the stored selection that becomes the
20358
+ * default for EVERY camera landing on this accelerator.
20359
+ */
20360
+ steps: record(string(), DeviceStepConfigSchema).optional()
20361
+ });
20362
+ var NodeInferenceDevicesSchema = object({
20363
+ nodeId: string(),
20364
+ /** False when the node's platform-probe was unreachable (no live device set). */
20365
+ reachable: boolean(),
20366
+ devices: array(NodeInferenceDeviceSchema).readonly()
20367
+ });
20241
20368
  method(object({
20242
20369
  deviceId: number(),
20243
20370
  agentNodeId: string()
@@ -20247,7 +20374,13 @@ method(object({
20247
20374
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20248
20375
  kind: "mutation",
20249
20376
  auth: "admin"
20250
- }), method(_void(), object({ migrated: number() }), {
20377
+ }), method(object({
20378
+ deviceId: number(),
20379
+ deviceKey: string()
20380
+ }), object({ success: literal(true) }), {
20381
+ kind: "mutation",
20382
+ auth: "admin"
20383
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20251
20384
  kind: "mutation",
20252
20385
  auth: "admin"
20253
20386
  }), 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({
@@ -20281,13 +20414,7 @@ method(object({
20281
20414
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20282
20415
  nodeId: string(),
20283
20416
  settings: AgentPipelineSettingsSchema
20284
- })).readonly()), method(object({
20285
- agentNodeId: string(),
20286
- defaults: record(string(), AgentAddonConfigSchema)
20287
- }), object({ success: literal(true) }), {
20288
- kind: "mutation",
20289
- auth: "admin"
20290
- }), method(object({ agentNodeId: string() }), object({
20417
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20291
20418
  success: boolean(),
20292
20419
  removed: boolean()
20293
20420
  }), {
@@ -20319,7 +20446,18 @@ method(object({
20319
20446
  }), object({ success: literal(true) }), {
20320
20447
  kind: "mutation",
20321
20448
  auth: "admin"
20322
- }), method(object({ agentNodeId: string() }), object({
20449
+ }), method(object({
20450
+ agentNodeId: string(),
20451
+ inferenceDevices: record(string(), object({
20452
+ enabled: boolean(),
20453
+ weight: number().positive().optional(),
20454
+ maxSessions: number().int().positive().optional(),
20455
+ steps: record(string(), DeviceStepConfigSchema).optional()
20456
+ }))
20457
+ }), object({ success: literal(true) }), {
20458
+ kind: "mutation",
20459
+ auth: "admin"
20460
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20323
20461
  success: literal(true),
20324
20462
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20325
20463
  effectiveModelId: string().nullable(),
@@ -20335,9 +20473,10 @@ method(object({
20335
20473
  }), object({ success: literal(true) }), {
20336
20474
  kind: "mutation",
20337
20475
  auth: "admin"
20338
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20476
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20339
20477
  deviceId: number(),
20340
20478
  agentNodeId: string(),
20479
+ deviceKey: string(),
20341
20480
  addonId: string(),
20342
20481
  patch: CameraStepOverridePatchSchema.nullable()
20343
20482
  }), object({ success: literal(true) }), {
@@ -20374,14 +20513,13 @@ method(object({
20374
20513
  });
20375
20514
  /**
20376
20515
  * server-management — per-NODE singleton capability for a node's ROOT
20377
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20378
- * agents).
20516
+ * package lifecycle (runtime-updatable node packages).
20379
20517
  *
20380
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20381
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20382
- * version describes the node. Updates install into
20383
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20384
- * starter (probation boot + auto-rollback to N-1).
20518
+ * Every node role runs the SAME root package (`@camstack/server`), which
20519
+ * carries the whole software stack in its npm dep tree, so ONE version
20520
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20521
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20522
+ * no auto-rollback).
20385
20523
  *
20386
20524
  * Providers:
20387
20525
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20489,7 +20627,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20489
20627
  /** Explicit target version; omitted = latest from the registry. */
20490
20628
  version: string().optional() }), ServerUpdateActionResultSchema, {
20491
20629
  kind: "mutation",
20492
- auth: "admin"
20630
+ auth: "admin",
20631
+ timeoutMs: 16 * 6e4
20493
20632
  }), method(_void(), ServerUpdateActionResultSchema, {
20494
20633
  kind: "mutation",
20495
20634
  auth: "admin"
@@ -21584,22 +21723,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21584
21723
  var RestartAddonResultSchema = unknown();
21585
21724
  var InstallPackageResultSchema = unknown();
21586
21725
  var ReloadPackagesResultSchema = unknown();
21587
- /**
21588
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21589
- * server restarts so the admin UI can react to the `restartingAt`
21590
- * timestamp (shows reconnect overlay). The transition from
21591
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21592
- * `system.restart-completed` event after the new process boots.
21593
- *
21594
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21595
- */
21596
- var UpdateFrameworkPackageResultSchema = object({
21597
- packageName: string(),
21598
- fromVersion: string(),
21599
- toVersion: string(),
21600
- /** Ms-epoch the server scheduled its self-restart. */
21601
- restartingAt: number()
21602
- });
21603
21726
  var BulkUpdateItemStatusSchema = _enum([
21604
21727
  "queued",
21605
21728
  "updating",
@@ -21727,13 +21850,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21727
21850
  }), object({ success: literal(true) }), {
21728
21851
  kind: "mutation",
21729
21852
  auth: "admin"
21730
- }), method(object({
21731
- packageName: string().min(1),
21732
- version: string().optional(),
21733
- deferRestart: boolean().optional()
21734
- }), UpdateFrameworkPackageResultSchema, {
21735
- kind: "mutation",
21736
- auth: "admin"
21737
21853
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21738
21854
  kind: "mutation",
21739
21855
  auth: "admin"
@@ -22650,10 +22766,10 @@ var TopologyCategorySchema = object({
22650
22766
  addons: array(TopologyCategoryAddonSchema).readonly()
22651
22767
  });
22652
22768
  /**
22653
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22654
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22655
- * version visibility for the Server management surface. Nullable: offline
22656
- * rows and pre-phase-2 nodes report none.
22769
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22770
+ * root package for every node role) as reported by its `registerNode`
22771
+ * manifest — version visibility for the Server management surface. Nullable:
22772
+ * offline rows and nodes that never reported one.
22657
22773
  */
22658
22774
  var TopologyRootPackageSchema = object({
22659
22775
  name: string(),
@@ -23087,17 +23203,28 @@ var PlatformScoreSchema = object({
23087
23203
  format: _enum([
23088
23204
  "onnx",
23089
23205
  "coreml",
23090
- "openvino"
23206
+ "openvino",
23207
+ "tflite"
23091
23208
  ]),
23092
23209
  score: number(),
23093
23210
  reason: string(),
23094
23211
  available: boolean()
23095
23212
  });
23213
+ var InferenceDeviceDescriptorSchema = object({
23214
+ key: string(),
23215
+ backend: string(),
23216
+ device: string(),
23217
+ format: ModelFormatSchema,
23218
+ runtime: literal("python"),
23219
+ score: number(),
23220
+ available: boolean()
23221
+ });
23096
23222
  var PlatformCapabilitiesSchema = object({
23097
23223
  hardware: HardwareInfoSchema,
23098
23224
  scores: array(PlatformScoreSchema).readonly(),
23099
23225
  bestScore: PlatformScoreSchema,
23100
- pythonPath: string().nullable()
23226
+ pythonPath: string().nullable(),
23227
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
23101
23228
  });
23102
23229
  var ModelRequirementSchema = object({
23103
23230
  modelId: string(),
@@ -24254,12 +24381,6 @@ Object.freeze({
24254
24381
  addonId: null,
24255
24382
  access: "delete"
24256
24383
  },
24257
- "addons.updateFrameworkPackage": {
24258
- capName: "addons",
24259
- capScope: "system",
24260
- addonId: null,
24261
- access: "create"
24262
- },
24263
24384
  "addons.updatePackage": {
24264
24385
  capName: "addons",
24265
24386
  capScope: "system",
@@ -27032,12 +27153,6 @@ Object.freeze({
27032
27153
  addonId: null,
27033
27154
  access: "view"
27034
27155
  },
27035
- "pipelineExecutor.reprobeEngine": {
27036
- capName: "pipeline-executor",
27037
- capScope: "system",
27038
- addonId: null,
27039
- access: "create"
27040
- },
27041
27156
  "pipelineExecutor.runAudioTest": {
27042
27157
  capName: "pipeline-executor",
27043
27158
  capScope: "system",
@@ -27188,6 +27303,12 @@ Object.freeze({
27188
27303
  addonId: null,
27189
27304
  access: "view"
27190
27305
  },
27306
+ "pipelineOrchestrator.getNodeInferenceDevices": {
27307
+ capName: "pipeline-orchestrator",
27308
+ capScope: "system",
27309
+ addonId: null,
27310
+ access: "view"
27311
+ },
27191
27312
  "pipelineOrchestrator.getPipelineAssignment": {
27192
27313
  capName: "pipeline-orchestrator",
27193
27314
  capScope: "system",
@@ -27200,6 +27321,12 @@ Object.freeze({
27200
27321
  addonId: null,
27201
27322
  access: "view"
27202
27323
  },
27324
+ "pipelineOrchestrator.getPipelineDevicePin": {
27325
+ capName: "pipeline-orchestrator",
27326
+ capScope: "system",
27327
+ addonId: null,
27328
+ access: "view"
27329
+ },
27203
27330
  "pipelineOrchestrator.listAgentSettings": {
27204
27331
  capName: "pipeline-orchestrator",
27205
27332
  capScope: "system",
@@ -27242,19 +27369,19 @@ Object.freeze({
27242
27369
  addonId: null,
27243
27370
  access: "create"
27244
27371
  },
27245
- "pipelineOrchestrator.setAgentAddonDefaults": {
27372
+ "pipelineOrchestrator.setAgentCapabilities": {
27246
27373
  capName: "pipeline-orchestrator",
27247
27374
  capScope: "system",
27248
27375
  addonId: null,
27249
27376
  access: "create"
27250
27377
  },
27251
- "pipelineOrchestrator.setAgentCapabilities": {
27378
+ "pipelineOrchestrator.setAgentDetectWeight": {
27252
27379
  capName: "pipeline-orchestrator",
27253
27380
  capScope: "system",
27254
27381
  addonId: null,
27255
27382
  access: "create"
27256
27383
  },
27257
- "pipelineOrchestrator.setAgentDetectWeight": {
27384
+ "pipelineOrchestrator.setAgentInferenceDevices": {
27258
27385
  capName: "pipeline-orchestrator",
27259
27386
  capScope: "system",
27260
27387
  addonId: null,
@@ -27296,6 +27423,12 @@ Object.freeze({
27296
27423
  addonId: null,
27297
27424
  access: "create"
27298
27425
  },
27426
+ "pipelineOrchestrator.setPipelineDevicePin": {
27427
+ capName: "pipeline-orchestrator",
27428
+ capScope: "system",
27429
+ addonId: null,
27430
+ access: "create"
27431
+ },
27299
27432
  "pipelineOrchestrator.unassignAudio": {
27300
27433
  capName: "pipeline-orchestrator",
27301
27434
  capScope: "system",
@@ -28848,32 +28981,6 @@ Object.freeze({
28848
28981
  "network-access": "ingress",
28849
28982
  "smtp-provider": "email"
28850
28983
  });
28851
- var frameworkSwapPackageSchema = object({
28852
- name: string(),
28853
- stagedPath: string(),
28854
- backupPath: string(),
28855
- toVersion: string(),
28856
- fromVersion: string().nullable()
28857
- });
28858
- object({
28859
- jobId: string(),
28860
- taskId: string(),
28861
- packages: array(frameworkSwapPackageSchema),
28862
- requestedAtMs: number(),
28863
- schemaVersion: literal(1)
28864
- });
28865
- object({
28866
- jobId: string(),
28867
- taskId: string(),
28868
- backups: array(object({
28869
- name: string(),
28870
- backupPath: string(),
28871
- livePath: string()
28872
- })),
28873
- appliedAtMs: number(),
28874
- bootAttempts: number(),
28875
- schemaVersion: literal(1)
28876
- });
28877
28984
  //#endregion
28878
28985
  //#region src/schema.ts
28879
28986
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-hikvision",
3
- "version": "1.1.29",
3
+ "version": "1.2.1",
4
4
  "description": "Hikvision camera device provider addon for CamStack — ISAPI over HTTP(S) with digest auth (snapshot, alarm stream, RTSP discovery)",
5
5
  "keywords": [
6
6
  "camstack",