@camstack/addon-decoder-ffmpeg 1.1.19 → 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.
Files changed (3) hide show
  1. package/dist/index.js +213 -106
  2. package/dist/index.mjs +213 -106
  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). */
@@ -11302,7 +11340,21 @@ var NativeCropResultSchema = object({
11302
11340
  /** Packed rgb (24-bit) pixels of the crop. */
11303
11341
  bytes: _instanceof(Uint8Array),
11304
11342
  width: number().int().positive(),
11305
- height: number().int().positive()
11343
+ height: number().int().positive(),
11344
+ /**
11345
+ * Which source served this crop, so a quality-sensitive consumer (the native
11346
+ * `keyFrame`) can reject a degraded fallback:
11347
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11348
+ * quality path).
11349
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11350
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11351
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11352
+ *
11353
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11354
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11355
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11356
+ */
11357
+ tier: _enum(["native", "ram-fullframe"]).optional()
11306
11358
  });
11307
11359
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11308
11360
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11542,7 +11594,14 @@ var RunnerCameraConfigSchema = object({
11542
11594
  * camera's detect node differs from its source-owner (P2d, gated by the
11543
11595
  * `remoteSourcingNodes` rollout setting).
11544
11596
  */
11545
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11597
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11598
+ /**
11599
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11600
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11601
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11602
+ * this only selects WHICH device pool of that node runs the session.
11603
+ */
11604
+ deviceKey: string().optional()
11546
11605
  });
11547
11606
  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
11607
  /**
@@ -11563,6 +11622,19 @@ var RunnerLocalLoadSchema = object({
11563
11622
  avgInferenceTimeMs: number(),
11564
11623
  /** Total queue depth across motion + detection queues. */
11565
11624
  queueDepthTotal: number(),
11625
+ /**
11626
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11627
+ * this runner currently has attached cameras on, so the orchestrator's second
11628
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11629
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11630
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11631
+ */
11632
+ devices: array(object({
11633
+ deviceKey: string(),
11634
+ backend: string(),
11635
+ attachedCameras: number(),
11636
+ queueDepthTotal: number()
11637
+ })).default([]),
11566
11638
  /** Hardware capability flags reported by this node. */
11567
11639
  hardware: object({
11568
11640
  hasGpu: boolean(),
@@ -13038,6 +13110,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13038
13110
  kind: "mutation",
13039
13111
  auth: "admin"
13040
13112
  });
13113
+ 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;
13114
+ new Set(Object.values(DeviceType));
13041
13115
  /**
13042
13116
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13043
13117
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -14741,7 +14815,8 @@ var LinkedDeviceSchema = object({
14741
14815
  deviceId: number(),
14742
14816
  name: string(),
14743
14817
  location: string().nullable(),
14744
- features: array(string())
14818
+ features: array(string()),
14819
+ producesTrackedEvents: boolean().optional()
14745
14820
  });
14746
14821
  var SavedDeviceRowSchema = object({
14747
14822
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16371,6 +16446,7 @@ var TrackSchema = object({
16371
16446
  deviceId: number(),
16372
16447
  className: string(),
16373
16448
  label: string().optional(),
16449
+ producingDeviceName: string().optional(),
16374
16450
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16375
16451
  source: TrackSourceSchema.optional(),
16376
16452
  firstSeen: number(),
@@ -16508,7 +16584,8 @@ var MediaFileKindEnum = _enum([
16508
16584
  "fullFrameBoxed",
16509
16585
  "faceCrop",
16510
16586
  "plateCrop",
16511
- "keyFrame"
16587
+ "keyFrame",
16588
+ "keyFrameSmall"
16512
16589
  ]);
16513
16590
  var MediaFileSchema = object({
16514
16591
  key: string(),
@@ -16837,13 +16914,11 @@ var PipelineTemplateSchema = object({
16837
16914
  createdAt: string(),
16838
16915
  updatedAt: string()
16839
16916
  });
16840
- var AgentAddonConfigSchema = object({
16841
- enabled: boolean(),
16917
+ var DeviceStepConfigSchema = object({
16842
16918
  modelId: string().optional(),
16843
- settings: record(string(), unknown()).readonly()
16919
+ settings: record(string(), unknown()).optional()
16844
16920
  });
16845
16921
  var AgentPipelineSettingsSchema = object({
16846
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16847
16922
  maxCameras: number().int().nonnegative().nullable().default(null),
16848
16923
  /** Per-node detection weight (relative share for the quota balancer). */
