@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
@@ -6,12 +6,11 @@
6
6
 
7
7
  import {
8
8
  markTelegramBusCrossTargetDelivery,
9
+ parseTelegramBusSelectedMenuTextEffect,
9
10
  stripTelegramBusApiMetadata,
11
+ type TelegramBusSelectedMenuDeliveryObservation,
12
+ type TelegramBusSelectedMenuTextEffect,
10
13
  } from "./bus.ts";
11
- import {
12
- buildTelegramAnswerGuestQueryBody,
13
- isTelegramMessageNotModifiedError,
14
- } from "./telegram-api.ts";
15
14
  import type { TelegramAttachmentSource } from "./media.ts";
16
15
  import type {
17
16
  TelegramAnswerGuestQueryOptions,
@@ -26,6 +25,13 @@ import type {
26
25
  TelegramSentMessage,
27
26
  TelegramUpdate,
28
27
  } from "./telegram-api.ts";
28
+ import {
29
+ buildTelegramAnswerGuestQueryBody,
30
+ isTelegramApiCommitUnknownError,
31
+ isTelegramMessageNotModifiedError,
32
+ TelegramApiAuthorityError,
33
+ TelegramApiCommitUnknownError,
34
+ } from "./telegram-api.ts";
29
35
 
30
36
  export type TelegramBusApiCall = (
31
37
  method: string,
@@ -83,6 +89,167 @@ function rejectTelegramDirectOwnership(method: string): Promise<never> {
83
89
  );
84
90
  }
85
91
 
92
+ /** Bound selected-menu projection only; no ordinary/raw API fallback and no activation during preparation. */
93
+ export function createTelegramSelectedMenuTextApi(deps: {
94
+ operationId: string;
95
+ registrationGeneration: string;
96
+ target: { chatId: number; threadId: number };
97
+ assertAuthority: () => void;
98
+ deliver(
99
+ effect: TelegramBusSelectedMenuTextEffect,
100
+ assertAuthority: () => void,
101
+ ): Promise<TelegramBusSelectedMenuDeliveryObservation>;
102
+ }): Pick<TelegramBridgeApiRuntime, "sendMessage" | "editMessageText"> {
103
+ const { operationId, registrationGeneration, assertAuthority, deliver } =
104
+ deps,
105
+ target = { ...deps.target };
106
+ if (
107
+ typeof assertAuthority !== "function" ||
108
+ typeof deliver !== "function" ||
109
+ !operationId?.trim() ||
110
+ operationId.length > 128 ||
111
+ !registrationGeneration?.trim() ||
112
+ registrationGeneration.length > 128 ||
113
+ !Number.isSafeInteger(target.chatId) ||
114
+ target.chatId <= 0 ||
115
+ !Number.isSafeInteger(target.threadId) ||
116
+ target.threadId <= 0
117
+ )
118
+ throw new TelegramApiAuthorityError(false);
119
+ const invoke = async (
120
+ edit: boolean,
121
+ raw: Record<string, unknown>,
122
+ options?: Pick<TelegramApiCallOptions, "assertAuthority">,
123
+ ) => {
124
+ let issued = false;
125
+ const assertCurrent = () => {
126
+ try {
127
+ assertAuthority();
128
+ } catch {
129
+ throw new TelegramApiAuthorityError(issued);
130
+ }
131
+ };
132
+ try {
133
+ if (
134
+ options?.assertAuthority !== assertAuthority ||
135
+ Reflect.ownKeys(raw).some(
136
+ (key) =>
137
+ typeof key !== "string" ||
138
+ ![
139
+ "chat_id",
140
+ "message_thread_id",
141
+ "text",
142
+ "parse_mode",
143
+ "reply_markup",
144
+ ...(edit ? ["message_id"] : ["reply_parameters"]),
145
+ ].includes(key),
146
+ )
147
+ )
148
+ throw new TelegramApiAuthorityError(false);
149
+ const body = structuredClone(raw),
150
+ reply = body.reply_parameters;
151
+ if (
152
+ body.chat_id !== target.chatId ||
153
+ body.message_thread_id !== target.threadId ||
154
+ (reply !== undefined &&
155
+ (!reply ||
156
+ typeof reply !== "object" ||
157
+ Array.isArray(reply) ||
158
+ Object.keys(reply).some(
159
+ (key) =>
160
+ !["message_id", "allow_sending_without_reply"].includes(key),
161
+ ) ||
162
+ (reply as Record<string, unknown>).allow_sending_without_reply !==
163
+ true ||
164
+ !Number.isSafeInteger(
165
+ (reply as Record<string, unknown>).message_id,
166
+ ) ||
167
+ ((reply as Record<string, unknown>).message_id as number) <= 0))
168
+ )
169
+ throw new TelegramApiAuthorityError(false);
170
+ const effect = parseTelegramBusSelectedMenuTextEffect({
171
+ kind: edit ? "edit-text" : "send-text",
172
+ text: body.text,
173
+ ...(body.parse_mode !== undefined
174
+ ? { parseMode: body.parse_mode }
175
+ : {}),
176
+ ...(body.reply_markup !== undefined
177
+ ? { replyMarkup: body.reply_markup }
178
+ : {}),
179
+ ...(edit
180
+ ? { messageId: body.message_id }
181
+ : reply !== undefined
182
+ ? {
183
+ replyToMessageId: (reply as Record<string, unknown>).message_id,
184
+ }
185
+ : {}),
186
+ });
187
+ if (!effect) throw new TelegramApiAuthorityError(false);
188
+ assertCurrent();
189
+ issued = true;
190
+ const observed = await deliver.call(deps, effect, assertAuthority);
191
+ assertCurrent();
192
+ if (
193
+ observed.operationId !== operationId ||
194
+ observed.registrationGeneration !== registrationGeneration ||
195
+ observed.effect !== effect.kind ||
196
+ observed.recipient.target.chatId !== target.chatId ||
197
+ observed.recipient.target.threadId !== target.threadId ||
198
+ !Number.isSafeInteger(observed.messageId) ||
199
+ observed.messageId <= 0 ||
200
+ (effect.kind === "edit-text" && observed.messageId !== effect.messageId)
201
+ )
202
+ throw new Error("Selected-menu transport result is unconfirmed.");
203
+ assertCurrent();
204
+ return observed.messageId;
205
+ } catch (error) {
206
+ if (
207
+ error instanceof TelegramApiAuthorityError ||
208
+ isTelegramApiCommitUnknownError(error)
209
+ )
210
+ throw error;
211
+ if (issued)
212
+ throw new TelegramApiCommitUnknownError(
213
+ edit ? "editMessageText" : "sendMessage",
214
+ error,
215
+ );
216
+ throw new TelegramApiAuthorityError(false);
217
+ }
218
+ };
219
+ return {
220
+ sendMessage: async (body, options) => ({
221
+ message_id: await invoke(false, body, options),
222
+ }),
223
+ editMessageText: async (body, options) => {
224
+ await invoke(true, body, options);
225
+ return "edited";
226
+ },
227
+ };
228
+ }
229
+
230
+ /** Followers route every chat action through the leader's generic `sendChatAction` call. */
231
+ function sendTelegramFollowerChatAction(
232
+ deps: Pick<
233
+ TelegramBusAwareApiRuntimeDeps,
234
+ "callFollowerApi" | "getDefaultTarget"
235
+ >,
236
+ chatId: number,
237
+ action: string,
238
+ options?: { message_thread_id?: number },
239
+ ): Promise<boolean> {
240
+ const body = withDefaultThreadTarget(
241
+ {
242
+ chat_id: chatId,
243
+ action,
244
+ ...(options?.message_thread_id !== undefined
245
+ ? { message_thread_id: options.message_thread_id }
246
+ : {}),
247
+ },
248
+ deps.getDefaultTarget?.(),
249
+ );
250
+ return deps.callFollowerApi("call", ["sendChatAction", body]).then(asBoolean);
251
+ }
252
+
86
253
  export function createTelegramBusAwareApiRuntime(
87
254
  deps: TelegramBusAwareApiRuntimeDeps,
88
255
  ): TelegramBridgeApiRuntime {
@@ -92,13 +259,16 @@ export function createTelegramBusAwareApiRuntime(
92
259
  body: Record<string, unknown>,
93
260
  options?: TelegramApiCallOptions,
94
261
  ): Promise<TResponse> {
95
- return deps.ownsDirect()
96
- ? deps.directRuntime.call<TResponse>(method, body, options)
97
- : (deps.callFollowerApi("call", [
98
- method,
99
- body,
100
- options,
101
- ]) as Promise<TResponse>);
262
+ if (deps.ownsDirect())
263
+ return deps.directRuntime.call<TResponse>(method, body, options);
264
+ // A process-local authority callback cannot cross IPC as an enforceable grant.
265
+ if (options?.assertAuthority)
266
+ return Promise.reject(new TelegramApiAuthorityError(false));
267
+ return deps.callFollowerApi("call", [
268
+ method,
269
+ body,
270
+ options,
271
+ ]) as Promise<TResponse>;
102
272
  },
103
273
  callMultipart<TResponse>(
104
274
  method: string,
@@ -108,25 +278,31 @@ export function createTelegramBusAwareApiRuntime(
108
278
  fileName: string,
109
279
  options?: TelegramApiCallOptions,
110
280
  ): Promise<TResponse> {
111
- return deps.ownsDirect()
112
- ? deps.directRuntime.callMultipart<TResponse>(
113
- method,
114
- fields,
115
- fileField,
116
- filePath,
117
- fileName,
118
- options,
119
- )
120
- : (deps.callFollowerApi("callMultipart", [
121
- method,
122
- fields,
123
- fileField,
124
- filePath,
125
- fileName,
126
- options,
127
- ]) as Promise<TResponse>);
281
+ if (deps.ownsDirect())
282
+ return deps.directRuntime.callMultipart<TResponse>(
283
+ method,
284
+ fields,
285
+ fileField,
286
+ filePath,
287
+ fileName,
288
+ options,
289
+ );
290
+ if (options?.assertAuthority)
291
+ return Promise.reject(new TelegramApiAuthorityError(false));
292
+ return deps.callFollowerApi("callMultipart", [
293
+ method,
294
+ fields,
295
+ fileField,
296
+ filePath,
297
+ fileName,
298
+ options,
299
+ ]) as Promise<TResponse>;
128
300
  },
129
- downloadFile(fileId: string, suggestedName: string, source?: TelegramAttachmentSource): Promise<string> {
301
+ downloadFile(
302
+ fileId: string,
303
+ suggestedName: string,
304
+ source?: TelegramAttachmentSource,
305
+ ): Promise<string> {
130
306
  // The source names the file (kind-scope-message); dropping it falls back to the bare generated name.
131
307
  return deps.ownsDirect()
132
308
  ? deps.directRuntime.downloadFile(fileId, suggestedName, source)
@@ -149,73 +325,39 @@ export function createTelegramBusAwareApiRuntime(
149
325
  ? deps.directRuntime.getUpdates(body, signal)
150
326
  : rejectTelegramDirectOwnership("getUpdates");
151
327
  },
152
- setMyCommands(commands): Promise<boolean> {
153
- return deps.ownsDirect()
154
- ? deps.directRuntime.setMyCommands(commands)
155
- : deps
156
- .callFollowerApi("call", ["setMyCommands", { commands }])
157
- .then(asBoolean);
328
+ setMyCommands(commands, options): Promise<boolean> {
329
+ if (deps.ownsDirect())
330
+ return deps.directRuntime.setMyCommands(commands, options);
331
+ if (options?.assertAuthority)
332
+ return Promise.reject(new TelegramApiAuthorityError(false));
333
+ return deps
334
+ .callFollowerApi("call", ["setMyCommands", { commands }])
335
+ .then(asBoolean);
158
336
  },
159
337
  sendChatAction(
160
338
  chatId: number,
161
339
  action: string,
162
340
  options?: { message_thread_id?: number },
163
341
  ): Promise<boolean> {
164
- const body = withDefaultThreadTarget(
165
- {
166
- chat_id: chatId,
167
- action,
168
- ...(options?.message_thread_id !== undefined
169
- ? { message_thread_id: options.message_thread_id }
170
- : {}),
171
- },
172
- deps.getDefaultTarget?.(),
173
- );
174
342
  return deps.ownsDirect()
175
343
  ? deps.directRuntime.sendChatAction(chatId, action, options)
176
- : deps
177
- .callFollowerApi("call", ["sendChatAction", body])
178
- .then(asBoolean);
344
+ : sendTelegramFollowerChatAction(deps, chatId, action, options);
179
345
  },
180
346
  sendTypingAction(
181
347
  chatId: number,
182
348
  options?: { message_thread_id?: number },
183
349
  ): Promise<unknown> {
184
- const body = withDefaultThreadTarget(
185
- {
186
- chat_id: chatId,
187
- action: "typing",
188
- ...(options?.message_thread_id !== undefined
189
- ? { message_thread_id: options.message_thread_id }
190
- : {}),
191
- },
192
- deps.getDefaultTarget?.(),
193
- );
194
350
  return deps.ownsDirect()
195
351
  ? deps.directRuntime.sendTypingAction(chatId, options)
196
- : deps
197
- .callFollowerApi("call", ["sendChatAction", body])
198
- .then(asBoolean);
352
+ : sendTelegramFollowerChatAction(deps, chatId, "typing", options);
199
353
  },
200
354
  sendRecordVoiceAction(
201
355
  chatId: number,
202
356
  options?: { message_thread_id?: number },
203
357
  ): Promise<unknown> {
204
- const body = withDefaultThreadTarget(
205
- {
206
- chat_id: chatId,
207
- action: "record_voice",
208
- ...(options?.message_thread_id !== undefined
209
- ? { message_thread_id: options.message_thread_id }
210
- : {}),
211
- },
212
- deps.getDefaultTarget?.(),
213
- );
214
358
  return deps.ownsDirect()
215
359
  ? deps.directRuntime.sendRecordVoiceAction(chatId, options)
216
- : deps
217
- .callFollowerApi("call", ["sendChatAction", body])
218
- .then(asBoolean);
360
+ : sendTelegramFollowerChatAction(deps, chatId, "record_voice", options);
219
361
  },
220
362
  sendMessageDraft(
221
363
  chatId: number,
@@ -250,33 +392,41 @@ export function createTelegramBusAwareApiRuntime(
250
392
  .callFollowerApi("call", ["sendMessageDraft", scopedBody])
251
393
  .then(asBoolean);
252
394
  },
253
- sendMessage(body: TelegramSendMessageBody): Promise<TelegramSentMessage> {
254
- return deps.ownsDirect()
255
- ? deps.directRuntime.sendMessage(stripTelegramBusApiMetadata(body))
256
- : deps
257
- .callFollowerApi("call", [
258
- "sendMessage",
259
- markFollowerCrossTargetDelivery(
260
- body,
261
- deps.getDefaultTarget?.(),
262
- ),
263
- ])
264
- .then(asSentMessage);
395
+ sendMessage(
396
+ body: TelegramSendMessageBody,
397
+ options?: Pick<TelegramApiCallOptions, "assertAuthority">,
398
+ ): Promise<TelegramSentMessage> {
399
+ if (deps.ownsDirect())
400
+ return deps.directRuntime.sendMessage(
401
+ stripTelegramBusApiMetadata(body),
402
+ options,
403
+ );
404
+ if (options?.assertAuthority)
405
+ return Promise.reject(new TelegramApiAuthorityError(false));
406
+ return deps
407
+ .callFollowerApi("call", [
408
+ "sendMessage",
409
+ markFollowerCrossTargetDelivery(body, deps.getDefaultTarget?.()),
410
+ ])
411
+ .then(asSentMessage);
265
412
  },
266
413
  sendRichMessage(
267
414
  body: TelegramSendRichMessageBody,
415
+ options?: Pick<TelegramApiCallOptions, "assertAuthority">,
268
416
  ): Promise<TelegramSentMessage> {
269
- return deps.ownsDirect()
270
- ? deps.directRuntime.sendRichMessage(stripTelegramBusApiMetadata(body))
271
- : deps
272
- .callFollowerApi("call", [
273
- "sendRichMessage",
274
- markFollowerCrossTargetDelivery(
275
- body,
276
- deps.getDefaultTarget?.(),
277
- ),
278
- ])
279
- .then(asSentMessage);
417
+ if (deps.ownsDirect())
418
+ return deps.directRuntime.sendRichMessage(
419
+ stripTelegramBusApiMetadata(body),
420
+ options,
421
+ );
422
+ if (options?.assertAuthority)
423
+ return Promise.reject(new TelegramApiAuthorityError(false));
424
+ return deps
425
+ .callFollowerApi("call", [
426
+ "sendRichMessage",
427
+ markFollowerCrossTargetDelivery(body, deps.getDefaultTarget?.()),
428
+ ])
429
+ .then(asSentMessage);
280
430
  },
281
431
  sendRichMessageDraft(
282
432
  body: TelegramSendRichMessageDraftBody,
@@ -289,8 +439,11 @@ export function createTelegramBusAwareApiRuntime(
289
439
  },
290
440
  async editMessageText(
291
441
  body: TelegramEditMessageTextBody,
442
+ options?: Pick<TelegramApiCallOptions, "assertAuthority">,
292
443
  ): Promise<"edited" | "unchanged"> {
293
- if (deps.ownsDirect()) return deps.directRuntime.editMessageText(body);
444
+ if (deps.ownsDirect())
445
+ return deps.directRuntime.editMessageText(body, options);
446
+ if (options?.assertAuthority) throw new TelegramApiAuthorityError(false);
294
447
  try {
295
448
  await deps.callFollowerApi("call", ["editMessageText", body]);
296
449
  return "edited";
@@ -320,11 +473,21 @@ export function createTelegramBusAwareApiRuntime(
320
473
  async answerCallbackQuery(
321
474
  callbackQueryId: string,
322
475
  text?: string,
476
+ options?: Pick<TelegramApiCallOptions, "assertAuthority">,
323
477
  ): Promise<void> {
478
+ const assertAuthority = options?.assertAuthority;
324
479
  if (deps.ownsDirect()) {
325
- await deps.directRuntime.answerCallbackQuery(callbackQueryId, text);
480
+ const authorityOptions:
481
+ [] | [Pick<TelegramApiCallOptions, "assertAuthority">] =
482
+ assertAuthority ? [{ assertAuthority }] : [];
483
+ await deps.directRuntime.answerCallbackQuery(
484
+ callbackQueryId,
485
+ text,
486
+ ...authorityOptions,
487
+ );
326
488
  return;
327
489
  }
490
+ if (assertAuthority) throw new TelegramApiAuthorityError(false);
328
491
  await deps.callFollowerApi("call", [
329
492
  "answerCallbackQuery",
330
493
  {