@llblab/pi-telegram 0.10.8 → 0.11.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.
@@ -8,18 +8,27 @@ import {
8
8
  getTelegramExtensionSettingsRows,
9
9
  type TelegramSectionRegistry,
10
10
  } from "./extension-sections.ts";
11
+ import type { TelegramTimeMode } from "./config.ts";
11
12
  import type { TelegramInlineKeyboardMarkup } from "./keyboard.ts";
12
13
  import type { TelegramModelMenuState } from "./menu-model.ts";
13
14
  import type { MenuModel } from "./model.ts";
15
+ import type { TelegramVoiceReplyMode } from "./voice.ts";
14
16
 
15
17
  export type TelegramSettingsMenuReplyMarkup = TelegramInlineKeyboardMarkup;
16
18
 
17
19
  export interface TelegramSettingsStateDeps {
18
20
  isProactivePushEnabled: () => boolean;
21
+ getTimeInjectionMode: () => TelegramTimeMode;
22
+ getVoiceReplyMode: () => TelegramVoiceReplyMode;
23
+ isVoiceReplyModeConfigured: () => boolean;
19
24
  }
20
25
 
21
26
  export interface TelegramSettingsMutationDeps extends TelegramSettingsStateDeps {
22
27
  setProactivePushEnabled: (enabled: boolean) => Promise<void>;
28
+ setVoiceReplyMode: (
29
+ mode: TelegramVoiceReplyMode | undefined,
30
+ ) => Promise<void>;
31
+ setTimeInjectionMode: (mode: TelegramTimeMode) => Promise<void>;
23
32
  }
24
33
 
25
34
  export interface TelegramSettingsMenuOpenDeps<
@@ -105,7 +114,22 @@ export interface TelegramSettingsMenuRuntimeDeps<
105
114
  }
106
115
 
107
116
  export const SETTINGS_MENU_TITLE = "<b>⚙️ Settings:</b>";
108
- export const PROACTIVE_PUSH_SETTINGS_TITLE = "<b>Proactive push:</b>";
117
+ export const PROACTIVE_PUSH_SETTINGS_TITLE = "<b>📌 Proactive push:</b>";
118
+ export const TIME_INJECTION_MODE_SETTINGS_TITLE = "<b>🕒 Time injection mode:</b>";
119
+ export const VOICE_REPLY_MODE_SETTINGS_TITLE = "<b>👄 Voice reply mode:</b>";
120
+
121
+ type TelegramVoiceReplyModeSetting = TelegramVoiceReplyMode | "hidden";
122
+
123
+ function getVoiceReplyModeLabel(mode: TelegramVoiceReplyModeSetting): string {
124
+ return mode;
125
+ }
126
+
127
+ function getVoiceReplyModeSetting(
128
+ mode: TelegramVoiceReplyMode,
129
+ configured: boolean,
130
+ ): TelegramVoiceReplyModeSetting {
131
+ return configured ? mode : "hidden";
132
+ }
109
133
 
110
134
  export function buildTelegramSettingsMenuText(): string {
111
135
  return SETTINGS_MENU_TITLE;
@@ -119,9 +143,37 @@ export function buildProactivePushSettingsText(): string {
119
143
  ].join("\n");
120
144
  }
121
145
 
