@diegoaltoworks/chatter 0.61.0 → 0.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -17
- package/dist/auth/secretStrength.d.ts +1 -1
- package/dist/auth/secretStrength.d.ts.map +1 -1
- package/dist/bin/create-apikey.js +45 -28
- package/dist/bin/wa-pair.js +113 -46
- package/dist/channels/backoff.d.ts +10 -0
- package/dist/channels/backoff.d.ts.map +1 -0
- package/dist/channels/gates.d.ts +15 -8
- package/dist/channels/gates.d.ts.map +1 -1
- package/dist/channels/index.d.ts +1 -1
- package/dist/channels/index.d.ts.map +1 -1
- package/dist/channels/index.js +38 -5
- package/dist/channels/index.mjs +37 -5
- package/dist/channels/matrix/api.d.ts +25 -6
- package/dist/channels/matrix/api.d.ts.map +1 -1
- package/dist/channels/matrix/channel.d.ts +4 -56
- package/dist/channels/matrix/channel.d.ts.map +1 -1
- package/dist/channels/matrix/handler.d.ts +16 -9
- package/dist/channels/matrix/handler.d.ts.map +1 -1
- package/dist/channels/matrix/index.d.ts +2 -2
- package/dist/channels/matrix/index.d.ts.map +1 -1
- package/dist/channels/matrix/index.js +196 -40
- package/dist/channels/matrix/index.mjs +189 -39
- package/dist/channels/matrix/sync.d.ts +4 -1
- package/dist/channels/matrix/sync.d.ts.map +1 -1
- package/dist/channels/matrix/updates.d.ts +39 -10
- package/dist/channels/matrix/updates.d.ts.map +1 -1
- package/dist/channels/pipeline.d.ts +14 -14
- package/dist/channels/pipeline.d.ts.map +1 -1
- package/dist/channels/polling.d.ts +67 -0
- package/dist/channels/polling.d.ts.map +1 -0
- package/dist/channels/telegram/channel.d.ts +2 -56
- package/dist/channels/telegram/channel.d.ts.map +1 -1
- package/dist/channels/telegram/index.js +53 -23
- package/dist/channels/telegram/index.mjs +53 -23
- package/dist/channels/telegram/poll.d.ts +5 -1
- package/dist/channels/telegram/poll.d.ts.map +1 -1
- package/dist/channels/telegram/webhook.d.ts +2 -10
- package/dist/channels/telegram/webhook.d.ts.map +1 -1
- package/dist/channels/whatsapp/authState.d.ts +40 -9
- package/dist/channels/whatsapp/authState.d.ts.map +1 -1
- package/dist/channels/whatsapp/channel.d.ts +39 -4
- package/dist/channels/whatsapp/channel.d.ts.map +1 -1
- package/dist/channels/whatsapp/inbound.d.ts +23 -25
- package/dist/channels/whatsapp/inbound.d.ts.map +1 -1
- package/dist/channels/whatsapp/index.d.ts +3 -3
- package/dist/channels/whatsapp/index.d.ts.map +1 -1
- package/dist/channels/whatsapp/index.js +188 -66
- package/dist/channels/whatsapp/index.mjs +185 -66
- package/dist/channels/whatsapp/pairing.d.ts.map +1 -1
- package/dist/client/src/Chat.d.ts.map +1 -1
- package/dist/client/src/ChatButton.d.ts.map +1 -1
- package/dist/client/src/browser.d.ts.map +1 -1
- package/dist/core/answer.d.ts +8 -0
- package/dist/core/answer.d.ts.map +1 -1
- package/dist/core/buildLock.d.ts +52 -0
- package/dist/core/buildLock.d.ts.map +1 -0
- package/dist/core/pipeline.d.ts +42 -5
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/prompts.d.ts +2 -0
- package/dist/core/prompts.d.ts.map +1 -1
- package/dist/core/retrieval.d.ts +100 -25
- package/dist/core/retrieval.d.ts.map +1 -1
- package/dist/core/session.d.ts +8 -0
- package/dist/core/session.d.ts.map +1 -1
- package/dist/flows/index.d.ts +1 -1
- package/dist/flows/index.d.ts.map +1 -1
- package/dist/flows/index.js +8 -6
- package/dist/flows/index.mjs +7 -6
- package/dist/flows/intent.d.ts +1 -1
- package/dist/flows/intent.d.ts.map +1 -1
- package/dist/flows/loader.d.ts +1 -2
- package/dist/flows/loader.d.ts.map +1 -1
- package/dist/flows/params.d.ts +1 -1
- package/dist/flows/params.d.ts.map +1 -1
- package/dist/flows/session.d.ts +4 -2
- package/dist/flows/session.d.ts.map +1 -1
- package/dist/flows/types.d.ts +2 -3
- package/dist/flows/types.d.ts.map +1 -1
- package/dist/history/index.d.ts +1 -1
- package/dist/history/index.d.ts.map +1 -1
- package/dist/history/index.js +6 -3
- package/dist/history/index.mjs +5 -3
- package/dist/history/tursoStore.d.ts +6 -4
- package/dist/history/tursoStore.d.ts.map +1 -1
- package/dist/images/index.js +2 -2
- package/dist/images/index.mjs +2 -2
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +596 -295
- package/dist/index.mjs +595 -295
- package/dist/mcp-server/index.d.ts +5 -5
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/logger.d.ts +12 -2
- package/dist/mcp-server/logger.d.ts.map +1 -1
- package/dist/mcp-server/rate-limiter.d.ts +10 -3
- package/dist/mcp-server/rate-limiter.d.ts.map +1 -1
- package/dist/mcp-server/types.d.ts +20 -5
- package/dist/mcp-server/types.d.ts.map +1 -1
- package/dist/mcp-server.js +479 -244
- package/dist/mcp-server.mjs +485 -244
- package/dist/middleware/apiKey.d.ts +10 -0
- package/dist/middleware/apiKey.d.ts.map +1 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/cors.d.ts.map +1 -1
- package/dist/middleware/ratelimit.d.ts.map +1 -1
- package/dist/middleware/referrer.d.ts.map +1 -1
- package/dist/middleware/session.d.ts +1 -1
- package/dist/middleware/session.d.ts.map +1 -1
- package/dist/routes/demo.d.ts.map +1 -1
- package/dist/routes/openai.d.ts.map +1 -1
- package/dist/routes/private.d.ts.map +1 -1
- package/dist/routes/public.d.ts.map +1 -1
- package/dist/scheduler/index.js +1 -1
- package/dist/scheduler/index.mjs +1 -1
- package/dist/scheduler/scheduler.d.ts +9 -1
- package/dist/scheduler/scheduler.d.ts.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +491 -268
- package/dist/server.mjs +497 -268
- package/dist/shortener.d.ts +5 -4
- package/dist/shortener.d.ts.map +1 -1
- package/dist/types.d.ts +129 -75
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -3
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
LEASE_WAIT_MS: () => LEASE_WAIT_MS,
|
|
36
36
|
acquireSessionLease: () => acquireSessionLease,
|
|
37
37
|
canAcquireLease: () => canAcquireLease,
|
|
38
|
+
createTursoWaAuthKV: () => createTursoWaAuthKV,
|
|
38
39
|
createTursoWaLeaseStore: () => createTursoWaLeaseStore,
|
|
39
40
|
createWhatsAppChannel: () => createWhatsAppChannel,
|
|
40
41
|
createWhatsAppImageHandler: () => createWhatsAppImageHandler,
|
|
@@ -50,12 +51,14 @@ __export(index_exports, {
|
|
|
50
51
|
jidsMatch: () => jidsMatch,
|
|
51
52
|
loadBaileys: () => loadBaileys,
|
|
52
53
|
messageContext: () => messageContext,
|
|
54
|
+
normalizeWaMediaPayload: () => normalizeWaMediaPayload,
|
|
53
55
|
reconnectDelayMs: () => reconnectDelayMs,
|
|
54
56
|
resolveWaMessage: () => resolveWaMessage,
|
|
55
57
|
senderNameFor: () => senderNameFor,
|
|
56
58
|
senderPhoneFor: () => senderPhoneFor,
|
|
57
59
|
shutdownWaSessions: () => shutdownWaSessions,
|
|
58
60
|
stripOwnMentions: () => stripOwnMentions,
|
|
61
|
+
useAuthState: () => useAuthState,
|
|
59
62
|
useTursoAuthState: () => useTursoAuthState
|
|
60
63
|
});
|
|
61
64
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -129,27 +132,55 @@ function ensureAuthSchema(client) {
|
|
|
129
132
|
}
|
|
130
133
|
return ready;
|
|
131
134
|
}
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
function createTursoWaAuthKV(db) {
|
|
136
|
+
return {
|
|
137
|
+
async read(id) {
|
|
138
|
+
await ensureAuthSchema(db);
|
|
139
|
+
const result = await db.execute({
|
|
140
|
+
sql: "SELECT value FROM wa_auth WHERE id = ?",
|
|
141
|
+
args: [id]
|
|
142
|
+
});
|
|
143
|
+
const row = result.rows[0];
|
|
144
|
+
return row ? row.value : null;
|
|
145
|
+
},
|
|
146
|
+
async write(id, value) {
|
|
147
|
+
await ensureAuthSchema(db);
|
|
148
|
+
await db.execute({
|
|
149
|
+
sql: "INSERT OR REPLACE INTO wa_auth (id, value) VALUES (?, ?)",
|
|
150
|
+
args: [id, value]
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
async remove(id) {
|
|
154
|
+
await ensureAuthSchema(db);
|
|
155
|
+
await db.execute({ sql: "DELETE FROM wa_auth WHERE id = ?", args: [id] });
|
|
156
|
+
},
|
|
157
|
+
// Mirrors isAuthRowForSession - keep the two in sync.
|
|
158
|
+
async clear(sessionId) {
|
|
159
|
+
await ensureAuthSchema(db);
|
|
160
|
+
if (sessionId === "default") {
|
|
161
|
+
await db.execute("DELETE FROM wa_auth WHERE id NOT LIKE 's:%'");
|
|
162
|
+
} else {
|
|
163
|
+
await db.execute({
|
|
164
|
+
sql: "DELETE FROM wa_auth WHERE id LIKE ?",
|
|
165
|
+
args: [`s:${sessionId}/%`]
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async function useAuthState(store, secret, sessionId, runtime) {
|
|
134
172
|
const rowId = (id) => sessionId === "default" ? id : `s:${sessionId}/${id}`;
|
|
135
173
|
async function read(id) {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
});
|
|
140
|
-
const row = result.rows[0];
|
|
141
|
-
if (!row) return null;
|
|
142
|
-
return JSON.parse(await decrypt(row.value, secret), runtime.bufferJSON.reviver);
|
|
174
|
+
const value = await store.read(rowId(id));
|
|
175
|
+
if (value === null) return null;
|
|
176
|
+
return JSON.parse(await decrypt(value, secret), runtime.bufferJSON.reviver);
|
|
143
177
|
}
|
|
144
178
|
async function write(id, value) {
|
|
145
179
|
const payload = await encrypt(JSON.stringify(value, runtime.bufferJSON.replacer), secret);
|
|
146
|
-
await
|
|
147
|
-
sql: "INSERT OR REPLACE INTO wa_auth (id, value) VALUES (?, ?)",
|
|
148
|
-
args: [rowId(id), payload]
|
|
149
|
-
});
|
|
180
|
+
await store.write(rowId(id), payload);
|
|
150
181
|
}
|
|
151
182
|
async function remove(id) {
|
|
152
|
-
await
|
|
183
|
+
await store.remove(rowId(id));
|
|
153
184
|
}
|
|
154
185
|
const creds = await read("creds") ?? runtime.initAuthCreds();
|
|
155
186
|
return {
|
|
@@ -186,18 +217,13 @@ async function useTursoAuthState(db, secret, sessionId, runtime) {
|
|
|
186
217
|
}
|
|
187
218
|
},
|
|
188
219
|
saveCreds: () => write("creds", creds),
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
await db.execute("DELETE FROM wa_auth WHERE id NOT LIKE 's:%'");
|
|
192
|
-
} else {
|
|
193
|
-
await db.execute({
|
|
194
|
-
sql: "DELETE FROM wa_auth WHERE id LIKE ?",
|
|
195
|
-
args: [`s:${sessionId}/%`]
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
220
|
+
// Scoped to THIS session - never nuke a sibling number's pairing.
|
|
221
|
+
clear: () => store.clear(sessionId)
|
|
199
222
|
};
|
|
200
223
|
}
|
|
224
|
+
async function useTursoAuthState(db, secret, sessionId, runtime) {
|
|
225
|
+
return useAuthState(createTursoWaAuthKV(db), secret, sessionId, runtime);
|
|
226
|
+
}
|
|
201
227
|
|
|
202
228
|
// src/channels/whatsapp/baileys.ts
|
|
203
229
|
function wrapMissingBaileysError(cause) {
|
|
@@ -260,6 +286,11 @@ function createConsoleLogger(level = "info") {
|
|
|
260
286
|
};
|
|
261
287
|
}
|
|
262
288
|
|
|
289
|
+
// src/channels/backoff.ts
|
|
290
|
+
function exponentialBackoffMs(baseMs, maxMs, n) {
|
|
291
|
+
return Math.min(baseMs * 2 ** Math.max(0, Math.min(n, 20)), maxMs);
|
|
292
|
+
}
|
|
293
|
+
|
|
263
294
|
// src/channels/whatsapp/lease.ts
|
|
264
295
|
var LEASE_STALE_MS = 9e4;
|
|
265
296
|
var LEASE_HEARTBEAT_MS = 3e4;
|
|
@@ -318,7 +349,7 @@ function createTursoWaLeaseStore(client) {
|
|
|
318
349
|
var RECONNECT_DELAY_MS = 5e3;
|
|
319
350
|
var RECONNECT_MAX_DELAY_MS = 10 * 60 * 1e3;
|
|
320
351
|
function reconnectDelayMs(failures) {
|
|
321
|
-
return
|
|
352
|
+
return exponentialBackoffMs(RECONNECT_DELAY_MS, RECONNECT_MAX_DELAY_MS, failures);
|
|
322
353
|
}
|
|
323
354
|
async function shutdownWaSessions(sessions) {
|
|
324
355
|
await Promise.all(
|
|
@@ -329,11 +360,17 @@ async function shutdownWaSessions(sessions) {
|
|
|
329
360
|
})
|
|
330
361
|
);
|
|
331
362
|
}
|
|
332
|
-
|
|
363
|
+
function claimSession(sessionId, sessions) {
|
|
333
364
|
const handle = sessions.get(sessionId);
|
|
334
|
-
if (!handle) return;
|
|
365
|
+
if (!handle) return void 0;
|
|
335
366
|
sessions.delete(sessionId);
|
|
367
|
+
return handle;
|
|
368
|
+
}
|
|
369
|
+
async function loseSession(sessionId, sessions) {
|
|
370
|
+
const handle = claimSession(sessionId, sessions);
|
|
371
|
+
if (!handle) return false;
|
|
336
372
|
await shutdownWaSessions(/* @__PURE__ */ new Map([[sessionId, handle]]));
|
|
373
|
+
return true;
|
|
337
374
|
}
|
|
338
375
|
async function acquireSessionLease(sessionId, deps) {
|
|
339
376
|
const { leaseStore, instanceId, sessions, isStopped, connect } = deps;
|
|
@@ -369,7 +406,9 @@ async function acquireSessionLease(sessionId, deps) {
|
|
|
369
406
|
void leaseStore.tryAcquire(sessionId, instanceId, now(), staleMs).then((stillHeld) => {
|
|
370
407
|
if (stillHeld || isStopped()) return;
|
|
371
408
|
logger.error(`WhatsApp[${sessionId}]: lost the lease to another instance \u2014 disconnecting`);
|
|
372
|
-
void loseSession(sessionId, sessions).then(
|
|
409
|
+
void loseSession(sessionId, sessions).then((lost) => {
|
|
410
|
+
if (lost) retry();
|
|
411
|
+
});
|
|
373
412
|
}).catch((error) => logger.warn(`WhatsApp[${sessionId}]: lease heartbeat failed:`, error));
|
|
374
413
|
}, heartbeatMs);
|
|
375
414
|
if (typeof heartbeat === "object" && "unref" in heartbeat) heartbeat.unref();
|
|
@@ -381,6 +420,10 @@ async function acquireSessionLease(sessionId, deps) {
|
|
|
381
420
|
try {
|
|
382
421
|
await connect(sessionId);
|
|
383
422
|
} catch (error) {
|
|
423
|
+
if (deps.onConnectFailed) {
|
|
424
|
+
deps.onConnectFailed(sessionId, error);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
384
427
|
logger.error(`WhatsApp[${sessionId}]: connect failed right after acquiring the lease:`, error);
|
|
385
428
|
await loseSession(sessionId, sessions);
|
|
386
429
|
retry();
|
|
@@ -389,9 +432,18 @@ async function acquireSessionLease(sessionId, deps) {
|
|
|
389
432
|
function senderNameFor(channelName, sessionId) {
|
|
390
433
|
return sessionId === "default" ? channelName : `${channelName}:${sessionId}`;
|
|
391
434
|
}
|
|
435
|
+
function normalizeWaMediaPayload(payload) {
|
|
436
|
+
const media = typeof payload === "string" ? { url: payload } : payload;
|
|
437
|
+
if (!media || typeof media !== "object" || typeof media.url !== "string" || !media.url) {
|
|
438
|
+
throw new TypeError(
|
|
439
|
+
`WhatsApp sendMedia payload must be a URL string or { url, caption? }, got: ${typeof payload}`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
return media;
|
|
443
|
+
}
|
|
392
444
|
function createWhatsAppChannel(config) {
|
|
393
445
|
assertStrongSecret(config.sessionSecret, "WhatsApp sessionSecret (e.g. WA_SESSION_SECRET)");
|
|
394
|
-
const channelName = "whatsapp";
|
|
446
|
+
const channelName = config.name ?? "whatsapp";
|
|
395
447
|
const sessionIds = config.sessionIds && config.sessionIds.length > 0 ? config.sessionIds : ["default"];
|
|
396
448
|
const now = config.now ?? Date.now;
|
|
397
449
|
const schedule = config.schedule ?? ((fn, ms) => void setTimeout(fn, ms));
|
|
@@ -409,10 +461,59 @@ function createWhatsAppChannel(config) {
|
|
|
409
461
|
name: channelName,
|
|
410
462
|
async start(deps) {
|
|
411
463
|
const log = config.logger ?? deps.logger ?? createConsoleLogger();
|
|
412
|
-
|
|
413
|
-
|
|
464
|
+
if ((!config.leaseStore || !config.authStore) && !deps.db) {
|
|
465
|
+
throw new Error(
|
|
466
|
+
"The WhatsApp channel needs a libsql client for auth state and the session lease: set config.database (config.retriever alone does not open one), or supply both config.leaseStore and config.authStore."
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
const leaseStore = config.leaseStore ?? createTursoWaLeaseStore(deps.db);
|
|
470
|
+
const authStore = config.authStore ?? createTursoWaAuthKV(deps.db);
|
|
414
471
|
senders = deps.senders;
|
|
415
472
|
await loadBaileys2();
|
|
473
|
+
const leaseDeps = {
|
|
474
|
+
leaseStore,
|
|
475
|
+
instanceId,
|
|
476
|
+
sessions,
|
|
477
|
+
isStopped: () => stopped,
|
|
478
|
+
connect,
|
|
479
|
+
now,
|
|
480
|
+
staleMs,
|
|
481
|
+
heartbeatMs,
|
|
482
|
+
waitMs,
|
|
483
|
+
schedule,
|
|
484
|
+
logger: log,
|
|
485
|
+
onConnectFailed: recoverFromFailedConnect
|
|
486
|
+
};
|
|
487
|
+
function nextRetryDelayMs(sessionId) {
|
|
488
|
+
const failures = failureCounts.get(sessionId) ?? 0;
|
|
489
|
+
failureCounts.set(sessionId, failures + 1);
|
|
490
|
+
return reconnectDelayMs(failures);
|
|
491
|
+
}
|
|
492
|
+
function attemptConnect(sessionId) {
|
|
493
|
+
void connect(sessionId).catch((error) => recoverFromFailedConnect(sessionId, error));
|
|
494
|
+
}
|
|
495
|
+
function recoverFromFailedConnect(sessionId, error) {
|
|
496
|
+
if (stopped) return;
|
|
497
|
+
const handle = claimSession(sessionId, sessions);
|
|
498
|
+
if (!handle) return;
|
|
499
|
+
const delay = nextRetryDelayMs(sessionId);
|
|
500
|
+
log.error(
|
|
501
|
+
`WhatsApp[${sessionId}]: connect attempt failed, releasing the lease and retrying in ${Math.round(delay / 1e3)}s:`,
|
|
502
|
+
error
|
|
503
|
+
);
|
|
504
|
+
schedule(
|
|
505
|
+
() => void acquireSessionLease(sessionId, leaseDeps).catch(
|
|
506
|
+
(retryError) => log.error(`WhatsApp[${sessionId}]: lease re-check failed:`, retryError)
|
|
507
|
+
),
|
|
508
|
+
delay
|
|
509
|
+
);
|
|
510
|
+
void shutdownWaSessions(/* @__PURE__ */ new Map([[sessionId, handle]])).catch(
|
|
511
|
+
(teardownError) => log.warn(
|
|
512
|
+
`WhatsApp[${sessionId}]: teardown after a failed connect failed:`,
|
|
513
|
+
teardownError
|
|
514
|
+
)
|
|
515
|
+
);
|
|
516
|
+
}
|
|
416
517
|
async function connect(sessionId) {
|
|
417
518
|
if (stopped || !sessions.has(sessionId)) return;
|
|
418
519
|
const baileys = await loadBaileys2();
|
|
@@ -421,8 +522,8 @@ function createWhatsAppChannel(config) {
|
|
|
421
522
|
initAuthCreds: baileys.initAuthCreds,
|
|
422
523
|
appStateSyncKeyFromObject: (value) => baileys.proto.Message.AppStateSyncKeyData.fromObject(value)
|
|
423
524
|
};
|
|
424
|
-
const { state, saveCreds } = await
|
|
425
|
-
|
|
525
|
+
const { state, saveCreds } = await useAuthState(
|
|
526
|
+
authStore,
|
|
426
527
|
config.sessionSecret,
|
|
427
528
|
sessionId,
|
|
428
529
|
runtime
|
|
@@ -431,7 +532,7 @@ function createWhatsAppChannel(config) {
|
|
|
431
532
|
log.warn(
|
|
432
533
|
`WhatsApp[${sessionId}]: no paired session found \u2014 pair it first (see docs/channels.md). Re-checking in 60s.`
|
|
433
534
|
);
|
|
434
|
-
schedule(() =>
|
|
535
|
+
schedule(() => attemptConnect(sessionId), 6e4);
|
|
435
536
|
return;
|
|
436
537
|
}
|
|
437
538
|
const { version } = await baileys.fetchLatestBaileysVersion();
|
|
@@ -466,6 +567,13 @@ function createWhatsAppChannel(config) {
|
|
|
466
567
|
sendText: async (chatId, text) => {
|
|
467
568
|
await sock.sendMessage(chatId, { text });
|
|
468
569
|
},
|
|
570
|
+
sendMedia: async (chatId, payload) => {
|
|
571
|
+
const { url, caption } = normalizeWaMediaPayload(payload);
|
|
572
|
+
await sock.sendMessage(
|
|
573
|
+
chatId,
|
|
574
|
+
caption !== void 0 ? { image: { url }, caption } : { image: { url } }
|
|
575
|
+
);
|
|
576
|
+
},
|
|
469
577
|
sendReaction: async (chatId, messageRef, emoji) => {
|
|
470
578
|
await sock.sendMessage(chatId, {
|
|
471
579
|
react: { text: emoji, key: messageRef }
|
|
@@ -490,17 +598,11 @@ function createWhatsAppChannel(config) {
|
|
|
490
598
|
return;
|
|
491
599
|
}
|
|
492
600
|
if (!stopped && sessions.has(sessionId)) {
|
|
493
|
-
const delay =
|
|
494
|
-
failureCounts.set(sessionId, (failureCounts.get(sessionId) ?? 0) + 1);
|
|
601
|
+
const delay = nextRetryDelayMs(sessionId);
|
|
495
602
|
log.warn(
|
|
496
603
|
`WhatsApp[${sessionId}]: connection closed (${statusCode ?? "?"}), reconnecting in ${Math.round(delay / 1e3)}s...`
|
|
497
604
|
);
|
|
498
|
-
schedule(
|
|
499
|
-
() => void connect(sessionId).catch(
|
|
500
|
-
(error) => log.error(`WhatsApp[${sessionId}]: reconnect failed:`, error)
|
|
501
|
-
),
|
|
502
|
-
delay
|
|
503
|
-
);
|
|
605
|
+
schedule(() => attemptConnect(sessionId), delay);
|
|
504
606
|
}
|
|
505
607
|
}
|
|
506
608
|
});
|
|
@@ -518,19 +620,9 @@ function createWhatsAppChannel(config) {
|
|
|
518
620
|
}
|
|
519
621
|
}
|
|
520
622
|
for (const sessionId of sessionIds) {
|
|
521
|
-
void acquireSessionLease(sessionId,
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
sessions,
|
|
525
|
-
isStopped: () => stopped,
|
|
526
|
-
connect,
|
|
527
|
-
now,
|
|
528
|
-
staleMs,
|
|
529
|
-
heartbeatMs,
|
|
530
|
-
waitMs,
|
|
531
|
-
schedule,
|
|
532
|
-
logger: log
|
|
533
|
-
}).catch((error) => log.error(`WhatsApp[${sessionId}]: failed to start:`, error));
|
|
623
|
+
void acquireSessionLease(sessionId, leaseDeps).catch(
|
|
624
|
+
(error) => log.error(`WhatsApp[${sessionId}]: failed to start:`, error)
|
|
625
|
+
);
|
|
534
626
|
}
|
|
535
627
|
},
|
|
536
628
|
async stop() {
|
|
@@ -741,7 +833,8 @@ async function answerOnce({
|
|
|
741
833
|
async function applyTransformReply(transformReply, input, logger) {
|
|
742
834
|
if (!transformReply) return input.text;
|
|
743
835
|
try {
|
|
744
|
-
|
|
836
|
+
const result = await transformReply(input);
|
|
837
|
+
return typeof result === "string" ? result : null;
|
|
745
838
|
} catch (error) {
|
|
746
839
|
logger?.error(
|
|
747
840
|
`transformReply threw for channel "${input.channel}"; sending the original reply`,
|
|
@@ -803,6 +896,7 @@ async function prepareChat({
|
|
|
803
896
|
sender,
|
|
804
897
|
rewriteQuery,
|
|
805
898
|
rerankContext,
|
|
899
|
+
fallbackFn,
|
|
806
900
|
logger
|
|
807
901
|
}) {
|
|
808
902
|
const lastUserMsg = lastUserMessage(messages);
|
|
@@ -819,21 +913,39 @@ async function prepareChat({
|
|
|
819
913
|
logger?.error("rewriteQuery threw; falling back to the original query", error);
|
|
820
914
|
}
|
|
821
915
|
}
|
|
822
|
-
|
|
916
|
+
const resolvedBuckets = buckets ?? defaultBuckets(mode);
|
|
917
|
+
const retrievedChunks = await store.query(query, topK, resolvedBuckets);
|
|
918
|
+
let ctx = retrievedChunks;
|
|
823
919
|
if (rerankContext) {
|
|
824
920
|
try {
|
|
825
|
-
const reranked = await rerankContext({ query, chunks: ctx });
|
|
921
|
+
const reranked = await rerankContext({ query, chunks: [...ctx] });
|
|
826
922
|
if (Array.isArray(reranked) && reranked.every((c) => typeof c === "string")) ctx = reranked;
|
|
827
923
|
} catch (error) {
|
|
828
924
|
logger?.error("rerankContext threw; falling back to the original chunks", error);
|
|
829
925
|
}
|
|
830
926
|
}
|
|
927
|
+
let fallback;
|
|
928
|
+
if (ctx.length === 0 && fallbackFn) {
|
|
929
|
+
try {
|
|
930
|
+
const guidance = await fallbackFn({
|
|
931
|
+
query,
|
|
932
|
+
mode,
|
|
933
|
+
buckets: resolvedBuckets,
|
|
934
|
+
sender,
|
|
935
|
+
retrievedChunks
|
|
936
|
+
});
|
|
937
|
+
if (typeof guidance === "string" && guidance.trim()) fallback = guidance.trim();
|
|
938
|
+
} catch (error) {
|
|
939
|
+
logger?.error("fallbackFn threw; proceeding without fallback guidance", error);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
831
942
|
const persona = personaLayer?.trim() || (mode === "private" ? prompts.privatePersona : prompts.publicPersona);
|
|
832
943
|
const hint = channelHint?.trim();
|
|
833
944
|
const system = [
|
|
834
945
|
prompts.baseSystemRules,
|
|
835
946
|
persona,
|
|
836
947
|
...hint ? [hint] : [],
|
|
948
|
+
...fallback ? [fallback] : [],
|
|
837
949
|
`${label}:
|
|
838
950
|
${ctx.join("\n\n")}`
|
|
839
951
|
].join("\n\n");
|
|
@@ -841,7 +953,7 @@ ${ctx.join("\n\n")}`
|
|
|
841
953
|
}
|
|
842
954
|
|
|
843
955
|
// src/history/compaction.ts
|
|
844
|
-
var
|
|
956
|
+
var COMPACTION_TIMEOUT_MS = 8e3;
|
|
845
957
|
var LOAD_ALL = Number.MAX_SAFE_INTEGER;
|
|
846
958
|
var SUMMARY_PREFIX = "Summary of earlier conversation: ";
|
|
847
959
|
function defaultSummarize(client, model) {
|
|
@@ -869,7 +981,7 @@ function createHistoryCompactor(deps, options) {
|
|
|
869
981
|
throw new Error(`Invalid history compaction keep: ${keep}`);
|
|
870
982
|
}
|
|
871
983
|
const summarize = options.summarize ?? defaultSummarize(deps.client, options.model);
|
|
872
|
-
const timeoutMs = options.timeoutMs ??
|
|
984
|
+
const timeoutMs = options.timeoutMs ?? COMPACTION_TIMEOUT_MS;
|
|
873
985
|
return {
|
|
874
986
|
async maybeCompact(store, conversationId) {
|
|
875
987
|
const turns = await store.load(conversationId, LOAD_ALL);
|
|
@@ -910,6 +1022,16 @@ function createHistoryCompactor(deps, options) {
|
|
|
910
1022
|
}
|
|
911
1023
|
|
|
912
1024
|
// src/channels/pipeline.ts
|
|
1025
|
+
function resolveBrainHooks(config, fallback) {
|
|
1026
|
+
return {
|
|
1027
|
+
answerFn: config.answerFn ?? fallback?.answerFn,
|
|
1028
|
+
bucketsFor: config.bucketsFor ?? fallback?.bucketsFor,
|
|
1029
|
+
rewriteQuery: config.rewriteQuery ?? fallback?.rewriteQuery,
|
|
1030
|
+
rerankContext: config.rerankContext ?? fallback?.rerankContext,
|
|
1031
|
+
fallbackFn: config.fallbackFn ?? fallback?.fallbackFn,
|
|
1032
|
+
transformReply: config.transformReply ?? fallback?.transformReply
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
913
1035
|
var DEFAULT_HISTORY_LIMIT = 20;
|
|
914
1036
|
var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
|
|
915
1037
|
var DEFAULT_DM_RATE_LIMIT = { max: 20, windowMs: 60 * 60 * 1e3 };
|
|
@@ -994,6 +1116,7 @@ function createInboundPipeline(deps, config) {
|
|
|
994
1116
|
sender,
|
|
995
1117
|
rewriteQuery: config.rewriteQuery,
|
|
996
1118
|
rerankContext: config.rerankContext,
|
|
1119
|
+
fallbackFn: config.fallbackFn,
|
|
997
1120
|
logger: config.logger
|
|
998
1121
|
});
|
|
999
1122
|
const { content: produced } = await answerOnce({
|
|
@@ -1129,13 +1252,9 @@ function createWhatsAppInboundHandler(config) {
|
|
|
1129
1252
|
{ client: config.client, store: config.store, prompts: config.prompts },
|
|
1130
1253
|
{
|
|
1131
1254
|
channel: "whatsapp",
|
|
1132
|
-
|
|
1133
|
-
bucketsFor: config.bucketsFor,
|
|
1134
|
-
rewriteQuery: config.rewriteQuery,
|
|
1135
|
-
rerankContext: config.rerankContext,
|
|
1136
|
-
transformReply: config.transformReply,
|
|
1255
|
+
...resolveBrainHooks(config, config.serverConfig),
|
|
1137
1256
|
model: config.model,
|
|
1138
|
-
channelHint: config.channelHint,
|
|
1257
|
+
channelHint: config.channelHint ?? "Channel: WhatsApp.",
|
|
1139
1258
|
personaResolver: personaResolver ? ({ sender, text }) => personaResolver({ senderPhone: sender, text }) : void 0,
|
|
1140
1259
|
history: config.history,
|
|
1141
1260
|
allowedChats,
|
|
@@ -1296,6 +1415,7 @@ function createWhatsAppMessageRouter(config) {
|
|
|
1296
1415
|
LEASE_WAIT_MS,
|
|
1297
1416
|
acquireSessionLease,
|
|
1298
1417
|
canAcquireLease,
|
|
1418
|
+
createTursoWaAuthKV,
|
|
1299
1419
|
createTursoWaLeaseStore,
|
|
1300
1420
|
createWhatsAppChannel,
|
|
1301
1421
|
createWhatsAppImageHandler,
|
|
@@ -1311,11 +1431,13 @@ function createWhatsAppMessageRouter(config) {
|
|
|
1311
1431
|
jidsMatch,
|
|
1312
1432
|
loadBaileys,
|
|
1313
1433
|
messageContext,
|
|
1434
|
+
normalizeWaMediaPayload,
|
|
1314
1435
|
reconnectDelayMs,
|
|
1315
1436
|
resolveWaMessage,
|
|
1316
1437
|
senderNameFor,
|
|
1317
1438
|
senderPhoneFor,
|
|
1318
1439
|
shutdownWaSessions,
|
|
1319
1440
|
stripOwnMentions,
|
|
1441
|
+
useAuthState,
|
|
1320
1442
|
useTursoAuthState
|
|
1321
1443
|
});
|