@llblab/pi-kit 0.12.0 → 0.13.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 (211) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -2
  3. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +4 -0
  4. package/node_modules/@llblab/pi-state-flow/README.md +1 -1
  5. package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +0 -1
  6. package/node_modules/@llblab/pi-state-flow/package.json +1 -1
  7. package/node_modules/@llblab/pi-telegram/AGENTS.md +5 -3
  8. package/node_modules/@llblab/pi-telegram/BACKLOG.md +0 -6
  9. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +22 -0
  10. package/node_modules/@llblab/pi-telegram/README.md +6 -3
  11. package/node_modules/@llblab/pi-telegram/dist/api/activity.d.ts +6 -0
  12. package/node_modules/@llblab/pi-telegram/dist/api/activity.js +6 -0
  13. package/node_modules/@llblab/pi-telegram/dist/api/commands.d.ts +6 -0
  14. package/node_modules/@llblab/pi-telegram/dist/api/commands.js +6 -0
  15. package/node_modules/@llblab/pi-telegram/dist/api/delivery.d.ts +6 -0
  16. package/node_modules/@llblab/pi-telegram/dist/api/delivery.js +6 -0
  17. package/node_modules/@llblab/pi-telegram/dist/api/inbound.d.ts +6 -0
  18. package/node_modules/@llblab/pi-telegram/dist/api/inbound.js +6 -0
  19. package/node_modules/@llblab/pi-telegram/dist/api/keyboard.d.ts +6 -0
  20. package/node_modules/@llblab/pi-telegram/dist/api/keyboard.js +6 -0
  21. package/node_modules/@llblab/pi-telegram/dist/api/outbound.d.ts +6 -0
  22. package/node_modules/@llblab/pi-telegram/dist/api/outbound.js +6 -0
  23. package/node_modules/@llblab/pi-telegram/dist/api/sections.d.ts +7 -0
  24. package/node_modules/@llblab/pi-telegram/dist/api/sections.js +6 -0
  25. package/node_modules/@llblab/pi-telegram/dist/api/status.d.ts +6 -0
  26. package/node_modules/@llblab/pi-telegram/dist/api/status.js +6 -0
  27. package/node_modules/@llblab/pi-telegram/dist/api/updates.d.ts +6 -0
  28. package/node_modules/@llblab/pi-telegram/dist/api/updates.js +6 -0
  29. package/node_modules/@llblab/pi-telegram/dist/api/voice.d.ts +6 -0
  30. package/node_modules/@llblab/pi-telegram/dist/api/voice.js +6 -0
  31. package/node_modules/@llblab/pi-telegram/dist/index.d.ts +6 -0
  32. package/node_modules/@llblab/pi-telegram/dist/index.js +6 -0
  33. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +52 -0
  34. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +596 -0
  35. package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +220 -0
  36. package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +574 -0
  37. package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.d.ts +28 -0
  38. package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.js +86 -0
  39. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +250 -0
  40. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +936 -0
  41. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.d.ts +18 -0
  42. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +254 -0
  43. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +464 -0
  44. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +1689 -0
  45. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +292 -0
  46. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +2242 -0
  47. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.d.ts +64 -0
  48. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +140 -0
  49. package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +518 -0
  50. package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +2055 -0
  51. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +170 -0
  52. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +611 -0
  53. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +70 -0
  54. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +744 -0
  55. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +541 -0
  56. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +1155 -0
  57. package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +252 -0
  58. package/node_modules/@llblab/pi-telegram/dist/lib/config.js +889 -0
  59. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +163 -0
  60. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +542 -0
  61. package/node_modules/@llblab/pi-telegram/dist/lib/extension.d.ts +7 -0
  62. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +1604 -0
  63. package/node_modules/@llblab/pi-telegram/dist/lib/generative-app-worker.mjs +104 -0
  64. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +212 -0
  65. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.js +1006 -0
  66. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +91 -0
  67. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +502 -0
  68. package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +665 -0
  69. package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +3701 -0
  70. package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.d.ts +23 -0
  71. package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.js +37 -0
  72. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +157 -0
  73. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +395 -0
  74. package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +164 -0
  75. package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +1208 -0
  76. package/node_modules/@llblab/pi-telegram/dist/lib/logging.d.ts +50 -0
  77. package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +274 -0
  78. package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +181 -0
  79. package/node_modules/@llblab/pi-telegram/dist/lib/media.js +602 -0
  80. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +217 -0
  81. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +663 -0
  82. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.d.ts +37 -0
  83. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.js +408 -0
  84. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +115 -0
  85. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +595 -0
  86. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +32 -0
  87. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +112 -0
  88. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +29 -0
  89. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +82 -0
  90. package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +171 -0
  91. package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +323 -0
  92. package/node_modules/@llblab/pi-telegram/dist/lib/model.d.ts +127 -0
  93. package/node_modules/@llblab/pi-telegram/dist/lib/model.js +409 -0
  94. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +241 -0
  95. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +639 -0
  96. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.d.ts +69 -0
  97. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +248 -0
  98. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +42 -0
  99. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +678 -0
  100. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.d.ts +55 -0
  101. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.js +152 -0
  102. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +185 -0
  103. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +516 -0
  104. package/node_modules/@llblab/pi-telegram/dist/lib/ownership.d.ts +77 -0
  105. package/node_modules/@llblab/pi-telegram/dist/lib/ownership.js +174 -0
  106. package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +40 -0
  107. package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +94 -0
  108. package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +72 -0
  109. package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +121 -0
  110. package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +351 -0
  111. package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +1196 -0
  112. package/node_modules/@llblab/pi-telegram/dist/lib/preview.d.ts +192 -0
  113. package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +614 -0
  114. package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.d.ts +24 -0
  115. package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.js +118 -0
  116. package/node_modules/@llblab/pi-telegram/dist/lib/prompts.d.ts +57 -0
  117. package/node_modules/@llblab/pi-telegram/dist/lib/prompts.js +167 -0
  118. package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +766 -0
  119. package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +1965 -0
  120. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +86 -0
  121. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +285 -0
  122. package/node_modules/@llblab/pi-telegram/dist/lib/rendering.d.ts +20 -0
  123. package/node_modules/@llblab/pi-telegram/dist/lib/rendering.js +983 -0
  124. package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +214 -0
  125. package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +737 -0
  126. package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +207 -0
  127. package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +2282 -0
  128. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.d.ts +172 -0
  129. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.js +402 -0
  130. package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +165 -0
  131. package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +327 -0
  132. package/node_modules/@llblab/pi-telegram/dist/lib/setup.d.ts +82 -0
  133. package/node_modules/@llblab/pi-telegram/dist/lib/setup.js +150 -0
  134. package/node_modules/@llblab/pi-telegram/dist/lib/skills.d.ts +8 -0
  135. package/node_modules/@llblab/pi-telegram/dist/lib/skills.js +12 -0
  136. package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +442 -0
  137. package/node_modules/@llblab/pi-telegram/dist/lib/status.js +1000 -0
  138. package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +179 -0
  139. package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +782 -0
  140. package/node_modules/@llblab/pi-telegram/dist/lib/target.d.ts +20 -0
  141. package/node_modules/@llblab/pi-telegram/dist/lib/target.js +27 -0
  142. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +541 -0
  143. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +1159 -0
  144. package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.d.ts +89 -0
  145. package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.js +317 -0
  146. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +288 -0
  147. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +560 -0
  148. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +46 -0
  149. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +257 -0
  150. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +46 -0
  151. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +78 -0
  152. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +239 -0
  153. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +644 -0
  154. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +621 -0
  155. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +3679 -0
  156. package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.d.ts +15 -0
  157. package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.js +56 -0
  158. package/node_modules/@llblab/pi-telegram/dist/lib/turns.d.ts +109 -0
  159. package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +500 -0
  160. package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +1290 -0
  161. package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +3634 -0
  162. package/node_modules/@llblab/pi-telegram/dist/lib/voice.d.ts +117 -0
  163. package/node_modules/@llblab/pi-telegram/dist/lib/voice.js +174 -0
  164. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +264 -0
  165. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +1136 -0
  166. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +219 -0
  167. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +587 -0
  168. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.d.ts +30 -0
  169. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.js +54 -0
  170. package/node_modules/@llblab/pi-telegram/dist/package.json +126 -0
  171. package/node_modules/@llblab/pi-telegram/dist/pi-telegram/index.js +1 -0
  172. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/SKILL.md +107 -0
  173. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/references/capability-adapters.md +27 -0
  174. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/references/layout-and-state.md +37 -0
  175. package/node_modules/@llblab/pi-telegram/dist/skills/generative-apps/SKILL.md +115 -0
  176. package/node_modules/@llblab/pi-telegram/dist/skills/show-me/SKILL.md +166 -0
  177. package/node_modules/@llblab/pi-telegram/dist/skills/show-me/references/telegram-surfaces.md +43 -0
  178. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/SKILL.md +129 -0
  179. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/configuration.md +15 -0
  180. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/delivery-and-threads.md +27 -0
  181. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/diagnosis.md +18 -0
  182. package/node_modules/@llblab/pi-telegram/docs/README.md +2 -0
  183. package/node_modules/@llblab/pi-telegram/docs/architecture.md +4 -2
  184. package/node_modules/@llblab/pi-telegram/docs/compact-matrix-literal.md +10 -3
  185. package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +15 -13
  186. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +6 -4
  187. package/node_modules/@llblab/pi-telegram/docs/outbound.md +1 -1
  188. package/node_modules/@llblab/pi-telegram/docs/public-api.md +3 -3
  189. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +89 -6
  190. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +12 -5
  191. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +44 -19
  192. package/node_modules/@llblab/pi-telegram/lib/bus.ts +4 -1
  193. package/node_modules/@llblab/pi-telegram/lib/commands.ts +2 -2
  194. package/node_modules/@llblab/pi-telegram/lib/config.ts +14 -7
  195. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +38 -6
  196. package/node_modules/@llblab/pi-telegram/lib/extension.ts +7 -0
  197. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +379 -13
  198. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +20 -6
  199. package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +16 -7
  200. package/node_modules/@llblab/pi-telegram/lib/status.ts +9 -15
  201. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +12 -1
  202. package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +96 -18
  203. package/node_modules/@llblab/pi-telegram/package.json +56 -13
  204. package/node_modules/@llblab/pi-telegram/scripts/build-dist.mjs +44 -0
  205. package/node_modules/@llblab/pi-telegram/scripts/measure-bus.mjs +8 -1
  206. package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +8 -1
  207. package/node_modules/@llblab/pi-telegram/skills/generative-apps/SKILL.md +1 -1
  208. package/node_modules/@llblab/pi-telegram/skills/show-me/SKILL.md +1 -1
  209. package/node_modules/@llblab/pi-telegram/skills/show-me/references/telegram-surfaces.md +1 -1
  210. package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/SKILL.md +1 -1
  211. package/package.json +5 -5
