@camstack/addon-import-alexa 0.1.25 → 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
@@ -7137,6 +7137,17 @@ var ModelCatalogEntrySchema = object({
7137
7137
  "imagenet",
7138
7138
  "none"
7139
7139
  ]).optional(),
7140
+ /**
7141
+ * The model already applies softmax IN-GRAPH — its raw output is a
7142
+ * probability distribution, not logits. When set, the `softmax`
7143
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7144
+ * probability vector collapses it toward uniform (top-1 score craters far
7145
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7146
+ * the output is raw logits and the postprocessor applies softmax (the normal
7147
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7148
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7149
+ */
7150
+ outputProbabilities: boolean().optional(),
7140
7151
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7141
7152
  /**
7142
7153
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12544,10 +12555,7 @@ var ConfigUISchemaNullableBridge = custom();
12544
12555
  var InferenceCapabilitiesBridge = custom();
12545
12556
  var ModelAvailabilityListBridge = custom();
12546
12557
  var PipelineRunResultBridge = custom();
12547
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12548
- kind: "mutation",
12549
- auth: "admin"
12550
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12558
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12551
12559
  modelId: string(),
12552
12560
  settings: record(string(), unknown()).readonly()
12553
12561
  }))), method(object({ steps: record(string(), object({
@@ -12607,13 +12615,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12607
12615
  * (inputClasses ≠ null) are skipped and served per-track via
12608
12616
  * pipelineRunner.runDetailSubtree (two-plane design).
12609
12617
  */
12610
- plane: _enum(["full", "frame"]).optional()
12618
+ plane: _enum(["full", "frame"]).optional(),
12619
+ /**
12620
+ * Inference-device selector (Phase 2 multi-device). Format
12621
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12622
+ * Omitted ⇒ the runner's default device (current single-engine
12623
+ * behaviour). Selects WHICH device pool of the node runs the call.
12624
+ */
12625
+ deviceKey: string().optional()
12611
12626
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12612
12627
  engine: PipelineEngineChoiceSchema.optional(),
12613
12628
  steps: array(PipelineStepInputSchema).min(1),
12614
12629
  frames: array(FrameInputSchema).min(1).max(255),
12615
12630
  deviceId: number().optional(),
12616
- sessionId: string().optional()
12631
+ sessionId: string().optional(),
12632
+ /**
12633
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12634
+ * the batch to the Python pool's bench preprocess cache
12635
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12636
+ * preprocessed ONCE and every later inference is a pure-inference cache
12637
+ * hit — the sustained-throughput run measures inference, not
12638
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12639
+ * full preprocess every call, correct). Fresh per sustained run;
12640
+ * released via `uncacheFrame`.
12641
+ */
12642
+ frameId: number().int().nonnegative().optional(),
12643
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12644
+ deviceKey: string().optional()
12617
12645
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12618
12646
  data: _instanceof(Uint8Array),
12619
12647
  width: number().int().positive(),
@@ -12645,8 +12673,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12645
12673
  * - `runtime` — main camera-serving engine (no idle TTL).
12646
12674
  * - `warm-override` — benchmark/test override held in the warm
12647
12675
  * cache; auto-disposed after the idle TTL.
12676
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12677
+ * multi-device, keyed by `deviceKey`) resolved
12678
+ * via `resolveDeviceFactory`. Runs alongside the
12679
+ * `runtime` engine on a DIFFERENT accelerator
12680
+ * (NPU / iGPU / Coral) — this is how the
12681
+ * Engines tab shows all pools running at once.
12648
12682
  */
12649
- kind: _enum(["runtime", "warm-override"]),
12683
+ kind: _enum([
12684
+ "runtime",
12685
+ "warm-override",
12686
+ "device-pool"
12687
+ ]),
12650
12688
  /** Native pid of the underlying Python pool (null when no pool). */
12651
12689
  poolPid: number().nullable(),
12652
12690
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -13021,7 +13059,14 @@ var RunnerCameraConfigSchema = object({
13021
13059
  * camera's detect node differs from its source-owner (P2d, gated by the
13022
13060
  * `remoteSourcingNodes` rollout setting).
13023
13061
  */
13024
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13062
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13063
+ /**
13064
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13065
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13066
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13067
+ * this only selects WHICH device pool of that node runs the session.
13068
+ */
13069
+ deviceKey: string().optional()
13025
13070
  });
13026
13071
  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;
13027
13072
  /**
@@ -13042,6 +13087,19 @@ var RunnerLocalLoadSchema = object({
13042
13087
  avgInferenceTimeMs: number(),
13043
13088
  /** Total queue depth across motion + detection queues. */
13044
13089
  queueDepthTotal: number(),
13090
+ /**
13091
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13092
+ * this runner currently has attached cameras on, so the orchestrator's second
13093
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13094
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13095
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13096
+ */
13097
+ devices: array(object({
13098
+ deviceKey: string(),
13099
+ backend: string(),
13100
+ attachedCameras: number(),
13101
+ queueDepthTotal: number()
13102
+ })).default([]),
13045
13103
  /** Hardware capability flags reported by this node. */
13046
13104
  hardware: object({
13047
13105
  hasGpu: boolean(),
@@ -16190,6 +16248,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16190
16248
  return toDeviceSummary(device, this.addonId);
16191
16249
  }
16192
16250
  };
