@camstack/addon-provider-vesync 0.1.14 → 0.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
@@ -7098,6 +7098,17 @@ var ModelCatalogEntrySchema = object({
7098
7098
  "imagenet",
7099
7099
  "none"
7100
7100
  ]).optional(),
7101
+ /**
7102
+ * The model already applies softmax IN-GRAPH — its raw output is a
7103
+ * probability distribution, not logits. When set, the `softmax`
7104
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7105
+ * probability vector collapses it toward uniform (top-1 score craters far
7106
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7107
+ * the output is raw logits and the postprocessor applies softmax (the normal
7108
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7109
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7110
+ */
7111
+ outputProbabilities: boolean().optional(),
7101
7112
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7102
7113
  /**
7103
7114
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12388,10 +12399,7 @@ var ConfigUISchemaNullableBridge = custom();
12388
12399
  var InferenceCapabilitiesBridge = custom();
12389
12400
  var ModelAvailabilityListBridge = custom();
12390
12401
  var PipelineRunResultBridge = custom();
12391
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12392
- kind: "mutation",
12393
- auth: "admin"
12394
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12402
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12395
12403
  modelId: string(),
12396
12404
  settings: record(string(), unknown()).readonly()
12397
12405
  }))), method(object({ steps: record(string(), object({
@@ -12451,13 +12459,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12451
12459
  * (inputClasses ≠ null) are skipped and served per-track via
12452
12460
  * pipelineRunner.runDetailSubtree (two-plane design).
12453
12461
  */
12454
- plane: _enum(["full", "frame"]).optional()
12462
+ plane: _enum(["full", "frame"]).optional(),
12463
+ /**
12464
+ * Inference-device selector (Phase 2 multi-device). Format
12465
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12466
+ * Omitted ⇒ the runner's default device (current single-engine
12467
+ * behaviour). Selects WHICH device pool of the node runs the call.
12468
+ */
12469
+ deviceKey: string().optional()
12455
12470
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12456
12471
  engine: PipelineEngineChoiceSchema.optional(),
12457
12472
  steps: array(PipelineStepInputSchema).min(1),
12458
12473
  frames: array(FrameInputSchema).min(1).max(255),
12459
12474
  deviceId: number().optional(),
12460
- sessionId: string().optional()
12475
+ sessionId: string().optional(),
12476
+ /**
12477
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12478
+ * the batch to the Python pool's bench preprocess cache
12479
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12480
+ * preprocessed ONCE and every later inference is a pure-inference cache
12481
+ * hit — the sustained-throughput run measures inference, not
12482
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12483
+ * full preprocess every call, correct). Fresh per sustained run;
12484
+ * released via `uncacheFrame`.
12485
+ */
12486
+ frameId: number().int().nonnegative().optional(),
12487
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12488
+ deviceKey: string().optional()
12461
12489
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12462
12490
  data: _instanceof(Uint8Array),
12463
12491
  width: number().int().positive(),
@@ -12489,8 +12517,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12489
12517
  * - `runtime` — main camera-serving engine (no idle TTL).
12490
12518
  * - `warm-override` — benchmark/test override held in the warm
12491
12519
  * cache; auto-disposed after the idle TTL.
12520
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12521
+ * multi-device, keyed by `deviceKey`) resolved
12522
+ * via `resolveDeviceFactory`. Runs alongside the
12523
+ * `runtime` engine on a DIFFERENT accelerator
12524
+ * (NPU / iGPU / Coral) — this is how the
12525
+ * Engines tab shows all pools running at once.
12492
12526
  */
12493
- kind: _enum(["runtime", "warm-override"]),
12527
+ kind: _enum([
12528
+ "runtime",
12529
+ "warm-override",
12530
+ "device-pool"
12531
+ ]),
12494
12532
  /** Native pid of the underlying Python pool (null when no pool). */
12495
12533
  poolPid: number().nullable(),
12496
12534
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12865,7 +12903,14 @@ var RunnerCameraConfigSchema = object({
12865
12903
  * camera's detect node differs from its source-owner (P2d, gated by the
12866
12904
  * `remoteSourcingNodes` rollout setting).
12867
12905
  */
12868
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12906
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12907
+ /**
12908
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12909
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12910
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12911
+ * this only selects WHICH device pool of that node runs the session.
12912
+ */
12913
+ deviceKey: string().optional()
12869
12914
  });
12870
12915
  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;
12871
12916
  /**
@@ -12886,6 +12931,19 @@ var RunnerLocalLoadSchema = object({
12886
12931
  avgInferenceTimeMs: number(),
12887
12932
  /** Total queue depth across motion + detection queues. */
12888
12933
  queueDepthTotal: number(),
12934
+ /**
12935
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12936
+ * this runner currently has attached cameras on, so the orchestrator's second
12937
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12938
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12939
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12940
+ */
12941
+ devices: array(object({
12942
+ deviceKey: string(),
12943
+ backend: string(),
12944
+ attachedCameras: number(),
12945
+ queueDepthTotal: number()
12946
+ })).default([]),
12889
12947
  /** Hardware capability flags reported by this node. */
12890
12948
  hardware: object({
12891
12949
  hasGpu: boolean(),
@@ -16034,6 +16092,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16034
16092
  return toDeviceSummary(device, this.addonId);
16035
16093
  }
16036
16094
  };
