@camstack/addon-provider-rademacher 0.1.14 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +193 -103
  2. package/dist/addon.mjs +193 -103
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -8083,6 +8083,17 @@ var ModelCatalogEntrySchema = object({
8083
8083
  "imagenet",
8084
8084
  "none"
8085
8085
  ]).optional(),
8086
+ /**
8087
+ * The model already applies softmax IN-GRAPH — its raw output is a
8088
+ * probability distribution, not logits. When set, the `softmax`
8089
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
8090
+ * probability vector collapses it toward uniform (top-1 score craters far
8091
+ * below its true value, making every confidence gate meaningless). Absent ⇒
8092
+ * the output is raw logits and the postprocessor applies softmax (the normal
8093
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
8094
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
8095
+ */
8096
+ outputProbabilities: boolean().optional(),
8086
8097
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
8087
8098
  /**
8088
8099
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -13373,10 +13384,7 @@ var ConfigUISchemaNullableBridge = custom();
13373
13384
  var InferenceCapabilitiesBridge = custom();
13374
13385
  var ModelAvailabilityListBridge = custom();
13375
13386
  var PipelineRunResultBridge = custom();
13376
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
13377
- kind: "mutation",
13378
- auth: "admin"
13379
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
13387
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
13380
13388
  modelId: string(),
13381
13389
  settings: record(string(), unknown()).readonly()
13382
13390
  }))), method(object({ steps: record(string(), object({
@@ -13436,13 +13444,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
13436
13444
  * (inputClasses ≠ null) are skipped and served per-track via
13437
13445
  * pipelineRunner.runDetailSubtree (two-plane design).
13438
13446
  */
13439
- plane: _enum(["full", "frame"]).optional()
13447
+ plane: _enum(["full", "frame"]).optional(),
13448
+ /**
13449
+ * Inference-device selector (Phase 2 multi-device). Format
13450
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
13451
+ * Omitted ⇒ the runner's default device (current single-engine
13452
+ * behaviour). Selects WHICH device pool of the node runs the call.
13453
+ */
13454
+ deviceKey: string().optional()
13440
13455
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
13441
13456
  engine: PipelineEngineChoiceSchema.optional(),
13442
13457
  steps: array(PipelineStepInputSchema).min(1),
13443
13458
  frames: array(FrameInputSchema).min(1).max(255),
13444
13459
  deviceId: number().optional(),
13445
- sessionId: string().optional()
13460
+ sessionId: string().optional(),
13461
+ /**
13462
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
13463
+ * the batch to the Python pool's bench preprocess cache
13464
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
13465
+ * preprocessed ONCE and every later inference is a pure-inference cache
13466
+ * hit — the sustained-throughput run measures inference, not
13467
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
13468
+ * full preprocess every call, correct). Fresh per sustained run;
13469
+ * released via `uncacheFrame`.
13470
+ */
13471
+ frameId: number().int().nonnegative().optional(),
13472
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
13473
+ deviceKey: string().optional()
13446
13474
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
13447
13475
  data: _instanceof(Uint8Array),
13448
13476
  width: number().int().positive(),
@@ -13474,8 +13502,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
13474
13502
  * - `runtime` — main camera-serving engine (no idle TTL).
13475
13503
  * - `warm-override` — benchmark/test override held in the warm
13476
13504
  * cache; auto-disposed after the idle TTL.
13505
+ * - `device-pool` — a concurrent per-device pool (Phase 2
13506
+ * multi-device, keyed by `deviceKey`) resolved
13507
+ * via `resolveDeviceFactory`. Runs alongside the
13508
+ * `runtime` engine on a DIFFERENT accelerator
13509
+ * (NPU / iGPU / Coral) — this is how the
13510
+ * Engines tab shows all pools running at once.
13477
13511
  */
13478
- kind: _enum(["runtime", "warm-override"]),
13512
+ kind: _enum([
13513
+ "runtime",
13514
+ "warm-override",
13515
+ "device-pool"
13516
+ ]),
13479
13517
  /** Native pid of the underlying Python pool (null when no pool). */
13480
13518
  poolPid: number().nullable(),
13481
13519
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -13850,7 +13888,14 @@ var RunnerCameraConfigSchema = object({
13850
13888
  * camera's detect node differs from its source-owner (P2d, gated by the
13851
13889
  * `remoteSourcingNodes` rollout setting).
13852
13890
  */
13853
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13891
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13892
+ /**
13893
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13894
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13895
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13896
+ * this only selects WHICH device pool of that node runs the session.
13897
+ */
13898
+ deviceKey: string().optional()
13854
13899
  });
13855
13900
  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;
13856
13901
  /**
@@ -13871,6 +13916,19 @@ var RunnerLocalLoadSchema = object({
13871
13916
  avgInferenceTimeMs: number(),
13872
13917
  /** Total queue depth across motion + detection queues. */
13873
13918
  queueDepthTotal: number(),
13919
+ /**
13920
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13921
+ * this runner currently has attached cameras on, so the orchestrator's second
13922
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13923
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13924
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13925
+ */
13926
+ devices: array(object({
13927
+ deviceKey: string(),
13928
+ backend: string(),
13929
+ attachedCameras: number(),
13930
+ queueDepthTotal: number()
13931
+ })).default([]),
13874
13932
  /** Hardware capability flags reported by this node. */
