@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.
- package/README.md +78 -14
- package/dist/approvals.d.ts +3 -0
- package/dist/approvals.d.ts.map +1 -1
- package/dist/approvals.js +1 -0
- package/dist/approvals.js.map +1 -1
- package/dist/assistant-config.d.ts +60 -0
- package/dist/assistant-config.d.ts.map +1 -1
- package/dist/assistant-config.js +102 -0
- package/dist/assistant-config.js.map +1 -1
- package/dist/channels/email/address.d.ts +44 -0
- package/dist/channels/email/address.d.ts.map +1 -0
- package/dist/channels/email/address.js +211 -0
- package/dist/channels/email/address.js.map +1 -0
- package/dist/channels/email/auth.d.ts +59 -0
- package/dist/channels/email/auth.d.ts.map +1 -0
- package/dist/channels/email/auth.js +212 -0
- package/dist/channels/email/auth.js.map +1 -0
- package/dist/channels/email/channel.d.ts +256 -0
- package/dist/channels/email/channel.d.ts.map +1 -0
- package/dist/channels/email/channel.js +701 -0
- package/dist/channels/email/channel.js.map +1 -0
- package/dist/channels/email/errors.d.ts +11 -0
- package/dist/channels/email/errors.d.ts.map +1 -0
- package/dist/channels/email/errors.js +13 -0
- package/dist/channels/email/errors.js.map +1 -0
- package/dist/channels/email/imap.d.ts +125 -0
- package/dist/channels/email/imap.d.ts.map +1 -0
- package/dist/channels/email/imap.js +309 -0
- package/dist/channels/email/imap.js.map +1 -0
- package/dist/channels/email/index.d.ts +7 -0
- package/dist/channels/email/index.d.ts.map +1 -0
- package/dist/channels/email/index.js +3 -0
- package/dist/channels/email/index.js.map +1 -0
- package/dist/channels/email/mime.d.ts +71 -0
- package/dist/channels/email/mime.d.ts.map +1 -0
- package/dist/channels/email/mime.js +83 -0
- package/dist/channels/email/mime.js.map +1 -0
- package/dist/channels/email/multipart.d.ts +28 -0
- package/dist/channels/email/multipart.d.ts.map +1 -0
- package/dist/channels/email/multipart.js +102 -0
- package/dist/channels/email/multipart.js.map +1 -0
- package/dist/channels/email/providers.d.ts +49 -0
- package/dist/channels/email/providers.d.ts.map +1 -0
- package/dist/channels/email/providers.js +292 -0
- package/dist/channels/email/providers.js.map +1 -0
- package/dist/channels/email/reply.d.ts +9 -0
- package/dist/channels/email/reply.d.ts.map +1 -0
- package/dist/channels/email/reply.js +122 -0
- package/dist/channels/email/reply.js.map +1 -0
- package/dist/channels/teams/activity.d.ts +108 -0
- package/dist/channels/teams/activity.d.ts.map +1 -0
- package/dist/channels/teams/activity.js +206 -0
- package/dist/channels/teams/activity.js.map +1 -0
- package/dist/channels/teams/auth.d.ts +65 -0
- package/dist/channels/teams/auth.d.ts.map +1 -0
- package/dist/channels/teams/auth.js +213 -0
- package/dist/channels/teams/auth.js.map +1 -0
- package/dist/channels/teams/cards.d.ts +23 -0
- package/dist/channels/teams/cards.d.ts.map +1 -0
- package/dist/channels/teams/cards.js +97 -0
- package/dist/channels/teams/cards.js.map +1 -0
- package/dist/channels/teams/channel.d.ts +303 -0
- package/dist/channels/teams/channel.d.ts.map +1 -0
- package/dist/channels/teams/channel.js +1071 -0
- package/dist/channels/teams/channel.js.map +1 -0
- package/dist/channels/teams/client.d.ts +72 -0
- package/dist/channels/teams/client.d.ts.map +1 -0
- package/dist/channels/teams/client.js +161 -0
- package/dist/channels/teams/client.js.map +1 -0
- package/dist/channels/teams/index.d.ts +7 -0
- package/dist/channels/teams/index.d.ts.map +1 -0
- package/dist/channels/teams/index.js +6 -0
- package/dist/channels/teams/index.js.map +1 -0
- package/dist/channels/teams/pacer.d.ts +47 -0
- package/dist/channels/teams/pacer.d.ts.map +1 -0
- package/dist/channels/teams/pacer.js +174 -0
- package/dist/channels/teams/pacer.js.map +1 -0
- package/dist/channels/teams/token.d.ts +47 -0
- package/dist/channels/teams/token.d.ts.map +1 -0
- package/dist/channels/teams/token.js +107 -0
- package/dist/channels/teams/token.js.map +1 -0
- package/dist/channels/telegram.d.ts.map +1 -1
- package/dist/channels/telegram.js +3 -0
- package/dist/channels/telegram.js.map +1 -1
- package/dist/formatters/html.d.ts +16 -0
- package/dist/formatters/html.d.ts.map +1 -0
- package/dist/formatters/html.js +535 -0
- package/dist/formatters/html.js.map +1 -0
- package/dist/formatters/markdown-images.d.ts +8 -0
- package/dist/formatters/markdown-images.d.ts.map +1 -0
- package/dist/formatters/markdown-images.js +181 -0
- package/dist/formatters/markdown-images.js.map +1 -0
- package/dist/formatters/markdown.d.ts.map +1 -1
- package/dist/formatters/markdown.js +22 -3
- package/dist/formatters/markdown.js.map +1 -1
- package/dist/gateway.d.ts +23 -1
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +113 -16
- package/dist/gateway.js.map +1 -1
- package/dist/inbound-debounce.d.ts +4 -1
- package/dist/inbound-debounce.d.ts.map +1 -1
- package/dist/inbound-debounce.js +4 -2
- package/dist/inbound-debounce.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/runtime-builder.d.ts +9 -0
- package/dist/runtime-builder.d.ts.map +1 -1
- package/dist/runtime-builder.js +145 -1
- package/dist/runtime-builder.js.map +1 -1
- 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 += '<';
|
|
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;
|
|
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
|
-
|
|
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
|
-
|
|
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":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,eAAe,GAA2B;IAC9C,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,IAAI;IACb,KAAK,EAAE,KAAK;IACZ,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE,KAAK;
|
|
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 */
|
package/dist/gateway.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EAIZ,cAAc,EAMd,YAAY,EAUb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAM3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;
|
|
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)
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
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();
|