@llblab/pi-telegram 0.52.1 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +10 -8
- package/BACKLOG.md +1 -16
- package/CHANGELOG.md +17 -0
- package/README.md +8 -10
- 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 +640 -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 +34 -3
- package/dist/lib/locks.js +318 -119
- package/dist/lib/logging.js +50 -14
- package/dist/lib/media.d.ts +22 -1
- package/dist/lib/media.js +46 -28
- package/dist/lib/menu-model.d.ts +19 -5
- package/dist/lib/menu-model.js +53 -11
- package/dist/lib/menu-queue.d.ts +5 -4
- package/dist/lib/menu-queue.js +45 -63
- package/dist/lib/menu-settings.d.ts +5 -4
- package/dist/lib/menu-settings.js +114 -78
- package/dist/lib/menu-status.d.ts +1 -1
- package/dist/lib/menu-status.js +8 -25
- package/dist/lib/menu-thinking.d.ts +6 -1
- package/dist/lib/menu-thinking.js +14 -21
- package/dist/lib/menu.d.ts +8 -61
- package/dist/lib/menu.js +92 -164
- package/dist/lib/model.d.ts +1 -1
- package/dist/lib/model.js +2 -16
- package/dist/lib/outbound-attachments.d.ts +6 -27
- package/dist/lib/outbound-attachments.js +45 -38
- package/dist/lib/outbound-buttons.js +22 -16
- package/dist/lib/outbound-markup.d.ts +0 -2
- package/dist/lib/outbound-markup.js +51 -64
- package/dist/lib/outbound-voice.js +6 -3
- package/dist/lib/outbound.d.ts +6 -6
- package/dist/lib/outbound.js +61 -51
- package/dist/lib/ownership.js +6 -2
- package/dist/lib/paths.d.ts +5 -0
- package/dist/lib/paths.js +37 -21
- package/dist/lib/pi.d.ts +2 -0
- package/dist/lib/pi.js +8 -1
- package/dist/lib/polling.d.ts +23 -37
- package/dist/lib/polling.js +71 -52
- package/dist/lib/preview.js +39 -19
- package/dist/lib/process-identity.d.ts +24 -0
- package/dist/lib/process-identity.js +133 -0
- package/dist/lib/prompts.js +2 -7
- package/dist/lib/queue.d.ts +14 -16
- package/dist/lib/queue.js +249 -126
- package/dist/lib/recovery.d.ts +2 -83
- package/dist/lib/recovery.js +20 -274
- package/dist/lib/replies.d.ts +16 -24
- package/dist/lib/replies.js +99 -116
- package/dist/lib/routing.d.ts +120 -7
- package/dist/lib/routing.js +4667 -1152
- package/dist/lib/runtime.d.ts +1 -11
- package/dist/lib/sections.d.ts +4 -29
- package/dist/lib/sections.js +7 -20
- package/dist/lib/skills.js +4 -3
- package/dist/lib/status.js +86 -57
- package/dist/lib/sync.d.ts +6 -3
- package/dist/lib/sync.js +112 -45
- 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 +165 -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 +36 -30
- 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 +1207 -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 +703 -212
- package/lib/logging.ts +147 -58
- package/lib/media.ts +82 -43
- package/lib/menu-model.ts +85 -18
- package/lib/menu-queue.ts +88 -129
- package/lib/menu-settings.ts +260 -155
- package/lib/menu-status.ts +20 -60
- package/lib/menu-thinking.ts +41 -56
- package/lib/menu.ts +112 -285
- package/lib/model.ts +8 -22
- package/lib/outbound-attachments.ts +156 -125
- package/lib/outbound-buttons.ts +76 -49
- package/lib/outbound-markup.ts +96 -94
- package/lib/outbound-voice.ts +33 -27
- package/lib/outbound.ts +125 -125
- package/lib/ownership.ts +19 -10
- package/lib/paths.ts +148 -49
- package/lib/pi.ts +35 -15
- package/lib/polling.ts +165 -149
- package/lib/preview.ts +93 -40
- package/lib/process-identity.ts +164 -0
- package/lib/prompts.ts +4 -11
- package/lib/queue.ts +511 -300
- package/lib/recovery.ts +50 -454
- package/lib/rendering.ts +1 -3
- package/lib/replies.ts +248 -209
- package/lib/routing.ts +8509 -2186
- package/lib/runtime.ts +1 -12
- package/lib/sections.ts +24 -89
- package/lib/setup.ts +1 -3
- package/lib/skills.ts +9 -4
- package/lib/status.ts +215 -110
- package/lib/sync.ts +488 -359
- package/lib/target.ts +22 -3
- package/lib/telegram-api.ts +322 -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);
|
|
@@ -1551,6 +1898,7 @@ export default function (pi) {
|
|
|
1551
1898
|
getSyncState: telegramSyncStateRuntime.getState,
|
|
1552
1899
|
setSyncState: telegramSyncStateRuntime.setState,
|
|
1553
1900
|
stopPolling: lockedPollingRuntime.stop,
|
|
1901
|
+
captureStopPolling: lockedPollingRuntime.captureStop,
|
|
1554
1902
|
suspendPolling: lockedPollingRuntime.suspend,
|
|
1555
1903
|
recordRuntimeEvent,
|
|
1556
1904
|
runWorkspaceOperation: telegramWorkspaceOperationRuntime.run,
|
|
@@ -1571,13 +1919,14 @@ export default function (pi) {
|
|
|
1571
1919
|
isCurrent: telegramSessionContextStore.isCurrent,
|
|
1572
1920
|
getProfileName: configStore.getActiveProfileName,
|
|
1573
1921
|
isConnected() {
|
|
1574
|
-
return lockRuntime.owns() ||
|
|
1922
|
+
return (lockRuntime.owns() ||
|
|
1923
|
+
telegramBusFollowerRegistrationState.isRegistered());
|
|
1575
1924
|
},
|
|
1576
1925
|
async activateProfile(profileName, isCurrent) {
|
|
1577
1926
|
await configStore.load();
|
|
1578
1927
|
if (!isCurrent())
|
|
1579
1928
|
return false;
|
|
1580
|
-
return configStore.activateProfile(profileName) && configStore.hasBotToken();
|
|
1929
|
+
return (configStore.activateProfile(profileName) && configStore.hasBotToken());
|
|
1581
1930
|
},
|
|
1582
1931
|
start(ctx) {
|
|
1583
1932
|
return lockedPollingRuntime.start(ctx);
|
|
@@ -1648,14 +1997,46 @@ export default function (pi) {
|
|
|
1648
1997
|
});
|
|
1649
1998
|
const sessionLifecycleRuntime = Lifecycle.createTelegramBridgeSessionLifecycleAssembly(telegramBridgeSessionLifecycleDeps);
|
|
1650
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
|
+
};
|
|
1651
2019
|
telegramThreadDisplayNameRenameBinding.bind({
|
|
1652
|
-
async rename(expectedTarget, threadName) {
|
|
2020
|
+
async rename(expectedTarget, threadName, options) {
|
|
1653
2021
|
try {
|
|
2022
|
+
const assertCaller = options?.assertAuthority;
|
|
2023
|
+
assertCaller?.();
|
|
1654
2024
|
if (telegramBusFollowerRegistrationState.isRegistered()) {
|
|
2025
|
+
if (assertCaller)
|
|
2026
|
+
return {
|
|
2027
|
+
ok: false,
|
|
2028
|
+
message: "Guarded follower Workspace Thread rename is unavailable.",
|
|
2029
|
+
};
|
|
1655
2030
|
if (typeof expectedTarget.threadId !== "number") {
|
|
1656
|
-
return {
|
|
2031
|
+
return {
|
|
2032
|
+
ok: false,
|
|
2033
|
+
message: "Telegram Workspace Thread target is unavailable.",
|
|
2034
|
+
};
|
|
1657
2035
|
}
|
|
1658
|
-
const renamedThreadName = await telegramBusFollowerRegistration.renameThread?.({
|
|
2036
|
+
const renamedThreadName = await telegramBusFollowerRegistration.renameThread?.({
|
|
2037
|
+
chatId: expectedTarget.chatId,
|
|
2038
|
+
threadId: expectedTarget.threadId,
|
|
2039
|
+
}, threadName);
|
|
1659
2040
|
if (!renamedThreadName) {
|
|
1660
2041
|
return {
|
|
1661
2042
|
ok: false,
|
|
@@ -1674,14 +2055,32 @@ export default function (pi) {
|
|
|
1674
2055
|
};
|
|
1675
2056
|
}
|
|
1676
2057
|
if (typeof expectedTarget.threadId !== "number") {
|
|
1677
|
-
return {
|
|
2058
|
+
return {
|
|
2059
|
+
ok: false,
|
|
2060
|
+
message: "Telegram Workspace Thread target is unavailable.",
|
|
2061
|
+
};
|
|
1678
2062
|
}
|
|
1679
|
-
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);
|
|
1680
2078
|
telegramBusLeaderState.set({
|
|
1681
2079
|
target: renamed.target,
|
|
1682
2080
|
slot: renamed.slot,
|
|
1683
2081
|
threadName: renamed.manualThreadName ?? renamed.threadName,
|
|
1684
2082
|
});
|
|
2083
|
+
recipient?.assertResult(renamed);
|
|
1685
2084
|
return {
|
|
1686
2085
|
ok: true,
|
|
1687
2086
|
threadName: renamed.manualThreadName,
|
|
@@ -1698,26 +2097,58 @@ export default function (pi) {
|
|
|
1698
2097
|
},
|
|
1699
2098
|
}.rename);
|
|
1700
2099
|
telegramThreadDisplayNameResetBinding.bind({
|
|
1701
|
-
async reset(expectedTarget) {
|
|
2100
|
+
async reset(expectedTarget, options) {
|
|
1702
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
|
+
};
|
|
1703
2110
|
if (typeof expectedTarget.threadId !== "number") {
|
|
1704
|
-
return {
|
|
2111
|
+
return {
|
|
2112
|
+
ok: false,
|
|
2113
|
+
message: "Telegram Workspace Thread target is unavailable.",
|
|
2114
|
+
};
|
|
1705
2115
|
}
|
|
1706
2116
|
const target = {
|
|
1707
2117
|
chatId: expectedTarget.chatId,
|
|
1708
2118
|
threadId: expectedTarget.threadId,
|
|
1709
2119
|
};
|
|
1710
|
-
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;
|
|
1711
2129
|
const result = wasFollower
|
|
1712
2130
|
? await telegramBusFollowerRegistration.resetThreadName?.(target)
|
|
1713
|
-
: (await
|
|
2131
|
+
: (await (recipient
|
|
2132
|
+
? telegramBusLeaderRuntime.resetLeaderThreadName(target, recipient.assertAuthority)
|
|
2133
|
+
: telegramBusLeaderRuntime.resetLeaderThreadName(target))).threadName;
|
|
1714
2134
|
if (!result) {
|
|
1715
|
-
return {
|
|
2135
|
+
return {
|
|
2136
|
+
ok: false,
|
|
2137
|
+
message: "Thread display name reset is unavailable.",
|
|
2138
|
+
};
|
|
1716
2139
|
}
|
|
2140
|
+
recipient?.assertResult(result);
|
|
1717
2141
|
const leaderTarget = telegramBusLeaderState.getTarget();
|
|
1718
2142
|
if (!wasFollower && leaderTarget) {
|
|
1719
|
-
telegramBusLeaderState.set({
|
|
2143
|
+
telegramBusLeaderState.set({
|
|
2144
|
+
target: leaderTarget,
|
|
2145
|
+
threadName: result,
|
|
2146
|
+
...(recipient
|
|
2147
|
+
? { slot: telegramBusLeaderState.getIdentity()?.slot }
|
|
2148
|
+
: {}),
|
|
2149
|
+
});
|
|
1720
2150
|
}
|
|
2151
|
+
recipient?.assertResult(result);
|
|
1721
2152
|
return {
|
|
1722
2153
|
ok: true,
|
|
1723
2154
|
threadName: result,
|
|
@@ -1727,7 +2158,8 @@ export default function (pi) {
|
|
|
1727
2158
|
return {
|
|
1728
2159
|
ok: false,
|
|
1729
2160
|
message: error instanceof Error
|
|
1730
|
-
? error.message
|
|
2161
|
+
? error.message
|
|
2162
|
+
: "Thread display name reset failed.",
|
|
1731
2163
|
};
|
|
1732
2164
|
}
|
|
1733
2165
|
},
|
|
@@ -1768,20 +2200,28 @@ export default function (pi) {
|
|
|
1768
2200
|
const botToken = configStore.getBotToken();
|
|
1769
2201
|
if (!botToken)
|
|
1770
2202
|
throw new Error("Telegram channel delivery requires an active bot token.");
|
|
1771
|
-
const store = ChannelPosts.
|
|
1772
|
-
...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
|
|
2203
|
+
const store = ChannelPosts.openTelegramChannelPostJournalStore({
|
|
1773
2204
|
profileName,
|
|
1774
|
-
|
|
2205
|
+
botToken,
|
|
1775
2206
|
});
|
|
1776
2207
|
const record = await ChannelPosts.publishTelegramChannelPost({
|
|
1777
|
-
store,
|
|
1778
|
-
|
|
2208
|
+
store,
|
|
2209
|
+
operationId: options.operationId,
|
|
2210
|
+
channel: channel,
|
|
2211
|
+
markdown,
|
|
1779
2212
|
async observeChannel(channelAddress) {
|
|
1780
|
-
return telegramApiRuntime.call("getChat", {
|
|
2213
|
+
return telegramApiRuntime.call("getChat", {
|
|
2214
|
+
chat_id: channelAddress,
|
|
2215
|
+
});
|
|
1781
2216
|
},
|
|
1782
2217
|
async send(channelAddress, body) {
|
|
1783
|
-
const sent = await telegramApiRuntime.call("sendRichMessage", {
|
|
1784
|
-
|
|
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
|
+
});
|
|
1785
2225
|
return { messageId: sent.message_id, chat: sent.chat };
|
|
1786
2226
|
},
|
|
1787
2227
|
});
|
|
@@ -1798,23 +2238,29 @@ export default function (pi) {
|
|
|
1798
2238
|
const media = await ChannelPosts.inspectTelegramChannelPostMedia(mediaPath);
|
|
1799
2239
|
const caption = Replies.renderTelegramMarkdownToHtmlDraft(markdown);
|
|
1800
2240
|
ChannelPosts.assertTelegramChannelPostCaptionWithinLimit(caption);
|
|
1801
|
-
const store = ChannelPosts.
|
|
1802
|
-
...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
|
|
2241
|
+
const store = ChannelPosts.openTelegramChannelPostJournalStore({
|
|
1803
2242
|
profileName,
|
|
1804
|
-
|
|
2243
|
+
botToken,
|
|
1805
2244
|
});
|
|
1806
2245
|
const record = await ChannelPosts.publishTelegramChannelPost({
|
|
1807
|
-
store,
|
|
1808
|
-
|
|
2246
|
+
store,
|
|
2247
|
+
operationId: options.operationId,
|
|
2248
|
+
channel: channel,
|
|
2249
|
+
markdown,
|
|
2250
|
+
media,
|
|
1809
2251
|
async observeChannel(channelAddress) {
|
|
1810
|
-
return telegramApiRuntime.call("getChat", {
|
|
2252
|
+
return telegramApiRuntime.call("getChat", {
|
|
2253
|
+
chat_id: channelAddress,
|
|
2254
|
+
});
|
|
1811
2255
|
},
|
|
1812
2256
|
async send(channelAddress) {
|
|
1813
2257
|
const sent = await telegramApiRuntime.callMultipart(media.kind === "photo" ? "sendPhoto" : "sendVideo", {
|
|
1814
2258
|
chat_id: String(channelAddress),
|
|
1815
2259
|
caption,
|
|
1816
2260
|
parse_mode: "HTML",
|
|
1817
|
-
...(options.replyMarkup
|
|
2261
|
+
...(options.replyMarkup
|
|
2262
|
+
? { reply_markup: JSON.stringify(options.replyMarkup) }
|
|
2263
|
+
: {}),
|
|
1818
2264
|
}, media.kind === "photo" ? "photo" : "video", mediaPath, media.fileName);
|
|
1819
2265
|
return { messageId: sent.message_id, chat: sent.chat };
|
|
1820
2266
|
},
|
|
@@ -1826,10 +2272,9 @@ export default function (pi) {
|
|
|
1826
2272
|
const botToken = configStore.getBotToken();
|
|
1827
2273
|
if (!botToken)
|
|
1828
2274
|
throw new Error("Telegram channel posts require an active bot token.");
|
|
1829
|
-
return ChannelPosts.
|
|
1830
|
-
...Paths.resolveTelegramServiceJournalStorage("channel-posts", undefined, profileName),
|
|
2275
|
+
return ChannelPosts.openTelegramChannelPostJournalStore({
|
|
1831
2276
|
profileName,
|
|
1832
|
-
|
|
2277
|
+
botToken,
|
|
1833
2278
|
}).list(input);
|
|
1834
2279
|
},
|
|
1835
2280
|
async mutateChannelPost(input) {
|
|
@@ -1839,23 +2284,28 @@ export default function (pi) {
|
|
|
1839
2284
|
const botToken = configStore.getBotToken();
|
|
1840
2285
|
if (!botToken)
|
|
1841
2286
|
throw new Error("Telegram channel post mutation requires an active bot token.");
|
|
1842
|
-
const store = ChannelPosts.
|
|
1843
|
-
|
|
1844
|
-
|
|
2287
|
+
const store = ChannelPosts.openTelegramChannelPostJournalStore({
|
|
2288
|
+
profileName,
|
|
2289
|
+
botToken,
|
|
1845
2290
|
});
|
|
1846
2291
|
if (input.action === "edit") {
|
|
1847
2292
|
if (!input.markdown)
|
|
1848
2293
|
throw new Error("Telegram channel post edit requires markdown.");
|
|
1849
2294
|
const current = store.get(input.operationId);
|
|
1850
2295
|
const caption = current?.media
|
|
1851
|
-
? Replies.renderTelegramMarkdownToHtmlDraft(input.markdown)
|
|
2296
|
+
? Replies.renderTelegramMarkdownToHtmlDraft(input.markdown)
|
|
2297
|
+
: undefined;
|
|
1852
2298
|
if (caption !== undefined) {
|
|
1853
2299
|
ChannelPosts.assertTelegramChannelPostCaptionWithinLimit(caption);
|
|
1854
2300
|
}
|
|
1855
|
-
const begun = store.beginEdit({
|
|
1856
|
-
|
|
2301
|
+
const begun = store.beginEdit({
|
|
2302
|
+
operationId: input.operationId,
|
|
2303
|
+
mutationId: input.mutationId,
|
|
2304
|
+
markdown: input.markdown,
|
|
2305
|
+
});
|
|
1857
2306
|
if (!begun.began) {
|
|
1858
|
-
if (begun.record.state === "published" &&
|
|
2307
|
+
if (begun.record.state === "published" &&
|
|
2308
|
+
begun.record.lastMutationId === input.mutationId)
|
|
1859
2309
|
return begun.record;
|
|
1860
2310
|
throw new Error("Telegram channel post edit outcome is unknown; refusing automatic replay.");
|
|
1861
2311
|
}
|
|
@@ -1865,29 +2315,48 @@ export default function (pi) {
|
|
|
1865
2315
|
if (caption === undefined) {
|
|
1866
2316
|
throw new Error("Telegram channel post media caption edit requires retained media identity.");
|
|
1867
2317
|
}
|
|
1868
|
-
await telegramApiRuntime.call("editMessageCaption", {
|
|
1869
|
-
|
|
2318
|
+
await telegramApiRuntime.call("editMessageCaption", {
|
|
2319
|
+
chat_id: begun.record.channelId,
|
|
2320
|
+
message_id: begun.record.messageId,
|
|
2321
|
+
caption,
|
|
2322
|
+
parse_mode: "HTML",
|
|
2323
|
+
});
|
|
1870
2324
|
}
|
|
1871
2325
|
else {
|
|
1872
|
-
await telegramApiRuntime.call("editMessageText", {
|
|
2326
|
+
await telegramApiRuntime.call("editMessageText", {
|
|
2327
|
+
chat_id: begun.record.channelId,
|
|
1873
2328
|
message_id: begun.record.messageId,
|
|
1874
|
-
text: Replies.renderTelegramMarkdownToHtmlDraft(input.markdown),
|
|
2329
|
+
text: Replies.renderTelegramMarkdownToHtmlDraft(input.markdown),
|
|
2330
|
+
parse_mode: "HTML",
|
|
2331
|
+
});
|
|
1875
2332
|
}
|
|
1876
|
-
return store.confirmEdited({
|
|
2333
|
+
return store.confirmEdited({
|
|
2334
|
+
operationId: input.operationId,
|
|
2335
|
+
mutationId: input.mutationId,
|
|
2336
|
+
}).record;
|
|
1877
2337
|
}
|
|
1878
2338
|
if (input.markdown !== undefined)
|
|
1879
2339
|
throw new Error("Telegram channel post deletion does not accept markdown.");
|
|
1880
|
-
const begun = store.beginDelete({
|
|
2340
|
+
const begun = store.beginDelete({
|
|
2341
|
+
operationId: input.operationId,
|
|
2342
|
+
mutationId: input.mutationId,
|
|
2343
|
+
});
|
|
1881
2344
|
if (!begun.began) {
|
|
1882
|
-
if (begun.record.state === "deleted" &&
|
|
2345
|
+
if (begun.record.state === "deleted" &&
|
|
2346
|
+
begun.record.mutationId === input.mutationId)
|
|
1883
2347
|
return begun.record;
|
|
1884
2348
|
throw new Error("Telegram channel post deletion outcome is unknown; refusing automatic replay.");
|
|
1885
2349
|
}
|
|
1886
2350
|
if (begun.record.state !== "delete-outcome-unknown")
|
|
1887
2351
|
throw new Error("Telegram channel post deletion authority is invalid.");
|
|
1888
|
-
await telegramApiRuntime.call("deleteMessage", {
|
|
1889
|
-
|
|
1890
|
-
|
|
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;
|
|
1891
2360
|
},
|
|
1892
2361
|
callMultipart,
|
|
1893
2362
|
getDefaultChatId: proactivePushChatIdGetter,
|