@llblab/pi-kit 0.29.2 → 0.30.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.
Files changed (208) hide show
  1. package/BACKLOG.md +2 -1
  2. package/CHANGELOG.md +9 -0
  3. package/README.md +2 -2
  4. package/node_modules/@llblab/pi-telegram/AGENTS.md +9 -7
  5. package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -18
  6. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +15 -0
  7. package/node_modules/@llblab/pi-telegram/README.md +7 -11
  8. package/node_modules/@llblab/pi-telegram/api/commands.ts +3 -0
  9. package/node_modules/@llblab/pi-telegram/dist/api/commands.d.ts +1 -1
  10. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +1 -5
  11. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +15 -42
  12. package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +9 -0
  13. package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +39 -10
  14. package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.js +7 -3
  15. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +43 -5
  16. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +163 -20
  17. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.d.ts +12 -0
  18. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +182 -79
  19. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +111 -31
  20. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +1324 -359
  21. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +41 -91
  22. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +969 -637
  23. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +16 -9
  24. package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +215 -18
  25. package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +1048 -327
  26. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +5 -0
  27. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +434 -261
  28. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +26 -5
  29. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +92 -176
  30. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +168 -82
  31. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +1409 -291
  32. package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +1 -8
  33. package/node_modules/@llblab/pi-telegram/dist/lib/config.js +34 -76
  34. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +2 -2
  35. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +16 -16
  36. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +639 -171
  37. package/node_modules/@llblab/pi-telegram/dist/lib/generative-app-worker.mjs +19 -7
  38. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +0 -5
  39. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.js +61 -49
  40. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +5 -0
  41. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +35 -59
  42. package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +33 -3
  43. package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +2063 -782
  44. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +2 -6
  45. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +75 -58
  46. package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +29 -3
  47. package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +289 -108
  48. package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +50 -14
  49. package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +22 -1
  50. package/node_modules/@llblab/pi-telegram/dist/lib/media.js +46 -28
  51. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +19 -5
  52. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +53 -11
  53. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.d.ts +5 -4
  54. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.js +45 -63
  55. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +5 -4
  56. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +114 -78
  57. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +1 -1
  58. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +8 -25
  59. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +6 -1
  60. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +14 -21
  61. package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +8 -61
  62. package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +92 -164
  63. package/node_modules/@llblab/pi-telegram/dist/lib/model.d.ts +1 -1
  64. package/node_modules/@llblab/pi-telegram/dist/lib/model.js +2 -16
  65. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +6 -27
  66. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +45 -38
  67. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +22 -16
  68. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +0 -2
  69. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +51 -64
  70. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.js +6 -3
  71. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +6 -6
  72. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +65 -51
  73. package/node_modules/@llblab/pi-telegram/dist/lib/ownership.js +6 -2
  74. package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +5 -0
  75. package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +37 -21
  76. package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +2 -0
  77. package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +8 -1
  78. package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +21 -37
  79. package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +59 -50
  80. package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +39 -19
  81. package/node_modules/@llblab/pi-telegram/dist/lib/process-identity.d.ts +24 -0
  82. package/node_modules/@llblab/pi-telegram/dist/lib/process-identity.js +133 -0
  83. package/node_modules/@llblab/pi-telegram/dist/lib/prompts.js +2 -7
  84. package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +14 -16
  85. package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +252 -127
  86. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +2 -83
  87. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +20 -274
  88. package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +16 -24
  89. package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +99 -116
  90. package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +120 -7
  91. package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +4667 -1152
  92. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.d.ts +1 -11
  93. package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +4 -29
  94. package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +7 -20
  95. package/node_modules/@llblab/pi-telegram/dist/lib/skills.js +4 -3
  96. package/node_modules/@llblab/pi-telegram/dist/lib/status.js +86 -57
  97. package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +1 -3
  98. package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +67 -43
  99. package/node_modules/@llblab/pi-telegram/dist/lib/target.d.ts +4 -0
  100. package/node_modules/@llblab/pi-telegram/dist/lib/target.js +18 -0
  101. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +18 -13
  102. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +148 -53
  103. package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.js +4 -39
  104. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +6 -27
  105. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +369 -186
  106. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +1 -2
  107. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +58 -38
  108. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +28 -8
  109. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +175 -66
  110. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +42 -16
  111. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +90 -50
  112. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +82 -20
  113. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +2247 -855
  114. package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.js +1 -2
  115. package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +1 -19
  116. package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +169 -80
  117. package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +2418 -641
  118. package/node_modules/@llblab/pi-telegram/dist/lib/voice.d.ts +7 -22
  119. package/node_modules/@llblab/pi-telegram/dist/lib/voice.js +7 -22
  120. package/node_modules/@llblab/pi-telegram/dist/lib/wire.js +1 -1
  121. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +3 -1
  122. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +425 -211
  123. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.js +8 -13
  124. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +1 -1
  125. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +328 -140
  126. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.js +8 -4
  127. package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
  128. package/node_modules/@llblab/pi-telegram/docs/architecture.md +31 -29
  129. package/node_modules/@llblab/pi-telegram/docs/inbound.md +1 -1
  130. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +15 -3
  131. package/node_modules/@llblab/pi-telegram/docs/outbound.md +1 -1
  132. package/node_modules/@llblab/pi-telegram/docs/public-api.md +29 -1
  133. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +25 -8
  134. package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +59 -82
  135. package/node_modules/@llblab/pi-telegram/lib/activity.ts +146 -102
  136. package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +12 -5
  137. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +389 -82
  138. package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +263 -102
  139. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +2440 -601
  140. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +2209 -1290
  141. package/node_modules/@llblab/pi-telegram/lib/bus-transport.ts +46 -12
  142. package/node_modules/@llblab/pi-telegram/lib/bus.ts +1673 -444
  143. package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +848 -327
  144. package/node_modules/@llblab/pi-telegram/lib/command-templates.ts +152 -265
  145. package/node_modules/@llblab/pi-telegram/lib/commands.ts +2398 -555
  146. package/node_modules/@llblab/pi-telegram/lib/config.ts +177 -170
  147. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +41 -29
  148. package/node_modules/@llblab/pi-telegram/lib/extension.ts +1206 -433
  149. package/node_modules/@llblab/pi-telegram/lib/generative-app-worker.mjs +19 -7
  150. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +324 -211
  151. package/node_modules/@llblab/pi-telegram/lib/inbound.ts +95 -97
  152. package/node_modules/@llblab/pi-telegram/lib/journal.ts +5311 -1763
  153. package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +1 -3
  154. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +128 -78
  155. package/node_modules/@llblab/pi-telegram/lib/locks.ts +677 -203
  156. package/node_modules/@llblab/pi-telegram/lib/logging.ts +147 -58
  157. package/node_modules/@llblab/pi-telegram/lib/media.ts +82 -43
  158. package/node_modules/@llblab/pi-telegram/lib/menu-model.ts +85 -18
  159. package/node_modules/@llblab/pi-telegram/lib/menu-queue.ts +88 -129
  160. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +260 -155
  161. package/node_modules/@llblab/pi-telegram/lib/menu-status.ts +20 -60
  162. package/node_modules/@llblab/pi-telegram/lib/menu-thinking.ts +41 -56
  163. package/node_modules/@llblab/pi-telegram/lib/menu.ts +112 -285
  164. package/node_modules/@llblab/pi-telegram/lib/model.ts +8 -22
  165. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +156 -125
  166. package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +76 -49
  167. package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +96 -94
  168. package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +33 -27
  169. package/node_modules/@llblab/pi-telegram/lib/outbound.ts +128 -125
  170. package/node_modules/@llblab/pi-telegram/lib/ownership.ts +19 -10
  171. package/node_modules/@llblab/pi-telegram/lib/paths.ts +148 -49
  172. package/node_modules/@llblab/pi-telegram/lib/pi.ts +35 -15
  173. package/node_modules/@llblab/pi-telegram/lib/polling.ts +144 -147
  174. package/node_modules/@llblab/pi-telegram/lib/preview.ts +93 -40
  175. package/node_modules/@llblab/pi-telegram/lib/process-identity.ts +164 -0
  176. package/node_modules/@llblab/pi-telegram/lib/prompts.ts +4 -11
  177. package/node_modules/@llblab/pi-telegram/lib/queue.ts +516 -301
  178. package/node_modules/@llblab/pi-telegram/lib/recovery.ts +50 -454
  179. package/node_modules/@llblab/pi-telegram/lib/rendering.ts +1 -3
  180. package/node_modules/@llblab/pi-telegram/lib/replies.ts +248 -209
  181. package/node_modules/@llblab/pi-telegram/lib/routing.ts +8509 -2186
  182. package/node_modules/@llblab/pi-telegram/lib/runtime.ts +1 -12
  183. package/node_modules/@llblab/pi-telegram/lib/sections.ts +24 -89
  184. package/node_modules/@llblab/pi-telegram/lib/setup.ts +1 -3
  185. package/node_modules/@llblab/pi-telegram/lib/skills.ts +9 -4
  186. package/node_modules/@llblab/pi-telegram/lib/status.ts +215 -110
  187. package/node_modules/@llblab/pi-telegram/lib/sync.ts +448 -361
  188. package/node_modules/@llblab/pi-telegram/lib/target.ts +22 -3
  189. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +302 -127
  190. package/node_modules/@llblab/pi-telegram/lib/text-groups.ts +5 -39
  191. package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +833 -331
  192. package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +213 -97
  193. package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +232 -87
  194. package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +155 -72
  195. package/node_modules/@llblab/pi-telegram/lib/threads.ts +5318 -1845
  196. package/node_modules/@llblab/pi-telegram/lib/time-injection.ts +1 -4
  197. package/node_modules/@llblab/pi-telegram/lib/turns.ts +15 -28
  198. package/node_modules/@llblab/pi-telegram/lib/updates.ts +5184 -1612
  199. package/node_modules/@llblab/pi-telegram/lib/voice.ts +7 -35
  200. package/node_modules/@llblab/pi-telegram/lib/wire.ts +1 -1
  201. package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +996 -416
  202. package/node_modules/@llblab/pi-telegram/lib/workspace-identity.ts +14 -17
  203. package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +878 -376
  204. package/node_modules/@llblab/pi-telegram/lib/workspace-slots.ts +22 -13
  205. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  206. package/package.json +2 -2
  207. package/node_modules/@llblab/pi-telegram/scripts/check-downgrade.mjs +0 -472
  208. package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +0 -108
