@camstack/types 1.1.42 → 1.1.43

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.
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-ByctZsHo.js");
2
+ const require_sleep = require("./sleep-DmvEGsRg.js");
3
3
  const require_err_msg = require("./err-msg-COpsHMw2.js");
4
4
  exports.BaseAddon = require_sleep.BaseAddon;
5
5
  exports.DATAPLANE_SECRET_HEADER = require_sleep.DATAPLANE_SECRET_HEADER;
package/dist/addon.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { A as parseJsonUnknown, D as asString, I as scopeKey, M as ReadinessRegistry, N as ReadinessTimeoutError, S as DeviceType, T as asJsonObject, a as viewerUiCapability, bt as EventCategory, ct as BaseAddon, ft as emitReadiness, i as deviceOpsCapability, j as DATAPLANE_SECRET_HEADER, lt as normalizeAddonInitResult, m as expandCapMethods, o as adminUiCapability, s as createDeviceProxy, t as sleep, xt as DisposerChain } from "./sleep-BC9Yqte7.mjs";
1
+ import { A as parseJsonUnknown, D as asString, I as scopeKey, M as ReadinessRegistry, N as ReadinessTimeoutError, S as DeviceType, T as asJsonObject, a as viewerUiCapability, bt as EventCategory, ct as BaseAddon, ft as emitReadiness, i as deviceOpsCapability, j as DATAPLANE_SECRET_HEADER, lt as normalizeAddonInitResult, m as expandCapMethods, o as adminUiCapability, s as createDeviceProxy, t as sleep, xt as DisposerChain } from "./sleep-Baang_XW.mjs";
2
2
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
3
3
  export { BaseAddon, DATAPLANE_SECRET_HEADER, DeviceType, DisposerChain, EventCategory, ReadinessRegistry, ReadinessTimeoutError, adminUiCapability, asJsonObject, asString, createDeviceProxy, deviceOpsCapability, emitReadiness, errMsg, expandCapMethods, normalizeAddonInitResult, parseJsonUnknown, scopeKey, sleep, viewerUiCapability };
@@ -28,9 +28,9 @@ declare const NotificationRuleTemplateSchema: z.ZodObject<{
28
28
  body: z.ZodString;
29
29
  imageMode: z.ZodEnum<{
30
30
  none: "none";
31
+ full: "full";
31
32
  crop: "crop";
32
33
  annotated: "annotated";
33
- full: "full";
34
34
  }>;
35
35
  }, z.core.$strip>;
