agentic-kdd 3.0.3 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/akdd.js +42 -4
- package/collab-manager.cjs +82 -5
- package/embeddings-v2.cjs +320 -0
- package/llms-generator.cjs +425 -0
- package/mem-curator.cjs +584 -0
- package/package.json +3 -2
package/bin/akdd.js
CHANGED
|
@@ -55,6 +55,13 @@ const HELP = `
|
|
|
55
55
|
akdd adr Ingest ADRs from docs/adr/
|
|
56
56
|
akdd knowledge Ingest gotchas/conventions from docs/
|
|
57
57
|
|
|
58
|
+
Memory Governance (v3.2):
|
|
59
|
+
akdd cure Run MemCurator — TTL, dedup, conflicts, scores
|
|
60
|
+
akdd cure report Preview what curation would do (no changes)
|
|
61
|
+
akdd llms Generate llms.txt + knowledge-graph.json
|
|
62
|
+
akdd benchmarks LongMemEval + Token Reduction + Memory Quality scores
|
|
63
|
+
akdd causal-prune Prune causal graph to prevent context collapse
|
|
64
|
+
|
|
58
65
|
Metrics & Observability:
|
|
59
66
|
akdd metrics Project KPIs — success rate, rework, autonomy score
|
|
60
67
|
akdd metrics trend Show trend of last 10 cycles
|
|
@@ -64,7 +71,8 @@ const HELP = `
|
|
|
64
71
|
|
|
65
72
|
Collaborative Mode (Legion):
|
|
66
73
|
akdd collab init Activate collaborative mode — creates shared DB automatically
|
|
67
|
-
akdd collab
|
|
74
|
+
akdd collab invite Generate a 6-char invite code for a team member (24h, one-use)
|
|
75
|
+
akdd collab join <code> Join the team with an invite code (e.g. LUMO-X7K2P4)
|
|
68
76
|
akdd collab push Push your learnings to the team
|
|
69
77
|
akdd collab pull Pull team's latest learnings
|
|
70
78
|
akdd collab status Check collaborative sync status
|
|
@@ -219,17 +227,47 @@ switch (command) {
|
|
|
219
227
|
break;
|
|
220
228
|
}
|
|
221
229
|
|
|
230
|
+
|
|
231
|
+
// ── v3.2: MemCurator ───────────────────────────────────────────────────────
|
|
232
|
+
case 'cure': {
|
|
233
|
+
const sub = arg1 || 'run';
|
|
234
|
+
runModule('mem-curator.cjs', sub);
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ── v3.2: llms.txt generator ───────────────────────────────────────────────
|
|
239
|
+
case 'llms': {
|
|
240
|
+
const sub = arg1 || 'all';
|
|
241
|
+
runModule('llms-generator.cjs', sub);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ── v3.2: Report benchmarks ────────────────────────────────────────────────
|
|
246
|
+
case 'benchmarks': {
|
|
247
|
+
runModule('metrics.cjs', 'benchmarks');
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ── v3.2: Causal prune ─────────────────────────────────────────────────────
|
|
252
|
+
case 'causal-prune': {
|
|
253
|
+
runModule('causal-edges.cjs', 'prune');
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
|
|
222
257
|
// ── v3.0: Collaborative Mode (Legion) ────────────────────────────────
|
|
223
258
|
case 'collab': {
|
|
224
259
|
const sub = arg1 || 'status';
|
|
225
260
|
if (sub === 'init') {
|
|
226
261
|
runModule('collab-manager.cjs', 'init');
|
|
262
|
+
} else if (sub === 'invite') {
|
|
263
|
+
runModule('collab-manager.cjs', 'invite');
|
|
227
264
|
} else if (sub === 'join') {
|
|
228
|
-
if (!arg2
|
|
229
|
-
console.log('\n Uso: akdd collab join <
|
|
265
|
+
if (!arg2) {
|
|
266
|
+
console.log('\n Uso: akdd collab join <código>\n');
|
|
267
|
+
console.log(' El código lo genera el jefe con: akdd collab invite\n');
|
|
230
268
|
break;
|
|
231
269
|
}
|
|
232
|
-
runModule('collab-manager.cjs', 'join', `"${arg2}"
|
|
270
|
+
runModule('collab-manager.cjs', 'join', `"${arg2}"`);
|
|
233
271
|
} else if (sub === 'push') {
|
|
234
272
|
runModule('collab-manager.cjs', 'push');
|
|
235
273
|
} else if (sub === 'pull') {
|
package/collab-manager.cjs
CHANGED
|
@@ -153,13 +153,43 @@ async function collabInit(projectRoot) {
|
|
|
153
153
|
|
|
154
154
|
// ─── JOIN — PARA EL DEV QUE SE UNE AL EQUIPO ─────────────────────────────────
|
|
155
155
|
|
|
156
|
-
async function collabJoin(projectRoot,
|
|
156
|
+
async function collabJoin(projectRoot, urlOrCode, token) {
|
|
157
157
|
console.log('\n[COLLAB] Uniéndose al equipo...\n');
|
|
158
158
|
|
|
159
|
+
let finalUrl = urlOrCode;
|
|
160
|
+
let finalToken = token;
|
|
161
|
+
|
|
162
|
+
// Detectar si es un código de invitación (formato: PREFIX-XXXXXX)
|
|
163
|
+
const isInviteCode = !urlOrCode?.startsWith('libsql://') && !urlOrCode?.startsWith('http');
|
|
164
|
+
|
|
165
|
+
if (isInviteCode) {
|
|
166
|
+
console.log(`[COLLAB] Resolviendo código: ${urlOrCode}`);
|
|
167
|
+
try {
|
|
168
|
+
const response = await fetch(`${PROVISIONER_URL}/join`, {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
headers: { 'Content-Type': 'application/json' },
|
|
171
|
+
body: JSON.stringify({ code: urlOrCode }),
|
|
172
|
+
});
|
|
173
|
+
const result = await response.json();
|
|
174
|
+
|
|
175
|
+
if (!result.ok) {
|
|
176
|
+
console.error(`[COLLAB] ❌ ${result.error}`);
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
finalUrl = result.url;
|
|
181
|
+
finalToken = result.token;
|
|
182
|
+
console.log(`[COLLAB] ✅ Código válido. Conectando a: ${result.db}`);
|
|
183
|
+
} catch (e) {
|
|
184
|
+
console.error('[COLLAB] Error resolviendo código:', e.message);
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
159
189
|
const config = {
|
|
160
190
|
enabled: true,
|
|
161
|
-
url,
|
|
162
|
-
token,
|
|
191
|
+
url: finalUrl,
|
|
192
|
+
token: finalToken,
|
|
163
193
|
member_id: os.userInfo().username,
|
|
164
194
|
sync_on_cycle_end: true,
|
|
165
195
|
last_sync: null,
|
|
@@ -176,6 +206,48 @@ async function collabJoin(projectRoot, url, token) {
|
|
|
176
206
|
console.log('[COLLAB] ✅ Listo. Ya tienes toda la memoria del equipo.\n');
|
|
177
207
|
}
|
|
178
208
|
|
|
209
|
+
// ─── INVITE ───────────────────────────────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
async function collabInvite(projectRoot) {
|
|
212
|
+
const config = loadConfig(projectRoot);
|
|
213
|
+
if (!config?.enabled) {
|
|
214
|
+
console.log('\n[COLLAB] Modo colaborativo no activado. Correr: akdd collab init\n');
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const projectId = config.project_id || getProjectId(projectRoot);
|
|
219
|
+
console.log('\n[COLLAB] Generando código de invitación...');
|
|
220
|
+
|
|
221
|
+
let result;
|
|
222
|
+
try {
|
|
223
|
+
const response = await fetch(`${PROVISIONER_URL}/invite`, {
|
|
224
|
+
method: 'POST',
|
|
225
|
+
headers: { 'Content-Type': 'application/json' },
|
|
226
|
+
body: JSON.stringify({ projectId }),
|
|
227
|
+
});
|
|
228
|
+
result = await response.json();
|
|
229
|
+
} catch (e) {
|
|
230
|
+
console.error('[COLLAB] Error:', e.message);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (!result.ok) {
|
|
235
|
+
console.error('[COLLAB] Error generando código:', result.error);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
console.log('\n' + '═'.repeat(50));
|
|
240
|
+
console.log(' 🔑 Código de invitación Agentic KDD');
|
|
241
|
+
console.log('═'.repeat(50));
|
|
242
|
+
console.log(`\n Código: ${result.code}`);
|
|
243
|
+
console.log(` Expira: ${result.expires_in}`);
|
|
244
|
+
console.log(` Un solo uso — expira al usarse o en 24h`);
|
|
245
|
+
console.log('\n Comparte este código por Slack/WhatsApp.');
|
|
246
|
+
console.log(' El miembro del equipo corre:');
|
|
247
|
+
console.log(`\n akdd collab join ${result.code}\n`);
|
|
248
|
+
console.log('═'.repeat(50) + '\n');
|
|
249
|
+
}
|
|
250
|
+
|
|
179
251
|
// ─── SYNC UP (local → Turso) ──────────────────────────────────────────────────
|
|
180
252
|
|
|
181
253
|
async function syncUp(projectRoot) {
|
|
@@ -368,9 +440,13 @@ if (require.main === module) {
|
|
|
368
440
|
case 'init':
|
|
369
441
|
collabInit(projectRoot).catch(console.error);
|
|
370
442
|
break;
|
|
443
|
+
case 'invite':
|
|
444
|
+
collabInvite(projectRoot).catch(console.error);
|
|
445
|
+
break;
|
|
371
446
|
case 'join':
|
|
372
|
-
if (!arg1
|
|
373
|
-
console.error('Uso: collab-manager.cjs join <
|
|
447
|
+
if (!arg1) {
|
|
448
|
+
console.error('Uso: collab-manager.cjs join <código>');
|
|
449
|
+
console.error(' o: collab-manager.cjs join <url> <token>');
|
|
374
450
|
process.exit(1);
|
|
375
451
|
}
|
|
376
452
|
collabJoin(projectRoot, arg1, arg2).catch(console.error);
|
|
@@ -396,6 +472,7 @@ if (require.main === module) {
|
|
|
396
472
|
module.exports = {
|
|
397
473
|
collabInit,
|
|
398
474
|
collabJoin,
|
|
475
|
+
collabInvite,
|
|
399
476
|
syncUp,
|
|
400
477
|
syncDown,
|
|
401
478
|
status,
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Agentic KDD — Embeddings Engine v2.0
|
|
6
|
+
*
|
|
7
|
+
* Modelo DEFAULT: jina-embeddings-v2-base-code (Jina AI)
|
|
8
|
+
* - 137M parámetros entrenados en CODE + texto natural (bimodal NL-PL)
|
|
9
|
+
* - 768 dimensiones vs 384 de all-MiniLM
|
|
10
|
+
* - Entiende relaciones lógicas de tipos, AST, control de flujo
|
|
11
|
+
* - ~500MB instalado, 100% offline
|
|
12
|
+
*
|
|
13
|
+
* Fallback automático si jina no está: all-MiniLM-L6-v2 (384 dims, ~23MB)
|
|
14
|
+
*
|
|
15
|
+
* Gap cerrado: all-MiniLM-L6-v2 fue entrenado en NL natural, no en código.
|
|
16
|
+
* UniXcoder/jina mapean correctamente la semántica formal de lenguajes de programación.
|
|
17
|
+
*
|
|
18
|
+
* Uso:
|
|
19
|
+
* node embeddings.cjs embed "function calculateTotal(price, qty)"
|
|
20
|
+
* node embeddings.cjs status
|
|
21
|
+
* node embeddings.cjs install-jina
|
|
22
|
+
* node embeddings.cjs install-mini (fallback ligero)
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const path = require('path');
|
|
26
|
+
const fs = require('fs');
|
|
27
|
+
const { execSync } = require('child_process');
|
|
28
|
+
|
|
29
|
+
// ─── MODELOS ──────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
const MODELS = {
|
|
32
|
+
// Modelo primario: bimodal NL-PL, específico para código
|
|
33
|
+
JINA_CODE: {
|
|
34
|
+
id: 'jinaai/jina-embeddings-v2-base-code',
|
|
35
|
+
name: 'jina-embeddings-v2-base-code',
|
|
36
|
+
dims: 768,
|
|
37
|
+
size: '~500MB',
|
|
38
|
+
type: 'bimodal_nlpl',
|
|
39
|
+
description: 'Entrenado en código + texto. Entiende relaciones de tipos, AST, control de flujo.',
|
|
40
|
+
},
|
|
41
|
+
// Fallback: modelo NL general, ligero
|
|
42
|
+
MINI_LM: {
|
|
43
|
+
id: 'Xenova/all-MiniLM-L6-v2',
|
|
44
|
+
name: 'all-MiniLM-L6-v2',
|
|
45
|
+
dims: 384,
|
|
46
|
+
size: '~23MB',
|
|
47
|
+
type: 'natural_language',
|
|
48
|
+
description: 'Modelo NL general. Fallback cuando jina no está instalado.',
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// ─── ESTADO INTERNO ───────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
let _pipeline = null;
|
|
55
|
+
let _activeModel = null;
|
|
56
|
+
let _available = null;
|
|
57
|
+
|
|
58
|
+
// ─── DETECCIÓN DE MODELO DISPONIBLE ──────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
function detectAvailableModel(projectRoot) {
|
|
61
|
+
if (_available !== null) return _available;
|
|
62
|
+
|
|
63
|
+
// 1. Verificar si jina está en cache local del proyecto
|
|
64
|
+
const localCache = path.join(projectRoot || process.cwd(), '.agentic', '.model_cache');
|
|
65
|
+
if (fs.existsSync(localCache)) {
|
|
66
|
+
const jinaDir = path.join(localCache, 'models--jinaai--jina-embeddings-v2-base-code');
|
|
67
|
+
if (fs.existsSync(jinaDir)) {
|
|
68
|
+
_available = 'jina';
|
|
69
|
+
return 'jina';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 2. Verificar cache global de HuggingFace
|
|
74
|
+
const hfCache = path.join(require('os').homedir(), '.cache', 'huggingface', 'hub');
|
|
75
|
+
if (fs.existsSync(hfCache)) {
|
|
76
|
+
const jinaGlobal = path.join(hfCache, 'models--jinaai--jina-embeddings-v2-base-code');
|
|
77
|
+
if (fs.existsSync(jinaGlobal)) {
|
|
78
|
+
_available = 'jina';
|
|
79
|
+
return 'jina';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 3. Verificar si @xenova/transformers está instalado
|
|
84
|
+
try {
|
|
85
|
+
require.resolve('@xenova/transformers');
|
|
86
|
+
// MiniLM siempre descargable si transformers está
|
|
87
|
+
_available = 'mini';
|
|
88
|
+
return 'mini';
|
|
89
|
+
} catch {}
|
|
90
|
+
|
|
91
|
+
_available = false;
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ─── CARGAR PIPELINE ─────────────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
async function getPipeline(projectRoot) {
|
|
98
|
+
if (_pipeline) return { pipeline: _pipeline, model: _activeModel };
|
|
99
|
+
|
|
100
|
+
const available = detectAvailableModel(projectRoot || process.cwd());
|
|
101
|
+
|
|
102
|
+
if (!available) {
|
|
103
|
+
return { pipeline: null, model: null };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
process.env.TRANSFORMERS_VERBOSITY = 'error';
|
|
108
|
+
const { pipeline, env } = require('@xenova/transformers');
|
|
109
|
+
|
|
110
|
+
// Usar cache local del proyecto si existe
|
|
111
|
+
const localCache = path.join(projectRoot || process.cwd(), '.agentic', '.model_cache');
|
|
112
|
+
if (fs.existsSync(localCache)) env.cacheDir = localCache;
|
|
113
|
+
|
|
114
|
+
const model = available === 'jina' ? MODELS.JINA_CODE : MODELS.MINI_LM;
|
|
115
|
+
_activeModel = model;
|
|
116
|
+
|
|
117
|
+
_pipeline = await pipeline('feature-extraction', model.id, { quantized: true });
|
|
118
|
+
|
|
119
|
+
return { pipeline: _pipeline, model };
|
|
120
|
+
} catch (e) {
|
|
121
|
+
_available = false;
|
|
122
|
+
return { pipeline: null, model: null };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ─── GENERAR EMBEDDING ────────────────────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Genera embedding para código o texto.
|
|
130
|
+
* Retorna array de dims (768 con jina, 384 con mini) o null si no disponible.
|
|
131
|
+
*/
|
|
132
|
+
async function embed(text, projectRoot) {
|
|
133
|
+
const { pipeline: pipe } = await getPipeline(projectRoot);
|
|
134
|
+
if (!pipe) return null;
|
|
135
|
+
try {
|
|
136
|
+
const output = await pipe(text, { pooling: 'mean', normalize: true });
|
|
137
|
+
return Array.from(output.data);
|
|
138
|
+
} catch { return null; }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── SIMILITUD COSENO ────────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
function cosineSim(a, b) {
|
|
144
|
+
if (!a || !b || a.length !== b.length) return 0;
|
|
145
|
+
let dot = 0, normA = 0, normB = 0;
|
|
146
|
+
for (let i = 0; i < a.length; i++) {
|
|
147
|
+
dot += a[i] * b[i];
|
|
148
|
+
normA += a[i] * a[i];
|
|
149
|
+
normB += b[i] * b[i];
|
|
150
|
+
}
|
|
151
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
152
|
+
return denom === 0 ? 0 : dot / denom;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ─── BÚSQUEDA SEMÁNTICA ───────────────────────────────────────────────────────
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Búsqueda semántica sobre un array de items.
|
|
159
|
+
* @param {string} query - consulta en lenguaje natural o código
|
|
160
|
+
* @param {Array} items - [{id, texto, embedding}]
|
|
161
|
+
* @param {number} topK
|
|
162
|
+
*/
|
|
163
|
+
async function semanticSearch(query, items, topK = 10, projectRoot) {
|
|
164
|
+
const queryEmbed = await embed(query, projectRoot);
|
|
165
|
+
if (!queryEmbed) return items.slice(0, topK); // fallback sin embeddings
|
|
166
|
+
|
|
167
|
+
const scored = items
|
|
168
|
+
.filter(item => item.embedding && Array.isArray(item.embedding))
|
|
169
|
+
.map(item => ({
|
|
170
|
+
...item,
|
|
171
|
+
score: cosineSim(queryEmbed, item.embedding),
|
|
172
|
+
}))
|
|
173
|
+
.sort((a, b) => b.score - a.score)
|
|
174
|
+
.slice(0, topK);
|
|
175
|
+
|
|
176
|
+
return scored;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ─── STATUS ───────────────────────────────────────────────────────────────────
|
|
180
|
+
|
|
181
|
+
async function getStatus(projectRoot) {
|
|
182
|
+
const available = detectAvailableModel(projectRoot || process.cwd());
|
|
183
|
+
const model = available === 'jina' ? MODELS.JINA_CODE : available === 'mini' ? MODELS.MINI_LM : null;
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
available: !!available,
|
|
187
|
+
active_model: model?.name || 'none',
|
|
188
|
+
model_type: model?.type || 'none',
|
|
189
|
+
dims: model?.dims || 0,
|
|
190
|
+
size: model?.size || 'N/A',
|
|
191
|
+
description: model?.description || 'Sin modelo de embeddings instalado',
|
|
192
|
+
recommended: 'jina-embeddings-v2-base-code',
|
|
193
|
+
install_command: available === 'jina' ? 'Ya instalado ✅' : 'akdd jina-install',
|
|
194
|
+
gap_status: available === 'jina'
|
|
195
|
+
? '✅ Modelo bimodal NL-PL activo — semántica de código precisa'
|
|
196
|
+
: available === 'mini'
|
|
197
|
+
? '⚠️ Usando all-MiniLM-L6-v2 — no optimizado para código. Ejecutar: akdd jina-install'
|
|
198
|
+
: '❌ Sin embeddings — búsqueda semántica desactivada. Ejecutar: akdd embed-install',
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ─── INSTALACIÓN ─────────────────────────────────────────────────────────────
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Instalar jina-embeddings-v2-base-code (modelo primario recomendado).
|
|
206
|
+
* ~500MB. Se guarda en .agentic/.model_cache para uso offline.
|
|
207
|
+
*/
|
|
208
|
+
async function installJina(projectRoot) {
|
|
209
|
+
projectRoot = projectRoot || process.cwd();
|
|
210
|
+
console.log('\n[EMBEDDINGS] Instalando jina-embeddings-v2-base-code...');
|
|
211
|
+
console.log('[EMBEDDINGS] Tamaño: ~500MB. Puede tomar 5-10 minutos.');
|
|
212
|
+
console.log('[EMBEDDINGS] Modelo bimodal NL-PL — entrenado específicamente en código.\n');
|
|
213
|
+
|
|
214
|
+
// Verificar que @xenova/transformers está instalado
|
|
215
|
+
try {
|
|
216
|
+
require.resolve('@xenova/transformers');
|
|
217
|
+
} catch {
|
|
218
|
+
console.log('[EMBEDDINGS] Instalando @xenova/transformers primero...');
|
|
219
|
+
execSync('npm install @xenova/transformers --save-dev', {
|
|
220
|
+
stdio: 'inherit',
|
|
221
|
+
cwd: projectRoot,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Descargar el modelo
|
|
226
|
+
try {
|
|
227
|
+
process.env.TRANSFORMERS_VERBOSITY = 'info';
|
|
228
|
+
const { pipeline, env } = require('@xenova/transformers');
|
|
229
|
+
const localCache = path.join(projectRoot, '.agentic', '.model_cache');
|
|
230
|
+
fs.mkdirSync(localCache, { recursive: true });
|
|
231
|
+
env.cacheDir = localCache;
|
|
232
|
+
|
|
233
|
+
console.log('[EMBEDDINGS] Descargando modelo...');
|
|
234
|
+
const pipe = await pipeline('feature-extraction', MODELS.JINA_CODE.id, { quantized: true });
|
|
235
|
+
|
|
236
|
+
// Test
|
|
237
|
+
const testEmbed = await pipe('function test() { return 1; }', { pooling: 'mean', normalize: true });
|
|
238
|
+
if (testEmbed && testEmbed.data.length > 0) {
|
|
239
|
+
console.log(`\n[EMBEDDINGS] ✅ jina-embeddings-v2-base-code instalado.`);
|
|
240
|
+
console.log(`[EMBEDDINGS] Dimensiones: ${testEmbed.data.length}`);
|
|
241
|
+
console.log(`[EMBEDDINGS] Búsqueda semántica de código ahora es precisa.\n`);
|
|
242
|
+
_available = 'jina';
|
|
243
|
+
_pipeline = pipe;
|
|
244
|
+
}
|
|
245
|
+
} catch (e) {
|
|
246
|
+
console.error('[EMBEDDINGS] Error instalando jina:', e.message);
|
|
247
|
+
console.log('[EMBEDDINGS] Alternativa: akdd embed-install (all-MiniLM-L6-v2, 23MB)\n');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Instalar all-MiniLM-L6-v2 (fallback ligero, ~23MB).
|
|
253
|
+
*/
|
|
254
|
+
async function installMini(projectRoot) {
|
|
255
|
+
projectRoot = projectRoot || process.cwd();
|
|
256
|
+
console.log('\n[EMBEDDINGS] Instalando all-MiniLM-L6-v2 (modelo ligero, 23MB)...');
|
|
257
|
+
console.log('[EMBEDDINGS] Nota: este modelo es para texto natural, no optimizado para código.');
|
|
258
|
+
console.log('[EMBEDDINGS] Para precisión máxima en código: akdd jina-install\n');
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
require.resolve('@xenova/transformers');
|
|
262
|
+
} catch {
|
|
263
|
+
execSync('npm install @xenova/transformers --save-dev', { stdio: 'inherit', cwd: projectRoot });
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
const { pipeline, env } = require('@xenova/transformers');
|
|
268
|
+
const localCache = path.join(projectRoot, '.agentic', '.model_cache');
|
|
269
|
+
fs.mkdirSync(localCache, { recursive: true });
|
|
270
|
+
env.cacheDir = localCache;
|
|
271
|
+
|
|
272
|
+
const pipe = await pipeline('feature-extraction', MODELS.MINI_LM.id, { quantized: true });
|
|
273
|
+
console.log('\n[EMBEDDINGS] ✅ all-MiniLM-L6-v2 instalado como fallback.\n');
|
|
274
|
+
_available = 'mini';
|
|
275
|
+
_pipeline = pipe;
|
|
276
|
+
} catch (e) {
|
|
277
|
+
console.error('[EMBEDDINGS] Error:', e.message);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ─── CLI ──────────────────────────────────────────────────────────────────────
|
|
282
|
+
|
|
283
|
+
if (require.main === module) {
|
|
284
|
+
const [,, cmd, ...args] = process.argv;
|
|
285
|
+
const projectRoot = process.cwd();
|
|
286
|
+
|
|
287
|
+
switch (cmd) {
|
|
288
|
+
case 'embed':
|
|
289
|
+
if (!args[0]) { console.error('Uso: embeddings.cjs embed "<texto>"'); break; }
|
|
290
|
+
embed(args.join(' '), projectRoot).then(v => {
|
|
291
|
+
if (!v) console.log('Sin embeddings disponibles. Ejecutar: akdd jina-install');
|
|
292
|
+
else console.log(`Vector [${v.length} dims]: [${v.slice(0,4).map(x=>x.toFixed(4)).join(', ')}...]`);
|
|
293
|
+
});
|
|
294
|
+
break;
|
|
295
|
+
|
|
296
|
+
case 'status':
|
|
297
|
+
getStatus(projectRoot).then(s => {
|
|
298
|
+
console.log('\n=== Embeddings Status ===');
|
|
299
|
+
console.log(`Modelo activo: ${s.active_model}`);
|
|
300
|
+
console.log(`Tipo: ${s.model_type}`);
|
|
301
|
+
console.log(`Dimensiones: ${s.dims}`);
|
|
302
|
+
console.log(`Gap: ${s.gap_status}`);
|
|
303
|
+
console.log(`Instalar: ${s.install_command}\n`);
|
|
304
|
+
});
|
|
305
|
+
break;
|
|
306
|
+
|
|
307
|
+
case 'install-jina':
|
|
308
|
+
installJina(projectRoot).catch(console.error);
|
|
309
|
+
break;
|
|
310
|
+
|
|
311
|
+
case 'install-mini':
|
|
312
|
+
installMini(projectRoot).catch(console.error);
|
|
313
|
+
break;
|
|
314
|
+
|
|
315
|
+
default:
|
|
316
|
+
console.log('Uso: embeddings.cjs [embed <text> | status | install-jina | install-mini]');
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
module.exports = { embed, cosineSim, semanticSearch, getStatus, installJina, installMini, detectAvailableModel, MODELS };
|