@camstack/addon-export-alexa 1.1.27 → 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.
@@ -7118,6 +7118,17 @@ var ModelCatalogEntrySchema = object({
7118
7118
  "imagenet",
7119
7119
  "none"
7120
7120
  ]).optional(),
7121
+ /**
7122
+ * The model already applies softmax IN-GRAPH — its raw output is a
7123
+ * probability distribution, not logits. When set, the `softmax`
7124
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7125
+ * probability vector collapses it toward uniform (top-1 score craters far
7126
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7127
+ * the output is raw logits and the postprocessor applies softmax (the normal
7128
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7129
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7130
+ */
7131
+ outputProbabilities: boolean().optional(),
7121
7132
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7122
7133
  /**
7123
7134
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11302,10 +11313,7 @@ var ConfigUISchemaNullableBridge = custom();
11302
11313
  var InferenceCapabilitiesBridge = custom();
11303
11314
  var ModelAvailabilityListBridge = custom();
11304
11315
  var PipelineRunResultBridge = custom();
11305
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11306
- kind: "mutation",
11307
- auth: "admin"
11308
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11316
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11309
11317
  modelId: string(),
11310
11318
  settings: record(string(), unknown()).readonly()
11311
11319
  }))), method(object({ steps: record(string(), object({
@@ -11365,13 +11373,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11365
11373
  * (inputClasses ≠ null) are skipped and served per-track via
11366
11374
  * pipelineRunner.runDetailSubtree (two-plane design).
11367
11375
  */
11368
- plane: _enum(["full", "frame"]).optional()
11376
+ plane: _enum(["full", "frame"]).optional(),
11377
+ /**
11378
+ * Inference-device selector (Phase 2 multi-device). Format
11379
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11380
+ * Omitted ⇒ the runner's default device (current single-engine
11381
+ * behaviour). Selects WHICH device pool of the node runs the call.
11382
+ */
11383
+ deviceKey: string().optional()
11369
11384
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11370
11385
  engine: PipelineEngineChoiceSchema.optional(),
11371
11386
  steps: array(PipelineStepInputSchema).min(1),
11372
11387
  frames: array(FrameInputSchema).min(1).max(255),
11373
11388
  deviceId: number().optional(),
11374
- sessionId: string().optional()
11389
+ sessionId: string().optional(),
11390
+ /**
11391
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11392
+ * the batch to the Python pool's bench preprocess cache
11393
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11394
+ * preprocessed ONCE and every later inference is a pure-inference cache
11395
+ * hit — the sustained-throughput run measures inference, not
11396
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11397
+ * full preprocess every call, correct). Fresh per sustained run;
11398
+ * released via `uncacheFrame`.
11399
+ */
11400
+ frameId: number().int().nonnegative().optional(),
11401
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11402
+ deviceKey: string().optional()
11375
11403
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11376
11404
  data: _instanceof(Uint8Array),
11377
11405
  width: number().int().positive(),
@@ -11403,8 +11431,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11403
11431
  * - `runtime` — main camera-serving engine (no idle TTL).
11404
11432
  * - `warm-override` — benchmark/test override held in the warm
11405
11433
  * cache; auto-disposed after the idle TTL.
11434
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11435
+ * multi-device, keyed by `deviceKey`) resolved
11436
+ * via `resolveDeviceFactory`. Runs alongside the
11437
+ * `runtime` engine on a DIFFERENT accelerator
11438
+ * (NPU / iGPU / Coral) — this is how the
11439
+ * Engines tab shows all pools running at once.
11406
11440
  */
11407
- kind: _enum(["runtime", "warm-override"]),
11441
+ kind: _enum([
11442
+ "runtime",
11443
+ "warm-override",
11444
+ "device-pool"
11445
+ ]),
11408
11446
  /** Native pid of the underlying Python pool (null when no pool). */
11409
11447
  poolPid: number().nullable(),
11410
11448
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11506,7 +11544,21 @@ var NativeCropResultSchema = object({
11506
11544
  /** Packed rgb (24-bit) pixels of the crop. */
11507
11545
  bytes: _instanceof(Uint8Array),
11508
11546
  width: number().int().positive(),
11509
- height: number().int().positive()
11547
+ height: number().int().positive(),
11548
+ /**
11549
+ * Which source served this crop, so a quality-sensitive consumer (the native
11550
+ * `keyFrame`) can reject a degraded fallback:
11551
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11552
+ * quality path).
11553
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11554
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11555
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11556
+ *
11557
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11558
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11559
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11560
+ */
11561
+ tier: _enum(["native", "ram-fullframe"]).optional()
11510
11562
  });
11511
11563
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11512
11564
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11746,7 +11798,14 @@ var RunnerCameraConfigSchema = object({
11746
11798
  * camera's detect node differs from its source-owner (P2d, gated by the
11747
11799
  * `remoteSourcingNodes` rollout setting).
11748
11800
  */
11749
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11801
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11802
+ /**
11803
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11804
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11805
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11806
+ * this only selects WHICH device pool of that node runs the session.
11807
+ */
11808
+ deviceKey: string().optional()
11750
11809
  });
11751
11810
  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;
11752
11811
  /**
@@ -11767,6 +11826,19 @@ var RunnerLocalLoadSchema = object({
11767
11826
  avgInferenceTimeMs: number(),
11768
11827
  /** Total queue depth across motion + detection queues. */
11769
11828
  queueDepthTotal: number(),
11829
+ /**
11830
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11831
+ * this runner currently has attached cameras on, so the orchestrator's second
11832
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11833
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11834
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11835
+ */
11836
+ devices: array(object({
11837
+ deviceKey: string(),
11838
+ backend: string(),
11839
+ attachedCameras: number(),
11840
+ queueDepthTotal: number()
11841
+ })).default([]),
11770
11842
  /** Hardware capability flags reported by this node. */
