@llblab/pi-telegram 0.5.2 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -14
- package/docs/README.md +1 -0
- package/docs/architecture.md +5 -1
- package/docs/attachment-handlers.md +9 -17
- package/docs/command-templates.md +102 -32
- package/docs/outbound-handlers.md +112 -0
- package/index.ts +17 -3
- package/lib/{handlers.ts → attachment-handlers.ts} +135 -123
- package/lib/command-templates.ts +295 -0
- package/lib/config.ts +16 -1
- package/lib/outbound-handlers.ts +899 -0
- package/lib/preview.ts +29 -9
- package/lib/prompts.ts +5 -1
- package/lib/queue.ts +44 -2
- package/lib/replies.ts +21 -11
- package/lib/routing.ts +39 -2
- package/package.json +1 -1
package/lib/preview.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type TelegramRenderMode,
|
|
21
21
|
} from "./rendering.ts";
|
|
22
22
|
import { buildTelegramReplyParameters } from "./replies.ts";
|
|
23
|
+
import { stripTelegramCommentMarkupForPreview } from "./outbound-handlers.ts";
|
|
23
24
|
|
|
24
25
|
const TELEGRAM_PREVIEW_THROTTLE_MS = 750;
|
|
25
26
|
const TELEGRAM_DRAFT_ID_MAX = 2_147_483_647;
|
|
@@ -43,6 +44,7 @@ export interface TelegramPreviewRuntimeState extends TelegramPreviewState {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export type TelegramSentPreviewMessage = TelegramSentMessage;
|
|
47
|
+
export type TelegramPreviewReplyMarkup = any;
|
|
46
48
|
|
|
47
49
|
export interface TelegramPreviewRuntimeDeps {
|
|
48
50
|
getState: () => TelegramPreviewRuntimeState | undefined;
|
|
@@ -76,11 +78,13 @@ export interface TelegramPreviewRuntimeDeps {
|
|
|
76
78
|
sendRenderedChunks: (
|
|
77
79
|
chatId: number,
|
|
78
80
|
chunks: TelegramRenderedChunk[],
|
|
81
|
+
options?: { replyMarkup?: TelegramPreviewReplyMarkup },
|
|
79
82
|
) => Promise<number | undefined>;
|
|
80
83
|
editRenderedMessage: (
|
|
81
84
|
chatId: number,
|
|
82
85
|
messageId: number,
|
|
83
86
|
chunks: TelegramRenderedChunk[],
|
|
87
|
+
options?: { replyMarkup?: TelegramPreviewReplyMarkup },
|
|
84
88
|
) => Promise<number | undefined>;
|
|
85
89
|
}
|
|
86
90
|
|
|
@@ -158,11 +162,13 @@ export interface TelegramPreviewControllerDeps {
|
|
|
158
162
|
chatId: number,
|
|
159
163
|
chunks: TelegramRenderedChunk[],
|
|
160
164
|
replyToMessageId: number | undefined,
|
|
165
|
+
options?: { replyMarkup?: TelegramPreviewReplyMarkup },
|
|
161
166
|
) => Promise<number | undefined>;
|
|
162
167
|
editRenderedMessage: (
|
|
163
168
|
chatId: number,
|
|
164
169
|
messageId: number,
|
|
165
170
|
chunks: TelegramRenderedChunk[],
|
|
171
|
+
options?: { replyMarkup?: TelegramPreviewReplyMarkup },
|
|
166
172
|
) => Promise<number | undefined>;
|
|
167
173
|
throttleMs?: number;
|
|
168
174
|
maxDraftId?: number;
|
|
@@ -187,6 +193,7 @@ export interface TelegramPreviewController {
|
|
|
187
193
|
chatId: number,
|
|
188
194
|
markdown: string,
|
|
189
195
|
replyToMessageId?: number,
|
|
196
|
+
options?: { replyMarkup?: TelegramPreviewReplyMarkup },
|
|
190
197
|
) => Promise<boolean>;
|
|
191
198
|
}
|
|
192
199
|
|
|
@@ -227,12 +234,16 @@ export interface TelegramPreviewRenderedChunkTransportDeps {
|
|
|
227
234
|
sendRenderedChunks: (
|
|
228
235
|
chatId: number,
|
|
229
236
|
chunks: TelegramRenderedChunk[],
|
|
230
|
-
options?: {
|
|
237
|
+
options?: {
|
|
238
|
+
replyToMessageId?: number;
|
|
239
|
+
replyMarkup?: TelegramPreviewReplyMarkup;
|
|
240
|
+
},
|
|
231
241
|
) => Promise<number | undefined>;
|
|
232
242
|
editRenderedMessage: (
|
|
233
243
|
chatId: number,
|
|
234
244
|
messageId: number,
|
|
235
245
|
chunks: TelegramRenderedChunk[],
|
|
246
|
+
options?: { replyMarkup?: TelegramPreviewReplyMarkup },
|
|
236
247
|
) => Promise<number | undefined>;
|
|
237
248
|
}
|
|
238
249
|
|
|
@@ -243,9 +254,13 @@ export function createTelegramPreviewRenderedChunkTransport(
|
|
|
243
254
|
"sendRenderedChunks" | "editRenderedMessage"
|
|
244
255
|
> {
|
|
245
256
|
return {
|
|
246
|
-
sendRenderedChunks: (chatId, chunks, replyToMessageId) =>
|
|
247
|
-
deps.sendRenderedChunks(chatId, chunks, {
|
|
248
|
-
|
|
257
|
+
sendRenderedChunks: (chatId, chunks, replyToMessageId, options) =>
|
|
258
|
+
deps.sendRenderedChunks(chatId, chunks, {
|
|
259
|
+
replyToMessageId,
|
|
260
|
+
...(options?.replyMarkup ? { replyMarkup: options.replyMarkup } : {}),
|
|
261
|
+
}),
|
|
262
|
+
editRenderedMessage: (chatId, messageId, chunks, options) =>
|
|
263
|
+
deps.editRenderedMessage(chatId, messageId, chunks, options),
|
|
249
264
|
};
|
|
250
265
|
}
|
|
251
266
|
|
|
@@ -364,11 +379,12 @@ export function createTelegramPreviewController(
|
|
|
364
379
|
),
|
|
365
380
|
editMessageText: deps.editMessageText,
|
|
366
381
|
renderTelegramMessage: renderMessage,
|
|
367
|
-
sendRenderedChunks: (chatId, chunks) =>
|
|
382
|
+
sendRenderedChunks: (chatId, chunks, options) =>
|
|
368
383
|
deps.sendRenderedChunks(
|
|
369
384
|
chatId,
|
|
370
385
|
chunks,
|
|
371
386
|
replyToMessageId ?? deps.getDefaultReplyToMessageId?.(),
|
|
387
|
+
options,
|
|
372
388
|
),
|
|
373
389
|
editRenderedMessage: deps.editRenderedMessage,
|
|
374
390
|
});
|
|
@@ -394,11 +410,12 @@ export function createTelegramPreviewController(
|
|
|
394
410
|
},
|
|
395
411
|
finalize: (chatId, replyToMessageId) =>
|
|
396
412
|
finalizeTelegramPreview(chatId, getRuntimeDeps(replyToMessageId)),
|
|
397
|
-
finalizeMarkdown: (chatId, markdown, replyToMessageId) =>
|
|
413
|
+
finalizeMarkdown: (chatId, markdown, replyToMessageId, options) =>
|
|
398
414
|
finalizeTelegramMarkdownPreview(
|
|
399
415
|
chatId,
|
|
400
416
|
markdown,
|
|
401
417
|
getRuntimeDeps(replyToMessageId),
|
|
418
|
+
options,
|
|
402
419
|
),
|
|
403
420
|
};
|
|
404
421
|
}
|
|
@@ -453,7 +470,9 @@ export async function handleTelegramAssistantMessagePreviewUpdate<TMessage>(
|
|
|
453
470
|
state = deps.createPreviewState();
|
|
454
471
|
deps.setState(state);
|
|
455
472
|
}
|
|
456
|
-
state.pendingText =
|
|
473
|
+
state.pendingText = stripTelegramCommentMarkupForPreview(
|
|
474
|
+
deps.getMessageText(message),
|
|
475
|
+
);
|
|
457
476
|
deps.schedulePreviewFlush(turn.chatId);
|
|
458
477
|
}
|
|
459
478
|
|
|
@@ -613,6 +632,7 @@ export async function finalizeTelegramMarkdownPreview(
|
|
|
613
632
|
chatId: number,
|
|
614
633
|
markdown: string,
|
|
615
634
|
deps: TelegramPreviewRuntimeDeps,
|
|
635
|
+
options?: { replyMarkup?: TelegramPreviewReplyMarkup },
|
|
616
636
|
): Promise<boolean> {
|
|
617
637
|
const state = deps.getState();
|
|
618
638
|
if (!state) return false;
|
|
@@ -623,12 +643,12 @@ export async function finalizeTelegramMarkdownPreview(
|
|
|
623
643
|
return false;
|
|
624
644
|
}
|
|
625
645
|
if (state.mode === "draft") {
|
|
626
|
-
await deps.sendRenderedChunks(chatId, chunks);
|
|
646
|
+
await deps.sendRenderedChunks(chatId, chunks, options);
|
|
627
647
|
await clearTelegramPreview(chatId, deps);
|
|
628
648
|
return true;
|
|
629
649
|
}
|
|
630
650
|
if (state.messageId === undefined) return false;
|
|
631
|
-
await deps.editRenderedMessage(chatId, state.messageId, chunks);
|
|
651
|
+
await deps.editRenderedMessage(chatId, state.messageId, chunks, options);
|
|
632
652
|
deps.setState(undefined);
|
|
633
653
|
return true;
|
|
634
654
|
}
|
package/lib/prompts.ts
CHANGED
|
@@ -11,9 +11,13 @@ const SYSTEM_PROMPT_SUFFIX = `
|
|
|
11
11
|
Telegram bridge extension is active.
|
|
12
12
|
- Messages forwarded from Telegram are prefixed with "[telegram]".
|
|
13
13
|
- [telegram] messages may include [attachments] sections with a base directory plus relative local file entries. Resolve and read those files as needed.
|
|
14
|
+
- [telegram] messages may include a [reply] block after the user's current text. Treat [reply] as quoted context from the Telegram message the user replied to, not as a new instruction by itself; use it to resolve references like "this", "it", or "that message". The actual new user instruction is the message text before [reply], unless it explicitly asks you to act on the quoted context.
|
|
14
15
|
- Telegram is often read on narrow phone screens, so prefer narrow table columns when presenting tabular data; wide monospace tables can become unreadable.
|
|
15
16
|
- If a [telegram] user asked for a file or generated artifact, use telegram_attach with the local path instead of only mentioning the path in text.
|
|
16
|
-
- Do not assume mentioning a local file path in plain text will send it to Telegram. Use telegram_attach
|
|
17
|
+
- Do not assume mentioning a local file path in plain text will send it to Telegram. Use telegram_attach.
|
|
18
|
+
- For Telegram-native outbound actions, use hidden top-level Markdown comments instead of agent-side tool calls: write a normal answer plus correctly formatted column-zero \`telegram_voice\` or \`telegram_button\` blocks outside code, quotes, and lists. The bridge handles delivery after \`agent_end\`, so do not call or register transport/TTS/text-to-OGG tools for these actions.
|
|
19
|
+
- A \`telegram_voice\` block body is the text to synthesize through the extension's configured outbound-handler pipeline. It may be a short companion summary when useful, but no specific summary format is required. Keep it TTS-friendly; avoid raw Markdown, code, formulas, tables, or long lists.
|
|
20
|
+
- Button blocks should contain quick reply prompts the user can tap; use independent blocks like \`<!-- telegram_button label="OK"\nPrompt text\n-->\`, or \`<!-- telegram_button label="OK" -->\` when the prompt should equal the label. The callback prompt is routed back as a normal Telegram turn.`;
|
|
17
21
|
|
|
18
22
|
export function buildTelegramBridgeSystemPrompt(options: {
|
|
19
23
|
prompt: string;
|
package/lib/queue.ts
CHANGED
|
@@ -720,6 +720,21 @@ export interface TelegramAgentEndAssistantResult {
|
|
|
720
720
|
errorMessage?: string;
|
|
721
721
|
}
|
|
722
722
|
|
|
723
|
+
export interface TelegramAgentEndOutboundVoiceReply {
|
|
724
|
+
text: string;
|
|
725
|
+
lang?: string;
|
|
726
|
+
rate?: string;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
export interface TelegramAgentEndOutboundReplyPlan<TReplyMarkup = unknown> {
|
|
730
|
+
markdown: string;
|
|
731
|
+
replyMarkup?: TReplyMarkup;
|
|
732
|
+
voiceText?: string;
|
|
733
|
+
voiceReplies?: TelegramAgentEndOutboundVoiceReply[];
|
|
734
|
+
lang?: string;
|
|
735
|
+
rate?: string;
|
|
736
|
+
}
|
|
737
|
+
|
|
723
738
|
export interface TelegramAgentEndRuntimeDeps<
|
|
724
739
|
TTurn extends PendingTelegramTurn,
|
|
725
740
|
> {
|
|
@@ -735,11 +750,13 @@ export interface TelegramAgentEndRuntimeDeps<
|
|
|
735
750
|
chatId: number,
|
|
736
751
|
markdown: string,
|
|
737
752
|
replyToMessageId: number,
|
|
753
|
+
options?: { replyMarkup?: unknown },
|
|
738
754
|
) => Promise<boolean>;
|
|
739
755
|
sendMarkdownReply: (
|
|
740
756
|
chatId: number,
|
|
741
757
|
replyToMessageId: number,
|
|
742
758
|
markdown: string,
|
|
759
|
+
options?: { replyMarkup?: unknown },
|
|
743
760
|
) => Promise<unknown>;
|
|
744
761
|
sendTextReply: (
|
|
745
762
|
chatId: number,
|
|
@@ -747,6 +764,12 @@ export interface TelegramAgentEndRuntimeDeps<
|
|
|
747
764
|
text: string,
|
|
748
765
|
) => Promise<unknown>;
|
|
749
766
|
sendQueuedAttachments: (turn: TTurn) => Promise<void>;
|
|
767
|
+
planOutboundReply?: (markdown: string) => TelegramAgentEndOutboundReplyPlan;
|
|
768
|
+
sendOutboundReplyArtifacts?: (
|
|
769
|
+
turn: TTurn,
|
|
770
|
+
plan: TelegramAgentEndOutboundReplyPlan,
|
|
771
|
+
options?: { replyToPrompt?: boolean },
|
|
772
|
+
) => Promise<void>;
|
|
750
773
|
}
|
|
751
774
|
|
|
752
775
|
export interface TelegramAgentEndHookRuntimeDeps<
|
|
@@ -768,6 +791,8 @@ export interface TelegramAgentEndHookRuntimeDeps<
|
|
|
768
791
|
sendMarkdownReply: TelegramAgentEndRuntimeDeps<TTurn>["sendMarkdownReply"];
|
|
769
792
|
sendTextReply: TelegramAgentEndRuntimeDeps<TTurn>["sendTextReply"];
|
|
770
793
|
sendQueuedAttachments: (turn: TTurn) => Promise<void>;
|
|
794
|
+
planOutboundReply?: TelegramAgentEndRuntimeDeps<TTurn>["planOutboundReply"];
|
|
795
|
+
sendOutboundReplyArtifacts?: TelegramAgentEndRuntimeDeps<TTurn>["sendOutboundReplyArtifacts"];
|
|
771
796
|
}
|
|
772
797
|
|
|
773
798
|
export interface TelegramAgentEndHookEvent<TMessage> {
|
|
@@ -865,6 +890,8 @@ export function createTelegramAgentEndHook<
|
|
|
865
890
|
sendMarkdownReply: deps.sendMarkdownReply,
|
|
866
891
|
sendTextReply: deps.sendTextReply,
|
|
867
892
|
sendQueuedAttachments: deps.sendQueuedAttachments,
|
|
893
|
+
planOutboundReply: deps.planOutboundReply,
|
|
894
|
+
sendOutboundReplyArtifacts: deps.sendOutboundReplyArtifacts,
|
|
868
895
|
});
|
|
869
896
|
};
|
|
870
897
|
}
|
|
@@ -873,13 +900,20 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
873
900
|
TTurn extends PendingTelegramTurn,
|
|
874
901
|
>(deps: TelegramAgentEndRuntimeDeps<TTurn>): Promise<void> {
|
|
875
902
|
const { turn, assistant } = deps;
|
|
876
|
-
const
|
|
903
|
+
const rawFinalText = assistant.text;
|
|
904
|
+
const outboundReply = rawFinalText
|
|
905
|
+
? deps.planOutboundReply?.(rawFinalText)
|
|
906
|
+
: undefined;
|
|
907
|
+
const finalText = outboundReply ? outboundReply.markdown : rawFinalText;
|
|
908
|
+
const hasOutboundArtifacts =
|
|
909
|
+
!!outboundReply?.voiceText || !!outboundReply?.voiceReplies?.length;
|
|
910
|
+
const replyMarkup = outboundReply?.replyMarkup;
|
|
877
911
|
deps.resetRuntimeState();
|
|
878
912
|
deps.updateStatus();
|
|
879
913
|
const endPlan = buildTelegramAgentEndPlan({
|
|
880
914
|
hasTurn: !!turn,
|
|
881
915
|
stopReason: assistant.stopReason,
|
|
882
|
-
hasFinalText: !!finalText,
|
|
916
|
+
hasFinalText: !!finalText || hasOutboundArtifacts,
|
|
883
917
|
hasQueuedAttachments: (turn?.queuedAttachments.length ?? 0) > 0,
|
|
884
918
|
preserveQueuedTurnsAsHistory: deps.preserveQueuedTurnsAsHistory,
|
|
885
919
|
});
|
|
@@ -901,11 +935,13 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
901
935
|
return;
|
|
902
936
|
}
|
|
903
937
|
if (finalText) deps.setPreviewPendingText(finalText);
|
|
938
|
+
if (!finalText && hasOutboundArtifacts) await deps.clearPreview(turn.chatId);
|
|
904
939
|
if (endPlan.kind === "text" && finalText) {
|
|
905
940
|
const finalized = await deps.finalizeMarkdownPreview(
|
|
906
941
|
turn.chatId,
|
|
907
942
|
finalText,
|
|
908
943
|
turn.replyToMessageId,
|
|
944
|
+
{ replyMarkup },
|
|
909
945
|
);
|
|
910
946
|
if (!finalized) {
|
|
911
947
|
await deps.clearPreview(turn.chatId);
|
|
@@ -913,9 +949,15 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
913
949
|
turn.chatId,
|
|
914
950
|
turn.replyToMessageId,
|
|
915
951
|
finalText,
|
|
952
|
+
{ replyMarkup },
|
|
916
953
|
);
|
|
917
954
|
}
|
|
918
955
|
}
|
|
956
|
+
if (outboundReply && deps.sendOutboundReplyArtifacts) {
|
|
957
|
+
await deps.sendOutboundReplyArtifacts(turn, outboundReply, {
|
|
958
|
+
replyToPrompt: !finalText,
|
|
959
|
+
});
|
|
960
|
+
}
|
|
919
961
|
if (endPlan.shouldSendAttachmentNotice) {
|
|
920
962
|
await deps.sendTextReply(
|
|
921
963
|
turn.chatId,
|
package/lib/replies.ts
CHANGED
|
@@ -174,13 +174,14 @@ export async function editTelegramRenderedMessage<TReplyMarkup>(
|
|
|
174
174
|
return messageId;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
export interface TelegramReplyRuntimeDeps {
|
|
177
|
+
export interface TelegramReplyRuntimeDeps<TReplyMarkup = unknown> {
|
|
178
178
|
renderTelegramMessage: (
|
|
179
179
|
text: string,
|
|
180
180
|
options?: { mode?: TelegramRenderMode },
|
|
181
181
|
) => TelegramRenderedChunk[];
|
|
182
182
|
sendRenderedChunks: (
|
|
183
183
|
chunks: TelegramRenderedChunk[],
|
|
184
|
+
options?: { replyMarkup?: TReplyMarkup },
|
|
184
185
|
) => Promise<number | undefined>;
|
|
185
186
|
}
|
|
186
187
|
|
|
@@ -195,15 +196,16 @@ export async function sendTelegramPlainReply(
|
|
|
195
196
|
return deps.sendRenderedChunks(chunks);
|
|
196
197
|
}
|
|
197
198
|
|
|
198
|
-
export async function sendTelegramMarkdownReply(
|
|
199
|
+
export async function sendTelegramMarkdownReply<TReplyMarkup = unknown>(
|
|
199
200
|
markdown: string,
|
|
200
201
|
deps: TelegramReplyRuntimeDeps,
|
|
202
|
+
options?: { replyMarkup?: TReplyMarkup },
|
|
201
203
|
): Promise<number | undefined> {
|
|
202
204
|
const chunks = deps.renderTelegramMessage(markdown, { mode: "markdown" });
|
|
203
205
|
if (chunks.length === 0) {
|
|
204
206
|
return sendTelegramPlainReply(markdown, deps);
|
|
205
207
|
}
|
|
206
|
-
return deps.sendRenderedChunks(chunks);
|
|
208
|
+
return deps.sendRenderedChunks(chunks, options);
|
|
207
209
|
}
|
|
208
210
|
|
|
209
211
|
export interface TelegramRenderedMessageRuntimeDeps<TReplyMarkup> {
|
|
@@ -225,6 +227,7 @@ export interface TelegramRenderedMessageRuntime<TReplyMarkup> {
|
|
|
225
227
|
chatId: number,
|
|
226
228
|
replyToMessageId: number,
|
|
227
229
|
markdown: string,
|
|
230
|
+
options?: { replyMarkup?: unknown },
|
|
228
231
|
) => Promise<number | undefined>;
|
|
229
232
|
editInteractiveMessage: (
|
|
230
233
|
chatId: number,
|
|
@@ -290,14 +293,21 @@ export function createTelegramRenderedMessageRuntime<TReplyMarkup>(
|
|
|
290
293
|
options,
|
|
291
294
|
);
|
|
292
295
|
},
|
|
293
|
-
sendMarkdownReply: async (chatId, replyToMessageId, markdown) => {
|
|
294
|
-
return sendTelegramMarkdownReply(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
deps.
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
296
|
+
sendMarkdownReply: async (chatId, replyToMessageId, markdown, options) => {
|
|
297
|
+
return sendTelegramMarkdownReply(
|
|
298
|
+
markdown,
|
|
299
|
+
{
|
|
300
|
+
renderTelegramMessage: deps.renderTelegramMessage,
|
|
301
|
+
sendRenderedChunks: (chunks, chunkOptions) =>
|
|
302
|
+
deps.replyTransport.sendRenderedChunks(chatId, chunks, {
|
|
303
|
+
replyToMessageId,
|
|
304
|
+
replyMarkup: chunkOptions?.replyMarkup as
|
|
305
|
+
| TReplyMarkup
|
|
306
|
+
| undefined,
|
|
307
|
+
}),
|
|
308
|
+
},
|
|
309
|
+
options,
|
|
310
|
+
);
|
|
301
311
|
},
|
|
302
312
|
editInteractiveMessage: async (
|
|
303
313
|
chatId,
|
package/lib/routing.ts
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* Wires authorized updates into menus, commands, media grouping, and prompt queueing
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import * as OutboundHandlers from "./outbound-handlers.ts";
|
|
6
7
|
import * as Commands from "./commands.ts";
|
|
7
8
|
import type { TelegramConfigStore } from "./config.ts";
|
|
8
|
-
import type { TelegramAttachmentHandlerRuntime } from "./handlers.ts";
|
|
9
|
+
import type { TelegramAttachmentHandlerRuntime } from "./attachment-handlers.ts";
|
|
9
10
|
import * as Media from "./media.ts";
|
|
10
11
|
import * as Menu from "./menu.ts";
|
|
11
12
|
import * as Model from "./model.ts";
|
|
@@ -50,6 +51,7 @@ export interface TelegramInboundRouteRuntimeDeps<
|
|
|
50
51
|
Model.ScopedTelegramModel<TModel>
|
|
51
52
|
>;
|
|
52
53
|
menuActions: Menu.TelegramMenuActionRuntime<TContext, TModel>;
|
|
54
|
+
buttonActionStore?: OutboundHandlers.TelegramButtonActionStore;
|
|
53
55
|
attachmentHandlerRuntime: TelegramAttachmentHandlerRuntime<TContext>;
|
|
54
56
|
updateStatus: (ctx: TContext, error?: string) => void;
|
|
55
57
|
dispatchNextQueuedTelegramTurn: (ctx: TContext) => void;
|
|
@@ -99,7 +101,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
99
101
|
TModel
|
|
100
102
|
>,
|
|
101
103
|
): Updates.TelegramUpdateRuntimeController<TContext, TUpdate> {
|
|
102
|
-
const
|
|
104
|
+
const menuCallbackHandler = Menu.createTelegramMenuCallbackHandlerForContext<
|
|
103
105
|
TCallbackQuery,
|
|
104
106
|
TContext,
|
|
105
107
|
TModel
|
|
@@ -124,6 +126,41 @@ export function createTelegramInboundRouteRuntime<
|
|
|
124
126
|
restartInterruptedTelegramTurn:
|
|
125
127
|
deps.modelSwitchController.restartInterruptedTurn,
|
|
126
128
|
});
|
|
129
|
+
const callbackHandler = async (
|
|
130
|
+
query: TCallbackQuery,
|
|
131
|
+
ctx: TContext,
|
|
132
|
+
): Promise<void> => {
|
|
133
|
+
if (deps.buttonActionStore) {
|
|
134
|
+
const handled = await OutboundHandlers.handleTelegramButtonCallbackQuery(
|
|
135
|
+
query,
|
|
136
|
+
ctx,
|
|
137
|
+
{
|
|
138
|
+
resolveAction: deps.buttonActionStore.resolve,
|
|
139
|
+
answerCallbackQuery: deps.answerCallbackQuery,
|
|
140
|
+
enqueueButtonPrompt: (buttonQuery, action, context) => {
|
|
141
|
+
const chatId = buttonQuery.message?.chat?.id;
|
|
142
|
+
const messageId = buttonQuery.message?.message_id;
|
|
143
|
+
if (typeof chatId !== "number" || typeof messageId !== "number")
|
|
144
|
+
return;
|
|
145
|
+
const queueOrder = deps.bridgeRuntime.queue.allocateItemOrder();
|
|
146
|
+
deps.queueMutationRuntime.append(
|
|
147
|
+
OutboundHandlers.createTelegramButtonPromptTurn({
|
|
148
|
+
chatId,
|
|
149
|
+
replyToMessageId: messageId,
|
|
150
|
+
queueOrder,
|
|
151
|
+
action,
|
|
152
|
+
}),
|
|
153
|
+
context,
|
|
154
|
+
);
|
|
155
|
+
deps.updateStatus(context);
|
|
156
|
+
deps.dispatchNextQueuedTelegramTurn(context);
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
);
|
|
160
|
+
if (handled) return;
|
|
161
|
+
}
|
|
162
|
+
await menuCallbackHandler(query, ctx);
|
|
163
|
+
};
|
|
127
164
|
const commandHandler = Commands.createTelegramCommandHandlerTargetRuntime<
|
|
128
165
|
TMessage,
|
|
129
166
|
TContext
|