@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.
Files changed (125) hide show
  1. package/README.md +55 -17
  2. package/dist/auth/secretStrength.d.ts +1 -1
  3. package/dist/auth/secretStrength.d.ts.map +1 -1
  4. package/dist/bin/create-apikey.js +45 -28
  5. package/dist/bin/wa-pair.js +113 -46
  6. package/dist/channels/backoff.d.ts +10 -0
  7. package/dist/channels/backoff.d.ts.map +1 -0
  8. package/dist/channels/gates.d.ts +15 -8
  9. package/dist/channels/gates.d.ts.map +1 -1
  10. package/dist/channels/index.d.ts +1 -1
  11. package/dist/channels/index.d.ts.map +1 -1
  12. package/dist/channels/index.js +38 -5
  13. package/dist/channels/index.mjs +37 -5
  14. package/dist/channels/matrix/api.d.ts +25 -6
  15. package/dist/channels/matrix/api.d.ts.map +1 -1
  16. package/dist/channels/matrix/channel.d.ts +4 -56
  17. package/dist/channels/matrix/channel.d.ts.map +1 -1
  18. package/dist/channels/matrix/handler.d.ts +16 -9
  19. package/dist/channels/matrix/handler.d.ts.map +1 -1
  20. package/dist/channels/matrix/index.d.ts +2 -2
  21. package/dist/channels/matrix/index.d.ts.map +1 -1
  22. package/dist/channels/matrix/index.js +196 -40
  23. package/dist/channels/matrix/index.mjs +189 -39
  24. package/dist/channels/matrix/sync.d.ts +4 -1
  25. package/dist/channels/matrix/sync.d.ts.map +1 -1
  26. package/dist/channels/matrix/updates.d.ts +39 -10
  27. package/dist/channels/matrix/updates.d.ts.map +1 -1
  28. package/dist/channels/pipeline.d.ts +14 -14
  29. package/dist/channels/pipeline.d.ts.map +1 -1
  30. package/dist/channels/polling.d.ts +67 -0
  31. package/dist/channels/polling.d.ts.map +1 -0
  32. package/dist/channels/telegram/channel.d.ts +2 -56
  33. package/dist/channels/telegram/channel.d.ts.map +1 -1
  34. package/dist/channels/telegram/index.js +53 -23
  35. package/dist/channels/telegram/index.mjs +53 -23
  36. package/dist/channels/telegram/poll.d.ts +5 -1
  37. package/dist/channels/telegram/poll.d.ts.map +1 -1
  38. package/dist/channels/telegram/webhook.d.ts +2 -10
  39. package/dist/channels/telegram/webhook.d.ts.map +1 -1
  40. package/dist/channels/whatsapp/authState.d.ts +40 -9
  41. package/dist/channels/whatsapp/authState.d.ts.map +1 -1
  42. package/dist/channels/whatsapp/channel.d.ts +39 -4
  43. package/dist/channels/whatsapp/channel.d.ts.map +1 -1
  44. package/dist/channels/whatsapp/inbound.d.ts +23 -25
  45. package/dist/channels/whatsapp/inbound.d.ts.map +1 -1
  46. package/dist/channels/whatsapp/index.d.ts +3 -3
  47. package/dist/channels/whatsapp/index.d.ts.map +1 -1
  48. package/dist/channels/whatsapp/index.js +188 -66
  49. package/dist/channels/whatsapp/index.mjs +185 -66
  50. package/dist/channels/whatsapp/pairing.d.ts.map +1 -1
  51. package/dist/client/src/Chat.d.ts.map +1 -1
  52. package/dist/client/src/ChatButton.d.ts.map +1 -1
  53. package/dist/client/src/browser.d.ts.map +1 -1
  54. package/dist/core/answer.d.ts +8 -0
  55. package/dist/core/answer.d.ts.map +1 -1
  56. package/dist/core/buildLock.d.ts +52 -0
  57. package/dist/core/buildLock.d.ts.map +1 -0
  58. package/dist/core/pipeline.d.ts +42 -5
  59. package/dist/core/pipeline.d.ts.map +1 -1
  60. package/dist/core/prompts.d.ts +2 -0
  61. package/dist/core/prompts.d.ts.map +1 -1
  62. package/dist/core/retrieval.d.ts +100 -25
  63. package/dist/core/retrieval.d.ts.map +1 -1
  64. package/dist/core/session.d.ts +8 -0
  65. package/dist/core/session.d.ts.map +1 -1
  66. package/dist/flows/index.d.ts +1 -1
  67. package/dist/flows/index.d.ts.map +1 -1
  68. package/dist/flows/index.js +8 -6
  69. package/dist/flows/index.mjs +7 -6
  70. package/dist/flows/intent.d.ts +1 -1
  71. package/dist/flows/intent.d.ts.map +1 -1
  72. package/dist/flows/loader.d.ts +1 -2
  73. package/dist/flows/loader.d.ts.map +1 -1
  74. package/dist/flows/params.d.ts +1 -1
  75. package/dist/flows/params.d.ts.map +1 -1
  76. package/dist/flows/session.d.ts +4 -2
  77. package/dist/flows/session.d.ts.map +1 -1
  78. package/dist/flows/types.d.ts +2 -3
  79. package/dist/flows/types.d.ts.map +1 -1
  80. package/dist/history/index.d.ts +1 -1
  81. package/dist/history/index.d.ts.map +1 -1
  82. package/dist/history/index.js +6 -3
  83. package/dist/history/index.mjs +5 -3
  84. package/dist/history/tursoStore.d.ts +6 -4
  85. package/dist/history/tursoStore.d.ts.map +1 -1
  86. package/dist/images/index.js +2 -2
  87. package/dist/images/index.mjs +2 -2
  88. package/dist/index.d.ts +7 -5
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +596 -295
  91. package/dist/index.mjs +595 -295
  92. package/dist/mcp-server/index.d.ts +5 -5
  93. package/dist/mcp-server/index.d.ts.map +1 -1
  94. package/dist/mcp-server/logger.d.ts +12 -2
  95. package/dist/mcp-server/logger.d.ts.map +1 -1
  96. package/dist/mcp-server/rate-limiter.d.ts +10 -3
  97. package/dist/mcp-server/rate-limiter.d.ts.map +1 -1
  98. package/dist/mcp-server/types.d.ts +20 -5
  99. package/dist/mcp-server/types.d.ts.map +1 -1
  100. package/dist/mcp-server.js +479 -244
  101. package/dist/mcp-server.mjs +485 -244
  102. package/dist/middleware/apiKey.d.ts +10 -0
  103. package/dist/middleware/apiKey.d.ts.map +1 -0
  104. package/dist/middleware/auth.d.ts.map +1 -1
  105. package/dist/middleware/cors.d.ts.map +1 -1
  106. package/dist/middleware/ratelimit.d.ts.map +1 -1
  107. package/dist/middleware/referrer.d.ts.map +1 -1
  108. package/dist/middleware/session.d.ts +1 -1
  109. package/dist/middleware/session.d.ts.map +1 -1
  110. package/dist/routes/demo.d.ts.map +1 -1
  111. package/dist/routes/openai.d.ts.map +1 -1
  112. package/dist/routes/private.d.ts.map +1 -1
  113. package/dist/routes/public.d.ts.map +1 -1
  114. package/dist/scheduler/index.js +1 -1
  115. package/dist/scheduler/index.mjs +1 -1
  116. package/dist/scheduler/scheduler.d.ts +9 -1
  117. package/dist/scheduler/scheduler.d.ts.map +1 -1
  118. package/dist/server.d.ts.map +1 -1
  119. package/dist/server.js +491 -268
  120. package/dist/server.mjs +497 -268
  121. package/dist/shortener.d.ts +5 -4
  122. package/dist/shortener.d.ts.map +1 -1
  123. package/dist/types.d.ts +129 -75
  124. package/dist/types.d.ts.map +1 -1
  125. package/package.json +6 -3