16849
16924
  detectWeight: number().positive().optional(),
@@ -16867,7 +16942,22 @@ var AgentPipelineSettingsSchema = object({
16867
16942
  * it already uses to reach the hub). Set this only when the auto-detected
16868
16943
  * address is wrong (multi-homed host, NAT, custom interface).
16869
16944
  */
16870
- reachableHost: string().optional()
16945
+ reachableHost: string().optional(),
16946
+ /**
16947
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16948
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16949
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16950
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16951
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16952
+ * the default model/settings for every camera landing on that accelerator;
16953
+ * a stepId absent ⇒ the step uses that device's format default.
16954
+ */
16955
+ inferenceDevices: record(string(), object({
16956
+ enabled: boolean(),
16957
+ weight: number().positive().optional(),
16958
+ maxSessions: number().int().positive().optional(),
16959
+ steps: record(string(), DeviceStepConfigSchema).optional()
16960
+ })).optional()
16871
16961
  });
16872
16962
  var CameraPipelineForAgentSchema = object({
16873
16963
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16877,14 +16967,13 @@ var CameraPipelineForAgentSchema = object({
16877
16967
  }).nullable()
16878
16968
  });
16879
16969
  var CameraStepOverridePatchSchema = object({
16880
- enabled: boolean().optional(),
16881
16970
  modelId: string().optional(),
16882
16971
  settings: record(string(), unknown()).readonly().optional()
16883
16972
  });
16884
16973
  var CameraPipelineSettingsSchema = object({
16885
16974
  pinnedAgentNodeId: string().optional(),
16886
16975
  stepToggles: record(string(), boolean()).optional(),
16887
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
16976
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
16888
16977
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
16889
16978
  });
