@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,112 @@
1
+ /**
2
+ * Telegram status menu UI helpers
3
+ * Zones: telegram ui, status controls, menu composition
4
+ * Owns status-menu payloads, status callback handling, and status-menu message rendering
5
+ */
6
+ import { formatTelegramCommandEmojiPrefix } from "./commands.js";
7
+ import { getTelegramSectionMainMenuRows, } from "./sections.js";
8
+ import { formatStatusButtonLabel, } from "./menu-model.js";
9
+ import { getCanonicalModelId, } from "./model.js";
10
+ function isTelegramStatusMenuCallbackAction(data, action) {
11
+ return data === `menu:${action}` || data === `status:${action}`;
12
+ }
13
+ function applyTelegramMenuRenderPayload(state, payload) {
14
+ state.mode = payload.nextMode;
15
+ return payload;
16
+ }
17
+ async function editTelegramMenuMessage(state, payload, deps) {
18
+ const appliedPayload = applyTelegramMenuRenderPayload(state, payload);
19
+ await deps.editInteractiveMessage(state.chatId, state.messageId, appliedPayload.text, appliedPayload.mode, appliedPayload.replyMarkup);
20
+ }
21
+ function sendTelegramMenuMessage(state, payload, deps) {
22
+ const appliedPayload = applyTelegramMenuRenderPayload(state, payload);
23
+ return deps.sendInteractiveMessage(state.chatId, appliedPayload.text, appliedPayload.mode, appliedPayload.replyMarkup, state.threadId !== undefined
24
+ ? { target: { chatId: state.chatId, threadId: state.threadId } }
25
+ : undefined);
26
+ }
27
+ export async function openTelegramStatusMenu(deps) {
28
+ const state = await deps.getModelMenuState();
29
+ const messageId = await deps.sendStatusMenu(state, deps.buildStatusHtml(), deps.getActiveModel(), deps.getThinkingLevel(), deps.getQueueItemCount?.() ?? 0);
30
+ if (messageId === undefined)
31
+ return;
32
+ state.messageId = messageId;
33
+ state.mode = "status";
34
+ deps.storeModelMenuState(state);
35
+ }
36
+ export async function handleTelegramStatusMenuCallbackAction(callbackQueryId, data, activeModel, deps) {
37
+ if (isTelegramStatusMenuCallbackAction(data, "model")) {
38
+ await deps.updateModelMenuMessage();
39
+ await deps.answerCallbackQuery(callbackQueryId);
40
+ return true;
41
+ }
42
+ if (isTelegramStatusMenuCallbackAction(data, "settings")) {
43
+ if (!deps.updateSettingsMenuMessage)
44
+ return false;
45
+ await deps.updateSettingsMenuMessage();
46
+ await deps.answerCallbackQuery(callbackQueryId);
47
+ return true;
48
+ }
49
+ if (!isTelegramStatusMenuCallbackAction(data, "thinking"))
50
+ return false;
51
+ if (deps.isVoiceReplyActive?.()) {
52
+ await deps.answerCallbackQuery(callbackQueryId, "Thinking controls are disabled during voice replies.");
53
+ return true;
54
+ }
55
+ if (!activeModel?.reasoning) {
56
+ await deps.answerCallbackQuery(callbackQueryId, "This model has no reasoning controls.");
57
+ return true;
58
+ }
59
+ await deps.updateThinkingMenuMessage();
60
+ await deps.answerCallbackQuery(callbackQueryId);
61
+ return true;
62
+ }
63
+ export function buildStatusReplyMarkup(activeModel, currentThinkingLevel, queueItemCount = 0, sectionRegistry, isVoiceReplyActive) {
64
+ const rows = [];
65
+ rows.push([
66
+ {
67
+ text: formatStatusButtonLabel(`${formatTelegramCommandEmojiPrefix("model")}Model`, activeModel ? getCanonicalModelId(activeModel) : "unknown"),
68
+ callback_data: "menu:model",
69
+ },
70
+ ]);
71
+ if (activeModel?.reasoning && !isVoiceReplyActive) {
72
+ rows.push([
73
+ {
74
+ text: formatStatusButtonLabel(`${formatTelegramCommandEmojiPrefix("thinking")}Thinking`, currentThinkingLevel),
75
+ callback_data: "menu:thinking",
76
+ },
77
+ ]);
78
+ }
79
+ rows.push([
80
+ {
81
+ text: `${queueItemCount === 0 ? "⌛" : "⏳"} Queue: ${queueItemCount}`,
82
+ callback_data: "menu:queue",
83
+ },
84
+ ]);
85
+ if (sectionRegistry) {
86
+ const sectionRows = getTelegramSectionMainMenuRows(sectionRegistry);
87
+ for (const row of sectionRows) {
88
+ rows.push([row]);
89
+ }
90
+ }
91
+ rows.push([
92
+ {
93
+ text: "⚙️ Settings",
94
+ callback_data: "menu:settings",
95
+ },
96
+ ]);
97
+ return { inline_keyboard: rows };
98
+ }
99
+ export function buildTelegramStatusMenuRenderPayload(statusText, activeModel, currentThinkingLevel, queueItemCount = 0, sectionRegistry, isVoiceReplyActive) {
100
+ return {
101
+ nextMode: "status",
102
+ text: statusText,
103
+ mode: "html",
104
+ replyMarkup: buildStatusReplyMarkup(activeModel, currentThinkingLevel, queueItemCount, sectionRegistry, isVoiceReplyActive),
105
+ };
106
+ }
107
+ export async function updateTelegramStatusMessage(state, statusText, activeModel, currentThinkingLevel, deps, queueItemCount = 0, sectionRegistry, isVoiceReplyActive) {
108
+ await editTelegramMenuMessage(state, buildTelegramStatusMenuRenderPayload(statusText, activeModel, currentThinkingLevel, queueItemCount, sectionRegistry, isVoiceReplyActive), deps);
109
+ }
110
+ export function sendTelegramStatusMessage(state, statusText, activeModel, currentThinkingLevel, deps, queueItemCount = 0, sectionRegistry, isVoiceReplyActive) {
111
+ return sendTelegramMenuMessage(state, buildTelegramStatusMenuRenderPayload(statusText, activeModel, currentThinkingLevel, queueItemCount, sectionRegistry, isVoiceReplyActive), deps);
112
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Telegram thinking menu UI helpers
3
+ * Zones: telegram ui, thinking controls, menu composition
4
+ * Owns thinking-menu text, reply markup, callback handling, and thinking-menu message rendering
5
+ */
6
+ import type { TelegramMenuMessageRuntimeDeps, TelegramMenuRenderPayload, TelegramModelMenuState, TelegramReplyMarkup } from "./menu-model.ts";
7
+ import { type MenuModel, type ThinkingLevel } from "./model.ts";
8
+ export interface TelegramThinkingMenuCallbackDeps {
9
+ setThinkingLevel: (level: ThinkingLevel) => void;
10
+ getCurrentThinkingLevel: () => ThinkingLevel;
11
+ updateStatusMessage: () => Promise<void>;
12
+ answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
13
+ isVoiceReplyActive?: () => boolean;
14
+ }
15
+ export interface TelegramThinkingMenuOpenDeps<TModel extends MenuModel = MenuModel> extends TelegramMenuMessageRuntimeDeps {
16
+ getModelMenuState: () => Promise<TelegramModelMenuState<TModel>>;
17
+ getActiveModel: () => TModel | undefined;
18
+ getThinkingLevel: () => ThinkingLevel;
19
+ storeModelMenuState: (state: TelegramModelMenuState<TModel>) => void;
20
+ isVoiceReplyActive?: () => boolean;
21
+ }
22
+ export declare function handleTelegramThinkingMenuCallbackAction(callbackQueryId: string, data: string | undefined, activeModel: MenuModel | undefined, deps: TelegramThinkingMenuCallbackDeps): Promise<boolean>;
23
+ export declare function buildThinkingMenuText(): string;
24
+ export declare function buildThinkingMenuReplyMarkup(currentThinkingLevel: ThinkingLevel): TelegramReplyMarkup;
25
+ export declare function buildTelegramThinkingMenuRenderPayload(_activeModel: MenuModel | undefined, currentThinkingLevel: ThinkingLevel): TelegramMenuRenderPayload;
26
+ export declare function openTelegramThinkingMenu<TModel extends MenuModel = MenuModel>(deps: TelegramThinkingMenuOpenDeps<TModel>): Promise<void>;
27
+ export declare function updateTelegramThinkingMenuMessage(state: TelegramModelMenuState, activeModel: MenuModel | undefined, currentThinkingLevel: ThinkingLevel, deps: TelegramMenuMessageRuntimeDeps & {
28
+ isVoiceReplyActive?: () => boolean;
29
+ }): Promise<void>;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Telegram thinking menu UI helpers
3
+ * Zones: telegram ui, thinking controls, menu composition
4
+ * Owns thinking-menu text, reply markup, callback handling, and thinking-menu message rendering
5
+ */
6
+ import { isThinkingLevel, THINKING_LEVELS, } from "./model.js";
7
+ function parseTelegramThinkingMenuCallbackAction(data) {
8
+ if (!data?.startsWith("thinking:set:"))
9
+ return undefined;
10
+ return { kind: "thinking:set", level: data.slice("thinking:set:".length) };
11
+ }
12
+ function applyTelegramMenuRenderPayload(state, payload) {
13
+ state.mode = payload.nextMode;
14
+ return payload;
15
+ }
16
+ async function editTelegramMenuMessage(state, payload, deps) {
17
+ const appliedPayload = applyTelegramMenuRenderPayload(state, payload);
18
+ await deps.editInteractiveMessage(state.chatId, state.messageId, appliedPayload.text, appliedPayload.mode, appliedPayload.replyMarkup);
19
+ }
20
+ function sendTelegramMenuMessage(state, payload, deps) {
21
+ const appliedPayload = applyTelegramMenuRenderPayload(state, payload);
22
+ return deps.sendInteractiveMessage(state.chatId, appliedPayload.text, appliedPayload.mode, appliedPayload.replyMarkup, state.threadId !== undefined
23
+ ? { target: { chatId: state.chatId, threadId: state.threadId } }
24
+ : undefined);
25
+ }
26
+ export async function handleTelegramThinkingMenuCallbackAction(callbackQueryId, data, activeModel, deps) {
27
+ const action = parseTelegramThinkingMenuCallbackAction(data);
28
+ if (!action)
29
+ return false;
30
+ if (!isThinkingLevel(action.level)) {
31
+ await deps.answerCallbackQuery(callbackQueryId, "Invalid thinking level.");
32
+ return true;
33
+ }
34
+ if (deps.isVoiceReplyActive?.()) {
35
+ await deps.answerCallbackQuery(callbackQueryId, "Thinking controls are disabled during voice replies.");
36
+ return true;
37
+ }
38
+ if (!activeModel?.reasoning) {
39
+ await deps.answerCallbackQuery(callbackQueryId, "This model has no reasoning controls.");
40
+ return true;
41
+ }
42
+ deps.setThinkingLevel(action.level);
43
+ await deps.updateStatusMessage();
44
+ await deps.answerCallbackQuery(callbackQueryId, `Thinking: ${deps.getCurrentThinkingLevel()}`);
45
+ return true;
46
+ }
47
+ export function buildThinkingMenuText() {
48
+ return "<b>🧠 Choose a thinking level:</b>";
49
+ }
50
+ export function buildThinkingMenuReplyMarkup(currentThinkingLevel) {
51
+ const rows = [[{ text: "⬆️ Main menu", callback_data: "menu:back" }]];
52
+ const levelButtons = THINKING_LEVELS.map((level) => ({
53
+ text: level === currentThinkingLevel ? `🟢 ${level}` : level,
54
+ callback_data: `thinking:set:${level}`,
55
+ }));
56
+ rows.push(levelButtons.slice(0, 1), levelButtons.slice(1, 4), levelButtons.slice(4, 7));
57
+ return { inline_keyboard: rows };
58
+ }
59
+ export function buildTelegramThinkingMenuRenderPayload(_activeModel, currentThinkingLevel) {
60
+ return {
61
+ nextMode: "thinking",
62
+ text: buildThinkingMenuText(),
63
+ mode: "html",
64
+ replyMarkup: buildThinkingMenuReplyMarkup(currentThinkingLevel),
65
+ };
66
+ }
67
+ export async function openTelegramThinkingMenu(deps) {
68
+ if (deps.isVoiceReplyActive?.())
69
+ return;
70
+ const state = await deps.getModelMenuState();
71
+ const messageId = await sendTelegramMenuMessage(state, buildTelegramThinkingMenuRenderPayload(deps.getActiveModel(), deps.getThinkingLevel()), deps);
72
+ if (messageId === undefined)
73
+ return;
74
+ state.messageId = messageId;
75
+ state.mode = "thinking";
76
+ deps.storeModelMenuState(state);
77
+ }
78
+ export async function updateTelegramThinkingMenuMessage(state, activeModel, currentThinkingLevel, deps) {
79
+ if (deps.isVoiceReplyActive?.())
80
+ return;
81
+ await editTelegramMenuMessage(state, buildTelegramThinkingMenuRenderPayload(activeModel, currentThinkingLevel), deps);
82
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Telegram menu and inline-keyboard rendering helpers
3
+ * Zones: telegram ui, controls, status menu
4
+ * Owns app-menu/status state, inline UI text, and callback composition while model/thinking/queue menu details live in dedicated domains
5
+ */
6
+ import { type TelegramMenuMessageRuntimeDeps, type TelegramModelMenuState, type TelegramModelMenuStateBuilderContext, type TelegramModelMenuStateBuilderDeps, type TelegramReplyMarkup } from "./menu-model.ts";
7
+ import { type MenuModel, type ScopedTelegramModel, type ThinkingLevel } from "./model.ts";
8
+ import type { TelegramInputRichMessage } from "./telegram-api.ts";
9
+ import { type TelegramSectionRegistry } from "./sections.ts";
10
+ export { applyTelegramModelPageSelection, applyTelegramModelScopeSelection, buildModelMenuReplyMarkup, buildModelPageMenuReplyMarkup, buildTelegramModelCallbackPlan, buildTelegramModelMenuRenderPayload, buildTelegramModelMenuState, buildTelegramModelMenuStateRuntime, buildTelegramModelPageMenuRenderPayload, createTelegramModelMenuRuntime, createTelegramModelMenuStateBuilder, formatScopedModelButtonText, getModelMenuItems, getStoredTelegramModelMenuState, getTelegramModelMenuPage, getTelegramModelSelection, handleTelegramModelMenuCallbackAction, MODEL_MENU_TITLE, MODEL_PAGE_MENU_TITLE, openTelegramModelMenu, pruneStoredTelegramModelMenus, resolveCachedTelegramModelMenuInputs, sendTelegramModelMenuMessage, storeTelegramModelMenuState, TELEGRAM_MODEL_PAGE_SIZE, updateTelegramModelMenuMessage, } from "./menu-model.ts";
11
+ export type { BuildTelegramModelCallbackPlanParams, BuildTelegramModelMenuStateParams, CachedTelegramModelMenuInputs, MenuSettingsManager, StoredTelegramModelMenuState, TelegramMenuMessageRuntimeDeps, TelegramMenuMutationResult, TelegramMenuRenderPayload, TelegramMenuSelectionResult, TelegramModelCallbackPlan, TelegramModelMenuCallbackDeps, TelegramModelMenuInputCacheDeps, TelegramModelMenuOpenDeps, TelegramModelMenuPage, TelegramModelMenuRuntime, TelegramModelMenuRuntimeContext, TelegramModelMenuRuntimeOptions, TelegramModelMenuState, TelegramModelMenuStateBuilderContext, TelegramModelMenuStateBuilderDeps, TelegramModelMenuStoreOptions, TelegramModelScope, TelegramReplyMarkup, } from "./menu-model.ts";
12
+ export { buildStatusReplyMarkup, buildTelegramStatusMenuRenderPayload, handleTelegramStatusMenuCallbackAction, openTelegramStatusMenu, sendTelegramStatusMessage, updateTelegramStatusMessage, } from "./menu-status.ts";
13
+ export type { TelegramStatusMenuCallbackDeps, TelegramStatusMenuOpenDeps, } from "./menu-status.ts";
14
+ export { buildTelegramThinkingMenuRenderPayload, buildThinkingMenuReplyMarkup, buildThinkingMenuText, handleTelegramThinkingMenuCallbackAction, openTelegramThinkingMenu, updateTelegramThinkingMenuMessage, } from "./menu-thinking.ts";
15
+ export type { TelegramThinkingMenuCallbackDeps, TelegramThinkingMenuOpenDeps, } from "./menu-thinking.ts";
16
+ export interface TelegramMenuCallbackEntryDeps {
17
+ handleStatusAction: () => Promise<boolean>;
18
+ handleThinkingAction: () => Promise<boolean>;
19
+ handleModelAction: () => Promise<boolean>;
20
+ answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
21
+ }
22
+ export interface MenuCallbackQuery {
23
+ id: string;
24
+ data?: string;
25
+ message?: {
26
+ message_id?: number;
27
+ message_thread_id?: number;
28
+ chat?: {
29
+ id?: number;
30
+ };
31
+ };
32
+ }
33
+ export interface StoredTelegramMenuCallbackDeps<TModel extends MenuModel = MenuModel> {
34
+ getStoredModelMenuState: (messageId: number | undefined, chatId?: number) => TelegramModelMenuState<TModel> | undefined;
35
+ handleStatusAction: (state: TelegramModelMenuState<TModel>) => Promise<boolean>;
36
+ handleThinkingAction: (state: TelegramModelMenuState<TModel>) => Promise<boolean>;
37
+ handleModelAction: (state: TelegramModelMenuState<TModel>) => Promise<boolean>;
38
+ answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
39
+ }
40
+ export interface TelegramMenuCallbackRuntimeDeps<TContext, TModel extends MenuModel = MenuModel> {
41
+ getStoredModelMenuState: (messageId: number | undefined, chatId?: number) => TelegramModelMenuState<TModel> | undefined;
42
+ getActiveModel: (ctx: TContext) => TModel | undefined;
43
+ getThinkingLevel: () => ThinkingLevel;
44
+ setThinkingLevel: (level: ThinkingLevel) => void;
45
+ updateStatus: (ctx: TContext) => void;
46
+ updateModelMenuMessage: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
47
+ updateThinkingMenuMessage: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
48
+ updateStatusMessage: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
49
+ updateSettingsMenuMessage?: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
50
+ answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
51
+ isIdle: (ctx: TContext) => boolean;
52
+ hasActiveTelegramTurn: () => boolean;
53
+ hasAbortHandler: () => boolean;
54
+ hasActiveToolExecutions: () => boolean;
55
+ persistScopedModelPatterns?: (patterns: string[], ctx: TContext) => Promise<void>;
56
+ setModel: (model: TModel) => Promise<boolean>;
57
+ setCurrentModel: (model: TModel, ctx: TContext) => void;
58
+ stagePendingModelSwitch: (selection: ScopedTelegramModel<TModel>, ctx: TContext) => void;
59
+ restartInterruptedTelegramTurn: (selection: ScopedTelegramModel<TModel>, ctx: TContext) => Promise<boolean> | boolean;
60
+ sectionRegistry?: TelegramSectionRegistry;
61
+ editInteractiveMessage?: (chatId: number, messageId: number, text: string, mode: "markdown" | "html" | "plain", replyMarkup: TelegramReplyMarkup) => Promise<void>;
62
+ sendInteractiveMessage?: (chatId: number, text: string, mode: "markdown" | "html" | "plain", replyMarkup: TelegramReplyMarkup, options?: {
63
+ target?: {
64
+ chatId: number;
65
+ threadId?: number;
66
+ };
67
+ }) => Promise<number | undefined>;
68
+ sendSectionRichMessage?: (chatId: number, message: TelegramInputRichMessage, options?: {
69
+ target?: {
70
+ chatId: number;
71
+ threadId?: number;
72
+ };
73
+ }) => Promise<number | undefined>;
74
+ enqueueSectionPrompt?: (prompt: string, ctx: TContext, target?: {
75
+ chatId: number;
76
+ threadId?: number;
77
+ }, source?: unknown) => Promise<void>;
78
+ deleteMessage?: (chatId: number, messageId: number) => Promise<void>;
79
+ isVoiceReplyActive?: () => boolean;
80
+ }
81
+ export interface TelegramMenuActionRuntimeDeps<TContext, TModel extends MenuModel = MenuModel> extends TelegramMenuMessageRuntimeDeps {
82
+ getModelMenuState: (chatId: number, ctx: TContext, threadId?: number) => Promise<TelegramModelMenuState<TModel>>;
83
+ getActiveModel: (ctx: TContext) => TModel | undefined;
84
+ getThinkingLevel: () => ThinkingLevel;
85
+ getQueueItemCount?: () => number;
86
+ buildStatusHtml: (ctx: TContext) => string;
87
+ storeModelMenuState: (state: TelegramModelMenuState<TModel>) => void;
88
+ isIdle: (ctx: TContext) => boolean;
89
+ canOfferInFlightModelSwitch: (ctx: TContext) => boolean;
90
+ sendTextReply: (chatId: number, replyToMessageId: number, text: string, options?: {
91
+ target?: {
92
+ chatId: number;
93
+ threadId?: number;
94
+ };
95
+ parseMode?: "HTML";
96
+ }) => Promise<unknown>;
97
+ sectionRegistry?: TelegramSectionRegistry;
98
+ isVoiceReplyActive?: () => boolean;
99
+ }
100
+ export interface TelegramMenuActionRuntime<TContext, TModel extends MenuModel = MenuModel> {
101
+ updateModelMenuMessage: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
102
+ updateThinkingMenuMessage: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
103
+ updateStatusMessage: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
104
+ sendStatusMessage: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number) => Promise<void>;
105
+ openModelMenu: (chatId: number, replyToMessageId: number, ctx: TContext, threadId?: number) => Promise<void>;
106
+ openThinkingMenu: (chatId: number, replyToMessageId: number, ctx: TContext) => Promise<void>;
107
+ }
108
+ export type TelegramMenuCallbackAction = {
109
+ kind: "ignore";
110
+ } | {
111
+ kind: "status";
112
+ action: "model" | "thinking" | "queue" | "settings";
113
+ } | {
114
+ kind: "thinking:set";
115
+ level: string;
116
+ } | {
117
+ kind: "model";
118
+ action: "noop" | "scope" | "page" | "pages" | "open" | "pick" | "pick-selected" | "scope-enable" | "scope-disable" | "scope-toggle";
119
+ value?: string;
120
+ };
121
+ export declare function parseTelegramMenuCallbackAction(data: string | undefined): TelegramMenuCallbackAction;
122
+ export declare function handleTelegramMenuCallbackEntry(callbackQueryId: string, data: string | undefined, state: TelegramModelMenuState | undefined, deps: TelegramMenuCallbackEntryDeps): Promise<void>;
123
+ export declare function handleStoredTelegramMenuCallback<TModel extends MenuModel = MenuModel>(query: MenuCallbackQuery, deps: StoredTelegramMenuCallbackDeps<TModel>): Promise<void>;
124
+ export interface TelegramMenuCallbackRuntimeAdapterDeps<TContext, TModel extends MenuModel = MenuModel> {
125
+ getStoredModelMenuState: (messageId: number | undefined, chatId?: number) => TelegramModelMenuState<TModel> | undefined;
126
+ getActiveModel: (ctx: TContext) => TModel | undefined;
127
+ getThinkingLevel: () => ThinkingLevel;
128
+ setThinkingLevel: (level: ThinkingLevel) => void;
129
+ updateStatus: (ctx: TContext, error?: string) => void;
130
+ updateModelMenuMessage: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
131
+ updateThinkingMenuMessage: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
132
+ updateStatusMessage: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
133
+ updateSettingsMenuMessage?: (state: TelegramModelMenuState<TModel>, ctx: TContext) => Promise<void>;
134
+ answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
135
+ isIdle: (ctx: TContext) => boolean;
136
+ hasActiveTelegramTurn: () => boolean;
137
+ hasAbortHandler: () => boolean;
138
+ getActiveToolExecutions: () => number;
139
+ persistScopedModelPatterns?: (patterns: string[], ctx: TContext) => Promise<void>;
140
+ setModel: (model: TModel) => Promise<boolean>;
141
+ setCurrentModel: (model: TModel, ctx: TContext) => void;
142
+ stagePendingModelSwitch: (selection: ScopedTelegramModel<TModel>, ctx: TContext) => void;
143
+ restartInterruptedTelegramTurn: (selection: ScopedTelegramModel<TModel>, ctx: TContext) => Promise<boolean> | boolean;
144
+ sectionRegistry?: TelegramSectionRegistry;
145
+ editInteractiveMessage?: (chatId: number, messageId: number, text: string, mode: "markdown" | "html" | "plain", replyMarkup: TelegramReplyMarkup) => Promise<void>;
146
+ sendInteractiveMessage?: (chatId: number, text: string, mode: "markdown" | "html" | "plain", replyMarkup: TelegramReplyMarkup, options?: {
147
+ target?: {
148
+ chatId: number;
149
+ threadId?: number;
150
+ };
151
+ }) => Promise<number | undefined>;
152
+ sendSectionRichMessage?: (chatId: number, message: TelegramInputRichMessage, options?: {
153
+ target?: {
154
+ chatId: number;
155
+ threadId?: number;
156
+ };
157
+ }) => Promise<number | undefined>;
158
+ enqueueSectionPrompt?: (prompt: string, ctx: TContext, target?: {
159
+ chatId: number;
160
+ threadId?: number;
161
+ }, source?: unknown) => Promise<void>;
162
+ deleteMessage?: (chatId: number, messageId: number) => Promise<void>;
163
+ }
164
+ export declare function createTelegramMenuCallbackHandler<TQuery extends MenuCallbackQuery, TContext, TModel extends MenuModel = MenuModel>(deps: TelegramMenuCallbackRuntimeDeps<TContext, TModel>): (query: TQuery, ctx: TContext) => Promise<void>;
165
+ export declare function createTelegramMenuCallbackHandlerForContext<TQuery extends MenuCallbackQuery, TContext, TModel extends MenuModel = MenuModel>(deps: TelegramMenuCallbackRuntimeAdapterDeps<TContext, TModel>): (query: TQuery, ctx: TContext) => Promise<void>;
166
+ export declare function handleTelegramMenuCallbackRuntime<TQuery extends MenuCallbackQuery, TContext, TModel extends MenuModel = MenuModel>(query: TQuery, ctx: TContext, deps: TelegramMenuCallbackRuntimeDeps<TContext, TModel>): Promise<void>;
167
+ export interface TelegramMenuActionRuntimeWithStateBuilderDeps<TModel extends MenuModel = MenuModel, TContext extends TelegramModelMenuStateBuilderContext<TModel> = TelegramModelMenuStateBuilderContext<TModel>> extends Omit<TelegramMenuActionRuntimeDeps<TContext, TModel>, "getModelMenuState">, TelegramModelMenuStateBuilderDeps<TModel, TContext> {
168
+ isVoiceReplyActive?: () => boolean;
169
+ }
170
+ export declare function createTelegramMenuActionRuntimeWithStateBuilder<TModel extends MenuModel = MenuModel, TContext extends TelegramModelMenuStateBuilderContext<TModel> = TelegramModelMenuStateBuilderContext<TModel>>(deps: TelegramMenuActionRuntimeWithStateBuilderDeps<TModel, TContext>): TelegramMenuActionRuntime<TContext, TModel>;
171
+ export declare function createTelegramMenuActionRuntime<TContext, TModel extends MenuModel = MenuModel>(deps: TelegramMenuActionRuntimeDeps<TContext, TModel>): TelegramMenuActionRuntime<TContext, TModel>;