@llblab/pi-kit 0.29.1 → 0.30.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.
Files changed (222) hide show
  1. package/BACKLOG.md +3 -1
  2. package/CHANGELOG.md +10 -0
  3. package/README.md +4 -4
  4. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +12 -0
  5. package/node_modules/@llblab/pi-state-flow/README.md +2 -2
  6. package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +2 -2
  7. package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +17 -8
  8. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +7 -3
  9. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +2 -1
  10. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +3 -2
  11. package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
  12. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +3 -3
  13. package/node_modules/@llblab/pi-state-flow/docs/usage.md +3 -2
  14. package/node_modules/@llblab/pi-state-flow/lib/context.ts +17 -8
  15. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +6 -3
  16. package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +4 -2
  17. package/node_modules/@llblab/pi-state-flow/package.json +1 -1
  18. package/node_modules/@llblab/pi-telegram/AGENTS.md +13 -10
  19. package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -1
  20. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +23 -0
  21. package/node_modules/@llblab/pi-telegram/README.md +10 -11
  22. package/node_modules/@llblab/pi-telegram/api/commands.ts +3 -0
  23. package/node_modules/@llblab/pi-telegram/dist/api/commands.d.ts +1 -1
  24. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +1 -5
  25. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +15 -42
  26. package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +9 -0
  27. package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +39 -10
  28. package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.js +7 -3
  29. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +43 -5
  30. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +164 -20
  31. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.d.ts +12 -0
  32. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +181 -77
  33. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +111 -31
  34. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +1324 -359
  35. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +41 -91
  36. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +969 -637
  37. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +16 -9
  38. package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +215 -18
  39. package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +1048 -327
  40. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +5 -0
  41. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +434 -261
  42. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +26 -5
  43. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +92 -176
  44. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +168 -82
  45. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +1409 -291
  46. package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +1 -8
  47. package/node_modules/@llblab/pi-telegram/dist/lib/config.js +34 -76
  48. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +2 -2
  49. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +16 -16
  50. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +642 -170
  51. package/node_modules/@llblab/pi-telegram/dist/lib/generative-app-worker.mjs +19 -7
  52. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +0 -5
  53. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.js +61 -49
  54. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +5 -0
  55. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +35 -59
  56. package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +40 -4
  57. package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +2102 -760
  58. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +2 -6
  59. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +75 -58
  60. package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +34 -3
  61. package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +318 -119
  62. package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +50 -14
  63. package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +22 -1
  64. package/node_modules/@llblab/pi-telegram/dist/lib/media.js +46 -28
  65. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +19 -5
  66. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +53 -11
  67. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.d.ts +5 -4
  68. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.js +45 -63
  69. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +5 -4
  70. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +114 -78
  71. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +1 -1
  72. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +8 -25
  73. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +6 -1
  74. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +14 -21
  75. package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +8 -61
  76. package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +92 -164
  77. package/node_modules/@llblab/pi-telegram/dist/lib/model.d.ts +1 -1
  78. package/node_modules/@llblab/pi-telegram/dist/lib/model.js +2 -16
  79. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +6 -27
  80. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +45 -38
  81. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +22 -16
  82. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +0 -2
  83. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +51 -64
  84. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.js +6 -3
  85. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +6 -6
  86. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +61 -51
  87. package/node_modules/@llblab/pi-telegram/dist/lib/ownership.js +6 -2
  88. package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +5 -0
  89. package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +37 -21
  90. package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +2 -0
  91. package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +8 -1
  92. package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +23 -37
  93. package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +71 -52
  94. package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +39 -19
  95. package/node_modules/@llblab/pi-telegram/dist/lib/process-identity.d.ts +24 -0
  96. package/node_modules/@llblab/pi-telegram/dist/lib/process-identity.js +133 -0
  97. package/node_modules/@llblab/pi-telegram/dist/lib/prompts.js +2 -7
  98. package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +16 -16
  99. package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +261 -116
  100. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +2 -83
  101. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +20 -274
  102. package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +16 -24
  103. package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +99 -116
  104. package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +121 -7
  105. package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +4750 -1161
  106. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.d.ts +1 -11
  107. package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +4 -29
  108. package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +7 -20
  109. package/node_modules/@llblab/pi-telegram/dist/lib/skills.js +4 -3
  110. package/node_modules/@llblab/pi-telegram/dist/lib/status.js +86 -57
  111. package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +6 -3
  112. package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +112 -45
  113. package/node_modules/@llblab/pi-telegram/dist/lib/target.d.ts +4 -0
  114. package/node_modules/@llblab/pi-telegram/dist/lib/target.js +18 -0
  115. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +18 -11
  116. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +165 -49
  117. package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.js +4 -39
  118. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +6 -27
  119. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +369 -186
  120. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +1 -2
  121. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +58 -38
  122. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +28 -8
  123. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +175 -66
  124. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +42 -16
  125. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +90 -50
  126. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +88 -24
  127. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +2276 -842
  128. package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.js +1 -2
  129. package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +1 -19
  130. package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +178 -82
  131. package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +2438 -645
  132. package/node_modules/@llblab/pi-telegram/dist/lib/voice.d.ts +7 -22
  133. package/node_modules/@llblab/pi-telegram/dist/lib/voice.js +7 -22
  134. package/node_modules/@llblab/pi-telegram/dist/lib/wire.js +1 -1
  135. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +3 -1
  136. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +425 -211
  137. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-identity.js +8 -13
  138. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +1 -1
  139. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +328 -140
  140. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.js +8 -4
  141. package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
  142. package/node_modules/@llblab/pi-telegram/docs/architecture.md +43 -35
  143. package/node_modules/@llblab/pi-telegram/docs/inbound.md +1 -1
  144. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +15 -3
  145. package/node_modules/@llblab/pi-telegram/docs/outbound.md +1 -1
  146. package/node_modules/@llblab/pi-telegram/docs/public-api.md +29 -1
  147. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +25 -8
  148. package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +59 -82
  149. package/node_modules/@llblab/pi-telegram/lib/activity.ts +146 -102
  150. package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +12 -5
  151. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +390 -82
  152. package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +262 -99
  153. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +2440 -601
  154. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +2209 -1290
  155. package/node_modules/@llblab/pi-telegram/lib/bus-transport.ts +46 -12
  156. package/node_modules/@llblab/pi-telegram/lib/bus.ts +1673 -444
  157. package/node_modules/@llblab/pi-telegram/lib/channel-posts.ts +848 -327
  158. package/node_modules/@llblab/pi-telegram/lib/command-templates.ts +152 -265
  159. package/node_modules/@llblab/pi-telegram/lib/commands.ts +2398 -555
  160. package/node_modules/@llblab/pi-telegram/lib/config.ts +177 -170
  161. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +41 -29
  162. package/node_modules/@llblab/pi-telegram/lib/extension.ts +1209 -431
  163. package/node_modules/@llblab/pi-telegram/lib/generative-app-worker.mjs +19 -7
  164. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +324 -211
  165. package/node_modules/@llblab/pi-telegram/lib/inbound.ts +95 -97
  166. package/node_modules/@llblab/pi-telegram/lib/journal.ts +5329 -1712
  167. package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +1 -3
  168. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +128 -78
  169. package/node_modules/@llblab/pi-telegram/lib/locks.ts +703 -212
  170. package/node_modules/@llblab/pi-telegram/lib/logging.ts +147 -58
  171. package/node_modules/@llblab/pi-telegram/lib/media.ts +82 -43
  172. package/node_modules/@llblab/pi-telegram/lib/menu-model.ts +85 -18
  173. package/node_modules/@llblab/pi-telegram/lib/menu-queue.ts +88 -129
  174. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +260 -155
  175. package/node_modules/@llblab/pi-telegram/lib/menu-status.ts +20 -60
  176. package/node_modules/@llblab/pi-telegram/lib/menu-thinking.ts +41 -56
  177. package/node_modules/@llblab/pi-telegram/lib/menu.ts +112 -285
  178. package/node_modules/@llblab/pi-telegram/lib/model.ts +8 -22
  179. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +156 -125
  180. package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +76 -49
  181. package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +96 -94
  182. package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +33 -27
  183. package/node_modules/@llblab/pi-telegram/lib/outbound.ts +125 -125
  184. package/node_modules/@llblab/pi-telegram/lib/ownership.ts +19 -10
  185. package/node_modules/@llblab/pi-telegram/lib/paths.ts +148 -49
  186. package/node_modules/@llblab/pi-telegram/lib/pi.ts +35 -15
  187. package/node_modules/@llblab/pi-telegram/lib/polling.ts +165 -149
  188. package/node_modules/@llblab/pi-telegram/lib/preview.ts +93 -40
  189. package/node_modules/@llblab/pi-telegram/lib/process-identity.ts +164 -0
  190. package/node_modules/@llblab/pi-telegram/lib/prompts.ts +4 -11
  191. package/node_modules/@llblab/pi-telegram/lib/queue.ts +523 -289
  192. package/node_modules/@llblab/pi-telegram/lib/recovery.ts +50 -454
  193. package/node_modules/@llblab/pi-telegram/lib/rendering.ts +1 -3
  194. package/node_modules/@llblab/pi-telegram/lib/replies.ts +248 -209
  195. package/node_modules/@llblab/pi-telegram/lib/routing.ts +8527 -2149
  196. package/node_modules/@llblab/pi-telegram/lib/runtime.ts +1 -12
  197. package/node_modules/@llblab/pi-telegram/lib/sections.ts +24 -89
  198. package/node_modules/@llblab/pi-telegram/lib/setup.ts +1 -3
  199. package/node_modules/@llblab/pi-telegram/lib/skills.ts +9 -4
  200. package/node_modules/@llblab/pi-telegram/lib/status.ts +215 -110
  201. package/node_modules/@llblab/pi-telegram/lib/sync.ts +488 -359
  202. package/node_modules/@llblab/pi-telegram/lib/target.ts +22 -3
  203. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +322 -122
  204. package/node_modules/@llblab/pi-telegram/lib/text-groups.ts +5 -39
  205. package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +833 -331
  206. package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +213 -97
  207. package/node_modules/@llblab/pi-telegram/lib/thread-naming.ts +232 -87
  208. package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +155 -72
  209. package/node_modules/@llblab/pi-telegram/lib/threads.ts +5329 -1817
  210. package/node_modules/@llblab/pi-telegram/lib/time-injection.ts +1 -4
  211. package/node_modules/@llblab/pi-telegram/lib/turns.ts +15 -28
  212. package/node_modules/@llblab/pi-telegram/lib/updates.ts +5194 -1600
  213. package/node_modules/@llblab/pi-telegram/lib/voice.ts +7 -35
  214. package/node_modules/@llblab/pi-telegram/lib/wire.ts +1 -1
  215. package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +996 -416
  216. package/node_modules/@llblab/pi-telegram/lib/workspace-identity.ts +14 -17
  217. package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +878 -376
  218. package/node_modules/@llblab/pi-telegram/lib/workspace-slots.ts +22 -13
  219. package/node_modules/@llblab/pi-telegram/package.json +1 -1
  220. package/package.json +3 -3
  221. package/node_modules/@llblab/pi-telegram/scripts/check-downgrade.mjs +0 -472
  222. 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 (