@llblab/pi-telegram 0.45.11 → 0.47.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 (204) hide show
  1. package/BACKLOG.md +5 -1
  2. package/CHANGELOG.md +12 -0
  3. package/README.md +6 -6
  4. package/dist/api/activity.d.ts +6 -0
  5. package/dist/api/activity.js +6 -0
  6. package/dist/api/commands.d.ts +6 -0
  7. package/dist/api/commands.js +6 -0
  8. package/dist/api/delivery.d.ts +6 -0
  9. package/dist/api/delivery.js +6 -0
  10. package/dist/api/inbound.d.ts +6 -0
  11. package/dist/api/inbound.js +6 -0
  12. package/dist/api/keyboard.d.ts +6 -0
  13. package/dist/api/keyboard.js +6 -0
  14. package/dist/api/outbound.d.ts +6 -0
  15. package/dist/api/outbound.js +6 -0
  16. package/dist/api/sections.d.ts +7 -0
  17. package/dist/api/sections.js +6 -0
  18. package/dist/api/status.d.ts +6 -0
  19. package/dist/api/status.js +6 -0
  20. package/dist/api/updates.d.ts +6 -0
  21. package/dist/api/updates.js +6 -0
  22. package/dist/api/voice.d.ts +6 -0
  23. package/dist/api/voice.js +6 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.js +6 -0
  26. package/dist/lib/activity-verbosity.d.ts +52 -0
  27. package/dist/lib/activity-verbosity.js +596 -0
  28. package/dist/lib/activity.d.ts +220 -0
  29. package/dist/lib/activity.js +574 -0
  30. package/dist/lib/agent-messages.d.ts +28 -0
  31. package/dist/lib/agent-messages.js +86 -0
  32. package/dist/lib/bindings.d.ts +250 -0
  33. package/dist/lib/bindings.js +936 -0
  34. package/dist/lib/bus-api.d.ts +18 -0
  35. package/dist/lib/bus-api.js +254 -0
  36. package/dist/lib/bus-follower.d.ts +464 -0
  37. package/dist/lib/bus-follower.js +1686 -0
  38. package/dist/lib/bus-leader.d.ts +292 -0
  39. package/dist/lib/bus-leader.js +2242 -0
  40. package/dist/lib/bus-transport.d.ts +64 -0
  41. package/dist/lib/bus-transport.js +140 -0
  42. package/dist/lib/bus.d.ts +518 -0
  43. package/dist/lib/bus.js +2055 -0
  44. package/dist/lib/channel-posts.d.ts +170 -0
  45. package/dist/lib/channel-posts.js +611 -0
  46. package/dist/lib/command-templates.d.ts +70 -0
  47. package/dist/lib/command-templates.js +744 -0
  48. package/dist/lib/commands.d.ts +541 -0
  49. package/dist/lib/commands.js +1155 -0
  50. package/dist/lib/config.d.ts +252 -0
  51. package/dist/lib/config.js +889 -0
  52. package/dist/lib/delivery.d.ts +163 -0
  53. package/dist/lib/delivery.js +542 -0
  54. package/dist/lib/extension.d.ts +7 -0
  55. package/dist/lib/extension.js +1608 -0
  56. package/dist/lib/generative-app-worker.mjs +104 -0
  57. package/dist/lib/generative-apps.d.ts +212 -0
  58. package/dist/lib/generative-apps.js +1006 -0
  59. package/dist/lib/inbound.d.ts +91 -0
  60. package/dist/lib/inbound.js +502 -0
  61. package/dist/lib/journal.d.ts +665 -0
  62. package/dist/lib/journal.js +3701 -0
  63. package/dist/lib/keyboard.d.ts +23 -0
  64. package/dist/lib/keyboard.js +37 -0
  65. package/dist/lib/lifecycle.d.ts +157 -0
  66. package/dist/lib/lifecycle.js +395 -0
  67. package/dist/lib/locks.d.ts +164 -0
  68. package/dist/lib/locks.js +1208 -0
  69. package/dist/lib/logging.d.ts +50 -0
  70. package/dist/lib/logging.js +274 -0
  71. package/dist/lib/media.d.ts +181 -0
  72. package/dist/lib/media.js +602 -0
  73. package/dist/lib/menu-model.d.ts +217 -0
  74. package/dist/lib/menu-model.js +663 -0
  75. package/dist/lib/menu-queue.d.ts +37 -0
  76. package/dist/lib/menu-queue.js +408 -0
  77. package/dist/lib/menu-settings.d.ts +116 -0
  78. package/dist/lib/menu-settings.js +595 -0
  79. package/dist/lib/menu-status.d.ts +32 -0
  80. package/dist/lib/menu-status.js +112 -0
  81. package/dist/lib/menu-thinking.d.ts +29 -0
  82. package/dist/lib/menu-thinking.js +82 -0
  83. package/dist/lib/menu.d.ts +171 -0
  84. package/dist/lib/menu.js +323 -0
  85. package/dist/lib/model.d.ts +127 -0
  86. package/dist/lib/model.js +409 -0
  87. package/dist/lib/outbound-attachments.d.ts +241 -0
  88. package/dist/lib/outbound-attachments.js +639 -0
  89. package/dist/lib/outbound-buttons.d.ts +69 -0
  90. package/dist/lib/outbound-buttons.js +248 -0
  91. package/dist/lib/outbound-markup.d.ts +42 -0
  92. package/dist/lib/outbound-markup.js +678 -0
  93. package/dist/lib/outbound-voice.d.ts +55 -0
  94. package/dist/lib/outbound-voice.js +152 -0
  95. package/dist/lib/outbound.d.ts +185 -0
  96. package/dist/lib/outbound.js +516 -0
  97. package/dist/lib/ownership.d.ts +77 -0
  98. package/dist/lib/ownership.js +174 -0
  99. package/dist/lib/paths.d.ts +40 -0
  100. package/dist/lib/paths.js +94 -0
  101. package/dist/lib/pi.d.ts +72 -0
  102. package/dist/lib/pi.js +121 -0
  103. package/dist/lib/polling.d.ts +351 -0
  104. package/dist/lib/polling.js +1196 -0
  105. package/dist/lib/preview.d.ts +192 -0
  106. package/dist/lib/preview.js +614 -0
  107. package/dist/lib/prompt-templates.d.ts +24 -0
  108. package/dist/lib/prompt-templates.js +118 -0
  109. package/dist/lib/prompts.d.ts +57 -0
  110. package/dist/lib/prompts.js +167 -0
  111. package/dist/lib/queue.d.ts +766 -0
  112. package/dist/lib/queue.js +1965 -0
  113. package/dist/lib/recovery.d.ts +86 -0
  114. package/dist/lib/recovery.js +285 -0
  115. package/dist/lib/rendering.d.ts +20 -0
  116. package/dist/lib/rendering.js +983 -0
  117. package/dist/lib/replies.d.ts +214 -0
  118. package/dist/lib/replies.js +737 -0
  119. package/dist/lib/routing.d.ts +207 -0
  120. package/dist/lib/routing.js +2282 -0
  121. package/dist/lib/runtime.d.ts +172 -0
  122. package/dist/lib/runtime.js +402 -0
  123. package/dist/lib/sections.d.ts +165 -0
  124. package/dist/lib/sections.js +327 -0
  125. package/dist/lib/setup.d.ts +82 -0
  126. package/dist/lib/setup.js +150 -0
  127. package/dist/lib/skills.d.ts +8 -0
  128. package/dist/lib/skills.js +12 -0
  129. package/dist/lib/status.d.ts +442 -0
  130. package/dist/lib/status.js +1006 -0
  131. package/dist/lib/sync.d.ts +179 -0
  132. package/dist/lib/sync.js +782 -0
  133. package/dist/lib/target.d.ts +20 -0
  134. package/dist/lib/target.js +27 -0
  135. package/dist/lib/telegram-api.d.ts +541 -0
  136. package/dist/lib/telegram-api.js +1159 -0
  137. package/dist/lib/text-groups.d.ts +89 -0
  138. package/dist/lib/text-groups.js +317 -0
  139. package/dist/lib/thread-cleanup-manager.d.ts +288 -0
  140. package/dist/lib/thread-cleanup-manager.js +560 -0
  141. package/dist/lib/thread-display.d.ts +46 -0
  142. package/dist/lib/thread-display.js +257 -0
  143. package/dist/lib/thread-naming.d.ts +46 -0
  144. package/dist/lib/thread-naming.js +78 -0
  145. package/dist/lib/thread-reconciler.d.ts +239 -0
  146. package/dist/lib/thread-reconciler.js +644 -0
  147. package/dist/lib/threads.d.ts +621 -0
  148. package/dist/lib/threads.js +3679 -0
  149. package/dist/lib/time-injection.d.ts +15 -0
  150. package/dist/lib/time-injection.js +56 -0
  151. package/dist/lib/turns.d.ts +109 -0
  152. package/dist/lib/turns.js +500 -0
  153. package/dist/lib/updates.d.ts +1290 -0
  154. package/dist/lib/updates.js +3634 -0
  155. package/dist/lib/voice.d.ts +117 -0
  156. package/dist/lib/voice.js +174 -0
  157. package/dist/lib/workspace-admission.d.ts +264 -0
  158. package/dist/lib/workspace-admission.js +1136 -0
  159. package/dist/lib/workspace-retirement.d.ts +219 -0
  160. package/dist/lib/workspace-retirement.js +587 -0
  161. package/dist/lib/workspace-slots.d.ts +30 -0
  162. package/dist/lib/workspace-slots.js +54 -0
  163. package/dist/package.json +126 -0
  164. package/dist/pi-telegram/index.js +1 -0
  165. package/dist/skills/generated-control-surface/SKILL.md +107 -0
  166. package/dist/skills/generated-control-surface/references/capability-adapters.md +27 -0
  167. package/dist/skills/generated-control-surface/references/layout-and-state.md +37 -0
  168. package/dist/skills/generative-apps/SKILL.md +115 -0
  169. package/dist/skills/show-me/SKILL.md +166 -0
  170. package/dist/skills/show-me/references/telegram-surfaces.md +43 -0
  171. package/dist/skills/telegram-bridge/SKILL.md +129 -0
  172. package/dist/skills/telegram-bridge/references/configuration.md +15 -0
  173. package/dist/skills/telegram-bridge/references/delivery-and-threads.md +27 -0
  174. package/dist/skills/telegram-bridge/references/diagnosis.md +18 -0
  175. package/docs/architecture.md +1 -1
  176. package/docs/compact-matrix-literal.md +10 -3
  177. package/docs/generative-apps.md +15 -13
  178. package/docs/multi-instance-bus.md +17 -3
  179. package/docs/outbound.md +1 -1
  180. package/docs/public-api.md +2 -2
  181. package/lib/bindings.ts +89 -6
  182. package/lib/bus-follower.ts +11 -3
  183. package/lib/bus-leader.ts +57 -20
  184. package/lib/bus.ts +12 -2
  185. package/lib/commands.ts +2 -2
  186. package/lib/config.ts +14 -7
  187. package/lib/delivery.ts +38 -6
  188. package/lib/extension.ts +26 -1
  189. package/lib/generative-apps.ts +379 -13
  190. package/lib/menu-settings.ts +21 -5
  191. package/lib/outbound-markup.ts +16 -7
  192. package/lib/pi.ts +4 -0
  193. package/lib/sync.ts +3 -0
  194. package/lib/telegram-api.ts +12 -1
  195. package/lib/thread-cleanup-manager.ts +36 -6
  196. package/lib/thread-display.ts +96 -18
  197. package/lib/threads.ts +150 -30
  198. package/package.json +56 -13
  199. package/scripts/build-dist.mjs +44 -0
  200. package/scripts/measure-bus.mjs +8 -1
  201. package/scripts/measure-workspace.mjs +8 -1
  202. package/skills/generative-apps/SKILL.md +1 -1
  203. package/skills/show-me/SKILL.md +1 -1
  204. package/skills/telegram-bridge/SKILL.md +1 -1
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Telegram outbound button helpers
3
+ * Zones: telegram outbound, assistant markup, callback routing
4
+ * Owns assistant-authored telegram_button extraction, button action storage, callback handling, and prompt-turn construction
5
+ */
6
+ import type { TelegramInlineKeyboardButtonStyle, TelegramInlineKeyboardMarkup } from "./keyboard.ts";
7
+ import { type PendingTelegramTurn, type TelegramQueueTarget } from "./queue.ts";
8
+ export interface TelegramOutboundButtonBinding {
9
+ generation: string;
10
+ app: string;
11
+ revision: number;
12
+ }
13
+ export interface TelegramOutboundButtonAction {
14
+ text: string;
15
+ prompt: string;
16
+ binding?: TelegramOutboundButtonBinding;
17
+ selectedStyle?: TelegramInlineKeyboardButtonStyle;
18
+ disabled?: true;
19
+ }
20
+ export interface TelegramOutboundButtonStoredAction extends TelegramOutboundButtonAction {
21
+ createdAt: number;
22
+ }
23
+ export type TelegramOutboundButtonMarkup = TelegramInlineKeyboardMarkup;
24
+ export interface TelegramButtonReplyPlan {
25
+ markdown: string;
26
+ replyMarkup?: TelegramOutboundButtonMarkup;
27
+ }
28
+ export interface TelegramButtonActionStore {
29
+ register: (action: TelegramOutboundButtonAction) => string;
30
+ resolve: (callbackData: string | undefined) => TelegramOutboundButtonAction | undefined;
31
+ }
32
+ export interface TelegramButtonCallbackQuery {
33
+ id: string;
34
+ data?: string;
35
+ message?: {
36
+ message_id?: number;
37
+ message_thread_id?: number;
38
+ chat?: {
39
+ id?: number;
40
+ };
41
+ reply_markup?: TelegramOutboundButtonMarkup;
42
+ };
43
+ }
44
+ export interface TelegramButtonCallbackHandlerDeps<TContext = unknown> {
45
+ resolveAction: (callbackData: string | undefined) => TelegramOutboundButtonAction | undefined;
46
+ answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
47
+ enqueueButtonPrompt: (query: TelegramButtonCallbackQuery, action: TelegramOutboundButtonAction, ctx: TContext) => boolean | void;
48
+ invokeBoundAction?: (query: TelegramButtonCallbackQuery, action: TelegramOutboundButtonAction, ctx: TContext) => Promise<false | "new" | "edit">;
49
+ editMessageReplyMarkup?: (chatId: number, messageId: number, replyMarkup: TelegramOutboundButtonMarkup) => Promise<void>;
50
+ }
51
+ export declare function createTelegramButtonActionStore(options?: {
52
+ ttlMs?: number;
53
+ }): TelegramButtonActionStore;
54
+ export declare function planTelegramButtonReply(markdown: string, deps: {
55
+ registerAction: (action: TelegramOutboundButtonAction) => string;
56
+ binding?: TelegramOutboundButtonBinding;
57
+ rendering?: "rich" | "html";
58
+ }): TelegramButtonReplyPlan;
59
+ export declare function createTelegramButtonReplyPlanner(store: Pick<TelegramButtonActionStore, "register">): (markdown: string) => TelegramButtonReplyPlan;
60
+ export declare function createTelegramButtonPromptTurn(options: {
61
+ chatId: number;
62
+ replyToMessageId: number;
63
+ queueOrder: number;
64
+ action: TelegramOutboundButtonAction;
65
+ target?: TelegramQueueTarget;
66
+ telegramPrefix?: string;
67
+ }): PendingTelegramTurn;
68
+ export declare function markTelegramButtonSelected(replyMarkup: TelegramOutboundButtonMarkup, callbackData: string, selectedStyle?: TelegramInlineKeyboardButtonStyle): TelegramOutboundButtonMarkup | undefined;
69
+ export declare function handleTelegramButtonCallbackQuery<TContext = unknown>(query: TelegramButtonCallbackQuery, ctx: TContext, deps: TelegramButtonCallbackHandlerDeps<TContext>): Promise<boolean>;
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Telegram outbound button helpers
3
+ * Zones: telegram outbound, assistant markup, callback routing
4
+ * Owns assistant-authored telegram_button extraction, button action storage, callback handling, and prompt-turn construction
5
+ */
6
+ import { randomUUID } from "node:crypto";
7
+ import { parseTelegramActionPayloadRows, parseTelegramButtonPayloadRows, replaceTelegramButtonFences, replaceTopLevelHtmlComments, } from "./outbound-markup.js";
8
+ import { truncateTelegramQueueSummary, } from "./queue.js";
9
+ const TELEGRAM_BUTTON_CALLBACK_PREFIX = "tgbtn";
10
+ const TELEGRAM_BUTTON_ACTION_TTL_MS = 24 * 60 * 60 * 1000;
11
+ function nowMs() {
12
+ return Date.now();
13
+ }
14
+ function normalizeMarkdownAfterButtonExtraction(markdown) {
15
+ return markdown.replace(/\n{3,}/g, "\n\n").trim();
16
+ }
17
+ function getTelegramButtonString(payload, key) {
18
+ const value = payload[key];
19
+ if (typeof value !== "string")
20
+ return undefined;
21
+ const trimmed = value.trim();
22
+ return trimmed || undefined;
23
+ }
24
+ function parseTelegramButtonAction(payload) {
25
+ const value = getTelegramButtonString(payload, "value");
26
+ const explicitLabel = getTelegramButtonString(payload, "label");
27
+ const explicitPrompt = getTelegramButtonString(payload, "prompt");
28
+ const label = explicitLabel ?? value ?? explicitPrompt;
29
+ if (payload.disabled !== undefined && typeof payload.disabled !== "boolean") {
30
+ return undefined;
31
+ }
32
+ if (payload.disabled === true) {
33
+ return { text: label ?? "", prompt: "", disabled: true };
34
+ }
35
+ const prompt = explicitPrompt ?? value ?? explicitLabel;
36
+ if (!label || !prompt)
37
+ return undefined;
38
+ const selectedStyle = payload.selected_style;
39
+ return {
40
+ text: label,
41
+ prompt,
42
+ ...(selectedStyle === "success" ||
43
+ selectedStyle === "danger" ||
44
+ selectedStyle === "primary"
45
+ ? { selectedStyle }
46
+ : {}),
47
+ };
48
+ }
49
+ export function createTelegramButtonActionStore(options = {}) {
50
+ const ttlMs = options.ttlMs ?? TELEGRAM_BUTTON_ACTION_TTL_MS;
51
+ const actions = new Map();
52
+ const cleanup = (currentTime) => {
53
+ for (const [key, action] of actions) {
54
+ if (currentTime - action.createdAt > ttlMs)
55
+ actions.delete(key);
56
+ }
57
+ };
58
+ return {
59
+ register: (action) => {
60
+ const currentTime = nowMs();
61
+ cleanup(currentTime);
62
+ const key = `${TELEGRAM_BUTTON_CALLBACK_PREFIX}:${randomUUID().slice(0, 8)}`;
63
+ actions.set(key, { ...action, createdAt: currentTime });
64
+ return key;
65
+ },
66
+ resolve: (callbackData) => {
67
+ if (!callbackData?.startsWith(`${TELEGRAM_BUTTON_CALLBACK_PREFIX}:`)) {
68
+ return undefined;
69
+ }
70
+ const currentTime = nowMs();
71
+ cleanup(currentTime);
72
+ const action = actions.get(callbackData);
73
+ if (!action)
74
+ return undefined;
75
+ actions.delete(callbackData);
76
+ return {
77
+ text: action.text,
78
+ prompt: action.prompt,
79
+ ...(action.disabled ? { disabled: true } : {}),
80
+ ...(action.binding ? { binding: action.binding } : {}),
81
+ ...(action.selectedStyle
82
+ ? { selectedStyle: action.selectedStyle }
83
+ : {}),
84
+ };
85
+ },
86
+ };
87
+ }
88
+ const DEFAULT_TELEGRAM_BUTTON_REPLY_MARKDOWN = "☑️ **Choose an option:**";
89
+ function escapeTelegramRichButtonText(text) {
90
+ return text.replace(/[&<>"'`\\*_\[\]{}$~\r\n]/g, (character) => `&#${character.charCodeAt(0)};`);
91
+ }
92
+ function renderTelegramRichButtonRow(row) {
93
+ return `<tg-button-row>${row.map((button) => {
94
+ const attributes = button.disabled
95
+ ? 'type="disabled"'
96
+ : `type="callback_data" data="${escapeTelegramRichButtonText(button.callback_data)}"`;
97
+ return `<tg-button ${attributes}>${escapeTelegramRichButtonText(button.text)}</tg-button>`;
98
+ }).join("")}</tg-button-row>`;
99
+ }
100
+ export function planTelegramButtonReply(markdown, deps) {
101
+ const keyboard = [];
102
+ const buildRows = (payloadRows, rich) => {
103
+ const actions = payloadRows.map((row) => row.map(parseTelegramButtonAction));
104
+ if (actions.some((row) => row.some((action) => !action)))
105
+ return undefined;
106
+ if (rich && actions.some((row) => {
107
+ const projected = row.map((action) => action.disabled
108
+ ? { text: action.text || "\u00a0", disabled: {} }
109
+ : { text: action.text, callback_data: "x".repeat(64) });
110
+ return row.length > 8 || renderTelegramRichButtonRow(projected).length > 32768;
111
+ }))
112
+ return undefined;
113
+ return actions.map((row) => row.map((action) => action.disabled
114
+ ? { text: action.text || "\u00a0", disabled: {} }
115
+ : {
116
+ text: action.text,
117
+ callback_data: deps.registerAction({
118
+ ...action,
119
+ ...(deps.binding ? { binding: deps.binding } : {}),
120
+ }),
121
+ }));
122
+ };
123
+ const withRichButtons = replaceTelegramButtonFences(markdown, (payload, closed) => {
124
+ if (!closed)
125
+ return "";
126
+ const payloadRows = parseTelegramButtonPayloadRows(payload);
127
+ if (!payloadRows)
128
+ return "";
129
+ const rich = deps.rendering !== "html";
130
+ const rows = buildRows(payloadRows, rich);
131
+ if (!rows)
132
+ return "";
133
+ if (!rich) {
134
+ keyboard.push(...rows);
135
+ return "";
136
+ }
137
+ return `\n${rows.map(renderTelegramRichButtonRow).join("\n\n")}\n`;
138
+ });
139
+ const stripped = replaceTopLevelHtmlComments(withRichButtons, (comment) => {
140
+ const command = "telegram_button";
141
+ const normalizedContent = comment.content.replace(/^\s+/, "").replace(/^!/, "");
142
+ if (!normalizedContent.startsWith(command))
143
+ return comment.raw;
144
+ const payloadRows = parseTelegramActionPayloadRows(comment, command);
145
+ if (!payloadRows)
146
+ return "";
147
+ const rows = buildRows(payloadRows, false);
148
+ if (rows)
149
+ keyboard.push(...rows);
150
+ return "";
151
+ });
152
+ const visibleMarkdown = normalizeMarkdownAfterButtonExtraction(stripped);
153
+ return {
154
+ markdown: keyboard.length > 0 && !visibleMarkdown
155
+ ? DEFAULT_TELEGRAM_BUTTON_REPLY_MARKDOWN
156
+ : visibleMarkdown,
157
+ ...(keyboard.length > 0
158
+ ? { replyMarkup: { inline_keyboard: keyboard } }
159
+ : {}),
160
+ };
161
+ }
162
+ export function createTelegramButtonReplyPlanner(store) {
163
+ return (markdown) => planTelegramButtonReply(markdown, { registerAction: store.register });
164
+ }
165
+ export function createTelegramButtonPromptTurn(options) {
166
+ const prompt = `${options.telegramPrefix ?? "[telegram]"} ${options.action.prompt}`;
167
+ return {
168
+ kind: "prompt",
169
+ chatId: options.chatId,
170
+ ...(options.target ? { target: options.target } : {}),
171
+ replyToMessageId: options.replyToMessageId,
172
+ sourceMessageIds: [options.replyToMessageId],
173
+ queueOrder: options.queueOrder,
174
+ queueLane: "priority",
175
+ laneOrder: options.queueOrder,
176
+ queuedAttachments: [],
177
+ content: [{ type: "text", text: prompt }],
178
+ historyText: options.action.prompt,
179
+ statusSummary: truncateTelegramQueueSummary(options.action.text || options.action.prompt),
180
+ };
181
+ }
182
+ export function markTelegramButtonSelected(replyMarkup, callbackData, selectedStyle = "primary") {
183
+ let matched = false;
184
+ const inlineKeyboard = replyMarkup.inline_keyboard.map((row) => row.map((button) => {
185
+ if (button.disabled || button.callback_data !== callbackData)
186
+ return { ...button };
187
+ matched = true;
188
+ return { ...button, style: selectedStyle };
189
+ }));
190
+ return matched ? { inline_keyboard: inlineKeyboard } : undefined;
191
+ }
192
+ export async function handleTelegramButtonCallbackQuery(query, ctx, deps) {
193
+ const action = deps.resolveAction(query.data);
194
+ if (!action) {
195
+ if (query.data?.startsWith(`${TELEGRAM_BUTTON_CALLBACK_PREFIX}:`)) {
196
+ await deps.answerCallbackQuery(query.id, "Button action expired.");
197
+ return true;
198
+ }
199
+ return false;
200
+ }
201
+ if (action.disabled) {
202
+ await deps.answerCallbackQuery(query.id, "Button action unavailable.");
203
+ return true;
204
+ }
205
+ const chatId = query.message?.chat?.id;
206
+ const messageId = query.message?.message_id;
207
+ if (typeof chatId !== "number" || typeof messageId !== "number") {
208
+ await deps.answerCallbackQuery(query.id, "Button action expired.");
209
+ return true;
210
+ }
211
+ if (deps.invokeBoundAction) {
212
+ try {
213
+ const viewMode = await deps.invokeBoundAction(query, action, ctx);
214
+ if (viewMode) {
215
+ if (viewMode === "new" && query.data && query.message?.reply_markup) {
216
+ const selectedMarkup = markTelegramButtonSelected(query.message.reply_markup, query.data, action.selectedStyle);
217
+ if (selectedMarkup && deps.editMessageReplyMarkup) {
218
+ try {
219
+ await deps.editMessageReplyMarkup(chatId, messageId, selectedMarkup);
220
+ }
221
+ catch {
222
+ // The action already succeeded; old-surface styling is best-effort.
223
+ }
224
+ }
225
+ }
226
+ await deps.answerCallbackQuery(query.id, "Done.");
227
+ return true;
228
+ }
229
+ }
230
+ catch (error) {
231
+ await deps.answerCallbackQuery(query.id, "Generative App action failed.");
232
+ throw error;
233
+ }
234
+ }
235
+ const enqueued = deps.enqueueButtonPrompt(query, action, ctx);
236
+ if (enqueued === false) {
237
+ await deps.answerCallbackQuery(query.id, "Already queued.");
238
+ return true;
239
+ }
240
+ const selectedMarkup = query.data && query.message?.reply_markup
241
+ ? markTelegramButtonSelected(query.message.reply_markup, query.data, action.selectedStyle)
242
+ : undefined;
243
+ if (selectedMarkup && deps.editMessageReplyMarkup) {
244
+ await deps.editMessageReplyMarkup(chatId, messageId, selectedMarkup);
245
+ }
246
+ await deps.answerCallbackQuery(query.id, "Queued.");
247
+ return true;
248
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Telegram outbound markup parsing helpers
3
+ * Zones: telegram outbound, assistant markup
4
+ * Owns top-level assistant action comment extraction, attribute parsing, and markup stripping shared by voice and outbound delivery
5
+ */
6
+ export interface TelegramTopLevelHtmlComment {
7
+ raw: string;
8
+ content: string;
9
+ start: number;
10
+ end: number;
11
+ }
12
+ export declare function collectTopLevelHtmlComments(markdown: string): {
13
+ comments: TelegramTopLevelHtmlComment[];
14
+ openCommentStart?: number;
15
+ };
16
+ export declare function replaceTelegramButtonFences(markdown: string, replace: (payload: string, closed: boolean) => string): string;
17
+ export declare function replaceTopLevelHtmlComments(markdown: string, replacer: (comment: TelegramTopLevelHtmlComment) => string): string;
18
+ export declare function findTopLevelOpenOrPartialHtmlCommentIndex(markdown: string): number;
19
+ export declare function parseTopLevelTelegramComment(comment: TelegramTopLevelHtmlComment, command: string): {
20
+ head: string;
21
+ body?: string;
22
+ } | undefined;
23
+ export declare function parseTelegramActionPayload(comment: TelegramTopLevelHtmlComment, command: string): Record<string, unknown> | undefined;
24
+ export declare function parseTelegramButtonPayloadRows(source: string): Record<string, unknown>[][] | undefined;
25
+ export declare function parseTelegramActionPayloadRows(comment: TelegramTopLevelHtmlComment, command: string): Record<string, unknown>[][] | undefined;
26
+ export declare function normalizeMarkdownAfterVoiceExtraction(markdown: string): string;
27
+ export declare function stripTelegramCommentMarkupForPreview(markdown: string): string;
28
+ export declare function stripTelegramCommentMarkupForDelivery(markdown: string): string;
29
+ export declare function stripTelegramVoiceMarkupForPreview(markdown: string): string;
30
+ export interface TelegramVoiceReplyItem {
31
+ text: string;
32
+ lang?: string;
33
+ rate?: string;
34
+ }
35
+ export interface TelegramVoiceReplyPlan {
36
+ markdown: string;
37
+ voiceText?: string;
38
+ voiceReplies?: TelegramVoiceReplyItem[];
39
+ lang?: string;
40
+ rate?: string;
41
+ }
42
+ export declare function planTelegramVoiceReply(markdown: string): TelegramVoiceReplyPlan;