16095
+ 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;
16096
+ new Set(Object.values(DeviceType));
16037
16097
  /**
16038
16098
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16039
16099
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19703,13 +19763,11 @@ var PipelineTemplateSchema = object({
19703
19763
  createdAt: string(),
19704
19764
  updatedAt: string()
19705
19765
  });
19706
- var AgentAddonConfigSchema = object({
19707
- enabled: boolean(),
19766
+ var DeviceStepConfigSchema = object({
19708
19767
  modelId: string().optional(),
19709
- settings: record(string(), unknown()).readonly()
19768
+ settings: record(string(), unknown()).optional()
19710
19769
  });
19711
19770
  var AgentPipelineSettingsSchema = object({
19712
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19713
19771
  maxCameras: number().int().nonnegative().nullable().default(null),
19714
19772
  /** Per-node detection weight (relative share for the quota balancer). */
19715
19773
  detectWeight: number().positive().optional(),
@@ -19733,7 +19791,22 @@ var AgentPipelineSettingsSchema = object({
19733
19791
  * it already uses to reach the hub). Set this only when the auto-detected
19734
19792
  * address is wrong (multi-homed host, NAT, custom interface).
19735
19793
  */
19736
- reachableHost: string().optional()
19794
+ reachableHost: string().optional(),
19795
+ /**
19796
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19797
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19798
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19799
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19800
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19801
+ * the default model/settings for every camera landing on that accelerator;
19802
+ * a stepId absent ⇒ the step uses that device's format default.
19803
+ */
19804
+ inferenceDevices: record(string(), object({
19805
+ enabled: boolean(),
19806
+ weight: number().positive().optional(),
19807
+ maxSessions: number().int().positive().optional(),
19808
+ steps: record(string(), DeviceStepConfigSchema).optional()
19809
+ })).optional()
19737
19810
  });
19738
19811
  var CameraPipelineForAgentSchema = object({
19739
19812
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19743,14 +19816,13 @@ var CameraPipelineForAgentSchema = object({
19743
19816
  }).nullable()
19744
19817
  });
19745
19818
  var CameraStepOverridePatchSchema = object({
19746
- enabled: boolean().optional(),
19747
19819
  modelId: string().optional(),
19748
19820
  settings: record(string(), unknown()).readonly().optional()
19749
19821
  });
19750
19822
  var CameraPipelineSettingsSchema = object({
19751
19823
  pinnedAgentNodeId: string().optional(),
19752
19824
  stepToggles: record(string(), boolean()).optional(),
19753
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19825
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19754
19826
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19755
19827
  });
