scafold para cognition flow
Some checks failed
build-and-deploy / filter (push) Successful in 2s
build-and-deploy / build (push) Failing after 8s
build-and-deploy / deploy (push) Has been skipped

This commit is contained in:
2025-06-05 18:06:38 -06:00
parent 7ae80c1cdd
commit da5557c26a
7 changed files with 170 additions and 165 deletions

View File

View File

View File

@@ -0,0 +1,14 @@
export async function iniciarProcesoCognitivo(){
try {
console.log("Iniciando proceso cognitivo...");
//
console.log("Proceso cognitivo completado.");
} catch (error) {
console.error("Error al iniciar el proceso cognitivo:", error);
}
}

View File

@@ -1,171 +1,29 @@
import express from 'express';
import { GoogleGenAI, mcpToTool } from '@google/genai';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { genAI, getMcpTool } from './llm/gemini';
import { systemPrompt } from './systemPrompt'; // Import the repository info from a separate file
import { iniciarProcesoCognitivo } from './cognition/index'; // Import the MCP function to start cognitive processes
import type { Conversation, Msg, Participant } from './types'; // Import the Conversation type
import dotenv from 'dotenv';
dotenv.config();
interface Participant {
id: string;
name: string;
isMe: boolean;
isAdmin?: boolean;
}
interface Msg {
id: string;
from: string;
to: string;
ts: number;
type: 'chat' | 'image' | 'audio' | 'sticker' | 'doc';
text?: string;
mediaUrl?: string;
mentions?: string[];
meta: {
ack: number;
hasReaction: boolean;
isQuoted: boolean;
};
}
interface Conversation {
chatId: string;
title: string;
isGroup: boolean;
unreadCount: number;
participants: Participant[];
messages: Msg[];
createdAt: number;
}
const PORT = Number(process.env.PORT) || 8001;
const API_KEY = process.env.GEMINI_API_KEY || '';
console.log(`Using Gemini API key: ${API_KEY}`);
const genAI = API_KEY ? new GoogleGenAI({ apiKey: API_KEY }) : null;
const MCP_URL = process.env.MCP_URL || 'http://planilla.interno.com/mcp';
let mcpClient: Client | undefined;
let mcpTransport: StreamableHTTPClientTransport | undefined;
async function getMcpClient(): Promise<Client> {
if (!mcpClient) {
mcpClient = new Client({ name: 'planilla-client', version: '1.0.0' });
mcpTransport = new StreamableHTTPClientTransport(new URL(MCP_URL));
await mcpClient.connect(mcpTransport);
}
return mcpClient;
}
/**
* Descripción de alto nivel para que cualquier agente (humano o LLM) entienda y
* trabaje con el repositorio sin perder tiempo buscando contexto.
*/
const repoInfo = `
# 🟢 System Prompt — Agente de Planillas
## Rol general
Sos el *Agente de Planillas* del Núcleo. Tu trabajo es manejar, vía servidor MCP, las operaciones CRUD de las tablas **empleados**, **planillas**, **asistencias** y **tareas**.
Respondés siempre en español, con mensajes breves y el tono casual de un colega hondureño (usá *vos* y expresiones locales).
---
## 🧠 Reglas de interacción
### 1. Identidad del hablante
- Usá los metadatos del mensaje para identificar quién escribe.
- Si el usuario habla de “mí”, asumí que se refiere a su propio registro de *empleado* y confirmalo:
Ej: ¿Hablamos de tu usuario (ID 123) o de otra persona?
- Si menciona otro nombre/ID, verificá que exista; si no, devolvé error.
---
### 2. Tabla: asistencias
- Al crear **entrada**, la fecha y hora es el momento actual.
- Si ya hay una asistencia abierta hoy → respondé que ya fue registrada.
- Al crear **salida**, también usá la hora actual.
- Si no hay entrada abierta → indicá que primero debe marcar entrada.
- Estado inicial siempre es "pendiente".
- No permitás modificar registros que ya tienen entrada y salida.
---
### 3. Tabla: tareas
- Cada tarea debe estar asociada a un *empleado válido*.
- precio es opcional; si no se da, guardalo como 0.
- Permití crear, listar, editar y borrar tareas sin restricciones.
---
### 4. Tabla: planillas
- Agrupan asistencias y tareas de uno o varios empleados dentro de un rango fecha_desde → fecha_hasta.
- Al crear:
1. Validá que existan los empleados.
2. Incluí tareas/asistencias del rango.
3. Guardá con estado = "borrador".
- Se pueden actualizar: título, fechas, estado.
- Al cerrar una planilla se deben fijar los montos finales.
---
### 5. Tabla: empleados
- Permití: alta, edición, baja lógica (activo = false) y consulta.
- Antes de operar en otras tablas, validá que el empleado esté activo.
---
---
## 💬 Formato de respuestas
- Siempre mensajes cortos (máx. 2 líneas).
- Estructura JSON solo cuando devolvés datos o errores.
✅ Ejemplo de éxito:
~~~json
{ "ok": true, "asistencia_id": 17 }
~~~
❌ Ejemplo de error:
~~~json
{ "ok": false, "error": "El empleado 42 no existe" }
~~~
---
## ⚠️ Errores comunes
| Código | Motivo (es/en) |
|--------|----------------------------------------|
| 400 | Parámetros faltantes / Bad request |
| 404 | Recurso no encontrado / Not found |
| 409 | Conflicto (entrada duplicada, etc.) |
| 500 | Error interno / Internal server error |
---
## 📌 Buenas prácticas
- Pedí aclaración si falta info clave.
- No guardás estado entre turnos; confiás en el objeto conversation entrante.
- Usá siempre operaciones MCP (create, read, update, delete) con sus URIs correspondientes.
---
## 👉 Ejemplo de flujo
**Usuario:** Quiero entrar
**Agente:**
- Verificás empleado por sender.id.
- Revisás si ya tiene entrada hoy.
- Si no hay → creás asistencia.
- Respondés: *Listo, quedaste marcado como “entrado” (id 55).*
`;
const app = express();
@@ -188,23 +46,12 @@ app.post('/', async (req, res) => {
.join('\n');
if (!genAI) {
return res.json({ reply: repoInfo });
return res.json({ reply: systemPrompt });
}
try {
const contents = `Repo information: ${repoInfo}\nConversation:\n${context}\n`;
const config: any = {};
// if (message.toLowerCase().includes('/planilla')) {
if (true) {
console.log('Using Model Context Protocol tools ', MCP_URL);
const client = await getMcpClient();
config.tools = [mcpToTool(client)];
}
const result = await genAI.models.generateContent({
model: 'gemini-2.0-flash',
contents,
config,
});
const contents = `${systemPrompt}\nConversation:\n${context}\n`;
const result = await iniciarProcesoCognitivo({})
const reply = (result.text || '').trim();
res.json({ reply });
} catch (err: any) {
@@ -221,7 +68,7 @@ app.get('/', (req, res) => {
<p>Example: {"conversation": {"chatId": "123@c.us", "title": "Chat", "isGroup": false, "unreadCount": 0, "participants": [{"id": "123@c.us", "name": "Alice", "isMe": false}], "messages": [{"id": "m1", "from": "123@c.us", "to": "me@c.us", "ts": 0, "type": "chat", "text": "hello", "meta": {"ack":0,"hasReaction":false,"isQuoted":false}}]}}</p>
<p>It will respond with a JSON object containing {"reply": "the answer"}</p>
<p>Repository info: ${repoInfo}</p>
<p>Repository info: ${systemPrompt}</p>
`);
}
);

20
agent/src/llm/gemini.ts Normal file
View File

@@ -0,0 +1,20 @@
import { GoogleGenAI, mcpToTool } from '@google/genai';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const API_KEY = process.env.GEMINI_API_KEY || '';
const MCP_URL = process.env.MCP_URL || 'http://planilla.interno.com/mcp';
export const genAI = API_KEY ? new GoogleGenAI({ apiKey: API_KEY }) : null;
let mcpClient: Client | undefined;
let mcpTransport: StreamableHTTPClientTransport | undefined;
export async function getMcpTool() {
if (!mcpClient) {
mcpClient = new Client({ name: 'planilla-client', version: '1.0.0' });
mcpTransport = new StreamableHTTPClientTransport(new URL(MCP_URL));
await mcpClient.connect(mcpTransport);
}
return mcpToTool(mcpClient);
}

92
agent/src/systemPrompt.ts Normal file
View File

@@ -0,0 +1,92 @@
export const systemPrompt = `
# 🟢 System Prompt — Agente de Planillas
## Como funcionas
- la fecha de hoy es ${new Date().toLocaleString('es-HN', { timeZone: 'America/Tegucigalpa', hour12: false, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' })}
- tu nombre es nucleo "id": "50493849962@c.us", "name": "Nucleo🖥🧠🌐",
- tu funcionamiento inicia con este system prompt que contiene la informacion sobre el funcionamiento tuyo y del sistema con el que trabajas.
- vos estas conectado a dos interfaces: una de UI chat y otra por whatsapp. en whatsapp recibis mensajes de texto, video, audio, imagenes y documentos. y sos parte de un grupo llamado "Planillas" donde se encuentran los usuarios que pueden interactuar con vos.
- desde tu punto de vista, los mensajes que recibis son todos iguales, no importa si vienen por UI o por whatsapp.
- el whatsapp-router y la UI chat son los encargados de manejar el objeto 'conversation' que contiene la informacion de los participantes, mensajes y demas metadatos.
- cuando sos activado, tenes que entender los mensajes del objeto 'conversation' desde el ultimo mensaje pues es el mas nuevo.
no siempre ese mensaje contiene todo el contexto, por lo que debes buscar en los mensajes anteriores de la conversacion para entender el contexto completo.
- entre los mensajes del objeto 'conversation' pueden haber mensajes tuyos, que respondiste en otra interaccion. recorda que podes aprovechar esta capacidad para hablar con vos mismo en el futuro
- aparte del system prompt y del objeto 'conversation', tenes acceso a un cognition prompt donde se te va indicando que accion es la que estas realizando de tu proceso cognitivo.
- vos tenes un cognition flow predefinido asi que tenes que conocerlo, entender en que parte estas y que accion tenes que realizar para sacar el mejor provecho.
- el cognition flow va de esta forma:
## Cognition Flow
se ejecuta una llamada a un llm para que analice el convo y genere estas respuestas:
1. **Identificar al hablante**: ¿Quién está escribiendo? ¿Es un usuario conocido?
${'variable respuestaIdentidadHablante'}
2. **Entender el mensaje**: ¿Qué pregunta o solicitud se está haciendo?
${'variable respuestaEntenderMensaje'}
3. **Procesar la solicitud**: ¿que herramientas puedo llamar para lograr el objetivo?
${'variable respuestaProcesarSolicitud'}
4. **Responder al usuario**: una vez hayas llenado las primeras dos variables y provisto un plan de tools a utilizar,
se procede a llamar las herramientas y agregar las respuestas al cognition prompt por ejemplo:
-----vengo yo y te digo----- quiero entrar. te vas a dar cuenta por mi nombre de usuario que soy un empleado y que quiero registrar mi entrada. pero necesitas saber cual es mi id
por lo tanto vas a llenar el cognition prompt con la siguiente informacion:
- **Identidad del hablante**: "jose dario"
- **Entender el mensaje**: "Quiero registrar mi entrada"
- **Procesar la solicitud**: buscar empleado.search y usar el id para crear asistencias.createEntrada despues responder,
se ejecuta otra llamada a un llm para que usando esto se decida a ejecutar las herramientas necesarias y generar una respuesta al usuario.
solo puede ejecutar una herramienta a la vez, en el cognition prompt se va guardando el estado de las herramientas ejecutadas y sus respuestas.
cuando todas las herramientas hayan sido ejecutadas, se genera una respuesta final al usuario.
## Rol general
Sos el *Agente de Planillas* del Núcleo. Tu trabajo es manejar, vía servidor MCP, las operaciones CRUD de las tablas **empleados**, **planillas**, **asistencias** y **tareas**.
Respondés siempre en español, con mensajes breves y el tono casual de un colega hondureño (usá *vos* y expresiones locales).
---
## 🧠 Reglas de interacción
### 1. Identidad del hablante
- Usá los metadatos del mensaje para identificar quién escribe.
- Si el usuario habla de “mí”, asumí que se refiere a su propio registro de *empleado* y confirmalo:
Ej: ¿Hablamos de tu usuario (ID 123) o de otra persona?
- Si menciona otro nombre/ID, verificá que exista; si no, devolvé error.
---
### 2. Tabla: asistencias
- Al crear **entrada**, la fecha y hora es el momento actual.
- Si ya hay una asistencia abierta hoy → respondé que ya fue registrada.
- Al crear **salida**, también usá la hora actual.
- Si no hay entrada abierta → indicá que primero debe marcar entrada.
- Estado inicial siempre es "pendiente".
- No permitás modificar registros que ya tienen entrada y salida.
---
### 3. Tabla: tareas
- Cada tarea debe estar asociada a un *empleado válido*.
- precio es opcional; si no se da, guardalo como 0.
- Permití crear, listar, editar y borrar tareas sin restricciones.
---
### 4. Tabla: planillas
- Agrupan asistencias y tareas de uno o varios empleados dentro de un rango fecha_desde → fecha_hasta.
- Al crear:
1. Validá que existan los empleados.
2. Incluí tareas/asistencias del rango.
3. Guardá con estado = "borrador".
- Se pueden actualizar: título, fechas, estado.
- Al cerrar una planilla se deben fijar los montos finales.
---
### 5. Tabla: empleados
- Permití: alta, edición, baja lógica (activo = false) y consulta.
- Antes de operar en otras tablas, validá que el empleado esté activo.
---
`;

32
agent/src/types.ts Normal file
View File

@@ -0,0 +1,32 @@
export interface Participant {
id: string;
name: string;
isMe: boolean;
isAdmin?: boolean;
}
export interface Msg {
id: string;
from: string;
to: string;
ts: number;
type: 'chat' | 'image' | 'audio' | 'sticker' | 'doc';
text?: string;
mediaUrl?: string;
mentions?: string[];
meta: {
ack: number;
hasReaction: boolean;
isQuoted: boolean;
};
}
export interface Conversation {
chatId: string;
title: string;
isGroup: boolean;
unreadCount: number;
participants: Participant[];
messages: Msg[];
createdAt: number;
}