@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
package/dist/index.js
DELETED
|
@@ -1,1098 +0,0 @@
|
|
|
1
|
-
// src/local-inference-routes.ts
|
|
2
|
-
import crypto from "crypto";
|
|
3
|
-
import * as dns from "dns";
|
|
4
|
-
import fs from "fs";
|
|
5
|
-
import fsp from "fs/promises";
|
|
6
|
-
import * as http from "http";
|
|
7
|
-
import * as https from "https";
|
|
8
|
-
import os from "os";
|
|
9
|
-
import path from "path";
|
|
10
|
-
import {
|
|
11
|
-
logger,
|
|
12
|
-
readJsonBody,
|
|
13
|
-
resolveStateDir,
|
|
14
|
-
sendJson,
|
|
15
|
-
sendJsonError
|
|
16
|
-
} from "@elizaos/core";
|
|
17
|
-
import {
|
|
18
|
-
getMobileDeviceBridgeStatus,
|
|
19
|
-
loadMobileDeviceBridgeModel,
|
|
20
|
-
unloadMobileDeviceBridgeModel
|
|
21
|
-
} from "@elizaos/plugin-capacitor-bridge";
|
|
22
|
-
var activeModelState = { modelId: null, loadedAt: null, status: "idle" };
|
|
23
|
-
function getLocalInferenceActiveModelId() {
|
|
24
|
-
return activeModelState.status === "ready" && activeModelState.modelId?.trim() ? activeModelState.modelId.trim() : void 0;
|
|
25
|
-
}
|
|
26
|
-
var CATALOG = [
|
|
27
|
-
{
|
|
28
|
-
id: "eliza-1-mobile-1_7b",
|
|
29
|
-
displayName: "Eliza-1 mobile 1.7B",
|
|
30
|
-
hfRepo: "elizaos/eliza-1-mobile-1_7b",
|
|
31
|
-
ggufFile: "text/eliza-1-mobile-1_7b-32k.gguf",
|
|
32
|
-
params: "1.7B",
|
|
33
|
-
quant: "fused GGUF",
|
|
34
|
-
sizeGb: 1.2,
|
|
35
|
-
minRamGb: 4,
|
|
36
|
-
category: "chat",
|
|
37
|
-
bucket: "small",
|
|
38
|
-
blurb: "Default local Eliza-1 chat model for mobile and laptops.",
|
|
39
|
-
role: "chat"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
id: "eliza-1-desktop-9b",
|
|
43
|
-
displayName: "Eliza-1 desktop 9B",
|
|
44
|
-
hfRepo: "elizaos/eliza-1-desktop-9b",
|
|
45
|
-
ggufFile: "text/eliza-1-desktop-9b-64k.gguf",
|
|
46
|
-
params: "9B",
|
|
47
|
-
quant: "fused GGUF",
|
|
48
|
-
sizeGb: 5.4,
|
|
49
|
-
minRamGb: 16,
|
|
50
|
-
category: "chat",
|
|
51
|
-
bucket: "medium",
|
|
52
|
-
blurb: "Higher-quality Eliza-1 local chat model for desktop systems.",
|
|
53
|
-
role: "chat"
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
id: "eliza-1-lite-0_6b",
|
|
57
|
-
displayName: "Eliza-1 lite embeddings",
|
|
58
|
-
hfRepo: "elizaos/eliza-1-lite-0_6b",
|
|
59
|
-
ggufFile: "text/eliza-1-lite-0_6b-32k.gguf",
|
|
60
|
-
params: "0.6B",
|
|
61
|
-
quant: "fused GGUF",
|
|
62
|
-
sizeGb: 0.5,
|
|
63
|
-
minRamGb: 1,
|
|
64
|
-
category: "tiny",
|
|
65
|
-
bucket: "small",
|
|
66
|
-
blurb: "Default Eliza-1 local embedding model for memory and knowledge search.",
|
|
67
|
-
role: "embedding"
|
|
68
|
-
}
|
|
69
|
-
];
|
|
70
|
-
var activeDownloads = /* @__PURE__ */ new Map();
|
|
71
|
-
var MOBILE_DNS_SERVERS = ["8.8.8.8", "1.1.1.1"];
|
|
72
|
-
var mobileDnsResolver = new dns.Resolver();
|
|
73
|
-
mobileDnsResolver.setServers(MOBILE_DNS_SERVERS);
|
|
74
|
-
function stateDir() {
|
|
75
|
-
return resolveStateDir();
|
|
76
|
-
}
|
|
77
|
-
function localInferenceRoot() {
|
|
78
|
-
return path.join(stateDir(), "local-inference");
|
|
79
|
-
}
|
|
80
|
-
function modelsDir() {
|
|
81
|
-
return path.join(localInferenceRoot(), "models");
|
|
82
|
-
}
|
|
83
|
-
function downloadsDir() {
|
|
84
|
-
return path.join(localInferenceRoot(), "downloads");
|
|
85
|
-
}
|
|
86
|
-
function registryPath() {
|
|
87
|
-
return path.join(localInferenceRoot(), "registry.json");
|
|
88
|
-
}
|
|
89
|
-
function assignmentsPath() {
|
|
90
|
-
return path.join(localInferenceRoot(), "assignments.json");
|
|
91
|
-
}
|
|
92
|
-
function routingPath() {
|
|
93
|
-
return path.join(localInferenceRoot(), "routing.json");
|
|
94
|
-
}
|
|
95
|
-
function finalModelPath(model) {
|
|
96
|
-
return path.join(
|
|
97
|
-
modelsDir(),
|
|
98
|
-
`${model.id.replace(/[^a-zA-Z0-9._-]/g, "_")}.gguf`
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
function stagingPath(model) {
|
|
102
|
-
return path.join(
|
|
103
|
-
downloadsDir(),
|
|
104
|
-
`${model.id.replace(/[^a-zA-Z0-9._-]/g, "_")}.part`
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
function huggingFaceResolveUrl(model) {
|
|
108
|
-
const base = process.env.ELIZA_HF_BASE_URL?.trim().replace(/\/+$/, "") || "https://huggingface.co";
|
|
109
|
-
const encodedPath = model.ggufFile.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
110
|
-
return `${base}/${model.hfRepo}/resolve/main/${encodedPath}?download=true`;
|
|
111
|
-
}
|
|
112
|
-
function shouldUseMobileDns() {
|
|
113
|
-
const platform = process.env.ELIZA_PLATFORM?.toLowerCase();
|
|
114
|
-
return platform === "android" || platform === "ios";
|
|
115
|
-
}
|
|
116
|
-
var mobileLookup = (hostname, options, callback) => {
|
|
117
|
-
mobileDnsResolver.resolve4(hostname, (error, addresses) => {
|
|
118
|
-
if (error) {
|
|
119
|
-
callback(error, void 0, void 0);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
if (options?.all) {
|
|
123
|
-
callback(
|
|
124
|
-
null,
|
|
125
|
-
addresses.map((address) => ({ address, family: 4 })),
|
|
126
|
-
void 0
|
|
127
|
-
);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
callback(null, addresses[0], 4);
|
|
131
|
-
});
|
|
132
|
-
};
|
|
133
|
-
async function openDownloadResponse(url, headers, signal, redirectCount = 0) {
|
|
134
|
-
if (redirectCount > 5) {
|
|
135
|
-
throw new Error("Too many redirects while downloading model");
|
|
136
|
-
}
|
|
137
|
-
const parsed = new URL(url);
|
|
138
|
-
const transport = parsed.protocol === "http:" ? http : https;
|
|
139
|
-
return new Promise((resolve, reject) => {
|
|
140
|
-
const req = transport.get(
|
|
141
|
-
parsed,
|
|
142
|
-
{
|
|
143
|
-
headers,
|
|
144
|
-
lookup: shouldUseMobileDns() ? mobileLookup : void 0
|
|
145
|
-
},
|
|
146
|
-
(response) => {
|
|
147
|
-
const statusCode = response.statusCode ?? 0;
|
|
148
|
-
const location = response.headers.location;
|
|
149
|
-
if (location && [301, 302, 303, 307, 308].includes(statusCode)) {
|
|
150
|
-
response.resume();
|
|
151
|
-
resolve(
|
|
152
|
-
openDownloadResponse(
|
|
153
|
-
new URL(location, parsed).toString(),
|
|
154
|
-
headers,
|
|
155
|
-
signal,
|
|
156
|
-
redirectCount + 1
|
|
157
|
-
)
|
|
158
|
-
);
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
resolve(response);
|
|
162
|
-
}
|
|
163
|
-
);
|
|
164
|
-
const abort = () => {
|
|
165
|
-
req.destroy(new Error("Download cancelled"));
|
|
166
|
-
};
|
|
167
|
-
if (signal.aborted) {
|
|
168
|
-
abort();
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
172
|
-
req.on("error", reject);
|
|
173
|
-
req.on("close", () => signal.removeEventListener("abort", abort));
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
async function ensureLocalInferenceDirs() {
|
|
177
|
-
await fsp.mkdir(modelsDir(), { recursive: true });
|
|
178
|
-
await fsp.mkdir(downloadsDir(), { recursive: true });
|
|
179
|
-
}
|
|
180
|
-
async function readJsonFile(filePath, fallback) {
|
|
181
|
-
try {
|
|
182
|
-
return JSON.parse(await fsp.readFile(filePath, "utf8"));
|
|
183
|
-
} catch {
|
|
184
|
-
return fallback;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
async function writeJsonFile(filePath, payload) {
|
|
188
|
-
await fsp.mkdir(path.dirname(filePath), { recursive: true });
|
|
189
|
-
const tmp = `${filePath}.tmp`;
|
|
190
|
-
await fsp.writeFile(tmp, JSON.stringify(payload, null, 2), "utf8");
|
|
191
|
-
await fsp.rename(tmp, filePath);
|
|
192
|
-
}
|
|
193
|
-
async function hashFile(filePath) {
|
|
194
|
-
return new Promise((resolve, reject) => {
|
|
195
|
-
const hash = crypto.createHash("sha256");
|
|
196
|
-
const stream = fs.createReadStream(filePath, {
|
|
197
|
-
highWaterMark: 1024 * 1024
|
|
198
|
-
});
|
|
199
|
-
stream.on("data", (chunk) => hash.update(chunk));
|
|
200
|
-
stream.on("end", () => resolve(hash.digest("hex")));
|
|
201
|
-
stream.on("error", reject);
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
async function isGgufFile(filePath) {
|
|
205
|
-
try {
|
|
206
|
-
const file = await fsp.open(filePath, "r");
|
|
207
|
-
try {
|
|
208
|
-
const buffer = Buffer.alloc(4);
|
|
209
|
-
await file.read(buffer, 0, 4, 0);
|
|
210
|
-
return buffer.toString("ascii") === "GGUF";
|
|
211
|
-
} finally {
|
|
212
|
-
await file.close();
|
|
213
|
-
}
|
|
214
|
-
} catch {
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
async function readRegistry() {
|
|
219
|
-
const registry = await readJsonFile(registryPath(), { version: 1, models: [] });
|
|
220
|
-
const models = Array.isArray(registry.models) ? registry.models : [];
|
|
221
|
-
const installed = [];
|
|
222
|
-
for (const model of models) {
|
|
223
|
-
if (!model?.id || !model.path) continue;
|
|
224
|
-
try {
|
|
225
|
-
const stat = await fsp.stat(model.path);
|
|
226
|
-
if (stat.isFile()) installed.push({ ...model, sizeBytes: stat.size });
|
|
227
|
-
} catch {
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return installed;
|
|
231
|
-
}
|
|
232
|
-
async function writeRegistry(models) {
|
|
233
|
-
await writeJsonFile(registryPath(), { version: 1, models });
|
|
234
|
-
}
|
|
235
|
-
async function upsertInstalledModel(model) {
|
|
236
|
-
const current = await readRegistry();
|
|
237
|
-
await writeRegistry([
|
|
238
|
-
...current.filter((entry) => entry.id !== model.id),
|
|
239
|
-
model
|
|
240
|
-
]);
|
|
241
|
-
}
|
|
242
|
-
async function removeInstalledModel(id) {
|
|
243
|
-
const current = await readRegistry();
|
|
244
|
-
const target = current.find((model) => model.id === id);
|
|
245
|
-
if (!target) return false;
|
|
246
|
-
await fsp.rm(target.path, { force: true });
|
|
247
|
-
await writeRegistry(current.filter((model) => model.id !== id));
|
|
248
|
-
return true;
|
|
249
|
-
}
|
|
250
|
-
async function readAssignments() {
|
|
251
|
-
const file = await readJsonFile(
|
|
252
|
-
assignmentsPath(),
|
|
253
|
-
{
|
|
254
|
-
assignments: {}
|
|
255
|
-
}
|
|
256
|
-
);
|
|
257
|
-
return file.assignments ?? {};
|
|
258
|
-
}
|
|
259
|
-
async function writeAssignments(assignments) {
|
|
260
|
-
await writeJsonFile(assignmentsPath(), { version: 1, assignments });
|
|
261
|
-
return assignments;
|
|
262
|
-
}
|
|
263
|
-
function defaultRoutingPreferences() {
|
|
264
|
-
return {
|
|
265
|
-
version: 1,
|
|
266
|
-
preferences: {
|
|
267
|
-
preferredProvider: {},
|
|
268
|
-
policy: {}
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
async function assignModel(model, overwrite) {
|
|
273
|
-
const assignments = await readAssignments();
|
|
274
|
-
if (model.role === "embedding") {
|
|
275
|
-
if (overwrite || !assignments.TEXT_EMBEDDING) {
|
|
276
|
-
assignments.TEXT_EMBEDDING = model.id;
|
|
277
|
-
}
|
|
278
|
-
} else if (model.role === "chat") {
|
|
279
|
-
if (overwrite || !assignments.TEXT_SMALL) assignments.TEXT_SMALL = model.id;
|
|
280
|
-
if (overwrite || !assignments.TEXT_LARGE) assignments.TEXT_LARGE = model.id;
|
|
281
|
-
}
|
|
282
|
-
await writeAssignments(assignments);
|
|
283
|
-
}
|
|
284
|
-
async function ensureDefaultAssignment(model) {
|
|
285
|
-
await assignModel(model, false);
|
|
286
|
-
}
|
|
287
|
-
async function downloadModel(model, record) {
|
|
288
|
-
const abortController = activeDownloads.get(model.id)?.abortController;
|
|
289
|
-
if (!abortController) return;
|
|
290
|
-
const finalPath = finalModelPath(model);
|
|
291
|
-
const partialPath = stagingPath(model);
|
|
292
|
-
const existingPartial = await fsp.stat(partialPath).then((stat) => stat.isFile() ? stat.size : 0).catch(() => 0);
|
|
293
|
-
record.state = "downloading";
|
|
294
|
-
record.received = existingPartial;
|
|
295
|
-
record.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
296
|
-
try {
|
|
297
|
-
const headers = {
|
|
298
|
-
"user-agent": "Eliza-MobileLocalInference/1.0"
|
|
299
|
-
};
|
|
300
|
-
if (existingPartial > 0) headers.range = `bytes=${existingPartial}-`;
|
|
301
|
-
const response = await openDownloadResponse(
|
|
302
|
-
huggingFaceResolveUrl(model),
|
|
303
|
-
headers,
|
|
304
|
-
abortController.signal
|
|
305
|
-
);
|
|
306
|
-
const statusCode = response.statusCode ?? 0;
|
|
307
|
-
if (statusCode < 200 || statusCode >= 300) {
|
|
308
|
-
throw new Error(`HTTP ${statusCode} ${response.statusMessage ?? ""}`);
|
|
309
|
-
}
|
|
310
|
-
const contentLength = Number.parseInt(
|
|
311
|
-
String(response.headers["content-length"] ?? "0"),
|
|
312
|
-
10
|
|
313
|
-
);
|
|
314
|
-
if (Number.isFinite(contentLength) && contentLength > 0) {
|
|
315
|
-
record.total = existingPartial + contentLength;
|
|
316
|
-
}
|
|
317
|
-
const stream = fs.createWriteStream(partialPath, {
|
|
318
|
-
flags: existingPartial > 0 ? "a" : "w"
|
|
319
|
-
});
|
|
320
|
-
let lastSampleAt = Date.now();
|
|
321
|
-
let lastSampleBytes = record.received;
|
|
322
|
-
try {
|
|
323
|
-
for await (const chunk of response) {
|
|
324
|
-
const value = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
325
|
-
if (!stream.write(Buffer.from(value))) {
|
|
326
|
-
await new Promise((resolve) => stream.once("drain", resolve));
|
|
327
|
-
}
|
|
328
|
-
record.received += value.length;
|
|
329
|
-
const now = Date.now();
|
|
330
|
-
const elapsed = now - lastSampleAt;
|
|
331
|
-
if (elapsed >= 1e3) {
|
|
332
|
-
record.bytesPerSec = (record.received - lastSampleBytes) * 1e3 / elapsed;
|
|
333
|
-
record.etaMs = record.bytesPerSec > 0 ? (record.total - record.received) * 1e3 / record.bytesPerSec : null;
|
|
334
|
-
lastSampleAt = now;
|
|
335
|
-
lastSampleBytes = record.received;
|
|
336
|
-
record.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
} finally {
|
|
340
|
-
stream.end();
|
|
341
|
-
await new Promise((resolve, reject) => {
|
|
342
|
-
stream.on("finish", resolve);
|
|
343
|
-
stream.on("error", reject);
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
await fsp.rename(partialPath, finalPath);
|
|
347
|
-
if (!await isGgufFile(finalPath)) {
|
|
348
|
-
throw new Error("Downloaded file is not a valid GGUF");
|
|
349
|
-
}
|
|
350
|
-
const stat = await fsp.stat(finalPath);
|
|
351
|
-
const sha256 = await hashFile(finalPath);
|
|
352
|
-
await upsertInstalledModel({
|
|
353
|
-
id: model.id,
|
|
354
|
-
displayName: model.displayName,
|
|
355
|
-
path: finalPath,
|
|
356
|
-
sizeBytes: stat.size,
|
|
357
|
-
hfRepo: model.hfRepo,
|
|
358
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
359
|
-
lastUsedAt: null,
|
|
360
|
-
source: "eliza-download",
|
|
361
|
-
sha256,
|
|
362
|
-
lastVerifiedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
363
|
-
});
|
|
364
|
-
await ensureDefaultAssignment(model);
|
|
365
|
-
for (const companionId of model.companionModelIds ?? []) {
|
|
366
|
-
if (!activeDownloads.has(companionId)) {
|
|
367
|
-
void startDownload(companionId).catch((error) => {
|
|
368
|
-
logger.warn(
|
|
369
|
-
`[local-inference] Companion download failed for ${companionId}: ${error instanceof Error ? error.message : String(error)}`
|
|
370
|
-
);
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
record.state = "completed";
|
|
375
|
-
record.received = stat.size;
|
|
376
|
-
record.total = stat.size;
|
|
377
|
-
record.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
378
|
-
} catch (error) {
|
|
379
|
-
if (abortController.signal.aborted) {
|
|
380
|
-
record.state = "cancelled";
|
|
381
|
-
} else {
|
|
382
|
-
record.state = "failed";
|
|
383
|
-
record.error = error instanceof Error ? error.message : String(error);
|
|
384
|
-
logger.warn(
|
|
385
|
-
`[local-inference] Download failed for ${model.id}: ${record.error}`
|
|
386
|
-
);
|
|
387
|
-
}
|
|
388
|
-
record.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
389
|
-
} finally {
|
|
390
|
-
if (record.state !== "downloading") {
|
|
391
|
-
activeDownloads.delete(model.id);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
async function startDownload(modelId) {
|
|
396
|
-
const existing = activeDownloads.get(modelId);
|
|
397
|
-
if (existing) return { ...existing.job };
|
|
398
|
-
const model = CATALOG.find((entry) => entry.id === modelId);
|
|
399
|
-
if (!model) throw new Error(`Unknown model id: ${modelId}`);
|
|
400
|
-
await ensureLocalInferenceDirs();
|
|
401
|
-
const job = {
|
|
402
|
-
jobId: crypto.randomUUID(),
|
|
403
|
-
modelId,
|
|
404
|
-
state: "queued",
|
|
405
|
-
received: 0,
|
|
406
|
-
total: Math.round(model.sizeGb * 1024 ** 3),
|
|
407
|
-
bytesPerSec: 0,
|
|
408
|
-
etaMs: null,
|
|
409
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
410
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
411
|
-
};
|
|
412
|
-
activeDownloads.set(modelId, {
|
|
413
|
-
job,
|
|
414
|
-
abortController: new AbortController()
|
|
415
|
-
});
|
|
416
|
-
void downloadModel(model, job);
|
|
417
|
-
return { ...job };
|
|
418
|
-
}
|
|
419
|
-
async function installedSnapshot() {
|
|
420
|
-
await ensureLocalInferenceDirs();
|
|
421
|
-
return readRegistry();
|
|
422
|
-
}
|
|
423
|
-
async function getLocalInferenceActiveSnapshot() {
|
|
424
|
-
const bridgeStatus = getMobileDeviceBridgeStatus();
|
|
425
|
-
const loadedPath = bridgeStatus.devices.find(
|
|
426
|
-
(device) => Boolean(device.loadedPath)
|
|
427
|
-
)?.loadedPath;
|
|
428
|
-
if (!loadedPath) return activeModelState;
|
|
429
|
-
const installed = (await installedSnapshot()).find(
|
|
430
|
-
(model) => model.path === loadedPath
|
|
431
|
-
);
|
|
432
|
-
if (!installed) return activeModelState;
|
|
433
|
-
const catalogModel = CATALOG.find((model) => model.id === installed.id);
|
|
434
|
-
if (catalogModel?.role !== "chat") return activeModelState;
|
|
435
|
-
return {
|
|
436
|
-
modelId: installed.id,
|
|
437
|
-
loadedAt: activeModelState.loadedAt,
|
|
438
|
-
status: "ready"
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
async function hubSnapshot() {
|
|
442
|
-
return {
|
|
443
|
-
catalog: CATALOG.filter((model) => !model.hiddenFromCatalog),
|
|
444
|
-
installed: await installedSnapshot(),
|
|
445
|
-
active: await getLocalInferenceActiveSnapshot(),
|
|
446
|
-
downloads: [...activeDownloads.values()].map(({ job }) => ({ ...job })),
|
|
447
|
-
hardware: {
|
|
448
|
-
totalRamGb: Math.round(os.totalmem() / 1024 ** 3 * 10) / 10,
|
|
449
|
-
freeRamGb: Math.round(os.freemem() / 1024 ** 3 * 10) / 10,
|
|
450
|
-
gpu: null,
|
|
451
|
-
cpuCores: os.cpus().length,
|
|
452
|
-
platform: process.platform,
|
|
453
|
-
arch: process.arch,
|
|
454
|
-
appleSilicon: process.platform === "darwin" && process.arch === "arm64",
|
|
455
|
-
recommendedBucket: "small",
|
|
456
|
-
source: "os-fallback"
|
|
457
|
-
},
|
|
458
|
-
assignments: await readAssignments()
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
function chatModels() {
|
|
462
|
-
return CATALOG.filter((model) => model.role === "chat");
|
|
463
|
-
}
|
|
464
|
-
function recommendedChatModel() {
|
|
465
|
-
const totalRamGb = os.totalmem() / 1024 ** 3;
|
|
466
|
-
const candidates = chatModels().filter((model) => totalRamGb >= model.minRamGb).sort((left, right) => {
|
|
467
|
-
const leftDflash = left.companionModelIds?.length ? 1 : 0;
|
|
468
|
-
const rightDflash = right.companionModelIds?.length ? 1 : 0;
|
|
469
|
-
if (leftDflash !== rightDflash && totalRamGb >= 6) {
|
|
470
|
-
return rightDflash - leftDflash;
|
|
471
|
-
}
|
|
472
|
-
return right.sizeGb - left.sizeGb;
|
|
473
|
-
});
|
|
474
|
-
return candidates[0] ?? chatModels().sort((a, b) => a.sizeGb - b.sizeGb)[0] ?? null;
|
|
475
|
-
}
|
|
476
|
-
function isNoSpaceMessage(value) {
|
|
477
|
-
const message = value instanceof Error ? value.message : typeof value === "string" ? value : "";
|
|
478
|
-
return /\b(?:enospc|no space left|disk full|not enough (?:disk )?space|insufficient storage)\b/i.test(
|
|
479
|
-
message
|
|
480
|
-
);
|
|
481
|
-
}
|
|
482
|
-
function formatBytes(bytes) {
|
|
483
|
-
if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
|
|
484
|
-
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
485
|
-
let value = bytes;
|
|
486
|
-
let unitIndex = 0;
|
|
487
|
-
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
488
|
-
value /= 1024;
|
|
489
|
-
unitIndex += 1;
|
|
490
|
-
}
|
|
491
|
-
const precision = value >= 10 || unitIndex === 0 ? 0 : 1;
|
|
492
|
-
return `${value.toFixed(precision)} ${units[unitIndex]}`;
|
|
493
|
-
}
|
|
494
|
-
function progressForJob(job) {
|
|
495
|
-
const percent = job.total > 0 ? Math.max(0, Math.min(100, Math.round(job.received / job.total * 100))) : void 0;
|
|
496
|
-
return {
|
|
497
|
-
...typeof percent === "number" ? { percent } : {},
|
|
498
|
-
receivedBytes: job.received,
|
|
499
|
-
totalBytes: job.total,
|
|
500
|
-
...job.bytesPerSec > 0 ? { bytesPerSec: Math.round(job.bytesPerSec) } : {},
|
|
501
|
-
etaMs: job.etaMs
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
function progressText(progress) {
|
|
505
|
-
if (!progress) return "";
|
|
506
|
-
const percent = typeof progress.percent === "number" ? `${progress.percent}%` : "progress";
|
|
507
|
-
const total = progress.totalBytes > 0 ? ` of ${formatBytes(progress.totalBytes)}` : "";
|
|
508
|
-
return `${percent} (${formatBytes(progress.receivedBytes)}${total})`;
|
|
509
|
-
}
|
|
510
|
-
function pickStatusLine(status) {
|
|
511
|
-
const variants = {
|
|
512
|
-
missing: [
|
|
513
|
-
"I do not have a local chat model installed yet.",
|
|
514
|
-
"Local chat is waiting on a model download.",
|
|
515
|
-
"There is no local chat model ready on this device."
|
|
516
|
-
],
|
|
517
|
-
downloading: [
|
|
518
|
-
"The local model is still downloading.",
|
|
519
|
-
"I am still pulling down the local model.",
|
|
520
|
-
"Local inference is waiting for the model download to finish."
|
|
521
|
-
],
|
|
522
|
-
loading: [
|
|
523
|
-
"The local model is loading now.",
|
|
524
|
-
"I am warming up the local model.",
|
|
525
|
-
"Local inference is still bringing the model online."
|
|
526
|
-
],
|
|
527
|
-
failed: [
|
|
528
|
-
"The local model setup hit an error.",
|
|
529
|
-
"Local inference failed before generation could start.",
|
|
530
|
-
"The local model is not ready because the last operation failed."
|
|
531
|
-
],
|
|
532
|
-
no_space: [
|
|
533
|
-
"The local model needs more disk space before it can finish.",
|
|
534
|
-
"Local inference is blocked because storage is full.",
|
|
535
|
-
"The model download cannot continue until some disk space is freed."
|
|
536
|
-
],
|
|
537
|
-
idle: [
|
|
538
|
-
"A local model is installed, but none is loaded right now.",
|
|
539
|
-
"Local inference is idle with an installed model available.",
|
|
540
|
-
"The local model is installed and waiting to be activated."
|
|
541
|
-
],
|
|
542
|
-
ready: [
|
|
543
|
-
"Local inference is ready.",
|
|
544
|
-
"The local model is loaded and ready.",
|
|
545
|
-
"On-device inference is online."
|
|
546
|
-
],
|
|
547
|
-
cancelled: [
|
|
548
|
-
"I cancelled the local model download.",
|
|
549
|
-
"The local download has been stopped.",
|
|
550
|
-
"Local model download cancelled."
|
|
551
|
-
],
|
|
552
|
-
routing: [
|
|
553
|
-
"I updated the inference routing.",
|
|
554
|
-
"The model routing preference is updated.",
|
|
555
|
-
"Inference routing has been changed."
|
|
556
|
-
]
|
|
557
|
-
};
|
|
558
|
-
const list = variants[status];
|
|
559
|
-
return list[Math.floor(Date.now() / 15e3) % list.length] ?? list[0];
|
|
560
|
-
}
|
|
561
|
-
function buildLocalInferenceChatResult(metadata, detail) {
|
|
562
|
-
const progress = progressText(metadata.progress);
|
|
563
|
-
const parts = [
|
|
564
|
-
pickStatusLine(metadata.status),
|
|
565
|
-
metadata.modelId ? `Model: ${metadata.modelId}.` : "",
|
|
566
|
-
progress ? `Progress: ${progress}.` : "",
|
|
567
|
-
metadata.error ? `Error: ${metadata.error}` : "",
|
|
568
|
-
detail ?? ""
|
|
569
|
-
].filter((part) => part.trim().length > 0);
|
|
570
|
-
return {
|
|
571
|
-
text: parts.join(" "),
|
|
572
|
-
localInference: metadata
|
|
573
|
-
};
|
|
574
|
-
}
|
|
575
|
-
function resolveRequestedCatalogModel(prompt) {
|
|
576
|
-
const normalized = prompt.toLowerCase();
|
|
577
|
-
return chatModels().find((model) => {
|
|
578
|
-
const candidates = [
|
|
579
|
-
model.id,
|
|
580
|
-
model.displayName,
|
|
581
|
-
model.params,
|
|
582
|
-
model.bucket,
|
|
583
|
-
model.category
|
|
584
|
-
].map((value) => value.toLowerCase());
|
|
585
|
-
return candidates.some((candidate) => normalized.includes(candidate));
|
|
586
|
-
}) ?? null;
|
|
587
|
-
}
|
|
588
|
-
async function resolveDefaultChatModel(prompt) {
|
|
589
|
-
const requested = resolveRequestedCatalogModel(prompt);
|
|
590
|
-
if (requested) return requested;
|
|
591
|
-
const installed = await installedSnapshot();
|
|
592
|
-
const active = await getLocalInferenceActiveSnapshot();
|
|
593
|
-
const activeCatalog = active.modelId ? CATALOG.find(
|
|
594
|
-
(model) => model.id === active.modelId && model.role === "chat"
|
|
595
|
-
) : null;
|
|
596
|
-
if (activeCatalog) return activeCatalog;
|
|
597
|
-
const installedCatalog = installed.map(
|
|
598
|
-
(entry) => CATALOG.find((model) => model.id === entry.id && model.role === "chat")
|
|
599
|
-
).filter((model) => Boolean(model)).sort((a, b) => a.sizeGb - b.sizeGb)[0];
|
|
600
|
-
return installedCatalog ?? recommendedChatModel();
|
|
601
|
-
}
|
|
602
|
-
async function setRoutingForChat(provider) {
|
|
603
|
-
const current = await readJsonFile(
|
|
604
|
-
routingPath(),
|
|
605
|
-
defaultRoutingPreferences()
|
|
606
|
-
);
|
|
607
|
-
const preferences = current.preferences ?? defaultRoutingPreferences().preferences;
|
|
608
|
-
for (const slot of ["TEXT_SMALL", "TEXT_LARGE"]) {
|
|
609
|
-
preferences.preferredProvider[slot] = provider;
|
|
610
|
-
preferences.policy[slot] = "manual";
|
|
611
|
-
}
|
|
612
|
-
await writeJsonFile(routingPath(), { version: 1, preferences });
|
|
613
|
-
}
|
|
614
|
-
async function activateInstalledModel(installed) {
|
|
615
|
-
activeModelState = {
|
|
616
|
-
modelId: installed.id,
|
|
617
|
-
loadedAt: null,
|
|
618
|
-
status: "loading"
|
|
619
|
-
};
|
|
620
|
-
try {
|
|
621
|
-
await loadMobileDeviceBridgeModel(installed.path, installed.id);
|
|
622
|
-
activeModelState = {
|
|
623
|
-
modelId: installed.id,
|
|
624
|
-
loadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
625
|
-
status: "ready"
|
|
626
|
-
};
|
|
627
|
-
return buildLocalInferenceChatResult({
|
|
628
|
-
intent: "use_local",
|
|
629
|
-
status: "ready",
|
|
630
|
-
modelId: installed.id,
|
|
631
|
-
activeModelId: installed.id,
|
|
632
|
-
provider: "capacitor-llama"
|
|
633
|
-
});
|
|
634
|
-
} catch (error) {
|
|
635
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
636
|
-
activeModelState = {
|
|
637
|
-
modelId: installed.id,
|
|
638
|
-
loadedAt: null,
|
|
639
|
-
status: "error",
|
|
640
|
-
error: message
|
|
641
|
-
};
|
|
642
|
-
return buildLocalInferenceChatResult({
|
|
643
|
-
intent: "use_local",
|
|
644
|
-
status: isNoSpaceMessage(message) ? "no_space" : "failed",
|
|
645
|
-
modelId: installed.id,
|
|
646
|
-
activeModelId: null,
|
|
647
|
-
error: message
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
async function getLocalInferenceChatStatus(intent = "status", error) {
|
|
652
|
-
const activeDownload = [...activeDownloads.values()].map(({ job }) => ({ ...job })).find((job) => job.state === "queued" || job.state === "downloading");
|
|
653
|
-
if (activeDownload) {
|
|
654
|
-
return buildLocalInferenceChatResult({
|
|
655
|
-
intent,
|
|
656
|
-
status: "downloading",
|
|
657
|
-
modelId: activeDownload.modelId,
|
|
658
|
-
activeModelId: activeModelState.modelId,
|
|
659
|
-
progress: progressForJob(activeDownload)
|
|
660
|
-
});
|
|
661
|
-
}
|
|
662
|
-
const active = await getLocalInferenceActiveSnapshot();
|
|
663
|
-
if (activeModelState.status === "loading") {
|
|
664
|
-
return buildLocalInferenceChatResult({
|
|
665
|
-
intent,
|
|
666
|
-
status: "loading",
|
|
667
|
-
modelId: activeModelState.modelId,
|
|
668
|
-
activeModelId: active.modelId
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
const errorMessage = error instanceof Error ? error.message : typeof error === "string" ? error : activeModelState.error;
|
|
672
|
-
if (errorMessage) {
|
|
673
|
-
return buildLocalInferenceChatResult({
|
|
674
|
-
intent,
|
|
675
|
-
status: isNoSpaceMessage(errorMessage) ? "no_space" : "failed",
|
|
676
|
-
modelId: activeModelState.modelId,
|
|
677
|
-
activeModelId: active.modelId,
|
|
678
|
-
error: errorMessage
|
|
679
|
-
});
|
|
680
|
-
}
|
|
681
|
-
if (active.status === "ready" && active.modelId) {
|
|
682
|
-
return buildLocalInferenceChatResult({
|
|
683
|
-
intent,
|
|
684
|
-
status: "ready",
|
|
685
|
-
modelId: active.modelId,
|
|
686
|
-
activeModelId: active.modelId,
|
|
687
|
-
provider: "capacitor-llama"
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
const installed = await installedSnapshot();
|
|
691
|
-
const installedChat = installed.find(
|
|
692
|
-
(entry) => CATALOG.some((model) => model.id === entry.id && model.role === "chat")
|
|
693
|
-
);
|
|
694
|
-
if (installedChat) {
|
|
695
|
-
return buildLocalInferenceChatResult({
|
|
696
|
-
intent,
|
|
697
|
-
status: "idle",
|
|
698
|
-
modelId: installedChat.id,
|
|
699
|
-
activeModelId: active.modelId
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
return buildLocalInferenceChatResult({
|
|
703
|
-
intent,
|
|
704
|
-
status: "missing",
|
|
705
|
-
modelId: null,
|
|
706
|
-
activeModelId: active.modelId
|
|
707
|
-
});
|
|
708
|
-
}
|
|
709
|
-
async function handleLocalInferenceChatCommand(intent, prompt) {
|
|
710
|
-
if (intent === "status") {
|
|
711
|
-
return getLocalInferenceChatStatus(intent);
|
|
712
|
-
}
|
|
713
|
-
if (intent === "cancel") {
|
|
714
|
-
const requested = resolveRequestedCatalogModel(prompt);
|
|
715
|
-
const targets = requested ? [requested.id] : [...activeDownloads.keys()];
|
|
716
|
-
for (const modelId of targets) {
|
|
717
|
-
activeDownloads.get(modelId)?.abortController.abort();
|
|
718
|
-
activeDownloads.delete(modelId);
|
|
719
|
-
}
|
|
720
|
-
return buildLocalInferenceChatResult({
|
|
721
|
-
intent,
|
|
722
|
-
status: "cancelled",
|
|
723
|
-
modelId: requested?.id ?? targets[0] ?? null,
|
|
724
|
-
activeModelId: activeModelState.modelId
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
if (intent === "use_cloud") {
|
|
728
|
-
await setRoutingForChat("elizacloud");
|
|
729
|
-
return buildLocalInferenceChatResult(
|
|
730
|
-
{
|
|
731
|
-
intent,
|
|
732
|
-
status: "routing",
|
|
733
|
-
modelId: activeModelState.modelId,
|
|
734
|
-
activeModelId: activeModelState.modelId,
|
|
735
|
-
provider: "elizacloud"
|
|
736
|
-
},
|
|
737
|
-
"Future chat model calls will prefer Eliza Cloud."
|
|
738
|
-
);
|
|
739
|
-
}
|
|
740
|
-
if (intent === "use_local") {
|
|
741
|
-
await setRoutingForChat("capacitor-llama");
|
|
742
|
-
const installed = await installedSnapshot();
|
|
743
|
-
const requested = await resolveDefaultChatModel(prompt);
|
|
744
|
-
const installedModel = installed.find(
|
|
745
|
-
(entry) => entry.id === requested?.id
|
|
746
|
-
);
|
|
747
|
-
if (installedModel) {
|
|
748
|
-
return activateInstalledModel(installedModel);
|
|
749
|
-
}
|
|
750
|
-
if (requested) {
|
|
751
|
-
const job2 = await startDownload(requested.id);
|
|
752
|
-
return buildLocalInferenceChatResult(
|
|
753
|
-
{
|
|
754
|
-
intent: "download",
|
|
755
|
-
status: "downloading",
|
|
756
|
-
modelId: requested.id,
|
|
757
|
-
activeModelId: activeModelState.modelId,
|
|
758
|
-
provider: "capacitor-llama",
|
|
759
|
-
progress: progressForJob(job2)
|
|
760
|
-
},
|
|
761
|
-
"I also set chat routing to prefer local inference."
|
|
762
|
-
);
|
|
763
|
-
}
|
|
764
|
-
return getLocalInferenceChatStatus(intent);
|
|
765
|
-
}
|
|
766
|
-
if (intent === "switch_smaller") {
|
|
767
|
-
const active = await getLocalInferenceActiveSnapshot();
|
|
768
|
-
const installed = await installedSnapshot();
|
|
769
|
-
const activeCatalog = active.modelId ? CATALOG.find((model2) => model2.id === active.modelId) : null;
|
|
770
|
-
const smallerInstalled = installed.map((entry) => ({
|
|
771
|
-
entry,
|
|
772
|
-
catalog: CATALOG.find(
|
|
773
|
-
(model2) => model2.id === entry.id && model2.role === "chat"
|
|
774
|
-
)
|
|
775
|
-
})).filter(
|
|
776
|
-
(entry) => {
|
|
777
|
-
const catalog = entry.catalog;
|
|
778
|
-
if (!catalog) return false;
|
|
779
|
-
return !activeCatalog || catalog.sizeGb < activeCatalog.sizeGb;
|
|
780
|
-
}
|
|
781
|
-
).sort((a, b) => a.catalog.sizeGb - b.catalog.sizeGb)[0];
|
|
782
|
-
if (smallerInstalled) {
|
|
783
|
-
return activateInstalledModel(smallerInstalled.entry);
|
|
784
|
-
}
|
|
785
|
-
const smallest = chatModels().sort((a, b) => a.sizeGb - b.sizeGb)[0];
|
|
786
|
-
if (smallest) {
|
|
787
|
-
const job2 = await startDownload(smallest.id);
|
|
788
|
-
return buildLocalInferenceChatResult(
|
|
789
|
-
{
|
|
790
|
-
intent,
|
|
791
|
-
status: "downloading",
|
|
792
|
-
modelId: smallest.id,
|
|
793
|
-
activeModelId: active.modelId,
|
|
794
|
-
progress: progressForJob(job2)
|
|
795
|
-
},
|
|
796
|
-
"I could not switch to a smaller installed model, so I started the smallest local chat model download."
|
|
797
|
-
);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
const model = await resolveDefaultChatModel(prompt);
|
|
801
|
-
if (!model) {
|
|
802
|
-
return getLocalInferenceChatStatus(intent);
|
|
803
|
-
}
|
|
804
|
-
if (intent === "redownload") {
|
|
805
|
-
await removeInstalledModel(model.id).catch(() => false);
|
|
806
|
-
}
|
|
807
|
-
const job = await startDownload(model.id);
|
|
808
|
-
return buildLocalInferenceChatResult({
|
|
809
|
-
intent,
|
|
810
|
-
status: "downloading",
|
|
811
|
-
modelId: model.id,
|
|
812
|
-
activeModelId: activeModelState.modelId,
|
|
813
|
-
progress: progressForJob(job)
|
|
814
|
-
});
|
|
815
|
-
}
|
|
816
|
-
function writeSse(res, payload) {
|
|
817
|
-
res.write(`data: ${JSON.stringify(payload)}
|
|
818
|
-
|
|
819
|
-
`);
|
|
820
|
-
}
|
|
821
|
-
async function handleLocalInferenceRoutes(req, res) {
|
|
822
|
-
const method = (req.method ?? "GET").toUpperCase();
|
|
823
|
-
const url = new URL(req.url ?? "/", "http://localhost");
|
|
824
|
-
const pathname = url.pathname;
|
|
825
|
-
if (!pathname.startsWith("/api/local-inference/")) return false;
|
|
826
|
-
if (method === "GET" && pathname === "/api/local-inference/downloads/stream") {
|
|
827
|
-
res.writeHead(200, {
|
|
828
|
-
"Content-Type": "text/event-stream",
|
|
829
|
-
"Cache-Control": "no-cache, no-transform",
|
|
830
|
-
Connection: "keep-alive"
|
|
831
|
-
});
|
|
832
|
-
const interval = setInterval(() => {
|
|
833
|
-
writeSse(res, {
|
|
834
|
-
type: "snapshot",
|
|
835
|
-
downloads: [...activeDownloads.values()].map(({ job }) => ({ ...job }))
|
|
836
|
-
});
|
|
837
|
-
}, 1e3);
|
|
838
|
-
interval.unref?.();
|
|
839
|
-
writeSse(res, {
|
|
840
|
-
type: "snapshot",
|
|
841
|
-
downloads: [...activeDownloads.values()].map(({ job }) => ({ ...job }))
|
|
842
|
-
});
|
|
843
|
-
req.on("close", () => clearInterval(interval));
|
|
844
|
-
return true;
|
|
845
|
-
}
|
|
846
|
-
if (method === "GET" && pathname === "/api/local-inference/hub") {
|
|
847
|
-
sendJson(res, await hubSnapshot());
|
|
848
|
-
return true;
|
|
849
|
-
}
|
|
850
|
-
if (method === "GET" && pathname === "/api/local-inference/hardware") {
|
|
851
|
-
sendJson(res, (await hubSnapshot()).hardware);
|
|
852
|
-
return true;
|
|
853
|
-
}
|
|
854
|
-
if (method === "GET" && pathname === "/api/local-inference/catalog") {
|
|
855
|
-
sendJson(res, {
|
|
856
|
-
models: CATALOG.filter((model) => !model.hiddenFromCatalog)
|
|
857
|
-
});
|
|
858
|
-
return true;
|
|
859
|
-
}
|
|
860
|
-
if (method === "GET" && pathname === "/api/local-inference/installed") {
|
|
861
|
-
sendJson(res, { models: await installedSnapshot() });
|
|
862
|
-
return true;
|
|
863
|
-
}
|
|
864
|
-
if (method === "GET" && pathname === "/api/local-inference/device") {
|
|
865
|
-
sendJson(res, getMobileDeviceBridgeStatus());
|
|
866
|
-
return true;
|
|
867
|
-
}
|
|
868
|
-
if (method === "GET" && pathname === "/api/local-inference/providers") {
|
|
869
|
-
const bridge = getMobileDeviceBridgeStatus();
|
|
870
|
-
const installed = await installedSnapshot();
|
|
871
|
-
sendJson(res, {
|
|
872
|
-
providers: [
|
|
873
|
-
{
|
|
874
|
-
id: "capacitor-llama",
|
|
875
|
-
label: "On-device llama.cpp (mobile)",
|
|
876
|
-
kind: "local",
|
|
877
|
-
description: "Runs llama.cpp natively on iOS or Android via Capacitor.",
|
|
878
|
-
supportedSlots: ["TEXT_SMALL", "TEXT_LARGE", "TEXT_EMBEDDING"],
|
|
879
|
-
configureHref: null,
|
|
880
|
-
enableState: {
|
|
881
|
-
enabled: bridge.connected,
|
|
882
|
-
reason: bridge.connected ? "Device bridge connected" : "Waiting for device bridge"
|
|
883
|
-
},
|
|
884
|
-
registeredSlots: ["TEXT_SMALL", "TEXT_LARGE", "TEXT_EMBEDDING"]
|
|
885
|
-
},
|
|
886
|
-
{
|
|
887
|
-
id: "eliza-local-inference",
|
|
888
|
-
label: "Local models",
|
|
889
|
-
kind: "local",
|
|
890
|
-
description: "GGUF models installed in this mobile agent state directory.",
|
|
891
|
-
supportedSlots: ["TEXT_SMALL", "TEXT_LARGE", "TEXT_EMBEDDING"],
|
|
892
|
-
configureHref: "#local-inference-panel",
|
|
893
|
-
enableState: {
|
|
894
|
-
enabled: installed.length > 0,
|
|
895
|
-
reason: installed.length > 0 ? "GGUF model installed" : "No local model installed"
|
|
896
|
-
},
|
|
897
|
-
registeredSlots: []
|
|
898
|
-
}
|
|
899
|
-
]
|
|
900
|
-
});
|
|
901
|
-
return true;
|
|
902
|
-
}
|
|
903
|
-
if (method === "GET" && pathname === "/api/local-inference/assignments") {
|
|
904
|
-
sendJson(res, { assignments: await readAssignments() });
|
|
905
|
-
return true;
|
|
906
|
-
}
|
|
907
|
-
if (method === "POST" && pathname === "/api/local-inference/assignments") {
|
|
908
|
-
const body = await readJsonBody(req, res);
|
|
909
|
-
if (!body) return true;
|
|
910
|
-
const slot = typeof body.slot === "string" ? body.slot : null;
|
|
911
|
-
if (!slot) {
|
|
912
|
-
sendJsonError(res, "slot is required");
|
|
913
|
-
return true;
|
|
914
|
-
}
|
|
915
|
-
const assignments = await readAssignments();
|
|
916
|
-
if (typeof body.modelId === "string" && body.modelId.trim()) {
|
|
917
|
-
assignments[slot] = body.modelId.trim();
|
|
918
|
-
} else {
|
|
919
|
-
delete assignments[slot];
|
|
920
|
-
}
|
|
921
|
-
sendJson(res, { assignments: await writeAssignments(assignments) });
|
|
922
|
-
return true;
|
|
923
|
-
}
|
|
924
|
-
if (method === "GET" && pathname === "/api/local-inference/routing") {
|
|
925
|
-
const preferences = await readJsonFile(
|
|
926
|
-
routingPath(),
|
|
927
|
-
defaultRoutingPreferences()
|
|
928
|
-
);
|
|
929
|
-
sendJson(res, {
|
|
930
|
-
registrations: ["TEXT_SMALL", "TEXT_LARGE", "TEXT_EMBEDDING"].map(
|
|
931
|
-
(modelType) => ({
|
|
932
|
-
modelType,
|
|
933
|
-
provider: "capacitor-llama",
|
|
934
|
-
priority: 0,
|
|
935
|
-
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
936
|
-
})
|
|
937
|
-
),
|
|
938
|
-
preferences: preferences.preferences ?? defaultRoutingPreferences().preferences
|
|
939
|
-
});
|
|
940
|
-
return true;
|
|
941
|
-
}
|
|
942
|
-
if (method === "POST" && (pathname === "/api/local-inference/routing/preferred" || pathname === "/api/local-inference/routing/policy")) {
|
|
943
|
-
const body = await readJsonBody(req, res);
|
|
944
|
-
if (!body || typeof body.slot !== "string") {
|
|
945
|
-
sendJsonError(res, "slot is required");
|
|
946
|
-
return true;
|
|
947
|
-
}
|
|
948
|
-
const current = await readJsonFile(
|
|
949
|
-
routingPath(),
|
|
950
|
-
defaultRoutingPreferences()
|
|
951
|
-
);
|
|
952
|
-
const preferences = current.preferences ?? defaultRoutingPreferences().preferences;
|
|
953
|
-
const slot = body.slot;
|
|
954
|
-
if (pathname.endsWith("/preferred")) {
|
|
955
|
-
if (typeof body.provider === "string" && body.provider.trim()) {
|
|
956
|
-
preferences.preferredProvider[slot] = body.provider.trim();
|
|
957
|
-
} else {
|
|
958
|
-
delete preferences.preferredProvider[slot];
|
|
959
|
-
}
|
|
960
|
-
} else if (typeof body.policy === "string" && body.policy.trim()) {
|
|
961
|
-
preferences.policy[slot] = body.policy.trim();
|
|
962
|
-
} else {
|
|
963
|
-
delete preferences.policy[slot];
|
|
964
|
-
}
|
|
965
|
-
await writeJsonFile(routingPath(), { version: 1, preferences });
|
|
966
|
-
sendJson(res, { preferences });
|
|
967
|
-
return true;
|
|
968
|
-
}
|
|
969
|
-
if (method === "POST" && pathname === "/api/local-inference/downloads") {
|
|
970
|
-
const body = await readJsonBody(req, res);
|
|
971
|
-
if (!body) return true;
|
|
972
|
-
const modelId = typeof body.modelId === "string" ? body.modelId : null;
|
|
973
|
-
if (!modelId) {
|
|
974
|
-
sendJsonError(res, "modelId is required");
|
|
975
|
-
return true;
|
|
976
|
-
}
|
|
977
|
-
try {
|
|
978
|
-
sendJson(res, { job: await startDownload(modelId) }, 202);
|
|
979
|
-
} catch (error) {
|
|
980
|
-
sendJsonError(
|
|
981
|
-
res,
|
|
982
|
-
error instanceof Error ? error.message : "Failed to start download",
|
|
983
|
-
400
|
|
984
|
-
);
|
|
985
|
-
}
|
|
986
|
-
return true;
|
|
987
|
-
}
|
|
988
|
-
const downloadMatch = /^\/api\/local-inference\/downloads\/([^/]+)$/.exec(
|
|
989
|
-
pathname
|
|
990
|
-
);
|
|
991
|
-
if (method === "DELETE" && downloadMatch) {
|
|
992
|
-
const modelId = decodeURIComponent(downloadMatch[1] ?? "");
|
|
993
|
-
activeDownloads.get(modelId)?.abortController.abort();
|
|
994
|
-
activeDownloads.delete(modelId);
|
|
995
|
-
sendJson(res, { cancelled: true });
|
|
996
|
-
return true;
|
|
997
|
-
}
|
|
998
|
-
if (method === "GET" && pathname === "/api/local-inference/active") {
|
|
999
|
-
sendJson(res, await getLocalInferenceActiveSnapshot());
|
|
1000
|
-
return true;
|
|
1001
|
-
}
|
|
1002
|
-
if (method === "POST" && pathname === "/api/local-inference/active") {
|
|
1003
|
-
const body = await readJsonBody(req, res);
|
|
1004
|
-
if (!body || typeof body.modelId !== "string") {
|
|
1005
|
-
sendJsonError(res, "modelId is required");
|
|
1006
|
-
return true;
|
|
1007
|
-
}
|
|
1008
|
-
const installed = (await installedSnapshot()).find(
|
|
1009
|
-
(model) => model.id === body.modelId
|
|
1010
|
-
);
|
|
1011
|
-
if (!installed) {
|
|
1012
|
-
sendJsonError(res, `Model not installed: ${body.modelId}`, 404);
|
|
1013
|
-
return true;
|
|
1014
|
-
}
|
|
1015
|
-
const catalog = CATALOG.find((model) => model.id === installed.id);
|
|
1016
|
-
if (catalog) await assignModel(catalog, true);
|
|
1017
|
-
try {
|
|
1018
|
-
activeModelState = {
|
|
1019
|
-
modelId: installed.id,
|
|
1020
|
-
loadedAt: null,
|
|
1021
|
-
status: "loading"
|
|
1022
|
-
};
|
|
1023
|
-
await loadMobileDeviceBridgeModel(installed.path, installed.id);
|
|
1024
|
-
activeModelState = {
|
|
1025
|
-
modelId: installed.id,
|
|
1026
|
-
loadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1027
|
-
status: "ready"
|
|
1028
|
-
};
|
|
1029
|
-
sendJson(res, activeModelState);
|
|
1030
|
-
} catch (error) {
|
|
1031
|
-
activeModelState = {
|
|
1032
|
-
modelId: installed.id,
|
|
1033
|
-
loadedAt: null,
|
|
1034
|
-
status: "error",
|
|
1035
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1036
|
-
};
|
|
1037
|
-
sendJsonError(
|
|
1038
|
-
res,
|
|
1039
|
-
error instanceof Error ? error.message : "Failed to load model",
|
|
1040
|
-
503
|
|
1041
|
-
);
|
|
1042
|
-
}
|
|
1043
|
-
return true;
|
|
1044
|
-
}
|
|
1045
|
-
if (method === "DELETE" && pathname === "/api/local-inference/active") {
|
|
1046
|
-
try {
|
|
1047
|
-
await unloadMobileDeviceBridgeModel();
|
|
1048
|
-
activeModelState = { modelId: null, loadedAt: null, status: "idle" };
|
|
1049
|
-
sendJson(res, activeModelState);
|
|
1050
|
-
} catch (error) {
|
|
1051
|
-
sendJsonError(
|
|
1052
|
-
res,
|
|
1053
|
-
error instanceof Error ? error.message : "Failed to unload model",
|
|
1054
|
-
503
|
|
1055
|
-
);
|
|
1056
|
-
}
|
|
1057
|
-
return true;
|
|
1058
|
-
}
|
|
1059
|
-
const verifyMatch = /^\/api\/local-inference\/installed\/([^/]+)\/verify$/.exec(pathname);
|
|
1060
|
-
if (method === "POST" && verifyMatch) {
|
|
1061
|
-
const id = decodeURIComponent(verifyMatch[1] ?? "");
|
|
1062
|
-
const installed = (await installedSnapshot()).find(
|
|
1063
|
-
(model) => model.id === id
|
|
1064
|
-
);
|
|
1065
|
-
if (!installed) {
|
|
1066
|
-
sendJsonError(res, "Model not installed", 404);
|
|
1067
|
-
return true;
|
|
1068
|
-
}
|
|
1069
|
-
const currentSha256 = await hashFile(installed.path);
|
|
1070
|
-
sendJson(res, {
|
|
1071
|
-
state: currentSha256 === installed.sha256 ? "ok" : "unknown",
|
|
1072
|
-
currentSha256,
|
|
1073
|
-
expectedSha256: installed.sha256 ?? null,
|
|
1074
|
-
currentBytes: installed.sizeBytes
|
|
1075
|
-
});
|
|
1076
|
-
return true;
|
|
1077
|
-
}
|
|
1078
|
-
const installedMatch = /^\/api\/local-inference\/installed\/([^/]+)$/.exec(
|
|
1079
|
-
pathname
|
|
1080
|
-
);
|
|
1081
|
-
if (method === "DELETE" && installedMatch) {
|
|
1082
|
-
const id = decodeURIComponent(installedMatch[1] ?? "");
|
|
1083
|
-
sendJson(res, { removed: await removeInstalledModel(id) });
|
|
1084
|
-
return true;
|
|
1085
|
-
}
|
|
1086
|
-
if (method === "GET" && pathname === "/api/local-inference/hf-search") {
|
|
1087
|
-
sendJson(res, { models: [] });
|
|
1088
|
-
return true;
|
|
1089
|
-
}
|
|
1090
|
-
return false;
|
|
1091
|
-
}
|
|
1092
|
-
export {
|
|
1093
|
-
getLocalInferenceActiveModelId,
|
|
1094
|
-
getLocalInferenceActiveSnapshot,
|
|
1095
|
-
getLocalInferenceChatStatus,
|
|
1096
|
-
handleLocalInferenceChatCommand,
|
|
1097
|
-
handleLocalInferenceRoutes
|
|
1098
|
-
};
|