@llblab/pi-telegram 0.52.2 → 0.53.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -7
- package/BACKLOG.md +1 -18
- package/CHANGELOG.md +15 -0
- package/README.md +7 -11
- package/api/commands.ts +3 -0
- package/dist/api/commands.d.ts +1 -1
- package/dist/lib/activity-verbosity.d.ts +1 -5
- package/dist/lib/activity-verbosity.js +15 -42
- package/dist/lib/activity.d.ts +9 -0
- package/dist/lib/activity.js +39 -10
- package/dist/lib/agent-messages.js +7 -3
- package/dist/lib/bindings.d.ts +43 -5
- package/dist/lib/bindings.js +163 -20
- package/dist/lib/bus-api.d.ts +12 -0
- package/dist/lib/bus-api.js +182 -79
- package/dist/lib/bus-follower.d.ts +111 -31
- package/dist/lib/bus-follower.js +1324 -359
- package/dist/lib/bus-leader.d.ts +41 -91
- package/dist/lib/bus-leader.js +969 -637
- package/dist/lib/bus-transport.js +16 -9
- package/dist/lib/bus.d.ts +215 -18
- package/dist/lib/bus.js +1048 -327
- package/dist/lib/channel-posts.d.ts +5 -0
- package/dist/lib/channel-posts.js +434 -261
- package/dist/lib/command-templates.d.ts +26 -5
- package/dist/lib/command-templates.js +92 -176
- package/dist/lib/commands.d.ts +168 -82
- package/dist/lib/commands.js +1409 -291
- package/dist/lib/config.d.ts +1 -8
- package/dist/lib/config.js +34 -76
- package/dist/lib/delivery.d.ts +2 -2
- package/dist/lib/delivery.js +16 -16
- package/dist/lib/extension.js +639 -171
- package/dist/lib/generative-app-worker.mjs +19 -7
- package/dist/lib/generative-apps.d.ts +0 -5
- package/dist/lib/generative-apps.js +61 -49
- package/dist/lib/inbound.d.ts +5 -0
- package/dist/lib/inbound.js +35 -59
- package/dist/lib/journal.d.ts +33 -3
- package/dist/lib/journal.js +2063 -782
- package/dist/lib/lifecycle.d.ts +2 -6
- package/dist/lib/lifecycle.js +75 -58
- package/dist/lib/locks.d.ts +29 -3
- package/dist/lib/locks.js +289 -108
- package/dist/lib/logging.js +50 -14
- package/dist/lib/media.d.ts +22 -1
- package/dist/lib/media.js +46 -28
- package/dist/lib/menu-model.d.ts +19 -5
- package/dist/lib/menu-model.js +53 -11
- package/dist/lib/menu-queue.d.ts +5 -4
- package/dist/lib/menu-queue.js +45 -63
- package/dist/lib/menu-settings.d.ts +5 -4
- package/dist/lib/menu-settings.js +114 -78
- package/dist/lib/menu-status.d.ts +1 -1
- package/dist/lib/menu-status.js +8 -25
- package/dist/lib/menu-thinking.d.ts +6 -1
- package/dist/lib/menu-thinking.js +14 -21
- package/dist/lib/menu.d.ts +8 -61
- package/dist/lib/menu.js +92 -164
- package/dist/lib/model.d.ts +1 -1
- package/dist/lib/model.js +2 -16
- package/dist/lib/outbound-attachments.d.ts +6 -27
- package/dist/lib/outbound-attachments.js +45 -38
- package/dist/lib/outbound-buttons.js +22 -16
- package/dist/lib/outbound-markup.d.ts +0 -2
- package/dist/lib/outbound-markup.js +51 -64
- package/dist/lib/outbound-voice.js +6 -3
- package/dist/lib/outbound.d.ts +6 -6
- package/dist/lib/outbound.js +65 -51
- package/dist/lib/ownership.js +6 -2
- package/dist/lib/paths.d.ts +5 -0
- package/dist/lib/paths.js +37 -21
- package/dist/lib/pi.d.ts +2 -0
- package/dist/lib/pi.js +8 -1
- package/dist/lib/polling.d.ts +21 -37
- package/dist/lib/polling.js +59 -50
- package/dist/lib/preview.js +39 -19
- package/dist/lib/process-identity.d.ts +24 -0
- package/dist/lib/process-identity.js +133 -0
- package/dist/lib/prompts.js +2 -7
- package/dist/lib/queue.d.ts +14 -16
- package/dist/lib/queue.js +252 -127
- package/dist/lib/recovery.d.ts +2 -83
- package/dist/lib/recovery.js +20 -274
- package/dist/lib/replies.d.ts +16 -24
- package/dist/lib/replies.js +99 -116
- package/dist/lib/routing.d.ts +120 -7
- package/dist/lib/routing.js +4667 -1152
- package/dist/lib/runtime.d.ts +1 -11
- package/dist/lib/sections.d.ts +4 -29
- package/dist/lib/sections.js +7 -20
- package/dist/lib/skills.js +4 -3
- package/dist/lib/status.js +86 -57
- package/dist/lib/sync.d.ts +1 -3
- package/dist/lib/sync.js +67 -43
- package/dist/lib/target.d.ts +4 -0
- package/dist/lib/target.js +18 -0
- package/dist/lib/telegram-api.d.ts +18 -13
- package/dist/lib/telegram-api.js +148 -53
- package/dist/lib/text-groups.js +4 -39
- package/dist/lib/thread-cleanup-manager.d.ts +6 -27
- package/dist/lib/thread-cleanup-manager.js +369 -186
- package/dist/lib/thread-display.d.ts +1 -2
- package/dist/lib/thread-display.js +58 -38
- package/dist/lib/thread-naming.d.ts +28 -8
- package/dist/lib/thread-naming.js +175 -66
- package/dist/lib/thread-reconciler.d.ts +42 -16
- package/dist/lib/thread-reconciler.js +90 -50
- package/dist/lib/threads.d.ts +82 -20
- package/dist/lib/threads.js +2247 -855
- package/dist/lib/time-injection.js +1 -2
- package/dist/lib/turns.js +1 -19
- package/dist/lib/updates.d.ts +169 -80
- package/dist/lib/updates.js +2418 -641
- package/dist/lib/voice.d.ts +7 -22
- package/dist/lib/voice.js +7 -22
- package/dist/lib/wire.js +1 -1
- package/dist/lib/workspace-admission.d.ts +3 -1
- package/dist/lib/workspace-admission.js +425 -211
- package/dist/lib/workspace-identity.js +8 -13
- package/dist/lib/workspace-retirement.d.ts +1 -1
- package/dist/lib/workspace-retirement.js +328 -140
- package/dist/lib/workspace-slots.js +8 -4
- package/dist/package.json +1 -1
- package/docs/architecture.md +31 -29
- package/docs/inbound.md +1 -1
- package/docs/multi-instance-bus.md +15 -3
- package/docs/outbound.md +1 -1
- package/docs/public-api.md +29 -1
- package/docs/ui-style.md +25 -8
- package/lib/activity-verbosity.ts +59 -82
- package/lib/activity.ts +146 -102
- package/lib/agent-messages.ts +12 -5
- package/lib/bindings.ts +389 -82
- package/lib/bus-api.ts +263 -102
- package/lib/bus-follower.ts +2440 -601
- package/lib/bus-leader.ts +2209 -1290
- package/lib/bus-transport.ts +46 -12
- package/lib/bus.ts +1673 -444
- package/lib/channel-posts.ts +848 -327
- package/lib/command-templates.ts +152 -265
- package/lib/commands.ts +2398 -555
- package/lib/config.ts +177 -170
- package/lib/delivery.ts +41 -29
- package/lib/extension.ts +1206 -433
- package/lib/generative-app-worker.mjs +19 -7
- package/lib/generative-apps.ts +324 -211
- package/lib/inbound.ts +95 -97
- package/lib/journal.ts +5311 -1763
- package/lib/keyboard.ts +1 -3
- package/lib/lifecycle.ts +128 -78
- package/lib/locks.ts +677 -203
- package/lib/logging.ts +147 -58
- package/lib/media.ts +82 -43
- package/lib/menu-model.ts +85 -18
- package/lib/menu-queue.ts +88 -129
- package/lib/menu-settings.ts +260 -155
- package/lib/menu-status.ts +20 -60
- package/lib/menu-thinking.ts +41 -56
- package/lib/menu.ts +112 -285
- package/lib/model.ts +8 -22
- package/lib/outbound-attachments.ts +156 -125
- package/lib/outbound-buttons.ts +76 -49
- package/lib/outbound-markup.ts +96 -94
- package/lib/outbound-voice.ts +33 -27
- package/lib/outbound.ts +128 -125
- package/lib/ownership.ts +19 -10
- package/lib/paths.ts +148 -49
- package/lib/pi.ts +35 -15
- package/lib/polling.ts +144 -147
- package/lib/preview.ts +93 -40
- package/lib/process-identity.ts +164 -0
- package/lib/prompts.ts +4 -11
- package/lib/queue.ts +516 -301
- package/lib/recovery.ts +50 -454
- package/lib/rendering.ts +1 -3
- package/lib/replies.ts +248 -209
- package/lib/routing.ts +8509 -2186
- package/lib/runtime.ts +1 -12
- package/lib/sections.ts +24 -89
- package/lib/setup.ts +1 -3
- package/lib/skills.ts +9 -4
- package/lib/status.ts +215 -110
- package/lib/sync.ts +448 -361
- package/lib/target.ts +22 -3
- package/lib/telegram-api.ts +302 -127
- package/lib/text-groups.ts +5 -39
- package/lib/thread-cleanup-manager.ts +833 -331
- package/lib/thread-display.ts +213 -97
- package/lib/thread-naming.ts +232 -87
- package/lib/thread-reconciler.ts +155 -72
- package/lib/threads.ts +5318 -1845
- package/lib/time-injection.ts +1 -4
- package/lib/turns.ts +15 -28
- package/lib/updates.ts +5184 -1612
- package/lib/voice.ts +7 -35
- package/lib/wire.ts +1 -1
- package/lib/workspace-admission.ts +996 -416
- package/lib/workspace-identity.ts +14 -17
- package/lib/workspace-retirement.ts +878 -376
- package/lib/workspace-slots.ts +22 -13
- package/package.json +1 -1
- package/scripts/check-downgrade.mjs +0 -472
- package/scripts/measure-workspace.mjs +0 -108
package/dist/lib/extension.js
CHANGED
|
@@ -11,7 +11,6 @@ import * as BusLeader from "./bus-leader.js";
|
|
|
11
11
|
import * as BusTransport from "./bus-transport.js";
|
|
12
12
|
import * as Bus from "./bus.js";
|
|
13
13
|
import * as ChannelPosts from "./channel-posts.js";
|
|
14
|
-
import * as ThreadCleanupManager from "./thread-cleanup-manager.js";
|
|
15
14
|
import * as CommandTemplates from "./command-templates.js";
|
|
16
15
|
import * as Commands from "./commands.js";
|
|
17
16
|
import * as Config from "./config.js";
|
|
@@ -32,6 +31,7 @@ import * as Paths from "./paths.js";
|
|
|
32
31
|
import * as Pi from "./pi.js";
|
|
33
32
|
import * as Polling from "./polling.js";
|
|
34
33
|
import * as Preview from "./preview.js";
|
|
34
|
+
import * as ProcessIdentity from "./process-identity.js";
|
|
35
35
|
import * as PromptTemplates from "./prompt-templates.js";
|
|
36
36
|
import * as Prompts from "./prompts.js";
|
|
37
37
|
import * as Queue from "./queue.js";
|
|
@@ -43,12 +43,13 @@ import * as Sections from "./sections.js";
|
|
|
43
43
|
import * as Skills from "./skills.js";
|
|
44
44
|
import * as Status from "./status.js";
|
|
45
45
|
import * as Sync from "./sync.js";
|
|
46
|
+
import * as Targets from "./target.js";
|
|
46
47
|
import * as TelegramApi from "./telegram-api.js";
|
|
47
48
|
import * as TextGroups from "./text-groups.js";
|
|
48
|
-
import * as
|
|
49
|
-
import * as Targets from "./target.js";
|
|
49
|
+
import * as ThreadCleanupManager from "./thread-cleanup-manager.js";
|
|
50
50
|
import * as ThreadDisplay from "./thread-display.js";
|
|
51
51
|
import * as ThreadNaming from "./thread-naming.js";
|
|
52
|
+
import * as ThreadReconciler from "./thread-reconciler.js";
|
|
52
53
|
import * as Threads from "./threads.js";
|
|
53
54
|
import * as TimeInjection from "./time-injection.js";
|
|
54
55
|
import * as Updates from "./updates.js";
|
|
@@ -64,6 +65,11 @@ const telegramBusProtocolIdentity = Bus.createTelegramCurrentBusProtocolIdentity
|
|
|
64
65
|
Bus.TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
|
|
65
66
|
Bus.TELEGRAM_BUS_CAPABILITY_SESSION_REPLACEMENT_INTENT,
|
|
66
67
|
Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE,
|
|
68
|
+
Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_SAVE,
|
|
69
|
+
Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_APPLY,
|
|
70
|
+
Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_SETTLE,
|
|
71
|
+
Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_COMMAND_SET,
|
|
72
|
+
Bus.TELEGRAM_BUS_CAPABILITY_SELECTED_MENU_DELIVERY,
|
|
67
73
|
]);
|
|
68
74
|
// --- Extension Runtime ---
|
|
69
75
|
export default function (pi) {
|
|
@@ -71,7 +77,9 @@ export default function (pi) {
|
|
|
71
77
|
const piRuntime = Pi.createExtensionApiRuntimePorts(pi);
|
|
72
78
|
const { getActiveTools, getCommands, getThinkingLevel, sendUserMessage, registerCommand, setActiveTools, setModel, setThinkingLevel, } = piRuntime;
|
|
73
79
|
const bridgeRuntime = Runtime.createTelegramBridgeRuntime();
|
|
74
|
-
const runtimeDiagnostics = Logging.createTelegramRuntimeDiagnosticsRuntime({
|
|
80
|
+
const runtimeDiagnostics = Logging.createTelegramRuntimeDiagnosticsRuntime({
|
|
81
|
+
sharedFile: true,
|
|
82
|
+
});
|
|
75
83
|
const runtimeEvents = runtimeDiagnostics.events;
|
|
76
84
|
const recordRuntimeEvent = runtimeDiagnostics.recordRuntimeEvent;
|
|
77
85
|
const configStore = Config.createTelegramConfigStore({ recordRuntimeEvent });
|
|
@@ -126,8 +134,12 @@ export default function (pi) {
|
|
|
126
134
|
getBotId: getTelegramBotId,
|
|
127
135
|
});
|
|
128
136
|
const telegramLeaderJournalPath = Locks.createTelegramLeaderJournalPathResolver({
|
|
129
|
-
getNamedJournalPath() {
|
|
130
|
-
|
|
137
|
+
getNamedJournalPath() {
|
|
138
|
+
return lockRuntime.getJournalPath();
|
|
139
|
+
},
|
|
140
|
+
getSessionId() {
|
|
141
|
+
return Pi.getExtensionContextSessionId(telegramSessionContextStore.get());
|
|
142
|
+
},
|
|
131
143
|
getProfileName: configStore.getActiveProfileName,
|
|
132
144
|
});
|
|
133
145
|
const telegramJournalBindingRuntime = Journal.createTelegramUpdateJournalBindingRuntime({
|
|
@@ -175,7 +187,6 @@ export default function (pi) {
|
|
|
175
187
|
const resolveTelegramFollowerJournalBinding = telegramJournalBindingRuntime.resolveFollower;
|
|
176
188
|
const getTelegramQueueJournalBinding = telegramJournalBindingRuntime.getActiveRecoveryKey;
|
|
177
189
|
const isTelegramBusRuntimeEnabled = telegramThreadCapabilityState.isBusRuntimeEnabled;
|
|
178
|
-
Config.bindGlobalTelegramConfigRuntime(configStore);
|
|
179
190
|
const configControls = Config.createTelegramConfigControls(configStore);
|
|
180
191
|
const lockRuntime = Locks.createTelegramLockRuntime({
|
|
181
192
|
key: Locks.createTelegramLockKeyResolver(configStore),
|
|
@@ -184,7 +195,9 @@ export default function (pi) {
|
|
|
184
195
|
busSecret: telegramBusAuthSecret,
|
|
185
196
|
staleHeartbeatMs: Locks.TELEGRAM_BUS_LEADER_STALE_HEARTBEAT_MS,
|
|
186
197
|
legacyLocksPath: Paths.resolveLegacyTelegramOwnersPath(),
|
|
187
|
-
createJournalPath() {
|
|
198
|
+
createJournalPath() {
|
|
199
|
+
return telegramLeaderJournalPath.createJournalPath();
|
|
200
|
+
},
|
|
188
201
|
});
|
|
189
202
|
const telegramSessionContextStore = Lifecycle.createTelegramSessionContextStore({
|
|
190
203
|
getIdentity(ctx) {
|
|
@@ -228,9 +241,9 @@ export default function (pi) {
|
|
|
228
241
|
instanceId: telegramInstanceId,
|
|
229
242
|
isRegisteredFor(target) {
|
|
230
243
|
const registered = telegramBusFollowerRegistrationState.getTarget();
|
|
231
|
-
return telegramBusFollowerRegistrationState.isRegistered() &&
|
|
244
|
+
return (telegramBusFollowerRegistrationState.isRegistered() &&
|
|
232
245
|
registered?.chatId === target.chatId &&
|
|
233
|
-
registered.threadId === target.threadId;
|
|
246
|
+
registered.threadId === target.threadId);
|
|
234
247
|
},
|
|
235
248
|
async requestSessionReplacement(operation, intent) {
|
|
236
249
|
const request = telegramBusFollowerRegistration.requestSessionReplacement;
|
|
@@ -241,10 +254,14 @@ export default function (pi) {
|
|
|
241
254
|
},
|
|
242
255
|
async sendResult(target, html) {
|
|
243
256
|
const delivery = await Delivery.sendTelegramView({ text: html, parseMode: "html", replyMarkup: { inline_keyboard: [] } }, { scope: { kind: "target", target } });
|
|
244
|
-
return delivery.ok
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
257
|
+
return delivery.ok
|
|
258
|
+
? { ok: true }
|
|
259
|
+
: {
|
|
260
|
+
ok: false,
|
|
261
|
+
retryable: delivery.reason === "runtime-unavailable" ||
|
|
262
|
+
delivery.reason === "target-unavailable" ||
|
|
263
|
+
delivery.reason === "transport-retryable",
|
|
264
|
+
};
|
|
248
265
|
},
|
|
249
266
|
handoffTtlMs: Threads.TELEGRAM_LEADER_SESSION_HANDOFF_TTL_MS,
|
|
250
267
|
recordRuntimeEvent,
|
|
@@ -302,13 +319,24 @@ export default function (pi) {
|
|
|
302
319
|
});
|
|
303
320
|
const telegramQueueStore = Queue.createTelegramTransportStampedQueueStore(rawTelegramQueueStore, telegramTransportStampRuntime.getStamp);
|
|
304
321
|
const telegramApiTargetActivityRuntime = TelegramApi.createTelegramApiTargetActivityRuntime();
|
|
305
|
-
|
|
306
|
-
|
|
322
|
+
// Retirement protection and dead-owner reclamation must inspect the same journal sources.
|
|
323
|
+
const workspaceRetirementJournalPorts = {
|
|
307
324
|
getActiveTurnTarget: activeTurnRuntime.getTarget,
|
|
308
325
|
getQueuedItems: telegramQueueStore.getQueuedItems,
|
|
309
326
|
resolveLeaderJournal: resolveTelegramUpdateJournalBinding,
|
|
310
327
|
createFollowerJournalResolver: telegramJournalBindingRuntime.createLegacyRecipientResolver,
|
|
311
328
|
createSessionJournalResolver: telegramJournalBindingRuntime.createRecipientResolver,
|
|
329
|
+
createJournalPathResolver: telegramJournalBindingRuntime.createPathResolver,
|
|
330
|
+
discoverFollowerJournals() {
|
|
331
|
+
return Journal.discoverTelegramRecipientJournalPaths({
|
|
332
|
+
directory: Paths.resolveTelegramTempDir(),
|
|
333
|
+
profileName: configStore.getActiveProfileName(),
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
const workspaceProtectionObserver = WorkspaceRetirement.createTelegramWorkspaceProtectionObserver({
|
|
338
|
+
listFollowers: telegramBusFollowerRegistry.list,
|
|
339
|
+
...workspaceRetirementJournalPorts,
|
|
312
340
|
withJournalReference(binding, operation) {
|
|
313
341
|
if (!binding.recoveryKey)
|
|
314
342
|
throw new Error("Telegram workspace journal reference identity is unavailable.");
|
|
@@ -317,13 +345,6 @@ export default function (pi) {
|
|
|
317
345
|
recoveryKey: binding.recoveryKey,
|
|
318
346
|
}, operation);
|
|
319
347
|
},
|
|
320
|
-
discoverFollowerJournals() {
|
|
321
|
-
return Journal.discoverTelegramRecipientJournalPaths({
|
|
322
|
-
directory: Paths.resolveTelegramTempDir(),
|
|
323
|
-
profileName: configStore.getActiveProfileName(),
|
|
324
|
-
});
|
|
325
|
-
},
|
|
326
|
-
createJournalPathResolver: telegramJournalBindingRuntime.createPathResolver,
|
|
327
348
|
inspectJournalNamespace() {
|
|
328
349
|
const botToken = configStore.getBotToken();
|
|
329
350
|
if (!botToken)
|
|
@@ -332,27 +353,40 @@ export default function (pi) {
|
|
|
332
353
|
directory: Paths.resolveTelegramTempDir(),
|
|
333
354
|
profile: configStore.getActiveProfileName() ?? "default",
|
|
334
355
|
pollingPath: telegramLeaderJournalPath.resolve(configStore.getActiveProfileName()),
|
|
335
|
-
botIdentity: Journal.createTelegramUpdateJournalBotIdentity({
|
|
336
|
-
|
|
337
|
-
|
|
356
|
+
botIdentity: Journal.createTelegramUpdateJournalBotIdentity({
|
|
357
|
+
botToken,
|
|
358
|
+
botId: getTelegramBotId(),
|
|
359
|
+
}),
|
|
360
|
+
limits: {
|
|
361
|
+
maxDirectoryEntries: 10_000,
|
|
362
|
+
maxFiles: 4096,
|
|
363
|
+
maxBytes: 64 * 1024 * 1024,
|
|
364
|
+
maxEntries: 10_000,
|
|
365
|
+
maxWork: 100_000,
|
|
366
|
+
},
|
|
338
367
|
});
|
|
339
368
|
},
|
|
340
369
|
getJournalWriterProtection(journalBindingKey) {
|
|
341
370
|
const owner = Threads.getTelegramThreadOwnerFromProfileKey(journalBindingKey);
|
|
342
371
|
if (owner.kind !== "manual-follower")
|
|
343
372
|
return "unknown";
|
|
344
|
-
const liveness =
|
|
373
|
+
const liveness = ProcessIdentity.getTelegramProcessBirthIdentityLiveness(owner.instanceId);
|
|
345
374
|
return liveness === "alive"
|
|
346
375
|
? "protected"
|
|
347
|
-
: liveness === "dead"
|
|
376
|
+
: liveness === "dead"
|
|
377
|
+
? "clear"
|
|
378
|
+
: "unknown";
|
|
348
379
|
},
|
|
349
380
|
getDeliveryAuthorityProtection(binding) {
|
|
350
|
-
const retainedRestore = resolveWorkspaceRestoreStore()
|
|
351
|
-
|
|
381
|
+
const retainedRestore = resolveWorkspaceRestoreStore()
|
|
382
|
+
?.list()
|
|
383
|
+
.some(function (intent) {
|
|
384
|
+
return (intent.request.binding.bindingKey === binding.bindingKey ||
|
|
352
385
|
Targets.areTelegramTargetsEqual(intent.request.binding.target, binding.target) ||
|
|
353
|
-
Targets.areTelegramTargetsEqual(intent.request.target, binding.target);
|
|
386
|
+
Targets.areTelegramTargetsEqual(intent.request.target, binding.target));
|
|
354
387
|
});
|
|
355
|
-
return retainedRestore ||
|
|
388
|
+
return retainedRestore ||
|
|
389
|
+
telegramApiTargetActivityRuntime.hasPendingTarget(binding.target)
|
|
356
390
|
? "protected"
|
|
357
391
|
: "clear";
|
|
358
392
|
},
|
|
@@ -367,18 +401,7 @@ export default function (pi) {
|
|
|
367
401
|
});
|
|
368
402
|
const reclaimTelegramWorkspaceDeadOwnerQueue = WorkspaceRetirement.createTelegramWorkspaceDeadOwnerQueueReclaimer({
|
|
369
403
|
getExternalProtection: captureWorkspaceExternalProtection,
|
|
370
|
-
|
|
371
|
-
getQueuedItems: telegramQueueStore.getQueuedItems,
|
|
372
|
-
resolveLeaderJournal: resolveTelegramUpdateJournalBinding,
|
|
373
|
-
createFollowerJournalResolver: telegramJournalBindingRuntime.createLegacyRecipientResolver,
|
|
374
|
-
createSessionJournalResolver: telegramJournalBindingRuntime.createRecipientResolver,
|
|
375
|
-
discoverFollowerJournals() {
|
|
376
|
-
return Journal.discoverTelegramRecipientJournalPaths({
|
|
377
|
-
directory: Paths.resolveTelegramTempDir(),
|
|
378
|
-
profileName: configStore.getActiveProfileName(),
|
|
379
|
-
});
|
|
380
|
-
},
|
|
381
|
-
createJournalPathResolver: telegramJournalBindingRuntime.createPathResolver,
|
|
404
|
+
...workspaceRetirementJournalPorts,
|
|
382
405
|
withJournalReference(binding, operation) {
|
|
383
406
|
if (!binding.recoveryKey)
|
|
384
407
|
throw new Error("Telegram workspace journal reference identity is unavailable.");
|
|
@@ -395,7 +418,7 @@ export default function (pi) {
|
|
|
395
418
|
sessionGeneration: telegramSessionContextStore.getGeneration(),
|
|
396
419
|
};
|
|
397
420
|
},
|
|
398
|
-
getQueueOwnerLiveness:
|
|
421
|
+
getQueueOwnerLiveness: ProcessIdentity.getTelegramProcessLiveness,
|
|
399
422
|
onMutationError(error) {
|
|
400
423
|
recordRuntimeEvent("Telegram dead-owner queue reclamation was refused.", {
|
|
401
424
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -406,7 +429,9 @@ export default function (pi) {
|
|
|
406
429
|
},
|
|
407
430
|
});
|
|
408
431
|
const inactiveThreadCleanupReviewRuntime = ThreadCleanupManager.createTelegramInactiveThreadCleanupReviewRuntime({
|
|
409
|
-
getProfileName() {
|
|
432
|
+
getProfileName() {
|
|
433
|
+
return configStore.getActiveProfileName() ?? "default";
|
|
434
|
+
},
|
|
410
435
|
listBindings: threadStore.listWorkspaceBindings,
|
|
411
436
|
getProtection: captureWorkspaceExternalProtection,
|
|
412
437
|
listReservations: threadStore.listReservations,
|
|
@@ -420,7 +445,9 @@ export default function (pi) {
|
|
|
420
445
|
return ThreadCleanupManager.createTelegramThreadCleanupWorkStore({
|
|
421
446
|
...Paths.resolveTelegramServiceJournalStorage("thread-cleanup", undefined, profileName),
|
|
422
447
|
profileName,
|
|
423
|
-
tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({
|
|
448
|
+
tokenSha256: Journal.createTelegramUpdateJournalBotIdentity({
|
|
449
|
+
botToken,
|
|
450
|
+
}).tokenSha256,
|
|
424
451
|
});
|
|
425
452
|
},
|
|
426
453
|
runWorkspaceOperation: telegramWorkspaceOperationRuntime.run,
|
|
@@ -484,7 +511,9 @@ export default function (pi) {
|
|
|
484
511
|
registry: telegramJournalReferenceRegistry,
|
|
485
512
|
resolveBinding: resolveTelegramUpdateJournalBinding,
|
|
486
513
|
referenceClass: "polling-cursor",
|
|
487
|
-
operation(binding) {
|
|
514
|
+
operation(binding) {
|
|
515
|
+
return binding.journal.read().acceptedThroughUpdateId;
|
|
516
|
+
},
|
|
488
517
|
});
|
|
489
518
|
},
|
|
490
519
|
getActiveSourceMessageIds: activeTurnRuntime.getSourceMessageIds,
|
|
@@ -534,7 +563,8 @@ export default function (pi) {
|
|
|
534
563
|
getBotToken: configStore.getBotToken,
|
|
535
564
|
getBotScope() {
|
|
536
565
|
const config = configStore.get();
|
|
537
|
-
return config.botUsername ??
|
|
566
|
+
return (config.botUsername ??
|
|
567
|
+
(config.botId === undefined ? undefined : String(config.botId)));
|
|
538
568
|
},
|
|
539
569
|
recordRuntimeEvent,
|
|
540
570
|
targetActivity: telegramApiTargetActivityRuntime,
|
|
@@ -762,15 +792,21 @@ export default function (pi) {
|
|
|
762
792
|
getCommands,
|
|
763
793
|
getReservedCommandNames: Commands.getTelegramReservedCommandNames,
|
|
764
794
|
});
|
|
765
|
-
const
|
|
795
|
+
const getQueueMenuState = Menu.createTelegramModelMenuStateBuilder({
|
|
766
796
|
runtime: modelMenuRuntime,
|
|
767
797
|
createSettingsManager: Pi.createSettingsManager,
|
|
768
798
|
getActiveModel: currentModelRuntime.get,
|
|
799
|
+
});
|
|
800
|
+
const menuActionPorts = {
|
|
801
|
+
getModelMenuState: getQueueMenuState,
|
|
802
|
+
getActiveModel: currentModelRuntime.get,
|
|
769
803
|
getThinkingLevel,
|
|
770
804
|
getQueueItemCount,
|
|
771
805
|
getPendingCancellationCount() {
|
|
772
|
-
return getCurrentLeaderEpoch() === undefined
|
|
773
|
-
|
|
806
|
+
return getCurrentLeaderEpoch() === undefined
|
|
807
|
+
? 0
|
|
808
|
+
: (updateAdmissionRuntimeBinding.getActive()?.getState()
|
|
809
|
+
?.abandoningClaimCount ?? 0);
|
|
774
810
|
},
|
|
775
811
|
buildStatusHtml: Commands.createTelegramAppMenuHtmlBuilder({
|
|
776
812
|
buildStatusHtml: Status.createTelegramStatusHtmlBuilder({
|
|
@@ -783,22 +819,20 @@ export default function (pi) {
|
|
|
783
819
|
storeModelMenuState: modelMenuRuntime.storeState,
|
|
784
820
|
isIdle,
|
|
785
821
|
canOfferInFlightModelSwitch: modelSwitchController.canOfferInFlightSwitch,
|
|
786
|
-
sendTextReply,
|
|
787
|
-
editInteractiveMessage,
|
|
788
|
-
sendInteractiveMessage,
|
|
789
822
|
sectionRegistry,
|
|
790
823
|
// Menu/status UI uses this to reflect whether the active Telegram turn expects voice delivery.
|
|
791
824
|
isVoiceReplyActive: function () {
|
|
792
825
|
const turn = activeTurnRuntime.get();
|
|
793
826
|
return Voice.isVoiceTurn(turn);
|
|
794
827
|
},
|
|
828
|
+
};
|
|
829
|
+
const menuActions = Menu.createTelegramMenuActionRuntime({
|
|
830
|
+
...menuActionPorts,
|
|
831
|
+
sendTextReply,
|
|
832
|
+
editInteractiveMessage,
|
|
833
|
+
sendInteractiveMessage,
|
|
795
834
|
});
|
|
796
835
|
// --- Queue And Settings Menus ---
|
|
797
|
-
const getQueueMenuState = Menu.createTelegramModelMenuStateBuilder({
|
|
798
|
-
runtime: modelMenuRuntime,
|
|
799
|
-
createSettingsManager: Pi.createSettingsManager,
|
|
800
|
-
getActiveModel: currentModelRuntime.get,
|
|
801
|
-
});
|
|
802
836
|
const queueMenuRuntime = MenuQueue.createTelegramQueueMenuRuntime({
|
|
803
837
|
telegramQueueStore,
|
|
804
838
|
queueMutationRuntime,
|
|
@@ -814,20 +848,30 @@ export default function (pi) {
|
|
|
814
848
|
});
|
|
815
849
|
const threadDisplaySettingsRuntime = ThreadDisplay.createTelegramThreadDisplaySettingsRuntime({
|
|
816
850
|
getTarget() {
|
|
817
|
-
return telegramBusFollowerRegistrationState.getTarget() ??
|
|
818
|
-
telegramBusLeaderState.getTarget();
|
|
851
|
+
return (telegramBusFollowerRegistrationState.getTarget() ??
|
|
852
|
+
telegramBusLeaderState.getTarget());
|
|
853
|
+
},
|
|
854
|
+
getBinding(target) {
|
|
855
|
+
return threadStore.getWorkspaceBindingByTarget(target);
|
|
819
856
|
},
|
|
820
|
-
getBinding(target) { return threadStore.getWorkspaceBindingByTarget(target); },
|
|
821
857
|
apply(mode) {
|
|
822
858
|
return ThreadDisplay.applyTelegramThreadDisplaySetting(mode, {
|
|
823
859
|
getProfileKey: configStore.getActiveProfileName,
|
|
824
|
-
ownsLeader() {
|
|
825
|
-
|
|
826
|
-
|
|
860
|
+
ownsLeader() {
|
|
861
|
+
return getCurrentLeaderEpoch() !== undefined;
|
|
862
|
+
},
|
|
863
|
+
getLeaderSetter() {
|
|
864
|
+
return telegramBusLeaderRuntime.setThreadDisplayMode;
|
|
865
|
+
},
|
|
866
|
+
getFollowerSetter() {
|
|
867
|
+
return telegramBusFollowerRegistration.setThreadDisplayMode;
|
|
868
|
+
},
|
|
827
869
|
reloadConfig: configStore.load,
|
|
828
870
|
});
|
|
829
871
|
},
|
|
830
|
-
reset(target) {
|
|
872
|
+
reset(target) {
|
|
873
|
+
return telegramThreadDisplayNameResetBinding.reset(target);
|
|
874
|
+
},
|
|
831
875
|
});
|
|
832
876
|
const settingsMenuRuntime = MenuSettings.createTelegramSettingsMenuRuntime({
|
|
833
877
|
reloadConfig: configStore.load,
|
|
@@ -841,7 +885,8 @@ export default function (pi) {
|
|
|
841
885
|
reviewInactiveThreads: inactiveThreadCleanupReviewRuntime.review,
|
|
842
886
|
getThreadDisplayMode() {
|
|
843
887
|
return threadStore.getBotState().threadMode === "enabled"
|
|
844
|
-
? Config.resolveTelegramThreadDisplayMode(configStore.get())
|
|
888
|
+
? Config.resolveTelegramThreadDisplayMode(configStore.get())
|
|
889
|
+
: undefined;
|
|
845
890
|
},
|
|
846
891
|
isThreadDisplayCustom: threadDisplaySettingsRuntime.isCustom,
|
|
847
892
|
async setThreadDisplayMode(mode) {
|
|
@@ -860,8 +905,42 @@ export default function (pi) {
|
|
|
860
905
|
getFollower: telegramBusFollowerRegistry.get,
|
|
861
906
|
localProtocolIdentity: telegramBusProtocolIdentity,
|
|
862
907
|
createRequestId: telegramBusFollowerClients.createRequestId,
|
|
863
|
-
getAuthSecret() {
|
|
908
|
+
getAuthSecret() {
|
|
909
|
+
return telegramBusAuthSecret;
|
|
910
|
+
},
|
|
864
911
|
});
|
|
912
|
+
const liveRebindFollowerController = Bus.createTelegramBusLiveRebindController({
|
|
913
|
+
getFollower: telegramBusFollowerRegistry.get,
|
|
914
|
+
localProtocolIdentity: telegramBusProtocolIdentity,
|
|
915
|
+
createRequestId: telegramBusFollowerClients.createRequestId,
|
|
916
|
+
getAuthSecret() {
|
|
917
|
+
return telegramBusAuthSecret;
|
|
918
|
+
},
|
|
919
|
+
});
|
|
920
|
+
const liveFollowerPorts = {
|
|
921
|
+
getJournalBindingKey(follower) {
|
|
922
|
+
if (!follower.profileKey || !follower.sessionId)
|
|
923
|
+
return undefined;
|
|
924
|
+
return telegramJournalBindingRuntime.createRecipientResolver(follower.profileKey, follower.sessionId)()?.recoveryKey;
|
|
925
|
+
},
|
|
926
|
+
isSelectedCommandAvailable(follower, name) {
|
|
927
|
+
return (Bus.hasTelegramBusSharedCapabilities(telegramBusProtocolIdentity, follower.protocol, [
|
|
928
|
+
...Bus.TELEGRAM_BUS_LIVE_REBIND_CAPABILITIES,
|
|
929
|
+
...Bus.TELEGRAM_BUS_HELD_COMMAND_CAPABILITIES,
|
|
930
|
+
]) &&
|
|
931
|
+
typeof selectedMenuDelivery === "function" &&
|
|
932
|
+
typeof inboundRouteRuntime.prepareHeldCommand === "function" &&
|
|
933
|
+
typeof inboundRouteRuntime.canPrepareHeldCommand === "function" &&
|
|
934
|
+
inboundRouteRuntime.canPrepareHeldCommand(name, {
|
|
935
|
+
showStatus: menuActions.sendStatusMessage,
|
|
936
|
+
sendTextReply,
|
|
937
|
+
}) &&
|
|
938
|
+
!!captureTelegramStateAuthority() &&
|
|
939
|
+
!!workspaceAdmissionRuntime.resolve() &&
|
|
940
|
+
!!resolveWorkspaceRestoreStore());
|
|
941
|
+
},
|
|
942
|
+
run: liveRebindFollowerController,
|
|
943
|
+
};
|
|
865
944
|
const observedThreadTargetBinding = Polling.createTelegramThreadTargetObservationBinding();
|
|
866
945
|
const topicLifecycleSync = Sync.createTelegramObservedTopicLifecycleSyncHandler({
|
|
867
946
|
topicTargetStore: threadStore,
|
|
@@ -890,6 +969,18 @@ export default function (pi) {
|
|
|
890
969
|
});
|
|
891
970
|
const telegramThreadDisplayNameRenameBinding = Commands.createTelegramThreadDisplayNameRenameBinding();
|
|
892
971
|
const telegramThreadDisplayNameResetBinding = Commands.createTelegramThreadDisplayNameResetBinding();
|
|
972
|
+
const observeLiveTargetWork = Bindings.createTelegramLiveTargetWorkObserver({
|
|
973
|
+
queue: telegramQueueStore,
|
|
974
|
+
activeTurn: activeTurnRuntime,
|
|
975
|
+
lifecycle: bridgeRuntime.lifecycle,
|
|
976
|
+
isIdle,
|
|
977
|
+
hasPendingMessages,
|
|
978
|
+
hasPendingControl: pendingModelSwitchStore.has,
|
|
979
|
+
publication: publicationRuntime,
|
|
980
|
+
activity: activityRuntime,
|
|
981
|
+
delivery: deliveryLifecycleRuntime,
|
|
982
|
+
api: telegramApiTargetActivityRuntime,
|
|
983
|
+
});
|
|
893
984
|
const inboundRouteRuntime = Routing.createTelegramInboundRouteRuntime({
|
|
894
985
|
configStore,
|
|
895
986
|
callApi: callTelegramApi,
|
|
@@ -898,6 +989,7 @@ export default function (pi) {
|
|
|
898
989
|
},
|
|
899
990
|
getAdmissionScope: getTelegramUpdateAdmissionScope,
|
|
900
991
|
getAdmissionJournalBinding: getTelegramQueueJournalBinding,
|
|
992
|
+
beginCommandEffectWork: publicationRuntime.beginWork,
|
|
901
993
|
getMessageOwnership: messageOwnershipRuntime.getForwardOwnership,
|
|
902
994
|
recordMessageOwnership: messageOwnershipRuntime.recordRouted,
|
|
903
995
|
...inboundBusProjectionRuntime,
|
|
@@ -915,24 +1007,40 @@ export default function (pi) {
|
|
|
915
1007
|
getSessionId: Pi.getExtensionContextSessionId,
|
|
916
1008
|
getCwd: Pi.getExtensionContextCwd,
|
|
917
1009
|
getLeaderIdentity: telegramBusLeaderState.getIdentity,
|
|
1010
|
+
observeLeaderWork: observeLiveTargetWork,
|
|
918
1011
|
followerRegistry: telegramBusFollowerRegistry,
|
|
919
1012
|
runFollower: workspaceRestoreFollowerController,
|
|
1013
|
+
liveFollower: liveFollowerPorts,
|
|
920
1014
|
},
|
|
921
1015
|
getWorkspaceRestoreStore: resolveWorkspaceRestoreStore,
|
|
922
1016
|
captureWorkspaceExternalProtection,
|
|
923
1017
|
inspectRestoreSourceCompletion(expected) {
|
|
924
|
-
return telegramJournalReferenceRegistry.withReference({
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1018
|
+
return telegramJournalReferenceRegistry.withReference({
|
|
1019
|
+
referenceClass: "operator-disposition",
|
|
1020
|
+
recoveryKey: expected.journalBindingKey,
|
|
1021
|
+
}, function () {
|
|
1022
|
+
const observed = telegramJournalBindingRuntime.inspectSourceCompletion(expected.journalBindingKey, {
|
|
1023
|
+
updateId: expected.updateId,
|
|
1024
|
+
sourceSha256: expected.sourceSha256,
|
|
1025
|
+
completionSha256: expected.completionSha256,
|
|
1026
|
+
});
|
|
1027
|
+
return (observed && {
|
|
1028
|
+
journalBindingKey: expected.journalBindingKey,
|
|
1029
|
+
...observed,
|
|
1030
|
+
});
|
|
929
1031
|
});
|
|
930
1032
|
},
|
|
931
1033
|
inspectRestoreQueuedReceipt(expected) {
|
|
932
|
-
return telegramJournalReferenceRegistry.withReference({
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1034
|
+
return telegramJournalReferenceRegistry.withReference({
|
|
1035
|
+
referenceClass: "operator-disposition",
|
|
1036
|
+
recoveryKey: expected.journalBindingKey,
|
|
1037
|
+
}, function () {
|
|
1038
|
+
return telegramJournalBindingRuntime.inspectQueuedReceipt(expected.journalBindingKey, {
|
|
1039
|
+
queueKind: expected.queueKind,
|
|
1040
|
+
receiptId: expected.receiptId,
|
|
1041
|
+
sourceUpdateIds: [...expected.sourceUpdateIds],
|
|
1042
|
+
queueOwner: { ...expected.queueOwner },
|
|
1043
|
+
});
|
|
936
1044
|
});
|
|
937
1045
|
},
|
|
938
1046
|
inspectRestoreSourceAbandonment(updateId, journalBindingKey) {
|
|
@@ -944,31 +1052,72 @@ export default function (pi) {
|
|
|
944
1052
|
});
|
|
945
1053
|
},
|
|
946
1054
|
inspectRoutingInputGroupExpiry(input) {
|
|
947
|
-
return telegramJournalReferenceRegistry.withReference({
|
|
1055
|
+
return telegramJournalReferenceRegistry.withReference({
|
|
1056
|
+
referenceClass: "operator-disposition",
|
|
1057
|
+
recoveryKey: input.journalBindingKey,
|
|
1058
|
+
}, function () {
|
|
1059
|
+
return telegramJournalBindingRuntime.inspectSourceGroupExpiry(input.journalBindingKey, input.updateIds);
|
|
1060
|
+
});
|
|
948
1061
|
},
|
|
949
|
-
inspectTemporaryThreadSources(
|
|
1062
|
+
inspectTemporaryThreadSources(target, requiredJournalBindingKeys, ownInputs) {
|
|
950
1063
|
const binding = resolveTelegramUpdateJournalBinding();
|
|
951
1064
|
const botToken = configStore.getBotToken();
|
|
952
1065
|
if (!binding || !botToken)
|
|
953
1066
|
return undefined;
|
|
954
1067
|
const profile = configStore.getActiveProfileName() ?? "default";
|
|
955
|
-
const botIdentity = Journal.createTelegramUpdateJournalBotIdentity({
|
|
1068
|
+
const botIdentity = Journal.createTelegramUpdateJournalBotIdentity({
|
|
1069
|
+
botToken,
|
|
1070
|
+
botId: getTelegramBotId(),
|
|
1071
|
+
});
|
|
956
1072
|
return configStore.withSourceSerialization(function () {
|
|
957
1073
|
return Journal.isTelegramThreadCleanupJournalNamespaceClear({
|
|
958
|
-
directory: Paths.resolveTelegramTempDir(),
|
|
1074
|
+
directory: Paths.resolveTelegramTempDir(),
|
|
1075
|
+
profile,
|
|
1076
|
+
botIdentity,
|
|
959
1077
|
pollingPath: telegramLeaderJournalPath.resolve(configStore.getActiveProfileName()),
|
|
960
|
-
requiredJournalBindingKeys: [
|
|
961
|
-
|
|
962
|
-
|
|
1078
|
+
requiredJournalBindingKeys: [
|
|
1079
|
+
binding.recoveryKey,
|
|
1080
|
+
...requiredJournalBindingKeys,
|
|
1081
|
+
],
|
|
1082
|
+
...(target.threadId !== undefined && ownInputs
|
|
1083
|
+
? {
|
|
1084
|
+
cleanup: {
|
|
1085
|
+
target: { chatId: target.chatId, threadId: target.threadId },
|
|
1086
|
+
ownInputs,
|
|
1087
|
+
},
|
|
1088
|
+
}
|
|
1089
|
+
: {}),
|
|
1090
|
+
limits: {
|
|
1091
|
+
maxDirectoryEntries: 10_000,
|
|
1092
|
+
maxFiles: 4096,
|
|
1093
|
+
maxBytes: 64 * 1024 * 1024,
|
|
1094
|
+
maxEntries: 10_000,
|
|
1095
|
+
maxWork: 100_000,
|
|
1096
|
+
},
|
|
963
1097
|
withSourceReference(path, operation) {
|
|
964
|
-
return telegramJournalReferenceRegistry.withReference({
|
|
965
|
-
|
|
1098
|
+
return telegramJournalReferenceRegistry.withReference({
|
|
1099
|
+
referenceClass: "operator-disposition",
|
|
1100
|
+
recoveryKey: Journal.createTelegramUpdateJournalBindingKey({
|
|
1101
|
+
path,
|
|
1102
|
+
profileName: profile,
|
|
1103
|
+
botIdentity,
|
|
1104
|
+
}),
|
|
1105
|
+
}, operation);
|
|
966
1106
|
},
|
|
967
|
-
})
|
|
1107
|
+
})
|
|
1108
|
+
? []
|
|
1109
|
+
: undefined;
|
|
968
1110
|
});
|
|
969
1111
|
},
|
|
970
1112
|
hasWorkspaceRestoreAuthority() {
|
|
971
|
-
return lockRuntime.owns() &&
|
|
1113
|
+
return (lockRuntime.owns() &&
|
|
1114
|
+
Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE));
|
|
1115
|
+
},
|
|
1116
|
+
hasWorkspaceLiveRebindAuthority() {
|
|
1117
|
+
return (lockRuntime.owns() &&
|
|
1118
|
+
Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_SAVE) &&
|
|
1119
|
+
Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_APPLY) &&
|
|
1120
|
+
Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_SETTLE));
|
|
972
1121
|
},
|
|
973
1122
|
getSessionGeneration: telegramSessionContextStore.getGeneration,
|
|
974
1123
|
bridgeRuntime,
|
|
@@ -1007,6 +1156,7 @@ export default function (pi) {
|
|
|
1007
1156
|
currentModelRuntime,
|
|
1008
1157
|
modelSwitchController,
|
|
1009
1158
|
menuActions,
|
|
1159
|
+
isVoiceReplyActive: menuActionPorts.isVoiceReplyActive,
|
|
1010
1160
|
updateSettingsMenuMessage: settingsMenuRuntime.updateSettingsMenuMessage,
|
|
1011
1161
|
openQueueMenu: queueMenuRuntime.openQueueMenu,
|
|
1012
1162
|
queueMenuCallbackHandler: queueMenuRuntime.handleCallbackQuery,
|
|
@@ -1019,6 +1169,7 @@ export default function (pi) {
|
|
|
1019
1169
|
inboundHandlerRuntime,
|
|
1020
1170
|
threadStore,
|
|
1021
1171
|
runWorkspaceOperation: telegramWorkspaceOperationRuntime.run,
|
|
1172
|
+
liveRebindCleanupSchedule: Routing.TELEGRAM_LIVE_REBIND_CLEANUP_SCHEDULE,
|
|
1022
1173
|
updateStatus,
|
|
1023
1174
|
isContextActive: telegramSessionContextStore.isCurrent,
|
|
1024
1175
|
dispatchNextQueuedTelegramTurn,
|
|
@@ -1038,6 +1189,22 @@ export default function (pi) {
|
|
|
1038
1189
|
startGuestPlaceholder: guestPlaceholderRuntime.start,
|
|
1039
1190
|
sendTextReply,
|
|
1040
1191
|
setMyCommands,
|
|
1192
|
+
captureThreadNameRecipientAuthority(target, ctx) {
|
|
1193
|
+
// Ordinary follower/classic dialogs keep their unguarded policy; closures are leader-local only.
|
|
1194
|
+
if (telegramBusFollowerRegistrationState.isRegistered() ||
|
|
1195
|
+
target.threadId === undefined)
|
|
1196
|
+
return undefined;
|
|
1197
|
+
return Threads.createTelegramWorkspaceThreadRenameRecipient({
|
|
1198
|
+
store: threadStore,
|
|
1199
|
+
instanceId: telegramInstanceId,
|
|
1200
|
+
target,
|
|
1201
|
+
assertAuthority() {
|
|
1202
|
+
if (telegramSessionContextStore.get() !== ctx)
|
|
1203
|
+
throw new Error("Telegram Thread name dialog lost Pi context.");
|
|
1204
|
+
},
|
|
1205
|
+
getAuthority: threadNameRecipientAuthority.getAuthority,
|
|
1206
|
+
}).assertAuthority;
|
|
1207
|
+
},
|
|
1041
1208
|
validateThreadName(threadName) {
|
|
1042
1209
|
return ThreadNaming.getTelegramManualThreadDisplayNameValidationError(threadName);
|
|
1043
1210
|
},
|
|
@@ -1110,16 +1277,21 @@ export default function (pi) {
|
|
|
1110
1277
|
if (verdict === "retain")
|
|
1111
1278
|
return verdict;
|
|
1112
1279
|
const journalBindingKey = getTelegramQueueJournalBinding();
|
|
1113
|
-
if (journalBindingKey &&
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1280
|
+
if (journalBindingKey &&
|
|
1281
|
+
resolveWorkspaceRestoreStore()
|
|
1282
|
+
?.list()
|
|
1283
|
+
.some(function (intent) {
|
|
1284
|
+
return (intent.request.source.journalBindingKey === journalBindingKey &&
|
|
1285
|
+
intent.request.source.updateIds.includes(entry.updateId));
|
|
1286
|
+
}))
|
|
1117
1287
|
return true;
|
|
1118
1288
|
return verdict;
|
|
1119
1289
|
},
|
|
1120
1290
|
spendHistoricalInput: true,
|
|
1121
1291
|
onHeldSourcesPrepared(input) {
|
|
1122
|
-
return inboundRouteRuntime
|
|
1292
|
+
return inboundRouteRuntime
|
|
1293
|
+
.forgetPreviousWorld(input, lockedPollingRuntime.captureTransportAuthority)
|
|
1294
|
+
.then(function () { });
|
|
1123
1295
|
},
|
|
1124
1296
|
async shouldHoldPendingInput(entry, ctx, signal) {
|
|
1125
1297
|
if (signal.aborted || !telegramSessionContextStore.isCurrent(ctx)) {
|
|
@@ -1141,7 +1313,7 @@ export default function (pi) {
|
|
|
1141
1313
|
isRegistered: telegramBusFollowerRegistrationState.isRegistered,
|
|
1142
1314
|
getGeneration: telegramBusFollowerRegistrationState.getGeneration,
|
|
1143
1315
|
prepareBinding(binding) {
|
|
1144
|
-
telegramJournalBindingRuntime.prepareActiveFollowerSuccession(function
|
|
1316
|
+
telegramJournalBindingRuntime.prepareActiveFollowerSuccession(function () {
|
|
1145
1317
|
return binding.hasAuthority?.() === true;
|
|
1146
1318
|
});
|
|
1147
1319
|
},
|
|
@@ -1214,25 +1386,38 @@ export default function (pi) {
|
|
|
1214
1386
|
local: agentMessageRuntime,
|
|
1215
1387
|
follower: telegramBusFollowerClients.agentMessages,
|
|
1216
1388
|
});
|
|
1217
|
-
const
|
|
1389
|
+
const followerWorkspaceTargetContextPorts = {
|
|
1390
|
+
isContextCurrent: telegramSessionContextStore.isCurrent,
|
|
1391
|
+
getSessionId: Pi.getExtensionContextSessionId,
|
|
1392
|
+
getCwd: Pi.getExtensionContextCwd,
|
|
1393
|
+
getGeneration: telegramSessionContextStore.getGeneration,
|
|
1394
|
+
getProfileBindingKey() {
|
|
1395
|
+
return workspaceAdmissionRuntime.resolve()?.getProfileKey();
|
|
1396
|
+
},
|
|
1397
|
+
getOperatorUserId: configStore.getAllowedUserId,
|
|
1398
|
+
getLeaderState: lockRuntime.getState,
|
|
1399
|
+
getAuthenticatedSecret: telegramBusFollowerControlState.getActiveAuthSecret,
|
|
1400
|
+
getLeaderProtocol: telegramBusFollowerRegistrationState.getLeaderProtocol,
|
|
1401
|
+
};
|
|
1402
|
+
const followerWorkspaceTargetOwnerPorts = {
|
|
1218
1403
|
instanceId: telegramInstanceId,
|
|
1219
|
-
getContextAuthority: BusFollower.createTelegramBusFollowerRestoreContextGetter({
|
|
1220
|
-
isContextCurrent: telegramSessionContextStore.isCurrent,
|
|
1221
|
-
getSessionId: Pi.getExtensionContextSessionId,
|
|
1222
|
-
getCwd: Pi.getExtensionContextCwd,
|
|
1223
|
-
getGeneration: telegramSessionContextStore.getGeneration,
|
|
1224
|
-
getProfileBindingKey() {
|
|
1225
|
-
return workspaceAdmissionRuntime.resolve()?.getProfileKey();
|
|
1226
|
-
},
|
|
1227
|
-
getOperatorUserId: configStore.getAllowedUserId,
|
|
1228
|
-
getLeaderState: lockRuntime.getState,
|
|
1229
|
-
getAuthenticatedSecret: telegramBusFollowerControlState.getActiveAuthSecret,
|
|
1230
|
-
getLeaderProtocol: telegramBusFollowerRegistrationState.getLeaderProtocol,
|
|
1231
|
-
}),
|
|
1232
1404
|
readRestoreIntent(operationId, profileBindingKey) {
|
|
1233
|
-
if (profileBindingKey !==
|
|
1405
|
+
if (profileBindingKey !==
|
|
1406
|
+
workspaceAdmissionRuntime.resolve()?.getProfileKey())
|
|
1234
1407
|
return undefined;
|
|
1235
|
-
return resolveWorkspaceRestoreStore()
|
|
1408
|
+
return resolveWorkspaceRestoreStore()
|
|
1409
|
+
?.list()
|
|
1410
|
+
.find(function (intent) {
|
|
1411
|
+
return intent.request.operationId === operationId;
|
|
1412
|
+
});
|
|
1413
|
+
},
|
|
1414
|
+
readLiveRebindIntent(operationId, profileBindingKey) {
|
|
1415
|
+
if (profileBindingKey !==
|
|
1416
|
+
workspaceAdmissionRuntime.resolve()?.getProfileKey())
|
|
1417
|
+
return undefined;
|
|
1418
|
+
return resolveWorkspaceRestoreStore()
|
|
1419
|
+
?.listLiveRebindings()
|
|
1420
|
+
.find(function (intent) {
|
|
1236
1421
|
return intent.request.operationId === operationId;
|
|
1237
1422
|
});
|
|
1238
1423
|
},
|
|
@@ -1240,6 +1425,91 @@ export default function (pi) {
|
|
|
1240
1425
|
registrationState: telegramBusFollowerRegistrationState,
|
|
1241
1426
|
getWorkspaceAdmission: workspaceAdmissionRuntime.resolve,
|
|
1242
1427
|
recordRuntimeEvent,
|
|
1428
|
+
};
|
|
1429
|
+
const followerWorkspaceRestore = BusFollower.createTelegramBusFollowerWorkspaceRestoreHandler({
|
|
1430
|
+
...followerWorkspaceTargetOwnerPorts,
|
|
1431
|
+
getContextAuthority: BusFollower.createTelegramBusFollowerRestoreContextGetter(followerWorkspaceTargetContextPorts),
|
|
1432
|
+
});
|
|
1433
|
+
const followerLiveRebindTarget = BusFollower.createTelegramBusFollowerWorkspaceRestoreHandler({
|
|
1434
|
+
...followerWorkspaceTargetOwnerPorts,
|
|
1435
|
+
getContextAuthority: BusFollower.createTelegramBusFollowerRestoreContextGetter({
|
|
1436
|
+
...followerWorkspaceTargetContextPorts,
|
|
1437
|
+
capability: Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_APPLY,
|
|
1438
|
+
}),
|
|
1439
|
+
});
|
|
1440
|
+
const selectedMenuCaller = BusFollower.createTelegramBusFollowerSelectedMenuCaller({
|
|
1441
|
+
client: {
|
|
1442
|
+
socketPath: getTelegramBusSocketPath,
|
|
1443
|
+
instanceId: telegramInstanceId,
|
|
1444
|
+
createRequestId: telegramBusFollowerClients.createRequestId,
|
|
1445
|
+
getAuthSecret: telegramBusFollowerControlState.getActiveAuthSecret,
|
|
1446
|
+
getRegistrationGeneration: telegramBusFollowerRegistrationState.getGeneration,
|
|
1447
|
+
},
|
|
1448
|
+
protocolIdentity: telegramBusProtocolIdentity,
|
|
1449
|
+
recipient: {
|
|
1450
|
+
getContextAuthority: BusFollower.createTelegramBusFollowerRestoreContextGetter({
|
|
1451
|
+
...followerWorkspaceTargetContextPorts,
|
|
1452
|
+
// Wire recipient identity is the registered profile key, not the admission namespace.
|
|
1453
|
+
getProfileBindingKey: getTelegramManualFollowerProfileKey,
|
|
1454
|
+
capability: Bus.TELEGRAM_BUS_CAPABILITY_SELECTED_MENU_DELIVERY,
|
|
1455
|
+
}),
|
|
1456
|
+
getJournalBindingKey: followerAdmissionLifecycleRuntime.getJournalBindingKey,
|
|
1457
|
+
getProcessIdentity() {
|
|
1458
|
+
return {
|
|
1459
|
+
processId: telegramProcessId,
|
|
1460
|
+
processBirthId: telegramQueueProcessBirthId,
|
|
1461
|
+
};
|
|
1462
|
+
},
|
|
1463
|
+
registrationState: telegramBusFollowerRegistrationState,
|
|
1464
|
+
},
|
|
1465
|
+
});
|
|
1466
|
+
const followerLiveRebindRuntime = BusFollower.createTelegramBusFollowerLiveRebindRuntime({
|
|
1467
|
+
getAdmission(ctx) {
|
|
1468
|
+
return telegramSessionContextStore.isCurrent(ctx)
|
|
1469
|
+
? followerAdmissionLifecycleRuntime
|
|
1470
|
+
: undefined;
|
|
1471
|
+
},
|
|
1472
|
+
applyTarget: followerLiveRebindTarget,
|
|
1473
|
+
getCommandOwner(input, ctx) {
|
|
1474
|
+
if (!Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_COMMAND_SET) ||
|
|
1475
|
+
!Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_SELECTED_MENU_DELIVERY) ||
|
|
1476
|
+
!input.selectedCommand ||
|
|
1477
|
+
!telegramSessionContextStore.isCurrent(ctx) ||
|
|
1478
|
+
followerAdmissionLifecycleRuntime.getJournalBindingKey() !==
|
|
1479
|
+
input.recipientBindingKey)
|
|
1480
|
+
return undefined;
|
|
1481
|
+
const recipient = followerLiveRebindTarget.prepareLiveCommandRecipient({
|
|
1482
|
+
operationId: input.operationId,
|
|
1483
|
+
registrationGeneration: input.recipientRegistrationGeneration,
|
|
1484
|
+
sessionId: input.recipientSessionId,
|
|
1485
|
+
sourceUpdateIds: input.updates.map(function sourceUpdateId(update) {
|
|
1486
|
+
return update.update_id;
|
|
1487
|
+
}),
|
|
1488
|
+
target: input.selectedCommand.target,
|
|
1489
|
+
}, ctx);
|
|
1490
|
+
return (recipient &&
|
|
1491
|
+
Bindings.createTelegramFollowerSelectedCommandBinding({
|
|
1492
|
+
ctx,
|
|
1493
|
+
operationId: input.operationId,
|
|
1494
|
+
registrationGeneration: input.recipientRegistrationGeneration,
|
|
1495
|
+
name: input.selectedCommand.name,
|
|
1496
|
+
target: input.selectedCommand.target,
|
|
1497
|
+
recipient,
|
|
1498
|
+
command: inboundRouteRuntime,
|
|
1499
|
+
menu: menuActionPorts,
|
|
1500
|
+
recordOwnership: messageOwnershipRuntime.recordLocal,
|
|
1501
|
+
deliver(effect, assertAuthority) {
|
|
1502
|
+
return selectedMenuCaller({
|
|
1503
|
+
ctx,
|
|
1504
|
+
operationId: input.operationId,
|
|
1505
|
+
registrationGeneration: input.recipientRegistrationGeneration,
|
|
1506
|
+
effect,
|
|
1507
|
+
assertAuthority,
|
|
1508
|
+
});
|
|
1509
|
+
},
|
|
1510
|
+
}));
|
|
1511
|
+
},
|
|
1512
|
+
observeWork: observeLiveTargetWork,
|
|
1243
1513
|
});
|
|
1244
1514
|
const telegramBusFollowerAssembly = BusFollower.createTelegramBusFollowerRuntimeAssembly({
|
|
1245
1515
|
instanceId: telegramInstanceId,
|
|
@@ -1250,12 +1520,36 @@ export default function (pi) {
|
|
|
1250
1520
|
getContext: telegramSessionContextStore.get,
|
|
1251
1521
|
getAuthSecret: telegramBusFollowerControlState.getActiveAuthSecret,
|
|
1252
1522
|
getRecipientBindingKey: getTelegramManualFollowerProfileKey,
|
|
1523
|
+
getLiveRebindJournalBindingKey: followerAdmissionLifecycleRuntime.getJournalBindingKey,
|
|
1524
|
+
getSessionId() {
|
|
1525
|
+
return telegramBusFollowerAssembly.getReadySessionId();
|
|
1526
|
+
},
|
|
1527
|
+
getLeaderProtocol: telegramBusFollowerRegistrationState.getLeaderProtocol,
|
|
1528
|
+
getLocalProtocol() {
|
|
1529
|
+
return telegramBusProtocolIdentity;
|
|
1530
|
+
},
|
|
1531
|
+
isLiveRebindSaveEnabled() {
|
|
1532
|
+
return Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_SAVE);
|
|
1533
|
+
},
|
|
1534
|
+
isLiveRebindApplyEnabled() {
|
|
1535
|
+
return Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_APPLY);
|
|
1536
|
+
},
|
|
1537
|
+
isLiveRebindSettleEnabled() {
|
|
1538
|
+
return Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_SETTLE);
|
|
1539
|
+
},
|
|
1540
|
+
isLiveRebindCommandSetEnabled() {
|
|
1541
|
+
return (Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_LIVE_REBIND_COMMAND_SET) &&
|
|
1542
|
+
Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_SELECTED_MENU_DELIVERY));
|
|
1543
|
+
},
|
|
1544
|
+
handleLiveRebindSave: followerLiveRebindRuntime.save,
|
|
1545
|
+
handleLiveRebindApply: followerLiveRebindRuntime.apply,
|
|
1546
|
+
handleLiveRebindSettle: followerLiveRebindRuntime.settle,
|
|
1253
1547
|
durableAdmission: followerDurableAdmissionRuntime,
|
|
1254
1548
|
handleQueueHandoff: acceptStagedQueueHandoff,
|
|
1255
1549
|
handleWorkspaceRestore: followerWorkspaceRestore,
|
|
1256
1550
|
isWorkspaceRestoreEnabled() {
|
|
1257
|
-
return Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) &&
|
|
1258
|
-
Bus.hasTelegramBusCapability(telegramBusFollowerRegistrationState.getLeaderProtocol(), Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE);
|
|
1551
|
+
return (Bus.hasTelegramBusCapability(telegramBusProtocolIdentity, Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE) &&
|
|
1552
|
+
Bus.hasTelegramBusCapability(telegramBusFollowerRegistrationState.getLeaderProtocol(), Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_RESTORE));
|
|
1259
1553
|
},
|
|
1260
1554
|
},
|
|
1261
1555
|
recovery: {
|
|
@@ -1292,7 +1586,7 @@ export default function (pi) {
|
|
|
1292
1586
|
const { admission: pollingAdmissionRuntime } = Polling.createTelegramDurablePollingRuntimeAssembly({
|
|
1293
1587
|
state: pollingControllerState,
|
|
1294
1588
|
canStart(ctx) {
|
|
1295
|
-
return telegramSessionContextStore.isCurrent(ctx) && lockRuntime.owns(ctx);
|
|
1589
|
+
return (telegramSessionContextStore.isCurrent(ctx) && lockRuntime.owns(ctx));
|
|
1296
1590
|
},
|
|
1297
1591
|
onPersistentConflict(ctx, count) {
|
|
1298
1592
|
return lockedPollingRuntime.onPersistentConflict(ctx, count);
|
|
@@ -1312,7 +1606,9 @@ export default function (pi) {
|
|
|
1312
1606
|
registry: telegramJournalReferenceRegistry,
|
|
1313
1607
|
resolveBinding: resolveTelegramUpdateJournalBinding,
|
|
1314
1608
|
referenceClass: "polling-cursor",
|
|
1315
|
-
operation(binding) {
|
|
1609
|
+
operation(binding) {
|
|
1610
|
+
return binding.journal.read().acceptedThroughUpdateId;
|
|
1611
|
+
},
|
|
1316
1612
|
});
|
|
1317
1613
|
},
|
|
1318
1614
|
async prepareCursorCutover() {
|
|
@@ -1341,12 +1637,14 @@ export default function (pi) {
|
|
|
1341
1637
|
getEntryCount: updateAdmissionLifecycleRuntime.getJournalEntryCount,
|
|
1342
1638
|
signalWorker: updateAdmissionLifecycleRuntime.signal,
|
|
1343
1639
|
getBootstrapEntryCount() {
|
|
1344
|
-
return Journal.withTelegramResolvedUpdateJournalReference({
|
|
1640
|
+
return (Journal.withTelegramResolvedUpdateJournalReference({
|
|
1345
1641
|
registry: telegramJournalReferenceRegistry,
|
|
1346
1642
|
resolveBinding: resolveTelegramUpdateJournalBinding,
|
|
1347
1643
|
referenceClass: "polling-bootstrap",
|
|
1348
|
-
operation(binding) {
|
|
1349
|
-
|
|
1644
|
+
operation(binding) {
|
|
1645
|
+
return binding.journal.read().entries.length;
|
|
1646
|
+
},
|
|
1647
|
+
}) ?? 0);
|
|
1350
1648
|
},
|
|
1351
1649
|
onSessionStart: updateAdmissionLifecycleRuntime.onSessionStart,
|
|
1352
1650
|
},
|
|
@@ -1358,13 +1656,59 @@ export default function (pi) {
|
|
|
1358
1656
|
const authorizeFollowerApiCall = Bus.createTelegramFollowerApiCallAuthorizer({
|
|
1359
1657
|
isMessageOwned: messageOwnershipRuntime.isOwnedByFollower,
|
|
1360
1658
|
});
|
|
1659
|
+
const selectedMenuDelivery = BusLeader.createTelegramBusSelectedMenuDeliveryHandler({
|
|
1660
|
+
followerRegistry: telegramBusFollowerRegistry,
|
|
1661
|
+
protocolIdentity: telegramBusProtocolIdentity,
|
|
1662
|
+
workspace: {
|
|
1663
|
+
getScopeKey() {
|
|
1664
|
+
return workspaceAdmissionRuntime.resolve()?.getProfileKey();
|
|
1665
|
+
},
|
|
1666
|
+
captureAuthority() {
|
|
1667
|
+
const isCurrent = captureTelegramStateAuthority(), epoch = lockRuntime.getOwnedLeaderEpoch(), operatorUserId = configStore.getAllowedUserId();
|
|
1668
|
+
return isCurrent &&
|
|
1669
|
+
epoch !== undefined &&
|
|
1670
|
+
operatorUserId !== undefined
|
|
1671
|
+
? {
|
|
1672
|
+
executor: {
|
|
1673
|
+
instanceId: telegramInstanceId,
|
|
1674
|
+
leaderEpoch: String(epoch),
|
|
1675
|
+
},
|
|
1676
|
+
operatorUserId,
|
|
1677
|
+
isCurrent,
|
|
1678
|
+
}
|
|
1679
|
+
: undefined;
|
|
1680
|
+
},
|
|
1681
|
+
getStore: resolveWorkspaceRestoreStore,
|
|
1682
|
+
threadStore,
|
|
1683
|
+
getJournalBindingKey: liveFollowerPorts.getJournalBindingKey,
|
|
1684
|
+
run: telegramWorkspaceOperationRuntime.run,
|
|
1685
|
+
},
|
|
1686
|
+
api: {
|
|
1687
|
+
runtime: directTelegramApiRuntime,
|
|
1688
|
+
authorize: authorizeFollowerApiCall,
|
|
1689
|
+
record(record, assertCurrent) {
|
|
1690
|
+
assertCurrent();
|
|
1691
|
+
messageOwnershipRuntime.recordFollower(record);
|
|
1692
|
+
assertCurrent();
|
|
1693
|
+
return messageOwnershipRuntime.isOwnedByFollower(record);
|
|
1694
|
+
},
|
|
1695
|
+
},
|
|
1696
|
+
});
|
|
1361
1697
|
const telegramSessionFolderSweeper = Recovery.createTelegramSessionFolderSweeper({
|
|
1362
1698
|
getSessionsDir: Paths.resolveTelegramSessionsDir,
|
|
1363
1699
|
getProfileName: configStore.getActiveProfileName,
|
|
1364
1700
|
getKeptSessionIds() {
|
|
1365
1701
|
return [
|
|
1366
|
-
...threadStore
|
|
1367
|
-
|
|
1702
|
+
...threadStore
|
|
1703
|
+
.listWorkspaceBindings()
|
|
1704
|
+
.map(function bindingSession(binding) {
|
|
1705
|
+
return binding.sessionId;
|
|
1706
|
+
}),
|
|
1707
|
+
...telegramBusFollowerRegistry
|
|
1708
|
+
.list()
|
|
1709
|
+
.map(function followerSession(follower) {
|
|
1710
|
+
return follower.sessionId;
|
|
1711
|
+
}),
|
|
1368
1712
|
Pi.getExtensionContextSessionId(telegramSessionContextStore.get()),
|
|
1369
1713
|
];
|
|
1370
1714
|
},
|
|
@@ -1378,6 +1722,7 @@ export default function (pi) {
|
|
|
1378
1722
|
followerRegistry: telegramBusFollowerRegistry,
|
|
1379
1723
|
authSecret: telegramBusAuthSecret,
|
|
1380
1724
|
protocolIdentity: telegramBusProtocolIdentity,
|
|
1725
|
+
selectedMenuDelivery,
|
|
1381
1726
|
startPolling: pollingAdmissionRuntime.start,
|
|
1382
1727
|
stopPolling: pollingAdmissionRuntime.stop,
|
|
1383
1728
|
authorizeFollowerApiCall,
|
|
@@ -1391,8 +1736,10 @@ export default function (pi) {
|
|
|
1391
1736
|
message,
|
|
1392
1737
|
});
|
|
1393
1738
|
},
|
|
1394
|
-
isFollowerProcessAlive:
|
|
1395
|
-
afterFollowerPrune() {
|
|
1739
|
+
isFollowerProcessAlive: ProcessIdentity.isProcessAlive,
|
|
1740
|
+
afterFollowerPrune() {
|
|
1741
|
+
telegramSessionFolderSweeper.sweep();
|
|
1742
|
+
},
|
|
1396
1743
|
shouldCleanupConfirmedDeadFollower: configControls.resolveAutomaticThreadCleanupEnabled,
|
|
1397
1744
|
recordFollowerMessageOwnership(record) {
|
|
1398
1745
|
messageOwnershipRuntime.recordFollower(record);
|
|
@@ -1572,13 +1919,14 @@ export default function (pi) {
|
|
|
1572
1919
|
isCurrent: telegramSessionContextStore.isCurrent,
|
|
1573
1920
|
getProfileName: configStore.getActiveProfileName,
|
|
1574
1921
|
isConnected() {
|
|
1575
|
-
return lockRuntime.owns() ||
|
|
1922
|
+
return (lockRuntime.owns() ||
|
|
1923
|
+
telegramBusFollowerRegistrationState.isRegistered());
|
|
1576
1924
|
},
|
|
1577
1925
|
async activateProfile(profileName, isCurrent) {
|
|
1578
1926
|
await configStore.load();
|
|
1579
1927
|
if (!isCurrent())
|
|
1580
1928
|
return false;
|
|
1581
|
-
return configStore.activateProfile(profileName) && configStore.hasBotToken();
|
|
1929
|
+
return (configStore.activateProfile(profileName) && configStore.hasBotToken());
|
|
1582
1930
|
},
|
|
1583
1931
|
start(ctx) {
|
|
1584
1932
|
return lockedPollingRuntime.start(ctx);
|
|
@@ -1649,14 +1997,46 @@ export default function (pi) {
|
|
|
1649
1997
|
});
|
|
1650
1998
|
const sessionLifecycleRuntime = Lifecycle.createTelegramBridgeSessionLifecycleAssembly(telegramBridgeSessionLifecycleDeps);
|
|
1651
1999
|
// --- Extension API Bindings ---
|
|
2000
|
+
const threadNameRecipientAuthority = {
|
|
2001
|
+
getAuthority() {
|
|
2002
|
+
const ctx = telegramSessionContextStore.get();
|
|
2003
|
+
return {
|
|
2004
|
+
context: ctx,
|
|
2005
|
+
sessionId: Pi.getExtensionContextSessionId(ctx),
|
|
2006
|
+
sessionGeneration: telegramSessionContextStore.getGeneration(),
|
|
2007
|
+
cwd: ctx && Pi.getExtensionContextCwd(ctx),
|
|
2008
|
+
profileName: configStore.getActiveProfileName(),
|
|
2009
|
+
botToken: configStore.getBotToken(),
|
|
2010
|
+
operatorUserId: configStore.getAllowedUserId(),
|
|
2011
|
+
leaderEpoch: getCurrentLeaderEpoch(),
|
|
2012
|
+
ownsDirectDelivery: ownsTelegramDirectDelivery(),
|
|
2013
|
+
followerRegistered: telegramBusFollowerRegistrationState.isRegistered(),
|
|
2014
|
+
localTarget: telegramBusLeaderState.getTarget(),
|
|
2015
|
+
localSlot: telegramBusLeaderState.getIdentity()?.slot,
|
|
2016
|
+
};
|
|
2017
|
+
},
|
|
2018
|
+
};
|
|
1652
2019
|
telegramThreadDisplayNameRenameBinding.bind({
|
|
1653
|
-
async rename(expectedTarget, threadName) {
|
|
2020
|
+
async rename(expectedTarget, threadName, options) {
|
|
1654
2021
|
try {
|
|
2022
|
+
const assertCaller = options?.assertAuthority;
|
|
2023
|
+
assertCaller?.();
|
|
1655
2024
|
if (telegramBusFollowerRegistrationState.isRegistered()) {
|
|
2025
|
+
if (assertCaller)
|
|
2026
|
+
return {
|
|
2027
|
+
ok: false,
|
|
2028
|
+
message: "Guarded follower Workspace Thread rename is unavailable.",
|
|
2029
|
+
};
|
|
1656
2030
|
if (typeof expectedTarget.threadId !== "number") {
|
|
1657
|
-
return {
|
|
2031
|
+
return {
|
|
2032
|
+
ok: false,
|
|
2033
|
+
message: "Telegram Workspace Thread target is unavailable.",
|
|
2034
|
+
};
|
|
1658
2035
|
}
|
|
1659
|
-
const renamedThreadName = await telegramBusFollowerRegistration.renameThread?.({
|
|
2036
|
+
const renamedThreadName = await telegramBusFollowerRegistration.renameThread?.({
|
|
2037
|
+
chatId: expectedTarget.chatId,
|
|
2038
|
+
threadId: expectedTarget.threadId,
|
|
2039
|
+
}, threadName);
|
|
1660
2040
|
if (!renamedThreadName) {
|
|
1661
2041
|
return {
|
|
1662
2042
|
ok: false,
|
|
@@ -1675,14 +2055,32 @@ export default function (pi) {
|
|
|
1675
2055
|
};
|
|
1676
2056
|
}
|
|
1677
2057
|
if (typeof expectedTarget.threadId !== "number") {
|
|
1678
|
-
return {
|
|
2058
|
+
return {
|
|
2059
|
+
ok: false,
|
|
2060
|
+
message: "Telegram Workspace Thread target is unavailable.",
|
|
2061
|
+
};
|
|
1679
2062
|
}
|
|
1680
|
-
const
|
|
2063
|
+
const target = {
|
|
2064
|
+
chatId: expectedTarget.chatId,
|
|
2065
|
+
threadId: expectedTarget.threadId,
|
|
2066
|
+
};
|
|
2067
|
+
const recipient = assertCaller
|
|
2068
|
+
? Threads.createTelegramWorkspaceThreadRenameRecipient({
|
|
2069
|
+
store: threadStore,
|
|
2070
|
+
instanceId: telegramInstanceId,
|
|
2071
|
+
target,
|
|
2072
|
+
assertAuthority: assertCaller,
|
|
2073
|
+
getAuthority: threadNameRecipientAuthority.getAuthority,
|
|
2074
|
+
})
|
|
2075
|
+
: undefined;
|
|
2076
|
+
const renamed = await telegramBusLeaderRuntime.renameLeaderThreadAdmitted(threadName, target, recipient?.assertAuthority);
|
|
2077
|
+
recipient?.assertResult(renamed);
|
|
1681
2078
|
telegramBusLeaderState.set({
|
|
1682
2079
|
target: renamed.target,
|
|
1683
2080
|
slot: renamed.slot,
|
|
1684
2081
|
threadName: renamed.manualThreadName ?? renamed.threadName,
|
|
1685
2082
|
});
|
|
2083
|
+
recipient?.assertResult(renamed);
|
|
1686
2084
|
return {
|
|
1687
2085
|
ok: true,
|
|
1688
2086
|
threadName: renamed.manualThreadName,
|
|
@@ -1699,26 +2097,58 @@ export default function (pi) {
|
|
|
1699
2097
|
},
|
|
1700
2098
|
}.rename);
|
|
1701
2099
|
telegramThreadDisplayNameResetBinding.bind({
|
|
1702
|
-
async reset(expectedTarget) {
|
|
2100
|
+
async reset(expectedTarget, options) {
|
|
1703
2101
|
try {
|
|
2102
|
+
const assertCaller = options?.assertAuthority;
|
|
2103
|
+
assertCaller?.();
|
|
2104
|
+
const wasFollower = telegramBusFollowerRegistrationState.isRegistered();
|
|
2105
|
+
if (wasFollower && assertCaller)
|
|
2106
|
+
return {
|
|
2107
|
+
ok: false,
|
|
2108
|
+
message: "Guarded follower Workspace Thread reset is unavailable.",
|
|
2109
|
+
};
|
|
1704
2110
|
if (typeof expectedTarget.threadId !== "number") {
|
|
1705
|
-
return {
|
|
2111
|
+
return {
|
|
2112
|
+
ok: false,
|
|
2113
|
+
message: "Telegram Workspace Thread target is unavailable.",
|
|
2114
|
+
};
|
|
1706
2115
|
}
|
|
1707
2116
|
const target = {
|
|
1708
2117
|
chatId: expectedTarget.chatId,
|
|
1709
2118
|
threadId: expectedTarget.threadId,
|
|
1710
2119
|
};
|
|
1711
|
-
const
|
|
2120
|
+
const recipient = assertCaller
|
|
2121
|
+
? Threads.createTelegramWorkspaceThreadResetRecipient({
|
|
2122
|
+
store: threadStore,
|
|
2123
|
+
instanceId: telegramInstanceId,
|
|
2124
|
+
target,
|
|
2125
|
+
assertAuthority: assertCaller,
|
|
2126
|
+
getAuthority: threadNameRecipientAuthority.getAuthority,
|
|
2127
|
+
})
|
|
2128
|
+
: undefined;
|
|
1712
2129
|
const result = wasFollower
|
|
1713
2130
|
? await telegramBusFollowerRegistration.resetThreadName?.(target)
|
|
1714
|
-
: (await
|
|
2131
|
+
: (await (recipient
|
|
2132
|
+
? telegramBusLeaderRuntime.resetLeaderThreadName(target, recipient.assertAuthority)
|
|
2133
|
+
: telegramBusLeaderRuntime.resetLeaderThreadName(target))).threadName;
|
|
1715
2134
|
if (!result) {
|
|
1716
|
-
return {
|
|
2135
|
+
return {
|
|
2136
|
+
ok: false,
|
|
2137
|
+
message: "Thread display name reset is unavailable.",
|
|
2138
|
+
};
|
|
1717
2139
|
}
|
|
2140
|
+
recipient?.assertResult(result);
|
|
1718
2141
|
const leaderTarget = telegramBusLeaderState.getTarget();
|
|
1719
2142
|
if (!wasFollower && leaderTarget) {
|
|
1720
|
-
telegramBusLeaderState.set({
|
|
2143
|
+
telegramBusLeaderState.set({
|
|
2144
|
+
target: leaderTarget,
|
|
2145
|
+
threadName: result,
|
|
2146
|
+
...(recipient
|
|
2147
|
+
? { slot: telegramBusLeaderState.getIdentity()?.slot }
|
|
2148
|
+
: {}),
|
|
2149
|
+
});
|
|
1721
2150
|
}
|
|
2151
|
+
recipient?.assertResult(result);
|
|
1722
2152
|
return {
|
|
1723
2153
|
ok: true,
|
|
1724
2154
|
threadName: result,
|
|
@@ -1728,7 +2158,8 @@ export default function (pi) {
|
|
|
1728
2158
|
return {
|
|
1729
2159
|
ok: false,
|
|
1730
2160
|
message: error instanceof Error
|
|
1731
|
-
? error.message
|
|
2161
|
+
? error.message
|
|
2162
|
+
: "Thread display name reset failed.",
|
|
1732
2163
|
};
|
|
1733
2164
|
}
|
|
1734
2165
|
},
|
|
@@ -1769,20 +2200,28 @@ export default function (pi) {
|
|
|
1769
2200
|
const botToken = configStore.getBotToken();
|
|
1770
2201
|
if (!botToken)
|
|
1771
2202
|
throw new Error("Telegram channel delivery requires an active bot token.");
|
|
1772
|
-
const store = ChannelPosts.
|
|
1773
|
-
...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
|
|
2203
|
+
const store = ChannelPosts.openTelegramChannelPostJournalStore({
|
|
1774
2204
|
profileName,
|
|
1775
|
-
|
|
2205
|
+
botToken,
|
|
1776
2206
|
});
|
|
1777
2207
|
const record = await ChannelPosts.publishTelegramChannelPost({
|
|
1778
|
-
store,
|
|
1779
|
-
|
|
2208
|
+
store,
|
|
2209
|
+
operationId: options.operationId,
|
|
2210
|
+
channel: channel,
|
|
2211
|
+
markdown,
|
|
1780
2212
|
async observeChannel(channelAddress) {
|
|
1781
|
-
return telegramApiRuntime.call("getChat", {
|
|
2213
|
+
return telegramApiRuntime.call("getChat", {
|
|
2214
|
+
chat_id: channelAddress,
|
|
2215
|
+
});
|
|
1782
2216
|
},
|
|
1783
2217
|
async send(channelAddress, body) {
|
|
1784
|
-
const sent = await telegramApiRuntime.call("sendRichMessage", {
|
|
1785
|
-
|
|
2218
|
+
const sent = await telegramApiRuntime.call("sendRichMessage", {
|
|
2219
|
+
chat_id: channelAddress,
|
|
2220
|
+
rich_message: { markdown: body },
|
|
2221
|
+
...(options.replyMarkup
|
|
2222
|
+
? { reply_markup: options.replyMarkup }
|
|
2223
|
+
: {}),
|
|
2224
|
+
});
|
|
1786
2225
|
return { messageId: sent.message_id, chat: sent.chat };
|
|
1787
2226
|
},
|
|
1788
2227
|
});
|
|
@@ -1799,23 +2238,29 @@ export default function (pi) {
|
|
|
1799
2238
|
const media = await ChannelPosts.inspectTelegramChannelPostMedia(mediaPath);
|
|
1800
2239
|
const caption = Replies.renderTelegramMarkdownToHtmlDraft(markdown);
|
|
1801
2240
|
ChannelPosts.assertTelegramChannelPostCaptionWithinLimit(caption);
|
|
1802
|
-
const store = ChannelPosts.
|
|
1803
|
-
...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
|
|
2241
|
+
const store = ChannelPosts.openTelegramChannelPostJournalStore({
|
|
1804
2242
|
profileName,
|
|
1805
|
-
|
|
2243
|
+
botToken,
|
|
1806
2244
|
});
|
|
1807
2245
|
const record = await ChannelPosts.publishTelegramChannelPost({
|
|
1808
|
-
store,
|
|
1809
|
-
|
|
2246
|
+
store,
|
|
2247
|
+
operationId: options.operationId,
|
|
2248
|
+
channel: channel,
|
|
2249
|
+
markdown,
|
|
2250
|
+
media,
|
|
1810
2251
|
async observeChannel(channelAddress) {
|
|
1811
|
-
return telegramApiRuntime.call("getChat", {
|
|
2252
|
+
return telegramApiRuntime.call("getChat", {
|
|
2253
|
+
chat_id: channelAddress,
|
|
2254
|
+
});
|
|
1812
2255
|
},
|
|
1813
2256
|
async send(channelAddress) {
|
|
1814
2257
|
const sent = await telegramApiRuntime.callMultipart(media.kind === "photo" ? "sendPhoto" : "sendVideo", {
|
|
1815
2258
|
chat_id: String(channelAddress),
|
|
1816
2259
|
caption,
|
|
1817
2260
|
parse_mode: "HTML",
|
|
1818
|
-
...(options.replyMarkup
|
|
2261
|
+
...(options.replyMarkup
|
|
2262
|
+
? { reply_markup: JSON.stringify(options.replyMarkup) }
|
|
2263
|
+
: {}),
|
|
1819
2264
|
}, media.kind === "photo" ? "photo" : "video", mediaPath, media.fileName);
|
|
1820
2265
|
return { messageId: sent.message_id, chat: sent.chat };
|
|
1821
2266
|
},
|
|
@@ -1827,10 +2272,9 @@ export default function (pi) {
|
|
|
1827
2272
|
const botToken = configStore.getBotToken();
|
|
1828
2273
|
if (!botToken)
|
|
1829
2274
|
throw new Error("Telegram channel posts require an active bot token.");
|
|
1830
|
-
return ChannelPosts.
|
|
1831
|
-
...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
|
|
2275
|
+
return ChannelPosts.openTelegramChannelPostJournalStore({
|
|
1832
2276
|
profileName,
|
|
1833
|
-
|
|
2277
|
+
botToken,
|
|
1834
2278
|
}).list(input);
|
|
1835
2279
|
},
|
|
1836
2280
|
async mutateChannelPost(input) {
|
|
@@ -1840,23 +2284,28 @@ export default function (pi) {
|
|
|
1840
2284
|
const botToken = configStore.getBotToken();
|
|
1841
2285
|
if (!botToken)
|
|
1842
2286
|
throw new Error("Telegram channel post mutation requires an active bot token.");
|
|
1843
|
-
const store = ChannelPosts.
|
|
1844
|
-
|
|
1845
|
-
|
|
2287
|
+
const store = ChannelPosts.openTelegramChannelPostJournalStore({
|
|
2288
|
+
profileName,
|
|
2289
|
+
botToken,
|
|
1846
2290
|
});
|
|
1847
2291
|
if (input.action === "edit") {
|
|
1848
2292
|
if (!input.markdown)
|
|
1849
2293
|
throw new Error("Telegram channel post edit requires markdown.");
|
|
1850
2294
|
const current = store.get(input.operationId);
|
|
1851
2295
|
const caption = current?.media
|
|
1852
|
-
? Replies.renderTelegramMarkdownToHtmlDraft(input.markdown)
|
|
2296
|
+
? Replies.renderTelegramMarkdownToHtmlDraft(input.markdown)
|
|
2297
|
+
: undefined;
|
|
1853
2298
|
if (caption !== undefined) {
|
|
1854
2299
|
ChannelPosts.assertTelegramChannelPostCaptionWithinLimit(caption);
|
|
1855
2300
|
}
|
|
1856
|
-
const begun = store.beginEdit({
|
|
1857
|
-
|
|
2301
|
+
const begun = store.beginEdit({
|
|
2302
|
+
operationId: input.operationId,
|
|
2303
|
+
mutationId: input.mutationId,
|
|
2304
|
+
markdown: input.markdown,
|
|
2305
|
+
});
|
|
1858
2306
|
if (!begun.began) {
|
|
1859
|
-
if (begun.record.state === "published" &&
|
|
2307
|
+
if (begun.record.state === "published" &&
|
|
2308
|
+
begun.record.lastMutationId === input.mutationId)
|
|
1860
2309
|
return begun.record;
|
|
1861
2310
|
throw new Error("Telegram channel post edit outcome is unknown; refusing automatic replay.");
|
|
1862
2311
|
}
|
|
@@ -1866,29 +2315,48 @@ export default function (pi) {
|
|
|
1866
2315
|
if (caption === undefined) {
|
|
1867
2316
|
throw new Error("Telegram channel post media caption edit requires retained media identity.");
|
|
1868
2317
|
}
|
|
1869
|
-
await telegramApiRuntime.call("editMessageCaption", {
|
|
1870
|
-
|
|
2318
|
+
await telegramApiRuntime.call("editMessageCaption", {
|
|
2319
|
+
chat_id: begun.record.channelId,
|
|
2320
|
+
message_id: begun.record.messageId,
|
|
2321
|
+
caption,
|
|
2322
|
+
parse_mode: "HTML",
|
|
2323
|
+
});
|
|
1871
2324
|
}
|
|
1872
2325
|
else {
|
|
1873
|
-
await telegramApiRuntime.call("editMessageText", {
|
|
2326
|
+
await telegramApiRuntime.call("editMessageText", {
|
|
2327
|
+
chat_id: begun.record.channelId,
|
|
1874
2328
|
message_id: begun.record.messageId,
|
|
1875
|
-
text: Replies.renderTelegramMarkdownToHtmlDraft(input.markdown),
|
|
2329
|
+
text: Replies.renderTelegramMarkdownToHtmlDraft(input.markdown),
|
|
2330
|
+
parse_mode: "HTML",
|
|
2331
|
+
});
|
|
1876
2332
|
}
|
|
1877
|
-
return store.confirmEdited({
|
|
2333
|
+
return store.confirmEdited({
|
|
2334
|
+
operationId: input.operationId,
|
|
2335
|
+
mutationId: input.mutationId,
|
|
2336
|
+
}).record;
|
|
1878
2337
|
}
|
|
1879
2338
|
if (input.markdown !== undefined)
|
|
1880
2339
|
throw new Error("Telegram channel post deletion does not accept markdown.");
|
|
1881
|
-
const begun = store.beginDelete({
|
|
2340
|
+
const begun = store.beginDelete({
|
|
2341
|
+
operationId: input.operationId,
|
|
2342
|
+
mutationId: input.mutationId,
|
|
2343
|
+
});
|
|
1882
2344
|
if (!begun.began) {
|
|
1883
|
-
if (begun.record.state === "deleted" &&
|
|
2345
|
+
if (begun.record.state === "deleted" &&
|
|
2346
|
+
begun.record.mutationId === input.mutationId)
|
|
1884
2347
|
return begun.record;
|
|
1885
2348
|
throw new Error("Telegram channel post deletion outcome is unknown; refusing automatic replay.");
|
|
1886
2349
|
}
|
|
1887
2350
|
if (begun.record.state !== "delete-outcome-unknown")
|
|
1888
2351
|
throw new Error("Telegram channel post deletion authority is invalid.");
|
|
1889
|
-
await telegramApiRuntime.call("deleteMessage", {
|
|
1890
|
-
|
|
1891
|
-
|
|
2352
|
+
await telegramApiRuntime.call("deleteMessage", {
|
|
2353
|
+
chat_id: begun.record.channelId,
|
|
2354
|
+
message_id: begun.record.messageId,
|
|
2355
|
+
});
|
|
2356
|
+
return store.confirmDeleted({
|
|
2357
|
+
operationId: input.operationId,
|
|
2358
|
+
mutationId: input.mutationId,
|
|
2359
|
+
}).record;
|
|
1892
2360
|
},
|
|
1893
2361
|
callMultipart,
|
|
1894
2362
|
getDefaultChatId: proactivePushChatIdGetter,
|