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

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 (881) hide show
  1. package/README.md +84 -10
  2. package/dist/actions/generate-media.d.ts.map +1 -0
  3. package/dist/actions/identify-speaker.d.ts.map +1 -0
  4. package/dist/actions/transcription-control.d.ts.map +1 -0
  5. package/dist/adapters/capacitor-llama/environment.d.ts +12 -0
  6. package/dist/adapters/capacitor-llama/environment.d.ts.map +1 -0
  7. package/dist/adapters/capacitor-llama/index.browser.d.ts +9 -0
  8. package/dist/adapters/capacitor-llama/index.browser.d.ts.map +1 -0
  9. package/dist/adapters/capacitor-llama/index.d.ts +18 -0
  10. package/dist/adapters/capacitor-llama/index.d.ts.map +1 -0
  11. package/dist/adapters/capacitor-llama/loader.d.ts +35 -0
  12. package/dist/adapters/capacitor-llama/loader.d.ts.map +1 -0
  13. package/dist/adapters/capacitor-llama/native-voice-capture.d.ts +70 -0
  14. package/dist/adapters/capacitor-llama/native-voice-capture.d.ts.map +1 -0
  15. package/dist/adapters/capacitor-llama/structured-output.d.ts +62 -0
  16. package/dist/adapters/capacitor-llama/structured-output.d.ts.map +1 -0
  17. package/dist/adapters/capacitor-llama/text-streaming.d.ts +24 -0
  18. package/dist/adapters/capacitor-llama/text-streaming.d.ts.map +1 -0
  19. package/dist/adapters/capacitor-llama/types.d.ts +338 -0
  20. package/dist/adapters/capacitor-llama/types.d.ts.map +1 -0
  21. package/dist/adapters/capacitor-llama/voice-turn.d.ts +86 -0
  22. package/dist/adapters/capacitor-llama/voice-turn.d.ts.map +1 -0
  23. package/dist/backends/apple-foundation.d.ts +56 -0
  24. package/dist/backends/apple-foundation.d.ts.map +1 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +39647 -0
  27. package/dist/index.js.map +217 -0
  28. package/{src → dist}/local-inference-routes.d.ts +9 -0
  29. package/dist/local-inference-routes.d.ts.map +1 -0
  30. package/dist/provider.d.ts.map +1 -0
  31. package/{src → dist}/routes/compat-helpers.d.ts +1 -1
  32. package/dist/routes/compat-helpers.d.ts.map +1 -0
  33. package/dist/routes/family-member-route.d.ts.map +1 -0
  34. package/{src → dist}/routes/index.d.ts +1 -0
  35. package/dist/routes/index.d.ts.map +1 -0
  36. package/dist/routes/index.js +42040 -0
  37. package/dist/routes/index.js.map +236 -0
  38. package/{src → dist}/routes/live-diarization-route.d.ts +7 -0
  39. package/dist/routes/live-diarization-route.d.ts.map +1 -0
  40. package/dist/routes/local-inference-asr-route.d.ts.map +1 -0
  41. package/dist/routes/local-inference-asr-transcribe.d.ts.map +1 -0
  42. package/dist/routes/local-inference-compat-routes.d.ts.map +1 -0
  43. package/dist/routes/local-inference-tts-route.d.ts.map +1 -0
  44. package/dist/routes/native-pcm-turn-route.d.ts +3 -0
  45. package/dist/routes/native-pcm-turn-route.d.ts.map +1 -0
  46. package/dist/routes/transcript-audio-store.d.ts.map +1 -0
  47. package/{src → dist}/routes/transcripts-routes.d.ts +8 -0
  48. package/dist/routes/transcripts-routes.d.ts.map +1 -0
  49. package/dist/routes/voice-first-run-routes.d.ts.map +1 -0
  50. package/dist/routes/voice-models-routes.d.ts.map +1 -0
  51. package/dist/routes/voice-profile-plugin-routes.d.ts.map +1 -0
  52. package/dist/routes/voice-profiles-management-routes.d.ts.map +1 -0
  53. package/dist/routes/voice-speaker-profile-routes.d.ts.map +1 -0
  54. package/dist/runtime/embedding-manager-support.d.ts.map +1 -0
  55. package/dist/runtime/embedding-presets.d.ts.map +1 -0
  56. package/dist/runtime/embedding-warmup-policy.d.ts.map +1 -0
  57. package/{src → dist}/runtime/ensure-local-inference-handler.d.ts +8 -0
  58. package/dist/runtime/ensure-local-inference-handler.d.ts.map +1 -0
  59. package/{src → dist}/runtime/index.d.ts +1 -1
  60. package/dist/runtime/index.d.ts.map +1 -0
  61. package/dist/runtime/index.js +38768 -0
  62. package/dist/runtime/index.js.map +217 -0
  63. package/dist/runtime/mobile-local-inference-gate.d.ts +63 -0
  64. package/dist/runtime/mobile-local-inference-gate.d.ts.map +1 -0
  65. package/{src → dist}/runtime/voice-entity-binding.d.ts +10 -0
  66. package/dist/runtime/voice-entity-binding.d.ts.map +1 -0
  67. package/{src → dist}/services/active-model.d.ts +28 -0
  68. package/dist/services/active-model.d.ts.map +1 -0
  69. package/dist/services/asr-provenance.d.ts +5 -0
  70. package/dist/services/asr-provenance.d.ts.map +1 -0
  71. package/{src → dist}/services/assignments.d.ts +16 -3
  72. package/dist/services/assignments.d.ts.map +1 -0
  73. package/dist/services/backend-selector.d.ts +55 -0
  74. package/dist/services/backend-selector.d.ts.map +1 -0
  75. package/{src → dist}/services/backend.d.ts +110 -16
  76. package/dist/services/backend.d.ts.map +1 -0
  77. package/{src → dist}/services/bionic-host-loader.d.ts +21 -0
  78. package/dist/services/bionic-host-loader.d.ts.map +1 -0
  79. package/dist/services/bundled-models.d.ts.map +1 -0
  80. package/dist/services/cache-bridge.d.ts.map +1 -0
  81. package/dist/services/catalog.d.ts +10 -0
  82. package/dist/services/catalog.d.ts.map +1 -0
  83. package/dist/services/checkpoint-client.d.ts.map +1 -0
  84. package/dist/services/checkpoint-manager.d.ts +217 -0
  85. package/dist/services/checkpoint-manager.d.ts.map +1 -0
  86. package/dist/services/cloud-fallback.d.ts.map +1 -0
  87. package/dist/services/context-fit.d.ts +36 -0
  88. package/dist/services/context-fit.d.ts.map +1 -0
  89. package/dist/services/conversation-registry.d.ts.map +1 -0
  90. package/{src → dist}/services/desktop-fused-ffi-backend-runtime.d.ts +22 -6
  91. package/dist/services/desktop-fused-ffi-backend-runtime.d.ts.map +1 -0
  92. package/dist/services/device-bridge.d.ts.map +1 -0
  93. package/dist/services/device-resource-metrics.d.ts.map +1 -0
  94. package/{src → dist}/services/device-tier.d.ts +19 -1
  95. package/dist/services/device-tier.d.ts.map +1 -0
  96. package/{src → dist}/services/downloader.d.ts +16 -4
  97. package/dist/services/downloader.d.ts.map +1 -0
  98. package/{src → dist}/services/engine.d.ts +43 -4
  99. package/dist/services/engine.d.ts.map +1 -0
  100. package/dist/services/ensure-local-artifacts.d.ts +82 -0
  101. package/dist/services/ensure-local-artifacts.d.ts.map +1 -0
  102. package/dist/services/external-scanner.d.ts.map +1 -0
  103. package/dist/services/ffi-llm-mock.d.ts +90 -0
  104. package/dist/services/ffi-llm-mock.d.ts.map +1 -0
  105. package/dist/services/ffi-llm-streaming-abi.d.ts +318 -0
  106. package/dist/services/ffi-llm-streaming-abi.d.ts.map +1 -0
  107. package/{src → dist}/services/ffi-streaming-backend.d.ts +28 -7
  108. package/dist/services/ffi-streaming-backend.d.ts.map +1 -0
  109. package/{src → dist}/services/ffi-streaming-runner.d.ts +24 -0
  110. package/dist/services/ffi-streaming-runner.d.ts.map +1 -0
  111. package/dist/services/gpu-autotune.d.ts +150 -0
  112. package/dist/services/gpu-autotune.d.ts.map +1 -0
  113. package/dist/services/gpu-detect.d.ts.map +1 -0
  114. package/dist/services/handler-registry.d.ts.map +1 -0
  115. package/dist/services/hardware.d.ts.map +1 -0
  116. package/dist/services/image-description-runtime.d.ts.map +1 -0
  117. package/dist/services/imagegen/aosp-unavailable.d.ts.map +1 -0
  118. package/dist/services/imagegen/backend-selector.d.ts.map +1 -0
  119. package/dist/services/imagegen/coreml-unavailable.d.ts.map +1 -0
  120. package/dist/services/imagegen/errors.d.ts.map +1 -0
  121. package/dist/services/imagegen/index.d.ts.map +1 -0
  122. package/dist/services/imagegen/mflux.d.ts.map +1 -0
  123. package/{src → dist}/services/imagegen/sd-cpp.d.ts +1 -0
  124. package/dist/services/imagegen/sd-cpp.d.ts.map +1 -0
  125. package/dist/services/imagegen/tensorrt-unavailable.d.ts.map +1 -0
  126. package/dist/services/imagegen/types.d.ts.map +1 -0
  127. package/{src → dist}/services/index.d.ts +3 -1
  128. package/dist/services/index.d.ts.map +1 -0
  129. package/dist/services/index.js +39453 -0
  130. package/dist/services/index.js.map +227 -0
  131. package/dist/services/inference-capabilities.d.ts.map +1 -0
  132. package/dist/services/inference-telemetry.d.ts.map +1 -0
  133. package/dist/services/ios-llama-streaming.d.ts +119 -0
  134. package/dist/services/ios-llama-streaming.d.ts.map +1 -0
  135. package/dist/services/kv-spill.d.ts.map +1 -0
  136. package/dist/services/latency-trace.d.ts.map +1 -0
  137. package/dist/services/lib-target.d.ts +55 -0
  138. package/dist/services/lib-target.d.ts.map +1 -0
  139. package/dist/services/live-signals.d.ts +86 -0
  140. package/dist/services/live-signals.d.ts.map +1 -0
  141. package/dist/services/llama-server-metrics.d.ts +114 -0
  142. package/dist/services/llama-server-metrics.d.ts.map +1 -0
  143. package/dist/services/llm-streaming-binding.d.ts.map +1 -0
  144. package/dist/services/load-args.d.ts.map +1 -0
  145. package/dist/services/manifest/index.d.ts +4 -0
  146. package/dist/services/manifest/index.d.ts.map +1 -0
  147. package/{src → dist}/services/manifest/schema.d.ts +196 -6
  148. package/dist/services/manifest/schema.d.ts.map +1 -0
  149. package/{src → dist}/services/manifest/types.d.ts +3 -1
  150. package/dist/services/manifest/types.d.ts.map +1 -0
  151. package/dist/services/manifest/validator.d.ts.map +1 -0
  152. package/{src → dist}/services/memory-arbiter.d.ts +33 -3
  153. package/dist/services/memory-arbiter.d.ts.map +1 -0
  154. package/dist/services/memory-benchmark.d.ts +76 -0
  155. package/dist/services/memory-benchmark.d.ts.map +1 -0
  156. package/{src → dist}/services/memory-monitor.d.ts +6 -0
  157. package/dist/services/memory-monitor.d.ts.map +1 -0
  158. package/dist/services/memory-pressure.d.ts.map +1 -0
  159. package/dist/services/mtp-doctor.d.ts.map +1 -0
  160. package/dist/services/network-policy.d.ts.map +1 -0
  161. package/dist/services/paths.d.ts.map +1 -0
  162. package/dist/services/planner-skeleton.d.ts.map +1 -0
  163. package/dist/services/providers.d.ts.map +1 -0
  164. package/dist/services/ram-budget.d.ts.map +1 -0
  165. package/dist/services/readiness.d.ts.map +1 -0
  166. package/dist/services/recommendation.d.ts.map +1 -0
  167. package/{src → dist}/services/registry.d.ts +11 -13
  168. package/dist/services/registry.d.ts.map +1 -0
  169. package/{src → dist}/services/router-handler.d.ts +2 -2
  170. package/dist/services/router-handler.d.ts.map +1 -0
  171. package/{src → dist}/services/routing-policy.d.ts +32 -9
  172. package/dist/services/routing-policy.d.ts.map +1 -0
  173. package/dist/services/routing-preferences.d.ts.map +1 -0
  174. package/dist/services/runtime-target.d.ts.map +1 -0
  175. package/{src → dist}/services/service.d.ts +1 -1
  176. package/dist/services/service.d.ts.map +1 -0
  177. package/dist/services/session-pool.d.ts.map +1 -0
  178. package/dist/services/structured-output/deterministic-repair.d.ts.map +1 -0
  179. package/dist/services/structured-output/index.d.ts +2 -0
  180. package/dist/services/structured-output/index.d.ts.map +1 -0
  181. package/dist/services/structured-output.d.ts.map +1 -0
  182. package/dist/services/system-memory.d.ts.map +1 -0
  183. package/{src → dist}/services/types.d.ts +1 -1
  184. package/dist/services/types.d.ts.map +1 -0
  185. package/dist/services/verify-on-device.d.ts.map +1 -0
  186. package/dist/services/verify.d.ts.map +1 -0
  187. package/dist/services/vision/aosp-unavailable.d.ts.map +1 -0
  188. package/dist/services/vision/capacitor-llama.d.ts.map +1 -0
  189. package/dist/services/vision/cloud-fallback.d.ts.map +1 -0
  190. package/dist/services/vision/hash.d.ts.map +1 -0
  191. package/{src → dist}/services/vision/index.d.ts +1 -1
  192. package/dist/services/vision/index.d.ts.map +1 -0
  193. package/dist/services/vision/llama-server.d.ts.map +1 -0
  194. package/{src → dist}/services/vision/types.d.ts +13 -4
  195. package/dist/services/vision/types.d.ts.map +1 -0
  196. package/dist/services/vision/vast-fallback.d.ts.map +1 -0
  197. package/{src → dist}/services/vision-embedding-cache.d.ts +1 -1
  198. package/dist/services/vision-embedding-cache.d.ts.map +1 -0
  199. package/dist/services/voice/__test-helpers__/fake-ffi.d.ts +27 -0
  200. package/dist/services/voice/__test-helpers__/fake-ffi.d.ts.map +1 -0
  201. package/dist/services/voice/__test-helpers__/synthetic-speech.d.ts +66 -0
  202. package/dist/services/voice/__test-helpers__/synthetic-speech.d.ts.map +1 -0
  203. package/dist/services/voice/acoustic-speaker-attribution.d.ts +61 -0
  204. package/dist/services/voice/acoustic-speaker-attribution.d.ts.map +1 -0
  205. package/{src → dist}/services/voice/audio-frame-consumer.d.ts +82 -0
  206. package/dist/services/voice/audio-frame-consumer.d.ts.map +1 -0
  207. package/dist/services/voice/barge-in.d.ts.map +1 -0
  208. package/dist/services/voice/cancellation-coordinator.d.ts.map +1 -0
  209. package/dist/services/voice/checkpoint-manager.d.ts.map +1 -0
  210. package/dist/services/voice/checkpoint-policy.d.ts +178 -0
  211. package/dist/services/voice/checkpoint-policy.d.ts.map +1 -0
  212. package/dist/services/voice/corpus-augment.d.ts +111 -0
  213. package/dist/services/voice/corpus-augment.d.ts.map +1 -0
  214. package/dist/services/voice/corpus-generator.d.ts +134 -0
  215. package/dist/services/voice/corpus-generator.d.ts.map +1 -0
  216. package/dist/services/voice/diarization-error-rate.d.ts +40 -0
  217. package/dist/services/voice/diarization-error-rate.d.ts.map +1 -0
  218. package/dist/services/voice/e2e-harness.d.ts +297 -0
  219. package/dist/services/voice/e2e-harness.d.ts.map +1 -0
  220. package/dist/services/voice/eager-context-builder.d.ts.map +1 -0
  221. package/dist/services/voice/echo-delay.d.ts +67 -0
  222. package/dist/services/voice/echo-delay.d.ts.map +1 -0
  223. package/dist/services/voice/echo-metrics.d.ts +7 -0
  224. package/dist/services/voice/echo-metrics.d.ts.map +1 -0
  225. package/dist/services/voice/echo-reference-buffer.d.ts +65 -0
  226. package/dist/services/voice/echo-reference-buffer.d.ts.map +1 -0
  227. package/{src → dist}/services/voice/eliza1-eot-scorer.d.ts +8 -8
  228. package/dist/services/voice/eliza1-eot-scorer.d.ts.map +1 -0
  229. package/dist/services/voice/embedding-server.d.ts +37 -0
  230. package/dist/services/voice/embedding-server.d.ts.map +1 -0
  231. package/{src → dist}/services/voice/embedding.d.ts +2 -3
  232. package/dist/services/voice/embedding.d.ts.map +1 -0
  233. package/dist/services/voice/emotion-attribution.d.ts.map +1 -0
  234. package/{src → dist}/services/voice/engine-bridge.d.ts +8 -5
  235. package/dist/services/voice/engine-bridge.d.ts.map +1 -0
  236. package/{src → dist}/services/voice/eot-classifier-ggml.d.ts +22 -22
  237. package/dist/services/voice/eot-classifier-ggml.d.ts.map +1 -0
  238. package/{src → dist}/services/voice/eot-classifier.d.ts +9 -12
  239. package/dist/services/voice/eot-classifier.d.ts.map +1 -0
  240. package/{src → dist}/services/voice/errors.d.ts +1 -1
  241. package/dist/services/voice/errors.d.ts.map +1 -0
  242. package/{src → dist}/services/voice/expressive-tags.d.ts +5 -5
  243. package/dist/services/voice/expressive-tags.d.ts.map +1 -0
  244. package/{src → dist}/services/voice/ffi-bindings.d.ts +26 -4
  245. package/dist/services/voice/ffi-bindings.d.ts.map +1 -0
  246. package/dist/services/voice/first-line-cache.d.ts.map +1 -0
  247. package/{src → dist}/services/voice/fused-eot-scorer.d.ts +6 -6
  248. package/dist/services/voice/fused-eot-scorer.d.ts.map +1 -0
  249. package/{src → dist}/services/voice/index.d.ts +8 -3
  250. package/dist/services/voice/index.d.ts.map +1 -0
  251. package/dist/services/voice/kokoro/index.d.ts +24 -0
  252. package/dist/services/voice/kokoro/index.d.ts.map +1 -0
  253. package/{src → dist}/services/voice/kokoro/kokoro-backend.d.ts +15 -0
  254. package/dist/services/voice/kokoro/kokoro-backend.d.ts.map +1 -0
  255. package/{src → dist}/services/voice/kokoro/kokoro-engine-discovery.d.ts +1 -1
  256. package/dist/services/voice/kokoro/kokoro-engine-discovery.d.ts.map +1 -0
  257. package/{src → dist}/services/voice/kokoro/kokoro-ffi-runtime.d.ts +3 -3
  258. package/dist/services/voice/kokoro/kokoro-ffi-runtime.d.ts.map +1 -0
  259. package/dist/services/voice/kokoro/kokoro-runtime.d.ts.map +1 -0
  260. package/dist/services/voice/kokoro/phoneme-stream.d.ts +51 -0
  261. package/dist/services/voice/kokoro/phoneme-stream.d.ts.map +1 -0
  262. package/dist/services/voice/kokoro/phonemizer.d.ts.map +1 -0
  263. package/{src → dist}/services/voice/kokoro/pick-runtime.d.ts +1 -1
  264. package/dist/services/voice/kokoro/pick-runtime.d.ts.map +1 -0
  265. package/dist/services/voice/kokoro/runtime-selection.d.ts +31 -0
  266. package/dist/services/voice/kokoro/runtime-selection.d.ts.map +1 -0
  267. package/dist/services/voice/kokoro/types.d.ts.map +1 -0
  268. package/dist/services/voice/kokoro/voice-presets.d.ts.map +1 -0
  269. package/dist/services/voice/kokoro/voices.d.ts.map +1 -0
  270. package/dist/services/voice/lifecycle.d.ts.map +1 -0
  271. package/dist/services/voice/live-diarization-session.d.ts +196 -0
  272. package/dist/services/voice/live-diarization-session.d.ts.map +1 -0
  273. package/dist/services/voice/metric-math.d.ts +10 -0
  274. package/dist/services/voice/metric-math.d.ts.map +1 -0
  275. package/{src → dist}/services/voice/mic-source.d.ts +1 -1
  276. package/dist/services/voice/mic-source.d.ts.map +1 -0
  277. package/dist/services/voice/nlms-echo-canceller.d.ts +137 -0
  278. package/dist/services/voice/nlms-echo-canceller.d.ts.map +1 -0
  279. package/dist/services/voice/optimistic-policy.d.ts.map +1 -0
  280. package/dist/services/voice/optimistic-rollback.d.ts +151 -0
  281. package/dist/services/voice/optimistic-rollback.d.ts.map +1 -0
  282. package/{src → dist}/services/voice/partial-stabilizer.d.ts +1 -1
  283. package/dist/services/voice/partial-stabilizer.d.ts.map +1 -0
  284. package/dist/services/voice/phoneme-tokenizer.d.ts.map +1 -0
  285. package/dist/services/voice/phrase-cache.d.ts.map +1 -0
  286. package/dist/services/voice/phrase-chunker.d.ts.map +1 -0
  287. package/dist/services/voice/pipeline-impls.d.ts.map +1 -0
  288. package/dist/services/voice/pipeline.d.ts.map +1 -0
  289. package/dist/services/voice/prefill-client.d.ts.map +1 -0
  290. package/dist/services/voice/prefix-preserving-queue.d.ts.map +1 -0
  291. package/dist/services/voice/profile-store.d.ts.map +1 -0
  292. package/dist/services/voice/ring-buffer.d.ts.map +1 -0
  293. package/dist/services/voice/rollback-queue.d.ts.map +1 -0
  294. package/dist/services/voice/samantha-preset-placeholder.d.ts.map +1 -0
  295. package/dist/services/voice/samantha-preset-regenerator.d.ts.map +1 -0
  296. package/dist/services/voice/scheduler.d.ts.map +1 -0
  297. package/dist/services/voice/self-voice-imprint.d.ts +33 -0
  298. package/dist/services/voice/self-voice-imprint.d.ts.map +1 -0
  299. package/{src → dist}/services/voice/shared-resources.d.ts +14 -0
  300. package/dist/services/voice/shared-resources.d.ts.map +1 -0
  301. package/dist/services/voice/speaker/attribution-pipeline.d.ts.map +1 -0
  302. package/dist/services/voice/speaker/diarizer-fused.d.ts.map +1 -0
  303. package/dist/services/voice/speaker/diarizer.d.ts.map +1 -0
  304. package/dist/services/voice/speaker/encoder-fused.d.ts.map +1 -0
  305. package/dist/services/voice/speaker/encoder-ggml.d.ts.map +1 -0
  306. package/dist/services/voice/speaker/encoder.d.ts.map +1 -0
  307. package/dist/services/voice/speaker-imprint.d.ts.map +1 -0
  308. package/dist/services/voice/speaker-preset-cache.d.ts.map +1 -0
  309. package/dist/services/voice/streaming-asr/streaming-pipeline-adapter.d.ts +160 -0
  310. package/dist/services/voice/streaming-asr/streaming-pipeline-adapter.d.ts.map +1 -0
  311. package/dist/services/voice/system-audio-sink.d.ts.map +1 -0
  312. package/{src → dist}/services/voice/transcriber.d.ts +4 -4
  313. package/dist/services/voice/transcriber.d.ts.map +1 -0
  314. package/dist/services/voice/transcript-knowledge.d.ts.map +1 -0
  315. package/{src → dist}/services/voice/transcript-service.d.ts +20 -1
  316. package/dist/services/voice/transcript-service.d.ts.map +1 -0
  317. package/{src → dist}/services/voice/transcript-store.d.ts +12 -1
  318. package/dist/services/voice/transcript-store.d.ts.map +1 -0
  319. package/dist/services/voice/turn-controller.d.ts.map +1 -0
  320. package/{src → dist}/services/voice/types.d.ts +6 -6
  321. package/dist/services/voice/types.d.ts.map +1 -0
  322. package/{src → dist}/services/voice/vad.d.ts +6 -5
  323. package/dist/services/voice/vad.d.ts.map +1 -0
  324. package/dist/services/voice/voice-budget.d.ts.map +1 -0
  325. package/dist/services/voice/voice-emotion-classifier.d.ts.map +1 -0
  326. package/dist/services/voice/voice-preload-predictor.d.ts +76 -0
  327. package/dist/services/voice/voice-preload-predictor.d.ts.map +1 -0
  328. package/{src → dist}/services/voice/voice-preset-format.d.ts +2 -2
  329. package/dist/services/voice/voice-preset-format.d.ts.map +1 -0
  330. package/dist/services/voice/voice-profile-artifact.d.ts.map +1 -0
  331. package/dist/services/voice/voice-profile-routes.d.ts.map +1 -0
  332. package/dist/services/voice/voice-scenario.d.ts +131 -0
  333. package/dist/services/voice/voice-scenario.d.ts.map +1 -0
  334. package/dist/services/voice/voice-state-machine.d.ts.map +1 -0
  335. package/dist/services/voice/voice-workbench-report.d.ts +117 -0
  336. package/dist/services/voice/voice-workbench-report.d.ts.map +1 -0
  337. package/{src → dist}/services/voice/wake-word-ggml.d.ts +8 -9
  338. package/dist/services/voice/wake-word-ggml.d.ts.map +1 -0
  339. package/dist/services/voice/wake-word.d.ts.map +1 -0
  340. package/dist/services/voice/wav-codec.d.ts +11 -0
  341. package/dist/services/voice/wav-codec.d.ts.map +1 -0
  342. package/dist/services/voice/workbench-entrypoint.d.ts +42 -0
  343. package/dist/services/voice/workbench-entrypoint.d.ts.map +1 -0
  344. package/dist/services/voice/workbench-headless-runner.d.ts +102 -0
  345. package/dist/services/voice/workbench-headless-runner.d.ts.map +1 -0
  346. package/dist/services/voice/workbench-logic-services.d.ts +36 -0
  347. package/dist/services/voice/workbench-logic-services.d.ts.map +1 -0
  348. package/dist/services/voice/workbench-real-services.d.ts +17 -0
  349. package/dist/services/voice/workbench-real-services.d.ts.map +1 -0
  350. package/dist/services/voice/workbench-scenarios.d.ts +24 -0
  351. package/dist/services/voice/workbench-scenarios.d.ts.map +1 -0
  352. package/dist/services/voice/wrap-with-first-line-cache.d.ts.map +1 -0
  353. package/dist/services/voice-model-updater.d.ts.map +1 -0
  354. package/dist/services/voice-prewarm.d.ts.map +1 -0
  355. package/dist/voice-workbench.d.ts +18 -0
  356. package/dist/voice-workbench.d.ts.map +1 -0
  357. package/dist/voice-workbench.js +5259 -0
  358. package/dist/voice-workbench.js.map +34 -0
  359. package/package.json +28 -9
  360. package/registry-entry.json +137 -0
  361. package/src/adapters/capacitor-llama/__tests__/voice-turn.test.ts +293 -0
  362. package/src/adapters/capacitor-llama/environment.ts +1 -1
  363. package/src/adapters/capacitor-llama/index.ts +28 -4
  364. package/src/adapters/capacitor-llama/native-voice-capture.ts +140 -0
  365. package/src/adapters/capacitor-llama/text-streaming.ts +2 -2
  366. package/src/adapters/capacitor-llama/voice-turn.ts +178 -0
  367. package/src/backends/apple-foundation.ts +1 -1
  368. package/src/local-inference-routes.test.ts +57 -11
  369. package/src/local-inference-routes.ts +90 -8
  370. package/src/provider.ts +32 -3
  371. package/src/routes/compat-helpers.ts +2 -1
  372. package/src/routes/index.ts +1 -0
  373. package/src/routes/live-diarization-route.test.ts +134 -0
  374. package/src/routes/live-diarization-route.ts +79 -3
  375. package/src/routes/local-inference-asr-route.test.ts +43 -2
  376. package/src/routes/local-inference-asr-route.ts +7 -4
  377. package/src/routes/local-inference-asr-transcribe.test.ts +4 -4
  378. package/src/routes/local-inference-asr-transcribe.ts +1 -1
  379. package/src/routes/local-inference-compat-routes.test.ts +3 -3
  380. package/src/routes/local-inference-compat-routes.ts +23 -56
  381. package/src/routes/native-pcm-turn-route.test.ts +136 -0
  382. package/src/routes/native-pcm-turn-route.ts +121 -0
  383. package/src/routes/transcripts-routes.test.ts +51 -0
  384. package/src/routes/transcripts-routes.ts +35 -3
  385. package/src/runtime/bionic-wire-encoding.test.ts +147 -0
  386. package/src/runtime/ensure-local-inference-handler.test.ts +203 -5
  387. package/src/runtime/ensure-local-inference-handler.ts +203 -11
  388. package/src/runtime/index.ts +4 -1
  389. package/src/runtime/mobile-local-inference-gate.test.ts +85 -2
  390. package/src/runtime/mobile-local-inference-gate.ts +60 -5
  391. package/src/runtime/voice-entity-binding.transcript.test.ts +29 -0
  392. package/src/runtime/voice-entity-binding.ts +46 -6
  393. package/src/runtime/voice-speaker-entity-contract.test.ts +149 -0
  394. package/src/services/README.md +2 -2
  395. package/src/services/__tests__/backend-selector.precedence.test.ts +333 -0
  396. package/src/services/active-model-context-fit.test.ts +125 -0
  397. package/src/services/active-model.ts +211 -8
  398. package/src/services/asr-provenance.ts +68 -0
  399. package/src/services/assignment-validation.test.ts +118 -0
  400. package/src/services/assignments.test.ts +26 -0
  401. package/src/services/assignments.ts +52 -4
  402. package/src/services/backend.test.ts +84 -0
  403. package/src/services/backend.ts +198 -19
  404. package/src/services/bionic-host-loader.test.ts +94 -1
  405. package/src/services/bionic-host-loader.ts +72 -0
  406. package/src/services/cache-bridge.test.ts +7 -7
  407. package/src/services/catalog.test.ts +32 -11
  408. package/src/services/catalog.ts +6 -0
  409. package/src/services/cloud-fallback.ts +1 -1
  410. package/src/services/context-fit.test.ts +121 -0
  411. package/src/services/context-fit.ts +113 -0
  412. package/src/services/desktop-fused-ffi-backend-runtime.ts +99 -7
  413. package/src/services/device-tier.test.ts +89 -2
  414. package/src/services/device-tier.ts +103 -11
  415. package/src/services/downloader.test.ts +199 -58
  416. package/src/services/downloader.ts +141 -27
  417. package/src/services/engine-direct-bundle.test.ts +38 -6
  418. package/src/services/engine.ts +291 -104
  419. package/src/services/ensure-local-artifacts.ts +1 -1
  420. package/src/services/ffi-llm-streaming-abi.ts +6 -3
  421. package/src/services/ffi-streaming-backend.ts +44 -8
  422. package/src/services/ffi-streaming-runner.test.ts +163 -3
  423. package/src/services/ffi-streaming-runner.ts +54 -1
  424. package/src/services/ffi-unload-ordering.test.ts +5 -1
  425. package/src/services/fused-eliza1-no-regression.test.ts +144 -0
  426. package/src/services/hardware.test.ts +7 -2
  427. package/src/services/hardware.ts +28 -0
  428. package/src/services/imagegen/backend-selector.test.ts +190 -0
  429. package/src/services/imagegen/sd-cpp.ts +6 -9
  430. package/src/services/index.ts +18 -0
  431. package/src/services/ios-llama-streaming.ts +1 -1
  432. package/src/services/kv-spill.ts +6 -5
  433. package/src/services/lib-target.test.ts +145 -0
  434. package/src/services/lib-target.ts +102 -0
  435. package/src/services/live-signals.test.ts +132 -0
  436. package/src/services/live-signals.ts +177 -0
  437. package/src/services/llama-server-metrics.test.ts +168 -0
  438. package/src/services/manifest/eliza-1.manifest.v1.json +84 -2
  439. package/src/services/manifest/index.ts +6 -0
  440. package/src/services/manifest/manifest.test.ts +156 -54
  441. package/src/services/manifest/schema.ts +160 -52
  442. package/src/services/manifest/types.ts +6 -0
  443. package/src/services/manifest/validator.ts +91 -25
  444. package/src/services/memory-arbiter.test.ts +139 -0
  445. package/src/services/memory-arbiter.ts +81 -15
  446. package/src/services/memory-benchmark.test.ts +91 -0
  447. package/src/services/memory-benchmark.ts +354 -0
  448. package/src/services/memory-monitor.test.ts +24 -0
  449. package/src/services/memory-monitor.ts +12 -0
  450. package/src/services/mtp-doctor.ts +10 -2
  451. package/src/services/network-policy.ts +5 -5
  452. package/src/services/ram-budget-cache.test.ts +2 -1
  453. package/src/services/ram-budget.ts +0 -0
  454. package/src/services/recommendation.test.ts +216 -0
  455. package/src/services/registry.ts +25 -19
  456. package/src/services/required-kernels-gate.test.ts +64 -0
  457. package/src/services/router-handler.ts +43 -24
  458. package/src/services/routing-policy.test.ts +211 -23
  459. package/src/services/routing-policy.ts +92 -22
  460. package/src/services/service.test.ts +3 -3
  461. package/src/services/service.ts +22 -7
  462. package/src/services/transcription-priority.test.ts +2 -2
  463. package/src/services/types.ts +4 -0
  464. package/src/services/verify-on-device.test.ts +2 -2
  465. package/src/services/vision/hash.ts +1 -1
  466. package/src/services/vision/index.ts +2 -2
  467. package/src/services/vision/llama-server.ts +1 -1
  468. package/src/services/vision/types.ts +13 -4
  469. package/src/services/vision-embedding-cache.ts +1 -1
  470. package/src/services/voice/VOICE_WORKBENCH.md +71 -26
  471. package/src/services/voice/__fixtures__/voice-workbench-logic-baseline.json +180 -0
  472. package/src/services/voice/__test-helpers__/synthetic-speech.ts +72 -2
  473. package/src/services/voice/__tests__/eliza1-eot-scorer.test.ts +29 -29
  474. package/src/services/voice/__tests__/streaming-asr.test.ts +1 -1
  475. package/src/services/voice/acoustic-speaker-attribution.test.ts +165 -0
  476. package/src/services/voice/acoustic-speaker-attribution.ts +336 -0
  477. package/src/services/voice/asr-timed.real.test.ts +6 -8
  478. package/src/services/voice/audio-frame-consumer.test.ts +327 -1
  479. package/src/services/voice/audio-frame-consumer.ts +165 -5
  480. package/src/services/voice/barge-in.ts +2 -3
  481. package/src/services/voice/corpus-augment.test.ts +276 -0
  482. package/src/services/voice/corpus-augment.ts +451 -0
  483. package/src/services/voice/corpus-generator.test.ts +201 -0
  484. package/src/services/voice/corpus-generator.ts +413 -0
  485. package/src/services/voice/diarization-error-rate.greedy.test.ts +140 -0
  486. package/src/services/voice/diarization-error-rate.test.ts +100 -0
  487. package/src/services/voice/diarization-error-rate.ts +249 -0
  488. package/src/services/voice/e2e-harness.der.test.ts +94 -0
  489. package/src/services/voice/e2e-harness.respond-eot-entity.test.ts +277 -0
  490. package/src/services/voice/e2e-harness.security-echo.test.ts +103 -0
  491. package/src/services/voice/e2e-harness.test.ts +2 -2
  492. package/src/services/voice/e2e-harness.ts +175 -16
  493. package/src/services/voice/echo-delay.test.ts +118 -0
  494. package/src/services/voice/echo-delay.ts +135 -0
  495. package/src/services/voice/echo-metrics.test.ts +17 -0
  496. package/src/services/voice/echo-metrics.ts +20 -0
  497. package/src/services/voice/echo-reference-buffer.test.ts +86 -0
  498. package/src/services/voice/echo-reference-buffer.ts +165 -0
  499. package/src/services/voice/eliza1-eot-scorer.ts +22 -22
  500. package/src/services/voice/embedding.ts +2 -3
  501. package/src/services/voice/engine-bridge-transcript-join.test.ts +278 -0
  502. package/src/services/voice/engine-bridge.ts +151 -110
  503. package/src/services/voice/eot-classifier-ggml.ts +42 -39
  504. package/src/services/voice/eot-classifier.test.ts +98 -0
  505. package/src/services/voice/eot-classifier.ts +11 -122
  506. package/src/services/voice/errors.ts +2 -0
  507. package/src/services/voice/expressive-tags.asr.test.ts +77 -0
  508. package/src/services/voice/expressive-tags.test.ts +102 -0
  509. package/src/services/voice/expressive-tags.ts +8 -8
  510. package/src/services/voice/ffi-bindings.test.ts +10 -3
  511. package/src/services/voice/ffi-bindings.ts +177 -15
  512. package/src/services/voice/fused-eot-scorer.ts +17 -13
  513. package/src/services/voice/index.ts +33 -12
  514. package/src/services/voice/kokoro/__tests__/kokoro-backend.test.ts +112 -1
  515. package/src/services/voice/kokoro/__tests__/kokoro-engine-bridge.real.test.ts +88 -3
  516. package/src/services/voice/kokoro/__tests__/runtime-selection.test.ts +37 -201
  517. package/src/services/voice/kokoro/kokoro-backend.ts +16 -0
  518. package/src/services/voice/kokoro/kokoro-engine-discovery.ts +1 -1
  519. package/src/services/voice/kokoro/kokoro-ffi-runtime.ts +3 -3
  520. package/src/services/voice/kokoro/pick-runtime.ts +1 -1
  521. package/src/services/voice/kokoro/runtime-selection.ts +28 -201
  522. package/src/services/voice/live-diarization-session.echo.test.ts +232 -0
  523. package/src/services/voice/live-diarization-session.ts +335 -2
  524. package/src/services/voice/metric-math.test.ts +61 -0
  525. package/src/services/voice/metric-math.ts +25 -0
  526. package/src/services/voice/mic-source.ts +1 -1
  527. package/src/services/voice/nlms-echo-canceller.test.ts +244 -0
  528. package/src/services/voice/nlms-echo-canceller.ts +317 -0
  529. package/src/services/voice/optimistic-policy.power-source.test.ts +36 -0
  530. package/src/services/voice/partial-stabilizer.ts +1 -1
  531. package/src/services/voice/pipeline.ts +3 -4
  532. package/src/services/voice/research/VOICE_8785_ASSESSMENT.md +141 -0
  533. package/src/services/voice/research/VOICE_PIPELINE_RESEARCH_2026.md +117 -0
  534. package/src/services/voice/research/VOICE_VALIDATION_RUNBOOK.md +135 -0
  535. package/src/services/voice/samantha-preset-regenerator.wav.test.ts +90 -0
  536. package/src/services/voice/self-voice-imprint.test.ts +59 -0
  537. package/src/services/voice/self-voice-imprint.ts +102 -0
  538. package/src/services/voice/shared-resources.ts +23 -0
  539. package/src/services/voice/speaker/attribution-pipeline.test.ts +221 -0
  540. package/src/services/voice/speaker/attribution-pipeline.ts +85 -22
  541. package/src/services/voice/speaker/encoder-ggml.test.ts +59 -0
  542. package/src/services/voice/transcriber.asr-backend.test.ts +76 -0
  543. package/src/services/voice/transcriber.ts +4 -4
  544. package/src/services/voice/transcript-service.test.ts +58 -0
  545. package/src/services/voice/transcript-service.ts +64 -0
  546. package/src/services/voice/transcript-store.test.ts +36 -0
  547. package/src/services/voice/transcript-store.ts +32 -0
  548. package/src/services/voice/types.ts +7 -7
  549. package/src/services/voice/vad.test.ts +33 -15
  550. package/src/services/voice/vad.ts +25 -20
  551. package/src/services/voice/voice-budget.test.ts +0 -3
  552. package/src/services/voice/voice-budget.ts +6 -6
  553. package/src/services/voice/voice-duet.test.ts +1 -1
  554. package/src/services/voice/voice-hardening.fuzz.test.ts +116 -0
  555. package/src/services/voice/voice-preload-predictor.test.ts +130 -0
  556. package/src/services/voice/voice-preload-predictor.ts +113 -0
  557. package/src/services/voice/voice-preset-format.fuzz.test.ts +89 -0
  558. package/src/services/voice/voice-preset-format.test.ts +75 -0
  559. package/src/services/voice/voice-preset-format.ts +17 -4
  560. package/src/services/voice/voice-scenario.test.ts +159 -0
  561. package/src/services/voice/voice-scenario.ts +133 -7
  562. package/src/services/voice/voice-scenario.turn-helpers.test.ts +77 -0
  563. package/src/services/voice/voice-workbench-report.ts +58 -17
  564. package/src/services/voice/wake-word-ggml.ts +12 -13
  565. package/src/services/voice/wav-codec.fuzz.test.ts +59 -0
  566. package/src/services/voice/wav-codec.test.ts +32 -0
  567. package/src/services/voice/wav-codec.ts +101 -0
  568. package/src/services/voice/workbench-entrypoint.test.ts +55 -0
  569. package/src/services/voice/workbench-entrypoint.ts +88 -0
  570. package/src/services/voice/workbench-headless-runner.test.ts +162 -0
  571. package/src/services/voice/workbench-headless-runner.ts +396 -0
  572. package/src/services/voice/workbench-logic-services.test.ts +225 -0
  573. package/src/services/voice/workbench-logic-services.ts +184 -0
  574. package/src/services/voice/workbench-real-services.ts +629 -0
  575. package/src/services/voice/workbench-scenarios.ts +407 -0
  576. package/src/services/voice-prewarm.ts +1 -1
  577. package/src/voice-workbench.ts +71 -0
  578. package/src/actions/generate-media.d.ts.map +0 -1
  579. package/src/actions/identify-speaker.d.ts.map +0 -1
  580. package/src/actions/transcription-control.d.ts.map +0 -1
  581. package/src/index.d.ts.map +0 -1
  582. package/src/local-inference-routes.d.ts.map +0 -1
  583. package/src/provider.d.ts.map +0 -1
  584. package/src/routes/compat-helpers.d.ts.map +0 -1
  585. package/src/routes/family-member-route.d.ts.map +0 -1
  586. package/src/routes/index.d.ts.map +0 -1
  587. package/src/routes/live-diarization-route.d.ts.map +0 -1
  588. package/src/routes/local-inference-asr-route.d.ts.map +0 -1
  589. package/src/routes/local-inference-asr-transcribe.d.ts.map +0 -1
  590. package/src/routes/local-inference-compat-routes.d.ts.map +0 -1
  591. package/src/routes/local-inference-tts-route.d.ts.map +0 -1
  592. package/src/routes/transcript-audio-store.d.ts.map +0 -1
  593. package/src/routes/transcripts-routes.d.ts.map +0 -1
  594. package/src/routes/voice-first-run-routes.d.ts.map +0 -1
  595. package/src/routes/voice-models-routes.d.ts.map +0 -1
  596. package/src/routes/voice-profile-plugin-routes.d.ts.map +0 -1
  597. package/src/routes/voice-profiles-management-routes.d.ts.map +0 -1
  598. package/src/routes/voice-speaker-profile-routes.d.ts.map +0 -1
  599. package/src/runtime/embedding-manager-support.d.ts.map +0 -1
  600. package/src/runtime/embedding-presets.d.ts.map +0 -1
  601. package/src/runtime/embedding-warmup-policy.d.ts.map +0 -1
  602. package/src/runtime/ensure-local-inference-handler.d.ts.map +0 -1
  603. package/src/runtime/index.d.ts.map +0 -1
  604. package/src/runtime/mobile-local-inference-gate.d.ts +0 -31
  605. package/src/runtime/mobile-local-inference-gate.d.ts.map +0 -1
  606. package/src/runtime/voice-entity-binding.d.ts.map +0 -1
  607. package/src/services/active-model.d.ts.map +0 -1
  608. package/src/services/assignments.d.ts.map +0 -1
  609. package/src/services/backend.d.ts.map +0 -1
  610. package/src/services/bionic-host-loader.d.ts.map +0 -1
  611. package/src/services/bundled-models.d.ts.map +0 -1
  612. package/src/services/cache-bridge.d.ts.map +0 -1
  613. package/src/services/catalog.d.ts +0 -10
  614. package/src/services/catalog.d.ts.map +0 -1
  615. package/src/services/checkpoint-client.d.ts.map +0 -1
  616. package/src/services/cloud-fallback.d.ts.map +0 -1
  617. package/src/services/conversation-registry.d.ts.map +0 -1
  618. package/src/services/desktop-fused-ffi-backend-runtime.d.ts.map +0 -1
  619. package/src/services/device-bridge.d.ts.map +0 -1
  620. package/src/services/device-resource-metrics.d.ts.map +0 -1
  621. package/src/services/device-tier.d.ts.map +0 -1
  622. package/src/services/downloader.d.ts.map +0 -1
  623. package/src/services/engine.d.ts.map +0 -1
  624. package/src/services/external-scanner.d.ts.map +0 -1
  625. package/src/services/ffi-streaming-backend.d.ts.map +0 -1
  626. package/src/services/ffi-streaming-runner.d.ts.map +0 -1
  627. package/src/services/gpu-detect.d.ts.map +0 -1
  628. package/src/services/handler-registry.d.ts.map +0 -1
  629. package/src/services/hardware.d.ts.map +0 -1
  630. package/src/services/hf-search.d.ts +0 -26
  631. package/src/services/hf-search.d.ts.map +0 -1
  632. package/src/services/hf-search.test.ts +0 -69
  633. package/src/services/hf-search.ts +0 -420
  634. package/src/services/image-description-runtime.d.ts.map +0 -1
  635. package/src/services/imagegen/aosp-unavailable.d.ts.map +0 -1
  636. package/src/services/imagegen/backend-selector.d.ts.map +0 -1
  637. package/src/services/imagegen/coreml-unavailable.d.ts.map +0 -1
  638. package/src/services/imagegen/errors.d.ts.map +0 -1
  639. package/src/services/imagegen/index.d.ts.map +0 -1
  640. package/src/services/imagegen/mflux.d.ts.map +0 -1
  641. package/src/services/imagegen/sd-cpp.d.ts.map +0 -1
  642. package/src/services/imagegen/tensorrt-unavailable.d.ts.map +0 -1
  643. package/src/services/imagegen/types.d.ts.map +0 -1
  644. package/src/services/index.d.ts.map +0 -1
  645. package/src/services/inference-capabilities.d.ts.map +0 -1
  646. package/src/services/inference-telemetry.d.ts.map +0 -1
  647. package/src/services/kv-spill.d.ts.map +0 -1
  648. package/src/services/latency-trace.d.ts.map +0 -1
  649. package/src/services/llm-streaming-binding.d.ts.map +0 -1
  650. package/src/services/load-args.d.ts.map +0 -1
  651. package/src/services/manifest/index.d.ts +0 -4
  652. package/src/services/manifest/index.d.ts.map +0 -1
  653. package/src/services/manifest/schema.d.ts.map +0 -1
  654. package/src/services/manifest/types.d.ts.map +0 -1
  655. package/src/services/manifest/validator.d.ts.map +0 -1
  656. package/src/services/memory-arbiter.d.ts.map +0 -1
  657. package/src/services/memory-monitor.d.ts.map +0 -1
  658. package/src/services/memory-pressure.d.ts.map +0 -1
  659. package/src/services/mtp-doctor.d.ts.map +0 -1
  660. package/src/services/network-policy.d.ts.map +0 -1
  661. package/src/services/paths.d.ts.map +0 -1
  662. package/src/services/planner-skeleton.d.ts.map +0 -1
  663. package/src/services/providers.d.ts.map +0 -1
  664. package/src/services/ram-budget.d.ts.map +0 -1
  665. package/src/services/readiness.d.ts.map +0 -1
  666. package/src/services/recommendation.d.ts.map +0 -1
  667. package/src/services/registry.d.ts.map +0 -1
  668. package/src/services/router-handler.d.ts.map +0 -1
  669. package/src/services/routing-policy.d.ts.map +0 -1
  670. package/src/services/routing-preferences.d.ts.map +0 -1
  671. package/src/services/runtime-target.d.ts.map +0 -1
  672. package/src/services/service.d.ts.map +0 -1
  673. package/src/services/session-pool.d.ts.map +0 -1
  674. package/src/services/structured-output/deterministic-repair.d.ts.map +0 -1
  675. package/src/services/structured-output.d.ts.map +0 -1
  676. package/src/services/system-memory.d.ts.map +0 -1
  677. package/src/services/types.d.ts.map +0 -1
  678. package/src/services/verify-on-device.d.ts.map +0 -1
  679. package/src/services/verify.d.ts.map +0 -1
  680. package/src/services/vision/aosp-unavailable.d.ts.map +0 -1
  681. package/src/services/vision/capacitor-llama.d.ts.map +0 -1
  682. package/src/services/vision/cloud-fallback.d.ts.map +0 -1
  683. package/src/services/vision/hash.d.ts.map +0 -1
  684. package/src/services/vision/index.d.ts.map +0 -1
  685. package/src/services/vision/llama-server.d.ts.map +0 -1
  686. package/src/services/vision/types.d.ts.map +0 -1
  687. package/src/services/vision/vast-fallback.d.ts.map +0 -1
  688. package/src/services/vision-embedding-cache.d.ts.map +0 -1
  689. package/src/services/voice/audio-frame-consumer.d.ts.map +0 -1
  690. package/src/services/voice/barge-in.d.ts.map +0 -1
  691. package/src/services/voice/cancellation-coordinator.d.ts.map +0 -1
  692. package/src/services/voice/checkpoint-manager.d.ts.map +0 -1
  693. package/src/services/voice/eager-context-builder.d.ts.map +0 -1
  694. package/src/services/voice/eliza1-eot-scorer.d.ts.map +0 -1
  695. package/src/services/voice/embedding.d.ts.map +0 -1
  696. package/src/services/voice/emotion-attribution.d.ts.map +0 -1
  697. package/src/services/voice/engine-bridge.d.ts.map +0 -1
  698. package/src/services/voice/eot-classifier-ggml.d.ts.map +0 -1
  699. package/src/services/voice/eot-classifier.d.ts.map +0 -1
  700. package/src/services/voice/errors.d.ts.map +0 -1
  701. package/src/services/voice/expressive-tags.d.ts.map +0 -1
  702. package/src/services/voice/ffi-bindings.d.ts.map +0 -1
  703. package/src/services/voice/first-line-cache.d.ts.map +0 -1
  704. package/src/services/voice/fused-eot-scorer.d.ts.map +0 -1
  705. package/src/services/voice/index.d.ts.map +0 -1
  706. package/src/services/voice/kokoro/kokoro-backend.d.ts.map +0 -1
  707. package/src/services/voice/kokoro/kokoro-engine-discovery.d.ts.map +0 -1
  708. package/src/services/voice/kokoro/kokoro-ffi-runtime.d.ts.map +0 -1
  709. package/src/services/voice/kokoro/kokoro-runtime.d.ts.map +0 -1
  710. package/src/services/voice/kokoro/phonemizer.d.ts.map +0 -1
  711. package/src/services/voice/kokoro/pick-runtime.d.ts.map +0 -1
  712. package/src/services/voice/kokoro/runtime-selection.d.ts +0 -92
  713. package/src/services/voice/kokoro/runtime-selection.d.ts.map +0 -1
  714. package/src/services/voice/kokoro/types.d.ts.map +0 -1
  715. package/src/services/voice/kokoro/voice-presets.d.ts.map +0 -1
  716. package/src/services/voice/kokoro/voices.d.ts.map +0 -1
  717. package/src/services/voice/lifecycle.d.ts.map +0 -1
  718. package/src/services/voice/live-diarization-session.d.ts +0 -96
  719. package/src/services/voice/live-diarization-session.d.ts.map +0 -1
  720. package/src/services/voice/mic-source.d.ts.map +0 -1
  721. package/src/services/voice/optimistic-policy.d.ts.map +0 -1
  722. package/src/services/voice/partial-stabilizer.d.ts.map +0 -1
  723. package/src/services/voice/phoneme-tokenizer.d.ts.map +0 -1
  724. package/src/services/voice/phrase-cache.d.ts.map +0 -1
  725. package/src/services/voice/phrase-chunker.d.ts.map +0 -1
  726. package/src/services/voice/pipeline-impls.d.ts.map +0 -1
  727. package/src/services/voice/pipeline.d.ts.map +0 -1
  728. package/src/services/voice/prefill-client.d.ts.map +0 -1
  729. package/src/services/voice/prefix-preserving-queue.d.ts.map +0 -1
  730. package/src/services/voice/profile-store.d.ts.map +0 -1
  731. package/src/services/voice/ring-buffer.d.ts.map +0 -1
  732. package/src/services/voice/rollback-queue.d.ts.map +0 -1
  733. package/src/services/voice/samantha-preset-placeholder.d.ts.map +0 -1
  734. package/src/services/voice/samantha-preset-regenerator.d.ts.map +0 -1
  735. package/src/services/voice/scheduler.d.ts.map +0 -1
  736. package/src/services/voice/shared-resources.d.ts.map +0 -1
  737. package/src/services/voice/speaker/attribution-pipeline.d.ts.map +0 -1
  738. package/src/services/voice/speaker/diarizer-fused.d.ts.map +0 -1
  739. package/src/services/voice/speaker/diarizer.d.ts.map +0 -1
  740. package/src/services/voice/speaker/encoder-fused.d.ts.map +0 -1
  741. package/src/services/voice/speaker/encoder-ggml.d.ts.map +0 -1
  742. package/src/services/voice/speaker/encoder.d.ts.map +0 -1
  743. package/src/services/voice/speaker-imprint.d.ts.map +0 -1
  744. package/src/services/voice/speaker-preset-cache.d.ts.map +0 -1
  745. package/src/services/voice/system-audio-sink.d.ts.map +0 -1
  746. package/src/services/voice/transcriber.d.ts.map +0 -1
  747. package/src/services/voice/transcript-knowledge.d.ts.map +0 -1
  748. package/src/services/voice/transcript-service.d.ts.map +0 -1
  749. package/src/services/voice/transcript-store.d.ts.map +0 -1
  750. package/src/services/voice/turn-controller.d.ts.map +0 -1
  751. package/src/services/voice/types.d.ts.map +0 -1
  752. package/src/services/voice/vad.d.ts.map +0 -1
  753. package/src/services/voice/voice-budget.d.ts.map +0 -1
  754. package/src/services/voice/voice-emotion-classifier.d.ts.map +0 -1
  755. package/src/services/voice/voice-preset-format.d.ts.map +0 -1
  756. package/src/services/voice/voice-profile-artifact.d.ts.map +0 -1
  757. package/src/services/voice/voice-profile-routes.d.ts.map +0 -1
  758. package/src/services/voice/voice-settings.d.ts +0 -82
  759. package/src/services/voice/voice-settings.d.ts.map +0 -1
  760. package/src/services/voice/voice-settings.ts +0 -172
  761. package/src/services/voice/voice-state-machine.d.ts.map +0 -1
  762. package/src/services/voice/wake-word-ggml.d.ts.map +0 -1
  763. package/src/services/voice/wake-word.d.ts.map +0 -1
  764. package/src/services/voice/wrap-with-first-line-cache.d.ts.map +0 -1
  765. package/src/services/voice-model-updater.d.ts.map +0 -1
  766. package/src/services/voice-prewarm.d.ts.map +0 -1
  767. /package/{src → dist}/actions/generate-media.d.ts +0 -0
  768. /package/{src → dist}/actions/identify-speaker.d.ts +0 -0
  769. /package/{src → dist}/actions/transcription-control.d.ts +0 -0
  770. /package/{src → dist}/index.d.ts +0 -0
  771. /package/{src → dist}/provider.d.ts +0 -0
  772. /package/{src → dist}/routes/family-member-route.d.ts +0 -0
  773. /package/{src → dist}/routes/local-inference-asr-route.d.ts +0 -0
  774. /package/{src → dist}/routes/local-inference-asr-transcribe.d.ts +0 -0
  775. /package/{src → dist}/routes/local-inference-compat-routes.d.ts +0 -0
  776. /package/{src → dist}/routes/local-inference-tts-route.d.ts +0 -0
  777. /package/{src → dist}/routes/transcript-audio-store.d.ts +0 -0
  778. /package/{src → dist}/routes/voice-first-run-routes.d.ts +0 -0
  779. /package/{src → dist}/routes/voice-models-routes.d.ts +0 -0
  780. /package/{src → dist}/routes/voice-profile-plugin-routes.d.ts +0 -0
  781. /package/{src → dist}/routes/voice-profiles-management-routes.d.ts +0 -0
  782. /package/{src → dist}/routes/voice-speaker-profile-routes.d.ts +0 -0
  783. /package/{src → dist}/runtime/embedding-manager-support.d.ts +0 -0
  784. /package/{src → dist}/runtime/embedding-presets.d.ts +0 -0
  785. /package/{src → dist}/runtime/embedding-warmup-policy.d.ts +0 -0
  786. /package/{src → dist}/services/bundled-models.d.ts +0 -0
  787. /package/{src → dist}/services/cache-bridge.d.ts +0 -0
  788. /package/{src → dist}/services/checkpoint-client.d.ts +0 -0
  789. /package/{src → dist}/services/cloud-fallback.d.ts +0 -0
  790. /package/{src → dist}/services/conversation-registry.d.ts +0 -0
  791. /package/{src → dist}/services/device-bridge.d.ts +0 -0
  792. /package/{src → dist}/services/device-resource-metrics.d.ts +0 -0
  793. /package/{src → dist}/services/external-scanner.d.ts +0 -0
  794. /package/{src → dist}/services/gpu-detect.d.ts +0 -0
  795. /package/{src → dist}/services/handler-registry.d.ts +0 -0
  796. /package/{src → dist}/services/hardware.d.ts +0 -0
  797. /package/{src → dist}/services/image-description-runtime.d.ts +0 -0
  798. /package/{src → dist}/services/imagegen/aosp-unavailable.d.ts +0 -0
  799. /package/{src → dist}/services/imagegen/backend-selector.d.ts +0 -0
  800. /package/{src → dist}/services/imagegen/coreml-unavailable.d.ts +0 -0
  801. /package/{src → dist}/services/imagegen/errors.d.ts +0 -0
  802. /package/{src → dist}/services/imagegen/index.d.ts +0 -0
  803. /package/{src → dist}/services/imagegen/mflux.d.ts +0 -0
  804. /package/{src → dist}/services/imagegen/tensorrt-unavailable.d.ts +0 -0
  805. /package/{src → dist}/services/imagegen/types.d.ts +0 -0
  806. /package/{src → dist}/services/inference-capabilities.d.ts +0 -0
  807. /package/{src → dist}/services/inference-telemetry.d.ts +0 -0
  808. /package/{src → dist}/services/kv-spill.d.ts +0 -0
  809. /package/{src → dist}/services/latency-trace.d.ts +0 -0
  810. /package/{src → dist}/services/llm-streaming-binding.d.ts +0 -0
  811. /package/{src → dist}/services/load-args.d.ts +0 -0
  812. /package/{src → dist}/services/manifest/validator.d.ts +0 -0
  813. /package/{src → dist}/services/memory-pressure.d.ts +0 -0
  814. /package/{src → dist}/services/mtp-doctor.d.ts +0 -0
  815. /package/{src → dist}/services/network-policy.d.ts +0 -0
  816. /package/{src → dist}/services/paths.d.ts +0 -0
  817. /package/{src → dist}/services/planner-skeleton.d.ts +0 -0
  818. /package/{src → dist}/services/providers.d.ts +0 -0
  819. /package/{src → dist}/services/ram-budget.d.ts +0 -0
  820. /package/{src → dist}/services/readiness.d.ts +0 -0
  821. /package/{src → dist}/services/recommendation.d.ts +0 -0
  822. /package/{src → dist}/services/routing-preferences.d.ts +0 -0
  823. /package/{src → dist}/services/runtime-target.d.ts +0 -0
  824. /package/{src → dist}/services/session-pool.d.ts +0 -0
  825. /package/{src → dist}/services/structured-output/deterministic-repair.d.ts +0 -0
  826. /package/{src → dist}/services/structured-output.d.ts +0 -0
  827. /package/{src → dist}/services/system-memory.d.ts +0 -0
  828. /package/{src → dist}/services/verify-on-device.d.ts +0 -0
  829. /package/{src → dist}/services/verify.d.ts +0 -0
  830. /package/{src → dist}/services/vision/aosp-unavailable.d.ts +0 -0
  831. /package/{src → dist}/services/vision/capacitor-llama.d.ts +0 -0
  832. /package/{src → dist}/services/vision/cloud-fallback.d.ts +0 -0
  833. /package/{src → dist}/services/vision/hash.d.ts +0 -0
  834. /package/{src → dist}/services/vision/llama-server.d.ts +0 -0
  835. /package/{src → dist}/services/vision/vast-fallback.d.ts +0 -0
  836. /package/{src → dist}/services/voice/barge-in.d.ts +0 -0
  837. /package/{src → dist}/services/voice/cancellation-coordinator.d.ts +0 -0
  838. /package/{src → dist}/services/voice/checkpoint-manager.d.ts +0 -0
  839. /package/{src → dist}/services/voice/eager-context-builder.d.ts +0 -0
  840. /package/{src → dist}/services/voice/emotion-attribution.d.ts +0 -0
  841. /package/{src → dist}/services/voice/first-line-cache.d.ts +0 -0
  842. /package/{src → dist}/services/voice/kokoro/kokoro-runtime.d.ts +0 -0
  843. /package/{src → dist}/services/voice/kokoro/phonemizer.d.ts +0 -0
  844. /package/{src → dist}/services/voice/kokoro/types.d.ts +0 -0
  845. /package/{src → dist}/services/voice/kokoro/voice-presets.d.ts +0 -0
  846. /package/{src → dist}/services/voice/kokoro/voices.d.ts +0 -0
  847. /package/{src → dist}/services/voice/lifecycle.d.ts +0 -0
  848. /package/{src → dist}/services/voice/optimistic-policy.d.ts +0 -0
  849. /package/{src → dist}/services/voice/phoneme-tokenizer.d.ts +0 -0
  850. /package/{src → dist}/services/voice/phrase-cache.d.ts +0 -0
  851. /package/{src → dist}/services/voice/phrase-chunker.d.ts +0 -0
  852. /package/{src → dist}/services/voice/pipeline-impls.d.ts +0 -0
  853. /package/{src → dist}/services/voice/pipeline.d.ts +0 -0
  854. /package/{src → dist}/services/voice/prefill-client.d.ts +0 -0
  855. /package/{src → dist}/services/voice/prefix-preserving-queue.d.ts +0 -0
  856. /package/{src → dist}/services/voice/profile-store.d.ts +0 -0
  857. /package/{src → dist}/services/voice/ring-buffer.d.ts +0 -0
  858. /package/{src → dist}/services/voice/rollback-queue.d.ts +0 -0
  859. /package/{src → dist}/services/voice/samantha-preset-placeholder.d.ts +0 -0
  860. /package/{src → dist}/services/voice/samantha-preset-regenerator.d.ts +0 -0
  861. /package/{src → dist}/services/voice/scheduler.d.ts +0 -0
  862. /package/{src → dist}/services/voice/speaker/attribution-pipeline.d.ts +0 -0
  863. /package/{src → dist}/services/voice/speaker/diarizer-fused.d.ts +0 -0
  864. /package/{src → dist}/services/voice/speaker/diarizer.d.ts +0 -0
  865. /package/{src → dist}/services/voice/speaker/encoder-fused.d.ts +0 -0
  866. /package/{src → dist}/services/voice/speaker/encoder-ggml.d.ts +0 -0
  867. /package/{src → dist}/services/voice/speaker/encoder.d.ts +0 -0
  868. /package/{src → dist}/services/voice/speaker-imprint.d.ts +0 -0
  869. /package/{src → dist}/services/voice/speaker-preset-cache.d.ts +0 -0
  870. /package/{src → dist}/services/voice/system-audio-sink.d.ts +0 -0
  871. /package/{src → dist}/services/voice/transcript-knowledge.d.ts +0 -0
  872. /package/{src → dist}/services/voice/turn-controller.d.ts +0 -0
  873. /package/{src → dist}/services/voice/voice-budget.d.ts +0 -0
  874. /package/{src → dist}/services/voice/voice-emotion-classifier.d.ts +0 -0
  875. /package/{src → dist}/services/voice/voice-profile-artifact.d.ts +0 -0
  876. /package/{src → dist}/services/voice/voice-profile-routes.d.ts +0 -0
  877. /package/{src → dist}/services/voice/voice-state-machine.d.ts +0 -0
  878. /package/{src → dist}/services/voice/wake-word.d.ts +0 -0
  879. /package/{src → dist}/services/voice/wrap-with-first-line-cache.d.ts +0 -0
  880. /package/{src → dist}/services/voice-model-updater.d.ts +0 -0
  881. /package/{src → dist}/services/voice-prewarm.d.ts +0 -0
@@ -0,0 +1,34 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/services/voice/wav-codec.ts", "../src/services/ffi-streaming-runner.ts", "../src/services/llm-streaming-binding.ts", "../src/services/voice/lifecycle.ts", "../src/services/voice/ffi-bindings.ts", "../src/services/desktop-fused-ffi-backend-runtime.ts", "../src/services/voice/speaker/diarizer.ts", "../src/services/voice/speaker/diarizer-fused.ts", "../src/services/voice/speaker-imprint.ts", "../src/services/voice/speaker/encoder-ggml.ts", "../src/services/voice/speaker/encoder.ts", "../src/services/voice/speaker/encoder-fused.ts", "../src/services/voice/transcriber.ts", "../src/services/voice/corpus-generator.ts", "../src/services/voice/__test-helpers__/synthetic-speech.ts", "../src/services/voice/corpus-augment.ts", "../src/services/voice/voice-scenario.ts", "../src/services/voice/metric-math.ts", "../src/services/voice/voice-workbench-report.ts", "../src/services/voice/workbench-entrypoint.ts", "../src/services/voice/workbench-headless-runner.ts", "../src/services/voice/e2e-harness.ts", "../src/services/voice/diarization-error-rate.ts", "../src/services/voice/workbench-scenarios.ts", "../src/services/voice/workbench-real-services.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Mono PCM16 WAV codec — dependency-light so corpus / fixture / test code can\n * encode + decode WAV without dragging in the heavy `engine-bridge` module\n * graph. `engine-bridge` re-exports these for its existing callers.\n */\n\nimport type { TranscriptionAudio } from \"./types\";\n\nfunction writeAscii(out: Uint8Array, offset: number, text: string): void {\n\tfor (let i = 0; i < text.length; i++) {\n\t\tout[offset + i] = text.charCodeAt(i);\n\t}\n}\n\nfunction readAscii(bytes: Uint8Array, offset: number, length: number): string {\n\tlet out = \"\";\n\tfor (let i = 0; i < length; i++) {\n\t\tout += String.fromCharCode(bytes[offset + i]);\n\t}\n\treturn out;\n}\n\n/** Encode mono float PCM as a 16-bit little-endian WAV byte stream. */\nexport function encodeMonoPcm16Wav(\n\tpcm: Float32Array,\n\tsampleRate: number,\n): Uint8Array {\n\tconst channels = 1;\n\tconst bytesPerSample = 2;\n\tconst dataBytes = pcm.length * bytesPerSample;\n\tconst out = new Uint8Array(44 + dataBytes);\n\tconst view = new DataView(out.buffer);\n\twriteAscii(out, 0, \"RIFF\");\n\tview.setUint32(4, 36 + dataBytes, true);\n\twriteAscii(out, 8, \"WAVE\");\n\twriteAscii(out, 12, \"fmt \");\n\tview.setUint32(16, 16, true);\n\tview.setUint16(20, 1, true);\n\tview.setUint16(22, channels, true);\n\tview.setUint32(24, sampleRate, true);\n\tview.setUint32(28, sampleRate * channels * bytesPerSample, true);\n\tview.setUint16(32, channels * bytesPerSample, true);\n\tview.setUint16(34, bytesPerSample * 8, true);\n\twriteAscii(out, 36, \"data\");\n\tview.setUint32(40, dataBytes, true);\n\n\tlet offset = 44;\n\tfor (const sample of pcm) {\n\t\tconst clamped = Math.max(-1, Math.min(1, sample));\n\t\tconst value = clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff;\n\t\tview.setInt16(offset, Math.round(value), true);\n\t\toffset += bytesPerSample;\n\t}\n\treturn out;\n}\n\n/** Decode a mono PCM16 WAV byte stream into float PCM + sample rate. */\nexport function decodeMonoPcm16Wav(bytes: Uint8Array): TranscriptionAudio {\n\tif (bytes.byteLength < 44) {\n\t\tthrow new Error(\"[voice] WAV input is too short to contain a header\");\n\t}\n\tconst view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n\tif (\n\t\treadAscii(bytes, 0, 4) !== \"RIFF\" ||\n\t\treadAscii(bytes, 8, 4) !== \"WAVE\" ||\n\t\treadAscii(bytes, 12, 4) !== \"fmt \"\n\t) {\n\t\tthrow new Error(\"[voice] Local transcription expects mono PCM16 WAV bytes\");\n\t}\n\tconst audioFormat = view.getUint16(20, true);\n\tconst channels = view.getUint16(22, true);\n\tconst sampleRate = view.getUint32(24, true);\n\tconst bitsPerSample = view.getUint16(34, true);\n\tif (audioFormat !== 1 || channels !== 1 || bitsPerSample !== 16) {\n\t\tthrow new Error(\n\t\t\t`[voice] Local transcription expects mono PCM16 WAV (format=1 channels=1 bits=16); got format=${audioFormat} channels=${channels} bits=${bitsPerSample}`,\n\t\t);\n\t}\n\n\tlet pos = 36;\n\twhile (pos + 8 <= bytes.byteLength) {\n\t\tconst chunkId = readAscii(bytes, pos, 4);\n\t\tconst chunkBytes = view.getUint32(pos + 4, true);\n\t\tconst dataStart = pos + 8;\n\t\tif (chunkId === \"data\") {\n\t\t\tif (dataStart + chunkBytes > bytes.byteLength) {\n\t\t\t\tthrow new Error(\"[voice] WAV data chunk exceeds input length\");\n\t\t\t}\n\t\t\tif (chunkBytes % 2 !== 0) {\n\t\t\t\tthrow new Error(\"[voice] WAV PCM16 data chunk has odd byte length\");\n\t\t\t}\n\t\t\tconst pcm = new Float32Array(chunkBytes / 2);\n\t\t\tfor (let i = 0; i < pcm.length; i++) {\n\t\t\t\tpcm[i] = view.getInt16(dataStart + i * 2, true) / 0x8000;\n\t\t\t}\n\t\t\treturn { pcm, sampleRate };\n\t\t}\n\t\tpos = dataStart + chunkBytes + (chunkBytes % 2);\n\t}\n\tthrow new Error(\"[voice] WAV input is missing a data chunk\");\n}\n",
6
+ "/**\n * In-process streaming-LLM runner.\n *\n * FFI streaming-LLM ABI declared in `ffi-streaming-llm.h`. The\n * token-by-token loop hands `onTextChunk` accepted chunks and surfaces\n * verifier events from native MTP.\n *\n * This file deliberately does not own the FFI context or the binding\n * itself. It takes a narrow `LlmStreamingBinding` (see\n * `services/llm-streaming-binding.ts`) + an opaque `LlmCtxHandle` as\n * constructor arguments — that way it can be driven by libelizainference\n * (via `wrapElizaInferenceFfi`) or any desktop libllama shim adapter without\n * dragging in TTS/ASR surfaces. A single context can host concurrent generation\n * sessions (one per pinned slot); the runner serialises with\n * `slotInFlight`.\n *\n * Single-flight: lock map keyed by slot id, slot id `-1` unlocked. Two concurrent generates\n * against the same pinned slot would interleave KV cache state, so the\n * runner serializes them at the JS layer.\n */\n\nimport { performance } from \"node:perf_hooks\";\n\nimport type {\n\tLlmCtxHandle,\n\tLlmStreamingBinding,\n} from \"./llm-streaming-binding\";\nimport type { LlmStreamHandle, LlmStreamStep } from \"./voice/ffi-bindings\";\nimport type { TextToken, VerifierStreamEvent } from \"./voice/types\";\n\nexport interface FfiStreamingGenerateArgs {\n\t/** Pre-tokenized prompt — the runner does not detokenize. */\n\tpromptTokens: Int32Array;\n\t/** Pinned slot id; -1 disables pinning (any free slot). */\n\tslotId: number;\n\t/** Optional prompt cache key used to derive a slot when `slotId === -1`. */\n\tcacheKey?: string;\n\tmaxTokens: number;\n\ttemperature: number;\n\ttopP: number;\n\ttopK: number;\n\trepeatPenalty: number;\n\tdraftMin: number;\n\tdraftMax: number;\n\t/** Reserved for separate draft-model speculation; null for Eliza-1 MTP. */\n\tdraftModelPath: string | null;\n\t/**\n\t * Per-load GPU offload (ABI v8). Forwarded into the native session config\n\t * on `llmStreamOpen`. The fused libelizainference path loads the text model\n\t * once per ctx, so the FIRST session's value wins; later sessions reuse the\n\t * resident model. `undefined` selects the runtime default (all layers).\n\t * The desktop libllama path already applies gpuLayers at `loadModel()`, so\n\t * it ignores this field — it is load-time config, threaded here only so the\n\t * fused runner can mirror the libllama load decision.\n\t */\n\tgpuLayers?: number;\n\t/**\n\t * KV-cache K/V quant type names (ABI v8), e.g. \"qjl1_256\" / \"q4_polar\".\n\t * Same load-time semantics as `gpuLayers`: forwarded into the fused\n\t * session config so the first `llmStreamOpen` applies the quantized cache.\n\t */\n\tcacheTypeK?: string | null;\n\tcacheTypeV?: string | null;\n\t/**\n\t * Runtime context window in tokens (ABI v9). Forwarded into the fused\n\t * session config on `llmStreamOpen`; `undefined` keeps the native\n\t * ELIZA_LLM_N_CTX/default fallback.\n\t */\n\tcontextSize?: number;\n\t/**\n\t * GBNF grammar source forcing the structured-reply envelope. Passed to\n\t * the native session's `llmStreamOpen` config so sampling is\n\t * grammar-constrained. `null` disables the constraint (free generation).\n\t */\n\tgbnfGrammar?: string | null;\n\t/** Cancellation signal — fires `llmStreamCancel` on the active session. */\n\tsignal?: AbortSignal;\n\t/**\n\t * Per-step token cap for the native decode loop. Lower values make the\n\t * local UI stream in finer-grained jumps (smoother token-by-token render)\n\t * at the cost of more JS↔FFI round-trips per reply; higher values batch\n\t * more tokens per step. When omitted, falls back to\n\t * `resolveMaxTokensPerStep()` (env `ELIZA_LOCAL_STREAM_TOKENS_PER_STEP`,\n\t * else `DEFAULT_MAX_TOKENS_PER_STEP`). Clamped to\n\t * `[MIN_MAX_TOKENS_PER_STEP, MAX_MAX_TOKENS_PER_STEP]`.\n\t */\n\tmaxTokensPerStep?: number;\n\t/** Per-chunk text callback. */\n\tonTextChunk?: (chunk: string) => void | Promise<void>;\n\t/** Speculative accept/reject events from MTP verification. */\n\tonVerifierEvent?: (event: VerifierStreamEvent) => void | Promise<void>;\n}\n\nexport interface FfiStreamingGenerateResult {\n\ttext: string;\n\tslotId: number;\n\tfirstTokenMs: number | null;\n\tdrafted: number;\n\taccepted: number;\n}\n\n/** Default per-step caps. Match upstream llama-server's `n_predict` chunk size. */\nconst DEFAULT_MAX_TOKENS_PER_STEP = 32;\nconst DEFAULT_MAX_TEXT_BYTES = 1024;\n/**\n * Sane bounds for the per-step token cap. The floor is 1 (true\n * token-by-token); the ceiling guards against pathological values that would\n * defeat streaming by emitting the whole reply in one step.\n */\nconst MIN_MAX_TOKENS_PER_STEP = 1;\nconst MAX_MAX_TOKENS_PER_STEP = 512;\n\n/** Clamp a caller-supplied per-step cap into the supported range. */\nfunction clampMaxTokensPerStep(value: number): number {\n\tif (!Number.isFinite(value)) return DEFAULT_MAX_TOKENS_PER_STEP;\n\treturn Math.min(\n\t\tMAX_MAX_TOKENS_PER_STEP,\n\t\tMath.max(MIN_MAX_TOKENS_PER_STEP, Math.trunc(value)),\n\t);\n}\n\n/**\n * Resolve the per-step token cap for the native decode loop. Override via the\n * `ELIZA_LOCAL_STREAM_TOKENS_PER_STEP` env var (e.g. set to `8` for smoother\n * local streaming, weighed against the extra JS↔FFI round-trips and the shared\n * voice phrase-chunker). Falls back to `DEFAULT_MAX_TOKENS_PER_STEP` (32) when\n * unset or invalid; clamped to `[MIN_MAX_TOKENS_PER_STEP, MAX_MAX_TOKENS_PER_STEP]`.\n */\nexport function resolveMaxTokensPerStep(): number {\n\tconst raw = process.env.ELIZA_LOCAL_STREAM_TOKENS_PER_STEP?.trim();\n\tif (!raw) return DEFAULT_MAX_TOKENS_PER_STEP;\n\tconst parsed = Number.parseInt(raw, 10);\n\tif (!Number.isFinite(parsed)) return DEFAULT_MAX_TOKENS_PER_STEP;\n\treturn clampMaxTokensPerStep(parsed);\n}\n\n/**\n * Backend used by the mobile and desktop FFI routes.\n */\nexport class FfiStreamingRunner {\n\tprivate readonly slotInFlight = new Map<number, Promise<void>>();\n\n\t/**\n\t * Constructor takes the narrow `LlmStreamingBinding` (see\n\t * `services/llm-streaming-binding.ts`) so both libelizainference (via\n\t * `wrapElizaInferenceFfi`) and desktop libllama adapters can\n\t * satisfy it. The runner never touches TTS/ASR/mmap surfaces.\n\t */\n\tconstructor(\n\t\tprivate readonly ffi: LlmStreamingBinding,\n\t\tprivate readonly ctx: LlmCtxHandle,\n\t) {}\n\n\t/**\n\t * Run one generation. Mirrors `MtpLlamaServer.generateWithUsage()`\n\t * — same single-flight rule, same callback shape, same result block\n\t * minus the metrics scrape (FFI does not have a `/metrics` endpoint).\n\t */\n\tasync generateWithUsage(\n\t\targs: FfiStreamingGenerateArgs,\n\t): Promise<FfiStreamingGenerateResult> {\n\t\tif (args.slotId < 0) {\n\t\t\treturn this.runGenerate(args);\n\t\t}\n\t\tconst prior = this.slotInFlight.get(args.slotId);\n\t\tconst run = (prior ?? Promise.resolve())\n\t\t\t.catch(() => {})\n\t\t\t.then(() => this.runGenerate(args));\n\t\tconst tail = run.then(\n\t\t\t() => {},\n\t\t\t() => {},\n\t\t);\n\t\tthis.slotInFlight.set(args.slotId, tail);\n\t\ttry {\n\t\t\treturn await run;\n\t\t} finally {\n\t\t\tif (this.slotInFlight.get(args.slotId) === tail) {\n\t\t\t\tthis.slotInFlight.delete(args.slotId);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Async-iterable variant. Yields each accepted-token batch as it lands\n\t * so callers that want token-grained control (e.g. the voice scheduler\n\t * driving phrase-chunking off accept/reject events) don't have to\n\t * register a callback. Internally still routes through `generateWithUsage`\n\t * via a pump so the single-flight rule applies.\n\t */\n\tasync *generateStream(\n\t\targs: FfiStreamingGenerateArgs,\n\t): AsyncIterable<LlmStreamStep> {\n\t\t// Queue accumulates steps the inner callback produces; the iterator\n\t\t// drains it. Using a plain array + resolver is simpler than wiring a\n\t\t// real async-queue for the single-consumer case here.\n\t\tconst queue: LlmStreamStep[] = [];\n\t\tlet resume: (() => void) | null = null;\n\t\tlet finished = false;\n\t\tlet failure: Error | null = null;\n\n\t\tconst wakeConsumer = () => {\n\t\t\tconst wake = resume;\n\t\t\tresume = null;\n\t\t\tif (wake) wake();\n\t\t};\n\n\t\tconst onStep = (step: LlmStreamStep) => {\n\t\t\tqueue.push(step);\n\t\t\twakeConsumer();\n\t\t};\n\n\t\tconst work = (async () => {\n\t\t\ttry {\n\t\t\t\tawait this.runGenerateInner(args, onStep);\n\t\t\t} catch (err) {\n\t\t\t\tfailure = err instanceof Error ? err : new Error(String(err));\n\t\t\t} finally {\n\t\t\t\tfinished = true;\n\t\t\t\twakeConsumer();\n\t\t\t}\n\t\t})();\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tif (queue.length > 0) {\n\t\t\t\t\tconst next = queue.shift();\n\t\t\t\t\tif (next === undefined) continue;\n\t\t\t\t\tyield next;\n\t\t\t\t\tif (next.done) return;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (failure) throw failure;\n\t\t\t\tif (finished) return;\n\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\tresume = resolve;\n\t\t\t\t});\n\t\t\t}\n\t\t} finally {\n\t\t\tawait work;\n\t\t}\n\t}\n\n\t/**\n\t * Save the streaming slot KV state to disk. Best called between turns\n\t * — calling mid-stream is racy and the FFI side is allowed to refuse.\n\t * Surfaced here so the conversation registry can persist between\n\t * mobile backgrounds the same way `MtpLlamaServer.persistSlot` does.\n\t */\n\tsaveSlot(stream: LlmStreamHandle, filename: string): void {\n\t\tif (this.ffi.llmStreamSaveSlot === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t\"[ffi-streaming-runner] llmStreamSaveSlot is not exported by this build\",\n\t\t\t);\n\t\t}\n\t\tthis.ffi.llmStreamSaveSlot({ stream, filename });\n\t}\n\n\t/** Restore a previously-saved slot KV file into a fresh session. */\n\trestoreSlot(stream: LlmStreamHandle, filename: string): void {\n\t\tif (this.ffi.llmStreamRestoreSlot === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t\"[ffi-streaming-runner] llmStreamRestoreSlot is not exported by this build\",\n\t\t\t);\n\t\t}\n\t\tthis.ffi.llmStreamRestoreSlot({ stream, filename });\n\t}\n\n\t/* ----- internals -------------------------------------------------- */\n\n\tprivate async runGenerate(\n\t\targs: FfiStreamingGenerateArgs,\n\t): Promise<FfiStreamingGenerateResult> {\n\t\tconst aggregated: string[] = [];\n\t\tlet totalDrafted = 0;\n\t\tlet totalAccepted = 0;\n\t\tlet firstTokenMs: number | null = null;\n\t\tconst startedAt = performance.now();\n\n\t\tawait this.runGenerateInner(args, (step) => {\n\t\t\tif (step.text.length > 0 && firstTokenMs === null) {\n\t\t\t\tfirstTokenMs = performance.now() - startedAt;\n\t\t\t}\n\t\t\taggregated.push(step.text);\n\t\t\ttotalDrafted += step.drafterDrafted;\n\t\t\ttotalAccepted += step.drafterAccepted;\n\t\t});\n\n\t\treturn {\n\t\t\ttext: aggregated.join(\"\"),\n\t\t\tslotId: args.slotId,\n\t\t\tfirstTokenMs,\n\t\t\tdrafted: totalDrafted,\n\t\t\taccepted: totalAccepted,\n\t\t};\n\t}\n\n\t/**\n\t * Shared inner loop. Opens the session, runs the prefill + next pump,\n\t * forwards each step through `onStep` plus the optional caller\n\t * callbacks, and wires abort + cancel.\n\t */\n\tprivate async runGenerateInner(\n\t\targs: FfiStreamingGenerateArgs,\n\t\tonStep: (step: LlmStreamStep) => void,\n\t): Promise<void> {\n\t\tif (\n\t\t\tthis.ffi.llmStreamOpen === undefined ||\n\t\t\tthis.ffi.llmStreamPrefill === undefined ||\n\t\t\tthis.ffi.llmStreamNext === undefined ||\n\t\t\tthis.ffi.llmStreamClose === undefined\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"[ffi-streaming-runner] libelizainference is missing streaming-LLM symbols. \" +\n\t\t\t\t\t\"Rebuild against the current eliza-inference-ffi.h.\",\n\t\t\t);\n\t\t}\n\n\t\tconst stream = this.ffi.llmStreamOpen({\n\t\t\tctx: this.ctx,\n\t\t\tconfig: {\n\t\t\t\tmaxTokens: args.maxTokens,\n\t\t\t\ttemperature: args.temperature,\n\t\t\t\ttopP: args.topP,\n\t\t\t\ttopK: args.topK,\n\t\t\t\trepeatPenalty: args.repeatPenalty,\n\t\t\t\tslotId: args.slotId,\n\t\t\t\tpromptCacheKey: args.cacheKey ?? null,\n\t\t\t\tdraftMin: args.draftMin,\n\t\t\t\tdraftMax: args.draftMax,\n\t\t\t\tdraftModelPath: args.draftModelPath,\n\t\t\t\tgbnfGrammar: args.gbnfGrammar ?? null,\n\t\t\t\tgpuLayers: args.gpuLayers,\n\t\t\t\tcacheTypeK: args.cacheTypeK,\n\t\t\t\tcacheTypeV: args.cacheTypeV,\n\t\t\t\tcontextSize: args.contextSize,\n\t\t\t},\n\t\t});\n\n\t\tlet abortListener: (() => void) | null = null;\n\t\tif (args.signal) {\n\t\t\tif (args.signal.aborted) {\n\t\t\t\tthis.ffi.llmStreamCancel?.(stream);\n\t\t\t\tthis.ffi.llmStreamClose(stream);\n\t\t\t\tthrow new Error(\"[ffi-streaming-runner] aborted before start\");\n\t\t\t}\n\t\t\tabortListener = () => {\n\t\t\t\tthis.ffi.llmStreamCancel?.(stream);\n\t\t\t};\n\t\t\targs.signal.addEventListener(\"abort\", abortListener, { once: true });\n\t\t}\n\n\t\ttry {\n\t\t\tthis.ffi.llmStreamPrefill({ stream, tokens: args.promptTokens });\n\t\t\tif (args.maxTokens <= 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst maxTokensPerStep =\n\t\t\t\targs.maxTokensPerStep !== undefined\n\t\t\t\t\t? clampMaxTokensPerStep(args.maxTokensPerStep)\n\t\t\t\t\t: resolveMaxTokensPerStep();\n\n\t\t\tlet tokenIndex = 0;\n\t\t\twhile (true) {\n\t\t\t\tif (args.signal?.aborted) {\n\t\t\t\t\tthis.ffi.llmStreamCancel?.(stream);\n\t\t\t\t\tthrow new Error(\"[ffi-streaming-runner] aborted\");\n\t\t\t\t}\n\t\t\t\tconst step = this.ffi.llmStreamNext({\n\t\t\t\t\tstream,\n\t\t\t\t\tmaxTokensPerStep,\n\t\t\t\t\tmaxTextBytes: DEFAULT_MAX_TEXT_BYTES,\n\t\t\t\t});\n\t\t\t\tonStep(step);\n\n\t\t\t\tif (args.onTextChunk && step.text.length > 0) {\n\t\t\t\t\tawait args.onTextChunk(step.text);\n\t\t\t\t}\n\t\t\t\tif (args.onVerifierEvent) {\n\t\t\t\t\tconst tokens: TextToken[] = step.tokens.map((id, i) => ({\n\t\t\t\t\t\tindex: tokenIndex + i,\n\t\t\t\t\t\ttext: i === 0 ? step.text : \"\",\n\t\t\t\t\t\tid,\n\t\t\t\t\t}));\n\t\t\t\t\t// The FFI ABI commits accepted tokens per step (the drafter\n\t\t\t\t\t// accept/reject decomposition is delivered through the\n\t\t\t\t\t// separate `setVerifierCallback` channel — see ffi.h §v2).\n\t\t\t\t\t// Surface the batched accept here so HTTP-path callers see a\n\t\t\t\t\t// matching event shape.\n\t\t\t\t\tif (tokens.length > 0) {\n\t\t\t\t\t\tawait args.onVerifierEvent({\n\t\t\t\t\t\t\tkind: \"accept\",\n\t\t\t\t\t\t\ttokens,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttokenIndex += step.tokens.length;\n\t\t\t\tif (step.done) break;\n\t\t\t}\n\t\t} finally {\n\t\t\tif (abortListener && args.signal) {\n\t\t\t\targs.signal.removeEventListener(\"abort\", abortListener);\n\t\t\t}\n\t\t\tthis.ffi.llmStreamClose(stream);\n\t\t}\n\t}\n}\n",
7
+ "/**\n * Narrow streaming-LLM binding.\n *\n * `FfiStreamingRunner` (`services/ffi-streaming-runner.ts`) used to require\n * the full `ElizaInferenceFfi` surface (TTS + ASR + VAD + mmap regions +\n * the entire fused libelizainference) just to run text generation. That\n * surface implies a *bundle-anchored* runtime — libelizainference owns a\n * context built from a bundle root, not a single GGUF — and ~25 methods\n * that have nothing to do with LLM streaming.\n *\n * This file extracts the actual contract the runner depends on: the seven\n * `llmStream*` methods plus the (optional) two slot save/restore methods.\n * Both libelizainference (via a tiny adapter) and the desktop\n * libllama + eliza-llama-shim path (built by `build-llama-cpp-desktop-dylib.mjs`,\n * mirroring the AOSP adapter pattern) can implement this narrow contract\n * without dragging in TTS/ASR.\n *\n * See `plugins/plugin-local-inference/FFI_BACKEND_WIREUP_PLAN.md` Step B\n * for the desktop adapter follow-up that implements this interface against\n * the libllama symbols.\n */\n\nimport type {\n\tElizaInferenceContextHandle,\n\tElizaInferenceFfi,\n\tLlmStreamConfig,\n\tLlmStreamHandle,\n\tLlmStreamStep,\n} from \"./voice/ffi-bindings\";\n\n/**\n * Opaque per-context handle. For libelizainference this is the\n * `ElizaInferenceContextHandle` (a bigint pointer to the bundle context).\n * For the desktop libllama path it's a bigint pointer to a per-model\n * llama_context. The runner only needs to pass it through to\n * `llmStreamOpen`.\n */\nexport type LlmCtxHandle = ElizaInferenceContextHandle;\n\n/**\n * The streaming-LLM contract `FfiStreamingRunner` consumes. Methods\n * mirror the C ABI declared in `tools/omnivoice/include/eliza-inference-ffi.h`\n * (the `eliza_inference_llm_stream_*` surface), but the binding doesn't have\n * to come from libelizainference — any implementation that satisfies this\n * interface works.\n *\n * Slot save/restore are optional because the desktop libllama path\n * does not expose `llama_state_seq_save_file` / `_load_file` through\n * the shim yet. The runner already guards both methods via\n * `if (this.ffi.llmStreamSaveSlot === undefined) throw ...`.\n */\nexport interface LlmStreamingBinding {\n\t/** Probe — must return `true` for the binding to be usable by the runner. */\n\tllmStreamSupported(): boolean;\n\t/**\n\t * Open a streaming-LLM session against `ctx`. Failure throws an\n\t * implementation-specific error (`VoiceLifecycleError` for\n\t * libelizainference). Close exactly once via `llmStreamClose`.\n\t */\n\tllmStreamOpen(args: {\n\t\tctx: LlmCtxHandle;\n\t\tconfig: LlmStreamConfig;\n\t}): LlmStreamHandle;\n\t/** Feed a batch of pre-tokenized prompt tokens before the first `next`. */\n\tllmStreamPrefill(args: { stream: LlmStreamHandle; tokens: Int32Array }): void;\n\t/**\n\t * Pull the next streaming step. `step.done === true` is the final step.\n\t * Implementations may bound the step by `maxTokensPerStep` /\n\t * `maxTextBytes`; defaults are runner-side.\n\t */\n\tllmStreamNext(args: {\n\t\tstream: LlmStreamHandle;\n\t\tmaxTokensPerStep?: number;\n\t\tmaxTextBytes?: number;\n\t}): LlmStreamStep;\n\t/** Cancel in-flight generation; the next `_next` returns CANCELLED. */\n\tllmStreamCancel(stream: LlmStreamHandle): void;\n\t/** Close + free a streaming-LLM session. Idempotent on already-closed handles. */\n\tllmStreamClose(stream: LlmStreamHandle): void;\n\t/** Optional — persist the session's slot KV state to disk. */\n\tllmStreamSaveSlot?(args: { stream: LlmStreamHandle; filename: string }): void;\n\t/** Optional — restore a previously-saved slot KV file. */\n\tllmStreamRestoreSlot?(args: {\n\t\tstream: LlmStreamHandle;\n\t\tfilename: string;\n\t}): void;\n}\n\n/**\n * Wrap a full `ElizaInferenceFfi` as a narrow `LlmStreamingBinding`.\n * The libelizainference path already implements the `llmStream*` methods\n * as optional properties; this adapter promotes them to required and\n * throws if the loaded library is too old to expose them.\n *\n * Usage:\n * const binding = wrapElizaInferenceFfi(ffi);\n * const runner = new FfiStreamingRunner(binding, ctxHandle);\n */\nexport function wrapElizaInferenceFfi(\n\tffi: ElizaInferenceFfi,\n): LlmStreamingBinding {\n\tif (\n\t\ttypeof ffi.llmStreamSupported !== \"function\" ||\n\t\t!ffi.llmStreamSupported() ||\n\t\ttypeof ffi.llmStreamOpen !== \"function\" ||\n\t\ttypeof ffi.llmStreamPrefill !== \"function\" ||\n\t\ttypeof ffi.llmStreamNext !== \"function\" ||\n\t\ttypeof ffi.llmStreamCancel !== \"function\" ||\n\t\ttypeof ffi.llmStreamClose !== \"function\"\n\t) {\n\t\tthrow new Error(\n\t\t\t\"[llm-streaming-binding] The loaded libelizainference does not expose \" +\n\t\t\t\t\"the streaming-LLM symbol set (llmStreamSupported/Open/Prefill/Next/\" +\n\t\t\t\t\"Cancel/Close). Rebuild the omnivoice fuse against the current \" +\n\t\t\t\t\"eliza-inference-ffi.h (verify-fused-symbols requires this set).\",\n\t\t);\n\t}\n\t// Narrowed function references so the returned object types are\n\t// non-optional even though the source surface declares them\n\t// optional.\n\tconst open = ffi.llmStreamOpen;\n\tconst prefill = ffi.llmStreamPrefill;\n\tconst next = ffi.llmStreamNext;\n\tconst cancel = ffi.llmStreamCancel;\n\tconst close = ffi.llmStreamClose;\n\treturn {\n\t\tllmStreamSupported: () => true,\n\t\tllmStreamOpen: open,\n\t\tllmStreamPrefill: prefill,\n\t\tllmStreamNext: next,\n\t\tllmStreamCancel: cancel,\n\t\tllmStreamClose: close,\n\t\tllmStreamSaveSlot: ffi.llmStreamSaveSlot,\n\t\tllmStreamRestoreSlot: ffi.llmStreamRestoreSlot,\n\t};\n}\n",
8
+ "/**\n * Voice on/off state machine.\n *\n * Per `packages/inference/AGENTS.md` §4 + this scope's design goals,\n * voice is OFF by default. Text + native MTP are hot; TTS, ASR, the\n * speaker preset cache and phrase cache, the chunker, the rollback\n * queue, the barge-in controller, and the ring buffer are NOT in RAM.\n *\n * Transitions are explicit. Illegal transitions throw — no\n * \"log-and-continue\" (AGENTS.md §9). The transition to `voice-off`\n * MUST issue a real page-eviction call on the TTS/ASR mmap regions\n * (see `MmapRegionHandle.evictPages()` in `shared-resources.ts`) so\n * the OS can reclaim those pages.\n *\n * ┌──────────┐ start() ┌──────────────┐ armed ┌──────────┐\n * │ voice-off│─────────▶│ voice-arming │────────▶│ voice-on │\n * └──────────┘ └──────────────┘ └──────────┘\n * ▲ │ start fails │ stop()\n * │ disarmed ▼ ▼\n * ┌──────────────────┐ ┌──────────────┐ ┌────────────────────┐\n * │ voice-disarming │◀───│ voice-error │ │ voice-disarming │\n * └──────────────────┘ └──────────────┘ └────────────────────┘\n * │ │\n * └────────────────── disarmed ◀───────────────┘\n *\n * `voice-error` is terminal until `reset()` is called. There is no\n * automatic retry: a missing kernel, mmap fail, or RAM-pressure\n * refusal MUST surface to the caller.\n */\n\nimport type {\n\tKernelSet,\n\tMmapRegionHandle,\n\tMtpDraftHandle,\n\tRefCountedResource,\n\tSchedulerSlot,\n\tSharedResourceRegistry,\n\tSharedTokenizer,\n} from \"./shared-resources\";\n\n/**\n * Discriminated union — never widened to `string`. Each state may carry\n * payload (the `armed` payload includes the loaded mmap regions so the\n * disarm path can call `evictPages()` on them).\n */\nexport type VoiceLifecycleState =\n\t| { readonly kind: \"voice-off\" }\n\t| { readonly kind: \"voice-arming\" }\n\t| { readonly kind: \"voice-on\"; readonly resources: ArmedResources }\n\t| { readonly kind: \"voice-disarming\"; readonly resources: ArmedResources }\n\t| { readonly kind: \"voice-error\"; readonly error: VoiceLifecycleError };\n\n/**\n * Resources held while voice is armed. Released in reverse order on\n * disarm; the mmap regions get an explicit `evictPages()` call before\n * `release()` so the OS reclaims pages even if the FFI keeps the file\n * descriptor open for the next re-arm.\n */\nexport interface ArmedResources {\n\treadonly tts: MmapRegionHandle;\n\treadonly asr: MmapRegionHandle;\n\t/** Speaker preset + phrase cache — kept in a small LRU after disarm. */\n\treadonly voiceCaches: RefCountedResource;\n\t/** Voice-specific scheduler nodes (chunker, rollback, ring buffer, barge-in). */\n\treadonly voiceSchedulerNodes: RefCountedResource;\n}\n\n/**\n * Resources held while text is up. Acquired by the engine when the\n * bundle is activated; voice piggy-backs on these without re-loading.\n */\nexport interface TextResources {\n\treadonly tokenizer: SharedTokenizer;\n\treadonly textWeights: MmapRegionHandle;\n\treadonly kernels: KernelSet;\n\treadonly scheduler: SchedulerSlot;\n\treadonly mtp: MtpDraftHandle;\n}\n\n/**\n * Structured failure surfaced to the caller. Never a generic `Error` —\n * the caller (engine + UI) needs to distinguish RAM pressure from a\n * missing kernel from a manifest mismatch (AGENTS.md §3).\n */\nexport class VoiceLifecycleError extends Error {\n\treadonly code:\n\t\t| \"ram-pressure\"\n\t\t| \"mmap-fail\"\n\t\t| \"kernel-missing\"\n\t\t| \"illegal-transition\"\n\t\t| \"arm-failed\"\n\t\t| \"disarm-failed\";\n\n\tconstructor(code: VoiceLifecycleError[\"code\"], message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"VoiceLifecycleError\";\n\t\tthis.code = code;\n\t}\n}\n\n/**\n * Loader functions injected at construction. Splitting these out keeps\n * `VoiceLifecycle` independent of FFI specifics — the engine wires real\n * loaders at runtime; tests inject mocks. Each loader MUST throw on\n * failure (AGENTS.md §3 — no silent fallback).\n */\nexport interface VoiceLifecycleLoaders {\n\tloadTtsRegion(): Promise<MmapRegionHandle>;\n\tloadAsrRegion(): Promise<MmapRegionHandle>;\n\tloadVoiceCaches(): Promise<RefCountedResource>;\n\tloadVoiceSchedulerNodes(): Promise<RefCountedResource>;\n}\n\nexport interface VoiceLifecycleEvents {\n\tonTransition?(prev: VoiceLifecycleState, next: VoiceLifecycleState): void;\n}\n\nexport class VoiceLifecycle {\n\tprivate state: VoiceLifecycleState = { kind: \"voice-off\" };\n\tprivate readonly registry: SharedResourceRegistry;\n\tprivate readonly loaders: VoiceLifecycleLoaders;\n\tprivate readonly events: VoiceLifecycleEvents;\n\n\tconstructor(args: {\n\t\tregistry: SharedResourceRegistry;\n\t\tloaders: VoiceLifecycleLoaders;\n\t\tevents?: VoiceLifecycleEvents;\n\t}) {\n\t\tthis.registry = args.registry;\n\t\tthis.loaders = args.loaders;\n\t\tthis.events = args.events ?? {};\n\t}\n\n\tcurrent(): VoiceLifecycleState {\n\t\treturn this.state;\n\t}\n\n\t/**\n\t * Transition `voice-off → voice-arming → voice-on`. Loads TTS + ASR\n\t * mmap regions, voice caches, voice scheduler nodes. Each load throws\n\t * on failure; a thrown loader transitions the state to `voice-error`\n\t * and re-throws so the caller sees the structured cause. No partial\n\t * arm: either all four resources are held or none are.\n\t */\n\tasync arm(): Promise<ArmedResources> {\n\t\tif (this.state.kind !== \"voice-off\") {\n\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\"illegal-transition\",\n\t\t\t\t`[voice-lifecycle] arm() called in state ${this.state.kind} — must be voice-off`,\n\t\t\t);\n\t\t}\n\t\tthis.transition({ kind: \"voice-arming\" });\n\n\t\tlet tts: MmapRegionHandle | null = null;\n\t\tlet asr: MmapRegionHandle | null = null;\n\t\tlet voiceCaches: RefCountedResource | null = null;\n\t\tlet voiceSchedulerNodes: RefCountedResource | null = null;\n\t\ttry {\n\t\t\ttts = this.registry.acquire(await this.loaders.loadTtsRegion());\n\t\t\tasr = this.registry.acquire(await this.loaders.loadAsrRegion());\n\t\t\tvoiceCaches = this.registry.acquire(await this.loaders.loadVoiceCaches());\n\t\t\tvoiceSchedulerNodes = this.registry.acquire(\n\t\t\t\tawait this.loaders.loadVoiceSchedulerNodes(),\n\t\t\t);\n\t\t} catch (err) {\n\t\t\t// Roll back partial acquisitions before surfacing the error so the\n\t\t\t// registry doesn't leak refs on a failed arm. Evict heavy mmap\n\t\t\t// regions before release; release() only drops the refcount and may\n\t\t\t// intentionally keep file descriptors alive for the next re-page.\n\t\t\tawait Promise.allSettled([\n\t\t\t\ttts?.evictPages() ?? Promise.resolve(),\n\t\t\t\tasr?.evictPages() ?? Promise.resolve(),\n\t\t\t]);\n\t\t\tconst rollback: Array<RefCountedResource | null> = [\n\t\t\t\tvoiceSchedulerNodes,\n\t\t\t\tvoiceCaches,\n\t\t\t\tasr,\n\t\t\t\ttts,\n\t\t\t];\n\t\t\tfor (const res of rollback) {\n\t\t\t\tif (res) await this.registry.release(res.id);\n\t\t\t}\n\t\t\tconst lifecycleErr = toLifecycleError(\"arm-failed\", err);\n\t\t\tthis.transition({ kind: \"voice-error\", error: lifecycleErr });\n\t\t\tthrow lifecycleErr;\n\t\t}\n\n\t\tconst resources: ArmedResources = {\n\t\t\ttts,\n\t\t\tasr,\n\t\t\tvoiceCaches,\n\t\t\tvoiceSchedulerNodes,\n\t\t};\n\t\tthis.transition({ kind: \"voice-on\", resources });\n\t\treturn resources;\n\t}\n\n\t/**\n\t * Transition `voice-on → voice-disarming → voice-off`. Calls\n\t * `evictPages()` on the TTS + ASR mmap regions before releasing them\n\t * so the OS reclaims the pages even if another consumer keeps the\n\t * file descriptor open. The voice caches stay in the registry as\n\t * tiny (KB-scale) entries — only the heavy mmap regions get evicted.\n\t */\n\tasync disarm(): Promise<void> {\n\t\tif (this.state.kind !== \"voice-on\") {\n\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\"illegal-transition\",\n\t\t\t\t`[voice-lifecycle] disarm() called in state ${this.state.kind} — must be voice-on`,\n\t\t\t);\n\t\t}\n\t\tconst resources = this.state.resources;\n\t\tthis.transition({ kind: \"voice-disarming\", resources });\n\n\t\tlet evictionFailure: unknown = null;\n\t\t// Eviction first — the mmap region is still mapped, the kernel can\n\t\t// still drop the pages. If eviction fails we still proceed to\n\t\t// release; the failure is captured and re-thrown after release so\n\t\t// the registry stays consistent.\n\t\t//\n\t\t// `evictPages()` on production handles wires through to the\n\t\t// `libelizainference` FFI (`ffi.mmapEvict(ctx, \"tts\" | \"asr\")`,\n\t\t// declared in `tools/omnivoice/include/eliza-inference-ffi.h`).\n\t\t// The fused build implements it by tearing down the OmniVoice /\n\t\t// ASR model context (`ov_free` + `eliza_free_asr`), which lets\n\t\t// the llama.cpp / OmniVoice destructors run their own\n\t\t// platform-appropriate unmap (`munmap` on POSIX, `UnmapViewOfFile`\n\t\t// on Windows). The TS layer is platform-agnostic — all\n\t\t// platform-specific eviction lives in the C ABI. The stub library\n\t\t// returns ELIZA_ERR_NOT_IMPLEMENTED, which the binding raises as\n\t\t// `VoiceLifecycleError({code:\"kernel-missing\"})` — this method\n\t\t// captures it and re-classifies as `disarm-failed` after release\n\t\t// runs (so registry refs don't leak on a bad eviction).\n\t\tconst evictResults = await Promise.allSettled([\n\t\t\tresources.tts.evictPages(),\n\t\t\tresources.asr.evictPages(),\n\t\t]);\n\t\tfor (const r of evictResults) {\n\t\t\tif (r.status === \"rejected\" && evictionFailure === null) {\n\t\t\t\tevictionFailure = r.reason;\n\t\t\t}\n\t\t}\n\n\t\t// Release in reverse acquisition order.\n\t\tawait this.registry.release(resources.voiceSchedulerNodes.id);\n\t\tawait this.registry.release(resources.voiceCaches.id);\n\t\tawait this.registry.release(resources.asr.id);\n\t\tawait this.registry.release(resources.tts.id);\n\n\t\tif (evictionFailure !== null) {\n\t\t\tconst err = toLifecycleError(\"disarm-failed\", evictionFailure);\n\t\t\tthis.transition({ kind: \"voice-error\", error: err });\n\t\t\tthrow err;\n\t\t}\n\t\tthis.transition({ kind: \"voice-off\" });\n\t}\n\n\t/**\n\t * Reset from `voice-error` back to `voice-off`. Required because\n\t * `voice-error` is terminal — the engine must explicitly acknowledge\n\t * the failure before the user can re-attempt voice. There is no\n\t * automatic retry path.\n\t */\n\treset(): void {\n\t\tif (this.state.kind !== \"voice-error\") {\n\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\"illegal-transition\",\n\t\t\t\t`[voice-lifecycle] reset() called in state ${this.state.kind} — must be voice-error`,\n\t\t\t);\n\t\t}\n\t\tthis.transition({ kind: \"voice-off\" });\n\t}\n\n\tprivate transition(next: VoiceLifecycleState): void {\n\t\tconst prev = this.state;\n\t\tthis.state = next;\n\t\tthis.events.onTransition?.(prev, next);\n\t}\n}\n\nfunction toLifecycleError(\n\tfallbackCode: VoiceLifecycleError[\"code\"],\n\terr: unknown,\n): VoiceLifecycleError {\n\tif (err instanceof VoiceLifecycleError) return err;\n\tconst message = err instanceof Error ? err.message : String(err);\n\t// Heuristic mapping of common platform-level signals into the\n\t// structured codes documented above. The lifecycle never fabricates\n\t// a code it didn't receive evidence for — anything that doesn't match\n\t// one of these falls back to the caller-provided code.\n\tif (/ENOMEM|out of memory|RAM/i.test(message)) {\n\t\treturn new VoiceLifecycleError(\"ram-pressure\", message);\n\t}\n\tif (/mmap|MAP_FAILED/i.test(message)) {\n\t\treturn new VoiceLifecycleError(\"mmap-fail\", message);\n\t}\n\tif (/kernel|missing kernel/i.test(message)) {\n\t\treturn new VoiceLifecycleError(\"kernel-missing\", message);\n\t}\n\treturn new VoiceLifecycleError(fallbackCode, message);\n}\n",
9
+ "/**\n * Node/Bun FFI binding to `libelizainference.{dylib,so,dll}`.\n *\n * The fused omnivoice + llama.cpp build (see\n * `packages/app-core/scripts/omnivoice-fuse/`) produces ONE shared\n * library that exports both `llama_*` and `omnivoice_*` symbols plus\n * the C ABI declared in `scripts/omnivoice-fuse/ffi.h`. This module is\n * the JS-side proxy for that ABI — it loads the library, binds every\n * `eliza_inference_*` symbol declared in `ffi.h`, and exposes a typed\n * handle (`ElizaInferenceFfi`) the voice lifecycle calls into.\n *\n * Runtime: production runs under Bun (Electrobun shell, Capacitor\n * bridge), so the loader uses `bun:ffi`. Tests that need to actually\n * load a `.dylib` against a stub library spawn a `bun` subprocess —\n * see `ffi-bindings.test.ts`. Calling this loader from a non-Bun\n * runtime (e.g. plain Node) throws `VoiceLifecycleError({code:\n * \"missing-ffi\"})` with a diagnostic explaining why.\n *\n * No defensive try/catch on the success path. Any dlopen failure,\n * symbol-resolution failure, or ABI mismatch is a structured throw\n * (AGENTS.md §3 + §9). The caller — `voice/lifecycle.ts` and\n * `voice/engine-bridge.ts` — surfaces it as a `VoiceLifecycleError` to\n * the UI.\n */\n\nimport path from \"node:path\";\n\nimport { VoiceLifecycleError } from \"./lifecycle\";\n\n/**\n * Make a directory discoverable by the Win32 DLL loader for this process by\n * prepending it to PATH (step 6 of the standard DLL search order).\n *\n * The fused lib's sibling backends (`ggml*.dll`, `llama*.dll`, `mtmd.dll`) are\n * staged NEXT TO `elizainference.dll`, but when a DLL is opened by absolute\n * path the Win32 loader does NOT search that DLL's own directory for its\n * dependencies — it searches the host EXE's dir, the system dirs, and PATH. So\n * `dlopen` fails with \"error code 126\" (a dependent DLL could not be found)\n * even though the siblings are right there. Linux/macOS don't need this:\n * `stage-desktop-fused-lib.mjs` bakes a relative rpath (`$ORIGIN` /\n * `@loader_path`) at link time so the loader resolves siblings from the lib's\n * own dir. Idempotent; a no-op off win32 and when `dir` is already on PATH.\n */\nfunction ensureWin32DllSearchDir(dir: string): void {\n\tif (process.platform !== \"win32\" || !dir) return;\n\tconst current = process.env.PATH ?? \"\";\n\tconst resolved = path.resolve(dir);\n\tconst already = current\n\t\t.split(path.delimiter)\n\t\t.some((seg) => seg && path.resolve(seg) === resolved);\n\tif (already) return;\n\tprocess.env.PATH = current\n\t\t? `${resolved}${path.delimiter}${current}`\n\t\t: resolved;\n}\n\n/**\n * ABI version the JS binding was authored against. Must match the value\n * `eliza_inference_abi_version()` returns at runtime — a mismatch is a\n * hard error (AGENTS.md §3, §9: no silent compatibility shims).\n *\n * Bump in lockstep with `ELIZA_INFERENCE_ABI_VERSION` in\n * `scripts/omnivoice-fuse/ffi.h` whenever the C surface changes shape.\n *\n * v4: the FFI bridge resolves `speaker_preset_id` against the bundle's\n * `cache/voice-preset-<id>.bin` (ELZ2 v2) and applies the\n * `(instruct, ref_audio_tokens, ref_T, ref_text)` triple to\n * `ov_tts_params` before calling `ov_synthesize`. Adds the\n * `eliza_inference_encode_reference` entrypoint that the freeze CLI\n * uses to pre-encode reference WAVs into the preset file. A v3 caller\n * remains source-compatible: every v3 entry point keeps its v3 shape.\n *\n * v5: the FFI bridge gains the native openWakeWord surface\n * (`eliza_inference_wakeword_supported/open/score/reset/close`). It\n * replaces the previous `onnxruntime-node`-backed wake-word path —\n * the JS binding routes wake-word detection exclusively through this\n * ABI with no ONNX fallback (AGENTS.md §3, §8). v4 callers that\n * never touched the wake-word entries are source-compatible.\n *\n * v6: the FFI bridge gains the native speaker-encoder + diarizer\n * surfaces (`eliza_inference_speaker_supported/open/embed/free/close`\n * and `eliza_inference_diariz_supported/open/segment/close`). These\n * fuse the remaining standalone `libvoice_classifier` voice\n * classifiers into the one `libelizainference` handle so the whole\n * voice pipeline runs through a single native lib. v5 callers that\n * never touched the speaker/diarizer entries are source-compatible.\n *\n * v9: the last text-adjacent modalities move onto the fused handle. Three\n * additive surfaces + probes: text embeddings (`embed` / `embedSupported`),\n * mmproj vision describe (`describeImage` / `visionSupported`), and the\n * tokenizer (`tokenize` / `detokenize` / `tokenizeSupported`). With these,\n * libllama is fully retired: text, embeddings, vision, and tokenization all\n * run through the fused handle. A pre-v9 library lacks these symbols, so the\n * probes report unsupported and the fused runtime refuses (there is no\n * libllama fallback). v8 callers that never touched the new entries remain\n * source-compatible (the new probes simply return false on a v8 lib).\n *\n * v10: Kokoro-82M TTS folded in-process. The fused handle gains\n * `eliza_inference_kokoro_supported/load/synthesize/sample_rate` so the\n * mobile Kokoro path synthesizes through the same dlopen()-ed\n * libelizainference as OmniVoice instead of POSTing to the local-TCP\n * `llama-server /v1/audio/speech` route (forbidden on iOS / Google Play).\n * The four symbols are additive — a v9 library lacks them, so the\n * `kokoroSupported()` probe reports false and the Kokoro FFI runtime\n * refuses (no TCP fallback on mobile). A v9 library is still accepted at\n * degraded capability: its voice/ASR/VAD/LLM/text surface is unchanged and\n * Kokoro just probes unsupported on it.\n */\nexport const ELIZA_INFERENCE_ABI_VERSION = 13 as const;\n\n/** One transcribed word with playback-synced timing (ms from utterance start). */\nexport interface AsrWordTiming {\n\ttext: string;\n\tstartMs: number;\n\tendMs: number;\n}\n\n/**\n * Recover per-word `{ text, startMs, endMs }` from a v12 timed-ASR result.\n *\n * The native `eliza_inference_asr_transcribe_timed` sizes the `startMs`/`endMs`\n * arrays by splitting the transcript on ASCII whitespace — `std::isspace` in the\n * C locale matches EXACTLY ` \\t\\n\\v\\f\\r`. We must mirror that split byte-for-byte\n * to recover the word strings: a broader Unicode `\\s` split collapses NBSP /\n * ideographic space (U+00A0, U+3000, …) that the native byte split keeps, which\n * would make `tokens` shorter than `count` and silently zip each word's text\n * against a DIFFERENT word's timing — a desync `validateAsrWordTimings` cannot\n * see (it never compares text to count). `count` only falls below the true word\n * count when the caller's `maxWords` cap is hit, in which case the trailing\n * (untimed) words are dropped by `Math.min`.\n */\nexport function recoverAsrWords(\n\ttext: string,\n\tcount: number,\n\tstartMs: Int32Array,\n\tendMs: Int32Array,\n): AsrWordTiming[] {\n\tconst tokens = text.split(/[ \\t\\n\\v\\f\\r]+/).filter(Boolean);\n\tconst n = Math.min(count, tokens.length);\n\tconst words: AsrWordTiming[] = [];\n\tfor (let i = 0; i < n; i++) {\n\t\twords.push({\n\t\t\ttext: tokens[i] as string,\n\t\t\tstartMs: startMs[i] ?? 0,\n\t\t\tendMs: endMs[i] ?? 0,\n\t\t});\n\t}\n\treturn words;\n}\n\n/**\n * Pooling strategies for `embed`. Mirror `enum llama_pooling_type` and the\n * `ELIZA_POOLING_*` constants in `eliza-inference-ffi.h`.\n */\nexport const ELIZA_POOLING_MEAN = 1;\nexport const ELIZA_POOLING_CLS = 2;\nexport const ELIZA_POOLING_LAST = 3;\n\n/** Status codes mirrored from `ffi.h`. Negative = failure. */\nexport const ELIZA_OK = 0;\nexport const ELIZA_ERR_NOT_IMPLEMENTED = -1;\nexport const ELIZA_ERR_INVALID_ARG = -2;\nexport const ELIZA_ERR_BUNDLE_INVALID = -3;\nexport const ELIZA_ERR_FFI_FAULT = -4;\nexport const ELIZA_ERR_OOM = -5;\nexport const ELIZA_ERR_ABI_MISMATCH = -6;\nexport const ELIZA_ERR_CANCELLED = -7;\n\n/**\n * WeSpeaker ResNet34-LM embedding dimension. The native\n * `eliza_inference_speaker_embed` writes exactly this many L2-normalized\n * fp32 values into the caller-owned output buffer. Mirrors the C-side\n * `VOICE_SPEAKER_EMBEDDING_DIM` and `SPEAKER_GGML_EMBEDDING_DIM`.\n */\nconst SPEAKER_EMBEDDING_DIM = 256;\n\n/**\n * Upper bound on the per-window diarizer label count. pyannote-3 emits 293\n * int8 frame labels per 5 s window; the caller passes a generous capacity and\n * the library reports the real count back via `*io_n_labels`.\n */\nconst DIARIZ_LABELS_CAPACITY = 2048;\n\n/**\n * Region names the lifecycle hands to `mmap_acquire` / `mmap_evict`.\n * Mirrors the set the C stub validates in `ffi-stub.c::valid_region`.\n */\nexport type ElizaInferenceRegion =\n\t| \"tts\"\n\t| \"asr\"\n\t| \"text\"\n\t| \"mtp\"\n\t| \"vad\"\n\t| \"wakeword\";\n\n/**\n * Opaque pointer to the C-side `EliInferenceContext`. Numeric on Bun\n * (FFI returns the raw pointer as `bigint`); never inspected on the JS\n * side beyond passing it back through the binding.\n */\nexport type ElizaInferenceContextHandle = bigint;\n\n/** Opaque pointer to a native Silero VAD session. */\nexport type NativeVadHandle = bigint;\n\n/** Opaque pointer to a native openWakeWord session. */\nexport type NativeWakeWordHandle = bigint;\n\n/** Opaque pointer to a native WeSpeaker speaker-encoder session. */\nexport type NativeSpeakerHandle = bigint;\n\n/** Opaque pointer to a native pyannote diarizer session. */\nexport type NativeDiarizHandle = bigint;\n\n/** Opaque pointer to a streaming-LLM session. */\nexport type LlmStreamHandle = bigint;\n\n/**\n * Per-session config handed to `llmStreamOpen`. Mirrors\n * `eliza_llm_stream_config_t` in\n * `native/llama.cpp/tools/omnivoice/include/eliza-inference-ffi.h` (ABI v9).\n */\nexport interface LlmStreamConfig {\n\tmaxTokens: number;\n\ttemperature: number;\n\ttopP: number;\n\ttopK: number;\n\trepeatPenalty: number;\n\t/** Pinned slot id; -1 disables pinning. */\n\tslotId: number;\n\t/** Optional prompt cache key used to derive a slot when `slotId === -1`. */\n\tpromptCacheKey: string | null;\n\t/** MTP drafter bounds; `0` for either disables speculative decoding. */\n\tdraftMin: number;\n\tdraftMax: number;\n\t/** Absolute MTP drafter GGUF path; null disables drafter-backed MTP. */\n\tdraftModelPath: string | null;\n\t/**\n\t * GBNF grammar source. When set the native session installs a grammar\n\t * sampler FIRST in the chain so every sampled token is constrained — this\n\t * is how the structured-reply envelope is forced on the in-process FFI\n\t * path. `null`/empty disables grammar constraint.\n\t */\n\tgbnfGrammar?: string | null;\n\t/** Thinking-tag suppression passthrough (v1 no-op). */\n\tdisableThinking?: boolean;\n\t/**\n\t * Per-load GPU offload (ABI v8). Number of model layers to place on GPU.\n\t * `undefined`/-1 selects the runtime default (all layers); 0 forces CPU.\n\t * The model is loaded once per ctx, so the FIRST session's value wins.\n\t */\n\tgpuLayers?: number;\n\t/**\n\t * KV-cache K quant type name (ABI v8), e.g. \"f16\", \"q8_0\", \"qjl1_256\".\n\t * `undefined`/null leaves the f16 default. Mapped to `ggml_type` by the\n\t * fused lib's `eliza_llm_stream_config_t.cache_type_k`.\n\t */\n\tcacheTypeK?: string | null;\n\t/** KV-cache V quant type name (ABI v8); see `cacheTypeK`. */\n\tcacheTypeV?: string | null;\n\t/** Runtime context window in tokens (ABI v9). `undefined`/0 uses native fallback. */\n\tcontextSize?: number;\n}\n\n/**\n * One step of streaming LLM output. `tokens` is the batch of accepted text\n * model token ids the runtime committed this step (>= 1; > 1 only when the\n * MTP drafter is active and the verifier accepted multiple drafts).\n * `text` is the detokenized text for those tokens. `done` is `true` only\n * on the final step (EOS reached). `drafterDrafted` and `drafterAccepted`\n * are populated when the drafter is active.\n */\nexport interface LlmStreamStep {\n\ttokens: number[];\n\ttext: string;\n\tdone: boolean;\n\tdrafterDrafted: number;\n\tdrafterAccepted: number;\n}\n\n/**\n * One streaming-TTS chunk delivered to the `onChunk` callback passed to\n * `ttsSynthesizeStream`. `pcm` is a *view* over the library's buffer —\n * valid only for the duration of the callback; copy it before\n * returning. `isFinal` marks the zero-length tail chunk that closes the\n * utterance. The callback returning `true` requests cancellation at the\n * next kernel boundary.\n */\nexport interface TtsStreamChunk {\n\tpcm: Float32Array;\n\tisFinal: boolean;\n}\n\n/**\n * A native MTP speculative-step event from\n * `eliza_inference_set_verifier_callback`. Token-index domain is the\n * generated-output stream (token 0 = first generated token), matching\n * `RejectedTokenRange`. `rejectedFrom`/`rejectedTo` are -1 when nothing\n * was rejected this step.\n */\nexport interface NativeVerifierEvent {\n\tacceptedTokenIds: number[];\n\trejectedFrom: number;\n\trejectedTo: number;\n\tcorrectedTokenIds: number[];\n}\n\n/**\n * Typed handle returned by `loadElizaInferenceFfi`. Each method maps\n * 1:1 to a symbol declared in `ffi.h`. Methods that allocate a context\n * return the opaque pointer; methods that consume one take it as the\n * first argument. Failures throw `VoiceLifecycleError` with the\n * structured code derived from the C return value.\n */\nexport interface ElizaInferenceFfi {\n\t/** Library path the binding was loaded from (for diagnostics). */\n\treadonly libraryPath: string;\n\t/** ABI version reported by the loaded library. */\n\treadonly libraryAbiVersion: string;\n\t/** Create a fresh context anchored at `bundleDir`. */\n\tcreate(bundleDir: string): ElizaInferenceContextHandle;\n\t/** Destroy a previously-created context. Idempotent on already-freed handles. */\n\tdestroy(ctx: ElizaInferenceContextHandle): void;\n\t/** Map / re-page weights for a region. */\n\tmmapAcquire(\n\t\tctx: ElizaInferenceContextHandle,\n\t\tregion: ElizaInferenceRegion,\n\t): void;\n\t/**\n\t * Release or evict a voice-only region after the lifecycle leaves\n\t * voice-on. Implementations may madvise mapped pages or unload the\n\t * ASR/TTS runtime state entirely; callers must treat the region as\n\t * unavailable until the next `mmapAcquire`.\n\t */\n\tmmapEvict(\n\t\tctx: ElizaInferenceContextHandle,\n\t\tregion: ElizaInferenceRegion,\n\t): void;\n\t/**\n\t * Synchronous TTS forward. Caller provides the output buffer; library\n\t * fills up to its capacity and returns the number of samples written.\n\t */\n\tttsSynthesize(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\ttext: string;\n\t\tspeakerPresetId: string | null;\n\t\tout: Float32Array;\n\t}): number;\n\t/**\n\t * Synchronous ASR forward. Returns the decoded transcript as a UTF-8\n\t * string (allocated by the JS side, sized to fit the library's max\n\t * write).\n\t */\n\tasrTranscribe(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tpcm: Float32Array;\n\t\tsampleRateHz: number;\n\t\tmaxTextBytes?: number;\n\t}): string;\n\n\t/* ---- ASR word timestamps (ABI v12) --------------------------- */\n\n\t/** True when this build can emit per-word ASR timestamps (v12+). v11 and\n\t * older report false — callers fall back to the text-only `asrTranscribe`. */\n\ttimedAsrSupported(): boolean;\n\t/** Transcribe like `asrTranscribe` AND return per-word `[startMs,endMs)`\n\t * spans (duration-proportional, char-weighted, monotonic — the honest\n\t * single-model signal; see the v12 ABI changelog). The word texts come from\n\t * a whitespace split of the transcript, zipped with the native timing. */\n\tasrTranscribeTimed(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tpcm: Float32Array;\n\t\tsampleRateHz: number;\n\t\tmaxTextBytes?: number;\n\t\tmaxWords?: number;\n\t}): { text: string; words: AsrWordTiming[] };\n\n\t/* ---- Streaming TTS + verifier callback (ABI v2) --------------- */\n\n\t/**\n\t * True when this build implements streaming TTS (false for the stub /\n\t * a TTS-disabled build). Callers pick the streaming path vs the batch\n\t * `ttsSynthesize` off this flag — no probe-and-catch.\n\t */\n\tttsStreamSupported(): boolean;\n\t/**\n\t * Chunked synthesis. `onChunk` is invoked for each decoded PCM segment\n\t * as it arrives, then once more with `isFinal: true` (zero-length\n\t * tail). Returning `true` from `onChunk` requests cancellation; the\n\t * call then resolves with `cancelled: true` after the final-chunk\n\t * callback. Any negative library return is a thrown `VoiceLifecycleError`.\n\t */\n\tttsSynthesizeStream(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\ttext: string;\n\t\tspeakerPresetId: string | null;\n\t\tonChunk: (chunk: TtsStreamChunk) => boolean | undefined;\n\t}): { cancelled: boolean };\n\t/**\n\t * Hard-cancel any in-flight TTS forward pass on `ctx` (started on\n\t * another thread by `ttsSynthesize` / `ttsSynthesizeStream`). The\n\t * in-flight call returns `ELIZA_ERR_CANCELLED` at the next kernel\n\t * boundary. Cancelling nothing is not an error.\n\t */\n\tcancelTts(ctx: ElizaInferenceContextHandle): void;\n\t/**\n\t * Register (or, with `cb: null`, clear) the native MTP verifier\n\t * callback. The runtime fires `cb` for every speculative accept/reject\n\t * step from the in-process drafter↔target loop. The returned\n\t * `JSCallbackHandle` MUST be kept alive for as long as the callback is\n\t * registered and `.close()`d when it's cleared (or on dispose) — Bun's\n\t * `JSCallback` is GC'd otherwise and the native side dereferences a\n\t * dead pointer.\n\t */\n\tsetVerifierCallback(\n\t\tctx: ElizaInferenceContextHandle,\n\t\tcb: ((event: NativeVerifierEvent) => void) | null,\n\t): { close(): void };\n\n\t/* ---- OmniVoice reference encode (ABI v4) ---------------------- */\n\n\t/**\n\t * True when this build exports the OmniVoice reference-encode symbols\n\t * (`eliza_inference_encode_reference`). The freeze CLI uses this to\n\t * pre-encode same reference audio into the persisted voice preset;\n\t * the runtime synthesis path never calls it (it reads pre-encoded\n\t * tokens from the preset file).\n\t */\n\tencodeReferenceSupported?(): boolean;\n\t/**\n\t * Run the encode-only half of the TTS pipeline (HuBERT semantic + RVQ\n\t * codec) on a 24 kHz mono fp32 PCM buffer and return the resulting\n\t * reference-audio-token tensor `[K=8, ref_T]` as `Int32Array`\n\t * row-major (`tokens[k*ref_T + t]`). The library allocates and the\n\t * binding takes care of freeing the native buffer via\n\t * `eliza_inference_free_tokens` before this returns.\n\t *\n\t * The TTS region must have been acquired (`mmapAcquire(\"tts\")`)\n\t * before the call. `sampleRateHz` must be 24000; the entrypoint does\n\t * NOT resample, by design — the freeze artifact must be deterministic.\n\t */\n\tencodeReference?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tpcm: Float32Array;\n\t\tsampleRateHz: number;\n\t}): { K: number; refT: number; tokens: Int32Array };\n\n\t/* ---- Native VAD (ABI v3) -------------------------------------- */\n\n\t/** True when this build exports and enables the native Silero VAD backend. */\n\tvadSupported?(): boolean;\n\t/** Open a native VAD session. The ABI-compatible sample rate is 16 kHz. */\n\tvadOpen?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tsampleRateHz: number;\n\t}): NativeVadHandle;\n\t/** Process one 512-sample fp32 mono window and return P(speech). */\n\tvadProcess?(args: { vad: NativeVadHandle; pcm: Float32Array }): number;\n\t/** Clear native VAD recurrent state at utterance boundaries. */\n\tvadReset?(vad: NativeVadHandle): void;\n\t/** Close + free a native VAD session. Idempotent on already-closed handles. */\n\tvadClose?(vad: NativeVadHandle): void;\n\n\t/* ---- Native wake-word (ABI v5) -------------------------------- */\n\n\t/**\n\t * True when this build exports and enables the native openWakeWord\n\t * backend. The JS binding routes wake-word detection exclusively\n\t * through this surface; when this returns false, the wake-word path\n\t * throws a structured \"runtime not ready\" error — no ONNX fallback\n\t * (AGENTS.md §3, §8).\n\t */\n\twakewordSupported?(): boolean;\n\t/**\n\t * Open a native wake-word session. `sampleRateHz` must be 16000;\n\t * `headName` selects the classifier head inside the bundle's combined\n\t * wake-word GGUF (e.g. \"hey-eliza\").\n\t */\n\twakewordOpen?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tsampleRateHz: number;\n\t\theadName: string;\n\t}): NativeWakeWordHandle;\n\t/**\n\t * Score one 1280-sample (80 ms @ 16 kHz) fp32 mono frame and return\n\t * the latest P(wake) in [0, 1]. Early calls before enough context\n\t * accumulates return 0.\n\t */\n\twakewordScore?(args: {\n\t\twake: NativeWakeWordHandle;\n\t\tpcm: Float32Array;\n\t}): number;\n\t/** Clear all streaming state (audio tail, mel ring, embedding ring). */\n\twakewordReset?(wake: NativeWakeWordHandle): void;\n\t/** Close + free a native wake-word session. Idempotent on already-closed handles. */\n\twakewordClose?(wake: NativeWakeWordHandle): void;\n\n\t/* ---- Native speaker encoder (ABI v6) -------------------------- */\n\n\t/** True when this build exports and enables the native WeSpeaker encoder. */\n\tspeakerSupported?(): boolean;\n\t/**\n\t * Open a native speaker-encoder session. `ggufPath` may be null to\n\t * resolve the bundle's `speaker/` dir, or an absolute path to a\n\t * WeSpeaker GGUF.\n\t */\n\tspeakerOpen?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tggufPath: string | null;\n\t}): NativeSpeakerHandle;\n\t/**\n\t * Embed `pcm` (16 kHz mono fp32) into a 256-d L2-normalized speaker\n\t * embedding. Returns a freshly-allocated `Float32Array` of length 256.\n\t */\n\tspeakerEmbed?(args: {\n\t\tspeaker: NativeSpeakerHandle;\n\t\tpcm: Float32Array;\n\t}): Float32Array;\n\t/** Close + free a native speaker-encoder session. Idempotent on already-closed handles. */\n\tspeakerClose?(speaker: NativeSpeakerHandle): void;\n\n\t/* ---- Native diarizer (ABI v6) --------------------------------- */\n\n\t/** True when this build exports and enables the native pyannote diarizer. */\n\tdiarizSupported?(): boolean;\n\t/**\n\t * Open a native diarizer session. `ggufPath` may be null to resolve the\n\t * bundle's `diariz/` dir, or an absolute path to a pyannote GGUF.\n\t */\n\tdiarizOpen?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tggufPath: string | null;\n\t}): NativeDiarizHandle;\n\t/**\n\t * Segment one 80000-sample (5 s @ 16 kHz) mono fp32 window into a\n\t * per-frame powerset-label sequence. Returns the `Int8Array` of frame\n\t * labels (293 for pyannote-segmentation-3.0), each in `[0, 7)`.\n\t */\n\tdiarizSegment?(args: {\n\t\tdiariz: NativeDiarizHandle;\n\t\tpcm: Float32Array;\n\t}): Int8Array;\n\t/** Close + free a native diarizer session. Idempotent on already-closed handles. */\n\tdiarizClose?(diariz: NativeDiarizHandle): void;\n\n\t/* ---- Streaming ASR (ABI v2) ----------------------------------- */\n\n\t/**\n\t * True when this build has a working streaming ASR decoder (false for\n\t * the stub / an ASR-disabled build). Callers pick the fused streaming\n\t * path vs the fused batch interim adapter off this flag — they do not\n\t * have to open a session and catch `ELIZA_ERR_NOT_IMPLEMENTED`.\n\t */\n\tasrStreamSupported(): boolean;\n\t/** Open a streaming ASR session. The handle is closed via `asrStreamClose`. */\n\tasrStreamOpen(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tsampleRateHz: number;\n\t}): bigint;\n\t/** Feed one PCM frame at the session's sample rate. */\n\tasrStreamFeed(args: { stream: bigint; pcm: Float32Array }): void;\n\t/** Read the current running partial transcript (and token ids when available). */\n\tasrStreamPartial(args: {\n\t\tstream: bigint;\n\t\tmaxTextBytes?: number;\n\t\tmaxTokens?: number;\n\t}): { partial: string; tokens?: number[] };\n\t/** Force-finalize: drain buffered audio, run a final decode, return the final transcript. */\n\tasrStreamFinish(args: {\n\t\tstream: bigint;\n\t\tmaxTextBytes?: number;\n\t\tmaxTokens?: number;\n\t}): { partial: string; tokens?: number[] };\n\t/** Close + free a streaming ASR session. Idempotent on already-closed handles. */\n\tasrStreamClose(stream: bigint): void;\n\n\t/* ---- Streaming LLM (additive on top of ABI v3) ---------------- */\n\n\t/**\n\t * True when this build exports the streaming LLM symbols\n\t * (`eliza_inference_llm_stream_*`). Transitional builds may load\n\t * without them; the runner uses this to pick between the FFI streaming\n\t * path.\n\t */\n\tllmStreamSupported?(): boolean;\n\t/**\n\t * True when this build wires same-file / separate-drafter MTP\n\t * speculative decoding into the streaming-LLM text path (ABI v8). A v7\n\t * library returns `false` here (the symbol is absent), so the fused TEXT\n\t * path can refuse to route through it without a speculative-decode\n\t * regression. Anti-regression guard — see ABI v8 changelog.\n\t */\n\tllmMtpSupported?(): boolean;\n\t/**\n\t * True when this build maps + applies KV-cache quant types in the\n\t * streaming-LLM text path (ABI v8). A v7 library returns `false` (symbol\n\t * absent); the fused TEXT path refuses it to avoid a silent fallback to\n\t * f16 KV when a quantized cache was requested.\n\t */\n\tllmKvQuantSupported?(): boolean;\n\t/**\n\t * Open a streaming-LLM session against `ctx`. Failure throws\n\t * `VoiceLifecycleError`. Close exactly once via `llmStreamClose`.\n\t */\n\tllmStreamOpen?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tconfig: LlmStreamConfig;\n\t}): LlmStreamHandle;\n\t/** Feed a batch of pre-tokenized prompt tokens before the first `next`. */\n\tllmStreamPrefill?(args: {\n\t\tstream: LlmStreamHandle;\n\t\ttokens: Int32Array;\n\t}): void;\n\t/**\n\t * Pull the next streaming step. Returns `null` when the runtime declined\n\t * to emit tokens this call (rare — drafter rejected everything and the\n\t * verifier had nothing to commit); poll again. `step.done === true` is\n\t * the final step.\n\t */\n\tllmStreamNext?(args: {\n\t\tstream: LlmStreamHandle;\n\t\tmaxTokensPerStep?: number;\n\t\tmaxTextBytes?: number;\n\t}): LlmStreamStep;\n\t/** Cancel in-flight generation; the next `_next` returns CANCELLED. */\n\tllmStreamCancel?(stream: LlmStreamHandle): void;\n\t/** Persist the session's slot KV state to disk. */\n\tllmStreamSaveSlot?(args: { stream: LlmStreamHandle; filename: string }): void;\n\t/** Restore a previously-saved slot KV file. Call before the first prefill/next. */\n\tllmStreamRestoreSlot?(args: {\n\t\tstream: LlmStreamHandle;\n\t\tfilename: string;\n\t}): void;\n\t/** Close + free a streaming-LLM session. Idempotent on already-closed handles. */\n\tllmStreamClose?(stream: LlmStreamHandle): void;\n\n\t/* ---- Text embeddings (ABI v9) -------------------------------- */\n\n\t/**\n\t * True when this build wires the fused text-embedding path\n\t * (`eliza_inference_embed`). A v8 library returns false (symbol absent),\n\t * so the default TEXT_EMBEDDING handler keeps the node-llama-cpp /\n\t * libllama path.\n\t */\n\tembedSupported?(): boolean;\n\t/**\n\t * Compute a pooled, L2-normalized sentence embedding for `text` over the\n\t * bundle's text model. `pooling` selects the strategy (default MEAN — the\n\t * gte-small convention). Returns a `Float32Array` of length `n_embd`.\n\t */\n\tembed?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\ttext: string;\n\t\tpooling?: number;\n\t}): Float32Array;\n\n\t/* ---- mmproj vision describe (ABI v9) ------------------------- */\n\n\t/**\n\t * True when this build was compiled with vision (`-DELIZA_ENABLE_VISION`)\n\t * and exports `eliza_inference_describe_image`. A v8 / vision-off library\n\t * returns false, so the IMAGE_DESCRIPTION handler keeps the libllama mtmd\n\t * path.\n\t */\n\tvisionSupported?(): boolean;\n\t/**\n\t * Describe `imageBytes` (raw PNG/JPEG/WebP) through the text model's\n\t * mmproj projector at `mmprojPath`. `prompt` defaults to a generic\n\t * caption request. Returns the description text.\n\t */\n\tdescribeImage?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\timageBytes: Uint8Array;\n\t\tmmprojPath: string;\n\t\tprompt?: string;\n\t\tmaxTextBytes?: number;\n\t}): string;\n\n\t/* ---- Streaming mmproj vision describe (ABI v13) -------------- */\n\n\t/**\n\t * True when this build wires token-by-token vision describe\n\t * (`eliza_inference_describe_image_stream_open`). A <=v12 / vision-off\n\t * library returns false, so the IMAGE_DESCRIPTION handler falls back to the\n\t * buffered {@link describeImage}.\n\t */\n\tvisionStreamSupported?(): boolean;\n\t/**\n\t * Open a streaming vision-describe session: prime an `LlmStreamHandle`'s KV\n\t * with `imageBytes` (raw PNG/JPEG/WebP) + `prompt` through the mmproj at\n\t * `mmprojPath`, then PULL tokens with the existing {@link llmStreamNext} loop\n\t * and release via {@link llmStreamClose} — the same machinery as chat text.\n\t * Throws `VoiceLifecycleError` when the build lacks vision streaming.\n\t */\n\tdescribeImageStreamOpen?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\timageBytes: Uint8Array;\n\t\tmmprojPath: string;\n\t\tprompt?: string;\n\t}): LlmStreamHandle;\n\n\t/* ---- Tokenizer (ABI v9) -------------------------------------- */\n\n\t/**\n\t * True when this build exposes the tokenizer over the loaded text vocab\n\t * (`eliza_inference_tokenize`). A pre-v9 library returns false, so the\n\t * desktop fused runtime refuses (libllama is retired — no tokenizer sidecar).\n\t */\n\ttokenizeSupported?(): boolean;\n\t/**\n\t * Tokenize `text` against the loaded text model's vocab. `addSpecial`\n\t * (default true) adds BOS/EOS; `parseSpecial` (default false) renders\n\t * special tokens from the input. Returns the token ids as an `Int32Array`.\n\t */\n\ttokenize?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\ttext: string;\n\t\taddSpecial?: boolean;\n\t\tparseSpecial?: boolean;\n\t}): Int32Array;\n\t/**\n\t * Detokenize `tokens` back to text against the loaded text model's vocab.\n\t * `removeSpecial` (default false) strips BOS/EOS; `unparseSpecial`\n\t * (default false) renders special tokens.\n\t */\n\tdetokenize?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\ttokens: Int32Array;\n\t\tremoveSpecial?: boolean;\n\t\tunparseSpecial?: boolean;\n\t\tmaxTextBytes?: number;\n\t}): string;\n\n\t/* ---- End-of-turn scoring (ABI v11) -------------------------- */\n\n\t/**\n\t * True when this build wires the fused end-of-turn scorer\n\t * (`eliza_inference_llm_eot_score`). A v10 library returns false (symbol\n\t * absent), so the composite EOT classifier uses the heuristic-only signal.\n\t */\n\teotSupported?(): boolean;\n\t/**\n\t * Single causal forward pass over `tokens` (a tokenized partial transcript)\n\t * returning the next-token softmax probability of `targetTokenId` (the\n\t * end-of-turn marker, e.g. `<end_of_turn>`), plus the argmax next token and its\n\t * probability. Runs on a dedicated scoring context over the loaded text\n\t * model; KV is cleared per call so scores are independent.\n\t */\n\teotScore?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\ttokens: Int32Array;\n\t\ttargetTokenId: number;\n\t}): { targetProb: number; topToken: number; topProb: number };\n\n\t/* ---- Kokoro TTS (ABI v10) ----------------------------------- */\n\n\t/**\n\t * True when this build linked Eliza-1's in-process Kokoro engine\n\t * (`eliza_inference_kokoro_*`). A v9 library returns false (symbols\n\t * absent), so the Kokoro FFI runtime refuses rather than falling back to\n\t * the local-TCP `llama-server` route (forbidden on iOS / Google Play).\n\t */\n\tkokoroSupported?(): boolean;\n\t/**\n\t * Load the Kokoro GGUF at `ggufPath` and the voice preset `.bin` at\n\t * `voiceBinPath` (raw fp32 ref_s, `styleDim` inner dim — 256 for v1.0)\n\t * into `ctx`. Replaces any previously-loaded Kokoro model on the ctx.\n\t * Throws `VoiceLifecycleError` on a negative return with the C diagnostic.\n\t */\n\tkokoroLoad?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\tggufPath: string;\n\t\tvoiceBinPath: string;\n\t\tstyleDim?: number;\n\t}): void;\n\t/**\n\t * Synthesize `text` through the loaded Kokoro model+voice at the model's\n\t * native rate (24 kHz for v1.0). `speed` scales predicted durations\n\t * (default 1.0). Allocates an output buffer of `maxSamples` fp32 samples,\n\t * reads back the count the library wrote, and returns that slice.\n\t */\n\tkokoroSynthesize?(args: {\n\t\tctx: ElizaInferenceContextHandle;\n\t\ttext: string;\n\t\tspeed?: number;\n\t\tmaxSamples: number;\n\t}): Float32Array;\n\t/** The loaded Kokoro model's audio sample rate (24000 for v1.0). */\n\tkokoroSampleRate?(ctx: ElizaInferenceContextHandle): number;\n\n\t/** Best-effort dispose for the binding itself (closes the dlopen handle). */\n\tclose(): void;\n}\n\n/* ---------------------------------------------------------------- */\n/* Loader */\n/* ---------------------------------------------------------------- */\n\n/** Runtime detector: returns true when running under Bun. */\nfunction isBunRuntime(): boolean {\n\treturn typeof (globalThis as { Bun?: unknown }).Bun !== \"undefined\";\n}\n\n/**\n * Load `libelizainference` at `dylibPath` and bind every symbol\n * declared in `ffi.h`. The returned handle's methods delegate directly\n * to the library; they throw `VoiceLifecycleError` on any negative\n * return value or runtime fault.\n *\n * Throws synchronously (no Promise) when:\n * - the JS runtime is not Bun (no FFI primitive available),\n * - `dlopen` cannot find or open the library,\n * - the library's reported ABI version does not match\n * `ELIZA_INFERENCE_ABI_VERSION`.\n */\nexport function loadElizaInferenceFfi(dylibPath: string): ElizaInferenceFfi {\n\tif (!isBunRuntime()) {\n\t\tthrow new VoiceLifecycleError(\n\t\t\t\"kernel-missing\",\n\t\t\t`[ffi-bindings] Cannot load libelizainference: current runtime is not Bun. ` +\n\t\t\t\t`The fused omnivoice FFI uses bun:ffi (production runs under Bun via Electrobun + Capacitor). ` +\n\t\t\t\t`process.versions=${JSON.stringify(process.versions)}`,\n\t\t);\n\t}\n\tif (!dylibPath || dylibPath.length === 0) {\n\t\tthrow new VoiceLifecycleError(\n\t\t\t\"kernel-missing\",\n\t\t\t\"[ffi-bindings] loadElizaInferenceFfi: dylibPath is required\",\n\t\t);\n\t}\n\treturn bindWithBunFfi(dylibPath);\n}\n\n/* ---------------------------------------------------------------- */\n/* Bun:ffi binding */\n/* ---------------------------------------------------------------- */\n\ninterface BunFfiSymbols {\n\teliza_inference_abi_version: () => unknown;\n\teliza_inference_create: (bundleDir: unknown, outErr: unknown) => unknown;\n\teliza_inference_destroy: (ctx: bigint) => void;\n\teliza_inference_mmap_acquire: (\n\t\tctx: bigint,\n\t\tregion: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_mmap_evict: (\n\t\tctx: bigint,\n\t\tregion: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_tts_synthesize: (\n\t\tctx: bigint,\n\t\ttext: unknown,\n\t\ttextLen: bigint | number,\n\t\tspeaker: unknown,\n\t\toutPcm: unknown,\n\t\tmaxSamples: bigint | number,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_asr_transcribe: (\n\t\tctx: bigint,\n\t\tpcm: unknown,\n\t\tnSamples: bigint | number,\n\t\tsampleRateHz: number,\n\t\toutText: unknown,\n\t\tmaxTextBytes: bigint | number,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_asr_timestamps_supported?: () => number;\n\teliza_inference_asr_transcribe_timed?: (\n\t\tctx: bigint,\n\t\tpcm: unknown,\n\t\tnSamples: bigint | number,\n\t\tsampleRateHz: number,\n\t\toutText: unknown,\n\t\tmaxTextBytes: bigint | number,\n\t\toutWordStartMs: unknown,\n\t\toutWordEndMs: unknown,\n\t\tioNWords: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_tts_stream_supported: () => number;\n\teliza_inference_tts_synthesize_stream: (\n\t\tctx: bigint,\n\t\ttext: unknown,\n\t\ttextLen: bigint | number,\n\t\tspeaker: unknown,\n\t\tonChunk: unknown,\n\t\tuserData: bigint | number,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_cancel_tts: (ctx: bigint, outErr: unknown) => number;\n\teliza_inference_set_verifier_callback: (\n\t\tctx: bigint,\n\t\tcb: unknown,\n\t\tuserData: bigint | number,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_encode_reference?: (\n\t\tctx: bigint,\n\t\tpcm: unknown,\n\t\tnSamples: bigint | number,\n\t\tsampleRateHz: number,\n\t\toutK: unknown,\n\t\toutRefT: unknown,\n\t\toutTokens: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_free_tokens?: (tokens: bigint | number) => void;\n\teliza_inference_vad_supported?: () => number;\n\teliza_inference_vad_open?: (\n\t\tctx: bigint,\n\t\tsampleRateHz: number,\n\t\toutErr: unknown,\n\t) => unknown;\n\teliza_inference_vad_process?: (\n\t\tvad: bigint,\n\t\tpcm: unknown,\n\t\tnSamples: bigint | number,\n\t\toutProbability: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_vad_reset?: (vad: bigint, outErr: unknown) => number;\n\teliza_inference_vad_close?: (vad: bigint) => void;\n\teliza_inference_wakeword_supported?: () => number;\n\teliza_inference_wakeword_open?: (\n\t\tctx: bigint,\n\t\tsampleRateHz: number,\n\t\theadName: unknown,\n\t\toutErr: unknown,\n\t) => unknown;\n\teliza_inference_wakeword_score?: (\n\t\twake: bigint,\n\t\tpcm: unknown,\n\t\tnSamples: bigint | number,\n\t\toutProbability: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_wakeword_reset?: (wake: bigint, outErr: unknown) => number;\n\teliza_inference_wakeword_close?: (wake: bigint) => void;\n\teliza_inference_speaker_supported?: () => number;\n\teliza_inference_speaker_open?: (\n\t\tctx: bigint,\n\t\tggufPath: unknown,\n\t\toutErr: unknown,\n\t) => unknown;\n\teliza_inference_speaker_embed?: (\n\t\tspeaker: bigint,\n\t\tpcm: unknown,\n\t\tnSamples: bigint | number,\n\t\toutEmbedding: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_speaker_close?: (speaker: bigint) => void;\n\teliza_inference_diariz_supported?: () => number;\n\teliza_inference_diariz_open?: (\n\t\tctx: bigint,\n\t\tggufPath: unknown,\n\t\toutErr: unknown,\n\t) => unknown;\n\teliza_inference_diariz_segment?: (\n\t\tdiariz: bigint,\n\t\tpcm: unknown,\n\t\tnSamples: bigint | number,\n\t\toutLabels: unknown,\n\t\tioNLabels: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_diariz_close?: (diariz: bigint) => void;\n\teliza_inference_asr_stream_supported: () => number;\n\teliza_inference_asr_stream_open: (\n\t\tctx: bigint,\n\t\tsampleRateHz: number,\n\t\toutErr: unknown,\n\t) => unknown;\n\teliza_inference_asr_stream_feed: (\n\t\tstream: bigint,\n\t\tpcm: unknown,\n\t\tnSamples: bigint | number,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_asr_stream_partial: (\n\t\tstream: bigint,\n\t\toutText: unknown,\n\t\tmaxTextBytes: bigint | number,\n\t\toutTokens: unknown,\n\t\tioNTokens: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_asr_stream_finish: (\n\t\tstream: bigint,\n\t\toutText: unknown,\n\t\tmaxTextBytes: bigint | number,\n\t\toutTokens: unknown,\n\t\tioNTokens: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_asr_stream_close: (stream: bigint) => void;\n\teliza_inference_free_string: (str: bigint | number) => void;\n\t// Streaming LLM (additive). Optional — transitional builds may omit.\n\t// ABI v8 capability probes — absent on v7 (treated as unsupported).\n\teliza_inference_llm_mtp_supported?: () => number;\n\teliza_inference_llm_kv_quant_supported?: () => number;\n\teliza_inference_llm_stream_open?: (\n\t\tctx: bigint,\n\t\tcfg: unknown,\n\t\toutErr: unknown,\n\t) => unknown;\n\teliza_inference_llm_stream_prefill?: (\n\t\tstream: bigint,\n\t\ttokens: unknown,\n\t\tnTokens: bigint | number,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_llm_stream_next?: (\n\t\tstream: bigint,\n\t\ttokensOut: unknown,\n\t\ttokensCapacity: bigint | number,\n\t\tnumTokensOut: unknown,\n\t\ttextOut: unknown,\n\t\ttextCapacity: bigint | number,\n\t\tdrafterDraftedOut: unknown,\n\t\tdrafterAcceptedOut: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_llm_stream_cancel?: (stream: bigint) => number;\n\teliza_inference_llm_stream_save_slot?: (\n\t\tstream: bigint,\n\t\tfilename: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_llm_stream_restore_slot?: (\n\t\tstream: bigint,\n\t\tfilename: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_llm_stream_close?: (stream: bigint) => void;\n\t// Text embeddings (ABI v9). Optional — absent on v8 builds.\n\teliza_inference_embed_supported?: () => number;\n\teliza_inference_embed?: (\n\t\tctx: bigint,\n\t\ttext: unknown,\n\t\ttextLen: bigint | number,\n\t\tpooling: number,\n\t\toutEmbedding: unknown,\n\t\toutCapacity: bigint | number,\n\t\toutDim: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\t// mmproj vision describe (ABI v9). Optional — absent on v8 / vision-off builds.\n\teliza_inference_vision_supported?: () => number;\n\teliza_inference_describe_image?: (\n\t\tctx: bigint,\n\t\timageBytes: unknown,\n\t\tnBytes: bigint | number,\n\t\tmmprojPath: unknown,\n\t\tprompt: unknown,\n\t\toutText: unknown,\n\t\tmaxTextBytes: bigint | number,\n\t\toutErr: unknown,\n\t) => number;\n\t// Streaming mmproj vision describe (ABI v13). Optional — absent on <=v12\n\t// builds (the probe then reports unsupported and IMAGE_DESCRIPTION falls back\n\t// to the buffered `eliza_inference_describe_image`). `_stream_open` returns an\n\t// EliLlmStream* (as a pointer/bigint) primed with the image+prompt KV; the\n\t// caller drives the existing `eliza_inference_llm_stream_next` loop and frees\n\t// via `eliza_inference_llm_stream_close`.\n\teliza_inference_vision_stream_supported?: () => number;\n\teliza_inference_describe_image_stream_open?: (\n\t\tctx: bigint,\n\t\timageBytes: unknown,\n\t\tnBytes: bigint | number,\n\t\tmmprojPath: unknown,\n\t\tprompt: unknown,\n\t\toutErr: unknown,\n\t) => bigint;\n\t// Tokenizer (ABI v9). Optional — absent on v8 builds.\n\teliza_inference_tokenize_supported?: () => number;\n\teliza_inference_tokenize?: (\n\t\tctx: bigint,\n\t\ttext: unknown,\n\t\ttextLen: bigint | number,\n\t\taddSpecial: number,\n\t\tparseSpecial: number,\n\t\toutTokens: unknown,\n\t\toutN: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_detokenize?: (\n\t\tctx: bigint,\n\t\ttokens: unknown,\n\t\tnTokens: bigint | number,\n\t\tremoveSpecial: number,\n\t\tunparseSpecial: number,\n\t\toutText: unknown,\n\t\tmaxTextBytes: bigint | number,\n\t\toutErr: unknown,\n\t) => number;\n\t// End-of-turn scoring (ABI v11). Optional — absent on v10 builds (the probe\n\t// then reports unsupported and the composite EOT classifier uses the\n\t// heuristic-only signal).\n\teliza_inference_llm_eot_supported?: () => number;\n\teliza_inference_llm_eot_score?: (\n\t\tctx: bigint,\n\t\ttokenIds: unknown,\n\t\tnumTokens: bigint | number,\n\t\ttargetTokenId: number,\n\t\toutTargetProb: unknown,\n\t\toutTopToken: unknown,\n\t\toutTopProb: unknown,\n\t\toutErr: unknown,\n\t) => number;\n\t// Kokoro TTS (ABI v10). Optional — absent on v9 builds (the probe then\n\t// reports unsupported and the Kokoro FFI runtime refuses).\n\teliza_inference_kokoro_supported?: () => number;\n\teliza_inference_kokoro_load?: (\n\t\tctx: bigint,\n\t\tggufPath: unknown,\n\t\tvoiceBinPath: unknown,\n\t\tstyleDim: number,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_kokoro_synthesize?: (\n\t\tctx: bigint,\n\t\ttext: unknown,\n\t\ttextLen: bigint | number,\n\t\tspeed: number,\n\t\toutPcm: unknown,\n\t\tmaxSamples: bigint | number,\n\t\toutErr: unknown,\n\t) => number;\n\teliza_inference_kokoro_sample_rate?: (ctx: bigint) => number;\n}\n\ninterface BunFfiLib {\n\tsymbols: BunFfiSymbols;\n\tclose(): void;\n}\n\ninterface BunFfiJSCallback {\n\treadonly ptr: bigint | number;\n\tclose(): void;\n}\n\ninterface BunFfiModule {\n\tdlopen(path: string, defs: Record<string, unknown>): BunFfiLib;\n\tFFIType: Record<string, number>;\n\tptr(value: ArrayBufferView): unknown;\n\tCString: new (ptr: unknown) => { toString(): string };\n\tread: {\n\t\tptr(buf: unknown, offset?: number): bigint;\n\t\ti32(buf: unknown, offset?: number): number;\n\t\tu64(buf: unknown, offset?: number): bigint;\n\t};\n\ttoArrayBuffer(\n\t\tptr: bigint | number,\n\t\tbyteOffset?: number,\n\t\tbyteLength?: number,\n\t): ArrayBuffer;\n\tJSCallback: new <F extends (...args: never[]) => unknown>(\n\t\tfn: F,\n\t\tdef: { args: number[]; returns: number },\n\t) => BunFfiJSCallback;\n}\n\n/**\n * Resolve `bun:ffi` synchronously via the Bun-injected `require`.\n * Bun exposes a CJS `require` even from ESM modules, and `bun:ffi` is\n * a built-in importable that way. Doing this dynamically (rather than a\n * static `import \"bun:ffi\"`) keeps the module loadable under plain Node\n * for the parts of the test suite that don't need the FFI.\n */\nfunction loadBunFfiModule(): BunFfiModule {\n\tconst req: ((id: string) => unknown) | undefined = (\n\t\tglobalThis as { Bun?: { __require?: (id: string) => unknown } }\n\t).Bun?.__require;\n\tif (typeof req === \"function\") {\n\t\treturn req(\"bun:ffi\") as BunFfiModule;\n\t}\n\t// Fallback to `module.createRequire` on the current file when running\n\t// under Bun via an ESM entry without `Bun.__require`. This is rare —\n\t// current Bun exposes `Bun.__require` — but we keep the path explicit\n\t// so the failure mode is `MODULE_NOT_FOUND` (a real error), not a\n\t// silent fall-through.\n\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\tconst mod = require(\"node:module\") as {\n\t\tcreateRequire: (filename: string) => (id: string) => unknown;\n\t};\n\tconst r = mod.createRequire(import.meta.url);\n\treturn r(\"bun:ffi\") as BunFfiModule;\n}\n\nfunction bindWithBunFfi(dylibPath: string): ElizaInferenceFfi {\n\tlet ffi: BunFfiModule;\n\ttry {\n\t\tffi = loadBunFfiModule();\n\t} catch (err) {\n\t\tthrow new VoiceLifecycleError(\n\t\t\t\"kernel-missing\",\n\t\t\t`[ffi-bindings] Cannot load bun:ffi while opening ${dylibPath}: ${formatFfiError(err)}`,\n\t\t);\n\t}\n\tconst T = ffi.FFIType;\n\n\t// Windows-only: make the fused lib's co-located backends (ggml*/llama*/mtmd\n\t// .dll) resolvable before dlopen, which otherwise fails with error 126. See\n\t// ensureWin32DllSearchDir for the full rationale.\n\tensureWin32DllSearchDir(path.dirname(dylibPath));\n\n\t// All `char *` arguments are typed as T.ptr — Bun's `T.cstring` is a\n\t// RETURN-only type for \"library hands back a NUL-terminated string\".\n\t// For inputs we encode UTF-8 to a NUL-terminated Buffer on the JS\n\t// side and pass `ffi.ptr(buffer)`.\n\tlet lib: BunFfiLib | null = null;\n\tlet nativeVadSymbolsAvailable = true;\n\tconst nativeVadDefs = {\n\t\t// Native Silero VAD (ABI v3). These are additive; some transitional\n\t\t// builds may report ABI v3 before carrying the VAD symbols, so bind\n\t\t// them opportunistically and advertise unsupported if absent.\n\t\teliza_inference_vad_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_vad_open: {\n\t\t\targs: [T.ptr, T.i32, T.ptr],\n\t\t\treturns: T.ptr,\n\t\t},\n\t\teliza_inference_vad_process: {\n\t\t\targs: [T.usize, T.ptr, T.usize, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_vad_reset: { args: [T.usize, T.ptr], returns: T.i32 },\n\t\teliza_inference_vad_close: { args: [T.usize], returns: T.void },\n\t};\n\t// Native openWakeWord (ABI v5). Additive; transitional builds may report\n\t// v5 before the wake-word symbols ship, so bind opportunistically and\n\t// advertise unsupported when absent. The wake-word path throws a\n\t// structured \"runtime not ready\" error in that case (no ONNX fallback).\n\tlet wakewordSymbolsAvailable = true;\n\tconst wakewordDefs = {\n\t\teliza_inference_wakeword_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_wakeword_open: {\n\t\t\t// ctx, sample_rate_hz, head_name (cstr), out_error\n\t\t\targs: [T.ptr, T.i32, T.ptr, T.ptr],\n\t\t\treturns: T.ptr,\n\t\t},\n\t\teliza_inference_wakeword_score: {\n\t\t\t// wake (usize), pcm (ptr), n_samples (usize), out_prob (ptr),\n\t\t\t// out_error (ptr)\n\t\t\targs: [T.usize, T.ptr, T.usize, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_wakeword_reset: {\n\t\t\targs: [T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_wakeword_close: {\n\t\t\targs: [T.usize],\n\t\t\treturns: T.void,\n\t\t},\n\t};\n\t// Native voice classifiers (ABI v6): WeSpeaker speaker encoder + pyannote\n\t// diarizer, fused into the one libelizainference handle. Additive;\n\t// transitional builds may report v6 before the classifier symbols ship, so\n\t// bind opportunistically and advertise unsupported when absent (the\n\t// fused encoder/diarizer classes throw a structured error in that case —\n\t// no standalone libvoice_classifier fallback).\n\tlet speakerSymbolsAvailable = true;\n\tconst speakerDefs = {\n\t\teliza_inference_speaker_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_speaker_open: {\n\t\t\t// ctx, gguf_path (cstr or NULL), out_error\n\t\t\targs: [T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.ptr,\n\t\t},\n\t\teliza_inference_speaker_embed: {\n\t\t\t// speaker (usize), pcm (ptr), n_samples (usize), out_embedding (ptr),\n\t\t\t// out_error (ptr)\n\t\t\targs: [T.usize, T.ptr, T.usize, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_speaker_close: {\n\t\t\targs: [T.usize],\n\t\t\treturns: T.void,\n\t\t},\n\t};\n\tlet diarizSymbolsAvailable = true;\n\tconst diarizDefs = {\n\t\teliza_inference_diariz_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_diariz_open: {\n\t\t\t// ctx, gguf_path (cstr or NULL), out_error\n\t\t\targs: [T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.ptr,\n\t\t},\n\t\teliza_inference_diariz_segment: {\n\t\t\t// diariz (usize), pcm (ptr), n_samples (usize), out_labels (ptr),\n\t\t\t// io_n_labels (ptr), out_error (ptr)\n\t\t\targs: [T.usize, T.ptr, T.usize, T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_diariz_close: {\n\t\t\targs: [T.usize],\n\t\t\treturns: T.void,\n\t\t},\n\t};\n\t// Streaming LLM (additive on top of v3). Bound opportunistically — when\n\t// absent the runner reports native streaming as unsupported.\n\tlet llmStreamSymbolsAvailable = true;\n\t// ABI v8 streaming-LLM capability probes. Bound as their own family so a\n\t// v7 library (which has the `llm_stream_*` symbols but not these probes)\n\t// still binds `llmStreamDefs` while reporting MTP / KV-quant unsupported.\n\tlet llmCapabilitySymbolsAvailable = true;\n\tconst llmCapabilityDefs = {\n\t\teliza_inference_llm_mtp_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_llm_kv_quant_supported: { args: [], returns: T.i32 },\n\t};\n\tconst llmStreamDefs = {\n\t\teliza_inference_llm_stream_open: {\n\t\t\t// ctx (ptr), cfg (ptr to eliza_llm_stream_config_t), out_error (ptr)\n\t\t\targs: [T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.ptr,\n\t\t},\n\t\teliza_inference_llm_stream_prefill: {\n\t\t\targs: [T.usize, T.ptr, T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_llm_stream_next: {\n\t\t\t// stream, tokens_out, tokens_cap, num_tokens_out, text_out,\n\t\t\t// text_cap, drafter_drafted_out, drafter_accepted_out, out_error\n\t\t\targs: [\n\t\t\t\tT.usize,\n\t\t\t\tT.ptr,\n\t\t\t\tT.usize,\n\t\t\t\tT.ptr,\n\t\t\t\tT.ptr,\n\t\t\t\tT.usize,\n\t\t\t\tT.ptr,\n\t\t\t\tT.ptr,\n\t\t\t\tT.ptr,\n\t\t\t],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_llm_stream_cancel: {\n\t\t\targs: [T.usize],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_llm_stream_save_slot: {\n\t\t\targs: [T.usize, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_llm_stream_restore_slot: {\n\t\t\targs: [T.usize, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_llm_stream_close: {\n\t\t\targs: [T.usize],\n\t\t\treturns: T.void,\n\t\t},\n\t};\n\tconst referenceEncodeDefs = {\n\t\t// OmniVoice reference encode (ABI v4) — optional for transitional\n\t\t// fused libraries. Default TTS/ASR must still load when reference-clone\n\t\t// freezing is unavailable; encodeReferenceSupported() exposes that state.\n\t\teliza_inference_encode_reference: {\n\t\t\t// ctx, pcm, n_samples, sample_rate_hz, out_K, out_ref_T, out_tokens (int**), out_error\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.i32, T.ptr, T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_free_tokens: { args: [T.usize], returns: T.void },\n\t};\n\tlet referenceEncodeSymbolsAvailable = true;\n\t// Text-adjacent modalities (ABI v9): embeddings, mmproj vision describe, and\n\t// the tokenizer over the loaded text vocab. They ship together in a v9\n\t// build; bound and gated as one block layered on top of the v8 surface so\n\t// the cascade peels them when a v8 library is loaded. `free_tokens` is\n\t// re-listed here (a v9 build that lacks reference-encode still needs it for\n\t// `tokenize`'s buffer); identical defs merge harmlessly.\n\tlet textModalitiesSymbolsAvailable = true;\n\tconst textModalitiesDefs = {\n\t\teliza_inference_embed_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_embed: {\n\t\t\t// ctx, text, text_len, pooling, out_embedding, out_capacity, out_dim, out_error\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.i32, T.ptr, T.usize, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_vision_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_describe_image: {\n\t\t\t// ctx, image_bytes, n_bytes, mmproj_path, prompt, out_text, max_text_bytes, out_error\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.ptr, T.ptr, T.ptr, T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_tokenize_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_tokenize: {\n\t\t\t// ctx, text, text_len, add_special, parse_special, out_tokens (int**), out_n, out_error\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.i32, T.i32, T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_detokenize: {\n\t\t\t// ctx, tokens, n_tokens, remove_special, unparse_special, out_text, max_text_bytes, out_error\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.i32, T.i32, T.ptr, T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_free_tokens: { args: [T.usize], returns: T.void },\n\t};\n\t// Kokoro TTS (ABI v10): the in-process Kokoro engine folded into the fused\n\t// handle so the mobile path stops POSTing to the local-TCP llama-server\n\t// route. Bound as its own family layered on top of the v9 surface; the\n\t// cascade peels it when a v9 library is loaded. `kokoroSupported()` reports\n\t// false in that case and the Kokoro FFI runtime refuses (no TCP fallback).\n\tlet kokoroSymbolsAvailable = true;\n\tconst kokoroDefs = {\n\t\teliza_inference_kokoro_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_kokoro_load: {\n\t\t\t// ctx, gguf_path, voice_bin_path, style_dim, out_error\n\t\t\targs: [T.ptr, T.ptr, T.ptr, T.i32, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_kokoro_synthesize: {\n\t\t\t// ctx, text, text_len, speed, out_pcm, max_samples, out_error\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.f32, T.ptr, T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_kokoro_sample_rate: { args: [T.ptr], returns: T.i32 },\n\t};\n\t// End-of-turn scoring (ABI v11): a single causal forward pass over a\n\t// pre-tokenized partial transcript returns P(end-of-turn token). Layered on\n\t// top of the v10 surface; the cascade peels it when a v10 library is loaded\n\t// (the `eotSupported()` probe then reports false and the composite EOT\n\t// classifier falls back to the heuristic-only signal).\n\tlet eotSymbolsAvailable = true;\n\tconst eotDefs = {\n\t\teliza_inference_llm_eot_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_llm_eot_score: {\n\t\t\t// ctx, token_ids, num_tokens, target_token_id,\n\t\t\t// out_target_prob, out_top_token, out_top_prob, out_error\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.i32, T.ptr, T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t};\n\t// ABI v12 — fused ASR word timestamps.\n\tlet timedAsrSymbolsAvailable = true;\n\tconst timedAsrDefs = {\n\t\teliza_inference_asr_timestamps_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_asr_transcribe_timed: {\n\t\t\t// ctx, pcm, n_samples, sr, out_text, max_text_bytes,\n\t\t\t// out_word_start_ms, out_word_end_ms, io_n_words, out_error\n\t\t\targs: [\n\t\t\t\tT.ptr,\n\t\t\t\tT.ptr,\n\t\t\t\tT.usize,\n\t\t\t\tT.i32,\n\t\t\t\tT.ptr,\n\t\t\t\tT.usize,\n\t\t\t\tT.ptr,\n\t\t\t\tT.ptr,\n\t\t\t\tT.ptr,\n\t\t\t\tT.ptr,\n\t\t\t],\n\t\t\treturns: T.i32,\n\t\t},\n\t};\n\t// Streaming mmproj vision describe (ABI v13): open returns an EliLlmStream*\n\t// primed with the image+prompt KV; the caller drives the existing\n\t// `eliza_inference_llm_stream_next` loop. Layered on top of the v12 surface;\n\t// the cascade peels it when a <=v12 library is loaded (the\n\t// `visionStreamSupported()` probe then reports false and IMAGE_DESCRIPTION\n\t// falls back to the buffered `eliza_inference_describe_image`).\n\tlet visionStreamSymbolsAvailable = true;\n\tconst visionStreamDefs = {\n\t\teliza_inference_vision_stream_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_describe_image_stream_open: {\n\t\t\t// ctx, image_bytes, n_bytes, mmproj_path, prompt, out_error -> EliLlmStream*\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.ptr,\n\t\t},\n\t};\n\tconst coreDefs = {\n\t\teliza_inference_abi_version: { args: [], returns: T.cstring },\n\t\teliza_inference_create: {\n\t\t\targs: [T.ptr, T.ptr],\n\t\t\treturns: T.ptr,\n\t\t},\n\t\teliza_inference_destroy: { args: [T.ptr], returns: T.void },\n\t\teliza_inference_mmap_acquire: {\n\t\t\targs: [T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_mmap_evict: {\n\t\t\targs: [T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_tts_synthesize: {\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.ptr, T.ptr, T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_asr_transcribe: {\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.i32, T.ptr, T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\t// Streaming TTS + native verifier callback (ABI v2). The\n\t\t// function-pointer args are passed as raw pointer values\n\t\t// (`JSCallback.ptr`, or 0n to clear) so this binding owns the\n\t\t// JSCallback lifetime explicitly — see `ttsSynthesizeStream` /\n\t\t// `setVerifierCallback` below.\n\t\teliza_inference_tts_stream_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_tts_synthesize_stream: {\n\t\t\t// ctx, text, text_len, speaker, on_chunk (fn ptr), user_data, out_error\n\t\t\targs: [T.ptr, T.ptr, T.usize, T.ptr, T.usize, T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_cancel_tts: { args: [T.ptr, T.ptr], returns: T.i32 },\n\t\teliza_inference_set_verifier_callback: {\n\t\t\t// ctx, cb (fn ptr — 0 to clear), user_data, out_error\n\t\t\targs: [T.ptr, T.usize, T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\t// Streaming ASR (ABI v2).\n\t\teliza_inference_asr_stream_supported: { args: [], returns: T.i32 },\n\t\teliza_inference_asr_stream_open: {\n\t\t\targs: [T.ptr, T.i32, T.ptr],\n\t\t\treturns: T.ptr,\n\t\t},\n\t\teliza_inference_asr_stream_feed: {\n\t\t\t// stream handle is a raw C pointer → pass as usize.\n\t\t\targs: [T.usize, T.ptr, T.usize, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_asr_stream_partial: {\n\t\t\targs: [T.usize, T.ptr, T.usize, T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_asr_stream_finish: {\n\t\t\targs: [T.usize, T.ptr, T.usize, T.ptr, T.ptr, T.ptr],\n\t\t\treturns: T.i32,\n\t\t},\n\t\teliza_inference_asr_stream_close: { args: [T.usize], returns: T.void },\n\t\t// Bun 1.3.x accepts raw pointer values passed back into C as\n\t\t// `usize`, while `ptr` is for JS-owned ArrayBuffer pointers.\n\t\teliza_inference_free_string: { args: [T.usize], returns: T.void },\n\t};\n\t// Try the maximal additive symbol set first, then progressively drop\n\t// optional families. Each fallback flips a sentinel so `*Supported()` probes\n\t// report false instead of making an unavailable native call.\n\t// The v6 voice-classifier families (speaker encoder + diarizer) ship\n\t// together in the fused build, so they are bound and gated as one\n\t// `classifiers` block layered on top of the v5 wake-word family. The\n\t// cascade peels them in priority order: full v6 → v6-without-classifiers\n\t// (a real v5 build) → progressively smaller. Each rung flips a sentinel so\n\t// `*Supported()` reports false instead of calling an unbound symbol.\n\tconst classifierDefs = { ...speakerDefs, ...diarizDefs };\n\tconst attempts = [\n\t\t{\n\t\t\t// Full v13 surface (v12 + token-by-token mmproj vision describe).\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...referenceEncodeDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...wakewordDefs,\n\t\t\t\t...classifierDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t\t...llmCapabilityDefs,\n\t\t\t\t...textModalitiesDefs,\n\t\t\t\t...kokoroDefs,\n\t\t\t\t...eotDefs,\n\t\t\t\t...timedAsrDefs,\n\t\t\t\t...visionStreamDefs,\n\t\t\t},\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: true,\n\t\t\twakeword: true,\n\t\t\tclassifiers: true,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: true,\n\t\t\ttextModalities: true,\n\t\t\tkokoro: true,\n\t\t\teot: true,\n\t\t\ttimedAsr: true,\n\t\t\tvisionStream: true,\n\t\t},\n\t\t{\n\t\t\t// Full v12 surface (v11 + the in-process ASR word-timestamp decoder);\n\t\t\t// a v12 build lacks the v13 streaming-vision symbols.\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...referenceEncodeDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...wakewordDefs,\n\t\t\t\t...classifierDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t\t...llmCapabilityDefs,\n\t\t\t\t...textModalitiesDefs,\n\t\t\t\t...kokoroDefs,\n\t\t\t\t...eotDefs,\n\t\t\t\t...timedAsrDefs,\n\t\t\t},\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: true,\n\t\t\twakeword: true,\n\t\t\tclassifiers: true,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: true,\n\t\t\ttextModalities: true,\n\t\t\tkokoro: true,\n\t\t\teot: true,\n\t\t\ttimedAsr: true,\n\t\t},\n\t\t{\n\t\t\t// Full v11 surface (v10 + the in-process end-of-turn scorer); a v11\n\t\t\t// build lacks the v12 timed-ASR symbols.\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...referenceEncodeDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...wakewordDefs,\n\t\t\t\t...classifierDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t\t...llmCapabilityDefs,\n\t\t\t\t...textModalitiesDefs,\n\t\t\t\t...kokoroDefs,\n\t\t\t\t...eotDefs,\n\t\t\t},\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: true,\n\t\t\twakeword: true,\n\t\t\tclassifiers: true,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: true,\n\t\t\ttextModalities: true,\n\t\t\tkokoro: true,\n\t\t\teot: true,\n\t\t\ttimedAsr: false,\n\t\t},\n\t\t{\n\t\t\t// Full v10 surface (v9 + the in-process Kokoro block).\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...referenceEncodeDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...wakewordDefs,\n\t\t\t\t...classifierDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t\t...llmCapabilityDefs,\n\t\t\t\t...textModalitiesDefs,\n\t\t\t\t...kokoroDefs,\n\t\t\t},\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: true,\n\t\t\twakeword: true,\n\t\t\tclassifiers: true,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: true,\n\t\t\ttextModalities: true,\n\t\t\tkokoro: true,\n\t\t},\n\t\t{\n\t\t\t// Full v9 surface (no v10 Kokoro block).\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...referenceEncodeDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...wakewordDefs,\n\t\t\t\t...classifierDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t\t...llmCapabilityDefs,\n\t\t\t\t...textModalitiesDefs,\n\t\t\t},\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: true,\n\t\t\twakeword: true,\n\t\t\tclassifiers: true,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: true,\n\t\t\ttextModalities: true,\n\t\t},\n\t\t{\n\t\t\t// Full v8 surface (no v9 text-modality block).\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...referenceEncodeDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...wakewordDefs,\n\t\t\t\t...classifierDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t\t...llmCapabilityDefs,\n\t\t\t},\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: true,\n\t\t\twakeword: true,\n\t\t\tclassifiers: true,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: true,\n\t\t\ttextModalities: false,\n\t\t},\n\t\t{\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...wakewordDefs,\n\t\t\t\t...classifierDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t\t...llmCapabilityDefs,\n\t\t\t},\n\t\t\treferenceEncode: false,\n\t\t\tnativeVad: true,\n\t\t\twakeword: true,\n\t\t\tclassifiers: true,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: true,\n\t\t\ttextModalities: false,\n\t\t},\n\t\t{\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...referenceEncodeDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...wakewordDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t},\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: true,\n\t\t\twakeword: true,\n\t\t\tclassifiers: false,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: false,\n\t\t},\n\t\t{\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...wakewordDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t},\n\t\t\treferenceEncode: false,\n\t\t\tnativeVad: true,\n\t\t\twakeword: true,\n\t\t\tclassifiers: false,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: false,\n\t\t},\n\t\t{\n\t\t\tdefs: {\n\t\t\t\t...coreDefs,\n\t\t\t\t...referenceEncodeDefs,\n\t\t\t\t...nativeVadDefs,\n\t\t\t\t...llmStreamDefs,\n\t\t\t},\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: true,\n\t\t\twakeword: false,\n\t\t\tclassifiers: false,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: false,\n\t\t},\n\t\t{\n\t\t\tdefs: { ...coreDefs, ...nativeVadDefs, ...llmStreamDefs },\n\t\t\treferenceEncode: false,\n\t\t\tnativeVad: true,\n\t\t\twakeword: false,\n\t\t\tclassifiers: false,\n\t\t\tllmStream: true,\n\t\t\tllmCapability: false,\n\t\t},\n\t\t{\n\t\t\tdefs: { ...coreDefs, ...referenceEncodeDefs, ...nativeVadDefs },\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: true,\n\t\t\twakeword: false,\n\t\t\tclassifiers: false,\n\t\t\tllmStream: false,\n\t\t\tllmCapability: false,\n\t\t},\n\t\t{\n\t\t\tdefs: { ...coreDefs, ...nativeVadDefs },\n\t\t\treferenceEncode: false,\n\t\t\tnativeVad: true,\n\t\t\twakeword: false,\n\t\t\tclassifiers: false,\n\t\t\tllmStream: false,\n\t\t\tllmCapability: false,\n\t\t},\n\t\t{\n\t\t\tdefs: { ...coreDefs, ...referenceEncodeDefs },\n\t\t\treferenceEncode: true,\n\t\t\tnativeVad: false,\n\t\t\twakeword: false,\n\t\t\tclassifiers: false,\n\t\t\tllmStream: false,\n\t\t\tllmCapability: false,\n\t\t},\n\t\t{\n\t\t\tdefs: coreDefs,\n\t\t\treferenceEncode: false,\n\t\t\tnativeVad: false,\n\t\t\twakeword: false,\n\t\t\tclassifiers: false,\n\t\t\tllmStream: false,\n\t\t\tllmCapability: false,\n\t\t},\n\t];\n\tlet lastOpenError: unknown = null;\n\tfor (const attempt of attempts) {\n\t\ttry {\n\t\t\tlib = ffi.dlopen(dylibPath, attempt.defs);\n\t\t\treferenceEncodeSymbolsAvailable = attempt.referenceEncode;\n\t\t\tnativeVadSymbolsAvailable = attempt.nativeVad;\n\t\t\twakewordSymbolsAvailable = attempt.wakeword;\n\t\t\tspeakerSymbolsAvailable = attempt.classifiers;\n\t\t\tdiarizSymbolsAvailable = attempt.classifiers;\n\t\t\tllmStreamSymbolsAvailable = attempt.llmStream;\n\t\t\tllmCapabilitySymbolsAvailable = attempt.llmCapability ?? false;\n\t\t\ttextModalitiesSymbolsAvailable =\n\t\t\t\t(attempt as { textModalities?: boolean }).textModalities ?? false;\n\t\t\tkokoroSymbolsAvailable =\n\t\t\t\t(attempt as { kokoro?: boolean }).kokoro ?? false;\n\t\t\teotSymbolsAvailable = (attempt as { eot?: boolean }).eot ?? false;\n\t\t\ttimedAsrSymbolsAvailable =\n\t\t\t\t(attempt as { timedAsr?: boolean }).timedAsr ?? false;\n\t\t\tvisionStreamSymbolsAvailable =\n\t\t\t\t(attempt as { visionStream?: boolean }).visionStream ?? false;\n\t\t\tbreak;\n\t\t} catch (err) {\n\t\t\tlastOpenError = err;\n\t\t}\n\t}\n\tif (lib === null) {\n\t\tthrow new VoiceLifecycleError(\n\t\t\t\"kernel-missing\",\n\t\t\t`[ffi-bindings] Failed to open libelizainference at ${dylibPath}: ${formatFfiError(lastOpenError)}`,\n\t\t);\n\t}\n\tconst loadedLib = lib;\n\n\t// ABI version check. v4 is the current full surface; v3 is accepted only\n\t// when the optional reference-encode symbols are absent so default TTS/ASR\n\t// can still run while sample-to-profile freezing stays explicitly disabled.\n\tconst reported = readCString(\n\t\tloadedLib.symbols.eliza_inference_abi_version(),\n\t\tffi,\n\t);\n\t// v8 is the current full surface (v8 = streaming-LLM text parity: same-file\n\t// MTP speculative decoding + KV-cache quant + per-load GPU layers, probed\n\t// via `eliza_inference_llm_{mtp,kv_quant}_supported()`). A v7 library has\n\t// the identical voice/ASR/VAD symbol surface but lacks those LLM\n\t// optimizations, so it is still accepted for voice — the new capability\n\t// probes report unsupported, and the fused TEXT path refuses to route\n\t// through it (the anti-regression guard). Older fused builds may still be\n\t// useful at degraded capability:\n\t// - v7: real Silero VAD; LLM-text optimizations absent (probed).\n\t// - v6: same symbols as v7; VAD may be a stub (probed at runtime).\n\t// - v5: no speaker/diarizer classifiers — JS reports them unsupported.\n\t// - v4: additionally no wake-word — JS reports wake-word unsupported.\n\t// - v3: additionally no reference-encode — accepted only when the\n\t// optional reference-encode symbols are absent from the binding.\n\t// v10 (current) accepts the full surface. A v9 library has the identical\n\t// voice/ASR/VAD/LLM/text surface but lacks the v10 Kokoro symbols\n\t// (`eliza_inference_kokoro_*`), so it is accepted only when those symbols\n\t// are absent — the `kokoroSupported()` probe then reports false and the\n\t// Kokoro FFI runtime refuses (no TCP fallback on mobile). A v8 library\n\t// additionally lacks the v9 text-modality symbols (embeddings, vision,\n\t// tokenizer), accepted only when those are absent too.\n\tconst abiOk =\n\t\treported === String(ELIZA_INFERENCE_ABI_VERSION) ||\n\t\t(reported === \"12\" && !visionStreamSymbolsAvailable) ||\n\t\t(reported === \"11\" && !timedAsrSymbolsAvailable) ||\n\t\t(reported === \"10\" && !eotSymbolsAvailable && !timedAsrSymbolsAvailable) ||\n\t\t(reported === \"9\" && !kokoroSymbolsAvailable && !eotSymbolsAvailable) ||\n\t\t(reported === \"8\" &&\n\t\t\t!kokoroSymbolsAvailable &&\n\t\t\t!textModalitiesSymbolsAvailable) ||\n\t\treported === \"7\" ||\n\t\treported === \"6\" ||\n\t\t(reported === \"5\" && !speakerSymbolsAvailable && !diarizSymbolsAvailable) ||\n\t\t(reported === \"4\" &&\n\t\t\t!wakewordSymbolsAvailable &&\n\t\t\t!speakerSymbolsAvailable &&\n\t\t\t!diarizSymbolsAvailable) ||\n\t\t(reported === \"3\" &&\n\t\t\t!wakewordSymbolsAvailable &&\n\t\t\t!speakerSymbolsAvailable &&\n\t\t\t!diarizSymbolsAvailable &&\n\t\t\t!referenceEncodeSymbolsAvailable);\n\tif (!abiOk) {\n\t\tloadedLib.close();\n\t\tthrow new VoiceLifecycleError(\n\t\t\t\"kernel-missing\",\n\t\t\t`[ffi-bindings] ABI mismatch: binding expected v${ELIZA_INFERENCE_ABI_VERSION}, ` +\n\t\t\t\t`library at ${dylibPath} reports v${reported}. The fused build was produced ` +\n\t\t\t\t`against a different ffi.h — rebuild against the current header.`,\n\t\t);\n\t}\n\n\t/**\n\t * Read `*outErrPtr` (a `char**` that the library populated with a\n\t * heap-allocated NUL-terminated string), free the underlying buffer\n\t * via `eliza_inference_free_string`, and return the JS string. When\n\t * the library left `*outErrPtr` as NULL, returns null.\n\t */\n\tfunction takeError(outErrPtrBuf: BigUint64Array): string | null {\n\t\tconst ptrValue = outErrPtrBuf[0];\n\t\tif (ptrValue === undefined || ptrValue === 0n) return null;\n\t\tconst ptrNumber = Number(ptrValue);\n\t\tif (!Number.isSafeInteger(ptrNumber)) {\n\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\"kernel-missing\",\n\t\t\t\t`[ffi-bindings] C diagnostic pointer ${ptrValue.toString()} exceeds JS safe integer range`,\n\t\t\t);\n\t\t}\n\t\tconst cstr = new ffi.CString(ptrNumber);\n\t\tconst message = cstr.toString();\n\t\tloadedLib.symbols.eliza_inference_free_string(ptrValue);\n\t\treturn message;\n\t}\n\n\tfunction makeOutErr(): { buf: BigUint64Array; ptr: unknown } {\n\t\tconst buf = new BigUint64Array(1);\n\t\treturn { buf, ptr: ffi.ptr(buf) };\n\t}\n\n\t/**\n\t * Encode a JS string to a NUL-terminated UTF-8 buffer and return a\n\t * `T.ptr`-compatible pointer suitable for `const char *` arguments.\n\t * Returns null when the input is null — the C ABI accepts NULL for\n\t * optional arguments like `speaker_preset_id`.\n\t */\n\tfunction cstr(value: string | null): {\n\t\tptr: unknown;\n\t\tbytes: number;\n\t\tbuffer: Buffer | null;\n\t} {\n\t\tif (value === null) return { ptr: null, bytes: 0, buffer: null };\n\t\tconst bytes = Buffer.from(value, \"utf8\");\n\t\tconst buf = Buffer.alloc(bytes.byteLength + 1);\n\t\tbytes.copy(buf);\n\t\treturn { ptr: ffi.ptr(buf), bytes: bytes.byteLength, buffer: buf };\n\t}\n\n\tfunction failureCode(rc: number): VoiceLifecycleError[\"code\"] {\n\t\tif (rc === ELIZA_ERR_OOM) return \"ram-pressure\";\n\t\tif (rc === ELIZA_ERR_FFI_FAULT) return \"mmap-fail\";\n\t\tif (rc === ELIZA_ERR_NOT_IMPLEMENTED) return \"kernel-missing\";\n\t\tif (rc === ELIZA_ERR_ABI_MISMATCH) return \"kernel-missing\";\n\t\tif (rc === ELIZA_ERR_BUNDLE_INVALID) return \"kernel-missing\";\n\t\treturn \"kernel-missing\";\n\t}\n\n\tfunction isNullPointer(value: unknown): boolean {\n\t\treturn value === null || value === undefined || value === 0n || value === 0;\n\t}\n\n\treturn {\n\t\tlibraryPath: dylibPath,\n\t\tlibraryAbiVersion: reported,\n\n\t\tcreate(bundleDir: string): ElizaInferenceContextHandle {\n\t\t\tconst err = makeOutErr();\n\t\t\tconst bundleArg = cstr(bundleDir);\n\t\t\tconst handle = loadedLib.symbols.eliza_inference_create(\n\t\t\t\tbundleArg.ptr,\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (isNullPointer(handle)) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_create returned NULL with no diagnostic\";\n\t\t\t\tthrow new VoiceLifecycleError(\"kernel-missing\", message);\n\t\t\t}\n\t\t\treturn handle as ElizaInferenceContextHandle;\n\t\t},\n\n\t\tdestroy(ctx: ElizaInferenceContextHandle): void {\n\t\t\tloadedLib.symbols.eliza_inference_destroy(ctx);\n\t\t},\n\n\t\tmmapAcquire(ctx, region) {\n\t\t\tconst err = makeOutErr();\n\t\t\tconst regionArg = cstr(region);\n\t\t\tconst rc = loadedLib.symbols.eliza_inference_mmap_acquire(\n\t\t\t\tctx,\n\t\t\t\tregionArg.ptr,\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_mmap_acquire(${region}) rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\tmmapEvict(ctx, region) {\n\t\t\tconst err = makeOutErr();\n\t\t\tconst regionArg = cstr(region);\n\t\t\tconst rc = loadedLib.symbols.eliza_inference_mmap_evict(\n\t\t\t\tctx,\n\t\t\t\tregionArg.ptr,\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_mmap_evict(${region}) rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\tttsSynthesize({ ctx, text, speakerPresetId, out }) {\n\t\t\tconst err = makeOutErr();\n\t\t\tconst textArg = cstr(text);\n\t\t\tconst speakerArg = cstr(speakerPresetId);\n\t\t\tconst rc = loadedLib.symbols.eliza_inference_tts_synthesize(\n\t\t\t\tctx,\n\t\t\t\ttextArg.ptr,\n\t\t\t\tBigInt(textArg.bytes),\n\t\t\t\tspeakerArg.ptr,\n\t\t\t\tffi.ptr(out),\n\t\t\t\tBigInt(out.length),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc < 0) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_tts_synthesize rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\treturn rc;\n\t\t},\n\n\t\tasrTranscribe({ ctx, pcm, sampleRateHz, maxTextBytes }) {\n\t\t\tconst err = makeOutErr();\n\t\t\tconst cap = maxTextBytes ?? 4096;\n\t\t\tconst outText = new Uint8Array(cap);\n\t\t\tconst rc = loadedLib.symbols.eliza_inference_asr_transcribe(\n\t\t\t\tctx,\n\t\t\t\tffi.ptr(pcm),\n\t\t\t\tBigInt(pcm.length),\n\t\t\t\tsampleRateHz,\n\t\t\t\tffi.ptr(outText),\n\t\t\t\tBigInt(cap),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc < 0) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_asr_transcribe rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\tconst nul = outText.indexOf(0, 0);\n\t\t\tconst len = nul >= 0 ? nul : rc;\n\t\t\treturn Buffer.from(outText.buffer, outText.byteOffset, len).toString(\n\t\t\t\t\"utf8\",\n\t\t\t);\n\t\t},\n\n\t\ttimedAsrSupported(): boolean {\n\t\t\tconst probe = loadedLib.symbols.eliza_inference_asr_timestamps_supported;\n\t\t\treturn (\n\t\t\t\ttimedAsrSymbolsAvailable && typeof probe === \"function\" && probe() === 1\n\t\t\t);\n\t\t},\n\n\t\tasrTranscribeTimed({ ctx, pcm, sampleRateHz, maxTextBytes, maxWords }) {\n\t\t\tconst fn = loadedLib.symbols.eliza_inference_asr_transcribe_timed;\n\t\t\tif (!timedAsrSymbolsAvailable || typeof fn !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_asr_transcribe_timed is not exported by this build (pre-v12)\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst cap = maxTextBytes ?? 4096;\n\t\t\tconst wordCap = maxWords ?? 1024;\n\t\t\tconst outText = new Uint8Array(cap);\n\t\t\tconst startMs = new Int32Array(wordCap);\n\t\t\tconst endMs = new Int32Array(wordCap);\n\t\t\tconst nWords = new BigUint64Array(1);\n\t\t\tnWords[0] = BigInt(wordCap);\n\t\t\tconst rc = fn(\n\t\t\t\tctx,\n\t\t\t\tffi.ptr(pcm),\n\t\t\t\tBigInt(pcm.length),\n\t\t\t\tsampleRateHz,\n\t\t\t\tffi.ptr(outText),\n\t\t\t\tBigInt(cap),\n\t\t\t\tffi.ptr(startMs),\n\t\t\t\tffi.ptr(endMs),\n\t\t\t\tffi.ptr(nWords),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc < 0) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_asr_transcribe_timed rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\tconst nul = outText.indexOf(0, 0);\n\t\t\tconst len = nul >= 0 ? nul : rc;\n\t\t\tconst text = Buffer.from(\n\t\t\t\toutText.buffer,\n\t\t\t\toutText.byteOffset,\n\t\t\t\tlen,\n\t\t\t).toString(\"utf8\");\n\t\t\tconst words = recoverAsrWords(text, Number(nWords[0]), startMs, endMs);\n\t\t\treturn { text, words };\n\t\t},\n\n\t\t/* ---- Streaming TTS + verifier callback (ABI v2) ------------ */\n\n\t\tttsStreamSupported(): boolean {\n\t\t\treturn loadedLib.symbols.eliza_inference_tts_stream_supported() === 1;\n\t\t},\n\n\t\tttsSynthesizeStream({ ctx, text, speakerPresetId, onChunk }) {\n\t\t\tconst err = makeOutErr();\n\t\t\tconst textArg = cstr(text);\n\t\t\tconst speakerArg = cstr(speakerPresetId);\n\t\t\t// (pcm: ptr, n_samples: usize, is_final: i32, user_data: ptr) -> i32\n\t\t\tconst cb = new ffi.JSCallback(\n\t\t\t\t(pcmPtr: bigint, nSamples: bigint, isFinal: number) => {\n\t\t\t\t\tconst n = Number(nSamples);\n\t\t\t\t\t// Bun delivers the C pointer as a bigint; copy the floats out\n\t\t\t\t\t// before returning — the buffer is the library's, valid only\n\t\t\t\t\t// for this call.\n\t\t\t\t\tconst pcm =\n\t\t\t\t\t\tn > 0 && pcmPtr !== 0n\n\t\t\t\t\t\t\t? new Float32Array(ffi.toArrayBuffer(pcmPtr, 0, n * 4).slice(0))\n\t\t\t\t\t\t\t: new Float32Array(0);\n\t\t\t\t\tconst requestCancel = onChunk({ pcm, isFinal: isFinal !== 0 });\n\t\t\t\t\treturn requestCancel === true ? 1 : 0;\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\targs: [T.ptr, T.usize, T.i32, T.ptr],\n\t\t\t\t\treturns: T.i32,\n\t\t\t\t},\n\t\t\t);\n\t\t\ttry {\n\t\t\t\tconst rc = loadedLib.symbols.eliza_inference_tts_synthesize_stream(\n\t\t\t\t\tctx,\n\t\t\t\t\ttextArg.ptr,\n\t\t\t\t\tBigInt(textArg.bytes),\n\t\t\t\t\tspeakerArg.ptr,\n\t\t\t\t\tBigInt(cb.ptr),\n\t\t\t\t\t0n,\n\t\t\t\t\terr.ptr,\n\t\t\t\t);\n\t\t\t\tif (rc === ELIZA_ERR_CANCELLED) return { cancelled: true };\n\t\t\t\tif (rc < 0) {\n\t\t\t\t\tconst message =\n\t\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\t`[ffi-bindings] eliza_inference_tts_synthesize_stream rc=${rc}`;\n\t\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t\t}\n\t\t\t\treturn { cancelled: false };\n\t\t\t} finally {\n\t\t\t\tcb.close();\n\t\t\t}\n\t\t},\n\n\t\tcancelTts(ctx) {\n\t\t\tconst err = makeOutErr();\n\t\t\tconst rc = loadedLib.symbols.eliza_inference_cancel_tts(ctx, err.ptr);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_cancel_tts rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\tencodeReferenceSupported(): boolean {\n\t\t\treturn (\n\t\t\t\ttypeof loadedLib.symbols.eliza_inference_encode_reference === \"function\"\n\t\t\t);\n\t\t},\n\n\t\tencodeReference({ ctx, pcm, sampleRateHz }) {\n\t\t\tif (\n\t\t\t\ttypeof loadedLib.symbols.eliza_inference_encode_reference !==\n\t\t\t\t\t\"function\" ||\n\t\t\t\ttypeof loadedLib.symbols.eliza_inference_free_tokens !== \"function\"\n\t\t\t) {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_encode_reference is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (sampleRateHz !== 24000) {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t`[ffi-bindings] encodeReference: sampleRateHz must be 24000 (got ${sampleRateHz})`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\t// out_K and out_ref_T are int*, out_tokens is int** — give the library\n\t\t\t// a slot to write into, then read back.\n\t\t\tconst outK = new Int32Array(1);\n\t\t\tconst outRefT = new Int32Array(1);\n\t\t\tconst outTokensPtr = new BigUint64Array(1);\n\t\t\tconst rc = loadedLib.symbols.eliza_inference_encode_reference(\n\t\t\t\tctx,\n\t\t\t\tffi.ptr(pcm),\n\t\t\t\tBigInt(pcm.length),\n\t\t\t\tsampleRateHz,\n\t\t\t\tffi.ptr(outK),\n\t\t\t\tffi.ptr(outRefT),\n\t\t\t\tffi.ptr(outTokensPtr),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_encode_reference rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\tconst K = outK[0];\n\t\t\tconst refT = outRefT[0];\n\t\t\tconst tokensRaw = outTokensPtr[0];\n\t\t\tif (K <= 0 || refT <= 0 || tokensRaw === 0n) {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t`[ffi-bindings] encodeReference returned empty result (K=${K}, refT=${refT})`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst tokenCount = K * refT;\n\t\t\ttry {\n\t\t\t\t// Copy out of the library's malloc'ed buffer so we can free it\n\t\t\t\t// before returning. Each int32 is 4 bytes.\n\t\t\t\tconst tokenBytes = tokenCount * 4;\n\t\t\t\tconst tokensPtr =\n\t\t\t\t\ttypeof tokensRaw === \"bigint\" ? Number(tokensRaw) : tokensRaw;\n\t\t\t\tconst nativeView = ffi.toArrayBuffer(tokensPtr, 0, tokenBytes);\n\t\t\t\tconst bytes = new Uint8Array(nativeView);\n\t\t\t\tif (bytes.byteLength < tokenBytes) {\n\t\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\t`[ffi-bindings] encodeReference returned an unreadable token buffer (K=${K}, refT=${refT}, got=${bytes.byteLength}, expected=${tokenBytes}, ctor=${nativeView.constructor.name})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst copied = bytes.slice(0, tokenBytes);\n\t\t\t\tconst tokens = new Int32Array(copied.buffer);\n\t\t\t\treturn { K, refT, tokens };\n\t\t\t} finally {\n\t\t\t\tloadedLib.symbols.eliza_inference_free_tokens(tokensRaw);\n\t\t\t}\n\t\t},\n\n\t\tsetVerifierCallback(ctx, cbFn) {\n\t\t\tconst err = makeOutErr();\n\t\t\tif (cbFn === null) {\n\t\t\t\tconst rc = loadedLib.symbols.eliza_inference_set_verifier_callback(\n\t\t\t\t\tctx,\n\t\t\t\t\t0n,\n\t\t\t\t\t0n,\n\t\t\t\t\terr.ptr,\n\t\t\t\t);\n\t\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\t\tconst message =\n\t\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\t`[ffi-bindings] eliza_inference_set_verifier_callback(clear) rc=${rc}`;\n\t\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t\t}\n\t\t\t\treturn { close: () => {} };\n\t\t\t}\n\t\t\t// (ev: ptr to EliVerifierEvent, user_data: ptr) -> void\n\t\t\tconst cb = new ffi.JSCallback(\n\t\t\t\t(evPtr: bigint) => {\n\t\t\t\t\tcbFn(readVerifierEvent(evPtr, ffi));\n\t\t\t\t},\n\t\t\t\t{ args: [T.ptr, T.ptr], returns: T.void },\n\t\t\t);\n\t\t\tconst rc = loadedLib.symbols.eliza_inference_set_verifier_callback(\n\t\t\t\tctx,\n\t\t\t\tBigInt(cb.ptr),\n\t\t\t\t0n,\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tcb.close();\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_set_verifier_callback rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tclose: () => {\n\t\t\t\t\t// Clear the native registration FIRST, then free the\n\t\t\t\t\t// JSCallback — order matters so the native side never\n\t\t\t\t\t// dereferences a closed callback.\n\t\t\t\t\tconst clearErr = makeOutErr();\n\t\t\t\t\tloadedLib.symbols.eliza_inference_set_verifier_callback(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t0n,\n\t\t\t\t\t\t0n,\n\t\t\t\t\t\tclearErr.ptr,\n\t\t\t\t\t);\n\t\t\t\t\ttakeError(clearErr.buf);\n\t\t\t\t\tcb.close();\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\n\t\t/* ---- Native VAD (ABI v3) ----------------------------------- */\n\n\t\tvadSupported(): boolean {\n\t\t\tif (\n\t\t\t\t!nativeVadSymbolsAvailable ||\n\t\t\t\ttypeof loadedLib.symbols.eliza_inference_vad_supported !== \"function\"\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn loadedLib.symbols.eliza_inference_vad_supported() === 1;\n\t\t},\n\n\t\tvadOpen({ ctx, sampleRateHz }) {\n\t\t\tconst open = loadedLib.symbols.eliza_inference_vad_open;\n\t\t\tif (!nativeVadSymbolsAvailable || typeof open !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_vad_open is not exported by this libelizainference build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst handle = open(ctx, sampleRateHz, err.ptr);\n\t\t\tif (isNullPointer(handle)) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_vad_open returned NULL with no diagnostic\";\n\t\t\t\tthrow new VoiceLifecycleError(\"kernel-missing\", message);\n\t\t\t}\n\t\t\treturn handle as NativeVadHandle;\n\t\t},\n\n\t\tvadProcess({ vad, pcm }) {\n\t\t\tconst process = loadedLib.symbols.eliza_inference_vad_process;\n\t\t\tif (!nativeVadSymbolsAvailable || typeof process !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_vad_process is not exported by this libelizainference build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst outProbability = new Float32Array(1);\n\t\t\tconst rc = process(\n\t\t\t\tvad,\n\t\t\t\tffi.ptr(pcm),\n\t\t\t\tBigInt(pcm.length),\n\t\t\t\tffi.ptr(outProbability),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_vad_process rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\treturn outProbability[0] ?? 0;\n\t\t},\n\n\t\tvadReset(vad) {\n\t\t\tconst reset = loadedLib.symbols.eliza_inference_vad_reset;\n\t\t\tif (!nativeVadSymbolsAvailable || typeof reset !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_vad_reset is not exported by this libelizainference build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst rc = reset(vad, err.ptr);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_vad_reset rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\tvadClose(vad) {\n\t\t\tloadedLib.symbols.eliza_inference_vad_close?.(vad);\n\t\t},\n\n\t\t/* ---- Native wake-word (ABI v5) ----------------------------- */\n\n\t\twakewordSupported(): boolean {\n\t\t\tif (\n\t\t\t\t!wakewordSymbolsAvailable ||\n\t\t\t\ttypeof loadedLib.symbols.eliza_inference_wakeword_supported !==\n\t\t\t\t\t\"function\"\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn loadedLib.symbols.eliza_inference_wakeword_supported() === 1;\n\t\t},\n\n\t\twakewordOpen({ ctx, sampleRateHz, headName }) {\n\t\t\tconst open = loadedLib.symbols.eliza_inference_wakeword_open;\n\t\t\tif (!wakewordSymbolsAvailable || typeof open !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_wakeword_open is not exported by this libelizainference build (wake-word GGUF runtime not present)\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst headArg = cstr(headName);\n\t\t\tconst handle = open(ctx, sampleRateHz, headArg.ptr, err.ptr);\n\t\t\tif (isNullPointer(handle)) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_wakeword_open returned NULL with no diagnostic\";\n\t\t\t\tthrow new VoiceLifecycleError(\"kernel-missing\", message);\n\t\t\t}\n\t\t\treturn handle as NativeWakeWordHandle;\n\t\t},\n\n\t\twakewordScore({ wake, pcm }) {\n\t\t\tconst score = loadedLib.symbols.eliza_inference_wakeword_score;\n\t\t\tif (!wakewordSymbolsAvailable || typeof score !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_wakeword_score is not exported by this libelizainference build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst outProbability = new Float32Array(1);\n\t\t\tconst rc = score(\n\t\t\t\twake,\n\t\t\t\tffi.ptr(pcm),\n\t\t\t\tBigInt(pcm.length),\n\t\t\t\tffi.ptr(outProbability),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_wakeword_score rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\treturn outProbability[0] ?? 0;\n\t\t},\n\n\t\twakewordReset(wake) {\n\t\t\tconst reset = loadedLib.symbols.eliza_inference_wakeword_reset;\n\t\t\tif (!wakewordSymbolsAvailable || typeof reset !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_wakeword_reset is not exported by this libelizainference build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst rc = reset(wake, err.ptr);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_wakeword_reset rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\twakewordClose(wake) {\n\t\t\tloadedLib.symbols.eliza_inference_wakeword_close?.(wake);\n\t\t},\n\n\t\t/* ---- Native speaker encoder (ABI v6) ----------------------- */\n\n\t\tspeakerSupported(): boolean {\n\t\t\tif (\n\t\t\t\t!speakerSymbolsAvailable ||\n\t\t\t\ttypeof loadedLib.symbols.eliza_inference_speaker_supported !==\n\t\t\t\t\t\"function\"\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn loadedLib.symbols.eliza_inference_speaker_supported() === 1;\n\t\t},\n\n\t\tspeakerOpen({ ctx, ggufPath }) {\n\t\t\tconst open = loadedLib.symbols.eliza_inference_speaker_open;\n\t\t\tif (!speakerSymbolsAvailable || typeof open !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_speaker_open is not exported by this libelizainference build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst ggufArg = cstr(ggufPath);\n\t\t\tconst handle = open(ctx, ggufArg.ptr, err.ptr);\n\t\t\tif (isNullPointer(handle)) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_speaker_open returned NULL with no diagnostic\";\n\t\t\t\tthrow new VoiceLifecycleError(\"kernel-missing\", message);\n\t\t\t}\n\t\t\treturn handle as NativeSpeakerHandle;\n\t\t},\n\n\t\tspeakerEmbed({ speaker, pcm }) {\n\t\t\tconst embed = loadedLib.symbols.eliza_inference_speaker_embed;\n\t\t\tif (!speakerSymbolsAvailable || typeof embed !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_speaker_embed is not exported by this libelizainference build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst outEmbedding = new Float32Array(SPEAKER_EMBEDDING_DIM);\n\t\t\tconst rc = embed(\n\t\t\t\tspeaker,\n\t\t\t\tffi.ptr(pcm),\n\t\t\t\tBigInt(pcm.length),\n\t\t\t\tffi.ptr(outEmbedding),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_speaker_embed rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\treturn outEmbedding;\n\t\t},\n\n\t\tspeakerClose(speaker) {\n\t\t\tloadedLib.symbols.eliza_inference_speaker_close?.(speaker);\n\t\t},\n\n\t\t/* ---- Native diarizer (ABI v6) ------------------------------ */\n\n\t\tdiarizSupported(): boolean {\n\t\t\tif (\n\t\t\t\t!diarizSymbolsAvailable ||\n\t\t\t\ttypeof loadedLib.symbols.eliza_inference_diariz_supported !== \"function\"\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn loadedLib.symbols.eliza_inference_diariz_supported() === 1;\n\t\t},\n\n\t\tdiarizOpen({ ctx, ggufPath }) {\n\t\t\tconst open = loadedLib.symbols.eliza_inference_diariz_open;\n\t\t\tif (!diarizSymbolsAvailable || typeof open !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_diariz_open is not exported by this libelizainference build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst ggufArg = cstr(ggufPath);\n\t\t\tconst handle = open(ctx, ggufArg.ptr, err.ptr);\n\t\t\tif (isNullPointer(handle)) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_diariz_open returned NULL with no diagnostic\";\n\t\t\t\tthrow new VoiceLifecycleError(\"kernel-missing\", message);\n\t\t\t}\n\t\t\treturn handle as NativeDiarizHandle;\n\t\t},\n\n\t\tdiarizSegment({ diariz, pcm }) {\n\t\t\tconst segment = loadedLib.symbols.eliza_inference_diariz_segment;\n\t\t\tif (!diarizSymbolsAvailable || typeof segment !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_diariz_segment is not exported by this libelizainference build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\t// The library writes `frames_per_window` (293 for pyannote-3) int8\n\t\t\t// labels. Pass a generous capacity and read back the actual count\n\t\t\t// the library writes into `*io_n_labels`.\n\t\t\tconst outLabels = new Int8Array(DIARIZ_LABELS_CAPACITY);\n\t\t\tconst ioNLabels = new BigUint64Array([BigInt(outLabels.length)]);\n\t\t\tconst rc = segment(\n\t\t\t\tdiariz,\n\t\t\t\tffi.ptr(pcm),\n\t\t\t\tBigInt(pcm.length),\n\t\t\t\tffi.ptr(outLabels),\n\t\t\t\tffi.ptr(ioNLabels),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_diariz_segment rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\tconst nFrames = Number(ioNLabels[0] ?? 0n);\n\t\t\treturn outLabels.slice(0, Math.min(nFrames, outLabels.length));\n\t\t},\n\n\t\tdiarizClose(diariz) {\n\t\t\tloadedLib.symbols.eliza_inference_diariz_close?.(diariz);\n\t\t},\n\n\t\t/* ---- Streaming ASR (ABI v2) -------------------------------- */\n\n\t\tasrStreamSupported(): boolean {\n\t\t\treturn loadedLib.symbols.eliza_inference_asr_stream_supported() === 1;\n\t\t},\n\n\t\tasrStreamOpen({ ctx, sampleRateHz }) {\n\t\t\tconst err = makeOutErr();\n\t\t\tconst handle = loadedLib.symbols.eliza_inference_asr_stream_open(\n\t\t\t\tctx,\n\t\t\t\tsampleRateHz,\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (isNullPointer(handle)) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_asr_stream_open returned NULL with no diagnostic\";\n\t\t\t\tthrow new VoiceLifecycleError(\"kernel-missing\", message);\n\t\t\t}\n\t\t\treturn handle as bigint;\n\t\t},\n\n\t\tasrStreamFeed({ stream, pcm }) {\n\t\t\tconst err = makeOutErr();\n\t\t\tconst rc = loadedLib.symbols.eliza_inference_asr_stream_feed(\n\t\t\t\tstream,\n\t\t\t\tffi.ptr(pcm),\n\t\t\t\tBigInt(pcm.length),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc < 0) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_asr_stream_feed rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\tasrStreamPartial(args) {\n\t\t\treturn readAsrStreamResult(\n\t\t\t\t\"partial\",\n\t\t\t\tloadedLib.symbols.eliza_inference_asr_stream_partial,\n\t\t\t\targs,\n\t\t\t);\n\t\t},\n\n\t\tasrStreamFinish(args) {\n\t\t\treturn readAsrStreamResult(\n\t\t\t\t\"finish\",\n\t\t\t\tloadedLib.symbols.eliza_inference_asr_stream_finish,\n\t\t\t\targs,\n\t\t\t);\n\t\t},\n\n\t\tasrStreamClose(stream) {\n\t\t\tloadedLib.symbols.eliza_inference_asr_stream_close(stream);\n\t\t},\n\n\t\t/* ---- Streaming LLM (additive on top of v3) ----------------- */\n\n\t\tllmStreamSupported(): boolean {\n\t\t\t// Symbols are bound at dlopen — if the fallback path stripped them\n\t\t\t// out, the runtime never advertises support.\n\t\t\treturn (\n\t\t\t\tllmStreamSymbolsAvailable &&\n\t\t\t\ttypeof loadedLib.symbols.eliza_inference_llm_stream_open === \"function\"\n\t\t\t);\n\t\t},\n\n\t\tllmMtpSupported(): boolean {\n\t\t\t// ABI v8 capability probe. Absent (or the whole probe family\n\t\t\t// unbound) on a v7 library → unsupported, so the fused text path\n\t\t\t// refuses to route MTP through it.\n\t\t\tconst probe = loadedLib.symbols.eliza_inference_llm_mtp_supported;\n\t\t\treturn (\n\t\t\t\tllmCapabilitySymbolsAvailable &&\n\t\t\t\ttypeof probe === \"function\" &&\n\t\t\t\tprobe() === 1\n\t\t\t);\n\t\t},\n\n\t\tllmKvQuantSupported(): boolean {\n\t\t\tconst probe = loadedLib.symbols.eliza_inference_llm_kv_quant_supported;\n\t\t\treturn (\n\t\t\t\tllmCapabilitySymbolsAvailable &&\n\t\t\t\ttypeof probe === \"function\" &&\n\t\t\t\tprobe() === 1\n\t\t\t);\n\t\t},\n\n\t\tllmStreamOpen({ ctx, config }) {\n\t\t\tconst open = loadedLib.symbols.eliza_inference_llm_stream_open;\n\t\t\tif (!llmStreamSymbolsAvailable || typeof open !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_llm_stream_open is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\t// Marshal the config struct into a Buffer. Layout matches\n\t\t\t// `eliza_llm_stream_config_t` in `eliza-inference-ffi.h`\n\t\t\t// (8-byte aligned, ABI v9):\n\t\t\t// off 0 : i32 max_tokens\n\t\t\t// off 4 : f32 temperature\n\t\t\t// off 8 : f32 top_p\n\t\t\t// off 12 : i32 top_k\n\t\t\t// off 16 : f32 repeat_penalty\n\t\t\t// off 20 : i32 slot_id\n\t\t\t// off 24 : ptr prompt_cache_key\n\t\t\t// off 32 : i32 draft_min\n\t\t\t// off 36 : i32 draft_max\n\t\t\t// off 40 : ptr mtp_drafter_path\n\t\t\t// off 48 : ptr gbnf_grammar\n\t\t\t// off 56 : i32 disable_thinking\n\t\t\t// off 60 : i32 n_gpu_layers (ABI v8 — fills old tail pad)\n\t\t\t// off 64 : ptr cache_type_k (ABI v8)\n\t\t\t// off 72 : ptr cache_type_v (ABI v8)\n\t\t\t// off 80 : i32 context_size (ABI v9)\n\t\t\t// sizeof = 88\n\t\t\tconst buf = Buffer.alloc(88);\n\t\t\tbuf.writeInt32LE(config.maxTokens, 0);\n\t\t\tbuf.writeFloatLE(config.temperature, 4);\n\t\t\tbuf.writeFloatLE(config.topP, 8);\n\t\t\tbuf.writeInt32LE(config.topK, 12);\n\t\t\tbuf.writeFloatLE(config.repeatPenalty, 16);\n\t\t\tbuf.writeInt32LE(config.slotId, 20);\n\t\t\tconst keyArg = cstr(config.promptCacheKey);\n\t\t\tconst drafterArg = cstr(config.draftModelPath);\n\t\t\tconst grammarArg = cstr(\n\t\t\t\tconfig.gbnfGrammar && config.gbnfGrammar.length > 0\n\t\t\t\t\t? config.gbnfGrammar\n\t\t\t\t\t: null,\n\t\t\t);\n\t\t\tconst cacheKArg = cstr(\n\t\t\t\tconfig.cacheTypeK && config.cacheTypeK.length > 0\n\t\t\t\t\t? config.cacheTypeK\n\t\t\t\t\t: null,\n\t\t\t);\n\t\t\tconst cacheVArg = cstr(\n\t\t\t\tconfig.cacheTypeV && config.cacheTypeV.length > 0\n\t\t\t\t\t? config.cacheTypeV\n\t\t\t\t\t: null,\n\t\t\t);\n\t\t\tbuf.writeBigUInt64LE(toPtrBigInt(keyArg.ptr), 24);\n\t\t\tbuf.writeInt32LE(config.draftMin, 32);\n\t\t\tbuf.writeInt32LE(config.draftMax, 36);\n\t\t\tbuf.writeBigUInt64LE(toPtrBigInt(drafterArg.ptr), 40);\n\t\t\tbuf.writeBigUInt64LE(toPtrBigInt(grammarArg.ptr), 48);\n\t\t\tbuf.writeInt32LE(config.disableThinking ? 1 : 0, 56);\n\t\t\t// -1 = runtime default (all layers); 0 = CPU. `undefined` -> -1.\n\t\t\tbuf.writeInt32LE(\n\t\t\t\tconfig.gpuLayers === undefined ? -1 : config.gpuLayers,\n\t\t\t\t60,\n\t\t\t);\n\t\t\tbuf.writeBigUInt64LE(toPtrBigInt(cacheKArg.ptr), 64);\n\t\t\tbuf.writeBigUInt64LE(toPtrBigInt(cacheVArg.ptr), 72);\n\t\t\tbuf.writeInt32LE(config.contextSize ?? 0, 80);\n\t\t\tconst handle = open(ctx, ffi.ptr(buf), err.ptr);\n\t\t\tif (isNullPointer(handle)) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_llm_stream_open returned NULL with no diagnostic\";\n\t\t\t\tthrow new VoiceLifecycleError(\"kernel-missing\", message);\n\t\t\t}\n\t\t\treturn handle as LlmStreamHandle;\n\t\t},\n\n\t\tllmStreamPrefill({ stream, tokens }) {\n\t\t\tconst prefill = loadedLib.symbols.eliza_inference_llm_stream_prefill;\n\t\t\tif (!llmStreamSymbolsAvailable || typeof prefill !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_llm_stream_prefill is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst rc = prefill(\n\t\t\t\tstream,\n\t\t\t\tffi.ptr(tokens),\n\t\t\t\tBigInt(tokens.length),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_llm_stream_prefill rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\tllmStreamNext({ stream, maxTokensPerStep, maxTextBytes }) {\n\t\t\tconst next = loadedLib.symbols.eliza_inference_llm_stream_next;\n\t\t\tif (!llmStreamSymbolsAvailable || typeof next !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_llm_stream_next is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst tokenCap = maxTokensPerStep ?? 32;\n\t\t\tconst textCap = maxTextBytes ?? 1024;\n\t\t\tconst tokensOut = new Int32Array(tokenCap);\n\t\t\tconst numTokensOut = new BigUint64Array(1);\n\t\t\tconst textOut = new Uint8Array(textCap);\n\t\t\tconst drafterDrafted = new Int32Array(1);\n\t\t\tconst drafterAccepted = new Int32Array(1);\n\t\t\tconst rc = next(\n\t\t\t\tstream,\n\t\t\t\tffi.ptr(tokensOut),\n\t\t\t\tBigInt(tokenCap),\n\t\t\t\tffi.ptr(numTokensOut),\n\t\t\t\tffi.ptr(textOut),\n\t\t\t\tBigInt(textCap),\n\t\t\t\tffi.ptr(drafterDrafted),\n\t\t\t\tffi.ptr(drafterAccepted),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc < 0) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_llm_stream_next rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\tconst n = Number(numTokensOut[0] ?? 0n);\n\t\t\tconst tokens = Array.from(tokensOut.subarray(0, Math.min(n, tokenCap)));\n\t\t\tconst nul = textOut.indexOf(0, 0);\n\t\t\tconst len = nul >= 0 ? nul : textCap;\n\t\t\tconst text = Buffer.from(\n\t\t\t\ttextOut.buffer,\n\t\t\t\ttextOut.byteOffset,\n\t\t\t\tlen,\n\t\t\t).toString(\"utf8\");\n\t\t\treturn {\n\t\t\t\ttokens,\n\t\t\t\ttext,\n\t\t\t\tdone: rc === 1,\n\t\t\t\tdrafterDrafted: drafterDrafted[0] ?? 0,\n\t\t\t\tdrafterAccepted: drafterAccepted[0] ?? 0,\n\t\t\t};\n\t\t},\n\n\t\tllmStreamCancel(stream) {\n\t\t\tconst cancel = loadedLib.symbols.eliza_inference_llm_stream_cancel;\n\t\t\tif (!llmStreamSymbolsAvailable || typeof cancel !== \"function\") {\n\t\t\t\t// Cancel is best-effort — a build without the symbol just means\n\t\t\t\t// the runtime cannot interrupt mid-step. The next `_next` call\n\t\t\t\t// will still finish normally; the caller drops the result.\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcancel(stream);\n\t\t},\n\n\t\tllmStreamSaveSlot({ stream, filename }) {\n\t\t\tconst save = loadedLib.symbols.eliza_inference_llm_stream_save_slot;\n\t\t\tif (!llmStreamSymbolsAvailable || typeof save !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_llm_stream_save_slot is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst fnameArg = cstr(filename);\n\t\t\tconst rc = save(stream, fnameArg.ptr, err.ptr);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_llm_stream_save_slot rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\tllmStreamRestoreSlot({ stream, filename }) {\n\t\t\tconst restore = loadedLib.symbols.eliza_inference_llm_stream_restore_slot;\n\t\t\tif (!llmStreamSymbolsAvailable || typeof restore !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_llm_stream_restore_slot is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst fnameArg = cstr(filename);\n\t\t\tconst rc = restore(stream, fnameArg.ptr, err.ptr);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_llm_stream_restore_slot rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\tllmStreamClose(stream) {\n\t\t\tloadedLib.symbols.eliza_inference_llm_stream_close?.(stream);\n\t\t},\n\n\t\t/* ---- Text embeddings (ABI v9) ------------------------------ */\n\n\t\tembedSupported(): boolean {\n\t\t\tconst probe = loadedLib.symbols.eliza_inference_embed_supported;\n\t\t\treturn (\n\t\t\t\ttextModalitiesSymbolsAvailable &&\n\t\t\t\ttypeof probe === \"function\" &&\n\t\t\t\tprobe() === 1\n\t\t\t);\n\t\t},\n\n\t\tembed({ ctx, text, pooling }) {\n\t\t\tconst embed = loadedLib.symbols.eliza_inference_embed;\n\t\t\tif (!textModalitiesSymbolsAvailable || typeof embed !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_embed is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst textArg = cstr(text);\n\t\t\t// The C side caps the write at n_embd. Hand it a generous buffer (the\n\t\t\t// largest dedicated-embedding dim we ship is 1024; 4096 covers any\n\t\t\t// decoder-as-embedder n_embd) and read back *out_dim for the real\n\t\t\t// length.\n\t\t\tconst cap = 4096;\n\t\t\tconst outEmbedding = new Float32Array(cap);\n\t\t\tconst outDim = new Int32Array(1);\n\t\t\tconst rc = embed(\n\t\t\t\tctx,\n\t\t\t\ttextArg.ptr,\n\t\t\t\tBigInt(textArg.bytes),\n\t\t\t\tpooling ?? ELIZA_POOLING_MEAN,\n\t\t\t\tffi.ptr(outEmbedding),\n\t\t\t\tBigInt(cap),\n\t\t\t\tffi.ptr(outDim),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ?? `[ffi-bindings] eliza_inference_embed rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\tconst dim = outDim[0] ?? 0;\n\t\t\tif (dim <= 0 || dim > cap) {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t`[ffi-bindings] eliza_inference_embed returned out-of-range n_embd=${dim}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn outEmbedding.slice(0, dim);\n\t\t},\n\n\t\t/* ---- mmproj vision describe (ABI v9) ----------------------- */\n\n\t\tvisionSupported(): boolean {\n\t\t\tconst probe = loadedLib.symbols.eliza_inference_vision_supported;\n\t\t\treturn (\n\t\t\t\ttextModalitiesSymbolsAvailable &&\n\t\t\t\ttypeof probe === \"function\" &&\n\t\t\t\tprobe() === 1\n\t\t\t);\n\t\t},\n\n\t\tdescribeImage({ ctx, imageBytes, mmprojPath, prompt, maxTextBytes }) {\n\t\t\tconst describe = loadedLib.symbols.eliza_inference_describe_image;\n\t\t\tif (!textModalitiesSymbolsAvailable || typeof describe !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_describe_image is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst cap = maxTextBytes ?? 4096;\n\t\t\tconst outText = new Uint8Array(cap);\n\t\t\tconst mmprojArg = cstr(mmprojPath);\n\t\t\tconst promptArg = cstr(prompt ?? null);\n\t\t\tconst rc = describe(\n\t\t\t\tctx,\n\t\t\t\tffi.ptr(imageBytes),\n\t\t\t\tBigInt(imageBytes.length),\n\t\t\t\tmmprojArg.ptr,\n\t\t\t\tpromptArg.ptr,\n\t\t\t\tffi.ptr(outText),\n\t\t\t\tBigInt(cap),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc < 0) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_describe_image rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\tconst nul = outText.indexOf(0, 0);\n\t\t\tconst len = nul >= 0 ? nul : rc;\n\t\t\treturn Buffer.from(outText.buffer, outText.byteOffset, len).toString(\n\t\t\t\t\"utf8\",\n\t\t\t);\n\t\t},\n\n\t\t/* ---- Streaming mmproj vision describe (ABI v13) ------------ */\n\n\t\tvisionStreamSupported(): boolean {\n\t\t\tconst probe = loadedLib.symbols.eliza_inference_vision_stream_supported;\n\t\t\treturn (\n\t\t\t\tvisionStreamSymbolsAvailable &&\n\t\t\t\ttypeof probe === \"function\" &&\n\t\t\t\tprobe() === 1\n\t\t\t);\n\t\t},\n\n\t\tdescribeImageStreamOpen({ ctx, imageBytes, mmprojPath, prompt }) {\n\t\t\tconst open = loadedLib.symbols.eliza_inference_describe_image_stream_open;\n\t\t\tif (!visionStreamSymbolsAvailable || typeof open !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_describe_image_stream_open is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst mmprojArg = cstr(mmprojPath);\n\t\t\tconst promptArg = cstr(prompt ?? null);\n\t\t\tconst handle = open(\n\t\t\t\tctx,\n\t\t\t\tffi.ptr(imageBytes),\n\t\t\t\tBigInt(imageBytes.length),\n\t\t\t\tmmprojArg.ptr,\n\t\t\t\tpromptArg.ptr,\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (isNullPointer(handle)) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_describe_image_stream_open returned NULL with no diagnostic\";\n\t\t\t\tthrow new VoiceLifecycleError(\"kernel-missing\", message);\n\t\t\t}\n\t\t\treturn handle as LlmStreamHandle;\n\t\t},\n\n\t\t/* ---- Tokenizer (ABI v9) ------------------------------------ */\n\n\t\ttokenizeSupported(): boolean {\n\t\t\tconst probe = loadedLib.symbols.eliza_inference_tokenize_supported;\n\t\t\treturn (\n\t\t\t\ttextModalitiesSymbolsAvailable &&\n\t\t\t\ttypeof probe === \"function\" &&\n\t\t\t\tprobe() === 1\n\t\t\t);\n\t\t},\n\n\t\ttokenize({ ctx, text, addSpecial, parseSpecial }) {\n\t\t\tconst tokenize = loadedLib.symbols.eliza_inference_tokenize;\n\t\t\tconst freeTokens = loadedLib.symbols.eliza_inference_free_tokens;\n\t\t\tif (\n\t\t\t\t!textModalitiesSymbolsAvailable ||\n\t\t\t\ttypeof tokenize !== \"function\" ||\n\t\t\t\ttypeof freeTokens !== \"function\"\n\t\t\t) {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_tokenize is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst textArg = cstr(text);\n\t\t\t// out_tokens is int** — give the library a slot to write the malloc'ed\n\t\t\t// pointer into, plus a size_t out for the count.\n\t\t\tconst outTokensPtr = new BigUint64Array(1);\n\t\t\tconst outN = new BigUint64Array(1);\n\t\t\tconst rc = tokenize(\n\t\t\t\tctx,\n\t\t\t\ttextArg.ptr,\n\t\t\t\tBigInt(textArg.bytes),\n\t\t\t\taddSpecial === false ? 0 : 1,\n\t\t\t\tparseSpecial === true ? 1 : 0,\n\t\t\t\tffi.ptr(outTokensPtr),\n\t\t\t\tffi.ptr(outN),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_tokenize rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\tconst n = Number(outN[0] ?? 0n);\n\t\t\tconst tokensRaw = outTokensPtr[0] ?? 0n;\n\t\t\tif (n === 0) {\n\t\t\t\t// Empty token sequence — the library still returns a non-NULL\n\t\t\t\t// 1-byte buffer to free.\n\t\t\t\tif (tokensRaw !== 0n) freeTokens(tokensRaw);\n\t\t\t\treturn new Int32Array(0);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst tokenBytes = n * 4;\n\t\t\t\tconst tokensPtr =\n\t\t\t\t\ttypeof tokensRaw === \"bigint\" ? Number(tokensRaw) : tokensRaw;\n\t\t\t\tconst view = ffi.toArrayBuffer(tokensPtr, 0, tokenBytes);\n\t\t\t\t// Copy out of the library's malloc'ed buffer before freeing.\n\t\t\t\treturn new Int32Array(new Uint8Array(view).slice(0, tokenBytes).buffer);\n\t\t\t} finally {\n\t\t\t\tfreeTokens(tokensRaw);\n\t\t\t}\n\t\t},\n\n\t\tdetokenize({ ctx, tokens, removeSpecial, unparseSpecial, maxTextBytes }) {\n\t\t\tconst detokenize = loadedLib.symbols.eliza_inference_detokenize;\n\t\t\tif (!textModalitiesSymbolsAvailable || typeof detokenize !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_detokenize is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst cap = maxTextBytes ?? 4096;\n\t\t\tconst outText = new Uint8Array(cap);\n\t\t\tconst rc = detokenize(\n\t\t\t\tctx,\n\t\t\t\tffi.ptr(tokens),\n\t\t\t\tBigInt(tokens.length),\n\t\t\t\tremoveSpecial === true ? 1 : 0,\n\t\t\t\tunparseSpecial === true ? 1 : 0,\n\t\t\t\tffi.ptr(outText),\n\t\t\t\tBigInt(cap),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc < 0) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_detokenize rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\tconst nul = outText.indexOf(0, 0);\n\t\t\tconst len = nul >= 0 ? nul : rc;\n\t\t\treturn Buffer.from(outText.buffer, outText.byteOffset, len).toString(\n\t\t\t\t\"utf8\",\n\t\t\t);\n\t\t},\n\n\t\t/* ---- End-of-turn scoring (ABI v11) ------------------------- */\n\n\t\teotSupported(): boolean {\n\t\t\tconst probe = loadedLib.symbols.eliza_inference_llm_eot_supported;\n\t\t\treturn (\n\t\t\t\teotSymbolsAvailable && typeof probe === \"function\" && probe() === 1\n\t\t\t);\n\t\t},\n\n\t\teotScore({ ctx, tokens, targetTokenId }) {\n\t\t\tconst score = loadedLib.symbols.eliza_inference_llm_eot_score;\n\t\t\tif (!eotSymbolsAvailable || typeof score !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_llm_eot_score is not exported by this build (pre-v11)\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (tokens.length === 0) {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_llm_eot_score requires a non-empty token sequence\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst outTargetProb = new Float32Array(1);\n\t\t\tconst outTopToken = new Int32Array(1);\n\t\t\tconst outTopProb = new Float32Array(1);\n\t\t\tconst rc = score(\n\t\t\t\tctx,\n\t\t\t\tffi.ptr(tokens),\n\t\t\t\tBigInt(tokens.length),\n\t\t\t\ttargetTokenId,\n\t\t\t\tffi.ptr(outTargetProb),\n\t\t\t\tffi.ptr(outTopToken),\n\t\t\t\tffi.ptr(outTopProb),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_llm_eot_score rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\ttargetProb: outTargetProb[0] ?? 0,\n\t\t\t\ttopToken: outTopToken[0] ?? -1,\n\t\t\t\ttopProb: outTopProb[0] ?? 0,\n\t\t\t};\n\t\t},\n\n\t\t/* ---- Kokoro TTS (ABI v10) ---------------------------------- */\n\n\t\tkokoroSupported(): boolean {\n\t\t\tconst probe = loadedLib.symbols.eliza_inference_kokoro_supported;\n\t\t\treturn (\n\t\t\t\tkokoroSymbolsAvailable && typeof probe === \"function\" && probe() === 1\n\t\t\t);\n\t\t},\n\n\t\tkokoroLoad({ ctx, ggufPath, voiceBinPath, styleDim }) {\n\t\t\tconst load = loadedLib.symbols.eliza_inference_kokoro_load;\n\t\t\tif (!kokoroSymbolsAvailable || typeof load !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_kokoro_load is not exported by this build (pre-v10; Eliza-1 Kokoro engine not linked)\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst ggufArg = cstr(ggufPath);\n\t\t\tconst voiceArg = cstr(voiceBinPath);\n\t\t\tconst rc = load(ctx, ggufArg.ptr, voiceArg.ptr, styleDim ?? 256, err.ptr);\n\t\t\tif (rc !== ELIZA_OK) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_kokoro_load rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t},\n\n\t\tkokoroSynthesize({ ctx, text, speed, maxSamples }) {\n\t\t\tconst synth = loadedLib.symbols.eliza_inference_kokoro_synthesize;\n\t\t\tif (!kokoroSymbolsAvailable || typeof synth !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_kokoro_synthesize is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst err = makeOutErr();\n\t\t\tconst textArg = cstr(text);\n\t\t\tconst outPcm = new Float32Array(maxSamples);\n\t\t\tconst rc = synth(\n\t\t\t\tctx,\n\t\t\t\ttextArg.ptr,\n\t\t\t\tBigInt(textArg.bytes),\n\t\t\t\tspeed ?? 1.0,\n\t\t\t\tffi.ptr(outPcm),\n\t\t\t\tBigInt(maxSamples),\n\t\t\t\terr.ptr,\n\t\t\t);\n\t\t\tif (rc < 0) {\n\t\t\t\tconst message =\n\t\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t\t`[ffi-bindings] eliza_inference_kokoro_synthesize rc=${rc}`;\n\t\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t\t}\n\t\t\treturn outPcm.slice(0, Math.min(rc, maxSamples));\n\t\t},\n\n\t\tkokoroSampleRate(ctx): number {\n\t\t\tconst rate = loadedLib.symbols.eliza_inference_kokoro_sample_rate;\n\t\t\tif (!kokoroSymbolsAvailable || typeof rate !== \"function\") {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\t\"kernel-missing\",\n\t\t\t\t\t\"[ffi-bindings] eliza_inference_kokoro_sample_rate is not exported by this build\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst rc = rate(ctx);\n\t\t\tif (rc < 0) {\n\t\t\t\tthrow new VoiceLifecycleError(\n\t\t\t\t\tfailureCode(rc),\n\t\t\t\t\t`[ffi-bindings] eliza_inference_kokoro_sample_rate rc=${rc} (no Kokoro model loaded on this ctx)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn rc;\n\t\t},\n\n\t\tclose(): void {\n\t\t\tloadedLib.close();\n\t\t},\n\t};\n\n\t/**\n\t * Convert a Bun-FFI pointer value (`unknown` per the lazy types) to the\n\t * bigint the marshalled config struct stores in its `const char *`\n\t * slots. NULL inputs translate to `0n`. Used by `llmStreamOpen` to\n\t * inline the cstr pointers into the config buffer.\n\t */\n\tfunction toPtrBigInt(value: unknown): bigint {\n\t\tif (value === null || value === undefined) return 0n;\n\t\tif (typeof value === \"bigint\") return value;\n\t\tif (typeof value === \"number\") return BigInt(value);\n\t\t// Bun returns its internal pointer object that coerces to bigint.\n\t\treturn BigInt(value as number);\n\t}\n\n\t/**\n\t * Shared body for `asr_stream_partial` / `asr_stream_finish` — both\n\t * have the same 6-arg shape (`stream, out_text, max_text_bytes,\n\t * out_tokens, io_n_tokens, out_error`). Token ids are read only when\n\t * the caller asks for them (`maxTokens > 0`); otherwise the\n\t * out_tokens / io_n_tokens pointers are NULL.\n\t */\n\tfunction readAsrStreamResult(\n\t\tlabel: string,\n\t\tfn: (\n\t\t\tstream: bigint,\n\t\t\toutText: unknown,\n\t\t\tmaxTextBytes: bigint | number,\n\t\t\toutTokens: unknown,\n\t\t\tioNTokens: unknown,\n\t\t\toutErr: unknown,\n\t\t) => number,\n\t\targs: { stream: bigint; maxTextBytes?: number; maxTokens?: number },\n\t): { partial: string; tokens?: number[] } {\n\t\tconst err = makeOutErr();\n\t\tconst textCap = args.maxTextBytes ?? 4096;\n\t\tconst outText = new Uint8Array(textCap);\n\t\tconst wantTokens = (args.maxTokens ?? 0) > 0;\n\t\tconst tokenCap = wantTokens ? (args.maxTokens as number) : 0;\n\t\tconst outTokens = wantTokens ? new Int32Array(tokenCap) : null;\n\t\tconst ioNTokens = wantTokens\n\t\t\t? new BigUint64Array([BigInt(tokenCap)])\n\t\t\t: null;\n\t\tconst rc = fn(\n\t\t\targs.stream,\n\t\t\tffi.ptr(outText),\n\t\t\tBigInt(textCap),\n\t\t\toutTokens ? ffi.ptr(outTokens) : null,\n\t\t\tioNTokens ? ffi.ptr(ioNTokens) : null,\n\t\t\terr.ptr,\n\t\t);\n\t\tif (rc < 0) {\n\t\t\tconst message =\n\t\t\t\ttakeError(err.buf) ??\n\t\t\t\t`[ffi-bindings] eliza_inference_asr_stream_${label} rc=${rc}`;\n\t\t\tthrow new VoiceLifecycleError(failureCode(rc), message);\n\t\t}\n\t\tconst nul = outText.indexOf(0, 0);\n\t\tconst len = nul >= 0 ? nul : rc;\n\t\tconst partial = Buffer.from(\n\t\t\toutText.buffer,\n\t\t\toutText.byteOffset,\n\t\t\tlen,\n\t\t).toString(\"utf8\");\n\t\tif (wantTokens && outTokens && ioNTokens) {\n\t\t\tconst n = Number(ioNTokens[0] ?? 0n);\n\t\t\tconst tokens = Array.from(outTokens.subarray(0, Math.min(n, tokenCap)));\n\t\t\treturn { partial, tokens };\n\t\t}\n\t\treturn { partial };\n\t}\n}\n\nfunction formatFfiError(err: unknown): string {\n\tif (err instanceof Error) {\n\t\treturn err.message;\n\t}\n\treturn String(err);\n}\n\n/**\n * Read an `EliVerifierEvent` (see `ffi.h`) from a C struct pointer.\n * Layout on 64-bit (8-byte aligned, default packing):\n * off 0 : const int* accepted_token_ids (8)\n * off 8 : size_t n_accepted (8)\n * off 16 : int rejected_from (4)\n * off 20 : int rejected_to (4)\n * off 24 : const int* corrected_token_ids (8)\n * off 32 : size_t n_corrected (8)\n */\nfunction readVerifierEvent(\n\tevPtr: bigint,\n\tffi: BunFfiModule,\n): NativeVerifierEvent {\n\tconst acceptedPtr = ffi.read.ptr(evPtr, 0);\n\tconst nAccepted = Number(ffi.read.u64(evPtr, 8));\n\tconst rejectedFrom = ffi.read.i32(evPtr, 16);\n\tconst rejectedTo = ffi.read.i32(evPtr, 20);\n\tconst correctedPtr = ffi.read.ptr(evPtr, 24);\n\tconst nCorrected = Number(ffi.read.u64(evPtr, 32));\n\treturn {\n\t\tacceptedTokenIds: readInt32Array(acceptedPtr, nAccepted, ffi),\n\t\trejectedFrom,\n\t\trejectedTo,\n\t\tcorrectedTokenIds: readInt32Array(correctedPtr, nCorrected, ffi),\n\t};\n}\n\nfunction readInt32Array(\n\tptr: bigint,\n\tcount: number,\n\tffi: BunFfiModule,\n): number[] {\n\tif (ptr === 0n || count <= 0) return [];\n\t// Copy out — the array is the library's, valid only for the callback.\n\tconst view = new Int32Array(ffi.toArrayBuffer(ptr, 0, count * 4).slice(0));\n\treturn Array.from(view);\n}\n\n/**\n * Decode a `T.cstring` return value (Bun returns these as either a\n * lazy string-like object with `toString()` or a JS string depending\n * on version). Wrap so the caller never has to branch.\n */\nfunction readCString(value: unknown, ffi: BunFfiModule): string {\n\tif (typeof value === \"string\") return value;\n\tif (value === null || value === undefined) return \"\";\n\tif (typeof value === \"object\" && value !== null && \"toString\" in value) {\n\t\treturn (value as { toString(): string }).toString();\n\t}\n\tif (typeof value === \"number\" || typeof value === \"bigint\") {\n\t\treturn new ffi.CString(value).toString();\n\t}\n\treturn String(value);\n}\n",
10
+ "/**\n * Desktop production `FfiBackendRuntime` over the FUSED `libelizainference` —\n * the SOLE desktop text runtime now that libllama has been retired.\n *\n * Desktop text generation runs through the fused library: the same\n * `eliza_inference_llm_stream_*` ABI (v9) the voice subsystem already loads,\n * so text + voice share one native lib, one GGML pin, and one resident text\n * model.\n *\n * - The fused lib's `eliza_inference_llm_stream_open` loads the bundle's text\n * GGUF (`<bundleRoot>/text/*.gguf`) and applies MTP speculative\n * decoding + KV-cache quant + per-load GPU layers natively (ABI v9). The\n * path is gated on the capability probes\n * (`llmStreamSupported && llmMtpSupported && llmKvQuantSupported`).\n * - A fused lib that lacks MTP / KV-quant / native tokenize is REFUSED by\n * `supported()` → the engine raises LocalInferenceUnavailable. There is no\n * libllama fallback and never an unoptimized fused loop.\n *\n * Tokenization runs over the fused handle's resident text vocab via ABI-v9\n * `eliza_inference_tokenize`: the fused `create()` + first `llmStreamOpen`\n * already made the text vocab resident, so no second model is loaded.\n * `tokenizeSupported()` gates this; a pre-v9 lib without the symbol is refused.\n *\n * Lifecycle: one fused context per loaded model; `acquire()` builds it,\n * `release()` tears it down. A throwing native free poisons the runtime so no\n * new allocation happens over leaked resources.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport { resolveStateDir } from \"@elizaos/core\";\n\nimport type { BackendPlan } from \"./backend\";\nimport type {\n\tFfiBackendRuntime,\n\tFfiBackendSession,\n} from \"./ffi-streaming-backend\";\nimport { FfiStreamingRunner } from \"./ffi-streaming-runner\";\nimport { wrapElizaInferenceFfi } from \"./llm-streaming-binding\";\nimport type { ElizaInferenceContextHandle } from \"./voice/ffi-bindings\";\nimport {\n\ttype ElizaInferenceFfi,\n\tloadElizaInferenceFfi,\n} from \"./voice/ffi-bindings\";\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"Aborted\", \"AbortError\");\n}\n\n/**\n * Candidate filenames for the fused library, per platform. Mirrors\n * `samantha-preset-regenerator.ts::libraryFilenames` so the runtime and the\n * voice regenerator resolve the same artifact.\n */\nfunction fusedLibraryFilenames(): string[] {\n\tif (process.platform === \"darwin\") return [\"libelizainference.dylib\"];\n\tif (process.platform === \"win32\") {\n\t\treturn [\"elizainference.dll\", \"libelizainference.dll\"];\n\t}\n\treturn [\"libelizainference.so\"];\n}\n\n/**\n * Resolve the on-disk path to the fused `libelizainference`. Precedence:\n * 1. `ELIZA_INFERENCE_LIBRARY` — an explicit absolute path.\n * 2. `<bundleRoot>/lib/<name>` — the bundle-local lib.\n * 3. `ELIZA_INFERENCE_LIB_DIR/<name>` — an explicit lib directory.\n * 4. `<stateDir>/local-inference/lib/<name>` — the default staging dir written\n * by `scripts/stage-desktop-fused-lib.mjs`, so a staged desktop build is\n * found with no env wiring.\n * Returns null when none of the candidates exist on disk — `supported()` then\n * reports unavailable and the engine raises LocalInferenceUnavailable.\n */\nexport function resolveFusedLibraryPath(\n\tbundleRoot: string | null,\n\tenv: NodeJS.ProcessEnv = process.env,\n): string | null {\n\tconst exact = env.ELIZA_INFERENCE_LIBRARY?.trim();\n\tif (exact && fs.existsSync(exact)) return exact;\n\tconst dirs = [\n\t\tbundleRoot ? path.join(bundleRoot, \"lib\") : null,\n\t\texact ? path.dirname(exact) : null,\n\t\tenv.ELIZA_INFERENCE_LIB_DIR?.trim() || null,\n\t\tpath.join(resolveStateDir(env), \"local-inference\", \"lib\"),\n\t].filter((dir): dir is string => Boolean(dir));\n\tfor (const dir of dirs) {\n\t\tfor (const name of fusedLibraryFilenames()) {\n\t\t\tconst candidate = path.join(dir, name);\n\t\t\tif (fs.existsSync(candidate)) return candidate;\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Derive the bundle root (the dir the fused `create()` anchors at) from a\n * BackendPlan. Eliza-1 bundles set `overrides.bundleRoot` explicitly; otherwise\n * the GGUF lives at `<bundleRoot>/text/<file>.gguf`, so the bundle root is\n * `dirname(dirname(modelPath))`.\n */\nfunction bundleRootForPlan(plan: BackendPlan): string {\n\tif (plan.overrides?.bundleRoot) return plan.overrides.bundleRoot;\n\treturn path.dirname(path.dirname(plan.modelPath));\n}\n\ninterface ActiveFusedSession {\n\tffi: ElizaInferenceFfi;\n\tctx: ElizaInferenceContextHandle;\n\tsession: FfiBackendSession;\n}\n\nexport class DesktopFusedFfiBackendRuntime implements FfiBackendRuntime {\n\tprivate active: ActiveFusedSession | null = null;\n\tprivate poisonedError: Error | null = null;\n\t/** Cached `supported()` result so the engine gate and the dispatcher agree. */\n\tprivate supportedCache: boolean | null = null;\n\n\t/**\n\t * Viable only when:\n\t * - bun:ffi resolves on the current runtime,\n\t * - the fused dylib is present AND reports ABI-v9 capability: the\n\t * streaming-LLM surface, MTP, KV-cache quant, AND native\n\t * tokenization (`eliza_inference_tokenize`).\n\t * A pre-v9 fused lib reports the probes as unsupported → refused, and the\n\t * engine raises LocalInferenceUnavailable. libllama has been retired; there\n\t * is no fallback runtime and no tokenizer sidecar.\n\t */\n\tsupported(): boolean {\n\t\tif (this.supportedCache !== null) return this.supportedCache;\n\t\tthis.supportedCache = this.computeSupported();\n\t\treturn this.supportedCache;\n\t}\n\n\t/** Clear the cached `supported()` result (tests / lib swaps). */\n\tresetSupportedCache(): void {\n\t\tthis.supportedCache = null;\n\t}\n\n\tprivate computeSupported(): boolean {\n\t\ttry {\n\t\t\trequire.resolve(\"bun:ffi\");\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t\tconst libPath = resolveFusedLibraryPath(null);\n\t\tif (!libPath) return false;\n\t\t// Load the lib and probe the v8 LLM capabilities. This dlopen is cheap (no\n\t\t// model load); we close it immediately after probing.\n\t\tlet ffi: ElizaInferenceFfi | null = null;\n\t\ttry {\n\t\t\tffi = loadElizaInferenceFfi(libPath);\n\t\t\tconst llmOk =\n\t\t\t\ttypeof ffi.llmStreamSupported === \"function\" &&\n\t\t\t\tffi.llmStreamSupported() === true &&\n\t\t\t\ttypeof ffi.llmMtpSupported === \"function\" &&\n\t\t\t\tffi.llmMtpSupported() === true &&\n\t\t\t\ttypeof ffi.llmKvQuantSupported === \"function\" &&\n\t\t\t\tffi.llmKvQuantSupported() === true;\n\t\t\tif (!llmOk) return false;\n\t\t\t// Native tokenization over the fused handle's resident text vocab\n\t\t\t// (ABI v9) is required: libllama has been retired, so there is no\n\t\t\t// tokenizer sidecar. A pre-v9 fused lib without `eliza_inference_tokenize`\n\t\t\t// is refused → the engine raises LocalInferenceUnavailable.\n\t\t\tconst fusedTokenize =\n\t\t\t\ttypeof ffi.tokenizeSupported === \"function\" &&\n\t\t\t\tffi.tokenizeSupported() === true;\n\t\t\tif (!fusedTokenize) return false;\n\t\t\treturn true;\n\t\t} catch {\n\t\t\t// dlopen / ABI-mismatch / non-Bun runtime → not viable.\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tffi?.close();\n\t\t}\n\t}\n\n\tasync acquire(plan: BackendPlan): Promise<FfiBackendSession> {\n\t\tif (this.poisonedError) {\n\t\t\tthrow new Error(\n\t\t\t\t`[desktop-fused-ffi-runtime] native cleanup previously failed; restart required before acquiring a new session: ${this.poisonedError.message}`,\n\t\t\t);\n\t\t}\n\t\tif (this.active) {\n\t\t\tthrow new Error(\n\t\t\t\t\"[desktop-fused-ffi-runtime] acquire() called with a live session; release() first\",\n\t\t\t);\n\t\t}\n\t\tconst bundleRoot = bundleRootForPlan(plan);\n\t\tconst libPath = resolveFusedLibraryPath(bundleRoot);\n\t\tif (!libPath) {\n\t\t\tthrow new Error(\n\t\t\t\t`[desktop-fused-ffi-runtime] fused libelizainference not found for bundle ${bundleRoot}. ` +\n\t\t\t\t\t\"Dispatcher should not have routed here; check supported().\",\n\t\t\t);\n\t\t}\n\n\t\t// 1. Fused lib + bundle context for the generation path. `create()`\n\t\t// anchors at the bundle root; the first `llmStreamOpen` loads\n\t\t// `<bundleRoot>/text/*.gguf` and applies gpuLayers + KV-cache quant\n\t\t// from the session config (threaded via loadConfig below).\n\t\tconst ffi = loadElizaInferenceFfi(libPath);\n\t\tlet ctx: ElizaInferenceContextHandle;\n\t\ttry {\n\t\t\tctx = ffi.create(bundleRoot);\n\t\t} catch (err) {\n\t\t\tffi.close();\n\t\t\tthrow err;\n\t\t}\n\n\t\t// 2. Tokenization over the fused handle's resident text vocab via ABI-v9\n\t\t// `eliza_inference_tokenize` — no second model load. `supported()`\n\t\t// already refused a pre-v9 lib, so the symbol is present here; this\n\t\t// guard turns any surprise absence into a loud failure (the session is\n\t\t// torn down) rather than a silent tokenizer gap. libllama is retired.\n\t\tconst fusedTokenizeFn = ffi.tokenize;\n\t\tif (\n\t\t\ttypeof ffi.tokenizeSupported !== \"function\" ||\n\t\t\tffi.tokenizeSupported() !== true ||\n\t\t\ttypeof fusedTokenizeFn !== \"function\"\n\t\t) {\n\t\t\tffi.destroy(ctx);\n\t\t\tffi.close();\n\t\t\tthrow new Error(\n\t\t\t\t\"[desktop-fused-ffi-runtime] fused lib lacks eliza_inference_tokenize (pre-v9). \" +\n\t\t\t\t\t\"libllama has been retired; rebuild the fused lib with the v9 tokenizer ABI.\",\n\t\t\t);\n\t\t}\n\t\tconst tokenizeFn = (prompt: string): Int32Array =>\n\t\t\tfusedTokenizeFn({ ctx, text: prompt });\n\n\t\tconst binding = wrapElizaInferenceFfi(ffi);\n\t\tconst runner = new FfiStreamingRunner(binding, ctx);\n\t\tconst overrides = plan.overrides;\n\t\tconst session: FfiBackendSession = {\n\t\t\tbinding,\n\t\t\tctx,\n\t\t\trunner,\n\t\t\ttokenize: (prompt) => tokenizeFn(prompt),\n\t\t\tmtp: plan.catalog?.runtime?.mtp ?? null,\n\t\t\tdraftModelPath: overrides?.draftModelPath ?? null,\n\t\t\tmmprojPath: overrides?.mmprojPath ?? null,\n\t\t\t// The fused path applies these at its first `llmStreamOpen`:\n\t\t\t// context size, gpuLayers, and KV-cache quant types from the\n\t\t\t// session config.\n\t\t\tloadConfig: {\n\t\t\t\tcontextSize:\n\t\t\t\t\ttypeof overrides?.contextSize === \"number\"\n\t\t\t\t\t\t? overrides.contextSize\n\t\t\t\t\t\t: undefined,\n\t\t\t\tgpuLayers:\n\t\t\t\t\ttypeof overrides?.gpuLayers === \"number\"\n\t\t\t\t\t\t? overrides.gpuLayers\n\t\t\t\t\t\t: undefined,\n\t\t\t\tcacheTypeK: overrides?.cacheTypeK ?? null,\n\t\t\t\tcacheTypeV: overrides?.cacheTypeV ?? null,\n\t\t\t},\n\t\t};\n\t\tthis.active = { ffi, ctx, session };\n\t\treturn session;\n\t}\n\n\tparallelSlots(): number {\n\t\t// The fused runtime holds one resident text context per loaded model;\n\t\t// multi-slot parallelism is not exposed by the fused ABI.\n\t\treturn 1;\n\t}\n\n\t/**\n\t * Whether the LIVE session can describe images through the fused\n\t * `eliza_inference_describe_image`. Mirrors the FfiStreamingBackend gate:\n\t * true only when a session is bound and the fused lib exposes vision.\n\t */\n\tvisionSupported(): boolean {\n\t\tif (!this.active) return false;\n\t\treturn (\n\t\t\ttypeof this.active.ffi.visionSupported === \"function\" &&\n\t\t\tthis.active.ffi.visionSupported() === true &&\n\t\t\ttypeof this.active.ffi.describeImage === \"function\"\n\t\t);\n\t}\n\n\t/**\n\t * Whether the LIVE session can STREAM a vision describe token-by-token\n\t * through `eliza_inference_describe_image_stream_open` + the existing\n\t * `llmStreamNext` loop (ABI v13). A <=v12 lib reports false and the handler\n\t * uses the buffered one-shot `describeImage` path.\n\t */\n\tvisionStreamSupported(): boolean {\n\t\tif (!this.active) return false;\n\t\tconst { ffi } = this.active;\n\t\treturn (\n\t\t\ttypeof ffi.visionStreamSupported === \"function\" &&\n\t\t\tffi.visionStreamSupported() === true &&\n\t\t\ttypeof ffi.describeImageStreamOpen === \"function\" &&\n\t\t\ttypeof ffi.llmStreamNext === \"function\" &&\n\t\t\ttypeof ffi.llmStreamClose === \"function\"\n\t\t);\n\t}\n\n\t/**\n\t * Vision describe through the fused mmproj path. Reuses the mtmd machinery\n\t * linked for ASR over the bundle's text model + the passed mmproj projector.\n\t * The `FfiStreamingBackend` forwards `describeImage`/`visionSupported` to this\n\t * runtime by duck-typing.\n\t *\n\t * When `onTextChunk` is supplied AND the fused lib exposes ABI-v13 streaming\n\t * vision, the description is decoded token-by-token: `describeImageStreamOpen`\n\t * primes a stream with the image+prompt KV and the EXISTING `llmStreamNext`\n\t * loop pulls tokens — the same machinery that streams chat text, so vision\n\t * flows into the dashboard through one pipe. Otherwise it falls back to the\n\t * buffered one-shot `eliza_inference_describe_image`.\n\t */\n\tasync describeImage(args: {\n\t\timageBytes: Uint8Array;\n\t\tmmprojPath: string;\n\t\tprompt?: string;\n\t\tmaxTokens?: number;\n\t\ttemperature?: number;\n\t\tsignal?: AbortSignal;\n\t\tonTextChunk?: (chunk: string) => void | Promise<void>;\n\t\tmaxTokensPerStep?: number;\n\t}): Promise<{ text: string; projectorMs?: number; decodeMs?: number }> {\n\t\tif (!this.active) {\n\t\t\tthrow new Error(\n\t\t\t\t\"[desktop-fused-ffi-runtime] describeImage before acquire — no session\",\n\t\t\t);\n\t\t}\n\t\tconst { ffi, ctx } = this.active;\n\t\tif (\n\t\t\ttypeof ffi.visionSupported !== \"function\" ||\n\t\t\tffi.visionSupported() !== true ||\n\t\t\ttypeof ffi.describeImage !== \"function\"\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"[desktop-fused-ffi-runtime] describeImage: fused lib was built without \" +\n\t\t\t\t\t\"vision (eliza_inference_vision_supported() == 0). Rebuild the fused \" +\n\t\t\t\t\t\"lib with -DELIZA_ENABLE_VISION=ON (verify-fused-symbols requires it).\",\n\t\t\t);\n\t\t}\n\n\t\t// Token-by-token streaming path (ABI v13): open a vision stream and drive\n\t\t// the shared `llmStreamNext` loop, surfacing each decoded piece through\n\t\t// `onTextChunk` so the description renders as it generates.\n\t\tif (\n\t\t\ttypeof args.onTextChunk === \"function\" &&\n\t\t\tthis.visionStreamSupported() &&\n\t\t\ttypeof ffi.describeImageStreamOpen === \"function\" &&\n\t\t\ttypeof ffi.llmStreamNext === \"function\" &&\n\t\t\ttypeof ffi.llmStreamClose === \"function\"\n\t\t) {\n\t\t\tthrowIfAborted(args.signal);\n\t\t\tconst startedAt = Date.now();\n\t\t\tconst stream = ffi.describeImageStreamOpen({\n\t\t\t\tctx,\n\t\t\t\timageBytes: args.imageBytes,\n\t\t\t\tmmprojPath: args.mmprojPath,\n\t\t\t\tprompt: args.prompt,\n\t\t\t});\n\t\t\tlet full = \"\";\n\t\t\tlet generated = 0;\n\t\t\t// JS-side token budget: the native ELIZA_VISION_MAX_TOKENS env does not\n\t\t\t// reliably reach the loaded DLL's getenv across runtimes, so cap here.\n\t\t\tconst tokenBudget =\n\t\t\t\ttypeof args.maxTokens === \"number\" && args.maxTokens > 0\n\t\t\t\t\t? args.maxTokens\n\t\t\t\t\t: 256;\n\t\t\ttry {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tif (args.signal?.aborted) {\n\t\t\t\t\t\tffi.llmStreamCancel?.(stream);\n\t\t\t\t\t\tthrowIfAborted(args.signal);\n\t\t\t\t\t}\n\t\t\t\t\tconst step = ffi.llmStreamNext({\n\t\t\t\t\t\tstream,\n\t\t\t\t\t\t// Fine-grained by default so the description renders token-by-token\n\t\t\t\t\t\t// in the dashboard rather than in coarse ~32-token jumps (matches\n\t\t\t\t\t\t// the tuned chat default). Callers may override per request.\n\t\t\t\t\t\tmaxTokensPerStep: args.maxTokensPerStep ?? 8,\n\t\t\t\t\t});\n\t\t\t\t\tif (step.text.length > 0) {\n\t\t\t\t\t\tfull += step.text;\n\t\t\t\t\t\tawait args.onTextChunk(step.text);\n\t\t\t\t\t}\n\t\t\t\t\tgenerated += step.tokens.length;\n\t\t\t\t\tif (step.done || generated >= tokenBudget) break;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tffi.llmStreamClose(stream);\n\t\t\t}\n\t\t\treturn { text: full, decodeMs: Date.now() - startedAt };\n\t\t}\n\n\t\tconst startedAt = Date.now();\n\t\tconst text = ffi.describeImage({\n\t\t\tctx,\n\t\t\timageBytes: args.imageBytes,\n\t\t\tmmprojPath: args.mmprojPath,\n\t\t\tprompt: args.prompt,\n\t\t});\n\t\treturn { text, decodeMs: Date.now() - startedAt };\n\t}\n\n\tasync release(): Promise<void> {\n\t\tif (!this.active) return;\n\t\tconst { ffi, ctx } = this.active;\n\t\t// Free the native handles. A throwing free poisons the runtime so a new\n\t\t// model cannot be allocated over leaked resources. Clear `active` in the\n\t\t// finally so a throwing free can't wedge the live-session guard.\n\t\ttry {\n\t\t\tffi.destroy(ctx);\n\t\t\tffi.close();\n\t\t} catch (err) {\n\t\t\tthis.poisonedError = err instanceof Error ? err : new Error(String(err));\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tthis.active = null;\n\t\t}\n\t}\n}\n\n/**\n * Process singleton — the engine wires this as the sole `FfiBackendRuntime` for\n * the dispatcher's `\"llama-cpp\"` slot. The ABI-v9 capability probes in\n * `supported()` gate whether the fused lib serves text at all.\n */\nexport const desktopFusedFfiBackendRuntime =\n\tnew DesktopFusedFfiBackendRuntime();\n",
11
+ "/**\n * pyannote-segmentation-3.0 shared types and pure segmentation logic.\n *\n * Diarization runs EXCLUSIVELY through the fused `libelizainference`\n * `eliza_inference_diariz_*` ABI (`FusedDiarizer` in `diarizer-fused.ts`).\n * The standalone `libvoice_classifier` binding has been removed — there is one\n * on-device voice runtime.\n *\n * This file holds the shared types (`Diarizer`, `LocalSpeakerSegment`,\n * `DiarizerOutput`), the model-id / window constants, the structured\n * `DiarizerUnavailableError`, and the pure `classifyFramesToSegments` reducer\n * the fused diarizer feeds its per-frame labels through.\n */\n\nexport const PYANNOTE_SEGMENTATION_3_INT8_MODEL_ID =\n\t\"pyannote-segmentation-3.0-int8\" as const;\nexport const PYANNOTE_SEGMENTATION_3_FP32_MODEL_ID =\n\t\"pyannote-segmentation-3.0-fp32\" as const;\nexport type PyannoteDiarizerModelId =\n\t| typeof PYANNOTE_SEGMENTATION_3_INT8_MODEL_ID\n\t| typeof PYANNOTE_SEGMENTATION_3_FP32_MODEL_ID;\n\n/** pyannote 3.0 segmentation window length (seconds) — model-fixed. */\nexport const PYANNOTE_WINDOW_SECONDS = 5;\n/** Required mono sample rate (matches upstream training config). */\nexport const PYANNOTE_SAMPLE_RATE = 16_000;\n/** Number of output frames per 5 s window (= 293 in the upstream export). */\nexport const PYANNOTE_FRAMES_PER_WINDOW = 293;\n/** Per-frame stride in milliseconds (5_000ms / 293 frames ≈ 17.06 ms). */\nexport const PYANNOTE_FRAME_STRIDE_MS =\n\t(1_000 * PYANNOTE_WINDOW_SECONDS) / PYANNOTE_FRAMES_PER_WINDOW;\n/** Output class count — 3 single + 3 overlap + 1 silence = 7. */\nexport const PYANNOTE_CLASS_COUNT = 7;\n\n/**\n * Powerset mapping of pyannote-3 segmentation classes. Each class is\n * the set of local speaker indices active in that frame. Class 0 is the\n * silence/no-speaker frame. This matches the upstream `Powerset` head\n * with `max_speakers_per_chunk=3, max_speakers_per_frame=2`.\n */\nexport const PYANNOTE_CLASS_TO_SPEAKERS: ReadonlyArray<ReadonlyArray<number>> =\n\t[\n\t\t[], // 0: silence\n\t\t[0], // 1: speaker 0 only\n\t\t[1], // 2: speaker 1 only\n\t\t[2], // 3: speaker 2 only\n\t\t[0, 1], // 4: speakers 0+1 overlap\n\t\t[0, 2], // 5: speakers 0+2 overlap\n\t\t[1, 2], // 6: speakers 1+2 overlap\n\t];\n\n/** Thrown when the diarizer cannot be constructed. */\nexport class DiarizerUnavailableError extends Error {\n\treadonly code:\n\t\t| \"ort-missing\"\n\t\t| \"native-missing\"\n\t\t| \"library-missing\"\n\t\t| \"model-missing\"\n\t\t| \"model-unavailable\"\n\t\t| \"model-load-failed\"\n\t\t| \"model-shape-mismatch\"\n\t\t| \"forward-not-implemented\"\n\t\t| \"invalid-input\";\n\tconstructor(code: DiarizerUnavailableError[\"code\"], message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"DiarizerUnavailableError\";\n\t\tthis.code = code;\n\t}\n}\n\n/**\n * One speaker-tagged span within a diarized window. `localSpeakerId` is\n * **window-local** (0..2): the same physical speaker gets different\n * local ids in different windows. The profile store re-clusters local\n * ids into stable identities via the WeSpeaker embedding cosine.\n */\nexport interface LocalSpeakerSegment {\n\tstartMs: number;\n\tendMs: number;\n\tlocalSpeakerId: number;\n\t/** Best class confidence over the span (max softmax). */\n\tconfidence: number;\n\t/** True if the span contains any overlap-class frames. */\n\thasOverlap: boolean;\n}\n\nexport interface DiarizerOutput {\n\tsegments: LocalSpeakerSegment[];\n\t/** Number of distinct local speakers observed in the window. */\n\tlocalSpeakerCount: number;\n\t/** Total speech (any-speaker) duration in milliseconds. */\n\tspeechMs: number;\n}\n\nexport interface Diarizer {\n\treadonly modelId: PyannoteDiarizerModelId;\n\treadonly sampleRate: number;\n\t/** Process one ~5 s window of PCM. */\n\tdiarizeWindow(pcm: Float32Array): Promise<DiarizerOutput>;\n\tdispose(): Promise<void>;\n}\n\n/** Numerically-stable softmax over the last axis. */\nfunction softmax(row: Float32Array): Float32Array {\n\tlet max = -Infinity;\n\tfor (let i = 0; i < row.length; i += 1) {\n\t\tif (row[i] > max) max = row[i];\n\t}\n\tconst out = new Float32Array(row.length);\n\tlet sum = 0;\n\tfor (let i = 0; i < row.length; i += 1) {\n\t\tout[i] = Math.exp(row[i] - max);\n\t\tsum += out[i];\n\t}\n\tif (sum === 0) return out;\n\tfor (let i = 0; i < row.length; i += 1) out[i] /= sum;\n\treturn out;\n}\n\n/**\n * Reduce a per-frame class probability tensor into one segment per\n * (local speaker × contiguous frame run). Frames where the silence\n * class wins are excluded; frames in overlap classes contribute to\n * **all** speakers in that class.\n */\nexport function classifyFramesToSegments(\n\tclassProbs: Float32Array,\n\tframes: number,\n\tclassCount: number,\n\tstartMs: number,\n\tframeStrideMs: number,\n): DiarizerOutput {\n\tif (classProbs.length !== frames * classCount) {\n\t\tthrow new DiarizerUnavailableError(\n\t\t\t\"model-load-failed\",\n\t\t\t`[pyannote] frame×class tensor mismatch: have ${classProbs.length}, expected ${frames * classCount}`,\n\t\t);\n\t}\n\ttype Active = {\n\t\tstartFrame: number;\n\t\tendFrame: number;\n\t\tconfSum: number;\n\t\tcount: number;\n\t\thasOverlap: boolean;\n\t};\n\t// Per-speaker active runs. The pyannote-3 head supports 3 speakers.\n\tconst open = new Map<number, Active>();\n\tconst closed: Array<Active & { speakerId: number }> = [];\n\n\tlet speechFrames = 0;\n\n\tfor (let f = 0; f < frames; f += 1) {\n\t\tconst offset = f * classCount;\n\t\tconst row = classProbs.subarray(offset, offset + classCount);\n\t\tconst probs = softmax(row);\n\t\t// Pick winning class.\n\t\tlet winner = 0;\n\t\tlet winnerProb = probs[0];\n\t\tfor (let c = 1; c < classCount; c += 1) {\n\t\t\tif (probs[c] > winnerProb) {\n\t\t\t\twinner = c;\n\t\t\t\twinnerProb = probs[c];\n\t\t\t}\n\t\t}\n\t\tconst activeSpeakers = PYANNOTE_CLASS_TO_SPEAKERS[winner] ?? [];\n\t\tconst isOverlap = activeSpeakers.length > 1;\n\t\tif (activeSpeakers.length > 0) speechFrames += 1;\n\n\t\t// Close runs for speakers not active this frame.\n\t\tfor (const [sid, run] of open.entries()) {\n\t\t\tif (!activeSpeakers.includes(sid)) {\n\t\t\t\tclosed.push({ ...run, speakerId: sid });\n\t\t\t\topen.delete(sid);\n\t\t\t}\n\t\t}\n\t\t// Open / extend runs for active speakers.\n\t\tfor (const sid of activeSpeakers) {\n\t\t\tconst existing = open.get(sid);\n\t\t\tif (existing) {\n\t\t\t\texisting.endFrame = f + 1;\n\t\t\t\texisting.confSum += winnerProb;\n\t\t\t\texisting.count += 1;\n\t\t\t\texisting.hasOverlap = existing.hasOverlap || isOverlap;\n\t\t\t} else {\n\t\t\t\topen.set(sid, {\n\t\t\t\t\tstartFrame: f,\n\t\t\t\t\tendFrame: f + 1,\n\t\t\t\t\tconfSum: winnerProb,\n\t\t\t\t\tcount: 1,\n\t\t\t\t\thasOverlap: isOverlap,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\t// Flush remaining open runs.\n\tfor (const [sid, run] of open.entries()) {\n\t\tclosed.push({ ...run, speakerId: sid });\n\t}\n\n\tconst segments = closed\n\t\t.map<LocalSpeakerSegment>((run) => ({\n\t\t\tstartMs: Math.round(startMs + run.startFrame * frameStrideMs),\n\t\t\tendMs: Math.round(startMs + run.endFrame * frameStrideMs),\n\t\t\tlocalSpeakerId: run.speakerId,\n\t\t\tconfidence: run.count > 0 ? run.confSum / run.count : 0,\n\t\t\thasOverlap: run.hasOverlap,\n\t\t}))\n\t\t.sort((a, b) =>\n\t\t\ta.startMs !== b.startMs ? a.startMs - b.startMs : a.endMs - b.endMs,\n\t\t);\n\n\tconst localSpeakers = new Set(segments.map((s) => s.localSpeakerId));\n\treturn {\n\t\tsegments,\n\t\tlocalSpeakerCount: localSpeakers.size,\n\t\tspeechMs: Math.round(speechFrames * frameStrideMs),\n\t};\n}\n",
12
+ "/**\n * pyannote-segmentation-3.0 diarizer — fused `libelizainference` binding\n * (ABI v6).\n *\n * Drives the native pyannote diarizer through the single fused-FFI\n * `libelizainference` handle (the merged llama.cpp fork — see\n * `plugins/plugin-local-inference/native/CLAUDE.md` §1) via the\n * `eliza_inference_diariz_*` ABI. This is the SOLE on-device diarizer runtime —\n * the same `ffi`/`ctx` pair powers VAD / wake-word / speaker / TTS / ASR.\n *\n * The native call returns a per-frame powerset-label sequence (293 int8\n * labels per 5 s window, each in `[0, 7)`). Agglomerative clustering and the\n * frame→segment reduction stay JS-side: this class one-hots the labels and\n * feeds them through the shared pure `classifyFramesToSegments` reducer.\n *\n * No silent fallback: when the fused build does not export the diarizer ABI\n * (`eliza_inference_diariz_supported() == 0`) `load()` throws a structured\n * `DiarizerUnavailableError` (AGENTS.md §3 — never fabricate a label\n * sequence, no standalone-lib fallback).\n */\n\nimport type {\n\tElizaInferenceContextHandle,\n\tElizaInferenceFfi,\n\tNativeDiarizHandle,\n} from \"../ffi-bindings\";\nimport {\n\tclassifyFramesToSegments,\n\ttype Diarizer,\n\ttype DiarizerOutput,\n\tDiarizerUnavailableError,\n\tPYANNOTE_CLASS_COUNT,\n\tPYANNOTE_FRAME_STRIDE_MS,\n\tPYANNOTE_SAMPLE_RATE,\n\tPYANNOTE_SEGMENTATION_3_INT8_MODEL_ID,\n\ttype PyannoteDiarizerModelId,\n} from \"./diarizer\";\n\nexport interface FusedDiarizerOptions {\n\tffi: ElizaInferenceFfi;\n\tctx: ElizaInferenceContextHandle | (() => ElizaInferenceContextHandle);\n\t/**\n\t * Optional explicit pyannote GGUF path. `null` lets the native runtime\n\t * resolve the bundle's `diariz/` dir (the default).\n\t */\n\tggufPath?: string | null;\n\t/** Stored model id (purely informational). */\n\tmodelId?: PyannoteDiarizerModelId;\n}\n\n/**\n * Fused-`libelizainference` pyannote-3 diarizer. Owns one\n * `eliza_inference_diariz_*` session; `diarizeWindow()` runs one forward pass\n * over a ~5 s window and reduces the powerset labels into speaker segments.\n */\nexport class FusedDiarizer implements Diarizer {\n\treadonly sampleRate = PYANNOTE_SAMPLE_RATE;\n\treadonly modelId: PyannoteDiarizerModelId;\n\tprivate disposed = false;\n\n\tprivate constructor(\n\t\tprivate readonly ffi: ElizaInferenceFfi,\n\t\tprivate readonly handle: NativeDiarizHandle,\n\t\tmodelId: PyannoteDiarizerModelId,\n\t) {\n\t\tthis.modelId = modelId;\n\t}\n\n\t/**\n\t * True only when the fused `libelizainference` build exports the diarizer\n\t * ABI and advertises support at runtime.\n\t */\n\tstatic isSupported(ffi: ElizaInferenceFfi | null | undefined): boolean {\n\t\tif (!ffi || typeof ffi.diarizSupported !== \"function\") return false;\n\t\treturn ffi.diarizSupported();\n\t}\n\n\t/**\n\t * Open a native diarizer session. Throws `DiarizerUnavailableError` when\n\t * the runtime is not present.\n\t */\n\tstatic async load(opts: FusedDiarizerOptions): Promise<FusedDiarizer> {\n\t\tif (!FusedDiarizer.isSupported(opts.ffi)) {\n\t\t\tthrow new DiarizerUnavailableError(\n\t\t\t\t\"native-missing\",\n\t\t\t\t\"[diarizer-fused] The native diarizer is not present in this libelizainference build. Rebuild with the pyannote forward graph linked in (eliza_inference_diariz_* symbols).\",\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\t!opts.ffi.diarizOpen ||\n\t\t\t!opts.ffi.diarizSegment ||\n\t\t\t!opts.ffi.diarizClose\n\t\t) {\n\t\t\tthrow new DiarizerUnavailableError(\n\t\t\t\t\"model-load-failed\",\n\t\t\t\t\"[diarizer-fused] Diarizer support probe succeeded, but the required FFI methods are missing on the binding.\",\n\t\t\t);\n\t\t}\n\t\tconst ctx = typeof opts.ctx === \"function\" ? opts.ctx() : opts.ctx;\n\t\tconst handle = opts.ffi.diarizOpen({\n\t\t\tctx,\n\t\t\tggufPath: opts.ggufPath ?? null,\n\t\t});\n\t\treturn new FusedDiarizer(\n\t\t\topts.ffi,\n\t\t\thandle,\n\t\t\topts.modelId ?? PYANNOTE_SEGMENTATION_3_INT8_MODEL_ID,\n\t\t);\n\t}\n\n\tasync diarizeWindow(pcm: Float32Array): Promise<DiarizerOutput> {\n\t\tif (this.disposed) {\n\t\t\tthrow new DiarizerUnavailableError(\n\t\t\t\t\"model-load-failed\",\n\t\t\t\t\"[diarizer-fused] diarizeWindow called after dispose()\",\n\t\t\t);\n\t\t}\n\t\tconst segment = this.ffi.diarizSegment;\n\t\tif (!segment) {\n\t\t\tthrow new DiarizerUnavailableError(\n\t\t\t\t\"model-load-failed\",\n\t\t\t\t\"[diarizer-fused] diarizeWindow missing FFI method\",\n\t\t\t);\n\t\t}\n\t\tconst labels = segment({ diariz: this.handle, pcm });\n\t\tconst frames = labels.length;\n\t\t// One-hot the powerset labels into the frame×class tensor the shared\n\t\t// pure reducer expects (it argmaxes back out, so the one-hot is exact).\n\t\tconst probs = new Float32Array(frames * PYANNOTE_CLASS_COUNT);\n\t\tfor (let frame = 0; frame < frames; frame += 1) {\n\t\t\tconst label = labels[frame] ?? -1;\n\t\t\tif (label < 0 || label >= PYANNOTE_CLASS_COUNT) {\n\t\t\t\tthrow new DiarizerUnavailableError(\n\t\t\t\t\t\"model-load-failed\",\n\t\t\t\t\t`[diarizer-fused] native diarizer emitted invalid class ${label} at frame ${frame}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tprobs[frame * PYANNOTE_CLASS_COUNT + label] = 1;\n\t\t}\n\t\treturn classifyFramesToSegments(\n\t\t\tprobs,\n\t\t\tframes,\n\t\t\tPYANNOTE_CLASS_COUNT,\n\t\t\t0,\n\t\t\tPYANNOTE_FRAME_STRIDE_MS,\n\t\t);\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.ffi.diarizClose?.(this.handle);\n\t}\n}\n",
13
+ "import type { VoiceInputSource, VoiceSegment, VoiceSpeaker } from \"./types\";\n\nexport const DEFAULT_VOICE_IMPRINT_MATCH_THRESHOLD = 0.78;\n\nexport interface VoiceImprintProfile {\n\tid: string;\n\tcentroidEmbedding: ArrayLike<number> | null | undefined;\n\tembeddingModel?: string | null;\n\tsampleCount?: number | null;\n\tconfidence?: number | null;\n\tlabel?: string | null;\n\tdisplayName?: string | null;\n\tentityId?: string | null;\n\tsourceKind?: string | null;\n\tsourceScopeId?: string | null;\n\tmetadata?: Record<string, unknown> | null;\n}\n\nexport interface VoiceImprintMatch {\n\tprofile: VoiceImprintProfile;\n\tsimilarity: number;\n\tconfidence: number;\n}\n\nexport interface VoiceImprintCentroidUpdate {\n\tcentroidEmbedding: number[];\n\tsampleCount: number;\n\tconfidence: number;\n}\n\nexport interface VoiceImprintObservationInput {\n\tid: string;\n\tsegmentId?: string;\n\ttext: string;\n\tstartMs: number;\n\tendMs: number;\n\tembedding: ArrayLike<number>;\n\tembeddingModel?: string | null;\n\tconfidence?: number | null;\n\tsource?: VoiceInputSource;\n\tmetadata?: Record<string, unknown> | null;\n}\n\nexport interface AttributedVoiceObservation {\n\tobservation: VoiceImprintObservationInput;\n\tmatch: VoiceImprintMatch | null;\n\tspeaker: VoiceSpeaker | null;\n\tsegment: VoiceSegment;\n}\n\nexport interface SpeakerAttributionResult {\n\tobservations: AttributedVoiceObservation[];\n\tsegments: VoiceSegment[];\n\tprimarySpeaker?: VoiceSpeaker;\n\tsummary: {\n\t\ttotalObservations: number;\n\t\tmatchedObservations: number;\n\t\tunmatchedObservations: number;\n\t\tmeanConfidence: number;\n\t\tmeanSimilarity: number | null;\n\t};\n}\n\nfunction clamp01(value: number): number {\n\tif (!Number.isFinite(value)) return 0;\n\treturn Math.max(0, Math.min(1, value));\n}\n\nexport function normalizeVoiceEmbedding(\n\tembedding: ArrayLike<number>,\n): number[] {\n\tlet sumSq = 0;\n\tconst out = new Array<number>(embedding.length);\n\tfor (let i = 0; i < embedding.length; i += 1) {\n\t\tconst value = Number(embedding[i]);\n\t\tif (!Number.isFinite(value)) {\n\t\t\tthrow new Error(\n\t\t\t\t`[voice-imprint] embedding contains non-finite value at ${i}`,\n\t\t\t);\n\t\t}\n\t\tout[i] = value;\n\t\tsumSq += value * value;\n\t}\n\tif (sumSq === 0) return out;\n\tconst invNorm = 1 / Math.sqrt(sumSq);\n\tfor (let i = 0; i < out.length; i += 1) out[i] *= invNorm;\n\treturn out;\n}\n\nexport function cosineSimilarity(\n\tleft: ArrayLike<number>,\n\tright: ArrayLike<number>,\n): number {\n\tif (left.length !== right.length) {\n\t\tthrow new Error(\n\t\t\t`[voice-imprint] embedding dimension mismatch: ${left.length} != ${right.length}`,\n\t\t);\n\t}\n\tconst a = normalizeVoiceEmbedding(left);\n\tconst b = normalizeVoiceEmbedding(right);\n\tlet dot = 0;\n\tfor (let i = 0; i < a.length; i += 1) dot += a[i] * b[i];\n\treturn Math.max(-1, Math.min(1, dot));\n}\n\nexport function updateVoiceImprintCentroid(args: {\n\tcentroidEmbedding?: ArrayLike<number> | null;\n\tsampleCount?: number | null;\n\tconfidence?: number | null;\n\tobservationEmbedding: ArrayLike<number>;\n\tobservationConfidence?: number | null;\n\tmaxObservationWeight?: number;\n}): VoiceImprintCentroidUpdate {\n\tconst observation = normalizeVoiceEmbedding(args.observationEmbedding);\n\tconst previousCount = Math.max(0, Math.floor(args.sampleCount ?? 0));\n\tconst observationWeight = clamp01(\n\t\tMath.min(args.maxObservationWeight ?? 1, args.observationConfidence ?? 1),\n\t);\n\tif (!args.centroidEmbedding || previousCount === 0) {\n\t\treturn {\n\t\t\tcentroidEmbedding: observation,\n\t\t\tsampleCount: 1,\n\t\t\tconfidence: observationWeight,\n\t\t};\n\t}\n\tif (args.centroidEmbedding.length !== observation.length) {\n\t\tthrow new Error(\n\t\t\t`[voice-imprint] cannot update ${args.centroidEmbedding.length}-dim centroid with ${observation.length}-dim observation`,\n\t\t);\n\t}\n\tconst centroid = normalizeVoiceEmbedding(args.centroidEmbedding);\n\tconst historicalWeight = Math.max(1, previousCount);\n\tconst updated = centroid.map(\n\t\t(value, i) => value * historicalWeight + observation[i] * observationWeight,\n\t);\n\treturn {\n\t\tcentroidEmbedding: normalizeVoiceEmbedding(updated),\n\t\tsampleCount: previousCount + 1,\n\t\tconfidence: clamp01(\n\t\t\t((args.confidence ?? 0) * previousCount + observationWeight) /\n\t\t\t\t(previousCount + 1),\n\t\t),\n\t};\n}\n\nexport function matchVoiceImprint(args: {\n\tembedding: ArrayLike<number>;\n\tprofiles: readonly VoiceImprintProfile[];\n\tembeddingModel?: string | null;\n\tthreshold?: number;\n}): VoiceImprintMatch | null {\n\tconst threshold = args.threshold ?? DEFAULT_VOICE_IMPRINT_MATCH_THRESHOLD;\n\tlet best: VoiceImprintMatch | null = null;\n\tfor (const profile of args.profiles) {\n\t\tif (!profile.centroidEmbedding || profile.centroidEmbedding.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\targs.embeddingModel &&\n\t\t\tprofile.embeddingModel &&\n\t\t\targs.embeddingModel !== profile.embeddingModel\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (profile.centroidEmbedding.length !== args.embedding.length) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst similarity = cosineSimilarity(\n\t\t\targs.embedding,\n\t\t\tprofile.centroidEmbedding,\n\t\t);\n\t\tif (similarity < threshold) continue;\n\t\tconst confidence = clamp01(\n\t\t\t((similarity - threshold) / Math.max(0.0001, 1 - threshold)) *\n\t\t\t\tclamp01(profile.confidence ?? 1),\n\t\t);\n\t\tif (!best || similarity > best.similarity) {\n\t\t\tbest = { profile, similarity, confidence };\n\t\t}\n\t}\n\treturn best;\n}\n\nexport function voiceSpeakerFromImprintMatch(args: {\n\tmatch: VoiceImprintMatch;\n\tsource?: VoiceInputSource;\n\tobservationId?: string;\n}): VoiceSpeaker {\n\tconst { profile } = args.match;\n\treturn {\n\t\tid: profile.entityId ?? profile.id,\n\t\tlabel: profile.label ?? undefined,\n\t\tdisplayName: profile.displayName ?? profile.label ?? undefined,\n\t\tsource: args.source,\n\t\timprintClusterId: profile.id,\n\t\timprintObservationId: args.observationId,\n\t\tentityId: profile.entityId ?? undefined,\n\t\tconfidence: args.match.confidence,\n\t\tmetadata: {\n\t\t\t...(profile.metadata ?? {}),\n\t\t\tattributionOnly: true,\n\t\t\tevidenceKind: \"voice_imprint_attribution\",\n\t\t\tidentityAuthority: false,\n\t\t\tsynthesisAuthorization: false,\n\t\t\tmatchSimilarity: args.match.similarity,\n\t\t\tembeddingModel: profile.embeddingModel ?? undefined,\n\t\t},\n\t};\n}\n\nexport function attributeVoiceImprintObservations(args: {\n\tobservations: readonly VoiceImprintObservationInput[];\n\tprofiles: readonly VoiceImprintProfile[];\n\tthreshold?: number;\n\tdefaultSource?: VoiceInputSource;\n}): SpeakerAttributionResult {\n\tconst attributed: AttributedVoiceObservation[] = [];\n\tlet confidenceSum = 0;\n\tlet confidenceCount = 0;\n\tlet similaritySum = 0;\n\tlet similarityCount = 0;\n\n\tfor (const observation of args.observations) {\n\t\tconst source = observation.source ?? args.defaultSource;\n\t\tconst match = matchVoiceImprint({\n\t\t\tembedding: observation.embedding,\n\t\t\tembeddingModel: observation.embeddingModel,\n\t\t\tprofiles: args.profiles,\n\t\t\tthreshold: args.threshold,\n\t\t});\n\t\tconst speaker = match\n\t\t\t? voiceSpeakerFromImprintMatch({\n\t\t\t\t\tmatch,\n\t\t\t\t\tsource,\n\t\t\t\t\tobservationId: observation.id,\n\t\t\t\t})\n\t\t\t: null;\n\t\tif (speaker?.confidence !== undefined) {\n\t\t\tconfidenceSum += speaker.confidence;\n\t\t\tconfidenceCount += 1;\n\t\t}\n\t\tif (match) {\n\t\t\tsimilaritySum += match.similarity;\n\t\t\tsimilarityCount += 1;\n\t\t}\n\t\tattributed.push({\n\t\t\tobservation,\n\t\t\tmatch,\n\t\t\tspeaker,\n\t\t\tsegment: {\n\t\t\t\tid: observation.segmentId ?? observation.id,\n\t\t\t\ttext: observation.text,\n\t\t\t\tstartMs: observation.startMs,\n\t\t\t\tendMs: observation.endMs,\n\t\t\t\t...(speaker ? { speaker, speakerId: speaker.id } : {}),\n\t\t\t\t...(source ? { source } : {}),\n\t\t\t\tconfidence: speaker?.confidence ?? observation.confidence ?? undefined,\n\t\t\t\tmetadata: {\n\t\t\t\t\t...(observation.metadata ?? {}),\n\t\t\t\t\tattributionOnly: true,\n\t\t\t\t\tevidenceKind: \"voice_imprint_attribution\",\n\t\t\t\t\tidentityAuthority: false,\n\t\t\t\t\tsynthesisAuthorization: false,\n\t\t\t\t\tdiarizationMode: \"attribution_only\",\n\t\t\t\t\tembeddingModel: observation.embeddingModel ?? undefined,\n\t\t\t\t\timprintObservationId: observation.id,\n\t\t\t\t\timprintClusterId: speaker?.imprintClusterId,\n\t\t\t\t\tentityId: speaker?.entityId,\n\t\t\t\t\tmatchSimilarity: match?.similarity,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t}\n\n\tconst segments = attributed.map((row) => row.segment);\n\tconst primarySpeaker = selectPrimarySpeaker(segments);\n\treturn {\n\t\tobservations: attributed,\n\t\tsegments,\n\t\t...(primarySpeaker ? { primarySpeaker } : {}),\n\t\tsummary: {\n\t\t\ttotalObservations: attributed.length,\n\t\t\tmatchedObservations: attributed.filter((row) => row.match).length,\n\t\t\tunmatchedObservations: attributed.filter((row) => !row.match).length,\n\t\t\tmeanConfidence:\n\t\t\t\tconfidenceCount === 0 ? 0 : clamp01(confidenceSum / confidenceCount),\n\t\t\tmeanSimilarity:\n\t\t\t\tsimilarityCount === 0 ? null : similaritySum / similarityCount,\n\t\t},\n\t};\n}\n\nfunction selectPrimarySpeaker(\n\tsegments: readonly VoiceSegment[],\n): VoiceSpeaker | undefined {\n\tconst durations = new Map<string, { speaker: VoiceSpeaker; ms: number }>();\n\tfor (const segment of segments) {\n\t\tif (!segment.speaker) continue;\n\t\tconst key = segment.speaker.id;\n\t\tconst prev = durations.get(key);\n\t\tconst ms = Math.max(0, segment.endMs - segment.startMs);\n\t\tdurations.set(key, {\n\t\t\tspeaker: segment.speaker,\n\t\t\tms: (prev?.ms ?? 0) + ms,\n\t\t});\n\t}\n\tlet best: { speaker: VoiceSpeaker; ms: number } | undefined;\n\tfor (const row of durations.values()) {\n\t\tif (!best || row.ms > best.ms) best = row;\n\t}\n\treturn best?.speaker;\n}\n",
14
+ "/**\n * Speaker-embedding encoder — shared constants, error class, and the\n * embedding-distance helper.\n *\n * The speaker encoder runs EXCLUSIVELY through the fused `libelizainference`\n * `eliza_inference_speaker_*` ABI (`FusedSpeakerEncoder` in `encoder-fused.ts`).\n * The standalone `libvoice_classifier` binding that previously lived here has\n * been removed — there is one on-device voice runtime.\n *\n * This module retains the pieces the fused path shares:\n * - the canonical dims (`SPEAKER_GGML_*`), pinned at 256 to match the C-side\n * `VOICE_SPEAKER_EMBEDDING_DIM` and the WeSpeaker ResNet34-LM head,\n * - the structured `SpeakerEncoderGgmlUnavailableError` the fused encoder\n * throws (no synthetic embedding fallback),\n * - the pure `voiceSpeakerDistance` cosine-distance helper.\n */\n\n/** Output embedding dim. Matches `VOICE_SPEAKER_EMBEDDING_DIM`. */\nexport const SPEAKER_GGML_EMBEDDING_DIM = 256;\n\n/** Required input sample rate. */\nexport const SPEAKER_GGML_SAMPLE_RATE = 16_000;\n\n/** Minimum useful audio window (~1.0 s). */\nexport const SPEAKER_GGML_MIN_SAMPLES = 16_000;\n\nexport class SpeakerEncoderGgmlUnavailableError extends Error {\n\treadonly code:\n\t\t| \"native-missing\"\n\t\t| \"library-missing\"\n\t\t| \"model-missing\"\n\t\t| \"model-load-failed\"\n\t\t| \"model-shape-mismatch\"\n\t\t| \"forward-not-implemented\"\n\t\t| \"invalid-input\";\n\tconstructor(\n\t\tcode: SpeakerEncoderGgmlUnavailableError[\"code\"],\n\t\tmessage: string,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"SpeakerEncoderGgmlUnavailableError\";\n\t\tthis.code = code;\n\t}\n}\n\n/**\n * Cosine distance between two 256-dim speaker embeddings. Defined as\n * `1 - cos_similarity(a, b)`, range [0, 2]. Mirrors the C-side\n * `voice_speaker_distance` helper exactly.\n */\nexport function voiceSpeakerDistance(a: Float32Array, b: Float32Array): number {\n\tif (a.length !== SPEAKER_GGML_EMBEDDING_DIM) {\n\t\tthrow new SpeakerEncoderGgmlUnavailableError(\n\t\t\t\"invalid-input\",\n\t\t\t`[speaker] left embedding has dim ${a.length}, expected ${SPEAKER_GGML_EMBEDDING_DIM}`,\n\t\t);\n\t}\n\tif (b.length !== SPEAKER_GGML_EMBEDDING_DIM) {\n\t\tthrow new SpeakerEncoderGgmlUnavailableError(\n\t\t\t\"invalid-input\",\n\t\t\t`[speaker] right embedding has dim ${b.length}, expected ${SPEAKER_GGML_EMBEDDING_DIM}`,\n\t\t);\n\t}\n\tlet dot = 0;\n\tlet normA = 0;\n\tlet normB = 0;\n\tfor (let i = 0; i < SPEAKER_GGML_EMBEDDING_DIM; i += 1) {\n\t\tconst av = a[i];\n\t\tconst bv = b[i];\n\t\tdot += av * bv;\n\t\tnormA += av * av;\n\t\tnormB += bv * bv;\n\t}\n\tif (normA <= 0 || normB <= 0) return 1;\n\tlet cosine = dot / (Math.sqrt(normA) * Math.sqrt(normB));\n\tif (cosine > 1) cosine = 1;\n\tif (cosine < -1) cosine = -1;\n\treturn 1 - cosine;\n}\n",
15
+ "/**\n * Speaker-embedding encoder — shared contract, model-id constants, and the\n * `averageEmbeddings` centroid helper.\n *\n * The speaker encoder runs EXCLUSIVELY through the fused `libelizainference`\n * `eliza_inference_speaker_*` ABI (`FusedSpeakerEncoder` in `encoder-fused.ts`).\n * The standalone `WespeakerEncoder` (`libvoice_classifier`) binding has been\n * removed — there is one on-device voice runtime.\n *\n * This module retains the cross-cutting pieces every encoder caller shares:\n * - the `SpeakerEncoder` interface the fused encoder implements,\n * - the stored model-id strings (kept stable so existing voice profiles in\n * the database stay valid),\n * - the canonical dims (re-exported from `encoder-ggml`),\n * - the `SpeakerEncoderUnavailableError` the enrollment routes raise,\n * - the pure `averageEmbeddings` centroid helper.\n */\n\nimport { normalizeVoiceEmbedding } from \"../speaker-imprint\";\nimport {\n\tSPEAKER_GGML_EMBEDDING_DIM,\n\tSPEAKER_GGML_MIN_SAMPLES,\n\tSPEAKER_GGML_SAMPLE_RATE,\n} from \"./encoder-ggml\";\n\n// ---------------------------------------------------------------------------\n// Stored model id constants.\n// The model id strings are kept stable for compatibility with stored profiles\n// (changing them would invalidate any existing voice profiles in the database).\n// ---------------------------------------------------------------------------\n\nexport const WESPEAKER_RESNET34_LM_INT8_MODEL_ID =\n\t\"wespeaker-resnet34-lm-int8\" as const;\nexport const WESPEAKER_RESNET34_LM_FP32_MODEL_ID =\n\t\"wespeaker-resnet34-lm-fp32\" as const;\nexport type WespeakerModelId =\n\t| typeof WESPEAKER_RESNET34_LM_INT8_MODEL_ID\n\t| typeof WESPEAKER_RESNET34_LM_FP32_MODEL_ID;\n\nexport const WESPEAKER_EMBEDDING_DIM = SPEAKER_GGML_EMBEDDING_DIM;\nexport const WESPEAKER_SAMPLE_RATE = SPEAKER_GGML_SAMPLE_RATE;\nexport const WESPEAKER_MIN_SAMPLES = SPEAKER_GGML_MIN_SAMPLES;\n\n// ---------------------------------------------------------------------------\n// Structured error.\n// ---------------------------------------------------------------------------\n\nexport class SpeakerEncoderUnavailableError extends Error {\n\treadonly code:\n\t\t| \"native-missing\"\n\t\t| \"library-missing\"\n\t\t| \"model-missing\"\n\t\t| \"model-load-failed\"\n\t\t| \"model-shape-mismatch\"\n\t\t| \"forward-not-implemented\"\n\t\t| \"invalid-input\";\n\tconstructor(code: SpeakerEncoderUnavailableError[\"code\"], message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"SpeakerEncoderUnavailableError\";\n\t\tthis.code = code;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// SpeakerEncoder interface.\n// ---------------------------------------------------------------------------\n\n/** The minimal contract every speaker encoder honors. */\nexport interface SpeakerEncoder {\n\treadonly embeddingDim: number;\n\treadonly sampleRate: number;\n\treadonly modelId?: string;\n\tencode(pcm: Float32Array): Promise<Float32Array>;\n\tdispose(): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// averageEmbeddings — pure centroid helper.\n// ---------------------------------------------------------------------------\n\nexport function averageEmbeddings(\n\tembeddings: readonly Float32Array[],\n): Float32Array {\n\tif (embeddings.length === 0) {\n\t\tthrow new SpeakerEncoderUnavailableError(\n\t\t\t\"invalid-input\",\n\t\t\t\"[wespeaker] averageEmbeddings called with no inputs\",\n\t\t);\n\t}\n\tconst dim = embeddings[0].length;\n\tconst sum = new Float64Array(dim);\n\tfor (const emb of embeddings) {\n\t\tif (emb.length !== dim) {\n\t\t\tthrow new SpeakerEncoderUnavailableError(\n\t\t\t\t\"invalid-input\",\n\t\t\t\t`[wespeaker] embedding dim mismatch: ${emb.length} vs ${dim}`,\n\t\t\t);\n\t\t}\n\t\tfor (let i = 0; i < dim; i += 1) sum[i] += emb[i];\n\t}\n\tconst out = new Float32Array(dim);\n\tfor (let i = 0; i < dim; i += 1) out[i] = sum[i] / embeddings.length;\n\tconst normalized = normalizeVoiceEmbedding(out);\n\treturn Float32Array.from(normalized);\n}\n",
16
+ "/**\n * Speaker-embedding encoder — fused `libelizainference` binding (ABI v6).\n *\n * The strategic on-device voice engine is the single fused-FFI\n * `libelizainference` library (the merged llama.cpp fork — see\n * `plugins/plugin-local-inference/native/CLAUDE.md` §1). This class drives the\n * WeSpeaker ResNet34-LM speaker encoder through that one native handle via the\n * `eliza_inference_speaker_*` ABI. This is the SOLE on-device speaker-encoder\n * runtime — the same `ffi`/`ctx` pair powers VAD / wake-word / TTS / ASR, so the\n * whole voice pipeline runs through one library.\n *\n * Shape mirrors the legacy `encoder.ts::SpeakerEncoder` contract exactly:\n * - 16 kHz mono fp32 PCM in,\n * - one L2-normalized 256-d embedding out,\n * - `encode(pcm)` / `dispose()`.\n *\n * No silent fallback: when the fused build does not export the speaker ABI\n * (`eliza_inference_speaker_supported() == 0`) `load()` throws a structured\n * `SpeakerEncoderGgmlUnavailableError` (AGENTS.md §3 — no synthetic\n * embeddings, no standalone-lib fallback).\n */\n\nimport type {\n\tElizaInferenceContextHandle,\n\tElizaInferenceFfi,\n\tNativeSpeakerHandle,\n} from \"../ffi-bindings\";\nimport type { SpeakerEncoder } from \"./encoder\";\nimport { WESPEAKER_RESNET34_LM_INT8_MODEL_ID } from \"./encoder\";\nimport {\n\tSPEAKER_GGML_EMBEDDING_DIM,\n\tSPEAKER_GGML_MIN_SAMPLES,\n\tSPEAKER_GGML_SAMPLE_RATE,\n\tSpeakerEncoderGgmlUnavailableError,\n} from \"./encoder-ggml\";\n\nexport interface FusedSpeakerEncoderOptions {\n\tffi: ElizaInferenceFfi;\n\tctx: ElizaInferenceContextHandle | (() => ElizaInferenceContextHandle);\n\t/**\n\t * Optional explicit WeSpeaker GGUF path. `null` lets the native runtime\n\t * resolve the bundle's `speaker/` dir (the default).\n\t */\n\tggufPath?: string | null;\n}\n\n/**\n * Fused-`libelizainference` WeSpeaker speaker encoder. Owns one\n * `eliza_inference_speaker_*` session; `encode()` runs one forward pass over\n * the supplied 16 kHz PCM and returns the normalized 256-d embedding. The\n * native side owns the model graph; this class is a thin handle.\n */\nexport class FusedSpeakerEncoder implements SpeakerEncoder {\n\treadonly embeddingDim = SPEAKER_GGML_EMBEDDING_DIM;\n\treadonly sampleRate = SPEAKER_GGML_SAMPLE_RATE;\n\treadonly modelId = WESPEAKER_RESNET34_LM_INT8_MODEL_ID;\n\tprivate disposed = false;\n\n\tprivate constructor(\n\t\tprivate readonly ffi: ElizaInferenceFfi,\n\t\tprivate readonly handle: NativeSpeakerHandle,\n\t) {}\n\n\t/**\n\t * True only when the fused `libelizainference` build exports the speaker\n\t * ABI and advertises support at runtime.\n\t */\n\tstatic isSupported(ffi: ElizaInferenceFfi | null | undefined): boolean {\n\t\tif (!ffi || typeof ffi.speakerSupported !== \"function\") return false;\n\t\treturn ffi.speakerSupported();\n\t}\n\n\t/**\n\t * Open a native speaker-encoder session. Throws\n\t * `SpeakerEncoderGgmlUnavailableError` when the runtime is not present.\n\t */\n\tstatic async load(\n\t\topts: FusedSpeakerEncoderOptions,\n\t): Promise<FusedSpeakerEncoder> {\n\t\tif (!FusedSpeakerEncoder.isSupported(opts.ffi)) {\n\t\t\tthrow new SpeakerEncoderGgmlUnavailableError(\n\t\t\t\t\"native-missing\",\n\t\t\t\t\"[speaker-fused] The native speaker encoder is not present in this libelizainference build. Rebuild with the WeSpeaker forward graph linked in (eliza_inference_speaker_* symbols).\",\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\t!opts.ffi.speakerOpen ||\n\t\t\t!opts.ffi.speakerEmbed ||\n\t\t\t!opts.ffi.speakerClose\n\t\t) {\n\t\t\tthrow new SpeakerEncoderGgmlUnavailableError(\n\t\t\t\t\"model-load-failed\",\n\t\t\t\t\"[speaker-fused] Speaker support probe succeeded, but the required FFI methods are missing on the binding.\",\n\t\t\t);\n\t\t}\n\t\tconst ctx = typeof opts.ctx === \"function\" ? opts.ctx() : opts.ctx;\n\t\tconst handle = opts.ffi.speakerOpen({\n\t\t\tctx,\n\t\t\tggufPath: opts.ggufPath ?? null,\n\t\t});\n\t\treturn new FusedSpeakerEncoder(opts.ffi, handle);\n\t}\n\n\tasync encode(pcm: Float32Array): Promise<Float32Array> {\n\t\tif (this.disposed) {\n\t\t\tthrow new SpeakerEncoderGgmlUnavailableError(\n\t\t\t\t\"model-load-failed\",\n\t\t\t\t\"[speaker-fused] encode called after dispose()\",\n\t\t\t);\n\t\t}\n\t\tif (!(pcm instanceof Float32Array)) {\n\t\t\tthrow new SpeakerEncoderGgmlUnavailableError(\n\t\t\t\t\"invalid-input\",\n\t\t\t\t\"[speaker-fused] pcm must be a Float32Array\",\n\t\t\t);\n\t\t}\n\t\tif (pcm.length < SPEAKER_GGML_MIN_SAMPLES) {\n\t\t\tthrow new SpeakerEncoderGgmlUnavailableError(\n\t\t\t\t\"invalid-input\",\n\t\t\t\t`[speaker-fused] pcm too short: ${pcm.length} samples < ${SPEAKER_GGML_MIN_SAMPLES}`,\n\t\t\t);\n\t\t}\n\t\tconst embed = this.ffi.speakerEmbed;\n\t\tif (!embed) {\n\t\t\tthrow new SpeakerEncoderGgmlUnavailableError(\n\t\t\t\t\"model-load-failed\",\n\t\t\t\t\"[speaker-fused] encode missing FFI method\",\n\t\t\t);\n\t\t}\n\t\treturn embed({ speaker: this.handle, pcm });\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.ffi.speakerClose?.(this.handle);\n\t}\n}\n",
17
+ "/**\n * Streaming ASR adapters for the local voice pipeline.\n *\n * Implements the `StreamingTranscriber` contract from `voice/types.ts`:\n * PCM frames in (`feed`), running partial-transcript events out, `flush()`\n * to force-finalize on `speech-end`. Two adapters, resolved in priority\n * order by `createStreamingTranscriber()` — both backed by the single fused\n * `libelizainference` build (the SOLE on-device ASR runtime):\n *\n * 1. `FfiStreamingTranscriber` — the FINAL path. Drives the fused\n * `libelizainference` streaming ASR ABI (`eliza_inference_asr_stream_*`,\n * ABI v2 — declared in `packages/app-core/scripts/omnivoice-fuse/ffi.h`,\n * bound in `voice/ffi-bindings.ts`). The C side is W7's job; until the\n * real fused build advertises streaming ASR the binding's `mmap`/`asr`\n * calls return `ELIZA_ERR_NOT_IMPLEMENTED`, which surfaces as a thrown\n * error here. Selected only when `ffi.asrStreamSupported()` is true.\n *\n * 2. `FfiBatchTranscriber` — the contract-clean INTERIM path. Runs the\n * fused build's *batch* decoder (`eliza_inference_asr_transcribe`, ABI\n * v1) over a sliding window with overlap, so each call covers ≤ ~6–7 s\n * of audio — incremental, not \"buffer the whole utterance, one giant\n * decode\". It lives inside the single shipped llama.cpp/GGML build and\n * emits Gemma text-vocabulary tokens, so it does not vendor a second\n * ggml or introduce a tokenizer-family mismatch.\n * Selected whenever a `libelizainference` handle + bundled ASR model are\n * present (which is always true when the fused build is loaded).\n *\n * If no fused ASR backend can be resolved, `createStreamingTranscriber()`\n * throws `AsrUnavailableError` — a real failure, never a silent\n * empty-transcript degrade and never a fall back to a second ASR runtime\n * (AGENTS.md §3 + §9).\n */\n\nimport type {\n\tElizaInferenceContextHandle,\n\tElizaInferenceFfi,\n} from \"./ffi-bindings\";\nimport type {\n\tPcmFrame,\n\tStreamingTranscriber,\n\tTranscriberEvent,\n\tTranscriberEventListener,\n\tTranscriptUpdate,\n\tVadEvent,\n\tVadEventSource,\n\tVoiceInputSource,\n\tVoiceSpeaker,\n\tVoiceTurnMetadata,\n} from \"./types\";\n\n/** The local voice runtime resamples mic input to 16 kHz mono for ASR. */\nexport const ASR_SAMPLE_RATE = 16_000;\n\n/**\n * Raised when no ASR backend can be resolved. Distinct error class so the\n * caller (engine, `TRANSCRIPTION` model handler) can surface \"ASR is not\n * installed\" with an actionable message rather than treating an empty\n * string as a successful transcription.\n */\nexport class AsrUnavailableError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"AsrUnavailableError\";\n\t}\n}\n\nexport type AsrBackendPreference = \"auto\" | \"fused\" | \"ffi-batch\";\n\nexport function normalizeAsrBackendPreference(\n\tvalue: string | null | undefined,\n): AsrBackendPreference | null {\n\tconst normalized = value?.trim().toLowerCase().replace(/_/g, \"-\");\n\tif (!normalized) return null;\n\tswitch (normalized) {\n\t\tcase \"auto\":\n\t\t\treturn \"auto\";\n\t\tcase \"fused\":\n\t\tcase \"streaming\":\n\t\tcase \"fused-streaming\":\n\t\t\treturn \"fused\";\n\t\tcase \"batch\":\n\t\tcase \"ffi-batch\":\n\t\tcase \"fused-batch\":\n\t\t\treturn \"ffi-batch\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nexport function readAsrBackendPreferenceFromEnv(\n\tenv: NodeJS.ProcessEnv = process.env,\n): AsrBackendPreference | null {\n\treturn normalizeAsrBackendPreference(env.ELIZA_LOCAL_ASR_BACKEND);\n}\n\n/* ==================================================================== *\n * Shared base — event fan-out, VAD gating, word detection.\n * ==================================================================== */\n\nconst WORD_RE = /[\\p{L}\\p{N}][\\p{L}\\p{N}'-]*/gu;\nconst VAD_PREROLL_MAX_FRAMES = 10;\n\nfunction extractWords(text: string): string[] {\n\tconst out = text.match(WORD_RE);\n\treturn out ? Array.from(out) : [];\n}\n\n/**\n * Linear-interpolation resample of mono fp32 PCM. Used to coerce mic\n * frames (commonly 16 / 24 / 48 kHz) to the ASR rate. Not a polyphase\n * filter — adequate for speech ASR; the fused build does its own\n * resampling so this is interim-batch only.\n */\nexport function resampleLinear(\n\tpcm: Float32Array,\n\tfromRate: number,\n\ttoRate: number,\n): Float32Array {\n\tif (fromRate === toRate || pcm.length === 0) return pcm;\n\tconst ratio = toRate / fromRate;\n\tconst outLen = Math.max(1, Math.round(pcm.length * ratio));\n\tconst out = new Float32Array(outLen);\n\tfor (let i = 0; i < outLen; i++) {\n\t\tconst srcPos = i / ratio;\n\t\tconst i0 = Math.floor(srcPos);\n\t\tconst i1 = Math.min(i0 + 1, pcm.length - 1);\n\t\tconst frac = srcPos - i0;\n\t\tout[i] = pcm[i0] * (1 - frac) + pcm[i1] * frac;\n\t}\n\treturn out;\n}\n\n/**\n * Base implementing the boilerplate every adapter shares: listener\n * fan-out, the `words`-once-per-segment latch, and (optional) VAD-event\n * gating. Subclasses implement `onFrame` / `onFlush` / `onDispose` and\n * call `emitPartial` / `emitFinal`.\n */\nexport abstract class BaseStreamingTranscriber implements StreamingTranscriber {\n\tprivate readonly listeners = new Set<TranscriberEventListener>();\n\tprivate metadata: TranscriptMetadataDefaults;\n\t/** True between `speech-start`/first-frame and the next `flush()`. */\n\tprotected segmentOpen = false;\n\t/** Latched once `words` is emitted for the current segment. */\n\tprivate wordsEmitted = false;\n\t/** When set, frames are only forwarded while the VAD is in an active speech window. */\n\tprivate vadActive: boolean | null = null;\n\tprivate readonly vadPrerollFrames: PcmFrame[] = [];\n\tprivate vadUnsub: (() => void) | null = null;\n\tprivate disposed = false;\n\n\tconstructor(vad?: VadEventSource, metadata: TranscriptMetadataDefaults = {}) {\n\t\tthis.metadata = metadata;\n\t\tif (vad) {\n\t\t\tthis.vadActive = false;\n\t\t\tthis.vadUnsub = vad.onVadEvent((ev) => this.onVadEvent(ev));\n\t\t}\n\t}\n\n\ton(listener: TranscriberEventListener): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\t/**\n\t * Update the metadata defaults that `withMetadata()` merges into every\n\t * partial / final emission. The voice pipeline calls this once the\n\t * async speaker-ID / diarizer lookup resolves, so the speaker /\n\t * segments are attached to the rest of the turn without buffering all\n\t * partials for the lookup.\n\t */\n\tsetMetadataDefaults(metadata: TranscriptMetadataDefaults): void {\n\t\tthis.metadata = { ...this.metadata, ...metadata };\n\t}\n\n\tfeed(frame: PcmFrame): void {\n\t\tif (this.disposed) {\n\t\t\tthrow new Error(\"[asr] feed() called on a disposed transcriber\");\n\t\t}\n\t\tif (frame.pcm.length === 0) return;\n\t\t// VAD gating: while the async VAD is still deciding, retain a tiny\n\t\t// leading pre-roll so the first voiced frames are not lost.\n\t\tif (this.vadActive === false) {\n\t\t\tthis.rememberVadPreroll(frame);\n\t\t\treturn;\n\t\t}\n\t\tif (!this.segmentOpen) {\n\t\t\tthis.segmentOpen = true;\n\t\t\tthis.wordsEmitted = false;\n\t\t}\n\t\tthis.onFrame(frame);\n\t}\n\n\tasync flush(): Promise<TranscriptUpdate> {\n\t\tif (this.disposed) {\n\t\t\tthrow new Error(\"[asr] flush() called on a disposed transcriber\");\n\t\t}\n\t\tconst update = this.withMetadata(await this.onFlush());\n\t\tthis.segmentOpen = false;\n\t\tthis.wordsEmitted = false;\n\t\tthis.emit({ kind: \"final\", update });\n\t\treturn update;\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.vadUnsub?.();\n\t\tthis.vadUnsub = null;\n\t\tthis.listeners.clear();\n\t\tthis.onDispose();\n\t}\n\n\t/** Subclass hook: a (VAD-gated) PCM frame for the current speech segment. */\n\tprotected abstract onFrame(frame: PcmFrame): void;\n\t/** Subclass hook: drain buffered audio, run a final decode, return the final transcript. */\n\tprotected abstract onFlush(): Promise<TranscriptUpdate>;\n\t/** Subclass hook: release native resources. */\n\tprotected abstract onDispose(): void;\n\n\tprivate rememberVadPreroll(frame: PcmFrame): void {\n\t\tthis.vadPrerollFrames.push({\n\t\t\t...frame,\n\t\t\tpcm: frame.pcm.slice(),\n\t\t});\n\t\twhile (this.vadPrerollFrames.length > VAD_PREROLL_MAX_FRAMES) {\n\t\t\tthis.vadPrerollFrames.shift();\n\t\t}\n\t}\n\n\tprivate drainVadPreroll(): void {\n\t\tif (this.vadPrerollFrames.length === 0) return;\n\t\tconst frames = this.vadPrerollFrames.splice(0);\n\t\tif (!this.segmentOpen) {\n\t\t\tthis.segmentOpen = true;\n\t\t\tthis.wordsEmitted = false;\n\t\t}\n\t\tfor (const frame of frames) this.onFrame(frame);\n\t}\n\n\t/** Emit a running-partial event and (the first time it has words) a `words` event. */\n\tprotected emitPartial(update: TranscriptUpdate): void {\n\t\tconst enriched = this.withMetadata(update);\n\t\tthis.emit({ kind: \"partial\", update: enriched });\n\t\tif (!this.wordsEmitted) {\n\t\t\tconst words = extractWords(enriched.partial);\n\t\t\tif (words.length > 0) {\n\t\t\t\tthis.wordsEmitted = true;\n\t\t\t\tthis.emit({ kind: \"words\", words });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate withMetadata(update: TranscriptUpdate): TranscriptUpdate {\n\t\tif (\n\t\t\t!this.metadata.source &&\n\t\t\t!this.metadata.speaker &&\n\t\t\t!this.metadata.turn\n\t\t) {\n\t\t\treturn update;\n\t\t}\n\t\tconst source = update.source ?? this.metadata.source;\n\t\tconst speaker = update.speaker ?? this.metadata.speaker;\n\t\tconst segments =\n\t\t\tupdate.segments ?? update.turn?.segments ?? this.metadata.turn?.segments;\n\t\tconst turn =\n\t\t\tupdate.turn || this.metadata.turn\n\t\t\t\t? {\n\t\t\t\t\t\t...this.metadata.turn,\n\t\t\t\t\t\t...update.turn,\n\t\t\t\t\t\tsource:\n\t\t\t\t\t\t\tupdate.turn?.source ??\n\t\t\t\t\t\t\tupdate.source ??\n\t\t\t\t\t\t\tthis.metadata.turn?.source ??\n\t\t\t\t\t\t\tsource,\n\t\t\t\t\t\tprimarySpeaker:\n\t\t\t\t\t\t\tupdate.turn?.primarySpeaker ??\n\t\t\t\t\t\t\tupdate.speaker ??\n\t\t\t\t\t\t\tthis.metadata.turn?.primarySpeaker ??\n\t\t\t\t\t\t\tspeaker,\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\t\treturn {\n\t\t\t...update,\n\t\t\t...(source ? { source } : {}),\n\t\t\t...(speaker ? { speaker } : {}),\n\t\t\t...(segments ? { segments } : {}),\n\t\t\t...(turn ? { turn } : {}),\n\t\t};\n\t}\n\n\tprivate emit(event: TranscriberEvent): void {\n\t\tfor (const l of this.listeners) l(event);\n\t}\n\n\tprivate onVadEvent(ev: VadEvent): void {\n\t\tswitch (ev.type) {\n\t\t\tcase \"speech-start\":\n\t\t\tcase \"speech-active\":\n\t\t\t\tthis.vadActive = true;\n\t\t\t\tthis.drainVadPreroll();\n\t\t\t\tbreak;\n\t\t\tcase \"speech-pause\":\n\t\t\t\t// Pause keeps the segment \"armed\" but stops accepting new audio\n\t\t\t\t// until speech resumes. The turn controller decides whether a\n\t\t\t\t// pause finalizes; this layer just stops decoding.\n\t\t\t\tthis.vadActive = false;\n\t\t\t\tbreak;\n\t\t\tcase \"speech-end\":\n\t\t\t\tthis.vadActive = false;\n\t\t\t\tthis.vadPrerollFrames.length = 0;\n\t\t\t\tbreak;\n\t\t\tcase \"blip\":\n\t\t\t\t// A blip never opens a speech window — ignore.\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\nexport interface TranscriptMetadataDefaults {\n\tsource?: VoiceInputSource;\n\tspeaker?: VoiceSpeaker;\n\tturn?: VoiceTurnMetadata;\n}\n\n/* ==================================================================== *\n * Fused (final) path — eliza_inference_asr_stream_* (ABI v2).\n * ==================================================================== */\n\n/**\n * True when the loaded fused library has a working streaming ASR decoder\n * (not just the v2 symbols — an ABI-only build exports them but `asrStreamSupported`\n * returns false). This is the gate `createStreamingTranscriber` uses to\n * pick the fused path over the fused-batch interim adapter.\n */\nexport function ffiSupportsStreamingAsr(\n\tffi: ElizaInferenceFfi | null | undefined,\n): boolean {\n\tif (!ffi || typeof ffi.asrStreamSupported !== \"function\") return false;\n\treturn ffi.asrStreamSupported();\n}\n\n/**\n * `StreamingTranscriber` over the fused `libelizainference` streaming ASR\n * ABI. Each `feed()` forwards the (resampled) PCM into `asrStreamFeed`;\n * after a feed it reads the running partial via `asrStreamPartial`.\n * `flush()` calls `asrStreamFinish` then re-opens a fresh stream for the\n * next segment. Token ids, when the library returns them, are surfaced in\n * `TranscriptUpdate.tokens` — the fused build shares the text vocabulary\n * (AGENTS.md §1) so they feed STT-finish token injection directly.\n *\n * The C side is owned by W7; until the fused build implements these\n * symbols every call throws (the binding maps `ELIZA_ERR_NOT_IMPLEMENTED`\n * to a `VoiceLifecycleError`). That is intentional — no fake transcripts.\n */\nexport class FfiStreamingTranscriber extends BaseStreamingTranscriber {\n\tprivate readonly ffi: ElizaInferenceFfi;\n\tprivate readonly getContext: () => ElizaInferenceContextHandle;\n\t/** Token count to ask the library for per partial; 0 = don't request tokens. */\n\tprivate readonly maxTokens: number;\n\tprivate stream: bigint | null = null;\n\n\tconstructor(args: {\n\t\tffi: ElizaInferenceFfi;\n\t\tgetContext: () => ElizaInferenceContextHandle;\n\t\tvad?: VadEventSource;\n\t\tmetadata?: TranscriptMetadataDefaults;\n\t\tsource?: VoiceInputSource;\n\t\t/** Cap on token ids read back per transcript snapshot. Default 256. */\n\t\tmaxTokens?: number;\n\t}) {\n\t\tsuper(args.vad, {\n\t\t\t...args.metadata,\n\t\t\tsource: args.metadata?.source ?? args.source,\n\t\t});\n\t\tif (!ffiSupportsStreamingAsr(args.ffi)) {\n\t\t\tthrow new AsrUnavailableError(\n\t\t\t\t\"[asr] fused libelizainference does not advertise a working streaming ASR decoder (eliza_inference_asr_stream_supported() == 0) — rebuild the fused omnivoice target or use the fused-batch interim adapter\",\n\t\t\t);\n\t\t}\n\t\tthis.ffi = args.ffi;\n\t\tthis.getContext = args.getContext;\n\t\tthis.maxTokens = Math.max(0, Math.floor(args.maxTokens ?? 256));\n\t}\n\n\tprivate ensureStream(): bigint {\n\t\tif (this.stream !== null) return this.stream;\n\t\tthis.stream = this.ffi.asrStreamOpen({\n\t\t\tctx: this.getContext(),\n\t\t\tsampleRateHz: ASR_SAMPLE_RATE,\n\t\t});\n\t\treturn this.stream;\n\t}\n\n\tprotected onFrame(frame: PcmFrame): void {\n\t\tconst pcm = resampleLinear(frame.pcm, frame.sampleRate, ASR_SAMPLE_RATE);\n\t\tconst handle = this.ensureStream();\n\t\tthis.ffi.asrStreamFeed({ stream: handle, pcm });\n\t\tconst update = this.ffi.asrStreamPartial({\n\t\t\tstream: handle,\n\t\t\tmaxTokens: this.maxTokens,\n\t\t});\n\t\tthis.emitPartial({ ...update, isFinal: false });\n\t}\n\n\tprotected async onFlush(): Promise<TranscriptUpdate> {\n\t\tif (this.stream === null) {\n\t\t\treturn { partial: \"\", isFinal: true };\n\t\t}\n\t\tconst handle = this.stream;\n\t\tconst update = this.ffi.asrStreamFinish({\n\t\t\tstream: handle,\n\t\t\tmaxTokens: this.maxTokens,\n\t\t});\n\t\tthis.ffi.asrStreamClose(handle);\n\t\tthis.stream = null;\n\t\treturn { ...update, isFinal: true };\n\t}\n\n\tprotected onDispose(): void {\n\t\tif (this.stream !== null) {\n\t\t\tthis.ffi.asrStreamClose(this.stream);\n\t\t\tthis.stream = null;\n\t\t}\n\t}\n}\n\n/* ==================================================================== *\n * Fused batch (interim streaming) path — eliza_inference_asr_transcribe.\n * ==================================================================== */\n\nexport interface FfiBatchTranscriberOptions {\n\tffi: ElizaInferenceFfi;\n\tgetContext: () => ElizaInferenceContextHandle;\n\tvad?: VadEventSource;\n\tmetadata?: TranscriptMetadataDefaults;\n\tsource?: VoiceInputSource;\n\t/** Sliding-window length, seconds. Each batch decode covers ≤ this + overlap. Default 6.0. */\n\twindowSeconds?: number;\n\t/** Trailing overlap kept when committing a prefix chunk, seconds. Default 1.0. */\n\toverlapSeconds?: number;\n\t/** Minimum new audio (seconds) accumulated before the next decode pass. Default 1.2. */\n\tstepSeconds?: number;\n}\n\n/**\n * Interim streaming-ASR adapter over the fused `libelizainference` **batch**\n * decoder (`eliza_inference_asr_transcribe`, ABI v1). The fused build's true\n * streaming decoder (`eliza_inference_asr_stream_*`, ABI v2) reports unsupported\n * until its runtime lands; this adapter is the contract-clean interim — it runs\n * inside the one shipped llama.cpp/GGML build and emits\n * Gemma token-vocab text, so no second ggml is vendored and no\n * tokenizer-family mismatch is introduced.\n *\n * It runs a *windowed re-transcription with overlap* strategy: a prefix older\n * than `windowSeconds` is committed (decoded once, in window-sized chunks\n * with `overlapSeconds` carry-over) and only the tail window is re-decoded\n * each step. So each `asr_transcribe` call is bounded by `windowSeconds +\n * overlap` of audio (≈6–7 s) — incremental, not \"buffer the whole utterance,\n * run one giant batch decode\". Decodes run serially on the shared ASR mutex\n * (the fused context's ASR region is single-threaded).\n *\n * Requires `ffi.mmapAcquire(ctx, \"asr\")` to have been called on `getContext()`\n * — the `EngineVoiceBridge` lifecycle does this when voice input is armed.\n */\nexport class FfiBatchTranscriber extends BaseStreamingTranscriber {\n\tprivate readonly ffi: ElizaInferenceFfi;\n\tprivate readonly getContext: () => ElizaInferenceContextHandle;\n\tprivate readonly windowSamples: number;\n\tprivate readonly overlapSamples: number;\n\tprivate readonly stepSamples: number;\n\t/** All 16 kHz samples accumulated for the current speech segment. */\n\tprivate buf: Float32Array = new Float32Array(0);\n\t/** Samples in `buf` already folded into `committed`. */\n\tprivate committedSamples = 0;\n\t/** Text decoded from `buf[0 .. committedSamples)`. */\n\tprivate committed = \"\";\n\t/** `buf.length` at the last decode pass — throttles to `stepSamples`. */\n\tprivate lastDecodeAt = 0;\n\t/** Decode chain — `asr_transcribe` calls serialize on the native ASR mutex anyway. */\n\tprivate decodeChain: Promise<void> = Promise.resolve();\n\n\tconstructor(opts: FfiBatchTranscriberOptions) {\n\t\tsuper(opts.vad, {\n\t\t\t...opts.metadata,\n\t\t\tsource: opts.metadata?.source ?? opts.source,\n\t\t});\n\t\tthis.ffi = opts.ffi;\n\t\tthis.getContext = opts.getContext;\n\t\tconst windowSeconds = opts.windowSeconds ?? 6.0;\n\t\tconst overlapSeconds = Math.min(opts.overlapSeconds ?? 1.0, windowSeconds);\n\t\tconst stepSeconds = opts.stepSeconds ?? 1.2;\n\t\tthis.windowSamples = Math.round(windowSeconds * ASR_SAMPLE_RATE);\n\t\tthis.overlapSamples = Math.round(overlapSeconds * ASR_SAMPLE_RATE);\n\t\tthis.stepSamples = Math.round(stepSeconds * ASR_SAMPLE_RATE);\n\t}\n\n\tprivate decodeWindow(pcm16k: Float32Array): string {\n\t\tif (pcm16k.length === 0) return \"\";\n\t\treturn this.ffi\n\t\t\t.asrTranscribe({\n\t\t\t\tctx: this.getContext(),\n\t\t\t\tpcm: pcm16k,\n\t\t\t\tsampleRateHz: ASR_SAMPLE_RATE,\n\t\t\t})\n\t\t\t.trim();\n\t}\n\n\tprotected onFrame(frame: PcmFrame): void {\n\t\tconst pcm = resampleLinear(frame.pcm, frame.sampleRate, ASR_SAMPLE_RATE);\n\t\tthis.buf = concatFloat32(this.buf, pcm);\n\t\tif (this.buf.length - this.lastDecodeAt < this.stepSamples) return;\n\t\tthis.lastDecodeAt = this.buf.length;\n\t\tthis.scheduleDecode(false);\n\t}\n\n\tprotected async onFlush(): Promise<TranscriptUpdate> {\n\t\tthis.scheduleDecode(true);\n\t\tawait this.decodeChain;\n\t\tconst final = this.committed.trim();\n\t\tthis.resetSegment();\n\t\treturn { partial: final, isFinal: true };\n\t}\n\n\tprotected onDispose(): void {\n\t\tthis.resetSegment();\n\t}\n\n\tprivate resetSegment(): void {\n\t\tthis.buf = new Float32Array(0);\n\t\tthis.committedSamples = 0;\n\t\tthis.committed = \"\";\n\t\tthis.lastDecodeAt = 0;\n\t}\n\n\tprivate scheduleDecode(final: boolean): void {\n\t\tthis.decodeChain = this.decodeChain.then(() => this.runDecode(final));\n\t}\n\n\tprivate async runDecode(final: boolean): Promise<void> {\n\t\tconst total = this.buf.length;\n\t\tif (total <= this.committedSamples && !final) return;\n\n\t\t// Commit any prefix that has scrolled fully out of the sliding window.\n\t\twhile (total - this.committedSamples > this.windowSamples) {\n\t\t\tconst chunkEnd = Math.min(\n\t\t\t\ttotal,\n\t\t\t\tthis.committedSamples + this.windowSamples,\n\t\t\t);\n\t\t\tconst chunk = this.buf.subarray(this.committedSamples, chunkEnd);\n\t\t\tconst text = this.decodeWindow(chunk);\n\t\t\tthis.committed = joinTranscriptParts(this.committed, text);\n\t\t\tconst advance = Math.max(1, this.windowSamples - this.overlapSamples);\n\t\t\tthis.committedSamples = Math.min(total, this.committedSamples + advance);\n\t\t}\n\n\t\tconst tail = this.buf.subarray(this.committedSamples, total);\n\t\tconst tailText = this.decodeWindow(tail);\n\n\t\tif (final) {\n\t\t\tthis.committed = joinTranscriptParts(this.committed, tailText);\n\t\t\tthis.committedSamples = total;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.emitPartial({\n\t\t\tpartial: joinTranscriptParts(this.committed, tailText).trim(),\n\t\t\tisFinal: false,\n\t\t});\n\t}\n}\n\nfunction concatFloat32(a: Float32Array, b: Float32Array): Float32Array {\n\tif (a.length === 0) return b.slice();\n\tif (b.length === 0) return a;\n\tconst out = new Float32Array(a.length + b.length);\n\tout.set(a, 0);\n\tout.set(b, a.length);\n\treturn out;\n}\n\n/**\n * Join two transcript fragments, collapsing the seam: drop a trailing\n * partial-word from `head` if `tail` begins mid-word (overlap re-decode\n * can split a word at the chunk boundary). Conservative — only trims when\n * both sides clearly continue the same token-ish run.\n */\nfunction joinTranscriptParts(head: string, tail: string): string {\n\tconst h = head.trimEnd();\n\tconst t = tail.trimStart();\n\tif (!h) return t;\n\tif (!t) return h;\n\t// If `tail` starts with a continuation of `head`'s last word, prefer\n\t// `tail`'s spelling of the overlap region: drop `head`'s last word when\n\t// `tail`'s first word starts with the same prefix (case-insensitive).\n\tconst headLast = h.match(/[\\p{L}\\p{N}'-]+$/u)?.[0] ?? \"\";\n\tconst tailFirst = t.match(/^[\\p{L}\\p{N}'-]+/u)?.[0] ?? \"\";\n\tif (headLast && tailFirst?.toLowerCase().startsWith(headLast.toLowerCase())) {\n\t\treturn `${h.slice(0, h.length - headLast.length).trimEnd()} ${t}`.trim();\n\t}\n\treturn `${h} ${t}`;\n}\n\n/* ==================================================================== *\n * Adapter selection.\n * ==================================================================== */\n\nexport interface CreateStreamingTranscriberOptions {\n\t/** Fused FFI handle (when a `libelizainference` build is loaded), else null. */\n\tffi?: ElizaInferenceFfi | null;\n\t/** Provider for the fused context pointer (the bridge owns the lazy create). */\n\tgetContext?: () => ElizaInferenceContextHandle;\n\t/**\n\t * Whether a bundled ASR model directory is present. The fused path is\n\t * only chosen when this is true AND the library advertises streaming\n\t * ASR.\n\t */\n\tasrBundlePresent?: boolean;\n\t/** VAD event stream to gate decoding (W1). */\n\tvad?: VadEventSource;\n\t/** Optional attribution metadata stamped onto emitted transcript updates. */\n\tmetadata?: TranscriptMetadataDefaults;\n\t/** Convenience shorthand for `metadata.source`. */\n\tsource?: VoiceInputSource;\n\t/** Fused-batch-interim window/step overrides (see `FfiBatchTranscriber`). */\n\tffiBatch?: Omit<FfiBatchTranscriberOptions, \"ffi\" | \"getContext\">;\n\t/**\n\t * Force a specific fused backend.\n\t * `\"fused\"` → fused streaming ASR only (throws if unavailable),\n\t * `\"ffi-batch\"` → fused batch (interim) only (throws if unavailable),\n\t * `\"auto\"` (default) → fused streaming → fused batch → throw.\n\t */\n\tprefer?: AsrBackendPreference;\n}\n\n/**\n * Resolve the fused ASR adapter chain:\n * 1. fused streaming ASR (`eliza_inference_asr_stream_*`, ABI v2 — the FINAL\n * path, W7),\n * 2. fused batch (interim) — windowed `eliza_inference_asr_transcribe` (ABI\n * v1); contract-clean (one ggml, shared text vocab) and available now.\n *\n * The fused `libelizainference` build is the SOLE on-device ASR runtime. There\n * is no whisper.cpp (or other second-runtime) fallback: if no fused decoder is\n * available the caller gets a hard, actionable failure (AGENTS.md §3 + §9) —\n * never a silent empty transcript.\n */\nexport function createStreamingTranscriber(\n\topts: CreateStreamingTranscriberOptions = {},\n): StreamingTranscriber {\n\tconst prefer = opts.prefer ?? readAsrBackendPreferenceFromEnv() ?? \"auto\";\n\n\tconst tryFusedStreaming = (): StreamingTranscriber | null => {\n\t\tif (!opts.ffi || !opts.getContext) return null;\n\t\tif (!opts.asrBundlePresent) return null;\n\t\tif (!ffiSupportsStreamingAsr(opts.ffi)) return null;\n\t\treturn new FfiStreamingTranscriber({\n\t\t\tffi: opts.ffi,\n\t\t\tgetContext: opts.getContext,\n\t\t\tvad: opts.vad,\n\t\t\tmetadata: opts.metadata,\n\t\t\tsource: opts.source,\n\t\t});\n\t};\n\n\tconst tryFusedBatch = (): StreamingTranscriber | null => {\n\t\tif (!opts.ffi || !opts.getContext) return null;\n\t\tif (!opts.asrBundlePresent) return null;\n\t\tif (typeof opts.ffi.asrTranscribe !== \"function\") return null;\n\t\treturn new FfiBatchTranscriber({\n\t\t\t...opts.ffiBatch,\n\t\t\tffi: opts.ffi,\n\t\t\tgetContext: opts.getContext,\n\t\t\tvad: opts.vad,\n\t\t\tmetadata: opts.metadata,\n\t\t\tsource: opts.source,\n\t\t});\n\t};\n\n\tif (prefer === \"fused\") {\n\t\tconst fused = tryFusedStreaming();\n\t\tif (fused) return fused;\n\t\tthrow new AsrUnavailableError(\n\t\t\t\"[asr] fused streaming ASR was requested but is not available (no libelizainference handle, no bundled ASR model, or the build does not export eliza_inference_asr_stream_*)\",\n\t\t);\n\t}\n\tif (prefer === \"ffi-batch\") {\n\t\tconst batch = tryFusedBatch();\n\t\tif (batch) return batch;\n\t\tthrow new AsrUnavailableError(\n\t\t\t\"[asr] fused batch ASR was requested but is not available (no libelizainference handle, no bundled ASR model, or the build does not export eliza_inference_asr_transcribe)\",\n\t\t);\n\t}\n\n\t// auto\n\tconst fused = tryFusedStreaming();\n\tif (fused) return fused;\n\tconst batch = tryFusedBatch();\n\tif (batch) return batch;\n\n\tthrow new AsrUnavailableError(\n\t\t\"[asr] no fused ASR decoder available — load the fused libelizainference build with a bundled ASR model (eliza_inference_asr_stream_* / eliza_inference_asr_transcribe). The fused build is the sole on-device ASR runtime; there is no whisper.cpp fallback.\",\n\t);\n}\n",
18
+ "/**\n * Voice Workbench corpus generator (#8785).\n *\n * Turns a declarative {@link VoiceScenario} into one labeled audio stream + a\n * ground-truth JSON the headless runner scores against. Two synthesis paths,\n * one shape:\n *\n * - Synthetic (default, deterministic, NO native model): formant-resonator\n * speech-like PCM (`__test-helpers__/synthetic-speech.ts`) the Silero VAD\n * reads as speech. Reproducible in CI with no artifacts — it exercises the\n * pipeline plumbing + the scorers/labels, not diarization/WER *accuracy*.\n * - Real TTS (gated): an injected {@link CorpusTtsSynthesizer} (Kokoro /\n * OmniVoice via the TTS route) produces natural speech. Real diarization\n * DER and transcription WER benchmarking need this path.\n *\n * `generateVoiceCorpus` is pure (no I/O) so it is unit-testable without disk;\n * `writeVoiceCorpus` / `readVoiceCorpus` handle the versioned on-disk corpus.\n * A turn's labels (speaker, transcript, respond decision, entity) come straight\n * from the scenario, so the ground truth is reproducible regardless of path.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport {\n\tAGENT_VOICE_TIMBRE,\n\tmakeSpeechWithSilenceFixture,\n\ttype SpeakerTimbre,\n\tspeakerTimbreForIndex,\n} from \"./__test-helpers__/synthetic-speech\";\nimport {\n\ttype AugmentationSpec,\n\taugmentPcm,\n\tspecIsClean,\n} from \"./corpus-augment\";\nimport {\n\tresolveTurnEnvironment,\n\tturnReferenceTranscript,\n\tturnSpeakerLabel,\n\ttype VoiceEnvironment,\n\ttype VoiceScenario,\n\tvalidateVoiceScenario,\n} from \"./voice-scenario\";\nimport { encodeMonoPcm16Wav } from \"./wav-codec\";\n\nconst DEFAULT_SAMPLE_RATE = 16_000;\n/** Natural speaking rate used to size synthetic speech from text length. */\nconst DEFAULT_CHARS_PER_SECOND = 13;\nconst DEFAULT_INTER_TURN_SILENCE_SEC = 0.4;\nconst MIN_SPEECH_SEC = 0.4;\n/** Cap a single synthetic turn (long-form monologue still lands well under). */\nconst MAX_SPEECH_SEC = 45;\nconst SYNTHETIC_LEAD_SILENCE_SEC = 0.15;\nconst SYNTHETIC_TAIL_SILENCE_SEC = 0.15;\n\n/** Per-turn ground-truth label with sample-accurate timing. */\nexport interface CorpusTurnLabel {\n\tindex: number;\n\t/** Diarization ground-truth label (the participant who spoke). */\n\tspeaker: string;\n\t/** Resolved elizaOS entity id for the speaker, when the scenario binds one. */\n\tentityId?: string;\n\t/** First sample of voiced speech in this turn (after any lead silence). */\n\tspeechStartSample: number;\n\t/** Sample just past the voiced speech (before trailing pauses). */\n\tspeechEndSample: number;\n\t/** First sample of this turn's whole segment in the stream. */\n\tsegmentStartSample: number;\n\t/** Sample just past this turn's whole segment (incl. trailing pauses). */\n\tsegmentEndSample: number;\n\t/** Reference transcript for WER scoring. */\n\treferenceTranscript: string;\n\t/** Ground truth: should the agent respond to this turn? */\n\texpectRespond: boolean;\n\t/** Ground truth: is this segment a real end-of-turn boundary? */\n\texpectEndOfTurn?: boolean;\n\t/** Expected inferred/recognized entity, when the scenario asserts one. */\n\texpectedEntity?: string;\n\t/** TTS voice id used for this turn (real-TTS path), when set. */\n\tttsVoiceId?: string;\n\t/** True when this turn was formant-synthesized rather than real TTS. */\n\tsynthetic: boolean;\n\t/** Acoustic degradation applied to this turn's audio (when any). */\n\tenvironment?: VoiceEnvironment;\n\t/** True when this \"turn\" is the agent's own TTS echoed back (not a user turn). */\n\tisAgentEcho?: boolean;\n\t/** Ground truth: the speaker is the device owner / primary enrolled voice. */\n\tisOwner?: boolean;\n\t/** The agent's spoken reply to this turn (drives the echo gate downstream). */\n\tagentReplyText?: string;\n}\n\n/**\n * On-disk corpus ground-truth schema version. Bump when the labeled-corpus\n * shape changes incompatibly; `readVoiceCorpusGroundTruth` treats a corpus\n * written by a different version as absent (→ `skipped`, never a stale `pass`).\n */\nexport const CORPUS_SCHEMA_VERSION = 1;\n\nexport interface CorpusGroundTruth {\n\t/** Labeled-corpus schema version (see {@link CORPUS_SCHEMA_VERSION}). */\n\tschemaVersion: number;\n\tscenarioId: string;\n\tclasses: VoiceScenario[\"classes\"];\n\tsampleRate: number;\n\ttotalSamples: number;\n\tdurationSec: number;\n\tparticipants: Array<{\n\t\tlabel: string;\n\t\tentityId?: string;\n\t\tisOwner?: boolean;\n\t\tttsVoiceId?: string;\n\t}>;\n\tagents?: string[];\n\t/** Entity ids the agent answers without a wake word (owner + enrolled). */\n\tknownSpeakerEntityIds?: string[];\n\tturns: CorpusTurnLabel[];\n\t/** True when EVERY turn was synthetic (no real TTS used anywhere). */\n\tsynthetic: boolean;\n}\n\nexport interface GeneratedVoiceCorpus {\n\tpcm: Float32Array;\n\tsampleRate: number;\n\tgroundTruth: CorpusGroundTruth;\n}\n\n/**\n * Real-TTS synthesizer. Gated: when omitted, the generator uses deterministic\n * synthetic speech. An implementation wraps the TTS route / Kokoro engine and\n * returns mono PCM at the requested sample rate.\n */\nexport interface CorpusTtsSynthesizer {\n\tsynthesize(args: {\n\t\ttext: string;\n\t\tvoiceId?: string;\n\t\tspeakerLabel: string;\n\t\tturnIndex: number;\n\t\tisAgentEcho: boolean;\n\t\tsampleRate: number;\n\t}): Promise<Float32Array>;\n}\n\nexport interface GenerateVoiceCorpusOptions {\n\tsampleRate?: number;\n\t/** Inject a real-TTS synthesizer to produce natural speech (else synthetic). */\n\tsynthesizer?: CorpusTtsSynthesizer;\n\t/** Silence (s) spliced after a turn that declares no explicit pauses. */\n\tinterTurnSilenceSec?: number;\n\t/** Synthetic-speech sizing: characters of text per second of audio. */\n\tcharsPerSecond?: number;\n}\n\n/** Deterministic 32-bit FNV-1a of a label → a stable per-speaker synthesis seed. */\nfunction labelSeed(label: string): number {\n\tlet h = 0x811c9dc5;\n\tfor (let i = 0; i < label.length; i++) {\n\t\th ^= label.charCodeAt(i);\n\t\th = Math.imul(h, 0x01000193);\n\t}\n\treturn h >>> 0;\n}\n\nfunction silenceSamples(ms: number, sampleRate: number): number {\n\treturn Math.max(0, Math.round((ms / 1000) * sampleRate));\n}\n\n/**\n * A continuous competing-talker stream for `backgroundTalkersDb`, built from\n * formant-synth speech (no models) so it is deterministic. `augmentPcm` mixes +\n * loops it under the real turn at the requested level.\n */\nfunction synthesizeBabble(\n\tsampleRate: number,\n\tlengthSamples: number,\n\tseed: number,\n): Float32Array {\n\tconst fixture = makeSpeechWithSilenceFixture({\n\t\tsampleRate,\n\t\tleadSilenceSec: 0,\n\t\tspeechSec: Math.max(0.3, lengthSamples / sampleRate),\n\t\ttailSilenceSec: 0,\n\t\tseed,\n\t});\n\treturn fixture.pcm;\n}\n\n/**\n * Generate one labeled audio stream for a scenario. Throws on an invalid\n * scenario (fail loud — a malformed corpus must not silently produce garbage).\n * A turn that carries only `audioRef` (no `text`) is not synthesizable here and\n * is rejected; pre-rendered audio is supplied through the corpus on disk.\n */\nexport async function generateVoiceCorpus(\n\tscenario: VoiceScenario,\n\toptions: GenerateVoiceCorpusOptions = {},\n): Promise<GeneratedVoiceCorpus> {\n\tconst validation = validateVoiceScenario(scenario);\n\tif (!validation.valid) {\n\t\tthrow new Error(\n\t\t\t`[voice-corpus] invalid scenario \"${scenario.id}\": ${validation.errors.join(\"; \")}`,\n\t\t);\n\t}\n\n\tconst sampleRate = options.sampleRate ?? DEFAULT_SAMPLE_RATE;\n\tconst charsPerSecond = options.charsPerSecond ?? DEFAULT_CHARS_PER_SECOND;\n\tconst interTurnSilence = silenceSamples(\n\t\t(options.interTurnSilenceSec ?? DEFAULT_INTER_TURN_SILENCE_SEC) * 1000,\n\t\tsampleRate,\n\t);\n\tconst synthesizer = options.synthesizer;\n\n\tconst participantByLabel = new Map(\n\t\tscenario.participants.map((p) => [p.label, p]),\n\t);\n\t// Each participant gets a distinct voice colour, spread evenly across the\n\t// timbre range so a blind acoustic diarizer can tell co-present speakers apart\n\t// from the audio alone (#9427).\n\tconst timbreByLabel = new Map<string, SpeakerTimbre>(\n\t\tscenario.participants.map((p, i) => [\n\t\t\tp.label,\n\t\t\tspeakerTimbreForIndex(i, scenario.participants.length),\n\t\t]),\n\t);\n\n\tconst segments: Float32Array[] = [];\n\tconst labels: CorpusTurnLabel[] = [];\n\tlet cursor = 0;\n\tlet anyReal = false;\n\n\tfor (let i = 0; i < scenario.turns.length; i++) {\n\t\tconst turn = scenario.turns[i];\n\t\tconst text = turn.text?.trim();\n\t\tif (!text) {\n\t\t\tthrow new Error(\n\t\t\t\t`[voice-corpus] turn[${i}] of \"${scenario.id}\" has no text to synthesize (audioRef-only turns are supplied via the on-disk corpus, not generated)`,\n\t\t\t);\n\t\t}\n\t\tconst participant = participantByLabel.get(turn.speaker);\n\t\tconst ttsVoiceId = turn.ttsVoiceId ?? participant?.ttsVoiceId;\n\n\t\tconst segmentStartSample = cursor;\n\t\tlet speech: Float32Array;\n\t\tlet speechStartOffset: number;\n\t\tlet speechEndOffset: number;\n\t\tlet synthetic: boolean;\n\n\t\tif (synthesizer) {\n\t\t\tspeech = await synthesizer.synthesize({\n\t\t\t\ttext,\n\t\t\t\tvoiceId: ttsVoiceId,\n\t\t\t\tspeakerLabel: turn.speaker,\n\t\t\t\tturnIndex: i,\n\t\t\t\tisAgentEcho: turn.isAgentEcho === true,\n\t\t\t\tsampleRate,\n\t\t\t});\n\t\t\tspeechStartOffset = 0;\n\t\t\tspeechEndOffset = speech.length;\n\t\t\tsynthetic = false;\n\t\t\tanyReal = true;\n\t\t} else {\n\t\t\tconst speechSec = Math.min(\n\t\t\t\tMAX_SPEECH_SEC,\n\t\t\t\tMath.max(MIN_SPEECH_SEC, text.length / charsPerSecond),\n\t\t\t);\n\t\t\t// An agent-echo turn is the agent's OWN TTS bleeding back through the\n\t\t\t// mic, so it carries the agent's voice — not the labelled speaker's. Real\n\t\t\t// speaker turns get their distinct per-speaker timbre (#9427).\n\t\t\tconst timbre = turn.isAgentEcho\n\t\t\t\t? AGENT_VOICE_TIMBRE\n\t\t\t\t: (timbreByLabel.get(turn.speaker) ?? AGENT_VOICE_TIMBRE);\n\t\t\tconst fixture = makeSpeechWithSilenceFixture({\n\t\t\t\tsampleRate,\n\t\t\t\tleadSilenceSec: SYNTHETIC_LEAD_SILENCE_SEC,\n\t\t\t\tspeechSec,\n\t\t\t\ttailSilenceSec: SYNTHETIC_TAIL_SILENCE_SEC,\n\t\t\t\tseed: labelSeed(turn.isAgentEcho ? \"__agent__\" : turn.speaker),\n\t\t\t\ttimbre,\n\t\t\t});\n\t\t\tspeech = fixture.pcm;\n\t\t\tspeechStartOffset = fixture.speechStartSample;\n\t\t\tspeechEndOffset = fixture.speechEndSample;\n\t\t\tsynthetic = true;\n\t\t}\n\n\t\t// Trailing pauses: explicit per-turn gaps, else the default inter-turn gap\n\t\t// (except after the final turn).\n\t\tconst pauseTotal =\n\t\t\tturn.pausesMs && turn.pausesMs.length > 0\n\t\t\t\t? turn.pausesMs.reduce((n, ms) => n + silenceSamples(ms, sampleRate), 0)\n\t\t\t\t: i < scenario.turns.length - 1\n\t\t\t\t\t? interTurnSilence\n\t\t\t\t\t: 0;\n\n\t\t// Assemble the turn's full segment (voiced speech + trailing pause) so the\n\t\t// per-turn acoustic degradation — reverb ringing into the gap, a noise\n\t\t// floor in the \"silence\" — covers the pause, not just the speech.\n\t\tlet segment: Float32Array = new Float32Array(speech.length + pauseTotal);\n\t\tsegment.set(speech, 0);\n\n\t\tconst env = resolveTurnEnvironment(scenario, turn);\n\t\tlet appliedEnv: VoiceEnvironment | undefined;\n\t\tif (env && !specIsClean(env)) {\n\t\t\tconst seed =\n\t\t\t\tenv.seed ?? (labelSeed(scenario.id) ^ (i * 0x9e3779b1)) >>> 0;\n\t\t\tconst resolvedEnv: AugmentationSpec = { ...env, seed };\n\t\t\tconst babble =\n\t\t\t\tresolvedEnv.backgroundTalkersDb !== undefined\n\t\t\t\t\t? synthesizeBabble(sampleRate, segment.length, (seed ^ 0x1234) >>> 0)\n\t\t\t\t\t: undefined;\n\t\t\tsegment = augmentPcm(segment, sampleRate, resolvedEnv, {\n\t\t\t\t...(babble ? { babble } : {}),\n\t\t\t});\n\t\t\tappliedEnv = resolvedEnv;\n\t\t}\n\n\t\tsegments.push(segment);\n\t\tcursor += segment.length;\n\n\t\tlabels.push({\n\t\t\tindex: i,\n\t\t\tspeaker: turnSpeakerLabel(turn),\n\t\t\t...(participant?.entityId ? { entityId: participant.entityId } : {}),\n\t\t\tspeechStartSample: segmentStartSample + speechStartOffset,\n\t\t\tspeechEndSample: segmentStartSample + speechEndOffset,\n\t\t\tsegmentStartSample,\n\t\t\tsegmentEndSample: cursor,\n\t\t\treferenceTranscript: turnReferenceTranscript(turn),\n\t\t\texpectRespond: turn.isAgentEcho ? false : turn.expectRespond,\n\t\t\texpectEndOfTurn: turn.expectEndOfTurn ?? true,\n\t\t\t...(turn.expectedEntity ? { expectedEntity: turn.expectedEntity } : {}),\n\t\t\t...(ttsVoiceId ? { ttsVoiceId } : {}),\n\t\t\tsynthetic,\n\t\t\t...(appliedEnv ? { environment: appliedEnv } : {}),\n\t\t\t...(turn.isAgentEcho ? { isAgentEcho: true } : {}),\n\t\t\t...(participant?.isOwner ? { isOwner: true } : {}),\n\t\t\t...(turn.agentReplyText ? { agentReplyText: turn.agentReplyText } : {}),\n\t\t});\n\t}\n\n\tconst pcm = new Float32Array(cursor);\n\tlet offset = 0;\n\tfor (const segment of segments) {\n\t\tpcm.set(segment, offset);\n\t\toffset += segment.length;\n\t}\n\n\tconst groundTruth: CorpusGroundTruth = {\n\t\tschemaVersion: CORPUS_SCHEMA_VERSION,\n\t\tscenarioId: scenario.id,\n\t\tclasses: scenario.classes,\n\t\tsampleRate,\n\t\ttotalSamples: pcm.length,\n\t\tdurationSec: pcm.length / sampleRate,\n\t\tparticipants: scenario.participants.map((p) => ({\n\t\t\tlabel: p.label,\n\t\t\t...(p.entityId ? { entityId: p.entityId } : {}),\n\t\t\t...(p.isOwner ? { isOwner: p.isOwner } : {}),\n\t\t\t...(p.ttsVoiceId ? { ttsVoiceId: p.ttsVoiceId } : {}),\n\t\t})),\n\t\t...(scenario.agents ? { agents: scenario.agents } : {}),\n\t\t...(scenario.knownSpeakerEntityIds\n\t\t\t? { knownSpeakerEntityIds: scenario.knownSpeakerEntityIds }\n\t\t\t: {}),\n\t\tturns: labels,\n\t\tsynthetic: !anyReal,\n\t};\n\n\treturn { pcm, sampleRate, groundTruth };\n}\n\nexport interface VoiceCorpusPaths {\n\tdir: string;\n\taudioPath: string;\n\tgroundTruthPath: string;\n}\n\n/** Persist a generated corpus as `audio.wav` + `ground-truth.json` under `dir`. */\nexport function writeVoiceCorpus(\n\tcorpus: GeneratedVoiceCorpus,\n\tdir: string,\n): VoiceCorpusPaths {\n\tmkdirSync(dir, { recursive: true });\n\tconst audioPath = path.join(dir, \"audio.wav\");\n\tconst groundTruthPath = path.join(dir, \"ground-truth.json\");\n\twriteFileSync(audioPath, encodeMonoPcm16Wav(corpus.pcm, corpus.sampleRate));\n\twriteFileSync(\n\t\tgroundTruthPath,\n\t\t`${JSON.stringify(corpus.groundTruth, null, 2)}\\n`,\n\t);\n\treturn { dir, audioPath, groundTruthPath };\n}\n\n/**\n * Read a previously-written corpus's ground truth. Returns null when the corpus\n * directory or its ground-truth file is absent (the honesty contract — the\n * runner reports `skipped`, never `pass`, when corpus artifacts are missing).\n */\nexport function readVoiceCorpusGroundTruth(\n\tdir: string,\n): CorpusGroundTruth | null {\n\tconst groundTruthPath = path.join(dir, \"ground-truth.json\");\n\tif (!existsSync(groundTruthPath)) return null;\n\tconst parsed = JSON.parse(readFileSync(groundTruthPath, \"utf8\")) as unknown;\n\tif (!parsed || typeof parsed !== \"object\") return null;\n\t// Honesty contract: a corpus written by an incompatible schema version is\n\t// treated as absent (→ skipped, never a stale pass against drifted labels).\n\tif (\n\t\t(parsed as { schemaVersion?: unknown }).schemaVersion !==\n\t\tCORPUS_SCHEMA_VERSION\n\t)\n\t\treturn null;\n\treturn parsed as CorpusGroundTruth;\n}\n",
19
+ "/**\n * Deterministic-ish speech-like audio generator for VAD/wake-word smoke\n * tests. Pure synthesis (glottal pulse train through a three-formant\n * resonator bank with a syllable-rate amplitude envelope and mild f0\n * jitter) — close enough to real speech in the time/frequency domain that\n * the Silero VAD reads it as speech, without shipping a recorded WAV.\n *\n * `silence + speech + silence` is the canonical smoke fixture: the VAD\n * should detect exactly one speech segment whose boundaries land inside\n * the voiced region, and `VadDetector` should drop the leading/trailing\n * silence windows from its speech-state timeline.\n */\n\nexport interface SpeechFixtureOptions {\n\tsampleRate?: number;\n\t/** Seconds of leading silence. */\n\tleadSilenceSec?: number;\n\t/** Seconds of synthesized speech. */\n\tspeechSec?: number;\n\t/** Seconds of trailing silence. */\n\ttailSilenceSec?: number;\n\t/** Deterministic seed for the f0 jitter. */\n\tseed?: number;\n\t/**\n\t * Per-speaker voice colour. Two speakers with different timbres have\n\t * measurably different spectral envelopes, so an acoustic diarizer can tell\n\t * them apart from the audio alone. Omit for the default (shared) voice — the\n\t * VAD/wake-word smoke fixtures don't care who is speaking.\n\t */\n\ttimbre?: SpeakerTimbre;\n}\n\n/** A speaker's voice colour: fundamental frequency + vocal-tract formants. */\nexport interface SpeakerTimbre {\n\t/** Base fundamental frequency (Hz) — speaker pitch. */\n\tf0Hz: number;\n\t/** Three `[centerHz, bandwidthHz]` formants — the vocal-tract resonances. */\n\tformants: ReadonlyArray<readonly [number, number]>;\n}\n\nexport interface SpeechFixture {\n\tpcm: Float32Array;\n\tsampleRate: number;\n\tspeechStartSample: number;\n\tspeechEndSample: number;\n}\n\nfunction mulberry32(seed: number): () => number {\n\tlet a = seed >>> 0;\n\treturn () => {\n\t\ta |= 0;\n\t\ta = (a + 0x6d2b79f5) | 0;\n\t\tlet t = Math.imul(a ^ (a >>> 15), 1 | a);\n\t\tt = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/** A three-formant resonator bank state. */\nclass FormantBank {\n\tprivate readonly r: number[];\n\tprivate readonly a1: number[];\n\tprivate readonly a2: number[];\n\tprivate readonly z1: number[];\n\tprivate readonly z2: number[];\n\tconstructor(\n\t\tsampleRate: number,\n\t\tformants: ReadonlyArray<readonly [number, number]>,\n\t) {\n\t\tthis.r = [];\n\t\tthis.a1 = [];\n\t\tthis.a2 = [];\n\t\tthis.z1 = [];\n\t\tthis.z2 = [];\n\t\tfor (const [fc, bw] of formants) {\n\t\t\tconst r = Math.exp((-Math.PI * bw) / sampleRate);\n\t\t\tconst theta = (2 * Math.PI * fc) / sampleRate;\n\t\t\tthis.r.push(r);\n\t\t\tthis.a1.push(-2 * r * Math.cos(theta));\n\t\t\tthis.a2.push(r * r);\n\t\t\tthis.z1.push(0);\n\t\t\tthis.z2.push(0);\n\t\t}\n\t}\n\tstep(excitation: number): number {\n\t\tlet v = 0;\n\t\tfor (let k = 0; k < this.r.length; k++) {\n\t\t\tconst y = excitation - this.a1[k] * this.z1[k] - this.a2[k] * this.z2[k];\n\t\t\tthis.z2[k] = this.z1[k];\n\t\t\tthis.z1[k] = y;\n\t\t\tv += y * (1 - k * 0.25);\n\t\t}\n\t\treturn v;\n\t}\n}\n\nconst DEFAULT_FORMANTS: ReadonlyArray<readonly [number, number]> = [\n\t[700, 80],\n\t[1220, 90],\n\t[2600, 120],\n];\n\n/** The shared (speaker-agnostic) voice used when no `timbre` is supplied. */\nexport const DEFAULT_SPEAKER_TIMBRE: SpeakerTimbre = {\n\tf0Hz: 110,\n\tformants: DEFAULT_FORMANTS,\n};\n\n/**\n * Deterministic, distinct voice colour for participant `index` of `count`\n * speakers in a scenario. The speakers are spread EVENLY across a wide\n * vocal-tract-length (formant-scaling) and pitch range, so every pair in a\n * scenario is acoustically far apart — a blind acoustic diarizer can split them\n * from the audio alone — while one participant always gets one timbre, so the\n * same speaker clusters together. Spreading by position (not by a label hash)\n * guarantees the separation; two labels could otherwise hash to near-identical\n * voices and merge.\n */\nexport function speakerTimbreForIndex(\n\tindex: number,\n\tcount: number,\n): SpeakerTimbre {\n\tconst frac = count <= 1 ? 0.5 : index / (count - 1); // 0..1\n\t// Vocal-tract scaling 0.72..1.32 (shorter tract → higher formants).\n\tconst formantScale = 0.72 + frac * 0.6;\n\t// Alternate the second formant up/down so even adjacent slots differ in\n\t// formant PATTERN (F2 is the most speaker-discriminative resonance), not just\n\t// a global shift.\n\tconst f2Bias = index % 2 === 0 ? 1.06 : 0.94;\n\tconst formants = DEFAULT_FORMANTS.map(([fc, bw], i) => {\n\t\tconst bias = i === 1 ? f2Bias : 1;\n\t\treturn [fc * formantScale * bias, bw] as const;\n\t});\n\t// Pitch 98..202 Hz.\n\tconst f0Hz = 98 + frac * 104;\n\treturn { f0Hz, formants };\n}\n\n/**\n * The agent's own synthetic TTS voice — a fixed timbre, deliberately placed\n * outside the speaker-seed range so it is acoustically distinct from every\n * scenario participant. The corpus synthesizes agent-echo turns with this voice,\n * and the acoustic self-voice gate enrolls it as the agent's imprint.\n */\nexport const AGENT_VOICE_TIMBRE: SpeakerTimbre = {\n\tf0Hz: 250,\n\tformants: [\n\t\t[1100, 90],\n\t\t[2400, 110],\n\t\t[3800, 150],\n\t],\n};\n\n/** Build a `silence + synthesized speech + silence` PCM buffer. */\nexport function makeSpeechWithSilenceFixture(\n\topts: SpeechFixtureOptions = {},\n): SpeechFixture {\n\tconst sampleRate = opts.sampleRate ?? 16_000;\n\tconst leadSec = opts.leadSilenceSec ?? 0.5;\n\tconst speechSec = opts.speechSec ?? 1.2;\n\tconst tailSec = opts.tailSilenceSec ?? 0.5;\n\tconst totalSec = leadSec + speechSec + tailSec;\n\tconst n = Math.floor(totalSec * sampleRate);\n\tconst pcm = new Float32Array(n);\n\tconst speechStartSample = Math.floor(leadSec * sampleRate);\n\tconst speechEndSample = Math.floor((leadSec + speechSec) * sampleRate);\n\n\tconst rng = mulberry32(opts.seed ?? 0xe11a);\n\tconst timbre = opts.timbre ?? DEFAULT_SPEAKER_TIMBRE;\n\tconst bank = new FormantBank(sampleRate, timbre.formants);\n\tlet phase = 0;\n\tfor (let i = speechStartSample; i < speechEndSample; i++) {\n\t\tconst tInSpeech = (i - speechStartSample) / sampleRate;\n\t\t// Syllable-rate vibrato proportional to the speaker's base pitch (the\n\t\t// original shared voice swung 30 Hz around 110 Hz ≈ ±27%).\n\t\tconst f0 =\n\t\t\ttimbre.f0Hz * (1 + 0.27 * Math.sin(2 * Math.PI * 5 * tInSpeech)) +\n\t\t\t(rng() - 0.5) * 4;\n\t\tphase += f0 / sampleRate;\n\t\tlet excitation = 0;\n\t\tif (phase >= 1) {\n\t\t\tphase -= 1;\n\t\t\texcitation = 1;\n\t\t}\n\t\t// Syllable-rate amplitude envelope (~4 Hz).\n\t\tconst amp = Math.max(\n\t\t\t0,\n\t\t\t0.6 * (1 + Math.sin(2 * Math.PI * 4 * tInSpeech - Math.PI / 2)),\n\t\t);\n\t\texcitation *= amp;\n\t\tpcm[i] = bank.step(excitation) * 0.15;\n\t}\n\treturn { pcm, sampleRate, speechStartSample, speechEndSample };\n}\n",
20
+ "/**\n * Voice Workbench corpus augmentation — acoustic degradation DSP (#8785).\n *\n * Real rooms are not clean. The corpus generator produces dry speech; this\n * module degrades it the way a microphone actually hears it: additive room\n * noise at a target SNR, reverberation (near vs far), far-field attenuation,\n * a low-quality/telephone line, and competing background talkers. Every\n * function is PURE and DETERMINISTIC (seeded PRNG, no `Math.random`, no I/O), so\n * the same scenario + seed always yields byte-identical audio — a labeled,\n * reproducible corpus the real ASR/diarization/EOT models can be benchmarked\n * against, and the DSP itself is unit-testable in CI with no models.\n *\n * Layering: this module knows nothing about scenarios. It operates on mono\n * `Float32Array` PCM at a given sample rate. `corpus-generator.ts` translates a\n * scenario's declarative {@link AugmentationSpec} into these calls.\n */\n\n/** Deterministic PRNG (mulberry32) — no `Math.random`, reproducible corpora. */\nfunction mulberry32(seed: number): () => number {\n\tlet a = seed >>> 0;\n\treturn () => {\n\t\ta |= 0;\n\t\ta = (a + 0x6d2b79f5) | 0;\n\t\tlet t = Math.imul(a ^ (a >>> 15), 1 | a);\n\t\tt = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/** Box–Muller standard-normal sample from a uniform PRNG. */\nfunction gaussian(rng: () => number): number {\n\tlet u = 0;\n\tlet v = 0;\n\twhile (u === 0) u = rng();\n\twhile (v === 0) v = rng();\n\treturn Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);\n}\n\n/** Root-mean-square amplitude over [start, end). */\nexport function measureRms(\n\tpcm: Float32Array,\n\tstart = 0,\n\tend = pcm.length,\n): number {\n\tconst lo = Math.max(0, start);\n\tconst hi = Math.min(pcm.length, end);\n\tif (hi <= lo) return 0;\n\tlet sum = 0;\n\tfor (let i = lo; i < hi; i++) sum += pcm[i] * pcm[i];\n\treturn Math.sqrt(sum / (hi - lo));\n}\n\n/** Peak absolute amplitude over [start, end). */\nexport function measurePeak(\n\tpcm: Float32Array,\n\tstart = 0,\n\tend = pcm.length,\n): number {\n\tconst lo = Math.max(0, start);\n\tconst hi = Math.min(pcm.length, end);\n\tlet peak = 0;\n\tfor (let i = lo; i < hi; i++) {\n\t\tconst a = Math.abs(pcm[i]);\n\t\tif (a > peak) peak = a;\n\t}\n\treturn peak;\n}\n\n/** Linear amplitude ratio for a dB gain (+6 dB ≈ ×2, −6 dB ≈ ×0.5). */\nexport function dbToGain(db: number): number {\n\treturn 10 ** (db / 20);\n}\n\n/** Estimated SNR (dB) of a signal region against a noise-only region. */\nexport function estimateSnrDb(signalRms: number, noiseRms: number): number {\n\tif (noiseRms <= 0) return Number.POSITIVE_INFINITY;\n\tif (signalRms <= 0) return Number.NEGATIVE_INFINITY;\n\treturn 20 * Math.log10(signalRms / noiseRms);\n}\n\nexport type NoiseKind = \"white\" | \"pink\" | \"music\";\n\n/**\n * Add background noise at a target SNR (dB) relative to the signal's voiced RMS.\n * Lower `snrDb` = noisier. `pink` is a one-pole-filtered approximation of 1/f\n * room rumble; `white` is flat; `music` is a seeded harmonic chord (a few\n * detuned partials under a slow tremolo) — tonal and sustained, the kind of\n * steady background that fools an energy-only VAD where flat hiss would not.\n * The noise floor is added across the WHOLE stream (including silent gaps) so\n * silence is no longer pristine — exactly the condition that makes a real\n * VAD/EOT classifier work for its living.\n */\nexport function addNoise(\n\tpcm: Float32Array,\n\topts: { snrDb: number; kind?: NoiseKind; seed?: number },\n): Float32Array {\n\tconst rng = mulberry32(opts.seed ?? 0x5eed);\n\tconst signalRms = measureRms(pcm) || 1e-6;\n\tconst targetNoiseRms = signalRms / dbToGain(opts.snrDb);\n\n\tconst raw = new Float32Array(pcm.length);\n\tconst kind = opts.kind ?? \"white\";\n\tif (kind === \"pink\") {\n\t\t// One-pole low-pass of white noise ≈ pink-ish (−~6 dB/oct) room rumble.\n\t\tlet prev = 0;\n\t\tconst alpha = 0.92;\n\t\tfor (let i = 0; i < raw.length; i++) {\n\t\t\tconst w = gaussian(rng);\n\t\t\tprev = alpha * prev + (1 - alpha) * w;\n\t\t\traw[i] = prev;\n\t\t}\n\t} else if (kind === \"music\") {\n\t\t// A seeded harmonic chord: detuned partials (root, major third, fifth,\n\t\t// octave) under a slow tremolo. Normalized frequencies (cycles/sample)\n\t\t// keep it sample-rate-agnostic; the RMS scaling below still pins it to the\n\t\t// requested SNR. Tonal + sustained, unlike flat white / pink rumble.\n\t\tconst fundamental = 0.018; // ≈ 288 Hz @ 16 kHz, ≈ 864 Hz @ 48 kHz\n\t\tconst partials = [\n\t\t\t{ ratio: 1, amp: 1.0 },\n\t\t\t{ ratio: 1.26, amp: 0.5 }, // ~major third (5:4)\n\t\t\t{ ratio: 1.5, amp: 0.6 }, // perfect fifth (3:2)\n\t\t\t{ ratio: 2, amp: 0.4 }, // octave\n\t\t];\n\t\tconst tuned = partials.map((p) => ({\n\t\t\tfreq: fundamental * p.ratio * (1 + (rng() - 0.5) * 0.01), // ±0.5% detune\n\t\t\tamp: p.amp,\n\t\t\tphase: rng() * 2 * Math.PI,\n\t\t}));\n\t\tconst tremRate = 0.0006; // slow amplitude modulation\n\t\tconst tremPhase = rng() * 2 * Math.PI;\n\t\tfor (let i = 0; i < raw.length; i++) {\n\t\t\tlet s = 0;\n\t\t\tfor (const t of tuned) {\n\t\t\t\ts += t.amp * Math.sin(2 * Math.PI * t.freq * i + t.phase);\n\t\t\t}\n\t\t\tconst trem = 0.7 + 0.3 * Math.sin(2 * Math.PI * tremRate * i + tremPhase);\n\t\t\traw[i] = s * trem;\n\t\t}\n\t} else {\n\t\tfor (let i = 0; i < raw.length; i++) raw[i] = gaussian(rng);\n\t}\n\n\tconst rawRms = measureRms(raw) || 1e-6;\n\tconst scale = targetNoiseRms / rawRms;\n\tconst out = new Float32Array(pcm.length);\n\tfor (let i = 0; i < out.length; i++) out[i] = pcm[i] + raw[i] * scale;\n\treturn out;\n}\n\n/** RBJ biquad coefficients (transposed direct form II applied below). */\ninterface Biquad {\n\tb0: number;\n\tb1: number;\n\tb2: number;\n\ta1: number;\n\ta2: number;\n}\n\nfunction lowpassBiquad(\n\tsampleRate: number,\n\tfreq: number,\n\tq = Math.SQRT1_2,\n): Biquad {\n\tconst w0 = (2 * Math.PI * freq) / sampleRate;\n\tconst cos = Math.cos(w0);\n\tconst alpha = Math.sin(w0) / (2 * q);\n\tconst a0 = 1 + alpha;\n\treturn {\n\t\tb0: (1 - cos) / 2 / a0,\n\t\tb1: (1 - cos) / a0,\n\t\tb2: (1 - cos) / 2 / a0,\n\t\ta1: (-2 * cos) / a0,\n\t\ta2: (1 - alpha) / a0,\n\t};\n}\n\nfunction highpassBiquad(\n\tsampleRate: number,\n\tfreq: number,\n\tq = Math.SQRT1_2,\n): Biquad {\n\tconst w0 = (2 * Math.PI * freq) / sampleRate;\n\tconst cos = Math.cos(w0);\n\tconst alpha = Math.sin(w0) / (2 * q);\n\tconst a0 = 1 + alpha;\n\treturn {\n\t\tb0: (1 + cos) / 2 / a0,\n\t\tb1: -(1 + cos) / a0,\n\t\tb2: (1 + cos) / 2 / a0,\n\t\ta1: (-2 * cos) / a0,\n\t\ta2: (1 - alpha) / a0,\n\t};\n}\n\nfunction applyBiquad(pcm: Float32Array, c: Biquad): Float32Array {\n\tconst out = new Float32Array(pcm.length);\n\tlet x1 = 0;\n\tlet x2 = 0;\n\tlet y1 = 0;\n\tlet y2 = 0;\n\tfor (let i = 0; i < pcm.length; i++) {\n\t\tconst x0 = pcm[i];\n\t\tconst y0 = c.b0 * x0 + c.b1 * x1 + c.b2 * x2 - c.a1 * y1 - c.a2 * y2;\n\t\tx2 = x1;\n\t\tx1 = x0;\n\t\ty2 = y1;\n\t\ty1 = y0;\n\t\tout[i] = y0;\n\t}\n\treturn out;\n}\n\n/** µ-law companding round-trip with 8-bit quantization (codec degradation). */\nfunction muLawRoundTrip(pcm: Float32Array): Float32Array {\n\tconst mu = 255;\n\tconst out = new Float32Array(pcm.length);\n\tfor (let i = 0; i < pcm.length; i++) {\n\t\tconst x = Math.max(-1, Math.min(1, pcm[i]));\n\t\tconst sign = x < 0 ? -1 : 1;\n\t\t// Encode to companded domain, quantize to 8 bits, decode back.\n\t\tconst y = (sign * Math.log1p(mu * Math.abs(x))) / Math.log1p(mu);\n\t\tconst q = Math.round(((y + 1) / 2) * 255) / 255; // 0..1, 8-bit\n\t\tconst yd = q * 2 - 1;\n\t\tconst sd = yd < 0 ? -1 : 1;\n\t\tout[i] = (sd * ((1 + mu) ** Math.abs(yd) - 1)) / mu;\n\t}\n\treturn out;\n}\n\n/**\n * Simulate a low-quality / telephone line: band-limit to ~300–3400 Hz then\n * companded 8-bit quantization. Cheap mics and phone codecs strip the highs and\n * add quantization grunge, which is the dominant real-world ASR stressor for\n * \"voices near and far\" / low-quality input.\n */\nexport function applyLowQualityLine(\n\tpcm: Float32Array,\n\tsampleRate: number,\n): Float32Array {\n\tconst hp = highpassBiquad(sampleRate, 300);\n\tconst lpFreq = Math.min(3400, sampleRate / 2 - 100);\n\tconst lp = lowpassBiquad(sampleRate, lpFreq);\n\treturn muLawRoundTrip(applyBiquad(applyBiquad(pcm, hp), lp));\n}\n\n/**\n * Freeverb-style Schroeder reverb (4 parallel combs → 2 series allpasses),\n * mixed with the dry signal. `room` (0..1) sets reflection density/decay;\n * `wet` (0..1) the reflected level. Reverb spreads energy in time — speech\n * keeps ringing after the talker stops — which is what makes a far/reverberant\n * voice hard to endpoint and to diarize. The output is `dry.length + tail`\n * samples so the decay is preserved (callers may keep or trim the tail).\n */\nexport function applyReverb(\n\tpcm: Float32Array,\n\tsampleRate: number,\n\topts: { room?: number; wet?: number; tailSec?: number } = {},\n): Float32Array {\n\tconst room = Math.max(0, Math.min(1, opts.room ?? 0.6));\n\tconst wet = Math.max(0, Math.min(1, opts.wet ?? 0.4));\n\tconst tailSamples = Math.round((opts.tailSec ?? 0.6) * sampleRate);\n\tconst n = pcm.length + tailSamples;\n\n\t// Classic Freeverb tunings (samples @ 44.1 kHz), scaled to this sample rate.\n\tconst sr = sampleRate / 44100;\n\tconst combTunings = [1116, 1188, 1277, 1356].map((d) =>\n\t\tMath.max(1, Math.round(d * sr)),\n\t);\n\tconst allpassTunings = [556, 441].map((d) => Math.max(1, Math.round(d * sr)));\n\tconst feedback = room * 0.28 + 0.7;\n\tconst damp = 0.2;\n\n\tconst combBufs = combTunings.map((d) => new Float32Array(d));\n\tconst combIdx = combTunings.map(() => 0);\n\tconst combFilter = combTunings.map(() => 0);\n\tconst apBufs = allpassTunings.map((d) => new Float32Array(d));\n\tconst apIdx = allpassTunings.map(() => 0);\n\n\tconst out = new Float32Array(n);\n\tfor (let i = 0; i < n; i++) {\n\t\tconst dry = i < pcm.length ? pcm[i] : 0;\n\t\tlet combSum = 0;\n\t\tfor (let c = 0; c < combBufs.length; c++) {\n\t\t\tconst buf = combBufs[c];\n\t\t\tconst idx = combIdx[c];\n\t\t\tconst sample = buf[idx];\n\t\t\tcombFilter[c] = sample * (1 - damp) + combFilter[c] * damp;\n\t\t\tbuf[idx] = dry + combFilter[c] * feedback;\n\t\t\tcombIdx[c] = (idx + 1) % buf.length;\n\t\t\tcombSum += sample;\n\t\t}\n\t\tlet wetSig = combSum / combBufs.length;\n\t\tfor (let a = 0; a < apBufs.length; a++) {\n\t\t\tconst buf = apBufs[a];\n\t\t\tconst idx = apIdx[a];\n\t\t\tconst bufOut = buf[idx];\n\t\t\tconst input = wetSig;\n\t\t\tbuf[idx] = input + bufOut * 0.5;\n\t\t\tapIdx[a] = (idx + 1) % buf.length;\n\t\t\twetSig = bufOut - input;\n\t\t}\n\t\tout[i] = dry * (1 - wet) + wetSig * wet;\n\t}\n\treturn out;\n}\n\n/** Multiply the whole stream by a dB gain (far-field attenuation = negative). */\nexport function applyGainDb(pcm: Float32Array, db: number): Float32Array {\n\tconst g = dbToGain(db);\n\tconst out = new Float32Array(pcm.length);\n\tfor (let i = 0; i < pcm.length; i++) out[i] = pcm[i] * g;\n\treturn out;\n}\n\n/**\n * Mix an overlay stream (a competing talker, babble, or the agent's own TTS for\n * an echo test) into a base stream at a given level, starting at `offsetSamples`\n * and optionally looping the overlay to cover the base. The base length is\n * preserved. Returns a new array; neither input is mutated.\n */\nexport function mixInto(\n\tbase: Float32Array,\n\toverlay: Float32Array,\n\topts: { gainDb?: number; offsetSamples?: number; loop?: boolean } = {},\n): Float32Array {\n\tconst out = Float32Array.from(base);\n\tif (overlay.length === 0) return out;\n\tconst g = dbToGain(opts.gainDb ?? 0);\n\tconst offset = Math.max(0, Math.round(opts.offsetSamples ?? 0));\n\tconst loop = opts.loop ?? false;\n\tfor (let i = offset; i < out.length; i++) {\n\t\tconst j = i - offset;\n\t\tconst src = loop ? overlay[j % overlay.length] : overlay[j];\n\t\tif (src === undefined) break;\n\t\tout[i] += src * g;\n\t}\n\treturn out;\n}\n\n/** Declarative degradation for one stream (the scenario's `environment`). */\nexport interface AugmentationSpec {\n\t/** Additive room-noise SNR (dB) relative to voiced speech. Lower = noisier. */\n\tnoiseSnrDb?: number;\n\t/** Noise character (default white). */\n\tnoiseKind?: NoiseKind;\n\t/** Reverb room size 0..1 (near→far, small→large room). */\n\treverb?: number;\n\t/** Reverb wet level 0..1 (defaults from `reverb` when omitted). */\n\treverbWet?: number;\n\t/** Far-field attenuation in dB (how many dB QUIETER; positive number). */\n\tfarFieldDb?: number;\n\t/** Band-limit + 8-bit companding (telephone / cheap-mic line). */\n\tlowQuality?: boolean;\n\t/** Competing background talkers, mixed this many dB BELOW the speech. */\n\tbackgroundTalkersDb?: number;\n\t/** Deterministic seed for noise/babble. */\n\tseed?: number;\n}\n\n/** True when the spec asks for any degradation at all. */\nexport function specIsClean(spec: AugmentationSpec | undefined): boolean {\n\tif (!spec) return true;\n\treturn (\n\t\tspec.noiseSnrDb === undefined &&\n\t\tspec.reverb === undefined &&\n\t\tspec.farFieldDb === undefined &&\n\t\t!spec.lowQuality &&\n\t\tspec.backgroundTalkersDb === undefined\n\t);\n}\n\nexport interface AugmentPcmOptions {\n\t/**\n\t * A babble source (a competing-talker stream) for `backgroundTalkersDb`.\n\t * The generator supplies one synthesized from other voices; omitted = no\n\t * background talkers even if the spec asks (the runner logs the gap).\n\t */\n\tbabble?: Float32Array;\n\t/** Trim reverb tail back to the input length (keeps corpus timing exact). */\n\ttrimReverbTail?: boolean;\n}\n\n/**\n * Apply a full degradation chain to one stream, in acoustically sensible order:\n * background talkers → reverb (room reflections) → far-field gain → low-quality\n * line → additive noise floor. Pure; returns a new array.\n */\nexport function augmentPcm(\n\tpcm: Float32Array,\n\tsampleRate: number,\n\tspec: AugmentationSpec,\n\toptions: AugmentPcmOptions = {},\n): Float32Array {\n\tlet out = pcm;\n\n\tif (\n\t\tspec.backgroundTalkersDb !== undefined &&\n\t\toptions.babble &&\n\t\toptions.babble.length > 0\n\t) {\n\t\tout = mixInto(out, options.babble, {\n\t\t\tgainDb: -Math.abs(spec.backgroundTalkersDb),\n\t\t\tloop: true,\n\t\t});\n\t}\n\n\tif (spec.reverb !== undefined && spec.reverb > 0) {\n\t\tconst reverbed = applyReverb(out, sampleRate, {\n\t\t\troom: spec.reverb,\n\t\t\t...(spec.reverbWet !== undefined ? { wet: spec.reverbWet } : {}),\n\t\t});\n\t\tout =\n\t\t\toptions.trimReverbTail !== false\n\t\t\t\t? reverbed.subarray(0, pcm.length)\n\t\t\t\t: reverbed;\n\t}\n\n\tif (spec.farFieldDb !== undefined && spec.farFieldDb !== 0) {\n\t\tout = applyGainDb(out, -Math.abs(spec.farFieldDb));\n\t}\n\n\tif (spec.lowQuality) {\n\t\tout = applyLowQualityLine(out, sampleRate);\n\t}\n\n\tif (spec.noiseSnrDb !== undefined) {\n\t\tout = addNoise(out, {\n\t\t\tsnrDb: spec.noiseSnrDb,\n\t\t\t...(spec.noiseKind ? { kind: spec.noiseKind } : {}),\n\t\t\t...(spec.seed !== undefined ? { seed: spec.seed } : {}),\n\t\t});\n\t}\n\n\t// Defensive de-clip: degradation chains can briefly exceed [-1, 1].\n\tlet peak = 0;\n\tfor (let i = 0; i < out.length; i++) {\n\t\tconst a = Math.abs(out[i]);\n\t\tif (a > peak) peak = a;\n\t}\n\tif (peak > 1) {\n\t\tconst norm = 0.999 / peak;\n\t\tconst scaled = new Float32Array(out.length);\n\t\tfor (let i = 0; i < out.length; i++) scaled[i] = out[i] * norm;\n\t\tout = scaled;\n\t}\n\n\t// Always return a fresh array of exactly the input length.\n\treturn out.length === pcm.length && out !== pcm\n\t\t? out\n\t\t: Float32Array.from(out);\n}\n",
21
+ "/**\n * Voice Workbench scenario schema (#8785).\n *\n * One declarative format for a voice conversation that BOTH the headless runner\n * (real services: ASR / diarization / EOT / respond / TTS over a corpus) and\n * the headful scenario player (the real frontend client pipeline) execute, and\n * that the benchmark layer scores. A scenario is an ordered list of turns plus\n * named participants and scenario-level assertions; each turn declares the\n * expected behavior (respond / don't, transcript, speaker label, entity) so the\n * runner can score against ground truth.\n *\n * Pure types + a pure validator — no model loading, no I/O — so it is safe to\n * import from the runner, the player, and tests alike.\n */\n\nimport type { AugmentationSpec } from \"./corpus-augment\";\n\n/**\n * Acoustic environment for a scenario or a single turn: room noise, reverb,\n * far-field attenuation, low-quality line, background talkers. Drives the\n * corpus generator's degradation chain ({@link AugmentationSpec}). A turn's\n * environment is merged over the scenario's, so a scenario can declare a noisy\n * room once and an individual turn can override it (e.g. one talker steps away).\n */\nexport type VoiceEnvironment = AugmentationSpec;\n\n/** A named voice/entity participating in the scenario. */\nexport interface VoiceScenarioParticipant {\n\t/** Stable label used in turns + diarization ground truth (e.g. \"alice\"). */\n\tlabel: string;\n\t/** TTS voice id used to synthesize this participant's turns in the corpus. */\n\tttsVoiceId?: string;\n\t/** The elizaOS entity id this voice should resolve to (voice→entity match). */\n\tentityId?: string;\n\t/** True when this participant is the device owner / primary enrolled speaker. */\n\tisOwner?: boolean;\n}\n\n/** One spoken turn in the scenario. */\nexport interface VoiceScenarioTurn {\n\t/** Participant label (must exist in `participants`). */\n\tspeaker: string;\n\t/** Spoken text — synthesized to audio by the corpus generator. */\n\ttext?: string;\n\t/** OR a reference to a pre-recorded/-generated audio file under the corpus. */\n\taudioRef?: string;\n\t/** Override the participant's default TTS voice for this turn. */\n\tttsVoiceId?: string;\n\t/** Silent gaps (ms) spliced AFTER this turn's audio (pauses / barge-in gaps). */\n\tpausesMs?: number[];\n\t/** Ground truth: SHOULD the agent respond to this turn? */\n\texpectRespond: boolean;\n\t/** Ground truth: is this segment a real end-of-turn boundary? */\n\texpectEndOfTurn?: boolean;\n\t/** Expected ASR transcript (for WER scoring); defaults to `text`. */\n\texpectedTranscript?: string;\n\t/** Expected diarization label (defaults to `speaker`). */\n\texpectedSpeakerLabel?: string;\n\t/** Expected entity inferred/recognized from this turn (name extraction). */\n\texpectedEntity?: string;\n\t/**\n\t * Acoustic degradation for THIS turn, merged over the scenario environment.\n\t * Use it to model one talker stepping away (far-field) or onto a bad line\n\t * while the rest of the room stays clean.\n\t */\n\tenvironment?: VoiceEnvironment;\n\t/**\n\t * Ground truth for echo/self-voice rejection: this \"turn\" is the agent's own\n\t * TTS bleeding back into the mic (not a real user turn). The respond gate\n\t * MUST suppress it. Always implies `expectRespond: false`.\n\t */\n\tisAgentEcho?: boolean;\n\t/**\n\t * The agent's spoken reply to THIS turn (when it responds). The real-decision\n\t * logic adapter uses it as the \"recent agent reply\" the echo gate compares a\n\t * following `isAgentEcho` turn against — so echo rejection is tested against a\n\t * genuine reply string, not a circular self-reference.\n\t */\n\tagentReplyText?: string;\n}\n\n/** Scenario-level pass/fail thresholds the benchmark layer enforces. */\nexport interface VoiceScenarioAssertions {\n\t/** Max word-error-rate across the scenario's transcripts. */\n\tmaxWer?: number;\n\t/** Max diarization error rate. */\n\tmaxDer?: number;\n\t/** Min respond-decision accuracy. */\n\tminRespondAccuracy?: number;\n\t/** Max EOT false-trigger rate. */\n\tmaxEotFalseTriggerRate?: number;\n\t/** Min voice→entity match rate. */\n\tminVoiceEntityMatchRate?: number;\n\t/** Latency budgets (ms) — first-audio / time-to-first-token, etc. */\n\tmaxFirstAudioMs?: number;\n\tmaxTtftMs?: number;\n\t/** Min echo/self-voice rejection rate (agent-echo turns correctly suppressed). */\n\tminEchoRejectionRate?: number;\n\t/** Min owner-vs-intruder accuracy for security scenarios. */\n\tminOwnerAccuracy?: number;\n}\n\nexport type VoiceScenarioClass =\n\t| \"multi-voice\"\n\t| \"pauses\"\n\t| \"respond-no-respond\"\n\t| \"multi-speaker\"\n\t| \"diarization\"\n\t| \"entity-extraction\"\n\t| \"voice-recognition\"\n\t| \"eot\"\n\t| \"transcription-mode\"\n\t| \"multi-agent-room\"\n\t| \"long-form-monologue\"\n\t// Robustness: degraded acoustics (noise / reverb / far-field / low-quality).\n\t| \"robustness\"\n\t// Self-echo: the agent's own TTS must not be treated as a user turn.\n\t| \"echo-rejection\"\n\t// Security: owner vs. intruder / non-owner voice gating.\n\t| \"owner-security\"\n\t// Two voices overlapping / interrupting each other.\n\t| \"overlapping-speech\";\n\nexport interface VoiceScenario {\n\t/** Stable id (also the corpus subdirectory name). */\n\tid: string;\n\t/** Human description of what the scenario exercises. */\n\tdescription?: string;\n\t/** Which scenario class(es) this belongs to (drives the headful spec matrix). */\n\tclasses: VoiceScenarioClass[];\n\tparticipants: VoiceScenarioParticipant[];\n\tturns: VoiceScenarioTurn[];\n\tassertions?: VoiceScenarioAssertions;\n\t/** Agent labels present in a multi-agent room (subset of participants). */\n\tagents?: string[];\n\t/** Scenario-wide acoustic environment; per-turn `environment` overrides it. */\n\tenvironment?: VoiceEnvironment;\n\t/**\n\t * Entity ids the agent answers WITHOUT a wake word (owner + enrolled\n\t * speakers). The respond gate suppresses a confident speaker NOT in this set\n\t * as a bystander. Defaults (in the runner) to every participant that has an\n\t * `entityId`; set it explicitly to mark some bound voices as strangers.\n\t */\n\tknownSpeakerEntityIds?: string[];\n}\n\nexport interface VoiceScenarioValidation {\n\tvalid: boolean;\n\terrors: string[];\n}\n\n/**\n * Validate a scenario's internal consistency (pure; no I/O). Checks ids,\n * participant references, turn audio/text presence, and that any agents named\n * exist as participants. Returns all errors (does not throw) so a corpus build\n * can report every problem at once.\n */\n/** True when a value is not a non-empty string (so `.trim()` is never called on a non-string). */\nfunction isBlank(v: unknown): boolean {\n\treturn typeof v !== \"string\" || v.trim().length === 0;\n}\n\nexport function validateVoiceScenario(\n\tscenario: VoiceScenario,\n): VoiceScenarioValidation {\n\tconst errors: string[] = [];\n\t// A malformed/empty scenario file can deserialize to a non-object; guard the\n\t// boundary so the validator reports an error instead of throwing.\n\tif (!scenario || typeof scenario !== \"object\" || Array.isArray(scenario)) {\n\t\treturn { valid: false, errors: [\"scenario must be an object\"] };\n\t}\n\tif (isBlank(scenario.id)) errors.push(\"scenario.id is required\");\n\tif (!Array.isArray(scenario.classes) || scenario.classes.length === 0) {\n\t\terrors.push(\"scenario.classes must be a non-empty array\");\n\t}\n\t// Iterate defensively: a malformed scenario may carry non-array fields.\n\tconst participants = Array.isArray(scenario.participants)\n\t\t? scenario.participants\n\t\t: [];\n\tconst turns = Array.isArray(scenario.turns) ? scenario.turns : [];\n\tconst agents = Array.isArray(scenario.agents) ? scenario.agents : [];\n\tconst labels = new Set<string>();\n\tfor (const p of participants) {\n\t\tif (!p || typeof p !== \"object\") {\n\t\t\terrors.push(\"participant must be an object\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (isBlank(p.label)) {\n\t\t\terrors.push(\"participant.label is required\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (labels.has(p.label))\n\t\t\terrors.push(`duplicate participant label: ${p.label}`);\n\t\tlabels.add(p.label);\n\t}\n\tif (labels.size === 0) errors.push(\"scenario.participants must be non-empty\");\n\tif (!Array.isArray(scenario.turns) || scenario.turns.length === 0) {\n\t\terrors.push(\"scenario.turns must be a non-empty array\");\n\t}\n\tturns.forEach((t, i) => {\n\t\tif (!t || typeof t !== \"object\") {\n\t\t\terrors.push(`turn[${i}] must be an object`);\n\t\t\treturn;\n\t\t}\n\t\tif (!labels.has(t.speaker)) {\n\t\t\terrors.push(`turn[${i}].speaker \"${t.speaker}\" is not a participant`);\n\t\t}\n\t\tif (isBlank(t.text) && isBlank(t.audioRef)) {\n\t\t\terrors.push(`turn[${i}] must have either text or audioRef`);\n\t\t}\n\t\tif (typeof t.expectRespond !== \"boolean\") {\n\t\t\terrors.push(`turn[${i}].expectRespond must be a boolean`);\n\t\t}\n\t\tif (\n\t\t\tt.expectEndOfTurn !== undefined &&\n\t\t\ttypeof t.expectEndOfTurn !== \"boolean\"\n\t\t) {\n\t\t\terrors.push(`turn[${i}].expectEndOfTurn must be a boolean`);\n\t\t}\n\t});\n\tfor (const agent of agents) {\n\t\tif (!labels.has(agent)) {\n\t\t\terrors.push(`agent \"${agent}\" is not a participant`);\n\t\t}\n\t}\n\tvalidateEnvironment(scenario.environment, \"scenario.environment\", errors);\n\tturns.forEach((t, i) => {\n\t\tvalidateEnvironment(t?.environment, `turn[${i}].environment`, errors);\n\t});\n\treturn { valid: errors.length === 0, errors };\n}\n\n/** Validate an acoustic environment's ranges (pure; appends to `errors`). */\nfunction validateEnvironment(\n\tenv: VoiceEnvironment | undefined,\n\twhere: string,\n\terrors: string[],\n): void {\n\tif (!env) return;\n\tif (\n\t\tenv.reverb !== undefined &&\n\t\t(!Number.isFinite(env.reverb) || env.reverb < 0 || env.reverb > 1)\n\t) {\n\t\terrors.push(`${where}.reverb must be in [0, 1]`);\n\t}\n\tif (env.noiseSnrDb !== undefined && !Number.isFinite(env.noiseSnrDb)) {\n\t\terrors.push(`${where}.noiseSnrDb must be a finite number`);\n\t}\n\tif (\n\t\tenv.farFieldDb !== undefined &&\n\t\t(!Number.isFinite(env.farFieldDb) || env.farFieldDb < 0)\n\t) {\n\t\terrors.push(`${where}.farFieldDb must be a non-negative dB attenuation`);\n\t}\n\tif (\n\t\tenv.backgroundTalkersDb !== undefined &&\n\t\t!Number.isFinite(env.backgroundTalkersDb)\n\t) {\n\t\terrors.push(`${where}.backgroundTalkersDb must be a finite number`);\n\t}\n}\n\n/** Merge a turn's environment over the scenario's (turn wins, field by field). */\nexport function resolveTurnEnvironment(\n\tscenario: VoiceScenario,\n\tturn: VoiceScenarioTurn,\n): VoiceEnvironment | undefined {\n\tif (!scenario.environment && !turn.environment) return undefined;\n\treturn { ...scenario.environment, ...turn.environment };\n}\n\n/** The expected ASR reference for a turn (explicit override or its text). */\nexport function turnReferenceTranscript(turn: VoiceScenarioTurn): string {\n\treturn (turn.expectedTranscript ?? turn.text ?? \"\").trim();\n}\n\n/** The expected diarization label for a turn (explicit override or speaker). */\nexport function turnSpeakerLabel(turn: VoiceScenarioTurn): string {\n\treturn turn.expectedSpeakerLabel ?? turn.speaker;\n}\n",
22
+ "/**\n * Pure rounding + percentile helpers shared by the voice E2E harness and the\n * voice workbench report (#8785). No models, filesystem, or network — just\n * numeric formatting so both consumers report identical metric values.\n */\n\nexport function round1(value: number): number {\n\treturn Math.round(value * 10) / 10;\n}\n\nexport function round4(value: number): number {\n\treturn Math.round(value * 1e4) / 1e4;\n}\n\n/** Nearest-rank percentile over a sample (null when empty), non-finite filtered. */\nexport function percentile(\n\tvalues: ReadonlyArray<number>,\n\tp: number,\n): number | null {\n\tconst finite = values.filter((v) => Number.isFinite(v));\n\tif (finite.length === 0) return null;\n\tconst sorted = [...finite].sort((a, b) => a - b);\n\tconst rank = Math.ceil((p / 100) * sorted.length);\n\treturn round1(sorted[Math.min(sorted.length - 1, Math.max(0, rank - 1))]);\n}\n",
23
+ "/**\n * Voice Workbench benchmark report (#8785).\n *\n * Rolls a matrix of per-scenario scorer results into one machine-readable\n * report + a Markdown rendering, mirroring `voicebench`'s p95/p99 output and the\n * `summarizeVoiceE2e` verdict shape. Pure: it consumes already-scored\n * `VoiceE2eCaseResult`s (the runners — headless services / headful frontend —\n * produce those), so it can be unit-tested without audio, models, or a browser.\n *\n * Honesty contract: a scenario whose corpus/backend artifacts are absent is\n * `skipped`, never `pass`. `overall` is `skipped` only when *every* scenario was\n * skipped; one ran-and-failed scenario makes the whole report `fail`.\n */\n\nimport type { VoiceE2eCaseResult } from \"./e2e-harness\";\nimport { percentile, round4 } from \"./metric-math\";\nimport type { VoiceScenarioClass } from \"./voice-scenario\";\n\nexport type VoiceWorkbenchStatus = \"ran\" | \"skipped\";\nexport type VoiceWorkbenchVerdict = \"pass\" | \"fail\" | \"skipped\";\n\n/**\n * A `.wav` artifact written for one scenario run when a capture sink is active.\n * `path` is RELATIVE to the run dir the headless runner was told to write under,\n * so the scenario run viewer (served from that dir) can reference it directly.\n */\nexport interface VoiceAudioArtifact {\n\t/** Turn index this artifact belongs to; the full corpus uses turn 0. */\n\tturnIndex: number;\n\t/** `generated` = the full synthesized corpus; `consumed` = a per-turn slice. */\n\tkind: \"generated\" | \"consumed\";\n\t/** Path to the `.wav`, relative to the run dir (forward-slash separated). */\n\tpath: string;\n\tsampleRate: number;\n\tdurationMs?: number;\n\t/** Diarization ground-truth speaker label for a consumed per-turn slice. */\n\tspeakerLabel?: string;\n}\n\n/** One scenario's outcome in a workbench run. */\nexport interface VoiceWorkbenchScenarioRun {\n\tscenarioId: string;\n\tclasses: VoiceScenarioClass[];\n\t/** `skipped` when corpus/backend artifacts were absent (never scored). */\n\tstatus: VoiceWorkbenchStatus;\n\t/** Scored cases for this scenario (empty when skipped). */\n\tcases: VoiceE2eCaseResult[];\n\t/** Why the scenario was skipped (artifact/backend absence), if it was. */\n\tskipReason?: string;\n\t/** `.wav` artifacts written when a capture sink was active (else absent). */\n\taudioArtifacts?: VoiceAudioArtifact[];\n}\n\nexport interface VoiceWorkbenchScenarioReport {\n\tscenarioId: string;\n\tclasses: VoiceScenarioClass[];\n\tstatus: VoiceWorkbenchStatus;\n\tverdict: VoiceWorkbenchVerdict;\n\tcaseCount: number;\n\tfailedCaseKinds: string[];\n\tskipReason?: string;\n}\n\n/** Mean + worst + sample-count for one metric across all ran scenarios. */\nexport interface MetricRollup {\n\tcount: number;\n\tmean: number | null;\n\tworst: number | null;\n}\n\nexport interface VoiceWorkbenchMetrics {\n\t/** Transcription word-error-rate (`worst` = max). */\n\twer: MetricRollup;\n\t/** EOT false-trigger rate (`worst` = max) + latency percentiles. */\n\teotFalseTriggerRate: MetricRollup;\n\teotLatencyP50Ms: number | null;\n\teotLatencyP95Ms: number | null;\n\t/** Diarization error rate (`worst` = max). */\n\tder: MetricRollup;\n\t/** Respond-decision accuracy (`worst` = min). */\n\trespondAccuracy: MetricRollup;\n\t/** Entity-extraction F1 (`worst` = min). */\n\tentityF1: MetricRollup;\n\t/** Voice→entity match rate (`worst` = min). */\n\tvoiceEntityMatchRate: MetricRollup;\n\t/** First-audio latency ms (`worst` = max). */\n\tfirstAudioMs: MetricRollup;\n\t/** Self-echo rejection rate (`worst` = min). */\n\techoRejectionRate: MetricRollup;\n\t/** Owner-vs-intruder accuracy (`worst` = min). */\n\townerAccuracy: MetricRollup;\n\t/** Impostor-accept rate (`worst` = max) — non-owner accepted as owner. */\n\timpostorAcceptRate: MetricRollup;\n}\n\nexport interface VoiceWorkbenchReport {\n\tschemaVersion: 1;\n\toverall: VoiceWorkbenchVerdict;\n\tscenariosTotal: number;\n\tscenariosRan: number;\n\tscenariosSkipped: number;\n\tscenarios: VoiceWorkbenchScenarioReport[];\n\tmetrics: VoiceWorkbenchMetrics;\n}\n\nfunction mean(values: ReadonlyArray<number>): number | null {\n\tif (values.length === 0) return null;\n\tconst sum = values.reduce((a, b) => a + b, 0);\n\treturn round4(sum / values.length);\n}\n\nfunction rollupMax(values: ReadonlyArray<number>): MetricRollup {\n\treturn {\n\t\tcount: values.length,\n\t\tmean: mean(values),\n\t\tworst: values.length > 0 ? round4(Math.max(...values)) : null,\n\t};\n}\n\nfunction rollupMin(values: ReadonlyArray<number>): MetricRollup {\n\treturn {\n\t\tcount: values.length,\n\t\tmean: mean(values),\n\t\tworst: values.length > 0 ? round4(Math.min(...values)) : null,\n\t};\n}\n\nfunction scenarioVerdict(\n\trun: VoiceWorkbenchScenarioRun,\n): VoiceWorkbenchVerdict {\n\tif (run.status === \"skipped\") return \"skipped\";\n\tif (run.cases.length === 0) return \"skipped\";\n\treturn run.cases.every((c) => c.passed) ? \"pass\" : \"fail\";\n}\n\n/**\n * Aggregate per-scenario scorer results into one gating report. `overall` is\n * `fail` if any scenario ran and failed, else `pass` if any scenario ran and\n * passed, else `skipped`.\n */\nexport function buildVoiceWorkbenchReport(\n\truns: ReadonlyArray<VoiceWorkbenchScenarioRun>,\n): VoiceWorkbenchReport {\n\tconst scenarios: VoiceWorkbenchScenarioReport[] = runs.map((run) => {\n\t\tconst verdict = scenarioVerdict(run);\n\t\treturn {\n\t\t\tscenarioId: run.scenarioId,\n\t\t\tclasses: run.classes,\n\t\t\tstatus: run.status,\n\t\t\tverdict,\n\t\t\tcaseCount: run.cases.length,\n\t\t\tfailedCaseKinds: run.cases.filter((c) => !c.passed).map((c) => c.kind),\n\t\t\tskipReason: run.skipReason,\n\t\t};\n\t});\n\n\tconst allCases = runs.flatMap((r) => r.cases);\n\tconst wer: number[] = [];\n\tconst ftr: number[] = [];\n\tconst eotLatencyP50: number[] = [];\n\tconst eotLatencyP95: number[] = [];\n\tconst der: number[] = [];\n\tconst respondAccuracy: number[] = [];\n\tconst entityF1: number[] = [];\n\tconst voiceEntityMatchRate: number[] = [];\n\tconst firstAudioMs: number[] = [];\n\tconst echoRejectionRate: number[] = [];\n\tconst ownerAccuracy: number[] = [];\n\tconst impostorAcceptRate: number[] = [];\n\n\tfor (const c of allCases) {\n\t\tswitch (c.kind) {\n\t\t\tcase \"tts-asr-roundtrip\":\n\t\t\t\twer.push(c.wer);\n\t\t\t\tbreak;\n\t\t\tcase \"eot-decision\":\n\t\t\t\tftr.push(c.falseTriggerRate);\n\t\t\t\tif (c.latencyP50Ms !== null) eotLatencyP50.push(c.latencyP50Ms);\n\t\t\t\tif (c.latencyP95Ms !== null) eotLatencyP95.push(c.latencyP95Ms);\n\t\t\t\tbreak;\n\t\t\tcase \"diarization\":\n\t\t\t\tder.push(c.der);\n\t\t\t\tbreak;\n\t\t\tcase \"respond-decision\":\n\t\t\t\trespondAccuracy.push(c.accuracy);\n\t\t\t\tbreak;\n\t\t\tcase \"entity-extraction\":\n\t\t\t\tentityF1.push(c.f1);\n\t\t\t\tbreak;\n\t\t\tcase \"voice-entity-match\":\n\t\t\t\tvoiceEntityMatchRate.push(c.matchRate);\n\t\t\t\tbreak;\n\t\t\tcase \"first-response-latency\":\n\t\t\t\tfirstAudioMs.push(c.firstAudioMs);\n\t\t\t\tbreak;\n\t\t\tcase \"echo-rejection\":\n\t\t\t\techoRejectionRate.push(c.rejectionRate);\n\t\t\t\tbreak;\n\t\t\tcase \"owner-security\":\n\t\t\t\townerAccuracy.push(c.accuracy);\n\t\t\t\timpostorAcceptRate.push(c.impostorAcceptRate);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst ran = runs.filter((r) => r.status === \"ran\" && r.cases.length > 0);\n\tconst anyRanFailed = scenarios.some((s) => s.verdict === \"fail\");\n\tconst anyRanPassed = scenarios.some((s) => s.verdict === \"pass\");\n\tconst overall: VoiceWorkbenchVerdict = anyRanFailed\n\t\t? \"fail\"\n\t\t: anyRanPassed\n\t\t\t? \"pass\"\n\t\t\t: \"skipped\";\n\n\treturn {\n\t\tschemaVersion: 1,\n\t\toverall,\n\t\tscenariosTotal: runs.length,\n\t\tscenariosRan: ran.length,\n\t\tscenariosSkipped: runs.length - ran.length,\n\t\tscenarios,\n\t\tmetrics: {\n\t\t\twer: rollupMax(wer),\n\t\t\teotFalseTriggerRate: rollupMax(ftr),\n\t\t\teotLatencyP50Ms: percentile(eotLatencyP50, 50),\n\t\t\teotLatencyP95Ms: percentile(eotLatencyP95, 95),\n\t\t\tder: rollupMax(der),\n\t\t\trespondAccuracy: rollupMin(respondAccuracy),\n\t\t\tentityF1: rollupMin(entityF1),\n\t\t\tvoiceEntityMatchRate: rollupMin(voiceEntityMatchRate),\n\t\t\tfirstAudioMs: rollupMax(firstAudioMs),\n\t\t\techoRejectionRate: rollupMin(echoRejectionRate),\n\t\t\townerAccuracy: rollupMin(ownerAccuracy),\n\t\t\timpostorAcceptRate: rollupMax(impostorAcceptRate),\n\t\t},\n\t};\n}\n\nfunction fmt(n: number | null): string {\n\treturn n === null ? \"—\" : String(n);\n}\n\n/** Render a workbench report as Markdown (one metric table + a scenario table). */\nexport function formatVoiceWorkbenchMarkdown(\n\treport: VoiceWorkbenchReport,\n): string {\n\tconst m = report.metrics;\n\tconst lines = [\n\t\t\"# Voice Workbench report\",\n\t\t\"\",\n\t\t`**Overall:** ${report.overall.toUpperCase()} — ${report.scenariosRan} ran, ${report.scenariosSkipped} skipped of ${report.scenariosTotal}`,\n\t\t\"\",\n\t\t\"## Metrics\",\n\t\t\"\",\n\t\t\"| Metric | Mean | Worst | n |\",\n\t\t\"| --- | --- | --- | --- |\",\n\t\t`| WER | ${fmt(m.wer.mean)} | ${fmt(m.wer.worst)} | ${m.wer.count} |`,\n\t\t`| EOT false-trigger rate | ${fmt(m.eotFalseTriggerRate.mean)} | ${fmt(m.eotFalseTriggerRate.worst)} | ${m.eotFalseTriggerRate.count} |`,\n\t\t`| EOT latency p50 (ms) | ${fmt(m.eotLatencyP50Ms)} | | |`,\n\t\t`| EOT latency p95 (ms) | ${fmt(m.eotLatencyP95Ms)} | | |`,\n\t\t`| Diarization DER | ${fmt(m.der.mean)} | ${fmt(m.der.worst)} | ${m.der.count} |`,\n\t\t`| Respond accuracy | ${fmt(m.respondAccuracy.mean)} | ${fmt(m.respondAccuracy.worst)} | ${m.respondAccuracy.count} |`,\n\t\t`| Entity F1 | ${fmt(m.entityF1.mean)} | ${fmt(m.entityF1.worst)} | ${m.entityF1.count} |`,\n\t\t`| Voice→entity match | ${fmt(m.voiceEntityMatchRate.mean)} | ${fmt(m.voiceEntityMatchRate.worst)} | ${m.voiceEntityMatchRate.count} |`,\n\t\t`| First-audio (ms) | ${fmt(m.firstAudioMs.mean)} | ${fmt(m.firstAudioMs.worst)} | ${m.firstAudioMs.count} |`,\n\t\t`| Echo rejection rate | ${fmt(m.echoRejectionRate.mean)} | ${fmt(m.echoRejectionRate.worst)} | ${m.echoRejectionRate.count} |`,\n\t\t`| Owner accuracy | ${fmt(m.ownerAccuracy.mean)} | ${fmt(m.ownerAccuracy.worst)} | ${m.ownerAccuracy.count} |`,\n\t\t`| Impostor-accept rate | ${fmt(m.impostorAcceptRate.mean)} | ${fmt(m.impostorAcceptRate.worst)} | ${m.impostorAcceptRate.count} |`,\n\t\t\"\",\n\t\t\"## Scenarios\",\n\t\t\"\",\n\t\t\"| Scenario | Classes | Verdict | Cases | Failed |\",\n\t\t\"| --- | --- | --- | --- | --- |\",\n\t];\n\tfor (const s of report.scenarios) {\n\t\tconst failed =\n\t\t\ts.failedCaseKinds.length > 0 ? s.failedCaseKinds.join(\", \") : \"—\";\n\t\tconst skip = s.skipReason ? ` (${s.skipReason})` : \"\";\n\t\tlines.push(\n\t\t\t`| ${s.scenarioId} | ${s.classes.join(\", \")} | ${s.verdict}${skip} | ${s.caseCount} | ${failed} |`,\n\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport interface MetricRegression {\n\tmetric: string;\n\tbaseline: number;\n\tcurrent: number;\n\tdelta: number;\n}\n\n/**\n * Compare two reports and flag metrics that regressed beyond `tolerance`.\n * \"Lower is better\" metrics (WER, EOT FTR, DER, latencies) regress when they\n * rise; \"higher is better\" metrics (accuracies, F1, match rate) regress when\n * they fall. Only metrics present (non-null mean) in both reports are compared.\n */\nexport function regressionsAgainstBaseline(\n\tcurrent: VoiceWorkbenchReport,\n\tbaseline: VoiceWorkbenchReport,\n\ttolerance = 0.02,\n): MetricRegression[] {\n\tconst lowerBetter: Array<[string, number | null, number | null]> = [\n\t\t[\"wer\", current.metrics.wer.mean, baseline.metrics.wer.mean],\n\t\t[\n\t\t\t\"eotFalseTriggerRate\",\n\t\t\tcurrent.metrics.eotFalseTriggerRate.mean,\n\t\t\tbaseline.metrics.eotFalseTriggerRate.mean,\n\t\t],\n\t\t[\n\t\t\t\"eotLatencyP95Ms\",\n\t\t\tcurrent.metrics.eotLatencyP95Ms,\n\t\t\tbaseline.metrics.eotLatencyP95Ms,\n\t\t],\n\t\t[\"der\", current.metrics.der.mean, baseline.metrics.der.mean],\n\t\t[\n\t\t\t\"firstAudioMs\",\n\t\t\tcurrent.metrics.firstAudioMs.mean,\n\t\t\tbaseline.metrics.firstAudioMs.mean,\n\t\t],\n\t\t[\n\t\t\t\"impostorAcceptRate\",\n\t\t\tcurrent.metrics.impostorAcceptRate.mean,\n\t\t\tbaseline.metrics.impostorAcceptRate.mean,\n\t\t],\n\t];\n\tconst higherBetter: Array<[string, number | null, number | null]> = [\n\t\t[\n\t\t\t\"respondAccuracy\",\n\t\t\tcurrent.metrics.respondAccuracy.mean,\n\t\t\tbaseline.metrics.respondAccuracy.mean,\n\t\t],\n\t\t[\"entityF1\", current.metrics.entityF1.mean, baseline.metrics.entityF1.mean],\n\t\t[\n\t\t\t\"voiceEntityMatchRate\",\n\t\t\tcurrent.metrics.voiceEntityMatchRate.mean,\n\t\t\tbaseline.metrics.voiceEntityMatchRate.mean,\n\t\t],\n\t\t[\n\t\t\t\"echoRejectionRate\",\n\t\t\tcurrent.metrics.echoRejectionRate.mean,\n\t\t\tbaseline.metrics.echoRejectionRate.mean,\n\t\t],\n\t\t[\n\t\t\t\"ownerAccuracy\",\n\t\t\tcurrent.metrics.ownerAccuracy.mean,\n\t\t\tbaseline.metrics.ownerAccuracy.mean,\n\t\t],\n\t];\n\tconst out: MetricRegression[] = [];\n\tfor (const [metric, cur, base] of lowerBetter) {\n\t\tif (cur === null || base === null) continue;\n\t\tconst delta = round4(cur - base);\n\t\tif (delta > tolerance)\n\t\t\tout.push({ metric, baseline: base, current: cur, delta });\n\t}\n\tfor (const [metric, cur, base] of higherBetter) {\n\t\tif (cur === null || base === null) continue;\n\t\tconst delta = round4(cur - base);\n\t\tif (delta < -tolerance)\n\t\t\tout.push({ metric, baseline: base, current: cur, delta });\n\t}\n\treturn out;\n}\n",
24
+ "/**\n * Voice Workbench entrypoint (#8785).\n *\n * One call that generates the corpus for a scenario matrix, runs them headless\n * through the (injected) voice services, and rolls the result into the single\n * JSON + Markdown benchmark report. The CLI (`voice:workbench`) and the CI lane\n * are thin shells over this:\n * - mocked lane (always): pass `groundTruthMockServices()` → runs + passes,\n * exercising corpus → runner → scorers → report end-to-end with no model;\n * - real lane (where provisioned): pass a real services adapter; absent\n * backend → `services: null` → every scenario `skipped` (never `pass`).\n *\n * Pure orchestration over the already-tested pieces, so it is unit-testable\n * without a model or a browser.\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport {\n\ttype CorpusTtsSynthesizer,\n\tgenerateVoiceCorpus,\n} from \"./corpus-generator\";\nimport type { VoiceScenario } from \"./voice-scenario\";\nimport {\n\tbuildVoiceWorkbenchReport,\n\tformatVoiceWorkbenchMarkdown,\n\ttype VoiceWorkbenchReport,\n} from \"./voice-workbench-report\";\nimport {\n\trunVoiceWorkbenchHeadless,\n\ttype VoiceWorkbenchServices,\n} from \"./workbench-headless-runner\";\nimport { VOICE_WORKBENCH_SCENARIOS } from \"./workbench-scenarios\";\n\nexport interface BuildAndRunVoiceWorkbenchArgs {\n\t/** Scenario matrix to run (defaults to the built-in set). */\n\tscenarios?: ReadonlyArray<VoiceScenario>;\n\t/** Voice services; null → every scenario is skipped (no backend). */\n\tservices: VoiceWorkbenchServices | null;\n\t/** Corpus sample rate (default 16 kHz). */\n\tsampleRate?: number;\n\t/** Real TTS for the corpus; omitted → deterministic synthetic speech. */\n\tsynthesizer?: CorpusTtsSynthesizer;\n}\n\nexport interface VoiceWorkbenchResult {\n\treport: VoiceWorkbenchReport;\n\tmarkdown: string;\n}\n\n/** Generate corpus → run headless → build the report + Markdown. */\nexport async function buildAndRunVoiceWorkbench(\n\targs: BuildAndRunVoiceWorkbenchArgs,\n): Promise<VoiceWorkbenchResult> {\n\tconst scenarios = args.scenarios ?? VOICE_WORKBENCH_SCENARIOS;\n\tconst entries = [];\n\tfor (const scenario of scenarios) {\n\t\tconst corpus = await generateVoiceCorpus(scenario, {\n\t\t\t...(args.sampleRate !== undefined ? { sampleRate: args.sampleRate } : {}),\n\t\t\t...(args.synthesizer ? { synthesizer: args.synthesizer } : {}),\n\t\t});\n\t\tentries.push({ scenario, corpus });\n\t}\n\tconst runs = await runVoiceWorkbenchHeadless({\n\t\tscenarios: entries,\n\t\tservices: args.services,\n\t});\n\tconst report = buildVoiceWorkbenchReport(runs);\n\treturn { report, markdown: formatVoiceWorkbenchMarkdown(report) };\n}\n\nexport interface VoiceWorkbenchArtifacts {\n\treportJsonPath: string;\n\treportMarkdownPath: string;\n}\n\n/** Persist the workbench result as `report.json` + `report.md` under `outDir`. */\nexport function writeVoiceWorkbenchResult(\n\tresult: VoiceWorkbenchResult,\n\toutDir: string,\n): VoiceWorkbenchArtifacts {\n\tmkdirSync(outDir, { recursive: true });\n\tconst reportJsonPath = path.join(outDir, \"report.json\");\n\tconst reportMarkdownPath = path.join(outDir, \"report.md\");\n\twriteFileSync(reportJsonPath, `${JSON.stringify(result.report, null, 2)}\\n`);\n\twriteFileSync(reportMarkdownPath, result.markdown);\n\treturn { reportJsonPath, reportMarkdownPath };\n}\n",
25
+ "/**\n * Voice Workbench headless runner (#8785).\n *\n * Drives a {@link VoiceScenario} + its generated corpus through the real voice\n * services WITHOUT a browser, scores every turn with the shared scorers\n * (`e2e-harness.ts`), and emits one {@link VoiceWorkbenchScenarioRun} the report\n * layer (`voice-workbench-report.ts`) aggregates. The services are injected\n * through {@link VoiceWorkbenchServices} so:\n * - a provisioned local backend wires the real ASR / diarization / EOT /\n * respond / entity / TTS path,\n * - a mock returns ground-truth-derived observations for the CI plumbing lane,\n * - and an ABSENT backend (`services === null`) or absent corpus\n * (`corpus === null`) yields a `skipped` run — never a `pass` (honesty\n * contract).\n *\n * Pure orchestration: it slices the corpus per turn, asks the services to\n * observe the turn, and maps observations onto scorer inputs. No model loading\n * here, so it is unit-testable with a fake services adapter.\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n\tCorpusGroundTruth,\n\tCorpusTurnLabel,\n\tGeneratedVoiceCorpus,\n} from \"./corpus-generator\";\nimport {\n\ttype DiarizationTurnSample,\n\tscoreDiarizationTimeline,\n\tscoreEchoRejection,\n\tscoreEntityExtraction,\n\tscoreEotDecision,\n\tscoreFirstResponseLatency,\n\tscoreOwnerSecurity,\n\tscoreRespondDecision,\n\tscoreTtsAsrRoundTrip,\n\tscoreVoiceEntityMatch,\n\ttype VoiceE2eCaseResult,\n} from \"./e2e-harness\";\nimport type { VoiceScenario } from \"./voice-scenario\";\nimport type {\n\tVoiceAudioArtifact,\n\tVoiceWorkbenchScenarioRun,\n} from \"./voice-workbench-report\";\nimport { encodeMonoPcm16Wav } from \"./wav-codec\";\n\n/** What the real (or mock) services observed for one turn of audio. */\nexport interface VoiceTurnObservation {\n\t/** ASR hypothesis transcript for the turn's audio. */\n\thypothesisTranscript: string;\n\t/** Diarized speaker label, or null when the diarizer missed the turn. */\n\tpredictedSpeakerLabel: string | null;\n\t/** The EOT classifier decided end-of-turn at this turn's boundary. */\n\teotDecided: boolean;\n\t/** EOT decision latency (ms) from the true boundary, when measured. */\n\teotLatencyMs?: number;\n\t/** The agent decided to respond to this turn. */\n\tresponded: boolean;\n\t/** Entities inferred from this turn's transcript (name/partner extraction). */\n\tinferredEntities: string[];\n\t/** Voice→entity match: the entity the recognized voice resolved to (or null). */\n\tmatchedEntityId: string | null;\n\t/** First-audio latency (ms) of the agent's spoken reply, when it replied. */\n\tfirstAudioMs?: number;\n\t/** The system judged this turn to be the device owner (owner-security). */\n\tpredictedOwner?: boolean;\n}\n\nexport interface VoiceWorkbenchServices {\n\t/**\n\t * Optional one-shot hook before a scenario's turns are scored. Real services\n\t * use this to enroll speaker centroids from the generated corpus; mock\n\t * services can omit it.\n\t */\n\tprepareScenario?(args: {\n\t\tscenario: VoiceScenario;\n\t\tcorpus: GeneratedVoiceCorpus;\n\t}): Promise<void> | void;\n\t/**\n\t * Feed one turn's audio slice through the real services and report what was\n\t * observed. The `label` carries the turn's ground truth (so a mock can echo\n\t * it); the real adapter ignores it and measures.\n\t */\n\tobserveTurn(args: {\n\t\tturnIndex: number;\n\t\taudio: Float32Array;\n\t\tsampleRate: number;\n\t\tlabel: CorpusTurnLabel;\n\t\t/** Scenario-level ground truth (participants, owner set, agents). */\n\t\tgroundTruth: CorpusGroundTruth;\n\t}): Promise<VoiceTurnObservation>;\n}\n\n/**\n * Where to write per-run `.wav` artifacts. When present, the runner encodes the\n * full corpus + each consumed per-turn slice to disk under `dir` and records the\n * paths (relative to `relativeTo`) on the run's `audioArtifacts`. Absent ⇒ no IO.\n */\nexport interface VoiceAudioCaptureSink {\n\t/** Directory the `.wav` files are written into (created recursively). */\n\tdir: string;\n\t/** Artifact paths are recorded relative to this dir (the scenario run dir). */\n\trelativeTo: string;\n}\n\nexport interface RunVoiceScenarioHeadlessArgs {\n\tscenario: VoiceScenario;\n\t/** The generated/loaded corpus; null when its artifacts are absent. */\n\tcorpus: GeneratedVoiceCorpus | null;\n\t/** The voice services; null when no backend is provisioned. */\n\tservices: VoiceWorkbenchServices | null;\n\t/** When set, write the run's audio as `.wav` artifacts and record their paths. */\n\tcaptureAudio?: VoiceAudioCaptureSink;\n}\n\n/** Encode `pcm` to `<dir>/<fileName>` and return a relative-path artifact. */\nfunction writeAudioArtifact(args: {\n\tsink: VoiceAudioCaptureSink;\n\tfileName: string;\n\tpcm: Float32Array;\n\tsampleRate: number;\n\tturnIndex: number;\n\tkind: VoiceAudioArtifact[\"kind\"];\n\tspeakerLabel?: string;\n}): VoiceAudioArtifact {\n\tconst absolutePath = path.join(args.sink.dir, args.fileName);\n\twriteFileSync(absolutePath, encodeMonoPcm16Wav(args.pcm, args.sampleRate));\n\tconst relativePath = path\n\t\t.relative(args.sink.relativeTo, absolutePath)\n\t\t.split(path.sep)\n\t\t.join(\"/\");\n\treturn {\n\t\tturnIndex: args.turnIndex,\n\t\tkind: args.kind,\n\t\tpath: relativePath,\n\t\tsampleRate: args.sampleRate,\n\t\tdurationMs: Math.round((args.pcm.length / args.sampleRate) * 1000),\n\t\t...(args.speakerLabel !== undefined\n\t\t\t? { speakerLabel: args.speakerLabel }\n\t\t\t: {}),\n\t};\n}\n\nfunction skipped(\n\tscenario: VoiceScenario,\n\tskipReason: string,\n): VoiceWorkbenchScenarioRun {\n\treturn {\n\t\tscenarioId: scenario.id,\n\t\tclasses: scenario.classes,\n\t\tstatus: \"skipped\",\n\t\tcases: [],\n\t\tskipReason,\n\t};\n}\n\n/**\n * Run one scenario headless and score it. Returns a `skipped` run (never a\n * pass) when the corpus or the backend is absent.\n */\nexport async function runVoiceScenarioHeadless(\n\targs: RunVoiceScenarioHeadlessArgs,\n): Promise<VoiceWorkbenchScenarioRun> {\n\tconst { scenario, corpus, services, captureAudio } = args;\n\tif (!corpus) return skipped(scenario, \"corpus artifacts absent\");\n\tif (!services) return skipped(scenario, \"no voice backend provisioned\");\n\n\tconst assertions = scenario.assertions ?? {};\n\tconst cases: VoiceE2eCaseResult[] = [];\n\tawait services.prepareScenario?.({ scenario, corpus });\n\n\t// When a capture sink is active, write the full corpus once + each per-turn\n\t// slice as `.wav` artifacts and record their (run-dir-relative) paths.\n\tconst audioArtifacts: VoiceAudioArtifact[] = [];\n\tif (captureAudio) {\n\t\tmkdirSync(captureAudio.dir, { recursive: true });\n\t\taudioArtifacts.push(\n\t\t\twriteAudioArtifact({\n\t\t\t\tsink: captureAudio,\n\t\t\t\tfileName: \"corpus.wav\",\n\t\t\t\tpcm: corpus.pcm,\n\t\t\t\tsampleRate: corpus.sampleRate,\n\t\t\t\tturnIndex: 0,\n\t\t\t\tkind: \"generated\",\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst eotSamples: Array<{\n\t\tdecided: boolean;\n\t\texpected: boolean;\n\t\tlatencyMs?: number;\n\t}> = [];\n\tconst diarTurns: DiarizationTurnSample[] = [];\n\tconst respondSamples: Array<{ responded: boolean; expectRespond: boolean }> =\n\t\t[];\n\tconst voiceEntitySamples: Array<{\n\t\tmatchedEntityId: string | null;\n\t\texpectedEntityId: string;\n\t}> = [];\n\tconst inferredEntities: string[] = [];\n\tconst expectedEntities: string[] = [];\n\tconst echoSamples: Array<{ isAgentEcho: boolean; responded: boolean }> = [];\n\tconst ownerSamples: Array<{\n\t\tpredictedOwner: boolean;\n\t\texpectedOwner: boolean;\n\t}> = [];\n\tconst wantsOwnerScoring = scenario.classes.includes(\"owner-security\");\n\n\tfor (const label of corpus.groundTruth.turns) {\n\t\tconst audio = corpus.pcm.subarray(\n\t\t\tlabel.segmentStartSample,\n\t\t\tlabel.segmentEndSample,\n\t\t);\n\t\tif (captureAudio) {\n\t\t\taudioArtifacts.push(\n\t\t\t\twriteAudioArtifact({\n\t\t\t\t\tsink: captureAudio,\n\t\t\t\t\tfileName: `turn-${label.index}.wav`,\n\t\t\t\t\tpcm: audio,\n\t\t\t\t\tsampleRate: corpus.sampleRate,\n\t\t\t\t\tturnIndex: label.index,\n\t\t\t\t\tkind: \"consumed\",\n\t\t\t\t\tspeakerLabel: label.speaker,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst obs = await services.observeTurn({\n\t\t\tturnIndex: label.index,\n\t\t\taudio,\n\t\t\tsampleRate: corpus.sampleRate,\n\t\t\tlabel,\n\t\t\tgroundTruth: corpus.groundTruth,\n\t\t});\n\n\t\t// WER — one round-trip case per turn (referenceTranscript vs ASR hypothesis).\n\t\tcases.push(\n\t\t\tscoreTtsAsrRoundTrip({\n\t\t\t\treferenceText: label.referenceTranscript,\n\t\t\t\thypothesisText: obs.hypothesisTranscript,\n\t\t\t\t...(assertions.maxWer !== undefined\n\t\t\t\t\t? { maxWer: assertions.maxWer }\n\t\t\t\t\t: {}),\n\t\t\t}),\n\t\t);\n\n\t\t// EOT — some corpus segments deliberately stop mid-utterance so the\n\t\t// classifier can be scored for false triggers.\n\t\teotSamples.push({\n\t\t\tdecided: obs.eotDecided,\n\t\t\texpected: label.expectEndOfTurn ?? true,\n\t\t\t...(obs.eotLatencyMs !== undefined\n\t\t\t\t? { latencyMs: obs.eotLatencyMs }\n\t\t\t\t: {}),\n\t\t});\n\t\t// Diarization scores REAL speaker turns only — an agent-echo turn is the\n\t\t// agent's own voice bleeding back, not a speaker to attribute, so it is\n\t\t// handled by the echo-rejection scorer instead.\n\t\tif (!label.isAgentEcho) {\n\t\t\tdiarTurns.push({\n\t\t\t\tpredictedLabel: obs.predictedSpeakerLabel,\n\t\t\t\texpectedLabel: label.speaker,\n\t\t\t\tstartMs: (label.speechStartSample / corpus.sampleRate) * 1000,\n\t\t\t\tendMs: (label.speechEndSample / corpus.sampleRate) * 1000,\n\t\t\t});\n\t\t}\n\t\trespondSamples.push({\n\t\t\tresponded: obs.responded,\n\t\t\texpectRespond: label.expectRespond,\n\t\t});\n\t\tif (label.entityId) {\n\t\t\tvoiceEntitySamples.push({\n\t\t\t\tmatchedEntityId: obs.matchedEntityId,\n\t\t\t\texpectedEntityId: label.entityId,\n\t\t\t});\n\t\t}\n\t\tif (label.expectedEntity) expectedEntities.push(label.expectedEntity);\n\t\tinferredEntities.push(...obs.inferredEntities);\n\n\t\tif (label.isAgentEcho) {\n\t\t\techoSamples.push({ isAgentEcho: true, responded: obs.responded });\n\t\t}\n\t\tif (wantsOwnerScoring && typeof obs.predictedOwner === \"boolean\") {\n\t\t\townerSamples.push({\n\t\t\t\tpredictedOwner: obs.predictedOwner,\n\t\t\t\texpectedOwner: label.isOwner === true,\n\t\t\t});\n\t\t}\n\n\t\tif (obs.responded && typeof obs.firstAudioMs === \"number\") {\n\t\t\tcases.push(\n\t\t\t\tscoreFirstResponseLatency({\n\t\t\t\t\tturnStartedAtMs: 0,\n\t\t\t\t\tttsFirstAudioAtMs: obs.firstAudioMs,\n\t\t\t\t\t...(assertions.maxFirstAudioMs !== undefined\n\t\t\t\t\t\t? { maxFirstAudioMs: assertions.maxFirstAudioMs }\n\t\t\t\t\t\t: {}),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tcases.push(\n\t\tscoreEotDecision(eotSamples, {\n\t\t\t...(assertions.maxEotFalseTriggerRate !== undefined\n\t\t\t\t? { maxFalseTriggerRate: assertions.maxEotFalseTriggerRate }\n\t\t\t\t: {}),\n\t\t}),\n\t);\n\tif (diarTurns.length > 0) {\n\t\tcases.push(\n\t\t\tscoreDiarizationTimeline(diarTurns, {\n\t\t\t\t...(assertions.maxDer !== undefined\n\t\t\t\t\t? { maxDer: assertions.maxDer }\n\t\t\t\t\t: {}),\n\t\t\t}),\n\t\t);\n\t}\n\tcases.push(\n\t\tscoreRespondDecision(respondSamples, {\n\t\t\t...(assertions.minRespondAccuracy !== undefined\n\t\t\t\t? { minAccuracy: assertions.minRespondAccuracy }\n\t\t\t\t: {}),\n\t\t}),\n\t);\n\t// Entity extraction + voice→entity match only when the scenario asserts them.\n\tif (expectedEntities.length > 0 || inferredEntities.length > 0) {\n\t\tcases.push(\n\t\t\tscoreEntityExtraction({\n\t\t\t\texpected: expectedEntities,\n\t\t\t\tinferred: inferredEntities,\n\t\t\t}),\n\t\t);\n\t}\n\tif (voiceEntitySamples.length > 0) {\n\t\tcases.push(\n\t\t\tscoreVoiceEntityMatch(voiceEntitySamples, {\n\t\t\t\t...(assertions.minVoiceEntityMatchRate !== undefined\n\t\t\t\t\t? { minMatchRate: assertions.minVoiceEntityMatchRate }\n\t\t\t\t\t: {}),\n\t\t\t}),\n\t\t);\n\t}\n\tif (echoSamples.length > 0) {\n\t\tcases.push(\n\t\t\tscoreEchoRejection(echoSamples, {\n\t\t\t\t...(assertions.minEchoRejectionRate !== undefined\n\t\t\t\t\t? { minRejectionRate: assertions.minEchoRejectionRate }\n\t\t\t\t\t: {}),\n\t\t\t}),\n\t\t);\n\t}\n\tif (ownerSamples.length > 0) {\n\t\tcases.push(\n\t\t\tscoreOwnerSecurity(ownerSamples, {\n\t\t\t\t...(assertions.minOwnerAccuracy !== undefined\n\t\t\t\t\t? { minAccuracy: assertions.minOwnerAccuracy }\n\t\t\t\t\t: {}),\n\t\t\t}),\n\t\t);\n\t}\n\n\treturn {\n\t\tscenarioId: scenario.id,\n\t\tclasses: scenario.classes,\n\t\tstatus: \"ran\",\n\t\tcases,\n\t\t...(audioArtifacts.length > 0 ? { audioArtifacts } : {}),\n\t};\n}\n\nexport interface RunVoiceWorkbenchArgs {\n\tscenarios: ReadonlyArray<{\n\t\tscenario: VoiceScenario;\n\t\tcorpus: GeneratedVoiceCorpus | null;\n\t}>;\n\tservices: VoiceWorkbenchServices | null;\n}\n\n/** Run a matrix of scenarios headless, returning one run per scenario. */\nexport async function runVoiceWorkbenchHeadless(\n\targs: RunVoiceWorkbenchArgs,\n): Promise<VoiceWorkbenchScenarioRun[]> {\n\tconst runs: VoiceWorkbenchScenarioRun[] = [];\n\tfor (const entry of args.scenarios) {\n\t\truns.push(\n\t\t\tawait runVoiceScenarioHeadless({\n\t\t\t\tscenario: entry.scenario,\n\t\t\t\tcorpus: entry.corpus,\n\t\t\t\tservices: args.services,\n\t\t\t}),\n\t\t);\n\t}\n\treturn runs;\n}\n",
26
+ "/**\n * Pure scoring and validation helpers for the local voice E2E harnesses.\n *\n * This file intentionally does not load models, touch the filesystem, or\n * start servers. Hardware scripts feed it real measurements; unit tests can\n * exercise the orchestration logic without native artifacts.\n *\n * Word-error-rate scoring lives in `@elizaos/shared/voice-wer` (the single\n * source of truth shared with the headful self-test, #8785); it is re-exported\n * here so existing `./e2e-harness` importers keep working unchanged.\n */\n\nexport { normalizeWerText, wordErrorRate } from \"@elizaos/shared/voice-wer\";\n\nimport { normalizeWerText, wordErrorRate } from \"@elizaos/shared/voice-wer\";\nimport {\n\tcomputeDiarizationErrorRate,\n\ttype DiarizationSegment,\n} from \"./diarization-error-rate\";\nimport { percentile, round1, round4 } from \"./metric-math\";\n\nexport type VoiceE2eHarnessErrorCode =\n\t| \"missing-artifact\"\n\t| \"missing-measurement\"\n\t| \"invalid-measurement\";\n\nexport class VoiceE2eHarnessError extends Error {\n\treadonly code: VoiceE2eHarnessErrorCode;\n\treadonly details?: unknown;\n\n\tconstructor(\n\t\tcode: VoiceE2eHarnessErrorCode,\n\t\tmessage: string,\n\t\tdetails?: unknown,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"VoiceE2eHarnessError\";\n\t\tthis.code = code;\n\t\tthis.details = details;\n\t}\n}\n\nexport interface RequiredVoiceArtifact {\n\tkind:\n\t\t| \"bundle-root\"\n\t\t| \"speaker-preset\"\n\t\t| \"tts-model\"\n\t\t| \"tts-tokenizer\"\n\t\t| \"asr-model\"\n\t\t| \"asr-mmproj\"\n\t\t| \"ffi-library\"\n\t\t| \"server-binary\";\n\tpath: string;\n\tminBytes?: number;\n\tmagic?: string;\n}\n\nexport interface VoiceArtifactProbe {\n\texists(path: string): boolean;\n\tsize(path: string): number | null;\n\treadMagic?(path: string, bytes: number): string | null;\n}\n\nexport interface VerifiedVoiceArtifact extends RequiredVoiceArtifact {\n\tsize: number | null;\n}\n\nexport function assertRequiredVoiceArtifacts(\n\tartifacts: ReadonlyArray<RequiredVoiceArtifact>,\n\tprobe: VoiceArtifactProbe,\n): VerifiedVoiceArtifact[] {\n\tconst failures: Array<{\n\t\tkind: RequiredVoiceArtifact[\"kind\"];\n\t\tpath: string;\n\t\treason: string;\n\t}> = [];\n\tconst verified: VerifiedVoiceArtifact[] = [];\n\n\tfor (const artifact of artifacts) {\n\t\tif (!probe.exists(artifact.path)) {\n\t\t\tfailures.push({\n\t\t\t\tkind: artifact.kind,\n\t\t\t\tpath: artifact.path,\n\t\t\t\treason: \"not found\",\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst size = probe.size(artifact.path);\n\t\tif (\n\t\t\tartifact.minBytes !== undefined &&\n\t\t\tsize !== null &&\n\t\t\tsize < artifact.minBytes\n\t\t) {\n\t\t\tfailures.push({\n\t\t\t\tkind: artifact.kind,\n\t\t\t\tpath: artifact.path,\n\t\t\t\treason: `too small (${size} bytes < ${artifact.minBytes} bytes)`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (artifact.magic) {\n\t\t\tconst got = probe.readMagic?.(artifact.path, artifact.magic.length);\n\t\t\tif (got !== artifact.magic) {\n\t\t\t\tfailures.push({\n\t\t\t\t\tkind: artifact.kind,\n\t\t\t\t\tpath: artifact.path,\n\t\t\t\t\treason: `bad magic (${JSON.stringify(got)} !== ${JSON.stringify(\n\t\t\t\t\t\tartifact.magic,\n\t\t\t\t\t)})`,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tverified.push({ ...artifact, size });\n\t}\n\n\tif (failures.length > 0) {\n\t\tconst list = failures\n\t\t\t.map((f) => `- ${f.kind}: ${f.path} (${f.reason})`)\n\t\t\t.join(\"\\n\");\n\t\tthrow new VoiceE2eHarnessError(\n\t\t\t\"missing-artifact\",\n\t\t\t`Missing required Eliza-1 voice artifact(s):\\n${list}`,\n\t\t\t{ failures },\n\t\t);\n\t}\n\n\treturn verified;\n}\n\nexport interface TtsAsrRoundTripInput {\n\treferenceText: string;\n\thypothesisText: string;\n\tmaxWer?: number;\n}\n\nexport interface TtsAsrRoundTripResult {\n\tkind: \"tts-asr-roundtrip\";\n\treferenceText: string;\n\thypothesisText: string;\n\tnormalizedReference: string;\n\tnormalizedHypothesis: string;\n\twer: number;\n\tmaxWer: number;\n\tpassed: boolean;\n}\n\nexport function scoreTtsAsrRoundTrip(\n\tinput: TtsAsrRoundTripInput,\n): TtsAsrRoundTripResult {\n\tconst maxWer = input.maxWer ?? 0.15;\n\tconst wer = wordErrorRate(input.referenceText, input.hypothesisText);\n\treturn {\n\t\tkind: \"tts-asr-roundtrip\",\n\t\treferenceText: input.referenceText,\n\t\thypothesisText: input.hypothesisText,\n\t\tnormalizedReference: normalizeWerText(input.referenceText),\n\t\tnormalizedHypothesis: normalizeWerText(input.hypothesisText),\n\t\twer: round4(wer),\n\t\tmaxWer,\n\t\tpassed: wer <= maxWer,\n\t};\n}\n\nexport interface BargeInInterruptionInput {\n\tvoiceDetectedAtMs: number;\n\tttsCancelledAtMs?: number | null;\n\tllmCancelledAtMs?: number | null;\n\taudioDrainedAtMs?: number | null;\n\tmaxCancelMs?: number;\n\trequireLlmCancel?: boolean;\n}\n\nexport interface BargeInInterruptionResult {\n\tkind: \"barge-in-interruption\";\n\tttsCancelMs: number | null;\n\tllmCancelMs: number | null;\n\taudioDrainMs: number | null;\n\tbargeInCancelMs: number;\n\tmaxCancelMs: number;\n\tpassed: boolean;\n}\n\nexport function scoreBargeInInterruption(\n\tinput: BargeInInterruptionInput,\n): BargeInInterruptionResult {\n\tconst maxCancelMs = input.maxCancelMs ?? 250;\n\tconst ttsCancelMs = optionalDuration(\n\t\t\"voiceDetectedAtMs\",\n\t\tinput.voiceDetectedAtMs,\n\t\t\"ttsCancelledAtMs\",\n\t\tinput.ttsCancelledAtMs,\n\t);\n\tconst llmCancelMs = optionalDuration(\n\t\t\"voiceDetectedAtMs\",\n\t\tinput.voiceDetectedAtMs,\n\t\t\"llmCancelledAtMs\",\n\t\tinput.llmCancelledAtMs,\n\t);\n\tconst audioDrainMs = optionalDuration(\n\t\t\"voiceDetectedAtMs\",\n\t\tinput.voiceDetectedAtMs,\n\t\t\"audioDrainedAtMs\",\n\t\tinput.audioDrainedAtMs,\n\t);\n\n\tif (ttsCancelMs === null) {\n\t\tthrow missingMeasurement(\"ttsCancelledAtMs\");\n\t}\n\tif (input.requireLlmCancel !== false && llmCancelMs === null) {\n\t\tthrow missingMeasurement(\"llmCancelledAtMs\");\n\t}\n\n\tconst measured = [ttsCancelMs, llmCancelMs, audioDrainMs].filter(\n\t\t(value): value is number => value !== null,\n\t);\n\tconst bargeInCancelMs = Math.max(...measured);\n\treturn {\n\t\tkind: \"barge-in-interruption\",\n\t\tttsCancelMs: round1(ttsCancelMs),\n\t\tllmCancelMs: llmCancelMs === null ? null : round1(llmCancelMs),\n\t\taudioDrainMs: audioDrainMs === null ? null : round1(audioDrainMs),\n\t\tbargeInCancelMs: round1(bargeInCancelMs),\n\t\tmaxCancelMs,\n\t\tpassed: bargeInCancelMs <= maxCancelMs,\n\t};\n}\n\nexport interface PauseContinuationInput {\n\tspeechPauseAtMs: number;\n\tcontinuationAtMs: number;\n\tspeculativeStartedAtMs?: number | null;\n\tspeculativeAbortedAtMs?: number | null;\n\tfinalRestartedAtMs?: number | null;\n\tcommittedBeforeContinuationAtMs?: number | null;\n\tmaxContinuationGapMs?: number;\n\tmaxAbortAfterContinuationMs?: number;\n\tmaxRestartAfterContinuationMs?: number;\n}\n\nexport interface PauseContinuationResult {\n\tkind: \"pause-continuation\";\n\tcontinuationGapMs: number;\n\tspeculativeStartAfterPauseMs: number | null;\n\tabortAfterContinuationMs: number;\n\trestartAfterContinuationMs: number;\n\tmaxContinuationGapMs: number;\n\tpassed: boolean;\n}\n\nexport function scorePauseContinuation(\n\tinput: PauseContinuationInput,\n): PauseContinuationResult {\n\tconst maxContinuationGapMs = input.maxContinuationGapMs ?? 4000;\n\tconst maxAbortAfterContinuationMs = input.maxAbortAfterContinuationMs ?? 250;\n\tconst maxRestartAfterContinuationMs =\n\t\tinput.maxRestartAfterContinuationMs ?? 1000;\n\tconst continuationGapMs = duration(\n\t\t\"speechPauseAtMs\",\n\t\tinput.speechPauseAtMs,\n\t\t\"continuationAtMs\",\n\t\tinput.continuationAtMs,\n\t);\n\tconst speculativeStartAfterPauseMs = optionalDuration(\n\t\t\"speechPauseAtMs\",\n\t\tinput.speechPauseAtMs,\n\t\t\"speculativeStartedAtMs\",\n\t\tinput.speculativeStartedAtMs,\n\t);\n\tconst abortAfterContinuationMs = duration(\n\t\t\"continuationAtMs\",\n\t\tinput.continuationAtMs,\n\t\t\"speculativeAbortedAtMs\",\n\t\trequired(input.speculativeAbortedAtMs, \"speculativeAbortedAtMs\"),\n\t);\n\tconst restartAfterContinuationMs = duration(\n\t\t\"continuationAtMs\",\n\t\tinput.continuationAtMs,\n\t\t\"finalRestartedAtMs\",\n\t\trequired(input.finalRestartedAtMs, \"finalRestartedAtMs\"),\n\t);\n\tconst committedBefore =\n\t\tinput.committedBeforeContinuationAtMs !== null &&\n\t\tinput.committedBeforeContinuationAtMs !== undefined &&\n\t\tinput.committedBeforeContinuationAtMs < input.continuationAtMs;\n\n\treturn {\n\t\tkind: \"pause-continuation\",\n\t\tcontinuationGapMs: round1(continuationGapMs),\n\t\tspeculativeStartAfterPauseMs:\n\t\t\tspeculativeStartAfterPauseMs === null\n\t\t\t\t? null\n\t\t\t\t: round1(speculativeStartAfterPauseMs),\n\t\tabortAfterContinuationMs: round1(abortAfterContinuationMs),\n\t\trestartAfterContinuationMs: round1(restartAfterContinuationMs),\n\t\tmaxContinuationGapMs,\n\t\tpassed:\n\t\t\t!committedBefore &&\n\t\t\tcontinuationGapMs <= maxContinuationGapMs &&\n\t\t\tabortAfterContinuationMs <= maxAbortAfterContinuationMs &&\n\t\t\trestartAfterContinuationMs <= maxRestartAfterContinuationMs,\n\t};\n}\n\nexport interface OptimisticRollbackRestartInput {\n\tspeechPauseAtMs: number;\n\tcontinuationAtMs: number;\n\tcheckpointSavedAtMs?: number | null;\n\tspeculativeStartedAtMs?: number | null;\n\tspeculativeAbortedAtMs?: number | null;\n\tcheckpointRestoredAtMs?: number | null;\n\trestartedAtMs?: number | null;\n\tmaxRestoreAfterContinuationMs?: number;\n\tmaxRestartAfterRestoreMs?: number;\n}\n\nexport interface OptimisticRollbackRestartResult {\n\tkind: \"optimistic-rollback-restart\";\n\tsaveAfterPauseMs: number | null;\n\tabortAfterContinuationMs: number;\n\trestoreAfterContinuationMs: number;\n\trestartAfterRestoreMs: number;\n\tpassed: boolean;\n}\n\nexport function scoreOptimisticRollbackRestart(\n\tinput: OptimisticRollbackRestartInput,\n): OptimisticRollbackRestartResult {\n\tconst maxRestoreAfterContinuationMs =\n\t\tinput.maxRestoreAfterContinuationMs ?? 300;\n\tconst maxRestartAfterRestoreMs = input.maxRestartAfterRestoreMs ?? 1000;\n\tconst saveAfterPauseMs = optionalDuration(\n\t\t\"speechPauseAtMs\",\n\t\tinput.speechPauseAtMs,\n\t\t\"checkpointSavedAtMs\",\n\t\tinput.checkpointSavedAtMs,\n\t);\n\tconst abortAfterContinuationMs = duration(\n\t\t\"continuationAtMs\",\n\t\tinput.continuationAtMs,\n\t\t\"speculativeAbortedAtMs\",\n\t\trequired(input.speculativeAbortedAtMs, \"speculativeAbortedAtMs\"),\n\t);\n\tconst restoreAfterContinuationMs = duration(\n\t\t\"continuationAtMs\",\n\t\tinput.continuationAtMs,\n\t\t\"checkpointRestoredAtMs\",\n\t\trequired(input.checkpointRestoredAtMs, \"checkpointRestoredAtMs\"),\n\t);\n\tconst restartAfterRestoreMs = duration(\n\t\t\"checkpointRestoredAtMs\",\n\t\trequired(input.checkpointRestoredAtMs, \"checkpointRestoredAtMs\"),\n\t\t\"restartedAtMs\",\n\t\trequired(input.restartedAtMs, \"restartedAtMs\"),\n\t);\n\n\treturn {\n\t\tkind: \"optimistic-rollback-restart\",\n\t\tsaveAfterPauseMs:\n\t\t\tsaveAfterPauseMs === null ? null : round1(saveAfterPauseMs),\n\t\tabortAfterContinuationMs: round1(abortAfterContinuationMs),\n\t\trestoreAfterContinuationMs: round1(restoreAfterContinuationMs),\n\t\trestartAfterRestoreMs: round1(restartAfterRestoreMs),\n\t\tpassed:\n\t\t\trestoreAfterContinuationMs <= maxRestoreAfterContinuationMs &&\n\t\t\trestartAfterRestoreMs <= maxRestartAfterRestoreMs &&\n\t\t\tabortAfterContinuationMs <= maxRestoreAfterContinuationMs,\n\t};\n}\n\nexport interface FirstResponseLatencyInput {\n\tturnStartedAtMs: number;\n\tasrFinalAtMs?: number | null;\n\tllmFirstTokenAtMs?: number | null;\n\tttsFirstAudioAtMs?: number | null;\n\taudioFirstPlayedAtMs?: number | null;\n\tmaxFirstAudioMs?: number;\n}\n\nexport interface FirstResponseLatencyResult {\n\tkind: \"first-response-latency\";\n\tasrFinalMs: number | null;\n\tfirstTokenMs: number | null;\n\tfirstAudioMs: number;\n\tfirstPlayedMs: number | null;\n\tmaxFirstAudioMs: number;\n\tpassed: boolean;\n}\n\nexport function scoreFirstResponseLatency(\n\tinput: FirstResponseLatencyInput,\n): FirstResponseLatencyResult {\n\tconst maxFirstAudioMs = input.maxFirstAudioMs ?? 1500;\n\tconst asrFinalMs = optionalDuration(\n\t\t\"turnStartedAtMs\",\n\t\tinput.turnStartedAtMs,\n\t\t\"asrFinalAtMs\",\n\t\tinput.asrFinalAtMs,\n\t);\n\tconst firstTokenMs = optionalDuration(\n\t\t\"turnStartedAtMs\",\n\t\tinput.turnStartedAtMs,\n\t\t\"llmFirstTokenAtMs\",\n\t\tinput.llmFirstTokenAtMs,\n\t);\n\tconst firstAudioMs = duration(\n\t\t\"turnStartedAtMs\",\n\t\tinput.turnStartedAtMs,\n\t\t\"ttsFirstAudioAtMs\",\n\t\trequired(input.ttsFirstAudioAtMs, \"ttsFirstAudioAtMs\"),\n\t);\n\tconst firstPlayedMs = optionalDuration(\n\t\t\"turnStartedAtMs\",\n\t\tinput.turnStartedAtMs,\n\t\t\"audioFirstPlayedAtMs\",\n\t\tinput.audioFirstPlayedAtMs,\n\t);\n\n\treturn {\n\t\tkind: \"first-response-latency\",\n\t\tasrFinalMs: asrFinalMs === null ? null : round1(asrFinalMs),\n\t\tfirstTokenMs: firstTokenMs === null ? null : round1(firstTokenMs),\n\t\tfirstAudioMs: round1(firstAudioMs),\n\t\tfirstPlayedMs: firstPlayedMs === null ? null : round1(firstPlayedMs),\n\t\tmaxFirstAudioMs,\n\t\tpassed: firstAudioMs <= maxFirstAudioMs,\n\t};\n}\n\n// ── EOT decision: latency + false-trigger / false-suppression over a stream ──\n\nexport interface EotDecisionSample {\n\t/** The classifier decided end-of-turn here (the agent may jump in). */\n\tdecided: boolean;\n\t/** Ground truth: this point WAS a real turn boundary. */\n\texpected: boolean;\n\t/** Optional ms from the true boundary to the decision (decided samples). */\n\tlatencyMs?: number;\n}\n\nexport interface EotDecisionResult {\n\tkind: \"eot-decision\";\n\ttotal: number;\n\t/** decided where there was no real boundary (jumped in too eagerly). */\n\tfalseTriggerRate: number;\n\t/** missed a real boundary (held when it should have ended the turn). */\n\tfalseSuppressionRate: number;\n\taccuracy: number;\n\tlatencyP50Ms: number | null;\n\tlatencyP95Ms: number | null;\n\tmaxFalseTriggerRate: number;\n\tpassed: boolean;\n}\n\nexport function scoreEotDecision(\n\tsamples: ReadonlyArray<EotDecisionSample>,\n\topts: { maxFalseTriggerRate?: number } = {},\n): EotDecisionResult {\n\tconst maxFalseTriggerRate = opts.maxFalseTriggerRate ?? 0.1;\n\tconst total = samples.length;\n\tlet falseTrigger = 0;\n\tlet falseSuppression = 0;\n\tlet correct = 0;\n\tconst latencies: number[] = [];\n\tfor (const s of samples) {\n\t\tif (s.decided && !s.expected) falseTrigger += 1;\n\t\tif (!s.decided && s.expected) falseSuppression += 1;\n\t\tif (s.decided === s.expected) correct += 1;\n\t\tif (s.decided && typeof s.latencyMs === \"number\")\n\t\t\tlatencies.push(s.latencyMs);\n\t}\n\tconst ftr = total > 0 ? falseTrigger / total : 0;\n\treturn {\n\t\tkind: \"eot-decision\",\n\t\ttotal,\n\t\tfalseTriggerRate: round4(ftr),\n\t\tfalseSuppressionRate: round4(total > 0 ? falseSuppression / total : 0),\n\t\taccuracy: round4(total > 0 ? correct / total : 0),\n\t\tlatencyP50Ms: percentile(latencies, 50),\n\t\tlatencyP95Ms: percentile(latencies, 95),\n\t\tmaxFalseTriggerRate,\n\t\tpassed: total > 0 && ftr <= maxFalseTriggerRate,\n\t};\n}\n\n// ── Respond decision: respond-when-should vs respond-when-shouldn't ──────────\n\nexport interface RespondDecisionSample {\n\tresponded: boolean;\n\texpectRespond: boolean;\n}\n\nexport interface RespondDecisionResult {\n\tkind: \"respond-decision\";\n\ttotal: number;\n\taccuracy: number;\n\t/** responded when it should NOT have (talked over / answered a bystander). */\n\tfalsePositiveRate: number;\n\t/** stayed silent when it SHOULD have replied. */\n\tfalseNegativeRate: number;\n\tminAccuracy: number;\n\tpassed: boolean;\n}\n\nexport function scoreRespondDecision(\n\tsamples: ReadonlyArray<RespondDecisionSample>,\n\topts: { minAccuracy?: number } = {},\n): RespondDecisionResult {\n\tconst minAccuracy = opts.minAccuracy ?? 0.9;\n\tconst total = samples.length;\n\tlet correct = 0;\n\tlet fp = 0;\n\tlet fn = 0;\n\tlet shouldNot = 0;\n\tlet should = 0;\n\tfor (const s of samples) {\n\t\tif (s.responded === s.expectRespond) correct += 1;\n\t\tif (s.expectRespond) should += 1;\n\t\telse shouldNot += 1;\n\t\tif (s.responded && !s.expectRespond) fp += 1;\n\t\tif (!s.responded && s.expectRespond) fn += 1;\n\t}\n\tconst accuracy = total > 0 ? correct / total : 0;\n\treturn {\n\t\tkind: \"respond-decision\",\n\t\ttotal,\n\t\taccuracy: round4(accuracy),\n\t\tfalsePositiveRate: round4(shouldNot > 0 ? fp / shouldNot : 0),\n\t\tfalseNegativeRate: round4(should > 0 ? fn / should : 0),\n\t\tminAccuracy,\n\t\tpassed: total > 0 && accuracy >= minAccuracy,\n\t};\n}\n\n// ── Diarization: DER (speaker-confusion) against ground-truth labels ─────────\n\nexport interface DiarizationSample {\n\tpredictedLabel: string | null;\n\texpectedLabel: string;\n}\n\nexport interface DiarizationResult {\n\tkind: \"diarization\";\n\ttotal: number;\n\t/** Diarization error rate: fraction of turns whose speaker was wrong/missing. */\n\tder: number;\n\tconfusions: number;\n\tmisses: number;\n\tmaxDer: number;\n\tpassed: boolean;\n}\n\nexport function scoreDiarization(\n\tsamples: ReadonlyArray<DiarizationSample>,\n\topts: { maxDer?: number } = {},\n): DiarizationResult {\n\tconst maxDer = opts.maxDer ?? 0.2;\n\tconst total = samples.length;\n\tlet confusions = 0;\n\tlet misses = 0;\n\tfor (const s of samples) {\n\t\tif (s.predictedLabel === null) misses += 1;\n\t\telse if (s.predictedLabel !== s.expectedLabel) confusions += 1;\n\t}\n\tconst der = total > 0 ? (confusions + misses) / total : 0;\n\treturn {\n\t\tkind: \"diarization\",\n\t\ttotal,\n\t\tder: round4(der),\n\t\tconfusions,\n\t\tmisses,\n\t\tmaxDer,\n\t\tpassed: total > 0 && der <= maxDer,\n\t};\n}\n\n/** One scored turn for timeline DER: its speech span + predicted/true speaker. */\nexport interface DiarizationTurnSample {\n\t/** Ground-truth speaker label (the diarization reference). */\n\texpectedLabel: string;\n\t/** Predicted speaker label from a real attributor, or null when it missed. */\n\tpredictedLabel: string | null;\n\t/** Speech-region start of this turn (ms into the stream). */\n\tstartMs: number;\n\t/** Speech-region end of this turn (ms; must be ≥ startMs). */\n\tendMs: number;\n}\n\n/**\n * Score diarization with the frame-based, label-agnostic {@link\n * computeDiarizationErrorRate} (#9147) rather than a per-turn string compare.\n * The predicted labels are an arbitrary cluster-id space (the attributor never\n * knows the ground-truth names) — DER finds the optimal cluster→speaker mapping,\n * so a correct partition scores 0 no matter how clusters are named, and a merged\n * or swapped speaker shows up as real error. `confusions`/`misses` are turn-level\n * tallies derived from that optimal mapping, for the report.\n */\nexport function scoreDiarizationTimeline(\n\tturns: ReadonlyArray<DiarizationTurnSample>,\n\topts: { maxDer?: number } = {},\n): DiarizationResult {\n\tconst maxDer = opts.maxDer ?? 0.2;\n\tconst reference: DiarizationSegment[] = turns.map((t) => ({\n\t\tspeaker: t.expectedLabel,\n\t\tstartMs: t.startMs,\n\t\tendMs: t.endMs,\n\t}));\n\tconst hypothesis: DiarizationSegment[] = turns\n\t\t.filter((t) => t.predictedLabel !== null)\n\t\t.map((t) => ({\n\t\t\tspeaker: t.predictedLabel as string,\n\t\t\tstartMs: t.startMs,\n\t\t\tendMs: t.endMs,\n\t\t}));\n\tconst result = computeDiarizationErrorRate(reference, hypothesis);\n\t// Turn-level tallies under the optimal mapping (the report's headline is `der`).\n\tlet confusions = 0;\n\tlet misses = 0;\n\tfor (const t of turns) {\n\t\tif (t.predictedLabel === null) {\n\t\t\tmisses += 1;\n\t\t} else if (result.mapping[t.predictedLabel] !== t.expectedLabel) {\n\t\t\tconfusions += 1;\n\t\t}\n\t}\n\treturn {\n\t\tkind: \"diarization\",\n\t\ttotal: turns.length,\n\t\tder: round4(result.der),\n\t\tconfusions,\n\t\tmisses,\n\t\tmaxDer,\n\t\tpassed: turns.length > 0 && result.der <= maxDer,\n\t};\n}\n\n// ── Entity extraction: inferred name/entity match (precision / recall / F1) ──\n\nexport interface EntityExtractionInput {\n\texpected: ReadonlyArray<string>;\n\tinferred: ReadonlyArray<string>;\n}\n\nexport interface EntityExtractionResult {\n\tkind: \"entity-extraction\";\n\tprecision: number;\n\trecall: number;\n\tf1: number;\n\tminF1: number;\n\tpassed: boolean;\n}\n\nfunction normEntity(s: string): string {\n\treturn s.trim().toLowerCase();\n}\n\nexport function scoreEntityExtraction(\n\tinput: EntityExtractionInput,\n\topts: { minF1?: number } = {},\n): EntityExtractionResult {\n\tconst minF1 = opts.minF1 ?? 0.8;\n\tconst expected = new Set(input.expected.map(normEntity).filter(Boolean));\n\tconst inferred = new Set(input.inferred.map(normEntity).filter(Boolean));\n\tlet tp = 0;\n\tfor (const e of inferred) if (expected.has(e)) tp += 1;\n\tconst precision =\n\t\tinferred.size > 0 ? tp / inferred.size : expected.size === 0 ? 1 : 0;\n\tconst recall = expected.size > 0 ? tp / expected.size : 1;\n\tconst f1 =\n\t\tprecision + recall > 0\n\t\t\t? (2 * precision * recall) / (precision + recall)\n\t\t\t: 0;\n\treturn {\n\t\tkind: \"entity-extraction\",\n\t\tprecision: round4(precision),\n\t\trecall: round4(recall),\n\t\tf1: round4(f1),\n\t\tminF1,\n\t\tpassed: f1 >= minF1,\n\t};\n}\n\n// ── Voice→entity match: recognized voice resolves to the right entity ────────\n\nexport interface VoiceEntityMatchSample {\n\tmatchedEntityId: string | null;\n\texpectedEntityId: string;\n}\n\nexport interface VoiceEntityMatchResult {\n\tkind: \"voice-entity-match\";\n\ttotal: number;\n\tmatchRate: number;\n\tcorrect: number;\n\tminMatchRate: number;\n\tpassed: boolean;\n}\n\nexport function scoreVoiceEntityMatch(\n\tsamples: ReadonlyArray<VoiceEntityMatchSample>,\n\topts: { minMatchRate?: number } = {},\n): VoiceEntityMatchResult {\n\tconst minMatchRate = opts.minMatchRate ?? 0.9;\n\tconst total = samples.length;\n\tlet correct = 0;\n\tfor (const s of samples) {\n\t\tif (s.matchedEntityId === s.expectedEntityId) correct += 1;\n\t}\n\tconst matchRate = total > 0 ? correct / total : 0;\n\treturn {\n\t\tkind: \"voice-entity-match\",\n\t\ttotal,\n\t\tmatchRate: round4(matchRate),\n\t\tcorrect,\n\t\tminMatchRate,\n\t\tpassed: total > 0 && matchRate >= minMatchRate,\n\t};\n}\n\n// ── Echo / self-voice rejection: the agent's own TTS must not be a user turn ─\n\nexport interface EchoRejectionSample {\n\t/** Ground truth: this turn is the agent's own TTS echoed back through the mic. */\n\tisAgentEcho: boolean;\n\t/** The agent responded to (i.e. failed to suppress) this turn. */\n\tresponded: boolean;\n}\n\nexport interface EchoRejectionResult {\n\tkind: \"echo-rejection\";\n\t/** Number of agent-echo turns scored. */\n\ttotal: number;\n\t/** Echo turns correctly suppressed (no response). */\n\trejected: number;\n\trejectionRate: number;\n\tminRejectionRate: number;\n\tpassed: boolean;\n}\n\n/**\n * Score self-echo rejection over the agent-echo turns only: each must be\n * suppressed (no response). Real turns are scored by {@link scoreRespondDecision}\n * — this isolates \"did the agent talk to itself?\".\n */\nexport function scoreEchoRejection(\n\tsamples: ReadonlyArray<EchoRejectionSample>,\n\topts: { minRejectionRate?: number } = {},\n): EchoRejectionResult {\n\tconst minRejectionRate = opts.minRejectionRate ?? 0.9;\n\tconst echo = samples.filter((s) => s.isAgentEcho);\n\tconst total = echo.length;\n\tlet rejected = 0;\n\tfor (const s of echo) if (!s.responded) rejected += 1;\n\tconst rejectionRate = total > 0 ? rejected / total : 0;\n\treturn {\n\t\tkind: \"echo-rejection\",\n\t\ttotal,\n\t\trejected,\n\t\trejectionRate: round4(rejectionRate),\n\t\tminRejectionRate,\n\t\tpassed: total > 0 && rejectionRate >= minRejectionRate,\n\t};\n}\n\n// ── Owner security: owner vs. intruder gating (never accept an impostor) ──────\n\nexport interface OwnerSecuritySample {\n\t/** The system judged this turn to be the device owner. */\n\tpredictedOwner: boolean;\n\t/** Ground truth: this turn IS the owner. */\n\texpectedOwner: boolean;\n}\n\nexport interface OwnerSecurityResult {\n\tkind: \"owner-security\";\n\ttotal: number;\n\taccuracy: number;\n\t/** Accepted a non-owner AS the owner (the dangerous false-accept). */\n\timpostorAcceptRate: number;\n\t/** Rejected the real owner (a friction false-reject). */\n\townerRejectRate: number;\n\tminAccuracy: number;\n\tmaxImpostorAcceptRate: number;\n\tpassed: boolean;\n}\n\n/**\n * Score owner-vs-intruder gating. Passing requires both high overall accuracy\n * AND an impostor-accept rate at/below the (strict, default 0) ceiling —\n * letting a stranger in is the failure mode that matters for security, so it is\n * gated separately from plain accuracy.\n */\nexport function scoreOwnerSecurity(\n\tsamples: ReadonlyArray<OwnerSecuritySample>,\n\topts: { minAccuracy?: number; maxImpostorAcceptRate?: number } = {},\n): OwnerSecurityResult {\n\tconst minAccuracy = opts.minAccuracy ?? 0.9;\n\tconst maxImpostorAcceptRate = opts.maxImpostorAcceptRate ?? 0;\n\tconst total = samples.length;\n\tlet correct = 0;\n\tlet impostorAccept = 0;\n\tlet ownerReject = 0;\n\tlet owners = 0;\n\tlet nonOwners = 0;\n\tfor (const s of samples) {\n\t\tif (s.predictedOwner === s.expectedOwner) correct += 1;\n\t\tif (s.expectedOwner) owners += 1;\n\t\telse nonOwners += 1;\n\t\tif (s.predictedOwner && !s.expectedOwner) impostorAccept += 1;\n\t\tif (!s.predictedOwner && s.expectedOwner) ownerReject += 1;\n\t}\n\tconst accuracy = total > 0 ? correct / total : 0;\n\tconst impostorAcceptRate = nonOwners > 0 ? impostorAccept / nonOwners : 0;\n\treturn {\n\t\tkind: \"owner-security\",\n\t\ttotal,\n\t\taccuracy: round4(accuracy),\n\t\timpostorAcceptRate: round4(impostorAcceptRate),\n\t\townerRejectRate: round4(owners > 0 ? ownerReject / owners : 0),\n\t\tminAccuracy,\n\t\tmaxImpostorAcceptRate,\n\t\tpassed:\n\t\t\ttotal > 0 &&\n\t\t\taccuracy >= minAccuracy &&\n\t\t\timpostorAcceptRate <= maxImpostorAcceptRate,\n\t};\n}\n\nexport type VoiceE2eCaseResult =\n\t| TtsAsrRoundTripResult\n\t| BargeInInterruptionResult\n\t| PauseContinuationResult\n\t| OptimisticRollbackRestartResult\n\t| FirstResponseLatencyResult\n\t| EotDecisionResult\n\t| RespondDecisionResult\n\t| DiarizationResult\n\t| EntityExtractionResult\n\t| VoiceEntityMatchResult\n\t| EchoRejectionResult\n\t| OwnerSecurityResult;\n\nexport interface VoiceE2eSummary {\n\tpassed: boolean;\n\tcases: VoiceE2eCaseResult[];\n}\n\nexport function summarizeVoiceE2e(\n\tcases: ReadonlyArray<VoiceE2eCaseResult>,\n): VoiceE2eSummary {\n\treturn {\n\t\tpassed: cases.length > 0 && cases.every((c) => c.passed),\n\t\tcases: [...cases],\n\t};\n}\n\nfunction required(value: number | null | undefined, name: string): number {\n\tif (value === null || value === undefined || !Number.isFinite(value)) {\n\t\tthrow missingMeasurement(name);\n\t}\n\treturn value;\n}\n\nfunction optionalDuration(\n\tfromName: string,\n\tfrom: number,\n\ttoName: string,\n\tto: number | null | undefined,\n): number | null {\n\tif (to === null || to === undefined) return null;\n\treturn duration(fromName, from, toName, to);\n}\n\nfunction duration(\n\tfromName: string,\n\tfrom: number,\n\ttoName: string,\n\tto: number,\n): number {\n\tif (!Number.isFinite(from)) throw missingMeasurement(fromName);\n\tif (!Number.isFinite(to)) throw missingMeasurement(toName);\n\tconst delta = to - from;\n\tif (delta < 0) {\n\t\tthrow new VoiceE2eHarnessError(\n\t\t\t\"invalid-measurement\",\n\t\t\t`Invalid voice E2E measurement: ${toName} (${to}) is before ${fromName} (${from})`,\n\t\t\t{ fromName, from, toName, to },\n\t\t);\n\t}\n\treturn delta;\n}\n\nfunction missingMeasurement(name: string): VoiceE2eHarnessError {\n\treturn new VoiceE2eHarnessError(\n\t\t\"missing-measurement\",\n\t\t`Missing required voice E2E measurement: ${name}`,\n\t\t{ name },\n\t);\n}\n",
27
+ "// Diarization Error Rate (DER) scorer for the voice test matrix (issue #9147).\n//\n// The voice-scenario schema already carries a `maxDer` threshold and an\n// `expectedSpeakerLabel` per turn, but nothing computed DER — diarization was\n// only ever scored on the respond-decision, so a wrong speaker attribution or a\n// missed overlapping talker passed silently. This is that missing scorer: a\n// pure, frame-based DER (the standard NIST md-eval decomposition) so the\n// diarization / multi-speaker / overlapping-speech scenario classes can assert\n// per-turn labels AND enforce `maxDer`.\n//\n// Frame-based (default 10ms) so OVERLAPPING speech is handled correctly: each\n// frame compares the SET of reference speakers against the SET of hypothesis\n// speakers, after an optimal one-to-one speaker mapping that maximizes matched\n// time. Everything here is deterministic and dependency-free.\n\nexport interface DiarizationSegment {\n\t/** Speaker label (any stable string — ground-truth and hypothesis label\n\t * spaces are mapped against each other, so the raw strings need not match). */\n\tspeaker: string;\n\t/** Segment start, milliseconds. */\n\tstartMs: number;\n\t/** Segment end, milliseconds (must be ≥ startMs). */\n\tendMs: number;\n}\n\nexport interface DerResult {\n\t/** Diarization Error Rate: (missed + falseAlarm + confusion) / referenceMs.\n\t * 0 = perfect; can exceed 1 when false alarms dominate. */\n\tder: number;\n\t/** Reference speech the system failed to attribute to anyone (ms). */\n\tmissedMs: number;\n\t/** System speech with no reference speaker present (ms). */\n\tfalseAlarmMs: number;\n\t/** Reference speech attributed to the wrong (mapped) speaker (ms). */\n\tconfusionMs: number;\n\t/** Total reference speaker-time (Σ |ref speakers in frame| · frame), the DER denominator. */\n\ttotalReferenceMs: number;\n\t/** The chosen hypothesis→reference speaker mapping (optimal for matched time). */\n\tmapping: Record<string, string>;\n}\n\nexport interface DerOptions {\n\t/** Frame size in ms (default 10). Smaller = more precise, more work. */\n\tframeMs?: number;\n\t/** Above this combined speaker count, fall back to a greedy mapping instead\n\t * of the exact permutation search (keeps it O(n) not O(n!)). Default 7. */\n\tmaxExactSpeakers?: number;\n}\n\nfunction totalDurationMs(segments: readonly DiarizationSegment[]): number {\n\treturn segments.reduce((max, s) => Math.max(max, s.endMs), 0);\n}\n\n/** Per-frame active-speaker sets. `frames[f]` is the set of speakers whose\n * segment covers the start of frame `f`. */\nfunction frameize(\n\tsegments: readonly DiarizationSegment[],\n\tframeMs: number,\n\tnumFrames: number,\n): Array<Set<string>> {\n\tconst frames: Array<Set<string>> = Array.from(\n\t\t{ length: numFrames },\n\t\t() => new Set<string>(),\n\t);\n\tfor (const seg of segments) {\n\t\tif (seg.endMs <= seg.startMs) continue;\n\t\tconst first = Math.max(0, Math.floor(seg.startMs / frameMs));\n\t\t// A frame f (covering [f·frameMs, (f+1)·frameMs)) is active if its start\n\t\t// time falls within [startMs, endMs).\n\t\tconst last = Math.min(numFrames - 1, Math.ceil(seg.endMs / frameMs) - 1);\n\t\tfor (let f = first; f <= last; f++) {\n\t\t\tif (f * frameMs >= seg.startMs && f * frameMs < seg.endMs) {\n\t\t\t\tframes[f].add(seg.speaker);\n\t\t\t}\n\t\t}\n\t}\n\treturn frames;\n}\n\nfunction uniqueSpeakers(segments: readonly DiarizationSegment[]): string[] {\n\treturn [...new Set(segments.map((s) => s.speaker))];\n}\n\n/** Frames where reference speaker `r` and hypothesis speaker `h` are both active. */\nfunction coOccurrence(\n\trefFrames: Array<Set<string>>,\n\thypFrames: Array<Set<string>>,\n\trefSpeakers: string[],\n\thypSpeakers: string[],\n): Map<string, Map<string, number>> {\n\tconst co = new Map<string, Map<string, number>>();\n\tfor (const r of refSpeakers)\n\t\tco.set(r, new Map(hypSpeakers.map((h) => [h, 0])));\n\tfor (let f = 0; f < refFrames.length; f++) {\n\t\tconst rs = refFrames[f];\n\t\tconst hs = hypFrames[f];\n\t\tif (rs.size === 0 || hs.size === 0) continue;\n\t\tfor (const r of rs) {\n\t\t\tconst row = co.get(r);\n\t\t\tif (!row) continue;\n\t\t\tfor (const h of hs) row.set(h, (row.get(h) ?? 0) + 1);\n\t\t}\n\t}\n\treturn co;\n}\n\n/** Optimal injective hyp→ref mapping maximizing total co-occurrence (exact for\n * small speaker counts, greedy beyond `maxExactSpeakers`). */\nfunction bestMapping(\n\tco: Map<string, Map<string, number>>,\n\trefSpeakers: string[],\n\thypSpeakers: string[],\n\tmaxExact: number,\n): Record<string, string> {\n\tconst score = (h: string, r: string) => co.get(r)?.get(h) ?? 0;\n\n\tif (refSpeakers.length + hypSpeakers.length <= maxExact) {\n\t\t// Exact: try every injective assignment of hyp speakers onto ref speakers.\n\t\tlet best: Record<string, string> = {};\n\t\tlet bestScore = -1;\n\t\tconst assign = (\n\t\t\ti: number,\n\t\t\tusedRefs: Set<string>,\n\t\t\tcurrent: Record<string, string>,\n\t\t\trunning: number,\n\t\t) => {\n\t\t\tif (i === hypSpeakers.length) {\n\t\t\t\tif (running > bestScore) {\n\t\t\t\t\tbestScore = running;\n\t\t\t\t\tbest = { ...current };\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst h = hypSpeakers[i];\n\t\t\t// Option: leave this hypothesis speaker unmapped (pure false alarm).\n\t\t\tassign(i + 1, usedRefs, current, running);\n\t\t\tfor (const r of refSpeakers) {\n\t\t\t\tif (usedRefs.has(r)) continue;\n\t\t\t\tusedRefs.add(r);\n\t\t\t\tcurrent[h] = r;\n\t\t\t\tassign(i + 1, usedRefs, current, running + score(h, r));\n\t\t\t\tdelete current[h];\n\t\t\t\tusedRefs.delete(r);\n\t\t\t}\n\t\t};\n\t\tassign(0, new Set(), {}, 0);\n\t\treturn best;\n\t}\n\n\t// Greedy: repeatedly take the highest-scoring (h, r) pair not yet used.\n\tconst pairs: Array<{ h: string; r: string; s: number }> = [];\n\tfor (const h of hypSpeakers) {\n\t\tfor (const r of refSpeakers) pairs.push({ h, r, s: score(h, r) });\n\t}\n\tpairs.sort((a, b) => b.s - a.s);\n\tconst usedHyp = new Set<string>();\n\tconst usedRef = new Set<string>();\n\tconst mapping: Record<string, string> = {};\n\tfor (const { h, r, s } of pairs) {\n\t\tif (s <= 0 || usedHyp.has(h) || usedRef.has(r)) continue;\n\t\tmapping[h] = r;\n\t\tusedHyp.add(h);\n\t\tusedRef.add(r);\n\t}\n\treturn mapping;\n}\n\n/**\n * Frame-based Diarization Error Rate between a reference (ground-truth) speaker\n * timeline and a hypothesis (diarizer output) timeline. Returns DER plus its\n * missed / false-alarm / confusion decomposition and the speaker mapping used.\n */\nexport function computeDiarizationErrorRate(\n\treference: readonly DiarizationSegment[],\n\thypothesis: readonly DiarizationSegment[],\n\toptions: DerOptions = {},\n): DerResult {\n\tconst frameMs = options.frameMs && options.frameMs > 0 ? options.frameMs : 10;\n\tconst maxExact = options.maxExactSpeakers ?? 7;\n\tconst durationMs = Math.max(\n\t\ttotalDurationMs(reference),\n\t\ttotalDurationMs(hypothesis),\n\t);\n\tconst numFrames = Math.ceil(durationMs / frameMs);\n\n\tconst refSpeakers = uniqueSpeakers(reference);\n\tconst hypSpeakers = uniqueSpeakers(hypothesis);\n\tconst refFrames = frameize(reference, frameMs, numFrames);\n\tconst hypFrames = frameize(hypothesis, frameMs, numFrames);\n\n\tconst co = coOccurrence(refFrames, hypFrames, refSpeakers, hypSpeakers);\n\tconst mapping = bestMapping(co, refSpeakers, hypSpeakers, maxExact);\n\t// inverse: ref speaker -> the hyp speaker mapped onto it.\n\tconst inverse = new Map<string, string>();\n\tfor (const [h, r] of Object.entries(mapping)) inverse.set(r, h);\n\n\tlet missedFrames = 0;\n\tlet falseAlarmFrames = 0;\n\tlet confusionFrames = 0;\n\tlet referenceSpeakerFrames = 0;\n\n\tfor (let f = 0; f < numFrames; f++) {\n\t\tconst R = refFrames[f];\n\t\tconst H = hypFrames[f];\n\t\tconst nRef = R.size;\n\t\tconst nSys = H.size;\n\t\treferenceSpeakerFrames += nRef;\n\t\tif (nRef === 0 && nSys === 0) continue;\n\n\t\t// Correctly attributed: a ref speaker whose mapped hyp speaker is active.\n\t\tlet correct = 0;\n\t\tfor (const r of R) {\n\t\t\tconst h = inverse.get(r);\n\t\t\tif (h !== undefined && H.has(h)) correct += 1;\n\t\t}\n\n\t\tmissedFrames += Math.max(0, nRef - nSys);\n\t\tfalseAlarmFrames += Math.max(0, nSys - nRef);\n\t\tconfusionFrames += Math.min(nRef, nSys) - correct;\n\t}\n\n\tconst missedMs = missedFrames * frameMs;\n\tconst falseAlarmMs = falseAlarmFrames * frameMs;\n\tconst confusionMs = confusionFrames * frameMs;\n\tconst totalReferenceMs = referenceSpeakerFrames * frameMs;\n\tconst der =\n\t\ttotalReferenceMs > 0\n\t\t\t? (missedMs + falseAlarmMs + confusionMs) / totalReferenceMs\n\t\t\t: falseAlarmMs > 0\n\t\t\t\t? Number.POSITIVE_INFINITY\n\t\t\t\t: 0;\n\n\treturn {\n\t\tder,\n\t\tmissedMs,\n\t\tfalseAlarmMs,\n\t\tconfusionMs,\n\t\ttotalReferenceMs,\n\t\tmapping,\n\t};\n}\n\n/** Whether a diarization hypothesis is within a scenario's `maxDer` budget. */\nexport function diarizationWithinBudget(\n\tresult: Pick<DerResult, \"der\">,\n\tmaxDer: number,\n): boolean {\n\treturn result.der <= maxDer;\n}\n",
28
+ "/**\n * Built-in Voice Workbench scenarios + a ground-truth mock services adapter\n * (#8785).\n *\n * The scenario set spans every {@link VoiceScenarioClass} so the headless runner\n * and the headful spec matrix exercise the whole surface from one source. The\n * mock adapter echoes each turn's ground truth, so the CI plumbing lane runs the\n * runner → scorers → report end-to-end and PASSES without any model — separate\n * from the gated real-backend lane.\n */\n\nimport type { CorpusTurnLabel } from \"./corpus-generator\";\nimport type { VoiceScenario } from \"./voice-scenario\";\nimport type {\n\tVoiceTurnObservation,\n\tVoiceWorkbenchServices,\n} from \"./workbench-headless-runner\";\n\nexport const VOICE_WORKBENCH_SCENARIOS: VoiceScenario[] = [\n\t{\n\t\tid: \"multi-voice-greeting\",\n\t\tdescription: \"Two distinct voices greet the agent in turn.\",\n\t\tclasses: [\"multi-voice\", \"diarization\"],\n\t\tparticipants: [\n\t\t\t{ label: \"alice\", entityId: \"entity-alice\", ttsVoiceId: \"af_bella\" },\n\t\t\t{ label: \"bob\", entityId: \"entity-bob\", ttsVoiceId: \"am_adam\" },\n\t\t],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"alice\",\n\t\t\t\ttext: \"Eliza good morning to you\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"bob\",\n\t\t\t\ttext: \"Eliza what is on my calendar\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t],\n\t\tassertions: { maxWer: 0.2, maxDer: 0.2 },\n\t},\n\t{\n\t\tid: \"respond-vs-bystander\",\n\t\tdescription:\n\t\t\t\"The agent answers a direct address and stays silent on cross-talk.\",\n\t\tclasses: [\"respond-no-respond\", \"multi-speaker\"],\n\t\t// Only the owner is enrolled; bob is a recognized-but-unknown bystander.\n\t\tknownSpeakerEntityIds: [\"entity-alice\"],\n\t\tparticipants: [\n\t\t\t{ label: \"alice\", entityId: \"entity-alice\", isOwner: true },\n\t\t\t{ label: \"bob\", entityId: \"entity-bob\" },\n\t\t],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"alice\",\n\t\t\t\ttext: \"Eliza set a timer for ten minutes\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"bob\",\n\t\t\t\ttext: \"hey alice did you see the game\",\n\t\t\t\texpectRespond: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"alice\",\n\t\t\t\ttext: \"Eliza thanks that is all\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t],\n\t\tassertions: { minRespondAccuracy: 0.9 },\n\t},\n\t{\n\t\tid: \"pauses-midutterance\",\n\t\tdescription: \"A slow speaker pauses mid-sentence; EOT must not jump in.\",\n\t\tclasses: [\"pauses\", \"eot\"],\n\t\tparticipants: [{ label: \"alice\", entityId: \"entity-alice\" }],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"alice\",\n\t\t\t\ttext: \"Eliza schedule a meeting with\",\n\t\t\t\texpectRespond: false,\n\t\t\t\texpectEndOfTurn: false,\n\t\t\t\tpausesMs: [1200],\n\t\t\t},\n\t\t\t{ speaker: \"alice\", text: \"Bob tomorrow at noon\", expectRespond: true },\n\t\t],\n\t\tassertions: { maxEotFalseTriggerRate: 0.2 },\n\t},\n\t{\n\t\tid: \"entity-from-speech\",\n\t\tdescription: \"Name inference from the live transcript creates an entity.\",\n\t\tclasses: [\"entity-extraction\", \"voice-recognition\"],\n\t\tparticipants: [{ label: \"jill\", entityId: \"entity-jill\", isOwner: true }],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"jill\",\n\t\t\t\ttext: \"Eliza I am Jill and this is my house\",\n\t\t\t\texpectRespond: true,\n\t\t\t\texpectedEntity: \"entity-jill\",\n\t\t\t},\n\t\t],\n\t\tassertions: { minVoiceEntityMatchRate: 0.9 },\n\t},\n\t{\n\t\tid: \"transcription-mode-dictation\",\n\t\tdescription: \"Long-form dictation lands silently in transcription mode.\",\n\t\tclasses: [\"transcription-mode\", \"long-form-monologue\"],\n\t\tparticipants: [{ label: \"alice\", entityId: \"entity-alice\" }],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"alice\",\n\t\t\t\ttext: `${\"I want to capture this thought for later. \".repeat(12)}`.trim(),\n\t\t\t\texpectRespond: false,\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tid: \"multi-agent-room-address\",\n\t\tdescription: \"In a room with two agents, only the addressed agent replies.\",\n\t\tclasses: [\"multi-agent-room\", \"respond-no-respond\"],\n\t\tparticipants: [\n\t\t\t{ label: \"owner\", entityId: \"entity-owner\", isOwner: true },\n\t\t\t{ label: \"eliza\" },\n\t\t\t{ label: \"aria\" },\n\t\t],\n\t\tagents: [\"eliza\", \"aria\"],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza what is the weather\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{ speaker: \"owner\", text: \"Aria play some music\", expectRespond: true },\n\t\t],\n\t\tassertions: { minRespondAccuracy: 0.9 },\n\t},\n\t{\n\t\tid: \"noisy-room-commands\",\n\t\tdescription:\n\t\t\t\"The owner gives commands in a noisy, reverberant room; the agent still answers.\",\n\t\tclasses: [\"robustness\", \"respond-no-respond\"],\n\t\tknownSpeakerEntityIds: [\"entity-owner\"],\n\t\t// 8 dB SNR room noise + light reverb across the whole scenario.\n\t\tenvironment: { noiseSnrDb: 8, noiseKind: \"pink\", reverb: 0.35, seed: 101 },\n\t\tparticipants: [{ label: \"owner\", entityId: \"entity-owner\", isOwner: true }],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza turn on the kitchen lights\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{ speaker: \"owner\", text: \"Eliza what time is it\", expectRespond: true },\n\t\t],\n\t\tassertions: { minRespondAccuracy: 0.9, maxWer: 0.35, maxDer: 0.3 },\n\t},\n\t{\n\t\tid: \"music-background-commands\",\n\t\tdescription:\n\t\t\t\"The owner gives commands with music playing in the background; the agent answers and the tonal music bed does not false-trigger VAD/respond.\",\n\t\tclasses: [\"robustness\", \"respond-no-respond\"],\n\t\tknownSpeakerEntityIds: [\"entity-owner\"],\n\t\t// 10 dB SNR music bed across the whole scenario. The `music` noise kind is\n\t\t// tonal/harmonic (unlike white/pink) — this scenario exercises the music\n\t\t// augmentation that landed in corpus-augment.ts (d56efcc80b) but until now\n\t\t// had no scenario driving it (#9147).\n\t\tenvironment: { noiseSnrDb: 10, noiseKind: \"music\", reverb: 0.2, seed: 404 },\n\t\tparticipants: [{ label: \"owner\", entityId: \"entity-owner\", isOwner: true }],\n\t\tturns: [\n\t\t\t{ speaker: \"owner\", text: \"Eliza pause the timer\", expectRespond: true },\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza what is the weather today\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t],\n\t\tassertions: { minRespondAccuracy: 0.9, maxWer: 0.35, maxDer: 0.3 },\n\t},\n\t{\n\t\tid: \"far-field-reverb\",\n\t\tdescription:\n\t\t\t\"A far, reverberant speaker across the room — quiet and washed out — is still understood.\",\n\t\tclasses: [\"robustness\", \"respond-no-respond\"],\n\t\tknownSpeakerEntityIds: [\"entity-owner\"],\n\t\tenvironment: { farFieldDb: 12, reverb: 0.75, noiseSnrDb: 12, seed: 202 },\n\t\tparticipants: [{ label: \"owner\", entityId: \"entity-owner\", isOwner: true }],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza add milk to the shopping list\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t],\n\t\tassertions: { minRespondAccuracy: 0.9, maxWer: 0.4 },\n\t},\n\t{\n\t\tid: \"background-talkers\",\n\t\tdescription:\n\t\t\t\"Other people are talking in the background while the owner addresses the agent.\",\n\t\tclasses: [\"robustness\", \"overlapping-speech\", \"multi-speaker\"],\n\t\tknownSpeakerEntityIds: [\"entity-owner\"],\n\t\tenvironment: { backgroundTalkersDb: 9, noiseSnrDb: 14, seed: 303 },\n\t\tparticipants: [{ label: \"owner\", entityId: \"entity-owner\", isOwner: true }],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza start a five minute timer\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t],\n\t\tassertions: { minRespondAccuracy: 0.9, maxWer: 0.4 },\n\t},\n\t{\n\t\tid: \"echo-self-trigger\",\n\t\tdescription:\n\t\t\t\"The agent's own reply bleeds back into the mic; it must not answer itself.\",\n\t\tclasses: [\"echo-rejection\", \"respond-no-respond\"],\n\t\tknownSpeakerEntityIds: [\"entity-owner\"],\n\t\tparticipants: [{ label: \"owner\", entityId: \"entity-owner\", isOwner: true }],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"hey Eliza what is the weather today\",\n\t\t\t\texpectRespond: true,\n\t\t\t\tagentReplyText:\n\t\t\t\t\t\"It is sunny and seventy two degrees in San Francisco today\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t// The agent's TTS echoed back through the open mic — NOT a user turn.\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"It is sunny and seventy two degrees in San Francisco today\",\n\t\t\t\tisAgentEcho: true,\n\t\t\t\texpectRespond: false,\n\t\t\t},\n\t\t\t{ speaker: \"owner\", text: \"hey Eliza thanks\", expectRespond: true },\n\t\t],\n\t\tassertions: { minEchoRejectionRate: 1, minRespondAccuracy: 0.9 },\n\t},\n\t{\n\t\tid: \"multi-speaker-name-capture\",\n\t\tdescription:\n\t\t\t\"Two new people in the room introduce themselves; each name is captured and bound to a distinct entity, separate from the owner.\",\n\t\tclasses: [\n\t\t\t\"diarization\",\n\t\t\t\"entity-extraction\",\n\t\t\t\"multi-speaker\",\n\t\t\t\"voice-recognition\",\n\t\t],\n\t\tknownSpeakerEntityIds: [\"entity-owner\", \"entity-marcus\", \"entity-priya\"],\n\t\tparticipants: [\n\t\t\t{ label: \"owner\", entityId: \"entity-owner\", isOwner: true },\n\t\t\t{ label: \"marcus\", entityId: \"entity-marcus\" },\n\t\t\t{ label: \"priya\", entityId: \"entity-priya\" },\n\t\t],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza meet my two coworkers\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"marcus\",\n\t\t\t\ttext: \"hey Eliza I am Marcus good to meet you\",\n\t\t\t\texpectRespond: true,\n\t\t\t\texpectedEntity: \"entity-marcus\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"priya\",\n\t\t\t\ttext: \"Eliza I am Priya from the design team\",\n\t\t\t\texpectRespond: true,\n\t\t\t\texpectedEntity: \"entity-priya\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza remember them for later\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t],\n\t\tassertions: {\n\t\t\tminRespondAccuracy: 0.9,\n\t\t\tmaxDer: 0.2,\n\t\t\tminVoiceEntityMatchRate: 0.9,\n\t\t},\n\t},\n\t{\n\t\tid: \"echo-mistranscribed\",\n\t\tdescription:\n\t\t\t\"The agent's echo is mis-transcribed (no word overlap); the ACOUSTIC self-voice gate still rejects it.\",\n\t\tclasses: [\"echo-rejection\"],\n\t\tknownSpeakerEntityIds: [\"entity-owner\"],\n\t\tparticipants: [{ label: \"owner\", entityId: \"entity-owner\", isOwner: true }],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"hey Eliza how many days until friday\",\n\t\t\t\texpectRespond: true,\n\t\t\t\tagentReplyText: \"There are three days until Friday\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t// ASR garbled the echoed reply — NO words overlap \"three days until\n\t\t\t\t// friday\", so the transcript guard would miss it. Self-voice catches it.\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"thudder ays untl fryeday\",\n\t\t\t\tisAgentEcho: true,\n\t\t\t\texpectRespond: false,\n\t\t\t},\n\t\t],\n\t\tassertions: { minEchoRejectionRate: 1 },\n\t},\n\t{\n\t\tid: \"owner-enrollment-inference\",\n\t\tdescription:\n\t\t\t\"No owner is enrolled; the agent infers the owner from who speaks to it most.\",\n\t\tclasses: [\"owner-security\", \"voice-recognition\"],\n\t\tknownSpeakerEntityIds: [\"entity-owner\", \"entity-guest\"],\n\t\tparticipants: [\n\t\t\t{ label: \"owner\", entityId: \"entity-owner\", isOwner: true },\n\t\t\t{ label: \"guest\", entityId: \"entity-guest\" },\n\t\t],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza what is on my agenda today\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza remind me to call the dentist\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza play my morning playlist\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"guest\",\n\t\t\t\ttext: \"Eliza what is the wifi password\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza turn the music down a little\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t],\n\t\tassertions: { minOwnerAccuracy: 0.9, minRespondAccuracy: 0.9 },\n\t},\n\t{\n\t\tid: \"owner-vs-intruder\",\n\t\tdescription:\n\t\t\t\"The owner is answered; a stranger trying the same command is gated out.\",\n\t\tclasses: [\"owner-security\", \"respond-no-respond\", \"multi-speaker\"],\n\t\t// Only the owner is enrolled; the intruder is a confident bystander.\n\t\tknownSpeakerEntityIds: [\"entity-owner\"],\n\t\tparticipants: [\n\t\t\t{ label: \"owner\", entityId: \"entity-owner\", isOwner: true },\n\t\t\t{ label: \"intruder\", entityId: \"entity-intruder\" },\n\t\t],\n\t\tturns: [\n\t\t\t{\n\t\t\t\tspeaker: \"owner\",\n\t\t\t\ttext: \"Eliza unlock the front door\",\n\t\t\t\texpectRespond: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tspeaker: \"intruder\",\n\t\t\t\ttext: \"Eliza unlock the front door\",\n\t\t\t\texpectRespond: false,\n\t\t\t},\n\t\t\t{ speaker: \"owner\", text: \"Eliza lock it again\", expectRespond: true },\n\t\t],\n\t\tassertions: { minOwnerAccuracy: 0.9, minRespondAccuracy: 0.9 },\n\t},\n];\n\n/**\n * A services adapter that echoes each turn's ground truth — perfect ASR /\n * diarization / EOT / respond / entity / match. Drives the CI plumbing lane\n * (runner → scorers → report) to a real PASS with no model. NOT a stand-in for\n * the real backend: it proves the wiring, not the models.\n */\nexport function groundTruthMockServices(\n\topts: { firstAudioMs?: number; eotLatencyMs?: number } = {},\n): VoiceWorkbenchServices {\n\treturn {\n\t\tasync observeTurn({\n\t\t\tlabel,\n\t\t}: {\n\t\t\tlabel: CorpusTurnLabel;\n\t\t}): Promise<VoiceTurnObservation> {\n\t\t\tconst eotDecided = label.expectEndOfTurn ?? true;\n\t\t\treturn {\n\t\t\t\thypothesisTranscript: label.referenceTranscript,\n\t\t\t\tpredictedSpeakerLabel: label.speaker,\n\t\t\t\teotDecided,\n\t\t\t\t...(eotDecided ? { eotLatencyMs: opts.eotLatencyMs ?? 80 } : {}),\n\t\t\t\tresponded: label.expectRespond,\n\t\t\t\tinferredEntities: label.expectedEntity ? [label.expectedEntity] : [],\n\t\t\t\tmatchedEntityId: label.entityId ?? null,\n\t\t\t\tpredictedOwner: label.isOwner === true,\n\t\t\t\t...(label.expectRespond\n\t\t\t\t\t? { firstAudioMs: opts.firstAudioMs ?? 250 }\n\t\t\t\t\t: {}),\n\t\t\t};\n\t\t},\n\t};\n}\n",
29
+ "/**\n * Voice Workbench real services adapter (#9147).\n *\n * `voice:workbench --real` must not be an all-skipped honesty stub: the\n * provisioned lane has a fused libelizainference build, ASR/TTS regions,\n * WeSpeaker, pyannote, and ElevenLabs-generated human speech. This adapter\n * drives those real pieces through the existing workbench runner/scorers.\n */\n\nimport { existsSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport {\n\ttype OwnerObservation,\n\tresolveOwnerCandidate,\n} from \"@elizaos/shared/voice/owner-inference\";\nimport { buildVoiceTurnSignal } from \"@elizaos/shared/voice/respond-gate\";\nimport { scoreEndOfTurnHeuristic } from \"@elizaos/shared/voice-eot\";\nimport { resolveFusedLibraryPath } from \"../desktop-fused-ffi-backend-runtime\";\nimport type {\n\tCorpusGroundTruth,\n\tCorpusTtsSynthesizer,\n\tGeneratedVoiceCorpus,\n} from \"./corpus-generator\";\nimport { type ElizaInferenceFfi, loadElizaInferenceFfi } from \"./ffi-bindings\";\nimport { FusedDiarizer } from \"./speaker/diarizer-fused\";\nimport { averageEmbeddings } from \"./speaker/encoder\";\nimport { FusedSpeakerEncoder } from \"./speaker/encoder-fused\";\nimport { SPEAKER_GGML_MIN_SAMPLES } from \"./speaker/encoder-ggml\";\nimport { cosineSimilarity } from \"./speaker-imprint\";\nimport { resampleLinear } from \"./transcriber\";\nimport type { VoiceScenario } from \"./voice-scenario\";\nimport type {\n\tVoiceTurnObservation,\n\tVoiceWorkbenchServices,\n} from \"./workbench-headless-runner\";\n\nconst SAMPLE_RATE = 16_000;\nconst EOT_COMMIT_THRESHOLD = 0.5;\nconst DEFAULT_OWNER_THRESHOLD = 0.78;\nconst MAX_AGENT_TTS_SECONDS = 12;\nconst SPEAKER_ENROLLMENT_PHRASE =\n\t\"This is my voice enrollment sample for reliable speaker recognition.\";\n\nconst ELEVENLABS_MODEL_ID = \"eleven_turbo_v2_5\";\nconst ELEVENLABS_VOICE_IDS = [\n\t\"21m00Tcm4TlvDq8ikWAM\", // Rachel\n\t\"pNInz6obpgDQGcFmaJgB\", // Adam\n\t\"EXAVITQu4vr4xnSDxMaL\", // Bella\n\t\"ErXwobaYiN019PkySvjV\", // Antoni\n\t\"MF3mGyEYCl7XYWbV9V6O\", // Elli\n\t\"TxGEqnHWrfWFTfGW9XjX\", // Josh\n] as const;\n\nconst VOICE_ID_ALIASES: Record<string, string> = {\n\taf_bella: \"EXAVITQu4vr4xnSDxMaL\",\n\taf_sarah: \"EXAVITQu4vr4xnSDxMaL\",\n\taf_nicole: \"MF3mGyEYCl7XYWbV9V6O\",\n\tam_adam: \"pNInz6obpgDQGcFmaJgB\",\n\tam_michael: \"ErXwobaYiN019PkySvjV\",\n\towner: \"21m00Tcm4TlvDq8ikWAM\",\n\talice: \"21m00Tcm4TlvDq8ikWAM\",\n\tjill: \"21m00Tcm4TlvDq8ikWAM\",\n\tbob: \"pNInz6obpgDQGcFmaJgB\",\n\tguest: \"pNInz6obpgDQGcFmaJgB\",\n\tintruder: \"pNInz6obpgDQGcFmaJgB\",\n\tmarcus: \"ErXwobaYiN019PkySvjV\",\n\tpriya: \"EXAVITQu4vr4xnSDxMaL\",\n\teliza: \"MF3mGyEYCl7XYWbV9V6O\",\n\taria: \"TxGEqnHWrfWFTfGW9XjX\",\n};\n\ninterface SpeakerProfile {\n\tlabel: string;\n\tentityId: string | null;\n\tisOwner: boolean;\n\tcentroid: Float32Array;\n}\n\ninterface SpeakerMatch {\n\tprofile: SpeakerProfile;\n\tsimilarity: number;\n}\n\nexport interface RealVoiceWorkbenchRuntime {\n\tservices: VoiceWorkbenchServices;\n\tsynthesizer: CorpusTtsSynthesizer;\n\tdispose(): Promise<void>;\n}\n\ninterface RealVoiceWorkbenchOptions {\n\tbundle: string;\n\tfusedLib: string;\n\tspeakerGguf: string;\n\tdiarizGguf: string;\n\televenLabsApiKey: string;\n\townerAcceptThreshold?: number;\n\tvoiceMap?: Record<string, string>;\n}\n\nfunction requirePath(label: string, value: string | null | undefined): string {\n\tif (!value || !existsSync(value)) {\n\t\tthrow new Error(\n\t\t\t`[voice:workbench --real] missing ${label}: ${value ?? \"(unset)\"}`,\n\t\t);\n\t}\n\treturn value;\n}\n\nfunction nonEmpty(value: string | null | undefined): string | undefined {\n\tconst trimmed = value?.trim();\n\treturn trimmed ? trimmed : undefined;\n}\n\nfunction firstExisting(\n\t...candidates: Array<string | null | undefined>\n): string | null {\n\tfor (const candidate of candidates) {\n\t\tif (candidate && existsSync(candidate)) return candidate;\n\t}\n\treturn null;\n}\n\nfunction finiteNumberEnv(\n\tenv: NodeJS.ProcessEnv,\n\tname: string,\n\tfallback: number,\n): number {\n\tconst raw = env[name]?.trim();\n\tif (!raw) return fallback;\n\tconst value = Number(raw);\n\tif (!Number.isFinite(value)) {\n\t\tthrow new Error(\n\t\t\t`[voice:workbench --real] ${name} must be finite, got ${raw}`,\n\t\t);\n\t}\n\treturn value;\n}\n\nfunction parseVoiceMap(raw: string | undefined): Record<string, string> {\n\tif (!raw?.trim()) return {};\n\tconst parsed = JSON.parse(raw) as unknown;\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(\n\t\t\t\"[voice:workbench --real] ELIZA_WORKBENCH_ELEVENLABS_VOICE_MAP must be a JSON object\",\n\t\t);\n\t}\n\tconst out: Record<string, string> = {};\n\tfor (const [key, value] of Object.entries(parsed)) {\n\t\tif (typeof value !== \"string\" || !value.trim()) {\n\t\t\tthrow new Error(\n\t\t\t\t`[voice:workbench --real] voice map value for ${key} must be a non-empty string`,\n\t\t\t);\n\t\t}\n\t\tout[key.toLowerCase()] = value.trim();\n\t}\n\treturn out;\n}\n\nfunction labelHash(label: string): number {\n\tlet h = 0x811c9dc5;\n\tfor (let i = 0; i < label.length; i += 1) {\n\t\th ^= label.charCodeAt(i);\n\t\th = Math.imul(h, 0x01000193);\n\t}\n\treturn h >>> 0;\n}\n\nfunction ensureSampleRate(\n\tpcm: Float32Array,\n\tfromRate: number,\n\ttoRate: number,\n): Float32Array {\n\treturn fromRate === toRate ? pcm : resampleLinear(pcm, fromRate, toRate);\n}\n\nfunction ensureMinSpeakerSamples(pcm: Float32Array): Float32Array {\n\tif (pcm.length >= SPEAKER_GGML_MIN_SAMPLES) return pcm;\n\tconst out = new Float32Array(SPEAKER_GGML_MIN_SAMPLES);\n\tout.set(pcm);\n\treturn out;\n}\n\nfunction diarizerWindow(pcm: Float32Array): Float32Array {\n\tconst targetSamples = SAMPLE_RATE * 5;\n\tif (pcm.length === targetSamples) return pcm;\n\tif (pcm.length > targetSamples) return pcm.subarray(0, targetSamples);\n\tconst out = new Float32Array(targetSamples);\n\tout.set(pcm);\n\treturn out;\n}\n\nfunction pcm16ToFloat32(bytes: Uint8Array): Float32Array {\n\tconst view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n\tconst samples = Math.floor(bytes.byteLength / 2);\n\tconst out = new Float32Array(samples);\n\tfor (let i = 0; i < samples; i += 1) {\n\t\tout[i] = view.getInt16(i * 2, true) / 32768;\n\t}\n\treturn out;\n}\n\nfunction extractName(transcript: string): string | null {\n\tconst match = transcript.match(\n\t\t/\\b(?:my name is|i am|i'm|this is|call me)\\s+([a-z]+)/i,\n\t);\n\treturn match?.[1]?.toLowerCase() ?? null;\n}\n\nfunction knownSpeakerIds(groundTruth: CorpusGroundTruth): string[] {\n\tif (groundTruth.knownSpeakerEntityIds)\n\t\treturn groundTruth.knownSpeakerEntityIds;\n\treturn groundTruth.participants\n\t\t.map((p) => p.entityId)\n\t\t.filter((id): id is string => typeof id === \"string\" && id.length > 0);\n}\n\nfunction bestSpeakerMatch(\n\tprofiles: Iterable<SpeakerProfile>,\n\tembedding: Float32Array,\n): SpeakerMatch | null {\n\tlet best: SpeakerMatch | null = null;\n\tfor (const profile of profiles) {\n\t\tconst similarity = cosineSimilarity(embedding, profile.centroid);\n\t\tif (!best || similarity > best.similarity) {\n\t\t\tbest = { profile, similarity };\n\t\t}\n\t}\n\treturn best;\n}\n\nasync function elevenLabsPcm(args: {\n\ttext: string;\n\tvoiceId: string;\n\tapiKey: string;\n\tsampleRate: number;\n}): Promise<Float32Array> {\n\tconst response = await fetch(\n\t\t`https://api.elevenlabs.io/v1/text-to-speech/${args.voiceId}?output_format=pcm_16000`,\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"xi-api-key\": args.apiKey,\n\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\ttext: args.text,\n\t\t\t\tmodel_id: ELEVENLABS_MODEL_ID,\n\t\t\t}),\n\t\t},\n\t);\n\tif (!response.ok) {\n\t\tconst body = await response.text().catch(() => \"\");\n\t\tthrow new Error(\n\t\t\t`[voice:workbench --real] ElevenLabs ${response.status} for ${args.voiceId}: ${body.slice(0, 240)}`,\n\t\t);\n\t}\n\tconst pcm = pcm16ToFloat32(new Uint8Array(await response.arrayBuffer()));\n\treturn ensureSampleRate(pcm, SAMPLE_RATE, args.sampleRate);\n}\n\nclass RealVoiceWorkbenchAdapter implements RealVoiceWorkbenchRuntime {\n\treadonly synthesizer: CorpusTtsSynthesizer;\n\treadonly services: VoiceWorkbenchServices;\n\n\tprivate readonly ffi: ElizaInferenceFfi;\n\tprivate readonly ctx: ReturnType<ElizaInferenceFfi[\"create\"]>;\n\tprivate readonly encoder: FusedSpeakerEncoder;\n\tprivate readonly diarizer: FusedDiarizer;\n\tprivate readonly apiKey: string;\n\tprivate readonly ownerThreshold: number;\n\tprivate readonly voiceMap: Record<string, string>;\n\tprivate readonly profiles = new Map<string, SpeakerProfile>();\n\tprivate readonly selfVoiceEmbeddings: Float32Array[] = [];\n\tprivate ownerObservations: OwnerObservation[] = [];\n\tprivate scenarioId: string | null = null;\n\tprivate lastAgentReply: string | undefined;\n\n\tprivate constructor(args: {\n\t\tffi: ElizaInferenceFfi;\n\t\tctx: ReturnType<ElizaInferenceFfi[\"create\"]>;\n\t\tencoder: FusedSpeakerEncoder;\n\t\tdiarizer: FusedDiarizer;\n\t\tapiKey: string;\n\t\townerThreshold: number;\n\t\tvoiceMap: Record<string, string>;\n\t}) {\n\t\tthis.ffi = args.ffi;\n\t\tthis.ctx = args.ctx;\n\t\tthis.encoder = args.encoder;\n\t\tthis.diarizer = args.diarizer;\n\t\tthis.apiKey = args.apiKey;\n\t\tthis.ownerThreshold = args.ownerThreshold;\n\t\tthis.voiceMap = args.voiceMap;\n\t\tthis.synthesizer = {\n\t\t\tsynthesize: (input) => this.synthesizeCorpusTurn(input),\n\t\t};\n\t\tthis.services = {\n\t\t\tprepareScenario: (input) => this.prepareScenario(input),\n\t\t\tobserveTurn: (input) => this.observeTurn(input),\n\t\t};\n\t}\n\n\tstatic async create(\n\t\toptions: RealVoiceWorkbenchOptions,\n\t): Promise<RealVoiceWorkbenchAdapter> {\n\t\tconst ffi = loadElizaInferenceFfi(options.fusedLib);\n\t\tconst ctx = ffi.create(options.bundle);\n\t\ttry {\n\t\t\tif (!FusedSpeakerEncoder.isSupported(ffi)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"[voice:workbench --real] fused library does not support speaker ABI\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!FusedDiarizer.isSupported(ffi)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"[voice:workbench --real] fused library does not support diarizer ABI\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst encoder = await FusedSpeakerEncoder.load({\n\t\t\t\tffi,\n\t\t\t\tctx,\n\t\t\t\tggufPath: options.speakerGguf,\n\t\t\t});\n\t\t\tconst diarizer = await FusedDiarizer.load({\n\t\t\t\tffi,\n\t\t\t\tctx,\n\t\t\t\tggufPath: options.diarizGguf,\n\t\t\t});\n\t\t\treturn new RealVoiceWorkbenchAdapter({\n\t\t\t\tffi,\n\t\t\t\tctx,\n\t\t\t\tencoder,\n\t\t\t\tdiarizer,\n\t\t\t\tapiKey: options.elevenLabsApiKey,\n\t\t\t\townerThreshold: options.ownerAcceptThreshold ?? DEFAULT_OWNER_THRESHOLD,\n\t\t\t\tvoiceMap: options.voiceMap ?? {},\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tffi.destroy(ctx);\n\t\t\tffi.close();\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tprivate async prepareScenario(args: {\n\t\tscenario: VoiceScenario;\n\t\tcorpus: GeneratedVoiceCorpus;\n\t}): Promise<void> {\n\t\tthis.scenarioId = args.scenario.id;\n\t\tthis.lastAgentReply = undefined;\n\t\tthis.ownerObservations = [];\n\t\tthis.profiles.clear();\n\t\tthis.selfVoiceEmbeddings.length = 0;\n\n\t\t// Build speaker profiles from held-out enrollment audio, never from the\n\t\t// scored scenario turns. Otherwise the DER gate can match a turn against\n\t\t// an embedding extracted from that same turn and false-green.\n\t\tfor (const participant of args.corpus.groundTruth.participants) {\n\t\t\tconst enrollment = await elevenLabsPcm({\n\t\t\t\ttext: SPEAKER_ENROLLMENT_PHRASE,\n\t\t\t\tvoiceId: this.resolveElevenLabsVoiceId(\n\t\t\t\t\tparticipant.ttsVoiceId,\n\t\t\t\t\tparticipant.label,\n\t\t\t\t),\n\t\t\t\tapiKey: this.apiKey,\n\t\t\t\tsampleRate: SAMPLE_RATE,\n\t\t\t});\n\t\t\tconst embedding = await this.encoder.encode(\n\t\t\t\tensureMinSpeakerSamples(enrollment),\n\t\t\t);\n\t\t\tthis.profiles.set(participant.label, {\n\t\t\t\tlabel: participant.label,\n\t\t\t\tentityId: participant.entityId ?? null,\n\t\t\t\tisOwner: participant.isOwner === true,\n\t\t\t\tcentroid: embedding,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async observeTurn(\n\t\targs: Parameters<VoiceWorkbenchServices[\"observeTurn\"]>[0],\n\t): Promise<VoiceTurnObservation> {\n\t\tif (args.groundTruth.scenarioId !== this.scenarioId) {\n\t\t\tthrow new Error(\n\t\t\t\t`[voice:workbench --real] scenario ${args.groundTruth.scenarioId} was not prepared before observeTurn`,\n\t\t\t);\n\t\t}\n\t\tconst audio16 = ensureSampleRate(args.audio, args.sampleRate, SAMPLE_RATE);\n\t\tconst speakerPcm = ensureMinSpeakerSamples(audio16);\n\t\tconst embedding = await this.encoder.encode(speakerPcm);\n\t\tconst diarized = await this.diarizer.diarizeWindow(diarizerWindow(audio16));\n\t\tconst hasSpeech = diarized.segments.some(\n\t\t\t(segment) => segment.endMs > segment.startMs,\n\t\t);\n\t\tconst bestMatch = hasSpeech\n\t\t\t? bestSpeakerMatch(this.profiles.values(), embedding)\n\t\t\t: null;\n\t\tconst speakerMatch =\n\t\t\tbestMatch && bestMatch.similarity >= this.ownerThreshold\n\t\t\t\t? bestMatch\n\t\t\t\t: null;\n\t\tconst matchedEntityId = speakerMatch?.profile.entityId ?? null;\n\t\tif (matchedEntityId && !args.label.isAgentEcho) {\n\t\t\tthis.ownerObservations.push({\n\t\t\t\tentityId: matchedEntityId,\n\t\t\t\tconfidence: Math.max(0, Math.min(1, speakerMatch?.similarity ?? 0)),\n\t\t\t});\n\t\t}\n\t\tconst ownerCandidate = resolveOwnerCandidate(this.ownerObservations);\n\t\tconst predictedOwner =\n\t\t\townerCandidate.ownerEntityId !== null\n\t\t\t\t? matchedEntityId === ownerCandidate.ownerEntityId\n\t\t\t\t: speakerMatch?.profile.isOwner === true;\n\n\t\tconst transcript = await this.transcribe(audio16);\n\t\tconst eotProbability = scoreEndOfTurnHeuristic(transcript);\n\t\tconst eotDecided = eotProbability >= EOT_COMMIT_THRESHOLD;\n\t\tconst selfVoiceSimilarity = this.selfVoiceSimilarity(embedding);\n\t\tconst signal = buildVoiceTurnSignal(transcript, {\n\t\t\t...(this.lastAgentReply\n\t\t\t\t? { recentAgentReply: this.lastAgentReply, replyAgeMs: 500 }\n\t\t\t\t: {}),\n\t\t\tagentSpeaking: args.label.isAgentEcho === true,\n\t\t\t...(typeof selfVoiceSimilarity === \"number\"\n\t\t\t\t? { selfVoiceSimilarity }\n\t\t\t\t: {}),\n\t\t\tspeaker: {\n\t\t\t\tentityId: matchedEntityId,\n\t\t\t\tconfidence: Math.max(0, Math.min(1, speakerMatch?.similarity ?? 0)),\n\t\t\t\tisOwner: predictedOwner,\n\t\t\t},\n\t\t\twakeWordActive: /\\bhey\\s+eliza\\b/i.test(transcript),\n\t\t\tknownSpeakerEntityIds: knownSpeakerIds(args.groundTruth),\n\t\t});\n\t\tconst transcriptionMode =\n\t\t\targs.groundTruth.classes.includes(\"transcription-mode\");\n\t\tconst responded = !transcriptionMode && signal.nextSpeaker === \"agent\";\n\t\tconst inferredEntities: string[] = [];\n\t\tconst name = extractName(transcript);\n\t\tif (name) {\n\t\t\tconst participant = args.groundTruth.participants.find(\n\t\t\t\t(p) => p.label.toLowerCase() === name && p.entityId,\n\t\t\t);\n\t\t\tif (participant?.entityId) inferredEntities.push(participant.entityId);\n\t\t}\n\n\t\tif (responded && args.label.agentReplyText) {\n\t\t\tthis.lastAgentReply = args.label.agentReplyText;\n\t\t\tawait this.observeAgentReply(args.label.agentReplyText);\n\t\t}\n\n\t\treturn {\n\t\t\thypothesisTranscript: transcript,\n\t\t\tpredictedSpeakerLabel: speakerMatch?.profile.label ?? null,\n\t\t\teotDecided,\n\t\t\tresponded,\n\t\t\tinferredEntities,\n\t\t\tmatchedEntityId,\n\t\t\tpredictedOwner,\n\t\t};\n\t}\n\n\tprivate async synthesizeCorpusTurn(args: {\n\t\ttext: string;\n\t\tvoiceId?: string;\n\t\tspeakerLabel: string;\n\t\tturnIndex: number;\n\t\tisAgentEcho: boolean;\n\t\tsampleRate: number;\n\t}): Promise<Float32Array> {\n\t\tif (args.isAgentEcho) {\n\t\t\treturn ensureSampleRate(\n\t\t\t\tthis.synthesizeAgent(args.text),\n\t\t\t\tSAMPLE_RATE,\n\t\t\t\targs.sampleRate,\n\t\t\t);\n\t\t}\n\t\tconst voiceId = this.resolveElevenLabsVoiceId(\n\t\t\targs.voiceId,\n\t\t\targs.speakerLabel,\n\t\t);\n\t\treturn elevenLabsPcm({\n\t\t\ttext: args.text,\n\t\t\tvoiceId,\n\t\t\tapiKey: this.apiKey,\n\t\t\tsampleRate: args.sampleRate,\n\t\t});\n\t}\n\n\tprivate resolveElevenLabsVoiceId(\n\t\tvoiceId: string | undefined,\n\t\tspeakerLabel: string,\n\t): string {\n\t\tconst keys = [voiceId, speakerLabel].filter(\n\t\t\t(value): value is string => typeof value === \"string\" && value.length > 0,\n\t\t);\n\t\tfor (const key of keys) {\n\t\t\tconst mapped =\n\t\t\t\tthis.voiceMap[key.toLowerCase()] ?? VOICE_ID_ALIASES[key.toLowerCase()];\n\t\t\tif (mapped) return mapped;\n\t\t}\n\t\treturn ELEVENLABS_VOICE_IDS[\n\t\t\tlabelHash(speakerLabel) % ELEVENLABS_VOICE_IDS.length\n\t\t];\n\t}\n\n\tprivate synthesizeAgent(text: string): Float32Array {\n\t\tthis.ffi.mmapAcquire(this.ctx, \"tts\");\n\t\ttry {\n\t\t\tconst out = new Float32Array(SAMPLE_RATE * MAX_AGENT_TTS_SECONDS);\n\t\t\tconst samples = this.ffi.ttsSynthesize({\n\t\t\t\tctx: this.ctx,\n\t\t\t\ttext,\n\t\t\t\tspeakerPresetId: null,\n\t\t\t\tout,\n\t\t\t});\n\t\t\tif (!Number.isFinite(samples) || samples <= 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`[voice:workbench --real] agent TTS produced ${samples} samples`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn out.slice(0, samples);\n\t\t} finally {\n\t\t\tthis.ffi.mmapEvict(this.ctx, \"tts\");\n\t\t}\n\t}\n\n\tprivate async observeAgentReply(text: string): Promise<void> {\n\t\tconst pcm = this.synthesizeAgent(text);\n\t\tthis.selfVoiceEmbeddings.push(\n\t\t\tawait this.encoder.encode(ensureMinSpeakerSamples(pcm)),\n\t\t);\n\t\twhile (this.selfVoiceEmbeddings.length > 8) {\n\t\t\tthis.selfVoiceEmbeddings.shift();\n\t\t}\n\t}\n\n\tprivate selfVoiceSimilarity(embedding: Float32Array): number | null {\n\t\tif (this.selfVoiceEmbeddings.length === 0) return null;\n\t\treturn cosineSimilarity(\n\t\t\tembedding,\n\t\t\taverageEmbeddings(this.selfVoiceEmbeddings),\n\t\t);\n\t}\n\n\tprivate async transcribe(pcm: Float32Array): Promise<string> {\n\t\tthis.ffi.mmapAcquire(this.ctx, \"asr\");\n\t\ttry {\n\t\t\tif (this.ffi.timedAsrSupported?.()) {\n\t\t\t\treturn this.ffi\n\t\t\t\t\t.asrTranscribeTimed({ ctx: this.ctx, pcm, sampleRateHz: SAMPLE_RATE })\n\t\t\t\t\t.text.trim();\n\t\t\t}\n\t\t\treturn this.ffi\n\t\t\t\t.asrTranscribe({ ctx: this.ctx, pcm, sampleRateHz: SAMPLE_RATE })\n\t\t\t\t.trim();\n\t\t} finally {\n\t\t\tthis.ffi.mmapEvict(this.ctx, \"asr\");\n\t\t}\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.encoder.dispose();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tawait this.diarizer.dispose();\n\t\t\t} finally {\n\t\t\t\tthis.ffi.destroy(this.ctx);\n\t\t\t\tthis.ffi.close();\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport async function createRealVoiceWorkbenchRuntimeFromEnv(\n\tenv: NodeJS.ProcessEnv = process.env,\n): Promise<RealVoiceWorkbenchRuntime> {\n\tconst bundle = requirePath(\n\t\t\"ELIZA_ASR_BUNDLE\",\n\t\tnonEmpty(env.ELIZA_ASR_BUNDLE) ??\n\t\t\tnonEmpty(env.ELIZA_VOICE_REAL_MODEL_DIR) ??\n\t\t\tpath.join(\n\t\t\t\tos.homedir(),\n\t\t\t\t\".eliza/local-inference/models/eliza-1-2b.bundle\",\n\t\t\t),\n\t);\n\tconst fusedLib = requirePath(\n\t\t\"libelizainference\",\n\t\tresolveFusedLibraryPath(bundle, env),\n\t);\n\tconst speakerGguf = requirePath(\n\t\t\"speaker GGUF\",\n\t\tfirstExisting(\n\t\t\tnonEmpty(env.ELIZA_SPEAKER_GGUF),\n\t\t\tpath.join(bundle, \"speaker\", \"wespeaker-resnet34-lm.gguf\"),\n\t\t\tpath.join(bundle, \"speaker-encoder\", \"wespeaker-resnet34-lm.gguf\"),\n\t\t\tpath.join(bundle, \"voice/speaker-encoder/wespeaker-resnet34-lm.gguf\"),\n\t\t),\n\t);\n\tconst diarizGguf = requirePath(\n\t\t\"diarizer GGUF\",\n\t\tfirstExisting(\n\t\t\tnonEmpty(env.ELIZA_DIARIZ_GGUF),\n\t\t\tpath.join(bundle, \"diariz\", \"pyannote-segmentation-3.0.gguf\"),\n\t\t\tpath.join(bundle, \"diarizer\", \"pyannote-segmentation-3.0.gguf\"),\n\t\t\tpath.join(bundle, \"voice/diarizer/pyannote-segmentation-3.0.gguf\"),\n\t\t),\n\t);\n\tconst apiKey = nonEmpty(env.ELEVENLABS_API_KEY);\n\tif (!apiKey) {\n\t\tthrow new Error(\"[voice:workbench --real] ELEVENLABS_API_KEY is required\");\n\t}\n\n\treturn RealVoiceWorkbenchAdapter.create({\n\t\tbundle,\n\t\tfusedLib,\n\t\tspeakerGguf,\n\t\tdiarizGguf,\n\t\televenLabsApiKey: apiKey,\n\t\townerAcceptThreshold: finiteNumberEnv(\n\t\t\tenv,\n\t\t\t\"ELIZA_VOICE_OWNER_ACCEPT_THRESHOLD\",\n\t\t\tDEFAULT_OWNER_THRESHOLD,\n\t\t),\n\t\tvoiceMap: parseVoiceMap(env.ELIZA_WORKBENCH_ELEVENLABS_VOICE_MAP),\n\t});\n}\n"
30
+ ],
31
+ "mappings": "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",
32
+ "debugId": "56692D5159CE0CFD64756E2164756E21",
33
+ "names": []
34
+ }