Merge pull request #10 from josedario87/codex/add-lightweight-agent-for-repo-understanding
All checks were successful
Deploy conversation layer / deploy (push) Successful in 6s

Add Gemini-based repo agent
This commit is contained in:
josedario87
2025-06-05 00:37:47 -06:00
committed by GitHub
11 changed files with 1691 additions and 5 deletions

View File

@@ -6,3 +6,5 @@ OPEN_WA_URL=https://whatsappbot.interno.com/
# Optional custom ports # Optional custom ports
PORT=3000 PORT=3000
ROUTER_PORT=3001 ROUTER_PORT=3001
# API key for the Gemini SDK
GEMINI_API_KEY=

View File

@@ -1,4 +1,4 @@
.PHONY: sync-from-github sync-to-github chat router .PHONY: sync-from-github sync-to-github chat router agent
# Pull latest changes from the GitHub mirror and push them to Gitea # Pull latest changes from the GitHub mirror and push them to Gitea
sync-from-github: sync-from-github:
@@ -15,4 +15,7 @@ chat:
router: router:
cd whatsapp-router && npm install && npm run dev cd whatsapp-router && npm install && npm run dev
agent:
cd conversation-layer-agent && npm install && npm run dev

View File

@@ -1,18 +1,20 @@
# Conversation Layer # Conversation Layer
This module contains the services that handle messaging for WhatsApp and the web chat interface. All source code is now written in **TypeScript**. It is composed of three containers: This module contains the services that handle messaging for WhatsApp and the web chat interface. All source code is now written in **TypeScript**. It is composed of four containers:
- **openwa** provides access to WhatsApp through the [open-wa](https://github.com/open-wa/wa-automate-nodejs) project. - **openwa** provides access to WhatsApp through the [open-wa](https://github.com/open-wa/wa-automate-nodejs) project.
- **whatsapp-router** receives webhook events from openwa and forwards messages to a conversation handler. Handlers can be configured per chat ID in `whatsapp-router/src/chatHandlers.ts`. - **whatsapp-router** receives webhook events from openwa and forwards messages to a conversation handler. Handlers can be configured per chat ID in `whatsapp-router/src/chatHandlers.ts`.
- **chat-ui** simple web chat interface that also communicates with the LLM agent. - **chat-ui** simple web chat interface that also communicates with the LLM agent.
- **conversation-layer-agent** lightweight agent that uses the Gemini SDK to answer questions about this repository.
All services can be launched together with `docker-compose`. All services can be launched together with `docker-compose`.
## Usage ## Usage
1. Configure the URL of your LLM agent in `docker-compose.yml` (`LLM_AGENT_URL`). 1. Configure the URL of your LLM agent in `docker-compose.yml` (`LLM_AGENT_URL`).
2. Optionally edit `whatsapp-router/src/chatHandlers.ts` to map specific chat IDs to different handler URLs or local handlers. By default the chat ID `50498554225@c.us` is mapped to a builtin *HelloWorld* agent that replies "hello world" for testing. 2. Set your Gemini API key in `.env` (`GEMINI_API_KEY`) so the conversation-layer-agent can use the Gemini SDK.
3. Run: 3. Optionally edit `whatsapp-router/src/chatHandlers.ts` to map specific chat IDs to different handler URLs or local handlers. By default the chat ID `50498554225@c.us` is mapped to a builtin *HelloWorld* agent for testing and `repo-helper@c.us` talks to the conversation-layer-agent.
4. Run:
```bash ```bash
docker-compose up --build docker-compose up --build
@@ -24,6 +26,7 @@ Alternatively you can run the chat UI and router locally using Make:
```bash ```bash
make chat # start chat-ui make chat # start chat-ui
make router # start whatsapp-router make router # start whatsapp-router
make agent # start conversation-layer-agent
``` ```
Both targets read configuration from a `.env` file if it exists (see `.env.example`). Both targets read configuration from a `.env` file if it exists (see `.env.example`).

View File

@@ -0,0 +1,2 @@
node_modules
npm-debug.log

View File

@@ -0,0 +1,17 @@
# ---------- Build stage ----------
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# ---------- Production stage ----------
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm install --production
ENV PORT=8001
EXPOSE 8001
CMD ["node", "dist/index.js"]

1552
conversation-layer-agent/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
{
"name": "conversation-layer-agent",
"version": "1.0.0",
"main": "dist/index.js",
"license": "MIT",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "nodemon --watch src --ext ts --exec \"ts-node src/index.ts\""
},
"dependencies": {
"express": "^4.18.2",
"@google/generative-ai": "^0.5.0",
"dotenv": "^16.5.0"
},
"devDependencies": {
"typescript": "^5.4.5",
"@types/node": "^20.11.19",
"@types/express": "^4.17.21",
"nodemon": "^3.1.10",
"ts-node": "^10.9.2"
}
}

View File

@@ -0,0 +1,57 @@
import express from 'express';
import { GoogleGenerativeAI } from '@google/generative-ai';
import dotenv from 'dotenv';
dotenv.config();
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 GoogleGenerativeAI(API_KEY) : null;
const model = genAI ? genAI.getGenerativeModel({ model: 'gemini-pro' }) : null;
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 message = req.body?.message as string | undefined;
if (!message) return res.status(400).json({ error: 'Missing message' });
if (!model) {
return res.json({ reply: repoInfo });
}
try {
const prompt = `Repo information: ${repoInfo}\nUser message: ${message}`;
const result = await model.generateContent(prompt);
const reply = result.response.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(`
<h1>Conversation Layer Agent</h1>
<p>This service answers questions about the repository.</p>
<p>Send a POST request to / with a JSON body containing {"message": "your question"}</p>
<p>Example: {"message": "What is this repository about?"}</p>
<p>It will respond with a JSON object containing {"reply": "the answer"}</p>
<p>Repository info: ${repoInfo}</p>
`);
}
);
app.listen(PORT, () => {
console.log(`conversation-layer-agent listening on ${PORT}`);
});

View File

@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"lib": ["es2020"],
"moduleResolution": "node"
},
"include": ["src"]
}

View File

@@ -37,6 +37,18 @@ services:
networks: networks:
- principal - principal
conversation-layer-agent:
build: ./conversation-layer-agent
image: gitea.interno.com/nucleo000/conversation-layer-agent:latest
container_name: conversation-layer-agent
environment:
- PORT=8001
- GEMINI_API_KEY=${GEMINI_API_KEY}
ports:
- "8001:8001"
networks:
- principal
volumes: volumes:
nucleo_whatsapp_sessions: nucleo_whatsapp_sessions:

View File

@@ -4,7 +4,8 @@ import { WhatsAppMessage } from './types';
export type Handler = string | ((msg: WhatsAppMessage | string) => Promise<string>); export type Handler = string | ((msg: WhatsAppMessage | string) => Promise<string>);
export const chatHandlers: Record<string, Handler> = { export const chatHandlers: Record<string, Handler> = {
'50498554225@c.us': helloWorldAgent, '50498554225@c.us': 'http://conversation-layer-agent:8001',
'repo-helper@c.us': 'http://conversation-layer-agent:8001',
// Add other mappings like: // Add other mappings like:
// '50496210031@c.us': 'http://llm-agent:8000' // '50496210031@c.us': 'http://llm-agent:8000'
}; };