@@ -5,15 +5,13 @@
5
5
  */
6
6
 
7
7
  import {
8
- createTelegramModelMenuStateBuilder,
8
+ createTelegramMenuDelivery,
9
9
  handleTelegramModelMenuCallbackAction,
10
10
  openTelegramModelMenu,
11
11
  sendTelegramModelMenuMessage,
12
12
  updateTelegramModelMenuMessage,
13
13
  type TelegramMenuMessageRuntimeDeps,
14
14
  type TelegramModelMenuState,
15
- type TelegramModelMenuStateBuilderContext,
16
- type TelegramModelMenuStateBuilderDeps,
17
15
  type TelegramReplyMarkup,
18
16
  } from "./menu-model.ts";
19
17
  import {
@@ -33,14 +31,18 @@ import {
33
31
  type TelegramModelSwitchContinuationSource,
34
32
  type ThinkingLevel,
35
33
  } from "./model.ts";
36
- import type { TelegramInputRichMessage } from "./telegram-api.ts";
37
34
  import {
38
35
  handleTelegramSectionCallback,
39
36
  handleTelegramSectionOpen,
40
37
  handleTelegramSectionSettingsOpen,
41
38
  parseTelegramSectionCallback,
39
+ type TelegramSectionRuntimeDeps,
42
40
  type TelegramSectionRegistry,
43
41
  } from "./sections.ts";
42
+ import type {
43
+ TelegramApiCallOptions,
44
+ TelegramInputRichMessage,
45
+ } from "./telegram-api.ts";
44
46
 
45
47
  export {
46
48
  applyTelegramModelPageSelection,
@@ -267,6 +269,7 @@ export interface TelegramMenuActionRuntimeDeps<
267
269
  options?: {
268
270
  target?: { chatId: number; threadId?: number };
269
271
  parseMode?: "HTML";
272
+ assertAuthority?: TelegramApiCallOptions["assertAuthority"];
270
273
  },
271
274
  ) => Promise<unknown>;
272
275
  sectionRegistry?: TelegramSectionRegistry;
@@ -294,81 +297,24 @@ export interface TelegramMenuActionRuntime<
294
297
  replyToMessageId: number,
295
298
  ctx: TContext,
296
299
  threadId?: number,
300
+ options?: Pick<TelegramApiCallOptions, "assertAuthority">,
297
301
  ) => Promise<void>;