11771
11843
  hardware: object({
11772
11844
  hasGpu: boolean(),
@@ -13242,6 +13314,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13242
13314
  kind: "mutation",
13243
13315
  auth: "admin"
13244
13316
  });
13317
+ 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;
13318
+ new Set(Object.values(DeviceType));
13245
13319
  /**
13246
13320
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13247
13321
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -14880,7 +14954,8 @@ var LinkedDeviceSchema = object({
14880
14954
  deviceId: number(),
14881
14955
  name: string(),
14882
14956
  location: string().nullable(),
14883
- features: array(string())
14957
+ features: array(string()),
14958
+ producesTrackedEvents: boolean().optional()
14884
14959
  });
14885
14960
  var SavedDeviceRowSchema = object({
14886
14961
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16516,6 +16591,7 @@ var TrackSchema = object({
16516
16591
  deviceId: number(),
16517
16592
  className: string(),
16518
16593
  label: string().optional(),
16594
+ producingDeviceName: string().optional(),
16519
16595
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16520
16596
  source: TrackSourceSchema.optional(),
16521
16597
  firstSeen: number(),
@@ -16653,7 +16729,8 @@ var MediaFileKindEnum = _enum([
16653
16729
  "fullFrameBoxed",
16654
16730
  "faceCrop",
16655
16731
  "plateCrop",
16656
- "keyFrame"
16732
+ "keyFrame",
16733
+ "keyFrameSmall"
16657
16734
  ]);
16658
16735
  var MediaFileSchema = object({
16659
16736
  key: string(),
@@ -16982,13 +17059,11 @@ var PipelineTemplateSchema = object({
16982
17059
  createdAt: string(),
16983
17060
  updatedAt: string()
16984
17061
  });
16985
- var AgentAddonConfigSchema = object({
16986
- enabled: boolean(),
17062
+ var DeviceStepConfigSchema = object({
16987
17063
  modelId: string().optional(),
16988
- settings: record(string(), unknown()).readonly()
17064
+ settings: record(string(), unknown()).optional()
16989
17065
  });
16990
17066
  var AgentPipelineSettingsSchema = object({
16991
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16992
17067
  maxCameras: number().int().nonnegative().nullable().default(null),
16993
17068
  /** Per-node detection weight (relative share for the quota balancer). */
16994
17069
  detectWeight: number().positive().optional(),
@@ -17012,7 +17087,22 @@ var AgentPipelineSettingsSchema = object({
17012
17087
  * it already uses to reach the hub). Set this only when the auto-detected
17013
17088
  * address is wrong (multi-homed host, NAT, custom interface).
17014
17089
  */
17015
- reachableHost: string().optional()
17090
+ reachableHost: string().optional(),
17091
+ /**
17092
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
17093
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
17094
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
17095
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
17096
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
17097
+ * the default model/settings for every camera landing on that accelerator;
17098
+ * a stepId absent ⇒ the step uses that device's format default.
17099
+ */
17100
+ inferenceDevices: record(string(), object({
17101
+ enabled: boolean(),
17102
+ weight: number().positive().optional(),
17103
+ maxSessions: number().int().positive().optional(),
17104
+ steps: record(string(), DeviceStepConfigSchema).optional()
17105
+ })).optional()
17016
17106
  });
17017
17107
  var CameraPipelineForAgentSchema = object({
17018
17108
  steps: array(PipelineStepInputSchema).readonly(),
@@ -17022,14 +17112,13 @@ var CameraPipelineForAgentSchema = object({
17022
17112
  }).nullable()
17023
17113
  });
17024
17114
  var CameraStepOverridePatchSchema = object({
17025
- enabled: boolean().optional(),
17026
17115
  modelId: string().optional(),
17027
17116
  settings: record(string(), unknown()).readonly().optional()
17028
17117
  });
17029
17118
  var CameraPipelineSettingsSchema = object({
17030
17119
  pinnedAgentNodeId: string().optional(),
17031
17120
  stepToggles: record(string(), boolean()).optional(),
17032
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
17121
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
17033
17122
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
17034
17123
  });