36
36
  declare const NotificationRuleSchema: z.ZodObject<{
@@ -67,9 +67,9 @@ declare const NotificationRuleSchema: z.ZodObject<{
67
67
  body: z.ZodString;
68
68
  imageMode: z.ZodEnum<{
69
69
  none: "none";
70
+ full: "full";
70
71
  crop: "crop";
71
72
  annotated: "annotated";
72
- full: "full";
73
73
  }>;
74
74
  }, z.core.$strip>>;
75
75
  priority: z.ZodEnum<{
@@ -145,9 +145,9 @@ export declare const advancedNotifierCapability: {
145
145
  body: z.ZodString;
146
146
  imageMode: z.ZodEnum<{
147
147
  none: "none";
148
+ full: "full";
148
149
  crop: "crop";
149
150
  annotated: "annotated";
150
- full: "full";
151
151
  }>;
152
152
  }, z.core.$strip>>;
153
153
  priority: z.ZodEnum<{
@@ -193,9 +193,9 @@ export declare const advancedNotifierCapability: {
193
193
  body: z.ZodString;
194
194
  imageMode: z.ZodEnum<{
195
195
  none: "none";
196
+ full: "full";
196
197
  crop: "crop";
197
198
  annotated: "annotated";
198
- full: "full";
199
199
  }>;
200
200
  }, z.core.$strip>>;
201
201
  priority: z.ZodEnum<{
@@ -79,7 +79,7 @@ export type { PipelineStepInputOutput, PipelineValidationIssue, PipelineValidati
79
79
  export { ModelSubstitutionSchema, PipelineDefaultStepSchema, PipelineEngineChoiceSchema, PipelineRunResultBridge, PipelineStepInputSchema, PipelineValidationIssueSchema, PipelineValidationResultSchema, pipelineExecutorCapability, } from './pipeline-executor.cap.js';
80
80
  export type { CameraAssignmentStatus, CameraAudioStatus, CameraBrokerProfile, CameraBrokerStatus, CameraDecoderShm, CameraDecoderStatus, CameraDetectionPhase, CameraDetectionProvisioning, CameraDetectionProvisioningState, CameraDetectionStatus, CameraMotionStatus, CameraRecordingMode, CameraRecordingStatus, CameraSourceStatus, CameraSourceStream, CameraStatus, IngestOwner, } from './pipeline-orchestrator.cap.js';
81
81
  export { AgentLoadSummarySchema, CameraAssignmentStatusSchema, CameraAudioStatusSchema, CameraBrokerProfileSchema, CameraBrokerStatusSchema, CameraDecoderShmSchema, CameraDecoderStatusSchema, CameraDetectionPhaseSchema, CameraDetectionProvisioningSchema, CameraDetectionProvisioningStateSchema, CameraDetectionStatusSchema, CameraMotionStatusSchema, CameraRecordingModeSchema, CameraRecordingStatusSchema, CameraSourceStatusSchema, CameraSourceStreamSchema, CameraStatusSchema, CapabilityBindingsSchema, GlobalMetricsSchema, IngestOwnerSchema, PipelineAssignmentSchema, pipelineOrchestratorCapability, } from './pipeline-orchestrator.cap.js';
82
- export type { MotionSource, MotionSources, ReportMotionInput, RunnerFrameSource, } from './pipeline-runner.cap.js';
82
+ export type { DetailParent, DetailResult, MotionSource, MotionSources, ReportMotionInput, RunDetailSubtreeInput, RunDetailSubtreeResult, RunnerFrameSource, } from './pipeline-runner.cap.js';
83
83
  export { MotionSourceEnum, MotionSourcesSchema, pipelineRunnerCapability, ReportMotionInputSchema, RunnerCameraConfigSchema, RunnerCameraDeviceUIFields, RunnerFrameSourceSchema, RunnerLocalLoadSchema, RunnerLocalMetricsSchema, } from './pipeline-runner.cap.js';
84
84
  export { AudioChunkInputSchema, AudioClassificationLabelSchema, AudioLevelSchema, BoundingBoxSchema, FrameInputSchema, SpatialDetectionSchema, } from './schemas/detection-shared.js';
85
85
  export { CameraMetricsSchema, CameraMetricsWithDeviceIdSchema, OrchestratorMetricsSchema, } from './schemas/orchestrator-metrics.js';
@@ -891,6 +891,10 @@ export declare const pipelineExecutorCapability: {
891
891
  referenceImage: z.ZodOptional<z.ZodString>;
892
892
  deviceId: z.ZodOptional<z.ZodNumber>;
893
893
  sessionId: z.ZodOptional<z.ZodString>;
894
+ plane: z.ZodOptional<z.ZodEnum<{
895
+ frame: "frame";
896
+ full: "full";
897
+ }>>;
894
898
  }, z.core.$strip>, z.ZodCustom<FrameResult, FrameResult>, "mutation">;
895
899
  /**
896
900
  * Batched run — N raw frames packed into one cap call. The provider
@@ -21,6 +21,39 @@ export declare const NativeCropResultSchema: z.ZodObject<{
21
21
  }, z.core.$strip>;
22
22
  export type NativeCropBbox = z.infer<typeof NativeCropBboxSchema>;
23
23
  export type NativeCropCapResult = z.infer<typeof NativeCropResultSchema>;
24
+ /** Parent detection context passed to `runDetailSubtree` — the crop's
25
+ * originating detection, in FRAME-space coordinates. Reuses
26
+ * `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
27
+ * the coordinates are frame-space rather than getNativeCrop's
28
+ * normalized [0,1] convention). */
29
+ declare const DetailParentSchema: z.ZodObject<{
30
+ bbox: z.ZodObject<{
31
+ x: z.ZodNumber;
32
+ y: z.ZodNumber;
33
+ w: z.ZodNumber;
34
+ h: z.ZodNumber;
35
+ }, z.core.$strip>;
36
+ className: z.ZodString;
37
+ }, z.core.$strip>;
38
+ /** One child-step result from `runDetailSubtree` — an embedding, label,
39
+ * or refined detection produced by running the crop-subtree on a
40
+ * single tracked detection. */
41
+ declare const DetailResultSchema: z.ZodObject<{
42
+ stepId: z.ZodString;
43
+ className: z.ZodString;
44
+ score: z.ZodNumber;
45
+ bbox: z.ZodOptional<z.ZodObject<{
46
+ x: z.ZodNumber;
47
+ y: z.ZodNumber;
48
+ w: z.ZodNumber;
49
+ h: z.ZodNumber;
50
+ }, z.core.$strip>>;
51
+ embedding: z.ZodOptional<z.ZodString>;
52
+ label: z.ZodOptional<z.ZodString>;
53
+ alignedCropJpeg: z.ZodOptional<z.ZodString>;
54
+ }, z.core.$strip>;
55
+ export type DetailParent = z.infer<typeof DetailParentSchema>;
56
+ export type DetailResult = z.infer<typeof DetailResultSchema>;
24
57
  /**
25
58
  * Source enum for motion signals fed to the runner. Extensible — add
26
59
  * new variants here when new motion-trigger paths are wired in
@@ -436,7 +469,81 @@ export declare const pipelineRunnerCapability: {
436
469
  width: z.ZodNumber;
437
470
  height: z.ZodNumber;
438
471
  }, z.core.$strip>>, import("./capability-definition.js").CapabilityMethodKind>;
472
+ /**
473
+ * Two-plane design: run the DETAIL subtree (crop children —
474
+ * embedding, classifier, refiner steps whose `inputClasses ≠ null`)
475
+ * for a single tracked detection. The per-frame plane (`runPipeline`
476
+ * with `plane: 'frame'`) skips crop children entirely; a track-level
477
+ * caller invokes this per-track, on its own cadence, instead of on
478
+ * every frame. Takes either a `frameHandle` (shm lease/session —
479
+ * preferred, zero-copy) or a `cropJpeg` fallback when the lease/
480
+ * session backing the frame is already gone. `steps` narrows which
481
+ * configured children to run (default: all configured children for
482
+ * `parent.className`). Returns `null` when neither frame source is
483
+ * resolvable (handle evicted and no cropJpeg fallback supplied).
484
+ */
485
+ readonly runDetailSubtree: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
486
+ deviceId: z.ZodNumber;
487
+ frameHandle: z.ZodOptional<z.ZodObject<{
488
+ shmId: z.ZodString;
489
+ slot: z.ZodNumber;
490
+ seq: z.ZodNumber;
491
+ width: z.ZodNumber;
492
+ height: z.ZodNumber;
493
+ format: z.ZodEnum<{
494
+ jpeg: "jpeg";
495
+ rgb: "rgb";
496
+ bgr: "bgr";
497
+ yuv420: "yuv420";
498
+ gray: "gray";
499
+ }>;
500
+ pts: z.ZodNumber;
501
+ byteLength: z.ZodNumber;
502
+ nodeId: z.ZodString;
503
+ slotCount: z.ZodNumber;
504
+ }, z.core.$strip>>;
505
+ cropJpeg: z.ZodOptional<z.ZodString>;
506
+ parent: z.ZodObject<{
507
+ bbox: z.ZodObject<{
508
+ x: z.ZodNumber;
509
+ y: z.ZodNumber;
510
+ w: z.ZodNumber;
511
+ h: z.ZodNumber;
512
+ }, z.core.$strip>;
513
+ className: z.ZodString;
514
+ }, z.core.$strip>;
515
+ steps: z.ZodOptional<z.ZodArray<z.ZodString>>;
516
+ }, z.core.$strip>, z.ZodNullable<z.ZodObject<{
517
+ details: z.ZodArray<z.ZodObject<{
518
+ stepId: z.ZodString;
519
+ className: z.ZodString;
520
+ score: z.ZodNumber;
521
+ bbox: z.ZodOptional<z.ZodObject<{
522
+ x: z.ZodNumber;
523
+ y: z.ZodNumber;
524
+ w: z.ZodNumber;
525
+ h: z.ZodNumber;
526
+ }, z.core.$strip>>;
527
+ embedding: z.ZodOptional<z.ZodString>;
528
+ label: z.ZodOptional<z.ZodString>;
529
+ alignedCropJpeg: z.ZodOptional<z.ZodString>;
530
+ }, z.core.$strip>>;
531
+ }, z.core.$strip>>, "mutation">;
439
532
  };
440
533
  };
441
534
  export type IPipelineRunnerProvider = InferProvider<typeof pipelineRunnerCapability>;
535
+ /**
536
+ * Named input/output types for `runDetailSubtree`, derived from the cap
537
+ * definition above (`InferProvider`) rather than a standalone exported zod
538
+ * schema — the method's input stays an INLINE `z.object({...})` literal so
539
+ * `scripts/lib/parse-cap.ts`'s `deviceBound` regex (which only scans a
540
+ * method's own inline call body for `deviceId: z.number(`) keeps detecting
541
+ * it as device-bound and `generate-device-proxy.ts` keeps mounting it on
542
+ * `DeviceProxy.pipelineRunner`. Extracting the input into a separate named
543
+ * schema constant (as `RunnerCameraConfigSchema` does for `attachCamera`)
544
+ * would silently drop it from the device proxy — verified via `npm run
545
+ * codegen` while implementing this cap.
546
+ */
547
+ export type RunDetailSubtreeInput = Parameters<IPipelineRunnerProvider['runDetailSubtree']>[0];
548
+ export type RunDetailSubtreeResult = NonNullable<Awaited<ReturnType<IPipelineRunnerProvider['runDetailSubtree']>>>;
442
549
  export { RunnerCameraConfigSchema, RunnerLocalLoadSchema, RunnerLocalMetricsSchema };
@@ -5987,6 +5987,13 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
5987
5987
  recognizedIdentityId?: string | undefined;
5988
5988
  identityName?: string | undefined;
5989
5989
  base64?: string | undefined;
5990
+ faceBbox?: {
5991
+ x: number;
5992
+ y: number;
5993
+ w: number;
5994
+ h: number;
5995
+ } | undefined;
5996
+ keyFrameMediaKey?: string | undefined;
5990
5997
  }[];
5991
5998
  meta: object;
5992
5999
  }>;