13875
13933
  hardware: object({
13876
13934
  hasGpu: boolean(),
@@ -17019,6 +17077,8 @@ var BaseDeviceProvider = class extends BaseAddon {
17019
17077
  return toDeviceSummary(device, this.addonId);
17020
17078
  }
17021
17079
  };
17080
+ 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;
17081
+ new Set(Object.values(DeviceType));
17022
17082
  /**
17023
17083
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
17024
17084
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -20688,13 +20748,11 @@ var PipelineTemplateSchema = object({
20688
20748
  createdAt: string(),
20689
20749
  updatedAt: string()
20690
20750
  });
20691
- var AgentAddonConfigSchema = object({
20692
- enabled: boolean(),
20751
+ var DeviceStepConfigSchema = object({
20693
20752
  modelId: string().optional(),
20694
- settings: record(string(), unknown()).readonly()
20753
+ settings: record(string(), unknown()).optional()
20695
20754
  });
20696
20755
  var AgentPipelineSettingsSchema = object({
20697
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
20698
20756
  maxCameras: number().int().nonnegative().nullable().default(null),
20699
20757
  /** Per-node detection weight (relative share for the quota balancer). */
20700
20758
  detectWeight: number().positive().optional(),
@@ -20718,7 +20776,22 @@ var AgentPipelineSettingsSchema = object({
20718
20776
  * it already uses to reach the hub). Set this only when the auto-detected
20719
20777
  * address is wrong (multi-homed host, NAT, custom interface).
20720
20778
  */
20721
- reachableHost: string().optional()
20779
+ reachableHost: string().optional(),
20780
+ /**
20781
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20782
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20783
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20784
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20785
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20786
+ * the default model/settings for every camera landing on that accelerator;
20787
+ * a stepId absent ⇒ the step uses that device's format default.
20788
+ */
20789
+ inferenceDevices: record(string(), object({
20790
+ enabled: boolean(),
20791
+ weight: number().positive().optional(),
20792
+ maxSessions: number().int().positive().optional(),
20793
+ steps: record(string(), DeviceStepConfigSchema).optional()
20794
+ })).optional()
20722
20795
  });
20723
20796
  var CameraPipelineForAgentSchema = object({
20724
20797
  steps: array(PipelineStepInputSchema).readonly(),
@@ -20728,14 +20801,13 @@ var CameraPipelineForAgentSchema = object({
20728
20801
  }).nullable()
20729
20802
  });
20730
20803
  var CameraStepOverridePatchSchema = object({
20731
- enabled: boolean().optional(),
20732
20804
  modelId: string().optional(),
20733
20805
  settings: record(string(), unknown()).readonly().optional()
20734
20806
  });
20735
20807
  var CameraPipelineSettingsSchema = object({
20736
20808
  pinnedAgentNodeId: string().optional(),
20737
20809
  stepToggles: record(string(), boolean()).optional(),
20738
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20810
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
20739
20811
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
20740
20812
  });
