@trillboards/edge-sdk 0.2.3 → 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 +122 -65
  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,436 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.defaultHttpJsonPoster = exports.LiteRtVlmProvider = void 0;
37
+ const http = __importStar(require("http"));
38
+ const https = __importStar(require("https"));
39
+ const url_1 = require("url");
40
+ /** Suffix litert-lm appends to a model id to advertise its GPU-delegate variant. */
41
+ const GPU_MODEL_SUFFIX = ',gpu';
42
+ /**
43
+ * Timeout for the one-shot `/v1/models` variant probe. Short: the serve is LOCAL,
44
+ * and a slow/absent model list must not stall the first frame behind the full
45
+ * inference timeout — it just means "CPU".
46
+ */
47
+ const MODEL_LIST_TIMEOUT_MS = 5000;
48
+ /** Marks a failure as transient (worth a perturbed retry) vs. fatal. */
49
+ class RetryableLiteRtError extends Error {
50
+ }
51
+ class LiteRtVlmProvider {
52
+ constructor(options = {}, poster) {
53
+ /** Resolved model id inference is posted under; null until the first resolve. */
54
+ this.selectedModel = null;
55
+ /** In-flight resolution, so N concurrent frames share ONE /v1/models probe. */
56
+ this.resolving = null;
57
+ /** Did the serve advertise the `,gpu` variant? null = not probed. */
58
+ this.gpuAdvertised = null;
59
+ /** Set once the GPU variant failed a whole frame and we fell back to CPU. */
60
+ this.gpuDemoted = false;
61
+ this.acceleratorReason = null;
62
+ const base = (options.litertLmBaseUrl || 'http://localhost:9379').replace(/\/+$/, '');
63
+ this.endpoint = `${base}/v1/chat/completions`;
64
+ this.modelsEndpoint = `${base}/v1/models`;
65
+ const configuredModel = options.model || 'gemma-4-E2B-it.litertlm';
66
+ // An operator may paste the GPU id straight into `localSensing.model`. Treat
67
+ // that as "base id + accelerator gpu" so we never build `…,gpu,gpu`.
68
+ const pinnedGpuInModelId = configuredModel.endsWith(GPU_MODEL_SUFFIX);
69
+ this.baseModel = pinnedGpuInModelId
70
+ ? configuredModel.slice(0, -GPU_MODEL_SUFFIX.length)
71
+ : configuredModel;
72
+ this.accelerator = pinnedGpuInModelId ? 'gpu' : (options.accelerator || 'auto');
73
+ this.timeoutMs = options.timeoutMs ?? 120000;
74
+ this.maxAttempts = Math.max(1, options.maxAttempts ?? 3);
75
+ this.retryBackoffMs = options.retryBackoffMs ?? 250;
76
+ this.poster = poster ?? exports.defaultHttpJsonPoster;
77
+ // eslint-disable-next-line no-console
78
+ this.log = options.log ?? ((message) => console.log(message));
79
+ // A PINNED delegate needs no probe — resolve it up front so getModel() is
80
+ // truthful from construction.
81
+ if (this.accelerator === 'cpu')
82
+ this.selectedModel = this.baseModel;
83
+ if (this.accelerator === 'gpu')
84
+ this.selectedModel = this.gpuModel();
85
+ }
86
+ /** The resolved chat-completions URL (exposed for assertions / logging). */
87
+ getEndpoint() {
88
+ return this.endpoint;
89
+ }
90
+ /**
91
+ * The model id this provider posts inference under. Before the first
92
+ * `analyze()` on the `'auto'` policy this is the BASE (CPU) id — the variant is
93
+ * resolved from the live model list at first use.
94
+ */
95
+ getModel() {
96
+ return this.selectedModel ?? this.baseModel;
97
+ }
98
+ /** The `,gpu` variant id for the configured base model. */
99
+ gpuModel() {
100
+ return `${this.baseModel}${GPU_MODEL_SUFFIX}`;
101
+ }
102
+ /**
103
+ * What this provider resolved about the host's accelerator — the health
104
+ * surface for "did we get the GPU, and if not, why not". Read by the
105
+ * local-sensing client so an operator/support can see it without log-diving.
106
+ */
107
+ getAcceleratorHealth() {
108
+ const selectedModel = this.getModel();
109
+ const selectedDelegate = this.selectedModel === null
110
+ ? null
111
+ : (this.selectedModel.endsWith(GPU_MODEL_SUFFIX) ? 'gpu' : 'cpu');
112
+ return {
113
+ accelerator: this.accelerator,
114
+ selectedModel,
115
+ selectedDelegate,
116
+ gpuAdvertised: this.gpuAdvertised,
117
+ gpuDemoted: this.gpuDemoted,
118
+ reason: this.acceleratorReason,
119
+ };
120
+ }
121
+ /**
122
+ * Resolve which model id to post under, probing `GET /v1/models` at most once
123
+ * for a SUCCESSFUL answer. A failed probe resolves to CPU for this frame only
124
+ * and is re-probed on the next one — a serve that is still warming up must not
125
+ * pin the connector to CPU for the life of the process.
126
+ */
127
+ async resolveModel() {
128
+ if (this.selectedModel !== null)
129
+ return this.selectedModel;
130
+ if (this.resolving)
131
+ return this.resolving;
132
+ this.resolving = (async () => {
133
+ const models = await this.fetchModelIds();
134
+ if (models === null) {
135
+ // Probe failed (serve down / unparseable). Run CPU for this frame and
136
+ // leave selectedModel unset so the next frame re-probes.
137
+ this.acceleratorReason =
138
+ `could not read ${this.modelsEndpoint} — running the CPU delegate for now`;
139
+ this.log(`[litert-lm] accelerator: CPU ("${this.baseModel}") — ${this.acceleratorReason}`);
140
+ return this.baseModel;
141
+ }
142
+ const gpuId = this.gpuModel();
143
+ this.gpuAdvertised = models.includes(gpuId);
144
+ if (this.gpuAdvertised) {
145
+ this.selectedModel = gpuId;
146
+ this.acceleratorReason = null;
147
+ this.log(`[litert-lm] accelerator: GPU — inference model "${gpuId}"`);
148
+ }
149
+ else {
150
+ this.selectedModel = this.baseModel;
151
+ this.acceleratorReason =
152
+ `${this.modelsEndpoint} does not advertise "${gpuId}" (has: ${models.join(', ') || 'none'})`;
153
+ this.log(`[litert-lm] accelerator: CPU — inference model "${this.baseModel}" ` +
154
+ `(${this.acceleratorReason})`);
155
+ }
156
+ return this.selectedModel;
157
+ })().finally(() => {
158
+ this.resolving = null;
159
+ });
160
+ return this.resolving;
161
+ }
162
+ /** GET the model-id list. Returns null on any transport/parse failure (never throws). */
163
+ async fetchModelIds() {
164
+ let result;
165
+ try {
166
+ result = await this.poster(this.modelsEndpoint, { method: 'GET', headers: { Accept: 'application/json' }, timeoutMs: MODEL_LIST_TIMEOUT_MS }, '');
167
+ }
168
+ catch {
169
+ return null;
170
+ }
171
+ if (result.statusCode < 200 || result.statusCode >= 300)
172
+ return null;
173
+ try {
174
+ const parsed = JSON.parse(result.body);
175
+ if (!Array.isArray(parsed?.data))
176
+ return null;
177
+ return parsed.data
178
+ .map((m) => (m && typeof m.id === 'string' ? m.id : null))
179
+ .filter((id) => id !== null);
180
+ }
181
+ catch {
182
+ return null;
183
+ }
184
+ }
185
+ /**
186
+ * Record that the GPU variant failed a whole frame (an unusable GPU delegate on
187
+ * this host) and pin the CPU delegate for the REST of the process. Idempotent —
188
+ * a SECOND concurrent frame that also failed on GPU must still be allowed to
189
+ * re-run on CPU, so the caller keys its retry on which model IT ran, not on
190
+ * whether it happened to be the one that recorded the demotion.
191
+ */
192
+ recordGpuDemotion(reason) {
193
+ if (this.accelerator === 'cpu' || this.gpuDemoted)
194
+ return;
195
+ this.gpuDemoted = true;
196
+ this.selectedModel = this.baseModel;
197
+ this.acceleratorReason = reason;
198
+ this.log(`[litert-lm] GPU delegate unusable on this host — falling back to the CPU model ` +
199
+ `"${this.baseModel}" for the rest of this run (${reason})`);
200
+ }
201
+ /**
202
+ * Run on-device inference on a JPEG frame and return the parsed + validated
203
+ * structured object (the same shape the cloud VLM emits for this schema).
204
+ * Retries a transient failure (non-2xx / unparseable / schema-invalid) with a
205
+ * perturbed temperature; a non-empty-jpeg failure is fatal (no retry).
206
+ *
207
+ * If EVERY attempt failed while running the GPU variant, the provider demotes
208
+ * to the CPU delegate and re-runs the attempt budget once — an init failure on
209
+ * a host with no usable GPU delegate degrades the frame's latency instead of
210
+ * losing the frame.
211
+ */
212
+ async analyze(request) {
213
+ if (!request?.jpeg || request.jpeg.length === 0) {
214
+ throw new Error('LiteRtVlmProvider.analyze requires a non-empty jpeg buffer');
215
+ }
216
+ const model = await this.resolveModel();
217
+ try {
218
+ return await this.runAttempts(request, model);
219
+ }
220
+ catch (err) {
221
+ if (!(err instanceof RetryableLiteRtError))
222
+ throw err;
223
+ // Only the GPU variant has a fallback left; a CPU failure is a real failure.
224
+ if (this.accelerator === 'cpu' || !model.endsWith(GPU_MODEL_SUFFIX))
225
+ throw err;
226
+ this.recordGpuDemotion(err.message);
227
+ return this.runAttempts(request, this.baseModel);
228
+ }
229
+ }
230
+ /** The retry budget for one frame against one model id. */
231
+ async runAttempts(request, model) {
232
+ let lastErr;
233
+ for (let attempt = 0; attempt < this.maxAttempts; attempt += 1) {
234
+ // attempt 0 → temperature 0 (deterministic); retries perturb to re-roll a
235
+ // degenerate generation (dropped key / out-of-enum value / unparseable).
236
+ const temperature = attempt === 0 ? 0 : 0.4;
237
+ try {
238
+ return await this.attemptOnce(request, temperature, model);
239
+ }
240
+ catch (err) {
241
+ lastErr = err;
242
+ if (!(err instanceof RetryableLiteRtError))
243
+ throw err;
244
+ if (attempt < this.maxAttempts - 1 && this.retryBackoffMs > 0) {
245
+ await new Promise((resolve) => setTimeout(resolve, this.retryBackoffMs));
246
+ }
247
+ }
248
+ }
249
+ throw lastErr ?? new Error('LiteRT-LM analyze failed');
250
+ }
251
+ /** A single inference attempt at the given temperature. */
252
+ async attemptOnce(request, temperature, model) {
253
+ const dataUri = `data:image/jpeg;base64,${request.jpeg.toString('base64')}`;
254
+ const fullPrompt = `${request.prompt}\n\n`
255
+ + 'Output ONLY a single minified JSON object (no markdown, no code fence, no prose) '
256
+ + 'with EXACTLY these keys:\n'
257
+ + renderSchemaAsFieldList(request.schema);
258
+ // PLAIN completion — no `tools`, no `tool_choice`, no `response_format`. Those
259
+ // route through litert-lm's broken constrained path (the `<|"|>` 500). Plain
260
+ // content is clean; we enforce the schema ourselves below.
261
+ const body = JSON.stringify({
262
+ model,
263
+ messages: [
264
+ {
265
+ role: 'user',
266
+ content: [
267
+ { type: 'text', text: fullPrompt },
268
+ { type: 'image_url', image_url: { url: dataUri } },
269
+ ],
270
+ },
271
+ ],
272
+ temperature,
273
+ });
274
+ let result;
275
+ try {
276
+ result = await this.poster(this.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, timeoutMs: this.timeoutMs }, body);
277
+ }
278
+ catch (err) {
279
+ // A TRANSPORT failure is the definition of transient, and until this it was
280
+ // the one class of failure treated as FATAL — the poster rejects with a
281
+ // plain Error (ECONNRESET, "socket hang up", ECONNREFUSED, the timeout),
282
+ // and `runAttempts` re-throws anything that is not a RetryableLiteRtError.
283
+ //
284
+ // That inverted the GPU-demotion contract in exactly the case it exists
285
+ // for. `litert-lm serve` is a serial http.server, so a GPU delegate that
286
+ // is unusable on this host does not answer with a status code — it takes
287
+ // the socket down with it, or never answers at all. Both arrived here as
288
+ // fatal, so `analyze()` never reached `recordGpuDemotion`, and a host with
289
+ // a bad GPU driver lost EVERY frame forever while the CPU delegate that
290
+ // would have worked was one line away. The same hole ate a frame on every
291
+ // ordinary serve restart — including the ones the Gemma OTA watcher does
292
+ // on purpose — and on every machine sleep/wake.
293
+ //
294
+ // A malformed base URL is NOT transient: it is a config error that would
295
+ // fail identically three times, so it stays fatal and fast.
296
+ const message = err?.message ?? String(err);
297
+ if (/^Invalid LiteRT-LM URL/.test(message))
298
+ throw err;
299
+ throw new RetryableLiteRtError(`LiteRT-LM transport failure: ${message}`);
300
+ }
301
+ if (result.statusCode < 200 || result.statusCode >= 300) {
302
+ throw new RetryableLiteRtError(`LiteRT-LM returned HTTP ${result.statusCode}: ${String(result.body).slice(0, 200)}`);
303
+ }
304
+ let envelope;
305
+ try {
306
+ envelope = JSON.parse(result.body);
307
+ }
308
+ catch (err) {
309
+ throw new RetryableLiteRtError(`Could not parse LiteRT-LM response JSON: ${err.message}`);
310
+ }
311
+ const content = envelope?.choices?.[0]?.message?.content;
312
+ if (typeof content !== 'string' || content.length === 0) {
313
+ throw new RetryableLiteRtError('LiteRT-LM returned no message content');
314
+ }
315
+ let parsed;
316
+ try {
317
+ parsed = repairAndParseJson(content);
318
+ }
319
+ catch (err) {
320
+ throw new RetryableLiteRtError(`Could not parse a JSON object from LiteRT-LM content: ${err.message}`);
321
+ }
322
+ // The model may emit an integer-valued field as a float (e.g. person_count:
323
+ // 1.0). Coerce declared integer fields back to int before validating.
324
+ coerceIntegerFields(parsed, request.schema);
325
+ // The structured-output guarantee lives HERE — reject (and retry) any
326
+ // generation missing a required key or emitting an out-of-enum value.
327
+ const violation = validateAgainstSchema(parsed, request.schema);
328
+ if (violation) {
329
+ throw new RetryableLiteRtError(`LiteRT-LM output failed schema validation: ${violation}`);
330
+ }
331
+ return parsed;
332
+ }
333
+ }
334
+ exports.LiteRtVlmProvider = LiteRtVlmProvider;
335
+ /**
336
+ * Render a JSON Schema's properties as a human-readable key list for the prompt.
337
+ * Enums render as `"key": one of [a, b, c]`; everything else as `"key": <type>`.
338
+ * (Embedding the raw JSON-schema OBJECT instead made Gemma echo the schema —
339
+ * the readable list reliably gets it to emit the data object.)
340
+ */
341
+ function renderSchemaAsFieldList(schema) {
342
+ const props = (schema && typeof schema === 'object' ? schema.properties : null) || {};
343
+ return Object.entries(props)
344
+ .map(([key, spec]) => {
345
+ const s = spec;
346
+ if (Array.isArray(s?.enum))
347
+ return ` "${key}": one of [${s.enum.join(', ')}]`;
348
+ const t = Array.isArray(s?.type) ? s.type.find((x) => x !== 'null') : s?.type;
349
+ return ` "${key}": ${t || 'string'}`;
350
+ })
351
+ .join('\n');
352
+ }
353
+ /**
354
+ * Extract + parse the JSON object from a plain-completion response. Tolerates a
355
+ * stray `<|"|>` quote token, ```json fences, and leading/trailing prose by
356
+ * slicing to the outermost { … }.
357
+ */
358
+ function repairAndParseJson(text) {
359
+ let s = String(text).replace(/<\|"\|>/g, '"').replace(/```(?:json)?/gi, '');
360
+ const start = s.indexOf('{');
361
+ const end = s.lastIndexOf('}');
362
+ if (start >= 0 && end > start)
363
+ s = s.slice(start, end + 1);
364
+ return JSON.parse(s);
365
+ }
366
+ /** Coerce float-valued integers (e.g. 1.0 → 1) for fields the schema declares integer. */
367
+ function coerceIntegerFields(obj, schema) {
368
+ const props = (schema && typeof schema === 'object' ? schema.properties : null) || {};
369
+ for (const [key, spec] of Object.entries(props)) {
370
+ const t = spec?.type;
371
+ const isInt = t === 'integer' || (Array.isArray(t) && t.includes('integer'));
372
+ if (isInt && typeof obj[key] === 'number' && Number.isFinite(obj[key])) {
373
+ obj[key] = Math.round(obj[key]);
374
+ }
375
+ }
376
+ }
377
+ /**
378
+ * Validate a parsed object against the schema's required keys + enum membership.
379
+ * Returns a human-readable violation string, or null when valid.
380
+ */
381
+ function validateAgainstSchema(obj, schema) {
382
+ const props = (schema && typeof schema === 'object' ? schema.properties : null) || {};
383
+ const required = Array.isArray(schema?.required) ? schema.required : [];
384
+ const missing = required.filter((k) => !(k in obj) || obj[k] === undefined || obj[k] === null);
385
+ if (missing.length)
386
+ return `missing required keys: ${missing.join(', ')}`;
387
+ const badEnum = [];
388
+ for (const [key, spec] of Object.entries(props)) {
389
+ const en = spec?.enum;
390
+ if (Array.isArray(en) && key in obj && obj[key] != null && !en.includes(obj[key])) {
391
+ badEnum.push(`${key}=${String(obj[key])}`);
392
+ }
393
+ }
394
+ if (badEnum.length)
395
+ return `out-of-enum values: ${badEnum.join(', ')}`;
396
+ return null;
397
+ }
398
+ /**
399
+ * Default transport using Node's built-in http/https. No third-party deps so it
400
+ * survives bundling into the self-contained connector.
401
+ */
402
+ const defaultHttpJsonPoster = (url, options, body) => {
403
+ return new Promise((resolve, reject) => {
404
+ let parsed;
405
+ try {
406
+ parsed = new url_1.URL(url);
407
+ }
408
+ catch (err) {
409
+ reject(new Error(`Invalid LiteRT-LM URL: ${err.message}`));
410
+ return;
411
+ }
412
+ const mod = parsed.protocol === 'https:' ? https : http;
413
+ const bodyBuffer = Buffer.from(body, 'utf-8');
414
+ const req = mod.request(url, {
415
+ method: options.method,
416
+ headers: { ...options.headers, 'Content-Length': String(bodyBuffer.length) },
417
+ timeout: options.timeoutMs,
418
+ // litert-lm serve emits non-strict HTTP framing (bare LF on the status
419
+ // line) that Node's strict parser rejects with "Missing expected CR
420
+ // after response line". The connector talks to a LOCAL, trusted
421
+ // litert-lm serve, so tolerate it. (Found via the production E2E — the
422
+ // strict parser silently broke every on-device inference call.)
423
+ insecureHTTPParser: true,
424
+ }, (res) => {
425
+ const chunks = [];
426
+ res.on('data', (chunk) => chunks.push(chunk));
427
+ res.on('end', () => resolve({ statusCode: res.statusCode || 0, body: Buffer.concat(chunks).toString('utf-8') }));
428
+ });
429
+ req.on('error', (err) => reject(err));
430
+ req.on('timeout', () => req.destroy(new Error('LiteRT-LM request timed out')));
431
+ req.write(bodyBuffer);
432
+ req.end();
433
+ });
434
+ };
435
+ exports.defaultHttpJsonPoster = defaultHttpJsonPoster;
436
+ //# sourceMappingURL=LiteRtVlmProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiteRtVlmProvider.js","sourceRoot":"","sources":["../src/LiteRtVlmProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import type { CameraProvider } from '@trillboards/edge-core';
2
+ import type { MosaicTile } from './config';
3
+ /**
4
+ * Wraps the FULL-mosaic frame provider so its single RTSP pull is shared by all
5
+ * tiles. The tiles' capture timers fire together (they start on the same
6
+ * cadence), so a tile asking within `maxAgeMs` of the last pull reuses that
7
+ * frame; concurrent callers coalesce onto one inflight pull. The cached frame is
8
+ * a co-temporal capture handed to sibling tiles — NOT a stored/replayed frame
9
+ * (it is always younger than the capture cadence).
10
+ */
11
+ export declare class SharedFrameSource {
12
+ private readonly source;
13
+ private readonly maxAgeMs;
14
+ private readonly nowFn;
15
+ private refs;
16
+ private last;
17
+ private inflight;
18
+ /** Coalesces concurrent ensureOpen() re-opens onto a single source.open(). */
19
+ private reopening;
20
+ constructor(source: CameraProvider, opts?: {
21
+ maxAgeMs?: number;
22
+ now?: () => number;
23
+ });
24
+ /** A tile attaches — open the underlying source on the first attach. */
25
+ acquire(): Promise<void>;
26
+ /** A tile detaches — close the underlying source when the last one leaves. */
27
+ release(): Promise<void>;
28
+ isOpen(): boolean;
29
+ /**
30
+ * Re-open the underlying source if it has dropped (e.g. the RTSP grabber gave
31
+ * up its per-attempt retries and closed itself), WITHOUT touching the
32
+ * refcount — this is recovery of an existing attachment, not a new tile
33
+ * joining. Concurrent re-opens (sibling tiles reconnecting on the same tick)
34
+ * coalesce onto one `source.open()`. The stale frame cache is cleared so the
35
+ * next getFrame() pulls fresh from the recovered source. No-op when already
36
+ * open. This is what lets mosaic feeds self-recover from an RTSP drop instead
37
+ * of staying down until the process restarts.
38
+ */
39
+ ensureOpen(): Promise<void>;
40
+ /** Source (mosaic) native resolution the tile crop coordinates are relative to. */
41
+ getResolution(): {
42
+ width: number;
43
+ height: number;
44
+ };
45
+ /** Full mosaic frame as a JPEG Buffer — cached/coalesced single pull. */
46
+ getFrame(): Promise<Buffer>;
47
+ }
48
+ export interface CropViewProviderOptions {
49
+ /** Sub-rectangle of the source frame for this tile (source pixels). Omit = full frame. */
50
+ crop?: MosaicTile;
51
+ /** Tile output width (px) — the sensing input size. */
52
+ width: number;
53
+ /** Tile output height (px). */
54
+ height: number;
55
+ /** Source (mosaic) native width/height — used to skip a re-encode for a full-frame view. */
56
+ sourceWidth?: number;
57
+ sourceHeight?: number;
58
+ /** Advisory fps reported to the cadence loop (default 8). */
59
+ fps?: number;
60
+ /** ffmpeg binary path (default 'ffmpeg'). */
61
+ ffmpegPath?: string;
62
+ /** JPEG quality 1-100 for the carved tile (default 70). */
63
+ jpegQuality?: number;
64
+ /** Carve timeout (ms) before the ffmpeg child is killed (default 8000). */
65
+ carveTimeoutMs?: number;
66
+ /**
67
+ * Carve output pixel format. 'jpeg' (default) — the VLM/cloud path that POSTs a
68
+ * JPEG. 'rgb24' — raw RGB24 (HWC) for the on-device ONNX zoo (AudienceSensingService
69
+ * → FaceDetector consumes raw RGB pixels, not JPEG). Both carve from the SAME
70
+ * cached mosaic pull; only the ffmpeg output encoding differs.
71
+ */
72
+ outputFormat?: 'jpeg' | 'rgb24';
73
+ }
74
+ /**
75
+ * A CameraProvider that yields one TILE of a shared mosaic frame. getFrame()
76
+ * pulls the (cached) full frame from the SharedFrameSource, then carves this
77
+ * tile in a single ffmpeg pass (`-i pipe:0 -vf crop=…,scale=… -f mjpeg`). A
78
+ * full-frame view at the source's own resolution skips the re-encode and returns
79
+ * the cached frame as-is.
80
+ */
81
+ export declare class CropViewProvider implements CameraProvider {
82
+ private readonly shared;
83
+ private readonly crop?;
84
+ private readonly width;
85
+ private readonly height;
86
+ private readonly sourceWidth?;
87
+ private readonly sourceHeight?;
88
+ private readonly fps;
89
+ private readonly ffmpegPath;
90
+ private readonly jpegQuality;
91
+ private readonly carveTimeoutMs;
92
+ private readonly outputFormat;
93
+ private opened;
94
+ constructor(shared: SharedFrameSource, opts: CropViewProviderOptions);
95
+ open(_deviceId?: string): Promise<void>;
96
+ close(): Promise<void>;
97
+ isOpen(): boolean;
98
+ getResolution(): {
99
+ width: number;
100
+ height: number;
101
+ };
102
+ getFps(): number;
103
+ getFrame(): Promise<Buffer>;
104
+ /** Carve this tile out of the cached full JPEG with a single ffmpeg pass.
105
+ * Output is JPEG (VLM/cloud) or raw RGB24 (on-device ONNX zoo) per outputFormat. */
106
+ private carve;
107
+ }
108
+ //# sourceMappingURL=MosaicSource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MosaicSource.d.ts","sourceRoot":"","sources":["../src/MosaicSource.ts"],"names":[],"mappings":"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"}