@@ -6005,6 +6012,13 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
6005
6012
  recognizedIdentityId?: string | undefined;
6006
6013
  identityName?: string | undefined;
6007
6014
  base64?: string | undefined;
6015
+ faceBbox?: {
6016
+ x: number;
6017
+ y: number;
6018
+ w: number;
6019
+ h: number;
6020
+ } | undefined;
6021
+ keyFrameMediaKey?: string | undefined;
6008
6022
  } | null;
6009
6023
  meta: object;
6010
6024
  }>;
@@ -9033,6 +9047,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
9033
9047
  frameWidth?: number | undefined;
9034
9048
  frameHeight?: number | undefined;
9035
9049
  mediaKey?: string | undefined;
9050
+ keyFrameMediaKey?: string | undefined;
9036
9051
  mediaUrl?: string | undefined;
9037
9052
  importance?: number | undefined;
9038
9053
  }[];
@@ -9118,11 +9133,11 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
9118
9133
  input: {
9119
9134
  [x: string]: unknown;
9120
9135
  eventId: string;
9121
- kind?: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop" | undefined;
9136
+ kind?: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop" | "keyFrame" | undefined;
9122
9137
  };
9123
9138
  output: readonly {
9124
9139
  key: string;
9125
- kind: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop";
9140
+ kind: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop" | "keyFrame";
9126
9141
  base64: string;
9127
9142
  sizeBytes: number;
9128
9143
  timestamp: number;
@@ -9136,7 +9151,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
9136
9151
  };
9137
9152
  output: readonly {
9138
9153
  key: string;
9139
- kind: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop";
9154
+ kind: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop" | "keyFrame";
9140
9155
  base64: string;
9141
9156
  sizeBytes: number;
9142
9157
  timestamp: number;
@@ -9177,6 +9192,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
9177
9192
  frameWidth?: number | undefined;
9178
9193
  frameHeight?: number | undefined;
9179
9194
  mediaKey?: string | undefined;
9195
+ keyFrameMediaKey?: string | undefined;
9180
9196
  mediaUrl?: string | undefined;
9181
9197
  importance?: number | undefined;
9182
9198
  }[];
@@ -9545,6 +9561,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
9545
9561
  referenceImage?: string | undefined;
9546
9562
  deviceId?: number | undefined;
9547
9563
  sessionId?: string | undefined;
9564
+ plane?: "full" | "frame" | undefined;
9548
9565
  };
9549
9566
  output: import("@camstack/types").FrameResult;
9550
9567
  meta: object;
@@ -10783,6 +10800,52 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
10783
10800
  } | null;
10784
10801
  meta: object;
10785
10802
  }>;
10803
+ runDetailSubtree: import("@trpc/server").TRPCMutationProcedure<{
10804
+ input: {
10805
+ [x: string]: unknown;
10806
+ deviceId: number;
10807
+ parent: {
10808
+ bbox: {
10809
+ x: number;
10810
+ y: number;
10811
+ w: number;
10812
+ h: number;
10813
+ };
10814
+ className: string;
10815
+ };
10816
+ frameHandle?: {
10817
+ shmId: string;
10818
+ slot: number;
10819
+ seq: number;
10820
+ width: number;
10821
+ height: number;
10822
+ format: "rgb" | "jpeg" | "bgr" | "yuv420" | "gray";
10823
+ pts: number;
10824
+ byteLength: number;
10825
+ nodeId: string;
10826
+ slotCount: number;
10827
+ } | undefined;
10828
+ cropJpeg?: string | undefined;
10829
+ steps?: string[] | undefined;
10830
+ };
10831
+ output: {
10832
+ details: {
10833
+ stepId: string;
10834
+ className: string;
10835
+ score: number;
10836
+ bbox?: {
10837
+ x: number;
10838
+ y: number;
10839
+ w: number;
10840
+ h: number;
10841
+ } | undefined;
10842
+ embedding?: string | undefined;
10843
+ label?: string | undefined;
10844
+ alignedCropJpeg?: string | undefined;
10845
+ }[];
10846
+ } | null;
10847
+ meta: object;
10848
+ }>;
10786
10849
  }>>;
10787
10850
  plateGallery: import("@trpc/server").TRPCBuiltRouter<{
10788
10851
  ctx: TrpcContext;
@@ -20967,6 +21030,13 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
20967
21030
  recognizedIdentityId?: string | undefined;
20968
21031
  identityName?: string | undefined;
20969
21032
  base64?: string | undefined;
21033
+ faceBbox?: {
21034
+ x: number;
21035
+ y: number;
21036
+ w: number;
21037
+ h: number;
21038
+ } | undefined;
21039
+ keyFrameMediaKey?: string | undefined;
20970
21040
  }[];
