@trillboards/edge-sdk 0.2.4 → 0.2.6

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 (200) hide show
  1. package/README.md +4 -3
  2. package/deploy/docker/Dockerfile.cloud-sense +117 -0
  3. package/deploy/docker/Dockerfile.cpu +30 -21
  4. package/deploy/docker/Dockerfile.cuda +30 -21
  5. package/deploy/docker/Dockerfile.openvino +30 -20
  6. package/deploy/docker/README.md +9 -4
  7. package/deploy/docker/connector-entrypoint.sh +122 -0
  8. package/deploy/helm/README.md +1 -1
  9. package/deploy/k8s/daemonset.yaml +1 -1
  10. package/deploy/macos/README.md +161 -0
  11. package/deploy/macos/TrillboardsSetupApp.m +603 -0
  12. package/deploy/macos/build-macos-pkg.sh +588 -0
  13. package/deploy/macos/com.trillboards.edge.plist +62 -0
  14. package/deploy/macos/com.trillboards.litertlm.plist +45 -0
  15. package/deploy/macos/pair.command +519 -0
  16. package/deploy/macos/scripts/ensure-litertlm.sh +62 -0
  17. package/deploy/macos/scripts/postinstall +153 -0
  18. package/deploy/macos/scripts/setup-litertlm.sh +272 -0
  19. package/deploy/macos/test-install-pair.sh +383 -0
  20. package/deploy/macos/test-setup-litertlm-reinstall.sh +109 -0
  21. package/deploy/systemd/install.sh +25 -15
  22. package/deploy/systemd/trillboards-edge.service +4 -1
  23. package/deploy/windows/README.md +70 -0
  24. package/deploy/windows/build-windows.ps1 +225 -0
  25. package/deploy/windows/bundle-windows-installer.ps1 +153 -0
  26. package/deploy/windows/check-feeds.js +26 -0
  27. package/deploy/windows/e2e/fixtures/person.jpg +0 -0
  28. package/deploy/windows/e2e/test-local-sense.ps1 +185 -0
  29. package/deploy/windows/install-update.ps1 +101 -0
  30. package/deploy/windows/installer.nsi +138 -0
  31. package/deploy/windows/register-litertlm-task.ps1 +42 -0
  32. package/deploy/windows/register-task.ps1 +44 -0
  33. package/deploy/windows/run-connector.ps1 +69 -0
  34. package/deploy/windows/setup-litertlm.ps1 +361 -0
  35. package/deploy/windows/stop-existing.ps1 +72 -0
  36. package/deploy/windows/trillboards-edge-task.vbs +25 -0
  37. package/deploy/windows/trillboards-edge.cmd +33 -0
  38. package/deploy/windows/trillboards-pair.cmd +276 -0
  39. package/deploy/windows/trillboards-setup.ps1 +456 -0
  40. package/deploy/windows/trillboards-setup.vbs +13 -0
  41. package/dist/AudienceAnalyzeClient.d.ts +136 -0
  42. package/dist/AudienceAnalyzeClient.d.ts.map +1 -0
  43. package/dist/AudienceAnalyzeClient.js +246 -0
  44. package/dist/AudienceAnalyzeClient.js.map +1 -0
  45. package/dist/ChannelProber.d.ts +150 -0
  46. package/dist/ChannelProber.d.ts.map +1 -0
  47. package/dist/ChannelProber.js +887 -0
  48. package/dist/ChannelProber.js.map +1 -0
  49. package/dist/CloudEscalationPolicy.d.ts +143 -0
  50. package/dist/CloudEscalationPolicy.d.ts.map +1 -0
  51. package/dist/CloudEscalationPolicy.js +137 -0
  52. package/dist/CloudEscalationPolicy.js.map +1 -0
  53. package/dist/CloudSensingManager.d.ts +533 -0
  54. package/dist/CloudSensingManager.d.ts.map +1 -0
  55. package/dist/CloudSensingManager.js +1254 -0
  56. package/dist/CloudSensingManager.js.map +1 -0
  57. package/dist/DiscoveryReportClient.d.ts +66 -0
  58. package/dist/DiscoveryReportClient.d.ts.map +1 -0
  59. package/dist/DiscoveryReportClient.js +85 -0
  60. package/dist/DiscoveryReportClient.js.map +1 -0
  61. package/dist/EdgeAgent.d.ts +12 -2
  62. package/dist/EdgeAgent.d.ts.map +1 -1
  63. package/dist/EdgeAgent.js +55 -13
  64. package/dist/EdgeAgent.js.map +1 -1
  65. package/dist/LiteRtVlmProvider.d.ts +193 -0
  66. package/dist/LiteRtVlmProvider.d.ts.map +1 -0
  67. package/dist/LiteRtVlmProvider.js +436 -0
  68. package/dist/LiteRtVlmProvider.js.map +1 -0
  69. package/dist/MosaicSource.d.ts +108 -0
  70. package/dist/MosaicSource.d.ts.map +1 -0
  71. package/dist/MosaicSource.js +274 -0
  72. package/dist/MosaicSource.js.map +1 -0
  73. package/dist/OnvifClient.d.ts +83 -0
  74. package/dist/OnvifClient.d.ts.map +1 -0
  75. package/dist/OnvifClient.js +209 -0
  76. package/dist/OnvifClient.js.map +1 -0
  77. package/dist/PairClient.d.ts +106 -0
  78. package/dist/PairClient.d.ts.map +1 -0
  79. package/dist/PairClient.js +186 -0
  80. package/dist/PairClient.js.map +1 -0
  81. package/dist/RecorderAddressRecovery.d.ts +53 -0
  82. package/dist/RecorderAddressRecovery.d.ts.map +1 -0
  83. package/dist/RecorderAddressRecovery.js +359 -0
  84. package/dist/RecorderAddressRecovery.js.map +1 -0
  85. package/dist/SceneChangeDetector.d.ts +291 -0
  86. package/dist/SceneChangeDetector.d.ts.map +1 -0
  87. package/dist/SceneChangeDetector.js +682 -0
  88. package/dist/SceneChangeDetector.js.map +1 -0
  89. package/dist/SensingProfileClient.d.ts +59 -0
  90. package/dist/SensingProfileClient.d.ts.map +1 -0
  91. package/dist/SensingProfileClient.js +78 -0
  92. package/dist/SensingProfileClient.js.map +1 -0
  93. package/dist/SetupSessionClient.d.ts +114 -0
  94. package/dist/SetupSessionClient.d.ts.map +1 -0
  95. package/dist/SetupSessionClient.js +95 -0
  96. package/dist/SetupSessionClient.js.map +1 -0
  97. package/dist/VlmAdmissionGate.d.ts +126 -0
  98. package/dist/VlmAdmissionGate.d.ts.map +1 -0
  99. package/dist/VlmAdmissionGate.js +166 -0
  100. package/dist/VlmAdmissionGate.js.map +1 -0
  101. package/dist/autoSense.d.ts +216 -0
  102. package/dist/autoSense.d.ts.map +1 -0
  103. package/dist/autoSense.js +521 -0
  104. package/dist/autoSense.js.map +1 -0
  105. package/dist/cli.d.ts +27 -1
  106. package/dist/cli.d.ts.map +1 -1
  107. package/dist/cli.js +511 -21
  108. package/dist/cli.js.map +1 -1
  109. package/dist/combinedSense.d.ts +128 -0
  110. package/dist/combinedSense.d.ts.map +1 -0
  111. package/dist/combinedSense.js +261 -0
  112. package/dist/combinedSense.js.map +1 -0
  113. package/dist/config.d.ts +351 -0
  114. package/dist/config.d.ts.map +1 -1
  115. package/dist/config.js +99 -2
  116. package/dist/config.js.map +1 -1
  117. package/dist/connectorCadence.d.ts +135 -0
  118. package/dist/connectorCadence.d.ts.map +1 -0
  119. package/dist/connectorCadence.js +151 -0
  120. package/dist/connectorCadence.js.map +1 -0
  121. package/dist/dataDir.d.ts +33 -0
  122. package/dist/dataDir.d.ts.map +1 -0
  123. package/dist/dataDir.js +76 -0
  124. package/dist/dataDir.js.map +1 -0
  125. package/dist/deployedCadence.d.ts +167 -0
  126. package/dist/deployedCadence.d.ts.map +1 -0
  127. package/dist/deployedCadence.js +209 -0
  128. package/dist/deployedCadence.js.map +1 -0
  129. package/dist/deployedCadenceSource.d.ts +48 -0
  130. package/dist/deployedCadenceSource.d.ts.map +1 -0
  131. package/dist/deployedCadenceSource.js +74 -0
  132. package/dist/deployedCadenceSource.js.map +1 -0
  133. package/dist/diagnose.d.ts +1 -1
  134. package/dist/diagnose.d.ts.map +1 -1
  135. package/dist/diagnose.js +13 -12
  136. package/dist/diagnose.js.map +1 -1
  137. package/dist/discovery.d.ts +131 -0
  138. package/dist/discovery.d.ts.map +1 -0
  139. package/dist/discovery.js +499 -0
  140. package/dist/discovery.js.map +1 -0
  141. package/dist/gemmaModelOta.d.ts +118 -0
  142. package/dist/gemmaModelOta.d.ts.map +1 -0
  143. package/dist/gemmaModelOta.js +291 -0
  144. package/dist/gemmaModelOta.js.map +1 -0
  145. package/dist/index.d.ts +16 -1
  146. package/dist/index.d.ts.map +1 -1
  147. package/dist/index.js +40 -1
  148. package/dist/index.js.map +1 -1
  149. package/dist/init.d.ts.map +1 -1
  150. package/dist/init.js +41 -18
  151. package/dist/init.js.map +1 -1
  152. package/dist/keepAwake.d.ts +33 -0
  153. package/dist/keepAwake.d.ts.map +1 -0
  154. package/dist/keepAwake.js +54 -0
  155. package/dist/keepAwake.js.map +1 -0
  156. package/dist/legacyRecorderProfile.d.ts +20 -0
  157. package/dist/legacyRecorderProfile.d.ts.map +1 -0
  158. package/dist/legacyRecorderProfile.js +27 -0
  159. package/dist/legacyRecorderProfile.js.map +1 -0
  160. package/dist/localInferenceSchema.d.ts +132 -0
  161. package/dist/localInferenceSchema.d.ts.map +1 -0
  162. package/dist/localInferenceSchema.js +274 -0
  163. package/dist/localInferenceSchema.js.map +1 -0
  164. package/dist/localSenseE2eHarness.d.ts +101 -0
  165. package/dist/localSenseE2eHarness.d.ts.map +1 -0
  166. package/dist/localSenseE2eHarness.js +279 -0
  167. package/dist/localSenseE2eHarness.js.map +1 -0
  168. package/dist/localSensing.d.ts +268 -0
  169. package/dist/localSensing.d.ts.map +1 -0
  170. package/dist/localSensing.js +492 -0
  171. package/dist/localSensing.js.map +1 -0
  172. package/dist/modelIntegrity.d.ts +59 -0
  173. package/dist/modelIntegrity.d.ts.map +1 -0
  174. package/dist/modelIntegrity.js +165 -0
  175. package/dist/modelIntegrity.js.map +1 -0
  176. package/dist/pairVerify.d.ts +100 -0
  177. package/dist/pairVerify.d.ts.map +1 -0
  178. package/dist/pairVerify.js +296 -0
  179. package/dist/pairVerify.js.map +1 -0
  180. package/dist/qrScanner.d.ts +33 -0
  181. package/dist/qrScanner.d.ts.map +1 -0
  182. package/dist/qrScanner.js +103 -0
  183. package/dist/qrScanner.js.map +1 -0
  184. package/dist/runtimePaths.d.ts +10 -0
  185. package/dist/runtimePaths.d.ts.map +1 -0
  186. package/dist/runtimePaths.js +79 -0
  187. package/dist/runtimePaths.js.map +1 -0
  188. package/dist/sensingRunMode.d.ts +68 -0
  189. package/dist/sensingRunMode.d.ts.map +1 -0
  190. package/dist/sensingRunMode.js +346 -0
  191. package/dist/sensingRunMode.js.map +1 -0
  192. package/dist/setupMode.d.ts +98 -0
  193. package/dist/setupMode.d.ts.map +1 -0
  194. package/dist/setupMode.js +828 -0
  195. package/dist/setupMode.js.map +1 -0
  196. package/dist/setupProgress.d.ts +31 -0
  197. package/dist/setupProgress.d.ts.map +1 -0
  198. package/dist/setupProgress.js +173 -0
  199. package/dist/setupProgress.js.map +1 -0
  200. package/package.json +13 -4
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ /**
3
+ * VlmAdmissionGate — the connector's port of the Android
4
+ * `VlmFrameAdmissionGate` (agent-core `inference/vlm/VlmFrameAdmissionGate.kt`).
5
+ *
6
+ * WHY THIS EXISTS. `litert-lm serve` is a SINGLE-CONVERSATION server: it
7
+ * processes one chat completion at a time. `CloudSensingManager` fans out one
8
+ * independent timer loop per feed, and those loops free-run — at 16 cameras on
9
+ * the 30 s cadence that is ~32 inference requests/minute arriving at a server
10
+ * that sustains 2–10/minute. Without a gate the surplus does not queue
11
+ * politely: the requests pile onto one serve instance, frames age against the
12
+ * provider's 120 s HTTP timeout, and every timeout burns up to 3 retry
13
+ * attempts (`LiteRtVlmProvider` maxAttempts). The machine spends its whole
14
+ * budget re-asking about frames that are already minutes stale.
15
+ *
16
+ * THE ANDROID SEMANTICS, MIRRORED (not reinvented):
17
+ * - a bounded number of in-flight slots (ONE, sized to the serve's real
18
+ * concurrency; `maxInFlight` exists so a genuinely concurrent backend can
19
+ * be sized up, never guessed up);
20
+ * - `minIntervalMs` — a global pacing floor between admissions;
21
+ * - stale recovery at `maxInFlightMs` — a slot whose holder vanished (a
22
+ * crashed provider, a socket that never resolved) is reclaimed rather than
23
+ * wedging sensing forever on an unattended 24/7 connector;
24
+ * - DROP, never queue. A stale frame is worthless: by the time a queued frame
25
+ * reached the model the scene has moved on. The caller is told "no" and
26
+ * tries again on its next tick.
27
+ *
28
+ * WHAT DIFFERS FROM ANDROID, AND WHY. Android has exactly one camera, so its
29
+ * gate is a bare boolean. The connector has N feeds sharing ONE serve, so
30
+ * admission must be attributable: every acquire/deny is counted per feed, which
31
+ * is what makes "camera 12 is being starved" observable instead of invisible.
32
+ * Acquire returns a TICKET rather than a bare boolean so a late release from a
33
+ * call whose slot was already reclaimed as stale cannot free somebody else's
34
+ * slot.
35
+ *
36
+ * THREADING. Node is single-threaded and `tryAcquire`/`release` never await, so
37
+ * the whole body is one critical section by construction — the Kotlin
38
+ * `@Synchronized` has no counterpart to write.
39
+ */
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.VlmAdmissionGate = void 0;
42
+ const DEFAULT_MAX_IN_FLIGHT = 1;
43
+ const DEFAULT_MAX_IN_FLIGHT_MS = 180000;
44
+ class VlmAdmissionGate {
45
+ constructor(options = {}) {
46
+ this.inFlight = new Set();
47
+ this.nextAllowedAtMs = 0;
48
+ this.admitted = 0;
49
+ this.droppedInFlight = 0;
50
+ this.droppedMinInterval = 0;
51
+ this.staleReclaimed = 0;
52
+ this.lateReleases = 0;
53
+ this.perFeed = new Map();
54
+ this.maxInFlight = Math.max(1, Math.trunc(options.maxInFlight ?? DEFAULT_MAX_IN_FLIGHT));
55
+ this.minIntervalMs = Math.max(0, Math.trunc(options.minIntervalMs ?? 0));
56
+ this.maxInFlightMs = Math.max(0, Math.trunc(options.maxInFlightMs ?? DEFAULT_MAX_IN_FLIGHT_MS));
57
+ this.now = options.now ?? Date.now;
58
+ }
59
+ /** Slots this gate will ever hand out at once. */
60
+ getMaxInFlight() {
61
+ return this.maxInFlight;
62
+ }
63
+ /** Slots currently held (after reclaiming any stale ones). */
64
+ getInFlight(nowMs) {
65
+ this.reclaimStale(nowMs ?? this.now());
66
+ return this.inFlight.size;
67
+ }
68
+ /**
69
+ * Try to take a slot for `name`. Returns a ticket on admission, `null` on a
70
+ * DROP — the caller must abandon this frame, not hold it. Never blocks.
71
+ */
72
+ tryAcquire(name, nowMs) {
73
+ const now = nowMs ?? this.now();
74
+ this.reclaimStale(now);
75
+ const feed = this.feedStats(name);
76
+ if (this.inFlight.size >= this.maxInFlight) {
77
+ this.droppedInFlight++;
78
+ feed.dropped++;
79
+ return null;
80
+ }
81
+ if (now < this.nextAllowedAtMs) {
82
+ this.droppedMinInterval++;
83
+ feed.dropped++;
84
+ return null;
85
+ }
86
+ const ticket = { name, acquiredAtMs: now };
87
+ this.inFlight.add(ticket);
88
+ this.nextAllowedAtMs = now + this.minIntervalMs;
89
+ this.admitted++;
90
+ feed.admitted++;
91
+ feed.lastAdmittedAtMs = now;
92
+ return ticket;
93
+ }
94
+ /**
95
+ * Give a slot back. Idempotent, and a no-op for a ticket already reclaimed as
96
+ * stale (counted as a late release so the reclaim threshold stays auditable).
97
+ */
98
+ release(ticket) {
99
+ if (!ticket)
100
+ return;
101
+ if (!this.inFlight.delete(ticket)) {
102
+ this.lateReleases++;
103
+ }
104
+ }
105
+ /** Age (ms) of the oldest held slot, or null when idle. */
106
+ oldestInFlightAgeMs(nowMs) {
107
+ const now = nowMs ?? this.now();
108
+ let oldest = null;
109
+ for (const t of this.inFlight) {
110
+ const age = Math.max(0, now - t.acquiredAtMs);
111
+ if (oldest === null || age > oldest)
112
+ oldest = age;
113
+ }
114
+ return oldest;
115
+ }
116
+ /** Drop every slot and counter (a stop()/start() cycle starts clean). */
117
+ reset() {
118
+ this.inFlight.clear();
119
+ this.nextAllowedAtMs = 0;
120
+ this.admitted = 0;
121
+ this.droppedInFlight = 0;
122
+ this.droppedMinInterval = 0;
123
+ this.staleReclaimed = 0;
124
+ this.lateReleases = 0;
125
+ this.perFeed.clear();
126
+ }
127
+ getStats(nowMs) {
128
+ this.reclaimStale(nowMs ?? this.now());
129
+ return {
130
+ maxInFlight: this.maxInFlight,
131
+ inFlight: this.inFlight.size,
132
+ admitted: this.admitted,
133
+ droppedInFlight: this.droppedInFlight,
134
+ droppedMinInterval: this.droppedMinInterval,
135
+ staleReclaimed: this.staleReclaimed,
136
+ lateReleases: this.lateReleases,
137
+ perFeed: [...this.perFeed.values()].map((f) => ({ ...f })),
138
+ };
139
+ }
140
+ // ─── Private ────────────────────────────────────────────────────────────────
141
+ feedStats(name) {
142
+ let feed = this.perFeed.get(name);
143
+ if (!feed) {
144
+ feed = { name, admitted: 0, dropped: 0, lastAdmittedAtMs: null };
145
+ this.perFeed.set(name, feed);
146
+ }
147
+ return feed;
148
+ }
149
+ /**
150
+ * Free slots whose holder has exceeded `maxInFlightMs` — the Kotlin gate's
151
+ * stale branch. A wedged slot on a 24/7 unattended connector is indefinite
152
+ * blindness, so the gate self-heals rather than waiting for a restart.
153
+ */
154
+ reclaimStale(nowMs) {
155
+ if (this.maxInFlightMs <= 0 || this.inFlight.size === 0)
156
+ return;
157
+ for (const t of this.inFlight) {
158
+ if (nowMs - t.acquiredAtMs > this.maxInFlightMs) {
159
+ this.inFlight.delete(t);
160
+ this.staleReclaimed++;
161
+ }
162
+ }
163
+ }
164
+ }
165
+ exports.VlmAdmissionGate = VlmAdmissionGate;
166
+ //# sourceMappingURL=VlmAdmissionGate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VlmAdmissionGate.js","sourceRoot":"","sources":["../src/VlmAdmissionGate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,216 @@
1
+ import { type EdgeAgentConfig } from './config';
2
+ import { type SensingManager } from './sensingRunMode';
3
+ import { type GemmaModelOtaHandle } from './gemmaModelOta';
4
+ /** The outcome of a LiteRT-LM health probe (consumed by the mode selector). */
5
+ export interface LiteRtHealthResult {
6
+ /** True iff litert-lm answered the readiness check with a usable response. */
7
+ ok: boolean;
8
+ /** Human-readable reason (logged so support can diagnose a fallback). */
9
+ reason: string;
10
+ /** Round-trip latency of the probe in ms (best-effort; present on success). */
11
+ latencyMs?: number;
12
+ /** HTTP status the probe observed, when it got a response at all. */
13
+ statusCode?: number;
14
+ }
15
+ /** Minimal injectable HTTP GET — lets tests stub litert-lm entirely (no network). */
16
+ export interface HttpGetter {
17
+ (url: string, options: {
18
+ timeoutMs: number;
19
+ }): Promise<{
20
+ statusCode: number;
21
+ body: string;
22
+ }>;
23
+ }
24
+ /**
25
+ * Probe `litert-lm serve` for reachability + readiness via `GET {base}/v1/models`
26
+ * (the OpenAI-compatible model list — cheap, present on a healthy serve, and a
27
+ * de-facto health endpoint). A 2xx with a parseable model list THAT INCLUDES THE
28
+ * MODEL the local-sense path will actually use is "healthy"; anything else
29
+ * (connection refused, timeout, non-2xx, empty/garbage body, OR a serve hosting
30
+ * a DIFFERENT model than configured) is "unhealthy" so the caller degrades to
31
+ * cloud.
32
+ *
33
+ * Why match the model (not just "non-empty list"): the local path posts inference
34
+ * to `config.localSensing.model` (default gemma-4-E2B-it.litertlm). A serve that
35
+ * is up but hosting a DIFFERENT model id would make auto-sense pick local and
36
+ * then fail EVERY frame — exactly the hard-fail this entrypoint exists to avoid.
37
+ * So we require the expected model to be present. (`expectedModel` omitted → fall
38
+ * back to "any non-empty list", e.g. for a pure reachability check.)
39
+ *
40
+ * Built-in http/https only (no extra dependency → survives bundling into the
41
+ * self-contained connector; trivially mockable in tests). Never throws.
42
+ */
43
+ export declare function probeLiteRtLmHealth(baseUrl?: string, opts?: {
44
+ timeoutMs?: number;
45
+ httpGetter?: HttpGetter;
46
+ expectedModel?: string;
47
+ }): Promise<LiteRtHealthResult>;
48
+ /** A timer handle the supervisor sets for its re-probe loop (injectable in tests). */
49
+ export type AutoSenseTimerHandle = ReturnType<typeof setTimeout>;
50
+ /** Which sensing path the supervisor is currently running. */
51
+ export type SensingMode = 'local' | 'cloud';
52
+ export type AutoSenseState = SensingMode | 'waiting';
53
+ /**
54
+ * Everything the AutoSenseSupervisor needs, all injectable so the supervisor can
55
+ * be unit-tested with a fake probe + fake managers. `runAutoSense` builds this
56
+ * from config + the real probe/managers/timers.
57
+ */
58
+ export interface AutoSenseSupervisorDeps {
59
+ /** Probe litert-lm, already bound to the resolved base URL / timeout / model. */
60
+ probe: () => Promise<LiteRtHealthResult>;
61
+ /** Build (NOT start) the local-sensing manager. `null` ⇒ no feeds (fatal). */
62
+ buildLocalManager: () => SensingManager | null;
63
+ /** Build (NOT start) the cloud-sensing manager. `null` ⇒ no feeds (fatal). */
64
+ buildCloudManager: () => SensingManager | null;
65
+ /** Log sink (tests capture it). */
66
+ log: (msg: string) => void;
67
+ /** Sleep between startup re-probes (tests inject a no-op). */
68
+ sleep: (ms: number) => Promise<void>;
69
+ /** Arm the steady-state re-probe timer (tests inject a controllable fake). */
70
+ setTimer: (cb: () => void, ms: number) => AutoSenseTimerHandle;
71
+ /** Clear the re-probe timer (tests assert this on shutdown). */
72
+ clearTimer: (handle: AutoSenseTimerHandle) => void;
73
+ /** Called when the chosen mode has NO feeds (fatal config error; default exits 1). */
74
+ onNoFeeds: () => void;
75
+ /** Called after LOCAL sensing starts. Used to defer model OTA until initial provisioning is complete. */
76
+ onLocalActivated?: () => void;
77
+ /** Bounded startup re-probe attempts before committing to the initial mode. */
78
+ startupAttempts: number;
79
+ /** Delay (ms) between startup re-probes. */
80
+ startupBackoffMs: number;
81
+ /** Steady-state re-probe interval (ms), already floored. */
82
+ recheckIntervalMs: number;
83
+ /** Consecutive unhealthy re-probes required before a LOCAL→CLOUD fallback. */
84
+ unhealthyChecksBeforeFallback: number;
85
+ /** Cloud inference is opt-in because continuous CCTV cloud load is expensive. */
86
+ allowCloudFallback: boolean;
87
+ /** For the initial "probing…" log line. */
88
+ litertLmBaseUrl: string;
89
+ expectedModel: string;
90
+ probeTimeoutMs: number;
91
+ }
92
+ /**
93
+ * The `auto-sense` SUPERVISOR. Instead of probing once and then blocking forever
94
+ * on a single manager (the old behavior — mode FIXED for the whole process run,
95
+ * "restart to re-probe"), it OWNS the sensing lifecycle so the connector always
96
+ * prefers on-device Gemma and switches automatically with NO restart:
97
+ *
98
+ * - startInitial(): bounded startup re-probe → start the chosen path's REAL
99
+ * manager directly when litert-lm is healthy; otherwise wait locally unless
100
+ * cloud fallback was explicitly enabled.
101
+ * - beginRechecks(): a steady-state background re-probe loop on recheckIntervalMs.
102
+ * - recheck(): one tick — AUTO-UPGRADE cloud→local the instant local is ready
103
+ * (fixes the fresh-install race with zero restart). Explicit cloud-fallback
104
+ * installs may also recover local→cloud after K unhealthy probes.
105
+ * - shutdown(): stop the active manager + clear the timer (SIGINT/SIGTERM).
106
+ *
107
+ * At most ONE switch per tick; a re-entrancy guard + the K-debounce mean a
108
+ * flapping health signal can never rapidly toggle managers.
109
+ */
110
+ export declare class AutoSenseSupervisor {
111
+ private readonly deps;
112
+ private mode;
113
+ private active;
114
+ private localManager;
115
+ private cloudManager;
116
+ private consecutiveUnhealthy;
117
+ private timer;
118
+ private switching;
119
+ private stopped;
120
+ constructor(deps: AutoSenseSupervisorDeps);
121
+ /** The active mode (null until startInitial). For tests/observability. */
122
+ get currentMode(): AutoSenseState | null;
123
+ private getManager;
124
+ /**
125
+ * Initial probe (bounded startup re-probe loop for the fresh-install warmup
126
+ * race) → start the chosen path's manager directly. Returns false (after
127
+ * onNoFeeds) when the chosen mode has no feeds configured.
128
+ */
129
+ startInitial(): Promise<boolean>;
130
+ /** Build + start a mode's manager and make it active. False ⇒ no feeds. */
131
+ private activate;
132
+ /** Start the steady-state background re-probe loop. */
133
+ beginRechecks(): void;
134
+ private scheduleNextRecheck;
135
+ /**
136
+ * One background re-probe tick.
137
+ * - While WAITING: a healthy probe starts local sensing immediately.
138
+ * - On CLOUD: any healthy probe → AUTO-UPGRADE to local immediately (running
139
+ * on cloud while local is ready is pure waste; the K-debounce on the return
140
+ * path bounds any toggling, so this is safe on the first healthy probe).
141
+ * - On LOCAL: a healthy probe resets the debounce; an unhealthy probe
142
+ * increments it, and only after K CONSECUTIVE unhealthy probes do we
143
+ * AUTO-RECOVER to cloud only when explicit fallback is enabled.
144
+ * At most one switch per tick; re-entrancy guarded.
145
+ */
146
+ recheck(): Promise<void>;
147
+ /** Stop the active manager, start the target — old.stop() BEFORE new.start(). */
148
+ private switchTo;
149
+ /** SIGINT/SIGTERM: stop the active manager + clear the re-probe timer. Idempotent. */
150
+ shutdown(): Promise<void>;
151
+ }
152
+ /** Injection points for runAutoSense (default to the real probe/managers/timers). */
153
+ export interface AutoSenseDeps {
154
+ /**
155
+ * Probe used to decide local-vs-cloud. Defaults to probeLiteRtLmHealth.
156
+ * Receives the resolved base URL, per-probe timeout, and the model the local
157
+ * path will run (so the probe can require it before declaring local usable).
158
+ */
159
+ probe?: (baseUrl: string, timeoutMs: number, expectedModel: string) => Promise<LiteRtHealthResult>;
160
+ /** Loads the connector config. Defaults to loadConfig. */
161
+ loadConfig?: (configPath: string) => EdgeAgentConfig;
162
+ /** Build (NOT start) the local manager. Defaults to buildLocalSensingManager(config). */
163
+ buildLocalManager?: () => SensingManager | null;
164
+ /** Build (NOT start) the cloud manager. Defaults to buildCloudSensingManager(config). */
165
+ buildCloudManager?: () => SensingManager | null;
166
+ /** Log sink (tests capture it). Defaults to console.log. */
167
+ log?: (msg: string) => void;
168
+ /** Sleep between startup re-probes (tests inject a no-op). Defaults to setTimeout. */
169
+ sleep?: (ms: number) => Promise<void>;
170
+ /** Arm the re-probe timer. Defaults to setTimeout. */
171
+ setTimer?: (cb: () => void, ms: number) => AutoSenseTimerHandle;
172
+ /** Clear the re-probe timer. Defaults to clearTimeout. */
173
+ clearTimer?: (handle: AutoSenseTimerHandle) => void;
174
+ /** Fatal no-feeds handler. Defaults to process.exit(1). */
175
+ onNoFeeds?: () => void;
176
+ /** Register the shutdown handler. Defaults to SIGINT/SIGTERM listeners. */
177
+ registerShutdown?: (handler: () => void | Promise<void>) => void;
178
+ /** Block until shutdown (production never resolves; tests inject a resolved waiter). */
179
+ waitForShutdown?: () => Promise<void>;
180
+ /**
181
+ * Start the on-device VLM (Gemma) OTA watcher. Defaults to startGemmaModelOta.
182
+ * Returns a handle whose stop() runs on shutdown (or null when disabled). It
183
+ * starts only after LOCAL sensing activates, so first-time provisioning owns
184
+ * the initial model download and OTA cannot race it.
185
+ */
186
+ startModelOta?: (config: EdgeAgentConfig) => GemmaModelOtaHandle | null;
187
+ }
188
+ /**
189
+ * `auto-sense` entrypoint: resolve probe + manager inputs from config, then run
190
+ * the AutoSenseSupervisor (probe → start the chosen REAL manager → keep
191
+ * re-probing → auto-upgrade/auto-recover with NO restart). Blocks until
192
+ * SIGINT/SIGTERM (the supervisor's re-probe timer keeps the event loop alive).
193
+ *
194
+ * The probe target is the operator's configured `localSensing.litertLmBaseUrl`
195
+ * (default http://localhost:9379) so a non-standard serve host is honored, and
196
+ * the probe requires the configured `localSensing.model` to be present so we
197
+ * never pick local against a serve hosting the wrong model.
198
+ *
199
+ * Config is REQUIRED to build the sensing managers, so it's loaded up front and a
200
+ * genuine config error propagates to main() (prints + exits 1) — the same net
201
+ * result as before, where the chosen run mode re-loaded the config and reported it.
202
+ *
203
+ * The explicit `local-sense` / `cloud-sense` entrypoints stay non-switching; only
204
+ * `auto-sense` is supervised.
205
+ */
206
+ export declare function runAutoSense(args: string[], deps?: AutoSenseDeps): Promise<void>;
207
+ /**
208
+ * Default transport using Node's built-in http/https. No third-party deps so it
209
+ * survives bundling into the self-contained connector. Mirrors the framing
210
+ * tolerance of LiteRtVlmProvider's poster: litert-lm serve emits non-strict HTTP
211
+ * framing (bare LF on the status line) that Node's strict parser rejects, and
212
+ * the connector talks to a LOCAL, trusted serve, so we tolerate it here too —
213
+ * otherwise a healthy serve would look "unreachable" and we'd wrongly pick cloud.
214
+ */
215
+ export declare const defaultHttpGetter: HttpGetter;
216
+ //# sourceMappingURL=autoSense.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoSense.d.ts","sourceRoot":"","sources":["../src/autoSense.ts"],"names":[],"mappings":"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"}