16251
+ 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;
16252
+ new Set(Object.values(DeviceType));
16193
16253
  /**
16194
16254
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16195
16255
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19944,13 +20004,11 @@ var PipelineTemplateSchema = object({
19944
20004
  createdAt: string(),
19945
20005
  updatedAt: string()
19946
20006
  });
19947
- var AgentAddonConfigSchema = object({
19948
- enabled: boolean(),
20007
+ var DeviceStepConfigSchema = object({
19949
20008
  modelId: string().optional(),
19950
- settings: record(string(), unknown()).readonly()
20009
+ settings: record(string(), unknown()).optional()
19951
20010
  });
19952
20011
  var AgentPipelineSettingsSchema = object({
19953
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19954
20012
  maxCameras: number().int().nonnegative().nullable().default(null),
19955
20013
  /** Per-node detection weight (relative share for the quota balancer). */
19956
20014
  detectWeight: number().positive().optional(),
@@ -19974,7 +20032,22 @@ var AgentPipelineSettingsSchema = object({
19974
20032
  * it already uses to reach the hub). Set this only when the auto-detected
19975
20033
  * address is wrong (multi-homed host, NAT, custom interface).
19976
20034
  */
19977
- reachableHost: string().optional()
20035
+ reachableHost: string().optional(),
20036
+ /**
20037
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20038
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20039
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20040
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20041
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20042
+ * the default model/settings for every camera landing on that accelerator;
20043
+ * a stepId absent ⇒ the step uses that device's format default.
20044
+ */
20045
+ inferenceDevices: record(string(), object({
20046
+ enabled: boolean(),
20047
+ weight: number().positive().optional(),
20048
+ maxSessions: number().int().positive().optional(),
20049
+ steps: record(string(), DeviceStepConfigSchema).optional()
20050
+ })).optional()
19978
20051
  });
19979
20052
  var CameraPipelineForAgentSchema = object({
19980
20053
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19984,14 +20057,13 @@ var CameraPipelineForAgentSchema = object({
19984
20057
  }).nullable()
19985
20058
  });
19986
20059
  var CameraStepOverridePatchSchema = object({
19987
- enabled: boolean().optional(),
19988
20060
  modelId: string().optional(),
19989
20061
  settings: record(string(), unknown()).readonly().optional()
19990
20062
  });
19991
20063
  var CameraPipelineSettingsSchema = object({
19992
20064
  pinnedAgentNodeId: string().optional(),
19993
20065
  stepToggles: record(string(), boolean()).optional(),
19994
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20066
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19995
20067
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19996
20068
  });
