@ssolis-ti/mcp-compra-agil 2.1.0 → 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 +31 -11
- package/dist/api/compra-agil-client.d.ts +35 -1
- package/dist/api/compra-agil-client.d.ts.map +1 -1
- package/dist/api/compra-agil-client.js +69 -4
- package/dist/api/compra-agil-client.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/reports/templates/radar-oportunidades.d.ts +1 -1
- package/dist/reports/templates/radar-oportunidades.js +2 -2
- package/dist/reports/templates/radar-oportunidades.js.map +1 -1
- package/dist/resources/glosario.d.ts.map +1 -1
- package/dist/resources/glosario.js +6 -2
- package/dist/resources/glosario.js.map +1 -1
- package/dist/services/monitor.js +1 -1
- package/dist/services/monitor.js.map +1 -1
- package/dist/tools/analizar-precios-mercado.js +2 -2
- package/dist/tools/auditar-desiertas.js +2 -2
- package/dist/tools/detalle-oc.d.ts.map +1 -1
- package/dist/tools/detalle-oc.js +2 -3
- package/dist/tools/detalle-oc.js.map +1 -1
- package/dist/tools/documentos.d.ts.map +1 -1
- package/dist/tools/documentos.js +68 -37
- package/dist/tools/documentos.js.map +1 -1
- package/dist/tools/estadisticas-uso.d.ts.map +1 -1
- package/dist/tools/estadisticas-uso.js +12 -2
- package/dist/tools/estadisticas-uso.js.map +1 -1
- package/dist/tools/generar-borrador.d.ts +25 -1
- package/dist/tools/generar-borrador.d.ts.map +1 -1
- package/dist/tools/generar-borrador.js +96 -78
- package/dist/tools/generar-borrador.js.map +1 -1
- package/dist/tools/radar-oportunidades.d.ts +4 -1
- package/dist/tools/radar-oportunidades.d.ts.map +1 -1
- package/dist/tools/radar-oportunidades.js +24 -2
- package/dist/tools/radar-oportunidades.js.map +1 -1
- package/dist/tools/verificar-oc.d.ts.map +1 -1
- package/dist/tools/verificar-oc.js +30 -4
- package/dist/tools/verificar-oc.js.map +1 -1
- package/dist/utils/cache.d.ts +53 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +131 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/doc-search.d.ts +52 -0
- package/dist/utils/doc-search.d.ts.map +1 -0
- package/dist/utils/doc-search.js +97 -0
- package/dist/utils/doc-search.js.map +1 -0
- package/dist/utils/error-handler.d.ts.map +1 -1
- package/dist/utils/error-handler.js +4 -6
- package/dist/utils/error-handler.js.map +1 -1
- package/dist/utils/rate-limiter.d.ts +37 -2
- package/dist/utils/rate-limiter.d.ts.map +1 -1
- package/dist/utils/rate-limiter.js +101 -13
- package/dist/utils/rate-limiter.js.map +1 -1
- package/package.json +1 -1
package/dist/tools/documentos.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from 'fs';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { PDFParse } from 'pdf-parse';
|
|
5
5
|
import { resolveDocsDir, listSupportedDocs } from '../utils/docs-locator.js';
|
|
6
|
+
import { buscarEnTexto } from '../utils/doc-search.js';
|
|
6
7
|
import { safeError } from '../utils/redact.js';
|
|
7
8
|
const DOCS_DIR = resolveDocsDir();
|
|
8
9
|
/**
|
|
@@ -28,18 +29,23 @@ export function registerDocumentosTools(server) {
|
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
else {
|
|
32
|
+
// Verificado en septiembre 2026: este endpoint heredado responde 404
|
|
33
|
+
// para los adjuntos de Compra Ágil, aun con IDs numéricos válidos
|
|
34
|
+
// entregados por la API. Se sigue ofreciendo por si el portal lo
|
|
35
|
+
// restablece, pero la ficha va primero y sin prometer que funcionará.
|
|
31
36
|
const directUrl = `https://www.mercadopublico.cl/FichaLicitacion/RetornaDocumento.aspx?id=${args.id_documento}`;
|
|
32
37
|
return {
|
|
33
38
|
content: [{
|
|
34
39
|
type: 'text',
|
|
35
|
-
text: `
|
|
40
|
+
text: `Para acceder al adjunto ${args.id_documento}, abre la ficha pública del proceso (no requiere iniciar sesión):\n${fichaUrl}\n\nExiste además un enlace heredado de descarga directa, pero se comprobó que hoy responde 404 para los adjuntos de Compra Ágil, así que probablemente no funcione:\n${directUrl}`,
|
|
36
41
|
}],
|
|
37
42
|
};
|
|
38
43
|
}
|
|
39
44
|
});
|
|
40
45
|
// ─── 2. DESCARGAR Y LEER DOCUMENTO DE PROCESO (REMOTO) ───────────────
|
|
41
46
|
server.registerTool('descargar_y_leer_documento', {
|
|
42
|
-
description:
|
|
47
|
+
description: `Intenta descargar un adjunto de Compra Ágil (bases técnicas/administrativas) y extraer su texto.
|
|
48
|
+
⚠ IMPORTANTE: para los IDs numéricos —que son los que entrega esta API— el portal ya NO sirve el archivo, así que la herramienta responde de inmediato con el enlace a la ficha pública en vez de intentar una descarga que se sabe fallida. Si necesitas las especificaciones para cotizar, tendrás que abrir esa ficha en un navegador: el enlace del adjunto lo genera JavaScript y no existe una URL que un programa pueda pedir.`,
|
|
43
49
|
inputSchema: {
|
|
44
50
|
id_documento: z.string().describe('ID único del documento. Ej: "123456" o un UUID.'),
|
|
45
51
|
codigo_compra: z.string().optional().describe('Código de la Compra Ágil asociada (Ej: "2494-141-COT26"). Permite guiar al usuario a la ficha pública en caso de fallar la descarga.'),
|
|
@@ -49,29 +55,58 @@ export function registerDocumentosTools(server) {
|
|
|
49
55
|
}, async (args) => {
|
|
50
56
|
try {
|
|
51
57
|
const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(args.id_documento);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
// ⚠ NO se intenta la descarga de IDs numéricos: se comprobó que el
|
|
59
|
+
// endpoint heredado responde 404 para todos los adjuntos de Compra
|
|
60
|
+
// Ágil (IDs 1855508 y 1854909, de procesos distintos), y la causa es
|
|
61
|
+
// estructural — en la ficha el enlace es un <a> con href vacío, la
|
|
62
|
+
// descarga la dispara JavaScript y no hay URL estática que pedir.
|
|
63
|
+
// Gastar una petición y esperar su timeout para confirmar un fallo
|
|
64
|
+
// conocido solo retrasa la única respuesta útil, que es el enlace.
|
|
65
|
+
//
|
|
66
|
+
// Los UUID SÍ se intentan: usan otro endpoint (adjunto.mercadopublico.cl)
|
|
67
|
+
// que nunca se pudo ejercitar, así que no se da por muerto sin prueba.
|
|
68
|
+
// Si algún día vuelven a servirse los numéricos, `scripts/debug-*.ts`
|
|
69
|
+
// y esta guarda son el punto por donde revertirlo.
|
|
70
|
+
if (!isUuid) {
|
|
71
|
+
const ficha = args.codigo_compra
|
|
72
|
+
? `\n\nÁbrelo desde la ficha pública del proceso (en un navegador, sin iniciar sesión):\nhttps://buscador.mercadopublico.cl/ficha?code=${args.codigo_compra}`
|
|
73
|
+
: '\n\nBusca el código de la compra en https://buscador.mercadopublico.cl y abre su ficha para ver el adjunto.';
|
|
74
|
+
return {
|
|
75
|
+
content: [{
|
|
76
|
+
type: 'text',
|
|
77
|
+
text: `El adjunto ${args.id_documento} no se puede descargar por programa: Mercado Público dejó de servir los adjuntos de Compra Ágil por enlace directo, y en la ficha el archivo se descarga mediante JavaScript, sin una URL que se pueda pedir.${ficha}\n\nSi necesitas las especificaciones técnicas para cotizar, suelen estar solo en ese adjunto, así que conviene abrirlo ahí.`,
|
|
78
|
+
}],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const url = `https://adjunto.mercadopublico.cl/adjunto-compra-agil/descargar/${args.id_documento}`;
|
|
55
82
|
// Descargar PDF
|
|
56
83
|
const response = await fetch(url, {
|
|
57
84
|
headers: {
|
|
58
85
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
|
59
86
|
}
|
|
60
87
|
});
|
|
61
|
-
|
|
88
|
+
// ⚠ 404 se trata igual que 401/403 y no como un fallo inesperado:
|
|
89
|
+
// verificado contra el servicio real (septiembre 2026) que el endpoint
|
|
90
|
+
// heredado RetornaDocumento.aspx responde 404 para los adjuntos de
|
|
91
|
+
// Compra Ágil, incluso con IDs numéricos entregados por la propia API
|
|
92
|
+
// (probados 1855508 y 1854909, de procesos distintos). Para el usuario
|
|
93
|
+
// la situación práctica es la misma que un bloqueo: hay que ir a la
|
|
94
|
+
// ficha. Devolver un "Error HTTP 404" pelado hacía que el modelo
|
|
95
|
+
// informara una falla técnica en vez de la vía alternativa que sí sirve.
|
|
96
|
+
if (!response.ok) {
|
|
62
97
|
const fichaMsg = args.codigo_compra
|
|
63
|
-
? `\n\
|
|
64
|
-
: '\n\
|
|
98
|
+
? `\n\nDescarga el archivo desde la ficha pública del proceso (se abre en el navegador, sin iniciar sesión):\nhttps://buscador.mercadopublico.cl/ficha?code=${args.codigo_compra}`
|
|
99
|
+
: '\n\nBusca el código de la compra en https://buscador.mercadopublico.cl para descargar el archivo desde su ficha.';
|
|
100
|
+
const causa = response.status === 404
|
|
101
|
+
? `el portal ya no expone este adjunto por descarga directa (HTTP 404). Es el comportamiento observado para los adjuntos de Compra Ágil, no un error de tu consulta`
|
|
102
|
+
: `el servidor de Mercado Público requiere autenticación (Clave Única) o bloquea las solicitudes programáticas (HTTP ${response.status})`;
|
|
65
103
|
return {
|
|
66
104
|
content: [{
|
|
67
105
|
type: 'text',
|
|
68
|
-
text: `No
|
|
106
|
+
text: `No fue posible descargar el documento ${args.id_documento} automáticamente: ${causa}.${fichaMsg}\n\nSi necesitas las especificaciones técnicas para cotizar, ábrelo desde ese enlace: suelen estar solo en el adjunto.`,
|
|
69
107
|
}],
|
|
70
108
|
};
|
|
71
109
|
}
|
|
72
|
-
if (!response.ok) {
|
|
73
|
-
throw new Error(`Error HTTP al intentar descargar el documento: ${response.status} ${response.statusText}`);
|
|
74
|
-
}
|
|
75
110
|
const arrayBuffer = await response.arrayBuffer();
|
|
76
111
|
const buffer = Buffer.from(arrayBuffer);
|
|
77
112
|
// Parsear PDF
|
|
@@ -143,7 +178,7 @@ export function registerDocumentosTools(server) {
|
|
|
143
178
|
server.registerTool('consultar_documentos_locales', {
|
|
144
179
|
description: 'Busca y lee información dentro de los manuales, normativas o guías de Compra Ágil almacenados localmente en la carpeta docs/ (soporta formatos .pdf, .txt, .md).',
|
|
145
180
|
inputSchema: {
|
|
146
|
-
query: z.string().optional().describe('
|
|
181
|
+
query: z.string().optional().describe('Qué buscar. Admite tanto un término suelto ("multas", "garantía") como una pregunta en lenguaje natural ("¿qué multas me pueden aplicar?"): la consulta se descompone en términos y se ignoran acentos y palabras vacías. Si se omite, lista los documentos disponibles.'),
|
|
147
182
|
max_caracteres: z.number().min(500).max(15000).default(3000).optional().describe('Cantidad máxima de texto a retornar de cada coincidencia.'),
|
|
148
183
|
},
|
|
149
184
|
}, async (args) => {
|
|
@@ -173,8 +208,11 @@ export function registerDocumentosTools(server) {
|
|
|
173
208
|
}],
|
|
174
209
|
};
|
|
175
210
|
}
|
|
176
|
-
const searchTerm = args.query.toLowerCase();
|
|
177
211
|
const results = [];
|
|
212
|
+
// Términos que sí aparecieron en algún documento, para poder explicar
|
|
213
|
+
// un resultado vacío en vez de afirmar que no existe información.
|
|
214
|
+
const terminosEncontrados = new Set();
|
|
215
|
+
let terminosConsulta = [];
|
|
178
216
|
for (const file of files) {
|
|
179
217
|
const filePath = path.join(DOCS_DIR, file);
|
|
180
218
|
const ext = path.extname(file).toLowerCase();
|
|
@@ -189,28 +227,18 @@ export function registerDocumentosTools(server) {
|
|
|
189
227
|
else {
|
|
190
228
|
fileText = fs.readFileSync(filePath, 'utf8');
|
|
191
229
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
context.push(`[Siguiente] ${lines[i + 1]?.trim()}`);
|
|
205
|
-
fileMatches.push(context.join('\n'));
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
if (fileMatches.length > 0) {
|
|
209
|
-
const limit = args.max_caracteres || 3000;
|
|
210
|
-
const matchesText = fileMatches.join('\n\n---\n\n');
|
|
211
|
-
const truncated = matchesText.length > limit ? `${matchesText.substring(0, limit)}... [TRUNCADO]` : matchesText;
|
|
212
|
-
results.push(`### Archivo: ${file}\n\n${truncated}`);
|
|
213
|
-
}
|
|
230
|
+
const hallazgo = buscarEnTexto(fileText, args.query);
|
|
231
|
+
terminosConsulta = hallazgo.terminos;
|
|
232
|
+
for (const f of hallazgo.fragmentos) {
|
|
233
|
+
for (const t of f.terminos)
|
|
234
|
+
terminosEncontrados.add(t);
|
|
235
|
+
}
|
|
236
|
+
if (hallazgo.fragmentos.length > 0) {
|
|
237
|
+
const limit = args.max_caracteres || 3000;
|
|
238
|
+
const matchesText = hallazgo.fragmentos.map((f) => f.texto).join('\n\n---\n\n');
|
|
239
|
+
const truncated = matchesText.length > limit ? `${matchesText.substring(0, limit)}... [TRUNCADO]` : matchesText;
|
|
240
|
+
const cubiertos = [...new Set(hallazgo.fragmentos.flatMap((f) => f.terminos))];
|
|
241
|
+
results.push(`### Archivo: ${file}\n(términos encontrados aquí: ${cubiertos.join(', ')})\n\n${truncated}`);
|
|
214
242
|
}
|
|
215
243
|
}
|
|
216
244
|
catch (e) {
|
|
@@ -218,10 +246,13 @@ export function registerDocumentosTools(server) {
|
|
|
218
246
|
}
|
|
219
247
|
}
|
|
220
248
|
if (results.length === 0) {
|
|
249
|
+
const detalle = terminosConsulta.length > 0
|
|
250
|
+
? `\n\nLa consulta se buscó como los términos: ${terminosConsulta.join(', ')}. Ninguno aparece en los documentos. Prueba con sinónimos o con un término más general.`
|
|
251
|
+
: '';
|
|
221
252
|
return {
|
|
222
253
|
content: [{
|
|
223
254
|
type: 'text',
|
|
224
|
-
text: `No se encontraron coincidencias para "${args.query}" en ninguno de los ${files.length} documentos locales en "docs/"
|
|
255
|
+
text: `No se encontraron coincidencias para "${args.query}" en ninguno de los ${files.length} documentos locales en "docs/".${detalle}`,
|
|
225
256
|
}],
|
|
226
257
|
};
|
|
227
258
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentos.js","sourceRoot":"","sources":["../../src/tools/documentos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;AAElC;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAiB;IAEvD,wEAAwE;IACxE,MAAM,CAAC,YAAY,CACjB,0BAA0B,EAC1B;QACE,WAAW,EAAE,yHAAyH;QACtI,WAAW,EAAE;YACX,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6FAA6F,CAAC;YAChI,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iHAAiH,CAAC;SACtJ;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,MAAM,MAAM,GAAG,iEAAiE,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACzG,MAAM,QAAQ,GAAG,iDAAiD,IAAI,CAAC,aAAa,EAAE,CAAC;QAEvF,IAAI,MAAM,EAAE,CAAC;YACX,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,4BAA4B,IAAI,CAAC,YAAY,2WAA2W,QAAQ,EAAE;qBACza,CAAC;aACH,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,GAAG,0EAA0E,IAAI,CAAC,YAAY,EAAE,CAAC;YAChH,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"documentos.js","sourceRoot":"","sources":["../../src/tools/documentos.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"estadisticas-uso.d.ts","sourceRoot":"","sources":["../../src/tools/estadisticas-uso.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"estadisticas-uso.d.ts","sourceRoot":"","sources":["../../src/tools/estadisticas-uso.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAMhE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAyBzF"}
|
|
@@ -5,16 +5,26 @@
|
|
|
5
5
|
* para la API de Compra Ágil de Mercado Público.
|
|
6
6
|
*/
|
|
7
7
|
const TOOL_NAME = 'obtener_estadisticas_uso';
|
|
8
|
-
const TOOL_DESCRIPTION =
|
|
8
|
+
const TOOL_DESCRIPTION = `Informa cuántas consultas a la API lleva hecha esta instalación en el día UTC en curso, y si ya se recibió un 429 por cuota agotada.
|
|
9
|
+
IMPORTANTE: es un conteo LOCAL, no el saldo oficial del ticket. La API no publica cuánta cuota queda, y el ticket puede estar siendo consumido también por otras herramientas o equipos. Sirve para moderar el gasto, no para afirmar cuántas consultas quedan.`;
|
|
9
10
|
export function registerEstadisticasUso(server, client) {
|
|
10
11
|
server.registerTool(TOOL_NAME, {
|
|
11
12
|
description: TOOL_DESCRIPTION,
|
|
12
13
|
}, async () => {
|
|
13
14
|
const stats = client.getRateLimitStats();
|
|
15
|
+
const salida = {
|
|
16
|
+
_alcance: 'Conteo local de esta instalación para el día UTC en curso. La API no expone el saldo real del ticket; si otras herramientas usan el mismo ticket, el consumo real es mayor que este número.',
|
|
17
|
+
requests_hechos_hoy: stats.requestsToday,
|
|
18
|
+
cuota_agotada: stats.isLimited,
|
|
19
|
+
reset_estimado: stats.resetTime,
|
|
20
|
+
_nota: stats.isLimited
|
|
21
|
+
? 'Se recibió un 429: la cuota diaria del ticket está agotada hasta el reset indicado. Evita nuevas consultas hasta entonces.'
|
|
22
|
+
: 'No se ha recibido ningún 429 en esta jornada. Eso NO garantiza que quede cuota: solo que esta instalación aún no ha chocado con el límite.',
|
|
23
|
+
};
|
|
14
24
|
return {
|
|
15
25
|
content: [{
|
|
16
26
|
type: 'text',
|
|
17
|
-
text: JSON.stringify(
|
|
27
|
+
text: JSON.stringify(salida, null, 2),
|
|
18
28
|
}],
|
|
19
29
|
};
|
|
20
30
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"estadisticas-uso.js","sourceRoot":"","sources":["../../src/tools/estadisticas-uso.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,SAAS,GAAG,0BAA0B,CAAC;AAC7C,MAAM,gBAAgB,GAAG,
|
|
1
|
+
{"version":3,"file":"estadisticas-uso.js","sourceRoot":"","sources":["../../src/tools/estadisticas-uso.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,SAAS,GAAG,0BAA0B,CAAC;AAC7C,MAAM,gBAAgB,GAAG;gQACuO,CAAC;AAEjQ,MAAM,UAAU,uBAAuB,CAAC,MAAiB,EAAE,MAAwB;IACjF,MAAM,CAAC,YAAY,CACjB,SAAS,EACT;QACE,WAAW,EAAE,gBAAgB;KAC9B,EACD,KAAK,IAAI,EAAE;QACT,MAAM,KAAK,GAAG,MAAM,CAAC,iBAAiB,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG;YACb,QAAQ,EAAE,6LAA6L;YACvM,mBAAmB,EAAE,KAAK,CAAC,aAAa;YACxC,aAAa,EAAE,KAAK,CAAC,SAAS;YAC9B,cAAc,EAAE,KAAK,CAAC,SAAS;YAC/B,KAAK,EAAE,KAAK,CAAC,SAAS;gBACpB,CAAC,CAAC,4HAA4H;gBAC9H,CAAC,CAAC,4IAA4I;SACjJ,CAAC;QACF,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;iBACtC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,28 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { CompraAgilClient } from '../api/compra-agil-client.js';
|
|
2
|
+
import { CompraAgilClient, CompraAgilDetalle } from '../api/compra-agil-client.js';
|
|
3
|
+
/** Precio de relleno cuando no se pudo estimar nada. Hay que advertirlo. */
|
|
4
|
+
export declare const PRECIO_PLACEHOLDER = 1000;
|
|
5
|
+
export interface EstimacionPrecio {
|
|
6
|
+
precio: number;
|
|
7
|
+
fuente: string;
|
|
8
|
+
/** `false` ⇒ es el placeholder y el borrador debe advertirlo. */
|
|
9
|
+
sugerido: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Decide el precio unitario del borrador, en orden de preferencia:
|
|
13
|
+
* 1. el que ingresó el usuario,
|
|
14
|
+
* 2. el percentil 25 de lo que cotizó el mercado en procesos similares,
|
|
15
|
+
* 3. el presupuesto del comprador menos 10%,
|
|
16
|
+
* 4. un placeholder de $1.000, que se advierte explícitamente.
|
|
17
|
+
*
|
|
18
|
+
* ⚠ POR QUÉ EL PASO 3 VIVE FUERA DEL try: antes, la consulta de precios de
|
|
19
|
+
* mercado y el respaldo por presupuesto estaban dentro del mismo bloque, así
|
|
20
|
+
* que CUALQUIER fallo de la API durante la consulta —un 429 por cuota
|
|
21
|
+
* agotada, típicamente— saltaba también el respaldo y el borrador salía con
|
|
22
|
+
* $1.000, pese a que el presupuesto ya estaba en la mano desde el detalle y
|
|
23
|
+
* no requería ninguna llamada adicional. Detectado en auditoría: un llamado
|
|
24
|
+
* de $4.800.000 generó un borrador de $1.000 por este camino.
|
|
25
|
+
*/
|
|
26
|
+
export declare function estimarPrecioUnitario(client: Pick<CompraAgilClient, 'buscar' | 'detalle'>, detalle: CompraAgilDetalle, precioPersonalizado?: number): Promise<EstimacionPrecio>;
|
|
3
27
|
export declare function registerGenerarBorrador(server: McpServer, client: CompraAgilClient): void;
|
|
4
28
|
//# sourceMappingURL=generar-borrador.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generar-borrador.d.ts","sourceRoot":"","sources":["../../src/tools/generar-borrador.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"generar-borrador.d.ts","sourceRoot":"","sources":["../../src/tools/generar-borrador.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAMnF,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,QAAQ,EAAE,OAAO,CAAC;CACnB;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,GAAG,SAAS,CAAC,EACpD,OAAO,EAAE,iBAAiB,EAC1B,mBAAmB,CAAC,EAAE,MAAM,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAwE3B;AAgBD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CA+GzF"}
|
|
@@ -3,6 +3,98 @@ import { CompraAgilApiError } from '../utils/error-handler.js';
|
|
|
3
3
|
import { logger } from '../utils/logger.js';
|
|
4
4
|
import { extraerPrecioUnitario, percentil } from '../utils/quotation.js';
|
|
5
5
|
import { safeError } from '../utils/redact.js';
|
|
6
|
+
/** Precio de relleno cuando no se pudo estimar nada. Hay que advertirlo. */
|
|
7
|
+
export const PRECIO_PLACEHOLDER = 1000;
|
|
8
|
+
/** Presupuesto del comprador, mirando también el estimado. */
|
|
9
|
+
function presupuestoDelComprador(detalle) {
|
|
10
|
+
const p = detalle.presupuesto;
|
|
11
|
+
return p?.monto_disponible_clp || p?.monto_disponible || p?.presupuesto_estimado || 0;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Decide el precio unitario del borrador, en orden de preferencia:
|
|
15
|
+
* 1. el que ingresó el usuario,
|
|
16
|
+
* 2. el percentil 25 de lo que cotizó el mercado en procesos similares,
|
|
17
|
+
* 3. el presupuesto del comprador menos 10%,
|
|
18
|
+
* 4. un placeholder de $1.000, que se advierte explícitamente.
|
|
19
|
+
*
|
|
20
|
+
* ⚠ POR QUÉ EL PASO 3 VIVE FUERA DEL try: antes, la consulta de precios de
|
|
21
|
+
* mercado y el respaldo por presupuesto estaban dentro del mismo bloque, así
|
|
22
|
+
* que CUALQUIER fallo de la API durante la consulta —un 429 por cuota
|
|
23
|
+
* agotada, típicamente— saltaba también el respaldo y el borrador salía con
|
|
24
|
+
* $1.000, pese a que el presupuesto ya estaba en la mano desde el detalle y
|
|
25
|
+
* no requería ninguna llamada adicional. Detectado en auditoría: un llamado
|
|
26
|
+
* de $4.800.000 generó un borrador de $1.000 por este camino.
|
|
27
|
+
*/
|
|
28
|
+
export async function estimarPrecioUnitario(client, detalle, precioPersonalizado) {
|
|
29
|
+
if (precioPersonalizado !== undefined && precioPersonalizado > 0) {
|
|
30
|
+
return {
|
|
31
|
+
precio: precioPersonalizado,
|
|
32
|
+
fuente: 'Precio neto ingresado por el usuario',
|
|
33
|
+
sugerido: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const keyword = detalle.productos_solicitados?.[0]?.nombre || detalle.nombre || '';
|
|
37
|
+
const precios = [];
|
|
38
|
+
if (keyword) {
|
|
39
|
+
try {
|
|
40
|
+
logger.info(`generar_borrador_cotizacion: Consultando precios cotizados por el mercado para "${keyword}"`);
|
|
41
|
+
// Solo `desierta`: medido contra la API real, es el único estado que
|
|
42
|
+
// publica cotizaciones (desierta 5/8 procesos con precios; cerrada 0/8).
|
|
43
|
+
// `proveedor_seleccionado` devuelve 0 resultados.
|
|
44
|
+
const busqueda = await client.buscar({
|
|
45
|
+
q: keyword,
|
|
46
|
+
estado: 'desierta',
|
|
47
|
+
tamano_pagina: 50,
|
|
48
|
+
numero_pagina: 1,
|
|
49
|
+
});
|
|
50
|
+
for (const item of (busqueda.items || []).slice(0, 5)) {
|
|
51
|
+
try {
|
|
52
|
+
const det = await client.detalle(item.codigo);
|
|
53
|
+
// Se toman TODAS las cotizaciones, incluidas las inadmisibles: en los
|
|
54
|
+
// procesos desiertos casi todas lo son (por eso quedaron desiertos), y
|
|
55
|
+
// el precio ofertado sigue siendo señal de mercado. Filtrarlas dejaba
|
|
56
|
+
// la muestra vacía. La API nunca marca un ganador, así que la
|
|
57
|
+
// referencia es lo que ofertó la competencia.
|
|
58
|
+
for (const prov of det.proveedores_cotizando ?? []) {
|
|
59
|
+
const unitario = extraerPrecioUnitario(prov, keyword);
|
|
60
|
+
if (unitario !== null)
|
|
61
|
+
precios.push(unitario);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Un histórico que falla no invalida el resto de la muestra.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
logger.warn(`generar_borrador_cotizacion: No se pudo consultar precios de mercado: ${safeError(err)}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (precios.length > 0) {
|
|
74
|
+
precios.sort((a, b) => a - b);
|
|
75
|
+
// Percentil 25 de lo cotizado: ubica la oferta en el cuarto más económico
|
|
76
|
+
// sin regalar margen, y resiste valores atípicos mejor que un promedio.
|
|
77
|
+
return {
|
|
78
|
+
precio: percentil(precios, 25),
|
|
79
|
+
fuente: `Sugerencia automática: percentil 25 de ${precios.length} precio(s) cotizado(s) por el mercado en procesos similares (NO son precios adjudicados: la API no los expone)`,
|
|
80
|
+
sugerido: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const presupuesto = presupuestoDelComprador(detalle);
|
|
84
|
+
if (presupuesto > 0) {
|
|
85
|
+
const cantidadTotal = detalle.productos_solicitados?.reduce((acc, p) => acc + p.cantidad, 0) || 1;
|
|
86
|
+
return {
|
|
87
|
+
precio: Math.round((presupuesto * 0.9) / cantidadTotal),
|
|
88
|
+
fuente: 'Sugerencia automática: presupuesto del comprador descontado 10% (no hubo cotizaciones de mercado comparables)',
|
|
89
|
+
sugerido: true,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
precio: PRECIO_PLACEHOLDER,
|
|
94
|
+
fuente: `Valor por defecto (placeholder de $${PRECIO_PLACEHOLDER.toLocaleString('es-CL')})`,
|
|
95
|
+
sugerido: false,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
6
98
|
const TOOL_NAME = 'generar_borrador_cotizacion';
|
|
7
99
|
const TOOL_DESCRIPTION = `Genera un borrador estructurado en formato JSON para presentar una cotización formal a un llamado de Compra Ágil activa.
|
|
8
100
|
Calcula automáticamente los valores netos, impuestos (19% IVA de Chile) y montos brutos, sugiriendo un precio unitario de mercado si no se ingresa uno personalizado.`;
|
|
@@ -30,88 +122,14 @@ export function registerGenerarBorrador(server, client) {
|
|
|
30
122
|
advertencias.push('rut_proveedor es un valor PLACEHOLDER; reemplázalo por el RUT real del proveedor antes de presentar.');
|
|
31
123
|
if (!args.razon_social)
|
|
32
124
|
advertencias.push('razon_social es un valor PLACEHOLDER; reemplázalo por la razón social real.');
|
|
33
|
-
const customPrice = args.precio_unitario_personalizado;
|
|
34
125
|
let plazoEntrega = args.plazo_entrega_dias;
|
|
35
126
|
if (plazoEntrega === undefined) {
|
|
36
127
|
plazoEntrega = targetDetail.entrega?.plazo_entrega_dias || 5;
|
|
37
128
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (customPrice !== undefined && customPrice > 0) {
|
|
43
|
-
suggestedPrice = customPrice;
|
|
44
|
-
priceSource = 'Precio neto ingresado por el usuario';
|
|
45
|
-
isPriceSuggested = true;
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
// Intentar obtener palabras clave del primer producto solicitado
|
|
49
|
-
let keyword = '';
|
|
50
|
-
if (targetDetail.productos_solicitados && targetDetail.productos_solicitados.length > 0) {
|
|
51
|
-
keyword = targetDetail.productos_solicitados[0].nombre;
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
keyword = targetDetail.nombre;
|
|
55
|
-
}
|
|
56
|
-
if (keyword) {
|
|
57
|
-
try {
|
|
58
|
-
logger.info(`generar_borrador_cotizacion: Consultando precios cotizados por el mercado para "${keyword}"`);
|
|
59
|
-
// Solo `desierta`: medido contra la API real, es el único estado que
|
|
60
|
-
// publica cotizaciones (desierta 5/8 procesos con precios; cerrada 0/8).
|
|
61
|
-
// `proveedor_seleccionado` devuelve 0 resultados.
|
|
62
|
-
const searchResponse = await client.buscar({
|
|
63
|
-
q: keyword,
|
|
64
|
-
estado: 'desierta',
|
|
65
|
-
tamano_pagina: 50, // mínimo de la API: 10
|
|
66
|
-
numero_pagina: 1,
|
|
67
|
-
});
|
|
68
|
-
const prices = [];
|
|
69
|
-
const itemsToProcess = (searchResponse.items || []).slice(0, 5);
|
|
70
|
-
if (itemsToProcess.length > 0) {
|
|
71
|
-
for (const item of itemsToProcess) {
|
|
72
|
-
try {
|
|
73
|
-
const detail = await client.detalle(item.codigo);
|
|
74
|
-
// Se toman TODAS las cotizaciones, incluidas las inadmisibles: en los
|
|
75
|
-
// procesos desiertos casi todas lo son (por eso quedaron desiertos), y
|
|
76
|
-
// el precio ofertado sigue siendo señal de mercado. Filtrarlas dejaba
|
|
77
|
-
// la muestra vacía. La API nunca marca un ganador, así que la
|
|
78
|
-
// referencia es lo que ofertó la competencia.
|
|
79
|
-
for (const prov of detail.proveedores_cotizando ?? []) {
|
|
80
|
-
const unitPrice = extraerPrecioUnitario(prov, keyword);
|
|
81
|
-
if (unitPrice !== null)
|
|
82
|
-
prices.push(unitPrice);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
catch (e) {
|
|
86
|
-
// ignore errors for individual historical lookups
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
if (prices.length > 0) {
|
|
91
|
-
prices.sort((a, b) => a - b);
|
|
92
|
-
// Percentil 25 de lo cotizado: ubica la oferta en el cuarto más
|
|
93
|
-
// económico sin regalar margen, y resiste valores atípicos mejor
|
|
94
|
-
// que un promedio.
|
|
95
|
-
suggestedPrice = percentil(prices, 25);
|
|
96
|
-
priceSource = `Sugerencia automática: percentil 25 de ${prices.length} precio(s) cotizado(s) por el mercado en procesos similares (NO son precios adjudicados: la API no los expone)`;
|
|
97
|
-
isPriceSuggested = true;
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
// Fallback: usar presupuesto estimado del comprador si existe
|
|
101
|
-
const totalCantidad = targetDetail.productos_solicitados?.reduce((acc, p) => acc + p.cantidad, 0) || 1;
|
|
102
|
-
const budget = targetDetail.presupuesto?.monto_disponible_clp || targetDetail.presupuesto?.monto_disponible || 0;
|
|
103
|
-
if (budget > 0) {
|
|
104
|
-
suggestedPrice = Math.round((budget * 0.9) / totalCantidad);
|
|
105
|
-
priceSource = 'Sugerencia automática: Presupuesto estimado del comprador (descontado 10%)';
|
|
106
|
-
isPriceSuggested = true;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
catch (err) {
|
|
111
|
-
logger.warn(`generar_borrador_cotizacion: No se pudo estimar precio sugerido: ${safeError(err)}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
129
|
+
const estimacion = await estimarPrecioUnitario(client, targetDetail, args.precio_unitario_personalizado);
|
|
130
|
+
const suggestedPrice = estimacion.precio;
|
|
131
|
+
const isPriceSuggested = estimacion.sugerido;
|
|
132
|
+
const priceSource = estimacion.fuente;
|
|
115
133
|
// Construir productos cotizados
|
|
116
134
|
const productosCotizados = (targetDetail.productos_solicitados || []).map(prod => {
|
|
117
135
|
const uPrice = suggestedPrice;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generar-borrador.js","sourceRoot":"","sources":["../../src/tools/generar-borrador.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,
|
|
1
|
+
{"version":3,"file":"generar-borrador.js","sourceRoot":"","sources":["../../src/tools/generar-borrador.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,13 +9,16 @@ export interface OportunidadRadar {
|
|
|
9
9
|
ofertas_recibidas: number;
|
|
10
10
|
horas_restantes: number;
|
|
11
11
|
fecha_cierre: string;
|
|
12
|
+
/** 1 = primer llamado · 2 = segundo llamado (el primero no recibió ofertas válidas). */
|
|
13
|
+
llamado: number;
|
|
12
14
|
puntuacion_caliente: number;
|
|
13
15
|
factores_calificacion: string[];
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Calcula el "Hot Score" de una oportunidad de forma pura (sin efectos secundarios).
|
|
17
19
|
* Retorna null si el proceso debe omitirse (ya cerrado o bajo el presupuesto mínimo).
|
|
18
|
-
* Ponderación: baja competencia (máx 50) + urgencia (máx 30) + presupuesto (máx 20)
|
|
20
|
+
* Ponderación: baja competencia (máx 50) + urgencia (máx 30) + presupuesto (máx 20)
|
|
21
|
+
* + facilidad (máx 5) + segundo llamado (máx 10). Máximo teórico: 115 pts.
|
|
19
22
|
*/
|
|
20
23
|
export declare function evaluarOportunidad(item: CompraAgilItem, now: number, minBudget?: number): OportunidadRadar | null;
|
|
21
24
|
export interface RadarParams {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radar-oportunidades.d.ts","sourceRoot":"","sources":["../../src/tools/radar-oportunidades.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"radar-oportunidades.d.ts","sourceRoot":"","sources":["../../src/tools/radar-oportunidades.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAmBhF,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,MAAM,EACX,SAAS,SAAI,GACZ,gBAAgB,GAAG,IAAI,CA8FzB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,yEAAyE;IACzE,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,8EAA8E;IAC9E,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,WAAW,EACnB,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,UAAU,CAAC,CA6BrB;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CA4C5F"}
|