@camstack/addon-provider-dreame 0.1.34 → 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
@@ -7136,6 +7136,17 @@ var ModelCatalogEntrySchema = object({
7136
7136
  "imagenet",
7137
7137
  "none"
7138
7138
  ]).optional(),
7139
+ /**
7140
+ * The model already applies softmax IN-GRAPH — its raw output is a
7141
+ * probability distribution, not logits. When set, the `softmax`
7142
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7143
+ * probability vector collapses it toward uniform (top-1 score craters far
7144
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7145
+ * the output is raw logits and the postprocessor applies softmax (the normal
7146
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7147
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7148
+ */
7149
+ outputProbabilities: boolean().optional(),
7139
7150
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7140
7151
  /**
7141
7152
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12426,10 +12437,7 @@ var ConfigUISchemaNullableBridge = custom();
12426
12437
  var InferenceCapabilitiesBridge = custom();
12427
12438
  var ModelAvailabilityListBridge = custom();
12428
12439
  var PipelineRunResultBridge = custom();
12429
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12430
- kind: "mutation",
12431
- auth: "admin"
12432
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12440
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12433
12441
  modelId: string(),
12434
12442
  settings: record(string(), unknown()).readonly()
12435
12443
  }))), method(object({ steps: record(string(), object({
@@ -12489,13 +12497,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12489
12497
  * (inputClasses ≠ null) are skipped and served per-track via
12490
12498
  * pipelineRunner.runDetailSubtree (two-plane design).
12491
12499
  */
12492
- plane: _enum(["full", "frame"]).optional()
12500
+ plane: _enum(["full", "frame"]).optional(),
12501
+ /**
12502
+ * Inference-device selector (Phase 2 multi-device). Format
12503
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12504
+ * Omitted ⇒ the runner's default device (current single-engine
12505
+ * behaviour). Selects WHICH device pool of the node runs the call.
12506
+ */
12507
+ deviceKey: string().optional()
12493
12508
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12494
12509
  engine: PipelineEngineChoiceSchema.optional(),
12495
12510
  steps: array(PipelineStepInputSchema).min(1),
12496
12511
  frames: array(FrameInputSchema).min(1).max(255),
12497
12512
  deviceId: number().optional(),
12498
- sessionId: string().optional()
12513
+ sessionId: string().optional(),
12514
+ /**
12515
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12516
+ * the batch to the Python pool's bench preprocess cache
12517
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12518
+ * preprocessed ONCE and every later inference is a pure-inference cache
12519
+ * hit — the sustained-throughput run measures inference, not
12520
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12521
+ * full preprocess every call, correct). Fresh per sustained run;
12522
+ * released via `uncacheFrame`.
12523
+ */
12524
+ frameId: number().int().nonnegative().optional(),
12525
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12526
+ deviceKey: string().optional()
12499
12527
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12500
12528
  data: _instanceof(Uint8Array),
12501
12529
  width: number().int().positive(),
@@ -12527,8 +12555,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12527
12555
  * - `runtime` — main camera-serving engine (no idle TTL).
12528
12556
  * - `warm-override` — benchmark/test override held in the warm
12529
12557
  * cache; auto-disposed after the idle TTL.
12558
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12559
+ * multi-device, keyed by `deviceKey`) resolved
12560
+ * via `resolveDeviceFactory`. Runs alongside the
12561
+ * `runtime` engine on a DIFFERENT accelerator
12562
+ * (NPU / iGPU / Coral) — this is how the
12563
+ * Engines tab shows all pools running at once.
12530
12564
  */
12531
- kind: _enum(["runtime", "warm-override"]),
12565
+ kind: _enum([
12566
+ "runtime",
12567
+ "warm-override",
12568
+ "device-pool"
12569
+ ]),
12532
12570
  /** Native pid of the underlying Python pool (null when no pool). */
12533
12571
  poolPid: number().nullable(),
12534
12572
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12903,7 +12941,14 @@ var RunnerCameraConfigSchema = object({
12903
12941
  * camera's detect node differs from its source-owner (P2d, gated by the
12904
12942
  * `remoteSourcingNodes` rollout setting).
12905
12943
  */
12906
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12944
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12945
+ /**
12946
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12947
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12948
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12949
+ * this only selects WHICH device pool of that node runs the session.
12950
+ */
12951
+ deviceKey: string().optional()
12907
12952
  });
12908
12953
  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;
12909
12954
  /**
@@ -12924,6 +12969,19 @@ var RunnerLocalLoadSchema = object({
12924
12969
  avgInferenceTimeMs: number(),
12925
12970
  /** Total queue depth across motion + detection queues. */
12926
12971
  queueDepthTotal: number(),
12972
+ /**
12973
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12974
+ * this runner currently has attached cameras on, so the orchestrator's second
12975
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12976
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12977
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12978
+ */
12979
+ devices: array(object({
12980
+ deviceKey: string(),
12981
+ backend: string(),
12982
+ attachedCameras: number(),
12983
+ queueDepthTotal: number()
12984
+ })).default([]),
12927
12985
  /** Hardware capability flags reported by this node. */
12928
12986
  hardware: object({
12929
12987
  hasGpu: boolean(),
@@ -16072,6 +16130,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16072
16130
  return toDeviceSummary(device, this.addonId);
16073
16131
  }
16074
16132
  };