@@ -67,27 +67,55 @@ function ensureAuthSchema(client) {
67
67
  }
68
68
  return ready;
69
69
  }
70
- async function useTursoAuthState(db, secret, sessionId, runtime) {
71
- await ensureAuthSchema(db);
70
+ function createTursoWaAuthKV(db) {
71
+ return {
72
+ async read(id) {
73
+ await ensureAuthSchema(db);
74
+ const result = await db.execute({
75
+ sql: "SELECT value FROM wa_auth WHERE id = ?",
76
+ args: [id]
77
+ });
78
+ const row = result.rows[0];
79
+ return row ? row.value : null;
80
+ },
81
+ async write(id, value) {
82
+ await ensureAuthSchema(db);
83
+ await db.execute({
84
+ sql: "INSERT OR REPLACE INTO wa_auth (id, value) VALUES (?, ?)",
85
+ args: [id, value]
86
+ });
87
+ },
88
+ async remove(id) {
89
+ await ensureAuthSchema(db);
90
+ await db.execute({ sql: "DELETE FROM wa_auth WHERE id = ?", args: [id] });
91
+ },
92
+ // Mirrors isAuthRowForSession - keep the two in sync.
93
+ async clear(sessionId) {
94
+ await ensureAuthSchema(db);
95
+ if (sessionId === "default") {
96
+ await db.execute("DELETE FROM wa_auth WHERE id NOT LIKE 's:%'");
97
+ } else {
98
+ await db.execute({
99
+ sql: "DELETE FROM wa_auth WHERE id LIKE ?",
100
+ args: [`s:${sessionId}/%`]
101
+ });
102
+ }
103
+ }
104
+ };
105
+ }
106
+ async function useAuthState(store, secret, sessionId, runtime) {
72
107
  const rowId = (id) => sessionId === "default" ? id : `s:${sessionId}/${id}`;
73
108
  async function read(id) {
74
- const result = await db.execute({
75
- sql: "SELECT value FROM wa_auth WHERE id = ?",
76
- args: [rowId(id)]
77
- });
78
- const row = result.rows[0];
79
- if (!row) return null;
80
- return JSON.parse(await decrypt(row.value, secret), runtime.bufferJSON.reviver);
109
+ const value = await store.read(rowId(id));
110
+ if (value === null) return null;
111
+ return JSON.parse(await decrypt(value, secret), runtime.bufferJSON.reviver);
81
112
  }
82
113
  async function write(id, value) {
83
114
  const payload = await encrypt(JSON.stringify(value, runtime.bufferJSON.replacer), secret);
84
- await db.execute({
85
- sql: "INSERT OR REPLACE INTO wa_auth (id, value) VALUES (?, ?)",
86
- args: [rowId(id), payload]
87
- });
115
+ await store.write(rowId(id), payload);
88
116
  }
89
117
  async function remove(id) {
90
- await db.execute({ sql: "DELETE FROM wa_auth WHERE id = ?", args: [rowId(id)] });
118
+ await store.remove(rowId(id));
91
119
  }
92
120
  const creds = await read("creds") ?? runtime.initAuthCreds();
93
121
  return {
@@ -124,18 +152,13 @@ async function useTursoAuthState(db, secret, sessionId, runtime) {
124
152
  }
125
153
  },
126
154
  saveCreds: () => write("creds", creds),
127
- clear: async () => {
128
- if (sessionId === "default") {
129
- await db.execute("DELETE FROM wa_auth WHERE id NOT LIKE 's:%'");
130
- } else {
131
- await db.execute({
132
- sql: "DELETE FROM wa_auth WHERE id LIKE ?",
133
- args: [`s:${sessionId}/%`]
134
- });
135
- }
136
- }
155
+ // Scoped to THIS session - never nuke a sibling number's pairing.
156
+ clear: () => store.clear(sessionId)
137
157
  };
138
158
  }
