diff --git a/agentic-flow/src/router/providers/onnx-local-optimized.ts b/agentic-flow/src/router/providers/onnx-local-optimized.ts index 6f3ea8e14..dd9cfc861 100644 --- a/agentic-flow/src/router/providers/onnx-local-optimized.ts +++ b/agentic-flow/src/router/providers/onnx-local-optimized.ts @@ -8,18 +8,18 @@ * - Better generation parameters for code tasks * - System prompt caching * - * Note: onnxruntime-node is optional - will error if not installed + * Note: onnxruntime-node is optional - will error if not installed. + * + * NOTE (ruvnet/ruflo#2048): the previous top-level `await import('onnxruntime-node')` + * fired the native-binding load (`onnxruntime_binding.node`) at module + * import time. On Windows this crashes with "OS cannot run %1" — and the + * crash propagated to any consumer that transitively imports this file + * (e.g. `agentic-flow/reasoningbank` via `core/distill -> router/router`). + * This file does not use `ort` directly — the base `ONNXLocalProvider` + * it extends does, and that file now lazy-loads ort on first session + * init. So we just drop the eager top-level load here. */ -let ort: any = null; - -// Dynamic import for optional onnxruntime-node -try { - ort = await import('onnxruntime-node'); -} catch { - // Will be handled at runtime -} - import { get_encoding } from 'tiktoken'; import { ensurePhi4Model, ModelDownloader, PHI4_MODEL_PATH } from '../../utils/model-downloader.js'; import type { diff --git a/agentic-flow/src/router/providers/onnx-local.ts b/agentic-flow/src/router/providers/onnx-local.ts index 0bcec4b02..63774f3f6 100644 --- a/agentic-flow/src/router/providers/onnx-local.ts +++ b/agentic-flow/src/router/providers/onnx-local.ts @@ -3,17 +3,30 @@ * * Uses onnxruntime-node for true local CPU/GPU inference * Falls back gracefully when native module isn't available (Windows) + * + * NOTE (ruvnet/ruflo#2048): `onnxruntime-node` is loaded LAZILY on first + * `initializeSession()` call, not at module import. The previous top-level + * `await import('onnxruntime-node')` fired the native-binding load + * (`onnxruntime_binding.node`) at module load time, which crashed Windows + * environments where the NAPI binary cannot be loaded — even when the + * consumer (e.g. `agentic-flow/reasoningbank`) never actually invokes + * the router. Moving the import inside `loadOrt()` keeps importing + * `reasoningbank` side-effect-free with respect to native bindings. */ let ort: any = null; let ortAvailable = false; - -// Dynamic import for optional onnxruntime-node -try { - ort = await import('onnxruntime-node'); - ortAvailable = true; -} catch { - console.warn('[ONNX] onnxruntime-node not available - local inference disabled'); +let ortLoaded = false; + +async function loadOrt(): Promise { + if (ortLoaded) return; + ortLoaded = true; + try { + ort = await import('onnxruntime-node'); + ortAvailable = true; + } catch { + console.warn('[ONNX] onnxruntime-node not available - local inference disabled'); + } } import * as fs from 'fs'; @@ -107,6 +120,7 @@ export class ONNXLocalProvider implements LLMProvider { private async initializeSession(): Promise { if (this.session) return; + await loadOrt(); if (!ortAvailable || !ort) { throw new Error('onnxruntime-node not available - install with: npm install onnxruntime-node'); }