@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
@@ -295,9 +295,10 @@ function detectLeakage(text) {
295
295
  function scrubOutput(text) {
296
296
  return text.replace(/sk-[A-Za-z0-9]{15,}/g, "[REDACTED]").replace(/AIza[0-9A-Za-z_-]{30,}/g, "[REDACTED]");
297
297
  }
298
- function guardOutput(text) {
298
+ var DEFAULT_REFUSAL = "Sorry, I can't share internal instructions. How else can I help?";
299
+ function guardOutput(text, refusal) {
299
300
  if (detectLeakage(text)) {
300
- return "Sorry, I can't share internal instructions. How else can I help?";
301
+ return typeof refusal === "string" && refusal.trim() ? refusal : DEFAULT_REFUSAL;
301
302
  }
302
303
  return scrubOutput(text);
303
304
  }
@@ -309,7 +310,8 @@ async function completeOnce({
309
310
  system,
310
311
  messages,
311
312
  temperature = 0.2,
312
- model = DEFAULT_MODEL
313
+ model = DEFAULT_MODEL,
314
+ refusal
313
315
  }) {
314
316
  const res = await client.chat.completions.create({
315
317
  model,
@@ -318,19 +320,19 @@ async function completeOnce({
318
320
  });
319
321
  const text = res.choices[0]?.message?.content ?? "";
320
322
  return {
321
- content: guardOutput(text),
323
+ content: guardOutput(text, refusal),
322
324
  usage: res.usage || { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
323
325
  };
324
326
  }
325
327
 
326
328
  // src/core/answer.ts
327
329
  var noUsage = () => ({ prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 });
328
- async function runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }) {
330
+ async function runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }, refusal) {
329
331
  const result = await answerFn({ system, messages, mode, sender, conversationId });
330
332
  const raw = typeof result === "string" ? result : result?.content;
331
333
  const usage = typeof result === "string" ? void 0 : result?.usage;
332
334
  return {
333
- content: guardOutput(typeof raw === "string" ? raw : ""),
335
+ content: guardOutput(typeof raw === "string" ? raw : "", refusal),
334
336
  usage: usage ?? noUsage()
335
337
  };
336
338
  }
@@ -343,12 +345,13 @@ async function answerOnce({
343
345
  sender,
344
346
  conversationId,
345
347
  temperature,
346
- model
348
+ model,
349
+ refusal
347
350
  }) {
348
351
  if (answerFn) {
349
- return runAnswerFn(answerFn, { system, messages, mode, sender, conversationId });
352
+ return runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }, refusal);
350
353
  }
351
- return completeOnce({ client, system, messages, temperature, model });
354
+ return completeOnce({ client, system, messages, temperature, model, refusal });
352
355
  }
