@camstack/addon-provider-homematic 1.1.27 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +193 -103
  2. package/dist/addon.mjs +193 -103
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -7107,6 +7107,17 @@ var ModelCatalogEntrySchema = object({
7107
7107
  "imagenet",
7108
7108
  "none"
7109
7109
  ]).optional(),
7110
+ /**
7111
+ * The model already applies softmax IN-GRAPH — its raw output is a
7112
+ * probability distribution, not logits. When set, the `softmax`
7113
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7114
+ * probability vector collapses it toward uniform (top-1 score craters far
7115
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7116
+ * the output is raw logits and the postprocessor applies softmax (the normal
7117
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7118
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7119
+ */
7120
+ outputProbabilities: boolean().optional(),
7110
7121
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7111
7122
  /**
7112
7123
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12397,10 +12408,7 @@ var ConfigUISchemaNullableBridge = custom();
12397
12408
  var InferenceCapabilitiesBridge = custom();
12398
12409
  var ModelAvailabilityListBridge = custom();
12399
12410
  var PipelineRunResultBridge = custom();
12400
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12401
- kind: "mutation",
12402
- auth: "admin"
12403
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12411
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12404
12412
  modelId: string(),
12405
12413
  settings: record(string(), unknown()).readonly()
12406
12414
  }))), method(object({ steps: record(string(), object({
@@ -12460,13 +12468,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12460
12468
  * (inputClasses ≠ null) are skipped and served per-track via
12461
12469
  * pipelineRunner.runDetailSubtree (two-plane design).
12462
12470
  */
12463
- plane: _enum(["full", "frame"]).optional()
12471
+ plane: _enum(["full", "frame"]).optional(),
12472
+ /**
12473
+ * Inference-device selector (Phase 2 multi-device). Format
12474
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12475
+ * Omitted ⇒ the runner's default device (current single-engine
12476
+ * behaviour). Selects WHICH device pool of the node runs the call.
12477
+ */
12478
+ deviceKey: string().optional()
12464
12479
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12465
12480
  engine: PipelineEngineChoiceSchema.optional(),
12466
12481
  steps: array(PipelineStepInputSchema).min(1),
12467
12482
  frames: array(FrameInputSchema).min(1).max(255),
12468
12483
  deviceId: number().optional(),
12469
- sessionId: string().optional()
12484
+ sessionId: string().optional(),
12485
+ /**
12486
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12487
+ * the batch to the Python pool's bench preprocess cache
12488
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12489
+ * preprocessed ONCE and every later inference is a pure-inference cache
12490
+ * hit — the sustained-throughput run measures inference, not
12491
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12492
+ * full preprocess every call, correct). Fresh per sustained run;
12493
+ * released via `uncacheFrame`.
12494
+ */
12495
+ frameId: number().int().nonnegative().optional(),
12496
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12497
+ deviceKey: string().optional()
12470
12498
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12471
12499
  data: _instanceof(Uint8Array),
12472
12500
  width: number().int().positive(),
@@ -12498,8 +12526,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12498
12526
  * - `runtime` — main camera-serving engine (no idle TTL).
12499
12527
  * - `warm-override` — benchmark/test override held in the warm
12500
12528
  * cache; auto-disposed after the idle TTL.
12529
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12530
+ * multi-device, keyed by `deviceKey`) resolved
12531
+ * via `resolveDeviceFactory`. Runs alongside the
12532
+ * `runtime` engine on a DIFFERENT accelerator
12533
+ * (NPU / iGPU / Coral) — this is how the
12534
+ * Engines tab shows all pools running at once.
12501
12535
  */
12502
- kind: _enum(["runtime", "warm-override"]),
12536
+ kind: _enum([
12537
+ "runtime",
12538
+ "warm-override",
12539
+ "device-pool"
12540
+ ]),
12503
12541
  /** Native pid of the underlying Python pool (null when no pool). */
12504
12542
  poolPid: number().nullable(),
12505
12543
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12874,7 +12912,14 @@ var RunnerCameraConfigSchema = object({
12874
12912
  * camera's detect node differs from its source-owner (P2d, gated by the
12875
12913
  * `remoteSourcingNodes` rollout setting).
12876
12914
  */
12877
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12915
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12916
+ /**
12917
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12918
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12919
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12920
+ * this only selects WHICH device pool of that node runs the session.
12921
+ */
12922
+ deviceKey: string().optional()
12878
12923
  });
12879
12924
  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;
12880
12925
  /**
@@ -12895,6 +12940,19 @@ var RunnerLocalLoadSchema = object({
12895
12940
  avgInferenceTimeMs: number(),
12896
12941
  /** Total queue depth across motion + detection queues. */
12897
12942
  queueDepthTotal: number(),
12943
+ /**
12944
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12945
+ * this runner currently has attached cameras on, so the orchestrator's second
12946
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12947
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12948
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12949
+ */
12950
+ devices: array(object({
12951
+ deviceKey: string(),
12952
+ backend: string(),
12953
+ attachedCameras: number(),
12954
+ queueDepthTotal: number()
12955
+ })).default([]),
12898
12956
  /** Hardware capability flags reported by this node. */
12899
12957
  hardware: object({
12900
12958
  hasGpu: boolean(),
@@ -16043,6 +16101,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16043
16101
  return toDeviceSummary(device, this.addonId);
16044
16102
  }
16045
16103
  };
