@camstack/system 1.1.62 → 1.1.64

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 (53) hide show
  1. package/dist/addon-runner.js +2 -2
  2. package/dist/addon-runner.mjs +2 -2
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  11. package/dist/builtins/console-logging/index.js +1 -1
  12. package/dist/builtins/console-logging/index.mjs +1 -1
  13. package/dist/builtins/device-manager/device-manager.addon.js +1 -1
  14. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  15. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  16. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  17. package/dist/builtins/hub-forwarder/index.js +1 -1
  18. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  19. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  20. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  21. package/dist/builtins/local-network/local-network.addon.js +1 -1
  22. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  23. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  24. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  25. package/dist/builtins/platform-probe/index.js +26 -7
  26. package/dist/builtins/platform-probe/index.mjs +26 -7
  27. package/dist/builtins/platform-probe/intel-accelerators.d.ts +6 -3
  28. package/dist/builtins/platform-probe/intel-npu.d.ts +38 -0
  29. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  30. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  31. package/dist/builtins/snapshot/index.js +1 -1
  32. package/dist/builtins/snapshot/index.mjs +1 -1
  33. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  34. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  35. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
  36. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  37. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  38. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  39. package/dist/builtins/system-config/system-config.addon.js +1 -1
  40. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  41. package/dist/builtins/winston-logging/index.js +1 -1
  42. package/dist/builtins/winston-logging/index.mjs +1 -1
  43. package/dist/{dist-Z2gkbfp8.js → dist-C0Pf5ShP.js} +161 -46
  44. package/dist/{dist-BqC8e44T.mjs → dist-Dycu89sF.mjs} +161 -46
  45. package/dist/index.js +2 -2
  46. package/dist/index.mjs +2 -2
  47. package/dist/{intel-accelerators-Gg0P5mnl.js → intel-accelerators-BvBjZn4j.js} +1 -5
  48. package/dist/{intel-accelerators-hGgpZ0pX.mjs → intel-accelerators-idEumqk1.mjs} +1 -5
  49. package/dist/intel-npu-C8HKvRQF.mjs +27 -0
  50. package/dist/intel-npu-DYF5hO5K.js +28 -0
  51. package/dist/{manifest-python-deps-Houw5lw4.js → manifest-python-deps-BRFns0U-.js} +1 -1
  52. package/dist/{manifest-python-deps-DQVZZVNo.mjs → manifest-python-deps-BiM1uDhe.mjs} +1 -1
  53. package/package.json +1 -1
