@markusylisiurunen/tau 0.3.50 → 0.3.52

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.
Files changed (105) hide show
  1. package/dist/code_mode/command.js +26 -14
  2. package/dist/code_mode/command.js.map +1 -1
  3. package/dist/code_mode/index.d.ts +2 -1
  4. package/dist/code_mode/index.js +1 -0
  5. package/dist/code_mode/index.js.map +1 -1
  6. package/dist/core/cli.js +0 -11
  7. package/dist/core/cli.js.map +1 -1
  8. package/dist/core/client_tools/command_client_tools.js +236 -151
  9. package/dist/core/client_tools/command_client_tools.js.map +1 -1
  10. package/dist/core/config/schema.js +8 -2
  11. package/dist/core/config/schema.js.map +1 -1
  12. package/dist/core/history/history_manager.js +73 -7
  13. package/dist/core/history/history_manager.js.map +1 -1
  14. package/dist/core/history/local_history_store.js +73 -2
  15. package/dist/core/history/local_history_store.js.map +1 -1
  16. package/dist/core/history/remote_history_client.js +36 -6
  17. package/dist/core/history/remote_history_client.js.map +1 -1
  18. package/dist/core/modes/index.js +0 -1
  19. package/dist/core/modes/index.js.map +1 -1
  20. package/dist/core/static/tau_docs/client-tools.md +212 -12
  21. package/dist/core/static/tau_docs/config-reference.md +1 -1
  22. package/dist/core/static/tau_docs/configuration.md +1 -1
  23. package/dist/core/static/tau_docs/credentials.md +4 -4
  24. package/dist/core/static/tau_docs/history.md +6 -4
  25. package/dist/core/static/tau_docs/index.md +1 -1
  26. package/dist/core/static/tau_docs/node-sdk.md +33 -26
  27. package/dist/core/static/tau_docs/ownership-and-scope.md +3 -4
  28. package/dist/core/static/tau_docs/prompts-and-project-context.md +2 -2
  29. package/dist/core/static/tau_docs/remote-sessions.md +4 -47
  30. package/dist/core/static/tau_docs/security.md +2 -6
  31. package/dist/core/static/tau_docs/session-protocol-methods.md +48 -7
  32. package/dist/core/static/tau_docs/session-protocol.md +18 -18
  33. package/dist/core/static/tau_docs/sessions.md +6 -5
  34. package/dist/core/static/tau_docs/telegram.md +8 -4
  35. package/dist/core/static/tau_docs/tools.md +1 -1
  36. package/dist/core/static/tau_docs/troubleshooting.md +3 -5
  37. package/dist/core/static/tau_docs/tui.md +4 -6
  38. package/dist/core/telegram/adapter.js +226 -18
  39. package/dist/core/telegram/adapter.js.map +1 -1
  40. package/dist/core/telegram/config.js +1 -1
  41. package/dist/core/telegram/config.js.map +1 -1
  42. package/dist/core/telegram/project_preferences.js +42 -12
  43. package/dist/core/telegram/project_preferences.js.map +1 -1
  44. package/dist/core/telegram/runtime.js +6 -1
  45. package/dist/core/telegram/runtime.js.map +1 -1
  46. package/dist/core/telegram/session_manager.js +50 -4
  47. package/dist/core/telegram/session_manager.js.map +1 -1
  48. package/dist/core/telegram/tts.js +137 -0
  49. package/dist/core/telegram/tts.js.map +1 -0
  50. package/dist/core/tools/execution_backend.js +13 -3
  51. package/dist/core/tools/execution_backend.js.map +1 -1
  52. package/dist/core/tools/presentation.js +55 -17
  53. package/dist/core/tools/presentation.js.map +1 -1
  54. package/dist/core/utils/gemini_speech.js +123 -42
  55. package/dist/core/utils/gemini_speech.js.map +1 -1
  56. package/dist/core/utils/gemini_transcription.js +1 -1
  57. package/dist/core/version.js +1 -1
  58. package/dist/execution/cloudflare_sandbox_execution_environment.js +2 -2
  59. package/dist/execution/cloudflare_sandbox_execution_environment.js.map +1 -1
  60. package/dist/execution/fly_sprite_execution_environment.js +2 -2
  61. package/dist/execution/fly_sprite_execution_environment.js.map +1 -1
  62. package/dist/host/client_tool_broker.js +71 -17
  63. package/dist/host/client_tool_broker.js.map +1 -1
  64. package/dist/host/local_session_host.js +2 -2
  65. package/dist/host/local_session_host.js.map +1 -1
  66. package/dist/host/session_host.js.map +1 -1
  67. package/dist/host/session_protocol_handler.js +17 -6
  68. package/dist/host/session_protocol_handler.js.map +1 -1
  69. package/dist/main.js +18 -92
  70. package/dist/main.js.map +1 -1
  71. package/dist/protocol/session_protocol.d.ts +22 -2
  72. package/dist/protocol/session_protocol.js +47 -3
  73. package/dist/protocol/session_protocol.js.map +1 -1
  74. package/dist/sdk/client_tool_command.d.ts +41 -13
  75. package/dist/sdk/client_tool_command.js +157 -39
  76. package/dist/sdk/client_tool_command.js.map +1 -1
  77. package/dist/sdk/client_tool_presentation.d.ts +17 -0
  78. package/dist/sdk/client_tool_presentation.js +9 -0
  79. package/dist/sdk/client_tool_presentation.js.map +1 -0
  80. package/dist/sdk/code_mode.js +10 -1
  81. package/dist/sdk/code_mode.js.map +1 -1
  82. package/dist/sdk/index.d.ts +5 -4
  83. package/dist/sdk/index.js +2 -1
  84. package/dist/sdk/index.js.map +1 -1
  85. package/dist/sdk/session.js +28 -9
  86. package/dist/sdk/session.js.map +1 -1
  87. package/dist/sdk/types.d.ts +11 -1
  88. package/dist/transport/errors.d.ts +0 -11
  89. package/dist/transport/errors.js +0 -12
  90. package/dist/transport/errors.js.map +1 -1
  91. package/dist/transport/index.d.ts +1 -3
  92. package/dist/transport/index.js +1 -2
  93. package/dist/transport/index.js.map +1 -1
  94. package/dist/tui/session_chat_app.js +28 -15
  95. package/dist/tui/session_chat_app.js.map +1 -1
  96. package/dist/tui/session_chat_controller.js +0 -51
  97. package/dist/tui/session_chat_controller.js.map +1 -1
  98. package/dist/tui/speech_playback.js +3 -3
  99. package/dist/tui/speech_playback.js.map +1 -1
  100. package/package.json +2 -2
  101. package/dist/core/modes/rpc_server.js +0 -105
  102. package/dist/core/modes/rpc_server.js.map +0 -1
  103. package/dist/transport/stdio_session_transport.d.ts +0 -48
  104. package/dist/transport/stdio_session_transport.js +0 -338
  105. package/dist/transport/stdio_session_transport.js.map +0 -1
