@llblab/pi-kit 0.33.1 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BACKLOG.md +2 -1
- package/CHANGELOG.md +9 -0
- package/README.md +3 -3
- package/node_modules/@llblab/pi-telegram/AGENTS.md +6 -5
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +6 -1
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +20 -0
- package/node_modules/@llblab/pi-telegram/README.md +28 -17
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +8 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +41 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +10 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +34 -20
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +8 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +21 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +33 -28
- package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +18 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +2 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +28 -20
- package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +6 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +3 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.js +100 -99
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +3 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +3 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +6 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +5 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +57 -5
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +313 -25
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +4 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +62 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +1 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/status.js +6 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +11 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +11 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +57 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +13 -32
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +44 -15
- package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/docs/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +25 -14
- package/node_modules/@llblab/pi-telegram/docs/callback-namespaces.md +4 -0
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +8 -6
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +17 -17
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +52 -3
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +13 -5
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +37 -23
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +23 -7
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +52 -47
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +18 -2
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +34 -28
- package/node_modules/@llblab/pi-telegram/lib/locks.ts +5 -2
- package/node_modules/@llblab/pi-telegram/lib/menu-queue.ts +114 -162
- package/node_modules/@llblab/pi-telegram/lib/pi.ts +8 -0
- package/node_modules/@llblab/pi-telegram/lib/polling.ts +7 -2
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +328 -33
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +51 -1
- package/node_modules/@llblab/pi-telegram/lib/status.ts +7 -7
- package/node_modules/@llblab/pi-telegram/lib/sync.ts +11 -0
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +57 -5
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +44 -21
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/package.json +2 -2
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Owns queue-menu rendering, queue item callbacks, and queue-menu runtime adapters while core queue mechanics stay in queue
|
|
5
5
|
*/
|
|
6
6
|
import { createTelegramMenuDelivery, } from "./menu-model.js";
|
|
7
|
+
import * as Queue from "./queue.js";
|
|
7
8
|
const QUEUE_ITEM_PROMPT_HTML_LIMIT = 3600;
|
|
8
9
|
const QUEUE_ITEM_PROMPT_TRUNCATION_SUFFIX = "\n… [truncated]";
|
|
9
10
|
const EMPTY_QUEUE_REFRESH_TITLES = [
|
|
@@ -29,15 +30,25 @@ function getTelegramQueueItemPromptText(item) {
|
|
|
29
30
|
.join("\n")
|
|
30
31
|
.trim() || item.statusSummary);
|
|
31
32
|
}
|
|
32
|
-
function toTelegramQueueMenuItems(items) {
|
|
33
|
+
function toTelegramQueueMenuItems(items, pendingDispatch = false) {
|
|
34
|
+
const head = items[0];
|
|
33
35
|
return items.map((item, index) => {
|
|
36
|
+
const dispatchProtected = pendingDispatch && (item === head ||
|
|
37
|
+
(head?.kind === "prompt" && head.steerPacketTail?.includes(item) === true));
|
|
38
|
+
const attemptFrozen = item.kind === "prompt" && item.steerAttempted === true && !dispatchProtected;
|
|
39
|
+
const editable = item.kind === "prompt" && item.guestQueryId === undefined && item.guestInlineMessageId === undefined && !dispatchProtected && !attemptFrozen;
|
|
34
40
|
return {
|
|
35
41
|
chatId: item.chatId,
|
|
36
42
|
replyToMessageId: item.replyToMessageId,
|
|
37
43
|
queueOrder: item.queueOrder,
|
|
38
44
|
isGuest: item.kind === "prompt" && item.guestQueryId !== undefined,
|
|
39
45
|
queuePosition: index + 1,
|
|
40
|
-
|
|
46
|
+
queueLane: item.queueLane,
|
|
47
|
+
canSelectLane: editable && item.queueLane !== "control",
|
|
48
|
+
canSelectDisposition: editable && (item.queueLane !== "control" || item.sourceMessageIds.includes(item.replyToMessageId)),
|
|
49
|
+
dispatchProtected, attemptFrozen,
|
|
50
|
+
exceedsIdleCapacity: item.kind === "prompt" && item.queueLane === "steer" && !item.steerAttempted &&
|
|
51
|
+
!Queue.isTelegramSteerItemWithinIdleCapacity(item),
|
|
41
52
|
priorityEmoji: item.kind === "prompt" ? item.priorityEmoji : undefined,
|
|
42
53
|
reactionSuppressionEmoji: item.kind === "prompt" ? item.reactionSuppressionEmoji : undefined,
|
|
43
54
|
hasAttachments: item.kind === "prompt" && item.queuedAttachments.length > 0,
|
|
@@ -59,18 +70,16 @@ function buildTelegramQueueMenuReplyMarkup(items, emptyRefreshIndex = 0) {
|
|
|
59
70
|
if (items.length === 0)
|
|
60
71
|
return { inline_keyboard: [backRow, refreshRow] };
|
|
61
72
|
const rows = items.map((item) => {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
: item.
|
|
65
|
-
? `${item.priorityEmoji ?? "⚡"} `
|
|
66
|
-
: item.hasAttachments
|
|
67
|
-
? "📎 "
|
|
68
|
-
: "";
|
|
73
|
+
const badge = getTelegramQueueMenuLaneBadge(item);
|
|
74
|
+
const prefix = item.reactionSuppressionEmoji ? "👎 " :
|
|
75
|
+
badge ? `${badge} ` : item.hasAttachments ? "📎 " : "";
|
|
69
76
|
const position = item.reactionSuppressionEmoji
|
|
70
77
|
? formatSkippedTelegramQueuePosition(item.queuePosition)
|
|
71
78
|
: String(item.queuePosition);
|
|
72
79
|
const ordinalSeparator = item.reactionSuppressionEmoji ? "\u200A" : "";
|
|
73
|
-
const
|
|
80
|
+
const state = item.attemptFrozen ? " · frozen" : item.dispatchProtected ? " · dispatch protected" :
|
|
81
|
+
item.exceedsIdleCapacity ? " · idle capacity" : "";
|
|
82
|
+
const label = `${position}${ordinalSeparator}. ${prefix}${item.statusSummary}${state}`;
|
|
74
83
|
return [
|
|
75
84
|
{
|
|
76
85
|
text: label,
|
|
@@ -114,18 +123,28 @@ function escapeTelegramQueueMenuHtmlPreview(text) {
|
|
|
114
123
|
}
|
|
115
124
|
return truncated ? escaped + suffix : escaped;
|
|
116
125
|
}
|
|
126
|
+
function getTelegramQueueMenuLaneBadge(item) {
|
|
127
|
+
if (item.queueLane === "control")
|
|
128
|
+
return "⚡";
|
|
129
|
+
if (item.queueLane === "steer")
|
|
130
|
+
return "🔥";
|
|
131
|
+
if (item.queueLane !== "priority")
|
|
132
|
+
return "";
|
|
133
|
+
return "👍";
|
|
134
|
+
}
|
|
117
135
|
function getTelegramQueueMenuItemText(item) {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
: item.isPriority
|
|
121
|
-
? ` ${item.priorityEmoji ?? "⚡"}`
|
|
122
|
-
: "";
|
|
136
|
+
const marker = item.reactionSuppressionEmoji ? "👎" : getTelegramQueueMenuLaneBadge(item);
|
|
137
|
+
const badge = marker ? ` ${marker}` : "";
|
|
123
138
|
const position = item.reactionSuppressionEmoji
|
|
124
139
|
? `<s>${item.queuePosition}</s>.`
|
|
125
140
|
: `<b>${item.queuePosition}.</b>`;
|
|
126
141
|
const heading = `${position}${badge}`;
|
|
127
142
|
const preview = `<pre>${escapeTelegramQueueMenuHtmlPreview(item.promptText)}</pre>`;
|
|
128
|
-
|
|
143
|
+
const note = item.attemptFrozen ? "\n<b>⚠️ Attempt frozen.</b>\nSDK/model use is unconfirmed; not editable or automatically retried." :
|
|
144
|
+
item.dispatchProtected ? "\n<b>⏳ Dispatch protected.</b>\nWaiting for agent_start; SDK/model use is unconfirmed." :
|
|
145
|
+
item.exceedsIdleCapacity ? "\n<b>⚠️ Idle Steer capacity exceeded.</b>\nEdit the source or choose Priority/Normal; source groups are never split." :
|
|
146
|
+
item.queueLane === "control" ? "\nControl lane is producer-owned." : "";
|
|
147
|
+
return `${heading}\n${preview}${note}`;
|
|
129
148
|
}
|
|
130
149
|
function buildTelegramGuestQueueItemSubmenuReplyMarkup(queueOrder) {
|
|
131
150
|
return {
|
|
@@ -140,32 +159,20 @@ function buildTelegramGuestQueueItemSubmenuReplyMarkup(queueOrder) {
|
|
|
140
159
|
],
|
|
141
160
|
};
|
|
142
161
|
}
|
|
143
|
-
function buildTelegramQueueItemSubmenuReplyMarkup(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
[
|
|
158
|
-
{
|
|
159
|
-
text: isSkipped ? "⚫️ Keep" : "🟢 Keep",
|
|
160
|
-
callback_data: `queue:skip-set:${chatId}:${replyToMessageId}:keep`,
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
text: isSkipped ? "🔴 Skip" : "⚫️ Skip",
|
|
164
|
-
callback_data: `queue:skip-set:${chatId}:${replyToMessageId}:skip`,
|
|
165
|
-
},
|
|
166
|
-
],
|
|
167
|
-
],
|
|
168
|
-
};
|
|
162
|
+
function buildTelegramQueueItemSubmenuReplyMarkup(item) {
|
|
163
|
+
const rows = [[{ text: "⬆️ Back", callback_data: "queue:list" }]];
|
|
164
|
+
if (item.canSelectLane)
|
|
165
|
+
rows.push([
|
|
166
|
+
{ text: item.queueLane === "default" ? "🔵 Normal" : "⚫️ Normal", callback_data: `queue:lane-set:${item.chatId}:${item.replyToMessageId}:normal` },
|
|
167
|
+
{ text: item.queueLane === "priority" ? "🟣 Priority" : "⚫️ Priority", callback_data: `queue:lane-set:${item.chatId}:${item.replyToMessageId}:priority` },
|
|
168
|
+
{ text: item.queueLane === "steer" ? "🟡 Steer" : "⚫️ Steer", callback_data: `queue:lane-set:${item.chatId}:${item.replyToMessageId}:steer` },
|
|
169
|
+
]);
|
|
170
|
+
if (item.canSelectDisposition)
|
|
171
|
+
rows.push([
|
|
172
|
+
{ text: item.reactionSuppressionEmoji ? "⚫️ Keep" : "🟢 Keep", callback_data: `queue:skip-set:${item.chatId}:${item.replyToMessageId}:keep` },
|
|
173
|
+
{ text: item.reactionSuppressionEmoji ? "🔴 Skip" : "⚫️ Skip", callback_data: `queue:skip-set:${item.chatId}:${item.replyToMessageId}:skip` },
|
|
174
|
+
]);
|
|
175
|
+
return { inline_keyboard: rows };
|
|
169
176
|
}
|
|
170
177
|
async function handleTelegramQueueMenuCallback(callbackQueryId, data, replyChatId, replyMessageId, ctx, deps) {
|
|
171
178
|
if (!data.startsWith("queue:"))
|
|
@@ -190,7 +197,13 @@ async function handleTelegramQueueMenuCallback(callbackQueryId, data, replyChatI
|
|
|
190
197
|
}
|
|
191
198
|
const guestSkipMatch = data.match(/^queue:guest-skip:(\d+)$/);
|
|
192
199
|
if (guestSkipMatch) {
|
|
193
|
-
const
|
|
200
|
+
const queueOrder = Number(guestSkipMatch[1]);
|
|
201
|
+
const item = deps.findGuestItem(queueOrder);
|
|
202
|
+
if (item?.dispatchProtected || item?.attemptFrozen) {
|
|
203
|
+
await deps.answerCallbackQuery(callbackQueryId, "Queue item is protected");
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
const skipped = await deps.skipGuest(queueOrder, ctx);
|
|
194
207
|
if (!skipped) {
|
|
195
208
|
await refreshStaleTelegramQueueMenuItem(callbackQueryId, replyChatId, replyMessageId, deps);
|
|
196
209
|
return true;
|
|
@@ -203,9 +216,9 @@ async function handleTelegramQueueMenuCallback(callbackQueryId, data, replyChatI
|
|
|
203
216
|
await handleTelegramQueueMenuPick(callbackQueryId, replyChatId, replyMessageId, Number(pickMatch[1]), Number(pickMatch[2]), deps);
|
|
204
217
|
return true;
|
|
205
218
|
}
|
|
206
|
-
const prioSetMatch = data.match(/^queue:prio-set:(\d+):(\d+):(priority|normal)$/);
|
|
219
|
+
const prioSetMatch = data.match(/^queue:(?:lane-set|prio-set):(\d+):(\d+):(steer|priority|normal)$/);
|
|
207
220
|
if (prioSetMatch) {
|
|
208
|
-
await
|
|
221
|
+
await handleTelegramQueueMenuLaneSet(callbackQueryId, replyChatId, replyMessageId, Number(prioSetMatch[1]), Number(prioSetMatch[2]), prioSetMatch[3] === "normal" ? "default" : prioSetMatch[3], ctx, deps);
|
|
209
222
|
return true;
|
|
210
223
|
}
|
|
211
224
|
const prioMatch = data.match(/^queue:prio:(\d+):(\d+)$/);
|
|
@@ -240,7 +253,9 @@ async function handleTelegramGuestQueueMenuPick(callbackQueryId, replyChatId, re
|
|
|
240
253
|
if (!item) {
|
|
241
254
|
return refreshStaleTelegramQueueMenuItem(callbackQueryId, replyChatId, replyMessageId, deps);
|
|
242
255
|
}
|
|
243
|
-
await deps.updateQueueMessage(replyChatId, replyMessageId, getTelegramQueueMenuItemText(item),
|
|
256
|
+
await deps.updateQueueMessage(replyChatId, replyMessageId, getTelegramQueueMenuItemText(item), item.dispatchProtected || item.attemptFrozen
|
|
257
|
+
? buildTelegramQueueItemSubmenuReplyMarkup(item)
|
|
258
|
+
: buildTelegramGuestQueueItemSubmenuReplyMarkup(queueOrder));
|
|
244
259
|
await deps.answerCallbackQuery(callbackQueryId);
|
|
245
260
|
}
|
|
246
261
|
async function handleTelegramQueueMenuPick(callbackQueryId, replyChatId, replyMessageId, chatId, msgId, deps) {
|
|
@@ -248,7 +263,7 @@ async function handleTelegramQueueMenuPick(callbackQueryId, replyChatId, replyMe
|
|
|
248
263
|
if (!item) {
|
|
249
264
|
return refreshStaleTelegramQueueMenuItem(callbackQueryId, replyChatId, replyMessageId, deps);
|
|
250
265
|
}
|
|
251
|
-
await deps.updateQueueMessage(replyChatId, replyMessageId, getTelegramQueueMenuItemText(item), buildTelegramQueueItemSubmenuReplyMarkup(
|
|
266
|
+
await deps.updateQueueMessage(replyChatId, replyMessageId, getTelegramQueueMenuItemText(item), buildTelegramQueueItemSubmenuReplyMarkup(item));
|
|
252
267
|
await deps.answerCallbackQuery(callbackQueryId);
|
|
253
268
|
}
|
|
254
269
|
async function handleTelegramQueueMenuPriority(callbackQueryId, replyChatId, replyMessageId, chatId, msgId, ctx, deps) {
|
|
@@ -256,37 +271,43 @@ async function handleTelegramQueueMenuPriority(callbackQueryId, replyChatId, rep
|
|
|
256
271
|
if (!item) {
|
|
257
272
|
return refreshStaleTelegramQueueMenuItem(callbackQueryId, replyChatId, replyMessageId, deps);
|
|
258
273
|
}
|
|
259
|
-
await
|
|
274
|
+
await updateTelegramQueueMenuLane(callbackQueryId, replyChatId, replyMessageId, chatId, msgId, item.queueLane === "priority" ? "default" : "priority", ctx, deps);
|
|
260
275
|
}
|
|
261
|
-
async function
|
|
276
|
+
async function handleTelegramQueueMenuLaneSet(callbackQueryId, replyChatId, replyMessageId, chatId, msgId, lane, ctx, deps) {
|
|
262
277
|
const item = deps.findItem(chatId, msgId);
|
|
263
278
|
if (!item) {
|
|
264
279
|
return refreshStaleTelegramQueueMenuItem(callbackQueryId, replyChatId, replyMessageId, deps);
|
|
265
280
|
}
|
|
266
|
-
await
|
|
281
|
+
await updateTelegramQueueMenuLane(callbackQueryId, replyChatId, replyMessageId, chatId, msgId, lane, ctx, deps);
|
|
267
282
|
}
|
|
268
|
-
async function
|
|
269
|
-
deps.
|
|
283
|
+
async function updateTelegramQueueMenuLane(callbackQueryId, replyChatId, replyMessageId, chatId, msgId, lane, ctx, deps) {
|
|
284
|
+
if (!deps.setLane(chatId, msgId, lane)) {
|
|
285
|
+
await deps.answerCallbackQuery(callbackQueryId, "Queue item is protected");
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
270
288
|
deps.updateStatus(ctx);
|
|
271
289
|
const updated = deps.findItem(chatId, msgId);
|
|
272
290
|
if (!updated) {
|
|
273
291
|
return refreshStaleTelegramQueueMenuItem(callbackQueryId, replyChatId, replyMessageId, deps);
|
|
274
292
|
}
|
|
275
|
-
await deps.updateQueueMessage(replyChatId, replyMessageId, getTelegramQueueMenuItemText(updated), buildTelegramQueueItemSubmenuReplyMarkup(
|
|
276
|
-
await deps.answerCallbackQuery(callbackQueryId, updated.
|
|
293
|
+
await deps.updateQueueMessage(replyChatId, replyMessageId, getTelegramQueueMenuItemText(updated), buildTelegramQueueItemSubmenuReplyMarkup(updated));
|
|
294
|
+
await deps.answerCallbackQuery(callbackQueryId, updated.queueLane === "steer" ? "Steer selected" : updated.queueLane === "priority" ? "Prioritized" : "Normal priority");
|
|
277
295
|
}
|
|
278
296
|
async function handleTelegramQueueMenuSkipSet(callbackQueryId, replyChatId, replyMessageId, chatId, msgId, skipped, ctx, deps) {
|
|
279
297
|
const item = deps.findItem(chatId, msgId);
|
|
280
298
|
if (!item) {
|
|
281
299
|
return refreshStaleTelegramQueueMenuItem(callbackQueryId, replyChatId, replyMessageId, deps);
|
|
282
300
|
}
|
|
283
|
-
deps.setSkipped(chatId, msgId, skipped)
|
|
301
|
+
if (!deps.setSkipped(chatId, msgId, skipped)) {
|
|
302
|
+
await deps.answerCallbackQuery(callbackQueryId, "Queue item is protected");
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
284
305
|
deps.updateStatus(ctx);
|
|
285
306
|
const updated = deps.findItem(chatId, msgId);
|
|
286
307
|
if (!updated) {
|
|
287
308
|
return refreshStaleTelegramQueueMenuItem(callbackQueryId, replyChatId, replyMessageId, deps);
|
|
288
309
|
}
|
|
289
|
-
await deps.updateQueueMessage(replyChatId, replyMessageId, getTelegramQueueMenuItemText(updated), buildTelegramQueueItemSubmenuReplyMarkup(
|
|
310
|
+
await deps.updateQueueMessage(replyChatId, replyMessageId, getTelegramQueueMenuItemText(updated), buildTelegramQueueItemSubmenuReplyMarkup(updated));
|
|
290
311
|
await deps.answerCallbackQuery(callbackQueryId);
|
|
291
312
|
}
|
|
292
313
|
export function createTelegramQueueMenuRuntime(deps) {
|
|
@@ -297,6 +318,7 @@ export function createTelegramQueueMenuRuntime(deps) {
|
|
|
297
318
|
const delivery = createTelegramMenuDelivery({ chatId, threadId }, options, deps);
|
|
298
319
|
return createOpenQueueMenu({
|
|
299
320
|
getQueuedItems: deps.telegramQueueStore.getQueuedItems,
|
|
321
|
+
hasPendingDispatch: deps.hasPendingDispatch,
|
|
300
322
|
getModelMenuState: (chat, context) => deps.getModelMenuState(chat, context, threadId),
|
|
301
323
|
storeModelMenuState: delivery.storeModelMenuState,
|
|
302
324
|
sendInteractiveMessage: delivery.assertAuthority
|
|
@@ -305,6 +327,7 @@ export function createTelegramQueueMenuRuntime(deps) {
|
|
|
305
327
|
})(chatId, replyToMessageId, ctx);
|
|
306
328
|
},
|
|
307
329
|
handleCallbackQuery: createQueueMenuCallbackHandler({
|
|
330
|
+
hasPendingDispatch: deps.hasPendingDispatch,
|
|
308
331
|
telegramQueueStore: deps.telegramQueueStore,
|
|
309
332
|
queueMutationRuntime: deps.queueMutationRuntime,
|
|
310
333
|
editInteractiveMessage: editQueueMenuMessage,
|
|
@@ -319,7 +342,7 @@ export function createTelegramQueueMenuRuntime(deps) {
|
|
|
319
342
|
function createOpenQueueMenu(deps) {
|
|
320
343
|
return async (chatId, replyToMessageId, ctx) => {
|
|
321
344
|
const state = await deps.getModelMenuState(chatId, ctx);
|
|
322
|
-
const menuItems = toTelegramQueueMenuItems(deps.getQueuedItems());
|
|
345
|
+
const menuItems = toTelegramQueueMenuItems(deps.getQueuedItems(), deps.hasPendingDispatch?.());
|
|
323
346
|
const text = getTelegramQueueMenuListText(menuItems);
|
|
324
347
|
const messageId = await deps.sendInteractiveMessage(chatId, replyToMessageId, text, buildTelegramQueueMenuReplyMarkup(menuItems));
|
|
325
348
|
if (messageId === undefined)
|
|
@@ -342,7 +365,7 @@ function createQueueMenuCallbackHandler(deps) {
|
|
|
342
365
|
await deps.answerCallbackQuery(query.id, "Interactive message expired");
|
|
343
366
|
return true;
|
|
344
367
|
}
|
|
345
|
-
const menuItems = toTelegramQueueMenuItems(deps.telegramQueueStore.getQueuedItems());
|
|
368
|
+
const menuItems = toTelegramQueueMenuItems(deps.telegramQueueStore.getQueuedItems(), deps.hasPendingDispatch?.());
|
|
346
369
|
await deps.editInteractiveMessage(chatId, messageId, getTelegramQueueMenuListText(menuItems), buildTelegramQueueMenuReplyMarkup(menuItems));
|
|
347
370
|
state.mode = "queue";
|
|
348
371
|
await deps.answerCallbackQuery(query.id);
|
|
@@ -354,7 +377,7 @@ function createQueueMenuCallbackHandler(deps) {
|
|
|
354
377
|
return deps.telegramQueueStore.getQueuedItems();
|
|
355
378
|
};
|
|
356
379
|
const toMenuItems = () => {
|
|
357
|
-
return toTelegramQueueMenuItems(getQueueSnapshot());
|
|
380
|
+
return toTelegramQueueMenuItems(getQueueSnapshot(), deps.hasPendingDispatch?.());
|
|
358
381
|
};
|
|
359
382
|
const findItem = (cId, rId) => {
|
|
360
383
|
return findTelegramQueueItem(toMenuItems(), cId, rId);
|
|
@@ -367,6 +390,7 @@ function createQueueMenuCallbackHandler(deps) {
|
|
|
367
390
|
const flagDeps = {
|
|
368
391
|
getQueueSnapshot,
|
|
369
392
|
queueMutationRuntime: deps.queueMutationRuntime,
|
|
393
|
+
hasPendingDispatch: deps.hasPendingDispatch,
|
|
370
394
|
};
|
|
371
395
|
return handleTelegramQueueMenuCallback(query.id, data, chatId, messageId, ctx, {
|
|
372
396
|
getQueuedItems: toMenuItems,
|
|
@@ -379,17 +403,8 @@ function createQueueMenuCallbackHandler(deps) {
|
|
|
379
403
|
dismissGuestPlaceholder: deps.dismissGuestPlaceholder,
|
|
380
404
|
});
|
|
381
405
|
},
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
skipped: isQueuedTelegramPromptSkipped(item),
|
|
385
|
-
})),
|
|
386
|
-
setPriority: (cId, rId, enabled) => applyQueuedTelegramPromptMenuFlags(cId, rId, ctx, flagDeps, (item) => ({
|
|
387
|
-
priority: enabled,
|
|
388
|
-
skipped: isQueuedTelegramPromptSkipped(item),
|
|
389
|
-
})),
|
|
390
|
-
setSkipped: (cId, rId, skipped) => applyQueuedTelegramPromptMenuFlags(cId, rId, ctx, flagDeps, (item) => item.kind === "prompt"
|
|
391
|
-
? { priority: item.queueLane === "priority", skipped }
|
|
392
|
-
: undefined),
|
|
406
|
+
setLane: (cId, rId, lane) => applyQueuedTelegramPromptMenuFlags(cId, rId, ctx, flagDeps, () => ({ lane })),
|
|
407
|
+
setSkipped: (cId, rId, skipped) => applyQueuedTelegramPromptMenuFlags(cId, rId, ctx, flagDeps, () => ({ skipped })),
|
|
393
408
|
updateQueueMessage: deps.editInteractiveMessage,
|
|
394
409
|
answerCallbackQuery: deps.answerCallbackQuery,
|
|
395
410
|
updateStatus: deps.updateStatus,
|
|
@@ -413,39 +428,25 @@ async function skipQueuedTelegramGuestPrompt(queueOrder, ctx, deps) {
|
|
|
413
428
|
}
|
|
414
429
|
return true;
|
|
415
430
|
}
|
|
416
|
-
|
|
417
|
-
if (priority && skipped) {
|
|
418
|
-
return {
|
|
419
|
-
kind: "priority-suppressed",
|
|
420
|
-
priorityEmoji: item.kind === "prompt" ? (item.priorityEmoji ?? "⚡") : "⚡",
|
|
421
|
-
suppressionEmoji: item.kind === "prompt" ? (item.reactionSuppressionEmoji ?? "👎") : "👎",
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
if (priority) {
|
|
425
|
-
return {
|
|
426
|
-
kind: "priority",
|
|
427
|
-
emoji: item.kind === "prompt" ? (item.priorityEmoji ?? "⚡") : "⚡",
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
if (skipped) {
|
|
431
|
-
return {
|
|
432
|
-
kind: "suppressed",
|
|
433
|
-
emoji: item.kind === "prompt" ? (item.reactionSuppressionEmoji ?? "👎") : "👎",
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
return { kind: "default" };
|
|
437
|
-
}
|
|
438
|
-
function isQueuedTelegramPromptSkipped(item) {
|
|
439
|
-
return item.kind === "prompt" && item.reactionSuppressionEmoji !== undefined;
|
|
440
|
-
}
|
|
441
|
-
/** Applies a menu Priority/Skip choice to one queued item through the reaction disposition path. */
|
|
431
|
+
/** Each menu selection changes one dimension through the existing Queue owner. */
|
|
442
432
|
function applyQueuedTelegramPromptMenuFlags(chatId, replyToMessageId, ctx, deps, chooseFlags) {
|
|
443
433
|
const item = findTelegramQueueItem(deps.getQueueSnapshot(), chatId, replyToMessageId);
|
|
444
434
|
const flags = item ? chooseFlags(item) : undefined;
|
|
445
|
-
if (!item || !flags)
|
|
435
|
+
if (!item || item.kind !== "prompt" || !flags)
|
|
446
436
|
return false;
|
|
447
|
-
deps.
|
|
448
|
-
|
|
437
|
+
const view = findTelegramQueueItem(toTelegramQueueMenuItems(deps.getQueueSnapshot(), deps.hasPendingDispatch?.()), chatId, replyToMessageId);
|
|
438
|
+
if (!view || (flags.lane !== undefined && !view.canSelectLane) || (flags.skipped !== undefined && !view.canSelectDisposition))
|
|
439
|
+
return false;
|
|
440
|
+
const disposition = { kind: "reaction-transition" };
|
|
441
|
+
if (flags.lane !== undefined) {
|
|
442
|
+
disposition.promptLane = flags.lane;
|
|
443
|
+
disposition.priorityEmoji = flags.lane === "steer" ? "🔥" : flags.lane === "priority" ? "👍" : null;
|
|
444
|
+
}
|
|
445
|
+
if (flags.skipped !== undefined)
|
|
446
|
+
disposition.suppressionEmoji = flags.skipped ? "👎" : null;
|
|
447
|
+
return deps.queueMutationRuntime.applyReactionByMessageId(replyToMessageId, disposition, ctx) ||
|
|
448
|
+
((flags.lane === undefined || flags.lane === item.queueLane) &&
|
|
449
|
+
(flags.skipped === undefined || flags.skipped === (item.reactionSuppressionEmoji !== undefined)));
|
|
449
450
|
}
|
|
450
451
|
function createQueueMenuSendMessageAdapter(sendInteractiveMessage) {
|
|
451
452
|
return (chatId, _replyToMessageId, text, replyMarkup) => {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Owns direct pi SDK imports and exposes narrow bridge-facing helpers/types for the extension composition layer
|
|
5
5
|
*/
|
|
6
6
|
import type { AssistantMessageEvent } from "@earendil-works/pi-ai";
|
|
7
|
-
import { type AgentEndEvent, type AgentSettledEvent, type AgentStartEvent, type BeforeAgentStartEvent, type ExtensionAPI, type ExtensionCommandContext, type ExtensionContext, type InputEvent, type MessageEndEvent, type SessionBeforeCompactEvent, type SessionCompactEvent, type SessionShutdownEvent, type SessionStartEvent, type SlashCommandInfo, type UIPromptEndEvent, type UIPromptStartEvent } from "@earendil-works/pi-coding-agent";
|
|
8
|
-
export type { AgentEndEvent, AgentSettledEvent, AgentStartEvent, AssistantMessageEvent, BeforeAgentStartEvent, ExtensionAPI, ExtensionCommandContext, ExtensionContext, InputEvent, MessageEndEvent, SessionBeforeCompactEvent, SessionCompactEvent, SessionShutdownEvent, SessionStartEvent, SlashCommandInfo, UIPromptEndEvent, UIPromptStartEvent, };
|
|
7
|
+
import { type AgentEndEvent, type AgentSettledEvent, type AgentStartEvent, type BeforeAgentStartEvent, type ExtensionAPI, type ExtensionCommandContext, type ExtensionContext, type InputEvent, type MessageEndEvent, type SessionBeforeCompactEvent, type SessionCompactEvent, type SessionShutdownEvent, type SessionStartEvent, type SlashCommandInfo, type TurnEndEvent, type TurnEndEventResult, type UIPromptEndEvent, type UIPromptStartEvent } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
export type { AgentEndEvent, AgentSettledEvent, AgentStartEvent, AssistantMessageEvent, BeforeAgentStartEvent, ExtensionAPI, ExtensionCommandContext, ExtensionContext, InputEvent, MessageEndEvent, SessionBeforeCompactEvent, SessionCompactEvent, SessionShutdownEvent, SessionStartEvent, SlashCommandInfo, TurnEndEvent, TurnEndEventResult, UIPromptEndEvent, UIPromptStartEvent, };
|
|
9
9
|
export interface SessionCompactFailedEvent {
|
|
10
10
|
type: "session_compact_failed";
|
|
11
11
|
reason: "manual" | "threshold" | "overflow";
|
|
@@ -72,5 +72,6 @@ export declare function getExtensionContextCwd(ctx: ExtensionContext): string;
|
|
|
72
72
|
export declare function getExtensionContextSessionId(ctx: ExtensionContext): string;
|
|
73
73
|
export declare function getExtensionContextSessionId(ctx: ExtensionContext | undefined): string | undefined;
|
|
74
74
|
export declare function isExtensionContextIdle(ctx: ExtensionContext): boolean;
|
|
75
|
+
export declare function isExtensionContextAbortRequested(ctx: ExtensionContext): boolean;
|
|
75
76
|
export declare function hasExtensionContextPendingMessages(ctx: ExtensionContext): boolean;
|
|
76
77
|
export declare function compactExtensionContext(ctx: ExtensionContext, callbacks: Parameters<ExtensionContext["compact"]>[0]): ReturnType<ExtensionContext["compact"]>;
|
|
@@ -122,6 +122,9 @@ export function getExtensionContextSessionId(ctx) {
|
|
|
122
122
|
export function isExtensionContextIdle(ctx) {
|
|
123
123
|
return ctx.isIdle();
|
|
124
124
|
}
|
|
125
|
+
export function isExtensionContextAbortRequested(ctx) {
|
|
126
|
+
return ctx.signal?.aborted === true;
|
|
127
|
+
}
|
|
125
128
|
export function hasExtensionContextPendingMessages(ctx) {
|
|
126
129
|
return ctx.hasPendingMessages();
|
|
127
130
|
}
|
|
@@ -221,7 +221,9 @@ export interface TelegramThreadAwarePollingPorts<TContext, TOwner> {
|
|
|
221
221
|
forceFreshLeaderThread?: boolean;
|
|
222
222
|
}) => Promise<void>;
|
|
223
223
|
stopPolling: () => Promise<void>;
|
|
224
|
-
registerFollowerWithOwner: (ctx: TContext, owner: TOwner
|
|
224
|
+
registerFollowerWithOwner: (ctx: TContext, owner: TOwner, options?: {
|
|
225
|
+
recoverConnection?: boolean;
|
|
226
|
+
}) => Promise<boolean | undefined>;
|
|
225
227
|
restoreFollowerWithOwner: (ctx: TContext, owner: TOwner) => Promise<boolean | undefined>;
|
|
226
228
|
stopFollowerRegistration: () => void;
|
|
227
229
|
}
|
|
@@ -233,7 +235,9 @@ export interface TelegramThreadAwarePollingControls<TContext, TOwner> {
|
|
|
233
235
|
stopBusLeaderPolling: () => Promise<void>;
|
|
234
236
|
startLeaderHealth: () => void;
|
|
235
237
|
stopLeaderHealth: () => void;
|
|
236
|
-
registerFollowerWithLeader: (ctx: TContext, owner: TOwner
|
|
238
|
+
registerFollowerWithLeader: (ctx: TContext, owner: TOwner, options?: {
|
|
239
|
+
recoverConnection?: boolean;
|
|
240
|
+
}) => Promise<boolean | undefined>;
|
|
237
241
|
restoreFollowerWithLeader?: (ctx: TContext, owner: TOwner) => Promise<boolean | undefined>;
|
|
238
242
|
hasRememberedWorkspaceBinding?: (ctx: TContext) => boolean;
|
|
239
243
|
stopFollowerRegistration: () => void;
|
|
@@ -752,10 +752,10 @@ export function createTelegramThreadAwarePollingPorts(deps) {
|
|
|
752
752
|
}
|
|
753
753
|
return deps.topicTargetStore.getBotState().threadMode === "enabled";
|
|
754
754
|
};
|
|
755
|
-
const registerFollowerWithOwner = async (ctx, owner) => {
|
|
755
|
+
const registerFollowerWithOwner = async (ctx, owner, options) => {
|
|
756
756
|
if (!(await refreshFollowerState()))
|
|
757
757
|
return undefined;
|
|
758
|
-
return deps.registerFollowerWithLeader(ctx, owner);
|
|
758
|
+
return deps.registerFollowerWithLeader(ctx, owner, options);
|
|
759
759
|
};
|
|
760
760
|
const restoreFollowerWithOwner = async (ctx, owner) => {
|
|
761
761
|
if (!(await refreshFollowerState())) {
|
|
@@ -844,7 +844,9 @@ export function createTelegramThreadCapabilityMonitor(deps) {
|
|
|
844
844
|
consecutiveDisabledProbes = 0;
|
|
845
845
|
const botState = deps.topicTargetStore.getBotState();
|
|
846
846
|
const current = botState.threadMode;
|
|
847
|
-
|
|
847
|
+
// Persisted capability is not proof that this owner started its local bus.
|
|
848
|
+
if (threadModeEnabled && current === "enabled" &&
|
|
849
|
+
(deps.getPollingStartedWithTelegramBus() || !deps.ownsLock(ctx)))
|
|
848
850
|
return;
|
|
849
851
|
if (!threadModeEnabled && current === "disabled") {
|
|
850
852
|
if (!deps.ownsLock(ctx) ||
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Telegram queue core contracts and pure planning helpers
|
|
3
3
|
* Zones: telegram queue, pi agent lifecycle, scheduling
|
|
4
|
-
* Owns queue item contracts, lane admission,
|
|
4
|
+
* Owns queue item contracts, lane admission, mutations, dispatch planning, and protected Steer publication attempts
|
|
5
5
|
*/
|
|
6
|
+
import { type TurnEndEvent, type TurnEndEventResult } from "./pi.ts";
|
|
6
7
|
export interface QueuedAttachment {
|
|
7
8
|
path: string;
|
|
8
9
|
fileName: string;
|
|
@@ -18,7 +19,7 @@ export interface TelegramPromptImageContent {
|
|
|
18
19
|
}
|
|
19
20
|
export type TelegramPromptContent = TelegramPromptTextContent | TelegramPromptImageContent;
|
|
20
21
|
export type TelegramQueueItemKind = "prompt" | "control";
|
|
21
|
-
export type TelegramQueueLane = "control" | "priority" | "default";
|
|
22
|
+
export type TelegramQueueLane = "control" | "steer" | "priority" | "default";
|
|
22
23
|
export type TelegramQueueReactionDisposition = {
|
|
23
24
|
kind: "default";
|
|
24
25
|
} | {
|
|
@@ -33,6 +34,7 @@ export type TelegramQueueReactionDisposition = {
|
|
|
33
34
|
suppressionEmoji: string;
|
|
34
35
|
} | {
|
|
35
36
|
kind: "reaction-transition";
|
|
37
|
+
promptLane?: Exclude<TelegramQueueLane, "control">;
|
|
36
38
|
priorityEmoji?: string | null;
|
|
37
39
|
suppressionEmoji?: string | null;
|
|
38
40
|
};
|
|
@@ -42,7 +44,7 @@ export interface TelegramQueueAdmissionReceipt {
|
|
|
42
44
|
sourceUpdateIds: readonly number[];
|
|
43
45
|
journalBindingKey?: string;
|
|
44
46
|
}
|
|
45
|
-
export type TelegramQueueAdmissionMode = "control-queue" | "priority-queue" | "default-queue";
|
|
47
|
+
export type TelegramQueueAdmissionMode = "control-queue" | "steer-queue" | "priority-queue" | "default-queue";
|
|
46
48
|
export interface TelegramQueueLaneContract {
|
|
47
49
|
lane: TelegramQueueLane;
|
|
48
50
|
admissionMode: TelegramQueueAdmissionMode;
|
|
@@ -84,6 +86,11 @@ export interface PendingTelegramTurn extends TelegramQueueItemBase {
|
|
|
84
86
|
historyText: string;
|
|
85
87
|
priorityEmoji?: string;
|
|
86
88
|
reactionSuppressionEmoji?: string;
|
|
89
|
+
/** Frozen before receipt mutation; failed/partial attempts must never become executable again. */
|
|
90
|
+
steerAttempted?: true;
|
|
91
|
+
/** Original tail objects of an issued idle packet; metadata only, not another waiting queue. */
|
|
92
|
+
steerPacketTail?: readonly PendingTelegramTurn[];
|
|
93
|
+
steerPacketSourceOrders?: readonly number[];
|
|
87
94
|
/** Emit the explicit aborted-turn notice when /next settles this active turn. */
|
|
88
95
|
announceNextAbortOnEnd?: boolean;
|
|
89
96
|
/** Turn should preferably be delivered as voice (mirror mode + user sent voice) */
|
|
@@ -220,8 +227,11 @@ export declare function appendTelegramQueueItem<TContext = unknown, TItem extend
|
|
|
220
227
|
export declare function createTelegramQueueHandoff<TContext>(input: {
|
|
221
228
|
handoffToken: string;
|
|
222
229
|
item: TelegramQueueItem<TContext>;
|
|
230
|
+
steerSupported?: boolean;
|
|
223
231
|
}): TelegramQueueHandoff;
|
|
224
|
-
export declare function createTelegramQueueHandoffPayload<TContext>(item: TelegramQueueItem<TContext
|
|
232
|
+
export declare function createTelegramQueueHandoffPayload<TContext>(item: TelegramQueueItem<TContext>, options?: {
|
|
233
|
+
steerSupported?: boolean;
|
|
234
|
+
}): TelegramQueueHandoffPayload;
|
|
225
235
|
export declare function restoreTelegramQueueHandoffPayload<TContext>(payload: TelegramQueueHandoffPayload, createControlExecution: (payload: TelegramControlQueueHandoffPayload) => PendingTelegramControlItem<TContext>["execute"]): TelegramQueueItem<TContext>;
|
|
226
236
|
export declare function removeTelegramQueueItemByReceipt<TContext>(input: {
|
|
227
237
|
receipt: TelegramQueueAdmissionReceipt;
|
|
@@ -258,7 +268,6 @@ export declare function consumeDispatchedTelegramPrompt<TContext = unknown>(item
|
|
|
258
268
|
activeTurn?: PendingTelegramTurn;
|
|
259
269
|
remainingItems: TelegramQueueItem<TContext>[];
|
|
260
270
|
};
|
|
261
|
-
export declare function formatQueuedTelegramItemsStatus<TContext = unknown>(items: TelegramQueueItem<TContext>[]): string;
|
|
262
271
|
export declare function truncateTelegramQueueSummary(text: string, maxWords?: number, maxLength?: number): string;
|
|
263
272
|
export declare function canDispatchTelegramTurnState(state: TelegramDispatchGuardState): boolean;
|
|
264
273
|
export interface TelegramDispatchReadinessDeps<TContext> {
|
|
@@ -296,6 +305,11 @@ export declare function createTelegramControlItemBuilder<TContext = unknown>(dep
|
|
|
296
305
|
export type TelegramQueueDispatchAction<TContext = unknown> = {
|
|
297
306
|
kind: "none";
|
|
298
307
|
remainingItems: TelegramQueueItem<TContext>[];
|
|
308
|
+
} | {
|
|
309
|
+
kind: "steer";
|
|
310
|
+
item: PendingTelegramTurn;
|
|
311
|
+
packet: readonly PendingTelegramTurn[];
|
|
312
|
+
remainingItems: TelegramQueueItem<TContext>[];
|
|
299
313
|
} | {
|
|
300
314
|
kind: "control";
|
|
301
315
|
item: PendingTelegramControlItem<TContext>;
|
|
@@ -305,6 +319,38 @@ export type TelegramQueueDispatchAction<TContext = unknown> = {
|
|
|
305
319
|
item: PendingTelegramTurn;
|
|
306
320
|
remainingItems: TelegramQueueItem<TContext>[];
|
|
307
321
|
};
|
|
322
|
+
export type TelegramSteerPacketPlan = {
|
|
323
|
+
kind: "none";
|
|
324
|
+
} | {
|
|
325
|
+
kind: "skip";
|
|
326
|
+
item: PendingTelegramTurn;
|
|
327
|
+
} | {
|
|
328
|
+
kind: "packet";
|
|
329
|
+
items: readonly PendingTelegramTurn[];
|
|
330
|
+
};
|
|
331
|
+
/** Plan a fixed ready prefix; publication/settlement remain with the Queue effect shell. */
|
|
332
|
+
export declare function planTelegramSteerPacket<TContext>(items: readonly TelegramQueueItem<TContext>[], options: {
|
|
333
|
+
blocked: boolean;
|
|
334
|
+
isItemReady: (item: TelegramQueueItem<TContext>) => boolean;
|
|
335
|
+
canAppend?: (packet: readonly PendingTelegramTurn[], item: PendingTelegramTurn) => boolean;
|
|
336
|
+
}): TelegramSteerPacketPlan;
|
|
337
|
+
export declare function isTelegramSteerItemWithinIdleCapacity(item: PendingTelegramTurn): boolean;
|
|
338
|
+
export interface TelegramSteerBoundaryRuntimeDeps<TContext> extends TelegramQueueStore<TContext> {
|
|
339
|
+
isContextCurrent: (ctx: TContext) => boolean;
|
|
340
|
+
isBlocked: (ctx: TContext) => boolean;
|
|
341
|
+
getGeneration: () => number;
|
|
342
|
+
isItemReady: (item: TelegramQueueItem<TContext>, ctx: TContext) => boolean;
|
|
343
|
+
isItemCurrent: (item: PendingTelegramTurn, ctx: TContext) => boolean;
|
|
344
|
+
getActiveTurn: () => PendingTelegramTurn | undefined;
|
|
345
|
+
commitPacket: (items: readonly PendingTelegramTurn[], ctx: TContext) => boolean;
|
|
346
|
+
discardItem: (item: PendingTelegramTurn, ctx: TContext) => boolean;
|
|
347
|
+
updateStatus: (ctx: TContext) => void;
|
|
348
|
+
recordRuntimeEvent?: TelegramRuntimeEventRecorderPort["recordRuntimeEvent"];
|
|
349
|
+
}
|
|
350
|
+
/** One publication attempt; journal ACK is source disposition, never SDK/model-use confirmation. */
|
|
351
|
+
export declare function createTelegramSteerBoundaryRuntime<TContext>(deps: TelegramSteerBoundaryRuntimeDeps<TContext>): {
|
|
352
|
+
onTurnEnd(event: Pick<TurnEndEvent, "turnIndex" | "outcome">, ctx: TContext): TurnEndEventResult | undefined;
|
|
353
|
+
};
|
|
308
354
|
export declare function planNextTelegramQueueAction<TContext = unknown>(items: TelegramQueueItem<TContext>[], canDispatch: boolean): TelegramQueueDispatchAction<TContext>;
|
|
309
355
|
export declare function shouldDispatchAfterTelegramAgentEnd(options: {
|
|
310
356
|
hasTurn: boolean;
|
|
@@ -752,6 +798,12 @@ export interface TelegramQueueDispatchControllerDeps<TContext = unknown> extends
|
|
|
752
798
|
sendUserMessage: TelegramDispatchRuntimeDeps<TContext>["sendUserMessage"];
|
|
753
799
|
onPromptDispatchFailure: (ctx: TContext, message: string) => void;
|
|
754
800
|
reconcileNextDispatchAnnouncementReplyOwnership?: (item: PendingTelegramTurn) => void;
|
|
801
|
+
steerDispatch?: {
|
|
802
|
+
commitPacket: (items: readonly PendingTelegramTurn[], ctx: TContext) => boolean;
|
|
803
|
+
isContextCurrent?: (ctx: TContext) => boolean;
|
|
804
|
+
/** Rechecks idle/native/abort guards without rejecting this packet's own pending flag. */
|
|
805
|
+
canSubmit?: (ctx: TContext) => boolean;
|
|
806
|
+
};
|
|
755
807
|
isQueueItemTransportActive?: (item: TelegramQueueItem<TContext>) => boolean;
|
|
756
808
|
hasPendingInboundQueueMutationForItem?: (item: TelegramQueueItem<TContext>) => boolean;
|
|
757
809
|
isQueueItemAdmissionReady?: (item: TelegramQueueItem<TContext>) => boolean;
|