@cogitator-ai/channels 0.16.0 → 0.18.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 (112) hide show
  1. package/README.md +78 -14
  2. package/dist/approvals.d.ts +3 -0
  3. package/dist/approvals.d.ts.map +1 -1
  4. package/dist/approvals.js +1 -0
  5. package/dist/approvals.js.map +1 -1
  6. package/dist/assistant-config.d.ts +60 -0
  7. package/dist/assistant-config.d.ts.map +1 -1
  8. package/dist/assistant-config.js +102 -0
  9. package/dist/assistant-config.js.map +1 -1
  10. package/dist/channels/email/address.d.ts +44 -0
  11. package/dist/channels/email/address.d.ts.map +1 -0
  12. package/dist/channels/email/address.js +211 -0
  13. package/dist/channels/email/address.js.map +1 -0
  14. package/dist/channels/email/auth.d.ts +59 -0
  15. package/dist/channels/email/auth.d.ts.map +1 -0
  16. package/dist/channels/email/auth.js +212 -0
  17. package/dist/channels/email/auth.js.map +1 -0
  18. package/dist/channels/email/channel.d.ts +256 -0
  19. package/dist/channels/email/channel.d.ts.map +1 -0
  20. package/dist/channels/email/channel.js +701 -0
  21. package/dist/channels/email/channel.js.map +1 -0
  22. package/dist/channels/email/errors.d.ts +11 -0
  23. package/dist/channels/email/errors.d.ts.map +1 -0
  24. package/dist/channels/email/errors.js +13 -0
  25. package/dist/channels/email/errors.js.map +1 -0
  26. package/dist/channels/email/imap.d.ts +125 -0
  27. package/dist/channels/email/imap.d.ts.map +1 -0
  28. package/dist/channels/email/imap.js +309 -0
  29. package/dist/channels/email/imap.js.map +1 -0
  30. package/dist/channels/email/index.d.ts +7 -0
  31. package/dist/channels/email/index.d.ts.map +1 -0
  32. package/dist/channels/email/index.js +3 -0
  33. package/dist/channels/email/index.js.map +1 -0
  34. package/dist/channels/email/mime.d.ts +71 -0
  35. package/dist/channels/email/mime.d.ts.map +1 -0
  36. package/dist/channels/email/mime.js +83 -0
  37. package/dist/channels/email/mime.js.map +1 -0
  38. package/dist/channels/email/multipart.d.ts +28 -0
  39. package/dist/channels/email/multipart.d.ts.map +1 -0
  40. package/dist/channels/email/multipart.js +102 -0
  41. package/dist/channels/email/multipart.js.map +1 -0
  42. package/dist/channels/email/providers.d.ts +49 -0
  43. package/dist/channels/email/providers.d.ts.map +1 -0
  44. package/dist/channels/email/providers.js +292 -0
  45. package/dist/channels/email/providers.js.map +1 -0
  46. package/dist/channels/email/reply.d.ts +9 -0
  47. package/dist/channels/email/reply.d.ts.map +1 -0
  48. package/dist/channels/email/reply.js +122 -0
  49. package/dist/channels/email/reply.js.map +1 -0
  50. package/dist/channels/teams/activity.d.ts +108 -0
  51. package/dist/channels/teams/activity.d.ts.map +1 -0
  52. package/dist/channels/teams/activity.js +206 -0
  53. package/dist/channels/teams/activity.js.map +1 -0
  54. package/dist/channels/teams/auth.d.ts +65 -0
  55. package/dist/channels/teams/auth.d.ts.map +1 -0
  56. package/dist/channels/teams/auth.js +213 -0
  57. package/dist/channels/teams/auth.js.map +1 -0
  58. package/dist/channels/teams/cards.d.ts +23 -0
  59. package/dist/channels/teams/cards.d.ts.map +1 -0
  60. package/dist/channels/teams/cards.js +97 -0
  61. package/dist/channels/teams/cards.js.map +1 -0
  62. package/dist/channels/teams/channel.d.ts +303 -0
  63. package/dist/channels/teams/channel.d.ts.map +1 -0
  64. package/dist/channels/teams/channel.js +1071 -0
  65. package/dist/channels/teams/channel.js.map +1 -0
  66. package/dist/channels/teams/client.d.ts +72 -0
  67. package/dist/channels/teams/client.d.ts.map +1 -0
  68. package/dist/channels/teams/client.js +161 -0
  69. package/dist/channels/teams/client.js.map +1 -0
  70. package/dist/channels/teams/index.d.ts +7 -0
  71. package/dist/channels/teams/index.d.ts.map +1 -0
  72. package/dist/channels/teams/index.js +6 -0
  73. package/dist/channels/teams/index.js.map +1 -0
  74. package/dist/channels/teams/pacer.d.ts +47 -0
  75. package/dist/channels/teams/pacer.d.ts.map +1 -0
  76. package/dist/channels/teams/pacer.js +174 -0
  77. package/dist/channels/teams/pacer.js.map +1 -0
  78. package/dist/channels/teams/token.d.ts +47 -0
  79. package/dist/channels/teams/token.d.ts.map +1 -0
  80. package/dist/channels/teams/token.js +107 -0
  81. package/dist/channels/teams/token.js.map +1 -0
  82. package/dist/channels/telegram.d.ts.map +1 -1
  83. package/dist/channels/telegram.js +3 -0
  84. package/dist/channels/telegram.js.map +1 -1
  85. package/dist/formatters/html.d.ts +16 -0
  86. package/dist/formatters/html.d.ts.map +1 -0
  87. package/dist/formatters/html.js +535 -0
  88. package/dist/formatters/html.js.map +1 -0
  89. package/dist/formatters/markdown-images.d.ts +8 -0
  90. package/dist/formatters/markdown-images.d.ts.map +1 -0
  91. package/dist/formatters/markdown-images.js +181 -0
  92. package/dist/formatters/markdown-images.js.map +1 -0
  93. package/dist/formatters/markdown.d.ts.map +1 -1
  94. package/dist/formatters/markdown.js +22 -3
  95. package/dist/formatters/markdown.js.map +1 -1
  96. package/dist/gateway.d.ts +23 -1
  97. package/dist/gateway.d.ts.map +1 -1
  98. package/dist/gateway.js +113 -16
  99. package/dist/gateway.js.map +1 -1
  100. package/dist/inbound-debounce.d.ts +4 -1
  101. package/dist/inbound-debounce.d.ts.map +1 -1
  102. package/dist/inbound-debounce.js +4 -2
  103. package/dist/inbound-debounce.js.map +1 -1
  104. package/dist/index.d.ts +5 -2
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +5 -2
  107. package/dist/index.js.map +1 -1
  108. package/dist/runtime-builder.d.ts +9 -0
  109. package/dist/runtime-builder.d.ts.map +1 -1
  110. package/dist/runtime-builder.js +145 -1
  111. package/dist/runtime-builder.js.map +1 -1
  112. package/package.json +25 -8