@@ -9,6 +9,7 @@ import { collectSpeechToTextContext, } from "../utils/speech_to_text_context.js"
9
9
  import { formatTauUserText, splitTauUserText } from "../utils/user_metadata.js";
10
10
  import { formatZodError } from "../utils/zod.js";
11
11
  import { createScopedTelegramSessionManager, TelegramSessionManagerError, } from "./session_manager.js";
12
+ import { generateTelegramVoice } from "./tts.js";
12
13
  const DEFAULT_POLL_INTERVAL_MS = 1000;
13
14
  const DEFAULT_REQUEST_TIMEOUT_SECONDS = 30;
14
15
  const MAX_COMMAND_PREVIEW_CHARS = 128;
@@ -36,6 +37,8 @@ const CALLBACK_ACTION_PREFIX = "tau:action:";
36
37
  const MAX_TELEGRAM_ATTACHMENTS_PER_TURN = 10;
37
38
  const MAX_TELEGRAM_ATTACHMENT_FILE_BYTES = 20 * 1024 * 1024;
38
39
  const MAX_TELEGRAM_ATTACHMENT_TOTAL_BYTES = 50 * 1024 * 1024;
40
+ const MAX_TELEGRAM_VOICE_BYTES = 50 * 1024 * 1024;
41
+ const TELEGRAM_TTS_JOB_TIMEOUT_MS = 5 * 60_000;
39
42
  const MAX_TELEGRAM_GROUP_PENDING_MESSAGES = 50;
