@elizaos/plugin-local-inference 2.0.0-beta.1 → 2.0.3-beta.2

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 (701) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/package.json +82 -15
  4. package/src/actions/generate-media.d.ts +59 -0
  5. package/src/actions/generate-media.d.ts.map +1 -0
  6. package/src/actions/generate-media.ts +647 -0
  7. package/src/actions/identify-speaker.d.ts +23 -0
  8. package/src/actions/identify-speaker.d.ts.map +1 -0
  9. package/src/actions/identify-speaker.ts +171 -0
  10. package/src/actions/transcription-control.d.ts +29 -0
  11. package/src/actions/transcription-control.d.ts.map +1 -0
  12. package/src/actions/transcription-control.test.ts +100 -0
  13. package/src/actions/transcription-control.ts +127 -0
  14. package/src/adapters/capacitor-llama/__tests__/compat-behavior.test.ts +218 -0
  15. package/src/adapters/capacitor-llama/__tests__/index.test.ts +68 -0
  16. package/src/adapters/capacitor-llama/__tests__/structured-output.test.ts +215 -0
  17. package/src/adapters/capacitor-llama/__tests__/text-streaming.test.ts +174 -0
  18. package/src/adapters/capacitor-llama/environment.ts +71 -0
  19. package/src/adapters/capacitor-llama/index.browser.ts +83 -0
  20. package/src/adapters/capacitor-llama/index.ts +807 -0
  21. package/src/adapters/capacitor-llama/loader.ts +109 -0
  22. package/src/adapters/capacitor-llama/structured-output.ts +165 -0
  23. package/src/adapters/capacitor-llama/text-streaming.ts +227 -0
  24. package/src/adapters/capacitor-llama/types.ts +374 -0
  25. package/src/backends/apple-foundation.ts +127 -0
  26. package/src/index.d.ts +8 -0
  27. package/src/index.d.ts.map +1 -0
  28. package/src/index.ts +62 -0
  29. package/src/local-inference-routes.d.ts +38 -0
  30. package/src/local-inference-routes.d.ts.map +1 -0
  31. package/src/local-inference-routes.test.ts +344 -0
  32. package/src/local-inference-routes.ts +1543 -0
  33. package/src/provider.d.ts +21 -0
  34. package/src/provider.d.ts.map +1 -0
  35. package/src/provider.ts +1082 -0
  36. package/src/routes/compat-helpers.d.ts +18 -0
  37. package/src/routes/compat-helpers.d.ts.map +1 -0
  38. package/src/routes/compat-helpers.ts +274 -0
  39. package/src/routes/family-member-route.d.ts +62 -0
  40. package/src/routes/family-member-route.d.ts.map +1 -0
  41. package/src/routes/family-member-route.ts +353 -0
  42. package/src/routes/index.d.ts +19 -0
  43. package/src/routes/index.d.ts.map +1 -0
  44. package/src/routes/index.ts +60 -0
  45. package/src/routes/live-diarization-route.d.ts +26 -0
  46. package/src/routes/live-diarization-route.d.ts.map +1 -0
  47. package/src/routes/live-diarization-route.test.ts +213 -0
  48. package/src/routes/live-diarization-route.ts +122 -0
  49. package/src/routes/local-inference-asr-route.d.ts +4 -0
  50. package/src/routes/local-inference-asr-route.d.ts.map +1 -0
  51. package/src/routes/local-inference-asr-route.test.ts +205 -0
  52. package/src/routes/local-inference-asr-route.ts +163 -0
  53. package/src/routes/local-inference-asr-transcribe.d.ts +20 -0
  54. package/src/routes/local-inference-asr-transcribe.d.ts.map +1 -0
  55. package/src/routes/local-inference-asr-transcribe.test.ts +118 -0
  56. package/src/routes/local-inference-asr-transcribe.ts +97 -0
  57. package/src/routes/local-inference-compat-routes.d.ts +16 -0
  58. package/src/routes/local-inference-compat-routes.d.ts.map +1 -0
  59. package/src/routes/local-inference-compat-routes.test.ts +485 -0
  60. package/src/routes/local-inference-compat-routes.ts +808 -0
  61. package/src/routes/local-inference-tts-route.d.ts +7 -0
  62. package/src/routes/local-inference-tts-route.d.ts.map +1 -0
  63. package/src/routes/local-inference-tts-route.test.ts +179 -0
  64. package/src/routes/local-inference-tts-route.ts +230 -0
  65. package/src/routes/transcript-audio-store.d.ts +15 -0
  66. package/src/routes/transcript-audio-store.d.ts.map +1 -0
  67. package/src/routes/transcript-audio-store.ts +27 -0
  68. package/src/routes/transcripts-routes.d.ts +36 -0
  69. package/src/routes/transcripts-routes.d.ts.map +1 -0
  70. package/src/routes/transcripts-routes.test.ts +144 -0
  71. package/src/routes/transcripts-routes.ts +159 -0
  72. package/src/routes/voice-first-run-routes.d.ts +62 -0
  73. package/src/routes/voice-first-run-routes.d.ts.map +1 -0
  74. package/src/routes/voice-first-run-routes.ts +524 -0
  75. package/src/routes/voice-models-routes.d.ts +62 -0
  76. package/src/routes/voice-models-routes.d.ts.map +1 -0
  77. package/src/routes/voice-models-routes.ts +554 -0
  78. package/src/routes/voice-profile-plugin-routes.d.ts +19 -0
  79. package/src/routes/voice-profile-plugin-routes.d.ts.map +1 -0
  80. package/src/routes/voice-profile-plugin-routes.ts +138 -0
  81. package/src/routes/voice-profiles-management-routes.d.ts +52 -0
  82. package/src/routes/voice-profiles-management-routes.d.ts.map +1 -0
  83. package/src/routes/voice-profiles-management-routes.ts +476 -0
  84. package/src/routes/voice-speaker-profile-routes.d.ts +57 -0
  85. package/src/routes/voice-speaker-profile-routes.d.ts.map +1 -0
  86. package/src/routes/voice-speaker-profile-routes.ts +199 -0
  87. package/src/runtime/aosp-llama-loader-selection.test.ts +80 -0
  88. package/src/runtime/capacitor-llama.d.ts +25 -0
  89. package/src/runtime/embedding-manager-support.d.ts +77 -0
  90. package/src/runtime/embedding-manager-support.d.ts.map +1 -0
  91. package/src/runtime/embedding-manager-support.ts +497 -0
  92. package/src/runtime/embedding-presets.d.ts +16 -0
  93. package/src/runtime/embedding-presets.d.ts.map +1 -0
  94. package/src/runtime/embedding-presets.ts +81 -0
  95. package/src/runtime/embedding-warmup-policy.d.ts +14 -0
  96. package/src/runtime/embedding-warmup-policy.d.ts.map +1 -0
  97. package/src/runtime/embedding-warmup-policy.test.ts +53 -0
  98. package/src/runtime/embedding-warmup-policy.ts +48 -0
  99. package/src/runtime/ensure-local-inference-handler.d.ts +62 -0
  100. package/src/runtime/ensure-local-inference-handler.d.ts.map +1 -0
  101. package/src/runtime/ensure-local-inference-handler.test.ts +528 -0
  102. package/src/runtime/ensure-local-inference-handler.ts +1448 -0
  103. package/src/runtime/index.d.ts +15 -0
  104. package/src/runtime/index.d.ts.map +1 -0
  105. package/src/runtime/index.ts +33 -0
  106. package/src/runtime/mobile-local-inference-gate.d.ts +31 -0
  107. package/src/runtime/mobile-local-inference-gate.d.ts.map +1 -0
  108. package/src/runtime/mobile-local-inference-gate.test.ts +69 -0
  109. package/src/runtime/mobile-local-inference-gate.ts +44 -0
  110. package/src/runtime/voice-entity-binding.d.ts +103 -0
  111. package/src/runtime/voice-entity-binding.d.ts.map +1 -0
  112. package/src/runtime/voice-entity-binding.transcript.test.ts +69 -0
  113. package/src/runtime/voice-entity-binding.ts +328 -0
  114. package/src/services/README.md +71 -0
  115. package/src/services/__tests__/backend-selector.test.ts +101 -0
  116. package/src/services/__tests__/checkpoint-manager.test.ts +376 -0
  117. package/src/services/__tests__/gpu-autotune.test.ts +400 -0
  118. package/src/services/__tests__/llm-streaming-binding.test.ts +85 -0
  119. package/src/services/__tests__/planner-grammar.test.ts +372 -0
  120. package/src/services/__tests__/runtime-target.test.ts +176 -0
  121. package/src/services/active-model-switch-rollback.test.ts +183 -0
  122. package/src/services/active-model.d.ts +282 -0
  123. package/src/services/active-model.d.ts.map +1 -0
  124. package/src/services/active-model.ts +1213 -0
  125. package/src/services/assignments.d.ts +71 -0
  126. package/src/services/assignments.d.ts.map +1 -0
  127. package/src/services/assignments.test.ts +80 -0
  128. package/src/services/assignments.ts +230 -0
  129. package/src/services/backend-selector.ts +95 -0
  130. package/src/services/backend.d.ts +346 -0
  131. package/src/services/backend.d.ts.map +1 -0
  132. package/src/services/backend.ts +612 -0
  133. package/src/services/bionic-host-loader.d.ts +46 -0
  134. package/src/services/bionic-host-loader.d.ts.map +1 -0
  135. package/src/services/bionic-host-loader.test.ts +133 -0
  136. package/src/services/bionic-host-loader.ts +180 -0
  137. package/src/services/bundled-models.d.ts +34 -0
  138. package/src/services/bundled-models.d.ts.map +1 -0
  139. package/src/services/bundled-models.ts +129 -0
  140. package/src/services/cache-bridge.d.ts +206 -0
  141. package/src/services/cache-bridge.d.ts.map +1 -0
  142. package/src/services/cache-bridge.test.ts +516 -0
  143. package/src/services/cache-bridge.ts +423 -0
  144. package/src/services/catalog.d.ts +10 -0
  145. package/src/services/catalog.d.ts.map +1 -0
  146. package/src/services/catalog.test.ts +238 -0
  147. package/src/services/catalog.ts +27 -0
  148. package/src/services/checkpoint-client.d.ts +109 -0
  149. package/src/services/checkpoint-client.d.ts.map +1 -0
  150. package/src/services/checkpoint-client.ts +258 -0
  151. package/src/services/checkpoint-manager.ts +474 -0
  152. package/src/services/cloud-fallback.d.ts +102 -0
  153. package/src/services/cloud-fallback.d.ts.map +1 -0
  154. package/src/services/cloud-fallback.ts +230 -0
  155. package/src/services/conversation-registry.d.ts +142 -0
  156. package/src/services/conversation-registry.d.ts.map +1 -0
  157. package/src/services/conversation-registry.test.ts +235 -0
  158. package/src/services/conversation-registry.ts +264 -0
  159. package/src/services/desktop-fused-ffi-backend-runtime.d.ts +95 -0
  160. package/src/services/desktop-fused-ffi-backend-runtime.d.ts.map +1 -0
  161. package/src/services/desktop-fused-ffi-backend-runtime.ts +339 -0
  162. package/src/services/device-bridge.d.ts +188 -0
  163. package/src/services/device-bridge.d.ts.map +1 -0
  164. package/src/services/device-bridge.ts +1237 -0
  165. package/src/services/device-resource-metrics.d.ts +149 -0
  166. package/src/services/device-resource-metrics.d.ts.map +1 -0
  167. package/src/services/device-resource-metrics.test.ts +98 -0
  168. package/src/services/device-resource-metrics.ts +346 -0
  169. package/src/services/device-tier.d.ts +115 -0
  170. package/src/services/device-tier.d.ts.map +1 -0
  171. package/src/services/device-tier.test.ts +371 -0
  172. package/src/services/device-tier.ts +410 -0
  173. package/src/services/downloader.d.ts +82 -0
  174. package/src/services/downloader.d.ts.map +1 -0
  175. package/src/services/downloader.test.ts +747 -0
  176. package/src/services/downloader.ts +925 -0
  177. package/src/services/engine-direct-bundle.test.ts +58 -0
  178. package/src/services/engine-streaming.test.ts +80 -0
  179. package/src/services/engine.d.ts +540 -0
  180. package/src/services/engine.d.ts.map +1 -0
  181. package/src/services/engine.ts +1909 -0
  182. package/src/services/ensure-local-artifacts.integration.test.ts +273 -0
  183. package/src/services/ensure-local-artifacts.test.ts +368 -0
  184. package/src/services/ensure-local-artifacts.ts +351 -0
  185. package/src/services/external-scanner.d.ts +17 -0
  186. package/src/services/external-scanner.d.ts.map +1 -0
  187. package/src/services/external-scanner.ts +312 -0
  188. package/src/services/ffi-llm-mock.ts +354 -0
  189. package/src/services/ffi-llm-streaming-abi.ts +442 -0
  190. package/src/services/ffi-streaming-backend.d.ts +180 -0
  191. package/src/services/ffi-streaming-backend.d.ts.map +1 -0
  192. package/src/services/ffi-streaming-backend.ts +382 -0
  193. package/src/services/ffi-streaming-runner.d.ts +122 -0
  194. package/src/services/ffi-streaming-runner.d.ts.map +1 -0
  195. package/src/services/ffi-streaming-runner.test.ts +60 -0
  196. package/src/services/ffi-streaming-runner.ts +354 -0
  197. package/src/services/ffi-unload-ordering.test.ts +162 -0
  198. package/src/services/gpu-autotune.ts +534 -0
  199. package/src/services/gpu-detect.d.ts +56 -0
  200. package/src/services/gpu-detect.d.ts.map +1 -0
  201. package/src/services/gpu-detect.ts +139 -0
  202. package/src/services/handler-registry.d.ts +72 -0
  203. package/src/services/handler-registry.d.ts.map +1 -0
  204. package/src/services/handler-registry.ts +240 -0
  205. package/src/services/hardware.d.ts +63 -0
  206. package/src/services/hardware.d.ts.map +1 -0
  207. package/src/services/hardware.test.ts +231 -0
  208. package/src/services/hardware.ts +410 -0
  209. package/src/services/hf-search.d.ts +26 -0
  210. package/src/services/hf-search.d.ts.map +1 -0
  211. package/src/services/hf-search.test.ts +69 -0
  212. package/src/services/hf-search.ts +420 -0
  213. package/src/services/image-description-runtime.d.ts +14 -0
  214. package/src/services/image-description-runtime.d.ts.map +1 -0
  215. package/src/services/image-description-runtime.test.ts +61 -0
  216. package/src/services/image-description-runtime.ts +118 -0
  217. package/src/services/imagegen/aosp-unavailable.d.ts +134 -0
  218. package/src/services/imagegen/aosp-unavailable.d.ts.map +1 -0
  219. package/src/services/imagegen/aosp-unavailable.ts +229 -0
  220. package/src/services/imagegen/backend-selector.d.ts +118 -0
  221. package/src/services/imagegen/backend-selector.d.ts.map +1 -0
  222. package/src/services/imagegen/backend-selector.ts +277 -0
  223. package/src/services/imagegen/coreml-unavailable.d.ts +105 -0
  224. package/src/services/imagegen/coreml-unavailable.d.ts.map +1 -0
  225. package/src/services/imagegen/coreml-unavailable.ts +237 -0
  226. package/src/services/imagegen/errors.d.ts +16 -0
  227. package/src/services/imagegen/errors.d.ts.map +1 -0
  228. package/src/services/imagegen/errors.ts +40 -0
  229. package/src/services/imagegen/index.d.ts +58 -0
  230. package/src/services/imagegen/index.d.ts.map +1 -0
  231. package/src/services/imagegen/index.ts +144 -0
  232. package/src/services/imagegen/mflux.d.ts +74 -0
  233. package/src/services/imagegen/mflux.d.ts.map +1 -0
  234. package/src/services/imagegen/mflux.ts +313 -0
  235. package/src/services/imagegen/sd-cpp.d.ts +180 -0
  236. package/src/services/imagegen/sd-cpp.d.ts.map +1 -0
  237. package/src/services/imagegen/sd-cpp.ts +718 -0
  238. package/src/services/imagegen/tensorrt-unavailable.d.ts +83 -0
  239. package/src/services/imagegen/tensorrt-unavailable.d.ts.map +1 -0
  240. package/src/services/imagegen/tensorrt-unavailable.ts +295 -0
  241. package/src/services/imagegen/types.d.ts +181 -0
  242. package/src/services/imagegen/types.d.ts.map +1 -0
  243. package/src/services/imagegen/types.ts +193 -0
  244. package/src/services/index.d.ts +29 -0
  245. package/src/services/index.d.ts.map +1 -0
  246. package/src/services/index.ts +211 -0
  247. package/src/services/inference-capabilities.d.ts +132 -0
  248. package/src/services/inference-capabilities.d.ts.map +1 -0
  249. package/src/services/inference-capabilities.test.ts +75 -0
  250. package/src/services/inference-capabilities.ts +204 -0
  251. package/src/services/inference-telemetry.d.ts +59 -0
  252. package/src/services/inference-telemetry.d.ts.map +1 -0
  253. package/src/services/inference-telemetry.ts +143 -0
  254. package/src/services/ios-llama-streaming.ts +248 -0
  255. package/src/services/kv-spill.d.ts +189 -0
  256. package/src/services/kv-spill.d.ts.map +1 -0
  257. package/src/services/kv-spill.test.ts +222 -0
  258. package/src/services/kv-spill.ts +356 -0
  259. package/src/services/latency-trace.d.ts +346 -0
  260. package/src/services/latency-trace.d.ts.map +1 -0
  261. package/src/services/latency-trace.test.ts +266 -0
  262. package/src/services/latency-trace.ts +844 -0
  263. package/src/services/llama-server-metrics.ts +304 -0
  264. package/src/services/llm-streaming-binding.d.ts +96 -0
  265. package/src/services/llm-streaming-binding.d.ts.map +1 -0
  266. package/src/services/llm-streaming-binding.ts +136 -0
  267. package/src/services/load-args.d.ts +82 -0
  268. package/src/services/load-args.d.ts.map +1 -0
  269. package/src/services/load-args.ts +81 -0
  270. package/src/services/manifest/eliza-1.manifest.v1.json +708 -0
  271. package/src/services/manifest/index.d.ts +4 -0
  272. package/src/services/manifest/index.d.ts.map +1 -0
  273. package/src/services/manifest/index.ts +66 -0
  274. package/src/services/manifest/manifest.test.ts +689 -0
  275. package/src/services/manifest/schema.d.ts +713 -0
  276. package/src/services/manifest/schema.d.ts.map +1 -0
  277. package/src/services/manifest/schema.ts +653 -0
  278. package/src/services/manifest/types.d.ts +30 -0
  279. package/src/services/manifest/types.d.ts.map +1 -0
  280. package/src/services/manifest/types.ts +55 -0
  281. package/src/services/manifest/validator.d.ts +66 -0
  282. package/src/services/manifest/validator.d.ts.map +1 -0
  283. package/src/services/manifest/validator.ts +567 -0
  284. package/src/services/memory-arbiter.d.ts +318 -0
  285. package/src/services/memory-arbiter.d.ts.map +1 -0
  286. package/src/services/memory-arbiter.test.ts +419 -0
  287. package/src/services/memory-arbiter.ts +925 -0
  288. package/src/services/memory-monitor.d.ts +122 -0
  289. package/src/services/memory-monitor.d.ts.map +1 -0
  290. package/src/services/memory-monitor.test.ts +208 -0
  291. package/src/services/memory-monitor.ts +297 -0
  292. package/src/services/memory-pressure.d.ts +130 -0
  293. package/src/services/memory-pressure.d.ts.map +1 -0
  294. package/src/services/memory-pressure.ts +414 -0
  295. package/src/services/mtp-doctor.d.ts +13 -0
  296. package/src/services/mtp-doctor.d.ts.map +1 -0
  297. package/src/services/mtp-doctor.ts +78 -0
  298. package/src/services/network-policy.d.ts +127 -0
  299. package/src/services/network-policy.d.ts.map +1 -0
  300. package/src/services/network-policy.ts +346 -0
  301. package/src/services/paths.d.ts +6 -0
  302. package/src/services/paths.d.ts.map +1 -0
  303. package/src/services/paths.ts +25 -0
  304. package/src/services/planner-skeleton.d.ts +124 -0
  305. package/src/services/planner-skeleton.d.ts.map +1 -0
  306. package/src/services/planner-skeleton.ts +175 -0
  307. package/src/services/providers.d.ts +38 -0
  308. package/src/services/providers.d.ts.map +1 -0
  309. package/src/services/providers.ts +507 -0
  310. package/src/services/ram-budget-cache.test.ts +163 -0
  311. package/src/services/ram-budget.d.ts +110 -0
  312. package/src/services/ram-budget.d.ts.map +1 -0
  313. package/src/services/ram-budget.ts +0 -0
  314. package/src/services/readiness.d.ts +9 -0
  315. package/src/services/readiness.d.ts.map +1 -0
  316. package/src/services/readiness.test.ts +87 -0
  317. package/src/services/readiness.ts +238 -0
  318. package/src/services/recommendation.d.ts +111 -0
  319. package/src/services/recommendation.d.ts.map +1 -0
  320. package/src/services/recommendation.ts +671 -0
  321. package/src/services/registry.d.ts +35 -0
  322. package/src/services/registry.d.ts.map +1 -0
  323. package/src/services/registry.ts +151 -0
  324. package/src/services/router-handler.d.ts +92 -0
  325. package/src/services/router-handler.d.ts.map +1 -0
  326. package/src/services/router-handler.test.ts +45 -0
  327. package/src/services/router-handler.ts +407 -0
  328. package/src/services/routing-policy.d.ts +69 -0
  329. package/src/services/routing-policy.d.ts.map +1 -0
  330. package/src/services/routing-policy.test.ts +164 -0
  331. package/src/services/routing-policy.ts +297 -0
  332. package/src/services/routing-preferences.d.ts +8 -0
  333. package/src/services/routing-preferences.d.ts.map +1 -0
  334. package/src/services/routing-preferences.ts +17 -0
  335. package/src/services/runtime-target.d.ts +98 -0
  336. package/src/services/runtime-target.d.ts.map +1 -0
  337. package/src/services/runtime-target.ts +154 -0
  338. package/src/services/service.d.ts +128 -0
  339. package/src/services/service.d.ts.map +1 -0
  340. package/src/services/service.test.ts +223 -0
  341. package/src/services/service.ts +735 -0
  342. package/src/services/session-pool.d.ts +72 -0
  343. package/src/services/session-pool.d.ts.map +1 -0
  344. package/src/services/session-pool.ts +153 -0
  345. package/src/services/structured-output/deterministic-repair.d.ts +23 -0
  346. package/src/services/structured-output/deterministic-repair.d.ts.map +1 -0
  347. package/src/services/structured-output/deterministic-repair.test.ts +169 -0
  348. package/src/services/structured-output/deterministic-repair.ts +443 -0
  349. package/src/services/structured-output/index.ts +4 -0
  350. package/src/services/structured-output.d.ts +311 -0
  351. package/src/services/structured-output.d.ts.map +1 -0
  352. package/src/services/structured-output.test.ts +483 -0
  353. package/src/services/structured-output.ts +712 -0
  354. package/src/services/system-memory.d.ts +33 -0
  355. package/src/services/system-memory.d.ts.map +1 -0
  356. package/src/services/system-memory.test.ts +47 -0
  357. package/src/services/system-memory.ts +67 -0
  358. package/src/services/transcription-priority.test.ts +211 -0
  359. package/src/services/types.d.ts +19 -0
  360. package/src/services/types.d.ts.map +1 -0
  361. package/src/services/types.ts +55 -0
  362. package/src/services/verify-on-device.d.ts +34 -0
  363. package/src/services/verify-on-device.d.ts.map +1 -0
  364. package/src/services/verify-on-device.test.ts +87 -0
  365. package/src/services/verify-on-device.ts +127 -0
  366. package/src/services/verify.d.ts +8 -0
  367. package/src/services/verify.d.ts.map +1 -0
  368. package/src/services/verify.ts +13 -0
  369. package/src/services/vision/aosp-unavailable.d.ts +115 -0
  370. package/src/services/vision/aosp-unavailable.d.ts.map +1 -0
  371. package/src/services/vision/aosp-unavailable.ts +163 -0
  372. package/src/services/vision/capacitor-llama.d.ts +99 -0
  373. package/src/services/vision/capacitor-llama.d.ts.map +1 -0
  374. package/src/services/vision/capacitor-llama.ts +255 -0
  375. package/src/services/vision/cloud-fallback.d.ts +47 -0
  376. package/src/services/vision/cloud-fallback.d.ts.map +1 -0
  377. package/src/services/vision/cloud-fallback.test.ts +243 -0
  378. package/src/services/vision/cloud-fallback.ts +268 -0
  379. package/src/services/vision/fallback-chain.test.ts +86 -0
  380. package/src/services/vision/hash.d.ts +71 -0
  381. package/src/services/vision/hash.d.ts.map +1 -0
  382. package/src/services/vision/hash.ts +157 -0
  383. package/src/services/vision/index.d.ts +95 -0
  384. package/src/services/vision/index.d.ts.map +1 -0
  385. package/src/services/vision/index.ts +251 -0
  386. package/src/services/vision/llama-server.d.ts +73 -0
  387. package/src/services/vision/llama-server.d.ts.map +1 -0
  388. package/src/services/vision/llama-server.ts +177 -0
  389. package/src/services/vision/types.d.ts +153 -0
  390. package/src/services/vision/types.d.ts.map +1 -0
  391. package/src/services/vision/types.ts +154 -0
  392. package/src/services/vision/vast-fallback.d.ts +18 -0
  393. package/src/services/vision/vast-fallback.d.ts.map +1 -0
  394. package/src/services/vision/vast-fallback.ts +127 -0
  395. package/src/services/vision-embedding-cache.d.ts +98 -0
  396. package/src/services/vision-embedding-cache.d.ts.map +1 -0
  397. package/src/services/vision-embedding-cache.ts +189 -0
  398. package/src/services/voice/VOICE_WORKBENCH.md +88 -0
  399. package/src/services/voice/__test-helpers__/fake-ffi.ts +94 -0
  400. package/src/services/voice/__test-helpers__/synthetic-speech.ts +124 -0
  401. package/src/services/voice/__tests__/checkpoint-manager.test.ts +241 -0
  402. package/src/services/voice/__tests__/checkpoint-policy.test.ts +270 -0
  403. package/src/services/voice/__tests__/eager-context-builder.test.ts +257 -0
  404. package/src/services/voice/__tests__/eliza1-eot-scorer.test.ts +288 -0
  405. package/src/services/voice/__tests__/eot-classifier.test.ts +431 -0
  406. package/src/services/voice/__tests__/optimistic-rollback.test.ts +312 -0
  407. package/src/services/voice/__tests__/prefill-client.test.ts +266 -0
  408. package/src/services/voice/__tests__/prefix-preserving-queue.test.ts +208 -0
  409. package/src/services/voice/__tests__/streaming-asr.test.ts +450 -0
  410. package/src/services/voice/__tests__/streaming-transcriber.test.ts +339 -0
  411. package/src/services/voice/__tests__/turn-detector-resolver.test.ts +195 -0
  412. package/src/services/voice/__tests__/voice-state-machine-prefill.test.ts +275 -0
  413. package/src/services/voice/__tests__/voice-state-machine.test.ts +354 -0
  414. package/src/services/voice/asr-timed.real.test.ts +141 -0
  415. package/src/services/voice/audio-frame-consumer.d.ts +212 -0
  416. package/src/services/voice/audio-frame-consumer.d.ts.map +1 -0
  417. package/src/services/voice/audio-frame-consumer.test.ts +343 -0
  418. package/src/services/voice/audio-frame-consumer.ts +491 -0
  419. package/src/services/voice/barge-in.d.ts +112 -0
  420. package/src/services/voice/barge-in.d.ts.map +1 -0
  421. package/src/services/voice/barge-in.test.ts +244 -0
  422. package/src/services/voice/barge-in.ts +336 -0
  423. package/src/services/voice/cancellation-coordinator.d.ts +127 -0
  424. package/src/services/voice/cancellation-coordinator.d.ts.map +1 -0
  425. package/src/services/voice/cancellation-coordinator.test.ts +196 -0
  426. package/src/services/voice/cancellation-coordinator.ts +269 -0
  427. package/src/services/voice/checkpoint-manager.d.ts +199 -0
  428. package/src/services/voice/checkpoint-manager.d.ts.map +1 -0
  429. package/src/services/voice/checkpoint-manager.ts +401 -0
  430. package/src/services/voice/checkpoint-policy.ts +336 -0
  431. package/src/services/voice/composite-eot-classifier.test.ts +59 -0
  432. package/src/services/voice/e2e-harness.test.ts +182 -0
  433. package/src/services/voice/e2e-harness.ts +743 -0
  434. package/src/services/voice/eager-context-builder.d.ts +170 -0
  435. package/src/services/voice/eager-context-builder.d.ts.map +1 -0
  436. package/src/services/voice/eager-context-builder.ts +262 -0
  437. package/src/services/voice/eliza1-eot-scorer.d.ts +124 -0
  438. package/src/services/voice/eliza1-eot-scorer.d.ts.map +1 -0
  439. package/src/services/voice/eliza1-eot-scorer.ts +242 -0
  440. package/src/services/voice/embedding-server.ts +200 -0
  441. package/src/services/voice/embedding.d.ts +133 -0
  442. package/src/services/voice/embedding.d.ts.map +1 -0
  443. package/src/services/voice/embedding.test.ts +131 -0
  444. package/src/services/voice/embedding.ts +243 -0
  445. package/src/services/voice/emotion-attribution.d.ts +68 -0
  446. package/src/services/voice/emotion-attribution.d.ts.map +1 -0
  447. package/src/services/voice/emotion-attribution.test.ts +129 -0
  448. package/src/services/voice/emotion-attribution.ts +361 -0
  449. package/src/services/voice/engine-bridge-cancellation.test.ts +422 -0
  450. package/src/services/voice/engine-bridge.d.ts +759 -0
  451. package/src/services/voice/engine-bridge.d.ts.map +1 -0
  452. package/src/services/voice/engine-bridge.test.ts +384 -0
  453. package/src/services/voice/engine-bridge.ts +2302 -0
  454. package/src/services/voice/eot-classifier-ggml.d.ts +179 -0
  455. package/src/services/voice/eot-classifier-ggml.d.ts.map +1 -0
  456. package/src/services/voice/eot-classifier-ggml.ts +566 -0
  457. package/src/services/voice/eot-classifier.d.ts +214 -0
  458. package/src/services/voice/eot-classifier.d.ts.map +1 -0
  459. package/src/services/voice/eot-classifier.ts +533 -0
  460. package/src/services/voice/errors.d.ts +20 -0
  461. package/src/services/voice/errors.d.ts.map +1 -0
  462. package/src/services/voice/errors.ts +32 -0
  463. package/src/services/voice/expressive-tags.d.ts +158 -0
  464. package/src/services/voice/expressive-tags.d.ts.map +1 -0
  465. package/src/services/voice/expressive-tags.ts +405 -0
  466. package/src/services/voice/ffi-bindings.d.ts +674 -0
  467. package/src/services/voice/ffi-bindings.d.ts.map +1 -0
  468. package/src/services/voice/ffi-bindings.test.ts +728 -0
  469. package/src/services/voice/ffi-bindings.ts +3225 -0
  470. package/src/services/voice/first-line-cache.d.ts +181 -0
  471. package/src/services/voice/first-line-cache.d.ts.map +1 -0
  472. package/src/services/voice/first-line-cache.ts +725 -0
  473. package/src/services/voice/fused-eot-scorer.d.ts +51 -0
  474. package/src/services/voice/fused-eot-scorer.d.ts.map +1 -0
  475. package/src/services/voice/fused-eot-scorer.ts +135 -0
  476. package/src/services/voice/index.d.ts +91 -0
  477. package/src/services/voice/index.d.ts.map +1 -0
  478. package/src/services/voice/index.ts +481 -0
  479. package/src/services/voice/kokoro/__tests__/kokoro-backend.test.ts +151 -0
  480. package/src/services/voice/kokoro/__tests__/kokoro-engine-bridge.real.test.ts +151 -0
  481. package/src/services/voice/kokoro/__tests__/kokoro-engine-bridge.test.ts +60 -0
  482. package/src/services/voice/kokoro/__tests__/kokoro-engine-discovery.test.ts +277 -0
  483. package/src/services/voice/kokoro/__tests__/kokoro-ffi-runtime.test.ts +235 -0
  484. package/src/services/voice/kokoro/__tests__/kokoro-runtime.test.ts +95 -0
  485. package/src/services/voice/kokoro/__tests__/phonemizer.test.ts +53 -0
  486. package/src/services/voice/kokoro/__tests__/runtime-selection.test.ts +231 -0
  487. package/src/services/voice/kokoro/__tests__/voices.test.ts +57 -0
  488. package/src/services/voice/kokoro/index.ts +79 -0
  489. package/src/services/voice/kokoro/kokoro-backend.d.ts +72 -0
  490. package/src/services/voice/kokoro/kokoro-backend.d.ts.map +1 -0
  491. package/src/services/voice/kokoro/kokoro-backend.ts +207 -0
  492. package/src/services/voice/kokoro/kokoro-engine-discovery.d.ts +58 -0
  493. package/src/services/voice/kokoro/kokoro-engine-discovery.d.ts.map +1 -0
  494. package/src/services/voice/kokoro/kokoro-engine-discovery.ts +177 -0
  495. package/src/services/voice/kokoro/kokoro-ffi-runtime.d.ts +75 -0
  496. package/src/services/voice/kokoro/kokoro-ffi-runtime.d.ts.map +1 -0
  497. package/src/services/voice/kokoro/kokoro-ffi-runtime.ts +233 -0
  498. package/src/services/voice/kokoro/kokoro-runtime.d.ts +100 -0
  499. package/src/services/voice/kokoro/kokoro-runtime.d.ts.map +1 -0
  500. package/src/services/voice/kokoro/kokoro-runtime.ts +170 -0
  501. package/src/services/voice/kokoro/phoneme-stream.ts +123 -0
  502. package/src/services/voice/kokoro/phonemizer.d.ts +50 -0
  503. package/src/services/voice/kokoro/phonemizer.d.ts.map +1 -0
  504. package/src/services/voice/kokoro/phonemizer.ts +344 -0
  505. package/src/services/voice/kokoro/pick-runtime.d.ts +61 -0
  506. package/src/services/voice/kokoro/pick-runtime.d.ts.map +1 -0
  507. package/src/services/voice/kokoro/pick-runtime.test.ts +91 -0
  508. package/src/services/voice/kokoro/pick-runtime.ts +130 -0
  509. package/src/services/voice/kokoro/runtime-selection.d.ts +92 -0
  510. package/src/services/voice/kokoro/runtime-selection.d.ts.map +1 -0
  511. package/src/services/voice/kokoro/runtime-selection.ts +237 -0
  512. package/src/services/voice/kokoro/types.d.ts +82 -0
  513. package/src/services/voice/kokoro/types.d.ts.map +1 -0
  514. package/src/services/voice/kokoro/types.ts +95 -0
  515. package/src/services/voice/kokoro/voice-presets.d.ts +23 -0
  516. package/src/services/voice/kokoro/voice-presets.d.ts.map +1 -0
  517. package/src/services/voice/kokoro/voice-presets.ts +129 -0
  518. package/src/services/voice/kokoro/voices.d.ts +30 -0
  519. package/src/services/voice/kokoro/voices.d.ts.map +1 -0
  520. package/src/services/voice/kokoro/voices.ts +64 -0
  521. package/src/services/voice/lifecycle.d.ts +135 -0
  522. package/src/services/voice/lifecycle.d.ts.map +1 -0
  523. package/src/services/voice/lifecycle.test.ts +315 -0
  524. package/src/services/voice/lifecycle.ts +301 -0
  525. package/src/services/voice/live-diarization-session.d.ts +96 -0
  526. package/src/services/voice/live-diarization-session.d.ts.map +1 -0
  527. package/src/services/voice/live-diarization-session.ts +289 -0
  528. package/src/services/voice/mic-source.d.ts +136 -0
  529. package/src/services/voice/mic-source.d.ts.map +1 -0
  530. package/src/services/voice/mic-source.test.ts +210 -0
  531. package/src/services/voice/mic-source.ts +503 -0
  532. package/src/services/voice/optimistic-policy.d.ts +109 -0
  533. package/src/services/voice/optimistic-policy.d.ts.map +1 -0
  534. package/src/services/voice/optimistic-policy.test.ts +101 -0
  535. package/src/services/voice/optimistic-policy.ts +192 -0
  536. package/src/services/voice/optimistic-rollback.ts +343 -0
  537. package/src/services/voice/partial-stabilizer.d.ts +73 -0
  538. package/src/services/voice/partial-stabilizer.d.ts.map +1 -0
  539. package/src/services/voice/partial-stabilizer.test.ts +68 -0
  540. package/src/services/voice/partial-stabilizer.ts +140 -0
  541. package/src/services/voice/phoneme-tokenizer.d.ts +49 -0
  542. package/src/services/voice/phoneme-tokenizer.d.ts.map +1 -0
  543. package/src/services/voice/phoneme-tokenizer.ts +158 -0
  544. package/src/services/voice/phrase-cache.d.ts +76 -0
  545. package/src/services/voice/phrase-cache.d.ts.map +1 -0
  546. package/src/services/voice/phrase-cache.test.ts +242 -0
  547. package/src/services/voice/phrase-cache.ts +186 -0
  548. package/src/services/voice/phrase-chunker.d.ts +62 -0
  549. package/src/services/voice/phrase-chunker.d.ts.map +1 -0
  550. package/src/services/voice/phrase-chunker.test.ts +239 -0
  551. package/src/services/voice/phrase-chunker.ts +281 -0
  552. package/src/services/voice/pipeline-impls.d.ts +151 -0
  553. package/src/services/voice/pipeline-impls.d.ts.map +1 -0
  554. package/src/services/voice/pipeline-impls.l6.test.ts +110 -0
  555. package/src/services/voice/pipeline-impls.test.ts +292 -0
  556. package/src/services/voice/pipeline-impls.ts +315 -0
  557. package/src/services/voice/pipeline.d.ts +216 -0
  558. package/src/services/voice/pipeline.d.ts.map +1 -0
  559. package/src/services/voice/pipeline.ts +505 -0
  560. package/src/services/voice/prefill-client.d.ts +123 -0
  561. package/src/services/voice/prefill-client.d.ts.map +1 -0
  562. package/src/services/voice/prefill-client.ts +316 -0
  563. package/src/services/voice/prefix-preserving-queue.d.ts +113 -0
  564. package/src/services/voice/prefix-preserving-queue.d.ts.map +1 -0
  565. package/src/services/voice/prefix-preserving-queue.ts +162 -0
  566. package/src/services/voice/profile-store.d.ts +248 -0
  567. package/src/services/voice/profile-store.d.ts.map +1 -0
  568. package/src/services/voice/profile-store.ts +887 -0
  569. package/src/services/voice/real-audio-decode.test.ts +148 -0
  570. package/src/services/voice/ring-buffer.d.ts +40 -0
  571. package/src/services/voice/ring-buffer.d.ts.map +1 -0
  572. package/src/services/voice/ring-buffer.test.ts +129 -0
  573. package/src/services/voice/ring-buffer.ts +123 -0
  574. package/src/services/voice/rollback-queue.d.ts +24 -0
  575. package/src/services/voice/rollback-queue.d.ts.map +1 -0
  576. package/src/services/voice/rollback-queue.ts +74 -0
  577. package/src/services/voice/samantha-preset-placeholder.d.ts +67 -0
  578. package/src/services/voice/samantha-preset-placeholder.d.ts.map +1 -0
  579. package/src/services/voice/samantha-preset-placeholder.test.ts +97 -0
  580. package/src/services/voice/samantha-preset-placeholder.ts +148 -0
  581. package/src/services/voice/samantha-preset-regenerator.d.ts +87 -0
  582. package/src/services/voice/samantha-preset-regenerator.d.ts.map +1 -0
  583. package/src/services/voice/samantha-preset-regenerator.ts +393 -0
  584. package/src/services/voice/scheduler.d.ts +146 -0
  585. package/src/services/voice/scheduler.d.ts.map +1 -0
  586. package/src/services/voice/scheduler.t2.test.ts +141 -0
  587. package/src/services/voice/scheduler.ts +927 -0
  588. package/src/services/voice/shared-resources.d.ts +190 -0
  589. package/src/services/voice/shared-resources.d.ts.map +1 -0
  590. package/src/services/voice/shared-resources.ts +320 -0
  591. package/src/services/voice/speaker/attribution-pipeline.d.ts +74 -0
  592. package/src/services/voice/speaker/attribution-pipeline.d.ts.map +1 -0
  593. package/src/services/voice/speaker/attribution-pipeline.ts +386 -0
  594. package/src/services/voice/speaker/diarizer-fused.d.ts +59 -0
  595. package/src/services/voice/speaker/diarizer-fused.d.ts.map +1 -0
  596. package/src/services/voice/speaker/diarizer-fused.real.test.ts +100 -0
  597. package/src/services/voice/speaker/diarizer-fused.ts +154 -0
  598. package/src/services/voice/speaker/diarizer.d.ts +75 -0
  599. package/src/services/voice/speaker/diarizer.d.ts.map +1 -0
  600. package/src/services/voice/speaker/diarizer.ts +218 -0
  601. package/src/services/voice/speaker/encoder-fused.d.ts +60 -0
  602. package/src/services/voice/speaker/encoder-fused.d.ts.map +1 -0
  603. package/src/services/voice/speaker/encoder-fused.real.test.ts +113 -0
  604. package/src/services/voice/speaker/encoder-fused.ts +138 -0
  605. package/src/services/voice/speaker/encoder-ggml.d.ts +33 -0
  606. package/src/services/voice/speaker/encoder-ggml.d.ts.map +1 -0
  607. package/src/services/voice/speaker/encoder-ggml.ts +79 -0
  608. package/src/services/voice/speaker/encoder.d.ts +37 -0
  609. package/src/services/voice/speaker/encoder.d.ts.map +1 -0
  610. package/src/services/voice/speaker/encoder.ts +105 -0
  611. package/src/services/voice/speaker-imprint.d.ts +83 -0
  612. package/src/services/voice/speaker-imprint.d.ts.map +1 -0
  613. package/src/services/voice/speaker-imprint.test.ts +185 -0
  614. package/src/services/voice/speaker-imprint.ts +312 -0
  615. package/src/services/voice/speaker-preset-cache.d.ts +77 -0
  616. package/src/services/voice/speaker-preset-cache.d.ts.map +1 -0
  617. package/src/services/voice/speaker-preset-cache.test.ts +154 -0
  618. package/src/services/voice/speaker-preset-cache.ts +195 -0
  619. package/src/services/voice/streaming-asr/streaming-pipeline-adapter.ts +292 -0
  620. package/src/services/voice/system-audio-sink.d.ts +73 -0
  621. package/src/services/voice/system-audio-sink.d.ts.map +1 -0
  622. package/src/services/voice/system-audio-sink.test.ts +29 -0
  623. package/src/services/voice/system-audio-sink.ts +366 -0
  624. package/src/services/voice/transcriber.d.ts +244 -0
  625. package/src/services/voice/transcriber.d.ts.map +1 -0
  626. package/src/services/voice/transcriber.test.ts +392 -0
  627. package/src/services/voice/transcriber.ts +704 -0
  628. package/src/services/voice/transcript-knowledge.d.ts +37 -0
  629. package/src/services/voice/transcript-knowledge.d.ts.map +1 -0
  630. package/src/services/voice/transcript-knowledge.test.ts +68 -0
  631. package/src/services/voice/transcript-knowledge.ts +75 -0
  632. package/src/services/voice/transcript-service.d.ts +41 -0
  633. package/src/services/voice/transcript-service.d.ts.map +1 -0
  634. package/src/services/voice/transcript-service.test.ts +137 -0
  635. package/src/services/voice/transcript-service.ts +141 -0
  636. package/src/services/voice/transcript-store.d.ts +53 -0
  637. package/src/services/voice/transcript-store.d.ts.map +1 -0
  638. package/src/services/voice/transcript-store.test.ts +153 -0
  639. package/src/services/voice/transcript-store.ts +132 -0
  640. package/src/services/voice/turn-controller.d.ts +183 -0
  641. package/src/services/voice/turn-controller.d.ts.map +1 -0
  642. package/src/services/voice/turn-controller.test.ts +575 -0
  643. package/src/services/voice/turn-controller.ts +596 -0
  644. package/src/services/voice/types.d.ts +643 -0
  645. package/src/services/voice/types.d.ts.map +1 -0
  646. package/src/services/voice/types.ts +699 -0
  647. package/src/services/voice/vad.d.ts +282 -0
  648. package/src/services/voice/vad.d.ts.map +1 -0
  649. package/src/services/voice/vad.test.ts +480 -0
  650. package/src/services/voice/vad.ts +827 -0
  651. package/src/services/voice/vad.v1-v4.test.ts +222 -0
  652. package/src/services/voice/voice-budget.d.ts +241 -0
  653. package/src/services/voice/voice-budget.d.ts.map +1 -0
  654. package/src/services/voice/voice-budget.test.ts +418 -0
  655. package/src/services/voice/voice-budget.ts +635 -0
  656. package/src/services/voice/voice-duet.test.ts +375 -0
  657. package/src/services/voice/voice-emotion-classifier.d.ts +95 -0
  658. package/src/services/voice/voice-emotion-classifier.d.ts.map +1 -0
  659. package/src/services/voice/voice-emotion-classifier.test.ts +210 -0
  660. package/src/services/voice/voice-emotion-classifier.ts +273 -0
  661. package/src/services/voice/voice-preset-format.d.ts +158 -0
  662. package/src/services/voice/voice-preset-format.d.ts.map +1 -0
  663. package/src/services/voice/voice-preset-format.ts +700 -0
  664. package/src/services/voice/voice-preset-generator.test.ts +89 -0
  665. package/src/services/voice/voice-profile-artifact.d.ts +116 -0
  666. package/src/services/voice/voice-profile-artifact.d.ts.map +1 -0
  667. package/src/services/voice/voice-profile-artifact.test.ts +138 -0
  668. package/src/services/voice/voice-profile-artifact.ts +518 -0
  669. package/src/services/voice/voice-profile-routes.d.ts +83 -0
  670. package/src/services/voice/voice-profile-routes.d.ts.map +1 -0
  671. package/src/services/voice/voice-profile-routes.test.ts +429 -0
  672. package/src/services/voice/voice-profile-routes.ts +425 -0
  673. package/src/services/voice/voice-scenario.ts +154 -0
  674. package/src/services/voice/voice-settings.d.ts +82 -0
  675. package/src/services/voice/voice-settings.d.ts.map +1 -0
  676. package/src/services/voice/voice-settings.ts +172 -0
  677. package/src/services/voice/voice-state-machine.d.ts +364 -0
  678. package/src/services/voice/voice-state-machine.d.ts.map +1 -0
  679. package/src/services/voice/voice-state-machine.ts +727 -0
  680. package/src/services/voice/voice-workbench-report.test.ts +168 -0
  681. package/src/services/voice/voice-workbench-report.ts +326 -0
  682. package/src/services/voice/voice-workbench.test.ts +158 -0
  683. package/src/services/voice/voice.test.ts +1070 -0
  684. package/src/services/voice/wake-word-ggml.d.ts +101 -0
  685. package/src/services/voice/wake-word-ggml.d.ts.map +1 -0
  686. package/src/services/voice/wake-word-ggml.ts +320 -0
  687. package/src/services/voice/wake-word.d.ts +255 -0
  688. package/src/services/voice/wake-word.d.ts.map +1 -0
  689. package/src/services/voice/wake-word.test.ts +298 -0
  690. package/src/services/voice/wake-word.ts +554 -0
  691. package/src/services/voice/wrap-with-first-line-cache.d.ts +70 -0
  692. package/src/services/voice/wrap-with-first-line-cache.d.ts.map +1 -0
  693. package/src/services/voice/wrap-with-first-line-cache.ts +267 -0
  694. package/src/services/voice-model-updater.d.ts +240 -0
  695. package/src/services/voice-model-updater.d.ts.map +1 -0
  696. package/src/services/voice-model-updater.ts +724 -0
  697. package/src/services/voice-prewarm.d.ts +3 -0
  698. package/src/services/voice-prewarm.d.ts.map +1 -0
  699. package/src/services/voice-prewarm.ts +51 -0
  700. package/dist/index.d.ts +0 -37
  701. package/dist/index.js +0 -1098
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Voice first-run route: create a family-member voice profile.
3
+ *
4
+ * Route:
5
+ * POST /v1/voice/first-run/family-member
6
+ * Body (JSON):
7
+ * {
8
+ * audioBase64: string, // raw base64-encoded audio (webm/wav/ogg)
9
+ * durationMs: number, // client-measured capture length
10
+ * displayName: string, // e.g. "Alex"
11
+ * relationship: string, // free-form label, e.g. "spouse", "colleague"
12
+ * ownerEntityId?: string // optional — stored on the profile for edge creation
13
+ * }
14
+ * Response:
15
+ * {
16
+ * profileId: string, // content-addressed vp_<sha> id
17
+ * entityId: string, // freshly minted UUID for the family-member entity
18
+ * displayName: string,
19
+ * relationship: string,
20
+ * relationshipTag: "family_of"
21
+ * }
22
+ *
23
+ * Audio pipeline (mirrors voice-first-run-routes.ts):
24
+ * 1. Decode base64 → Buffer → Float32 PCM (assumes 16 kHz, mono).
25
+ * 2. Encode via the fused `FusedSpeakerEncoder` → 256-dim centroid.
26
+ * 3. Store in VoiceProfileStore (non-OWNER entity binding).
27
+ *
28
+ * Graceful degradation: when the fused libelizainference (or its speaker ABI)
29
+ * is unavailable the route returns a 503. The client-side adapter
30
+ * (`VoiceProfilesClient`) falls back to a client-side pending profile so the UI
31
+ * flow is not blocked.
32
+ *
33
+ * The `family_of` relationship edge is recorded in profile metadata so a
34
+ * runtime-level consumer (e.g. voice-first-run-complete handler) can create
35
+ * the real Entity + Relationship rows after the runtime is up. The route
36
+ * itself does not call IAgentRuntime because HTTP route handlers in this
37
+ * plugin do not hold a runtime reference.
38
+ */
39
+
40
+ import crypto from "node:crypto";
41
+ import type * as http from "node:http";
42
+ import path from "node:path";
43
+ import {
44
+ logger,
45
+ readJsonBody,
46
+ resolveStateDir,
47
+ sendJson,
48
+ sendJsonError,
49
+ } from "@elizaos/core";
50
+ import { resolveFusedLibraryPath } from "../services/desktop-fused-ffi-backend-runtime.js";
51
+ import { loadElizaInferenceFfi } from "../services/voice/ffi-bindings.js";
52
+ import { VoiceProfileStore } from "../services/voice/profile-store.js";
53
+ import {
54
+ type SpeakerEncoder,
55
+ SpeakerEncoderUnavailableError,
56
+ WESPEAKER_EMBEDDING_DIM,
57
+ WESPEAKER_MIN_SAMPLES,
58
+ WESPEAKER_RESNET34_LM_INT8_MODEL_ID,
59
+ WESPEAKER_SAMPLE_RATE,
60
+ } from "../services/voice/speaker/encoder.js";
61
+ import { FusedSpeakerEncoder } from "../services/voice/speaker/encoder-fused.js";
62
+
63
+ // ---------------------------------------------------------------------------
64
+ // Injectable test hooks (mirrors voice-first-run-routes.ts)
65
+ // ---------------------------------------------------------------------------
66
+
67
+ export type FamilyMemberEncoderFactory = () => Promise<SpeakerEncoder>;
68
+
69
+ let encoderFactoryOverride: FamilyMemberEncoderFactory | null = null;
70
+ let cachedEncoder: SpeakerEncoder | null = null;
71
+
72
+ export function setFamilyMemberEncoderFactory(
73
+ factory: FamilyMemberEncoderFactory | null,
74
+ ): void {
75
+ encoderFactoryOverride = factory;
76
+ cachedEncoder = null;
77
+ }
78
+
79
+ let profileStoreOverride: VoiceProfileStore | null = null;
80
+
81
+ export function setFamilyMemberProfileStore(
82
+ store: VoiceProfileStore | null,
83
+ ): void {
84
+ profileStoreOverride = store;
85
+ }
86
+
87
+ // ---------------------------------------------------------------------------
88
+ // Loader helpers
89
+ // ---------------------------------------------------------------------------
90
+
91
+ async function loadEncoder(): Promise<SpeakerEncoder> {
92
+ if (cachedEncoder) return cachedEncoder;
93
+ if (encoderFactoryOverride) {
94
+ cachedEncoder = await encoderFactoryOverride();
95
+ return cachedEncoder;
96
+ }
97
+ cachedEncoder = await loadFusedSpeakerEncoder();
98
+ return cachedEncoder;
99
+ }
100
+
101
+ /**
102
+ * Load the fused speaker encoder through the `eliza_inference_speaker_*` ABI —
103
+ * the sole on-device speaker runtime. Probes the speaker ABI up front: a build
104
+ * that lacks it raises a structured `SpeakerEncoderUnavailableError` (the route
105
+ * surfaces a 503) rather than degrading silently. No standalone-lib fallback.
106
+ */
107
+ async function loadFusedSpeakerEncoder(): Promise<SpeakerEncoder> {
108
+ const bundleRoot = path.join(resolveStateDir(), "voice-profiles");
109
+ const libPath = resolveFusedLibraryPath(bundleRoot);
110
+ if (!libPath) {
111
+ throw new SpeakerEncoderUnavailableError(
112
+ "library-missing",
113
+ "[family-member-route] fused libelizainference not found. Set $ELIZA_INFERENCE_LIBRARY (exact path) or $ELIZA_INFERENCE_LIB_DIR, or build it via packages/app-core/scripts/build-llama-cpp-mtp.mjs.",
114
+ );
115
+ }
116
+ const ffi = loadElizaInferenceFfi(libPath);
117
+ if (!FusedSpeakerEncoder.isSupported(ffi)) {
118
+ throw new SpeakerEncoderUnavailableError(
119
+ "native-missing",
120
+ `[family-member-route] the fused libelizainference at ${libPath} (ABI v${ffi.libraryAbiVersion}) lacks the speaker ABI (eliza_inference_speaker_supported() == 0). Rebuild with the WeSpeaker forward graph linked in.`,
121
+ );
122
+ }
123
+ const ctx = ffi.create(bundleRoot);
124
+ return FusedSpeakerEncoder.load({ ffi, ctx });
125
+ }
126
+
127
+ async function getProfileStore(): Promise<VoiceProfileStore> {
128
+ if (profileStoreOverride) return profileStoreOverride;
129
+ const store = new VoiceProfileStore({
130
+ rootDir: path.join(resolveStateDir(), "voice-profiles"),
131
+ });
132
+ await store.init();
133
+ return store;
134
+ }
135
+
136
+ // ---------------------------------------------------------------------------
137
+ // Request body validation
138
+ // ---------------------------------------------------------------------------
139
+
140
+ interface FamilyMemberBody {
141
+ audioBase64: string;
142
+ durationMs: number;
143
+ displayName: string;
144
+ relationship: string;
145
+ ownerEntityId?: string | null;
146
+ }
147
+
148
+ function parseFamilyMemberBody(
149
+ raw: Record<string, unknown>,
150
+ ): FamilyMemberBody | string {
151
+ const audioBase64 =
152
+ typeof raw.audioBase64 === "string" ? raw.audioBase64.trim() : null;
153
+ if (!audioBase64) return "audioBase64 is required";
154
+
155
+ const durationMs =
156
+ typeof raw.durationMs === "number" && raw.durationMs > 0
157
+ ? raw.durationMs
158
+ : null;
159
+ if (durationMs === null) return "durationMs must be a positive number";
160
+
161
+ const displayName =
162
+ typeof raw.displayName === "string" && raw.displayName.trim().length > 0
163
+ ? raw.displayName.trim()
164
+ : null;
165
+ if (!displayName) return "displayName is required";
166
+
167
+ const relationship =
168
+ typeof raw.relationship === "string" && raw.relationship.trim().length > 0
169
+ ? raw.relationship.trim()
170
+ : "family";
171
+
172
+ const ownerEntityId =
173
+ typeof raw.ownerEntityId === "string" && raw.ownerEntityId.trim()
174
+ ? raw.ownerEntityId.trim()
175
+ : null;
176
+
177
+ return { audioBase64, durationMs, displayName, relationship, ownerEntityId };
178
+ }
179
+
180
+ // ---------------------------------------------------------------------------
181
+ // PCM decode
182
+ // ---------------------------------------------------------------------------
183
+
184
+ function decodeBase64ToPcm(audioBase64: string): Float32Array | string {
185
+ let rawBuf: Buffer;
186
+ try {
187
+ rawBuf = Buffer.from(audioBase64, "base64");
188
+ } catch {
189
+ return "failed to decode audioBase64";
190
+ }
191
+ if (rawBuf.byteLength % 4 !== 0) {
192
+ return `PCM buffer length ${rawBuf.byteLength} is not a multiple of 4 (expected raw Float32 PCM)`;
193
+ }
194
+ const out = new Float32Array(rawBuf.byteLength / 4);
195
+ const view = new DataView(
196
+ rawBuf.buffer,
197
+ rawBuf.byteOffset,
198
+ rawBuf.byteLength,
199
+ );
200
+ for (let i = 0; i < out.length; i += 1) {
201
+ out[i] = view.getFloat32(i * 4, true);
202
+ }
203
+ return out;
204
+ }
205
+
206
+ // ---------------------------------------------------------------------------
207
+ // Route handler
208
+ // ---------------------------------------------------------------------------
209
+
210
+ /** Relationship tag written to profile metadata and echoed in response. */
211
+ export const FAMILY_OF_TAG = "family_of" as const;
212
+
213
+ export interface FamilyMemberResult {
214
+ profileId: string;
215
+ entityId: string;
216
+ displayName: string;
217
+ relationship: string;
218
+ relationshipTag: typeof FAMILY_OF_TAG;
219
+ ownerEntityId: string | null;
220
+ }
221
+
222
+ /**
223
+ * Handle `POST /v1/voice/first-run/family-member`.
224
+ *
225
+ * Returns `true` when the request was handled (success or error response
226
+ * written), `false` when the path does not match this handler.
227
+ */
228
+ export async function handleFamilyMemberRoute(
229
+ req: http.IncomingMessage,
230
+ res: http.ServerResponse,
231
+ ): Promise<boolean> {
232
+ const method = (req.method ?? "GET").toUpperCase();
233
+ const url = new URL(req.url ?? "/", "http://localhost");
234
+ const pathname = url.pathname;
235
+
236
+ if (method !== "POST" || pathname !== "/v1/voice/first-run/family-member") {
237
+ return false;
238
+ }
239
+
240
+ const raw = await readJsonBody<Record<string, unknown>>(req, res);
241
+ if (!raw) return true; // readJsonBody already sent a 4xx
242
+
243
+ const parsed = parseFamilyMemberBody(raw);
244
+ if (typeof parsed === "string") {
245
+ sendJsonError(res, parsed, 400);
246
+ return true;
247
+ }
248
+
249
+ const { audioBase64, durationMs, displayName, relationship, ownerEntityId } =
250
+ parsed;
251
+
252
+ // Decode audio.
253
+ const pcmOrError = decodeBase64ToPcm(audioBase64);
254
+ if (typeof pcmOrError === "string") {
255
+ sendJsonError(res, pcmOrError, 400);
256
+ return true;
257
+ }
258
+ const pcm = pcmOrError;
259
+
260
+ if (pcm.length < WESPEAKER_MIN_SAMPLES) {
261
+ sendJsonError(
262
+ res,
263
+ `capture too short: ${pcm.length} PCM samples (< ${WESPEAKER_MIN_SAMPLES} required for ${WESPEAKER_SAMPLE_RATE} Hz encoder). Minimum ~${Math.ceil((WESPEAKER_MIN_SAMPLES / WESPEAKER_SAMPLE_RATE) * 1000)}ms.`,
264
+ 400,
265
+ );
266
+ return true;
267
+ }
268
+
269
+ // Encode via WeSpeaker.
270
+ let encoder: SpeakerEncoder;
271
+ try {
272
+ encoder = await loadEncoder();
273
+ } catch (err) {
274
+ if (err instanceof SpeakerEncoderUnavailableError) {
275
+ sendJsonError(res, err.message, 503);
276
+ return true;
277
+ }
278
+ throw err;
279
+ }
280
+
281
+ let centroid: Float32Array;
282
+ try {
283
+ centroid = await encoder.encode(pcm);
284
+ } catch (err) {
285
+ if (err instanceof SpeakerEncoderUnavailableError) {
286
+ sendJsonError(res, err.message, err.code === "invalid-input" ? 400 : 503);
287
+ return true;
288
+ }
289
+ throw err;
290
+ }
291
+
292
+ if (centroid.length !== WESPEAKER_EMBEDDING_DIM) {
293
+ sendJsonError(
294
+ res,
295
+ `centroid dim mismatch: ${centroid.length} != ${WESPEAKER_EMBEDDING_DIM}`,
296
+ 500,
297
+ );
298
+ return true;
299
+ }
300
+
301
+ // Generate a stable entity ID for the family member.
302
+ const entityId = crypto.randomUUID();
303
+
304
+ // Store the profile in VoiceProfileStore.
305
+ const store = await getProfileStore();
306
+ let profile: Awaited<ReturnType<VoiceProfileStore["createProfile"]>>;
307
+ try {
308
+ profile = await store.createProfile({
309
+ centroid,
310
+ embeddingModel: WESPEAKER_RESNET34_LM_INT8_MODEL_ID,
311
+ entityId,
312
+ confidence: 0.85,
313
+ durationMs,
314
+ consent: {
315
+ attributionAuthorized: true,
316
+ synthesisAuthorized: false,
317
+ grantedAt: new Date().toISOString(),
318
+ grantedBy: ownerEntityId ?? undefined,
319
+ },
320
+ metadata: {
321
+ displayName,
322
+ relationship,
323
+ cohort: "family",
324
+ source: "first-run",
325
+ relationshipTag: FAMILY_OF_TAG,
326
+ ownerEntityId: ownerEntityId ?? null,
327
+ },
328
+ });
329
+ } catch (err) {
330
+ logger.error(
331
+ { err, displayName, relationship },
332
+ "[family-member-route] failed to create voice profile",
333
+ );
334
+ sendJsonError(
335
+ res,
336
+ err instanceof Error ? err.message : "failed to create voice profile",
337
+ 500,
338
+ );
339
+ return true;
340
+ }
341
+
342
+ const result: FamilyMemberResult = {
343
+ profileId: profile.profileId,
344
+ entityId,
345
+ displayName,
346
+ relationship,
347
+ relationshipTag: FAMILY_OF_TAG,
348
+ ownerEntityId: ownerEntityId ?? null,
349
+ };
350
+
351
+ sendJson(res, result);
352
+ return true;
353
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Route-side exports for plugin-local-inference.
3
+ *
4
+ * Consumers (app-core/api/server.ts) import from
5
+ * `@elizaos/plugin-local-inference/routes` to mount the HTTP compat routes
6
+ * for model catalog, downloads, status, and chat commands.
7
+ */
8
+ export { handleVoiceProfileRoutes, registerProfileInCatalog, resolveDefaultProfileId, type VoiceProfileCatalog, type VoiceProfileCatalogEntry, type VoiceProfileRouteOptions, } from "../services/voice/voice-profile-routes.js";
9
+ export { FAMILY_OF_TAG, type FamilyMemberEncoderFactory, type FamilyMemberResult, handleFamilyMemberRoute, setFamilyMemberEncoderFactory, setFamilyMemberProfileStore, } from "./family-member-route.js";
10
+ export { handleLiveDiarizationRoute, resetLiveDiarizationSession, } from "./live-diarization-route.js";
11
+ export * from "./local-inference-asr-route.js";
12
+ export * from "./local-inference-compat-routes.js";
13
+ export * from "./local-inference-tts-route.js";
14
+ export { __resetVoiceFirstRunSessions, type EncoderFactory as VoiceFirstRunEncoderFactory, FIRST_RUN_SCRIPT, type FirstRunScriptStep, handleVoiceFirstRunRoutes, setVoiceFirstRunEncoderFactory, setVoiceFirstRunProfileStore, setVoiceFirstRunSettingsWriter, } from "./voice-first-run-routes.js";
15
+ export { handleVoiceModelsRoutes, resolveInstalledVersions as resolveInstalledVoiceModelVersions, setVoiceModelDownloader, setVoiceModelsBundleVersionForTest, setVoiceModelsUpdater, type VoiceModelInstallationView, } from "./voice-models-routes.js";
16
+ export { voiceProfilePluginRoutes } from "./voice-profile-plugin-routes.js";
17
+ export { handleVoiceProfilesManagementRoutes, setVoiceProfilesManagementStore, type VoiceProfileDto, } from "./voice-profiles-management-routes.js";
18
+ export { handleVoiceSpeakerProfileRoutes, type SpeakerProfileSummary, setVoiceSpeakerProfileStore, } from "./voice-speaker-profile-routes.js";
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACN,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,GAC7B,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACN,aAAa,EACb,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,uBAAuB,EACvB,6BAA6B,EAC7B,2BAA2B,GAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,0BAA0B,EAC1B,2BAA2B,GAC3B,MAAM,6BAA6B,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC;AACnD,cAAc,gCAAgC,CAAC;AAC/C,OAAO,EACN,4BAA4B,EAC5B,KAAK,cAAc,IAAI,2BAA2B,EAClD,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,yBAAyB,EACzB,8BAA8B,EAC9B,4BAA4B,EAC5B,8BAA8B,GAC9B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACN,uBAAuB,EACvB,wBAAwB,IAAI,kCAAkC,EAC9D,uBAAuB,EACvB,kCAAkC,EAClC,qBAAqB,EACrB,KAAK,0BAA0B,GAC/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EACN,mCAAmC,EACnC,+BAA+B,EAC/B,KAAK,eAAe,GACpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EACN,+BAA+B,EAC/B,KAAK,qBAAqB,EAC1B,2BAA2B,GAC3B,MAAM,mCAAmC,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Route-side exports for plugin-local-inference.
3
+ *
4
+ * Consumers (app-core/api/server.ts) import from
5
+ * `@elizaos/plugin-local-inference/routes` to mount the HTTP compat routes
6
+ * for model catalog, downloads, status, and chat commands.
7
+ */
8
+
9
+ export {
10
+ handleVoiceProfileRoutes,
11
+ registerProfileInCatalog,
12
+ resolveDefaultProfileId,
13
+ type VoiceProfileCatalog,
14
+ type VoiceProfileCatalogEntry,
15
+ type VoiceProfileRouteOptions,
16
+ } from "../services/voice/voice-profile-routes.js";
17
+ export {
18
+ FAMILY_OF_TAG,
19
+ type FamilyMemberEncoderFactory,
20
+ type FamilyMemberResult,
21
+ handleFamilyMemberRoute,
22
+ setFamilyMemberEncoderFactory,
23
+ setFamilyMemberProfileStore,
24
+ } from "./family-member-route.js";
25
+ export {
26
+ handleLiveDiarizationRoute,
27
+ resetLiveDiarizationSession,
28
+ } from "./live-diarization-route.js";
29
+ export * from "./local-inference-asr-route.js";
30
+ export * from "./local-inference-compat-routes.js";
31
+ export * from "./local-inference-tts-route.js";
32
+ export {
33
+ __resetVoiceFirstRunSessions,
34
+ type EncoderFactory as VoiceFirstRunEncoderFactory,
35
+ FIRST_RUN_SCRIPT,
36
+ type FirstRunScriptStep,
37
+ handleVoiceFirstRunRoutes,
38
+ setVoiceFirstRunEncoderFactory,
39
+ setVoiceFirstRunProfileStore,
40
+ setVoiceFirstRunSettingsWriter,
41
+ } from "./voice-first-run-routes.js";
42
+ export {
43
+ handleVoiceModelsRoutes,
44
+ resolveInstalledVersions as resolveInstalledVoiceModelVersions,
45
+ setVoiceModelDownloader,
46
+ setVoiceModelsBundleVersionForTest,
47
+ setVoiceModelsUpdater,
48
+ type VoiceModelInstallationView,
49
+ } from "./voice-models-routes.js";
50
+ export { voiceProfilePluginRoutes } from "./voice-profile-plugin-routes.js";
51
+ export {
52
+ handleVoiceProfilesManagementRoutes,
53
+ setVoiceProfilesManagementStore,
54
+ type VoiceProfileDto,
55
+ } from "./voice-profiles-management-routes.js";
56
+ export {
57
+ handleVoiceSpeakerProfileRoutes,
58
+ type SpeakerProfileSummary,
59
+ setVoiceSpeakerProfileStore,
60
+ } from "./voice-speaker-profile-routes.js";
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `/api/voice/audio-frames` — WebView → agent transport for live on-device
3
+ * speaker diarization.
4
+ *
5
+ * The Android `audioFrame` PCM stream is captured in the Capacitor WebView but
6
+ * the bun:ffi voice libs run in the agent process. The WebView batches frames
7
+ * (~49 fps) and POSTs them here; this route feeds them to the single
8
+ * {@link LiveDiarizationSession}, which runs the real ggml VAD / encoder /
9
+ * diarizer / attribution pipeline and emits VOICE_TURN_OBSERVED.
10
+ *
11
+ * Routes:
12
+ * POST /api/voice/audio-frames body: { frames: AudioFrameEvent[],
13
+ * flush?: boolean }
14
+ * → { ok, framesReceived, turnsObserved }
15
+ * GET /api/voice/audio-frames/status → LiveDiarizationStatus (device evidence)
16
+ *
17
+ * Auth follows the compat pattern: trusted-loopback OR the compat API token.
18
+ * The WebView reaches this over 127.0.0.1 (trusted local), matching the rest of
19
+ * the on-device agent surface.
20
+ */
21
+ import type http from "node:http";
22
+ import { type CompatRuntimeState } from "./compat-helpers.js";
23
+ /** Reset the module-level session (tests + capture teardown). */
24
+ export declare function resetLiveDiarizationSession(): Promise<void>;
25
+ export declare function handleLiveDiarizationRoute(req: http.IncomingMessage, res: http.ServerResponse, state: CompatRuntimeState): Promise<boolean>;
26
+ //# sourceMappingURL=live-diarization-route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-diarization-route.d.ts","sourceRoot":"","sources":["live-diarization-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAMlC,OAAO,EACN,KAAK,kBAAkB,EAKvB,MAAM,qBAAqB,CAAC;AAY7B,iEAAiE;AACjE,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAIjE;AAgBD,wBAAsB,0BAA0B,CAC/C,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,KAAK,EAAE,kBAAkB,GACvB,OAAO,CAAC,OAAO,CAAC,CAmDlB"}
@@ -0,0 +1,213 @@
1
+ /**
2
+ * live-diarization-route unit tests (HTTP-level, no GGUF models).
3
+ *
4
+ * Exercises the WebView → agent transport route's request/response contract:
5
+ * - loopback (trusted-local) auth pass-through;
6
+ * - non-loopback rejection (401);
7
+ * - frame-shape validation (rejects malformed frames);
8
+ * - the status route surfaces the model/lib resolution (and, on a host with
9
+ * no on-device GGUFs, the precise "voice GGUFs missing" blocker — the same
10
+ * readiness payload the device read returns).
11
+ *
12
+ * The model-heavy path (real ggml VAD/encoder/diarizer) is covered by the
13
+ * host smoke harness (`packages/app-core/scripts/voice-attribution-smoke.ts`),
14
+ * which exercises the same AudioFrameConsumer with real models.
15
+ */
16
+
17
+ import type http from "node:http";
18
+ import { Readable } from "node:stream";
19
+ import { afterEach, describe, expect, it } from "vitest";
20
+ import type { CompatRuntimeState } from "./compat-helpers.js";
21
+ import {
22
+ handleLiveDiarizationRoute,
23
+ resetLiveDiarizationSession,
24
+ } from "./live-diarization-route.js";
25
+
26
+ class FakeRes {
27
+ statusCode = 200;
28
+ headersSent = false;
29
+ private readonly headers = new Map<string, string>();
30
+ body = "";
31
+ ended = false;
32
+ setHeader(name: string, value: string): void {
33
+ this.headers.set(name.toLowerCase(), value);
34
+ }
35
+ end(chunk?: string): void {
36
+ if (chunk) this.body += chunk;
37
+ this.ended = true;
38
+ this.headersSent = true;
39
+ }
40
+ json(): unknown {
41
+ return JSON.parse(this.body);
42
+ }
43
+ }
44
+
45
+ function makeReq(opts: {
46
+ method: string;
47
+ url: string;
48
+ body?: unknown;
49
+ remoteAddress?: string;
50
+ host?: string;
51
+ }): http.IncomingMessage {
52
+ const payload = opts.body !== undefined ? JSON.stringify(opts.body) : "";
53
+ const stream = Readable.from(payload ? [Buffer.from(payload)] : []);
54
+ const req = stream as unknown as http.IncomingMessage & {
55
+ method: string;
56
+ url: string;
57
+ headers: Record<string, string>;
58
+ socket: { remoteAddress: string };
59
+ };
60
+ req.method = opts.method;
61
+ req.url = opts.url;
62
+ req.headers = { host: opts.host ?? "127.0.0.1:31337" };
63
+ req.socket = { remoteAddress: opts.remoteAddress ?? "127.0.0.1" } as never;
64
+ return req;
65
+ }
66
+
67
+ const runtimeState = (): CompatRuntimeState => ({
68
+ current: {
69
+ emitEvent: async () => {},
70
+ } as never,
71
+ });
72
+
73
+ /** A well-formed AudioFrameEvent (20 ms silence frame). */
74
+ function silentFrame(frameIndex: number) {
75
+ const samples = 320;
76
+ const pcm16 = Buffer.alloc(samples * 2).toString("base64");
77
+ return {
78
+ pcm16,
79
+ sampleRate: 16_000,
80
+ channels: 1,
81
+ samples,
82
+ rms: 0,
83
+ timestamp: frameIndex * 20,
84
+ frameIndex,
85
+ };
86
+ }
87
+
88
+ afterEach(async () => {
89
+ await resetLiveDiarizationSession();
90
+ });
91
+
92
+ describe("handleLiveDiarizationRoute", () => {
93
+ it("returns false for an unrelated path (passes through)", async () => {
94
+ const res = new FakeRes();
95
+ const handled = await handleLiveDiarizationRoute(
96
+ makeReq({ method: "GET", url: "/api/unrelated" }),
97
+ res as unknown as http.ServerResponse,
98
+ runtimeState(),
99
+ );
100
+ expect(handled).toBe(false);
101
+ expect(res.ended).toBe(false);
102
+ });
103
+
104
+ it("rejects a non-loopback caller with 401", async () => {
105
+ const res = new FakeRes();
106
+ const handled = await handleLiveDiarizationRoute(
107
+ makeReq({
108
+ method: "GET",
109
+ url: "/api/voice/audio-frames/status",
110
+ remoteAddress: "10.0.0.5",
111
+ host: "example.com",
112
+ }),
113
+ res as unknown as http.ServerResponse,
114
+ runtimeState(),
115
+ );
116
+ expect(handled).toBe(true);
117
+ expect(res.statusCode).toBe(401);
118
+ });
119
+
120
+ it("status route surfaces model/lib resolution (blocker on a host without device GGUFs)", async () => {
121
+ const res = new FakeRes();
122
+ const handled = await handleLiveDiarizationRoute(
123
+ makeReq({ method: "GET", url: "/api/voice/audio-frames/status" }),
124
+ res as unknown as http.ServerResponse,
125
+ runtimeState(),
126
+ );
127
+ expect(handled).toBe(true);
128
+ expect(res.statusCode).toBe(200);
129
+ const status = res.json() as {
130
+ ready: boolean;
131
+ libs: { fusedInference: string | null };
132
+ models: { dir: string };
133
+ framesReceived: number;
134
+ turnsObserved: number;
135
+ error?: string;
136
+ };
137
+ // On CI/host there is no fused libelizainference, so readiness fails with
138
+ // a precise blocker rather than a silent default — the device-evidence
139
+ // read. The session now runs the whole stack (VAD/encoder/diarizer)
140
+ // through the one fused FFI handle, not separate bun:ffi-musl libs.
141
+ expect(typeof status.models.dir).toBe("string");
142
+ expect("fusedInference" in status.libs).toBe(true);
143
+ expect(status.framesReceived).toBe(0);
144
+ expect(status.turnsObserved).toBe(0);
145
+ if (!status.ready) {
146
+ expect(status.error).toMatch(
147
+ /fused libelizainference|ABI|FFI|libelizainference/i,
148
+ );
149
+ }
150
+ });
151
+
152
+ it("rejects a malformed frame batch with 400", async () => {
153
+ const res = new FakeRes();
154
+ const handled = await handleLiveDiarizationRoute(
155
+ makeReq({
156
+ method: "POST",
157
+ url: "/api/voice/audio-frames",
158
+ body: { frames: [{ pcm16: "AA==" /* missing fields */ }] },
159
+ }),
160
+ res as unknown as http.ServerResponse,
161
+ runtimeState(),
162
+ );
163
+ expect(handled).toBe(true);
164
+ expect(res.statusCode).toBe(400);
165
+ expect((res.json() as { error: string }).error).toMatch(/Malformed/);
166
+ });
167
+
168
+ it("rejects a non-array frames field with 400", async () => {
169
+ const res = new FakeRes();
170
+ const handled = await handleLiveDiarizationRoute(
171
+ makeReq({
172
+ method: "POST",
173
+ url: "/api/voice/audio-frames",
174
+ body: { frames: "nope" },
175
+ }),
176
+ res as unknown as http.ServerResponse,
177
+ runtimeState(),
178
+ );
179
+ expect(handled).toBe(true);
180
+ expect(res.statusCode).toBe(400);
181
+ });
182
+
183
+ it("accepts a well-formed batch shape (validation passes before model build)", async () => {
184
+ // Well-formed frames clear the route's shape gate. Without on-device GGUFs
185
+ // the session build then throws; the route surfaces that as a 500-class
186
+ // failure, NOT a 400 — proving the wire contract is satisfied.
187
+ const res = new FakeRes();
188
+ const handled = await handleLiveDiarizationRoute(
189
+ makeReq({
190
+ method: "POST",
191
+ url: "/api/voice/audio-frames",
192
+ body: { frames: [silentFrame(0), silentFrame(1)] },
193
+ }),
194
+ res as unknown as http.ServerResponse,
195
+ runtimeState(),
196
+ ).catch(() => "threw");
197
+ // Either it threw inside ingest (no models) or returned true; either way
198
+ // the request was NOT rejected as malformed (no 400).
199
+ expect(res.statusCode).not.toBe(400);
200
+ expect(handled === true || handled === "threw").toBe(true);
201
+ });
202
+
203
+ it("returns 503 when the runtime is not ready", async () => {
204
+ const res = new FakeRes();
205
+ const handled = await handleLiveDiarizationRoute(
206
+ makeReq({ method: "GET", url: "/api/voice/audio-frames/status" }),
207
+ res as unknown as http.ServerResponse,
208
+ { current: null },
209
+ );
210
+ expect(handled).toBe(true);
211
+ expect(res.statusCode).toBe(503);
212
+ });
213
+ });