@@ -0,0 +1,181 @@
1
+ const FENCE = /^ {0,3}(`{3,}|~{3,})/;
2
+ const CLOSING_FENCE = /^ {0,3}(`{3,}|~{3,})[ \t]*$/;
3
+ /** The marker of a line that opens a fenced block: a backtick fence's info string has no backtick. */
4
+ function openingFence(line) {
5
+ const marker = FENCE.exec(line)?.[1];
6
+ if (!marker)
7
+ return undefined;
8
+ if (marker.startsWith('`') && line.includes('`', line.indexOf(marker) + marker.length)) {
9
+ return undefined;
10
+ }
11
+ return marker;
12
+ }
13
+ /**
14
+ * The code spans of a paragraph, as CommonMark reads them: a backtick run that no backslash
15
+ * escapes opens one, the next run of the same length closes it, and a run nothing closes is
16
+ * text. Backslashes inside a span are text. Each list of runs of one length is walked once, so
17
+ * this is linear in the length of `text`.
18
+ */
19
+ function codeSpansOf(text) {
20
+ const runsByLength = new Map();
21
+ for (let i = 0; i < text.length;) {
22
+ if (text[i] !== '`') {
23
+ i++;
24
+ continue;
25
+ }
26
+ const start = i;
27
+ while (i < text.length && text[i] === '`')
28
+ i++;
29
+ const starts = runsByLength.get(i - start) ?? [];
30
+ starts.push(start);
31
+ runsByLength.set(i - start, starts);
32
+ }
33
+ const cursors = new Map();
34
+ const spans = [];
35
+ for (let i = 0; i < text.length;) {
36
+ const char = text[i];
37
+ if (char === '\\' && i + 1 < text.length) {
38
+ i += 2;
39
+ continue;
40
+ }
41
+ if (char !== '`') {
42
+ i++;
43
+ continue;
44
+ }
45
+ const start = i;
46
+ while (i < text.length && text[i] === '`')
47
+ i++;
48
+ const length = i - start;
49
+ const starts = runsByLength.get(length) ?? [];
50
+ let cursor = cursors.get(length) ?? 0;
51
+ while (cursor < starts.length && starts[cursor] < i)
52
+ cursor++;
53
+ cursors.set(length, cursor);
54
+ const closing = starts[cursor];
55
+ if (closing === undefined)
56
+ continue;
57
+ spans.push([start, closing + length]);
58
+ i = closing + length;
59
+ }
60
+ return spans;
61
+ }
62
+ /** `prose` with its images as links (`![` becomes `[`) and raw `<img` tags as text. */
63
+ function rewriteProse(prose) {
64
+ let out = '';
65
+ for (let i = 0; i < prose.length; i++) {
66
+ const char = prose[i];
67
+ if (char === '\\' && i + 1 < prose.length) {
68
+ out += char + prose[i + 1];
69
+ i++;
70
+ }
71
+ else if (char === '!' && prose[i + 1] === '[') {
72
+ continue;
73
+ }
74
+ else if (char === '<' && prose.slice(i + 1, i + 4).toLowerCase() === 'img') {
75
+ out += '&lt;';
76
+ }
77
+ else {
78
+ out += char;
79
+ }
80
+ }
81
+ return out;
82
+ }
83
+ /**
84
+ * How `line` starts a block that ends the paragraph before it: a list item, heading, block
85
+ * quote, thematic break or HTML block. `single` blocks (headings, breaks) end on their own line.
86
+ * Splitting more often than CommonMark does only protects less as code, which stays safe.
87
+ */
88
+ function blockStart(line) {
89
+ let at = 0;
90
+ while (at < 3 && line[at] === ' ')
91
+ at++;
92
+ const first = line[at];
93
+ const after = (index) => index >= line.length || line[index] === ' ' || line[index] === '\t';
94
+ if (first === '>' || first === '<')
95
+ return 'open';
96
+ if (first === '#') {
97
+ let level = at;
98
+ while (level < line.length && line[level] === '#')
99
+ level++;
100
+ return level - at <= 6 && after(level) ? 'single' : undefined;
101
+ }
102
+ if (first === '-' || first === '*' || first === '_') {
103
+ let marks = 0;
104
+ let onlyMarks = true;
105
+ for (let i = at; i < line.length; i++) {
106
+ if (line[i] === first)
107
+ marks++;
108
+ else if (line[i] !== ' ' && line[i] !== '\t') {
109
+ onlyMarks = false;
110
+ break;
111
+ }
112
+ }
113
+ if (onlyMarks && marks >= 3)
114
+ return 'single';
115
+ return first !== '_' && after(at + 1) ? 'open' : undefined;
116
+ }
117
+ if (first === '+')
118
+ return after(at + 1) ? 'open' : undefined;
119
+ let digits = at;
120
+ while (digits < line.length && digits - at < 9 && line[digits] >= '0' && line[digits] <= '9')
121
+ digits++;
122
+ if (digits > at && (line[digits] === '.' || line[digits] === ')') && after(digits + 1)) {
123
+ return 'open';
124
+ }
125
+ return undefined;
126
+ }
127
+ function rewriteParagraph(paragraph) {
128
+ let out = '';
129
+ let from = 0;
130
+ for (const [start, end] of codeSpansOf(paragraph)) {
131
+ out += rewriteProse(paragraph.slice(from, start)) + paragraph.slice(start, end);
132
+ from = end;
133
+ }
134
+ return out + rewriteProse(paragraph.slice(from));
135
+ }
136
+ /**
137
+ * Markdown with its images turned into links and raw `<img>` tags into text, outside code
138
+ * (fenced blocks and code spans, read as CommonMark reads them), so a client that loads images
139
+ * as it shows a message cannot be made to request a URL the text names. Linear in the length of
140
+ * `text`.
141
+ */
142
+ export function imagesAsLinks(text) {
143
+ const out = [];
144
+ let paragraph = [];
145
+ let fence;
146
+ const flush = () => {
147
+ if (paragraph.length > 0)
148
+ out.push(rewriteParagraph(paragraph.join('\n')));
149
+ paragraph = [];
150
+ };
151
+ for (const line of text.split('\n')) {
152
+ if (fence) {
153
+ out.push(line);
154
+ const closing = CLOSING_FENCE.exec(line)?.[1];
155
+ if (closing?.[0] === fence[0] && closing.length >= fence.length)
156
+ fence = undefined;
157
+ continue;
158
+ }
159
+ const marker = openingFence(line);
160
+ if (marker) {
161
+ flush();
162
+ fence = marker;
163
+ out.push(line);
164
+ continue;
165
+ }
166
+ if (!line.trim()) {
167
+ flush();
168
+ out.push(line);
169
+ continue;
170
+ }
171
+ const block = blockStart(line);
172
+ if (block)
173
+ flush();
174
+ paragraph.push(line);
175
+ if (block === 'single')
176
+ flush();
177
+ }
178
+ flush();
179
+ return out.join('\n');
180
+ }
181
+ //# sourceMappingURL=markdown-images.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-images.js","sourceRoot":"","sources":["../../src/formatters/markdown-images.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAmBvD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAEjE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,CAc5E;AAsED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAuClE"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAqBvD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAEjE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,CAc5E;AAoFD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA0ClE"}
@@ -10,6 +10,8 @@ const PLATFORM_LIMITS = {
10
10
  bluesky: Infinity,
11
11
  threads: Infinity,
12
12
  github: 65536,
13
+ email: Infinity,
14
+ teams: 13653,
13
15
  };
