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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (701) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/package.json +82 -15
  4. package/src/actions/generate-media.d.ts +59 -0
  5. package/src/actions/generate-media.d.ts.map +1 -0
  6. package/src/actions/generate-media.ts +647 -0
  7. package/src/actions/identify-speaker.d.ts +23 -0
  8. package/src/actions/identify-speaker.d.ts.map +1 -0
  9. package/src/actions/identify-speaker.ts +171 -0
  10. package/src/actions/transcription-control.d.ts +29 -0
  11. package/src/actions/transcription-control.d.ts.map +1 -0
  12. package/src/actions/transcription-control.test.ts +100 -0
  13. package/src/actions/transcription-control.ts +127 -0
  14. package/src/adapters/capacitor-llama/__tests__/compat-behavior.test.ts +218 -0
  15. package/src/adapters/capacitor-llama/__tests__/index.test.ts +68 -0
  16. package/src/adapters/capacitor-llama/__tests__/structured-output.test.ts +215 -0
  17. package/src/adapters/capacitor-llama/__tests__/text-streaming.test.ts +174 -0
  18. package/src/adapters/capacitor-llama/environment.ts +71 -0
  19. package/src/adapters/capacitor-llama/index.browser.ts +83 -0
  20. package/src/adapters/capacitor-llama/index.ts +807 -0
  21. package/src/adapters/capacitor-llama/loader.ts +109 -0
  22. package/src/adapters/capacitor-llama/structured-output.ts +165 -0
  23. package/src/adapters/capacitor-llama/text-streaming.ts +227 -0
  24. package/src/adapters/capacitor-llama/types.ts +374 -0
  25. package/src/backends/apple-foundation.ts +127 -0
  26. package/src/index.d.ts +8 -0
  27. package/src/index.d.ts.map +1 -0
  28. package/src/index.ts +62 -0
  29. package/src/local-inference-routes.d.ts +38 -0
  30. package/src/local-inference-routes.d.ts.map +1 -0
  31. package/src/local-inference-routes.test.ts +344 -0
  32. package/src/local-inference-routes.ts +1543 -0
  33. package/src/provider.d.ts +21 -0
  34. package/src/provider.d.ts.map +1 -0
  35. package/src/provider.ts +1082 -0
  36. package/src/routes/compat-helpers.d.ts +18 -0
  37. package/src/routes/compat-helpers.d.ts.map +1 -0
  38. package/src/routes/compat-helpers.ts +274 -0
  39. package/src/routes/family-member-route.d.ts +62 -0
  40. package/src/routes/family-member-route.d.ts.map +1 -0
  41. package/src/routes/family-member-route.ts +353 -0
  42. package/src/routes/index.d.ts +19 -0
  43. package/src/routes/index.d.ts.map +1 -0
  44. package/src/routes/index.ts +60 -0
  45. package/src/routes/live-diarization-route.d.ts +26 -0
  46. package/src/routes/live-diarization-route.d.ts.map +1 -0
  47. package/src/routes/live-diarization-route.test.ts +213 -0
  48. package/src/routes/live-diarization-route.ts +122 -0
  49. package/src/routes/local-inference-asr-route.d.ts +4 -0
  50. package/src/routes/local-inference-asr-route.d.ts.map +1 -0
  51. package/src/routes/local-inference-asr-route.test.ts +205 -0
  52. package/src/routes/local-inference-asr-route.ts +163 -0
  53. package/src/routes/local-inference-asr-transcribe.d.ts +20 -0
  54. package/src/routes/local-inference-asr-transcribe.d.ts.map +1 -0
  55. package/src/routes/local-inference-asr-transcribe.test.ts +118 -0
  56. package/src/routes/local-inference-asr-transcribe.ts +97 -0
  57. package/src/routes/local-inference-compat-routes.d.ts +16 -0
  58. package/src/routes/local-inference-compat-routes.d.ts.map +1 -0
  59. package/src/routes/local-inference-compat-routes.test.ts +485 -0
  60. package/src/routes/local-inference-compat-routes.ts +808 -0
  61. package/src/routes/local-inference-tts-route.d.ts +7 -0
  62. package/src/routes/local-inference-tts-route.d.ts.map +1 -0
  63. package/src/routes/local-inference-tts-route.test.ts +179 -0
  64. package/src/routes/local-inference-tts-route.ts +230 -0
  65. package/src/routes/transcript-audio-store.d.ts +15 -0
  66. package/src/routes/transcript-audio-store.d.ts.map +1 -0
  67. package/src/routes/transcript-audio-store.ts +27 -0
  68. package/src/routes/transcripts-routes.d.ts +36 -0
  69. package/src/routes/transcripts-routes.d.ts.map +1 -0
  70. package/src/routes/transcripts-routes.test.ts +144 -0
  71. package/src/routes/transcripts-routes.ts +159 -0
  72. package/src/routes/voice-first-run-routes.d.ts +62 -0
  73. package/src/routes/voice-first-run-routes.d.ts.map +1 -0
  74. package/src/routes/voice-first-run-routes.ts +524 -0
  75. package/src/routes/voice-models-routes.d.ts +62 -0
  76. package/src/routes/voice-models-routes.d.ts.map +1 -0
  77. package/src/routes/voice-models-routes.ts +554 -0
  78. package/src/routes/voice-profile-plugin-routes.d.ts +19 -0
  79. package/src/routes/voice-profile-plugin-routes.d.ts.map +1 -0
  80. package/src/routes/voice-profile-plugin-routes.ts +138 -0
  81. package/src/routes/voice-profiles-management-routes.d.ts +52 -0
  82. package/src/routes/voice-profiles-management-routes.d.ts.map +1 -0
  83. package/src/routes/voice-profiles-management-routes.ts +476 -0
  84. package/src/routes/voice-speaker-profile-routes.d.ts +57 -0
  85. package/src/routes/voice-speaker-profile-routes.d.ts.map +1 -0
  86. package/src/routes/voice-speaker-profile-routes.ts +199 -0
  87. package/src/runtime/aosp-llama-loader-selection.test.ts +80 -0
  88. package/src/runtime/capacitor-llama.d.ts +25 -0
  89. package/src/runtime/embedding-manager-support.d.ts +77 -0
  90. package/src/runtime/embedding-manager-support.d.ts.map +1 -0
  91. package/src/runtime/embedding-manager-support.ts +497 -0
  92. package/src/runtime/embedding-presets.d.ts +16 -0
  93. package/src/runtime/embedding-presets.d.ts.map +1 -0
  94. package/src/runtime/embedding-presets.ts +81 -0
  95. package/src/runtime/embedding-warmup-policy.d.ts +14 -0
  96. package/src/runtime/embedding-warmup-policy.d.ts.map +1 -0
  97. package/src/runtime/embedding-warmup-policy.test.ts +53 -0
  98. package/src/runtime/embedding-warmup-policy.ts +48 -0
  99. package/src/runtime/ensure-local-inference-handler.d.ts +62 -0
  100. package/src/runtime/ensure-local-inference-handler.d.ts.map +1 -0
  101. package/src/runtime/ensure-local-inference-handler.test.ts +528 -0
  102. package/src/runtime/ensure-local-inference-handler.ts +1448 -0
  103. package/src/runtime/index.d.ts +15 -0
  104. package/src/runtime/index.d.ts.map +1 -0
  105. package/src/runtime/index.ts +33 -0
  106. package/src/runtime/mobile-local-inference-gate.d.ts +31 -0
  107. package/src/runtime/mobile-local-inference-gate.d.ts.map +1 -0
  108. package/src/runtime/mobile-local-inference-gate.test.ts +69 -0
  109. package/src/runtime/mobile-local-inference-gate.ts +44 -0
  110. package/src/runtime/voice-entity-binding.d.ts +103 -0
  111. package/src/runtime/voice-entity-binding.d.ts.map +1 -0
  112. package/src/runtime/voice-entity-binding.transcript.test.ts +69 -0
  113. package/src/runtime/voice-entity-binding.ts +328 -0
  114. package/src/services/README.md +71 -0
  115. package/src/services/__tests__/backend-selector.test.ts +101 -0
  116. package/src/services/__tests__/checkpoint-manager.test.ts +376 -0
  117. package/src/services/__tests__/gpu-autotune.test.ts +400 -0
  118. package/src/services/__tests__/llm-streaming-binding.test.ts +85 -0
  119. package/src/services/__tests__/planner-grammar.test.ts +372 -0
  120. package/src/services/__tests__/runtime-target.test.ts +176 -0
  121. package/src/services/active-model-switch-rollback.test.ts +183 -0
  122. package/src/services/active-model.d.ts +282 -0
  123. package/src/services/active-model.d.ts.map +1 -0
  124. package/src/services/active-model.ts +1213 -0
  125. package/src/services/assignments.d.ts +71 -0
  126. package/src/services/assignments.d.ts.map +1 -0
  127. package/src/services/assignments.test.ts +80 -0
  128. package/src/services/assignments.ts +230 -0
  129. package/src/services/backend-selector.ts +95 -0
  130. package/src/services/backend.d.ts +346 -0
  131. package/src/services/backend.d.ts.map +1 -0
  132. package/src/services/backend.ts +612 -0
  133. package/src/services/bionic-host-loader.d.ts +46 -0
  134. package/src/services/bionic-host-loader.d.ts.map +1 -0
  135. package/src/services/bionic-host-loader.test.ts +133 -0
  136. package/src/services/bionic-host-loader.ts +180 -0
  137. package/src/services/bundled-models.d.ts +34 -0
  138. package/src/services/bundled-models.d.ts.map +1 -0
  139. package/src/services/bundled-models.ts +129 -0
  140. package/src/services/cache-bridge.d.ts +206 -0
  141. package/src/services/cache-bridge.d.ts.map +1 -0
  142. package/src/services/cache-bridge.test.ts +516 -0
  143. package/src/services/cache-bridge.ts +423 -0
  144. package/src/services/catalog.d.ts +10 -0
  145. package/src/services/catalog.d.ts.map +1 -0
  146. package/src/services/catalog.test.ts +238 -0
  147. package/src/services/catalog.ts +27 -0
  148. package/src/services/checkpoint-client.d.ts +109 -0
  149. package/src/services/checkpoint-client.d.ts.map +1 -0
  150. package/src/services/checkpoint-client.ts +258 -0
  151. package/src/services/checkpoint-manager.ts +474 -0
  152. package/src/services/cloud-fallback.d.ts +102 -0
  153. package/src/services/cloud-fallback.d.ts.map +1 -0
  154. package/src/services/cloud-fallback.ts +230 -0
  155. package/src/services/conversation-registry.d.ts +142 -0
  156. package/src/services/conversation-registry.d.ts.map +1 -0
  157. package/src/services/conversation-registry.test.ts +235 -0
  158. package/src/services/conversation-registry.ts +264 -0
  159. package/src/services/desktop-fused-ffi-backend-runtime.d.ts +95 -0
  160. package/src/services/desktop-fused-ffi-backend-runtime.d.ts.map +1 -0
  161. package/src/services/desktop-fused-ffi-backend-runtime.ts +339 -0
  162. package/src/services/device-bridge.d.ts +188 -0
  163. package/src/services/device-bridge.d.ts.map +1 -0
  164. package/src/services/device-bridge.ts +1237 -0
  165. package/src/services/device-resource-metrics.d.ts +149 -0
  166. package/src/services/device-resource-metrics.d.ts.map +1 -0
  167. package/src/services/device-resource-metrics.test.ts +98 -0
  168. package/src/services/device-resource-metrics.ts +346 -0
  169. package/src/services/device-tier.d.ts +115 -0
  170. package/src/services/device-tier.d.ts.map +1 -0
  171. package/src/services/device-tier.test.ts +371 -0
  172. package/src/services/device-tier.ts +410 -0
  173. package/src/services/downloader.d.ts +82 -0
  174. package/src/services/downloader.d.ts.map +1 -0
  175. package/src/services/downloader.test.ts +747 -0
  176. package/src/services/downloader.ts +925 -0
  177. package/src/services/engine-direct-bundle.test.ts +58 -0
  178. package/src/services/engine-streaming.test.ts +80 -0
  179. package/src/services/engine.d.ts +540 -0
  180. package/src/services/engine.d.ts.map +1 -0
  181. package/src/services/engine.ts +1909 -0
  182. package/src/services/ensure-local-artifacts.integration.test.ts +273 -0
  183. package/src/services/ensure-local-artifacts.test.ts +368 -0
  184. package/src/services/ensure-local-artifacts.ts +351 -0
  185. package/src/services/external-scanner.d.ts +17 -0
  186. package/src/services/external-scanner.d.ts.map +1 -0
  187. package/src/services/external-scanner.ts +312 -0
  188. package/src/services/ffi-llm-mock.ts +354 -0
  189. package/src/services/ffi-llm-streaming-abi.ts +442 -0
  190. package/src/services/ffi-streaming-backend.d.ts +180 -0
  191. package/src/services/ffi-streaming-backend.d.ts.map +1 -0
  192. package/src/services/ffi-streaming-backend.ts +382 -0
  193. package/src/services/ffi-streaming-runner.d.ts +122 -0
  194. package/src/services/ffi-streaming-runner.d.ts.map +1 -0
  195. package/src/services/ffi-streaming-runner.test.ts +60 -0
  196. package/src/services/ffi-streaming-runner.ts +354 -0
  197. package/src/services/ffi-unload-ordering.test.ts +162 -0
  198. package/src/services/gpu-autotune.ts +534 -0
  199. package/src/services/gpu-detect.d.ts +56 -0
  200. package/src/services/gpu-detect.d.ts.map +1 -0
  201. package/src/services/gpu-detect.ts +139 -0
  202. package/src/services/handler-registry.d.ts +72 -0
  203. package/src/services/handler-registry.d.ts.map +1 -0
  204. package/src/services/handler-registry.ts +240 -0
  205. package/src/services/hardware.d.ts +63 -0
  206. package/src/services/hardware.d.ts.map +1 -0
  207. package/src/services/hardware.test.ts +231 -0
  208. package/src/services/hardware.ts +410 -0
  209. package/src/services/hf-search.d.ts +26 -0
  210. package/src/services/hf-search.d.ts.map +1 -0
  211. package/src/services/hf-search.test.ts +69 -0
  212. package/src/services/hf-search.ts +420 -0
  213. package/src/services/image-description-runtime.d.ts +14 -0
  214. package/src/services/image-description-runtime.d.ts.map +1 -0
  215. package/src/services/image-description-runtime.test.ts +61 -0
  216. package/src/services/image-description-runtime.ts +118 -0
  217. package/src/services/imagegen/aosp-unavailable.d.ts +134 -0
  218. package/src/services/imagegen/aosp-unavailable.d.ts.map +1 -0
  219. package/src/services/imagegen/aosp-unavailable.ts +229 -0
  220. package/src/services/imagegen/backend-selector.d.ts +118 -0
  221. package/src/services/imagegen/backend-selector.d.ts.map +1 -0
  222. package/src/services/imagegen/backend-selector.ts +277 -0
  223. package/src/services/imagegen/coreml-unavailable.d.ts +105 -0
  224. package/src/services/imagegen/coreml-unavailable.d.ts.map +1 -0
  225. package/src/services/imagegen/coreml-unavailable.ts +237 -0
  226. package/src/services/imagegen/errors.d.ts +16 -0
  227. package/src/services/imagegen/errors.d.ts.map +1 -0
  228. package/src/services/imagegen/errors.ts +40 -0
  229. package/src/services/imagegen/index.d.ts +58 -0
  230. package/src/services/imagegen/index.d.ts.map +1 -0
  231. package/src/services/imagegen/index.ts +144 -0
  232. package/src/services/imagegen/mflux.d.ts +74 -0
  233. package/src/services/imagegen/mflux.d.ts.map +1 -0
  234. package/src/services/imagegen/mflux.ts +313 -0
  235. package/src/services/imagegen/sd-cpp.d.ts +180 -0
  236. package/src/services/imagegen/sd-cpp.d.ts.map +1 -0
  237. package/src/services/imagegen/sd-cpp.ts +718 -0
  238. package/src/services/imagegen/tensorrt-unavailable.d.ts +83 -0
  239. package/src/services/imagegen/tensorrt-unavailable.d.ts.map +1 -0
  240. package/src/services/imagegen/tensorrt-unavailable.ts +295 -0
  241. package/src/services/imagegen/types.d.ts +181 -0
  242. package/src/services/imagegen/types.d.ts.map +1 -0
  243. package/src/services/imagegen/types.ts +193 -0
  244. package/src/services/index.d.ts +29 -0
  245. package/src/services/index.d.ts.map +1 -0
  246. package/src/services/index.ts +211 -0
  247. package/src/services/inference-capabilities.d.ts +132 -0
  248. package/src/services/inference-capabilities.d.ts.map +1 -0
  249. package/src/services/inference-capabilities.test.ts +75 -0
  250. package/src/services/inference-capabilities.ts +204 -0
  251. package/src/services/inference-telemetry.d.ts +59 -0
  252. package/src/services/inference-telemetry.d.ts.map +1 -0
  253. package/src/services/inference-telemetry.ts +143 -0
  254. package/src/services/ios-llama-streaming.ts +248 -0
  255. package/src/services/kv-spill.d.ts +189 -0
  256. package/src/services/kv-spill.d.ts.map +1 -0
  257. package/src/services/kv-spill.test.ts +222 -0
  258. package/src/services/kv-spill.ts +356 -0
  259. package/src/services/latency-trace.d.ts +346 -0
  260. package/src/services/latency-trace.d.ts.map +1 -0
  261. package/src/services/latency-trace.test.ts +266 -0
  262. package/src/services/latency-trace.ts +844 -0
  263. package/src/services/llama-server-metrics.ts +304 -0
  264. package/src/services/llm-streaming-binding.d.ts +96 -0
  265. package/src/services/llm-streaming-binding.d.ts.map +1 -0
  266. package/src/services/llm-streaming-binding.ts +136 -0
  267. package/src/services/load-args.d.ts +82 -0
  268. package/src/services/load-args.d.ts.map +1 -0
  269. package/src/services/load-args.ts +81 -0
  270. package/src/services/manifest/eliza-1.manifest.v1.json +708 -0
  271. package/src/services/manifest/index.d.ts +4 -0
  272. package/src/services/manifest/index.d.ts.map +1 -0
  273. package/src/services/manifest/index.ts +66 -0
  274. package/src/services/manifest/manifest.test.ts +689 -0
  275. package/src/services/manifest/schema.d.ts +713 -0
  276. package/src/services/manifest/schema.d.ts.map +1 -0
  277. package/src/services/manifest/schema.ts +653 -0
  278. package/src/services/manifest/types.d.ts +30 -0
  279. package/src/services/manifest/types.d.ts.map +1 -0
  280. package/src/services/manifest/types.ts +55 -0
  281. package/src/services/manifest/validator.d.ts +66 -0
  282. package/src/services/manifest/validator.d.ts.map +1 -0
  283. package/src/services/manifest/validator.ts +567 -0
  284. package/src/services/memory-arbiter.d.ts +318 -0
  285. package/src/services/memory-arbiter.d.ts.map +1 -0
  286. package/src/services/memory-arbiter.test.ts +419 -0
  287. package/src/services/memory-arbiter.ts +925 -0
  288. package/src/services/memory-monitor.d.ts +122 -0
  289. package/src/services/memory-monitor.d.ts.map +1 -0
  290. package/src/services/memory-monitor.test.ts +208 -0
  291. package/src/services/memory-monitor.ts +297 -0
  292. package/src/services/memory-pressure.d.ts +130 -0
  293. package/src/services/memory-pressure.d.ts.map +1 -0
  294. package/src/services/memory-pressure.ts +414 -0
  295. package/src/services/mtp-doctor.d.ts +13 -0
  296. package/src/services/mtp-doctor.d.ts.map +1 -0
  297. package/src/services/mtp-doctor.ts +78 -0
  298. package/src/services/network-policy.d.ts +127 -0
  299. package/src/services/network-policy.d.ts.map +1 -0
  300. package/src/services/network-policy.ts +346 -0
  301. package/src/services/paths.d.ts +6 -0
  302. package/src/services/paths.d.ts.map +1 -0
  303. package/src/services/paths.ts +25 -0
  304. package/src/services/planner-skeleton.d.ts +124 -0
  305. package/src/services/planner-skeleton.d.ts.map +1 -0
  306. package/src/services/planner-skeleton.ts +175 -0
  307. package/src/services/providers.d.ts +38 -0
  308. package/src/services/providers.d.ts.map +1 -0
  309. package/src/services/providers.ts +507 -0
  310. package/src/services/ram-budget-cache.test.ts +163 -0
  311. package/src/services/ram-budget.d.ts +110 -0
  312. package/src/services/ram-budget.d.ts.map +1 -0
  313. package/src/services/ram-budget.ts +0 -0
  314. package/src/services/readiness.d.ts +9 -0
  315. package/src/services/readiness.d.ts.map +1 -0
  316. package/src/services/readiness.test.ts +87 -0
  317. package/src/services/readiness.ts +238 -0
  318. package/src/services/recommendation.d.ts +111 -0
  319. package/src/services/recommendation.d.ts.map +1 -0
  320. package/src/services/recommendation.ts +671 -0
  321. package/src/services/registry.d.ts +35 -0
  322. package/src/services/registry.d.ts.map +1 -0
  323. package/src/services/registry.ts +151 -0
  324. package/src/services/router-handler.d.ts +92 -0
  325. package/src/services/router-handler.d.ts.map +1 -0
  326. package/src/services/router-handler.test.ts +45 -0
  327. package/src/services/router-handler.ts +407 -0
  328. package/src/services/routing-policy.d.ts +69 -0
  329. package/src/services/routing-policy.d.ts.map +1 -0
  330. package/src/services/routing-policy.test.ts +164 -0
  331. package/src/services/routing-policy.ts +297 -0
  332. package/src/services/routing-preferences.d.ts +8 -0
  333. package/src/services/routing-preferences.d.ts.map +1 -0
  334. package/src/services/routing-preferences.ts +17 -0
  335. package/src/services/runtime-target.d.ts +98 -0
  336. package/src/services/runtime-target.d.ts.map +1 -0
  337. package/src/services/runtime-target.ts +154 -0
  338. package/src/services/service.d.ts +128 -0
  339. package/src/services/service.d.ts.map +1 -0
  340. package/src/services/service.test.ts +223 -0
  341. package/src/services/service.ts +735 -0
  342. package/src/services/session-pool.d.ts +72 -0
  343. package/src/services/session-pool.d.ts.map +1 -0
  344. package/src/services/session-pool.ts +153 -0
  345. package/src/services/structured-output/deterministic-repair.d.ts +23 -0
  346. package/src/services/structured-output/deterministic-repair.d.ts.map +1 -0
  347. package/src/services/structured-output/deterministic-repair.test.ts +169 -0
  348. package/src/services/structured-output/deterministic-repair.ts +443 -0
  349. package/src/services/structured-output/index.ts +4 -0
  350. package/src/services/structured-output.d.ts +311 -0
  351. package/src/services/structured-output.d.ts.map +1 -0
  352. package/src/services/structured-output.test.ts +483 -0
  353. package/src/services/structured-output.ts +712 -0
  354. package/src/services/system-memory.d.ts +33 -0
  355. package/src/services/system-memory.d.ts.map +1 -0
  356. package/src/services/system-memory.test.ts +47 -0
  357. package/src/services/system-memory.ts +67 -0
  358. package/src/services/transcription-priority.test.ts +211 -0
  359. package/src/services/types.d.ts +19 -0
  360. package/src/services/types.d.ts.map +1 -0
  361. package/src/services/types.ts +55 -0
  362. package/src/services/verify-on-device.d.ts +34 -0
  363. package/src/services/verify-on-device.d.ts.map +1 -0
  364. package/src/services/verify-on-device.test.ts +87 -0
  365. package/src/services/verify-on-device.ts +127 -0
  366. package/src/services/verify.d.ts +8 -0
  367. package/src/services/verify.d.ts.map +1 -0
  368. package/src/services/verify.ts +13 -0
  369. package/src/services/vision/aosp-unavailable.d.ts +115 -0
  370. package/src/services/vision/aosp-unavailable.d.ts.map +1 -0
  371. package/src/services/vision/aosp-unavailable.ts +163 -0
  372. package/src/services/vision/capacitor-llama.d.ts +99 -0
  373. package/src/services/vision/capacitor-llama.d.ts.map +1 -0
  374. package/src/services/vision/capacitor-llama.ts +255 -0
  375. package/src/services/vision/cloud-fallback.d.ts +47 -0
  376. package/src/services/vision/cloud-fallback.d.ts.map +1 -0
  377. package/src/services/vision/cloud-fallback.test.ts +243 -0
  378. package/src/services/vision/cloud-fallback.ts +268 -0
  379. package/src/services/vision/fallback-chain.test.ts +86 -0
  380. package/src/services/vision/hash.d.ts +71 -0
  381. package/src/services/vision/hash.d.ts.map +1 -0
  382. package/src/services/vision/hash.ts +157 -0
  383. package/src/services/vision/index.d.ts +95 -0
  384. package/src/services/vision/index.d.ts.map +1 -0
  385. package/src/services/vision/index.ts +251 -0
  386. package/src/services/vision/llama-server.d.ts +73 -0
  387. package/src/services/vision/llama-server.d.ts.map +1 -0
  388. package/src/services/vision/llama-server.ts +177 -0
  389. package/src/services/vision/types.d.ts +153 -0
  390. package/src/services/vision/types.d.ts.map +1 -0
  391. package/src/services/vision/types.ts +154 -0
  392. package/src/services/vision/vast-fallback.d.ts +18 -0
  393. package/src/services/vision/vast-fallback.d.ts.map +1 -0
  394. package/src/services/vision/vast-fallback.ts +127 -0
  395. package/src/services/vision-embedding-cache.d.ts +98 -0
  396. package/src/services/vision-embedding-cache.d.ts.map +1 -0
  397. package/src/services/vision-embedding-cache.ts +189 -0
  398. package/src/services/voice/VOICE_WORKBENCH.md +88 -0
  399. package/src/services/voice/__test-helpers__/fake-ffi.ts +94 -0
  400. package/src/services/voice/__test-helpers__/synthetic-speech.ts +124 -0
  401. package/src/services/voice/__tests__/checkpoint-manager.test.ts +241 -0
  402. package/src/services/voice/__tests__/checkpoint-policy.test.ts +270 -0
  403. package/src/services/voice/__tests__/eager-context-builder.test.ts +257 -0
  404. package/src/services/voice/__tests__/eliza1-eot-scorer.test.ts +288 -0
  405. package/src/services/voice/__tests__/eot-classifier.test.ts +431 -0
  406. package/src/services/voice/__tests__/optimistic-rollback.test.ts +312 -0
  407. package/src/services/voice/__tests__/prefill-client.test.ts +266 -0
  408. package/src/services/voice/__tests__/prefix-preserving-queue.test.ts +208 -0
  409. package/src/services/voice/__tests__/streaming-asr.test.ts +450 -0
  410. package/src/services/voice/__tests__/streaming-transcriber.test.ts +339 -0
  411. package/src/services/voice/__tests__/turn-detector-resolver.test.ts +195 -0
  412. package/src/services/voice/__tests__/voice-state-machine-prefill.test.ts +275 -0
  413. package/src/services/voice/__tests__/voice-state-machine.test.ts +354 -0
  414. package/src/services/voice/asr-timed.real.test.ts +141 -0
  415. package/src/services/voice/audio-frame-consumer.d.ts +212 -0
  416. package/src/services/voice/audio-frame-consumer.d.ts.map +1 -0
  417. package/src/services/voice/audio-frame-consumer.test.ts +343 -0
  418. package/src/services/voice/audio-frame-consumer.ts +491 -0
  419. package/src/services/voice/barge-in.d.ts +112 -0
  420. package/src/services/voice/barge-in.d.ts.map +1 -0
  421. package/src/services/voice/barge-in.test.ts +244 -0
  422. package/src/services/voice/barge-in.ts +336 -0
  423. package/src/services/voice/cancellation-coordinator.d.ts +127 -0
  424. package/src/services/voice/cancellation-coordinator.d.ts.map +1 -0
  425. package/src/services/voice/cancellation-coordinator.test.ts +196 -0
  426. package/src/services/voice/cancellation-coordinator.ts +269 -0
  427. package/src/services/voice/checkpoint-manager.d.ts +199 -0
  428. package/src/services/voice/checkpoint-manager.d.ts.map +1 -0
  429. package/src/services/voice/checkpoint-manager.ts +401 -0
  430. package/src/services/voice/checkpoint-policy.ts +336 -0
  431. package/src/services/voice/composite-eot-classifier.test.ts +59 -0
  432. package/src/services/voice/e2e-harness.test.ts +182 -0
  433. package/src/services/voice/e2e-harness.ts +743 -0
  434. package/src/services/voice/eager-context-builder.d.ts +170 -0
  435. package/src/services/voice/eager-context-builder.d.ts.map +1 -0
  436. package/src/services/voice/eager-context-builder.ts +262 -0
  437. package/src/services/voice/eliza1-eot-scorer.d.ts +124 -0
  438. package/src/services/voice/eliza1-eot-scorer.d.ts.map +1 -0
  439. package/src/services/voice/eliza1-eot-scorer.ts +242 -0
  440. package/src/services/voice/embedding-server.ts +200 -0
  441. package/src/services/voice/embedding.d.ts +133 -0
  442. package/src/services/voice/embedding.d.ts.map +1 -0
  443. package/src/services/voice/embedding.test.ts +131 -0
  444. package/src/services/voice/embedding.ts +243 -0
  445. package/src/services/voice/emotion-attribution.d.ts +68 -0
  446. package/src/services/voice/emotion-attribution.d.ts.map +1 -0
  447. package/src/services/voice/emotion-attribution.test.ts +129 -0
  448. package/src/services/voice/emotion-attribution.ts +361 -0
  449. package/src/services/voice/engine-bridge-cancellation.test.ts +422 -0
  450. package/src/services/voice/engine-bridge.d.ts +759 -0
  451. package/src/services/voice/engine-bridge.d.ts.map +1 -0
  452. package/src/services/voice/engine-bridge.test.ts +384 -0
  453. package/src/services/voice/engine-bridge.ts +2302 -0
  454. package/src/services/voice/eot-classifier-ggml.d.ts +179 -0
  455. package/src/services/voice/eot-classifier-ggml.d.ts.map +1 -0
  456. package/src/services/voice/eot-classifier-ggml.ts +566 -0
  457. package/src/services/voice/eot-classifier.d.ts +214 -0
  458. package/src/services/voice/eot-classifier.d.ts.map +1 -0
  459. package/src/services/voice/eot-classifier.ts +533 -0
  460. package/src/services/voice/errors.d.ts +20 -0
  461. package/src/services/voice/errors.d.ts.map +1 -0
  462. package/src/services/voice/errors.ts +32 -0
  463. package/src/services/voice/expressive-tags.d.ts +158 -0
  464. package/src/services/voice/expressive-tags.d.ts.map +1 -0
  465. package/src/services/voice/expressive-tags.ts +405 -0
  466. package/src/services/voice/ffi-bindings.d.ts +674 -0
  467. package/src/services/voice/ffi-bindings.d.ts.map +1 -0
  468. package/src/services/voice/ffi-bindings.test.ts +728 -0
  469. package/src/services/voice/ffi-bindings.ts +3225 -0
  470. package/src/services/voice/first-line-cache.d.ts +181 -0
  471. package/src/services/voice/first-line-cache.d.ts.map +1 -0
  472. package/src/services/voice/first-line-cache.ts +725 -0
  473. package/src/services/voice/fused-eot-scorer.d.ts +51 -0
  474. package/src/services/voice/fused-eot-scorer.d.ts.map +1 -0
  475. package/src/services/voice/fused-eot-scorer.ts +135 -0
  476. package/src/services/voice/index.d.ts +91 -0
  477. package/src/services/voice/index.d.ts.map +1 -0
  478. package/src/services/voice/index.ts +481 -0
  479. package/src/services/voice/kokoro/__tests__/kokoro-backend.test.ts +151 -0
  480. package/src/services/voice/kokoro/__tests__/kokoro-engine-bridge.real.test.ts +151 -0
  481. package/src/services/voice/kokoro/__tests__/kokoro-engine-bridge.test.ts +60 -0
  482. package/src/services/voice/kokoro/__tests__/kokoro-engine-discovery.test.ts +277 -0
  483. package/src/services/voice/kokoro/__tests__/kokoro-ffi-runtime.test.ts +235 -0
  484. package/src/services/voice/kokoro/__tests__/kokoro-runtime.test.ts +95 -0
  485. package/src/services/voice/kokoro/__tests__/phonemizer.test.ts +53 -0
  486. package/src/services/voice/kokoro/__tests__/runtime-selection.test.ts +231 -0
  487. package/src/services/voice/kokoro/__tests__/voices.test.ts +57 -0
  488. package/src/services/voice/kokoro/index.ts +79 -0
  489. package/src/services/voice/kokoro/kokoro-backend.d.ts +72 -0
  490. package/src/services/voice/kokoro/kokoro-backend.d.ts.map +1 -0
  491. package/src/services/voice/kokoro/kokoro-backend.ts +207 -0
  492. package/src/services/voice/kokoro/kokoro-engine-discovery.d.ts +58 -0
  493. package/src/services/voice/kokoro/kokoro-engine-discovery.d.ts.map +1 -0
  494. package/src/services/voice/kokoro/kokoro-engine-discovery.ts +177 -0
  495. package/src/services/voice/kokoro/kokoro-ffi-runtime.d.ts +75 -0
  496. package/src/services/voice/kokoro/kokoro-ffi-runtime.d.ts.map +1 -0
  497. package/src/services/voice/kokoro/kokoro-ffi-runtime.ts +233 -0
  498. package/src/services/voice/kokoro/kokoro-runtime.d.ts +100 -0
  499. package/src/services/voice/kokoro/kokoro-runtime.d.ts.map +1 -0
  500. package/src/services/voice/kokoro/kokoro-runtime.ts +170 -0
  501. package/src/services/voice/kokoro/phoneme-stream.ts +123 -0
  502. package/src/services/voice/kokoro/phonemizer.d.ts +50 -0
  503. package/src/services/voice/kokoro/phonemizer.d.ts.map +1 -0
  504. package/src/services/voice/kokoro/phonemizer.ts +344 -0
  505. package/src/services/voice/kokoro/pick-runtime.d.ts +61 -0
  506. package/src/services/voice/kokoro/pick-runtime.d.ts.map +1 -0
  507. package/src/services/voice/kokoro/pick-runtime.test.ts +91 -0
  508. package/src/services/voice/kokoro/pick-runtime.ts +130 -0
  509. package/src/services/voice/kokoro/runtime-selection.d.ts +92 -0
  510. package/src/services/voice/kokoro/runtime-selection.d.ts.map +1 -0
  511. package/src/services/voice/kokoro/runtime-selection.ts +237 -0
  512. package/src/services/voice/kokoro/types.d.ts +82 -0
  513. package/src/services/voice/kokoro/types.d.ts.map +1 -0
  514. package/src/services/voice/kokoro/types.ts +95 -0
  515. package/src/services/voice/kokoro/voice-presets.d.ts +23 -0
  516. package/src/services/voice/kokoro/voice-presets.d.ts.map +1 -0
  517. package/src/services/voice/kokoro/voice-presets.ts +129 -0
  518. package/src/services/voice/kokoro/voices.d.ts +30 -0
  519. package/src/services/voice/kokoro/voices.d.ts.map +1 -0
  520. package/src/services/voice/kokoro/voices.ts +64 -0
  521. package/src/services/voice/lifecycle.d.ts +135 -0
  522. package/src/services/voice/lifecycle.d.ts.map +1 -0
  523. package/src/services/voice/lifecycle.test.ts +315 -0
  524. package/src/services/voice/lifecycle.ts +301 -0
  525. package/src/services/voice/live-diarization-session.d.ts +96 -0
  526. package/src/services/voice/live-diarization-session.d.ts.map +1 -0
  527. package/src/services/voice/live-diarization-session.ts +289 -0
  528. package/src/services/voice/mic-source.d.ts +136 -0
  529. package/src/services/voice/mic-source.d.ts.map +1 -0
  530. package/src/services/voice/mic-source.test.ts +210 -0
  531. package/src/services/voice/mic-source.ts +503 -0
  532. package/src/services/voice/optimistic-policy.d.ts +109 -0
  533. package/src/services/voice/optimistic-policy.d.ts.map +1 -0
  534. package/src/services/voice/optimistic-policy.test.ts +101 -0
  535. package/src/services/voice/optimistic-policy.ts +192 -0
  536. package/src/services/voice/optimistic-rollback.ts +343 -0
  537. package/src/services/voice/partial-stabilizer.d.ts +73 -0
  538. package/src/services/voice/partial-stabilizer.d.ts.map +1 -0
  539. package/src/services/voice/partial-stabilizer.test.ts +68 -0
  540. package/src/services/voice/partial-stabilizer.ts +140 -0
  541. package/src/services/voice/phoneme-tokenizer.d.ts +49 -0
  542. package/src/services/voice/phoneme-tokenizer.d.ts.map +1 -0
  543. package/src/services/voice/phoneme-tokenizer.ts +158 -0
  544. package/src/services/voice/phrase-cache.d.ts +76 -0
  545. package/src/services/voice/phrase-cache.d.ts.map +1 -0
  546. package/src/services/voice/phrase-cache.test.ts +242 -0
  547. package/src/services/voice/phrase-cache.ts +186 -0
  548. package/src/services/voice/phrase-chunker.d.ts +62 -0
  549. package/src/services/voice/phrase-chunker.d.ts.map +1 -0
  550. package/src/services/voice/phrase-chunker.test.ts +239 -0
  551. package/src/services/voice/phrase-chunker.ts +281 -0
  552. package/src/services/voice/pipeline-impls.d.ts +151 -0
  553. package/src/services/voice/pipeline-impls.d.ts.map +1 -0
  554. package/src/services/voice/pipeline-impls.l6.test.ts +110 -0
  555. package/src/services/voice/pipeline-impls.test.ts +292 -0
  556. package/src/services/voice/pipeline-impls.ts +315 -0
  557. package/src/services/voice/pipeline.d.ts +216 -0
  558. package/src/services/voice/pipeline.d.ts.map +1 -0
  559. package/src/services/voice/pipeline.ts +505 -0
  560. package/src/services/voice/prefill-client.d.ts +123 -0
  561. package/src/services/voice/prefill-client.d.ts.map +1 -0
  562. package/src/services/voice/prefill-client.ts +316 -0
  563. package/src/services/voice/prefix-preserving-queue.d.ts +113 -0
  564. package/src/services/voice/prefix-preserving-queue.d.ts.map +1 -0
  565. package/src/services/voice/prefix-preserving-queue.ts +162 -0
  566. package/src/services/voice/profile-store.d.ts +248 -0
  567. package/src/services/voice/profile-store.d.ts.map +1 -0
  568. package/src/services/voice/profile-store.ts +887 -0
  569. package/src/services/voice/real-audio-decode.test.ts +148 -0
  570. package/src/services/voice/ring-buffer.d.ts +40 -0
  571. package/src/services/voice/ring-buffer.d.ts.map +1 -0
  572. package/src/services/voice/ring-buffer.test.ts +129 -0
  573. package/src/services/voice/ring-buffer.ts +123 -0
  574. package/src/services/voice/rollback-queue.d.ts +24 -0
  575. package/src/services/voice/rollback-queue.d.ts.map +1 -0
  576. package/src/services/voice/rollback-queue.ts +74 -0
  577. package/src/services/voice/samantha-preset-placeholder.d.ts +67 -0
  578. package/src/services/voice/samantha-preset-placeholder.d.ts.map +1 -0
  579. package/src/services/voice/samantha-preset-placeholder.test.ts +97 -0
  580. package/src/services/voice/samantha-preset-placeholder.ts +148 -0
  581. package/src/services/voice/samantha-preset-regenerator.d.ts +87 -0
  582. package/src/services/voice/samantha-preset-regenerator.d.ts.map +1 -0
  583. package/src/services/voice/samantha-preset-regenerator.ts +393 -0
  584. package/src/services/voice/scheduler.d.ts +146 -0
  585. package/src/services/voice/scheduler.d.ts.map +1 -0
  586. package/src/services/voice/scheduler.t2.test.ts +141 -0
  587. package/src/services/voice/scheduler.ts +927 -0
  588. package/src/services/voice/shared-resources.d.ts +190 -0
  589. package/src/services/voice/shared-resources.d.ts.map +1 -0
  590. package/src/services/voice/shared-resources.ts +320 -0
  591. package/src/services/voice/speaker/attribution-pipeline.d.ts +74 -0
  592. package/src/services/voice/speaker/attribution-pipeline.d.ts.map +1 -0
  593. package/src/services/voice/speaker/attribution-pipeline.ts +386 -0
  594. package/src/services/voice/speaker/diarizer-fused.d.ts +59 -0
  595. package/src/services/voice/speaker/diarizer-fused.d.ts.map +1 -0
  596. package/src/services/voice/speaker/diarizer-fused.real.test.ts +100 -0
  597. package/src/services/voice/speaker/diarizer-fused.ts +154 -0
  598. package/src/services/voice/speaker/diarizer.d.ts +75 -0
  599. package/src/services/voice/speaker/diarizer.d.ts.map +1 -0
  600. package/src/services/voice/speaker/diarizer.ts +218 -0
  601. package/src/services/voice/speaker/encoder-fused.d.ts +60 -0
  602. package/src/services/voice/speaker/encoder-fused.d.ts.map +1 -0
  603. package/src/services/voice/speaker/encoder-fused.real.test.ts +113 -0
  604. package/src/services/voice/speaker/encoder-fused.ts +138 -0
  605. package/src/services/voice/speaker/encoder-ggml.d.ts +33 -0
  606. package/src/services/voice/speaker/encoder-ggml.d.ts.map +1 -0
  607. package/src/services/voice/speaker/encoder-ggml.ts +79 -0
  608. package/src/services/voice/speaker/encoder.d.ts +37 -0
  609. package/src/services/voice/speaker/encoder.d.ts.map +1 -0
  610. package/src/services/voice/speaker/encoder.ts +105 -0
  611. package/src/services/voice/speaker-imprint.d.ts +83 -0
  612. package/src/services/voice/speaker-imprint.d.ts.map +1 -0
  613. package/src/services/voice/speaker-imprint.test.ts +185 -0
  614. package/src/services/voice/speaker-imprint.ts +312 -0
  615. package/src/services/voice/speaker-preset-cache.d.ts +77 -0
  616. package/src/services/voice/speaker-preset-cache.d.ts.map +1 -0
  617. package/src/services/voice/speaker-preset-cache.test.ts +154 -0
  618. package/src/services/voice/speaker-preset-cache.ts +195 -0
  619. package/src/services/voice/streaming-asr/streaming-pipeline-adapter.ts +292 -0
  620. package/src/services/voice/system-audio-sink.d.ts +73 -0
  621. package/src/services/voice/system-audio-sink.d.ts.map +1 -0
  622. package/src/services/voice/system-audio-sink.test.ts +29 -0
  623. package/src/services/voice/system-audio-sink.ts +366 -0
  624. package/src/services/voice/transcriber.d.ts +244 -0
  625. package/src/services/voice/transcriber.d.ts.map +1 -0
  626. package/src/services/voice/transcriber.test.ts +392 -0
  627. package/src/services/voice/transcriber.ts +704 -0
  628. package/src/services/voice/transcript-knowledge.d.ts +37 -0
  629. package/src/services/voice/transcript-knowledge.d.ts.map +1 -0
  630. package/src/services/voice/transcript-knowledge.test.ts +68 -0
  631. package/src/services/voice/transcript-knowledge.ts +75 -0
  632. package/src/services/voice/transcript-service.d.ts +41 -0
  633. package/src/services/voice/transcript-service.d.ts.map +1 -0
  634. package/src/services/voice/transcript-service.test.ts +137 -0
  635. package/src/services/voice/transcript-service.ts +141 -0
  636. package/src/services/voice/transcript-store.d.ts +53 -0
  637. package/src/services/voice/transcript-store.d.ts.map +1 -0
  638. package/src/services/voice/transcript-store.test.ts +153 -0
  639. package/src/services/voice/transcript-store.ts +132 -0
  640. package/src/services/voice/turn-controller.d.ts +183 -0
  641. package/src/services/voice/turn-controller.d.ts.map +1 -0
  642. package/src/services/voice/turn-controller.test.ts +575 -0
  643. package/src/services/voice/turn-controller.ts +596 -0
  644. package/src/services/voice/types.d.ts +643 -0
  645. package/src/services/voice/types.d.ts.map +1 -0
  646. package/src/services/voice/types.ts +699 -0
  647. package/src/services/voice/vad.d.ts +282 -0
  648. package/src/services/voice/vad.d.ts.map +1 -0
  649. package/src/services/voice/vad.test.ts +480 -0
  650. package/src/services/voice/vad.ts +827 -0
  651. package/src/services/voice/vad.v1-v4.test.ts +222 -0
  652. package/src/services/voice/voice-budget.d.ts +241 -0
  653. package/src/services/voice/voice-budget.d.ts.map +1 -0
  654. package/src/services/voice/voice-budget.test.ts +418 -0
  655. package/src/services/voice/voice-budget.ts +635 -0
  656. package/src/services/voice/voice-duet.test.ts +375 -0
  657. package/src/services/voice/voice-emotion-classifier.d.ts +95 -0
  658. package/src/services/voice/voice-emotion-classifier.d.ts.map +1 -0
  659. package/src/services/voice/voice-emotion-classifier.test.ts +210 -0
  660. package/src/services/voice/voice-emotion-classifier.ts +273 -0
  661. package/src/services/voice/voice-preset-format.d.ts +158 -0
  662. package/src/services/voice/voice-preset-format.d.ts.map +1 -0
  663. package/src/services/voice/voice-preset-format.ts +700 -0
  664. package/src/services/voice/voice-preset-generator.test.ts +89 -0
  665. package/src/services/voice/voice-profile-artifact.d.ts +116 -0
  666. package/src/services/voice/voice-profile-artifact.d.ts.map +1 -0
  667. package/src/services/voice/voice-profile-artifact.test.ts +138 -0
  668. package/src/services/voice/voice-profile-artifact.ts +518 -0
  669. package/src/services/voice/voice-profile-routes.d.ts +83 -0
  670. package/src/services/voice/voice-profile-routes.d.ts.map +1 -0
  671. package/src/services/voice/voice-profile-routes.test.ts +429 -0
  672. package/src/services/voice/voice-profile-routes.ts +425 -0
  673. package/src/services/voice/voice-scenario.ts +154 -0
  674. package/src/services/voice/voice-settings.d.ts +82 -0
  675. package/src/services/voice/voice-settings.d.ts.map +1 -0
  676. package/src/services/voice/voice-settings.ts +172 -0
  677. package/src/services/voice/voice-state-machine.d.ts +364 -0
  678. package/src/services/voice/voice-state-machine.d.ts.map +1 -0
  679. package/src/services/voice/voice-state-machine.ts +727 -0
  680. package/src/services/voice/voice-workbench-report.test.ts +168 -0
  681. package/src/services/voice/voice-workbench-report.ts +326 -0
  682. package/src/services/voice/voice-workbench.test.ts +158 -0
  683. package/src/services/voice/voice.test.ts +1070 -0
  684. package/src/services/voice/wake-word-ggml.d.ts +101 -0
  685. package/src/services/voice/wake-word-ggml.d.ts.map +1 -0
  686. package/src/services/voice/wake-word-ggml.ts +320 -0
  687. package/src/services/voice/wake-word.d.ts +255 -0
  688. package/src/services/voice/wake-word.d.ts.map +1 -0
  689. package/src/services/voice/wake-word.test.ts +298 -0
  690. package/src/services/voice/wake-word.ts +554 -0
  691. package/src/services/voice/wrap-with-first-line-cache.d.ts +70 -0
  692. package/src/services/voice/wrap-with-first-line-cache.d.ts.map +1 -0
  693. package/src/services/voice/wrap-with-first-line-cache.ts +267 -0
  694. package/src/services/voice-model-updater.d.ts +240 -0
  695. package/src/services/voice-model-updater.d.ts.map +1 -0
  696. package/src/services/voice-model-updater.ts +724 -0
  697. package/src/services/voice-prewarm.d.ts +3 -0
  698. package/src/services/voice-prewarm.d.ts.map +1 -0
  699. package/src/services/voice-prewarm.ts +51 -0
  700. package/dist/index.d.ts +0 -37
  701. package/dist/index.js +0 -1098
