@elizaos/plugin-local-inference 2.0.0-beta.1 → 2.0.11-beta.7
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 +81 -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/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 +7 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.ts +54 -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 +1171 -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 +190 -0
- package/src/routes/local-inference-asr-route.ts +213 -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 +423 -0
- package/src/routes/local-inference-compat-routes.ts +782 -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/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 +53 -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 +1398 -0
- package/src/runtime/index.d.ts +14 -0
- package/src/runtime/index.d.ts.map +1 -0
- package/src/runtime/index.ts +27 -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/asr/errors.d.ts +21 -0
- package/src/services/asr/errors.d.ts.map +1 -0
- package/src/services/asr/errors.ts +50 -0
- package/src/services/asr/hash.d.ts +28 -0
- package/src/services/asr/hash.d.ts.map +1 -0
- package/src/services/asr/hash.ts +49 -0
- package/src/services/asr/index.d.ts +76 -0
- package/src/services/asr/index.d.ts.map +1 -0
- package/src/services/asr/index.ts +178 -0
- package/src/services/asr/types.d.ts +91 -0
- package/src/services/asr/types.d.ts.map +1 -0
- package/src/services/asr/types.ts +95 -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/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 +240 -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 +92 -0
- package/src/services/desktop-fused-ffi-backend-runtime.d.ts.map +1 -0
- package/src/services/desktop-fused-ffi-backend-runtime.ts +333 -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 +724 -0
- package/src/services/downloader.ts +899 -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 +534 -0
- package/src/services/engine.d.ts.map +1 -0
- package/src/services/engine.ts +1891 -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.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 +183 -0
- package/src/services/hardware.ts +404 -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 +281 -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 +30 -0
- package/src/services/index.d.ts.map +1 -0
- package/src/services/index.ts +225 -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 +693 -0
- package/src/services/manifest/schema.d.ts +715 -0
- package/src/services/manifest/schema.d.ts.map +1 -0
- package/src/services/manifest/schema.ts +655 -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 +569 -0
- package/src/services/memory-arbiter.d.ts +343 -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 +1000 -0
- package/src/services/memory-monitor.d.ts +119 -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 +296 -0
- package/src/services/memory-pressure.d.ts +127 -0
- package/src/services/memory-pressure.d.ts.map +1 -0
- package/src/services/memory-pressure.ts +413 -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 +672 -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 +376 -0
- package/src/services/routing-policy.d.ts +55 -0
- package/src/services/routing-policy.d.ts.map +1 -0
- package/src/services/routing-policy.ts +228 -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 +15 -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/transcription-priority.test.ts +211 -0
- package/src/services/tts/errors.ts +46 -0
- package/src/services/tts/index.ts +214 -0
- package/src/services/tts/tts-audio-cache.ts +235 -0
- package/src/services/tts/types.ts +157 -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 +92 -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 +197 -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/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 +148 -0
- package/src/services/voice/embedding.ts +244 -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 +746 -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 +2226 -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 +636 -0
- package/src/services/voice/ffi-bindings.d.ts.map +1 -0
- package/src/services/voice/ffi-bindings.test.ts +671 -0
- package/src/services/voice/ffi-bindings.ts +3050 -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/ring-buffer.d.ts +40 -0
- package/src/services/voice/ring-buffer.d.ts.map +1 -0
- package/src/services/voice/ring-buffer.ts +105 -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/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 +420 -0
- package/src/services/voice/voice-budget.ts +656 -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,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local-embedding route resolution + Matryoshka truncation (`embedding.ts`):
|
|
3
|
+
* - `0_8b` / `2b` → pooled-text source on the text backbone with `--pooling last`
|
|
4
|
+
* (no separate GGUF)
|
|
5
|
+
* - `4b` / `9b` / `27b` / `27b-256k` → dedicated `embedding/`
|
|
6
|
+
* region; hard-fails when that region is missing (AGENTS.md §1 — do NOT
|
|
7
|
+
* collapse to pooled text on the larger tiers; that breaks the 1024-dim
|
|
8
|
+
* Matryoshka contract)
|
|
9
|
+
* - every route guarantees 1024 dimensions and a sidecar embedding server
|
|
10
|
+
* launched with `--embeddings --pooling last`
|
|
11
|
+
* - `truncateMatryoshka` truncates 1024 → {64,128,256,512,768} and
|
|
12
|
+
* L2-renormalizes; rejects invalid widths
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
16
|
+
import { tmpdir } from "node:os";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { describe, expect, it } from "vitest";
|
|
19
|
+
import {
|
|
20
|
+
buildLocalEmbeddingRoute,
|
|
21
|
+
EMBEDDING_MATRYOSHKA_DIMS,
|
|
22
|
+
isValidEmbeddingDim,
|
|
23
|
+
resolveLocalEmbeddingSource,
|
|
24
|
+
truncateMatryoshka,
|
|
25
|
+
} from "./embedding";
|
|
26
|
+
|
|
27
|
+
function tmpBundle(): string {
|
|
28
|
+
return mkdtempSync(path.join(tmpdir(), "eliza-emb-"));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe("resolveLocalEmbeddingSource", () => {
|
|
32
|
+
it("0_8b: uses the text backbone with --pooling last (no separate GGUF)", () => {
|
|
33
|
+
const bundleRoot = tmpBundle();
|
|
34
|
+
const textPath = path.join(bundleRoot, "text", "eliza-1-0_8b-128k.gguf");
|
|
35
|
+
mkdirSync(path.dirname(textPath), { recursive: true });
|
|
36
|
+
writeFileSync(textPath, "gguf");
|
|
37
|
+
const src = resolveLocalEmbeddingSource({
|
|
38
|
+
bundleRoot,
|
|
39
|
+
tierId: "eliza-1-0_8b",
|
|
40
|
+
textModelPath: textPath,
|
|
41
|
+
});
|
|
42
|
+
expect(src.kind).toBe("pooled-text");
|
|
43
|
+
if (src.kind === "pooled-text") {
|
|
44
|
+
expect(src.poolingType).toBe("last");
|
|
45
|
+
expect(src.textModelPath).toBe(textPath);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("2b: reuses the text backbone with --pooling last (no duplicate GGUF)", () => {
|
|
50
|
+
const bundleRoot = tmpBundle();
|
|
51
|
+
const textPath = path.join(bundleRoot, "text", "eliza-1-2b-128k.gguf");
|
|
52
|
+
mkdirSync(path.dirname(textPath), { recursive: true });
|
|
53
|
+
writeFileSync(textPath, "gguf");
|
|
54
|
+
const src = resolveLocalEmbeddingSource({
|
|
55
|
+
bundleRoot,
|
|
56
|
+
tierId: "eliza-1-2b",
|
|
57
|
+
textModelPath: textPath,
|
|
58
|
+
});
|
|
59
|
+
expect(src.kind).toBe("pooled-text");
|
|
60
|
+
if (src.kind === "pooled-text") {
|
|
61
|
+
expect(src.textModelPath).toBe(textPath);
|
|
62
|
+
expect(src.poolingType).toBe("last");
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("buildLocalEmbeddingRoute", () => {
|
|
68
|
+
it("0_8b route emits --embeddings --pooling last and guarantees 1024 dims", () => {
|
|
69
|
+
const bundleRoot = tmpBundle();
|
|
70
|
+
const textPath = path.join(bundleRoot, "text", "t.gguf");
|
|
71
|
+
mkdirSync(path.dirname(textPath), { recursive: true });
|
|
72
|
+
writeFileSync(textPath, "gguf");
|
|
73
|
+
const route = buildLocalEmbeddingRoute({
|
|
74
|
+
bundleRoot,
|
|
75
|
+
tierId: "eliza-1-0_8b",
|
|
76
|
+
textModelPath: textPath,
|
|
77
|
+
});
|
|
78
|
+
expect(route.dimensions).toBe(1024);
|
|
79
|
+
expect(route.defaultDim).toBe(1024);
|
|
80
|
+
expect(route.matryoshkaDims).toEqual(EMBEDDING_MATRYOSHKA_DIMS);
|
|
81
|
+
expect(route.serverFlags).toEqual(["--embeddings", "--pooling", "last"]);
|
|
82
|
+
});
|
|
83
|
+
it("accepts a smaller defaultDim and rejects invalid widths", () => {
|
|
84
|
+
const bundleRoot = tmpBundle();
|
|
85
|
+
const textPath = path.join(bundleRoot, "text", "t.gguf");
|
|
86
|
+
mkdirSync(path.dirname(textPath), { recursive: true });
|
|
87
|
+
writeFileSync(textPath, "gguf");
|
|
88
|
+
const route = buildLocalEmbeddingRoute({
|
|
89
|
+
bundleRoot,
|
|
90
|
+
tierId: "eliza-1-0_8b",
|
|
91
|
+
textModelPath: textPath,
|
|
92
|
+
defaultDim: 256,
|
|
93
|
+
});
|
|
94
|
+
expect(route.defaultDim).toBe(256);
|
|
95
|
+
expect(() =>
|
|
96
|
+
buildLocalEmbeddingRoute({
|
|
97
|
+
bundleRoot,
|
|
98
|
+
tierId: "eliza-1-0_8b",
|
|
99
|
+
textModelPath: textPath,
|
|
100
|
+
defaultDim: 300,
|
|
101
|
+
}),
|
|
102
|
+
).toThrow();
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe("truncateMatryoshka", () => {
|
|
107
|
+
it("EMBEDDING_MATRYOSHKA_DIMS = {64,128,256,512,768,1024}", () => {
|
|
108
|
+
expect([...EMBEDDING_MATRYOSHKA_DIMS]).toEqual([
|
|
109
|
+
64, 128, 256, 512, 768, 1024,
|
|
110
|
+
]);
|
|
111
|
+
expect(isValidEmbeddingDim(256)).toBe(true);
|
|
112
|
+
expect(isValidEmbeddingDim(1000)).toBe(false);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("truncates to the leading slice and L2-renormalizes", () => {
|
|
116
|
+
// A 1024-dim vector that is unit-norm overall but whose leading 512
|
|
117
|
+
// components are not unit-norm on their own.
|
|
118
|
+
const full = new Array(1024).fill(0);
|
|
119
|
+
for (let i = 0; i < 1024; i += 1) full[i] = 1 / Math.sqrt(1024);
|
|
120
|
+
const half = truncateMatryoshka(full, 512);
|
|
121
|
+
expect(half).toHaveLength(512);
|
|
122
|
+
const norm = Math.sqrt(half.reduce((s, x) => s + x * x, 0));
|
|
123
|
+
expect(norm).toBeCloseTo(1, 6);
|
|
124
|
+
// Leading components preserved (up to the renormalization scale).
|
|
125
|
+
expect(half[0]).toBeCloseTo(1 / Math.sqrt(512), 6);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("renormalizes even when dim == vec.length (raw last-token state may not be unit-norm)", () => {
|
|
129
|
+
const v = [3, 4]; // norm 5, not a valid Matryoshka width, but exercise the equal-length path via 64
|
|
130
|
+
const v64 = new Array(64)
|
|
131
|
+
.fill(0)
|
|
132
|
+
.map((_, i) => (i === 0 ? 3 : i === 1 ? 4 : 0));
|
|
133
|
+
const out = truncateMatryoshka(v64, 64);
|
|
134
|
+
const norm = Math.sqrt(out.reduce((s, x) => s + x * x, 0));
|
|
135
|
+
expect(norm).toBeCloseTo(1, 6);
|
|
136
|
+
void v;
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("rejects an invalid width or a too-short vector", () => {
|
|
140
|
+
expect(() => truncateMatryoshka(new Array(1024).fill(0.1), 300)).toThrow();
|
|
141
|
+
expect(() => truncateMatryoshka(new Array(128).fill(0.1), 256)).toThrow();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("passes a zero vector through unchanged", () => {
|
|
145
|
+
const z = truncateMatryoshka(new Array(1024).fill(0), 64);
|
|
146
|
+
expect(z.every((x) => x === 0)).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local embedding wiring for Eliza-1 bundles.
|
|
3
|
+
*
|
|
4
|
+
* Per `packages/inference/AGENTS.md` §1:
|
|
5
|
+
* - On the `0_8b` and `2b` tiers the **embedding model IS the text backbone**,
|
|
6
|
+
* served with `--pooling last` — there is no separate `embedding/`
|
|
7
|
+
* GGUF and no duplicate parameters in the mobile/default tiers.
|
|
8
|
+
* - On `4b` and larger tiers, a dedicated
|
|
9
|
+
* `embedding/` GGUF region (Apache-2.0,
|
|
10
|
+
* 1024-dim Matryoshka, 32k ctx) is acquired lazily through the same
|
|
11
|
+
* engine / `SharedResourceRegistry`. **Do not collapse it to pooled
|
|
12
|
+
* text on the larger tiers** — that breaks the 1024-dim Matryoshka
|
|
13
|
+
* contract (B1's verdict).
|
|
14
|
+
*
|
|
15
|
+
* This module is a pure resolver: given a bundle root + tier id it
|
|
16
|
+
* describes *where* embeddings come from (the text GGUF with a pooling
|
|
17
|
+
* flag, or a separate region file) without doing any I/O beyond an
|
|
18
|
+
* `existsSync`. The engine consumes the descriptor to mount the region
|
|
19
|
+
* and the local-embedding route. It also owns the Matryoshka-truncation
|
|
20
|
+
* helper that callers / the vector store use to trade dimensionality for
|
|
21
|
+
* storage (see `EMBEDDING_MATRYOSHKA_DIMS` + `truncateMatryoshka`).
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
25
|
+
import path from "node:path";
|
|
26
|
+
import type { Eliza1TierId } from "../catalog";
|
|
27
|
+
import { VoiceStartupError } from "./errors";
|
|
28
|
+
|
|
29
|
+
/** Bundle-relative directory holding a dedicated embedding GGUF (larger tiers). */
|
|
30
|
+
export const EMBEDDING_DIR_REL_PATH = "embedding";
|
|
31
|
+
|
|
32
|
+
/** Full output dimensionality of the Eliza-1 embedding model. */
|
|
33
|
+
export const EMBEDDING_FULL_DIM = 1024 as const;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Valid Matryoshka truncation points for the Eliza-1 embedding region. The model
|
|
37
|
+
* is trained so that the leading N components of the 1024-dim vector are
|
|
38
|
+
* themselves a usable embedding at these widths; quality degrades
|
|
39
|
+
* gracefully as N shrinks (see the tradeoff table in
|
|
40
|
+
* `reports/porting/2026-05-11/embedding-model-review.md`).
|
|
41
|
+
*
|
|
42
|
+
* 1024 (full) → 768 → 512 → 256 → 128 → 64. Smaller widths than 64 are
|
|
43
|
+
* not part of the published contract.
|
|
44
|
+
*/
|
|
45
|
+
export const EMBEDDING_MATRYOSHKA_DIMS: readonly number[] = [
|
|
46
|
+
64, 128, 256, 512, 768, 1024,
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
/** Type-narrow guard for `EMBEDDING_MATRYOSHKA_DIMS`. */
|
|
50
|
+
export function isValidEmbeddingDim(dim: number): boolean {
|
|
51
|
+
return EMBEDDING_MATRYOSHKA_DIMS.includes(dim);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Truncate a full 1024-dim embedding to one of the Matryoshka widths and
|
|
56
|
+
* L2-renormalize. Renormalization matters: the dedicated embedding outputs are
|
|
57
|
+
* unit-norm at 1024 dims, but the leading slice is *not* unit-norm, and
|
|
58
|
+
* downstream cosine-similarity / dot-product retrieval assumes unit
|
|
59
|
+
* vectors.
|
|
60
|
+
*
|
|
61
|
+
* Throws on an invalid `dim` (must be one of `EMBEDDING_MATRYOSHKA_DIMS`)
|
|
62
|
+
* or when `vec` is shorter than `dim` — no silent truncation-to-whatever
|
|
63
|
+
* or zero-padding (Commandment 8: don't hide a broken pipeline).
|
|
64
|
+
*/
|
|
65
|
+
export function truncateMatryoshka(
|
|
66
|
+
vec: readonly number[],
|
|
67
|
+
dim: number,
|
|
68
|
+
): number[] {
|
|
69
|
+
if (!isValidEmbeddingDim(dim)) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`[embedding] dim ${dim} is not a valid Matryoshka width; expected one of ${EMBEDDING_MATRYOSHKA_DIMS.join(", ")}`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
if (vec.length < dim) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`[embedding] cannot truncate a ${vec.length}-dim vector to ${dim} dims`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (vec.length === dim) {
|
|
80
|
+
// Already the requested width; still renormalize so a caller passing a
|
|
81
|
+
// raw last-token state (which may not be unit-norm) gets a clean vec.
|
|
82
|
+
return l2Normalize(vec.slice());
|
|
83
|
+
}
|
|
84
|
+
return l2Normalize(vec.slice(0, dim));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** L2-normalize in place; returns the same array. Zero vectors pass through. */
|
|
88
|
+
function l2Normalize(vec: number[]): number[] {
|
|
89
|
+
let sumSq = 0;
|
|
90
|
+
for (const x of vec) sumSq += x * x;
|
|
91
|
+
if (sumSq === 0) return vec;
|
|
92
|
+
const inv = 1 / Math.sqrt(sumSq);
|
|
93
|
+
for (let i = 0; i < vec.length; i += 1) vec[i] *= inv;
|
|
94
|
+
return vec;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export type LocalEmbeddingSource =
|
|
98
|
+
| {
|
|
99
|
+
/** `0_8b` / `2b`: reuse the text backbone GGUF; serve with `--pooling last`. */
|
|
100
|
+
readonly kind: "pooled-text";
|
|
101
|
+
readonly textModelPath: string;
|
|
102
|
+
readonly poolingType: "last";
|
|
103
|
+
}
|
|
104
|
+
| {
|
|
105
|
+
/** Larger tiers: a dedicated `embedding/<name>.gguf` region. */
|
|
106
|
+
readonly kind: "dedicated-region";
|
|
107
|
+
readonly embeddingModelPath: string;
|
|
108
|
+
/** 1024-dim Matryoshka (the published Eliza-1 embedding contract). */
|
|
109
|
+
readonly dimensions: typeof EMBEDDING_FULL_DIM;
|
|
110
|
+
/**
|
|
111
|
+
* The dedicated model already ships a contrastive `last`-token
|
|
112
|
+
* pooling head — `--pooling last` is still passed so llama-server
|
|
113
|
+
* doesn't fall back to the GGUF's metadata default (which for a raw
|
|
114
|
+
* Qwen3 base is `mean`). The model's own pooling layer dominates;
|
|
115
|
+
* this just pins the read.
|
|
116
|
+
*/
|
|
117
|
+
readonly poolingType: "last";
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/** First regular `.gguf` file under `dir`, or null. */
|
|
121
|
+
function firstGguf(dir: string): string | null {
|
|
122
|
+
if (!existsSync(dir)) return null;
|
|
123
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
124
|
+
if (entry.isFile() && /\.gguf$/i.test(entry.name)) {
|
|
125
|
+
return path.join(dir, entry.name);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Tiers whose embedding model is the text backbone with `--pooling last`
|
|
133
|
+
* (no separate GGUF). The default mobile tiers deliberately avoid duplicate
|
|
134
|
+
* parameters; larger tiers may use a dedicated embedding region.
|
|
135
|
+
*/
|
|
136
|
+
export const POOLED_TEXT_EMBEDDING_TIERS: ReadonlySet<Eliza1TierId> = new Set([
|
|
137
|
+
"eliza-1-0_8b",
|
|
138
|
+
"eliza-1-2b",
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Resolve the embedding source for an activated Eliza-1 bundle.
|
|
143
|
+
*
|
|
144
|
+
* @param bundleRoot Bundle directory on disk.
|
|
145
|
+
* @param tierId The Eliza-1 tier id (`eliza-1-0_8b`, ...).
|
|
146
|
+
* @param textModelPath Absolute path of the activated text GGUF (needed for
|
|
147
|
+
* the `pooled-text` case).
|
|
148
|
+
*
|
|
149
|
+
* Hard-fails (AGENTS.md §3) when a larger tier is missing its
|
|
150
|
+
* `embedding/` region — no silent fallback to pooled text, which would
|
|
151
|
+
* regress dimensions from 1024 to whatever the text model emits.
|
|
152
|
+
*/
|
|
153
|
+
export function resolveLocalEmbeddingSource(args: {
|
|
154
|
+
bundleRoot: string;
|
|
155
|
+
tierId: Eliza1TierId;
|
|
156
|
+
textModelPath: string;
|
|
157
|
+
}): LocalEmbeddingSource {
|
|
158
|
+
if (POOLED_TEXT_EMBEDDING_TIERS.has(args.tierId)) {
|
|
159
|
+
if (!existsSync(args.textModelPath)) {
|
|
160
|
+
throw new VoiceStartupError(
|
|
161
|
+
"missing-bundle-root",
|
|
162
|
+
`[embedding] ${args.tierId}: text model not found at ${args.textModelPath} — cannot serve pooled-text embeddings.`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
kind: "pooled-text",
|
|
167
|
+
textModelPath: args.textModelPath,
|
|
168
|
+
poolingType: "last",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const dir = path.join(args.bundleRoot, EMBEDDING_DIR_REL_PATH);
|
|
172
|
+
const gguf = firstGguf(dir);
|
|
173
|
+
if (!gguf) {
|
|
174
|
+
throw new VoiceStartupError(
|
|
175
|
+
"missing-bundle-root",
|
|
176
|
+
`[embedding] ${args.tierId}: required dedicated embedding region missing under ${dir}. Tiers above 2b ship a separate 1024-dim Matryoshka embedding GGUF (AGENTS.md §1) — do not fall back to pooled text.`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
kind: "dedicated-region",
|
|
181
|
+
embeddingModelPath: gguf,
|
|
182
|
+
dimensions: EMBEDDING_FULL_DIM,
|
|
183
|
+
poolingType: "last",
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Descriptor for the local-embedding route the engine exposes. The
|
|
189
|
+
* route's job is `text[] → number[dim][]`; the runtime mounts the source
|
|
190
|
+
* (pooled text or dedicated region) and forwards. Kept as a plain data
|
|
191
|
+
* shape so both the API layer and tests can assert it without standing up
|
|
192
|
+
* a server.
|
|
193
|
+
*/
|
|
194
|
+
export interface LocalEmbeddingRoute {
|
|
195
|
+
readonly tierId: Eliza1TierId;
|
|
196
|
+
readonly source: LocalEmbeddingSource;
|
|
197
|
+
/** Full output dimensionality the route produces before truncation. 1024 on every tier. */
|
|
198
|
+
readonly dimensions: typeof EMBEDDING_FULL_DIM;
|
|
199
|
+
/**
|
|
200
|
+
* Default Matryoshka width the route returns when a caller does not ask
|
|
201
|
+
* for a smaller `dim`. Always 1024 (= `dimensions`) — callers/the vector
|
|
202
|
+
* store opt into a smaller width for storage savings.
|
|
203
|
+
*/
|
|
204
|
+
readonly defaultDim: number;
|
|
205
|
+
/** The Matryoshka widths a caller may request. */
|
|
206
|
+
readonly matryoshkaDims: readonly number[];
|
|
207
|
+
/**
|
|
208
|
+
* `llama-server` flags for the embedding server process — always
|
|
209
|
+
* `--embeddings --pooling last`. The embedding server is a lazily-started
|
|
210
|
+
* sidecar over the route's GGUF (the text backbone on `0_8b` / `2b`, the
|
|
211
|
+
* `embedding/` GGUF on larger tiers); see `embedding-server.ts`. The
|
|
212
|
+
* chat `llama-server` is left untouched (completions-only) — these flags
|
|
213
|
+
* do NOT go on it.
|
|
214
|
+
*/
|
|
215
|
+
readonly serverFlags: ReadonlyArray<string>;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function buildLocalEmbeddingRoute(args: {
|
|
219
|
+
bundleRoot: string;
|
|
220
|
+
tierId: Eliza1TierId;
|
|
221
|
+
textModelPath: string;
|
|
222
|
+
/** Default output width; must be one of `EMBEDDING_MATRYOSHKA_DIMS`. Defaults to 1024. */
|
|
223
|
+
defaultDim?: number;
|
|
224
|
+
}): LocalEmbeddingRoute {
|
|
225
|
+
const source = resolveLocalEmbeddingSource(args);
|
|
226
|
+
const defaultDim = args.defaultDim ?? EMBEDDING_FULL_DIM;
|
|
227
|
+
if (!isValidEmbeddingDim(defaultDim)) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`[embedding] defaultDim ${defaultDim} is not a valid Matryoshka width; expected one of ${EMBEDDING_MATRYOSHKA_DIMS.join(", ")}`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
// Both modes serve through a sidecar `llama-server --embeddings --pooling
|
|
233
|
+
// last` (over the text GGUF on 0_8b / 2b, over the embedding/ GGUF on
|
|
234
|
+
// larger tiers). The chat server is never given these flags.
|
|
235
|
+
const serverFlags = ["--embeddings", "--pooling", source.poolingType];
|
|
236
|
+
return {
|
|
237
|
+
tierId: args.tierId,
|
|
238
|
+
source,
|
|
239
|
+
dimensions: EMBEDDING_FULL_DIM,
|
|
240
|
+
defaultDim,
|
|
241
|
+
matryoshkaDims: EMBEDDING_MATRYOSHKA_DIMS,
|
|
242
|
+
serverFlags,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type ExpressiveEmotion } from "./expressive-tags";
|
|
2
|
+
import type { VoiceEmotionClassifierOutput, VoiceEmotionVad } from "./voice-emotion-classifier";
|
|
3
|
+
export type VoiceEmotionAttributionMethod = "none" | "text_tag" | "text_audio_heuristic" | "explicit_asr_metadata" | "acoustic_model" | "acoustic_text_fused";
|
|
4
|
+
export interface VoiceEmotionAudioFeatures {
|
|
5
|
+
durationMs?: number;
|
|
6
|
+
rms?: number;
|
|
7
|
+
zeroCrossingRate?: number;
|
|
8
|
+
speechRateWpm?: number;
|
|
9
|
+
meanPitchHz?: number;
|
|
10
|
+
pitchStdHz?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface VoiceEmotionAsrFeatures {
|
|
13
|
+
transcript?: string;
|
|
14
|
+
confidence?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Optional structured metadata supplied by an ASR service. The local fused
|
|
17
|
+
* ASR path does not currently advertise model-native emotion labels, so this
|
|
18
|
+
* is ignored unless `emotionLabelSupported` is explicitly true.
|
|
19
|
+
*/
|
|
20
|
+
emotionLabel?: string | null;
|
|
21
|
+
emotionLabelSupported?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Acoustic-model emotion read fed in as a *fusion* source — the result of
|
|
25
|
+
* running the Wav2Small student (`VoiceEmotionClassifier.classify()`) over
|
|
26
|
+
* the utterance window. Pass the raw classifier output directly; the
|
|
27
|
+
* fusion logic in `attributeVoiceEmotion` is the single place that combines
|
|
28
|
+
* acoustic + text-side evidence (R3-emotion §3, "Two confidence scores,
|
|
29
|
+
* no fusion rule" risk).
|
|
30
|
+
*/
|
|
31
|
+
export interface VoiceEmotionModelInput {
|
|
32
|
+
output: VoiceEmotionClassifierOutput;
|
|
33
|
+
/** Stable model id recorded on the resulting evidence row. */
|
|
34
|
+
modelId?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface VoiceEmotionAttributionInput {
|
|
37
|
+
text?: string;
|
|
38
|
+
asr?: VoiceEmotionAsrFeatures;
|
|
39
|
+
audio?: VoiceEmotionAudioFeatures;
|
|
40
|
+
/**
|
|
41
|
+
* Acoustic classifier output — the Wav2Small read. Optional; when absent
|
|
42
|
+
* the attribution falls back to the lexicon + audio-prosody heuristic
|
|
43
|
+
* (which is what `evidence.source === "audio_prosody"` covers).
|
|
44
|
+
*/
|
|
45
|
+
model?: VoiceEmotionModelInput;
|
|
46
|
+
}
|
|
47
|
+
export interface VoiceEmotionEvidence {
|
|
48
|
+
source: "text_expressive_tag" | "text_lexicon" | "audio_prosody" | "asr_transcript" | "asr_emotion_metadata" | "asr_emotion_metadata_ignored" | "acoustic_model";
|
|
49
|
+
detail: string;
|
|
50
|
+
confidence: number;
|
|
51
|
+
}
|
|
52
|
+
export interface VoiceEmotionAttribution {
|
|
53
|
+
emotion: ExpressiveEmotion | null;
|
|
54
|
+
confidence: number;
|
|
55
|
+
method: VoiceEmotionAttributionMethod;
|
|
56
|
+
modelNativeEmotion: false;
|
|
57
|
+
evidence: VoiceEmotionEvidence[];
|
|
58
|
+
scores: Record<ExpressiveEmotion, number>;
|
|
59
|
+
/**
|
|
60
|
+
* Continuous V-A-D from the acoustic classifier when one was supplied via
|
|
61
|
+
* `model`. Carried through so downstream consumers (planner provider,
|
|
62
|
+
* memory tagging, bench) can read the raw continuous signal instead of the
|
|
63
|
+
* projected discrete label.
|
|
64
|
+
*/
|
|
65
|
+
vad?: VoiceEmotionVad;
|
|
66
|
+
}
|
|
67
|
+
export declare function attributeVoiceEmotion(input: VoiceEmotionAttributionInput): VoiceEmotionAttribution;
|
|
68
|
+
//# sourceMappingURL=emotion-attribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emotion-attribution.d.ts","sourceRoot":"","sources":["emotion-attribution.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,iBAAiB,EAGtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACX,4BAA4B,EAC5B,eAAe,EACf,MAAM,4BAA4B,CAAC;AAEpC,MAAM,MAAM,6BAA6B,GACtC,MAAM,GACN,UAAU,GACV,sBAAsB,GACtB,uBAAuB,GACvB,gBAAgB,GAChB,qBAAqB,CAAC;AAEzB,MAAM,WAAW,yBAAyB;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,4BAA4B,CAAC;IACrC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,4BAA4B;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,uBAAuB,CAAC;IAC9B,KAAK,CAAC,EAAE,yBAAyB,CAAC;IAClC;;;;OAIG;IACH,KAAK,CAAC,EAAE,sBAAsB,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACpC,MAAM,EACH,qBAAqB,GACrB,cAAc,GACd,eAAe,GACf,gBAAgB,GAChB,sBAAsB,GACtB,8BAA8B,GAC9B,gBAAgB,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,6BAA6B,CAAC;IACtC,kBAAkB,EAAE,KAAK,CAAC;IAC1B,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;IAC1C;;;;;OAKG;IACH,GAAG,CAAC,EAAE,eAAe,CAAC;CACtB;AAoGD,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,4BAA4B,GACjC,uBAAuB,CAgKzB"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { attributeVoiceEmotion } from "./emotion-attribution";
|
|
3
|
+
import { WAV2SMALL_INT8_MODEL_ID } from "./voice-emotion-classifier";
|
|
4
|
+
|
|
5
|
+
describe("emotion-attribution", () => {
|
|
6
|
+
it("prefers explicit expressive text tags and marks attribution as non-native", () => {
|
|
7
|
+
const result = attributeVoiceEmotion({
|
|
8
|
+
text: "[excited] That is amazing news!",
|
|
9
|
+
audio: { durationMs: 1200, rms: 0.2, zeroCrossingRate: 0.08 },
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
expect(result.emotion).toBe("excited");
|
|
13
|
+
expect(result.method).toBe("text_tag");
|
|
14
|
+
expect(result.modelNativeEmotion).toBe(false);
|
|
15
|
+
expect(result.evidence[0]).toMatchObject({
|
|
16
|
+
source: "text_expressive_tag",
|
|
17
|
+
detail: "[excited]",
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("uses ASR transcript and audio features without claiming model-native emotion labels", () => {
|
|
22
|
+
const result = attributeVoiceEmotion({
|
|
23
|
+
asr: {
|
|
24
|
+
transcript: "I am worried this might break",
|
|
25
|
+
confidence: 0.91,
|
|
26
|
+
emotionLabel: "anger",
|
|
27
|
+
emotionLabelSupported: false,
|
|
28
|
+
},
|
|
29
|
+
audio: {
|
|
30
|
+
durationMs: 1100,
|
|
31
|
+
rms: 0.22,
|
|
32
|
+
zeroCrossingRate: 0.11,
|
|
33
|
+
speechRateWpm: 180,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
expect(result.emotion).toBe("nervous");
|
|
38
|
+
expect(result.method).toBe("text_audio_heuristic");
|
|
39
|
+
expect(result.modelNativeEmotion).toBe(false);
|
|
40
|
+
expect(result.evidence).toContainEqual({
|
|
41
|
+
source: "asr_emotion_metadata_ignored",
|
|
42
|
+
detail: "anger",
|
|
43
|
+
confidence: 0,
|
|
44
|
+
});
|
|
45
|
+
expect(result.evidence.some((row) => row.source === "asr_transcript")).toBe(
|
|
46
|
+
true,
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("can use explicitly supported ASR emotion metadata but still labels it as metadata", () => {
|
|
51
|
+
const result = attributeVoiceEmotion({
|
|
52
|
+
asr: {
|
|
53
|
+
transcript: "I am okay",
|
|
54
|
+
emotionLabel: "happiness",
|
|
55
|
+
emotionLabelSupported: true,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(result.emotion).toBe("happy");
|
|
60
|
+
expect(result.method).toBe("explicit_asr_metadata");
|
|
61
|
+
expect(result.modelNativeEmotion).toBe(false);
|
|
62
|
+
expect(
|
|
63
|
+
result.evidence.some((row) => row.source === "asr_emotion_metadata"),
|
|
64
|
+
).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("fuses acoustic classifier output with text evidence and reports vad + acoustic_text_fused", () => {
|
|
68
|
+
const result = attributeVoiceEmotion({
|
|
69
|
+
text: "I am furious about this!",
|
|
70
|
+
model: {
|
|
71
|
+
output: {
|
|
72
|
+
vad: { valence: 0.15, arousal: 0.85, dominance: 0.8 },
|
|
73
|
+
emotion: "angry",
|
|
74
|
+
confidence: 0.82,
|
|
75
|
+
scores: {
|
|
76
|
+
happy: 0.05,
|
|
77
|
+
sad: 0.1,
|
|
78
|
+
angry: 0.82,
|
|
79
|
+
nervous: 0.2,
|
|
80
|
+
calm: 0.0,
|
|
81
|
+
excited: 0.3,
|
|
82
|
+
whisper: 0.0,
|
|
83
|
+
},
|
|
84
|
+
modelId: WAV2SMALL_INT8_MODEL_ID,
|
|
85
|
+
latencyMs: 4,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(result.emotion).toBe("angry");
|
|
91
|
+
expect(result.method).toBe("acoustic_text_fused");
|
|
92
|
+
expect(result.vad).toMatchObject({
|
|
93
|
+
valence: 0.15,
|
|
94
|
+
arousal: 0.85,
|
|
95
|
+
dominance: 0.8,
|
|
96
|
+
});
|
|
97
|
+
expect(result.evidence.some((row) => row.source === "acoustic_model")).toBe(
|
|
98
|
+
true,
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("attributes acoustic_model alone when only the classifier output is provided", () => {
|
|
103
|
+
const result = attributeVoiceEmotion({
|
|
104
|
+
model: {
|
|
105
|
+
output: {
|
|
106
|
+
vad: { valence: 0.1, arousal: 0.1, dominance: 0.2 },
|
|
107
|
+
emotion: "sad",
|
|
108
|
+
confidence: 0.7,
|
|
109
|
+
scores: {
|
|
110
|
+
happy: 0.0,
|
|
111
|
+
sad: 0.7,
|
|
112
|
+
angry: 0.05,
|
|
113
|
+
nervous: 0.1,
|
|
114
|
+
calm: 0.1,
|
|
115
|
+
excited: 0.0,
|
|
116
|
+
whisper: 0.05,
|
|
117
|
+
},
|
|
118
|
+
modelId: WAV2SMALL_INT8_MODEL_ID,
|
|
119
|
+
latencyMs: 3,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
expect(result.emotion).toBe("sad");
|
|
125
|
+
expect(result.method).toBe("acoustic_model");
|
|
126
|
+
expect(result.modelNativeEmotion).toBe(false);
|
|
127
|
+
expect(result.vad).toBeDefined();
|
|
128
|
+
});
|
|
129
|
+
});
|