16104
+ 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;
16105
+ new Set(Object.values(DeviceType));
16046
16106
  /**
16047
16107
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16048
16108
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19778,13 +19838,11 @@ var PipelineTemplateSchema = object({
19778
19838
  createdAt: string(),
19779
19839
  updatedAt: string()
19780
19840
  });
19781
- var AgentAddonConfigSchema = object({
19782
- enabled: boolean(),
19841
+ var DeviceStepConfigSchema = object({
19783
19842
  modelId: string().optional(),
19784
- settings: record(string(), unknown()).readonly()
19843
+ settings: record(string(), unknown()).optional()
19785
19844
  });
19786
19845
  var AgentPipelineSettingsSchema = object({
19787
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19788
19846
  maxCameras: number().int().nonnegative().nullable().default(null),
19789
19847
  /** Per-node detection weight (relative share for the quota balancer). */
19790
19848
  detectWeight: number().positive().optional(),
@@ -19808,7 +19866,22 @@ var AgentPipelineSettingsSchema = object({
19808
19866
  * it already uses to reach the hub). Set this only when the auto-detected
19809
19867
  * address is wrong (multi-homed host, NAT, custom interface).
19810
19868
  */
19811
- reachableHost: string().optional()
19869
+ reachableHost: string().optional(),
19870
+ /**
19871
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19872
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19873
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19874
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19875
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19876
+ * the default model/settings for every camera landing on that accelerator;
19877
+ * a stepId absent ⇒ the step uses that device's format default.
19878
+ */
19879
+ inferenceDevices: record(string(), object({
19880
+ enabled: boolean(),
19881
+ weight: number().positive().optional(),
19882
+ maxSessions: number().int().positive().optional(),
19883
+ steps: record(string(), DeviceStepConfigSchema).optional()
19884
+ })).optional()
19812
19885
  });
19813
19886
  var CameraPipelineForAgentSchema = object({
19814
19887
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19818,14 +19891,13 @@ var CameraPipelineForAgentSchema = object({
19818
19891
  }).nullable()
19819
19892
  });
19820
19893
  var CameraStepOverridePatchSchema = object({
19821
- enabled: boolean().optional(),
19822
19894
  modelId: string().optional(),
19823
19895
  settings: record(string(), unknown()).readonly().optional()
19824
19896
  });
19825
19897
  var CameraPipelineSettingsSchema = object({
19826
19898
  pinnedAgentNodeId: string().optional(),
19827
19899
  stepToggles: record(string(), boolean()).optional(),
19828
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19900
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19829
19901
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19830
19902
  });
