@llblab/pi-telegram 0.52.1 → 0.53.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 +10 -8
- package/BACKLOG.md +1 -16
- package/CHANGELOG.md +17 -0
- package/README.md +8 -10
- package/api/commands.ts +3 -0
- package/dist/api/commands.d.ts +1 -1
- package/dist/lib/activity-verbosity.d.ts +1 -5
- package/dist/lib/activity-verbosity.js +15 -42
- package/dist/lib/activity.d.ts +9 -0
- package/dist/lib/activity.js +39 -10
- package/dist/lib/agent-messages.js +7 -3
- package/dist/lib/bindings.d.ts +43 -5
- package/dist/lib/bindings.js +163 -20
- package/dist/lib/bus-api.d.ts +12 -0
- package/dist/lib/bus-api.js +182 -79
- package/dist/lib/bus-follower.d.ts +111 -31
- package/dist/lib/bus-follower.js +1324 -359
- package/dist/lib/bus-leader.d.ts +41 -91
- package/dist/lib/bus-leader.js +969 -637
- package/dist/lib/bus-transport.js +16 -9
- package/dist/lib/bus.d.ts +215 -18
- package/dist/lib/bus.js +1048 -327
- package/dist/lib/channel-posts.d.ts +5 -0
- package/dist/lib/channel-posts.js +434 -261
- package/dist/lib/command-templates.d.ts +26 -5
- package/dist/lib/command-templates.js +92 -176
- package/dist/lib/commands.d.ts +168 -82
- package/dist/lib/commands.js +1409 -291
- package/dist/lib/config.d.ts +1 -8
- package/dist/lib/config.js +34 -76
- package/dist/lib/delivery.d.ts +2 -2
- package/dist/lib/delivery.js +16 -16
- package/dist/lib/extension.js +640 -171
- package/dist/lib/generative-app-worker.mjs +19 -7
- package/dist/lib/generative-apps.d.ts +0 -5
- package/dist/lib/generative-apps.js +61 -49
- package/dist/lib/inbound.d.ts +5 -0
- package/dist/lib/inbound.js +35 -59
- package/dist/lib/journal.d.ts +33 -3
- package/dist/lib/journal.js +2063 -782
- package/dist/lib/lifecycle.d.ts +2 -6
- package/dist/lib/lifecycle.js +75 -58
- package/dist/lib/locks.d.ts +34 -3
- package/dist/lib/locks.js +318 -119
- package/dist/lib/logging.js +50 -14
- package/dist/lib/media.d.ts +22 -1
- package/dist/lib/media.js +46 -28
- package/dist/lib/menu-model.d.ts +19 -5
- package/dist/lib/menu-model.js +53 -11
- package/dist/lib/menu-queue.d.ts +5 -4
- package/dist/lib/menu-queue.js +45 -63
- package/dist/lib/menu-settings.d.ts +5 -4
- package/dist/lib/menu-settings.js +114 -78
- package/dist/lib/menu-status.d.ts +1 -1
- package/dist/lib/menu-status.js +8 -25
- package/dist/lib/menu-thinking.d.ts +6 -1
- package/dist/lib/menu-thinking.js +14 -21
- package/dist/lib/menu.d.ts +8 -61
- package/dist/lib/menu.js +92 -164
- package/dist/lib/model.d.ts +1 -1
- package/dist/lib/model.js +2 -16
- package/dist/lib/outbound-attachments.d.ts +6 -27
- package/dist/lib/outbound-attachments.js +45 -38
- package/dist/lib/outbound-buttons.js +22 -16
- package/dist/lib/outbound-markup.d.ts +0 -2
- package/dist/lib/outbound-markup.js +51 -64
- package/dist/lib/outbound-voice.js +6 -3
- package/dist/lib/outbound.d.ts +6 -6
- package/dist/lib/outbound.js +61 -51
- package/dist/lib/ownership.js +6 -2
- package/dist/lib/paths.d.ts +5 -0
- package/dist/lib/paths.js +37 -21
- package/dist/lib/pi.d.ts +2 -0
- package/dist/lib/pi.js +8 -1
- package/dist/lib/polling.d.ts +23 -37
- package/dist/lib/polling.js +71 -52
- package/dist/lib/preview.js +39 -19
- package/dist/lib/process-identity.d.ts +24 -0
- package/dist/lib/process-identity.js +133 -0
- package/dist/lib/prompts.js +2 -7
- package/dist/lib/queue.d.ts +14 -16
- package/dist/lib/queue.js +249 -126
- package/dist/lib/recovery.d.ts +2 -83
- package/dist/lib/recovery.js +20 -274
- package/dist/lib/replies.d.ts +16 -24
- package/dist/lib/replies.js +99 -116
- package/dist/lib/routing.d.ts +120 -7
- package/dist/lib/routing.js +4667 -1152
- package/dist/lib/runtime.d.ts +1 -11
- package/dist/lib/sections.d.ts +4 -29
- package/dist/lib/sections.js +7 -20
- package/dist/lib/skills.js +4 -3
- package/dist/lib/status.js +86 -57
- package/dist/lib/sync.d.ts +6 -3
- package/dist/lib/sync.js +112 -45
- package/dist/lib/target.d.ts +4 -0
- package/dist/lib/target.js +18 -0
- package/dist/lib/telegram-api.d.ts +18 -13
- package/dist/lib/telegram-api.js +165 -53
- package/dist/lib/text-groups.js +4 -39
- package/dist/lib/thread-cleanup-manager.d.ts +6 -27
- package/dist/lib/thread-cleanup-manager.js +369 -186
- package/dist/lib/thread-display.d.ts +1 -2
- package/dist/lib/thread-display.js +58 -38
- package/dist/lib/thread-naming.d.ts +28 -8
- package/dist/lib/thread-naming.js +175 -66
- package/dist/lib/thread-reconciler.d.ts +42 -16
- package/dist/lib/thread-reconciler.js +90 -50
- package/dist/lib/threads.d.ts +82 -20
- package/dist/lib/threads.js +2247 -855
- package/dist/lib/time-injection.js +1 -2
- package/dist/lib/turns.js +1 -19
- package/dist/lib/updates.d.ts +169 -80
- package/dist/lib/updates.js +2418 -641
- package/dist/lib/voice.d.ts +7 -22
- package/dist/lib/voice.js +7 -22
- package/dist/lib/wire.js +1 -1
- package/dist/lib/workspace-admission.d.ts +3 -1
- package/dist/lib/workspace-admission.js +425 -211
- package/dist/lib/workspace-identity.js +8 -13
- package/dist/lib/workspace-retirement.d.ts +1 -1
- package/dist/lib/workspace-retirement.js +328 -140
- package/dist/lib/workspace-slots.js +8 -4
- package/dist/package.json +1 -1
- package/docs/architecture.md +36 -30
- package/docs/inbound.md +1 -1
- package/docs/multi-instance-bus.md +15 -3
- package/docs/outbound.md +1 -1
- package/docs/public-api.md +29 -1
- package/docs/ui-style.md +25 -8
- package/lib/activity-verbosity.ts +59 -82
- package/lib/activity.ts +146 -102
- package/lib/agent-messages.ts +12 -5
- package/lib/bindings.ts +389 -82
- package/lib/bus-api.ts +263 -102
- package/lib/bus-follower.ts +2440 -601
- package/lib/bus-leader.ts +2209 -1290
- package/lib/bus-transport.ts +46 -12
- package/lib/bus.ts +1673 -444
- package/lib/channel-posts.ts +848 -327
- package/lib/command-templates.ts +152 -265
- package/lib/commands.ts +2398 -555
- package/lib/config.ts +177 -170
- package/lib/delivery.ts +41 -29
- package/lib/extension.ts +1207 -433
- package/lib/generative-app-worker.mjs +19 -7
- package/lib/generative-apps.ts +324 -211
- package/lib/inbound.ts +95 -97
- package/lib/journal.ts +5311 -1763
- package/lib/keyboard.ts +1 -3
- package/lib/lifecycle.ts +128 -78
- package/lib/locks.ts +703 -212
- package/lib/logging.ts +147 -58
- package/lib/media.ts +82 -43
- package/lib/menu-model.ts +85 -18
- package/lib/menu-queue.ts +88 -129
- package/lib/menu-settings.ts +260 -155
- package/lib/menu-status.ts +20 -60
- package/lib/menu-thinking.ts +41 -56
- package/lib/menu.ts +112 -285
- package/lib/model.ts +8 -22
- package/lib/outbound-attachments.ts +156 -125
- package/lib/outbound-buttons.ts +76 -49
- package/lib/outbound-markup.ts +96 -94
- package/lib/outbound-voice.ts +33 -27
- package/lib/outbound.ts +125 -125
- package/lib/ownership.ts +19 -10
- package/lib/paths.ts +148 -49
- package/lib/pi.ts +35 -15
- package/lib/polling.ts +165 -149
- package/lib/preview.ts +93 -40
- package/lib/process-identity.ts +164 -0
- package/lib/prompts.ts +4 -11
- package/lib/queue.ts +511 -300
- package/lib/recovery.ts +50 -454
- package/lib/rendering.ts +1 -3
- package/lib/replies.ts +248 -209
- package/lib/routing.ts +8509 -2186
- package/lib/runtime.ts +1 -12
- package/lib/sections.ts +24 -89
- package/lib/setup.ts +1 -3
- package/lib/skills.ts +9 -4
- package/lib/status.ts +215 -110
- package/lib/sync.ts +488 -359
- package/lib/target.ts +22 -3
- package/lib/telegram-api.ts +322 -127
- package/lib/text-groups.ts +5 -39
- package/lib/thread-cleanup-manager.ts +833 -331
- package/lib/thread-display.ts +213 -97
- package/lib/thread-naming.ts +232 -87
- package/lib/thread-reconciler.ts +155 -72
- package/lib/threads.ts +5318 -1845
- package/lib/time-injection.ts +1 -4
- package/lib/turns.ts +15 -28
- package/lib/updates.ts +5184 -1612
- package/lib/voice.ts +7 -35
- package/lib/wire.ts +1 -1
- package/lib/workspace-admission.ts +996 -416
- package/lib/workspace-identity.ts +14 -17
- package/lib/workspace-retirement.ts +878 -376
- package/lib/workspace-slots.ts +22 -13
- package/package.json +1 -1
- package/scripts/check-downgrade.mjs +0 -472
- package/scripts/measure-workspace.mjs +0 -108
package/dist/lib/polling.js
CHANGED
|
@@ -14,7 +14,8 @@ export const TELEGRAM_GET_UPDATES_CONFLICT_STOP_LIMIT = 10;
|
|
|
14
14
|
const TELEGRAM_GET_UPDATES_CONFLICT_FAST_RETRY_LIMIT = 3;
|
|
15
15
|
const TELEGRAM_GET_UPDATES_CONFLICT_FAST_RETRY_MS = 1_000;
|
|
16
16
|
const TELEGRAM_GET_UPDATES_CONFLICT_SLOW_RETRY_MS = 3_000;
|
|
17
|
-
const
|
|
17
|
+
const TELEGRAM_POLLING_RETRY_BASE_MS = 1_000;
|
|
18
|
+
const TELEGRAM_POLLING_RETRY_MAX_MS = 30_000;
|
|
18
19
|
const TELEGRAM_GET_UPDATES_GRACE_MS = 10_000;
|
|
19
20
|
// Standard Telegram DM polling does not expose ordinary message-deletion events.
|
|
20
21
|
// Business deletions belong to a separate namespace and default routing ignores them.
|
|
@@ -51,6 +52,11 @@ export class TelegramPersistentGetUpdatesConflictError extends Error {
|
|
|
51
52
|
this.count = count;
|
|
52
53
|
}
|
|
53
54
|
}
|
|
55
|
+
/** Exponential backoff for non-conflict polling/admission failures. */
|
|
56
|
+
export function getTelegramPollingRetryDelayMs(consecutiveFailures) {
|
|
57
|
+
const exponent = Math.max(0, Math.min(consecutiveFailures - 1, 16));
|
|
58
|
+
return Math.min(TELEGRAM_POLLING_RETRY_BASE_MS * 2 ** exponent, TELEGRAM_POLLING_RETRY_MAX_MS);
|
|
59
|
+
}
|
|
54
60
|
export class TelegramGetUpdatesTimeoutError extends Error {
|
|
55
61
|
timeoutMs;
|
|
56
62
|
constructor(timeoutMs) {
|
|
@@ -152,7 +158,10 @@ export function createTelegramDurablePollingRuntimeAssembly(deps) {
|
|
|
152
158
|
}
|
|
153
159
|
catch (error) {
|
|
154
160
|
try {
|
|
155
|
-
deps.recordRuntimeEvent?.("polling", error, {
|
|
161
|
+
deps.recordRuntimeEvent?.("polling", error, {
|
|
162
|
+
phase: "batch-preparation",
|
|
163
|
+
updateCount: updates.length,
|
|
164
|
+
});
|
|
156
165
|
}
|
|
157
166
|
catch {
|
|
158
167
|
// Already-published input must still reach the worker if diagnostics fail.
|
|
@@ -356,8 +365,13 @@ export function startTelegramPollingRuntime(ctx, deps) {
|
|
|
356
365
|
deps.setPollingController(undefined);
|
|
357
366
|
if (!ownsPromise && !ownsController)
|
|
358
367
|
return;
|
|
359
|
-
deps.onPollingStopped?.(controller.signal.aborted
|
|
360
|
-
? "
|
|
368
|
+
deps.onPollingStopped?.(controller.signal.aborted
|
|
369
|
+
? "requested"
|
|
370
|
+
: persistentConflict
|
|
371
|
+
? "persistent-conflict"
|
|
372
|
+
: failed
|
|
373
|
+
? "failed"
|
|
374
|
+
: "completed");
|
|
361
375
|
// Detach the inner promise before outer teardown calls polling.stop().
|
|
362
376
|
if (persistentConflict && !controller.signal.aborted) {
|
|
363
377
|
try {
|
|
@@ -367,12 +381,15 @@ export function startTelegramPollingRuntime(ctx, deps) {
|
|
|
367
381
|
else {
|
|
368
382
|
deps.stopTypingLoop();
|
|
369
383
|
deps.recordRuntimeEvent?.("polling", persistentConflict, {
|
|
370
|
-
phase: "persistent-conflict",
|
|
384
|
+
phase: "persistent-conflict",
|
|
385
|
+
count: persistentConflict.count,
|
|
371
386
|
});
|
|
372
387
|
}
|
|
373
388
|
}
|
|
374
389
|
catch (error) {
|
|
375
|
-
deps.recordRuntimeEvent?.("polling", error, {
|
|
390
|
+
deps.recordRuntimeEvent?.("polling", error, {
|
|
391
|
+
phase: "conflict-stand-down",
|
|
392
|
+
});
|
|
376
393
|
}
|
|
377
394
|
if (deps.getPollingController() || deps.getPollingPromise())
|
|
378
395
|
return;
|
|
@@ -429,7 +446,9 @@ export function createTelegramThreadCapabilityOrchestration(deps) {
|
|
|
429
446
|
const expected = generation;
|
|
430
447
|
return () => expected === generation;
|
|
431
448
|
},
|
|
432
|
-
invalidate() {
|
|
449
|
+
invalidate() {
|
|
450
|
+
generation++;
|
|
451
|
+
},
|
|
433
452
|
};
|
|
434
453
|
const capabilityDeps = {
|
|
435
454
|
lifecycle,
|
|
@@ -537,6 +556,29 @@ function hasTelegramThreadCapabilityBindings(store) {
|
|
|
537
556
|
record.status !== "stale");
|
|
538
557
|
}) ?? false);
|
|
539
558
|
}
|
|
559
|
+
/** Falls back to classic polling, recording a failed restore durably; false once the attempt is stale. */
|
|
560
|
+
async function restoreTelegramClassicPolling(ctx, phase, deps, isCurrent) {
|
|
561
|
+
try {
|
|
562
|
+
await deps.startClassicPolling(ctx);
|
|
563
|
+
return isCurrent();
|
|
564
|
+
}
|
|
565
|
+
catch (classicError) {
|
|
566
|
+
if (!isCurrent())
|
|
567
|
+
return false;
|
|
568
|
+
deps.topicTargetStore.setBotState({
|
|
569
|
+
threadMode: "disabled",
|
|
570
|
+
updatedAtMs: (deps.getNowMs ?? Date.now)(),
|
|
571
|
+
lastReconcileAction: `${phase}-classic-restore-failed`,
|
|
572
|
+
});
|
|
573
|
+
await deps.topicTargetStore.persist();
|
|
574
|
+
if (!isCurrent())
|
|
575
|
+
return false;
|
|
576
|
+
deps.recordEvent("bus", classicError, {
|
|
577
|
+
phase: `${phase}-classic-restore`,
|
|
578
|
+
});
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
540
582
|
export async function applyTelegramThreadCapability(ctx, threadModeEnabled, phase, deps, isCurrent = deps.lifecycle?.capture() ?? (() => true)) {
|
|
541
583
|
if (!isCurrent())
|
|
542
584
|
return;
|
|
@@ -574,26 +616,8 @@ export async function applyTelegramThreadCapability(ctx, threadModeEnabled, phas
|
|
|
574
616
|
deps.setPollingStartedWithTelegramBus(false);
|
|
575
617
|
if (hadLiveThreadTransport)
|
|
576
618
|
deps.suspendLiveThreadTarget?.();
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
if (!isCurrent())
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
catch (classicError) {
|
|
583
|
-
if (!isCurrent())
|
|
584
|
-
return;
|
|
585
|
-
deps.topicTargetStore.setBotState({
|
|
586
|
-
threadMode: "disabled",
|
|
587
|
-
updatedAtMs: (deps.getNowMs ?? Date.now)(),
|
|
588
|
-
lastReconcileAction: `${phase}-classic-restore-failed`,
|
|
589
|
-
});
|
|
590
|
-
await deps.topicTargetStore.persist();
|
|
591
|
-
if (!isCurrent())
|
|
592
|
-
return;
|
|
593
|
-
deps.recordEvent("bus", classicError, {
|
|
594
|
-
phase: `${phase}-classic-restore`,
|
|
595
|
-
});
|
|
596
|
-
}
|
|
619
|
+
if (!(await restoreTelegramClassicPolling(ctx, phase, deps, isCurrent)))
|
|
620
|
+
return;
|
|
597
621
|
}
|
|
598
622
|
deps.updateStatus(ctx);
|
|
599
623
|
return;
|
|
@@ -635,26 +659,8 @@ export async function applyTelegramThreadCapability(ctx, threadModeEnabled, phas
|
|
|
635
659
|
return;
|
|
636
660
|
deps.setTopicModeUnavailable(true);
|
|
637
661
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
if (!isCurrent())
|
|
641
|
-
return;
|
|
642
|
-
}
|
|
643
|
-
catch (classicError) {
|
|
644
|
-
if (!isCurrent())
|
|
645
|
-
return;
|
|
646
|
-
deps.topicTargetStore.setBotState({
|
|
647
|
-
threadMode: "disabled",
|
|
648
|
-
updatedAtMs: (deps.getNowMs ?? Date.now)(),
|
|
649
|
-
lastReconcileAction: `${phase}-classic-restore-failed`,
|
|
650
|
-
});
|
|
651
|
-
await deps.topicTargetStore.persist();
|
|
652
|
-
if (!isCurrent())
|
|
653
|
-
return;
|
|
654
|
-
deps.recordEvent("bus", classicError, {
|
|
655
|
-
phase: `${phase}-classic-restore`,
|
|
656
|
-
});
|
|
657
|
-
}
|
|
662
|
+
if (!(await restoreTelegramClassicPolling(ctx, phase, deps, isCurrent)))
|
|
663
|
+
return;
|
|
658
664
|
deps.updateStatus(ctx);
|
|
659
665
|
if (threadModeUnavailable)
|
|
660
666
|
return;
|
|
@@ -753,11 +759,17 @@ export function createTelegramThreadAwarePollingPorts(deps) {
|
|
|
753
759
|
};
|
|
754
760
|
const restoreFollowerWithOwner = async (ctx, owner) => {
|
|
755
761
|
if (!(await refreshFollowerState())) {
|
|
756
|
-
deps.recordEvent("bus", "Telegram follower auto-connect skipped: Threaded Mode is not enabled.", {
|
|
762
|
+
deps.recordEvent("bus", "Telegram follower auto-connect skipped: Threaded Mode is not enabled.", {
|
|
763
|
+
phase: "follower-auto-connect-skip",
|
|
764
|
+
reason: "thread-mode-unavailable",
|
|
765
|
+
});
|
|
757
766
|
return undefined;
|
|
758
767
|
}
|
|
759
768
|
if (!deps.hasRememberedWorkspaceBinding?.(ctx)) {
|
|
760
|
-
deps.recordEvent("bus", "Telegram follower auto-connect skipped: no binding for this session.", {
|
|
769
|
+
deps.recordEvent("bus", "Telegram follower auto-connect skipped: no binding for this session.", {
|
|
770
|
+
phase: "follower-auto-connect-skip",
|
|
771
|
+
reason: "session-binding-unavailable",
|
|
772
|
+
});
|
|
761
773
|
return undefined;
|
|
762
774
|
}
|
|
763
775
|
return deps.restoreFollowerWithLeader?.(ctx, owner);
|
|
@@ -892,7 +904,9 @@ export function createTelegramThreadCapabilityMonitor(deps) {
|
|
|
892
904
|
try {
|
|
893
905
|
stop();
|
|
894
906
|
}
|
|
895
|
-
catch {
|
|
907
|
+
catch {
|
|
908
|
+
/* Timer shutdown must not escape the callback. */
|
|
909
|
+
}
|
|
896
910
|
try {
|
|
897
911
|
deps.recordEvent("bus", error, { phase: "capability-monitor" });
|
|
898
912
|
}
|
|
@@ -1103,12 +1117,14 @@ export async function runTelegramPollLoop(deps) {
|
|
|
1103
1117
|
if (!deps.config.botToken)
|
|
1104
1118
|
return;
|
|
1105
1119
|
let consecutiveGetUpdatesConflicts = 0;
|
|
1120
|
+
let consecutiveFailures = 0;
|
|
1106
1121
|
const retryConflict = async () => {
|
|
1107
1122
|
consecutiveGetUpdatesConflicts += 1;
|
|
1108
1123
|
if (consecutiveGetUpdatesConflicts >= TELEGRAM_GET_UPDATES_CONFLICT_STOP_LIMIT) {
|
|
1109
1124
|
throw new TelegramPersistentGetUpdatesConflictError(consecutiveGetUpdatesConflicts);
|
|
1110
1125
|
}
|
|
1111
|
-
await deps.sleep(consecutiveGetUpdatesConflicts <
|
|
1126
|
+
await deps.sleep(consecutiveGetUpdatesConflicts <
|
|
1127
|
+
TELEGRAM_GET_UPDATES_CONFLICT_FAST_RETRY_LIMIT
|
|
1112
1128
|
? TELEGRAM_GET_UPDATES_CONFLICT_FAST_RETRY_MS
|
|
1113
1129
|
: TELEGRAM_GET_UPDATES_CONFLICT_SLOW_RETRY_MS, deps.signal);
|
|
1114
1130
|
};
|
|
@@ -1171,6 +1187,7 @@ export async function runTelegramPollLoop(deps) {
|
|
|
1171
1187
|
onPhaseChange: deps.onPhaseChange,
|
|
1172
1188
|
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
1173
1189
|
});
|
|
1190
|
+
consecutiveFailures = 0;
|
|
1174
1191
|
currentUpdateId = undefined;
|
|
1175
1192
|
}
|
|
1176
1193
|
catch (error) {
|
|
@@ -1190,8 +1207,10 @@ export async function runTelegramPollLoop(deps) {
|
|
|
1190
1207
|
: {}),
|
|
1191
1208
|
});
|
|
1192
1209
|
consecutiveGetUpdatesConflicts = 0;
|
|
1210
|
+
consecutiveFailures += 1;
|
|
1193
1211
|
deps.onErrorStatus(getTelegramPollingErrorMessage(error));
|
|
1194
|
-
|
|
1212
|
+
// Cap the pause, not retry count: outages must recover without manual reconnect.
|
|
1213
|
+
await deps.sleep(getTelegramPollingRetryDelayMs(consecutiveFailures), deps.signal);
|
|
1195
1214
|
if (deps.signal.aborted)
|
|
1196
1215
|
return;
|
|
1197
1216
|
deps.onStatusReset();
|
package/dist/lib/preview.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Zones: telegram outbound, native rich markdown drafts
|
|
4
4
|
* Owns safe draft preview selection, runtime updates, and preview finalization
|
|
5
5
|
*/
|
|
6
|
-
import { normalizeTelegramNativeMarkdown } from "./replies.js";
|
|
7
6
|
import { stripTelegramCommentMarkupForPreview } from "./outbound-markup.js";
|
|
7
|
+
import { isTelegramMarkdownFenceClosing, normalizeTelegramNativeMarkdown, parseTelegramMarkdownFenceOpening, } from "./replies.js";
|
|
8
8
|
import { getTelegramTargetThreadParams, } from "./target.js";
|
|
9
9
|
import { shouldSuppressPreviewForVoice } from "./voice.js";
|
|
10
10
|
const TELEGRAM_DRAFT_ID_MAX = 2_147_483_647;
|
|
@@ -73,9 +73,15 @@ export function createTelegramAssistantPreviewRuntime(deps) {
|
|
|
73
73
|
clearPreview: async (chatId, options) => {
|
|
74
74
|
if (controller.getState() !== state || !isDeliveryActive())
|
|
75
75
|
return;
|
|
76
|
-
await controller.prepareClear(chatId, {
|
|
76
|
+
await controller.prepareClear(chatId, {
|
|
77
|
+
...options,
|
|
78
|
+
isDeliveryActive,
|
|
79
|
+
})();
|
|
77
80
|
},
|
|
78
|
-
finalizeMarkdownPreview: prepareTelegramNativeMarkdownPreviewFinalizer({
|
|
81
|
+
finalizeMarkdownPreview: prepareTelegramNativeMarkdownPreviewFinalizer({
|
|
82
|
+
...finalizerDeps,
|
|
83
|
+
isDeliveryActive,
|
|
84
|
+
}),
|
|
79
85
|
};
|
|
80
86
|
},
|
|
81
87
|
...createTelegramAssistantMessagePreviewHooks({
|
|
@@ -130,7 +136,10 @@ export function createTelegramPreviewController(deps) {
|
|
|
130
136
|
createState: () => createTelegramPreviewRuntimeState(),
|
|
131
137
|
resetState: () => {
|
|
132
138
|
generation += 1;
|
|
133
|
-
setState({
|
|
139
|
+
setState({
|
|
140
|
+
...createTelegramPreviewRuntimeState(),
|
|
141
|
+
nextDraftAt: state?.nextDraftAt,
|
|
142
|
+
});
|
|
134
143
|
},
|
|
135
144
|
invalidate: () => {
|
|
136
145
|
generation += 1;
|
|
@@ -143,8 +152,15 @@ export function createTelegramPreviewController(deps) {
|
|
|
143
152
|
sealTelegramPreviewState(state);
|
|
144
153
|
const prior = state.publicationPromise ?? state.flushPromise ?? state.precedingFlush;
|
|
145
154
|
let settle;
|
|
146
|
-
state.publicationPromise = new Promise((resolve) => {
|
|
147
|
-
|
|
155
|
+
state.publicationPromise = new Promise((resolve) => {
|
|
156
|
+
settle = resolve;
|
|
157
|
+
});
|
|
158
|
+
return {
|
|
159
|
+
wait: async () => {
|
|
160
|
+
await prior?.catch(() => { });
|
|
161
|
+
},
|
|
162
|
+
settle,
|
|
163
|
+
};
|
|
148
164
|
},
|
|
149
165
|
prepareClear: (chatId, options) => {
|
|
150
166
|
const admittedState = state;
|
|
@@ -154,7 +170,8 @@ export function createTelegramPreviewController(deps) {
|
|
|
154
170
|
return;
|
|
155
171
|
await clearTelegramPreview(chatId, runtime, {
|
|
156
172
|
...options,
|
|
157
|
-
isDeliveryActive: () => runtime.canSend?.() !== false &&
|
|
173
|
+
isDeliveryActive: () => runtime.canSend?.() !== false &&
|
|
174
|
+
options?.isDeliveryActive?.() !== false,
|
|
158
175
|
});
|
|
159
176
|
};
|
|
160
177
|
},
|
|
@@ -208,7 +225,8 @@ async function handleTelegramAssistantMessagePreviewStart(message, deps) {
|
|
|
208
225
|
// Carry the previous delivery boundary; permanent text remains with its publication owner.
|
|
209
226
|
next.draftId = state?.draftId;
|
|
210
227
|
next.nextDraftAt = state?.nextDraftAt;
|
|
211
|
-
next.precedingFlush =
|
|
228
|
+
next.precedingFlush =
|
|
229
|
+
state?.publicationPromise ?? state?.flushPromise ?? state?.precedingFlush;
|
|
212
230
|
deps.setState(next);
|
|
213
231
|
}
|
|
214
232
|
async function handleTelegramAssistantMessagePreviewUpdate(message, deps) {
|
|
@@ -280,7 +298,9 @@ export async function clearTelegramPreview(chatId, deps, options = {}) {
|
|
|
280
298
|
if (options.isDeliveryActive?.() === false)
|
|
281
299
|
return;
|
|
282
300
|
deps.setState(undefined);
|
|
283
|
-
if (state.mode === "draft" &&
|
|
301
|
+
if (state.mode === "draft" &&
|
|
302
|
+
state.draftId !== undefined &&
|
|
303
|
+
deps.canSend?.() !== false) {
|
|
284
304
|
try {
|
|
285
305
|
await deps.sendDraft(chatId, state.draftId, undefined, {
|
|
286
306
|
...getTelegramTargetThreadParams(options.target ?? { chatId }),
|
|
@@ -423,9 +443,8 @@ function updateTelegramDraftInlineStateForLine(line, state) {
|
|
|
423
443
|
}
|
|
424
444
|
}
|
|
425
445
|
function updateTelegramDraftBlockStateForLine(line, state) {
|
|
426
|
-
const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
427
446
|
if (state.fence) {
|
|
428
|
-
if (
|
|
447
|
+
if (isTelegramMarkdownFenceClosing(line, state.fence)) {
|
|
429
448
|
state.fence = undefined;
|
|
430
449
|
}
|
|
431
450
|
return true;
|
|
@@ -435,12 +454,9 @@ function updateTelegramDraftBlockStateForLine(line, state) {
|
|
|
435
454
|
state.displayMath = false;
|
|
436
455
|
return true;
|
|
437
456
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
state.fence =
|
|
441
|
-
marker: markerText[0],
|
|
442
|
-
length: markerText.length,
|
|
443
|
-
};
|
|
457
|
+
const openingFence = parseTelegramMarkdownFenceOpening(line);
|
|
458
|
+
if (openingFence) {
|
|
459
|
+
state.fence = openingFence;
|
|
444
460
|
return true;
|
|
445
461
|
}
|
|
446
462
|
if (line.trim() === "$$") {
|
|
@@ -523,7 +539,9 @@ async function performTelegramPreviewFlush(chatId, state, deps, options = {}) {
|
|
|
523
539
|
state.nextDraftAt = Date.now() + (deps.minDraftIntervalMs ?? 0);
|
|
524
540
|
try {
|
|
525
541
|
const delivered = await deps.sendDraft(chatId, draftId, normalizeTelegramNativeMarkdown(snapshot.text), { ...getTelegramTargetThreadParams(options.target ?? { chatId }) });
|
|
526
|
-
if (delivered === false ||
|
|
542
|
+
if (delivered === false ||
|
|
543
|
+
deps.getState() !== state ||
|
|
544
|
+
deps.canSend?.() === false)
|
|
527
545
|
return;
|
|
528
546
|
deps.setDraftSupport("supported");
|
|
529
547
|
state.mode = "draft";
|
|
@@ -584,7 +602,9 @@ export async function flushTelegramPreview(chatId, deps, options = {}) {
|
|
|
584
602
|
});
|
|
585
603
|
break;
|
|
586
604
|
}
|
|
587
|
-
} while (deps.getState() === state &&
|
|
605
|
+
} while (deps.getState() === state &&
|
|
606
|
+
!state.sealed &&
|
|
607
|
+
state.flushRequested);
|
|
588
608
|
})();
|
|
589
609
|
try {
|
|
590
610
|
await state.flushPromise;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process identity and liveness proofs
|
|
3
|
+
* Zones: shared utils, multi-instance bus, durable admission
|
|
4
|
+
* Owns PID liveness probes and stable Linux/macOS/Windows process-birth identity. Only an absent PID or a
|
|
5
|
+
* mismatched birth proof establishes death; inaccessible metadata stays unverifiable.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isProcessAlive(pid: number): boolean;
|
|
8
|
+
interface TelegramProcessBirthIdentityOptions {
|
|
9
|
+
platform?: NodeJS.Platform;
|
|
10
|
+
readProcStat?: (pid: number) => string;
|
|
11
|
+
readDarwinProcessStart?: (pid: number) => string;
|
|
12
|
+
readWindowsProcessStart?: (pid: number) => string;
|
|
13
|
+
}
|
|
14
|
+
export type TelegramProcessLiveness = "alive" | "dead" | "unverifiable";
|
|
15
|
+
interface TelegramProcessLivenessOptions extends TelegramProcessBirthIdentityOptions {
|
|
16
|
+
isProcessAlive?: (pid: number) => boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function getTelegramProcessBirthIdentity(pid: number, fallbackGeneration: number | string, options?: TelegramProcessBirthIdentityOptions): string;
|
|
19
|
+
export declare function getTelegramProcessLiveness(owner: {
|
|
20
|
+
processId: number;
|
|
21
|
+
processBirthId: string;
|
|
22
|
+
}, options?: TelegramProcessLivenessOptions): TelegramProcessLiveness;
|
|
23
|
+
export declare function getTelegramProcessBirthIdentityLiveness(processBirthId: string, options?: TelegramProcessLivenessOptions): TelegramProcessLiveness;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process identity and liveness proofs
|
|
3
|
+
* Zones: shared utils, multi-instance bus, durable admission
|
|
4
|
+
* Owns PID liveness probes and stable Linux/macOS/Windows process-birth identity. Only an absent PID or a
|
|
5
|
+
* mismatched birth proof establishes death; inaccessible metadata stays unverifiable.
|
|
6
|
+
*/
|
|
7
|
+
import { execFileSync } from "node:child_process";
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
import { platform as getPlatform } from "node:os";
|
|
11
|
+
export function isProcessAlive(pid) {
|
|
12
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
13
|
+
return false;
|
|
14
|
+
try {
|
|
15
|
+
process.kill(pid, 0);
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
// Only an absent PID proves death; permission and unexpected failures do not.
|
|
20
|
+
return error.code !== "ESRCH";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function readDarwinProcessStart(pid) {
|
|
24
|
+
return execFileSync("/bin/ps", ["-o", "lstart=", "-p", String(pid)], {
|
|
25
|
+
encoding: "utf8",
|
|
26
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
27
|
+
}).trim();
|
|
28
|
+
}
|
|
29
|
+
/** Creation time in UTC 100 ns ticks; PowerShell ships with every supported Windows and needs no native addon. */
|
|
30
|
+
function readWindowsProcessStart(pid) {
|
|
31
|
+
const root = process.env.SystemRoot ?? "C:\\Windows";
|
|
32
|
+
return execFileSync(`${root}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`, [
|
|
33
|
+
"-NoProfile",
|
|
34
|
+
"-NonInteractive",
|
|
35
|
+
"-Command",
|
|
36
|
+
`(Get-Process -Id ${pid} -ErrorAction Stop).StartTime.ToUniversalTime().Ticks`,
|
|
37
|
+
], {
|
|
38
|
+
encoding: "utf8",
|
|
39
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
40
|
+
timeout: 10_000,
|
|
41
|
+
windowsHide: true,
|
|
42
|
+
}).trim();
|
|
43
|
+
}
|
|
44
|
+
/** The current process never changes birth, so its slow Windows proof is read once; other PIDs are never cached. */
|
|
45
|
+
let ownWindowsBirthProof;
|
|
46
|
+
function getTelegramProcessBirthProof(pid, options = {}) {
|
|
47
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
48
|
+
return { status: "unverifiable" };
|
|
49
|
+
const platform = options.platform ?? getPlatform();
|
|
50
|
+
if (platform === "linux") {
|
|
51
|
+
try {
|
|
52
|
+
const stat = (options.readProcStat ??
|
|
53
|
+
((targetPid) => readFileSync(`/proc/${targetPid}/stat`, "utf8")))(pid);
|
|
54
|
+
const closeParen = stat.lastIndexOf(")");
|
|
55
|
+
const fields = stat
|
|
56
|
+
.slice(closeParen + 2)
|
|
57
|
+
.trim()
|
|
58
|
+
.split(/\s+/u);
|
|
59
|
+
const startTicks = fields[19];
|
|
60
|
+
if (startTicks) {
|
|
61
|
+
return { status: "proven", identity: `${pid}:start:${startTicks}` };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
/* inaccessible process metadata */
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (platform === "darwin") {
|
|
69
|
+
try {
|
|
70
|
+
const startedAt = (options.readDarwinProcessStart ?? readDarwinProcessStart)(pid);
|
|
71
|
+
if (startedAt) {
|
|
72
|
+
const fingerprint = createHash("sha256")
|
|
73
|
+
.update(startedAt)
|
|
74
|
+
.digest("hex")
|
|
75
|
+
.slice(0, 16);
|
|
76
|
+
return { status: "proven", identity: `${pid}:start:${fingerprint}` };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
/* inaccessible process metadata */
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if (platform === "win32") {
|
|
84
|
+
const injected = options.readWindowsProcessStart;
|
|
85
|
+
if (!injected && pid === process.pid && ownWindowsBirthProof)
|
|
86
|
+
return ownWindowsBirthProof;
|
|
87
|
+
let proof = { status: "unverifiable" };
|
|
88
|
+
try {
|
|
89
|
+
const ticks = (injected ?? readWindowsProcessStart)(pid);
|
|
90
|
+
if (/^\d+$/u.test(ticks))
|
|
91
|
+
proof = { status: "proven", identity: `${pid}:start:${ticks}` };
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
/* inaccessible process metadata, including another user's process */
|
|
95
|
+
}
|
|
96
|
+
if (!injected && pid === process.pid && proof.status === "proven")
|
|
97
|
+
ownWindowsBirthProof = proof;
|
|
98
|
+
return proof;
|
|
99
|
+
}
|
|
100
|
+
return { status: "unverifiable" };
|
|
101
|
+
}
|
|
102
|
+
export function getTelegramProcessBirthIdentity(pid, fallbackGeneration, options = {}) {
|
|
103
|
+
const proof = getTelegramProcessBirthProof(pid, options);
|
|
104
|
+
return proof.status === "proven"
|
|
105
|
+
? proof.identity
|
|
106
|
+
: `${pid}:generation:${fallbackGeneration}`;
|
|
107
|
+
}
|
|
108
|
+
export function getTelegramProcessLiveness(owner, options = {}) {
|
|
109
|
+
const processAlive = options.isProcessAlive ?? isProcessAlive;
|
|
110
|
+
if (!processAlive(owner.processId))
|
|
111
|
+
return "dead";
|
|
112
|
+
const proof = getTelegramProcessBirthProof(owner.processId, options);
|
|
113
|
+
if (proof.status === "unverifiable")
|
|
114
|
+
return "unverifiable";
|
|
115
|
+
return proof.identity === owner.processBirthId ? "alive" : "dead";
|
|
116
|
+
}
|
|
117
|
+
export function getTelegramProcessBirthIdentityLiveness(processBirthId, options = {}) {
|
|
118
|
+
const match = /^(\d+):(start|generation):(.+)$/u.exec(processBirthId);
|
|
119
|
+
if (!match)
|
|
120
|
+
return "unverifiable";
|
|
121
|
+
const processId = Number(match[1]);
|
|
122
|
+
if (!Number.isSafeInteger(processId) || processId <= 0)
|
|
123
|
+
return "unverifiable";
|
|
124
|
+
const processAlive = options.isProcessAlive ?? isProcessAlive;
|
|
125
|
+
if (!processAlive(processId))
|
|
126
|
+
return "dead";
|
|
127
|
+
if (match[2] === "generation")
|
|
128
|
+
return "unverifiable";
|
|
129
|
+
const proof = getTelegramProcessBirthProof(processId, options);
|
|
130
|
+
if (proof.status === "unverifiable")
|
|
131
|
+
return "unverifiable";
|
|
132
|
+
return proof.identity === processBirthId ? "alive" : "dead";
|
|
133
|
+
}
|
package/dist/lib/prompts.js
CHANGED
|
@@ -121,13 +121,8 @@ export function buildTelegramBridgeSystemPrompt(options) {
|
|
|
121
121
|
: "";
|
|
122
122
|
return {
|
|
123
123
|
systemPrompt: Array.isArray(basePrompt)
|
|
124
|
-
? [
|
|
125
|
-
|
|
126
|
-
options.localSystemPromptSuffix + telegramSuffix,
|
|
127
|
-
]
|
|
128
|
-
: basePrompt +
|
|
129
|
-
options.localSystemPromptSuffix +
|
|
130
|
-
telegramSuffix,
|
|
124
|
+
? [...basePrompt, options.localSystemPromptSuffix + telegramSuffix]
|
|
125
|
+
: basePrompt + options.localSystemPromptSuffix + telegramSuffix,
|
|
131
126
|
};
|
|
132
127
|
}
|
|
133
128
|
export function createTelegramBeforeAgentStartHook(options = {}) {
|
package/dist/lib/queue.d.ts
CHANGED
|
@@ -188,9 +188,7 @@ export declare function createTelegramQueueAdmissionReceipt(options: {
|
|
|
188
188
|
scope: string;
|
|
189
189
|
sourceUpdateIds: readonly number[];
|
|
190
190
|
}): TelegramQueueAdmissionReceipt | undefined;
|
|
191
|
-
export declare function isTelegramQueueItemDurablyAdmitted<TContext = unknown>(item: TelegramQueueItem<TContext>, isReceiptCommitted: (receipt: TelegramQueueAdmissionReceipt) => boolean): boolean;
|
|
192
191
|
export declare function getTelegramQueueLaneContract(lane: TelegramQueueLane): TelegramQueueLaneContract;
|
|
193
|
-
export declare function getTelegramQueueItemAdmissionMode(item: Pick<TelegramQueueItem, "queueLane">): TelegramQueueAdmissionMode;
|
|
194
192
|
export declare function isTelegramQueueItemAdmissionValid(item: Pick<TelegramQueueItem, "kind" | "queueLane">): boolean;
|
|
195
193
|
export declare function assertTelegramQueueItemAdmissionValid(item: Pick<TelegramQueueItem, "kind" | "queueLane" | "admissionReceipts">): void;
|
|
196
194
|
export declare function createTelegramQueueStore<TContext = unknown>(initialItems?: TelegramQueueItem<TContext>[]): TelegramQueueStateStore<TContext>;
|
|
@@ -202,6 +200,13 @@ export declare function createTelegramTransportStampedQueueStore<TContext>(store
|
|
|
202
200
|
export declare function countExecutableTelegramQueueItems<TContext = unknown>(items: readonly TelegramQueueItem<TContext>[]): number;
|
|
203
201
|
export declare function createTelegramQueueItemCountGetter<TContext = unknown>(store: Pick<TelegramQueueStore<TContext>, "getQueuedItems">): () => number;
|
|
204
202
|
export declare function createTelegramActiveTurnStore<TTurn extends PendingTelegramTurn = PendingTelegramTurn>(): TelegramActiveTurnStore<TTurn>;
|
|
203
|
+
/** Current captured targets only; skipped/receipt-held items remain work, never historical census. */
|
|
204
|
+
export declare function observeTelegramTargetQueueWork(target: TelegramQueueTarget & {
|
|
205
|
+
threadId: number;
|
|
206
|
+
}, activeTurn: Pick<TelegramQueueItemBase, "chatId" | "target"> | undefined, items: readonly Pick<TelegramQueueItemBase, "chatId" | "target">[]): {
|
|
207
|
+
protected: boolean;
|
|
208
|
+
unknown: boolean;
|
|
209
|
+
};
|
|
205
210
|
export declare function partitionTelegramQueueItemsForHistory<TContext = unknown>(items: TelegramQueueItem<TContext>[]): {
|
|
206
211
|
historyTurns: PendingTelegramTurn[];
|
|
207
212
|
remainingItems: TelegramQueueItem<TContext>[];
|
|
@@ -586,7 +591,7 @@ export interface TelegramSessionShutdownRuntimeDeps<TQueueItem> {
|
|
|
586
591
|
clearAbort: () => void;
|
|
587
592
|
stopPolling: () => Promise<void>;
|
|
588
593
|
}
|
|
589
|
-
export interface TelegramSessionLifecycleHookRuntimeDeps<TContext, TQueueItem, TModel = unknown> extends TelegramRuntimeEventRecorderPort {
|
|
594
|
+
export interface TelegramSessionLifecycleHookRuntimeDeps<TContext, TQueueItem, TModel = unknown> extends TelegramRuntimeEventRecorderPort, Omit<TelegramSessionShutdownRuntimeDeps<TQueueItem>, "isSessionActive" | "discardQueuedItems" | "applyState"> {
|
|
590
595
|
getCurrentModel: (ctx: TContext) => TModel | undefined;
|
|
591
596
|
loadConfig: () => Promise<void>;
|
|
592
597
|
applySessionStartState: (state: TelegramSessionStartState<TModel>) => void;
|
|
@@ -594,20 +599,8 @@ export interface TelegramSessionLifecycleHookRuntimeDeps<TContext, TQueueItem, T
|
|
|
594
599
|
prepareTempDir: () => Promise<unknown>;
|
|
595
600
|
updateStatus: (ctx: TContext) => void;
|
|
596
601
|
isSessionActive?: (ctx: TContext) => boolean;
|
|
597
|
-
unbindDeferredDispatchContext?: () => void;
|
|
598
602
|
discardQueuedItems?: (ctx: TContext) => void;
|
|
599
603
|
applySessionShutdownState: (state: TelegramSessionShutdownState<TQueueItem>) => void;
|
|
600
|
-
clearPendingMediaGroups: () => void;
|
|
601
|
-
clearModelMenuState: () => void;
|
|
602
|
-
getActiveTurnChatId: () => number | undefined;
|
|
603
|
-
getActiveTurnTarget?: () => TelegramQueueTarget | undefined;
|
|
604
|
-
clearPreview: (chatId: number, options?: {
|
|
605
|
-
target?: TelegramQueueTarget;
|
|
606
|
-
}) => Promise<void>;
|
|
607
|
-
previewShutdownTimeoutMs?: number;
|
|
608
|
-
clearActiveTurn: () => void;
|
|
609
|
-
clearAbort: () => void;
|
|
610
|
-
stopPolling: () => Promise<void>;
|
|
611
604
|
}
|
|
612
605
|
export type TelegramSessionLifecycleHookEvent = unknown;
|
|
613
606
|
export declare function createTelegramSessionStateApplier<TQueueItem, TModel>(deps: TelegramSessionStateApplierDeps<TQueueItem, TModel>): TelegramSessionStateApplier<TQueueItem, TModel>;
|
|
@@ -648,6 +641,8 @@ export interface TelegramPromptEnqueueRuntimeDeps<TMessage, TContext = unknown>
|
|
|
648
641
|
updateStatus: () => void;
|
|
649
642
|
dispatchNextQueuedTelegramTurn: () => void;
|
|
650
643
|
assertExecutionCurrent?: () => void;
|
|
644
|
+
/** Input-specific relocation must not fold or replace unrelated queued work. */
|
|
645
|
+
preserveQueued?: boolean;
|
|
651
646
|
onQueued?: (turn: PendingTelegramTurn) => void;
|
|
652
647
|
}
|
|
653
648
|
export interface TelegramPromptEnqueueControllerDeps<TMessage, TContext = unknown> extends TelegramQueueStore<TContext> {
|
|
@@ -660,7 +655,10 @@ export interface TelegramPromptEnqueueControllerDeps<TMessage, TContext = unknow
|
|
|
660
655
|
assertExecutionCurrent?: (messages: TMessage[]) => void;
|
|
661
656
|
}
|
|
662
657
|
export interface TelegramPromptEnqueueController<TMessage, TContext = unknown> {
|
|
663
|
-
enqueue: (messages: TMessage[], ctx: TContext, onQueued?: (turn: PendingTelegramTurn) => void
|
|
658
|
+
enqueue: (messages: TMessage[], ctx: TContext, onQueued?: (turn: PendingTelegramTurn) => void, options?: {
|
|
659
|
+
assertCurrent?: () => void;
|
|
660
|
+
preserveQueued?: boolean;
|
|
661
|
+
}) => Promise<PendingTelegramTurn>;
|
|
664
662
|
}
|
|
665
663
|
export declare function buildTelegramSessionStartState<TModel = unknown>(currentModel: TModel | undefined): TelegramSessionStartState<TModel>;
|
|
666
664
|
export declare function buildTelegramSessionShutdownState<TQueueItem>(): TelegramSessionShutdownState<TQueueItem>;
|