@@ -0,0 +1,195 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import type { SpeakerPreset } from "./types";
4
+ import {
5
+ type RefAudioTokens,
6
+ readVoicePresetFile,
7
+ type VoicePresetSeedPhrase,
8
+ } from "./voice-preset-format";
9
+
10
+ export interface PresetBundlePaths {
11
+ bundleRoot: string;
12
+ /** Relative path to the *default* voice preset inside the bundle. */
13
+ cacheRelPath?: string;
14
+ }
15
+
16
+ export interface LoadedPresetBundle {
17
+ preset: SpeakerPreset;
18
+ /** Phrase-cache seed entries parsed alongside the embedding. The engine
19
+ * bridge feeds these into a `PhraseCache.seed(...)` call before the
20
+ * scheduler is constructed. */
21
+ phrases: ReadonlyArray<VoicePresetSeedPhrase>;
22
+ }
23
+
24
+ export interface SpeakerPresetCacheOptions {
25
+ /**
26
+ * Maximum number of distinct voices held in RAM at once. Speaker presets
27
+ * are KB-scale (an embedding vector + the seed-phrase PCM), so the default
28
+ * is generous; the bound exists so a connector that switches voices per
29
+ * speaker (e.g. a Discord room with many users) does not grow unbounded.
30
+ * On insert past the bound the least-recently-used voice is evicted.
31
+ *
32
+ * Defaults to 8 hot voices (R6 §1: "LRU 8 hot, mmap-backed").
33
+ */
34
+ maxVoices?: number;
35
+ }
36
+
37
+ export const DEFAULT_VOICE_ID = "default";
38
+ const DEFAULT_MAX_VOICES = 8;
39
+
40
+ export const DEFAULT_VOICE_PRESET_REL_PATH = path.join(
41
+ "cache",
42
+ "voice-preset-default.bin",
43
+ );
44
+
45
+ /**
46
+ * Resolve the on-disk path of a voice preset inside a bundle. The default
47
+ * voice lives at `cache/voice-preset-default.bin`; additional voices ship as
48
+ * `cache/voice-preset-<voiceId>.bin`. Throws on a `voiceId` that is not a safe
49
+ * single path segment (no `/`, no `..`).
50
+ */
51
+ export function voicePresetPath(bundleRoot: string, voiceId: string): string {
52
+ if (voiceId === DEFAULT_VOICE_ID) {
53
+ return path.join(bundleRoot, DEFAULT_VOICE_PRESET_REL_PATH);
54
+ }
55
+ if (!/^[A-Za-z0-9._-]+$/.test(voiceId) || voiceId.includes("..")) {
56
+ throw new Error(
57
+ `[voice] Invalid voiceId ${JSON.stringify(voiceId)} — must be a single path-safe segment.`,
58
+ );
59
+ }
60
+ return path.join(bundleRoot, "cache", `voice-preset-${voiceId}.bin`);
61
+ }
62
+
63
+ interface CacheEntry {
64
+ preset: SpeakerPreset;
65
+ phrases: ReadonlyArray<VoicePresetSeedPhrase>;
66
+ }
67
+
68
+ /**
69
+ * LRU cache of parsed speaker presets keyed by `voiceId`. Holds the speaker
70
+ * embedding, the raw preset bytes (for FFI handoff), and the phrase-cache seed
71
+ * list parsed from the preset file. Multi-voice: `load(bundleRoot, voiceId)`
72
+ * reads `cache/voice-preset-<voiceId>.bin` from the bundle on a miss.
73
+ *
74
+ * v2 preset fields (`refAudioTokens`, `refText`, `instruct`) are surfaced
75
+ * on the `SpeakerPreset` shape so the FFI bridge can pass them through to
76
+ * `ov_tts_params` without going through the legacy "instruct == voiceId"
77
+ * misreading.
78
+ */
79
+ export class SpeakerPresetCache {
80
+ // `Map` preserves insertion order; we re-insert on access so the first key
81
+ // is always the least-recently-used.
82
+ private readonly entries = new Map<string, CacheEntry>();
83
+ private readonly maxVoices: number;
84
+
85
+ constructor(opts: SpeakerPresetCacheOptions = {}) {
86
+ this.maxVoices = Math.max(
87
+ 1,
88
+ Math.floor(opts.maxVoices ?? DEFAULT_MAX_VOICES),
89
+ );
90
+ }
91
+
92
+ /**
93
+ * Load the bundle's default voice preset (`cache/voice-preset-default.bin`,
94
+ * or `paths.cacheRelPath` if overridden) and return both the speaker
95
+ * embedding and the phrase-cache seed entries. Cached for subsequent
96
+ * `get("default")` lookups (and marked most-recently-used).
97
+ */
98
+ loadFromBundle(
99
+ paths: PresetBundlePaths,
100
+ voiceId = DEFAULT_VOICE_ID,
101
+ ): LoadedPresetBundle {
102
+ const rel =
103
+ paths.cacheRelPath ??
104
+ (voiceId === DEFAULT_VOICE_ID
105
+ ? DEFAULT_VOICE_PRESET_REL_PATH
106
+ : path.join("cache", `voice-preset-${voiceId}.bin`));
107
+ return this.loadFile(path.join(paths.bundleRoot, rel), voiceId);
108
+ }
109
+
110
+ /**
111
+ * Load an arbitrary voice by id from a bundle root, reading
112
+ * `cache/voice-preset-<voiceId>.bin` (or `cache/voice-preset-default.bin`
113
+ * for `"default"`). Returns the cached entry on a hit (marked MRU).
114
+ */
115
+ load(bundleRoot: string, voiceId: string): LoadedPresetBundle {
116
+ return this.loadFile(voicePresetPath(bundleRoot, voiceId), voiceId);
117
+ }
118
+
119
+ /** True if `voiceId` is currently resident in the cache. */
120
+ has(voiceId: string): boolean {
121
+ return this.entries.has(voiceId);
122
+ }
123
+
124
+ put(preset: SpeakerPreset): void {
125
+ const existing = this.entries.get(preset.voiceId);
126
+ this.entries.delete(preset.voiceId);
127
+ this.entries.set(preset.voiceId, {
128
+ preset,
129
+ phrases: existing?.phrases ?? [],
130
+ });
131
+ this.evictOverflow();
132
+ }
133
+
134
+ get(voiceId: string): SpeakerPreset | undefined {
135
+ const entry = this.entries.get(voiceId);
136
+ if (!entry) return undefined;
137
+ this.entries.delete(voiceId);
138
+ this.entries.set(voiceId, entry);
139
+ return entry.preset;
140
+ }
141
+
142
+ /** Seed entries previously loaded for a voice, if any (does not touch LRU order). */
143
+ getSeed(voiceId: string): ReadonlyArray<VoicePresetSeedPhrase> {
144
+ return this.entries.get(voiceId)?.phrases ?? [];
145
+ }
146
+
147
+ /** Number of voices currently resident. */
148
+ size(): number {
149
+ return this.entries.size;
150
+ }
151
+
152
+ /** Drop every cached preset. */
153
+ clear(): void {
154
+ this.entries.clear();
155
+ }
156
+
157
+ private loadFile(fullPath: string, voiceId: string): LoadedPresetBundle {
158
+ const cached = this.entries.get(voiceId);
159
+ if (cached) {
160
+ this.entries.delete(voiceId);
161
+ this.entries.set(voiceId, cached);
162
+ return { preset: cached.preset, phrases: cached.phrases };
163
+ }
164
+ if (!existsSync(fullPath)) {
165
+ throw new Error(
166
+ `[voice] Speaker preset for voice ${JSON.stringify(voiceId)} not found at ${fullPath}.`,
167
+ );
168
+ }
169
+ const bytes = new Uint8Array(readFileSync(fullPath));
170
+ const parsed = readVoicePresetFile(bytes);
171
+ const refTokens: RefAudioTokens = parsed.refAudioTokens;
172
+ const preset: SpeakerPreset = {
173
+ voiceId,
174
+ embedding: parsed.embedding,
175
+ bytes,
176
+ version: parsed.version,
177
+ refAudioTokens: refTokens,
178
+ refText: parsed.refText,
179
+ instruct: parsed.instruct,
180
+ metadata: parsed.metadata,
181
+ };
182
+ const entry: CacheEntry = { preset, phrases: parsed.phrases };
183
+ this.entries.set(voiceId, entry);
184
+ this.evictOverflow();
185
+ return { preset, phrases: parsed.phrases };
186
+ }
187
+
188
+ private evictOverflow(): void {
189
+ while (this.entries.size > this.maxVoices) {
190
+ const lru = this.entries.keys().next().value;
191
+ if (lru === undefined) return;
192
+ this.entries.delete(lru);
193
+ }
194
+ }
195
+ }
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Streaming-ASR pipeline adapter (item A1 / W7).
3
+ *
4
+ * The base `VoicePipeline` in `voice/pipeline.ts` drives a `StreamingTranscriber`
5
+ * as a batch: it pushes the WHOLE VAD-gated utterance buffer in a single
6
+ * `feed()` call, awaits `flush()`, and only then splits the final transcript
7
+ * into tokens for the drafter/verifier loop. That works for the fused
8
+ * batch decoder, but it leaves the biggest
9
+ * H2 UX seam (incremental partials → planner / barge-in word-confirm /
10
+ * speculative-on-pause) untapped when the fused build is in streaming mode.
11
+ *
12
+ * Rather than rewrite `pipeline.ts` (the Phase 0/1 agent owns it), this
13
+ * module is a small WRAPPER the engine bridge can use to deliver PCM
14
+ * chunks to a `StreamingTranscriber` as they arrive from the mic / VAD,
15
+ * surface every `partial` event to the turn controller via `onPartial`,
16
+ * and only finalize on `speech-end`. Behind a flag — when the fused
17
+ * library advertises `asrStreamSupported() === false` or the flag is off
18
+ * the caller keeps using `VoicePipeline.transcribeAll` exactly as today.
19
+ *
20
+ * Integration point (documented for the Phase 0/1 agent so they can wire
21
+ * it without merge friction):
22
+ *
23
+ * 1. `EngineVoiceBridge` decides whether streaming is available via
24
+ * `pickStreamingMode({ ffi, asrBundlePresent, flag })`. When the
25
+ * mode is `"streaming"`, the bridge constructs `StreamingAsrFeeder`
26
+ * once per turn (passing the same transcriber that would have been
27
+ * handed to `VoicePipeline`) and routes mic PCM frames through
28
+ * `feeder.feedFrame(frame)` instead of buffering them.
29
+ * 2. The feeder forwards every transcriber `partial` event to
30
+ * `onPartial(update)`. When VAD reports `speech-end` the caller
31
+ * calls `await feeder.finalize()`; the returned `TranscriptUpdate`
32
+ * is the final and is used to seed the drafter/verifier loop exactly
33
+ * as before (`splitTranscriptToTokens(final.partial, 0, final.tokens)`).
34
+ * 3. The batch path (`VoicePipeline.transcribeAll`) is unchanged for
35
+ * every other adapter — there is no fork in `pipeline.ts` itself.
36
+ *
37
+ * This file is intentionally small and side-effect-free so it can land
38
+ * during the merge window without touching files other agents own.
39
+ */
40
+
41
+ import { splitTranscriptToTokens } from "../pipeline";
42
+ import type {
43
+ PcmFrame,
44
+ StreamingTranscriber,
45
+ TextToken,
46
+ TranscriptUpdate,
47
+ } from "../types";
48
+
49
+ /* ==================================================================== *
50
+ * LocalAgreementBuffer — word-level streaming-ASR partial stabilizer.
51
+ *
52
+ * Streaming ASR emits a fresh word-sequence hypothesis on every audio
53
+ * frame. Individual words near the end of the hypothesis can change
54
+ * across frames ("sat" → "cap" → "sat") before settling. This buffer
55
+ * applies LocalAgreement-n (n=2 default) at the word level: a word is
56
+ * emitted to downstream only when it appears at the same position in n
57
+ * consecutive hypotheses. The committed stable prefix is monotonically
58
+ * non-decreasing — once a word is committed it is never retracted.
59
+ *
60
+ * Word-level (not character-level): suited for the VAD pipeline adapter
61
+ * where downstream consumers (drafter, verifier) operate on word tokens.
62
+ * For the character-level prefix variant, see `partial-stabilizer.ts`.
63
+ * ==================================================================== */
64
+
65
+ /**
66
+ * LocalAgreement-n word-level partial stabilizer.
67
+ *
68
+ * Usage:
69
+ * const buf = new LocalAgreementBuffer();
70
+ * const stable = buf.stable(["hello", "there", "world"]);
71
+ * // → [] on first call (need n=2 consecutive identical prefix)
72
+ * const stable2 = buf.stable(["hello", "there", "how"]);
73
+ * // → ["hello", "there"] (matched across two consecutive hypotheses)
74
+ */
75
+ export class LocalAgreementBuffer {
76
+ private readonly n: number;
77
+ /** Rolling window of the last `n` hypotheses, oldest first. */
78
+ private window: string[][] = [];
79
+ /** Monotonically growing committed word list. */
80
+ private committed: string[] = [];
81
+
82
+ constructor(n = 2) {
83
+ if (!Number.isFinite(n) || n < 1) {
84
+ throw new Error(
85
+ `[LocalAgreementBuffer] n must be a finite integer >= 1; got ${String(n)}`,
86
+ );
87
+ }
88
+ this.n = Math.floor(n);
89
+ }
90
+
91
+ /**
92
+ * Feed the latest word-level hypothesis. Returns the stable committed
93
+ * prefix — the longest leading word sequence that has appeared
94
+ * identically in `n` consecutive calls. Monotonically non-decreasing.
95
+ *
96
+ * A rolling window of the last `n` hypotheses is maintained. Once the
97
+ * window is full, the agreed prefix is the intersection across all `n`
98
+ * entries — word i is in the agreed prefix only if it is identical in
99
+ * every hypothesis in the window.
100
+ */
101
+ stable(current: string[]): string[] {
102
+ this.window.push(current);
103
+ if (this.window.length > this.n) {
104
+ this.window.shift();
105
+ }
106
+ // Need a full window of `n` hypotheses before any word can be agreed.
107
+ if (this.window.length < this.n) {
108
+ return this.committed;
109
+ }
110
+ // Intersect: the agreed prefix is the longest common leading prefix
111
+ // across all entries in the window.
112
+ const first = this.window[0];
113
+ if (!first) {
114
+ throw new Error("hypothesis window unexpectedly empty");
115
+ }
116
+ let agreedLen = first.length;
117
+ for (let i = 1; i < this.window.length; i++) {
118
+ const h = this.window[i];
119
+ if (!h) {
120
+ throw new Error(`missing hypothesis at index ${i}`);
121
+ }
122
+ let matchLen = 0;
123
+ const limit = Math.min(agreedLen, h.length);
124
+ for (let j = 0; j < limit; j++) {
125
+ if (first[j] === h[j]) matchLen++;
126
+ else break;
127
+ }
128
+ agreedLen = matchLen;
129
+ if (agreedLen === 0) break;
130
+ }
131
+ // Extend committed if the new agreement is longer.
132
+ if (agreedLen > this.committed.length) {
133
+ this.committed = first.slice(0, agreedLen);
134
+ }
135
+ return this.committed;
136
+ }
137
+
138
+ /** Clear all state. Call at utterance boundaries. */
139
+ reset(): void {
140
+ this.window = [];
141
+ this.committed = [];
142
+ }
143
+
144
+ /** The current committed stable word list (read-only view). */
145
+ getCommitted(): string[] {
146
+ return this.committed;
147
+ }
148
+ }
149
+
150
+ /** Available transcription drive modes. */
151
+ export type StreamingPipelineMode = "streaming" | "batch";
152
+
153
+ export interface PickStreamingModeArgs {
154
+ /** True only when the loaded fused library advertises a working streaming decoder. */
155
+ ffiSupportsStreaming: boolean;
156
+ /** True only when the bundled ASR model is present on disk. */
157
+ asrBundlePresent: boolean;
158
+ /**
159
+ * Feature flag — defaults to FALSE so the streaming path stays opt-in
160
+ * until the Phase 0/1 partial-stabilizer wiring lands. Once that lands
161
+ * the engine bridge flips this default to true.
162
+ */
163
+ enableStreaming: boolean;
164
+ }
165
+
166
+ /**
167
+ * Choose the transcription drive mode. Streaming is selected only when:
168
+ * - the loaded fused library advertises a working streaming decoder
169
+ * (`asr_stream_supported() === 1`), AND
170
+ * - the bundled ASR model is present, AND
171
+ * - the engine bridge has opted in via `enableStreaming`.
172
+ *
173
+ * Any other combination falls back to the existing batch path
174
+ * (`VoicePipeline.transcribeAll`).
175
+ */
176
+ export function pickStreamingMode(
177
+ args: PickStreamingModeArgs,
178
+ ): StreamingPipelineMode {
179
+ if (!args.enableStreaming) return "batch";
180
+ if (!args.ffiSupportsStreaming) return "batch";
181
+ if (!args.asrBundlePresent) return "batch";
182
+ return "streaming";
183
+ }
184
+
185
+ export interface StreamingAsrFeederEvents {
186
+ /**
187
+ * Called for every transcriber `partial` event the feeder observes
188
+ * BEFORE the segment is finalized. Includes the running `partial`
189
+ * text, `isFinal: false`, and (when the fused build supplied them)
190
+ * the shared text-model token ids.
191
+ */
192
+ onPartial?(update: TranscriptUpdate): void;
193
+ /**
194
+ * Called the first time ≥1 real word is recognized in the segment.
195
+ * Wired into the turn controller's word-confirm gate so the agent
196
+ * only barge-in-cancels on real speech, not blips.
197
+ */
198
+ onWords?(words: ReadonlyArray<string>): void;
199
+ /**
200
+ * Called once, after `finalize()` returns, with the final transcript
201
+ * split into contiguous text tokens (`splitTranscriptToTokens`). The
202
+ * batch path delivers the same shape via `transcribeAll`, so the
203
+ * downstream drafter/verifier loop sees an identical signal.
204
+ */
205
+ onFinalTokens?(
206
+ tokens: ReadonlyArray<TextToken>,
207
+ final: TranscriptUpdate,
208
+ ): void;
209
+ }
210
+
211
+ /**
212
+ * Drives a `StreamingTranscriber` chunk-by-chunk on behalf of the engine
213
+ * bridge / turn controller. One instance per active speech segment;
214
+ * `finalize()` returns the final transcript and the feeder is disposed.
215
+ *
216
+ * Construction takes a `StreamingTranscriber` (already constructed via
217
+ * `createStreamingTranscriber` with the same options used for batch).
218
+ * The feeder does NOT own the transcriber's lifecycle — disposal still
219
+ * runs through the engine bridge so the same path is used when the
220
+ * batch fallback is taken.
221
+ */
222
+ export class StreamingAsrFeeder {
223
+ private readonly transcriber: StreamingTranscriber;
224
+ private readonly events: StreamingAsrFeederEvents;
225
+ private latestPartial: TranscriptUpdate | null = null;
226
+ private finalized = false;
227
+ private unsubscribe: (() => void) | null = null;
228
+
229
+ constructor(args: {
230
+ transcriber: StreamingTranscriber;
231
+ events?: StreamingAsrFeederEvents;
232
+ }) {
233
+ this.transcriber = args.transcriber;
234
+ this.events = args.events ?? {};
235
+ this.unsubscribe = this.transcriber.on((event) => {
236
+ switch (event.kind) {
237
+ case "partial":
238
+ this.latestPartial = event.update;
239
+ this.events.onPartial?.(event.update);
240
+ break;
241
+ case "words":
242
+ this.events.onWords?.(event.words);
243
+ break;
244
+ case "final":
245
+ // Final events are surfaced via `finalize()`'s return value so
246
+ // the caller has a single point of truth. We do not re-emit
247
+ // them here.
248
+ break;
249
+ }
250
+ });
251
+ }
252
+
253
+ /**
254
+ * Feed one PCM frame as it arrives from the mic / connector. Drops
255
+ * frames received after `finalize()` (the segment is over).
256
+ */
257
+ feedFrame(frame: PcmFrame): void {
258
+ if (this.finalized) return;
259
+ this.transcriber.feed(frame);
260
+ }
261
+
262
+ /**
263
+ * Force-finalize on `speech-end`. Resolves with the final transcript
264
+ * and emits `onFinalTokens` so the caller can seed the drafter /
265
+ * verifier loop without re-running the surface split itself.
266
+ *
267
+ * Calling `finalize()` twice is a hard error — the segment is over.
268
+ */
269
+ async finalize(): Promise<TranscriptUpdate> {
270
+ if (this.finalized) {
271
+ throw new Error(
272
+ "[streaming-asr] finalize() called twice on the same feeder",
273
+ );
274
+ }
275
+ this.finalized = true;
276
+ const final = await this.transcriber.flush();
277
+ const tokens = splitTranscriptToTokens(final.partial, 0, final.tokens);
278
+ this.events.onFinalTokens?.(tokens, final);
279
+ return final;
280
+ }
281
+
282
+ /** The most recent `partial` snapshot observed, or `null` until the first decode lands. */
283
+ getLatestPartial(): TranscriptUpdate | null {
284
+ return this.latestPartial;
285
+ }
286
+
287
+ /** Detach the transcriber subscription. Does NOT dispose the transcriber itself. */
288
+ dispose(): void {
289
+ this.unsubscribe?.();
290
+ this.unsubscribe = null;
291
+ }
292
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * System audio sinks for the interactive voice harness.
3
+ *
4
+ * The voice scheduler writes synthesized PCM (`Float32Array` mono in
5
+ * [-1, 1] at the bridge sample rate) into an {@link AudioSink}. For tests
6
+ * and headless runs `InMemoryAudioSink` (in `./ring-buffer`) captures the
7
+ * samples; for an interactive session the harness needs the audio to
8
+ * actually come out of the speakers.
9
+ *
10
+ * `SystemAudioSink` shells out to a long-lived player that reads raw 16-bit
11
+ * signed-LE PCM on stdin. Per-platform selection (priority order):
12
+ * - Linux: `aplay` (alsa-utils), else `paplay` (PulseAudio), else
13
+ * `play`/`sox` (sox), else `ffplay` (ffmpeg).
14
+ * - macOS: `play`/`sox` (sox), else `ffplay` (ffmpeg). `afplay` needs a
15
+ * file (no stdin) so it cannot be used for streaming.
16
+ * - Windows: `ffplay` (ffmpeg), else `play`/`sox` if installed. PowerShell's
17
+ * `Media.SoundPlayer` also needs a file, not a stream, so it's not
18
+ * used here — the renderer's `AudioContext` path (feeding nothing
19
+ * here; the renderer plays directly) is the no-ffmpeg route.
20
+ * If no player is on `PATH`, `available()` returns false and the harness
21
+ * falls back to `WavFileAudioSink` (writes a rolling WAV) — never silence.
22
+ *
23
+ * `WavFileAudioSink` accumulates everything written and serializes a
24
+ * single mono PCM16 WAV on `finalize()` — used by `--no-audio` and as the
25
+ * no-player fallback.
26
+ */
27
+ import type { AudioSink } from "./types";
28
+ /**
29
+ * Exported view of {@link resolvePlayer} for the cross-platform preflight
30
+ * (`voice:interactive --platform-report`). Returns the bare program name
31
+ * (no args) the host would stream synthesized audio to, or `null`.
32
+ */
33
+ export declare function resolveSystemPlayerName(sampleRate?: number): string | null;
34
+ export interface SystemAudioSinkOptions {
35
+ sampleRate: number;
36
+ }
37
+ export declare class SystemAudioSink implements AudioSink {
38
+ private readonly sampleRate;
39
+ private readonly playerSpec;
40
+ private proc;
41
+ private buffered;
42
+ constructor(opts: SystemAudioSinkOptions);
43
+ available(): boolean;
44
+ player(): string;
45
+ private ensureProc;
46
+ write(pcm: Float32Array, _sampleRate: number): void;
47
+ drain(): void;
48
+ bufferedSamples(): number;
49
+ /** Flush + close the player. Idempotent. */
50
+ dispose(): Promise<void>;
51
+ }
52
+ export interface WavFileAudioSinkOptions {
53
+ sampleRate: number;
54
+ filePath: string;
55
+ }
56
+ /**
57
+ * Accumulates all written PCM and serializes a single mono PCM16 WAV on
58
+ * {@link finalize}. Used by `--no-audio` and as the no-player fallback so
59
+ * a headless run still produces an inspectable artifact (never silence).
60
+ */
61
+ export declare class WavFileAudioSink implements AudioSink {
62
+ private readonly sampleRate;
63
+ private readonly filePath;
64
+ private readonly chunks;
65
+ private buffered;
66
+ constructor(opts: WavFileAudioSinkOptions);
67
+ write(pcm: Float32Array, _sampleRate: number): void;
68
+ drain(): void;
69
+ bufferedSamples(): number;
70
+ totalSamples(): number;
71
+ finalize(): Promise<string>;
72
+ }
73
+ //# sourceMappingURL=system-audio-sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-audio-sink.d.ts","sourceRoot":"","sources":["system-audio-sink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAQH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAoIzC;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,SAAS,GAAG,MAAM,GAAG,IAAI,CAG1E;AAED,MAAM,WAAW,sBAAsB;IACtC,UAAU,EAAE,MAAM,CAAC;CACnB;AAWD,qBAAa,eAAgB,YAAW,SAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyC;IACpE,OAAO,CAAC,IAAI,CAAiC;IAC7C,OAAO,CAAC,QAAQ,CAAK;gBAET,IAAI,EAAE,sBAAsB;IAKxC,SAAS,IAAI,OAAO;IAIpB,MAAM,IAAI,MAAM;IAIhB,OAAO,CAAC,UAAU;IAmBlB,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAUnD,KAAK,IAAI,IAAI;IAmBb,eAAe,IAAI,MAAM;IAIzB,4CAA4C;IACtC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA6B9B;AAED,MAAM,WAAW,uBAAuB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,SAAS;IACjD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAK;gBAET,IAAI,EAAE,uBAAuB;IAKzC,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAKnD,KAAK,IAAI,IAAI;IAMb,eAAe,IAAI,MAAM;IAIzB,YAAY,IAAI,MAAM;IAMhB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;CAgCjC"}
@@ -0,0 +1,29 @@
1
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import path from "node:path";
4
+ import { describe, expect, it } from "vitest";
5
+ import { WavFileAudioSink } from "./system-audio-sink";
6
+
7
+ describe("WavFileAudioSink", () => {
8
+ it("drain resets buffered samples without dropping artifact chunks", async () => {
9
+ const dir = mkdtempSync(path.join(tmpdir(), "eliza-audio-sink-"));
10
+ const filePath = path.join(dir, "out.wav");
11
+ try {
12
+ const sink = new WavFileAudioSink({ sampleRate: 24_000, filePath });
13
+ sink.write(new Float32Array([0.1, 0.2, 0.3]), 24_000);
14
+ expect(sink.bufferedSamples()).toBe(3);
15
+
16
+ sink.drain();
17
+ expect(sink.bufferedSamples()).toBe(0);
18
+ await sink.finalize();
19
+
20
+ const wav = readFileSync(filePath);
21
+ expect(wav.subarray(0, 4).toString("ascii")).toBe("RIFF");
22
+ expect(wav.subarray(8, 12).toString("ascii")).toBe("WAVE");
23
+ expect(wav.readUInt32LE(40)).toBe(6);
24
+ expect(wav.length).toBe(50);
25
+ } finally {
26
+ rmSync(dir, { recursive: true, force: true });
27
+ }
28
+ });
29
+ });