@@ -0,0 +1,596 @@
1
+ /**
2
+ * Bridge-owned Telegram activity verbosity projection
3
+ * Zones: telegram activity, rich rendering, operational delivery
4
+ * Owns persistent bounded thinking and tool disclosures; excludes activity normalization, assistant answer rendering, and transport authority policy
5
+ */
6
+ import { escapeHtml, renderTelegramInlineMarkdownHtml, } from "./rendering.js";
7
+ export const TELEGRAM_ACTIVITY_DETAIL_MAX_CHARS = 1_200;
8
+ export const TELEGRAM_ACTIVITY_MESSAGE_MAX_CHARS = 3_900;
9
+ export const TELEGRAM_ACTIVITY_MESSAGE_MAX_TOOLS = 6;
10
+ export const TELEGRAM_REASONING_MESSAGE_MAX_FRAMES = 24;
11
+ export const TELEGRAM_REASONING_BUFFER_MAX_CHARS = 1_200;
12
+ export const TELEGRAM_REASONING_MIN_INTERVAL_MS = 1_200;
13
+ export const TELEGRAM_TOOL_UPDATE_MAX_ENTRIES = 4;
14
+ function targetEquals(left, right) {
15
+ return left.chatId === right.chatId && left.threadId === right.threadId;
16
+ }
17
+ function redactActivityText(text) {
18
+ return text
19
+ .replace(/\b\d{8,12}:[A-Za-z0-9_-]{30,}\b/g, "[REDACTED_BOT_TOKEN]")
20
+ .replace(/\b(Bearer\s+)[A-Za-z0-9._~+/=-]{16,}\b/gi, "$1[REDACTED]")
21
+ .replace(/(["']?(?:api[_-]?key|token|password|secret)["']?\s*[:=]\s*["']?)[^"',\s}]+/gi, "$1[REDACTED]");
22
+ }
23
+ function formatActivityJson(value, depth = 0) {
24
+ const indent = " ".repeat(depth);
25
+ if (Array.isArray(value)) {
26
+ if (value.length === 0)
27
+ return [`${indent}[]`];
28
+ if (value.every((entry) => entry !== null && typeof entry === "object" && !Array.isArray(entry))) {
29
+ const lines = [`${indent}[{`];
30
+ value.forEach((entry, index) => {
31
+ const fields = Object.entries(entry);
32
+ fields.forEach(([key, nested], fieldIndex) => {
33
+ const nestedLines = formatActivityJson(nested, depth + 1);
34
+ const nestedIndent = " ".repeat(depth + 1);
35
+ lines.push(`${nestedIndent}${JSON.stringify(key)}: ${nestedLines[0].slice(nestedIndent.length)}`, ...nestedLines.slice(1));
36
+ if (fieldIndex < fields.length - 1) {
37
+ lines[lines.length - 1] += ",";
38
+ }
39
+ });
40
+ lines.push(index < value.length - 1 ? `${indent}}, {` : `${indent}}]`);
41
+ });
42
+ return lines;
43
+ }
44
+ const lines = [`${indent}[`];
45
+ value.forEach((entry, index) => {
46
+ const nestedLines = formatActivityJson(entry, depth + 1);
47
+ if (index < value.length - 1) {
48
+ nestedLines[nestedLines.length - 1] += ",";
49
+ }
50
+ lines.push(...nestedLines);
51
+ });
52
+ lines.push(`${indent}]`);
53
+ return lines;
54
+ }
55
+ if (value !== null && typeof value === "object") {
56
+ const entries = Object.entries(value);
57
+ if (entries.length === 0)
58
+ return [`${indent}{}`];
59
+ const lines = [`${indent}{`];
60
+ entries.forEach(([key, nested], index) => {
61
+ const nestedLines = formatActivityJson(nested, depth + 1);
62
+ const nestedIndent = " ".repeat(depth + 1);
63
+ lines.push(`${nestedIndent}${JSON.stringify(key)}: ${nestedLines[0].slice(nestedIndent.length)}`, ...nestedLines.slice(1));
64
+ if (index < entries.length - 1)
65
+ lines[lines.length - 1] += ",";
66
+ });
67
+ lines.push(`${indent}}`);
68
+ return lines;
69
+ }
70
+ return [`${indent}${JSON.stringify(value)}`];
71
+ }
72
+ function serializeActivityValue(value) {
73
+ const seen = new WeakSet();
74
+ let text;
75
+ try {
76
+ const normalized = JSON.stringify(value, (_key, nested) => {
77
+ if (typeof nested === "bigint")
78
+ return nested.toString();
79
+ if (nested && typeof nested === "object") {
80
+ if (seen.has(nested))
81
+ return "[Circular]";
82
+ seen.add(nested);
83
+ }
84
+ return nested;
85
+ }) ?? JSON.stringify(String(value));
86
+ text = formatActivityJson(JSON.parse(normalized)).join("\n");
87
+ }
88
+ catch {
89
+ text = JSON.stringify(String(value));
90
+ }
91
+ const redacted = redactActivityText(text);
92
+ if (redacted.length <= TELEGRAM_ACTIVITY_DETAIL_MAX_CHARS)
93
+ return redacted;
94
+ const omitted = redacted.length - TELEGRAM_ACTIVITY_DETAIL_MAX_CHARS;
95
+ return `${redacted.slice(0, TELEGRAM_ACTIVITY_DETAIL_MAX_CHARS)}\n… [${omitted} chars truncated]`;
96
+ }
97
+ function neutralizeActivityAutoLinks(text) {
98
+ return text.replace(/\b(https?:\/\/)(?=\S)/gi, "$1\u200b");
99
+ }
100
+ function escapeActivityEvidenceHtml(text) {
101
+ return escapeHtml(neutralizeActivityAutoLinks(text));
102
+ }
103
+ function renderThinkingActivityEvidenceHtml(text) {
104
+ return renderTelegramInlineMarkdownHtml(neutralizeActivityAutoLinks(text), {
105
+ allowLinks: false,
106
+ });
107
+ }
108
+ function formatToolActivityLabel(label) {
109
+ return label
110
+ .split("_")
111
+ .filter(Boolean)
112
+ .map((word) => {
113
+ const repeatedPrefix = word.match(/^([a-z])\1*/iu)?.[0] ?? "";
114
+ if (repeatedPrefix.length === 2 || repeatedPrefix.length === 3) {
115
+ return `${repeatedPrefix.toUpperCase()}${word.slice(repeatedPrefix.length)}`;
116
+ }
117
+ return `${word[0].toUpperCase()}${word.slice(1)}`;
118
+ })
119
+ .join(" ");
120
+ }
121
+ function renderToolActivityHtml(tool) {
122
+ const evidence = [`"arguments": ${tool.args}`];
123
+ if (tool.droppedUpdates > 0) {
124
+ evidence.push(`… [${tool.droppedUpdates} earlier updates omitted]`);
125
+ }
126
+ tool.updates.forEach((update, index) => {
127
+ evidence.push(`"update ${tool.droppedUpdates + index + 1}": ${update}`);
128
+ });
129
+ if (tool.complete && tool.result !== undefined) {
130
+ evidence.push(`"${tool.isError ? "error" : "result"}": ${tool.result}`);
131
+ }
132
+ const status = tool.complete
133
+ ? tool.isError
134
+ ? "failed"
135
+ : "done"
136
+ : "running";
137
+ return [
138
+ `<b>${escapeHtml(formatToolActivityLabel(tool.name))}:</b> <code>${status}</code>`,
139
+ `<blockquote expandable>${escapeActivityEvidenceHtml(evidence.join("\n\n"))}</blockquote>`,
140
+ ].join("\n");
141
+ }
142
+ export function renderTelegramToolActivityHtml(tools) {
143
+ return tools.map(renderToolActivityHtml).join("\n\n");
144
+ }
145
+ function createToolActivityDetail(summary, text, isOpen = false) {
146
+ return {
147
+ type: "details",
148
+ summary: { type: "code", text: summary },
149
+ blocks: [{ type: "pre", text, language: "json" }],
150
+ ...(isOpen ? { is_open: true } : {}),
151
+ };
152
+ }
153
+ function renderToolActivityRichBlocks(tool) {
154
+ const status = tool.complete
155
+ ? tool.isError
156
+ ? "failed"
157
+ : "done"
158
+ : "running";
159
+ const evidenceBlocks = [
160
+ createToolActivityDetail("arguments", tool.args, true),
161
+ ];
162
+ tool.updates.forEach((update, index) => {
163
+ const number = tool.droppedUpdates + index + 1;
164
+ const omitted = index === 0 && tool.droppedUpdates > 0
165
+ ? ` (${tool.droppedUpdates} earlier omitted)`
166
+ : "";
167
+ evidenceBlocks.push(createToolActivityDetail(`update ${number}${omitted}`, update));
168
+ });
169
+ if (tool.complete && tool.result !== undefined) {
170
+ evidenceBlocks.push(createToolActivityDetail(tool.isError ? "error" : "result", tool.result));
171
+ }
172
+ return [
173
+ {
174
+ type: "details",
175
+ summary: [
176
+ {
177
+ type: "bold",
178
+ text: `${formatToolActivityLabel(tool.name)}:`,
179
+ },
180
+ " ",
181
+ { type: "code", text: status },
182
+ ],
183
+ blocks: evidenceBlocks,
184
+ },
185
+ ];
186
+ }
187
+ export function renderTelegramToolActivityRichMessage(tools) {
188
+ return {
189
+ blocks: tools.flatMap(renderToolActivityRichBlocks),
190
+ skip_entity_detection: true,
191
+ };
192
+ }
193
+ function toolMessageSize(tools) {
194
+ return renderTelegramToolActivityHtml(tools).length;
195
+ }
196
+ function isKnownSafeRichActivityRejection(error) {
197
+ return error instanceof Error && /HTTP 400: Bad Request:/i.test(error.message);
198
+ }
199
+ export function renderTelegramThinkingActivityHtml(text) {
200
+ return `<blockquote expandable>${renderThinkingActivityEvidenceHtml(text)}</blockquote>`;
201
+ }
202
+ export function createTelegramActivityVerbosityBinding() {
203
+ let runtime;
204
+ return {
205
+ bind(next) {
206
+ runtime = next;
207
+ },
208
+ accept(event) {
209
+ runtime?.accept(event);
210
+ },
211
+ reset() {
212
+ runtime?.reset();
213
+ },
214
+ stop() {
215
+ runtime?.stop();
216
+ },
217
+ waitForIdle() {
218
+ return runtime?.waitForIdle() ?? Promise.resolve();
219
+ },
220
+ };
221
+ }
222
+ export function createTelegramActivityVerbosityRuntime(deps) {
223
+ let active = true;
224
+ let generation = 0;
225
+ let tail = Promise.resolve();
226
+ const getNowMs = deps.getNowMs ?? Date.now;
227
+ let activityId;
228
+ let authority;
229
+ let target;
230
+ let reasoningBuffer = "";
231
+ let reasoningChars = 0;
232
+ let reasoningMessageFrames = 0;
233
+ let lastReasoningMessageChars = 0;
234
+ let reasoningMessage;
235
+ let reasoningBlocked = false;
236
+ let lastReasoningPublishMs = 0;
237
+ let toolMessage;
238
+ const tools = new Map();
239
+ const toolOrder = [];
240
+ const clearActivity = () => {
241
+ activityId = undefined;
242
+ authority = undefined;
243
+ target = undefined;
244
+ reasoningBuffer = "";
245
+ reasoningChars = 0;
246
+ reasoningMessageFrames = 0;
247
+ lastReasoningMessageChars = 0;
248
+ reasoningMessage = undefined;
249
+ reasoningBlocked = false;
250
+ lastReasoningPublishMs = 0;
251
+ toolMessage = undefined;
252
+ tools.clear();
253
+ toolOrder.length = 0;
254
+ };
255
+ const hasAuthority = () => authority !== undefined && deps.isAuthorityActive(authority);
256
+ const isCurrent = (acceptedGeneration, admittedAuthority) => active && generation === acceptedGeneration && admittedAuthority !== undefined && deps.isAuthorityActive(admittedAuthority);
257
+ const ensureActivity = (event, admittedTarget, admittedAuthority) => {
258
+ if (deps.getActivityMode() === "quiet")
259
+ return false;
260
+ if (activityId === event.activityId)
261
+ return hasAuthority();
262
+ clearActivity();
263
+ if (!admittedTarget)
264
+ return false;
265
+ activityId = event.activityId;
266
+ target = admittedTarget;
267
+ authority = admittedAuthority;
268
+ return hasAuthority();
269
+ };
270
+ const closeToolBatch = () => {
271
+ toolMessage = undefined;
272
+ };
273
+ const publishReasoning = async (event, acceptedGeneration) => {
274
+ const admittedAuthority = authority;
275
+ if (!isCurrent(acceptedGeneration, admittedAuthority) ||
276
+ !target ||
277
+ reasoningBlocked) {
278
+ return;
279
+ }
280
+ let retained = reasoningBuffer;
281
+ let body = "";
282
+ do {
283
+ const omitted = reasoningChars - retained.length;
284
+ const text = redactActivityText(omitted > 0
285
+ ? `… [${omitted} earlier chars omitted]\n${retained}`
286
+ : retained);
287
+ body = renderTelegramThinkingActivityHtml(text);
288
+ if (body.length <= TELEGRAM_ACTIVITY_MESSAGE_MAX_CHARS)
289
+ break;
290
+ retained = retained.slice(-Math.max(1, Math.floor(retained.length * 0.75)));
291
+ } while (retained.length > 1);
292
+ const canEdit = reasoningMessage && targetEquals(reasoningMessage.target, target);
293
+ try {
294
+ if (canEdit && reasoningMessage) {
295
+ await deps.editMessageText({
296
+ chat_id: target.chatId,
297
+ message_id: reasoningMessage.messageId,
298
+ text: body,
299
+ parse_mode: "HTML",
300
+ link_preview_options: { is_disabled: true },
301
+ });
302
+ }
303
+ else {
304
+ const sent = await deps.sendMessage({
305
+ chat_id: target.chatId,
306
+ ...(target.threadId === undefined
307
+ ? {}
308
+ : { message_thread_id: target.threadId }),
309
+ text: body,
310
+ parse_mode: "HTML",
311
+ link_preview_options: { is_disabled: true },
312
+ });
313
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
314
+ return;
315
+ reasoningMessage = {
316
+ messageId: sent.message_id,
317
+ target: { ...target },
318
+ };
319
+ }
320
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
321
+ return;
322
+ reasoningMessageFrames += 1;
323
+ lastReasoningMessageChars = reasoningChars;
324
+ lastReasoningPublishMs = getNowMs();
325
+ }
326
+ catch (error) {
327
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
328
+ return;
329
+ reasoningBlocked = true;
330
+ deps.recordFailure?.(canEdit ? "reasoning-edit" : "reasoning-send", event, error);
331
+ }
332
+ };
333
+ const publishTool = async (event, tool, acceptedGeneration) => {
334
+ const admittedAuthority = authority;
335
+ if (!isCurrent(acceptedGeneration, admittedAuthority) || !target) {
336
+ return;
337
+ }
338
+ const canAppend = toolMessage &&
339
+ targetEquals(toolMessage.target, target) &&
340
+ toolMessage.tools.length < TELEGRAM_ACTIVITY_MESSAGE_MAX_TOOLS &&
341
+ toolMessageSize([...toolMessage.tools, tool]) <=
342
+ TELEGRAM_ACTIVITY_MESSAGE_MAX_CHARS;
343
+ try {
344
+ if (canAppend && toolMessage) {
345
+ const nextTools = [...toolMessage.tools, tool];
346
+ try {
347
+ await deps.editMessageText({
348
+ chat_id: target.chatId,
349
+ message_id: toolMessage.messageId,
350
+ ...(toolMessage.format === "rich"
351
+ ? {
352
+ rich_message: renderTelegramToolActivityRichMessage(nextTools),
353
+ }
354
+ : {
355
+ text: renderTelegramToolActivityHtml(nextTools),
356
+ parse_mode: "HTML",
357
+ link_preview_options: { is_disabled: true },
358
+ }),
359
+ });
360
+ }
361
+ catch (error) {
362
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
363
+ return;
364
+ if (toolMessage.format !== "rich" ||
365
+ !isKnownSafeRichActivityRejection(error)) {
366
+ throw error;
367
+ }
368
+ await deps.editMessageText({
369
+ chat_id: target.chatId,
370
+ message_id: toolMessage.messageId,
371
+ text: renderTelegramToolActivityHtml(nextTools),
372
+ parse_mode: "HTML",
373
+ link_preview_options: { is_disabled: true },
374
+ });
375
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
376
+ return;
377
+ toolMessage.format = "html";
378
+ }
379
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
380
+ return;
381
+ toolMessage.tools = nextTools;
382
+ return;
383
+ }
384
+ const body = {
385
+ chat_id: target.chatId,
386
+ ...(target.threadId === undefined
387
+ ? {}
388
+ : { message_thread_id: target.threadId }),
389
+ };
390
+ let sent;
391
+ let format = "rich";
392
+ try {
393
+ sent = await deps.sendRichMessage({
394
+ ...body,
395
+ rich_message: renderTelegramToolActivityRichMessage([tool]),
396
+ });
397
+ }
398
+ catch (error) {
399
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
400
+ return;
401
+ if (!isKnownSafeRichActivityRejection(error))
402
+ throw error;
403
+ sent = await deps.sendMessage({
404
+ ...body,
405
+ text: renderTelegramToolActivityHtml([tool]),
406
+ parse_mode: "HTML",
407
+ link_preview_options: { is_disabled: true },
408
+ });
409
+ format = "html";
410
+ }
411
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
412
+ return;
413
+ toolMessage = {
414
+ messageId: sent.message_id,
415
+ tools: [tool],
416
+ target: { ...target },
417
+ format,
418
+ };
419
+ }
420
+ catch (error) {
421
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
422
+ return;
423
+ closeToolBatch();
424
+ deps.recordFailure?.(canAppend ? "tool-edit" : "tool-send", event, error);
425
+ }
426
+ };
427
+ const process = async (event, acceptedGeneration, admittedTarget, admittedAuthority) => {
428
+ if (event.type === "agent-start" && deps.refreshActivityMode) {
429
+ try {
430
+ await deps.refreshActivityMode();
431
+ }
432
+ catch (error) {
433
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
434
+ return;
435
+ clearActivity();
436
+ activityId = event.activityId;
437
+ deps.recordFailure?.("config-refresh", event, error);
438
+ return;
439
+ }
440
+ }
441
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
442
+ return;
443
+ if (!ensureActivity(event, admittedTarget, admittedAuthority)) {
444
+ if (activityId === event.activityId &&
445
+ deps.getActivityMode() === "quiet") {
446
+ clearActivity();
447
+ }
448
+ return;
449
+ }
450
+ const mode = deps.getActivityMode();
451
+ const showThinking = mode === "thinking" || mode === "verbose";
452
+ const showTools = mode === "tools" || mode === "verbose";
453
+ if (event.type === "assistant-text-delta" ||
454
+ event.type === "assistant-segment" ||
455
+ event.type === "reasoning-delta" ||
456
+ event.type === "reasoning-end") {
457
+ closeToolBatch();
458
+ }
459
+ if (event.type === "reasoning-delta") {
460
+ if (!showThinking)
461
+ return;
462
+ reasoningChars += event.delta.length;
463
+ reasoningBuffer = `${reasoningBuffer}${event.delta}`.slice(-TELEGRAM_REASONING_BUFFER_MAX_CHARS);
464
+ if (reasoningMessageFrames < TELEGRAM_REASONING_MESSAGE_MAX_FRAMES &&
465
+ (reasoningMessageFrames === 0 ||
466
+ (getNowMs() - lastReasoningPublishMs >=
467
+ TELEGRAM_REASONING_MIN_INTERVAL_MS &&
468
+ reasoningChars - lastReasoningMessageChars >= 160))) {
469
+ await publishReasoning(event, acceptedGeneration);
470
+ }
471
+ return;
472
+ }
473
+ if (event.type === "reasoning-end") {
474
+ if (!showThinking)
475
+ return;
476
+ if (reasoningChars === 0 && event.text) {
477
+ reasoningChars = event.text.length;
478
+ reasoningBuffer = event.text.slice(-TELEGRAM_REASONING_BUFFER_MAX_CHARS);
479
+ }
480
+ if (reasoningChars > 0 &&
481
+ reasoningChars > lastReasoningMessageChars &&
482
+ !reasoningBlocked) {
483
+ await publishReasoning(event, acceptedGeneration);
484
+ }
485
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
486
+ return;
487
+ reasoningBuffer = "";
488
+ reasoningChars = 0;
489
+ reasoningMessageFrames = 0;
490
+ lastReasoningMessageChars = 0;
491
+ lastReasoningPublishMs = 0;
492
+ reasoningMessage = undefined;
493
+ reasoningBlocked = false;
494
+ return;
495
+ }
496
+ if (event.type === "tool-start") {
497
+ if (!showTools)
498
+ return;
499
+ tools.set(event.toolCallId, {
500
+ id: event.toolCallId,
501
+ name: event.toolName,
502
+ args: serializeActivityValue(event.args),
503
+ updates: [],
504
+ droppedUpdates: 0,
505
+ complete: false,
506
+ });
507
+ toolOrder.push(event.toolCallId);
508
+ return;
509
+ }
510
+ if (event.type === "tool-update") {
511
+ if (!showTools)
512
+ return;
513
+ const tool = tools.get(event.toolCallId);
514
+ if (!tool)
515
+ return;
516
+ tool.updates.push(serializeActivityValue(event.update));
517
+ if (tool.updates.length > TELEGRAM_TOOL_UPDATE_MAX_ENTRIES) {
518
+ tool.updates.shift();
519
+ tool.droppedUpdates += 1;
520
+ }
521
+ return;
522
+ }
523
+ if (event.type === "tool-end") {
524
+ if (!showTools)
525
+ return;
526
+ const tool = tools.get(event.toolCallId) ?? {
527
+ id: event.toolCallId,
528
+ name: event.toolName,
529
+ args: serializeActivityValue(undefined),
530
+ updates: [],
531
+ droppedUpdates: 0,
532
+ complete: false,
533
+ };
534
+ if (!tools.has(event.toolCallId))
535
+ toolOrder.push(event.toolCallId);
536
+ tool.result = serializeActivityValue(event.result);
537
+ tool.isError = event.isError;
538
+ tool.complete = true;
539
+ tools.set(event.toolCallId, tool);
540
+ while (toolOrder.length > 0) {
541
+ const next = tools.get(toolOrder[0]);
542
+ if (!next?.complete)
543
+ break;
544
+ toolOrder.shift();
545
+ tools.delete(next.id);
546
+ await publishTool(event, next, acceptedGeneration);
547
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
548
+ return;
549
+ }
550
+ return;
551
+ }
552
+ if (event.type === "agent-end" || event.type === "agent-settled") {
553
+ if (reasoningMessage &&
554
+ reasoningChars > lastReasoningMessageChars &&
555
+ !reasoningBlocked) {
556
+ await publishReasoning(event, acceptedGeneration);
557
+ }
558
+ if (!isCurrent(acceptedGeneration, admittedAuthority))
559
+ return;
560
+ clearActivity();
561
+ }
562
+ };
563
+ return {
564
+ accept(event) {
565
+ if (!active)
566
+ return;
567
+ const acceptedGeneration = generation;
568
+ const resolvedTarget = deps.resolveTarget(event);
569
+ const admittedTarget = resolvedTarget ? { ...resolvedTarget } : undefined;
570
+ const admittedAuthority = deps.captureAuthority();
571
+ const enqueue = deps.enqueue ?? ((task) => tail.then(task));
572
+ tail = enqueue(async () => {
573
+ if (!active || generation !== acceptedGeneration || !deps.isAuthorityActive(admittedAuthority))
574
+ return;
575
+ await process(event, acceptedGeneration, admittedTarget, admittedAuthority);
576
+ })
577
+ .catch((error) => {
578
+ deps.recordFailure?.("tool-send", event, error);
579
+ });
580
+ },
581
+ reset() {
582
+ generation += 1;
583
+ clearActivity();
584
+ tail = Promise.resolve();
585
+ },
586
+ stop() {
587
+ active = false;
588
+ generation += 1;
589
+ clearActivity();
590
+ tail = Promise.resolve();
591
+ },
592
+ waitForIdle() {
593
+ return tail;
594
+ },
595
+ };
596
+ }