20971
21041
  meta: object;
20972
21042
  }>;
@@ -20985,6 +21055,13 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
20985
21055
  recognizedIdentityId?: string | undefined;
20986
21056
  identityName?: string | undefined;
20987
21057
  base64?: string | undefined;
21058
+ faceBbox?: {
21059
+ x: number;
21060
+ y: number;
21061
+ w: number;
21062
+ h: number;
21063
+ } | undefined;
21064
+ keyFrameMediaKey?: string | undefined;
20988
21065
  } | null;
20989
21066
  meta: object;
20990
21067
  }>;
@@ -24013,6 +24090,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
24013
24090
  frameWidth?: number | undefined;
24014
24091
  frameHeight?: number | undefined;
24015
24092
  mediaKey?: string | undefined;
24093
+ keyFrameMediaKey?: string | undefined;
24016
24094
  mediaUrl?: string | undefined;
24017
24095
  importance?: number | undefined;
24018
24096
  }[];
@@ -24098,11 +24176,11 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
24098
24176
  input: {
24099
24177
  [x: string]: unknown;
24100
24178
  eventId: string;
24101
- kind?: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop" | undefined;
24179
+ kind?: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop" | "keyFrame" | undefined;
24102
24180
  };
24103
24181
  output: readonly {
24104
24182
  key: string;
24105
- kind: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop";
24183
+ kind: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop" | "keyFrame";
24106
24184
  base64: string;
24107
24185
  sizeBytes: number;
24108
24186
  timestamp: number;
@@ -24116,7 +24194,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
24116
24194
  };
24117
24195
  output: readonly {
24118
24196
  key: string;
24119
- kind: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop";
24197
+ kind: "snapshot" | "crop" | "thumbnail" | "firstFrame" | "lastFrame" | "fullFrame" | "fullFrameBoxed" | "faceCrop" | "plateCrop" | "keyFrame";
24120
24198
  base64: string;
24121
24199
  sizeBytes: number;
24122
24200
  timestamp: number;
@@ -24157,6 +24235,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
24157
24235
  frameWidth?: number | undefined;
24158
24236
  frameHeight?: number | undefined;
24159
24237
  mediaKey?: string | undefined;
24238
+ keyFrameMediaKey?: string | undefined;
24160
24239
  mediaUrl?: string | undefined;
24161
24240
  importance?: number | undefined;
24162
24241
  }[];
@@ -24525,6 +24604,7 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
24525
24604
  referenceImage?: string | undefined;
24526
24605
  deviceId?: number | undefined;
24527
24606
  sessionId?: string | undefined;
24607
+ plane?: "full" | "frame" | undefined;
24528
24608
  };
24529
24609
  output: import("@camstack/types").FrameResult;
24530
24610
  meta: object;
@@ -25763,6 +25843,52 @@ export type AppRouter = import("@trpc/server/unstable-core-do-not-import").Route
25763
25843
  } | null;
25764
25844
  meta: object;
25765
25845
  }>;
25846
+ runDetailSubtree: import("@trpc/server").TRPCMutationProcedure<{
25847
+ input: {
25848
+ [x: string]: unknown;
25849
+ deviceId: number;
25850
+ parent: {
25851
+ bbox: {
25852
+ x: number;
25853
+ y: number;
25854
+ w: number;
25855
+ h: number;
25856
+ };
25857
+ className: string;
25858
+ };
25859
+ frameHandle?: {
25860
+ shmId: string;
25861
+ slot: number;
25862
+ seq: number;
25863
+ width: number;
25864
+ height: number;
25865
+ format: "rgb" | "jpeg" | "bgr" | "yuv420" | "gray";
25866
+ pts: number;
25867
+ byteLength: number;
25868
+ nodeId: string;
25869
+ slotCount: number;
25870
+ } | undefined;
25871
+ cropJpeg?: string | undefined;
25872
+ steps?: string[] | undefined;
25873
+ };
25874
+ output: {
25875
+ details: {
25876
+ stepId: string;
25877
+ className: string;
25878
+ score: number;
25879
+ bbox?: {
25880
+ x: number;
25881
+ y: number;
25882
+ w: number;
25883
+ h: number;
25884
+ } | undefined;
25885
+ embedding?: string | undefined;
25886
+ label?: string | undefined;
25887
+ alignedCropJpeg?: string | undefined;
25888
+ }[];
25889
+ } | null;
25890
+ meta: object;
25891
+ }>;
25766
25892
  }>>;
