@camstack/addon-provider-petkit 0.1.14 → 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
@@ -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()`.
@@ -17626,7 +17700,8 @@ var LinkedDeviceSchema = object({
17626
17700
  deviceId: number(),
17627
17701
  name: string(),
17628
17702
  location: string().nullable(),
17629
- features: array(string())
17703
+ features: array(string()),
17704
+ producesTrackedEvents: boolean().optional()
17630
17705
  });
17631
17706
  var SavedDeviceRowSchema = object({
17632
17707
  /** Numeric id reserved at allocateDeviceId time. */
@@ -19256,6 +19331,7 @@ var TrackSchema = object({
19256
19331
  deviceId: number(),
19257
19332
  className: string(),
19258
19333
  label: string().optional(),
19334
+ producingDeviceName: string().optional(),
19259
19335
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
19260
19336
  source: TrackSourceSchema.optional(),
19261
19337
  firstSeen: number(),
@@ -19393,7 +19469,8 @@ var MediaFileKindEnum = _enum([
19393
19469
  "fullFrameBoxed",
19394
19470
  "faceCrop",
19395
19471
  "plateCrop",
19396
- "keyFrame"
19472
+ "keyFrame",
19473
+ "keyFrameSmall"
19397
19474
  ]);
19398
19475
  var MediaFileSchema = object({
19399
19476
  key: string(),
@@ -19722,13 +19799,11 @@ var PipelineTemplateSchema = object({
19722
19799
  createdAt: string(),
19723
19800
  updatedAt: string()
19724
19801
  });
19725
- var AgentAddonConfigSchema = object({
19726
- enabled: boolean(),
19802
+ var DeviceStepConfigSchema = object({
19727
19803
  modelId: string().optional(),
19728
- settings: record(string(), unknown()).readonly()
19804
+ settings: record(string(), unknown()).optional()
19729
19805
  });
19730
19806
  var AgentPipelineSettingsSchema = object({
19731
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19732
19807
  maxCameras: number().int().nonnegative().nullable().default(null),
19733
19808
  /** Per-node detection weight (relative share for the quota balancer). */
19734
19809
  detectWeight: number().positive().optional(),
@@ -19752,7 +19827,22 @@ var AgentPipelineSettingsSchema = object({
19752
19827
  * it already uses to reach the hub). Set this only when the auto-detected
19753
19828
  * address is wrong (multi-homed host, NAT, custom interface).
19754
19829
  */
19755
- reachableHost: string().optional()
19830
+ reachableHost: string().optional(),
19831
+ /**
19832
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19833
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19834
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19835
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19836
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19837
+ * the default model/settings for every camera landing on that accelerator;
19838
+ * a stepId absent ⇒ the step uses that device's format default.
19839
+ */
19840
+ inferenceDevices: record(string(), object({
19841
+ enabled: boolean(),
19842
+ weight: number().positive().optional(),
19843
+ maxSessions: number().int().positive().optional(),
19844
+ steps: record(string(), DeviceStepConfigSchema).optional()
19845
+ })).optional()
19756
19846
  });
19757
19847
  var CameraPipelineForAgentSchema = object({
19758
19848
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19762,14 +19852,13 @@ var CameraPipelineForAgentSchema = object({
19762
19852
  }).nullable()
19763
19853
  });
19764
19854
  var CameraStepOverridePatchSchema = object({
19765
- enabled: boolean().optional(),
19766
19855
  modelId: string().optional(),
19767
19856
  settings: record(string(), unknown()).readonly().optional()
19768
19857
  });
19769
19858
  var CameraPipelineSettingsSchema = object({
19770
19859
  pinnedAgentNodeId: string().optional(),
19771
19860
  stepToggles: record(string(), boolean()).optional(),
19772
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19861
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19773
19862
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19774
19863
  });
19775
19864
  /**
@@ -19983,6 +20072,44 @@ var CameraStatusSchema = object({
19983
20072
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
19984
20073
  fetchedAt: number()
19985
20074
  });
20075
+ var NodeInferenceDeviceSchema = object({
20076
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20077
+ key: string(),
20078
+ backend: string(),
20079
+ device: string(),
20080
+ format: _enum(MODEL_FORMATS),
20081
+ /** Whether the node's live probe reports the device as usable right now. */
20082
+ available: boolean(),
20083
+ /**
20084
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20085
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20086
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20087
+ * not a balanced target). An explicit stored value always wins; a stored-only
20088
+ * (unavailable) key keeps its stored value.
20089
+ */
20090
+ enabled: boolean(),
20091
+ /** Relative balancer weight for the enabled device (default 1). */
20092
+ weight: number(),
20093
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20094
+ maxSessions: number().nullable(),
20095
+ /** Object-detection model the executor defaults to for this deviceKey. */
20096
+ defaultModelId: string(),
20097
+ /**
20098
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20099
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20100
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20101
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20102
+ * available per format; this is the stored selection that becomes the
20103
+ * default for EVERY camera landing on this accelerator.
20104
+ */
20105
+ steps: record(string(), DeviceStepConfigSchema).optional()
20106
+ });
20107
+ var NodeInferenceDevicesSchema = object({
20108
+ nodeId: string(),
20109
+ /** False when the node's platform-probe was unreachable (no live device set). */
20110
+ reachable: boolean(),
20111
+ devices: array(NodeInferenceDeviceSchema).readonly()
20112
+ });
19986
20113
  method(object({
19987
20114
  deviceId: number(),
19988
20115
  agentNodeId: string()
@@ -19992,7 +20119,13 @@ method(object({
19992
20119
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
19993
20120
  kind: "mutation",
19994
20121
  auth: "admin"
19995
- }), method(_void(), object({ migrated: number() }), {
20122
+ }), method(object({
20123
+ deviceId: number(),
20124
+ deviceKey: string()
20125
+ }), object({ success: literal(true) }), {
20126
+ kind: "mutation",
20127
+ auth: "admin"
20128
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
19996
20129
  kind: "mutation",
19997
20130
  auth: "admin"
19998
20131
  }), 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({
@@ -20026,13 +20159,7 @@ method(object({
20026
20159
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20027
20160
  nodeId: string(),
20028
20161
  settings: AgentPipelineSettingsSchema
20029
- })).readonly()), method(object({
20030
- agentNodeId: string(),
20031
- defaults: record(string(), AgentAddonConfigSchema)
20032
- }), object({ success: literal(true) }), {
20033
- kind: "mutation",
20034
- auth: "admin"
20035
- }), method(object({ agentNodeId: string() }), object({
20162
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20036
20163
  success: boolean(),
20037
20164
  removed: boolean()
20038
20165
  }), {
@@ -20064,7 +20191,18 @@ method(object({
20064
20191
  }), object({ success: literal(true) }), {
20065
20192
  kind: "mutation",
20066
20193
  auth: "admin"
20067
- }), method(object({ agentNodeId: string() }), object({
20194
+ }), method(object({
20195
+ agentNodeId: string(),
20196
+ inferenceDevices: record(string(), object({
20197
+ enabled: boolean(),
20198
+ weight: number().positive().optional(),
20199
+ maxSessions: number().int().positive().optional(),
20200
+ steps: record(string(), DeviceStepConfigSchema).optional()
20201
+ }))
20202
+ }), object({ success: literal(true) }), {
20203
+ kind: "mutation",
20204
+ auth: "admin"
20205
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20068
20206
  success: literal(true),
20069
20207
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20070
20208
  effectiveModelId: string().nullable(),
@@ -20080,9 +20218,10 @@ method(object({
20080
20218
  }), object({ success: literal(true) }), {
20081
20219
  kind: "mutation",
20082
20220
  auth: "admin"
20083
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20221
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20084
20222
  deviceId: number(),
20085
20223
  agentNodeId: string(),
20224
+ deviceKey: string(),
20086
20225
  addonId: string(),
20087
20226
  patch: CameraStepOverridePatchSchema.nullable()
20088
20227
  }), object({ success: literal(true) }), {
@@ -20119,14 +20258,13 @@ method(object({
20119
20258
  });
20120
20259
  /**
20121
20260
  * server-management — per-NODE singleton capability for a node's ROOT
20122
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20123
- * agents).
20261
+ * package lifecycle (runtime-updatable node packages).
20124
20262
  *
20125
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20126
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20127
- * version describes the node. Updates install into
20128
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20129
- * starter (probation boot + auto-rollback to N-1).
20263
+ * Every node role runs the SAME root package (`@camstack/server`), which
20264
+ * carries the whole software stack in its npm dep tree, so ONE version
20265
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20266
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20267
+ * no auto-rollback).
20130
20268
  *
20131
20269
  * Providers:
20132
20270
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20234,7 +20372,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20234
20372
  /** Explicit target version; omitted = latest from the registry. */
20235
20373
  version: string().optional() }), ServerUpdateActionResultSchema, {
20236
20374
  kind: "mutation",
20237
- auth: "admin"
20375
+ auth: "admin",
20376
+ timeoutMs: 16 * 6e4
20238
20377
  }), method(_void(), ServerUpdateActionResultSchema, {
20239
20378
  kind: "mutation",
20240
20379
  auth: "admin"
@@ -21278,22 +21417,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21278
21417
  var RestartAddonResultSchema = unknown();
21279
21418
  var InstallPackageResultSchema = unknown();
21280
21419
  var ReloadPackagesResultSchema = unknown();
21281
- /**
21282
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21283
- * server restarts so the admin UI can react to the `restartingAt`
21284
- * timestamp (shows reconnect overlay). The transition from
21285
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21286
- * `system.restart-completed` event after the new process boots.
21287
- *
21288
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21289
- */
21290
- var UpdateFrameworkPackageResultSchema = object({
21291
- packageName: string(),
21292
- fromVersion: string(),
21293
- toVersion: string(),
21294
- /** Ms-epoch the server scheduled its self-restart. */
21295
- restartingAt: number()
21296
- });
21297
21420
  var BulkUpdateItemStatusSchema = _enum([
21298
21421
  "queued",
21299
21422
  "updating",
@@ -21421,13 +21544,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21421
21544
  }), object({ success: literal(true) }), {
21422
21545
  kind: "mutation",
21423
21546
  auth: "admin"
21424
- }), method(object({
21425
- packageName: string().min(1),
21426
- version: string().optional(),
21427
- deferRestart: boolean().optional()
21428
- }), UpdateFrameworkPackageResultSchema, {
21429
- kind: "mutation",
21430
- auth: "admin"
21431
21547
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21432
21548
  kind: "mutation",
21433
21549
  auth: "admin"
@@ -22293,10 +22409,10 @@ var TopologyCategorySchema = object({
22293
22409
  addons: array(TopologyCategoryAddonSchema).readonly()
22294
22410
  });
22295
22411
  /**
22296
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22297
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22298
- * version visibility for the Server management surface. Nullable: offline
22299
- * rows and pre-phase-2 nodes report none.
22412
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22413
+ * root package for every node role) as reported by its `registerNode`
22414
+ * manifest — version visibility for the Server management surface. Nullable:
22415
+ * offline rows and nodes that never reported one.
22300
22416
  */
22301
22417
  var TopologyRootPackageSchema = object({
22302
22418
  name: string(),
@@ -22684,17 +22800,28 @@ var PlatformScoreSchema = object({
22684
22800
  format: _enum([
22685
22801
  "onnx",
22686
22802
  "coreml",
22687
- "openvino"
22803
+ "openvino",
22804
+ "tflite"
22688
22805
  ]),
22689
22806
  score: number(),
22690
22807
  reason: string(),
22691
22808
  available: boolean()
22692
22809
  });
22810
+ var InferenceDeviceDescriptorSchema = object({
22811
+ key: string(),
22812
+ backend: string(),
22813
+ device: string(),
22814
+ format: ModelFormatSchema,
22815
+ runtime: literal("python"),
22816
+ score: number(),
22817
+ available: boolean()
22818
+ });
22693
22819
  var PlatformCapabilitiesSchema = object({
22694
22820
  hardware: HardwareInfoSchema,
22695
22821
  scores: array(PlatformScoreSchema).readonly(),
22696
22822
  bestScore: PlatformScoreSchema,
22697
- pythonPath: string().nullable()
22823
+ pythonPath: string().nullable(),
22824
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22698
22825
  });
22699
22826
  var ModelRequirementSchema = object({
22700
22827
  modelId: string(),
@@ -23573,12 +23700,6 @@ Object.freeze({
23573
23700
  addonId: null,
23574
23701
  access: "delete"
23575
23702
  },
23576
- "addons.updateFrameworkPackage": {
23577
- capName: "addons",
23578
- capScope: "system",
23579
- addonId: null,
23580
- access: "create"
23581
- },
23582
23703
  "addons.updatePackage": {
23583
23704
  capName: "addons",
23584
23705
  capScope: "system",
@@ -26351,12 +26472,6 @@ Object.freeze({
26351
26472
  addonId: null,
26352
26473
  access: "view"
26353
26474
  },
26354
- "pipelineExecutor.reprobeEngine": {
26355
- capName: "pipeline-executor",
26356
- capScope: "system",
26357
- addonId: null,
26358
- access: "create"
26359
- },
26360
26475
  "pipelineExecutor.runAudioTest": {
26361
26476
  capName: "pipeline-executor",
26362
26477
  capScope: "system",
@@ -26507,6 +26622,12 @@ Object.freeze({
26507
26622
  addonId: null,
26508
26623
  access: "view"
26509
26624
  },
26625
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26626
+ capName: "pipeline-orchestrator",
26627
+ capScope: "system",
26628
+ addonId: null,
26629
+ access: "view"
26630
+ },
26510
26631
  "pipelineOrchestrator.getPipelineAssignment": {
26511
26632
  capName: "pipeline-orchestrator",
26512
26633
  capScope: "system",
@@ -26519,6 +26640,12 @@ Object.freeze({
26519
26640
  addonId: null,
26520
26641
  access: "view"
26521
26642
  },
26643
+ "pipelineOrchestrator.getPipelineDevicePin": {
26644
+ capName: "pipeline-orchestrator",
26645
+ capScope: "system",
26646
+ addonId: null,
26647
+ access: "view"
26648
+ },
26522
26649
  "pipelineOrchestrator.listAgentSettings": {
26523
26650
  capName: "pipeline-orchestrator",
26524
26651
  capScope: "system",
@@ -26561,19 +26688,19 @@ Object.freeze({
26561
26688
  addonId: null,
26562
26689
  access: "create"
26563
26690
  },
26564
- "pipelineOrchestrator.setAgentAddonDefaults": {
26691
+ "pipelineOrchestrator.setAgentCapabilities": {
26565
26692
  capName: "pipeline-orchestrator",
26566
26693
  capScope: "system",
26567
26694
  addonId: null,
26568
26695
  access: "create"
26569
26696
  },
26570
- "pipelineOrchestrator.setAgentCapabilities": {
26697
+ "pipelineOrchestrator.setAgentDetectWeight": {
26571
26698
  capName: "pipeline-orchestrator",
26572
26699
  capScope: "system",
26573
26700
  addonId: null,
26574
26701
  access: "create"
26575
26702
  },
26576
- "pipelineOrchestrator.setAgentDetectWeight": {
26703
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26577
26704
  capName: "pipeline-orchestrator",
26578
26705
  capScope: "system",
26579
26706
  addonId: null,
@@ -26615,6 +26742,12 @@ Object.freeze({
26615
26742
  addonId: null,
26616
26743
  access: "create"
26617
26744
  },
26745
+ "pipelineOrchestrator.setPipelineDevicePin": {
26746
+ capName: "pipeline-orchestrator",
26747
+ capScope: "system",
26748
+ addonId: null,
26749
+ access: "create"
26750
+ },
26618
26751
  "pipelineOrchestrator.unassignAudio": {
26619
26752
  capName: "pipeline-orchestrator",
26620
26753
  capScope: "system",
@@ -28167,32 +28300,6 @@ Object.freeze({
28167
28300
  "network-access": "ingress",
28168
28301
  "smtp-provider": "email"
28169
28302
  });
28170
- var frameworkSwapPackageSchema = object({
28171
- name: string(),
28172
- stagedPath: string(),
28173
- backupPath: string(),
28174
- toVersion: string(),
28175
- fromVersion: string().nullable()
28176
- });
28177
- object({
28178
- jobId: string(),
28179
- taskId: string(),
28180
- packages: array(frameworkSwapPackageSchema),
28181
- requestedAtMs: number(),
28182
- schemaVersion: literal(1)
28183
- });
28184
- object({
28185
- jobId: string(),
28186
- taskId: string(),
28187
- backups: array(object({
28188
- name: string(),
28189
- backupPath: string(),
28190
- livePath: string()
28191
- })),
28192
- appliedAtMs: number(),
28193
- bootAttempts: number(),
28194
- schemaVersion: literal(1)
28195
- });
28196
28303
  //#endregion
28197
28304
  //#region ../../node_modules/@apocaliss92/nodepetkit/dist/index.js
28198
28305
  var PetkitError = class extends Error {
package/dist/addon.mjs CHANGED
@@ -7099,6 +7099,17 @@ var ModelCatalogEntrySchema = object({
7099
7099
  "imagenet",
7100
7100
  "none"
7101
7101
  ]).optional(),
7102
+ /**
7103
+ * The model already applies softmax IN-GRAPH — its raw output is a
7104
+ * probability distribution, not logits. When set, the `softmax`
7105
+ * postprocessor must NOT re-apply softmax: re-softmaxing an already-normalised
7106
+ * probability vector collapses it toward uniform (top-1 score craters far
7107
+ * below its true value, making every confidence gate meaningless). Absent ⇒
7108
+ * the output is raw logits and the postprocessor applies softmax (the normal
7109
+ * case). Set on the Google AIY Birds `bird-classifier` (softmax baked into the
7110
+ * TF graph). Threaded to the Python pool via `PoolModelConfig.outputProbabilities`.
7111
+ */
7112
+ outputProbabilities: boolean().optional(),
7102
7113
  preprocessMode: _enum(["letterbox", "resize"]).optional(),
7103
7114
  /**
7104
7115
  * Per-MODEL postprocessor override. Absent ⇒ the step's own
@@ -12389,10 +12400,7 @@ var ConfigUISchemaNullableBridge = custom();
12389
12400
  var InferenceCapabilitiesBridge = custom();
12390
12401
  var ModelAvailabilityListBridge = custom();
12391
12402
  var PipelineRunResultBridge = custom();
12392
- method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(_void(), PipelineEngineChoiceSchema, {
12393
- kind: "mutation",
12394
- auth: "admin"
12395
- }), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12403
+ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngineChoiceSchema), method(PipelineEngineChoiceSchema, array(PipelineDefaultStepSchema)), method(object({ nodeId: string() }), EngineProvisioningSchema), method(_void(), record(string(), object({
12396
12404
  modelId: string(),
12397
12405
  settings: record(string(), unknown()).readonly()
12398
12406
  }))), method(object({ steps: record(string(), object({
@@ -12452,13 +12460,33 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12452
12460
  * (inputClasses ≠ null) are skipped and served per-track via
12453
12461
  * pipelineRunner.runDetailSubtree (two-plane design).
12454
12462
  */
12455
- plane: _enum(["full", "frame"]).optional()
12463
+ plane: _enum(["full", "frame"]).optional(),
12464
+ /**
12465
+ * Inference-device selector (Phase 2 multi-device). Format
12466
+ * `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`).
12467
+ * Omitted ⇒ the runner's default device (current single-engine
12468
+ * behaviour). Selects WHICH device pool of the node runs the call.
12469
+ */
12470
+ deviceKey: string().optional()
12456
12471
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
12457
12472
  engine: PipelineEngineChoiceSchema.optional(),
12458
12473
  steps: array(PipelineStepInputSchema).min(1),
12459
12474
  frames: array(FrameInputSchema).min(1).max(255),
12460
12475
  deviceId: number().optional(),
12461
- sessionId: string().optional()
12476
+ sessionId: string().optional(),
12477
+ /**
12478
+ * Pure-inference benchmark hint. A NONZERO uint32 pins every frame in
12479
+ * the batch to the Python pool's bench preprocess cache
12480
+ * (`_bench_frame_id`) so a REPEATED benchmark frame is decoded +
12481
+ * preprocessed ONCE and every later inference is a pure-inference cache
12482
+ * hit — the sustained-throughput run measures inference, not
12483
+ * decode+preprocess+infer. Omitted/0 for live frames (all different →
12484
+ * full preprocess every call, correct). Fresh per sustained run;
12485
+ * released via `uncacheFrame`.
12486
+ */
12487
+ frameId: number().int().nonnegative().optional(),
12488
+ /** Inference-device selector (Phase 2 multi-device); see runPipeline. */
12489
+ deviceKey: string().optional()
12462
12490
  }), object({ results: array(PipelineRunResultBridge).readonly() }), { kind: "mutation" }), method(object({
12463
12491
  data: _instanceof(Uint8Array),
12464
12492
  width: number().int().positive(),
@@ -12490,8 +12518,18 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
12490
12518
  * - `runtime` — main camera-serving engine (no idle TTL).
12491
12519
  * - `warm-override` — benchmark/test override held in the warm
12492
12520
  * cache; auto-disposed after the idle TTL.
12521
+ * - `device-pool` — a concurrent per-device pool (Phase 2
12522
+ * multi-device, keyed by `deviceKey`) resolved
12523
+ * via `resolveDeviceFactory`. Runs alongside the
12524
+ * `runtime` engine on a DIFFERENT accelerator
12525
+ * (NPU / iGPU / Coral) — this is how the
12526
+ * Engines tab shows all pools running at once.
12493
12527
  */
12494
- kind: _enum(["runtime", "warm-override"]),
12528
+ kind: _enum([
12529
+ "runtime",
12530
+ "warm-override",
12531
+ "device-pool"
12532
+ ]),
12495
12533
  /** Native pid of the underlying Python pool (null when no pool). */
12496
12534
  poolPid: number().nullable(),
12497
12535
  /** ms since this factory was last used (null when not warm-tracked). */
@@ -12626,7 +12664,21 @@ var NativeCropResultSchema = object({
12626
12664
  /** Packed rgb (24-bit) pixels of the crop. */
12627
12665
  bytes: _instanceof(Uint8Array),
12628
12666
  width: number().int().positive(),
12629
- height: number().int().positive()
12667
+ height: number().int().positive(),
12668
+ /**
12669
+ * Which source served this crop, so a quality-sensitive consumer (the native
12670
+ * `keyFrame`) can reject a degraded fallback:
12671
+ * - `native` — cut from the decode worker's retained NATIVE surface (the
12672
+ * quality path).
12673
+ * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
12674
+ * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
12675
+ * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
12676
+ *
12677
+ * OPTIONAL: a pre-tier runner (version skew) omits it — an ABSENT `tier` MUST be
12678
+ * treated as `native` (accepted) by every consumer so mixed-version clusters
12679
+ * keep the pre-tier behaviour. An ROI miss returns `null` (no tier at all).
12680
+ */
12681
+ tier: _enum(["native", "ram-fullframe"]).optional()
12630
12682
  });
12631
12683
  /** Parent detection context passed to `runDetailSubtree` — the crop's
12632
12684
  * originating detection, in FRAME-space coordinates. Reuses
@@ -12866,7 +12918,14 @@ var RunnerCameraConfigSchema = object({
12866
12918
  * camera's detect node differs from its source-owner (P2d, gated by the
12867
12919
  * `remoteSourcingNodes` rollout setting).
12868
12920
  */
12869
- frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
12921
+ frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" }),
12922
+ /**
12923
+ * Inference-device selector for this camera's sessions (Phase 2 multi-device).
12924
+ * Format `<backend>:<device>` (e.g. `openvino:gpu`, `edgetpu:usb`, `cpu`);
12925
+ * omitted ⇒ the runner's default device. The engine itself stays node-local —
12926
+ * this only selects WHICH device pool of that node runs the session.
12927
+ */
12928
+ deviceKey: string().optional()
12870
12929
  });
12871
12930
  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;
12872
12931
  /**
@@ -12887,6 +12946,19 @@ var RunnerLocalLoadSchema = object({
12887
12946
  avgInferenceTimeMs: number(),
12888
12947
  /** Total queue depth across motion + detection queues. */
12889
12948
  queueDepthTotal: number(),
12949
+ /**
12950
+ * Per-inference-device live load (multi-device C4). One entry per deviceKey
12951
+ * this runner currently has attached cameras on, so the orchestrator's second
12952
+ * `balance()` pass (over a node's devices) weights on real per-pool session
12953
+ * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
12954
+ * per device is 0 until the pool backlog gets a public accessor (follow-up).
12955
+ */
12956
+ devices: array(object({
12957
+ deviceKey: string(),
12958
+ backend: string(),
12959
+ attachedCameras: number(),
12960
+ queueDepthTotal: number()
12961
+ })).default([]),
12890
12962
  /** Hardware capability flags reported by this node. */
12891
12963
  hardware: object({
12892
12964
  hasGpu: boolean(),
@@ -16035,6 +16107,8 @@ var BaseDeviceProvider = class extends BaseAddon {
16035
16107
  return toDeviceSummary(device, this.addonId);
16036
16108
  }
16037
16109
  };
16110
+ 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;
16111
+ new Set(Object.values(DeviceType));
16038
16112
  /**
16039
16113
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
16040
16114
  * surface that admin-ui consumes through `useAddonPagesListPages()`.
@@ -17625,7 +17699,8 @@ var LinkedDeviceSchema = object({
17625
17699
  deviceId: number(),
17626
17700
  name: string(),
17627
17701
  location: string().nullable(),
17628
- features: array(string())
17702
+ features: array(string()),
17703
+ producesTrackedEvents: boolean().optional()
17629
17704
  });
17630
17705
  var SavedDeviceRowSchema = object({
17631
17706
  /** Numeric id reserved at allocateDeviceId time. */
@@ -19255,6 +19330,7 @@ var TrackSchema = object({
19255
19330
  deviceId: number(),
19256
19331
  className: string(),
19257
19332
  label: string().optional(),
19333
+ producingDeviceName: string().optional(),
19258
19334
  /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
19259
19335
  source: TrackSourceSchema.optional(),
19260
19336
  firstSeen: number(),
@@ -19392,7 +19468,8 @@ var MediaFileKindEnum = _enum([
19392
19468
  "fullFrameBoxed",
19393
19469
  "faceCrop",
19394
19470
  "plateCrop",
19395
- "keyFrame"
19471
+ "keyFrame",
19472
+ "keyFrameSmall"
19396
19473
  ]);
19397
19474
  var MediaFileSchema = object({
19398
19475
  key: string(),
@@ -19721,13 +19798,11 @@ var PipelineTemplateSchema = object({
19721
19798
  createdAt: string(),
19722
19799
  updatedAt: string()
19723
19800
  });
19724
- var AgentAddonConfigSchema = object({
19725
- enabled: boolean(),
19801
+ var DeviceStepConfigSchema = object({
19726
19802
  modelId: string().optional(),
19727
- settings: record(string(), unknown()).readonly()
19803
+ settings: record(string(), unknown()).optional()
19728
19804
  });
19729
19805
  var AgentPipelineSettingsSchema = object({
19730
- addonDefaults: record(string(), AgentAddonConfigSchema).readonly(),
19731
19806
  maxCameras: number().int().nonnegative().nullable().default(null),
19732
19807
  /** Per-node detection weight (relative share for the quota balancer). */
19733
19808
  detectWeight: number().positive().optional(),
@@ -19751,7 +19826,22 @@ var AgentPipelineSettingsSchema = object({
19751
19826
  * it already uses to reach the hub). Set this only when the auto-detected
19752
19827
  * address is wrong (multi-homed host, NAT, custom interface).
19753
19828
  */
19754
- reachableHost: string().optional()
19829
+ reachableHost: string().optional(),
19830
+ /**
19831
+ * Multi-device inference opt-in (Phase 4). Per-node map deviceKey → {enabled,
19832
+ * weight, steps}. Absent / all-disabled ⇒ the node's single default
19833
+ * accelerator (safe default); two+ enabled ⇒ the dispatcher balances
19834
+ * detection sessions across them so they run CONCURRENTLY. `steps` is the
19835
+ * per-(node,device) BASE provisioning (`stepId → {modelId?, settings?}`) —
19836
+ * the default model/settings for every camera landing on that accelerator;
19837
+ * a stepId absent ⇒ the step uses that device's format default.
19838
+ */
19839
+ inferenceDevices: record(string(), object({
19840
+ enabled: boolean(),
19841
+ weight: number().positive().optional(),
19842
+ maxSessions: number().int().positive().optional(),
19843
+ steps: record(string(), DeviceStepConfigSchema).optional()
19844
+ })).optional()
19755
19845
  });
19756
19846
  var CameraPipelineForAgentSchema = object({
19757
19847
  steps: array(PipelineStepInputSchema).readonly(),
@@ -19761,14 +19851,13 @@ var CameraPipelineForAgentSchema = object({
19761
19851
  }).nullable()
19762
19852
  });
19763
19853
  var CameraStepOverridePatchSchema = object({
19764
- enabled: boolean().optional(),
19765
19854
  modelId: string().optional(),
19766
19855
  settings: record(string(), unknown()).readonly().optional()
19767
19856
  });
19768
19857
  var CameraPipelineSettingsSchema = object({
19769
19858
  pinnedAgentNodeId: string().optional(),
19770
19859
  stepToggles: record(string(), boolean()).optional(),
19771
- stepOverridesByAgent: record(string(), record(string(), CameraStepOverridePatchSchema)).optional(),
19860
+ stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
19772
19861
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
19773
19862
  });
19774
19863
  /**
@@ -19982,6 +20071,44 @@ var CameraStatusSchema = object({
19982
20071
  /** Unix timestamp (ms) when this snapshot was composed server-side. */
19983
20072
  fetchedAt: number()
19984
20073
  });
20074
+ var NodeInferenceDeviceSchema = object({
20075
+ /** Stable per-node device key, e.g. `openvino:npu`, `edgetpu:usb`, `cpu`. */
20076
+ key: string(),
20077
+ backend: string(),
20078
+ device: string(),
20079
+ format: _enum(MODEL_FORMATS),
20080
+ /** Whether the node's live probe reports the device as usable right now. */
20081
+ available: boolean(),
20082
+ /**
20083
+ * Whether this device participates in dispatch. AUTO default (spec C2):
20084
+ * accelerators are opt-OUT (a discovered NPU/iGPU/Coral/ANE with no stored
20085
+ * entry is `true`); CPU is opt-IN (`false` by default — the fallback pool,
20086
+ * not a balanced target). An explicit stored value always wins; a stored-only
20087
+ * (unavailable) key keeps its stored value.
20088
+ */
20089
+ enabled: boolean(),
20090
+ /** Relative balancer weight for the enabled device (default 1). */
20091
+ weight: number(),
20092
+ /** Per-device concurrent-session cap; null = unlimited (multi-device C4). */
20093
+ maxSessions: number().nullable(),
20094
+ /** Object-detection model the executor defaults to for this deviceKey. */
20095
+ defaultModelId: string(),
20096
+ /**
20097
+ * Per-(node,device) BASE provisioning (C7.2/C7.4) — the RAW stored
20098
+ * `stepId → {modelId?, settings?}` map from `inferenceDevices[key].steps`.
20099
+ * Absent/empty ⇒ no base (every step uses its device format default). The
20100
+ * UI cross-references `pipelineExecutor.getSchema` for the models actually
20101
+ * available per format; this is the stored selection that becomes the
20102
+ * default for EVERY camera landing on this accelerator.
20103
+ */
20104
+ steps: record(string(), DeviceStepConfigSchema).optional()
20105
+ });
20106
+ var NodeInferenceDevicesSchema = object({
20107
+ nodeId: string(),
20108
+ /** False when the node's platform-probe was unreachable (no live device set). */
20109
+ reachable: boolean(),
20110
+ devices: array(NodeInferenceDeviceSchema).readonly()
20111
+ });
19985
20112
  method(object({
19986
20113
  deviceId: number(),
19987
20114
  agentNodeId: string()
@@ -19991,7 +20118,13 @@ method(object({
19991
20118
  }), method(object({ deviceId: number() }), object({ success: literal(true) }), {
19992
20119
  kind: "mutation",
19993
20120
  auth: "admin"
19994
- }), method(_void(), object({ migrated: number() }), {
20121
+ }), method(object({
20122
+ deviceId: number(),
20123
+ deviceKey: string()
20124
+ }), object({ success: literal(true) }), {
20125
+ kind: "mutation",
20126
+ auth: "admin"
20127
+ }), method(object({ deviceId: number() }), object({ deviceKey: string().nullable() })), method(_void(), object({ migrated: number() }), {
19995
20128
  kind: "mutation",
19996
20129
  auth: "admin"
19997
20130
  }), 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({
@@ -20025,13 +20158,7 @@ method(object({
20025
20158
  }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
20026
20159
  nodeId: string(),
20027
20160
  settings: AgentPipelineSettingsSchema
20028
- })).readonly()), method(object({
20029
- agentNodeId: string(),
20030
- defaults: record(string(), AgentAddonConfigSchema)
20031
- }), object({ success: literal(true) }), {
20032
- kind: "mutation",
20033
- auth: "admin"
20034
- }), method(object({ agentNodeId: string() }), object({
20161
+ })).readonly()), method(object({ agentNodeId: string() }), object({
20035
20162
  success: boolean(),
20036
20163
  removed: boolean()
20037
20164
  }), {
@@ -20063,7 +20190,18 @@ method(object({
20063
20190
  }), object({ success: literal(true) }), {
20064
20191
  kind: "mutation",
20065
20192
  auth: "admin"
20066
- }), method(object({ agentNodeId: string() }), object({
20193
+ }), method(object({
20194
+ agentNodeId: string(),
20195
+ inferenceDevices: record(string(), object({
20196
+ enabled: boolean(),
20197
+ weight: number().positive().optional(),
20198
+ maxSessions: number().int().positive().optional(),
20199
+ steps: record(string(), DeviceStepConfigSchema).optional()
20200
+ }))
20201
+ }), object({ success: literal(true) }), {
20202
+ kind: "mutation",
20203
+ auth: "admin"
20204
+ }), method(object({ nodeId: string() }), NodeInferenceDevicesSchema), method(object({ agentNodeId: string() }), object({
20067
20205
  success: literal(true),
20068
20206
  /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
20069
20207
  effectiveModelId: string().nullable(),
@@ -20079,9 +20217,10 @@ method(object({
20079
20217
  }), object({ success: literal(true) }), {
20080
20218
  kind: "mutation",
20081
20219
  auth: "admin"
20082
- }), method(object({ deviceId: number() }), record(string(), record(string(), CameraStepOverridePatchSchema)).nullable()), method(object({
20220
+ }), method(object({ deviceId: number() }), record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).nullable()), method(object({
20083
20221
  deviceId: number(),
20084
20222
  agentNodeId: string(),
20223
+ deviceKey: string(),
20085
20224
  addonId: string(),
20086
20225
  patch: CameraStepOverridePatchSchema.nullable()
20087
20226
  }), object({ success: literal(true) }), {
@@ -20118,14 +20257,13 @@ method(object({
20118
20257
  });
20119
20258
  /**
20120
20259
  * server-management — per-NODE singleton capability for a node's ROOT
20121
- * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
20122
- * agents).
20260
+ * package lifecycle (runtime-updatable node packages).
20123
20261
  *
20124
- * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
20125
- * on agents) carries the whole software stack in its npm dep tree, so ONE
20126
- * version describes the node. Updates install into
20127
- * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
20128
- * starter (probation boot + auto-rollback to N-1).
20262
+ * Every node role runs the SAME root package (`@camstack/server`), which
20263
+ * carries the whole software stack in its npm dep tree, so ONE version
20264
+ * describes the node. Updates stage into `<dataDir>/server-root/` and apply
20265
+ * on restart via the baked starter (single-copy in-place swap — no probation,
20266
+ * no auto-rollback).
20129
20267
  *
20130
20268
  * Providers:
20131
20269
  * - HUB: `ServerUpdateService` behind the `server-provided` mount
@@ -20233,7 +20371,8 @@ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), S
20233
20371
  /** Explicit target version; omitted = latest from the registry. */
20234
20372
  version: string().optional() }), ServerUpdateActionResultSchema, {
20235
20373
  kind: "mutation",
20236
- auth: "admin"
20374
+ auth: "admin",
20375
+ timeoutMs: 16 * 6e4
20237
20376
  }), method(_void(), ServerUpdateActionResultSchema, {
20238
20377
  kind: "mutation",
20239
20378
  auth: "admin"
@@ -21277,22 +21416,6 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
21277
21416
  var RestartAddonResultSchema = unknown();
21278
21417
  var InstallPackageResultSchema = unknown();
21279
21418
  var ReloadPackagesResultSchema = unknown();
21280
- /**
21281
- * Result of `updateFrameworkPackage`. The cap method returns BEFORE the
21282
- * server restarts so the admin UI can react to the `restartingAt`
21283
- * timestamp (shows reconnect overlay). The transition from
21284
- * `fromVersion` to `toVersion` will be confirmed by a subsequent
21285
- * `system.restart-completed` event after the new process boots.
21286
- *
21287
- * Spec: docs/superpowers/specs/2026-05-14-framework-live-update-design.md
21288
- */
21289
- var UpdateFrameworkPackageResultSchema = object({
21290
- packageName: string(),
21291
- fromVersion: string(),
21292
- toVersion: string(),
21293
- /** Ms-epoch the server scheduled its self-restart. */
21294
- restartingAt: number()
21295
- });
21296
21419
  var BulkUpdateItemStatusSchema = _enum([
21297
21420
  "queued",
21298
21421
  "updating",
@@ -21420,13 +21543,6 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21420
21543
  }), object({ success: literal(true) }), {
21421
21544
  kind: "mutation",
21422
21545
  auth: "admin"
21423
- }), method(object({
21424
- packageName: string().min(1),
21425
- version: string().optional(),
21426
- deferRestart: boolean().optional()
21427
- }), UpdateFrameworkPackageResultSchema, {
21428
- kind: "mutation",
21429
- auth: "admin"
21430
21546
  }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
21431
21547
  kind: "mutation",
21432
21548
  auth: "admin"
@@ -22292,10 +22408,10 @@ var TopologyCategorySchema = object({
22292
22408
  addons: array(TopologyCategoryAddonSchema).readonly()
22293
22409
  });
22294
22410
  /**
22295
- * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
22296
- * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
22297
- * version visibility for the Server management surface. Nullable: offline
22298
- * rows and pre-phase-2 nodes report none.
22411
+ * The node's runtime-updatable ROOT package (`@camstack/server` the single
22412
+ * root package for every node role) as reported by its `registerNode`
22413
+ * manifest — version visibility for the Server management surface. Nullable:
22414
+ * offline rows and nodes that never reported one.
22299
22415
  */
22300
22416
  var TopologyRootPackageSchema = object({
22301
22417
  name: string(),
@@ -22683,17 +22799,28 @@ var PlatformScoreSchema = object({
22683
22799
  format: _enum([
22684
22800
  "onnx",
22685
22801
  "coreml",
22686
- "openvino"
22802
+ "openvino",
22803
+ "tflite"
22687
22804
  ]),
22688
22805
  score: number(),
22689
22806
  reason: string(),
22690
22807
  available: boolean()
22691
22808
  });
22809
+ var InferenceDeviceDescriptorSchema = object({
22810
+ key: string(),
22811
+ backend: string(),
22812
+ device: string(),
22813
+ format: ModelFormatSchema,
22814
+ runtime: literal("python"),
22815
+ score: number(),
22816
+ available: boolean()
22817
+ });
22692
22818
  var PlatformCapabilitiesSchema = object({
22693
22819
  hardware: HardwareInfoSchema,
22694
22820
  scores: array(PlatformScoreSchema).readonly(),
22695
22821
  bestScore: PlatformScoreSchema,
22696
- pythonPath: string().nullable()
22822
+ pythonPath: string().nullable(),
22823
+ devices: array(InferenceDeviceDescriptorSchema).readonly()
22697
22824
  });
22698
22825
  var ModelRequirementSchema = object({
22699
22826
  modelId: string(),
@@ -23572,12 +23699,6 @@ Object.freeze({
23572
23699
  addonId: null,
23573
23700
  access: "delete"
23574
23701
  },
23575
- "addons.updateFrameworkPackage": {
23576
- capName: "addons",
23577
- capScope: "system",
23578
- addonId: null,
23579
- access: "create"
23580
- },
23581
23702
  "addons.updatePackage": {
23582
23703
  capName: "addons",
23583
23704
  capScope: "system",
@@ -26350,12 +26471,6 @@ Object.freeze({
26350
26471
  addonId: null,
26351
26472
  access: "view"
26352
26473
  },
26353
- "pipelineExecutor.reprobeEngine": {
26354
- capName: "pipeline-executor",
26355
- capScope: "system",
26356
- addonId: null,
26357
- access: "create"
26358
- },
26359
26474
  "pipelineExecutor.runAudioTest": {
26360
26475
  capName: "pipeline-executor",
26361
26476
  capScope: "system",
@@ -26506,6 +26621,12 @@ Object.freeze({
26506
26621
  addonId: null,
26507
26622
  access: "view"
26508
26623
  },
26624
+ "pipelineOrchestrator.getNodeInferenceDevices": {
26625
+ capName: "pipeline-orchestrator",
26626
+ capScope: "system",
26627
+ addonId: null,
26628
+ access: "view"
26629
+ },
26509
26630
  "pipelineOrchestrator.getPipelineAssignment": {
26510
26631
  capName: "pipeline-orchestrator",
26511
26632
  capScope: "system",
@@ -26518,6 +26639,12 @@ Object.freeze({
26518
26639
  addonId: null,
26519
26640
  access: "view"
26520
26641
  },
26642
+ "pipelineOrchestrator.getPipelineDevicePin": {
26643
+ capName: "pipeline-orchestrator",
26644
+ capScope: "system",
26645
+ addonId: null,
26646
+ access: "view"
26647
+ },
26521
26648
  "pipelineOrchestrator.listAgentSettings": {
26522
26649
  capName: "pipeline-orchestrator",
26523
26650
  capScope: "system",
@@ -26560,19 +26687,19 @@ Object.freeze({
26560
26687
  addonId: null,
26561
26688
  access: "create"
26562
26689
  },
26563
- "pipelineOrchestrator.setAgentAddonDefaults": {
26690
+ "pipelineOrchestrator.setAgentCapabilities": {
26564
26691
  capName: "pipeline-orchestrator",
26565
26692
  capScope: "system",
26566
26693
  addonId: null,
26567
26694
  access: "create"
26568
26695
  },
26569
- "pipelineOrchestrator.setAgentCapabilities": {
26696
+ "pipelineOrchestrator.setAgentDetectWeight": {
26570
26697
  capName: "pipeline-orchestrator",
26571
26698
  capScope: "system",
26572
26699
  addonId: null,
26573
26700
  access: "create"
26574
26701
  },
26575
- "pipelineOrchestrator.setAgentDetectWeight": {
26702
+ "pipelineOrchestrator.setAgentInferenceDevices": {
26576
26703
  capName: "pipeline-orchestrator",
26577
26704
  capScope: "system",
26578
26705
  addonId: null,
@@ -26614,6 +26741,12 @@ Object.freeze({
26614
26741
  addonId: null,
26615
26742
  access: "create"
26616
26743
  },
26744
+ "pipelineOrchestrator.setPipelineDevicePin": {
26745
+ capName: "pipeline-orchestrator",
26746
+ capScope: "system",
26747
+ addonId: null,
26748
+ access: "create"
26749
+ },
26617
26750
  "pipelineOrchestrator.unassignAudio": {
26618
26751
  capName: "pipeline-orchestrator",
26619
26752
  capScope: "system",
@@ -28166,32 +28299,6 @@ Object.freeze({
28166
28299
  "network-access": "ingress",
28167
28300
  "smtp-provider": "email"
28168
28301
  });
28169
- var frameworkSwapPackageSchema = object({
28170
- name: string(),
28171
- stagedPath: string(),
28172
- backupPath: string(),
28173
- toVersion: string(),
28174
- fromVersion: string().nullable()
28175
- });
28176
- object({
28177
- jobId: string(),
28178
- taskId: string(),
28179
- packages: array(frameworkSwapPackageSchema),
28180
- requestedAtMs: number(),
28181
- schemaVersion: literal(1)
28182
- });
28183
- object({
28184
- jobId: string(),
28185
- taskId: string(),
28186
- backups: array(object({
28187
- name: string(),
28188
- backupPath: string(),
28189
- livePath: string()
28190
- })),
28191
- appliedAtMs: number(),
28192
- bootAttempts: number(),
28193
- schemaVersion: literal(1)
28194
- });
28195
28302
  //#endregion
28196
28303
  //#region ../../node_modules/@apocaliss92/nodepetkit/dist/index.js
28197
28304
  var PetkitError = class extends Error {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-petkit",
3
- "version": "0.1.14",
3
+ "version": "0.2.1",
4
4
  "description": "PetKit smart-feeder device-provider addon for CamStack — wraps the @apocaliss92/nodepetkit PetKit cloud client",
5
5
  "keywords": [
6
6
  "camstack",