@camstack/addon-decoder-ffmpeg 1.1.19 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +193 -103
  2. package/dist/index.mjs +193 -103
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7085,6 +7085,17 @@ var ModelCatalogEntrySchema = object({
7085
7085
  "imagenet",
7086
7086
  "none"
7087
7087
  ]).optional(),
7088
+ /**
7089
+ * The model already applies softmax IN-GRAPH — its raw output is a
7090
+ * probability distribution, not logits. When set, the `softmax`
7091
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7092
+ * probability vector collapses it toward uniform (top-1 score craters far
7093
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7094
+ * the output is raw logits and the postprocessor applies softmax (the normal
7095
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7096
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7097
+ */
7098
+ outputProbabilities: boolean().optional(),
7088
7099
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7089
7100
  /**
7090
7101
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11098,10 +11109,7 @@ var ConfigUISchemaNullableBridge = custom();
11098
11109
  var InferenceCapabilitiesBridge = custom();
11099
11110
  var ModelAvailabilityListBridge = custom();
11100
11111
  var PipelineRunResultBridge = custom();
11101
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11102
- kind: "mutation",
11103
- auth: "admin"
11104
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11112
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11105
11113
  modelId: string(),
11106
11114
  settings: record(string(), unknown()).readonly()
11107
11115
  }))), method(object({ steps: record(string(), object({
@@ -11161,13 +11169,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11161
11169
  * (inputClasses ≠ null) are skipped and served per-track via
11162
11170
  * pipelineRunner.runDetailSubtree (two-plane design).
11163
11171
  */
11164
- plane: _enum(["full", "frame"]).optional()
11172
+ plane: _enum(["full", "frame"]).optional(),
11173
+ /**
11174
+ * Inference-device selector (Phase 2 multi-device). Format
11175
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11176
+ * Omitted ⇒ the runner's default device (current single-engine
11177
+ * behaviour). Selects WHICH device pool of the node runs the call.
11178
+ */
11179
+ deviceKey: string().optional()
11165
11180
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11166
11181
  engine: PipelineEngineChoiceSchema.optional(),
11167
11182
  steps: array(PipelineStepInputSchema).min(1),
11168
11183
  frames: array(FrameInputSchema).min(1).max(255),
11169
11184
  deviceId: number().optional(),
11170
- sessionId: string().optional()
11185
+ sessionId: string().optional(),
11186
+ /**
11187
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11188
+ * the batch to the Python pool's bench preprocess cache
11189
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11190
+ * preprocessed ONCE and every later inference is a pure-inference cache
11191
+ * hit — the sustained-throughput run measures inference, not
11192
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11193
+ * full preprocess every call, correct). Fresh per sustained run;
11194
+ * released via `uncacheFrame`.
11195
+ */
11196
+ frameId: number().int().nonnegative().optional(),
11197
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11198
+ deviceKey: string().optional()
11171
11199
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11172
11200
  data: _instanceof(Uint8Array),
11173
11201
  width: number().int().positive(),
@@ -11199,8 +11227,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11199
11227
  * - `runtime` — main camera-serving engine (no idle TTL).
11200
11228
  * - `warm-override` — benchmark/test override held in the warm
11201
11229
  * cache; auto-disposed after the idle TTL.
11230
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11231
+ * multi-device, keyed by `deviceKey`) resolved
11232
+ * via `resolveDeviceFactory`. Runs alongside the
11233
+ * `runtime` engine on a DIFFERENT accelerator
11234
+ * (NPU / iGPU / Coral) — this is how the
11235
+ * Engines tab shows all pools running at once.
11202
11236
  */
11203
- kind: _enum(["runtime", "warm-override"]),
11237
+ kind: _enum([
11238
+ "runtime",
11239
+ "warm-override",
11240
+ "device-pool"
11241
+ ]),
11204
11242
  /** Native pid of the underlying Python pool (null when no pool). */
11205
11243
  poolPid: number().nullable(),
11206
11244
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11542,7 +11580,14 @@ var RunnerCameraConfigSchema = object({
11542
11580
  * camera's detect node differs from its source-owner (P2d, gated by the
11543
11581
  * `remoteSourcingNodes` rollout setting).
11544
11582
  */
11545
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11583
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11584
+ /**
11585
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11586
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11587
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11588
+ * this only selects WHICH device pool of that node runs the session.
11589
+ */
11590
+ deviceKey: string().optional()
11546
11591
  });
11547
11592
  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;
11548
11593
  /**
@@ -11563,6 +11608,19 @@ var RunnerLocalLoadSchema = object({
11563
11608
  avgInferenceTimeMs: number(),
11564
11609
  /** Total queue depth across motion + detection queues. */
11565
11610
  queueDepthTotal: number(),
11611
+ /**
11612
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11613
+ * this runner currently has attached cameras on, so the orchestrator's second
11614
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11615
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11616
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11617
+ */
11618
+ devices: array(object({
11619
+ deviceKey: string(),
11620
+ backend: string(),
11621
+ attachedCameras: number(),
11622
+ queueDepthTotal: number()
11623
+ })).default([]),
11566
11624
  /** Hardware capability flags reported by this node. */
11567
11625
  hardware: object({
11568
11626
  hasGpu: boolean(),
@@ -13038,6 +13096,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13038
13096
  kind: "mutation",
13039
13097
  auth: "admin"
13040
13098
  });
