@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
|
@@ -19,6 +19,7 @@ import * as Queue from "./queue.ts";
|
|
|
19
19
|
import type { TelegramBridgeRuntime } from "./runtime.ts";
|
|
20
20
|
import type { TelegramSectionRegistry } from "./sections.ts";
|
|
21
21
|
import * as TextGroups from "./text-groups.ts";
|
|
22
|
+
import * as ThreadNaming from "./thread-naming.ts";
|
|
22
23
|
import * as ThreadReconciler from "./thread-reconciler.ts";
|
|
23
24
|
import type {
|
|
24
25
|
TelegramInstanceThreadIdentityCandidate,
|
|
@@ -175,6 +176,8 @@ function escapeHtml(text: string): string {
|
|
|
175
176
|
const TELEGRAM_UNBOUND_REROUTE_CALLBACK_PREFIX = "reroute:";
|
|
176
177
|
const TELEGRAM_UNBOUND_REROUTE_RESTORE_MENU_CALLBACK_PREFIX = "rerouterestore:";
|
|
177
178
|
const TELEGRAM_UNBOUND_REROUTE_NEW_SLOT_CALLBACK_PREFIX = "reroutenew:";
|
|
179
|
+
const TELEGRAM_SLOT_CAPACITY_MESSAGE =
|
|
180
|
+
"No Telegram instance slot is available. Automatic reclamation is disabled for safety.";
|
|
178
181
|
|
|
179
182
|
function formatTelegramUnboundRerouteCallbackData(
|
|
180
183
|
rerouteId: string,
|
|
@@ -218,20 +221,9 @@ function parseTelegramUnboundRerouteCallbackData(
|
|
|
218
221
|
|
|
219
222
|
function getTelegramThreadRecordLabel(
|
|
220
223
|
record: Threads.TelegramTopicTargetRecord,
|
|
224
|
+
getDisplayTitle?: Threads.TelegramCurrentThreadAssembly["getDisplayTitle"],
|
|
221
225
|
): string {
|
|
222
|
-
return getRestoredThreadName(record, record.slot ?? "");
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function getTelegramRouteThreadButtonLabel(
|
|
226
|
-
record: Threads.TelegramTopicTargetRecord,
|
|
227
|
-
): string {
|
|
228
|
-
return `↪️ ${getTelegramThreadRecordLabel(record)}`;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function getTelegramReplaceThreadButtonLabel(
|
|
232
|
-
record: Threads.TelegramTopicTargetRecord,
|
|
233
|
-
): string {
|
|
234
|
-
return `➡️ ${getTelegramThreadRecordLabel(record)}`;
|
|
226
|
+
return getDisplayTitle?.(record.target) ?? getRestoredThreadName(record, record.slot ?? "");
|
|
235
227
|
}
|
|
236
228
|
|
|
237
229
|
function getNextTelegramSlotPreference(
|
|
@@ -288,13 +280,16 @@ function formatTelegramAllTabMenuChooserText(command: string): string {
|
|
|
288
280
|
function buildTelegramUnboundRerouteChooserMarkup(
|
|
289
281
|
rerouteId: string,
|
|
290
282
|
records: readonly Threads.TelegramTopicTargetRecord[],
|
|
291
|
-
options: {
|
|
283
|
+
options: {
|
|
284
|
+
canRestore: boolean;
|
|
285
|
+
getDisplayTitle?: Threads.TelegramCurrentThreadAssembly["getDisplayTitle"];
|
|
286
|
+
},
|
|
292
287
|
): Menu.TelegramReplyMarkup {
|
|
293
288
|
const activeRecords = records.filter((record) => record.status === "active");
|
|
294
289
|
const canRestoreAnyLiveThread = options.canRestore && activeRecords.length > 0;
|
|
295
290
|
const rows = activeRecords.map((record) => [
|
|
296
291
|
{
|
|
297
|
-
text:
|
|
292
|
+
text: `↪️ ${getTelegramThreadRecordLabel(record, options.getDisplayTitle)}`,
|
|
298
293
|
callback_data: formatTelegramUnboundRerouteCallbackData(
|
|
299
294
|
rerouteId,
|
|
300
295
|
record.target.threadId,
|
|
@@ -320,13 +315,14 @@ function buildTelegramUnboundRerouteChooserMarkup(
|
|
|
320
315
|
function buildTelegramUnboundRerouteRestoreChooserMarkup(
|
|
321
316
|
rerouteId: string,
|
|
322
317
|
records: readonly Threads.TelegramTopicTargetRecord[],
|
|
318
|
+
getDisplayTitle?: Threads.TelegramCurrentThreadAssembly["getDisplayTitle"],
|
|
323
319
|
): Menu.TelegramReplyMarkup {
|
|
324
320
|
return {
|
|
325
321
|
inline_keyboard: records
|
|
326
322
|
.filter((record) => record.status === "active")
|
|
327
323
|
.map((record) => [
|
|
328
324
|
{
|
|
329
|
-
text:
|
|
325
|
+
text: `➡️ ${getTelegramThreadRecordLabel(record, getDisplayTitle)}`,
|
|
330
326
|
callback_data: formatTelegramUnboundRerouteNewSlotCallbackData(
|
|
331
327
|
rerouteId,
|
|
332
328
|
record.target.threadId,
|
|
@@ -527,7 +523,7 @@ export interface TelegramInboundRouteRuntimeDeps<
|
|
|
527
523
|
> {
|
|
528
524
|
configStore: Pick<
|
|
529
525
|
TelegramConfigStore,
|
|
530
|
-
"get" | "getAllowedUserId" | "
|
|
526
|
+
"get" | "getAllowedUserId" | "persistAllowedUserId" | "persist"
|
|
531
527
|
> & { set?: TelegramConfigStore["set"] };
|
|
532
528
|
callApi?: <TResponse>(
|
|
533
529
|
method: string,
|
|
@@ -540,6 +536,7 @@ export interface TelegramInboundRouteRuntimeDeps<
|
|
|
540
536
|
getTargetOwnership?: Updates.TelegramTargetOwnershipLookup;
|
|
541
537
|
recordMessageOwnership?: Updates.TelegramMessageOwnershipRecorder;
|
|
542
538
|
getLiveThreadTargets?: () => Queue.TelegramQueueTarget[];
|
|
539
|
+
getDisplayTitle?: Threads.TelegramCurrentThreadAssembly["getDisplayTitle"];
|
|
543
540
|
getLocalThreadLabelForTarget?: (
|
|
544
541
|
target: Queue.TelegramQueueTarget,
|
|
545
542
|
) => string | undefined;
|
|
@@ -616,6 +613,14 @@ export interface TelegramInboundRouteRuntimeDeps<
|
|
|
616
613
|
) => Promise<false | "new" | "edit">;
|
|
617
614
|
inboundHandlerRuntime: TelegramInboundHandlerRuntime<TContext>;
|
|
618
615
|
threadStore?: Threads.TelegramTopicTargetStore;
|
|
616
|
+
runWorkspaceOperation?: <T>(
|
|
617
|
+
input: {
|
|
618
|
+
operationId: string;
|
|
619
|
+
operationKind: string;
|
|
620
|
+
scopes: readonly [{ kind: "profile" }];
|
|
621
|
+
},
|
|
622
|
+
operation: () => Promise<T>,
|
|
623
|
+
) => Promise<T>;
|
|
619
624
|
updateStatus: (ctx: TContext, error?: string) => void;
|
|
620
625
|
isContextActive?: (ctx: TContext) => boolean;
|
|
621
626
|
dispatchNextQueuedTelegramTurn: (ctx: TContext) => void;
|
|
@@ -661,6 +666,9 @@ export interface TelegramInboundRouteRuntimeDeps<
|
|
|
661
666
|
options?: { parseMode?: "HTML"; target?: Queue.TelegramQueueTarget },
|
|
662
667
|
) => Promise<number | undefined>;
|
|
663
668
|
setMyCommands: Commands.TelegramBotCommandRegistrationDeps["setMyCommands"];
|
|
669
|
+
validateThreadName?: (threadName: string) => string | undefined;
|
|
670
|
+
renameCurrentThread?: Commands.TelegramThreadDisplayNameRenamePort;
|
|
671
|
+
resetCurrentThreadName?: Commands.TelegramThreadDisplayNameResetPort;
|
|
664
672
|
getCommands: () => Parameters<
|
|
665
673
|
typeof PromptTemplates.getTelegramPromptTemplateCommands
|
|
666
674
|
>[0];
|
|
@@ -785,7 +793,8 @@ export function createTelegramInboundRouteRuntime<
|
|
|
785
793
|
const chatId = message.chat.id;
|
|
786
794
|
const threadId = message.message_thread_id;
|
|
787
795
|
if (!threadId) return undefined;
|
|
788
|
-
const localLabel = deps.
|
|
796
|
+
const localLabel = deps.getDisplayTitle?.({ chatId, threadId }) ??
|
|
797
|
+
deps.getLocalThreadLabelForTarget?.({ chatId, threadId });
|
|
789
798
|
if (localLabel) return localLabel;
|
|
790
799
|
if (!deps.threadStore) return undefined;
|
|
791
800
|
const records = deps.threadStore.list();
|
|
@@ -964,6 +973,8 @@ export function createTelegramInboundRouteRuntime<
|
|
|
964
973
|
timer: ReturnType<typeof setTimeout>;
|
|
965
974
|
}
|
|
966
975
|
>();
|
|
976
|
+
const threadNameDialog = ThreadNaming.createTelegramThreadNameDialogRuntime();
|
|
977
|
+
const getThreadNameDialogScope = () => deps.getCurrentInstanceId?.() ?? "local";
|
|
967
978
|
const menuCallbackHandler = Menu.createTelegramMenuCallbackHandlerForContext<
|
|
968
979
|
TCallbackQuery,
|
|
969
980
|
TContext,
|
|
@@ -1328,6 +1339,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1328
1339
|
const replyMarkup = buildTelegramUnboundRerouteRestoreChooserMarkup(
|
|
1329
1340
|
parsed.rerouteId,
|
|
1330
1341
|
activeRecords,
|
|
1342
|
+
deps.getDisplayTitle,
|
|
1331
1343
|
);
|
|
1332
1344
|
if (deps.editInteractiveMessage) {
|
|
1333
1345
|
await deps.editInteractiveMessage(
|
|
@@ -1352,7 +1364,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1352
1364
|
await deps.answerCallbackQuery(query.id, "Choose instance to restore.");
|
|
1353
1365
|
return true;
|
|
1354
1366
|
};
|
|
1355
|
-
const
|
|
1367
|
+
const executeUnboundRerouteCallbackOperation = async (
|
|
1356
1368
|
query: TCallbackQuery,
|
|
1357
1369
|
ctx: TContext,
|
|
1358
1370
|
): Promise<boolean> => {
|
|
@@ -1471,6 +1483,13 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1471
1483
|
currentInstanceId,
|
|
1472
1484
|
);
|
|
1473
1485
|
if (parsed.useNewSlot && !isCurrentLeaderRecord) {
|
|
1486
|
+
if (!record.slot || !/^[A-Z]$/u.test(record.slot)) {
|
|
1487
|
+
await deps.answerCallbackQuery(
|
|
1488
|
+
query.id,
|
|
1489
|
+
"Follower thread slot authority is unavailable.",
|
|
1490
|
+
);
|
|
1491
|
+
return true;
|
|
1492
|
+
}
|
|
1474
1493
|
if (
|
|
1475
1494
|
!sourceTarget ||
|
|
1476
1495
|
!deps.replaceFollowerThreadTarget ||
|
|
@@ -1497,7 +1516,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1497
1516
|
return true;
|
|
1498
1517
|
}
|
|
1499
1518
|
const nowMs = Date.now();
|
|
1500
|
-
const slot = record.slot
|
|
1519
|
+
const slot = record.slot;
|
|
1501
1520
|
const threadName = getRestoredThreadName(record, slot);
|
|
1502
1521
|
assertExecutionCurrent();
|
|
1503
1522
|
deps.threadStore.markStaleByTarget(
|
|
@@ -1640,18 +1659,21 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1640
1659
|
(record.target.chatId !== sourceTarget.chatId ||
|
|
1641
1660
|
record.target.threadId !== sourceTarget.threadId)
|
|
1642
1661
|
) {
|
|
1662
|
+
const slot = deps.threadStore.allocateSlot(
|
|
1663
|
+
leaderProfileKey ?? record.profileKey,
|
|
1664
|
+
getNextTelegramSlotPreference(record.slot),
|
|
1665
|
+
undefined,
|
|
1666
|
+
{ excludeCurrentRecord: true },
|
|
1667
|
+
);
|
|
1668
|
+
if (!slot) {
|
|
1669
|
+
await deps.answerCallbackQuery(query.id, TELEGRAM_SLOT_CAPACITY_MESSAGE);
|
|
1670
|
+
return true;
|
|
1671
|
+
}
|
|
1643
1672
|
deps.threadStore.markStaleByTarget(
|
|
1644
1673
|
record.target,
|
|
1645
1674
|
"deleted",
|
|
1646
1675
|
"Current leader thread was replaced by a new-slot reroute source.",
|
|
1647
1676
|
);
|
|
1648
|
-
const slot =
|
|
1649
|
-
deps.threadStore.allocateSlot(
|
|
1650
|
-
leaderProfileKey ?? record.profileKey,
|
|
1651
|
-
getNextTelegramSlotPreference(record.slot),
|
|
1652
|
-
) ??
|
|
1653
|
-
record.slot ??
|
|
1654
|
-
"?";
|
|
1655
1677
|
const nowMs = Date.now();
|
|
1656
1678
|
const threadName = getRestoredThreadName(record, slot);
|
|
1657
1679
|
deps.threadStore.upsert({
|
|
@@ -1759,6 +1781,23 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1759
1781
|
);
|
|
1760
1782
|
return true;
|
|
1761
1783
|
};
|
|
1784
|
+
const executeUnboundRerouteCallback = (
|
|
1785
|
+
query: TCallbackQuery,
|
|
1786
|
+
ctx: TContext,
|
|
1787
|
+
): Promise<boolean> => {
|
|
1788
|
+
if (!parseTelegramUnboundRerouteCallbackData(query.data) ||
|
|
1789
|
+
!deps.runWorkspaceOperation) {
|
|
1790
|
+
return executeUnboundRerouteCallbackOperation(query, ctx);
|
|
1791
|
+
}
|
|
1792
|
+
return deps.runWorkspaceOperation(
|
|
1793
|
+
{
|
|
1794
|
+
operationId: `workspace-reroute:${query.id}`,
|
|
1795
|
+
operationKind: "workspace.route-unbound-thread",
|
|
1796
|
+
scopes: [{ kind: "profile" }],
|
|
1797
|
+
},
|
|
1798
|
+
() => executeUnboundRerouteCallbackOperation(query, ctx),
|
|
1799
|
+
);
|
|
1800
|
+
};
|
|
1762
1801
|
const handleUnboundRerouteCallback = async (
|
|
1763
1802
|
query: TCallbackQuery,
|
|
1764
1803
|
ctx: TContext,
|
|
@@ -1881,6 +1920,70 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1881
1920
|
assertExecutionCurrent();
|
|
1882
1921
|
if (handled) return;
|
|
1883
1922
|
}
|
|
1923
|
+
if (query.data?.startsWith("thread-name:")) {
|
|
1924
|
+
const chatId = query.message?.chat?.id;
|
|
1925
|
+
const dialogMessageId = query.message?.message_id;
|
|
1926
|
+
if (typeof chatId !== "number" || typeof dialogMessageId !== "number") {
|
|
1927
|
+
await deps.answerCallbackQuery(query.id, "⌛ Rename dialog expired.");
|
|
1928
|
+
return;
|
|
1929
|
+
}
|
|
1930
|
+
const target = typeof query.message?.message_thread_id === "number"
|
|
1931
|
+
? { chatId, threadId: query.message.message_thread_id }
|
|
1932
|
+
: { chatId };
|
|
1933
|
+
const action = query.data.slice("thread-name:".length);
|
|
1934
|
+
if (action !== "reset" && action !== "cancel") {
|
|
1935
|
+
await deps.answerCallbackQuery(query.id, "⌛ Rename dialog expired.");
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
const selected = threadNameDialog.select({
|
|
1939
|
+
scope: getThreadNameDialogScope(),
|
|
1940
|
+
target,
|
|
1941
|
+
dialogMessageId,
|
|
1942
|
+
action,
|
|
1943
|
+
});
|
|
1944
|
+
if (selected.kind === "expired") {
|
|
1945
|
+
await deps.answerCallbackQuery(query.id, "⌛ Rename dialog expired.");
|
|
1946
|
+
return;
|
|
1947
|
+
}
|
|
1948
|
+
if (selected.kind === "cancel") {
|
|
1949
|
+
await deps.editInteractiveMessage?.(
|
|
1950
|
+
chatId,
|
|
1951
|
+
dialogMessageId,
|
|
1952
|
+
"<b>✖ Rename cancelled. Returning to normal agent mode.</b>",
|
|
1953
|
+
"html",
|
|
1954
|
+
{ inline_keyboard: [] },
|
|
1955
|
+
);
|
|
1956
|
+
await deps.answerCallbackQuery(query.id);
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
try {
|
|
1960
|
+
const result = await deps.resetCurrentThreadName?.(target);
|
|
1961
|
+
if (!result?.ok) {
|
|
1962
|
+
throw new Error(result?.message ?? "Thread display name reset is unavailable.");
|
|
1963
|
+
}
|
|
1964
|
+
await deps.editInteractiveMessage?.(
|
|
1965
|
+
chatId,
|
|
1966
|
+
dialogMessageId,
|
|
1967
|
+
result.message
|
|
1968
|
+
? Commands.formatTelegramInformationHeading("✅", result.message)
|
|
1969
|
+
: Commands.formatTelegramAutomaticThreadDisplayNameRestoredHeading(
|
|
1970
|
+
result.threadName ?? "automatic",
|
|
1971
|
+
),
|
|
1972
|
+
"html",
|
|
1973
|
+
{ inline_keyboard: [] },
|
|
1974
|
+
);
|
|
1975
|
+
await deps.answerCallbackQuery(query.id);
|
|
1976
|
+
} catch (error) {
|
|
1977
|
+
threadNameDialog.open({
|
|
1978
|
+
scope: getThreadNameDialogScope(), target, dialogMessageId,
|
|
1979
|
+
});
|
|
1980
|
+
deps.recordRuntimeEvent?.("telegram-command", error, {
|
|
1981
|
+
command: "name", phase: "reset",
|
|
1982
|
+
});
|
|
1983
|
+
await deps.answerCallbackQuery(query.id, "⚠️ Thread name reset failed.");
|
|
1984
|
+
}
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1884
1987
|
const handledByCompact =
|
|
1885
1988
|
await Commands.handleTelegramCompactConfirmationCallback(query, {
|
|
1886
1989
|
ctx,
|
|
@@ -2083,10 +2186,54 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2083
2186
|
},
|
|
2084
2187
|
openSettingsMenu: deps.openSettingsMenu,
|
|
2085
2188
|
getAllowedUserId: deps.configStore.getAllowedUserId,
|
|
2086
|
-
|
|
2189
|
+
persistAllowedUserId: deps.configStore.persistAllowedUserId,
|
|
2087
2190
|
setMyCommands: deps.setMyCommands,
|
|
2191
|
+
validateThreadName: deps.validateThreadName,
|
|
2192
|
+
renameCurrentThread: deps.renameCurrentThread,
|
|
2193
|
+
resetCurrentThreadName: deps.resetCurrentThreadName,
|
|
2194
|
+
openThreadNameDialog: async (message) => {
|
|
2195
|
+
const target = Updates.getTelegramMessageTarget(message);
|
|
2196
|
+
if (!deps.sendInteractiveMessage || !target) {
|
|
2197
|
+
await deps.sendTextReply(
|
|
2198
|
+
message.chat.id,
|
|
2199
|
+
message.message_id,
|
|
2200
|
+
Commands.formatTelegramInformationHeading(
|
|
2201
|
+
"🏷️",
|
|
2202
|
+
"Usage: /name Navigator",
|
|
2203
|
+
),
|
|
2204
|
+
{ parseMode: "HTML", target },
|
|
2205
|
+
);
|
|
2206
|
+
return;
|
|
2207
|
+
}
|
|
2208
|
+
const hasManualName = deps.threadStore?.listWorkspaceBindings().some(
|
|
2209
|
+
(binding) => binding.target.chatId === target.chatId &&
|
|
2210
|
+
binding.target.threadId === target.threadId &&
|
|
2211
|
+
typeof binding.manualThreadName === "string",
|
|
2212
|
+
) ?? false;
|
|
2213
|
+
const instructions = hasManualName
|
|
2214
|
+
? "<b>🏷️ Send a new Thread name using printable ASCII, reset to automatic, or cancel.</b>"
|
|
2215
|
+
: "<b>🏷️ Send a Thread name using printable ASCII, or cancel.</b>";
|
|
2216
|
+
const buttons = hasManualName
|
|
2217
|
+
? [
|
|
2218
|
+
{ text: "↩️ Reset to automatic", callback_data: "thread-name:reset" },
|
|
2219
|
+
{ text: "✖ Cancel rename", callback_data: "thread-name:cancel" },
|
|
2220
|
+
]
|
|
2221
|
+
: [{ text: "✖ Cancel rename", callback_data: "thread-name:cancel" }];
|
|
2222
|
+
const dialogMessageId = await deps.sendInteractiveMessage(
|
|
2223
|
+
target.chatId,
|
|
2224
|
+
instructions,
|
|
2225
|
+
"html",
|
|
2226
|
+
{ inline_keyboard: buttons.map((button) => [button]) },
|
|
2227
|
+
{ target },
|
|
2228
|
+
);
|
|
2229
|
+
if (typeof dialogMessageId !== "number") return;
|
|
2230
|
+
threadNameDialog.open({
|
|
2231
|
+
scope: getThreadNameDialogScope(),
|
|
2232
|
+
target,
|
|
2233
|
+
dialogMessageId,
|
|
2234
|
+
});
|
|
2235
|
+
},
|
|
2088
2236
|
getPromptTemplateCommands,
|
|
2089
|
-
persistConfig: deps.configStore.persist,
|
|
2090
2237
|
sendTextReply: deps.sendTextReply,
|
|
2091
2238
|
getActiveTurnReply: () => {
|
|
2092
2239
|
const activeTurn = deps.activeTurnRuntime.get();
|
|
@@ -2158,7 +2305,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2158
2305
|
message.message_id,
|
|
2159
2306
|
[
|
|
2160
2307
|
includeGuidance ? formatTelegramUnboundTopicGuidance() : undefined,
|
|
2161
|
-
|
|
2308
|
+
`This thread is not bound to a Pi instance. Open an active Pi thread or run ${Commands.formatTelegramPiCommandHtml("/telegram-connect")} from a Pi session to bind one.`,
|
|
2162
2309
|
]
|
|
2163
2310
|
.filter((line): line is string => typeof line === "string")
|
|
2164
2311
|
.join("\n\n"),
|
|
@@ -2178,7 +2325,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2178
2325
|
const replyMarkup = buildTelegramUnboundRerouteChooserMarkup(
|
|
2179
2326
|
rerouteId,
|
|
2180
2327
|
activeRecords,
|
|
2181
|
-
{ canRestore: sourceTarget !== undefined },
|
|
2328
|
+
{ canRestore: sourceTarget !== undefined, getDisplayTitle: deps.getDisplayTitle },
|
|
2182
2329
|
);
|
|
2183
2330
|
if (deps.sendInteractiveMessage) {
|
|
2184
2331
|
const chooserId = await deps.sendInteractiveMessage(
|
|
@@ -2262,7 +2409,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2262
2409
|
const replyMarkup = buildTelegramUnboundRerouteChooserMarkup(
|
|
2263
2410
|
rerouteId,
|
|
2264
2411
|
activeRecords,
|
|
2265
|
-
{ canRestore: typeof message.message_thread_id === "number" },
|
|
2412
|
+
{ canRestore: typeof message.message_thread_id === "number", getDisplayTitle: deps.getDisplayTitle },
|
|
2266
2413
|
);
|
|
2267
2414
|
let chooserId: number | undefined;
|
|
2268
2415
|
try {
|
|
@@ -2311,6 +2458,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2311
2458
|
throw error;
|
|
2312
2459
|
}
|
|
2313
2460
|
rememberRerouteChooser(rerouteId, chooserId);
|
|
2461
|
+
Updates.reportTelegramUpdateCompleted(commandMessage);
|
|
2314
2462
|
return true;
|
|
2315
2463
|
};
|
|
2316
2464
|
const commandOrPrompt = Commands.createTelegramCommandOrPromptRuntime<
|
|
@@ -2323,6 +2471,84 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2323
2471
|
},
|
|
2324
2472
|
shouldIgnoreMessages: (messages) =>
|
|
2325
2473
|
!Media.hasTelegramMessagesPromptContent(messages),
|
|
2474
|
+
consumeThreadNameInput: async (messages) => {
|
|
2475
|
+
const message = messages[0];
|
|
2476
|
+
if (!message || messages.length !== 1) return false;
|
|
2477
|
+
const target = Updates.getTelegramMessageTarget(message);
|
|
2478
|
+
if (!target) return false;
|
|
2479
|
+
const candidate = threadNameDialog.inspect(target);
|
|
2480
|
+
if (!candidate || candidate.scope !== getThreadNameDialogScope() ||
|
|
2481
|
+
candidate.phase !== "input") return false;
|
|
2482
|
+
const name = Media.extractFirstTelegramMessageText(messages).trim();
|
|
2483
|
+
if (/^[A-Z]$/.test(name) && deps.resetCurrentThreadName) {
|
|
2484
|
+
const consumed = threadNameDialog.consumeName({
|
|
2485
|
+
scope: getThreadNameDialogScope(), target, text: name,
|
|
2486
|
+
});
|
|
2487
|
+
if (consumed.kind !== "name") return false;
|
|
2488
|
+
const result = await deps.resetCurrentThreadName(target);
|
|
2489
|
+
if (!result.ok) {
|
|
2490
|
+
threadNameDialog.open({
|
|
2491
|
+
scope: getThreadNameDialogScope(), target,
|
|
2492
|
+
dialogMessageId: candidate.dialogMessageId,
|
|
2493
|
+
});
|
|
2494
|
+
}
|
|
2495
|
+
await deps.sendTextReply(
|
|
2496
|
+
target.chatId,
|
|
2497
|
+
message.message_id,
|
|
2498
|
+
result.ok && !result.message
|
|
2499
|
+
? Commands.formatTelegramAutomaticThreadDisplayNameRestoredHeading(
|
|
2500
|
+
result.threadName ?? name,
|
|
2501
|
+
)
|
|
2502
|
+
: Commands.formatTelegramInformationHeading(
|
|
2503
|
+
result.ok ? "✅" : "⚠️",
|
|
2504
|
+
result.message ?? "Thread display name reset failed.",
|
|
2505
|
+
),
|
|
2506
|
+
{ parseMode: "HTML", target },
|
|
2507
|
+
);
|
|
2508
|
+
return true;
|
|
2509
|
+
}
|
|
2510
|
+
const validationError = deps.validateThreadName?.(name);
|
|
2511
|
+
if (!name || validationError) {
|
|
2512
|
+
await deps.sendTextReply(
|
|
2513
|
+
target.chatId,
|
|
2514
|
+
message.message_id,
|
|
2515
|
+
validationError
|
|
2516
|
+
? Commands.formatTelegramInvalidInstanceName(validationError)
|
|
2517
|
+
: Commands.formatTelegramInformationHeading(
|
|
2518
|
+
"⚠️",
|
|
2519
|
+
"Send 1–96 printable ASCII characters.",
|
|
2520
|
+
),
|
|
2521
|
+
{ parseMode: "HTML", target },
|
|
2522
|
+
);
|
|
2523
|
+
return true;
|
|
2524
|
+
}
|
|
2525
|
+
const consumed = threadNameDialog.consumeName({
|
|
2526
|
+
scope: getThreadNameDialogScope(), target, text: name,
|
|
2527
|
+
});
|
|
2528
|
+
if (consumed.kind !== "name") return false;
|
|
2529
|
+
const result = await deps.renameCurrentThread?.(target, consumed.name);
|
|
2530
|
+
if (!result?.ok) {
|
|
2531
|
+
threadNameDialog.open({
|
|
2532
|
+
scope: getThreadNameDialogScope(),
|
|
2533
|
+
target,
|
|
2534
|
+
dialogMessageId: candidate.dialogMessageId,
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
await deps.sendTextReply(
|
|
2538
|
+
target.chatId,
|
|
2539
|
+
message.message_id,
|
|
2540
|
+
result?.ok && !result.message
|
|
2541
|
+
? Commands.formatTelegramThreadDisplayNameSavedHeading(
|
|
2542
|
+
result.threadName ?? consumed.name,
|
|
2543
|
+
)
|
|
2544
|
+
: Commands.formatTelegramInformationHeading(
|
|
2545
|
+
result?.ok ? "✅" : "⚠️",
|
|
2546
|
+
result?.message ?? "Thread display name update failed.",
|
|
2547
|
+
),
|
|
2548
|
+
{ parseMode: "HTML", target },
|
|
2549
|
+
);
|
|
2550
|
+
return true;
|
|
2551
|
+
},
|
|
2326
2552
|
handleCommand: commandHandler,
|
|
2327
2553
|
executeExtensionCommand: async (command, message, ctx) => {
|
|
2328
2554
|
const extensionCommand = Commands.findTelegramExtensionCommand(
|
|
@@ -2585,8 +2811,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2585
2811
|
recordMessageOwnership: deps.recordMessageOwnership,
|
|
2586
2812
|
handleTelegramTopicLifecycleUpdate,
|
|
2587
2813
|
foreignOwnedUpdateForwarder: deps.foreignOwnedUpdateForwarder,
|
|
2588
|
-
|
|
2589
|
-
persistConfig: deps.configStore.persist,
|
|
2814
|
+
persistAllowedUserId: deps.configStore.persistAllowedUserId,
|
|
2590
2815
|
updateStatus: deps.updateStatus,
|
|
2591
2816
|
removePendingMediaGroupMessages: deps.mediaGroupRuntime.removeMessages,
|
|
2592
2817
|
flushPendingMediaGroupMessage: deps.mediaGroupRuntime.flushMessage,
|
|
@@ -2684,7 +2909,8 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2684
2909
|
},
|
|
2685
2910
|
handleAuthorizedTelegramEditedMessage: editRuntime.updateFromEditedMessage,
|
|
2686
2911
|
handleAuthorizedTelegramGuestMessage,
|
|
2687
|
-
handleUnboundTelegramTopicMessage:
|
|
2912
|
+
handleUnboundTelegramTopicMessage: (message, ctx) => {
|
|
2913
|
+
const operation = async (): Promise<void> => {
|
|
2688
2914
|
const assertExecutionCurrent =
|
|
2689
2915
|
Updates.createTelegramUpdateExecutionFenceGuard(message);
|
|
2690
2916
|
assertExecutionCurrent();
|
|
@@ -2743,7 +2969,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2743
2969
|
target.chatId,
|
|
2744
2970
|
message.message_id,
|
|
2745
2971
|
"Instance " +
|
|
2746
|
-
getTelegramThreadRecordLabel(existing) +
|
|
2972
|
+
getTelegramThreadRecordLabel(existing, deps.getDisplayTitle) +
|
|
2747
2973
|
" is starting. Please wait…",
|
|
2748
2974
|
{ target },
|
|
2749
2975
|
);
|
|
@@ -2754,74 +2980,10 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2754
2980
|
target.chatId,
|
|
2755
2981
|
message.message_id,
|
|
2756
2982
|
"Instance " +
|
|
2757
|
-
getTelegramThreadRecordLabel(existing) +
|
|
2758
|
-
|
|
2759
|
-
{ target },
|
|
2760
|
-
);
|
|
2761
|
-
return;
|
|
2762
|
-
}
|
|
2763
|
-
if (
|
|
2764
|
-
(existing.status === "stale" || existing.status === "offline") &&
|
|
2765
|
-
leaderProfileKey &&
|
|
2766
|
-
!hasActiveLeaderTopic(
|
|
2767
|
-
deps.threadStore.list(),
|
|
2768
|
-
leaderProfileKey,
|
|
2769
|
-
instanceId,
|
|
2770
|
-
) &&
|
|
2771
|
-
!hasAnyRoutableThread
|
|
2772
|
-
) {
|
|
2773
|
-
const priorLeaderRecord =
|
|
2774
|
-
deps.threadStore.getByProfileKey(leaderProfileKey);
|
|
2775
|
-
const slot =
|
|
2776
|
-
deps.threadStore.allocateSlot(
|
|
2777
|
-
leaderProfileKey,
|
|
2778
|
-
priorLeaderRecord?.slot ?? existing.slot,
|
|
2779
|
-
) ??
|
|
2780
|
-
priorLeaderRecord?.slot ??
|
|
2781
|
-
existing.slot ??
|
|
2782
|
-
"A";
|
|
2783
|
-
const threadName =
|
|
2784
|
-
priorLeaderRecord?.threadName ??
|
|
2785
|
-
existing.threadName ??
|
|
2786
|
-
Threads.chooseTelegramThreadName({ slot }) ??
|
|
2787
|
-
"Pi";
|
|
2788
|
-
deps.threadStore.upsert({
|
|
2789
|
-
profileKey: leaderProfileKey,
|
|
2790
|
-
owner: {
|
|
2791
|
-
kind: "leader",
|
|
2792
|
-
cwd:
|
|
2793
|
-
typeof (ctx as { cwd?: unknown }).cwd === "string"
|
|
2794
|
-
? (ctx as { cwd?: string }).cwd
|
|
2795
|
-
: undefined,
|
|
2796
|
-
instanceId,
|
|
2797
|
-
},
|
|
2798
|
-
target: { chatId: target.chatId, threadId: target.threadId },
|
|
2799
|
-
status: "active",
|
|
2800
|
-
createdAtMs: priorLeaderRecord?.createdAtMs ?? existing.createdAtMs,
|
|
2801
|
-
updatedAtMs: Date.now(),
|
|
2802
|
-
threadName,
|
|
2803
|
-
instanceId,
|
|
2804
|
-
slot,
|
|
2805
|
-
});
|
|
2806
|
-
await deps.threadStore.persist();
|
|
2807
|
-
assertExecutionCurrent();
|
|
2808
|
-
deps.setCurrentLeaderIdentity?.({
|
|
2809
|
-
target: { chatId: target.chatId, threadId: target.threadId },
|
|
2810
|
-
slot,
|
|
2811
|
-
threadName,
|
|
2812
|
-
});
|
|
2813
|
-
deps.recordRuntimeEvent?.(
|
|
2814
|
-
"bus",
|
|
2815
|
-
"Bus leader reclaimed unbound thread",
|
|
2816
|
-
{
|
|
2817
|
-
phase: "leader-topic-reclaim",
|
|
2818
|
-
chatId: target.chatId,
|
|
2819
|
-
threadId: target.threadId,
|
|
2820
|
-
slot,
|
|
2821
|
-
profileKey: leaderProfileKey,
|
|
2822
|
-
},
|
|
2983
|
+
escapeHtml(getTelegramThreadRecordLabel(existing, deps.getDisplayTitle)) +
|
|
2984
|
+
` is not currently registered with the Telegram bus. This thread is preserved; retry shortly. If it does not recover, run ${Commands.formatTelegramPiCommandHtml("/telegram-connect")} in that Pi instance.`,
|
|
2985
|
+
{ parseMode: "HTML", target },
|
|
2823
2986
|
);
|
|
2824
|
-
await textDispatch.handleMessage(message as TMessage, ctx);
|
|
2825
2987
|
return;
|
|
2826
2988
|
}
|
|
2827
2989
|
await deps.sendTextReply(
|
|
@@ -2914,12 +3076,28 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2914
3076
|
if (!currentLeaderIsStale) throw error;
|
|
2915
3077
|
}
|
|
2916
3078
|
if (currentLeaderIsStale) {
|
|
3079
|
+
const slot = deps.threadStore.allocateSlot(leaderProfileKey);
|
|
3080
|
+
if (!slot) {
|
|
3081
|
+
deps.threadStore.markStaleByTarget(
|
|
3082
|
+
currentLeaderRecord.target,
|
|
3083
|
+
"deleted",
|
|
3084
|
+
"Current leader thread is stale during unbound prompt routing.",
|
|
3085
|
+
);
|
|
3086
|
+
await deps.threadStore.persist();
|
|
3087
|
+
assertExecutionCurrent();
|
|
3088
|
+
await deps.sendTextReply(
|
|
3089
|
+
target.chatId,
|
|
3090
|
+
message.message_id,
|
|
3091
|
+
TELEGRAM_SLOT_CAPACITY_MESSAGE,
|
|
3092
|
+
{ target },
|
|
3093
|
+
);
|
|
3094
|
+
return;
|
|
3095
|
+
}
|
|
2917
3096
|
deps.threadStore.markStaleByTarget(
|
|
2918
3097
|
currentLeaderRecord.target,
|
|
2919
3098
|
"deleted",
|
|
2920
3099
|
"Current leader thread is stale during unbound prompt routing.",
|
|
2921
3100
|
);
|
|
2922
|
-
const slot = currentLeaderRecord.slot ?? "A";
|
|
2923
3101
|
const threadName = getRestoredThreadName(currentLeaderRecord, slot);
|
|
2924
3102
|
deps.threadStore.upsert({
|
|
2925
3103
|
...currentLeaderRecord,
|
|
@@ -2972,14 +3150,19 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2972
3150
|
deps.threadStore.getByProfileKey(leaderProfileKey);
|
|
2973
3151
|
const priorLeaderIdentity =
|
|
2974
3152
|
deps.threadStore.getIdentityByProfileKey(leaderProfileKey);
|
|
2975
|
-
const slot =
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
3153
|
+
const slot = deps.threadStore.allocateSlot(
|
|
3154
|
+
leaderProfileKey,
|
|
3155
|
+
priorLeaderRecord?.slot ?? priorLeaderIdentity?.slot,
|
|
3156
|
+
);
|
|
3157
|
+
if (!slot) {
|
|
3158
|
+
await deps.sendTextReply(
|
|
3159
|
+
target.chatId,
|
|
3160
|
+
message.message_id,
|
|
3161
|
+
TELEGRAM_SLOT_CAPACITY_MESSAGE,
|
|
3162
|
+
{ target },
|
|
3163
|
+
);
|
|
3164
|
+
return;
|
|
3165
|
+
}
|
|
2983
3166
|
const identityThreadName =
|
|
2984
3167
|
priorLeaderIdentity?.threadName &&
|
|
2985
3168
|
Threads.isTelegramTopicThreadNameValidForSlot(
|
|
@@ -3034,6 +3217,16 @@ export function createTelegramInboundRouteRuntime<
|
|
|
3034
3217
|
}
|
|
3035
3218
|
await sendUnboundRerouteChooser(message as TMessage, ctx);
|
|
3036
3219
|
return;
|
|
3220
|
+
};
|
|
3221
|
+
if (!deps.runWorkspaceOperation) return operation();
|
|
3222
|
+
return deps.runWorkspaceOperation(
|
|
3223
|
+
{
|
|
3224
|
+
operationId: `workspace-unbound:${message.chat.id}:${message.message_id}`,
|
|
3225
|
+
operationKind: "workspace.route-unbound-thread",
|
|
3226
|
+
scopes: [{ kind: "profile" }],
|
|
3227
|
+
},
|
|
3228
|
+
operation,
|
|
3229
|
+
);
|
|
3037
3230
|
},
|
|
3038
3231
|
});
|
|
3039
3232
|
}
|