@camstack/addon-provider-ecowitt 0.1.27 → 0.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/addon.js +213 -106
  2. package/dist/addon.mjs +213 -106
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -7101,6 +7101,17 @@ var ModelCatalogEntrySchema = object({
7101
7101
  "imagenet",
7102
7102
  "none"
7103
7103
  ]).optional(),
7104
+ /**
7105
+ * The model already applies softmax IN-GRAPH — its raw output is a
7106
+ * probability distribution, not logits. When set, the `softmax`
7107
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7108
+ * probability vector collapses it toward uniform (top-1 score craters far
7109
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7110
+ * the output is raw logits and the postprocessor applies softmax (the normal
7111
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7112
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7113
+ */
7114
+ outputProbabilities: boolean().optional(),
7104
7115
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7105
7116
  /**
7106
7117
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12391,10 +12402,7 @@ var ConfigUISchemaNullableBridge = custom();
12391
12402
  var InferenceCapabilitiesBridge = custom();
12392
12403
  var ModelAvailabilityListBridge = custom();
12393
12404
  var PipelineRunResultBridge = custom();
12394
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12395
- kind: "mutation",
12396
- auth: "admin"
12397
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12405
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12398
12406
  modelId: string(),
12399
12407
  settings: record(string(), unknown()).readonly()
12400
12408
  }))), method(object({ steps: record(string(), object({
@@ -12454,13 +12462,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12454
12462
  * (inputClasses ≠ null) are skipped and served per-track via
12455
12463
  * pipelineRunner.runDetailSubtree (two-plane design).
12456
12464
  */
12457
- plane: _enum(["full", "frame"]).optional()
12465
+ plane: _enum(["full", "frame"]).optional(),
12466
+ /**
12467
+ * Inference-device selector (Phase 2 multi-device). Format
12468
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12469
+ * Omitted ⇒ the runner's default device (current single-engine
12470
+ * behaviour). Selects WHICH device pool of the node runs the call.
12471
+ */
12472
+ deviceKey: string().optional()
12458
12473
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12459
12474
  engine: PipelineEngineChoiceSchema.optional(),
12460
12475
  steps: array(PipelineStepInputSchema).min(1),
12461
12476
  frames: array(FrameInputSchema).min(1).max(255),
12462
12477
  deviceId: number().optional(),
12463
- sessionId: string().optional()
12478
+ sessionId: string().optional(),
12479
+ /**
12480
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12481
+ * the batch to the Python pool's bench preprocess cache
12482
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12483
+ * preprocessed ONCE and every later inference is a pure-inference cache
12484
+ * hit — the sustained-throughput run measures inference, not
12485
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12486
+ * full preprocess every call, correct). Fresh per sustained run;
12487
+ * released via `uncacheFrame`.
12488
+ */
12489
+ frameId: number().int().nonnegative().optional(),
12490
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12491
+ deviceKey: string().optional()
12464
12492
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12465
12493
  data: _instanceof(Uint8Array),
12466
12494
  width: number().int().positive(),
@@ -12492,8 +12520,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12492
12520
  * - `runtime` — main camera-serving engine (no idle TTL).
12493
12521
  * - `warm-override` — benchmark/test override held in the warm
12494
12522
  * cache; auto-disposed after the idle TTL.
12523
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12524
+ * multi-device, keyed by `deviceKey`) resolved
12525
+ * via `resolveDeviceFactory`. Runs alongside the
12526
+ * `runtime` engine on a DIFFERENT accelerator
12527
+ * (NPU / iGPU / Coral) — this is how the
12528
+ * Engines tab shows all pools running at once.
12495
12529
  */
12496
- kind: _enum(["runtime", "warm-override"]),
12530
+ kind: _enum([
12531
+ "runtime",
12532
+ "warm-override",
12533
+ "device-pool"
12534
+ ]),
12497
12535
  /** Native pid of the underlying Python pool (null when no pool). */
12498
12536
  poolPid: number().nullable(),
12499
12537
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12628,7 +12666,21 @@ var NativeCropResultSchema = object({
12628
12666
  /** Packed rgb (24-bit) pixels of the crop. */
12629
12667
  bytes: _instanceof(Uint8Array),
12630
12668
  width: number().int().positive(),
12631
- height: number().int().positive()
12669
+ height: number().int().positive(),
12670
+ /**
12671
+ * Which source served this crop, so a quality-sensitive consumer (the native
12672
+ * `keyFrame`) can reject a degraded fallback:
12673
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
12674
+ * quality path).
12675
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
12676
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
12677
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
12678
+ *
12679
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
12680
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
12681
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
12682
+ */
12683
+ tier: _enum(["native", "ram-fullframe"]).optional()
12632
12684
  });
12633
12685
  /** Parent detection context passed to `runDetailSubtree` — the crop's
12634
12686
  * originating detection, in FRAME-space coordinates. Reuses
@@ -12868,7 +12920,14 @@ var RunnerCameraConfigSchema = object({
12868
12920
  * camera's detect node differs from its source-owner (P2d, gated by the
12869
12921
  * `remoteSourcingNodes` rollout setting).
12870
12922
  */
12871
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12923
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12924
+ /**
12925
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12926
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12927
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12928
+ * this only selects WHICH device pool of that node runs the session.
12929
+ */
12930
+ deviceKey: string().optional()
12872
12931
  });
12873
12932
  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;
12874
12933
  /**
@@ -12889,6 +12948,19 @@ var RunnerLocalLoadSchema = object({
12889
12948
  avgInferenceTimeMs: number(),
12890
12949
  /** Total queue depth across motion + detection queues. */
12891
12950
  queueDepthTotal: number(),
12951
+ /**
12952
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12953
+ * this runner currently has attached cameras on, so the orchestrator's second
12954
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12955
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12956
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12957
+ */
12958
+ devices: array(object({
12959
+ deviceKey: string(),
12960
+ backend: string(),
12961
+ attachedCameras: number(),
12962
+ queueDepthTotal: number()
12963
+ })).default([]),
12892
12964
  /** Hardware capability flags reported by this node. */
