@llblab/pi-telegram 0.17.5 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +67 -32
- package/BACKLOG.md +59 -19
- package/CHANGELOG.md +36 -15
- package/README.md +63 -35
- package/docs/README.md +3 -1
- package/docs/architecture.md +55 -23
- package/docs/callback-namespaces.md +1 -1
- package/docs/inbound.md +1 -1
- package/docs/locks.md +0 -2
- package/docs/multi-instance-bus.md +483 -0
- package/docs/outbound.md +4 -3
- package/docs/public-api.md +12 -10
- package/docs/sections.md +2 -2
- package/docs/ui-style.md +76 -0
- package/index.ts +789 -32
- package/lib/bindings.ts +68 -12
- package/lib/bus-api.ts +314 -0
- package/lib/bus-follower.ts +853 -0
- package/lib/bus-leader.ts +915 -0
- package/lib/bus.ts +866 -0
- package/lib/command-templates.ts +9 -11
- package/lib/commands.ts +133 -47
- package/lib/config.ts +53 -5
- package/lib/lifecycle.ts +23 -7
- package/lib/locks.ts +230 -66
- package/lib/media.ts +30 -2
- package/lib/menu-model.ts +48 -17
- package/lib/menu-queue.ts +51 -20
- package/lib/menu-settings.ts +9 -5
- package/lib/menu-status.ts +3 -0
- package/lib/menu-thinking.ts +3 -0
- package/lib/menu.ts +67 -26
- package/lib/outbound-attachments.ts +102 -17
- package/lib/outbound-buttons.ts +6 -2
- package/lib/outbound-voice.ts +31 -11
- package/lib/outbound.ts +6 -4
- package/lib/ownership.ts +119 -0
- package/lib/pi.ts +26 -3
- package/lib/polling.ts +477 -7
- package/lib/preview.ts +141 -88
- package/lib/prompt-templates.ts +3 -3
- package/lib/prompts.ts +80 -30
- package/lib/queue.ts +193 -91
- package/lib/rendering.ts +0 -25
- package/lib/replies.ts +187 -55
- package/lib/routing.ts +1673 -9
- package/lib/runtime-log.ts +123 -0
- package/lib/runtime.ts +84 -12
- package/lib/sections.ts +28 -21
- package/lib/setup.ts +1 -1
- package/lib/status.ts +532 -9
- package/lib/sync.ts +618 -0
- package/lib/target.ts +49 -0
- package/lib/telegram-api.ts +405 -40
- package/lib/text-groups.ts +5 -1
- package/lib/thread-reconciler.ts +915 -0
- package/lib/threads.ts +2205 -0
- package/lib/turns.ts +48 -3
- package/lib/updates.ts +355 -32
- package/package.json +24 -2
- package/docs/telegram-bot-api-rich-messages.md +0 -890
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram runtime JSONL diagnostics log
|
|
3
|
+
* Zones: telegram diagnostics, filesystem, session observability
|
|
4
|
+
* Owns session-local append-only runtime evidence for debugging without becoming routing state
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { existsSync, mkdirSync, statSync, writeFileSync, appendFile } from "node:fs";
|
|
8
|
+
import { homedir } from "node:os";
|
|
9
|
+
import { dirname, join, resolve } from "node:path";
|
|
10
|
+
|
|
11
|
+
export interface TelegramRuntimeJsonlEvent {
|
|
12
|
+
at: number;
|
|
13
|
+
category: string;
|
|
14
|
+
message: string;
|
|
15
|
+
details?: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface TelegramRuntimeJsonlLogOptions {
|
|
19
|
+
path?: string;
|
|
20
|
+
maxBytes?: number;
|
|
21
|
+
getNowMs?: () => number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TelegramRuntimeJsonlLog {
|
|
25
|
+
path: string;
|
|
26
|
+
reset: (reason: string, scope?: Record<string, unknown>) => void;
|
|
27
|
+
resetIfScopeChanged: (
|
|
28
|
+
scopeKey: string,
|
|
29
|
+
reason: string,
|
|
30
|
+
scope?: Record<string, unknown>,
|
|
31
|
+
) => void;
|
|
32
|
+
record: (event: TelegramRuntimeJsonlEvent) => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const DEFAULT_MAX_LOG_BYTES = 5 * 1024 * 1024;
|
|
36
|
+
|
|
37
|
+
function getAgentDir(): string {
|
|
38
|
+
return process.env.PI_CODING_AGENT_DIR
|
|
39
|
+
? resolve(process.env.PI_CODING_AGENT_DIR)
|
|
40
|
+
: join(homedir(), ".pi", "agent");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getTelegramRuntimeLogPath(agentDir = getAgentDir()): string {
|
|
44
|
+
return join(agentDir, "tmp", "telegram", "logs.jsonl");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function safeJsonLine(value: unknown): string {
|
|
48
|
+
return JSON.stringify(value, (_key, item) => {
|
|
49
|
+
if (item instanceof Error) return item.message;
|
|
50
|
+
if (typeof item === "bigint") return item.toString();
|
|
51
|
+
if (typeof item === "function" || typeof item === "symbol") return undefined;
|
|
52
|
+
return item;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function createTelegramRuntimeJsonlLog(
|
|
57
|
+
options: TelegramRuntimeJsonlLogOptions = {},
|
|
58
|
+
): TelegramRuntimeJsonlLog {
|
|
59
|
+
const path = options.path ?? getTelegramRuntimeLogPath();
|
|
60
|
+
const maxBytes = options.maxBytes ?? DEFAULT_MAX_LOG_BYTES;
|
|
61
|
+
const getNowMs = options.getNowMs ?? Date.now;
|
|
62
|
+
let scopeKey: string | undefined;
|
|
63
|
+
let pending: Promise<void> = Promise.resolve();
|
|
64
|
+
|
|
65
|
+
const ensureParent = () => {
|
|
66
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const writeReset = (reason: string, scope?: Record<string, unknown>) => {
|
|
70
|
+
ensureParent();
|
|
71
|
+
writeFileSync(
|
|
72
|
+
path,
|
|
73
|
+
safeJsonLine({
|
|
74
|
+
at: getNowMs(),
|
|
75
|
+
kind: "reset",
|
|
76
|
+
reason,
|
|
77
|
+
scope,
|
|
78
|
+
}) + "\n",
|
|
79
|
+
{ mode: 0o600 },
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const appendLine = (line: string) => {
|
|
84
|
+
pending = pending
|
|
85
|
+
.catch(() => undefined)
|
|
86
|
+
.then(async () => {
|
|
87
|
+
ensureParent();
|
|
88
|
+
if (existsSync(path) && statSync(path).size > maxBytes) {
|
|
89
|
+
writeReset("max-bytes", { maxBytes });
|
|
90
|
+
}
|
|
91
|
+
await new Promise<void>((resolve, reject) => {
|
|
92
|
+
appendFile(path, line, { mode: 0o600 }, (error) => {
|
|
93
|
+
if (error) reject(error);
|
|
94
|
+
else resolve();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
path,
|
|
102
|
+
reset(reason, scope) {
|
|
103
|
+
scopeKey = scope ? safeJsonLine(scope) : undefined;
|
|
104
|
+
try {
|
|
105
|
+
writeReset(reason, scope);
|
|
106
|
+
} catch {
|
|
107
|
+
// Diagnostics must never break Telegram runtime behavior.
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
resetIfScopeChanged(nextScopeKey, reason, scope) {
|
|
111
|
+
if (scopeKey === nextScopeKey) return;
|
|
112
|
+
scopeKey = nextScopeKey;
|
|
113
|
+
try {
|
|
114
|
+
writeReset(reason, scope);
|
|
115
|
+
} catch {
|
|
116
|
+
// Diagnostics must never break Telegram runtime behavior.
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
record(event) {
|
|
120
|
+
appendLine(safeJsonLine({ kind: "event", ...event }) + "\n");
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
package/lib/runtime.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Owns small session-local runtime primitives that are shared by orchestration but are not specific to queueing, rendering, polling, or Telegram transport
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const TELEGRAM_TYPING_ACTION_INTERVAL_MS =
|
|
7
|
+
const TELEGRAM_TYPING_ACTION_INTERVAL_MS = 1500;
|
|
8
8
|
const TELEGRAM_TYPING_IDLE_DRAIN_MAX_MS = 250;
|
|
9
9
|
|
|
10
10
|
export interface TelegramRuntimeQueueCounters {
|
|
@@ -26,6 +26,8 @@ export interface TelegramBridgeRuntimeState
|
|
|
26
26
|
abortHandler?: () => void;
|
|
27
27
|
typingInterval?: ReturnType<typeof setInterval>;
|
|
28
28
|
typingInFlight?: Promise<void>;
|
|
29
|
+
typingLoopDeps?: TelegramTypingLoopDeps;
|
|
30
|
+
typingLoopKey?: string;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export interface TelegramRuntimeQueuePort {
|
|
@@ -318,10 +320,29 @@ export function abortTelegramTurn(state: TelegramBridgeRuntimeState): boolean {
|
|
|
318
320
|
return true;
|
|
319
321
|
}
|
|
320
322
|
|
|
323
|
+
export interface TelegramTypingLoopTarget {
|
|
324
|
+
chatId: number;
|
|
325
|
+
threadId?: number;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function getTelegramTypingLoopThreadParams(
|
|
329
|
+
target: TelegramTypingLoopTarget | undefined,
|
|
330
|
+
): { message_thread_id?: number } | undefined {
|
|
331
|
+
const threadId = target?.threadId;
|
|
332
|
+
return Number.isInteger(threadId)
|
|
333
|
+
? { message_thread_id: threadId }
|
|
334
|
+
: undefined;
|
|
335
|
+
}
|
|
336
|
+
|
|
321
337
|
export interface TelegramTypingLoopDeps {
|
|
322
338
|
chatId: number | undefined;
|
|
339
|
+
target?: TelegramTypingLoopTarget;
|
|
323
340
|
intervalMs: number;
|
|
324
|
-
sendTypingAction: (
|
|
341
|
+
sendTypingAction: (
|
|
342
|
+
chatId: number,
|
|
343
|
+
options?: { message_thread_id?: number },
|
|
344
|
+
) => Promise<unknown>;
|
|
345
|
+
sendAggregateTypingAction?: (chatId: number) => Promise<unknown>;
|
|
325
346
|
}
|
|
326
347
|
|
|
327
348
|
export interface TelegramRuntimeEventRecorderPort {
|
|
@@ -356,21 +377,34 @@ export interface TelegramTypingLoopStarterDeps<
|
|
|
356
377
|
> extends TelegramRuntimeEventRecorderPort {
|
|
357
378
|
typing: TelegramRuntimeTypingPort;
|
|
358
379
|
getDefaultChatId: () => number | undefined;
|
|
359
|
-
sendTypingAction: (
|
|
380
|
+
sendTypingAction: (
|
|
381
|
+
chatId: number,
|
|
382
|
+
options?: { message_thread_id?: number },
|
|
383
|
+
) => Promise<unknown>;
|
|
384
|
+
sendAggregateTypingAction?: (chatId: number) => Promise<unknown>;
|
|
360
385
|
updateStatus: (ctx: TContext, error?: string) => void;
|
|
361
386
|
intervalMs?: number;
|
|
362
387
|
}
|
|
363
388
|
|
|
364
389
|
export function createTelegramTypingLoopStarter<TContext>(
|
|
365
390
|
deps: TelegramTypingLoopStarterDeps<TContext>,
|
|
366
|
-
): (
|
|
367
|
-
|
|
391
|
+
): (
|
|
392
|
+
ctx: TContext,
|
|
393
|
+
chatId?: number,
|
|
394
|
+
options?: { target?: TelegramTypingLoopTarget },
|
|
395
|
+
) => void {
|
|
396
|
+
return (ctx, chatId, options) => {
|
|
368
397
|
deps.typing.start({
|
|
369
398
|
chatId: chatId ?? deps.getDefaultChatId(),
|
|
399
|
+
target: options?.target,
|
|
370
400
|
intervalMs: deps.intervalMs ?? TELEGRAM_TYPING_ACTION_INTERVAL_MS,
|
|
371
401
|
sendTypingAction: async (targetChatId) => {
|
|
372
402
|
try {
|
|
373
|
-
|
|
403
|
+
const threadParams = getTelegramTypingLoopThreadParams(options?.target);
|
|
404
|
+
await deps.sendTypingAction(targetChatId, threadParams);
|
|
405
|
+
if (threadParams?.message_thread_id !== undefined) {
|
|
406
|
+
await deps.sendAggregateTypingAction?.(targetChatId);
|
|
407
|
+
}
|
|
374
408
|
} catch (error) {
|
|
375
409
|
const message =
|
|
376
410
|
error instanceof Error ? error.message : String(error);
|
|
@@ -389,14 +423,33 @@ export function createTelegramTypingLoopStarter<TContext>(
|
|
|
389
423
|
};
|
|
390
424
|
}
|
|
391
425
|
|
|
426
|
+
function getTelegramTypingLoopKey(deps: TelegramTypingLoopDeps): string {
|
|
427
|
+
const threadId = deps.target?.threadId;
|
|
428
|
+
return `${deps.chatId ?? 0}:${Number.isInteger(threadId) ? threadId : "all"}`;
|
|
429
|
+
}
|
|
430
|
+
|
|
392
431
|
export function startTelegramTypingLoop(
|
|
393
432
|
state: TelegramBridgeRuntimeState,
|
|
394
433
|
deps: TelegramTypingLoopDeps,
|
|
395
434
|
): boolean {
|
|
396
|
-
if (
|
|
397
|
-
|
|
435
|
+
if (deps.chatId === undefined || deps.chatId === 0) return false;
|
|
436
|
+
const previousKey = state.typingLoopKey;
|
|
437
|
+
const nextKey = getTelegramTypingLoopKey(deps);
|
|
438
|
+
state.typingLoopDeps = deps;
|
|
439
|
+
state.typingLoopKey = nextKey;
|
|
398
440
|
const sendTyping = (): void => {
|
|
399
|
-
const
|
|
441
|
+
const activeDeps = state.typingLoopDeps;
|
|
442
|
+
if (!activeDeps || activeDeps.chatId === undefined || activeDeps.chatId === 0)
|
|
443
|
+
return;
|
|
444
|
+
const targetChatId = activeDeps.chatId;
|
|
445
|
+
const threadParams = getTelegramTypingLoopThreadParams(activeDeps.target);
|
|
446
|
+
const typing = Promise.resolve()
|
|
447
|
+
.then(async () => {
|
|
448
|
+
await activeDeps.sendTypingAction(targetChatId, threadParams);
|
|
449
|
+
if (threadParams?.message_thread_id !== undefined) {
|
|
450
|
+
await activeDeps.sendAggregateTypingAction?.(targetChatId);
|
|
451
|
+
}
|
|
452
|
+
})
|
|
400
453
|
.then(() => undefined)
|
|
401
454
|
.catch(() => undefined);
|
|
402
455
|
state.typingInFlight = typing;
|
|
@@ -404,6 +457,11 @@ export function startTelegramTypingLoop(
|
|
|
404
457
|
if (state.typingInFlight === typing) state.typingInFlight = undefined;
|
|
405
458
|
});
|
|
406
459
|
};
|
|
460
|
+
if (state.typingInterval) {
|
|
461
|
+
if (previousKey === nextKey) return false;
|
|
462
|
+
sendTyping();
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
407
465
|
sendTyping();
|
|
408
466
|
state.typingInterval = setInterval(sendTyping, deps.intervalMs);
|
|
409
467
|
state.typingInterval.unref?.();
|
|
@@ -416,6 +474,8 @@ export function stopTelegramTypingLoop(
|
|
|
416
474
|
if (!state.typingInterval) return false;
|
|
417
475
|
clearInterval(state.typingInterval);
|
|
418
476
|
state.typingInterval = undefined;
|
|
477
|
+
state.typingLoopDeps = undefined;
|
|
478
|
+
state.typingLoopKey = undefined;
|
|
419
479
|
return true;
|
|
420
480
|
}
|
|
421
481
|
|
|
@@ -478,7 +538,11 @@ export interface TelegramPromptDispatchLifecycleDeps<
|
|
|
478
538
|
"setDispatchPending" | "clearDispatchPending"
|
|
479
539
|
>;
|
|
480
540
|
typing: Pick<TelegramRuntimeTypingPort, "stop">;
|
|
481
|
-
startTypingLoop: (
|
|
541
|
+
startTypingLoop: (
|
|
542
|
+
ctx: TContext,
|
|
543
|
+
chatId?: number,
|
|
544
|
+
options?: { target?: TelegramTypingLoopTarget },
|
|
545
|
+
) => void;
|
|
482
546
|
updateStatus: (ctx: TContext, error?: string) => void;
|
|
483
547
|
}
|
|
484
548
|
|
|
@@ -488,13 +552,21 @@ export interface TelegramPromptDispatchRuntimeDeps<
|
|
|
488
552
|
lifecycle: TelegramPromptDispatchLifecycleDeps<TContext>["lifecycle"];
|
|
489
553
|
typing: TelegramRuntimeTypingPort;
|
|
490
554
|
getDefaultChatId: () => number | undefined;
|
|
491
|
-
sendTypingAction: (
|
|
555
|
+
sendTypingAction: (
|
|
556
|
+
chatId: number,
|
|
557
|
+
options?: { message_thread_id?: number },
|
|
558
|
+
) => Promise<unknown>;
|
|
559
|
+
sendAggregateTypingAction?: (chatId: number) => Promise<unknown>;
|
|
492
560
|
updateStatus: (ctx: TContext, error?: string) => void;
|
|
493
561
|
intervalMs?: number;
|
|
494
562
|
}
|
|
495
563
|
|
|
496
564
|
export interface TelegramPromptDispatchRuntime<TContext> {
|
|
497
|
-
startTypingLoop: (
|
|
565
|
+
startTypingLoop: (
|
|
566
|
+
ctx: TContext,
|
|
567
|
+
chatId?: number,
|
|
568
|
+
options?: { target?: TelegramTypingLoopTarget },
|
|
569
|
+
) => void;
|
|
498
570
|
onPromptDispatchStart: (ctx: TContext, chatId?: number) => void;
|
|
499
571
|
onPromptDispatchFailure: (ctx: TContext, message: string) => void;
|
|
500
572
|
}
|
package/lib/sections.ts
CHANGED
|
@@ -136,9 +136,16 @@ export interface TelegramSectionSettingsRow {
|
|
|
136
136
|
|
|
137
137
|
// --- Runtime Port Builders ---
|
|
138
138
|
|
|
139
|
+
/** @internal */
|
|
140
|
+
export interface TelegramSectionTarget {
|
|
141
|
+
chatId: number;
|
|
142
|
+
threadId?: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
139
145
|
/** @internal */
|
|
140
146
|
export interface TelegramSectionRuntimeDeps {
|
|
141
147
|
answerCallbackQuery: (id: string, text?: string) => Promise<void>;
|
|
148
|
+
target?: TelegramSectionTarget;
|
|
142
149
|
editInteractiveMessage: (
|
|
143
150
|
chatId: number,
|
|
144
151
|
messageId: number,
|
|
@@ -151,6 +158,7 @@ export interface TelegramSectionRuntimeDeps {
|
|
|
151
158
|
text: string,
|
|
152
159
|
mode: "markdown" | "html" | "plain",
|
|
153
160
|
replyMarkup: TelegramInlineKeyboardMarkup,
|
|
161
|
+
options?: { target?: TelegramSectionTarget },
|
|
154
162
|
) => Promise<number | undefined>;
|
|
155
163
|
enqueuePrompt: (prompt: string) => Promise<void>;
|
|
156
164
|
deleteMessage: (chatId: number, messageId: number) => Promise<void>;
|
|
@@ -191,6 +199,7 @@ function buildTelegramSectionContext(
|
|
|
191
199
|
view.text,
|
|
192
200
|
view.parseMode ?? "html",
|
|
193
201
|
view.replyMarkup ?? { inline_keyboard: [] },
|
|
202
|
+
deps.target ? { target: deps.target } : undefined,
|
|
194
203
|
)
|
|
195
204
|
.then(() => {}),
|
|
196
205
|
enqueuePrompt: deps.enqueuePrompt,
|
|
@@ -239,6 +248,7 @@ function buildTelegramSectionCallbackContext(
|
|
|
239
248
|
view.text,
|
|
240
249
|
view.parseMode ?? "html",
|
|
241
250
|
view.replyMarkup ?? { inline_keyboard: [] },
|
|
251
|
+
deps.target ? { target: deps.target } : undefined,
|
|
242
252
|
)
|
|
243
253
|
.then(() => {}),
|
|
244
254
|
enqueuePrompt: deps.enqueuePrompt,
|
|
@@ -299,11 +309,6 @@ export function getTelegramSectionDiagnostics(): TelegramSectionDiagnostic[] {
|
|
|
299
309
|
|
|
300
310
|
// --- Registry ---
|
|
301
311
|
|
|
302
|
-
const MAIN_MENU_ROW = {
|
|
303
|
-
text: "⬆️ Main menu",
|
|
304
|
-
callback_data: "menu:back",
|
|
305
|
-
} as const;
|
|
306
|
-
|
|
307
312
|
const BACK_NAV_ROW = {
|
|
308
313
|
text: "⬆️ Back",
|
|
309
314
|
} as const;
|
|
@@ -353,7 +358,7 @@ export function createTelegramExtensionSectionRegistry(): TelegramSectionRegistr
|
|
|
353
358
|
>();
|
|
354
359
|
let nextToken = 0;
|
|
355
360
|
|
|
356
|
-
|
|
361
|
+
const register = (section: TelegramSectionRegistration): () => void => {
|
|
357
362
|
const duplicate = [...sections.values()].find((s) => s.id === section.id);
|
|
358
363
|
if (duplicate) {
|
|
359
364
|
throw new Error(`Telegram section id already registered: ${section.id}`);
|
|
@@ -371,22 +376,22 @@ export function createTelegramExtensionSectionRegistry(): TelegramSectionRegistr
|
|
|
371
376
|
sections.delete(token);
|
|
372
377
|
errors.delete(token);
|
|
373
378
|
};
|
|
374
|
-
}
|
|
379
|
+
};
|
|
375
380
|
|
|
376
|
-
|
|
381
|
+
const getSections = (): RegisteredTelegramSection[] => {
|
|
377
382
|
return [...sections.values()].sort((a, b) => {
|
|
378
383
|
if (a.order !== b.order) return a.order - b.order;
|
|
379
384
|
return a.id.localeCompare(b.id);
|
|
380
385
|
});
|
|
381
|
-
}
|
|
386
|
+
};
|
|
382
387
|
|
|
383
|
-
|
|
388
|
+
const getByToken = (
|
|
384
389
|
token: TelegramSectionToken,
|
|
385
|
-
): RegisteredTelegramSection | undefined {
|
|
390
|
+
): RegisteredTelegramSection | undefined => {
|
|
386
391
|
return sections.get(token);
|
|
387
|
-
}
|
|
392
|
+
};
|
|
388
393
|
|
|
389
|
-
|
|
394
|
+
const getDiagnostics = (): TelegramSectionDiagnostic[] => {
|
|
390
395
|
return getSections().map((s) => ({
|
|
391
396
|
id: s.id,
|
|
392
397
|
token: s.token,
|
|
@@ -394,26 +399,26 @@ export function createTelegramExtensionSectionRegistry(): TelegramSectionRegistr
|
|
|
394
399
|
status: errors.has(s.token) ? "error" : "active",
|
|
395
400
|
lastError: errors.get(s.token)?.message,
|
|
396
401
|
}));
|
|
397
|
-
}
|
|
402
|
+
};
|
|
398
403
|
|
|
399
|
-
|
|
404
|
+
const recordError = (
|
|
400
405
|
token: TelegramSectionToken,
|
|
401
406
|
message: string,
|
|
402
407
|
source = "runtime",
|
|
403
|
-
): void {
|
|
408
|
+
): void => {
|
|
404
409
|
if (sections.has(token)) errors.set(token, { message, source });
|
|
405
|
-
}
|
|
410
|
+
};
|
|
406
411
|
|
|
407
|
-
|
|
412
|
+
const clearError = (token: TelegramSectionToken, source?: string): void => {
|
|
408
413
|
const current = errors.get(token);
|
|
409
414
|
if (!source || !current || current.source === source) errors.delete(token);
|
|
410
|
-
}
|
|
415
|
+
};
|
|
411
416
|
|
|
412
|
-
|
|
417
|
+
const clear = (): void => {
|
|
413
418
|
sections.clear();
|
|
414
419
|
errors.clear();
|
|
415
420
|
nextToken = 0;
|
|
416
|
-
}
|
|
421
|
+
};
|
|
417
422
|
|
|
418
423
|
return {
|
|
419
424
|
register,
|
|
@@ -506,6 +511,7 @@ export function parseTelegramSectionCallback(
|
|
|
506
511
|
/** @internal */
|
|
507
512
|
export interface TelegramSectionCallbackHandlerDeps {
|
|
508
513
|
answerCallbackQuery: (id: string, text?: string) => Promise<void>;
|
|
514
|
+
target?: TelegramSectionTarget;
|
|
509
515
|
editInteractiveMessage: (
|
|
510
516
|
chatId: number,
|
|
511
517
|
messageId: number,
|
|
@@ -518,6 +524,7 @@ export interface TelegramSectionCallbackHandlerDeps {
|
|
|
518
524
|
text: string,
|
|
519
525
|
mode: "markdown" | "html" | "plain",
|
|
520
526
|
replyMarkup: TelegramInlineKeyboardMarkup,
|
|
527
|
+
options?: { target?: TelegramSectionTarget },
|
|
521
528
|
) => Promise<number | undefined>;
|
|
522
529
|
enqueuePrompt: (prompt: string) => Promise<void>;
|
|
523
530
|
deleteMessage: (chatId: number, messageId: number) => Promise<void>;
|
package/lib/setup.ts
CHANGED
|
@@ -162,7 +162,7 @@ export async function runTelegramSetup(
|
|
|
162
162
|
export function createTelegramSetupPromptRuntime<
|
|
163
163
|
TContext extends TelegramSetupPromptContext,
|
|
164
164
|
>(deps: TelegramSetupPromptRuntimeDeps<TContext>) {
|
|
165
|
-
return async
|
|
165
|
+
return async (ctx: TContext): Promise<void> => {
|
|
166
166
|
if (!ctx.hasUI || !deps.setupGuard.start()) return;
|
|
167
167
|
try {
|
|
168
168
|
const nextConfig = await runTelegramSetup({
|