@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.
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/package.json +82 -15
- package/src/actions/generate-media.d.ts +59 -0
- package/src/actions/generate-media.d.ts.map +1 -0
- package/src/actions/generate-media.ts +647 -0
- package/src/actions/identify-speaker.d.ts +23 -0
- package/src/actions/identify-speaker.d.ts.map +1 -0
- package/src/actions/identify-speaker.ts +171 -0
- package/src/actions/transcription-control.d.ts +29 -0
- package/src/actions/transcription-control.d.ts.map +1 -0
- package/src/actions/transcription-control.test.ts +100 -0
- package/src/actions/transcription-control.ts +127 -0
- package/src/adapters/capacitor-llama/__tests__/compat-behavior.test.ts +218 -0
- package/src/adapters/capacitor-llama/__tests__/index.test.ts +68 -0
- package/src/adapters/capacitor-llama/__tests__/structured-output.test.ts +215 -0
- package/src/adapters/capacitor-llama/__tests__/text-streaming.test.ts +174 -0
- package/src/adapters/capacitor-llama/environment.ts +71 -0
- package/src/adapters/capacitor-llama/index.browser.ts +83 -0
- package/src/adapters/capacitor-llama/index.ts +807 -0
- package/src/adapters/capacitor-llama/loader.ts +109 -0
- package/src/adapters/capacitor-llama/structured-output.ts +165 -0
- package/src/adapters/capacitor-llama/text-streaming.ts +227 -0
- package/src/adapters/capacitor-llama/types.ts +374 -0
- package/src/backends/apple-foundation.ts +127 -0
- package/src/index.d.ts +8 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.ts +62 -0
- package/src/local-inference-routes.d.ts +38 -0
- package/src/local-inference-routes.d.ts.map +1 -0
- package/src/local-inference-routes.test.ts +344 -0
- package/src/local-inference-routes.ts +1543 -0
- package/src/provider.d.ts +21 -0
- package/src/provider.d.ts.map +1 -0
- package/src/provider.ts +1082 -0
- package/src/routes/compat-helpers.d.ts +18 -0
- package/src/routes/compat-helpers.d.ts.map +1 -0
- package/src/routes/compat-helpers.ts +274 -0
- package/src/routes/family-member-route.d.ts +62 -0
- package/src/routes/family-member-route.d.ts.map +1 -0
- package/src/routes/family-member-route.ts +353 -0
- package/src/routes/index.d.ts +19 -0
- package/src/routes/index.d.ts.map +1 -0
- package/src/routes/index.ts +60 -0
- package/src/routes/live-diarization-route.d.ts +26 -0
- package/src/routes/live-diarization-route.d.ts.map +1 -0
- package/src/routes/live-diarization-route.test.ts +213 -0
- package/src/routes/live-diarization-route.ts +122 -0
- package/src/routes/local-inference-asr-route.d.ts +4 -0
- package/src/routes/local-inference-asr-route.d.ts.map +1 -0
- package/src/routes/local-inference-asr-route.test.ts +205 -0
- package/src/routes/local-inference-asr-route.ts +163 -0
- package/src/routes/local-inference-asr-transcribe.d.ts +20 -0
- package/src/routes/local-inference-asr-transcribe.d.ts.map +1 -0
- package/src/routes/local-inference-asr-transcribe.test.ts +118 -0
- package/src/routes/local-inference-asr-transcribe.ts +97 -0
- package/src/routes/local-inference-compat-routes.d.ts +16 -0
- package/src/routes/local-inference-compat-routes.d.ts.map +1 -0
- package/src/routes/local-inference-compat-routes.test.ts +485 -0
- package/src/routes/local-inference-compat-routes.ts +808 -0
- package/src/routes/local-inference-tts-route.d.ts +7 -0
- package/src/routes/local-inference-tts-route.d.ts.map +1 -0
- package/src/routes/local-inference-tts-route.test.ts +179 -0
- package/src/routes/local-inference-tts-route.ts +230 -0
- package/src/routes/transcript-audio-store.d.ts +15 -0
- package/src/routes/transcript-audio-store.d.ts.map +1 -0
- package/src/routes/transcript-audio-store.ts +27 -0
- package/src/routes/transcripts-routes.d.ts +36 -0
- package/src/routes/transcripts-routes.d.ts.map +1 -0
- package/src/routes/transcripts-routes.test.ts +144 -0
- package/src/routes/transcripts-routes.ts +159 -0
- package/src/routes/voice-first-run-routes.d.ts +62 -0
- package/src/routes/voice-first-run-routes.d.ts.map +1 -0
- package/src/routes/voice-first-run-routes.ts +524 -0
- package/src/routes/voice-models-routes.d.ts +62 -0
- package/src/routes/voice-models-routes.d.ts.map +1 -0
- package/src/routes/voice-models-routes.ts +554 -0
- package/src/routes/voice-profile-plugin-routes.d.ts +19 -0
- package/src/routes/voice-profile-plugin-routes.d.ts.map +1 -0
- package/src/routes/voice-profile-plugin-routes.ts +138 -0
- package/src/routes/voice-profiles-management-routes.d.ts +52 -0
- package/src/routes/voice-profiles-management-routes.d.ts.map +1 -0
- package/src/routes/voice-profiles-management-routes.ts +476 -0
- package/src/routes/voice-speaker-profile-routes.d.ts +57 -0
- package/src/routes/voice-speaker-profile-routes.d.ts.map +1 -0
- package/src/routes/voice-speaker-profile-routes.ts +199 -0
- package/src/runtime/aosp-llama-loader-selection.test.ts +80 -0
- package/src/runtime/capacitor-llama.d.ts +25 -0
- package/src/runtime/embedding-manager-support.d.ts +77 -0
- package/src/runtime/embedding-manager-support.d.ts.map +1 -0
- package/src/runtime/embedding-manager-support.ts +497 -0
- package/src/runtime/embedding-presets.d.ts +16 -0
- package/src/runtime/embedding-presets.d.ts.map +1 -0
- package/src/runtime/embedding-presets.ts +81 -0
- package/src/runtime/embedding-warmup-policy.d.ts +14 -0
- package/src/runtime/embedding-warmup-policy.d.ts.map +1 -0
- package/src/runtime/embedding-warmup-policy.test.ts +53 -0
- package/src/runtime/embedding-warmup-policy.ts +48 -0
- package/src/runtime/ensure-local-inference-handler.d.ts +62 -0
- package/src/runtime/ensure-local-inference-handler.d.ts.map +1 -0
- package/src/runtime/ensure-local-inference-handler.test.ts +528 -0
- package/src/runtime/ensure-local-inference-handler.ts +1448 -0
- package/src/runtime/index.d.ts +15 -0
- package/src/runtime/index.d.ts.map +1 -0
- package/src/runtime/index.ts +33 -0
- package/src/runtime/mobile-local-inference-gate.d.ts +31 -0
- package/src/runtime/mobile-local-inference-gate.d.ts.map +1 -0
- package/src/runtime/mobile-local-inference-gate.test.ts +69 -0
- package/src/runtime/mobile-local-inference-gate.ts +44 -0
- package/src/runtime/voice-entity-binding.d.ts +103 -0
- package/src/runtime/voice-entity-binding.d.ts.map +1 -0
- package/src/runtime/voice-entity-binding.transcript.test.ts +69 -0
- package/src/runtime/voice-entity-binding.ts +328 -0
- package/src/services/README.md +71 -0
- package/src/services/__tests__/backend-selector.test.ts +101 -0
- package/src/services/__tests__/checkpoint-manager.test.ts +376 -0
- package/src/services/__tests__/gpu-autotune.test.ts +400 -0
- package/src/services/__tests__/llm-streaming-binding.test.ts +85 -0
- package/src/services/__tests__/planner-grammar.test.ts +372 -0
- package/src/services/__tests__/runtime-target.test.ts +176 -0
- package/src/services/active-model-switch-rollback.test.ts +183 -0
- package/src/services/active-model.d.ts +282 -0
- package/src/services/active-model.d.ts.map +1 -0
- package/src/services/active-model.ts +1213 -0
- package/src/services/assignments.d.ts +71 -0
- package/src/services/assignments.d.ts.map +1 -0
- package/src/services/assignments.test.ts +80 -0
- package/src/services/assignments.ts +230 -0
- package/src/services/backend-selector.ts +95 -0
- package/src/services/backend.d.ts +346 -0
- package/src/services/backend.d.ts.map +1 -0
- package/src/services/backend.ts +612 -0
- package/src/services/bionic-host-loader.d.ts +46 -0
- package/src/services/bionic-host-loader.d.ts.map +1 -0
- package/src/services/bionic-host-loader.test.ts +133 -0
- package/src/services/bionic-host-loader.ts +180 -0
- package/src/services/bundled-models.d.ts +34 -0
- package/src/services/bundled-models.d.ts.map +1 -0
- package/src/services/bundled-models.ts +129 -0
- package/src/services/cache-bridge.d.ts +206 -0
- package/src/services/cache-bridge.d.ts.map +1 -0
- package/src/services/cache-bridge.test.ts +516 -0
- package/src/services/cache-bridge.ts +423 -0
- package/src/services/catalog.d.ts +10 -0
- package/src/services/catalog.d.ts.map +1 -0
- package/src/services/catalog.test.ts +238 -0
- package/src/services/catalog.ts +27 -0
- package/src/services/checkpoint-client.d.ts +109 -0
- package/src/services/checkpoint-client.d.ts.map +1 -0
- package/src/services/checkpoint-client.ts +258 -0
- package/src/services/checkpoint-manager.ts +474 -0
- package/src/services/cloud-fallback.d.ts +102 -0
- package/src/services/cloud-fallback.d.ts.map +1 -0
- package/src/services/cloud-fallback.ts +230 -0
- package/src/services/conversation-registry.d.ts +142 -0
- package/src/services/conversation-registry.d.ts.map +1 -0
- package/src/services/conversation-registry.test.ts +235 -0
- package/src/services/conversation-registry.ts +264 -0
- package/src/services/desktop-fused-ffi-backend-runtime.d.ts +95 -0
- package/src/services/desktop-fused-ffi-backend-runtime.d.ts.map +1 -0
- package/src/services/desktop-fused-ffi-backend-runtime.ts +339 -0
- package/src/services/device-bridge.d.ts +188 -0
- package/src/services/device-bridge.d.ts.map +1 -0
- package/src/services/device-bridge.ts +1237 -0
- package/src/services/device-resource-metrics.d.ts +149 -0
- package/src/services/device-resource-metrics.d.ts.map +1 -0
- package/src/services/device-resource-metrics.test.ts +98 -0
- package/src/services/device-resource-metrics.ts +346 -0
- package/src/services/device-tier.d.ts +115 -0
- package/src/services/device-tier.d.ts.map +1 -0
- package/src/services/device-tier.test.ts +371 -0
- package/src/services/device-tier.ts +410 -0
- package/src/services/downloader.d.ts +82 -0
- package/src/services/downloader.d.ts.map +1 -0
- package/src/services/downloader.test.ts +747 -0
- package/src/services/downloader.ts +925 -0
- package/src/services/engine-direct-bundle.test.ts +58 -0
- package/src/services/engine-streaming.test.ts +80 -0
- package/src/services/engine.d.ts +540 -0
- package/src/services/engine.d.ts.map +1 -0
- package/src/services/engine.ts +1909 -0
- package/src/services/ensure-local-artifacts.integration.test.ts +273 -0
- package/src/services/ensure-local-artifacts.test.ts +368 -0
- package/src/services/ensure-local-artifacts.ts +351 -0
- package/src/services/external-scanner.d.ts +17 -0
- package/src/services/external-scanner.d.ts.map +1 -0
- package/src/services/external-scanner.ts +312 -0
- package/src/services/ffi-llm-mock.ts +354 -0
- package/src/services/ffi-llm-streaming-abi.ts +442 -0
- package/src/services/ffi-streaming-backend.d.ts +180 -0
- package/src/services/ffi-streaming-backend.d.ts.map +1 -0
- package/src/services/ffi-streaming-backend.ts +382 -0
- package/src/services/ffi-streaming-runner.d.ts +122 -0
- package/src/services/ffi-streaming-runner.d.ts.map +1 -0
- package/src/services/ffi-streaming-runner.test.ts +60 -0
- package/src/services/ffi-streaming-runner.ts +354 -0
- package/src/services/ffi-unload-ordering.test.ts +162 -0
- package/src/services/gpu-autotune.ts +534 -0
- package/src/services/gpu-detect.d.ts +56 -0
- package/src/services/gpu-detect.d.ts.map +1 -0
- package/src/services/gpu-detect.ts +139 -0
- package/src/services/handler-registry.d.ts +72 -0
- package/src/services/handler-registry.d.ts.map +1 -0
- package/src/services/handler-registry.ts +240 -0
- package/src/services/hardware.d.ts +63 -0
- package/src/services/hardware.d.ts.map +1 -0
- package/src/services/hardware.test.ts +231 -0
- package/src/services/hardware.ts +410 -0
- package/src/services/hf-search.d.ts +26 -0
- package/src/services/hf-search.d.ts.map +1 -0
- package/src/services/hf-search.test.ts +69 -0
- package/src/services/hf-search.ts +420 -0
- package/src/services/image-description-runtime.d.ts +14 -0
- package/src/services/image-description-runtime.d.ts.map +1 -0
- package/src/services/image-description-runtime.test.ts +61 -0
- package/src/services/image-description-runtime.ts +118 -0
- package/src/services/imagegen/aosp-unavailable.d.ts +134 -0
- package/src/services/imagegen/aosp-unavailable.d.ts.map +1 -0
- package/src/services/imagegen/aosp-unavailable.ts +229 -0
- package/src/services/imagegen/backend-selector.d.ts +118 -0
- package/src/services/imagegen/backend-selector.d.ts.map +1 -0
- package/src/services/imagegen/backend-selector.ts +277 -0
- package/src/services/imagegen/coreml-unavailable.d.ts +105 -0
- package/src/services/imagegen/coreml-unavailable.d.ts.map +1 -0
- package/src/services/imagegen/coreml-unavailable.ts +237 -0
- package/src/services/imagegen/errors.d.ts +16 -0
- package/src/services/imagegen/errors.d.ts.map +1 -0
- package/src/services/imagegen/errors.ts +40 -0
- package/src/services/imagegen/index.d.ts +58 -0
- package/src/services/imagegen/index.d.ts.map +1 -0
- package/src/services/imagegen/index.ts +144 -0
- package/src/services/imagegen/mflux.d.ts +74 -0
- package/src/services/imagegen/mflux.d.ts.map +1 -0
- package/src/services/imagegen/mflux.ts +313 -0
- package/src/services/imagegen/sd-cpp.d.ts +180 -0
- package/src/services/imagegen/sd-cpp.d.ts.map +1 -0
- package/src/services/imagegen/sd-cpp.ts +718 -0
- package/src/services/imagegen/tensorrt-unavailable.d.ts +83 -0
- package/src/services/imagegen/tensorrt-unavailable.d.ts.map +1 -0
- package/src/services/imagegen/tensorrt-unavailable.ts +295 -0
- package/src/services/imagegen/types.d.ts +181 -0
- package/src/services/imagegen/types.d.ts.map +1 -0
- package/src/services/imagegen/types.ts +193 -0
- package/src/services/index.d.ts +29 -0
- package/src/services/index.d.ts.map +1 -0
- package/src/services/index.ts +211 -0
- package/src/services/inference-capabilities.d.ts +132 -0
- package/src/services/inference-capabilities.d.ts.map +1 -0
- package/src/services/inference-capabilities.test.ts +75 -0
- package/src/services/inference-capabilities.ts +204 -0
- package/src/services/inference-telemetry.d.ts +59 -0
- package/src/services/inference-telemetry.d.ts.map +1 -0
- package/src/services/inference-telemetry.ts +143 -0
- package/src/services/ios-llama-streaming.ts +248 -0
- package/src/services/kv-spill.d.ts +189 -0
- package/src/services/kv-spill.d.ts.map +1 -0
- package/src/services/kv-spill.test.ts +222 -0
- package/src/services/kv-spill.ts +356 -0
- package/src/services/latency-trace.d.ts +346 -0
- package/src/services/latency-trace.d.ts.map +1 -0
- package/src/services/latency-trace.test.ts +266 -0
- package/src/services/latency-trace.ts +844 -0
- package/src/services/llama-server-metrics.ts +304 -0
- package/src/services/llm-streaming-binding.d.ts +96 -0
- package/src/services/llm-streaming-binding.d.ts.map +1 -0
- package/src/services/llm-streaming-binding.ts +136 -0
- package/src/services/load-args.d.ts +82 -0
- package/src/services/load-args.d.ts.map +1 -0
- package/src/services/load-args.ts +81 -0
- package/src/services/manifest/eliza-1.manifest.v1.json +708 -0
- package/src/services/manifest/index.d.ts +4 -0
- package/src/services/manifest/index.d.ts.map +1 -0
- package/src/services/manifest/index.ts +66 -0
- package/src/services/manifest/manifest.test.ts +689 -0
- package/src/services/manifest/schema.d.ts +713 -0
- package/src/services/manifest/schema.d.ts.map +1 -0
- package/src/services/manifest/schema.ts +653 -0
- package/src/services/manifest/types.d.ts +30 -0
- package/src/services/manifest/types.d.ts.map +1 -0
- package/src/services/manifest/types.ts +55 -0
- package/src/services/manifest/validator.d.ts +66 -0
- package/src/services/manifest/validator.d.ts.map +1 -0
- package/src/services/manifest/validator.ts +567 -0
- package/src/services/memory-arbiter.d.ts +318 -0
- package/src/services/memory-arbiter.d.ts.map +1 -0
- package/src/services/memory-arbiter.test.ts +419 -0
- package/src/services/memory-arbiter.ts +925 -0
- package/src/services/memory-monitor.d.ts +122 -0
- package/src/services/memory-monitor.d.ts.map +1 -0
- package/src/services/memory-monitor.test.ts +208 -0
- package/src/services/memory-monitor.ts +297 -0
- package/src/services/memory-pressure.d.ts +130 -0
- package/src/services/memory-pressure.d.ts.map +1 -0
- package/src/services/memory-pressure.ts +414 -0
- package/src/services/mtp-doctor.d.ts +13 -0
- package/src/services/mtp-doctor.d.ts.map +1 -0
- package/src/services/mtp-doctor.ts +78 -0
- package/src/services/network-policy.d.ts +127 -0
- package/src/services/network-policy.d.ts.map +1 -0
- package/src/services/network-policy.ts +346 -0
- package/src/services/paths.d.ts +6 -0
- package/src/services/paths.d.ts.map +1 -0
- package/src/services/paths.ts +25 -0
- package/src/services/planner-skeleton.d.ts +124 -0
- package/src/services/planner-skeleton.d.ts.map +1 -0
- package/src/services/planner-skeleton.ts +175 -0
- package/src/services/providers.d.ts +38 -0
- package/src/services/providers.d.ts.map +1 -0
- package/src/services/providers.ts +507 -0
- package/src/services/ram-budget-cache.test.ts +163 -0
- package/src/services/ram-budget.d.ts +110 -0
- package/src/services/ram-budget.d.ts.map +1 -0
- package/src/services/ram-budget.ts +0 -0
- package/src/services/readiness.d.ts +9 -0
- package/src/services/readiness.d.ts.map +1 -0
- package/src/services/readiness.test.ts +87 -0
- package/src/services/readiness.ts +238 -0
- package/src/services/recommendation.d.ts +111 -0
- package/src/services/recommendation.d.ts.map +1 -0
- package/src/services/recommendation.ts +671 -0
- package/src/services/registry.d.ts +35 -0
- package/src/services/registry.d.ts.map +1 -0
- package/src/services/registry.ts +151 -0
- package/src/services/router-handler.d.ts +92 -0
- package/src/services/router-handler.d.ts.map +1 -0
- package/src/services/router-handler.test.ts +45 -0
- package/src/services/router-handler.ts +407 -0
- package/src/services/routing-policy.d.ts +69 -0
- package/src/services/routing-policy.d.ts.map +1 -0
- package/src/services/routing-policy.test.ts +164 -0
- package/src/services/routing-policy.ts +297 -0
- package/src/services/routing-preferences.d.ts +8 -0
- package/src/services/routing-preferences.d.ts.map +1 -0
- package/src/services/routing-preferences.ts +17 -0
- package/src/services/runtime-target.d.ts +98 -0
- package/src/services/runtime-target.d.ts.map +1 -0
- package/src/services/runtime-target.ts +154 -0
- package/src/services/service.d.ts +128 -0
- package/src/services/service.d.ts.map +1 -0
- package/src/services/service.test.ts +223 -0
- package/src/services/service.ts +735 -0
- package/src/services/session-pool.d.ts +72 -0
- package/src/services/session-pool.d.ts.map +1 -0
- package/src/services/session-pool.ts +153 -0
- package/src/services/structured-output/deterministic-repair.d.ts +23 -0
- package/src/services/structured-output/deterministic-repair.d.ts.map +1 -0
- package/src/services/structured-output/deterministic-repair.test.ts +169 -0
- package/src/services/structured-output/deterministic-repair.ts +443 -0
- package/src/services/structured-output/index.ts +4 -0
- package/src/services/structured-output.d.ts +311 -0
- package/src/services/structured-output.d.ts.map +1 -0
- package/src/services/structured-output.test.ts +483 -0
- package/src/services/structured-output.ts +712 -0
- package/src/services/system-memory.d.ts +33 -0
- package/src/services/system-memory.d.ts.map +1 -0
- package/src/services/system-memory.test.ts +47 -0
- package/src/services/system-memory.ts +67 -0
- package/src/services/transcription-priority.test.ts +211 -0
- package/src/services/types.d.ts +19 -0
- package/src/services/types.d.ts.map +1 -0
- package/src/services/types.ts +55 -0
- package/src/services/verify-on-device.d.ts +34 -0
- package/src/services/verify-on-device.d.ts.map +1 -0
- package/src/services/verify-on-device.test.ts +87 -0
- package/src/services/verify-on-device.ts +127 -0
- package/src/services/verify.d.ts +8 -0
- package/src/services/verify.d.ts.map +1 -0
- package/src/services/verify.ts +13 -0
- package/src/services/vision/aosp-unavailable.d.ts +115 -0
- package/src/services/vision/aosp-unavailable.d.ts.map +1 -0
- package/src/services/vision/aosp-unavailable.ts +163 -0
- package/src/services/vision/capacitor-llama.d.ts +99 -0
- package/src/services/vision/capacitor-llama.d.ts.map +1 -0
- package/src/services/vision/capacitor-llama.ts +255 -0
- package/src/services/vision/cloud-fallback.d.ts +47 -0
- package/src/services/vision/cloud-fallback.d.ts.map +1 -0
- package/src/services/vision/cloud-fallback.test.ts +243 -0
- package/src/services/vision/cloud-fallback.ts +268 -0
- package/src/services/vision/fallback-chain.test.ts +86 -0
- package/src/services/vision/hash.d.ts +71 -0
- package/src/services/vision/hash.d.ts.map +1 -0
- package/src/services/vision/hash.ts +157 -0
- package/src/services/vision/index.d.ts +95 -0
- package/src/services/vision/index.d.ts.map +1 -0
- package/src/services/vision/index.ts +251 -0
- package/src/services/vision/llama-server.d.ts +73 -0
- package/src/services/vision/llama-server.d.ts.map +1 -0
- package/src/services/vision/llama-server.ts +177 -0
- package/src/services/vision/types.d.ts +153 -0
- package/src/services/vision/types.d.ts.map +1 -0
- package/src/services/vision/types.ts +154 -0
- package/src/services/vision/vast-fallback.d.ts +18 -0
- package/src/services/vision/vast-fallback.d.ts.map +1 -0
- package/src/services/vision/vast-fallback.ts +127 -0
- package/src/services/vision-embedding-cache.d.ts +98 -0
- package/src/services/vision-embedding-cache.d.ts.map +1 -0
- package/src/services/vision-embedding-cache.ts +189 -0
- package/src/services/voice/VOICE_WORKBENCH.md +88 -0
- package/src/services/voice/__test-helpers__/fake-ffi.ts +94 -0
- package/src/services/voice/__test-helpers__/synthetic-speech.ts +124 -0
- package/src/services/voice/__tests__/checkpoint-manager.test.ts +241 -0
- package/src/services/voice/__tests__/checkpoint-policy.test.ts +270 -0
- package/src/services/voice/__tests__/eager-context-builder.test.ts +257 -0
- package/src/services/voice/__tests__/eliza1-eot-scorer.test.ts +288 -0
- package/src/services/voice/__tests__/eot-classifier.test.ts +431 -0
- package/src/services/voice/__tests__/optimistic-rollback.test.ts +312 -0
- package/src/services/voice/__tests__/prefill-client.test.ts +266 -0
- package/src/services/voice/__tests__/prefix-preserving-queue.test.ts +208 -0
- package/src/services/voice/__tests__/streaming-asr.test.ts +450 -0
- package/src/services/voice/__tests__/streaming-transcriber.test.ts +339 -0
- package/src/services/voice/__tests__/turn-detector-resolver.test.ts +195 -0
- package/src/services/voice/__tests__/voice-state-machine-prefill.test.ts +275 -0
- package/src/services/voice/__tests__/voice-state-machine.test.ts +354 -0
- package/src/services/voice/asr-timed.real.test.ts +141 -0
- package/src/services/voice/audio-frame-consumer.d.ts +212 -0
- package/src/services/voice/audio-frame-consumer.d.ts.map +1 -0
- package/src/services/voice/audio-frame-consumer.test.ts +343 -0
- package/src/services/voice/audio-frame-consumer.ts +491 -0
- package/src/services/voice/barge-in.d.ts +112 -0
- package/src/services/voice/barge-in.d.ts.map +1 -0
- package/src/services/voice/barge-in.test.ts +244 -0
- package/src/services/voice/barge-in.ts +336 -0
- package/src/services/voice/cancellation-coordinator.d.ts +127 -0
- package/src/services/voice/cancellation-coordinator.d.ts.map +1 -0
- package/src/services/voice/cancellation-coordinator.test.ts +196 -0
- package/src/services/voice/cancellation-coordinator.ts +269 -0
- package/src/services/voice/checkpoint-manager.d.ts +199 -0
- package/src/services/voice/checkpoint-manager.d.ts.map +1 -0
- package/src/services/voice/checkpoint-manager.ts +401 -0
- package/src/services/voice/checkpoint-policy.ts +336 -0
- package/src/services/voice/composite-eot-classifier.test.ts +59 -0
- package/src/services/voice/e2e-harness.test.ts +182 -0
- package/src/services/voice/e2e-harness.ts +743 -0
- package/src/services/voice/eager-context-builder.d.ts +170 -0
- package/src/services/voice/eager-context-builder.d.ts.map +1 -0
- package/src/services/voice/eager-context-builder.ts +262 -0
- package/src/services/voice/eliza1-eot-scorer.d.ts +124 -0
- package/src/services/voice/eliza1-eot-scorer.d.ts.map +1 -0
- package/src/services/voice/eliza1-eot-scorer.ts +242 -0
- package/src/services/voice/embedding-server.ts +200 -0
- package/src/services/voice/embedding.d.ts +133 -0
- package/src/services/voice/embedding.d.ts.map +1 -0
- package/src/services/voice/embedding.test.ts +131 -0
- package/src/services/voice/embedding.ts +243 -0
- package/src/services/voice/emotion-attribution.d.ts +68 -0
- package/src/services/voice/emotion-attribution.d.ts.map +1 -0
- package/src/services/voice/emotion-attribution.test.ts +129 -0
- package/src/services/voice/emotion-attribution.ts +361 -0
- package/src/services/voice/engine-bridge-cancellation.test.ts +422 -0
- package/src/services/voice/engine-bridge.d.ts +759 -0
- package/src/services/voice/engine-bridge.d.ts.map +1 -0
- package/src/services/voice/engine-bridge.test.ts +384 -0
- package/src/services/voice/engine-bridge.ts +2302 -0
- package/src/services/voice/eot-classifier-ggml.d.ts +179 -0
- package/src/services/voice/eot-classifier-ggml.d.ts.map +1 -0
- package/src/services/voice/eot-classifier-ggml.ts +566 -0
- package/src/services/voice/eot-classifier.d.ts +214 -0
- package/src/services/voice/eot-classifier.d.ts.map +1 -0
- package/src/services/voice/eot-classifier.ts +533 -0
- package/src/services/voice/errors.d.ts +20 -0
- package/src/services/voice/errors.d.ts.map +1 -0
- package/src/services/voice/errors.ts +32 -0
- package/src/services/voice/expressive-tags.d.ts +158 -0
- package/src/services/voice/expressive-tags.d.ts.map +1 -0
- package/src/services/voice/expressive-tags.ts +405 -0
- package/src/services/voice/ffi-bindings.d.ts +674 -0
- package/src/services/voice/ffi-bindings.d.ts.map +1 -0
- package/src/services/voice/ffi-bindings.test.ts +728 -0
- package/src/services/voice/ffi-bindings.ts +3225 -0
- package/src/services/voice/first-line-cache.d.ts +181 -0
- package/src/services/voice/first-line-cache.d.ts.map +1 -0
- package/src/services/voice/first-line-cache.ts +725 -0
- package/src/services/voice/fused-eot-scorer.d.ts +51 -0
- package/src/services/voice/fused-eot-scorer.d.ts.map +1 -0
- package/src/services/voice/fused-eot-scorer.ts +135 -0
- package/src/services/voice/index.d.ts +91 -0
- package/src/services/voice/index.d.ts.map +1 -0
- package/src/services/voice/index.ts +481 -0
- package/src/services/voice/kokoro/__tests__/kokoro-backend.test.ts +151 -0
- package/src/services/voice/kokoro/__tests__/kokoro-engine-bridge.real.test.ts +151 -0
- package/src/services/voice/kokoro/__tests__/kokoro-engine-bridge.test.ts +60 -0
- package/src/services/voice/kokoro/__tests__/kokoro-engine-discovery.test.ts +277 -0
- package/src/services/voice/kokoro/__tests__/kokoro-ffi-runtime.test.ts +235 -0
- package/src/services/voice/kokoro/__tests__/kokoro-runtime.test.ts +95 -0
- package/src/services/voice/kokoro/__tests__/phonemizer.test.ts +53 -0
- package/src/services/voice/kokoro/__tests__/runtime-selection.test.ts +231 -0
- package/src/services/voice/kokoro/__tests__/voices.test.ts +57 -0
- package/src/services/voice/kokoro/index.ts +79 -0
- package/src/services/voice/kokoro/kokoro-backend.d.ts +72 -0
- package/src/services/voice/kokoro/kokoro-backend.d.ts.map +1 -0
- package/src/services/voice/kokoro/kokoro-backend.ts +207 -0
- package/src/services/voice/kokoro/kokoro-engine-discovery.d.ts +58 -0
- package/src/services/voice/kokoro/kokoro-engine-discovery.d.ts.map +1 -0
- package/src/services/voice/kokoro/kokoro-engine-discovery.ts +177 -0
- package/src/services/voice/kokoro/kokoro-ffi-runtime.d.ts +75 -0
- package/src/services/voice/kokoro/kokoro-ffi-runtime.d.ts.map +1 -0
- package/src/services/voice/kokoro/kokoro-ffi-runtime.ts +233 -0
- package/src/services/voice/kokoro/kokoro-runtime.d.ts +100 -0
- package/src/services/voice/kokoro/kokoro-runtime.d.ts.map +1 -0
- package/src/services/voice/kokoro/kokoro-runtime.ts +170 -0
- package/src/services/voice/kokoro/phoneme-stream.ts +123 -0
- package/src/services/voice/kokoro/phonemizer.d.ts +50 -0
- package/src/services/voice/kokoro/phonemizer.d.ts.map +1 -0
- package/src/services/voice/kokoro/phonemizer.ts +344 -0
- package/src/services/voice/kokoro/pick-runtime.d.ts +61 -0
- package/src/services/voice/kokoro/pick-runtime.d.ts.map +1 -0
- package/src/services/voice/kokoro/pick-runtime.test.ts +91 -0
- package/src/services/voice/kokoro/pick-runtime.ts +130 -0
- package/src/services/voice/kokoro/runtime-selection.d.ts +92 -0
- package/src/services/voice/kokoro/runtime-selection.d.ts.map +1 -0
- package/src/services/voice/kokoro/runtime-selection.ts +237 -0
- package/src/services/voice/kokoro/types.d.ts +82 -0
- package/src/services/voice/kokoro/types.d.ts.map +1 -0
- package/src/services/voice/kokoro/types.ts +95 -0
- package/src/services/voice/kokoro/voice-presets.d.ts +23 -0
- package/src/services/voice/kokoro/voice-presets.d.ts.map +1 -0
- package/src/services/voice/kokoro/voice-presets.ts +129 -0
- package/src/services/voice/kokoro/voices.d.ts +30 -0
- package/src/services/voice/kokoro/voices.d.ts.map +1 -0
- package/src/services/voice/kokoro/voices.ts +64 -0
- package/src/services/voice/lifecycle.d.ts +135 -0
- package/src/services/voice/lifecycle.d.ts.map +1 -0
- package/src/services/voice/lifecycle.test.ts +315 -0
- package/src/services/voice/lifecycle.ts +301 -0
- package/src/services/voice/live-diarization-session.d.ts +96 -0
- package/src/services/voice/live-diarization-session.d.ts.map +1 -0
- package/src/services/voice/live-diarization-session.ts +289 -0
- package/src/services/voice/mic-source.d.ts +136 -0
- package/src/services/voice/mic-source.d.ts.map +1 -0
- package/src/services/voice/mic-source.test.ts +210 -0
- package/src/services/voice/mic-source.ts +503 -0
- package/src/services/voice/optimistic-policy.d.ts +109 -0
- package/src/services/voice/optimistic-policy.d.ts.map +1 -0
- package/src/services/voice/optimistic-policy.test.ts +101 -0
- package/src/services/voice/optimistic-policy.ts +192 -0
- package/src/services/voice/optimistic-rollback.ts +343 -0
- package/src/services/voice/partial-stabilizer.d.ts +73 -0
- package/src/services/voice/partial-stabilizer.d.ts.map +1 -0
- package/src/services/voice/partial-stabilizer.test.ts +68 -0
- package/src/services/voice/partial-stabilizer.ts +140 -0
- package/src/services/voice/phoneme-tokenizer.d.ts +49 -0
- package/src/services/voice/phoneme-tokenizer.d.ts.map +1 -0
- package/src/services/voice/phoneme-tokenizer.ts +158 -0
- package/src/services/voice/phrase-cache.d.ts +76 -0
- package/src/services/voice/phrase-cache.d.ts.map +1 -0
- package/src/services/voice/phrase-cache.test.ts +242 -0
- package/src/services/voice/phrase-cache.ts +186 -0
- package/src/services/voice/phrase-chunker.d.ts +62 -0
- package/src/services/voice/phrase-chunker.d.ts.map +1 -0
- package/src/services/voice/phrase-chunker.test.ts +239 -0
- package/src/services/voice/phrase-chunker.ts +281 -0
- package/src/services/voice/pipeline-impls.d.ts +151 -0
- package/src/services/voice/pipeline-impls.d.ts.map +1 -0
- package/src/services/voice/pipeline-impls.l6.test.ts +110 -0
- package/src/services/voice/pipeline-impls.test.ts +292 -0
- package/src/services/voice/pipeline-impls.ts +315 -0
- package/src/services/voice/pipeline.d.ts +216 -0
- package/src/services/voice/pipeline.d.ts.map +1 -0
- package/src/services/voice/pipeline.ts +505 -0
- package/src/services/voice/prefill-client.d.ts +123 -0
- package/src/services/voice/prefill-client.d.ts.map +1 -0
- package/src/services/voice/prefill-client.ts +316 -0
- package/src/services/voice/prefix-preserving-queue.d.ts +113 -0
- package/src/services/voice/prefix-preserving-queue.d.ts.map +1 -0
- package/src/services/voice/prefix-preserving-queue.ts +162 -0
- package/src/services/voice/profile-store.d.ts +248 -0
- package/src/services/voice/profile-store.d.ts.map +1 -0
- package/src/services/voice/profile-store.ts +887 -0
- package/src/services/voice/real-audio-decode.test.ts +148 -0
- package/src/services/voice/ring-buffer.d.ts +40 -0
- package/src/services/voice/ring-buffer.d.ts.map +1 -0
- package/src/services/voice/ring-buffer.test.ts +129 -0
- package/src/services/voice/ring-buffer.ts +123 -0
- package/src/services/voice/rollback-queue.d.ts +24 -0
- package/src/services/voice/rollback-queue.d.ts.map +1 -0
- package/src/services/voice/rollback-queue.ts +74 -0
- package/src/services/voice/samantha-preset-placeholder.d.ts +67 -0
- package/src/services/voice/samantha-preset-placeholder.d.ts.map +1 -0
- package/src/services/voice/samantha-preset-placeholder.test.ts +97 -0
- package/src/services/voice/samantha-preset-placeholder.ts +148 -0
- package/src/services/voice/samantha-preset-regenerator.d.ts +87 -0
- package/src/services/voice/samantha-preset-regenerator.d.ts.map +1 -0
- package/src/services/voice/samantha-preset-regenerator.ts +393 -0
- package/src/services/voice/scheduler.d.ts +146 -0
- package/src/services/voice/scheduler.d.ts.map +1 -0
- package/src/services/voice/scheduler.t2.test.ts +141 -0
- package/src/services/voice/scheduler.ts +927 -0
- package/src/services/voice/shared-resources.d.ts +190 -0
- package/src/services/voice/shared-resources.d.ts.map +1 -0
- package/src/services/voice/shared-resources.ts +320 -0
- package/src/services/voice/speaker/attribution-pipeline.d.ts +74 -0
- package/src/services/voice/speaker/attribution-pipeline.d.ts.map +1 -0
- package/src/services/voice/speaker/attribution-pipeline.ts +386 -0
- package/src/services/voice/speaker/diarizer-fused.d.ts +59 -0
- package/src/services/voice/speaker/diarizer-fused.d.ts.map +1 -0
- package/src/services/voice/speaker/diarizer-fused.real.test.ts +100 -0
- package/src/services/voice/speaker/diarizer-fused.ts +154 -0
- package/src/services/voice/speaker/diarizer.d.ts +75 -0
- package/src/services/voice/speaker/diarizer.d.ts.map +1 -0
- package/src/services/voice/speaker/diarizer.ts +218 -0
- package/src/services/voice/speaker/encoder-fused.d.ts +60 -0
- package/src/services/voice/speaker/encoder-fused.d.ts.map +1 -0
- package/src/services/voice/speaker/encoder-fused.real.test.ts +113 -0
- package/src/services/voice/speaker/encoder-fused.ts +138 -0
- package/src/services/voice/speaker/encoder-ggml.d.ts +33 -0
- package/src/services/voice/speaker/encoder-ggml.d.ts.map +1 -0
- package/src/services/voice/speaker/encoder-ggml.ts +79 -0
- package/src/services/voice/speaker/encoder.d.ts +37 -0
- package/src/services/voice/speaker/encoder.d.ts.map +1 -0
- package/src/services/voice/speaker/encoder.ts +105 -0
- package/src/services/voice/speaker-imprint.d.ts +83 -0
- package/src/services/voice/speaker-imprint.d.ts.map +1 -0
- package/src/services/voice/speaker-imprint.test.ts +185 -0
- package/src/services/voice/speaker-imprint.ts +312 -0
- package/src/services/voice/speaker-preset-cache.d.ts +77 -0
- package/src/services/voice/speaker-preset-cache.d.ts.map +1 -0
- package/src/services/voice/speaker-preset-cache.test.ts +154 -0
- package/src/services/voice/speaker-preset-cache.ts +195 -0
- package/src/services/voice/streaming-asr/streaming-pipeline-adapter.ts +292 -0
- package/src/services/voice/system-audio-sink.d.ts +73 -0
- package/src/services/voice/system-audio-sink.d.ts.map +1 -0
- package/src/services/voice/system-audio-sink.test.ts +29 -0
- package/src/services/voice/system-audio-sink.ts +366 -0
- package/src/services/voice/transcriber.d.ts +244 -0
- package/src/services/voice/transcriber.d.ts.map +1 -0
- package/src/services/voice/transcriber.test.ts +392 -0
- package/src/services/voice/transcriber.ts +704 -0
- package/src/services/voice/transcript-knowledge.d.ts +37 -0
- package/src/services/voice/transcript-knowledge.d.ts.map +1 -0
- package/src/services/voice/transcript-knowledge.test.ts +68 -0
- package/src/services/voice/transcript-knowledge.ts +75 -0
- package/src/services/voice/transcript-service.d.ts +41 -0
- package/src/services/voice/transcript-service.d.ts.map +1 -0
- package/src/services/voice/transcript-service.test.ts +137 -0
- package/src/services/voice/transcript-service.ts +141 -0
- package/src/services/voice/transcript-store.d.ts +53 -0
- package/src/services/voice/transcript-store.d.ts.map +1 -0
- package/src/services/voice/transcript-store.test.ts +153 -0
- package/src/services/voice/transcript-store.ts +132 -0
- package/src/services/voice/turn-controller.d.ts +183 -0
- package/src/services/voice/turn-controller.d.ts.map +1 -0
- package/src/services/voice/turn-controller.test.ts +575 -0
- package/src/services/voice/turn-controller.ts +596 -0
- package/src/services/voice/types.d.ts +643 -0
- package/src/services/voice/types.d.ts.map +1 -0
- package/src/services/voice/types.ts +699 -0
- package/src/services/voice/vad.d.ts +282 -0
- package/src/services/voice/vad.d.ts.map +1 -0
- package/src/services/voice/vad.test.ts +480 -0
- package/src/services/voice/vad.ts +827 -0
- package/src/services/voice/vad.v1-v4.test.ts +222 -0
- package/src/services/voice/voice-budget.d.ts +241 -0
- package/src/services/voice/voice-budget.d.ts.map +1 -0
- package/src/services/voice/voice-budget.test.ts +418 -0
- package/src/services/voice/voice-budget.ts +635 -0
- package/src/services/voice/voice-duet.test.ts +375 -0
- package/src/services/voice/voice-emotion-classifier.d.ts +95 -0
- package/src/services/voice/voice-emotion-classifier.d.ts.map +1 -0
- package/src/services/voice/voice-emotion-classifier.test.ts +210 -0
- package/src/services/voice/voice-emotion-classifier.ts +273 -0
- package/src/services/voice/voice-preset-format.d.ts +158 -0
- package/src/services/voice/voice-preset-format.d.ts.map +1 -0
- package/src/services/voice/voice-preset-format.ts +700 -0
- package/src/services/voice/voice-preset-generator.test.ts +89 -0
- package/src/services/voice/voice-profile-artifact.d.ts +116 -0
- package/src/services/voice/voice-profile-artifact.d.ts.map +1 -0
- package/src/services/voice/voice-profile-artifact.test.ts +138 -0
- package/src/services/voice/voice-profile-artifact.ts +518 -0
- package/src/services/voice/voice-profile-routes.d.ts +83 -0
- package/src/services/voice/voice-profile-routes.d.ts.map +1 -0
- package/src/services/voice/voice-profile-routes.test.ts +429 -0
- package/src/services/voice/voice-profile-routes.ts +425 -0
- package/src/services/voice/voice-scenario.ts +154 -0
- package/src/services/voice/voice-settings.d.ts +82 -0
- package/src/services/voice/voice-settings.d.ts.map +1 -0
- package/src/services/voice/voice-settings.ts +172 -0
- package/src/services/voice/voice-state-machine.d.ts +364 -0
- package/src/services/voice/voice-state-machine.d.ts.map +1 -0
- package/src/services/voice/voice-state-machine.ts +727 -0
- package/src/services/voice/voice-workbench-report.test.ts +168 -0
- package/src/services/voice/voice-workbench-report.ts +326 -0
- package/src/services/voice/voice-workbench.test.ts +158 -0
- package/src/services/voice/voice.test.ts +1070 -0
- package/src/services/voice/wake-word-ggml.d.ts +101 -0
- package/src/services/voice/wake-word-ggml.d.ts.map +1 -0
- package/src/services/voice/wake-word-ggml.ts +320 -0
- package/src/services/voice/wake-word.d.ts +255 -0
- package/src/services/voice/wake-word.d.ts.map +1 -0
- package/src/services/voice/wake-word.test.ts +298 -0
- package/src/services/voice/wake-word.ts +554 -0
- package/src/services/voice/wrap-with-first-line-cache.d.ts +70 -0
- package/src/services/voice/wrap-with-first-line-cache.d.ts.map +1 -0
- package/src/services/voice/wrap-with-first-line-cache.ts +267 -0
- package/src/services/voice-model-updater.d.ts +240 -0
- package/src/services/voice-model-updater.d.ts.map +1 -0
- package/src/services/voice-model-updater.ts +724 -0
- package/src/services/voice-prewarm.d.ts +3 -0
- package/src/services/voice-prewarm.d.ts.map +1 -0
- package/src/services/voice-prewarm.ts +51 -0
- package/dist/index.d.ts +0 -37
- package/dist/index.js +0 -1098
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wake-word detection (openWakeWord) — opt-in, local-mode only.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the previous `onnxruntime-node`-backed implementation with a
|
|
5
|
+
* pure GGML / llama.cpp path. The three-stage openWakeWord pipeline (mel
|
|
6
|
+
* filterbank → speech embedding model → per-phrase classifier head) is
|
|
7
|
+
* compiled into one combined GGUF
|
|
8
|
+
* (`wake/openwakeword.gguf`, produced by
|
|
9
|
+
* `packages/training/scripts/wakeword/convert_openwakeword_to_gguf.py`)
|
|
10
|
+
* and executed natively by the fused `libelizainference` build via the
|
|
11
|
+
* `eliza_inference_wakeword_*` FFI surface (ABI v5).
|
|
12
|
+
*
|
|
13
|
+
* The JS side is now a thin adapter over that surface — there is NO ONNX
|
|
14
|
+
* fallback. When the fused library was built without the wake-word
|
|
15
|
+
* runtime, the JS path throws a structured `WakeWordUnavailableError`
|
|
16
|
+
* (AGENTS.md §3, §8 — no silent fallbacks).
|
|
17
|
+
*
|
|
18
|
+
* Per `packages/inference/AGENTS.md` §1 + the three-mode rules (§1, §5):
|
|
19
|
+
* - openWakeWord (Apache-2.0, ~3 MB) ships in the bundle but is
|
|
20
|
+
* **opt-in**: voice mode works without it (push-to-talk / VAD-gated).
|
|
21
|
+
* - It is **local-mode only**. In `cloud` mode the surface is hidden
|
|
22
|
+
* *and inert* (hide-not-disable §5): the model is not loaded, the
|
|
23
|
+
* setting is rejected by the API, no background job runs it.
|
|
24
|
+
* - Detections feed the same place a push-to-talk press would: they arm
|
|
25
|
+
* a listening window that the VAD gate then bounds.
|
|
26
|
+
*
|
|
27
|
+
* Streaming pipeline shape (16 kHz mono):
|
|
28
|
+
* - 1280-sample (80 ms) PCM frames per `scoreFrame` call.
|
|
29
|
+
* - Internally: mel filterbank → 32-bin frames; embedding model windows
|
|
30
|
+
* 76 mel frames, hop 8 → 96-dim embedding; head windows 16 embeddings
|
|
31
|
+
* → P(wake) in [0, 1].
|
|
32
|
+
* - The native runtime owns the audio tail, mel ring and embedding
|
|
33
|
+
* ring; the JS side feeds frames and reads back probabilities.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { existsSync } from "node:fs";
|
|
37
|
+
import path from "node:path";
|
|
38
|
+
import { localInferenceRoot } from "../paths";
|
|
39
|
+
import type {
|
|
40
|
+
ElizaInferenceContextHandle,
|
|
41
|
+
ElizaInferenceFfi,
|
|
42
|
+
NativeWakeWordHandle,
|
|
43
|
+
} from "./ffi-bindings";
|
|
44
|
+
import {
|
|
45
|
+
OpenWakeWordGgmlModel,
|
|
46
|
+
WakeWordGgmlUnavailableError,
|
|
47
|
+
} from "./wake-word-ggml";
|
|
48
|
+
|
|
49
|
+
/** Directory holding the bundled openWakeWord GGUF inside a bundle. */
|
|
50
|
+
export const OPENWAKEWORD_DIR_REL_PATH = "wake";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Combined wake-word GGUF: contains the mel filterbank constants, the
|
|
54
|
+
* speech embedding model weights, AND every per-phrase classifier head
|
|
55
|
+
* (`head.<name>.*` tensors). The fused `libelizainference` build mmaps
|
|
56
|
+
* this file from `<bundleRoot>/wake/openwakeword.gguf` (or the shared
|
|
57
|
+
* cache at `<state-dir>/local-inference/wake/openwakeword.gguf`).
|
|
58
|
+
*/
|
|
59
|
+
export const OPENWAKEWORD_GGUF_REL_PATH = path.join(
|
|
60
|
+
OPENWAKEWORD_DIR_REL_PATH,
|
|
61
|
+
"openwakeword.gguf",
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Default wake-phrase head shipped with a voice bundle. The documented
|
|
66
|
+
* default Eliza-1 wake phrase is **"hey eliza"** — a two-word,
|
|
67
|
+
* four-syllable phrase the openWakeWord TTS-augmented pipeline handles
|
|
68
|
+
* well. It is replaceable: retrain on a different `--phrase` via
|
|
69
|
+
* `packages/training/scripts/wakeword/train_eliza1_wakeword_head.py`,
|
|
70
|
+
* convert to GGUF via
|
|
71
|
+
* `packages/training/scripts/wakeword/convert_openwakeword_to_gguf.py`,
|
|
72
|
+
* and re-point this constant.
|
|
73
|
+
*/
|
|
74
|
+
export const OPENWAKEWORD_DEFAULT_HEAD = "hey-eliza";
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Heads that are placeholders, not trained on the Eliza-1 wake phrase.
|
|
78
|
+
*
|
|
79
|
+
* `hey-eliza` stays in this set until a head trained against the real
|
|
80
|
+
* phrase ships in every tier bundle (the bundled binary is still the
|
|
81
|
+
* upstream `hey_jarvis_v0.1` weights renamed). `hey_jarvis` stays by
|
|
82
|
+
* definition — it is the wrong phrase.
|
|
83
|
+
*
|
|
84
|
+
* A real "hey eliza" head HAS been trained and verified end-to-end through
|
|
85
|
+
* this exact runtime — ~98% true-accept / ~4-7% false-accept on a held-out set
|
|
86
|
+
* scored via `libwakeword.so` (see
|
|
87
|
+
* `packages/training/scripts/wakeword/HEY_ELIZA_HEAD_PROVENANCE.md`). It must
|
|
88
|
+
* be trained with `train_eliza1_wakeword_head.py --no-mel-rescale` to match
|
|
89
|
+
* this runtime's mel preprocessing.
|
|
90
|
+
*
|
|
91
|
+
* The trained GGUFs are now PUBLISHED to `elizaos/eliza-1` at
|
|
92
|
+
* `voice/wakeword/hey-eliza.{melspec,embedding,classifier}.gguf` and registered
|
|
93
|
+
* in the voice catalog as `wakeword` v0.3.0 (`VOICE_MODEL_VERSIONS` in
|
|
94
|
+
* `@elizaos/shared`). `hey-eliza` nonetheless STAYS in this set until that head
|
|
95
|
+
* ships in every tier BUNDLE's `wake/` dir — the gated `publish_all_eliza1.sh`
|
|
96
|
+
* re-publish — because the bundles users currently download still carry the
|
|
97
|
+
* renamed `hey_jarvis` placeholder; removing the flag before the bundle ships
|
|
98
|
+
* the real head would make the runtime treat the placeholder as authentic.
|
|
99
|
+
* `hey_jarvis` stays by definition (wrong phrase). A future pass should make
|
|
100
|
+
* this data-driven off the bundle manifest's `releaseState` rather than
|
|
101
|
+
* hard-coded.
|
|
102
|
+
*/
|
|
103
|
+
export const OPENWAKEWORD_PLACEHOLDER_HEADS: ReadonlySet<string> = new Set([
|
|
104
|
+
"hey-eliza",
|
|
105
|
+
"hey_jarvis",
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
export function isPlaceholderWakeWordHead(head: string): boolean {
|
|
109
|
+
return OPENWAKEWORD_PLACEHOLDER_HEADS.has(head.trim());
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Audio chunk the streaming pipeline consumes, in samples (80 ms @ 16 kHz). */
|
|
113
|
+
const FRAME_SAMPLES = 1280;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Per-frame wake-word probability source. openWakeWord runs on 80 ms
|
|
117
|
+
* frames of 16 kHz audio; `scoreFrame` takes one PCM frame and returns
|
|
118
|
+
* the latest P(wake) in [0, 1] (the head only re-runs once enough
|
|
119
|
+
* context has accumulated — early frames return 0). Stateful (the
|
|
120
|
+
* streaming front-end carries its buffers); `reset()` clears it.
|
|
121
|
+
*
|
|
122
|
+
* The default backend (`GgmlWakeWordModel`) calls into the native FFI
|
|
123
|
+
* synchronously; the method is still `async` so the interface fits a
|
|
124
|
+
* async-friendly backend variant (e.g. worker-thread based) and
|
|
125
|
+
* matches the same shape the previous ONNX backend exposed to callers.
|
|
126
|
+
*/
|
|
127
|
+
export type { WakeWordModel } from "./types.js";
|
|
128
|
+
|
|
129
|
+
import type { WakeWordModel } from "./types.js";
|
|
130
|
+
|
|
131
|
+
export interface WakeWordConfig {
|
|
132
|
+
/** P(wake) above this fires a detection. openWakeWord default ~0.5. */
|
|
133
|
+
threshold?: number;
|
|
134
|
+
/**
|
|
135
|
+
* Refractory frames after a detection during which no new detection
|
|
136
|
+
* fires (debounce a single utterance into one event).
|
|
137
|
+
*/
|
|
138
|
+
refractoryFrames?: number;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const DEFAULTS: Required<WakeWordConfig> = {
|
|
142
|
+
threshold: 0.5,
|
|
143
|
+
refractoryFrames: 25, // ~2 s @ 80 ms frames
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Thrown when the native openWakeWord runtime cannot service this call:
|
|
148
|
+
* - `ffi-missing`: the FFI handle was not provided to the loader (the
|
|
149
|
+
* voice lifecycle hands one in via `loadBundledWakeWordModel`).
|
|
150
|
+
* - `runtime-not-ready`: the fused `libelizainference` build does not
|
|
151
|
+
* export `eliza_inference_wakeword_*` — the wake-word GGUF runtime
|
|
152
|
+
* is not yet compiled into this binary. NOT thrown for an absent
|
|
153
|
+
* bundled GGUF (that is "wake word unavailable for this bundle",
|
|
154
|
+
* not a broken build — `resolveWakeWordModel` returns null instead).
|
|
155
|
+
* - `model-load-failed`: the native side rejected the GGUF or the
|
|
156
|
+
* selected head name at session open.
|
|
157
|
+
*/
|
|
158
|
+
export class WakeWordUnavailableError extends Error {
|
|
159
|
+
readonly code: "ffi-missing" | "runtime-not-ready" | "model-load-failed";
|
|
160
|
+
constructor(code: WakeWordUnavailableError["code"], message: string) {
|
|
161
|
+
super(message);
|
|
162
|
+
this.name = "WakeWordUnavailableError";
|
|
163
|
+
this.code = code;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Path to the combined wake-word GGUF and the name of the head to bind. */
|
|
168
|
+
export interface WakeWordModelPaths {
|
|
169
|
+
/** Absolute path to `wake/openwakeword.gguf`. */
|
|
170
|
+
gguf: string;
|
|
171
|
+
/** Name of the classifier head inside the GGUF (e.g. "hey-eliza"). */
|
|
172
|
+
head: string;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* The real openWakeWord streaming detector, backed by the native FFI.
|
|
177
|
+
* Owns one `eliza_inference_wakeword_*` session; `scoreFrame` consumes
|
|
178
|
+
* exactly `frameSamples` (1280) samples at 16 kHz and returns the most
|
|
179
|
+
* recent head probability the native pipeline produced. The audio tail,
|
|
180
|
+
* mel ring and embedding ring live on the C side; this class is a thin
|
|
181
|
+
* handle.
|
|
182
|
+
*/
|
|
183
|
+
export class GgmlWakeWordModel implements WakeWordModel {
|
|
184
|
+
readonly frameSamples = FRAME_SAMPLES;
|
|
185
|
+
readonly sampleRate = 16_000;
|
|
186
|
+
private closed = false;
|
|
187
|
+
|
|
188
|
+
private constructor(
|
|
189
|
+
private readonly ffi: ElizaInferenceFfi,
|
|
190
|
+
private readonly handle: NativeWakeWordHandle,
|
|
191
|
+
) {}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* True only when the fused `libelizainference` build exports the
|
|
195
|
+
* wake-word ABI and advertises support at runtime. The wake-word
|
|
196
|
+
* loader uses this to surface a structured `runtime-not-ready` error
|
|
197
|
+
* before attempting to open a session.
|
|
198
|
+
*/
|
|
199
|
+
static isSupported(ffi: ElizaInferenceFfi | null | undefined): boolean {
|
|
200
|
+
if (!ffi || typeof ffi.wakewordSupported !== "function") return false;
|
|
201
|
+
return ffi.wakewordSupported();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Open a native wake-word session. Throws `WakeWordUnavailableError`
|
|
206
|
+
* when the runtime is not present or rejects the head name. No silent
|
|
207
|
+
* fallback (AGENTS.md §3).
|
|
208
|
+
*/
|
|
209
|
+
static async load(opts: {
|
|
210
|
+
ffi: ElizaInferenceFfi;
|
|
211
|
+
ctx: ElizaInferenceContextHandle | (() => ElizaInferenceContextHandle);
|
|
212
|
+
headName: string;
|
|
213
|
+
}): Promise<GgmlWakeWordModel> {
|
|
214
|
+
if (!GgmlWakeWordModel.isSupported(opts.ffi)) {
|
|
215
|
+
throw new WakeWordUnavailableError(
|
|
216
|
+
"runtime-not-ready",
|
|
217
|
+
"[wake-word] The native wake-word GGUF runtime is not present in this libelizainference build. Rebuild with the openWakeWord GGML runtime linked in (eliza_inference_wakeword_* symbols).",
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
if (
|
|
221
|
+
!opts.ffi.wakewordOpen ||
|
|
222
|
+
!opts.ffi.wakewordScore ||
|
|
223
|
+
!opts.ffi.wakewordReset ||
|
|
224
|
+
!opts.ffi.wakewordClose
|
|
225
|
+
) {
|
|
226
|
+
throw new WakeWordUnavailableError(
|
|
227
|
+
"runtime-not-ready",
|
|
228
|
+
"[wake-word] Wake-word support probe succeeded, but the required FFI methods are missing on the binding.",
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
const ctx = typeof opts.ctx === "function" ? opts.ctx() : opts.ctx;
|
|
232
|
+
let handle: NativeWakeWordHandle;
|
|
233
|
+
try {
|
|
234
|
+
handle = opts.ffi.wakewordOpen({
|
|
235
|
+
ctx,
|
|
236
|
+
sampleRateHz: 16_000,
|
|
237
|
+
headName: opts.headName,
|
|
238
|
+
});
|
|
239
|
+
} catch (err) {
|
|
240
|
+
throw new WakeWordUnavailableError(
|
|
241
|
+
"model-load-failed",
|
|
242
|
+
`[wake-word] failed to open native wake-word session for head '${opts.headName}': ${
|
|
243
|
+
err instanceof Error ? err.message : String(err)
|
|
244
|
+
}`,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
return new GgmlWakeWordModel(opts.ffi, handle);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async scoreFrame(frame: Float32Array): Promise<number> {
|
|
251
|
+
if (this.closed) {
|
|
252
|
+
throw new Error(
|
|
253
|
+
"[wake-word] GgmlWakeWordModel.scoreFrame called after close()",
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
if (frame.length !== FRAME_SAMPLES) {
|
|
257
|
+
throw new Error(
|
|
258
|
+
`[wake-word] GgmlWakeWordModel.scoreFrame expects ${FRAME_SAMPLES} samples; got ${frame.length}`,
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const score = this.ffi.wakewordScore;
|
|
262
|
+
if (!score) {
|
|
263
|
+
throw new Error("[wake-word] scoreFrame missing FFI method");
|
|
264
|
+
}
|
|
265
|
+
return score({ wake: this.handle, pcm: frame });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
reset(): void {
|
|
269
|
+
if (this.closed) return;
|
|
270
|
+
const reset = this.ffi.wakewordReset;
|
|
271
|
+
if (!reset) {
|
|
272
|
+
throw new Error("[wake-word] reset missing FFI method");
|
|
273
|
+
}
|
|
274
|
+
reset(this.handle);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
close(): void {
|
|
278
|
+
if (this.closed) return;
|
|
279
|
+
this.closed = true;
|
|
280
|
+
this.ffi.wakewordClose?.(this.handle);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Resolve the bundled wake-word GGUF. Unlike the VAD model this is
|
|
286
|
+
* *optional* — a missing file means "wake word unavailable for this
|
|
287
|
+
* bundle", not "broken bundle". Returns null when the GGUF is absent so
|
|
288
|
+
* callers keep voice mode working (push-to-talk / VAD-gated) without it.
|
|
289
|
+
*
|
|
290
|
+
* Search order:
|
|
291
|
+
* 1. `<bundleRoot>/wake/openwakeword.gguf`
|
|
292
|
+
* 2. `<state-dir>/local-inference/wake/openwakeword.gguf` (shared cache)
|
|
293
|
+
*
|
|
294
|
+
* `head` defaults to the bundle's default wake phrase. The head name is
|
|
295
|
+
* resolved by the native runtime against tensors inside the GGUF, so it
|
|
296
|
+
* is validated at open time, not here.
|
|
297
|
+
*
|
|
298
|
+
* MUST only be called in `local` mode. The cloud-mode router does not
|
|
299
|
+
* reach this (the wake-word setting is rejected there) — see AGENTS.md §5
|
|
300
|
+
* hide-not-disable.
|
|
301
|
+
*/
|
|
302
|
+
export function resolveWakeWordModel(opts: {
|
|
303
|
+
bundleRoot?: string;
|
|
304
|
+
head?: string;
|
|
305
|
+
}): WakeWordModelPaths | null {
|
|
306
|
+
const headName = opts.head?.trim() || OPENWAKEWORD_DEFAULT_HEAD;
|
|
307
|
+
const candidates: string[] = [];
|
|
308
|
+
if (opts.bundleRoot) {
|
|
309
|
+
candidates.push(path.join(opts.bundleRoot, OPENWAKEWORD_GGUF_REL_PATH));
|
|
310
|
+
}
|
|
311
|
+
candidates.push(path.join(localInferenceRoot(), OPENWAKEWORD_GGUF_REL_PATH));
|
|
312
|
+
for (const c of candidates) {
|
|
313
|
+
if (existsSync(c)) return { gguf: path.resolve(c), head: headName };
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Resolve the standalone wakeword-cpp library + three-GGUF bundle.
|
|
320
|
+
* Returns `null` when any of the four files is missing — that means
|
|
321
|
+
* "use a different provider", not "broken bundle".
|
|
322
|
+
*
|
|
323
|
+
* Search order for the shared library:
|
|
324
|
+
* 1. `$ELIZA_WAKEWORD_LIB` (operator override)
|
|
325
|
+
* 2. `<bundleRoot>/wake/libwakeword.{so,dylib,dll}`
|
|
326
|
+
* 3. `<state-dir>/local-inference/wake/libwakeword.{so,dylib,dll}`
|
|
327
|
+
* 4. `packages/native/plugins/wakeword-cpp/build/libwakeword.{so,dylib,dll}`
|
|
328
|
+
* (developer build tree)
|
|
329
|
+
*
|
|
330
|
+
* Search order for the three GGUFs (per kind in
|
|
331
|
+
* {melspec, embedding, classifier}):
|
|
332
|
+
* 1. `<bundleRoot>/wake/<head>.<kind>.gguf`
|
|
333
|
+
* 2. `<state-dir>/local-inference/wake/<head>.<kind>.gguf`
|
|
334
|
+
* 3. `packages/native/plugins/wakeword-cpp/build/wakeword/<head>.<kind>.gguf`
|
|
335
|
+
*/
|
|
336
|
+
function libExtCandidates(): readonly string[] {
|
|
337
|
+
switch (process.platform) {
|
|
338
|
+
case "darwin":
|
|
339
|
+
return [".dylib", ".so"] as const;
|
|
340
|
+
case "win32":
|
|
341
|
+
return [".dll"] as const;
|
|
342
|
+
default:
|
|
343
|
+
return [".so", ".dylib"] as const;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function firstExisting(paths: readonly string[]): string | null {
|
|
348
|
+
for (const p of paths) if (existsSync(p)) return path.resolve(p);
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Resolved triple of standalone wakeword-cpp paths (library + 3 GGUFs). */
|
|
353
|
+
export interface WakeWordStandalonePaths {
|
|
354
|
+
libraryPath: string;
|
|
355
|
+
melspec: string;
|
|
356
|
+
embedding: string;
|
|
357
|
+
classifier: string;
|
|
358
|
+
head: string;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export function resolveWakeWordStandalonePaths(opts: {
|
|
362
|
+
bundleRoot?: string;
|
|
363
|
+
head?: string;
|
|
364
|
+
}): WakeWordStandalonePaths | null {
|
|
365
|
+
const head = opts.head?.trim() || OPENWAKEWORD_DEFAULT_HEAD;
|
|
366
|
+
const root = localInferenceRoot();
|
|
367
|
+
|
|
368
|
+
const libCandidates: string[] = [];
|
|
369
|
+
const envLib = process.env.ELIZA_WAKEWORD_LIB;
|
|
370
|
+
if (envLib && envLib.length > 0) libCandidates.push(envLib);
|
|
371
|
+
for (const ext of libExtCandidates()) {
|
|
372
|
+
if (opts.bundleRoot)
|
|
373
|
+
libCandidates.push(
|
|
374
|
+
path.join(opts.bundleRoot, "wake", `libwakeword${ext}`),
|
|
375
|
+
);
|
|
376
|
+
libCandidates.push(path.join(root, "wake", `libwakeword${ext}`));
|
|
377
|
+
libCandidates.push(
|
|
378
|
+
path.join(
|
|
379
|
+
__dirname,
|
|
380
|
+
"..",
|
|
381
|
+
"..",
|
|
382
|
+
"..",
|
|
383
|
+
"..",
|
|
384
|
+
"..",
|
|
385
|
+
"packages/native/plugins/wakeword-cpp/build",
|
|
386
|
+
`libwakeword${ext}`,
|
|
387
|
+
),
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
const libraryPath = firstExisting(libCandidates);
|
|
391
|
+
if (!libraryPath) return null;
|
|
392
|
+
|
|
393
|
+
const ggufCandidates = (
|
|
394
|
+
kind: "melspec" | "embedding" | "classifier",
|
|
395
|
+
): string[] => {
|
|
396
|
+
const fname = `${head}.${kind}.gguf`;
|
|
397
|
+
const cs: string[] = [];
|
|
398
|
+
if (opts.bundleRoot) cs.push(path.join(opts.bundleRoot, "wake", fname));
|
|
399
|
+
cs.push(path.join(root, "wake", fname));
|
|
400
|
+
cs.push(
|
|
401
|
+
path.join(
|
|
402
|
+
__dirname,
|
|
403
|
+
"..",
|
|
404
|
+
"..",
|
|
405
|
+
"..",
|
|
406
|
+
"..",
|
|
407
|
+
"..",
|
|
408
|
+
"packages/native/plugins/wakeword-cpp/build/wakeword",
|
|
409
|
+
fname,
|
|
410
|
+
),
|
|
411
|
+
);
|
|
412
|
+
return cs;
|
|
413
|
+
};
|
|
414
|
+
const melspec = firstExisting(ggufCandidates("melspec"));
|
|
415
|
+
const embedding = firstExisting(ggufCandidates("embedding"));
|
|
416
|
+
const classifier = firstExisting(ggufCandidates("classifier"));
|
|
417
|
+
if (!melspec || !embedding || !classifier) return null;
|
|
418
|
+
|
|
419
|
+
return { libraryPath, melspec, embedding, classifier, head };
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Open a wake-word session, preferring the fused `libelizainference`
|
|
424
|
+
* wake-word path (the single native engine the whole voice pipeline runs
|
|
425
|
+
* through — the user directive: no separate bun:ffi-musl libs). Falls back to
|
|
426
|
+
* the standalone `wakeword-cpp` build only when the fused build does not carry
|
|
427
|
+
* the wake-word GGUF. Returns `null` when neither provider can serve a session.
|
|
428
|
+
*
|
|
429
|
+
* Provider order:
|
|
430
|
+
* 1. `GgmlWakeWordModel` (this file) — the fused-`libelizainference` path
|
|
431
|
+
* that consumes `wake/openwakeword.gguf` from the bundle cache via the
|
|
432
|
+
* `eliza_inference_wakeword_*` ABI. Tried first whenever the bundled GGUF
|
|
433
|
+
* is on disk; uses the same `ffi`/`ctx` as VAD / speaker / TTS / ASR.
|
|
434
|
+
* 2. `OpenWakeWordGgmlModel` from `./wake-word-ggml.ts` — the standalone
|
|
435
|
+
* `packages/native/plugins/wakeword-cpp` build (three GGUFs). Guarded
|
|
436
|
+
* fallback for paths where the fused build lacks the wake-word runtime.
|
|
437
|
+
*
|
|
438
|
+
* `ffi` and `ctx` come from the voice lifecycle — they are the same
|
|
439
|
+
* `ElizaInferenceFfi` handle and context the VAD / speaker / TTS / ASR paths
|
|
440
|
+
* use. The standalone fallback uses neither.
|
|
441
|
+
*/
|
|
442
|
+
export async function loadBundledWakeWordModel(opts: {
|
|
443
|
+
ffi: ElizaInferenceFfi;
|
|
444
|
+
ctx: ElizaInferenceContextHandle | (() => ElizaInferenceContextHandle);
|
|
445
|
+
bundleRoot?: string;
|
|
446
|
+
head?: string;
|
|
447
|
+
}): Promise<WakeWordModel | null> {
|
|
448
|
+
const paths = resolveWakeWordModel({
|
|
449
|
+
...(opts.bundleRoot !== undefined ? { bundleRoot: opts.bundleRoot } : {}),
|
|
450
|
+
...(opts.head !== undefined ? { head: opts.head } : {}),
|
|
451
|
+
});
|
|
452
|
+
if (paths && GgmlWakeWordModel.isSupported(opts.ffi)) {
|
|
453
|
+
return GgmlWakeWordModel.load({
|
|
454
|
+
ffi: opts.ffi,
|
|
455
|
+
ctx: opts.ctx,
|
|
456
|
+
headName: paths.head,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Fused build lacks the wake-word GGUF/runtime — fall back to the standalone
|
|
461
|
+
// wakeword-cpp build when its library + three GGUFs are present.
|
|
462
|
+
const standalone = resolveWakeWordStandalonePaths({
|
|
463
|
+
...(opts.bundleRoot !== undefined ? { bundleRoot: opts.bundleRoot } : {}),
|
|
464
|
+
...(opts.head !== undefined ? { head: opts.head } : {}),
|
|
465
|
+
});
|
|
466
|
+
if (standalone) {
|
|
467
|
+
try {
|
|
468
|
+
return await OpenWakeWordGgmlModel.load({
|
|
469
|
+
libraryPath: standalone.libraryPath,
|
|
470
|
+
paths: {
|
|
471
|
+
melspec: standalone.melspec,
|
|
472
|
+
embedding: standalone.embedding,
|
|
473
|
+
classifier: standalone.classifier,
|
|
474
|
+
},
|
|
475
|
+
});
|
|
476
|
+
} catch (err) {
|
|
477
|
+
if (
|
|
478
|
+
err instanceof WakeWordGgmlUnavailableError &&
|
|
479
|
+
err.code === "not-bun"
|
|
480
|
+
) {
|
|
481
|
+
/* The standalone path needs Bun for `bun:ffi`; under Node
|
|
482
|
+
* we fall through to the fused path below. */
|
|
483
|
+
} else {
|
|
484
|
+
throw err;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Last resort: the fused GGUF is present but the build did not advertise
|
|
490
|
+
// support — let GgmlWakeWordModel.load surface the structured
|
|
491
|
+
// runtime-not-ready error rather than silently returning null.
|
|
492
|
+
if (!paths) return null;
|
|
493
|
+
return GgmlWakeWordModel.load({
|
|
494
|
+
ffi: opts.ffi,
|
|
495
|
+
ctx: opts.ctx,
|
|
496
|
+
headName: paths.head,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Streaming wake-word detector. Feed frames; `onWake` fires once per
|
|
502
|
+
* detected utterance (refractory-debounced). The voice loop wires
|
|
503
|
+
* `onWake` to "start a listening window" — exactly what a push-to-talk
|
|
504
|
+
* press does.
|
|
505
|
+
*
|
|
506
|
+
* Only constructed in `local` mode. `cloud` mode never instantiates this
|
|
507
|
+
* (and `resolveWakeWordModel` is never called there), so the surface is
|
|
508
|
+
* inert per the hide-not-disable rule.
|
|
509
|
+
*/
|
|
510
|
+
export class OpenWakeWordDetector {
|
|
511
|
+
private readonly model: WakeWordModel;
|
|
512
|
+
private readonly cfg: Required<WakeWordConfig>;
|
|
513
|
+
private cooldown = 0;
|
|
514
|
+
private readonly onWake: () => void;
|
|
515
|
+
|
|
516
|
+
constructor(args: {
|
|
517
|
+
model: WakeWordModel;
|
|
518
|
+
config?: WakeWordConfig;
|
|
519
|
+
onWake: () => void;
|
|
520
|
+
}) {
|
|
521
|
+
this.model = args.model;
|
|
522
|
+
this.cfg = { ...DEFAULTS, ...(args.config ?? {}) };
|
|
523
|
+
this.onWake = args.onWake;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Score one PCM frame; fire `onWake` on a fresh detection. Resolves
|
|
528
|
+
* to true when this frame fired the wake word.
|
|
529
|
+
*/
|
|
530
|
+
async pushFrame(frame: Float32Array): Promise<boolean> {
|
|
531
|
+
if (frame.length !== this.model.frameSamples) {
|
|
532
|
+
throw new Error(
|
|
533
|
+
`[wake-word] frame has ${frame.length} samples, expected ${this.model.frameSamples}`,
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
if (this.cooldown > 0) {
|
|
537
|
+
this.cooldown--;
|
|
538
|
+
await this.model.scoreFrame(frame); // keep the streaming state warm
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
const p = await this.model.scoreFrame(frame);
|
|
542
|
+
if (p >= this.cfg.threshold) {
|
|
543
|
+
this.cooldown = this.cfg.refractoryFrames;
|
|
544
|
+
this.onWake();
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
reset(): void {
|
|
551
|
+
this.model.reset();
|
|
552
|
+
this.cooldown = 0;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrap a TTS model handler (`ModelType.TEXT_TO_SPEECH`) with the
|
|
3
|
+
* `FirstLineCache` disk-tier.
|
|
4
|
+
*
|
|
5
|
+
* Behaviour on a wrapped handler call:
|
|
6
|
+
* 1. Snip the first sentence of the input text. Reject if > 10 words or
|
|
7
|
+
* no terminator found → defer to the inner handler unchanged.
|
|
8
|
+
* 2. Build the cache key from the snip + caller-supplied
|
|
9
|
+
* `(provider, voiceId, voiceRevision, codec, voiceSettingsFingerprint)`.
|
|
10
|
+
* 3. On hit: if the snip is the WHOLE input, return cached bytes. If the
|
|
11
|
+
* snip is only a prefix, return `cachedBytes ++ synthesize(remainder)`.
|
|
12
|
+
* The concat path is safe for the codecs we cache today (mp3, opus,
|
|
13
|
+
* ogg are self-framed; wav/pcm_f32 are not, and the wrapper falls
|
|
14
|
+
* through for those).
|
|
15
|
+
* 4. On miss: call the inner handler with the full input, return that.
|
|
16
|
+
* In the background, call the inner handler with JUST the snip to get
|
|
17
|
+
* a cleanly-framed cache entry (no mid-stream-byte alignment hazards).
|
|
18
|
+
*
|
|
19
|
+
* The wrapper is provider-agnostic — `WrapOptions.resolveContext` is the
|
|
20
|
+
* single seam where each TTS plugin teaches the cache its provider name +
|
|
21
|
+
* voice id + revision + voice-settings fingerprint.
|
|
22
|
+
*/
|
|
23
|
+
import type { IAgentRuntime } from "@elizaos/core";
|
|
24
|
+
import { type FirstLineCache, type FirstLineCacheKey } from "./first-line-cache";
|
|
25
|
+
export type TtsBytes = Uint8Array | ArrayBuffer | Buffer;
|
|
26
|
+
export type TtsHandlerInput = string | {
|
|
27
|
+
text: string;
|
|
28
|
+
[k: string]: unknown;
|
|
29
|
+
};
|
|
30
|
+
export type TtsHandlerOutput = TtsBytes;
|
|
31
|
+
export type TtsHandler = (runtime: IAgentRuntime, input: TtsHandlerInput) => Promise<TtsHandlerOutput>;
|
|
32
|
+
/** Caller-supplied context resolver — provider name + voice metadata. */
|
|
33
|
+
export interface TtsResolvedContext {
|
|
34
|
+
provider: string;
|
|
35
|
+
voiceId: string;
|
|
36
|
+
voiceRevision: string;
|
|
37
|
+
codec: FirstLineCacheKey["codec"];
|
|
38
|
+
contentType: string;
|
|
39
|
+
sampleRate: number;
|
|
40
|
+
voiceSettingsFingerprint: string;
|
|
41
|
+
/** Optional: if true, bypass the cache entirely on this call. */
|
|
42
|
+
bypass?: boolean;
|
|
43
|
+
}
|
|
44
|
+
export interface WrapOptions {
|
|
45
|
+
/** Inject for tests. */
|
|
46
|
+
cache?: FirstLineCache;
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the per-call provider/voice context. Must be cheap (typically
|
|
49
|
+
* a settings read + a small sha256). Return `null` to bypass the cache.
|
|
50
|
+
*/
|
|
51
|
+
resolveContext: (runtime: IAgentRuntime, input: TtsHandlerInput) => Promise<TtsResolvedContext | null> | TtsResolvedContext | null;
|
|
52
|
+
/**
|
|
53
|
+
* Whether to attempt to concatenate cached bytes + remainder synthesis.
|
|
54
|
+
* Defaults to true for mp3/opus/ogg, false for wav/pcm_f32 (concat would
|
|
55
|
+
* corrupt the RIFF / raw stream).
|
|
56
|
+
*/
|
|
57
|
+
concatRemainder?: boolean;
|
|
58
|
+
/** Optional pre-resolved fingerprint of voiceSettings; rarely needed. */
|
|
59
|
+
enableCachePopulation?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Wrap a TTS handler with first-sentence caching. Returns a new handler with
|
|
63
|
+
* the same signature.
|
|
64
|
+
*
|
|
65
|
+
* The wrapper is safe to apply at runtime registration time — if the cache
|
|
66
|
+
* is disabled (env / no sqlite), the wrapper short-circuits to the inner
|
|
67
|
+
* handler with zero overhead beyond a snip attempt.
|
|
68
|
+
*/
|
|
69
|
+
export declare function wrapWithFirstLineCache(inner: TtsHandler, options: WrapOptions): TtsHandler;
|
|
70
|
+
//# sourceMappingURL=wrap-with-first-line-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap-with-first-line-cache.d.ts","sourceRoot":"","sources":["wrap-with-first-line-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAOnD,OAAO,EACN,KAAK,cAAc,EAEnB,KAAK,iBAAiB,EAGtB,MAAM,oBAAoB,CAAC;AAM5B,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,CAAC;AACzD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAC9E,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AACxC,MAAM,MAAM,UAAU,GAAG,CACxB,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,eAAe,KAClB,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAE/B,yEAAyE;AACzE,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,wBAAwB,EAAE,MAAM,CAAC;IACjC,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC3B,wBAAwB;IACxB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB;;;OAGG;IACH,cAAc,EAAE,CACf,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,eAAe,KAClB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,kBAAkB,GAAG,IAAI,CAAC;IACpE;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,yEAAyE;IACzE,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC;AA2CD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,WAAW,GAClB,UAAU,CAgEZ"}
|