@@ -8594,20 +8594,6 @@ var pipelineExecutorCapability = {
8594
8594
  getSelectedEngine: method(zod.z.void(), PipelineEngineChoiceSchema),
8595
8595
  getDefaultSteps: method(PipelineEngineChoiceSchema, zod.z.array(PipelineDefaultStepSchema)),
8596
8596
  /**
8597
- * Re-run the platform probe for the inference engine and write the
8598
- * detected runtime / backend / device back into the addon's own
8599
- * global settings store. Returns the engine that was picked so the
8600
- * UI can confirm without a second round-trip. Triggers the standard
8601
- * `requiresRestart` auto-restart flow because all three fields are
8602
- * marked restart-required. Replaces the legacy per-agent
8603
- * `pipeline-orchestrator.reprobeAgentHwAccel` surface for the
8604
- * engine dimension — each addon now owns its own probe.
8605
- */
8606
- reprobeEngine: method(zod.z.void(), PipelineEngineChoiceSchema, {
8607
- kind: "mutation",
8608
- auth: "admin"
8609
- }),
8610
- /**
8611
8597
  * Per-node detection-engine provisioning snapshot. Returns the live
8612
8598
  * state of the lazy runtime-provisioning machine on `nodeId`
8613
8599
  * (idle / installing / verifying / ready / failed). The UI pairs this
@@ -9271,6 +9257,19 @@ var RunnerLocalLoadSchema = zod.z.object({
9271
9257
  avgInferenceTimeMs: zod.z.number(),
9272
9258
  /** Total queue depth across motion + detection queues. */
9273
9259
  queueDepthTotal: zod.z.number(),
9260
+ /**
9261
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
9262
+ * this runner currently has attached cameras on, so the orchestrator's second
9263
+ * `balance()` pass (over a node's devices) weights on real per-pool session
9264
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
9265
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
9266
+ */
9267
+ devices: zod.z.array(zod.z.object({
9268
+ deviceKey: zod.z.string(),
9269
+ backend: zod.z.string(),
9270
+ attachedCameras: zod.z.number(),
9271
+ queueDepthTotal: zod.z.number()
9272
+ })).default([]),
9274
9273
  /** Hardware capability flags reported by this node. */
9275
9274
  hardware: zod.z.object({
9276
9275
  hasGpu: zod.z.boolean(),
@@ -16925,13 +16924,11 @@ var PipelineTemplateSchema = zod.z.object({
16925
16924
  createdAt: zod.z.string(),
16926
16925
  updatedAt: zod.z.string()
16927
16926
  });
16928
- var AgentAddonConfigSchema = zod.z.object({
16929
- enabled: zod.z.boolean(),
16927
+ var DeviceStepConfigSchema = zod.z.object({
16930
16928
  modelId: zod.z.string().optional(),
16931
- settings: zod.z.record(zod.z.string(), zod.z.unknown()).readonly()
16929
+ settings: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
16932
16930
  });
16933
16931
  var AgentPipelineSettingsSchema = zod.z.object({
16934
- addonDefaults: zod.z.record(zod.z.string(), AgentAddonConfigSchema).readonly(),
16935
16932
  maxCameras: zod.z.number().int().nonnegative().nullable().default(null),
16936
16933
  /** Per-node detection weight (relative share for the quota balancer). */
16937
16934
  detectWeight: zod.z.number().positive().optional(),
@@ -16958,13 +16955,18 @@ var AgentPipelineSettingsSchema = zod.z.object({
16958
16955
  reachableHost: zod.z.string().optional(),
16959
16956
  /**
16960
16957
  * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16961
- * weight}. Absent / all-disabled ⇒ the node's single default accelerator
16962
- * (safe default); two+ enabled ⇒ the dispatcher balances detection sessions
16963
- * across them so they run CONCURRENTLY.
16958
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16959
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16960
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16961
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16962
+ * the default model/settings for every camera landing on that accelerator;
16963
+ * a stepId absent ⇒ the step uses that device's format default.
16964
16964
  */
16965
16965
  inferenceDevices: zod.z.record(zod.z.string(), zod.z.object({
16966
16966
  enabled: zod.z.boolean(),
16967
- weight: zod.z.number().positive().optional()
16967
+ weight: zod.z.number().positive().optional(),
16968
+ maxSessions: zod.z.number().int().positive().optional(),
16969
+ steps: zod.z.record(zod.z.string(), DeviceStepConfigSchema).optional()
16968
16970
  })).optional()
16969
16971
  });
16970
16972
  var CameraPipelineForAgentSchema = zod.z.object({
@@ -16975,14 +16977,13 @@ var CameraPipelineForAgentSchema = zod.z.object({
16975
16977
  }).nullable()
16976
16978
  });
16977
16979
  var CameraStepOverridePatchSchema = zod.z.object({
16978
- enabled: zod.z.boolean().optional(),
16979
16980
  modelId: zod.z.string().optional(),
16980
16981
  settings: zod.z.record(zod.z.string(), zod.z.unknown()).readonly().optional()
16981
16982
  });
16982
16983
  var CameraPipelineSettingsSchema = zod.z.object({
16983
16984
  pinnedAgentNodeId: zod.z.string().optional(),
16984
16985
  stepToggles: zod.z.record(zod.z.string(), zod.z.boolean()).optional(),
16985
- stepOverridesByAgent: zod.z.record(zod.z.string(), zod.z.record(zod.z.string(), CameraStepOverridePatchSchema)).optional(),
16986
+ stepOverridesByDevice: zod.z.record(zod.z.string(), zod.z.record(zod.z.string(), zod.z.record(zod.z.string(), CameraStepOverridePatchSchema))).optional(),
16986
16987
  pipelineByAgent: zod.z.record(zod.z.string(), CameraPipelineForAgentSchema).optional()
16987
16988
  });
16988
16989
  /**
@@ -17204,6 +17205,44 @@ var CameraStatusSchema = zod.z.object({
17204
17205
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17205
17206
  fetchedAt: zod.z.number()
17206
17207
  });
17208
+ var NodeInferenceDeviceSchema = zod.z.object({
17209
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17210
+ key: zod.z.string(),
17211
+ backend: zod.z.string(),
17212
+ device: zod.z.string(),
17213
+ format: zod.z.enum(MODEL_FORMATS),
17214
+ /** Whether the node's live probe reports the device as usable right now. */
17215
+ available: zod.z.boolean(),
17216
+ /**
17217
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17218
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17219
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17220
+ * not a balanced target). An explicit stored value always wins; a stored-only
17221
+ * (unavailable) key keeps its stored value.
17222
+ */
17223
+ enabled: zod.z.boolean(),
17224
+ /** Relative balancer weight for the enabled device (default 1). */
17225
+ weight: zod.z.number(),
17226
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17227
+ maxSessions: zod.z.number().nullable(),
17228
+ /** Object-detection model the executor defaults to for this deviceKey. */
17229
+ defaultModelId: zod.z.string(),
17230
+ /**
17231
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17232
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17233
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17234
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17235
+ * available per format; this is the stored selection that becomes the
17236
+ * default for EVERY camera landing on this accelerator.
17237
+ */
17238
+ steps: zod.z.record(zod.z.string(), DeviceStepConfigSchema).optional()
17239
+ });
17240
+ var NodeInferenceDevicesSchema = zod.z.object({
17241
+ nodeId: zod.z.string(),
17242
+ /** False when the node's platform-probe was unreachable (no live device set). */
17243
+ reachable: zod.z.boolean(),
17244
+ devices: zod.z.array(NodeInferenceDeviceSchema).readonly()
17245
+ });
17207
17246
  /**
17208
17247
  * Pipeline Orchestrator capability — global load balancer + camera dispatcher.
17209
17248
  *
@@ -17253,6 +17292,34 @@ var pipelineOrchestratorCapability = {
17253
17292
  auth: "admin"
17254
17293
  }),
17255
17294
  /**
17295
+ * Pin a camera's detection to a specific INFERENCE DEVICE (accelerator)
17296
+ * within its node — a SOFT L1 device affinity honoured by the per-session
17297
+ * device `balance()` pass (sibling of the node-level `pipelineNodeId` pin;
17298
+ * persisted as `pipelineDeviceKey` in the device store, read by
17299
+ * `readPipelineDevicePin`). `deviceKey` is a concrete key
17300
+ * (`openvino:npu` / `edgetpu:usb` / `cpu`), or the `'auto'` sentinel /
17301
+ * empty string to CLEAR the pin and let the balancer pick the device.
17302
+ *
17303
+ * Applies promptly: the device is chosen per-session at dispatch, so any
17304
+ * running detection session is closed and re-dispatched onto the new pin
17305
+ * (the camera stays on the SAME node — a device pin never moves the camera).
17306
+ * Cameras with no active session pick it up on their next dispatch.
17307
+ */
17308
+ setPipelineDevicePin: method(zod.z.object({
17309
+ deviceId: zod.z.number(),
17310
+ deviceKey: zod.z.string()
17311
+ }), zod.z.object({ success: zod.z.literal(true) }), {
17312
+ kind: "mutation",
17313
+ auth: "admin"
17314
+ }),
17315
+ /**
17316
+ * Read a camera's persisted inference-device pin (`pipelineDeviceKey`).
17317
+ * Returns the concrete device key, or `null` when unpinned (auto). Lets the
17318
+ * UI show the current pin alongside the node pin (parity with the node-pin
17319
+ * value carried on the assignment record).
17320
+ */
17321
+ getPipelineDevicePin: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.object({ deviceKey: zod.z.string().nullable() })),
17322
+ /**
17256
17323
  * Trigger a full rebalance pass. Iterates over all assigned cameras,
17257
17324
  * recomputes the optimal agent for each one based on current load +
17258
17325
  * hardware affinity, and migrates cameras whose current agent is no
@@ -17337,14 +17404,6 @@ var pipelineOrchestratorCapability = {
17337
17404
  nodeId: zod.z.string(),
17338
17405
  settings: AgentPipelineSettingsSchema
17339
17406
  })).readonly()),
17340
- /** Bulk-replace ALL addon configs on one agent. Used by the agent-level PipelineEditor which emits the full map per edit. Merges on top of existing entries — omitted addonIds are left alone. */
17341
- setAgentAddonDefaults: method(zod.z.object({
17342
- agentNodeId: zod.z.string(),
17343
- defaults: zod.z.record(zod.z.string(), AgentAddonConfigSchema)
17344
- }), zod.z.object({ success: zod.z.literal(true) }), {
17345
- kind: "mutation",
17346
- auth: "admin"
17347
- }),
17348
17407
  /**
17349
17408
  * Drop a single agent's persisted settings. Used by the cluster
17350
17409
  * "Offline agents" panel to evict stale entries left behind when an
@@ -17431,6 +17490,46 @@ var pipelineOrchestratorCapability = {
17431
17490
  auth: "admin"
17432
17491
  }),
17433
17492
  /**
17493
+ * Set one node's multi-device inference opt-in (Phase 4 multi-device) — the
17494
+ * per-node `deviceKey → { enabled, weight }` map that decides which
17495
+ * accelerators the dispatcher may balance detection sessions across.
17496
+ * The map REPLACES the node's stored `inferenceDevices` wholesale (pass the
17497
+ * complete desired set; an empty map clears the opt-in → the node reverts to
17498
+ * its single DEFAULT accelerator). `weight` is optional and defaults to 1.
17499
+ * `models` is the optional per-device model override (`stepId → modelId`,
17500
+ * C7.2/C7.4) — a stepId absent ⇒ the step uses that device's default model.
17501
+ * Creates the node's settings entry if absent. Changes take effect on the
17502
+ * next dispatch/rebalance cycle — the dispatcher reads the enabled set via
17503
+ * `PipelineSettingsStore.buildNodeInferenceDevices` when placing sessions
17504
+ * and the per-(node,device) base provisioning via
17505
+ * `buildNodeInferenceDeviceSteps`.
17506
+ */
17507
+ setAgentInferenceDevices: method(zod.z.object({
17508
+ agentNodeId: zod.z.string(),
17509
+ inferenceDevices: zod.z.record(zod.z.string(), zod.z.object({
17510
+ enabled: zod.z.boolean(),
17511
+ weight: zod.z.number().positive().optional(),
17512
+ maxSessions: zod.z.number().int().positive().optional(),
17513
+ steps: zod.z.record(zod.z.string(), DeviceStepConfigSchema).optional()
17514
+ }))
17515
+ }), zod.z.object({ success: zod.z.literal(true) }), {
17516
+ kind: "mutation",
17517
+ auth: "admin"
17518
+ }),
17519
+ /**
17520
+ * DEVICE-AWARE merged view of ONE node's inference accelerators. Joins each
17521
+ * physical device the node HAS — probed live via a node-pinned
17522
+ * `platformProbe.getCapabilities` (the platform-probe singleton is targeted
17523
+ * by the `nodeId` cap INPUT, since a `nodePin` context is ignored by a
17524
+ * singleton mount) — with its stored opt-in (`enabled`/`weight`) and the
17525
+ * object-detection `defaultModelId` the executor would run for that
17526
+ * deviceKey. Disabled-but-configured keys still appear. An unreachable node
17527
+ * returns `reachable:false` + best-effort stored-only devices (never
17528
+ * throws). Read surface for the cluster/agent multi-device UI — hence a
17529
+ * default (read-level) auth, matching the other `getAgent*` reads.
17530
+ */
17531
+ getNodeInferenceDevices: method(zod.z.object({ nodeId: zod.z.string() }), NodeInferenceDevicesSchema),
17532
+ /**
17434
17533
  * Reset one node's pipeline to its hardware-aware defaults — the HONEST
17435
17534
  * reset (replaces the executor's legacy `resetToDefault`, which cleared a
17436
17535
  * dead persisted step-tree seed nothing in the live path read):
@@ -17469,15 +17568,18 @@ var pipelineOrchestratorCapability = {
17469
17568
  kind: "mutation",
17470
17569
  auth: "admin"
17471
17570
  }),
17472
- /** Read every L2.5 override map for a device. Null when device has no overrides. */
17473
- getCameraStepOverrides: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.record(zod.z.string(), zod.z.record(zod.z.string(), CameraStepOverridePatchSchema)).nullable()),
17571
+ /** Read every per-(node,device) override map for a device. Null when device has no overrides. */
17572
+ getCameraStepOverrides: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.record(zod.z.string(), zod.z.record(zod.z.string(), zod.z.record(zod.z.string(), CameraStepOverridePatchSchema))).nullable()),
17474
17573
  /**
17475
- * Write or clear the L2.5 per-agent override for one addonId on a device.
17476
- * `patch: null` clears the entry entirely for that (agent, addon) pair.
17574
+ * Write or clear the per-(camera,node,device) override for one addonId.
17575
+ * `patch: null` clears the entry entirely for that (node, deviceKey, addon)
17576
+ * triple (empty parents are pruned). Model/settings only — enablement is
17577
+ * the per-camera `stepToggles` authority.
17477
17578
  */
17478
17579
  setCameraStepOverride: method(zod.z.object({
17479
17580
  deviceId: zod.z.number(),
17480
17581
  agentNodeId: zod.z.string(),
17582
+ deviceKey: zod.z.string(),
17481
17583
  addonId: zod.z.string(),
17482
17584
  patch: CameraStepOverridePatchSchema.nullable()
17483
17585
  }), zod.z.object({ success: zod.z.literal(true) }), {
@@ -17673,7 +17775,8 @@ var serverManagementCapability = {
17673
17775
  /** Explicit target version; omitted = latest from the registry. */
17674
17776
  version: zod.z.string().optional() }), ServerUpdateActionResultSchema, {
17675
17777
  kind: "mutation",
17676
- auth: "admin"
17778
+ auth: "admin",
17779
+ timeoutMs: 16 * 6e4
17677
17780
  }),
17678
17781
  rollbackServerUpdate: method(zod.z.void(), ServerUpdateActionResultSchema, {
17679
17782
  kind: "mutation",
@@ -25487,12 +25590,6 @@ var METHOD_ACCESS_MAP = Object.freeze({
25487
25590
  addonId: null,
25488
25591
  access: "view"
25489
25592
  },
25490
- "pipelineExecutor.reprobeEngine": {
25491
- capName: "pipeline-executor",
25492
- capScope: "system",
25493
- addonId: null,
25494
- access: "create"
25495
- },
25496
25593
  "pipelineExecutor.runAudioTest": {
25497
25594
  capName: "pipeline-executor",
25498
25595
  capScope: "system",
@@ -25643,6 +25740,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
25643
25740
  addonId: null,
25644
25741
  access: "view"
25645
25742
  },
25743
+ "pipelineOrchestrator.getNodeInferenceDevices": {
25744
+ capName: "pipeline-orchestrator",
25745
+ capScope: "system",
25746
+ addonId: null,
25747
+ access: "view"
25748
+ },
25646
25749
  "pipelineOrchestrator.getPipelineAssignment": {
25647
25750
  capName: "pipeline-orchestrator",
25648
25751
  capScope: "system",
@@ -25655,6 +25758,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
25655
25758
  addonId: null,
25656
25759
  access: "view"
25657
25760
  },
25761
+ "pipelineOrchestrator.getPipelineDevicePin": {
25762
+ capName: "pipeline-orchestrator",
25763
+ capScope: "system",
25764
+ addonId: null,
25765
+ access: "view"
25766
+ },
25658
25767
  "pipelineOrchestrator.listAgentSettings": {
25659
25768
  capName: "pipeline-orchestrator",
25660
25769
  capScope: "system",
@@ -25697,19 +25806,19 @@ var METHOD_ACCESS_MAP = Object.freeze({
25697
25806
  addonId: null,
25698
25807
  access: "create"
25699
25808
  },
25700
- "pipelineOrchestrator.setAgentAddonDefaults": {
25809
+ "pipelineOrchestrator.setAgentCapabilities": {
25701
25810
  capName: "pipeline-orchestrator",
25702
25811
  capScope: "system",
25703
25812
  addonId: null,
25704
25813
  access: "create"
25705
25814
  },
25706
- "pipelineOrchestrator.setAgentCapabilities": {
25815
+ "pipelineOrchestrator.setAgentDetectWeight": {
25707
25816
  capName: "pipeline-orchestrator",
25708
25817
  capScope: "system",
25709
25818
  addonId: null,
25710
25819
  access: "create"
25711
25820
  },
25712
- "pipelineOrchestrator.setAgentDetectWeight": {
25821
+ "pipelineOrchestrator.setAgentInferenceDevices": {
25713
25822
  capName: "pipeline-orchestrator",
25714
25823
  capScope: "system",
25715
25824
  addonId: null,
@@ -25751,6 +25860,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
25751
25860
  addonId: null,
25752
25861
  access: "create"
25753
25862
  },
25863
+ "pipelineOrchestrator.setPipelineDevicePin": {
25864
+ capName: "pipeline-orchestrator",
25865
+ capScope: "system",
25866
+ addonId: null,
25867
+ access: "create"
25868
+ },
25754
25869
  "pipelineOrchestrator.unassignAudio": {
25755
25870
  capName: "pipeline-orchestrator",
25756
25871
  capScope: "system",
@@ -8594,20 +8594,6 @@ var pipelineExecutorCapability = {
8594
8594
  getSelectedEngine: method(z.void(), PipelineEngineChoiceSchema),
8595
8595
  getDefaultSteps: method(PipelineEngineChoiceSchema, z.array(PipelineDefaultStepSchema)),
8596
8596
  /**
8597
- * Re-run the platform probe for the inference engine and write the
8598
- * detected runtime / backend / device back into the addon's own
8599
- * global settings store. Returns the engine that was picked so the
8600
- * UI can confirm without a second round-trip. Triggers the standard
8601
- * `requiresRestart` auto-restart flow because all three fields are
8602
- * marked restart-required. Replaces the legacy per-agent
8603
- * `pipeline-orchestrator.reprobeAgentHwAccel` surface for the
8604
- * engine dimension — each addon now owns its own probe.
8605
- */
8606
- reprobeEngine: method(z.void(), PipelineEngineChoiceSchema, {
8607
- kind: "mutation",
8608
- auth: "admin"
8609
- }),
8610
- /**
8611
8597
  * Per-node detection-engine provisioning snapshot. Returns the live
8612
8598
  * state of the lazy runtime-provisioning machine on `nodeId`
8613
8599
  * (idle / installing / verifying / ready / failed). The UI pairs this
@@ -9271,6 +9257,19 @@ var RunnerLocalLoadSchema = z.object({
9271
9257
  avgInferenceTimeMs: z.number(),
9272
9258
  /** Total queue depth across motion + detection queues. */
9273
9259
  queueDepthTotal: z.number(),
9260
+ /**
9261
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
9262
+ * this runner currently has attached cameras on, so the orchestrator's second
9263
+ * `balance()` pass (over a node's devices) weights on real per-pool session
9264
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
9265
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
9266
+ */
9267
+ devices: z.array(z.object({
9268
+ deviceKey: z.string(),
9269
+ backend: z.string(),
9270
+ attachedCameras: z.number(),
9271
+ queueDepthTotal: z.number()
9272
+ })).default([]),
9274
9273
  /** Hardware capability flags reported by this node. */
9275
9274
  hardware: z.object({
9276
9275
  hasGpu: z.boolean(),
@@ -16925,13 +16924,11 @@ var PipelineTemplateSchema = z.object({
16925
16924
  createdAt: z.string(),
16926
16925
  updatedAt: z.string()
16927
16926
  });
16928
- var AgentAddonConfigSchema = z.object({
16929
- enabled: z.boolean(),
16927
+ var DeviceStepConfigSchema = z.object({
16930
16928
  modelId: z.string().optional(),
16931
- settings: z.record(z.string(), z.unknown()).readonly()
16929
+ settings: z.record(z.string(), z.unknown()).optional()
16932
16930
  });
16933
16931
  var AgentPipelineSettingsSchema = z.object({
16934
- addonDefaults: z.record(z.string(), AgentAddonConfigSchema).readonly(),
16935
16932
  maxCameras: z.number().int().nonnegative().nullable().default(null),
16936
16933
  /** Per-node detection weight (relative share for the quota balancer). */
16937
16934
  detectWeight: z.number().positive().optional(),
@@ -16958,13 +16955,18 @@ var AgentPipelineSettingsSchema = z.object({
16958
16955
  reachableHost: z.string().optional(),
16959
16956
  /**
16960
16957
  * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16961
- * weight}. Absent / all-disabled ⇒ the node's single default accelerator
16962
- * (safe default); two+ enabled ⇒ the dispatcher balances detection sessions
16963
- * across them so they run CONCURRENTLY.
16958
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16959
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16960
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16961
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16962
+ * the default model/settings for every camera landing on that accelerator;
16963
+ * a stepId absent ⇒ the step uses that device's format default.
16964
16964
  */
16965
16965
  inferenceDevices: z.record(z.string(), z.object({
16966
16966
  enabled: z.boolean(),
16967
- weight: z.number().positive().optional()
16967
+ weight: z.number().positive().optional(),
16968
+ maxSessions: z.number().int().positive().optional(),
16969
+ steps: z.record(z.string(), DeviceStepConfigSchema).optional()
16968
16970
  })).optional()
16969
16971
  });
16970
16972
  var CameraPipelineForAgentSchema = z.object({
@@ -16975,14 +16977,13 @@ var CameraPipelineForAgentSchema = z.object({
16975
16977
  }).nullable()
16976
16978
  });
16977
16979
  var CameraStepOverridePatchSchema = z.object({
16978
- enabled: z.boolean().optional(),
16979
16980
  modelId: z.string().optional(),
16980
16981
  settings: z.record(z.string(), z.unknown()).readonly().optional()
16981
16982
  });
16982
16983
  var CameraPipelineSettingsSchema = z.object({
16983
16984
  pinnedAgentNodeId: z.string().optional(),
16984
16985
  stepToggles: z.record(z.string(), z.boolean()).optional(),
16985
- stepOverridesByAgent: z.record(z.string(), z.record(z.string(), CameraStepOverridePatchSchema)).optional(),
16986
+ stepOverridesByDevice: z.record(z.string(), z.record(z.string(), z.record(z.string(), CameraStepOverridePatchSchema))).optional(),
16986
16987
  pipelineByAgent: z.record(z.string(), CameraPipelineForAgentSchema).optional()
16987
16988
  });
16988
16989
  /**
@@ -17204,6 +17205,44 @@ var CameraStatusSchema = z.object({
17204
17205
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17205
17206
  fetchedAt: z.number()
17206
17207
  });
17208
+ var NodeInferenceDeviceSchema = z.object({
17209
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17210
+ key: z.string(),
17211
+ backend: z.string(),
17212
+ device: z.string(),
17213
+ format: z.enum(MODEL_FORMATS),
17214
+ /** Whether the node's live probe reports the device as usable right now. */
17215
+ available: z.boolean(),
17216
+ /**
17217
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17218
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17219
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17220
+ * not a balanced target). An explicit stored value always wins; a stored-only
17221
+ * (unavailable) key keeps its stored value.
17222
+ */
17223
+ enabled: z.boolean(),
17224
+ /** Relative balancer weight for the enabled device (default 1). */
17225
+ weight: z.number(),
17226
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17227
+ maxSessions: z.number().nullable(),
17228
+ /** Object-detection model the executor defaults to for this deviceKey. */
17229
+ defaultModelId: z.string(),
17230
+ /**
17231
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17232
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17233
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17234
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17235
+ * available per format; this is the stored selection that becomes the
17236
+ * default for EVERY camera landing on this accelerator.
17237
+ */
17238
+ steps: z.record(z.string(), DeviceStepConfigSchema).optional()
17239
+ });
17240
+ var NodeInferenceDevicesSchema = z.object({
17241
+ nodeId: z.string(),
17242
+ /** False when the node's platform-probe was unreachable (no live device set). */
17243
+ reachable: z.boolean(),
17244
+ devices: z.array(NodeInferenceDeviceSchema).readonly()
17245
+ });
17207
17246
  /**
17208
17247
  * Pipeline Orchestrator capability — global load balancer + camera dispatcher.
17209
17248
  *
@@ -17253,6 +17292,34 @@ var pipelineOrchestratorCapability = {
17253
17292
  auth: "admin"
17254
17293
  }),
17255
17294
  /**
17295
+ * Pin a camera's detection to a specific INFERENCE DEVICE (accelerator)
17296
+ * within its node — a SOFT L1 device affinity honoured by the per-session
17297
+ * device `balance()` pass (sibling of the node-level `pipelineNodeId` pin;
17298
+ * persisted as `pipelineDeviceKey` in the device store, read by
17299
+ * `readPipelineDevicePin`). `deviceKey` is a concrete key
17300
+ * (`openvino:npu` / `edgetpu:usb` / `cpu`), or the `'auto'` sentinel /
17301
+ * empty string to CLEAR the pin and let the balancer pick the device.
17302
+ *
17303
+ * Applies promptly: the device is chosen per-session at dispatch, so any
17304
+ * running detection session is closed and re-dispatched onto the new pin
17305
+ * (the camera stays on the SAME node — a device pin never moves the camera).
17306
+ * Cameras with no active session pick it up on their next dispatch.
17307
+ */
17308
+ setPipelineDevicePin: method(z.object({
17309
+ deviceId: z.number(),
17310
+ deviceKey: z.string()
17311
+ }), z.object({ success: z.literal(true) }), {
17312
+ kind: "mutation",
17313
+ auth: "admin"
17314
+ }),
17315
+ /**
17316
+ * Read a camera's persisted inference-device pin (`pipelineDeviceKey`).
17317
+ * Returns the concrete device key, or `null` when unpinned (auto). Lets the
17318
+ * UI show the current pin alongside the node pin (parity with the node-pin
17319
+ * value carried on the assignment record).
17320
+ */
17321
+ getPipelineDevicePin: method(z.object({ deviceId: z.number() }), z.object({ deviceKey: z.string().nullable() })),
17322
+ /**
17256
17323
  * Trigger a full rebalance pass. Iterates over all assigned cameras,
17257
17324
  * recomputes the optimal agent for each one based on current load +
17258
17325
  * hardware affinity, and migrates cameras whose current agent is no
@@ -17337,14 +17404,6 @@ var pipelineOrchestratorCapability = {
17337
17404
  nodeId: z.string(),
17338
17405
  settings: AgentPipelineSettingsSchema
17339
17406
  })).readonly()),
17340
- /** Bulk-replace ALL addon configs on one agent. Used by the agent-level PipelineEditor which emits the full map per edit. Merges on top of existing entries — omitted addonIds are left alone. */
17341
- setAgentAddonDefaults: method(z.object({
17342
- agentNodeId: z.string(),
17343
- defaults: z.record(z.string(), AgentAddonConfigSchema)
17344
- }), z.object({ success: z.literal(true) }), {
17345
- kind: "mutation",
17346
- auth: "admin"
17347
- }),
17348
17407
  /**
17349
17408
  * Drop a single agent's persisted settings. Used by the cluster
17350
17409
  * "Offline agents" panel to evict stale entries left behind when an
@@ -17431,6 +17490,46 @@ var pipelineOrchestratorCapability = {
17431
17490
  auth: "admin"
17432
17491
  }),
17433
17492
  /**
17493
+ * Set one node's multi-device inference opt-in (Phase 4 multi-device) — the
17494
+ * per-node `deviceKey → { enabled, weight }` map that decides which
17495
+ * accelerators the dispatcher may balance detection sessions across.
17496
+ * The map REPLACES the node's stored `inferenceDevices` wholesale (pass the
17497
+ * complete desired set; an empty map clears the opt-in → the node reverts to
17498
+ * its single DEFAULT accelerator). `weight` is optional and defaults to 1.
17499
+ * `models` is the optional per-device model override (`stepId → modelId`,
17500
+ * C7.2/C7.4) — a stepId absent ⇒ the step uses that device's default model.
17501
+ * Creates the node's settings entry if absent. Changes take effect on the
17502
+ * next dispatch/rebalance cycle — the dispatcher reads the enabled set via
17503
+ * `PipelineSettingsStore.buildNodeInferenceDevices` when placing sessions
17504
+ * and the per-(node,device) base provisioning via
17505
+ * `buildNodeInferenceDeviceSteps`.
17506
+ */
17507
+ setAgentInferenceDevices: method(z.object({
17508
+ agentNodeId: z.string(),
17509
+ inferenceDevices: z.record(z.string(), z.object({
17510
+ enabled: z.boolean(),
17511
+ weight: z.number().positive().optional(),
17512
+ maxSessions: z.number().int().positive().optional(),
17513
+ steps: z.record(z.string(), DeviceStepConfigSchema).optional()
17514
+ }))
17515
+ }), z.object({ success: z.literal(true) }), {
17516
+ kind: "mutation",
17517
+ auth: "admin"
17518
+ }),
17519
+ /**
17520
+ * DEVICE-AWARE merged view of ONE node's inference accelerators. Joins each
17521
+ * physical device the node HAS — probed live via a node-pinned
17522
+ * `platformProbe.getCapabilities` (the platform-probe singleton is targeted
17523
+ * by the `nodeId` cap INPUT, since a `nodePin` context is ignored by a
17524
+ * singleton mount) — with its stored opt-in (`enabled`/`weight`) and the
17525
+ * object-detection `defaultModelId` the executor would run for that
17526
+ * deviceKey. Disabled-but-configured keys still appear. An unreachable node
17527
+ * returns `reachable:false` + best-effort stored-only devices (never
17528
+ * throws). Read surface for the cluster/agent multi-device UI — hence a
17529
+ * default (read-level) auth, matching the other `getAgent*` reads.
17530
+ */
17531
+ getNodeInferenceDevices: method(z.object({ nodeId: z.string() }), NodeInferenceDevicesSchema),
17532
+ /**
17434
17533
  * Reset one node's pipeline to its hardware-aware defaults — the HONEST
17435
17534
  * reset (replaces the executor's legacy `resetToDefault`, which cleared a
17436
17535
  * dead persisted step-tree seed nothing in the live path read):
@@ -17469,15 +17568,18 @@ var pipelineOrchestratorCapability = {
17469
17568
  kind: "mutation",
17470
17569
  auth: "admin"
17471
17570
  }),
17472
- /** Read every L2.5 override map for a device. Null when device has no overrides. */
17473
- getCameraStepOverrides: method(z.object({ deviceId: z.number() }), z.record(z.string(), z.record(z.string(), CameraStepOverridePatchSchema)).nullable()),
17571
+ /** Read every per-(node,device) override map for a device. Null when device has no overrides. */
17572
+ getCameraStepOverrides: method(z.object({ deviceId: z.number() }), z.record(z.string(), z.record(z.string(), z.record(z.string(), CameraStepOverridePatchSchema))).nullable()),
17474
17573
  /**
17475
- * Write or clear the L2.5 per-agent override for one addonId on a device.
17476
- * `patch: null` clears the entry entirely for that (agent, addon) pair.
17574
+ * Write or clear the per-(camera,node,device) override for one addonId.
17575
+ * `patch: null` clears the entry entirely for that (node, deviceKey, addon)
17576
+ * triple (empty parents are pruned). Model/settings only — enablement is
17577
+ * the per-camera `stepToggles` authority.
17477
17578
  */
17478
17579
  setCameraStepOverride: method(z.object({
17479
17580
  deviceId: z.number(),
17480
17581
  agentNodeId: z.string(),
17582
+ deviceKey: z.string(),
17481
17583
  addonId: z.string(),
17482
17584
  patch: CameraStepOverridePatchSchema.nullable()
17483
17585
  }), z.object({ success: z.literal(true) }), {
@@ -17673,7 +17775,8 @@ var serverManagementCapability = {
17673
17775
  /** Explicit target version; omitted = latest from the registry. */
17674
17776
  version: z.string().optional() }), ServerUpdateActionResultSchema, {
17675
17777
  kind: "mutation",
17676
- auth: "admin"
17778
+ auth: "admin",
17779
+ timeoutMs: 16 * 6e4
17677
17780
  }),
17678
17781
  rollbackServerUpdate: method(z.void(), ServerUpdateActionResultSchema, {
17679
17782
  kind: "mutation",
@@ -25487,12 +25590,6 @@ var METHOD_ACCESS_MAP = Object.freeze({
25487
25590
  addonId: null,
25488
25591
  access: "view"
25489
25592
  },
25490
- "pipelineExecutor.reprobeEngine": {
25491
- capName: "pipeline-executor",
25492
- capScope: "system",
25493
- addonId: null,
25494
- access: "create"
25495
- },
25496
25593
  "pipelineExecutor.runAudioTest": {
25497
25594
  capName: "pipeline-executor",
25498
25595
  capScope: "system",
@@ -25643,6 +25740,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
25643
25740
  addonId: null,
25644
25741
  access: "view"
25645
25742
  },
25743
+ "pipelineOrchestrator.getNodeInferenceDevices": {
25744
+ capName: "pipeline-orchestrator",
25745
+ capScope: "system",
25746
+ addonId: null,
25747
+ access: "view"
25748
+ },
25646
25749
  "pipelineOrchestrator.getPipelineAssignment": {
25647
25750
  capName: "pipeline-orchestrator",
25648
25751
  capScope: "system",
@@ -25655,6 +25758,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
25655
25758
  addonId: null,
25656
25759
  access: "view"
25657
25760
  },
25761
+ "pipelineOrchestrator.getPipelineDevicePin": {
25762
+ capName: "pipeline-orchestrator",
25763
+ capScope: "system",
25764
+ addonId: null,
25765
+ access: "view"
25766
+ },
25658
25767
  "pipelineOrchestrator.listAgentSettings": {
25659
25768
  capName: "pipeline-orchestrator",
25660
25769
  capScope: "system",
@@ -25697,19 +25806,19 @@ var METHOD_ACCESS_MAP = Object.freeze({
25697
25806
  addonId: null,
25698
25807
  access: "create"
25699
25808
  },
25700
- "pipelineOrchestrator.setAgentAddonDefaults": {
25809
+ "pipelineOrchestrator.setAgentCapabilities": {
25701
25810
  capName: "pipeline-orchestrator",
25702
25811
  capScope: "system",
25703
25812
  addonId: null,
25704
25813
  access: "create"
25705
25814
  },
25706
- "pipelineOrchestrator.setAgentCapabilities": {
25815
+ "pipelineOrchestrator.setAgentDetectWeight": {
25707
25816
  capName: "pipeline-orchestrator",
25708
25817
  capScope: "system",
25709
25818
  addonId: null,
25710
25819
  access: "create"
25711
25820
  },
25712
- "pipelineOrchestrator.setAgentDetectWeight": {
25821
+ "pipelineOrchestrator.setAgentInferenceDevices": {
25713
25822
  capName: "pipeline-orchestrator",
25714
25823
  capScope: "system",
25715
25824
  addonId: null,
@@ -25751,6 +25860,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
25751
25860
  addonId: null,
25752
25861
  access: "create"
25753
25862
  },
25863
+ "pipelineOrchestrator.setPipelineDevicePin": {
25864
+ capName: "pipeline-orchestrator",
25865
+ capScope: "system",
25866
+ addonId: null,
25867
+ access: "create"
25868
+ },
25754
25869
  "pipelineOrchestrator.unassignAudio": {
25755
25870
  capName: "pipeline-orchestrator",
25756
25871
  capScope: "system",