@ruvector/ruvllm 0.2.3 → 2.4.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.
- package/README.md +379 -739
- package/bin/cli.js +619 -2
- package/dist/cjs/benchmarks/embedding-benchmark.d.ts +102 -0
- package/dist/cjs/benchmarks/embedding-benchmark.d.ts.map +1 -0
- package/dist/cjs/benchmarks/embedding-benchmark.js +436 -0
- package/dist/cjs/benchmarks/index.d.ts +34 -0
- package/dist/cjs/benchmarks/index.d.ts.map +1 -0
- package/dist/cjs/benchmarks/index.js +132 -0
- package/dist/cjs/benchmarks/model-comparison.d.ts +71 -0
- package/dist/cjs/benchmarks/model-comparison.d.ts.map +1 -0
- package/dist/cjs/benchmarks/model-comparison.js +476 -0
- package/dist/cjs/benchmarks/routing-benchmark.d.ts +70 -0
- package/dist/cjs/benchmarks/routing-benchmark.d.ts.map +1 -0
- package/dist/cjs/benchmarks/routing-benchmark.js +289 -0
- package/dist/cjs/contrastive.d.ts +229 -0
- package/dist/cjs/contrastive.d.ts.map +1 -0
- package/dist/cjs/contrastive.js +589 -0
- package/dist/cjs/engine.d.ts +3 -0
- package/dist/cjs/engine.d.ts.map +1 -1
- package/dist/cjs/engine.js +29 -9
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +9 -1
- package/dist/cjs/models.d.ts +129 -0
- package/dist/cjs/models.d.ts.map +1 -0
- package/dist/cjs/models.js +323 -0
- package/dist/cjs/rlm/controller.d.ts +245 -0
- package/dist/cjs/rlm/controller.d.ts.map +1 -0
- package/dist/cjs/rlm/controller.js +554 -0
- package/dist/cjs/rlm/index.d.ts +62 -0
- package/dist/cjs/rlm/index.d.ts.map +1 -0
- package/dist/cjs/rlm/index.js +97 -0
- package/dist/cjs/rlm/training.d.ts +333 -0
- package/dist/cjs/rlm/training.d.ts.map +1 -0
- package/dist/cjs/rlm/training.js +680 -0
- package/dist/cjs/rlm/types.d.ts +189 -0
- package/dist/cjs/rlm/types.d.ts.map +1 -0
- package/dist/cjs/rlm/types.js +10 -0
- package/dist/esm/benchmarks/embedding-benchmark.d.ts +102 -0
- package/dist/esm/benchmarks/embedding-benchmark.d.ts.map +1 -0
- package/dist/esm/benchmarks/embedding-benchmark.js +427 -0
- package/dist/esm/benchmarks/index.d.ts +34 -0
- package/dist/esm/benchmarks/index.d.ts.map +1 -0
- package/dist/esm/benchmarks/index.js +110 -0
- package/dist/esm/benchmarks/model-comparison.d.ts +71 -0
- package/dist/esm/benchmarks/model-comparison.d.ts.map +1 -0
- package/dist/esm/benchmarks/model-comparison.js +434 -0
- package/dist/esm/benchmarks/routing-benchmark.d.ts +70 -0
- package/dist/esm/benchmarks/routing-benchmark.d.ts.map +1 -0
- package/dist/esm/benchmarks/routing-benchmark.js +283 -0
- package/dist/esm/contrastive.d.ts +229 -0
- package/dist/esm/contrastive.d.ts.map +1 -0
- package/dist/esm/contrastive.js +578 -0
- package/dist/esm/engine.d.ts +3 -0
- package/dist/esm/engine.d.ts.map +1 -1
- package/dist/esm/engine.js +29 -9
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +9 -1
- package/dist/esm/models.d.ts +129 -0
- package/dist/esm/models.d.ts.map +1 -0
- package/dist/esm/models.js +282 -0
- package/dist/esm/rlm/controller.d.ts +245 -0
- package/dist/esm/rlm/controller.d.ts.map +1 -0
- package/dist/esm/rlm/controller.js +550 -0
- package/dist/esm/rlm/index.d.ts +62 -0
- package/dist/esm/rlm/index.d.ts.map +1 -0
- package/dist/esm/rlm/index.js +71 -0
- package/dist/esm/rlm/training.d.ts +333 -0
- package/dist/esm/rlm/training.d.ts.map +1 -0
- package/dist/esm/rlm/training.js +672 -0
- package/dist/esm/rlm/types.d.ts +189 -0
- package/dist/esm/rlm/types.d.ts.map +1 -0
- package/dist/esm/rlm/types.js +9 -0
- package/package.json +13 -11
- package/scripts/ensemble-model-compare.js +287 -0
- package/scripts/huggingface/README.md +537 -0
- package/scripts/huggingface/publish.sh +112 -0
- package/scripts/hybrid-model-compare.js +373 -0
- package/scripts/improved-model-compare.js +288 -0
- package/scripts/optimized-model-compare.js +364 -0
- package/scripts/real-model-compare.js +280 -0
- package/scripts/training/agentic-flow-capabilities.json +329 -0
- package/scripts/training/claude-code-synth.js +505 -0
- package/scripts/training/claude-flow-capabilities.json +1322 -0
- package/scripts/training/claude-hard-negatives.js +222 -0
- package/scripts/training/contrastive-finetune.js +517 -0
- package/scripts/training/ecosystem-triplets.jsonl +1467 -0
- package/scripts/training/generate-ecosystem-triplets.js +1324 -0
- package/scripts/training/rlm-dataset.js +671 -0
- package/scripts/training/routing-dataset.js +634 -0
- package/scripts/training/ruvector-capabilities.json +798 -0
- package/scripts/training/validate-ecosystem.js +381 -0
- package/scripts/training/validation-results.json +23 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Hybrid Model Comparison
|
|
4
|
+
*
|
|
5
|
+
* Combines embedding similarity with keyword boosting.
|
|
6
|
+
* This addresses the "reviewer overfit" problem by:
|
|
7
|
+
* 1. Computing embedding similarity
|
|
8
|
+
* 2. Boosting agents that have keyword matches in the task
|
|
9
|
+
* 3. Using weighted combination for final score
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
const { existsSync } = require('fs');
|
|
14
|
+
const { join } = require('path');
|
|
15
|
+
const { homedir } = require('os');
|
|
16
|
+
|
|
17
|
+
const MODELS_DIR = join(homedir(), '.ruvllm', 'models');
|
|
18
|
+
const RUVLTRA_MODEL = join(MODELS_DIR, 'ruvltra-claude-code-0.5b-q4_k_m.gguf');
|
|
19
|
+
const QWEN_MODEL = join(MODELS_DIR, 'qwen2.5-0.5b-instruct-q4_k_m.gguf');
|
|
20
|
+
|
|
21
|
+
// V1 descriptions for embedding
|
|
22
|
+
const DESCRIPTIONS_V1 = {
|
|
23
|
+
coder: 'implement create write build add code function class component feature',
|
|
24
|
+
researcher: 'research find investigate analyze explore search discover examine',
|
|
25
|
+
reviewer: 'review check evaluate assess inspect examine code quality',
|
|
26
|
+
tester: 'test unit integration e2e coverage mock assertion spec',
|
|
27
|
+
architect: 'design architecture schema system structure plan database',
|
|
28
|
+
'security-architect': 'security vulnerability xss injection audit cve authentication',
|
|
29
|
+
debugger: 'debug fix bug error issue broken crash exception trace',
|
|
30
|
+
documenter: 'document readme jsdoc comment explain describe documentation',
|
|
31
|
+
refactorer: 'refactor extract rename consolidate clean restructure simplify',
|
|
32
|
+
optimizer: 'optimize performance slow fast cache speed memory latency',
|
|
33
|
+
devops: 'deploy ci cd kubernetes docker pipeline container infrastructure',
|
|
34
|
+
'api-docs': 'openapi swagger api documentation graphql schema endpoint',
|
|
35
|
+
planner: 'plan estimate prioritize sprint roadmap schedule milestone',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// UNIQUE trigger keywords - words that strongly indicate a specific agent
|
|
39
|
+
// Priority-ordered: first match wins for disambiguation
|
|
40
|
+
// NOTE: "investigate" takes priority over "slow" for researcher vs optimizer
|
|
41
|
+
const TRIGGER_KEYWORDS = {
|
|
42
|
+
// Higher priority agents (check these first)
|
|
43
|
+
researcher: ['research', 'investigate', 'explore', 'discover', 'best practices', 'patterns', 'analyze', 'look into', 'find out'],
|
|
44
|
+
coder: ['implement', 'build', 'create', 'component', 'function', 'typescript', 'react', 'feature', 'write code'],
|
|
45
|
+
tester: ['test', 'tests', 'testing', 'unit test', 'integration test', 'e2e', 'coverage', 'spec'],
|
|
46
|
+
reviewer: ['review', 'pull request', 'pr', 'code quality', 'code review', 'check code'],
|
|
47
|
+
debugger: ['debug', 'fix', 'bug', 'error', 'exception', 'crash', 'trace', 'null pointer', 'memory leak'],
|
|
48
|
+
'security-architect': ['security', 'vulnerability', 'xss', 'injection', 'csrf', 'cve', 'audit', 'exploit'],
|
|
49
|
+
refactorer: ['refactor', 'async/await', 'modernize', 'restructure', 'extract', 'legacy'],
|
|
50
|
+
// Optimizer: removed "slow" (too generic), added query-specific terms
|
|
51
|
+
optimizer: ['optimize', 'performance', 'cache', 'caching', 'speed up', 'latency', 'faster', 'queries', 'reduce time'],
|
|
52
|
+
architect: ['design', 'architecture', 'schema', 'structure', 'diagram', 'system design', 'plan architecture'],
|
|
53
|
+
documenter: ['jsdoc', 'comment', 'comments', 'readme', 'documentation', 'document', 'explain'],
|
|
54
|
+
devops: ['deploy', 'ci/cd', 'kubernetes', 'docker', 'pipeline', 'infrastructure', 'container'],
|
|
55
|
+
'api-docs': ['openapi', 'swagger', 'api doc', 'rest api', 'graphql', 'endpoint'],
|
|
56
|
+
planner: ['sprint', 'plan', 'roadmap', 'milestone', 'estimate', 'schedule', 'prioritize'],
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Priority order for disambiguation (when multiple agents match)
|
|
60
|
+
const AGENT_PRIORITY = [
|
|
61
|
+
'researcher', // "investigate" wins over "slow"
|
|
62
|
+
'debugger', // "fix" wins over generic terms
|
|
63
|
+
'tester', // "test" is specific
|
|
64
|
+
'security-architect',
|
|
65
|
+
'coder',
|
|
66
|
+
'reviewer',
|
|
67
|
+
'refactorer',
|
|
68
|
+
'optimizer',
|
|
69
|
+
'architect',
|
|
70
|
+
'documenter',
|
|
71
|
+
'devops',
|
|
72
|
+
'api-docs',
|
|
73
|
+
'planner',
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const ROUTING_TESTS = [
|
|
77
|
+
{ task: 'Implement a binary search function in TypeScript', expected: 'coder' },
|
|
78
|
+
{ task: 'Write unit tests for the authentication module', expected: 'tester' },
|
|
79
|
+
{ task: 'Review the pull request for security vulnerabilities', expected: 'reviewer' },
|
|
80
|
+
{ task: 'Research best practices for React state management', expected: 'researcher' },
|
|
81
|
+
{ task: 'Design the database schema for user profiles', expected: 'architect' },
|
|
82
|
+
{ task: 'Fix the null pointer exception in the login handler', expected: 'debugger' },
|
|
83
|
+
{ task: 'Audit the API endpoints for XSS vulnerabilities', expected: 'security-architect' },
|
|
84
|
+
{ task: 'Write JSDoc comments for the utility functions', expected: 'documenter' },
|
|
85
|
+
{ task: 'Refactor the payment module to use async/await', expected: 'refactorer' },
|
|
86
|
+
{ task: 'Optimize the database queries for the dashboard', expected: 'optimizer' },
|
|
87
|
+
{ task: 'Set up the CI/CD pipeline for the microservices', expected: 'devops' },
|
|
88
|
+
{ task: 'Generate OpenAPI documentation for the REST API', expected: 'api-docs' },
|
|
89
|
+
{ task: 'Create a sprint plan for the next two weeks', expected: 'planner' },
|
|
90
|
+
{ task: 'Build a React component for user registration', expected: 'coder' },
|
|
91
|
+
{ task: 'Debug memory leak in the WebSocket handler', expected: 'debugger' },
|
|
92
|
+
{ task: 'Investigate slow API response times', expected: 'researcher' },
|
|
93
|
+
{ task: 'Check code for potential race conditions', expected: 'reviewer' },
|
|
94
|
+
{ task: 'Add integration tests for the payment gateway', expected: 'tester' },
|
|
95
|
+
{ task: 'Plan the architecture for real-time notifications', expected: 'architect' },
|
|
96
|
+
{ task: 'Cache the frequently accessed user data', expected: 'optimizer' },
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
function getEmbedding(modelPath, text) {
|
|
100
|
+
try {
|
|
101
|
+
const sanitized = text.replace(/"/g, '\\"').replace(/\n/g, ' ');
|
|
102
|
+
const result = execSync(
|
|
103
|
+
`llama-embedding -m "${modelPath}" -p "${sanitized}" --embd-output-format json 2>/dev/null`,
|
|
104
|
+
{ encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 }
|
|
105
|
+
);
|
|
106
|
+
const json = JSON.parse(result);
|
|
107
|
+
return json.data[json.data.length - 1].embedding;
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function cosineSimilarity(a, b) {
|
|
114
|
+
if (!a || !b || a.length !== b.length) return 0;
|
|
115
|
+
let dot = 0, normA = 0, normB = 0;
|
|
116
|
+
for (let i = 0; i < a.length; i++) {
|
|
117
|
+
dot += a[i] * b[i];
|
|
118
|
+
normA += a[i] * a[i];
|
|
119
|
+
normB += b[i] * b[i];
|
|
120
|
+
}
|
|
121
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB) || 1);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Count keyword matches for each agent
|
|
126
|
+
*/
|
|
127
|
+
function getKeywordScores(task) {
|
|
128
|
+
const taskLower = task.toLowerCase();
|
|
129
|
+
const scores = {};
|
|
130
|
+
|
|
131
|
+
for (const [agent, keywords] of Object.entries(TRIGGER_KEYWORDS)) {
|
|
132
|
+
let matches = 0;
|
|
133
|
+
for (const kw of keywords) {
|
|
134
|
+
if (taskLower.includes(kw.toLowerCase())) {
|
|
135
|
+
matches++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
scores[agent] = matches;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return scores;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Pure embedding routing (baseline)
|
|
146
|
+
*/
|
|
147
|
+
function routeEmbeddingOnly(taskEmbedding, agentEmbeddings) {
|
|
148
|
+
let bestAgent = 'coder';
|
|
149
|
+
let bestSim = -1;
|
|
150
|
+
|
|
151
|
+
for (const [agent, emb] of Object.entries(agentEmbeddings)) {
|
|
152
|
+
const sim = cosineSimilarity(taskEmbedding, emb);
|
|
153
|
+
if (sim > bestSim) {
|
|
154
|
+
bestSim = sim;
|
|
155
|
+
bestAgent = agent;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return { agent: bestAgent, confidence: bestSim };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Pure keyword routing
|
|
164
|
+
*/
|
|
165
|
+
function routeKeywordOnly(task) {
|
|
166
|
+
const scores = getKeywordScores(task);
|
|
167
|
+
let bestAgent = 'coder';
|
|
168
|
+
let bestScore = 0;
|
|
169
|
+
|
|
170
|
+
for (const [agent, score] of Object.entries(scores)) {
|
|
171
|
+
if (score > bestScore) {
|
|
172
|
+
bestScore = score;
|
|
173
|
+
bestAgent = agent;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { agent: bestAgent, confidence: bestScore };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Hybrid routing - combine embedding similarity with keyword boost
|
|
182
|
+
*/
|
|
183
|
+
function routeHybrid(task, taskEmbedding, agentEmbeddings, embeddingWeight = 0.6, keywordWeight = 0.4) {
|
|
184
|
+
const keywordScores = getKeywordScores(task);
|
|
185
|
+
|
|
186
|
+
// Normalize keyword scores to 0-1 range
|
|
187
|
+
const maxKeyword = Math.max(...Object.values(keywordScores), 1);
|
|
188
|
+
const normalizedKeywords = {};
|
|
189
|
+
for (const agent of Object.keys(keywordScores)) {
|
|
190
|
+
normalizedKeywords[agent] = keywordScores[agent] / maxKeyword;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
let bestAgent = 'coder';
|
|
194
|
+
let bestScore = -1;
|
|
195
|
+
const allScores = {};
|
|
196
|
+
|
|
197
|
+
for (const [agent, emb] of Object.entries(agentEmbeddings)) {
|
|
198
|
+
const embSim = cosineSimilarity(taskEmbedding, emb);
|
|
199
|
+
const kwScore = normalizedKeywords[agent] || 0;
|
|
200
|
+
const combined = embeddingWeight * embSim + keywordWeight * kwScore;
|
|
201
|
+
allScores[agent] = { embedding: embSim, keyword: kwScore, combined };
|
|
202
|
+
|
|
203
|
+
if (combined > bestScore) {
|
|
204
|
+
bestScore = combined;
|
|
205
|
+
bestAgent = agent;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return { agent: bestAgent, confidence: bestScore, scores: allScores };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Keyword-first routing - use keywords as primary, embedding as tiebreaker
|
|
214
|
+
*/
|
|
215
|
+
function routeKeywordFirst(task, taskEmbedding, agentEmbeddings) {
|
|
216
|
+
const keywordScores = getKeywordScores(task);
|
|
217
|
+
|
|
218
|
+
// Find agents with max keyword matches
|
|
219
|
+
const maxKw = Math.max(...Object.values(keywordScores));
|
|
220
|
+
|
|
221
|
+
if (maxKw > 0) {
|
|
222
|
+
// At least one keyword match - use keywords, embedding as tiebreaker
|
|
223
|
+
const candidates = Object.entries(keywordScores)
|
|
224
|
+
.filter(([_, score]) => score === maxKw)
|
|
225
|
+
.map(([agent, _]) => agent);
|
|
226
|
+
|
|
227
|
+
if (candidates.length === 1) {
|
|
228
|
+
return { agent: candidates[0], confidence: maxKw };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Multiple candidates with same keyword count - use embedding
|
|
232
|
+
let bestAgent = candidates[0];
|
|
233
|
+
let bestSim = -1;
|
|
234
|
+
for (const agent of candidates) {
|
|
235
|
+
const sim = cosineSimilarity(taskEmbedding, agentEmbeddings[agent]);
|
|
236
|
+
if (sim > bestSim) {
|
|
237
|
+
bestSim = sim;
|
|
238
|
+
bestAgent = agent;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return { agent: bestAgent, confidence: maxKw + bestSim / 10 };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// No keyword matches - fall back to pure embedding
|
|
245
|
+
return routeEmbeddingOnly(taskEmbedding, agentEmbeddings);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function runBenchmark(modelPath, routerFn, name) {
|
|
249
|
+
const agentEmbeddings = {};
|
|
250
|
+
for (const [agent, desc] of Object.entries(DESCRIPTIONS_V1)) {
|
|
251
|
+
agentEmbeddings[agent] = getEmbedding(modelPath, desc);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
let correct = 0;
|
|
255
|
+
const results = [];
|
|
256
|
+
|
|
257
|
+
for (const test of ROUTING_TESTS) {
|
|
258
|
+
const taskEmb = getEmbedding(modelPath, test.task);
|
|
259
|
+
const { agent } = routerFn(test.task, taskEmb, agentEmbeddings);
|
|
260
|
+
const isCorrect = agent === test.expected;
|
|
261
|
+
if (isCorrect) correct++;
|
|
262
|
+
results.push({ task: test.task, expected: test.expected, got: agent, correct: isCorrect });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return { accuracy: correct / ROUTING_TESTS.length, correct, total: ROUTING_TESTS.length, results, name };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function main() {
|
|
269
|
+
console.log('\n╔═══════════════════════════════════════════════════════════════════════════════════╗');
|
|
270
|
+
console.log('║ HYBRID ROUTING: Embeddings + Keywords ║');
|
|
271
|
+
console.log('╚═══════════════════════════════════════════════════════════════════════════════════╝\n');
|
|
272
|
+
|
|
273
|
+
if (!existsSync(RUVLTRA_MODEL)) {
|
|
274
|
+
console.error('RuvLTRA model not found.');
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
console.log('Strategies:');
|
|
279
|
+
console.log(' 1. Embedding Only (baseline)');
|
|
280
|
+
console.log(' 2. Keyword Only (no model)');
|
|
281
|
+
console.log(' 3. Hybrid 60/40 (60% embedding, 40% keyword)');
|
|
282
|
+
console.log(' 4. Hybrid 40/60 (40% embedding, 60% keyword)');
|
|
283
|
+
console.log(' 5. Keyword-First (keywords primary, embedding tiebreaker)\n');
|
|
284
|
+
|
|
285
|
+
// RuvLTRA tests
|
|
286
|
+
console.log('─────────────────────────────────────────────────────────────────');
|
|
287
|
+
console.log(' RUVLTRA RESULTS');
|
|
288
|
+
console.log('─────────────────────────────────────────────────────────────────\n');
|
|
289
|
+
|
|
290
|
+
const ruvEmbedding = runBenchmark(RUVLTRA_MODEL,
|
|
291
|
+
(task, taskEmb, agentEmbs) => routeEmbeddingOnly(taskEmb, agentEmbs),
|
|
292
|
+
'Embedding Only');
|
|
293
|
+
console.log(` Embedding Only: ${(ruvEmbedding.accuracy * 100).toFixed(1)}%`);
|
|
294
|
+
|
|
295
|
+
const ruvKeyword = runBenchmark(RUVLTRA_MODEL,
|
|
296
|
+
(task, taskEmb, agentEmbs) => routeKeywordOnly(task),
|
|
297
|
+
'Keyword Only');
|
|
298
|
+
console.log(` Keyword Only: ${(ruvKeyword.accuracy * 100).toFixed(1)}%`);
|
|
299
|
+
|
|
300
|
+
const ruvHybrid60 = runBenchmark(RUVLTRA_MODEL,
|
|
301
|
+
(task, taskEmb, agentEmbs) => routeHybrid(task, taskEmb, agentEmbs, 0.6, 0.4),
|
|
302
|
+
'Hybrid 60/40');
|
|
303
|
+
console.log(` Hybrid 60/40: ${(ruvHybrid60.accuracy * 100).toFixed(1)}%`);
|
|
304
|
+
|
|
305
|
+
const ruvHybrid40 = runBenchmark(RUVLTRA_MODEL,
|
|
306
|
+
(task, taskEmb, agentEmbs) => routeHybrid(task, taskEmb, agentEmbs, 0.4, 0.6),
|
|
307
|
+
'Hybrid 40/60');
|
|
308
|
+
console.log(` Hybrid 40/60: ${(ruvHybrid40.accuracy * 100).toFixed(1)}%`);
|
|
309
|
+
|
|
310
|
+
const ruvKwFirst = runBenchmark(RUVLTRA_MODEL,
|
|
311
|
+
(task, taskEmb, agentEmbs) => routeKeywordFirst(task, taskEmb, agentEmbs),
|
|
312
|
+
'Keyword-First');
|
|
313
|
+
console.log(` Keyword-First: ${(ruvKwFirst.accuracy * 100).toFixed(1)}%`);
|
|
314
|
+
|
|
315
|
+
// Qwen tests
|
|
316
|
+
console.log('\n─────────────────────────────────────────────────────────────────');
|
|
317
|
+
console.log(' QWEN RESULTS');
|
|
318
|
+
console.log('─────────────────────────────────────────────────────────────────\n');
|
|
319
|
+
|
|
320
|
+
const qwenEmbedding = runBenchmark(QWEN_MODEL,
|
|
321
|
+
(task, taskEmb, agentEmbs) => routeEmbeddingOnly(taskEmb, agentEmbs),
|
|
322
|
+
'Embedding Only');
|
|
323
|
+
console.log(` Embedding Only: ${(qwenEmbedding.accuracy * 100).toFixed(1)}%`);
|
|
324
|
+
|
|
325
|
+
const qwenHybrid60 = runBenchmark(QWEN_MODEL,
|
|
326
|
+
(task, taskEmb, agentEmbs) => routeHybrid(task, taskEmb, agentEmbs, 0.6, 0.4),
|
|
327
|
+
'Hybrid 60/40');
|
|
328
|
+
console.log(` Hybrid 60/40: ${(qwenHybrid60.accuracy * 100).toFixed(1)}%`);
|
|
329
|
+
|
|
330
|
+
const qwenKwFirst = runBenchmark(QWEN_MODEL,
|
|
331
|
+
(task, taskEmb, agentEmbs) => routeKeywordFirst(task, taskEmb, agentEmbs),
|
|
332
|
+
'Keyword-First');
|
|
333
|
+
console.log(` Keyword-First: ${(qwenKwFirst.accuracy * 100).toFixed(1)}%`);
|
|
334
|
+
|
|
335
|
+
// Summary table
|
|
336
|
+
console.log('\n═══════════════════════════════════════════════════════════════════════════════════');
|
|
337
|
+
console.log(' SUMMARY');
|
|
338
|
+
console.log('═══════════════════════════════════════════════════════════════════════════════════\n');
|
|
339
|
+
|
|
340
|
+
const fmt = (v) => `${(v * 100).toFixed(1)}%`.padStart(8);
|
|
341
|
+
|
|
342
|
+
console.log('┌───────────────────────┬──────────┬──────────┬──────────────────┐');
|
|
343
|
+
console.log('│ Strategy │ RuvLTRA │ Qwen │ RuvLTRA vs Qwen │');
|
|
344
|
+
console.log('├───────────────────────┼──────────┼──────────┼──────────────────┤');
|
|
345
|
+
console.log(`│ Embedding Only │${fmt(ruvEmbedding.accuracy)} │${fmt(qwenEmbedding.accuracy)} │ +${((ruvEmbedding.accuracy - qwenEmbedding.accuracy) * 100).toFixed(1)} pts │`);
|
|
346
|
+
console.log(`│ Keyword Only │${fmt(ruvKeyword.accuracy)} │${fmt(ruvKeyword.accuracy)} │ same │`);
|
|
347
|
+
console.log(`│ Hybrid 60/40 │${fmt(ruvHybrid60.accuracy)} │${fmt(qwenHybrid60.accuracy)} │ +${((ruvHybrid60.accuracy - qwenHybrid60.accuracy) * 100).toFixed(1)} pts │`);
|
|
348
|
+
console.log(`│ Keyword-First │${fmt(ruvKwFirst.accuracy)} │${fmt(qwenKwFirst.accuracy)} │ +${((ruvKwFirst.accuracy - qwenKwFirst.accuracy) * 100).toFixed(1)} pts │`);
|
|
349
|
+
console.log('└───────────────────────┴──────────┴──────────┴──────────────────┘');
|
|
350
|
+
|
|
351
|
+
// Best results
|
|
352
|
+
const ruvBest = [ruvEmbedding, ruvKeyword, ruvHybrid60, ruvHybrid40, ruvKwFirst]
|
|
353
|
+
.reduce((a, b) => a.accuracy > b.accuracy ? a : b);
|
|
354
|
+
|
|
355
|
+
console.log(`\n BEST RuvLTRA: ${ruvBest.name} = ${(ruvBest.accuracy * 100).toFixed(1)}%`);
|
|
356
|
+
console.log(` Improvement over embedding-only: +${((ruvBest.accuracy - ruvEmbedding.accuracy) * 100).toFixed(1)} points`);
|
|
357
|
+
|
|
358
|
+
// Show best results details
|
|
359
|
+
console.log('\n─────────────────────────────────────────────────────────────────');
|
|
360
|
+
console.log(` BEST STRATEGY DETAILS: ${ruvBest.name}`);
|
|
361
|
+
console.log('─────────────────────────────────────────────────────────────────\n');
|
|
362
|
+
|
|
363
|
+
for (const r of ruvBest.results) {
|
|
364
|
+
const mark = r.correct ? '✓' : '✗';
|
|
365
|
+
const task = r.task.slice(0, 45).padEnd(45);
|
|
366
|
+
const exp = r.expected.padEnd(18);
|
|
367
|
+
console.log(`${mark} ${task} ${exp}${r.correct ? '' : '→ ' + r.got}`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
console.log('\n');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Improved Model Comparison - Enhanced Agent Descriptions
|
|
4
|
+
*
|
|
5
|
+
* Key improvements:
|
|
6
|
+
* 1. Semantic sentence descriptions instead of keyword lists
|
|
7
|
+
* 2. Example tasks embedded in descriptions
|
|
8
|
+
* 3. Unique discriminating phrases for each agent
|
|
9
|
+
* 4. Adjusted similarity scoring with top-k voting
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
const { existsSync } = require('fs');
|
|
14
|
+
const { join } = require('path');
|
|
15
|
+
const { homedir } = require('os');
|
|
16
|
+
|
|
17
|
+
// Model paths
|
|
18
|
+
const MODELS_DIR = join(homedir(), '.ruvllm', 'models');
|
|
19
|
+
const QWEN_MODEL = join(MODELS_DIR, 'qwen2.5-0.5b-instruct-q4_k_m.gguf');
|
|
20
|
+
const RUVLTRA_MODEL = join(MODELS_DIR, 'ruvltra-claude-code-0.5b-q4_k_m.gguf');
|
|
21
|
+
|
|
22
|
+
// IMPROVED: Semantic sentence descriptions with examples
|
|
23
|
+
const AGENT_DESCRIPTIONS_V1 = {
|
|
24
|
+
coder: 'implement create write build add code function class component feature',
|
|
25
|
+
researcher: 'research find investigate analyze explore search discover examine',
|
|
26
|
+
reviewer: 'review check evaluate assess inspect examine code quality',
|
|
27
|
+
tester: 'test unit integration e2e coverage mock assertion spec',
|
|
28
|
+
architect: 'design architecture schema system structure plan database',
|
|
29
|
+
'security-architect': 'security vulnerability xss injection audit cve authentication',
|
|
30
|
+
debugger: 'debug fix bug error issue broken crash exception trace',
|
|
31
|
+
documenter: 'document readme jsdoc comment explain describe documentation',
|
|
32
|
+
refactorer: 'refactor extract rename consolidate clean restructure simplify',
|
|
33
|
+
optimizer: 'optimize performance slow fast cache speed memory latency',
|
|
34
|
+
devops: 'deploy ci cd kubernetes docker pipeline container infrastructure',
|
|
35
|
+
'api-docs': 'openapi swagger api documentation graphql schema endpoint',
|
|
36
|
+
planner: 'plan estimate prioritize sprint roadmap schedule milestone',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// V2: Semantic sentences with task context
|
|
40
|
+
const AGENT_DESCRIPTIONS_V2 = {
|
|
41
|
+
coder: 'I write new code and implement features. Create functions, build components, implement algorithms like binary search, build React components, write TypeScript code.',
|
|
42
|
+
researcher: 'I research and investigate topics. Find best practices, explore solutions, investigate performance issues, analyze patterns, discover new approaches.',
|
|
43
|
+
reviewer: 'I review existing code for quality. Check pull requests, evaluate code style, assess readability, inspect for bugs, examine code patterns.',
|
|
44
|
+
tester: 'I write tests for code. Create unit tests, add integration tests, write e2e tests, mock dependencies, check test coverage, write test specs.',
|
|
45
|
+
architect: 'I design system architecture. Plan database schemas, design API structures, create system diagrams, plan microservices, design data models.',
|
|
46
|
+
'security-architect': 'I audit security vulnerabilities. Check for XSS, SQL injection, CSRF, audit authentication, review security policies, scan for CVEs.',
|
|
47
|
+
debugger: 'I fix bugs and debug errors. Trace exceptions, fix crashes, resolve null pointer errors, debug memory leaks, fix runtime issues.',
|
|
48
|
+
documenter: 'I write documentation and comments. Add JSDoc comments, write README files, explain code functionality, describe APIs, create guides.',
|
|
49
|
+
refactorer: 'I refactor and restructure code. Modernize to async/await, extract functions, rename variables, consolidate duplicate code, simplify logic.',
|
|
50
|
+
optimizer: 'I optimize performance and speed. Cache data, improve query performance, reduce latency, optimize memory usage, speed up slow operations.',
|
|
51
|
+
devops: 'I handle deployment and infrastructure. Set up CI/CD pipelines, configure Kubernetes, manage Docker containers, deploy to cloud.',
|
|
52
|
+
'api-docs': 'I create API documentation specs. Generate OpenAPI specs, write Swagger docs, document REST endpoints, create GraphQL schemas.',
|
|
53
|
+
planner: 'I create project plans and estimates. Sprint planning, roadmap creation, milestone tracking, task prioritization, schedule estimation.',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// V3: Even more specific with negative space
|
|
57
|
+
const AGENT_DESCRIPTIONS_V3 = {
|
|
58
|
+
coder: 'Software developer who implements new features and writes production code. Tasks: implement binary search, build React components, create TypeScript functions, add new functionality to applications.',
|
|
59
|
+
researcher: 'Technical researcher who investigates and analyzes. Tasks: research best practices, explore state management options, investigate slow response times, analyze codebase patterns.',
|
|
60
|
+
reviewer: 'Code reviewer who evaluates existing code quality. Tasks: review pull requests, check for race conditions, assess code style, evaluate implementation approaches.',
|
|
61
|
+
tester: 'QA engineer who writes automated tests. Tasks: write unit tests, add integration tests, create e2e test suites, test payment gateways, verify authentication modules.',
|
|
62
|
+
architect: 'System architect who designs software structure. Tasks: design database schemas, plan real-time notification systems, architect microservices, model data relationships.',
|
|
63
|
+
'security-architect': 'Security specialist who audits vulnerabilities. Tasks: audit API endpoints for XSS, check SQL injection risks, review authentication security, scan for CSRF vulnerabilities.',
|
|
64
|
+
debugger: 'Bug hunter who fixes errors and traces issues. Tasks: fix null pointer exceptions, debug memory leaks, trace WebSocket errors, resolve crash bugs.',
|
|
65
|
+
documenter: 'Technical writer who creates documentation. Tasks: write JSDoc comments, create README files, document utility functions, explain complex code.',
|
|
66
|
+
refactorer: 'Code modernizer who restructures without changing behavior. Tasks: refactor to async/await, extract reusable functions, modernize legacy patterns, simplify complex logic.',
|
|
67
|
+
optimizer: 'Performance engineer who speeds up slow code. Tasks: cache frequently accessed data, optimize database queries, reduce API latency, improve memory efficiency.',
|
|
68
|
+
devops: 'DevOps engineer who manages deployment infrastructure. Tasks: set up CI/CD pipelines, configure Kubernetes clusters, manage Docker deployments, automate releases.',
|
|
69
|
+
'api-docs': 'API documentation specialist. Tasks: generate OpenAPI documentation, create Swagger specs, document REST API endpoints, write API reference guides.',
|
|
70
|
+
planner: 'Project planner who organizes work. Tasks: create sprint plans, estimate timelines, prioritize backlog, schedule milestones, plan roadmaps.',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Test cases for routing
|
|
74
|
+
const ROUTING_TESTS = [
|
|
75
|
+
{ task: 'Implement a binary search function in TypeScript', expected: 'coder' },
|
|
76
|
+
{ task: 'Write unit tests for the authentication module', expected: 'tester' },
|
|
77
|
+
{ task: 'Review the pull request for security vulnerabilities', expected: 'reviewer' },
|
|
78
|
+
{ task: 'Research best practices for React state management', expected: 'researcher' },
|
|
79
|
+
{ task: 'Design the database schema for user profiles', expected: 'architect' },
|
|
80
|
+
{ task: 'Fix the null pointer exception in the login handler', expected: 'debugger' },
|
|
81
|
+
{ task: 'Audit the API endpoints for XSS vulnerabilities', expected: 'security-architect' },
|
|
82
|
+
{ task: 'Write JSDoc comments for the utility functions', expected: 'documenter' },
|
|
83
|
+
{ task: 'Refactor the payment module to use async/await', expected: 'refactorer' },
|
|
84
|
+
{ task: 'Optimize the database queries for the dashboard', expected: 'optimizer' },
|
|
85
|
+
{ task: 'Set up the CI/CD pipeline for the microservices', expected: 'devops' },
|
|
86
|
+
{ task: 'Generate OpenAPI documentation for the REST API', expected: 'api-docs' },
|
|
87
|
+
{ task: 'Create a sprint plan for the next two weeks', expected: 'planner' },
|
|
88
|
+
{ task: 'Build a React component for user registration', expected: 'coder' },
|
|
89
|
+
{ task: 'Debug memory leak in the WebSocket handler', expected: 'debugger' },
|
|
90
|
+
{ task: 'Investigate slow API response times', expected: 'researcher' },
|
|
91
|
+
{ task: 'Check code for potential race conditions', expected: 'reviewer' },
|
|
92
|
+
{ task: 'Add integration tests for the payment gateway', expected: 'tester' },
|
|
93
|
+
{ task: 'Plan the architecture for real-time notifications', expected: 'architect' },
|
|
94
|
+
{ task: 'Cache the frequently accessed user data', expected: 'optimizer' },
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
// Similarity test pairs
|
|
98
|
+
const SIMILARITY_TESTS = [
|
|
99
|
+
{ text1: 'implement user authentication', text2: 'create login functionality', expected: 'high' },
|
|
100
|
+
{ text1: 'write unit tests', text2: 'fix database bug', expected: 'low' },
|
|
101
|
+
{ text1: 'optimize query performance', text2: 'improve database speed', expected: 'high' },
|
|
102
|
+
{ text1: 'design system architecture', text2: 'plan software structure', expected: 'high' },
|
|
103
|
+
{ text1: 'deploy to kubernetes', text2: 'analyze user behavior', expected: 'low' },
|
|
104
|
+
{ text1: 'refactor legacy code', text2: 'restructure old module', expected: 'high' },
|
|
105
|
+
{ text1: 'debug memory leak', text2: 'fix memory consumption issue', expected: 'high' },
|
|
106
|
+
{ text1: 'document api endpoints', text2: 'write openapi spec', expected: 'high' },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get embedding from model
|
|
111
|
+
*/
|
|
112
|
+
function getEmbedding(modelPath, text) {
|
|
113
|
+
try {
|
|
114
|
+
const sanitized = text.replace(/"/g, '\\"').replace(/\n/g, ' ');
|
|
115
|
+
const result = execSync(
|
|
116
|
+
`llama-embedding -m "${modelPath}" -p "${sanitized}" --embd-output-format json 2>/dev/null`,
|
|
117
|
+
{ encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 }
|
|
118
|
+
);
|
|
119
|
+
const json = JSON.parse(result);
|
|
120
|
+
return json.data[json.data.length - 1].embedding;
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.error(`Error: ${err.message}`);
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Cosine similarity
|
|
129
|
+
*/
|
|
130
|
+
function cosineSimilarity(a, b) {
|
|
131
|
+
if (!a || !b || a.length !== b.length) return 0;
|
|
132
|
+
let dot = 0, normA = 0, normB = 0;
|
|
133
|
+
for (let i = 0; i < a.length; i++) {
|
|
134
|
+
dot += a[i] * b[i];
|
|
135
|
+
normA += a[i] * a[i];
|
|
136
|
+
normB += b[i] * b[i];
|
|
137
|
+
}
|
|
138
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB) || 1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Route task with top-k analysis
|
|
143
|
+
*/
|
|
144
|
+
function routeTask(taskEmbedding, agentEmbeddings, topK = 3) {
|
|
145
|
+
const scores = [];
|
|
146
|
+
for (const [agent, embedding] of Object.entries(agentEmbeddings)) {
|
|
147
|
+
const sim = cosineSimilarity(taskEmbedding, embedding);
|
|
148
|
+
scores.push({ agent, similarity: sim });
|
|
149
|
+
}
|
|
150
|
+
scores.sort((a, b) => b.similarity - a.similarity);
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
agent: scores[0].agent,
|
|
154
|
+
confidence: scores[0].similarity,
|
|
155
|
+
topK: scores.slice(0, topK),
|
|
156
|
+
margin: scores[0].similarity - scores[1].similarity,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Run benchmark for a specific description version
|
|
162
|
+
*/
|
|
163
|
+
function runBenchmark(modelPath, modelName, descriptions, version) {
|
|
164
|
+
console.log(`\n [${version}] Computing agent embeddings...`);
|
|
165
|
+
|
|
166
|
+
const agentEmbeddings = {};
|
|
167
|
+
for (const [agent, description] of Object.entries(descriptions)) {
|
|
168
|
+
process.stdout.write(` ${agent}... `);
|
|
169
|
+
agentEmbeddings[agent] = getEmbedding(modelPath, description);
|
|
170
|
+
console.log('done');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
console.log(` [${version}] Running routing tests...`);
|
|
174
|
+
let correct = 0;
|
|
175
|
+
const failures = [];
|
|
176
|
+
|
|
177
|
+
for (const test of ROUTING_TESTS) {
|
|
178
|
+
const taskEmbedding = getEmbedding(modelPath, test.task);
|
|
179
|
+
const { agent, confidence, topK, margin } = routeTask(taskEmbedding, agentEmbeddings);
|
|
180
|
+
const isCorrect = agent === test.expected;
|
|
181
|
+
if (isCorrect) {
|
|
182
|
+
correct++;
|
|
183
|
+
} else {
|
|
184
|
+
failures.push({
|
|
185
|
+
task: test.task,
|
|
186
|
+
expected: test.expected,
|
|
187
|
+
got: agent,
|
|
188
|
+
topK,
|
|
189
|
+
margin,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const accuracy = correct / ROUTING_TESTS.length;
|
|
195
|
+
return { accuracy, correct, total: ROUTING_TESTS.length, failures, version };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Main comparison
|
|
200
|
+
*/
|
|
201
|
+
async function main() {
|
|
202
|
+
console.log('\n╔═══════════════════════════════════════════════════════════════════════════════════╗');
|
|
203
|
+
console.log('║ IMPROVED MODEL COMPARISON: Testing Description Strategies ║');
|
|
204
|
+
console.log('║ Semantic Descriptions vs Keyword Lists ║');
|
|
205
|
+
console.log('╚═══════════════════════════════════════════════════════════════════════════════════╝\n');
|
|
206
|
+
|
|
207
|
+
if (!existsSync(QWEN_MODEL) || !existsSync(RUVLTRA_MODEL)) {
|
|
208
|
+
console.error('Models not found. Run the original comparison first.');
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
console.log('Testing 3 description strategies:');
|
|
213
|
+
console.log(' V1: Keyword lists (baseline)');
|
|
214
|
+
console.log(' V2: Semantic sentences with examples');
|
|
215
|
+
console.log(' V3: Task-specific descriptions with context\n');
|
|
216
|
+
|
|
217
|
+
// Test all three versions with RuvLTRA
|
|
218
|
+
console.log('─────────────────────────────────────────────────────────────────');
|
|
219
|
+
console.log(' RUVLTRA CLAUDE CODE MODEL');
|
|
220
|
+
console.log('─────────────────────────────────────────────────────────────────');
|
|
221
|
+
|
|
222
|
+
const v1Results = runBenchmark(RUVLTRA_MODEL, 'RuvLTRA', AGENT_DESCRIPTIONS_V1, 'V1-Keywords');
|
|
223
|
+
const v2Results = runBenchmark(RUVLTRA_MODEL, 'RuvLTRA', AGENT_DESCRIPTIONS_V2, 'V2-Semantic');
|
|
224
|
+
const v3Results = runBenchmark(RUVLTRA_MODEL, 'RuvLTRA', AGENT_DESCRIPTIONS_V3, 'V3-TaskSpecific');
|
|
225
|
+
|
|
226
|
+
// Also test Qwen with best strategy
|
|
227
|
+
console.log('\n─────────────────────────────────────────────────────────────────');
|
|
228
|
+
console.log(' QWEN 0.5B BASE MODEL');
|
|
229
|
+
console.log('─────────────────────────────────────────────────────────────────');
|
|
230
|
+
|
|
231
|
+
const qwenV1 = runBenchmark(QWEN_MODEL, 'Qwen', AGENT_DESCRIPTIONS_V1, 'V1-Keywords');
|
|
232
|
+
const qwenV3 = runBenchmark(QWEN_MODEL, 'Qwen', AGENT_DESCRIPTIONS_V3, 'V3-TaskSpecific');
|
|
233
|
+
|
|
234
|
+
// Results summary
|
|
235
|
+
console.log('\n═══════════════════════════════════════════════════════════════════════════════════');
|
|
236
|
+
console.log(' RESULTS COMPARISON');
|
|
237
|
+
console.log('═══════════════════════════════════════════════════════════════════════════════════\n');
|
|
238
|
+
|
|
239
|
+
console.log('┌─────────────────────────┬───────────────┬───────────────┬───────────────┐');
|
|
240
|
+
console.log('│ Strategy │ RuvLTRA │ Qwen Base │ Improvement │');
|
|
241
|
+
console.log('├─────────────────────────┼───────────────┼───────────────┼───────────────┤');
|
|
242
|
+
|
|
243
|
+
const formatPct = (v) => `${(v * 100).toFixed(1)}%`.padStart(12);
|
|
244
|
+
|
|
245
|
+
console.log(`│ V1: Keywords │${formatPct(v1Results.accuracy)} │${formatPct(qwenV1.accuracy)} │ baseline │`);
|
|
246
|
+
console.log(`│ V2: Semantic │${formatPct(v2Results.accuracy)} │ - │${formatPct(v2Results.accuracy - v1Results.accuracy)} │`);
|
|
247
|
+
console.log(`│ V3: Task-Specific │${formatPct(v3Results.accuracy)} │${formatPct(qwenV3.accuracy)} │${formatPct(v3Results.accuracy - v1Results.accuracy)} │`);
|
|
248
|
+
|
|
249
|
+
console.log('└─────────────────────────┴───────────────┴───────────────┴───────────────┘');
|
|
250
|
+
|
|
251
|
+
// Find best strategy
|
|
252
|
+
const best = [v1Results, v2Results, v3Results].reduce((a, b) => a.accuracy > b.accuracy ? a : b);
|
|
253
|
+
|
|
254
|
+
console.log(`\n BEST STRATEGY: ${best.version} with ${(best.accuracy * 100).toFixed(1)}% accuracy`);
|
|
255
|
+
console.log(` Improvement over V1: +${((best.accuracy - v1Results.accuracy) * 100).toFixed(1)} percentage points`);
|
|
256
|
+
|
|
257
|
+
// Show remaining failures for best strategy
|
|
258
|
+
if (best.failures.length > 0) {
|
|
259
|
+
console.log(`\n Remaining failures (${best.failures.length}):`);
|
|
260
|
+
for (const f of best.failures.slice(0, 5)) {
|
|
261
|
+
console.log(` "${f.task.slice(0, 45)}..."`);
|
|
262
|
+
console.log(` Expected: ${f.expected}, Got: ${f.got}`);
|
|
263
|
+
console.log(` Top-3: ${f.topK.map(t => `${t.agent}(${(t.similarity * 100).toFixed(0)}%)`).join(', ')}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// RuvLTRA vs Qwen with best strategy
|
|
268
|
+
console.log('\n═══════════════════════════════════════════════════════════════════════════════════');
|
|
269
|
+
console.log(' FINAL COMPARISON (V3 Task-Specific Descriptions)');
|
|
270
|
+
console.log('═══════════════════════════════════════════════════════════════════════════════════\n');
|
|
271
|
+
|
|
272
|
+
console.log('┌─────────────────────────────┬───────────────┬───────────────┐');
|
|
273
|
+
console.log('│ Metric │ Qwen Base │ RuvLTRA │');
|
|
274
|
+
console.log('├─────────────────────────────┼───────────────┼───────────────┤');
|
|
275
|
+
|
|
276
|
+
const qwenWins = qwenV3.accuracy > v3Results.accuracy;
|
|
277
|
+
const ruvWins = v3Results.accuracy > qwenV3.accuracy;
|
|
278
|
+
console.log(`│ V3 Routing Accuracy │${qwenWins ? '✓' : ' '}${formatPct(qwenV3.accuracy)} │${ruvWins ? '✓' : ' '}${formatPct(v3Results.accuracy)} │`);
|
|
279
|
+
console.log('└─────────────────────────────┴───────────────┴───────────────┘');
|
|
280
|
+
|
|
281
|
+
const winner = ruvWins ? 'RuvLTRA' : qwenWins ? 'Qwen' : 'Tie';
|
|
282
|
+
const margin = Math.abs(v3Results.accuracy - qwenV3.accuracy) * 100;
|
|
283
|
+
|
|
284
|
+
console.log(`\n WINNER: ${winner} (${margin.toFixed(1)} point margin)`);
|
|
285
|
+
console.log('\n');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
main().catch(console.error);
|