@ruvector/ruvllm 2.7.0 → 4.0.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 (151) hide show
  1. package/GPU-LOOP.md +229 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +9 -0
  4. package/README.md +157 -263
  5. package/examples/gpu-loop.example.json +26 -0
  6. package/package.json +50 -120
  7. package/src/adapters-cli.mjs +23 -0
  8. package/src/adapters.mjs +91 -0
  9. package/src/cli.mjs +30 -0
  10. package/src/engine.mjs +238 -0
  11. package/src/fixture.mjs +38 -0
  12. package/src/gpu-host.mjs +47 -0
  13. package/src/gpu-loop-cli.mjs +67 -0
  14. package/src/gpu-loop.mjs +184 -0
  15. package/src/gpu-spool-adapter.mjs +80 -0
  16. package/src/vast-host-adapter.mjs +274 -0
  17. package/bin/cli.js +0 -1020
  18. package/dist/cjs/benchmarks/embedding-benchmark.d.ts +0 -102
  19. package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +0 -1
  20. package/dist/cjs/benchmarks/embedding-benchmark.js +0 -436
  21. package/dist/cjs/benchmarks/index.d.ts +0 -34
  22. package/dist/cjs/benchmarks/index.d.ts.map +0 -1
  23. package/dist/cjs/benchmarks/index.js +0 -132
  24. package/dist/cjs/benchmarks/model-comparison.d.ts +0 -71
  25. package/dist/cjs/benchmarks/model-comparison.d.ts.map +0 -1
  26. package/dist/cjs/benchmarks/model-comparison.js +0 -476
  27. package/dist/cjs/benchmarks/routing-benchmark.d.ts +0 -70
  28. package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +0 -1
  29. package/dist/cjs/benchmarks/routing-benchmark.js +0 -289
  30. package/dist/cjs/contrastive.d.ts +0 -229
  31. package/dist/cjs/contrastive.d.ts.map +0 -1
  32. package/dist/cjs/contrastive.js +0 -589
  33. package/dist/cjs/engine.d.ts +0 -95
  34. package/dist/cjs/engine.d.ts.map +0 -1
  35. package/dist/cjs/engine.js +0 -372
  36. package/dist/cjs/export.d.ts +0 -182
  37. package/dist/cjs/export.d.ts.map +0 -1
  38. package/dist/cjs/export.js +0 -422
  39. package/dist/cjs/federated.d.ts +0 -233
  40. package/dist/cjs/federated.d.ts.map +0 -1
  41. package/dist/cjs/federated.js +0 -525
  42. package/dist/cjs/index.d.ts +0 -68
  43. package/dist/cjs/index.d.ts.map +0 -1
  44. package/dist/cjs/index.js +0 -104
  45. package/dist/cjs/intelligence.d.ts +0 -136
  46. package/dist/cjs/intelligence.d.ts.map +0 -1
  47. package/dist/cjs/intelligence.js +0 -226
  48. package/dist/cjs/lora.d.ts +0 -251
  49. package/dist/cjs/lora.d.ts.map +0 -1
  50. package/dist/cjs/lora.js +0 -509
  51. package/dist/cjs/models.d.ts +0 -129
  52. package/dist/cjs/models.d.ts.map +0 -1
  53. package/dist/cjs/models.js +0 -323
  54. package/dist/cjs/native.d.ts +0 -92
  55. package/dist/cjs/native.d.ts.map +0 -1
  56. package/dist/cjs/native.js +0 -77
  57. package/dist/cjs/session.d.ts +0 -80
  58. package/dist/cjs/session.d.ts.map +0 -1
  59. package/dist/cjs/session.js +0 -203
  60. package/dist/cjs/simd.d.ts +0 -90
  61. package/dist/cjs/simd.d.ts.map +0 -1
  62. package/dist/cjs/simd.js +0 -209
  63. package/dist/cjs/sona.d.ts +0 -223
  64. package/dist/cjs/sona.d.ts.map +0 -1
  65. package/dist/cjs/sona.js +0 -562
  66. package/dist/cjs/streaming.d.ts +0 -55
  67. package/dist/cjs/streaming.d.ts.map +0 -1
  68. package/dist/cjs/streaming.js +0 -131
  69. package/dist/cjs/training.d.ts +0 -312
  70. package/dist/cjs/training.d.ts.map +0 -1
  71. package/dist/cjs/training.js +0 -610
  72. package/dist/cjs/types.d.ts +0 -615
  73. package/dist/cjs/types.d.ts.map +0 -1
  74. package/dist/cjs/types.js +0 -6
  75. package/dist/esm/benchmarks/embedding-benchmark.d.ts +0 -102
  76. package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +0 -1
  77. package/dist/esm/benchmarks/embedding-benchmark.js +0 -427
  78. package/dist/esm/benchmarks/index.d.ts +0 -34
  79. package/dist/esm/benchmarks/index.d.ts.map +0 -1
  80. package/dist/esm/benchmarks/index.js +0 -110
  81. package/dist/esm/benchmarks/model-comparison.d.ts +0 -71
  82. package/dist/esm/benchmarks/model-comparison.d.ts.map +0 -1
  83. package/dist/esm/benchmarks/model-comparison.js +0 -434
  84. package/dist/esm/benchmarks/routing-benchmark.d.ts +0 -70
  85. package/dist/esm/benchmarks/routing-benchmark.d.ts.map +0 -1
  86. package/dist/esm/benchmarks/routing-benchmark.js +0 -283
  87. package/dist/esm/contrastive.d.ts +0 -229
  88. package/dist/esm/contrastive.d.ts.map +0 -1
  89. package/dist/esm/contrastive.js +0 -578
  90. package/dist/esm/engine.d.ts +0 -95
  91. package/dist/esm/engine.d.ts.map +0 -1
  92. package/dist/esm/engine.js +0 -368
  93. package/dist/esm/export.d.ts +0 -182
  94. package/dist/esm/export.d.ts.map +0 -1
  95. package/dist/esm/export.js +0 -414
  96. package/dist/esm/federated.d.ts +0 -233
  97. package/dist/esm/federated.d.ts.map +0 -1
  98. package/dist/esm/federated.js +0 -520
  99. package/dist/esm/index.d.ts +0 -68
  100. package/dist/esm/index.d.ts.map +0 -1
  101. package/dist/esm/index.js +0 -84
  102. package/dist/esm/intelligence.d.ts +0 -136
  103. package/dist/esm/intelligence.d.ts.map +0 -1
  104. package/dist/esm/intelligence.js +0 -188
  105. package/dist/esm/lora.d.ts +0 -251
  106. package/dist/esm/lora.d.ts.map +0 -1
  107. package/dist/esm/lora.js +0 -504
  108. package/dist/esm/models.d.ts +0 -129
  109. package/dist/esm/models.d.ts.map +0 -1
  110. package/dist/esm/models.js +0 -282
  111. package/dist/esm/native.d.ts +0 -92
  112. package/dist/esm/native.d.ts.map +0 -1
  113. package/dist/esm/native.js +0 -72
  114. package/dist/esm/session.d.ts +0 -80
  115. package/dist/esm/session.d.ts.map +0 -1
  116. package/dist/esm/session.js +0 -199
  117. package/dist/esm/simd.d.ts +0 -90
  118. package/dist/esm/simd.d.ts.map +0 -1
  119. package/dist/esm/simd.js +0 -205
  120. package/dist/esm/sona.d.ts +0 -223
  121. package/dist/esm/sona.d.ts.map +0 -1
  122. package/dist/esm/sona.js +0 -556
  123. package/dist/esm/streaming.d.ts +0 -55
  124. package/dist/esm/streaming.d.ts.map +0 -1
  125. package/dist/esm/streaming.js +0 -126
  126. package/dist/esm/training.d.ts +0 -312
  127. package/dist/esm/training.d.ts.map +0 -1
  128. package/dist/esm/training.js +0 -603
  129. package/dist/esm/types.d.ts +0 -615
  130. package/dist/esm/types.d.ts.map +0 -1
  131. package/dist/esm/types.js +0 -5
  132. package/scripts/ensemble-model-compare.js +0 -287
  133. package/scripts/fix-esm-extensions.mjs +0 -181
  134. package/scripts/huggingface/README.md +0 -537
  135. package/scripts/huggingface/publish.sh +0 -112
  136. package/scripts/hybrid-model-compare.js +0 -373
  137. package/scripts/improved-model-compare.js +0 -288
  138. package/scripts/optimized-model-compare.js +0 -364
  139. package/scripts/real-model-compare.js +0 -280
  140. package/scripts/smoke-esm.mjs +0 -82
  141. package/scripts/training/agentic-flow-capabilities.json +0 -329
  142. package/scripts/training/claude-code-synth.js +0 -505
  143. package/scripts/training/claude-flow-capabilities.json +0 -1322
  144. package/scripts/training/claude-hard-negatives.js +0 -222
  145. package/scripts/training/contrastive-finetune.js +0 -517
  146. package/scripts/training/ecosystem-triplets.jsonl +0 -1467
  147. package/scripts/training/generate-ecosystem-triplets.js +0 -1324
  148. package/scripts/training/routing-dataset.js +0 -634
  149. package/scripts/training/ruvector-capabilities.json +0 -798
  150. package/scripts/training/validate-ecosystem.js +0 -381
  151. package/scripts/training/validation-results.json +0 -23