13099
+ 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;
13100
+ new Set(Object.values(DeviceType));
13041
13101
  /**
13042
13102
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13043
13103
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -16837,13 +16897,11 @@ var PipelineTemplateSchema = object({
16837
16897
  createdAt: string(),
16838
16898
  updatedAt: string()
16839
16899
  });
16840
- var AgentAddonConfigSchema = object({
16841
- enabled: boolean(),
16900
+ var DeviceStepConfigSchema = object({
16842
16901
  modelId: string().optional(),
16843
- settings: record(string(), unknown()).readonly()
16902
+ settings: record(string(), unknown()).optional()
16844
16903
  });
16845
16904
  var AgentPipelineSettingsSchema = object({
16846
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16847
16905
  maxCameras: number().int().nonnegative().nullable().default(null),
16848
16906
  /** Per-node detection weight (relative share for the quota balancer). */
16849
16907
  detectWeight: number().positive().optional(),
@@ -16867,7 +16925,22 @@ var AgentPipelineSettingsSchema = object({
16867
16925
  * it already uses to reach the hub). Set this only when the auto-detected
16868
16926
  * address is wrong (multi-homed host, NAT, custom interface).
16869
16927
  */
16870
- reachableHost: string().optional()
16928
+ reachableHost: string().optional(),
16929
+ /**
16930
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16931
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16932
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16933
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16934
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16935
+ * the default model/settings for every camera landing on that accelerator;
16936
+ * a stepId absent ⇒ the step uses that device's format default.
16937
+ */
16938
+ inferenceDevices: record(string(), object({
16939
+ enabled: boolean(),
16940
+ weight: number().positive().optional(),
16941
+ maxSessions: number().int().positive().optional(),
16942
+ steps: record(string(), DeviceStepConfigSchema).optional()
16943
+ })).optional()
16871
16944
  });
16872
16945
  var CameraPipelineForAgentSchema = object({
16873
16946
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16877,14 +16950,13 @@ var CameraPipelineForAgentSchema = object({
16877
16950
  }).nullable()
16878
16951
  });
16879
16952
  var CameraStepOverridePatchSchema = object({
16880
- enabled: boolean().optional(),
16881
16953
  modelId: string().optional(),
16882
16954
  settings: record(string(), unknown()).readonly().optional()
16883
16955
  });
16884
16956
  var CameraPipelineSettingsSchema = object({
16885
16957
  pinnedAgentNodeId: string().optional(),
16886
16958
  stepToggles: record(string(), boolean()).optional(),
16887
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
16959
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
16888
16960
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
16889
16961
  });
