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
All checks were successful
Deploy conversation layer / deploy (push) Successful in 6s
Add Gemini-based repo agent
This commit is contained in:
@@ -6,3 +6,5 @@ OPEN_WA_URL=https://whatsappbot.interno.com/
|
||||
# Optional custom ports
|
||||
PORT=3000
|
||||
ROUTER_PORT=3001
|
||||
# API key for the Gemini SDK
|
||||
GEMINI_API_KEY=
|
||||
|
||||
5
Makefile
5
Makefile
@@ -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
|
||||
sync-from-github:
|
||||
@@ -15,4 +15,7 @@ chat:
|
||||
router:
|
||||
cd whatsapp-router && npm install && npm run dev
|
||||
|
||||
agent:
|
||||
cd conversation-layer-agent && npm install && npm run dev
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
# 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.
|
||||
- **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.
|
||||
- **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`.
|
||||
|
||||
## Usage
|
||||
|
||||
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 built‑in *HelloWorld* agent that replies "hello world" for testing.
|
||||
3. Run:
|
||||
2. Set your Gemini API key in `.env` (`GEMINI_API_KEY`) so the conversation-layer-agent can use the Gemini SDK.
|
||||
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 built‑in *HelloWorld* agent for testing and `repo-helper@c.us` talks to the conversation-layer-agent.
|
||||
4. Run:
|
||||
|
||||
```bash
|
||||
docker-compose up --build
|
||||
@@ -24,6 +26,7 @@ Alternatively you can run the chat UI and router locally using Make:
|
||||
```bash
|
||||
make chat # start chat-ui
|
||||
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`).
|
||||
|
||||
2
conversation-layer-agent/.dockerignore
Normal file
2
conversation-layer-agent/.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
17
conversation-layer-agent/Dockerfile
Normal file
17
conversation-layer-agent/Dockerfile
Normal 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
1552
conversation-layer-agent/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
conversation-layer-agent/package.json
Normal file
23
conversation-layer-agent/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
57
conversation-layer-agent/src/index.ts
Normal file
57
conversation-layer-agent/src/index.ts
Normal 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}`);
|
||||
});
|
||||
14
conversation-layer-agent/tsconfig.json
Normal file
14
conversation-layer-agent/tsconfig.json
Normal 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"]
|
||||
}
|
||||
@@ -37,6 +37,18 @@ services:
|
||||
networks:
|
||||
- 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:
|
||||
nucleo_whatsapp_sessions:
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ import { WhatsAppMessage } from './types';
|
||||
export type Handler = string | ((msg: WhatsAppMessage | string) => Promise<string>);
|
||||
|
||||
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:
|
||||
// '50496210031@c.us': 'http://llm-agent:8000'
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user