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