298
302
  openModelMenu: (
299
303
  chatId: number,
300
304
  replyToMessageId: number,
301
305
  ctx: TContext,
302
306
  threadId?: number,
307
+ options?: Pick<TelegramApiCallOptions, "assertAuthority">,
303
308
  ) => Promise<void>;
304
309
  openThinkingMenu: (
305
310
  chatId: number,
306
311
  replyToMessageId: number,
307
312
  ctx: TContext,
313
+ threadId?: number,
314
+ options?: Pick<TelegramApiCallOptions, "assertAuthority">,
308
315
  ) => Promise<void>;
309
316
  }
310
317
 
311
- export type TelegramMenuCallbackAction =
312
- | { kind: "ignore" }
313
- | { kind: "status"; action: "model" | "thinking" | "queue" | "settings" }
314
- | { kind: "thinking:set"; level: string }
315
- | {
316
- kind: "model";
317
- action:
318
- | "noop"
319
- | "scope"
320
- | "page"
321
- | "pages"
322
- | "open"
323
- | "pick"
324
- | "pick-selected"
325
- | "scope-enable"
326
- | "scope-disable"
327
- | "scope-toggle";
328
- value?: string;
329
- };
330
-
331
- export function parseTelegramMenuCallbackAction(
332
- data: string | undefined,
333
- ): TelegramMenuCallbackAction {
334
- if (data === "menu:model" || data === "status:model") {
335
- return { kind: "status", action: "model" };
336
- }
337
- if (data === "menu:thinking" || data === "status:thinking") {
338
- return { kind: "status", action: "thinking" };
339
- }
340
- if (data === "menu:queue" || data === "status:queue") {
341
- return { kind: "status", action: "queue" };
342
- }
343
- if (data === "menu:settings" || data === "status:settings") {
344
- return { kind: "status", action: "settings" };
345
- }
346
- if (data?.startsWith("thinking:set:")) {
347
- return {
348
- kind: "thinking:set",
349
- level: data.slice("thinking:set:".length),
350
- };
351
- }
352
- if (data?.startsWith("model:")) {
353
- const [, action, value] = data.split(":");
354
- if (
355
- action === "noop" ||
356
- action === "scope" ||
357
- action === "page" ||
358
- action === "pages" ||
359
- action === "open" ||
360
- action === "pick" ||
361
- action === "pick-selected" ||
362
- action === "scope-enable" ||
363
- action === "scope-disable" ||
364
- action === "scope-toggle"
365
- ) {
366
- return { kind: "model", action, value };
367
- }
368
- }
369
- return { kind: "ignore" };
370
- }
371
-
372
318
  export async function handleTelegramMenuCallbackEntry(
373
319
  callbackQueryId: string,
374
320
  data: string | undefined,
@@ -382,7 +328,7 @@ export async function handleTelegramMenuCallbackEntry(
382
328
  if (!state) {
383
329
  await deps.answerCallbackQuery(
384
330
  callbackQueryId,
385
- "Interactive message expired.",
331
+ "Interactive message expired",
386
332
  );
387
333
  return;
388
334
  }
@@ -422,85 +368,15 @@ export async function handleStoredTelegramMenuCallback<
422
368
  });