146
+ export function buildVoiceReplyModeSettingsText(): string {
147
+ return [
148
+ VOICE_REPLY_MODE_SETTINGS_TITLE,
149
+ "",
150
+ "Controls when pi-telegram converts assistant text replies into Telegram voice messages.",
151
+ "",
152
+ "<code>-</code> <code>hidden</code> (default): same behavior as 'manual', but no voice policy is added to prompt context.",
153
+ "<code>-</code> <code>manual</code>: agent decides; explicit 'telegram_voice' markup still works and reply mode is visible in prompt context.",
154
+ "<code>-</code> <code>mirror</code>: voice input prefers a voice reply; text input gracefully follows 'manual' behavior.",
155
+ "<code>-</code> <code>always</code>: every reply is converted to voice when delivery succeeds.",
156
+ ].join("\n");
157
+ }
158
+
159
+ export function buildTimeInjectionModeSettingsText(): string {
160
+ return [
161
+ TIME_INJECTION_MODE_SETTINGS_TITLE,
162
+ "",
163
+ "Controls whether Telegram-originated prompts include a compact wall-clock [time] line.",
164
+ "",
165
+ "<code>-</code> <code>off</code> (default): no time line is added.",
166
+ "<code>-</code> <code>always</code>: add time to every Telegram turn.",
167
+ "<code>-</code> <code>interval</code>: add time at most once per chat interval (default: 1 hour).",
168
+ ].join("\n");
169
+ }
170
+
122
171
  export function buildTelegramSettingsMenuReplyMarkup(
123
172
  proactivePushEnabled: boolean,
173
+ voiceReplyMode: TelegramVoiceReplyMode,
174
+ timeInjectionMode: TelegramTimeMode,
124
175
  sectionRegistry?: TelegramSectionRegistry,
176
+ voiceReplyModeConfigured = true,
125
177
  ): TelegramSettingsMenuReplyMarkup {
126
178
  const rows: Array<Array<{ text: string; callback_data: string }>> = [
127
179
  [{ text: "⬆️ Main menu", callback_data: "menu:back" }],
@@ -133,12 +185,28 @@ export function buildTelegramSettingsMenuReplyMarkup(
133
185
  rows.push([{ text: row.label, callback_data: row.callback_data }]);
134
186
  }
135
187
  }
136
- rows.push([
137
- {
138
- text: `${proactivePushEnabled ? "🟢" : "⚫️"} Proactive push`,
139
- callback_data: "settings:open:proactive",
140
- },
141
- ]);
188
+ rows.push(
189
+ [
190
+ {
191
+ text: `👄 Voice reply: ${getVoiceReplyModeLabel(
192
+ getVoiceReplyModeSetting(voiceReplyMode, voiceReplyModeConfigured),
193
+ )}`,
194
+ callback_data: "settings:open:voice-reply",
195
+ },
196
+ ],
197
+ [
198
+ {
199
+ text: `🕒 Time injection: ${timeInjectionMode}`,
200
+ callback_data: "settings:open:time-injection",
201
+ },
202
+ ],
203
+ [
204
+ {
205
+ text: `📌 Proactive push: ${proactivePushEnabled ? "on" : "off"}`,
206
+ callback_data: "settings:open:proactive",
207
+ },
208
+ ],
209
+ );
142
210
  return { inline_keyboard: rows };
143
211
  }
144
212
 
@@ -154,7 +222,10 @@ export async function openTelegramSettingsMenu<
154
222
  buildTelegramSettingsMenuText(),
155
223
  buildTelegramSettingsMenuReplyMarkup(
156
224
  deps.isProactivePushEnabled(),
225
+ deps.getVoiceReplyMode(),
226
+ deps.getTimeInjectionMode(),
157
227
  sectionRegistry,
228
+ deps.isVoiceReplyModeConfigured(),
158
229
  ),
159
230
  );
160
231
  if (messageId === undefined) return;
@@ -171,11 +242,11 @@ export function buildProactivePushSettingsReplyMarkup(
171
242
  [{ text: "⬆️ Back", callback_data: "settings:list" }],
172
243
  [
173
244
  {
174
- text: proactivePushEnabled ? "🟢 On" : "⚫️ On",
245
+ text: proactivePushEnabled ? "🟢 on" : "⚫️ on",
175
246
  callback_data: "settings:set:proactive:on",
176
247
  },
177
248
  {
178
- text: proactivePushEnabled ? "⚫️ Off" : "🟡 Off",
249
+ text: proactivePushEnabled ? "⚫️ off" : "🟡 off",
179
250
  callback_data: "settings:set:proactive:off",
180
251
  },
181
252
  ],
@@ -183,6 +254,47 @@ export function buildProactivePushSettingsReplyMarkup(
183
254
  };
184
255
  }
185
256
 
