@camstack/addon-provider-hikvision 1.1.29 → 1.2.0

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 +193 -103
  2. package/dist/addon.mjs +193 -103
  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). */
@@ -13126,7 +13164,14 @@ var RunnerCameraConfigSchema = object({
13126
13164
  * camera's detect node differs from its source-owner (P2d, gated by the
13127
13165
  * `remoteSourcingNodes` rollout setting).
13128
13166
  */
13129
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13167
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13168
+ /**
13169
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13170
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13171
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13172
+ * this only selects WHICH device pool of that node runs the session.
13173
+ */
13174
+ deviceKey: string().optional()
13130
13175
  });
13131
13176
  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
13177
  /**
@@ -13147,6 +13192,19 @@ var RunnerLocalLoadSchema = object({
13147
13192
  avgInferenceTimeMs: number(),
13148
13193
  /** Total queue depth across motion + detection queues. */
13149
13194
  queueDepthTotal: number(),
13195
+ /**
13196
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13197
+ * this runner currently has attached cameras on, so the orchestrator's second
13198
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13199
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13200
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13201
+ */
13202
+ devices: array(object({
13203
+ deviceKey: string(),
13204
+ backend: string(),
13205
+ attachedCameras: number(),
13206
+ queueDepthTotal: number()
13207
+ })).default([]),
13150
13208
  /** Hardware capability flags reported by this node. */
13151
13209
  hardware: object({
13152
13210
  hasGpu: boolean(),
@@ -16295,6 +16353,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16295
16353
  return toDeviceSummary(device, this.addonId);
16296
16354
  }
16297
16355
  };
16356
+ 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;
16357
+ new Set(Object.values(DeviceType));
16298
16358
  /**
16299
16359
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16300
16360
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19976,13 +20036,11 @@ var PipelineTemplateSchema = object({
19976
20036
  createdAt: string(),
19977
20037
  updatedAt: string()
19978
20038
  });
19979
- var AgentAddonConfigSchema = object({
19980
- enabled: boolean(),
20039
+ var DeviceStepConfigSchema = object({
19981
20040
  modelId: string().optional(),
19982
- settings: record(string(), unknown()).readonly()
20041
+ settings: record(string(), unknown()).optional()
19983
20042
  });
19984
20043
  var AgentPipelineSettingsSchema = object({
19985
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19986
20044
  maxCameras: number().int().nonnegative().nullable().default(null),
19987
20045
  /** Per-node detection weight (relative share for the quota balancer). */
19988
20046
  detectWeight: number().positive().optional(),
@@ -20006,7 +20064,22 @@ var AgentPipelineSettingsSchema = object({
20006
20064
  * it already uses to reach the hub). Set this only when the auto-detected
20007
20065
  * address is wrong (multi-homed host, NAT, custom interface).
20008
20066
  */
20009
- reachableHost: string().optional()
20067
+ reachableHost: string().optional(),
20068
+ /**
20069
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20070
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20071
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20072
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20073
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20074
+ * the default model/settings for every camera landing on that accelerator;
20075
+ * a stepId absent ⇒ the step uses that device's format default.
20076
+ */
20077
+ inferenceDevices: record(string(), object({
20078
+ enabled: boolean(),
20079
+ weight: number().positive().optional(),
20080
+ maxSessions: number().int().positive().optional(),
20081
+ steps: record(string(), DeviceStepConfigSchema).optional()
20082
+ })).optional()
20010
20083
  });
20011
20084
  var CameraPipelineForAgentSchema = object({
20012
20085
  steps: array(PipelineStepInputSchema).readonly(),
@@ -20016,14 +20089,13 @@ var CameraPipelineForAgentSchema = object({
20016
20089
  }).nullable()
20017
20090
  });
20018
20091
  var CameraStepOverridePatchSchema = object({
20019
- enabled: boolean().optional(),
20020
20092
  modelId: string().optional(),
20021
20093
  settings: record(string(), unknown()).readonly().optional()
20022
20094
  });