12893
12965
  hardware: object({
12894
12966
  hasGpu: boolean(),
@@ -16037,6 +16109,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16037
16109
  return toDeviceSummary(device, this.addonId);
16038
16110
  }
16039
16111
  };
16112
+ 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;
16113
+ new Set(Object.values(DeviceType));
16040
16114
  /**
16041
16115
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16042
16116
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -17610,7 +17684,8 @@ var LinkedDeviceSchema = object({
17610
17684
  deviceId: number(),
17611
17685
  name: string(),
17612
17686
  location: string().nullable(),
17613
- features: array(string())
17687
+ features: array(string()),
17688
+ producesTrackedEvents: boolean().optional()
17614
17689
  });
17615
17690
  var SavedDeviceRowSchema = object({
17616
17691
  /** Numeric id reserved at allocateDeviceId time. */
@@ -19240,6 +19315,7 @@ var TrackSchema = object({
19240
19315
  deviceId: number(),
19241
19316
  className: string(),
19242
19317
  label: string().optional(),
19318
+ producingDeviceName: string().optional(),
19243
19319
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
19244
19320
  source: TrackSourceSchema.optional(),
19245
19321
  firstSeen: number(),
@@ -19377,7 +19453,8 @@ var MediaFileKindEnum = _enum([
19377
19453
  "fullFrameBoxed",
19378
19454
  "faceCrop",
19379
19455
  "plateCrop",
19380
- "keyFrame"
19456
+ "keyFrame",
19457
+ "keyFrameSmall"
19381
19458
  ]);
19382
19459
  var MediaFileSchema = object({
19383
19460
  key: string(),
@@ -19706,13 +19783,11 @@ var PipelineTemplateSchema = object({
19706
19783
  createdAt: string(),
19707
19784
  updatedAt: string()
19708
19785
  });
19709
- var AgentAddonConfigSchema = object({
19710
- enabled: boolean(),
19786
+ var DeviceStepConfigSchema = object({
19711
19787
  modelId: string().optional(),
19712
- settings: record(string(), unknown()).readonly()
19788
+ settings: record(string(), unknown()).optional()
19713
19789
  });
19714
19790
  var AgentPipelineSettingsSchema = object({
19715
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19716
19791
  maxCameras: number().int().nonnegative().nullable().default(null),
19717
19792
  /** Per-node detection weight (relative share for the quota balancer). */
19718
19793
  detectWeight: number().positive().optional(),
@@ -19736,7 +19811,22 @@ var AgentPipelineSettingsSchema = object({
19736
19811
  * it already uses to reach the hub). Set this only when the auto-detected
19737
19812
  * address is wrong (multi-homed host, NAT, custom interface).
19738
19813
  */
19739
- reachableHost: string().optional()
19814
+ reachableHost: string().optional(),
19815
+ /**
19816
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19817
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19818
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19819
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19820
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19821
+ * the default model/settings for every camera landing on that accelerator;
19822
+ * a stepId absent ⇒ the step uses that device's format default.
19823
+ */
19824
+ inferenceDevices: record(string(), object({
19825
+ enabled: boolean(),
19826
+ weight: number().positive().optional(),
19827
+ maxSessions: number().int().positive().optional(),
19828
+ steps: record(string(), DeviceStepConfigSchema).optional()
19829
+ })).optional()
19740
19830
  });
19741
19831
  var CameraPipelineForAgentSchema = object({
19742
19832
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19746,14 +19836,13 @@ var CameraPipelineForAgentSchema = object({
19746
19836
  }).nullable()
19747
19837
  });
19748
19838
  var CameraStepOverridePatchSchema = object({
19749
- enabled: boolean().optional(),
19750
19839
  modelId: string().optional(),
19751
19840
  settings: record(string(), unknown()).readonly().optional()
19752
19841
  });
19753
19842
  var CameraPipelineSettingsSchema = object({
19754
19843
  pinnedAgentNodeId: string().optional(),
19755
19844
  stepToggles: record(string(), boolean()).optional(),
19756
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19845
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19757
19846
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19758
19847
  });
19759
19848
  /**
@@ -19967,6 +20056,44 @@ var CameraStatusSchema = object({
19967
20056
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
19968
20057
  fetchedAt: number()
19969
20058
  });
20059
+ var NodeInferenceDeviceSchema = object({
20060
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20061
+ key: string(),
20062
+ backend: string(),
20063
+ device: string(),
20064
+ format: _enum(MODEL_FORMATS),
20065
+ /** Whether the node's live probe reports the device as usable right now. */
20066
+ available: boolean(),
20067
+ /**
20068
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20069
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20070
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20071
+ * not a balanced target). An explicit stored value always wins; a stored-only
20072
+ * (unavailable) key keeps its stored value.
20073
+ */
20074
+ enabled: boolean(),
20075
+ /** Relative balancer weight for the enabled device (default 1). */
20076
+ weight: number(),
20077
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20078
+ maxSessions: number().nullable(),
20079
+ /** Object-detection model the executor defaults to for this deviceKey. */
20080
+ defaultModelId: string(),
20081
+ /**
20082
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20083
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20084
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20085
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20086
+ * available per format; this is the stored selection that becomes the
20087
+ * default for EVERY camera landing on this accelerator.
20088
+ */
20089
+ steps: record(string(), DeviceStepConfigSchema).optional()
20090
+ });
20091
+ var NodeInferenceDevicesSchema = object({
20092
+ nodeId: string(),
20093
+ /** False when the node's platform-probe was unreachable (no live device set). */
20094
+ reachable: boolean(),
20095
+ devices: array(NodeInferenceDeviceSchema).readonly()
20096
+ });
19970
20097
  method(object({
19971
20098
  deviceId: number(),
19972
20099
  agentNodeId: string()
@@ -19976,7 +20103,13 @@ method(object({
19976
20103
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
19977
20104
  kind: "mutation",
19978
20105
  auth: "admin"
19979
- }), method(_void(), object({ migrated: number() }), {
20106
+ }), method(object({
20107
+ deviceId: number(),
20108
+ deviceKey: string()
20109
+ }), object({ success: literal(true) }), {
20110
+ kind: "mutation",
20111
+ auth: "admin"
20112
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
19980
20113
  kind: "mutation",
19981
20114
  auth: "admin"
19982
20115
  }), 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({
@@ -20010,13 +20143,7 @@ method(object({
20010
20143
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20011
20144
  nodeId: string(),
20012
20145
  settings: AgentPipelineSettingsSchema
20013
- })).readonly()), method(object({
20014
- agentNodeId: string(),
20015
- defaults: record(string(), AgentAddonConfigSchema)
20016
- }), object({ success: literal(true) }), {
20017
- kind: "mutation",
20018
- auth: "admin"
20019
- }), method(object({ agentNodeId: string() }), object({
20146
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20020
20147
  success: boolean(),
20021
20148
  removed: boolean()
20022
20149
  }), {
@@ -20048,7 +20175,18 @@ method(object({
20048
20175
  }), object({ success: literal(true) }), {
20049
20176
  kind: "mutation",
20050
20177
  auth: "admin"
20051
- }), method(object({ agentNodeId: string() }), object({
20178
+ }), method(object({
20179
+ agentNodeId: string(),
20180
+ inferenceDevices: record(string(), object({
20181
+ enabled: boolean(),
20182
+ weight: number().positive().optional(),
20183
+ maxSessions: number().int().positive().optional(),
20184
+ steps: record(string(), DeviceStepConfigSchema).optional()
20185
+ }))
20186
+ }), object({ success: literal(true) }), {
20187
+ kind: "mutation",
20188
+ auth: "admin"
20189
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20052
20190
  success: literal(true),
20053
20191
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20054
20192
  effectiveModelId: string().nullable(),
@@ -20064,9 +20202,10 @@ method(object({
20064
20202
  }), object({ success: literal(true) }), {
20065
20203
  kind: "mutation",
20066
20204
  auth: "admin"
20067
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20205
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20068
20206
  deviceId: number(),
20069
20207
  agentNodeId: string(),
20208
+ deviceKey: string(),
20070
20209
  addonId: string(),
20071
20210
  patch: CameraStepOverridePatchSchema.nullable()
20072
20211
  }), object({ success: literal(true) }), {
@@ -20103,14 +20242,13 @@ method(object({
20103
20242
  });
20104
20243
  /**
20105
20244
  * server-management — per-NODE singleton capability for a node's ROOT
20106
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20107
- * agents).
20245
+ * package lifecycle (runtime-updatable node packages).
20108
20246
  *
20109
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20110
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20111
- * version describes the node. Updates install into
20112
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20113
- * starter (probation boot + auto-rollback to N-1).
20247
+ * Every node role runs the SAME root package (`@camstack/server`), which
20248
+ * carries the whole software stack in its npm dep tree, so ONE version
20249
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20250
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20251
+ * no auto-rollback).
20114
20252
  *
20115
20253
  * Providers:
20116
20254
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20218,7 +20356,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20218
20356
  /** Explicit target version; omitted = latest from the registry. */
20219
20357
  version: string().optional() }), ServerUpdateActionResultSchema, {
20220
20358
  kind: "mutation",
20221
- auth: "admin"
20359
+ auth: "admin",
20360
+ timeoutMs: 16 * 6e4
20222
20361
  }), method(_void(), ServerUpdateActionResultSchema, {
20223
20362
  kind: "mutation",
20224
20363
  auth: "admin"
@@ -21262,22 +21401,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21262
21401
  var RestartAddonResultSchema = unknown();
21263
21402
  var InstallPackageResultSchema = unknown();
21264
21403
  var ReloadPackagesResultSchema = unknown();
21265
- /**
21266
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21267
- * server restarts so the admin UI can react to the `restartingAt`
21268
- * timestamp (shows reconnect overlay). The transition from
21269
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21270
- * `system.restart-completed` event after the new process boots.
21271
- *
21272
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21273
- */
21274
- var UpdateFrameworkPackageResultSchema = object({
21275
- packageName: string(),
21276
- fromVersion: string(),
21277
- toVersion: string(),
21278
- /** Ms-epoch the server scheduled its self-restart. */
21279
- restartingAt: number()
21280
- });
21281
21404
  var BulkUpdateItemStatusSchema = _enum([
21282
21405
  "queued",
21283
21406
  "updating",
@@ -21405,13 +21528,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21405
21528
  }), object({ success: literal(true) }), {
21406
21529
  kind: "mutation",
21407
21530
  auth: "admin"
21408
- }), method(object({
21409
- packageName: string().min(1),
21410
- version: string().optional(),
21411
- deferRestart: boolean().optional()
21412
- }), UpdateFrameworkPackageResultSchema, {
21413
- kind: "mutation",
21414
- auth: "admin"
21415
21531
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21416
21532
  kind: "mutation",
21417
21533
  auth: "admin"
@@ -22277,10 +22393,10 @@ var TopologyCategorySchema = object({
22277
22393
  addons: array(TopologyCategoryAddonSchema).readonly()
22278
22394
  });
22279
22395
  /**
22280
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22281
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22282
- * version visibility for the Server management surface. Nullable: offline
22283
- * rows and pre-phase-2 nodes report none.
22396
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22397
+ * root package for every node role) as reported by its `registerNode`
22398
+ * manifest — version visibility for the Server management surface. Nullable:
22399
+ * offline rows and nodes that never reported one.
22284
22400
  */
22285
22401
  var TopologyRootPackageSchema = object({
22286
22402
  name: string(),
@@ -22668,17 +22784,28 @@ var PlatformScoreSchema = object({
22668
22784
  format: _enum([
22669
22785
  "onnx",
22670
22786
  "coreml",
22671
- "openvino"
22787
+ "openvino",
22788
+ "tflite"
22672
22789
  ]),
22673
22790
  score: number(),
22674
22791
  reason: string(),
22675
22792
  available: boolean()
22676
22793
  });
22794
+ var InferenceDeviceDescriptorSchema = object({
22795
+ key: string(),
22796
+ backend: string(),
22797
+ device: string(),
22798
+ format: ModelFormatSchema,
22799
+ runtime: literal("python"),
22800
+ score: number(),
22801
+ available: boolean()
22802
+ });
22677
22803
  var PlatformCapabilitiesSchema = object({
22678
22804
  hardware: HardwareInfoSchema,
22679
22805
  scores: array(PlatformScoreSchema).readonly(),
22680
22806
  bestScore: PlatformScoreSchema,
22681
- pythonPath: string().nullable()
22807
+ pythonPath: string().nullable(),
22808
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22682
22809
  });
22683
22810
  var ModelRequirementSchema = object({
22684
22811
  modelId: string(),
@@ -23557,12 +23684,6 @@ Object.freeze({
23557
23684
  addonId: null,
23558
23685
  access: "delete"
23559
23686
  },
23560
- "addons.updateFrameworkPackage": {
23561
- capName: "addons",
23562
- capScope: "system",
23563
- addonId: null,
23564
- access: "create"
23565
- },
23566
23687
  "addons.updatePackage": {
23567
23688
  capName: "addons",
23568
23689
  capScope: "system",
@@ -26335,12 +26456,6 @@ Object.freeze({
26335
26456
  addonId: null,
26336
26457
  access: "view"
26337
26458
  },
26338
- "pipelineExecutor.reprobeEngine": {
26339
- capName: "pipeline-executor",
26340
- capScope: "system",
26341
- addonId: null,
26342
- access: "create"
26343
- },
26344
26459
  "pipelineExecutor.runAudioTest": {
26345
26460
  capName: "pipeline-executor",
26346
26461
  capScope: "system",
@@ -26491,6 +26606,12 @@ Object.freeze({
26491
26606
  addonId: null,
26492
26607
  access: "view"
26493
26608
  },
26609
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26610
+ capName: "pipeline-orchestrator",
26611
+ capScope: "system",
26612
+ addonId: null,
26613
+ access: "view"
26614
+ },
26494
26615
  "pipelineOrchestrator.getPipelineAssignment": {
26495
26616
  capName: "pipeline-orchestrator",
26496
26617
  capScope: "system",
@@ -26503,6 +26624,12 @@ Object.freeze({
26503
26624
  addonId: null,
26504
26625
  access: "view"
26505
26626
  },
26627
+ "pipelineOrchestrator.getPipelineDevicePin": {
26628
+ capName: "pipeline-orchestrator",
26629
+ capScope: "system",
26630
+ addonId: null,
26631
+ access: "view"
26632
+ },
26506
26633
  "pipelineOrchestrator.listAgentSettings": {
26507
26634
  capName: "pipeline-orchestrator",
26508
26635
  capScope: "system",
@@ -26545,19 +26672,19 @@ Object.freeze({
26545
26672
  addonId: null,
26546
26673
  access: "create"
26547
26674
  },
26548
- "pipelineOrchestrator.setAgentAddonDefaults": {
26675
+ "pipelineOrchestrator.setAgentCapabilities": {
26549
26676
  capName: "pipeline-orchestrator",
26550
26677
  capScope: "system",
26551
26678
  addonId: null,
26552
26679
  access: "create"
26553
26680
  },
26554
- "pipelineOrchestrator.setAgentCapabilities": {
26681
+ "pipelineOrchestrator.setAgentDetectWeight": {
26555
26682
  capName: "pipeline-orchestrator",
26556
26683
  capScope: "system",
26557
26684
  addonId: null,
26558
26685
  access: "create"
26559
26686
  },
26560
- "pipelineOrchestrator.setAgentDetectWeight": {
26687
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26561
26688
  capName: "pipeline-orchestrator",
26562
26689
  capScope: "system",
26563
26690
  addonId: null,
@@ -26599,6 +26726,12 @@ Object.freeze({
26599
26726
  addonId: null,
26600
26727
  access: "create"
26601
26728
  },
26729
+ "pipelineOrchestrator.setPipelineDevicePin": {
26730
+ capName: "pipeline-orchestrator",
26731
+ capScope: "system",
26732
+ addonId: null,
26733
+ access: "create"
26734
+ },
26602
26735
  "pipelineOrchestrator.unassignAudio": {
26603
26736
  capName: "pipeline-orchestrator",
26604
26737
  capScope: "system",
@@ -28151,32 +28284,6 @@ Object.freeze({
28151
28284
  "network-access": "ingress",
28152
28285
  "smtp-provider": "email"
28153
28286
  });
28154
- var frameworkSwapPackageSchema = object({
28155
- name: string(),
28156
- stagedPath: string(),
28157
- backupPath: string(),
28158
- toVersion: string(),
28159
- fromVersion: string().nullable()
28160
- });
28161
- object({
28162
- jobId: string(),
28163
- taskId: string(),
28164
- packages: array(frameworkSwapPackageSchema),
28165
- requestedAtMs: number(),
28166
- schemaVersion: literal(1)
28167
- });
28168
- object({
28169
- jobId: string(),
28170
- taskId: string(),
28171
- backups: array(object({
28172
- name: string(),
28173
- backupPath: string(),
28174
- livePath: string()
28175
- })),
28176
- appliedAtMs: number(),
28177
- bootAttempts: number(),
28178
- schemaVersion: literal(1)
28179
- });
28180
28287
  //#endregion
28181
28288
  //#region node_modules/@apocaliss92/nodewitt/node_modules/zod/v3/helpers/util.js
28182
28289
  var util;
package/dist/addon.mjs CHANGED
@@ -7100,6 +7100,17 @@ var ModelCatalogEntrySchema = object({
7100
7100
  "imagenet",
7101
7101
  "none"
7102
7102
  ]).optional(),
7103
+ /**
7104
+ * The model already applies softmax IN-GRAPH — its raw output is a
7105
+ * probability distribution, not logits. When set, the `softmax`
7106
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7107
+ * probability vector collapses it toward uniform (top-1 score craters far
7108
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7109
+ * the output is raw logits and the postprocessor applies softmax (the normal
7110
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7111
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7112
+ */
7113
+ outputProbabilities: boolean().optional(),
7103
7114
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7104
7115
  /**
7105
7116
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12390,10 +12401,7 @@ var ConfigUISchemaNullableBridge = custom();
12390
12401
  var InferenceCapabilitiesBridge = custom();
12391
12402
  var ModelAvailabilityListBridge = custom();
12392
12403
  var PipelineRunResultBridge = custom();
12393
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12394
- kind: "mutation",
12395
- auth: "admin"
12396
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12404
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12397
12405
  modelId: string(),
12398
12406
  settings: record(string(), unknown()).readonly()
12399
12407
  }))), method(object({ steps: record(string(), object({
@@ -12453,13 +12461,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12453
12461
  * (inputClasses ≠ null) are skipped and served per-track via
12454
12462
  * pipelineRunner.runDetailSubtree (two-plane design).
12455
12463
  */
12456
- plane: _enum(["full", "frame"]).optional()
12464
+ plane: _enum(["full", "frame"]).optional(),
12465
+ /**
12466
+ * Inference-device selector (Phase 2 multi-device). Format
12467
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12468
+ * Omitted ⇒ the runner's default device (current single-engine
12469
+ * behaviour). Selects WHICH device pool of the node runs the call.
12470
+ */
12471
+ deviceKey: string().optional()
12457
12472
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12458
12473
  engine: PipelineEngineChoiceSchema.optional(),
12459
12474
  steps: array(PipelineStepInputSchema).min(1),
12460
12475
  frames: array(FrameInputSchema).min(1).max(255),
12461
12476
  deviceId: number().optional(),
12462
- sessionId: string().optional()
12477
+ sessionId: string().optional(),
12478
+ /**
12479
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12480
+ * the batch to the Python pool's bench preprocess cache
12481
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12482
+ * preprocessed ONCE and every later inference is a pure-inference cache
12483
+ * hit — the sustained-throughput run measures inference, not
12484
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12485
+ * full preprocess every call, correct). Fresh per sustained run;
12486
+ * released via `uncacheFrame`.
12487
+ */
12488
+ frameId: number().int().nonnegative().optional(),
12489
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12490
+ deviceKey: string().optional()
12463
12491
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12464
12492
  data: _instanceof(Uint8Array),
12465
12493
  width: number().int().positive(),
@@ -12491,8 +12519,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12491
12519
  * - `runtime` — main camera-serving engine (no idle TTL).
12492
12520
  * - `warm-override` — benchmark/test override held in the warm
12493
12521
  * cache; auto-disposed after the idle TTL.
12522
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12523
+ * multi-device, keyed by `deviceKey`) resolved
12524
+ * via `resolveDeviceFactory`. Runs alongside the
12525
+ * `runtime` engine on a DIFFERENT accelerator
12526
+ * (NPU / iGPU / Coral) — this is how the
12527
+ * Engines tab shows all pools running at once.
12494
12528
  */
12495
- kind: _enum(["runtime", "warm-override"]),
12529
+ kind: _enum([
12530
+ "runtime",
12531
+ "warm-override",
12532
+ "device-pool"
12533
+ ]),
12496
12534
  /** Native pid of the underlying Python pool (null when no pool). */
12497
12535
  poolPid: number().nullable(),
12498
12536
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12627,7 +12665,21 @@ var NativeCropResultSchema = object({
12627
12665
  /** Packed rgb (24-bit) pixels of the crop. */
12628
12666
  bytes: _instanceof(Uint8Array),
12629
12667
  width: number().int().positive(),
12630
- height: number().int().positive()
12668
+ height: number().int().positive(),
12669
+ /**
12670
+ * Which source served this crop, so a quality-sensitive consumer (the native
12671
+ * `keyFrame`) can reject a degraded fallback:
12672
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
12673
+ * quality path).
12674
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
12675
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
12676
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
12677
+ *
12678
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
12679
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
12680
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
12681
+ */
12682
+ tier: _enum(["native", "ram-fullframe"]).optional()
12631
12683
  });
12632
12684
  /** Parent detection context passed to `runDetailSubtree` — the crop's
12633
12685
  * originating detection, in FRAME-space coordinates. Reuses
@@ -12867,7 +12919,14 @@ var RunnerCameraConfigSchema = object({
12867
12919
  * camera's detect node differs from its source-owner (P2d, gated by the
12868
12920
  * `remoteSourcingNodes` rollout setting).
12869
12921
  */
12870
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12922
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12923
+ /**
12924
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12925
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12926
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12927
+ * this only selects WHICH device pool of that node runs the session.
12928
+ */
12929
+ deviceKey: string().optional()
12871
12930
  });
12872
12931
  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;
12873
12932
  /**
@@ -12888,6 +12947,19 @@ var RunnerLocalLoadSchema = object({
12888
12947
  avgInferenceTimeMs: number(),
12889
12948
  /** Total queue depth across motion + detection queues. */
12890
12949
  queueDepthTotal: number(),
12950
+ /**
12951
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12952
+ * this runner currently has attached cameras on, so the orchestrator's second
12953
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12954
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12955
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12956
+ */
12957
+ devices: array(object({
12958
+ deviceKey: string(),
12959
+ backend: string(),
12960
+ attachedCameras: number(),
12961
+ queueDepthTotal: number()
12962
+ })).default([]),
12891
12963
  /** Hardware capability flags reported by this node. */
12892
12964
  hardware: object({
12893
12965
  hasGpu: boolean(),
@@ -16036,6 +16108,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16036
16108
  return toDeviceSummary(device, this.addonId);
16037
16109
  }
16038
16110
  };
16111
+ 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;
16112
+ new Set(Object.values(DeviceType));
16039
16113
  /**
16040
16114
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16041
16115
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -17609,7 +17683,8 @@ var LinkedDeviceSchema = object({
17609
17683
  deviceId: number(),
17610
17684
  name: string(),
17611
17685
  location: string().nullable(),
17612
- features: array(string())
17686
+ features: array(string()),
17687
+ producesTrackedEvents: boolean().optional()
17613
17688
  });
17614
17689
  var SavedDeviceRowSchema = object({
17615
17690
  /** Numeric id reserved at allocateDeviceId time. */
@@ -19239,6 +19314,7 @@ var TrackSchema = object({
19239
19314
  deviceId: number(),
19240
19315
  className: string(),
19241
19316
  label: string().optional(),
19317
+ producingDeviceName: string().optional(),
19242
19318
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
19243
19319
  source: TrackSourceSchema.optional(),
19244
19320
  firstSeen: number(),
@@ -19376,7 +19452,8 @@ var MediaFileKindEnum = _enum([
19376
19452
  "fullFrameBoxed",
19377
19453
  "faceCrop",
19378
19454
  "plateCrop",
19379
- "keyFrame"
19455
+ "keyFrame",
19456
+ "keyFrameSmall"
19380
19457
  ]);
19381
19458
  var MediaFileSchema = object({
19382
19459
  key: string(),
@@ -19705,13 +19782,11 @@ var PipelineTemplateSchema = object({
19705
19782
  createdAt: string(),
19706
19783
  updatedAt: string()
19707
19784
  });
19708
- var AgentAddonConfigSchema = object({
19709
- enabled: boolean(),
19785
+ var DeviceStepConfigSchema = object({
19710
19786
  modelId: string().optional(),
19711
- settings: record(string(), unknown()).readonly()
19787
+ settings: record(string(), unknown()).optional()
19712
19788
  });
19713
19789
  var AgentPipelineSettingsSchema = object({
19714
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19715
19790
  maxCameras: number().int().nonnegative().nullable().default(null),
19716
19791
  /** Per-node detection weight (relative share for the quota balancer). */
19717
19792
  detectWeight: number().positive().optional(),
@@ -19735,7 +19810,22 @@ var AgentPipelineSettingsSchema = object({
19735
19810
  * it already uses to reach the hub). Set this only when the auto-detected
19736
19811
  * address is wrong (multi-homed host, NAT, custom interface).
19737
19812
  */
19738
- reachableHost: string().optional()
19813
+ reachableHost: string().optional(),
19814
+ /**
19815
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19816
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19817
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19818
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19819
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19820
+ * the default model/settings for every camera landing on that accelerator;
19821
+ * a stepId absent ⇒ the step uses that device's format default.
19822
+ */
19823
+ inferenceDevices: record(string(), object({
19824
+ enabled: boolean(),
19825
+ weight: number().positive().optional(),
19826
+ maxSessions: number().int().positive().optional(),
19827
+ steps: record(string(), DeviceStepConfigSchema).optional()
19828
+ })).optional()
19739
19829
  });
19740
19830
  var CameraPipelineForAgentSchema = object({
19741
19831
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19745,14 +19835,13 @@ var CameraPipelineForAgentSchema = object({
19745
19835
  }).nullable()
19746
19836
  });
19747
19837
  var CameraStepOverridePatchSchema = object({
19748
- enabled: boolean().optional(),
19749
19838
  modelId: string().optional(),
19750
19839
  settings: record(string(), unknown()).readonly().optional()
19751
19840
  });
19752
19841
  var CameraPipelineSettingsSchema = object({
19753
19842
  pinnedAgentNodeId: string().optional(),
19754
19843
  stepToggles: record(string(), boolean()).optional(),
19755
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19844
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19756
19845
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19757
19846
  });
19758
19847
  /**
@@ -19966,6 +20055,44 @@ var CameraStatusSchema = object({
19966
20055
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
19967
20056
  fetchedAt: number()
19968
20057
  });
20058
+ var NodeInferenceDeviceSchema = object({
20059
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20060
+ key: string(),
20061
+ backend: string(),
20062
+ device: string(),
20063
+ format: _enum(MODEL_FORMATS),
20064
+ /** Whether the node's live probe reports the device as usable right now. */
20065
+ available: boolean(),
20066
+ /**
20067
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20068
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20069
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20070
+ * not a balanced target). An explicit stored value always wins; a stored-only
20071
+ * (unavailable) key keeps its stored value.
20072
+ */
20073
+ enabled: boolean(),
20074
+ /** Relative balancer weight for the enabled device (default 1). */
20075
+ weight: number(),
20076
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20077
+ maxSessions: number().nullable(),
20078
+ /** Object-detection model the executor defaults to for this deviceKey. */
20079
+ defaultModelId: string(),
20080
+ /**
20081
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20082
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20083
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20084
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20085
+ * available per format; this is the stored selection that becomes the
20086
+ * default for EVERY camera landing on this accelerator.
20087
+ */
20088
+ steps: record(string(), DeviceStepConfigSchema).optional()
20089
+ });
20090
+ var NodeInferenceDevicesSchema = object({
20091
+ nodeId: string(),
20092
+ /** False when the node's platform-probe was unreachable (no live device set). */
20093
+ reachable: boolean(),
20094
+ devices: array(NodeInferenceDeviceSchema).readonly()
20095
+ });
19969
20096
  method(object({
19970
20097
  deviceId: number(),
19971
20098
  agentNodeId: string()
@@ -19975,7 +20102,13 @@ method(object({
19975
20102
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
19976
20103
  kind: "mutation",
19977
20104
  auth: "admin"
19978
- }), method(_void(), object({ migrated: number() }), {
20105
+ }), method(object({
20106
+ deviceId: number(),
20107
+ deviceKey: string()
20108
+ }), object({ success: literal(true) }), {
20109
+ kind: "mutation",
20110
+ auth: "admin"
20111
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
19979
20112
  kind: "mutation",
19980
20113
  auth: "admin"
19981
20114
  }), 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({
@@ -20009,13 +20142,7 @@ method(object({
20009
20142
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20010
20143
  nodeId: string(),
20011
20144
  settings: AgentPipelineSettingsSchema
20012
- })).readonly()), method(object({
20013
- agentNodeId: string(),
20014
- defaults: record(string(), AgentAddonConfigSchema)
20015
- }), object({ success: literal(true) }), {
20016
- kind: "mutation",
20017
- auth: "admin"
20018
- }), method(object({ agentNodeId: string() }), object({
20145
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20019
20146
  success: boolean(),
20020
20147
  removed: boolean()
20021
20148
  }), {
@@ -20047,7 +20174,18 @@ method(object({
20047
20174
  }), object({ success: literal(true) }), {
20048
20175
  kind: "mutation",
20049
20176
  auth: "admin"
20050
- }), method(object({ agentNodeId: string() }), object({
20177
+ }), method(object({
20178
+ agentNodeId: string(),
20179
+ inferenceDevices: record(string(), object({
20180
+ enabled: boolean(),
20181
+ weight: number().positive().optional(),
20182
+ maxSessions: number().int().positive().optional(),
20183
+ steps: record(string(), DeviceStepConfigSchema).optional()
20184
+ }))
20185
+ }), object({ success: literal(true) }), {
20186
+ kind: "mutation",
20187
+ auth: "admin"
20188
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20051
20189
  success: literal(true),
20052
20190
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20053
20191
  effectiveModelId: string().nullable(),
@@ -20063,9 +20201,10 @@ method(object({
20063
20201
  }), object({ success: literal(true) }), {
20064
20202
  kind: "mutation",
20065
20203
  auth: "admin"
20066
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20204
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20067
20205
  deviceId: number(),
20068
20206
  agentNodeId: string(),
20207
+ deviceKey: string(),
20069
20208
  addonId: string(),
20070
20209
  patch: CameraStepOverridePatchSchema.nullable()
20071
20210
  }), object({ success: literal(true) }), {
@@ -20102,14 +20241,13 @@ method(object({
20102
20241
  });
20103
20242
  /**
20104
20243
  * server-management — per-NODE singleton capability for a node's ROOT
20105
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20106
- * agents).
20244
+ * package lifecycle (runtime-updatable node packages).
20107
20245
  *
20108
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20109
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20110
- * version describes the node. Updates install into
20111
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20112
- * starter (probation boot + auto-rollback to N-1).
20246
+ * Every node role runs the SAME root package (`@camstack/server`), which
20247
+ * carries the whole software stack in its npm dep tree, so ONE version
20248
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20249
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20250
+ * no auto-rollback).
20113
20251
  *
20114
20252
  * Providers:
20115
20253
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20217,7 +20355,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20217
20355
  /** Explicit target version; omitted = latest from the registry. */
20218
20356
  version: string().optional() }), ServerUpdateActionResultSchema, {
20219
20357
  kind: "mutation",
20220
- auth: "admin"
20358
+ auth: "admin",
20359
+ timeoutMs: 16 * 6e4
20221
20360
  }), method(_void(), ServerUpdateActionResultSchema, {
20222
20361
  kind: "mutation",
20223
20362
  auth: "admin"
@@ -21261,22 +21400,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21261
21400
  var RestartAddonResultSchema = unknown();
21262
21401
  var InstallPackageResultSchema = unknown();
21263
21402
  var ReloadPackagesResultSchema = unknown();
21264
- /**
21265
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21266
- * server restarts so the admin UI can react to the `restartingAt`
21267
- * timestamp (shows reconnect overlay). The transition from
21268
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21269
- * `system.restart-completed` event after the new process boots.
21270
- *
21271
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21272
- */
21273
- var UpdateFrameworkPackageResultSchema = object({
21274
- packageName: string(),
21275
- fromVersion: string(),
21276
- toVersion: string(),
21277
- /** Ms-epoch the server scheduled its self-restart. */
21278
- restartingAt: number()
21279
- });
21280
21403
  var BulkUpdateItemStatusSchema = _enum([
21281
21404
  "queued",
21282
21405
  "updating",
@@ -21404,13 +21527,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21404
21527
  }), object({ success: literal(true) }), {
21405
21528
  kind: "mutation",
21406
21529
  auth: "admin"
21407
- }), method(object({
21408
- packageName: string().min(1),
21409
- version: string().optional(),
21410
- deferRestart: boolean().optional()
21411
- }), UpdateFrameworkPackageResultSchema, {
21412
- kind: "mutation",
21413
- auth: "admin"
21414
21530
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21415
21531
  kind: "mutation",
21416
21532
  auth: "admin"
@@ -22276,10 +22392,10 @@ var TopologyCategorySchema = object({
22276
22392
  addons: array(TopologyCategoryAddonSchema).readonly()
22277
22393
  });
22278
22394
  /**
22279
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22280
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22281
- * version visibility for the Server management surface. Nullable: offline
22282
- * rows and pre-phase-2 nodes report none.
22395
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22396
+ * root package for every node role) as reported by its `registerNode`
22397
+ * manifest — version visibility for the Server management surface. Nullable:
22398
+ * offline rows and nodes that never reported one.
22283
22399
  */
22284
22400
  var TopologyRootPackageSchema = object({
22285
22401
  name: string(),
@@ -22667,17 +22783,28 @@ var PlatformScoreSchema = object({
22667
22783
  format: _enum([
22668
22784
  "onnx",
22669
22785
  "coreml",
22670
- "openvino"
22786
+ "openvino",
22787
+ "tflite"
22671
22788
  ]),
22672
22789
  score: number(),
22673
22790
  reason: string(),
22674
22791
  available: boolean()
22675
22792
  });
22793
+ var InferenceDeviceDescriptorSchema = object({
22794
+ key: string(),
22795
+ backend: string(),
22796
+ device: string(),
22797
+ format: ModelFormatSchema,
22798
+ runtime: literal("python"),
22799
+ score: number(),
22800
+ available: boolean()
22801
+ });
22676
22802
  var PlatformCapabilitiesSchema = object({
22677
22803
  hardware: HardwareInfoSchema,
22678
22804
  scores: array(PlatformScoreSchema).readonly(),
22679
22805
  bestScore: PlatformScoreSchema,
22680
- pythonPath: string().nullable()
22806
+ pythonPath: string().nullable(),
22807
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22681
22808
  });
22682
22809
  var ModelRequirementSchema = object({
22683
22810
  modelId: string(),
@@ -23556,12 +23683,6 @@ Object.freeze({
23556
23683
  addonId: null,
23557
23684
  access: "delete"
23558
23685
  },
23559
- "addons.updateFrameworkPackage": {
23560
- capName: "addons",
23561
- capScope: "system",
23562
- addonId: null,
23563
- access: "create"
23564
- },
23565
23686
  "addons.updatePackage": {
23566
23687
  capName: "addons",
23567
23688
  capScope: "system",
@@ -26334,12 +26455,6 @@ Object.freeze({
26334
26455
  addonId: null,
26335
26456
  access: "view"
26336
26457
  },
26337
- "pipelineExecutor.reprobeEngine": {
26338
- capName: "pipeline-executor",
26339
- capScope: "system",
26340
- addonId: null,
26341
- access: "create"
26342
- },
26343
26458
  "pipelineExecutor.runAudioTest": {
26344
26459
  capName: "pipeline-executor",
26345
26460
  capScope: "system",
@@ -26490,6 +26605,12 @@ Object.freeze({
26490
26605
  addonId: null,
26491
26606
  access: "view"
26492
26607
  },
26608
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26609
+ capName: "pipeline-orchestrator",
26610
+ capScope: "system",
26611
+ addonId: null,
26612
+ access: "view"
26613
+ },
26493
26614
  "pipelineOrchestrator.getPipelineAssignment": {
26494
26615
  capName: "pipeline-orchestrator",
26495
26616
  capScope: "system",
@@ -26502,6 +26623,12 @@ Object.freeze({
26502
26623
  addonId: null,
26503
26624
  access: "view"
26504
26625
  },
26626
+ "pipelineOrchestrator.getPipelineDevicePin": {
26627
+ capName: "pipeline-orchestrator",
26628
+ capScope: "system",
26629
+ addonId: null,
26630
+ access: "view"
26631
+ },
26505
26632
  "pipelineOrchestrator.listAgentSettings": {
26506
26633
  capName: "pipeline-orchestrator",
26507
26634
  capScope: "system",
@@ -26544,19 +26671,19 @@ Object.freeze({
26544
26671
  addonId: null,
26545
26672
  access: "create"
26546
26673
  },
26547
- "pipelineOrchestrator.setAgentAddonDefaults": {
26674
+ "pipelineOrchestrator.setAgentCapabilities": {
26548
26675
  capName: "pipeline-orchestrator",
26549
26676
  capScope: "system",
26550
26677
  addonId: null,
26551
26678
  access: "create"
26552
26679
  },
26553
- "pipelineOrchestrator.setAgentCapabilities": {
26680
+ "pipelineOrchestrator.setAgentDetectWeight": {
26554
26681
  capName: "pipeline-orchestrator",
26555
26682
  capScope: "system",
26556
26683
  addonId: null,
26557
26684
  access: "create"
26558
26685
  },
26559
- "pipelineOrchestrator.setAgentDetectWeight": {
26686
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26560
26687
  capName: "pipeline-orchestrator",
26561
26688
  capScope: "system",
26562
26689
  addonId: null,
@@ -26598,6 +26725,12 @@ Object.freeze({
26598
26725
  addonId: null,
26599
26726
  access: "create"
26600
26727
  },
26728
+ "pipelineOrchestrator.setPipelineDevicePin": {
26729
+ capName: "pipeline-orchestrator",
26730
+ capScope: "system",
26731
+ addonId: null,
26732
+ access: "create"
26733
+ },
26601
26734
  "pipelineOrchestrator.unassignAudio": {
26602
26735
  capName: "pipeline-orchestrator",
26603
26736
  capScope: "system",
@@ -28150,32 +28283,6 @@ Object.freeze({
28150
28283
  "network-access": "ingress",
28151
28284
  "smtp-provider": "email"
28152
28285
  });
28153
- var frameworkSwapPackageSchema = object({
28154
- name: string(),
28155
- stagedPath: string(),
28156
- backupPath: string(),
28157
- toVersion: string(),
28158
- fromVersion: string().nullable()
28159
- });
28160
- object({
28161
- jobId: string(),
28162
- taskId: string(),
28163
- packages: array(frameworkSwapPackageSchema),
28164
- requestedAtMs: number(),
28165
- schemaVersion: literal(1)
28166
- });
28167
- object({
28168
- jobId: string(),
28169
- taskId: string(),
28170
- backups: array(object({
28171
- name: string(),
28172
- backupPath: string(),
28173
- livePath: string()
28174
- })),
28175
- appliedAtMs: number(),
28176
- bootAttempts: number(),
28177
- schemaVersion: literal(1)
28178
- });
28179
28286
  //#endregion
28180
28287
  //#region node_modules/@apocaliss92/nodewitt/node_modules/zod/v3/helpers/util.js
28181
28288
  var util;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-ecowitt",
3
- "version": "0.1.27",
3
+ "version": "0.2.1",
4
4
  "description": "Ecowitt weather-station device-provider addon for CamStack — wraps the @apocaliss92/nodewitt local-poll / push client",
5
5
  "keywords": [
6
6
  "camstack",