-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
159 lines (135 loc) · 4.96 KB
/
Copy pathindex.js
File metadata and controls
159 lines (135 loc) · 4.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// ==========================================
// Entry Point — Multi-Platform AI Agent
// ==========================================
import config from './config.js';
import { handleMessage } from './orchestrator.js';
import { runStartupChecks } from './startup-checks.js';
import { startHealthServer, recordError } from './health.js';
import { registerSelf } from './discovery.js';
import { downloadBaileysMedia, describeMedia } from './media.js';
function attachListeners(client, label, baileysSocket = null) {
client.on('message', async ({ sender, text, isGroup, participant, raw }) => {
try {
// Handle media messages (Baileys only for now)
let mediaInfo = null;
if (baileysSocket && raw?.message && !text) {
const hasMedia = raw.message.imageMessage || raw.message.audioMessage
|| raw.message.videoMessage || raw.message.documentMessage;
if (hasMedia) {
mediaInfo = await downloadBaileysMedia(baileysSocket, raw);
const caption = raw.message.imageMessage?.caption
|| raw.message.videoMessage?.caption || '';
text = caption || describeMedia(mediaInfo) || '[media]';
}
}
if (!text) return; // skip empty
await handleMessage(sender, text, client, isGroup, mediaInfo);
} catch (err) {
console.error(`[${label} Error] Failed to handle message:`, err);
recordError();
await client.sendMessage(sender, 'Sorry, I encountered an error processing your message.');
}
});
client.on('ready', () => {
console.log(`\n[Ready] ${label} agent is listening for messages!\n`);
});
}
async function startWhatsApp() {
let client;
if (config.whatsapp.mode === 'cloud-api') {
const { CloudAPIClient } = await import('./whatsapp/cloud-api-client.js');
client = new CloudAPIClient();
await client.connect();
attachListeners(client, 'WhatsApp');
} else {
const { WhatsAppClient } = await import('./whatsapp/baileys-client.js');
client = new WhatsAppClient();
await client.connect();
attachListeners(client, 'WhatsApp', client.sock);
}
return client;
}
async function startTeams() {
const { TeamsClient } = await import('./teams/teams-client.js');
const client = new TeamsClient();
await client.connect();
attachListeners(client, 'Teams');
return client;
}
async function startTelegram() {
const { TelegramClient } = await import('./telegram/telegram-client.js');
const client = new TelegramClient();
await client.connect();
attachListeners(client, 'Telegram');
return client;
}
// ---- Global error handlers ----
process.on('unhandledRejection', (reason) => {
console.error('[Fatal] Unhandled promise rejection:', reason);
recordError();
});
process.on('uncaughtException', (err) => {
console.error('[Fatal] Uncaught exception:', err);
recordError();
// Give logs time to flush, then exit
setTimeout(() => process.exit(1), 1000).unref();
});
// ---- Graceful shutdown ----
const activeClients = [];
let shuttingDown = false;
async function shutdown(signal) {
if (shuttingDown) return;
shuttingDown = true;
console.log(`\n[Shutdown] Received ${signal}, cleaning up...`);
// Close platform clients
for (const client of activeClients) {
try {
if (typeof client.close === 'function') await client.close();
else if (typeof client.disconnect === 'function') await client.disconnect();
} catch (err) {
console.error('[Shutdown] Error closing client:', err.message);
}
}
console.log('[Shutdown] Done. Exiting.');
process.exit(0);
}
process.on('SIGINT', () => shutdown('SIGINT'));
process.on('SIGTERM', () => shutdown('SIGTERM'));
async function main() {
console.log('===========================================');
console.log(` AI COMMS — ${config.agent.name}`);
console.log(` AI Provider: ${config.aiProvider}`);
console.log(` Platform: ${config.platform}`);
console.log('===========================================\n');
runStartupChecks();
// Start health monitoring endpoint
const healthPort = parseInt(process.env.HEALTH_PORT || '9090');
startHealthServer(healthPort);
// Register self in agent discovery
registerSelf();
const platform = config.platform.toLowerCase();
const platforms = platform === 'both'
? ['whatsapp', 'teams', 'telegram']
: platform.split(',').map(p => p.trim());
if (platforms.includes('whatsapp')) {
const client = await startWhatsApp();
activeClients.push(client);
}
if (platforms.includes('teams')) {
const client = await startTeams();
activeClients.push(client);
}
if (platforms.includes('telegram')) {
const client = await startTelegram();
activeClients.push(client);
}
const valid = ['whatsapp', 'teams', 'telegram'];
if (!platforms.some(p => valid.includes(p))) {
console.error(`Unknown platform "${platform}". Use: whatsapp | teams | telegram | both | whatsapp,telegram`);
process.exit(1);
}
}
main().catch((err) => {
console.error('[Fatal] Startup failed:', err);
process.exit(1);
});