@llblab/pi-kit 0.29.2 → 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 (208) hide show
  1. package/BACKLOG.md +2 -1
  2. package/CHANGELOG.md +5 -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 +11 -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 +61 -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 +249 -126
  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 +125 -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 +511 -300
  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
@@ -91,16 +91,14 @@ function createTelegramActivityContext(event, isActive) {
91
91
  };
92
92
  }
93
93
  function canCoalesceActivityEvents(previous, next) {
94
- if (previous.activityId !== next.activityId ||
95
- previous.type !== next.type) {
94
+ if (previous.activityId !== next.activityId || previous.type !== next.type) {
96
95
  return false;
97
96
  }
98
97
  if (previous.type === "assistant-text-delta" &&
99
98
  next.type === "assistant-text-delta") {
100
99
  return previous.contentIndex === next.contentIndex;
101
100
  }
102
- if (previous.type === "reasoning-delta" &&
103
- next.type === "reasoning-delta") {
101
+ if (previous.type === "reasoning-delta" && next.type === "reasoning-delta") {
104
102
  return previous.contentIndex === next.contentIndex;
105
103
  }
106
104
  if (previous.type === "tool-update" && next.type === "tool-update") {
@@ -113,8 +111,7 @@ function coalesceActivityEvents(previous, next) {
113
111
  next.type === "assistant-text-delta") {
114
112
  return { ...next, delta: previous.delta + next.delta };
115
113
  }
116
- if (previous.type === "reasoning-delta" &&
117
- next.type === "reasoning-delta") {
114
+ if (previous.type === "reasoning-delta" && next.type === "reasoning-delta") {
118
115
  return { ...next, delta: previous.delta + next.delta };
119
116
  }
120
117
  return next;
@@ -152,6 +149,7 @@ export function createTelegramActivityDispatcher(deps = {}) {
152
149
  }
153
150
  };
154
151
  return {
152
+ hasPending: () => Array.from(queues.values()).some((queue) => queue.active && (queue.running || queue.events.length > 0)),
155
153
  dispatch(event) {
156
154
  if (stopped)
157
155
  return;
@@ -194,6 +192,7 @@ export function createTelegramActivityBridgeRuntime(deps) {
194
192
  let runtime;
195
193
  const getRuntime = () => runtime;
196
194
  return {
195
+ hasPending: () => getRuntime()?.hasPending?.(),
197
196
  onSessionStart() {
198
197
  runtime?.onSessionShutdown();
199
198
  runtime = createTelegramActivityRuntime({
@@ -298,7 +297,9 @@ export function createTelegramActivityRuntime(deps) {
298
297
  sequence,
299
298
  source: activitySource,
300
299
  ...(activityTarget ? { target: activityTarget } : {}),
301
- ...(activityReplyToMessageId !== undefined ? { replyToMessageId: activityReplyToMessageId } : {}),
300
+ ...(activityReplyToMessageId !== undefined
301
+ ? { replyToMessageId: activityReplyToMessageId }
302
+ : {}),
302
303
  timestamp: now(),
303
304
  };
304
305
  try {
@@ -342,13 +343,15 @@ export function createTelegramActivityRuntime(deps) {
342
343
  clearActivity();
343
344
  };
344
345
  return {
346
+ hasPending: () => deps.dispatcher.hasPending?.(),
345
347
  recordInputSource(source) {
346
348
  pendingInputSource = source;
347
349
  },
348
350
  onAgentStart(activeTelegramTarget, replyToMessageId) {
349
351
  abandonCompaction();
350
352
  ensureActivity(activeTelegramTarget);
351
- activityReplyToMessageId = activitySource === "telegram" ? replyToMessageId : undefined;
353
+ activityReplyToMessageId =
354
+ activitySource === "telegram" ? replyToMessageId : undefined;
352
355
  emit({ type: "agent-start" });
353
356
  },
354
357
  onAssistantEvent(event) {
@@ -470,12 +473,15 @@ export function createTelegramActivityRuntime(deps) {
470
473
  export function createTelegramActivityPublicationRuntime() {
471
474
  let generation = 0;
472
475
  let tail = Promise.resolve();
476
+ let outstanding = 0, unconfirmed = false;
473
477
  const pending = new Set();
474
478
  const reserve = () => {
475
479
  const admittedGeneration = generation;
476
480
  let state = "pending";
477
481
  let resolve;
478
- const ready = new Promise((accept) => { resolve = accept; });
482
+ const ready = new Promise((accept) => {
483
+ resolve = accept;
484
+ });
479
485
  const cancel = () => {
480
486
  if (state !== "pending")
481
487
  return;
@@ -484,10 +490,15 @@ export function createTelegramActivityPublicationRuntime() {
484
490
  resolve(undefined);
485
491
  };
486
492
  pending.add(cancel);
487
- const result = tail.then(async () => {
493
+ outstanding += 1;
494
+ const result = tail
495
+ .then(async () => {
488
496
  const task = await ready;
489
497
  if (admittedGeneration === generation && task)
490
498
  await task();
499
+ })
500
+ .finally(() => {
501
+ outstanding -= 1;
491
502
  });
492
503
  tail = result.catch(() => { });
493
504
  return {
@@ -507,8 +518,26 @@ export function createTelegramActivityPublicationRuntime() {
507
518
  return {
508
519
  reserve,
509
520
  enqueue: (task) => reserve().publish(task),
521
+ hasPending: () => outstanding > 0,
522
+ hasUnconfirmed: () => unconfirmed,
523
+ beginWork() {
524
+ const admittedGeneration = generation;
525
+ let settled = false;
526
+ outstanding += 1;
527
+ return {
528
+ settle(outcome) {
529
+ if (settled)
530
+ return;
531
+ settled = true;
532
+ outstanding -= 1;
533
+ if (outcome === "unconfirmed" && admittedGeneration === generation)
534
+ unconfirmed = true;
535
+ },
536
+ };
537
+ },
510
538
  reset() {
511
539
  generation += 1;
540
+ unconfirmed = false;
512
541
  for (const cancel of pending)
513
542
  cancel();
514
543
  tail = Promise.resolve();
@@ -12,7 +12,10 @@ export function createTelegramAgentMessageRuntime(deps) {
12
12
  const leaderTarget = deps.getLeaderTarget();
13
13
  if (leaderTarget?.threadId) {
14
14
  targets.push({
15
- target: { chatId: leaderTarget.chatId, threadId: leaderTarget.threadId },
15
+ target: {
16
+ chatId: leaderTarget.chatId,
17
+ threadId: leaderTarget.threadId,
18
+ },
16
19
  threadName: deps.getDisplayTitle?.(leaderTarget) ?? deps.getLeaderThreadName(),
17
20
  });
18
21
  }
@@ -65,8 +68,9 @@ export function createTelegramAgentMessageRuntime(deps) {
65
68
  if (allowedChatId === undefined || !ctx) {
66
69
  throw new Error("Telegram agent turn routing is unavailable.");
67
70
  }
68
- const sourceTitle = (input.sourceTarget ? deps.getDisplayTitle?.(input.sourceTarget) : undefined)
69
- ?? input.sourceThreadName;
71
+ const sourceTitle = (input.sourceTarget
72
+ ? deps.getDisplayTitle?.(input.sourceTarget)
73
+ : undefined) ?? input.sourceThreadName;
70
74
  const sourceLabel = sourceTitle
71
75
  ?.replace(/[\r\n\[\]]+/g, " ")
72
76
  .trim()
@@ -3,14 +3,20 @@
3
3
  * Zones: telegram, pi agent, orchestration
4
4
  * Owns pi-facing tool, command, and lifecycle hook registration for the entrypoint
5
5
  */
6
- import * as Activity from "./activity.ts";
7
6
  import * as ActivityVerbosity from "./activity-verbosity.ts";
7
+ import * as Activity from "./activity.ts";
8
+ import * as BusApi from "./bus-api.ts";
9
+ import type { TelegramBusFollowerCommandOwner } from "./bus-follower.ts";
10
+ import type { TelegramBusLiveRebindWorkState } from "./bus.ts";
8
11
  import * as ChannelPosts from "./channel-posts.ts";
9
12
  import * as Commands from "./commands.ts";
10
13
  import * as Config from "./config.ts";
14
+ import * as Delivery from "./delivery.ts";
15
+ import * as GenerativeApps from "./generative-apps.ts";
11
16
  import * as Keyboard from "./keyboard.ts";
12
17
  import * as Lifecycle from "./lifecycle.ts";
13
18
  import * as Locks from "./locks.ts";
19
+ import * as Menu from "./menu.ts";
14
20
  import * as Model from "./model.ts";
15
21
  import * as OutboundAttachments from "./outbound-attachments.ts";
16
22
  import * as OutboundHandlers from "./outbound.ts";
@@ -18,13 +24,28 @@ import * as Pi from "./pi.ts";
18
24
  import * as Preview from "./preview.ts";
19
25
  import * as Prompts from "./prompts.ts";
20
26
  import * as Queue from "./queue.ts";
27
+ import * as Replies from "./replies.ts";
21
28
  import * as Routing from "./routing.ts";
22
29
  import * as Runtime from "./runtime.ts";
23
30
  import * as Setup from "./setup.ts";
24
31
  import * as Status from "./status.ts";
25
- import * as TelegramApi from "./telegram-api.ts";
26
32
  import type { TelegramTarget } from "./target.ts";
27
- import * as GenerativeApps from "./generative-apps.ts";
33
+ import * as TelegramApi from "./telegram-api.ts";
34
+ /** Compose any registered held command over captured recipient effects; no ordinary follower API fallback. */
35
+ export declare function createTelegramFollowerSelectedCommandBinding<TContext, TModel extends Model.MenuModel = Model.MenuModel>(deps: {
36
+ ctx: TContext;
37
+ operationId: string;
38
+ registrationGeneration: string;
39
+ name: string;
40
+ target: TelegramTarget & {
41
+ threadId: number;
42
+ };
43
+ recipient: Pick<TelegramBusFollowerCommandOwner<TContext>, "isCurrent" | "assertRecipientCurrent">;
44
+ command: Pick<ReturnType<typeof Commands.createTelegramCommandHandlerTargetRuntime<Commands.TelegramCommandRuntimeMessage, TContext>>, "prepareHeldCommand" | "canPrepareHeldCommand">;
45
+ menu?: Omit<Menu.TelegramMenuActionRuntimeDeps<TContext, TModel>, "sendTextReply" | "sendInteractiveMessage" | "editInteractiveMessage">;
46
+ deliver: Parameters<typeof BusApi.createTelegramSelectedMenuTextApi>[0]["deliver"];
47
+ recordOwnership: NonNullable<Replies.TelegramRenderedMessageDeliveryRuntimeDeps<Menu.TelegramReplyMarkup>["recordOwnership"]>;
48
+ }): TelegramBusFollowerCommandOwner<TContext> | undefined;
28
49
  type ActivePiModel = NonNullable<Pi.ExtensionContext["model"]>;
29
50
  type TelegramRuntimeEventRecorder = (category: string, error: unknown, details?: Record<string, unknown>) => void;
30
51
  type TelegramBridgeStatusUpdater = Status.TelegramStatusRuntime<Pi.ExtensionContext>["updateStatus"];
@@ -139,6 +160,9 @@ type TelegramAssistantOutputAuthority<TTransportStamp> = ReturnType<Routing.Tele
139
160
  export interface TelegramBridgePublicationRuntime {
140
161
  enqueue: Activity.TelegramActivityPublicationRuntime["enqueue"];
141
162
  reserve: Activity.TelegramActivityPublicationRuntime["reserve"];
163
+ hasPending: Activity.TelegramActivityPublicationRuntime["hasPending"];
164
+ beginWork: Activity.TelegramActivityPublicationRuntime["beginWork"];
165
+ hasUnconfirmed: Activity.TelegramActivityPublicationRuntime["hasUnconfirmed"];
142
166
  capture: () => {
143
167
  target?: Queue.TelegramQueueTarget;
144
168
  isCurrent: () => boolean;
@@ -156,6 +180,21 @@ export declare function createTelegramActivityBindingRuntime<TTransportStamp>(de
156
180
  assistantOutput: Omit<Parameters<typeof createTelegramAssistantOutputBindingRuntime<TTransportStamp>>[0], "waitForActivityIdle" | "enqueue">;
157
181
  activityVerbosity: Omit<Parameters<typeof ActivityVerbosity.createTelegramActivityVerbosityRuntime<TelegramAssistantOutputAuthority<TTransportStamp>>>[0], "captureAuthority" | "isAuthorityActive" | "recordFailure" | "enqueue">;
158
182
  }): TelegramActivityBindingRuntime;
183
+ /** Fresh current work projection; a snapshot is not a cleanup grant or target-application ACK. */
184
+ export declare function createTelegramLiveTargetWorkObserver<TContext>(deps: {
185
+ queue: Pick<Queue.TelegramQueueStateStore<TContext>, "getQueuedItems">;
186
+ activeTurn: Pick<Queue.TelegramActiveTurnStore, "get">;
187
+ lifecycle: Pick<Runtime.TelegramBridgeRuntime["lifecycle"], "hasDispatchPending" | "isCompactionInProgress" | "getActiveToolExecutions">;
188
+ isIdle(ctx: TContext): boolean;
189
+ hasPendingMessages(ctx: TContext): boolean;
190
+ hasPendingControl(): boolean;
191
+ publication: Pick<TelegramBridgePublicationRuntime, "hasPending" | "hasUnconfirmed">;
192
+ activity: Pick<Activity.TelegramActivityRuntime, "hasPending">;
193
+ delivery: Pick<ReturnType<typeof Delivery.createTelegramDeliveryLifecycleHooks>, "hasPendingTarget">;
194
+ api: Pick<TelegramApi.TelegramApiTargetActivityRuntime, "hasPendingTarget">;
195
+ }): (target: TelegramTarget & {
196
+ threadId: number;
197
+ }, ctx: TContext) => TelegramBusLiveRebindWorkState;
159
198
  interface TelegramCommandsAndToolsBindingDeps {
160
199
  pi: Pi.ExtensionAPI;
161
200
  agentDir: string;
@@ -165,7 +204,6 @@ interface TelegramCommandsAndToolsBindingDeps {
165
204
  activeTurnRuntime: Queue.TelegramActiveTurnStore<Queue.PendingTelegramTurn>;
166
205
  lockedPollingRuntime: Locks.TelegramLockedPollingRuntime<Pi.ExtensionContext>;
167
206
  stopPolling?: () => Promise<void | string>;
168
- recoverPollingStart?: Commands.TelegramBridgeCommandRegistrationDeps["recoverPollingStart"];
169
207
  getDisconnectThreadName?: () => string | undefined;
170
208
  onTransportChanged?: () => Promise<void> | void;
171
209
  getStatusLines: (options?: Status.TelegramBridgeStatusLineOptions) => string[];
@@ -199,7 +237,7 @@ interface TelegramCommandsAndToolsBindingDeps {
199
237
  connectionIntent: NonNullable<Commands.TelegramBridgeCommandRegistrationDeps["connectionIntent"]>;
200
238
  recordRuntimeEvent: TelegramRuntimeEventRecorder;
201
239
  }
202
- export declare function registerTelegramCommandsAndTools({ pi, agentDir, configStore, persistConfig, setup, activeTurnRuntime, lockedPollingRuntime, stopPolling, recoverPollingStart, getDisconnectThreadName, onTransportChanged, getStatusLines, buttonActionStore, sendMarkdownReply, sendChannelMarkdownMessage, sendChannelMediaMessage, listChannelPosts, mutateChannelPost, callMultipart, getDefaultChatId, getDefaultTarget, resolveAgentTarget, routeAgentMessage, canSendDirect, setGenerativeAppLiveSurfaceRuntime, recordRuntimeEvent, updateStatus, isContextCurrent, getSessionGeneration, connectionIntent, }: TelegramCommandsAndToolsBindingDeps): void;
240
+ export declare function registerTelegramCommandsAndTools({ pi, agentDir, configStore, persistConfig, setup, activeTurnRuntime, lockedPollingRuntime, stopPolling, getDisconnectThreadName, onTransportChanged, getStatusLines, buttonActionStore, sendMarkdownReply, sendChannelMarkdownMessage, sendChannelMediaMessage, listChannelPosts, mutateChannelPost, callMultipart, getDefaultChatId, getDefaultTarget, resolveAgentTarget, routeAgentMessage, canSendDirect, setGenerativeAppLiveSurfaceRuntime, recordRuntimeEvent, updateStatus, isContextCurrent, getSessionGeneration, connectionIntent, }: TelegramCommandsAndToolsBindingDeps): void;
203
241
  interface TelegramLifecycleBindingDeps {
204
242
  pi: Pi.ExtensionAPI;
205
243
  publicationRuntime: TelegramBridgePublicationRuntime;
@@ -3,14 +3,17 @@
3
3
  * Zones: telegram, pi agent, orchestration
4
4
  * Owns pi-facing tool, command, and lifecycle hook registration for the entrypoint
5
5
  */
6
- import * as Activity from "./activity.js";
7
6
  import * as ActivityVerbosity from "./activity-verbosity.js";
7
+ import * as Activity from "./activity.js";
8
+ import * as BusApi from "./bus-api.js";
8
9
  import * as ChannelPosts from "./channel-posts.js";
9
10
  import * as CommandTemplates from "./command-templates.js";
10
11
  import * as Commands from "./commands.js";
11
12
  import * as Config from "./config.js";
12
13
  import * as Delivery from "./delivery.js";
14
+ import * as GenerativeApps from "./generative-apps.js";
13
15
  import * as Lifecycle from "./lifecycle.js";
16
+ import * as Menu from "./menu.js";
14
17
  import * as OutboundAttachments from "./outbound-attachments.js";
15
18
  import * as OutboundHandlers from "./outbound.js";
16
19
  import * as Pi from "./pi.js";
@@ -21,7 +24,91 @@ import * as Routing from "./routing.js";
21
24
  import * as Runtime from "./runtime.js";
22
25
  import * as Setup from "./setup.js";
23
26
  import * as TelegramApi from "./telegram-api.js";
24
- import * as GenerativeApps from "./generative-apps.js";
27
+ /** Compose any registered held command over captured recipient effects; no ordinary follower API fallback. */
28
+ export function createTelegramFollowerSelectedCommandBinding(deps) {
29
+ const { ctx, operationId, registrationGeneration, name, recipient, command, deliver, recordOwnership, } = deps, target = { ...deps.target };
30
+ const prepare = command.prepareHeldCommand, canPrepare = command.canPrepareHeldCommand;
31
+ const isCurrent = recipient.isCurrent, assertRecipientCurrent = recipient.assertRecipientCurrent, menu = deps.menu, menuPorts = menu && { ...menu };
32
+ if ([
33
+ prepare,
34
+ canPrepare,
35
+ isCurrent,
36
+ assertRecipientCurrent,
37
+ deliver,
38
+ recordOwnership,
39
+ ].some((port) => typeof port !== "function") ||
40
+ (menuPorts &&
41
+ [
42
+ menuPorts.getModelMenuState,
43
+ menuPorts.storeModelMenuState,
44
+ menuPorts.getActiveModel,
45
+ menuPorts.getThinkingLevel,
46
+ menuPorts.buildStatusHtml,
47
+ menuPorts.isIdle,
48
+ menuPorts.canOfferInFlightModelSwitch,
49
+ ].some((port) => typeof port !== "function")))
50
+ return undefined;
51
+ const portsCurrent = () => deps.ctx === ctx &&
52
+ deps.operationId === operationId &&
53
+ deps.registrationGeneration === registrationGeneration &&
54
+ deps.name === name &&
55
+ deps.recipient === recipient &&
56
+ recipient.isCurrent === isCurrent &&
57
+ recipient.assertRecipientCurrent === assertRecipientCurrent &&
58
+ deps.command === command &&
59
+ command.prepareHeldCommand === prepare &&
60
+ command.canPrepareHeldCommand === canPrepare &&
61
+ deps.deliver === deliver &&
62
+ deps.recordOwnership === recordOwnership &&
63
+ deps.menu === menu &&
64
+ (!menuPorts ||
65
+ Object.entries(menuPorts).every(([key, value]) => Reflect.get(menu, key) === value));
66
+ const current = () => portsCurrent() && isCurrent.call(recipient) && portsCurrent();
67
+ if (!current())
68
+ return undefined;
69
+ const api = BusApi.createTelegramSelectedMenuTextApi({
70
+ operationId,
71
+ registrationGeneration,
72
+ target,
73
+ assertAuthority: assertRecipientCurrent,
74
+ deliver,
75
+ });
76
+ const rendered = Replies.createTelegramRenderedMessageDeliveryRuntime({
77
+ sendMessage: api.sendMessage,
78
+ editMessage: api.editMessageText,
79
+ recordOwnership,
80
+ async sendRichMessage() {
81
+ throw new Error("Selected command has no rich or ordinary API fallback.");
82
+ },
83
+ });
84
+ const menus = menuPorts &&
85
+ Menu.createTelegramMenuActionRuntime({
86
+ ...menuPorts,
87
+ sendTextReply: rendered.sendTextReply,
88
+ sendInteractiveMessage: rendered.sendInteractiveMessage,
89
+ editInteractiveMessage: rendered.editInteractiveMessage,
90
+ });
91
+ const effects = {
92
+ sendTextReply: rendered.sendTextReply,
93
+ ...(menus ? { showStatus: menus.sendStatusMessage } : {}),
94
+ };
95
+ if (!canPrepare.call(command, name, effects) || !current())
96
+ return undefined;
97
+ return {
98
+ isCurrent: current,
99
+ assertRecipientCurrent,
100
+ prepare(readiness, context, input) {
101
+ if (!current() ||
102
+ context !== ctx ||
103
+ input.target.chatId !== target.chatId ||
104
+ input.target.threadId !== target.threadId ||
105
+ input.assertRecipientCurrent !== assertRecipientCurrent)
106
+ return undefined;
107
+ const plan = prepare.call(command, name, readiness, context, input, effects);
108
+ return current() ? plan : undefined;
109
+ },
110
+ };
111
+ }
25
112
  export function createTelegramQueueBindingRuntime(deps) {
26
113
  const settleDiscardedItems = (items, ctx) => {
27
114
  const durableItems = items.filter((item) => (item.admissionReceipts?.length ?? 0) > 0);
@@ -100,7 +187,9 @@ export function createTelegramQueueBindingRuntime(deps) {
100
187
  export function createTelegramGenerativeAppLiveSurfaceBinding() {
101
188
  let current;
102
189
  return {
103
- get() { return current; },
190
+ get() {
191
+ return current;
192
+ },
104
193
  set(runtime) {
105
194
  current?.shutdown();
106
195
  current = runtime;
@@ -314,6 +403,9 @@ export function createTelegramActivityBindingRuntime(deps) {
314
403
  publicationRuntime: {
315
404
  enqueue: publication.enqueue,
316
405
  reserve: publication.reserve,
406
+ hasPending: publication.hasPending,
407
+ beginWork: publication.beginWork,
408
+ hasUnconfirmed: publication.hasUnconfirmed,
317
409
  capture() {
318
410
  const authority = assistantOutputBinding.authority.captureAuthority();
319
411
  return {
@@ -324,7 +416,37 @@ export function createTelegramActivityBindingRuntime(deps) {
324
416
  },
325
417
  };
326
418
  }
327
- export function registerTelegramCommandsAndTools({ pi, agentDir, configStore, persistConfig, setup, activeTurnRuntime, lockedPollingRuntime, stopPolling, recoverPollingStart, getDisconnectThreadName, onTransportChanged, getStatusLines, buttonActionStore, sendMarkdownReply, sendChannelMarkdownMessage, sendChannelMediaMessage, listChannelPosts, mutateChannelPost, callMultipart, getDefaultChatId, getDefaultTarget, resolveAgentTarget, routeAgentMessage, canSendDirect, setGenerativeAppLiveSurfaceRuntime, recordRuntimeEvent, updateStatus, isContextCurrent, getSessionGeneration, connectionIntent, }) {
419
+ /** Fresh current work projection; a snapshot is not a cleanup grant or target-application ACK. */
420
+ export function createTelegramLiveTargetWorkObserver(deps) {
421
+ return (target, ctx) => {
422
+ const work = Queue.observeTelegramTargetQueueWork(target, deps.activeTurn.get(), deps.queue.getQueuedItems());
423
+ const flags = [
424
+ deps.isIdle(ctx),
425
+ deps.hasPendingMessages(ctx),
426
+ deps.lifecycle.hasDispatchPending(),
427
+ deps.lifecycle.isCompactionInProgress(),
428
+ deps.hasPendingControl(),
429
+ ];
430
+ const tools = deps.lifecycle.getActiveToolExecutions();
431
+ const publication = deps.publication.hasPending(), unconfirmed = deps.publication.hasUnconfirmed?.(), activity = deps.activity.hasPending?.(), delivery = deps.delivery.hasPendingTarget(target), api = deps.api.hasPendingTarget(target);
432
+ const unknown = work.unknown ||
433
+ flags.some((flag) => typeof flag !== "boolean") ||
434
+ !Number.isSafeInteger(tools) ||
435
+ tools < 0 ||
436
+ unconfirmed !== false ||
437
+ [publication, activity, delivery, api].some((flag) => typeof flag !== "boolean");
438
+ return {
439
+ sessionBusy: flags[0] !== true || flags.slice(1).some(Boolean) || tools > 0,
440
+ targetWork: work.protected,
441
+ deliveryPending: publication === true ||
442
+ activity === true ||
443
+ delivery === true ||
444
+ api === true,
445
+ unknown,
446
+ };
447
+ };
448
+ }
449
+ export function registerTelegramCommandsAndTools({ pi, agentDir, configStore, persistConfig, setup, activeTurnRuntime, lockedPollingRuntime, stopPolling, getDisconnectThreadName, onTransportChanged, getStatusLines, buttonActionStore, sendMarkdownReply, sendChannelMarkdownMessage, sendChannelMediaMessage, listChannelPosts, mutateChannelPost, callMultipart, getDefaultChatId, getDefaultTarget, resolveAgentTarget, routeAgentMessage, canSendDirect, setGenerativeAppLiveSurfaceRuntime, recordRuntimeEvent, updateStatus, isContextCurrent, getSessionGeneration, connectionIntent, }) {
328
450
  GenerativeApps.registerTelegramBindTool(pi, {
329
451
  agentDir,
330
452
  getActiveProfileName: configStore.getActiveProfileName,
@@ -334,13 +456,18 @@ export function registerTelegramCommandsAndTools({ pi, agentDir, configStore, pe
334
456
  : {}),
335
457
  isDeliveryHandleCurrent: Delivery.isTelegramDeliveryHandleCurrent,
336
458
  editView: (handle, view) => Delivery.editTelegramView(handle, view),
337
- planOutput: OutboundHandlers.createTelegramOutboundReplyPlanner(buttonActionStore, Config.createTelegramConfigControls(configStore).getAssistantRenderingMode),
459
+ planOutput: OutboundHandlers.createTelegramOutboundReplyPlanner(buttonActionStore, Config.createTelegramConfigControls(configStore)
460
+ .getAssistantRenderingMode),
338
461
  sendMarkdownReply,
339
462
  sendView: (view, options) => Delivery.sendTelegramView(view, options),
340
463
  recordRuntimeEvent,
341
464
  });
342
- ChannelPosts.registerTelegramChannelPostMutationTool(pi, { mutate: mutateChannelPost });
343
- ChannelPosts.registerTelegramChannelPostListTool(pi, { list: listChannelPosts });
465
+ ChannelPosts.registerTelegramChannelPostMutationTool(pi, {
466
+ mutate: mutateChannelPost,
467
+ });
468
+ ChannelPosts.registerTelegramChannelPostListTool(pi, {
469
+ list: listChannelPosts,
470
+ });
344
471
  OutboundAttachments.registerTelegramOutboundAttachmentTool(pi, {
345
472
  getActiveTurn: activeTurnRuntime.get,
346
473
  getDefaultChatId,
@@ -356,7 +483,8 @@ export function registerTelegramCommandsAndTools({ pi, agentDir, configStore, pe
356
483
  resolveAgentTarget,
357
484
  routeAgentMessage,
358
485
  canSendDirect,
359
- planMessage: OutboundHandlers.createTelegramOutboundReplyPlanner(buttonActionStore, Config.createTelegramConfigControls(configStore).getAssistantRenderingMode),
486
+ planMessage: OutboundHandlers.createTelegramOutboundReplyPlanner(buttonActionStore, Config.createTelegramConfigControls(configStore)
487
+ .getAssistantRenderingMode),
360
488
  sendMarkdownMessage: (chatId, markdown, options) => sendMarkdownReply(chatId, undefined, markdown, options),
361
489
  sendChannelMarkdownMessage,
362
490
  sendChannelMediaMessage,
@@ -456,7 +584,6 @@ export function registerTelegramCommandsAndTools({ pi, agentDir, configStore, pe
456
584
  startPolling: lockedPollingRuntime.start,
457
585
  recordConnectionEvent: (error, phase) => recordRuntimeEvent("connection", error, { phase }),
458
586
  stopPolling: stopPolling ?? lockedPollingRuntime.stop,
459
- recoverPollingStart,
460
587
  getDisconnectThreadName,
461
588
  queueAgentConnectionContext,
462
589
  updateStatus,
@@ -599,7 +726,9 @@ export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime,
599
726
  pendingFinalPublication = undefined;
600
727
  };
601
728
  const recordPublicationFailure = (error) => {
602
- recordRuntimeEvent("delivery", error, { phase: "agent-end-background-delivery" });
729
+ recordRuntimeEvent("delivery", error, {
730
+ phase: "agent-end-background-delivery",
731
+ });
603
732
  };
604
733
  const scheduleActiveTurnDelivery = (task) => {
605
734
  void publicationRuntime.enqueue(task).catch(recordPublicationFailure);
@@ -630,7 +759,8 @@ export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime,
630
759
  getActiveTurn: activeTurnRuntime.get,
631
760
  loadConfig: configStore.load,
632
761
  extractAssistant: Replies.extractRunAssistantMessage,
633
- isAssistantAlreadyPublished: (assistant) => !!assistant.text && assistantOutputRuntime.hasAdmittedTelegramIntermediate(assistant.text),
762
+ isAssistantAlreadyPublished: (assistant) => !!assistant.text &&
763
+ assistantOutputRuntime.hasAdmittedTelegramIntermediate(assistant.text),
634
764
  getFoldQueuedPromptsIntoHistory: lifecycle.shouldFoldQueuedPromptsIntoHistory,
635
765
  resetRuntimeState: agentEndResetter,
636
766
  isSessionActive: isSessionContextActive,
@@ -647,7 +777,9 @@ export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime,
647
777
  pending?.reservation.cancel();
648
778
  const reservation = matches && pending ? pending.reservation : publicationRuntime.reserve();
649
779
  return {
650
- schedule: (task) => { void reservation.publish(task).catch(recordPublicationFailure); },
780
+ schedule: (task) => {
781
+ void reservation.publish(task).catch(recordPublicationFailure);
782
+ },
651
783
  cancel: reservation.cancel,
652
784
  };
653
785
  },
@@ -673,8 +805,7 @@ export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime,
673
805
  setActiveToolExecutions: lifecycle.setActiveToolExecutions,
674
806
  triggerPendingModelSwitchAbort: modelSwitchController.triggerPendingAbort,
675
807
  });
676
- Lifecycle.setResetTransportReplyDedup(Replies.resetTransportReplyDedup);
677
- const agentStartWithDedupReset = Lifecycle.createAgentStartDedupHook(agentLifecycleHooks.onAgentStart, scheduleActiveTurnDelivery);
808
+ const agentStartWithDedupReset = Lifecycle.createAgentStartDedupHook(agentLifecycleHooks.onAgentStart, Replies.resetTransportReplyDedup, scheduleActiveTurnDelivery);
678
809
  let uiPromptActive = false;
679
810
  const startAgentActivityTypingLoop = (ctx) => {
680
811
  if (uiPromptActive || !canSendAgentActivity(ctx))
@@ -705,7 +836,9 @@ export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime,
705
836
  if (turn && isTurnTransportActive?.(turn) === false)
706
837
  return;
707
838
  try {
708
- await sendMarkdownReply(target.chatId, replyToMessageId, text, { target });
839
+ await sendMarkdownReply(target.chatId, replyToMessageId, text, {
840
+ target,
841
+ });
709
842
  }
710
843
  catch (error) {
711
844
  recordRuntimeEvent("delivery", error, { phase: "compaction-notice" });
@@ -879,16 +1012,25 @@ export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime,
879
1012
  previewRuntime.seal();
880
1013
  activityRuntime.onAssistantMessageEnd(event.message.stopReason);
881
1014
  }
882
- if (event.message.role !== "assistant" || event.message.stopReason === "toolUse" || event.message.stopReason === "aborted")
1015
+ if (event.message.role !== "assistant" ||
1016
+ event.message.stopReason === "toolUse" ||
1017
+ event.message.stopReason === "aborted")
883
1018
  return;
884
1019
  const turn = activeTurnRuntime.get();
885
1020
  if (!turn || turn.guestQueryId || pendingFinalPublication?.turn === turn)
886
1021
  return;
887
1022
  cancelPendingFinalPublication();
888
- const assistant = Replies.extractLatestAssistantMessageText([event.message]);
889
- if (!assistant.text && assistant.stopReason !== "error" && turn.queuedAttachments.length === 0)
1023
+ const assistant = Replies.extractLatestAssistantMessageText([
1024
+ event.message,
1025
+ ]);
1026
+ if (!assistant.text &&
1027
+ assistant.stopReason !== "error" &&
1028
+ turn.queuedAttachments.length === 0)
890
1029
  return;
891
- pendingFinalPublication = { turn, reservation: publicationRuntime.reserve() };
1030
+ pendingFinalPublication = {
1031
+ turn,
1032
+ reservation: publicationRuntime.reserve(),
1033
+ };
892
1034
  },
893
1035
  onUiPromptStart(event, ctx) {
894
1036
  if (!isSessionContextActive(ctx))
@@ -911,7 +1053,8 @@ export function registerTelegramLifecycleRuntimeHooks({ pi, publicationRuntime,
911
1053
  async onAgentEnd(event, ctx) {
912
1054
  if (!isSessionContextActive(ctx))
913
1055
  return;
914
- if (pendingFinalPublication && pendingFinalPublication.turn !== activeTurnRuntime.get()) {
1056
+ if (pendingFinalPublication &&
1057
+ pendingFinalPublication.turn !== activeTurnRuntime.get()) {
915
1058
  cancelPendingFinalPublication();
916
1059
  return;
917
1060
  }
@@ -3,6 +3,7 @@
3
3
  * Zones: multi-instance bus, telegram api transport, live instance routing
4
4
  * Wraps the direct Telegram Bot API runtime so follower instances can route outbound calls through the bus leader
5
5
  */
6
+ import { type TelegramBusSelectedMenuDeliveryObservation, type TelegramBusSelectedMenuTextEffect } from "./bus.ts";
6
7
  import type { TelegramBridgeApiRuntime } from "./telegram-api.ts";
7
8
  export type TelegramBusApiCall = (method: string, args: unknown[]) => Promise<unknown>;
8
9
  export interface TelegramBusAwareApiRuntimeDeps {
@@ -14,4 +15,15 @@ export interface TelegramBusAwareApiRuntimeDeps {
14
15
  threadId?: number;
15
16
  } | undefined;
16
17
  }
18
+ /** Bound selected-menu projection only; no ordinary/raw API fallback and no activation during preparation. */
19
+ export declare function createTelegramSelectedMenuTextApi(deps: {
20
+ operationId: string;
21
+ registrationGeneration: string;
22
+ target: {
23
+ chatId: number;
24
+ threadId: number;
25
+ };
26
+ assertAuthority: () => void;
27
+ deliver(effect: TelegramBusSelectedMenuTextEffect, assertAuthority: () => void): Promise<TelegramBusSelectedMenuDeliveryObservation>;
28
+ }): Pick<TelegramBridgeApiRuntime, "sendMessage" | "editMessageText">;
17
29
  export declare function createTelegramBusAwareApiRuntime(deps: TelegramBusAwareApiRuntimeDeps): TelegramBridgeApiRuntime;