@camstack/addon-export-hap 1.1.28 → 1.2.1

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.
@@ -7104,6 +7104,17 @@ var ModelCatalogEntrySchema = object({
7104
7104
  "imagenet",
7105
7105
  "none"
7106
7106
  ]).optional(),
7107
+ /**
7108
+ * The model already applies softmax IN-GRAPH — its raw output is a
7109
+ * probability distribution, not logits. When set, the `softmax`
7110
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7111
+ * probability vector collapses it toward uniform (top-1 score craters far
7112
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7113
+ * the output is raw logits and the postprocessor applies softmax (the normal
7114
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7115
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7116
+ */
7117
+ outputProbabilities: boolean().optional(),
7107
7118
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7108
7119
  /**
7109
7120
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11171,10 +11182,7 @@ var ConfigUISchemaNullableBridge = custom();
11171
11182
  var InferenceCapabilitiesBridge = custom();
11172
11183
  var ModelAvailabilityListBridge = custom();
11173
11184
  var PipelineRunResultBridge = custom();
11174
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11175
- kind: "mutation",
11176
- auth: "admin"
11177
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11185
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11178
11186
  modelId: string(),
11179
11187
  settings: record(string(), unknown()).readonly()
11180
11188
  }))), method(object({ steps: record(string(), object({
@@ -11234,13 +11242,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11234
11242
  * (inputClasses ≠ null) are skipped and served per-track via
11235
11243
  * pipelineRunner.runDetailSubtree (two-plane design).
11236
11244
  */
11237
- plane: _enum(["full", "frame"]).optional()
11245
+ plane: _enum(["full", "frame"]).optional(),
11246
+ /**
11247
+ * Inference-device selector (Phase 2 multi-device). Format
11248
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11249
+ * Omitted ⇒ the runner's default device (current single-engine
11250
+ * behaviour). Selects WHICH device pool of the node runs the call.
11251
+ */
11252
+ deviceKey: string().optional()
11238
11253
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11239
11254
  engine: PipelineEngineChoiceSchema.optional(),
11240
11255
  steps: array(PipelineStepInputSchema).min(1),
11241
11256
  frames: array(FrameInputSchema).min(1).max(255),
11242
11257
  deviceId: number().optional(),
11243
- sessionId: string().optional()
11258
+ sessionId: string().optional(),
11259
+ /**
11260
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11261
+ * the batch to the Python pool's bench preprocess cache
11262
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11263
+ * preprocessed ONCE and every later inference is a pure-inference cache
11264
+ * hit — the sustained-throughput run measures inference, not
11265
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11266
+ * full preprocess every call, correct). Fresh per sustained run;
11267
+ * released via `uncacheFrame`.
11268
+ */
11269
+ frameId: number().int().nonnegative().optional(),
11270
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11271
+ deviceKey: string().optional()
11244
11272
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11245
11273
  data: _instanceof(Uint8Array),
11246
11274
  width: number().int().positive(),
@@ -11272,8 +11300,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11272
11300
  * - `runtime` — main camera-serving engine (no idle TTL).
11273
11301
  * - `warm-override` — benchmark/test override held in the warm
11274
11302
  * cache; auto-disposed after the idle TTL.
11303
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11304
+ * multi-device, keyed by `deviceKey`) resolved
11305
+ * via `resolveDeviceFactory`. Runs alongside the
11306
+ * `runtime` engine on a DIFFERENT accelerator
11307
+ * (NPU / iGPU / Coral) — this is how the
11308
+ * Engines tab shows all pools running at once.
11275
11309
  */
11276
- kind: _enum(["runtime", "warm-override"]),
11310
+ kind: _enum([
11311
+ "runtime",
11312
+ "warm-override",
11313
+ "device-pool"
11314
+ ]),
11277
11315
  /** Native pid of the underlying Python pool (null when no pool). */
11278
11316
  poolPid: number().nullable(),
11279
11317
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11375,7 +11413,21 @@ var NativeCropResultSchema = object({
11375
11413
  /** Packed rgb (24-bit) pixels of the crop. */
11376
11414
  bytes: _instanceof(Uint8Array),
11377
11415
  width: number().int().positive(),
11378
- height: number().int().positive()
11416
+ height: number().int().positive(),
11417
+ /**
11418
+ * Which source served this crop, so a quality-sensitive consumer (the native
11419
+ * `keyFrame`) can reject a degraded fallback:
11420
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11421
+ * quality path).
11422
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11423
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11424
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11425
+ *
11426
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11427
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11428
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11429
+ */
11430
+ tier: _enum(["native", "ram-fullframe"]).optional()
11379
11431
  });
11380
11432
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11381
11433
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11615,7 +11667,14 @@ var RunnerCameraConfigSchema = object({
11615
11667
  * camera's detect node differs from its source-owner (P2d, gated by the
11616
11668
  * `remoteSourcingNodes` rollout setting).
11617
11669
  */
11618
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11670
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11671
+ /**
11672
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11673
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11674
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11675
+ * this only selects WHICH device pool of that node runs the session.
11676
+ */
11677
+ deviceKey: string().optional()
11619
11678
  });
11620
11679
  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;
11621
11680
  /**
@@ -11636,6 +11695,19 @@ var RunnerLocalLoadSchema = object({
11636
11695
  avgInferenceTimeMs: number(),
11637
11696
  /** Total queue depth across motion + detection queues. */
11638
11697
  queueDepthTotal: number(),
11698
+ /**
11699
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11700
+ * this runner currently has attached cameras on, so the orchestrator's second
11701
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11702
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11703
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11704
+ */
11705
+ devices: array(object({
11706
+ deviceKey: string(),
11707
+ backend: string(),
11708
+ attachedCameras: number(),
11709
+ queueDepthTotal: number()
11710
+ })).default([]),
11639
11711
  /** Hardware capability flags reported by this node. */
