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
|
# Optional custom ports
|
||||||
PORT=3000
|
PORT=3000
|
||||||
ROUTER_PORT=3001
|
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
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 built‑in *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 built‑in *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`).
|
||||||
|
|||||||
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:
|
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:
|
||||||
|
|
||||||
|
|||||||
@@ -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'
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user