423
369
  }
424
370
 
425
- export interface TelegramMenuCallbackRuntimeAdapterDeps<
371
+ export type TelegramMenuCallbackRuntimeAdapterDeps<
426
372
  TContext,
427
373
  TModel extends MenuModel = MenuModel,
428
- > {
429
- getStoredModelMenuState: (
430
- messageId: number | undefined,
431
- chatId?: number,
432
- ) => TelegramModelMenuState<TModel> | undefined;
433
- getActiveModel: (ctx: TContext) => TModel | undefined;
434
- getThinkingLevel: () => ThinkingLevel;
435
- setThinkingLevel: (level: ThinkingLevel) => void;
436
- updateStatus: (ctx: TContext, error?: string) => void;
437
- updateModelMenuMessage: (
438
- state: TelegramModelMenuState<TModel>,
439
- ctx: TContext,
440
- ) => Promise<void>;
441
- updateThinkingMenuMessage: (
442
- state: TelegramModelMenuState<TModel>,
443
- ctx: TContext,
444
- ) => Promise<void>;
445
- updateStatusMessage: (
446
- state: TelegramModelMenuState<TModel>,
447
- ctx: TContext,
448
- ) => Promise<void>;
449
- updateSettingsMenuMessage?: (
450
- state: TelegramModelMenuState<TModel>,
451
- ctx: TContext,
452
- ) => Promise<void>;
453
- answerCallbackQuery: (
454
- callbackQueryId: string,
455
- text?: string,
456
- ) => Promise<void>;
457
- isIdle: (ctx: TContext) => boolean;
458
- hasAbortHandler: () => boolean;
374
+ > = Omit<
375
+ TelegramMenuCallbackRuntimeDeps<TContext, TModel>,
376
+ "hasActiveToolExecutions"
377
+ > & {
459
378
  getActiveToolExecutions: () => number;
460
- persistScopedModelPatterns?: (
461
- patterns: string[],
462
- ctx: TContext,
463
- ) => Promise<void>;
464
- setModel: (model: TModel) => Promise<boolean>;
465
- setCurrentModel: (model: TModel, ctx: TContext) => void;
466
- stagePendingModelSwitch: (
467
- selection: ScopedTelegramModel<TModel>,
468
- ctx: TContext,
469
- continuationTurn: TelegramModelSwitchContinuationSource,
470
- ) => void;
471
- restartInterruptedTelegramTurn: (
472
- selection: ScopedTelegramModel<TModel>,
473
- ctx: TContext,
474
- continuationTurn: TelegramModelSwitchContinuationSource,
475
- ) => Promise<boolean> | boolean;
476
- sectionRegistry?: TelegramSectionRegistry;
477
- editInteractiveMessage?: (
478
- chatId: number,
479
- messageId: number,
480
- text: string,
481
- mode: "markdown" | "html" | "plain",
482
- replyMarkup: TelegramReplyMarkup,
483
- ) => Promise<void>;
484
- sendInteractiveMessage?: (
485
- chatId: number,
486
- text: string,
487
- mode: "markdown" | "html" | "plain",
488
- replyMarkup: TelegramReplyMarkup,
489
- options?: { target?: { chatId: number; threadId?: number } },
490
- ) => Promise<number | undefined>;
491
- sendSectionRichMessage?: (
492
- chatId: number,
493
- message: TelegramInputRichMessage,
494
- options?: { target?: { chatId: number; threadId?: number } },
495
- ) => Promise<number | undefined>;
496
- enqueueSectionPrompt?: (
497
- prompt: string,
498
- ctx: TContext,
499
- target?: { chatId: number; threadId?: number },
500
- source?: unknown,
501
- ) => Promise<void>;
502
- deleteMessage?: (chatId: number, messageId: number) => Promise<void>;
503
- }
379
+ };
504
380
 
