@llblab/pi-telegram 0.46.0 → 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 (199) hide show
  1. package/BACKLOG.md +0 -1
  2. package/CHANGELOG.md +8 -0
  3. package/README.md +2 -2
  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 +4 -2
  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 +7 -3
  183. package/lib/bus-leader.ts +44 -19
  184. package/lib/bus.ts +4 -1
  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 +19 -0
  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/telegram-api.ts +12 -1
  193. package/lib/thread-display.ts +96 -18
  194. package/package.json +56 -13
  195. package/scripts/build-dist.mjs +44 -0
  196. package/scripts/measure-bus.mjs +8 -1
  197. package/scripts/measure-workspace.mjs +8 -1
  198. package/skills/generative-apps/SKILL.md +1 -1
  199. package/skills/telegram-bridge/SKILL.md +1 -1
@@ -43,6 +43,7 @@ import {
43
43
  type TelegramBusSocketPathSource,
44
44
  TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME,
45
45
  TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
46
+ TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
46
47
  } from "./bus.ts";
47
48
  import type { TelegramConfigStore, TelegramThreadDisplayMode } from "./config.ts";
48
49
  import {
@@ -1914,9 +1915,12 @@ export function createTelegramBusFollowerRegistrationRuntime<
1914
1915
  if (!socketPath || !generation || !deps.registrationState?.isRegistered()) {
1915
1916
  throw new Error("Telegram follower is not registered with the leader.");
1916
1917
  }
1917
- if (!hasTelegramBusCapability(deps.protocolIdentity, TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE) ||
1918
- !hasTelegramBusCapability(deps.registrationState.getLeaderProtocol(), TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE)) {
1919
- throw new Error("The Telegram peers do not support Thread display settings. Update or restart both instances.");
1918
+ const requiredCapability = mode === "directory-snake" || mode === "directory-title"
1919
+ ? TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT
1920
+ : TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE;
1921
+ if (!hasTelegramBusCapability(deps.protocolIdentity, requiredCapability) ||
1922
+ !hasTelegramBusCapability(deps.registrationState.getLeaderProtocol(), requiredCapability)) {
1923
+ throw new Error("The Telegram peers do not support this Thread display setting. Update or restart both instances.");
1920
1924
  }
1921
1925
  const requestId = deps.createRequestId();
1922
1926
  const response = await sendTelegramBusLocalEnvelope({
package/lib/bus-leader.ts CHANGED
@@ -9,6 +9,7 @@ import * as Sync from "./sync.ts";
9
9
  import {
10
10
  createTelegramThreadDisplayReconciler,
11
11
  resolveTelegramInitialWorkspaceDisplayName,
12
+ resolveTelegramLiveWorkspaceBindingKeys,
12
13
  } from "./thread-display.ts";
13
14
  import type { TelegramThreadDisplayMode } from "./config.ts";
14
15
  import * as ThreadReconciler from "./thread-reconciler.ts";
@@ -40,6 +41,7 @@ import {
40
41
  TELEGRAM_BUS_CAPABILITY_WORKSPACE_FOLLOWER_AUTO_CONNECT,
41
42
  TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME,
42
43
  TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
44
+ TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
43
45
  } from "./bus.ts";
44
46
  import { getTelegramBusTransportRetryPolicy } from "./bus-transport.ts";
45
47
  import type { TelegramQueueHandoffPayload } from "./queue.ts";
@@ -309,6 +311,13 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
309
311
  });
310
312
  },
311
313
  }).run;
314
+ const captureLiveBindingKeys = (
315
+ bindings: readonly Threads.TelegramWorkspaceThreadBinding[],
316
+ ): ReadonlySet<string> => resolveTelegramLiveWorkspaceBindingKeys(
317
+ bindings,
318
+ deps.topicTargetStore.getActiveByInstanceId(deps.instanceId)?.target,
319
+ deps.runtime.followerRegistry.list(),
320
+ );
312
321
  const provisionerPorts = {
313
322
  getAllowedUserId: deps.getAllowedUserId,
314
323
  topicTargetStore: deps.topicTargetStore,
@@ -327,6 +336,9 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
327
336
  bindings: deps.topicTargetStore.listWorkspaceBindings(),
328
337
  binding,
329
338
  mode: deps.getThreadDisplayMode!(),
339
+ liveBindingKeys: captureLiveBindingKeys(
340
+ deps.topicTargetStore.listWorkspaceBindings(),
341
+ ),
330
342
  });
