@llblab/pi-kit 0.14.1 → 0.16.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 +11 -0
- package/README.md +3 -3
- package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +5 -0
- package/node_modules/@llblab/pi-codex-usage/README.md +6 -0
- package/node_modules/@llblab/pi-codex-usage/index.ts +81 -7
- package/node_modules/@llblab/pi-codex-usage/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +9 -9
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +0 -13
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +15 -0
- package/node_modules/@llblab/pi-state-flow/README.md +7 -6
- package/node_modules/@llblab/pi-state-flow/dist/lib/config.d.ts +5 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/config.js +17 -16
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +8 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +24 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +4 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/durable.d.ts +1 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +8 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/episode.d.ts +2 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/episode.js +4 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.d.ts +5 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +93 -35
- package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +20 -23
- package/node_modules/@llblab/pi-state-flow/dist/lib/history.js +8 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/json.js +29 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/migration.js +34 -18
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +14 -16
- package/node_modules/@llblab/pi-state-flow/dist/lib/query.d.ts +27 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +182 -10
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +2 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +34 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +5 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +20 -24
- package/node_modules/@llblab/pi-state-flow/dist/lib/state.d.ts +6 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/state.js +5 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/storage.d.ts +2 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/storage.js +55 -20
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +8 -6
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +10 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +7 -3
- package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-memory/SKILL.md +11 -3
- package/node_modules/@llblab/pi-state-flow/docs/README.md +1 -0
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +5 -3
- package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +3 -2
- package/node_modules/@llblab/pi-state-flow/docs/lazy-state.md +504 -0
- package/node_modules/@llblab/pi-state-flow/docs/usage.md +11 -8
- package/node_modules/@llblab/pi-state-flow/lib/config.ts +18 -15
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +24 -0
- package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +4 -3
- package/node_modules/@llblab/pi-state-flow/lib/durable.ts +8 -4
- package/node_modules/@llblab/pi-state-flow/lib/episode.ts +5 -0
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +86 -34
- package/node_modules/@llblab/pi-state-flow/lib/git.ts +23 -22
- package/node_modules/@llblab/pi-state-flow/lib/history.ts +8 -4
- package/node_modules/@llblab/pi-state-flow/lib/json.ts +31 -3
- package/node_modules/@llblab/pi-state-flow/lib/migration.ts +33 -16
- package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +14 -16
- package/node_modules/@llblab/pi-state-flow/lib/query.ts +173 -9
- package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +32 -4
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +22 -25
- package/node_modules/@llblab/pi-state-flow/lib/state.ts +11 -6
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +1 -1
- package/node_modules/@llblab/pi-state-flow/lib/storage.ts +46 -18
- package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +19 -6
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +7 -3
- package/node_modules/@llblab/pi-state-flow/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +11 -3
- package/node_modules/@llblab/pi-telegram/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -0
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +12 -0
- package/node_modules/@llblab/pi-telegram/README.md +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +12 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +3 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +7 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +134 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +297 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +11 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +68 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +4 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +17 -13
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +2 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +5 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +59 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +23 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +20 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +18 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +152 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +5 -3
- package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +3 -3
- package/node_modules/@llblab/pi-telegram/docs/callback-namespaces.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +4 -3
- package/node_modules/@llblab/pi-telegram/docs/sections.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +2 -1
- package/node_modules/@llblab/pi-telegram/docs/updates.md +1 -1
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +14 -0
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +10 -2
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +466 -21
- package/node_modules/@llblab/pi-telegram/lib/delivery.ts +15 -0
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +77 -9
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +25 -10
- package/node_modules/@llblab/pi-telegram/lib/pi.ts +3 -0
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +7 -1
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +2 -0
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +90 -19
- package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +30 -0
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +199 -6
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +5 -2
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/package.json +4 -4
|
@@ -77,6 +77,7 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
77
77
|
getCommands,
|
|
78
78
|
getThinkingLevel,
|
|
79
79
|
sendUserMessage,
|
|
80
|
+
registerCommand,
|
|
80
81
|
setActiveTools,
|
|
81
82
|
setModel,
|
|
82
83
|
setThinkingLevel,
|
|
@@ -237,6 +238,26 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
237
238
|
canReset: lockRuntime.owns,
|
|
238
239
|
commitReset: lockRuntime.commitIfOwned,
|
|
239
240
|
});
|
|
241
|
+
const sessionActionAssembly = Commands.createTelegramSessionActionAssembly({
|
|
242
|
+
registerCommand,
|
|
243
|
+
sendUserMessage,
|
|
244
|
+
store: threadStore,
|
|
245
|
+
getProfileName: configStore.getActiveProfileName,
|
|
246
|
+
ownsPersistence: lockRuntime.owns,
|
|
247
|
+
async sendResult(target, html) {
|
|
248
|
+
const delivery = await Delivery.sendTelegramView(
|
|
249
|
+
{ text: html, parseMode: "html", replyMarkup: { inline_keyboard: [] } },
|
|
250
|
+
{ scope: { kind: "target", target } },
|
|
251
|
+
);
|
|
252
|
+
return delivery.ok ? { ok: true } : { ok: false,
|
|
253
|
+
retryable: delivery.reason === "runtime-unavailable" ||
|
|
254
|
+
delivery.reason === "target-unavailable" ||
|
|
255
|
+
delivery.reason === "transport-retryable" };
|
|
256
|
+
},
|
|
257
|
+
handoffTtlMs: Threads.TELEGRAM_LEADER_SESSION_HANDOFF_TTL_MS,
|
|
258
|
+
recordRuntimeEvent,
|
|
259
|
+
});
|
|
260
|
+
const sessionActionsRuntime = sessionActionAssembly.action;
|
|
240
261
|
const lockOwnershipGuard =
|
|
241
262
|
Locks.createTelegramLockOwnershipGuard(lockRuntime);
|
|
242
263
|
const getCurrentLeaderEpoch = lockRuntime.getOwnedLeaderEpoch;
|
|
@@ -851,6 +872,24 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
851
872
|
updateStatusMessage: menuActions.updateStatusMessage,
|
|
852
873
|
updateStatus,
|
|
853
874
|
});
|
|
875
|
+
const threadDisplaySettingsRuntime =
|
|
876
|
+
ThreadDisplay.createTelegramThreadDisplaySettingsRuntime({
|
|
877
|
+
getTarget() {
|
|
878
|
+
return telegramBusFollowerRegistrationState.getTarget() ??
|
|
879
|
+
telegramBusLeaderState.getTarget();
|
|
880
|
+
},
|
|
881
|
+
getBinding(target) { return threadStore.getWorkspaceBindingByTarget(target); },
|
|
882
|
+
apply(mode) {
|
|
883
|
+
return ThreadDisplay.applyTelegramThreadDisplaySetting(mode, {
|
|
884
|
+
getProfileKey: configStore.getActiveProfileName,
|
|
885
|
+
ownsLeader() { return getCurrentLeaderEpoch() !== undefined; },
|
|
886
|
+
getLeaderSetter() { return telegramBusLeaderRuntime.setThreadDisplayMode; },
|
|
887
|
+
getFollowerSetter() { return telegramBusFollowerRegistration.setThreadDisplayMode; },
|
|
888
|
+
reloadConfig: configStore.load,
|
|
889
|
+
});
|
|
890
|
+
},
|
|
891
|
+
reset(target) { return telegramThreadDisplayNameResetBinding.reset(target); },
|
|
892
|
+
});
|
|
854
893
|
const settingsMenuRuntime = MenuSettings.createTelegramSettingsMenuRuntime(
|
|
855
894
|
{
|
|
856
895
|
reloadConfig: configStore.load,
|
|
@@ -866,16 +905,10 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
866
905
|
return threadStore.getBotState().threadMode === "enabled"
|
|
867
906
|
? Config.resolveTelegramThreadDisplayMode(configStore.get()) : undefined;
|
|
868
907
|
},
|
|
908
|
+
isThreadDisplayCustom: threadDisplaySettingsRuntime.isCustom,
|
|
869
909
|
async setThreadDisplayMode(mode) {
|
|
870
|
-
try {
|
|
871
|
-
|
|
872
|
-
getProfileKey: configStore.getActiveProfileName,
|
|
873
|
-
ownsLeader() { return getCurrentLeaderEpoch() !== undefined; },
|
|
874
|
-
getLeaderSetter() { return telegramBusLeaderRuntime.setThreadDisplayMode; },
|
|
875
|
-
getFollowerSetter() { return telegramBusFollowerRegistration.setThreadDisplayMode; },
|
|
876
|
-
reloadConfig: configStore.load,
|
|
877
|
-
});
|
|
878
|
-
} catch (error) {
|
|
910
|
+
try { await threadDisplaySettingsRuntime.setMode(mode); }
|
|
911
|
+
catch (error) {
|
|
879
912
|
recordRuntimeEvent("bus", error, { phase: "thread-display-setting" });
|
|
880
913
|
throw error;
|
|
881
914
|
}
|
|
@@ -959,6 +992,36 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
959
992
|
foreignOwnedUpdateForwarder,
|
|
960
993
|
replaceFollowerThreadTarget: restoreFollowerThreadTarget,
|
|
961
994
|
bridgeRuntime,
|
|
995
|
+
requestNewSession(source) {
|
|
996
|
+
const updateId = Updates.getTelegramUpdateExecutionFence(source)?.updateId;
|
|
997
|
+
if (updateId === undefined) {
|
|
998
|
+
throw new Error("Telegram session replacement requires durable update authority.");
|
|
999
|
+
}
|
|
1000
|
+
const callbackMessage = source && typeof source === "object" && "message" in source
|
|
1001
|
+
? (source as { message?: unknown }).message
|
|
1002
|
+
: source;
|
|
1003
|
+
const messageTarget = callbackMessage as {
|
|
1004
|
+
chat?: { id?: unknown };
|
|
1005
|
+
message_id?: unknown;
|
|
1006
|
+
message_thread_id?: unknown;
|
|
1007
|
+
} | undefined;
|
|
1008
|
+
const target = typeof messageTarget?.chat?.id === "number" &&
|
|
1009
|
+
typeof messageTarget.message_id === "number"
|
|
1010
|
+
? {
|
|
1011
|
+
chatId: messageTarget.chat.id,
|
|
1012
|
+
messageId: messageTarget.message_id,
|
|
1013
|
+
...(typeof messageTarget.message_thread_id === "number"
|
|
1014
|
+
? { threadId: messageTarget.message_thread_id }
|
|
1015
|
+
: {}),
|
|
1016
|
+
}
|
|
1017
|
+
: undefined;
|
|
1018
|
+
if (!target) {
|
|
1019
|
+
throw new Error("Telegram session replacement target is unavailable.");
|
|
1020
|
+
}
|
|
1021
|
+
if (!sessionActionsRuntime.scheduleAfterUpdate(updateId, target)) {
|
|
1022
|
+
throw new Error("A Telegram session replacement is already pending.");
|
|
1023
|
+
}
|
|
1024
|
+
},
|
|
962
1025
|
activeTurnRuntime,
|
|
963
1026
|
mediaGroupRuntime,
|
|
964
1027
|
textGroupRuntime,
|
|
@@ -1066,6 +1129,7 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1066
1129
|
dispatchNext: dispatchNextQueuedTelegramTurn,
|
|
1067
1130
|
requestQueueHandoffReconciliation:
|
|
1068
1131
|
queueHandoffReconciliationBinding.request,
|
|
1132
|
+
afterUpdateCompleted: sessionActionsRuntime.onUpdateCompleted,
|
|
1069
1133
|
},
|
|
1070
1134
|
worker: {
|
|
1071
1135
|
defaultHandle: inboundRouteRuntime.handleUpdate,
|
|
@@ -1638,6 +1702,7 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1638
1702
|
}
|
|
1639
1703
|
},
|
|
1640
1704
|
}.reset);
|
|
1705
|
+
sessionActionsRuntime.register();
|
|
1641
1706
|
Bindings.registerTelegramCommandsAndTools({
|
|
1642
1707
|
pi,
|
|
1643
1708
|
agentDir: Paths.resolveAgentDir(),
|
|
@@ -1840,6 +1905,9 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1840
1905
|
shutdownGenerativeAppLiveSurfaces: generativeAppLiveSurfaceBinding.shutdown,
|
|
1841
1906
|
resolveAutomaticThreadCleanupEnabled:
|
|
1842
1907
|
configControls.resolveAutomaticThreadCleanupEnabled,
|
|
1908
|
+
onSessionStarted(_event, ctx) {
|
|
1909
|
+
sessionActionAssembly.settlement.onSessionStart(ctx);
|
|
1910
|
+
},
|
|
1843
1911
|
buttonActionStore,
|
|
1844
1912
|
callMultipart,
|
|
1845
1913
|
sendChatAction,
|
|
@@ -23,6 +23,7 @@ export type TelegramSettingsMenuReplyMarkup = TelegramInlineKeyboardMarkup;
|
|
|
23
23
|
|
|
24
24
|
export interface TelegramSettingsStateDeps {
|
|
25
25
|
getThreadDisplayMode?: () => TelegramThreadDisplayMode | undefined;
|
|
26
|
+
isThreadDisplayCustom?: () => boolean;
|
|
26
27
|
areDraftPreviewsEnabled: () => boolean;
|
|
27
28
|
getAssistantRenderingMode: () => TelegramAssistantRenderingMode;
|
|
28
29
|
getActivityVerbosity: () => TelegramActivityVerbosity;
|
|
@@ -177,12 +178,15 @@ export function buildTelegramSettingsMenuText(): string {
|
|
|
177
178
|
|
|
178
179
|
export function buildThreadDisplaySettingsText(
|
|
179
180
|
mode: TelegramThreadDisplayMode,
|
|
181
|
+
custom = false,
|
|
180
182
|
): string {
|
|
181
183
|
return [
|
|
182
|
-
`${THREAD_DISPLAY_SETTINGS_TITLE} <code>${threadDisplayModeLabel(mode)}</code>`,
|
|
184
|
+
`${THREAD_DISPLAY_SETTINGS_TITLE} <code>${custom ? "custom" : threadDisplayModeLabel(mode)}</code>`,
|
|
183
185
|
"",
|
|
184
186
|
"Choose how this bot profile labels Telegram tabs and Pi terminal status. Each slot is unique across this bot profile.",
|
|
185
187
|
"",
|
|
188
|
+
"Set a manual name for the current Thread with /name <code>Name</code>.",
|
|
189
|
+
"",
|
|
186
190
|
"<code>-</code> <code>letters</code> (default): show the unique slot, such as <b><i>A</i></b> or <b><i>B</i></b>.",
|
|
187
191
|
"<code>-</code> <code>names</code>: show the generated dictionary name for the slot, such as <b><i>Anchor</i></b> or <b><i>Briar</i></b>.",
|
|
188
192
|
"<code>-</code> <code>directory-title</code>: humanize the distinguishing directory path, such as <b><i>Api Tools</i></b> or <b><i>Frontend / Extensions A</i></b>.",
|
|
@@ -311,6 +315,7 @@ export function buildTelegramSettingsMenuReplyMarkup(
|
|
|
311
315
|
automaticThreadCleanupEnabled = true,
|
|
312
316
|
activityVerbosity: TelegramActivityVerbosity = "quiet",
|
|
313
317
|
threadDisplayMode?: TelegramThreadDisplayMode,
|
|
318
|
+
threadDisplayCustom = false,
|
|
314
319
|
): TelegramSettingsMenuReplyMarkup {
|
|
315
320
|
const hasRenderingMode =
|
|
316
321
|
assistantRenderingModeOrVoiceReplyMode === "rich" ||
|
|
@@ -364,15 +369,17 @@ export function buildTelegramSettingsMenuReplyMarkup(
|
|
|
364
369
|
text: `🕒 Time injection: ${getTelegramSettingsStateValueLabel(timeInjectionMode)}`,
|
|
365
370
|
callback_data: "settings:open:time-injection",
|
|
366
371
|
},
|
|
372
|
+
];
|
|
373
|
+
if (threadDisplayMode) settingsButtons.push(
|
|
367
374
|
{
|
|
368
375
|
text: `🧹 Thread cleanup: ${automaticThreadCleanupEnabled ? "on" : "off"}`,
|
|
369
376
|
callback_data: "settings:open:automatic-thread-cleanup",
|
|
370
377
|
},
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
378
|
+
{
|
|
379
|
+
text: `🧵 Thread display: ${threadDisplayCustom ? "custom" : threadDisplayMode}`,
|
|
380
|
+
callback_data: "settings:open:thread-display",
|
|
381
|
+
},
|
|
382
|
+
);
|
|
376
383
|
if (sectionRegistry) {
|
|
377
384
|
const extensionRows = getTelegramExtensionSettingsRows(sectionRegistry);
|
|
378
385
|
settingsButtons.push(
|
|
@@ -406,6 +413,7 @@ export async function openTelegramSettingsMenu<
|
|
|
406
413
|
deps.isAutomaticThreadCleanupEnabled(),
|
|
407
414
|
deps.getActivityVerbosity(),
|
|
408
415
|
deps.getThreadDisplayMode?.(),
|
|
416
|
+
deps.isThreadDisplayCustom?.() ?? false,
|
|
409
417
|
),
|
|
410
418
|
);
|
|
411
419
|
if (messageId === undefined) return;
|
|
@@ -424,11 +432,14 @@ function threadDisplayModeLabel(mode: TelegramThreadDisplayMode): string {
|
|
|
424
432
|
}
|
|
425
433
|
}
|
|
426
434
|
|
|
427
|
-
export function buildThreadDisplaySettingsReplyMarkup(
|
|
435
|
+
export function buildThreadDisplaySettingsReplyMarkup(
|
|
436
|
+
mode: TelegramThreadDisplayMode,
|
|
437
|
+
custom = false,
|
|
438
|
+
): TelegramSettingsMenuReplyMarkup {
|
|
428
439
|
return { inline_keyboard: [
|
|
429
440
|
[{ text: "⬆️ Back", callback_data: "settings:list" }],
|
|
430
441
|
...(["letters", "names", "directory-title", "directory-snake"] as const).map((value) => [{
|
|
431
|
-
text: `${mode === value ? "🟢 " : ""}${threadDisplayModeLabel(value)}`,
|
|
442
|
+
text: `${!custom && mode === value ? "🟢 " : ""}${threadDisplayModeLabel(value)}`,
|
|
432
443
|
callback_data: `settings:set:thread-display:${value}`,
|
|
433
444
|
}]),
|
|
434
445
|
] };
|
|
@@ -565,6 +576,7 @@ export async function updateTelegramSettingsMenuMessage(
|
|
|
565
576
|
deps.isAutomaticThreadCleanupEnabled(),
|
|
566
577
|
deps.getActivityVerbosity(),
|
|
567
578
|
deps.getThreadDisplayMode?.(),
|
|
579
|
+
deps.isThreadDisplayCustom?.() ?? false,
|
|
568
580
|
),
|
|
569
581
|
);
|
|
570
582
|
}
|
|
@@ -661,8 +673,8 @@ export async function handleTelegramSettingsMenuCallbackAction(
|
|
|
661
673
|
return true;
|
|
662
674
|
}
|
|
663
675
|
await deps.updateSettingsMessage(
|
|
664
|
-
buildThreadDisplaySettingsText(mode),
|
|
665
|
-
buildThreadDisplaySettingsReplyMarkup(mode),
|
|
676
|
+
buildThreadDisplaySettingsText(mode, deps.isThreadDisplayCustom?.() ?? false),
|
|
677
|
+
buildThreadDisplaySettingsReplyMarkup(mode, deps.isThreadDisplayCustom?.() ?? false),
|
|
666
678
|
);
|
|
667
679
|
await deps.answerCallbackQuery(callbackQueryId);
|
|
668
680
|
return true;
|
|
@@ -877,6 +889,7 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
877
889
|
getTimeInjectionMode: deps.getTimeInjectionMode,
|
|
878
890
|
isAutomaticThreadCleanupEnabled: deps.isAutomaticThreadCleanupEnabled,
|
|
879
891
|
getThreadDisplayMode: deps.getThreadDisplayMode,
|
|
892
|
+
isThreadDisplayCustom: deps.isThreadDisplayCustom,
|
|
880
893
|
sendSettingsMenu: (state, text, replyMarkup) =>
|
|
881
894
|
deps.sendInteractiveMessage(
|
|
882
895
|
state.chatId,
|
|
@@ -901,6 +914,7 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
901
914
|
getTimeInjectionMode: deps.getTimeInjectionMode,
|
|
902
915
|
isAutomaticThreadCleanupEnabled: deps.isAutomaticThreadCleanupEnabled,
|
|
903
916
|
getThreadDisplayMode: deps.getThreadDisplayMode,
|
|
917
|
+
isThreadDisplayCustom: deps.isThreadDisplayCustom,
|
|
904
918
|
updateSettingsMessage: (text, replyMarkup) =>
|
|
905
919
|
deps.editInteractiveMessage(
|
|
906
920
|
state.chatId,
|
|
@@ -945,6 +959,7 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
945
959
|
getTimeInjectionMode: deps.getTimeInjectionMode,
|
|
946
960
|
isAutomaticThreadCleanupEnabled: deps.isAutomaticThreadCleanupEnabled,
|
|
947
961
|
getThreadDisplayMode: deps.getThreadDisplayMode,
|
|
962
|
+
isThreadDisplayCustom: deps.isThreadDisplayCustom,
|
|
948
963
|
setThreadDisplayMode: deps.setThreadDisplayMode,
|
|
949
964
|
setDraftPreviewsEnabled: deps.setDraftPreviewsEnabled,
|
|
950
965
|
setAssistantRenderingMode: deps.setAssistantRenderingMode,
|
|
@@ -138,6 +138,7 @@ export interface PiExtensionApiRuntimePorts {
|
|
|
138
138
|
getActiveTools: ExtensionAPI["getActiveTools"];
|
|
139
139
|
setActiveTools: ExtensionAPI["setActiveTools"];
|
|
140
140
|
setModel: ExtensionAPI["setModel"];
|
|
141
|
+
registerCommand: ExtensionAPI["registerCommand"];
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
export function createExtensionApiRuntimePorts(
|
|
@@ -151,6 +152,7 @@ export function createExtensionApiRuntimePorts(
|
|
|
151
152
|
| "getActiveTools"
|
|
152
153
|
| "setActiveTools"
|
|
153
154
|
| "setModel"
|
|
155
|
+
| "registerCommand"
|
|
154
156
|
>,
|
|
155
157
|
): PiExtensionApiRuntimePorts {
|
|
156
158
|
return {
|
|
@@ -163,6 +165,7 @@ export function createExtensionApiRuntimePorts(
|
|
|
163
165
|
getActiveTools: () => api.getActiveTools(),
|
|
164
166
|
setActiveTools: (names) => api.setActiveTools(names),
|
|
165
167
|
setModel: (model) => api.setModel(model),
|
|
168
|
+
registerCommand: (name, options) => api.registerCommand(name, options),
|
|
166
169
|
};
|
|
167
170
|
}
|
|
168
171
|
|
|
@@ -1474,6 +1474,7 @@ export interface TelegramAgentEndAssistantResult {
|
|
|
1474
1474
|
text?: string;
|
|
1475
1475
|
stopReason?: string;
|
|
1476
1476
|
errorMessage?: string;
|
|
1477
|
+
recoveredFromEarlier?: boolean;
|
|
1477
1478
|
}
|
|
1478
1479
|
|
|
1479
1480
|
export interface TelegramAgentEndOutboundVoiceReply {
|
|
@@ -1592,6 +1593,7 @@ export interface TelegramAgentEndHookRuntimeDeps<
|
|
|
1592
1593
|
extractAssistant: (
|
|
1593
1594
|
messages: readonly TMessage[],
|
|
1594
1595
|
) => TelegramAgentEndAssistantResult;
|
|
1596
|
+
isRecoveredAssistantAlreadyPublished?: (assistant: TelegramAgentEndAssistantResult) => boolean;
|
|
1595
1597
|
getFoldQueuedPromptsIntoHistory: () => boolean;
|
|
1596
1598
|
resetRuntimeState: () => void;
|
|
1597
1599
|
isSessionActive?: (ctx: TContext) => boolean;
|
|
@@ -1736,7 +1738,11 @@ export function createTelegramAgentEndHook<
|
|
|
1736
1738
|
): Promise<void> => {
|
|
1737
1739
|
if (deps.isSessionActive?.(ctx) === false) return;
|
|
1738
1740
|
const turn = deps.getActiveTurn();
|
|
1739
|
-
const
|
|
1741
|
+
const extractedAssistant = assistantOverride ?? (turn ? deps.extractAssistant(event.messages) : {});
|
|
1742
|
+
const assistant = extractedAssistant.recoveredFromEarlier &&
|
|
1743
|
+
deps.isRecoveredAssistantAlreadyPublished?.(extractedAssistant)
|
|
1744
|
+
? { stopReason: extractedAssistant.stopReason }
|
|
1745
|
+
: extractedAssistant;
|
|
1740
1746
|
const hasPublication = !!assistant.text || assistant.stopReason === "error" || !!turn?.queuedAttachments.length;
|
|
1741
1747
|
const reservation = turn && !turn.guestQueryId && hasPublication ? deps.reserveActiveTurnDelivery?.() : undefined;
|
|
1742
1748
|
const scheduleDelivery = reservation?.schedule ?? deps.scheduleActiveTurnDelivery;
|
|
@@ -191,6 +191,7 @@ export function extractRunAssistantMessage(
|
|
|
191
191
|
text?: string;
|
|
192
192
|
stopReason?: string;
|
|
193
193
|
errorMessage?: string;
|
|
194
|
+
recoveredFromEarlier?: boolean;
|
|
194
195
|
} {
|
|
195
196
|
const latest = extractLatestAssistantMessageText(messages);
|
|
196
197
|
if (latest.text || latest.stopReason !== "stop") return latest;
|
|
@@ -213,6 +214,7 @@ export function extractRunAssistantMessage(
|
|
|
213
214
|
stopReason: typeof rawStopReason === "string" ? rawStopReason : undefined,
|
|
214
215
|
errorMessage:
|
|
215
216
|
typeof rawErrorMessage === "string" ? rawErrorMessage : undefined,
|
|
217
|
+
recoveredFromEarlier: true,
|
|
216
218
|
};
|
|
217
219
|
}
|
|
218
220
|
return latest;
|
|
@@ -698,6 +698,7 @@ export interface TelegramInboundRouteRuntimeDeps<
|
|
|
698
698
|
) => void;
|
|
699
699
|
isIdle: (ctx: TContext) => boolean;
|
|
700
700
|
hasPendingMessages: (ctx: TContext) => boolean;
|
|
701
|
+
requestNewSession?: (source: unknown) => void;
|
|
701
702
|
compact: (
|
|
702
703
|
ctx: TContext,
|
|
703
704
|
callbacks: { onComplete: () => void; onError: (error: unknown) => void },
|
|
@@ -721,6 +722,7 @@ const TELEGRAM_OWNED_CALLBACK_PREFIXES = [
|
|
|
721
722
|
"compact:",
|
|
722
723
|
"menu:",
|
|
723
724
|
"model:",
|
|
725
|
+
"new:",
|
|
724
726
|
"queue:",
|
|
725
727
|
"section:",
|
|
726
728
|
"settings:",
|
|
@@ -1560,7 +1562,9 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1560
1562
|
await deps.callApi("editForumTopic", {
|
|
1561
1563
|
chat_id: sourceTarget.chatId,
|
|
1562
1564
|
message_thread_id: sourceTarget.threadId,
|
|
1563
|
-
name:
|
|
1565
|
+
name:
|
|
1566
|
+
deps.getDisplayTitle?.(sourceTarget) ??
|
|
1567
|
+
Threads.getTelegramTopicTitleForThreadName(threadName, slot),
|
|
1564
1568
|
});
|
|
1565
1569
|
assertExecutionCurrent();
|
|
1566
1570
|
} catch (renameError) {
|
|
@@ -1717,7 +1721,9 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1717
1721
|
await deps.callApi("editForumTopic", {
|
|
1718
1722
|
chat_id: sourceTarget.chatId,
|
|
1719
1723
|
message_thread_id: sourceTarget.threadId,
|
|
1720
|
-
name:
|
|
1724
|
+
name:
|
|
1725
|
+
deps.getDisplayTitle?.(sourceTarget) ??
|
|
1726
|
+
Threads.getTelegramTopicTitleForThreadName(threadName, slot),
|
|
1721
1727
|
});
|
|
1722
1728
|
assertExecutionCurrent();
|
|
1723
1729
|
} catch (renameError) {
|
|
@@ -1966,7 +1972,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
1966
1972
|
await deps.editInteractiveMessage?.(
|
|
1967
1973
|
chatId,
|
|
1968
1974
|
dialogMessageId,
|
|
1969
|
-
"<b>✖ Rename cancelled
|
|
1975
|
+
"<b>✖ Rename cancelled.</b>",
|
|
1970
1976
|
"html",
|
|
1971
1977
|
{ inline_keyboard: [] },
|
|
1972
1978
|
);
|
|
@@ -2001,6 +2007,42 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2001
2007
|
}
|
|
2002
2008
|
return;
|
|
2003
2009
|
}
|
|
2010
|
+
const handledByNew =
|
|
2011
|
+
await Commands.handleTelegramNewConfirmationCallback(query, {
|
|
2012
|
+
ctx,
|
|
2013
|
+
answerCallbackQuery: deps.answerCallbackQuery,
|
|
2014
|
+
editInteractiveMessage: deps.editInteractiveMessage ?? (async () => {}),
|
|
2015
|
+
deleteMessage: deps.deleteMessage ?? (async () => {}),
|
|
2016
|
+
runNew: async (newCtx) => {
|
|
2017
|
+
await Commands.handleTelegramNewCommand({
|
|
2018
|
+
isIdle: () => deps.isIdle(newCtx),
|
|
2019
|
+
hasPendingMessages: () => deps.hasPendingMessages(newCtx),
|
|
2020
|
+
hasActiveTelegramTurn: deps.activeTurnRuntime.has,
|
|
2021
|
+
hasDispatchPending: deps.bridgeRuntime.lifecycle.hasDispatchPending,
|
|
2022
|
+
hasQueuedTelegramItems: deps.telegramQueueStore.hasQueuedItems,
|
|
2023
|
+
isCompactionInProgress:
|
|
2024
|
+
deps.bridgeRuntime.lifecycle.isCompactionInProgress,
|
|
2025
|
+
requestNewSession: deps.requestNewSession
|
|
2026
|
+
? () => deps.requestNewSession!(query)
|
|
2027
|
+
: undefined,
|
|
2028
|
+
sendTextReply: async (text) => {
|
|
2029
|
+
const chatId = query.message?.chat?.id;
|
|
2030
|
+
const messageId = query.message?.message_id;
|
|
2031
|
+
if (typeof chatId !== "number" || typeof messageId !== "number") return;
|
|
2032
|
+
await deps.editInteractiveMessage?.(
|
|
2033
|
+
chatId,
|
|
2034
|
+
messageId,
|
|
2035
|
+
text,
|
|
2036
|
+
"html",
|
|
2037
|
+
{ inline_keyboard: [] },
|
|
2038
|
+
);
|
|
2039
|
+
},
|
|
2040
|
+
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
2041
|
+
});
|
|
2042
|
+
},
|
|
2043
|
+
});
|
|
2044
|
+
assertExecutionCurrent();
|
|
2045
|
+
if (handledByNew) return;
|
|
2004
2046
|
const handledByCompact =
|
|
2005
2047
|
await Commands.handleTelegramCompactConfirmationCallback(query, {
|
|
2006
2048
|
ctx,
|
|
@@ -2186,6 +2228,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2186
2228
|
stopTypingLoop: deps.stopTypingLoop,
|
|
2187
2229
|
enqueueContinueTurn,
|
|
2188
2230
|
compact: deps.compact,
|
|
2231
|
+
requestNewSession: deps.requestNewSession,
|
|
2189
2232
|
allocateItemOrder: deps.bridgeRuntime.queue.allocateItemOrder,
|
|
2190
2233
|
allocateControlOrder: deps.bridgeRuntime.queue.allocateControlOrder,
|
|
2191
2234
|
appendControlItem: deps.queueMutationRuntime.append,
|
|
@@ -2515,17 +2558,31 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2515
2558
|
dialogMessageId: candidate.dialogMessageId,
|
|
2516
2559
|
});
|
|
2517
2560
|
}
|
|
2561
|
+
const replyText = result.ok && !result.message
|
|
2562
|
+
? Commands.formatTelegramAutomaticThreadDisplayNameRestoredHeading(
|
|
2563
|
+
result.threadName ?? name,
|
|
2564
|
+
)
|
|
2565
|
+
: Commands.formatTelegramInformationHeading(
|
|
2566
|
+
result.ok ? "✅" : "⚠️",
|
|
2567
|
+
result.message ?? "Thread display name reset failed.",
|
|
2568
|
+
);
|
|
2569
|
+
if (result.ok) {
|
|
2570
|
+
Updates.assertTelegramUpdateExecutionCurrent(message);
|
|
2571
|
+
Updates.reportTelegramUpdateCompleted(message);
|
|
2572
|
+
void deps.sendTextReply(
|
|
2573
|
+
target.chatId,
|
|
2574
|
+
message.message_id,
|
|
2575
|
+
replyText,
|
|
2576
|
+
{ parseMode: "HTML", target },
|
|
2577
|
+
).catch((error) => deps.recordRuntimeEvent?.("telegram-command", error, {
|
|
2578
|
+
command: "name", phase: "reset-result",
|
|
2579
|
+
}));
|
|
2580
|
+
return true;
|
|
2581
|
+
}
|
|
2518
2582
|
await deps.sendTextReply(
|
|
2519
2583
|
target.chatId,
|
|
2520
2584
|
message.message_id,
|
|
2521
|
-
|
|
2522
|
-
? Commands.formatTelegramAutomaticThreadDisplayNameRestoredHeading(
|
|
2523
|
-
result.threadName ?? name,
|
|
2524
|
-
)
|
|
2525
|
-
: Commands.formatTelegramInformationHeading(
|
|
2526
|
-
result.ok ? "✅" : "⚠️",
|
|
2527
|
-
result.message ?? "Thread display name reset failed.",
|
|
2528
|
-
),
|
|
2585
|
+
replyText,
|
|
2529
2586
|
{ parseMode: "HTML", target },
|
|
2530
2587
|
);
|
|
2531
2588
|
return true;
|
|
@@ -2557,17 +2614,31 @@ export function createTelegramInboundRouteRuntime<
|
|
|
2557
2614
|
dialogMessageId: candidate.dialogMessageId,
|
|
2558
2615
|
});
|
|
2559
2616
|
}
|
|
2617
|
+
const replyText = result?.ok && !result.message
|
|
2618
|
+
? Commands.formatTelegramThreadDisplayNameSavedHeading(
|
|
2619
|
+
result.threadName ?? consumed.name,
|
|
2620
|
+
)
|
|
2621
|
+
: Commands.formatTelegramInformationHeading(
|
|
2622
|
+
result?.ok ? "✅" : "⚠️",
|
|
2623
|
+
result?.message ?? "Thread display name update failed.",
|
|
2624
|
+
);
|
|
2625
|
+
if (result?.ok) {
|
|
2626
|
+
Updates.assertTelegramUpdateExecutionCurrent(message);
|
|
2627
|
+
Updates.reportTelegramUpdateCompleted(message);
|
|
2628
|
+
void deps.sendTextReply(
|
|
2629
|
+
target.chatId,
|
|
2630
|
+
message.message_id,
|
|
2631
|
+
replyText,
|
|
2632
|
+
{ parseMode: "HTML", target },
|
|
2633
|
+
).catch((error) => deps.recordRuntimeEvent?.("telegram-command", error, {
|
|
2634
|
+
command: "name", phase: "rename-result",
|
|
2635
|
+
}));
|
|
2636
|
+
return true;
|
|
2637
|
+
}
|
|
2560
2638
|
await deps.sendTextReply(
|
|
2561
2639
|
target.chatId,
|
|
2562
2640
|
message.message_id,
|
|
2563
|
-
|
|
2564
|
-
? Commands.formatTelegramThreadDisplayNameSavedHeading(
|
|
2565
|
-
result.threadName ?? consumed.name,
|
|
2566
|
-
)
|
|
2567
|
-
: Commands.formatTelegramInformationHeading(
|
|
2568
|
-
result?.ok ? "✅" : "⚠️",
|
|
2569
|
-
result?.message ?? "Thread display name update failed.",
|
|
2570
|
-
),
|
|
2641
|
+
replyText,
|
|
2571
2642
|
{ parseMode: "HTML", target },
|
|
2572
2643
|
);
|
|
2573
2644
|
return true;
|
|
@@ -239,6 +239,36 @@ export interface TelegramThreadDisplayReconcilerDeps {
|
|
|
239
239
|
): Promise<TResponse>;
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
export function createTelegramThreadDisplaySettingsRuntime(deps: {
|
|
243
|
+
getTarget(): { chatId: number; threadId?: number } | undefined;
|
|
244
|
+
getBinding(target: { chatId: number; threadId?: number }):
|
|
245
|
+
{ manualThreadName?: string } | undefined;
|
|
246
|
+
apply(mode: TelegramThreadDisplayMode): Promise<void>;
|
|
247
|
+
reset(target: { chatId: number; threadId?: number }):
|
|
248
|
+
Promise<{ ok: boolean; message?: string }>;
|
|
249
|
+
}): {
|
|
250
|
+
isCustom(): boolean;
|
|
251
|
+
setMode(mode: TelegramThreadDisplayMode): Promise<void>;
|
|
252
|
+
} {
|
|
253
|
+
return {
|
|
254
|
+
isCustom() {
|
|
255
|
+
const target = deps.getTarget();
|
|
256
|
+
return !!target && typeof deps.getBinding(target)?.manualThreadName === "string";
|
|
257
|
+
},
|
|
258
|
+
async setMode(mode) {
|
|
259
|
+
const target = deps.getTarget();
|
|
260
|
+
const hadManualName = !!target &&
|
|
261
|
+
typeof deps.getBinding(target)?.manualThreadName === "string";
|
|
262
|
+
await deps.apply(mode);
|
|
263
|
+
if (!hadManualName || !target) return;
|
|
264
|
+
const reset = await deps.reset(target);
|
|
265
|
+
if (!reset.ok) {
|
|
266
|
+
throw new Error(reset.message ?? "Telegram Thread display override reset failed.");
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
242
272
|
/** Caller owns triggering and reporting; no timer or background retry is created. */
|
|
243
273
|
export function createTelegramThreadDisplayReconciler(
|
|
244
274
|
deps: TelegramThreadDisplayReconcilerDeps,
|