@llblab/pi-telegram 0.52.2 → 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 +9 -7
- package/BACKLOG.md +1 -18
- package/CHANGELOG.md +11 -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 +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 +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 +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 +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 +125 -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 +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 +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/replies.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Owns native assistant replies, rendered UI delivery, guest placeholder rotation, reply transport wiring, and plain text replies
|
|
5
5
|
*/
|
|
6
6
|
import { assertTelegramInlineKeyboardCallbackData } from "./keyboard.js";
|
|
7
|
-
import { getTelegramTargetThreadParams, } from "./target.js";
|
|
8
|
-
import { isTelegramApiCommitUnknownError } from "./telegram-api.js";
|
|
9
7
|
import { renderTelegramMessage, } from "./rendering.js";
|
|
8
|
+
import { getTelegramTargetThreadParams, } from "./target.js";
|
|
9
|
+
import { assertTelegramApiCallAuthority, isTelegramApiCommitUnknownError, TelegramApiAuthorityError, } from "./telegram-api.js";
|
|
10
10
|
export { renderTelegramMessage, };
|
|
11
11
|
export function renderTelegramMarkdownToHtmlDraft(markdown) {
|
|
12
12
|
return renderTelegramMessage(markdown, { mode: "markdown" })
|
|
@@ -15,21 +15,6 @@ export function renderTelegramMarkdownToHtmlDraft(markdown) {
|
|
|
15
15
|
}
|
|
16
16
|
export const TELEGRAM_RICH_MESSAGE_MAX_CHARS = 32768;
|
|
17
17
|
export const TELEGRAM_RICH_MESSAGE_MAX_BLOCKS = 500;
|
|
18
|
-
export function createReplyDedupRuntime() {
|
|
19
|
-
const replied = new Map();
|
|
20
|
-
return {
|
|
21
|
-
shouldReply(promptMessageId) {
|
|
22
|
-
if (replied.has(promptMessageId))
|
|
23
|
-
return false;
|
|
24
|
-
replied.set(promptMessageId, true);
|
|
25
|
-
return true;
|
|
26
|
-
},
|
|
27
|
-
reset() {
|
|
28
|
-
replied.clear();
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
// --- Transport-level dedup ---
|
|
33
18
|
const lastRepliedToMessageIdByTarget = new Map();
|
|
34
19
|
const replyDedupPreservedOnNextReset = new Map();
|
|
35
20
|
let replyDedupGeneration = 0;
|
|
@@ -80,9 +65,11 @@ export async function withTelegramReplyParameters(chatId, messageId, target, sen
|
|
|
80
65
|
return await send(parameters);
|
|
81
66
|
}
|
|
82
67
|
catch (error) {
|
|
83
|
-
if (parameters &&
|
|
84
|
-
&&
|
|
85
|
-
&&
|
|
68
|
+
if (parameters &&
|
|
69
|
+
!isTelegramApiCommitUnknownError(error) &&
|
|
70
|
+
!(error instanceof TelegramApiAuthorityError && error.requestIssued) &&
|
|
71
|
+
generation === replyDedupGeneration &&
|
|
72
|
+
lastRepliedToMessageIdByTarget.get(key) === messageId) {
|
|
86
73
|
if (previous === undefined)
|
|
87
74
|
lastRepliedToMessageIdByTarget.delete(key);
|
|
88
75
|
else
|
|
@@ -172,32 +159,49 @@ export function buildTelegramReplyTransport(deps) {
|
|
|
172
159
|
};
|
|
173
160
|
}
|
|
174
161
|
export async function sendTelegramRenderedChunks(chatId, chunks, deps, options) {
|
|
175
|
-
|
|
162
|
+
return sendTelegramChunkSequence(chatId, chunks, options?.replyToMessageId, options, deps.recordOwnership, (chunk, fields, callOptions) => deps.sendMessage({
|
|
163
|
+
chat_id: chatId,
|
|
164
|
+
text: chunk.text,
|
|
165
|
+
parse_mode: chunk.parseMode,
|
|
166
|
+
...fields,
|
|
167
|
+
}, callOptions));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Ordered chunk delivery: only the first chunk replies, only the last carries markup, and authority is rechecked
|
|
171
|
+
* before issuance and after every response/ownership publication.
|
|
172
|
+
*/
|
|
173
|
+
async function sendTelegramChunkSequence(chatId, chunks, replyToMessageId, options, recordOwnership, send) {
|
|
174
|
+
const target = options?.target && { ...options.target }, assertAuthority = options?.assertAuthority, replyMarkup = options?.replyMarkup;
|
|
175
|
+
assertTelegramInlineKeyboardCallbackData(replyMarkup);
|
|
176
176
|
let lastMessageId;
|
|
177
177
|
for (const [index, chunk] of chunks.entries()) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
deps.recordOwnership?.({
|
|
188
|
-
chatId,
|
|
189
|
-
messageId: sent.message_id,
|
|
190
|
-
target: options?.target,
|
|
178
|
+
assertTelegramApiCallAuthority(assertAuthority, false);
|
|
179
|
+
const sent = await withTelegramReplyParameters(chatId, index === 0 ? replyToMessageId : undefined, target, async (replyParameters) => {
|
|
180
|
+
const sent = await send(chunk, {
|
|
181
|
+
reply_markup: index === chunks.length - 1 ? replyMarkup : undefined,
|
|
182
|
+
...(replyParameters ? { reply_parameters: replyParameters } : {}),
|
|
183
|
+
...(target ? getTelegramTargetThreadParams(target) : {}),
|
|
184
|
+
}, assertAuthority ? { assertAuthority } : undefined);
|
|
185
|
+
assertTelegramApiCallAuthority(assertAuthority, true);
|
|
186
|
+
return sent;
|
|
191
187
|
});
|
|
188
|
+
assertTelegramApiCallAuthority(assertAuthority, true);
|
|
189
|
+
lastMessageId = sent.message_id;
|
|
190
|
+
recordOwnership?.({ chatId, messageId: sent.message_id, target });
|
|
191
|
+
assertTelegramApiCallAuthority(assertAuthority, true);
|
|
192
192
|
}
|
|
193
193
|
return lastMessageId;
|
|
194
194
|
}
|
|
195
195
|
export async function editTelegramRenderedMessage(chatId, messageId, chunks, deps, options) {
|
|
196
|
+
options = { ...options, target: options?.target && { ...options.target } };
|
|
197
|
+
const assertAuthority = options.assertAuthority;
|
|
198
|
+
assertTelegramApiCallAuthority(assertAuthority, false);
|
|
196
199
|
assertTelegramInlineKeyboardCallbackData(options?.replyMarkup);
|
|
197
200
|
if (chunks.length === 0)
|
|
198
201
|
return messageId;
|
|
199
202
|
const [firstChunk, ...remainingChunks] = chunks;
|
|
200
|
-
|
|
203
|
+
if (!assertAuthority)
|
|
204
|
+
deps.recordOwnership?.({ chatId, messageId, target: options.target });
|
|
201
205
|
await deps.editMessage({
|
|
202
206
|
chat_id: chatId,
|
|
203
207
|
message_id: messageId,
|
|
@@ -205,22 +209,29 @@ export async function editTelegramRenderedMessage(chatId, messageId, chunks, dep
|
|
|
205
209
|
parse_mode: firstChunk.parseMode,
|
|
206
210
|
reply_markup: remainingChunks.length === 0 ? options?.replyMarkup : undefined,
|
|
207
211
|
...(options?.target ? getTelegramTargetThreadParams(options.target) : {}),
|
|
208
|
-
});
|
|
212
|
+
}, assertAuthority ? { assertAuthority } : undefined);
|
|
213
|
+
assertTelegramApiCallAuthority(assertAuthority, true);
|
|
214
|
+
if (assertAuthority)
|
|
215
|
+
deps.recordOwnership?.({ chatId, messageId, target: options.target });
|
|
216
|
+
assertTelegramApiCallAuthority(assertAuthority, true);
|
|
209
217
|
if (remainingChunks.length > 0) {
|
|
210
218
|
return sendTelegramRenderedChunks(chatId, remainingChunks, deps, {
|
|
211
219
|
replyMarkup: options?.replyMarkup,
|
|
212
220
|
target: options?.target,
|
|
221
|
+
assertAuthority,
|
|
213
222
|
});
|
|
214
223
|
}
|
|
215
224
|
return messageId;
|
|
216
225
|
}
|
|
217
226
|
export async function sendTelegramPlainReply(text, deps, options) {
|
|
227
|
+
options = { ...options, target: options?.target && { ...options.target } };
|
|
218
228
|
const chunks = deps.renderTelegramMessage(text, {
|
|
219
229
|
mode: options?.parseMode === "HTML" ? "html" : "plain",
|
|
220
230
|
});
|
|
221
231
|
return deps.sendRenderedChunks(chunks, {
|
|
222
232
|
target: options?.target,
|
|
223
233
|
replyToMessageId: options?.replyToMessageId,
|
|
234
|
+
assertAuthority: options.assertAuthority,
|
|
224
235
|
});
|
|
225
236
|
}
|
|
226
237
|
function normalizeIndentedTelegramNativeMarkdownList(line) {
|
|
@@ -242,22 +253,28 @@ function normalizeTelegramNativeMarkdownLine(line) {
|
|
|
242
253
|
result = result.replace(/(^|[^\\$])\$([A-Z][A-Z0-9]{1,})(?!\$)(?=\b|[.,;:)/-])/g, (_match, prefix, ticker) => `${prefix}\\$${ticker}`);
|
|
243
254
|
return result.replace(/\u0000(\d+)\u0000/g, (_match, index) => codeSpans[Number(index)] ?? "");
|
|
244
255
|
}
|
|
256
|
+
export function parseTelegramMarkdownFenceOpening(line) {
|
|
257
|
+
const markerText = line.match(/^ {0,3}(`{3,}|~{3,})/)?.[1];
|
|
258
|
+
return markerText
|
|
259
|
+
? { marker: markerText[0], length: markerText.length }
|
|
260
|
+
: undefined;
|
|
261
|
+
}
|
|
262
|
+
export function isTelegramMarkdownFenceClosing(line, fence) {
|
|
263
|
+
return new RegExp(`^ {0,3}${fence.marker}{${fence.length},}\\s*$`).test(line);
|
|
264
|
+
}
|
|
265
|
+
/** Fence state after one line: outside a fence a marker opens one; inside, a matching marker closes it. */
|
|
266
|
+
function advanceTelegramMarkdownFence(fence, line) {
|
|
267
|
+
if (!fence)
|
|
268
|
+
return parseTelegramMarkdownFenceOpening(line);
|
|
269
|
+
return isTelegramMarkdownFenceClosing(line, fence) ? undefined : fence;
|
|
270
|
+
}
|
|
245
271
|
function hasClosingDisplayMathDelimiter(lines, startIndex) {
|
|
246
272
|
let fence;
|
|
247
273
|
for (let index = startIndex + 1; index < lines.length; index += 1) {
|
|
248
274
|
const line = lines[index] ?? "";
|
|
249
|
-
const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
250
275
|
if (!fence && line.trim() === "$$")
|
|
251
276
|
return true;
|
|
252
|
-
|
|
253
|
-
const markerText = fenceMatch[1] ?? "```";
|
|
254
|
-
fence = { marker: markerText[0], length: markerText.length };
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
if (fence &&
|
|
258
|
-
new RegExp(`^ {0,3}${fence.marker}{${fence.length},}\\s*$`).test(line)) {
|
|
259
|
-
fence = undefined;
|
|
260
|
-
}
|
|
277
|
+
fence = advanceTelegramMarkdownFence(fence, line);
|
|
261
278
|
}
|
|
262
279
|
return false;
|
|
263
280
|
}
|
|
@@ -267,7 +284,6 @@ export function normalizeTelegramNativeMarkdown(markdown) {
|
|
|
267
284
|
let displayMath = false;
|
|
268
285
|
return lines
|
|
269
286
|
.map((line, index) => {
|
|
270
|
-
const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
271
287
|
const inFence = fence !== undefined;
|
|
272
288
|
if (!inFence && line.trim() === "$$") {
|
|
273
289
|
if (displayMath) {
|
|
@@ -281,17 +297,9 @@ export function normalizeTelegramNativeMarkdown(markdown) {
|
|
|
281
297
|
}
|
|
282
298
|
if (displayMath)
|
|
283
299
|
return line;
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
fence =
|
|
287
|
-
marker: markerText[0],
|
|
288
|
-
length: markerText.length,
|
|
289
|
-
};
|
|
290
|
-
return line;
|
|
291
|
-
}
|
|
292
|
-
if (inFence &&
|
|
293
|
-
new RegExp(`^ {0,3}${fence?.marker}{${fence?.length},}\\s*$`).test(line)) {
|
|
294
|
-
fence = undefined;
|
|
300
|
+
const nextFence = advanceTelegramMarkdownFence(fence, line);
|
|
301
|
+
if (nextFence !== fence) {
|
|
302
|
+
fence = nextFence;
|
|
295
303
|
return line;
|
|
296
304
|
}
|
|
297
305
|
if (!inFence)
|
|
@@ -349,21 +357,12 @@ function splitTelegramNativeMarkdownBlocks(markdown) {
|
|
|
349
357
|
current.length = 0;
|
|
350
358
|
};
|
|
351
359
|
for (const line of markdown.split("\n")) {
|
|
352
|
-
const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
353
360
|
if (!fence && line.trim().length === 0) {
|
|
354
361
|
flush();
|
|
355
362
|
continue;
|
|
356
363
|
}
|
|
357
364
|
current.push(line);
|
|
358
|
-
|
|
359
|
-
const markerText = fenceMatch[1] ?? "```";
|
|
360
|
-
fence = { marker: markerText[0], length: markerText.length };
|
|
361
|
-
continue;
|
|
362
|
-
}
|
|
363
|
-
if (fence &&
|
|
364
|
-
new RegExp(`^ {0,3}${fence.marker}{${fence.length},}\\s*$`).test(line)) {
|
|
365
|
-
fence = undefined;
|
|
366
|
-
}
|
|
365
|
+
fence = advanceTelegramMarkdownFence(fence, line);
|
|
367
366
|
}
|
|
368
367
|
flush();
|
|
369
368
|
return blocks;
|
|
@@ -376,21 +375,12 @@ function splitTelegramNativeMarkdownCountedBlocks(block) {
|
|
|
376
375
|
let current = [];
|
|
377
376
|
let fence;
|
|
378
377
|
for (const line of block.split("\n")) {
|
|
379
|
-
const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
380
378
|
if (!fence && current.length >= TELEGRAM_RICH_MESSAGE_MAX_BLOCKS) {
|
|
381
379
|
chunks.push(current.join("\n"));
|
|
382
380
|
current = [];
|
|
383
381
|
}
|
|
384
382
|
current.push(line);
|
|
385
|
-
|
|
386
|
-
const markerText = fenceMatch[1] ?? "```";
|
|
387
|
-
fence = { marker: markerText[0], length: markerText.length };
|
|
388
|
-
continue;
|
|
389
|
-
}
|
|
390
|
-
if (fence &&
|
|
391
|
-
new RegExp(`^ {0,3}${fence.marker}{${fence.length},}\\s*$`).test(line)) {
|
|
392
|
-
fence = undefined;
|
|
393
|
-
}
|
|
383
|
+
fence = advanceTelegramMarkdownFence(fence, line);
|
|
394
384
|
}
|
|
395
385
|
if (current.length > 0)
|
|
396
386
|
chunks.push(current.join("\n"));
|
|
@@ -427,12 +417,10 @@ function splitTelegramNativeMarkdownLongFenceBlock(block) {
|
|
|
427
417
|
const lines = block.split("\n");
|
|
428
418
|
const opening = lines[0] ?? "";
|
|
429
419
|
const closing = lines[lines.length - 1] ?? "";
|
|
430
|
-
const
|
|
431
|
-
if (!
|
|
420
|
+
const openingFence = parseTelegramMarkdownFenceOpening(opening);
|
|
421
|
+
if (!openingFence || !closing || lines.length < 2)
|
|
432
422
|
return undefined;
|
|
433
|
-
|
|
434
|
-
const marker = markerText[0];
|
|
435
|
-
if (!new RegExp(`^ {0,3}${marker}{${markerText.length},}\\s*$`).test(closing)) {
|
|
423
|
+
if (!isTelegramMarkdownFenceClosing(closing, openingFence)) {
|
|
436
424
|
return undefined;
|
|
437
425
|
}
|
|
438
426
|
const maxContentLength = TELEGRAM_RICH_MESSAGE_MAX_CHARS - opening.length - closing.length - 2;
|
|
@@ -478,33 +466,24 @@ function findTelegramNativeMarkdownSplitIndex(text, hardLimit = TELEGRAM_RICH_ME
|
|
|
478
466
|
return hardLimit;
|
|
479
467
|
}
|
|
480
468
|
export async function sendTelegramNativeMarkdownReply(chatId, replyToMessageId, markdown, deps, options) {
|
|
481
|
-
|
|
482
|
-
let lastMessageId;
|
|
483
|
-
const chunks = splitTelegramNativeMarkdown(markdown);
|
|
484
|
-
for (const [index, chunk] of chunks.entries()) {
|
|
485
|
-
const sent = await withTelegramReplyParameters(chatId, index === 0 ? replyToMessageId : undefined, options?.target, (replyParameters) => deps.sendRichMessage({
|
|
486
|
-
chat_id: chatId,
|
|
487
|
-
rich_message: { markdown: chunk },
|
|
488
|
-
reply_markup: index === chunks.length - 1 ? options?.replyMarkup : undefined,
|
|
489
|
-
...(replyParameters ? { reply_parameters: replyParameters } : {}),
|
|
490
|
-
...(options?.target ? getTelegramTargetThreadParams(options.target) : {}),
|
|
491
|
-
}));
|
|
492
|
-
lastMessageId = sent.message_id;
|
|
493
|
-
deps.recordOwnership?.({
|
|
494
|
-
chatId,
|
|
495
|
-
messageId: sent.message_id,
|
|
496
|
-
target: options?.target,
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
return lastMessageId;
|
|
469
|
+
return sendTelegramChunkSequence(chatId, splitTelegramNativeMarkdown(markdown), replyToMessageId, options, deps.recordOwnership, (chunk, fields, callOptions) => deps.sendRichMessage({ chat_id: chatId, rich_message: { markdown: chunk }, ...fields }, callOptions));
|
|
500
470
|
}
|
|
501
471
|
async function sendTelegramNativeRichMessage(chatId, richMessage, deps, options) {
|
|
472
|
+
options = { ...options, target: options?.target && { ...options.target } };
|
|
473
|
+
const assertAuthority = options.assertAuthority;
|
|
474
|
+
assertTelegramApiCallAuthority(assertAuthority, false);
|
|
502
475
|
const sent = await deps.sendRichMessage({
|
|
503
476
|
chat_id: chatId,
|
|
504
477
|
rich_message: richMessage,
|
|
505
478
|
...(options?.target ? getTelegramTargetThreadParams(options.target) : {}),
|
|
479
|
+
}, assertAuthority ? { assertAuthority } : undefined);
|
|
480
|
+
assertTelegramApiCallAuthority(assertAuthority, true);
|
|
481
|
+
deps.recordOwnership?.({
|
|
482
|
+
chatId,
|
|
483
|
+
messageId: sent.message_id,
|
|
484
|
+
target: options?.target,
|
|
506
485
|
});
|
|
507
|
-
|
|
486
|
+
assertTelegramApiCallAuthority(assertAuthority, true);
|
|
508
487
|
return sent.message_id;
|
|
509
488
|
}
|
|
510
489
|
export function createTelegramRenderedMessageDeliveryRuntime(deps) {
|
|
@@ -531,17 +510,23 @@ export function createTelegramRenderedMessageRuntime(deps) {
|
|
|
531
510
|
renderTelegramMessage: deps.renderTelegramMessage,
|
|
532
511
|
sendRenderedChunks: (chunks, chunkOptions) => deps.replyTransport.sendRenderedChunks(chatId, chunks, {
|
|
533
512
|
target: chunkOptions?.target,
|
|
513
|
+
assertAuthority: chunkOptions?.assertAuthority,
|
|
534
514
|
replyToMessageId: chunkOptions?.replyToMessageId ?? replyToMessageId,
|
|
535
515
|
}),
|
|
536
516
|
}, options);
|
|
537
517
|
},
|
|
538
518
|
sendMarkdownReply: async (chatId, replyToMessageId, markdown, options) => {
|
|
519
|
+
options = {
|
|
520
|
+
...options,
|
|
521
|
+
target: options?.target && { ...options.target },
|
|
522
|
+
};
|
|
539
523
|
const renderingMode = deps.getAssistantRenderingMode?.() ?? "rich";
|
|
540
524
|
if (renderingMode === "html") {
|
|
541
525
|
return deps.replyTransport.sendRenderedChunks(chatId, deps.renderTelegramMessage(markdown, { mode: "markdown" }), {
|
|
542
526
|
replyMarkup: options?.replyMarkup,
|
|
543
527
|
target: options?.target,
|
|
544
528
|
replyToMessageId,
|
|
529
|
+
assertAuthority: options.assertAuthority,
|
|
545
530
|
});
|
|
546
531
|
}
|
|
547
532
|
return sendTelegramNativeMarkdownReply(chatId, replyToMessageId, markdown, {
|
|
@@ -549,14 +534,23 @@ export function createTelegramRenderedMessageRuntime(deps) {
|
|
|
549
534
|
sendRichMessage: deps.sendRichMessage,
|
|
550
535
|
}, options);
|
|
551
536
|
},
|
|
552
|
-
editInteractiveMessage: async (chatId, messageId, text, mode, replyMarkup) => {
|
|
553
|
-
|
|
537
|
+
editInteractiveMessage: async (chatId, messageId, text, mode, replyMarkup, options) => {
|
|
538
|
+
options = {
|
|
539
|
+
...options,
|
|
540
|
+
target: options?.target && { ...options.target },
|
|
541
|
+
};
|
|
542
|
+
await deps.replyTransport.editRenderedMessage(chatId, messageId, deps.renderTelegramMessage(text, { mode }), { ...options, replyMarkup });
|
|
554
543
|
},
|
|
555
544
|
sendInteractiveMessage: async (chatId, text, mode, replyMarkup, options) => {
|
|
545
|
+
options = {
|
|
546
|
+
...options,
|
|
547
|
+
target: options?.target && { ...options.target },
|
|
548
|
+
};
|
|
556
549
|
return deps.replyTransport.sendRenderedChunks(chatId, deps.renderTelegramMessage(text, { mode }), {
|
|
557
550
|
replyMarkup,
|
|
558
551
|
target: options?.target,
|
|
559
552
|
replyToMessageId: options?.replyToMessageId,
|
|
553
|
+
assertAuthority: options.assertAuthority,
|
|
560
554
|
});
|
|
561
555
|
},
|
|
562
556
|
sendSectionRichMessage: (chatId, message, options) => sendTelegramNativeRichMessage(chatId, message, {
|
|
@@ -565,17 +559,6 @@ export function createTelegramRenderedMessageRuntime(deps) {
|
|
|
565
559
|
}, options),
|
|
566
560
|
};
|
|
567
561
|
}
|
|
568
|
-
// --- Dedup-wrapped Reply Wrappers ---
|
|
569
|
-
/** Wrap a sendTextReply with reply dedup so only the first message
|
|
570
|
-
* in a turn carries reply metadata. */
|
|
571
|
-
export function dedupSendTextReply(dedup, inner) {
|
|
572
|
-
return async (chatId, replyToMessageId, text, options) => {
|
|
573
|
-
const effectiveReplyTo = dedup.shouldReply(replyToMessageId)
|
|
574
|
-
? replyToMessageId
|
|
575
|
-
: undefined;
|
|
576
|
-
return inner(chatId, effectiveReplyTo, text, options);
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
562
|
/**
|
|
580
563
|
* Guest reply sender: answers guest queries with native Rich Markdown content.
|
|
581
564
|
* Guest queries use InlineQueryResult input_message_content rather than chat
|
package/dist/lib/routing.d.ts
CHANGED
|
@@ -43,6 +43,71 @@ export declare function resolveTelegramGuestPromptPeer(input: {
|
|
|
43
43
|
export declare function resolveTelegramGuestFileScope(input: Parameters<typeof resolveTelegramGuestPromptPeer>[0]): string;
|
|
44
44
|
import * as Threads from "./threads.ts";
|
|
45
45
|
import * as Updates from "./updates.ts";
|
|
46
|
+
/** Prepare the selected leader's exact retained originals; no copy, adoption, acceptance proof or dispatch. */
|
|
47
|
+
export declare function prepareTelegramLiveLeaderOriginal(input: {
|
|
48
|
+
request: Threads.TelegramWorkspaceRestoreRequest;
|
|
49
|
+
messages: readonly unknown[];
|
|
50
|
+
isCurrent(): boolean;
|
|
51
|
+
}): Updates.TelegramLiveDeferredInputPreparation | undefined;
|
|
52
|
+
export type TelegramLiveRebindCleanupIssue = {
|
|
53
|
+
status: "not-ready";
|
|
54
|
+
} | {
|
|
55
|
+
status: "finished";
|
|
56
|
+
operationId: string;
|
|
57
|
+
cleanup: ThreadReconciler.TelegramLiveRebindCleanupOutcome;
|
|
58
|
+
recorded: boolean;
|
|
59
|
+
};
|
|
60
|
+
/** Default live-rebind cleanup pacing: quick early attempts, then minutely, within a 15-minute window. */
|
|
61
|
+
export declare const TELEGRAM_LIVE_REBIND_CLEANUP_SCHEDULE: Readonly<{
|
|
62
|
+
delaysMs: readonly number[];
|
|
63
|
+
intervalMs: 60000;
|
|
64
|
+
windowMs: number;
|
|
65
|
+
}>;
|
|
66
|
+
/** Chooser-scoped saved command reference; it is never retained after the chooser record. */
|
|
67
|
+
type TelegramLiveRebindSelectedCommandReference = {
|
|
68
|
+
operationId: string;
|
|
69
|
+
preparedSource: Bus.TelegramBusPreparedCommandSource;
|
|
70
|
+
selectedCommand: Bus.TelegramBusSelectedCommandInput;
|
|
71
|
+
};
|
|
72
|
+
/** One warm live attempt with exact post-release peer donor settlement; no startup recovery, Restore ACK or cleanup. */
|
|
73
|
+
export declare function createTelegramLiveRebindCoordinator(input: {
|
|
74
|
+
request: Threads.TelegramWorkspaceRestoreRequest;
|
|
75
|
+
/** Captures caller source/reference, admission, profile, transport and Pi lifetime. */
|
|
76
|
+
authority: Threads.TelegramWorkspaceRestoreAuthority;
|
|
77
|
+
messages: readonly unknown[];
|
|
78
|
+
restoreStore: Threads.TelegramWorkspaceRestore;
|
|
79
|
+
threadStore: Pick<Threads.TelegramTopicTargetStore, "withWorkspaceRestoreSnapshot">;
|
|
80
|
+
getRecipient(): (Threads.TelegramWorkspaceRestoreRecipient & {
|
|
81
|
+
bindingKey: string;
|
|
82
|
+
}) | undefined;
|
|
83
|
+
leader?: {
|
|
84
|
+
apply(intent: Threads.TelegramWorkspaceLiveRebindIntent, mode: "apply" | "inspect", isCurrent: () => boolean): Promise<void>;
|
|
85
|
+
/** Synchronous local identity only; safe inside a Workspace publication fence. */
|
|
86
|
+
isApplied(intent: Threads.TelegramWorkspaceLiveRebindIntent): boolean;
|
|
87
|
+
} & ({
|
|
88
|
+
/** Confirm ordinary queue admission of these same bound messages, never handler replay. */
|
|
89
|
+
continue(messages: readonly unknown[], isCurrent: () => boolean): Promise<boolean>;
|
|
90
|
+
/** Observe only the same issued admission through its existing receipt owner; never re-enqueue. */
|
|
91
|
+
observeAdmission?(): boolean;
|
|
92
|
+
complete?: never;
|
|
93
|
+
} | {
|
|
94
|
+
/** Issue one semantic completion; the adapter owns detached delivery and errors, not a removal ACK. */
|
|
95
|
+
complete(messages: readonly unknown[], isCurrent: () => boolean): void;
|
|
96
|
+
continue?: never;
|
|
97
|
+
});
|
|
98
|
+
follower?: {
|
|
99
|
+
run: ReturnType<typeof Bus.createTelegramBusLiveRebindController>;
|
|
100
|
+
/** Explicit staged singleton command branch; absence preserves ordinary live input behavior. */
|
|
101
|
+
selectedCommand?: Bus.TelegramBusSelectedCommandInput;
|
|
102
|
+
};
|
|
103
|
+
recordRuntimeEvent?: (category: string, error: unknown, details: Record<string, unknown>) => void;
|
|
104
|
+
}): {
|
|
105
|
+
/** Correlation only; a later cleanup attempt rereads and revalidates the canonical row itself. */
|
|
106
|
+
operationId: string;
|
|
107
|
+
/** Body-free copy of the authenticated saved command reference: correlation only, never authority, an ACK or a cleanup permit. */
|
|
108
|
+
selectedCommandReference(): TelegramLiveRebindSelectedCommandReference | undefined;
|
|
109
|
+
advance(): Promise<"protected" | "unknown" | "released">;
|
|
110
|
+
};
|
|
46
111
|
/** One admitted Restore attempt through recipient readiness, never source dispatch or cleanup. */
|
|
47
112
|
export declare function advanceTelegramWorkspaceRestore(input: {
|
|
48
113
|
request: Threads.TelegramWorkspaceRestoreRequest;
|
|
@@ -68,8 +133,8 @@ export declare function advanceTelegramWorkspaceRestore(input: {
|
|
|
68
133
|
inspectOnly?: true;
|
|
69
134
|
}): Promise<Threads.TelegramWorkspaceRestoreIntent | undefined>;
|
|
70
135
|
export declare const TELEGRAM_ALL_TAB_COMMAND_MAX_AGE_MS: number;
|
|
71
|
-
/**
|
|
72
|
-
export declare const TELEGRAM_ROUTING_CHOICE_EXPIRED = "
|
|
136
|
+
/** The toast for expired or previous-process routing controls; the chooser notice is written separately. */
|
|
137
|
+
export declare const TELEGRAM_ROUTING_CHOICE_EXPIRED = "Routing choice expired";
|
|
73
138
|
export declare function isTelegramAllTabCommandExpired(message: {
|
|
74
139
|
date?: number;
|
|
75
140
|
message_thread_id?: number;
|
|
@@ -132,17 +197,36 @@ export interface TelegramInboundRouteRuntimeDeps<TMessage extends TelegramRouted
|
|
|
132
197
|
journalBindingKey: string;
|
|
133
198
|
}) => TelegramUpdateJournalQueuedReceiptEvidence | undefined;
|
|
134
199
|
hasWorkspaceRestoreAuthority?: () => boolean;
|
|
200
|
+
/** Exact live root authority; capability advertisement alone cannot replace owned profile/session/recipient fences. */
|
|
201
|
+
hasWorkspaceLiveRebindAuthority?: () => boolean;
|
|
135
202
|
/** Strict complete namespace plus exact current/historical references; only an empty result clears journal protection. */
|
|
136
|
-
inspectTemporaryThreadSources?: (target: Queue.TelegramQueueTarget, requiredJournalBindingKeys: readonly string[]) => readonly number[] | undefined;
|
|
203
|
+
inspectTemporaryThreadSources?: (target: Queue.TelegramQueueTarget, requiredJournalBindingKeys: readonly string[], ownInputs?: readonly Threads.TelegramTemporaryThreadInput[]) => readonly number[] | undefined;
|
|
137
204
|
/** Quiet period after the last cancelled input before one cleanup attempt; defaults to 1000 ms. */
|
|
138
205
|
temporaryThreadCleanupDelayMs?: number;
|
|
206
|
+
/** Live-rebind cleanup attempt pacing; the bounded window ends in `not-issued`, never a time-based deletion. */
|
|
207
|
+
liveRebindCleanupSchedule?: {
|
|
208
|
+
delaysMs: readonly number[];
|
|
209
|
+
intervalMs: number;
|
|
210
|
+
windowMs: number;
|
|
211
|
+
};
|
|
139
212
|
getSessionGeneration?: () => number;
|
|
140
213
|
workspaceRestoreRecipient?: {
|
|
141
214
|
getSessionId: (ctx: TContext) => string | undefined;
|
|
142
215
|
getCwd: (ctx: TContext) => string | undefined;
|
|
143
216
|
getLeaderIdentity: Threads.TelegramLeaderThreadStateRuntime["getIdentity"];
|
|
217
|
+
/** Read-only current leader work; source/chooser lifetime is not recipient authority. */
|
|
218
|
+
observeLeaderWork?: (oldTarget: Queue.TelegramQueueTarget & {
|
|
219
|
+
threadId: number;
|
|
220
|
+
}, ctx: TContext) => Bus.TelegramBusLiveRebindWorkState;
|
|
144
221
|
followerRegistry: Pick<Bus.TelegramBusFollowerRegistry, "get" | "register">;
|
|
145
222
|
runFollower: ReturnType<typeof Bus.createTelegramBusWorkspaceRestoreController>;
|
|
223
|
+
liveFollower?: {
|
|
224
|
+
/** Pure trusted assembly availability (Commands/native/menu and local protocol), never future target activation. */
|
|
225
|
+
isSelectedCommandAvailable?(follower: Readonly<Bus.TelegramBusFollowerView>, name: string): boolean;
|
|
226
|
+
/** Exact session journal identity from the existing registration/journal owners, never the profile routing key. */
|
|
227
|
+
getJournalBindingKey(follower: Bus.TelegramBusFollowerView): string | undefined;
|
|
228
|
+
run: ReturnType<typeof Bus.createTelegramBusLiveRebindController>;
|
|
229
|
+
};
|
|
146
230
|
};
|
|
147
231
|
bridgeRuntime: TelegramBridgeRuntime;
|
|
148
232
|
activeTurnRuntime: Queue.TelegramActiveTurnStore;
|
|
@@ -154,9 +238,11 @@ export interface TelegramInboundRouteRuntimeDeps<TMessage extends TelegramRouted
|
|
|
154
238
|
currentModelRuntime: Model.CurrentModelRuntime<TContext, TModel>;
|
|
155
239
|
modelSwitchController: Model.TelegramModelSwitchController<TContext, Model.ScopedTelegramModel<TModel>>;
|
|
156
240
|
menuActions: Menu.TelegramMenuActionRuntime<TContext, TModel>;
|
|
241
|
+
/** Thinking controls refuse while the active Telegram turn expects a voice reply. */
|
|
242
|
+
isVoiceReplyActive?: () => boolean;
|
|
157
243
|
updateSettingsMenuMessage?: (state: Menu.TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
|
|
158
|
-
openQueueMenu: (chatId: number, replyToMessageId: number, ctx: TContext) => Promise<void>;
|
|
159
|
-
openSettingsMenu?: (chatId: number, replyToMessageId: number, ctx: TContext) => Promise<void>;
|
|
244
|
+
openQueueMenu: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
|
|
245
|
+
openSettingsMenu?: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
|
|
160
246
|
settingsMenuCallbackHandler?: (query: TCallbackQuery, ctx: TContext) => Promise<boolean>;
|
|
161
247
|
queueMenuCallbackHandler: (query: TCallbackQuery, ctx: TContext) => Promise<boolean>;
|
|
162
248
|
buttonActionStore?: OutboundHandlers.TelegramButtonActionStore;
|
|
@@ -184,12 +270,16 @@ export interface TelegramInboundRouteRuntimeDeps<TMessage extends TelegramRouted
|
|
|
184
270
|
};
|
|
185
271
|
}) => void;
|
|
186
272
|
stopTypingLoop?: () => void;
|
|
187
|
-
answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
|
|
188
|
-
editInteractiveMessage?: (chatId: number, messageId: number, text: string, mode: "markdown" | "html" | "plain", replyMarkup: Menu.TelegramReplyMarkup
|
|
273
|
+
answerCallbackQuery: (callbackQueryId: string, text?: string, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
|
|
274
|
+
editInteractiveMessage?: (chatId: number, messageId: number, text: string, mode: "markdown" | "html" | "plain", replyMarkup: Menu.TelegramReplyMarkup, options?: {
|
|
275
|
+
target?: Queue.TelegramQueueTarget;
|
|
276
|
+
assertAuthority?: TelegramApiCallOptions["assertAuthority"];
|
|
277
|
+
}) => Promise<void>;
|
|
189
278
|
editMessageReplyMarkup?: (chatId: number, messageId: number, replyMarkup: OutboundHandlers.TelegramOutboundButtonMarkup) => Promise<void>;
|
|
190
279
|
sendInteractiveMessage?: (chatId: number, text: string, mode: "markdown" | "html" | "plain", replyMarkup: Menu.TelegramReplyMarkup, options?: {
|
|
191
280
|
target?: Queue.TelegramQueueTarget;
|
|
192
281
|
replyToMessageId?: number;
|
|
282
|
+
assertAuthority?: TelegramApiCallOptions["assertAuthority"];
|
|
193
283
|
}) => Promise<number | undefined>;
|
|
194
284
|
deleteMessage?: (chatId: number, messageId: number) => Promise<void>;
|
|
195
285
|
answerGuestQuery: (guestQueryId: string, text?: string) => Promise<void>;
|
|
@@ -202,8 +292,11 @@ export interface TelegramInboundRouteRuntimeDeps<TMessage extends TelegramRouted
|
|
|
202
292
|
sendTextReply: (chatId: number, replyToMessageId: number, text: string, options?: {
|
|
203
293
|
parseMode?: "HTML";
|
|
204
294
|
target?: Queue.TelegramQueueTarget;
|
|
295
|
+
assertAuthority?: TelegramApiCallOptions["assertAuthority"];
|
|
205
296
|
}) => Promise<number | undefined>;
|
|
206
297
|
setMyCommands: Commands.TelegramBotCommandRegistrationDeps["setMyCommands"];
|
|
298
|
+
/** Captures independent recipient authority, never the source execution or dialog handle. */
|
|
299
|
+
captureThreadNameRecipientAuthority?: (target: Queue.TelegramQueueTarget, ctx: TContext) => (() => void) | undefined;
|
|
207
300
|
validateThreadName?: (threadName: string) => string | undefined;
|
|
208
301
|
renameCurrentThread?: Commands.TelegramThreadDisplayNameRenamePort;
|
|
209
302
|
resetCurrentThreadName?: Commands.TelegramThreadDisplayNameResetPort;
|
|
@@ -223,6 +316,7 @@ export interface TelegramInboundRouteRuntimeDeps<TMessage extends TelegramRouted
|
|
|
223
316
|
onError: (error: unknown) => void;
|
|
224
317
|
}) => void;
|
|
225
318
|
recordRuntimeEvent?: (category: string, error: unknown, details?: Record<string, unknown>) => void;
|
|
319
|
+
beginCommandEffectWork?: Commands.TelegramCommandRuntimeDeps<TMessage, TContext>["beginCommandEffectWork"];
|
|
226
320
|
sectionRegistry?: TelegramSectionRegistry;
|
|
227
321
|
sendSectionRichMessage?: (chatId: number, message: TelegramInputRichMessage, options?: {
|
|
228
322
|
target?: {
|
|
@@ -249,6 +343,25 @@ export declare function createTelegramInboundRouteRuntime<TUpdate extends Update
|
|
|
249
343
|
onUpdateCompleted: NonNullable<Updates.TelegramUpdateWorkerRuntimeDeps<TContext>["onUpdateCompleted"]>;
|
|
250
344
|
onWorkspaceRestoreRecipientObserved(follower: Bus.TelegramBusFollowerView, isCurrent: () => boolean, ctx: TContext | undefined): Promise<void> | undefined;
|
|
251
345
|
waitForRestoreSettlement(): Promise<void>;
|
|
346
|
+
/** Commands-owned registry port for dormant scoped recipient assembly, not ordinary update replay. */
|
|
347
|
+
prepareHeldCommand: ReturnType<typeof Commands.createTelegramCommandHandlerTargetRuntime<TMessage, TContext>>["prepareHeldCommand"];
|
|
348
|
+
canPrepareHeldCommand: ReturnType<typeof Commands.createTelegramCommandHandlerTargetRuntime<TMessage, TContext>>["canPrepareHeldCommand"];
|
|
349
|
+
/** Fresh body-free recipient observation only; never reconstructs an attempt or grants cleanup. */
|
|
350
|
+
observeLiveRebindLeaderWork(intent: Threads.TelegramWorkspaceLiveRebindIntent, ctx: TContext): Promise<Bus.TelegramBusLiveRebindWorkObservation | undefined>;
|
|
351
|
+
/** Fresh non-destructive candidate only; no retained idle, cleanup action or deletion grant. */
|
|
352
|
+
prepareLiveRebindLeaderCleanup(intent: Threads.TelegramWorkspaceLiveRebindIntent, ctx: TContext): Promise<ThreadReconciler.TelegramLiveRebindCleanupPreparation | undefined>;
|
|
353
|
+
/** Requires the authenticated peer's exact retained released carrier; never recreates save/apply/release. */
|
|
354
|
+
prepareLiveRebindFollowerCleanup(intent: Threads.TelegramWorkspaceLiveRebindIntent, ctx: TContext): Promise<ThreadReconciler.TelegramLiveRebindCleanupPreparation | undefined>;
|
|
355
|
+
/**
|
|
356
|
+
* One cleanup attempt under fresh admission: a fresh clear sample, then the durable issue marker, one unretried
|
|
357
|
+
* deletion and the terminal record. `not-ready` leaves the released row unissued; `undefined` is lost authority.
|
|
358
|
+
*/
|
|
359
|
+
issueLiveRebindLeaderCleanup(intent: Threads.TelegramWorkspaceLiveRebindIntent, ctx: TContext): Promise<TelegramLiveRebindCleanupIssue | undefined>;
|
|
360
|
+
issueLiveRebindFollowerCleanup(intent: Threads.TelegramWorkspaceLiveRebindIntent, ctx: TContext): Promise<TelegramLiveRebindCleanupIssue | undefined>;
|
|
361
|
+
/** Coordinator-only prompt admission; caller retains Workspace/canonical and exact recipient authority. */
|
|
362
|
+
continueLiveRebindPrompt(messages: readonly TMessage[], ctx: TContext, target: Queue.TelegramQueueTarget & {
|
|
363
|
+
threadId: number;
|
|
364
|
+
}, isCurrent: () => boolean): Promise<boolean>;
|
|
252
365
|
};
|
|
253
366
|
export interface TelegramAssistantOutputAuthority<TTransportStamp> {
|
|
254
367
|
transportStamp: TTransportStamp;
|