505
381
  export function createTelegramMenuCallbackHandler<
506
382
  TQuery extends MenuCallbackQuery,
@@ -519,31 +395,10 @@ export function createTelegramMenuCallbackHandlerForContext<
519
395
  >(
520
396
  deps: TelegramMenuCallbackRuntimeAdapterDeps<TContext, TModel>,
521
397
  ): (query: TQuery, ctx: TContext) => Promise<void> {
398
+ const { getActiveToolExecutions, ...ports } = deps;
522
399
  return createTelegramMenuCallbackHandler<TQuery, TContext, TModel>({
523
- getStoredModelMenuState: deps.getStoredModelMenuState,
524
- getActiveModel: deps.getActiveModel,
525
- getThinkingLevel: deps.getThinkingLevel,
526
- setThinkingLevel: deps.setThinkingLevel,
527
- updateStatus: deps.updateStatus,
528
- updateModelMenuMessage: deps.updateModelMenuMessage,
529
- updateThinkingMenuMessage: deps.updateThinkingMenuMessage,
530
- updateStatusMessage: deps.updateStatusMessage,
531
- updateSettingsMenuMessage: deps.updateSettingsMenuMessage,
532
- answerCallbackQuery: deps.answerCallbackQuery,
533
- isIdle: deps.isIdle,
534
- hasAbortHandler: deps.hasAbortHandler,
535
- hasActiveToolExecutions: () => deps.getActiveToolExecutions() > 0,
536
- persistScopedModelPatterns: deps.persistScopedModelPatterns,
537
- setModel: deps.setModel,
538
- setCurrentModel: deps.setCurrentModel,
539
- stagePendingModelSwitch: deps.stagePendingModelSwitch,
540
- restartInterruptedTelegramTurn: deps.restartInterruptedTelegramTurn,
541
- sectionRegistry: deps.sectionRegistry,
542
- editInteractiveMessage: deps.editInteractiveMessage,
543
- sendInteractiveMessage: deps.sendInteractiveMessage,
544
- sendSectionRichMessage: deps.sendSectionRichMessage,
545
- enqueueSectionPrompt: deps.enqueueSectionPrompt,
546
- deleteMessage: deps.deleteMessage,
400
+ ...ports,
401
+ hasActiveToolExecutions: () => getActiveToolExecutions() > 0,
547
402
  });
548
403
  }
549
404
 
@@ -562,7 +417,7 @@ export async function handleTelegramMenuCallbackRuntime<
562
417
  query.message?.chat?.id,
563
418
  );
564
419
  if (!state) {
565
- await deps.answerCallbackQuery(query.id, "Interactive message expired.");
420
+ await deps.answerCallbackQuery(query.id, "Interactive message expired");
566
421
  return;
567
422
  }
568
423
  await deps.updateStatusMessage(state, ctx);
@@ -584,12 +439,30 @@ export async function handleTelegramMenuCallbackRuntime<
584
439
  : undefined;
