@ruvector/ruvllm 4.0.1 → 4.2.0

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 (171) hide show
  1. package/README.md +446 -160
  2. package/bin/cli.js +1066 -0
  3. package/bin/gpu-delegate.js +67 -0
  4. package/bin/ruvllm-adapters.js +5 -0
  5. package/bin/ruvllm-gpu-loop.js +5 -0
  6. package/bin/serve.js +265 -0
  7. package/dist/cjs/benchmarks/embedding-benchmark.d.ts +102 -0
  8. package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +1 -0
  9. package/dist/cjs/benchmarks/embedding-benchmark.js +436 -0
  10. package/dist/cjs/benchmarks/index.d.ts +34 -0
  11. package/dist/cjs/benchmarks/index.d.ts.map +1 -0
  12. package/dist/cjs/benchmarks/index.js +132 -0
  13. package/dist/cjs/benchmarks/model-comparison.d.ts +71 -0
  14. package/dist/cjs/benchmarks/model-comparison.d.ts.map +1 -0
  15. package/dist/cjs/benchmarks/model-comparison.js +476 -0
  16. package/dist/cjs/benchmarks/routing-benchmark.d.ts +70 -0
  17. package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +1 -0
  18. package/dist/cjs/benchmarks/routing-benchmark.js +289 -0
  19. package/dist/cjs/contrastive.d.ts +229 -0
  20. package/dist/cjs/contrastive.d.ts.map +1 -0
  21. package/dist/cjs/contrastive.js +589 -0
  22. package/dist/cjs/engine.d.ts +160 -0
  23. package/dist/cjs/engine.d.ts.map +1 -0
  24. package/dist/cjs/engine.js +552 -0
  25. package/dist/cjs/export.d.ts +182 -0
  26. package/dist/cjs/export.d.ts.map +1 -0
  27. package/dist/cjs/export.js +422 -0
  28. package/dist/cjs/federated.d.ts +233 -0
  29. package/dist/cjs/federated.d.ts.map +1 -0
  30. package/dist/cjs/federated.js +525 -0
  31. package/dist/cjs/index.d.ts +68 -0
  32. package/dist/cjs/index.d.ts.map +1 -0
  33. package/dist/cjs/index.js +104 -0
  34. package/dist/cjs/intelligence.d.ts +136 -0
  35. package/dist/cjs/intelligence.d.ts.map +1 -0
  36. package/dist/cjs/intelligence.js +226 -0
  37. package/dist/cjs/lora.d.ts +251 -0
  38. package/dist/cjs/lora.d.ts.map +1 -0
  39. package/dist/cjs/lora.js +509 -0
  40. package/dist/cjs/models.d.ts +129 -0
  41. package/dist/cjs/models.d.ts.map +1 -0
  42. package/dist/cjs/models.js +323 -0
  43. package/dist/cjs/native.d.ts +140 -0
  44. package/dist/cjs/native.d.ts.map +1 -0
  45. package/dist/cjs/native.js +98 -0
  46. package/dist/cjs/session.d.ts +80 -0
  47. package/dist/cjs/session.d.ts.map +1 -0
  48. package/dist/cjs/session.js +203 -0
  49. package/dist/cjs/simd.d.ts +90 -0
  50. package/dist/cjs/simd.d.ts.map +1 -0
  51. package/dist/cjs/simd.js +209 -0
  52. package/dist/cjs/sona.d.ts +223 -0
  53. package/dist/cjs/sona.d.ts.map +1 -0
  54. package/dist/cjs/sona.js +562 -0
  55. package/dist/cjs/streaming.d.ts +55 -0
  56. package/dist/cjs/streaming.d.ts.map +1 -0
  57. package/dist/cjs/streaming.js +131 -0
  58. package/dist/cjs/training.d.ts +312 -0
  59. package/dist/cjs/training.d.ts.map +1 -0
  60. package/dist/cjs/training.js +610 -0
  61. package/dist/cjs/types.d.ts +696 -0
  62. package/dist/cjs/types.d.ts.map +1 -0
  63. package/dist/cjs/types.js +6 -0
  64. package/dist/esm/benchmarks/embedding-benchmark.d.ts +102 -0
  65. package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +1 -0
  66. package/dist/esm/benchmarks/embedding-benchmark.js +427 -0
  67. package/dist/esm/benchmarks/index.d.ts +34 -0
  68. package/dist/esm/benchmarks/index.d.ts.map +1 -0
  69. package/dist/esm/benchmarks/index.js +110 -0
  70. package/dist/esm/benchmarks/model-comparison.d.ts +71 -0
  71. package/dist/esm/benchmarks/model-comparison.d.ts.map +1 -0
  72. package/dist/esm/benchmarks/model-comparison.js +434 -0
  73. package/dist/esm/benchmarks/routing-benchmark.d.ts +70 -0
  74. package/dist/esm/benchmarks/routing-benchmark.d.ts.map +1 -0
  75. package/dist/esm/benchmarks/routing-benchmark.js +283 -0
  76. package/dist/esm/contrastive.d.ts +229 -0
  77. package/dist/esm/contrastive.d.ts.map +1 -0
  78. package/dist/esm/contrastive.js +578 -0
  79. package/dist/esm/engine.d.ts +160 -0
  80. package/dist/esm/engine.d.ts.map +1 -0
  81. package/dist/esm/engine.js +548 -0
  82. package/dist/esm/export.d.ts +182 -0
  83. package/dist/esm/export.d.ts.map +1 -0
  84. package/dist/esm/export.js +414 -0
  85. package/dist/esm/federated.d.ts +233 -0
  86. package/dist/esm/federated.d.ts.map +1 -0
  87. package/dist/esm/federated.js +520 -0
  88. package/dist/esm/index.d.ts +68 -0
  89. package/dist/esm/index.d.ts.map +1 -0
  90. package/dist/esm/index.js +84 -0
  91. package/dist/esm/intelligence.d.ts +136 -0
  92. package/dist/esm/intelligence.d.ts.map +1 -0
  93. package/dist/esm/intelligence.js +188 -0
  94. package/dist/esm/lora.d.ts +251 -0
  95. package/dist/esm/lora.d.ts.map +1 -0
  96. package/dist/esm/lora.js +504 -0
  97. package/dist/esm/models.d.ts +129 -0
  98. package/dist/esm/models.d.ts.map +1 -0
  99. package/dist/esm/models.js +282 -0
  100. package/dist/esm/native.d.ts +140 -0
  101. package/dist/esm/native.d.ts.map +1 -0
  102. package/dist/esm/native.js +100 -0
  103. package/dist/esm/session.d.ts +80 -0
  104. package/dist/esm/session.d.ts.map +1 -0
  105. package/dist/esm/session.js +199 -0
  106. package/dist/esm/simd.d.ts +90 -0
  107. package/dist/esm/simd.d.ts.map +1 -0
  108. package/dist/esm/simd.js +205 -0
  109. package/dist/esm/sona.d.ts +223 -0
  110. package/dist/esm/sona.d.ts.map +1 -0
  111. package/dist/esm/sona.js +556 -0
  112. package/dist/esm/streaming.d.ts +55 -0
  113. package/dist/esm/streaming.d.ts.map +1 -0
  114. package/dist/esm/streaming.js +126 -0
  115. package/dist/esm/training.d.ts +312 -0
  116. package/dist/esm/training.d.ts.map +1 -0
  117. package/dist/esm/training.js +603 -0
  118. package/dist/esm/types.d.ts +696 -0
  119. package/dist/esm/types.d.ts.map +1 -0
  120. package/dist/esm/types.js +5 -0
  121. package/gpu/_load.cjs +38 -0
  122. package/gpu/_load.mjs +33 -0
  123. package/gpu/adapters.cjs +3 -0
  124. package/gpu/adapters.mjs +5 -0
  125. package/gpu/engine.cjs +3 -0
  126. package/gpu/engine.mjs +5 -0
  127. package/gpu/fixture.cjs +3 -0
  128. package/gpu/fixture.mjs +5 -0
  129. package/gpu/gpu-host.cjs +3 -0
  130. package/gpu/gpu-host.mjs +5 -0
  131. package/gpu/gpu-loop.cjs +3 -0
  132. package/gpu/gpu-loop.mjs +5 -0
  133. package/gpu/gpu-spool-adapter.cjs +3 -0
  134. package/gpu/gpu-spool-adapter.mjs +5 -0
  135. package/gpu/vast-host-adapter.cjs +3 -0
  136. package/gpu/vast-host-adapter.mjs +5 -0
  137. package/package.json +159 -49
  138. package/scripts/ensemble-model-compare.js +287 -0
  139. package/scripts/fix-esm-extensions.mjs +220 -0
  140. package/scripts/huggingface/README.md +537 -0
  141. package/scripts/huggingface/publish.sh +112 -0
  142. package/scripts/hybrid-model-compare.js +373 -0
  143. package/scripts/improved-model-compare.js +288 -0
  144. package/scripts/optimized-model-compare.js +364 -0
  145. package/scripts/real-model-compare.js +280 -0
  146. package/scripts/smoke-esm.mjs +82 -0
  147. package/scripts/training/agentic-flow-capabilities.json +329 -0
  148. package/scripts/training/claude-code-synth.js +505 -0
  149. package/scripts/training/claude-flow-capabilities.json +1322 -0
  150. package/scripts/training/claude-hard-negatives.js +222 -0
  151. package/scripts/training/contrastive-finetune.js +517 -0
  152. package/scripts/training/ecosystem-triplets.jsonl +1467 -0
  153. package/scripts/training/generate-ecosystem-triplets.js +1324 -0
  154. package/scripts/training/routing-dataset.js +634 -0
  155. package/scripts/training/ruvector-capabilities.json +798 -0
  156. package/scripts/training/validate-ecosystem.js +381 -0
  157. package/scripts/training/validation-results.json +23 -0
  158. package/GPU-LOOP.md +0 -229
  159. package/LICENSE +0 -201
  160. package/NOTICE +0 -9
  161. package/examples/gpu-loop.example.json +0 -26
  162. package/src/adapters-cli.mjs +0 -23
  163. package/src/adapters.mjs +0 -91
  164. package/src/cli.mjs +0 -30
  165. package/src/engine.mjs +0 -238
  166. package/src/fixture.mjs +0 -38
  167. package/src/gpu-host.mjs +0 -47
  168. package/src/gpu-loop-cli.mjs +0 -67
  169. package/src/gpu-loop.mjs +0 -184
  170. package/src/gpu-spool-adapter.mjs +0 -80
  171. package/src/vast-host-adapter.mjs +0 -274
