@reftrixmcp/ml 0.3.0 → 0.5.1

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.
Files changed (36) hide show
  1. package/dist/config/worker-resource-limits.d.ts +89 -0
  2. package/dist/config/worker-resource-limits.d.ts.map +1 -0
  3. package/dist/config/worker-resource-limits.js +156 -0
  4. package/dist/config/worker-resource-limits.js.map +1 -0
  5. package/dist/dinov2/service.d.ts.map +1 -1
  6. package/dist/dinov2/service.js +70 -10
  7. package/dist/dinov2/service.js.map +1 -1
  8. package/dist/dinov2/worker-thread.js +72 -9
  9. package/dist/dinov2/worker-thread.js.map +1 -1
  10. package/dist/embeddings/service.d.ts.map +1 -1
  11. package/dist/embeddings/service.js +13 -1
  12. package/dist/embeddings/service.js.map +1 -1
  13. package/dist/embeddings/worker-thread.d.ts.map +1 -1
  14. package/dist/embeddings/worker-thread.js +8 -83
  15. package/dist/embeddings/worker-thread.js.map +1 -1
  16. package/dist/index.d.ts +3 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +4 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/onnx-availability.d.ts +29 -0
  21. package/dist/onnx-availability.d.ts.map +1 -0
  22. package/dist/onnx-availability.js +69 -0
  23. package/dist/onnx-availability.js.map +1 -0
  24. package/dist/onnx-provider-detect.d.ts +47 -0
  25. package/dist/onnx-provider-detect.d.ts.map +1 -0
  26. package/dist/onnx-provider-detect.js +111 -0
  27. package/dist/onnx-provider-detect.js.map +1 -0
  28. package/package.json +5 -3
  29. package/src/config/worker-resource-limits.ts +176 -0
  30. package/src/dinov2/service.ts +88 -10
  31. package/src/dinov2/worker-thread.ts +85 -10
  32. package/src/embeddings/service.ts +13 -1
  33. package/src/embeddings/worker-thread.ts +13 -102
  34. package/src/index.ts +15 -0
  35. package/src/onnx-availability.ts +78 -0
  36. package/src/onnx-provider-detect.ts +134 -0
package/src/index.ts CHANGED
@@ -49,6 +49,21 @@ export { DINOv2Service, DINOV2_EMBEDDING_DIMENSION, DINOV2_INPUT_SIZE } from "./
49
49
  export type { DINOv2ServiceConfig } from "./dinov2/index.js";
50
50
  export type { DINOv2WorkerMessage, DINOv2WorkerResponse } from "./dinov2/index.js";
51
51
 
52
+ // ONNX Runtime availability checker
53
+ export {
54
+ isOnnxRuntimeAvailable,
55
+ OnnxRuntimeUnavailableError,
56
+ safeImportOnnx,
57
+ } from "./onnx-availability.js";
58
+
59
+ // ML Worker Thread resource limits (PR7e-β1)
60
+ export {
61
+ loadMLWorkerResourceLimits,
62
+ getMLWorkerThreadOptions,
63
+ MLWorkerResourceLimitsSchema,
64
+ } from "./config/worker-resource-limits.js";
65
+ export type { MLWorkerResourceLimits } from "./config/worker-resource-limits.js";
66
+
52
67
  // Search utilities exports (SearchService removed in v0.1.0)
53
68
  export { calculateRRF, mergeWithRRF, normalizeRRFScore, toRankedItems } from "./search/index.js";
54
69
  export { executeHybridSearch } from "./search/index.js";
