@llblab/pi-kit 0.6.0 → 0.7.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/CHANGELOG.md +4 -0
- package/README.md +4 -4
- package/node_modules/@llblab/pi-actors/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-actors/CHANGELOG.md +6 -0
- package/node_modules/@llblab/pi-actors/README.md +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.d.ts +3 -0
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.js +14 -1
- package/node_modules/@llblab/pi-actors/dist/lib/command-templates.js +45 -3
- package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.js +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/observability.d.ts +16 -3
- package/node_modules/@llblab/pi-actors/dist/lib/observability.js +92 -7
- package/node_modules/@llblab/pi-actors/dist/lib/pi.d.ts +0 -1
- package/node_modules/@llblab/pi-actors/dist/lib/pi.js +15 -24
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery-lineage.d.ts +17 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery-lineage.js +44 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.d.ts +4 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.js +102 -4
- package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.js +58 -39
- package/node_modules/@llblab/pi-actors/dist/lib/runtime.js +14 -6
- package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +1 -1
- package/node_modules/@llblab/pi-actors/docs/async-runs.md +1 -1
- package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +18 -23
- package/node_modules/@llblab/pi-actors/lib/async-runs.ts +18 -1
- package/node_modules/@llblab/pi-actors/lib/command-templates.ts +41 -3
- package/node_modules/@llblab/pi-actors/lib/extension-runtime.ts +1 -1
- package/node_modules/@llblab/pi-actors/lib/observability.ts +119 -5
- package/node_modules/@llblab/pi-actors/lib/pi.ts +15 -28
- package/node_modules/@llblab/pi-actors/lib/run-delivery-lineage.ts +68 -0
- package/node_modules/@llblab/pi-actors/lib/run-delivery.ts +120 -4
- package/node_modules/@llblab/pi-actors/lib/run-ui-runtime.ts +69 -44
- package/node_modules/@llblab/pi-actors/lib/runtime.ts +17 -6
- package/node_modules/@llblab/pi-actors/package.json +1 -1
- package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +1 -1
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +33 -12
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +125 -2
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +87 -45
- package/node_modules/@llblab/pi-state-flow/README.md +203 -107
- package/node_modules/@llblab/pi-state-flow/docs/README.md +4 -0
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +188 -0
- package/node_modules/@llblab/pi-state-flow/docs/temporal-acceptance.md +42 -0
- package/node_modules/@llblab/pi-state-flow/index.ts +164 -2
- package/node_modules/@llblab/pi-state-flow/lib/acquisition.ts +138 -0
- package/node_modules/@llblab/pi-state-flow/lib/artifact.ts +273 -0
- package/node_modules/@llblab/pi-state-flow/lib/config.ts +48 -0
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +18 -5
- package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +268 -0
- package/node_modules/@llblab/pi-state-flow/lib/discovery.ts +117 -0
- package/node_modules/@llblab/pi-state-flow/lib/durable.ts +562 -0
- package/node_modules/@llblab/pi-state-flow/lib/episode.ts +24 -12
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +606 -70
- package/node_modules/@llblab/pi-state-flow/lib/git.ts +666 -0
- package/node_modules/@llblab/pi-state-flow/lib/history.ts +95 -0
- package/node_modules/@llblab/pi-state-flow/lib/json.ts +24 -0
- package/node_modules/@llblab/pi-state-flow/lib/maintenance.ts +141 -0
- package/node_modules/@llblab/pi-state-flow/lib/memory.ts +52 -0
- package/node_modules/@llblab/pi-state-flow/lib/migration.ts +88 -0
- package/node_modules/@llblab/pi-state-flow/lib/publication.ts +296 -0
- package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +23 -7
- package/node_modules/@llblab/pi-state-flow/lib/rehydration.ts +79 -0
- package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +264 -0
- package/node_modules/@llblab/pi-state-flow/lib/session.ts +6 -0
- package/node_modules/@llblab/pi-state-flow/lib/skills.ts +99 -7
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +305 -48
- package/node_modules/@llblab/pi-state-flow/lib/state.ts +74 -7
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +125 -6
- package/node_modules/@llblab/pi-state-flow/lib/storage.ts +196 -0
- package/node_modules/@llblab/pi-state-flow/lib/temporal.ts +233 -0
- package/node_modules/@llblab/pi-state-flow/lib/terminal.ts +70 -24
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +254 -29
- package/node_modules/@llblab/pi-state-flow/package.json +8 -2
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +128 -0
- package/node_modules/@llblab/pi-telegram/AGENTS.md +13 -8
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +20 -3
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +13 -0
- package/node_modules/@llblab/pi-telegram/README.md +12 -8
- package/node_modules/@llblab/pi-telegram/docs/README.md +1 -0
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +220 -18
- package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +70 -19
- package/node_modules/@llblab/pi-telegram/docs/outbound.md +6 -6
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +12 -5
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +3 -1
- package/node_modules/@llblab/pi-telegram/index.ts +4 -1418
- package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +6 -3
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +28 -1
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +600 -135
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +962 -55
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +350 -26
- package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +544 -0
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +234 -11
- package/node_modules/@llblab/pi-telegram/lib/config.ts +177 -24
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +1792 -0
- package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +20 -2
- package/node_modules/@llblab/pi-telegram/lib/journal.ts +2184 -126
- package/node_modules/@llblab/pi-telegram/lib/locks.ts +38 -1
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +152 -13
- package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +51 -10
- package/node_modules/@llblab/pi-telegram/lib/paths.ts +29 -0
- package/node_modules/@llblab/pi-telegram/lib/polling.ts +85 -17
- package/node_modules/@llblab/pi-telegram/lib/prompts.ts +5 -2
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +52 -18
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +2 -2
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +305 -112
- package/node_modules/@llblab/pi-telegram/lib/status.ts +10 -0
- package/node_modules/@llblab/pi-telegram/lib/sync.ts +308 -39
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +279 -4
- package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +664 -0
- package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +226 -0
- package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +118 -0
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +1686 -129
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +1319 -97
- package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +1643 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +968 -0
- package/node_modules/@llblab/pi-telegram/lib/workspace-slots.ts +84 -0
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/screenshot.png +0 -0
- package/node_modules/@llblab/pi-telegram/scripts/measure-bus.mjs +83 -0
- package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +101 -0
- package/node_modules/@llblab/{skills → pi-telegram/skills}/show-me/SKILL.md +28 -6
- package/node_modules/@llblab/pi-telegram/skills/show-me/references/telegram-surfaces.md +43 -0
- package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/delivery-and-threads.md +1 -1
- package/node_modules/@llblab/skills/package.json +2 -3
- package/package.json +6 -5
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
pairTelegramUserIfNeeded,
|
|
9
|
+
type TelegramConfigStore,
|
|
9
10
|
TELEGRAM_DEFAULT_PROFILE_NAME,
|
|
10
11
|
} from "./config.ts";
|
|
11
12
|
import type { ExtensionAPI, ExtensionCommandContext } from "./pi.ts";
|
|
@@ -170,6 +171,7 @@ export const TELEGRAM_COMMAND_EMOJI = {
|
|
|
170
171
|
continue: "▶️",
|
|
171
172
|
abort: "⏹️",
|
|
172
173
|
stop: "🟥",
|
|
174
|
+
name: "🏷️",
|
|
173
175
|
} as const;
|
|
174
176
|
|
|
175
177
|
export type TelegramCommandEmojiName = keyof typeof TELEGRAM_COMMAND_EMOJI;
|
|
@@ -186,6 +188,10 @@ export function formatTelegramCommandEmojiPrefix(
|
|
|
186
188
|
return `${getTelegramCommandEmoji(command)} `;
|
|
187
189
|
}
|
|
188
190
|
|
|
191
|
+
export function formatTelegramPiCommandHtml(command: string): string {
|
|
192
|
+
return `<code>${escapeHtml(command)}</code>`;
|
|
193
|
+
}
|
|
194
|
+
|
|
189
195
|
export function formatTelegramInformationHeading(
|
|
190
196
|
emoji: string,
|
|
191
197
|
text: string,
|
|
@@ -193,6 +199,37 @@ export function formatTelegramInformationHeading(
|
|
|
193
199
|
return `<b>${escapeHtml(emoji)} ${escapeHtml(text)}</b>`;
|
|
194
200
|
}
|
|
195
201
|
|
|
202
|
+
export function formatTelegramInvalidInstanceName(
|
|
203
|
+
validationError: string,
|
|
204
|
+
): string {
|
|
205
|
+
const details = validationError.replace(
|
|
206
|
+
/^Invalid Telegram (?:instance name|Thread display name):\s*/,
|
|
207
|
+
"",
|
|
208
|
+
);
|
|
209
|
+
const items = details
|
|
210
|
+
.split(/;\s+|(?<=\.)\s+(?=[A-Z])/)
|
|
211
|
+
.map((item) => item.trim())
|
|
212
|
+
.filter(Boolean)
|
|
213
|
+
.map((item) => /[.!?]$/.test(item) ? item : `${item}.`)
|
|
214
|
+
.map((item) => item[0]!.toUpperCase() + item.slice(1));
|
|
215
|
+
return [
|
|
216
|
+
"<b>⚠️ Invalid Thread Display Name:</b>\n",
|
|
217
|
+
...items.map((item) => `• ${escapeHtml(item)}`),
|
|
218
|
+
].join("\n");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function formatTelegramThreadDisplayNameSavedHeading(
|
|
222
|
+
name: string,
|
|
223
|
+
): string {
|
|
224
|
+
return `<b>✅ Thread display name saved as <i>${escapeHtml(name)}</i>.</b>`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function formatTelegramAutomaticThreadDisplayNameRestoredHeading(
|
|
228
|
+
name: string,
|
|
229
|
+
): string {
|
|
230
|
+
return `<b>✅ Automatic Thread display name restored as <i>${escapeHtml(name)}</i>.</b>`;
|
|
231
|
+
}
|
|
232
|
+
|
|
196
233
|
export const TELEGRAM_COMPACTION_STARTED_TEXT =
|
|
197
234
|
formatTelegramInformationHeading(
|
|
198
235
|
getTelegramCommandEmoji("compact"),
|
|
@@ -221,6 +258,13 @@ export const TELEGRAM_BUILTIN_BOT_COMMANDS: readonly TelegramBotCommandDefinitio
|
|
|
221
258
|
"Open menu / Pair bridge",
|
|
222
259
|
),
|
|
223
260
|
},
|
|
261
|
+
{
|
|
262
|
+
command: "name",
|
|
263
|
+
description: formatTelegramBotCommandDescription(
|
|
264
|
+
"name",
|
|
265
|
+
"Rename this thread",
|
|
266
|
+
),
|
|
267
|
+
},
|
|
224
268
|
{
|
|
225
269
|
command: "compact",
|
|
226
270
|
description: formatTelegramBotCommandDescription(
|
|
@@ -319,6 +363,7 @@ export function createTelegramBotCommandRegistrar(
|
|
|
319
363
|
export interface TelegramBridgeCommandStartPollingOptions {
|
|
320
364
|
force?: boolean;
|
|
321
365
|
forceFreshLeaderThread?: boolean;
|
|
366
|
+
requestedThreadName?: string;
|
|
322
367
|
}
|
|
323
368
|
|
|
324
369
|
export interface TelegramBridgeCommandStartPollingResult {
|
|
@@ -358,15 +403,76 @@ export interface TelegramBridgeCommandRegistrationDeps {
|
|
|
358
403
|
ctx: ExtensionCommandContext,
|
|
359
404
|
profileName: string,
|
|
360
405
|
) => Promise<boolean>;
|
|
406
|
+
validateThreadName?: (threadName: string) => string | undefined;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export type TelegramThreadDisplayNameRenamePort = (
|
|
410
|
+
target: { chatId: number; threadId?: number },
|
|
411
|
+
threadName: string,
|
|
412
|
+
) => Promise<{ ok: boolean; threadName?: string; message?: string }>;
|
|
413
|
+
|
|
414
|
+
export type TelegramThreadDisplayNameResetPort = (
|
|
415
|
+
target: { chatId: number; threadId?: number },
|
|
416
|
+
) => Promise<{
|
|
417
|
+
ok: boolean;
|
|
418
|
+
threadName?: string;
|
|
419
|
+
message?: string;
|
|
420
|
+
}>;
|
|
421
|
+
|
|
422
|
+
export function createTelegramThreadDisplayNameResetBinding(): {
|
|
423
|
+
bind: (reset: TelegramThreadDisplayNameResetPort) => void;
|
|
424
|
+
reset: TelegramThreadDisplayNameResetPort;
|
|
425
|
+
} {
|
|
426
|
+
let current: TelegramThreadDisplayNameResetPort | undefined;
|
|
427
|
+
return {
|
|
428
|
+
bind(reset) { current = reset; },
|
|
429
|
+
async reset(target) {
|
|
430
|
+
return current
|
|
431
|
+
? current(target)
|
|
432
|
+
: { ok: false, message: "Thread display name reset is unavailable." };
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export function createTelegramThreadDisplayNameRenameBinding(): {
|
|
438
|
+
bind: (rename: TelegramThreadDisplayNameRenamePort) => void;
|
|
439
|
+
rename: TelegramThreadDisplayNameRenamePort;
|
|
440
|
+
} {
|
|
441
|
+
let current: TelegramThreadDisplayNameRenamePort | undefined;
|
|
442
|
+
return {
|
|
443
|
+
bind(rename) {
|
|
444
|
+
current = rename;
|
|
445
|
+
},
|
|
446
|
+
async rename(target, threadName) {
|
|
447
|
+
if (!current) {
|
|
448
|
+
return {
|
|
449
|
+
ok: false,
|
|
450
|
+
message: "Thread display naming is unavailable.",
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
return current(target, threadName);
|
|
454
|
+
},
|
|
455
|
+
};
|
|
361
456
|
}
|
|
362
457
|
|
|
363
458
|
function parseTelegramProfileArg(args: string): string | undefined {
|
|
364
459
|
const word = args.trim().split(/\s+/)[0];
|
|
365
460
|
if (!word || word.length === 0) return undefined;
|
|
366
|
-
if (word.startsWith("-")) return undefined;
|
|
461
|
+
if (word.startsWith("-") || /^as=/i.test(word)) return undefined;
|
|
367
462
|
return word === TELEGRAM_DEFAULT_PROFILE_NAME ? undefined : word;
|
|
368
463
|
}
|
|
369
464
|
|
|
465
|
+
export function parseTelegramRequestedThreadName(
|
|
466
|
+
args: string,
|
|
467
|
+
): string | undefined {
|
|
468
|
+
const token = args
|
|
469
|
+
.trim()
|
|
470
|
+
.split(/\s+/)
|
|
471
|
+
.find((word) => /^as=/i.test(word));
|
|
472
|
+
const value = token?.slice(3).trim();
|
|
473
|
+
return value || undefined;
|
|
474
|
+
}
|
|
475
|
+
|
|
370
476
|
function formatTelegramTakeoverTitle(ctx: ExtensionCommandContext): string {
|
|
371
477
|
return ctx.ui.theme.fg("accent", "pi-telegram");
|
|
372
478
|
}
|
|
@@ -403,9 +509,28 @@ export function registerTelegramBridgeCommands(
|
|
|
403
509
|
},
|
|
404
510
|
});
|
|
405
511
|
pi.registerCommand("telegram-connect", {
|
|
406
|
-
description:
|
|
512
|
+
description:
|
|
513
|
+
"Start the Telegram bridge. Use /telegram-connect <profile> and optional as=Name for a fresh Workspace Thread.",
|
|
407
514
|
handler: async (args, ctx) => {
|
|
408
515
|
const profileName = parseTelegramProfileArg(args);
|
|
516
|
+
const requestedNameTokens = args
|
|
517
|
+
.trim()
|
|
518
|
+
.split(/\s+/)
|
|
519
|
+
.filter((word) => /^as=/i.test(word));
|
|
520
|
+
const requestedThreadName = parseTelegramRequestedThreadName(args);
|
|
521
|
+
const requestedNameError =
|
|
522
|
+
requestedNameTokens.length > 1
|
|
523
|
+
? "Specify at most one as=Name Workspace Thread name."
|
|
524
|
+
: requestedNameTokens.length === 1 && !requestedThreadName
|
|
525
|
+
? "Usage: /telegram-connect [profile] as=Flightprice"
|
|
526
|
+
: requestedThreadName
|
|
527
|
+
? deps.validateThreadName?.(requestedThreadName)
|
|
528
|
+
: undefined;
|
|
529
|
+
if (requestedNameError) {
|
|
530
|
+
ctx.ui.notify(requestedNameError, "warning");
|
|
531
|
+
deps.updateStatus(ctx);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
409
534
|
if (profileName && deps.activateProfileConfig) {
|
|
410
535
|
const ok = await deps.activateProfileConfig(ctx, profileName);
|
|
411
536
|
if (!ok) {
|
|
@@ -466,6 +591,7 @@ export function registerTelegramBridgeCommands(
|
|
|
466
591
|
};
|
|
467
592
|
let result = await startWithRecovery({
|
|
468
593
|
forceFreshLeaderThread: true,
|
|
594
|
+
...(requestedThreadName ? { requestedThreadName } : {}),
|
|
469
595
|
});
|
|
470
596
|
if (result && !result.ok && result.canTakeover) {
|
|
471
597
|
const confirmed = await ctx.ui.confirm(
|
|
@@ -480,6 +606,7 @@ export function registerTelegramBridgeCommands(
|
|
|
480
606
|
result = await startWithRecovery({
|
|
481
607
|
force: true,
|
|
482
608
|
forceFreshLeaderThread: true,
|
|
609
|
+
...(requestedThreadName ? { requestedThreadName } : {}),
|
|
483
610
|
});
|
|
484
611
|
}
|
|
485
612
|
if (result?.message) {
|
|
@@ -527,6 +654,7 @@ export function registerTelegramBridgeCommands(
|
|
|
527
654
|
|
|
528
655
|
export const TELEGRAM_RESERVED_COMMAND_NAMES = [
|
|
529
656
|
"stop",
|
|
657
|
+
"name",
|
|
530
658
|
"abort",
|
|
531
659
|
"next",
|
|
532
660
|
"continue",
|
|
@@ -559,6 +687,7 @@ export function isTelegramReservedCommandName(
|
|
|
559
687
|
export type TelegramCommandAction =
|
|
560
688
|
| { kind: "ignore"; executionMode: "ignored" }
|
|
561
689
|
| { kind: "stop"; executionMode: "immediate" }
|
|
690
|
+
| { kind: "name"; executionMode: "immediate" }
|
|
562
691
|
| { kind: "abort"; executionMode: "immediate" }
|
|
563
692
|
| { kind: "next"; executionMode: "immediate" }
|
|
564
693
|
| { kind: "continue"; executionMode: "immediate" }
|
|
@@ -578,6 +707,7 @@ export type TelegramCommandExecutionMode = "ignored" | "immediate";
|
|
|
578
707
|
|
|
579
708
|
export interface TelegramCommandActionDeps<TMessage, TContext> {
|
|
580
709
|
handleStop: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
710
|
+
handleName: (message: TMessage, ctx: TContext, name: string) => Promise<void>;
|
|
581
711
|
handleAbort: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
582
712
|
handleNext: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
583
713
|
handleContinue: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
@@ -971,10 +1101,15 @@ export function createTelegramCommandTargetRuntime<
|
|
|
971
1101
|
export interface TelegramCommandOrPromptRuntimeDeps<TMessage, TContext> {
|
|
972
1102
|
extractRawText: (messages: TMessage[]) => string;
|
|
973
1103
|
shouldIgnoreMessages?: (messages: TMessage[]) => boolean;
|
|
1104
|
+
consumeThreadNameInput?: (
|
|
1105
|
+
messages: TMessage[],
|
|
1106
|
+
ctx: TContext,
|
|
1107
|
+
) => Promise<boolean>;
|
|
974
1108
|
handleCommand: (
|
|
975
1109
|
commandName: string | undefined,
|
|
976
1110
|
message: TMessage,
|
|
977
1111
|
ctx: TContext,
|
|
1112
|
+
commandArgs?: string,
|
|
978
1113
|
) => Promise<boolean>;
|
|
979
1114
|
executeExtensionCommand?: (
|
|
980
1115
|
command: ParsedTelegramCommand,
|
|
@@ -1039,11 +1174,17 @@ export interface TelegramCommandRuntimeDeps<
|
|
|
1039
1174
|
openThinkingMenu: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
1040
1175
|
openQueueMenu: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
1041
1176
|
openSettingsMenu?: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
1177
|
+
validateThreadName?: (threadName: string) => string | undefined;
|
|
1178
|
+
renameCurrentThread?: TelegramThreadDisplayNameRenamePort;
|
|
1179
|
+
resetCurrentThreadName?: TelegramThreadDisplayNameResetPort;
|
|
1180
|
+
openThreadNameDialog?: (
|
|
1181
|
+
message: TMessage,
|
|
1182
|
+
ctx: TContext,
|
|
1183
|
+
) => Promise<void>;
|
|
1042
1184
|
getAllowedUserId: () => number | undefined;
|
|
1043
|
-
|
|
1185
|
+
persistAllowedUserId: TelegramConfigStore["persistAllowedUserId"];
|
|
1044
1186
|
registerBotCommands: () => Promise<void>;
|
|
1045
1187
|
getPromptTemplateCommands?: () => readonly TelegramPromptTemplateMenuCommand[];
|
|
1046
|
-
persistConfig: () => Promise<void>;
|
|
1047
1188
|
sendTextReply: (
|
|
1048
1189
|
message: TMessage,
|
|
1049
1190
|
text: string,
|
|
@@ -1060,6 +1201,7 @@ export const TELEGRAM_APP_MENU_INTRO_HTML = [
|
|
|
1060
1201
|
"<b>Pi Telegram</b>",
|
|
1061
1202
|
"",
|
|
1062
1203
|
`${formatTelegramCommandEmojiPrefix("start")}/start — Open menu / Pair bridge`,
|
|
1204
|
+
`${formatTelegramCommandEmojiPrefix("name")}/name Name — Rename this thread`,
|
|
1063
1205
|
`${formatTelegramCommandEmojiPrefix("compact")}/compact — Compact current session`,
|
|
1064
1206
|
`${formatTelegramCommandEmojiPrefix("next")}/next — Force next turn`,
|
|
1065
1207
|
`${formatTelegramCommandEmojiPrefix("continue")}/continue — Queue continue prompt`,
|
|
@@ -1100,6 +1242,7 @@ function buildTelegramAppMenuIntroHtml(): string {
|
|
|
1100
1242
|
"<b>Pi Telegram</b>",
|
|
1101
1243
|
"",
|
|
1102
1244
|
`${formatTelegramCommandEmojiPrefix("start")}/start — Open menu / Pair bridge`,
|
|
1245
|
+
`${formatTelegramCommandEmojiPrefix("name")}/name Name — Rename this thread`,
|
|
1103
1246
|
`${formatTelegramCommandEmojiPrefix("compact")}/compact — Compact current session`,
|
|
1104
1247
|
...extensionLines,
|
|
1105
1248
|
`${formatTelegramCommandEmojiPrefix("next")}/next — Force next turn`,
|
|
@@ -1168,6 +1311,7 @@ export function parseTelegramCommand(
|
|
|
1168
1311
|
|
|
1169
1312
|
export const TELEGRAM_COMMAND_ACTIONS = {
|
|
1170
1313
|
stop: { kind: "stop", executionMode: "immediate" },
|
|
1314
|
+
name: { kind: "name", executionMode: "immediate" },
|
|
1171
1315
|
abort: { kind: "abort", executionMode: "immediate" },
|
|
1172
1316
|
next: { kind: "next", executionMode: "immediate" },
|
|
1173
1317
|
continue: { kind: "continue", executionMode: "immediate" },
|
|
@@ -1294,7 +1438,7 @@ export async function handleTelegramNextCommand(deps: {
|
|
|
1294
1438
|
deps.updateStatus();
|
|
1295
1439
|
const notice = formatTelegramInformationHeading(
|
|
1296
1440
|
"⏩",
|
|
1297
|
-
"
|
|
1441
|
+
"Dispatching next queued turn.",
|
|
1298
1442
|
);
|
|
1299
1443
|
if (activeTurnReply) {
|
|
1300
1444
|
await activeTurnReply(notice, { parseMode: "HTML" });
|
|
@@ -1525,6 +1669,7 @@ export async function executeTelegramCommandAction<TMessage, TContext>(
|
|
|
1525
1669
|
message: TMessage,
|
|
1526
1670
|
ctx: TContext,
|
|
1527
1671
|
deps: TelegramCommandActionDeps<TMessage, TContext>,
|
|
1672
|
+
commandArgs = "",
|
|
1528
1673
|
): Promise<boolean> {
|
|
1529
1674
|
switch (action.kind) {
|
|
1530
1675
|
case "ignore":
|
|
@@ -1532,6 +1677,9 @@ export async function executeTelegramCommandAction<TMessage, TContext>(
|
|
|
1532
1677
|
case "stop":
|
|
1533
1678
|
await deps.handleStop(message, ctx);
|
|
1534
1679
|
return true;
|
|
1680
|
+
case "name":
|
|
1681
|
+
await deps.handleName(message, ctx, commandArgs);
|
|
1682
|
+
return true;
|
|
1535
1683
|
case "abort":
|
|
1536
1684
|
await deps.handleAbort(message, ctx);
|
|
1537
1685
|
return true;
|
|
@@ -1595,6 +1743,7 @@ export function createTelegramCommandHandlerTargetRuntime<
|
|
|
1595
1743
|
commandName: string | undefined,
|
|
1596
1744
|
message: TMessage,
|
|
1597
1745
|
ctx: TContext,
|
|
1746
|
+
commandArgs?: string,
|
|
1598
1747
|
) => Promise<boolean> {
|
|
1599
1748
|
const commandTargetRuntime = createTelegramCommandTargetQueueRuntime<
|
|
1600
1749
|
TMessage,
|
|
@@ -1643,11 +1792,14 @@ export function createTelegramCommandHandlerTargetRuntime<
|
|
|
1643
1792
|
openSettingsMenu: commandTargetRuntime.openSettingsMenu,
|
|
1644
1793
|
handleForumBootstrap: deps.handleForumBootstrap,
|
|
1645
1794
|
getAllowedUserId: deps.getAllowedUserId,
|
|
1646
|
-
|
|
1795
|
+
persistAllowedUserId: deps.persistAllowedUserId,
|
|
1647
1796
|
registerBotCommands: createTelegramBotCommandRegistrar({
|
|
1648
1797
|
setMyCommands: deps.setMyCommands,
|
|
1649
1798
|
}),
|
|
1650
|
-
|
|
1799
|
+
validateThreadName: deps.validateThreadName,
|
|
1800
|
+
renameCurrentThread: deps.renameCurrentThread,
|
|
1801
|
+
resetCurrentThreadName: deps.resetCurrentThreadName,
|
|
1802
|
+
openThreadNameDialog: deps.openThreadNameDialog,
|
|
1651
1803
|
sendTextReply: commandTargetRuntime.sendTextReply,
|
|
1652
1804
|
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
1653
1805
|
});
|
|
@@ -1661,8 +1813,9 @@ export function createTelegramCommandHandler<
|
|
|
1661
1813
|
commandName: string | undefined,
|
|
1662
1814
|
message: TMessage,
|
|
1663
1815
|
ctx: TContext,
|
|
1816
|
+
commandArgs?: string,
|
|
1664
1817
|
): Promise<boolean> => {
|
|
1665
|
-
return handleTelegramCommandRuntime(commandName, message, ctx, deps);
|
|
1818
|
+
return handleTelegramCommandRuntime(commandName, message, ctx, deps, commandArgs);
|
|
1666
1819
|
};
|
|
1667
1820
|
}
|
|
1668
1821
|
|
|
@@ -1678,11 +1831,16 @@ export function createTelegramCommandOrPromptRuntime<TMessage, TContext>(
|
|
|
1678
1831
|
if (!firstMessage) return;
|
|
1679
1832
|
if (deps.shouldIgnoreMessages?.(messages)) return;
|
|
1680
1833
|
deps.assertExecutionCurrent?.(firstMessage);
|
|
1834
|
+
if (await deps.consumeThreadNameInput?.(messages, ctx)) {
|
|
1835
|
+
deps.assertExecutionCurrent?.(firstMessage);
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1681
1838
|
const command = parseTelegramCommand(deps.extractRawText(messages));
|
|
1682
1839
|
const handled = await deps.handleCommand(
|
|
1683
1840
|
command?.name,
|
|
1684
1841
|
firstMessage,
|
|
1685
1842
|
ctx,
|
|
1843
|
+
command?.args,
|
|
1686
1844
|
);
|
|
1687
1845
|
deps.assertExecutionCurrent?.(firstMessage);
|
|
1688
1846
|
if (handled) return;
|
|
@@ -1755,6 +1913,7 @@ async function handleTelegramCommandRuntime<
|
|
|
1755
1913
|
message: TMessage,
|
|
1756
1914
|
ctx: TContext,
|
|
1757
1915
|
deps: TelegramCommandRuntimeDeps<TMessage, TContext>,
|
|
1916
|
+
commandArgs = "",
|
|
1758
1917
|
): Promise<boolean> {
|
|
1759
1918
|
const assertExecutionCurrentFor = (nextMessage: TMessage) => (): void =>
|
|
1760
1919
|
deps.assertExecutionCurrent?.(nextMessage);
|
|
@@ -1784,6 +1943,69 @@ async function handleTelegramCommandRuntime<
|
|
|
1784
1943
|
sendTextReply: sendReplyFor(nextMessage),
|
|
1785
1944
|
});
|
|
1786
1945
|
},
|
|
1946
|
+
handleName: async (nextMessage, _commandCtx, requestedName) => {
|
|
1947
|
+
const threadName = requestedName.trim();
|
|
1948
|
+
if (!threadName) {
|
|
1949
|
+
if (deps.openThreadNameDialog) {
|
|
1950
|
+
await deps.openThreadNameDialog(nextMessage, _commandCtx);
|
|
1951
|
+
} else {
|
|
1952
|
+
await sendReplyFor(nextMessage)(
|
|
1953
|
+
formatTelegramInformationHeading("🏷️", "Usage: /name Navigator"),
|
|
1954
|
+
{ parseMode: "HTML" },
|
|
1955
|
+
);
|
|
1956
|
+
}
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
if (/^[A-Z]$/.test(threadName) && deps.resetCurrentThreadName) {
|
|
1960
|
+
const result = await deps.resetCurrentThreadName(
|
|
1961
|
+
getTelegramCommandMessageTarget(nextMessage),
|
|
1962
|
+
);
|
|
1963
|
+
await sendReplyFor(nextMessage)(
|
|
1964
|
+
result.ok && !result.message
|
|
1965
|
+
? formatTelegramAutomaticThreadDisplayNameRestoredHeading(
|
|
1966
|
+
result.threadName ?? threadName,
|
|
1967
|
+
)
|
|
1968
|
+
: formatTelegramInformationHeading(
|
|
1969
|
+
result.ok ? "✅" : "⚠️",
|
|
1970
|
+
result.message ?? "Thread display name reset failed.",
|
|
1971
|
+
),
|
|
1972
|
+
{ parseMode: "HTML" },
|
|
1973
|
+
);
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
const validationError = deps.validateThreadName?.(threadName);
|
|
1977
|
+
if (validationError) {
|
|
1978
|
+
await sendReplyFor(nextMessage)(
|
|
1979
|
+
formatTelegramInvalidInstanceName(validationError),
|
|
1980
|
+
{ parseMode: "HTML" },
|
|
1981
|
+
);
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
if (!deps.renameCurrentThread) {
|
|
1985
|
+
await sendReplyFor(nextMessage)(
|
|
1986
|
+
formatTelegramInformationHeading("🚫", "Thread display naming is unavailable."),
|
|
1987
|
+
{ parseMode: "HTML" },
|
|
1988
|
+
);
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
deps.assertExecutionCurrent?.(nextMessage);
|
|
1992
|
+
const result = await deps.renameCurrentThread(
|
|
1993
|
+
getTelegramCommandMessageTarget(nextMessage),
|
|
1994
|
+
threadName,
|
|
1995
|
+
);
|
|
1996
|
+
deps.assertExecutionCurrent?.(nextMessage);
|
|
1997
|
+
await sendReplyFor(nextMessage)(
|
|
1998
|
+
result.ok && !result.message
|
|
1999
|
+
? formatTelegramThreadDisplayNameSavedHeading(
|
|
2000
|
+
result.threadName ?? threadName,
|
|
2001
|
+
)
|
|
2002
|
+
: formatTelegramInformationHeading(
|
|
2003
|
+
result.ok ? "✅" : "⚠️",
|
|
2004
|
+
result.message ?? "Thread display name update failed.",
|
|
2005
|
+
),
|
|
2006
|
+
{ parseMode: "HTML" },
|
|
2007
|
+
);
|
|
2008
|
+
},
|
|
1787
2009
|
handleAbort: async (nextMessage, commandCtx) => {
|
|
1788
2010
|
await handleTelegramAbortCommand({
|
|
1789
2011
|
hasAbortHandler: deps.hasAbortHandler,
|
|
@@ -1916,14 +2138,14 @@ async function handleTelegramCommandRuntime<
|
|
|
1916
2138
|
nextMessage.from?.id !== undefined &&
|
|
1917
2139
|
canPairTelegramUserFromCommandMessage(nextMessage)
|
|
1918
2140
|
) {
|
|
1919
|
-
await pairTelegramUserIfNeeded(nextMessage.from.id, {
|
|
2141
|
+
const allowed = await pairTelegramUserIfNeeded(nextMessage.from.id, {
|
|
1920
2142
|
allowedUserId: deps.getAllowedUserId(),
|
|
1921
2143
|
ctx: undefined,
|
|
1922
|
-
|
|
1923
|
-
persistConfig: deps.persistConfig,
|
|
2144
|
+
persistAllowedUserId: deps.persistAllowedUserId,
|
|
1924
2145
|
updateStatus: updateStatusFor(commandCtx),
|
|
1925
2146
|
assertExecutionCurrent: assertExecutionCurrentFor(nextMessage),
|
|
1926
2147
|
});
|
|
2148
|
+
if (!allowed) return;
|
|
1927
2149
|
}
|
|
1928
2150
|
const isContextActive = () =>
|
|
1929
2151
|
deps.isContextActive?.(commandCtx) !== false;
|
|
@@ -1959,5 +2181,6 @@ async function handleTelegramCommandRuntime<
|
|
|
1959
2181
|
);
|
|
1960
2182
|
},
|
|
1961
2183
|
},
|
|
2184
|
+
commandArgs,
|
|
1962
2185
|
);
|
|
1963
2186
|
}
|