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 dotenv from 'dotenv'; dotenv.config(); interface Conversation { chatId: string; messages: { text: string }[]; createdAt: number; updatedAt: number; messageCount: 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 { 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; } const repoInfo = `This repository contains a WhatsApp router, a simple chat UI and now a conversation-layer-agent service. - whatsapp-router: Forwards WhatsApp messages to configured agents. - chat-ui: Minimal web interface that also talks to an agent. - conversation-layer-agent: Answers questions about the repository. Run all services with docker-compose. Configure handler mappings in whatsapp-router/src/chatHandlers.ts.`; const app = express(); app.use(express.json()); app.post('/', async (req, res) => { const conversation = req.body?.conversation as Conversation | undefined; if (!conversation) return res.status(400).json({ error: 'Missing conversation' }); const message = conversation.messages[conversation.messages.length - 1]?.text || ''; if (!genAI) { return res.json({ reply: repoInfo }); } try { const contents = `Repo information: ${repoInfo}\nUser message: ${message}`; const config: any = {}; if (message.toLowerCase().includes('/planilla')) { 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 reply = (result.text || '').trim(); res.json({ reply }); } catch (err: any) { console.error('Gemini error', err.message); res.status(500).json({ error: 'Failed to generate reply' }); } }); app.get('/', (req, res) => { res.send(`

Conversation Layer Agent

This service answers questions about the repository.

Send a POST request to / with a JSON body containing {"conversation": {...}}

Example: {"conversation": {"chatId": "123@c.us", "messages": [{"text": "hello"}]}}

It will respond with a JSON object containing {"reply": "the answer"}

Repository info: ${repoInfo}

`); } ); app.listen(PORT, () => { console.log(`conversation-layer-agent listening on ${PORT}`); });