585
440
  if (typeof chatId === "number" && typeof messageId === "number") {
586
441
  const { token, action, payload } = parsed;
442
+ const sectionDeps: TelegramSectionRuntimeDeps = {
443
+ answerCallbackQuery: deps.answerCallbackQuery,
444
+ target,
445
+ editInteractiveMessage:
446
+ deps.editInteractiveMessage ?? (async () => {}),
447
+ sendInteractiveMessage:
448
+ deps.sendInteractiveMessage ?? (async () => undefined),
449
+ sendRichMessage:
450
+ deps.sendSectionRichMessage ??
451
+ (async () => {
452
+ throw new Error("Rich Message delivery is unavailable");
453
+ }),
454
+ enqueuePrompt: deps.enqueueSectionPrompt
455
+ ? (prompt: string) =>
456
+ deps.enqueueSectionPrompt!(prompt, ctx, target, query)
457
+ : async () => {},
458
+ deleteMessage: deps.deleteMessage ?? (async () => {}),
459
+ };
587
460
  if (action === "open") {
588
461
  const state = deps.getStoredModelMenuState(messageId, chatId);
589
462
  if (!state) {
590
463
  await deps.answerCallbackQuery(
591
464
  query.id,
592
- "Interactive message expired.",
465
+ "Interactive message expired",
593
466
  );
594
467
  return;
595
468
  }
@@ -599,51 +472,19 @@ export async function handleTelegramMenuCallbackRuntime<
599
472
  chatId,
600
473
  messageId,
601
474
  query.id,
602
- {
603
- answerCallbackQuery: deps.answerCallbackQuery,
604
- target,
605
- editInteractiveMessage:
606
- deps.editInteractiveMessage ?? (async () => {}),
607
- sendInteractiveMessage:
608
- deps.sendInteractiveMessage ?? (async () => undefined),
609
- sendRichMessage: deps.sendSectionRichMessage ?? (async () => {
610
- throw new Error("Rich Message delivery is unavailable");
611
- }),
612
- enqueuePrompt: deps.enqueueSectionPrompt
613
- ? (prompt: string) =>
614
- deps.enqueueSectionPrompt!(prompt, ctx, target, query)
615
- : async () => {},
616
- deleteMessage: deps.deleteMessage ?? (async () => {}),
617
- },
475
+ sectionDeps,
618
476
  );
619
477
  if (handled) return;
620
478
  } else if (action === "settings") {
621
- if (typeof chatId === "number" && typeof messageId === "number") {
622
- const handled = await handleTelegramSectionSettingsOpen(
623
- deps.sectionRegistry,
624
- token,
625
- chatId,
626
- messageId,
627
- query.id,
628
- {
629
- answerCallbackQuery: deps.answerCallbackQuery,
630
- target,
631
- editInteractiveMessage:
632
- deps.editInteractiveMessage ?? (async () => {}),
633
- sendInteractiveMessage:
634
- deps.sendInteractiveMessage ?? (async () => undefined),
635
- sendRichMessage: deps.sendSectionRichMessage ?? (async () => {
636
- throw new Error("Rich Message delivery is unavailable");
637
- }),
638
- enqueuePrompt: deps.enqueueSectionPrompt
639
- ? (prompt: string) =>
640
- deps.enqueueSectionPrompt!(prompt, ctx, target, query)
641
- : async () => {},
642
- deleteMessage: deps.deleteMessage ?? (async () => {}),
643
- },
644
- );
645
- if (handled) return;
646
- }
479
+ const handled = await handleTelegramSectionSettingsOpen(
480
+ deps.sectionRegistry,
481
+ token,
482
+ chatId,
483
+ messageId,
484
+ query.id,
485
+ sectionDeps,
486
+ );
487
+ if (handled) return;
647
488
  } else {
648
489
  const handled = await handleTelegramSectionCallback(
649
490
  deps.sectionRegistry,
@@ -653,22 +494,7 @@ export async function handleTelegramMenuCallbackRuntime<
653
494
  chatId,
654
495
  messageId,
655
496
  query.id,
656
- {
657
- answerCallbackQuery: deps.answerCallbackQuery,
658
- target,
659
- editInteractiveMessage:
660
- deps.editInteractiveMessage ?? (async () => {}),
661
- sendInteractiveMessage:
662
- deps.sendInteractiveMessage ?? (async () => undefined),
663
- sendRichMessage: deps.sendSectionRichMessage ?? (async () => {
664
- throw new Error("Rich Message delivery is unavailable");
665
- }),
666
- enqueuePrompt: deps.enqueueSectionPrompt
667
- ? (prompt: string) =>
668
- deps.enqueueSectionPrompt!(prompt, ctx, target, query)
669
- : async () => {},
670
- deleteMessage: deps.deleteMessage ?? (async () => {}),
671
- },
497
+ sectionDeps,
672
498
  );
673
499
  if (handled) return;
674
500
  }
@@ -703,7 +529,8 @@ export async function handleTelegramMenuCallbackRuntime<
703
529
  deps.updateStatus(ctx);
704
530
  },
705
531
  getCurrentThinkingLevel: deps.getThinkingLevel,
706
- updateThinkingMenuMessage: () => deps.updateThinkingMenuMessage(state, ctx),
532
+ updateThinkingMenuMessage: () =>
533
+ deps.updateThinkingMenuMessage(state, ctx),
707
534
  answerCallbackQuery: deps.answerCallbackQuery,
708
535
  isVoiceReplyActive: deps.isVoiceReplyActive,
709
536
  },
@@ -756,45 +583,6 @@ export async function handleTelegramMenuCallbackRuntime<
756
583
  });
757
584
  }
758
585
 