257
+ export function buildTimeInjectionModeSettingsReplyMarkup(
258
+ mode: TelegramTimeMode,
259
+ ): TelegramSettingsMenuReplyMarkup {
260
+ const modes: TelegramTimeMode[] = ["off", "always", "interval"];
261
+ return {
262
+ inline_keyboard: [
263
+ [{ text: "⬆️ Back", callback_data: "settings:list" }],
264
+ ...modes.map((value) => [
265
+ {
266
+ text: `${value === mode ? "🟢 " : ""}${value}`,
267
+ callback_data: `settings:set:time-injection:${value}`,
268
+ },
269
+ ]),
270
+ ],
271
+ };
272
+ }
273
+
274
+ export function buildVoiceReplyModeSettingsReplyMarkup(
275
+ mode: TelegramVoiceReplyMode,
276
+ configured = true,
277
+ ): TelegramSettingsMenuReplyMarkup {
278
+ const activeMode = getVoiceReplyModeSetting(mode, configured);
279
+ const modes: TelegramVoiceReplyModeSetting[] = [
280
+ "hidden",
281
+ "manual",
282
+ "mirror",
283
+ "always",
284
+ ];
285
+ return {
286
+ inline_keyboard: [
287
+ [{ text: "⬆️ Back", callback_data: "settings:list" }],
288
+ ...modes.map((value) => [
289
+ {
290
+ text: `${value === activeMode ? "🟢 " : ""}${getVoiceReplyModeLabel(value)}`,
291
+ callback_data: `settings:set:voice-reply:${value}`,
292
+ },
293
+ ]),
294
+ ],
295
+ };
296
+ }
297
+
186
298
  export async function updateTelegramSettingsMenuMessage(
187
299
  deps: TelegramSettingsMenuMessageUpdateDeps,
188
300
  sectionRegistry?: TelegramSectionRegistry,
@@ -191,7 +303,10 @@ export async function updateTelegramSettingsMenuMessage(
191
303
  buildTelegramSettingsMenuText(),
192
304
  buildTelegramSettingsMenuReplyMarkup(
193
305
  deps.isProactivePushEnabled(),
306
+ deps.getVoiceReplyMode(),
307
+ deps.getTimeInjectionMode(),
194
308
  sectionRegistry,
309
+ deps.isVoiceReplyModeConfigured(),
195
310
  ),
196
311
  );
197
312
  }
@@ -205,6 +320,27 @@ export async function updateProactivePushSettingsMessage(
205
320
  );
206
321
  }
207
322
 