16890
16962
  /**
@@ -17098,6 +17170,44 @@ var CameraStatusSchema = object({
17098
17170
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17099
17171
  fetchedAt: number()
17100
17172
  });
17173
+ var NodeInferenceDeviceSchema = object({
17174
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17175
+ key: string(),
17176
+ backend: string(),
17177
+ device: string(),
17178
+ format: _enum(MODEL_FORMATS),
17179
+ /** Whether the node's live probe reports the device as usable right now. */
17180
+ available: boolean(),
17181
+ /**
17182
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17183
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17184
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17185
+ * not a balanced target). An explicit stored value always wins; a stored-only
17186
+ * (unavailable) key keeps its stored value.
17187
+ */
17188
+ enabled: boolean(),
17189
+ /** Relative balancer weight for the enabled device (default 1). */
17190
+ weight: number(),
17191
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17192
+ maxSessions: number().nullable(),
17193
+ /** Object-detection model the executor defaults to for this deviceKey. */
17194
+ defaultModelId: string(),
17195
+ /**
17196
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17197
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17198
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17199
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17200
+ * available per format; this is the stored selection that becomes the
17201
+ * default for EVERY camera landing on this accelerator.
17202
+ */
17203
+ steps: record(string(), DeviceStepConfigSchema).optional()
17204
+ });
17205
+ var NodeInferenceDevicesSchema = object({
17206
+ nodeId: string(),
17207
+ /** False when the node's platform-probe was unreachable (no live device set). */
17208
+ reachable: boolean(),
17209
+ devices: array(NodeInferenceDeviceSchema).readonly()
17210
+ });
17101
17211
  method(object({
17102
17212
  deviceId: number(),
17103
17213
  agentNodeId: string()
@@ -17107,7 +17217,13 @@ method(object({
17107
17217
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17108
17218
  kind: "mutation",
17109
17219
  auth: "admin"
17110
- }), method(_void(), object({ migrated: number() }), {
17220
+ }), method(object({
17221
+ deviceId: number(),
17222
+ deviceKey: string()
17223
+ }), object({ success: literal(true) }), {
17224
+ kind: "mutation",
17225
+ auth: "admin"
17226
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17111
17227
  kind: "mutation",
17112
17228
  auth: "admin"
17113
17229
  }), 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({
@@ -17141,13 +17257,7 @@ method(object({
17141
17257
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17142
17258
  nodeId: string(),
17143
17259
  settings: AgentPipelineSettingsSchema
17144
- })).readonly()), method(object({
17145
- agentNodeId: string(),
17146
- defaults: record(string(), AgentAddonConfigSchema)
17147
- }), object({ success: literal(true) }), {
17148
- kind: "mutation",
17149
- auth: "admin"
17150
- }), method(object({ agentNodeId: string() }), object({
17260
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17151
17261
  success: boolean(),
17152
17262
  removed: boolean()
17153
17263
  }), {
@@ -17179,7 +17289,18 @@ method(object({
17179
17289
  }), object({ success: literal(true) }), {
17180
17290
  kind: "mutation",
17181
17291
  auth: "admin"
17182
- }), method(object({ agentNodeId: string() }), object({
17292
+ }), method(object({
17293
+ agentNodeId: string(),
17294
+ inferenceDevices: record(string(), object({
17295
+ enabled: boolean(),
17296
+ weight: number().positive().optional(),
17297
+ maxSessions: number().int().positive().optional(),
17298
+ steps: record(string(), DeviceStepConfigSchema).optional()
17299
+ }))
17300
+ }), object({ success: literal(true) }), {
17301
+ kind: "mutation",
17302
+ auth: "admin"
17303
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17183
17304
  success: literal(true),
17184
17305
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17185
17306
  effectiveModelId: string().nullable(),
@@ -17195,9 +17316,10 @@ method(object({
17195
17316
  }), object({ success: literal(true) }), {
17196
17317
  kind: "mutation",
17197
17318
  auth: "admin"
17198
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17319
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17199
17320
  deviceId: number(),
17200
17321
  agentNodeId: string(),
17322
+ deviceKey: string(),
17201
17323
  addonId: string(),
17202
17324
  patch: CameraStepOverridePatchSchema.nullable()
17203
17325
  }), object({ success: literal(true) }), {
@@ -17234,14 +17356,13 @@ method(object({
17234
17356
  });
17235
17357
  /**
17236
17358
  * server-management — per-NODE singleton capability for a node's ROOT
17237
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17238
- * agents).
17359
+ * package lifecycle (runtime-updatable node packages).
17239
17360
  *
17240
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17241
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17242
- * version describes the node. Updates install into
17243
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17244
- * starter (probation boot + auto-rollback to N-1).
17361
+ * Every node role runs the SAME root package (`@camstack/server`), which
17362
+ * carries the whole software stack in its npm dep tree, so ONE version
17363
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17364
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17365
+ * no auto-rollback).
17245
17366
  *
17246
17367
  * Providers:
17247
17368
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17349,7 +17470,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17349
17470
  /** Explicit target version; omitted = latest from the registry. */
17350
17471
  version: string().optional() }), ServerUpdateActionResultSchema, {
17351
17472
  kind: "mutation",
17352
- auth: "admin"
17473
+ auth: "admin",
17474
+ timeoutMs: 16 * 6e4
17353
17475
  }), method(_void(), ServerUpdateActionResultSchema, {
17354
17476
  kind: "mutation",
17355
17477
  auth: "admin"
@@ -18393,22 +18515,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18393
18515
  var RestartAddonResultSchema = unknown();
18394
18516
  var InstallPackageResultSchema = unknown();
18395
18517
  var ReloadPackagesResultSchema = unknown();
18396
- /**
18397
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18398
- * server restarts so the admin UI can react to the `restartingAt`
18399
- * timestamp (shows reconnect overlay). The transition from
18400
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18401
- * `system.restart-completed` event after the new process boots.
18402
- *
18403
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18404
- */
18405
- var UpdateFrameworkPackageResultSchema = object({
18406
- packageName: string(),
18407
- fromVersion: string(),
18408
- toVersion: string(),
18409
- /** Ms-epoch the server scheduled its self-restart. */
18410
- restartingAt: number()
18411
- });
18412
18518
  var BulkUpdateItemStatusSchema = _enum([
18413
18519
  "queued",
18414
18520
  "updating",
@@ -18536,13 +18642,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18536
18642
  }), object({ success: literal(true) }), {
18537
18643
  kind: "mutation",
18538
18644
  auth: "admin"
18539
- }), method(object({
18540
- packageName: string().min(1),
18541
- version: string().optional(),
18542
- deferRestart: boolean().optional()
18543
- }), UpdateFrameworkPackageResultSchema, {
18544
- kind: "mutation",
18545
- auth: "admin"
18546
18645
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18547
18646
  kind: "mutation",
18548
18647
  auth: "admin"
@@ -19408,10 +19507,10 @@ var TopologyCategorySchema = object({
19408
19507
  addons: array(TopologyCategoryAddonSchema).readonly()
19409
19508
  });
19410
19509
  /**
19411
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19412
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19413
- * version visibility for the Server management surface. Nullable: offline
19414
- * rows and pre-phase-2 nodes report none.
19510
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19511
+ * root package for every node role) as reported by its `registerNode`
19512
+ * manifest — version visibility for the Server management surface. Nullable:
19513
+ * offline rows and nodes that never reported one.
19415
19514
  */
19416
19515
  var TopologyRootPackageSchema = object({
19417
19516
  name: string(),
@@ -19799,17 +19898,28 @@ var PlatformScoreSchema = object({
19799
19898
  format: _enum([
19800
19899
  "onnx",
19801
19900
  "coreml",
19802
- "openvino"
19901
+ "openvino",
19902
+ "tflite"
19803
19903
  ]),
19804
19904
  score: number(),
19805
19905
  reason: string(),
19806
19906
  available: boolean()
19807
19907
  });
19908
+ var InferenceDeviceDescriptorSchema = object({
19909
+ key: string(),
19910
+ backend: string(),
19911
+ device: string(),
19912
+ format: ModelFormatSchema,
19913
+ runtime: literal("python"),
19914
+ score: number(),
19915
+ available: boolean()
19916
+ });
19808
19917
  var PlatformCapabilitiesSchema = object({
19809
19918
  hardware: HardwareInfoSchema,
19810
19919
  scores: array(PlatformScoreSchema).readonly(),
19811
19920
  bestScore: PlatformScoreSchema,
19812
- pythonPath: string().nullable()
19921
+ pythonPath: string().nullable(),
19922
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19813
19923
  });
19814
19924
  var ModelRequirementSchema = object({
19815
19925
  modelId: string(),
@@ -20688,12 +20798,6 @@ Object.freeze({
20688
20798
  addonId: null,
20689
20799
  access: "delete"
20690
20800
  },
20691
- "addons.updateFrameworkPackage": {
20692
- capName: "addons",
20693
- capScope: "system",
20694
- addonId: null,
20695
- access: "create"
20696
- },
20697
20801
  "addons.updatePackage": {
20698
20802
  capName: "addons",
20699
20803
  capScope: "system",
@@ -23466,12 +23570,6 @@ Object.freeze({
23466
23570
  addonId: null,
23467
23571
  access: "view"
23468
23572
  },
23469
- "pipelineExecutor.reprobeEngine": {
23470
- capName: "pipeline-executor",
23471
- capScope: "system",
23472
- addonId: null,
23473
- access: "create"
23474
- },
23475
23573
  "pipelineExecutor.runAudioTest": {
23476
23574
  capName: "pipeline-executor",
23477
23575
  capScope: "system",
@@ -23622,6 +23720,12 @@ Object.freeze({
23622
23720
  addonId: null,
23623
23721
  access: "view"
23624
23722
  },
23723
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23724
+ capName: "pipeline-orchestrator",
23725
+ capScope: "system",
23726
+ addonId: null,
23727
+ access: "view"
23728
+ },
23625
23729
  "pipelineOrchestrator.getPipelineAssignment": {
23626
23730
  capName: "pipeline-orchestrator",
23627
23731
  capScope: "system",
@@ -23634,6 +23738,12 @@ Object.freeze({
23634
23738
  addonId: null,
23635
23739
  access: "view"
23636
23740
  },
23741
+ "pipelineOrchestrator.getPipelineDevicePin": {
23742
+ capName: "pipeline-orchestrator",
23743
+ capScope: "system",
23744
+ addonId: null,
23745
+ access: "view"
23746
+ },
23637
23747
  "pipelineOrchestrator.listAgentSettings": {
23638
23748
  capName: "pipeline-orchestrator",
23639
23749
  capScope: "system",
@@ -23676,19 +23786,19 @@ Object.freeze({
23676
23786
  addonId: null,
23677
23787
  access: "create"
23678
23788
  },
23679
- "pipelineOrchestrator.setAgentAddonDefaults": {
23789
+ "pipelineOrchestrator.setAgentCapabilities": {
23680
23790
  capName: "pipeline-orchestrator",
23681
23791
  capScope: "system",
23682
23792
  addonId: null,
23683
23793
  access: "create"
23684
23794
  },
23685
- "pipelineOrchestrator.setAgentCapabilities": {
23795
+ "pipelineOrchestrator.setAgentDetectWeight": {
23686
23796
  capName: "pipeline-orchestrator",
23687
23797
  capScope: "system",
23688
23798
  addonId: null,
23689
23799
  access: "create"
23690
23800
  },
23691
- "pipelineOrchestrator.setAgentDetectWeight": {
23801
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23692
23802
  capName: "pipeline-orchestrator",
23693
23803
  capScope: "system",
23694
23804
  addonId: null,
@@ -23730,6 +23840,12 @@ Object.freeze({
23730
23840
  addonId: null,
23731
23841
  access: "create"
23732
23842
  },
23843
+ "pipelineOrchestrator.setPipelineDevicePin": {
23844
+ capName: "pipeline-orchestrator",
23845
+ capScope: "system",
23846
+ addonId: null,
23847
+ access: "create"
23848
+ },
23733
23849
  "pipelineOrchestrator.unassignAudio": {
23734
23850
  capName: "pipeline-orchestrator",
23735
23851
  capScope: "system",
@@ -25282,32 +25398,6 @@ Object.freeze({
25282
25398
  "network-access": "ingress",
25283
25399
  "smtp-provider": "email"
25284
25400
  });
25285
- var frameworkSwapPackageSchema = object({
25286
- name: string(),
25287
- stagedPath: string(),
25288
- backupPath: string(),
25289
- toVersion: string(),
25290
- fromVersion: string().nullable()
25291
- });
25292
- object({
25293
- jobId: string(),
25294
- taskId: string(),
25295
- packages: array(frameworkSwapPackageSchema),
25296
- requestedAtMs: number(),
25297
- schemaVersion: literal(1)
25298
- });
25299
- object({
25300
- jobId: string(),
25301
- taskId: string(),
25302
- backups: array(object({
25303
- name: string(),
25304
- backupPath: string(),
25305
- livePath: string()
25306
- })),
25307
- appliedAtMs: number(),
25308
- bootAttempts: number(),
25309
- schemaVersion: literal(1)
25310
- });
25311
25401
  /**
25312
25402
  * Fixed-capacity ring buffer. When full, push() overwrites the oldest entry.
25313
25403
  * drain() returns up to maxCount items in FIFO order and removes them.
package/dist/index.mjs CHANGED
@@ -7081,6 +7081,17 @@ var ModelCatalogEntrySchema = object({
7081
7081
  "imagenet",
7082
7082
  "none"
7083
7083
  ]).optional(),
7084
+ /**
7085
+ * The model already applies softmax IN-GRAPH — its raw output is a
7086
+ * probability distribution, not logits. When set, the `softmax`
7087
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7088
+ * probability vector collapses it toward uniform (top-1 score craters far
7089
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7090
+ * the output is raw logits and the postprocessor applies softmax (the normal
7091
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7092
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7093
+ */
7094
+ outputProbabilities: boolean().optional(),
7084
7095
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7085
7096
  /**
7086
7097
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -11094,10 +11105,7 @@ var ConfigUISchemaNullableBridge = custom();
11094
11105
  var InferenceCapabilitiesBridge = custom();
11095
11106
  var ModelAvailabilityListBridge = custom();
11096
11107
  var PipelineRunResultBridge = custom();
11097
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
11098
- kind: "mutation",
11099
- auth: "admin"
11100
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11108
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
11101
11109
  modelId: string(),
11102
11110
  settings: record(string(), unknown()).readonly()
11103
11111
  }))), method(object({ steps: record(string(), object({
@@ -11157,13 +11165,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11157
11165
  * (inputClasses ≠ null) are skipped and served per-track via
11158
11166
  * pipelineRunner.runDetailSubtree (two-plane design).
11159
11167
  */
11160
- plane: _enum(["full", "frame"]).optional()
11168
+ plane: _enum(["full", "frame"]).optional(),
11169
+ /**
11170
+ * Inference-device selector (Phase 2 multi-device). Format
11171
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
11172
+ * Omitted ⇒ the runner's default device (current single-engine
11173
+ * behaviour). Selects WHICH device pool of the node runs the call.
11174
+ */
11175
+ deviceKey: string().optional()
11161
11176
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
11162
11177
  engine: PipelineEngineChoiceSchema.optional(),
11163
11178
  steps: array(PipelineStepInputSchema).min(1),
11164
11179
  frames: array(FrameInputSchema).min(1).max(255),
11165
11180
  deviceId: number().optional(),
11166
- sessionId: string().optional()
11181
+ sessionId: string().optional(),
11182
+ /**
11183
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
11184
+ * the batch to the Python pool's bench preprocess cache
11185
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
11186
+ * preprocessed ONCE and every later inference is a pure-inference cache
11187
+ * hit — the sustained-throughput run measures inference, not
11188
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
11189
+ * full preprocess every call, correct). Fresh per sustained run;
11190
+ * released via `uncacheFrame`.
11191
+ */
11192
+ frameId: number().int().nonnegative().optional(),
11193
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
11194
+ deviceKey: string().optional()
11167
11195
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
11168
11196
  data: _instanceof(Uint8Array),
11169
11197
  width: number().int().positive(),
@@ -11195,8 +11223,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
11195
11223
  * - `runtime` — main camera-serving engine (no idle TTL).
11196
11224
  * - `warm-override` — benchmark/test override held in the warm
11197
11225
  * cache; auto-disposed after the idle TTL.
11226
+ * - `device-pool` — a concurrent per-device pool (Phase 2
11227
+ * multi-device, keyed by `deviceKey`) resolved
11228
+ * via `resolveDeviceFactory`. Runs alongside the
11229
+ * `runtime` engine on a DIFFERENT accelerator
11230
+ * (NPU / iGPU / Coral) — this is how the
11231
+ * Engines tab shows all pools running at once.
11198
11232
  */
11199
- kind: _enum(["runtime", "warm-override"]),
11233
+ kind: _enum([
11234
+ "runtime",
11235
+ "warm-override",
11236
+ "device-pool"
11237
+ ]),
11200
11238
  /** Native pid of the underlying Python pool (null when no pool). */
11201
11239
  poolPid: number().nullable(),
11202
11240
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -11538,7 +11576,14 @@ var RunnerCameraConfigSchema = object({
11538
11576
  * camera's detect node differs from its source-owner (P2d, gated by the
11539
11577
  * `remoteSourcingNodes` rollout setting).
11540
11578
  */
11541
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11579
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11580
+ /**
11581
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11582
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11583
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11584
+ * this only selects WHICH device pool of that node runs the session.
11585
+ */
11586
+ deviceKey: string().optional()
11542
11587
  });
11543
11588
  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;
11544
11589
  /**
@@ -11559,6 +11604,19 @@ var RunnerLocalLoadSchema = object({
11559
11604
  avgInferenceTimeMs: number(),
11560
11605
  /** Total queue depth across motion + detection queues. */
11561
11606
  queueDepthTotal: number(),
11607
+ /**
11608
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11609
+ * this runner currently has attached cameras on, so the orchestrator's second
11610
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11611
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11612
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11613
+ */
11614
+ devices: array(object({
11615
+ deviceKey: string(),
11616
+ backend: string(),
11617
+ attachedCameras: number(),
11618
+ queueDepthTotal: number()
11619
+ })).default([]),
11562
11620
  /** Hardware capability flags reported by this node. */
11563
11621
  hardware: object({
11564
11622
  hasGpu: boolean(),
@@ -13034,6 +13092,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13034
13092
  kind: "mutation",
13035
13093
  auth: "admin"
13036
13094
  });
13095
+ 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;
13096
+ new Set(Object.values(DeviceType));
13037
13097
  /**
13038
13098
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13039
13099
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -16833,13 +16893,11 @@ var PipelineTemplateSchema = object({
16833
16893
  createdAt: string(),
16834
16894
  updatedAt: string()
16835
16895
  });
16836
- var AgentAddonConfigSchema = object({
16837
- enabled: boolean(),
16896
+ var DeviceStepConfigSchema = object({
16838
16897
  modelId: string().optional(),
16839
- settings: record(string(), unknown()).readonly()
16898
+ settings: record(string(), unknown()).optional()
16840
16899
  });
16841
16900
  var AgentPipelineSettingsSchema = object({
16842
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16843
16901
  maxCameras: number().int().nonnegative().nullable().default(null),
16844
16902
  /** Per-node detection weight (relative share for the quota balancer). */
16845
16903
  detectWeight: number().positive().optional(),
@@ -16863,7 +16921,22 @@ var AgentPipelineSettingsSchema = object({
16863
16921
  * it already uses to reach the hub). Set this only when the auto-detected
16864
16922
  * address is wrong (multi-homed host, NAT, custom interface).
16865
16923
  */
16866
- reachableHost: string().optional()
16924
+ reachableHost: string().optional(),
16925
+ /**
16926
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16927
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16928
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16929
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16930
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16931
+ * the default model/settings for every camera landing on that accelerator;
16932
+ * a stepId absent ⇒ the step uses that device's format default.
16933
+ */
16934
+ inferenceDevices: record(string(), object({
16935
+ enabled: boolean(),
16936
+ weight: number().positive().optional(),
16937
+ maxSessions: number().int().positive().optional(),
16938
+ steps: record(string(), DeviceStepConfigSchema).optional()
16939
+ })).optional()
16867
16940
  });
16868
16941
  var CameraPipelineForAgentSchema = object({
16869
16942
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16873,14 +16946,13 @@ var CameraPipelineForAgentSchema = object({
16873
16946
  }).nullable()
16874
16947
  });
16875
16948
  var CameraStepOverridePatchSchema = object({
16876
- enabled: boolean().optional(),
16877
16949
  modelId: string().optional(),
16878
16950
  settings: record(string(), unknown()).readonly().optional()
16879
16951
  });
16880
16952
  var CameraPipelineSettingsSchema = object({
16881
16953
  pinnedAgentNodeId: string().optional(),
16882
16954
  stepToggles: record(string(), boolean()).optional(),
16883
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
16955
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
16884
16956
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
16885
16957
  });
16886
16958
  /**
@@ -17094,6 +17166,44 @@ var CameraStatusSchema = object({
17094
17166
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17095
17167
  fetchedAt: number()
17096
17168
  });
17169
+ var NodeInferenceDeviceSchema = object({
17170
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17171
+ key: string(),
17172
+ backend: string(),
17173
+ device: string(),
17174
+ format: _enum(MODEL_FORMATS),
17175
+ /** Whether the node's live probe reports the device as usable right now. */
17176
+ available: boolean(),
17177
+ /**
17178
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17179
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17180
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17181
+ * not a balanced target). An explicit stored value always wins; a stored-only
17182
+ * (unavailable) key keeps its stored value.
17183
+ */
17184
+ enabled: boolean(),
17185
+ /** Relative balancer weight for the enabled device (default 1). */
17186
+ weight: number(),
17187
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17188
+ maxSessions: number().nullable(),
17189
+ /** Object-detection model the executor defaults to for this deviceKey. */
17190
+ defaultModelId: string(),
17191
+ /**
17192
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17193
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17194
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17195
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17196
+ * available per format; this is the stored selection that becomes the
17197
+ * default for EVERY camera landing on this accelerator.
17198
+ */
17199
+ steps: record(string(), DeviceStepConfigSchema).optional()
17200
+ });
17201
+ var NodeInferenceDevicesSchema = object({
17202
+ nodeId: string(),
17203
+ /** False when the node's platform-probe was unreachable (no live device set). */
17204
+ reachable: boolean(),
17205
+ devices: array(NodeInferenceDeviceSchema).readonly()
17206
+ });
17097
17207
  method(object({
17098
17208
  deviceId: number(),
17099
17209
  agentNodeId: string()
@@ -17103,7 +17213,13 @@ method(object({
17103
17213
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17104
17214
  kind: "mutation",
17105
17215
  auth: "admin"
17106
- }), method(_void(), object({ migrated: number() }), {
17216
+ }), method(object({
17217
+ deviceId: number(),
17218
+ deviceKey: string()
17219
+ }), object({ success: literal(true) }), {
17220
+ kind: "mutation",
17221
+ auth: "admin"
17222
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17107
17223
  kind: "mutation",
17108
17224
  auth: "admin"
17109
17225
  }), 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({
@@ -17137,13 +17253,7 @@ method(object({
17137
17253
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17138
17254
  nodeId: string(),
17139
17255
  settings: AgentPipelineSettingsSchema
17140
- })).readonly()), method(object({
17141
- agentNodeId: string(),
17142
- defaults: record(string(), AgentAddonConfigSchema)
17143
- }), object({ success: literal(true) }), {
17144
- kind: "mutation",
17145
- auth: "admin"
17146
- }), method(object({ agentNodeId: string() }), object({
17256
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17147
17257
  success: boolean(),
17148
17258
  removed: boolean()
17149
17259
  }), {
@@ -17175,7 +17285,18 @@ method(object({
17175
17285
  }), object({ success: literal(true) }), {
17176
17286
  kind: "mutation",
17177
17287
  auth: "admin"
17178
- }), method(object({ agentNodeId: string() }), object({
17288
+ }), method(object({
17289
+ agentNodeId: string(),
17290
+ inferenceDevices: record(string(), object({
17291
+ enabled: boolean(),
17292
+ weight: number().positive().optional(),
17293
+ maxSessions: number().int().positive().optional(),
17294
+ steps: record(string(), DeviceStepConfigSchema).optional()
17295
+ }))
17296
+ }), object({ success: literal(true) }), {
17297
+ kind: "mutation",
17298
+ auth: "admin"
17299
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17179
17300
  success: literal(true),
17180
17301
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17181
17302
  effectiveModelId: string().nullable(),
@@ -17191,9 +17312,10 @@ method(object({
17191
17312
  }), object({ success: literal(true) }), {
17192
17313
  kind: "mutation",
17193
17314
  auth: "admin"
17194
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17315
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17195
17316
  deviceId: number(),
17196
17317
  agentNodeId: string(),
17318
+ deviceKey: string(),
17197
17319
  addonId: string(),
17198
17320
  patch: CameraStepOverridePatchSchema.nullable()
17199
17321
  }), object({ success: literal(true) }), {
@@ -17230,14 +17352,13 @@ method(object({
17230
17352
  });
17231
17353
  /**
17232
17354
  * server-management — per-NODE singleton capability for a node's ROOT
17233
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17234
- * agents).
17355
+ * package lifecycle (runtime-updatable node packages).
17235
17356
  *
17236
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
17237
- * on agents) carries the whole software stack in its npm dep tree, so ONE
17238
- * version describes the node. Updates install into
17239
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
17240
- * starter (probation boot + auto-rollback to N-1).
17357
+ * Every node role runs the SAME root package (`@camstack/server`), which
17358
+ * carries the whole software stack in its npm dep tree, so ONE version
17359
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17360
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17361
+ * no auto-rollback).
17241
17362
  *
17242
17363
  * Providers:
17243
17364
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17345,7 +17466,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17345
17466
  /** Explicit target version; omitted = latest from the registry. */
17346
17467
  version: string().optional() }), ServerUpdateActionResultSchema, {
17347
17468
  kind: "mutation",
17348
- auth: "admin"
17469
+ auth: "admin",
17470
+ timeoutMs: 16 * 6e4
17349
17471
  }), method(_void(), ServerUpdateActionResultSchema, {
17350
17472
  kind: "mutation",
17351
17473
  auth: "admin"
@@ -18389,22 +18511,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18389
18511
  var RestartAddonResultSchema = unknown();
18390
18512
  var InstallPackageResultSchema = unknown();
18391
18513
  var ReloadPackagesResultSchema = unknown();
18392
- /**
18393
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
18394
- * server restarts so the admin UI can react to the `restartingAt`
18395
- * timestamp (shows reconnect overlay). The transition from
18396
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
18397
- * `system.restart-completed` event after the new process boots.
18398
- *
18399
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
18400
- */
18401
- var UpdateFrameworkPackageResultSchema = object({
18402
- packageName: string(),
18403
- fromVersion: string(),
18404
- toVersion: string(),
18405
- /** Ms-epoch the server scheduled its self-restart. */
18406
- restartingAt: number()
18407
- });
18408
18514
  var BulkUpdateItemStatusSchema = _enum([
18409
18515
  "queued",
18410
18516
  "updating",
@@ -18532,13 +18638,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18532
18638
  }), object({ success: literal(true) }), {
18533
18639
  kind: "mutation",
18534
18640
  auth: "admin"
18535
- }), method(object({
18536
- packageName: string().min(1),
18537
- version: string().optional(),
18538
- deferRestart: boolean().optional()
18539
- }), UpdateFrameworkPackageResultSchema, {
18540
- kind: "mutation",
18541
- auth: "admin"
18542
18641
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18543
18642
  kind: "mutation",
18544
18643
  auth: "admin"
@@ -19404,10 +19503,10 @@ var TopologyCategorySchema = object({
19404
19503
  addons: array(TopologyCategoryAddonSchema).readonly()
19405
19504
  });
19406
19505
  /**
19407
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
19408
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
19409
- * version visibility for the Server management surface. Nullable: offline
19410
- * rows and pre-phase-2 nodes report none.
19506
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19507
+ * root package for every node role) as reported by its `registerNode`
19508
+ * manifest — version visibility for the Server management surface. Nullable:
19509
+ * offline rows and nodes that never reported one.
19411
19510
  */
19412
19511
  var TopologyRootPackageSchema = object({
19413
19512
  name: string(),
@@ -19795,17 +19894,28 @@ var PlatformScoreSchema = object({
19795
19894
  format: _enum([
19796
19895
  "onnx",
19797
19896
  "coreml",
19798
- "openvino"
19897
+ "openvino",
19898
+ "tflite"
19799
19899
  ]),
19800
19900
  score: number(),
19801
19901
  reason: string(),
19802
19902
  available: boolean()
19803
19903
  });
19904
+ var InferenceDeviceDescriptorSchema = object({
19905
+ key: string(),
19906
+ backend: string(),
19907
+ device: string(),
19908
+ format: ModelFormatSchema,
19909
+ runtime: literal("python"),
19910
+ score: number(),
19911
+ available: boolean()
19912
+ });
19804
19913
  var PlatformCapabilitiesSchema = object({
19805
19914
  hardware: HardwareInfoSchema,
19806
19915
  scores: array(PlatformScoreSchema).readonly(),
19807
19916
  bestScore: PlatformScoreSchema,
19808
- pythonPath: string().nullable()
19917
+ pythonPath: string().nullable(),
19918
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19809
19919
  });
19810
19920
  var ModelRequirementSchema = object({
19811
19921
  modelId: string(),
@@ -20684,12 +20794,6 @@ Object.freeze({
20684
20794
  addonId: null,
20685
20795
  access: "delete"
20686
20796
  },
20687
- "addons.updateFrameworkPackage": {
20688
- capName: "addons",
20689
- capScope: "system",
20690
- addonId: null,
20691
- access: "create"
20692
- },
20693
20797
  "addons.updatePackage": {
20694
20798
  capName: "addons",
20695
20799
  capScope: "system",
@@ -23462,12 +23566,6 @@ Object.freeze({
23462
23566
  addonId: null,
23463
23567
  access: "view"
23464
23568
  },
23465
- "pipelineExecutor.reprobeEngine": {
23466
- capName: "pipeline-executor",
23467
- capScope: "system",
23468
- addonId: null,
23469
- access: "create"
23470
- },
23471
23569
  "pipelineExecutor.runAudioTest": {
23472
23570
  capName: "pipeline-executor",
23473
23571
  capScope: "system",
@@ -23618,6 +23716,12 @@ Object.freeze({
23618
23716
  addonId: null,
23619
23717
  access: "view"
23620
23718
  },
23719
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23720
+ capName: "pipeline-orchestrator",
23721
+ capScope: "system",
23722
+ addonId: null,
23723
+ access: "view"
23724
+ },
23621
23725
  "pipelineOrchestrator.getPipelineAssignment": {
23622
23726
  capName: "pipeline-orchestrator",
23623
23727
  capScope: "system",
@@ -23630,6 +23734,12 @@ Object.freeze({
23630
23734
  addonId: null,
23631
23735
  access: "view"
23632
23736
  },
23737
+ "pipelineOrchestrator.getPipelineDevicePin": {
23738
+ capName: "pipeline-orchestrator",
23739
+ capScope: "system",
23740
+ addonId: null,
23741
+ access: "view"
23742
+ },
23633
23743
  "pipelineOrchestrator.listAgentSettings": {
23634
23744
  capName: "pipeline-orchestrator",
23635
23745
  capScope: "system",
@@ -23672,19 +23782,19 @@ Object.freeze({
23672
23782
  addonId: null,
23673
23783
  access: "create"
23674
23784
  },
23675
- "pipelineOrchestrator.setAgentAddonDefaults": {
23785
+ "pipelineOrchestrator.setAgentCapabilities": {
23676
23786
  capName: "pipeline-orchestrator",
23677
23787
  capScope: "system",
23678
23788
  addonId: null,
23679
23789
  access: "create"
23680
23790
  },
23681
- "pipelineOrchestrator.setAgentCapabilities": {
23791
+ "pipelineOrchestrator.setAgentDetectWeight": {
23682
23792
  capName: "pipeline-orchestrator",
23683
23793
  capScope: "system",
23684
23794
  addonId: null,
23685
23795
  access: "create"
23686
23796
  },
23687
- "pipelineOrchestrator.setAgentDetectWeight": {
23797
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23688
23798
  capName: "pipeline-orchestrator",
23689
23799
  capScope: "system",
23690
23800
  addonId: null,
@@ -23726,6 +23836,12 @@ Object.freeze({
23726
23836
  addonId: null,
23727
23837
  access: "create"
23728
23838
  },
23839
+ "pipelineOrchestrator.setPipelineDevicePin": {
23840
+ capName: "pipeline-orchestrator",
23841
+ capScope: "system",
23842
+ addonId: null,
23843
+ access: "create"
23844
+ },
23729
23845
  "pipelineOrchestrator.unassignAudio": {
23730
23846
  capName: "pipeline-orchestrator",
23731
23847
  capScope: "system",
@@ -25278,32 +25394,6 @@ Object.freeze({
25278
25394
  "network-access": "ingress",
25279
25395
  "smtp-provider": "email"
25280
25396
  });
25281
- var frameworkSwapPackageSchema = object({
25282
- name: string(),
25283
- stagedPath: string(),
25284
- backupPath: string(),
25285
- toVersion: string(),
25286
- fromVersion: string().nullable()
25287
- });
25288
- object({
25289
- jobId: string(),
25290
- taskId: string(),
25291
- packages: array(frameworkSwapPackageSchema),
25292
- requestedAtMs: number(),
25293
- schemaVersion: literal(1)
25294
- });
25295
- object({
25296
- jobId: string(),
25297
- taskId: string(),
25298
- backups: array(object({
25299
- name: string(),
25300
- backupPath: string(),
25301
- livePath: string()
25302
- })),
25303
- appliedAtMs: number(),
25304
- bootAttempts: number(),
25305
- schemaVersion: literal(1)
25306
- });
25307
25397
  /**
25308
25398
  * Fixed-capacity ring buffer. When full, push() overwrites the oldest entry.
25309
25399
  * drain() returns up to maxCount items in FIFO order and removes them.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-decoder-ffmpeg",
3
- "version": "1.1.19",
3
+ "version": "1.2.0",
4
4
  "description": "Standalone ffmpeg-subprocess decoder fallback addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",