@camstack/addon-provider-reolink 1.1.31 → 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 +180 -48
  2. package/dist/addon.mjs +180 -48
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -12638,10 +12638,7 @@ var ConfigUISchemaNullableBridge = custom$2();
12638
12638
  var InferenceCapabilitiesBridge = custom$2();
12639
12639
  var ModelAvailabilityListBridge = custom$2();
12640
12640
  var PipelineRunResultBridge = custom$2();
12641
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12642
- kind: "mutation",
12643
- auth: "admin"
12644
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12641
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12645
12642
  modelId: string(),
12646
12643
  settings: record(string(), unknown()).readonly()
12647
12644
  }))), method(object({ steps: record(string(), object({
@@ -12701,13 +12698,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12701
12698
  * (inputClasses ≠ null) are skipped and served per-track via
12702
12699
  * pipelineRunner.runDetailSubtree (two-plane design).
12703
12700
  */
12704
- plane: _enum(["full", "frame"]).optional()
12701
+ plane: _enum(["full", "frame"]).optional(),
12702
+ /**
12703
+ * Inference-device selector (Phase 2 multi-device). Format
12704
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12705
+ * Omitted ⇒ the runner's default device (current single-engine
12706
+ * behaviour). Selects WHICH device pool of the node runs the call.
12707
+ */
12708
+ deviceKey: string().optional()
12705
12709
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12706
12710
  engine: PipelineEngineChoiceSchema.optional(),
12707
12711
  steps: array(PipelineStepInputSchema).min(1),
12708
12712
  frames: array(FrameInputSchema).min(1).max(255),
12709
12713
  deviceId: number().optional(),
12710
- sessionId: string().optional()
12714
+ sessionId: string().optional(),
12715
+ /**
12716
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12717
+ * the batch to the Python pool's bench preprocess cache
12718
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12719
+ * preprocessed ONCE and every later inference is a pure-inference cache
12720
+ * hit — the sustained-throughput run measures inference, not
12721
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12722
+ * full preprocess every call, correct). Fresh per sustained run;
12723
+ * released via `uncacheFrame`.
12724
+ */
12725
+ frameId: number().int().nonnegative().optional(),
12726
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12727
+ deviceKey: string().optional()
12711
12728
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12712
12729
  data: _instanceof(Uint8Array),
12713
12730
  width: number().int().positive(),
@@ -12739,8 +12756,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12739
12756
  * - `runtime` — main camera-serving engine (no idle TTL).
12740
12757
  * - `warm-override` — benchmark/test override held in the warm
12741
12758
  * cache; auto-disposed after the idle TTL.
12759
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12760
+ * multi-device, keyed by `deviceKey`) resolved
12761
+ * via `resolveDeviceFactory`. Runs alongside the
12762
+ * `runtime` engine on a DIFFERENT accelerator
12763
+ * (NPU / iGPU / Coral) — this is how the
12764
+ * Engines tab shows all pools running at once.
12742
12765
  */
12743
- kind: _enum(["runtime", "warm-override"]),
12766
+ kind: _enum([
12767
+ "runtime",
12768
+ "warm-override",
12769
+ "device-pool"
12770
+ ]),
12744
12771
  /** Native pid of the underlying Python pool (null when no pool). */
12745
12772
  poolPid: number().nullable(),
12746
12773
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -13115,7 +13142,14 @@ var RunnerCameraConfigSchema = object({
13115
13142
  * camera's detect node differs from its source-owner (P2d, gated by the
13116
13143
  * `remoteSourcingNodes` rollout setting).
13117
13144
  */
13118
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13145
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13146
+ /**
13147
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13148
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13149
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13150
+ * this only selects WHICH device pool of that node runs the session.
13151
+ */
13152
+ deviceKey: string().optional()
13119
13153
  });
13120
13154
  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;
13121
13155
  /**
@@ -13136,6 +13170,19 @@ var RunnerLocalLoadSchema = object({
13136
13170
  avgInferenceTimeMs: number(),
13137
13171
  /** Total queue depth across motion + detection queues. */
13138
13172
  queueDepthTotal: number(),
13173
+ /**
13174
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13175
+ * this runner currently has attached cameras on, so the orchestrator's second
13176
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13177
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13178
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13179
+ */
13180
+ devices: array(object({
13181
+ deviceKey: string(),
13182
+ backend: string(),
13183
+ attachedCameras: number(),
13184
+ queueDepthTotal: number()
13185
+ })).default([]),
13139
13186
  /** Hardware capability flags reported by this node. */
13140
13187
  hardware: object({
13141
13188
  hasGpu: boolean(),
@@ -19967,13 +20014,11 @@ var PipelineTemplateSchema = object({
19967
20014
  createdAt: string(),
19968
20015
  updatedAt: string()
19969
20016
  });
19970
- var AgentAddonConfigSchema = object({
19971
- enabled: boolean(),
20017
+ var DeviceStepConfigSchema = object({
19972
20018
  modelId: string().optional(),
19973
- settings: record(string(), unknown()).readonly()
20019
+ settings: record(string(), unknown()).optional()
19974
20020
  });
19975
20021
  var AgentPipelineSettingsSchema = object({
19976
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19977
20022
  maxCameras: number().int().nonnegative().nullable().default(null),
19978
20023
  /** Per-node detection weight (relative share for the quota balancer). */
19979
20024
  detectWeight: number().positive().optional(),
@@ -19997,7 +20042,22 @@ var AgentPipelineSettingsSchema = object({
19997
20042
  * it already uses to reach the hub). Set this only when the auto-detected
19998
20043
  * address is wrong (multi-homed host, NAT, custom interface).
19999
20044
  */
20000
- reachableHost: string().optional()
20045
+ reachableHost: string().optional(),
20046
+ /**
20047
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20048
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20049
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20050
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20051
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20052
+ * the default model/settings for every camera landing on that accelerator;
20053
+ * a stepId absent ⇒ the step uses that device's format default.
20054
+ */
20055
+ inferenceDevices: record(string(), object({
20056
+ enabled: boolean(),
20057
+ weight: number().positive().optional(),
20058
+ maxSessions: number().int().positive().optional(),
20059
+ steps: record(string(), DeviceStepConfigSchema).optional()
20060
+ })).optional()
20001
20061
  });
20002
20062
  var CameraPipelineForAgentSchema = object({
20003
20063
  steps: array(PipelineStepInputSchema).readonly(),
@@ -20007,14 +20067,13 @@ var CameraPipelineForAgentSchema = object({
20007
20067
  }).nullable()
20008
20068
  });
20009
20069
  var CameraStepOverridePatchSchema = object({
20010
- enabled: boolean().optional(),
20011
20070
  modelId: string().optional(),
20012
20071
  settings: record(string(), unknown()).readonly().optional()
20013
20072
  });
20014
20073
  var CameraPipelineSettingsSchema = object({
20015
20074
  pinnedAgentNodeId: string().optional(),
20016
20075
  stepToggles: record(string(), boolean()).optional(),
20017
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20076
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
20018
20077
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
20019
20078
  });
20020
20079
  /**
@@ -20228,6 +20287,44 @@ var CameraStatusSchema = object({
20228
20287
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20229
20288
  fetchedAt: number()
20230
20289
  });
20290
+ var NodeInferenceDeviceSchema = object({
20291
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20292
+ key: string(),
20293
+ backend: string(),
20294
+ device: string(),
20295
+ format: _enum(MODEL_FORMATS),
20296
+ /** Whether the node's live probe reports the device as usable right now. */
20297
+ available: boolean(),
20298
+ /**
20299
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20300
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20301
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20302
+ * not a balanced target). An explicit stored value always wins; a stored-only
20303
+ * (unavailable) key keeps its stored value.
20304
+ */
20305
+ enabled: boolean(),
20306
+ /** Relative balancer weight for the enabled device (default 1). */
20307
+ weight: number(),
20308
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20309
+ maxSessions: number().nullable(),
20310
+ /** Object-detection model the executor defaults to for this deviceKey. */
20311
+ defaultModelId: string(),
20312
+ /**
20313
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20314
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20315
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20316
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20317
+ * available per format; this is the stored selection that becomes the
20318
+ * default for EVERY camera landing on this accelerator.
20319
+ */
20320
+ steps: record(string(), DeviceStepConfigSchema).optional()
20321
+ });
20322
+ var NodeInferenceDevicesSchema = object({
20323
+ nodeId: string(),
20324
+ /** False when the node's platform-probe was unreachable (no live device set). */
20325
+ reachable: boolean(),
20326
+ devices: array(NodeInferenceDeviceSchema).readonly()
20327
+ });
20231
20328
  method(object({
20232
20329
  deviceId: number(),
20233
20330
  agentNodeId: string()
@@ -20237,7 +20334,13 @@ method(object({
20237
20334
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20238
20335
  kind: "mutation",
20239
20336
  auth: "admin"
20240
- }), method(_void(), object({ migrated: number() }), {
20337
+ }), method(object({
20338
+ deviceId: number(),
20339
+ deviceKey: string()
20340
+ }), object({ success: literal(true) }), {
20341
+ kind: "mutation",
20342
+ auth: "admin"
20343
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20241
20344
  kind: "mutation",
20242
20345
  auth: "admin"
20243
20346
  }), 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({
@@ -20271,13 +20374,7 @@ method(object({
20271
20374
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20272
20375
  nodeId: string(),
20273
20376
  settings: AgentPipelineSettingsSchema
20274
- })).readonly()), method(object({
20275
- agentNodeId: string(),
20276
- defaults: record(string(), AgentAddonConfigSchema)
20277
- }), object({ success: literal(true) }), {
20278
- kind: "mutation",
20279
- auth: "admin"
20280
- }), method(object({ agentNodeId: string() }), object({
20377
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20281
20378
  success: boolean(),
20282
20379
  removed: boolean()
20283
20380
  }), {
@@ -20309,7 +20406,18 @@ method(object({
20309
20406
  }), object({ success: literal(true) }), {
20310
20407
  kind: "mutation",
20311
20408
  auth: "admin"
20312
- }), method(object({ agentNodeId: string() }), object({
20409
+ }), method(object({
20410
+ agentNodeId: string(),
20411
+ inferenceDevices: record(string(), object({
20412
+ enabled: boolean(),
20413
+ weight: number().positive().optional(),
20414
+ maxSessions: number().int().positive().optional(),
20415
+ steps: record(string(), DeviceStepConfigSchema).optional()
20416
+ }))
20417
+ }), object({ success: literal(true) }), {
20418
+ kind: "mutation",
20419
+ auth: "admin"
20420
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20313
20421
  success: literal(true),
20314
20422
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20315
20423
  effectiveModelId: string().nullable(),
@@ -20325,9 +20433,10 @@ method(object({
20325
20433
  }), object({ success: literal(true) }), {
20326
20434
  kind: "mutation",
20327
20435
  auth: "admin"
20328
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20436
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20329
20437
  deviceId: number(),
20330
20438
  agentNodeId: string(),
20439
+ deviceKey: string(),
20331
20440
  addonId: string(),
20332
20441
  patch: CameraStepOverridePatchSchema.nullable()
20333
20442
  }), object({ success: literal(true) }), {
@@ -20364,14 +20473,13 @@ method(object({
20364
20473
  });
20365
20474
  /**
20366
20475
  * server-management — per-NODE singleton capability for a node's ROOT
20367
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20368
- * agents).
20476
+ * package lifecycle (runtime-updatable node packages).
20369
20477
  *
20370
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20371
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20372
- * version describes the node. Updates install into
20373
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20374
- * starter (probation boot + auto-rollback to N-1).
20478
+ * Every node role runs the SAME root package (`@camstack/server`), which
20479
+ * carries the whole software stack in its npm dep tree, so ONE version
20480
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20481
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20482
+ * no auto-rollback).
20375
20483
  *
20376
20484
  * Providers:
20377
20485
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20479,7 +20587,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20479
20587
  /** Explicit target version; omitted = latest from the registry. */
20480
20588
  version: string().optional() }), ServerUpdateActionResultSchema, {
20481
20589
  kind: "mutation",
20482
- auth: "admin"
20590
+ auth: "admin",
20591
+ timeoutMs: 16 * 6e4
20483
20592
  }), method(_void(), ServerUpdateActionResultSchema, {
20484
20593
  kind: "mutation",
20485
20594
  auth: "admin"
@@ -22617,10 +22726,10 @@ var TopologyCategorySchema = object({
22617
22726
  addons: array(TopologyCategoryAddonSchema).readonly()
22618
22727
  });
22619
22728
  /**
22620
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22621
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22622
- * version visibility for the Server management surface. Nullable: offline
22623
- * rows and pre-phase-2 nodes report none.
22729
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22730
+ * root package for every node role) as reported by its `registerNode`
22731
+ * manifest — version visibility for the Server management surface. Nullable:
22732
+ * offline rows and nodes that never reported one.
22624
22733
  */
22625
22734
  var TopologyRootPackageSchema = object({
22626
22735
  name: string(),
@@ -23008,17 +23117,28 @@ var PlatformScoreSchema = object({
23008
23117
  format: _enum([
23009
23118
  "onnx",
23010
23119
  "coreml",
23011
- "openvino"
23120
+ "openvino",
23121
+ "tflite"
23012
23122
  ]),
23013
23123
  score: number(),
23014
23124
  reason: string(),
23015
23125
  available: boolean()
23016
23126
  });
23127
+ var InferenceDeviceDescriptorSchema = object({
23128
+ key: string(),
23129
+ backend: string(),
23130
+ device: string(),
23131
+ format: ModelFormatSchema,
23132
+ runtime: literal("python"),
23133
+ score: number(),
23134
+ available: boolean()
23135
+ });
23017
23136
  var PlatformCapabilitiesSchema = object({
23018
23137
  hardware: HardwareInfoSchema,
23019
23138
  scores: array(PlatformScoreSchema).readonly(),
23020
23139
  bestScore: PlatformScoreSchema,
23021
- pythonPath: string().nullable()
23140
+ pythonPath: string().nullable(),
23141
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
23022
23142
  });
23023
23143
  var ModelRequirementSchema = object({
23024
23144
  modelId: string(),
@@ -26947,12 +27067,6 @@ Object.freeze({
26947
27067
  addonId: null,
26948
27068
  access: "view"
26949
27069
  },
26950
- "pipelineExecutor.reprobeEngine": {
26951
- capName: "pipeline-executor",
26952
- capScope: "system",
26953
- addonId: null,
26954
- access: "create"
26955
- },
26956
27070
  "pipelineExecutor.runAudioTest": {
26957
27071
  capName: "pipeline-executor",
26958
27072
  capScope: "system",
@@ -27103,6 +27217,12 @@ Object.freeze({
27103
27217
  addonId: null,
27104
27218
  access: "view"
27105
27219
  },
27220
+ "pipelineOrchestrator.getNodeInferenceDevices": {
27221
+ capName: "pipeline-orchestrator",
27222
+ capScope: "system",
27223
+ addonId: null,
27224
+ access: "view"
27225
+ },
27106
27226
  "pipelineOrchestrator.getPipelineAssignment": {
27107
27227
  capName: "pipeline-orchestrator",
27108
27228
  capScope: "system",
@@ -27115,6 +27235,12 @@ Object.freeze({
27115
27235
  addonId: null,
27116
27236
  access: "view"
27117
27237
  },
27238
+ "pipelineOrchestrator.getPipelineDevicePin": {
27239
+ capName: "pipeline-orchestrator",
27240
+ capScope: "system",
27241
+ addonId: null,
27242
+ access: "view"
27243
+ },
27118
27244
  "pipelineOrchestrator.listAgentSettings": {
27119
27245
  capName: "pipeline-orchestrator",
27120
27246
  capScope: "system",
@@ -27157,19 +27283,19 @@ Object.freeze({
27157
27283
  addonId: null,
27158
27284
  access: "create"
27159
27285
  },
27160
- "pipelineOrchestrator.setAgentAddonDefaults": {
27286
+ "pipelineOrchestrator.setAgentCapabilities": {
27161
27287
  capName: "pipeline-orchestrator",
27162
27288
  capScope: "system",
27163
27289
  addonId: null,
27164
27290
  access: "create"
27165
27291
  },
27166
- "pipelineOrchestrator.setAgentCapabilities": {
27292
+ "pipelineOrchestrator.setAgentDetectWeight": {
27167
27293
  capName: "pipeline-orchestrator",
27168
27294
  capScope: "system",
27169
27295
  addonId: null,
27170
27296
  access: "create"
27171
27297
  },
27172
- "pipelineOrchestrator.setAgentDetectWeight": {
27298
+ "pipelineOrchestrator.setAgentInferenceDevices": {
27173
27299
  capName: "pipeline-orchestrator",
27174
27300
  capScope: "system",
27175
27301
  addonId: null,
@@ -27211,6 +27337,12 @@ Object.freeze({
27211
27337
  addonId: null,
27212
27338
  access: "create"
27213
27339
  },
27340
+ "pipelineOrchestrator.setPipelineDevicePin": {
27341
+ capName: "pipeline-orchestrator",
27342
+ capScope: "system",
27343
+ addonId: null,
27344
+ access: "create"
27345
+ },
27214
27346
  "pipelineOrchestrator.unassignAudio": {
27215
27347
  capName: "pipeline-orchestrator",
27216
27348
  capScope: "system",
package/dist/addon.mjs CHANGED
@@ -12633,10 +12633,7 @@ var ConfigUISchemaNullableBridge = custom$2();
12633
12633
  var InferenceCapabilitiesBridge = custom$2();
12634
12634
  var ModelAvailabilityListBridge = custom$2();
12635
12635
  var PipelineRunResultBridge = custom$2();
12636
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12637
- kind: "mutation",
12638
- auth: "admin"
12639
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12636
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12640
12637
  modelId: string(),
12641
12638
  settings: record(string(), unknown()).readonly()
12642
12639
  }))), method(object({ steps: record(string(), object({
@@ -12696,13 +12693,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12696
12693
  * (inputClasses ≠ null) are skipped and served per-track via
12697
12694
  * pipelineRunner.runDetailSubtree (two-plane design).
12698
12695
  */
12699
- plane: _enum(["full", "frame"]).optional()
12696
+ plane: _enum(["full", "frame"]).optional(),
12697
+ /**
12698
+ * Inference-device selector (Phase 2 multi-device). Format
12699
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12700
+ * Omitted ⇒ the runner's default device (current single-engine
12701
+ * behaviour). Selects WHICH device pool of the node runs the call.
12702
+ */
12703
+ deviceKey: string().optional()
12700
12704
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12701
12705
  engine: PipelineEngineChoiceSchema.optional(),
12702
12706
  steps: array(PipelineStepInputSchema).min(1),
12703
12707
  frames: array(FrameInputSchema).min(1).max(255),
12704
12708
  deviceId: number().optional(),
12705
- sessionId: string().optional()
12709
+ sessionId: string().optional(),
12710
+ /**
12711
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12712
+ * the batch to the Python pool's bench preprocess cache
12713
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12714
+ * preprocessed ONCE and every later inference is a pure-inference cache
12715
+ * hit — the sustained-throughput run measures inference, not
12716
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12717
+ * full preprocess every call, correct). Fresh per sustained run;
12718
+ * released via `uncacheFrame`.
12719
+ */
12720
+ frameId: number().int().nonnegative().optional(),
12721
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12722
+ deviceKey: string().optional()
12706
12723
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12707
12724
  data: _instanceof(Uint8Array),
12708
12725
  width: number().int().positive(),
@@ -12734,8 +12751,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12734
12751
  * - `runtime` — main camera-serving engine (no idle TTL).
12735
12752
  * - `warm-override` — benchmark/test override held in the warm
12736
12753
  * cache; auto-disposed after the idle TTL.
12754
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12755
+ * multi-device, keyed by `deviceKey`) resolved
12756
+ * via `resolveDeviceFactory`. Runs alongside the
12757
+ * `runtime` engine on a DIFFERENT accelerator
12758
+ * (NPU / iGPU / Coral) — this is how the
12759
+ * Engines tab shows all pools running at once.
12737
12760
  */
12738
- kind: _enum(["runtime", "warm-override"]),
12761
+ kind: _enum([
12762
+ "runtime",
12763
+ "warm-override",
12764
+ "device-pool"
12765
+ ]),
12739
12766
  /** Native pid of the underlying Python pool (null when no pool). */
12740
12767
  poolPid: number().nullable(),
12741
12768
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -13110,7 +13137,14 @@ var RunnerCameraConfigSchema = object({
13110
13137
  * camera's detect node differs from its source-owner (P2d, gated by the
13111
13138
  * `remoteSourcingNodes` rollout setting).
13112
13139
  */
13113
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13140
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13141
+ /**
13142
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13143
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13144
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13145
+ * this only selects WHICH device pool of that node runs the session.
13146
+ */
13147
+ deviceKey: string().optional()
13114
13148
  });
13115
13149
  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;
13116
13150
  /**
@@ -13131,6 +13165,19 @@ var RunnerLocalLoadSchema = object({
13131
13165
  avgInferenceTimeMs: number(),
13132
13166
  /** Total queue depth across motion + detection queues. */
13133
13167
  queueDepthTotal: number(),
13168
+ /**
13169
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13170
+ * this runner currently has attached cameras on, so the orchestrator's second
13171
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13172
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13173
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13174
+ */
13175
+ devices: array(object({
13176
+ deviceKey: string(),
13177
+ backend: string(),
13178
+ attachedCameras: number(),
13179
+ queueDepthTotal: number()
13180
+ })).default([]),
13134
13181
  /** Hardware capability flags reported by this node. */
13135
13182
  hardware: object({
13136
13183
  hasGpu: boolean(),
@@ -19962,13 +20009,11 @@ var PipelineTemplateSchema = object({
19962
20009
  createdAt: string(),
19963
20010
  updatedAt: string()
19964
20011
  });
19965
- var AgentAddonConfigSchema = object({
19966
- enabled: boolean(),
20012
+ var DeviceStepConfigSchema = object({
19967
20013
  modelId: string().optional(),
19968
- settings: record(string(), unknown()).readonly()
20014
+ settings: record(string(), unknown()).optional()
19969
20015
  });
19970
20016
  var AgentPipelineSettingsSchema = object({
19971
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19972
20017
  maxCameras: number().int().nonnegative().nullable().default(null),
19973
20018
  /** Per-node detection weight (relative share for the quota balancer). */
19974
20019
  detectWeight: number().positive().optional(),
@@ -19992,7 +20037,22 @@ var AgentPipelineSettingsSchema = object({
19992
20037
  * it already uses to reach the hub). Set this only when the auto-detected
19993
20038
  * address is wrong (multi-homed host, NAT, custom interface).
19994
20039
  */
19995
- reachableHost: string().optional()
20040
+ reachableHost: string().optional(),
20041
+ /**
20042
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20043
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20044
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20045
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20046
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20047
+ * the default model/settings for every camera landing on that accelerator;
20048
+ * a stepId absent ⇒ the step uses that device's format default.
20049
+ */
20050
+ inferenceDevices: record(string(), object({
20051
+ enabled: boolean(),
20052
+ weight: number().positive().optional(),
20053
+ maxSessions: number().int().positive().optional(),
20054
+ steps: record(string(), DeviceStepConfigSchema).optional()
20055
+ })).optional()
19996
20056
  });
19997
20057
  var CameraPipelineForAgentSchema = object({
19998
20058
  steps: array(PipelineStepInputSchema).readonly(),
@@ -20002,14 +20062,13 @@ var CameraPipelineForAgentSchema = object({
20002
20062
  }).nullable()
20003
20063
  });
20004
20064
  var CameraStepOverridePatchSchema = object({
20005
- enabled: boolean().optional(),
20006
20065
  modelId: string().optional(),
20007
20066
  settings: record(string(), unknown()).readonly().optional()
20008
20067
  });
20009
20068
  var CameraPipelineSettingsSchema = object({
20010
20069
  pinnedAgentNodeId: string().optional(),
20011
20070
  stepToggles: record(string(), boolean()).optional(),
20012
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20071
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
20013
20072
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
20014
20073
  });
20015
20074
  /**
@@ -20223,6 +20282,44 @@ var CameraStatusSchema = object({
20223
20282
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20224
20283
  fetchedAt: number()
20225
20284
  });
20285
+ var NodeInferenceDeviceSchema = object({
20286
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20287
+ key: string(),
20288
+ backend: string(),
20289
+ device: string(),
20290
+ format: _enum(MODEL_FORMATS),
20291
+ /** Whether the node's live probe reports the device as usable right now. */
20292
+ available: boolean(),
20293
+ /**
20294
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20295
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20296
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20297
+ * not a balanced target). An explicit stored value always wins; a stored-only
20298
+ * (unavailable) key keeps its stored value.
20299
+ */
20300
+ enabled: boolean(),
20301
+ /** Relative balancer weight for the enabled device (default 1). */
20302
+ weight: number(),
20303
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20304
+ maxSessions: number().nullable(),
20305
+ /** Object-detection model the executor defaults to for this deviceKey. */
20306
+ defaultModelId: string(),
20307
+ /**
20308
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20309
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20310
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20311
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20312
+ * available per format; this is the stored selection that becomes the
20313
+ * default for EVERY camera landing on this accelerator.
20314
+ */
20315
+ steps: record(string(), DeviceStepConfigSchema).optional()
20316
+ });
20317
+ var NodeInferenceDevicesSchema = object({
20318
+ nodeId: string(),
20319
+ /** False when the node's platform-probe was unreachable (no live device set). */
20320
+ reachable: boolean(),
20321
+ devices: array(NodeInferenceDeviceSchema).readonly()
20322
+ });
20226
20323
  method(object({
20227
20324
  deviceId: number(),
20228
20325
  agentNodeId: string()
@@ -20232,7 +20329,13 @@ method(object({
20232
20329
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20233
20330
  kind: "mutation",
20234
20331
  auth: "admin"
20235
- }), method(_void(), object({ migrated: number() }), {
20332
+ }), method(object({
20333
+ deviceId: number(),
20334
+ deviceKey: string()
20335
+ }), object({ success: literal(true) }), {
20336
+ kind: "mutation",
20337
+ auth: "admin"
20338
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20236
20339
  kind: "mutation",
20237
20340
  auth: "admin"
20238
20341
  }), 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({
@@ -20266,13 +20369,7 @@ method(object({
20266
20369
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20267
20370
  nodeId: string(),
20268
20371
  settings: AgentPipelineSettingsSchema
20269
- })).readonly()), method(object({
20270
- agentNodeId: string(),
20271
- defaults: record(string(), AgentAddonConfigSchema)
20272
- }), object({ success: literal(true) }), {
20273
- kind: "mutation",
20274
- auth: "admin"
20275
- }), method(object({ agentNodeId: string() }), object({
20372
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20276
20373
  success: boolean(),
20277
20374
  removed: boolean()
20278
20375
  }), {
@@ -20304,7 +20401,18 @@ method(object({
20304
20401
  }), object({ success: literal(true) }), {
20305
20402
  kind: "mutation",
20306
20403
  auth: "admin"
20307
- }), method(object({ agentNodeId: string() }), object({
20404
+ }), method(object({
20405
+ agentNodeId: string(),
20406
+ inferenceDevices: record(string(), object({
20407
+ enabled: boolean(),
20408
+ weight: number().positive().optional(),
20409
+ maxSessions: number().int().positive().optional(),
20410
+ steps: record(string(), DeviceStepConfigSchema).optional()
20411
+ }))
20412
+ }), object({ success: literal(true) }), {
20413
+ kind: "mutation",
20414
+ auth: "admin"
20415
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20308
20416
  success: literal(true),
20309
20417
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20310
20418
  effectiveModelId: string().nullable(),
@@ -20320,9 +20428,10 @@ method(object({
20320
20428
  }), object({ success: literal(true) }), {
20321
20429
  kind: "mutation",
20322
20430
  auth: "admin"
20323
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20431
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20324
20432
  deviceId: number(),
20325
20433
  agentNodeId: string(),
20434
+ deviceKey: string(),
20326
20435
  addonId: string(),
20327
20436
  patch: CameraStepOverridePatchSchema.nullable()
20328
20437
  }), object({ success: literal(true) }), {
@@ -20359,14 +20468,13 @@ method(object({
20359
20468
  });
20360
20469
  /**
20361
20470
  * server-management — per-NODE singleton capability for a node's ROOT
20362
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20363
- * agents).
20471
+ * package lifecycle (runtime-updatable node packages).
20364
20472
  *
20365
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20366
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20367
- * version describes the node. Updates install into
20368
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20369
- * starter (probation boot + auto-rollback to N-1).
20473
+ * Every node role runs the SAME root package (`@camstack/server`), which
20474
+ * carries the whole software stack in its npm dep tree, so ONE version
20475
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20476
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20477
+ * no auto-rollback).
20370
20478
  *
20371
20479
  * Providers:
20372
20480
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20474,7 +20582,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20474
20582
  /** Explicit target version; omitted = latest from the registry. */
20475
20583
  version: string().optional() }), ServerUpdateActionResultSchema, {
20476
20584
  kind: "mutation",
20477
- auth: "admin"
20585
+ auth: "admin",
20586
+ timeoutMs: 16 * 6e4
20478
20587
  }), method(_void(), ServerUpdateActionResultSchema, {
20479
20588
  kind: "mutation",
20480
20589
  auth: "admin"
@@ -22612,10 +22721,10 @@ var TopologyCategorySchema = object({
22612
22721
  addons: array(TopologyCategoryAddonSchema).readonly()
22613
22722
  });
22614
22723
  /**
22615
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22616
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22617
- * version visibility for the Server management surface. Nullable: offline
22618
- * rows and pre-phase-2 nodes report none.
22724
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22725
+ * root package for every node role) as reported by its `registerNode`
22726
+ * manifest — version visibility for the Server management surface. Nullable:
22727
+ * offline rows and nodes that never reported one.
22619
22728
  */
22620
22729
  var TopologyRootPackageSchema = object({
22621
22730
  name: string(),
@@ -23003,17 +23112,28 @@ var PlatformScoreSchema = object({
23003
23112
  format: _enum([
23004
23113
  "onnx",
23005
23114
  "coreml",
23006
- "openvino"
23115
+ "openvino",
23116
+ "tflite"
23007
23117
  ]),
23008
23118
  score: number(),
23009
23119
  reason: string(),
23010
23120
  available: boolean()
23011
23121
  });
23122
+ var InferenceDeviceDescriptorSchema = object({
23123
+ key: string(),
23124
+ backend: string(),
23125
+ device: string(),
23126
+ format: ModelFormatSchema,
23127
+ runtime: literal("python"),
23128
+ score: number(),
23129
+ available: boolean()
23130
+ });
23012
23131
  var PlatformCapabilitiesSchema = object({
23013
23132
  hardware: HardwareInfoSchema,
23014
23133
  scores: array(PlatformScoreSchema).readonly(),
23015
23134
  bestScore: PlatformScoreSchema,
23016
- pythonPath: string().nullable()
23135
+ pythonPath: string().nullable(),
23136
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
23017
23137
  });
23018
23138
  var ModelRequirementSchema = object({
23019
23139
  modelId: string(),
@@ -26942,12 +27062,6 @@ Object.freeze({
26942
27062
  addonId: null,
26943
27063
  access: "view"
26944
27064
  },
26945
- "pipelineExecutor.reprobeEngine": {
26946
- capName: "pipeline-executor",
26947
- capScope: "system",
26948
- addonId: null,
26949
- access: "create"
26950
- },
26951
27065
  "pipelineExecutor.runAudioTest": {
26952
27066
  capName: "pipeline-executor",
26953
27067
  capScope: "system",
@@ -27098,6 +27212,12 @@ Object.freeze({
27098
27212
  addonId: null,
27099
27213
  access: "view"
27100
27214
  },
27215
+ "pipelineOrchestrator.getNodeInferenceDevices": {
27216
+ capName: "pipeline-orchestrator",
27217
+ capScope: "system",
27218
+ addonId: null,
27219
+ access: "view"
27220
+ },
27101
27221
  "pipelineOrchestrator.getPipelineAssignment": {
27102
27222
  capName: "pipeline-orchestrator",
27103
27223
  capScope: "system",
@@ -27110,6 +27230,12 @@ Object.freeze({
27110
27230
  addonId: null,
27111
27231
  access: "view"
27112
27232
  },
27233
+ "pipelineOrchestrator.getPipelineDevicePin": {
27234
+ capName: "pipeline-orchestrator",
27235
+ capScope: "system",
27236
+ addonId: null,
27237
+ access: "view"
27238
+ },
27113
27239
  "pipelineOrchestrator.listAgentSettings": {
27114
27240
  capName: "pipeline-orchestrator",
27115
27241
  capScope: "system",
@@ -27152,19 +27278,19 @@ Object.freeze({
27152
27278
  addonId: null,
27153
27279
  access: "create"
27154
27280
  },
27155
- "pipelineOrchestrator.setAgentAddonDefaults": {
27281
+ "pipelineOrchestrator.setAgentCapabilities": {
27156
27282
  capName: "pipeline-orchestrator",
27157
27283
  capScope: "system",
27158
27284
  addonId: null,
27159
27285
  access: "create"
27160
27286
  },
27161
- "pipelineOrchestrator.setAgentCapabilities": {
27287
+ "pipelineOrchestrator.setAgentDetectWeight": {
27162
27288
  capName: "pipeline-orchestrator",
27163
27289
  capScope: "system",
27164
27290
  addonId: null,
27165
27291
  access: "create"
27166
27292
  },
27167
- "pipelineOrchestrator.setAgentDetectWeight": {
27293
+ "pipelineOrchestrator.setAgentInferenceDevices": {
27168
27294
  capName: "pipeline-orchestrator",
27169
27295
  capScope: "system",
27170
27296
  addonId: null,
@@ -27206,6 +27332,12 @@ Object.freeze({
27206
27332
  addonId: null,
27207
27333
  access: "create"
27208
27334
  },
27335
+ "pipelineOrchestrator.setPipelineDevicePin": {
27336
+ capName: "pipeline-orchestrator",
27337
+ capScope: "system",
27338
+ addonId: null,
27339
+ access: "create"
27340
+ },
27209
27341
  "pipelineOrchestrator.unassignAudio": {
27210
27342
  capName: "pipeline-orchestrator",
27211
27343
  capScope: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-reolink",
3
- "version": "1.1.31",
3
+ "version": "1.2.0",
4
4
  "description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
5
5
  "keywords": [
6
6
  "camstack",