@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,407 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-priority router handler.
|
|
3
|
+
*
|
|
4
|
+
* Registers a model handler for every `AgentModelSlot` at priority
|
|
5
|
+
* `Number.MAX_SAFE_INTEGER`, which guarantees the runtime dispatches to
|
|
6
|
+
* us first. At dispatch time we:
|
|
7
|
+
*
|
|
8
|
+
* 1. Read the user's per-slot policy + preferred-provider choice from
|
|
9
|
+
* `routing-preferences.ts`.
|
|
10
|
+
* 2. Ask the `policyEngine` to pick a provider from the handler
|
|
11
|
+
* registry's current set (excluding ourselves).
|
|
12
|
+
* 3. Invoke that provider's original handler directly — bypassing
|
|
13
|
+
* `runtime.useModel` which would recurse into us.
|
|
14
|
+
* 4. Record the observed latency so later "fastest" picks have data.
|
|
15
|
+
* 5. On handler failure: retry the next eligible provider in priority
|
|
16
|
+
* order until exhausted (except in `manual` mode with an explicit
|
|
17
|
+
* preferred provider — that throws verbatim).
|
|
18
|
+
*
|
|
19
|
+
* If no other handler exists we throw a clear error rather than return
|
|
20
|
+
* garbage — the caller is meant to see "no provider configured" so they
|
|
21
|
+
* know to set one up.
|
|
22
|
+
*
|
|
23
|
+
* Because the router sits at the top of the priority stack, the user's
|
|
24
|
+
* preference is always authoritative regardless of what plugins register
|
|
25
|
+
* at lower priorities. This is the mechanism that unifies cloud + local
|
|
26
|
+
* + device-bridge routing from one settings panel.
|
|
27
|
+
*
|
|
28
|
+
* ## TTS routing precedence (`TEXT_TO_SPEECH` slot)
|
|
29
|
+
*
|
|
30
|
+
* The default per-slot policy is `prefer-local` (see
|
|
31
|
+
* `DEFAULT_ROUTING_POLICY` in `routing-preferences.ts`), which the
|
|
32
|
+
* policyEngine implements by short-circuiting to whichever candidate
|
|
33
|
+
* has provider `eliza-local-inference` / `capacitor-llama` /
|
|
34
|
+
* `eliza-device-bridge`. So even though `plugin-elizacloud` registers
|
|
35
|
+
* its TTS handler at plugin priority 50 (higher than the default 0 of
|
|
36
|
+
* direct providers like ElevenLabs / OpenAI / Groq / Edge-TTS), the
|
|
37
|
+
* router prefers local first when local is registered AND
|
|
38
|
+
* `local-inference` has a TTS-capable handler.
|
|
39
|
+
*
|
|
40
|
+
* Documented routing precedence for `TEXT_TO_SPEECH`:
|
|
41
|
+
*
|
|
42
|
+
* 1. **Local (`eliza-local-inference`)** — tier-aware Eliza-1 voice,
|
|
43
|
+
* using the ordered `ELIZA_1_VOICE_BACKENDS` policy in
|
|
44
|
+
* `@elizaos/shared/local-inference/catalog` (OmniVoice first where
|
|
45
|
+
* bundled, Kokoro fallback where bundled). Always preferred when
|
|
46
|
+
* available.
|
|
47
|
+
* 2. **Eliza Cloud (`elizacloud`)** — managed cloud proxy. Picked when
|
|
48
|
+
* local is unavailable. Throws `CloudTtsUnavailableError` when
|
|
49
|
+
* cloud isn't connected, which the loop above catches and falls
|
|
50
|
+
* through to step 3.
|
|
51
|
+
* 3. **ElevenLabs (`elevenlabs`)** — direct API key path.
|
|
52
|
+
* 4. **OpenAI (`openai`)** — direct API key path.
|
|
53
|
+
* 5. **Groq (`groq`)** — direct API key path.
|
|
54
|
+
* 6. **Edge-TTS (`edge-tts`)** — free Microsoft Edge endpoint, no key.
|
|
55
|
+
*
|
|
56
|
+
* Same precedence applies to `TRANSCRIPTION`, with the local side using
|
|
57
|
+
* Qwen3-ASR via the fused libelizainference (no whisper.cpp; see
|
|
58
|
+
* `plugin-local-inference/native/AGENTS.md` §1).
|
|
59
|
+
*
|
|
60
|
+
* Users can override this per slot via the routing-preferences settings
|
|
61
|
+
* panel (`prefer-local` ↔ `manual` + explicit `preferredProvider`).
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
import type { AgentRuntime, IAgentRuntime } from "@elizaos/core";
|
|
65
|
+
import {
|
|
66
|
+
logger,
|
|
67
|
+
ModelType,
|
|
68
|
+
NoModelProviderConfiguredError,
|
|
69
|
+
} from "@elizaos/core";
|
|
70
|
+
import { readEffectiveAssignments } from "./assignments";
|
|
71
|
+
import { classifyDeviceTier, type DeviceTierAssessment } from "./device-tier";
|
|
72
|
+
import { localInferenceEngine } from "./engine";
|
|
73
|
+
import type { HandlerRegistration } from "./handler-registry";
|
|
74
|
+
import { handlerRegistry } from "./handler-registry";
|
|
75
|
+
import { probeHardware } from "./hardware";
|
|
76
|
+
import { policyEngine } from "./routing-policy";
|
|
77
|
+
import {
|
|
78
|
+
DEFAULT_ROUTING_POLICY,
|
|
79
|
+
readRoutingPreferences,
|
|
80
|
+
} from "./routing-preferences";
|
|
81
|
+
import { AGENT_MODEL_SLOTS, type AgentModelSlot } from "./types";
|
|
82
|
+
|
|
83
|
+
export const ROUTER_PROVIDER = "eliza-router";
|
|
84
|
+
/**
|
|
85
|
+
* Max safe integer keeps us at the top even if a plugin registers with
|
|
86
|
+
* a very high priority. If someone deliberately wants to outrank us,
|
|
87
|
+
* they can register with Infinity — unlikely in practice.
|
|
88
|
+
*/
|
|
89
|
+
const ROUTER_PRIORITY = Number.MAX_SAFE_INTEGER;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The device-tier assessment drives the `auto` policy (and softly hints
|
|
93
|
+
* `prefer-local`). Probing hardware is cheap but not free, so cache the
|
|
94
|
+
* assessment for a short window — long enough to avoid re-probing on every
|
|
95
|
+
* model call, short enough that free-RAM demotion stays roughly current.
|
|
96
|
+
*/
|
|
97
|
+
const DEVICE_TIER_TTL_MS = 30_000;
|
|
98
|
+
let cachedDeviceTier: { at: number; assessment: DeviceTierAssessment } | null =
|
|
99
|
+
null;
|
|
100
|
+
|
|
101
|
+
async function resolveDeviceTier(): Promise<DeviceTierAssessment | null> {
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
if (cachedDeviceTier && now - cachedDeviceTier.at < DEVICE_TIER_TTL_MS) {
|
|
104
|
+
return cachedDeviceTier.assessment;
|
|
105
|
+
}
|
|
106
|
+
const probe = await probeHardware();
|
|
107
|
+
const assessment = classifyDeviceTier(probe);
|
|
108
|
+
cachedDeviceTier = { at: now, assessment };
|
|
109
|
+
return assessment;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function readBooleanEnv(name: string): boolean {
|
|
113
|
+
const value =
|
|
114
|
+
typeof process !== "undefined" ? process.env[name]?.trim() : undefined;
|
|
115
|
+
if (!value) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return value === "1" || value.toLowerCase() === "true";
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Runtime's registerModel type, narrowed for our use. The core signature
|
|
123
|
+
* lets the handler return any model type; for routing we only care that
|
|
124
|
+
* we can call it and await a result.
|
|
125
|
+
*/
|
|
126
|
+
type AnyHandler = (
|
|
127
|
+
runtime: IAgentRuntime,
|
|
128
|
+
params: Record<string, unknown>,
|
|
129
|
+
) => Promise<unknown>;
|
|
130
|
+
|
|
131
|
+
function slotToModelType(slot: AgentModelSlot): string | undefined {
|
|
132
|
+
switch (slot) {
|
|
133
|
+
case "TEXT_SMALL":
|
|
134
|
+
return ModelType.TEXT_SMALL;
|
|
135
|
+
case "TEXT_LARGE":
|
|
136
|
+
return ModelType.TEXT_LARGE;
|
|
137
|
+
case "TEXT_EMBEDDING":
|
|
138
|
+
return ModelType.TEXT_EMBEDDING;
|
|
139
|
+
case "TEXT_TO_SPEECH":
|
|
140
|
+
return ModelType.TEXT_TO_SPEECH;
|
|
141
|
+
case "TRANSCRIPTION":
|
|
142
|
+
return ModelType.TRANSCRIPTION;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function modelTypeToSlot(modelType: string): AgentModelSlot | null {
|
|
147
|
+
for (const slot of AGENT_MODEL_SLOTS) {
|
|
148
|
+
if (slotToModelType(slot) === modelType) return slot;
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function shouldForceLocalInference(
|
|
154
|
+
policy: string,
|
|
155
|
+
preferredProvider: string | null,
|
|
156
|
+
): boolean {
|
|
157
|
+
return policy === "manual" && preferredProvider === "eliza-local-inference";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function getRuntimeModelCandidates(
|
|
161
|
+
runtime: IAgentRuntime,
|
|
162
|
+
modelType: string,
|
|
163
|
+
): HandlerRegistration[] {
|
|
164
|
+
const models = (runtime as { models?: unknown }).models;
|
|
165
|
+
if (!(models instanceof Map)) return [];
|
|
166
|
+
const registrations = models.get(modelType);
|
|
167
|
+
if (!Array.isArray(registrations)) return [];
|
|
168
|
+
return registrations
|
|
169
|
+
.filter(
|
|
170
|
+
(
|
|
171
|
+
entry,
|
|
172
|
+
): entry is {
|
|
173
|
+
provider: string;
|
|
174
|
+
priority?: number;
|
|
175
|
+
handler: HandlerRegistration["handler"];
|
|
176
|
+
} =>
|
|
177
|
+
entry &&
|
|
178
|
+
typeof entry === "object" &&
|
|
179
|
+
typeof (entry as { provider?: unknown }).provider === "string" &&
|
|
180
|
+
(entry as { provider: string }).provider !== ROUTER_PROVIDER &&
|
|
181
|
+
typeof (entry as { handler?: unknown }).handler === "function",
|
|
182
|
+
)
|
|
183
|
+
.map((entry) => ({
|
|
184
|
+
modelType,
|
|
185
|
+
provider: entry.provider,
|
|
186
|
+
priority: typeof entry.priority === "number" ? entry.priority : 0,
|
|
187
|
+
registeredAt: "runtime-introspection",
|
|
188
|
+
handler: entry.handler,
|
|
189
|
+
}))
|
|
190
|
+
.sort((a, b) => b.priority - a.priority);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function filterUnavailableLocalInferenceCandidates(
|
|
194
|
+
candidates: HandlerRegistration[],
|
|
195
|
+
localInferenceAvailable: boolean,
|
|
196
|
+
forceLocalInference: boolean,
|
|
197
|
+
): HandlerRegistration[] {
|
|
198
|
+
if (forceLocalInference || localInferenceAvailable) {
|
|
199
|
+
return candidates;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return candidates.filter(
|
|
203
|
+
(candidate) => candidate.provider !== "eliza-local-inference",
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export async function filterUnavailableLocalInference(
|
|
208
|
+
slot: AgentModelSlot,
|
|
209
|
+
policy: string,
|
|
210
|
+
preferredProvider: string | null,
|
|
211
|
+
candidates: HandlerRegistration[],
|
|
212
|
+
): Promise<HandlerRegistration[]> {
|
|
213
|
+
// Voice slots (TTS / STT) are self-sufficient — their handlers call
|
|
214
|
+
// ensureActiveBundleVoiceReady() internally which loads the voice model
|
|
215
|
+
// on-demand. Don't gate them behind text model availability; the text
|
|
216
|
+
// model assignment check only makes sense for text generation slots.
|
|
217
|
+
if (slot === "TEXT_TO_SPEECH" || slot === "TRANSCRIPTION") {
|
|
218
|
+
return candidates;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const hasLocalInference = candidates.some(
|
|
222
|
+
(candidate) => candidate.provider === "eliza-local-inference",
|
|
223
|
+
);
|
|
224
|
+
if (!hasLocalInference) {
|
|
225
|
+
return candidates;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const assignments = await readEffectiveAssignments();
|
|
229
|
+
return filterUnavailableLocalInferenceCandidates(
|
|
230
|
+
candidates,
|
|
231
|
+
Boolean(assignments[slot]) || localInferenceEngine.hasLoadedModel(),
|
|
232
|
+
shouldForceLocalInference(policy, preferredProvider),
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function makeRouterHandler(slot: AgentModelSlot): AnyHandler {
|
|
237
|
+
return async (runtime, params) => {
|
|
238
|
+
const modelType = slotToModelType(slot);
|
|
239
|
+
if (!modelType) {
|
|
240
|
+
throw new Error(`[router] Unknown agent slot: ${slot}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Global local-only override: ELIZA_LOCAL_ONLY=1 pins every slot to
|
|
244
|
+
// manual + eliza-local-inference, disabling cloud fallback entirely.
|
|
245
|
+
const globalLocalOnly = readBooleanEnv("ELIZA_LOCAL_ONLY");
|
|
246
|
+
|
|
247
|
+
// Read the user's policy for this slot. Absent = local-first fallback.
|
|
248
|
+
const prefs = await readRoutingPreferences();
|
|
249
|
+
const policy = globalLocalOnly
|
|
250
|
+
? "manual"
|
|
251
|
+
: (prefs.policy[slot] ?? DEFAULT_ROUTING_POLICY);
|
|
252
|
+
const preferred = globalLocalOnly
|
|
253
|
+
? "eliza-local-inference"
|
|
254
|
+
: (prefs.preferredProvider[slot] ?? null);
|
|
255
|
+
|
|
256
|
+
// Ask the policy engine which handler to dispatch to. For automatic
|
|
257
|
+
// policies, honor the documented fallback behaviour: if the selected
|
|
258
|
+
// provider throws, try the next eligible provider instead of surfacing a
|
|
259
|
+
// local/model-specific failure while cloud providers are available.
|
|
260
|
+
const registeredCandidates = handlerRegistry.getForTypeExcluding(
|
|
261
|
+
modelType,
|
|
262
|
+
ROUTER_PROVIDER,
|
|
263
|
+
);
|
|
264
|
+
const candidates = await filterUnavailableLocalInference(
|
|
265
|
+
slot,
|
|
266
|
+
policy,
|
|
267
|
+
preferred,
|
|
268
|
+
registeredCandidates.length > 0
|
|
269
|
+
? registeredCandidates
|
|
270
|
+
: getRuntimeModelCandidates(runtime, modelType),
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
// Only the capability-aware policies need a hardware assessment.
|
|
274
|
+
const deviceTier =
|
|
275
|
+
policy === "auto" || policy === "prefer-local"
|
|
276
|
+
? await resolveDeviceTier()
|
|
277
|
+
: null;
|
|
278
|
+
|
|
279
|
+
const failedProviders = new Set<string>();
|
|
280
|
+
let lastError: unknown = null;
|
|
281
|
+
|
|
282
|
+
while (true) {
|
|
283
|
+
const remaining = candidates.filter(
|
|
284
|
+
(candidate) => !failedProviders.has(candidate.provider),
|
|
285
|
+
);
|
|
286
|
+
const pick = policyEngine.pickProvider({
|
|
287
|
+
modelType,
|
|
288
|
+
policy,
|
|
289
|
+
preferredProvider: preferred,
|
|
290
|
+
candidates: remaining,
|
|
291
|
+
selfProvider: ROUTER_PROVIDER,
|
|
292
|
+
deviceTier,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
if (!pick) {
|
|
296
|
+
if (lastError) {
|
|
297
|
+
throw lastError;
|
|
298
|
+
}
|
|
299
|
+
throw new NoModelProviderConfiguredError(
|
|
300
|
+
`[router] No provider registered for ${slot}. Configure a cloud provider, enable local inference, or pair a device.`,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
policyEngine.recordPick(pick.provider, modelType);
|
|
305
|
+
const start = Date.now();
|
|
306
|
+
try {
|
|
307
|
+
const result = await pick.handler(runtime, params);
|
|
308
|
+
policyEngine.recordLatency(
|
|
309
|
+
pick.provider,
|
|
310
|
+
modelType,
|
|
311
|
+
Date.now() - start,
|
|
312
|
+
);
|
|
313
|
+
return result;
|
|
314
|
+
} catch (err) {
|
|
315
|
+
// Record the timing even on failure so "fastest" doesn't silently
|
|
316
|
+
// prefer providers that error out fast.
|
|
317
|
+
policyEngine.recordLatency(
|
|
318
|
+
pick.provider,
|
|
319
|
+
modelType,
|
|
320
|
+
Date.now() - start,
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const manualPreferred =
|
|
324
|
+
policy === "manual" &&
|
|
325
|
+
preferred !== null &&
|
|
326
|
+
pick.provider === preferred;
|
|
327
|
+
const hasAlternative = remaining.some(
|
|
328
|
+
(candidate) => candidate.provider !== pick.provider,
|
|
329
|
+
);
|
|
330
|
+
if (manualPreferred || !hasAlternative) {
|
|
331
|
+
throw err;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
failedProviders.add(pick.provider);
|
|
335
|
+
lastError = err;
|
|
336
|
+
logger.info(
|
|
337
|
+
`[router] Provider ${pick.provider} failed for ${slot}; trying fallback provider (${err instanceof Error ? err.message : String(err)})`,
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Install the router as the top-priority handler for every slot.
|
|
346
|
+
*
|
|
347
|
+
* Idempotent per-runtime via the handler-registry's "last write wins"
|
|
348
|
+
* behaviour — re-registering our handlers just refreshes them in place.
|
|
349
|
+
* Called from `ensure-local-inference-handler.ts` after `handlerRegistry`
|
|
350
|
+
* has been installed on the runtime.
|
|
351
|
+
*/
|
|
352
|
+
export interface RouterInstallOptions {
|
|
353
|
+
skipSlots?: readonly AgentModelSlot[];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export function installRouterHandler(
|
|
357
|
+
runtime: AgentRuntime,
|
|
358
|
+
options: RouterInstallOptions = {},
|
|
359
|
+
): void {
|
|
360
|
+
const rt = runtime as AgentRuntime & {
|
|
361
|
+
registerModel?: (
|
|
362
|
+
modelType: string,
|
|
363
|
+
handler: AnyHandler,
|
|
364
|
+
provider: string,
|
|
365
|
+
priority?: number,
|
|
366
|
+
) => void;
|
|
367
|
+
};
|
|
368
|
+
if (typeof rt.registerModel !== "function") return;
|
|
369
|
+
|
|
370
|
+
const skippedSlots = new Set(options.skipSlots ?? []);
|
|
371
|
+
for (const slot of AGENT_MODEL_SLOTS) {
|
|
372
|
+
if (skippedSlots.has(slot)) continue;
|
|
373
|
+
const modelType = slotToModelType(slot);
|
|
374
|
+
if (!modelType) continue;
|
|
375
|
+
rt.registerModel(
|
|
376
|
+
modelType,
|
|
377
|
+
makeRouterHandler(slot),
|
|
378
|
+
ROUTER_PROVIDER,
|
|
379
|
+
ROUTER_PRIORITY,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** Public helper — useful for diagnostics endpoints. */
|
|
385
|
+
export function describeCurrentRouting(): Array<{
|
|
386
|
+
slot: AgentModelSlot;
|
|
387
|
+
modelType: string;
|
|
388
|
+
candidates: Array<{
|
|
389
|
+
provider: string;
|
|
390
|
+
priority: number;
|
|
391
|
+
}>;
|
|
392
|
+
}> {
|
|
393
|
+
const out: ReturnType<typeof describeCurrentRouting> = [];
|
|
394
|
+
for (const slot of AGENT_MODEL_SLOTS) {
|
|
395
|
+
const modelType = slotToModelType(slot);
|
|
396
|
+
if (!modelType) continue;
|
|
397
|
+
const candidates = handlerRegistry
|
|
398
|
+
.getForTypeExcluding(modelType, ROUTER_PROVIDER)
|
|
399
|
+
.map((c) => ({ provider: c.provider, priority: c.priority }));
|
|
400
|
+
out.push({ slot, modelType, candidates });
|
|
401
|
+
}
|
|
402
|
+
return out;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Re-export so the handler registry can tell whether it's looking at a
|
|
406
|
+
// recursive router registration when filtering.
|
|
407
|
+
export { modelTypeToSlot };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy engine + latency + cost tracking for cross-provider routing.
|
|
3
|
+
*
|
|
4
|
+
* The policy engine sits on top of the `handlerRegistry` and, given a
|
|
5
|
+
* model type and a user-selected policy, decides which provider's handler
|
|
6
|
+
* should serve the next request. The router-handler (registered at top
|
|
7
|
+
* priority) calls `pickProvider` to make that decision.
|
|
8
|
+
*
|
|
9
|
+
* Policies:
|
|
10
|
+
* - manual — honour `preferredProvider`; when no pref set, fall
|
|
11
|
+
* through to the runtime's native priority order
|
|
12
|
+
* (highest registered priority wins).
|
|
13
|
+
* - auto — capability-driven: consult the device-tier assessment.
|
|
14
|
+
* When the device can comfortably run local inference
|
|
15
|
+
* (recommended mode "local", or a MAX/GOOD tier) AND a
|
|
16
|
+
* local handler is registered for the slot, pick local.
|
|
17
|
+
* Otherwise pick the highest-priority cloud provider.
|
|
18
|
+
* - cheapest — pick the provider with the lowest per-token cost.
|
|
19
|
+
* - fastest — pick the provider with the lowest tracked p50 latency
|
|
20
|
+
* (needs at least a few samples; falls back to native).
|
|
21
|
+
* - prefer-local — try local first; if it fails or has no handler,
|
|
22
|
+
* fall through to the next-best non-local. A POOR device
|
|
23
|
+
* tier (cannot run a local LM) softly demotes the local
|
|
24
|
+
* pick so an unusable on-device path isn't forced.
|
|
25
|
+
* - round-robin — distribute load evenly across eligible providers.
|
|
26
|
+
*
|
|
27
|
+
* Latency is tracked in a ring buffer per provider per model type. Cost
|
|
28
|
+
* is a static table of published per-million-token rates; local providers
|
|
29
|
+
* are $0. Neither is exact — the goal is "good enough to discriminate"
|
|
30
|
+
* rather than dollar-accurate billing.
|
|
31
|
+
*/
|
|
32
|
+
import type { DeviceTierAssessment } from "./device-tier";
|
|
33
|
+
import type { HandlerRegistration } from "./handler-registry";
|
|
34
|
+
import type { RoutingPolicy } from "./routing-preferences";
|
|
35
|
+
declare class PolicyEngine {
|
|
36
|
+
private stats;
|
|
37
|
+
private statsFor;
|
|
38
|
+
recordLatency(provider: string, modelType: string, durationMs: number): void;
|
|
39
|
+
recordPick(provider: string, modelType: string): void;
|
|
40
|
+
p50(provider: string, modelType: string): number | null;
|
|
41
|
+
lastPicked(provider: string, modelType: string): number | null;
|
|
42
|
+
costOf(provider: string): number | null;
|
|
43
|
+
/**
|
|
44
|
+
* Pick a provider for this (modelType, policy) given the registry.
|
|
45
|
+
* Returns the HandlerRegistration whose handler the router-handler
|
|
46
|
+
* should dispatch to, or null if no eligible handler exists.
|
|
47
|
+
*
|
|
48
|
+
* `preferredProvider` is only honoured for policy === "manual".
|
|
49
|
+
*/
|
|
50
|
+
pickProvider(args: {
|
|
51
|
+
modelType: string;
|
|
52
|
+
policy: RoutingPolicy;
|
|
53
|
+
preferredProvider: string | null;
|
|
54
|
+
candidates: HandlerRegistration[];
|
|
55
|
+
/** Provider ID of the router itself — always excluded from candidates. */
|
|
56
|
+
selfProvider: string;
|
|
57
|
+
/**
|
|
58
|
+
* Device-capability assessment from `classifyDeviceTier()`. Consulted by
|
|
59
|
+
* the `auto` policy and used as a soft hint by `prefer-local`. Null when
|
|
60
|
+
* the host hasn't probed hardware yet — `auto` then falls back to cloud.
|
|
61
|
+
*/
|
|
62
|
+
deviceTier?: DeviceTierAssessment | null;
|
|
63
|
+
}): HandlerRegistration | null;
|
|
64
|
+
/** For tests and diagnostics. */
|
|
65
|
+
snapshot(): Record<string, Record<string, number | null>>;
|
|
66
|
+
}
|
|
67
|
+
export declare const policyEngine: PolicyEngine;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=routing-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing-policy.d.ts","sourceRoot":"","sources":["routing-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAyG3D,cAAM,YAAY;IACjB,OAAO,CAAC,KAAK,CAAmD;IAEhE,OAAO,CAAC,QAAQ;IAShB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAU5E,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAIrD,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAIvD,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI9D,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAQvC;;;;;;OAMG;IACH,YAAY,CAAC,IAAI,EAAE;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,aAAa,CAAC;QACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,UAAU,EAAE,mBAAmB,EAAE,CAAC;QAClC,0EAA0E;QAC1E,YAAY,EAAE,MAAM,CAAC;QACrB;;;;WAIG;QACH,UAAU,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;KACzC,GAAG,mBAAmB,GAAG,IAAI;IAiF9B,iCAAiC;IACjC,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CAWzD;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { IAgentRuntime } from "@elizaos/core";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { classifyDeviceTier, type DeviceTierAssessment } from "./device-tier";
|
|
4
|
+
import type { HandlerRegistration } from "./handler-registry";
|
|
5
|
+
import { policyEngine } from "./routing-policy";
|
|
6
|
+
import type { HardwareProbe } from "./types";
|
|
7
|
+
|
|
8
|
+
const noopHandler: HandlerRegistration["handler"] = async (
|
|
9
|
+
_runtime: IAgentRuntime,
|
|
10
|
+
_params: Record<string, unknown>,
|
|
11
|
+
) => null;
|
|
12
|
+
|
|
13
|
+
function registration(provider: string, priority: number): HandlerRegistration {
|
|
14
|
+
return {
|
|
15
|
+
modelType: "TEXT_LARGE",
|
|
16
|
+
provider,
|
|
17
|
+
priority,
|
|
18
|
+
registeredAt: "test",
|
|
19
|
+
handler: noopHandler,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const baseProbe: HardwareProbe = {
|
|
24
|
+
totalRamGb: 16,
|
|
25
|
+
freeRamGb: 8,
|
|
26
|
+
gpu: null,
|
|
27
|
+
cpuCores: 8,
|
|
28
|
+
platform: "linux",
|
|
29
|
+
arch: "x64",
|
|
30
|
+
appleSilicon: false,
|
|
31
|
+
recommendedBucket: "mid",
|
|
32
|
+
source: "os-fallback",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// A CUDA workstation: 24 GB VRAM, plenty of free RAM → MAX tier, mode "local".
|
|
36
|
+
const strongDevice: DeviceTierAssessment = classifyDeviceTier({
|
|
37
|
+
...baseProbe,
|
|
38
|
+
totalRamGb: 64,
|
|
39
|
+
freeRamGb: 48,
|
|
40
|
+
gpu: { backend: "cuda", totalVramGb: 24, freeVramGb: 22 },
|
|
41
|
+
cpuCores: 16,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// A 4 GB Chromebook-class box → POOR tier, mode "cloud-only".
|
|
45
|
+
const weakDevice: DeviceTierAssessment = classifyDeviceTier({
|
|
46
|
+
...baseProbe,
|
|
47
|
+
totalRamGb: 4,
|
|
48
|
+
freeRamGb: 1.5,
|
|
49
|
+
cpuCores: 2,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("PolicyEngine — auto policy", () => {
|
|
53
|
+
it("classifier sanity: strong device favours local, weak device does not", () => {
|
|
54
|
+
expect(strongDevice.tier).toBe("MAX");
|
|
55
|
+
expect(strongDevice.recommendedMode).toBe("local");
|
|
56
|
+
expect(strongDevice.canRunLocalLm).toBe(true);
|
|
57
|
+
expect(weakDevice.tier).toBe("POOR");
|
|
58
|
+
expect(weakDevice.canRunLocalLm).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("routes a strong device to the local provider", () => {
|
|
62
|
+
const pick = policyEngine.pickProvider({
|
|
63
|
+
modelType: "TEXT_LARGE",
|
|
64
|
+
policy: "auto",
|
|
65
|
+
preferredProvider: null,
|
|
66
|
+
candidates: [
|
|
67
|
+
registration("eliza-local-inference", -100),
|
|
68
|
+
registration("anthropic", 0),
|
|
69
|
+
],
|
|
70
|
+
selfProvider: "eliza-router",
|
|
71
|
+
deviceTier: strongDevice,
|
|
72
|
+
});
|
|
73
|
+
expect(pick?.provider).toBe("eliza-local-inference");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("routes a weak device to the highest-priority cloud provider", () => {
|
|
77
|
+
const pick = policyEngine.pickProvider({
|
|
78
|
+
modelType: "TEXT_LARGE",
|
|
79
|
+
policy: "auto",
|
|
80
|
+
preferredProvider: null,
|
|
81
|
+
candidates: [
|
|
82
|
+
registration("eliza-local-inference", -100),
|
|
83
|
+
registration("anthropic", 0),
|
|
84
|
+
registration("elizacloud", 50),
|
|
85
|
+
],
|
|
86
|
+
selfProvider: "eliza-router",
|
|
87
|
+
deviceTier: weakDevice,
|
|
88
|
+
});
|
|
89
|
+
expect(pick?.provider).toBe("elizacloud");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("falls back to cloud when no device assessment is available", () => {
|
|
93
|
+
const pick = policyEngine.pickProvider({
|
|
94
|
+
modelType: "TEXT_LARGE",
|
|
95
|
+
policy: "auto",
|
|
96
|
+
preferredProvider: null,
|
|
97
|
+
candidates: [
|
|
98
|
+
registration("eliza-local-inference", -100),
|
|
99
|
+
registration("anthropic", 0),
|
|
100
|
+
],
|
|
101
|
+
selfProvider: "eliza-router",
|
|
102
|
+
deviceTier: null,
|
|
103
|
+
});
|
|
104
|
+
expect(pick?.provider).toBe("anthropic");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("uses the only available provider even if it is local on a weak device", () => {
|
|
108
|
+
const pick = policyEngine.pickProvider({
|
|
109
|
+
modelType: "TEXT_LARGE",
|
|
110
|
+
policy: "auto",
|
|
111
|
+
preferredProvider: null,
|
|
112
|
+
candidates: [registration("eliza-local-inference", -100)],
|
|
113
|
+
selfProvider: "eliza-router",
|
|
114
|
+
deviceTier: weakDevice,
|
|
115
|
+
});
|
|
116
|
+
expect(pick?.provider).toBe("eliza-local-inference");
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe("PolicyEngine — prefer-local capability soft-hint", () => {
|
|
121
|
+
it("keeps local-first when no assessment is provided", () => {
|
|
122
|
+
const pick = policyEngine.pickProvider({
|
|
123
|
+
modelType: "TEXT_LARGE",
|
|
124
|
+
policy: "prefer-local",
|
|
125
|
+
preferredProvider: null,
|
|
126
|
+
candidates: [
|
|
127
|
+
registration("eliza-local-inference", -100),
|
|
128
|
+
registration("anthropic", 0),
|
|
129
|
+
],
|
|
130
|
+
selfProvider: "eliza-router",
|
|
131
|
+
});
|
|
132
|
+
expect(pick?.provider).toBe("eliza-local-inference");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("demotes to cloud on a POOR device that cannot run a local LM", () => {
|
|
136
|
+
const pick = policyEngine.pickProvider({
|
|
137
|
+
modelType: "TEXT_LARGE",
|
|
138
|
+
policy: "prefer-local",
|
|
139
|
+
preferredProvider: null,
|
|
140
|
+
candidates: [
|
|
141
|
+
registration("eliza-local-inference", -100),
|
|
142
|
+
registration("anthropic", 0),
|
|
143
|
+
],
|
|
144
|
+
selfProvider: "eliza-router",
|
|
145
|
+
deviceTier: weakDevice,
|
|
146
|
+
});
|
|
147
|
+
expect(pick?.provider).toBe("anthropic");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("still prefers local on a strong device", () => {
|
|
151
|
+
const pick = policyEngine.pickProvider({
|
|
152
|
+
modelType: "TEXT_LARGE",
|
|
153
|
+
policy: "prefer-local",
|
|
154
|
+
preferredProvider: null,
|
|
155
|
+
candidates: [
|
|
156
|
+
registration("eliza-local-inference", -100),
|
|
157
|
+
registration("anthropic", 0),
|
|
158
|
+
],
|
|
159
|
+
selfProvider: "eliza-router",
|
|
160
|
+
deviceTier: strongDevice,
|
|
161
|
+
});
|
|
162
|
+
expect(pick?.provider).toBe("eliza-local-inference");
|
|
163
|
+
});
|
|
164
|
+
});
|