package/README.md CHANGED
@@ -1,187 +1,473 @@
1
- # MetaHarness weight experiments
1
+ # @ruvector/ruvllm
2
+
3
+ <p align="center"><img src="https://raw.githubusercontent.com/ruvnet/RuVector/main/assets/ruvector/packages/ruvllm.svg" alt="@ruvector/ruvllm: self-learning LLM runtime for Node.js with GGUF inference, SONA, TurboQuant KV cache and an optional GPU job loop." width="100%"></p>
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@ruvector/ruvllm.svg)](https://www.npmjs.com/package/@ruvector/ruvllm)
6
+ [![Downloads](https://img.shields.io/npm/dm/@ruvector/ruvllm)](https://www.npmjs.com/package/@ruvector/ruvllm)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
8
+ [![GitHub Stars](https://img.shields.io/github/stars/ruvnet/ruvector?style=social)](https://github.com/ruvnet/ruvector)
9
+
10
+ **Self-learning LLM runtime for Node.js** — GGUF inference, TurboQuant KV-cache compression (6-8x memory savings), SONA adaptive learning, FlashAttention, speculative decoding, and SIMD-optimized kernels. Built in Rust, runs everywhere.
11
+
12
+ > Inference at **88-135 tok/s** on M4 Pro | **<1ms** SONA adaptation | **6-8x** KV-cache compression via TurboQuant
13
+
14
+ ## One package: the LLM runtime and the GPU job loop (4.1.0)
15
+
16
+ `@ruvector/ruvllm` is the RuVLLM **self-learning LLM runtime for Node.js**:
17
+ GGUF inference, SONA adaptive learning, MicroLoRA, TurboQuant KV-cache
18
+ compression, FlashAttention, speculative decoding, HNSW memory, the `ruvllm`
19
+ CLI and a local `ruvllm serve` HTTP server. Since 4.1.0 it also pulls in
20
+ **[`@ruvector/ruvllm-gpu-loop`](https://www.npmjs.com/package/@ruvector/ruvllm-gpu-loop)**
21
+ (the RuVLLM GPU job loop, Vast.ai host adapter, adapter archives and bounded
22
+ weight experiments) as an optional dependency, so a single
23
+ `npm install @ruvector/ruvllm` gives you both.
24
+
25
+ **Why 4.1.0 exists.** Versions 4.0.0 and 4.0.1 were published from a different
26
+ repository (`ruvnet/ruvllm`) and replaced this runtime with only the GPU job
27
+ loop harness: no runtime API, no native bindings, no `ruvllm` CLI. 4.1.0
28
+ restores the runtime (the same API as 3.0.0) and keeps every 4.0.x entry point
29
+ working through `@ruvector/ruvllm-gpu-loop`. Do not use 4.0.0 or 4.0.1.
30
+
31
+ | You used | In 4.1.0 |
32
+ | :--- | :--- |
33
+ | 3.x / 2.x runtime: `require('@ruvector/ruvllm')`, `import … from '@ruvector/ruvllm'` | Unchanged (CommonJS and ESM) |
34
+ | 4.0.x root: `import { runExperiment } from '@ruvector/ruvllm'` | `import { runExperiment } from '@ruvector/ruvllm/engine'` |
35
+ | 4.0.x subpaths: `@ruvector/ruvllm/gpu-loop`, `/adapters`, `/gpu-host`, `/gpu-spool-adapter`, `/vast-host-adapter`, `/fixture` | Unchanged (re-exported from `@ruvector/ruvllm-gpu-loop`) |
36
+ | 4.0.x CLI: `ruvllm run …`, `ruvllm fixture …` | `ruvllm gpu run …`, `ruvllm gpu fixture …` (or `ruvllm-gpu` from `@ruvector/ruvllm-gpu-loop`) |
37
+ | `ruvllm-gpu-loop`, `ruvllm-adapters` | Unchanged; also `ruvllm gpu loop …`, `ruvllm gpu adapters …` |
38
+
39
+ The GPU-loop subpaths are loaded lazily: importing the root never loads them.
40
+ They need Node 22+ (the GPU-loop package's requirement). If the optional
41
+ package was skipped (`--omit=optional`), they throw `RUVLLM_GPU_LOOP_MISSING`
42
+ naming the install command. They are ESM; `require()` of them works where
43
+ Node supports `require(esm)` (20.19+ / 22.12+). If you only need the GPU job
44
+ loop, install `@ruvector/ruvllm-gpu-loop` on its own.
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ npm install @ruvector/ruvllm
50
+ ```
2
51
 
3
- <p align="center"><img src="https://raw.githubusercontent.com/ruvnet/ruvllm/ruvllm-npm-v4.0.1/docs/assets/gpu-job-loop.svg" alt="The GPU job loop checks a spending ceiling, rents the offer and arms a destroy timer, runs the pinned job, pulls raw outputs, checks them locally, then destroys the rental and confirms it is gone." width="100%"></p>
52
+ ## Quick Start
4
53
 
5
- <p align="center"><img src="https://raw.githubusercontent.com/ruvnet/ruvllm/ruvllm-npm-v4.0.1/docs/assets/heldout-results.svg" alt="Held-out results on 256 untouched tasks: tool passes 149, 176 and 192 of 192 for base, coding-4b and coding-4b-r2; arithmetic 62, 64 and 46 of 64. coding-4b is kept; coding-4b-r2 is rejected." width="100%"></p>
54
+ ```typescript
55
+ import { RuvLLM, RuvLLMConfig } from '@ruvector/ruvllm';
6
56
 
7
- Published on npm as `@ruvector/ruvllm`. Version 4.0.0 replaces the 3.x
8
- inference runtime from `ruvnet/ruvector` with this package, because ruvllm now
9
- lives in `ruvnet/ruvllm`. The 3.x API and its CLI subcommands are not part of
10
- 4.x; pin `@ruvector/ruvllm@3` to keep using them. The npm package ships the
11
- JavaScript controller, GPU loop and Vast.ai host adapter. It does not ship the
12
- native `weight_evolution` binary, model weights or adapters. Build the binary
13
- from this repository and pass its path with `--binary`.
57
+ // Initialize with default configuration
58
+ const llm = new RuvLLM();
14
59
 
15
- ```sh
16
- npm install @ruvector/ruvllm
17
- npx ruvllm --help # bounded weight-edit experiments
18
- npx ruvllm-gpu-loop status --config /abs/private/gpu-loop.json
60
+ // Or with custom configuration
61
+ const llm = new RuvLLM({ embeddingDim: 384, learningEnabled: true });
62
+
63
+ // Routing, memory and embeddings (no model needed)
64
+ const decision = llm.route('Explain quantum computing');
65
+ llm.addMemory('RuvLLM routes queries with FastGRNN', { source: 'docs' });
66
+ const hits = llm.searchMemory('how are queries routed?', 3);
67
+ const vec = llm.embed('Explain quantum computing');
68
+ ```
69
+
70
+ ## Text Generation (GGUF)
71
+
72
+ Text comes only from a model you load. `loadModel()` runs a local GGUF file
73
+ on the native candle backend (CPU; Metal on macOS builds with the `metal`
74
+ feature):
75
+
76
+ ```typescript
77
+ const llm = new RuvLLM();
78
+ llm.loadModel('./qwen2.5-0.5b-instruct-q4_k_m.gguf', { maxContext: 4096 });
79
+
80
+ const out = llm.chat([{ role: 'user', content: 'What is the capital of France?' }], {
81
+ maxTokens: 64,
82
+ temperature: 0,
83
+ });
84
+ // { text: 'The capital of France is Paris.', promptTokens: 15,
85
+ // completionTokens: 8, finishReason: 'stop' }
86
+ ```
87
+
88
+ - **Architectures**: GGUF `llama`, `mistral`, `qwen2` (Qwen2.5) and `qwen3`.
89
+ Any other architecture (phi, gemma, qwen3.5, ...) fails to load with an error
90
+ naming it.
91
+ - **Tokenizer**: a `tokenizer.json` next to the GGUF, else the tokenizer
92
+ embedded in the GGUF. The embedded one works for byte-level BPE (`gpt2`)
93
+ vocabularies such as Qwen and Llama 3; GGUFs with a SentencePiece vocabulary
94
+ (Llama 2, Mistral, TinyLlama) need the `tokenizer.json`, otherwise loading
95
+ fails with `RUVLLM_TOKENIZER_MISSING`.
96
+ - **`chat()`** applies the model's chat template, read from the GGUF's
97
+ embedded `tokenizer.chat_template` (ChatML for Qwen). A `qwen2`/`qwen3` GGUF
98
+ whose template is not ChatML (e.g. DeepSeek-R1-Distill-Qwen) fails to load
99
+ with `RUVLLM_MODEL_LOAD_FAILED` rather than run under the wrong format.
100
+ - **`generate()`** continues the prompt verbatim; **`query()`** routes, then
101
+ answers as a single chat message.
102
+ - **Usage**: `promptTokens`/`completionTokens` are counted with the model's
103
+ tokenizer; `finishReason` is `stop` (end-of-sequence token or a stop
104
+ sequence) or `length` (`maxTokens` reached or the context is full).
105
+ - **Blocking**: loading and generation are synchronous and block the event
106
+ loop; run them in a worker thread if that matters.
107
+
108
+ Without a loaded model, `generate()`, `query()`, `chat()` and
109
+ `generateDetailed()` throw `RUVLLM_NO_LANGUAGE_MODEL`; they never return text
110
+ that is not model output. For demos and tests, `new RuvLLM({ allowPlaceholder:
111
+ true })` (or `RUVLLM_ALLOW_MOCK=1`) makes `generate()`/`query()` return the
112
+ labelled `PLACEHOLDER_TEXT` instead, with a one-time warning.
113
+
114
+ ### Native binary requirements
115
+
116
+ Model loading needs a native binary built with the `candle` feature;
117
+ `supportsModelLoading()` reports whether the installed one was.
118
+
119
+ | Native binary | `loadModel()` |
120
+ |---------------|---------------|
121
+ | Built from this source (`npm run build:native`) | Works |
122
+ | `@ruvector/ruvllm-<platform>` 2.1.x (installed with `@ruvector/ruvllm` 4.2.0+, built by the release workflow with `candle`) | Works |
123
+ | `@ruvector/ruvllm-<platform>` 2.0.x | Throws `RUVLLM_NATIVE_TOO_OLD`: they predate model loading |
124
+ | Built with `--features napi` only (no `candle`) | Throws `RUVLLM_NO_INFERENCE_BACKEND` |
125
+ | None for your platform | Throws `RUVLLM_NATIVE_UNAVAILABLE` |
126
+
127
+ To use a binary you built, point `RUVLLM_NATIVE_PATH` at it (it takes
128
+ precedence over the installed platform package):
129
+
130
+ ```bash
131
+ npm run build:native # writes ruvllm.<platform>.node (needs a Rust toolchain)
132
+ RUVLLM_NATIVE_PATH=$PWD/ruvllm.linux-x64-gnu.node node app.js
133
+ ```
134
+
135
+ From 4.2.0 the platform packages (`@ruvector/ruvllm-<platform>@2.1.0`) are
136
+ built with `candle`, so `loadModel()`, `query`/`generate` with `--model` and
137
+ `ruvllm serve` work on a plain `npm install` for linux-x64, linux-arm64,
138
+ darwin-x64, darwin-arm64 and win32-x64. 4.1.0 and earlier shipped the 2.0.1
139
+ binaries, which predate model loading.
140
+
141
+ | Error code | Meaning |
142
+ |------------|---------|
143
+ | `RUVLLM_NO_LANGUAGE_MODEL` | Generation was requested with no model loaded |
144
+ | `RUVLLM_NATIVE_UNAVAILABLE` | No native binary could be loaded |
145
+ | `RUVLLM_NATIVE_TOO_OLD` | The native binary predates model loading (2.0.x platform packages) |
146
+ | `RUVLLM_NO_INFERENCE_BACKEND` | The native binary was built without the `candle` backend |
147
+ | `RUVLLM_MODEL_NOT_FOUND` | The model path does not exist |
148
+ | `RUVLLM_MODEL_LOAD_FAILED` | The file could not be loaded (unsupported architecture, not GGUF, ...) |
149
+ | `RUVLLM_TOKENIZER_MISSING` | Weights loaded but no usable tokenizer was found |
150
+
151
+ ## What's New in v2.5
152
+
153
+ | Feature | Description |
154
+ |---------|-------------|
155
+ | **TurboQuant KV-Cache** | 2-4 bit asymmetric quantization with per-channel scale/zero-point — 6-8x memory reduction, <0.5% perplexity loss |
156
+ | **TurboQuant Embedding Store** | Quantized vector storage with compressed search — 10-30x memory savings |
157
+ | **H2O / PyramidKV Eviction** | Intelligent cache eviction policies for long-context inference |
158
+ | **Optimized Inner Product** | Asymmetric distance on quantized data — skip decompression for 2-4x faster search |
159
+ | **RuvLTRA Models** | Purpose-built 0.5B & 3B models for Claude Flow |
160
+ | **Task-Specific LoRA** | 5 pre-trained adapters (coder, researcher, security, architect, reviewer) |
161
+ | **HuggingFace Hub** | Download/upload models directly |
162
+ | **Adapter Merging** | TIES, DARE, SLERP strategies |
163
+ | **HNSW Routing** | 150x faster semantic matching |
164
+ | **Evaluation Harness** | SWE-Bench testing with 5 ablation modes |
165
+ | **mistral-rs Backend** | Production serving with PagedAttention, X-LoRA, ISQ |
166
+
167
+ ## TurboQuant — KV-Cache Compression
168
+
169
+ Reduce inference memory by 6-8x with <0.5% quality loss:
170
+
171
+ ```typescript
172
+ import { simd } from '@ruvector/ruvllm/simd';
173
+
174
+ // TurboQuant compresses KV-cache entries at 2-4 bit precision
175
+ // with per-channel asymmetric quantization (scale + zero-point).
176
+ // Eviction policies (H2O, Sliding Window, PyramidKV) keep the
177
+ // most important tokens in cache during long-context generation.
178
+
179
+ // Supported bit widths: 2-bit (32x), 3-bit (10.7x), 4-bit (8x), 8-bit (4x)
180
+ ```
181
+
182
+ | Bits | Compression | Perplexity Loss | Use Case |
183
+ |------|-------------|-----------------|----------|
184
+ | 2-bit | 32x | ~2% | Maximum compression, edge devices |
185
+ | 3-bit | 10.7x | <1% | Balanced — recommended for most uses |
186
+ | 4-bit | 8x | <0.5% | High quality, long-context inference |
187
+ | 8-bit | 4x | ~0% | Baseline quantization |
188
+
189
+ ## CLI Usage
190
+
191
+ ```bash
192
+ # Query a model (this package's `ruvllm` bin; needs --model, see above)
193
+ ruvllm query "What is machine learning?" --model ./qwen2.5-0.5b-instruct-q4_k_m.gguf
194
+
195
+ # The commands below are the Rust ruvllm CLI (crate ruvllm-cli)
196
+ # Stream output
197
+ ruvllm query --stream "Write a poem"
198
+
199
+ # Download a model
200
+ ruvllm download ruvector/ruvltra-small-q4km
201
+
202
+ # Benchmark
203
+ ruvllm bench ./models/model.gguf
204
+
205
+ # Run evaluation (SWE-Bench)
206
+ ruvllm eval --model ./models/model.gguf --subset lite --max-tasks 50
207
+ ```
208
+
209
+ ## HTTP server: `ruvllm serve`
210
+
211
+ `ruvllm serve` runs a local LLM server over a GGUF model, on
212
+ `127.0.0.1:3000` by default (`--host`, `--port`, `--max-context`,
213
+ `--max-tokens`, `--temperature`). It is the endpoint the
214
+ [ruflo / claude-flow](https://github.com/ruvnet/claude-flow) RuVector provider
215
+ calls:
216
+
217
+ ```bash
218
+ npx @ruvector/ruvllm serve ./qwen2.5-0.5b-instruct-q4_k_m.gguf
219
+ curl -s localhost:3000/health
220
+ curl -s localhost:3000/query -H 'content-type: application/json' -d '{"query":"What is HNSW?"}'
221
+ curl -s localhost:3000/v1/chat/completions -H 'content-type: application/json' \
222
+ -d '{"messages":[{"role":"user","content":"Hello"}],"max_tokens":32}'
19
223
  ```
20
224
 
21
- Run multiple bounded RuVLLM edits against one unchanged checkpoint, validate
22
- supplied evaluations, package RVF evidence, restore every patched checkpoint,
23
- and rank research-qualified candidates through MetaHarness. This controller
24
- uses the actual Flywheel, Darwin and Weight-EFT packages pinned in
25
- [package-lock.json](package-lock.json).
26
-
27
- The runner does not perform inference, discover an effective weight edit, train
28
- an adapter or activate a model. CPU fixtures exercise real file editing and
29
- restoration with explicitly synthetic evaluation receipts. External evaluation
30
- files remain caller-supplied evidence; hashes do not authenticate their origin.
31
-
32
- ## Install and run the CPU fixture
33
-
34
- Requirements: Linux or macOS, Node 22+, Python 3.12+, a C linker, and Rust 1.97.1
35
- as pinned by `native/rust-toolchain.toml`. Activate any locally installed Rust
36
- toolchain before using Cargo. From the repository root:
37
-
38
- ```sh
39
- (cd integrations/metaharness && npm ci --ignore-scripts)
40
- (cd native && cargo build --locked --release --bin weight_evolution)
41
- python3 native/verify_source.py
42
- node integrations/metaharness/src/cli.mjs fixture \
43
- --dir "$PWD/runtime/metaharness-fixture" \
44
- --binary "$PWD/native/target/release/weight_evolution"
225
+ | Endpoint | Body / response |
226
+ | :--- | :--- |
227
+ | `GET /health` | `{ status, model, modelLoaded, native, sona, hnsw, version }` |
228
+ | `GET /v1/models` | OpenAI-style model list |
229
+ | `POST /query` | `{ query, session_id? }` → `{ id, model, content, done, usage, router_metrics }` |
230
+ | `POST /v1/chat/completions` | OpenAI chat format; `stream: true` returns the finished completion as one SSE chunk, then `[DONE]` |
231
+
232
+ The server is strict: it starts only after the model loads, and exits 1
233
+ otherwise (no placeholder answers, so clients such as ruflo fall back to
234
+ another provider instead of receiving non-model text). Generation is
235
+ synchronous, so requests are answered one at a time.
236
+
237
+ ## GPU job loop: `ruvllm gpu`
238
+
239
+ The RuVLLM GPU job loop schedules bounded GPU jobs (spending ceiling, destroy
240
+ timer, confirmed cleanup) on a Vast.ai host, packages LoRA adapter archives
241
+ and runs bounded weight-edit experiments. It lives in
242
+ [`@ruvector/ruvllm-gpu-loop`](https://www.npmjs.com/package/@ruvector/ruvllm-gpu-loop)
243
+ ([source](https://github.com/ruvnet/ruvllm/tree/main/integrations/metaharness));
244
+ this package exposes it as:
245
+
246
+ ```bash
247
+ npx ruvllm gpu loop status --config /abs/private/gpu-loop.json # = ruvllm-gpu-loop
248
+ npx ruvllm gpu adapters training-plan < plan.json # = ruvllm-adapters
249
+ npx ruvllm gpu fixture --dir /abs/new-dir --binary /abs/weight_evolution
45
250
  ```
46
251
 
47
- Create the fixture's parent directory first (`mkdir -p runtime`). Its own directory
48
- must not exist: exclusive creation prevents accidental replacement. For another
49
- fixture use a new directory. The report should select `fixture-improvement`, leave
50
- `unevaluated-control` unqualified, verify RVF and exact rollback for both, and
51
- report `inferencePerformed: false`, `independentConfirmation: false` and
52
- `productionActivation: false`. A selected synthetic candidate says nothing about
53
- actual model accuracy.
54
-
55
- ## Configure real experiment inputs
56
-
57
- Prepare reviewed source checkpoint, patch, policy and optional evaluation JSON
58
- under explicit input roots. Native request/data contracts are described in the
59
- [native guide](../../native/README.md). Patch generation remains model specific;
60
- the controller does not guess useful tensor edits.
61
-
62
- Run the project-local installer with paths you control:
63
-
64
- ```sh
65
- bash scripts/install-metaharness.sh \
66
- --config-dir /absolute/private/operator-profile \
67
- --read-root /absolute/checkpoints \
68
- --read-root /absolute/experiment-inputs \
69
- --policy /absolute/experiment-inputs/policy.json \
70
- --output-root /absolute/private/experiment-outputs
252
+ ```js
253
+ import { tickLoop, readLoopStatus } from '@ruvector/ruvllm/gpu-loop';
254
+ import { createVastAdapter } from '@ruvector/ruvllm/vast-host-adapter';
71
255
  ```
72
256
 
73
- It installs frozen npm dependencies without lifecycle scripts, builds the native
74
- binary, verifies native provenance and runs its smoke fixture. It creates a
75
- private runtime profile and Claude launcher without changing global settings.
76
- Repeat `--read-root`/`--policy` for additional approved inputs. Existing profile
77
- files are never replaced; use another directory for a new profile. Existing config
78
- and output directories must be owner-only. `--configure-only` skips installation
79
- and building but still checks native readiness.
80
-
81
- Example plan inside an approved read root:
82
-
83
- ```json
84
- {
85
- "schema": "ruvllm-experiment-plan/v1",
86
- "evidenceMode": "external",
87
- "source": "/absolute/checkpoints/source.safetensors",
88
- "policy": "/absolute/experiment-inputs/policy.json",
89
- "candidates": [
90
- {
91
- "id": "candidate-01",
92
- "patch": "/absolute/experiment-inputs/patch.json",
93
- "evaluation": "/absolute/experiment-inputs/evaluation.json"
94
- }
95
- ]
257
+ ## API Reference
258
+
259
+ ### RuvLLM Class
260
+
261
+ ```typescript
262
+ class RuvLLM {
263
+ constructor(config?: RuvLLMConfig);
264
+
265
+ // Language model (see "Text Generation" above)
266
+ loadModel(path: string, options?: LoadModelOptions): LoadedModelInfo;
267
+ unloadModel(): void;
268
+ isModelLoaded(): boolean;
269
+ modelInfo(): LoadedModelInfo | null;
270
+ supportsModelLoading(): boolean; // native binary can load models
271
+
272
+ // Generation; all throw RUVLLM_NO_LANGUAGE_MODEL without a loaded model
273
+ chat(messages: ChatMessage[], config?: GenerationConfig): GenerationResult;
274
+ generateDetailed(prompt: string, config?: GenerationConfig): GenerationResult;
275
+ generate(prompt: string, config?: GenerationConfig): string;
276
+ query(text: string, config?: GenerationConfig): QueryResponse; // routed, + token usage
277
+
278
+ // Routing, memory and embeddings
279
+ route(text: string): RoutingDecision;
280
+ addMemory(content: string, metadata?: Record<string, unknown>): MemoryId;
281
+ searchMemory(text: string, k?: number): MemoryResult[];
282
+ embed(text: string): Embedding;
283
+
284
+ // Not in this package: token streaming (StreamingGenerator chunks a
285
+ // finished generate() result), mistral-rs backends.
286
+
287
+ // Get SONA learning stats
288
+ sonaStats(): SonaStats | null;
289
+
290
+ // Adapt on feedback
291
+ adapt(input: Float32Array, quality: number): void;
96
292
  }
97
293
  ```
98
294
 
99
- ```sh
100
- node integrations/metaharness/src/cli.mjs run \
101
- --config /absolute/private/operator-profile/runtime.json \
102
- --plan /absolute/experiment-inputs/plan.json
295
+ ### Configuration
296
+
297
+ ```typescript
298
+ interface RuvLLMConfig {
299
+ modelPath?: string; // GGUF to load in the constructor (throws if it cannot be loaded)
300
+ modelOptions?: LoadModelOptions; // { maxContext?: number } for modelPath
301
+ allowPlaceholder?: boolean; // generate()/query() return PLACEHOLDER_TEXT instead of
302
+ // throwing when no model is loaded (default: false)
303
+ strict?: boolean; // Throw instead of warning for unsupported options (`backend`)
304
+ // ...plus routing/memory options (embeddingDim, hnswM, ...), see types.ts
305
+ }
103
306
  ```
104
307
 
105
- Omit `evaluation` to run mechanical checks without qualification. After an external
106
- inference runner has evaluated a candidate, submit its hash-bound evaluation in a
107
- new plan/run. Candidate checkpoint hashes are deterministic for the same patch;
108
- new artifact paths do not relax identity checks. Paired baseline, protocol, suite,
109
- runtime, precision and output-budget consistency remain the evaluator's responsibility.
308
+ ### Generation Config and Result
309
+
310
+ ```typescript
311
+ interface GenerationConfig {
312
+ maxTokens?: number; // default 256
313
+ temperature?: number; // default 0.7; 0 = greedy
314
+ topP?: number; // default 0.9, in (0, 1]
315
+ topK?: number; // default 50; 0 disables
316
+ repetitionPenalty?: number; // default 1.1
317
+ stopSequences?: string[]; // stop text is not included in the output
318
+ seed?: number; // reproducible sampling at temperature > 0
319
+ }
110
320
 
111
- Runs use new private `run-*` directories and preserve rejected candidates. Reports
112
- bind config/plan/source/policy/binary/gate/patch/evaluation identities and record
113
- rollback and RVF verification. Native rejection records a reason. Structural or
114
- restoration failures abort; interrupted runs can leave artifacts. Reconcile those
115
- directories before retrying; never erase failed evidence to manufacture success.
321
+ interface GenerationResult {
322
+ text: string;
323
+ promptTokens: number; // after the chat template, for chat()
324
+ completionTokens: number; // includes an end-of-sequence token that ended generation
325
+ finishReason: 'stop' | 'length' | 'cancelled';
326
+ }
327
+ ```
116
328
 
117
- ## Claude Code and Ruflo
329
+ ## SIMD Module
118
330
 
119
- Load [ruflo-metaharness](../../plugins/ruflo-metaharness/README.md) using the
120
- generated `launch-claude.sh`, or set `RUVLLM_EXPERIMENT_CONFIG` and use Claude's
121
- `--plugin-dir`. The `/ruflo-metaharness:weight-experiment` command and reviewer
122
- agent guide the bounded workflow. Its single MCP tool accepts a plan path; the
123
- model cannot override the operator configuration. The same stdio server can be
124
- registered in a Ruflo project's MCP configuration. Portable wire tests exercise
125
- the real engine; installed Claude/Ruflo client acceptance is separate.
331
+ For direct access to optimized SIMD kernels:
126
332
 
127
- ## Scheduled GPU work
333
+ ```typescript
334
+ import { simd } from '@ruvector/ruvllm/simd';
128
335
 
129
- For scheduled GPU work, use the [durable GPU loop](GPU-LOOP.md). It supports
130
- host-owned ruOS secret references, Vast job descriptors, persisted reservations,
131
- deadline-aware polling and confirmed cleanup. Local contract tests require no
132
- live provider. The bundled file handoff keeps requests pending for a trusted host.
336
+ // Dot product
337
+ const result = simd.dotProduct(vecA, vecB);
133
338
 
134
- ## Weight-EFT data and plans
339
+ // Matrix multiplication
340
+ const output = simd.matmul(matrix, vector);
135
341
 
136
- The data-only adapter CLI reads JSON stdin, with a 16 MiB bound:
342
+ // Flash Attention
343
+ const attended = simd.flashAttention(query, key, value, scale);
137
344
 
138
- ```sh
139
- node integrations/metaharness/src/adapters-cli.mjs export < reviewed-archive-input.json > export.json
140
- node integrations/metaharness/src/adapters-cli.mjs training-plan < training-input.json > plan.json
141
- node integrations/metaharness/src/adapters-cli.mjs select < measured-candidates.json > selection.json
345
+ // RMS Normalization
346
+ simd.rmsNorm(hidden, weights, epsilon);
142
347
  ```
143
348
 
144
- `export` takes `{archive, evalHoldout, maxTokens?}`. Archive entries follow the
145
- pinned Weight-EFT `DarwinTrajectory` contract (`instance_id`, `model`, `tier`,
146
- boolean `resolved`, `messages`, `model_patch`). All actual evaluation instance IDs
147
- must be in `evalHoldout`. Output contains standard `sft`/`dpo` arrays, drop reports
148
- and input hashes. Reward-hacking filtering stays enabled, overlength traces are
149
- dropped, and tool calls are preserved. These filters cannot authenticate outcomes
150
- or detect all semantic contamination.
151
-
152
- `training-plan` takes `{base:{id,paramsB},sftPath,dpoPath,adapterPrefix}`. It emits
153
- upstream plans plus `executionStatus: not_executed` and
154
- `runnerCompatibility: adapter-required`. This repository has no upstream
155
- `ruvllm microlora` executable. Its existing fixed CUDA/PEFT experiment runner is
156
- not a configurable SFT/DPO trainer. No GPU, model download or paid job is started.
157
-
158
- `select` takes `{baseline,candidates,envelope}` with entries
159
- `{id,score,evidenceSha256}`. It replays finite, supplied scores through Darwin's
160
- contrastive engine. It is development ranking with an immutable envelope and no
161
- independent confirmation; it cannot authenticate caller-supplied evidence. The
162
- native runner applies its stricter qualification first.
163
-
164
- ## Tests and benchmark
165
-
166
- ```sh
167
- (cd integrations/metaharness && npm test)
168
- node --test plugins/ruflo-metaharness/test/*.test.mjs
169
- node integrations/metaharness/bench/run.mjs --iterations 7 --warmup 2 --candidates 2
349
+ ## Performance (M4 Pro)
350
+
351
+ | Operation | Performance |
352
+ |-----------|-------------|
353
+ | Inference | 88-135 tok/s |
354
+ | Flash Attention | 320µs (seq=2048) |
355
+ | HNSW Search | 17-62µs |
356
+ | SONA Adapt | <1ms |
357
+ | Evaluation | 5 ablation modes |
358
+
359
+ ## Evaluation Harness
360
+
361
+ > **Not in this npm package**: `EvaluationHarness` and `AblationMode` are
362
+ > not exported by `@ruvector/ruvllm`. The sketch below shows the intended API.
363
+
364
+ Run model evaluations with SWE-Bench integration:
365
+
366
+ ```typescript
367
+ import { RuvLLM, EvaluationHarness, AblationMode } from '@ruvector/ruvllm';
368
+
369
+ const harness = new EvaluationHarness({
370
+ modelPath: './models/model.gguf',
371
+ enableHnsw: true,
372
+ enableSona: true,
373
+ });
374
+
375
+ // Run single evaluation
376
+ const result = await harness.evaluate(
377
+ 'Fix the null pointer exception',
378
+ 'def process(data): return data.split()',
379
+ AblationMode.Full
380
+ );
381
+
382
+ console.log(`Success: ${result.success}, Quality: ${result.qualityScore}`);
383
+
384
+ // Run ablation study (Baseline, RetrievalOnly, AdaptersOnly, R+A, Full)
385
+ const report = await harness.runAblationStudy(tasks);
386
+ for (const [mode, metrics] of Object.entries(report.modeMetrics)) {
387
+ console.log(`${mode}: ${metrics.successRate * 100}% success`);
388
+ }
170
389
  ```
171
390
 
172
- Tests require the built native binary. In restricted agent environments the Node
173
- test runner, native child processes and package fetching may require the host's
174
- supported execution permission. Verify actual subtest counts; a file-only runner
175
- summary is insufficient evidence. Do not disable TLS/checksums or native checks.
176
-
177
- The benchmark compares fresh versus reused Node processes on identical CPU
178
- fixtures, retaining raw latency samples and implementation/binary/lock hashes.
179
- The reused process matches the MCP server architecture. All native hashing,
180
- patch validation and byte restoration remain enabled. See the
181
- [benchmark report](../../docs/benchmarks/metaharness-cpu.md) for measured scope
182
- and limits; no model-performance claim follows from orchestration speed.
183
-
184
- Architecture and threat boundaries are recorded in
185
- [ADR 012](../../docs/adr/ADR-012-metaharness-bounded-experiment-runner.md),
186
- [ADR 013](../../docs/adr/ADR-013-training-and-development-selection.md) and
187
- [ADR 014](../../docs/adr/ADR-014-claude-ruflo-integration.md).
391
+ ## mistral-rs Backend (Production Serving)
392
+
393
+ For production deployments with 10-100+ concurrent users, use the mistral-rs backend:
394
+
395
+ ```typescript
396
+ import { RuvLLM, MistralBackend, PagedAttentionConfig } from '@ruvector/ruvllm';
397
+
398
+ // Configure for production serving
399
+ const backend = new MistralBackend({
400
+ // PagedAttention: 5-10x more concurrent users
401
+ pagedAttention: {
402
+ blockSize: 16,
403
+ maxBlocks: 4096,
404
+ gpuMemoryFraction: 0.9,
405
+ prefixCaching: true,
406
+ },
407
+ // X-LoRA: Per-token adapter routing
408
+ xlora: {
409
+ adapters: ['./adapters/coder', './adapters/researcher'],
410
+ topK: 2,
411
+ },
412
+ // ISQ: Runtime quantization
413
+ isq: {
414
+ bits: 4,
415
+ method: 'awq',
416
+ },
417
+ });
418
+
419
+ const llm = new RuvLLM({ backend });
420
+ await llm.loadModel('mistralai/Mistral-7B-Instruct-v0.2');
421
+
422
+ // Serve multiple concurrent requests
423
+ const response = await llm.query('Write production code');
424
+ ```
425
+
426
+ > **Not in this npm package**: `MistralBackend` is not exported, the
427
+ > `backend` option is ignored (with a `RUVLLM_UNSUPPORTED_OPTION` warning), and
428
+ > `loadModel()` takes a local GGUF path, not a Hub id. mistral-rs serving is a
429
+ > feature of the Rust crate (`mistral-rs` feature).
430
+
431
+ ## Supported Models
432
+
433
+ GGUF files loadable with `loadModel()` (architectures llama, mistral, qwen2, qwen3):
434
+
435
+ - **RuvLTRA-Small** (494M) - Q4K, Q5K, Q8
436
+ - **RuvLTRA-Medium** (3B) - Q4K, Q5K, Q8
437
+ - **Qwen 2.5 / Qwen 3** (0.5B-72B)
438
+ - **Llama 3.x** (8B-70B)
439
+ - **Mistral** (7B-22B)
440
+
441
+ Phi-3, Gemma-2 and Qwen3.5 GGUFs are not supported: loading fails with an
442
+ error naming the architecture.
443
+
444
+ ## Platform Support
445
+
446
+ The table covers routing, memory and embeddings. Model loading additionally
447
+ needs a native binary built with the `candle` feature (see "Native binary
448
+ requirements").
449
+
450
+ | Platform | Architecture | Status |
451
+ |----------|--------------|--------|
452
+ | macOS | arm64 (M1-M4) | ✅ Full support |
453
+ | macOS | x64 | ✅ Supported |
454
+ | Linux | x64 | ✅ Supported |
455
+ | Linux | arm64 | ✅ Supported |
456
+ | Windows | x64 | ✅ Supported |
457
+
458
+ ## Related Packages
459
+
460
+ - [@ruvector/core](https://www.npmjs.com/package/@ruvector/core) - Vector operations
461
+ - [@ruvector/sona](https://www.npmjs.com/package/@ruvector/sona) - SONA learning engine
462
+ - [@ruvector/ruvllm-gpu-loop](https://www.npmjs.com/package/@ruvector/ruvllm-gpu-loop) - RuVLLM GPU job loop, Vast.ai adapter and adapter archives
463
+ - [@ruvector/ruvector](https://www.npmjs.com/package/@ruvector/ruvector) - Full Ruvector SDK
464
+
465
+ ## Links
466
+
467
+ - [GitHub Repository](https://github.com/ruvnet/ruvector)
468
+ - [API Documentation](https://docs.rs/ruvllm)
469
+ - [Crate (Rust)](https://crates.io/crates/ruvllm)
470
+
471
+ ## License
472
+
473
+ MIT OR Apache-2.0