@llblab/pi-telegram 0.27.11 → 0.28.0
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 +150 -258
- package/BACKLOG.md +1 -169
- package/CHANGELOG.md +396 -441
- package/README.md +9 -6
- package/api/updates.ts +5 -0
- package/docs/architecture.md +71 -26
- package/docs/multi-instance-bus.md +23 -5
- package/docs/public-api.md +7 -6
- package/docs/ui-style.md +6 -6
- package/docs/updates.md +29 -11
- package/index.ts +356 -246
- package/lib/activity-verbosity.ts +26 -0
- package/lib/bindings.ts +240 -2
- package/lib/bus-follower.ts +436 -238
- package/lib/bus-leader.ts +395 -42
- package/lib/bus.ts +994 -153
- package/lib/commands.ts +184 -30
- package/lib/config.ts +23 -2
- package/lib/journal.ts +3140 -0
- package/lib/lifecycle.ts +4 -0
- package/lib/locks.ts +21 -21
- package/lib/media.ts +71 -32
- package/lib/menu-queue.ts +31 -17
- package/lib/menu.ts +5 -3
- package/lib/model.ts +51 -24
- package/lib/ownership.ts +42 -7
- package/lib/paths.ts +35 -0
- package/lib/polling.ts +591 -106
- package/lib/prompts.ts +17 -0
- package/lib/queue.ts +732 -143
- package/lib/routing.ts +291 -64
- package/lib/runtime.ts +26 -10
- package/lib/status.ts +257 -18
- package/lib/sync.ts +131 -5
- package/lib/telegram-api.ts +41 -11
- package/lib/text-groups.ts +75 -35
- package/lib/threads.ts +112 -4
- package/lib/turns.ts +79 -14
- package/lib/updates.ts +3771 -223
- package/package.json +3 -3
- package/scripts/check-downgrade.mjs +435 -0
package/lib/turns.ts
CHANGED
|
@@ -22,28 +22,23 @@ import {
|
|
|
22
22
|
type DownloadTelegramMessageFilesDeps,
|
|
23
23
|
type TelegramMediaMessage,
|
|
24
24
|
} from "./media.ts";
|
|
25
|
-
import
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
import {
|
|
26
|
+
createTelegramQueueAdmissionReceipt,
|
|
27
|
+
truncateTelegramQueueSummary,
|
|
28
|
+
type PendingTelegramTurn,
|
|
29
|
+
type TelegramPromptContent,
|
|
30
|
+
type TelegramQueueAdmissionReceipt,
|
|
31
|
+
type TelegramQueueItem,
|
|
32
|
+
type TelegramQueueStore,
|
|
30
33
|
} from "./queue.ts";
|
|
31
34
|
|
|
32
35
|
import {
|
|
33
36
|
computeVoicePromptContribution,
|
|
34
37
|
computeVoiceTurnFlags,
|
|
35
38
|
getTelegramVoiceReplyMode,
|
|
36
|
-
TELEGRAM_VOICE_REPLY_MODES,
|
|
37
39
|
type TelegramVoiceReplyMode,
|
|
38
40
|
} from "./voice.ts";
|
|
39
41
|
|
|
40
|
-
// Re-export for backward compatibility with existing namespace imports (e.g. Turns.getTelegramVoiceReplyMode in routing.ts)
|
|
41
|
-
export {
|
|
42
|
-
getTelegramVoiceReplyMode,
|
|
43
|
-
TELEGRAM_VOICE_REPLY_MODES,
|
|
44
|
-
type TelegramVoiceReplyMode,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
42
|
export const TELEGRAM_PREFIX = "[telegram]";
|
|
48
43
|
|
|
49
44
|
export interface TelegramTurnTarget {
|
|
@@ -55,6 +50,7 @@ export interface TelegramTurnMessage {
|
|
|
55
50
|
message_id: number;
|
|
56
51
|
message_thread_id?: number;
|
|
57
52
|
pi_telegram_agent_source_thread?: string;
|
|
53
|
+
pi_telegram_source_update_id?: number;
|
|
58
54
|
chat: { id: number; type?: string };
|
|
59
55
|
}
|
|
60
56
|
|
|
@@ -93,7 +89,6 @@ export function formatTelegramTurnPrefix(
|
|
|
93
89
|
return basePrefix;
|
|
94
90
|
}
|
|
95
91
|
|
|
96
|
-
import { truncateTelegramQueueSummary } from "./queue.ts";
|
|
97
92
|
export { truncateTelegramQueueSummary };
|
|
98
93
|
|
|
99
94
|
export function formatTelegramTurnStatusSummary(
|
|
@@ -417,6 +412,8 @@ export interface BuildTelegramPromptTurnOptions {
|
|
|
417
412
|
inferImageMimeType: (path: string) => string | undefined;
|
|
418
413
|
voiceReplyMode?: TelegramVoiceReplyMode;
|
|
419
414
|
voicePromptContribution?: string;
|
|
415
|
+
admissionScope?: string;
|
|
416
|
+
admissionJournalBinding?: string;
|
|
420
417
|
}
|
|
421
418
|
|
|
422
419
|
export type BuildTelegramPromptTurnRuntimeOptions = Omit<
|
|
@@ -445,6 +442,9 @@ export interface TelegramPromptTurnRuntimeBuilderDeps<
|
|
|
445
442
|
message_thread_id?: number;
|
|
446
443
|
}) => string | undefined;
|
|
447
444
|
getAllowedUserId?: () => number | undefined;
|
|
445
|
+
getAdmissionScope?: () => string | undefined;
|
|
446
|
+
getAdmissionJournalBinding?: () => string | undefined;
|
|
447
|
+
assertExecutionCurrent?: (message: TelegramTurnMessage) => void;
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
export function createTelegramPromptTurnRuntimeBuilder<
|
|
@@ -460,12 +460,14 @@ export function createTelegramPromptTurnRuntimeBuilder<
|
|
|
460
460
|
return async (messages, historyTurns = [], ctx) => {
|
|
461
461
|
const rawText = extractTelegramMessagesText(messages);
|
|
462
462
|
const firstMessage = messages[0];
|
|
463
|
+
if (firstMessage) deps.assertExecutionCurrent?.(firstMessage);
|
|
463
464
|
const replyFiles = firstMessage?.reply_to_message
|
|
464
465
|
? await downloadTelegramMessageFiles(
|
|
465
466
|
[firstMessage.reply_to_message as typeof firstMessage],
|
|
466
467
|
{ downloadFile: deps.downloadFile },
|
|
467
468
|
)
|
|
468
469
|
: [];
|
|
470
|
+
if (firstMessage) deps.assertExecutionCurrent?.(firstMessage);
|
|
469
471
|
const replyContext = firstMessage
|
|
470
472
|
? buildTelegramReplyContextBlock(firstMessage, replyFiles)
|
|
471
473
|
: "";
|
|
@@ -490,9 +492,11 @@ export function createTelegramPromptTurnRuntimeBuilder<
|
|
|
490
492
|
const files = await downloadTelegramMessageFiles(messages, {
|
|
491
493
|
downloadFile: deps.downloadFile,
|
|
492
494
|
});
|
|
495
|
+
if (firstMessage) deps.assertExecutionCurrent?.(firstMessage);
|
|
493
496
|
const processed = deps.processAttachments
|
|
494
497
|
? await deps.processAttachments(files, rawText, ctx as TContext)
|
|
495
498
|
: { rawText, promptFiles: files };
|
|
499
|
+
if (firstMessage) deps.assertExecutionCurrent?.(firstMessage);
|
|
496
500
|
const sourceBlocks: string[] = [];
|
|
497
501
|
let promptRawText = processed.rawText;
|
|
498
502
|
const forwardedFilePaths = new Set<string>();
|
|
@@ -579,6 +583,8 @@ export function createTelegramPromptTurnRuntimeBuilder<
|
|
|
579
583
|
files,
|
|
580
584
|
rawText,
|
|
581
585
|
),
|
|
586
|
+
admissionScope: deps.getAdmissionScope?.(),
|
|
587
|
+
admissionJournalBinding: deps.getAdmissionJournalBinding?.(),
|
|
582
588
|
});
|
|
583
589
|
};
|
|
584
590
|
}
|
|
@@ -596,6 +602,58 @@ function getTelegramVoicePromptContext(
|
|
|
596
602
|
return { delivery: "automatic voice" };
|
|
597
603
|
}
|
|
598
604
|
|
|
605
|
+
function collectTelegramTurnAdmissionReceipts(
|
|
606
|
+
messages: TelegramTurnMessage[],
|
|
607
|
+
historyTurns: PendingTelegramTurn[],
|
|
608
|
+
admissionScope: string | undefined,
|
|
609
|
+
admissionJournalBinding: string | undefined,
|
|
610
|
+
): TelegramQueueAdmissionReceipt[] {
|
|
611
|
+
const receipts = new Map<string, TelegramQueueAdmissionReceipt>();
|
|
612
|
+
const addReceipt = (receipt: TelegramQueueAdmissionReceipt): void => {
|
|
613
|
+
const existing = receipts.get(receipt.receiptId);
|
|
614
|
+
if (existing) {
|
|
615
|
+
if (
|
|
616
|
+
existing.queueKind !== receipt.queueKind ||
|
|
617
|
+
existing.journalBindingKey !== receipt.journalBindingKey ||
|
|
618
|
+
existing.sourceUpdateIds.length !== receipt.sourceUpdateIds.length ||
|
|
619
|
+
existing.sourceUpdateIds.some(
|
|
620
|
+
(updateId, index) => updateId !== receipt.sourceUpdateIds[index],
|
|
621
|
+
)
|
|
622
|
+
) {
|
|
623
|
+
throw new Error(
|
|
624
|
+
`Conflicting Telegram turn receipt: ${receipt.receiptId}`,
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
receipts.set(receipt.receiptId, structuredClone(receipt));
|
|
630
|
+
};
|
|
631
|
+
for (const turn of historyTurns) {
|
|
632
|
+
for (const receipt of turn.admissionReceipts ?? []) addReceipt(receipt);
|
|
633
|
+
}
|
|
634
|
+
const sourceUpdateIds = messages.flatMap((message) =>
|
|
635
|
+
typeof message.pi_telegram_source_update_id === "number"
|
|
636
|
+
? [message.pi_telegram_source_update_id]
|
|
637
|
+
: [],
|
|
638
|
+
);
|
|
639
|
+
if (sourceUpdateIds.length > 0) {
|
|
640
|
+
const currentReceipt = createTelegramQueueAdmissionReceipt({
|
|
641
|
+
queueKind: "prompt",
|
|
642
|
+
scope: admissionScope ?? "",
|
|
643
|
+
sourceUpdateIds,
|
|
644
|
+
});
|
|
645
|
+
if (currentReceipt) {
|
|
646
|
+
addReceipt({
|
|
647
|
+
...currentReceipt,
|
|
648
|
+
...(admissionJournalBinding
|
|
649
|
+
? { journalBindingKey: admissionJournalBinding }
|
|
650
|
+
: {}),
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return [...receipts.values()];
|
|
655
|
+
}
|
|
656
|
+
|
|
599
657
|
export async function buildTelegramPromptTurn(
|
|
600
658
|
options: BuildTelegramPromptTurnOptions,
|
|
601
659
|
): Promise<PendingTelegramTurn> {
|
|
@@ -648,6 +706,12 @@ export async function buildTelegramPromptTurn(
|
|
|
648
706
|
textItem.text = `${textItem.text}\n\n${options.voicePromptContribution.trim()}`;
|
|
649
707
|
}
|
|
650
708
|
}
|
|
709
|
+
const admissionReceipts = collectTelegramTurnAdmissionReceipts(
|
|
710
|
+
options.messages,
|
|
711
|
+
options.historyTurns ?? [],
|
|
712
|
+
options.admissionScope,
|
|
713
|
+
options.admissionJournalBinding,
|
|
714
|
+
);
|
|
651
715
|
|
|
652
716
|
return {
|
|
653
717
|
kind: "prompt",
|
|
@@ -673,6 +737,7 @@ export async function buildTelegramPromptTurn(
|
|
|
673
737
|
options.displayFiles ?? options.promptFiles ?? options.files,
|
|
674
738
|
options.handlerOutputs,
|
|
675
739
|
),
|
|
740
|
+
...(admissionReceipts.length > 0 ? { admissionReceipts } : {}),
|
|
676
741
|
// Voice tagging (used for preview suppression and prompt guidance)
|
|
677
742
|
...computeVoiceTurnFlags(voiceReplyMode, hasVoiceFile),
|
|
678
743
|
};
|