@llblab/pi-kit 0.27.6 → 0.28.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/BACKLOG.md +2 -5
- package/CHANGELOG.md +5 -0
- package/README.md +2 -2
- package/node_modules/@llblab/pi-telegram/AGENTS.md +10 -8
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -9
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +13 -0
- package/node_modules/@llblab/pi-telegram/LICENSE +21 -0
- package/node_modules/@llblab/pi-telegram/README.md +15 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +1 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +5 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +5 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +6 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +4 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +54 -56
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +206 -139
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +21 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +181 -25
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.d.ts +4 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +28 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +52 -56
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +78 -246
- package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +1 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +23 -26
- package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +0 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +5 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +0 -23
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +15 -15
- package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +0 -17
- package/node_modules/@llblab/pi-telegram/dist/lib/config.js +12 -14
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +0 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +2 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +255 -61
- package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +0 -19
- package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +0 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +177 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +1115 -249
- package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.d.ts +0 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.js +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +100 -12
- package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +380 -14
- package/node_modules/@llblab/pi-telegram/dist/lib/logging.d.ts +30 -12
- package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +129 -72
- package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +28 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/media.js +26 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +0 -11
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +8 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +0 -18
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +18 -18
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +4 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +12 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +4 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +0 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +1 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +1 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +4 -21
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +0 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +5 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +50 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +155 -17
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +2 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +0 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +5 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/preview.d.ts +0 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +3 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.d.ts +0 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +3 -15
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +69 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +29 -9
- package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +104 -33
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +0 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +73 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +2206 -307
- package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +0 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +44 -9
- package/node_modules/@llblab/pi-telegram/dist/lib/status.js +149 -27
- package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +0 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +5 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +11 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +34 -23
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +18 -21
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +32 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +191 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +291 -59
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +1647 -369
- package/node_modules/@llblab/pi-telegram/dist/lib/turns.d.ts +0 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +184 -28
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +1032 -114
- package/node_modules/@llblab/pi-telegram/dist/lib/wire.d.ts +12 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/wire.js +21 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +25 -17
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +95 -20
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.d.ts +20 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.js +103 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +43 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +148 -52
- package/node_modules/@llblab/pi-telegram/dist/package.json +6 -6
- package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/SKILL.md +3 -3
- package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/diagnosis.md +3 -3
- package/node_modules/@llblab/pi-telegram/docs/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/activity.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +152 -34
- package/node_modules/@llblab/pi-telegram/docs/callback-namespaces.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/delivery.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/inbound.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +125 -19
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +3 -1
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +22 -8
- package/node_modules/@llblab/pi-telegram/docs/updates.md +1 -1
- package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +5 -9
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +6 -0
- package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +5 -2
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +243 -224
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +178 -31
- package/node_modules/@llblab/pi-telegram/lib/bus-transport.ts +30 -8
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +110 -334
- package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +29 -29
- package/node_modules/@llblab/pi-telegram/lib/command-templates.ts +5 -5
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +15 -15
- package/node_modules/@llblab/pi-telegram/lib/config.ts +12 -17
- package/node_modules/@llblab/pi-telegram/lib/delivery.ts +2 -8
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +257 -72
- package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +0 -22
- package/node_modules/@llblab/pi-telegram/lib/inbound.ts +2 -2
- package/node_modules/@llblab/pi-telegram/lib/journal.ts +1182 -326
- package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +2 -2
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/locks.ts +402 -23
- package/node_modules/@llblab/pi-telegram/lib/logging.ts +151 -101
- package/node_modules/@llblab/pi-telegram/lib/media.ts +51 -9
- package/node_modules/@llblab/pi-telegram/lib/menu-model.ts +8 -8
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +18 -18
- package/node_modules/@llblab/pi-telegram/lib/menu-status.ts +11 -0
- package/node_modules/@llblab/pi-telegram/lib/menu-thinking.ts +2 -2
- package/node_modules/@llblab/pi-telegram/lib/menu.ts +5 -1
- package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +1 -10
- package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +5 -24
- package/node_modules/@llblab/pi-telegram/lib/outbound.ts +5 -5
- package/node_modules/@llblab/pi-telegram/lib/paths.ts +177 -17
- package/node_modules/@llblab/pi-telegram/lib/pi.ts +5 -2
- package/node_modules/@llblab/pi-telegram/lib/polling.ts +5 -5
- package/node_modules/@llblab/pi-telegram/lib/preview.ts +3 -3
- package/node_modules/@llblab/pi-telegram/lib/prompt-templates.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +67 -9
- package/node_modules/@llblab/pi-telegram/lib/recovery.ts +104 -44
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +1955 -375
- package/node_modules/@llblab/pi-telegram/lib/sections.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/status.ts +156 -36
- package/node_modules/@llblab/pi-telegram/lib/sync.ts +4 -4
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +48 -33
- package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +24 -21
- package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +267 -9
- package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +3 -1
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +1697 -488
- package/node_modules/@llblab/pi-telegram/lib/turns.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +1072 -151
- package/node_modules/@llblab/pi-telegram/lib/wire.ts +28 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +97 -47
- package/node_modules/@llblab/pi-telegram/lib/workspace-identity.ts +147 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +188 -89
- package/node_modules/@llblab/pi-telegram/package.json +6 -6
- package/node_modules/@llblab/pi-telegram/scripts/audit-exports.mjs +100 -0
- package/node_modules/@llblab/pi-telegram/scripts/check-downgrade.mjs +80 -43
- package/node_modules/@llblab/pi-telegram/skills/generated-control-surface/SKILL.md +3 -3
- package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/diagnosis.md +3 -3
- package/package.json +2 -2
|
@@ -26,7 +26,7 @@ const TELEGRAM_GET_UPDATES_CONFLICT_FAST_RETRY_LIMIT = 3;
|
|
|
26
26
|
const TELEGRAM_GET_UPDATES_CONFLICT_FAST_RETRY_MS = 1_000;
|
|
27
27
|
const TELEGRAM_GET_UPDATES_CONFLICT_SLOW_RETRY_MS = 3_000;
|
|
28
28
|
const TELEGRAM_POLLING_RETRY_MS = 3_000;
|
|
29
|
-
|
|
29
|
+
const TELEGRAM_GET_UPDATES_GRACE_MS = 10_000;
|
|
30
30
|
|
|
31
31
|
// Standard Telegram DM polling does not expose ordinary message-deletion events.
|
|
32
32
|
// Business deletions belong to a separate namespace and default routing ignores them.
|
|
@@ -163,7 +163,7 @@ export function createTelegramPollingControllerState(): TelegramPollingControlle
|
|
|
163
163
|
};
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
function getTelegramPollingStateSnapshot(
|
|
167
167
|
state: TelegramPollingControllerState,
|
|
168
168
|
): TelegramPollingStateSnapshot {
|
|
169
169
|
return {
|
|
@@ -906,7 +906,7 @@ export function createTelegramThreadCapabilityOrchestration<TContext, TOwner>(
|
|
|
906
906
|
};
|
|
907
907
|
}
|
|
908
908
|
|
|
909
|
-
|
|
909
|
+
async function readTelegramThreadCapability(
|
|
910
910
|
deps: TelegramThreadCapabilityReaderDeps,
|
|
911
911
|
): Promise<boolean | undefined> {
|
|
912
912
|
const bot = await deps.callApi<{ has_topics_enabled?: boolean }>("getMe", {});
|
|
@@ -915,7 +915,7 @@ export async function readTelegramThreadCapability(
|
|
|
915
915
|
return undefined;
|
|
916
916
|
}
|
|
917
917
|
|
|
918
|
-
|
|
918
|
+
async function probeTelegramStartupThreadCapability(
|
|
919
919
|
deps: TelegramStartupThreadCapabilityProbeDeps,
|
|
920
920
|
isCurrent: () => boolean = () => true,
|
|
921
921
|
): Promise<boolean | undefined> {
|
|
@@ -1201,7 +1201,7 @@ export function createTelegramThreadAwarePollingPorts<TContext, TOwner>(
|
|
|
1201
1201
|
};
|
|
1202
1202
|
}
|
|
1203
1203
|
|
|
1204
|
-
|
|
1204
|
+
function createTelegramThreadTargetObservationHandler<TContext>(
|
|
1205
1205
|
deps: TelegramThreadCapabilityRuntimeDeps<TContext>,
|
|
1206
1206
|
): TelegramThreadTargetObservationHandler<TContext> {
|
|
1207
1207
|
let transitionPending = false;
|
|
@@ -397,7 +397,7 @@ export function createTelegramPreviewController(
|
|
|
397
397
|
};
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
-
|
|
400
|
+
function createTelegramAssistantMessagePreviewHooks<TMessage>(
|
|
401
401
|
deps: TelegramAssistantMessagePreviewHookDeps<TMessage>,
|
|
402
402
|
): TelegramAssistantMessagePreviewHooks<TMessage> {
|
|
403
403
|
return {
|
|
@@ -425,7 +425,7 @@ export function shouldSuppressPreviewForGuestTurn(
|
|
|
425
425
|
return !!turn?.guestQueryId;
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
-
|
|
428
|
+
async function handleTelegramAssistantMessagePreviewStart<TMessage>(
|
|
429
429
|
message: TMessage,
|
|
430
430
|
deps: TelegramAssistantMessagePreviewStartDeps<TMessage>,
|
|
431
431
|
): Promise<void> {
|
|
@@ -453,7 +453,7 @@ export async function handleTelegramAssistantMessagePreviewStart<TMessage>(
|
|
|
453
453
|
deps.setState(next);
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
-
|
|
456
|
+
async function handleTelegramAssistantMessagePreviewUpdate<TMessage>(
|
|
457
457
|
message: TMessage,
|
|
458
458
|
deps: TelegramAssistantMessagePreviewUpdateDeps<TMessage>,
|
|
459
459
|
): Promise<void> {
|
|
@@ -79,7 +79,7 @@ export function substitutePromptTemplateArgs(
|
|
|
79
79
|
return result.replace(/\$ARGUMENTS/g, allArgs).replace(/\$@/g, allArgs);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
function isTelegramPromptTemplateCommandName(name: string): boolean {
|
|
83
83
|
return TELEGRAM_BOT_COMMAND_NAME_PATTERN.test(name);
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
|
|
9
9
|
import { isVoiceTurn } from "./voice.ts";
|
|
10
|
+
import { isWireRecord as isQueuePayloadRecord } from "./wire.ts";
|
|
10
11
|
import { isTelegramApiCommitUnknownError } from "./telegram-api.ts";
|
|
11
12
|
|
|
12
13
|
// --- Queue Items ---
|
|
@@ -147,7 +148,7 @@ export type TelegramQueueItem<TContext = unknown> =
|
|
|
147
148
|
PendingTelegramTurn | PendingTelegramControlItem<TContext>;
|
|
148
149
|
|
|
149
150
|
export const TELEGRAM_QUEUE_HANDOFF_PAYLOAD_MAX_BYTES = 8 * 1024 * 1024;
|
|
150
|
-
|
|
151
|
+
const TELEGRAM_QUEUE_HANDOFF_MAX_RECEIPTS = 256;
|
|
151
152
|
|
|
152
153
|
export interface TelegramQueueHandoffBase {
|
|
153
154
|
chatId: number;
|
|
@@ -191,6 +192,63 @@ export interface TelegramQueueHandoff {
|
|
|
191
192
|
payload: TelegramQueueHandoffPayload;
|
|
192
193
|
}
|
|
193
194
|
|
|
195
|
+
function parseQueuePayloadReceipt(value: unknown, kind: TelegramQueueItemKind): TelegramQueueAdmissionReceipt | undefined {
|
|
196
|
+
if (!isQueuePayloadRecord(value) || value.queueKind !== kind ||
|
|
197
|
+
typeof value.receiptId !== "string" || !value.receiptId ||
|
|
198
|
+
(value.journalBindingKey !== undefined && (typeof value.journalBindingKey !== "string" || !value.journalBindingKey.trim())) ||
|
|
199
|
+
!Array.isArray(value.sourceUpdateIds) || value.sourceUpdateIds.length === 0 ||
|
|
200
|
+
value.sourceUpdateIds.some((id, index) => !Number.isSafeInteger(id) || id < 0 ||
|
|
201
|
+
(index > 0 && id <= (value.sourceUpdateIds as number[])[index - 1]!))) return undefined;
|
|
202
|
+
return { queueKind: kind, receiptId: value.receiptId, sourceUpdateIds: value.sourceUpdateIds as number[],
|
|
203
|
+
...(typeof value.journalBindingKey === "string" ? { journalBindingKey: value.journalBindingKey } : {}) };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Data decoder shared by authenticated IPC and cold storage; decoding grants no admission. */
|
|
207
|
+
export function parseTelegramQueueHandoffPayload(value: unknown): TelegramQueueHandoffPayload | undefined {
|
|
208
|
+
if (!isQueuePayloadRecord(value) || (value.kind !== "prompt" && value.kind !== "control")) return undefined;
|
|
209
|
+
const target = isQueuePayloadRecord(value.target) && typeof value.target.chatId === "number"
|
|
210
|
+
? { chatId: value.target.chatId, ...(typeof value.target.threadId === "number" ? { threadId: value.target.threadId } : {}) } : undefined;
|
|
211
|
+
const transportStamp = isQueuePayloadRecord(value.transportStamp) &&
|
|
212
|
+
typeof value.transportStamp.profile === "string" && typeof value.transportStamp.generation === "string"
|
|
213
|
+
? { profile: value.transportStamp.profile, generation: value.transportStamp.generation } : undefined;
|
|
214
|
+
if (!Number.isSafeInteger(value.chatId) || (value.target !== undefined && !target) ||
|
|
215
|
+
(value.transportStamp !== undefined && !transportStamp) || !Number.isSafeInteger(value.replyToMessageId) ||
|
|
216
|
+
(value.guestQueryId !== undefined && typeof value.guestQueryId !== "string") ||
|
|
217
|
+
(value.guestInlineMessageId !== undefined && typeof value.guestInlineMessageId !== "string") ||
|
|
218
|
+
!Number.isSafeInteger(value.queueOrder) || (value.queueLane !== "control" && value.queueLane !== "priority" && value.queueLane !== "default") ||
|
|
219
|
+
!Number.isSafeInteger(value.laneOrder) || typeof value.statusSummary !== "string" || !Array.isArray(value.admissionReceipts)) return undefined;
|
|
220
|
+
const admissionReceipts = value.admissionReceipts.map(receipt => parseQueuePayloadReceipt(receipt, value.kind as TelegramQueueItemKind));
|
|
221
|
+
if (admissionReceipts.length === 0 || admissionReceipts.length > TELEGRAM_QUEUE_HANDOFF_MAX_RECEIPTS ||
|
|
222
|
+
admissionReceipts.some(receipt => !receipt)) return undefined;
|
|
223
|
+
const base = { chatId: value.chatId as number, ...(target ? { target } : {}), ...(transportStamp ? { transportStamp } : {}),
|
|
224
|
+
replyToMessageId: value.replyToMessageId as number,
|
|
225
|
+
...(typeof value.guestQueryId === "string" ? { guestQueryId: value.guestQueryId } : {}),
|
|
226
|
+
...(typeof value.guestInlineMessageId === "string" ? { guestInlineMessageId: value.guestInlineMessageId } : {}),
|
|
227
|
+
queueOrder: value.queueOrder as number, queueLane: value.queueLane as TelegramQueueLane,
|
|
228
|
+
laneOrder: value.laneOrder as number, statusSummary: value.statusSummary,
|
|
229
|
+
admissionReceipts: admissionReceipts as TelegramQueueAdmissionReceipt[] };
|
|
230
|
+
if (value.kind === "control") {
|
|
231
|
+
return value.queueLane === "control" && (value.controlType === "status" || value.controlType === "model")
|
|
232
|
+
? { kind: "control", controlType: value.controlType, ...base } : undefined;
|
|
233
|
+
}
|
|
234
|
+
if (value.queueLane === "control" || !Array.isArray(value.sourceMessageIds) || value.sourceMessageIds.some(id => !Number.isSafeInteger(id)) ||
|
|
235
|
+
!Array.isArray(value.queuedAttachments) || value.queuedAttachments.some(attachment => !isQueuePayloadRecord(attachment) ||
|
|
236
|
+
typeof attachment.path !== "string" || typeof attachment.fileName !== "string") ||
|
|
237
|
+
!Array.isArray(value.content) || value.content.some(content => !isQueuePayloadRecord(content) ||
|
|
238
|
+
(content.type === "text" ? typeof content.text !== "string" : content.type === "image"
|
|
239
|
+
? typeof content.data !== "string" || typeof content.mimeType !== "string" : true)) ||
|
|
240
|
+
typeof value.historyText !== "string" || (value.priorityEmoji !== undefined && typeof value.priorityEmoji !== "string") ||
|
|
241
|
+
(value.reactionSuppressionEmoji !== undefined && typeof value.reactionSuppressionEmoji !== "string") ||
|
|
242
|
+
(value.voiceReplyPreferred !== undefined && typeof value.voiceReplyPreferred !== "boolean") ||
|
|
243
|
+
(value.voiceReplyRequired !== undefined && typeof value.voiceReplyRequired !== "boolean")) return undefined;
|
|
244
|
+
return { kind: "prompt", ...base, sourceMessageIds: value.sourceMessageIds as number[],
|
|
245
|
+
queuedAttachments: value.queuedAttachments as QueuedAttachment[], content: value.content as TelegramPromptContent[], historyText: value.historyText,
|
|
246
|
+
...(typeof value.priorityEmoji === "string" ? { priorityEmoji: value.priorityEmoji } : {}),
|
|
247
|
+
...(typeof value.reactionSuppressionEmoji === "string" ? { reactionSuppressionEmoji: value.reactionSuppressionEmoji } : {}),
|
|
248
|
+
...(typeof value.voiceReplyPreferred === "boolean" ? { voiceReplyPreferred: value.voiceReplyPreferred } : {}),
|
|
249
|
+
...(typeof value.voiceReplyRequired === "boolean" ? { voiceReplyRequired: value.voiceReplyRequired } : {}) };
|
|
250
|
+
}
|
|
251
|
+
|
|
194
252
|
export interface TelegramQueueHandoffStageReceipt {
|
|
195
253
|
status: "staged";
|
|
196
254
|
receiptId: string;
|
|
@@ -367,7 +425,7 @@ function getTelegramQueueLaneRank(lane: TelegramQueueLane): number {
|
|
|
367
425
|
return getTelegramQueueLaneContract(lane).dispatchRank;
|
|
368
426
|
}
|
|
369
427
|
|
|
370
|
-
|
|
428
|
+
function isPendingTelegramTurn<TContext = unknown>(
|
|
371
429
|
item: TelegramQueueItem<TContext>,
|
|
372
430
|
): item is PendingTelegramTurn {
|
|
373
431
|
return item.kind === "prompt";
|
|
@@ -434,7 +492,7 @@ export function createTelegramTransportStampedQueueStore<TContext>(
|
|
|
434
492
|
};
|
|
435
493
|
}
|
|
436
494
|
|
|
437
|
-
|
|
495
|
+
function isTelegramQueueItemSkipped<TContext = unknown>(
|
|
438
496
|
item: TelegramQueueItem<TContext>,
|
|
439
497
|
): boolean {
|
|
440
498
|
return item.kind === "prompt" && Boolean(item.reactionSuppressionEmoji);
|
|
@@ -936,7 +994,7 @@ export function removeTelegramQueueItemsByMessageIds<TContext = unknown>(
|
|
|
936
994
|
};
|
|
937
995
|
}
|
|
938
996
|
|
|
939
|
-
|
|
997
|
+
function removeTelegramQueuedGuestPromptByOrder<TContext = unknown>(
|
|
940
998
|
items: TelegramQueueItem<TContext>[],
|
|
941
999
|
queueOrder: number,
|
|
942
1000
|
): {
|
|
@@ -2695,7 +2753,7 @@ function appendTelegramQueueItemRuntime<TContext>(
|
|
|
2695
2753
|
commitReorderedTelegramQueueItemsRuntime(nextItems, deps);
|
|
2696
2754
|
}
|
|
2697
2755
|
|
|
2698
|
-
|
|
2756
|
+
function reorderTelegramQueueItemsRuntime<TContext>(
|
|
2699
2757
|
deps: TelegramQueueMutationRuntimeDeps<TContext>,
|
|
2700
2758
|
): void {
|
|
2701
2759
|
commitReorderedTelegramQueueItemsRuntime(deps.getQueuedItems(), deps);
|
|
@@ -2737,7 +2795,7 @@ export function removeTelegramQueueItemsByMessageIdsRuntime<TContext>(
|
|
|
2737
2795
|
return removedCount;
|
|
2738
2796
|
}
|
|
2739
2797
|
|
|
2740
|
-
|
|
2798
|
+
function removeTelegramQueuedGuestPromptByOrderRuntime<TContext>(
|
|
2741
2799
|
queueOrder: number,
|
|
2742
2800
|
deps: TelegramQueueMutationRuntimeDeps<TContext>,
|
|
2743
2801
|
): boolean {
|
|
@@ -2883,7 +2941,7 @@ export interface TelegramControlRuntimeDeps<
|
|
|
2883
2941
|
chatId: number,
|
|
2884
2942
|
replyToMessageId: number,
|
|
2885
2943
|
text: string,
|
|
2886
|
-
options?: { target?: TelegramQueueTarget },
|
|
2944
|
+
options?: { target?: TelegramQueueTarget; parseMode?: "HTML" },
|
|
2887
2945
|
) => Promise<number | undefined>;
|
|
2888
2946
|
onSettled: (item: PendingTelegramControlItem<TContext>) => void;
|
|
2889
2947
|
}
|
|
@@ -2936,7 +2994,7 @@ export interface TelegramDeferredQueueDispatchRuntime<TContext = unknown> {
|
|
|
2936
2994
|
* Production debounce for deferred queue dispatch; the factory defaults to this
|
|
2937
2995
|
* so the entrypoint wires ports instead of policy constants.
|
|
2938
2996
|
*/
|
|
2939
|
-
|
|
2997
|
+
const TELEGRAM_DEFERRED_DISPATCH_DELAY_MS = 50;
|
|
2940
2998
|
|
|
2941
2999
|
export function createTelegramDeferredQueueDispatchRuntime<TContext = unknown>(
|
|
2942
3000
|
deps: TelegramDeferredQueueDispatchRuntimeDeps = {},
|
|
@@ -3436,7 +3494,7 @@ export function createTelegramQueueDispatchController<TContext = unknown>(
|
|
|
3436
3494
|
dispatchPlan.item.chatId,
|
|
3437
3495
|
dispatchPlan.item.replyToMessageId,
|
|
3438
3496
|
"<b>⏩ Dispatching next queued turn.</b>",
|
|
3439
|
-
{ target: dispatchPlan.item.target },
|
|
3497
|
+
{ target: dispatchPlan.item.target, parseMode: "HTML" },
|
|
3440
3498
|
).catch((error) => {
|
|
3441
3499
|
deps.recordRuntimeEvent?.("dispatch", error, {
|
|
3442
3500
|
phase: "next-announcement",
|
|
@@ -4,21 +4,21 @@
|
|
|
4
4
|
* Owns fail-safe classification of temporary ownership and routing artifacts
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { randomUUID } from "node:crypto";
|
|
8
7
|
import {
|
|
9
8
|
existsSync,
|
|
10
9
|
lstatSync,
|
|
11
|
-
mkdirSync,
|
|
12
10
|
readFileSync,
|
|
13
11
|
readdirSync,
|
|
14
|
-
|
|
12
|
+
rmdirSync,
|
|
13
|
+
rmSync,
|
|
15
14
|
} from "node:fs";
|
|
16
15
|
import { basename, dirname, join } from "node:path";
|
|
17
16
|
|
|
17
|
+
import { decodeTelegramSessionDirectoryName, getTelegramProfilePathSuffix } from "./paths.ts";
|
|
18
|
+
|
|
18
19
|
import {
|
|
19
20
|
isProcessAlive as defaultIsProcessAlive,
|
|
20
21
|
parseTelegramLockEntry,
|
|
21
|
-
renameTelegramPathWithRetry,
|
|
22
22
|
TELEGRAM_BUS_LEADER_STALE_HEARTBEAT_MS,
|
|
23
23
|
withTelegramFileTransaction,
|
|
24
24
|
type TelegramFileTransactionOptions,
|
|
@@ -59,22 +59,22 @@ export type TelegramRuntimeRecoveryResult =
|
|
|
59
59
|
| {
|
|
60
60
|
kind: "blocked-live-owner";
|
|
61
61
|
livePids: number[];
|
|
62
|
-
|
|
62
|
+
deletedPaths?: string[];
|
|
63
63
|
}
|
|
64
64
|
| {
|
|
65
65
|
kind: "recovered";
|
|
66
66
|
artifacts: TelegramRuntimeCorruptArtifact[];
|
|
67
|
-
|
|
67
|
+
/** Damaged disposable artifacts deleted per the approved corruption policy; nothing is quarantined. */
|
|
68
|
+
deletedPaths: string[];
|
|
68
69
|
};
|
|
69
70
|
|
|
70
71
|
export interface TelegramRuntimeRecoveryOptions
|
|
71
72
|
extends TelegramRuntimeRecoveryClassificationOptions {
|
|
72
73
|
recoveryTransactionPath?: string;
|
|
73
|
-
quarantineRoot?: string;
|
|
74
74
|
pid?: number;
|
|
75
75
|
getNowMs?: () => number;
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
/** Fault-injection seam; production uses bounded-retry recursive removal. */
|
|
77
|
+
removePath?: (path: string) => void;
|
|
78
78
|
transactionOptions?: TelegramFileTransactionOptions;
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -145,6 +145,9 @@ function inspectOwners(
|
|
|
145
145
|
function inspectState(path: string): ArtifactInspection {
|
|
146
146
|
if (!existsSync(path)) return { source: "state", ownerPids: [] };
|
|
147
147
|
try {
|
|
148
|
+
const stat = lstatSync(path);
|
|
149
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1 || stat.size > 8 * 1024 * 1024)
|
|
150
|
+
return corruption("state", path, `${basename(path)} cannot be safely inspected`);
|
|
148
151
|
JSON.parse(readFileSync(path, "utf8"));
|
|
149
152
|
return { source: "state", ownerPids: [] };
|
|
150
153
|
} catch {
|
|
@@ -293,24 +296,24 @@ export function classifyTelegramRuntimeRecovery(
|
|
|
293
296
|
}
|
|
294
297
|
|
|
295
298
|
/**
|
|
296
|
-
*
|
|
299
|
+
* Delete classifier-approved disposable corruption under two guards.
|
|
297
300
|
*
|
|
298
301
|
* A dedicated recovery transaction serializes recoverers. The ownership
|
|
299
302
|
* transaction then prevents a new Telegram owner from appearing between the
|
|
300
|
-
* final classification and mutation.
|
|
301
|
-
*
|
|
303
|
+
* final classification and mutation. Damaged ownership debris and canonical
|
|
304
|
+
* state are deleted (operator policy: unfinished Restores in unreadable state
|
|
305
|
+
* are acceptable loss). Durable config and diagnostics never enter the set.
|
|
302
306
|
*/
|
|
303
307
|
export function recoverTelegramRuntimeState(
|
|
304
308
|
options: TelegramRuntimeRecoveryOptions,
|
|
305
309
|
): TelegramRuntimeRecoveryResult {
|
|
306
|
-
const pid = options.pid ?? process.pid;
|
|
307
310
|
const transactionPath =
|
|
308
311
|
options.transactionPath ?? `${options.ownersPath}.transaction`;
|
|
309
312
|
const recoveryTransactionPath =
|
|
310
313
|
options.recoveryTransactionPath ??
|
|
311
314
|
join(dirname(options.ownersPath), "runtime-recovery.transaction");
|
|
312
|
-
const
|
|
313
|
-
|
|
315
|
+
const removePath = options.removePath ?? ((path: string) =>
|
|
316
|
+
rmSync(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 }));
|
|
314
317
|
const classificationOptions = {
|
|
315
318
|
ownersPath: options.ownersPath,
|
|
316
319
|
statePaths: options.statePaths,
|
|
@@ -332,34 +335,19 @@ export function recoverTelegramRuntimeState(
|
|
|
332
335
|
};
|
|
333
336
|
}
|
|
334
337
|
|
|
335
|
-
|
|
338
|
+
const deletedPaths: string[] = [];
|
|
336
339
|
const recoveredArtifacts: TelegramRuntimeCorruptArtifact[] = [];
|
|
337
|
-
const
|
|
338
|
-
if (quarantineDir) return quarantineDir;
|
|
339
|
-
quarantineDir = join(
|
|
340
|
-
quarantineRoot,
|
|
341
|
-
`${options.getNowMs?.() ?? Date.now()}-${pid}-${randomUUID()}`,
|
|
342
|
-
);
|
|
343
|
-
mkdirSync(quarantineDir, { recursive: true, mode: 0o700 });
|
|
344
|
-
return quarantineDir;
|
|
345
|
-
};
|
|
346
|
-
const quarantineArtifact = (
|
|
340
|
+
const deleteArtifact = (
|
|
347
341
|
artifact: TelegramRuntimeCorruptArtifact,
|
|
348
342
|
): void => {
|
|
349
343
|
if (!existsSync(artifact.path)) return;
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
rename: options.quarantineRename,
|
|
354
|
-
retryDelayMs: options.quarantineRenameRetryDelayMs,
|
|
355
|
-
})
|
|
356
|
-
) {
|
|
357
|
-
recoveredArtifacts.push(artifact);
|
|
358
|
-
}
|
|
344
|
+
removePath(artifact.path);
|
|
345
|
+
deletedPaths.push(artifact.path);
|
|
346
|
+
recoveredArtifacts.push(artifact);
|
|
359
347
|
};
|
|
360
348
|
|
|
361
349
|
for (const artifact of initial.artifacts) {
|
|
362
|
-
if (artifact.kind === "transaction")
|
|
350
|
+
if (artifact.kind === "transaction") deleteArtifact(artifact);
|
|
363
351
|
}
|
|
364
352
|
|
|
365
353
|
return withTelegramFileTransaction(
|
|
@@ -373,19 +361,19 @@ export function recoverTelegramRuntimeState(
|
|
|
373
361
|
return {
|
|
374
362
|
kind: "blocked-live-owner",
|
|
375
363
|
livePids: current.livePids,
|
|
376
|
-
|
|
364
|
+
...(deletedPaths.length > 0 ? { deletedPaths } : {}),
|
|
377
365
|
};
|
|
378
366
|
}
|
|
379
367
|
if (current.kind === "recoverable-corruption") {
|
|
380
368
|
for (const artifact of current.artifacts) {
|
|
381
|
-
if (artifact.kind !== "transaction")
|
|
369
|
+
if (artifact.kind !== "transaction") deleteArtifact(artifact);
|
|
382
370
|
}
|
|
383
371
|
}
|
|
384
|
-
return recoveredArtifacts.length > 0
|
|
372
|
+
return recoveredArtifacts.length > 0
|
|
385
373
|
? {
|
|
386
374
|
kind: "recovered",
|
|
387
375
|
artifacts: recoveredArtifacts,
|
|
388
|
-
|
|
376
|
+
deletedPaths,
|
|
389
377
|
}
|
|
390
378
|
: { kind: "not-needed" };
|
|
391
379
|
},
|
|
@@ -396,6 +384,81 @@ export function recoverTelegramRuntimeState(
|
|
|
396
384
|
);
|
|
397
385
|
}
|
|
398
386
|
|
|
387
|
+
/**
|
|
388
|
+
* Remove recovery folders written by earlier releases (runtime root and session folders).
|
|
389
|
+
* Current releases delete damaged files instead of quarantining them; nothing reads these copies.
|
|
390
|
+
*/
|
|
391
|
+
export function removeTelegramLegacyRecoveryStorage(runtimeDir: string): string[] {
|
|
392
|
+
const removed: string[] = [];
|
|
393
|
+
const remove = (path: string): void => {
|
|
394
|
+
try {
|
|
395
|
+
if (!lstatSync(path).isDirectory()) return;
|
|
396
|
+
rmSync(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
|
|
397
|
+
removed.push(path);
|
|
398
|
+
} catch {
|
|
399
|
+
// Best-effort housekeeping; a later startup retries.
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
remove(join(runtimeDir, "recovery"));
|
|
403
|
+
let sessions: string[] = [];
|
|
404
|
+
try { sessions = readdirSync(join(runtimeDir, "sessions")); } catch { /* no sessions yet */ }
|
|
405
|
+
for (const session of sessions) remove(join(runtimeDir, "sessions", session, "recovery"));
|
|
406
|
+
return removed;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const TELEGRAM_SESSION_SWEEP_INTERVAL_MS = 10 * 60 * 1000;
|
|
410
|
+
|
|
411
|
+
export interface TelegramSessionFolderSweeperDeps {
|
|
412
|
+
getSessionsDir: () => string;
|
|
413
|
+
getProfileName: () => string | undefined;
|
|
414
|
+
/** Sessions holding a Workspace slot binding, live registrations and this process's own session. */
|
|
415
|
+
getKeptSessionIds: () => Iterable<string | undefined>;
|
|
416
|
+
getNowMs?: () => number;
|
|
417
|
+
intervalMs?: number;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Leader housekeeping (operator policy): a session without a Workspace slot loses its
|
|
422
|
+
* current-profile journal family; the folder disappears once no profile uses it.
|
|
423
|
+
*/
|
|
424
|
+
export function createTelegramSessionFolderSweeper(deps: TelegramSessionFolderSweeperDeps): { sweep: () => string[] } {
|
|
425
|
+
const getNowMs = deps.getNowMs ?? Date.now;
|
|
426
|
+
const intervalMs = deps.intervalMs ?? TELEGRAM_SESSION_SWEEP_INTERVAL_MS;
|
|
427
|
+
let lastSweepAtMs: number | undefined;
|
|
428
|
+
return {
|
|
429
|
+
sweep() {
|
|
430
|
+
const now = getNowMs();
|
|
431
|
+
if (lastSweepAtMs !== undefined && now - lastSweepAtMs < intervalMs) return [];
|
|
432
|
+
lastSweepAtMs = now;
|
|
433
|
+
const sessionsDir = deps.getSessionsDir();
|
|
434
|
+
const kept = new Set(deps.getKeptSessionIds());
|
|
435
|
+
const suffix = getTelegramProfilePathSuffix(deps.getProfileName()).replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
436
|
+
const family = new RegExp(`^journal\\.[a-f0-9]{16}${suffix}\\.json(?:\\.segments|\\.retained)?$`, "u");
|
|
437
|
+
const removed: string[] = [];
|
|
438
|
+
let names: string[];
|
|
439
|
+
try { names = readdirSync(sessionsDir); } catch { return removed; }
|
|
440
|
+
for (const name of names) {
|
|
441
|
+
const sessionId = decodeTelegramSessionDirectoryName(name);
|
|
442
|
+
if (sessionId === undefined || kept.has(sessionId)) continue;
|
|
443
|
+
const folder = join(sessionsDir, name);
|
|
444
|
+
try {
|
|
445
|
+
if (!lstatSync(folder).isDirectory()) continue;
|
|
446
|
+
for (const entry of readdirSync(folder)) {
|
|
447
|
+
if (!family.test(entry)) continue;
|
|
448
|
+
const path = join(folder, entry);
|
|
449
|
+
rmSync(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
|
|
450
|
+
removed.push(path);
|
|
451
|
+
}
|
|
452
|
+
if (readdirSync(folder).length === 0) { rmdirSync(folder); removed.push(folder); }
|
|
453
|
+
} catch {
|
|
454
|
+
// Best-effort housekeeping; the next sweep retries.
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return removed;
|
|
458
|
+
},
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
399
462
|
/** Build the `/telegram-connect` recovery boundary around runtime artifacts. */
|
|
400
463
|
export function createTelegramPollingStartRecoveryHandler(
|
|
401
464
|
deps: TelegramPollingStartRecoveryHandlerDeps,
|
|
@@ -435,10 +498,7 @@ export function createTelegramPollingStartRecoveryHandler(
|
|
|
435
498
|
});
|
|
436
499
|
}
|
|
437
500
|
try {
|
|
438
|
-
const recovery = recoverTelegramRuntimeState({
|
|
439
|
-
ownersPath,
|
|
440
|
-
statePaths,
|
|
441
|
-
});
|
|
501
|
+
const recovery = recoverTelegramRuntimeState({ ownersPath, statePaths });
|
|
442
502
|
if (recovery.kind === "blocked-live-owner") {
|
|
443
503
|
return {
|
|
444
504
|
kind: "blocked",
|
|
@@ -750,7 +750,7 @@ export async function sendTelegramNativeMarkdownReply<TReplyMarkup = unknown>(
|
|
|
750
750
|
return lastMessageId;
|
|
751
751
|
}
|
|
752
752
|
|
|
753
|
-
|
|
753
|
+
async function sendTelegramNativeRichMessage(
|
|
754
754
|
chatId: number,
|
|
755
755
|
richMessage: TelegramInputRichMessage,
|
|
756
756
|
deps: {
|