@llblab/pi-kit 0.5.2 → 0.7.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 +5 -5
- package/node_modules/@llblab/pi-actors/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-actors/CHANGELOG.md +6 -0
- package/node_modules/@llblab/pi-actors/README.md +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.d.ts +3 -0
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.js +14 -1
- package/node_modules/@llblab/pi-actors/dist/lib/command-templates.js +45 -3
- package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.js +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/observability.d.ts +16 -3
- package/node_modules/@llblab/pi-actors/dist/lib/observability.js +92 -7
- package/node_modules/@llblab/pi-actors/dist/lib/pi.d.ts +0 -1
- package/node_modules/@llblab/pi-actors/dist/lib/pi.js +15 -24
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery-lineage.d.ts +17 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery-lineage.js +44 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.d.ts +4 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.js +102 -4
- package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.js +58 -39
- package/node_modules/@llblab/pi-actors/dist/lib/runtime.js +14 -6
- package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +1 -1
- package/node_modules/@llblab/pi-actors/docs/async-runs.md +1 -1
- package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +18 -23
- package/node_modules/@llblab/pi-actors/lib/async-runs.ts +18 -1
- package/node_modules/@llblab/pi-actors/lib/command-templates.ts +41 -3
- package/node_modules/@llblab/pi-actors/lib/extension-runtime.ts +1 -1
- package/node_modules/@llblab/pi-actors/lib/observability.ts +119 -5
- package/node_modules/@llblab/pi-actors/lib/pi.ts +15 -28
- package/node_modules/@llblab/pi-actors/lib/run-delivery-lineage.ts +68 -0
- package/node_modules/@llblab/pi-actors/lib/run-delivery.ts +120 -4
- package/node_modules/@llblab/pi-actors/lib/run-ui-runtime.ts +69 -44
- package/node_modules/@llblab/pi-actors/lib/runtime.ts +17 -6
- package/node_modules/@llblab/pi-actors/package.json +1 -1
- package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +1 -1
- 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-state-flow/AGENTS.md +33 -12
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +125 -2
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +87 -45
- package/node_modules/@llblab/pi-state-flow/README.md +203 -107
- package/node_modules/@llblab/pi-state-flow/docs/README.md +4 -0
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +188 -0
- package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +42 -0
- package/node_modules/@llblab/pi-state-flow/index.ts +164 -2
- package/node_modules/@llblab/pi-state-flow/lib/acquisition.ts +138 -0
- package/node_modules/@llblab/pi-state-flow/lib/artifact.ts +273 -0
- package/node_modules/@llblab/pi-state-flow/lib/config.ts +48 -0
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +18 -5
- package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +268 -0
- package/node_modules/@llblab/pi-state-flow/lib/discovery.ts +117 -0
- package/node_modules/@llblab/pi-state-flow/lib/durable.ts +562 -0
- package/node_modules/@llblab/pi-state-flow/lib/episode.ts +24 -12
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +606 -70
- package/node_modules/@llblab/pi-state-flow/lib/git.ts +666 -0
- package/node_modules/@llblab/pi-state-flow/lib/history.ts +95 -0
- package/node_modules/@llblab/pi-state-flow/lib/json.ts +24 -0
- package/node_modules/@llblab/pi-state-flow/lib/maintenance.ts +141 -0
- package/node_modules/@llblab/pi-state-flow/lib/memory.ts +52 -0
- package/node_modules/@llblab/pi-state-flow/lib/migration.ts +88 -0
- package/node_modules/@llblab/pi-state-flow/lib/publication.ts +296 -0
- package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +23 -7
- package/node_modules/@llblab/pi-state-flow/lib/rehydration.ts +79 -0
- package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +264 -0
- package/node_modules/@llblab/pi-state-flow/lib/session.ts +6 -0
- package/node_modules/@llblab/pi-state-flow/lib/skills.ts +99 -7
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +305 -48
- package/node_modules/@llblab/pi-state-flow/lib/state.ts +74 -7
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +125 -6
- package/node_modules/@llblab/pi-state-flow/lib/storage.ts +196 -0
- package/node_modules/@llblab/pi-state-flow/lib/temporal.ts +233 -0
- package/node_modules/@llblab/pi-state-flow/lib/terminal.ts +70 -24
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +254 -29
- package/node_modules/@llblab/pi-state-flow/package.json +8 -2
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +128 -0
- package/node_modules/@llblab/pi-telegram/AGENTS.md +14 -9
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +20 -4
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +22 -5
- package/node_modules/@llblab/pi-telegram/README.md +13 -9
- package/node_modules/@llblab/pi-telegram/docs/README.md +1 -0
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +220 -18
- package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +70 -19
- package/node_modules/@llblab/pi-telegram/docs/outbound.md +13 -7
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +13 -5
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +3 -1
- package/node_modules/@llblab/pi-telegram/index.ts +4 -1415
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +19 -5
- package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +6 -3
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +37 -2
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +600 -135
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +962 -55
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +350 -26
- package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +544 -0
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +234 -11
- package/node_modules/@llblab/pi-telegram/lib/config.ts +178 -25
- package/node_modules/@llblab/pi-telegram/lib/delivery.ts +18 -18
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +1792 -0
- package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +20 -2
- package/node_modules/@llblab/pi-telegram/lib/journal.ts +2184 -126
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +7 -1
- package/node_modules/@llblab/pi-telegram/lib/locks.ts +38 -1
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +154 -15
- package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +74 -40
- package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +28 -42
- package/node_modules/@llblab/pi-telegram/lib/outbound.ts +18 -14
- package/node_modules/@llblab/pi-telegram/lib/paths.ts +29 -0
- package/node_modules/@llblab/pi-telegram/lib/polling.ts +85 -17
- package/node_modules/@llblab/pi-telegram/lib/preview.ts +115 -70
- package/node_modules/@llblab/pi-telegram/lib/prompts.ts +5 -2
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +66 -22
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +47 -39
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +305 -112
- package/node_modules/@llblab/pi-telegram/lib/status.ts +10 -0
- package/node_modules/@llblab/pi-telegram/lib/sync.ts +308 -39
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +315 -7
- package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +664 -0
- package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +226 -0
- package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +118 -0
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +1686 -129
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +1319 -97
- package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +1643 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +968 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-slots.ts +84 -0
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/screenshot.png +0 -0
- package/node_modules/@llblab/pi-telegram/scripts/measure-bus.mjs +83 -0
- package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +101 -0
- package/node_modules/@llblab/{skills → pi-telegram/skills}/show-me/SKILL.md +28 -6
- package/node_modules/@llblab/pi-telegram/skills/show-me/references/telegram-surfaces.md +43 -0
- package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/delivery-and-threads.md +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 +2 -3
- package/node_modules/@llblab/skills/release-flow/SKILL.md +2 -4
- package/package.json +7 -6
|
@@ -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,8 @@ export interface TelegramPreviewControllerDeps {
|
|
|
140
135
|
}
|
|
141
136
|
|
|
142
137
|
export interface TelegramPreviewController {
|
|
138
|
+
seal: () => void;
|
|
139
|
+
preparePublication: () => TelegramAssistantOutputPreparation | undefined;
|
|
143
140
|
prepareClear: (
|
|
144
141
|
chatId: number,
|
|
145
142
|
options?: { target?: TelegramTarget; isDeliveryActive?: () => boolean },
|
|
@@ -201,11 +198,18 @@ export interface TelegramAssistantPreviewRuntimeDeps<
|
|
|
201
198
|
) => Promise<number | undefined>;
|
|
202
199
|
}
|
|
203
200
|
|
|
201
|
+
export interface TelegramPreparedPreviewDelivery<TReplyMarkup = unknown> {
|
|
202
|
+
clearPreview: TelegramPreviewController["clear"];
|
|
203
|
+
setPreviewPendingText: TelegramPreviewController["setPendingText"];
|
|
204
|
+
finalizeMarkdownPreview: ReturnType<typeof createTelegramNativeMarkdownPreviewFinalizer<TReplyMarkup>>;
|
|
205
|
+
}
|
|
206
|
+
|
|
204
207
|
export type TelegramAssistantPreviewRuntime<
|
|
205
208
|
TMessage,
|
|
206
209
|
TReplyMarkup = TelegramPreviewReplyMarkup,
|
|
207
210
|
> = TelegramPreviewController &
|
|
208
211
|
TelegramAssistantMessagePreviewHooks<TMessage> & {
|
|
212
|
+
prepareDelivery: (isDeliveryActive: () => boolean) => TelegramPreparedPreviewDelivery<TReplyMarkup>;
|
|
209
213
|
finalizeMarkdown: (
|
|
210
214
|
chatId: number,
|
|
211
215
|
markdown: string,
|
|
@@ -214,6 +218,14 @@ export type TelegramAssistantPreviewRuntime<
|
|
|
214
218
|
) => Promise<boolean>;
|
|
215
219
|
};
|
|
216
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
|
+
|
|
217
229
|
export function createTelegramNativeMarkdownPreviewFinalizer<
|
|
218
230
|
TReplyMarkup,
|
|
219
231
|
>(deps: {
|
|
@@ -223,6 +235,7 @@ export function createTelegramNativeMarkdownPreviewFinalizer<
|
|
|
223
235
|
options?: { awaitFlush?: boolean; target?: TelegramTarget },
|
|
224
236
|
) => Promise<void>;
|
|
225
237
|
discard?: () => void;
|
|
238
|
+
isDeliveryActive?: () => boolean;
|
|
226
239
|
sendMarkdownReply: (
|
|
227
240
|
chatId: number,
|
|
228
241
|
replyToMessageId: number | undefined,
|
|
@@ -235,14 +248,21 @@ export function createTelegramNativeMarkdownPreviewFinalizer<
|
|
|
235
248
|
replyToMessageId?: number,
|
|
236
249
|
options?: { replyMarkup?: TReplyMarkup; target?: TelegramTarget },
|
|
237
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;
|
|
238
260
|
return async (chatId, markdown, replyToMessageId, options) => {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if (deps.getState() !== state) return false;
|
|
243
|
-
}
|
|
261
|
+
if (deps.isDeliveryActive?.() === false) return false;
|
|
262
|
+
await inFlight?.catch(() => {});
|
|
263
|
+
if (deps.getState() !== state || deps.isDeliveryActive?.() === false) return false;
|
|
244
264
|
await deps.sendMarkdownReply(chatId, replyToMessageId, markdown, options);
|
|
245
|
-
if (deps.getState() === state) deps.discard?.();
|
|
265
|
+
if (deps.getState() === state && deps.isDeliveryActive?.() !== false) deps.discard?.();
|
|
246
266
|
return true;
|
|
247
267
|
};
|
|
248
268
|
}
|
|
@@ -254,15 +274,28 @@ export function createTelegramAssistantPreviewRuntime<
|
|
|
254
274
|
deps: TelegramAssistantPreviewRuntimeDeps<TMessage, TReplyMarkup>,
|
|
255
275
|
): TelegramAssistantPreviewRuntime<TMessage, TReplyMarkup> {
|
|
256
276
|
const controller = createTelegramPreviewControllerRuntime(deps);
|
|
257
|
-
const
|
|
277
|
+
const finalizerDeps = {
|
|
258
278
|
getState: controller.getState,
|
|
259
279
|
clear: controller.clear,
|
|
260
280
|
discard: () => controller.setState(undefined),
|
|
261
281
|
sendMarkdownReply: deps.sendMarkdownReply,
|
|
262
|
-
}
|
|
282
|
+
};
|
|
263
283
|
return {
|
|
264
284
|
...controller,
|
|
265
|
-
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
|
+
},
|
|
266
299
|
...createTelegramAssistantMessagePreviewHooks({
|
|
267
300
|
getActiveTurn: deps.getActiveTurn,
|
|
268
301
|
isAssistantMessage: deps.isAssistantMessage,
|
|
@@ -270,8 +303,6 @@ export function createTelegramAssistantPreviewRuntime<
|
|
|
270
303
|
setState: controller.setState,
|
|
271
304
|
createPreviewState: controller.createState,
|
|
272
305
|
canSend: deps.canSend,
|
|
273
|
-
finalizePreview: controller.finalize,
|
|
274
|
-
finalizeMarkdownPreview,
|
|
275
306
|
getMessageText: deps.getMessageText,
|
|
276
307
|
schedulePreviewFlush: controller.scheduleFlush,
|
|
277
308
|
}),
|
|
@@ -288,14 +319,17 @@ export function createTelegramPreviewController(
|
|
|
288
319
|
deps.maxMessageLength ?? TELEGRAM_DRAFT_PREVIEW_MAX_CHARS;
|
|
289
320
|
let draftSupport = deps.initialDraftSupport ?? "unknown";
|
|
290
321
|
let nextDraftId = 0;
|
|
322
|
+
const setState = (nextState: TelegramPreviewRuntimeState | undefined): void => {
|
|
323
|
+
if (state !== nextState) sealTelegramPreviewState(state);
|
|
324
|
+
state = nextState;
|
|
325
|
+
};
|
|
291
326
|
const getRuntimeDeps = (
|
|
292
327
|
operationGeneration = generation,
|
|
293
328
|
): TelegramPreviewRuntimeDeps => ({
|
|
294
329
|
getState: () => state,
|
|
295
|
-
setState
|
|
296
|
-
state = nextState;
|
|
297
|
-
},
|
|
330
|
+
setState,
|
|
298
331
|
maxMessageLength,
|
|
332
|
+
minDraftIntervalMs: TELEGRAM_DRAFT_INTERVAL_MS,
|
|
299
333
|
getDraftSupport: () => draftSupport,
|
|
300
334
|
setDraftSupport: (support) => {
|
|
301
335
|
draftSupport = support;
|
|
@@ -311,20 +345,27 @@ export function createTelegramPreviewController(
|
|
|
311
345
|
});
|
|
312
346
|
return {
|
|
313
347
|
getState: () => state,
|
|
314
|
-
setState
|
|
315
|
-
state = nextState;
|
|
316
|
-
},
|
|
348
|
+
setState,
|
|
317
349
|
setPendingText: (text) => {
|
|
318
350
|
if (state) state.pendingText = text;
|
|
319
351
|
},
|
|
320
352
|
createState: () => createTelegramPreviewRuntimeState(),
|
|
321
353
|
resetState: () => {
|
|
322
354
|
generation += 1;
|
|
323
|
-
|
|
355
|
+
setState({ ...createTelegramPreviewRuntimeState(), nextDraftAt: state?.nextDraftAt });
|
|
324
356
|
},
|
|
325
357
|
invalidate: () => {
|
|
326
358
|
generation += 1;
|
|
327
|
-
|
|
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 };
|
|
328
369
|
},
|
|
329
370
|
prepareClear: (chatId, options) => {
|
|
330
371
|
const admittedState = state;
|
|
@@ -350,11 +391,8 @@ export function createTelegramPreviewController(
|
|
|
350
391
|
};
|
|
351
392
|
}
|
|
352
393
|
|
|
353
|
-
export function createTelegramAssistantMessagePreviewHooks<
|
|
354
|
-
TMessage
|
|
355
|
-
TReplyMarkup = TelegramPreviewReplyMarkup,
|
|
356
|
-
>(
|
|
357
|
-
deps: TelegramAssistantMessagePreviewHookDeps<TMessage, TReplyMarkup>,
|
|
394
|
+
export function createTelegramAssistantMessagePreviewHooks<TMessage>(
|
|
395
|
+
deps: TelegramAssistantMessagePreviewHookDeps<TMessage>,
|
|
358
396
|
): TelegramAssistantMessagePreviewHooks<TMessage> {
|
|
359
397
|
return {
|
|
360
398
|
onMessageStart: async (
|
|
@@ -370,12 +408,9 @@ export function createTelegramAssistantMessagePreviewHooks<
|
|
|
370
408
|
};
|
|
371
409
|
}
|
|
372
410
|
|
|
373
|
-
export async function handleTelegramAssistantMessagePreviewStart<
|
|
374
|
-
TMessage,
|
|
375
|
-
TReplyMarkup = TelegramPreviewReplyMarkup,
|
|
376
|
-
>(
|
|
411
|
+
export async function handleTelegramAssistantMessagePreviewStart<TMessage>(
|
|
377
412
|
message: TMessage,
|
|
378
|
-
deps: TelegramAssistantMessagePreviewStartDeps<TMessage
|
|
413
|
+
deps: TelegramAssistantMessagePreviewStartDeps<TMessage>,
|
|
379
414
|
): Promise<void> {
|
|
380
415
|
const turn = deps.getActiveTurn();
|
|
381
416
|
if (!turn || !deps.isAssistantMessage(message)) return;
|
|
@@ -388,26 +423,13 @@ export async function handleTelegramAssistantMessagePreviewStart<
|
|
|
388
423
|
return;
|
|
389
424
|
}
|
|
390
425
|
const state = deps.getState();
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
await deps.finalizeMarkdownPreview(
|
|
399
|
-
turn.chatId,
|
|
400
|
-
previousText,
|
|
401
|
-
turn.replyToMessageId,
|
|
402
|
-
{
|
|
403
|
-
target: turn.target,
|
|
404
|
-
},
|
|
405
|
-
);
|
|
406
|
-
} else {
|
|
407
|
-
await deps.finalizePreview(turn.chatId);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
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);
|
|
411
433
|
}
|
|
412
434
|
|
|
413
435
|
export async function handleTelegramAssistantMessagePreviewUpdate<TMessage>(
|
|
@@ -426,6 +448,7 @@ export async function handleTelegramAssistantMessagePreviewUpdate<TMessage>(
|
|
|
426
448
|
state = deps.createPreviewState();
|
|
427
449
|
deps.setState(state);
|
|
428
450
|
}
|
|
451
|
+
if (state.sealed) return;
|
|
429
452
|
state.pendingText = stripTelegramCommentMarkupForPreview(
|
|
430
453
|
deps.getMessageText(message),
|
|
431
454
|
);
|
|
@@ -473,9 +496,11 @@ export async function clearTelegramPreview(
|
|
|
473
496
|
): Promise<void> {
|
|
474
497
|
const state = deps.getState();
|
|
475
498
|
if (!state || options.isDeliveryActive?.() === false) return;
|
|
476
|
-
|
|
499
|
+
sealTelegramPreviewState(state);
|
|
500
|
+
const inFlight = state.flushPromise ?? state.precedingFlush;
|
|
501
|
+
if (inFlight && options.awaitFlush !== false) {
|
|
477
502
|
state.flushRequested = false;
|
|
478
|
-
await
|
|
503
|
+
await inFlight.catch(() => {});
|
|
479
504
|
if (deps.getState() !== state) return;
|
|
480
505
|
}
|
|
481
506
|
if (options.isDeliveryActive?.() === false) return;
|
|
@@ -782,13 +807,15 @@ async function performTelegramPreviewFlush(
|
|
|
782
807
|
) {
|
|
783
808
|
const draftId = state.draftId ?? deps.allocateDraftId();
|
|
784
809
|
state.draftId = draftId;
|
|
810
|
+
state.nextDraftAt = Date.now() + (deps.minDraftIntervalMs ?? 0);
|
|
785
811
|
try {
|
|
786
|
-
await deps.sendDraft(
|
|
812
|
+
const delivered = await deps.sendDraft(
|
|
787
813
|
chatId,
|
|
788
814
|
draftId,
|
|
789
815
|
normalizeTelegramNativeMarkdown(snapshot.text),
|
|
790
816
|
{ ...getTelegramTargetThreadParams(options.target ?? { chatId }) },
|
|
791
817
|
);
|
|
818
|
+
if (delivered === false || deps.getState() !== state || deps.canSend?.() === false) return;
|
|
792
819
|
deps.setDraftSupport("supported");
|
|
793
820
|
state.mode = "draft";
|
|
794
821
|
state.lastSentText = snapshot.text;
|
|
@@ -810,15 +837,33 @@ export async function flushTelegramPreview(
|
|
|
810
837
|
options: { target?: TelegramTarget } = {},
|
|
811
838
|
): Promise<void> {
|
|
812
839
|
const state = deps.getState();
|
|
813
|
-
if (!state) return;
|
|
840
|
+
if (!state || state.sealed) return;
|
|
814
841
|
if (state.flushPromise) {
|
|
815
842
|
state.flushRequested = true;
|
|
816
843
|
await state.flushPromise;
|
|
817
844
|
return;
|
|
818
845
|
}
|
|
819
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
|
+
}
|
|
820
852
|
do {
|
|
821
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;
|
|
822
867
|
try {
|
|
823
868
|
await performTelegramPreviewFlush(chatId, state, deps, options);
|
|
824
869
|
} catch (error) {
|
|
@@ -829,7 +874,7 @@ export async function flushTelegramPreview(
|
|
|
829
874
|
});
|
|
830
875
|
break;
|
|
831
876
|
}
|
|
832
|
-
} while (deps.getState() === state && state.flushRequested);
|
|
877
|
+
} while (deps.getState() === state && !state.sealed && state.flushRequested);
|
|
833
878
|
})();
|
|
834
879
|
try {
|
|
835
880
|
await state.flushPromise;
|
|
@@ -14,7 +14,7 @@ export const TELEGRAM_DISCONNECTED_CONTEXT_MESSAGE =
|
|
|
14
14
|
|
|
15
15
|
const LOCAL_SYSTEM_PROMPT_SUFFIX = `
|
|
16
16
|
|
|
17
|
-
${TELEGRAM_CONNECTED_CONTEXT_MESSAGE} For Telegram work, consult bundled Skills in routing order: \`telegram-bridge\` for the transport and turn protocol, \`generated-control-surface\` when contextual controls materially shorten feedback, then \`generative-apps\` when the interaction warrants a reusable deterministic app. Load a Skill only if its instructions are not already present in the current context. Do not use Telegram-specific features from unrelated local/TUI prompts.`;
|
|
17
|
+
${TELEGRAM_CONNECTED_CONTEXT_MESSAGE} For Telegram work, consult bundled Skills in routing order: \`telegram-bridge\` for the transport and turn protocol, \`show-me\` when a user needs a truthful visual explanation of work or behavior, \`generated-control-surface\` when contextual controls materially shorten feedback, then \`generative-apps\` when the interaction warrants a reusable deterministic app. Load a Skill only if its instructions are not already present in the current context. Do not use Telegram-specific features from unrelated local/TUI prompts.`;
|
|
18
18
|
|
|
19
19
|
const TELEGRAM_TURN_SYSTEM_PROMPT_SUFFIX = `
|
|
20
20
|
|
|
@@ -28,9 +28,10 @@ export const TELEGRAM_ATTACH_PROMPT_GUIDELINES = [
|
|
|
28
28
|
"For an explicit thread target, provide chat_id plus thread_id; registered multi-instance followers default to their assigned thread target.",
|
|
29
29
|
] as const;
|
|
30
30
|
export const TELEGRAM_MESSAGE_PROMPT_SNIPPET =
|
|
31
|
-
"Send direct Telegram Markdown text when the user explicitly asks for Telegram delivery outside the normal reply flow.";
|
|
31
|
+
"Send direct Telegram Markdown text when the user explicitly asks for Telegram delivery to a concrete chat, channel, or live Pi Thread outside the normal reply flow.";
|
|
32
32
|
export const TELEGRAM_MESSAGE_PROMPT_GUIDELINES = [
|
|
33
33
|
"Use telegram_message only when the user explicitly asks to send a message to Telegram from the local/TUI side, or names a concrete Telegram delivery target.",
|
|
34
|
+
"For an explicitly requested channel post, pass its exact numeric id or public @username as chat_id; no local channel registry is required, and Telegram remains the authority on the bot's posting permission.",
|
|
34
35
|
"For a live Pi thread target, provide thread as its case-insensitive name or numeric id; the bridge sends visibly and admits one attributed turn to that live instance. Unknown, ambiguous, same, or offline targets fail before sending.",
|
|
35
36
|
"Add buttons by embedding the same top-level telegram_button HTML comments used in normal Telegram replies; Telegram does not support standalone buttons.",
|
|
36
37
|
"During an active Telegram turn, omit telegram_message for the current target and answer normally; use thread only when the user requests delivery to a different live Pi thread.",
|
|
@@ -48,6 +49,8 @@ const TELEGRAM_TOOL_METADATA_LINES = Object.fromEntries(
|
|
|
48
49
|
const TELEGRAM_MODEL_CONTEXT_TOOL_NAMES = new Set([
|
|
49
50
|
"telegram_attach",
|
|
50
51
|
"telegram_bind",
|
|
52
|
+
"telegram_channel_post",
|
|
53
|
+
"telegram_channel_posts",
|
|
51
54
|
"telegram_message",
|
|
52
55
|
]);
|
|
53
56
|
const TELEGRAM_MODEL_CONTEXT_MEMORY_KEY = Symbol.for(
|
|
@@ -1498,6 +1498,10 @@ export interface TelegramAgentEndRuntimeDeps<
|
|
|
1498
1498
|
updateStatus: () => void;
|
|
1499
1499
|
dispatchNextQueuedTelegramTurn: () => void;
|
|
1500
1500
|
scheduleActiveTurnDelivery?: (task: () => Promise<void>) => void;
|
|
1501
|
+
preparePreviewDelivery?: (isDeliveryActive: () => boolean) => Pick<
|
|
1502
|
+
TelegramAgentEndRuntimeDeps<TTurn, TReplyMarkup>,
|
|
1503
|
+
"clearPreview" | "setPreviewPendingText" | "finalizeMarkdownPreview"
|
|
1504
|
+
> | undefined;
|
|
1501
1505
|
preparePreviewClear?: (
|
|
1502
1506
|
chatId: number,
|
|
1503
1507
|
options?: { target?: TelegramQueueTarget; isDeliveryActive?: () => boolean },
|
|
@@ -1523,7 +1527,7 @@ export interface TelegramAgentEndRuntimeDeps<
|
|
|
1523
1527
|
chatId: number,
|
|
1524
1528
|
replyToMessageId: number,
|
|
1525
1529
|
text: string,
|
|
1526
|
-
options?: { target?: TelegramQueueTarget },
|
|
1530
|
+
options?: { target?: TelegramQueueTarget; parseMode?: "HTML" },
|
|
1527
1531
|
) => Promise<unknown>;
|
|
1528
1532
|
sendQueuedAttachments: (
|
|
1529
1533
|
turn: TTurn,
|
|
@@ -1595,6 +1599,7 @@ export interface TelegramAgentEndHookRuntimeDeps<
|
|
|
1595
1599
|
schedule: (task: () => Promise<void>) => void;
|
|
1596
1600
|
cancel: () => void;
|
|
1597
1601
|
};
|
|
1602
|
+
preparePreviewDelivery?: TelegramAgentEndRuntimeDeps<TTurn, TReplyMarkup>["preparePreviewDelivery"];
|
|
1598
1603
|
preparePreviewClear?: TelegramAgentEndRuntimeDeps<TTurn, TReplyMarkup>["preparePreviewClear"];
|
|
1599
1604
|
clearPreview: TelegramAgentEndRuntimeDeps<
|
|
1600
1605
|
TTurn,
|
|
@@ -1746,6 +1751,7 @@ export function createTelegramAgentEndHook<
|
|
|
1746
1751
|
await task();
|
|
1747
1752
|
})
|
|
1748
1753
|
: undefined,
|
|
1754
|
+
preparePreviewDelivery: deps.preparePreviewDelivery,
|
|
1749
1755
|
preparePreviewClear: deps.preparePreviewClear,
|
|
1750
1756
|
clearPreview: deps.clearPreview,
|
|
1751
1757
|
setPreviewPendingText: deps.setPreviewPendingText,
|
|
@@ -1807,9 +1813,13 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
1807
1813
|
const isDeliveryActive = (): boolean =>
|
|
1808
1814
|
deps.isSessionActive?.() !== false &&
|
|
1809
1815
|
(!turn || deps.isTurnTransportActive?.(turn) !== false);
|
|
1816
|
+
const preview = turn && !turn.guestQueryId ? deps.preparePreviewDelivery?.(isDeliveryActive) : undefined;
|
|
1817
|
+
const setPreviewPendingText = preview?.setPreviewPendingText ?? deps.setPreviewPendingText;
|
|
1818
|
+
const finalizeMarkdownPreview = preview?.finalizeMarkdownPreview ?? deps.finalizeMarkdownPreview;
|
|
1810
1819
|
const clearPreview = turn
|
|
1811
|
-
?
|
|
1812
|
-
|
|
1820
|
+
? preview ? () => preview.clearPreview(turn.chatId, { target: turn.target })
|
|
1821
|
+
: deps.preparePreviewClear?.(turn.chatId, { target: turn.target, isDeliveryActive })
|
|
1822
|
+
?? (() => deps.clearPreview(turn.chatId, { target: turn.target }))
|
|
1813
1823
|
: undefined;
|
|
1814
1824
|
const updateStatusIgnoringStaleContext = (): void => {
|
|
1815
1825
|
try {
|
|
@@ -1898,23 +1908,37 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
1898
1908
|
const deliverActiveTurn = async () => {
|
|
1899
1909
|
await deps.waitForActivityIdle?.();
|
|
1900
1910
|
if (!isDeliveryActive()) return;
|
|
1901
|
-
|
|
1911
|
+
let previewCleared = false;
|
|
1912
|
+
const clearTurnPreview = async () => {
|
|
1913
|
+
if (previewCleared) return;
|
|
1902
1914
|
await clearPreview?.();
|
|
1915
|
+
previewCleared = true;
|
|
1916
|
+
};
|
|
1917
|
+
if (endPlan.shouldClearPreview || (!finalText && hasOutboundArtifacts)) {
|
|
1918
|
+
await clearTurnPreview();
|
|
1903
1919
|
if (!isDeliveryActive()) return;
|
|
1904
1920
|
}
|
|
1905
1921
|
if (endPlan.shouldSendErrorMessage) {
|
|
1922
|
+
const errorMessage = assistant.errorMessage ||
|
|
1923
|
+
"Telegram bridge: Pi failed while processing the request.";
|
|
1924
|
+
const isOperationAborted = errorMessage.trim().replace(/\.$/, "") ===
|
|
1925
|
+
"This operation was aborted";
|
|
1906
1926
|
await deps.sendTextReply(
|
|
1907
1927
|
turn.chatId,
|
|
1908
1928
|
turn.replyToMessageId,
|
|
1909
|
-
|
|
1910
|
-
"
|
|
1911
|
-
|
|
1929
|
+
isOperationAborted
|
|
1930
|
+
? "<b>⏹️ This operation was aborted.</b>"
|
|
1931
|
+
: errorMessage,
|
|
1932
|
+
{
|
|
1933
|
+
target: turn.target,
|
|
1934
|
+
...(isOperationAborted ? { parseMode: "HTML" as const } : {}),
|
|
1935
|
+
},
|
|
1912
1936
|
);
|
|
1913
1937
|
if (!isDeliveryActive()) return;
|
|
1914
1938
|
if (endPlan.shouldDispatchNext) deps.dispatchNextQueuedTelegramTurn();
|
|
1915
1939
|
return;
|
|
1916
1940
|
}
|
|
1917
|
-
if (finalText)
|
|
1941
|
+
if (finalText && turn.queuedAttachments.length === 0) setPreviewPendingText(finalText);
|
|
1918
1942
|
|
|
1919
1943
|
if (!isDeliveryActive()) return;
|
|
1920
1944
|
let richAttachmentDelivered = false;
|
|
@@ -1932,9 +1956,9 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
1932
1956
|
);
|
|
1933
1957
|
if (!isDeliveryActive()) return;
|
|
1934
1958
|
if (richAttachmentDelivered) {
|
|
1935
|
-
await
|
|
1959
|
+
await clearTurnPreview();
|
|
1936
1960
|
if (!isDeliveryActive()) return;
|
|
1937
|
-
|
|
1961
|
+
setPreviewPendingText("");
|
|
1938
1962
|
}
|
|
1939
1963
|
} catch (error) {
|
|
1940
1964
|
if (!isDeliveryActive()) return;
|
|
@@ -1947,27 +1971,45 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
1947
1971
|
}
|
|
1948
1972
|
}
|
|
1949
1973
|
if (!isDeliveryActive()) return;
|
|
1974
|
+
let queuedAttachmentsDelivered = false;
|
|
1975
|
+
if (!richAttachmentDelivered && turn.queuedAttachments.length > 0) {
|
|
1976
|
+
await clearTurnPreview();
|
|
1977
|
+
if (!isDeliveryActive()) return;
|
|
1978
|
+
setPreviewPendingText("");
|
|
1979
|
+
await deps.sendQueuedAttachments(turn, { isDeliveryActive });
|
|
1980
|
+
if (!isDeliveryActive()) return;
|
|
1981
|
+
queuedAttachmentsDelivered = true;
|
|
1982
|
+
}
|
|
1950
1983
|
if (!richAttachmentDelivered && endPlan.kind === "text" && finalText) {
|
|
1951
1984
|
try {
|
|
1952
|
-
|
|
1953
|
-
turn.chatId,
|
|
1954
|
-
finalText,
|
|
1955
|
-
turn.replyToMessageId,
|
|
1956
|
-
{ replyMarkup, target: turn.target },
|
|
1957
|
-
);
|
|
1958
|
-
if (!isDeliveryActive()) return;
|
|
1959
|
-
if (!finalized) {
|
|
1960
|
-
await deps.clearPreview(turn.chatId, { target: turn.target });
|
|
1961
|
-
if (!isDeliveryActive()) return;
|
|
1985
|
+
if (queuedAttachmentsDelivered) {
|
|
1962
1986
|
await deps.sendMarkdownReply(
|
|
1963
1987
|
turn.chatId,
|
|
1964
1988
|
turn.replyToMessageId,
|
|
1965
1989
|
finalText,
|
|
1966
1990
|
{ replyMarkup, target: turn.target },
|
|
1967
1991
|
);
|
|
1992
|
+
} else {
|
|
1993
|
+
const finalized = await finalizeMarkdownPreview(
|
|
1994
|
+
turn.chatId,
|
|
1995
|
+
finalText,
|
|
1996
|
+
turn.replyToMessageId,
|
|
1997
|
+
{ replyMarkup, target: turn.target },
|
|
1998
|
+
);
|
|
1999
|
+
if (!isDeliveryActive()) return;
|
|
2000
|
+
if (!finalized) {
|
|
2001
|
+
await clearTurnPreview();
|
|
2002
|
+
if (!isDeliveryActive()) return;
|
|
2003
|
+
await deps.sendMarkdownReply(
|
|
2004
|
+
turn.chatId,
|
|
2005
|
+
turn.replyToMessageId,
|
|
2006
|
+
finalText,
|
|
2007
|
+
{ replyMarkup, target: turn.target },
|
|
2008
|
+
);
|
|
2009
|
+
}
|
|
1968
2010
|
}
|
|
1969
2011
|
if (!isDeliveryActive()) return;
|
|
1970
|
-
|
|
2012
|
+
setPreviewPendingText("");
|
|
1971
2013
|
} catch (error) {
|
|
1972
2014
|
deps.recordRuntimeEvent?.("delivery", error, {
|
|
1973
2015
|
phase: "final-text",
|
|
@@ -2031,7 +2073,9 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
2031
2073
|
);
|
|
2032
2074
|
}
|
|
2033
2075
|
if (!isDeliveryActive()) return;
|
|
2034
|
-
if (!richAttachmentDelivered
|
|
2076
|
+
if (!richAttachmentDelivered && !queuedAttachmentsDelivered) {
|
|
2077
|
+
await deps.sendQueuedAttachments(turn, { isDeliveryActive });
|
|
2078
|
+
}
|
|
2035
2079
|
if (!isDeliveryActive()) return;
|
|
2036
2080
|
if (endPlan.shouldDispatchNext) deps.dispatchNextQueuedTelegramTurn();
|
|
2037
2081
|
};
|