@markusylisiurunen/tau 0.3.1 → 0.3.3
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 +15 -57
- package/dist/core/cli.js +2 -2
- package/dist/core/cli.js.map +1 -1
- package/dist/core/config/content_loader.js +3 -3
- package/dist/core/config/content_loader.js.map +1 -1
- package/dist/core/config/index.js.map +1 -1
- package/dist/core/config/schema.js +0 -159
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/personas.js +2 -2
- package/dist/core/personas.js.map +1 -1
- package/dist/core/subagents/control_plane.js +12 -4
- package/dist/core/subagents/control_plane.js.map +1 -1
- package/dist/core/{async/telegram.js → telegram/adapter.js} +229 -329
- package/dist/core/telegram/adapter.js.map +1 -0
- package/dist/core/telegram/cli.js +148 -0
- package/dist/core/telegram/cli.js.map +1 -0
- package/dist/core/telegram/config.js +241 -0
- package/dist/core/telegram/config.js.map +1 -0
- package/dist/core/telegram/index.js +4 -0
- package/dist/core/telegram/index.js.map +1 -0
- package/dist/core/telegram/runtime.js +96 -0
- package/dist/core/telegram/runtime.js.map +1 -0
- package/dist/core/{async → telegram}/session_manager.js +22 -22
- package/dist/core/telegram/session_manager.js.map +1 -0
- package/dist/core/telegram/workspace.js.map +1 -0
- package/dist/core/tools/catalog.js +2 -2
- package/dist/core/tools/catalog.js.map +1 -1
- package/dist/core/tools/registry.js.map +1 -1
- package/dist/core/tools/spawn_agent.js +1 -1
- package/dist/core/tools/spawn_agent.js.map +1 -1
- package/dist/core/tools/tool_names.js +2 -2
- package/dist/core/tools/tool_names.js.map +1 -1
- package/dist/core/tools/{wait_for_agent.js → wait_for_agents.js} +30 -22
- package/dist/core/tools/wait_for_agents.js.map +1 -0
- package/dist/core/version.js +1 -1
- package/dist/main.js +7 -7
- package/dist/main.js.map +1 -1
- package/dist/tui/tool_ui_router.js +7 -7
- package/dist/tui/tool_ui_router.js.map +1 -1
- package/dist/tui/ui/tool_ui_registry.js +3 -3
- package/dist/tui/ui/tool_ui_registry.js.map +1 -1
- package/package.json +1 -1
- package/dist/core/async/cli.js +0 -557
- package/dist/core/async/cli.js.map +0 -1
- package/dist/core/async/cron.js +0 -370
- package/dist/core/async/cron.js.map +0 -1
- package/dist/core/async/daemon_runtime.js +0 -120
- package/dist/core/async/daemon_runtime.js.map +0 -1
- package/dist/core/async/http_protocol.js +0 -177
- package/dist/core/async/http_protocol.js.map +0 -1
- package/dist/core/async/http_server.js +0 -278
- package/dist/core/async/http_server.js.map +0 -1
- package/dist/core/async/index.js +0 -10
- package/dist/core/async/index.js.map +0 -1
- package/dist/core/async/server_config.js +0 -420
- package/dist/core/async/server_config.js.map +0 -1
- package/dist/core/async/session_manager.js.map +0 -1
- package/dist/core/async/telegram.js.map +0 -1
- package/dist/core/async/workspace.js.map +0 -1
- package/dist/core/tools/wait_for_agent.js.map +0 -1
- /package/dist/core/{async → telegram}/workspace.js +0 -0
|
@@ -4,7 +4,7 @@ import { basename, extname, join } from "node:path";
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { transcribeAudio } from "../utils/speech_to_text.js";
|
|
6
6
|
import { formatZodError } from "../utils/zod.js";
|
|
7
|
-
import {
|
|
7
|
+
import { createScopedTelegramSessionManager, TelegramSessionManagerError, } from "./session_manager.js";
|
|
8
8
|
const DEFAULT_POLL_INTERVAL_MS = 1000;
|
|
9
9
|
const DEFAULT_REQUEST_TIMEOUT_SECONDS = 30;
|
|
10
10
|
const MAX_COMMAND_PREVIEW_CHARS = 128;
|
|
@@ -17,19 +17,22 @@ const DEFAULT_TELEGRAM_DOCUMENT_MIME_TYPE = "application/octet-stream";
|
|
|
17
17
|
const MESSAGE_QUEUED_REACTION_EMOJI = "👀";
|
|
18
18
|
const MESSAGE_QUEUED_REACTION_DELAY_MS = 1000;
|
|
19
19
|
const TELEGRAM_MAX_MESSAGE_BYTES = 4096;
|
|
20
|
+
const TELEGRAM_MAX_RICH_MESSAGE_BYTES = 32 * 1024;
|
|
20
21
|
const TELEGRAM_MESSAGE_BYTE_BUFFER_RATIO = 0.95;
|
|
21
22
|
const TELEGRAM_SAFE_MESSAGE_BYTES = Math.floor(TELEGRAM_MAX_MESSAGE_BYTES * TELEGRAM_MESSAGE_BYTE_BUFFER_RATIO);
|
|
23
|
+
const TELEGRAM_RICH_MESSAGE_SAFE_BYTES = Math.floor(TELEGRAM_MAX_RICH_MESSAGE_BYTES * TELEGRAM_MESSAGE_BYTE_BUFFER_RATIO);
|
|
22
24
|
const TELEGRAM_MESSAGE_SPLIT_DELAY_MS = 1000;
|
|
25
|
+
const TELEGRAM_DRAFT_MAX_CHARS = 4096;
|
|
26
|
+
const TELEGRAM_DRAFT_PREAMBLE_VISIBLE_MS = 5000;
|
|
27
|
+
const TELEGRAM_TYPING_REFRESH_MS = 4000;
|
|
23
28
|
const ABORTED = Symbol("aborted");
|
|
24
29
|
const CALLBACK_ACTION_PREFIX = "tau:action:";
|
|
25
|
-
const CALLBACK_USE_PREFIX = "tau:use:";
|
|
26
|
-
const MAX_SESSION_PREVIEW_CHARS = 64;
|
|
27
30
|
const MAX_TELEGRAM_ATTACHMENTS_PER_TURN = 10;
|
|
28
31
|
const MAX_TELEGRAM_ATTACHMENT_FILE_BYTES = 20 * 1024 * 1024;
|
|
29
32
|
const MAX_TELEGRAM_ATTACHMENT_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
30
33
|
const MAX_TELEGRAM_GROUP_PENDING_MESSAGES = 50;
|
|
31
34
|
const TELEGRAM_ATTACHMENT_TEMP_DIR_PREFIX = "tau-telegram-attachments-";
|
|
32
|
-
const NO_ACTIVE_SESSION_MESSAGE = "no active session. use /new
|
|
35
|
+
const NO_ACTIVE_SESSION_MESSAGE = "no active session. use /new";
|
|
33
36
|
const SUPPORTED_TEXT_ATTACHMENT_EXTENSIONS = new Set([
|
|
34
37
|
".txt",
|
|
35
38
|
".md",
|
|
@@ -98,11 +101,6 @@ async function sweepStaleTelegramAttachmentTempDirs() {
|
|
|
98
101
|
return;
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
|
-
const QUICK_ACTION_ROWS = [
|
|
102
|
-
["new", "sessions", "status"],
|
|
103
|
-
["interrupt", "close"],
|
|
104
|
-
["quiet", "verbose"],
|
|
105
|
-
];
|
|
106
104
|
function splitCommandText(text) {
|
|
107
105
|
return text
|
|
108
106
|
.trim()
|
|
@@ -196,15 +194,15 @@ function truncateText(text, maxChars) {
|
|
|
196
194
|
}
|
|
197
195
|
return `${trimmed.slice(0, maxChars - 1)}…`;
|
|
198
196
|
}
|
|
199
|
-
function
|
|
200
|
-
if (Buffer.byteLength(text, "utf8") <=
|
|
197
|
+
function splitTelegramTextByBytes(text, maxBytes) {
|
|
198
|
+
if (Buffer.byteLength(text, "utf8") <= maxBytes) {
|
|
201
199
|
return [text];
|
|
202
200
|
}
|
|
203
201
|
const chunks = [];
|
|
204
202
|
let currentChunk = "";
|
|
205
203
|
for (const character of text) {
|
|
206
204
|
const nextChunk = `${currentChunk}${character}`;
|
|
207
|
-
if (Buffer.byteLength(nextChunk, "utf8") <=
|
|
205
|
+
if (Buffer.byteLength(nextChunk, "utf8") <= maxBytes) {
|
|
208
206
|
currentChunk = nextChunk;
|
|
209
207
|
continue;
|
|
210
208
|
}
|
|
@@ -220,6 +218,12 @@ function splitTelegramMessage(text) {
|
|
|
220
218
|
}
|
|
221
219
|
return chunks;
|
|
222
220
|
}
|
|
221
|
+
function splitTelegramMessage(text) {
|
|
222
|
+
return splitTelegramTextByBytes(text, TELEGRAM_SAFE_MESSAGE_BYTES);
|
|
223
|
+
}
|
|
224
|
+
function splitTelegramRichMessage(text) {
|
|
225
|
+
return splitTelegramTextByBytes(text, TELEGRAM_RICH_MESSAGE_SAFE_BYTES);
|
|
226
|
+
}
|
|
223
227
|
function normalizeSizeBytes(value) {
|
|
224
228
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
225
229
|
return undefined;
|
|
@@ -478,6 +482,28 @@ function createTelegramApi(botToken) {
|
|
|
478
482
|
...(options?.replyMarkup ? { reply_markup: options.replyMarkup } : {}),
|
|
479
483
|
}, z.unknown());
|
|
480
484
|
},
|
|
485
|
+
async sendRichMessage(chatId, markdown, options) {
|
|
486
|
+
await callTelegramMethod("sendRichMessage", {
|
|
487
|
+
chat_id: chatId,
|
|
488
|
+
rich_message: {
|
|
489
|
+
markdown,
|
|
490
|
+
},
|
|
491
|
+
...(options?.replyMarkup ? { reply_markup: options.replyMarkup } : {}),
|
|
492
|
+
}, z.unknown());
|
|
493
|
+
},
|
|
494
|
+
async sendMessageDraft(chatId, draftId, text) {
|
|
495
|
+
await callTelegramMethod("sendMessageDraft", {
|
|
496
|
+
chat_id: chatId,
|
|
497
|
+
draft_id: draftId,
|
|
498
|
+
text,
|
|
499
|
+
}, TelegramAckResultSchema);
|
|
500
|
+
},
|
|
501
|
+
async sendChatAction(chatId, action) {
|
|
502
|
+
await callTelegramMethod("sendChatAction", {
|
|
503
|
+
chat_id: chatId,
|
|
504
|
+
action,
|
|
505
|
+
}, TelegramAckResultSchema);
|
|
506
|
+
},
|
|
481
507
|
async downloadFile(fileId) {
|
|
482
508
|
const parsed = await callTelegramMethod("getFile", {
|
|
483
509
|
file_id: fileId,
|
|
@@ -514,7 +540,7 @@ function createTelegramApi(botToken) {
|
|
|
514
540
|
},
|
|
515
541
|
};
|
|
516
542
|
}
|
|
517
|
-
class
|
|
543
|
+
class TelegramAdapterImpl {
|
|
518
544
|
projects;
|
|
519
545
|
defaultProjectId;
|
|
520
546
|
systemMessage;
|
|
@@ -540,7 +566,9 @@ class AsyncTelegramAdapterImpl {
|
|
|
540
566
|
activeSessionsByChat = new Map();
|
|
541
567
|
sessionsByChat = new Map();
|
|
542
568
|
chatsBySession = new Map();
|
|
543
|
-
|
|
569
|
+
chatTypesByChat = new Map();
|
|
570
|
+
typingIntervalsBySessionChat = new Map();
|
|
571
|
+
draftStatesBySessionChat = new Map();
|
|
544
572
|
lastCommandBySession = new Map();
|
|
545
573
|
lastAssistantMessageBySession = new Map();
|
|
546
574
|
latestAssistantMessageByRun = new Map();
|
|
@@ -612,6 +640,10 @@ class AsyncTelegramAdapterImpl {
|
|
|
612
640
|
try {
|
|
613
641
|
await this.loopPromise;
|
|
614
642
|
await this.waitForInFlightUpdateTasks();
|
|
643
|
+
for (const sessionId of Array.from(this.chatsBySession.keys())) {
|
|
644
|
+
this.stopTypingIndicators(sessionId);
|
|
645
|
+
this.clearSessionDrafts(sessionId);
|
|
646
|
+
}
|
|
615
647
|
for (const sessionId of Array.from(this.attachmentTempDirsBySession.keys())) {
|
|
616
648
|
await this.cleanupSessionAttachmentTempDirs(sessionId);
|
|
617
649
|
}
|
|
@@ -627,38 +659,13 @@ class AsyncTelegramAdapterImpl {
|
|
|
627
659
|
}
|
|
628
660
|
createCommandDefinitions() {
|
|
629
661
|
return [
|
|
630
|
-
{
|
|
631
|
-
command: "/help",
|
|
632
|
-
description: "show supported commands",
|
|
633
|
-
usage: "/help",
|
|
634
|
-
handler: async (chatId) => this.handleHelp(chatId),
|
|
635
|
-
},
|
|
636
662
|
{
|
|
637
663
|
command: "/new",
|
|
638
664
|
description: "start a new session",
|
|
639
|
-
usage: "/new
|
|
665
|
+
usage: "/new",
|
|
640
666
|
callbackAction: "new",
|
|
641
667
|
handler: async (chatId, args, sourceMessageId) => this.handleNew(chatId, args, sourceMessageId),
|
|
642
668
|
},
|
|
643
|
-
{
|
|
644
|
-
command: "/projects",
|
|
645
|
-
description: "list configured projects",
|
|
646
|
-
usage: "/projects",
|
|
647
|
-
handler: async (chatId) => this.handleProjects(chatId),
|
|
648
|
-
},
|
|
649
|
-
{
|
|
650
|
-
command: "/use",
|
|
651
|
-
description: "switch active session",
|
|
652
|
-
usage: "/use <sessionId|prefix|index>",
|
|
653
|
-
handler: async (chatId, args) => this.handleUse(chatId, args),
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
command: "/sessions",
|
|
657
|
-
description: "list sessions",
|
|
658
|
-
usage: "/sessions",
|
|
659
|
-
callbackAction: "sessions",
|
|
660
|
-
handler: async (chatId) => this.handleSessions(chatId),
|
|
661
|
-
},
|
|
662
669
|
{
|
|
663
670
|
command: "/status",
|
|
664
671
|
description: "show active session status",
|
|
@@ -673,33 +680,9 @@ class AsyncTelegramAdapterImpl {
|
|
|
673
680
|
callbackAction: "interrupt",
|
|
674
681
|
handler: async (chatId) => this.handleInterrupt(chatId),
|
|
675
682
|
},
|
|
676
|
-
{
|
|
677
|
-
command: "/close",
|
|
678
|
-
description: "close session(s)",
|
|
679
|
-
usage: "/close [<sessionId>|all]",
|
|
680
|
-
callbackAction: "close",
|
|
681
|
-
handler: async (chatId, args) => this.handleClose(chatId, args),
|
|
682
|
-
},
|
|
683
|
-
{
|
|
684
|
-
command: "/verbose",
|
|
685
|
-
description: "stream progress updates",
|
|
686
|
-
usage: "/verbose",
|
|
687
|
-
callbackAction: "verbose",
|
|
688
|
-
handler: async (chatId) => this.handleVerbosityCommand(chatId, "verbose"),
|
|
689
|
-
},
|
|
690
|
-
{
|
|
691
|
-
command: "/quiet",
|
|
692
|
-
description: "only send final assistant message",
|
|
693
|
-
usage: "/quiet",
|
|
694
|
-
callbackAction: "quiet",
|
|
695
|
-
handler: async (chatId) => this.handleVerbosityCommand(chatId, "quiet"),
|
|
696
|
-
},
|
|
697
683
|
];
|
|
698
684
|
}
|
|
699
685
|
async syncCommands() {
|
|
700
|
-
if (!this.api.setCommands) {
|
|
701
|
-
return;
|
|
702
|
-
}
|
|
703
686
|
const commands = this.commandDefinitions.map((definition) => ({
|
|
704
687
|
command: definition.command.slice(1),
|
|
705
688
|
description: definition.description,
|
|
@@ -837,6 +820,7 @@ class AsyncTelegramAdapterImpl {
|
|
|
837
820
|
if (!chat) {
|
|
838
821
|
return;
|
|
839
822
|
}
|
|
823
|
+
this.chatTypesByChat.set(chat.id, chat.type);
|
|
840
824
|
if (chat.type === "private") {
|
|
841
825
|
await this.handlePrivateMessage(chat.id, message);
|
|
842
826
|
return;
|
|
@@ -1277,7 +1261,7 @@ class AsyncTelegramAdapterImpl {
|
|
|
1277
1261
|
if (!this.enforceChatOwnership) {
|
|
1278
1262
|
return this.sessionManager;
|
|
1279
1263
|
}
|
|
1280
|
-
return
|
|
1264
|
+
return createScopedTelegramSessionManager({
|
|
1281
1265
|
sessionManager: this.sessionManager,
|
|
1282
1266
|
ownerId: this.ownerIdForChat(chatId),
|
|
1283
1267
|
allowedProjectIds: this.allowedProjectIds,
|
|
@@ -1289,20 +1273,12 @@ class AsyncTelegramAdapterImpl {
|
|
|
1289
1273
|
const args = parts.slice(1);
|
|
1290
1274
|
const handler = this.commandHandlers.get(command);
|
|
1291
1275
|
if (!handler) {
|
|
1292
|
-
await this.reply(chatId, "unsupported command.
|
|
1276
|
+
await this.reply(chatId, "unsupported command. supported commands: /new, /status, /interrupt");
|
|
1293
1277
|
return;
|
|
1294
1278
|
}
|
|
1295
1279
|
await handler(chatId, args, sourceMessageId);
|
|
1296
1280
|
}
|
|
1297
1281
|
async handleCallback(chatId, callbackData) {
|
|
1298
|
-
if (callbackData.startsWith(CALLBACK_USE_PREFIX)) {
|
|
1299
|
-
const sessionId = callbackData.slice(CALLBACK_USE_PREFIX.length).trim();
|
|
1300
|
-
if (!sessionId) {
|
|
1301
|
-
return false;
|
|
1302
|
-
}
|
|
1303
|
-
await this.handleUse(chatId, [sessionId]);
|
|
1304
|
-
return true;
|
|
1305
|
-
}
|
|
1306
1282
|
if (!callbackData.startsWith(CALLBACK_ACTION_PREFIX)) {
|
|
1307
1283
|
return false;
|
|
1308
1284
|
}
|
|
@@ -1314,77 +1290,29 @@ class AsyncTelegramAdapterImpl {
|
|
|
1314
1290
|
await handler(chatId, []);
|
|
1315
1291
|
return true;
|
|
1316
1292
|
}
|
|
1317
|
-
async handleHelp(chatId) {
|
|
1318
|
-
const lines = [
|
|
1319
|
-
"commands:",
|
|
1320
|
-
...this.commandDefinitions.map((definition) => definition.usage),
|
|
1321
|
-
"",
|
|
1322
|
-
"tip: use /sessions and tap a session button to switch quickly",
|
|
1323
|
-
];
|
|
1324
|
-
await this.reply(chatId, lines.join("\n"), {
|
|
1325
|
-
replyMarkup: this.buildQuickActionsKeyboard(),
|
|
1326
|
-
});
|
|
1327
|
-
}
|
|
1328
1293
|
resolveNewCommand(args) {
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
if (this.defaultProjectId) {
|
|
1332
|
-
if (!this.projects[this.defaultProjectId]) {
|
|
1333
|
-
return {
|
|
1334
|
-
error: `telegram.<botId>.defaultProjectId '${this.defaultProjectId}' is not configured`,
|
|
1335
|
-
};
|
|
1336
|
-
}
|
|
1337
|
-
return { projectId: this.defaultProjectId };
|
|
1338
|
-
}
|
|
1339
|
-
if (projectIds.length === 1) {
|
|
1340
|
-
return { projectId: projectIds[0] };
|
|
1341
|
-
}
|
|
1342
|
-
if (projectIds.length === 0) {
|
|
1343
|
-
return { error: "no async projects configured" };
|
|
1344
|
-
}
|
|
1345
|
-
return {
|
|
1346
|
-
error: "missing project id. usage: /new [projectId]. use /projects to list options",
|
|
1347
|
-
};
|
|
1348
|
-
};
|
|
1349
|
-
if (args.length > 1) {
|
|
1350
|
-
return { error: "usage: /new [projectId]" };
|
|
1294
|
+
if (args.length > 0) {
|
|
1295
|
+
return { error: "usage: /new" };
|
|
1351
1296
|
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
if (!
|
|
1355
|
-
return { error: "usage: /new [projectId]" };
|
|
1356
|
-
}
|
|
1357
|
-
if (!this.projects[projectId]) {
|
|
1297
|
+
const projectIds = Object.keys(this.projects);
|
|
1298
|
+
if (this.defaultProjectId) {
|
|
1299
|
+
if (!this.projects[this.defaultProjectId]) {
|
|
1358
1300
|
return {
|
|
1359
|
-
error: `
|
|
1301
|
+
error: `telegram.<botId>.defaultProjectId '${this.defaultProjectId}' is not configured`,
|
|
1360
1302
|
};
|
|
1361
1303
|
}
|
|
1362
|
-
return { projectId };
|
|
1304
|
+
return { projectId: this.defaultProjectId };
|
|
1363
1305
|
}
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
};
|
|
1306
|
+
if (projectIds.length === 1) {
|
|
1307
|
+
return { projectId: projectIds[0] };
|
|
1308
|
+
}
|
|
1309
|
+
if (projectIds.length === 0) {
|
|
1310
|
+
return { error: "no telegram projects configured" };
|
|
1369
1311
|
}
|
|
1370
1312
|
return {
|
|
1371
|
-
|
|
1313
|
+
error: "multiple projects configured. set defaultProjectId for this bot before using /new",
|
|
1372
1314
|
};
|
|
1373
1315
|
}
|
|
1374
|
-
async handleProjects(chatId) {
|
|
1375
|
-
const entries = Object.entries(this.projects).sort(([left], [right]) => left.localeCompare(right));
|
|
1376
|
-
if (entries.length === 0) {
|
|
1377
|
-
await this.reply(chatId, "no async projects configured");
|
|
1378
|
-
return;
|
|
1379
|
-
}
|
|
1380
|
-
const lines = entries.map(([projectId, project]) => {
|
|
1381
|
-
if (!project.description) {
|
|
1382
|
-
return projectId;
|
|
1383
|
-
}
|
|
1384
|
-
return `${projectId}: ${project.description}`;
|
|
1385
|
-
});
|
|
1386
|
-
await this.reply(chatId, [`projects:`, ...lines].join("\n"));
|
|
1387
|
-
}
|
|
1388
1316
|
async handleNew(chatId, args, sourceMessageId) {
|
|
1389
1317
|
const parsed = this.resolveNewCommand(args);
|
|
1390
1318
|
if ("error" in parsed) {
|
|
@@ -1393,134 +1321,27 @@ class AsyncTelegramAdapterImpl {
|
|
|
1393
1321
|
}
|
|
1394
1322
|
try {
|
|
1395
1323
|
const sessionManager = this.getSessionManagerForChat(chatId);
|
|
1324
|
+
const previousSession = this.getActiveSession(chatId);
|
|
1325
|
+
if (previousSession) {
|
|
1326
|
+
await sessionManager.closeSession(previousSession.id);
|
|
1327
|
+
this.clearClosedSession(previousSession.id);
|
|
1328
|
+
}
|
|
1396
1329
|
const session = await sessionManager.createSession({
|
|
1397
1330
|
projectId: parsed.projectId,
|
|
1398
1331
|
});
|
|
1399
1332
|
this.setActiveSession(chatId, session.id);
|
|
1400
|
-
this.sessionVerbosityBySession.set(session.id, "quiet");
|
|
1401
1333
|
void this.reactToQueuedMessage(chatId, sourceMessageId);
|
|
1402
1334
|
}
|
|
1403
1335
|
catch (error) {
|
|
1404
1336
|
await this.reply(chatId, this.formatManagerError(error));
|
|
1405
1337
|
}
|
|
1406
1338
|
}
|
|
1407
|
-
async handleUse(chatId, args) {
|
|
1408
|
-
const selector = args[0]?.trim();
|
|
1409
|
-
if (!selector) {
|
|
1410
|
-
await this.reply(chatId, "usage: /use <sessionId|prefix|index>");
|
|
1411
|
-
return;
|
|
1412
|
-
}
|
|
1413
|
-
const sessionManager = this.getSessionManagerForChat(chatId);
|
|
1414
|
-
const sessions = sessionManager.listSessions();
|
|
1415
|
-
const selectedSession = this.resolveSessionSelector(selector, sessions, sessionManager);
|
|
1416
|
-
if ("error" in selectedSession) {
|
|
1417
|
-
await this.reply(chatId, selectedSession.error);
|
|
1418
|
-
return;
|
|
1419
|
-
}
|
|
1420
|
-
this.setActiveSession(chatId, selectedSession.session.id);
|
|
1421
|
-
await this.reply(chatId, `switched to ${formatTelegramSessionName(selectedSession.session)}.`);
|
|
1422
|
-
}
|
|
1423
|
-
resolveSessionSelector(selector, sessions, sessionManager) {
|
|
1424
|
-
const exactSession = sessionManager.getSession(selector);
|
|
1425
|
-
if (exactSession) {
|
|
1426
|
-
return { session: exactSession };
|
|
1427
|
-
}
|
|
1428
|
-
if (/^\d+$/.test(selector)) {
|
|
1429
|
-
const index = Number.parseInt(selector, 10);
|
|
1430
|
-
if (index <= 0 || index > sessions.length) {
|
|
1431
|
-
return {
|
|
1432
|
-
error: sessions.length === 0
|
|
1433
|
-
? "no sessions"
|
|
1434
|
-
: `session index '${selector}' is out of range (1-${sessions.length})`,
|
|
1435
|
-
};
|
|
1436
|
-
}
|
|
1437
|
-
const indexedSession = sessions[index - 1];
|
|
1438
|
-
if (!indexedSession) {
|
|
1439
|
-
return { error: "session index lookup failed" };
|
|
1440
|
-
}
|
|
1441
|
-
return { session: indexedSession };
|
|
1442
|
-
}
|
|
1443
|
-
const prefixMatches = sessions.filter((session) => session.id.startsWith(selector));
|
|
1444
|
-
if (prefixMatches.length === 1) {
|
|
1445
|
-
const [prefixMatch] = prefixMatches;
|
|
1446
|
-
if (!prefixMatch) {
|
|
1447
|
-
return { error: "session prefix lookup failed" };
|
|
1448
|
-
}
|
|
1449
|
-
return { session: prefixMatch };
|
|
1450
|
-
}
|
|
1451
|
-
if (prefixMatches.length > 1) {
|
|
1452
|
-
return {
|
|
1453
|
-
error: `session prefix '${selector}' is ambiguous: ${prefixMatches.map((session) => session.id).join(", ")}`,
|
|
1454
|
-
};
|
|
1455
|
-
}
|
|
1456
|
-
return { error: `session '${selector}' not found` };
|
|
1457
|
-
}
|
|
1458
|
-
async handleSessions(chatId) {
|
|
1459
|
-
const sessionManager = this.getSessionManagerForChat(chatId);
|
|
1460
|
-
const sessions = sessionManager.listSessions();
|
|
1461
|
-
const lines = this.formatSessions(chatId, sessions);
|
|
1462
|
-
await this.reply(chatId, lines.join("\n"), {
|
|
1463
|
-
replyMarkup: this.buildSessionsKeyboard(chatId, sessions),
|
|
1464
|
-
});
|
|
1465
|
-
}
|
|
1466
|
-
formatSessions(chatId, sessions) {
|
|
1467
|
-
if (sessions.length === 0) {
|
|
1468
|
-
return ["no sessions"];
|
|
1469
|
-
}
|
|
1470
|
-
const activeSessionId = this.activeSessionsByChat.get(chatId);
|
|
1471
|
-
return [
|
|
1472
|
-
"sessions:",
|
|
1473
|
-
...sessions.map((session, index) => {
|
|
1474
|
-
const marker = session.id === activeSessionId ? "*" : "-";
|
|
1475
|
-
const preview = this.formatSessionPreview(session.id);
|
|
1476
|
-
return `${index + 1}. ${marker} ${session.id} ${session.projectId} ${session.state}${preview ? ` · ${preview}` : ""}`;
|
|
1477
|
-
}),
|
|
1478
|
-
];
|
|
1479
|
-
}
|
|
1480
|
-
formatSessionPreview(sessionId) {
|
|
1481
|
-
const previews = [];
|
|
1482
|
-
const lastCommand = this.lastCommandBySession.get(sessionId);
|
|
1483
|
-
if (lastCommand) {
|
|
1484
|
-
previews.push(`$ ${truncateText(lastCommand, MAX_SESSION_PREVIEW_CHARS)}`);
|
|
1485
|
-
}
|
|
1486
|
-
const lastAssistantMessage = this.lastAssistantMessageBySession.get(sessionId);
|
|
1487
|
-
if (lastAssistantMessage) {
|
|
1488
|
-
previews.push(truncateText(lastAssistantMessage, MAX_SESSION_PREVIEW_CHARS));
|
|
1489
|
-
}
|
|
1490
|
-
if (previews.length === 0) {
|
|
1491
|
-
return undefined;
|
|
1492
|
-
}
|
|
1493
|
-
return previews.join(" | ");
|
|
1494
|
-
}
|
|
1495
|
-
buildSessionsKeyboard(chatId, sessions) {
|
|
1496
|
-
const activeSessionId = this.activeSessionsByChat.get(chatId);
|
|
1497
|
-
const inlineKeyboard = sessions.map((session, index) => [
|
|
1498
|
-
{
|
|
1499
|
-
text: `${index + 1}. ${session.id}${session.id === activeSessionId ? " *" : ""}`,
|
|
1500
|
-
callback_data: `${CALLBACK_USE_PREFIX}${session.id}`,
|
|
1501
|
-
},
|
|
1502
|
-
]);
|
|
1503
|
-
inlineKeyboard.push(...this.buildQuickActionsKeyboard().inline_keyboard);
|
|
1504
|
-
return {
|
|
1505
|
-
inline_keyboard: inlineKeyboard,
|
|
1506
|
-
};
|
|
1507
|
-
}
|
|
1508
|
-
buildQuickActionsKeyboard() {
|
|
1509
|
-
return {
|
|
1510
|
-
inline_keyboard: QUICK_ACTION_ROWS.map((row) => row.map((action) => ({
|
|
1511
|
-
text: `/${action}`,
|
|
1512
|
-
callback_data: `${CALLBACK_ACTION_PREFIX}${action}`,
|
|
1513
|
-
}))),
|
|
1514
|
-
};
|
|
1515
|
-
}
|
|
1516
1339
|
async handleStatus(chatId) {
|
|
1517
1340
|
const session = await this.requireActiveSession(chatId);
|
|
1518
1341
|
if (!session) {
|
|
1519
1342
|
return;
|
|
1520
1343
|
}
|
|
1521
|
-
await this.reply(chatId, formatSessionStatus(session)
|
|
1522
|
-
replyMarkup: this.buildQuickActionsKeyboard(),
|
|
1523
|
-
});
|
|
1344
|
+
await this.reply(chatId, formatSessionStatus(session));
|
|
1524
1345
|
}
|
|
1525
1346
|
async handleInterrupt(chatId) {
|
|
1526
1347
|
const session = await this.requireActiveSession(chatId);
|
|
@@ -1540,57 +1361,6 @@ class AsyncTelegramAdapterImpl {
|
|
|
1540
1361
|
await this.reply(chatId, this.formatManagerError(error));
|
|
1541
1362
|
}
|
|
1542
1363
|
}
|
|
1543
|
-
async handleClose(chatId, args) {
|
|
1544
|
-
if (args.length > 1) {
|
|
1545
|
-
await this.reply(chatId, "usage: /close [<sessionId>|all]");
|
|
1546
|
-
return;
|
|
1547
|
-
}
|
|
1548
|
-
const target = args[0]?.trim();
|
|
1549
|
-
if (target === "all") {
|
|
1550
|
-
try {
|
|
1551
|
-
const sessionManager = this.getSessionManagerForChat(chatId);
|
|
1552
|
-
const closed = await sessionManager.closeInactiveSessions();
|
|
1553
|
-
for (const session of closed) {
|
|
1554
|
-
this.clearClosedSession(session.id);
|
|
1555
|
-
}
|
|
1556
|
-
if (closed.length === 0) {
|
|
1557
|
-
await this.reply(chatId, "there are no idle sessions to close.");
|
|
1558
|
-
return;
|
|
1559
|
-
}
|
|
1560
|
-
const label = closed.length === 1 ? "session" : "sessions";
|
|
1561
|
-
await this.reply(chatId, `closed ${closed.length} idle ${label}.`);
|
|
1562
|
-
}
|
|
1563
|
-
catch (error) {
|
|
1564
|
-
await this.reply(chatId, this.formatManagerError(error));
|
|
1565
|
-
}
|
|
1566
|
-
return;
|
|
1567
|
-
}
|
|
1568
|
-
const sessionId = target ?? this.getActiveSession(chatId)?.id;
|
|
1569
|
-
if (!sessionId) {
|
|
1570
|
-
await this.reply(chatId, NO_ACTIVE_SESSION_MESSAGE);
|
|
1571
|
-
return;
|
|
1572
|
-
}
|
|
1573
|
-
try {
|
|
1574
|
-
const sessionManager = this.getSessionManagerForChat(chatId);
|
|
1575
|
-
const closed = await sessionManager.closeSession(sessionId);
|
|
1576
|
-
this.clearClosedSession(closed.id);
|
|
1577
|
-
await this.reply(chatId, `closed ${formatTelegramSessionName(closed)}.`);
|
|
1578
|
-
}
|
|
1579
|
-
catch (error) {
|
|
1580
|
-
await this.reply(chatId, this.formatManagerError(error));
|
|
1581
|
-
}
|
|
1582
|
-
}
|
|
1583
|
-
async handleVerbosityCommand(chatId, verbosity) {
|
|
1584
|
-
const session = await this.requireActiveSession(chatId);
|
|
1585
|
-
if (!session) {
|
|
1586
|
-
return;
|
|
1587
|
-
}
|
|
1588
|
-
this.sessionVerbosityBySession.set(session.id, verbosity);
|
|
1589
|
-
const message = verbosity === "quiet"
|
|
1590
|
-
? `${formatTelegramSessionName(session)} is now quiet.`
|
|
1591
|
-
: `${formatTelegramSessionName(session)} will now show progress updates.`;
|
|
1592
|
-
await this.reply(chatId, message);
|
|
1593
|
-
}
|
|
1594
1364
|
async handleMessage(chatId, text, sourceMessageId) {
|
|
1595
1365
|
const session = await this.requireActiveOrSingleSession(chatId);
|
|
1596
1366
|
if (!session) {
|
|
@@ -1893,6 +1663,8 @@ class AsyncTelegramAdapterImpl {
|
|
|
1893
1663
|
}
|
|
1894
1664
|
}
|
|
1895
1665
|
clearClosedSession(sessionId) {
|
|
1666
|
+
this.stopTypingIndicators(sessionId);
|
|
1667
|
+
this.clearSessionDrafts(sessionId);
|
|
1896
1668
|
for (const [chatId, activeSessionId] of this.activeSessionsByChat) {
|
|
1897
1669
|
if (activeSessionId === sessionId) {
|
|
1898
1670
|
this.activeSessionsByChat.delete(chatId);
|
|
@@ -1902,17 +1674,13 @@ class AsyncTelegramAdapterImpl {
|
|
|
1902
1674
|
for (const chatId of chatIds) {
|
|
1903
1675
|
this.unlinkChatFromSession(chatId, sessionId);
|
|
1904
1676
|
}
|
|
1905
|
-
this.sessionVerbosityBySession.delete(sessionId);
|
|
1906
1677
|
this.lastCommandBySession.delete(sessionId);
|
|
1907
1678
|
this.lastAssistantMessageBySession.delete(sessionId);
|
|
1908
1679
|
this.latestAssistantMessageByRun.delete(sessionId);
|
|
1909
1680
|
this.clearSessionAttachments(sessionId);
|
|
1910
1681
|
}
|
|
1911
|
-
|
|
1912
|
-
return
|
|
1913
|
-
}
|
|
1914
|
-
isVerboseSession(sessionId) {
|
|
1915
|
-
return this.getSessionVerbosity(sessionId) === "verbose";
|
|
1682
|
+
isVerboseSession(_sessionId) {
|
|
1683
|
+
return false;
|
|
1916
1684
|
}
|
|
1917
1685
|
onSessionEvent(event) {
|
|
1918
1686
|
if (event.type === "session-progress") {
|
|
@@ -1930,6 +1698,8 @@ class AsyncTelegramAdapterImpl {
|
|
|
1930
1698
|
}
|
|
1931
1699
|
if (event.state === "running") {
|
|
1932
1700
|
this.latestAssistantMessageByRun.delete(event.sessionId);
|
|
1701
|
+
this.startTypingIndicators(event.sessionId);
|
|
1702
|
+
this.showDraftThinking(event.sessionId);
|
|
1933
1703
|
if (this.isVerboseSession(event.sessionId)) {
|
|
1934
1704
|
this.notifyLifecycle(event.sessionId, event.projectId, "started");
|
|
1935
1705
|
}
|
|
@@ -1937,6 +1707,8 @@ class AsyncTelegramAdapterImpl {
|
|
|
1937
1707
|
}
|
|
1938
1708
|
if (event.state === "failed") {
|
|
1939
1709
|
this.latestAssistantMessageByRun.delete(event.sessionId);
|
|
1710
|
+
this.stopTypingIndicators(event.sessionId);
|
|
1711
|
+
this.clearSessionDrafts(event.sessionId);
|
|
1940
1712
|
this.notifyLifecycle(event.sessionId, event.projectId, "failed");
|
|
1941
1713
|
return;
|
|
1942
1714
|
}
|
|
@@ -1945,6 +1717,8 @@ class AsyncTelegramAdapterImpl {
|
|
|
1945
1717
|
return;
|
|
1946
1718
|
}
|
|
1947
1719
|
if (event.state === "waiting-input" && event.previousState === "running") {
|
|
1720
|
+
this.stopTypingIndicators(event.sessionId);
|
|
1721
|
+
this.clearSessionDrafts(event.sessionId);
|
|
1948
1722
|
if (this.isVerboseSession(event.sessionId)) {
|
|
1949
1723
|
this.notifyLifecycle(event.sessionId, event.projectId, "finished");
|
|
1950
1724
|
return;
|
|
@@ -1952,7 +1726,7 @@ class AsyncTelegramAdapterImpl {
|
|
|
1952
1726
|
const message = this.latestAssistantMessageByRun.get(event.sessionId);
|
|
1953
1727
|
this.latestAssistantMessageByRun.delete(event.sessionId);
|
|
1954
1728
|
if (message) {
|
|
1955
|
-
this.notifySession(event.sessionId, message);
|
|
1729
|
+
this.notifySession(event.sessionId, message, { rich: true });
|
|
1956
1730
|
}
|
|
1957
1731
|
}
|
|
1958
1732
|
}
|
|
@@ -1985,6 +1759,7 @@ class AsyncTelegramAdapterImpl {
|
|
|
1985
1759
|
}
|
|
1986
1760
|
this.lastAssistantMessageBySession.set(event.sessionId, event.progress.text);
|
|
1987
1761
|
this.latestAssistantMessageByRun.set(event.sessionId, event.progress.text);
|
|
1762
|
+
this.showDraftPreamble(event.sessionId, event.progress.text);
|
|
1988
1763
|
if (!isVerbose) {
|
|
1989
1764
|
return;
|
|
1990
1765
|
}
|
|
@@ -2002,19 +1777,138 @@ class AsyncTelegramAdapterImpl {
|
|
|
2002
1777
|
}
|
|
2003
1778
|
this.notifySession(sessionId, [formatSessionHeadline(sessionId, stateLabel), `project: ${projectId}`].join("\n"));
|
|
2004
1779
|
}
|
|
2005
|
-
notifySession(sessionId, text) {
|
|
1780
|
+
notifySession(sessionId, text, options = {}) {
|
|
2006
1781
|
const chatIds = this.chatsBySession.get(sessionId);
|
|
2007
1782
|
if (!chatIds || chatIds.size === 0) {
|
|
2008
1783
|
return;
|
|
2009
1784
|
}
|
|
2010
1785
|
for (const chatId of chatIds) {
|
|
2011
|
-
void this.reply(chatId, text)
|
|
1786
|
+
void this.reply(chatId, text, { rich: options.rich }).catch((error) => {
|
|
1787
|
+
this.log("warn", "failed to send telegram notification", {
|
|
1788
|
+
chatId,
|
|
1789
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
1790
|
+
});
|
|
1791
|
+
});
|
|
2012
1792
|
}
|
|
2013
1793
|
}
|
|
2014
|
-
|
|
2015
|
-
|
|
1794
|
+
startTypingIndicators(sessionId) {
|
|
1795
|
+
const chatIds = this.chatsBySession.get(sessionId);
|
|
1796
|
+
if (!chatIds) {
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
for (const chatId of chatIds) {
|
|
1800
|
+
const key = this.getSessionChatKey(sessionId, chatId);
|
|
1801
|
+
if (this.typingIntervalsBySessionChat.has(key)) {
|
|
1802
|
+
continue;
|
|
1803
|
+
}
|
|
1804
|
+
const sendTyping = () => {
|
|
1805
|
+
void this.api.sendChatAction(chatId, "typing").catch((error) => {
|
|
1806
|
+
this.log("warn", "failed to send telegram typing action", {
|
|
1807
|
+
chatId,
|
|
1808
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
1809
|
+
});
|
|
1810
|
+
});
|
|
1811
|
+
};
|
|
1812
|
+
sendTyping();
|
|
1813
|
+
const interval = setInterval(sendTyping, TELEGRAM_TYPING_REFRESH_MS);
|
|
1814
|
+
interval.unref?.();
|
|
1815
|
+
this.typingIntervalsBySessionChat.set(key, interval);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
stopTypingIndicators(sessionId) {
|
|
1819
|
+
const chatIds = this.chatsBySession.get(sessionId);
|
|
1820
|
+
if (!chatIds) {
|
|
1821
|
+
return;
|
|
1822
|
+
}
|
|
1823
|
+
for (const chatId of chatIds) {
|
|
1824
|
+
const key = this.getSessionChatKey(sessionId, chatId);
|
|
1825
|
+
const interval = this.typingIntervalsBySessionChat.get(key);
|
|
1826
|
+
if (interval) {
|
|
1827
|
+
clearInterval(interval);
|
|
1828
|
+
this.typingIntervalsBySessionChat.delete(key);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
showDraftThinking(sessionId) {
|
|
1833
|
+
const chatIds = this.chatsBySession.get(sessionId);
|
|
1834
|
+
if (!chatIds) {
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
for (const chatId of chatIds) {
|
|
1838
|
+
if (this.chatTypesByChat.get(chatId) !== "private") {
|
|
1839
|
+
continue;
|
|
1840
|
+
}
|
|
1841
|
+
void this.updateMessageDraft(sessionId, chatId, "");
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
showDraftPreamble(sessionId, text) {
|
|
1845
|
+
const chatIds = this.chatsBySession.get(sessionId);
|
|
1846
|
+
if (!chatIds) {
|
|
2016
1847
|
return;
|
|
2017
1848
|
}
|
|
1849
|
+
for (const chatId of chatIds) {
|
|
1850
|
+
if (this.chatTypesByChat.get(chatId) !== "private") {
|
|
1851
|
+
continue;
|
|
1852
|
+
}
|
|
1853
|
+
const key = this.getSessionChatKey(sessionId, chatId);
|
|
1854
|
+
const state = this.getDraftState(key);
|
|
1855
|
+
if (state.preambleTimeout) {
|
|
1856
|
+
clearTimeout(state.preambleTimeout);
|
|
1857
|
+
}
|
|
1858
|
+
void this.updateMessageDraft(sessionId, chatId, truncateText(text, TELEGRAM_DRAFT_MAX_CHARS));
|
|
1859
|
+
const timeout = setTimeout(() => {
|
|
1860
|
+
const currentState = this.draftStatesBySessionChat.get(key);
|
|
1861
|
+
if (currentState === state) {
|
|
1862
|
+
void this.updateMessageDraft(sessionId, chatId, "");
|
|
1863
|
+
}
|
|
1864
|
+
}, TELEGRAM_DRAFT_PREAMBLE_VISIBLE_MS);
|
|
1865
|
+
timeout.unref?.();
|
|
1866
|
+
state.preambleTimeout = timeout;
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
async updateMessageDraft(sessionId, chatId, text) {
|
|
1870
|
+
const key = this.getSessionChatKey(sessionId, chatId);
|
|
1871
|
+
const state = this.getDraftState(key);
|
|
1872
|
+
try {
|
|
1873
|
+
await this.api.sendMessageDraft(chatId, state.draftId, text);
|
|
1874
|
+
}
|
|
1875
|
+
catch (error) {
|
|
1876
|
+
this.log("warn", "failed to update telegram message draft", {
|
|
1877
|
+
chatId,
|
|
1878
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
clearSessionDrafts(sessionId) {
|
|
1883
|
+
const chatIds = this.chatsBySession.get(sessionId);
|
|
1884
|
+
if (!chatIds) {
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
for (const chatId of chatIds) {
|
|
1888
|
+
const key = this.getSessionChatKey(sessionId, chatId);
|
|
1889
|
+
const state = this.draftStatesBySessionChat.get(key);
|
|
1890
|
+
if (state?.preambleTimeout) {
|
|
1891
|
+
clearTimeout(state.preambleTimeout);
|
|
1892
|
+
}
|
|
1893
|
+
this.draftStatesBySessionChat.delete(key);
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
getDraftState(key) {
|
|
1897
|
+
const existing = this.draftStatesBySessionChat.get(key);
|
|
1898
|
+
if (existing) {
|
|
1899
|
+
return existing;
|
|
1900
|
+
}
|
|
1901
|
+
const state = { draftId: this.createDraftId() };
|
|
1902
|
+
this.draftStatesBySessionChat.set(key, state);
|
|
1903
|
+
return state;
|
|
1904
|
+
}
|
|
1905
|
+
createDraftId() {
|
|
1906
|
+
return Math.floor(Math.random() * 2_000_000_000) + 1;
|
|
1907
|
+
}
|
|
1908
|
+
getSessionChatKey(sessionId, chatId) {
|
|
1909
|
+
return `${sessionId}:${chatId}`;
|
|
1910
|
+
}
|
|
1911
|
+
async reactToQueuedMessage(chatId, messageId) {
|
|
2018
1912
|
if (typeof messageId !== "number" || !Number.isInteger(messageId) || messageId <= 0) {
|
|
2019
1913
|
return;
|
|
2020
1914
|
}
|
|
@@ -2034,9 +1928,6 @@ class AsyncTelegramAdapterImpl {
|
|
|
2034
1928
|
}
|
|
2035
1929
|
}
|
|
2036
1930
|
async answerCallbackQuery(callbackQueryId, text) {
|
|
2037
|
-
if (!this.api.answerCallbackQuery) {
|
|
2038
|
-
return;
|
|
2039
|
-
}
|
|
2040
1931
|
const trimmedCallbackQueryId = callbackQueryId?.trim();
|
|
2041
1932
|
if (!trimmedCallbackQueryId) {
|
|
2042
1933
|
return;
|
|
@@ -2058,26 +1949,35 @@ class AsyncTelegramAdapterImpl {
|
|
|
2058
1949
|
return formatSessionHeadline(sessionId, "message queued");
|
|
2059
1950
|
}
|
|
2060
1951
|
formatManagerError(error) {
|
|
2061
|
-
if (error instanceof
|
|
1952
|
+
if (error instanceof TelegramSessionManagerError) {
|
|
2062
1953
|
return error.message;
|
|
2063
1954
|
}
|
|
2064
1955
|
return error instanceof Error ? error.message : String(error);
|
|
2065
1956
|
}
|
|
2066
1957
|
async reply(chatId, text, options) {
|
|
2067
|
-
|
|
1958
|
+
if (options?.rich === true) {
|
|
1959
|
+
await this.replyWithRichMessage(chatId, text, options.replyMarkup);
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
await this.replyWithPlainMessage(chatId, text, options?.replyMarkup);
|
|
1963
|
+
}
|
|
1964
|
+
async replyWithRichMessage(chatId, text, replyMarkup) {
|
|
1965
|
+
const chunks = splitTelegramRichMessage(text);
|
|
2068
1966
|
for (const [index, chunk] of chunks.entries()) {
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
catch (error) {
|
|
2075
|
-
this.log("warn", "failed to send telegram message", {
|
|
2076
|
-
chatId,
|
|
2077
|
-
cause: error instanceof Error ? error.message : String(error),
|
|
2078
|
-
});
|
|
2079
|
-
return;
|
|
1967
|
+
await this.api.sendRichMessage(chatId, chunk, {
|
|
1968
|
+
replyMarkup: index === chunks.length - 1 ? replyMarkup : undefined,
|
|
1969
|
+
});
|
|
1970
|
+
if (index < chunks.length - 1) {
|
|
1971
|
+
await this.wait(TELEGRAM_MESSAGE_SPLIT_DELAY_MS);
|
|
2080
1972
|
}
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
async replyWithPlainMessage(chatId, text, replyMarkup) {
|
|
1976
|
+
const chunks = splitTelegramMessage(text);
|
|
1977
|
+
for (const [index, chunk] of chunks.entries()) {
|
|
1978
|
+
await this.api.sendMessage(chatId, chunk, {
|
|
1979
|
+
replyMarkup: index === chunks.length - 1 ? replyMarkup : undefined,
|
|
1980
|
+
});
|
|
2081
1981
|
if (index < chunks.length - 1) {
|
|
2082
1982
|
await this.wait(TELEGRAM_MESSAGE_SPLIT_DELAY_MS);
|
|
2083
1983
|
}
|
|
@@ -2101,14 +2001,14 @@ class AsyncTelegramAdapterImpl {
|
|
|
2101
2001
|
});
|
|
2102
2002
|
}
|
|
2103
2003
|
}
|
|
2104
|
-
export async function
|
|
2004
|
+
export async function startTelegramAdapter(options) {
|
|
2105
2005
|
await sweepStaleTelegramAttachmentTempDirs();
|
|
2106
2006
|
const api = options.api ?? createTelegramApi(options.botToken);
|
|
2107
2007
|
const botUsername = normalizeTelegramUsername((await api.getMe()).username);
|
|
2108
2008
|
if (!botUsername) {
|
|
2109
2009
|
throw new Error("telegram bot username is missing");
|
|
2110
2010
|
}
|
|
2111
|
-
const adapter = new
|
|
2011
|
+
const adapter = new TelegramAdapterImpl({
|
|
2112
2012
|
...options,
|
|
2113
2013
|
api,
|
|
2114
2014
|
botUsername,
|
|
@@ -2117,4 +2017,4 @@ export async function startAsyncTelegramAdapter(options) {
|
|
|
2117
2017
|
close: () => adapter.close(),
|
|
2118
2018
|
};
|
|
2119
2019
|
}
|
|
2120
|
-
//# sourceMappingURL=
|
|
2020
|
+
//# sourceMappingURL=adapter.js.map
|