19831
19903
  /**
@@ -20039,6 +20111,44 @@ var CameraStatusSchema = object({
20039
20111
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20040
20112
  fetchedAt: number()
20041
20113
  });
20114
+ var NodeInferenceDeviceSchema = object({
20115
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20116
+ key: string(),
20117
+ backend: string(),
20118
+ device: string(),
20119
+ format: _enum(MODEL_FORMATS),
20120
+ /** Whether the node's live probe reports the device as usable right now. */
20121
+ available: boolean(),
20122
+ /**
20123
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20124
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20125
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20126
+ * not a balanced target). An explicit stored value always wins; a stored-only
20127
+ * (unavailable) key keeps its stored value.
20128
+ */
20129
+ enabled: boolean(),
20130
+ /** Relative balancer weight for the enabled device (default 1). */
20131
+ weight: number(),
20132
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20133
+ maxSessions: number().nullable(),
20134
+ /** Object-detection model the executor defaults to for this deviceKey. */
20135
+ defaultModelId: string(),
20136
+ /**
20137
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20138
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20139
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20140
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20141
+ * available per format; this is the stored selection that becomes the
20142
+ * default for EVERY camera landing on this accelerator.
20143
+ */
20144
+ steps: record(string(), DeviceStepConfigSchema).optional()
20145
+ });
20146
+ var NodeInferenceDevicesSchema = object({
20147
+ nodeId: string(),
20148
+ /** False when the node's platform-probe was unreachable (no live device set). */
20149
+ reachable: boolean(),
20150
+ devices: array(NodeInferenceDeviceSchema).readonly()
20151
+ });
20042
20152
  method(object({
20043
20153
  deviceId: number(),
20044
20154
  agentNodeId: string()
@@ -20048,7 +20158,13 @@ method(object({
20048
20158
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20049
20159
  kind: "mutation",
20050
20160
  auth: "admin"
20051
- }), method(_void(), object({ migrated: number() }), {
20161
+ }), method(object({
20162
+ deviceId: number(),
20163
+ deviceKey: string()
20164
+ }), object({ success: literal(true) }), {
20165
+ kind: "mutation",
20166
+ auth: "admin"
20167
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20052
20168
  kind: "mutation",
20053
20169
  auth: "admin"
20054
20170
  }), 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({
@@ -20082,13 +20198,7 @@ method(object({
20082
20198
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20083
20199
  nodeId: string(),
20084
20200
  settings: AgentPipelineSettingsSchema
20085
- })).readonly()), method(object({
20086
- agentNodeId: string(),
20087
- defaults: record(string(), AgentAddonConfigSchema)
20088
- }), object({ success: literal(true) }), {
20089
- kind: "mutation",
20090
- auth: "admin"
20091
- }), method(object({ agentNodeId: string() }), object({
20201
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20092
20202
  success: boolean(),
20093
20203
  removed: boolean()
20094
20204
  }), {
@@ -20120,7 +20230,18 @@ method(object({
20120
20230
  }), object({ success: literal(true) }), {
20121
20231
  kind: "mutation",
20122
20232
  auth: "admin"
20123
- }), method(object({ agentNodeId: string() }), object({
20233
+ }), method(object({
20234
+ agentNodeId: string(),
20235
+ inferenceDevices: record(string(), object({
20236
+ enabled: boolean(),
20237
+ weight: number().positive().optional(),
20238
+ maxSessions: number().int().positive().optional(),
20239
+ steps: record(string(), DeviceStepConfigSchema).optional()
20240
+ }))
20241
+ }), object({ success: literal(true) }), {
20242
+ kind: "mutation",
20243
+ auth: "admin"
20244
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20124
20245
  success: literal(true),
20125
20246
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20126
20247
  effectiveModelId: string().nullable(),
@@ -20136,9 +20257,10 @@ method(object({
20136
20257
  }), object({ success: literal(true) }), {
20137
20258
  kind: "mutation",
20138
20259
  auth: "admin"
20139
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20260
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20140
20261
  deviceId: number(),
20141
20262
  agentNodeId: string(),
20263
+ deviceKey: string(),
20142
20264
  addonId: string(),
20143
20265
  patch: CameraStepOverridePatchSchema.nullable()
20144
20266
  }), object({ success: literal(true) }), {
@@ -20175,14 +20297,13 @@ method(object({
20175
20297
  });
20176
20298
  /**
20177
20299
  * server-management — per-NODE singleton capability for a node's ROOT
20178
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20179
- * agents).
20300
+ * package lifecycle (runtime-updatable node packages).
20180
20301
  *
20181
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20182
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20183
- * version describes the node. Updates install into
20184
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20185
- * starter (probation boot + auto-rollback to N-1).
20302
+ * Every node role runs the SAME root package (`@camstack/server`), which
20303
+ * carries the whole software stack in its npm dep tree, so ONE version
20304
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20305
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20306
+ * no auto-rollback).
20186
20307
  *
20187
20308
  * Providers:
20188
20309
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20290,7 +20411,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20290
20411
  /** Explicit target version; omitted = latest from the registry. */
20291
20412
  version: string().optional() }), ServerUpdateActionResultSchema, {
20292
20413
  kind: "mutation",
20293
- auth: "admin"
20414
+ auth: "admin",
20415
+ timeoutMs: 16 * 6e4
20294
20416
  }), method(_void(), ServerUpdateActionResultSchema, {
20295
20417
  kind: "mutation",
20296
20418
  auth: "admin"
@@ -21334,22 +21456,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21334
21456
  var RestartAddonResultSchema = unknown();
21335
21457
  var InstallPackageResultSchema = unknown();
21336
21458
  var ReloadPackagesResultSchema = unknown();
21337
- /**
21338
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21339
- * server restarts so the admin UI can react to the `restartingAt`
21340
- * timestamp (shows reconnect overlay). The transition from
21341
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21342
- * `system.restart-completed` event after the new process boots.
21343
- *
21344
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21345
- */
21346
- var UpdateFrameworkPackageResultSchema = object({
21347
- packageName: string(),
21348
- fromVersion: string(),
21349
- toVersion: string(),
21350
- /** Ms-epoch the server scheduled its self-restart. */
21351
- restartingAt: number()
21352
- });
21353
21459
  var BulkUpdateItemStatusSchema = _enum([
21354
21460
  "queued",
21355
21461
  "updating",
@@ -21477,13 +21583,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21477
21583
  }), object({ success: literal(true) }), {
21478
21584
  kind: "mutation",
21479
21585
  auth: "admin"
21480
- }), method(object({
21481
- packageName: string().min(1),
21482
- version: string().optional(),
21483
- deferRestart: boolean().optional()
21484
- }), UpdateFrameworkPackageResultSchema, {
21485
- kind: "mutation",
21486
- auth: "admin"
21487
21586
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21488
21587
  kind: "mutation",
21489
21588
  auth: "admin"
@@ -22349,10 +22448,10 @@ var TopologyCategorySchema = object({
22349
22448
  addons: array(TopologyCategoryAddonSchema).readonly()
22350
22449
  });
22351
22450
  /**
22352
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22353
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22354
- * version visibility for the Server management surface. Nullable: offline
22355
- * rows and pre-phase-2 nodes report none.
22451
+ * The node's runtime-updatable ROOT package (`@camstack/server` — the single
22452
+ * root package for every node role) as reported by its `registerNode`
22453
+ * manifest — version visibility for the Server management surface. Nullable:
22454
+ * offline rows and nodes that never reported one.
22356
22455
  */
22357
22456
  var TopologyRootPackageSchema = object({
22358
22457
  name: string(),
@@ -22740,17 +22839,28 @@ var PlatformScoreSchema = object({
22740
22839
  format: _enum([
22741
22840
  "onnx",
22742
22841
  "coreml",
22743
- "openvino"
22842
+ "openvino",
22843
+ "tflite"
22744
22844
  ]),
22745
22845
  score: number(),
22746
22846
  reason: string(),
22747
22847
  available: boolean()
22748
22848
  });
22849
+ var InferenceDeviceDescriptorSchema = object({
22850
+ key: string(),
22851
+ backend: string(),
22852
+ device: string(),
22853
+ format: ModelFormatSchema,
22854
+ runtime: literal("python"),
22855
+ score: number(),
22856
+ available: boolean()
22857
+ });
22749
22858
  var PlatformCapabilitiesSchema = object({
22750
22859
  hardware: HardwareInfoSchema,
22751
22860
  scores: array(PlatformScoreSchema).readonly(),
22752
22861
  bestScore: PlatformScoreSchema,
22753
- pythonPath: string().nullable()
22862
+ pythonPath: string().nullable(),
22863
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22754
22864
  });
22755
22865
  var ModelRequirementSchema = object({
22756
22866
  modelId: string(),
@@ -23629,12 +23739,6 @@ Object.freeze({
23629
23739
  addonId: null,
23630
23740
  access: "delete"
23631
23741
  },
23632
- "addons.updateFrameworkPackage": {
23633
- capName: "addons",
23634
- capScope: "system",
23635
- addonId: null,
23636
- access: "create"
23637
- },
23638
23742
  "addons.updatePackage": {
23639
23743
  capName: "addons",
23640
23744
  capScope: "system",
@@ -26407,12 +26511,6 @@ Object.freeze({
26407
26511
  addonId: null,
26408
26512
  access: "view"
26409
26513
  },
26410
- "pipelineExecutor.reprobeEngine": {
26411
- capName: "pipeline-executor",
26412
- capScope: "system",
26413
- addonId: null,
26414
- access: "create"
26415
- },
26416
26514
  "pipelineExecutor.runAudioTest": {
26417
26515
  capName: "pipeline-executor",
26418
26516
  capScope: "system",
@@ -26563,6 +26661,12 @@ Object.freeze({
26563
26661
  addonId: null,
26564
26662
  access: "view"
26565
26663
  },
26664
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26665
+ capName: "pipeline-orchestrator",
26666
+ capScope: "system",
26667
+ addonId: null,
26668
+ access: "view"
26669
+ },
26566
26670
  "pipelineOrchestrator.getPipelineAssignment": {
26567
26671
  capName: "pipeline-orchestrator",
26568
26672
  capScope: "system",
@@ -26575,6 +26679,12 @@ Object.freeze({
26575
26679
  addonId: null,
26576
26680
  access: "view"
26577
26681
  },
26682
+ "pipelineOrchestrator.getPipelineDevicePin": {
26683
+ capName: "pipeline-orchestrator",
26684
+ capScope: "system",
26685
+ addonId: null,
26686
+ access: "view"
26687
+ },
26578
26688
  "pipelineOrchestrator.listAgentSettings": {
26579
26689
  capName: "pipeline-orchestrator",
26580
26690
  capScope: "system",
@@ -26617,19 +26727,19 @@ Object.freeze({
26617
26727
  addonId: null,
26618
26728
  access: "create"
26619
26729
  },
26620
- "pipelineOrchestrator.setAgentAddonDefaults": {
26730
+ "pipelineOrchestrator.setAgentCapabilities": {
26621
26731
  capName: "pipeline-orchestrator",
26622
26732
  capScope: "system",
26623
26733
  addonId: null,
26624
26734
  access: "create"
26625
26735
  },
26626
- "pipelineOrchestrator.setAgentCapabilities": {
26736
+ "pipelineOrchestrator.setAgentDetectWeight": {
26627
26737
  capName: "pipeline-orchestrator",
26628
26738
  capScope: "system",
26629
26739
  addonId: null,
26630
26740
  access: "create"
26631
26741
  },
26632
- "pipelineOrchestrator.setAgentDetectWeight": {
26742
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26633
26743
  capName: "pipeline-orchestrator",
26634
26744
  capScope: "system",
26635
26745
  addonId: null,
@@ -26671,6 +26781,12 @@ Object.freeze({
26671
26781
  addonId: null,
26672
26782
  access: "create"
26673
26783
  },
26784
+ "pipelineOrchestrator.setPipelineDevicePin": {
26785
+ capName: "pipeline-orchestrator",
26786
+ capScope: "system",
26787
+ addonId: null,
26788
+ access: "create"
26789
+ },
26674
26790
  "pipelineOrchestrator.unassignAudio": {
26675
26791
  capName: "pipeline-orchestrator",
26676
26792
  capScope: "system",
@@ -28223,32 +28339,6 @@ Object.freeze({
28223
28339
  "network-access": "ingress",
28224
28340
  "smtp-provider": "email"
28225
28341
  });
28226
- var frameworkSwapPackageSchema = object({
28227
- name: string(),
28228
- stagedPath: string(),
28229
- backupPath: string(),
28230
- toVersion: string(),
28231
- fromVersion: string().nullable()
28232
- });
28233
- object({
28234
- jobId: string(),
28235
- taskId: string(),
28236
- packages: array(frameworkSwapPackageSchema),
28237
- requestedAtMs: number(),
28238
- schemaVersion: literal(1)
28239
- });
28240
- object({
28241
- jobId: string(),
28242
- taskId: string(),
28243
- backups: array(object({
28244
- name: string(),
28245
- backupPath: string(),
28246
- livePath: string()
28247
- })),
28248
- appliedAtMs: number(),
28249
- bootAttempts: number(),
28250
- schemaVersion: literal(1)
28251
- });
28252
28342
  /**
28253
28343
  * Pure fuzzy matcher for adoption location import. Normalized
28254
28344
  * case-insensitive Levenshtein similarity, used to reuse an existing
package/dist/addon.mjs CHANGED
@@ -7108,6 +7108,17 @@ var ModelCatalogEntrySchema = object({
7108
7108
  "imagenet",
7109
7109
  "none"
7110
7110
  ]).optional(),
7111
+ /**
7112
+ * The model already applies softmax IN-GRAPH — its raw output is a
7113
+ * probability distribution, not logits. When set, the `softmax`
7114
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7115
+ * probability vector collapses it toward uniform (top-1 score craters far
7116
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7117
+ * the output is raw logits and the postprocessor applies softmax (the normal
7118
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7119
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7120
+ */
7121
+ outputProbabilities: boolean().optional(),
7111
7122
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7112
7123
  /**
7113
7124
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12398,10 +12409,7 @@ var ConfigUISchemaNullableBridge = custom();
12398
12409
  var InferenceCapabilitiesBridge = custom();
12399
12410
  var ModelAvailabilityListBridge = custom();
12400
12411
  var PipelineRunResultBridge = custom();
12401
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12402
- kind: "mutation",
12403
- auth: "admin"
12404
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12412
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12405
12413
  modelId: string(),
12406
12414
  settings: record(string(), unknown()).readonly()
12407
12415
  }))), method(object({ steps: record(string(), object({
@@ -12461,13 +12469,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12461
12469
  * (inputClasses ≠ null) are skipped and served per-track via
12462
12470
  * pipelineRunner.runDetailSubtree (two-plane design).
12463
12471
  */
12464
- plane: _enum(["full", "frame"]).optional()
12472
+ plane: _enum(["full", "frame"]).optional(),
12473
+ /**
12474
+ * Inference-device selector (Phase 2 multi-device). Format
12475
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12476
+ * Omitted ⇒ the runner's default device (current single-engine
12477
+ * behaviour). Selects WHICH device pool of the node runs the call.
12478
+ */
12479
+ deviceKey: string().optional()
12465
12480
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12466
12481
  engine: PipelineEngineChoiceSchema.optional(),
12467
12482
  steps: array(PipelineStepInputSchema).min(1),
12468
12483
  frames: array(FrameInputSchema).min(1).max(255),
12469
12484
  deviceId: number().optional(),
12470
- sessionId: string().optional()
12485
+ sessionId: string().optional(),
12486
+ /**
12487
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12488
+ * the batch to the Python pool's bench preprocess cache
12489
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12490
+ * preprocessed ONCE and every later inference is a pure-inference cache
12491
+ * hit — the sustained-throughput run measures inference, not
12492
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12493
+ * full preprocess every call, correct). Fresh per sustained run;
12494
+ * released via `uncacheFrame`.
12495
+ */
12496
+ frameId: number().int().nonnegative().optional(),
12497
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12498
+ deviceKey: string().optional()
12471
12499
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12472
12500
  data: _instanceof(Uint8Array),
12473
12501
  width: number().int().positive(),
@@ -12499,8 +12527,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12499
12527
  * - `runtime` — main camera-serving engine (no idle TTL).
12500
12528
  * - `warm-override` — benchmark/test override held in the warm
12501
12529
  * cache; auto-disposed after the idle TTL.
12530
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12531
+ * multi-device, keyed by `deviceKey`) resolved
12532
+ * via `resolveDeviceFactory`. Runs alongside the
12533
+ * `runtime` engine on a DIFFERENT accelerator
12534
+ * (NPU / iGPU / Coral) — this is how the
12535
+ * Engines tab shows all pools running at once.
12502
12536
  */
12503
- kind: _enum(["runtime", "warm-override"]),
12537
+ kind: _enum([
12538
+ "runtime",
12539
+ "warm-override",
12540
+ "device-pool"
12541
+ ]),
12504
12542
  /** Native pid of the underlying Python pool (null when no pool). */
12505
12543
  poolPid: number().nullable(),
12506
12544
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12875,7 +12913,14 @@ var RunnerCameraConfigSchema = object({
12875
12913
  * camera's detect node differs from its source-owner (P2d, gated by the
12876
12914
  * `remoteSourcingNodes` rollout setting).
12877
12915
  */
12878
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12916
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12917
+ /**
12918
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12919
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12920
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12921
+ * this only selects WHICH device pool of that node runs the session.
12922
+ */
12923
+ deviceKey: string().optional()
12879
12924
  });
12880
12925
  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;
12881
12926
  /**
@@ -12896,6 +12941,19 @@ var RunnerLocalLoadSchema = object({
12896
12941
  avgInferenceTimeMs: number(),
12897
12942
  /** Total queue depth across motion + detection queues. */
12898
12943
  queueDepthTotal: number(),
12944
+ /**
12945
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12946
+ * this runner currently has attached cameras on, so the orchestrator's second
12947
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12948
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12949
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12950
+ */
12951
+ devices: array(object({
12952
+ deviceKey: string(),
12953
+ backend: string(),
12954
+ attachedCameras: number(),
12955
+ queueDepthTotal: number()
12956
+ })).default([]),
12899
12957
  /** Hardware capability flags reported by this node. */
12900
12958
  hardware: object({
12901
12959
  hasGpu: boolean(),
@@ -16044,6 +16102,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16044
16102
  return toDeviceSummary(device, this.addonId);
16045
16103
  }
16046
16104
  };
16105
+ 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;
16106
+ new Set(Object.values(DeviceType));
16047
16107
  /**
16048
16108
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16049
16109
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19779,13 +19839,11 @@ var PipelineTemplateSchema = object({
19779
19839
  createdAt: string(),
19780
19840
  updatedAt: string()
19781
19841
  });
19782
- var AgentAddonConfigSchema = object({
19783
- enabled: boolean(),
19842
+ var DeviceStepConfigSchema = object({
19784
19843
  modelId: string().optional(),
19785
- settings: record(string(), unknown()).readonly()
19844
+ settings: record(string(), unknown()).optional()
19786
19845
  });
19787
19846
  var AgentPipelineSettingsSchema = object({
19788
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19789
19847
  maxCameras: number().int().nonnegative().nullable().default(null),
19790
19848
  /** Per-node detection weight (relative share for the quota balancer). */
19791
19849
  detectWeight: number().positive().optional(),
@@ -19809,7 +19867,22 @@ var AgentPipelineSettingsSchema = object({
19809
19867
  * it already uses to reach the hub). Set this only when the auto-detected
19810
19868
  * address is wrong (multi-homed host, NAT, custom interface).
19811
19869
  */
19812
- reachableHost: string().optional()
19870
+ reachableHost: string().optional(),
19871
+ /**
19872
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19873
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19874
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19875
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19876
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19877
+ * the default model/settings for every camera landing on that accelerator;
19878
+ * a stepId absent ⇒ the step uses that device's format default.
19879
+ */
19880
+ inferenceDevices: record(string(), object({
19881
+ enabled: boolean(),
19882
+ weight: number().positive().optional(),
19883
+ maxSessions: number().int().positive().optional(),
19884
+ steps: record(string(), DeviceStepConfigSchema).optional()
19885
+ })).optional()
19813
19886
  });
19814
19887
  var CameraPipelineForAgentSchema = object({
19815
19888
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19819,14 +19892,13 @@ var CameraPipelineForAgentSchema = object({
19819
19892
  }).nullable()
19820
19893
  });
19821
19894
  var CameraStepOverridePatchSchema = object({
19822
- enabled: boolean().optional(),
19823
19895
  modelId: string().optional(),
19824
19896
  settings: record(string(), unknown()).readonly().optional()
19825
19897
  });
19826
19898
  var CameraPipelineSettingsSchema = object({
19827
19899
  pinnedAgentNodeId: string().optional(),
19828
19900
  stepToggles: record(string(), boolean()).optional(),
19829
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19901
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19830
19902
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19831
19903
  });
19832
19904
  /**
@@ -20040,6 +20112,44 @@ var CameraStatusSchema = object({
20040
20112
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20041
20113
  fetchedAt: number()
20042
20114
  });
20115
+ var NodeInferenceDeviceSchema = object({
20116
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20117
+ key: string(),
20118
+ backend: string(),
20119
+ device: string(),
20120
+ format: _enum(MODEL_FORMATS),
20121
+ /** Whether the node's live probe reports the device as usable right now. */
20122
+ available: boolean(),
20123
+ /**
20124
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20125
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20126
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20127
+ * not a balanced target). An explicit stored value always wins; a stored-only
20128
+ * (unavailable) key keeps its stored value.
20129
+ */
20130
+ enabled: boolean(),
20131
+ /** Relative balancer weight for the enabled device (default 1). */
20132
+ weight: number(),
20133
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20134
+ maxSessions: number().nullable(),
20135
+ /** Object-detection model the executor defaults to for this deviceKey. */
20136
+ defaultModelId: string(),
20137
+ /**
20138
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20139
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20140
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20141
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20142
+ * available per format; this is the stored selection that becomes the
20143
+ * default for EVERY camera landing on this accelerator.
20144
+ */
20145
+ steps: record(string(), DeviceStepConfigSchema).optional()
20146
+ });
20147
+ var NodeInferenceDevicesSchema = object({
20148
+ nodeId: string(),
20149
+ /** False when the node's platform-probe was unreachable (no live device set). */
20150
+ reachable: boolean(),
20151
+ devices: array(NodeInferenceDeviceSchema).readonly()
20152
+ });
20043
20153
  method(object({
20044
20154
  deviceId: number(),
20045
20155
  agentNodeId: string()
@@ -20049,7 +20159,13 @@ method(object({
20049
20159
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20050
20160
  kind: "mutation",
20051
20161
  auth: "admin"
20052
- }), method(_void(), object({ migrated: number() }), {
20162
+ }), method(object({
20163
+ deviceId: number(),
20164
+ deviceKey: string()
20165
+ }), object({ success: literal(true) }), {
20166
+ kind: "mutation",
20167
+ auth: "admin"
20168
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20053
20169
  kind: "mutation",
20054
20170
  auth: "admin"
20055
20171
  }), 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({
@@ -20083,13 +20199,7 @@ method(object({
20083
20199
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20084
20200
  nodeId: string(),
20085
20201
  settings: AgentPipelineSettingsSchema
20086
- })).readonly()), method(object({
20087
- agentNodeId: string(),
20088
- defaults: record(string(), AgentAddonConfigSchema)
20089
- }), object({ success: literal(true) }), {
20090
- kind: "mutation",
20091
- auth: "admin"
20092
- }), method(object({ agentNodeId: string() }), object({
20202
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20093
20203
  success: boolean(),
20094
20204
  removed: boolean()
20095
20205
  }), {
@@ -20121,7 +20231,18 @@ method(object({
20121
20231
  }), object({ success: literal(true) }), {
20122
20232
  kind: "mutation",
20123
20233
  auth: "admin"
20124
- }), method(object({ agentNodeId: string() }), object({
20234
+ }), method(object({
20235
+ agentNodeId: string(),
20236
+ inferenceDevices: record(string(), object({
20237
+ enabled: boolean(),
20238
+ weight: number().positive().optional(),
20239
+ maxSessions: number().int().positive().optional(),
20240
+ steps: record(string(), DeviceStepConfigSchema).optional()
20241
+ }))
20242
+ }), object({ success: literal(true) }), {
20243
+ kind: "mutation",
20244
+ auth: "admin"
20245
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20125
20246
  success: literal(true),
20126
20247
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20127
20248
  effectiveModelId: string().nullable(),
@@ -20137,9 +20258,10 @@ method(object({
20137
20258
  }), object({ success: literal(true) }), {
20138
20259
  kind: "mutation",
20139
20260
  auth: "admin"
20140
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20261
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20141
20262
  deviceId: number(),
20142
20263
  agentNodeId: string(),
20264
+ deviceKey: string(),
20143
20265
  addonId: string(),
20144
20266
  patch: CameraStepOverridePatchSchema.nullable()
20145
20267
  }), object({ success: literal(true) }), {
@@ -20176,14 +20298,13 @@ method(object({
20176
20298
  });
20177
20299
  /**
20178
20300
  * server-management — per-NODE singleton capability for a node's ROOT
20179
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20180
- * agents).
20301
+ * package lifecycle (runtime-updatable node packages).
20181
20302
  *
20182
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20183
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20184
- * version describes the node. Updates install into
20185
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20186
- * starter (probation boot + auto-rollback to N-1).
20303
+ * Every node role runs the SAME root package (`@camstack/server`), which
20304
+ * carries the whole software stack in its npm dep tree, so ONE version
20305
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20306
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20307
+ * no auto-rollback).
20187
20308
  *
20188
20309
  * Providers:
20189
20310
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20291,7 +20412,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20291
20412
  /** Explicit target version; omitted = latest from the registry. */
20292
20413
  version: string().optional() }), ServerUpdateActionResultSchema, {
20293
20414
  kind: "mutation",
20294
- auth: "admin"
20415
+ auth: "admin",
20416
+ timeoutMs: 16 * 6e4
20295
20417
  }), method(_void(), ServerUpdateActionResultSchema, {
20296
20418
  kind: "mutation",
20297
20419
  auth: "admin"
@@ -21335,22 +21457,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21335
21457
  var RestartAddonResultSchema = unknown();
21336
21458
  var InstallPackageResultSchema = unknown();
21337
21459
  var ReloadPackagesResultSchema = unknown();
21338
- /**
21339
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21340
- * server restarts so the admin UI can react to the `restartingAt`
21341
- * timestamp (shows reconnect overlay). The transition from
21342
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21343
- * `system.restart-completed` event after the new process boots.
21344
- *
21345
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21346
- */
21347
- var UpdateFrameworkPackageResultSchema = object({
21348
- packageName: string(),
21349
- fromVersion: string(),
21350
- toVersion: string(),
21351
- /** Ms-epoch the server scheduled its self-restart. */
21352
- restartingAt: number()
21353
- });
21354
21460
  var BulkUpdateItemStatusSchema = _enum([
21355
21461
  "queued",
21356
21462
  "updating",
@@ -21478,13 +21584,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21478
21584
  }), object({ success: literal(true) }), {
21479
21585
  kind: "mutation",
21480
21586
  auth: "admin"
21481
- }), method(object({
21482
- packageName: string().min(1),
21483
- version: string().optional(),
21484
- deferRestart: boolean().optional()
21485
- }), UpdateFrameworkPackageResultSchema, {
21486
- kind: "mutation",
21487
- auth: "admin"
21488
21587
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21489
21588
  kind: "mutation",
21490
21589
  auth: "admin"
@@ -22350,10 +22449,10 @@ var TopologyCategorySchema = object({
22350
22449
  addons: array(TopologyCategoryAddonSchema).readonly()
22351
22450
  });
22352
22451
  /**
22353
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22354
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22355
- * version visibility for the Server management surface. Nullable: offline
22356
- * rows and pre-phase-2 nodes report none.
22452
+ * The node's runtime-updatable ROOT package (`@camstack/server` — the single
22453
+ * root package for every node role) as reported by its `registerNode`
22454
+ * manifest — version visibility for the Server management surface. Nullable:
22455
+ * offline rows and nodes that never reported one.
22357
22456
  */
22358
22457
  var TopologyRootPackageSchema = object({
22359
22458
  name: string(),
@@ -22741,17 +22840,28 @@ var PlatformScoreSchema = object({
22741
22840
  format: _enum([
22742
22841
  "onnx",
22743
22842
  "coreml",
22744
- "openvino"
22843
+ "openvino",
22844
+ "tflite"
22745
22845
  ]),
22746
22846
  score: number(),
22747
22847
  reason: string(),
22748
22848
  available: boolean()
22749
22849
  });
22850
+ var InferenceDeviceDescriptorSchema = object({
22851
+ key: string(),
22852
+ backend: string(),
22853
+ device: string(),
22854
+ format: ModelFormatSchema,
22855
+ runtime: literal("python"),
22856
+ score: number(),
22857
+ available: boolean()
22858
+ });
22750
22859
  var PlatformCapabilitiesSchema = object({
22751
22860
  hardware: HardwareInfoSchema,
22752
22861
  scores: array(PlatformScoreSchema).readonly(),
22753
22862
  bestScore: PlatformScoreSchema,
22754
- pythonPath: string().nullable()
22863
+ pythonPath: string().nullable(),
22864
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22755
22865
  });
22756
22866
  var ModelRequirementSchema = object({
22757
22867
  modelId: string(),
@@ -23630,12 +23740,6 @@ Object.freeze({
23630
23740
  addonId: null,
23631
23741
  access: "delete"
23632
23742
  },
23633
- "addons.updateFrameworkPackage": {
23634
- capName: "addons",
23635
- capScope: "system",
23636
- addonId: null,
23637
- access: "create"
23638
- },
23639
23743
  "addons.updatePackage": {
23640
23744
  capName: "addons",
23641
23745
  capScope: "system",
@@ -26408,12 +26512,6 @@ Object.freeze({
26408
26512
  addonId: null,
26409
26513
  access: "view"
26410
26514
  },
26411
- "pipelineExecutor.reprobeEngine": {
26412
- capName: "pipeline-executor",
26413
- capScope: "system",
26414
- addonId: null,
26415
- access: "create"
26416
- },
26417
26515
  "pipelineExecutor.runAudioTest": {
26418
26516
  capName: "pipeline-executor",
26419
26517
  capScope: "system",
@@ -26564,6 +26662,12 @@ Object.freeze({
26564
26662
  addonId: null,
26565
26663
  access: "view"
26566
26664
  },
26665
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26666
+ capName: "pipeline-orchestrator",
26667
+ capScope: "system",
26668
+ addonId: null,
26669
+ access: "view"
26670
+ },
26567
26671
  "pipelineOrchestrator.getPipelineAssignment": {
26568
26672
  capName: "pipeline-orchestrator",
26569
26673
  capScope: "system",
@@ -26576,6 +26680,12 @@ Object.freeze({
26576
26680
  addonId: null,
26577
26681
  access: "view"
26578
26682
  },
26683
+ "pipelineOrchestrator.getPipelineDevicePin": {
26684
+ capName: "pipeline-orchestrator",
26685
+ capScope: "system",
26686
+ addonId: null,
26687
+ access: "view"
26688
+ },
26579
26689
  "pipelineOrchestrator.listAgentSettings": {
26580
26690
  capName: "pipeline-orchestrator",
26581
26691
  capScope: "system",
@@ -26618,19 +26728,19 @@ Object.freeze({
26618
26728
  addonId: null,
26619
26729
  access: "create"
26620
26730
  },
26621
- "pipelineOrchestrator.setAgentAddonDefaults": {
26731
+ "pipelineOrchestrator.setAgentCapabilities": {
26622
26732
  capName: "pipeline-orchestrator",
26623
26733
  capScope: "system",
26624
26734
  addonId: null,
26625
26735
  access: "create"
26626
26736
  },
26627
- "pipelineOrchestrator.setAgentCapabilities": {
26737
+ "pipelineOrchestrator.setAgentDetectWeight": {
26628
26738
  capName: "pipeline-orchestrator",
26629
26739
  capScope: "system",
26630
26740
  addonId: null,
26631
26741
  access: "create"
26632
26742
  },
26633
- "pipelineOrchestrator.setAgentDetectWeight": {
26743
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26634
26744
  capName: "pipeline-orchestrator",
26635
26745
  capScope: "system",
26636
26746
  addonId: null,
@@ -26672,6 +26782,12 @@ Object.freeze({
26672
26782
  addonId: null,
26673
26783
  access: "create"
26674
26784
  },
26785
+ "pipelineOrchestrator.setPipelineDevicePin": {
26786
+ capName: "pipeline-orchestrator",
26787
+ capScope: "system",
26788
+ addonId: null,
26789
+ access: "create"
26790
+ },
26675
26791
  "pipelineOrchestrator.unassignAudio": {
26676
26792
  capName: "pipeline-orchestrator",
26677
26793
  capScope: "system",
@@ -28224,32 +28340,6 @@ Object.freeze({
28224
28340
  "network-access": "ingress",
28225
28341
  "smtp-provider": "email"
28226
28342
  });
28227
- var frameworkSwapPackageSchema = object({
28228
- name: string(),
28229
- stagedPath: string(),
28230
- backupPath: string(),
28231
- toVersion: string(),
28232
- fromVersion: string().nullable()
28233
- });
28234
- object({
28235
- jobId: string(),
28236
- taskId: string(),
28237
- packages: array(frameworkSwapPackageSchema),
28238
- requestedAtMs: number(),
28239
- schemaVersion: literal(1)
28240
- });
28241
- object({
28242
- jobId: string(),
28243
- taskId: string(),
28244
- backups: array(object({
28245
- name: string(),
28246
- backupPath: string(),
28247
- livePath: string()
28248
- })),
28249
- appliedAtMs: number(),
28250
- bootAttempts: number(),
28251
- schemaVersion: literal(1)
28252
- });
28253
28343
  /**
28254
28344
  * Pure fuzzy matcher for adoption location import. Normalized
28255
28345
  * case-insensitive Levenshtein similarity, used to reuse an existing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homematic",
3
- "version": "1.1.27",
3
+ "version": "1.2.0",
4
4
  "description": "Homematic / HomematicIP (CCU3 / RaspberryMatic) device-provider addon for CamStack — wraps the nodehomematic library",
5
5
  "keywords": [
6
6
  "camstack",