@llblab/pi-kit 0.31.2 → 0.33.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/BACKLOG.md +1 -1
- package/CHANGELOG.md +8 -0
- package/README.md +5 -3
- package/node_modules/@llblab/pi-codex-usage/AGENTS.md +2 -1
- package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +4 -0
- package/node_modules/@llblab/pi-codex-usage/README.md +11 -9
- package/node_modules/@llblab/pi-codex-usage/lib/extension.ts +13 -10
- package/node_modules/@llblab/pi-codex-usage/lib/fast.ts +6 -5
- package/node_modules/@llblab/pi-codex-usage/lib/query.ts +4 -4
- package/node_modules/@llblab/pi-codex-usage/lib/status.ts +10 -10
- package/node_modules/@llblab/pi-codex-usage/lib/telegram.ts +1 -1
- package/node_modules/@llblab/pi-codex-usage/lib/usage.ts +2 -1
- package/node_modules/@llblab/pi-codex-usage/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/AGENTS.md +4 -2
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -1
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +11 -0
- package/node_modules/@llblab/pi-telegram/README.md +5 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +5 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +31 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +3 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +8 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.d.ts +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +7 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +49 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +313 -146
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +3 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +99 -18
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +5 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +13 -10
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +4 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +48 -15
- package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +48 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +68 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +178 -58
- package/node_modules/@llblab/pi-telegram/dist/lib/machine.d.ts +23 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/machine.js +37 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +114 -28
- package/node_modules/@llblab/pi-telegram/dist/lib/media.js +292 -119
- package/node_modules/@llblab/pi-telegram/dist/lib/model.d.ts +54 -15
- package/node_modules/@llblab/pi-telegram/dist/lib/model.js +98 -53
- package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/preview.d.ts +128 -113
- package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +448 -366
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +3 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +6 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +334 -210
- package/node_modules/@llblab/pi-telegram/dist/lib/runtime.d.ts +77 -11
- package/node_modules/@llblab/pi-telegram/dist/lib/runtime.js +174 -92
- package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +0 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +11 -9
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +53 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.d.ts +0 -26
- package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.js +51 -98
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +14 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +18 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +107 -30
- package/node_modules/@llblab/pi-telegram/dist/lib/turns.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +6 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +11 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +54 -19
- package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/docs/activity.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +12 -11
- package/node_modules/@llblab/pi-telegram/docs/delivery.md +7 -5
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +18 -8
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +2 -2
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +29 -5
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +9 -1
- package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +11 -3
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +417 -203
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +88 -14
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +17 -15
- package/node_modules/@llblab/pi-telegram/lib/delivery.ts +47 -19
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +51 -9
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +229 -55
- package/node_modules/@llblab/pi-telegram/lib/machine.ts +60 -0
- package/node_modules/@llblab/pi-telegram/lib/media.ts +438 -172
- package/node_modules/@llblab/pi-telegram/lib/model.ts +169 -74
- package/node_modules/@llblab/pi-telegram/lib/polling.ts +2 -0
- package/node_modules/@llblab/pi-telegram/lib/preview.ts +715 -566
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +5 -5
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +325 -238
- package/node_modules/@llblab/pi-telegram/lib/runtime.ts +260 -104
- package/node_modules/@llblab/pi-telegram/lib/sections.ts +0 -2
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +61 -8
- package/node_modules/@llblab/pi-telegram/lib/text-groups.ts +75 -136
- package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +15 -4
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +120 -36
- package/node_modules/@llblab/pi-telegram/lib/turns.ts +8 -1
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +58 -21
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/package.json +3 -3
|
@@ -116,10 +116,28 @@ function coalesceActivityEvents(previous, next) {
|
|
|
116
116
|
}
|
|
117
117
|
return next;
|
|
118
118
|
}
|
|
119
|
+
/** Optional observation must not change queue/transport settlement. */
|
|
120
|
+
function captureActivityDrainObserver(capture) {
|
|
121
|
+
try {
|
|
122
|
+
const notify = capture?.();
|
|
123
|
+
return () => {
|
|
124
|
+
try {
|
|
125
|
+
const emitted = notify?.();
|
|
126
|
+
if (emitted)
|
|
127
|
+
void Promise.resolve(emitted).catch(() => undefined);
|
|
128
|
+
}
|
|
129
|
+
catch { /* Observer failure is inert. */ }
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return () => { };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
119
136
|
/** @internal */
|
|
120
137
|
export function createTelegramActivityDispatcher(deps = {}) {
|
|
121
138
|
const queues = new Map();
|
|
122
139
|
let stopped = false;
|
|
140
|
+
const hasPending = () => Array.from(queues.values()).some(queue => queue.active && (queue.running || queue.events.length > 0));
|
|
123
141
|
const drain = async (queue) => {
|
|
124
142
|
if (queue.running || !queue.active)
|
|
125
143
|
return;
|
|
@@ -146,10 +164,12 @@ export function createTelegramActivityDispatcher(deps = {}) {
|
|
|
146
164
|
}
|
|
147
165
|
finally {
|
|
148
166
|
queue.running = false;
|
|
167
|
+
if (!stopped && !hasPending())
|
|
168
|
+
queue.notifyDrained?.();
|
|
149
169
|
}
|
|
150
170
|
};
|
|
151
171
|
return {
|
|
152
|
-
hasPending
|
|
172
|
+
hasPending,
|
|
153
173
|
dispatch(event) {
|
|
154
174
|
if (stopped)
|
|
155
175
|
return;
|
|
@@ -164,6 +184,8 @@ export function createTelegramActivityDispatcher(deps = {}) {
|
|
|
164
184
|
};
|
|
165
185
|
queues.set(registration.id, queue);
|
|
166
186
|
}
|
|
187
|
+
if (!queue.running && queue.events.length === 0)
|
|
188
|
+
queue.notifyDrained = captureActivityDrainObserver(deps.captureDrain);
|
|
167
189
|
const previous = queue.events.at(-1);
|
|
168
190
|
if (previous && canCoalesceActivityEvents(previous, event)) {
|
|
169
191
|
queue.events[queue.events.length - 1] = coalesceActivityEvents(previous, event);
|
|
@@ -198,6 +220,7 @@ export function createTelegramActivityBridgeRuntime(deps) {
|
|
|
198
220
|
runtime = createTelegramActivityRuntime({
|
|
199
221
|
generation: `${deps.generation}:${++generationSequence}`,
|
|
200
222
|
dispatcher: createTelegramActivityDispatcher({
|
|
223
|
+
captureDrain: deps.captureDrain,
|
|
201
224
|
recordFailure: deps.recordFailure,
|
|
202
225
|
}),
|
|
203
226
|
observeEvent: deps.observeEvent,
|
|
@@ -470,13 +493,14 @@ export function createTelegramActivityRuntime(deps) {
|
|
|
470
493
|
},
|
|
471
494
|
};
|
|
472
495
|
}
|
|
473
|
-
export function createTelegramActivityPublicationRuntime() {
|
|
496
|
+
export function createTelegramActivityPublicationRuntime(deps = {}) {
|
|
474
497
|
let generation = 0;
|
|
475
498
|
let tail = Promise.resolve();
|
|
476
499
|
let outstanding = 0, unconfirmed = false;
|
|
477
500
|
const pending = new Set();
|
|
478
501
|
const reserve = () => {
|
|
479
502
|
const admittedGeneration = generation;
|
|
503
|
+
const notifyDrained = captureActivityDrainObserver(deps.captureDrain);
|
|
480
504
|
let state = "pending";
|
|
481
505
|
let resolve;
|
|
482
506
|
const ready = new Promise((accept) => {
|
|
@@ -499,6 +523,8 @@ export function createTelegramActivityPublicationRuntime() {
|
|
|
499
523
|
})
|
|
500
524
|
.finally(() => {
|
|
501
525
|
outstanding -= 1;
|
|
526
|
+
if (admittedGeneration === generation && outstanding === 0 && !unconfirmed)
|
|
527
|
+
notifyDrained();
|
|
502
528
|
});
|
|
503
529
|
tail = result.catch(() => { });
|
|
504
530
|
return {
|
|
@@ -522,6 +548,7 @@ export function createTelegramActivityPublicationRuntime() {
|
|
|
522
548
|
hasUnconfirmed: () => unconfirmed,
|
|
523
549
|
beginWork() {
|
|
524
550
|
const admittedGeneration = generation;
|
|
551
|
+
const notifyDrained = captureActivityDrainObserver(deps.captureDrain);
|
|
525
552
|
let settled = false;
|
|
526
553
|
outstanding += 1;
|
|
527
554
|
return {
|
|
@@ -532,6 +559,8 @@ export function createTelegramActivityPublicationRuntime() {
|
|
|
532
559
|
outstanding -= 1;
|
|
533
560
|
if (outcome === "unconfirmed" && admittedGeneration === generation)
|
|
534
561
|
unconfirmed = true;
|
|
562
|
+
if (admittedGeneration === generation && outstanding === 0 && !unconfirmed)
|
|
563
|
+
notifyDrained();
|
|
535
564
|
},
|
|
536
565
|
};
|
|
537
566
|
},
|
|
@@ -177,6 +177,7 @@ export interface TelegramActivityBindingRuntime {
|
|
|
177
177
|
/** Compose public activity fanout, verbosity, and assistant output ordering. */
|
|
178
178
|
export declare function createTelegramActivityBindingRuntime<TTransportStamp>(deps: {
|
|
179
179
|
generation: string;
|
|
180
|
+
captureDrain?: () => (() => void) | undefined;
|
|
180
181
|
assistantOutput: Omit<Parameters<typeof createTelegramAssistantOutputBindingRuntime<TTransportStamp>>[0], "waitForActivityIdle" | "enqueue">;
|
|
181
182
|
activityVerbosity: Omit<Parameters<typeof ActivityVerbosity.createTelegramActivityVerbosityRuntime<TelegramAssistantOutputAuthority<TTransportStamp>>>[0], "captureAuthority" | "isAuthorityActive" | "recordFailure" | "enqueue">;
|
|
182
183
|
}): TelegramActivityBindingRuntime;
|
|
@@ -288,11 +289,12 @@ interface TelegramLifecycleBindingDeps {
|
|
|
288
289
|
}) => void;
|
|
289
290
|
canSendAgentActivity: (ctx: Pi.ExtensionContext) => boolean;
|
|
290
291
|
isSessionContextActive: (ctx: Pi.ExtensionContext) => boolean;
|
|
292
|
+
getSessionGeneration?: () => number;
|
|
291
293
|
isTurnTransportActive?: (turn: Queue.PendingTelegramTurn) => boolean;
|
|
292
294
|
updateStatus: TelegramBridgeStatusUpdater;
|
|
293
295
|
recordRuntimeEvent: TelegramRuntimeEventRecorder;
|
|
294
296
|
/** Settled-session hint for owners that wait on agent idleness, such as old-tab cleanup after a live rebind. */
|
|
295
297
|
onSessionSettled?: (ctx: Pi.ExtensionContext) => void;
|
|
296
298
|
}
|
|
297
|
-
export declare function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime, activityRuntime, activityVerbosityRuntime, diagnostics, assistantOutputRuntime, sessionLifecycleRuntime, configStore, abort, typing, lifecycle, activeTurnRuntime, telegramQueueStore, modelSwitchController, previewRuntime, promptDispatchRuntime, deferredQueueDispatchRuntime, modelContextAvailabilityRuntime, disconnectOnQuit, onSessionStarted, shutdownGenerativeAppLiveSurfaces, resolveAutomaticThreadCleanupEnabled, buttonActionStore, callMultipart, sendChatAction, sendRecordVoiceAction, sendMarkdownReply, sendTextReply, dispatchNextQueuedTelegramTurn, onPromptHandedOff, answerGuestQuery, deleteMessage, sendGuestReply, editGuestReply, stopGuestPlaceholder, preparePreviewDelivery, finalizeMarkdownPreview, proactivePushTargetGetter, getAssistantRenderingMode, recordMessageOwnership, canSendAgentActivity, isSessionContextActive, isTurnTransportActive, updateStatus, recordRuntimeEvent, onSessionSettled, }: TelegramLifecycleBindingDeps): void;
|
|
299
|
+
export declare function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime, activityRuntime, activityVerbosityRuntime, diagnostics, assistantOutputRuntime, sessionLifecycleRuntime, configStore, abort, typing, lifecycle, activeTurnRuntime, telegramQueueStore, modelSwitchController, previewRuntime, promptDispatchRuntime, deferredQueueDispatchRuntime, modelContextAvailabilityRuntime, disconnectOnQuit, onSessionStarted, shutdownGenerativeAppLiveSurfaces, resolveAutomaticThreadCleanupEnabled, buttonActionStore, callMultipart, sendChatAction, sendRecordVoiceAction, sendMarkdownReply, sendTextReply, dispatchNextQueuedTelegramTurn, onPromptHandedOff, answerGuestQuery, deleteMessage, sendGuestReply, editGuestReply, stopGuestPlaceholder, preparePreviewDelivery, finalizeMarkdownPreview, proactivePushTargetGetter, getAssistantRenderingMode, recordMessageOwnership, canSendAgentActivity, isSessionContextActive, getSessionGeneration, isTurnTransportActive, updateStatus, recordRuntimeEvent, onSessionSettled, }: TelegramLifecycleBindingDeps): void;
|
|
298
300
|
export {};
|
|
@@ -354,7 +354,7 @@ export function createTelegramAssistantOutputBindingRuntime(deps) {
|
|
|
354
354
|
}
|
|
355
355
|
/** Compose public activity fanout, verbosity, and assistant output ordering. */
|
|
356
356
|
export function createTelegramActivityBindingRuntime(deps) {
|
|
357
|
-
const publication = Activity.createTelegramActivityPublicationRuntime();
|
|
357
|
+
const publication = Activity.createTelegramActivityPublicationRuntime({ captureDrain: deps.captureDrain });
|
|
358
358
|
const assistantOutputBinding = createTelegramAssistantOutputBindingRuntime({
|
|
359
359
|
...deps.assistantOutput,
|
|
360
360
|
enqueue: publication.enqueue,
|
|
@@ -374,6 +374,7 @@ export function createTelegramActivityBindingRuntime(deps) {
|
|
|
374
374
|
});
|
|
375
375
|
const activityRuntime = Activity.createTelegramActivityBridgeRuntime({
|
|
376
376
|
generation: deps.generation,
|
|
377
|
+
captureDrain: deps.captureDrain,
|
|
377
378
|
observeEvent(event) {
|
|
378
379
|
assistantOutputBinding.observeEvent(event);
|
|
379
380
|
activityVerbosityRuntime.accept(event);
|
|
@@ -626,7 +627,7 @@ export function registerTelegramCommandsAndTools({ pi, agentDir, configStore, pe
|
|
|
626
627
|
},
|
|
627
628
|
});
|
|
628
629
|
}
|
|
629
|
-
export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime, activityRuntime, activityVerbosityRuntime, diagnostics, assistantOutputRuntime, sessionLifecycleRuntime, configStore, abort, typing, lifecycle, activeTurnRuntime, telegramQueueStore, modelSwitchController, previewRuntime, promptDispatchRuntime, deferredQueueDispatchRuntime, modelContextAvailabilityRuntime, disconnectOnQuit, onSessionStarted, shutdownGenerativeAppLiveSurfaces, resolveAutomaticThreadCleanupEnabled, buttonActionStore, callMultipart, sendChatAction, sendRecordVoiceAction, sendMarkdownReply, sendTextReply, dispatchNextQueuedTelegramTurn, onPromptHandedOff, answerGuestQuery, deleteMessage, sendGuestReply, editGuestReply, stopGuestPlaceholder, preparePreviewDelivery, finalizeMarkdownPreview, proactivePushTargetGetter, getAssistantRenderingMode, recordMessageOwnership, canSendAgentActivity, isSessionContextActive = () => true, isTurnTransportActive, updateStatus, recordRuntimeEvent, onSessionSettled, }) {
|
|
630
|
+
export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime, activityRuntime, activityVerbosityRuntime, diagnostics, assistantOutputRuntime, sessionLifecycleRuntime, configStore, abort, typing, lifecycle, activeTurnRuntime, telegramQueueStore, modelSwitchController, previewRuntime, promptDispatchRuntime, deferredQueueDispatchRuntime, modelContextAvailabilityRuntime, disconnectOnQuit, onSessionStarted, shutdownGenerativeAppLiveSurfaces, resolveAutomaticThreadCleanupEnabled, buttonActionStore, callMultipart, sendChatAction, sendRecordVoiceAction, sendMarkdownReply, sendTextReply, dispatchNextQueuedTelegramTurn, onPromptHandedOff, answerGuestQuery, deleteMessage, sendGuestReply, editGuestReply, stopGuestPlaceholder, preparePreviewDelivery, finalizeMarkdownPreview, proactivePushTargetGetter, getAssistantRenderingMode, recordMessageOwnership, canSendAgentActivity, isSessionContextActive = () => true, getSessionGeneration, isTurnTransportActive, updateStatus, recordRuntimeEvent, onSessionSettled, }) {
|
|
630
631
|
const agentEndResetter = Runtime.createTelegramAgentEndResetter({
|
|
631
632
|
abort,
|
|
632
633
|
typing,
|
|
@@ -864,6 +865,8 @@ export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime,
|
|
|
864
865
|
});
|
|
865
866
|
const messageActivityTypingHooks = Lifecycle.createTelegramMessageActivityTypingHooks({
|
|
866
867
|
hasActiveTurn: activeTurnRuntime.has,
|
|
868
|
+
isContextActive: isSessionContextActive,
|
|
869
|
+
getSessionGeneration,
|
|
867
870
|
startTypingLoop: startActiveTurnTypingLoop,
|
|
868
871
|
onMessageStart: previewRuntime.onMessageStart,
|
|
869
872
|
onMessageUpdate: previewRuntime.onMessageUpdate,
|
|
@@ -955,9 +958,12 @@ export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime,
|
|
|
955
958
|
async onAgentStart(event, ctx) {
|
|
956
959
|
if (!isSessionContextActive(ctx))
|
|
957
960
|
return;
|
|
961
|
+
const generation = getSessionGeneration?.();
|
|
958
962
|
agentWorkActive = true;
|
|
959
963
|
cancelPendingFinalPublication();
|
|
960
964
|
await agentStartWithDedupReset(event, ctx);
|
|
965
|
+
if (!isSessionContextActive(ctx) || (getSessionGeneration && !Object.is(getSessionGeneration(), generation)))
|
|
966
|
+
return;
|
|
961
967
|
const turn = activeTurnRuntime.get();
|
|
962
968
|
activityRuntime.onAgentStart(turn?.target, turn?.replyToMessageId);
|
|
963
969
|
startAgentActivityTypingLoop(ctx);
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Wraps the direct Telegram Bot API runtime so follower instances can route outbound calls through the bus leader
|
|
5
5
|
*/
|
|
6
6
|
import { type TelegramBusSelectedMenuDeliveryObservation, type TelegramBusSelectedMenuTextEffect } from "./bus.ts";
|
|
7
|
-
import type { TelegramBridgeApiRuntime } from "./telegram-api.ts";
|
|
8
|
-
export type TelegramBusApiCall = (method: string, args: unknown[]) => Promise<unknown>;
|
|
7
|
+
import type { TelegramApiCallOptions, TelegramBridgeApiRuntime } from "./telegram-api.ts";
|
|
8
|
+
export type TelegramBusApiCall = (method: string, args: unknown[], localOptions?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<unknown>;
|
|
9
9
|
export interface TelegramBusAwareApiRuntimeDeps {
|
|
10
10
|
directRuntime: TelegramBridgeApiRuntime;
|
|
11
11
|
ownsDirect: () => boolean;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Wraps the direct Telegram Bot API runtime so follower instances can route outbound calls through the bus leader
|
|
5
5
|
*/
|
|
6
6
|
import { markTelegramBusCrossTargetDelivery, parseTelegramBusSelectedMenuTextEffect, stripTelegramBusApiMetadata, } from "./bus.js";
|
|
7
|
-
import { buildTelegramAnswerGuestQueryBody, isTelegramApiCommitUnknownError, isTelegramMessageNotModifiedError, TelegramApiAuthorityError, TelegramApiCommitUnknownError, } from "./telegram-api.js";
|
|
7
|
+
import { buildTelegramAnswerGuestQueryBody, assertTelegramApiCallAuthority, isTelegramApiCommitUnknownError, isTelegramMessageNotModifiedError, TelegramApiAuthorityError, TelegramApiCommitUnknownError, } from "./telegram-api.js";
|
|
8
8
|
function asRecord(value) {
|
|
9
9
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
10
10
|
? value
|
|
@@ -142,6 +142,7 @@ export function createTelegramSelectedMenuTextApi(deps) {
|
|
|
142
142
|
}
|
|
143
143
|
/** Followers route every chat action through the leader's generic `sendChatAction` call. */
|
|
144
144
|
function sendTelegramFollowerChatAction(deps, chatId, action, options) {
|
|
145
|
+
assertTelegramApiCallAuthority(options?.assertAuthority, false);
|
|
145
146
|
const body = withDefaultThreadTarget({
|
|
146
147
|
chat_id: chatId,
|
|
147
148
|
action,
|
|
@@ -149,7 +150,11 @@ function sendTelegramFollowerChatAction(deps, chatId, action, options) {
|
|
|
149
150
|
? { message_thread_id: options.message_thread_id }
|
|
150
151
|
: {}),
|
|
151
152
|
}, deps.getDefaultTarget?.());
|
|
152
|
-
|
|
153
|
+
// Only plain single-attempt policy crosses IPC; the captured assertion is a local issuance fence.
|
|
154
|
+
const args = ["sendChatAction", body, ...(action === "typing"
|
|
155
|
+
? [{ maxAttempts: 1, retrySafety: "non-idempotent" }] : [])];
|
|
156
|
+
return deps.callFollowerApi("call", args, options?.assertAuthority
|
|
157
|
+
? { assertAuthority: options.assertAuthority } : undefined).then(asBoolean);
|
|
153
158
|
}
|
|
154
159
|
export function createTelegramBusAwareApiRuntime(deps) {
|
|
155
160
|
return {
|
|
@@ -12,8 +12,10 @@ import { TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_APPLY, TELEGRAM_BUS_CAPABILITY_SELE
|
|
|
12
12
|
import type { TelegramConfigStore, TelegramThreadDisplayMode } from "./config.ts";
|
|
13
13
|
import { type TelegramUpdateJournalStoreOptions } from "./journal.ts";
|
|
14
14
|
import { type TelegramLockEntry, type TelegramLockState } from "./locks.ts";
|
|
15
|
+
import * as Machine from "./machine.ts";
|
|
15
16
|
import type { TelegramQueueHandoffStageResult } from "./queue.ts";
|
|
16
17
|
import { type TelegramTarget } from "./target.ts";
|
|
18
|
+
import { type TelegramApiCallOptions } from "./telegram-api.ts";
|
|
17
19
|
import * as Threads from "./threads.ts";
|
|
18
20
|
import { type TelegramWorkspaceAdmissionLedger } from "./workspace-admission.ts";
|
|
19
21
|
export declare const TELEGRAM_BUS_FOLLOWER_HEARTBEAT_TIMEOUT_MS = 8000;
|
|
@@ -343,7 +345,9 @@ export declare function createTelegramBusFollowerWorkspaceRestoreHandler<TContex
|
|
|
343
345
|
expectedTarget?: TelegramTarget & {
|
|
344
346
|
threadId: number;
|
|
345
347
|
};
|
|
346
|
-
release?: (canRelease: () => boolean
|
|
348
|
+
release?: (canRelease: () => boolean, target: TelegramTarget & {
|
|
349
|
+
threadId: number;
|
|
350
|
+
}) => void;
|
|
347
351
|
observeWork?: (oldTarget: TelegramTarget & {
|
|
348
352
|
threadId: number;
|
|
349
353
|
}) => void;
|
|
@@ -362,7 +366,7 @@ export declare function createTelegramBusFollowerWorkspaceRestoreHandler<TContex
|
|
|
362
366
|
};
|
|
363
367
|
export declare function createTelegramBusFollowerClientRuntime<TContext, TReactionUpdate, TCallbackQuery, TMessage = unknown>(deps: TelegramBusFollowerClientRuntimeDeps<TMessage>): {
|
|
364
368
|
createRequestId: () => string;
|
|
365
|
-
callApi: (method: string, args: unknown[]) => Promise<unknown>;
|
|
369
|
+
callApi: (method: string, args: unknown[], localOptions?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<unknown>;
|
|
366
370
|
agentMessages: {
|
|
367
371
|
resolveTarget: (selector: TelegramBusAgentTargetSelector) => Promise<TelegramTarget & {
|
|
368
372
|
threadId: number;
|
|
@@ -414,7 +418,7 @@ export declare function createTelegramBusFollowerSelectedMenuCaller<TContext>(de
|
|
|
414
418
|
effect: TelegramBusSelectedMenuTextEffect;
|
|
415
419
|
assertAuthority: () => void;
|
|
416
420
|
}) => Promise<TelegramBusSelectedMenuDeliveryObservation>;
|
|
417
|
-
export declare function createTelegramBusFollowerApiCaller(deps: TelegramBusFollowerApiCallerDeps): (method: string, args: unknown[]) => Promise<unknown>;
|
|
421
|
+
export declare function createTelegramBusFollowerApiCaller(deps: TelegramBusFollowerApiCallerDeps): (method: string, args: unknown[], localOptions?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<unknown>;
|
|
418
422
|
export declare function createTelegramBusFollowerSessionReplacementSuspender(deps: TelegramBusFollowerSessionReplacementSuspenderDeps): (preserveTarget?: boolean) => Promise<void>;
|
|
419
423
|
export declare function createTelegramBusFollowerSessionRefreshHook<TContext>(deps: TelegramBusFollowerSessionRefreshHookDeps<TContext>): (_event: unknown, ctx: TContext) => Promise<void>;
|
|
420
424
|
export declare function createTelegramBusFollowerControlState(): TelegramBusFollowerControlState;
|
|
@@ -426,6 +430,48 @@ export type TelegramBusFollowerHeartbeatRecoveryHandler<TContext> = ((error: unk
|
|
|
426
430
|
halt: () => void;
|
|
427
431
|
resume: () => void;
|
|
428
432
|
};
|
|
433
|
+
/** The whole recovery lifecycle state; only `transitionTelegramBusFollowerRecovery` produces a new one. */
|
|
434
|
+
export interface TelegramBusFollowerRecoveryState {
|
|
435
|
+
/** Bumped by halt and resume, so a recovery or retry from before an operator stop or connect is inert. */
|
|
436
|
+
readonly epoch: number;
|
|
437
|
+
readonly halted: boolean;
|
|
438
|
+
/** One recovery runs at a time; it belongs to the epoch it started in. */
|
|
439
|
+
readonly recovering: boolean;
|
|
440
|
+
readonly retryId: number | null;
|
|
441
|
+
readonly nextRetryId: number;
|
|
442
|
+
}
|
|
443
|
+
export type TelegramBusFollowerRecoveryEvent = {
|
|
444
|
+
type: "recoverRequested";
|
|
445
|
+
} | {
|
|
446
|
+
type: "recoverySettled";
|
|
447
|
+
epoch: number;
|
|
448
|
+
} | {
|
|
449
|
+
type: "retryRequested";
|
|
450
|
+
epoch: number;
|
|
451
|
+
} | {
|
|
452
|
+
type: "retryFired";
|
|
453
|
+
retryId: number;
|
|
454
|
+
} | {
|
|
455
|
+
type: "halted";
|
|
456
|
+
} | {
|
|
457
|
+
type: "resumed";
|
|
458
|
+
};
|
|
459
|
+
export type TelegramBusFollowerRecoveryEffect = {
|
|
460
|
+
type: "runRecovery";
|
|
461
|
+
epoch: number;
|
|
462
|
+
} | {
|
|
463
|
+
type: "armRetry";
|
|
464
|
+
retryId: number;
|
|
465
|
+
} | {
|
|
466
|
+
type: "cancelRetry";
|
|
467
|
+
retryId: number;
|
|
468
|
+
};
|
|
469
|
+
export declare function createTelegramBusFollowerRecoveryState(): TelegramBusFollowerRecoveryState;
|
|
470
|
+
/**
|
|
471
|
+
* Pure follower-recovery lifecycle. An operator stop halts it and a connect resumes it, each in a new epoch: work
|
|
472
|
+
* from the old epoch, a recovery still awaiting or a retry still armed, can no longer register or promote.
|
|
473
|
+
*/
|
|
474
|
+
export declare function transitionTelegramBusFollowerRecovery(state: TelegramBusFollowerRecoveryState, event: TelegramBusFollowerRecoveryEvent): Machine.TelegramMachineStep<TelegramBusFollowerRecoveryState, TelegramBusFollowerRecoveryEffect>;
|
|
429
475
|
export declare function createTelegramBusFollowerHeartbeatRecoveryHandler<TContext>(deps: TelegramBusFollowerHeartbeatRecoveryHandlerDeps<TContext>): TelegramBusFollowerHeartbeatRecoveryHandler<TContext>;
|
|
430
476
|
export declare function createTelegramBusFollowerRegistrationRuntime<TContext extends {
|
|
431
477
|
cwd?: string;
|