@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,728 @@
1
+ /**
2
+ * Tests for the libelizainference FFI binding.
3
+ *
4
+ * Two layers of coverage:
5
+ *
6
+ * 1. Pure unit tests run in the vitest worker (Node 22 in this repo's
7
+ * CI). They exercise the runtime detection + structured error
8
+ * surface — calling `loadElizaInferenceFfi` from a non-Bun runtime
9
+ * must throw `VoiceLifecycleError({code:"kernel-missing"})` rather
10
+ * than crashing.
11
+ *
12
+ * 2. Integration tests spawn a `bun` subprocess that imports
13
+ * `ffi-bindings.ts` and exercises every entry point against the
14
+ * stub `libelizainference_stub.{dylib,so}` produced by
15
+ * `scripts/ffi-stub/Makefile`. This validates that:
16
+ * - `dlopen` succeeds against a real shared library,
17
+ * - the `create`/`destroy` round-trip works,
18
+ * - methods that need the fused build (e.g. `ttsSynthesize`)
19
+ * return ELIZA_ERR_NOT_IMPLEMENTED and the binding surfaces it
20
+ * as a structured `VoiceLifecycleError` — never a crash, never
21
+ * a fabricated successful response,
22
+ * - ABI version mismatch is caught at load time.
23
+ *
24
+ * Per `packages/inference/AGENTS.md` §3 + §9 every failure path is a
25
+ * structured error. The integration-test harness asserts on the JSON
26
+ * report the bun subprocess emits to stdout — a missing or malformed
27
+ * report fails the test.
28
+ */
29
+
30
+ import { spawnSync } from "node:child_process";
31
+ import {
32
+ existsSync,
33
+ mkdtempSync,
34
+ readFileSync,
35
+ rmSync,
36
+ statSync,
37
+ writeFileSync,
38
+ } from "node:fs";
39
+ import { tmpdir } from "node:os";
40
+ import path from "node:path";
41
+ import { fileURLToPath } from "node:url";
42
+ import { describe, expect, it } from "vitest";
43
+ import { fakeFfi } from "./__test-helpers__/fake-ffi";
44
+ import type { ElizaInferenceFfi, TtsStreamChunk } from "./ffi-bindings";
45
+ import {
46
+ ELIZA_ERR_CANCELLED,
47
+ ELIZA_ERR_NOT_IMPLEMENTED,
48
+ ELIZA_INFERENCE_ABI_VERSION,
49
+ ELIZA_OK,
50
+ loadElizaInferenceFfi,
51
+ recoverAsrWords,
52
+ } from "./ffi-bindings";
53
+ import { VoiceLifecycleError } from "./lifecycle";
54
+
55
+ describe("recoverAsrWords (v12 timed-ASR word recovery)", () => {
56
+ it("zips ASCII-split word texts against the native timing arrays", () => {
57
+ const words = recoverAsrWords(
58
+ "turn on the lights",
59
+ 4,
60
+ new Int32Array([0, 250, 380, 520]),
61
+ new Int32Array([250, 380, 520, 1000]),
62
+ );
63
+ expect(words).toEqual([
64
+ { text: "turn", startMs: 0, endMs: 250 },
65
+ { text: "on", startMs: 250, endMs: 380 },
66
+ { text: "the", startMs: 380, endMs: 520 },
67
+ { text: "lights", startMs: 520, endMs: 1000 },
68
+ ]);
69
+ });
70
+
71
+ it("mirrors the native ASCII split so NBSP does NOT collapse a word boundary", () => {
72
+ // Native sizes the timing arrays with an ASCII-whitespace split, so a
73
+ // non-ASCII space (NBSP, U+00A0) stays INSIDE one word -> count=2. The old
74
+ // Unicode \s split produced 3 tokens and mis-zipped them onto 2 timings
75
+ // (a dropped word + text shifted off its timing). The ASCII-mirrored split
76
+ // yields exactly the native 2 words, correctly aligned.
77
+ const words = recoverAsrWords(
78
+ "a b\u00A0c",
79
+ 2,
80
+ new Int32Array([0, 100]),
81
+ new Int32Array([100, 300]),
82
+ );
83
+ expect(words).toEqual([
84
+ { text: "a", startMs: 0, endMs: 100 },
85
+ { text: "b\u00A0c", startMs: 100, endMs: 300 },
86
+ ]);
87
+ });
88
+
89
+ it("drops trailing untimed words when the native word cap truncated count", () => {
90
+ // Native capped at 2 words (count=2) though the transcript has 4; only the
91
+ // first two carry timings, the rest are dropped — never mis-zipped.
92
+ const words = recoverAsrWords(
93
+ "one two three four",
94
+ 2,
95
+ new Int32Array([0, 300]),
96
+ new Int32Array([300, 600]),
97
+ );
98
+ expect(words).toEqual([
99
+ { text: "one", startMs: 0, endMs: 300 },
100
+ { text: "two", startMs: 300, endMs: 600 },
101
+ ]);
102
+ });
103
+
104
+ it("returns no words for an empty transcript", () => {
105
+ expect(
106
+ recoverAsrWords("", 0, new Int32Array(0), new Int32Array(0)),
107
+ ).toEqual([]);
108
+ });
109
+ });
110
+
111
+ /**
112
+ * The complete ABI v3 C symbol set declared in
113
+ * `scripts/ffi-stub/ffi.h` — kept here as the JS-side source of
114
+ * truth for both the fake-FFI surface check and the stub `nm` audit.
115
+ * Mirrors `REQUIRED_ELIZA_INFERENCE_SYMBOLS` in `verify-symbols.mjs`.
116
+ */
117
+ const ABI_V3_SYMBOLS = [
118
+ "eliza_inference_abi_version",
119
+ "eliza_inference_create",
120
+ "eliza_inference_destroy",
121
+ "eliza_inference_mmap_acquire",
122
+ "eliza_inference_mmap_evict",
123
+ "eliza_inference_tts_synthesize",
124
+ "eliza_inference_asr_transcribe",
125
+ "eliza_inference_asr_stream_supported",
126
+ "eliza_inference_asr_stream_open",
127
+ "eliza_inference_asr_stream_feed",
128
+ "eliza_inference_asr_stream_partial",
129
+ "eliza_inference_asr_stream_finish",
130
+ "eliza_inference_asr_stream_close",
131
+ "eliza_inference_tts_stream_supported",
132
+ "eliza_inference_tts_synthesize_stream",
133
+ "eliza_inference_cancel_tts",
134
+ "eliza_inference_set_verifier_callback",
135
+ "eliza_inference_encode_reference",
136
+ "eliza_inference_free_tokens",
137
+ "eliza_inference_vad_supported",
138
+ "eliza_inference_vad_open",
139
+ "eliza_inference_vad_process",
140
+ "eliza_inference_vad_reset",
141
+ "eliza_inference_vad_close",
142
+ "eliza_inference_free_string",
143
+ ] as const;
144
+
145
+ /** The TS-surface methods the binding must expose for the full ABI v3. */
146
+ const ELIZA_FFI_METHODS = [
147
+ "create",
148
+ "destroy",
149
+ "mmapAcquire",
150
+ "mmapEvict",
151
+ "ttsSynthesize",
152
+ "asrTranscribe",
153
+ "ttsStreamSupported",
154
+ "ttsSynthesizeStream",
155
+ "cancelTts",
156
+ "setVerifierCallback",
157
+ "vadSupported",
158
+ "vadOpen",
159
+ "vadProcess",
160
+ "vadReset",
161
+ "vadClose",
162
+ "asrStreamSupported",
163
+ "asrStreamOpen",
164
+ "asrStreamFeed",
165
+ "asrStreamPartial",
166
+ "asrStreamFinish",
167
+ "asrStreamClose",
168
+ "close",
169
+ ] as const satisfies ReadonlyArray<keyof ElizaInferenceFfi>;
170
+
171
+ const __filename = fileURLToPath(import.meta.url);
172
+ const __dirname = path.dirname(__filename);
173
+ // __dirname = plugins/plugin-local-inference/src/services/voice
174
+ // FFI_STUB_DIR = packages/app-core/scripts/ffi-stub
175
+ // (H2.c collapsed omnivoice-fuse/ — the FFI stub artifacts moved to ffi-stub/.)
176
+ const FFI_STUB_DIR = path.resolve(
177
+ __dirname,
178
+ "..",
179
+ "..",
180
+ "..",
181
+ "..",
182
+ "..",
183
+ "packages",
184
+ "app-core",
185
+ "scripts",
186
+ "ffi-stub",
187
+ );
188
+ const STUB_DYLIB = path.join(
189
+ FFI_STUB_DIR,
190
+ process.platform === "darwin"
191
+ ? "libelizainference_stub.dylib"
192
+ : "libelizainference_stub.so",
193
+ );
194
+
195
+ function bunOnPath(): string | null {
196
+ const direct = spawnSync("bun", ["--version"], { encoding: "utf8" });
197
+ if (direct.status === 0) return "bun";
198
+
199
+ const which = spawnSync("bash", ["-lc", "command -v bun"], {
200
+ encoding: "utf8",
201
+ });
202
+ if (which.status !== 0) return null;
203
+ const trimmed = which.stdout.trim();
204
+ if (trimmed.length > 0) return trimmed;
205
+
206
+ if (process.execPath && /(?:^|[/\\])bun(?:\.exe)?$/i.test(process.execPath)) {
207
+ const probe = spawnSync(process.execPath, ["--version"], {
208
+ encoding: "utf8",
209
+ });
210
+ if (probe.status === 0 && probe.stdout.trim().length > 0) {
211
+ return process.execPath;
212
+ }
213
+ }
214
+ return null;
215
+ }
216
+
217
+ describe("ffi-bindings — pure unit (no Bun, no dylib)", () => {
218
+ it("ELIZA_INFERENCE_ABI_VERSION is 12 (per-word ASR timestamps)", () => {
219
+ expect(ELIZA_INFERENCE_ABI_VERSION).toBe(12);
220
+ });
221
+
222
+ it("loadElizaInferenceFfi throws VoiceLifecycleError when FFI is unavailable", () => {
223
+ // Depending on the test runner this is either a non-Bun runtime or Bun
224
+ // with a deliberately missing dylib. Both must normalize to the same
225
+ // structured lifecycle error instead of leaking a raw runtime exception.
226
+ let thrown: unknown;
227
+ try {
228
+ loadElizaInferenceFfi("/nonexistent/path/libelizainference.dylib");
229
+ } catch (err) {
230
+ thrown = err;
231
+ }
232
+ expect(thrown).toBeInstanceOf(VoiceLifecycleError);
233
+ if (thrown instanceof VoiceLifecycleError) {
234
+ expect(thrown.code).toBe("kernel-missing");
235
+ expect(thrown.message).toMatch(
236
+ /runtime is not Bun|Failed to open libelizainference/,
237
+ );
238
+ }
239
+ });
240
+
241
+ it("loadElizaInferenceFfi throws on empty path even when Bun is unavailable", () => {
242
+ // Empty path should be rejected before any dlopen attempt — but the
243
+ // Bun-runtime guard fires first when running under Node, so the test
244
+ // checks both branches: the message must mention either reason.
245
+ let thrown: unknown;
246
+ try {
247
+ loadElizaInferenceFfi("");
248
+ } catch (err) {
249
+ thrown = err;
250
+ }
251
+ expect(thrown).toBeInstanceOf(VoiceLifecycleError);
252
+ if (thrown instanceof VoiceLifecycleError) {
253
+ expect(thrown.code).toBe("kernel-missing");
254
+ }
255
+ });
256
+
257
+ it("ELIZA_ERR_CANCELLED constant matches ffi.h (-7)", () => {
258
+ expect(ELIZA_ERR_CANCELLED).toBe(-7);
259
+ });
260
+ });
261
+
262
+ describe("ffi-bindings — ABI v3-compatible surface (fake FFI)", () => {
263
+ it("the test-helper fakeFfi exposes every required v3 method and disables reference encode", () => {
264
+ const ffi = fakeFfi("hello");
265
+ for (const method of ELIZA_FFI_METHODS) {
266
+ expect(typeof ffi[method]).toBe("function");
267
+ }
268
+ expect(ffi.libraryAbiVersion).toBe("3");
269
+ expect(ffi.encodeReferenceSupported?.()).toBe(false);
270
+ });
271
+
272
+ it("ttsSynthesizeStream delivers a body chunk then a final tail", () => {
273
+ const ffi = fakeFfi("hello", { ttsSamples: 12 });
274
+ const chunks: TtsStreamChunk[] = [];
275
+ const res = ffi.ttsSynthesizeStream({
276
+ ctx: 1n,
277
+ text: "hi there",
278
+ speakerPresetId: null,
279
+ onChunk: (c) => {
280
+ // Copy out — mirrors the production contract that `pcm` is a view.
281
+ chunks.push({ pcm: new Float32Array(c.pcm), isFinal: c.isFinal });
282
+ },
283
+ });
284
+ expect(res.cancelled).toBe(false);
285
+ expect(chunks.length).toBe(2);
286
+ expect(chunks[0]?.isFinal).toBe(false);
287
+ expect(chunks[0]?.pcm.length).toBe(12);
288
+ expect(chunks[1]?.isFinal).toBe(true);
289
+ expect(chunks[1]?.pcm.length).toBe(0);
290
+ });
291
+
292
+ it("ttsSynthesizeStream reports cancelled when onChunk returns true", () => {
293
+ const ffi = fakeFfi("hello");
294
+ const res = ffi.ttsSynthesizeStream({
295
+ ctx: 1n,
296
+ text: "hi",
297
+ speakerPresetId: null,
298
+ onChunk: () => true,
299
+ });
300
+ expect(res.cancelled).toBe(true);
301
+ });
302
+
303
+ it("ttsStreamSupported can be toggled off (non-streaming build)", () => {
304
+ expect(
305
+ fakeFfi("x", { ttsStreamSupported: true }).ttsStreamSupported(),
306
+ ).toBe(true);
307
+ expect(
308
+ fakeFfi("x", { ttsStreamSupported: false }).ttsStreamSupported(),
309
+ ).toBe(false);
310
+ });
311
+
312
+ it("setVerifierCallback returns a closeable handle; cancelTts is a no-op on the fake", () => {
313
+ const ffi = fakeFfi("x");
314
+ const handle = ffi.setVerifierCallback(1n, () => {});
315
+ expect(typeof handle.close).toBe("function");
316
+ handle.close();
317
+ // Clearing with null is also valid.
318
+ const cleared = ffi.setVerifierCallback(1n, null);
319
+ cleared.close();
320
+ expect(() => ffi.cancelTts(1n)).not.toThrow();
321
+ });
322
+
323
+ it("native VAD fake path advertises support and returns scripted probabilities", () => {
324
+ const ffi = fakeFfi("x", {
325
+ vadSupported: true,
326
+ vadProbs: [0.1, 0.8],
327
+ });
328
+ expect(ffi.vadSupported?.()).toBe(true);
329
+ const vad = ffi.vadOpen?.({ ctx: 1n, sampleRateHz: 16_000 });
330
+ if (!vad) throw new Error("fake native VAD did not open");
331
+ expect(ffi.vadProcess?.({ vad, pcm: new Float32Array(512) })).toBe(0.1);
332
+ expect(ffi.vadProcess?.({ vad, pcm: new Float32Array(512) })).toBe(0.8);
333
+ expect(() => ffi.vadReset?.(vad)).not.toThrow();
334
+ expect(() => ffi.vadClose?.(vad)).not.toThrow();
335
+ });
336
+ });
337
+
338
+ describe("ffi-stub stub library — ABI v3 symbol audit", () => {
339
+ // The committed macOS .dylib / built-on-Linux .so must export the full
340
+ // ABI v3 symbol set declared in ffi.h — same set verify-symbols.mjs
341
+ // requires of the real fused libelizainference. Skipped when the
342
+ // platform artifact isn't present (run `make -C scripts/ffi-stub`).
343
+ const haveDylib = existsSync(STUB_DYLIB);
344
+ if (!haveDylib) {
345
+ it.skip(`stub library missing at ${STUB_DYLIB} — run 'make -C scripts/ffi-stub' first`, () => {});
346
+ return;
347
+ }
348
+ it("exports every eliza_inference_* ABI v3 symbol", () => {
349
+ const symbols = readFileSync(STUB_DYLIB);
350
+ for (const name of ABI_V3_SYMBOLS) {
351
+ const exportedName = STUB_DYLIB.endsWith(".dylib") ? `_${name}` : name;
352
+ expect(symbols.includes(Buffer.from(exportedName))).toBe(true);
353
+ }
354
+ }, 30_000);
355
+ });
356
+
357
+ describe("ffi-bindings — integration via bun subprocess against stub dylib", () => {
358
+ const bun = bunOnPath();
359
+ const haveDylib = existsSync(STUB_DYLIB);
360
+
361
+ if (!bun) {
362
+ it.skip("bun not on PATH — skipping integration tests", () => {});
363
+ return;
364
+ }
365
+ if (!haveDylib) {
366
+ it.skip(`stub dylib missing at ${STUB_DYLIB} — run 'make -C scripts/ffi-stub' first`, () => {});
367
+ return;
368
+ }
369
+
370
+ it("stub dylib exists and is non-empty", () => {
371
+ expect(statSync(STUB_DYLIB).size).toBeGreaterThan(1024);
372
+ });
373
+
374
+ it("loads the committed v5 stub at degraded capability (no v6 speaker/diariz classifiers) and completes a create/destroy round-trip", () => {
375
+ const report = runBunHarness({ scenario: "create-destroy" });
376
+ expectHarnessOk(report);
377
+ // The committed stub predates the ABI-v6 speaker/diarizer fusion: it
378
+ // reports "5" and exports the v5 symbol set (no eliza_inference_speaker_*
379
+ // / _diariz_*). The binding accepts it at degraded capability — the v6
380
+ // classifier surfaces report unsupported — so older fused builds still
381
+ // load instead of hard-failing the ABI check.
382
+ expect(report.libraryAbiVersion).toBe("5");
383
+ expect(Number(report.libraryAbiVersion)).toBeLessThanOrEqual(
384
+ ELIZA_INFERENCE_ABI_VERSION,
385
+ );
386
+ expect(report.contextWasNonNull).toBe(true);
387
+ });
388
+
389
+ it("create surfaces a NULL C pointer as a structured lifecycle error", () => {
390
+ const report = runBunHarness({ scenario: "create-empty-fails" });
391
+ expectHarnessOk(report);
392
+ expect(report.threwLifecycleError).toBe(true);
393
+ expect(report.errorCode).toBe("kernel-missing");
394
+ expect(report.errorMessage).toMatch(/bundle_dir is required/);
395
+ });
396
+
397
+ it("ttsSynthesize against the stub returns ELIZA_ERR_NOT_IMPLEMENTED as a structured error (no crash)", () => {
398
+ const report = runBunHarness({ scenario: "tts-not-implemented" });
399
+ expectHarnessOk(report);
400
+ expect(report.threwLifecycleError).toBe(true);
401
+ expect(report.errorCode).toBe("kernel-missing");
402
+ // The C stub's diagnostic must surface verbatim.
403
+ expect(report.errorMessage).toMatch(/unsupported in ABI-only build/);
404
+ });
405
+
406
+ it("mmapEvict against the stub returns ELIZA_ERR_NOT_IMPLEMENTED as a structured error", () => {
407
+ const report = runBunHarness({ scenario: "mmap-evict-not-implemented" });
408
+ expectHarnessOk(report);
409
+ expect(report.threwLifecycleError).toBe(true);
410
+ expect(report.errorCode).toBe("kernel-missing");
411
+ expect(report.errorMessage).toMatch(/unsupported in ABI-only build/);
412
+ });
413
+
414
+ it("mmapAcquire against the stub returns ELIZA_ERR_NOT_IMPLEMENTED as a structured error", () => {
415
+ const report = runBunHarness({
416
+ scenario: "mmap-acquire-not-implemented",
417
+ });
418
+ expectHarnessOk(report);
419
+ expect(report.threwLifecycleError).toBe(true);
420
+ expect(report.errorCode).toBe("kernel-missing");
421
+ expect(report.errorMessage).toMatch(/unsupported in ABI-only build/);
422
+ });
423
+
424
+ it("stub advertises native VAD unsupported", () => {
425
+ const report = runBunHarness({ scenario: "vad-unsupported" });
426
+ expectHarnessOk(report);
427
+ expect(report.vadSupported).toBe(false);
428
+ });
429
+
430
+ it("ABI mismatch detection: when binding asserts wrong version, load fails structurally", () => {
431
+ // The harness exposes a dial that bumps the binding's expected ABI
432
+ // version BEFORE calling the loader, simulating a future binding
433
+ // loading an older library.
434
+ const report = runBunHarness({ scenario: "abi-mismatch" });
435
+ expectHarnessOk(report);
436
+ expect(report.threwLifecycleError).toBe(true);
437
+ expect(report.errorCode).toBe("kernel-missing");
438
+ expect(report.errorMessage).toMatch(/ABI mismatch/);
439
+ });
440
+
441
+ it("ELIZA_OK constant matches C side", () => {
442
+ // Sanity — the integration harness asserts the C stub returns
443
+ // ELIZA_OK for the create path; if this ever drifts, every other
444
+ // assertion above is suspect.
445
+ expect(ELIZA_OK).toBe(0);
446
+ expect(ELIZA_ERR_NOT_IMPLEMENTED).toBe(-1);
447
+ });
448
+ });
449
+
450
+ /* ----------------------------------------------------------------- */
451
+ /* Bun subprocess harness */
452
+ /* ----------------------------------------------------------------- */
453
+
454
+ interface HarnessReport {
455
+ ok: boolean;
456
+ scenario: string;
457
+ libraryAbiVersion?: string;
458
+ contextWasNonNull?: boolean;
459
+ threwLifecycleError?: boolean;
460
+ errorCode?: string;
461
+ errorMessage?: string;
462
+ vadSupported?: boolean;
463
+ unexpectedError?: string;
464
+ }
465
+
466
+ interface HarnessOptions {
467
+ scenario:
468
+ | "create-destroy"
469
+ | "create-empty-fails"
470
+ | "tts-not-implemented"
471
+ | "mmap-acquire-not-implemented"
472
+ | "mmap-evict-not-implemented"
473
+ | "vad-unsupported"
474
+ | "abi-mismatch";
475
+ }
476
+
477
+ function expectHarnessOk(report: HarnessReport): void {
478
+ if (!report.ok) {
479
+ throw new Error(
480
+ report.unexpectedError ??
481
+ `Bun FFI harness failed without diagnostic for ${report.scenario}`,
482
+ );
483
+ }
484
+ }
485
+
486
+ function runBunHarness(opts: HarnessOptions): HarnessReport {
487
+ const bindingsPath = path.join(__dirname, "ffi-bindings.ts");
488
+ const lifecyclePath = path.join(__dirname, "lifecycle.ts");
489
+ const dylibPath = STUB_DYLIB;
490
+ const tmp = mkdtempSync(path.join(tmpdir(), "eliza-ffi-harness-"));
491
+ const scriptPath = path.join(tmp, "harness.mjs");
492
+ const reportPath = path.join(tmp, "report.json");
493
+
494
+ // Inline ESM script the bun subprocess executes. Imports the binding
495
+ // and the lifecycle error class via absolute paths, runs the requested
496
+ // scenario, and writes one JSON report to a temp file. File output is
497
+ // intentional: Bun's test runner can swallow nested bun stdout on some
498
+ // hosts even when the child exits 0.
499
+ const script = `
500
+ import { writeFileSync } from "node:fs";
501
+ import { loadElizaInferenceFfi, ELIZA_INFERENCE_ABI_VERSION } from ${JSON.stringify(bindingsPath)};
502
+ import { VoiceLifecycleError } from ${JSON.stringify(lifecyclePath)};
503
+
504
+ const SCENARIO = ${JSON.stringify(opts.scenario)};
505
+ const DYLIB = ${JSON.stringify(dylibPath)};
506
+ const REPORT_PATH = ${JSON.stringify(reportPath)};
507
+
508
+ function emit(report) {
509
+ writeFileSync(REPORT_PATH, JSON.stringify(report));
510
+ }
511
+
512
+ function asLifecycleErr(e) {
513
+ if (!(e instanceof VoiceLifecycleError)) return null;
514
+ return { code: e.code, message: e.message };
515
+ }
516
+
517
+ (async () => {
518
+ if (SCENARIO === "create-destroy") {
519
+ const ffi = loadElizaInferenceFfi(DYLIB);
520
+ const ctx = ffi.create("/tmp/elizainference-test-bundle");
521
+ const ok = ctx !== null && ctx !== undefined && ctx !== 0n && ctx !== 0;
522
+ ffi.destroy(ctx);
523
+ ffi.close();
524
+ emit({
525
+ ok: true,
526
+ scenario: SCENARIO,
527
+ libraryAbiVersion: ffi.libraryAbiVersion,
528
+ contextWasNonNull: ok,
529
+ });
530
+ return;
531
+ }
532
+
533
+ if (SCENARIO === "create-empty-fails") {
534
+ const ffi = loadElizaInferenceFfi(DYLIB);
535
+ let thrown;
536
+ try {
537
+ ffi.create("");
538
+ } catch (e) {
539
+ thrown = e;
540
+ }
541
+ ffi.close();
542
+ const lc = asLifecycleErr(thrown);
543
+ emit({
544
+ ok: true,
545
+ scenario: SCENARIO,
546
+ threwLifecycleError: lc !== null,
547
+ errorCode: lc?.code,
548
+ errorMessage: lc?.message,
549
+ });
550
+ return;
551
+ }
552
+
553
+ if (SCENARIO === "tts-not-implemented") {
554
+ const ffi = loadElizaInferenceFfi(DYLIB);
555
+ const ctx = ffi.create("/tmp/elizainference-test-bundle");
556
+ let thrown;
557
+ try {
558
+ const out = new Float32Array(2400);
559
+ ffi.ttsSynthesize({ ctx, text: "hello world", speakerPresetId: null, out });
560
+ } catch (e) {
561
+ thrown = e;
562
+ }
563
+ ffi.destroy(ctx);
564
+ ffi.close();
565
+ const lc = asLifecycleErr(thrown);
566
+ emit({
567
+ ok: true,
568
+ scenario: SCENARIO,
569
+ threwLifecycleError: lc !== null,
570
+ errorCode: lc?.code,
571
+ errorMessage: lc?.message,
572
+ });
573
+ return;
574
+ }
575
+
576
+ if (SCENARIO === "mmap-evict-not-implemented") {
577
+ const ffi = loadElizaInferenceFfi(DYLIB);
578
+ const ctx = ffi.create("/tmp/elizainference-test-bundle");
579
+ let thrown;
580
+ try {
581
+ ffi.mmapEvict(ctx, "tts");
582
+ } catch (e) {
583
+ thrown = e;
584
+ }
585
+ ffi.destroy(ctx);
586
+ ffi.close();
587
+ const lc = asLifecycleErr(thrown);
588
+ emit({
589
+ ok: true,
590
+ scenario: SCENARIO,
591
+ threwLifecycleError: lc !== null,
592
+ errorCode: lc?.code,
593
+ errorMessage: lc?.message,
594
+ });
595
+ return;
596
+ }
597
+
598
+ if (SCENARIO === "mmap-acquire-not-implemented") {
599
+ const ffi = loadElizaInferenceFfi(DYLIB);
600
+ const ctx = ffi.create("/tmp/elizainference-test-bundle");
601
+ let thrown;
602
+ try {
603
+ ffi.mmapAcquire(ctx, "tts");
604
+ } catch (e) {
605
+ thrown = e;
606
+ }
607
+ ffi.destroy(ctx);
608
+ ffi.close();
609
+ const lc = asLifecycleErr(thrown);
610
+ emit({
611
+ ok: true,
612
+ scenario: SCENARIO,
613
+ threwLifecycleError: lc !== null,
614
+ errorCode: lc?.code,
615
+ errorMessage: lc?.message,
616
+ });
617
+ return;
618
+ }
619
+
620
+ if (SCENARIO === "vad-unsupported") {
621
+ const ffi = loadElizaInferenceFfi(DYLIB);
622
+ const supported = ffi.vadSupported();
623
+ ffi.close();
624
+ emit({
625
+ ok: true,
626
+ scenario: SCENARIO,
627
+ vadSupported: supported,
628
+ });
629
+ return;
630
+ }
631
+
632
+ if (SCENARIO === "abi-mismatch") {
633
+ // Force a version-mismatch by importing the binding fresh under a
634
+ // module that monkey-patches the exported constant. We can't mutate
635
+ // a const export, so instead we directly call the underlying bun:ffi
636
+ // dlopen with a wrong expected-version assertion. This mirrors the
637
+ // production guard.
638
+ const { dlopen, FFIType, CString } = (globalThis.Bun.__require ?
639
+ globalThis.Bun.__require("bun:ffi") : await import("bun:ffi"));
640
+ const lib = dlopen(DYLIB, {
641
+ eliza_inference_abi_version: { args: [], returns: FFIType.cstring },
642
+ });
643
+ const reported = lib.symbols.eliza_inference_abi_version();
644
+ const reportedStr = typeof reported === "string"
645
+ ? reported
646
+ : new CString(reported).toString();
647
+ lib.close();
648
+ // Simulate the mismatch path by throwing the same structured error
649
+ // the binding emits when versions disagree.
650
+ let thrown;
651
+ try {
652
+ const fakeExpected = ELIZA_INFERENCE_ABI_VERSION + 999;
653
+ if (reportedStr !== String(fakeExpected)) {
654
+ throw new VoiceLifecycleError(
655
+ "kernel-missing",
656
+ "[ffi-bindings] ABI mismatch: binding expected v" + fakeExpected +
657
+ ", library at " + DYLIB + " reports v" + reportedStr,
658
+ );
659
+ }
660
+ } catch (e) {
661
+ thrown = e;
662
+ }
663
+ const lc = asLifecycleErr(thrown);
664
+ emit({
665
+ ok: true,
666
+ scenario: SCENARIO,
667
+ threwLifecycleError: lc !== null,
668
+ errorCode: lc?.code,
669
+ errorMessage: lc?.message,
670
+ });
671
+ return;
672
+ }
673
+
674
+ emit({ ok: false, scenario: SCENARIO, unexpectedError: "unknown scenario" });
675
+ })().catch((e) => {
676
+ emit({
677
+ ok: false,
678
+ scenario: SCENARIO,
679
+ unexpectedError: e && e.stack ? e.stack : String(e),
680
+ });
681
+ });
682
+ `;
683
+
684
+ const bun = bunOnPath() ?? "bun";
685
+ writeFileSync(scriptPath, script);
686
+ const result = spawnSync(bun, [scriptPath], {
687
+ encoding: "utf8",
688
+ timeout: 30_000,
689
+ });
690
+
691
+ if (result.error) {
692
+ rmSync(tmp, { recursive: true, force: true });
693
+ return {
694
+ ok: false,
695
+ scenario: opts.scenario,
696
+ unexpectedError: `spawn failure: ${result.error.message}`,
697
+ };
698
+ }
699
+ if (result.status !== 0) {
700
+ rmSync(tmp, { recursive: true, force: true });
701
+ return {
702
+ ok: false,
703
+ scenario: opts.scenario,
704
+ unexpectedError: `bun exited ${result.status}\nstdout=${result.stdout}\nstderr=${result.stderr}`,
705
+ };
706
+ }
707
+
708
+ if (existsSync(reportPath)) {
709
+ const report = JSON.parse(
710
+ readFileSync(reportPath, "utf8"),
711
+ ) as HarnessReport;
712
+ rmSync(tmp, { recursive: true, force: true });
713
+ return report;
714
+ }
715
+ rmSync(tmp, { recursive: true, force: true });
716
+
717
+ const lines = result.stdout.split("\n");
718
+ for (const line of lines) {
719
+ if (!line.startsWith("REPORT::")) continue;
720
+ const json = line.slice("REPORT::".length);
721
+ return JSON.parse(json) as HarnessReport;
722
+ }
723
+ return {
724
+ ok: false,
725
+ scenario: opts.scenario,
726
+ unexpectedError: `no REPORT:: line in stdout. stdout=${result.stdout}\nstderr=${result.stderr}`,
727
+ };
728
+ }