From 624d06530e5b91b8a07470788bbaafa806e07d36 Mon Sep 17 00:00:00 2001
From: josedario87 <71241187+josedario87@users.noreply.github.com>
Date: Thu, 5 Jun 2025 14:25:20 -0600
Subject: [PATCH] Implement conversation snapshot structure
---
conversation-layer-agent/src/index.ts | 33 +++++++--
whatsapp-router/src/store/conversation.ts | 86 +++++++++++++++++++++--
whatsapp-router/src/types.ts | 31 +++++++-
3 files changed, 136 insertions(+), 14 deletions(-)
diff --git a/conversation-layer-agent/src/index.ts b/conversation-layer-agent/src/index.ts
index b791493..8db03b2 100644
--- a/conversation-layer-agent/src/index.ts
+++ b/conversation-layer-agent/src/index.ts
@@ -6,12 +6,37 @@ 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;
- messages: { text: string }[];
+ title: string;
+ isGroup: boolean;
+ unreadCount: number;
+ participants: Participant[];
+ messages: Msg[];
createdAt: number;
- updatedAt: number;
- messageCount: number;
}
const PORT = Number(process.env.PORT) || 8001;
@@ -76,7 +101,7 @@ app.get('/', (req, res) => {
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"}]}}
+ Example: {"conversation": {"chatId": "123@c.us", "title": "Alice", "isGroup": false, "unreadCount": 0, "participants": [{"id": "123@c.us", "name": "Alice", "isMe": false}], "messages": [{"id": "msg1", "from": "123@c.us", "to": "me@c.us", "ts": 0, "type": "chat", "text": "hello", "meta": {"ack": 0, "hasReaction": false, "isQuoted": false}}], "createdAt": 0 }}
It will respond with a JSON object containing {"reply": "the answer"}
Repository info: ${repoInfo}
diff --git a/whatsapp-router/src/store/conversation.ts b/whatsapp-router/src/store/conversation.ts
index 18d938c..6c23e83 100644
--- a/whatsapp-router/src/store/conversation.ts
+++ b/whatsapp-router/src/store/conversation.ts
@@ -1,5 +1,5 @@
import axios from 'axios';
-import { WhatsAppMessage, Conversation } from '../types';
+import { WhatsAppMessage, Conversation, Msg, Participant } from '../types';
const conversations = new Map();
@@ -19,6 +19,24 @@ async function loadMessages(
return msgs;
}
+function mapMessage(m: WhatsAppMessage): Msg {
+ return {
+ id: m.id,
+ from: m.from,
+ to: m.to,
+ ts: (m as any).timestamp || (m as any).t,
+ type: ((m as any).type as any) || 'chat',
+ text: (m as any).text || (m as any).caption || (m as any).body,
+ mediaUrl: (m as any).cloudUrl || (m as any).clientUrl,
+ mentions: ((m as any).mentionedJidList as any) || [],
+ meta: {
+ ack: (m as any).ack || 0,
+ hasReaction: (m as any).hasReaction || false,
+ isQuoted: !!(m as any).quotedMsg,
+ },
+ };
+}
+
export async function getConversation(
chatId: string,
openWaUrl: string
@@ -41,15 +59,61 @@ export async function buildConversation(
openWaUrl: string
): Promise {
console.log(`[conversationStore] Building conversation for ${chatId}`);
- const messages = await loadMessages(chatId, openWaUrl);
+ const rawMessages = await loadMessages(chatId, openWaUrl);
const now = Date.now();
+
+ const first = rawMessages[0];
+ const chat = first?.chat;
+ const title = chat?.formattedTitle || chat?.name || chatId;
+ const isGroup = chat?.isGroup || false;
+ const unreadCount = chat?.unreadCount || 0;
+
+ const participantsMap = new Map();
+ if (chat?.contact) {
+ const c = chat.contact;
+ participantsMap.set(c.id, {
+ id: c.id,
+ name: c.pushname || c.name || '',
+ isMe: c.isMe,
+ });
+ }
+ if (isGroup && chat?.groupMetadata?.participants) {
+ for (const p of chat.groupMetadata.participants as any[]) {
+ const c = p.contact || {};
+ const id = c.id || p.id;
+ participantsMap.set(id, {
+ id,
+ name: c.pushname || c.name || '',
+ isMe: c.isMe || false,
+ isAdmin: p.isAdmin || p.isSuperAdmin,
+ });
+ }
+ }
+
+ for (const m of rawMessages) {
+ const s = m.sender;
+ if (s && !participantsMap.has(s.id)) {
+ participantsMap.set(s.id, {
+ id: s.id,
+ name: s.pushname || s.name || '',
+ isMe: s.isMe,
+ });
+ }
+ }
+
+ const messages: Msg[] = rawMessages.slice(-20).map(mapMessage);
+ messages.sort((a, b) => a.ts - b.ts);
+
const conv: Conversation = {
chatId,
+ title,
+ isGroup,
+ unreadCount,
+ participants: Array.from(participantsMap.values()),
messages,
createdAt: conversations.get(chatId)?.createdAt || now,
- updatedAt: now,
- messageCount: messages.length,
};
+
conversations.set(chatId, conv);
return conv;
}
@@ -66,8 +130,16 @@ export async function addMessageToConversation(
): Promise {
console.log(`[conversationStore] Adding message to ${chatId}`);
const conv = await getConversation(chatId, openWaUrl);
- conv.messages.push(msg);
- conv.messageCount = conv.messages.length;
- conv.updatedAt = Date.now();
+ const mapped = mapMessage(msg);
+ conv.messages.push(mapped);
+ if (conv.messages.length > 20) conv.messages.shift();
+ const s = msg.sender;
+ if (s && !conv.participants.some((p) => p.id === s.id)) {
+ conv.participants.push({
+ id: s.id,
+ name: s.pushname || s.name || '',
+ isMe: s.isMe,
+ });
+ }
return conv;
}
diff --git a/whatsapp-router/src/types.ts b/whatsapp-router/src/types.ts
index 5152240..4bbdedb 100644
--- a/whatsapp-router/src/types.ts
+++ b/whatsapp-router/src/types.ts
@@ -193,10 +193,35 @@ export interface WhatsAppMessage {
text: string;
}
+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;
- messages: WhatsAppMessage[];
+ title: string;
+ isGroup: boolean;
+ unreadCount: number;
+ participants: Participant[];
+ messages: Msg[];
createdAt: number;
- updatedAt: number;
- messageCount: number;
}