759
- export interface TelegramMenuActionRuntimeWithStateBuilderDeps<
760
- TModel extends MenuModel = MenuModel,
761
- TContext extends TelegramModelMenuStateBuilderContext<TModel> =
762
- TelegramModelMenuStateBuilderContext<TModel>,
763
- >
764
- extends
765
- Omit<TelegramMenuActionRuntimeDeps<TContext, TModel>, "getModelMenuState">,
766
- TelegramModelMenuStateBuilderDeps<TModel, TContext> {
767
- isVoiceReplyActive?: () => boolean;
768
- }
769
-
770
- export function createTelegramMenuActionRuntimeWithStateBuilder<
771
- TModel extends MenuModel = MenuModel,
772
- TContext extends TelegramModelMenuStateBuilderContext<TModel> =
773
- TelegramModelMenuStateBuilderContext<TModel>,
774
- >(
775
- deps: TelegramMenuActionRuntimeWithStateBuilderDeps<TModel, TContext>,
776
- ): TelegramMenuActionRuntime<TContext, TModel> {
777
- return createTelegramMenuActionRuntime({
778
- getModelMenuState: createTelegramModelMenuStateBuilder({
779
- runtime: deps.runtime,
780
- createSettingsManager: deps.createSettingsManager,
781
- getActiveModel: deps.getActiveModel,
782
- }),
783
- getActiveModel: deps.getActiveModel,
784
- getThinkingLevel: deps.getThinkingLevel,
785
- getQueueItemCount: deps.getQueueItemCount,
786
- getPendingCancellationCount: deps.getPendingCancellationCount,
787
- buildStatusHtml: deps.buildStatusHtml,
788
- storeModelMenuState: deps.storeModelMenuState,
789
- isIdle: deps.isIdle,
790
- canOfferInFlightModelSwitch: deps.canOfferInFlightModelSwitch,
791
- sendTextReply: deps.sendTextReply,
792
- editInteractiveMessage: deps.editInteractiveMessage,
793
- sendInteractiveMessage: deps.sendInteractiveMessage,
794
- sectionRegistry: deps.sectionRegistry,
795
- });
796
- }
797
-
798
586
  export function createTelegramMenuActionRuntime<
799
587
  TContext,
800
588
  TModel extends MenuModel = MenuModel,
@@ -823,15 +611,26 @@ export function createTelegramMenuActionRuntime<
823
611
  deps.isVoiceReplyActive?.(),
824
612
  deps.getPendingCancellationCount?.() ?? 0,
825
613
  ),
826
- sendStatusMessage: (chatId, replyToMessageId, ctx, threadId) =>
827
- openTelegramStatusMenu({
614
+ sendStatusMessage: (chatId, replyToMessageId, ctx, threadId, options) => {
615
+ const delivery = createTelegramMenuDelivery(
616
+ { chatId, threadId },
617
+ options,
618
+ deps,
619
+ );
620
+ return openTelegramStatusMenu({
828
621
  isIdle: () => deps.isIdle(ctx),
829
622
  sendBusyMessage: async () => {
830
623
  await deps.sendTextReply(
831
624
  chatId,
832
625
  replyToMessageId,
833
626
  "<b>⏳ Cannot open status while Pi is busy. Send /abort, /next, or /stop.</b>",
834
- { target: { chatId, threadId }, parseMode: "HTML" },
627
+ {
628
+ target: { chatId, threadId },
629
+ parseMode: "HTML",
630
+ ...(delivery.assertAuthority
631
+ ? { assertAuthority: delivery.assertAuthority }
632
+ : {}),
633
+ },
835
634
  );
836
635
  },
837
636
  getModelMenuState: () => deps.getModelMenuState(chatId, ctx, threadId),
@@ -851,16 +650,26 @@ export function createTelegramMenuActionRuntime<
851
650
  statusHtml,
852
651
  activeModel,
853
652
  thinkingLevel,
854
- deps,
653
+ {
654
+ ...deps,
655
+ sendInteractiveMessage: delivery.sendInteractiveMessage,
656
+ },
855
657
  queueItemCount,
856
658
  deps.sectionRegistry,
857
659
  deps.isVoiceReplyActive?.(),
858
660
  deps.getPendingCancellationCount?.() ?? 0,
859
661
  ),
860
- storeModelMenuState: deps.storeModelMenuState,
861
- }),
862
- openModelMenu: (chatId, replyToMessageId, ctx, threadId) =>
863
- openTelegramModelMenu({
662
+ storeModelMenuState: delivery.storeModelMenuState,
663
+ });
664
+ },
665
+ openModelMenu: (chatId, replyToMessageId, ctx, threadId, options) => {
666
+ const delivery = createTelegramMenuDelivery(
667
+ { chatId, threadId },
668
+ options,
669
+ deps,
670
+ );
671
+ const assertAuthority = delivery.assertAuthority;
672
+ return openTelegramModelMenu({
864
673
  isIdle: () => deps.isIdle(ctx),
865
674
  canOfferInFlightModelSwitch: () =>
866
675
  deps.canOfferInFlightModelSwitch(ctx),
@@ -869,7 +678,11 @@ export function createTelegramMenuActionRuntime<
869
678
  chatId,
870
679
  replyToMessageId,
871
680
  "<b>⏳ Cannot switch model while Pi is busy. Send /abort, /next, or /stop.</b>",
872
- { target: { chatId, threadId }, parseMode: "HTML" },
681
+ {
682
+ target: { chatId, threadId },
683
+ parseMode: "HTML",
684
+ ...(assertAuthority ? { assertAuthority } : {}),
685
+ },
873
686
  );
874
687
  },
875
688
  sendNoModelsMessage: async () => {
@@ -877,24 +690,38 @@ export function createTelegramMenuActionRuntime<
877
690
  chatId,
878
691
  replyToMessageId,
879
692
  "<b>🚫 No available models with configured auth.</b>",
880
- { target: { chatId, threadId }, parseMode: "HTML" },
693
+ {
694
+ target: { chatId, threadId },
695
+ parseMode: "HTML",
696
+ ...(assertAuthority ? { assertAuthority } : {}),
697
+ },
881
698
  );
882
699
  },
883
700
  getModelMenuState: () => deps.getModelMenuState(chatId, ctx, threadId),
884
701
  getActiveModel: () => deps.getActiveModel(ctx),
885
702
  sendModelMenu: (state, activeModel) =>
886
- sendTelegramModelMenuMessage(state, activeModel, deps),
887
- storeModelMenuState: deps.storeModelMenuState,
888
- }),
889
- openThinkingMenu: (chatId, _replyToMessageId, ctx) =>
890
- openTelegramThinkingMenu({
891
- getModelMenuState: () => deps.getModelMenuState(chatId, ctx),
703
+ sendTelegramModelMenuMessage(state, activeModel, {
704
+ ...deps,
705
+ sendInteractiveMessage: delivery.sendInteractiveMessage,
706
+ }),
707
+ storeModelMenuState: delivery.storeModelMenuState,
708
+ });
709
+ },
710
+ openThinkingMenu: (chatId, _replyToMessageId, ctx, threadId, options) => {
711
+ const delivery = createTelegramMenuDelivery(
712
+ { chatId, threadId },
713
+ options,
714
+ deps,
715
+ );
716
+ return openTelegramThinkingMenu({
717
+ getModelMenuState: () => deps.getModelMenuState(chatId, ctx, threadId),
892
718
  getActiveModel: () => deps.getActiveModel(ctx),
893
719
  getThinkingLevel: deps.getThinkingLevel,
894
- storeModelMenuState: deps.storeModelMenuState,
720
+ storeModelMenuState: delivery.storeModelMenuState,
895
721
  editInteractiveMessage: deps.editInteractiveMessage,
896
- sendInteractiveMessage: deps.sendInteractiveMessage,
722
+ sendInteractiveMessage: delivery.sendInteractiveMessage,
897
723
  isVoiceReplyActive: deps.isVoiceReplyActive,
898
- }),
724
+ });
725
+ },
899
726
  };
