@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/outbound.ts
CHANGED
|
@@ -9,17 +9,6 @@ import { mkdir } from "node:fs/promises";
|
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
|
|
11
11
|
import type { TelegramAssistantSegmentEvent } from "./activity.ts";
|
|
12
|
-
import { resolveTelegramAttachmentsDir } from "./paths.ts";
|
|
13
|
-
import * as Replies from "./replies.ts";
|
|
14
|
-
import type { TelegramPreparedPreviewDelivery } from "./preview.ts";
|
|
15
|
-
import { isTelegramApiCommitUnknownError } from "./telegram-api.ts";
|
|
16
|
-
import type {
|
|
17
|
-
TelegramEditMessageTextBody,
|
|
18
|
-
TelegramSendMessageBody,
|
|
19
|
-
TelegramSendRichMessageBody,
|
|
20
|
-
TelegramSentMessage,
|
|
21
|
-
} from "./telegram-api.ts";
|
|
22
|
-
|
|
23
12
|
import {
|
|
24
13
|
planTelegramButtonReply,
|
|
25
14
|
type TelegramButtonActionStore,
|
|
@@ -32,15 +21,32 @@ import {
|
|
|
32
21
|
type TelegramVoiceReplyItem,
|
|
33
22
|
} from "./outbound-markup.ts";
|
|
34
23
|
import { createTelegramVoiceReplySender as createTelegramVoiceReplySenderWithPorts } from "./outbound-voice.ts";
|
|
24
|
+
import { resolveTelegramAttachmentsDir } from "./paths.ts";
|
|
25
|
+
import type { TelegramPreparedPreviewDelivery } from "./preview.ts";
|
|
26
|
+
import * as Replies from "./replies.ts";
|
|
35
27
|
import type { TelegramTarget } from "./target.ts";
|
|
28
|
+
import type {
|
|
29
|
+
TelegramEditMessageTextBody,
|
|
30
|
+
TelegramSendMessageBody,
|
|
31
|
+
TelegramSendRichMessageBody,
|
|
32
|
+
TelegramSentMessage,
|
|
33
|
+
} from "./telegram-api.ts";
|
|
34
|
+
import {
|
|
35
|
+
assertTelegramApiCallAuthority,
|
|
36
|
+
isTelegramApiCommitUnknownError,
|
|
37
|
+
} from "./telegram-api.ts";
|
|
36
38
|
|
|
37
39
|
const OUTBOUND_HANDLER_REGISTRY_KEY = "__piTelegramOutboundHandlers__";
|
|
38
40
|
const VOICE_EVENT_RECORDER_KEY = "__piTelegramVoiceEventRecorder__";
|
|
39
41
|
|
|
40
42
|
import {
|
|
41
43
|
buildCommandTemplateInvocation,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
createCommandTemplateRecovery,
|
|
45
|
+
getCommandTemplateCompositionSteps,
|
|
46
|
+
shouldRunCommandTemplateConfig,
|
|
47
|
+
getCommandTemplateConfiguredTimeout,
|
|
48
|
+
getCommandTemplateStepTimeout,
|
|
49
|
+
resolveCommandTemplateNumericField,
|
|
44
50
|
type CommandTemplateObjectConfig,
|
|
45
51
|
} from "./command-templates.ts";
|
|
46
52
|
const DEFAULT_VOICE_TIMEOUT_MS = 120_000;
|
|
@@ -87,22 +93,13 @@ export interface TelegramOutboundHandlerConfig extends CommandTemplateObjectConf
|
|
|
87
93
|
timeout?: number | string;
|
|
88
94
|
}
|
|
89
95
|
|
|
90
|
-
export {
|
|
91
|
-
normalizeMarkdownAfterVoiceExtraction,
|
|
92
|
-
planTelegramVoiceReply,
|
|
93
|
-
stripTelegramCommentMarkupForDelivery,
|
|
94
|
-
stripTelegramCommentMarkupForPreview,
|
|
95
|
-
stripTelegramVoiceMarkupForPreview,
|
|
96
|
-
type TelegramVoiceReplyItem,
|
|
97
|
-
type TelegramVoiceReplyPlan,
|
|
98
|
-
} from "./outbound-markup.ts";
|
|
99
|
-
|
|
100
96
|
export interface TelegramVoiceExecOptions {
|
|
101
97
|
cwd?: string;
|
|
102
98
|
timeout?: number;
|
|
103
99
|
signal?: AbortSignal;
|
|
104
100
|
stdin?: string;
|
|
105
101
|
retry?: number;
|
|
102
|
+
recover?: () => Promise<void>;
|
|
106
103
|
}
|
|
107
104
|
|
|
108
105
|
export interface TelegramVoiceExecResult {
|
|
@@ -216,13 +213,19 @@ export interface TelegramOutboundTextReplyRuntimeDeps<TReplyMarkup = unknown> {
|
|
|
216
213
|
chatId: number,
|
|
217
214
|
replyToMessageId: number | undefined,
|
|
218
215
|
text: string,
|
|
219
|
-
options?: { parseMode?: "HTML"; target?: TelegramTarget }
|
|
216
|
+
options?: { parseMode?: "HTML"; target?: TelegramTarget } & Pick<
|
|
217
|
+
Replies.TelegramReplyTargetOptions,
|
|
218
|
+
"assertAuthority"
|
|
219
|
+
>,
|
|
220
220
|
) => Promise<number | undefined>;
|
|
221
221
|
sendMarkdownReply: (
|
|
222
222
|
chatId: number,
|
|
223
223
|
replyToMessageId: number | undefined,
|
|
224
224
|
markdown: string,
|
|
225
|
-
options?: { replyMarkup?: TReplyMarkup; target?: TelegramTarget }
|
|
225
|
+
options?: { replyMarkup?: TReplyMarkup; target?: TelegramTarget } & Pick<
|
|
226
|
+
Replies.TelegramReplyTargetOptions,
|
|
227
|
+
"assertAuthority"
|
|
228
|
+
>,
|
|
226
229
|
) => Promise<number | undefined>;
|
|
227
230
|
cwd?: string;
|
|
228
231
|
recordRuntimeEvent?: TelegramVoiceReplySenderDeps["recordRuntimeEvent"];
|
|
@@ -251,60 +254,21 @@ export interface TelegramOutboundTextPreviewRuntimeDeps<
|
|
|
251
254
|
execCommand: TelegramVoiceReplySenderDeps["execCommand"];
|
|
252
255
|
getHandlers?: () => TelegramOutboundHandlerConfig[] | undefined;
|
|
253
256
|
finalizeMarkdownPreview: TelegramPreparedPreviewDelivery<TReplyMarkup>["finalizeMarkdownPreview"];
|
|
254
|
-
preparePreviewDelivery?: (
|
|
257
|
+
preparePreviewDelivery?: (
|
|
258
|
+
isDeliveryActive: () => boolean,
|
|
259
|
+
) => TelegramPreparedPreviewDelivery<TReplyMarkup>;
|
|
255
260
|
cwd?: string;
|
|
256
261
|
recordRuntimeEvent?: TelegramVoiceReplySenderDeps["recordRuntimeEvent"];
|
|
257
262
|
}
|
|
258
263
|
|
|
259
264
|
// --- Voice Reply Timeout Helpers ---
|
|
260
265
|
|
|
261
|
-
function resolveOutboundNumericControlField(
|
|
262
|
-
value: number | string | undefined,
|
|
263
|
-
values: Record<string, unknown>,
|
|
264
|
-
label: string,
|
|
265
|
-
): number | undefined {
|
|
266
|
-
if (value === undefined) return undefined;
|
|
267
|
-
const resolved =
|
|
268
|
-
typeof value === "string"
|
|
269
|
-
? substituteCommandTemplateToken(value, values, label)
|
|
270
|
-
: value;
|
|
271
|
-
if (resolved === "") return undefined;
|
|
272
|
-
const numeric = Number(resolved);
|
|
273
|
-
if (!Number.isFinite(numeric) || numeric < 0)
|
|
274
|
-
throw new Error(`Command template ${label} must be a non-negative number.`);
|
|
275
|
-
return numeric;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
function getVoiceReplyConfiguredTimeout(
|
|
279
|
-
config: TelegramOutboundCommandTemplateConfig | undefined,
|
|
280
|
-
): number | undefined {
|
|
281
|
-
const timeout = typeof config === "string" ? undefined : config?.timeout;
|
|
282
|
-
return resolveOutboundNumericControlField(timeout, {}, "timeout");
|
|
283
|
-
}
|
|
284
|
-
|
|
285
266
|
function getVoiceReplyTimeout(
|
|
286
267
|
config: TelegramOutboundCommandTemplateConfig | undefined,
|
|
287
268
|
): number {
|
|
288
|
-
return
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
function getRemainingVoiceReplyTimeout(
|
|
292
|
-
timeout: number,
|
|
293
|
-
startedAt: number,
|
|
294
|
-
): number {
|
|
295
|
-
return Math.max(1, timeout - (Date.now() - startedAt));
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
function getVoiceReplyCompositionStepTimeout(
|
|
299
|
-
handlerTimeout: number,
|
|
300
|
-
step: TelegramOutboundCommandTemplateConfig,
|
|
301
|
-
startedAt: number,
|
|
302
|
-
): number {
|
|
303
|
-
const remaining = getRemainingVoiceReplyTimeout(handlerTimeout, startedAt);
|
|
304
|
-
const stepTimeout = getVoiceReplyConfiguredTimeout(step);
|
|
305
|
-
return stepTimeout === undefined
|
|
306
|
-
? remaining
|
|
307
|
-
: Math.min(stepTimeout, remaining);
|
|
269
|
+
return (
|
|
270
|
+
getCommandTemplateConfiguredTimeout(config) ?? DEFAULT_VOICE_TIMEOUT_MS
|
|
271
|
+
);
|
|
308
272
|
}
|
|
309
273
|
|
|
310
274
|
function formatVoiceReplyExecutionFailure(
|
|
@@ -319,6 +283,12 @@ function formatVoiceReplyExecutionFailure(
|
|
|
319
283
|
return parts.join("\n\n");
|
|
320
284
|
}
|
|
321
285
|
|
|
286
|
+
function withCommandTemplateRecovery(
|
|
287
|
+
recover: (() => Promise<void>) | undefined,
|
|
288
|
+
): Pick<TelegramVoiceExecOptions, "recover"> {
|
|
289
|
+
return recover ? { recover } : {};
|
|
290
|
+
}
|
|
291
|
+
|
|
322
292
|
async function runVoiceReplyCommand(
|
|
323
293
|
label: string,
|
|
324
294
|
config: TelegramOutboundCommandTemplateConfig,
|
|
@@ -350,11 +320,18 @@ async function runVoiceReplyCommand(
|
|
|
350
320
|
timeout: options.timeout,
|
|
351
321
|
...(typeof config === "object" && config.retry !== undefined
|
|
352
322
|
? {
|
|
353
|
-
retry:
|
|
323
|
+
retry: resolveCommandTemplateNumericField(
|
|
354
324
|
config.retry,
|
|
355
325
|
{},
|
|
356
326
|
"retry",
|
|
357
327
|
),
|
|
328
|
+
...withCommandTemplateRecovery(
|
|
329
|
+
createCommandTemplateRecovery(config, values, {
|
|
330
|
+
cwd: options.cwd,
|
|
331
|
+
timeout: options.timeout,
|
|
332
|
+
execCommand: options.execCommand,
|
|
333
|
+
}),
|
|
334
|
+
),
|
|
358
335
|
}
|
|
359
336
|
: {}),
|
|
360
337
|
...(options.stdin !== undefined ? { stdin: options.stdin } : {}),
|
|
@@ -402,17 +379,6 @@ export function findTelegramOutboundHandlers(
|
|
|
402
379
|
);
|
|
403
380
|
}
|
|
404
381
|
|
|
405
|
-
function getTelegramVoiceHandlerCompositionSteps(
|
|
406
|
-
handler: TelegramOutboundHandlerConfig,
|
|
407
|
-
): TelegramOutboundCommandTemplateConfig[] {
|
|
408
|
-
if (Array.isArray(handler.template)) {
|
|
409
|
-
return expandCommandTemplateConfigs(
|
|
410
|
-
handler,
|
|
411
|
-
) as TelegramOutboundCommandTemplateConfig[];
|
|
412
|
-
}
|
|
413
|
-
return [];
|
|
414
|
-
}
|
|
415
|
-
|
|
416
382
|
function extractVoiceReplyPath(stdout: string): string {
|
|
417
383
|
const path = stdout.trim().split(/\r?\n/).filter(Boolean).at(-1);
|
|
418
384
|
if (!path) throw new Error("Voice generator did not print an output path");
|
|
@@ -465,7 +431,7 @@ async function generateTelegramVoiceReplyFileWithHandler(
|
|
|
465
431
|
timeout: number;
|
|
466
432
|
execCommand: TelegramVoiceReplySenderDeps["execCommand"];
|
|
467
433
|
},
|
|
468
|
-
): Promise<string> {
|
|
434
|
+
): Promise<string | undefined> {
|
|
469
435
|
await mkdir(options.tempDir, { recursive: true });
|
|
470
436
|
const artifactId = randomUUID();
|
|
471
437
|
const values = getVoiceReplyTemplateValues(text, {
|
|
@@ -474,11 +440,14 @@ async function generateTelegramVoiceReplyFileWithHandler(
|
|
|
474
440
|
mp3Path: join(options.tempDir, `${artifactId}-voice.mp3`),
|
|
475
441
|
oggPath: join(options.tempDir, `${artifactId}-voice.ogg`),
|
|
476
442
|
});
|
|
477
|
-
|
|
443
|
+
if (!shouldRunCommandTemplateConfig(options.handler, values))
|
|
444
|
+
return undefined;
|
|
445
|
+
const steps = getCommandTemplateCompositionSteps(options.handler);
|
|
478
446
|
if (steps.length > 0) {
|
|
479
447
|
const startedAt = Date.now();
|
|
480
448
|
let stdout = text;
|
|
481
449
|
for (const [index, step] of steps.entries()) {
|
|
450
|
+
if (!shouldRunCommandTemplateConfig(step, values)) continue;
|
|
482
451
|
try {
|
|
483
452
|
const result = await runVoiceReplyCommand(
|
|
484
453
|
`Outbound voice template step ${index + 1}`,
|
|
@@ -486,10 +455,10 @@ async function generateTelegramVoiceReplyFileWithHandler(
|
|
|
486
455
|
values,
|
|
487
456
|
{
|
|
488
457
|
cwd: options.cwd,
|
|
489
|
-
timeout:
|
|
458
|
+
timeout: getCommandTemplateStepTimeout(
|
|
490
459
|
options.timeout,
|
|
491
460
|
step,
|
|
492
|
-
startedAt,
|
|
461
|
+
Date.now() - startedAt,
|
|
493
462
|
),
|
|
494
463
|
execCommand: options.execCommand,
|
|
495
464
|
stdin: stdout,
|
|
@@ -554,11 +523,13 @@ async function transformTelegramOutboundTextWithHandler(
|
|
|
554
523
|
},
|
|
555
524
|
): Promise<string> {
|
|
556
525
|
const values = getOutboundTextTemplateValues(text);
|
|
557
|
-
|
|
526
|
+
if (!shouldRunCommandTemplateConfig(options.handler, values)) return text;
|
|
527
|
+
const steps = getCommandTemplateCompositionSteps(options.handler);
|
|
558
528
|
if (steps.length > 0) {
|
|
559
529
|
const startedAt = Date.now();
|
|
560
530
|
let stdout = text;
|
|
561
531
|
for (const [index, step] of steps.entries()) {
|
|
532
|
+
if (!shouldRunCommandTemplateConfig(step, values)) continue;
|
|
562
533
|
try {
|
|
563
534
|
const result = await runVoiceReplyCommand(
|
|
564
535
|
`Outbound text template step ${index + 1}`,
|
|
@@ -566,10 +537,10 @@ async function transformTelegramOutboundTextWithHandler(
|
|
|
566
537
|
values,
|
|
567
538
|
{
|
|
568
539
|
cwd: options.cwd,
|
|
569
|
-
timeout:
|
|
540
|
+
timeout: getCommandTemplateStepTimeout(
|
|
570
541
|
getVoiceReplyTimeout(options.handler),
|
|
571
542
|
step,
|
|
572
|
-
startedAt,
|
|
543
|
+
Date.now() - startedAt,
|
|
573
544
|
),
|
|
574
545
|
execCommand: options.execCommand,
|
|
575
546
|
stdin: stdout,
|
|
@@ -658,9 +629,7 @@ async function transformTelegramOutboundReplyMarkup<TReplyMarkup>(
|
|
|
658
629
|
return { ...replyMarkup, inline_keyboard: translatedRows } as TReplyMarkup;
|
|
659
630
|
}
|
|
660
631
|
|
|
661
|
-
async function transformTelegramOutboundTextReply<
|
|
662
|
-
TReplyMarkup = unknown,
|
|
663
|
-
>(
|
|
632
|
+
async function transformTelegramOutboundTextReply<TReplyMarkup = unknown>(
|
|
664
633
|
text: string,
|
|
665
634
|
options: TelegramOutboundTextTransformOptions<TReplyMarkup>,
|
|
666
635
|
): Promise<TelegramOutboundTextTransformResult<TReplyMarkup>> {
|
|
@@ -687,37 +656,65 @@ export function createTelegramOutboundTextReplyRuntime<TReplyMarkup = unknown>(
|
|
|
687
656
|
TelegramOutboundTextReplyRuntimeDeps<TReplyMarkup>,
|
|
688
657
|
"sendTextReply" | "sendMarkdownReply"
|
|
689
658
|
> {
|
|
659
|
+
const sendTextReply = deps.sendTextReply,
|
|
660
|
+
sendMarkdownReply = deps.sendMarkdownReply;
|
|
690
661
|
return {
|
|
691
662
|
sendTextReply: async (chatId, replyToMessageId, text, options) => {
|
|
663
|
+
const capturedOptions = options && {
|
|
664
|
+
...options,
|
|
665
|
+
...(options.target ? { target: { ...options.target } } : {}),
|
|
666
|
+
};
|
|
667
|
+
const assertAuthority = capturedOptions?.assertAuthority;
|
|
668
|
+
assertTelegramApiCallAuthority(assertAuthority, false);
|
|
692
669
|
const transformed = await transformTelegramOutboundText(text, {
|
|
693
670
|
handlers: deps.getHandlers?.(),
|
|
694
671
|
cwd: deps.cwd,
|
|
695
672
|
execCommand: deps.execCommand,
|
|
696
673
|
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
697
674
|
});
|
|
698
|
-
|
|
675
|
+
assertTelegramApiCallAuthority(assertAuthority, false);
|
|
676
|
+
const messageId = await sendTextReply(
|
|
677
|
+
chatId,
|
|
678
|
+
replyToMessageId,
|
|
679
|
+
transformed,
|
|
680
|
+
capturedOptions,
|
|
681
|
+
);
|
|
682
|
+
assertTelegramApiCallAuthority(assertAuthority, true);
|
|
683
|
+
return messageId;
|
|
699
684
|
},
|
|
700
685
|
sendMarkdownReply: async (chatId, replyToMessageId, markdown, options) => {
|
|
686
|
+
const capturedOptions = options && {
|
|
687
|
+
...options,
|
|
688
|
+
...(options.target ? { target: { ...options.target } } : {}),
|
|
689
|
+
};
|
|
690
|
+
const assertAuthority = capturedOptions?.assertAuthority;
|
|
691
|
+
assertTelegramApiCallAuthority(assertAuthority, false);
|
|
701
692
|
const deliveryMarkdown = stripTelegramCommentMarkupForDelivery(markdown);
|
|
702
693
|
if (!deliveryMarkdown) return undefined;
|
|
703
|
-
const transformed = await transformTelegramOutboundTextReply(
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
694
|
+
const transformed = await transformTelegramOutboundTextReply(
|
|
695
|
+
deliveryMarkdown,
|
|
696
|
+
{
|
|
697
|
+
handlers: deps.getHandlers?.(),
|
|
698
|
+
cwd: deps.cwd,
|
|
699
|
+
execCommand: deps.execCommand,
|
|
700
|
+
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
701
|
+
replyMarkup: capturedOptions?.replyMarkup,
|
|
702
|
+
},
|
|
703
|
+
);
|
|
704
|
+
assertTelegramApiCallAuthority(assertAuthority, false);
|
|
705
|
+
const messageId = await sendMarkdownReply(
|
|
711
706
|
chatId,
|
|
712
707
|
replyToMessageId,
|
|
713
708
|
transformed.text,
|
|
714
709
|
{
|
|
715
|
-
...
|
|
710
|
+
...capturedOptions,
|
|
716
711
|
...(transformed.replyMarkup
|
|
717
712
|
? { replyMarkup: transformed.replyMarkup }
|
|
718
713
|
: {}),
|
|
719
714
|
},
|
|
720
715
|
);
|
|
716
|
+
assertTelegramApiCallAuthority(assertAuthority, true);
|
|
717
|
+
return messageId;
|
|
721
718
|
},
|
|
722
719
|
};
|
|
723
720
|
}
|
|
@@ -728,16 +725,15 @@ export function createTelegramOutboundTextPreviewRuntime<
|
|
|
728
725
|
deps: TelegramOutboundTextPreviewRuntimeDeps<TReplyMarkup>,
|
|
729
726
|
): {
|
|
730
727
|
finalizeMarkdownPreview: TelegramPreparedPreviewDelivery<TReplyMarkup>["finalizeMarkdownPreview"];
|
|
731
|
-
preparePreviewDelivery: (
|
|
728
|
+
preparePreviewDelivery: (
|
|
729
|
+
isDeliveryActive: () => boolean,
|
|
730
|
+
) => TelegramPreparedPreviewDelivery<TReplyMarkup> | undefined;
|
|
732
731
|
} {
|
|
733
|
-
const wrap =
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
replyToMessageId,
|
|
739
|
-
options,
|
|
740
|
-
) => {
|
|
732
|
+
const wrap =
|
|
733
|
+
(
|
|
734
|
+
finalize: TelegramPreparedPreviewDelivery<TReplyMarkup>["finalizeMarkdownPreview"],
|
|
735
|
+
): TelegramPreparedPreviewDelivery<TReplyMarkup>["finalizeMarkdownPreview"] =>
|
|
736
|
+
async (chatId, markdown, replyToMessageId, options) => {
|
|
741
737
|
const transformed = await transformTelegramOutboundTextReply(markdown, {
|
|
742
738
|
handlers: deps.getHandlers?.(),
|
|
743
739
|
cwd: deps.cwd,
|
|
@@ -745,23 +741,23 @@ export function createTelegramOutboundTextPreviewRuntime<
|
|
|
745
741
|
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
746
742
|
replyMarkup: options?.replyMarkup,
|
|
747
743
|
});
|
|
748
|
-
return finalize(
|
|
749
|
-
|
|
750
|
-
transformed.
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
...(transformed.replyMarkup
|
|
755
|
-
? { replyMarkup: transformed.replyMarkup }
|
|
756
|
-
: {}),
|
|
757
|
-
},
|
|
758
|
-
);
|
|
744
|
+
return finalize(chatId, transformed.text, replyToMessageId, {
|
|
745
|
+
...options,
|
|
746
|
+
...(transformed.replyMarkup
|
|
747
|
+
? { replyMarkup: transformed.replyMarkup }
|
|
748
|
+
: {}),
|
|
749
|
+
});
|
|
759
750
|
};
|
|
760
751
|
return {
|
|
761
752
|
finalizeMarkdownPreview: wrap(deps.finalizeMarkdownPreview),
|
|
762
753
|
preparePreviewDelivery(isDeliveryActive) {
|
|
763
754
|
const prepared = deps.preparePreviewDelivery?.(isDeliveryActive);
|
|
764
|
-
return prepared
|
|
755
|
+
return prepared
|
|
756
|
+
? {
|
|
757
|
+
...prepared,
|
|
758
|
+
finalizeMarkdownPreview: wrap(prepared.finalizeMarkdownPreview),
|
|
759
|
+
}
|
|
760
|
+
: undefined;
|
|
765
761
|
},
|
|
766
762
|
};
|
|
767
763
|
}
|
|
@@ -892,8 +888,12 @@ export function createTelegramOutboundReplyArtifactSender(
|
|
|
892
888
|
options?: { replyToPrompt?: boolean; isDeliveryActive?: () => boolean },
|
|
893
889
|
): Promise<void> => {
|
|
894
890
|
const isDeliveryActive = () =>
|
|
895
|
-
deps.isDeliveryActive?.() !== false &&
|
|
896
|
-
|
|
891
|
+
deps.isDeliveryActive?.() !== false &&
|
|
892
|
+
options?.isDeliveryActive?.() !== false;
|
|
893
|
+
const sendVoiceReply = createTelegramVoiceReplySender({
|
|
894
|
+
...deps,
|
|
895
|
+
isDeliveryActive,
|
|
896
|
+
});
|
|
897
897
|
// Normalize voice replies: either use explicit voiceReplies array or fall back to voiceText
|
|
898
898
|
const voiceReplies = plan.voiceReplies?.length
|
|
899
899
|
? plan.voiceReplies
|
package/lib/ownership.ts
CHANGED
|
@@ -51,7 +51,11 @@ export interface TelegramMessageOwnershipStore {
|
|
|
51
51
|
|
|
52
52
|
export type TelegramFollowerOwnershipView = Pick<
|
|
53
53
|
TelegramBusFollowerView,
|
|
54
|
-
|
|
54
|
+
| "instanceId"
|
|
55
|
+
| "connectedAtMs"
|
|
56
|
+
| "profileKey"
|
|
57
|
+
| "registrationGeneration"
|
|
58
|
+
| "protocol"
|
|
55
59
|
>;
|
|
56
60
|
|
|
57
61
|
export interface TelegramBusMessageOwnershipRuntime {
|
|
@@ -115,8 +119,7 @@ export function createTelegramBusMessageOwnershipRuntime(deps: {
|
|
|
115
119
|
const follower = deps
|
|
116
120
|
.listFollowers()
|
|
117
121
|
.find(
|
|
118
|
-
(candidate) =>
|
|
119
|
-
candidate.profileKey === record.recipientBindingKey,
|
|
122
|
+
(candidate) => candidate.profileKey === record.recipientBindingKey,
|
|
120
123
|
);
|
|
121
124
|
return follower
|
|
122
125
|
? {
|
|
@@ -146,17 +149,23 @@ export function createTelegramBusMessageOwnershipRuntime(deps: {
|
|
|
146
149
|
store,
|
|
147
150
|
getForwardOwnership(chatId, messageId) {
|
|
148
151
|
const record = store.get(chatId, messageId);
|
|
149
|
-
if (!record?.ownerGeneration || !record.recipientBindingKey)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
if (!record?.ownerGeneration || !record.recipientBindingKey)
|
|
153
|
+
return record;
|
|
154
|
+
const follower = deps
|
|
155
|
+
.listFollowers()
|
|
156
|
+
.find(
|
|
157
|
+
(candidate) =>
|
|
158
|
+
candidate.instanceId === record.instanceId &&
|
|
159
|
+
candidate.registrationGeneration === record.ownerGeneration &&
|
|
160
|
+
candidate.profileKey === record.recipientBindingKey,
|
|
161
|
+
);
|
|
155
162
|
// Protocol is live registration authority, not message-cache history.
|
|
156
163
|
// Keep an incomplete known owner foreign so the forwarder fails closed.
|
|
157
164
|
return follower?.protocol?.capabilities.includes(
|
|
158
165
|
TELEGRAM_BUS_CAPABILITY_DURABLE_FOLLOWER_ADMISSION,
|
|
159
|
-
)
|
|
166
|
+
)
|
|
167
|
+
? { ...record, protocolIdentity: follower.protocol }
|
|
168
|
+
: record;
|
|
160
169
|
},
|
|
161
170
|
recordLocal(input) {
|
|
162
171
|
return store.record({ ...input, instanceId: deps.instanceId });
|