25767
25893
  plateGallery: import("@trpc/server").TRPCBuiltRouter<{
25768
25894
  ctx: TrpcContext;
@@ -268,7 +268,7 @@ export interface DeviceProxy {
268
268
  readonly networkQuality: Pick<InferDeviceProxyCap<typeof networkQualityCapability>, 'getDeviceStats' | 'reportClientStats'>;
269
269
  readonly pipelineExecutor: Pick<InferDeviceProxyCap<typeof pipelineExecutorCapability>, 'runPipeline' | 'runPipelineBatch'>;
270
270
  readonly pipelineOrchestrator: Pick<InferDeviceProxyCap<typeof pipelineOrchestratorCapability>, 'assignPipeline' | 'unassignPipeline' | 'getPipelineAssignment' | 'getCameraMetrics' | 'assignAudio' | 'unassignAudio' | 'getAudioAssignment' | 'getAudioAssignments' | 'getCameraSettings' | 'setCameraStepToggle' | 'getCameraStepOverrides' | 'setCameraStepOverride' | 'setCameraPipelineForAgent' | 'resolvePipeline' | 'getCameraStatus' | 'getDeviceSettingsContribution' | 'getDeviceLiveContribution' | 'applyDeviceSettingsPatch'>;
271
- readonly pipelineRunner: Pick<InferDeviceProxyCap<typeof pipelineRunnerCapability>, 'detachCamera' | 'getCameraMetrics'>;
271
+ readonly pipelineRunner: Pick<InferDeviceProxyCap<typeof pipelineRunnerCapability>, 'detachCamera' | 'getCameraMetrics' | 'runDetailSubtree'>;
272
272
  readonly plateGallery: Pick<InferDeviceProxyCap<typeof plateGalleryCapability>, 'listPlates' | 'getPlateByTrack'>;
273
273
  readonly recording: Pick<InferDeviceProxyCap<typeof recordingCapability>, 'getAvailability' | 'getDaysWithRecordings' | 'getPlaybackManifest' | 'getDeviceConfig' | 'locateSegment' | 'readSegmentBytes' | 'setDeviceConfig' | 'rescanStorage' | 'pruneFootage' | 'getStatus' | 'getDeviceSettingsContribution' | 'getDeviceLiveContribution' | 'applyDeviceSettingsPatch'>;
274
274
  readonly streamBroker: Pick<InferDeviceProxyCap<typeof streamBrokerCapability>, 'publishCameraStream' | 'retractCameraStream' | 'assignProfile' | 'unassignProfile' | 'restartProfile' | 'getDeviceSettingsContribution' | 'getDeviceLiveContribution' | 'applyDeviceSettingsPatch'>;
@@ -6,7 +6,7 @@
6
6
  * scope+access check inside `protectedProcedure` (see
7
7
  * `server/backend/src/api/trpc/trpc.middleware.ts`).
8
8
  *
9
- * Coverage: 737 method paths across 112 capabilities.
9
+ * Coverage: 738 method paths across 112 capabilities.
10
10
  */
11
11
  import type { CapabilityMethodAccess } from '../capabilities/capability-definition.js';
12
12
  export interface MethodAccessRecord {
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-ByctZsHo.js");
2
+ const require_sleep = require("./sleep-DmvEGsRg.js");
3
3
  const require_err_msg = require("./err-msg-COpsHMw2.js");
4
4
  let zod = require("zod");
5
5
  //#region src/health/wiring-health.ts
@@ -7880,7 +7880,15 @@ var pipelineExecutorCapability = {
7880
7880
  image: zod.z.instanceof(Uint8Array).optional(),
7881
7881
  referenceImage: zod.z.string().optional(),
7882
7882
  deviceId: zod.z.number().optional(),
7883
- sessionId: zod.z.string().optional()
7883
+ sessionId: zod.z.string().optional(),
7884
+ /**
7885
+ * Execution plane. 'full' (default) runs the whole tree — benchmark,
7886
+ * reference-image, and detail-subtree calls. 'frame' is the live
7887
+ * per-frame dispatch: ONLY root-plane steps run; crop children
7888
+ * (inputClasses ≠ null) are skipped and served per-track via
7889
+ * pipelineRunner.runDetailSubtree (two-plane design).
7890
+ */
7891
+ plane: zod.z.enum(["full", "frame"]).optional()
7884
7892
  }), PipelineRunResultBridge, { kind: "mutation" }),
7885
7893
  /**
7886
7894
  * Batched run — N raw frames packed into one cap call. The provider
@@ -8114,6 +8122,28 @@ var NativeCropResultSchema = zod.z.object({
8114
8122
  width: zod.z.number().int().positive(),
8115
8123
  height: zod.z.number().int().positive()
8116
8124
  });
8125
+ /** Parent detection context passed to `runDetailSubtree` — the crop's
8126
+ * originating detection, in FRAME-space coordinates. Reuses
8127
+ * `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
8128
+ * the coordinates are frame-space rather than getNativeCrop's
8129
+ * normalized [0,1] convention). */
8130
+ var DetailParentSchema = zod.z.object({
8131
+ bbox: NativeCropBboxSchema,
8132
+ className: zod.z.string()
8133
+ });
8134
+ /** One child-step result from `runDetailSubtree` — an embedding, label,
8135
+ * or refined detection produced by running the crop-subtree on a
8136
+ * single tracked detection. */
8137
+ var DetailResultSchema = zod.z.object({
8138
+ stepId: zod.z.string(),
8139
+ className: zod.z.string(),
8140
+ score: zod.z.number(),
8141
+ /** FRAME-space bbox (already mapped back from crop space). */
8142
+ bbox: NativeCropBboxSchema.optional(),
8143
+ embedding: zod.z.string().optional(),
8144
+ label: zod.z.string().optional(),
8145
+ alignedCropJpeg: zod.z.string().optional()
8146
+ });
8117
8147
  /**
8118
8148
  * Per-camera tunable ranges + defaults. Single source of truth used
8119
8149
  * by both the Zod data schema (validation + default fallback) and
@@ -8557,7 +8587,27 @@ var pipelineRunnerCapability = {
8557
8587
  handle: require_sleep.FrameHandleSchema,
8558
8588
  bbox: NativeCropBboxSchema,
8559
8589
  maxWidth: zod.z.number().int().positive().optional()
8560
- }), NativeCropResultSchema.nullable())
8590
+ }), NativeCropResultSchema.nullable()),
8591
+ /**
8592
+ * Two-plane design: run the DETAIL subtree (crop children —
8593
+ * embedding, classifier, refiner steps whose `inputClasses ≠ null`)
8594
+ * for a single tracked detection. The per-frame plane (`runPipeline`
8595
+ * with `plane: 'frame'`) skips crop children entirely; a track-level
8596
+ * caller invokes this per-track, on its own cadence, instead of on
8597
+ * every frame. Takes either a `frameHandle` (shm lease/session —
8598
+ * preferred, zero-copy) or a `cropJpeg` fallback when the lease/
8599
+ * session backing the frame is already gone. `steps` narrows which
8600
+ * configured children to run (default: all configured children for
8601
+ * `parent.className`). Returns `null` when neither frame source is
8602
+ * resolvable (handle evicted and no cropJpeg fallback supplied).
8603
+ */
8604
+ runDetailSubtree: require_sleep.method(zod.z.object({
8605
+ deviceId: zod.z.number(),
8606
+ frameHandle: require_sleep.FrameHandleSchema.optional(),
8607
+ cropJpeg: zod.z.string().optional(),
8608
+ parent: DetailParentSchema,
8609
+ steps: zod.z.array(zod.z.string()).optional()
8610
+ }), zod.z.object({ details: zod.z.array(DetailResultSchema) }).nullable(), { kind: "mutation" })
8561
8611
  }
8562
8612
  };
8563
8613
  //#endregion
@@ -27025,6 +27075,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27025
27075
  addonId: null,
27026
27076
  access: "create"
27027
27077
  },