16890
16979
  /**
@@ -17098,6 +17187,44 @@ var CameraStatusSchema = object({
17098
17187
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17099
17188
  fetchedAt: number()
17100
17189
  });
17190
+ var NodeInferenceDeviceSchema = object({
17191
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17192
+ key: string(),
17193
+ backend: string(),
17194
+ device: string(),
17195
+ format: _enum(MODEL_FORMATS),
17196
+ /** Whether the node's live probe reports the device as usable right now. */
17197
+ available: boolean(),
17198
+ /**
17199
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17200
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17201
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17202
+ * not a balanced target). An explicit stored value always wins; a stored-only
17203
+ * (unavailable) key keeps its stored value.
17204
+ */
17205
+ enabled: boolean(),
17206
+ /** Relative balancer weight for the enabled device (default 1). */
17207
+ weight: number(),
17208
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17209
+ maxSessions: number().nullable(),
17210
+ /** Object-detection model the executor defaults to for this deviceKey. */
17211
+ defaultModelId: string(),
17212
+ /**
17213
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17214
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17215
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17216
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17217
+ * available per format; this is the stored selection that becomes the
17218
+ * default for EVERY camera landing on this accelerator.
17219
+ */
17220
+ steps: record(string(), DeviceStepConfigSchema).optional()
17221
+ });
17222
+ var NodeInferenceDevicesSchema = object({
17223
+ nodeId: string(),
17224
+ /** False when the node's platform-probe was unreachable (no live device set). */
17225
+ reachable: boolean(),
17226
+ devices: array(NodeInferenceDeviceSchema).readonly()
17227
+ });
17101
17228
  method(object({
17102
17229
  deviceId: number(),
17103
17230
  agentNodeId: string()
@@ -17107,7 +17234,13 @@ method(object({
17107
17234
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17108
17235
  kind: "mutation",
17109
17236
  auth: "admin"
17110
- }), method(_void(), object({ migrated: number() }), {
17237
+ }), method(object({
17238
+ deviceId: number(),
17239
+ deviceKey: string()
17240
+ }), object({ success: literal(true) }), {
17241
+ kind: "mutation",
17242
+ auth: "admin"
17243
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17111
17244
  kind: "mutation",
17112
17245
  auth: "admin"
17113
17246
  }), 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 +17274,7 @@ method(object({
17141
17274
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17142
17275
  nodeId: string(),
17143
17276
  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({
17277
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17151
17278
  success: boolean(),
17152
17279
  removed: boolean()
17153
17280
  }), {
@@ -17179,7 +17306,18 @@ method(object({
17179
17306
  }), object({ success: literal(true) }), {
17180
17307
  kind: "mutation",
17181
17308
  auth: "admin"
17182
- }), method(object({ agentNodeId: string() }), object({
17309
+ }), method(object({
17310
+ agentNodeId: string(),
17311
+ inferenceDevices: record(string(), object({
17312
+ enabled: boolean(),
17313
+ weight: number().positive().optional(),
17314
+ maxSessions: number().int().positive().optional(),
17315
+ steps: record(string(), DeviceStepConfigSchema).optional()
17316
+ }))
17317
+ }), object({ success: literal(true) }), {
17318
+ kind: "mutation",
17319
+ auth: "admin"
17320
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17183
17321
  success: literal(true),
17184
17322
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17185
17323
  effectiveModelId: string().nullable(),
@@ -17195,9 +17333,10 @@ method(object({
17195
17333
  }), object({ success: literal(true) }), {
17196
17334
  kind: "mutation",
17197
17335
  auth: "admin"
17198
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17336
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17199
17337
  deviceId: number(),
17200
17338
  agentNodeId: string(),
17339
+ deviceKey: string(),
17201
17340
  addonId: string(),
17202
17341
  patch: CameraStepOverridePatchSchema.nullable()
17203
17342
  }), object({ success: literal(true) }), {
@@ -17234,14 +17373,13 @@ method(object({
17234
17373
  });
17235
17374
  /**
17236
17375
  * server-management — per-NODE singleton capability for a node's ROOT
17237
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17238
- * agents).
17376
+ * package lifecycle (runtime-updatable node packages).
17239
17377
  *
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).
17378
+ * Every node role runs the SAME root package (`@camstack/server`), which
17379
+ * carries the whole software stack in its npm dep tree, so ONE version
17380
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17381
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17382
+ * no auto-rollback).
17245
17383
  *
17246
17384
  * Providers:
17247
17385
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17349,7 +17487,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17349
17487
  /** Explicit target version; omitted = latest from the registry. */
17350
17488
  version: string().optional() }), ServerUpdateActionResultSchema, {
17351
17489
  kind: "mutation",
17352
- auth: "admin"
17490
+ auth: "admin",
17491
+ timeoutMs: 16 * 6e4
17353
17492
  }), method(_void(), ServerUpdateActionResultSchema, {
17354
17493
  kind: "mutation",
17355
17494
  auth: "admin"
@@ -18393,22 +18532,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18393
18532
  var RestartAddonResultSchema = unknown();
18394
18533
  var InstallPackageResultSchema = unknown();
18395
18534
  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
18535
  var BulkUpdateItemStatusSchema = _enum([
18413
18536
  "queued",
18414
18537
  "updating",
@@ -18536,13 +18659,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18536
18659
  }), object({ success: literal(true) }), {
18537
18660
  kind: "mutation",
18538
18661
  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
18662
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18547
18663
  kind: "mutation",
18548
18664
  auth: "admin"
@@ -19408,10 +19524,10 @@ var TopologyCategorySchema = object({
19408
19524
  addons: array(TopologyCategoryAddonSchema).readonly()
19409
19525
  });
19410
19526
  /**
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.
19527
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19528
+ * root package for every node role) as reported by its `registerNode`
19529
+ * manifest — version visibility for the Server management surface. Nullable:
19530
+ * offline rows and nodes that never reported one.
19415
19531
  */
19416
19532
  var TopologyRootPackageSchema = object({
19417
19533
  name: string(),
@@ -19799,17 +19915,28 @@ var PlatformScoreSchema = object({
19799
19915
  format: _enum([
19800
19916
  "onnx",
19801
19917
  "coreml",
19802
- "openvino"
19918
+ "openvino",
19919
+ "tflite"
19803
19920
  ]),
19804
19921
  score: number(),
19805
19922
  reason: string(),
19806
19923
  available: boolean()
19807
19924
  });
19925
+ var InferenceDeviceDescriptorSchema = object({
19926
+ key: string(),
19927
+ backend: string(),
19928
+ device: string(),
19929
+ format: ModelFormatSchema,
19930
+ runtime: literal("python"),
19931
+ score: number(),
19932
+ available: boolean()
19933
+ });
19808
19934
  var PlatformCapabilitiesSchema = object({
19809
19935
  hardware: HardwareInfoSchema,
19810
19936
  scores: array(PlatformScoreSchema).readonly(),
19811
19937
  bestScore: PlatformScoreSchema,
19812
- pythonPath: string().nullable()
19938
+ pythonPath: string().nullable(),
19939
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19813
19940
  });
19814
19941
  var ModelRequirementSchema = object({
19815
19942
  modelId: string(),
@@ -20688,12 +20815,6 @@ Object.freeze({
20688
20815
  addonId: null,
20689
20816
  access: "delete"
20690
20817
  },
20691
- "addons.updateFrameworkPackage": {
20692
- capName: "addons",
20693
- capScope: "system",
20694
- addonId: null,
20695
- access: "create"
20696
- },
20697
20818
  "addons.updatePackage": {
20698
20819
  capName: "addons",
20699
20820
  capScope: "system",
@@ -23466,12 +23587,6 @@ Object.freeze({
23466
23587
  addonId: null,
23467
23588
  access: "view"
23468
23589
  },
23469
- "pipelineExecutor.reprobeEngine": {
23470
- capName: "pipeline-executor",
23471
- capScope: "system",
23472
- addonId: null,
23473
- access: "create"
23474
- },
23475
23590
  "pipelineExecutor.runAudioTest": {
23476
23591
  capName: "pipeline-executor",
23477
23592
  capScope: "system",
@@ -23622,6 +23737,12 @@ Object.freeze({
23622
23737
  addonId: null,
23623
23738
  access: "view"
23624
23739
  },
23740
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23741
+ capName: "pipeline-orchestrator",
23742
+ capScope: "system",
23743
+ addonId: null,
23744
+ access: "view"
23745
+ },
23625
23746
  "pipelineOrchestrator.getPipelineAssignment": {
23626
23747
  capName: "pipeline-orchestrator",
23627
23748
  capScope: "system",
@@ -23634,6 +23755,12 @@ Object.freeze({
23634
23755
  addonId: null,
23635
23756
  access: "view"
23636
23757
  },
23758
+ "pipelineOrchestrator.getPipelineDevicePin": {
23759
+ capName: "pipeline-orchestrator",
23760
+ capScope: "system",
23761
+ addonId: null,
23762
+ access: "view"
23763
+ },
23637
23764
  "pipelineOrchestrator.listAgentSettings": {
23638
23765
  capName: "pipeline-orchestrator",
23639
23766
  capScope: "system",
@@ -23676,19 +23803,19 @@ Object.freeze({
23676
23803
  addonId: null,
23677
23804
  access: "create"
23678
23805
  },
23679
- "pipelineOrchestrator.setAgentAddonDefaults": {
23806
+ "pipelineOrchestrator.setAgentCapabilities": {
23680
23807
  capName: "pipeline-orchestrator",
23681
23808
  capScope: "system",
23682
23809
  addonId: null,
23683
23810
  access: "create"
23684
23811
  },
23685
- "pipelineOrchestrator.setAgentCapabilities": {
23812
+ "pipelineOrchestrator.setAgentDetectWeight": {
23686
23813
  capName: "pipeline-orchestrator",
23687
23814
  capScope: "system",
23688
23815
  addonId: null,
23689
23816
  access: "create"
23690
23817
  },
23691
- "pipelineOrchestrator.setAgentDetectWeight": {
23818
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23692
23819
  capName: "pipeline-orchestrator",
23693
23820
  capScope: "system",
23694
23821
  addonId: null,
@@ -23730,6 +23857,12 @@ Object.freeze({
23730
23857
  addonId: null,
23731
23858
  access: "create"
23732
23859
  },
23860
+ "pipelineOrchestrator.setPipelineDevicePin": {
23861
+ capName: "pipeline-orchestrator",
23862
+ capScope: "system",
23863
+ addonId: null,
23864
+ access: "create"
23865
+ },
23733
23866
  "pipelineOrchestrator.unassignAudio": {
23734
23867
  capName: "pipeline-orchestrator",
23735
23868
  capScope: "system",
@@ -25282,32 +25415,6 @@ Object.freeze({
25282
25415
  "network-access": "ingress",
25283
25416
  "smtp-provider": "email"
25284
25417
  });
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
25418
  /**
25312
25419
  * Fixed-capacity ring buffer. When full, push() overwrites the oldest entry.
25313
25420
  * 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). */
@@ -11298,7 +11336,21 @@ var NativeCropResultSchema = object({
11298
11336
  /** Packed rgb (24-bit) pixels of the crop. */
11299
11337
  bytes: _instanceof(Uint8Array),
11300
11338
  width: number().int().positive(),
11301
- height: number().int().positive()
11339
+ height: number().int().positive(),
11340
+ /**
11341
+ * Which source served this crop, so a quality-sensitive consumer (the native
11342
+ * `keyFrame`) can reject a degraded fallback:
11343
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
11344
+ * quality path).
11345
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
11346
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
11347
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
11348
+ *
11349
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
11350
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
11351
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
11352
+ */
11353
+ tier: _enum(["native", "ram-fullframe"]).optional()
11302
11354
  });
11303
11355
  /** Parent detection context passed to `runDetailSubtree` — the crop's
11304
11356
  * originating detection, in FRAME-space coordinates. Reuses
@@ -11538,7 +11590,14 @@ var RunnerCameraConfigSchema = object({
11538
11590
  * camera's detect node differs from its source-owner (P2d, gated by the
11539
11591
  * `remoteSourcingNodes` rollout setting).
11540
11592
  */
11541
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
11593
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
11594
+ /**
11595
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
11596
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
11597
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
11598
+ * this only selects WHICH device pool of that node runs the session.
11599
+ */
11600
+ deviceKey: string().optional()
11542
11601
  });
11543
11602
  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
11603
  /**
@@ -11559,6 +11618,19 @@ var RunnerLocalLoadSchema = object({
11559
11618
  avgInferenceTimeMs: number(),
11560
11619
  /** Total queue depth across motion + detection queues. */
11561
11620
  queueDepthTotal: number(),
11621
+ /**
11622
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
11623
+ * this runner currently has attached cameras on, so the orchestrator's second
11624
+ * `balance()` pass (over a node's devices) weights on real per-pool session
11625
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
11626
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
11627
+ */
11628
+ devices: array(object({
11629
+ deviceKey: string(),
11630
+ backend: string(),
11631
+ attachedCameras: number(),
11632
+ queueDepthTotal: number()
11633
+ })).default([]),
11562
11634
  /** Hardware capability flags reported by this node. */
11563
11635
  hardware: object({
11564
11636
  hasGpu: boolean(),
@@ -13034,6 +13106,8 @@ method(_void(), _void(), { kind: "mutation" }), method(_void(), _void(), { kind:
13034
13106
  kind: "mutation",
13035
13107
  auth: "admin"
13036
13108
  });
13109
+ 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;
13110
+ new Set(Object.values(DeviceType));
13037
13111
  /**
13038
13112
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
13039
13113
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -14737,7 +14811,8 @@ var LinkedDeviceSchema = object({
14737
14811
  deviceId: number(),
14738
14812
  name: string(),
14739
14813
  location: string().nullable(),
14740
- features: array(string())
14814
+ features: array(string()),
14815
+ producesTrackedEvents: boolean().optional()
14741
14816
  });
14742
14817
  var SavedDeviceRowSchema = object({
14743
14818
  /** Numeric id reserved at allocateDeviceId time. */
@@ -16367,6 +16442,7 @@ var TrackSchema = object({
16367
16442
  deviceId: number(),
16368
16443
  className: string(),
16369
16444
  label: string().optional(),
16445
+ producingDeviceName: string().optional(),
16370
16446
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
16371
16447
  source: TrackSourceSchema.optional(),
16372
16448
  firstSeen: number(),
@@ -16504,7 +16580,8 @@ var MediaFileKindEnum = _enum([
16504
16580
  "fullFrameBoxed",
16505
16581
  "faceCrop",
16506
16582
  "plateCrop",
16507
- "keyFrame"
16583
+ "keyFrame",
16584
+ "keyFrameSmall"
16508
16585
  ]);
16509
16586
  var MediaFileSchema = object({
16510
16587
  key: string(),
@@ -16833,13 +16910,11 @@ var PipelineTemplateSchema = object({
16833
16910
  createdAt: string(),
16834
16911
  updatedAt: string()
16835
16912
  });
16836
- var AgentAddonConfigSchema = object({
16837
- enabled: boolean(),
16913
+ var DeviceStepConfigSchema = object({
16838
16914
  modelId: string().optional(),
16839
- settings: record(string(), unknown()).readonly()
16915
+ settings: record(string(), unknown()).optional()
16840
16916
  });
16841
16917
  var AgentPipelineSettingsSchema = object({
16842
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
16843
16918
  maxCameras: number().int().nonnegative().nullable().default(null),
16844
16919
  /** Per-node detection weight (relative share for the quota balancer). */
16845
16920
  detectWeight: number().positive().optional(),
@@ -16863,7 +16938,22 @@ var AgentPipelineSettingsSchema = object({
16863
16938
  * it already uses to reach the hub). Set this only when the auto-detected
16864
16939
  * address is wrong (multi-homed host, NAT, custom interface).
16865
16940
  */
16866
- reachableHost: string().optional()
16941
+ reachableHost: string().optional(),
16942
+ /**
16943
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
16944
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
16945
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
16946
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
16947
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
16948
+ * the default model/settings for every camera landing on that accelerator;
16949
+ * a stepId absent ⇒ the step uses that device's format default.
16950
+ */
16951
+ inferenceDevices: record(string(), object({
16952
+ enabled: boolean(),
16953
+ weight: number().positive().optional(),
16954
+ maxSessions: number().int().positive().optional(),
16955
+ steps: record(string(), DeviceStepConfigSchema).optional()
16956
+ })).optional()
16867
16957
  });
16868
16958
  var CameraPipelineForAgentSchema = object({
16869
16959
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16873,14 +16963,13 @@ var CameraPipelineForAgentSchema = object({
16873
16963
  }).nullable()
16874
16964
  });
16875
16965
  var CameraStepOverridePatchSchema = object({
16876
- enabled: boolean().optional(),
16877
16966
  modelId: string().optional(),
16878
16967
  settings: record(string(), unknown()).readonly().optional()
16879
16968
  });
16880
16969
  var CameraPipelineSettingsSchema = object({
16881
16970
  pinnedAgentNodeId: string().optional(),
16882
16971
  stepToggles: record(string(), boolean()).optional(),
16883
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
16972
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
16884
16973
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
16885
16974
  });
16886
16975
  /**
@@ -17094,6 +17183,44 @@ var CameraStatusSchema = object({
17094
17183
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
17095
17184
  fetchedAt: number()
17096
17185
  });
17186
+ var NodeInferenceDeviceSchema = object({
17187
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
17188
+ key: string(),
17189
+ backend: string(),
17190
+ device: string(),
17191
+ format: _enum(MODEL_FORMATS),
17192
+ /** Whether the node's live probe reports the device as usable right now. */
17193
+ available: boolean(),
17194
+ /**
17195
+ * Whether this device participates in dispatch. AUTO default (spec C2):
17196
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
17197
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
17198
+ * not a balanced target). An explicit stored value always wins; a stored-only
17199
+ * (unavailable) key keeps its stored value.
17200
+ */
17201
+ enabled: boolean(),
17202
+ /** Relative balancer weight for the enabled device (default 1). */
17203
+ weight: number(),
17204
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
17205
+ maxSessions: number().nullable(),
17206
+ /** Object-detection model the executor defaults to for this deviceKey. */
17207
+ defaultModelId: string(),
17208
+ /**
17209
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
17210
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
17211
+ * Absent/empty ⇒ no base (every step uses its device format default). The
17212
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
17213
+ * available per format; this is the stored selection that becomes the
17214
+ * default for EVERY camera landing on this accelerator.
17215
+ */
17216
+ steps: record(string(), DeviceStepConfigSchema).optional()
17217
+ });
17218
+ var NodeInferenceDevicesSchema = object({
17219
+ nodeId: string(),
17220
+ /** False when the node's platform-probe was unreachable (no live device set). */
17221
+ reachable: boolean(),
17222
+ devices: array(NodeInferenceDeviceSchema).readonly()
17223
+ });
17097
17224
  method(object({
17098
17225
  deviceId: number(),
17099
17226
  agentNodeId: string()
@@ -17103,7 +17230,13 @@ method(object({
17103
17230
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
17104
17231
  kind: "mutation",
17105
17232
  auth: "admin"
17106
- }), method(_void(), object({ migrated: number() }), {
17233
+ }), method(object({
17234
+ deviceId: number(),
17235
+ deviceKey: string()
17236
+ }), object({ success: literal(true) }), {
17237
+ kind: "mutation",
17238
+ auth: "admin"
17239
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
17107
17240
  kind: "mutation",
17108
17241
  auth: "admin"
17109
17242
  }), 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 +17270,7 @@ method(object({
17137
17270
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
17138
17271
  nodeId: string(),
17139
17272
  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({
17273
+ })).readonly()), method(object({ agentNodeId: string() }), object({
17147
17274
  success: boolean(),
17148
17275
  removed: boolean()
17149
17276
  }), {
@@ -17175,7 +17302,18 @@ method(object({
17175
17302
  }), object({ success: literal(true) }), {
17176
17303
  kind: "mutation",
17177
17304
  auth: "admin"
17178
- }), method(object({ agentNodeId: string() }), object({
17305
+ }), method(object({
17306
+ agentNodeId: string(),
17307
+ inferenceDevices: record(string(), object({
17308
+ enabled: boolean(),
17309
+ weight: number().positive().optional(),
17310
+ maxSessions: number().int().positive().optional(),
17311
+ steps: record(string(), DeviceStepConfigSchema).optional()
17312
+ }))
17313
+ }), object({ success: literal(true) }), {
17314
+ kind: "mutation",
17315
+ auth: "admin"
17316
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
17179
17317
  success: literal(true),
17180
17318
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
17181
17319
  effectiveModelId: string().nullable(),
@@ -17191,9 +17329,10 @@ method(object({
17191
17329
  }), object({ success: literal(true) }), {
17192
17330
  kind: "mutation",
17193
17331
  auth: "admin"
17194
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
17332
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
17195
17333
  deviceId: number(),
17196
17334
  agentNodeId: string(),
17335
+ deviceKey: string(),
17197
17336
  addonId: string(),
17198
17337
  patch: CameraStepOverridePatchSchema.nullable()
17199
17338
  }), object({ success: literal(true) }), {
@@ -17230,14 +17369,13 @@ method(object({
17230
17369
  });
17231
17370
  /**
17232
17371
  * server-management — per-NODE singleton capability for a node's ROOT
17233
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
17234
- * agents).
17372
+ * package lifecycle (runtime-updatable node packages).
17235
17373
  *
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).
17374
+ * Every node role runs the SAME root package (`@camstack/server`), which
17375
+ * carries the whole software stack in its npm dep tree, so ONE version
17376
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
17377
+ * on restart via the baked starter (single-copy in-place swap — no probation,
17378
+ * no auto-rollback).
17241
17379
  *
17242
17380
  * Providers:
17243
17381
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -17345,7 +17483,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
17345
17483
  /** Explicit target version; omitted = latest from the registry. */
17346
17484
  version: string().optional() }), ServerUpdateActionResultSchema, {
17347
17485
  kind: "mutation",
17348
- auth: "admin"
17486
+ auth: "admin",
17487
+ timeoutMs: 16 * 6e4
17349
17488
  }), method(_void(), ServerUpdateActionResultSchema, {
17350
17489
  kind: "mutation",
17351
17490
  auth: "admin"
@@ -18389,22 +18528,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
18389
18528
  var RestartAddonResultSchema = unknown();
18390
18529
  var InstallPackageResultSchema = unknown();
18391
18530
  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
18531
  var BulkUpdateItemStatusSchema = _enum([
18409
18532
  "queued",
18410
18533
  "updating",
@@ -18532,13 +18655,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
18532
18655
  }), object({ success: literal(true) }), {
18533
18656
  kind: "mutation",
18534
18657
  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
18658
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
18543
18659
  kind: "mutation",
18544
18660
  auth: "admin"
@@ -19404,10 +19520,10 @@ var TopologyCategorySchema = object({
19404
19520
  addons: array(TopologyCategoryAddonSchema).readonly()
19405
19521
  });
19406
19522
  /**
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.
19523
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
19524
+ * root package for every node role) as reported by its `registerNode`
19525
+ * manifest — version visibility for the Server management surface. Nullable:
19526
+ * offline rows and nodes that never reported one.
19411
19527
  */
19412
19528
  var TopologyRootPackageSchema = object({
19413
19529
  name: string(),
@@ -19795,17 +19911,28 @@ var PlatformScoreSchema = object({
19795
19911
  format: _enum([
19796
19912
  "onnx",
19797
19913
  "coreml",
19798
- "openvino"
19914
+ "openvino",
19915
+ "tflite"
19799
19916
  ]),
19800
19917
  score: number(),
19801
19918
  reason: string(),
19802
19919
  available: boolean()
19803
19920
  });
19921
+ var InferenceDeviceDescriptorSchema = object({
19922
+ key: string(),
19923
+ backend: string(),
19924
+ device: string(),
19925
+ format: ModelFormatSchema,
19926
+ runtime: literal("python"),
19927
+ score: number(),
19928
+ available: boolean()
19929
+ });
19804
19930
  var PlatformCapabilitiesSchema = object({
19805
19931
  hardware: HardwareInfoSchema,
19806
19932
  scores: array(PlatformScoreSchema).readonly(),
19807
19933
  bestScore: PlatformScoreSchema,
19808
- pythonPath: string().nullable()
19934
+ pythonPath: string().nullable(),
19935
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
19809
19936
  });
19810
19937
  var ModelRequirementSchema = object({
19811
19938
  modelId: string(),
@@ -20684,12 +20811,6 @@ Object.freeze({
20684
20811
  addonId: null,
20685
20812
  access: "delete"
20686
20813
  },
20687
- "addons.updateFrameworkPackage": {
20688
- capName: "addons",
20689
- capScope: "system",
20690
- addonId: null,
20691
- access: "create"
20692
- },
20693
20814
  "addons.updatePackage": {
20694
20815
  capName: "addons",
20695
20816
  capScope: "system",
@@ -23462,12 +23583,6 @@ Object.freeze({
23462
23583
  addonId: null,
23463
23584
  access: "view"
23464
23585
  },
23465
- "pipelineExecutor.reprobeEngine": {
23466
- capName: "pipeline-executor",
23467
- capScope: "system",
23468
- addonId: null,
23469
- access: "create"
23470
- },
23471
23586
  "pipelineExecutor.runAudioTest": {
23472
23587
  capName: "pipeline-executor",
23473
23588
  capScope: "system",
@@ -23618,6 +23733,12 @@ Object.freeze({
23618
23733
  addonId: null,
23619
23734
  access: "view"
23620
23735
  },
23736
+ "pipelineOrchestrator.getNodeInferenceDevices": {
23737
+ capName: "pipeline-orchestrator",
23738
+ capScope: "system",
23739
+ addonId: null,
23740
+ access: "view"
23741
+ },
23621
23742
  "pipelineOrchestrator.getPipelineAssignment": {
23622
23743
  capName: "pipeline-orchestrator",
23623
23744
  capScope: "system",
@@ -23630,6 +23751,12 @@ Object.freeze({
23630
23751
  addonId: null,
23631
23752
  access: "view"
23632
23753
  },
23754
+ "pipelineOrchestrator.getPipelineDevicePin": {
23755
+ capName: "pipeline-orchestrator",
23756
+ capScope: "system",
23757
+ addonId: null,
23758
+ access: "view"
23759
+ },
23633
23760
  "pipelineOrchestrator.listAgentSettings": {
23634
23761
  capName: "pipeline-orchestrator",
23635
23762
  capScope: "system",
@@ -23672,19 +23799,19 @@ Object.freeze({
23672
23799
  addonId: null,
23673
23800
  access: "create"
23674
23801
  },
23675
- "pipelineOrchestrator.setAgentAddonDefaults": {
23802
+ "pipelineOrchestrator.setAgentCapabilities": {
23676
23803
  capName: "pipeline-orchestrator",
23677
23804
  capScope: "system",
23678
23805
  addonId: null,
23679
23806
  access: "create"
23680
23807
  },
23681
- "pipelineOrchestrator.setAgentCapabilities": {
23808
+ "pipelineOrchestrator.setAgentDetectWeight": {
23682
23809
  capName: "pipeline-orchestrator",
23683
23810
  capScope: "system",
23684
23811
  addonId: null,
23685
23812
  access: "create"
23686
23813
  },
23687
- "pipelineOrchestrator.setAgentDetectWeight": {
23814
+ "pipelineOrchestrator.setAgentInferenceDevices": {
23688
23815
  capName: "pipeline-orchestrator",
23689
23816
  capScope: "system",
23690
23817
  addonId: null,
@@ -23726,6 +23853,12 @@ Object.freeze({
23726
23853
  addonId: null,
23727
23854
  access: "create"
23728
23855
  },
23856
+ "pipelineOrchestrator.setPipelineDevicePin": {
23857
+ capName: "pipeline-orchestrator",
23858
+ capScope: "system",
23859
+ addonId: null,
23860
+ access: "create"
23861
+ },
23729
23862
  "pipelineOrchestrator.unassignAudio": {
23730
23863
  capName: "pipeline-orchestrator",
23731
23864
  capScope: "system",
@@ -25278,32 +25411,6 @@ Object.freeze({
25278
25411
  "network-access": "ingress",
25279
25412
  "smtp-provider": "email"
25280
25413
  });
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
25414
  /**
25308
25415
  * Fixed-capacity ring buffer. When full, push() overwrites the oldest entry.
25309
25416
  * 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.1",
4
4
  "description": "Standalone ffmpeg-subprocess decoder fallback addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",