@llblab/pi-kit 0.5.1 → 0.6.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/CHANGELOG.md +8 -0
- package/README.md +3 -3
- package/node_modules/@llblab/pi-grow-loop/AGENTS.md +2 -2
- package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +4 -0
- package/node_modules/@llblab/pi-grow-loop/README.md +6 -6
- package/node_modules/@llblab/pi-grow-loop/index.ts +6 -3
- package/node_modules/@llblab/pi-grow-loop/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +20 -0
- package/node_modules/@llblab/pi-telegram/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +4 -0
- package/node_modules/@llblab/pi-telegram/docs/outbound.md +27 -5
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +1 -0
- package/node_modules/@llblab/pi-telegram/index.ts +24 -19
- package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +43 -25
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +79 -6
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +110 -91
- package/node_modules/@llblab/pi-telegram/lib/config.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/delivery.ts +18 -18
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +14 -3
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +2 -2
- package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +41 -37
- package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +39 -42
- package/node_modules/@llblab/pi-telegram/lib/outbound.ts +28 -17
- package/node_modules/@llblab/pi-telegram/lib/preview.ts +134 -73
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +113 -72
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +46 -38
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +192 -58
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +36 -3
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +27 -35
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/node_modules/@llblab/skills/abcd-context/AGENTS.md +1 -0
- package/node_modules/@llblab/skills/abcd-context/CHANGELOG.md +6 -2
- package/node_modules/@llblab/skills/abcd-context/SKILL.md +1 -1
- package/node_modules/@llblab/skills/abcd-context/docs/validation-design.md +11 -5
- package/node_modules/@llblab/skills/abcd-context/scripts/_self-test.mjs +61 -0
- package/node_modules/@llblab/skills/abcd-context/scripts/validate-context.mjs +67 -0
- package/node_modules/@llblab/skills/package.json +1 -1
- package/node_modules/@llblab/skills/release-flow/SKILL.md +2 -4
- package/package.json +4 -4
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { normalizeTelegramNativeMarkdown } from "./replies.ts";
|
|
8
|
-
import {
|
|
8
|
+
import type { TelegramAssistantOutputPreparation } from "./activity.ts";
|
|
9
|
+
import { stripTelegramCommentMarkupForPreview } from "./outbound-markup.ts";
|
|
9
10
|
import {
|
|
10
11
|
getTelegramTargetThreadParams,
|
|
11
12
|
type TelegramTarget,
|
|
@@ -14,6 +15,7 @@ import { shouldSuppressPreviewForVoice } from "./voice.ts";
|
|
|
14
15
|
|
|
15
16
|
const TELEGRAM_DRAFT_ID_MAX = 2_147_483_647;
|
|
16
17
|
const TELEGRAM_DRAFT_PREVIEW_MAX_CHARS = 4096;
|
|
18
|
+
const TELEGRAM_DRAFT_INTERVAL_MS = 2_000;
|
|
17
19
|
|
|
18
20
|
export type TelegramDraftSupport = "unknown" | "supported";
|
|
19
21
|
|
|
@@ -27,6 +29,11 @@ export interface TelegramPreviewState {
|
|
|
27
29
|
export interface TelegramPreviewRuntimeState extends TelegramPreviewState {
|
|
28
30
|
flushPromise?: Promise<void>;
|
|
29
31
|
flushRequested?: boolean;
|
|
32
|
+
precedingFlush?: Promise<void>;
|
|
33
|
+
publicationPromise?: Promise<void>;
|
|
34
|
+
sealed?: boolean;
|
|
35
|
+
nextDraftAt?: number;
|
|
36
|
+
flushTimer?: ReturnType<typeof setTimeout>;
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
export type TelegramPreviewReplyMarkup = unknown;
|
|
@@ -35,6 +42,7 @@ export interface TelegramPreviewRuntimeDeps {
|
|
|
35
42
|
getState: () => TelegramPreviewRuntimeState | undefined;
|
|
36
43
|
setState: (state: TelegramPreviewRuntimeState | undefined) => void;
|
|
37
44
|
maxMessageLength: number;
|
|
45
|
+
minDraftIntervalMs?: number;
|
|
38
46
|
getDraftSupport: () => TelegramDraftSupport;
|
|
39
47
|
setDraftSupport: (support: TelegramDraftSupport) => void;
|
|
40
48
|
allocateDraftId: () => number;
|
|
@@ -64,23 +72,13 @@ export interface TelegramPreviewActiveTurn {
|
|
|
64
72
|
voiceReplyRequired?: boolean;
|
|
65
73
|
}
|
|
66
74
|
|
|
67
|
-
export interface TelegramAssistantMessagePreviewStartDeps<
|
|
68
|
-
TMessage,
|
|
69
|
-
TReplyMarkup = TelegramPreviewReplyMarkup,
|
|
70
|
-
> {
|
|
75
|
+
export interface TelegramAssistantMessagePreviewStartDeps<TMessage> {
|
|
71
76
|
getActiveTurn: () => TelegramPreviewActiveTurn | undefined;
|
|
72
77
|
isAssistantMessage: (message: TMessage) => boolean;
|
|
73
78
|
getState: () => TelegramPreviewRuntimeState | undefined;
|
|
74
79
|
setState: (state: TelegramPreviewRuntimeState | undefined) => void;
|
|
75
80
|
createPreviewState: () => TelegramPreviewRuntimeState;
|
|
76
81
|
canSend?: () => boolean;
|
|
77
|
-
finalizePreview: (chatId: number) => Promise<boolean>;
|
|
78
|
-
finalizeMarkdownPreview: (
|
|
79
|
-
chatId: number,
|
|
80
|
-
markdown: string,
|
|
81
|
-
replyToMessageId?: number,
|
|
82
|
-
options?: { replyMarkup?: TReplyMarkup; target?: TelegramTarget },
|
|
83
|
-
) => Promise<boolean>;
|
|
84
82
|
}
|
|
85
83
|
|
|
86
84
|
export interface TelegramAssistantMessagePreviewUpdateDeps<TMessage> {
|
|
@@ -97,10 +95,7 @@ export interface TelegramAssistantMessagePreviewUpdateDeps<TMessage> {
|
|
|
97
95
|
) => void;
|
|
98
96
|
}
|
|
99
97
|
|
|
100
|
-
export type TelegramAssistantMessagePreviewHookDeps<
|
|
101
|
-
TMessage,
|
|
102
|
-
TReplyMarkup = TelegramPreviewReplyMarkup,
|
|
103
|
-
> = TelegramAssistantMessagePreviewStartDeps<TMessage, TReplyMarkup> &
|
|
98
|
+
export type TelegramAssistantMessagePreviewHookDeps<TMessage> = TelegramAssistantMessagePreviewStartDeps<TMessage> &
|
|
104
99
|
TelegramAssistantMessagePreviewUpdateDeps<TMessage>;
|
|
105
100
|
|
|
106
101
|
export interface TelegramAssistantMessagePreviewHookEvent<TMessage> {
|
|
@@ -140,6 +135,12 @@ export interface TelegramPreviewControllerDeps {
|
|
|
140
135
|
}
|
|
141
136
|
|
|
142
137
|
export interface TelegramPreviewController {
|
|
138
|
+
seal: () => void;
|
|
139
|
+
preparePublication: () => TelegramAssistantOutputPreparation | undefined;
|
|
140
|
+
prepareClear: (
|
|
141
|
+
chatId: number,
|
|
142
|
+
options?: { target?: TelegramTarget; isDeliveryActive?: () => boolean },
|
|
143
|
+
) => () => Promise<void>;
|
|
143
144
|
getState: () => TelegramPreviewRuntimeState | undefined;
|
|
144
145
|
setState: (state: TelegramPreviewRuntimeState | undefined) => void;
|
|
145
146
|
setPendingText: (text: string) => void;
|
|
@@ -197,11 +198,18 @@ export interface TelegramAssistantPreviewRuntimeDeps<
|
|
|
197
198
|
) => Promise<number | undefined>;
|
|
198
199
|
}
|
|
199
200
|
|
|
201
|
+
export interface TelegramPreparedPreviewDelivery<TReplyMarkup = unknown> {
|
|
202
|
+
clearPreview: TelegramPreviewController["clear"];
|
|
203
|
+
setPreviewPendingText: TelegramPreviewController["setPendingText"];
|
|
204
|
+
finalizeMarkdownPreview: ReturnType<typeof createTelegramNativeMarkdownPreviewFinalizer<TReplyMarkup>>;
|
|
205
|
+
}
|
|
206
|
+
|
|
200
207
|
export type TelegramAssistantPreviewRuntime<
|
|
201
208
|
TMessage,
|
|
202
209
|
TReplyMarkup = TelegramPreviewReplyMarkup,
|
|
203
210
|
> = TelegramPreviewController &
|
|
204
211
|
TelegramAssistantMessagePreviewHooks<TMessage> & {
|
|
212
|
+
prepareDelivery: (isDeliveryActive: () => boolean) => TelegramPreparedPreviewDelivery<TReplyMarkup>;
|
|
205
213
|
finalizeMarkdown: (
|
|
206
214
|
chatId: number,
|
|
207
215
|
markdown: string,
|
|
@@ -210,6 +218,14 @@ export type TelegramAssistantPreviewRuntime<
|
|
|
210
218
|
) => Promise<boolean>;
|
|
211
219
|
};
|
|
212
220
|
|
|
221
|
+
function sealTelegramPreviewState(state: TelegramPreviewRuntimeState | undefined): void {
|
|
222
|
+
if (!state) return;
|
|
223
|
+
state.sealed = true;
|
|
224
|
+
state.flushRequested = false;
|
|
225
|
+
if (state.flushTimer) clearTimeout(state.flushTimer);
|
|
226
|
+
state.flushTimer = undefined;
|
|
227
|
+
}
|
|
228
|
+
|
|
213
229
|
export function createTelegramNativeMarkdownPreviewFinalizer<
|
|
214
230
|
TReplyMarkup,
|
|
215
231
|
>(deps: {
|
|
@@ -219,6 +235,7 @@ export function createTelegramNativeMarkdownPreviewFinalizer<
|
|
|
219
235
|
options?: { awaitFlush?: boolean; target?: TelegramTarget },
|
|
220
236
|
) => Promise<void>;
|
|
221
237
|
discard?: () => void;
|
|
238
|
+
isDeliveryActive?: () => boolean;
|
|
222
239
|
sendMarkdownReply: (
|
|
223
240
|
chatId: number,
|
|
224
241
|
replyToMessageId: number | undefined,
|
|
@@ -231,14 +248,21 @@ export function createTelegramNativeMarkdownPreviewFinalizer<
|
|
|
231
248
|
replyToMessageId?: number,
|
|
232
249
|
options?: { replyMarkup?: TReplyMarkup; target?: TelegramTarget },
|
|
233
250
|
) => Promise<boolean> {
|
|
251
|
+
return (...args) => prepareTelegramNativeMarkdownPreviewFinalizer(deps)(...args);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function prepareTelegramNativeMarkdownPreviewFinalizer<TReplyMarkup>(
|
|
255
|
+
deps: Parameters<typeof createTelegramNativeMarkdownPreviewFinalizer<TReplyMarkup>>[0],
|
|
256
|
+
): ReturnType<typeof createTelegramNativeMarkdownPreviewFinalizer<TReplyMarkup>> {
|
|
257
|
+
const state = deps.getState();
|
|
258
|
+
sealTelegramPreviewState(state);
|
|
259
|
+
const inFlight = state?.flushPromise ?? state?.precedingFlush;
|
|
234
260
|
return async (chatId, markdown, replyToMessageId, options) => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
if (deps.getState() !== state) return false;
|
|
239
|
-
}
|
|
261
|
+
if (deps.isDeliveryActive?.() === false) return false;
|
|
262
|
+
await inFlight?.catch(() => {});
|
|
263
|
+
if (deps.getState() !== state || deps.isDeliveryActive?.() === false) return false;
|
|
240
264
|
await deps.sendMarkdownReply(chatId, replyToMessageId, markdown, options);
|
|
241
|
-
if (deps.getState() === state) deps.discard?.();
|
|
265
|
+
if (deps.getState() === state && deps.isDeliveryActive?.() !== false) deps.discard?.();
|
|
242
266
|
return true;
|
|
243
267
|
};
|
|
244
268
|
}
|
|
@@ -250,15 +274,28 @@ export function createTelegramAssistantPreviewRuntime<
|
|
|
250
274
|
deps: TelegramAssistantPreviewRuntimeDeps<TMessage, TReplyMarkup>,
|
|
251
275
|
): TelegramAssistantPreviewRuntime<TMessage, TReplyMarkup> {
|
|
252
276
|
const controller = createTelegramPreviewControllerRuntime(deps);
|
|
253
|
-
const
|
|
277
|
+
const finalizerDeps = {
|
|
254
278
|
getState: controller.getState,
|
|
255
279
|
clear: controller.clear,
|
|
256
280
|
discard: () => controller.setState(undefined),
|
|
257
281
|
sendMarkdownReply: deps.sendMarkdownReply,
|
|
258
|
-
}
|
|
282
|
+
};
|
|
259
283
|
return {
|
|
260
284
|
...controller,
|
|
261
|
-
finalizeMarkdown:
|
|
285
|
+
finalizeMarkdown: createTelegramNativeMarkdownPreviewFinalizer(finalizerDeps),
|
|
286
|
+
prepareDelivery(isDeliveryActive) {
|
|
287
|
+
const state = controller.getState();
|
|
288
|
+
return {
|
|
289
|
+
setPreviewPendingText(text) {
|
|
290
|
+
if (controller.getState() === state && isDeliveryActive()) controller.setPendingText(text);
|
|
291
|
+
},
|
|
292
|
+
clearPreview: async (chatId, options) => {
|
|
293
|
+
if (controller.getState() !== state || !isDeliveryActive()) return;
|
|
294
|
+
await controller.prepareClear(chatId, { ...options, isDeliveryActive })();
|
|
295
|
+
},
|
|
296
|
+
finalizeMarkdownPreview: prepareTelegramNativeMarkdownPreviewFinalizer({ ...finalizerDeps, isDeliveryActive }),
|
|
297
|
+
};
|
|
298
|
+
},
|
|
262
299
|
...createTelegramAssistantMessagePreviewHooks({
|
|
263
300
|
getActiveTurn: deps.getActiveTurn,
|
|
264
301
|
isAssistantMessage: deps.isAssistantMessage,
|
|
@@ -266,8 +303,6 @@ export function createTelegramAssistantPreviewRuntime<
|
|
|
266
303
|
setState: controller.setState,
|
|
267
304
|
createPreviewState: controller.createState,
|
|
268
305
|
canSend: deps.canSend,
|
|
269
|
-
finalizePreview: controller.finalize,
|
|
270
|
-
finalizeMarkdownPreview,
|
|
271
306
|
getMessageText: deps.getMessageText,
|
|
272
307
|
schedulePreviewFlush: controller.scheduleFlush,
|
|
273
308
|
}),
|
|
@@ -284,14 +319,17 @@ export function createTelegramPreviewController(
|
|
|
284
319
|
deps.maxMessageLength ?? TELEGRAM_DRAFT_PREVIEW_MAX_CHARS;
|
|
285
320
|
let draftSupport = deps.initialDraftSupport ?? "unknown";
|
|
286
321
|
let nextDraftId = 0;
|
|
322
|
+
const setState = (nextState: TelegramPreviewRuntimeState | undefined): void => {
|
|
323
|
+
if (state !== nextState) sealTelegramPreviewState(state);
|
|
324
|
+
state = nextState;
|
|
325
|
+
};
|
|
287
326
|
const getRuntimeDeps = (
|
|
288
327
|
operationGeneration = generation,
|
|
289
328
|
): TelegramPreviewRuntimeDeps => ({
|
|
290
329
|
getState: () => state,
|
|
291
|
-
setState
|
|
292
|
-
state = nextState;
|
|
293
|
-
},
|
|
330
|
+
setState,
|
|
294
331
|
maxMessageLength,
|
|
332
|
+
minDraftIntervalMs: TELEGRAM_DRAFT_INTERVAL_MS,
|
|
295
333
|
getDraftSupport: () => draftSupport,
|
|
296
334
|
setDraftSupport: (support) => {
|
|
297
335
|
draftSupport = support;
|
|
@@ -307,20 +345,38 @@ export function createTelegramPreviewController(
|
|
|
307
345
|
});
|
|
308
346
|
return {
|
|
309
347
|
getState: () => state,
|
|
310
|
-
setState
|
|
311
|
-
state = nextState;
|
|
312
|
-
},
|
|
348
|
+
setState,
|
|
313
349
|
setPendingText: (text) => {
|
|
314
350
|
if (state) state.pendingText = text;
|
|
315
351
|
},
|
|
316
352
|
createState: () => createTelegramPreviewRuntimeState(),
|
|
317
353
|
resetState: () => {
|
|
318
354
|
generation += 1;
|
|
319
|
-
|
|
355
|
+
setState({ ...createTelegramPreviewRuntimeState(), nextDraftAt: state?.nextDraftAt });
|
|
320
356
|
},
|
|
321
357
|
invalidate: () => {
|
|
322
358
|
generation += 1;
|
|
323
|
-
|
|
359
|
+
setState(undefined);
|
|
360
|
+
},
|
|
361
|
+
seal: () => sealTelegramPreviewState(state),
|
|
362
|
+
preparePublication: () => {
|
|
363
|
+
if (!state) return undefined;
|
|
364
|
+
sealTelegramPreviewState(state);
|
|
365
|
+
const prior = state.publicationPromise ?? state.flushPromise ?? state.precedingFlush;
|
|
366
|
+
let settle!: () => void;
|
|
367
|
+
state.publicationPromise = new Promise<void>((resolve) => { settle = resolve; });
|
|
368
|
+
return { wait: async () => { await prior?.catch(() => {}); }, settle };
|
|
369
|
+
},
|
|
370
|
+
prepareClear: (chatId, options) => {
|
|
371
|
+
const admittedState = state;
|
|
372
|
+
const runtime = getRuntimeDeps();
|
|
373
|
+
return async () => {
|
|
374
|
+
if (state !== admittedState) return;
|
|
375
|
+
await clearTelegramPreview(chatId, runtime, {
|
|
376
|
+
...options,
|
|
377
|
+
isDeliveryActive: () => runtime.canSend?.() !== false && options?.isDeliveryActive?.() !== false,
|
|
378
|
+
});
|
|
379
|
+
};
|
|
324
380
|
},
|
|
325
381
|
clear: (chatId, options) =>
|
|
326
382
|
clearTelegramPreview(chatId, getRuntimeDeps(), options),
|
|
@@ -335,11 +391,8 @@ export function createTelegramPreviewController(
|
|
|
335
391
|
};
|
|
336
392
|
}
|
|
337
393
|
|
|
338
|
-
export function createTelegramAssistantMessagePreviewHooks<
|
|
339
|
-
TMessage
|
|
340
|
-
TReplyMarkup = TelegramPreviewReplyMarkup,
|
|
341
|
-
>(
|
|
342
|
-
deps: TelegramAssistantMessagePreviewHookDeps<TMessage, TReplyMarkup>,
|
|
394
|
+
export function createTelegramAssistantMessagePreviewHooks<TMessage>(
|
|
395
|
+
deps: TelegramAssistantMessagePreviewHookDeps<TMessage>,
|
|
343
396
|
): TelegramAssistantMessagePreviewHooks<TMessage> {
|
|
344
397
|
return {
|
|
345
398
|
onMessageStart: async (
|
|
@@ -355,12 +408,9 @@ export function createTelegramAssistantMessagePreviewHooks<
|
|
|
355
408
|
};
|
|
356
409
|
}
|
|
357
410
|
|
|
358
|
-
export async function handleTelegramAssistantMessagePreviewStart<
|
|
359
|
-
TMessage,
|
|
360
|
-
TReplyMarkup = TelegramPreviewReplyMarkup,
|
|
361
|
-
>(
|
|
411
|
+
export async function handleTelegramAssistantMessagePreviewStart<TMessage>(
|
|
362
412
|
message: TMessage,
|
|
363
|
-
deps: TelegramAssistantMessagePreviewStartDeps<TMessage
|
|
413
|
+
deps: TelegramAssistantMessagePreviewStartDeps<TMessage>,
|
|
364
414
|
): Promise<void> {
|
|
365
415
|
const turn = deps.getActiveTurn();
|
|
366
416
|
if (!turn || !deps.isAssistantMessage(message)) return;
|
|
@@ -373,26 +423,13 @@ export async function handleTelegramAssistantMessagePreviewStart<
|
|
|
373
423
|
return;
|
|
374
424
|
}
|
|
375
425
|
const state = deps.getState();
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
await deps.finalizeMarkdownPreview(
|
|
384
|
-
turn.chatId,
|
|
385
|
-
previousText,
|
|
386
|
-
turn.replyToMessageId,
|
|
387
|
-
{
|
|
388
|
-
target: turn.target,
|
|
389
|
-
},
|
|
390
|
-
);
|
|
391
|
-
} else {
|
|
392
|
-
await deps.finalizePreview(turn.chatId);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
deps.setState(deps.createPreviewState());
|
|
426
|
+
sealTelegramPreviewState(state);
|
|
427
|
+
const next = deps.createPreviewState();
|
|
428
|
+
// Carry the previous delivery boundary; permanent text remains with its publication owner.
|
|
429
|
+
next.draftId = state?.draftId;
|
|
430
|
+
next.nextDraftAt = state?.nextDraftAt;
|
|
431
|
+
next.precedingFlush = state?.publicationPromise ?? state?.flushPromise ?? state?.precedingFlush;
|
|
432
|
+
deps.setState(next);
|
|
396
433
|
}
|
|
397
434
|
|
|
398
435
|
export async function handleTelegramAssistantMessagePreviewUpdate<TMessage>(
|
|
@@ -411,6 +448,7 @@ export async function handleTelegramAssistantMessagePreviewUpdate<TMessage>(
|
|
|
411
448
|
state = deps.createPreviewState();
|
|
412
449
|
deps.setState(state);
|
|
413
450
|
}
|
|
451
|
+
if (state.sealed) return;
|
|
414
452
|
state.pendingText = stripTelegramCommentMarkupForPreview(
|
|
415
453
|
deps.getMessageText(message),
|
|
416
454
|
);
|
|
@@ -454,17 +492,20 @@ export function shouldUseTelegramDraftPreview(_options: {
|
|
|
454
492
|
export async function clearTelegramPreview(
|
|
455
493
|
chatId: number,
|
|
456
494
|
deps: TelegramPreviewRuntimeDeps,
|
|
457
|
-
options: { awaitFlush?: boolean; target?: TelegramTarget } = {},
|
|
495
|
+
options: { awaitFlush?: boolean; target?: TelegramTarget; isDeliveryActive?: () => boolean } = {},
|
|
458
496
|
): Promise<void> {
|
|
459
497
|
const state = deps.getState();
|
|
460
|
-
if (!state) return;
|
|
461
|
-
|
|
498
|
+
if (!state || options.isDeliveryActive?.() === false) return;
|
|
499
|
+
sealTelegramPreviewState(state);
|
|
500
|
+
const inFlight = state.flushPromise ?? state.precedingFlush;
|
|
501
|
+
if (inFlight && options.awaitFlush !== false) {
|
|
462
502
|
state.flushRequested = false;
|
|
463
|
-
await
|
|
503
|
+
await inFlight.catch(() => {});
|
|
464
504
|
if (deps.getState() !== state) return;
|
|
465
505
|
}
|
|
506
|
+
if (options.isDeliveryActive?.() === false) return;
|
|
466
507
|
deps.setState(undefined);
|
|
467
|
-
if (state.mode === "draft" && state.draftId !== undefined) {
|
|
508
|
+
if (state.mode === "draft" && state.draftId !== undefined && deps.canSend?.() !== false) {
|
|
468
509
|
try {
|
|
469
510
|
await deps.sendDraft(chatId, state.draftId, undefined, {
|
|
470
511
|
...getTelegramTargetThreadParams(options.target ?? { chatId }),
|
|
@@ -766,13 +807,15 @@ async function performTelegramPreviewFlush(
|
|
|
766
807
|
) {
|
|
767
808
|
const draftId = state.draftId ?? deps.allocateDraftId();
|
|
768
809
|
state.draftId = draftId;
|
|
810
|
+
state.nextDraftAt = Date.now() + (deps.minDraftIntervalMs ?? 0);
|
|
769
811
|
try {
|
|
770
|
-
await deps.sendDraft(
|
|
812
|
+
const delivered = await deps.sendDraft(
|
|
771
813
|
chatId,
|
|
772
814
|
draftId,
|
|
773
815
|
normalizeTelegramNativeMarkdown(snapshot.text),
|
|
774
816
|
{ ...getTelegramTargetThreadParams(options.target ?? { chatId }) },
|
|
775
817
|
);
|
|
818
|
+
if (delivered === false || deps.getState() !== state || deps.canSend?.() === false) return;
|
|
776
819
|
deps.setDraftSupport("supported");
|
|
777
820
|
state.mode = "draft";
|
|
778
821
|
state.lastSentText = snapshot.text;
|
|
@@ -794,15 +837,33 @@ export async function flushTelegramPreview(
|
|
|
794
837
|
options: { target?: TelegramTarget } = {},
|
|
795
838
|
): Promise<void> {
|
|
796
839
|
const state = deps.getState();
|
|
797
|
-
if (!state) return;
|
|
840
|
+
if (!state || state.sealed) return;
|
|
798
841
|
if (state.flushPromise) {
|
|
799
842
|
state.flushRequested = true;
|
|
800
843
|
await state.flushPromise;
|
|
801
844
|
return;
|
|
802
845
|
}
|
|
803
846
|
state.flushPromise = (async () => {
|
|
847
|
+
if (state.precedingFlush) {
|
|
848
|
+
await state.precedingFlush.catch(() => {});
|
|
849
|
+
state.precedingFlush = undefined;
|
|
850
|
+
if (deps.getState() !== state || state.sealed) return;
|
|
851
|
+
}
|
|
804
852
|
do {
|
|
805
853
|
state.flushRequested = false;
|
|
854
|
+
const delay = (state.nextDraftAt ?? 0) - Date.now();
|
|
855
|
+
if (delay > 0) {
|
|
856
|
+
if (!state.flushTimer) {
|
|
857
|
+
state.flushTimer = setTimeout(() => {
|
|
858
|
+
state.flushTimer = undefined;
|
|
859
|
+
if (deps.getState() === state && !state.sealed) void flushTelegramPreview(chatId, deps, options);
|
|
860
|
+
}, delay);
|
|
861
|
+
state.flushTimer.unref?.();
|
|
862
|
+
}
|
|
863
|
+
break;
|
|
864
|
+
}
|
|
865
|
+
if (state.flushTimer) clearTimeout(state.flushTimer);
|
|
866
|
+
state.flushTimer = undefined;
|
|
806
867
|
try {
|
|
807
868
|
await performTelegramPreviewFlush(chatId, state, deps, options);
|
|
808
869
|
} catch (error) {
|
|
@@ -813,7 +874,7 @@ export async function flushTelegramPreview(
|
|
|
813
874
|
});
|
|
814
875
|
break;
|
|
815
876
|
}
|
|
816
|
-
} while (deps.getState() === state && state.flushRequested);
|
|
877
|
+
} while (deps.getState() === state && !state.sealed && state.flushRequested);
|
|
817
878
|
})();
|
|
818
879
|
try {
|
|
819
880
|
await state.flushPromise;
|