arisa 5.1.49 → 5.1.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +0 -2
- package/README.md +9 -0
- package/package.json +1 -1
- package/src/core/agent/agent-manager.js +49 -489
- package/src/core/agent/agent-session-lifecycle.js +181 -0
- package/src/core/agent/pi-capability-tools.js +183 -0
- package/src/core/artifacts/artifact-store.js +73 -17
- package/src/core/capabilities/capability-service.js +340 -0
- package/src/core/config/config-defaults.js +28 -1
- package/src/core/tasks/task-routing.js +7 -0
- package/src/core/tasks/task-runner.js +68 -0
- package/src/core/tasks/task-store.js +382 -92
- package/src/core/tools/tool-output-materializer.js +5 -5
- package/src/core/tools/tool-registry.js +20 -5
- package/src/core/tools/weighted-resource-governor.js +153 -0
- package/src/index.js +20 -0
- package/src/official-tools.lock.json +62 -45
- package/src/runtime/arisa-capabilities.js +51 -242
- package/src/runtime/create-app.js +11 -2
- package/src/runtime/create-headless-app.js +7 -4
- package/src/runtime/paths.js +4 -0
- package/src/runtime/service-manager.js +3 -1
- package/src/runtime/service-supervisor.js +98 -0
- package/src/transport/telegram/bot.js +186 -374
- package/src/transport/telegram/chat-queue.js +83 -6
- package/src/transport/telegram/prompt-builders.js +9 -0
- package/src/transport/telegram/reply-topic-routing.js +111 -0
- package/src/transport/telegram/task-dispatcher.js +96 -36
- package/src/transport/telegram/telegram-auth-controller.js +180 -0
- package/src/transport/telegram/telegram-session-bridge.js +177 -0
- package/src/transport/telegram/telegram-tools-command.js +28 -0
- package/src/transport/telegram/telegram-workspace-controller.js +66 -0
- package/src/transport/telegram/workspace-topic-store.js +228 -0
- package/test/agent-session-lifecycle.test.js +58 -0
- package/test/artifact-store.test.js +38 -2
- package/test/capabilities-security.test.js +58 -0
- package/test/chat-queue.test.js +32 -0
- package/test/context-and-task-bounds.test.js +76 -1
- package/test/device-code-message.test.js +9 -0
- package/test/media-caption.test.js +1 -1
- package/test/model-selection.test.js +9 -1
- package/test/official-tool-dependencies.test.js +1 -1
- package/test/paths.test.js +8 -0
- package/test/pi-capability-tools.test.js +65 -0
- package/test/service-manager.test.js +48 -0
- package/test/session-start-operational-notes.test.js +1 -1
- package/test/task-idempotency.test.js +40 -0
- package/test/task-routing.test.js +62 -0
- package/test/task-store.test.js +231 -7
- package/test/telegram-reply-topic-routing.test.js +94 -0
- package/test/telegram-task-dispatcher.test.js +150 -23
- package/test/telegram-text-artifact.test.js +13 -2
- package/test/telegram-tools-command.test.js +47 -0
- package/test/telegram-workspace-topic-store.test.js +124 -0
- package/test/tool-registry-run.test.js +41 -0
- package/test/weighted-resource-governor.test.js +95 -0
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import { Bot
|
|
2
|
-
import path from "node:path";
|
|
1
|
+
import { Bot } from "grammy";
|
|
3
2
|
import { authorizeChat } from "./auth.js";
|
|
4
3
|
import { captureIncomingArtifact } from "./media.js";
|
|
5
|
-
import { buildDeviceCodeTelegramMessage } from "./device-code-message.js";
|
|
6
4
|
import { renderTelegramHtml } from "./text-format.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
5
|
+
import { buildPiAuthTelegramMessage, getErrorMessage, getPiAuthIssue } from "../../core/agent/auth-flow.js";
|
|
6
|
+
import { createTelegramAuthController } from "./telegram-auth-controller.js";
|
|
9
7
|
import { resolveChatSpeed } from "../../core/agent/model-selection.js";
|
|
10
8
|
import { SessionSeedStore } from "../../core/conversation/session-seed-store.js";
|
|
11
9
|
import { formatDoctorReport } from "../../runtime/doctor.js";
|
|
12
|
-
import { formatToolUsageReport } from "../../runtime/tool-usage-report.js";
|
|
13
10
|
import { ToolResourceNoteStore } from "../../core/tools/tool-resource-note-store.js";
|
|
14
11
|
import { formatUpdateReport } from "../../runtime/update-manager.js";
|
|
15
12
|
import { cancelRestartReceipt, deliverRestartReceipt, prepareRestartReceipt } from "../../runtime/restart-receipt.js";
|
|
@@ -17,7 +14,16 @@ import { buildUpdatePicker, createTelegramUpdateCallbackHandler } from "./update
|
|
|
17
14
|
import { createTelegramModelControls } from "./model-controls.js";
|
|
18
15
|
import { createTelegramModelCallbackHandler } from "./model-callback.js";
|
|
19
16
|
import { createTelegramTaskDispatcher } from "./task-dispatcher.js";
|
|
20
|
-
import {
|
|
17
|
+
import { createTelegramSessionBridgeController } from "./telegram-session-bridge.js";
|
|
18
|
+
import { createTelegramToolsCommandHandler } from "./telegram-tools-command.js";
|
|
19
|
+
import { createTelegramWorkspaceController } from "./telegram-workspace-controller.js";
|
|
20
|
+
import { resolveTelegramWorkspaceRoute } from "./workspace-group.js";
|
|
21
|
+
import {
|
|
22
|
+
appendGeneralReplyRoutingInstruction,
|
|
23
|
+
isGeneralWorkspaceRoute,
|
|
24
|
+
routeGeneralWorkspaceReply
|
|
25
|
+
} from "./reply-topic-routing.js";
|
|
26
|
+
import { migrateLegacyReplyTopics, WorkspaceTopicStore } from "./workspace-topic-store.js";
|
|
21
27
|
import {
|
|
22
28
|
buildNewSessionPrompt,
|
|
23
29
|
buildPrompt,
|
|
@@ -30,17 +36,18 @@ import {
|
|
|
30
36
|
isSilentReply,
|
|
31
37
|
normalizeIncomingArtifact,
|
|
32
38
|
sanitizeSessionHandoff,
|
|
39
|
+
scheduledPromptSpeedOptions,
|
|
33
40
|
shouldIncludeArtifactReference,
|
|
34
41
|
withPromptSpeed
|
|
35
42
|
} from "./prompt-builders.js";
|
|
36
43
|
import {
|
|
37
44
|
createChatStateStore,
|
|
45
|
+
createPromptExecutionReceipt,
|
|
38
46
|
drainChatPromptQueue,
|
|
39
47
|
queueChatPrompt,
|
|
40
48
|
resolveTelegramBusyMessageMode,
|
|
41
49
|
routeBusyPrompt
|
|
42
50
|
} from "./chat-queue.js";
|
|
43
|
-
|
|
44
51
|
export {
|
|
45
52
|
createChatStateStore,
|
|
46
53
|
drainChatPromptQueue,
|
|
@@ -56,6 +63,7 @@ export {
|
|
|
56
63
|
collectText,
|
|
57
64
|
isScheduledTaskPrompt,
|
|
58
65
|
isSilentReply,
|
|
66
|
+
scheduledPromptSpeedOptions,
|
|
59
67
|
shouldIncludeArtifactReference,
|
|
60
68
|
withPromptSpeed
|
|
61
69
|
} from "./prompt-builders.js";
|
|
@@ -73,6 +81,12 @@ export function isProcessableTelegramMessage(message = {}) {
|
|
|
73
81
|
);
|
|
74
82
|
}
|
|
75
83
|
|
|
84
|
+
export function resolveIncomingBusyMessageMode({ config, route, message }) {
|
|
85
|
+
if (route?.workspace) return "queue";
|
|
86
|
+
if (typeof message?.text !== "string") return "queue";
|
|
87
|
+
return resolveTelegramBusyMessageMode(config, route?.sessionId);
|
|
88
|
+
}
|
|
89
|
+
|
|
76
90
|
export function buildTopicInitializationHandoff({ name, context }) {
|
|
77
91
|
return [
|
|
78
92
|
`Telegram topic: ${String(name || "").trim()}`,
|
|
@@ -166,12 +180,14 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
166
180
|
const bot = new Bot(config.telegram.token);
|
|
167
181
|
const perChatState = createChatStateStore();
|
|
168
182
|
const sessionSeeds = new SessionSeedStore();
|
|
183
|
+
const workspaceTopics = new WorkspaceTopicStore();
|
|
169
184
|
const notifiedPromptErrors = new WeakSet();
|
|
170
|
-
const authRenewals = new Map();
|
|
171
|
-
const workspaceRoutes = new WeakMap();
|
|
172
|
-
const workspaceGateStates = new Map();
|
|
173
|
-
let piAuthIssue = null;
|
|
174
185
|
let taskTimer = null;
|
|
186
|
+
const { authorizeContext, contextRoute, registerRoute } = createTelegramWorkspaceController({
|
|
187
|
+
config,
|
|
188
|
+
api: bot.api,
|
|
189
|
+
saveConfig
|
|
190
|
+
});
|
|
175
191
|
|
|
176
192
|
const requestRestartWithReceipt = async (ctx, reason = "Telegram restart") => {
|
|
177
193
|
const route = contextRoute(ctx);
|
|
@@ -211,152 +227,13 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
211
227
|
if (error instanceof Error) notifiedPromptErrors.add(error);
|
|
212
228
|
}
|
|
213
229
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const issue = rememberPiAuthIssue(error);
|
|
222
|
-
if (!issue) return false;
|
|
223
|
-
|
|
224
|
-
try {
|
|
225
|
-
await bot.api.sendMessage(chatId, buildPiAuthTelegramMessage({ config, chatId, issue }));
|
|
226
|
-
markPromptErrorNotified(error);
|
|
227
|
-
return true;
|
|
228
|
-
} catch (notifyError) {
|
|
229
|
-
logger?.error("telegram", `auth issue notice failed for chat ${chatId}: ${getErrorMessage(notifyError)}`);
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function selectTelegramLoginOption(options = []) {
|
|
235
|
-
return options.find((option) => /device/i.test(`${option.id} ${option.label}`))
|
|
236
|
-
|| options.find((option) => /browser|oauth|web/i.test(`${option.id} ${option.label}`))
|
|
237
|
-
|| options[0]
|
|
238
|
-
|| null;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async function finishAuthRenewal(chatId, renewal) {
|
|
242
|
-
try {
|
|
243
|
-
await renewal.promise;
|
|
244
|
-
await agentManager.validateAgent();
|
|
245
|
-
agentManager.clearSessionCache(chatId);
|
|
246
|
-
piAuthIssue = null;
|
|
247
|
-
logger?.log("telegram", `Pi auth renewal completed for chat ${chatId}`);
|
|
248
|
-
await bot.api.sendMessage(chatId, buildPiAuthTelegramMessage({ config, chatId, verified: true }));
|
|
249
|
-
} catch (error) {
|
|
250
|
-
const issue = rememberPiAuthIssue(error) || { kind: "validation-failed", message: getErrorMessage(error) };
|
|
251
|
-
piAuthIssue = issue;
|
|
252
|
-
logger?.error("telegram", `Pi auth renewal failed for chat ${chatId}: ${getErrorMessage(error)}`);
|
|
253
|
-
await bot.api.sendMessage(chatId, buildPiAuthTelegramMessage({ config, chatId, issue })).catch((notifyError) => {
|
|
254
|
-
logger?.error("telegram", `auth renewal failure notice failed for chat ${chatId}: ${getErrorMessage(notifyError)}`);
|
|
255
|
-
});
|
|
256
|
-
} finally {
|
|
257
|
-
authRenewals.delete(chatKey(chatId));
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
async function startAuthRenewal(chatId) {
|
|
262
|
-
const key = chatKey(chatId);
|
|
263
|
-
const existing = authRenewals.get(key);
|
|
264
|
-
if (existing) {
|
|
265
|
-
return { started: false, renewal: existing };
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const renewal = createPiOAuthLogin({
|
|
269
|
-
provider: config.pi.provider,
|
|
270
|
-
onSelect: async ({ message, options }) => {
|
|
271
|
-
const selected = selectTelegramLoginOption(options);
|
|
272
|
-
if (!selected) return undefined;
|
|
273
|
-
logger?.log("telegram", `Pi auth option for chat ${chatId}: ${selected.id}`);
|
|
274
|
-
await bot.api.sendMessage(chatId, `${message}\nUsing: ${selected.label || selected.id}`);
|
|
275
|
-
return selected.id;
|
|
276
|
-
},
|
|
277
|
-
onAuth: async ({ url, instructions }) => {
|
|
278
|
-
await bot.api.sendMessage(chatId, [
|
|
279
|
-
instructions || "Open this URL to continue Pi authentication:",
|
|
280
|
-
url,
|
|
281
|
-
"After login, paste the full redirect URL back here."
|
|
282
|
-
].join("\n"));
|
|
283
|
-
},
|
|
284
|
-
onDeviceCode: async ({ userCode, verificationUri, expiresInSeconds }) => {
|
|
285
|
-
const payload = buildDeviceCodeTelegramMessage({ userCode, verificationUri, expiresInSeconds });
|
|
286
|
-
const { text, ...options } = payload;
|
|
287
|
-
await bot.api.sendMessage(chatId, text, options);
|
|
288
|
-
},
|
|
289
|
-
onPrompt: async ({ message, controller }) => {
|
|
290
|
-
await bot.api.sendMessage(chatId, `${message}\nReply here with the value.`);
|
|
291
|
-
return controller.waitForManualCode();
|
|
292
|
-
},
|
|
293
|
-
onProgress: (message) => {
|
|
294
|
-
if (message) logger?.log("telegram", `Pi auth progress for chat ${chatId}: ${message}`);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
authRenewals.set(key, renewal);
|
|
299
|
-
finishAuthRenewal(chatId, renewal);
|
|
300
|
-
return { started: true, renewal };
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
async function submitAuthRenewalInput(ctx) {
|
|
304
|
-
const renewal = authRenewals.get(chatKey(ctx.chat.id));
|
|
305
|
-
const text = getIncomingMessageText(ctx.message).trim();
|
|
306
|
-
if (!renewal || !renewal.manualInputRequested || !text) return false;
|
|
307
|
-
|
|
308
|
-
if (!renewal.submitManualCode(text)) return false;
|
|
309
|
-
await ctx.reply("Got it. Finishing Pi login now...");
|
|
310
|
-
return true;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function getIncomingChatMeta(ctx) {
|
|
314
|
-
return {
|
|
315
|
-
languageCode: ctx.from?.language_code || "",
|
|
316
|
-
username: ctx.from?.username || "",
|
|
317
|
-
firstName: ctx.from?.first_name || "",
|
|
318
|
-
lastName: ctx.from?.last_name || ""
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
async function authorizeContext(ctx) {
|
|
323
|
-
const route = await resolveTelegramWorkspaceRoute({ config, api: ctx.api, ctx });
|
|
324
|
-
if (!route.workspace) {
|
|
325
|
-
const auth = await authorizeChat({ config, chatId: ctx.chat.id, saveConfig, chatMeta: getIncomingChatMeta(ctx) });
|
|
326
|
-
if (auth.ok) workspaceRoutes.set(ctx, route);
|
|
327
|
-
return auth;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const gateKey = String(ctx.chat.id);
|
|
331
|
-
const previous = workspaceGateStates.get(gateKey);
|
|
332
|
-
if (!route.ok) {
|
|
333
|
-
workspaceGateStates.set(gateKey, route.reason || "locked");
|
|
334
|
-
if (previous !== (route.reason || "locked")) {
|
|
335
|
-
await ctx.reply("Private workspace access is paused because this forum is no longer owner-only.").catch(() => {});
|
|
336
|
-
}
|
|
337
|
-
return { ok: false, reason: route.reason || "workspace-locked" };
|
|
338
|
-
}
|
|
339
|
-
if (!(config.telegram.authorizedChatIds || []).includes(route.ownerChatId)) {
|
|
340
|
-
return { ok: false, reason: "owner-not-authorized" };
|
|
341
|
-
}
|
|
342
|
-
workspaceRoutes.set(ctx, route);
|
|
343
|
-
workspaceGateStates.set(gateKey, "ready");
|
|
344
|
-
if (previous && previous !== "ready") {
|
|
345
|
-
await ctx.reply("Private workspace access restored.").catch(() => {});
|
|
346
|
-
}
|
|
347
|
-
return { ok: true, firstTime: false, workspace: true };
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function contextRoute(ctx) {
|
|
351
|
-
return workspaceRoutes.get(ctx) || {
|
|
352
|
-
ok: true,
|
|
353
|
-
workspace: false,
|
|
354
|
-
sessionId: String(ctx.chat.id),
|
|
355
|
-
scopeChatId: ctx.chat.id,
|
|
356
|
-
transportChatId: ctx.chat.id,
|
|
357
|
-
threadId: null
|
|
358
|
-
};
|
|
359
|
-
}
|
|
230
|
+
const authController = createTelegramAuthController({
|
|
231
|
+
config,
|
|
232
|
+
api: bot.api,
|
|
233
|
+
agentManager,
|
|
234
|
+
logger,
|
|
235
|
+
markPromptErrorNotified
|
|
236
|
+
});
|
|
360
237
|
|
|
361
238
|
function getChatState(chatId) {
|
|
362
239
|
return perChatState.get(chatId);
|
|
@@ -406,145 +283,34 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
406
283
|
if (normalizationRequired && !transcript) {
|
|
407
284
|
logger?.log("telegram", `media normalization unavailable for chat ${route.transportChatId}: ${toolResult?.error || toolResult?.missingConfig?.join(", ") || "unknown error"}`);
|
|
408
285
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
logger?.log("telegram", `suppressing silent reply for chat ${chatId}`);
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (text.length > maxInlineReplyLength) {
|
|
421
|
-
logger?.log("telegram", `sending long reply as markdown attachment for chat ${chatId}`);
|
|
422
|
-
const chatArtifactStore = artifactStore.forChat(artifactChatId);
|
|
423
|
-
const artifact = await chatArtifactStore.createGeneratedFile({
|
|
424
|
-
fileName: `reply-${Date.now()}.md`,
|
|
425
|
-
content: text,
|
|
426
|
-
kind: "document",
|
|
427
|
-
mimeType: "text/markdown",
|
|
428
|
-
source: { type: "assistant", chatId },
|
|
429
|
-
metadata: { delivery: "telegram-document" }
|
|
430
|
-
});
|
|
431
|
-
await sendDocument(new InputFile(artifact.path, path.basename(artifact.path)), {
|
|
432
|
-
caption: "Response attached as Markdown."
|
|
433
|
-
});
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
logger?.log("telegram", `sending text reply for chat ${chatId}`);
|
|
438
|
-
const sent = await sendText(renderTelegramHtml(text), { parse_mode: "HTML" });
|
|
439
|
-
if (sent?.message_id) {
|
|
440
|
-
const messages = getChatState(chatId).assistantMessages;
|
|
441
|
-
messages.set(sent.message_id, text);
|
|
442
|
-
while (messages.size > 50) messages.delete(messages.keys().next().value);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function createWorkspaceAccessGuard(route) {
|
|
447
|
-
return async () => {
|
|
448
|
-
if (!route.workspace) return;
|
|
449
|
-
const current = await resolveTelegramWorkspaceRoute({
|
|
450
|
-
config,
|
|
451
|
-
api: bot.api,
|
|
452
|
-
ctx: {
|
|
453
|
-
chat: { id: route.transportChatId, type: "supergroup", is_forum: true },
|
|
454
|
-
from: { id: route.ownerChatId },
|
|
455
|
-
message: { message_thread_id: route.threadId }
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
if (!current.ok) throw new Error("Owner-only workspace access is paused.");
|
|
459
|
-
};
|
|
286
|
+
const prompt = buildPrompt({ ctx, artifact, transcript, toolResult });
|
|
287
|
+
if (!isGeneralWorkspaceRoute(route)) return prompt;
|
|
288
|
+
const [topics, recentProposals] = await Promise.all([
|
|
289
|
+
workspaceTopics.listTopics(route.ownerChatId, route.transportChatId),
|
|
290
|
+
workspaceTopics.listRecentProposals(route.ownerChatId, route.transportChatId)
|
|
291
|
+
]);
|
|
292
|
+
return appendGeneralReplyRoutingInstruction(prompt, topics, recentProposals);
|
|
460
293
|
}
|
|
461
294
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
const handoff = buildTopicInitializationHandoff({ name, context });
|
|
479
|
-
await sessionSeeds.set(initializedSessionId, handoff);
|
|
480
|
-
agentManager.resetSession(initializedSessionId, { handoff });
|
|
481
|
-
await agentManager.waitForSessionClose(initializedSessionId);
|
|
482
|
-
return {
|
|
483
|
-
ok: true,
|
|
484
|
-
chatId: route.transportChatId,
|
|
485
|
-
messageThreadId,
|
|
486
|
-
sessionId: initializedSessionId,
|
|
487
|
-
name,
|
|
488
|
-
initialized: true
|
|
489
|
-
};
|
|
490
|
-
};
|
|
491
|
-
return {
|
|
492
|
-
sendMedia: async (filePath, { method = "audio", caption, filename } = {}) => {
|
|
493
|
-
logger?.log("telegram", `sending ${method} reply for chat ${route.transportChatId}`);
|
|
494
|
-
const input = new InputFile(filePath, filename || undefined);
|
|
495
|
-
const options = messageOptions({ caption });
|
|
496
|
-
if (method === "voice") return bot.api.sendVoice(route.transportChatId, input, options);
|
|
497
|
-
if (method === "document") return bot.api.sendDocument(route.transportChatId, input, options);
|
|
498
|
-
if (method === "photo" || method === "image") return bot.api.sendPhoto(route.transportChatId, input, options);
|
|
499
|
-
if (method === "video") return bot.api.sendVideo(route.transportChatId, input, options);
|
|
500
|
-
return bot.api.sendAudio(route.transportChatId, input, options);
|
|
501
|
-
},
|
|
502
|
-
createForumTopic: async (name, context) => {
|
|
503
|
-
if (!route.workspace) throw new Error("Telegram topic creation is only available from the owner workspace forum.");
|
|
504
|
-
await createWorkspaceAccessGuard(route)();
|
|
505
|
-
const topic = await bot.api.createForumTopic(route.transportChatId, name);
|
|
506
|
-
return initializeForumTopic({
|
|
507
|
-
messageThreadId: topic.message_thread_id,
|
|
508
|
-
name: topic.name,
|
|
509
|
-
context
|
|
510
|
-
});
|
|
511
|
-
},
|
|
512
|
-
initializeForumTopic,
|
|
513
|
-
prepareRestartReceipt: (summary) => prepareRestartReceipt({
|
|
514
|
-
transportChatId: route.transportChatId,
|
|
515
|
-
threadId: route.threadId
|
|
516
|
-
}, { reason: String(summary || "Agent-requested restart").trim() }),
|
|
517
|
-
cancelRestartReceipt,
|
|
518
|
-
getTaskContext: () => route.workspace ? {
|
|
519
|
-
transportChatId: route.transportChatId,
|
|
520
|
-
messageThreadId: route.topicThreadId
|
|
521
|
-
} : null
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
agentManager.setArtifactDeliveryHandler?.(async ({ chatId, artifact, caption, method }) => {
|
|
526
|
-
const resolvedMethod = method
|
|
527
|
-
|| artifact.metadata?.delivery?.method
|
|
528
|
-
|| (artifact.kind === "audio" || artifact.mimeType?.startsWith("audio/") ? "audio"
|
|
529
|
-
: artifact.kind === "image" || artifact.mimeType?.startsWith("image/") ? "photo"
|
|
530
|
-
: artifact.kind === "video" || artifact.mimeType?.startsWith("video/") ? "video"
|
|
531
|
-
: "document");
|
|
532
|
-
const safeCaption = caption && !/(^|\s)(\/[^\s]|[A-Za-z]:[\\/])/.test(caption) ? caption : undefined;
|
|
533
|
-
await createTelegramSessionBridge({
|
|
534
|
-
workspace: false,
|
|
535
|
-
sessionId: String(chatId),
|
|
536
|
-
scopeChatId: chatId,
|
|
537
|
-
transportChatId: chatId,
|
|
538
|
-
threadId: null
|
|
539
|
-
}).sendMedia(artifact.path, {
|
|
540
|
-
method: resolvedMethod,
|
|
541
|
-
caption: safeCaption,
|
|
542
|
-
filename: path.basename(artifact.path)
|
|
543
|
-
});
|
|
544
|
-
return { ok: true, artifactId: artifact.id, method: resolvedMethod };
|
|
295
|
+
const {
|
|
296
|
+
createSessionBridge: createTelegramSessionBridge,
|
|
297
|
+
createWorkspaceAccessGuard,
|
|
298
|
+
installArtifactDeliveryHandler,
|
|
299
|
+
sendTextReply
|
|
300
|
+
} = createTelegramSessionBridgeController({
|
|
301
|
+
config,
|
|
302
|
+
api: bot.api,
|
|
303
|
+
agentManager,
|
|
304
|
+
artifactStore,
|
|
305
|
+
sessionSeeds,
|
|
306
|
+
workspaceTopics,
|
|
307
|
+
getChatState,
|
|
308
|
+
buildTopicInitializationHandoff,
|
|
309
|
+
logger
|
|
545
310
|
});
|
|
311
|
+
installArtifactDeliveryHandler();
|
|
546
312
|
|
|
547
|
-
async function processPromptForChat({ chatId, prompt, ctx = null }) {
|
|
313
|
+
async function processPromptForChat({ chatId, prompt, ctx = null, executionReceipt = null }) {
|
|
548
314
|
const route = ctx ? contextRoute(ctx) : {
|
|
549
315
|
workspace: false,
|
|
550
316
|
sessionId: String(chatId),
|
|
@@ -575,11 +341,12 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
575
341
|
chatState.activeSession = session;
|
|
576
342
|
chatState.activeRoute = route;
|
|
577
343
|
try {
|
|
578
|
-
text = await withPromptSpeed({
|
|
344
|
+
text = await withPromptSpeed(scheduledPromptSpeedOptions({
|
|
345
|
+
prompt,
|
|
346
|
+
session,
|
|
579
347
|
speedController,
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
}, () => collectText(session, prompt, {
|
|
348
|
+
configuredSpeed: resolveChatSpeed(config, sessionId)
|
|
349
|
+
}), () => collectText(session, prompt, {
|
|
583
350
|
logger,
|
|
584
351
|
chatId: sessionId,
|
|
585
352
|
onSlowPrompt: () => bot.api.sendMessage(
|
|
@@ -590,19 +357,40 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
590
357
|
}));
|
|
591
358
|
} catch (error) {
|
|
592
359
|
agentManager.resetSession(sessionId);
|
|
360
|
+
if (error && typeof error === "object") {
|
|
361
|
+
error.retryable = false;
|
|
362
|
+
error.outcomeUncertain = true;
|
|
363
|
+
}
|
|
593
364
|
throw error;
|
|
594
365
|
} finally {
|
|
595
366
|
if (chatState.activeSession === session) chatState.activeSession = null;
|
|
596
367
|
chatState.activeRoute = null;
|
|
597
368
|
}
|
|
369
|
+
executionReceipt?.resolve({ status: "executed" });
|
|
598
370
|
if (text) {
|
|
599
|
-
|
|
371
|
+
const topics = route.workspace && route.ownerChatId
|
|
372
|
+
? await workspaceTopics.listTopics(route.ownerChatId, route.transportChatId)
|
|
373
|
+
: [];
|
|
374
|
+
const routedReply = routeGeneralWorkspaceReply({ route, text, topics });
|
|
375
|
+
if (routedReply.proposal) {
|
|
376
|
+
await workspaceTopics.recordProposal(route.ownerChatId, route.transportChatId, routedReply.proposal);
|
|
377
|
+
logger?.log("telegram", `recorded topic proposal ${routedReply.proposal} for workspace ${route.transportChatId}`);
|
|
378
|
+
}
|
|
379
|
+
if (!routedReply.text) return;
|
|
380
|
+
const deliveryRoute = routedReply.route;
|
|
381
|
+
const deliveryOptions = (extra = {}) => deliveryRoute.workspace && deliveryRoute.threadId
|
|
382
|
+
? { ...extra, message_thread_id: deliveryRoute.threadId }
|
|
383
|
+
: extra;
|
|
384
|
+
await createWorkspaceAccessGuard(deliveryRoute)();
|
|
385
|
+
if (routedReply.topic) {
|
|
386
|
+
logger?.log("telegram", `routing General reply to topic ${routedReply.topic.threadId} (${routedReply.topic.name})`);
|
|
387
|
+
}
|
|
600
388
|
await sendTextReply({
|
|
601
|
-
sendText: (message, extra) => bot.api.sendMessage(
|
|
602
|
-
sendDocument: (file, extra) => bot.api.sendDocument(
|
|
389
|
+
sendText: (message, extra) => bot.api.sendMessage(deliveryRoute.transportChatId, message, deliveryOptions(extra)),
|
|
390
|
+
sendDocument: (file, extra) => bot.api.sendDocument(deliveryRoute.transportChatId, file, deliveryOptions(extra)),
|
|
603
391
|
chatId: sessionId,
|
|
604
|
-
artifactChatId:
|
|
605
|
-
text
|
|
392
|
+
artifactChatId: deliveryRoute.scopeChatId,
|
|
393
|
+
text: routedReply.text
|
|
606
394
|
});
|
|
607
395
|
}
|
|
608
396
|
};
|
|
@@ -611,8 +399,19 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
611
399
|
return work();
|
|
612
400
|
}
|
|
613
401
|
|
|
614
|
-
async function enqueuePrompt({
|
|
402
|
+
async function enqueuePrompt({
|
|
403
|
+
chatId,
|
|
404
|
+
prompt,
|
|
405
|
+
label,
|
|
406
|
+
ctx = null,
|
|
407
|
+
replaceQueued = false,
|
|
408
|
+
busyMessageMode = "queue",
|
|
409
|
+
waitForExecution = false,
|
|
410
|
+
onExecutionStart = null,
|
|
411
|
+
coalesceQueued = false
|
|
412
|
+
}) {
|
|
615
413
|
const chatState = getChatState(chatId);
|
|
414
|
+
const receipt = waitForExecution ? createPromptExecutionReceipt(onExecutionStart) : null;
|
|
616
415
|
|
|
617
416
|
if (chatState.processing) {
|
|
618
417
|
const incomingRoute = ctx ? contextRoute(ctx) : null;
|
|
@@ -626,10 +425,14 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
626
425
|
prompt,
|
|
627
426
|
mode: sameDelivery ? busyMessageMode : "queue",
|
|
628
427
|
replaceQueued,
|
|
629
|
-
ctx
|
|
428
|
+
ctx,
|
|
429
|
+
receipt,
|
|
430
|
+
coalesceQueued
|
|
630
431
|
});
|
|
631
432
|
if (routed.disposition === "steered") {
|
|
632
433
|
logger?.log("telegram", `chat ${chatId} busy, steering ${label}`);
|
|
434
|
+
} else if (routed.disposition === "coalesced") {
|
|
435
|
+
logger?.log("telegram", `chat ${chatId} busy, coalescing ${label} into pending direct turn`);
|
|
633
436
|
} else {
|
|
634
437
|
logger?.log("telegram", `chat ${chatId} busy, queueing ${label}`);
|
|
635
438
|
if (routed.steerError) {
|
|
@@ -637,24 +440,28 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
637
440
|
}
|
|
638
441
|
}
|
|
639
442
|
if (replaceQueued) chatState.continueAfterClose = true;
|
|
640
|
-
return;
|
|
443
|
+
return receipt ? receipt.promise : undefined;
|
|
641
444
|
}
|
|
642
445
|
|
|
643
446
|
chatState.processing = true;
|
|
644
447
|
logger?.log("telegram", `processing ${label} in chat ${chatId}`);
|
|
645
|
-
|
|
448
|
+
const draining = processChatPromptQueue({ chatId, prompt, label, ctx, initialReceipt: receipt });
|
|
449
|
+
if (!receipt) return draining;
|
|
450
|
+
draining.catch(() => {});
|
|
451
|
+
return receipt.promise;
|
|
646
452
|
}
|
|
647
453
|
|
|
648
|
-
function processChatPromptQueue({ chatId, prompt, label, ctx = null, beforeInitialPrompt }) {
|
|
454
|
+
function processChatPromptQueue({ chatId, prompt, label, ctx = null, beforeInitialPrompt, initialReceipt = null }) {
|
|
649
455
|
const chatState = getChatState(chatId);
|
|
650
456
|
return drainChatPromptQueue({
|
|
651
457
|
chatState,
|
|
652
458
|
initialPrompt: prompt,
|
|
653
459
|
initialCtx: ctx,
|
|
460
|
+
initialReceipt,
|
|
654
461
|
beforeInitialPrompt,
|
|
655
|
-
processPrompt: ({ prompt: currentPrompt, ctx: currentCtx }) => {
|
|
462
|
+
processPrompt: ({ prompt: currentPrompt, ctx: currentCtx, receipt }) => {
|
|
656
463
|
logger?.log("telegram", `prompt dispatch for chat ${chatId}`);
|
|
657
|
-
return processPromptForChat({ chatId, prompt: currentPrompt, ctx: currentCtx });
|
|
464
|
+
return processPromptForChat({ chatId, prompt: currentPrompt, ctx: currentCtx, executionReceipt: receipt });
|
|
658
465
|
},
|
|
659
466
|
onPromptInterrupted: (error) => {
|
|
660
467
|
logger?.log("telegram", `${label} interrupted by queued /new for chat ${chatId}: ${getErrorMessage(error)}`);
|
|
@@ -662,7 +469,7 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
662
469
|
onPromptFailure: async (error) => {
|
|
663
470
|
const message = getErrorMessage(error);
|
|
664
471
|
logger?.error("telegram", `${label} failed for chat ${chatId}: ${message}`);
|
|
665
|
-
await
|
|
472
|
+
await authController.notifyIssueIfNeeded(chatId, error);
|
|
666
473
|
}
|
|
667
474
|
});
|
|
668
475
|
}
|
|
@@ -674,14 +481,17 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
674
481
|
if (chatState.processing) {
|
|
675
482
|
await ensureQueuedTelegramTyping(chatState, ctx);
|
|
676
483
|
const incomingPrompt = await buildIncomingPrompt(ctx, route);
|
|
677
|
-
const busyMessageMode =
|
|
678
|
-
|
|
679
|
-
|
|
484
|
+
const busyMessageMode = resolveIncomingBusyMessageMode({
|
|
485
|
+
config,
|
|
486
|
+
route,
|
|
487
|
+
message: ctx.message
|
|
488
|
+
});
|
|
680
489
|
return enqueuePrompt({
|
|
681
490
|
chatId: route.sessionId,
|
|
682
491
|
prompt: incomingPrompt,
|
|
683
492
|
label: `message ${ctx.msg.message_id}`,
|
|
684
493
|
busyMessageMode,
|
|
494
|
+
coalesceQueued: busyMessageMode === "steer" && typeof ctx.message?.text === "string",
|
|
685
495
|
ctx
|
|
686
496
|
});
|
|
687
497
|
}
|
|
@@ -695,6 +505,13 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
695
505
|
});
|
|
696
506
|
}
|
|
697
507
|
|
|
508
|
+
async function migrateConfiguredReplyTopics() {
|
|
509
|
+
const migratedGroups = await migrateLegacyReplyTopics(config, workspaceTopics);
|
|
510
|
+
if (!migratedGroups) return;
|
|
511
|
+
await saveConfig(config);
|
|
512
|
+
logger?.log("telegram", `migrated configured reply topics for ${migratedGroups} workspace group(s)`);
|
|
513
|
+
}
|
|
514
|
+
|
|
698
515
|
async function sendStartupMessages() {
|
|
699
516
|
for (const chatId of config.telegram.authorizedChatIds || []) {
|
|
700
517
|
try {
|
|
@@ -726,33 +543,60 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
726
543
|
timer.unref?.();
|
|
727
544
|
}
|
|
728
545
|
|
|
729
|
-
async function enqueueAsyncPrompt({ chatId, prompt, label,
|
|
546
|
+
async function enqueueAsyncPrompt({ chatId, prompt, label, route: taskRoute, timeoutMs }) {
|
|
730
547
|
let ctx = { chat: { id: chatId }, api: bot.api };
|
|
731
|
-
|
|
548
|
+
const destination = taskRoute?.transport === "telegram" ? taskRoute.destination : null;
|
|
549
|
+
if (destination?.chatId && destination?.threadId) {
|
|
732
550
|
ctx = {
|
|
733
|
-
chat: { id:
|
|
551
|
+
chat: { id: destination.chatId, type: "supergroup", is_forum: true },
|
|
734
552
|
from: { id: chatId },
|
|
735
|
-
message: { message_thread_id:
|
|
553
|
+
message: { message_thread_id: destination.threadId },
|
|
736
554
|
api: bot.api
|
|
737
555
|
};
|
|
738
556
|
const route = await resolveTelegramWorkspaceRoute({ config, api: bot.api, ctx });
|
|
739
557
|
if (!route.ok) throw new Error("Scheduled owner-workspace destination is unavailable.");
|
|
740
|
-
|
|
558
|
+
registerRoute(ctx, route);
|
|
741
559
|
}
|
|
742
560
|
const route = contextRoute(ctx);
|
|
743
561
|
const chatState = getChatState(route.sessionId);
|
|
744
562
|
if (chatState.processing) await ensureQueuedTelegramTyping(chatState, ctx);
|
|
745
|
-
|
|
563
|
+
let timer = null;
|
|
564
|
+
const execution = enqueuePrompt({
|
|
565
|
+
chatId: route.sessionId,
|
|
566
|
+
prompt,
|
|
567
|
+
label,
|
|
568
|
+
ctx,
|
|
569
|
+
waitForExecution: true,
|
|
570
|
+
onExecutionStart: ({ reject }) => {
|
|
571
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) return;
|
|
572
|
+
timer = setTimeout(() => {
|
|
573
|
+
const error = new Error(`${label} exceeded its ${timeoutMs}ms execution deadline`);
|
|
574
|
+
error.retryable = false;
|
|
575
|
+
error.outcomeUncertain = true;
|
|
576
|
+
reject(error);
|
|
577
|
+
agentManager.abortSession(route.sessionId).catch((abortError) => {
|
|
578
|
+
logger?.error("tasks", `${label} abort failed: ${getErrorMessage(abortError)}`);
|
|
579
|
+
});
|
|
580
|
+
}, timeoutMs);
|
|
581
|
+
timer.unref?.();
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
execution.then(
|
|
585
|
+
() => { if (timer) clearTimeout(timer); },
|
|
586
|
+
() => { if (timer) clearTimeout(timer); }
|
|
587
|
+
);
|
|
588
|
+
return execution;
|
|
746
589
|
}
|
|
747
590
|
|
|
748
591
|
const { dispatchDueTasks } = createTelegramTaskDispatcher({
|
|
749
592
|
taskStore,
|
|
750
|
-
sendMessage: (chatId, text) => bot.api.sendMessage(chatId, text),
|
|
593
|
+
sendMessage: (chatId, text, options) => bot.api.sendMessage(chatId, text, options),
|
|
751
594
|
enqueueAsyncPrompt,
|
|
752
595
|
artifactStore,
|
|
753
596
|
toolRegistry,
|
|
754
597
|
resourceNotes,
|
|
755
598
|
agentManager,
|
|
599
|
+
taskTimeouts: config.tasks,
|
|
756
600
|
logger
|
|
757
601
|
});
|
|
758
602
|
|
|
@@ -840,13 +684,8 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
840
684
|
bot.command("new", async (ctx) => {
|
|
841
685
|
const auth = await authorizeContext(ctx);
|
|
842
686
|
if (!auth.ok) return;
|
|
843
|
-
if (
|
|
844
|
-
await ctx.reply(
|
|
845
|
-
config,
|
|
846
|
-
chatId: ctx.chat.id,
|
|
847
|
-
issue: piAuthIssue,
|
|
848
|
-
renewalActive: authRenewals.has(chatKey(ctx.chat.id))
|
|
849
|
-
}));
|
|
687
|
+
if (authController.getIssue()) {
|
|
688
|
+
await ctx.reply(authController.buildBlockedMessage(ctx.chat.id));
|
|
850
689
|
return;
|
|
851
690
|
}
|
|
852
691
|
await handleNewCommand(ctx);
|
|
@@ -890,11 +729,13 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
890
729
|
}
|
|
891
730
|
});
|
|
892
731
|
|
|
893
|
-
bot.command("tools",
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
732
|
+
bot.command("tools", createTelegramToolsCommandHandler({
|
|
733
|
+
authorize: authorizeContext,
|
|
734
|
+
contextRoute,
|
|
735
|
+
toolRegistry,
|
|
736
|
+
withTyping,
|
|
737
|
+
logger
|
|
738
|
+
}));
|
|
898
739
|
|
|
899
740
|
bot.command("model", async (ctx) => {
|
|
900
741
|
const auth = await authorizeContext(ctx);
|
|
@@ -914,38 +755,10 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
914
755
|
await showSpeedPicker(ctx);
|
|
915
756
|
});
|
|
916
757
|
|
|
917
|
-
bot.command("auth",
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
const status = getPiAuthStatus(config, ctx.chat.id);
|
|
922
|
-
if (status.hasApiKey || !status.supportsOAuth) {
|
|
923
|
-
await withTyping(ctx, async () => {
|
|
924
|
-
try {
|
|
925
|
-
await agentManager.validateAgent();
|
|
926
|
-
agentManager.clearSessionCache(ctx.chat.id);
|
|
927
|
-
piAuthIssue = null;
|
|
928
|
-
await ctx.reply(buildPiAuthTelegramMessage({ config, chatId: ctx.chat.id, verified: true }));
|
|
929
|
-
} catch (error) {
|
|
930
|
-
const issue = rememberPiAuthIssue(error) || { kind: "validation-failed", message: getErrorMessage(error) };
|
|
931
|
-
piAuthIssue = issue;
|
|
932
|
-
await ctx.reply(buildPiAuthTelegramMessage({ config, chatId: ctx.chat.id, issue }));
|
|
933
|
-
}
|
|
934
|
-
});
|
|
935
|
-
return;
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
try {
|
|
939
|
-
const { started } = await startAuthRenewal(ctx.chat.id);
|
|
940
|
-
await ctx.reply(started
|
|
941
|
-
? "Starting Pi login from Telegram..."
|
|
942
|
-
: "Pi login is already in progress. Paste the redirect URL or code here when you have it.");
|
|
943
|
-
} catch (error) {
|
|
944
|
-
const issue = rememberPiAuthIssue(error) || { kind: "validation-failed", message: getErrorMessage(error) };
|
|
945
|
-
piAuthIssue = issue;
|
|
946
|
-
await ctx.reply(buildPiAuthTelegramMessage({ config, chatId: ctx.chat.id, issue }));
|
|
947
|
-
}
|
|
948
|
-
});
|
|
758
|
+
bot.command("auth", (ctx) => authController.handleCommand(ctx, {
|
|
759
|
+
authorize: authorizeContext,
|
|
760
|
+
withTyping
|
|
761
|
+
}));
|
|
949
762
|
|
|
950
763
|
const handleModelCallback = createTelegramModelCallbackHandler({
|
|
951
764
|
config,
|
|
@@ -970,7 +783,7 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
970
783
|
const reaction = ctx.messageReaction;
|
|
971
784
|
const chatId = reaction.chat.id;
|
|
972
785
|
const auth = await authorizeChat({ config, chatId, saveConfig });
|
|
973
|
-
if (!auth.ok ||
|
|
786
|
+
if (!auth.ok || authController.getIssue()) return;
|
|
974
787
|
|
|
975
788
|
const reactedMessageText = getChatState(chatId).assistantMessages.get(reaction.message_id) || "";
|
|
976
789
|
const prompt = buildReactionPrompt({ reaction, reactedMessageText });
|
|
@@ -988,20 +801,18 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
988
801
|
bot.on("message", async (ctx) => {
|
|
989
802
|
const auth = await authorizeContext(ctx);
|
|
990
803
|
if (!auth.ok) return;
|
|
804
|
+
await workspaceTopics.observeMessage(contextRoute(ctx), ctx.message).catch((error) => {
|
|
805
|
+
logger?.error("telegram", `workspace topic observation failed: ${getErrorMessage(error)}`);
|
|
806
|
+
});
|
|
991
807
|
if (!isProcessableTelegramMessage(ctx.message)) return;
|
|
992
808
|
|
|
993
809
|
const command = getTelegramCommand(ctx);
|
|
994
810
|
if (command) return;
|
|
995
811
|
|
|
996
|
-
if (await
|
|
812
|
+
if (await authController.submitRenewalInput(ctx)) return;
|
|
997
813
|
|
|
998
|
-
if (
|
|
999
|
-
await ctx.reply(
|
|
1000
|
-
config,
|
|
1001
|
-
chatId: ctx.chat.id,
|
|
1002
|
-
issue: piAuthIssue,
|
|
1003
|
-
renewalActive: authRenewals.has(chatKey(ctx.chat.id))
|
|
1004
|
-
}));
|
|
814
|
+
if (authController.getIssue()) {
|
|
815
|
+
await ctx.reply(authController.buildBlockedMessage(ctx.chat.id));
|
|
1005
816
|
return;
|
|
1006
817
|
}
|
|
1007
818
|
|
|
@@ -1021,6 +832,7 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
1021
832
|
return {
|
|
1022
833
|
async start({ skipAgentStartupPrompts = false } = {}) {
|
|
1023
834
|
config.telegram.chatMeta ||= {};
|
|
835
|
+
await migrateConfiguredReplyTopics();
|
|
1024
836
|
await bot.api.setMyCommands(telegramCommands);
|
|
1025
837
|
if (!taskTimer) {
|
|
1026
838
|
taskTimer = setInterval(() => {
|
|
@@ -1047,7 +859,7 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
1047
859
|
async notifyPiAuthIssue(error) {
|
|
1048
860
|
let notified = false;
|
|
1049
861
|
for (const chatId of config.telegram.authorizedChatIds || []) {
|
|
1050
|
-
notified = await
|
|
862
|
+
notified = await authController.notifyIssueIfNeeded(chatId, error) || notified;
|
|
1051
863
|
}
|
|
1052
864
|
return notified;
|
|
1053
865
|
}
|