20023
20095
  var CameraPipelineSettingsSchema = object({
20024
20096
  pinnedAgentNodeId: string().optional(),
20025
20097
  stepToggles: record(string(), boolean()).optional(),
20026
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20098
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
20027
20099
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
20028
20100
  });
20029
20101
  /**
@@ -20237,6 +20309,44 @@ var CameraStatusSchema = object({
20237
20309
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20238
20310
  fetchedAt: number()
20239
20311
  });
20312
+ var NodeInferenceDeviceSchema = object({
20313
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20314
+ key: string(),
20315
+ backend: string(),
20316
+ device: string(),
20317
+ format: _enum(MODEL_FORMATS),
20318
+ /** Whether the node's live probe reports the device as usable right now. */
20319
+ available: boolean(),
20320
+ /**
20321
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20322
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20323
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20324
+ * not a balanced target). An explicit stored value always wins; a stored-only
20325
+ * (unavailable) key keeps its stored value.
20326
+ */
20327
+ enabled: boolean(),
20328
+ /** Relative balancer weight for the enabled device (default 1). */
20329
+ weight: number(),
20330
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20331
+ maxSessions: number().nullable(),
20332
+ /** Object-detection model the executor defaults to for this deviceKey. */
20333
+ defaultModelId: string(),
20334
+ /**
20335
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20336
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20337
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20338
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20339
+ * available per format; this is the stored selection that becomes the
20340
+ * default for EVERY camera landing on this accelerator.
20341
+ */
20342
+ steps: record(string(), DeviceStepConfigSchema).optional()
20343
+ });
20344
+ var NodeInferenceDevicesSchema = object({
20345
+ nodeId: string(),
20346
+ /** False when the node's platform-probe was unreachable (no live device set). */
20347
+ reachable: boolean(),
20348
+ devices: array(NodeInferenceDeviceSchema).readonly()
20349
+ });
20240
20350
  method(object({
20241
20351
  deviceId: number(),
20242
20352
  agentNodeId: string()
@@ -20246,7 +20356,13 @@ method(object({
20246
20356
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20247
20357
  kind: "mutation",
20248
20358
  auth: "admin"
20249
- }), method(_void(), object({ migrated: number() }), {
20359
+ }), method(object({
20360
+ deviceId: number(),
20361
+ deviceKey: string()
20362
+ }), object({ success: literal(true) }), {
20363
+ kind: "mutation",
20364
+ auth: "admin"
20365
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20250
20366
  kind: "mutation",
20251
20367
  auth: "admin"
20252
20368
  }), 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 +20396,7 @@ method(object({
20280
20396
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20281
20397
  nodeId: string(),
20282
20398
  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({
20399
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20290
20400
  success: boolean(),
20291
20401
  removed: boolean()
20292
20402
  }), {
@@ -20318,7 +20428,18 @@ method(object({
20318
20428
  }), object({ success: literal(true) }), {
20319
20429
  kind: "mutation",
20320
20430
  auth: "admin"
20321
- }), method(object({ agentNodeId: string() }), object({
20431
+ }), method(object({
20432
+ agentNodeId: string(),
20433
+ inferenceDevices: record(string(), object({
20434
+ enabled: boolean(),
20435
+ weight: number().positive().optional(),
20436
+ maxSessions: number().int().positive().optional(),
20437
+ steps: record(string(), DeviceStepConfigSchema).optional()
20438
+ }))
20439
+ }), object({ success: literal(true) }), {
20440
+ kind: "mutation",
20441
+ auth: "admin"
20442
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20322
20443
  success: literal(true),
20323
20444
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20324
20445
  effectiveModelId: string().nullable(),
@@ -20334,9 +20455,10 @@ method(object({
20334
20455
  }), object({ success: literal(true) }), {
20335
20456
  kind: "mutation",
20336
20457
  auth: "admin"
20337
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20458
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20338
20459
  deviceId: number(),
20339
20460
  agentNodeId: string(),
20461
+ deviceKey: string(),
20340
20462
  addonId: string(),
20341
20463
  patch: CameraStepOverridePatchSchema.nullable()
20342
20464
  }), object({ success: literal(true) }), {
@@ -20373,14 +20495,13 @@ method(object({
20373
20495
  });
20374
20496
  /**
20375
20497
  * server-management — per-NODE singleton capability for a node's ROOT
20376
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20377
- * agents).
20498
+ * package lifecycle (runtime-updatable node packages).
20378
20499
  *
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).
20500
+ * Every node role runs the SAME root package (`@camstack/server`), which
20501
+ * carries the whole software stack in its npm dep tree, so ONE version
20502
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20503
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20504
+ * no auto-rollback).
20384
20505
  *
20385
20506
  * Providers:
20386
20507
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20488,7 +20609,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20488
20609
  /** Explicit target version; omitted = latest from the registry. */
20489
20610
  version: string().optional() }), ServerUpdateActionResultSchema, {
20490
20611
  kind: "mutation",
20491
- auth: "admin"
20612
+ auth: "admin",
20613
+ timeoutMs: 16 * 6e4
20492
20614
  }), method(_void(), ServerUpdateActionResultSchema, {
20493
20615
  kind: "mutation",
20494
20616
  auth: "admin"
@@ -21583,22 +21705,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21583
21705
  var RestartAddonResultSchema = unknown();
21584
21706
  var InstallPackageResultSchema = unknown();
21585
21707
  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
21708
  var BulkUpdateItemStatusSchema = _enum([
21603
21709
  "queued",
21604
21710
  "updating",
@@ -21726,13 +21832,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21726
21832
  }), object({ success: literal(true) }), {
21727
21833
  kind: "mutation",
21728
21834
  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
21835
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21737
21836
  kind: "mutation",
21738
21837
  auth: "admin"
@@ -22649,10 +22748,10 @@ var TopologyCategorySchema = object({
22649
22748
  addons: array(TopologyCategoryAddonSchema).readonly()
22650
22749
  });
22651
22750
  /**
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.
22751
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22752
+ * root package for every node role) as reported by its `registerNode`
22753
+ * manifest — version visibility for the Server management surface. Nullable:
22754
+ * offline rows and nodes that never reported one.
22656
22755
  */
22657
22756
  var TopologyRootPackageSchema = object({
22658
22757
  name: string(),
@@ -23086,17 +23185,28 @@ var PlatformScoreSchema = object({
23086
23185
  format: _enum([
23087
23186
  "onnx",
23088
23187
  "coreml",
23089
- "openvino"
23188
+ "openvino",
23189
+ "tflite"
23090
23190
  ]),
23091
23191
  score: number(),
23092
23192
  reason: string(),
23093
23193
  available: boolean()
23094
23194
  });
23195
+ var InferenceDeviceDescriptorSchema = object({
23196
+ key: string(),
23197
+ backend: string(),
23198
+ device: string(),
23199
+ format: ModelFormatSchema,
23200
+ runtime: literal("python"),
23201
+ score: number(),
23202
+ available: boolean()
23203
+ });
23095
23204
  var PlatformCapabilitiesSchema = object({
23096
23205
  hardware: HardwareInfoSchema,
23097
23206
  scores: array(PlatformScoreSchema).readonly(),
23098
23207
  bestScore: PlatformScoreSchema,
23099
- pythonPath: string().nullable()
23208
+ pythonPath: string().nullable(),
23209
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
23100
23210
  });
23101
23211
  var ModelRequirementSchema = object({
23102
23212
  modelId: string(),
@@ -24253,12 +24363,6 @@ Object.freeze({
24253
24363
  addonId: null,
24254
24364
  access: "delete"
24255
24365
  },
24256
- "addons.updateFrameworkPackage": {
24257
- capName: "addons",
24258
- capScope: "system",
24259
- addonId: null,
24260
- access: "create"
24261
- },
24262
24366
  "addons.updatePackage": {
24263
24367
  capName: "addons",
24264
24368
  capScope: "system",
@@ -27031,12 +27135,6 @@ Object.freeze({
27031
27135
  addonId: null,
27032
27136
  access: "view"
27033
27137
  },
27034
- "pipelineExecutor.reprobeEngine": {
27035
- capName: "pipeline-executor",
27036
- capScope: "system",
27037
- addonId: null,
27038
- access: "create"
27039
- },
27040
27138
  "pipelineExecutor.runAudioTest": {
27041
27139
  capName: "pipeline-executor",
27042
27140
  capScope: "system",
@@ -27187,6 +27285,12 @@ Object.freeze({
27187
27285
  addonId: null,
27188
27286
  access: "view"
27189
27287
  },
27288
+ "pipelineOrchestrator.getNodeInferenceDevices": {
27289
+ capName: "pipeline-orchestrator",
27290
+ capScope: "system",
27291
+ addonId: null,
27292
+ access: "view"
27293
+ },
27190
27294
  "pipelineOrchestrator.getPipelineAssignment": {
27191
27295
  capName: "pipeline-orchestrator",
27192
27296
  capScope: "system",
@@ -27199,6 +27303,12 @@ Object.freeze({
27199
27303
  addonId: null,
27200
27304
  access: "view"
27201
27305
  },
27306
+ "pipelineOrchestrator.getPipelineDevicePin": {
27307
+ capName: "pipeline-orchestrator",
27308
+ capScope: "system",
27309
+ addonId: null,
27310
+ access: "view"
27311
+ },
27202
27312
  "pipelineOrchestrator.listAgentSettings": {
27203
27313
  capName: "pipeline-orchestrator",
27204
27314
  capScope: "system",
@@ -27241,19 +27351,19 @@ Object.freeze({
27241
27351
  addonId: null,
27242
27352
  access: "create"
27243
27353
  },
27244
- "pipelineOrchestrator.setAgentAddonDefaults": {
27354
+ "pipelineOrchestrator.setAgentCapabilities": {
27245
27355
  capName: "pipeline-orchestrator",
27246
27356
  capScope: "system",
27247
27357
  addonId: null,
27248
27358
  access: "create"
27249
27359
  },
27250
- "pipelineOrchestrator.setAgentCapabilities": {
27360
+ "pipelineOrchestrator.setAgentDetectWeight": {
27251
27361
  capName: "pipeline-orchestrator",
27252
27362
  capScope: "system",
27253
27363
  addonId: null,
27254
27364
  access: "create"
27255
27365
  },
27256
- "pipelineOrchestrator.setAgentDetectWeight": {
27366
+ "pipelineOrchestrator.setAgentInferenceDevices": {
27257
27367
  capName: "pipeline-orchestrator",
27258
27368
  capScope: "system",
27259
27369
  addonId: null,
@@ -27295,6 +27405,12 @@ Object.freeze({
27295
27405
  addonId: null,
27296
27406
  access: "create"
27297
27407
  },
27408
+ "pipelineOrchestrator.setPipelineDevicePin": {
27409
+ capName: "pipeline-orchestrator",
27410
+ capScope: "system",
27411
+ addonId: null,
27412
+ access: "create"
27413
+ },
27298
27414
  "pipelineOrchestrator.unassignAudio": {
27299
27415
  capName: "pipeline-orchestrator",
27300
27416
  capScope: "system",
@@ -28847,32 +28963,6 @@ Object.freeze({
28847
28963
  "network-access": "ingress",
28848
28964
  "smtp-provider": "email"
28849
28965
  });
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
28966
  //#endregion
28877
28967
  //#region src/schema.ts
28878
28968
  /**
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). */
@@ -13127,7 +13165,14 @@ var RunnerCameraConfigSchema = object({
13127
13165
  * camera's detect node differs from its source-owner (P2d, gated by the
13128
13166
  * `remoteSourcingNodes` rollout setting).
13129
13167
  */
13130
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13168
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13169
+ /**
13170
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13171
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13172
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13173
+ * this only selects WHICH device pool of that node runs the session.
13174
+ */
13175
+ deviceKey: string().optional()
13131
13176
  });
13132
13177
  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
13178
  /**
@@ -13148,6 +13193,19 @@ var RunnerLocalLoadSchema = object({
13148
13193
  avgInferenceTimeMs: number(),
13149
13194
  /** Total queue depth across motion + detection queues. */
13150
13195
  queueDepthTotal: number(),
13196
+ /**
13197
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13198
+ * this runner currently has attached cameras on, so the orchestrator's second
13199
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13200
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13201
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13202
+ */
13203
+ devices: array(object({
13204
+ deviceKey: string(),
13205
+ backend: string(),
13206
+ attachedCameras: number(),
13207
+ queueDepthTotal: number()
13208
+ })).default([]),
13151
13209
  /** Hardware capability flags reported by this node. */
13152
13210
  hardware: object({
13153
13211
  hasGpu: boolean(),
@@ -16296,6 +16354,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16296
16354
  return toDeviceSummary(device, this.addonId);
16297
16355
  }
16298
16356
  };
16357
+ 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;
16358
+ new Set(Object.values(DeviceType));
16299
16359
  /**
16300
16360
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16301
16361
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19977,13 +20037,11 @@ var PipelineTemplateSchema = object({
19977
20037
  createdAt: string(),
19978
20038
  updatedAt: string()
19979
20039
  });
19980
- var AgentAddonConfigSchema = object({
19981
- enabled: boolean(),
20040
+ var DeviceStepConfigSchema = object({
19982
20041
  modelId: string().optional(),
19983
- settings: record(string(), unknown()).readonly()
20042
+ settings: record(string(), unknown()).optional()
19984
20043
  });
19985
20044
  var AgentPipelineSettingsSchema = object({
19986
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19987
20045
  maxCameras: number().int().nonnegative().nullable().default(null),
19988
20046
  /** Per-node detection weight (relative share for the quota balancer). */
19989
20047
  detectWeight: number().positive().optional(),
@@ -20007,7 +20065,22 @@ var AgentPipelineSettingsSchema = object({
20007
20065
  * it already uses to reach the hub). Set this only when the auto-detected
20008
20066
  * address is wrong (multi-homed host, NAT, custom interface).
20009
20067
  */
20010
- reachableHost: string().optional()
20068
+ reachableHost: string().optional(),
20069
+ /**
20070
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20071
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20072
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20073
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20074
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20075
+ * the default model/settings for every camera landing on that accelerator;
20076
+ * a stepId absent ⇒ the step uses that device's format default.
20077
+ */
20078
+ inferenceDevices: record(string(), object({
20079
+ enabled: boolean(),
20080
+ weight: number().positive().optional(),
20081
+ maxSessions: number().int().positive().optional(),
20082
+ steps: record(string(), DeviceStepConfigSchema).optional()
20083
+ })).optional()
20011
20084
  });
20012
20085
  var CameraPipelineForAgentSchema = object({
20013
20086
  steps: array(PipelineStepInputSchema).readonly(),
@@ -20017,14 +20090,13 @@ var CameraPipelineForAgentSchema = object({
20017
20090
  }).nullable()
20018
20091
  });
20019
20092
  var CameraStepOverridePatchSchema = object({
20020
- enabled: boolean().optional(),
20021
20093
  modelId: string().optional(),
20022
20094
  settings: record(string(), unknown()).readonly().optional()
20023
20095
  });
20024
20096
  var CameraPipelineSettingsSchema = object({
20025
20097
  pinnedAgentNodeId: string().optional(),
20026
20098
  stepToggles: record(string(), boolean()).optional(),
20027
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20099
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
20028
20100
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
20029
20101
  });
20030
20102
  /**
@@ -20238,6 +20310,44 @@ var CameraStatusSchema = object({
20238
20310
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20239
20311
  fetchedAt: number()
20240
20312
  });
20313
+ var NodeInferenceDeviceSchema = object({
20314
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20315
+ key: string(),
20316
+ backend: string(),
20317
+ device: string(),
20318
+ format: _enum(MODEL_FORMATS),
20319
+ /** Whether the node's live probe reports the device as usable right now. */
20320
+ available: boolean(),
20321
+ /**
20322
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20323
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20324
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20325
+ * not a balanced target). An explicit stored value always wins; a stored-only
20326
+ * (unavailable) key keeps its stored value.
20327
+ */
20328
+ enabled: boolean(),
20329
+ /** Relative balancer weight for the enabled device (default 1). */
20330
+ weight: number(),
20331
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20332
+ maxSessions: number().nullable(),
20333
+ /** Object-detection model the executor defaults to for this deviceKey. */
20334
+ defaultModelId: string(),
20335
+ /**
20336
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20337
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20338
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20339
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20340
+ * available per format; this is the stored selection that becomes the
20341
+ * default for EVERY camera landing on this accelerator.
20342
+ */
20343
+ steps: record(string(), DeviceStepConfigSchema).optional()
20344
+ });
20345
+ var NodeInferenceDevicesSchema = object({
20346
+ nodeId: string(),
20347
+ /** False when the node's platform-probe was unreachable (no live device set). */
20348
+ reachable: boolean(),
20349
+ devices: array(NodeInferenceDeviceSchema).readonly()
20350
+ });
20241
20351
  method(object({
20242
20352
  deviceId: number(),
20243
20353
  agentNodeId: string()
@@ -20247,7 +20357,13 @@ method(object({
20247
20357
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20248
20358
  kind: "mutation",
20249
20359
  auth: "admin"
20250
- }), method(_void(), object({ migrated: number() }), {
20360
+ }), method(object({
20361
+ deviceId: number(),
20362
+ deviceKey: string()
20363
+ }), object({ success: literal(true) }), {
20364
+ kind: "mutation",
20365
+ auth: "admin"
20366
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20251
20367
  kind: "mutation",
20252
20368
  auth: "admin"
20253
20369
  }), 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 +20397,7 @@ method(object({
20281
20397
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20282
20398
  nodeId: string(),
20283
20399
  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({
20400
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20291
20401
  success: boolean(),
20292
20402
  removed: boolean()
20293
20403
  }), {
@@ -20319,7 +20429,18 @@ method(object({
20319
20429
  }), object({ success: literal(true) }), {
20320
20430
  kind: "mutation",
20321
20431
  auth: "admin"
20322
- }), method(object({ agentNodeId: string() }), object({
20432
+ }), method(object({
20433
+ agentNodeId: string(),
20434
+ inferenceDevices: record(string(), object({
20435
+ enabled: boolean(),
20436
+ weight: number().positive().optional(),
20437
+ maxSessions: number().int().positive().optional(),
20438
+ steps: record(string(), DeviceStepConfigSchema).optional()
20439
+ }))
20440
+ }), object({ success: literal(true) }), {
20441
+ kind: "mutation",
20442
+ auth: "admin"
20443
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20323
20444
  success: literal(true),
20324
20445
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20325
20446
  effectiveModelId: string().nullable(),
@@ -20335,9 +20456,10 @@ method(object({
20335
20456
  }), object({ success: literal(true) }), {
20336
20457
  kind: "mutation",
20337
20458
  auth: "admin"
20338
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20459
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20339
20460
  deviceId: number(),
20340
20461
  agentNodeId: string(),
20462
+ deviceKey: string(),
20341
20463
  addonId: string(),
20342
20464
  patch: CameraStepOverridePatchSchema.nullable()
20343
20465
  }), object({ success: literal(true) }), {
@@ -20374,14 +20496,13 @@ method(object({
20374
20496
  });
20375
20497
  /**
20376
20498
  * server-management — per-NODE singleton capability for a node's ROOT
20377
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20378
- * agents).
20499
+ * package lifecycle (runtime-updatable node packages).
20379
20500
  *
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).
20501
+ * Every node role runs the SAME root package (`@camstack/server`), which
20502
+ * carries the whole software stack in its npm dep tree, so ONE version
20503
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20504
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20505
+ * no auto-rollback).
20385
20506
  *
20386
20507
  * Providers:
20387
20508
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20489,7 +20610,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20489
20610
  /** Explicit target version; omitted = latest from the registry. */
20490
20611
  version: string().optional() }), ServerUpdateActionResultSchema, {
20491
20612
  kind: "mutation",
20492
- auth: "admin"
20613
+ auth: "admin",
20614
+ timeoutMs: 16 * 6e4
20493
20615
  }), method(_void(), ServerUpdateActionResultSchema, {
20494
20616
  kind: "mutation",
20495
20617
  auth: "admin"
@@ -21584,22 +21706,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21584
21706
  var RestartAddonResultSchema = unknown();
21585
21707
  var InstallPackageResultSchema = unknown();
21586
21708
  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
21709
  var BulkUpdateItemStatusSchema = _enum([
21604
21710
  "queued",
21605
21711
  "updating",
@@ -21727,13 +21833,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21727
21833
  }), object({ success: literal(true) }), {
21728
21834
  kind: "mutation",
21729
21835
  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
21836
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21738
21837
  kind: "mutation",
21739
21838
  auth: "admin"
@@ -22650,10 +22749,10 @@ var TopologyCategorySchema = object({
22650
22749
  addons: array(TopologyCategoryAddonSchema).readonly()
22651
22750
  });
22652
22751
  /**
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.
22752
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22753
+ * root package for every node role) as reported by its `registerNode`
22754
+ * manifest — version visibility for the Server management surface. Nullable:
22755
+ * offline rows and nodes that never reported one.
22657
22756
  */
22658
22757
  var TopologyRootPackageSchema = object({
22659
22758
  name: string(),
@@ -23087,17 +23186,28 @@ var PlatformScoreSchema = object({
23087
23186
  format: _enum([
23088
23187
  "onnx",
23089
23188
  "coreml",
23090
- "openvino"
23189
+ "openvino",
23190
+ "tflite"
23091
23191
  ]),
23092
23192
  score: number(),
23093
23193
  reason: string(),
23094
23194
  available: boolean()
23095
23195
  });
23196
+ var InferenceDeviceDescriptorSchema = object({
23197
+ key: string(),
23198
+ backend: string(),
23199
+ device: string(),
23200
+ format: ModelFormatSchema,
23201
+ runtime: literal("python"),
23202
+ score: number(),
23203
+ available: boolean()
23204
+ });
23096
23205
  var PlatformCapabilitiesSchema = object({
23097
23206
  hardware: HardwareInfoSchema,
23098
23207
  scores: array(PlatformScoreSchema).readonly(),
23099
23208
  bestScore: PlatformScoreSchema,
23100
- pythonPath: string().nullable()
23209
+ pythonPath: string().nullable(),
23210
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
23101
23211
  });
23102
23212
  var ModelRequirementSchema = object({
23103
23213
  modelId: string(),
@@ -24254,12 +24364,6 @@ Object.freeze({
24254
24364
  addonId: null,
24255
24365
  access: "delete"
24256
24366
  },
24257
- "addons.updateFrameworkPackage": {
24258
- capName: "addons",
24259
- capScope: "system",
24260
- addonId: null,
24261
- access: "create"
24262
- },
24263
24367
  "addons.updatePackage": {
24264
24368
  capName: "addons",
24265
24369
  capScope: "system",
@@ -27032,12 +27136,6 @@ Object.freeze({
27032
27136
  addonId: null,
27033
27137
  access: "view"
27034
27138
  },
27035
- "pipelineExecutor.reprobeEngine": {
27036
- capName: "pipeline-executor",
27037
- capScope: "system",
27038
- addonId: null,
27039
- access: "create"
27040
- },
27041
27139
  "pipelineExecutor.runAudioTest": {
27042
27140
  capName: "pipeline-executor",
27043
27141
  capScope: "system",
@@ -27188,6 +27286,12 @@ Object.freeze({
27188
27286
  addonId: null,
27189
27287
  access: "view"
27190
27288
  },
27289
+ "pipelineOrchestrator.getNodeInferenceDevices": {
27290
+ capName: "pipeline-orchestrator",
27291
+ capScope: "system",
27292
+ addonId: null,
27293
+ access: "view"
27294
+ },
27191
27295
  "pipelineOrchestrator.getPipelineAssignment": {
27192
27296
  capName: "pipeline-orchestrator",
27193
27297
  capScope: "system",
@@ -27200,6 +27304,12 @@ Object.freeze({
27200
27304
  addonId: null,
27201
27305
  access: "view"
27202
27306
  },
27307
+ "pipelineOrchestrator.getPipelineDevicePin": {
27308
+ capName: "pipeline-orchestrator",
27309
+ capScope: "system",
27310
+ addonId: null,
27311
+ access: "view"
27312
+ },
27203
27313
  "pipelineOrchestrator.listAgentSettings": {
27204
27314
  capName: "pipeline-orchestrator",
27205
27315
  capScope: "system",
@@ -27242,19 +27352,19 @@ Object.freeze({
27242
27352
  addonId: null,
27243
27353
  access: "create"
27244
27354
  },
27245
- "pipelineOrchestrator.setAgentAddonDefaults": {
27355
+ "pipelineOrchestrator.setAgentCapabilities": {
27246
27356
  capName: "pipeline-orchestrator",
27247
27357
  capScope: "system",
27248
27358
  addonId: null,
27249
27359
  access: "create"
27250
27360
  },
27251
- "pipelineOrchestrator.setAgentCapabilities": {
27361
+ "pipelineOrchestrator.setAgentDetectWeight": {
27252
27362
  capName: "pipeline-orchestrator",
27253
27363
  capScope: "system",
27254
27364
  addonId: null,
27255
27365
  access: "create"
27256
27366
  },
27257
- "pipelineOrchestrator.setAgentDetectWeight": {
27367
+ "pipelineOrchestrator.setAgentInferenceDevices": {
27258
27368
  capName: "pipeline-orchestrator",
27259
27369
  capScope: "system",
27260
27370
  addonId: null,
@@ -27296,6 +27406,12 @@ Object.freeze({
27296
27406
  addonId: null,
27297
27407
  access: "create"
27298
27408
  },
27409
+ "pipelineOrchestrator.setPipelineDevicePin": {
27410
+ capName: "pipeline-orchestrator",
27411
+ capScope: "system",
27412
+ addonId: null,
27413
+ access: "create"
27414
+ },
27299
27415
  "pipelineOrchestrator.unassignAudio": {
27300
27416
  capName: "pipeline-orchestrator",
27301
27417
  capScope: "system",
@@ -28848,32 +28964,6 @@ Object.freeze({
28848
28964
  "network-access": "ingress",
28849
28965
  "smtp-provider": "email"
28850
28966
  });
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
28967
  //#endregion
28878
28968
  //#region src/schema.ts
28879
28969
  /**
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.0",
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",