@@ -0,0 +1,78 @@
1
+ // SPDX-FileCopyrightText: 2026 TKMD and Reftrix Contributors
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+
4
+ /**
5
+ * Cached availability checker for onnxruntime-node (optionalDependency).
6
+ * When unavailable, ML features degrade gracefully.
7
+ *
8
+ * @module onnx-availability
9
+ */
10
+
11
+ let _available: boolean | null = null;
12
+ let _unavailableReason: string | null = null;
13
+
14
+ /**
15
+ * Check if onnxruntime-node is available (async, caches result).
16
+ */
17
+ export async function isOnnxRuntimeAvailable(): Promise<boolean> {
18
+ if (_available !== null) return _available;
19
+ try {
20
+ await import("onnxruntime-node");
21
+ _available = true;
22
+ _unavailableReason = null;
23
+ } catch {
24
+ _available = false;
25
+ _unavailableReason = "onnxruntime-node is not installed";
26
+ }
27
+ return _available;
28
+ }
29
+
30
+ /**
31
+ * Synchronous check — returns null if not yet probed.
32
+ */
33
+ export function isOnnxRuntimeAvailableSync(): boolean | null {
34
+ return _available;
35
+ }
36
+
37
+ /**
38
+ * Returns the reason onnxruntime-node is unavailable, or null if available.
39
+ */
40
+ export function getOnnxUnavailableReason(): string | null {
41
+ return _unavailableReason;
42
+ }
43
+
44
+ /**
45
+ * Error thrown when ML features require onnxruntime-node but it is not installed.
46
+ */
47
+ export class OnnxRuntimeUnavailableError extends Error {
48
+ constructor(context?: string) {
49
+ super(
50
+ `ML features require onnxruntime-node which is not available. ` +
51
+ `Install with: pnpm add onnxruntime-node` +
52
+ (context ? ` (${context})` : "")
53
+ );
54
+ this.name = "OnnxRuntimeUnavailableError";
55
+ }
56
+ }
57
+
58
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
59
+ type OnnxRuntimeModule = typeof import("onnxruntime-node");
60
+
61
+ /**
62
+ * Safely import onnxruntime-node with a sanitized error on failure.
63
+ */
64
+ export async function safeImportOnnx(): Promise<OnnxRuntimeModule> {
65
+ try {
66
+ return await import("onnxruntime-node");
67
+ } catch {
68
+ throw new OnnxRuntimeUnavailableError();
69
+ }
70
+ }
71
+
72
+ /**
73
+ * For testing: reset cached state.
74
+ */
75
+ export function _resetForTesting(): void {
76
+ _available = null;
77
+ _unavailableReason = null;
78
+ }
@@ -0,0 +1,134 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ /**
3
+ * ONNX Execution Provider Detection Utilities
4
+ *
5
+ * Shared logic for detecting the ONNX execution provider (CPU vs CUDA)
6
+ * based on environment configuration and CUDA shared library availability.
7
+ *
8
+ * Used by both the e5-base embedding worker thread and the DINOv2 worker thread
9
+ * to avoid code duplication. Extracted from embeddings/worker-thread.ts in v0.4.0.
10
+ *
11
+ * @module onnx-provider-detect
12
+ */
13
+
14
+ import { createRequire } from "node:module";
15
+ import fs from "node:fs";
16
+ import nodePath from "node:path";
17
+
18
+ // =====================================================
19
+ // Types
20
+ // =====================================================
21
+
22
+ export type ExecutionProvider = "cpu" | "cuda";
23
+
24
+ // =====================================================
25
+ // Provider Detection
26
+ // =====================================================
27
+
28
+ /**
29
+ * Detect the ONNX execution provider based on environment configuration.
30
+ *
31
+ * Checks ONNX_EXECUTION_PROVIDER env var and verifies that the CUDA
32
+ * provider shared library is available on disk. Falls back to CPU
33
+ * gracefully if the provider is not installed.
34
+ *
35
+ * @param logPrefix - Log prefix for warning messages (e.g. "EmbeddingWorker", "DINOv2Worker")
36
+ */
37
+ export function detectExecutionProvider(logPrefix?: string): ExecutionProvider {
38
+ const prefix = logPrefix ?? "OnnxProvider";
39
+ const envProvider = process.env.ONNX_EXECUTION_PROVIDER;
40
+
41
+ if (envProvider === "cuda" || envProvider === "rocm") {
42
+ const cudaAvailable = verifyCudaAvailability(logPrefix);
43
+ if (cudaAvailable) {
44
+ return "cuda";
45
+ }
46
+ console.warn(
47
+ "[%s] ONNX_EXECUTION_PROVIDER=%s but CUDA provider not available, falling back to CPU",
48
+ prefix,
49
+ envProvider
50
+ );
51
+ return "cpu";
52
+ }
53
+
54
+ return "cpu";
55
+ }
56
+
57
+ // =====================================================
58
+ // CUDA Availability Verification
59
+ // =====================================================
60
+
61
+ /**
62
+ * Verify that CUDA provider (libonnxruntime_providers_cuda.so) is available.
63
+ *
64
+ * onnxruntime-node can download the CUDA provider shared library via
65
+ * `ONNXRUNTIME_NODE_INSTALL_CUDA=v12 node .../install.js`. This function
66
+ * checks for its presence on disk rather than trying to resolve a
67
+ * non-existent npm package (onnxruntime-gpu is Python-only).
68
+ *
69
+ * @param logPrefix - Log prefix for warning messages
70
+ */
71
+ export function verifyCudaAvailability(logPrefix?: string): boolean {
72
+ const prefix = logPrefix ?? "OnnxProvider";
73
+ try {
74
+ const esmRequire = createRequire(import.meta.url);
75
+ const ortNodePath = esmRequire.resolve("onnxruntime-node");
76
+ // require.resolve returns e.g. .../onnxruntime-node/dist/index.js
77
+ // Walk up to package root by finding the directory containing package.json
78
+ let packageDir = nodePath.dirname(ortNodePath);
79
+ for (let i = 0; i < 5; i++) {
80
+ if (fs.existsSync(nodePath.join(packageDir, "package.json"))) break;
81
+ packageDir = nodePath.dirname(packageDir);
82
+ }
83
+
84
+ // Search across napi versions (v3, v6, etc.) for CUDA provider
85
+ const binDir = nodePath.join(packageDir, "bin");
86
+ if (fs.existsSync(binDir)) {
87
+ const napiDirs = fs.readdirSync(binDir).filter((d) => d.startsWith("napi-v"));
88
+ for (const napiDir of napiDirs) {
89
+ const cudaProviderPath = nodePath.join(
90
+ binDir,
91
+ napiDir,
92
+ "linux",
93
+ "x64",
94
+ "libonnxruntime_providers_cuda.so"
95
+ );
96
+ if (fs.existsSync(cudaProviderPath)) {
97
+ return true;
98
+ }
99
+ }
100
+ }
101
+
102
+ console.warn("[%s] CUDA provider not found in: %s", prefix, binDir);
103
+ return false;
104
+ } catch {
105
+ console.warn("[%s] Cannot verify CUDA provider: onnxruntime-node not found", prefix);
106
+ return false;
107
+ }
108
+ }
109
+
110
+ // =====================================================
111
+ // LD_LIBRARY_PATH Check
112
+ // =====================================================
113
+
114
+ /**
115
+ * Verify that LD_LIBRARY_PATH is set at the OS level (not just process.env).
116
+ *
117
+ * dlopen() reads LD_LIBRARY_PATH from the kernel environment (/proc/self/environ),
118
+ * NOT from process.env modifications made at runtime. If LD_LIBRARY_PATH was set
119
+ * after process startup (e.g. by loadEnvLocal()), dlopen() cannot find CUDA
120
+ * libraries and ONNX Runtime CUDA provider initialization will segfault or throw.
121
+ *
122
+ * Returns true only if LD_LIBRARY_PATH was present in the original process environment.
123
+ *
124
+ * @returns true if LD_LIBRARY_PATH is set at OS level, or if /proc/self/environ is unavailable
125
+ */
126
+ export function isLdLibraryPathSetAtOsLevel(): boolean {
127
+ try {
128
+ const procEnv = fs.readFileSync("/proc/self/environ", "utf-8");
129
+ return procEnv.includes("LD_LIBRARY_PATH");
130
+ } catch {
131
+ // /proc/self/environ not available (non-Linux) — assume set
132
+ return true;
133
+ }
134
+ }