11640
11712
  hardware: object({
11641
11713
  hasGpu: boolean(),
@@ -13111,6 +13183,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13111
13183
  kind: "mutation",
13112
13184
  auth: "admin"
13113
13185
  });
13186
+ 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;
13187
+ new Set(Object.values(DeviceType));
13114
13188
  /**
13115
13189
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13116
13190
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -14709,7 +14783,8 @@ var LinkedDeviceSchema = object({
14709
14783
  deviceId: number(),
14710
14784
  name: string(),
14711
14785
  location: string().nullable(),
14712
- features: array(string())
14786
+ features: array(string()),
14787
+ producesTrackedEvents: boolean().optional()
14713
14788
  });
14714
14789
  var SavedDeviceRowSchema = object({
14715
14790
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16339,6 +16414,7 @@ var TrackSchema = object({
16339
16414
  deviceId: number(),
16340
16415
  className: string(),
16341
16416
  label: string().optional(),
16417
+ producingDeviceName: string().optional(),
16342
16418
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16343
16419
  source: TrackSourceSchema.optional(),
16344
16420
  firstSeen: number(),
@@ -16476,7 +16552,8 @@ var MediaFileKindEnum = _enum([
16476
16552
  "fullFrameBoxed",
16477
16553
  "faceCrop",
16478
16554
  "plateCrop",
16479
- "keyFrame"
16555
+ "keyFrame",
16556
+ "keyFrameSmall"
16480
16557
  ]);
16481
16558
  var MediaFileSchema = object({
16482
16559
  key: string(),
@@ -16805,13 +16882,11 @@ var PipelineTemplateSchema = object({
16805
16882
  createdAt: string(),
16806
16883
  updatedAt: string()
16807
16884
  });
16808
- var AgentAddonConfigSchema = object({
16809
- enabled: boolean(),
16885
+ var DeviceStepConfigSchema = object({
16810
16886
  modelId: string().optional(),
16811
- settings: record(string(), unknown()).readonly()
16887
+ settings: record(string(), unknown()).optional()
16812
16888
  });
16813
16889
  var AgentPipelineSettingsSchema = object({
16814
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16815
16890
  maxCameras: number().int().nonnegative().nullable().default(null),
16816
16891
  /** Per-node detection weight (relative share for the quota balancer). */
16817
16892
  detectWeight: number().positive().optional(),
@@ -16835,7 +16910,22 @@ var AgentPipelineSettingsSchema = object({
16835
16910
  * it already uses to reach the hub). Set this only when the auto-detected
16836
16911
  * address is wrong (multi-homed host, NAT, custom interface).
16837
16912
  */
16838
- reachableHost: string().optional()
16913
+ reachableHost: string().optional(),
16914
+ /**
16915
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16916
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16917
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16918
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16919
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16920
+ * the default model/settings for every camera landing on that accelerator;
16921
+ * a stepId absent ⇒ the step uses that device's format default.
16922
+ */
16923
+ inferenceDevices: record(string(), object({
16924
+ enabled: boolean(),
16925
+ weight: number().positive().optional(),
16926
+ maxSessions: number().int().positive().optional(),
16927
+ steps: record(string(), DeviceStepConfigSchema).optional()
16928
+ })).optional()
16839
16929
  });
16840
16930
  var CameraPipelineForAgentSchema = object({
16841
16931
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16845,14 +16935,13 @@ var CameraPipelineForAgentSchema = object({
16845
16935
  }).nullable()
16846
16936
  });
16847
16937
  var CameraStepOverridePatchSchema = object({
16848
- enabled: boolean().optional(),
16849
16938
  modelId: string().optional(),
16850
16939
  settings: record(string(), unknown()).readonly().optional()
16851
16940
  });
16852
16941
  var CameraPipelineSettingsSchema = object({
16853
16942
  pinnedAgentNodeId: string().optional(),
16854
16943
  stepToggles: record(string(), boolean()).optional(),
16855
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
16944
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
16856
16945
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
16857
16946
  });
