@diegoaltoworks/chatter 1.0.0 → 2.0.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 (72) hide show
  1. package/README.md +3 -1
  2. package/dist/channels/gates.d.ts +21 -2
  3. package/dist/channels/gates.d.ts.map +1 -1
  4. package/dist/channels/index.d.ts +5 -3
  5. package/dist/channels/index.d.ts.map +1 -1
  6. package/dist/channels/index.js +31 -13
  7. package/dist/channels/index.mjs +30 -13
  8. package/dist/channels/matrix/channel.d.ts +2 -0
  9. package/dist/channels/matrix/channel.d.ts.map +1 -1
  10. package/dist/channels/matrix/handler.d.ts +9 -0
  11. package/dist/channels/matrix/handler.d.ts.map +1 -1
  12. package/dist/channels/matrix/index.d.ts +1 -1
  13. package/dist/channels/matrix/index.d.ts.map +1 -1
  14. package/dist/channels/matrix/index.js +75 -20
  15. package/dist/channels/matrix/index.mjs +74 -20
  16. package/dist/channels/matrix/updates.d.ts +8 -2
  17. package/dist/channels/matrix/updates.d.ts.map +1 -1
  18. package/dist/channels/pipeline.d.ts +34 -4
  19. package/dist/channels/pipeline.d.ts.map +1 -1
  20. package/dist/channels/polling.d.ts +11 -0
  21. package/dist/channels/polling.d.ts.map +1 -1
  22. package/dist/channels/telegram/channel.d.ts +2 -0
  23. package/dist/channels/telegram/channel.d.ts.map +1 -1
  24. package/dist/channels/telegram/handler.d.ts +9 -0
  25. package/dist/channels/telegram/handler.d.ts.map +1 -1
  26. package/dist/channels/telegram/index.d.ts +1 -1
  27. package/dist/channels/telegram/index.d.ts.map +1 -1
  28. package/dist/channels/telegram/index.js +73 -24
  29. package/dist/channels/telegram/index.mjs +72 -24
  30. package/dist/channels/telegram/updates.d.ts +8 -2
  31. package/dist/channels/telegram/updates.d.ts.map +1 -1
  32. package/dist/channels/telegram/webhook.d.ts +10 -0
  33. package/dist/channels/telegram/webhook.d.ts.map +1 -1
  34. package/dist/channels/whatsapp/channel.d.ts +8 -0
  35. package/dist/channels/whatsapp/channel.d.ts.map +1 -1
  36. package/dist/channels/whatsapp/inbound.d.ts +2 -0
  37. package/dist/channels/whatsapp/inbound.d.ts.map +1 -1
  38. package/dist/channels/whatsapp/index.js +45 -18
  39. package/dist/channels/whatsapp/index.mjs +45 -18
  40. package/dist/core/answer.d.ts +9 -2
  41. package/dist/core/answer.d.ts.map +1 -1
  42. package/dist/core/guardrails.d.ts +11 -1
  43. package/dist/core/guardrails.d.ts.map +1 -1
  44. package/dist/core/llm.d.ts +3 -1
  45. package/dist/core/llm.d.ts.map +1 -1
  46. package/dist/history/index.js +12 -9
  47. package/dist/history/index.mjs +12 -9
  48. package/dist/index.d.ts +1 -1
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +50 -27
  51. package/dist/index.mjs +49 -27
  52. package/dist/mcp-server.d.ts.map +1 -1
  53. package/dist/mcp-server.js +16 -11
  54. package/dist/mcp-server.mjs +16 -11
  55. package/dist/personas/index.d.ts +1 -1
  56. package/dist/personas/index.d.ts.map +1 -1
  57. package/dist/personas/index.js +17 -5
  58. package/dist/personas/index.mjs +17 -5
  59. package/dist/personas/resolver.d.ts +35 -8
  60. package/dist/personas/resolver.d.ts.map +1 -1
  61. package/dist/routes/demo.d.ts.map +1 -1
  62. package/dist/routes/openai.d.ts.map +1 -1
  63. package/dist/routes/private.d.ts.map +1 -1
  64. package/dist/routes/public.d.ts.map +1 -1
  65. package/dist/scheduler/index.js +12 -9
  66. package/dist/scheduler/index.mjs +12 -9
  67. package/dist/server.d.ts.map +1 -1
  68. package/dist/server.js +44 -25
  69. package/dist/server.mjs +44 -25
  70. package/dist/types.d.ts +32 -1
  71. package/dist/types.d.ts.map +1 -1
  72. package/package.json +11 -11