17035
17124
  /**
@@ -17243,6 +17332,44 @@ var CameraStatusSchema = object({
17243
17332
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17244
17333
  fetchedAt: number()
17245
17334
  });
17335
+ var NodeInferenceDeviceSchema = object({
17336
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17337
+ key: string(),
17338
+ backend: string(),
17339
+ device: string(),
17340
+ format: _enum(MODEL_FORMATS),
17341
+ /** Whether the node's live probe reports the device as usable right now. */
17342
+ available: boolean(),
17343
+ /**
17344
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17345
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17346
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17347
+ * not a balanced target). An explicit stored value always wins; a stored-only
17348
+ * (unavailable) key keeps its stored value.
17349
+ */
17350
+ enabled: boolean(),
17351
+ /** Relative balancer weight for the enabled device (default 1). */
17352
+ weight: number(),
17353
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17354
+ maxSessions: number().nullable(),
17355
+ /** Object-detection model the executor defaults to for this deviceKey. */
17356
+ defaultModelId: string(),
17357
+ /**
17358
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17359
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17360
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17361
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17362
+ * available per format; this is the stored selection that becomes the
17363
+ * default for EVERY camera landing on this accelerator.
17364
+ */
17365
+ steps: record(string(), DeviceStepConfigSchema).optional()
17366
+ });
17367
+ var NodeInferenceDevicesSchema = object({
17368
+ nodeId: string(),
17369
+ /** False when the node's platform-probe was unreachable (no live device set). */
17370
+ reachable: boolean(),
17371
+ devices: array(NodeInferenceDeviceSchema).readonly()
17372
+ });
17246
17373
  method(object({
17247
17374
  deviceId: number(),
17248
17375
  agentNodeId: string()
@@ -17252,7 +17379,13 @@ method(object({
17252
17379
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17253
17380
  kind: "mutation",
17254
17381
  auth: "admin"
17255
- }), method(_void(), object({ migrated: number() }), {
17382
+ }), method(object({
17383
+ deviceId: number(),
17384
+ deviceKey: string()
17385
+ }), object({ success: literal(true) }), {
17386
+ kind: "mutation",
17387
+ auth: "admin"
17388
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17256
17389
  kind: "mutation",
17257
17390
  auth: "admin"
17258
17391
  }), 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({
@@ -17286,13 +17419,7 @@ method(object({
17286
17419
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17287
17420
  nodeId: string(),
17288
17421
  settings: AgentPipelineSettingsSchema
17289
- })).readonly()), method(object({
17290
- agentNodeId: string(),
17291
- defaults: record(string(), AgentAddonConfigSchema)
17292
- }), object({ success: literal(true) }), {
17293
- kind: "mutation",
17294
- auth: "admin"
17295
- }), method(object({ agentNodeId: string() }), object({
17422
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17296
17423
  success: boolean(),
17297
17424
  removed: boolean()
17298
17425
  }), {
@@ -17324,7 +17451,18 @@ method(object({
17324
17451
  }), object({ success: literal(true) }), {
17325
17452
  kind: "mutation",
17326
17453
  auth: "admin"
17327
- }), method(object({ agentNodeId: string() }), object({
17454
+ }), method(object({
17455
+ agentNodeId: string(),
17456
+ inferenceDevices: record(string(), object({
17457
+ enabled: boolean(),
17458
+ weight: number().positive().optional(),
17459
+ maxSessions: number().int().positive().optional(),
17460
+ steps: record(string(), DeviceStepConfigSchema).optional()
17461
+ }))
17462
+ }), object({ success: literal(true) }), {
17463
+ kind: "mutation",
17464
+ auth: "admin"
17465
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17328
17466
  success: literal(true),
17329
17467
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17330
17468
  effectiveModelId: string().nullable(),
@@ -17340,9 +17478,10 @@ method(object({
17340
17478
  }), object({ success: literal(true) }), {
17341
17479
  kind: "mutation",
17342
17480
  auth: "admin"
17343
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17481
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17344
17482
  deviceId: number(),
17345
17483
  agentNodeId: string(),
17484
+ deviceKey: string(),
17346
17485
  addonId: string(),
17347
17486
  patch: CameraStepOverridePatchSchema.nullable()
17348
17487
  }), object({ success: literal(true) }), {
@@ -17379,14 +17518,13 @@ method(object({
17379
17518
  });
17380
17519
  /**
17381
17520
  * server-management — per-NODE singleton capability for a node's ROOT
17382
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17383
- * agents).
17521
+ * package lifecycle (runtime-updatable node packages).
17384
17522
  *
17385
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17386
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17387
- * version describes the node. Updates install into
17388
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17389
- * starter (probation boot + auto-rollback to N-1).
17523
+ * Every node role runs the SAME root package (`@camstack/server`), which
17524
+ * carries the whole software stack in its npm dep tree, so ONE version
17525
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17526
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17527
+ * no auto-rollback).
17390
17528
  *
17391
17529
  * Providers:
17392
17530
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17494,7 +17632,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17494
17632
  /** Explicit target version; omitted = latest from the registry. */
17495
17633
  version: string().optional() }), ServerUpdateActionResultSchema, {
17496
17634
  kind: "mutation",
17497
- auth: "admin"
17635
+ auth: "admin",
17636
+ timeoutMs: 16 * 6e4
17498
17637
  }), method(_void(), ServerUpdateActionResultSchema, {
17499
17638
  kind: "mutation",
17500
17639
  auth: "admin"
@@ -18538,22 +18677,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18538
18677
  var RestartAddonResultSchema = unknown();
18539
18678
  var InstallPackageResultSchema = unknown();
18540
18679
  var ReloadPackagesResultSchema = unknown();
18541
- /**
18542
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18543
- * server restarts so the admin UI can react to the `restartingAt`
18544
- * timestamp (shows reconnect overlay). The transition from
18545
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18546
- * `system.restart-completed` event after the new process boots.
18547
- *
18548
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18549
- */
18550
- var UpdateFrameworkPackageResultSchema = object({
18551
- packageName: string(),
18552
- fromVersion: string(),
18553
- toVersion: string(),
18554
- /** Ms-epoch the server scheduled its self-restart. */
18555
- restartingAt: number()
18556
- });
18557
18680
  var BulkUpdateItemStatusSchema = _enum([
18558
18681
  "queued",
18559
18682
  "updating",
@@ -18681,13 +18804,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18681
18804
  }), object({ success: literal(true) }), {
18682
18805
  kind: "mutation",
18683
18806
  auth: "admin"
18684
- }), method(object({
18685
- packageName: string().min(1),
18686
- version: string().optional(),
18687
- deferRestart: boolean().optional()
18688
- }), UpdateFrameworkPackageResultSchema, {
18689
- kind: "mutation",
18690
- auth: "admin"
18691
18807
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18692
18808
  kind: "mutation",
18693
18809
  auth: "admin"
@@ -19553,10 +19669,10 @@ var TopologyCategorySchema = object({
19553
19669
  addons: array(TopologyCategoryAddonSchema).readonly()
19554
19670
  });
19555
19671
  /**
19556
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19557
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19558
- * version visibility for the Server management surface. Nullable: offline
19559
- * rows and pre-phase-2 nodes report none.
19672
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19673
+ * root package for every node role) as reported by its `registerNode`
19674
+ * manifest — version visibility for the Server management surface. Nullable:
19675
+ * offline rows and nodes that never reported one.
19560
19676
  */
19561
19677
  var TopologyRootPackageSchema = object({
19562
19678
  name: string(),
@@ -19944,17 +20060,28 @@ var PlatformScoreSchema = object({
19944
20060
  format: _enum([
19945
20061
  "onnx",
19946
20062
  "coreml",
19947
- "openvino"
20063
+ "openvino",
20064
+ "tflite"
19948
20065
  ]),
19949
20066
  score: number(),
19950
20067
  reason: string(),
19951
20068
  available: boolean()
19952
20069
  });
20070
+ var InferenceDeviceDescriptorSchema = object({
20071
+ key: string(),
20072
+ backend: string(),
20073
+ device: string(),
20074
+ format: ModelFormatSchema,
20075
+ runtime: literal("python"),
20076
+ score: number(),
20077
+ available: boolean()
20078
+ });
19953
20079
  var PlatformCapabilitiesSchema = object({
19954
20080
  hardware: HardwareInfoSchema,
19955
20081
  scores: array(PlatformScoreSchema).readonly(),
19956
20082
  bestScore: PlatformScoreSchema,
19957
- pythonPath: string().nullable()
20083
+ pythonPath: string().nullable(),
20084
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19958
20085
  });
19959
20086
  var ModelRequirementSchema = object({
19960
20087
  modelId: string(),
@@ -20833,12 +20960,6 @@ Object.freeze({
20833
20960
  addonId: null,
20834
20961
  access: "delete"
20835
20962
  },
20836
- "addons.updateFrameworkPackage": {
20837
- capName: "addons",
20838
- capScope: "system",
20839
- addonId: null,
20840
- access: "create"
20841
- },
20842
20963
  "addons.updatePackage": {
20843
20964
  capName: "addons",
20844
20965
  capScope: "system",
@@ -23611,12 +23732,6 @@ Object.freeze({
23611
23732
  addonId: null,
23612
23733
  access: "view"
23613
23734
  },
23614
- "pipelineExecutor.reprobeEngine": {
23615
- capName: "pipeline-executor",
23616
- capScope: "system",
23617
- addonId: null,
23618
- access: "create"
23619
- },
23620
23735
  "pipelineExecutor.runAudioTest": {
23621
23736
  capName: "pipeline-executor",
23622
23737
  capScope: "system",
@@ -23767,6 +23882,12 @@ Object.freeze({
23767
23882
  addonId: null,
23768
23883
  access: "view"
23769
23884
  },
23885
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23886
+ capName: "pipeline-orchestrator",
23887
+ capScope: "system",
23888
+ addonId: null,
23889
+ access: "view"
23890
+ },
23770
23891
  "pipelineOrchestrator.getPipelineAssignment": {
23771
23892
  capName: "pipeline-orchestrator",
23772
23893
  capScope: "system",
@@ -23779,6 +23900,12 @@ Object.freeze({
23779
23900
  addonId: null,
23780
23901
  access: "view"
23781
23902
  },
23903
+ "pipelineOrchestrator.getPipelineDevicePin": {
23904
+ capName: "pipeline-orchestrator",
23905
+ capScope: "system",
23906
+ addonId: null,
23907
+ access: "view"
23908
+ },
23782
23909
  "pipelineOrchestrator.listAgentSettings": {
23783
23910
  capName: "pipeline-orchestrator",
23784
23911
  capScope: "system",
@@ -23821,19 +23948,19 @@ Object.freeze({
23821
23948
  addonId: null,
23822
23949
  access: "create"
23823
23950
  },
23824
- "pipelineOrchestrator.setAgentAddonDefaults": {
23951
+ "pipelineOrchestrator.setAgentCapabilities": {
23825
23952
  capName: "pipeline-orchestrator",
23826
23953
  capScope: "system",
23827
23954
  addonId: null,
23828
23955
  access: "create"
23829
23956
  },
23830
- "pipelineOrchestrator.setAgentCapabilities": {
23957
+ "pipelineOrchestrator.setAgentDetectWeight": {
23831
23958
  capName: "pipeline-orchestrator",
23832
23959
  capScope: "system",
23833
23960
  addonId: null,
23834
23961
  access: "create"
23835
23962
  },
23836
- "pipelineOrchestrator.setAgentDetectWeight": {
23963
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23837
23964
  capName: "pipeline-orchestrator",
23838
23965
  capScope: "system",
23839
23966
  addonId: null,
@@ -23875,6 +24002,12 @@ Object.freeze({
23875
24002
  addonId: null,
23876
24003
  access: "create"
23877
24004
  },
24005
+ "pipelineOrchestrator.setPipelineDevicePin": {
24006
+ capName: "pipeline-orchestrator",
24007
+ capScope: "system",
24008
+ addonId: null,
24009
+ access: "create"
24010
+ },
23878
24011
  "pipelineOrchestrator.unassignAudio": {
23879
24012
  capName: "pipeline-orchestrator",
23880
24013
  capScope: "system",
@@ -25427,32 +25560,6 @@ Object.freeze({
25427
25560
  "network-access": "ingress",
25428
25561
  "smtp-provider": "email"
25429
25562
  });
25430
- var frameworkSwapPackageSchema = object({
25431
- name: string(),
25432
- stagedPath: string(),
25433
- backupPath: string(),
25434
- toVersion: string(),
25435
- fromVersion: string().nullable()
25436
- });
25437
- object({
25438
- jobId: string(),
25439
- taskId: string(),
25440
- packages: array(frameworkSwapPackageSchema),
25441
- requestedAtMs: number(),
25442
- schemaVersion: literal(1)
25443
- });
25444
- object({
25445
- jobId: string(),
25446
- taskId: string(),
25447
- backups: array(object({
25448
- name: string(),
25449
- backupPath: string(),
25450
- livePath: string()
25451
- })),
25452
- appliedAtMs: number(),
25453
- bootAttempts: number(),
25454
- schemaVersion: literal(1)
25455
- });
25456
25563
  //#endregion
25457
25564
  //#region src/custom-actions.ts
25458
25565
  /**
@@ -7092,6 +7092,17 @@ var ModelCatalogEntrySchema = object({
7092
7092
  "imagenet",
7093
7093
  "none"
7094
7094
  ]).optional(),
7095
+ /**
7096
+ * The model already applies softmax IN-GRAPH — its raw output is a
7097
+ * probability distribution, not logits. When set, the `softmax`
7098
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7099
+ * probability vector collapses it toward uniform (top-1 score craters far
7100
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7101
+ * the output is raw logits and the postprocessor applies softmax (the normal
7102
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7103
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7104
+ */
7105
+ outputProbabilities: boolean().optional(),
7095
7106
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7096
7107
  /**
7097
7108
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11276,10 +11287,7 @@ var ConfigUISchemaNullableBridge = custom();
11276
11287
  var InferenceCapabilitiesBridge = custom();
11277
11288
  var ModelAvailabilityListBridge = custom();
11278
11289
  var PipelineRunResultBridge = custom();
11279
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11280
- kind: "mutation",
11281
- auth: "admin"
11282
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11290
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11283
11291
  modelId: string(),
11284
11292
  settings: record(string(), unknown()).readonly()
11285
11293
  }))), method(object({ steps: record(string(), object({
@@ -11339,13 +11347,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11339
11347
  * (inputClasses ≠ null) are skipped and served per-track via
11340
11348
  * pipelineRunner.runDetailSubtree (two-plane design).
11341
11349
  */
11342
- plane: _enum(["full", "frame"]).optional()
11350
+ plane: _enum(["full", "frame"]).optional(),
11351
+ /**
11352
+ * Inference-device selector (Phase 2 multi-device). Format
11353
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11354
+ * Omitted ⇒ the runner's default device (current single-engine
11355
+ * behaviour). Selects WHICH device pool of the node runs the call.
11356
+ */
11357
+ deviceKey: string().optional()
11343
11358
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11344
11359
  engine: PipelineEngineChoiceSchema.optional(),
11345
11360
  steps: array(PipelineStepInputSchema).min(1),
11346
11361
  frames: array(FrameInputSchema).min(1).max(255),
11347
11362
  deviceId: number().optional(),
11348
- sessionId: string().optional()
11363
+ sessionId: string().optional(),
11364
+ /**
11365
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11366
+ * the batch to the Python pool's bench preprocess cache
11367
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11368
+ * preprocessed ONCE and every later inference is a pure-inference cache
11369
+ * hit — the sustained-throughput run measures inference, not
11370
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11371
+ * full preprocess every call, correct). Fresh per sustained run;
11372
+ * released via `uncacheFrame`.
11373
+ */
11374
+ frameId: number().int().nonnegative().optional(),
11375
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11376
+ deviceKey: string().optional()
11349
11377
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11350
11378
  data: _instanceof(Uint8Array),
11351
11379
  width: number().int().positive(),
@@ -11377,8 +11405,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11377
11405
  * - `runtime` — main camera-serving engine (no idle TTL).
11378
11406
  * - `warm-override` — benchmark/test override held in the warm
11379
11407
  * cache; auto-disposed after the idle TTL.
11408
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11409
+ * multi-device, keyed by `deviceKey`) resolved
11410
+ * via `resolveDeviceFactory`. Runs alongside the
11411
+ * `runtime` engine on a DIFFERENT accelerator
11412
+ * (NPU / iGPU / Coral) — this is how the
11413
+ * Engines tab shows all pools running at once.
11380
11414
  */
11381
- kind: _enum(["runtime", "warm-override"]),
11415
+ kind: _enum([
11416
+ "runtime",
11417
+ "warm-override",
11418
+ "device-pool"
11419
+ ]),
11382
11420
  /** Native pid of the underlying Python pool (null when no pool). */
11383
11421
  poolPid: number().nullable(),
11384
11422
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11480,7 +11518,21 @@ var NativeCropResultSchema = object({
11480
11518
  /** Packed rgb (24-bit) pixels of the crop. */
11481
11519
  bytes: _instanceof(Uint8Array),
11482
11520
  width: number().int().positive(),
11483
- height: number().int().positive()
11521
+ height: number().int().positive(),
11522
+ /**
11523
+ * Which source served this crop, so a quality-sensitive consumer (the native
11524
+ * `keyFrame`) can reject a degraded fallback:
11525
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11526
+ * quality path).
11527
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11528
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11529
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11530
+ *
11531
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11532
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11533
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11534
+ */
11535
+ tier: _enum(["native", "ram-fullframe"]).optional()
11484
11536
  });
11485
11537
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11486
11538
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11720,7 +11772,14 @@ var RunnerCameraConfigSchema = object({
11720
11772
  * camera's detect node differs from its source-owner (P2d, gated by the
11721
11773
  * `remoteSourcingNodes` rollout setting).
11722
11774
  */
11723
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11775
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11776
+ /**
11777
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11778
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11779
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11780
+ * this only selects WHICH device pool of that node runs the session.
11781
+ */
11782
+ deviceKey: string().optional()
11724
11783
  });
11725
11784
  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;
11726
11785
  /**
@@ -11741,6 +11800,19 @@ var RunnerLocalLoadSchema = object({
11741
11800
  avgInferenceTimeMs: number(),
11742
11801
  /** Total queue depth across motion + detection queues. */
11743
11802
  queueDepthTotal: number(),
11803
+ /**
11804
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11805
+ * this runner currently has attached cameras on, so the orchestrator's second
11806
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11807
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11808
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11809
+ */
11810
+ devices: array(object({
11811
+ deviceKey: string(),
11812
+ backend: string(),
11813
+ attachedCameras: number(),
11814
+ queueDepthTotal: number()
11815
+ })).default([]),
11744
11816
  /** Hardware capability flags reported by this node. */
11745
11817
  hardware: object({
11746
11818
  hasGpu: boolean(),
@@ -13216,6 +13288,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13216
13288
  kind: "mutation",
13217
13289
  auth: "admin"
13218
13290
  });
13291
+ 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;
13292
+ new Set(Object.values(DeviceType));
13219
13293
  /**
13220
13294
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13221
13295
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -14854,7 +14928,8 @@ var LinkedDeviceSchema = object({
14854
14928
  deviceId: number(),
14855
14929
  name: string(),
14856
14930
  location: string().nullable(),
14857
- features: array(string())
14931
+ features: array(string()),
14932
+ producesTrackedEvents: boolean().optional()
14858
14933
  });
14859
14934
  var SavedDeviceRowSchema = object({
14860
14935
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16490,6 +16565,7 @@ var TrackSchema = object({
16490
16565
  deviceId: number(),
16491
16566
  className: string(),
16492
16567
  label: string().optional(),
16568
+ producingDeviceName: string().optional(),
16493
16569
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16494
16570
  source: TrackSourceSchema.optional(),
16495
16571
  firstSeen: number(),
@@ -16627,7 +16703,8 @@ var MediaFileKindEnum = _enum([
16627
16703
  "fullFrameBoxed",
16628
16704
  "faceCrop",
16629
16705
  "plateCrop",
16630
- "keyFrame"
16706
+ "keyFrame",
16707
+ "keyFrameSmall"
16631
16708
  ]);
16632
16709
  var MediaFileSchema = object({
16633
16710
  key: string(),
@@ -16956,13 +17033,11 @@ var PipelineTemplateSchema = object({
16956
17033
  createdAt: string(),
16957
17034
  updatedAt: string()
16958
17035
  });
16959
- var AgentAddonConfigSchema = object({
16960
- enabled: boolean(),
17036
+ var DeviceStepConfigSchema = object({
16961
17037
  modelId: string().optional(),
16962
- settings: record(string(), unknown()).readonly()
17038
+ settings: record(string(), unknown()).optional()
16963
17039
  });
16964
17040
  var AgentPipelineSettingsSchema = object({
16965
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16966
17041
  maxCameras: number().int().nonnegative().nullable().default(null),
16967
17042
  /** Per-node detection weight (relative share for the quota balancer). */
16968
17043
  detectWeight: number().positive().optional(),
@@ -16986,7 +17061,22 @@ var AgentPipelineSettingsSchema = object({
16986
17061
  * it already uses to reach the hub). Set this only when the auto-detected
16987
17062
  * address is wrong (multi-homed host, NAT, custom interface).
16988
17063
  */
16989
- reachableHost: string().optional()
17064
+ reachableHost: string().optional(),
17065
+ /**
17066
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
17067
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
17068
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
17069
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
17070
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
17071
+ * the default model/settings for every camera landing on that accelerator;
17072
+ * a stepId absent ⇒ the step uses that device's format default.
17073
+ */
17074
+ inferenceDevices: record(string(), object({
17075
+ enabled: boolean(),
17076
+ weight: number().positive().optional(),
17077
+ maxSessions: number().int().positive().optional(),
17078
+ steps: record(string(), DeviceStepConfigSchema).optional()
17079
+ })).optional()
16990
17080
  });
16991
17081
  var CameraPipelineForAgentSchema = object({
16992
17082
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16996,14 +17086,13 @@ var CameraPipelineForAgentSchema = object({
16996
17086
  }).nullable()
16997
17087
  });
16998
17088
  var CameraStepOverridePatchSchema = object({
16999
- enabled: boolean().optional(),
17000
17089
  modelId: string().optional(),
17001
17090
  settings: record(string(), unknown()).readonly().optional()
17002
17091
  });
17003
17092
  var CameraPipelineSettingsSchema = object({
17004
17093
  pinnedAgentNodeId: string().optional(),
17005
17094
  stepToggles: record(string(), boolean()).optional(),
17006
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
17095
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
17007
17096
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
17008
17097
  });
17009
17098
  /**
@@ -17217,6 +17306,44 @@ var CameraStatusSchema = object({
17217
17306
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17218
17307
  fetchedAt: number()
17219
17308
  });
17309
+ var NodeInferenceDeviceSchema = object({
17310
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17311
+ key: string(),
17312
+ backend: string(),
17313
+ device: string(),
17314
+ format: _enum(MODEL_FORMATS),
17315
+ /** Whether the node's live probe reports the device as usable right now. */
17316
+ available: boolean(),
17317
+ /**
17318
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17319
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17320
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17321
+ * not a balanced target). An explicit stored value always wins; a stored-only
17322
+ * (unavailable) key keeps its stored value.
17323
+ */
17324
+ enabled: boolean(),
17325
+ /** Relative balancer weight for the enabled device (default 1). */
17326
+ weight: number(),
17327
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17328
+ maxSessions: number().nullable(),
17329
+ /** Object-detection model the executor defaults to for this deviceKey. */
17330
+ defaultModelId: string(),
17331
+ /**
17332
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17333
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17334
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17335
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17336
+ * available per format; this is the stored selection that becomes the
17337
+ * default for EVERY camera landing on this accelerator.
17338
+ */
17339
+ steps: record(string(), DeviceStepConfigSchema).optional()
17340
+ });
17341
+ var NodeInferenceDevicesSchema = object({
17342
+ nodeId: string(),
17343
+ /** False when the node's platform-probe was unreachable (no live device set). */
17344
+ reachable: boolean(),
17345
+ devices: array(NodeInferenceDeviceSchema).readonly()
17346
+ });
17220
17347
  method(object({
17221
17348
  deviceId: number(),
17222
17349
  agentNodeId: string()
@@ -17226,7 +17353,13 @@ method(object({
17226
17353
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17227
17354
  kind: "mutation",
17228
17355
  auth: "admin"
17229
- }), method(_void(), object({ migrated: number() }), {
17356
+ }), method(object({
17357
+ deviceId: number(),
17358
+ deviceKey: string()
17359
+ }), object({ success: literal(true) }), {
17360
+ kind: "mutation",
17361
+ auth: "admin"
17362
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17230
17363
  kind: "mutation",
17231
17364
  auth: "admin"
17232
17365
  }), 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({
@@ -17260,13 +17393,7 @@ method(object({
17260
17393
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17261
17394
  nodeId: string(),
17262
17395
  settings: AgentPipelineSettingsSchema
17263
- })).readonly()), method(object({
17264
- agentNodeId: string(),
17265
- defaults: record(string(), AgentAddonConfigSchema)
17266
- }), object({ success: literal(true) }), {
17267
- kind: "mutation",
17268
- auth: "admin"
17269
- }), method(object({ agentNodeId: string() }), object({
17396
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17270
17397
  success: boolean(),
17271
17398
  removed: boolean()
17272
17399
  }), {
@@ -17298,7 +17425,18 @@ method(object({
17298
17425
  }), object({ success: literal(true) }), {
17299
17426
  kind: "mutation",
17300
17427
  auth: "admin"
17301
- }), method(object({ agentNodeId: string() }), object({
17428
+ }), method(object({
17429
+ agentNodeId: string(),
17430
+ inferenceDevices: record(string(), object({
17431
+ enabled: boolean(),
17432
+ weight: number().positive().optional(),
17433
+ maxSessions: number().int().positive().optional(),
17434
+ steps: record(string(), DeviceStepConfigSchema).optional()
17435
+ }))
17436
+ }), object({ success: literal(true) }), {
17437
+ kind: "mutation",
17438
+ auth: "admin"
17439
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17302
17440
  success: literal(true),
17303
17441
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17304
17442
  effectiveModelId: string().nullable(),
@@ -17314,9 +17452,10 @@ method(object({
17314
17452
  }), object({ success: literal(true) }), {
17315
17453
  kind: "mutation",
17316
17454
  auth: "admin"
17317
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17455
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17318
17456
  deviceId: number(),
17319
17457
  agentNodeId: string(),
17458
+ deviceKey: string(),
17320
17459
  addonId: string(),
17321
17460
  patch: CameraStepOverridePatchSchema.nullable()
17322
17461
  }), object({ success: literal(true) }), {
@@ -17353,14 +17492,13 @@ method(object({
17353
17492
  });
17354
17493
  /**
17355
17494
  * server-management — per-NODE singleton capability for a node's ROOT
17356
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17357
- * agents).
17495
+ * package lifecycle (runtime-updatable node packages).
17358
17496
  *
17359
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17360
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17361
- * version describes the node. Updates install into
17362
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17363
- * starter (probation boot + auto-rollback to N-1).
17497
+ * Every node role runs the SAME root package (`@camstack/server`), which
17498
+ * carries the whole software stack in its npm dep tree, so ONE version
17499
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17500
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17501
+ * no auto-rollback).
17364
17502
  *
17365
17503
  * Providers:
17366
17504
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17468,7 +17606,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17468
17606
  /** Explicit target version; omitted = latest from the registry. */
17469
17607
  version: string().optional() }), ServerUpdateActionResultSchema, {
17470
17608
  kind: "mutation",
17471
- auth: "admin"
17609
+ auth: "admin",
17610
+ timeoutMs: 16 * 6e4
17472
17611
  }), method(_void(), ServerUpdateActionResultSchema, {
17473
17612
  kind: "mutation",
17474
17613
  auth: "admin"
@@ -18512,22 +18651,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18512
18651
  var RestartAddonResultSchema = unknown();
18513
18652
  var InstallPackageResultSchema = unknown();
18514
18653
  var ReloadPackagesResultSchema = unknown();
18515
- /**
18516
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18517
- * server restarts so the admin UI can react to the `restartingAt`
18518
- * timestamp (shows reconnect overlay). The transition from
18519
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18520
- * `system.restart-completed` event after the new process boots.
18521
- *
18522
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18523
- */
18524
- var UpdateFrameworkPackageResultSchema = object({
18525
- packageName: string(),
18526
- fromVersion: string(),
18527
- toVersion: string(),
18528
- /** Ms-epoch the server scheduled its self-restart. */
18529
- restartingAt: number()
18530
- });
18531
18654
  var BulkUpdateItemStatusSchema = _enum([
18532
18655
  "queued",
18533
18656
  "updating",
@@ -18655,13 +18778,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18655
18778
  }), object({ success: literal(true) }), {
18656
18779
  kind: "mutation",
18657
18780
  auth: "admin"
18658
- }), method(object({
18659
- packageName: string().min(1),
18660
- version: string().optional(),
18661
- deferRestart: boolean().optional()
18662
- }), UpdateFrameworkPackageResultSchema, {
18663
- kind: "mutation",
18664
- auth: "admin"
18665
18781
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18666
18782
  kind: "mutation",
18667
18783
  auth: "admin"
@@ -19527,10 +19643,10 @@ var TopologyCategorySchema = object({
19527
19643
  addons: array(TopologyCategoryAddonSchema).readonly()
19528
19644
  });
19529
19645
  /**
19530
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19531
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19532
- * version visibility for the Server management surface. Nullable: offline
19533
- * rows and pre-phase-2 nodes report none.
19646
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19647
+ * root package for every node role) as reported by its `registerNode`
19648
+ * manifest — version visibility for the Server management surface. Nullable:
19649
+ * offline rows and nodes that never reported one.
19534
19650
  */
19535
19651
  var TopologyRootPackageSchema = object({
19536
19652
  name: string(),
@@ -19918,17 +20034,28 @@ var PlatformScoreSchema = object({
19918
20034
  format: _enum([
19919
20035
  "onnx",
19920
20036
  "coreml",
19921
- "openvino"
20037
+ "openvino",
20038
+ "tflite"
19922
20039
  ]),
19923
20040
  score: number(),
19924
20041
  reason: string(),
19925
20042
  available: boolean()
19926
20043
  });
20044
+ var InferenceDeviceDescriptorSchema = object({
20045
+ key: string(),
20046
+ backend: string(),
20047
+ device: string(),
20048
+ format: ModelFormatSchema,
20049
+ runtime: literal("python"),
20050
+ score: number(),
20051
+ available: boolean()
20052
+ });
19927
20053
  var PlatformCapabilitiesSchema = object({
19928
20054
  hardware: HardwareInfoSchema,
19929
20055
  scores: array(PlatformScoreSchema).readonly(),
19930
20056
  bestScore: PlatformScoreSchema,
19931
- pythonPath: string().nullable()
20057
+ pythonPath: string().nullable(),
20058
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19932
20059
  });
19933
20060
  var ModelRequirementSchema = object({
19934
20061
  modelId: string(),
@@ -20807,12 +20934,6 @@ Object.freeze({
20807
20934
  addonId: null,
20808
20935
  access: "delete"
20809
20936
  },
20810
- "addons.updateFrameworkPackage": {
20811
- capName: "addons",
20812
- capScope: "system",
20813
- addonId: null,
20814
- access: "create"
20815
- },
20816
20937
  "addons.updatePackage": {
20817
20938
  capName: "addons",
20818
20939
  capScope: "system",
@@ -23585,12 +23706,6 @@ Object.freeze({
23585
23706
  addonId: null,
23586
23707
  access: "view"
23587
23708
  },
23588
- "pipelineExecutor.reprobeEngine": {
23589
- capName: "pipeline-executor",
23590
- capScope: "system",
23591
- addonId: null,
23592
- access: "create"
23593
- },
23594
23709
  "pipelineExecutor.runAudioTest": {
23595
23710
  capName: "pipeline-executor",
23596
23711
  capScope: "system",
@@ -23741,6 +23856,12 @@ Object.freeze({
23741
23856
  addonId: null,
23742
23857
  access: "view"
23743
23858
  },
23859
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23860
+ capName: "pipeline-orchestrator",
23861
+ capScope: "system",
23862
+ addonId: null,
23863
+ access: "view"
23864
+ },
23744
23865
  "pipelineOrchestrator.getPipelineAssignment": {
23745
23866
  capName: "pipeline-orchestrator",
23746
23867
  capScope: "system",
@@ -23753,6 +23874,12 @@ Object.freeze({
23753
23874
  addonId: null,
23754
23875
  access: "view"
23755
23876
  },
23877
+ "pipelineOrchestrator.getPipelineDevicePin": {
23878
+ capName: "pipeline-orchestrator",
23879
+ capScope: "system",
23880
+ addonId: null,
23881
+ access: "view"
23882
+ },
23756
23883
  "pipelineOrchestrator.listAgentSettings": {
23757
23884
  capName: "pipeline-orchestrator",
23758
23885
  capScope: "system",
@@ -23795,19 +23922,19 @@ Object.freeze({
23795
23922
  addonId: null,
23796
23923
  access: "create"
23797
23924
  },
23798
- "pipelineOrchestrator.setAgentAddonDefaults": {
23925
+ "pipelineOrchestrator.setAgentCapabilities": {
23799
23926
  capName: "pipeline-orchestrator",
23800
23927
  capScope: "system",
23801
23928
  addonId: null,
23802
23929
  access: "create"
23803
23930
  },
23804
- "pipelineOrchestrator.setAgentCapabilities": {
23931
+ "pipelineOrchestrator.setAgentDetectWeight": {
23805
23932
  capName: "pipeline-orchestrator",
23806
23933
  capScope: "system",
23807
23934
  addonId: null,
23808
23935
  access: "create"
23809
23936
  },
23810
- "pipelineOrchestrator.setAgentDetectWeight": {
23937
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23811
23938
  capName: "pipeline-orchestrator",
23812
23939
  capScope: "system",
23813
23940
  addonId: null,
@@ -23849,6 +23976,12 @@ Object.freeze({
23849
23976
  addonId: null,
23850
23977
  access: "create"
23851
23978
  },
23979
+ "pipelineOrchestrator.setPipelineDevicePin": {
23980
+ capName: "pipeline-orchestrator",
23981
+ capScope: "system",
23982
+ addonId: null,
23983
+ access: "create"
23984
+ },
23852
23985
  "pipelineOrchestrator.unassignAudio": {
23853
23986
  capName: "pipeline-orchestrator",
23854
23987
  capScope: "system",
@@ -25401,32 +25534,6 @@ Object.freeze({
25401
25534
  "network-access": "ingress",
25402
25535
  "smtp-provider": "email"
25403
25536
  });
25404
- var frameworkSwapPackageSchema = object({
25405
- name: string(),
25406
- stagedPath: string(),
25407
- backupPath: string(),
25408
- toVersion: string(),
25409
- fromVersion: string().nullable()
25410
- });
25411
- object({
25412
- jobId: string(),
25413
- taskId: string(),
25414
- packages: array(frameworkSwapPackageSchema),
25415
- requestedAtMs: number(),
25416
- schemaVersion: literal(1)
25417
- });
25418
- object({
25419
- jobId: string(),
25420
- taskId: string(),
25421
- backups: array(object({
25422
- name: string(),
25423
- backupPath: string(),
25424
- livePath: string()
25425
- })),
25426
- appliedAtMs: number(),
25427
- bootAttempts: number(),
25428
- schemaVersion: literal(1)
25429
- });
25430
25537
  //#endregion
25431
25538
  //#region src/custom-actions.ts
25432
25539
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-alexa",
3
- "version": "1.1.27",
3
+ "version": "1.2.1",
4
4
  "description": "Alexa Smart Home Skill export — hub-side OAuth provider + directive handler. The companion AWS Lambda forwards Alexa directives to this addon's /addon/export-alexa/directive endpoint.",
5
5
  "keywords": [
6
6
  "camstack",