16858
16947
  /**
@@ -17066,6 +17155,44 @@ var CameraStatusSchema = object({
17066
17155
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17067
17156
  fetchedAt: number()
17068
17157
  });
17158
+ var NodeInferenceDeviceSchema = object({
17159
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17160
+ key: string(),
17161
+ backend: string(),
17162
+ device: string(),
17163
+ format: _enum(MODEL_FORMATS),
17164
+ /** Whether the node's live probe reports the device as usable right now. */
17165
+ available: boolean(),
17166
+ /**
17167
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17168
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17169
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17170
+ * not a balanced target). An explicit stored value always wins; a stored-only
17171
+ * (unavailable) key keeps its stored value.
17172
+ */
17173
+ enabled: boolean(),
17174
+ /** Relative balancer weight for the enabled device (default 1). */
17175
+ weight: number(),
17176
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17177
+ maxSessions: number().nullable(),
17178
+ /** Object-detection model the executor defaults to for this deviceKey. */
17179
+ defaultModelId: string(),
17180
+ /**
17181
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17182
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17183
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17184
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17185
+ * available per format; this is the stored selection that becomes the
17186
+ * default for EVERY camera landing on this accelerator.
17187
+ */
17188
+ steps: record(string(), DeviceStepConfigSchema).optional()
17189
+ });
17190
+ var NodeInferenceDevicesSchema = object({
17191
+ nodeId: string(),
17192
+ /** False when the node's platform-probe was unreachable (no live device set). */
17193
+ reachable: boolean(),
17194
+ devices: array(NodeInferenceDeviceSchema).readonly()
17195
+ });
17069
17196
  method(object({
17070
17197
  deviceId: number(),
17071
17198
  agentNodeId: string()
@@ -17075,7 +17202,13 @@ method(object({
17075
17202
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17076
17203
  kind: "mutation",
17077
17204
  auth: "admin"
17078
- }), method(_void(), object({ migrated: number() }), {
17205
+ }), method(object({
17206
+ deviceId: number(),
17207
+ deviceKey: string()
17208
+ }), object({ success: literal(true) }), {
17209
+ kind: "mutation",
17210
+ auth: "admin"
17211
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17079
17212
  kind: "mutation",
17080
17213
  auth: "admin"
17081
17214
  }), 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({
@@ -17109,13 +17242,7 @@ method(object({
17109
17242
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17110
17243
  nodeId: string(),
17111
17244
  settings: AgentPipelineSettingsSchema
17112
- })).readonly()), method(object({
17113
- agentNodeId: string(),
17114
- defaults: record(string(), AgentAddonConfigSchema)
17115
- }), object({ success: literal(true) }), {
17116
- kind: "mutation",
17117
- auth: "admin"
17118
- }), method(object({ agentNodeId: string() }), object({
17245
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17119
17246
  success: boolean(),
17120
17247
  removed: boolean()
17121
17248
  }), {
@@ -17147,7 +17274,18 @@ method(object({
17147
17274
  }), object({ success: literal(true) }), {
17148
17275
  kind: "mutation",
17149
17276
  auth: "admin"
17150
- }), method(object({ agentNodeId: string() }), object({
17277
+ }), method(object({
17278
+ agentNodeId: string(),
17279
+ inferenceDevices: record(string(), object({
17280
+ enabled: boolean(),
17281
+ weight: number().positive().optional(),
17282
+ maxSessions: number().int().positive().optional(),
17283
+ steps: record(string(), DeviceStepConfigSchema).optional()
17284
+ }))
17285
+ }), object({ success: literal(true) }), {
17286
+ kind: "mutation",
17287
+ auth: "admin"
17288
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17151
17289
  success: literal(true),
17152
17290
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17153
17291
  effectiveModelId: string().nullable(),
@@ -17163,9 +17301,10 @@ method(object({
17163
17301
  }), object({ success: literal(true) }), {
17164
17302
  kind: "mutation",
17165
17303
  auth: "admin"
17166
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17304
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17167
17305
  deviceId: number(),
17168
17306
  agentNodeId: string(),
17307
+ deviceKey: string(),
17169
17308
  addonId: string(),
17170
17309
  patch: CameraStepOverridePatchSchema.nullable()
17171
17310
  }), object({ success: literal(true) }), {
@@ -17202,14 +17341,13 @@ method(object({
17202
17341
  });
17203
17342
  /**
17204
17343
  * server-management — per-NODE singleton capability for a node's ROOT
17205
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17206
- * agents).
17344
+ * package lifecycle (runtime-updatable node packages).
17207
17345
  *
17208
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17209
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17210
- * version describes the node. Updates install into
17211
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17212
- * starter (probation boot + auto-rollback to N-1).
17346
+ * Every node role runs the SAME root package (`@camstack/server`), which
17347
+ * carries the whole software stack in its npm dep tree, so ONE version
17348
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17349
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17350
+ * no auto-rollback).
17213
17351
  *
17214
17352
  * Providers:
17215
17353
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17317,7 +17455,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17317
17455
  /** Explicit target version; omitted = latest from the registry. */
17318
17456
  version: string().optional() }), ServerUpdateActionResultSchema, {
17319
17457
  kind: "mutation",
17320
- auth: "admin"
17458
+ auth: "admin",
17459
+ timeoutMs: 16 * 6e4
17321
17460
  }), method(_void(), ServerUpdateActionResultSchema, {
17322
17461
  kind: "mutation",
17323
17462
  auth: "admin"
@@ -18361,22 +18500,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18361
18500
  var RestartAddonResultSchema = unknown();
18362
18501
  var InstallPackageResultSchema = unknown();
18363
18502
  var ReloadPackagesResultSchema = unknown();
18364
- /**
18365
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18366
- * server restarts so the admin UI can react to the `restartingAt`
18367
- * timestamp (shows reconnect overlay). The transition from
18368
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18369
- * `system.restart-completed` event after the new process boots.
18370
- *
18371
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18372
- */
18373
- var UpdateFrameworkPackageResultSchema = object({
18374
- packageName: string(),
18375
- fromVersion: string(),
18376
- toVersion: string(),
18377
- /** Ms-epoch the server scheduled its self-restart. */
18378
- restartingAt: number()
18379
- });
18380
18503
  var BulkUpdateItemStatusSchema = _enum([
18381
18504
  "queued",
18382
18505
  "updating",
@@ -18504,13 +18627,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18504
18627
  }), object({ success: literal(true) }), {
18505
18628
  kind: "mutation",
18506
18629
  auth: "admin"
18507
- }), method(object({
18508
- packageName: string().min(1),
18509
- version: string().optional(),
18510
- deferRestart: boolean().optional()
18511
- }), UpdateFrameworkPackageResultSchema, {
18512
- kind: "mutation",
18513
- auth: "admin"
18514
18630
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18515
18631
  kind: "mutation",
18516
18632
  auth: "admin"
@@ -19376,10 +19492,10 @@ var TopologyCategorySchema = object({
19376
19492
  addons: array(TopologyCategoryAddonSchema).readonly()
19377
19493
  });
19378
19494
  /**
19379
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19380
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19381
- * version visibility for the Server management surface. Nullable: offline
19382
- * rows and pre-phase-2 nodes report none.
19495
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19496
+ * root package for every node role) as reported by its `registerNode`
19497
+ * manifest — version visibility for the Server management surface. Nullable:
19498
+ * offline rows and nodes that never reported one.
19383
19499
  */
19384
19500
  var TopologyRootPackageSchema = object({
19385
19501
  name: string(),
@@ -19767,17 +19883,28 @@ var PlatformScoreSchema = object({
19767
19883
  format: _enum([
19768
19884
  "onnx",
19769
19885
  "coreml",
19770
- "openvino"
19886
+ "openvino",
19887
+ "tflite"
19771
19888
  ]),
19772
19889
  score: number(),
19773
19890
  reason: string(),
19774
19891
  available: boolean()
19775
19892
  });
19893
+ var InferenceDeviceDescriptorSchema = object({
19894
+ key: string(),
19895
+ backend: string(),
19896
+ device: string(),
19897
+ format: ModelFormatSchema,
19898
+ runtime: literal("python"),
19899
+ score: number(),
19900
+ available: boolean()
19901
+ });
19776
19902
  var PlatformCapabilitiesSchema = object({
19777
19903
  hardware: HardwareInfoSchema,
19778
19904
  scores: array(PlatformScoreSchema).readonly(),
19779
19905
  bestScore: PlatformScoreSchema,
19780
- pythonPath: string().nullable()
19906
+ pythonPath: string().nullable(),
19907
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19781
19908
  });
19782
19909
  var ModelRequirementSchema = object({
19783
19910
  modelId: string(),
@@ -20656,12 +20783,6 @@ Object.freeze({
20656
20783
  addonId: null,
20657
20784
  access: "delete"
20658
20785
  },
20659
- "addons.updateFrameworkPackage": {
20660
- capName: "addons",
20661
- capScope: "system",
20662
- addonId: null,
20663
- access: "create"
20664
- },
20665
20786
  "addons.updatePackage": {
20666
20787
  capName: "addons",
20667
20788
  capScope: "system",
@@ -23434,12 +23555,6 @@ Object.freeze({
23434
23555
  addonId: null,
23435
23556
  access: "view"
23436
23557
  },
23437
- "pipelineExecutor.reprobeEngine": {
23438
- capName: "pipeline-executor",
23439
- capScope: "system",
23440
- addonId: null,
23441
- access: "create"
23442
- },
23443
23558
  "pipelineExecutor.runAudioTest": {
23444
23559
  capName: "pipeline-executor",
23445
23560
  capScope: "system",
@@ -23590,6 +23705,12 @@ Object.freeze({
23590
23705
  addonId: null,
23591
23706
  access: "view"
23592
23707
  },
23708
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23709
+ capName: "pipeline-orchestrator",
23710
+ capScope: "system",
23711
+ addonId: null,
23712
+ access: "view"
23713
+ },
23593
23714
  "pipelineOrchestrator.getPipelineAssignment": {
23594
23715
  capName: "pipeline-orchestrator",
23595
23716
  capScope: "system",
@@ -23602,6 +23723,12 @@ Object.freeze({
23602
23723
  addonId: null,
23603
23724
  access: "view"
23604
23725
  },
23726
+ "pipelineOrchestrator.getPipelineDevicePin": {
23727
+ capName: "pipeline-orchestrator",
23728
+ capScope: "system",
23729
+ addonId: null,
23730
+ access: "view"
23731
+ },
23605
23732
  "pipelineOrchestrator.listAgentSettings": {
23606
23733
  capName: "pipeline-orchestrator",
23607
23734
  capScope: "system",
@@ -23644,19 +23771,19 @@ Object.freeze({
23644
23771
  addonId: null,
23645
23772
  access: "create"
23646
23773
  },
23647
- "pipelineOrchestrator.setAgentAddonDefaults": {
23774
+ "pipelineOrchestrator.setAgentCapabilities": {
23648
23775
  capName: "pipeline-orchestrator",
23649
23776
  capScope: "system",
23650
23777
  addonId: null,
23651
23778
  access: "create"
23652
23779
  },
23653
- "pipelineOrchestrator.setAgentCapabilities": {
23780
+ "pipelineOrchestrator.setAgentDetectWeight": {
23654
23781
  capName: "pipeline-orchestrator",
23655
23782
  capScope: "system",
23656
23783
  addonId: null,
23657
23784
  access: "create"
23658
23785
  },
23659
- "pipelineOrchestrator.setAgentDetectWeight": {
23786
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23660
23787
  capName: "pipeline-orchestrator",
23661
23788
  capScope: "system",
23662
23789
  addonId: null,
@@ -23698,6 +23825,12 @@ Object.freeze({
23698
23825
  addonId: null,
23699
23826
  access: "create"
23700
23827
  },
23828
+ "pipelineOrchestrator.setPipelineDevicePin": {
23829
+ capName: "pipeline-orchestrator",
23830
+ capScope: "system",
23831
+ addonId: null,
23832
+ access: "create"
23833
+ },
23701
23834
  "pipelineOrchestrator.unassignAudio": {
23702
23835
  capName: "pipeline-orchestrator",
23703
23836
  capScope: "system",
@@ -25250,32 +25383,6 @@ Object.freeze({
25250
25383
  "network-access": "ingress",
25251
25384
  "smtp-provider": "email"
25252
25385
  });
25253
- var frameworkSwapPackageSchema = object({
25254
- name: string(),
25255
- stagedPath: string(),
25256
- backupPath: string(),
25257
- toVersion: string(),
25258
- fromVersion: string().nullable()
25259
- });
25260
- object({
25261
- jobId: string(),
25262
- taskId: string(),
25263
- packages: array(frameworkSwapPackageSchema),
25264
- requestedAtMs: number(),
25265
- schemaVersion: literal(1)
25266
- });
25267
- object({
25268
- jobId: string(),
25269
- taskId: string(),
25270
- backups: array(object({
25271
- name: string(),
25272
- backupPath: string(),
25273
- livePath: string()
25274
- })),
25275
- appliedAtMs: number(),
25276
- bootAttempts: number(),
25277
- schemaVersion: literal(1)
25278
- });
25279
25386
  /**
25280
25387
  * Deterministic SHA-256 hash of an arbitrary serialisable value. The
25281
25388
  * canonical form sorts object keys alphabetically at every depth so two
@@ -7079,6 +7079,17 @@ var ModelCatalogEntrySchema = object({
7079
7079
  "imagenet",
7080
7080
  "none"
7081
7081
  ]).optional(),
7082
+ /**
7083
+ * The model already applies softmax IN-GRAPH — its raw output is a
7084
+ * probability distribution, not logits. When set, the `softmax`
7085
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7086
+ * probability vector collapses it toward uniform (top-1 score craters far
7087
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7088
+ * the output is raw logits and the postprocessor applies softmax (the normal
7089
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7090
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7091
+ */
7092
+ outputProbabilities: boolean().optional(),
7082
7093
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7083
7094
  /**
7084
7095
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11146,10 +11157,7 @@ var ConfigUISchemaNullableBridge = custom();
11146
11157
  var InferenceCapabilitiesBridge = custom();
11147
11158
  var ModelAvailabilityListBridge = custom();
11148
11159
  var PipelineRunResultBridge = custom();
11149
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11150
- kind: "mutation",
11151
- auth: "admin"
11152
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11160
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11153
11161
  modelId: string(),
11154
11162
  settings: record(string(), unknown()).readonly()
11155
11163
  }))), method(object({ steps: record(string(), object({
@@ -11209,13 +11217,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11209
11217
  * (inputClasses ≠ null) are skipped and served per-track via
11210
11218
  * pipelineRunner.runDetailSubtree (two-plane design).
11211
11219
  */
11212
- plane: _enum(["full", "frame"]).optional()
11220
+ plane: _enum(["full", "frame"]).optional(),
11221
+ /**
11222
+ * Inference-device selector (Phase 2 multi-device). Format
11223
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11224
+ * Omitted ⇒ the runner's default device (current single-engine
11225
+ * behaviour). Selects WHICH device pool of the node runs the call.
11226
+ */
11227
+ deviceKey: string().optional()
11213
11228
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11214
11229
  engine: PipelineEngineChoiceSchema.optional(),
11215
11230
  steps: array(PipelineStepInputSchema).min(1),
11216
11231
  frames: array(FrameInputSchema).min(1).max(255),
11217
11232
  deviceId: number().optional(),
11218
- sessionId: string().optional()
11233
+ sessionId: string().optional(),
11234
+ /**
11235
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11236
+ * the batch to the Python pool's bench preprocess cache
11237
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11238
+ * preprocessed ONCE and every later inference is a pure-inference cache
11239
+ * hit — the sustained-throughput run measures inference, not
11240
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11241
+ * full preprocess every call, correct). Fresh per sustained run;
11242
+ * released via `uncacheFrame`.
11243
+ */
11244
+ frameId: number().int().nonnegative().optional(),
11245
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11246
+ deviceKey: string().optional()
11219
11247
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11220
11248
  data: _instanceof(Uint8Array),
11221
11249
  width: number().int().positive(),
@@ -11247,8 +11275,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11247
11275
  * - `runtime` — main camera-serving engine (no idle TTL).
11248
11276
  * - `warm-override` — benchmark/test override held in the warm
11249
11277
  * cache; auto-disposed after the idle TTL.
11278
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11279
+ * multi-device, keyed by `deviceKey`) resolved
11280
+ * via `resolveDeviceFactory`. Runs alongside the
11281
+ * `runtime` engine on a DIFFERENT accelerator
11282
+ * (NPU / iGPU / Coral) — this is how the
11283
+ * Engines tab shows all pools running at once.
11250
11284
  */
11251
- kind: _enum(["runtime", "warm-override"]),
11285
+ kind: _enum([
11286
+ "runtime",
11287
+ "warm-override",
11288
+ "device-pool"
11289
+ ]),
11252
11290
  /** Native pid of the underlying Python pool (null when no pool). */
11253
11291
  poolPid: number().nullable(),
11254
11292
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11350,7 +11388,21 @@ var NativeCropResultSchema = object({
11350
11388
  /** Packed rgb (24-bit) pixels of the crop. */
11351
11389
  bytes: _instanceof(Uint8Array),
11352
11390
  width: number().int().positive(),
11353
- height: number().int().positive()
11391
+ height: number().int().positive(),
11392
+ /**
11393
+ * Which source served this crop, so a quality-sensitive consumer (the native
11394
+ * `keyFrame`) can reject a degraded fallback:
11395
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11396
+ * quality path).
11397
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11398
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11399
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11400
+ *
11401
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11402
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11403
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11404
+ */
11405
+ tier: _enum(["native", "ram-fullframe"]).optional()
11354
11406
  });
11355
11407
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11356
11408
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11590,7 +11642,14 @@ var RunnerCameraConfigSchema = object({
11590
11642
  * camera's detect node differs from its source-owner (P2d, gated by the
11591
11643
  * `remoteSourcingNodes` rollout setting).
11592
11644
  */
11593
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11645
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11646
+ /**
11647
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11648
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11649
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11650
+ * this only selects WHICH device pool of that node runs the session.
11651
+ */
11652
+ deviceKey: string().optional()
11594
11653
  });
11595
11654
  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;
11596
11655
  /**
@@ -11611,6 +11670,19 @@ var RunnerLocalLoadSchema = object({
11611
11670
  avgInferenceTimeMs: number(),
11612
11671
  /** Total queue depth across motion + detection queues. */
11613
11672
  queueDepthTotal: number(),
11673
+ /**
11674
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11675
+ * this runner currently has attached cameras on, so the orchestrator's second
11676
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11677
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11678
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11679
+ */
11680
+ devices: array(object({
11681
+ deviceKey: string(),
11682
+ backend: string(),
11683
+ attachedCameras: number(),
11684
+ queueDepthTotal: number()
11685
+ })).default([]),
11614
11686
  /** Hardware capability flags reported by this node. */
11615
11687
  hardware: object({
11616
11688
  hasGpu: boolean(),
@@ -13086,6 +13158,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13086
13158
  kind: "mutation",
13087
13159
  auth: "admin"
13088
13160
  });
13161
+ 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;
13162
+ new Set(Object.values(DeviceType));
13089
13163
  /**
13090
13164
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13091
13165
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -14684,7 +14758,8 @@ var LinkedDeviceSchema = object({
14684
14758
  deviceId: number(),
14685
14759
  name: string(),
14686
14760
  location: string().nullable(),
14687
- features: array(string())
14761
+ features: array(string()),
14762
+ producesTrackedEvents: boolean().optional()
14688
14763
  });
14689
14764
  var SavedDeviceRowSchema = object({
14690
14765
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16314,6 +16389,7 @@ var TrackSchema = object({
16314
16389
  deviceId: number(),
16315
16390
  className: string(),
16316
16391
  label: string().optional(),
16392
+ producingDeviceName: string().optional(),
16317
16393
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16318
16394
  source: TrackSourceSchema.optional(),
16319
16395
  firstSeen: number(),
@@ -16451,7 +16527,8 @@ var MediaFileKindEnum = _enum([
16451
16527
  "fullFrameBoxed",
16452
16528
  "faceCrop",
16453
16529
  "plateCrop",
16454
- "keyFrame"
16530
+ "keyFrame",
16531
+ "keyFrameSmall"
16455
16532
  ]);
16456
16533
  var MediaFileSchema = object({
16457
16534
  key: string(),
@@ -16780,13 +16857,11 @@ var PipelineTemplateSchema = object({
16780
16857
  createdAt: string(),
16781
16858
  updatedAt: string()
16782
16859
  });
16783
- var AgentAddonConfigSchema = object({
16784
- enabled: boolean(),
16860
+ var DeviceStepConfigSchema = object({
16785
16861
  modelId: string().optional(),
16786
- settings: record(string(), unknown()).readonly()
16862
+ settings: record(string(), unknown()).optional()
16787
16863
  });
16788
16864
  var AgentPipelineSettingsSchema = object({
16789
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16790
16865
  maxCameras: number().int().nonnegative().nullable().default(null),
16791
16866
  /** Per-node detection weight (relative share for the quota balancer). */
16792
16867
  detectWeight: number().positive().optional(),
@@ -16810,7 +16885,22 @@ var AgentPipelineSettingsSchema = object({
16810
16885
  * it already uses to reach the hub). Set this only when the auto-detected
16811
16886
  * address is wrong (multi-homed host, NAT, custom interface).
16812
16887
  */
16813
- reachableHost: string().optional()
16888
+ reachableHost: string().optional(),
16889
+ /**
16890
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16891
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16892
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16893
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16894
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16895
+ * the default model/settings for every camera landing on that accelerator;
16896
+ * a stepId absent ⇒ the step uses that device's format default.
16897
+ */
16898
+ inferenceDevices: record(string(), object({
16899
+ enabled: boolean(),
16900
+ weight: number().positive().optional(),
16901
+ maxSessions: number().int().positive().optional(),
16902
+ steps: record(string(), DeviceStepConfigSchema).optional()
16903
+ })).optional()
16814
16904
  });
16815
16905
  var CameraPipelineForAgentSchema = object({
16816
16906
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16820,14 +16910,13 @@ var CameraPipelineForAgentSchema = object({
16820
16910
  }).nullable()
16821
16911
  });
16822
16912
  var CameraStepOverridePatchSchema = object({
16823
- enabled: boolean().optional(),
16824
16913
  modelId: string().optional(),
16825
16914
  settings: record(string(), unknown()).readonly().optional()
16826
16915
  });
16827
16916
  var CameraPipelineSettingsSchema = object({
16828
16917
  pinnedAgentNodeId: string().optional(),
16829
16918
  stepToggles: record(string(), boolean()).optional(),
16830
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
16919
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
16831
16920
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
16832
16921
  });
16833
16922
  /**
@@ -17041,6 +17130,44 @@ var CameraStatusSchema = object({
17041
17130
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17042
17131
  fetchedAt: number()
17043
17132
  });
17133
+ var NodeInferenceDeviceSchema = object({
17134
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17135
+ key: string(),
17136
+ backend: string(),
17137
+ device: string(),
17138
+ format: _enum(MODEL_FORMATS),
17139
+ /** Whether the node's live probe reports the device as usable right now. */
17140
+ available: boolean(),
17141
+ /**
17142
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17143
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17144
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17145
+ * not a balanced target). An explicit stored value always wins; a stored-only
17146
+ * (unavailable) key keeps its stored value.
17147
+ */
17148
+ enabled: boolean(),
17149
+ /** Relative balancer weight for the enabled device (default 1). */
17150
+ weight: number(),
17151
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17152
+ maxSessions: number().nullable(),
17153
+ /** Object-detection model the executor defaults to for this deviceKey. */
17154
+ defaultModelId: string(),
17155
+ /**
17156
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17157
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17158
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17159
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17160
+ * available per format; this is the stored selection that becomes the
17161
+ * default for EVERY camera landing on this accelerator.
17162
+ */
17163
+ steps: record(string(), DeviceStepConfigSchema).optional()
17164
+ });
17165
+ var NodeInferenceDevicesSchema = object({
17166
+ nodeId: string(),
17167
+ /** False when the node's platform-probe was unreachable (no live device set). */
17168
+ reachable: boolean(),
17169
+ devices: array(NodeInferenceDeviceSchema).readonly()
17170
+ });
17044
17171
  method(object({
17045
17172
  deviceId: number(),
17046
17173
  agentNodeId: string()
@@ -17050,7 +17177,13 @@ method(object({
17050
17177
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17051
17178
  kind: "mutation",
17052
17179
  auth: "admin"
17053
- }), method(_void(), object({ migrated: number() }), {
17180
+ }), method(object({
17181
+ deviceId: number(),
17182
+ deviceKey: string()
17183
+ }), object({ success: literal(true) }), {
17184
+ kind: "mutation",
17185
+ auth: "admin"
17186
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17054
17187
  kind: "mutation",
17055
17188
  auth: "admin"
17056
17189
  }), 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({
@@ -17084,13 +17217,7 @@ method(object({
17084
17217
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17085
17218
  nodeId: string(),
17086
17219
  settings: AgentPipelineSettingsSchema
17087
- })).readonly()), method(object({
17088
- agentNodeId: string(),
17089
- defaults: record(string(), AgentAddonConfigSchema)
17090
- }), object({ success: literal(true) }), {
17091
- kind: "mutation",
17092
- auth: "admin"
17093
- }), method(object({ agentNodeId: string() }), object({
17220
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17094
17221
  success: boolean(),
17095
17222
  removed: boolean()
17096
17223
  }), {
@@ -17122,7 +17249,18 @@ method(object({
17122
17249
  }), object({ success: literal(true) }), {
17123
17250
  kind: "mutation",
17124
17251
  auth: "admin"
17125
- }), method(object({ agentNodeId: string() }), object({
17252
+ }), method(object({
17253
+ agentNodeId: string(),
17254
+ inferenceDevices: record(string(), object({
17255
+ enabled: boolean(),
17256
+ weight: number().positive().optional(),
17257
+ maxSessions: number().int().positive().optional(),
17258
+ steps: record(string(), DeviceStepConfigSchema).optional()
17259
+ }))
17260
+ }), object({ success: literal(true) }), {
17261
+ kind: "mutation",
17262
+ auth: "admin"
17263
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17126
17264
  success: literal(true),
17127
17265
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17128
17266
  effectiveModelId: string().nullable(),
@@ -17138,9 +17276,10 @@ method(object({
17138
17276
  }), object({ success: literal(true) }), {
17139
17277
  kind: "mutation",
17140
17278
  auth: "admin"
17141
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17279
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17142
17280
  deviceId: number(),
17143
17281
  agentNodeId: string(),
17282
+ deviceKey: string(),
17144
17283
  addonId: string(),
17145
17284
  patch: CameraStepOverridePatchSchema.nullable()
17146
17285
  }), object({ success: literal(true) }), {
@@ -17177,14 +17316,13 @@ method(object({
17177
17316
  });
17178
17317
  /**
17179
17318
  * server-management — per-NODE singleton capability for a node's ROOT
17180
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17181
- * agents).
17319
+ * package lifecycle (runtime-updatable node packages).
17182
17320
  *
17183
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17184
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17185
- * version describes the node. Updates install into
17186
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17187
- * starter (probation boot + auto-rollback to N-1).
17321
+ * Every node role runs the SAME root package (`@camstack/server`), which
17322
+ * carries the whole software stack in its npm dep tree, so ONE version
17323
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17324
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17325
+ * no auto-rollback).
17188
17326
  *
17189
17327
  * Providers:
17190
17328
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17292,7 +17430,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17292
17430
  /** Explicit target version; omitted = latest from the registry. */
17293
17431
  version: string().optional() }), ServerUpdateActionResultSchema, {
17294
17432
  kind: "mutation",
17295
- auth: "admin"
17433
+ auth: "admin",
17434
+ timeoutMs: 16 * 6e4
17296
17435
  }), method(_void(), ServerUpdateActionResultSchema, {
17297
17436
  kind: "mutation",
17298
17437
  auth: "admin"
@@ -18336,22 +18475,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18336
18475
  var RestartAddonResultSchema = unknown();
18337
18476
  var InstallPackageResultSchema = unknown();
18338
18477
  var ReloadPackagesResultSchema = unknown();
18339
- /**
18340
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18341
- * server restarts so the admin UI can react to the `restartingAt`
18342
- * timestamp (shows reconnect overlay). The transition from
18343
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18344
- * `system.restart-completed` event after the new process boots.
18345
- *
18346
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18347
- */
18348
- var UpdateFrameworkPackageResultSchema = object({
18349
- packageName: string(),
18350
- fromVersion: string(),
18351
- toVersion: string(),
18352
- /** Ms-epoch the server scheduled its self-restart. */
18353
- restartingAt: number()
18354
- });
18355
18478
  var BulkUpdateItemStatusSchema = _enum([
18356
18479
  "queued",
18357
18480
  "updating",
@@ -18479,13 +18602,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18479
18602
  }), object({ success: literal(true) }), {
18480
18603
  kind: "mutation",
18481
18604
  auth: "admin"
18482
- }), method(object({
18483
- packageName: string().min(1),
18484
- version: string().optional(),
18485
- deferRestart: boolean().optional()
18486
- }), UpdateFrameworkPackageResultSchema, {
18487
- kind: "mutation",
18488
- auth: "admin"
18489
18605
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18490
18606
  kind: "mutation",
18491
18607
  auth: "admin"
@@ -19351,10 +19467,10 @@ var TopologyCategorySchema = object({
19351
19467
  addons: array(TopologyCategoryAddonSchema).readonly()
19352
19468
  });
19353
19469
  /**
19354
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19355
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19356
- * version visibility for the Server management surface. Nullable: offline
19357
- * rows and pre-phase-2 nodes report none.
19470
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19471
+ * root package for every node role) as reported by its `registerNode`
19472
+ * manifest — version visibility for the Server management surface. Nullable:
19473
+ * offline rows and nodes that never reported one.
19358
19474
  */
19359
19475
  var TopologyRootPackageSchema = object({
19360
19476
  name: string(),
@@ -19742,17 +19858,28 @@ var PlatformScoreSchema = object({
19742
19858
  format: _enum([
19743
19859
  "onnx",
19744
19860
  "coreml",
19745
- "openvino"
19861
+ "openvino",
19862
+ "tflite"
19746
19863
  ]),
19747
19864
  score: number(),
19748
19865
  reason: string(),
19749
19866
  available: boolean()
19750
19867
  });
19868
+ var InferenceDeviceDescriptorSchema = object({
19869
+ key: string(),
19870
+ backend: string(),
19871
+ device: string(),
19872
+ format: ModelFormatSchema,
19873
+ runtime: literal("python"),
19874
+ score: number(),
19875
+ available: boolean()
19876
+ });
19751
19877
  var PlatformCapabilitiesSchema = object({
19752
19878
  hardware: HardwareInfoSchema,
19753
19879
  scores: array(PlatformScoreSchema).readonly(),
19754
19880
  bestScore: PlatformScoreSchema,
19755
- pythonPath: string().nullable()
19881
+ pythonPath: string().nullable(),
19882
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19756
19883
  });
19757
19884
  var ModelRequirementSchema = object({
19758
19885
  modelId: string(),
@@ -20631,12 +20758,6 @@ Object.freeze({
20631
20758
  addonId: null,
20632
20759
  access: "delete"
20633
20760
  },
20634
- "addons.updateFrameworkPackage": {
20635
- capName: "addons",
20636
- capScope: "system",
20637
- addonId: null,
20638
- access: "create"
20639
- },
20640
20761
  "addons.updatePackage": {
20641
20762
  capName: "addons",
20642
20763
  capScope: "system",
@@ -23409,12 +23530,6 @@ Object.freeze({
23409
23530
  addonId: null,
23410
23531
  access: "view"
23411
23532
  },
23412
- "pipelineExecutor.reprobeEngine": {
23413
- capName: "pipeline-executor",
23414
- capScope: "system",
23415
- addonId: null,
23416
- access: "create"
23417
- },
23418
23533
  "pipelineExecutor.runAudioTest": {
23419
23534
  capName: "pipeline-executor",
23420
23535
  capScope: "system",
@@ -23565,6 +23680,12 @@ Object.freeze({
23565
23680
  addonId: null,
23566
23681
  access: "view"
23567
23682
  },
23683
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23684
+ capName: "pipeline-orchestrator",
23685
+ capScope: "system",
23686
+ addonId: null,
23687
+ access: "view"
23688
+ },
23568
23689
  "pipelineOrchestrator.getPipelineAssignment": {
23569
23690
  capName: "pipeline-orchestrator",
23570
23691
  capScope: "system",
@@ -23577,6 +23698,12 @@ Object.freeze({
23577
23698
  addonId: null,
23578
23699
  access: "view"
23579
23700
  },
23701
+ "pipelineOrchestrator.getPipelineDevicePin": {
23702
+ capName: "pipeline-orchestrator",
23703
+ capScope: "system",
23704
+ addonId: null,
23705
+ access: "view"
23706
+ },
23580
23707
  "pipelineOrchestrator.listAgentSettings": {
23581
23708
  capName: "pipeline-orchestrator",
23582
23709
  capScope: "system",
@@ -23619,19 +23746,19 @@ Object.freeze({
23619
23746
  addonId: null,
23620
23747
  access: "create"
23621
23748
  },
23622
- "pipelineOrchestrator.setAgentAddonDefaults": {
23749
+ "pipelineOrchestrator.setAgentCapabilities": {
23623
23750
  capName: "pipeline-orchestrator",
23624
23751
  capScope: "system",
23625
23752
  addonId: null,
23626
23753
  access: "create"
23627
23754
  },
23628
- "pipelineOrchestrator.setAgentCapabilities": {
23755
+ "pipelineOrchestrator.setAgentDetectWeight": {
23629
23756
  capName: "pipeline-orchestrator",
23630
23757
  capScope: "system",
23631
23758
  addonId: null,
23632
23759
  access: "create"
23633
23760
  },
23634
- "pipelineOrchestrator.setAgentDetectWeight": {
23761
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23635
23762
  capName: "pipeline-orchestrator",
23636
23763
  capScope: "system",
23637
23764
  addonId: null,
@@ -23673,6 +23800,12 @@ Object.freeze({
23673
23800
  addonId: null,
23674
23801
  access: "create"
23675
23802
  },
23803
+ "pipelineOrchestrator.setPipelineDevicePin": {
23804
+ capName: "pipeline-orchestrator",
23805
+ capScope: "system",
23806
+ addonId: null,
23807
+ access: "create"
23808
+ },
23676
23809
  "pipelineOrchestrator.unassignAudio": {
23677
23810
  capName: "pipeline-orchestrator",
23678
23811
  capScope: "system",
@@ -25225,32 +25358,6 @@ Object.freeze({
25225
25358
  "network-access": "ingress",
25226
25359
  "smtp-provider": "email"
25227
25360
  });
25228
- var frameworkSwapPackageSchema = object({
25229
- name: string(),
25230
- stagedPath: string(),
25231
- backupPath: string(),
25232
- toVersion: string(),
25233
- fromVersion: string().nullable()
25234
- });
25235
- object({
25236
- jobId: string(),
25237
- taskId: string(),
25238
- packages: array(frameworkSwapPackageSchema),
25239
- requestedAtMs: number(),
25240
- schemaVersion: literal(1)
25241
- });
25242
- object({
25243
- jobId: string(),
25244
- taskId: string(),
25245
- backups: array(object({
25246
- name: string(),
25247
- backupPath: string(),
25248
- livePath: string()
25249
- })),
25250
- appliedAtMs: number(),
25251
- bootAttempts: number(),
25252
- schemaVersion: literal(1)
25253
- });
25254
25361
  /**
25255
25362
  * Deterministic SHA-256 hash of an arbitrary serialisable value. The
25256
25363
  * canonical form sorts object keys alphabetically at every depth so two
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-hap",
3
- "version": "1.1.28",
3
+ "version": "1.2.1",
4
4
  "description": "HomeKit (HAP) bridge exporter for CamStack devices. Publishes a bridged accessory per exposed device — MotionSensor in this MVP; Camera/Doorbell/Switch/Light follow.",
5
5
  "keywords": [
6
6
  "camstack",