19997
20069
  /**
@@ -20205,6 +20277,44 @@ var CameraStatusSchema = object({
20205
20277
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20206
20278
  fetchedAt: number()
20207
20279
  });
20280
+ var NodeInferenceDeviceSchema = object({
20281
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20282
+ key: string(),
20283
+ backend: string(),
20284
+ device: string(),
20285
+ format: _enum(MODEL_FORMATS),
20286
+ /** Whether the node's live probe reports the device as usable right now. */
20287
+ available: boolean(),
20288
+ /**
20289
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20290
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20291
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20292
+ * not a balanced target). An explicit stored value always wins; a stored-only
20293
+ * (unavailable) key keeps its stored value.
20294
+ */
20295
+ enabled: boolean(),
20296
+ /** Relative balancer weight for the enabled device (default 1). */
20297
+ weight: number(),
20298
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20299
+ maxSessions: number().nullable(),
20300
+ /** Object-detection model the executor defaults to for this deviceKey. */
20301
+ defaultModelId: string(),
20302
+ /**
20303
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20304
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20305
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20306
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20307
+ * available per format; this is the stored selection that becomes the
20308
+ * default for EVERY camera landing on this accelerator.
20309
+ */
20310
+ steps: record(string(), DeviceStepConfigSchema).optional()
20311
+ });
20312
+ var NodeInferenceDevicesSchema = object({
20313
+ nodeId: string(),
20314
+ /** False when the node's platform-probe was unreachable (no live device set). */
20315
+ reachable: boolean(),
20316
+ devices: array(NodeInferenceDeviceSchema).readonly()
20317
+ });
20208
20318
  method(object({
20209
20319
  deviceId: number(),
20210
20320
  agentNodeId: string()
@@ -20214,7 +20324,13 @@ method(object({
20214
20324
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20215
20325
  kind: "mutation",
20216
20326
  auth: "admin"
20217
- }), method(_void(), object({ migrated: number() }), {
20327
+ }), method(object({
20328
+ deviceId: number(),
20329
+ deviceKey: string()
20330
+ }), object({ success: literal(true) }), {
20331
+ kind: "mutation",
20332
+ auth: "admin"
20333
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20218
20334
  kind: "mutation",
20219
20335
  auth: "admin"
20220
20336
  }), 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({
@@ -20248,13 +20364,7 @@ method(object({
20248
20364
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20249
20365
  nodeId: string(),
20250
20366
  settings: AgentPipelineSettingsSchema
20251
- })).readonly()), method(object({
20252
- agentNodeId: string(),
20253
- defaults: record(string(), AgentAddonConfigSchema)
20254
- }), object({ success: literal(true) }), {
20255
- kind: "mutation",
20256
- auth: "admin"
20257
- }), method(object({ agentNodeId: string() }), object({
20367
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20258
20368
  success: boolean(),
20259
20369
  removed: boolean()
20260
20370
  }), {
@@ -20286,7 +20396,18 @@ method(object({
20286
20396
  }), object({ success: literal(true) }), {
20287
20397
  kind: "mutation",
20288
20398
  auth: "admin"
20289
- }), method(object({ agentNodeId: string() }), object({
20399
+ }), method(object({
20400
+ agentNodeId: string(),
20401
+ inferenceDevices: record(string(), object({
20402
+ enabled: boolean(),
20403
+ weight: number().positive().optional(),
20404
+ maxSessions: number().int().positive().optional(),
20405
+ steps: record(string(), DeviceStepConfigSchema).optional()
20406
+ }))
20407
+ }), object({ success: literal(true) }), {
20408
+ kind: "mutation",
20409
+ auth: "admin"
20410
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20290
20411
  success: literal(true),
20291
20412
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20292
20413
  effectiveModelId: string().nullable(),
@@ -20302,9 +20423,10 @@ method(object({
20302
20423
  }), object({ success: literal(true) }), {
20303
20424
  kind: "mutation",
20304
20425
  auth: "admin"
20305
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20426
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20306
20427
  deviceId: number(),
20307
20428
  agentNodeId: string(),
20429
+ deviceKey: string(),
20308
20430
  addonId: string(),
20309
20431
  patch: CameraStepOverridePatchSchema.nullable()
20310
20432
  }), object({ success: literal(true) }), {
@@ -20341,14 +20463,13 @@ method(object({
20341
20463
  });
20342
20464
  /**
20343
20465
  * server-management — per-NODE singleton capability for a node's ROOT
20344
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20345
- * agents).
20466
+ * package lifecycle (runtime-updatable node packages).
20346
20467
  *
20347
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20348
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20349
- * version describes the node. Updates install into
20350
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20351
- * starter (probation boot + auto-rollback to N-1).
20468
+ * Every node role runs the SAME root package (`@camstack/server`), which
20469
+ * carries the whole software stack in its npm dep tree, so ONE version
20470
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20471
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20472
+ * no auto-rollback).
20352
20473
  *
20353
20474
  * Providers:
20354
20475
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20456,7 +20577,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20456
20577
  /** Explicit target version; omitted = latest from the registry. */
20457
20578
  version: string().optional() }), ServerUpdateActionResultSchema, {
20458
20579
  kind: "mutation",
20459
- auth: "admin"
20580
+ auth: "admin",
20581
+ timeoutMs: 16 * 6e4
20460
20582
  }), method(_void(), ServerUpdateActionResultSchema, {
20461
20583
  kind: "mutation",
20462
20584
  auth: "admin"
@@ -21500,22 +21622,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21500
21622
  var RestartAddonResultSchema = unknown();
21501
21623
  var InstallPackageResultSchema = unknown();
21502
21624
  var ReloadPackagesResultSchema = unknown();
21503
- /**
21504
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21505
- * server restarts so the admin UI can react to the `restartingAt`
21506
- * timestamp (shows reconnect overlay). The transition from
21507
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21508
- * `system.restart-completed` event after the new process boots.
21509
- *
21510
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21511
- */
21512
- var UpdateFrameworkPackageResultSchema = object({
21513
- packageName: string(),
21514
- fromVersion: string(),
21515
- toVersion: string(),
21516
- /** Ms-epoch the server scheduled its self-restart. */
21517
- restartingAt: number()
21518
- });
21519
21625
  var BulkUpdateItemStatusSchema = _enum([
21520
21626
  "queued",
21521
21627
  "updating",
@@ -21643,13 +21749,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21643
21749
  }), object({ success: literal(true) }), {
21644
21750
  kind: "mutation",
21645
21751
  auth: "admin"
21646
- }), method(object({
21647
- packageName: string().min(1),
21648
- version: string().optional(),
21649
- deferRestart: boolean().optional()
21650
- }), UpdateFrameworkPackageResultSchema, {
21651
- kind: "mutation",
21652
- auth: "admin"
21653
21752
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21654
21753
  kind: "mutation",
21655
21754
  auth: "admin"
@@ -22532,10 +22631,10 @@ var TopologyCategorySchema = object({
22532
22631
  addons: array(TopologyCategoryAddonSchema).readonly()
22533
22632
  });
22534
22633
  /**
22535
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22536
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22537
- * version visibility for the Server management surface. Nullable: offline
22538
- * rows and pre-phase-2 nodes report none.
22634
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22635
+ * root package for every node role) as reported by its `registerNode`
22636
+ * manifest — version visibility for the Server management surface. Nullable:
22637
+ * offline rows and nodes that never reported one.
22539
22638
  */
22540
22639
  var TopologyRootPackageSchema = object({
22541
22640
  name: string(),
@@ -22923,17 +23022,28 @@ var PlatformScoreSchema = object({
22923
23022
  format: _enum([
22924
23023
  "onnx",
22925
23024
  "coreml",
22926
- "openvino"
23025
+ "openvino",
23026
+ "tflite"
22927
23027
  ]),
22928
23028
  score: number(),
22929
23029
  reason: string(),
22930
23030
  available: boolean()
22931
23031
  });
23032
+ var InferenceDeviceDescriptorSchema = object({
23033
+ key: string(),
23034
+ backend: string(),
23035
+ device: string(),
23036
+ format: ModelFormatSchema,
23037
+ runtime: literal("python"),
23038
+ score: number(),
23039
+ available: boolean()
23040
+ });
22932
23041
  var PlatformCapabilitiesSchema = object({
22933
23042
  hardware: HardwareInfoSchema,
22934
23043
  scores: array(PlatformScoreSchema).readonly(),
22935
23044
  bestScore: PlatformScoreSchema,
22936
- pythonPath: string().nullable()
23045
+ pythonPath: string().nullable(),
23046
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22937
23047
  });
22938
23048
  var ModelRequirementSchema = object({
22939
23049
  modelId: string(),
@@ -23812,12 +23922,6 @@ Object.freeze({
23812
23922
  addonId: null,
23813
23923
  access: "delete"
23814
23924
  },
23815
- "addons.updateFrameworkPackage": {
23816
- capName: "addons",
23817
- capScope: "system",
23818
- addonId: null,
23819
- access: "create"
23820
- },
23821
23925
  "addons.updatePackage": {
23822
23926
  capName: "addons",
23823
23927
  capScope: "system",
@@ -26590,12 +26694,6 @@ Object.freeze({
26590
26694
  addonId: null,
26591
26695
  access: "view"
26592
26696
  },
26593
- "pipelineExecutor.reprobeEngine": {
26594
- capName: "pipeline-executor",
26595
- capScope: "system",
26596
- addonId: null,
26597
- access: "create"
26598
- },
26599
26697
  "pipelineExecutor.runAudioTest": {
26600
26698
  capName: "pipeline-executor",
26601
26699
  capScope: "system",
@@ -26746,6 +26844,12 @@ Object.freeze({
26746
26844
  addonId: null,
26747
26845
  access: "view"
26748
26846
  },
26847
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26848
+ capName: "pipeline-orchestrator",
26849
+ capScope: "system",
26850
+ addonId: null,
26851
+ access: "view"
26852
+ },
26749
26853
  "pipelineOrchestrator.getPipelineAssignment": {
26750
26854
  capName: "pipeline-orchestrator",
26751
26855
  capScope: "system",
@@ -26758,6 +26862,12 @@ Object.freeze({
26758
26862
  addonId: null,
26759
26863
  access: "view"
26760
26864
  },
26865
+ "pipelineOrchestrator.getPipelineDevicePin": {
26866
+ capName: "pipeline-orchestrator",
26867
+ capScope: "system",
26868
+ addonId: null,
26869
+ access: "view"
26870
+ },
26761
26871
  "pipelineOrchestrator.listAgentSettings": {
26762
26872
  capName: "pipeline-orchestrator",
26763
26873
  capScope: "system",
@@ -26800,19 +26910,19 @@ Object.freeze({
26800
26910
  addonId: null,
26801
26911
  access: "create"
26802
26912
  },
26803
- "pipelineOrchestrator.setAgentAddonDefaults": {
26913
+ "pipelineOrchestrator.setAgentCapabilities": {
26804
26914
  capName: "pipeline-orchestrator",
26805
26915
  capScope: "system",
26806
26916
  addonId: null,
26807
26917
  access: "create"
26808
26918
  },
26809
- "pipelineOrchestrator.setAgentCapabilities": {
26919
+ "pipelineOrchestrator.setAgentDetectWeight": {
26810
26920
  capName: "pipeline-orchestrator",
26811
26921
  capScope: "system",
26812
26922
  addonId: null,
26813
26923
  access: "create"
26814
26924
  },
26815
- "pipelineOrchestrator.setAgentDetectWeight": {
26925
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26816
26926
  capName: "pipeline-orchestrator",
26817
26927
  capScope: "system",
26818
26928
  addonId: null,
@@ -26854,6 +26964,12 @@ Object.freeze({
26854
26964
  addonId: null,
26855
26965
  access: "create"
26856
26966
  },
26967
+ "pipelineOrchestrator.setPipelineDevicePin": {
26968
+ capName: "pipeline-orchestrator",
26969
+ capScope: "system",
26970
+ addonId: null,
26971
+ access: "create"
26972
+ },
26857
26973
  "pipelineOrchestrator.unassignAudio": {
26858
26974
  capName: "pipeline-orchestrator",
26859
26975
  capScope: "system",
@@ -28406,32 +28522,6 @@ Object.freeze({
28406
28522
  "network-access": "ingress",
28407
28523
  "smtp-provider": "email"
28408
28524
  });
28409
- var frameworkSwapPackageSchema = object({
28410
- name: string(),
28411
- stagedPath: string(),
28412
- backupPath: string(),
28413
- toVersion: string(),
28414
- fromVersion: string().nullable()
28415
- });
28416
- object({
28417
- jobId: string(),
28418
- taskId: string(),
28419
- packages: array(frameworkSwapPackageSchema),
28420
- requestedAtMs: number(),
28421
- schemaVersion: literal(1)
28422
- });
28423
- object({
28424
- jobId: string(),
28425
- taskId: string(),
28426
- backups: array(object({
28427
- name: string(),
28428
- backupPath: string(),
28429
- livePath: string()
28430
- })),
28431
- appliedAtMs: number(),
28432
- bootAttempts: number(),
28433
- schemaVersion: literal(1)
28434
- });
28435
28525
  //#endregion
28436
28526
  //#region src/config.ts
28437
28527
  /**
package/dist/addon.mjs CHANGED
@@ -7137,6 +7137,17 @@ var ModelCatalogEntrySchema = object({
7137
7137
  "imagenet",
7138
7138
  "none"
7139
7139
  ]).optional(),
7140
+ /**
7141
+ * The model already applies softmax IN-GRAPH — its raw output is a
7142
+ * probability distribution, not logits. When set, the `softmax`
7143
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7144
+ * probability vector collapses it toward uniform (top-1 score craters far
7145
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7146
+ * the output is raw logits and the postprocessor applies softmax (the normal
7147
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7148
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7149
+ */
7150
+ outputProbabilities: boolean().optional(),
7140
7151
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7141
7152
  /**
7142
7153
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12544,10 +12555,7 @@ var ConfigUISchemaNullableBridge = custom();
12544
12555
  var InferenceCapabilitiesBridge = custom();
12545
12556
  var ModelAvailabilityListBridge = custom();
12546
12557
  var PipelineRunResultBridge = custom();
12547
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12548
- kind: "mutation",
12549
- auth: "admin"
12550
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12558
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12551
12559
  modelId: string(),
12552
12560
  settings: record(string(), unknown()).readonly()
12553
12561
  }))), method(object({ steps: record(string(), object({
@@ -12607,13 +12615,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12607
12615
  * (inputClasses ≠ null) are skipped and served per-track via
12608
12616
  * pipelineRunner.runDetailSubtree (two-plane design).
12609
12617
  */
12610
- plane: _enum(["full", "frame"]).optional()
12618
+ plane: _enum(["full", "frame"]).optional(),
12619
+ /**
12620
+ * Inference-device selector (Phase 2 multi-device). Format
12621
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12622
+ * Omitted ⇒ the runner's default device (current single-engine
12623
+ * behaviour). Selects WHICH device pool of the node runs the call.
12624
+ */
12625
+ deviceKey: string().optional()
12611
12626
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12612
12627
  engine: PipelineEngineChoiceSchema.optional(),
12613
12628
  steps: array(PipelineStepInputSchema).min(1),
12614
12629
  frames: array(FrameInputSchema).min(1).max(255),
12615
12630
  deviceId: number().optional(),
12616
- sessionId: string().optional()
12631
+ sessionId: string().optional(),
12632
+ /**
12633
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12634
+ * the batch to the Python pool's bench preprocess cache
12635
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12636
+ * preprocessed ONCE and every later inference is a pure-inference cache
12637
+ * hit — the sustained-throughput run measures inference, not
12638
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12639
+ * full preprocess every call, correct). Fresh per sustained run;
12640
+ * released via `uncacheFrame`.
12641
+ */
12642
+ frameId: number().int().nonnegative().optional(),
12643
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12644
+ deviceKey: string().optional()
12617
12645
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12618
12646
  data: _instanceof(Uint8Array),
12619
12647
  width: number().int().positive(),
@@ -12645,8 +12673,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12645
12673
  * - `runtime` — main camera-serving engine (no idle TTL).
12646
12674
  * - `warm-override` — benchmark/test override held in the warm
12647
12675
  * cache; auto-disposed after the idle TTL.
12676
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12677
+ * multi-device, keyed by `deviceKey`) resolved
12678
+ * via `resolveDeviceFactory`. Runs alongside the
12679
+ * `runtime` engine on a DIFFERENT accelerator
12680
+ * (NPU / iGPU / Coral) — this is how the
12681
+ * Engines tab shows all pools running at once.
12648
12682
  */
12649
- kind: _enum(["runtime", "warm-override"]),
12683
+ kind: _enum([
12684
+ "runtime",
12685
+ "warm-override",
12686
+ "device-pool"
12687
+ ]),
12650
12688
  /** Native pid of the underlying Python pool (null when no pool). */
12651
12689
  poolPid: number().nullable(),
12652
12690
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -13021,7 +13059,14 @@ var RunnerCameraConfigSchema = object({
13021
13059
  * camera's detect node differs from its source-owner (P2d, gated by the
13022
13060
  * `remoteSourcingNodes` rollout setting).
13023
13061
  */
13024
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
13062
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
13063
+ /**
13064
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
13065
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
13066
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
13067
+ * this only selects WHICH device pool of that node runs the session.
13068
+ */
13069
+ deviceKey: string().optional()
13025
13070
  });
13026
13071
  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;
13027
13072
  /**
@@ -13042,6 +13087,19 @@ var RunnerLocalLoadSchema = object({
13042
13087
  avgInferenceTimeMs: number(),
13043
13088
  /** Total queue depth across motion + detection queues. */
13044
13089
  queueDepthTotal: number(),
13090
+ /**
13091
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
13092
+ * this runner currently has attached cameras on, so the orchestrator's second
13093
+ * `balance()` pass (over a node's devices) weights on real per-pool session
13094
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
13095
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
13096
+ */
13097
+ devices: array(object({
13098
+ deviceKey: string(),
13099
+ backend: string(),
13100
+ attachedCameras: number(),
13101
+ queueDepthTotal: number()
13102
+ })).default([]),
13045
13103
  /** Hardware capability flags reported by this node. */
13046
13104
  hardware: object({
13047
13105
  hasGpu: boolean(),
@@ -16190,6 +16248,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16190
16248
  return toDeviceSummary(device, this.addonId);
16191
16249
  }
16192
16250
  };
16251
+ 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;
16252
+ new Set(Object.values(DeviceType));
16193
16253
  /**
16194
16254
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16195
16255
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -19944,13 +20004,11 @@ var PipelineTemplateSchema = object({
19944
20004
  createdAt: string(),
19945
20005
  updatedAt: string()
19946
20006
  });
19947
- var AgentAddonConfigSchema = object({
19948
- enabled: boolean(),
20007
+ var DeviceStepConfigSchema = object({
19949
20008
  modelId: string().optional(),
19950
- settings: record(string(), unknown()).readonly()
20009
+ settings: record(string(), unknown()).optional()
19951
20010
  });
19952
20011
  var AgentPipelineSettingsSchema = object({
19953
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19954
20012
  maxCameras: number().int().nonnegative().nullable().default(null),
19955
20013
  /** Per-node detection weight (relative share for the quota balancer). */
19956
20014
  detectWeight: number().positive().optional(),
@@ -19974,7 +20032,22 @@ var AgentPipelineSettingsSchema = object({
19974
20032
  * it already uses to reach the hub). Set this only when the auto-detected
19975
20033
  * address is wrong (multi-homed host, NAT, custom interface).
19976
20034
  */
19977
- reachableHost: string().optional()
20035
+ reachableHost: string().optional(),
20036
+ /**
20037
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
20038
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
20039
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
20040
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
20041
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
20042
+ * the default model/settings for every camera landing on that accelerator;
20043
+ * a stepId absent ⇒ the step uses that device's format default.
20044
+ */
20045
+ inferenceDevices: record(string(), object({
20046
+ enabled: boolean(),
20047
+ weight: number().positive().optional(),
20048
+ maxSessions: number().int().positive().optional(),
20049
+ steps: record(string(), DeviceStepConfigSchema).optional()
20050
+ })).optional()
19978
20051
  });
19979
20052
  var CameraPipelineForAgentSchema = object({
19980
20053
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19984,14 +20057,13 @@ var CameraPipelineForAgentSchema = object({
19984
20057
  }).nullable()
19985
20058
  });
19986
20059
  var CameraStepOverridePatchSchema = object({
19987
- enabled: boolean().optional(),
19988
20060
  modelId: string().optional(),
19989
20061
  settings: record(string(), unknown()).readonly().optional()
19990
20062
  });
19991
20063
  var CameraPipelineSettingsSchema = object({
19992
20064
  pinnedAgentNodeId: string().optional(),
19993
20065
  stepToggles: record(string(), boolean()).optional(),
19994
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
20066
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19995
20067
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19996
20068
  });
19997
20069
  /**
@@ -20205,6 +20277,44 @@ var CameraStatusSchema = object({
20205
20277
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
20206
20278
  fetchedAt: number()
20207
20279
  });
20280
+ var NodeInferenceDeviceSchema = object({
20281
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20282
+ key: string(),
20283
+ backend: string(),
20284
+ device: string(),
20285
+ format: _enum(MODEL_FORMATS),
20286
+ /** Whether the node's live probe reports the device as usable right now. */
20287
+ available: boolean(),
20288
+ /**
20289
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20290
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20291
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20292
+ * not a balanced target). An explicit stored value always wins; a stored-only
20293
+ * (unavailable) key keeps its stored value.
20294
+ */
20295
+ enabled: boolean(),
20296
+ /** Relative balancer weight for the enabled device (default 1). */
20297
+ weight: number(),
20298
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20299
+ maxSessions: number().nullable(),
20300
+ /** Object-detection model the executor defaults to for this deviceKey. */
20301
+ defaultModelId: string(),
20302
+ /**
20303
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20304
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20305
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20306
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20307
+ * available per format; this is the stored selection that becomes the
20308
+ * default for EVERY camera landing on this accelerator.
20309
+ */
20310
+ steps: record(string(), DeviceStepConfigSchema).optional()
20311
+ });
20312
+ var NodeInferenceDevicesSchema = object({
20313
+ nodeId: string(),
20314
+ /** False when the node's platform-probe was unreachable (no live device set). */
20315
+ reachable: boolean(),
20316
+ devices: array(NodeInferenceDeviceSchema).readonly()
20317
+ });
20208
20318
  method(object({
20209
20319
  deviceId: number(),
20210
20320
  agentNodeId: string()
@@ -20214,7 +20324,13 @@ method(object({
20214
20324
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
20215
20325
  kind: "mutation",
20216
20326
  auth: "admin"
20217
- }), method(_void(), object({ migrated: number() }), {
20327
+ }), method(object({
20328
+ deviceId: number(),
20329
+ deviceKey: string()
20330
+ }), object({ success: literal(true) }), {
20331
+ kind: "mutation",
20332
+ auth: "admin"
20333
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
20218
20334
  kind: "mutation",
20219
20335
  auth: "admin"
20220
20336
  }), 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({
@@ -20248,13 +20364,7 @@ method(object({
20248
20364
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20249
20365
  nodeId: string(),
20250
20366
  settings: AgentPipelineSettingsSchema
20251
- })).readonly()), method(object({
20252
- agentNodeId: string(),
20253
- defaults: record(string(), AgentAddonConfigSchema)
20254
- }), object({ success: literal(true) }), {
20255
- kind: "mutation",
20256
- auth: "admin"
20257
- }), method(object({ agentNodeId: string() }), object({
20367
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20258
20368
  success: boolean(),
20259
20369
  removed: boolean()
20260
20370
  }), {
@@ -20286,7 +20396,18 @@ method(object({
20286
20396
  }), object({ success: literal(true) }), {
20287
20397
  kind: "mutation",
20288
20398
  auth: "admin"
20289
- }), method(object({ agentNodeId: string() }), object({
20399
+ }), method(object({
20400
+ agentNodeId: string(),
20401
+ inferenceDevices: record(string(), object({
20402
+ enabled: boolean(),
20403
+ weight: number().positive().optional(),
20404
+ maxSessions: number().int().positive().optional(),
20405
+ steps: record(string(), DeviceStepConfigSchema).optional()
20406
+ }))
20407
+ }), object({ success: literal(true) }), {
20408
+ kind: "mutation",
20409
+ auth: "admin"
20410
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20290
20411
  success: literal(true),
20291
20412
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20292
20413
  effectiveModelId: string().nullable(),
@@ -20302,9 +20423,10 @@ method(object({
20302
20423
  }), object({ success: literal(true) }), {
20303
20424
  kind: "mutation",
20304
20425
  auth: "admin"
20305
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20426
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20306
20427
  deviceId: number(),
20307
20428
  agentNodeId: string(),
20429
+ deviceKey: string(),
20308
20430
  addonId: string(),
20309
20431
  patch: CameraStepOverridePatchSchema.nullable()
20310
20432
  }), object({ success: literal(true) }), {
@@ -20341,14 +20463,13 @@ method(object({
20341
20463
  });
20342
20464
  /**
20343
20465
  * server-management — per-NODE singleton capability for a node's ROOT
20344
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20345
- * agents).
20466
+ * package lifecycle (runtime-updatable node packages).
20346
20467
  *
20347
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20348
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20349
- * version describes the node. Updates install into
20350
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20351
- * starter (probation boot + auto-rollback to N-1).
20468
+ * Every node role runs the SAME root package (`@camstack/server`), which
20469
+ * carries the whole software stack in its npm dep tree, so ONE version
20470
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20471
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20472
+ * no auto-rollback).
20352
20473
  *
20353
20474
  * Providers:
20354
20475
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20456,7 +20577,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20456
20577
  /** Explicit target version; omitted = latest from the registry. */
20457
20578
  version: string().optional() }), ServerUpdateActionResultSchema, {
20458
20579
  kind: "mutation",
20459
- auth: "admin"
20580
+ auth: "admin",
20581
+ timeoutMs: 16 * 6e4
20460
20582
  }), method(_void(), ServerUpdateActionResultSchema, {
20461
20583
  kind: "mutation",
20462
20584
  auth: "admin"
@@ -21500,22 +21622,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21500
21622
  var RestartAddonResultSchema = unknown();
21501
21623
  var InstallPackageResultSchema = unknown();
21502
21624
  var ReloadPackagesResultSchema = unknown();
21503
- /**
21504
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21505
- * server restarts so the admin UI can react to the `restartingAt`
21506
- * timestamp (shows reconnect overlay). The transition from
21507
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21508
- * `system.restart-completed` event after the new process boots.
21509
- *
21510
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21511
- */
21512
- var UpdateFrameworkPackageResultSchema = object({
21513
- packageName: string(),
21514
- fromVersion: string(),
21515
- toVersion: string(),
21516
- /** Ms-epoch the server scheduled its self-restart. */
21517
- restartingAt: number()
21518
- });
21519
21625
  var BulkUpdateItemStatusSchema = _enum([
21520
21626
  "queued",
21521
21627
  "updating",
@@ -21643,13 +21749,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21643
21749
  }), object({ success: literal(true) }), {
21644
21750
  kind: "mutation",
21645
21751
  auth: "admin"
21646
- }), method(object({
21647
- packageName: string().min(1),
21648
- version: string().optional(),
21649
- deferRestart: boolean().optional()
21650
- }), UpdateFrameworkPackageResultSchema, {
21651
- kind: "mutation",
21652
- auth: "admin"
21653
21752
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21654
21753
  kind: "mutation",
21655
21754
  auth: "admin"
@@ -22532,10 +22631,10 @@ var TopologyCategorySchema = object({
22532
22631
  addons: array(TopologyCategoryAddonSchema).readonly()
22533
22632
  });
22534
22633
  /**
22535
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22536
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22537
- * version visibility for the Server management surface. Nullable: offline
22538
- * rows and pre-phase-2 nodes report none.
22634
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22635
+ * root package for every node role) as reported by its `registerNode`
22636
+ * manifest — version visibility for the Server management surface. Nullable:
22637
+ * offline rows and nodes that never reported one.
22539
22638
  */
22540
22639
  var TopologyRootPackageSchema = object({
22541
22640
  name: string(),
@@ -22923,17 +23022,28 @@ var PlatformScoreSchema = object({
22923
23022
  format: _enum([
22924
23023
  "onnx",
22925
23024
  "coreml",
22926
- "openvino"
23025
+ "openvino",
23026
+ "tflite"
22927
23027
  ]),
22928
23028
  score: number(),
22929
23029
  reason: string(),
22930
23030
  available: boolean()
22931
23031
  });
23032
+ var InferenceDeviceDescriptorSchema = object({
23033
+ key: string(),
23034
+ backend: string(),
23035
+ device: string(),
23036
+ format: ModelFormatSchema,
23037
+ runtime: literal("python"),
23038
+ score: number(),
23039
+ available: boolean()
23040
+ });
22932
23041
  var PlatformCapabilitiesSchema = object({
22933
23042
  hardware: HardwareInfoSchema,
22934
23043
  scores: array(PlatformScoreSchema).readonly(),
22935
23044
  bestScore: PlatformScoreSchema,
22936
- pythonPath: string().nullable()
23045
+ pythonPath: string().nullable(),
23046
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22937
23047
  });
22938
23048
  var ModelRequirementSchema = object({
22939
23049
  modelId: string(),
@@ -23812,12 +23922,6 @@ Object.freeze({
23812
23922
  addonId: null,
23813
23923
  access: "delete"
23814
23924
  },
23815
- "addons.updateFrameworkPackage": {
23816
- capName: "addons",
23817
- capScope: "system",
23818
- addonId: null,
23819
- access: "create"
23820
- },
23821
23925
  "addons.updatePackage": {
23822
23926
  capName: "addons",
23823
23927
  capScope: "system",
@@ -26590,12 +26694,6 @@ Object.freeze({
26590
26694
  addonId: null,
26591
26695
  access: "view"
26592
26696
  },
26593
- "pipelineExecutor.reprobeEngine": {
26594
- capName: "pipeline-executor",
26595
- capScope: "system",
26596
- addonId: null,
26597
- access: "create"
26598
- },
26599
26697
  "pipelineExecutor.runAudioTest": {
26600
26698
  capName: "pipeline-executor",
26601
26699
  capScope: "system",
@@ -26746,6 +26844,12 @@ Object.freeze({
26746
26844
  addonId: null,
26747
26845
  access: "view"
26748
26846
  },
26847
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26848
+ capName: "pipeline-orchestrator",
26849
+ capScope: "system",
26850
+ addonId: null,
26851
+ access: "view"
26852
+ },
26749
26853
  "pipelineOrchestrator.getPipelineAssignment": {
26750
26854
  capName: "pipeline-orchestrator",
26751
26855
  capScope: "system",
@@ -26758,6 +26862,12 @@ Object.freeze({
26758
26862
  addonId: null,
26759
26863
  access: "view"
26760
26864
  },
26865
+ "pipelineOrchestrator.getPipelineDevicePin": {
26866
+ capName: "pipeline-orchestrator",
26867
+ capScope: "system",
26868
+ addonId: null,
26869
+ access: "view"
26870
+ },
26761
26871
  "pipelineOrchestrator.listAgentSettings": {
26762
26872
  capName: "pipeline-orchestrator",
26763
26873
  capScope: "system",
@@ -26800,19 +26910,19 @@ Object.freeze({
26800
26910
  addonId: null,
26801
26911
  access: "create"
26802
26912
  },
26803
- "pipelineOrchestrator.setAgentAddonDefaults": {
26913
+ "pipelineOrchestrator.setAgentCapabilities": {
26804
26914
  capName: "pipeline-orchestrator",
26805
26915
  capScope: "system",
26806
26916
  addonId: null,
26807
26917
  access: "create"
26808
26918
  },
26809
- "pipelineOrchestrator.setAgentCapabilities": {
26919
+ "pipelineOrchestrator.setAgentDetectWeight": {
26810
26920
  capName: "pipeline-orchestrator",
26811
26921
  capScope: "system",
26812
26922
  addonId: null,
26813
26923
  access: "create"
26814
26924
  },
26815
- "pipelineOrchestrator.setAgentDetectWeight": {
26925
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26816
26926
  capName: "pipeline-orchestrator",
26817
26927
  capScope: "system",
26818
26928
  addonId: null,
@@ -26854,6 +26964,12 @@ Object.freeze({
26854
26964
  addonId: null,
26855
26965
  access: "create"
26856
26966
  },
26967
+ "pipelineOrchestrator.setPipelineDevicePin": {
26968
+ capName: "pipeline-orchestrator",
26969
+ capScope: "system",
26970
+ addonId: null,
26971
+ access: "create"
26972
+ },
26857
26973
  "pipelineOrchestrator.unassignAudio": {
26858
26974
  capName: "pipeline-orchestrator",
26859
26975
  capScope: "system",
@@ -28406,32 +28522,6 @@ Object.freeze({
28406
28522
  "network-access": "ingress",
28407
28523
  "smtp-provider": "email"
28408
28524
  });
28409
- var frameworkSwapPackageSchema = object({
28410
- name: string(),
28411
- stagedPath: string(),
28412
- backupPath: string(),
28413
- toVersion: string(),
28414
- fromVersion: string().nullable()
28415
- });
28416
- object({
28417
- jobId: string(),
28418
- taskId: string(),
28419
- packages: array(frameworkSwapPackageSchema),
28420
- requestedAtMs: number(),
28421
- schemaVersion: literal(1)
28422
- });
28423
- object({
28424
- jobId: string(),
28425
- taskId: string(),
28426
- backups: array(object({
28427
- name: string(),
28428
- backupPath: string(),
28429
- livePath: string()
28430
- })),
28431
- appliedAtMs: number(),
28432
- bootAttempts: number(),
28433
- schemaVersion: literal(1)
28434
- });
28435
28525
  //#endregion
28436
28526
  //#region src/config.ts
28437
28527
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-import-alexa",
3
- "version": "0.1.25",
3
+ "version": "0.2.0",
4
4
  "description": "Alexa device-import provider for CamStack — imports the smart-home devices in a user's Alexa account via the unofficial alexa-remote2 cookie/token client (the inverse of the Alexa exporter)",
5
5
  "keywords": [
6
6
  "camstack",