@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,101 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_OPTIMISTIC_EOT_THRESHOLD,
|
|
4
|
+
OptimisticGenerationPolicy,
|
|
5
|
+
resolveOptimisticPolicyEnabled,
|
|
6
|
+
} from "./optimistic-policy";
|
|
7
|
+
|
|
8
|
+
describe("resolveOptimisticPolicyEnabled — pure", () => {
|
|
9
|
+
it("override:true wins regardless of power source", () => {
|
|
10
|
+
expect(
|
|
11
|
+
resolveOptimisticPolicyEnabled({
|
|
12
|
+
powerSource: "battery",
|
|
13
|
+
override: true,
|
|
14
|
+
}),
|
|
15
|
+
).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("override:false wins regardless of power source", () => {
|
|
19
|
+
expect(
|
|
20
|
+
resolveOptimisticPolicyEnabled({
|
|
21
|
+
powerSource: "plugged-in",
|
|
22
|
+
override: false,
|
|
23
|
+
}),
|
|
24
|
+
).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("battery without override → false", () => {
|
|
28
|
+
expect(resolveOptimisticPolicyEnabled({ powerSource: "battery" })).toBe(
|
|
29
|
+
false,
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("plugged-in without override → true", () => {
|
|
34
|
+
expect(resolveOptimisticPolicyEnabled({ powerSource: "plugged-in" })).toBe(
|
|
35
|
+
true,
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("unknown power source defaults to true", () => {
|
|
40
|
+
expect(resolveOptimisticPolicyEnabled({ powerSource: "unknown" })).toBe(
|
|
41
|
+
true,
|
|
42
|
+
);
|
|
43
|
+
expect(resolveOptimisticPolicyEnabled({})).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("OptimisticGenerationPolicy", () => {
|
|
48
|
+
it("defaults: enabled, threshold = DEFAULT", () => {
|
|
49
|
+
const p = new OptimisticGenerationPolicy();
|
|
50
|
+
expect(p.enabled()).toBe(true);
|
|
51
|
+
expect(p.threshold).toBe(DEFAULT_OPTIMISTIC_EOT_THRESHOLD);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("battery flips enabled() to false", () => {
|
|
55
|
+
const p = new OptimisticGenerationPolicy();
|
|
56
|
+
p.setPowerSource("battery");
|
|
57
|
+
expect(p.enabled()).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("explicit override true wins on battery", () => {
|
|
61
|
+
const p = new OptimisticGenerationPolicy();
|
|
62
|
+
p.setPowerSource("battery");
|
|
63
|
+
p.setOverride(true);
|
|
64
|
+
expect(p.enabled()).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("override:false wins on plugged-in", () => {
|
|
68
|
+
const p = new OptimisticGenerationPolicy();
|
|
69
|
+
p.setPowerSource("plugged-in");
|
|
70
|
+
p.setOverride(false);
|
|
71
|
+
expect(p.enabled()).toBe(false);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("shouldStartOptimisticLm gates on EOT threshold", () => {
|
|
75
|
+
const p = new OptimisticGenerationPolicy({ eotThreshold: 0.7 });
|
|
76
|
+
expect(p.shouldStartOptimisticLm(0.5)).toBe(false);
|
|
77
|
+
expect(p.shouldStartOptimisticLm(0.7)).toBe(true);
|
|
78
|
+
expect(p.shouldStartOptimisticLm(0.95)).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("shouldStartOptimisticLm returns false when disabled regardless of probability", () => {
|
|
82
|
+
const p = new OptimisticGenerationPolicy();
|
|
83
|
+
p.setPowerSource("battery");
|
|
84
|
+
expect(p.shouldStartOptimisticLm(0.99)).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("override clears back to default with undefined", () => {
|
|
88
|
+
const p = new OptimisticGenerationPolicy();
|
|
89
|
+
p.setOverride(false);
|
|
90
|
+
expect(p.enabled()).toBe(false);
|
|
91
|
+
p.setOverride(undefined);
|
|
92
|
+
expect(p.enabled()).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("constructor defaultEnabled=false flips the base policy", () => {
|
|
96
|
+
const p = new OptimisticGenerationPolicy({ defaultEnabled: false });
|
|
97
|
+
expect(p.enabled()).toBe(false);
|
|
98
|
+
p.setOverride(true);
|
|
99
|
+
expect(p.enabled()).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optimistic-generation policy — Wave 3 W3-9.
|
|
3
|
+
*
|
|
4
|
+
* Decides whether the LM should fire optimistically the moment the turn
|
|
5
|
+
* detector crosses the EOT threshold (before the audio buffer is fully
|
|
6
|
+
* drained), or wait for the full hangover. Per the user spec:
|
|
7
|
+
*
|
|
8
|
+
* > "We want to optimize to start running and checking basically the
|
|
9
|
+
* second there is no audio / voice detected, and then we start
|
|
10
|
+
* optimistically processing, and if the user starts talking again we
|
|
11
|
+
* kill and add to the conversation and start reprocessing."
|
|
12
|
+
*
|
|
13
|
+
* Default heuristic:
|
|
14
|
+
* - Plugged-in (or power state unknown): optimistic = true.
|
|
15
|
+
* - On battery: optimistic = false (the extra forward pass burns
|
|
16
|
+
* joules every false-positive EOT).
|
|
17
|
+
*
|
|
18
|
+
* Callers (notably `VoiceStateMachine`) read `shouldStartOptimisticLm()`
|
|
19
|
+
* each time they consider firing the speculative drafter. The policy can be
|
|
20
|
+
* mutated at runtime via `setOptimisticOverride()` so a Settings UI toggle
|
|
21
|
+
* or a per-session env var can pin the value without restarting the engine.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/** Power-source signal. `unknown` is treated as "plugged in" for the
|
|
25
|
+
* default policy (a desktop without battery telemetry). */
|
|
26
|
+
export type PowerSourceState = "plugged-in" | "battery" | "unknown";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the current power-source state.
|
|
30
|
+
*
|
|
31
|
+
* Production callers (engine bridge) prime the optimistic policy with this
|
|
32
|
+
* once at session start. There is no canonical power-source accessor in
|
|
33
|
+
* `device-tier.ts` (the hardware probe records RAM / GPU / cores but no
|
|
34
|
+
* battery telemetry), so this resolver consults two cheap signals:
|
|
35
|
+
*
|
|
36
|
+
* 1. `ELIZA_VOICE_POWER_SOURCE` env var (`"plugged-in" | "battery" |
|
|
37
|
+
* "unknown"`). Wins outright when set — operators / Settings can pin
|
|
38
|
+
* the policy without restarting the engine.
|
|
39
|
+
* 2. Linux `/sys/class/power_supply` AC online status when available
|
|
40
|
+
* synchronously. Returns `"plugged-in"` when any AC adapter reports
|
|
41
|
+
* `online`, `"battery"` when only batteries are present and none
|
|
42
|
+
* report online, `"unknown"` otherwise.
|
|
43
|
+
*
|
|
44
|
+
* macOS / Windows / mobile go through `"unknown"` here — the desktop probe
|
|
45
|
+
* surfaces those via the Electrobun side and Settings overrides it through
|
|
46
|
+
* (1). The default heuristic (`unknown → enabled`) treats those as
|
|
47
|
+
* plugged-in for the optimistic gate, which is the right default for
|
|
48
|
+
* desktop / dev (battery-aware mobile builds set the override explicitly).
|
|
49
|
+
*/
|
|
50
|
+
export function resolvePowerSourceState(): PowerSourceState {
|
|
51
|
+
const fromEnv = process.env.ELIZA_VOICE_POWER_SOURCE?.trim().toLowerCase();
|
|
52
|
+
if (
|
|
53
|
+
fromEnv === "plugged-in" ||
|
|
54
|
+
fromEnv === "battery" ||
|
|
55
|
+
fromEnv === "unknown"
|
|
56
|
+
) {
|
|
57
|
+
return fromEnv;
|
|
58
|
+
}
|
|
59
|
+
if (process.platform === "linux") {
|
|
60
|
+
try {
|
|
61
|
+
// Lazy require so this module stays free of node-fs imports for
|
|
62
|
+
// non-linux platforms / browser bundlers.
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
64
|
+
const fs = require("node:fs") as typeof import("node:fs");
|
|
65
|
+
const base = "/sys/class/power_supply";
|
|
66
|
+
if (!fs.existsSync(base)) return "unknown";
|
|
67
|
+
const entries = fs.readdirSync(base);
|
|
68
|
+
let sawBattery = false;
|
|
69
|
+
for (const entry of entries) {
|
|
70
|
+
const typePath = `${base}/${entry}/type`;
|
|
71
|
+
if (!fs.existsSync(typePath)) continue;
|
|
72
|
+
const type = fs.readFileSync(typePath, "utf8").trim();
|
|
73
|
+
if (type === "Mains") {
|
|
74
|
+
const onlinePath = `${base}/${entry}/online`;
|
|
75
|
+
if (
|
|
76
|
+
fs.existsSync(onlinePath) &&
|
|
77
|
+
fs.readFileSync(onlinePath, "utf8").trim() === "1"
|
|
78
|
+
) {
|
|
79
|
+
return "plugged-in";
|
|
80
|
+
}
|
|
81
|
+
} else if (type === "Battery") {
|
|
82
|
+
sawBattery = true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return sawBattery ? "battery" : "unknown";
|
|
86
|
+
} catch {
|
|
87
|
+
return "unknown";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return "unknown";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface OptimisticPolicyOptions {
|
|
94
|
+
/**
|
|
95
|
+
* Default value when no override is set. Resolved from the device tier
|
|
96
|
+
* at construction time (per the user spec: true on plugged-in,
|
|
97
|
+
* false on battery). Defaults to `true` when no power signal is given.
|
|
98
|
+
*/
|
|
99
|
+
defaultEnabled?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* The threshold the turn detector's EOT probability must clear before
|
|
102
|
+
* the optimistic LM start fires. Mirrors `EOT_TENTATIVE_THRESHOLD`
|
|
103
|
+
* (the existing default) but is configurable per-policy so tier-aware
|
|
104
|
+
* deployments can tighten it on slower devices.
|
|
105
|
+
*/
|
|
106
|
+
eotThreshold?: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface ResolveOptimisticPolicyArgs {
|
|
110
|
+
powerSource?: PowerSourceState;
|
|
111
|
+
/**
|
|
112
|
+
* Explicit override. When set, wins over both the default and the
|
|
113
|
+
* power-source heuristic. Sourced from `voice.optimisticGenerationOnEot`
|
|
114
|
+
* in user settings (Wave 3C).
|
|
115
|
+
*/
|
|
116
|
+
override?: boolean;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export const DEFAULT_OPTIMISTIC_EOT_THRESHOLD = 0.6;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Pure resolver. Takes the power source + an optional override and returns
|
|
123
|
+
* whether optimistic LM start should fire.
|
|
124
|
+
*/
|
|
125
|
+
export function resolveOptimisticPolicyEnabled(
|
|
126
|
+
args: ResolveOptimisticPolicyArgs,
|
|
127
|
+
): boolean {
|
|
128
|
+
if (typeof args.override === "boolean") return args.override;
|
|
129
|
+
if (args.powerSource === "battery") return false;
|
|
130
|
+
// plugged-in OR unknown OR undefined → enabled (safer default for
|
|
131
|
+
// desktop / dev where power telemetry isn't surfaced).
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Mutable runtime policy. The voice state machine asks
|
|
137
|
+
* `policy.shouldStartOptimisticLm(eotProb)` before firing the drafter.
|
|
138
|
+
*
|
|
139
|
+
* Reasoning for a class rather than a free function: at runtime we need
|
|
140
|
+
* the override + the power source to be hot-swappable from Settings or a
|
|
141
|
+
* device-event listener (battery state change) without re-plumbing the
|
|
142
|
+
* machine.
|
|
143
|
+
*/
|
|
144
|
+
export class OptimisticGenerationPolicy {
|
|
145
|
+
private overrideValue: boolean | undefined;
|
|
146
|
+
private powerSource: PowerSourceState;
|
|
147
|
+
private readonly defaultEnabled: boolean;
|
|
148
|
+
private readonly eotThreshold: number;
|
|
149
|
+
|
|
150
|
+
constructor(opts: OptimisticPolicyOptions = {}) {
|
|
151
|
+
this.defaultEnabled = opts.defaultEnabled ?? true;
|
|
152
|
+
this.eotThreshold = opts.eotThreshold ?? DEFAULT_OPTIMISTIC_EOT_THRESHOLD;
|
|
153
|
+
this.powerSource = "unknown";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Update the power source (called by the device-tier observer). */
|
|
157
|
+
setPowerSource(state: PowerSourceState): void {
|
|
158
|
+
this.powerSource = state;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Set / clear the user override. */
|
|
162
|
+
setOverride(value: boolean | undefined): void {
|
|
163
|
+
this.overrideValue = value;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Resolve "should we be optimistic right now?". */
|
|
167
|
+
enabled(): boolean {
|
|
168
|
+
// Explicit user override wins outright.
|
|
169
|
+
if (typeof this.overrideValue === "boolean") return this.overrideValue;
|
|
170
|
+
// No override: apply the battery heuristic on top of `defaultEnabled`.
|
|
171
|
+
// `defaultEnabled=false` pins the policy off regardless of power source;
|
|
172
|
+
// `defaultEnabled=true` enables it on plugged-in / unknown and disables
|
|
173
|
+
// it on battery.
|
|
174
|
+
if (!this.defaultEnabled) return false;
|
|
175
|
+
return resolveOptimisticPolicyEnabled({ powerSource: this.powerSource });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Combined gate: the policy must be enabled AND the EOT probability
|
|
180
|
+
* must clear the policy's threshold. This is the canonical check the
|
|
181
|
+
* voice state machine calls before firing the drafter on a partial
|
|
182
|
+
* transcript.
|
|
183
|
+
*/
|
|
184
|
+
shouldStartOptimisticLm(eotProb: number): boolean {
|
|
185
|
+
if (!this.enabled()) return false;
|
|
186
|
+
return eotProb >= this.eotThreshold;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
get threshold(): number {
|
|
190
|
+
return this.eotThreshold;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optimistic-decode-with-rollback controller for the voice loop.
|
|
3
|
+
*
|
|
4
|
+
* IDLE
|
|
5
|
+
* │ speech-start
|
|
6
|
+
* ▼
|
|
7
|
+
* LISTENING
|
|
8
|
+
* │ speech-pause
|
|
9
|
+
* ▼
|
|
10
|
+
* PAUSE_TENTATIVE ── speech-active (within rollback window) ──▶ LISTENING
|
|
11
|
+
* │ ▲
|
|
12
|
+
* │ speech-end (or pause > rollback window) │
|
|
13
|
+
* ▼ │
|
|
14
|
+
* DRAFT_RESPONSE ──── speech-active (within rollback window) ──────┘
|
|
15
|
+
* │ (restore checkpoint, abort drafter)
|
|
16
|
+
* │ commit
|
|
17
|
+
* ▼
|
|
18
|
+
* COMMITTED → IDLE
|
|
19
|
+
*
|
|
20
|
+
* On `speech-pause` we snapshot the slot's KV state (`C1-<turn-id>`) and
|
|
21
|
+
* speculatively start the drafter against the partial transcript so that
|
|
22
|
+
* when the user IS done, the response is already underway. If they resume
|
|
23
|
+
* within the rollback window (~2× pause hangover), we restore the snapshot
|
|
24
|
+
* and abort the speculative draft — net cost is one checkpoint write/read.
|
|
25
|
+
*
|
|
26
|
+
* This module deliberately does NOT modify `turn-controller.ts`,
|
|
27
|
+
* `vad.ts`, `scheduler.ts`, `phrase-chunker.ts`, `barge-in.ts`, `pipeline.ts`,
|
|
28
|
+
* `pipeline-impls.ts`, or `transcriber.ts` — those are owned elsewhere.
|
|
29
|
+
* Instead, the turn controller composes this controller after the upstream
|
|
30
|
+
* llama.cpp merge lands and the feature flag flips.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import type { CheckpointClient, CheckpointHandle } from "../checkpoint-client";
|
|
34
|
+
import type { VadEvent, VadEventSource } from "./types";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* State of the optimistic-rollback controller. Mirrors the comment-block
|
|
38
|
+
* state machine above; exported so tests and telemetry can assert on it.
|
|
39
|
+
*/
|
|
40
|
+
export type OptimisticRollbackState =
|
|
41
|
+
| "idle"
|
|
42
|
+
| "listening"
|
|
43
|
+
| "pause-tentative"
|
|
44
|
+
| "draft-response"
|
|
45
|
+
| "committed";
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Telemetry event stream. Stays narrow — the controller emits exactly four
|
|
49
|
+
* lifecycle events per turn (save, restore-or-commit, draft-start,
|
|
50
|
+
* draft-abort). Consumers wire these into the existing voice-bench
|
|
51
|
+
* trajectory captures.
|
|
52
|
+
*/
|
|
53
|
+
export interface OptimisticRollbackTelemetry {
|
|
54
|
+
onCheckpointSaved?: (handle: CheckpointHandle, turnId: string) => void;
|
|
55
|
+
onCheckpointRestored?: (handle: CheckpointHandle, turnId: string) => void;
|
|
56
|
+
onSpeculativeDraftStarted?: (turnId: string) => void;
|
|
57
|
+
onSpeculativeDraftAborted?: (turnId: string, reason: AbortReason) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Fired when the controller silently swallows an error from the
|
|
60
|
+
* checkpoint client — surfacing it via telemetry rather than rethrowing
|
|
61
|
+
* keeps a failing checkpoint endpoint from breaking the voice loop. The
|
|
62
|
+
* caller decides whether to flip the feature flag off.
|
|
63
|
+
*/
|
|
64
|
+
onCheckpointError?: (
|
|
65
|
+
op: "save" | "restore" | "cancel",
|
|
66
|
+
error: unknown,
|
|
67
|
+
turnId: string,
|
|
68
|
+
) => void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type AbortReason = "resumed" | "committed" | "shutdown";
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Speculative drafter handle. The voice turn controller hands one of these
|
|
75
|
+
* in when starting the drafter so this module can abort it without
|
|
76
|
+
* importing the drafter's internals. `abort()` MUST be idempotent — the
|
|
77
|
+
* controller may call it again on shutdown.
|
|
78
|
+
*/
|
|
79
|
+
export interface SpeculativeDraftHandle {
|
|
80
|
+
abort(): void;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Caller-supplied drafter starter. Returns a handle the controller can
|
|
85
|
+
* abort. Called on entry to `pause-tentative`. The promise must resolve
|
|
86
|
+
* synchronously (or near-synchronously) — the speculative draft runs in
|
|
87
|
+
* the background.
|
|
88
|
+
*/
|
|
89
|
+
export type StartSpeculativeDraft = (
|
|
90
|
+
partialTranscript: string,
|
|
91
|
+
turnId: string,
|
|
92
|
+
) => SpeculativeDraftHandle;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Caller-supplied source for the partial transcript captured at the
|
|
96
|
+
* `speech-pause` instant. Kept as a function so the controller doesn't
|
|
97
|
+
* have to hold a reference to the transcriber.
|
|
98
|
+
*/
|
|
99
|
+
export type ReadPartialTranscript = () => string;
|
|
100
|
+
|
|
101
|
+
export interface OptimisticRollbackControllerOptions {
|
|
102
|
+
/** The slot id the voice loop is pinned to for this turn. */
|
|
103
|
+
slotId: number;
|
|
104
|
+
/**
|
|
105
|
+
* Per-process feature flag. Defaults to `false` — flip on once the
|
|
106
|
+
* upstream `--ctx-checkpoints` merge lands AND the rollout plan in
|
|
107
|
+
* `docs/eliza-1-optimistic-rollback.md` reaches the desired bucket.
|
|
108
|
+
* Forwards every VAD event to the wrapped state machine when off but
|
|
109
|
+
* never makes a checkpoint REST call.
|
|
110
|
+
*/
|
|
111
|
+
enableOptimisticRollback?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* VAD pause hangover (ms). Default 100 ms (lowered from 220ms; further
|
|
114
|
+
* reduction gated on semantic EOT classifier V2) — matches the voice
|
|
115
|
+
* loop's standard hangover. The rollback window is `2 ×` this value.
|
|
116
|
+
*/
|
|
117
|
+
pauseHangoverMs?: number;
|
|
118
|
+
/** Source of VAD events; usually `VadDetector`. */
|
|
119
|
+
vadSource: VadEventSource;
|
|
120
|
+
client: CheckpointClient;
|
|
121
|
+
startSpeculativeDraft: StartSpeculativeDraft;
|
|
122
|
+
readPartialTranscript: ReadPartialTranscript;
|
|
123
|
+
telemetry?: OptimisticRollbackTelemetry;
|
|
124
|
+
/**
|
|
125
|
+
* Wall-clock function. Injected for tests; defaults to `Date.now`. The
|
|
126
|
+
* controller uses this to enforce the rollback window — if a
|
|
127
|
+
* `speech-active` arrives more than `2 × pauseHangoverMs` after the
|
|
128
|
+
* `speech-pause`, the controller commits rather than restores.
|
|
129
|
+
*/
|
|
130
|
+
now?: () => number;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Lowered from 220ms; further reduction gated on semantic EOT classifier (V2).
|
|
134
|
+
const DEFAULT_PAUSE_HANGOVER_MS = 100;
|
|
135
|
+
/** Rollback window = ROLLBACK_WINDOW_MULTIPLIER × pauseHangoverMs. */
|
|
136
|
+
const ROLLBACK_WINDOW_MULTIPLIER = 2;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Optimistic-rollback controller. Subscribes to a `VadEventSource` and
|
|
140
|
+
* drives the checkpoint REST client + a caller-supplied speculative
|
|
141
|
+
* drafter. Idempotent `dispose()` for clean shutdown.
|
|
142
|
+
*/
|
|
143
|
+
export class OptimisticRollbackController {
|
|
144
|
+
private state: OptimisticRollbackState = "idle";
|
|
145
|
+
private currentTurnId = 0;
|
|
146
|
+
private pauseTimestampMs: number | null = null;
|
|
147
|
+
private currentCheckpoint: CheckpointHandle | null = null;
|
|
148
|
+
private currentDraft: SpeculativeDraftHandle | null = null;
|
|
149
|
+
private readonly unsubscribe: () => void;
|
|
150
|
+
private readonly enabled: boolean;
|
|
151
|
+
private readonly pauseHangoverMs: number;
|
|
152
|
+
private readonly slotId: number;
|
|
153
|
+
private readonly client: CheckpointClient;
|
|
154
|
+
private readonly startSpeculativeDraft: StartSpeculativeDraft;
|
|
155
|
+
private readonly readPartialTranscript: ReadPartialTranscript;
|
|
156
|
+
private readonly telemetry: OptimisticRollbackTelemetry;
|
|
157
|
+
private readonly now: () => number;
|
|
158
|
+
private disposed = false;
|
|
159
|
+
|
|
160
|
+
constructor(opts: OptimisticRollbackControllerOptions) {
|
|
161
|
+
this.slotId = opts.slotId;
|
|
162
|
+
this.enabled = opts.enableOptimisticRollback ?? false;
|
|
163
|
+
this.pauseHangoverMs = opts.pauseHangoverMs ?? DEFAULT_PAUSE_HANGOVER_MS;
|
|
164
|
+
this.client = opts.client;
|
|
165
|
+
this.startSpeculativeDraft = opts.startSpeculativeDraft;
|
|
166
|
+
this.readPartialTranscript = opts.readPartialTranscript;
|
|
167
|
+
this.telemetry = opts.telemetry ?? {};
|
|
168
|
+
this.now = opts.now ?? Date.now;
|
|
169
|
+
this.unsubscribe = opts.vadSource.onVadEvent((event) =>
|
|
170
|
+
this.handleVadEvent(event),
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Current state — read-only view for tests / telemetry. */
|
|
175
|
+
getState(): OptimisticRollbackState {
|
|
176
|
+
return this.state;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Detach from the VAD source and abort any in-flight speculative draft.
|
|
181
|
+
* Safe to call multiple times.
|
|
182
|
+
*/
|
|
183
|
+
dispose(): void {
|
|
184
|
+
if (this.disposed) return;
|
|
185
|
+
this.disposed = true;
|
|
186
|
+
this.unsubscribe();
|
|
187
|
+
if (this.currentDraft) {
|
|
188
|
+
this.currentDraft.abort();
|
|
189
|
+
this.telemetry.onSpeculativeDraftAborted?.(
|
|
190
|
+
this.turnIdString(),
|
|
191
|
+
"shutdown",
|
|
192
|
+
);
|
|
193
|
+
this.currentDraft = null;
|
|
194
|
+
}
|
|
195
|
+
if (this.currentCheckpoint && this.enabled) {
|
|
196
|
+
// Best-effort cancellation of any in-flight decode on the slot. We do
|
|
197
|
+
// NOT delete the snapshot file — upstream evicts on slot reuse, and a
|
|
198
|
+
// dangling snapshot is cheap. Errors here are swallowed (the loop is
|
|
199
|
+
// shutting down) but surfaced via telemetry.
|
|
200
|
+
this.client
|
|
201
|
+
.cancelSlot(this.slotId)
|
|
202
|
+
.catch((error: unknown) =>
|
|
203
|
+
this.telemetry.onCheckpointError?.(
|
|
204
|
+
"cancel",
|
|
205
|
+
error,
|
|
206
|
+
this.turnIdString(),
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
this.currentCheckpoint = null;
|
|
211
|
+
this.state = "idle";
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private handleVadEvent(event: VadEvent): void {
|
|
215
|
+
if (this.disposed) return;
|
|
216
|
+
switch (event.type) {
|
|
217
|
+
case "speech-start":
|
|
218
|
+
this.transitionToListening();
|
|
219
|
+
return;
|
|
220
|
+
case "speech-pause":
|
|
221
|
+
this.handleSpeechPause(event.timestampMs);
|
|
222
|
+
return;
|
|
223
|
+
case "speech-active":
|
|
224
|
+
this.handleSpeechActive(event.timestampMs);
|
|
225
|
+
return;
|
|
226
|
+
case "speech-end":
|
|
227
|
+
this.handleSpeechEnd();
|
|
228
|
+
return;
|
|
229
|
+
case "blip":
|
|
230
|
+
return;
|
|
231
|
+
default: {
|
|
232
|
+
// exhaustive — VadEvent is a closed union; if it gains a variant
|
|
233
|
+
// the compiler will flag this cast.
|
|
234
|
+
const _exhaustive: never = event;
|
|
235
|
+
void _exhaustive;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private transitionToListening(): void {
|
|
241
|
+
if (this.state === "idle") {
|
|
242
|
+
this.currentTurnId += 1;
|
|
243
|
+
}
|
|
244
|
+
this.state = "listening";
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private handleSpeechPause(timestampMs: number): void {
|
|
248
|
+
if (this.state !== "listening") return;
|
|
249
|
+
this.pauseTimestampMs = timestampMs;
|
|
250
|
+
if (!this.enabled) {
|
|
251
|
+
this.state = "pause-tentative";
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const turnId = this.turnIdString();
|
|
255
|
+
const filename = `C1-${turnId}`;
|
|
256
|
+
this.state = "pause-tentative";
|
|
257
|
+
void this.client
|
|
258
|
+
.saveCheckpoint(this.slotId, filename)
|
|
259
|
+
.then((handle) => {
|
|
260
|
+
if (this.state !== "pause-tentative") return;
|
|
261
|
+
this.currentCheckpoint = handle;
|
|
262
|
+
this.telemetry.onCheckpointSaved?.(handle, turnId);
|
|
263
|
+
this.startDraftIfStillPaused(turnId);
|
|
264
|
+
})
|
|
265
|
+
.catch((error: unknown) => {
|
|
266
|
+
this.telemetry.onCheckpointError?.("save", error, turnId);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private startDraftIfStillPaused(turnId: string): void {
|
|
271
|
+
if (this.state !== "pause-tentative") return;
|
|
272
|
+
const partial = this.readPartialTranscript();
|
|
273
|
+
this.currentDraft = this.startSpeculativeDraft(partial, turnId);
|
|
274
|
+
this.state = "draft-response";
|
|
275
|
+
this.telemetry.onSpeculativeDraftStarted?.(turnId);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private handleSpeechActive(timestampMs: number): void {
|
|
279
|
+
if (this.state !== "pause-tentative" && this.state !== "draft-response") {
|
|
280
|
+
// `listening → speech-active` is a heartbeat; ignore.
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const pauseAt = this.pauseTimestampMs;
|
|
284
|
+
if (pauseAt === null) {
|
|
285
|
+
this.state = "listening";
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const elapsed = timestampMs - pauseAt;
|
|
289
|
+
const rollbackWindowMs = this.pauseHangoverMs * ROLLBACK_WINDOW_MULTIPLIER;
|
|
290
|
+
if (elapsed > rollbackWindowMs) {
|
|
291
|
+
// Resumed too late to roll back — commit and let the drafter's
|
|
292
|
+
// output flow as the response.
|
|
293
|
+
this.commit();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
this.rollback("resumed");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private handleSpeechEnd(): void {
|
|
300
|
+
if (this.state === "pause-tentative" || this.state === "draft-response") {
|
|
301
|
+
this.commit();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
this.state = "idle";
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private rollback(reason: AbortReason): void {
|
|
308
|
+
const turnId = this.turnIdString();
|
|
309
|
+
if (this.currentDraft) {
|
|
310
|
+
this.currentDraft.abort();
|
|
311
|
+
this.telemetry.onSpeculativeDraftAborted?.(turnId, reason);
|
|
312
|
+
this.currentDraft = null;
|
|
313
|
+
}
|
|
314
|
+
if (this.enabled && this.currentCheckpoint) {
|
|
315
|
+
const handle = this.currentCheckpoint;
|
|
316
|
+
void this.client
|
|
317
|
+
.restoreCheckpoint(this.slotId, handle.filename)
|
|
318
|
+
.then(() => this.telemetry.onCheckpointRestored?.(handle, turnId))
|
|
319
|
+
.catch((error: unknown) => {
|
|
320
|
+
this.telemetry.onCheckpointError?.("restore", error, turnId);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
this.currentCheckpoint = null;
|
|
324
|
+
this.pauseTimestampMs = null;
|
|
325
|
+
this.state = "listening";
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private commit(): void {
|
|
329
|
+
// Commit drops the snapshot reference and leaves the drafter's
|
|
330
|
+
// in-flight decode to flow into the response. We do NOT abort the
|
|
331
|
+
// drafter — its output IS the response.
|
|
332
|
+
this.currentCheckpoint = null;
|
|
333
|
+
this.currentDraft = null;
|
|
334
|
+
this.pauseTimestampMs = null;
|
|
335
|
+
this.state = "committed";
|
|
336
|
+
// Auto-return to idle so the next `speech-start` opens a new turn.
|
|
337
|
+
this.state = "idle";
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private turnIdString(): string {
|
|
341
|
+
return `turn-${this.currentTurnId.toString(36)}`;
|
|
342
|
+
}
|
|
343
|
+
}
|