14
16
  const DEFAULT_LIMIT = 4096;
15
17
  const FENCE_LINE_RE = /^ {0,3}(`{3,}|~{3,})/;
@@ -64,7 +66,22 @@ function findSplit(text, maxLength) {
64
66
  const space = text.lastIndexOf(' ', maxLength);
65
67
  if (space > 0)
66
68
  return { end: space, resume: space + 1 };
67
- return { end: maxLength, resume: maxLength };
69
+ const cut = cutBetweenCharacters(text, maxLength);
70
+ return { end: cut, resume: cut };
71
+ }
72
+ /**
73
+ * `at`, or one earlier when it falls between the two halves of a surrogate pair (an emoji), so a
74
+ * hard cut never leaves half a character on either side. A pair at the very start moves past it.
75
+ */
76
+ function cutBetweenCharacters(text, at) {
77
+ if (at <= 0 || at >= text.length)
78
+ return at;
79
+ const high = text.charCodeAt(at - 1);
80
+ const low = text.charCodeAt(at);
81
+ const splitsPair = high >= 0xd800 && high <= 0xdbff && low >= 0xdc00 && low <= 0xdfff;
82
+ if (!splitsPair)
83
+ return at;
84
+ return at - 1 > 0 ? at - 1 : at + 1;
68
85
  }
69
86
  function openFenceAtEnd(text) {
70
87
  let open = null;
@@ -105,8 +122,10 @@ export function chunkMessage(text, limit) {
105
122
  const room = maxLength - reserve;
106
123
  if (room > fence.length + 1) {
107
124
  split = findSplit(remaining, room);
108
- if (split.resume <= fence.length + 1)
109
- split = { end: room, resume: room };
125
+ if (split.resume <= fence.length + 1) {
126
+ const cut = cutBetweenCharacters(remaining, room);
127
+ split = { end: cut, resume: cut };
128
+ }
110
129
  chunk = remaining.slice(0, split.end);
111
130
  const stillOpen = openFenceAtEnd(chunk);
112
131
  if (stillOpen && split.resume > stillOpen.length + 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"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"}
package/dist/gateway.d.ts CHANGED
@@ -67,6 +67,18 @@ export declare class Gateway {
67
67
  private readonly pending;
68
68
  /** The stop in progress, which a second {@link stop} call returns */
69
69
  private stopping;
70
+ /** Calls of `channel.redeliver` in progress */
71
+ private readonly redeliveries;
72
+ /**
73
+ * Messages taken from a channel that can redeliver them, by the promise of their answer, until
74
+ * it settles. Those still here once `stop()` gave up on the runs are handed back.
75
+ */
76
+ private readonly unanswered;
77
+ /**
78
+ * Messages whose answer is going out or went out, by `answerKey`, so a run aborted after its
79
+ * first message was sent (or while it is being sent) is not redelivered
80
+ */
81
+ private readonly answeredKeys;
70
82
  /** The last pending write of each user's session, so writes to one session never interleave */
71
83
  private readonly sessionWrites;
72
84
  private running;
@@ -141,9 +153,19 @@ export declare class Gateway {
141
153
  /**
142
154
  * A message from a channel, a button or {@link injectMessage}. With a queue, a channel's message
143
155
  * is only queued, so the channel goes on to its next update while the thread waits its turn.
144
- * `untilAnswered` waits for the answer.
156
+ * `untilAnswered` waits for the answer. A message of `channel` the gateway does not answer
157
+ * because it stops (refused while stopping, or dropped by `stop()`) goes back through
158
+ * `channel.redeliver`.
145
159
  */
146
160
  private handleIncoming;
161
+ /** Hands a message back to its channel, reporting a failure to `onError`. */
162
+ private redeliver;
163
+ /**
164
+ * Watches the answer of messages taken from `channel`: when the gateway stops before answering
165
+ * them they go back through `channel.redeliver`, and so do those whose run is still going when
166
+ * `stop()` gives up on it. A message whose answer went out is never handed back.
167
+ */
168
+ private watchUnanswered;
147
169
  /** Puts a message through the queue of its thread, resolving once it is done with */
148
170
  private dispatch;
149
171
  /** Resolves `true` once the message is handled, `false` when it failed or was dropped */
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"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"}
package/dist/gateway.js CHANGED
@@ -8,7 +8,7 @@ import { InboundDebouncer } from './inbound-debounce.js';
8
8
  import { formatEnvelope } from './envelope.js';
9
9
  import { MessageQueue } from './message-queue.js';
10
10
  import { CONVERSATIONS_KEY, defaultThreadKey, findConversation, legacyThreadKey, readConversations, rememberConversation, } from './thread-key.js';
11
- import { DEFAULT_APPROVE_WORDS, DEFAULT_DENY_WORDS, DEFAULT_NOT_ALLOWED_MESSAGE, DEFAULT_EXPIRED_MESSAGE, APPROVE_ACTION, DENY_ACTION, formatApprovalPrompt, parseApprovalReply, } from './approvals.js';
11
+ import { DEFAULT_APPROVE_WORDS, DEFAULT_DENY_WORDS, DEFAULT_NOT_ALLOWED_MESSAGE, DEFAULT_EXPIRED_MESSAGE, DEFAULT_STOPPING_MESSAGE, APPROVE_ACTION, DENY_ACTION, formatApprovalPrompt, parseApprovalReply, } from './approvals.js';
12
12
  /** Markdown as the channel takes it: as written when it renders Markdown itself. */
13
13
  function adaptFor(channel, msg, text) {
14
14
  return channel.nativeMarkdown ? text : adaptMarkdown(text, msg.channelType);
@@ -17,6 +17,18 @@ function adaptFor(channel, msg, text) {
17
17
  function limitFor(channel, msg) {
18
18
  return channel.maxMessageChars ?? getPlatformLimit(msg.channelType);
19
19
  }
20
+ /**
21
+ * Lets the promise chains of what just settled run (the queue settles what it drops at once,
22
+ * and each answer settles a few promise steps later), without waiting for any timer.
23
+ */
24
+ async function settleMicrotasks() {
25
+ for (let i = 0; i < 20; i++)
26
+ await Promise.resolve();
27
+ }
28
+ /** The key of a message whose answer the gateway tracks: its channel, chat and id. */
29
+ function answerKey(msg) {
30
+ return `${msg.channelType}\u0000${msg.channelId}\u0000${msg.id}`;
31
+ }
20
32
  function draftKey(channelType, channelId, draftId) {
21
33
  return `${channelType}:${channelId}:${draftId}`;
22
34
  }
@@ -103,6 +115,18 @@ export class Gateway {
103
115
  pending = new Set();
104
116
  /** The stop in progress, which a second {@link stop} call returns */
105
117
  stopping = null;
118
+ /** Calls of `channel.redeliver` in progress */
119
+ redeliveries = new Set();
120
+ /**
121
+ * Messages taken from a channel that can redeliver them, by the promise of their answer, until
122
+ * it settles. Those still here once `stop()` gave up on the runs are handed back.
123
+ */
124
+ unanswered = new Map();
125
+ /**
126
+ * Messages whose answer is going out or went out, by `answerKey`, so a run aborted after its
127
+ * first message was sent (or while it is being sent) is not redelivered
128
+ */
129
+ answeredKeys = new Set();
106
130
  /** The last pending write of each user's session, so writes to one session never interleave */
107
131
  sessionWrites = new Map();
108
132
  running = false;
@@ -127,12 +151,17 @@ export class Gateway {
127
151
  ? null
128
152
  : new MessageQueue(queueMode, (msg, signal) => this.processMessage(msg, signal));
129
153
  this.debouncer = config.debounce?.enabled
130
- ? new InboundDebouncer(config.debounce, async (merged) => {
131
- this.dispatch(merged).catch(() => { });
154
+ ? new InboundDebouncer(config.debounce, async (merged, originals) => {
155
+ const answered = this.dispatch(merged);
156
+ const channel = this.channels.find((ch) => ch.type === merged.channelType);
157
+ if (channel?.redeliver)
158
+ this.watchUnanswered(channel, merged, originals, answered);
159
+ else
160
+ answered.catch(() => { });
132
161
  })
133
162
  : null;
134
163
  for (const channel of this.channels) {
135
- channel.onMessage((msg) => this.handleIncoming(msg, false));
164
+ channel.onMessage((msg) => this.handleIncoming(msg, false, channel));
136
165
  channel.onAction?.((action) => this.handleAction(channel, action));
137
166
  channel.onStop?.((stop) => {
138
167
  this.stoppableDrafts
@@ -188,6 +217,15 @@ export class Gateway {
188
217
  await settlesWithin(this.idle(), timeout);
189
218
  }
190
219
  this.messageQueue?.dispose();
220
+ await settleMicrotasks();
221
+ for (const [answered, { channel, handled, messages }] of this.unanswered) {
222
+ this.unanswered.delete(answered);
223
+ if (this.answeredKeys.has(answerKey(handled)))
224
+ continue;
225
+ for (const msg of messages)
226
+ void this.redeliver(channel, msg);
227
+ }
228
+ await Promise.all([...this.redeliveries].map((redelivery) => settlesWithin(redelivery, timeout)));
191
229
  await Promise.all(this.channels.map((ch) => ch.stop()));
192
230
  this.startedAt = null;
193
231
  }
@@ -358,6 +396,13 @@ export class Gateway {
358
396
  }
359
397
  }
360
398
  async answerApprovalButton(channel, action, answer) {
399
+ if (this.stopping) {
400
+ await answer({
401
+ text: this.config.approvals?.stoppingMessage ?? DEFAULT_STOPPING_MESSAGE,
402
+ alert: true,
403
+ });
404
+ return;
405
+ }
361
406
  const approve = action.data === APPROVE_ACTION;
362
407
  const msg = {
363
408
  id: action.messageId ?? action.id,
@@ -365,7 +410,7 @@ export class Gateway {
365
410
  channelId: action.channelId,
366
411
  userId: action.userId,
367
412
  ...(action.userName ? { userName: action.userName } : {}),
368
- ...(action.channelId.startsWith('-') ? { groupId: action.channelId } : {}),
413
+ ...(action.groupId ? { groupId: action.groupId } : {}),
369
414
  ...(action.topicId ? { topicId: action.topicId } : {}),
370
415
  ...(action.conversationId ? { conversationId: action.conversationId } : {}),
371
416
  text: (approve ? this.approvalWords.approveWords : this.approvalWords.denyWords)[0] ?? '',
@@ -429,14 +474,18 @@ export class Gateway {
429
474
  /**
430
475
  * A message from a channel, a button or {@link injectMessage}. With a queue, a channel's message
431
476
  * is only queued, so the channel goes on to its next update while the thread waits its turn.
432
- * `untilAnswered` waits for the answer.
477
+ * `untilAnswered` waits for the answer. A message of `channel` the gateway does not answer
478
+ * because it stops (refused while stopping, or dropped by `stop()`) goes back through
479
+ * `channel.redeliver`.
433
480
  */
434
- async handleIncoming(msg, untilAnswered) {
481
+ async handleIncoming(msg, untilAnswered, channel) {
435
482
  if (this.stopping) {
436
483
  const refused = new Error('The gateway is stopping: the message was dropped');
437
484
  this.config.onError?.(refused, msg);
438
485
  if (untilAnswered)
439
486
  throw refused;
487
+ if (channel?.redeliver)
488
+ await this.redeliver(channel, msg);
440
489
  return;
441
490
  }
442
491
  if (this.debouncer) {
@@ -444,13 +493,44 @@ export class Gateway {
444
493
  return;
445
494
  }
446
495
  const answered = this.dispatch(msg);
496
+ if (channel?.redeliver && !untilAnswered)
497
+ this.watchUnanswered(channel, msg, [msg], answered);
447
498
  if (untilAnswered || !this.messageQueue) {
448
- if (!(await answered) && untilAnswered) {
499
+ const done = await answered;
500
+ if (!done && untilAnswered) {
449
501
  throw new Error('The message was not answered: its run failed or was aborted');
450
502
  }
451
503
  return;
452
504
  }
453
- answered.catch(() => { });
505
+ if (!channel?.redeliver)
506
+ answered.catch(() => { });
507
+ }
508
+ /** Hands a message back to its channel, reporting a failure to `onError`. */
509
+ redeliver(channel, msg) {
510
+ const redelivery = Promise.resolve()
511
+ .then(() => channel.redeliver?.(msg))
512
+ .catch((error) => this.config.onError?.(toError(error), msg))
513
+ .finally(() => this.redeliveries.delete(redelivery));
514
+ this.redeliveries.add(redelivery);
515
+ return redelivery;
516
+ }
517
+ /**
518
+ * Watches the answer of messages taken from `channel`: when the gateway stops before answering
519
+ * them they go back through `channel.redeliver`, and so do those whose run is still going when
520
+ * `stop()` gives up on it. A message whose answer went out is never handed back.
521
+ */
522
+ watchUnanswered(channel, handled, messages, answered) {
523
+ const entry = { channel, handled, messages };
524
+ this.unanswered.set(answered, entry);
525
+ void answered.then((done) => {
526
+ if (this.unanswered.get(answered) !== entry)
527
+ return;
528
+ this.unanswered.delete(answered);
529
+ if (done || this.running)
530
+ return;
531
+ for (const msg of messages)
532
+ void this.redeliver(channel, msg);
533
+ });
454
534
  }
455
535
  /** Puts a message through the queue of its thread, resolving once it is done with */
456
536
  dispatch(msg) {
@@ -537,16 +617,20 @@ export class Gateway {
537
617
  const runSignal = signal ? AbortSignal.any([signal, stop.signal]) : stop.signal;
538
618
  this.stops.set(runSignal, stop);
539
619
  this.runs.add(stop);
620
+ const key = answerKey(msg);
540
621
  try {
541
622
  await this.processWithChannel(msg, channel, threadId, runSignal);
623
+ if (this.answeredKeys.has(key))
624
+ return true;
542
625
  return signal?.aborted !== true && stop.signal.reason !== GATEWAY_STOPPED;
543
626
  }
544
627
  catch (error) {
545
628
  if (!runSignal.aborted)
546
629
  this.config.onError?.(toError(error), msg);
547
- return false;
630
+ return this.answeredKeys.has(key);
548
631
  }
549
632
  finally {
633
+ this.answeredKeys.delete(key);
550
634
  this.runs.delete(stop);
551
635
  const remaining = (this.inFlight.get(threadId) ?? 1) - 1;
552
636
  if (remaining <= 0)
@@ -807,13 +891,24 @@ export class Gateway {
807
891
  async sendChunked(channel, msg, output, replyTo, buttons) {
808
892
  const chunks = chunkMessage(output, limitFor(channel, msg));
809
893
  const ids = [];
894
+ const key = answerKey(msg);
895
+ const first = !this.answeredKeys.has(key);
810
896
  for (let i = 0; i < chunks.length; i++) {
811
- ids.push(await channel.sendText(msg.channelId, chunks[i], {
812
- ...(i === 0 && replyTo ? { replyTo } : {}),
813
- ...(i === chunks.length - 1 && buttons ? { buttons } : {}),
814
- ...(msg.topicId ? { topicId: msg.topicId } : {}),
815
- format: 'markdown',
816
- }));
897
+ if (i === 0)
898
+ this.answeredKeys.add(key);
899
+ try {
900
+ ids.push(await channel.sendText(msg.channelId, chunks[i], {
901
+ ...(i === 0 && replyTo ? { replyTo } : {}),
902
+ ...(i === chunks.length - 1 && buttons ? { buttons } : {}),
903
+ ...(msg.topicId ? { topicId: msg.topicId } : {}),
904
+ format: 'markdown',
905
+ }));
906
+ }
907
+ catch (error) {
908
+ if (i === 0 && first)
909
+ this.answeredKeys.delete(key);
910
+ throw error;
911
+ }
817
912
  }
818
913
  return ids;
819
914
  }
@@ -887,6 +982,7 @@ export class Gateway {
887
982
  const stoppedByUser = () => stop?.signal.aborted === true;
888
983
  const keepWhatWasWritten = async () => {
889
984
  await stream.finish();
985
+ this.answeredKeys.add(answerKey(msg));
890
986
  await this.hooks?.emit('stream:finished', {
891
987
  msg,
892
988
  threadId,
@@ -928,6 +1024,7 @@ export class Gateway {
928
1024
  let replied = tokenCount > 0;
929
1025
  if (replied) {
930
1026
  await stream.finish();
1027
+ this.answeredKeys.add(answerKey(msg));
931
1028
  }
932
1029
  else {
933
1030
  await stream.abort();