@trillboards/edge-sdk 0.2.4 → 0.2.7

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 (204) 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 -5
  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-service.ps1 +6 -1
  30. package/deploy/windows/install-update.ps1 +101 -0
  31. package/deploy/windows/installer.nsi +138 -0
  32. package/deploy/windows/register-litertlm-task.ps1 +42 -0
  33. package/deploy/windows/register-task.ps1 +44 -0
  34. package/deploy/windows/run-connector.ps1 +69 -0
  35. package/deploy/windows/setup-litertlm.ps1 +361 -0
  36. package/deploy/windows/stop-existing.ps1 +72 -0
  37. package/deploy/windows/trillboards-edge-task.vbs +25 -0
  38. package/deploy/windows/trillboards-edge.cmd +33 -0
  39. package/deploy/windows/trillboards-pair.cmd +276 -0
  40. package/deploy/windows/trillboards-setup.ps1 +456 -0
  41. package/deploy/windows/trillboards-setup.vbs +13 -0
  42. package/dist/AudienceAnalyzeClient.d.ts +136 -0
  43. package/dist/AudienceAnalyzeClient.d.ts.map +1 -0
  44. package/dist/AudienceAnalyzeClient.js +246 -0
  45. package/dist/AudienceAnalyzeClient.js.map +1 -0
  46. package/dist/ChannelProber.d.ts +150 -0
  47. package/dist/ChannelProber.d.ts.map +1 -0
  48. package/dist/ChannelProber.js +887 -0
  49. package/dist/ChannelProber.js.map +1 -0
  50. package/dist/CloudEscalationPolicy.d.ts +143 -0
  51. package/dist/CloudEscalationPolicy.d.ts.map +1 -0
  52. package/dist/CloudEscalationPolicy.js +137 -0
  53. package/dist/CloudEscalationPolicy.js.map +1 -0
  54. package/dist/CloudSensingManager.d.ts +557 -0
  55. package/dist/CloudSensingManager.d.ts.map +1 -0
  56. package/dist/CloudSensingManager.js +1267 -0
  57. package/dist/CloudSensingManager.js.map +1 -0
  58. package/dist/DiscoveryReportClient.d.ts +66 -0
  59. package/dist/DiscoveryReportClient.d.ts.map +1 -0
  60. package/dist/DiscoveryReportClient.js +85 -0
  61. package/dist/DiscoveryReportClient.js.map +1 -0
  62. package/dist/EdgeAgent.d.ts +12 -2
  63. package/dist/EdgeAgent.d.ts.map +1 -1
  64. package/dist/EdgeAgent.js +55 -13
  65. package/dist/EdgeAgent.js.map +1 -1
  66. package/dist/LiteRtVlmProvider.d.ts +193 -0
  67. package/dist/LiteRtVlmProvider.d.ts.map +1 -0
  68. package/dist/LiteRtVlmProvider.js +436 -0
  69. package/dist/LiteRtVlmProvider.js.map +1 -0
  70. package/dist/MosaicSource.d.ts +108 -0
  71. package/dist/MosaicSource.d.ts.map +1 -0
  72. package/dist/MosaicSource.js +274 -0
  73. package/dist/MosaicSource.js.map +1 -0
  74. package/dist/OnvifClient.d.ts +83 -0
  75. package/dist/OnvifClient.d.ts.map +1 -0
  76. package/dist/OnvifClient.js +209 -0
  77. package/dist/OnvifClient.js.map +1 -0
  78. package/dist/PairClient.d.ts +106 -0
  79. package/dist/PairClient.d.ts.map +1 -0
  80. package/dist/PairClient.js +186 -0
  81. package/dist/PairClient.js.map +1 -0
  82. package/dist/RecorderAddressRecovery.d.ts +53 -0
  83. package/dist/RecorderAddressRecovery.d.ts.map +1 -0
  84. package/dist/RecorderAddressRecovery.js +359 -0
  85. package/dist/RecorderAddressRecovery.js.map +1 -0
  86. package/dist/SceneChangeDetector.d.ts +291 -0
  87. package/dist/SceneChangeDetector.d.ts.map +1 -0
  88. package/dist/SceneChangeDetector.js +682 -0
  89. package/dist/SceneChangeDetector.js.map +1 -0
  90. package/dist/SensingProfileClient.d.ts +59 -0
  91. package/dist/SensingProfileClient.d.ts.map +1 -0
  92. package/dist/SensingProfileClient.js +78 -0
  93. package/dist/SensingProfileClient.js.map +1 -0
  94. package/dist/SetupSessionClient.d.ts +114 -0
  95. package/dist/SetupSessionClient.d.ts.map +1 -0
  96. package/dist/SetupSessionClient.js +95 -0
  97. package/dist/SetupSessionClient.js.map +1 -0
  98. package/dist/VlmAdmissionGate.d.ts +126 -0
  99. package/dist/VlmAdmissionGate.d.ts.map +1 -0
  100. package/dist/VlmAdmissionGate.js +166 -0
  101. package/dist/VlmAdmissionGate.js.map +1 -0
  102. package/dist/autoSense.d.ts +266 -0
  103. package/dist/autoSense.d.ts.map +1 -0
  104. package/dist/autoSense.js +606 -0
  105. package/dist/autoSense.js.map +1 -0
  106. package/dist/cli.d.ts +27 -1
  107. package/dist/cli.d.ts.map +1 -1
  108. package/dist/cli.js +526 -27
  109. package/dist/cli.js.map +1 -1
  110. package/dist/combinedSense.d.ts +128 -0
  111. package/dist/combinedSense.d.ts.map +1 -0
  112. package/dist/combinedSense.js +261 -0
  113. package/dist/combinedSense.js.map +1 -0
  114. package/dist/config.d.ts +351 -0
  115. package/dist/config.d.ts.map +1 -1
  116. package/dist/config.js +99 -2
  117. package/dist/config.js.map +1 -1
  118. package/dist/connectorCadence.d.ts +135 -0
  119. package/dist/connectorCadence.d.ts.map +1 -0
  120. package/dist/connectorCadence.js +151 -0
  121. package/dist/connectorCadence.js.map +1 -0
  122. package/dist/dataDir.d.ts +33 -0
  123. package/dist/dataDir.d.ts.map +1 -0
  124. package/dist/dataDir.js +76 -0
  125. package/dist/dataDir.js.map +1 -0
  126. package/dist/deployedCadence.d.ts +167 -0
  127. package/dist/deployedCadence.d.ts.map +1 -0
  128. package/dist/deployedCadence.js +209 -0
  129. package/dist/deployedCadence.js.map +1 -0
  130. package/dist/deployedCadenceSource.d.ts +48 -0
  131. package/dist/deployedCadenceSource.d.ts.map +1 -0
  132. package/dist/deployedCadenceSource.js +74 -0
  133. package/dist/deployedCadenceSource.js.map +1 -0
  134. package/dist/diagnose.d.ts +1 -1
  135. package/dist/diagnose.d.ts.map +1 -1
  136. package/dist/diagnose.js +15 -13
  137. package/dist/diagnose.js.map +1 -1
  138. package/dist/discovery.d.ts +131 -0
  139. package/dist/discovery.d.ts.map +1 -0
  140. package/dist/discovery.js +499 -0
  141. package/dist/discovery.js.map +1 -0
  142. package/dist/gemmaModelOta.d.ts +118 -0
  143. package/dist/gemmaModelOta.d.ts.map +1 -0
  144. package/dist/gemmaModelOta.js +291 -0
  145. package/dist/gemmaModelOta.js.map +1 -0
  146. package/dist/index.d.ts +16 -1
  147. package/dist/index.d.ts.map +1 -1
  148. package/dist/index.js +40 -1
  149. package/dist/index.js.map +1 -1
  150. package/dist/init.d.ts.map +1 -1
  151. package/dist/init.js +25 -87
  152. package/dist/init.js.map +1 -1
  153. package/dist/keepAwake.d.ts +33 -0
  154. package/dist/keepAwake.d.ts.map +1 -0
  155. package/dist/keepAwake.js +54 -0
  156. package/dist/keepAwake.js.map +1 -0
  157. package/dist/legacyRecorderProfile.d.ts +20 -0
  158. package/dist/legacyRecorderProfile.d.ts.map +1 -0
  159. package/dist/legacyRecorderProfile.js +27 -0
  160. package/dist/legacyRecorderProfile.js.map +1 -0
  161. package/dist/localInferenceSchema.d.ts +132 -0
  162. package/dist/localInferenceSchema.d.ts.map +1 -0
  163. package/dist/localInferenceSchema.js +274 -0
  164. package/dist/localInferenceSchema.js.map +1 -0
  165. package/dist/localSenseE2eHarness.d.ts +101 -0
  166. package/dist/localSenseE2eHarness.d.ts.map +1 -0
  167. package/dist/localSenseE2eHarness.js +279 -0
  168. package/dist/localSenseE2eHarness.js.map +1 -0
  169. package/dist/localSensing.d.ts +284 -0
  170. package/dist/localSensing.d.ts.map +1 -0
  171. package/dist/localSensing.js +512 -0
  172. package/dist/localSensing.js.map +1 -0
  173. package/dist/mcp-server.d.ts.map +1 -1
  174. package/dist/mcp-server.js +3 -1
  175. package/dist/mcp-server.js.map +1 -1
  176. package/dist/modelIntegrity.d.ts +80 -0
  177. package/dist/modelIntegrity.d.ts.map +1 -0
  178. package/dist/modelIntegrity.js +194 -0
  179. package/dist/modelIntegrity.js.map +1 -0
  180. package/dist/pairVerify.d.ts +100 -0
  181. package/dist/pairVerify.d.ts.map +1 -0
  182. package/dist/pairVerify.js +296 -0
  183. package/dist/pairVerify.js.map +1 -0
  184. package/dist/qrScanner.d.ts +33 -0
  185. package/dist/qrScanner.d.ts.map +1 -0
  186. package/dist/qrScanner.js +103 -0
  187. package/dist/qrScanner.js.map +1 -0
  188. package/dist/runtimePaths.d.ts +10 -0
  189. package/dist/runtimePaths.d.ts.map +1 -0
  190. package/dist/runtimePaths.js +79 -0
  191. package/dist/runtimePaths.js.map +1 -0
  192. package/dist/sensingRunMode.d.ts +86 -0
  193. package/dist/sensingRunMode.d.ts.map +1 -0
  194. package/dist/sensingRunMode.js +346 -0
  195. package/dist/sensingRunMode.js.map +1 -0
  196. package/dist/setupMode.d.ts +98 -0
  197. package/dist/setupMode.d.ts.map +1 -0
  198. package/dist/setupMode.js +828 -0
  199. package/dist/setupMode.js.map +1 -0
  200. package/dist/setupProgress.d.ts +31 -0
  201. package/dist/setupProgress.d.ts.map +1 -0
  202. package/dist/setupProgress.js +173 -0
  203. package/dist/setupProgress.js.map +1 -0
  204. 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,266 @@
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
+ /**
118
+ * Completed local analyses as of the previous re-probe. `null` = no baseline
119
+ * yet (not on local, or the manager cannot report it), which reads as "no
120
+ * positive evidence" and leaves the pre-existing behaviour in place.
121
+ */
122
+ private analysesAtLastRecheck;
123
+ private timer;
124
+ private switching;
125
+ private stopped;
126
+ constructor(deps: AutoSenseSupervisorDeps);
127
+ /** The active mode (null until startInitial). For tests/observability. */
128
+ get currentMode(): AutoSenseState | null;
129
+ private getManager;
130
+ /**
131
+ * Initial probe (bounded startup re-probe loop for the fresh-install warmup
132
+ * race) → start the chosen path's manager directly. Returns false (after
133
+ * onNoFeeds) when the chosen mode has no feeds configured.
134
+ */
135
+ startInitial(): Promise<boolean>;
136
+ /** Build + start a mode's manager and make it active. False ⇒ no feeds. */
137
+ private activate;
138
+ /** Start the steady-state background re-probe loop. */
139
+ beginRechecks(): void;
140
+ private scheduleNextRecheck;
141
+ /**
142
+ * How many ON-DEVICE inferences have completed this run. `null` when the
143
+ * manager cannot report it (a test fake, a not-yet-built manager) — which
144
+ * reads as "no positive evidence", i.e. today's behaviour.
145
+ */
146
+ private localInferencesCompleted;
147
+ /**
148
+ * One background re-probe tick.
149
+ * - While WAITING: a healthy probe starts local sensing immediately.
150
+ * - On CLOUD: any healthy probe → AUTO-UPGRADE to local immediately (running
151
+ * on cloud while local is ready is pure waste; the K-debounce on the return
152
+ * path bounds any toggling, so this is safe on the first healthy probe).
153
+ * - On LOCAL: a healthy probe resets the debounce; an unhealthy probe
154
+ * increments it, and only after K CONSECUTIVE unhealthy probes do we
155
+ * AUTO-RECOVER to cloud only when explicit fallback is enabled.
156
+ * At most one switch per tick; re-entrancy guarded.
157
+ *
158
+ * ── Why an unanswered probe is not, by itself, a verdict ───────────────────
159
+ *
160
+ * `litert-lm serve` builds on `http.server.HTTPServer` — the SERIAL one, not
161
+ * `ThreadingHTTPServer`. One request is handled at a time, so for the whole
162
+ * duration of a generation the accept loop is blocked and `GET /v1/models`
163
+ * cannot be answered by anybody. The readiness probe therefore competes with
164
+ * the very work whose viability it is meant to certify: measured against the
165
+ * real serve, 4 of 5 probes issued during ONE 11.8 s inference timed out at
166
+ * the shipped 2 000 ms, while an idle serve answered the same request in
167
+ * 2.6 ms.
168
+ *
169
+ * A 16-camera connector keeps that single slot busy essentially all the time,
170
+ * so an UNANSWERED probe was near-certain and two consecutive ones demoted the
171
+ * whole install: measured 3 mode switches in the first 6 minutes of a
172
+ * 16-camera run, each one stopping and restarting all 16 loops and moving
173
+ * every feed onto the metered cloud path. The connector's own success at
174
+ * local inference was the thing that made local inference look dead.
175
+ *
176
+ * The evidence that settles it is not the ping, it is the WORK: an ON-DEVICE
177
+ * inference that COMPLETED since the previous re-probe proves the runtime is
178
+ * alive, and proves it more directly than any side-channel could. So an
179
+ * unanswered probe is inconclusive only while local inferences are still
180
+ * landing; the moment they stop landing the same probe counts, and K of them
181
+ * demote exactly as before.
182
+ *
183
+ * It has to be `localInferences` and not the total analysis count. With
184
+ * `cloudFallbackOnError` on, a frame the local provider THREW on is answered
185
+ * by the cloud and still lands as an analysis — so a dead runtime would keep
186
+ * advancing the total forever and this rule would mask it permanently, which
187
+ * is strictly worse than the defect it replaces.
188
+ *
189
+ * Deliberately NOT keyed on "we have a request in flight": a serve that
190
+ * ACCEPTS and never answers holds our permit for the provider's whole timeout,
191
+ * so in-flight work is compatible with a runtime that is doing nothing. Only
192
+ * completion is proof. An ANSWERED probe stays conclusive either way — a
193
+ * non-2xx or a wrong model list is a real verdict, and a serve that answers
194
+ * has an opinion.
195
+ */
196
+ recheck(): Promise<void>;
197
+ /** Stop the active manager, start the target — old.stop() BEFORE new.start(). */
198
+ private switchTo;
199
+ /** SIGINT/SIGTERM: stop the active manager + clear the re-probe timer. Idempotent. */
200
+ shutdown(): Promise<void>;
201
+ }
202
+ /** Injection points for runAutoSense (default to the real probe/managers/timers). */
203
+ export interface AutoSenseDeps {
204
+ /**
205
+ * Probe used to decide local-vs-cloud. Defaults to probeLiteRtLmHealth.
206
+ * Receives the resolved base URL, per-probe timeout, and the model the local
207
+ * path will run (so the probe can require it before declaring local usable).
208
+ */
209
+ probe?: (baseUrl: string, timeoutMs: number, expectedModel: string) => Promise<LiteRtHealthResult>;
210
+ /** Loads the connector config. Defaults to loadConfig. */
211
+ loadConfig?: (configPath: string) => EdgeAgentConfig;
212
+ /** Build (NOT start) the local manager. Defaults to buildLocalSensingManager(config). */
213
+ buildLocalManager?: () => SensingManager | null;
214
+ /** Build (NOT start) the cloud manager. Defaults to buildCloudSensingManager(config). */
215
+ buildCloudManager?: () => SensingManager | null;
216
+ /** Log sink (tests capture it). Defaults to console.log. */
217
+ log?: (msg: string) => void;
218
+ /** Sleep between startup re-probes (tests inject a no-op). Defaults to setTimeout. */
219
+ sleep?: (ms: number) => Promise<void>;
220
+ /** Arm the re-probe timer. Defaults to setTimeout. */
221
+ setTimer?: (cb: () => void, ms: number) => AutoSenseTimerHandle;
222
+ /** Clear the re-probe timer. Defaults to clearTimeout. */
223
+ clearTimer?: (handle: AutoSenseTimerHandle) => void;
224
+ /** Fatal no-feeds handler. Defaults to process.exit(1). */
225
+ onNoFeeds?: () => void;
226
+ /** Register the shutdown handler. Defaults to SIGINT/SIGTERM listeners. */
227
+ registerShutdown?: (handler: () => void | Promise<void>) => void;
228
+ /** Block until shutdown (production never resolves; tests inject a resolved waiter). */
229
+ waitForShutdown?: () => Promise<void>;
230
+ /**
231
+ * Start the on-device VLM (Gemma) OTA watcher. Defaults to startGemmaModelOta.
232
+ * Returns a handle whose stop() runs on shutdown (or null when disabled). It
233
+ * starts only after LOCAL sensing activates, so first-time provisioning owns
234
+ * the initial model download and OTA cannot race it.
235
+ */
236
+ startModelOta?: (config: EdgeAgentConfig) => GemmaModelOtaHandle | null;
237
+ }
238
+ /**
239
+ * `auto-sense` entrypoint: resolve probe + manager inputs from config, then run
240
+ * the AutoSenseSupervisor (probe → start the chosen REAL manager → keep
241
+ * re-probing → auto-upgrade/auto-recover with NO restart). Blocks until
242
+ * SIGINT/SIGTERM (the supervisor's re-probe timer keeps the event loop alive).
243
+ *
244
+ * The probe target is the operator's configured `localSensing.litertLmBaseUrl`
245
+ * (default http://localhost:9379) so a non-standard serve host is honored, and
246
+ * the probe requires the configured `localSensing.model` to be present so we
247
+ * never pick local against a serve hosting the wrong model.
248
+ *
249
+ * Config is REQUIRED to build the sensing managers, so it's loaded up front and a
250
+ * genuine config error propagates to main() (prints + exits 1) — the same net
251
+ * result as before, where the chosen run mode re-loaded the config and reported it.
252
+ *
253
+ * The explicit `local-sense` / `cloud-sense` entrypoints stay non-switching; only
254
+ * `auto-sense` is supervised.
255
+ */
256
+ export declare function runAutoSense(args: string[], deps?: AutoSenseDeps): Promise<void>;
257
+ /**
258
+ * Default transport using Node's built-in http/https. No third-party deps so it
259
+ * survives bundling into the self-contained connector. Mirrors the framing
260
+ * tolerance of LiteRtVlmProvider's poster: litert-lm serve emits non-strict HTTP
261
+ * framing (bare LF on the status line) that Node's strict parser rejects, and
262
+ * the connector talks to a LOCAL, trusted serve, so we tolerate it here too —
263
+ * otherwise a healthy serve would look "unreachable" and we'd wrongly pick cloud.
264
+ */
265
+ export declare const defaultHttpGetter: HttpGetter;
266
+ //# 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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"}