arisa 5.1.68 → 5.2.7
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 +7 -4
- package/package.json +1 -1
- package/src/core/agent/agent-manager.js +46 -6
- package/src/core/agent/agent-session-lifecycle.js +80 -3
- package/src/core/agent/core-tools.js +1 -1
- package/src/core/agent/pi-auth-login.js +1 -1
- package/src/core/agent/pi-runtime.js +1 -1
- package/src/core/agent/runtime-context.js +1 -1
- package/src/core/agent/worker-heap-circuit-breaker.js +122 -0
- package/src/core/artifacts/artifact-store.js +1 -1
- package/src/core/capabilities/capability-service.js +1 -1
- package/src/core/config/config-defaults.js +30 -1
- package/src/core/config/config-store.js +1 -1
- package/src/core/conversation/session-seed-store.js +1 -1
- package/src/core/tasks/task-store.js +1 -1
- package/src/core/tools/daemon-client.js +180 -0
- package/src/core/tools/daemon-processes.js +19 -3
- package/src/core/tools/daemon-protocol.js +72 -0
- package/src/core/tools/daemon-runtime.js +13 -490
- package/src/core/tools/daemon-worker.js +310 -0
- package/src/core/tools/ipc-client.js +2 -2
- package/src/core/tools/memory-pressure.js +56 -0
- package/src/core/tools/official-tool-installer.js +1 -1
- package/src/core/tools/tool-config.js +1 -1
- package/src/core/tools/tool-process-output.js +100 -0
- package/src/core/tools/tool-process-runner.js +175 -0
- package/src/core/tools/tool-registry.js +99 -187
- package/src/core/tools/tool-resource-note-store.js +1 -1
- package/src/core/tools/tool-usage-store.js +1 -1
- package/src/core/tools/weighted-resource-governor.js +188 -38
- package/src/index.js +14 -2
- package/src/official-tools.lock.json +424 -50
- package/src/platform/paths.js +152 -0
- package/src/runtime/bootstrap-cli.js +121 -0
- package/src/runtime/bootstrap-config.js +97 -0
- package/src/runtime/bootstrap-telegram.js +325 -0
- package/src/runtime/bootstrap.js +6 -543
- package/src/runtime/doctor.js +6 -3
- package/src/runtime/flush.js +1 -1
- package/src/runtime/ipc/ipc-server.js +1 -1
- package/src/runtime/log-viewer.js +1 -1
- package/src/runtime/oom-protection.js +20 -0
- package/src/runtime/paths.js +3 -151
- package/src/runtime/restart-receipt.js +1 -1
- package/src/runtime/service-manager.js +1 -1
- package/src/runtime/service-supervisor.js +14 -0
- package/src/runtime/slave-cli.js +1 -1
- package/src/runtime/tool-process-supervisor.js +1 -1
- package/src/runtime/tui.js +200 -0
- package/src/runtime/update-manager.js +1 -1
- package/src/runtime/worker-recovery-report.js +142 -0
- package/src/transport/telegram/bot.js +42 -320
- package/src/transport/telegram/prompt-builders.js +8 -3
- package/src/transport/telegram/telegram-prompt-controller.js +346 -0
- package/src/transport/telegram/workspace-topic-store.js +1 -1
- package/test/agent-session-lifecycle.test.js +92 -0
- package/test/architecture-boundaries.test.js +29 -0
- package/test/bootstrap.test.js +65 -0
- package/test/daemon-process-invocation.test.js +27 -0
- package/test/daemon-runtime.test.js +36 -1
- package/test/doctor.test.js +22 -0
- package/test/memory-pressure.test.js +36 -0
- package/test/model-selection.test.js +11 -1
- package/test/official-tool-dependencies.test.js +1 -1
- package/test/official-tool-installer.test.js +18 -1
- package/test/oom-protection.test.js +32 -0
- package/test/paths.test.js +7 -0
- package/test/pi-compaction.test.js +9 -0
- package/test/service-manager.test.js +6 -1
- package/test/telegram-prompt-controller.test.js +81 -0
- package/test/telegram-text-artifact.test.js +30 -0
- package/test/tool-registry-run.test.js +108 -4
- package/test/tui.test.js +41 -0
- package/test/weighted-resource-governor.test.js +97 -5
- package/test/worker-heap-circuit-breaker.test.js +79 -0
- package/test/worker-recovery-report.test.js +69 -0
- package/test-fixtures/fake-daemon.js +5 -0
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { Bot } from "grammy";
|
|
2
2
|
import { authorizeChat } from "./auth.js";
|
|
3
|
-
import { captureIncomingArtifact } from "./media.js";
|
|
4
3
|
import { renderTelegramHtml } from "./text-format.js";
|
|
5
4
|
import { buildPiAuthTelegramMessage, getErrorMessage, getPiAuthIssue } from "../../core/agent/auth-flow.js";
|
|
6
5
|
import { createTelegramAuthController } from "./telegram-auth-controller.js";
|
|
7
|
-
import { resolveChatSpeed } from "../../core/agent/model-selection.js";
|
|
8
6
|
import { SessionSeedStore } from "../../core/conversation/session-seed-store.js";
|
|
9
7
|
import { formatDoctorReport } from "../../runtime/doctor.js";
|
|
10
8
|
import { ToolResourceNoteStore } from "../../core/tools/tool-resource-note-store.js";
|
|
11
9
|
import { formatUpdateReport } from "../../runtime/update-manager.js";
|
|
12
10
|
import { cancelRestartReceipt, deliverRestartReceipt, prepareRestartReceipt } from "../../runtime/restart-receipt.js";
|
|
11
|
+
import { consumeWorkerRecoveryReport, loadWorkerRecoveryReport } from "../../runtime/worker-recovery-report.js";
|
|
13
12
|
import { buildUpdatePicker, createTelegramUpdateCallbackHandler } from "./update-command.js";
|
|
14
13
|
import { createTelegramModelControls } from "./model-controls.js";
|
|
15
14
|
import { createTelegramModelCallbackHandler } from "./model-callback.js";
|
|
@@ -18,36 +17,10 @@ import { createTelegramSessionBridgeController } from "./telegram-session-bridge
|
|
|
18
17
|
import { createTelegramToolsCommandHandler } from "./telegram-tools-command.js";
|
|
19
18
|
import { createTelegramWorkspaceController } from "./telegram-workspace-controller.js";
|
|
20
19
|
import { resolveTelegramWorkspaceRoute } from "./workspace-group.js";
|
|
21
|
-
import {
|
|
22
|
-
appendGeneralReplyRoutingInstruction,
|
|
23
|
-
isGeneralWorkspaceRoute,
|
|
24
|
-
routeGeneralWorkspaceReply
|
|
25
|
-
} from "./reply-topic-routing.js";
|
|
26
20
|
import { migrateLegacyReplyTopics, WorkspaceTopicStore } from "./workspace-topic-store.js";
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
buildReactionPrompt,
|
|
31
|
-
buildSessionHandoffPrompt,
|
|
32
|
-
buildStartupMessage,
|
|
33
|
-
collectText,
|
|
34
|
-
getIncomingMessageText,
|
|
35
|
-
isScheduledTaskPrompt,
|
|
36
|
-
isSilentReply,
|
|
37
|
-
normalizeIncomingArtifact,
|
|
38
|
-
sanitizeSessionHandoff,
|
|
39
|
-
scheduledPromptSpeedOptions,
|
|
40
|
-
shouldIncludeArtifactReference,
|
|
41
|
-
withPromptSpeed
|
|
42
|
-
} from "./prompt-builders.js";
|
|
43
|
-
import {
|
|
44
|
-
createChatStateStore,
|
|
45
|
-
createPromptExecutionReceipt,
|
|
46
|
-
drainChatPromptQueue,
|
|
47
|
-
queueChatPrompt,
|
|
48
|
-
resolveTelegramBusyMessageMode,
|
|
49
|
-
routeBusyPrompt
|
|
50
|
-
} from "./chat-queue.js";
|
|
21
|
+
import { buildReactionPrompt, buildStartupMessage } from "./prompt-builders.js";
|
|
22
|
+
import { createChatStateStore, resolveTelegramBusyMessageMode } from "./chat-queue.js";
|
|
23
|
+
import { createTelegramPromptController } from "./telegram-prompt-controller.js";
|
|
51
24
|
export {
|
|
52
25
|
createChatStateStore,
|
|
53
26
|
drainChatPromptQueue,
|
|
@@ -268,30 +241,6 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
268
241
|
logger?.log("telegram", `inherited model ${inherited.model} for workspace topic session ${route.sessionId}`);
|
|
269
242
|
}
|
|
270
243
|
|
|
271
|
-
async function buildIncomingPrompt(ctx, route = contextRoute(ctx)) {
|
|
272
|
-
logger?.log("telegram", `message ${ctx.msg.message_id} in chat ${route.transportChatId} session ${route.sessionId}`);
|
|
273
|
-
const chatArtifactStore = artifactStore.forChat(route.scopeChatId);
|
|
274
|
-
const artifact = await captureIncomingArtifact(ctx, artifactStore, { storageChatId: route.scopeChatId });
|
|
275
|
-
if (artifact) logger?.log("telegram", `captured artifact ${artifact.kind}${artifact.id ? ` ${artifact.id}` : ""}`);
|
|
276
|
-
const { transcript, toolResult, normalizationRequired } = await normalizeIncomingArtifact({
|
|
277
|
-
artifact,
|
|
278
|
-
toolRegistry,
|
|
279
|
-
chatArtifactStore,
|
|
280
|
-
chatId: route.scopeChatId
|
|
281
|
-
});
|
|
282
|
-
if (transcript) logger?.log("telegram", `media transcribed to artifact ${transcript.id}`);
|
|
283
|
-
if (normalizationRequired && !transcript) {
|
|
284
|
-
logger?.log("telegram", `media normalization unavailable for chat ${route.transportChatId}: ${toolResult?.error || toolResult?.missingConfig?.join(", ") || "unknown error"}`);
|
|
285
|
-
}
|
|
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);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
244
|
const {
|
|
296
245
|
createSessionBridge: createTelegramSessionBridge,
|
|
297
246
|
createWorkspaceAccessGuard,
|
|
@@ -310,200 +259,30 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
310
259
|
});
|
|
311
260
|
installArtifactDeliveryHandler();
|
|
312
261
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
accessGuard: createWorkspaceAccessGuard(route)
|
|
338
|
-
});
|
|
339
|
-
let text = "";
|
|
340
|
-
const chatState = getChatState(sessionId);
|
|
341
|
-
chatState.activeSession = session;
|
|
342
|
-
chatState.activeRoute = route;
|
|
343
|
-
try {
|
|
344
|
-
text = await withPromptSpeed(scheduledPromptSpeedOptions({
|
|
345
|
-
prompt,
|
|
346
|
-
session,
|
|
347
|
-
speedController,
|
|
348
|
-
configuredSpeed: resolveChatSpeed(config, sessionId)
|
|
349
|
-
}), () => collectText(session, prompt, {
|
|
350
|
-
logger,
|
|
351
|
-
chatId: sessionId,
|
|
352
|
-
onSlowPrompt: () => bot.api.sendMessage(
|
|
353
|
-
route.transportChatId,
|
|
354
|
-
"This is taking longer than 5 minutes, so I will keep the current session running instead of starting over. Send /new if you want to abandon it and start fresh.",
|
|
355
|
-
messageOptions()
|
|
356
|
-
)
|
|
357
|
-
}));
|
|
358
|
-
} catch (error) {
|
|
359
|
-
agentManager.resetSession(sessionId);
|
|
360
|
-
if (error && typeof error === "object") {
|
|
361
|
-
error.retryable = false;
|
|
362
|
-
error.outcomeUncertain = true;
|
|
363
|
-
}
|
|
364
|
-
throw error;
|
|
365
|
-
} finally {
|
|
366
|
-
if (chatState.activeSession === session) chatState.activeSession = null;
|
|
367
|
-
chatState.activeRoute = null;
|
|
368
|
-
}
|
|
369
|
-
executionReceipt?.resolve({ status: "executed" });
|
|
370
|
-
if (text) {
|
|
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
|
-
}
|
|
388
|
-
await sendTextReply({
|
|
389
|
-
sendText: (message, extra) => bot.api.sendMessage(deliveryRoute.transportChatId, message, deliveryOptions(extra)),
|
|
390
|
-
sendDocument: (file, extra) => bot.api.sendDocument(deliveryRoute.transportChatId, file, deliveryOptions(extra)),
|
|
391
|
-
chatId: sessionId,
|
|
392
|
-
artifactChatId: deliveryRoute.scopeChatId,
|
|
393
|
-
text: routedReply.text
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
if (ctx) return withTyping(ctx, work);
|
|
399
|
-
return work();
|
|
400
|
-
}
|
|
401
|
-
|
|
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
|
-
}) {
|
|
413
|
-
const chatState = getChatState(chatId);
|
|
414
|
-
const receipt = waitForExecution ? createPromptExecutionReceipt(onExecutionStart) : null;
|
|
415
|
-
|
|
416
|
-
if (chatState.processing) {
|
|
417
|
-
const incomingRoute = ctx ? contextRoute(ctx) : null;
|
|
418
|
-
const activeRoute = chatState.activeRoute;
|
|
419
|
-
const sameDelivery = !incomingRoute || !activeRoute || (
|
|
420
|
-
incomingRoute.transportChatId === activeRoute.transportChatId
|
|
421
|
-
&& incomingRoute.threadId === activeRoute.threadId
|
|
422
|
-
);
|
|
423
|
-
const routed = await routeBusyPrompt({
|
|
424
|
-
chatState,
|
|
425
|
-
prompt,
|
|
426
|
-
mode: sameDelivery ? busyMessageMode : "queue",
|
|
427
|
-
replaceQueued,
|
|
428
|
-
ctx,
|
|
429
|
-
receipt,
|
|
430
|
-
coalesceQueued
|
|
431
|
-
});
|
|
432
|
-
if (routed.disposition === "steered") {
|
|
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`);
|
|
436
|
-
} else {
|
|
437
|
-
logger?.log("telegram", `chat ${chatId} busy, queueing ${label}`);
|
|
438
|
-
if (routed.steerError) {
|
|
439
|
-
logger?.log("telegram", `steer failed for chat ${chatId}, queued instead: ${getErrorMessage(routed.steerError)}`);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
if (replaceQueued) chatState.continueAfterClose = true;
|
|
443
|
-
return receipt ? receipt.promise : undefined;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
chatState.processing = true;
|
|
447
|
-
logger?.log("telegram", `processing ${label} in chat ${chatId}`);
|
|
448
|
-
const draining = processChatPromptQueue({ chatId, prompt, label, ctx, initialReceipt: receipt });
|
|
449
|
-
if (!receipt) return draining;
|
|
450
|
-
draining.catch(() => {});
|
|
451
|
-
return receipt.promise;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
function processChatPromptQueue({ chatId, prompt, label, ctx = null, beforeInitialPrompt, initialReceipt = null }) {
|
|
455
|
-
const chatState = getChatState(chatId);
|
|
456
|
-
return drainChatPromptQueue({
|
|
457
|
-
chatState,
|
|
458
|
-
initialPrompt: prompt,
|
|
459
|
-
initialCtx: ctx,
|
|
460
|
-
initialReceipt,
|
|
461
|
-
beforeInitialPrompt,
|
|
462
|
-
processPrompt: ({ prompt: currentPrompt, ctx: currentCtx, receipt }) => {
|
|
463
|
-
logger?.log("telegram", `prompt dispatch for chat ${chatId}`);
|
|
464
|
-
return processPromptForChat({ chatId, prompt: currentPrompt, ctx: currentCtx, executionReceipt: receipt });
|
|
465
|
-
},
|
|
466
|
-
onPromptInterrupted: (error) => {
|
|
467
|
-
logger?.log("telegram", `${label} interrupted by queued /new for chat ${chatId}: ${getErrorMessage(error)}`);
|
|
468
|
-
},
|
|
469
|
-
onPromptFailure: async (error) => {
|
|
470
|
-
const message = getErrorMessage(error);
|
|
471
|
-
logger?.error("telegram", `${label} failed for chat ${chatId}: ${message}`);
|
|
472
|
-
await authController.notifyIssueIfNeeded(chatId, error);
|
|
473
|
-
}
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
async function enqueueOrProcess(ctx) {
|
|
478
|
-
const route = contextRoute(ctx);
|
|
479
|
-
const chatState = getChatState(route.sessionId);
|
|
480
|
-
|
|
481
|
-
if (chatState.processing) {
|
|
482
|
-
await ensureQueuedTelegramTyping(chatState, ctx);
|
|
483
|
-
const incomingPrompt = await buildIncomingPrompt(ctx, route);
|
|
484
|
-
const busyMessageMode = resolveIncomingBusyMessageMode({
|
|
485
|
-
config,
|
|
486
|
-
route,
|
|
487
|
-
message: ctx.message
|
|
488
|
-
});
|
|
489
|
-
return enqueuePrompt({
|
|
490
|
-
chatId: route.sessionId,
|
|
491
|
-
prompt: incomingPrompt,
|
|
492
|
-
label: `message ${ctx.msg.message_id}`,
|
|
493
|
-
busyMessageMode,
|
|
494
|
-
coalesceQueued: busyMessageMode === "steer" && typeof ctx.message?.text === "string",
|
|
495
|
-
ctx
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
const incomingPrompt = await buildIncomingPrompt(ctx, route);
|
|
500
|
-
return enqueuePrompt({
|
|
501
|
-
chatId: route.sessionId,
|
|
502
|
-
prompt: incomingPrompt,
|
|
503
|
-
label: `message ${ctx.msg.message_id}`,
|
|
504
|
-
ctx
|
|
505
|
-
});
|
|
506
|
-
}
|
|
262
|
+
const {
|
|
263
|
+
enqueueOrProcess,
|
|
264
|
+
enqueuePrompt,
|
|
265
|
+
handleNewCommand
|
|
266
|
+
} = createTelegramPromptController({
|
|
267
|
+
config,
|
|
268
|
+
api: bot.api,
|
|
269
|
+
artifactStore,
|
|
270
|
+
toolRegistry,
|
|
271
|
+
agentManager,
|
|
272
|
+
sessionSeeds,
|
|
273
|
+
workspaceTopics,
|
|
274
|
+
logger,
|
|
275
|
+
contextRoute,
|
|
276
|
+
getChatState,
|
|
277
|
+
createTelegramSessionBridge,
|
|
278
|
+
createWorkspaceAccessGuard,
|
|
279
|
+
sendTextReply,
|
|
280
|
+
authController,
|
|
281
|
+
ensureWorkspaceTopicModelSelection,
|
|
282
|
+
ensureQueuedTyping: ensureQueuedTelegramTyping,
|
|
283
|
+
withTyping,
|
|
284
|
+
resolveBusyMessageMode: resolveIncomingBusyMessageMode
|
|
285
|
+
});
|
|
507
286
|
|
|
508
287
|
async function migrateConfiguredReplyTopics() {
|
|
509
288
|
const migratedGroups = await migrateLegacyReplyTopics(config, workspaceTopics);
|
|
@@ -513,15 +292,28 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
513
292
|
}
|
|
514
293
|
|
|
515
294
|
async function sendStartupMessages() {
|
|
295
|
+
let recovery = null;
|
|
296
|
+
try {
|
|
297
|
+
recovery = await loadWorkerRecoveryReport();
|
|
298
|
+
} catch (error) {
|
|
299
|
+
logger?.log("telegram", `worker recovery report load failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
300
|
+
}
|
|
301
|
+
let recoveryDelivered = false;
|
|
516
302
|
for (const chatId of config.telegram.authorizedChatIds || []) {
|
|
517
303
|
try {
|
|
518
304
|
logger?.log("telegram", `sending startup message for chat ${chatId}`);
|
|
519
305
|
const chatMeta = config.telegram.chatMeta[chatId] || {};
|
|
520
|
-
await bot.api.sendMessage(chatId, buildStartupMessage(chatMeta));
|
|
306
|
+
await bot.api.sendMessage(chatId, recovery?.text || buildStartupMessage(chatMeta));
|
|
307
|
+
if (recovery) recoveryDelivered = true;
|
|
521
308
|
} catch (error) {
|
|
522
309
|
logger?.log("telegram", `startup message failed for chat ${chatId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
523
310
|
}
|
|
524
311
|
}
|
|
312
|
+
if (recovery && recoveryDelivered) {
|
|
313
|
+
await consumeWorkerRecoveryReport(recovery.report.id).catch((error) => {
|
|
314
|
+
logger?.log("telegram", `worker recovery report cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
525
317
|
try {
|
|
526
318
|
const result = await deliverRestartReceipt((chatId, text, options) => bot.api.sendMessage(chatId, text, options));
|
|
527
319
|
if (result) logger?.log("telegram", `delivered restart receipt ${result.receipt.id}`);
|
|
@@ -600,76 +392,6 @@ export async function createTelegramBot({ config, artifactStore, toolRegistry, t
|
|
|
600
392
|
logger
|
|
601
393
|
});
|
|
602
394
|
|
|
603
|
-
async function summarizeSessionBeforeReset(chatId, route = {
|
|
604
|
-
workspace: false,
|
|
605
|
-
sessionId: String(chatId),
|
|
606
|
-
scopeChatId: chatId,
|
|
607
|
-
transportChatId: chatId,
|
|
608
|
-
threadId: null
|
|
609
|
-
}) {
|
|
610
|
-
try {
|
|
611
|
-
const context = await agentManager.getSessionContext(chatId, createTelegramSessionBridge(route), {
|
|
612
|
-
scopeChatId: route.scopeChatId,
|
|
613
|
-
accessGuard: createWorkspaceAccessGuard(route)
|
|
614
|
-
});
|
|
615
|
-
const parentSession = context.session.sessionFile || "";
|
|
616
|
-
if (!context.session.messages.length) return { handoff: "", parentSession: "" };
|
|
617
|
-
|
|
618
|
-
const summary = await collectText(context.session, buildSessionHandoffPrompt(), { logger, chatId });
|
|
619
|
-
return { handoff: sanitizeSessionHandoff(summary), parentSession };
|
|
620
|
-
} catch (error) {
|
|
621
|
-
logger?.log("agent", `session handoff summary failed for chat ${chatId}: ${getErrorMessage(error)}`);
|
|
622
|
-
return { handoff: "", parentSession: "" };
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
async function handleNewCommand(ctx) {
|
|
627
|
-
const route = contextRoute(ctx);
|
|
628
|
-
const sessionId = route.sessionId;
|
|
629
|
-
const chatState = getChatState(sessionId);
|
|
630
|
-
const wasProcessing = chatState.processing;
|
|
631
|
-
chatState.historyRevision += 1;
|
|
632
|
-
const commandRevision = chatState.historyRevision;
|
|
633
|
-
const prompt = buildNewSessionPrompt(ctx);
|
|
634
|
-
|
|
635
|
-
if (wasProcessing) {
|
|
636
|
-
logger?.log("telegram", `chat ${sessionId} busy, queueing new-session command`);
|
|
637
|
-
queueChatPrompt(chatState, prompt, { replace: true, ctx });
|
|
638
|
-
chatState.continueAfterClose = true;
|
|
639
|
-
const reset = (async () => {
|
|
640
|
-
await sessionSeeds.clear(sessionId);
|
|
641
|
-
agentManager.resetSession(sessionId);
|
|
642
|
-
})();
|
|
643
|
-
chatState.beforeNextPrompt = reset;
|
|
644
|
-
try {
|
|
645
|
-
await reset;
|
|
646
|
-
} finally {
|
|
647
|
-
if (chatState.beforeNextPrompt === reset) chatState.beforeNextPrompt = null;
|
|
648
|
-
}
|
|
649
|
-
return;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
chatState.processing = true;
|
|
653
|
-
logger?.log("telegram", `processing new-session command in chat ${sessionId}`);
|
|
654
|
-
await processChatPromptQueue({
|
|
655
|
-
chatId: sessionId,
|
|
656
|
-
prompt,
|
|
657
|
-
label: "new-session command",
|
|
658
|
-
ctx,
|
|
659
|
-
beforeInitialPrompt: async () => {
|
|
660
|
-
const handoff = await withTyping(ctx, () => summarizeSessionBeforeReset(sessionId, route));
|
|
661
|
-
if (chatState.historyRevision !== commandRevision) return;
|
|
662
|
-
if (route.workspace && route.threadId) {
|
|
663
|
-
await sessionSeeds.set(sessionId, handoff.handoff);
|
|
664
|
-
} else {
|
|
665
|
-
await sessionSeeds.clear(sessionId);
|
|
666
|
-
}
|
|
667
|
-
if (chatState.historyRevision !== commandRevision) return;
|
|
668
|
-
agentManager.resetSession(sessionId, handoff);
|
|
669
|
-
}
|
|
670
|
-
});
|
|
671
|
-
}
|
|
672
|
-
|
|
673
395
|
bot.catch((error) => {
|
|
674
396
|
logger?.error("telegram", `bot error: ${error instanceof Error ? error.message : String(error)}`);
|
|
675
397
|
console.error("Telegram bot error:", error);
|
|
@@ -4,12 +4,15 @@ import { clampModelSpeed } from "../../core/agent/model-speed.js";
|
|
|
4
4
|
|
|
5
5
|
const slowPromptNoticeMs = 300_000;
|
|
6
6
|
|
|
7
|
-
function quotedMessageSummary(
|
|
7
|
+
function quotedMessageSummary(incomingMessage) {
|
|
8
|
+
const message = incomingMessage?.reply_to_message;
|
|
8
9
|
if (!message) return [];
|
|
9
10
|
|
|
10
11
|
const fromName = message.from?.username
|
|
11
12
|
? `@${message.from.username}`
|
|
12
13
|
: [message.from?.first_name, message.from?.last_name].filter(Boolean).join(" ") || "unknown";
|
|
14
|
+
const quotedSelection = incomingMessage.quote?.text;
|
|
15
|
+
const quotedTopicName = message.forum_topic_created?.name;
|
|
13
16
|
|
|
14
17
|
const parts = [
|
|
15
18
|
`quotedMessageId: ${message.message_id}`,
|
|
@@ -18,6 +21,7 @@ function quotedMessageSummary(message) {
|
|
|
18
21
|
|
|
19
22
|
if (message.text) parts.push(`quotedText: ${message.text}`);
|
|
20
23
|
if (message.caption) parts.push(`quotedCaption: ${message.caption}`);
|
|
24
|
+
if (quotedSelection) parts.push(`quotedSelection: ${quotedSelection}`);
|
|
21
25
|
if (message.voice) parts.push(`quotedKind: voice`);
|
|
22
26
|
if (message.audio) parts.push(`quotedKind: audio`);
|
|
23
27
|
if (message.photo?.length) parts.push(`quotedKind: image`);
|
|
@@ -25,8 +29,9 @@ function quotedMessageSummary(message) {
|
|
|
25
29
|
if (message.video) parts.push(`quotedKind: video`);
|
|
26
30
|
if (message.sticker) parts.push(`quotedKind: sticker`);
|
|
27
31
|
if (message.location) parts.push(`quotedKind: location`, `quotedLocation: ${formatLocationText(message)}`);
|
|
32
|
+
if (message.forum_topic_created) parts.push(`quotedKind: forum_topic_created`, `quotedTopicName: ${quotedTopicName || "unknown"}`);
|
|
28
33
|
|
|
29
|
-
if (!message.text && !message.caption) {
|
|
34
|
+
if (!message.text && !message.caption && !quotedSelection && !quotedTopicName) {
|
|
30
35
|
parts.push(`Important: this message replies to a Telegram message with no textual body available in the update. Use the quoted kind and metadata as context.`);
|
|
31
36
|
}
|
|
32
37
|
|
|
@@ -126,7 +131,7 @@ export function buildPrompt({ ctx, artifact, transcript, toolResult }) {
|
|
|
126
131
|
const messageText = getIncomingMessageText(ctx.message);
|
|
127
132
|
if (messageText) parts.push(`text: ${messageText}`);
|
|
128
133
|
parts.push(...forwardedMessageSummary(ctx.message));
|
|
129
|
-
parts.push(...quotedMessageSummary(ctx.message
|
|
134
|
+
parts.push(...quotedMessageSummary(ctx.message));
|
|
130
135
|
if (shouldIncludeArtifactReference({ artifact, messageText })) {
|
|
131
136
|
if (artifact?.path) parts.push(`artifactPath: ${artifact.path}`);
|
|
132
137
|
if (artifact?.id) parts.push(`artifactId: ${artifact.id}`);
|