20741
20813
  /**
@@ -20949,6 +21021,44 @@ var CameraStatusSchema = object({
20949
21021
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20950
21022
  fetchedAt: number()
20951
21023
  });
21024
+ var NodeInferenceDeviceSchema = object({
21025
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
21026
+ key: string(),
21027
+ backend: string(),
21028
+ device: string(),
21029
+ format: _enum(MODEL_FORMATS),
21030
+ /** Whether the node's live probe reports the device as usable right now. */
21031
+ available: boolean(),
21032
+ /**
21033
+ * Whether this device participates in dispatch. AUTO default (spec C2):
21034
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
21035
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
21036
+ * not a balanced target). An explicit stored value always wins; a stored-only
21037
+ * (unavailable) key keeps its stored value.
21038
+ */
21039
+ enabled: boolean(),
21040
+ /** Relative balancer weight for the enabled device (default 1). */
21041
+ weight: number(),
21042
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
21043
+ maxSessions: number().nullable(),
21044
+ /** Object-detection model the executor defaults to for this deviceKey. */
21045
+ defaultModelId: string(),
21046
+ /**
21047
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
21048
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
21049
+ * Absent/empty ⇒ no base (every step uses its device format default). The
21050
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
21051
+ * available per format; this is the stored selection that becomes the
21052
+ * default for EVERY camera landing on this accelerator.
21053
+ */
21054
+ steps: record(string(), DeviceStepConfigSchema).optional()
21055
+ });
21056
+ var NodeInferenceDevicesSchema = object({
21057
+ nodeId: string(),
21058
+ /** False when the node's platform-probe was unreachable (no live device set). */
21059
+ reachable: boolean(),
21060
+ devices: array(NodeInferenceDeviceSchema).readonly()
21061
+ });
20952
21062
  method(object({
20953
21063
  deviceId: number(),
20954
21064
  agentNodeId: string()
@@ -20958,7 +21068,13 @@ method(object({
20958
21068
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20959
21069
  kind: "mutation",
20960
21070
  auth: "admin"
20961
- }), method(_void(), object({ migrated: number() }), {
21071
+ }), method(object({
21072
+ deviceId: number(),
21073
+ deviceKey: string()
21074
+ }), object({ success: literal(true) }), {
21075
+ kind: "mutation",
21076
+ auth: "admin"
21077
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20962
21078
  kind: "mutation",
20963
21079
  auth: "admin"
20964
21080
  }), 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({
@@ -20992,13 +21108,7 @@ method(object({
20992
21108
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20993
21109
  nodeId: string(),
20994
21110
  settings: AgentPipelineSettingsSchema
20995
- })).readonly()), method(object({
20996
- agentNodeId: string(),
20997
- defaults: record(string(), AgentAddonConfigSchema)
20998
- }), object({ success: literal(true) }), {
20999
- kind: "mutation",
21000
- auth: "admin"
21001
- }), method(object({ agentNodeId: string() }), object({
21111
+ })).readonly()), method(object({ agentNodeId: string() }), object({
21002
21112
  success: boolean(),
21003
21113
  removed: boolean()
21004
21114
  }), {
@@ -21030,7 +21140,18 @@ method(object({
21030
21140
  }), object({ success: literal(true) }), {
21031
21141
  kind: "mutation",
21032
21142
  auth: "admin"
21033
- }), method(object({ agentNodeId: string() }), object({
21143
+ }), method(object({
21144
+ agentNodeId: string(),
21145
+ inferenceDevices: record(string(), object({
21146
+ enabled: boolean(),
21147
+ weight: number().positive().optional(),
21148
+ maxSessions: number().int().positive().optional(),
21149
+ steps: record(string(), DeviceStepConfigSchema).optional()
21150
+ }))
21151
+ }), object({ success: literal(true) }), {
21152
+ kind: "mutation",
21153
+ auth: "admin"
21154
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
21034
21155
  success: literal(true),
21035
21156
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
21036
21157
  effectiveModelId: string().nullable(),
@@ -21046,9 +21167,10 @@ method(object({
21046
21167
  }), object({ success: literal(true) }), {
21047
21168
  kind: "mutation",
21048
21169
  auth: "admin"
21049
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
21170
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
21050
21171
  deviceId: number(),
21051
21172
  agentNodeId: string(),
21173
+ deviceKey: string(),
21052
21174
  addonId: string(),
21053
21175
  patch: CameraStepOverridePatchSchema.nullable()
21054
21176
  }), object({ success: literal(true) }), {
@@ -21085,14 +21207,13 @@ method(object({
21085
21207
  });
21086
21208
  /**
21087
21209
  * server-management — per-NODE singleton capability for a node's ROOT
21088
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
21089
- * agents).
21210
+ * package lifecycle (runtime-updatable node packages).
21090
21211
  *
21091
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
21092
- * on agents) carries the whole software stack in its npm dep tree, so ONE
21093
- * version describes the node. Updates install into
21094
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
21095
- * starter (probation boot + auto-rollback to N-1).
21212
+ * Every node role runs the SAME root package (`@camstack/server`), which
21213
+ * carries the whole software stack in its npm dep tree, so ONE version
21214
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
21215
+ * on restart via the baked starter (single-copy in-place swap — no probation,
21216
+ * no auto-rollback).
21096
21217
  *
21097
21218
  * Providers:
21098
21219
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -21200,7 +21321,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
21200
21321
  /** Explicit target version; omitted = latest from the registry. */
21201
21322
  version: string().optional() }), ServerUpdateActionResultSchema, {
21202
21323
  kind: "mutation",
21203
- auth: "admin"
21324
+ auth: "admin",
21325
+ timeoutMs: 16 * 6e4
21204
21326
  }), method(_void(), ServerUpdateActionResultSchema, {
21205
21327
  kind: "mutation",
21206
21328
  auth: "admin"
@@ -22244,22 +22366,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
22244
22366
  var RestartAddonResultSchema = unknown();
22245
22367
  var InstallPackageResultSchema = unknown();
22246
22368
  var ReloadPackagesResultSchema = unknown();
22247
- /**
22248
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
22249
- * server restarts so the admin UI can react to the `restartingAt`
22250
- * timestamp (shows reconnect overlay). The transition from
22251
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
22252
- * `system.restart-completed` event after the new process boots.
22253
- *
22254
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
22255
- */
22256
- var UpdateFrameworkPackageResultSchema = object({
22257
- packageName: string(),
22258
- fromVersion: string(),
22259
- toVersion: string(),
22260
- /** Ms-epoch the server scheduled its self-restart. */
22261
- restartingAt: number()
22262
- });
22263
22369
  var BulkUpdateItemStatusSchema = _enum([
22264
22370
  "queued",
22265
22371
  "updating",
@@ -22387,13 +22493,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
22387
22493
  }), object({ success: literal(true) }), {
22388
22494
  kind: "mutation",
22389
22495
  auth: "admin"
22390
- }), method(object({
22391
- packageName: string().min(1),
22392
- version: string().optional(),
22393
- deferRestart: boolean().optional()
22394
- }), UpdateFrameworkPackageResultSchema, {
22395
- kind: "mutation",
22396
- auth: "admin"
22397
22496
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
22398
22497
  kind: "mutation",
22399
22498
  auth: "admin"
@@ -23259,10 +23358,10 @@ var TopologyCategorySchema = object({
23259
23358
  addons: array(TopologyCategoryAddonSchema).readonly()
23260
23359
  });
23261
23360
  /**
23262
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
23263
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
23264
- * version visibility for the Server management surface. Nullable: offline
23265
- * rows and pre-phase-2 nodes report none.
23361
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
23362
+ * root package for every node role) as reported by its `registerNode`
23363
+ * manifest — version visibility for the Server management surface. Nullable:
23364
+ * offline rows and nodes that never reported one.
23266
23365
  */
23267
23366
  var TopologyRootPackageSchema = object({
23268
23367
  name: string(),
@@ -23650,17 +23749,28 @@ var PlatformScoreSchema = object({
23650
23749
  format: _enum([
23651
23750
  "onnx",
23652
23751
  "coreml",
23653
- "openvino"
23752
+ "openvino",
23753
+ "tflite"
23654
23754
  ]),
23655
23755
  score: number(),
23656
23756
  reason: string(),
23657
23757
  available: boolean()
23658
23758
  });
23759
+ var InferenceDeviceDescriptorSchema = object({
23760
+ key: string(),
23761
+ backend: string(),
23762
+ device: string(),
23763
+ format: ModelFormatSchema,
23764
+ runtime: literal("python"),
23765
+ score: number(),
23766
+ available: boolean()
23767
+ });
23659
23768
  var PlatformCapabilitiesSchema = object({
23660
23769
  hardware: HardwareInfoSchema,
23661
23770
  scores: array(PlatformScoreSchema).readonly(),
23662
23771
  bestScore: PlatformScoreSchema,
23663
- pythonPath: string().nullable()
23772
+ pythonPath: string().nullable(),
23773
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
23664
23774
  });
23665
23775
  var ModelRequirementSchema = object({
23666
23776
  modelId: string(),
@@ -24539,12 +24649,6 @@ Object.freeze({
24539
24649
  addonId: null,
24540
24650
  access: "delete"
24541
24651
  },
24542
- "addons.updateFrameworkPackage": {
24543
- capName: "addons",
24544
- capScope: "system",
24545
- addonId: null,
24546
- access: "create"
24547
- },
24548
24652
  "addons.updatePackage": {
24549
24653
  capName: "addons",
24550
24654
  capScope: "system",
@@ -27317,12 +27421,6 @@ Object.freeze({
27317
27421
  addonId: null,
27318
27422
  access: "view"
27319
27423
  },
27320
- "pipelineExecutor.reprobeEngine": {
27321
- capName: "pipeline-executor",
27322
- capScope: "system",
27323
- addonId: null,
27324
- access: "create"
27325
- },
27326
27424
  "pipelineExecutor.runAudioTest": {
27327
27425
  capName: "pipeline-executor",
27328
27426
  capScope: "system",
@@ -27473,6 +27571,12 @@ Object.freeze({
27473
27571
  addonId: null,
27474
27572
  access: "view"
27475
27573
  },
27574
+ "pipelineOrchestrator.getNodeInferenceDevices": {
27575
+ capName: "pipeline-orchestrator",
27576
+ capScope: "system",
27577
+ addonId: null,
27578
+ access: "view"
27579
+ },
27476
27580
  "pipelineOrchestrator.getPipelineAssignment": {
27477
27581
  capName: "pipeline-orchestrator",
27478
27582
  capScope: "system",
@@ -27485,6 +27589,12 @@ Object.freeze({
27485
27589
  addonId: null,
27486
27590
  access: "view"
27487
27591
  },
27592
+ "pipelineOrchestrator.getPipelineDevicePin": {
27593
+ capName: "pipeline-orchestrator",
27594
+ capScope: "system",
27595
+ addonId: null,
27596
+ access: "view"
27597
+ },
27488
27598
  "pipelineOrchestrator.listAgentSettings": {
27489
27599
  capName: "pipeline-orchestrator",
27490
27600
  capScope: "system",
@@ -27527,19 +27637,19 @@ Object.freeze({
27527
27637
  addonId: null,
27528
27638
  access: "create"
27529
27639
  },
27530
- "pipelineOrchestrator.setAgentAddonDefaults": {
27640
+ "pipelineOrchestrator.setAgentCapabilities": {
27531
27641
  capName: "pipeline-orchestrator",
27532
27642
  capScope: "system",
27533
27643
  addonId: null,
27534
27644
  access: "create"
27535
27645
  },
27536
- "pipelineOrchestrator.setAgentCapabilities": {
27646
+ "pipelineOrchestrator.setAgentDetectWeight": {
27537
27647
  capName: "pipeline-orchestrator",
27538
27648
  capScope: "system",
27539
27649
  addonId: null,
27540
27650
  access: "create"
27541
27651
  },
27542
- "pipelineOrchestrator.setAgentDetectWeight": {
27652
+ "pipelineOrchestrator.setAgentInferenceDevices": {
27543
27653
  capName: "pipeline-orchestrator",
27544
27654
  capScope: "system",
27545
27655
  addonId: null,
@@ -27581,6 +27691,12 @@ Object.freeze({
27581
27691
  addonId: null,
27582
27692
  access: "create"
27583
27693
  },
27694
+ "pipelineOrchestrator.setPipelineDevicePin": {
27695
+ capName: "pipeline-orchestrator",
27696
+ capScope: "system",
27697
+ addonId: null,
27698
+ access: "create"
27699
+ },
27584
27700
  "pipelineOrchestrator.unassignAudio": {
27585
27701
  capName: "pipeline-orchestrator",
27586
27702
  capScope: "system",
@@ -29133,32 +29249,6 @@ Object.freeze({
29133
29249
  "network-access": "ingress",
29134
29250
  "smtp-provider": "email"
29135
29251
  });
29136
- var frameworkSwapPackageSchema = object({
29137
- name: string(),
29138
- stagedPath: string(),
29139
- backupPath: string(),
29140
- toVersion: string(),
29141
- fromVersion: string().nullable()
29142
- });
29143
- object({
29144
- jobId: string(),
29145
- taskId: string(),
29146
- packages: array(frameworkSwapPackageSchema),
29147
- requestedAtMs: number(),
29148
- schemaVersion: literal(1)
29149
- });
29150
- object({
29151
- jobId: string(),
29152
- taskId: string(),
29153
- backups: array(object({
29154
- name: string(),
29155
- backupPath: string(),
29156
- livePath: string()
29157
- })),
29158
- appliedAtMs: number(),
29159
- bootAttempts: number(),
29160
- schemaVersion: literal(1)
29161
- });
29162
29252
  //#endregion
29163
29253
  //#region src/config.ts
29164
29254
  /**
package/dist/addon.mjs CHANGED
@@ -8082,6 +8082,17 @@ var ModelCatalogEntrySchema = object({
8082
8082
  "imagenet",
8083
8083
  "none"
8084
8084
  ]).optional(),
8085
+ /**
8086
+ * The model already applies softmax IN-GRAPH — its raw output is a
8087
+ * probability distribution, not logits. When set, the `softmax`
8088
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
8089
+ * probability vector collapses it toward uniform (top-1 score craters far
8090
+ * below its true value, making every confidence gate meaningless). Absent ⇒
8091
+ * the output is raw logits and the postprocessor applies softmax (the normal
8092
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
8093
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
8094
+ */
8095
+ outputProbabilities: boolean().optional(),
8085
8096
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
8086
8097
  /**
8087
8098
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -13372,10 +13383,7 @@ var ConfigUISchemaNullableBridge = custom();
13372
13383
  var InferenceCapabilitiesBridge = custom();
13373
13384
  var ModelAvailabilityListBridge = custom();
13374
13385
  var PipelineRunResultBridge = custom();
13375
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
13376
- kind: "mutation",
13377
- auth: "admin"
13378
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
13386
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
13379
13387
  modelId: string(),
13380
13388
  settings: record(string(), unknown()).readonly()
13381
13389
  }))), method(object({ steps: record(string(), object({
@@ -13435,13 +13443,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
13435
13443
  * (inputClasses ≠ null) are skipped and served per-track via
13436
13444
  * pipelineRunner.runDetailSubtree (two-plane design).
13437
13445
  */
13438
- plane: _enum(["full", "frame"]).optional()
13446
+ plane: _enum(["full", "frame"]).optional(),
13447
+ /**
13448
+ * Inference-device selector (Phase 2 multi-device). Format
13449
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
13450
+ * Omitted ⇒ the runner's default device (current single-engine
13451
+ * behaviour). Selects WHICH device pool of the node runs the call.
13452
+ */
13453
+ deviceKey: string().optional()
13439
13454
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
13440
13455
  engine: PipelineEngineChoiceSchema.optional(),
13441
13456
  steps: array(PipelineStepInputSchema).min(1),
13442
13457
  frames: array(FrameInputSchema).min(1).max(255),
13443
13458
  deviceId: number().optional(),
13444
- sessionId: string().optional()
13459
+ sessionId: string().optional(),
13460
+ /**
13461
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
13462
+ * the batch to the Python pool's bench preprocess cache
13463
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
13464
+ * preprocessed ONCE and every later inference is a pure-inference cache
13465
+ * hit — the sustained-throughput run measures inference, not
13466
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
13467
+ * full preprocess every call, correct). Fresh per sustained run;
13468
+ * released via `uncacheFrame`.
13469
+ */
13470
+ frameId: number().int().nonnegative().optional(),
13471
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
13472
+ deviceKey: string().optional()
13445
13473
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
13446
13474
  data: _instanceof(Uint8Array),
13447
13475
  width: number().int().positive(),
@@ -13473,8 +13501,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
13473
13501
  * - `runtime` — main camera-serving engine (no idle TTL).
13474
13502
  * - `warm-override` — benchmark/test override held in the warm
13475
13503
  * cache; auto-disposed after the idle TTL.
13504
+ * - `device-pool` — a concurrent per-device pool (Phase 2
13505
+ * multi-device, keyed by `deviceKey`) resolved
13506
+ * via `resolveDeviceFactory`. Runs alongside the
13507
+ * `runtime` engine on a DIFFERENT accelerator
13508
+ * (NPU / iGPU / Coral) — this is how the
13509
+ * Engines tab shows all pools running at once.
13476
13510
  */
13477
- kind: _enum(["runtime", "warm-override"]),
13511
+ kind: _enum([
13512
+ "runtime",
13513
+ "warm-override",
13514
+ "device-pool"
13515
+ ]),
13478
13516
  /** Native pid of the underlying Python pool (null when no pool). */
13479
13517
  poolPid: number().nullable(),
13480
13518
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -13849,7 +13887,14 @@ var RunnerCameraConfigSchema = object({
13849
13887
  * camera's detect node differs from its source-owner (P2d, gated by the
13850
13888
  * `remoteSourcingNodes` rollout setting).
13851
13889
  */
13852
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13890
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13891
+ /**
13892
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13893
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13894
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13895
+ * this only selects WHICH device pool of that node runs the session.
13896
+ */
13897
+ deviceKey: string().optional()
13853
13898
  });
13854
13899
  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;
13855
13900
  /**
@@ -13870,6 +13915,19 @@ var RunnerLocalLoadSchema = object({
13870
13915
  avgInferenceTimeMs: number(),
13871
13916
  /** Total queue depth across motion + detection queues. */
13872
13917
  queueDepthTotal: number(),
13918
+ /**
13919
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13920
+ * this runner currently has attached cameras on, so the orchestrator's second
13921
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13922
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13923
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13924
+ */
13925
+ devices: array(object({
13926
+ deviceKey: string(),
13927
+ backend: string(),
13928
+ attachedCameras: number(),
13929
+ queueDepthTotal: number()
13930
+ })).default([]),
13873
13931
  /** Hardware capability flags reported by this node. */
13874
13932
  hardware: object({
13875
13933
  hasGpu: boolean(),
@@ -17018,6 +17076,8 @@ var BaseDeviceProvider = class extends BaseAddon {
17018
17076
  return toDeviceSummary(device, this.addonId);
17019
17077
  }
17020
17078
  };
17079
+ 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;
17080
+ new Set(Object.values(DeviceType));
17021
17081
  /**
17022
17082
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
17023
17083
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -20687,13 +20747,11 @@ var PipelineTemplateSchema = object({
20687
20747
  createdAt: string(),
20688
20748
  updatedAt: string()
20689
20749
  });
20690
- var AgentAddonConfigSchema = object({
20691
- enabled: boolean(),
20750
+ var DeviceStepConfigSchema = object({
20692
20751
  modelId: string().optional(),
20693
- settings: record(string(), unknown()).readonly()
20752
+ settings: record(string(), unknown()).optional()
20694
20753
  });
20695
20754
  var AgentPipelineSettingsSchema = object({
20696
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
20697
20755
  maxCameras: number().int().nonnegative().nullable().default(null),
20698
20756
  /** Per-node detection weight (relative share for the quota balancer). */
20699
20757
  detectWeight: number().positive().optional(),
@@ -20717,7 +20775,22 @@ var AgentPipelineSettingsSchema = object({
20717
20775
  * it already uses to reach the hub). Set this only when the auto-detected
20718
20776
  * address is wrong (multi-homed host, NAT, custom interface).
20719
20777
  */
20720
- reachableHost: string().optional()
20778
+ reachableHost: string().optional(),
20779
+ /**
20780
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20781
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20782
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20783
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20784
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20785
+ * the default model/settings for every camera landing on that accelerator;
20786
+ * a stepId absent ⇒ the step uses that device's format default.
20787
+ */
20788
+ inferenceDevices: record(string(), object({
20789
+ enabled: boolean(),
20790
+ weight: number().positive().optional(),
20791
+ maxSessions: number().int().positive().optional(),
20792
+ steps: record(string(), DeviceStepConfigSchema).optional()
20793
+ })).optional()
20721
20794
  });
20722
20795
  var CameraPipelineForAgentSchema = object({
20723
20796
  steps: array(PipelineStepInputSchema).readonly(),
@@ -20727,14 +20800,13 @@ var CameraPipelineForAgentSchema = object({
20727
20800
  }).nullable()
20728
20801
  });
20729
20802
  var CameraStepOverridePatchSchema = object({
20730
- enabled: boolean().optional(),
20731
20803
  modelId: string().optional(),
20732
20804
  settings: record(string(), unknown()).readonly().optional()
20733
20805
  });
20734
20806
  var CameraPipelineSettingsSchema = object({
20735
20807
  pinnedAgentNodeId: string().optional(),
20736
20808
  stepToggles: record(string(), boolean()).optional(),
20737
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20809
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
20738
20810
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
20739
20811
  });
20740
20812
  /**
@@ -20948,6 +21020,44 @@ var CameraStatusSchema = object({
20948
21020
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20949
21021
  fetchedAt: number()
20950
21022
  });
21023
+ var NodeInferenceDeviceSchema = object({
21024
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
21025
+ key: string(),
21026
+ backend: string(),
21027
+ device: string(),
21028
+ format: _enum(MODEL_FORMATS),
21029
+ /** Whether the node's live probe reports the device as usable right now. */
21030
+ available: boolean(),
21031
+ /**
21032
+ * Whether this device participates in dispatch. AUTO default (spec C2):
21033
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
21034
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
21035
+ * not a balanced target). An explicit stored value always wins; a stored-only
21036
+ * (unavailable) key keeps its stored value.
21037
+ */
21038
+ enabled: boolean(),
21039
+ /** Relative balancer weight for the enabled device (default 1). */
21040
+ weight: number(),
21041
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
21042
+ maxSessions: number().nullable(),
21043
+ /** Object-detection model the executor defaults to for this deviceKey. */
21044
+ defaultModelId: string(),
21045
+ /**
21046
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
21047
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
21048
+ * Absent/empty ⇒ no base (every step uses its device format default). The
21049
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
21050
+ * available per format; this is the stored selection that becomes the
21051
+ * default for EVERY camera landing on this accelerator.
21052
+ */
21053
+ steps: record(string(), DeviceStepConfigSchema).optional()
21054
+ });
21055
+ var NodeInferenceDevicesSchema = object({
21056
+ nodeId: string(),
21057
+ /** False when the node's platform-probe was unreachable (no live device set). */
21058
+ reachable: boolean(),
21059
+ devices: array(NodeInferenceDeviceSchema).readonly()
21060
+ });
20951
21061
  method(object({
20952
21062
  deviceId: number(),
20953
21063
  agentNodeId: string()
@@ -20957,7 +21067,13 @@ method(object({
20957
21067
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20958
21068
  kind: "mutation",
20959
21069
  auth: "admin"
20960
- }), method(_void(), object({ migrated: number() }), {
21070
+ }), method(object({
21071
+ deviceId: number(),
21072
+ deviceKey: string()
21073
+ }), object({ success: literal(true) }), {
21074
+ kind: "mutation",
21075
+ auth: "admin"
21076
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20961
21077
  kind: "mutation",
20962
21078
  auth: "admin"
20963
21079
  }), 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({
@@ -20991,13 +21107,7 @@ method(object({
20991
21107
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20992
21108
  nodeId: string(),
20993
21109
  settings: AgentPipelineSettingsSchema
20994
- })).readonly()), method(object({
20995
- agentNodeId: string(),
20996
- defaults: record(string(), AgentAddonConfigSchema)
20997
- }), object({ success: literal(true) }), {
20998
- kind: "mutation",
20999
- auth: "admin"
21000
- }), method(object({ agentNodeId: string() }), object({
21110
+ })).readonly()), method(object({ agentNodeId: string() }), object({
21001
21111
  success: boolean(),
21002
21112
  removed: boolean()
21003
21113
  }), {
@@ -21029,7 +21139,18 @@ method(object({
21029
21139
  }), object({ success: literal(true) }), {
21030
21140
  kind: "mutation",
21031
21141
  auth: "admin"
21032
- }), method(object({ agentNodeId: string() }), object({
21142
+ }), method(object({
21143
+ agentNodeId: string(),
21144
+ inferenceDevices: record(string(), object({
21145
+ enabled: boolean(),
21146
+ weight: number().positive().optional(),
21147
+ maxSessions: number().int().positive().optional(),
21148
+ steps: record(string(), DeviceStepConfigSchema).optional()
21149
+ }))
21150
+ }), object({ success: literal(true) }), {
21151
+ kind: "mutation",
21152
+ auth: "admin"
21153
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
21033
21154
  success: literal(true),
21034
21155
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
21035
21156
  effectiveModelId: string().nullable(),
@@ -21045,9 +21166,10 @@ method(object({
21045
21166
  }), object({ success: literal(true) }), {
21046
21167
  kind: "mutation",
21047
21168
  auth: "admin"
21048
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
21169
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
21049
21170
  deviceId: number(),
21050
21171
  agentNodeId: string(),
21172
+ deviceKey: string(),
21051
21173
  addonId: string(),
21052
21174
  patch: CameraStepOverridePatchSchema.nullable()
21053
21175
  }), object({ success: literal(true) }), {
@@ -21084,14 +21206,13 @@ method(object({
21084
21206
  });
21085
21207
  /**
21086
21208
  * server-management — per-NODE singleton capability for a node's ROOT
21087
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
21088
- * agents).
21209
+ * package lifecycle (runtime-updatable node packages).
21089
21210
  *
21090
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
21091
- * on agents) carries the whole software stack in its npm dep tree, so ONE
21092
- * version describes the node. Updates install into
21093
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
21094
- * starter (probation boot + auto-rollback to N-1).
21211
+ * Every node role runs the SAME root package (`@camstack/server`), which
21212
+ * carries the whole software stack in its npm dep tree, so ONE version
21213
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
21214
+ * on restart via the baked starter (single-copy in-place swap — no probation,
21215
+ * no auto-rollback).
21095
21216
  *
21096
21217
  * Providers:
21097
21218
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -21199,7 +21320,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
21199
21320
  /** Explicit target version; omitted = latest from the registry. */
21200
21321
  version: string().optional() }), ServerUpdateActionResultSchema, {
21201
21322
  kind: "mutation",
21202
- auth: "admin"
21323
+ auth: "admin",
21324
+ timeoutMs: 16 * 6e4
21203
21325
  }), method(_void(), ServerUpdateActionResultSchema, {
21204
21326
  kind: "mutation",
21205
21327
  auth: "admin"
@@ -22243,22 +22365,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
22243
22365
  var RestartAddonResultSchema = unknown();
22244
22366
  var InstallPackageResultSchema = unknown();
22245
22367
  var ReloadPackagesResultSchema = unknown();
22246
- /**
22247
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
22248
- * server restarts so the admin UI can react to the `restartingAt`
22249
- * timestamp (shows reconnect overlay). The transition from
22250
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
22251
- * `system.restart-completed` event after the new process boots.
22252
- *
22253
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
22254
- */
22255
- var UpdateFrameworkPackageResultSchema = object({
22256
- packageName: string(),
22257
- fromVersion: string(),
22258
- toVersion: string(),
22259
- /** Ms-epoch the server scheduled its self-restart. */
22260
- restartingAt: number()
22261
- });
22262
22368
  var BulkUpdateItemStatusSchema = _enum([
22263
22369
  "queued",
22264
22370
  "updating",
@@ -22386,13 +22492,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
22386
22492
  }), object({ success: literal(true) }), {
22387
22493
  kind: "mutation",
22388
22494
  auth: "admin"
22389
- }), method(object({
22390
- packageName: string().min(1),
22391
- version: string().optional(),
22392
- deferRestart: boolean().optional()
22393
- }), UpdateFrameworkPackageResultSchema, {
22394
- kind: "mutation",
22395
- auth: "admin"
22396
22495
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
22397
22496
  kind: "mutation",
22398
22497
  auth: "admin"
@@ -23258,10 +23357,10 @@ var TopologyCategorySchema = object({
23258
23357
  addons: array(TopologyCategoryAddonSchema).readonly()
23259
23358
  });
23260
23359
  /**
23261
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
23262
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
23263
- * version visibility for the Server management surface. Nullable: offline
23264
- * rows and pre-phase-2 nodes report none.
23360
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
23361
+ * root package for every node role) as reported by its `registerNode`
23362
+ * manifest — version visibility for the Server management surface. Nullable:
23363
+ * offline rows and nodes that never reported one.
23265
23364
  */
23266
23365
  var TopologyRootPackageSchema = object({
23267
23366
  name: string(),
@@ -23649,17 +23748,28 @@ var PlatformScoreSchema = object({
23649
23748
  format: _enum([
23650
23749
  "onnx",
23651
23750
  "coreml",
23652
- "openvino"
23751
+ "openvino",
23752
+ "tflite"
23653
23753
  ]),
23654
23754
  score: number(),
23655
23755
  reason: string(),
23656
23756
  available: boolean()
23657
23757
  });
23758
+ var InferenceDeviceDescriptorSchema = object({
23759
+ key: string(),
23760
+ backend: string(),
23761
+ device: string(),
23762
+ format: ModelFormatSchema,
23763
+ runtime: literal("python"),
23764
+ score: number(),
23765
+ available: boolean()
23766
+ });
23658
23767
  var PlatformCapabilitiesSchema = object({
23659
23768
  hardware: HardwareInfoSchema,
23660
23769
  scores: array(PlatformScoreSchema).readonly(),
23661
23770
  bestScore: PlatformScoreSchema,
23662
- pythonPath: string().nullable()
23771
+ pythonPath: string().nullable(),
23772
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
23663
23773
  });
23664
23774
  var ModelRequirementSchema = object({
23665
23775
  modelId: string(),
@@ -24538,12 +24648,6 @@ Object.freeze({
24538
24648
  addonId: null,
24539
24649
  access: "delete"
24540
24650
  },
24541
- "addons.updateFrameworkPackage": {
24542
- capName: "addons",
24543
- capScope: "system",
24544
- addonId: null,
24545
- access: "create"
24546
- },
24547
24651
  "addons.updatePackage": {
24548
24652
  capName: "addons",
24549
24653
  capScope: "system",
@@ -27316,12 +27420,6 @@ Object.freeze({
27316
27420
  addonId: null,
27317
27421
  access: "view"
27318
27422
  },
27319
- "pipelineExecutor.reprobeEngine": {
27320
- capName: "pipeline-executor",
27321
- capScope: "system",
27322
- addonId: null,
27323
- access: "create"
27324
- },
27325
27423
  "pipelineExecutor.runAudioTest": {
27326
27424
  capName: "pipeline-executor",
27327
27425
  capScope: "system",
@@ -27472,6 +27570,12 @@ Object.freeze({
27472
27570
  addonId: null,
27473
27571
  access: "view"
27474
27572
  },
27573
+ "pipelineOrchestrator.getNodeInferenceDevices": {
27574
+ capName: "pipeline-orchestrator",
27575
+ capScope: "system",
27576
+ addonId: null,
27577
+ access: "view"
27578
+ },
27475
27579
  "pipelineOrchestrator.getPipelineAssignment": {
27476
27580
  capName: "pipeline-orchestrator",
27477
27581
  capScope: "system",
@@ -27484,6 +27588,12 @@ Object.freeze({
27484
27588
  addonId: null,
27485
27589
  access: "view"
27486
27590
  },
27591
+ "pipelineOrchestrator.getPipelineDevicePin": {
27592
+ capName: "pipeline-orchestrator",
27593
+ capScope: "system",
27594
+ addonId: null,
27595
+ access: "view"
27596
+ },
27487
27597
  "pipelineOrchestrator.listAgentSettings": {
27488
27598
  capName: "pipeline-orchestrator",
27489
27599
  capScope: "system",
@@ -27526,19 +27636,19 @@ Object.freeze({
27526
27636
  addonId: null,
27527
27637
  access: "create"
27528
27638
  },
27529
- "pipelineOrchestrator.setAgentAddonDefaults": {
27639
+ "pipelineOrchestrator.setAgentCapabilities": {
27530
27640
  capName: "pipeline-orchestrator",
27531
27641
  capScope: "system",
27532
27642
  addonId: null,
27533
27643
  access: "create"
27534
27644
  },
27535
- "pipelineOrchestrator.setAgentCapabilities": {
27645
+ "pipelineOrchestrator.setAgentDetectWeight": {
27536
27646
  capName: "pipeline-orchestrator",
27537
27647
  capScope: "system",
27538
27648
  addonId: null,
27539
27649
  access: "create"
27540
27650
  },
27541
- "pipelineOrchestrator.setAgentDetectWeight": {
27651
+ "pipelineOrchestrator.setAgentInferenceDevices": {
27542
27652
  capName: "pipeline-orchestrator",
27543
27653
  capScope: "system",
27544
27654
  addonId: null,
@@ -27580,6 +27690,12 @@ Object.freeze({
27580
27690
  addonId: null,
27581
27691
  access: "create"
27582
27692
  },
27693
+ "pipelineOrchestrator.setPipelineDevicePin": {
27694
+ capName: "pipeline-orchestrator",
27695
+ capScope: "system",
27696
+ addonId: null,
27697
+ access: "create"
27698
+ },
27583
27699
  "pipelineOrchestrator.unassignAudio": {
27584
27700
  capName: "pipeline-orchestrator",
27585
27701
  capScope: "system",
@@ -29132,32 +29248,6 @@ Object.freeze({
29132
29248
  "network-access": "ingress",
29133
29249
  "smtp-provider": "email"
29134
29250
  });
29135
- var frameworkSwapPackageSchema = object({
29136
- name: string(),
29137
- stagedPath: string(),
29138
- backupPath: string(),
29139
- toVersion: string(),
29140
- fromVersion: string().nullable()
29141
- });
29142
- object({
29143
- jobId: string(),
29144
- taskId: string(),
29145
- packages: array(frameworkSwapPackageSchema),
29146
- requestedAtMs: number(),
29147
- schemaVersion: literal(1)
29148
- });
29149
- object({
29150
- jobId: string(),
29151
- taskId: string(),
29152
- backups: array(object({
29153
- name: string(),
29154
- backupPath: string(),
29155
- livePath: string()
29156
- })),
29157
- appliedAtMs: number(),
29158
- bootAttempts: number(),
29159
- schemaVersion: literal(1)
29160
- });
29161
29251
  //#endregion
29162
29252
  //#region src/config.ts
29163
29253
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-rademacher",
3
- "version": "0.1.14",
3
+ "version": "0.2.0",
4
4
  "description": "Rademacher HomePilot device-provider addon for CamStack — wraps the @apocaliss92/noderademacher local-hub client (roller shutters over the cover cap)",
5
5
  "keywords": [
6
6
  "camstack",