331
343
  },
332
344
  }
@@ -339,6 +351,7 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
339
351
  getMode: deps.getThreadDisplayMode,
340
352
  getProfileKey: () => deps.getTelegramProfile?.() ?? "default",
341
353
  getLeaderEpoch: () => deps.getCurrentLeaderEpoch?.(),
354
+ captureLiveBindingKeys,
342
355
  captureBindingAuthority(binding) {
343
356
  const matches = (target: TelegramTarget | undefined) =>
344
357
  target?.chatId === binding.target.chatId && target?.threadId === binding.target.threadId;
@@ -392,8 +405,11 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
392
405
  throw new Error("Telegram Thread display setting requires current leader authority.");
393
406
  }
394
407
  const assertDisplayPeers = () => {
408
+ const requiredCapability = mode === "directory-snake" || mode === "directory-title"
409
+ ? TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT
410
+ : TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE;
395
411
  if (mode !== "names" && deps.runtime.followerRegistry.list().some((follower) =>
396
- !hasTelegramBusCapability(follower.protocol, TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE),
412
+ !hasTelegramBusCapability(follower.protocol, requiredCapability),
397
413
  )) throw new Error("Update or restart all connected followers before changing Thread display mode.");
398
414
  };
399
415
  assertDisplayPeers();
@@ -597,14 +613,17 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
597
613
  );
598
614
  return binding?.displayTitle ?? binding?.threadName;
599
615
  },
600
- onFollowerDisconnected: (follower) => runWorkspaceOperation(
601
- {
602
- operationId: createTelegramWorkspaceAdmissionOperationId(),
603
- operationKind: "workspace.disconnect-follower",
604
- scopes: [{ kind: "profile" }],
605
- },
606
- () => disconnectFollower(follower),
607
- ),
616
+ onFollowerDisconnected: async (follower) => {
617
+ await runWorkspaceOperation(
618
+ {
619
+ operationId: createTelegramWorkspaceAdmissionOperationId(),
620
+ operationKind: "workspace.disconnect-follower",
621
+ scopes: [{ kind: "profile" }],
622
+ },
623
+ () => disconnectFollower(follower),
624
+ );
625
+ scheduleDisplay();
626
+ },
608
627
  async renameFollowerThread(follower, threadName) {
609
628
  return runWorkspaceOperation({
610
629
  operationId: createTelegramWorkspaceAdmissionOperationId(),
@@ -692,14 +711,17 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
692
711
  });
693
712
  },
694
713
  ),