353
356
  async function applyTransformReply(transformReply, input, logger) {
354
357
  if (!transformReply) return input.text;
@@ -595,6 +598,16 @@ function createSlidingWindowRateLimiter(maxPerWindow, windowMs, now = Date.now)
595
598
  function underReplyRateLimit(msg, limiters) {
596
599
  return msg.isDirectMessage ? limiters.dm(msg.chatId) : limiters.group(msg.chatId);
597
600
  }
601
+ function isFromAnySession(id, registry) {
602
+ if (!id) return false;
603
+ for (const ids of registry.values()) {
604
+ if (ids.includes(id)) return true;
605
+ }
606
+ return false;
607
+ }
608
+ function isEffectivelyFromSelf(msg, registry) {
609
+ return msg.fromBot || isFromAnySession(msg.senderId, registry);
610
+ }
598
611
 
599
612
  // src/channels/pipeline.ts
600
613
  function resolveBrainHooks(config, fallback) {
@@ -604,9 +617,17 @@ function resolveBrainHooks(config, fallback) {
604
617
  rewriteQuery: config.rewriteQuery ?? fallback?.rewriteQuery,
605
618
  rerankContext: config.rerankContext ?? fallback?.rerankContext,
606
619
  fallbackFn: config.fallbackFn ?? fallback?.fallbackFn,
607
- transformReply: config.transformReply ?? fallback?.transformReply
620
+ transformReply: config.transformReply ?? fallback?.transformReply,
621
+ refusal: config.refusal ?? fallback?.refusal
608
622
  };
609
623
  }
624
+ function escapeKeyPart(part) {
625
+ return part.replaceAll("%", "%25").replaceAll("#", "%23");
626
+ }
627
+ function conversationKeyFor(chatId, endpointId) {
628
+ if (!endpointId) return chatId;
629
+ return `${escapeKeyPart(chatId)}#${escapeKeyPart(endpointId)}`;
630
+ }
610
631
  var DEFAULT_HISTORY_LIMIT = 20;
611
632
  var DEFAULT_GROUP_RATE_LIMIT = { max: 30, windowMs: 60 * 60 * 1e3 };
612
633
  var DEFAULT_DM_RATE_LIMIT = { max: 20, windowMs: 60 * 60 * 1e3 };
@@ -665,11 +686,15 @@ function createInboundPipeline(deps, config) {
665
686
  return { action: "rate-limited" };
666
687
  }
667
688
  const sender = typeof turn.sender === "function" ? await turn.sender() : turn.sender ?? msg.senderId;
668
- const conversationId = turn.conversationId ?? msg.chatId;
689
+ const conversationId = turn.conversationId ?? conversationKeyFor(msg.chatId, msg.endpointId);
669
690
  if (turn.intercept && await turn.intercept(sender)) {
670
691
  return { action: "intercepted" };
671
692
  }
672
- const personaLayer = await resolvePersonaLayer(config, { sender, text: msg.text });
693
+ const personaLayer = await resolvePersonaLayer(config, {
694
+ sender,
695
+ text: msg.text,
696
+ endpointId: msg.endpointId
697
+ });
673
698
  const buckets = await resolveBuckets({ mode, sender, bucketsFor: config.bucketsFor });
674
699
  const historyEnabled = config.history ? await isHistoryEnabled(config, sender) : false;
675
700
  const priorTurns = config.history && historyEnabled ? await config.history.store.load(
@@ -702,7 +727,8 @@ function createInboundPipeline(deps, config) {
702
727
  mode,
703
728
  sender,
704
729
  conversationId,
705
- model: config.model
730
+ model: config.model,
731
+ refusal: config.refusal
706
732
  });
707
733
  const content = await applyTransformReply(
708
734
  config.transformReply,
@@ -737,6 +763,7 @@ function defaultSleep(ms) {
737
763
  }
738
764
 
739
765
  // src/channels/matrix/updates.ts
766
+ var NO_IDENTITIES = /* @__PURE__ */ new Map();
740
767
  function messageText(content) {
741
768
  return content.body ?? "";
742
769
  }
@@ -804,7 +831,7 @@ function directInviteFrom(room, me) {
804
831
  }
805
832
  return void 0;
806
833
  }
807
- function toChannelMessage(roomId, event, me, directRooms, sentEventIds) {
834
+ function toChannelMessage(roomId, event, me, directRooms, sentEventIds, identities = NO_IDENTITIES, channelName) {
808
835
  if (event.type !== "m.room.message") return void 0;
809
836
  const content = event.content;
810
837
  if (!content.msgtype) return void 0;
@@ -816,10 +843,22 @@ function toChannelMessage(roomId, event, me, directRooms, sentEventIds) {
816
843
  isDirectMessage: directRooms.has(roomId),
817
844
  mentionsBot: mentionsBot(content, me),
818
845
  isReplyToBot: isReplyToBot(content, sentEventIds),
819
- fromBot: event.sender === me.userId,
820
- messageRef: event.event_id
846
+ // One access token is one user, but one process is not: a second bot
847
+ // account mounted alongside this one is a stranger to `me` and would be
848
+ // answered, and would answer back, forever. `identities` is what makes
849
+ // the other endpoint's user id "us" too - an empty one degenerates to
850
+ // the equality check.
851
+ fromBot: isEffectivelyFromSelf(
852
+ { fromBot: event.sender === me.userId, senderId: event.sender },
853
+ identities
854
+ ),
855
+ messageRef: event.event_id,
856
+ endpointId: channelName
821
857
  };
822
858
  }
859
+ function matrixOwnIdentities(me) {
860
+ return [me.userId];
861
+ }
823
862
  function matrixSenderKey(userId) {
824
863
  return `mx:${userId}`;
825
864
  }
@@ -834,7 +873,7 @@ async function sendText(api, roomId, text, sentEventIds, replyToEventId) {
834
873
  recordSentEventId(sentEventIds, eventId);
835
874
  }
836
875
  function createMatrixSyncHandler(deps) {
837
- const { api, me, pipeline, allowedChats, sentEventIds, logger, label } = deps;
876
+ const { api, me, pipeline, identities, allowedChats, sentEventIds, logger, label, channelName } = deps;
838
877
  const autoJoin = deps.autoJoin ?? true;
839
878
  const loggedUnallowedChats = /* @__PURE__ */ new Set();
840
879
  const loggedDeclinedInvites = /* @__PURE__ */ new Set();
@@ -879,7 +918,15 @@ function createMatrixSyncHandler(deps) {
879
918
  }
880
919
  for (const [roomId, room] of Object.entries(response.rooms?.join ?? {})) {
881
920
  for (const event of room.timeline.events) {
882
- const msg = toChannelMessage(roomId, event, me, directRooms, sentEventIds);
921
+ const msg = toChannelMessage(
922
+ roomId,
923
+ event,
924
+ me,
925
+ directRooms,
926
+ sentEventIds,
927
+ identities,
928
+ channelName
929
+ );
883
930
  if (!msg) continue;
884
931
  if (isBlockedByAllowlist(msg, { allowedChats })) {
885
932
  if (!loggedUnallowedChats.has(msg.chatId)) {
@@ -896,7 +943,6 @@ function createMatrixSyncHandler(deps) {
896
943
  try {
897
944
  await pipeline(msg, {
898
945
  reply,
899
- conversationId: msg.chatId,
900
946
  sender: matrixSenderKey(msg.senderId)
901
947
  });
902
948
  } catch (error) {
@@ -992,6 +1038,8 @@ function createMatrixChannel(config) {
992
1038
  });
993
1039
  const me = await api.whoami();
994
1040
  const label = `Matrix[${me.userId}]`;
1041
+ const identities = config.identities ?? deps.identities;
1042
+ identities.set(channelName, matrixOwnIdentities(me));
995
1043
  let initialDirect;
996
1044
  try {
997
1045
  const direct = await api.getAccountData(me.userId, "m.direct");
@@ -1025,13 +1073,18 @@ function createMatrixChannel(config) {
1025
1073
  const handleSync = createMatrixSyncHandler({
1026
1074
  api,
1027
1075
  me,
1076
+ identities,
1028
1077
  pipeline,
1029
1078
  allowedChats,
1030
1079
  sentEventIds,
1031
1080
  autoJoin: config.autoJoin,
1032
1081
  initialDirect,
1033
1082
  logger: log,
1034
- label
1083
+ label,
1084
+ // config.name, not the resolved channelName: endpointId opts in only
1085
+ // when the host explicitly named this channel (running more than
1086
+ // one bot in the process), not for a default single-token channel.
1087
+ channelName: config.name
1035
1088
  });
1036
1089
  abort = new AbortController();
1037
1090
  const signal = abort.signal;
@@ -1070,6 +1123,7 @@ export {
1070
1123
  directMappingRooms,
1071
1124
  directRoomIds,
1072
1125
  isReplyToBot,
1126
+ matrixOwnIdentities,
1073
1127
  matrixSenderKey,
1074
1128
  mentionsBot,
1075
1129
  messageText,
@@ -11,7 +11,7 @@
11
11
  * fallback for clients that only set that. The gate policy that consumes
12
12
  * those booleans (`decideChannelAction`) is identical for every channel.
13
13
  */
14
- import type { ChannelMessage } from "../gates";
14
+ import { type ChannelMessage, type SessionIdentityRegistry } from "../gates";
15
15
  import type { MatrixAccountDataEvent, MatrixEvent, MatrixInvitedRoom } from "./api";
16
16
  /** The bot's own identity, as `whoami` reports it. */
17
17
  export interface MatrixIdentity {
@@ -92,7 +92,13 @@ export declare function directInviteFrom(room: MatrixInvitedRoom, me: MatrixIden
92
92
  * decrypt), one with no `msgtype` at all (a redacted message), or an edit of
93
93
  * a message that was already delivered (see below).
94
94
  */
95
- export declare function toChannelMessage(roomId: string, event: MatrixEvent, me: MatrixIdentity, directRooms: ReadonlySet<string>, sentEventIds: ReadonlySet<string>): ChannelMessage | undefined;
95
+ export declare function toChannelMessage(roomId: string, event: MatrixEvent, me: MatrixIdentity, directRooms: ReadonlySet<string>, sentEventIds: ReadonlySet<string>, identities?: SessionIdentityRegistry, channelName?: string): ChannelMessage | undefined;
96
+ /**
97
+ * What this bot answers to on the wire, for a {@link SessionIdentityRegistry}.
98
+ * A Matrix user id is already globally unique (`@user:server.tld`), so it
99
+ * needs no namespacing to sit safely beside another transport's identities.
100
+ */
101
+ export declare function matrixOwnIdentities(me: MatrixIdentity): string[];
96
102
  /**
97
103
  * A stable identity key for `bucketsFor`/`personaResolver`/`answerFn`.
98
104
  * Namespaced so a bare Matrix user id (which is itself already `@user:
@@ -1 +1 @@
1
- {"version":3,"file":"updates.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/updates.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"updates.d.ts","sourceRoot":"","sources":["../../../src/channels/matrix/updates.ts"],"names":[],"mappings":"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"}
@@ -23,11 +23,12 @@ import type { BrainHooks } from "../types";
23
23
  import { type ChannelMessage } from "./gates";
24
24
  /**
25
25
  * Resolves the brain hooks (`answerFn`, `bucketsFor`, `rewriteQuery`,
26
- * `rerankContext`, `fallbackFn`, `transformReply`) for one channel: each
26
+ * `rerankContext`, `fallbackFn`, `transformReply`, `refusal`) for one
27
+ * channel: each
27
28
  * field from `config` wins when set, falling back to the matching field on
28
29
  * `fallback` (typically `deps.config`, the server-level `ChatterConfig`).
29
30
  * Every channel that layers its own hooks over the server's uses this
30
- * instead of hand-rolling the same six `??` lines: see `../telegram`,
31
+ * instead of hand-rolling the same `??` lines: see `../telegram`,
31
32
  * `../matrix` and `../whatsapp/inbound`.
32
33
  */
33
34
  export declare function resolveBrainHooks(config: BrainHooks, fallback?: BrainHooks): BrainHooks;
@@ -52,10 +53,16 @@ export interface InboundPipelineConfig extends BrainHooks {
52
53
  model?: string;
53
54
  /** Extra system-prompt section describing the delivery channel; passed through to `prepareChat`. */
54
55
  channelHint?: string;
55
- /** A throw/rejection is treated as "no persona" for that turn rather than failing the whole reply. */
56
+ /**
57
+ * A throw/rejection is treated as "no persona" for that turn rather than
58
+ * failing the whole reply. `endpointId` is `ChannelMessage.endpointId`, so a
59
+ * resolver can key on which of the process's own endpoints was reached; it
60
+ * is unset for a channel running a single endpoint.
61
+ */
56
62
  personaResolver?: (ctx: {
57
63
  sender: string;
58
64
  text: string;
65
+ endpointId?: string;
59
66
  }) => string | undefined | Promise<string | undefined>;
60
67
  /** Off by default — a channel stays single-turn until a store is configured. */
61
68
  history?: {
@@ -108,7 +115,7 @@ export interface InboundTurn {
108
115
  * Omitted -> `msg.senderId`.
109
116
  */
110
117
  sender?: string | (() => string | Promise<string>);
111
- /** Thread key for history/`answerFn`. Omitted -> `msg.chatId`. */
118
+ /** Thread key for history/`answerFn`. Omitted -> {@link conversationKeyFor}`(msg.chatId, msg.endpointId)`. */
112
119
  conversationId?: string;
113
120
  /**
114
121
  * Consulted after gates and rate-limiting pass, before persona/buckets/
@@ -127,6 +134,29 @@ export type InboundPipelineOutcome = {
127
134
  };
128
135
  /** The reusable handler `createInboundPipeline` returns — one call per inbound message. */
129
136
  export type InboundPipeline = (msg: ChannelMessage, turn: InboundTurn) => Promise<InboundPipelineOutcome>;
137
+ /**
138
+ * The default thread key for a message: `chatId` alone, or `chatId` paired
139
+ * with the endpoint that received it once one is set.
140
+ *
141
+ * `chatId` alone is not a thread. One sender reaching two of a process's own
142
+ * personas produces the same `chatId` on both, so a single key would hand
143
+ * each persona the other's turns. `ChannelMessage.endpointId` is only ever
144
+ * set by a channel genuinely running more than one endpoint, or given a
145
+ * custom name, which is exactly when that collision is possible, so a
146
+ * default single-endpoint host's key stays `chatId` and its stored history
147
+ * keeps reading back.
148
+ *
149
+ * Both halves are host-chosen strings that may contain anything, `#`
150
+ * included, so the pair is what has to stay unambiguous rather than either
151
+ * side: escaping both leaves exactly one bare `#`, and splitting there
152
+ * recovers the pair, so no two distinct pairs share a key.
153
+ *
154
+ * That guarantee covers pairs, not the two shapes: the single-endpoint key is
155
+ * left unescaped so it stays byte-identical to what a host already stored, so
156
+ * a bare `chatId` containing a `#` can coincide with some other pair's
157
+ * composed key. Marking it would close that and re-key every existing host.
158
+ */
159
+ export declare function conversationKeyFor(chatId: string, endpointId?: string): string;
130
160
  /**
131
161
  * Builds the reusable per-session (or per-channel) inbound handler: gates
132
162
  * and rate limiters live in its closure, exactly like a hand-rolled
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/channels/pipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/channels/pipeline.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ import type { Logger } from "../core/logger";
10
10
  import type { HistoryCompactionOptions } from "../history/compaction";
11
11
  import type { HistoryStore } from "../history/types";
12
12
  import type { BrainHooks } from "../types";
13
+ import type { SessionIdentityRegistry } from "./gates";
13
14
  export interface PollingChannelConfig extends BrainHooks {
14
15
  /** Channel and sender-registry name. Override to run more than one bot in one process. */
15
16
  name?: string;
@@ -22,6 +23,8 @@ export interface PollingChannelConfig extends BrainHooks {
22
23
  personaResolver?: (ctx: {
23
24
  sender: string;
24
25
  text: string;
26
+ /** Which of this process's endpoints received the message - see `ChannelMessage.endpointId`. Unset unless the channel runs more than one. */
27
+ endpointId?: string;
25
28
  }) => string | undefined | Promise<string | undefined>;
26
29
  /** Off by default — the channel stays single-turn until a store is configured. */
27
30
  history?: {
@@ -54,6 +57,14 @@ export interface PollingChannelConfig extends BrainHooks {
54
57
  max: number;
55
58
  windowMs: number;
56
59
  };
60
+ /**
61
+ * Every identity this process answers to, keyed by endpoint - what `fromBot`
62
+ * is resolved against, so one of your own bots is never answered as a
63
+ * stranger. @default `deps.identities`, the one registry `createServer`
64
+ * owns and shares with every channel; set this only to scope a channel to a
65
+ * registry of your own.
66
+ */
67
+ identities?: SessionIdentityRegistry;
57
68
  /** Overridable for tests and for hosts routing through a proxy; defaults to `globalThis.fetch`. */
58
69
  fetch?: typeof fetch;
59
70
  /** Overridable for tests; defaults to a `setTimeout`-based sleep. */
@@ -1 +1 @@
1
- {"version":3,"file":"polling.d.ts","sourceRoot":"","sources":["../../src/channels/polling.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,WAAW,oBAAqB,SAAQ,UAAU;IACtD,0FAA0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sHAAsH;IACtH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,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;;;;WAIG;QACH,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,gHAAgH;IAChH,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,mGAAmG;IACnG,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,qEAAqE;IACrE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,uGAAuG;IACvG,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uHAAuH;AACvH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKtD"}
1
+ {"version":3,"file":"polling.d.ts","sourceRoot":"","sources":["../../src/channels/polling.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEvD,MAAM,WAAW,oBAAqB,SAAQ,UAAU;IACtD,0FAA0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sHAAsH;IACtH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,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;;;;WAIG;QACH,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,gHAAgH;IAChH,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;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,uBAAuB,CAAC;IACrC,mGAAmG;IACnG,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,qEAAqE;IACrE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,uGAAuG;IACvG,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uHAAuH;AACvH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKtD"}
@@ -34,6 +34,8 @@ export interface TelegramChannelConfig extends PollingChannelConfig {
34
34
  personaResolver?: (ctx: {
35
35
  sender: string;
36
36
  text: string;
37
+ /** Which of this process's endpoints received the message - see `ChannelMessage.endpointId`. Unset unless the channel runs more than one. */
38
+ endpointId?: string;
37
39
  }) => string | undefined | Promise<string | undefined>;
38
40
  /** @default 30 */
39
41
  pollTimeoutSeconds?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,OAAO,CAAC;AAQ5D,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,8GAA8G;IAC9G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,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,kBAAkB;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0GAA0G;IAC1G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qJAAqJ;IACrJ,GAAG,CAAC,EAAE,WAAW,CAAC;CACnB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAmG5E"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,OAAO,CAAC;AAQ5D,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,8GAA8G;IAC9G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,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,kBAAkB;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0GAA0G;IAC1G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qJAAqJ;IACrJ,GAAG,CAAC,EAAE,WAAW,CAAC;CACnB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CA8G5E"}
@@ -6,6 +6,7 @@
6
6
  * moment one transport's gate behaviour changed and the other didn't.
7
7
  */
8
8
  import type { Logger } from "../../core/logger";
9
+ import { type SessionIdentityRegistry } from "../gates";
9
10
  import type { InboundPipeline } from "../pipeline";
10
11
  import type { ChannelSender } from "../senders";
11
12
  import type { TelegramApi, TelegramUpdate } from "./api";
@@ -14,11 +15,19 @@ export interface TelegramUpdateHandlerDeps {
14
15
  api: TelegramApi;
15
16
  me: TelegramBotIdentity;
16
17
  pipeline: InboundPipeline;
18
+ /**
19
+ * Every identity this process answers to, across all its channels - what
20
+ * `fromBot` is resolved against, so another endpoint of the same process is
21
+ * recognised as "us". Omitted: `me` alone, which cannot see a second bot.
22
+ */
23
+ identities?: SessionIdentityRegistry;
17
24
  /** Group chats eligible for a reply. Empty = every group. */
18
25
  allowedChats: string[];
19
26
  logger: Logger;
20
27
  /** Log-line prefix, e.g. `Telegram[mybot]`. */
21
28
  label: string;
29
+ /** This channel's configured name - populates `ChannelMessage.endpointId`. Omitted: `endpointId` is left unset. */
30
+ channelName?: string;
22
31
  }
23
32
  /**
24
33
  * One update -> one pipeline turn. Builds its own allowlist-log dedup set, so
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,KAAK,mBAAmB,EAAuC,MAAM,WAAW,CAAC;AAE1F,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,WAAW,CAAC;IACjB,EAAE,EAAE,mBAAmB,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,6DAA6D;IAC7D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,yBAAyB,GAC9B,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CA8B3C;AAED,wJAAwJ;AACxJ,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,CAOpE"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAwB,KAAK,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,KAAK,mBAAmB,EAAuC,MAAM,WAAW,CAAC;AAE1F,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,WAAW,CAAC;IACjB,EAAE,EAAE,mBAAmB,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B;;;;OAIG;IACH,UAAU,CAAC,EAAE,uBAAuB,CAAC;IACrC,6DAA6D;IAC7D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,mHAAmH;IACnH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,yBAAyB,GAC9B,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CA6B3C;AAED,wJAAwJ;AACxJ,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,CAOpE"}
@@ -28,6 +28,6 @@ export { createTelegramApi, redactToken, splitTelegramText, TELEGRAM_API_BASE, T
28
28
  export { createTelegramChannel, type TelegramChannelConfig } from "./channel";
29
29
  export { createTelegramSender, createTelegramUpdateHandler, type TelegramUpdateHandlerDeps, } from "./handler";
30
30
  export { type LongPollDeps, pollBackoffMs, retryDelayMs, runLongPoll } from "./poll";
31
- export { mentionsBot, messageEntities, messageText, nextOffset, type TelegramBotIdentity, telegramSenderKey, toChannelMessage, } from "./updates";
31
+ export { mentionsBot, messageEntities, messageText, nextOffset, type TelegramBotIdentity, telegramOwnIdentities, telegramSenderKey, toChannelMessage, } from "./updates";
32
32
  export { createTelegramWebhookRoute, type TelegramWebhookConfig } from "./webhook";
33
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,sBAAsB,GACvB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,qBAAqB,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC9E,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,KAAK,yBAAyB,GAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrF,OAAO,EACL,WAAW,EACX,eAAe,EACf,WAAW,EACX,UAAU,EACV,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,0BAA0B,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/channels/telegram/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,sBAAsB,GACvB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,qBAAqB,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC9E,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,KAAK,yBAAyB,GAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrF,OAAO,EACL,WAAW,EACX,eAAe,EACf,WAAW,EACX,UAAU,EACV,KAAK,mBAAmB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,0BAA0B,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC"}