27078
+ "pipelineRunner.runDetailSubtree": {
27079
+ capName: "pipeline-runner",
27080
+ capScope: "system",
27081
+ addonId: null,
27082
+ access: "create"
27083
+ },
27028
27084
  "plateGallery.correctPlateText": {
27029
27085
  capName: "plate-gallery",
27030
27086
  capScope: "system",
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as StreamSourceSchema, A as parseJsonUnknown, B as CamProfileSchema, C as asBoolean, D as asString, E as asNumber, F as readinessKey, G as DecodedFrameSchema, H as CamStreamResolutionSchema, I as scopeKey, J as FrameHandleSchema, K as EncodedPacketSchema, L as BrokerStatsSchema, M as ReadinessRegistry, N as ReadinessTimeoutError, O as parseJsonArray, P as emitDownForOwnedCaps, Q as StreamSourceEntrySchema, R as BrokerStatusSchema, S as DeviceType, T as asJsonObject, U as CameraStreamSchema, V as CamStreamKindSchema, W as DecodedAudioChunkSchema, X as ProfileSlotSchema, Y as ProfileRtspEntrySchema, Z as ProfileSlotStatusSchema, _ as resolveCapMount, _t as collectHydratedFieldValues, a as viewerUiCapability, at as makeSourceBrokerId, b as DeviceFeature, bt as EventCategory, c as createLazyTrpcSource, ct as BaseAddon, d as DEVICE_SETTINGS_CONTRIBUTION_METHODS, dt as createEvent, et as SubscribeAudioChunksInputSchema, f as DEVICE_STATUS_METHOD, ft as emitReadiness, g as method, gt as collectHydratedFieldEntries, h as isDeviceConfigCap, ht as WELL_KNOWN_TAB_MAP, i as deviceOpsCapability, it as makeProfileBrokerId, j as DATAPLANE_SECRET_HEADER, k as parseJsonObject, l as createMirrorSource, lt as normalizeAddonInitResult, m as expandCapMethods, mt as WELL_KNOWN_TABS, n as sleepCancellable, nt as SubscribeFramesInputSchema, o as adminUiCapability, ot as parseProfileBrokerId, p as event, pt as isEvent, q as FrameHandleFormatSchema, r as RawStateResultSchema, rt as SubscribeFramesResultSchema, s as createDeviceProxy, st as selectAssignedProfileSlots, t as sleep, tt as SubscribeAudioChunksResultSchema, u as createSliceHandle, ut as createDurableState, v as systemMethod, vt as hydrateSchema, w as asJsonArray, x as DeviceRole, xt as DisposerChain, y as ChargingStatus, yt as resolveHydratedFieldValue, z as CAM_PROFILE_ORDER } from "./sleep-BC9Yqte7.mjs";
1
+ import { $ as StreamSourceSchema, A as parseJsonUnknown, B as CamProfileSchema, C as asBoolean, D as asString, E as asNumber, F as readinessKey, G as DecodedFrameSchema, H as CamStreamResolutionSchema, I as scopeKey, J as FrameHandleSchema, K as EncodedPacketSchema, L as BrokerStatsSchema, M as ReadinessRegistry, N as ReadinessTimeoutError, O as parseJsonArray, P as emitDownForOwnedCaps, Q as StreamSourceEntrySchema, R as BrokerStatusSchema, S as DeviceType, T as asJsonObject, U as CameraStreamSchema, V as CamStreamKindSchema, W as DecodedAudioChunkSchema, X as ProfileSlotSchema, Y as ProfileRtspEntrySchema, Z as ProfileSlotStatusSchema, _ as resolveCapMount, _t as collectHydratedFieldValues, a as viewerUiCapability, at as makeSourceBrokerId, b as DeviceFeature, bt as EventCategory, c as createLazyTrpcSource, ct as BaseAddon, d as DEVICE_SETTINGS_CONTRIBUTION_METHODS, dt as createEvent, et as SubscribeAudioChunksInputSchema, f as DEVICE_STATUS_METHOD, ft as emitReadiness, g as method, gt as collectHydratedFieldEntries, h as isDeviceConfigCap, ht as WELL_KNOWN_TAB_MAP, i as deviceOpsCapability, it as makeProfileBrokerId, j as DATAPLANE_SECRET_HEADER, k as parseJsonObject, l as createMirrorSource, lt as normalizeAddonInitResult, m as expandCapMethods, mt as WELL_KNOWN_TABS, n as sleepCancellable, nt as SubscribeFramesInputSchema, o as adminUiCapability, ot as parseProfileBrokerId, p as event, pt as isEvent, q as FrameHandleFormatSchema, r as RawStateResultSchema, rt as SubscribeFramesResultSchema, s as createDeviceProxy, st as selectAssignedProfileSlots, t as sleep, tt as SubscribeAudioChunksResultSchema, u as createSliceHandle, ut as createDurableState, v as systemMethod, vt as hydrateSchema, w as asJsonArray, x as DeviceRole, xt as DisposerChain, y as ChargingStatus, yt as resolveHydratedFieldValue, z as CAM_PROFILE_ORDER } from "./sleep-Baang_XW.mjs";
2
2
  import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/health/wiring-health.ts
@@ -7879,7 +7879,15 @@ var pipelineExecutorCapability = {
7879
7879
  image: z.instanceof(Uint8Array).optional(),
7880
7880
  referenceImage: z.string().optional(),
7881
7881
  deviceId: z.number().optional(),
7882
- sessionId: z.string().optional()
7882
+ sessionId: z.string().optional(),
7883
+ /**
7884
+ * Execution plane. 'full' (default) runs the whole tree — benchmark,
7885
+ * reference-image, and detail-subtree calls. 'frame' is the live
7886
+ * per-frame dispatch: ONLY root-plane steps run; crop children
7887
+ * (inputClasses ≠ null) are skipped and served per-track via
7888
+ * pipelineRunner.runDetailSubtree (two-plane design).
7889
+ */
7890
+ plane: z.enum(["full", "frame"]).optional()
7883
7891
  }), PipelineRunResultBridge, { kind: "mutation" }),