323
+ export async function updateTimeInjectionModeSettingsMessage(
324
+ deps: TelegramSettingsMenuCallbackDeps,
325
+ ): Promise<void> {
326
+ await deps.updateSettingsMessage(
327
+ buildTimeInjectionModeSettingsText(),
328
+ buildTimeInjectionModeSettingsReplyMarkup(deps.getTimeInjectionMode()),
329
+ );
330
+ }
331
+
332
+ export async function updateVoiceReplyModeSettingsMessage(
333
+ deps: TelegramSettingsMenuCallbackDeps,
334
+ ): Promise<void> {
335
+ await deps.updateSettingsMessage(
336
+ buildVoiceReplyModeSettingsText(),
337
+ buildVoiceReplyModeSettingsReplyMarkup(
338
+ deps.getVoiceReplyMode(),
339
+ deps.isVoiceReplyModeConfigured(),
340
+ ),
341
+ );
342
+ }
343
+
208
344
  export async function handleTelegramSettingsMenuCallbackAction(
209
345
  callbackQueryId: string,
210
346
  data: string | undefined,
@@ -221,6 +357,47 @@ export async function handleTelegramSettingsMenuCallbackAction(
221
357
  await deps.answerCallbackQuery(callbackQueryId);
222
358
  return true;
223
359
  }
360
+ if (data === "settings:open:voice-reply") {
361
+ await updateVoiceReplyModeSettingsMessage(deps);
362
+ await deps.answerCallbackQuery(callbackQueryId);
363
+ return true;
364
+ }
365
+ if (data === "settings:open:time-injection" || data === "settings:open:time") {
366
+ await updateTimeInjectionModeSettingsMessage(deps);
367
+ await deps.answerCallbackQuery(callbackQueryId);
368
+ return true;
369
+ }
370
+ if (data.startsWith("settings:set:voice-reply:")) {
371
+ const mode = data.slice("settings:set:voice-reply:".length);
372
+ if (
373
+ mode === "hidden" ||
374
+ mode === "manual" ||
375
+ mode === "mirror" ||
376
+ mode === "always"
377
+ ) {
378
+ await deps.setVoiceReplyMode(mode === "hidden" ? undefined : mode);
379
+ await updateVoiceReplyModeSettingsMessage(deps);
380
+ await deps.answerCallbackQuery(
381
+ callbackQueryId,
382
+ `Voice reply mode: ${mode}`,
383
+ );
384
+ return true;
385
+ }
386
+ }
387
+ if (
388
+ data.startsWith("settings:set:time-injection:") ||
389
+ data.startsWith("settings:set:time:")
390
+ ) {
391
+ const mode = data.startsWith("settings:set:time-injection:")
392
+ ? data.slice("settings:set:time-injection:".length)
393
+ : data.slice("settings:set:time:".length);
394
+ if (mode === "off" || mode === "always" || mode === "interval") {
395
+ await deps.setTimeInjectionMode(mode);
396
+ await updateTimeInjectionModeSettingsMessage(deps);
397
+ await deps.answerCallbackQuery(callbackQueryId, `Time injection: ${mode}`);
398
+ return true;
399
+ }
400
+ }
224
401
  if (
225
402
  data === "settings:set:proactive:on" ||
226
403
  data === "settings:set:proactive:off"
@@ -251,6 +428,9 @@ export function createTelegramSettingsMenuRuntime<
251
428
  {
252
429
  getModelMenuState: () => deps.getModelMenuState(chatId, ctx),
253
430
  isProactivePushEnabled: deps.isProactivePushEnabled,
431
+ getVoiceReplyMode: deps.getVoiceReplyMode,
432
+ isVoiceReplyModeConfigured: deps.isVoiceReplyModeConfigured,
433
+ getTimeInjectionMode: deps.getTimeInjectionMode,
254
434
  sendSettingsMenu: (state, text, replyMarkup) =>
255
435
  deps.sendInteractiveMessage(
256
436
  state.chatId,
@@ -266,6 +446,9 @@ export function createTelegramSettingsMenuRuntime<
266
446
  updateTelegramSettingsMenuMessage(
267
447
  {
268
448
  isProactivePushEnabled: deps.isProactivePushEnabled,
449
+ getVoiceReplyMode: deps.getVoiceReplyMode,
450
+ isVoiceReplyModeConfigured: deps.isVoiceReplyModeConfigured,
451
+ getTimeInjectionMode: deps.getTimeInjectionMode,
269
452
  updateSettingsMessage: (text, replyMarkup) =>
270
453
  deps.editInteractiveMessage(
271
454
  state.chatId,
@@ -281,6 +464,42 @@ export function createTelegramSettingsMenuRuntime<
281
464
  if (!query.data?.startsWith("settings:")) return false;
282
465
  const state = deps.getStoredModelMenuState(query.message?.message_id);
283
466
  if (!state) {
467
+ const voiceMode = query.data.slice("settings:set:voice-reply:".length);
468
+ if (
469
+ query.data.startsWith("settings:set:voice-reply:") &&
470
+ (voiceMode === "hidden" ||
471
+ voiceMode === "manual" ||
472
+ voiceMode === "mirror" ||
473
+ voiceMode === "always")
474
+ ) {
475
+ await deps.setVoiceReplyMode(
476
+ voiceMode === "hidden" ? undefined : voiceMode,
477
+ );
478
+ await deps.answerCallbackQuery(
479
+ query.id,
480
+ `Voice reply mode: ${voiceMode}`,
481
+ );
482
+ return true;
483
+ }
484
+ const hasTimeInjectionPrefix = query.data.startsWith(
485
+ "settings:set:time-injection:",
486
+ );
487
+ const timeMode = hasTimeInjectionPrefix
488
+ ? query.data.slice("settings:set:time-injection:".length)
489
+ : query.data.slice("settings:set:time:".length);
490
+ if (
491
+ (hasTimeInjectionPrefix || query.data.startsWith("settings:set:time:")) &&
492
+ (timeMode === "off" ||
493
+ timeMode === "always" ||
494
+ timeMode === "interval")
495
+ ) {
496
+ await deps.setTimeInjectionMode(timeMode);
497
+ await deps.answerCallbackQuery(
498
+ query.id,
499
+ `Time injection: ${timeMode}`,
500
+ );
501
+ return true;
502
+ }
284
503
  await deps.answerCallbackQuery(
285
504
  query.id,
286
505
  "Interactive message expired.",
@@ -289,7 +508,12 @@ export function createTelegramSettingsMenuRuntime<
289
508
  }
290
509
  return handleTelegramSettingsMenuCallbackAction(query.id, query.data, {
291
510
  isProactivePushEnabled: deps.isProactivePushEnabled,
511
+ getVoiceReplyMode: deps.getVoiceReplyMode,
512
+ isVoiceReplyModeConfigured: deps.isVoiceReplyModeConfigured,
513
+ getTimeInjectionMode: deps.getTimeInjectionMode,
292
514
  setProactivePushEnabled: deps.setProactivePushEnabled,
515
+ setVoiceReplyMode: deps.setVoiceReplyMode,
516
+ setTimeInjectionMode: deps.setTimeInjectionMode,
293
517
  updateSettingsMessage: (text, replyMarkup) =>
294
518
  deps.editInteractiveMessage(
295
519
  state.chatId,
@@ -30,6 +30,7 @@ export interface TelegramStatusMenuCallbackDeps {
30
30
  callbackQueryId: string,
31
31
  text?: string,
32
32
  ) => Promise<void>;
33
+ isVoiceReplyActive?: () => boolean;
33
34
  }
34
35
 
35
36
  export interface TelegramStatusMenuOpenDeps<
@@ -131,6 +132,13 @@ export async function handleTelegramStatusMenuCallbackAction(
131
132
  return true;
132
133
  }
133
134
  if (!isTelegramStatusMenuCallbackAction(data, "thinking")) return false;
135
+ if (deps.isVoiceReplyActive?.()) {
136
+ await deps.answerCallbackQuery(
137
+ callbackQueryId,
138
+ "Thinking controls are disabled during voice replies.",
139
+ );
140
+ return true;
141
+ }
134
142
  if (!activeModel?.reasoning) {
135
143
  await deps.answerCallbackQuery(
136
144
  callbackQueryId,
@@ -148,6 +156,7 @@ export function buildStatusReplyMarkup(
148
156
  currentThinkingLevel: ThinkingLevel,
149
157
  queueItemCount = 0,
150
158
  sectionRegistry?: TelegramSectionRegistry,
159
+ isVoiceReplyActive?: boolean,
151
160
  ): TelegramReplyMarkup {
152
161
  const rows: Array<Array<{ text: string; callback_data: string }>> = [];
153
162
  rows.push([
@@ -159,7 +168,7 @@ export function buildStatusReplyMarkup(
159
168
  callback_data: "menu:model",
160
169
  },
161
170
  ]);
162
- if (activeModel?.reasoning) {
171
+ if (activeModel?.reasoning && !isVoiceReplyActive) {
163
172
  rows.push([
164
173
  {
165
174
  text: formatStatusButtonLabel(
@@ -176,11 +185,10 @@ export function buildStatusReplyMarkup(
176
185
  callback_data: "menu:queue",
177
186
  },
178
187
  ]);
179
- // Extension section rows before Settings
180
188
  if (sectionRegistry) {
181
189
  const sectionRows = getTelegramSectionMainMenuRows(sectionRegistry);
182
190
  for (const row of sectionRows) {
183
- rows.push([{ text: row.text, callback_data: row.callback_data }]);
191
+ rows.push([row]);
184
192
  }
185
193
  }
186
194
  rows.push([
@@ -198,6 +206,7 @@ export function buildTelegramStatusMenuRenderPayload(
198
206
  currentThinkingLevel: ThinkingLevel,
199
207
  queueItemCount = 0,
200
208
  sectionRegistry?: TelegramSectionRegistry,
209
+ isVoiceReplyActive?: boolean,
201
210
  ): TelegramMenuRenderPayload {
202
211
  return {
203
212
  nextMode: "status",
@@ -208,6 +217,7 @@ export function buildTelegramStatusMenuRenderPayload(
208
217
  currentThinkingLevel,
209
218
  queueItemCount,
210
219
  sectionRegistry,
220
+ isVoiceReplyActive,
211
221
  ),
212
222
  };
213
223
  }
@@ -220,6 +230,7 @@ export async function updateTelegramStatusMessage(
220
230
  deps: TelegramMenuMessageRuntimeDeps,
221
231
  queueItemCount = 0,
222
232
  sectionRegistry?: TelegramSectionRegistry,
233
+ isVoiceReplyActive?: boolean,
223
234
  ): Promise<void> {
224
235
  await editTelegramMenuMessage(
225
236
  state,
@@ -229,6 +240,7 @@ export async function updateTelegramStatusMessage(
229
240
  currentThinkingLevel,
230
241
  queueItemCount,
231
242
  sectionRegistry,
243
+ isVoiceReplyActive,
232
244
  ),
233
245
  deps,
234
246
  );
@@ -242,6 +254,7 @@ export function sendTelegramStatusMessage(
242
254
  deps: TelegramMenuMessageRuntimeDeps,
243
255
  queueItemCount = 0,
244
256
  sectionRegistry?: TelegramSectionRegistry,
257
+ isVoiceReplyActive?: boolean,
245
258
  ): Promise<number | undefined> {
246
259
  return sendTelegramMenuMessage(
247
260
  state,
@@ -251,6 +264,7 @@ export function sendTelegramStatusMessage(
251
264
  currentThinkingLevel,
252
265
  queueItemCount,
253
266
  sectionRegistry,
267
+ isVoiceReplyActive,
254
268
  ),
255
269
  deps,
256
270
  );
@@ -25,6 +25,7 @@ export interface TelegramThinkingMenuCallbackDeps {
25
25
  callbackQueryId: string,
26
26
  text?: string,
27
27
  ) => Promise<void>;
28
+ isVoiceReplyActive?: () => boolean;
28
29
  }
29
30
 
30
31
  export interface TelegramThinkingMenuOpenDeps<
@@ -34,6 +35,7 @@ export interface TelegramThinkingMenuOpenDeps<
34
35
  getActiveModel: () => TModel | undefined;
35
36
  getThinkingLevel: () => ThinkingLevel;
36
37
  storeModelMenuState: (state: TelegramModelMenuState<TModel>) => void;
38
+ isVoiceReplyActive?: () => boolean;
37
39
  }
38
40
 
39
41
  function parseTelegramThinkingMenuCallbackAction(
@@ -92,6 +94,13 @@ export async function handleTelegramThinkingMenuCallbackAction(
92
94
  await deps.answerCallbackQuery(callbackQueryId, "Invalid thinking level.");
93
95
  return true;
94
96
  }
97
+ if (deps.isVoiceReplyActive?.()) {
98
+ await deps.answerCallbackQuery(
99
+ callbackQueryId,
100
+ "Thinking controls are disabled during voice replies.",
101
+ );
102
+ return true;
103
+ }
95
104
  if (!activeModel?.reasoning) {
96
105
  await deps.answerCallbackQuery(
97
106
  callbackQueryId,
@@ -142,6 +151,7 @@ export function buildTelegramThinkingMenuRenderPayload(
142
151
  export async function openTelegramThinkingMenu<
143
152
  TModel extends MenuModel = MenuModel,
144
153
  >(deps: TelegramThinkingMenuOpenDeps<TModel>): Promise<void> {
154
+ if (deps.isVoiceReplyActive?.()) return;
145
155
  const state = await deps.getModelMenuState();
146
156
  const messageId = await sendTelegramMenuMessage(
147
157
  state,
@@ -161,8 +171,9 @@ export async function updateTelegramThinkingMenuMessage(
161
171
  state: TelegramModelMenuState,
162
172
  activeModel: MenuModel | undefined,
163
173
  currentThinkingLevel: ThinkingLevel,
164
- deps: TelegramMenuMessageRuntimeDeps,
174
+ deps: TelegramMenuMessageRuntimeDeps & { isVoiceReplyActive?: () => boolean },
165
175
  ): Promise<void> {
176
+ if (deps.isVoiceReplyActive?.()) return;
166
177
  await editTelegramMenuMessage(
167
178
  state,
168
179
  buildTelegramThinkingMenuRenderPayload(activeModel, currentThinkingLevel),
package/lib/menu.ts CHANGED
@@ -239,6 +239,7 @@ export interface TelegramMenuCallbackRuntimeDeps<
239
239
  ) => Promise<number | undefined>;
240
240
  enqueueSectionPrompt?: (prompt: string, ctx: TContext) => Promise<void>;
241
241
  deleteMessage?: (chatId: number, messageId: number) => Promise<void>;
242
+ isVoiceReplyActive?: () => boolean;
242
243
  }
243
244
 
244
245
  export interface TelegramMenuActionRuntimeDeps<
@@ -262,6 +263,7 @@ export interface TelegramMenuActionRuntimeDeps<
262
263
  text: string,
263
264
  ) => Promise<unknown>;
264
265
  sectionRegistry?: TelegramSectionRegistry;
266
+ isVoiceReplyActive?: () => boolean;
265
267
  }
266
268
 
267
269
  export interface TelegramMenuActionRuntime<
@@ -639,6 +641,7 @@ export async function handleTelegramMenuCallbackRuntime<
639
641
  updateSettingsMenuMessage: () =>
640
642
  deps.updateSettingsMenuMessage?.(state, ctx) ?? Promise.resolve(),
641
643
  answerCallbackQuery: deps.answerCallbackQuery,
644
+ isVoiceReplyActive: deps.isVoiceReplyActive,
642
645
  },
643
646
  ),
644
647
  handleThinkingAction: async (state) =>
@@ -654,6 +657,7 @@ export async function handleTelegramMenuCallbackRuntime<
654
657
  getCurrentThinkingLevel: deps.getThinkingLevel,
655
658
  updateStatusMessage: () => deps.updateStatusMessage(state, ctx),
656
659
  answerCallbackQuery: deps.answerCallbackQuery,
660
+ isVoiceReplyActive: deps.isVoiceReplyActive,
657
661
  },
658
662
  ),
659
663
  handleModelAction: async (state) => {
@@ -708,7 +712,9 @@ export interface TelegramMenuActionRuntimeWithStateBuilderDeps<
708
712
  >
709
713
  extends
710
714
  Omit<TelegramMenuActionRuntimeDeps<TContext, TModel>, "getModelMenuState">,
711
- TelegramModelMenuStateBuilderDeps<TModel, TContext> {}
715
+ TelegramModelMenuStateBuilderDeps<TModel, TContext> {
716
+ isVoiceReplyActive?: () => boolean;
717
+ }
712
718
 
713
719
  export function createTelegramMenuActionRuntimeWithStateBuilder<
714
720
  TModel extends MenuModel = MenuModel,
@@ -762,6 +768,7 @@ export function createTelegramMenuActionRuntime<
762
768
  deps,
763
769
  deps.getQueueItemCount?.() ?? 0,
764
770
  deps.sectionRegistry,
771
+ deps.isVoiceReplyActive?.(),
765
772
  ),
766
773
  sendStatusMessage: (chatId, replyToMessageId, ctx) =>
767
774
  openTelegramStatusMenu({
@@ -793,6 +800,7 @@ export function createTelegramMenuActionRuntime<
793
800
  deps,
794
801
  queueItemCount,
795
802
  deps.sectionRegistry,
803
+ deps.isVoiceReplyActive?.(),
796
804
  ),
797
805
  storeModelMenuState: deps.storeModelMenuState,
798
806
  }),
@@ -829,6 +837,7 @@ export function createTelegramMenuActionRuntime<
829
837
  storeModelMenuState: deps.storeModelMenuState,
830
838
  editInteractiveMessage: deps.editInteractiveMessage,
831
839
  sendInteractiveMessage: deps.sendInteractiveMessage,
840
+ isVoiceReplyActive: deps.isVoiceReplyActive,
832
841
  }),
833
842
  };
834
843
  }