16133
+ 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;
16134
+ new Set(Object.values(DeviceType));
16075
16135
  /**
16076
16136
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16077
16137
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19758,13 +19818,11 @@ var PipelineTemplateSchema = object({
19758
19818
  createdAt: string(),
19759
19819
  updatedAt: string()
19760
19820
  });
19761
- var AgentAddonConfigSchema = object({
19762
- enabled: boolean(),
19821
+ var DeviceStepConfigSchema = object({
19763
19822
  modelId: string().optional(),
19764
- settings: record(string(), unknown()).readonly()
19823
+ settings: record(string(), unknown()).optional()
19765
19824
  });
19766
19825
  var AgentPipelineSettingsSchema = object({
19767
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19768
19826
  maxCameras: number().int().nonnegative().nullable().default(null),
19769
19827
  /** Per-node detection weight (relative share for the quota balancer). */
19770
19828
  detectWeight: number().positive().optional(),
@@ -19788,7 +19846,22 @@ var AgentPipelineSettingsSchema = object({
19788
19846
  * it already uses to reach the hub). Set this only when the auto-detected
19789
19847
  * address is wrong (multi-homed host, NAT, custom interface).
19790
19848
  */
19791
- reachableHost: string().optional()
19849
+ reachableHost: string().optional(),
19850
+ /**
19851
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19852
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19853
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19854
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19855
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19856
+ * the default model/settings for every camera landing on that accelerator;
19857
+ * a stepId absent ⇒ the step uses that device's format default.
19858
+ */
19859
+ inferenceDevices: record(string(), object({
19860
+ enabled: boolean(),
19861
+ weight: number().positive().optional(),
19862
+ maxSessions: number().int().positive().optional(),
19863
+ steps: record(string(), DeviceStepConfigSchema).optional()
19864
+ })).optional()
19792
19865
  });
19793
19866
  var CameraPipelineForAgentSchema = object({
19794
19867
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19798,14 +19871,13 @@ var CameraPipelineForAgentSchema = object({
19798
19871
  }).nullable()
19799
19872
  });
19800
19873
  var CameraStepOverridePatchSchema = object({
19801
- enabled: boolean().optional(),
19802
19874
  modelId: string().optional(),
19803
19875
  settings: record(string(), unknown()).readonly().optional()
19804
19876
  });
19805
19877
  var CameraPipelineSettingsSchema = object({
19806
19878
  pinnedAgentNodeId: string().optional(),
19807
19879
  stepToggles: record(string(), boolean()).optional(),
19808
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19880
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19809
19881
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19810
19882
  });