159
+ async function useTursoAuthState(db, secret, sessionId, runtime) {
160
+ return useAuthState(createTursoWaAuthKV(db), secret, sessionId, runtime);
161
+ }
139
162
 
140
163
  // src/channels/whatsapp/baileys.ts
141
164
  function wrapMissingBaileysError(cause) {
@@ -198,6 +221,11 @@ function createConsoleLogger(level = "info") {
198
221
  };
199
222
  }
200
223
 
224
+ // src/channels/backoff.ts
225
+ function exponentialBackoffMs(baseMs, maxMs, n) {
226
+ return Math.min(baseMs * 2 ** Math.max(0, Math.min(n, 20)), maxMs);
227
+ }
228
+
201
229
  // src/channels/whatsapp/lease.ts
202
230
  var LEASE_STALE_MS = 9e4;
203
231
  var LEASE_HEARTBEAT_MS = 3e4;
@@ -256,7 +284,7 @@ function createTursoWaLeaseStore(client) {
256
284
  var RECONNECT_DELAY_MS = 5e3;
257
285
  var RECONNECT_MAX_DELAY_MS = 10 * 60 * 1e3;
258
286
  function reconnectDelayMs(failures) {
259
- return Math.min(RECONNECT_DELAY_MS * 2 ** Math.min(failures, 20), RECONNECT_MAX_DELAY_MS);
287
+ return exponentialBackoffMs(RECONNECT_DELAY_MS, RECONNECT_MAX_DELAY_MS, failures);
260
288
  }
261
289
  async function shutdownWaSessions(sessions) {
262
290
  await Promise.all(
@@ -267,11 +295,17 @@ async function shutdownWaSessions(sessions) {
267
295
  })
268
296
  );
269
297
  }
