128 lines
4.0 KiB
JavaScript
128 lines
4.0 KiB
JavaScript
// /respuesta/respuestaMCP.js
|
|
import fs from 'fs/promises';
|
|
import { log } from '../logger.js';
|
|
import {
|
|
sendText,
|
|
fetchChatMessages,
|
|
setTypingStatus
|
|
} from '../whatsapp.js';
|
|
import { processMessage } from '../utils/processMessage.js';
|
|
import { saveMedia } from '../utils/saveMedia.js';
|
|
|
|
import { GoogleGenAI } from '@google/genai';
|
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
|
|
/* limpia el esquema JSON recursivamente */
|
|
function sanitizeSchema(obj) {
|
|
if (Array.isArray(obj)) return obj.map(sanitizeSchema);
|
|
if (obj && typeof obj === 'object') {
|
|
const out = {};
|
|
for (const [k, v] of Object.entries(obj)) {
|
|
if (k === 'additionalProperties' || k === '$schema') continue;
|
|
out[k] = sanitizeSchema(v);
|
|
}
|
|
return out;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
const cleanForGemini = ({ media, reactions, preview, ...rest }) => rest;
|
|
|
|
export async function respuestaMCP(msg) {
|
|
const text = msg.text || '';
|
|
|
|
setTypingStatus(msg.chatId, true);
|
|
log('info', '🧠 Generando respuesta para @nucleo…');
|
|
|
|
try {
|
|
const allraw = await fetchChatMessages(msg.chatId);
|
|
const allMsgs = allraw.map(processMessage);
|
|
|
|
const context = allMsgs.map(cleanForGemini);
|
|
let json = JSON.stringify(context);
|
|
while (json.length > 100_000 && context.length) {
|
|
context.shift();
|
|
json = JSON.stringify(context);
|
|
}
|
|
|
|
const chatName = context.length > 0 ? context[0]?.chatName : 'chat';
|
|
const prompt = [
|
|
`Eres el asistente del grupo "${chatName}". tenes la capacidad de interactuar con las carpetas ubicacadas en el directorio "/media/mcp" y sus subcarpetas.`,
|
|
`Pregunta del usuario: ${text}`,
|
|
...context
|
|
];
|
|
|
|
const medias = allraw.filter(m => m.type !== 'chat');
|
|
const settled = await Promise.allSettled(medias.map(saveMedia));
|
|
|
|
const MAX = 20 * 1024 * 1024;
|
|
let total = 0;
|
|
const files = {};
|
|
|
|
for (const r of settled) {
|
|
if (r.status !== 'fulfilled' || !r.value) continue;
|
|
const entries = Object.entries(r.value);
|
|
if (entries.length === 0) continue;
|
|
const [msgId, obj] = entries[0];
|
|
let size = Number(obj.sizeBytes || 0);
|
|
if (!size && obj.filePath) {
|
|
try { size = (await fs.stat(obj.filePath)).size; } catch { size = 0; }
|
|
}
|
|
if (total + size > MAX && total > 0) break;
|
|
if (size > MAX) continue;
|
|
|
|
total += size;
|
|
files[msgId] = { uri: obj.uri || obj.filePath, mimeType: obj.mimeType };
|
|
}
|
|
|
|
// === MCP setup ===
|
|
const client = new Client({ name: 'mcp-agent', version: '1.0.0' });
|
|
const serverParams = new StdioClientTransport({
|
|
command: 'npx',
|
|
args: ['-y', '@modelcontextprotocol/server-filesystem', '/media/mcp']
|
|
});
|
|
await client.connect(serverParams);
|
|
|
|
const mcp = await client.listTools();
|
|
const tools = mcp.tools.map(t => ({
|
|
name: t.name,
|
|
description: t.description,
|
|
parameters: sanitizeSchema({
|
|
type: 'object',
|
|
...t.inputSchema
|
|
})
|
|
}));
|
|
|
|
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
|
|
const response = await ai.models.generateContent({
|
|
model: 'gemini-2.5-flash-preview-04-17',
|
|
contents: prompt,
|
|
config: {
|
|
tools: [{ googleSearch: {} }],
|
|
temperature: 0
|
|
}
|
|
});
|
|
|
|
let respuesta;
|
|
if (response.functionCalls && response.functionCalls.length > 0) {
|
|
const call = response.functionCalls[0];
|
|
const result = await client.callTool({ name: call.name, arguments: call.args });
|
|
await client.close();
|
|
respuesta = result.content?.[0]?.text ?? JSON.stringify(result);
|
|
} else {
|
|
await client.close();
|
|
respuesta = response.text;
|
|
}
|
|
|
|
await sendText(msg.chatId, respuesta);
|
|
log('info', '🧠 Respuesta enviada');
|
|
|
|
} catch (error) {
|
|
log('error', 'Error en respuestaMCP:', error);
|
|
await sendText(msg.chatId, 'Hubo un error al procesar tu solicitud.');
|
|
} finally {
|
|
setTypingStatus(msg.chatId, false);
|
|
}
|
|
}
|