40
43
  const TELEGRAM_ATTACHMENT_TEMP_DIR_PREFIX = "tau-telegram-attachments-";
41
44
  const TELEGRAM_REASONING_EFFORTS = [
@@ -617,15 +620,20 @@ function asPermanentTelegramRequestError(error) {
617
620
  }
618
621
  function createTelegramApi(botToken) {
619
622
  const apiUrl = `https://api.telegram.org/bot${botToken}`;
620
- async function callTelegramMethod(method, payload, resultSchema, signal) {
623
+ async function callTelegramMethod(method, payload, resultSchema, signal, upload) {
624
+ const body = upload ? new FormData() : JSON.stringify(payload);
625
+ if (body instanceof FormData && upload) {
626
+ for (const [key, value] of Object.entries(payload)) {
627
+ body.append(key, typeof value === "string" ? value : JSON.stringify(value));
628
+ }
629
+ body.append(upload.field, new Blob([Uint8Array.from(upload.data)], { type: upload.mimeType }), upload.fileName);
630
+ }
621
631
  let response;
622
632
  try {
623
633
  response = await fetch(`${apiUrl}/${method}`, {
624
634
  method: "POST",
625
- headers: {
626
- "content-type": "application/json",
627
- },
628
- body: JSON.stringify(payload),
635
+ ...(upload ? {} : { headers: { "content-type": "application/json" } }),
636
+ body,
629
637
  signal,
630
638
  });
631
639
  }
@@ -716,6 +724,14 @@ function createTelegramApi(botToken) {
716
724
  ...(options?.replyMarkup ? { reply_markup: options.replyMarkup } : {}),
717
725
  }, z.unknown(), options.signal);
718
726
  },
727
+ async sendVoice(chatId, voice, options) {
728
+ await callTelegramMethod("sendVoice", { chat_id: chatId }, z.unknown(), options.signal, {
729
+ field: "voice",
730
+ fileName: "response.ogg",
731
+ mimeType: "audio/ogg",
732
+ data: voice,
733
+ });
734
+ },
719
735
  async sendChatAction(chatId, action) {
720
736
  await callTelegramMethod("sendChatAction", {
721
737
  chat_id: chatId,
@@ -777,6 +793,7 @@ class TelegramAdapterImpl {
777
793
  allowedProjectIds;
778
794
  api;
779
795
  fetchImpl;
796
+ generateVoice;
780
797
  onLog;
781
798
  commandDefinitions;
782
799
  commandHandlers;
@@ -796,6 +813,8 @@ class TelegramAdapterImpl {
796
813
  inFlightUpdateTasks = new Set();
797
814
  notificationQueueTailByChat = new Map();
798
815
  inFlightNotificationTasks = new Set();
816
+ ttsQueueTailBySession = new Map();
817
+ inFlightTtsTasks = new Set();
799
818
  unsubscribeSessionEvents;
800
819
  loopPromise;
801
820
  nextUpdateOffset = 0;
@@ -829,6 +848,7 @@ class TelegramAdapterImpl {
829
848
  this.allowedProjectIds = Object.keys(options.projects);
830
849
  this.api = options.api;
831
850
  this.fetchImpl = options.fetchImpl;
851
+ this.generateVoice = options.generateVoice ?? generateTelegramVoice;
832
852
  this.onLog = options.onLog;
833
853
  this.commandDefinitions = this.createCommandDefinitions();
834
854
  this.commandHandlers = new Map();
@@ -868,6 +888,8 @@ class TelegramAdapterImpl {
868
888
  try {
869
889
  await this.loopPromise;
870
890
  await this.waitForInFlightUpdateTasks();
891
+ await Promise.allSettled(Array.from(this.inFlightTtsTasks));
892
+ this.ttsQueueTailBySession.clear();
871
893
  await Promise.allSettled(Array.from(this.inFlightNotificationTasks));
872
894
  for (const sessionId of Array.from(this.chatsBySession.keys())) {
873
895
  this.stopTypingIndicators(sessionId);
@@ -910,6 +932,16 @@ class TelegramAdapterImpl {
910
932
  callbackAction: "interrupt",
911
933
  handler: async (chatId) => this.handleInterrupt(chatId),
912
934
  },
935
+ {
936
+ command: "/tts_on",
937
+ description: "enable voice responses",
938
+ handler: async (chatId, args) => this.handleTtsPreference(chatId, true, args),
939
+ },
940
+ {
941
+ command: "/tts_off",
942
+ description: "disable voice responses",
943
+ handler: async (chatId, args) => this.handleTtsPreference(chatId, false, args),
944
+ },
913
945
  ];
914
946
  for (const reasoning of TELEGRAM_REASONING_EFFORTS) {
915
947
  definitions.push({
@@ -1588,6 +1620,24 @@ class TelegramAdapterImpl {
1588
1620
  await this.reply(chatId, `failed to save project preference: ${error instanceof Error ? error.message : String(error)}`);
1589
1621
  }
1590
1622
  }
1623
+ async handleTtsPreference(chatId, enabled, args) {
1624
+ const command = enabled ? "/tts_on" : "/tts_off";
1625
+ if (args.length > 0) {
1626
+ await this.reply(chatId, `usage: ${command}`);
1627
+ return;
1628
+ }
1629
+ if (enabled && !this.geminiApiKey) {
1630
+ await this.reply(chatId, "set GEMINI_API_KEY or apiKeys.google to enable voice responses.");
1631
+ return;
1632
+ }
1633
+ try {
1634
+ await this.projectPreferences.setTtsEnabled(this.ownerIdForChat(chatId), enabled);
1635
+ await this.reply(chatId, `voice responses ${enabled ? "enabled" : "disabled"}.`);
1636
+ }
1637
+ catch (error) {
1638
+ await this.reply(chatId, `failed to save voice response preference: ${error instanceof Error ? error.message : String(error)}`);
1639
+ }
1640
+ }
1591
1641
  async handleSetReasoning(chatId, reasoning, args) {
1592
1642
  if (args.length > 0) {
1593
1643
  await this.reply(chatId, `usage: /effort_${reasoning}`);
@@ -2058,6 +2108,12 @@ class TelegramAdapterImpl {
2058
2108
  this.handleSessionProgress(event);
2059
2109
  return;
2060
2110
  }
2111
+ if (event.type === "session-response-completed") {
2112
+ if (this.chatsBySession.has(event.sessionId)) {
2113
+ this.startTtsNotification(event.sessionId, event.text);
2114
+ }
2115
+ return;
2116
+ }
2061
2117
  if (event.type === "session-turn-failed" || event.type === "session-turn-rejected") {
2062
2118
  if (!this.chatsBySession.has(event.sessionId)) {
2063
2119
  return;
@@ -2147,6 +2203,104 @@ class TelegramAdapterImpl {
2147
2203
  ? [formatSessionHeadline(event.sessionId, "assistant message"), event.progress.text].join("\n")
2148
2204
  : event.progress.text, { rich: true, messageId: event.progress.messageId });
2149
2205
  }
2206
+ startTtsNotification(sessionId, sourceText) {
2207
+ const chatIds = this.chatsBySession.get(sessionId);
2208
+ if (!chatIds ||
2209
+ ![...chatIds].some((chatId) => this.projectPreferences.isTtsEnabled(this.ownerIdForChat(chatId)))) {
2210
+ return;
2211
+ }
2212
+ const previousTask = this.ttsQueueTailBySession.get(sessionId) ?? Promise.resolve();
2213
+ const task = previousTask
2214
+ .then(async () => {
2215
+ if (!this.abortController.signal.aborted) {
2216
+ await this.generateAndSendTtsNotification(sessionId, sourceText);
2217
+ }
2218
+ })
2219
+ .finally(() => {
2220
+ this.inFlightTtsTasks.delete(task);
2221
+ if (this.ttsQueueTailBySession.get(sessionId) === task) {
2222
+ this.ttsQueueTailBySession.delete(sessionId);
2223
+ }
2224
+ });
2225
+ this.ttsQueueTailBySession.set(sessionId, task);
2226
+ this.inFlightTtsTasks.add(task);
2227
+ void task;
2228
+ }
2229
+ async generateAndSendTtsNotification(sessionId, sourceText) {
2230
+ let timedOut = false;
2231
+ const timeoutController = new AbortController();
2232
+ const timeout = setTimeout(() => {
2233
+ timedOut = true;
2234
+ timeoutController.abort();
2235
+ }, TELEGRAM_TTS_JOB_TIMEOUT_MS);
2236
+ timeout.unref?.();
2237
+ try {
2238
+ if (!this.geminiApiKey) {
2239
+ throw new Error("missing Google credential for Telegram voice responses");
2240
+ }
2241
+ const voice = await this.generateVoice({
2242
+ apiKey: this.geminiApiKey,
2243
+ sourceText,
2244
+ fetchImpl: this.fetchImpl,
2245
+ signal: AbortSignal.any([this.abortController.signal, timeoutController.signal]),
2246
+ });
2247
+ if (voice.length > MAX_TELEGRAM_VOICE_BYTES) {
2248
+ throw new Error("generated voice response exceeds Telegram's 50 MB limit");
2249
+ }
2250
+ const chatIds = this.chatsBySession.get(sessionId);
2251
+ if (!chatIds) {
2252
+ return;
2253
+ }
2254
+ await Promise.all([...chatIds]
2255
+ .filter((chatId) => this.projectPreferences.isTtsEnabled(this.ownerIdForChat(chatId)))
2256
+ .map(async (chatId) => {
2257
+ const result = await this.enqueueVoiceNotification(sessionId, chatId, voice, timeoutController.signal);
2258
+ if (result === "timed-out") {
2259
+ this.log("error", "Telegram voice response job timed out", {
2260
+ sessionId,
2261
+ chatId,
2262
+ cause: "voice response job timed out after 5 minutes",
2263
+ });
2264
+ }
2265
+ if (result === "failed" || result === "timed-out") {
2266
+ await this.enqueueTtsFailureNotification(sessionId, chatId);
2267
+ }
2268
+ }));
2269
+ }
2270
+ catch (error) {
2271
+ if (this.abortController.signal.aborted) {
2272
+ return;
2273
+ }
2274
+ this.log("error", "failed to generate Telegram voice response", {
2275
+ sessionId,
2276
+ cause: timedOut
2277
+ ? "voice generation timed out after 5 minutes"
2278
+ : error instanceof Error
2279
+ ? error.message
2280
+ : String(error),
2281
+ });
2282
+ await this.notifyTtsFailure(sessionId);
2283
+ }
2284
+ finally {
2285
+ clearTimeout(timeout);
2286
+ }
2287
+ }
2288
+ async notifyTtsFailure(sessionId) {
2289
+ const chatIds = this.chatsBySession.get(sessionId);
2290
+ if (!chatIds) {
2291
+ return;
2292
+ }
2293
+ await Promise.all([...chatIds]
2294
+ .filter((chatId) => this.projectPreferences.isTtsEnabled(this.ownerIdForChat(chatId)))
2295
+ .map(async (chatId) => await this.enqueueTtsFailureNotification(sessionId, chatId)));
2296
+ }
2297
+ async enqueueTtsFailureNotification(sessionId, chatId) {
2298
+ if (this.abortController.signal.aborted ||
2299
+ !this.projectPreferences.isTtsEnabled(this.ownerIdForChat(chatId))) {
2300
+ return;
2301
+ }
2302
+ await this.enqueueNotification(sessionId, chatId, "voice response failed. please try again.", {});
2303
+ }
2150
2304
  notifyLifecycle(sessionId, projectId, state) {
2151
2305
  const sessionName = formatTelegramSessionName(sessionId, projectId);
2152
2306
  if (state === "failed") {
@@ -2207,6 +2361,54 @@ class TelegramAdapterImpl {
2207
2361
  this.inFlightNotificationTasks.add(trackedTask);
2208
2362
  return deliveryTask;
2209
2363
  }
2364
+ enqueueVoiceNotification(sessionId, chatId, voice, jobSignal) {
2365
+ const previousTask = this.notificationQueueTailByChat.get(chatId) ?? Promise.resolve();
2366
+ const deliveryTask = previousTask
2367
+ .then(async () => {
2368
+ if (this.abortController.signal.aborted ||
2369
+ !this.projectPreferences.isTtsEnabled(this.ownerIdForChat(chatId))) {
2370
+ return "skipped";
2371
+ }
2372
+ if (jobSignal.aborted) {
2373
+ return "timed-out";
2374
+ }
2375
+ const result = await this.sendWithRetry(async (signal) => await this.api.sendVoice(chatId, voice, { signal }), jobSignal);
2376
+ if (result === ABORTED) {
2377
+ return jobSignal.aborted && !this.abortController.signal.aborted
2378
+ ? "timed-out"
2379
+ : "skipped";
2380
+ }
2381
+ return "sent";
2382
+ })
2383
+ .catch((error) => {
2384
+ if (this.abortController.signal.aborted) {
2385
+ return "skipped";
2386
+ }
2387
+ const deliveryError = error instanceof TelegramDeliveryError
2388
+ ? error
2389
+ : new TelegramDeliveryError(error, 1, false);
2390
+ this.log("error", deliveryError.retryable
2391
+ ? "telegram voice response delivery retries exhausted"
2392
+ : "failed to send Telegram voice response", {
2393
+ sessionId,
2394
+ chatId,
2395
+ attempts: deliveryError.attempts,
2396
+ cause: deliveryError.message,
2397
+ });
2398
+ return "failed";
2399
+ });
2400
+ const trackedTask = deliveryTask
2401
+ .then(() => undefined)
2402
+ .finally(() => {
2403
+ this.inFlightNotificationTasks.delete(trackedTask);
2404
+ if (this.notificationQueueTailByChat.get(chatId) === trackedTask) {
2405
+ this.notificationQueueTailByChat.delete(chatId);
2406
+ }
2407
+ });
2408
+ this.notificationQueueTailByChat.set(chatId, trackedTask);
2409
+ this.inFlightNotificationTasks.add(trackedTask);
2410
+ return deliveryTask;
2411
+ }
2210
2412
  startTypingIndicators(sessionId) {
2211
2413
  const chatIds = this.chatsBySession.get(sessionId);
2212
2414
  if (!chatIds) {
@@ -2346,17 +2548,17 @@ class TelegramAdapterImpl {
2346
2548
  }
2347
2549
  }
2348
2550
  }
2349
- async sendWithRetry(send) {
2551
+ async sendWithRetry(send, externalSignal) {
2350
2552
  for (let attempt = 1;; attempt += 1) {
2351
2553
  try {
2352
- const result = await this.runDeliveryAttempt(send);
2554
+ const result = await this.runDeliveryAttempt(send, externalSignal);
2353
2555
  if (result === ABORTED) {
2354
2556
  return ABORTED;
2355
2557
  }
2356
2558
  return;
2357
2559
  }
2358
2560
  catch (error) {
2359
- if (this.abortController.signal.aborted) {
2561
+ if (this.abortController.signal.aborted || externalSignal?.aborted) {
2360
2562
  return ABORTED;
2361
2563
  }
2362
2564
  const retryDelayMs = TELEGRAM_DELIVERY_RETRY_DELAYS_MS[attempt - 1];
@@ -2364,15 +2566,18 @@ class TelegramAdapterImpl {
2364
2566
  if (!retryable || retryDelayMs === undefined) {
2365
2567
  throw new TelegramDeliveryError(error, attempt, retryable);
2366
2568
  }
2367
- await this.wait(Math.max(retryDelayMs, error.retryAfterMs ?? 0));
2368
- if (this.abortController.signal.aborted) {
2569
+ await this.wait(Math.max(retryDelayMs, error.retryAfterMs ?? 0), externalSignal);
2570
+ if (this.abortController.signal.aborted || externalSignal?.aborted) {
2369
2571
  return ABORTED;
2370
2572
  }
2371
2573
  }
2372
2574
  }
2373
2575
  }
2374
- async runDeliveryAttempt(send) {
2375
- if (this.abortController.signal.aborted) {
2576
+ async runDeliveryAttempt(send, externalSignal) {
2577
+ const deliverySignal = externalSignal
2578
+ ? AbortSignal.any([this.abortController.signal, externalSignal])
2579
+ : this.abortController.signal;
2580
+ if (deliverySignal.aborted) {
2376
2581
  return ABORTED;
2377
2582
  }
2378
2583
  const attemptController = new AbortController();
@@ -2382,7 +2587,7 @@ class TelegramAdapterImpl {
2382
2587
  resolve(ABORTED);
2383
2588
  attemptController.abort();
2384
2589
  };
2385
- this.abortController.signal.addEventListener("abort", abortListener, { once: true });
2590
+ deliverySignal.addEventListener("abort", abortListener, { once: true });
2386
2591
  });
2387
2592
  let timeout;
2388
2593
  const timeoutPromise = new Promise((resolve) => {
@@ -2405,7 +2610,7 @@ class TelegramAdapterImpl {
2405
2610
  clearTimeout(timeout);
2406
2611
  }
2407
2612
  if (abortListener) {
2408
- this.abortController.signal.removeEventListener("abort", abortListener);
2613
+ deliverySignal.removeEventListener("abort", abortListener);
2409
2614
  }
2410
2615
  if (raceResult === ABORTED) {
2411
2616
  return ABORTED;
@@ -2417,13 +2622,16 @@ class TelegramAdapterImpl {
2417
2622
  throw raceResult.error;
2418
2623
  }
2419
2624
  }
2420
- async wait(durationMs) {
2421
- if (durationMs <= 0 || this.abortController.signal.aborted) {
2625
+ async wait(durationMs, externalSignal) {
2626
+ const waitSignal = externalSignal
2627
+ ? AbortSignal.any([this.abortController.signal, externalSignal])
2628
+ : this.abortController.signal;
2629
+ if (durationMs <= 0 || waitSignal.aborted) {
2422
2630
  return;
2423
2631
  }
2424
2632
  await new Promise((resolve) => {
2425
2633
  const timeout = setTimeout(() => {
2426
- this.abortController.signal.removeEventListener("abort", onAbort);
2634
+ waitSignal.removeEventListener("abort", onAbort);
2427
2635
  resolve();
2428
2636
  }, durationMs);
2429
2637
  timeout.unref?.();
@@ -2431,7 +2639,7 @@ class TelegramAdapterImpl {
2431
2639
  clearTimeout(timeout);
2432
2640
  resolve();
2433
2641
  };
2434
- this.abortController.signal.addEventListener("abort", onAbort, { once: true });
2642
+ waitSignal.addEventListener("abort", onAbort, { once: true });
2435
2643
  });
2436
2644
  }
2437
2645
  }