7884
7892
  /**
7885
7893
  * Batched run — N raw frames packed into one cap call. The provider
@@ -8113,6 +8121,28 @@ var NativeCropResultSchema = z.object({
8113
8121
  width: z.number().int().positive(),
8114
8122
  height: z.number().int().positive()
8115
8123
  });
8124
+ /** Parent detection context passed to `runDetailSubtree` — the crop's
8125
+ * originating detection, in FRAME-space coordinates. Reuses
8126
+ * `NativeCropBboxSchema`'s `{x,y,w,h}` shape (same numeric fields; here
8127
+ * the coordinates are frame-space rather than getNativeCrop's
8128
+ * normalized [0,1] convention). */
8129
+ var DetailParentSchema = z.object({
8130
+ bbox: NativeCropBboxSchema,
8131
+ className: z.string()
8132
+ });
8133
+ /** One child-step result from `runDetailSubtree` — an embedding, label,
8134
+ * or refined detection produced by running the crop-subtree on a
8135
+ * single tracked detection. */
8136
+ var DetailResultSchema = z.object({
8137
+ stepId: z.string(),
8138
+ className: z.string(),
8139
+ score: z.number(),
8140
+ /** FRAME-space bbox (already mapped back from crop space). */
8141
+ bbox: NativeCropBboxSchema.optional(),
8142
+ embedding: z.string().optional(),
8143
+ label: z.string().optional(),
8144
+ alignedCropJpeg: z.string().optional()
8145
+ });
8116
8146
  /**
8117
8147
  * Per-camera tunable ranges + defaults. Single source of truth used
8118
8148
  * by both the Zod data schema (validation + default fallback) and
@@ -8556,7 +8586,27 @@ var pipelineRunnerCapability = {
8556
8586
  handle: FrameHandleSchema,
8557
8587
  bbox: NativeCropBboxSchema,
8558
8588
  maxWidth: z.number().int().positive().optional()
8559
- }), NativeCropResultSchema.nullable())
8589
+ }), NativeCropResultSchema.nullable()),
8590
+ /**
8591
+ * Two-plane design: run the DETAIL subtree (crop children —
8592
+ * embedding, classifier, refiner steps whose `inputClasses ≠ null`)
8593
+ * for a single tracked detection. The per-frame plane (`runPipeline`
8594
+ * with `plane: 'frame'`) skips crop children entirely; a track-level
8595
+ * caller invokes this per-track, on its own cadence, instead of on
8596
+ * every frame. Takes either a `frameHandle` (shm lease/session —
8597
+ * preferred, zero-copy) or a `cropJpeg` fallback when the lease/
8598
+ * session backing the frame is already gone. `steps` narrows which
8599
+ * configured children to run (default: all configured children for
8600
+ * `parent.className`). Returns `null` when neither frame source is
8601
+ * resolvable (handle evicted and no cropJpeg fallback supplied).
8602
+ */
8603
+ runDetailSubtree: method(z.object({
8604
+ deviceId: z.number(),
8605
+ frameHandle: FrameHandleSchema.optional(),
8606
+ cropJpeg: z.string().optional(),
8607
+ parent: DetailParentSchema,
8608
+ steps: z.array(z.string()).optional()
8609
+ }), z.object({ details: z.array(DetailResultSchema) }).nullable(), { kind: "mutation" })
8560
8610
  }
8561
8611
  };
8562
8612
  //#endregion
@@ -27024,6 +27074,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
27024
27074
  addonId: null,
27025
27075
  access: "create"
27026
27076
  },
27077
+ "pipelineRunner.runDetailSubtree": {
27078
+ capName: "pipeline-runner",
27079
+ capScope: "system",
27080
+ addonId: null,
27081
+ access: "create"
27082
+ },
27027
27083
  "plateGallery.correctPlateText": {
27028
27084
  capName: "plate-gallery",
27029
27085
  capScope: "system",
@@ -1,5 +1,5 @@
1
1
  import type { FrameResult, AudioResult } from '../types/detection.js';
2
- import type { PipelineExecutionTrace } from '../types/pipeline-step.js';
2
+ import type { PipelineExecutionTrace, StepCadence } from '../types/pipeline-step.js';
3
3
  import type { MotionRegion } from '../capabilities/motion-detection.cap.js';
4
4
  import type { CameraPipelineConfig } from '../types/camera-pipeline.js';
5
5
  import type { CameraMetrics } from './api-shared.js';
@@ -120,6 +120,18 @@ export interface DetectionResultPayload {
120
120
  readonly capturedAt?: number;
121
121
  [key: string]: unknown;
122
122
  }
123
+ /**
124
+ * Child steps enabled for a camera + their scheduling policy, as read
125
+ * from the pipeline catalog. Announced on `PipelineInferenceResultPayload`
126
+ * so a track-level consumer knows which detail-subtree steps it can
127
+ * dispatch via `pipelineRunner.runDetailSubtree` and on what cadence,
128
+ * without a separate round-trip to the executor's schema/config caps.
129
+ */
130
+ export interface DetailStepAnnounce {
131
+ readonly stepId: string;
132
+ readonly inputClasses: readonly string[];
133
+ readonly cadence: StepCadence;
134
+ }
123
135
  /**
124
136
  * Raw inference output emitted by `addon-pipeline-runner` per detection
125
137
  * frame. Carries the FrameResult produced by the runner — the hub-side
@@ -145,6 +157,8 @@ export interface PipelineInferenceResultPayload {
145
157
  * → delivery latency. Undefined when the frame carried no capture stamp.
146
158
  */
147
159
  readonly capturedAt?: number;
160
+ /** Child steps enabled for this camera + their scheduling policy (from the catalog). */
161
+ readonly detailSteps?: readonly DetailStepAnnounce[];
148
162
  readonly [key: string]: unknown;
149
163
  }
150
164
  /**
@@ -1,4 +1,5 @@
1
1
  import type { PipelineEngineChoice, PipelineConfig } from '../types/pipeline.js';
2
+ import type { PipelineExecutionPlane } from '../types/pipeline-step.js';
2
3
  import type { PipelineSchema, PipelineDefaultStep, PipelineTemplateStep, PipelineTemplate } from '../types/pipeline-schema.js';
3
4
  import type { ModelFormat } from '../types/models.js';
4
5
  import type { FrameInput } from '../types/io.js';
@@ -65,6 +66,14 @@ export interface PipelineRunInput {
65
66
  * that omit this field get a generated id.
66
67
  */
67
68
  readonly sessionId?: string;
69
+ /**
70
+ * Execution plane. 'full' (default) runs the whole tree — benchmark,
71
+ * reference-image, and detail-subtree calls. 'frame' is the live
72
+ * per-frame dispatch: ONLY root-plane steps run; crop children
73
+ * (inputClasses ≠ null) are skipped and served per-track via
74
+ * pipelineRunner.runDetailSubtree (two-plane design).
75
+ */
76
+ readonly plane?: PipelineExecutionPlane;
68
77
  }
69
78
  /**
70
79
  * Singleton capability provided by the pipeline-executor addon.
@@ -166,4 +166,12 @@ export interface IPipelineRunnerProvider {
166
166
  } & CameraMetrics>;
167
167
  /** List the deviceIds currently attached to this runner. */