@@ -37,6 +37,7 @@ __export(index_exports, {
37
37
  retryDelayMs: () => retryDelayMs,
38
38
  runLongPoll: () => runLongPoll,
39
39
  splitTelegramText: () => splitTelegramText,
40
+ telegramOwnIdentities: () => telegramOwnIdentities,
40
41
  telegramSenderKey: () => telegramSenderKey,
41
42
  toChannelMessage: () => toChannelMessage,
42
43
  toTelegramMediaRequest: () => toTelegramMediaRequest
@@ -236,9 +237,10 @@ function detectLeakage(text) {
236
237
  function scrubOutput(text) {
237
238
  return text.replace(/sk-[A-Za-z0-9]{15,}/g, "[REDACTED]").replace(/AIza[0-9A-Za-z_-]{30,}/g, "[REDACTED]");
238
239
  }
239
- function guardOutput(text) {
240
+ var DEFAULT_REFUSAL = "Sorry, I can't share internal instructions. How else can I help?";
241
+ function guardOutput(text, refusal) {
240
242
  if (detectLeakage(text)) {
241
- return "Sorry, I can't share internal instructions. How else can I help?";
243
+ return typeof refusal === "string" && refusal.trim() ? refusal : DEFAULT_REFUSAL;
242
244
  }
243
245
  return scrubOutput(text);
244
246
  }
@@ -250,7 +252,8 @@ async function completeOnce({
250
252
  system,
251
253
  messages,
252
254
  temperature = 0.2,
253
- model = DEFAULT_MODEL
255
+ model = DEFAULT_MODEL,
256
+ refusal
254
257
  }) {
255
258
  const res = await client.chat.completions.create({
256
259
  model,
@@ -259,19 +262,19 @@ async function completeOnce({
259
262
  });
260
263
  const text = res.choices[0]?.message?.content ?? "";
261
264
  return {
262
- content: guardOutput(text),
265
+ content: guardOutput(text, refusal),
263
266
  usage: res.usage || { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
264
267
  };
265
268
  }
266
269
 
267
270
  // src/core/answer.ts
268
271
  var noUsage = () => ({ prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 });
269
- async function runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }) {
272
+ async function runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }, refusal) {
270
273
  const result = await answerFn({ system, messages, mode, sender, conversationId });
271
274
  const raw = typeof result === "string" ? result : result?.content;
272
275
  const usage = typeof result === "string" ? void 0 : result?.usage;
273
276
  return {
274
- content: guardOutput(typeof raw === "string" ? raw : ""),
277
+ content: guardOutput(typeof raw === "string" ? raw : "", refusal),
275
278
  usage: usage ?? noUsage()
276
279
  };
277
280
  }
@@ -284,12 +287,13 @@ async function answerOnce({
284
287
  sender,
285
288
  conversationId,
286
289
  temperature,
287
- model
290
+ model,
291
+ refusal
288
292
  }) {
289
293
  if (answerFn) {
290
- return runAnswerFn(answerFn, { system, messages, mode, sender, conversationId });
294
+ return runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }, refusal);
291
295
  }
292
- return completeOnce({ client, system, messages, temperature, model });
296
+ return completeOnce({ client, system, messages, temperature, model, refusal });
293
297
  }
294
298
  async function applyTransformReply(transformReply, input, logger) {
295
299
  if (!transformReply) return input.text;
@@ -536,6 +540,16 @@ function createSlidingWindowRateLimiter(maxPerWindow, windowMs, now = Date.now)
536
540
  function underReplyRateLimit(msg, limiters) {
537
541
  return msg.isDirectMessage ? limiters.dm(msg.chatId) : limiters.group(msg.chatId);
538
542
  }
543
+ function isFromAnySession(id, registry) {
544
+ if (!id) return false;
545
+ for (const ids of registry.values()) {
546
+ if (ids.includes(id)) return true;
547
+ }
548
+ return false;
549
+ }
550
+ function isEffectivelyFromSelf(msg, registry) {
551
+ return msg.fromBot || isFromAnySession(msg.senderId, registry);
552
+ }
539
553
 
540
554
  // src/channels/pipeline.ts
541
555
  function resolveBrainHooks(config, fallback) {
@@ -545,9 +559,17 @@ function resolveBrainHooks(config, fallback) {
545
559
  rewriteQuery: config.rewriteQuery ?? fallback?.rewriteQuery,
546
560
  rerankContext: config.rerankContext ?? fallback?.rerankContext,
547
561
  fallbackFn: config.fallbackFn ?? fallback?.fallbackFn,
548
- transformReply: config.transformReply ?? fallback?.transformReply
562
+ transformReply: config.transformReply ?? fallback?.transformReply,
563
+ refusal: config.refusal ?? fallback?.refusal
549
564
  };
550
565
  }
566
+ function escapeKeyPart(part) {
567
+ return part.replaceAll("%", "%25").replaceAll("#", "%23");
568
+ }
569
+ function conversationKeyFor(chatId, endpointId) {
570
+ if (!endpointId) return chatId;
571
+ return `${escapeKeyPart(chatId)}#${escapeKeyPart(endpointId)}`;
572
+ }
551
573
  var DEFAULT_HISTORY_LIMIT = 20;
552
574
  var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
553
575
  var DEFAULT_DM_RATE_LIMIT = { max: 20, windowMs: 60 * 60 * 1e3 };
@@ -606,11 +628,15 @@ function createInboundPipeline(deps, config) {
606
628
  return { action: "rate-limited" };
607
629
  }
608
630
  const sender = typeof turn.sender === "function" ? await turn.sender() : turn.sender ?? msg.senderId;
609
- const conversationId = turn.conversationId ?? msg.chatId;
631
+ const conversationId = turn.conversationId ?? conversationKeyFor(msg.chatId, msg.endpointId);
610
632
  if (turn.intercept && await turn.intercept(sender)) {
611
633
  return { action: "intercepted" };
612
634
  }
613
- const personaLayer = await resolvePersonaLayer(config, { sender, text: msg.text });
635
+ const personaLayer = await resolvePersonaLayer(config, {
636
+ sender,
637
+ text: msg.text,
638
+ endpointId: msg.endpointId
639
+ });
614
640
  const buckets = await resolveBuckets({ mode, sender, bucketsFor: config.bucketsFor });
615
641
  const historyEnabled = config.history ? await isHistoryEnabled(config, sender) : false;
616
642
  const priorTurns = config.history && historyEnabled ? await config.history.store.load(
@@ -643,7 +669,8 @@ function createInboundPipeline(deps, config) {
643
669
  mode,
644
670
  sender,
645
671
  conversationId,
646
- model: config.model
672
+ model: config.model,
673
+ refusal: config.refusal
647
674
  });
648
675
  const content = await applyTransformReply(
649
676
  config.transformReply,
@@ -678,6 +705,7 @@ function defaultSleep(ms) {
678
705
  }
679
706
 
680
707
  // src/channels/telegram/updates.ts
708
+ var NO_IDENTITIES = /* @__PURE__ */ new Map();
681
709
  function messageText(message) {
682
710
  return message.text ?? message.caption ?? "";
683
711
  }
@@ -696,23 +724,30 @@ function mentionsBot(message, me) {
696
724
  return false;
697
725
  });
698
726
  }
699
- function toChannelMessage(update, me) {
727
+ function toChannelMessage(update, me, identities = NO_IDENTITIES, channelName) {
700
728
  const message = update.message;
701
729
  if (!message?.from) return void 0;
730
+ const senderId = String(message.from.id);
702
731
  return {
703
732
  chatId: String(message.chat.id),
704
- senderId: String(message.from.id),
733
+ senderId,
705
734
  text: messageText(message),
706
735
  isDirectMessage: message.chat.type === "private",
707
736
  mentionsBot: mentionsBot(message, me),
708
737
  isReplyToBot: message.reply_to_message?.from?.id === me.id,
709
- // A single bot token is a single identity, so unlike WhatsApp's
710
- // multi-session loop guard this is a plain equality check.
711
- fromBot: message.from.id === me.id,
738
+ // One bot token is one identity, but one process is not: a second token
739
+ // mounted alongside this one is a stranger to `me` and would be answered,
740
+ // and would answer back, forever. `identities` is what makes the other
741
+ // endpoint's id "us" too - an empty one degenerates to the equality check.
742
+ fromBot: isEffectivelyFromSelf({ fromBot: message.from.id === me.id, senderId }, identities),
712
743
  // What `setMessageReaction` targets — see `ChannelSenderRegistry.sendReaction`.
713
- messageRef: message.message_id
744
+ messageRef: message.message_id,
745
+ endpointId: channelName
714
746
  };
715
747
  }
748
+ function telegramOwnIdentities(me) {
749
+ return [String(me.id)];
750
+ }
716
751
  function nextOffset(update) {
717
752
  return update.update_id + 1;
718
753
  }
@@ -722,11 +757,11 @@ function telegramSenderKey(senderId) {
722
757
 
723
758
  // src/channels/telegram/handler.ts
724
759
  function createTelegramUpdateHandler(deps) {
725
- const { api, me, pipeline, allowedChats, logger, label } = deps;
760
+ const { api, me, pipeline, identities, allowedChats, logger, label, channelName } = deps;
726
761
  const loggedUnallowedChats = /* @__PURE__ */ new Set();
727
762
  return async function handleUpdate(update) {
728
763
  const message = update.message;
729
- const msg = toChannelMessage(update, me);
764
+ const msg = toChannelMessage(update, me, identities, channelName);
730
765
  if (!msg || !message) return;
731
766
  if (isBlockedByAllowlist(msg, { allowedChats })) {
732
767
  if (!loggedUnallowedChats.has(msg.chatId)) {
@@ -742,7 +777,6 @@ function createTelegramUpdateHandler(deps) {
742
777
  };
743
778
  await pipeline(msg, {
744
779
  reply,
745
- conversationId: msg.chatId,
746
780
  sender: telegramSenderKey(msg.senderId)
747
781
  });
748
782
  };
@@ -824,6 +858,8 @@ function createTelegramChannel(config) {
824
858
  });
825
859
  const me = await api.getMe();
826
860
  const label = `Telegram[${me.username ?? me.id}]`;
861
+ const identities = config.identities ?? deps.identities;
862
+ identities.set(channelName, telegramOwnIdentities(me));
827
863
  deps.senders.register(channelName, createTelegramSender(api));
828
864
  senders = deps.senders;
829
865
  registered = true;
@@ -850,10 +886,15 @@ function createTelegramChannel(config) {
850
886
  const handleUpdate = createTelegramUpdateHandler({
851
887
  api,
852
888
  me,
889
+ identities,
853
890
  pipeline,
854
891
  allowedChats,
855
892
  logger: log,
856
- label
893
+ label,
894
+ // config.name, not the resolved channelName: endpointId opts in only
895
+ // when the host explicitly named this channel (running more than
896
+ // one bot in the process), not for a default single-token channel.
897
+ channelName: config.name
857
898
  });
858
899
  abort = new AbortController();
859
900
  const signal = abort.signal;
@@ -1005,6 +1046,8 @@ function createTelegramWebhookRoute(config) {
1005
1046
  });
1006
1047
  const me = await api.getMe();
1007
1048
  const label = `Telegram[${me.username ?? me.id}] (webhook)`;
1049
+ const identities = config.identities ?? deps.identities;
1050
+ identities.set(channelName, telegramOwnIdentities(me));
1008
1051
  deps.senders.register(channelName, createTelegramSender(api));
1009
1052
  const pipeline = createInboundPipeline(
1010
1053
  { client: deps.client, store: deps.store, prompts: deps.prompts },
@@ -1029,10 +1072,15 @@ function createTelegramWebhookRoute(config) {
1029
1072
  const handleUpdate = createTelegramUpdateHandler({
1030
1073
  api,
1031
1074
  me,
1075
+ identities,
1032
1076
  pipeline,
1033
1077
  allowedChats,
1034
1078
  logger: log,
1035
- label
1079
+ label,
1080
+ // config.name, not the resolved channelName: endpointId opts in only
1081
+ // when the host explicitly named this channel (running more than one
1082
+ // bot in the process), not for a default single-token channel.
1083
+ channelName: config.name
1036
1084
  });
1037
1085
  app.post(
1038
1086
  path,
@@ -1084,6 +1132,7 @@ function createTelegramWebhookRoute(config) {
1084
1132
  retryDelayMs,
1085
1133
  runLongPoll,
1086
1134
  splitTelegramText,
1135
+ telegramOwnIdentities,
1087
1136
  telegramSenderKey,
1088
1137
  toChannelMessage,
1089
1138
  toTelegramMediaRequest
@@ -191,9 +191,10 @@ function detectLeakage(text) {
191
191
  function scrubOutput(text) {
192
192
  return text.replace(/sk-[A-Za-z0-9]{15,}/g, "[REDACTED]").replace(/AIza[0-9A-Za-z_-]{30,}/g, "[REDACTED]");
193
193
  }
194
- function guardOutput(text) {
194
+ var DEFAULT_REFUSAL = "Sorry, I can't share internal instructions. How else can I help?";
195
+ function guardOutput(text, refusal) {
195
196
  if (detectLeakage(text)) {
196
- return "Sorry, I can't share internal instructions. How else can I help?";
197
+ return typeof refusal === "string" && refusal.trim() ? refusal : DEFAULT_REFUSAL;
197
198
  }
198
199
  return scrubOutput(text);
199
200
  }
@@ -205,7 +206,8 @@ async function completeOnce({
205
206
  system,
206
207
  messages,
207
208
  temperature = 0.2,
208
- model = DEFAULT_MODEL
209
+ model = DEFAULT_MODEL,
210
+ refusal
209
211
  }) {
210
212
  const res = await client.chat.completions.create({
211
213
  model,
@@ -214,19 +216,19 @@ async function completeOnce({
214
216
  });
215
217
  const text = res.choices[0]?.message?.content ?? "";
216
218
  return {
217
- content: guardOutput(text),
219
+ content: guardOutput(text, refusal),
218
220
  usage: res.usage || { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
219
221
  };
220
222
  }
221
223
 
222
224
  // src/core/answer.ts
223
225
  var noUsage = () => ({ prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 });
224
- async function runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }) {
226
+ async function runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }, refusal) {
225
227
  const result = await answerFn({ system, messages, mode, sender, conversationId });
226
228
  const raw = typeof result === "string" ? result : result?.content;
227
229
  const usage = typeof result === "string" ? void 0 : result?.usage;
228
230
  return {
229
- content: guardOutput(typeof raw === "string" ? raw : ""),
231
+ content: guardOutput(typeof raw === "string" ? raw : "", refusal),
230
232
  usage: usage ?? noUsage()
231
233
  };
232
234
  }
@@ -239,12 +241,13 @@ async function answerOnce({
239
241
  sender,
240
242
  conversationId,
241
243
  temperature,
242
- model
244
+ model,
245
+ refusal
243
246
  }) {
244
247
  if (answerFn) {
245
- return runAnswerFn(answerFn, { system, messages, mode, sender, conversationId });
248
+ return runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }, refusal);
246
249
  }
247
- return completeOnce({ client, system, messages, temperature, model });
250
+ return completeOnce({ client, system, messages, temperature, model, refusal });
248
251
  }
249
252
  async function applyTransformReply(transformReply, input, logger) {
250
253
  if (!transformReply) return input.text;
@@ -491,6 +494,16 @@ function createSlidingWindowRateLimiter(maxPerWindow, windowMs, now = Date.now)
491
494
  function underReplyRateLimit(msg, limiters) {
492
495
  return msg.isDirectMessage ? limiters.dm(msg.chatId) : limiters.group(msg.chatId);
493
496
  }
497
+ function isFromAnySession(id, registry) {
498
+ if (!id) return false;
499
+ for (const ids of registry.values()) {
500
+ if (ids.includes(id)) return true;
501
+ }
502
+ return false;
503
+ }
504
+ function isEffectivelyFromSelf(msg, registry) {
505
+ return msg.fromBot || isFromAnySession(msg.senderId, registry);
506
+ }
494
507
 
495
508
  // src/channels/pipeline.ts
496
509
  function resolveBrainHooks(config, fallback) {
@@ -500,9 +513,17 @@ function resolveBrainHooks(config, fallback) {
500
513
  rewriteQuery: config.rewriteQuery ?? fallback?.rewriteQuery,
501
514
  rerankContext: config.rerankContext ?? fallback?.rerankContext,
502
515
  fallbackFn: config.fallbackFn ?? fallback?.fallbackFn,
503
- transformReply: config.transformReply ?? fallback?.transformReply
516
+ transformReply: config.transformReply ?? fallback?.transformReply,
517
+ refusal: config.refusal ?? fallback?.refusal
504
518
  };
505
519
  }
520
+ function escapeKeyPart(part) {
521
+ return part.replaceAll("%", "%25").replaceAll("#", "%23");
522
+ }
523
+ function conversationKeyFor(chatId, endpointId) {
524
+ if (!endpointId) return chatId;
525
+ return `${escapeKeyPart(chatId)}#${escapeKeyPart(endpointId)}`;
526
+ }
506
527
  var DEFAULT_HISTORY_LIMIT = 20;
507
528
  var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
508
529
  var DEFAULT_DM_RATE_LIMIT = { max: 20, windowMs: 60 * 60 * 1e3 };
@@ -561,11 +582,15 @@ function createInboundPipeline(deps, config) {
561
582
  return { action: "rate-limited" };
562
583
  }
563
584
  const sender = typeof turn.sender === "function" ? await turn.sender() : turn.sender ?? msg.senderId;
564
- const conversationId = turn.conversationId ?? msg.chatId;
585
+ const conversationId = turn.conversationId ?? conversationKeyFor(msg.chatId, msg.endpointId);
565
586
  if (turn.intercept && await turn.intercept(sender)) {
566
587
  return { action: "intercepted" };
567
588
  }
568
- const personaLayer = await resolvePersonaLayer(config, { sender, text: msg.text });
589
+ const personaLayer = await resolvePersonaLayer(config, {
590
+ sender,
591
+ text: msg.text,
592
+ endpointId: msg.endpointId
593
+ });
569
594
  const buckets = await resolveBuckets({ mode, sender, bucketsFor: config.bucketsFor });
570
595
  const historyEnabled = config.history ? await isHistoryEnabled(config, sender) : false;
571
596
  const priorTurns = config.history && historyEnabled ? await config.history.store.load(
@@ -598,7 +623,8 @@ function createInboundPipeline(deps, config) {
598
623
  mode,
599
624
  sender,
600
625
  conversationId,
601
- model: config.model
626
+ model: config.model,
627
+ refusal: config.refusal
602
628
  });
603
629
  const content = await applyTransformReply(
604
630
  config.transformReply,
@@ -633,6 +659,7 @@ function defaultSleep(ms) {
633
659
  }
634
660
 
635
661
  // src/channels/telegram/updates.ts
662
+ var NO_IDENTITIES = /* @__PURE__ */ new Map();
636
663
  function messageText(message) {
637
664
  return message.text ?? message.caption ?? "";
638
665
  }
@@ -651,23 +678,30 @@ function mentionsBot(message, me) {
651
678
  return false;
652
679
  });
653
680
  }
654
- function toChannelMessage(update, me) {
681
+ function toChannelMessage(update, me, identities = NO_IDENTITIES, channelName) {
655
682
  const message = update.message;
656
683
  if (!message?.from) return void 0;
684
+ const senderId = String(message.from.id);
657
685
  return {
658
686
  chatId: String(message.chat.id),
659
- senderId: String(message.from.id),
687
+ senderId,
660
688
  text: messageText(message),
661
689
  isDirectMessage: message.chat.type === "private",
662
690
  mentionsBot: mentionsBot(message, me),
663
691
  isReplyToBot: message.reply_to_message?.from?.id === me.id,
664
- // A single bot token is a single identity, so unlike WhatsApp's
665
- // multi-session loop guard this is a plain equality check.
666
- fromBot: message.from.id === me.id,
692
+ // One bot token is one identity, but one process is not: a second token
693
+ // mounted alongside this one is a stranger to `me` and would be answered,
694
+ // and would answer back, forever. `identities` is what makes the other
695
+ // endpoint's id "us" too - an empty one degenerates to the equality check.
696
+ fromBot: isEffectivelyFromSelf({ fromBot: message.from.id === me.id, senderId }, identities),
667
697
  // What `setMessageReaction` targets — see `ChannelSenderRegistry.sendReaction`.
668
- messageRef: message.message_id
698
+ messageRef: message.message_id,
699
+ endpointId: channelName
669
700
  };
670
701
  }
702
+ function telegramOwnIdentities(me) {
703
+ return [String(me.id)];
704
+ }
671
705
  function nextOffset(update) {
672
706
  return update.update_id + 1;
673
707
  }
@@ -677,11 +711,11 @@ function telegramSenderKey(senderId) {
677
711
 
678
712
  // src/channels/telegram/handler.ts
679
713
  function createTelegramUpdateHandler(deps) {
680
- const { api, me, pipeline, allowedChats, logger, label } = deps;
714
+ const { api, me, pipeline, identities, allowedChats, logger, label, channelName } = deps;
681
715
  const loggedUnallowedChats = /* @__PURE__ */ new Set();
682
716
  return async function handleUpdate(update) {
683
717
  const message = update.message;
684
- const msg = toChannelMessage(update, me);
718
+ const msg = toChannelMessage(update, me, identities, channelName);
685
719
  if (!msg || !message) return;
686
720
  if (isBlockedByAllowlist(msg, { allowedChats })) {
687
721
  if (!loggedUnallowedChats.has(msg.chatId)) {
@@ -697,7 +731,6 @@ function createTelegramUpdateHandler(deps) {
697
731
  };
698
732
  await pipeline(msg, {
699
733
  reply,
700
- conversationId: msg.chatId,
701
734
  sender: telegramSenderKey(msg.senderId)
702
735
  });
703
736
  };
@@ -779,6 +812,8 @@ function createTelegramChannel(config) {
779
812
  });
780
813
  const me = await api.getMe();
781
814
  const label = `Telegram[${me.username ?? me.id}]`;
815
+ const identities = config.identities ?? deps.identities;
816
+ identities.set(channelName, telegramOwnIdentities(me));
782
817
  deps.senders.register(channelName, createTelegramSender(api));
783
818
  senders = deps.senders;
784
819
  registered = true;
@@ -805,10 +840,15 @@ function createTelegramChannel(config) {
805
840
  const handleUpdate = createTelegramUpdateHandler({
806
841
  api,
807
842
  me,
843
+ identities,
808
844
  pipeline,
809
845
  allowedChats,
810
846
  logger: log,
811
- label
847
+ label,
848
+ // config.name, not the resolved channelName: endpointId opts in only
849
+ // when the host explicitly named this channel (running more than
850
+ // one bot in the process), not for a default single-token channel.
851
+ channelName: config.name
812
852
  });
813
853
  abort = new AbortController();
814
854
  const signal = abort.signal;
@@ -960,6 +1000,8 @@ function createTelegramWebhookRoute(config) {
960
1000
  });
961
1001
  const me = await api.getMe();
962
1002
  const label = `Telegram[${me.username ?? me.id}] (webhook)`;
1003
+ const identities = config.identities ?? deps.identities;
1004
+ identities.set(channelName, telegramOwnIdentities(me));
963
1005
  deps.senders.register(channelName, createTelegramSender(api));
964
1006
  const pipeline = createInboundPipeline(
965
1007
  { client: deps.client, store: deps.store, prompts: deps.prompts },
@@ -984,10 +1026,15 @@ function createTelegramWebhookRoute(config) {
984
1026
  const handleUpdate = createTelegramUpdateHandler({
985
1027
  api,
986
1028
  me,
1029
+ identities,
987
1030
  pipeline,
988
1031
  allowedChats,
989
1032
  logger: log,
990
- label
1033
+ label,
1034
+ // config.name, not the resolved channelName: endpointId opts in only
1035
+ // when the host explicitly named this channel (running more than one
1036
+ // bot in the process), not for a default single-token channel.
1037
+ channelName: config.name
991
1038
  });
992
1039
  app.post(
993
1040
  path,
@@ -1038,6 +1085,7 @@ export {
1038
1085
  retryDelayMs,
1039
1086
  runLongPoll,
1040
1087
  splitTelegramText,
1088
+ telegramOwnIdentities,
1041
1089
  telegramSenderKey,
1042
1090
  toChannelMessage,
1043
1091
  toTelegramMediaRequest
@@ -9,7 +9,7 @@
9
9
  * `reply_to_message.from`. The gate policy that consumes those booleans
10
10
  * (`decideChannelAction`) is identical for both.
11
11
  */
12
- import type { ChannelMessage } from "../gates";
12
+ import { type ChannelMessage, type SessionIdentityRegistry } from "../gates";
13
13
  import type { TelegramMessage, TelegramMessageEntity, TelegramUpdate } from "./api";
14
14
  /** The bot's own identity, as `getMe` reports it. */
15
15
  export interface TelegramBotIdentity {
@@ -45,7 +45,13 @@ export declare function mentionsBot(message: TelegramMessage, me: TelegramBotIde
45
45
  * mapping it keeps this function's rule simple: interpret the wire, let the
46
46
  * gates decide policy.
47
47
  */
48
- export declare function toChannelMessage(update: TelegramUpdate, me: TelegramBotIdentity): ChannelMessage | undefined;
48
+ export declare function toChannelMessage(update: TelegramUpdate, me: TelegramBotIdentity, identities?: SessionIdentityRegistry, channelName?: string): ChannelMessage | undefined;
49
+ /**
50
+ * What this bot answers to on the wire, for a {@link SessionIdentityRegistry}.
51
+ * The numeric id only: `senderId` on an inbound message is `from.id`, never
52
+ * the `@username`, so registering the handle would match nothing.
53
+ */
54
+ export declare function telegramOwnIdentities(me: TelegramBotIdentity): string[];
49
55
  /**
50
56
  * The `offset` to request next so `update` is never redelivered:
51
57
  * `update_id + 1`, which is also how the Bot API acknowledges it (there is no
@@ -1 +1 @@
1
- {"version":3,"file":"updates.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/updates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAEpF,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAE5D;AAED,yGAAyG;AACzG,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,qBAAqB,EAAE,CAEjF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,mBAAmB,GAAG,OAAO,CAYtF;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,cAAc,EACtB,EAAE,EAAE,mBAAmB,GACtB,cAAc,GAAG,SAAS,CAiB5B;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEzD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D"}
1
+ {"version":3,"file":"updates.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/updates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,cAAc,EAAyB,KAAK,uBAAuB,EAAE,MAAM,UAAU,CAAC;AACpG,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAKpF,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAE5D;AAED,yGAAyG;AACzG,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,qBAAqB,EAAE,CAEjF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,mBAAmB,GAAG,OAAO,CAYtF;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,cAAc,EACtB,EAAE,EAAE,mBAAmB,EACvB,UAAU,GAAE,uBAAuC,EAKnD,WAAW,CAAC,EAAE,MAAM,GACnB,cAAc,GAAG,SAAS,CAsB5B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEzD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D"}
@@ -23,6 +23,7 @@ import { type Logger } from "../../core/logger";
23
23
  import type { HistoryCompactionOptions } from "../../history/compaction";
24
24
  import type { HistoryStore } from "../../history/types";
25
25
  import type { BrainHooks, CustomRoutes } from "../../types";
26
+ import type { SessionIdentityRegistry } from "../gates";
26
27
  import { type TelegramApi } from "./api";
27
28
  export interface TelegramWebhookConfig extends BrainHooks {
28
29
  /** From @BotFather. A credential — pass it from the environment, never commit it. */
@@ -41,6 +42,13 @@ export interface TelegramWebhookConfig extends BrainHooks {
41
42
  name?: string;
42
43
  /** Group chats eligible for a reply. Empty (default) = every group. Has no effect on DMs, which always reply. */
43
44
  allowedChats?: string[];
45
+ /**
46
+ * Every identity this process answers to, keyed by endpoint - what `fromBot`
47
+ * is resolved against, so one of your own bots is never answered as a
48
+ * stranger. @default `deps.identities`, the one registry `createServer`
49
+ * owns and shares with every channel.
50
+ */
51
+ identities?: SessionIdentityRegistry;
44
52
  model?: string;
45
53
  /** Extra system-prompt section describing the delivery channel; passed through to `prepareChat`. @default "Channel: Telegram." */
46
54
  channelHint?: string;
@@ -48,6 +56,8 @@ export interface TelegramWebhookConfig extends BrainHooks {
48
56
  personaResolver?: (ctx: {
49
57
  sender: string;
50
58
  text: string;
59
+ /** Which of this process's endpoints received the message - see `ChannelMessage.endpointId`. Unset unless the channel runs more than one. */
60
+ endpointId?: string;
51
61
  }) => string | undefined | Promise<string | undefined>;
52
62
  /** Off by default — the channel stays single-turn until a store is configured. */
53
63
  history?: {
@@ -1 +1 @@
1
- {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/webhook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EAAqB,KAAK,WAAW,EAAuB,MAAM,OAAO,CAAC;AAMjF,MAAM,WAAW,qBAAsB,SAAQ,UAAU;IACvD,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8GAA8G;IAC9G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iHAAiH;IACjH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kIAAkI;IAClI,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4GAA4G;IAC5G,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACvD,kFAAkF;IAClF,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,YAAY,CAAC;QACpB,uDAAuD;QACvD,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QACnE;;;;WAIG;QACH,UAAU,CAAC,EAAE,wBAAwB,CAAC;KACvC,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,cAAc,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,mGAAmG;IACnG,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qJAAqJ;IACrJ,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,qBAAqB,GAAG,YAAY,CA8GtF"}
1
+ {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/webhook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD,OAAO,EAAqB,KAAK,WAAW,EAAuB,MAAM,OAAO,CAAC;AAOjF,MAAM,WAAW,qBAAsB,SAAQ,UAAU;IACvD,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8GAA8G;IAC9G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iHAAiH;IACjH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,uBAAuB,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kIAAkI;IAClI,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4GAA4G;IAC5G,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE;QACtB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,6IAA6I;QAC7I,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACvD,kFAAkF;IAClF,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,YAAY,CAAC;QACpB,uDAAuD;QACvD,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QACnE;;;;WAIG;QACH,UAAU,CAAC,EAAE,wBAAwB,CAAC;KACvC,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,cAAc,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,mGAAmG;IACnG,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qJAAqJ;IACrJ,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,qBAAqB,GAAG,YAAY,CAwHtF"}
@@ -29,6 +29,14 @@ export interface WhatsAppMessageEvent {
29
29
  sessionId: string;
30
30
  sock: WASocket;
31
31
  message: WAMessage;
32
+ /**
33
+ * `sessionId`, but only when this channel is actually running more than
34
+ * one endpoint (a custom `name`, or more than one configured `sessionId`)
35
+ * - unset for a default single-session channel, so a host that hasn't
36
+ * opted into multiple endpoints stays byte-identical to before endpointId
37
+ * existed. See {@link ChannelMessage.endpointId}.
38
+ */
39
+ endpointId?: string;
32
40
  }
33
41
  /**
34
42
  * A session's connection state, derived from the same `connection.update`
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/channel.ts"],"names":[],"mappings":"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"}
@@ -173,6 +173,8 @@ export interface WhatsAppInboundConfig extends BrainHooks {
173
173
  personaResolver?: (ctx: {
174
174
  senderPhone: string;
175
175
  text: string;
176
+ /** Which of this process's sessions received the message - see `ChannelMessage.endpointId`. Unset unless the channel runs more than one. */
177
+ endpointId?: string;
176
178
  }) => string | undefined | Promise<string | undefined>;
177
179
  /**
178
180
  * Optional image-request routing (see `./images`). Consulted right before
@@ -1 +1 @@
1
- {"version":3,"file":"inbound.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/inbound.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"inbound.d.ts","sourceRoot":"","sources":["../../../src/channels/whatsapp/inbound.ts"],"names":[],"mappings":"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"}