900
727
  }
@@ -4,7 +4,10 @@
4
4
  * Owns model identity, thinking levels, scoped resolution, current-model state, and in-flight model switching
5
5
  */
6
6
 
7
- import type { PendingTelegramTurn } from "./queue.ts";
7
+ import {
8
+ truncateTelegramQueueSummary,
9
+ type PendingTelegramTurn,
10
+ } from "./queue.ts";
8
11
  import { TELEGRAM_PREFIX } from "./turns.ts";
9
12
 
10
13
  export interface MenuModel {
@@ -428,24 +431,6 @@ export function restartTelegramModelSwitchContinuation<
428
431
  return true;
429
432
  }
430
433
 
431
- function truncateTelegramModelSwitchStatusSummary(
432
- text: string,
433
- maxWords = 4,
434
- maxLength = 32,
435
- ): string {
436
- const normalized = text.replace(/\s+/g, " ").trim();
437
- if (!normalized) return "";
438
- const words = normalized.split(" ");
439
- let summary = words.slice(0, maxWords).join(" ");
440
- if (summary.length === 0) summary = normalized;
441
- if (summary.length > maxLength) {
442
- summary = summary.slice(0, maxLength).trimEnd();
443
- }
444
- return summary.length < normalized.length || words.length > maxWords
445
- ? `${summary}…`
446
- : summary;
447
- }
448
-
449
434
  export function buildTelegramModelSwitchContinuationText<
450
435
  TModel extends MenuModel,
451
436
  >(
@@ -473,8 +458,10 @@ export function buildTelegramModelSwitchContinuationTurn<
473
458
  laneOrder: number;
474
459
  }): PendingTelegramTurn {
475
460
  const modelLabel = `${options.selection.model.provider}/${options.selection.model.id}`;
476
- const statusLabel = truncateTelegramModelSwitchStatusSummary(
461
+ const statusLabel = truncateTelegramQueueSummary(
477
462
  `continue on ${options.selection.model.id}`,
463
+ 4,
464
+ 32,
478
465
  );
479
466
  return {
480
467
  kind: "prompt",
@@ -643,8 +630,7 @@ export function createTelegramModelSwitchController<TContext, TSelection>(
643
630
  deps: TelegramModelSwitchControllerDeps<TContext, TSelection>,
644
631
  ): TelegramModelSwitchController<TContext, TSelection> {
645
632
  let pendingContinuationTurn:
646
- | TelegramModelSwitchContinuationSource
647
- | undefined;
633
+ TelegramModelSwitchContinuationSource | undefined;
648
634
  const triggerPendingAbort = (ctx: TContext): boolean => {
649
635
  const turn = pendingContinuationTurn ?? deps.getActiveTurn();
650
636
  if (