@llblab/pi-telegram 0.52.2 → 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 +9 -7
- package/BACKLOG.md +1 -18
- package/CHANGELOG.md +11 -0
- package/README.md +7 -11
- 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 +639 -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 +29 -3
- package/dist/lib/locks.js +289 -108
- 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 +21 -37
- package/dist/lib/polling.js +59 -50
- 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 +1 -3
- package/dist/lib/sync.js +67 -43
- 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 +148 -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 +31 -29
- 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 +1206 -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 +677 -203
- 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 +144 -147
- 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 +448 -361
- package/lib/target.ts +22 -3
- package/lib/telegram-api.ts +302 -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/lib/preview.ts
CHANGED
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
* Owns safe draft preview selection, runtime updates, and preview finalization
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { normalizeTelegramNativeMarkdown } from "./replies.ts";
|
|
8
7
|
import type { TelegramAssistantOutputPreparation } from "./activity.ts";
|
|
9
8
|
import { stripTelegramCommentMarkupForPreview } from "./outbound-markup.ts";
|
|
9
|
+
import {
|
|
10
|
+
isTelegramMarkdownFenceClosing,
|
|
11
|
+
normalizeTelegramNativeMarkdown,
|
|
12
|
+
parseTelegramMarkdownFenceOpening,
|
|
13
|
+
type TelegramMarkdownFence,
|
|
14
|
+
} from "./replies.ts";
|
|
10
15
|
import {
|
|
11
16
|
getTelegramTargetThreadParams,
|
|
12
17
|
type TelegramTarget,
|
|
@@ -100,8 +105,9 @@ export interface TelegramAssistantMessagePreviewUpdateDeps<TMessage> {
|
|
|
100
105
|
) => void;
|
|
101
106
|
}
|
|
102
107
|
|
|
103
|
-
export type TelegramAssistantMessagePreviewHookDeps<TMessage> =
|
|
104
|
-
|
|
108
|
+
export type TelegramAssistantMessagePreviewHookDeps<TMessage> =
|
|
109
|
+
TelegramAssistantMessagePreviewStartDeps<TMessage> &
|
|
110
|
+
TelegramAssistantMessagePreviewUpdateDeps<TMessage>;
|
|
105
111
|
|
|
106
112
|
export interface TelegramAssistantMessagePreviewHookEvent<TMessage> {
|
|
107
113
|
message: TMessage;
|
|
@@ -206,7 +212,9 @@ export interface TelegramAssistantPreviewRuntimeDeps<
|
|
|
206
212
|
export interface TelegramPreparedPreviewDelivery<TReplyMarkup = unknown> {
|
|
207
213
|
clearPreview: TelegramPreviewController["clear"];
|
|
208
214
|
setPreviewPendingText: TelegramPreviewController["setPendingText"];
|
|
209
|
-
finalizeMarkdownPreview: ReturnType<
|
|
215
|
+
finalizeMarkdownPreview: ReturnType<
|
|
216
|
+
typeof createTelegramNativeMarkdownPreviewFinalizer<TReplyMarkup>
|
|
217
|
+
>;
|
|
210
218
|
}
|
|
211
219
|
|
|
212
220
|
export type TelegramAssistantPreviewRuntime<
|
|
@@ -214,7 +222,9 @@ export type TelegramAssistantPreviewRuntime<
|
|
|
214
222
|
TReplyMarkup = TelegramPreviewReplyMarkup,
|
|
215
223
|
> = TelegramPreviewController &
|
|
216
224
|
TelegramAssistantMessagePreviewHooks<TMessage> & {
|
|
217
|
-
prepareDelivery: (
|
|
225
|
+
prepareDelivery: (
|
|
226
|
+
isDeliveryActive: () => boolean,
|
|
227
|
+
) => TelegramPreparedPreviewDelivery<TReplyMarkup>;
|
|
218
228
|
finalizeMarkdown: (
|
|
219
229
|
chatId: number,
|
|
220
230
|
markdown: string,
|
|
@@ -223,7 +233,9 @@ export type TelegramAssistantPreviewRuntime<
|
|
|
223
233
|
) => Promise<boolean>;
|
|
224
234
|
};
|
|
225
235
|
|
|
226
|
-
function sealTelegramPreviewState(
|
|
236
|
+
function sealTelegramPreviewState(
|
|
237
|
+
state: TelegramPreviewRuntimeState | undefined,
|
|
238
|
+
): void {
|
|
227
239
|
if (!state) return;
|
|
228
240
|
state.sealed = true;
|
|
229
241
|
state.flushRequested = false;
|
|
@@ -253,21 +265,28 @@ export function createTelegramNativeMarkdownPreviewFinalizer<
|
|
|
253
265
|
replyToMessageId?: number,
|
|
254
266
|
options?: { replyMarkup?: TReplyMarkup; target?: TelegramTarget },
|
|
255
267
|
) => Promise<boolean> {
|
|
256
|
-
return (...args) =>
|
|
268
|
+
return (...args) =>
|
|
269
|
+
prepareTelegramNativeMarkdownPreviewFinalizer(deps)(...args);
|
|
257
270
|
}
|
|
258
271
|
|
|
259
272
|
function prepareTelegramNativeMarkdownPreviewFinalizer<TReplyMarkup>(
|
|
260
|
-
deps: Parameters<
|
|
261
|
-
|
|
273
|
+
deps: Parameters<
|
|
274
|
+
typeof createTelegramNativeMarkdownPreviewFinalizer<TReplyMarkup>
|
|
275
|
+
>[0],
|
|
276
|
+
): ReturnType<
|
|
277
|
+
typeof createTelegramNativeMarkdownPreviewFinalizer<TReplyMarkup>
|
|
278
|
+
> {
|
|
262
279
|
const state = deps.getState();
|
|
263
280
|
sealTelegramPreviewState(state);
|
|
264
281
|
const inFlight = state?.flushPromise ?? state?.precedingFlush;
|
|
265
282
|
return async (chatId, markdown, replyToMessageId, options) => {
|
|
266
283
|
if (deps.isDeliveryActive?.() === false) return false;
|
|
267
284
|
await inFlight?.catch(() => {});
|
|
268
|
-
if (deps.getState() !== state || deps.isDeliveryActive?.() === false)
|
|
285
|
+
if (deps.getState() !== state || deps.isDeliveryActive?.() === false)
|
|
286
|
+
return false;
|
|
269
287
|
await deps.sendMarkdownReply(chatId, replyToMessageId, markdown, options);
|
|
270
|
-
if (deps.getState() === state && deps.isDeliveryActive?.() !== false)
|
|
288
|
+
if (deps.getState() === state && deps.isDeliveryActive?.() !== false)
|
|
289
|
+
deps.discard?.();
|
|
271
290
|
return true;
|
|
272
291
|
};
|
|
273
292
|
}
|
|
@@ -287,18 +306,26 @@ export function createTelegramAssistantPreviewRuntime<
|
|
|
287
306
|
};
|
|
288
307
|
return {
|
|
289
308
|
...controller,
|
|
290
|
-
finalizeMarkdown:
|
|
309
|
+
finalizeMarkdown:
|
|
310
|
+
createTelegramNativeMarkdownPreviewFinalizer(finalizerDeps),
|
|
291
311
|
prepareDelivery(isDeliveryActive) {
|
|
292
312
|
const state = controller.getState();
|
|
293
313
|
return {
|
|
294
314
|
setPreviewPendingText(text) {
|
|
295
|
-
if (controller.getState() === state && isDeliveryActive())
|
|
315
|
+
if (controller.getState() === state && isDeliveryActive())
|
|
316
|
+
controller.setPendingText(text);
|
|
296
317
|
},
|
|
297
318
|
clearPreview: async (chatId, options) => {
|
|
298
319
|
if (controller.getState() !== state || !isDeliveryActive()) return;
|
|
299
|
-
await controller.prepareClear(chatId, {
|
|
320
|
+
await controller.prepareClear(chatId, {
|
|
321
|
+
...options,
|
|
322
|
+
isDeliveryActive,
|
|
323
|
+
})();
|
|
300
324
|
},
|
|
301
|
-
finalizeMarkdownPreview: prepareTelegramNativeMarkdownPreviewFinalizer({
|
|
325
|
+
finalizeMarkdownPreview: prepareTelegramNativeMarkdownPreviewFinalizer({
|
|
326
|
+
...finalizerDeps,
|
|
327
|
+
isDeliveryActive,
|
|
328
|
+
}),
|
|
302
329
|
};
|
|
303
330
|
},
|
|
304
331
|
...createTelegramAssistantMessagePreviewHooks({
|
|
@@ -325,7 +352,9 @@ export function createTelegramPreviewController(
|
|
|
325
352
|
deps.maxMessageLength ?? TELEGRAM_DRAFT_PREVIEW_MAX_CHARS;
|
|
326
353
|
let draftSupport = deps.initialDraftSupport ?? "unknown";
|
|
327
354
|
let nextDraftId = 0;
|
|
328
|
-
const setState = (
|
|
355
|
+
const setState = (
|
|
356
|
+
nextState: TelegramPreviewRuntimeState | undefined,
|
|
357
|
+
): void => {
|
|
329
358
|
if (state !== nextState) sealTelegramPreviewState(state);
|
|
330
359
|
state = nextState;
|
|
331
360
|
};
|
|
@@ -358,7 +387,10 @@ export function createTelegramPreviewController(
|
|
|
358
387
|
createState: () => createTelegramPreviewRuntimeState(),
|
|
359
388
|
resetState: () => {
|
|
360
389
|
generation += 1;
|
|
361
|
-
setState({
|
|
390
|
+
setState({
|
|
391
|
+
...createTelegramPreviewRuntimeState(),
|
|
392
|
+
nextDraftAt: state?.nextDraftAt,
|
|
393
|
+
});
|
|
362
394
|
},
|
|
363
395
|
invalidate: () => {
|
|
364
396
|
generation += 1;
|
|
@@ -368,10 +400,18 @@ export function createTelegramPreviewController(
|
|
|
368
400
|
preparePublication: () => {
|
|
369
401
|
if (!state) return undefined;
|
|
370
402
|
sealTelegramPreviewState(state);
|
|
371
|
-
const prior =
|
|
403
|
+
const prior =
|
|
404
|
+
state.publicationPromise ?? state.flushPromise ?? state.precedingFlush;
|
|
372
405
|
let settle!: () => void;
|
|
373
|
-
state.publicationPromise = new Promise<void>((resolve) => {
|
|
374
|
-
|
|
406
|
+
state.publicationPromise = new Promise<void>((resolve) => {
|
|
407
|
+
settle = resolve;
|
|
408
|
+
});
|
|
409
|
+
return {
|
|
410
|
+
wait: async () => {
|
|
411
|
+
await prior?.catch(() => {});
|
|
412
|
+
},
|
|
413
|
+
settle,
|
|
414
|
+
};
|
|
375
415
|
},
|
|
376
416
|
prepareClear: (chatId, options) => {
|
|
377
417
|
const admittedState = state;
|
|
@@ -380,7 +420,9 @@ export function createTelegramPreviewController(
|
|
|
380
420
|
if (state !== admittedState) return;
|
|
381
421
|
await clearTelegramPreview(chatId, runtime, {
|
|
382
422
|
...options,
|
|
383
|
-
isDeliveryActive: () =>
|
|
423
|
+
isDeliveryActive: () =>
|
|
424
|
+
runtime.canSend?.() !== false &&
|
|
425
|
+
options?.isDeliveryActive?.() !== false,
|
|
384
426
|
});
|
|
385
427
|
};
|
|
386
428
|
},
|
|
@@ -449,7 +491,8 @@ async function handleTelegramAssistantMessagePreviewStart<TMessage>(
|
|
|
449
491
|
// Carry the previous delivery boundary; permanent text remains with its publication owner.
|
|
450
492
|
next.draftId = state?.draftId;
|
|
451
493
|
next.nextDraftAt = state?.nextDraftAt;
|
|
452
|
-
next.precedingFlush =
|
|
494
|
+
next.precedingFlush =
|
|
495
|
+
state?.publicationPromise ?? state?.flushPromise ?? state?.precedingFlush;
|
|
453
496
|
deps.setState(next);
|
|
454
497
|
}
|
|
455
498
|
|
|
@@ -529,7 +572,11 @@ export function shouldUseTelegramDraftPreview(_options: {
|
|
|
529
572
|
export async function clearTelegramPreview(
|
|
530
573
|
chatId: number,
|
|
531
574
|
deps: TelegramPreviewRuntimeDeps,
|
|
532
|
-
options: {
|
|
575
|
+
options: {
|
|
576
|
+
awaitFlush?: boolean;
|
|
577
|
+
target?: TelegramTarget;
|
|
578
|
+
isDeliveryActive?: () => boolean;
|
|
579
|
+
} = {},
|
|
533
580
|
): Promise<void> {
|
|
534
581
|
const state = deps.getState();
|
|
535
582
|
if (!state || options.isDeliveryActive?.() === false) return;
|
|
@@ -542,7 +589,11 @@ export async function clearTelegramPreview(
|
|
|
542
589
|
}
|
|
543
590
|
if (options.isDeliveryActive?.() === false) return;
|
|
544
591
|
deps.setState(undefined);
|
|
545
|
-
if (
|
|
592
|
+
if (
|
|
593
|
+
state.mode === "draft" &&
|
|
594
|
+
state.draftId !== undefined &&
|
|
595
|
+
deps.canSend?.() !== false
|
|
596
|
+
) {
|
|
546
597
|
try {
|
|
547
598
|
await deps.sendDraft(chatId, state.draftId, undefined, {
|
|
548
599
|
...getTelegramTargetThreadParams(options.target ?? { chatId }),
|
|
@@ -561,7 +612,7 @@ interface TelegramDraftInlineState {
|
|
|
561
612
|
codeTicks: number;
|
|
562
613
|
htmlComment: boolean;
|
|
563
614
|
displayMath: boolean;
|
|
564
|
-
fence?:
|
|
615
|
+
fence?: TelegramMarkdownFence;
|
|
565
616
|
strongAsterisk: boolean;
|
|
566
617
|
emphasisAsterisk: boolean;
|
|
567
618
|
strongUnderscore: boolean;
|
|
@@ -724,13 +775,8 @@ function updateTelegramDraftBlockStateForLine(
|
|
|
724
775
|
line: string,
|
|
725
776
|
state: TelegramDraftInlineState,
|
|
726
777
|
): boolean {
|
|
727
|
-
const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
728
778
|
if (state.fence) {
|
|
729
|
-
if (
|
|
730
|
-
new RegExp(
|
|
731
|
-
`^ {0,3}${state.fence.marker}{${state.fence.length},}\\s*$`,
|
|
732
|
-
).test(line)
|
|
733
|
-
) {
|
|
779
|
+
if (isTelegramMarkdownFenceClosing(line, state.fence)) {
|
|
734
780
|
state.fence = undefined;
|
|
735
781
|
}
|
|
736
782
|
return true;
|
|
@@ -739,12 +785,9 @@ function updateTelegramDraftBlockStateForLine(
|
|
|
739
785
|
if (line.trim() === "$$") state.displayMath = false;
|
|
740
786
|
return true;
|
|
741
787
|
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
state.fence =
|
|
745
|
-
marker: markerText[0] as "`" | "~",
|
|
746
|
-
length: markerText.length,
|
|
747
|
-
};
|
|
788
|
+
const openingFence = parseTelegramMarkdownFenceOpening(line);
|
|
789
|
+
if (openingFence) {
|
|
790
|
+
state.fence = openingFence;
|
|
748
791
|
return true;
|
|
749
792
|
}
|
|
750
793
|
if (line.trim() === "$$") {
|
|
@@ -852,7 +895,12 @@ async function performTelegramPreviewFlush(
|
|
|
852
895
|
normalizeTelegramNativeMarkdown(snapshot.text),
|
|
853
896
|
{ ...getTelegramTargetThreadParams(options.target ?? { chatId }) },
|
|
854
897
|
);
|
|
855
|
-
if (
|
|
898
|
+
if (
|
|
899
|
+
delivered === false ||
|
|
900
|
+
deps.getState() !== state ||
|
|
901
|
+
deps.canSend?.() === false
|
|
902
|
+
)
|
|
903
|
+
return;
|
|
856
904
|
deps.setDraftSupport("supported");
|
|
857
905
|
state.mode = "draft";
|
|
858
906
|
state.lastSentText = snapshot.text;
|
|
@@ -893,7 +941,8 @@ export async function flushTelegramPreview(
|
|
|
893
941
|
if (!state.flushTimer) {
|
|
894
942
|
state.flushTimer = setTimeout(() => {
|
|
895
943
|
state.flushTimer = undefined;
|
|
896
|
-
if (deps.getState() === state && !state.sealed)
|
|
944
|
+
if (deps.getState() === state && !state.sealed)
|
|
945
|
+
void flushTelegramPreview(chatId, deps, options);
|
|
897
946
|
}, delay);
|
|
898
947
|
state.flushTimer.unref?.();
|
|
899
948
|
}
|
|
@@ -911,7 +960,11 @@ export async function flushTelegramPreview(
|
|
|
911
960
|
});
|
|
912
961
|
break;
|
|
913
962
|
}
|
|
914
|
-
} while (
|
|
963
|
+
} while (
|
|
964
|
+
deps.getState() === state &&
|
|
965
|
+
!state.sealed &&
|
|
966
|
+
state.flushRequested
|
|
967
|
+
);
|
|
915
968
|
})();
|
|
916
969
|
try {
|
|
917
970
|
await state.flushPromise;
|
|
@@ -0,0 +1,164 @@
|
|
|
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
|
+
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { platform as getPlatform } from "node:os";
|
|
12
|
+
|
|
13
|
+
export function isProcessAlive(pid: number): boolean {
|
|
14
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
15
|
+
try {
|
|
16
|
+
process.kill(pid, 0);
|
|
17
|
+
return true;
|
|
18
|
+
} catch (error) {
|
|
19
|
+
// Only an absent PID proves death; permission and unexpected failures do not.
|
|
20
|
+
return (error as { code?: string }).code !== "ESRCH";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface TelegramProcessBirthIdentityOptions {
|
|
25
|
+
platform?: NodeJS.Platform;
|
|
26
|
+
readProcStat?: (pid: number) => string;
|
|
27
|
+
readDarwinProcessStart?: (pid: number) => string;
|
|
28
|
+
readWindowsProcessStart?: (pid: number) => string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type TelegramProcessBirthProof =
|
|
32
|
+
{ status: "proven"; identity: string } | { status: "unverifiable" };
|
|
33
|
+
|
|
34
|
+
export type TelegramProcessLiveness = "alive" | "dead" | "unverifiable";
|
|
35
|
+
|
|
36
|
+
interface TelegramProcessLivenessOptions extends TelegramProcessBirthIdentityOptions {
|
|
37
|
+
isProcessAlive?: (pid: number) => boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readDarwinProcessStart(pid: number): string {
|
|
41
|
+
return execFileSync("/bin/ps", ["-o", "lstart=", "-p", String(pid)], {
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
44
|
+
}).trim();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Creation time in UTC 100 ns ticks; PowerShell ships with every supported Windows and needs no native addon. */
|
|
48
|
+
function readWindowsProcessStart(pid: number): string {
|
|
49
|
+
const root = process.env.SystemRoot ?? "C:\\Windows";
|
|
50
|
+
return execFileSync(
|
|
51
|
+
`${root}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`,
|
|
52
|
+
[
|
|
53
|
+
"-NoProfile",
|
|
54
|
+
"-NonInteractive",
|
|
55
|
+
"-Command",
|
|
56
|
+
`(Get-Process -Id ${pid} -ErrorAction Stop).StartTime.ToUniversalTime().Ticks`,
|
|
57
|
+
],
|
|
58
|
+
{
|
|
59
|
+
encoding: "utf8",
|
|
60
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
61
|
+
timeout: 10_000,
|
|
62
|
+
windowsHide: true,
|
|
63
|
+
},
|
|
64
|
+
).trim();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** The current process never changes birth, so its slow Windows proof is read once; other PIDs are never cached. */
|
|
68
|
+
let ownWindowsBirthProof: TelegramProcessBirthProof | undefined;
|
|
69
|
+
|
|
70
|
+
function getTelegramProcessBirthProof(
|
|
71
|
+
pid: number,
|
|
72
|
+
options: TelegramProcessBirthIdentityOptions = {},
|
|
73
|
+
): TelegramProcessBirthProof {
|
|
74
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return { status: "unverifiable" };
|
|
75
|
+
const platform = options.platform ?? getPlatform();
|
|
76
|
+
if (platform === "linux") {
|
|
77
|
+
try {
|
|
78
|
+
const stat = (
|
|
79
|
+
options.readProcStat ??
|
|
80
|
+
((targetPid) => readFileSync(`/proc/${targetPid}/stat`, "utf8"))
|
|
81
|
+
)(pid);
|
|
82
|
+
const closeParen = stat.lastIndexOf(")");
|
|
83
|
+
const fields = stat
|
|
84
|
+
.slice(closeParen + 2)
|
|
85
|
+
.trim()
|
|
86
|
+
.split(/\s+/u);
|
|
87
|
+
const startTicks = fields[19];
|
|
88
|
+
if (startTicks) {
|
|
89
|
+
return { status: "proven", identity: `${pid}:start:${startTicks}` };
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
/* inaccessible process metadata */
|
|
93
|
+
}
|
|
94
|
+
} else if (platform === "darwin") {
|
|
95
|
+
try {
|
|
96
|
+
const startedAt = (
|
|
97
|
+
options.readDarwinProcessStart ?? readDarwinProcessStart
|
|
98
|
+
)(pid);
|
|
99
|
+
if (startedAt) {
|
|
100
|
+
const fingerprint = createHash("sha256")
|
|
101
|
+
.update(startedAt)
|
|
102
|
+
.digest("hex")
|
|
103
|
+
.slice(0, 16);
|
|
104
|
+
return { status: "proven", identity: `${pid}:start:${fingerprint}` };
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
/* inaccessible process metadata */
|
|
108
|
+
}
|
|
109
|
+
} else if (platform === "win32") {
|
|
110
|
+
const injected = options.readWindowsProcessStart;
|
|
111
|
+
if (!injected && pid === process.pid && ownWindowsBirthProof)
|
|
112
|
+
return ownWindowsBirthProof;
|
|
113
|
+
let proof: TelegramProcessBirthProof = { status: "unverifiable" };
|
|
114
|
+
try {
|
|
115
|
+
const ticks = (injected ?? readWindowsProcessStart)(pid);
|
|
116
|
+
if (/^\d+$/u.test(ticks))
|
|
117
|
+
proof = { status: "proven", identity: `${pid}:start:${ticks}` };
|
|
118
|
+
} catch {
|
|
119
|
+
/* inaccessible process metadata, including another user's process */
|
|
120
|
+
}
|
|
121
|
+
if (!injected && pid === process.pid && proof.status === "proven")
|
|
122
|
+
ownWindowsBirthProof = proof;
|
|
123
|
+
return proof;
|
|
124
|
+
}
|
|
125
|
+
return { status: "unverifiable" };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function getTelegramProcessBirthIdentity(
|
|
129
|
+
pid: number,
|
|
130
|
+
fallbackGeneration: number | string,
|
|
131
|
+
options: TelegramProcessBirthIdentityOptions = {},
|
|
132
|
+
): string {
|
|
133
|
+
const proof = getTelegramProcessBirthProof(pid, options);
|
|
134
|
+
return proof.status === "proven"
|
|
135
|
+
? proof.identity
|
|
136
|
+
: `${pid}:generation:${fallbackGeneration}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function getTelegramProcessLiveness(
|
|
140
|
+
owner: { processId: number; processBirthId: string },
|
|
141
|
+
options: TelegramProcessLivenessOptions = {},
|
|
142
|
+
): TelegramProcessLiveness {
|
|
143
|
+
const processAlive = options.isProcessAlive ?? isProcessAlive;
|
|
144
|
+
if (!processAlive(owner.processId)) return "dead";
|
|
145
|
+
const proof = getTelegramProcessBirthProof(owner.processId, options);
|
|
146
|
+
if (proof.status === "unverifiable") return "unverifiable";
|
|
147
|
+
return proof.identity === owner.processBirthId ? "alive" : "dead";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function getTelegramProcessBirthIdentityLiveness(
|
|
151
|
+
processBirthId: string,
|
|
152
|
+
options: TelegramProcessLivenessOptions = {},
|
|
153
|
+
): TelegramProcessLiveness {
|
|
154
|
+
const match = /^(\d+):(start|generation):(.+)$/u.exec(processBirthId);
|
|
155
|
+
if (!match) return "unverifiable";
|
|
156
|
+
const processId = Number(match[1]);
|
|
157
|
+
if (!Number.isSafeInteger(processId) || processId <= 0) return "unverifiable";
|
|
158
|
+
const processAlive = options.isProcessAlive ?? isProcessAlive;
|
|
159
|
+
if (!processAlive(processId)) return "dead";
|
|
160
|
+
if (match[2] === "generation") return "unverifiable";
|
|
161
|
+
const proof = getTelegramProcessBirthProof(processId, options);
|
|
162
|
+
if (proof.status === "unverifiable") return "unverifiable";
|
|
163
|
+
return proof.identity === processBirthId ? "alive" : "dead";
|
|
164
|
+
}
|
package/lib/prompts.ts
CHANGED
|
@@ -86,8 +86,7 @@ export interface TelegramModelContextAvailabilityRuntime {
|
|
|
86
86
|
reconcile: () => void;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
export interface TelegramModelContextAvailabilityBinding
|
|
90
|
-
extends TelegramModelContextAvailabilityRuntime {
|
|
89
|
+
export interface TelegramModelContextAvailabilityBinding extends TelegramModelContextAvailabilityRuntime {
|
|
91
90
|
bind: (runtime: TelegramModelContextAvailabilityRuntime) => void;
|
|
92
91
|
}
|
|
93
92
|
|
|
@@ -110,8 +109,7 @@ export function createTelegramModelContextAvailabilityRuntime(deps: {
|
|
|
110
109
|
canReconcile?: () => boolean;
|
|
111
110
|
memory?: TelegramModelContextAvailabilityMemory;
|
|
112
111
|
}): TelegramModelContextAvailabilityRuntime {
|
|
113
|
-
const memory =
|
|
114
|
-
deps.memory ?? getTelegramModelContextAvailabilityMemory();
|
|
112
|
+
const memory = deps.memory ?? getTelegramModelContextAvailabilityMemory();
|
|
115
113
|
return {
|
|
116
114
|
reconcile() {
|
|
117
115
|
if (deps.canReconcile && !deps.canReconcile()) return;
|
|
@@ -188,13 +186,8 @@ export function buildTelegramBridgeSystemPrompt(options: {
|
|
|
188
186
|
: "";
|
|
189
187
|
return {
|
|
190
188
|
systemPrompt: Array.isArray(basePrompt)
|
|
191
|
-
? [
|
|
192
|
-
|
|
193
|
-
options.localSystemPromptSuffix + telegramSuffix,
|
|
194
|
-
]
|
|
195
|
-
: basePrompt +
|
|
196
|
-
options.localSystemPromptSuffix +
|
|
197
|
-
telegramSuffix,
|
|
189
|
+
? [...basePrompt, options.localSystemPromptSuffix + telegramSuffix]
|
|
190
|
+
: basePrompt + options.localSystemPromptSuffix + telegramSuffix,
|
|
198
191
|
};
|
|
199
192
|
}
|
|
200
193
|
|