19811
19883
  /**
@@ -20019,6 +20091,44 @@ var CameraStatusSchema = object({
20019
20091
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20020
20092
  fetchedAt: number()
20021
20093
  });
20094
+ var NodeInferenceDeviceSchema = object({
20095
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20096
+ key: string(),
20097
+ backend: string(),
20098
+ device: string(),
20099
+ format: _enum(MODEL_FORMATS),
20100
+ /** Whether the node's live probe reports the device as usable right now. */
20101
+ available: boolean(),
20102
+ /**
20103
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20104
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20105
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20106
+ * not a balanced target). An explicit stored value always wins; a stored-only
20107
+ * (unavailable) key keeps its stored value.
20108
+ */
20109
+ enabled: boolean(),
20110
+ /** Relative balancer weight for the enabled device (default 1). */
20111
+ weight: number(),
20112
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20113
+ maxSessions: number().nullable(),
20114
+ /** Object-detection model the executor defaults to for this deviceKey. */
20115
+ defaultModelId: string(),
20116
+ /**
20117
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20118
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20119
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20120
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20121
+ * available per format; this is the stored selection that becomes the
20122
+ * default for EVERY camera landing on this accelerator.
20123
+ */
20124
+ steps: record(string(), DeviceStepConfigSchema).optional()
20125
+ });
20126
+ var NodeInferenceDevicesSchema = object({
20127
+ nodeId: string(),
20128
+ /** False when the node's platform-probe was unreachable (no live device set). */
20129
+ reachable: boolean(),
20130
+ devices: array(NodeInferenceDeviceSchema).readonly()
20131
+ });
20022
20132
  method(object({
20023
20133
  deviceId: number(),
20024
20134
  agentNodeId: string()
@@ -20028,7 +20138,13 @@ method(object({
20028
20138
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20029
20139
  kind: "mutation",
20030
20140
  auth: "admin"
20031
- }), method(_void(), object({ migrated: number() }), {
20141
+ }), method(object({
20142
+ deviceId: number(),
20143
+ deviceKey: string()
20144
+ }), object({ success: literal(true) }), {
20145
+ kind: "mutation",
20146
+ auth: "admin"
20147
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20032
20148
  kind: "mutation",
20033
20149
  auth: "admin"
20034
20150
  }), 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({
@@ -20062,13 +20178,7 @@ method(object({
20062
20178
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20063
20179
  nodeId: string(),
20064
20180
  settings: AgentPipelineSettingsSchema
20065
- })).readonly()), method(object({
20066
- agentNodeId: string(),
20067
- defaults: record(string(), AgentAddonConfigSchema)
20068
- }), object({ success: literal(true) }), {
20069
- kind: "mutation",
20070
- auth: "admin"
20071
- }), method(object({ agentNodeId: string() }), object({
20181
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20072
20182
  success: boolean(),
20073
20183
  removed: boolean()
20074
20184
  }), {
@@ -20100,7 +20210,18 @@ method(object({
20100
20210
  }), object({ success: literal(true) }), {
20101
20211
  kind: "mutation",
20102
20212
  auth: "admin"
20103
- }), method(object({ agentNodeId: string() }), object({
20213
+ }), method(object({
20214
+ agentNodeId: string(),
20215
+ inferenceDevices: record(string(), object({
20216
+ enabled: boolean(),
20217
+ weight: number().positive().optional(),
20218
+ maxSessions: number().int().positive().optional(),
20219
+ steps: record(string(), DeviceStepConfigSchema).optional()
20220
+ }))
20221
+ }), object({ success: literal(true) }), {
20222
+ kind: "mutation",
20223
+ auth: "admin"
20224
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20104
20225
  success: literal(true),
20105
20226
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20106
20227
  effectiveModelId: string().nullable(),
@@ -20116,9 +20237,10 @@ method(object({
20116
20237
  }), object({ success: literal(true) }), {
20117
20238
  kind: "mutation",
20118
20239
  auth: "admin"
20119
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20240
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20120
20241
  deviceId: number(),
20121
20242
  agentNodeId: string(),
20243
+ deviceKey: string(),
20122
20244
  addonId: string(),
20123
20245
  patch: CameraStepOverridePatchSchema.nullable()
20124
20246
  }), object({ success: literal(true) }), {
@@ -20155,14 +20277,13 @@ method(object({
20155
20277
  });
20156
20278
  /**
20157
20279
  * server-management — per-NODE singleton capability for a node's ROOT
20158
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20159
- * agents).
20280
+ * package lifecycle (runtime-updatable node packages).
20160
20281
  *
20161
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20162
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20163
- * version describes the node. Updates install into
20164
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20165
- * starter (probation boot + auto-rollback to N-1).
20282
+ * Every node role runs the SAME root package (`@camstack/server`), which
20283
+ * carries the whole software stack in its npm dep tree, so ONE version
20284
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20285
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20286
+ * no auto-rollback).
20166
20287
  *
20167
20288
  * Providers:
20168
20289
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20270,7 +20391,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20270
20391
  /** Explicit target version; omitted = latest from the registry. */
20271
20392
  version: string().optional() }), ServerUpdateActionResultSchema, {
20272
20393
  kind: "mutation",
20273
- auth: "admin"
20394
+ auth: "admin",
20395
+ timeoutMs: 16 * 6e4
20274
20396
  }), method(_void(), ServerUpdateActionResultSchema, {
20275
20397
  kind: "mutation",
20276
20398
  auth: "admin"
@@ -21314,22 +21436,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21314
21436
  var RestartAddonResultSchema = unknown();
21315
21437
  var InstallPackageResultSchema = unknown();
21316
21438
  var ReloadPackagesResultSchema = unknown();
21317
- /**
21318
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21319
- * server restarts so the admin UI can react to the `restartingAt`
21320
- * timestamp (shows reconnect overlay). The transition from
21321
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21322
- * `system.restart-completed` event after the new process boots.
21323
- *
21324
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21325
- */
21326
- var UpdateFrameworkPackageResultSchema = object({
21327
- packageName: string(),
21328
- fromVersion: string(),
21329
- toVersion: string(),
21330
- /** Ms-epoch the server scheduled its self-restart. */
21331
- restartingAt: number()
21332
- });
21333
21439
  var BulkUpdateItemStatusSchema = _enum([
21334
21440
  "queued",
21335
21441
  "updating",
@@ -21457,13 +21563,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21457
21563
  }), object({ success: literal(true) }), {
21458
21564
  kind: "mutation",
21459
21565
  auth: "admin"
21460
- }), method(object({
21461
- packageName: string().min(1),
21462
- version: string().optional(),
21463
- deferRestart: boolean().optional()
21464
- }), UpdateFrameworkPackageResultSchema, {
21465
- kind: "mutation",
21466
- auth: "admin"
21467
21566
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21468
21567
  kind: "mutation",
21469
21568
  auth: "admin"
@@ -22346,10 +22445,10 @@ var TopologyCategorySchema = object({
22346
22445
  addons: array(TopologyCategoryAddonSchema).readonly()
22347
22446
  });
22348
22447
  /**
22349
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22350
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22351
- * version visibility for the Server management surface. Nullable: offline
22352
- * rows and pre-phase-2 nodes report none.
22448
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22449
+ * root package for every node role) as reported by its `registerNode`
22450
+ * manifest — version visibility for the Server management surface. Nullable:
22451
+ * offline rows and nodes that never reported one.
22353
22452
  */
22354
22453
  var TopologyRootPackageSchema = object({
22355
22454
  name: string(),
@@ -22737,17 +22836,28 @@ var PlatformScoreSchema = object({
22737
22836
  format: _enum([
22738
22837
  "onnx",
22739
22838
  "coreml",
22740
- "openvino"
22839
+ "openvino",
22840
+ "tflite"
22741
22841
  ]),
22742
22842
  score: number(),
22743
22843
  reason: string(),
22744
22844
  available: boolean()
22745
22845
  });
22846
+ var InferenceDeviceDescriptorSchema = object({
22847
+ key: string(),
22848
+ backend: string(),
22849
+ device: string(),
22850
+ format: ModelFormatSchema,
22851
+ runtime: literal("python"),
22852
+ score: number(),
22853
+ available: boolean()
22854
+ });
22746
22855
  var PlatformCapabilitiesSchema = object({
22747
22856
  hardware: HardwareInfoSchema,
22748
22857
  scores: array(PlatformScoreSchema).readonly(),
22749
22858
  bestScore: PlatformScoreSchema,
22750
- pythonPath: string().nullable()
22859
+ pythonPath: string().nullable(),
22860
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22751
22861
  });
22752
22862
  var ModelRequirementSchema = object({
22753
22863
  modelId: string(),
@@ -23626,12 +23736,6 @@ Object.freeze({
23626
23736
  addonId: null,
23627
23737
  access: "delete"
23628
23738
  },
23629
- "addons.updateFrameworkPackage": {
23630
- capName: "addons",
23631
- capScope: "system",
23632
- addonId: null,
23633
- access: "create"
23634
- },
23635
23739
  "addons.updatePackage": {
23636
23740
  capName: "addons",
23637
23741
  capScope: "system",
@@ -26404,12 +26508,6 @@ Object.freeze({
26404
26508
  addonId: null,
26405
26509
  access: "view"
26406
26510
  },
26407
- "pipelineExecutor.reprobeEngine": {
26408
- capName: "pipeline-executor",
26409
- capScope: "system",
26410
- addonId: null,
26411
- access: "create"
26412
- },
26413
26511
  "pipelineExecutor.runAudioTest": {
26414
26512
  capName: "pipeline-executor",
26415
26513
  capScope: "system",
@@ -26560,6 +26658,12 @@ Object.freeze({
26560
26658
  addonId: null,
26561
26659
  access: "view"
26562
26660
  },
26661
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26662
+ capName: "pipeline-orchestrator",
26663
+ capScope: "system",
26664
+ addonId: null,
26665
+ access: "view"
26666
+ },
26563
26667
  "pipelineOrchestrator.getPipelineAssignment": {
26564
26668
  capName: "pipeline-orchestrator",
26565
26669
  capScope: "system",
@@ -26572,6 +26676,12 @@ Object.freeze({
26572
26676
  addonId: null,
26573
26677
  access: "view"
26574
26678
  },
26679
+ "pipelineOrchestrator.getPipelineDevicePin": {
26680
+ capName: "pipeline-orchestrator",
26681
+ capScope: "system",
26682
+ addonId: null,
26683
+ access: "view"
26684
+ },
26575
26685
  "pipelineOrchestrator.listAgentSettings": {
26576
26686
  capName: "pipeline-orchestrator",
26577
26687
  capScope: "system",
@@ -26614,19 +26724,19 @@ Object.freeze({
26614
26724
  addonId: null,
26615
26725
  access: "create"
26616
26726
  },
26617
- "pipelineOrchestrator.setAgentAddonDefaults": {
26727
+ "pipelineOrchestrator.setAgentCapabilities": {
26618
26728
  capName: "pipeline-orchestrator",
26619
26729
  capScope: "system",
26620
26730
  addonId: null,
26621
26731
  access: "create"
26622
26732
  },
26623
- "pipelineOrchestrator.setAgentCapabilities": {
26733
+ "pipelineOrchestrator.setAgentDetectWeight": {
26624
26734
  capName: "pipeline-orchestrator",
26625
26735
  capScope: "system",
26626
26736
  addonId: null,
26627
26737
  access: "create"
26628
26738
  },
26629
- "pipelineOrchestrator.setAgentDetectWeight": {
26739
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26630
26740
  capName: "pipeline-orchestrator",
26631
26741
  capScope: "system",
26632
26742
  addonId: null,
@@ -26668,6 +26778,12 @@ Object.freeze({
26668
26778
  addonId: null,
26669
26779
  access: "create"
26670
26780
  },
26781
+ "pipelineOrchestrator.setPipelineDevicePin": {
26782
+ capName: "pipeline-orchestrator",
26783
+ capScope: "system",
26784
+ addonId: null,
26785
+ access: "create"
26786
+ },
26671
26787
  "pipelineOrchestrator.unassignAudio": {
26672
26788
  capName: "pipeline-orchestrator",
26673
26789
  capScope: "system",
@@ -28220,32 +28336,6 @@ Object.freeze({
28220
28336
  "network-access": "ingress",
28221
28337
  "smtp-provider": "email"
28222
28338
  });
28223
- var frameworkSwapPackageSchema = object({
28224
- name: string(),
28225
- stagedPath: string(),
28226
- backupPath: string(),
28227
- toVersion: string(),
28228
- fromVersion: string().nullable()
28229
- });
28230
- object({
28231
- jobId: string(),
28232
- taskId: string(),
28233
- packages: array(frameworkSwapPackageSchema),
28234
- requestedAtMs: number(),
28235
- schemaVersion: literal(1)
28236
- });
28237
- object({
28238
- jobId: string(),
28239
- taskId: string(),
28240
- backups: array(object({
28241
- name: string(),
28242
- backupPath: string(),
28243
- livePath: string()
28244
- })),
28245
- appliedAtMs: number(),
28246
- bootAttempts: number(),
28247
- schemaVersion: literal(1)
28248
- });
28249
28339
  //#endregion
28250
28340
  //#region src/config.ts
28251
28341
  /**
package/dist/addon.mjs CHANGED
@@ -7136,6 +7136,17 @@ var ModelCatalogEntrySchema = object({
7136
7136
  "imagenet",
7137
7137
  "none"
7138
7138
  ]).optional(),
7139
+ /**
7140
+ * The model already applies softmax IN-GRAPH — its raw output is a
7141
+ * probability distribution, not logits. When set, the `softmax`
7142
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7143
+ * probability vector collapses it toward uniform (top-1 score craters far
7144
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7145
+ * the output is raw logits and the postprocessor applies softmax (the normal
7146
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7147
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7148
+ */
7149
+ outputProbabilities: boolean().optional(),
7139
7150
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7140
7151
  /**
7141
7152
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12426,10 +12437,7 @@ var ConfigUISchemaNullableBridge = custom();
12426
12437
  var InferenceCapabilitiesBridge = custom();
12427
12438
  var ModelAvailabilityListBridge = custom();
12428
12439
  var PipelineRunResultBridge = custom();
12429
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12430
- kind: "mutation",
12431
- auth: "admin"
12432
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12440
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12433
12441
  modelId: string(),
12434
12442
  settings: record(string(), unknown()).readonly()
12435
12443
  }))), method(object({ steps: record(string(), object({
@@ -12489,13 +12497,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12489
12497
  * (inputClasses ≠ null) are skipped and served per-track via
12490
12498
  * pipelineRunner.runDetailSubtree (two-plane design).
12491
12499
  */
12492
- plane: _enum(["full", "frame"]).optional()
12500
+ plane: _enum(["full", "frame"]).optional(),
12501
+ /**
12502
+ * Inference-device selector (Phase 2 multi-device). Format
12503
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12504
+ * Omitted ⇒ the runner's default device (current single-engine
12505
+ * behaviour). Selects WHICH device pool of the node runs the call.
12506
+ */
12507
+ deviceKey: string().optional()
12493
12508
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12494
12509
  engine: PipelineEngineChoiceSchema.optional(),
12495
12510
  steps: array(PipelineStepInputSchema).min(1),
12496
12511
  frames: array(FrameInputSchema).min(1).max(255),
12497
12512
  deviceId: number().optional(),
12498
- sessionId: string().optional()
12513
+ sessionId: string().optional(),
12514
+ /**
12515
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12516
+ * the batch to the Python pool's bench preprocess cache
12517
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12518
+ * preprocessed ONCE and every later inference is a pure-inference cache
12519
+ * hit — the sustained-throughput run measures inference, not
12520
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12521
+ * full preprocess every call, correct). Fresh per sustained run;
12522
+ * released via `uncacheFrame`.
12523
+ */
12524
+ frameId: number().int().nonnegative().optional(),
12525
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12526
+ deviceKey: string().optional()
12499
12527
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12500
12528
  data: _instanceof(Uint8Array),
12501
12529
  width: number().int().positive(),
@@ -12527,8 +12555,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12527
12555
  * - `runtime` — main camera-serving engine (no idle TTL).
12528
12556
  * - `warm-override` — benchmark/test override held in the warm
12529
12557
  * cache; auto-disposed after the idle TTL.
12558
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12559
+ * multi-device, keyed by `deviceKey`) resolved
12560
+ * via `resolveDeviceFactory`. Runs alongside the
12561
+ * `runtime` engine on a DIFFERENT accelerator
12562
+ * (NPU / iGPU / Coral) — this is how the
12563
+ * Engines tab shows all pools running at once.
12530
12564
  */
12531
- kind: _enum(["runtime", "warm-override"]),
12565
+ kind: _enum([
12566
+ "runtime",
12567
+ "warm-override",
12568
+ "device-pool"
12569
+ ]),
12532
12570
  /** Native pid of the underlying Python pool (null when no pool). */
12533
12571
  poolPid: number().nullable(),
12534
12572
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12903,7 +12941,14 @@ var RunnerCameraConfigSchema = object({
12903
12941
  * camera's detect node differs from its source-owner (P2d, gated by the
12904
12942
  * `remoteSourcingNodes` rollout setting).
12905
12943
  */
12906
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12944
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12945
+ /**
12946
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12947
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12948
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12949
+ * this only selects WHICH device pool of that node runs the session.
12950
+ */
12951
+ deviceKey: string().optional()
12907
12952
  });
12908
12953
  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;
12909
12954
  /**
@@ -12924,6 +12969,19 @@ var RunnerLocalLoadSchema = object({
12924
12969
  avgInferenceTimeMs: number(),
12925
12970
  /** Total queue depth across motion + detection queues. */
12926
12971
  queueDepthTotal: number(),
12972
+ /**
12973
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12974
+ * this runner currently has attached cameras on, so the orchestrator's second
12975
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12976
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12977
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12978
+ */
12979
+ devices: array(object({
12980
+ deviceKey: string(),
12981
+ backend: string(),
12982
+ attachedCameras: number(),
12983
+ queueDepthTotal: number()
12984
+ })).default([]),
12927
12985
  /** Hardware capability flags reported by this node. */
12928
12986
  hardware: object({
12929
12987
  hasGpu: boolean(),
@@ -16072,6 +16130,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16072
16130
  return toDeviceSummary(device, this.addonId);
16073
16131
  }
16074
16132
  };
16133
+ 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;
16134
+ new Set(Object.values(DeviceType));
16075
16135
  /**
16076
16136
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16077
16137
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19758,13 +19818,11 @@ var PipelineTemplateSchema = object({
19758
19818
  createdAt: string(),
19759
19819
  updatedAt: string()
19760
19820
  });
19761
- var AgentAddonConfigSchema = object({
19762
- enabled: boolean(),
19821
+ var DeviceStepConfigSchema = object({
19763
19822
  modelId: string().optional(),
19764
- settings: record(string(), unknown()).readonly()
19823
+ settings: record(string(), unknown()).optional()
19765
19824
  });
19766
19825
  var AgentPipelineSettingsSchema = object({
19767
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19768
19826
  maxCameras: number().int().nonnegative().nullable().default(null),
19769
19827
  /** Per-node detection weight (relative share for the quota balancer). */
19770
19828
  detectWeight: number().positive().optional(),
@@ -19788,7 +19846,22 @@ var AgentPipelineSettingsSchema = object({
19788
19846
  * it already uses to reach the hub). Set this only when the auto-detected
19789
19847
  * address is wrong (multi-homed host, NAT, custom interface).
19790
19848
  */
19791
- reachableHost: string().optional()
19849
+ reachableHost: string().optional(),
19850
+ /**
19851
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19852
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19853
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19854
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19855
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19856
+ * the default model/settings for every camera landing on that accelerator;
19857
+ * a stepId absent ⇒ the step uses that device's format default.
19858
+ */
19859
+ inferenceDevices: record(string(), object({
19860
+ enabled: boolean(),
19861
+ weight: number().positive().optional(),
19862
+ maxSessions: number().int().positive().optional(),
19863
+ steps: record(string(), DeviceStepConfigSchema).optional()
19864
+ })).optional()
19792
19865
  });
19793
19866
  var CameraPipelineForAgentSchema = object({
19794
19867
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19798,14 +19871,13 @@ var CameraPipelineForAgentSchema = object({
19798
19871
  }).nullable()
19799
19872
  });
19800
19873
  var CameraStepOverridePatchSchema = object({
19801
- enabled: boolean().optional(),
19802
19874
  modelId: string().optional(),
19803
19875
  settings: record(string(), unknown()).readonly().optional()
19804
19876
  });
19805
19877
  var CameraPipelineSettingsSchema = object({
19806
19878
  pinnedAgentNodeId: string().optional(),
19807
19879
  stepToggles: record(string(), boolean()).optional(),
19808
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19880
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19809
19881
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19810
19882
  });
19811
19883
  /**
@@ -20019,6 +20091,44 @@ var CameraStatusSchema = object({
20019
20091
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20020
20092
  fetchedAt: number()
20021
20093
  });
20094
+ var NodeInferenceDeviceSchema = object({
20095
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20096
+ key: string(),
20097
+ backend: string(),
20098
+ device: string(),
20099
+ format: _enum(MODEL_FORMATS),
20100
+ /** Whether the node's live probe reports the device as usable right now. */
20101
+ available: boolean(),
20102
+ /**
20103
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20104
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20105
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20106
+ * not a balanced target). An explicit stored value always wins; a stored-only
20107
+ * (unavailable) key keeps its stored value.
20108
+ */
20109
+ enabled: boolean(),
20110
+ /** Relative balancer weight for the enabled device (default 1). */
20111
+ weight: number(),
20112
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20113
+ maxSessions: number().nullable(),
20114
+ /** Object-detection model the executor defaults to for this deviceKey. */
20115
+ defaultModelId: string(),
20116
+ /**
20117
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20118
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20119
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20120
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20121
+ * available per format; this is the stored selection that becomes the
20122
+ * default for EVERY camera landing on this accelerator.
20123
+ */
20124
+ steps: record(string(), DeviceStepConfigSchema).optional()
20125
+ });
20126
+ var NodeInferenceDevicesSchema = object({
20127
+ nodeId: string(),
20128
+ /** False when the node's platform-probe was unreachable (no live device set). */
20129
+ reachable: boolean(),
20130
+ devices: array(NodeInferenceDeviceSchema).readonly()
20131
+ });
20022
20132
  method(object({
20023
20133
  deviceId: number(),
20024
20134
  agentNodeId: string()
@@ -20028,7 +20138,13 @@ method(object({
20028
20138
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20029
20139
  kind: "mutation",
20030
20140
  auth: "admin"
20031
- }), method(_void(), object({ migrated: number() }), {
20141
+ }), method(object({
20142
+ deviceId: number(),
20143
+ deviceKey: string()
20144
+ }), object({ success: literal(true) }), {
20145
+ kind: "mutation",
20146
+ auth: "admin"
20147
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20032
20148
  kind: "mutation",
20033
20149
  auth: "admin"
20034
20150
  }), 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({
@@ -20062,13 +20178,7 @@ method(object({
20062
20178
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20063
20179
  nodeId: string(),
20064
20180
  settings: AgentPipelineSettingsSchema
20065
- })).readonly()), method(object({
20066
- agentNodeId: string(),
20067
- defaults: record(string(), AgentAddonConfigSchema)
20068
- }), object({ success: literal(true) }), {
20069
- kind: "mutation",
20070
- auth: "admin"
20071
- }), method(object({ agentNodeId: string() }), object({
20181
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20072
20182
  success: boolean(),
20073
20183
  removed: boolean()
20074
20184
  }), {
@@ -20100,7 +20210,18 @@ method(object({
20100
20210
  }), object({ success: literal(true) }), {
20101
20211
  kind: "mutation",
20102
20212
  auth: "admin"
20103
- }), method(object({ agentNodeId: string() }), object({
20213
+ }), method(object({
20214
+ agentNodeId: string(),
20215
+ inferenceDevices: record(string(), object({
20216
+ enabled: boolean(),
20217
+ weight: number().positive().optional(),
20218
+ maxSessions: number().int().positive().optional(),
20219
+ steps: record(string(), DeviceStepConfigSchema).optional()
20220
+ }))
20221
+ }), object({ success: literal(true) }), {
20222
+ kind: "mutation",
20223
+ auth: "admin"
20224
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20104
20225
  success: literal(true),
20105
20226
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20106
20227
  effectiveModelId: string().nullable(),
@@ -20116,9 +20237,10 @@ method(object({
20116
20237
  }), object({ success: literal(true) }), {
20117
20238
  kind: "mutation",
20118
20239
  auth: "admin"
20119
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20240
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20120
20241
  deviceId: number(),
20121
20242
  agentNodeId: string(),
20243
+ deviceKey: string(),
20122
20244
  addonId: string(),
20123
20245
  patch: CameraStepOverridePatchSchema.nullable()
20124
20246
  }), object({ success: literal(true) }), {
@@ -20155,14 +20277,13 @@ method(object({
20155
20277
  });
20156
20278
  /**
20157
20279
  * server-management — per-NODE singleton capability for a node's ROOT
20158
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20159
- * agents).
20280
+ * package lifecycle (runtime-updatable node packages).
20160
20281
  *
20161
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20162
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20163
- * version describes the node. Updates install into
20164
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20165
- * starter (probation boot + auto-rollback to N-1).
20282
+ * Every node role runs the SAME root package (`@camstack/server`), which
20283
+ * carries the whole software stack in its npm dep tree, so ONE version
20284
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20285
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20286
+ * no auto-rollback).
20166
20287
  *
20167
20288
  * Providers:
20168
20289
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20270,7 +20391,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20270
20391
  /** Explicit target version; omitted = latest from the registry. */
20271
20392
  version: string().optional() }), ServerUpdateActionResultSchema, {
20272
20393
  kind: "mutation",
20273
- auth: "admin"
20394
+ auth: "admin",
20395
+ timeoutMs: 16 * 6e4
20274
20396
  }), method(_void(), ServerUpdateActionResultSchema, {
20275
20397
  kind: "mutation",
20276
20398
  auth: "admin"
@@ -21314,22 +21436,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21314
21436
  var RestartAddonResultSchema = unknown();
21315
21437
  var InstallPackageResultSchema = unknown();
21316
21438
  var ReloadPackagesResultSchema = unknown();
21317
- /**
21318
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21319
- * server restarts so the admin UI can react to the `restartingAt`
21320
- * timestamp (shows reconnect overlay). The transition from
21321
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21322
- * `system.restart-completed` event after the new process boots.
21323
- *
21324
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21325
- */
21326
- var UpdateFrameworkPackageResultSchema = object({
21327
- packageName: string(),
21328
- fromVersion: string(),
21329
- toVersion: string(),
21330
- /** Ms-epoch the server scheduled its self-restart. */
21331
- restartingAt: number()
21332
- });
21333
21439
  var BulkUpdateItemStatusSchema = _enum([
21334
21440
  "queued",
21335
21441
  "updating",
@@ -21457,13 +21563,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21457
21563
  }), object({ success: literal(true) }), {
21458
21564
  kind: "mutation",
21459
21565
  auth: "admin"
21460
- }), method(object({
21461
- packageName: string().min(1),
21462
- version: string().optional(),
21463
- deferRestart: boolean().optional()
21464
- }), UpdateFrameworkPackageResultSchema, {
21465
- kind: "mutation",
21466
- auth: "admin"
21467
21566
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21468
21567
  kind: "mutation",
21469
21568
  auth: "admin"
@@ -22346,10 +22445,10 @@ var TopologyCategorySchema = object({
22346
22445
  addons: array(TopologyCategoryAddonSchema).readonly()
22347
22446
  });
22348
22447
  /**
22349
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22350
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22351
- * version visibility for the Server management surface. Nullable: offline
22352
- * rows and pre-phase-2 nodes report none.
22448
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22449
+ * root package for every node role) as reported by its `registerNode`
22450
+ * manifest — version visibility for the Server management surface. Nullable:
22451
+ * offline rows and nodes that never reported one.
22353
22452
  */
22354
22453
  var TopologyRootPackageSchema = object({
22355
22454
  name: string(),
@@ -22737,17 +22836,28 @@ var PlatformScoreSchema = object({
22737
22836
  format: _enum([
22738
22837
  "onnx",
22739
22838
  "coreml",
22740
- "openvino"
22839
+ "openvino",
22840
+ "tflite"
22741
22841
  ]),
22742
22842
  score: number(),
22743
22843
  reason: string(),
22744
22844
  available: boolean()
22745
22845
  });
22846
+ var InferenceDeviceDescriptorSchema = object({
22847
+ key: string(),
22848
+ backend: string(),
22849
+ device: string(),
22850
+ format: ModelFormatSchema,
22851
+ runtime: literal("python"),
22852
+ score: number(),
22853
+ available: boolean()
22854
+ });
22746
22855
  var PlatformCapabilitiesSchema = object({
22747
22856
  hardware: HardwareInfoSchema,
22748
22857
  scores: array(PlatformScoreSchema).readonly(),
22749
22858
  bestScore: PlatformScoreSchema,
22750
- pythonPath: string().nullable()
22859
+ pythonPath: string().nullable(),
22860
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22751
22861
  });
22752
22862
  var ModelRequirementSchema = object({
22753
22863
  modelId: string(),
@@ -23626,12 +23736,6 @@ Object.freeze({
23626
23736
  addonId: null,
23627
23737
  access: "delete"
23628
23738
  },
23629
- "addons.updateFrameworkPackage": {
23630
- capName: "addons",
23631
- capScope: "system",
23632
- addonId: null,
23633
- access: "create"
23634
- },
23635
23739
  "addons.updatePackage": {
23636
23740
  capName: "addons",
23637
23741
  capScope: "system",
@@ -26404,12 +26508,6 @@ Object.freeze({
26404
26508
  addonId: null,
26405
26509
  access: "view"
26406
26510
  },
26407
- "pipelineExecutor.reprobeEngine": {
26408
- capName: "pipeline-executor",
26409
- capScope: "system",
26410
- addonId: null,
26411
- access: "create"
26412
- },
26413
26511
  "pipelineExecutor.runAudioTest": {
26414
26512
  capName: "pipeline-executor",
26415
26513
  capScope: "system",
@@ -26560,6 +26658,12 @@ Object.freeze({
26560
26658
  addonId: null,
26561
26659
  access: "view"
26562
26660
  },
26661
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26662
+ capName: "pipeline-orchestrator",
26663
+ capScope: "system",
26664
+ addonId: null,
26665
+ access: "view"
26666
+ },
26563
26667
  "pipelineOrchestrator.getPipelineAssignment": {
26564
26668
  capName: "pipeline-orchestrator",
26565
26669
  capScope: "system",
@@ -26572,6 +26676,12 @@ Object.freeze({
26572
26676
  addonId: null,
26573
26677
  access: "view"
26574
26678
  },
26679
+ "pipelineOrchestrator.getPipelineDevicePin": {
26680
+ capName: "pipeline-orchestrator",
26681
+ capScope: "system",
26682
+ addonId: null,
26683
+ access: "view"
26684
+ },
26575
26685
  "pipelineOrchestrator.listAgentSettings": {
26576
26686
  capName: "pipeline-orchestrator",
26577
26687
  capScope: "system",
@@ -26614,19 +26724,19 @@ Object.freeze({
26614
26724
  addonId: null,
26615
26725
  access: "create"
26616
26726
  },
26617
- "pipelineOrchestrator.setAgentAddonDefaults": {
26727
+ "pipelineOrchestrator.setAgentCapabilities": {
26618
26728
  capName: "pipeline-orchestrator",
26619
26729
  capScope: "system",
26620
26730
  addonId: null,
26621
26731
  access: "create"
26622
26732
  },
26623
- "pipelineOrchestrator.setAgentCapabilities": {
26733
+ "pipelineOrchestrator.setAgentDetectWeight": {
26624
26734
  capName: "pipeline-orchestrator",
26625
26735
  capScope: "system",
26626
26736
  addonId: null,
26627
26737
  access: "create"
26628
26738
  },
26629
- "pipelineOrchestrator.setAgentDetectWeight": {
26739
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26630
26740
  capName: "pipeline-orchestrator",
26631
26741
  capScope: "system",
26632
26742
  addonId: null,
@@ -26668,6 +26778,12 @@ Object.freeze({
26668
26778
  addonId: null,
26669
26779
  access: "create"
26670
26780
  },
26781
+ "pipelineOrchestrator.setPipelineDevicePin": {
26782
+ capName: "pipeline-orchestrator",
26783
+ capScope: "system",
26784
+ addonId: null,
26785
+ access: "create"
26786
+ },
26671
26787
  "pipelineOrchestrator.unassignAudio": {
26672
26788
  capName: "pipeline-orchestrator",
26673
26789
  capScope: "system",
@@ -28220,32 +28336,6 @@ Object.freeze({
28220
28336
  "network-access": "ingress",
28221
28337
  "smtp-provider": "email"
28222
28338
  });
28223
- var frameworkSwapPackageSchema = object({
28224
- name: string(),
28225
- stagedPath: string(),
28226
- backupPath: string(),
28227
- toVersion: string(),
28228
- fromVersion: string().nullable()
28229
- });
28230
- object({
28231
- jobId: string(),
28232
- taskId: string(),
28233
- packages: array(frameworkSwapPackageSchema),
28234
- requestedAtMs: number(),
28235
- schemaVersion: literal(1)
28236
- });
28237
- object({
28238
- jobId: string(),
28239
- taskId: string(),
28240
- backups: array(object({
28241
- name: string(),
28242
- backupPath: string(),
28243
- livePath: string()
28244
- })),
28245
- appliedAtMs: number(),
28246
- bootAttempts: number(),
28247
- schemaVersion: literal(1)
28248
- });
28249
28339
  //#endregion
28250
28340
  //#region src/config.ts
28251
28341
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-dreame",
3
- "version": "0.1.34",
3
+ "version": "0.2.0",
4
4
  "description": "Dreame robot-vacuum / lawn-mower device-provider addon for CamStack — wraps the @apocaliss92/nodedreame Dreamehome cloud client",
5
5
  "keywords": [
6
6
  "camstack",