19756
19828
  /**
@@ -19964,6 +20036,44 @@ var CameraStatusSchema = object({
19964
20036
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
19965
20037
  fetchedAt: number()
19966
20038
  });
20039
+ var NodeInferenceDeviceSchema = object({
20040
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20041
+ key: string(),
20042
+ backend: string(),
20043
+ device: string(),
20044
+ format: _enum(MODEL_FORMATS),
20045
+ /** Whether the node's live probe reports the device as usable right now. */
20046
+ available: boolean(),
20047
+ /**
20048
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20049
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20050
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20051
+ * not a balanced target). An explicit stored value always wins; a stored-only
20052
+ * (unavailable) key keeps its stored value.
20053
+ */
20054
+ enabled: boolean(),
20055
+ /** Relative balancer weight for the enabled device (default 1). */
20056
+ weight: number(),
20057
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20058
+ maxSessions: number().nullable(),
20059
+ /** Object-detection model the executor defaults to for this deviceKey. */
20060
+ defaultModelId: string(),
20061
+ /**
20062
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20063
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20064
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20065
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20066
+ * available per format; this is the stored selection that becomes the
20067
+ * default for EVERY camera landing on this accelerator.
20068
+ */
20069
+ steps: record(string(), DeviceStepConfigSchema).optional()
20070
+ });
20071
+ var NodeInferenceDevicesSchema = object({
20072
+ nodeId: string(),
20073
+ /** False when the node's platform-probe was unreachable (no live device set). */
20074
+ reachable: boolean(),
20075
+ devices: array(NodeInferenceDeviceSchema).readonly()
20076
+ });
19967
20077
  method(object({
19968
20078
  deviceId: number(),
19969
20079
  agentNodeId: string()
@@ -19973,7 +20083,13 @@ method(object({
19973
20083
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
19974
20084
  kind: "mutation",
19975
20085
  auth: "admin"
19976
- }), method(_void(), object({ migrated: number() }), {
20086
+ }), method(object({
20087
+ deviceId: number(),
20088
+ deviceKey: string()
20089
+ }), object({ success: literal(true) }), {
20090
+ kind: "mutation",
20091
+ auth: "admin"
20092
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
19977
20093
  kind: "mutation",
19978
20094
  auth: "admin"
19979
20095
  }), 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({
@@ -20007,13 +20123,7 @@ method(object({
20007
20123
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20008
20124
  nodeId: string(),
20009
20125
  settings: AgentPipelineSettingsSchema
20010
- })).readonly()), method(object({
20011
- agentNodeId: string(),
20012
- defaults: record(string(), AgentAddonConfigSchema)
20013
- }), object({ success: literal(true) }), {
20014
- kind: "mutation",
20015
- auth: "admin"
20016
- }), method(object({ agentNodeId: string() }), object({
20126
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20017
20127
  success: boolean(),
20018
20128
  removed: boolean()
20019
20129
  }), {
@@ -20045,7 +20155,18 @@ method(object({
20045
20155
  }), object({ success: literal(true) }), {
20046
20156
  kind: "mutation",
20047
20157
  auth: "admin"
20048
- }), method(object({ agentNodeId: string() }), object({
20158
+ }), method(object({
20159
+ agentNodeId: string(),
20160
+ inferenceDevices: record(string(), object({
20161
+ enabled: boolean(),
20162
+ weight: number().positive().optional(),
20163
+ maxSessions: number().int().positive().optional(),
20164
+ steps: record(string(), DeviceStepConfigSchema).optional()
20165
+ }))
20166
+ }), object({ success: literal(true) }), {
20167
+ kind: "mutation",
20168
+ auth: "admin"
20169
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20049
20170
  success: literal(true),
20050
20171
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20051
20172
  effectiveModelId: string().nullable(),
@@ -20061,9 +20182,10 @@ method(object({
20061
20182
  }), object({ success: literal(true) }), {
20062
20183
  kind: "mutation",
20063
20184
  auth: "admin"
20064
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20185
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20065
20186
  deviceId: number(),
20066
20187
  agentNodeId: string(),
20188
+ deviceKey: string(),
20067
20189
  addonId: string(),
20068
20190
  patch: CameraStepOverridePatchSchema.nullable()
20069
20191
  }), object({ success: literal(true) }), {
@@ -20100,14 +20222,13 @@ method(object({
20100
20222
  });
20101
20223
  /**
20102
20224
  * server-management — per-NODE singleton capability for a node's ROOT
20103
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20104
- * agents).
20225
+ * package lifecycle (runtime-updatable node packages).
20105
20226
  *
20106
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20107
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20108
- * version describes the node. Updates install into
20109
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20110
- * starter (probation boot + auto-rollback to N-1).
20227
+ * Every node role runs the SAME root package (`@camstack/server`), which
20228
+ * carries the whole software stack in its npm dep tree, so ONE version
20229
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20230
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20231
+ * no auto-rollback).
20111
20232
  *
20112
20233
  * Providers:
20113
20234
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20215,7 +20336,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20215
20336
  /** Explicit target version; omitted = latest from the registry. */
20216
20337
  version: string().optional() }), ServerUpdateActionResultSchema, {
20217
20338
  kind: "mutation",
20218
- auth: "admin"
20339
+ auth: "admin",
20340
+ timeoutMs: 16 * 6e4
20219
20341
  }), method(_void(), ServerUpdateActionResultSchema, {
20220
20342
  kind: "mutation",
20221
20343
  auth: "admin"
@@ -21259,22 +21381,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21259
21381
  var RestartAddonResultSchema = unknown();
21260
21382
  var InstallPackageResultSchema = unknown();
21261
21383
  var ReloadPackagesResultSchema = unknown();
21262
- /**
21263
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21264
- * server restarts so the admin UI can react to the `restartingAt`
21265
- * timestamp (shows reconnect overlay). The transition from
21266
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21267
- * `system.restart-completed` event after the new process boots.
21268
- *
21269
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21270
- */
21271
- var UpdateFrameworkPackageResultSchema = object({
21272
- packageName: string(),
21273
- fromVersion: string(),
21274
- toVersion: string(),
21275
- /** Ms-epoch the server scheduled its self-restart. */
21276
- restartingAt: number()
21277
- });
21278
21384
  var BulkUpdateItemStatusSchema = _enum([
21279
21385
  "queued",
21280
21386
  "updating",
@@ -21402,13 +21508,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21402
21508
  }), object({ success: literal(true) }), {
21403
21509
  kind: "mutation",
21404
21510
  auth: "admin"
21405
- }), method(object({
21406
- packageName: string().min(1),
21407
- version: string().optional(),
21408
- deferRestart: boolean().optional()
21409
- }), UpdateFrameworkPackageResultSchema, {
21410
- kind: "mutation",
21411
- auth: "admin"
21412
21511
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21413
21512
  kind: "mutation",
21414
21513
  auth: "admin"
@@ -22274,10 +22373,10 @@ var TopologyCategorySchema = object({
22274
22373
  addons: array(TopologyCategoryAddonSchema).readonly()
22275
22374
  });
22276
22375
  /**
22277
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22278
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22279
- * version visibility for the Server management surface. Nullable: offline
22280
- * rows and pre-phase-2 nodes report none.
22376
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22377
+ * root package for every node role) as reported by its `registerNode`
22378
+ * manifest — version visibility for the Server management surface. Nullable:
22379
+ * offline rows and nodes that never reported one.
22281
22380
  */
22282
22381
  var TopologyRootPackageSchema = object({
22283
22382
  name: string(),
@@ -22665,17 +22764,28 @@ var PlatformScoreSchema = object({
22665
22764
  format: _enum([
22666
22765
  "onnx",
22667
22766
  "coreml",
22668
- "openvino"
22767
+ "openvino",
22768
+ "tflite"
22669
22769
  ]),
22670
22770
  score: number(),
22671
22771
  reason: string(),
22672
22772
  available: boolean()
22673
22773
  });
22774
+ var InferenceDeviceDescriptorSchema = object({
22775
+ key: string(),
22776
+ backend: string(),
22777
+ device: string(),
22778
+ format: ModelFormatSchema,
22779
+ runtime: literal("python"),
22780
+ score: number(),
22781
+ available: boolean()
22782
+ });
22674
22783
  var PlatformCapabilitiesSchema = object({
22675
22784
  hardware: HardwareInfoSchema,
22676
22785
  scores: array(PlatformScoreSchema).readonly(),
22677
22786
  bestScore: PlatformScoreSchema,
22678
- pythonPath: string().nullable()
22787
+ pythonPath: string().nullable(),
22788
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22679
22789
  });
22680
22790
  var ModelRequirementSchema = object({
22681
22791
  modelId: string(),
@@ -23554,12 +23664,6 @@ Object.freeze({
23554
23664
  addonId: null,
23555
23665
  access: "delete"
23556
23666
  },
23557
- "addons.updateFrameworkPackage": {
23558
- capName: "addons",
23559
- capScope: "system",
23560
- addonId: null,
23561
- access: "create"
23562
- },
23563
23667
  "addons.updatePackage": {
23564
23668
  capName: "addons",
23565
23669
  capScope: "system",
@@ -26332,12 +26436,6 @@ Object.freeze({
26332
26436
  addonId: null,
26333
26437
  access: "view"
26334
26438
  },
26335
- "pipelineExecutor.reprobeEngine": {
26336
- capName: "pipeline-executor",
26337
- capScope: "system",
26338
- addonId: null,
26339
- access: "create"
26340
- },
26341
26439
  "pipelineExecutor.runAudioTest": {
26342
26440
  capName: "pipeline-executor",
26343
26441
  capScope: "system",
@@ -26488,6 +26586,12 @@ Object.freeze({
26488
26586
  addonId: null,
26489
26587
  access: "view"
26490
26588
  },
26589
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26590
+ capName: "pipeline-orchestrator",
26591
+ capScope: "system",
26592
+ addonId: null,
26593
+ access: "view"
26594
+ },
26491
26595
  "pipelineOrchestrator.getPipelineAssignment": {
26492
26596
  capName: "pipeline-orchestrator",
26493
26597
  capScope: "system",
@@ -26500,6 +26604,12 @@ Object.freeze({
26500
26604
  addonId: null,
26501
26605
  access: "view"
26502
26606
  },
26607
+ "pipelineOrchestrator.getPipelineDevicePin": {
26608
+ capName: "pipeline-orchestrator",
26609
+ capScope: "system",
26610
+ addonId: null,
26611
+ access: "view"
26612
+ },
26503
26613
  "pipelineOrchestrator.listAgentSettings": {
26504
26614
  capName: "pipeline-orchestrator",
26505
26615
  capScope: "system",
@@ -26542,19 +26652,19 @@ Object.freeze({
26542
26652
  addonId: null,
26543
26653
  access: "create"
26544
26654
  },
26545
- "pipelineOrchestrator.setAgentAddonDefaults": {
26655
+ "pipelineOrchestrator.setAgentCapabilities": {
26546
26656
  capName: "pipeline-orchestrator",
26547
26657
  capScope: "system",
26548
26658
  addonId: null,
26549
26659
  access: "create"
26550
26660
  },
26551
- "pipelineOrchestrator.setAgentCapabilities": {
26661
+ "pipelineOrchestrator.setAgentDetectWeight": {
26552
26662
  capName: "pipeline-orchestrator",
26553
26663
  capScope: "system",
26554
26664
  addonId: null,
26555
26665
  access: "create"
26556
26666
  },
26557
- "pipelineOrchestrator.setAgentDetectWeight": {
26667
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26558
26668
  capName: "pipeline-orchestrator",
26559
26669
  capScope: "system",
26560
26670
  addonId: null,
@@ -26596,6 +26706,12 @@ Object.freeze({
26596
26706
  addonId: null,
26597
26707
  access: "create"
26598
26708
  },
26709
+ "pipelineOrchestrator.setPipelineDevicePin": {
26710
+ capName: "pipeline-orchestrator",
26711
+ capScope: "system",
26712
+ addonId: null,
26713
+ access: "create"
26714
+ },
26599
26715
  "pipelineOrchestrator.unassignAudio": {
26600
26716
  capName: "pipeline-orchestrator",
26601
26717
  capScope: "system",
@@ -28148,32 +28264,6 @@ Object.freeze({
28148
28264
  "network-access": "ingress",
28149
28265
  "smtp-provider": "email"
28150
28266
  });
28151
- var frameworkSwapPackageSchema = object({
28152
- name: string(),
28153
- stagedPath: string(),
28154
- backupPath: string(),
28155
- toVersion: string(),
28156
- fromVersion: string().nullable()
28157
- });
28158
- object({
28159
- jobId: string(),
28160
- taskId: string(),
28161
- packages: array(frameworkSwapPackageSchema),
28162
- requestedAtMs: number(),
28163
- schemaVersion: literal(1)
28164
- });
28165
- object({
28166
- jobId: string(),
28167
- taskId: string(),
28168
- backups: array(object({
28169
- name: string(),
28170
- backupPath: string(),
28171
- livePath: string()
28172
- })),
28173
- appliedAtMs: number(),
28174
- bootAttempts: number(),
28175
- schemaVersion: literal(1)
28176
- });
28177
28267
  //#endregion
28178
28268
  //#region src/config.ts
28179
28269
  /**
package/dist/addon.mjs CHANGED
@@ -7097,6 +7097,17 @@ var ModelCatalogEntrySchema = object({
7097
7097
  "imagenet",
7098
7098
  "none"
7099
7099
  ]).optional(),
7100
+ /**
7101
+ * The model already applies softmax IN-GRAPH — its raw output is a
7102
+ * probability distribution, not logits. When set, the `softmax`
7103
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7104
+ * probability vector collapses it toward uniform (top-1 score craters far
7105
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7106
+ * the output is raw logits and the postprocessor applies softmax (the normal
7107
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7108
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7109
+ */
7110
+ outputProbabilities: boolean().optional(),
7100
7111
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7101
7112
  /**
7102
7113
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12387,10 +12398,7 @@ var ConfigUISchemaNullableBridge = custom();
12387
12398
  var InferenceCapabilitiesBridge = custom();
12388
12399
  var ModelAvailabilityListBridge = custom();
12389
12400
  var PipelineRunResultBridge = custom();
12390
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12391
- kind: "mutation",
12392
- auth: "admin"
12393
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12401
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12394
12402
  modelId: string(),
12395
12403
  settings: record(string(), unknown()).readonly()
12396
12404
  }))), method(object({ steps: record(string(), object({
@@ -12450,13 +12458,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12450
12458
  * (inputClasses ≠ null) are skipped and served per-track via
12451
12459
  * pipelineRunner.runDetailSubtree (two-plane design).
12452
12460
  */
12453
- plane: _enum(["full", "frame"]).optional()
12461
+ plane: _enum(["full", "frame"]).optional(),
12462
+ /**
12463
+ * Inference-device selector (Phase 2 multi-device). Format
12464
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12465
+ * Omitted ⇒ the runner's default device (current single-engine
12466
+ * behaviour). Selects WHICH device pool of the node runs the call.
12467
+ */
12468
+ deviceKey: string().optional()
12454
12469
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12455
12470
  engine: PipelineEngineChoiceSchema.optional(),
12456
12471
  steps: array(PipelineStepInputSchema).min(1),
12457
12472
  frames: array(FrameInputSchema).min(1).max(255),
12458
12473
  deviceId: number().optional(),
12459
- sessionId: string().optional()
12474
+ sessionId: string().optional(),
12475
+ /**
12476
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12477
+ * the batch to the Python pool's bench preprocess cache
12478
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12479
+ * preprocessed ONCE and every later inference is a pure-inference cache
12480
+ * hit — the sustained-throughput run measures inference, not
12481
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12482
+ * full preprocess every call, correct). Fresh per sustained run;
12483
+ * released via `uncacheFrame`.
12484
+ */
12485
+ frameId: number().int().nonnegative().optional(),
12486
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12487
+ deviceKey: string().optional()
12460
12488
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12461
12489
  data: _instanceof(Uint8Array),
12462
12490
  width: number().int().positive(),
@@ -12488,8 +12516,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12488
12516
  * - `runtime` — main camera-serving engine (no idle TTL).
12489
12517
  * - `warm-override` — benchmark/test override held in the warm
12490
12518
  * cache; auto-disposed after the idle TTL.
12519
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12520
+ * multi-device, keyed by `deviceKey`) resolved
12521
+ * via `resolveDeviceFactory`. Runs alongside the
12522
+ * `runtime` engine on a DIFFERENT accelerator
12523
+ * (NPU / iGPU / Coral) — this is how the
12524
+ * Engines tab shows all pools running at once.
12491
12525
  */
12492
- kind: _enum(["runtime", "warm-override"]),
12526
+ kind: _enum([
12527
+ "runtime",
12528
+ "warm-override",
12529
+ "device-pool"
12530
+ ]),
12493
12531
  /** Native pid of the underlying Python pool (null when no pool). */
12494
12532
  poolPid: number().nullable(),
12495
12533
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12864,7 +12902,14 @@ var RunnerCameraConfigSchema = object({
12864
12902
  * camera's detect node differs from its source-owner (P2d, gated by the
12865
12903
  * `remoteSourcingNodes` rollout setting).
12866
12904
  */
12867
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12905
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12906
+ /**
12907
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12908
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12909
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12910
+ * this only selects WHICH device pool of that node runs the session.
12911
+ */
12912
+ deviceKey: string().optional()
12868
12913
  });
12869
12914
  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;
12870
12915
  /**
@@ -12885,6 +12930,19 @@ var RunnerLocalLoadSchema = object({
12885
12930
  avgInferenceTimeMs: number(),
12886
12931
  /** Total queue depth across motion + detection queues. */
12887
12932
  queueDepthTotal: number(),
12933
+ /**
12934
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12935
+ * this runner currently has attached cameras on, so the orchestrator's second
12936
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12937
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12938
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12939
+ */
12940
+ devices: array(object({
12941
+ deviceKey: string(),
12942
+ backend: string(),
12943
+ attachedCameras: number(),
12944
+ queueDepthTotal: number()
12945
+ })).default([]),
12888
12946
  /** Hardware capability flags reported by this node. */
12889
12947
  hardware: object({
12890
12948
  hasGpu: boolean(),
@@ -16033,6 +16091,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16033
16091
  return toDeviceSummary(device, this.addonId);
16034
16092
  }
16035
16093
  };
16094
+ 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;
16095
+ new Set(Object.values(DeviceType));
16036
16096
  /**
16037
16097
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16038
16098
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19702,13 +19762,11 @@ var PipelineTemplateSchema = object({
19702
19762
  createdAt: string(),
19703
19763
  updatedAt: string()
19704
19764
  });
19705
- var AgentAddonConfigSchema = object({
19706
- enabled: boolean(),
19765
+ var DeviceStepConfigSchema = object({
19707
19766
  modelId: string().optional(),
19708
- settings: record(string(), unknown()).readonly()
19767
+ settings: record(string(), unknown()).optional()
19709
19768
  });
19710
19769
  var AgentPipelineSettingsSchema = object({
19711
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19712
19770
  maxCameras: number().int().nonnegative().nullable().default(null),
19713
19771
  /** Per-node detection weight (relative share for the quota balancer). */
19714
19772
  detectWeight: number().positive().optional(),
@@ -19732,7 +19790,22 @@ var AgentPipelineSettingsSchema = object({
19732
19790
  * it already uses to reach the hub). Set this only when the auto-detected
19733
19791
  * address is wrong (multi-homed host, NAT, custom interface).
19734
19792
  */
19735
- reachableHost: string().optional()
19793
+ reachableHost: string().optional(),
19794
+ /**
19795
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19796
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19797
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19798
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19799
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19800
+ * the default model/settings for every camera landing on that accelerator;
19801
+ * a stepId absent ⇒ the step uses that device's format default.
19802
+ */
19803
+ inferenceDevices: record(string(), object({
19804
+ enabled: boolean(),
19805
+ weight: number().positive().optional(),
19806
+ maxSessions: number().int().positive().optional(),
19807
+ steps: record(string(), DeviceStepConfigSchema).optional()
19808
+ })).optional()
19736
19809
  });
19737
19810
  var CameraPipelineForAgentSchema = object({
19738
19811
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19742,14 +19815,13 @@ var CameraPipelineForAgentSchema = object({
19742
19815
  }).nullable()
19743
19816
  });
19744
19817
  var CameraStepOverridePatchSchema = object({
19745
- enabled: boolean().optional(),
19746
19818
  modelId: string().optional(),
19747
19819
  settings: record(string(), unknown()).readonly().optional()
19748
19820
  });
19749
19821
  var CameraPipelineSettingsSchema = object({
19750
19822
  pinnedAgentNodeId: string().optional(),
19751
19823
  stepToggles: record(string(), boolean()).optional(),
19752
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19824
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19753
19825
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19754
19826
  });
19755
19827
  /**
@@ -19963,6 +20035,44 @@ var CameraStatusSchema = object({
19963
20035
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
19964
20036
  fetchedAt: number()
19965
20037
  });
20038
+ var NodeInferenceDeviceSchema = object({
20039
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20040
+ key: string(),
20041
+ backend: string(),
20042
+ device: string(),
20043
+ format: _enum(MODEL_FORMATS),
20044
+ /** Whether the node's live probe reports the device as usable right now. */
20045
+ available: boolean(),
20046
+ /**
20047
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20048
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20049
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20050
+ * not a balanced target). An explicit stored value always wins; a stored-only
20051
+ * (unavailable) key keeps its stored value.
20052
+ */
20053
+ enabled: boolean(),
20054
+ /** Relative balancer weight for the enabled device (default 1). */
20055
+ weight: number(),
20056
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20057
+ maxSessions: number().nullable(),
20058
+ /** Object-detection model the executor defaults to for this deviceKey. */
20059
+ defaultModelId: string(),
20060
+ /**
20061
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20062
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20063
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20064
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20065
+ * available per format; this is the stored selection that becomes the
20066
+ * default for EVERY camera landing on this accelerator.
20067
+ */
20068
+ steps: record(string(), DeviceStepConfigSchema).optional()
20069
+ });
20070
+ var NodeInferenceDevicesSchema = object({
20071
+ nodeId: string(),
20072
+ /** False when the node's platform-probe was unreachable (no live device set). */
20073
+ reachable: boolean(),
20074
+ devices: array(NodeInferenceDeviceSchema).readonly()
20075
+ });
19966
20076
  method(object({
19967
20077
  deviceId: number(),
19968
20078
  agentNodeId: string()
@@ -19972,7 +20082,13 @@ method(object({
19972
20082
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
19973
20083
  kind: "mutation",
19974
20084
  auth: "admin"
19975
- }), method(_void(), object({ migrated: number() }), {
20085
+ }), method(object({
20086
+ deviceId: number(),
20087
+ deviceKey: string()
20088
+ }), object({ success: literal(true) }), {
20089
+ kind: "mutation",
20090
+ auth: "admin"
20091
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
19976
20092
  kind: "mutation",
19977
20093
  auth: "admin"
19978
20094
  }), 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({
@@ -20006,13 +20122,7 @@ method(object({
20006
20122
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20007
20123
  nodeId: string(),
20008
20124
  settings: AgentPipelineSettingsSchema
20009
- })).readonly()), method(object({
20010
- agentNodeId: string(),
20011
- defaults: record(string(), AgentAddonConfigSchema)
20012
- }), object({ success: literal(true) }), {
20013
- kind: "mutation",
20014
- auth: "admin"
20015
- }), method(object({ agentNodeId: string() }), object({
20125
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20016
20126
  success: boolean(),
20017
20127
  removed: boolean()
20018
20128
  }), {
@@ -20044,7 +20154,18 @@ method(object({
20044
20154
  }), object({ success: literal(true) }), {
20045
20155
  kind: "mutation",
20046
20156
  auth: "admin"
20047
- }), method(object({ agentNodeId: string() }), object({
20157
+ }), method(object({
20158
+ agentNodeId: string(),
20159
+ inferenceDevices: record(string(), object({
20160
+ enabled: boolean(),
20161
+ weight: number().positive().optional(),
20162
+ maxSessions: number().int().positive().optional(),
20163
+ steps: record(string(), DeviceStepConfigSchema).optional()
20164
+ }))
20165
+ }), object({ success: literal(true) }), {
20166
+ kind: "mutation",
20167
+ auth: "admin"
20168
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20048
20169
  success: literal(true),
20049
20170
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20050
20171
  effectiveModelId: string().nullable(),
@@ -20060,9 +20181,10 @@ method(object({
20060
20181
  }), object({ success: literal(true) }), {
20061
20182
  kind: "mutation",
20062
20183
  auth: "admin"
20063
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20184
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20064
20185
  deviceId: number(),
20065
20186
  agentNodeId: string(),
20187
+ deviceKey: string(),
20066
20188
  addonId: string(),
20067
20189
  patch: CameraStepOverridePatchSchema.nullable()
20068
20190
  }), object({ success: literal(true) }), {
@@ -20099,14 +20221,13 @@ method(object({
20099
20221
  });
20100
20222
  /**
20101
20223
  * server-management — per-NODE singleton capability for a node's ROOT
20102
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20103
- * agents).
20224
+ * package lifecycle (runtime-updatable node packages).
20104
20225
  *
20105
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20106
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20107
- * version describes the node. Updates install into
20108
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20109
- * starter (probation boot + auto-rollback to N-1).
20226
+ * Every node role runs the SAME root package (`@camstack/server`), which
20227
+ * carries the whole software stack in its npm dep tree, so ONE version
20228
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20229
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20230
+ * no auto-rollback).
20110
20231
  *
20111
20232
  * Providers:
20112
20233
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20214,7 +20335,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20214
20335
  /** Explicit target version; omitted = latest from the registry. */
20215
20336
  version: string().optional() }), ServerUpdateActionResultSchema, {
20216
20337
  kind: "mutation",
20217
- auth: "admin"
20338
+ auth: "admin",
20339
+ timeoutMs: 16 * 6e4
20218
20340
  }), method(_void(), ServerUpdateActionResultSchema, {
20219
20341
  kind: "mutation",
20220
20342
  auth: "admin"
@@ -21258,22 +21380,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21258
21380
  var RestartAddonResultSchema = unknown();
21259
21381
  var InstallPackageResultSchema = unknown();
21260
21382
  var ReloadPackagesResultSchema = unknown();
21261
- /**
21262
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21263
- * server restarts so the admin UI can react to the `restartingAt`
21264
- * timestamp (shows reconnect overlay). The transition from
21265
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21266
- * `system.restart-completed` event after the new process boots.
21267
- *
21268
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21269
- */
21270
- var UpdateFrameworkPackageResultSchema = object({
21271
- packageName: string(),
21272
- fromVersion: string(),
21273
- toVersion: string(),
21274
- /** Ms-epoch the server scheduled its self-restart. */
21275
- restartingAt: number()
21276
- });
21277
21383
  var BulkUpdateItemStatusSchema = _enum([
21278
21384
  "queued",
21279
21385
  "updating",
@@ -21401,13 +21507,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21401
21507
  }), object({ success: literal(true) }), {
21402
21508
  kind: "mutation",
21403
21509
  auth: "admin"
21404
- }), method(object({
21405
- packageName: string().min(1),
21406
- version: string().optional(),
21407
- deferRestart: boolean().optional()
21408
- }), UpdateFrameworkPackageResultSchema, {
21409
- kind: "mutation",
21410
- auth: "admin"
21411
21510
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21412
21511
  kind: "mutation",
21413
21512
  auth: "admin"
@@ -22273,10 +22372,10 @@ var TopologyCategorySchema = object({
22273
22372
  addons: array(TopologyCategoryAddonSchema).readonly()
22274
22373
  });
22275
22374
  /**
22276
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22277
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22278
- * version visibility for the Server management surface. Nullable: offline
22279
- * rows and pre-phase-2 nodes report none.
22375
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22376
+ * root package for every node role) as reported by its `registerNode`
22377
+ * manifest — version visibility for the Server management surface. Nullable:
22378
+ * offline rows and nodes that never reported one.
22280
22379
  */
22281
22380
  var TopologyRootPackageSchema = object({
22282
22381
  name: string(),
@@ -22664,17 +22763,28 @@ var PlatformScoreSchema = object({
22664
22763
  format: _enum([
22665
22764
  "onnx",
22666
22765
  "coreml",
22667
- "openvino"
22766
+ "openvino",
22767
+ "tflite"
22668
22768
  ]),
22669
22769
  score: number(),
22670
22770
  reason: string(),
22671
22771
  available: boolean()
22672
22772
  });
22773
+ var InferenceDeviceDescriptorSchema = object({
22774
+ key: string(),
22775
+ backend: string(),
22776
+ device: string(),
22777
+ format: ModelFormatSchema,
22778
+ runtime: literal("python"),
22779
+ score: number(),
22780
+ available: boolean()
22781
+ });
22673
22782
  var PlatformCapabilitiesSchema = object({
22674
22783
  hardware: HardwareInfoSchema,
22675
22784
  scores: array(PlatformScoreSchema).readonly(),
22676
22785
  bestScore: PlatformScoreSchema,
22677
- pythonPath: string().nullable()
22786
+ pythonPath: string().nullable(),
22787
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22678
22788
  });
22679
22789
  var ModelRequirementSchema = object({
22680
22790
  modelId: string(),
@@ -23553,12 +23663,6 @@ Object.freeze({
23553
23663
  addonId: null,
23554
23664
  access: "delete"
23555
23665
  },
23556
- "addons.updateFrameworkPackage": {
23557
- capName: "addons",
23558
- capScope: "system",
23559
- addonId: null,
23560
- access: "create"
23561
- },
23562
23666
  "addons.updatePackage": {
23563
23667
  capName: "addons",
23564
23668
  capScope: "system",
@@ -26331,12 +26435,6 @@ Object.freeze({
26331
26435
  addonId: null,
26332
26436
  access: "view"
26333
26437
  },
26334
- "pipelineExecutor.reprobeEngine": {
26335
- capName: "pipeline-executor",
26336
- capScope: "system",
26337
- addonId: null,
26338
- access: "create"
26339
- },
26340
26438
  "pipelineExecutor.runAudioTest": {
26341
26439
  capName: "pipeline-executor",
26342
26440
  capScope: "system",
@@ -26487,6 +26585,12 @@ Object.freeze({
26487
26585
  addonId: null,
26488
26586
  access: "view"
26489
26587
  },
26588
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26589
+ capName: "pipeline-orchestrator",
26590
+ capScope: "system",
26591
+ addonId: null,
26592
+ access: "view"
26593
+ },
26490
26594
  "pipelineOrchestrator.getPipelineAssignment": {
26491
26595
  capName: "pipeline-orchestrator",
26492
26596
  capScope: "system",
@@ -26499,6 +26603,12 @@ Object.freeze({
26499
26603
  addonId: null,
26500
26604
  access: "view"
26501
26605
  },
26606
+ "pipelineOrchestrator.getPipelineDevicePin": {
26607
+ capName: "pipeline-orchestrator",
26608
+ capScope: "system",
26609
+ addonId: null,
26610
+ access: "view"
26611
+ },
26502
26612
  "pipelineOrchestrator.listAgentSettings": {
26503
26613
  capName: "pipeline-orchestrator",
26504
26614
  capScope: "system",
@@ -26541,19 +26651,19 @@ Object.freeze({
26541
26651
  addonId: null,
26542
26652
  access: "create"
26543
26653
  },
26544
- "pipelineOrchestrator.setAgentAddonDefaults": {
26654
+ "pipelineOrchestrator.setAgentCapabilities": {
26545
26655
  capName: "pipeline-orchestrator",
26546
26656
  capScope: "system",
26547
26657
  addonId: null,
26548
26658
  access: "create"
26549
26659
  },
26550
- "pipelineOrchestrator.setAgentCapabilities": {
26660
+ "pipelineOrchestrator.setAgentDetectWeight": {
26551
26661
  capName: "pipeline-orchestrator",
26552
26662
  capScope: "system",
26553
26663
  addonId: null,
26554
26664
  access: "create"
26555
26665
  },
26556
- "pipelineOrchestrator.setAgentDetectWeight": {
26666
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26557
26667
  capName: "pipeline-orchestrator",
26558
26668
  capScope: "system",
26559
26669
  addonId: null,
@@ -26595,6 +26705,12 @@ Object.freeze({
26595
26705
  addonId: null,
26596
26706
  access: "create"
26597
26707
  },
26708
+ "pipelineOrchestrator.setPipelineDevicePin": {
26709
+ capName: "pipeline-orchestrator",
26710
+ capScope: "system",
26711
+ addonId: null,
26712
+ access: "create"
26713
+ },
26598
26714
  "pipelineOrchestrator.unassignAudio": {
26599
26715
  capName: "pipeline-orchestrator",
26600
26716
  capScope: "system",
@@ -28147,32 +28263,6 @@ Object.freeze({
28147
28263
  "network-access": "ingress",
28148
28264
  "smtp-provider": "email"
28149
28265
  });
28150
- var frameworkSwapPackageSchema = object({
28151
- name: string(),
28152
- stagedPath: string(),
28153
- backupPath: string(),
28154
- toVersion: string(),
28155
- fromVersion: string().nullable()
28156
- });
28157
- object({
28158
- jobId: string(),
28159
- taskId: string(),
28160
- packages: array(frameworkSwapPackageSchema),
28161
- requestedAtMs: number(),
28162
- schemaVersion: literal(1)
28163
- });
28164
- object({
28165
- jobId: string(),
28166
- taskId: string(),
28167
- backups: array(object({
28168
- name: string(),
28169
- backupPath: string(),
28170
- livePath: string()
28171
- })),
28172
- appliedAtMs: number(),
28173
- bootAttempts: number(),
28174
- schemaVersion: literal(1)
28175
- });
28176
28266
  //#endregion
28177
28267
  //#region src/config.ts
28178
28268
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-vesync",
3
- "version": "0.1.14",
3
+ "version": "0.2.0",
4
4
  "description": "VeSync cloud-account device-provider addon for CamStack — Levoit / Cosori air purifiers as Fan devices (power, speed, preset, child-lock, display, air-quality + filter-life sensors)",
5
5
  "keywords": [
6
6
  "camstack",