695
- onFollowerConfirmedDead: (follower) => runWorkspaceOperation(
696
- {
697
- operationId: createTelegramWorkspaceAdmissionOperationId(),
698
- operationKind: "workspace.cleanup-dead-follower",
699
- scopes: [{ kind: "profile" }],
700
- },
701
- () => cleanupConfirmedDeadFollower(follower),
702
- ),
714
+ onFollowerConfirmedDead: async (follower) => {
715
+ await runWorkspaceOperation(
716
+ {
717
+ operationId: createTelegramWorkspaceAdmissionOperationId(),
718
+ operationKind: "workspace.cleanup-dead-follower",
719
+ scopes: [{ kind: "profile" }],
720
+ },
721
+ () => cleanupConfirmedDeadFollower(follower),
722
+ );
723
+ scheduleDisplay();
724
+ },
703
725
  provisionFollowerTarget: (registration, options) => runWorkspaceOperation(
704
726
  {
705
727
  operationId: `follower-provision:${registration.instanceId}:${registration.registrationGeneration}`,
@@ -2243,9 +2265,12 @@ export function createTelegramBusLeaderEnvelopeHandler(deps: {
2243
2265
  const current = () => epoch !== undefined && deps.getCurrentLeaderEpoch?.() === epoch &&
2244
2266
  deps.followerRegistry.get(envelope.instanceId)?.registrationGeneration === envelope.registrationGeneration;
2245
2267
  const follower = deps.followerRegistry.get(envelope.instanceId);
2268
+ const requiredCapability = envelope.mode === "directory-snake" || envelope.mode === "directory-title"
2269
+ ? TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT
2270
+ : TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE;
2246
2271
  if (!current() || !follower?.registrationGeneration || !deps.applyThreadDisplayMode ||
2247
- !hasTelegramBusCapability(deps.protocolIdentity, TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE) ||
2248
- !hasTelegramBusCapability(follower.protocol, TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE)) {
2272
+ !hasTelegramBusCapability(deps.protocolIdentity, requiredCapability) ||
2273
+ !hasTelegramBusCapability(follower.protocol, requiredCapability)) {
2249
2274
  return { kind: "bus.ack", requestId: envelope.requestId, ok: false,
2250
2275
  message: "Thread display settings require current registration and compatible leader authority." };
2251
2276
  }
package/lib/bus.ts CHANGED
@@ -230,6 +230,8 @@ export const TELEGRAM_BUS_CAPABILITY_INPUT_CUSTODY_REFERENCE =
230
230
  export const TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME =
231
231
  "workspace-thread-rename-v1" as const;
232
232
  export const TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE = "thread-display-mode-v1" as const;
233
+ export const TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT =
234
+ "directory-display-format-v1" as const;
233
235
  export const TELEGRAM_BUS_CAPABILITY_WORKSPACE_FOLLOWER_AUTO_CONNECT =
234
236
  "workspace-follower-auto-connect-v1" as const;
235
237
 
@@ -1027,7 +1029,8 @@ export function parseTelegramBusEnvelope(
1027
1029
  case "follower.setThreadDisplayMode":
1028
1030
  if (typeof value.instanceId === "string" &&
1029
1031
  typeof value.registrationGeneration === "string" &&
1030
- (value.mode === "letters" || value.mode === "names" || value.mode === "directories")) {
1032
+ (value.mode === "letters" || value.mode === "names" || value.mode === "directories" ||
1033
+ value.mode === "directory-snake" || value.mode === "directory-title")) {
1031
1034
  envelope = { kind, requestId, instanceId: value.instanceId,
1032
1035
  registrationGeneration: value.registrationGeneration, mode: value.mode };
1033
1036
  }
package/lib/commands.ts CHANGED
@@ -1205,7 +1205,7 @@ export const TELEGRAM_APP_MENU_INTRO_HTML = [
1205
1205
  "<b>Pi Telegram</b>",
1206
1206
  "",
1207
1207
  `${formatTelegramCommandEmojiPrefix("start")}/start — Open menu / Pair bridge`,
1208
- `${formatTelegramCommandEmojiPrefix("name")}/name Name — Rename this thread`,
1208
+ `${formatTelegramCommandEmojiPrefix("name")}/name — Rename this thread`,
1209
1209
  `${formatTelegramCommandEmojiPrefix("compact")}/compact — Compact current session`,
1210
1210
  `${formatTelegramCommandEmojiPrefix("next")}/next — Force next turn`,
1211
1211
  `${formatTelegramCommandEmojiPrefix("continue")}/continue — Queue continue prompt`,
@@ -1246,7 +1246,7 @@ function buildTelegramAppMenuIntroHtml(): string {
1246
1246
  "<b>Pi Telegram</b>",
1247
1247
  "",
1248
1248
  `${formatTelegramCommandEmojiPrefix("start")}/start — Open menu / Pair bridge`,
1249
- `${formatTelegramCommandEmojiPrefix("name")}/name Name — Rename this thread`,
1249
+ `${formatTelegramCommandEmojiPrefix("name")}/name — Rename this thread`,
1250
1250
  `${formatTelegramCommandEmojiPrefix("compact")}/compact — Compact current session`,
1251
1251
  ...extensionLines,
1252
1252
  `${formatTelegramCommandEmojiPrefix("next")}/next — Force next turn`,
package/lib/config.ts CHANGED
@@ -136,16 +136,23 @@ export interface ResolvedTelegramTimeConfig {
136
136
  timezone: string;
137
137
  }
138
138
 
139
- export type TelegramThreadDisplayMode = "letters" | "names" | "directories";
139
+ export type TelegramThreadDisplayMode =
140
+ | "letters"
141
+ | "names"
142
+ | "directories"
143
+ | "directory-snake"
144
+ | "directory-title";
145
+
146
+ const TELEGRAM_THREAD_DISPLAY_MODES: readonly TelegramThreadDisplayMode[] = [
147
+ "letters", "names", "directories", "directory-snake", "directory-title",
148
+ ];
140
149
 
141
150
  export function resolveTelegramThreadDisplayMode(
142
151
  config: Pick<TelegramConfig, "threadDisplayMode">,
143
152
  ): TelegramThreadDisplayMode {
144
- return config.threadDisplayMode === "names"
145
- ? "names"
146
- : config.threadDisplayMode === "directories"
147
- ? "directories"
148
- : "letters";
153
+ return TELEGRAM_THREAD_DISPLAY_MODES.includes(config.threadDisplayMode as TelegramThreadDisplayMode)
154
+ ? config.threadDisplayMode as TelegramThreadDisplayMode
155
+ : "letters";
149
156
  }
150
157
 
151
158
  export async function setTelegramThreadDisplayMode(
@@ -153,7 +160,7 @@ export async function setTelegramThreadDisplayMode(
153
160
  mode: TelegramThreadDisplayMode,
154
161
  isCurrent: () => boolean,
155
162
  ): Promise<void> {
156
- if (!["letters", "names", "directories"].includes(mode)) {
163
+ if (!TELEGRAM_THREAD_DISPLAY_MODES.includes(mode)) {
157
164
  throw new Error("Invalid Telegram Thread display mode.");
158
165
  }
159
166
  const profile = store.getActiveProfileName();
package/lib/delivery.ts CHANGED
@@ -18,7 +18,10 @@ import {
18
18
  type TelegramTarget,
19
19
  } from "./target.ts";
20
20
  import {
21
+ getTelegramApiRetryAfterMs,
22
+ isRetryableTelegramApiError,
21
23
  isTelegramApiCommitUnknownError,
24
+ isTelegramMessageUnavailableError,
22
25
  type TelegramBridgeApiRuntime,
23
26
  } from "./telegram-api.ts";
24
27
 
@@ -60,6 +63,9 @@ export type TelegramDeliveryFailureReason =
60
63
  | "stale-handle"
61
64
  | "invalid-view"
62
65
  | "commit-unknown"
66
+ | "message-unavailable"
67
+ | "rate-limited"
68
+ | "transport-retryable"
63
69
  | "transport-failed";
64
70
 
65
71
  export type TelegramDeliveryResult<T> =
@@ -68,6 +74,8 @@ export type TelegramDeliveryResult<T> =
68
74
  ok: false;
69
75
  reason: TelegramDeliveryFailureReason;
70
76
  message: string;
77
+ /** Exact Telegram flood-control delay when supplied by the API. */
78
+ retryAfterMs?: number;
71
79
  /** Successfully materialized state that callers may edit or delete to recover. */
72
80
  partial?: T;
73
81
  };
@@ -246,10 +254,26 @@ function failure<T>(
246
254
  reason: TelegramDeliveryFailureReason,
247
255
  message: string,
248
256
  partial?: T,
257
+ retryAfterMs?: number,
249
258
  ): TelegramDeliveryResult<T> {
259
+ const retry = retryAfterMs === undefined ? {} : { retryAfterMs };
250
260
  return partial === undefined
251
- ? { ok: false, reason, message }
252
- : { ok: false, reason, message, partial };
261
+ ? { ok: false, reason, message, ...retry }
262
+ : { ok: false, reason, message, partial, ...retry };
263
+ }
264
+
265
+ export function classifyTelegramDeliveryTransportError(error: unknown): {
266
+ reason: Extract<TelegramDeliveryFailureReason,
267
+ "commit-unknown" | "message-unavailable" | "rate-limited" |
268
+ "transport-retryable" | "transport-failed">;
269
+ retryAfterMs?: number;
270
+ } {
271
+ if (isTelegramApiCommitUnknownError(error)) return { reason: "commit-unknown" };
272
+ if (isTelegramMessageUnavailableError(error)) return { reason: "message-unavailable" };
273
+ const retryAfterMs = getTelegramApiRetryAfterMs(error);
274
+ if (retryAfterMs !== undefined) return { reason: "rate-limited", retryAfterMs };
275
+ if (isRetryableTelegramApiError(error)) return { reason: "transport-retryable" };
276
+ return { reason: "transport-failed" };
253
277
  }
254
278
 
255
279
  /** @internal */
@@ -479,14 +503,14 @@ export function createTelegramDeliveryRuntime(
479
503
  if (error instanceof TelegramDeliveryTransportGenerationError) {
480
504
  return inactive();
481
505
  }
506
+ const classified = classifyTelegramDeliveryTransportError(error);
482
507
  return failure(
483
- isTelegramApiCommitUnknownError(error)
484
- ? "commit-unknown"
485
- : "transport-failed",
486
- isTelegramApiCommitUnknownError(error)
508
+ classified.reason,
509
+ classified.reason === "commit-unknown"
487
510
  ? `Telegram delivery ${operation} may have committed before transport failed.`
488
511
  : `Telegram delivery ${operation} failed.`,
489
512
  partial,
513
+ classified.retryAfterMs,
490
514
  );
491
515
  };
492
516
  const createHandle = (
@@ -837,6 +861,14 @@ export function clearTelegramDeliveryRuntime(): void {
837
861
  registry.runtime = undefined;
838
862
  }
839
863
 
864
+ /** @internal */
865
+ export function isTelegramDeliveryHandleCurrent(
866
+ handle: TelegramDeliveryHandle,
867
+ ): boolean {
868
+ const runtime = getTelegramDeliveryRuntimeRegistry().runtime;
869
+ return runtime !== undefined && runtime.generation === handle.generation;
870
+ }
871
+
840
872
  export async function sendTelegramView(
841
873
  view: TelegramDeliveryView,
842
874
  options: SendTelegramViewOptions,
package/lib/extension.ts CHANGED
@@ -64,6 +64,7 @@ const telegramBusProtocolIdentity =
64
64
  Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_FOLLOWER_AUTO_CONNECT,
65
65
  Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME,
66
66
  Bus.TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
67
+ Bus.TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
67
68
  ]);
68
69
 
69
70
  // --- Extension Runtime ---
@@ -672,11 +673,15 @@ export default function (pi: Pi.ExtensionAPI) {
672
673
  getHandlers: configStore.getOutboundHandlers,
673
674
  recordRuntimeEvent,
674
675
  });
676
+ const generativeAppLiveSurfaceBinding =
677
+ Bindings.createTelegramGenerativeAppLiveSurfaceBinding();
675
678
  const invokeGenerativeAppBoundButtonAction =
676
679
  Bindings.createTelegramGenerativeAppBoundButtonActionInvoker({
677
680
  agentDir: Paths.resolveAgentDir(),
678
681
  assertExecutionCurrent: Updates.assertTelegramUpdateExecutionCurrent,
679
682
  getExecutionFence: Updates.getTelegramUpdateExecutionFence,
683
+ getActiveProfileName: configStore.getActiveProfileName,
684
+ getLiveSurfaceRuntime: generativeAppLiveSurfaceBinding.get,
680
685
  planOutput: planGenerativeAppOutput,
681
686
  sendMarkdownReply,
682
687
  editInteractiveMessage,
@@ -861,6 +866,18 @@ export default function (pi: Pi.ExtensionAPI) {
861
866
  return threadStore.getBotState().threadMode === "enabled"
862
867
  ? Config.resolveTelegramThreadDisplayMode(configStore.get()) : undefined;
863
868
  },
869
+ getThreadDisplayPreview(mode) {
870
+ const bindings = threadStore.listWorkspaceBindings();
871
+ return [...ThreadDisplay.resolveTelegramWorkspaceDisplayNames(
872
+ bindings,
873
+ mode,
874
+ ThreadDisplay.resolveTelegramLiveWorkspaceBindingKeys(
875
+ bindings,
876
+ threadStore.getActiveByInstanceId(telegramInstanceId)?.target,
877
+ telegramBusFollowerRegistry.list(),
878
+ ),
879
+ ).values()];
880
+ },
864
881
  async setThreadDisplayMode(mode) {
865
882
  try {
866
883
  await ThreadDisplay.applyTelegramThreadDisplaySetting(mode, {
@@ -1803,6 +1820,7 @@ export default function (pi: Pi.ExtensionAPI) {
1803
1820
  getDefaultChatId: proactivePushChatIdGetter,
1804
1821
  getDefaultTarget: proactivePushTargetGetter,
1805
1822
  ...agentMessageToolRoutingRuntime,
1823
+ setGenerativeAppLiveSurfaceRuntime: generativeAppLiveSurfaceBinding.set,
1806
1824
  updateStatus,
1807
1825
  recordRuntimeEvent,
1808
1826
  });
@@ -1831,6 +1849,7 @@ export default function (pi: Pi.ExtensionAPI) {
1831
1849
  deferredQueueDispatchRuntime,
1832
1850
  modelContextAvailabilityRuntime,
1833
1851
  disconnectOnQuit: cleanupTelegramThreadForSessionRestart,
1852
+ shutdownGenerativeAppLiveSurfaces: generativeAppLiveSurfaceBinding.shutdown,
1834
1853
  resolveAutomaticThreadCleanupEnabled:
1835
1854
  configControls.resolveAutomaticThreadCleanupEnabled,
1836
1855
  buttonActionStore,