270
- async function loseSession(sessionId, sessions) {
298
+ function claimSession(sessionId, sessions) {
271
299
  const handle = sessions.get(sessionId);
272
- if (!handle) return;
300
+ if (!handle) return void 0;
273
301
  sessions.delete(sessionId);
302
+ return handle;
303
+ }
304
+ async function loseSession(sessionId, sessions) {
305
+ const handle = claimSession(sessionId, sessions);
306
+ if (!handle) return false;
274
307
  await shutdownWaSessions(/* @__PURE__ */ new Map([[sessionId, handle]]));
308
+ return true;
275
309
  }
276
310
  async function acquireSessionLease(sessionId, deps) {
277
311
  const { leaseStore, instanceId, sessions, isStopped, connect } = deps;
@@ -307,7 +341,9 @@ async function acquireSessionLease(sessionId, deps) {
307
341
  void leaseStore.tryAcquire(sessionId, instanceId, now(), staleMs).then((stillHeld) => {
308
342
  if (stillHeld || isStopped()) return;
309
343
  logger.error(`WhatsApp[${sessionId}]: lost the lease to another instance \u2014 disconnecting`);
310
- void loseSession(sessionId, sessions).then(retry);
344
+ void loseSession(sessionId, sessions).then((lost) => {
345
+ if (lost) retry();
346
+ });
311
347
  }).catch((error) => logger.warn(`WhatsApp[${sessionId}]: lease heartbeat failed:`, error));
312
348
  }, heartbeatMs);
313
349
  if (typeof heartbeat === "object" && "unref" in heartbeat) heartbeat.unref();
@@ -319,6 +355,10 @@ async function acquireSessionLease(sessionId, deps) {
319
355
  try {
320
356
  await connect(sessionId);
321
357
  } catch (error) {
358
+ if (deps.onConnectFailed) {
359
+ deps.onConnectFailed(sessionId, error);
360
+ return;
361
+ }
322
362
  logger.error(`WhatsApp[${sessionId}]: connect failed right after acquiring the lease:`, error);
323
363
  await loseSession(sessionId, sessions);
324
364
  retry();
@@ -327,9 +367,18 @@ async function acquireSessionLease(sessionId, deps) {
327
367
  function senderNameFor(channelName, sessionId) {
328
368
  return sessionId === "default" ? channelName : `${channelName}:${sessionId}`;
329
369
  }
370
+ function normalizeWaMediaPayload(payload) {
371
+ const media = typeof payload === "string" ? { url: payload } : payload;
372
+ if (!media || typeof media !== "object" || typeof media.url !== "string" || !media.url) {
373
+ throw new TypeError(
374
+ `WhatsApp sendMedia payload must be a URL string or { url, caption? }, got: ${typeof payload}`
375
+ );
376
+ }
377
+ return media;
378
+ }
330
379
  function createWhatsAppChannel(config) {
331
380
  assertStrongSecret(config.sessionSecret, "WhatsApp sessionSecret (e.g. WA_SESSION_SECRET)");
332
- const channelName = "whatsapp";
381
+ const channelName = config.name ?? "whatsapp";
333
382
  const sessionIds = config.sessionIds && config.sessionIds.length > 0 ? config.sessionIds : ["default"];
334
383
  const now = config.now ?? Date.now;
335
384
  const schedule = config.schedule ?? ((fn, ms) => void setTimeout(fn, ms));
@@ -347,10 +396,59 @@ function createWhatsAppChannel(config) {
347
396
  name: channelName,
348
397
  async start(deps) {
349
398
  const log = config.logger ?? deps.logger ?? createConsoleLogger();
350
- const db = deps.db;
351
- const leaseStore = createTursoWaLeaseStore(db);
399
+ if ((!config.leaseStore || !config.authStore) && !deps.db) {
400
+ throw new Error(
401
+ "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."
402
+ );
403
+ }
404
+ const leaseStore = config.leaseStore ?? createTursoWaLeaseStore(deps.db);
405
+ const authStore = config.authStore ?? createTursoWaAuthKV(deps.db);
352
406
  senders = deps.senders;
353
407
  await loadBaileys2();
408
+ const leaseDeps = {
409
+ leaseStore,
410
+ instanceId,
411
+ sessions,
412
+ isStopped: () => stopped,
413
+ connect,
414
+ now,
415
+ staleMs,
416
+ heartbeatMs,
417
+ waitMs,
418
+ schedule,
419
+ logger: log,
420
+ onConnectFailed: recoverFromFailedConnect
421
+ };
422
+ function nextRetryDelayMs(sessionId) {
423
+ const failures = failureCounts.get(sessionId) ?? 0;
424
+ failureCounts.set(sessionId, failures + 1);
425
+ return reconnectDelayMs(failures);
426
+ }
427
+ function attemptConnect(sessionId) {
428
+ void connect(sessionId).catch((error) => recoverFromFailedConnect(sessionId, error));
429
+ }
430
+ function recoverFromFailedConnect(sessionId, error) {
431
+ if (stopped) return;
432
+ const handle = claimSession(sessionId, sessions);
433
+ if (!handle) return;
434
+ const delay = nextRetryDelayMs(sessionId);
435
+ log.error(
436
+ `WhatsApp[${sessionId}]: connect attempt failed, releasing the lease and retrying in ${Math.round(delay / 1e3)}s:`,
437
+ error
438
+ );
439
+ schedule(
440
+ () => void acquireSessionLease(sessionId, leaseDeps).catch(
441
+ (retryError) => log.error(`WhatsApp[${sessionId}]: lease re-check failed:`, retryError)
442
+ ),
443
+ delay
444
+ );
445
+ void shutdownWaSessions(/* @__PURE__ */ new Map([[sessionId, handle]])).catch(
446
+ (teardownError) => log.warn(
447
+ `WhatsApp[${sessionId}]: teardown after a failed connect failed:`,
448
+ teardownError
449
+ )
450
+ );
451
+ }
354
452
  async function connect(sessionId) {
355
453
  if (stopped || !sessions.has(sessionId)) return;
356
454
  const baileys = await loadBaileys2();
@@ -359,8 +457,8 @@ function createWhatsAppChannel(config) {
359
457
  initAuthCreds: baileys.initAuthCreds,
360
458
  appStateSyncKeyFromObject: (value) => baileys.proto.Message.AppStateSyncKeyData.fromObject(value)
361
459
  };
362
- const { state, saveCreds } = await useTursoAuthState(
363
- db,
460
+ const { state, saveCreds } = await useAuthState(
461
+ authStore,
364
462
  config.sessionSecret,
365
463
  sessionId,
366
464
  runtime
@@ -369,7 +467,7 @@ function createWhatsAppChannel(config) {
369
467
  log.warn(
370
468
  `WhatsApp[${sessionId}]: no paired session found \u2014 pair it first (see docs/channels.md). Re-checking in 60s.`
371
469
  );
372
- schedule(() => void connect(sessionId).catch(() => void 0), 6e4);
470
+ schedule(() => attemptConnect(sessionId), 6e4);
373
471
  return;
374
472
  }
375
473
  const { version } = await baileys.fetchLatestBaileysVersion();
@@ -404,6 +502,13 @@ function createWhatsAppChannel(config) {
404
502
  sendText: async (chatId, text) => {
405
503
  await sock.sendMessage(chatId, { text });
406
504
  },
505
+ sendMedia: async (chatId, payload) => {
506
+ const { url, caption } = normalizeWaMediaPayload(payload);
507
+ await sock.sendMessage(
508
+ chatId,
509
+ caption !== void 0 ? { image: { url }, caption } : { image: { url } }
510
+ );
511
+ },
407
512
  sendReaction: async (chatId, messageRef, emoji) => {
408
513
  await sock.sendMessage(chatId, {
409
514
  react: { text: emoji, key: messageRef }
@@ -428,17 +533,11 @@ function createWhatsAppChannel(config) {
428
533
  return;
429
534
  }
430
535
  if (!stopped && sessions.has(sessionId)) {
431
- const delay = reconnectDelayMs(failureCounts.get(sessionId) ?? 0);
432
- failureCounts.set(sessionId, (failureCounts.get(sessionId) ?? 0) + 1);
536
+ const delay = nextRetryDelayMs(sessionId);
433
537
  log.warn(
434
538
  `WhatsApp[${sessionId}]: connection closed (${statusCode ?? "?"}), reconnecting in ${Math.round(delay / 1e3)}s...`
435
539
  );
436
- schedule(
437
- () => void connect(sessionId).catch(
438
- (error) => log.error(`WhatsApp[${sessionId}]: reconnect failed:`, error)
439
- ),
440
- delay
441
- );
540
+ schedule(() => attemptConnect(sessionId), delay);
442
541
  }
443
542
  }
444
543
  });
@@ -456,19 +555,9 @@ function createWhatsAppChannel(config) {
456
555
  }
457
556
  }
458
557
  for (const sessionId of sessionIds) {
459
- void acquireSessionLease(sessionId, {
460
- leaseStore,
461
- instanceId,
462
- sessions,
463
- isStopped: () => stopped,
464
- connect,
465
- now,
466
- staleMs,
467
- heartbeatMs,
468
- waitMs,
469
- schedule,
470
- logger: log
471
- }).catch((error) => log.error(`WhatsApp[${sessionId}]: failed to start:`, error));
558
+ void acquireSessionLease(sessionId, leaseDeps).catch(
559
+ (error) => log.error(`WhatsApp[${sessionId}]: failed to start:`, error)
560
+ );
472
561
  }
473
562
  },
474
563
  async stop() {
@@ -679,7 +768,8 @@ async function answerOnce({
679
768
  async function applyTransformReply(transformReply, input, logger) {
680
769
  if (!transformReply) return input.text;
681
770
  try {
682
- return await transformReply(input);
771
+ const result = await transformReply(input);
772
+ return typeof result === "string" ? result : null;
683
773
  } catch (error) {
684
774
  logger?.error(
685
775
  `transformReply threw for channel "${input.channel}"; sending the original reply`,
@@ -741,6 +831,7 @@ async function prepareChat({
741
831
  sender,
742
832
  rewriteQuery,
743
833
  rerankContext,
834
+ fallbackFn,
744
835
  logger
745
836
  }) {
746
837
  const lastUserMsg = lastUserMessage(messages);
@@ -757,21 +848,39 @@ async function prepareChat({
757
848
  logger?.error("rewriteQuery threw; falling back to the original query", error);
758
849
  }
759
850
  }
760
- let ctx = await store.query(query, topK, buckets ?? defaultBuckets(mode));
851
+ const resolvedBuckets = buckets ?? defaultBuckets(mode);
852
+ const retrievedChunks = await store.query(query, topK, resolvedBuckets);
853
+ let ctx = retrievedChunks;
761
854
  if (rerankContext) {
762
855
  try {
763
- const reranked = await rerankContext({ query, chunks: ctx });
856
+ const reranked = await rerankContext({ query, chunks: [...ctx] });
764
857
  if (Array.isArray(reranked) && reranked.every((c) => typeof c === "string")) ctx = reranked;
765
858
  } catch (error) {
766
859
  logger?.error("rerankContext threw; falling back to the original chunks", error);
767
860
  }
768
861
  }
862
+ let fallback;
863
+ if (ctx.length === 0 && fallbackFn) {
864
+ try {
865
+ const guidance = await fallbackFn({
866
+ query,
867
+ mode,
868
+ buckets: resolvedBuckets,
869
+ sender,
870
+ retrievedChunks
871
+ });
872
+ if (typeof guidance === "string" && guidance.trim()) fallback = guidance.trim();
873
+ } catch (error) {
874
+ logger?.error("fallbackFn threw; proceeding without fallback guidance", error);
875
+ }
876
+ }
769
877
  const persona = personaLayer?.trim() || (mode === "private" ? prompts.privatePersona : prompts.publicPersona);
770
878
  const hint = channelHint?.trim();
771
879
  const system = [
772
880
  prompts.baseSystemRules,
773
881
  persona,
774
882
  ...hint ? [hint] : [],
883
+ ...fallback ? [fallback] : [],
775
884
  `${label}:
776
885
  ${ctx.join("\n\n")}`
777
886
  ].join("\n\n");
@@ -779,7 +888,7 @@ ${ctx.join("\n\n")}`
779
888
  }
780
889
 
781
890
  // src/history/compaction.ts
782
- var DEFAULT_TIMEOUT_MS = 8e3;
891
+ var COMPACTION_TIMEOUT_MS = 8e3;
783
892
  var LOAD_ALL = Number.MAX_SAFE_INTEGER;
784
893
  var SUMMARY_PREFIX = "Summary of earlier conversation: ";
785
894
  function defaultSummarize(client, model) {
@@ -807,7 +916,7 @@ function createHistoryCompactor(deps, options) {
807
916
  throw new Error(`Invalid history compaction keep: ${keep}`);
808
917
  }
809
918
  const summarize = options.summarize ?? defaultSummarize(deps.client, options.model);
810
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
919
+ const timeoutMs = options.timeoutMs ?? COMPACTION_TIMEOUT_MS;
811
920
  return {
812
921
  async maybeCompact(store, conversationId) {
813
922
  const turns = await store.load(conversationId, LOAD_ALL);
@@ -848,6 +957,16 @@ function createHistoryCompactor(deps, options) {
848
957
  }
849
958
 
850
959
  // src/channels/pipeline.ts
960
+ function resolveBrainHooks(config, fallback) {
961
+ return {
962
+ answerFn: config.answerFn ?? fallback?.answerFn,
963
+ bucketsFor: config.bucketsFor ?? fallback?.bucketsFor,
964
+ rewriteQuery: config.rewriteQuery ?? fallback?.rewriteQuery,
965
+ rerankContext: config.rerankContext ?? fallback?.rerankContext,
966
+ fallbackFn: config.fallbackFn ?? fallback?.fallbackFn,
967
+ transformReply: config.transformReply ?? fallback?.transformReply
968
+ };
969
+ }
851
970
  var DEFAULT_HISTORY_LIMIT = 20;
852
971
  var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
853
972
  var DEFAULT_DM_RATE_LIMIT = { max: 20, windowMs: 60 * 60 * 1e3 };
@@ -932,6 +1051,7 @@ function createInboundPipeline(deps, config) {
932
1051
  sender,
933
1052
  rewriteQuery: config.rewriteQuery,
934
1053
  rerankContext: config.rerankContext,
1054
+ fallbackFn: config.fallbackFn,
935
1055
  logger: config.logger
936
1056
  });
937
1057
  const { content: produced } = await answerOnce({
@@ -1067,13 +1187,9 @@ function createWhatsAppInboundHandler(config) {
1067
1187
  { client: config.client, store: config.store, prompts: config.prompts },
1068
1188
  {
1069
1189
  channel: "whatsapp",
1070
- answerFn: config.answerFn,
1071
- bucketsFor: config.bucketsFor,
1072
- rewriteQuery: config.rewriteQuery,
1073
- rerankContext: config.rerankContext,
1074
- transformReply: config.transformReply,
1190
+ ...resolveBrainHooks(config, config.serverConfig),
1075
1191
  model: config.model,
1076
- channelHint: config.channelHint,
1192
+ channelHint: config.channelHint ?? "Channel: WhatsApp.",
1077
1193
  personaResolver: personaResolver ? ({ sender, text }) => personaResolver({ senderPhone: sender, text }) : void 0,
1078
1194
  history: config.history,
1079
1195
  allowedChats,
@@ -1233,6 +1349,7 @@ export {
1233
1349
  LEASE_WAIT_MS,
1234
1350
  acquireSessionLease,
1235
1351
  canAcquireLease,
1352
+ createTursoWaAuthKV,
1236
1353
  createTursoWaLeaseStore,
1237
1354
  createWhatsAppChannel,
1238
1355
  createWhatsAppImageHandler,
@@ -1248,11 +1365,13 @@ export {
1248
1365
  jidsMatch,
1249
1366
  loadBaileys,
1250
1367
  messageContext,
1368
+ normalizeWaMediaPayload,
1251
1369
  reconnectDelayMs,
1252
1370
  resolveWaMessage,
1253
1371
  senderNameFor,
1254
1372
  senderPhoneFor,
1255
1373
  shutdownWaSessions,
1256
1374
  stripOwnMentions,
1375
+ useAuthState,
1257
1376
  useTursoAuthState
1258
1377
  };
@@ -1 +1 @@
1
- {"version":3,"file":"pairing.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/pairing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,8FAA8F;AAC9F,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAczC;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAM/F;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CAS/E;AAED,2DAA2D;AAC3D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE;QACF,EAAE,EAAE,CACF,KAAK,EAAE,mBAAmB,GAAG,cAAc,EAC3C,QAAQ,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,KAChD,IAAI,CAAC;KACX,CAAC;IACF,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9B,kBAAkB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7D,qEAAqE;IACrE,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAOD,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CAC7C;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,WAAW,GAAG,OAAO,GAAG,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjG,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,OAAO,EAAE,CACP,OAAO,EAAE,MAAM,KACZ,aAAa,GAAG,cAAc,GAAG,OAAO,CAAC,aAAa,GAAG,cAAc,CAAC,CAAC;IAC9E,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,uEAAuE;IACvE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,+BAA+B;IAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,2EAA2E;IAC3E,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CA0NvE"}
1
+ {"version":3,"file":"pairing.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/pairing.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/client/src/Chat.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEvD,qBAAa,IAAI;IACf,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAC,CAAa;IAE7B,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,UAAU,CAAqB;IAEvC,YAAY,MAAM,EAAE,UAAU,EA4B7B;IAED,OAAO,CAAC,MAAM;IAqBd,OAAO,CAAC,oBAAoB;YA+Cd,UAAU;IAkExB,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,KAAK,IAAI,IAAI,CAGZ;IAED;;OAEG;IACH,WAAW,IAAI,WAAW,EAAE,CAE3B;IAED;;OAEG;IACH,OAAO,IAAI,IAAI,CAEd;IAED;;OAEG;IACH,OAAO,CAAC,QAAQ;CAGjB"}
1
+ {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/client/src/Chat.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEvD,qBAAa,IAAI;IACf,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAC,CAAa;IAE7B,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,UAAU,CAAqB;IAEvC,YAAY,MAAM,EAAE,UAAU,EA0B7B;IAED,OAAO,CAAC,MAAM;IAoBd,OAAO,CAAC,oBAAoB;YA8Cd,UAAU;IA4DxB,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,KAAK,IAAI,IAAI,CAGZ;IAED;;OAEG;IACH,WAAW,IAAI,WAAW,EAAE,CAE3B;IAED;;OAEG;IACH,OAAO,IAAI,IAAI,CAEd;IAED;;OAEG;IACH,OAAO,CAAC,QAAQ;CAGjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"ChatButton.d.ts","sourceRoot":"","sources":["../../../src/client/src/ChatButton.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,MAAM,CAAS;IAEvB,YAAY,MAAM,EAAE,gBAAgB,EASnC;IAED,OAAO,CAAC,MAAM;IAsBd,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,MAAM;IAQd,IAAI,IAAI,IAAI,CAgDX;IAED,KAAK,IAAI,IAAI,CAcZ;IAED;;OAEG;IACH,OAAO,CAAC,QAAQ;IAIhB;;OAEG;IACH,OAAO,IAAI,IAAI,CAId;IAED;;OAEG;IACH,QAAQ,IAAI,OAAO,CAElB;CACF"}
1
+ {"version":3,"file":"ChatButton.d.ts","sourceRoot":"","sources":["../../../src/client/src/ChatButton.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,MAAM,CAAS;IAEvB,YAAY,MAAM,EAAE,gBAAgB,EASnC;IAED,OAAO,CAAC,MAAM;IAkBd,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,MAAM;IAQd,IAAI,IAAI,IAAI,CA+CX;IAED,KAAK,IAAI,IAAI,CAcZ;IAED;;OAEG;IACH,OAAO,CAAC,QAAQ;IAIhB;;OAEG;IACH,OAAO,IAAI,IAAI,CAId;IAED;;OAEG;IACH,QAAQ,IAAI,OAAO,CAElB;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/client/src/browser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,OAAO,EAAE;YACP,OAAO,EAAE,OAAO,OAAO,CAAC;YACxB,IAAI,EAAE,OAAO,IAAI,CAAC;YAClB,UAAU,EAAE,OAAO,UAAU,CAAC;SAC/B,CAAC;KACH;CACF;AAWD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/client/src/browser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,OAAO,EAAE;YACP,OAAO,EAAE,OAAO,OAAO,CAAC;YACxB,IAAI,EAAE,OAAO,IAAI,CAAC;YAClB,UAAU,EAAE,OAAO,UAAU,CAAC;SAC/B,CAAC;KACH;CACF;AAYD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -95,6 +95,14 @@ export type TransformReply = (input: TransformReplyInput) => string | null | Pro
95
95
  * Runs `transformReply` if configured. A throw/rejection is logged and the
96
96
  * ORIGINAL text is returned — the delivery invariant: a bug in a plugin hook
97
97
  * must never silently swallow an answer the model already produced.
98
+ *
99
+ * The result crosses the same plugin boundary `runAnswerFn` does, so it gets
100
+ * the same treatment: anything that isn't a string is coerced to `null`
101
+ * (treated as a veto) rather than passed through as whatever a
102
+ * non-conforming hook happened to return (`undefined` from a missing
103
+ * `return`, say). Every call site already treats a falsy result as "nothing
104
+ * delivered", but only a normalized `string | null` matches this function's
105
+ * own declared return type.
98
106
  */
99
107
  export declare function applyTransformReply(transformReply: TransformReply | undefined, input: TransformReplyInput, logger?: Pick<Logger, "error">): Promise<string | null>;
100
108
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/core/answer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAGjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEhE,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAKD,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,uCAAuC;IACvC,IAAI,EAAE,YAAY,CAAC;IACnB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,WAAW,CAAA;CAAE,CAAC;AAE/E;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,CAAC;AAE1F,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqBD;;GAEG;AACH,wBAAsB,UAAU,CAAC,EAC/B,QAAQ,EACR,MAAM,EACN,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,cAAc,EACd,WAAW,EACX,KAAK,GACN,EAAE,aAAa,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC,CAKlE;AAED,4FAA4F;AAC5F,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAEpG;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,cAAc,EAAE,cAAc,GAAG,SAAS,EAC1C,KAAK,EAAE,mBAAmB,EAC1B,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWxB;AAED;;;;;;;;GAQG;AACH,wBAAuB,YAAY,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,cAAc,EACd,WAAW,EACX,KAAK,GACN,EAAE,aAAa,GAAG,cAAc,CAAC,MAAM,CAAC,CAaxC"}
1
+ {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/core/answer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAGjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEhE,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAKD,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,uCAAuC;IACvC,IAAI,EAAE,YAAY,CAAC;IACnB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,WAAW,CAAA;CAAE,CAAC;AAE/E;;;GAGG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,CAAC;AAE1F,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqBD;;GAEG;AACH,wBAAsB,UAAU,CAAC,EAC/B,QAAQ,EACR,MAAM,EACN,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,cAAc,EACd,WAAW,EACX,KAAK,GACN,EAAE,aAAa,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC,CAKlE;AAED,4FAA4F;AAC5F,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAEpG;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,cAAc,EAAE,cAAc,GAAG,SAAS,EAC1C,KAAK,EAAE,mBAAmB,EAC1B,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYxB;AAED;;;;;;;;GAQG;AACH,wBAAuB,YAAY,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,cAAc,EACd,WAAW,EACX,KAAK,GACN,EAAE,aAAa,GAAG,cAAc,CAAC,MAAM,CAAC,CAaxC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Single-writer lock around the destructive half of a knowledge-base build.
3
+ *
4
+ * `VectorStore.build()` is a read-diff-delete-insert sequence: it reads the
5
+ * chunk ids already in the database, computes the ids its own `knowledgeDir`
6
+ * produces, and deletes everything not in that set. Two instances booting
7
+ * against the same database at the same time (a rolling deploy, a manual
8
+ * deploy racing an automated one) each run that sequence against a view of
9
+ * the data the other is still mutating, so one boot's cleanup can delete
10
+ * chunks the other has just written or has not finished writing.
11
+ *
12
+ * The lock lives in the same database (`chatter_build_lock`) so it is visible
13
+ * to every instance, and acquiring or renewing it is a single atomic upsert
14
+ * (see `createTursoBuildLock`) - two instances racing the same key can never
15
+ * both believe they hold it. A holder that dies without releasing leaves a
16
+ * stale row instead of wedging every future boot: after `staleMs` with no
17
+ * heartbeat, the next instance may take it over.
18
+ */
19
+ import type { Client } from "@libsql/client";
20
+ /** Lock key for the knowledge-base build. One build runs per database at a time. */
21
+ export declare const BUILD_LOCK_KEY = "knowledge_build";
22
+ /**
23
+ * A held lock this old with no heartbeat is treated as abandoned. Generous
24
+ * because a first build embeds every chunk it loads, which can take minutes;
25
+ * a holder renews the lock as it goes (see `VectorStore.build`), so only a
26
+ * process that actually died lets the lock go stale.
27
+ */
28
+ export declare const BUILD_LOCK_STALE_MS: number;
29
+ export interface BuildLockRow {
30
+ holderId: string;
31
+ heartbeatAt: number;
32
+ }
33
+ /**
34
+ * Pure: may `holderId` take (or keep) the build lock right now, given the
35
+ * current row (null = never held)? Mirrors the SQL WHERE clause in
36
+ * `createTursoBuildLock` - keep the two in sync.
37
+ */
38
+ export declare function canAcquireBuildLock(existing: BuildLockRow | null, holderId: string, now: number, staleMs?: number): boolean;
39
+ export interface BuildLock {
40
+ /** Atomically acquires or renews the lock; resolves true iff `holderId` now holds it. */
41
+ tryAcquire(key: string, holderId: string, now: number, staleMs: number): Promise<boolean>;
42
+ /** Releases the lock iff still held by `holderId` (no-op otherwise, so a late release never undoes a takeover). */
43
+ release(key: string, holderId: string): Promise<void>;
44
+ }
45
+ /**
46
+ * A libsql-backed {@link BuildLock}. The WHERE clause on DO UPDATE encodes
47
+ * `canAcquireBuildLock`: SQLite skips the update (and RETURNING yields no
48
+ * row) when it is false, so a losing racer sees zero rows back - no separate
49
+ * read-then-write, no race window.
50
+ */
51
+ export declare function createTursoBuildLock(client: Client): BuildLock;
52
+ //# sourceMappingURL=buildLock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildLock.d.ts","sourceRoot":"","sources":["../../src/core/buildLock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,oFAAoF;AACpF,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,QAAc,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,GAAG,IAAI,EAC7B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,MAA4B,GACpC,OAAO,CAIT;AAED,MAAM,WAAW,SAAS;IACxB,yFAAyF;IACzF,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1F,mHAAmH;IACnH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAwBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAyB9D"}
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import type { Logger } from "./logger";
12
12
  import type { PromptLoader } from "./prompts";
13
- import type { VectorStore } from "./retrieval";
13
+ import type { Retriever } from "./retrieval";
14
14
  export type PipelineMode = "public" | "private";
15
15
  export interface PipelineMessage {
16
16
  role: "user" | "assistant";
@@ -60,11 +60,43 @@ export interface RerankContextArgs {
60
60
  * fails closed by design; use this hook for relevance/ordering only.
61
61
  */
62
62
  export type RerankContext = (ctx: RerankContextArgs) => string[] | Promise<string[]>;
63
+ /** What `fallbackFn` sees for a turn where retrieval came back empty. */
64
+ export interface FallbackContext {
65
+ /** The query retrieval actually ran with, post-`rewriteQuery` if configured. */
66
+ query: string;
67
+ mode: PipelineMode;
68
+ /** Buckets retrieval ran against for this turn. */
69
+ buckets: string[];
70
+ /** Caller identity, where the surface has one. Absent on anonymous surfaces. */
71
+ sender?: string;
72
+ /**
73
+ * What `store.query` returned, before `rerankContext` ran: always
74
+ * non-empty when this is empty because `rerankContext` filtered
75
+ * everything out, and always empty when the store itself found nothing.
76
+ * A hook can use this to tell "some low-confidence signal existed" apart
77
+ * from "nothing matched at all".
78
+ */
79
+ retrievedChunks: string[];
80
+ }
81
+ /**
82
+ * Runs only when retrieval produced no chunks for a turn (after
83
+ * `rerankContext`, if configured), the deterministic, testable alternative
84
+ * to baking "what if there's nothing to retrieve" judgment calls into
85
+ * freeform system-prompt text. Return a string to inject as an extra system
86
+ * prompt layer scoped to this turn only (e.g. "no matching context was
87
+ * found; offer a clearly-labelled guess or decline"); return `undefined` to
88
+ * leave the prompt exactly as it would be otherwise.
89
+ *
90
+ * A throw/rejection is caught by `prepareChat`, which proceeds without
91
+ * fallback guidance: a broken hook must never break the chat path.
92
+ */
93
+ export type FallbackFn = (ctx: FallbackContext) => string | undefined | Promise<string | undefined>;
63
94
  /**
64
95
  * Run retrieval for the latest user message and assemble the system prompt.
65
96
  *
66
97
  * The assembled system prompt is layered, in order:
67
- * base rules → persona → channel hint (optional) → retrieved context.
98
+ * base rules → persona → channel hint (optional) → fallback guidance
99
+ * (optional, only when retrieval came back empty) → retrieved context.
68
100
  *
69
101
  * `personaLayer` and `channelHint` let a caller shape those middle layers
70
102
  * without hand-rolling its own sandwich around `store`/`prompts`. Both are
@@ -83,10 +115,13 @@ export type RerankContext = (ctx: RerankContextArgs) => string[] | Promise<strin
83
115
  * value falls back to what retrieval would have done unmodified, so a buggy
84
116
  * hook degrades relevance rather than breaking the chat path.
85
117
  *
118
+ * `fallbackFn` runs after both, only when the chunks folded into the prompt
119
+ * would otherwise be empty, see {@link FallbackFn}.
120
+ *
86
121
  * @throws if the conversation contains no user message
87
122
  */
88
- export declare function prepareChat({ store, prompts, mode, messages, personaLayer, channelHint, buckets, sender, rewriteQuery, rerankContext, logger, }: {
89
- store: VectorStore;
123
+ export declare function prepareChat({ store, prompts, mode, messages, personaLayer, channelHint, buckets, sender, rewriteQuery, rerankContext, fallbackFn, logger, }: {
124
+ store: Retriever;
90
125
  prompts: PromptLoader;
91
126
  mode: PipelineMode;
92
127
  messages: PipelineMessage[];
@@ -105,7 +140,9 @@ export declare function prepareChat({ store, prompts, mode, messages, personaLay
105
140
  rewriteQuery?: RewriteQuery;
106
141
  /** Post-processes retrieved chunks before they're folded into the prompt — see {@link RerankContext}. */
107
142
  rerankContext?: RerankContext;
108
- /** Logs a `rewriteQuery`/`rerankContext` throw before falling back. Unset: the failure is silent. */
143
+ /** Injects fallback guidance when retrieval comes back empty, see {@link FallbackFn}. */
144
+ fallbackFn?: FallbackFn;
145
+ /** Logs a `rewriteQuery`/`rerankContext`/`fallbackFn` throw before falling back. Unset: the failure is silent. */
109
146
  logger?: Pick<Logger, "error">;
110
147
  }): Promise<PreparedChat>;
111
148
  //# sourceMappingURL=pipeline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,iIAAiI;IACjI,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,2CAA2C;AAC3C,MAAM,WAAW,gBAAgB;IAC/B,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,gBAAgB,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE/E,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,iBAAiB,KAAK,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAOrF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,WAAW,CAAC,EAChC,KAAK,EACL,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,OAAO,EACP,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,GACP,EAAE;IACD,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,yGAAyG;IACzG,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,qGAAqG;IACrG,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,GAAG,OAAO,CAAC,YAAY,CAAC,CAuCxB"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"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"}