@@ -1,95 +0,0 @@
1
- /**
2
- * RuvLLM Engine - Main orchestrator for self-learning LLM
3
- */
4
- import { RuvLLMConfig, GenerationConfig, QueryResponse, RoutingDecision, MemoryResult, MemoryId, RuvLLMStats, Feedback, Embedding, BatchQueryRequest, BatchQueryResponse } from './types';
5
- /**
6
- * RuvLLM - Self-learning LLM orchestrator
7
- *
8
- * Combines SONA adaptive learning with HNSW memory,
9
- * FastGRNN routing, and SIMD-optimized inference.
10
- *
11
- * @example
12
- * ```typescript
13
- * import { RuvLLM } from '@ruvector/ruvllm';
14
- *
15
- * const llm = new RuvLLM({ embeddingDim: 768 });
16
- *
17
- * // Query with automatic routing
18
- * const response = await llm.query('What is machine learning?');
19
- * console.log(response.text);
20
- *
21
- * // Provide feedback for learning
22
- * llm.feedback({ requestId: response.requestId, rating: 5 });
23
- * ```
24
- */
25
- export declare class RuvLLM {
26
- private native;
27
- private config;
28
- private fallbackState;
29
- /**
30
- * Create a new RuvLLM instance
31
- */
32
- constructor(config?: RuvLLMConfig);
33
- /**
34
- * Query the LLM with automatic routing
35
- */
36
- query(text: string, config?: GenerationConfig): QueryResponse;
37
- /**
38
- * Generate text with SIMD-optimized inference
39
- *
40
- * Note: the native engine has no language-model weights, so its text is
41
- * not model output; the first call emits a `RUVLLM_NO_LANGUAGE_MODEL`
42
- * warning (or throws with `strict: true`). Without the native module this
43
- * returns an informational message.
44
- */
45
- generate(prompt: string, config?: GenerationConfig): string;
46
- /**
47
- * Get routing decision for a query
48
- */
49
- route(text: string): RoutingDecision;
50
- /**
51
- * Search memory for similar content
52
- */
53
- searchMemory(text: string, k?: number): MemoryResult[];
54
- /**
55
- * Add content to memory
56
- */
57
- addMemory(content: string, metadata?: Record<string, unknown>): MemoryId;
58
- /**
59
- * Provide feedback for learning
60
- */
61
- feedback(fb: Feedback): boolean;
62
- /**
63
- * Get engine statistics
64
- */
65
- stats(): RuvLLMStats;
66
- /**
67
- * Force router learning cycle
68
- */
69
- forceLearn(): string;
70
- /**
71
- * Get embedding for text
72
- */
73
- embed(text: string): Embedding;
74
- /**
75
- * Compute similarity between two texts
76
- */
77
- similarity(text1: string, text2: string): number;
78
- /**
79
- * Check if SIMD is available
80
- */
81
- hasSimd(): boolean;
82
- /**
83
- * Get SIMD capabilities
84
- */
85
- simdCapabilities(): string[];
86
- /**
87
- * Batch query multiple prompts
88
- */
89
- batchQuery(request: BatchQueryRequest): BatchQueryResponse;
90
- /**
91
- * Check if native module is loaded
92
- */
93
- isNativeLoaded(): boolean;
94
- }
95
- //# sourceMappingURL=engine.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AA+DjB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,MAAM,CAAe;IAG7B,OAAO,CAAC,aAAa,CAInB;IAEF;;OAEG;gBACS,MAAM,CAAC,EAAE,YAAY;IAwBjC;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,aAAa;IA6B7D;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,gBAAgB,GAAG,MAAM;IA0B3D;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;IAsBpC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,SAAK,GAAG,YAAY,EAAE;IAmClD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ;IAexE;;OAEG;IACH,QAAQ,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO;IAO/B;;OAEG;IACH,KAAK,IAAI,WAAW;IA8BpB;;OAEG;IACH,UAAU,IAAI,MAAM;IAOpB;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS;IAmB9B;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IA6BhD;;OAEG;IACH,OAAO,IAAI,OAAO;IAOlB;;OAEG;IACH,gBAAgB,IAAI,MAAM,EAAE;IAO5B;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,kBAAkB;IAS1D;;OAEG;IACH,cAAc,IAAI,OAAO;CAG1B"}
@@ -1,372 +0,0 @@
1
- "use strict";
2
- /**
3
- * RuvLLM Engine - Main orchestrator for self-learning LLM
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.RuvLLM = void 0;
7
- const native_1 = require("./native");
8
- /**
9
- * Convert JS config to native config format
10
- */
11
- function toNativeConfig(config) {
12
- if (!config)
13
- return undefined;
14
- return {
15
- embedding_dim: config.embeddingDim,
16
- router_hidden_dim: config.routerHiddenDim,
17
- hnsw_m: config.hnswM,
18
- hnsw_ef_construction: config.hnswEfConstruction,
19
- hnsw_ef_search: config.hnswEfSearch,
20
- learning_enabled: config.learningEnabled,
21
- quality_threshold: config.qualityThreshold,
22
- ewc_lambda: config.ewcLambda,
23
- };
24
- }
25
- /**
26
- * Convert JS generation config to native format
27
- */
28
- function toNativeGenConfig(config) {
29
- if (!config)
30
- return undefined;
31
- return {
32
- max_tokens: config.maxTokens,
33
- temperature: config.temperature,
34
- top_p: config.topP,
35
- top_k: config.topK,
36
- repetition_penalty: config.repetitionPenalty,
37
- };
38
- }
39
- const warned = new Set();
40
- /** Warn once per process (or throw when `strict`). */
41
- function notice(code, message, strict) {
42
- if (strict)
43
- throw new Error(`${code}: ${message}`);
44
- if (warned.has(code))
45
- return;
46
- warned.add(code);
47
- const g = globalThis;
48
- if (typeof g.process?.emitWarning === 'function')
49
- g.process.emitWarning(message, { code });
50
- else
51
- g.console?.warn?.(`${code}: ${message}`);
52
- }
53
- const NO_LM_MESSAGE = 'the native RuvLLM engine has no language-model weights, so generate()/query() text is ' +
54
- 'not model output. For GGUF inference use the ruvllm CLI (`ruvllm serve <model> --strict`) ' +
55
- 'or another OpenAI-compatible server. Routing, memory and embeddings are unaffected. ' +
56
- 'Pass { strict: true } to throw instead.';
57
- /**
58
- * RuvLLM - Self-learning LLM orchestrator
59
- *
60
- * Combines SONA adaptive learning with HNSW memory,
61
- * FastGRNN routing, and SIMD-optimized inference.
62
- *
63
- * @example
64
- * ```typescript
65
- * import { RuvLLM } from '@ruvector/ruvllm';
66
- *
67
- * const llm = new RuvLLM({ embeddingDim: 768 });
68
- *
69
- * // Query with automatic routing
70
- * const response = await llm.query('What is machine learning?');
71
- * console.log(response.text);
72
- *
73
- * // Provide feedback for learning
74
- * llm.feedback({ requestId: response.requestId, rating: 5 });
75
- * ```
76
- */
77
- class RuvLLM {
78
- /**
79
- * Create a new RuvLLM instance
80
- */
81
- constructor(config) {
82
- this.native = null;
83
- // Fallback state for when native module is not available
84
- this.fallbackState = {
85
- memory: new Map(),
86
- nextId: 1,
87
- queryCount: 0,
88
- };
89
- this.config = config ?? {};
90
- const extra = this.config;
91
- for (const key of ['modelPath', 'backend']) {
92
- if (extra[key] !== undefined) {
93
- notice('RUVLLM_UNSUPPORTED_OPTION', `\`${key}\` is not supported by @ruvector/ruvllm and is ignored: this package does not ` +
94
- 'load model files. For GGUF inference use the ruvllm CLI (`ruvllm serve <model> --strict`).', this.config.strict);
95
- }
96
- }
97
- const mod = (0, native_1.getNativeModule)();
98
- if (mod) {
99
- try {
100
- this.native = new mod.RuvLLMEngine(toNativeConfig(config));
101
- }
102
- catch {
103
- // Silently fall back to JS implementation
104
- }
105
- }
106
- }
107
- /**
108
- * Query the LLM with automatic routing
109
- */
110
- query(text, config) {
111
- if (this.native) {
112
- notice('RUVLLM_NO_LANGUAGE_MODEL', NO_LM_MESSAGE, this.config.strict);
113
- const result = this.native.query(text, toNativeGenConfig(config));
114
- // napi-rs camelCases Rust field names on the way out, so the native
115
- // object carries `contextSize`/`latencyMs`/`requestId`. The snake_case
116
- // reads are kept as a fallback for older native builds.
117
- return {
118
- text: result.text,
119
- confidence: result.confidence,
120
- model: result.model,
121
- contextSize: result.contextSize ?? result.context_size,
122
- latencyMs: result.latencyMs ?? result.latency_ms,
123
- requestId: result.requestId ?? result.request_id,
124
- };
125
- }
126
- // Fallback implementation
127
- this.fallbackState.queryCount++;
128
- return {
129
- text: `[Fallback] Response to: ${text.slice(0, 50)}...`,
130
- confidence: 0.5,
131
- model: 'fallback',
132
- contextSize: 512,
133
- latencyMs: 1.0,
134
- requestId: `fb-${Date.now()}-${Math.random().toString(36).slice(2)}`,
135
- };
136
- }
137
- /**
138
- * Generate text with SIMD-optimized inference
139
- *
140
- * Note: the native engine has no language-model weights, so its text is
141
- * not model output; the first call emits a `RUVLLM_NO_LANGUAGE_MODEL`
142
- * warning (or throws with `strict: true`). Without the native module this
143
- * returns an informational message.
144
- */
145
- generate(prompt, config) {
146
- if (this.native) {
147
- notice('RUVLLM_NO_LANGUAGE_MODEL', NO_LM_MESSAGE, this.config.strict);
148
- return this.native.generate(prompt, toNativeGenConfig(config));
149
- }
150
- // Fallback - provide helpful message instead of garbled output
151
- const maxTokens = config?.maxTokens ?? 256;
152
- const temp = config?.temperature ?? 0.7;
153
- const topP = config?.topP ?? 0.9;
154
- return `[RuvLLM JavaScript Fallback Mode]
155
- No native SIMD module loaded. Running in JavaScript fallback mode.
156
-
157
- Your prompt: "${prompt.slice(0, 100)}${prompt.length > 100 ? '...' : ''}"
158
-
159
- To enable native SIMD inference:
160
- 1. Install the native bindings: npm install @ruvector/ruvllm-${process.platform}-${process.arch}
161
- 2. Or load a GGUF model file
162
- 3. Or connect to an external LLM API
163
-
164
- Config: temp=${temp.toFixed(2)}, top_p=${topP.toFixed(2)}, max_tokens=${maxTokens}
165
-
166
- This fallback provides routing, memory, and embedding features but not full text generation.`;
167
- }
168
- /**
169
- * Get routing decision for a query
170
- */
171
- route(text) {
172
- if (this.native) {
173
- const result = this.native.route(text);
174
- return {
175
- model: result.model,
176
- contextSize: result.contextSize ?? result.context_size,
177
- temperature: result.temperature,
178
- topP: result.topP ?? result.top_p,
179
- confidence: result.confidence,
180
- };
181
- }
182
- // Fallback
183
- return {
184
- model: 'M700',
185
- contextSize: 512,
186
- temperature: 0.7,
187
- topP: 0.9,
188
- confidence: 0.5,
189
- };
190
- }
191
- /**
192
- * Search memory for similar content
193
- */
194
- searchMemory(text, k = 10) {
195
- if (this.native) {
196
- const results = this.native.searchMemory(text, k);
197
- return results.map(r => {
198
- // The native side reports `distance` (smaller is closer). MemoryResult
199
- // documents `score` as a similarity, so convert rather than passing a
200
- // distance through under a similarity's name. Older builds that already
201
- // emit `score` are used as-is.
202
- const anyR = r;
203
- const score = typeof anyR.score === 'number'
204
- ? anyR.score
205
- : typeof anyR.distance === 'number'
206
- ? 1 / (1 + Math.max(0, anyR.distance))
207
- : 0;
208
- return {
209
- id: r.id,
210
- score,
211
- content: r.content,
212
- metadata: JSON.parse(r.metadata || '{}'),
213
- };
214
- });
215
- }
216
- // Fallback - simple search
217
- return Array.from(this.fallbackState.memory.entries())
218
- .slice(0, k)
219
- .map(([id, data]) => ({
220
- id,
221
- score: 0.5,
222
- content: data.content,
223
- metadata: data.metadata,
224
- }));
225
- }
226
- /**
227
- * Add content to memory
228
- */
229
- addMemory(content, metadata) {
230
- if (this.native) {
231
- return this.native.addMemory(content, metadata ? JSON.stringify(metadata) : undefined);
232
- }
233
- // Fallback
234
- const id = this.fallbackState.nextId++;
235
- this.fallbackState.memory.set(id, {
236
- content,
237
- embedding: this.embed(content),
238
- metadata: metadata ?? {},
239
- });
240
- return id;
241
- }
242
- /**
243
- * Provide feedback for learning
244
- */
245
- feedback(fb) {
246
- if (this.native) {
247
- return this.native.feedback(fb.requestId, fb.rating, fb.correction);
248
- }
249
- return false;
250
- }
251
- /**
252
- * Get engine statistics
253
- */
254
- stats() {
255
- if (this.native) {
256
- const s = this.native.stats();
257
- // Map native stats (snake_case) to TypeScript interface (camelCase)
258
- // Handle both old and new field names for backward compatibility
259
- return {
260
- totalQueries: s.totalQueries ?? s.total_queries ?? 0,
261
- memoryNodes: s.memoryNodes ?? s.memory_nodes ?? 0,
262
- patternsLearned: s.trainingSteps ??
263
- s.patterns_learned ??
264
- s.training_steps ??
265
- 0,
266
- avgLatencyMs: s.avgLatencyMs ?? s.avg_latency_ms ?? 0,
267
- cacheHitRate: s.cacheHitRate ?? s.cache_hit_rate ?? 0,
268
- routerAccuracy: s.routerAccuracy ?? s.router_accuracy ?? 0.5,
269
- };
270
- }
271
- // Fallback
272
- return {
273
- totalQueries: this.fallbackState.queryCount,
274
- memoryNodes: this.fallbackState.memory.size,
275
- patternsLearned: 0,
276
- avgLatencyMs: 1.0,
277
- cacheHitRate: 0.0,
278
- routerAccuracy: 0.5,
279
- };
280
- }
281
- /**
282
- * Force router learning cycle
283
- */
284
- forceLearn() {
285
- if (this.native) {
286
- return this.native.forceLearn();
287
- }
288
- return 'Learning not available in fallback mode';
289
- }
290
- /**
291
- * Get embedding for text
292
- */
293
- embed(text) {
294
- if (this.native) {
295
- return this.native.embed(text);
296
- }
297
- // Fallback - simple hash-based embedding
298
- const dim = this.config.embeddingDim ?? 768;
299
- const embedding = new Array(dim).fill(0);
300
- for (let i = 0; i < text.length; i++) {
301
- const idx = (text.charCodeAt(i) * (i + 1)) % dim;
302
- embedding[idx] += 0.1;
303
- }
304
- // Normalize
305
- const norm = Math.sqrt(embedding.reduce((sum, x) => sum + x * x, 0)) || 1;
306
- return embedding.map(x => x / norm);
307
- }
308
- /**
309
- * Compute similarity between two texts
310
- */
311
- similarity(text1, text2) {
312
- if (this.native) {
313
- // f32 accumulation can land just outside the mathematical range — an
314
- // identical pair measures 1.0000001 — which turns Math.acos(sim) into
315
- // NaN downstream. Cosine similarity is defined on [-1, 1], so clamp.
316
- const raw = this.native.similarity(text1, text2);
317
- return Math.min(1, Math.max(-1, raw));
318
- }
319
- // Fallback - cosine similarity
320
- const emb1 = this.embed(text1);
321
- const emb2 = this.embed(text2);
322
- let dot = 0;
323
- let norm1 = 0;
324
- let norm2 = 0;
325
- for (let i = 0; i < emb1.length; i++) {
326
- dot += emb1[i] * emb2[i];
327
- norm1 += emb1[i] * emb1[i];
328
- norm2 += emb2[i] * emb2[i];
329
- }
330
- const denom = Math.sqrt(norm1) * Math.sqrt(norm2);
331
- const similarity = denom > 0 ? dot / denom : 0;
332
- // Clamp to [0, 1] to handle floating point errors
333
- return Math.max(0, Math.min(1, similarity));
334
- }
335
- /**
336
- * Check if SIMD is available
337
- */
338
- hasSimd() {
339
- if (this.native) {
340
- return this.native.hasSimd();
341
- }
342
- return false;
343
- }
344
- /**
345
- * Get SIMD capabilities
346
- */
347
- simdCapabilities() {
348
- if (this.native) {
349
- return this.native.simdCapabilities();
350
- }
351
- return ['Scalar (fallback)'];
352
- }
353
- /**
354
- * Batch query multiple prompts
355
- */
356
- batchQuery(request) {
357
- const start = Date.now();
358
- const responses = request.queries.map(q => this.query(q, request.config));
359
- return {
360
- responses,
361
- totalLatencyMs: Date.now() - start,
362
- };
363
- }
364
- /**
365
- * Check if native module is loaded
366
- */
367
- isNativeLoaded() {
368
- return this.native !== null;
369
- }
370
- }
371
- exports.RuvLLM = RuvLLM;
372
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5naW5lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VuZ2luZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7OztBQWdCSCxxQ0FLa0I7QUFFbEI7O0dBRUc7QUFDSCxTQUFTLGNBQWMsQ0FBQyxNQUFxQjtJQUMzQyxJQUFJLENBQUMsTUFBTTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBRTlCLE9BQU87UUFDTCxhQUFhLEVBQUUsTUFBTSxDQUFDLFlBQVk7UUFDbEMsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLGVBQWU7UUFDekMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLO1FBQ3BCLG9CQUFvQixFQUFFLE1BQU0sQ0FBQyxrQkFBa0I7UUFDL0MsY0FBYyxFQUFFLE1BQU0sQ0FBQyxZQUFZO1FBQ25DLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxlQUFlO1FBQ3hDLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxnQkFBZ0I7UUFDMUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxTQUFTO0tBQzdCLENBQUM7QUFDSixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLGlCQUFpQixDQUFDLE1BQXlCO0lBQ2xELElBQUksQ0FBQyxNQUFNO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFFOUIsT0FBTztRQUNMLFVBQVUsRUFBRSxNQUFNLENBQUMsU0FBUztRQUM1QixXQUFXLEVBQUUsTUFBTSxDQUFDLFdBQVc7UUFDL0IsS0FBSyxFQUFFLE1BQU0sQ0FBQyxJQUFJO1FBQ2xCLEtBQUssRUFBRSxNQUFNLENBQUMsSUFBSTtRQUNsQixrQkFBa0IsRUFBRSxNQUFNLENBQUMsaUJBQWlCO0tBQzdDLENBQUM7QUFDSixDQUFDO0FBRUQsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztBQUVqQyxzREFBc0Q7QUFDdEQsU0FBUyxNQUFNLENBQUMsSUFBWSxFQUFFLE9BQWUsRUFBRSxNQUEyQjtJQUN4RSxJQUFJLE1BQU07UUFBRSxNQUFNLElB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O1lBQ2hCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3hDLENBQUM7UUFDRCxPQUFPLENBQUMsbUJBQW1CLENBQUMsQ0FBQztJQUMvQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxVQUFVLENBQUMsT0FBMEI7UUFDbkMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3pCLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDMUUsT0FBTztZQUNMLFNBQVM7WUFDVCxjQUFjLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEtBQUs7U0FDbkMsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWM7UUFDWixPQUFPLElBQUksQ0FBQyxNQUFNLEtBQUssSUFBSSxDQUFDO0lBQzlCLENBQUM7Q0FDRjtBQTFVRCx3QkEwVUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFJ1dkxMTSBFbmdpbmUgLSBNYWluIG9yY2hlc3RyYXRvciBmb3Igc2VsZi1sZWFybmluZyBMTE1cbiAqL1xuXG5pbXBvcnQge1xuICBSdXZMTE1Db25maWcsXG4gIEdlbmVyYXRpb25Db25maWcsXG4gIFF1ZXJ5UmVzcG9uc2UsXG4gIFJvdXRpbmdEZWNpc2lvbixcbiAgTWVtb3J5UmVzdWx0LFxuICBNZW1vcnlJZCxcbiAgUnV2TExNU3RhdHMsXG4gIEZlZWRiYWNrLFxuICBFbWJlZGRpbmcsXG4gIEJhdGNoUXVlcnlSZXF1ZXN0LFxuICBCYXRjaFF1ZXJ5UmVzcG9uc2UsXG59IGZyb20gJy4vdHlwZXMnO1xuXG5pbXBvcnQge1xuICBnZXROYXRpdmVNb2R1bGUsXG4gIE5hdGl2ZUVuZ2luZSxcbiAgTmF0aXZlQ29uZmlnLFxuICBOYXRpdmVHZW5Db25maWcsXG59IGZyb20gJy4vbmF0aXZlJztcblxuLyoqXG4gKiBDb252ZXJ0IEpTIGNvbmZpZyB0byBuYXRpdmUgY29uZmlnIGZvcm1hdFxuICovXG5mdW5jdGlvbiB0b05hdGl2ZUNvbmZpZyhjb25maWc/OiBSdXZMTE1Db25maWcpOiBOYXRpdmVDb25maWcgfCB1bmRlZmluZWQge1xuICBpZiAoIWNvbmZpZykgcmV0dXJuIHVuZGVmaW5lZDtcblxuICByZXR1cm4ge1xuICAgIGVtYmVkZGluZ19kaW06IGNvbmZpZy5lbWJlZGRpbmdEaW0sXG4gICAgcm91dGVyX2hpZGRlbl9kaW06IGNvbmZpZy5yb3V0ZXJIaWRkZW5EaW0sXG4gICAgaG5zd19tOiBjb25maWcuaG5zd00sXG4gICAgaG5zd19lZl9jb25zdHJ1Y3Rpb246IGNvbmZpZy5obnN3RWZDb25zdHJ1Y3Rpb24sXG4gICAgaG5zd19lZl9zZWFyY2g6IGNvbmZpZy5obnN3RWZTZWFyY2gsXG4gICAgbGVhcm5pbmdfZW5hYmxlZDogY29uZmlnLmxlYXJuaW5nRW5hYmxlZCxcbiAgICBxdWFsaXR5X3RocmVzaG9sZDogY29uZmlnLnF1YWxpdHlUaHJlc2hvbGQsXG4gICAgZXdjX2xhbWJkYTogY29uZmlnLmV3Y0xhbWJkYSxcbiAgfTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IEpTIGdlbmVyYXRpb24gY29uZmlnIHRvIG5hdGl2ZSBmb3JtYXRcbiAqL1xuZnVuY3Rpb24gdG9OYXRpdmVHZW5Db25maWcoY29uZmlnPzogR2VuZXJhdGlvbkNvbmZpZyk6IE5hdGl2ZUdlbkNvbmZpZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghY29uZmlnKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIHJldHVybiB7XG4gICAgbWF4X3Rva2VuczogY29uZmlnLm1heFRva2VucyxcbiAgICB0ZW1wZXJhdHVyZTogY29uZmlnLnRlbXBlcmF0dXJlLFxuICAgIHRvcF9wOiBjb25maWcudG9wUCxcbiAgICB0b3BfazogY29uZmlnLnRvcEssXG4gICAgcmVwZXRpdGlvbl9wZW5hbHR5OiBjb25maWcucmVwZXRpdGlvblBlbmFsdHksXG4gIH07XG59XG5cbmNvbnN0IHdhcm5lZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4vKiogV2FybiBvbmNlIHBlciBwcm9jZXNzIChvciB0aHJvdyB3aGVuIGBzdHJpY3RgKS4gKi9cbmZ1bmN0aW9uIG5vdGljZShjb2RlOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZywgc3RyaWN0OiBib29sZWFuIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gIGlmIChzdHJpY3QpIHRocm93IG5ldyBFcnJvcihgJHtjb2RlfTogJHttZXNzYWdlfWApO1xuICBpZiAod2FybmVkLmhhcyhjb2RlKSkgcmV0dXJuO1xuICB3YXJuZWQuYWRkKGNvZGUpO1xuICBjb25zdCBnID0gZ2xvYmFsVGhpcyBhcyB1bmtub3duIGFzIHtcbiAgICBwcm9jZXNzPzogeyBlbWl0V2FybmluZz86IChtOiBzdHJpbmcsIG8/OiB7IGNvZGU/OiBzdHJpbmcgfSkgPT4gdm9pZCB9O1xuICAgIGNvbnNvbGU/OiB7IHdhcm4/OiAobTogc3RyaW5nKSA9PiB2b2lkIH07XG4gIH07XG4gIGlmICh0eXBlb2YgZy5wcm9jZXNzPy5lbWl0V2FybmluZyA9PT0gJ2Z1bmN0aW9uJykgZy5wcm9jZXNzLmVtaXRXYXJuaW5nKG1lc3NhZ2UsIHsgY29kZSB9KTtcbiAgZWxzZSBnLmNvbnNvbGU/Lndhcm4/LihgJHtjb2RlfTogJHttZXNzYWdlfWApO1xufVxuXG5jb25zdCBOT19MTV9NRVNTQUdFID1cbiAgJ3RoZSBuYXRpdmUgUnV2TExNIGVuZ2luZSBoYXMgbm8gbGFuZ3VhZ2UtbW9kZWwgd2VpZ2h0cywgc28gZ2VuZXJhdGUoKS9xdWVyeSgpIHRleHQgaXMgJyArXG4gICdub3QgbW9kZWwgb3V0cHV0LiBGb3IgR0dVRiBpbmZlcmVuY2UgdXNlIHRoZSBydXZsbG0gQ0xJIChgcnV2bGxtIHNlcnZlIDxtb2RlbD4gLS1zdHJpY3RgKSAnICtcbiAgJ29yIGFub3RoZXIgT3BlbkFJLWNvbXBhdGlibGUgc2VydmVyLiBSb3V0aW5nLCBtZW1vcnkgYW5kIGVtYmVkZGluZ3MgYXJlIHVuYWZmZWN0ZWQuICcgK1xuICAnUGFzcyB7IHN0cmljdDogdHJ1ZSB9IHRvIHRocm93IGluc3RlYWQuJztcblxuLyoqXG4gKiBSdXZMTE0gLSBTZWxmLWxlYXJuaW5nIExMTSBvcmNoZXN0cmF0b3JcbiAqXG4gKiBDb21iaW5lcyBTT05BIGFkYXB0aXZlIGxlYXJuaW5nIHdpdGggSE5TVyBtZW1vcnksXG4gKiBGYXN0R1JOTiByb3V0aW5nLCBhbmQgU0lNRC1vcHRpbWl6ZWQgaW5mZXJlbmNlLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBSdXZMTE0gfSBmcm9tICdAcnV2ZWN0b3IvcnV2bGxtJztcbiAqXG4gKiBjb25zdCBsbG0gPSBuZXcgUnV2TExNKHsgZW1iZWRkaW5nRGltOiA3NjggfSk7XG4gKlxuICogLy8gUXVlcnkgd2l0aCBhdXRvbWF0aWMgcm91dGluZ1xuICogY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBsbG0ucXVlcnkoJ1doYXQgaXMgbWFjaGluZSBsZWFybmluZz8nKTtcbiAqIGNvbnNvbGUubG9nKHJlc3BvbnNlLnRleHQpO1xuICpcbiAqIC8vIFByb3ZpZGUgZmVlZGJhY2sgZm9yIGxlYXJuaW5nXG4gKiBsbG0uZmVlZGJhY2soeyByZXF1ZXN0SWQ6IHJlc3BvbnNlLnJlcXVlc3RJZCwgcmF0aW5nOiA1IH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBSdXZMTE0ge1xuICBwcml2YXRlIG5hdGl2ZTogTmF0aXZlRW5naW5lIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgY29uZmlnOiBSdXZMTE1Db25maWc7XG5cbiAgLy8gRmFsbGJhY2sgc3RhdGUgZm9yIHdoZW4gbmF0aXZlIG1vZHVsZSBpcyBub3QgYXZhaWxhYmxlXG4gIHByaXZhdGUgZmFsbGJhY2tTdGF0ZSA9IHtcbiAgICBtZW1vcnk6IG5ldyBNYXA8bnVtYmVyLCB7IGNvbnRlbnQ6IHN0cmluZzsgZW1iZWRkaW5nOiBudW1iZXJbXTsgbWV0YWRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IH0+KCksXG4gICAgbmV4dElkOiAxLFxuICAgIHF1ZXJ5Q291bnQ6IDAsXG4gIH07XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyBSdXZMTE0gaW5zdGFuY2VcbiAgICovXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IFJ1dkxMTUNvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnID8/IHt9O1xuICAgIGNvbnN0IGV4dHJhID0gdGhpcy5jb25maWcgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgZm9yIChjb25zdCBrZXkgb2YgWydtb2RlbFBhdGgnLCAnYmFja2VuZCddKSB7XG4gICAgICBpZiAoZXh0cmFba2V5XSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIG5vdGljZShcbiAgICAgICAgICAnUlVWTExNX1VOU1VQUE9SVEVEX09QVElPTicsXG4gICAgICAgICAgYFxcYCR7a2V5fVxcYCBpcyBub3Qgc3VwcG9ydGVkIGJ5IEBydXZlY3Rvci9ydXZsbG0gYW5kIGlzIGlnbm9yZWQ6IHRoaXMgcGFja2FnZSBkb2VzIG5vdCBgICtcbiAgICAgICAgICAgICdsb2FkIG1vZGVsIGZpbGVzLiBGb3IgR0dVRiBpbmZlcmVuY2UgdXNlIHRoZSBydXZsbG0gQ0xJIChgcnV2bGxtIHNlcnZlIDxtb2RlbD4gLS1zdHJpY3RgKS4nLFxuICAgICAgICAgIHRoaXMuY29uZmlnLnN0cmljdCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBtb2QgPSBnZXROYXRpdmVNb2R1bGUoKTtcbiAgICBpZiAobW9kKSB7XG4gICAgICB0cnkge1xuICAgICAgICB0aGlzLm5hdGl2ZSA9IG5ldyBtb2QuUnV2TExNRW5naW5lKHRvTmF0aXZlQ29uZmlnKGNvbmZpZykpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIFNpbGVudGx5IGZhbGwgYmFjayB0byBKUyBpbXBsZW1lbnRhdGlvblxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBRdWVyeSB0aGUgTExNIHdpdGggYXV0b21hdGljIHJvdXRpbmdcbiAgICovXG4gIHF1ZXJ5KHRleHQ6IHN0cmluZywgY29uZmlnPzogR2VuZXJhdGlvbkNvbmZpZyk6IFF1ZXJ5UmVzcG9uc2Uge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgbm90aWNlKCdSVVZMTE1fTk9fTEFOR1VBR0VfTU9ERUwnLCBOT19MTV9NRVNTQUdFLCB0aGlzLmNvbmZpZy5zdHJpY3QpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy5uYXRpdmUucXVlcnkodGV4dCwgdG9OYXRpdmVHZW5Db25maWcoY29uZmlnKSk7XG4gICAgICAvLyBuYXBpLXJzIGNhbWVsQ2FzZXMgUnVzdCBmaWVsZCBuYW1lcyBvbiB0aGUgd2F5IG91dCwgc28gdGhlIG5hdGl2ZVxuICAgICAgLy8gb2JqZWN0IGNhcnJpZXMgYGNvbnRleHRTaXplYC9gbGF0ZW5jeU1zYC9gcmVxdWVzdElkYC4gVGhlIHNuYWtlX2Nhc2VcbiAgICAgIC8vIHJlYWRzIGFyZSBrZXB0IGFzIGEgZmFsbGJhY2sgZm9yIG9sZGVyIG5hdGl2ZSBidWlsZHMuXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0ZXh0OiByZXN1bHQudGV4dCxcbiAgICAgICAgY29uZmlkZW5jZTogcmVzdWx0LmNvbmZpZGVuY2UsXG4gICAgICAgIG1vZGVsOiByZXN1bHQubW9kZWwsXG4gICAgICAgIGNvbnRleHRTaXplOiByZXN1bHQuY29udGV4dFNpemUgPz8gcmVzdWx0LmNvbnRleHRfc2l6ZSxcbiAgICAgICAgbGF0ZW5jeU1zOiByZXN1bHQubGF0ZW5jeU1zID8/IHJlc3VsdC5sYXRlbmN5X21zLFxuICAgICAgICByZXF1ZXN0SWQ6IHJlc3VsdC5yZXF1ZXN0SWQgPz8gcmVzdWx0LnJlcXVlc3RfaWQsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrIGltcGxlbWVudGF0aW9uXG4gICAgdGhpcy5mYWxsYmFja1N0YXRlLnF1ZXJ5Q291bnQrKztcbiAgICByZXR1cm4ge1xuICAgICAgdGV4dDogYFtGYWxsYmFja10gUmVzcG9uc2UgdG86ICR7dGV4dC5zbGljZSgwLCA1MCl9Li4uYCxcbiAgICAgIGNvbmZpZGVuY2U6IDAuNSxcbiAgICAgIG1vZGVsOiAnZmFsbGJhY2snLFxuICAgICAgY29udGV4dFNpemU6IDUxMixcbiAgICAgIGxhdGVuY3lNczogMS4wLFxuICAgICAgcmVxdWVzdElkOiBgZmItJHtEYXRlLm5vdygpfS0ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIpfWAsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSB0ZXh0IHdpdGggU0lNRC1vcHRpbWl6ZWQgaW5mZXJlbmNlXG4gICAqXG4gICAqIE5vdGU6IHRoZSBuYXRpdmUgZW5naW5lIGhhcyBubyBsYW5ndWFnZS1tb2RlbCB3ZWlnaHRzLCBzbyBpdHMgdGV4dCBpc1xuICAgKiBub3QgbW9kZWwgb3V0cHV0OyB0aGUgZmlyc3QgY2FsbCBlbWl0cyBhIGBSVVZMTE1fTk9fTEFOR1VBR0VfTU9ERUxgXG4gICAqIHdhcm5pbmcgKG9yIHRocm93cyB3aXRoIGBzdHJpY3Q6IHRydWVgKS4gV2l0aG91dCB0aGUgbmF0aXZlIG1vZHVsZSB0aGlzXG4gICAqIHJldHVybnMgYW4gaW5mb3JtYXRpb25hbCBtZXNzYWdlLlxuICAgKi9cbiAgZ2VuZXJhdGUocHJvbXB0OiBzdHJpbmcsIGNvbmZpZz86IEdlbmVyYXRpb25Db25maWcpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgbm90aWNlKCdSVVZMTE1fTk9fTEFOR1VBR0VfTU9ERUwnLCBOT19MTV9NRVNTQUdFLCB0aGlzLmNvbmZpZy5zdHJpY3QpO1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLmdlbmVyYXRlKHByb21wdCwgdG9OYXRpdmVHZW5Db25maWcoY29uZmlnKSk7XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2sgLSBwcm92aWRlIGhlbHBmdWwgbWVzc2FnZSBpbnN0ZWFkIG9mIGdhcmJsZWQgb3V0cHV0XG4gICAgY29uc3QgbWF4VG9rZW5zID0gY29uZmlnPy5tYXhUb2tlbnMgPz8gMjU2O1xuICAgIGNvbnN0IHRlbXAgPSBjb25maWc/LnRlbXBlcmF0dXJlID8/IDAuNztcbiAgICBjb25zdCB0b3BQID0gY29uZmlnPy50b3BQID8/IDAuOTtcblxuICAgIHJldHVybiBgW1J1dkxMTSBKYXZhU2NyaXB0IEZhbGxiYWNrIE1vZGVdXG5ObyBuYXRpdmUgU0lNRCBtb2R1bGUgbG9hZGVkLiBSdW5uaW5nIGluIEphdmFTY3JpcHQgZmFsbGJhY2sgbW9kZS5cblxuWW91ciBwcm9tcHQ6IFwiJHtwcm9tcHQuc2xpY2UoMCwgMTAwKX0ke3Byb21wdC5sZW5ndGggPiAxMDAgPyAnLi4uJyA6ICcnfVwiXG5cblRvIGVuYWJsZSBuYXRpdmUgU0lNRCBpbmZlcmVuY2U6XG4xLiBJbnN0YWxsIHRoZSBuYXRpdmUgYmluZGluZ3M6IG5wbSBpbnN0YWxsIEBydXZlY3Rvci9ydXZsbG0tJHtwcm9jZXNzLnBsYXRmb3JtfS0ke3Byb2Nlc3MuYXJjaH1cbjIuIE9yIGxvYWQgYSBHR1VGIG1vZGVsIGZpbGVcbjMuIE9yIGNvbm5lY3QgdG8gYW4gZXh0ZXJuYWwgTExNIEFQSVxuXG5Db25maWc6IHRlbXA9JHt0ZW1wLnRvRml4ZWQoMil9LCB0b3BfcD0ke3RvcFAudG9GaXhlZCgyKX0sIG1heF90b2tlbnM9JHttYXhUb2tlbnN9XG5cblRoaXMgZmFsbGJhY2sgcHJvdmlkZXMgcm91dGluZywgbWVtb3J5LCBhbmQgZW1iZWRkaW5nIGZlYXR1cmVzIGJ1dCBub3QgZnVsbCB0ZXh0IGdlbmVyYXRpb24uYDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgcm91dGluZyBkZWNpc2lvbiBmb3IgYSBxdWVyeVxuICAgKi9cbiAgcm91dGUodGV4dDogc3RyaW5nKTogUm91dGluZ0RlY2lzaW9uIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMubmF0aXZlLnJvdXRlKHRleHQpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbW9kZWw6IHJlc3VsdC5tb2RlbCBhcyBhbnksXG4gICAgICAgIGNvbnRleHRTaXplOiByZXN1bHQuY29udGV4dFNpemUgPz8gcmVzdWx0LmNvbnRleHRfc2l6ZSxcbiAgICAgICAgdGVtcGVyYXR1cmU6IHJlc3VsdC50ZW1wZXJhdHVyZSxcbiAgICAgICAgdG9wUDogcmVzdWx0LnRvcFAgPz8gcmVzdWx0LnRvcF9wLFxuICAgICAgICBjb25maWRlbmNlOiByZXN1bHQuY29uZmlkZW5jZSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2tcbiAgICByZXR1cm4ge1xuICAgICAgbW9kZWw6ICdNNzAwJyxcbiAgICAgIGNvbnRleHRTaXplOiA1MTIsXG4gICAgICB0ZW1wZXJhdHVyZTogMC43LFxuICAgICAgdG9wUDogMC45LFxuICAgICAgY29uZmlkZW5jZTogMC41LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU2VhcmNoIG1lbW9yeSBmb3Igc2ltaWxhciBjb250ZW50XG4gICAqL1xuICBzZWFyY2hNZW1vcnkodGV4dDogc3RyaW5nLCBrID0gMTApOiBNZW1vcnlSZXN1bHRbXSB7XG4gICAgaWYgKHRoaXMubmF0aXZlKSB7XG4gICAgICBjb25zdCByZXN1bHRzID0gdGhpcy5uYXRpdmUuc2VhcmNoTWVtb3J5KHRleHQsIGspO1xuICAgICAgcmV0dXJuIHJlc3VsdHMubWFwKHIgPT4ge1xuICAgICAgICAvLyBUaGUgbmF0aXZlIHNpZGUgcmVwb3J0cyBgZGlzdGFuY2VgIChzbWFsbGVyIGlzIGNsb3NlcikuIE1lbW9yeVJlc3VsdFxuICAgICAgICAvLyBkb2N1bWVudHMgYHNjb3JlYCBhcyBhIHNpbWlsYXJpdHksIHNvIGNvbnZlcnQgcmF0aGVyIHRoYW4gcGFzc2luZyBhXG4gICAgICAgIC8vIGRpc3RhbmNlIHRocm91Z2ggdW5kZXIgYSBzaW1pbGFyaXR5J3MgbmFtZS4gT2xkZXIgYnVpbGRzIHRoYXQgYWxyZWFkeVxuICAgICAgICAvLyBlbWl0IGBzY29yZWAgYXJlIHVzZWQgYXMtaXMuXG4gICAgICAgIGNvbnN0IGFueVIgPSByIGFzIGFueTtcbiAgICAgICAgY29uc3Qgc2NvcmUgPVxuICAgICAgICAgIHR5cGVvZiBhbnlSLnNjb3JlID09PSAnbnVtYmVyJ1xuICAgICAgICAgICAgPyBhbnlSLnNjb3JlXG4gICAgICAgICAgICA6IHR5cGVvZiBhbnlSLmRpc3RhbmNlID09PSAnbnVtYmVyJ1xuICAgICAgICAgICAgICA/IDEgLyAoMSArIE1hdGgubWF4KDAsIGFueVIuZGlzdGFuY2UpKVxuICAgICAgICAgICAgICA6IDA7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgaWQ6IHIuaWQsXG4gICAgICAgICAgc2NvcmUsXG4gICAgICAgICAgY29udGVudDogci5jb250ZW50LFxuICAgICAgICAgIG1ldGFkYXRhOiBKU09OLnBhcnNlKHIubWV0YWRhdGEgfHwgJ3t9JyksXG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBGYWxsYmFjayAtIHNpbXBsZSBzZWFyY2hcbiAgICByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmZhbGxiYWNrU3RhdGUubWVtb3J5LmVudHJpZXMoKSlcbiAgICAgIC5zbGljZSgwLCBrKVxuICAgICAgLm1hcCgoW2lkLCBkYXRhXSkgPT4gKHtcbiAgICAgICAgaWQsXG4gICAgICAgIHNjb3JlOiAwLjUsXG4gICAgICAgIGNvbnRlbnQ6IGRhdGEuY29udGVudCxcbiAgICAgICAgbWV0YWRhdGE6IGRhdGEubWV0YWRhdGEsXG4gICAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGNvbnRlbnQgdG8gbWVtb3J5XG4gICAqL1xuICBhZGRNZW1vcnkoY29udGVudDogc3RyaW5nLCBtZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogTWVtb3J5SWQge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLmFkZE1lbW9yeShjb250ZW50LCBtZXRhZGF0YSA/IEpTT04uc3RyaW5naWZ5KG1ldGFkYXRhKSA6IHVuZGVmaW5lZCk7XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2tcbiAgICBjb25zdCBpZCA9IHRoaXMuZmFsbGJhY2tTdGF0ZS5uZXh0SWQrKztcbiAgICB0aGlzLmZhbGxiYWNrU3RhdGUubWVtb3J5LnNldChpZCwge1xuICAgICAgY29udGVudCxcbiAgICAgIGVtYmVkZGluZzogdGhpcy5lbWJlZChjb250ZW50KSxcbiAgICAgIG1ldGFkYXRhOiBtZXRhZGF0YSA/PyB7fSxcbiAgICB9KTtcbiAgICByZXR1cm4gaWQ7XG4gIH1cblxuICAvKipcbiAgICogUHJvdmlkZSBmZWVkYmFjayBmb3IgbGVhcm5pbmdcbiAgICovXG4gIGZlZWRiYWNrKGZiOiBGZWVkYmFjayk6IGJvb2xlYW4ge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLmZlZWRiYWNrKGZiLnJlcXVlc3RJZCwgZmIucmF0aW5nLCBmYi5jb3JyZWN0aW9uKTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBlbmdpbmUgc3RhdGlzdGljc1xuICAgKi9cbiAgc3RhdHMoKTogUnV2TExNU3RhdHMge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgY29uc3QgcyA9IHRoaXMubmF0aXZlLnN0YXRzKCk7XG4gICAgICAvLyBNYXAgbmF0aXZlIHN0YXRzIChzbmFrZV9jYXNlKSB0byBUeXBlU2NyaXB0IGludGVyZmFjZSAoY2FtZWxDYXNlKVxuICAgICAgLy8gSGFuZGxlIGJvdGggb2xkIGFuZCBuZXcgZmllbGQgbmFtZXMgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHlcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRvdGFsUXVlcmllczogKHMgYXMgYW55KS50b3RhbFF1ZXJpZXMgPz8gcy50b3RhbF9xdWVyaWVzID8/IDAsXG4gICAgICAgIG1lbW9yeU5vZGVzOiAocyBhcyBhbnkpLm1lbW9yeU5vZGVzID8/IHMubWVtb3J5X25vZGVzID8/IDAsXG4gICAgICAgIHBhdHRlcm5zTGVhcm5lZDpcbiAgICAgICAgICAocyBhcyBhbnkpLnRyYWluaW5nU3RlcHMgPz9cbiAgICAgICAgICBzLnBhdHRlcm5zX2xlYXJuZWQgPz9cbiAgICAgICAgICAocyBhcyBhbnkpLnRyYWluaW5nX3N0ZXBzID8/XG4gICAgICAgICAgMCxcbiAgICAgICAgYXZnTGF0ZW5jeU1zOiAocyBhcyBhbnkpLmF2Z0xhdGVuY3lNcyA/PyBzLmF2Z19sYXRlbmN5X21zID8/IDAsXG4gICAgICAgIGNhY2hlSGl0UmF0ZTogKHMgYXMgYW55KS5jYWNoZUhpdFJhdGUgPz8gcy5jYWNoZV9oaXRfcmF0ZSA/PyAwLFxuICAgICAgICByb3V0ZXJBY2N1cmFjeTogKHMgYXMgYW55KS5yb3V0ZXJBY2N1cmFjeSA/PyBzLnJvdXRlcl9hY2N1cmFjeSA/PyAwLjUsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrXG4gICAgcmV0dXJuIHtcbiAgICAgIHRvdGFsUXVlcmllczogdGhpcy5mYWxsYmFja1N0YXRlLnF1ZXJ5Q291bnQsXG4gICAgICBtZW1vcnlOb2RlczogdGhpcy5mYWxsYmFja1N0YXRlLm1lbW9yeS5zaXplLFxuICAgICAgcGF0dGVybnNMZWFybmVkOiAwLFxuICAgICAgYXZnTGF0ZW5jeU1zOiAxLjAsXG4gICAgICBjYWNoZUhpdFJhdGU6IDAuMCxcbiAgICAgIHJvdXRlckFjY3VyYWN5OiAwLjUsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JjZSByb3V0ZXIgbGVhcm5pbmcgY3ljbGVcbiAgICovXG4gIGZvcmNlTGVhcm4oKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIHJldHVybiB0aGlzLm5hdGl2ZS5mb3JjZUxlYXJuKCk7XG4gICAgfVxuICAgIHJldHVybiAnTGVhcm5pbmcgbm90IGF2YWlsYWJsZSBpbiBmYWxsYmFjayBtb2RlJztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZW1iZWRkaW5nIGZvciB0ZXh0XG4gICAqL1xuICBlbWJlZCh0ZXh0OiBzdHJpbmcpOiBFbWJlZGRpbmcge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLmVtYmVkKHRleHQpO1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrIC0gc2ltcGxlIGhhc2gtYmFzZWQgZW1iZWRkaW5nXG4gICAgY29uc3QgZGltID0gdGhpcy5jb25maWcuZW1iZWRkaW5nRGltID8/IDc2ODtcbiAgICBjb25zdCBlbWJlZGRpbmcgPSBuZXcgQXJyYXkoZGltKS5maWxsKDApO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0ZXh0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBpZHggPSAodGV4dC5jaGFyQ29kZUF0KGkpICogKGkgKyAxKSkgJSBkaW07XG4gICAgICBlbWJlZGRpbmdbaWR4XSArPSAwLjE7XG4gICAgfVxuXG4gICAgLy8gTm9ybWFsaXplXG4gICAgY29uc3Qgbm9ybSA9IE1hdGguc3FydChlbWJlZGRpbmcucmVkdWNlKChzdW0sIHgpID0+IHN1bSArIHggKiB4LCAwKSkgfHwgMTtcbiAgICByZXR1cm4gZW1iZWRkaW5nLm1hcCh4ID0+IHggLyBub3JtKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb21wdXRlIHNpbWlsYXJpdHkgYmV0d2VlbiB0d28gdGV4dHNcbiAgICovXG4gIHNpbWlsYXJpdHkodGV4dDE6IHN0cmluZywgdGV4dDI6IHN0cmluZyk6IG51bWJlciB7XG4gICAgaWYgKHRoaXMubmF0aXZlKSB7XG4gICAgICAvLyBmMzIgYWNjdW11bGF0aW9uIGNhbiBsYW5kIGp1c3Qgb3V0c2lkZSB0aGUgbWF0aGVtYXRpY2FsIHJhbmdlIOKAlCBhblxuICAgICAgLy8gaWRlbnRpY2FsIHBhaXIgbWVhc3VyZXMgMS4wMDAwMDAxIOKAlCB3aGljaCB0dXJucyBNYXRoLmFjb3Moc2ltKSBpbnRvXG4gICAgICAvLyBOYU4gZG93bnN0cmVhbS4gQ29zaW5lIHNpbWlsYXJpdHkgaXMgZGVmaW5lZCBvbiBbLTEsIDFdLCBzbyBjbGFtcC5cbiAgICAgIGNvbnN0IHJhdyA9IHRoaXMubmF0aXZlLnNpbWlsYXJpdHkodGV4dDEsIHRleHQyKTtcbiAgICAgIHJldHVybiBNYXRoLm1pbigxLCBNYXRoLm1heCgtMSwgcmF3KSk7XG4gICAgfVxuXG4gICAgLy8gRmFsbGJhY2sgLSBjb3NpbmUgc2ltaWxhcml0eVxuICAgIGNvbnN0IGVtYjEgPSB0aGlzLmVtYmVkKHRleHQxKTtcbiAgICBjb25zdCBlbWIyID0gdGhpcy5lbWJlZCh0ZXh0Mik7XG5cbiAgICBsZXQgZG90ID0gMDtcbiAgICBsZXQgbm9ybTEgPSAwO1xuICAgIGxldCBub3JtMiA9IDA7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGVtYjEubGVuZ3RoOyBpKyspIHtcbiAgICAgIGRvdCArPSBlbWIxW2ldICogZW1iMltpXTtcbiAgICAgIG5vcm0xICs9IGVtYjFbaV0gKiBlbWIxW2ldO1xuICAgICAgbm9ybTIgKz0gZW1iMltpXSAqIGVtYjJbaV07XG4gICAgfVxuXG4gICAgY29uc3QgZGVub20gPSBNYXRoLnNxcnQobm9ybTEpICogTWF0aC5zcXJ0KG5vcm0yKTtcbiAgICBjb25zdCBzaW1pbGFyaXR5ID0gZGVub20gPiAwID8gZG90IC8gZGVub20gOiAwO1xuICAgIC8vIENsYW1wIHRvIFswLCAxXSB0byBoYW5kbGUgZmxvYXRpbmcgcG9pbnQgZXJyb3JzXG4gICAgcmV0dXJuIE1hdGgubWF4KDAsIE1hdGgubWluKDEsIHNpbWlsYXJpdHkpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiBTSU1EIGlzIGF2YWlsYWJsZVxuICAgKi9cbiAgaGFzU2ltZCgpOiBib29sZWFuIHtcbiAgICBpZiAodGhpcy5uYXRpdmUpIHtcbiAgICAgIHJldHVybiB0aGlzLm5hdGl2ZS5oYXNTaW1kKCk7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgU0lNRCBjYXBhYmlsaXRpZXNcbiAgICovXG4gIHNpbWRDYXBhYmlsaXRpZXMoKTogc3RyaW5nW10ge1xuICAgIGlmICh0aGlzLm5hdGl2ZSkge1xuICAgICAgcmV0dXJuIHRoaXMubmF0aXZlLnNpbWRDYXBhYmlsaXRpZXMoKTtcbiAgICB9XG4gICAgcmV0dXJuIFsnU2NhbGFyIChmYWxsYmFjayknXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCYXRjaCBxdWVyeSBtdWx0aXBsZSBwcm9tcHRzXG4gICAqL1xuICBiYXRjaFF1ZXJ5KHJlcXVlc3Q6IEJhdGNoUXVlcnlSZXF1ZXN0KTogQmF0Y2hRdWVyeVJlc3BvbnNlIHtcbiAgICBjb25zdCBzdGFydCA9IERhdGUubm93KCk7XG4gICAgY29uc3QgcmVzcG9uc2VzID0gcmVxdWVzdC5xdWVyaWVzLm1hcChxID0+IHRoaXMucXVlcnkocSwgcmVxdWVzdC5jb25maWcpKTtcbiAgICByZXR1cm4ge1xuICAgICAgcmVzcG9uc2VzLFxuICAgICAgdG90YWxMYXRlbmN5TXM6IERhdGUubm93KCkgLSBzdGFydCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIG5hdGl2ZSBtb2R1bGUgaXMgbG9hZGVkXG4gICAqL1xuICBpc05hdGl2ZUxvYWRlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5uYXRpdmUgIT09IG51bGw7XG4gIH1cbn1cbiJdfQ==