168
168
  getLocalCameras(): readonly number[];
169
+ /**
170
+ * Two-plane design: run the DETAIL subtree (crop children — embedding,
171
+ * classifier, refiner steps whose `inputClasses !== null`) for a single
172
+ * tracked detection. See `pipelineRunnerCapability.runDetailSubtree`
173
+ * (`capabilities/pipeline-runner.cap.ts`) for full semantics. Returns
174
+ * `null` when neither `frameHandle` nor `cropJpeg` resolves to a crop.
175
+ */
176
+ runDetailSubtree(input: import('../capabilities/pipeline-runner.cap.js').RunDetailSubtreeInput): Promise<import('../capabilities/pipeline-runner.cap.js').RunDetailSubtreeResult | null>;
169
177
  }
@@ -3626,7 +3626,8 @@ function createDeviceProxy(api, binding, opts) {
3626
3626
  },
3627
3627
  pipelineRunner: {
3628
3628
  detachCamera: (input) => dispatchSystem("pipelineRunner", "detachCamera", "mutation", input),
3629
- getCameraMetrics: (input) => dispatchSystem("pipelineRunner", "getCameraMetrics", "query", input)
3629
+ getCameraMetrics: (input) => dispatchSystem("pipelineRunner", "getCameraMetrics", "query", input),
3630
+ runDetailSubtree: (input) => dispatchSystem("pipelineRunner", "runDetailSubtree", "mutation", input)
3630
3631
  },
3631
3632
  plateGallery: {
3632
3633
  listPlates: (input) => dispatchSystem("plateGallery", "listPlates", "query", input),
@@ -3626,7 +3626,8 @@ function createDeviceProxy(api, binding, opts) {
3626
3626
  },
3627
3627
  pipelineRunner: {
3628
3628
  detachCamera: (input) => dispatchSystem("pipelineRunner", "detachCamera", "mutation", input),
3629
- getCameraMetrics: (input) => dispatchSystem("pipelineRunner", "getCameraMetrics", "query", input)
3629
+ getCameraMetrics: (input) => dispatchSystem("pipelineRunner", "getCameraMetrics", "query", input),
3630
+ runDetailSubtree: (input) => dispatchSystem("pipelineRunner", "runDetailSubtree", "mutation", input)
3630
3631
  },
3631
3632
  plateGallery: {
3632
3633
  listPlates: (input) => dispatchSystem("plateGallery", "listPlates", "query", input),
@@ -206,6 +206,18 @@ export interface ObjectDetection extends DetectionBase {
206
206
  /** Model id that produced `embedding` (e.g. `arcface-r100`). Present iff
207
207
  * `embedding` is present — lets consumers skip samples from a stale model. */
208
208
  readonly embeddingModelId?: string;
209
+ /**
210
+ * The EXACT landmark-aligned crop (base64-encoded JPEG) that a face-embedding
211
+ * step fed to the recognizer for THIS `face` detail — i.e. the literal ArcFace
212
+ * model input the `embedding` above was computed from. Present iff an aligned
213
+ * crop was produced (a `faceAlignment` model ran with ≥5 landmarks); absent on
214
+ * the plain-crop fallback and on non-face detections. Lets a gallery display
215
+ * the true embedded crop (1:1 with the embedding, for match debugging) instead
216
+ * of a separately captured natural crop. Small (a 112² JPEG), cheap to carry on
217
+ * the face detail. Only the `face` detail carries it — it is NOT inherited onto
218
+ * the parent person (the person box is not the ArcFace input).
219
+ */
220
+ readonly faceAlignedCrop?: string;
209
221
  }
210
222
  /** Audio detection — flat, time-localised within the window. */
211
223
  export interface AudioDetection extends DetectionBase {
@@ -82,6 +82,28 @@ export interface StepDefinition {
82
82
  * detected with score ≥ 0.7. Configurable per-step via settings.
83
83
  */
84
84
  readonly defaultMinParentScore?: number;
85
+ /**
86
+ * Detail-subtree dispatch cadence — how often a track-level consumer
87
+ * should invoke `pipelineRunner.runDetailSubtree` for this step. Only
88
+ * meaningful for child steps (`inputClasses !== null`); root steps
89
+ * (object-detection, audio-classifier) run on every frame instead and
90
+ * ignore this field. Absent on a child step falls back to the catalog
91
+ * builder's default (`{ trigger: 'once', maxPerTrack: 3 }` — see
92
+ * `PipelineStepBase` in `addon-pipeline`'s step-definitions.ts).
93
+ */
94
+ readonly cadence?: StepCadence;
95
+ }
96
+ /**
97
+ * Scheduling policy for a detail-subtree step, shared by
98
+ * `StepDefinition.cadence` (the catalog authority) and
99
+ * `DetailStepAnnounce.cadence` (the per-camera announce derived from it —
100
+ * see `interfaces/event-bus.ts`).
101
+ */
102
+ export interface StepCadence {
103
+ readonly trigger: 'once' | 'improve' | 'periodic';
104
+ readonly minIntervalMs?: number;
105
+ readonly maxPerTrack?: number;
106
+ readonly stickyOnConfidence?: number;
85
107
  }
86
108
  export interface PoolModelConfig {
87
109
  /** Absolute path to the model file (.mlpackage, .xml, .onnx) */
@@ -158,8 +180,17 @@ export interface MaskOutput {
158
180
  /** Discriminated union for step output — use switch(output.kind) */
159
181
  export type StepOutput = DetectionsOutput | ClassificationsOutput | EmbeddingOutput | TextOutput | MaskOutput;
160
182
  export type TraceVerbosity = 'off' | 'summary' | 'full';
183
+ /**
184
+ * Execution plane for a pipeline run (two-plane design). `'full'` (default)
185
+ * runs the whole tree — benchmark, reference-image, and detail-subtree
186
+ * calls. `'frame'` is the live per-frame dispatch: ONLY root-plane steps
187
+ * (`StepDefinition.inputClasses === null`) run; crop children are skipped
188
+ * and served per-track via a separate detail-subtree call instead.
189
+ */
190
+ export type PipelineExecutionPlane = 'full' | 'frame';
161
191
  export interface PipelineRunOptions {
162
192
  readonly traceVerbosity?: TraceVerbosity;
193
+ readonly plane?: PipelineExecutionPlane;
163
194
  }
164
195
  export interface StepTrace {
165
196
  readonly stepId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.1.42",
3
+ "version": "1.1.43",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",