@llblab/pi-telegram 0.46.0 → 0.48.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/AGENTS.md +4 -2
  2. package/BACKLOG.md +0 -6
  3. package/CHANGELOG.md +14 -0
  4. package/README.md +5 -2
  5. package/dist/api/activity.d.ts +6 -0
  6. package/dist/api/activity.js +6 -0
  7. package/dist/api/commands.d.ts +6 -0
  8. package/dist/api/commands.js +6 -0
  9. package/dist/api/delivery.d.ts +6 -0
  10. package/dist/api/delivery.js +6 -0
  11. package/dist/api/inbound.d.ts +6 -0
  12. package/dist/api/inbound.js +6 -0
  13. package/dist/api/keyboard.d.ts +6 -0
  14. package/dist/api/keyboard.js +6 -0
  15. package/dist/api/outbound.d.ts +6 -0
  16. package/dist/api/outbound.js +6 -0
  17. package/dist/api/sections.d.ts +7 -0
  18. package/dist/api/sections.js +6 -0
  19. package/dist/api/status.d.ts +6 -0
  20. package/dist/api/status.js +6 -0
  21. package/dist/api/updates.d.ts +6 -0
  22. package/dist/api/updates.js +6 -0
  23. package/dist/api/voice.d.ts +6 -0
  24. package/dist/api/voice.js +6 -0
  25. package/dist/index.d.ts +6 -0
  26. package/dist/index.js +6 -0
  27. package/dist/lib/activity-verbosity.d.ts +52 -0
  28. package/dist/lib/activity-verbosity.js +596 -0
  29. package/dist/lib/activity.d.ts +220 -0
  30. package/dist/lib/activity.js +574 -0
  31. package/dist/lib/agent-messages.d.ts +28 -0
  32. package/dist/lib/agent-messages.js +86 -0
  33. package/dist/lib/bindings.d.ts +250 -0
  34. package/dist/lib/bindings.js +936 -0
  35. package/dist/lib/bus-api.d.ts +18 -0
  36. package/dist/lib/bus-api.js +254 -0
  37. package/dist/lib/bus-follower.d.ts +464 -0
  38. package/dist/lib/bus-follower.js +1686 -0
  39. package/dist/lib/bus-leader.d.ts +292 -0
  40. package/dist/lib/bus-leader.js +2242 -0
  41. package/dist/lib/bus-transport.d.ts +64 -0
  42. package/dist/lib/bus-transport.js +140 -0
  43. package/dist/lib/bus.d.ts +518 -0
  44. package/dist/lib/bus.js +2055 -0
  45. package/dist/lib/channel-posts.d.ts +170 -0
  46. package/dist/lib/channel-posts.js +611 -0
  47. package/dist/lib/command-templates.d.ts +70 -0
  48. package/dist/lib/command-templates.js +744 -0
  49. package/dist/lib/commands.d.ts +541 -0
  50. package/dist/lib/commands.js +1155 -0
  51. package/dist/lib/config.d.ts +252 -0
  52. package/dist/lib/config.js +889 -0
  53. package/dist/lib/delivery.d.ts +163 -0
  54. package/dist/lib/delivery.js +542 -0
  55. package/dist/lib/extension.d.ts +7 -0
  56. package/dist/lib/extension.js +1604 -0
  57. package/dist/lib/generative-app-worker.mjs +104 -0
  58. package/dist/lib/generative-apps.d.ts +212 -0
  59. package/dist/lib/generative-apps.js +1006 -0
  60. package/dist/lib/inbound.d.ts +91 -0
  61. package/dist/lib/inbound.js +502 -0
  62. package/dist/lib/journal.d.ts +665 -0
  63. package/dist/lib/journal.js +3701 -0
  64. package/dist/lib/keyboard.d.ts +23 -0
  65. package/dist/lib/keyboard.js +37 -0
  66. package/dist/lib/lifecycle.d.ts +157 -0
  67. package/dist/lib/lifecycle.js +395 -0
  68. package/dist/lib/locks.d.ts +164 -0
  69. package/dist/lib/locks.js +1208 -0
  70. package/dist/lib/logging.d.ts +50 -0
  71. package/dist/lib/logging.js +274 -0
  72. package/dist/lib/media.d.ts +181 -0
  73. package/dist/lib/media.js +602 -0
  74. package/dist/lib/menu-model.d.ts +217 -0
  75. package/dist/lib/menu-model.js +663 -0
  76. package/dist/lib/menu-queue.d.ts +37 -0
  77. package/dist/lib/menu-queue.js +408 -0
  78. package/dist/lib/menu-settings.d.ts +115 -0
  79. package/dist/lib/menu-settings.js +595 -0
  80. package/dist/lib/menu-status.d.ts +32 -0
  81. package/dist/lib/menu-status.js +112 -0
  82. package/dist/lib/menu-thinking.d.ts +29 -0
  83. package/dist/lib/menu-thinking.js +82 -0
  84. package/dist/lib/menu.d.ts +171 -0
  85. package/dist/lib/menu.js +323 -0
  86. package/dist/lib/model.d.ts +127 -0
  87. package/dist/lib/model.js +409 -0
  88. package/dist/lib/outbound-attachments.d.ts +241 -0
  89. package/dist/lib/outbound-attachments.js +639 -0
  90. package/dist/lib/outbound-buttons.d.ts +69 -0
  91. package/dist/lib/outbound-buttons.js +248 -0
  92. package/dist/lib/outbound-markup.d.ts +42 -0
  93. package/dist/lib/outbound-markup.js +678 -0
  94. package/dist/lib/outbound-voice.d.ts +55 -0
  95. package/dist/lib/outbound-voice.js +152 -0
  96. package/dist/lib/outbound.d.ts +185 -0
  97. package/dist/lib/outbound.js +516 -0
  98. package/dist/lib/ownership.d.ts +77 -0
  99. package/dist/lib/ownership.js +174 -0
  100. package/dist/lib/paths.d.ts +40 -0
  101. package/dist/lib/paths.js +94 -0
  102. package/dist/lib/pi.d.ts +72 -0
  103. package/dist/lib/pi.js +121 -0
  104. package/dist/lib/polling.d.ts +351 -0
  105. package/dist/lib/polling.js +1196 -0
  106. package/dist/lib/preview.d.ts +192 -0
  107. package/dist/lib/preview.js +614 -0
  108. package/dist/lib/prompt-templates.d.ts +24 -0
  109. package/dist/lib/prompt-templates.js +118 -0
  110. package/dist/lib/prompts.d.ts +57 -0
  111. package/dist/lib/prompts.js +167 -0
  112. package/dist/lib/queue.d.ts +766 -0
  113. package/dist/lib/queue.js +1965 -0
  114. package/dist/lib/recovery.d.ts +86 -0
  115. package/dist/lib/recovery.js +285 -0
  116. package/dist/lib/rendering.d.ts +20 -0
  117. package/dist/lib/rendering.js +983 -0
  118. package/dist/lib/replies.d.ts +214 -0
  119. package/dist/lib/replies.js +737 -0
  120. package/dist/lib/routing.d.ts +207 -0
  121. package/dist/lib/routing.js +2282 -0
  122. package/dist/lib/runtime.d.ts +172 -0
  123. package/dist/lib/runtime.js +402 -0
  124. package/dist/lib/sections.d.ts +165 -0
  125. package/dist/lib/sections.js +327 -0
  126. package/dist/lib/setup.d.ts +82 -0
  127. package/dist/lib/setup.js +150 -0
  128. package/dist/lib/skills.d.ts +8 -0
  129. package/dist/lib/skills.js +12 -0
  130. package/dist/lib/status.d.ts +442 -0
  131. package/dist/lib/status.js +1008 -0
  132. package/dist/lib/sync.d.ts +179 -0
  133. package/dist/lib/sync.js +782 -0
  134. package/dist/lib/target.d.ts +20 -0
  135. package/dist/lib/target.js +27 -0
  136. package/dist/lib/telegram-api.d.ts +541 -0
  137. package/dist/lib/telegram-api.js +1159 -0
  138. package/dist/lib/text-groups.d.ts +89 -0
  139. package/dist/lib/text-groups.js +317 -0
  140. package/dist/lib/thread-cleanup-manager.d.ts +288 -0
  141. package/dist/lib/thread-cleanup-manager.js +560 -0
  142. package/dist/lib/thread-display.d.ts +46 -0
  143. package/dist/lib/thread-display.js +257 -0
  144. package/dist/lib/thread-naming.d.ts +46 -0
  145. package/dist/lib/thread-naming.js +78 -0
  146. package/dist/lib/thread-reconciler.d.ts +239 -0
  147. package/dist/lib/thread-reconciler.js +644 -0
  148. package/dist/lib/threads.d.ts +621 -0
  149. package/dist/lib/threads.js +3679 -0
  150. package/dist/lib/time-injection.d.ts +15 -0
  151. package/dist/lib/time-injection.js +56 -0
  152. package/dist/lib/turns.d.ts +109 -0
  153. package/dist/lib/turns.js +500 -0
  154. package/dist/lib/updates.d.ts +1290 -0
  155. package/dist/lib/updates.js +3634 -0
  156. package/dist/lib/voice.d.ts +117 -0
  157. package/dist/lib/voice.js +174 -0
  158. package/dist/lib/workspace-admission.d.ts +264 -0
  159. package/dist/lib/workspace-admission.js +1136 -0
  160. package/dist/lib/workspace-retirement.d.ts +219 -0
  161. package/dist/lib/workspace-retirement.js +587 -0
  162. package/dist/lib/workspace-slots.d.ts +30 -0
  163. package/dist/lib/workspace-slots.js +54 -0
  164. package/dist/package.json +126 -0
  165. package/dist/pi-telegram/index.js +1 -0
  166. package/dist/skills/generated-control-surface/SKILL.md +107 -0
  167. package/dist/skills/generated-control-surface/references/capability-adapters.md +27 -0
  168. package/dist/skills/generated-control-surface/references/layout-and-state.md +37 -0
  169. package/dist/skills/generative-apps/SKILL.md +115 -0
  170. package/dist/skills/show-me/SKILL.md +166 -0
  171. package/dist/skills/show-me/references/telegram-surfaces.md +43 -0
  172. package/dist/skills/telegram-bridge/SKILL.md +129 -0
  173. package/dist/skills/telegram-bridge/references/configuration.md +15 -0
  174. package/dist/skills/telegram-bridge/references/delivery-and-threads.md +27 -0
  175. package/dist/skills/telegram-bridge/references/diagnosis.md +18 -0
  176. package/docs/README.md +2 -0
  177. package/docs/architecture.md +1 -1
  178. package/docs/compact-matrix-literal.md +10 -3
  179. package/docs/generative-apps.md +15 -13
  180. package/docs/multi-instance-bus.md +6 -4
  181. package/docs/outbound.md +1 -1
  182. package/docs/public-api.md +3 -3
  183. package/lib/bindings.ts +89 -6
  184. package/lib/bus-follower.ts +7 -3
  185. package/lib/bus-leader.ts +44 -19
  186. package/lib/bus.ts +4 -1
  187. package/lib/commands.ts +2 -2
  188. package/lib/config.ts +14 -7
  189. package/lib/delivery.ts +38 -6
  190. package/lib/extension.ts +7 -0
  191. package/lib/generative-apps.ts +379 -13
  192. package/lib/menu-settings.ts +20 -6
  193. package/lib/outbound-markup.ts +16 -7
  194. package/lib/status.ts +15 -12
  195. package/lib/telegram-api.ts +12 -1
  196. package/lib/thread-display.ts +96 -18
  197. package/package.json +56 -13
  198. package/scripts/build-dist.mjs +44 -0
  199. package/scripts/measure-bus.mjs +8 -1
  200. package/scripts/measure-workspace.mjs +8 -1
  201. package/skills/generative-apps/SKILL.md +1 -1
  202. package/skills/show-me/SKILL.md +1 -1
  203. package/skills/show-me/references/telegram-surfaces.md +1 -1
  204. package/skills/telegram-bridge/SKILL.md +1 -1
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Telegram bridge runtime-state helpers
3
+ * Zones: pi agent runtime state, telegram session, shared coordination
4
+ * Owns small session-local runtime primitives that are shared by orchestration but are not specific to queueing, rendering, polling, or Telegram transport
5
+ */
6
+ export interface TelegramRuntimeQueueCounters {
7
+ nextQueuedTelegramItemOrder: number;
8
+ nextQueuedTelegramControlOrder: number;
9
+ }
10
+ export interface TelegramRuntimeLifecycleFlags {
11
+ activeTelegramToolExecutions: number;
12
+ telegramTurnDispatchPending: boolean;
13
+ compactionInProgress: boolean;
14
+ foldQueuedPromptsIntoHistory: boolean;
15
+ setupInProgress: boolean;
16
+ }
17
+ export interface TelegramBridgeRuntimeState extends TelegramRuntimeQueueCounters, TelegramRuntimeLifecycleFlags {
18
+ abortHandler?: () => void;
19
+ typingInterval?: ReturnType<typeof setInterval>;
20
+ typingInFlight?: Promise<void>;
21
+ typingLoopDeps?: TelegramTypingLoopDeps;
22
+ typingLoopKey?: string;
23
+ }
24
+ export interface TelegramRuntimeQueuePort {
25
+ syncCounters: (counters: Partial<TelegramRuntimeQueueCounters>) => void;
26
+ allocateItemOrder: () => number;
27
+ allocateControlOrder: () => number;
28
+ }
29
+ export interface TelegramRuntimeLifecyclePort {
30
+ syncFlags: (flags: Partial<TelegramRuntimeLifecycleFlags>) => void;
31
+ getActiveToolExecutions: () => number;
32
+ setActiveToolExecutions: (count: number) => void;
33
+ resetActiveToolExecutions: () => void;
34
+ hasDispatchPending: () => boolean;
35
+ setDispatchPending: (pending: boolean) => void;
36
+ clearDispatchPending: () => void;
37
+ isCompactionInProgress: () => boolean;
38
+ setCompactionInProgress: (inProgress: boolean) => void;
39
+ shouldFoldQueuedPromptsIntoHistory: () => boolean;
40
+ setFoldQueuedPromptsIntoHistory: (fold: boolean) => void;
41
+ }
42
+ export interface TelegramRuntimeSetupPort {
43
+ isInProgress: () => boolean;
44
+ start: () => boolean;
45
+ finish: () => void;
46
+ }
47
+ export interface TelegramRuntimeAbortPort {
48
+ hasHandler: () => boolean;
49
+ setHandler: (abortHandler: () => void) => void;
50
+ clearHandler: () => void;
51
+ getHandler: () => (() => void) | undefined;
52
+ abortTurn: () => boolean;
53
+ }
54
+ export interface TelegramRuntimeTypingPort {
55
+ start: (deps: TelegramTypingLoopDeps) => boolean;
56
+ stop: () => boolean;
57
+ waitForIdle: () => Promise<void>;
58
+ }
59
+ export interface TelegramBridgeRuntime {
60
+ state: TelegramBridgeRuntimeState;
61
+ queue: TelegramRuntimeQueuePort;
62
+ lifecycle: TelegramRuntimeLifecyclePort;
63
+ setup: TelegramRuntimeSetupPort;
64
+ abort: TelegramRuntimeAbortPort;
65
+ typing: TelegramRuntimeTypingPort;
66
+ }
67
+ export declare function createTelegramBridgeRuntimeState(): TelegramBridgeRuntimeState;
68
+ export declare function createTelegramBridgeRuntime(state?: TelegramBridgeRuntimeState): TelegramBridgeRuntime;
69
+ export declare function syncTelegramQueueRuntimeCounters(state: TelegramBridgeRuntimeState, counters: Partial<TelegramRuntimeQueueCounters>): void;
70
+ export declare function allocateTelegramQueueItemOrder(state: TelegramBridgeRuntimeState): number;
71
+ export declare function allocateTelegramQueueControlOrder(state: TelegramBridgeRuntimeState): number;
72
+ export declare function syncTelegramLifecycleRuntimeFlags(state: TelegramBridgeRuntimeState, flags: Partial<TelegramRuntimeLifecycleFlags>): void;
73
+ export declare function getActiveTelegramToolExecutions(state: TelegramBridgeRuntimeState): number;
74
+ export declare function setActiveTelegramToolExecutions(state: TelegramBridgeRuntimeState, count: number): void;
75
+ export declare function resetActiveTelegramToolExecutions(state: TelegramBridgeRuntimeState): void;
76
+ export declare function hasTelegramDispatchPending(state: TelegramBridgeRuntimeState): boolean;
77
+ export declare function clearTelegramDispatchPending(state: TelegramBridgeRuntimeState): void;
78
+ export declare function isTelegramCompactionInProgress(state: TelegramBridgeRuntimeState): boolean;
79
+ export declare function setTelegramCompactionInProgress(state: TelegramBridgeRuntimeState, inProgress: boolean): void;
80
+ export declare function shouldFoldQueuedPromptsIntoHistory(state: TelegramBridgeRuntimeState): boolean;
81
+ export declare function setFoldQueuedPromptsIntoHistory(state: TelegramBridgeRuntimeState, fold: boolean): void;
82
+ export declare function isTelegramSetupInProgress(state: TelegramBridgeRuntimeState): boolean;
83
+ export declare function startTelegramSetup(state: TelegramBridgeRuntimeState): boolean;
84
+ export declare function finishTelegramSetup(state: TelegramBridgeRuntimeState): void;
85
+ export declare function hasTelegramAbortHandler(state: TelegramBridgeRuntimeState): boolean;
86
+ export declare function setTelegramAbortHandler(state: TelegramBridgeRuntimeState, abortHandler: () => void): void;
87
+ export declare function clearTelegramAbortHandler(state: TelegramBridgeRuntimeState): void;
88
+ export declare function getTelegramAbortHandler(state: TelegramBridgeRuntimeState): (() => void) | undefined;
89
+ export declare function abortTelegramTurn(state: TelegramBridgeRuntimeState): boolean;
90
+ export interface TelegramTypingLoopTarget {
91
+ chatId: number;
92
+ threadId?: number;
93
+ }
94
+ export interface TelegramTypingLoopDeps {
95
+ chatId: number | undefined;
96
+ target?: TelegramTypingLoopTarget;
97
+ intervalMs: number;
98
+ sendTypingAction: (chatId: number, options?: {
99
+ message_thread_id?: number;
100
+ }) => Promise<unknown>;
101
+ sendAggregateTypingAction?: (chatId: number) => Promise<unknown>;
102
+ shouldContinue?: () => boolean;
103
+ onStopped?: () => void;
104
+ }
105
+ export interface TelegramRuntimeEventRecorderPort {
106
+ recordRuntimeEvent?: (category: string, error: unknown, details?: Record<string, unknown>) => void;
107
+ }
108
+ export interface TelegramTypingLoopStarterDeps<TContext> extends TelegramRuntimeEventRecorderPort {
109
+ typing: TelegramRuntimeTypingPort;
110
+ getDefaultChatId: () => number | undefined;
111
+ sendTypingAction: (chatId: number, options?: {
112
+ message_thread_id?: number;
113
+ }) => Promise<unknown>;
114
+ sendAggregateTypingAction?: (chatId: number) => Promise<unknown>;
115
+ updateStatus: (ctx: TContext, error?: string) => void;
116
+ isContextActive?: (ctx: TContext) => boolean;
117
+ isTransportAvailable?: () => boolean;
118
+ getTransportAuthority?: () => string | number | undefined;
119
+ intervalMs?: number;
120
+ }
121
+ export declare function createTelegramTypingLoopStarter<TContext>(deps: TelegramTypingLoopStarterDeps<TContext>): (ctx: TContext, chatId?: number, options?: {
122
+ target?: TelegramTypingLoopTarget;
123
+ }) => void;
124
+ export declare function startTelegramTypingLoop(state: TelegramBridgeRuntimeState, deps: TelegramTypingLoopDeps): boolean;
125
+ export declare function stopTelegramTypingLoop(state: TelegramBridgeRuntimeState): boolean;
126
+ export declare function waitForTelegramTypingLoopIdle(state: TelegramBridgeRuntimeState, timeoutMs?: number): Promise<void>;
127
+ export declare function createTelegramContextAbortHandlerSetter<TContext extends {
128
+ abort: () => void;
129
+ }>(abort: Pick<TelegramRuntimeAbortPort, "setHandler">): (ctx: TContext) => void;
130
+ export interface TelegramAgentEndResetDeps {
131
+ abort: Pick<TelegramRuntimeAbortPort, "clearHandler">;
132
+ typing: Pick<TelegramRuntimeTypingPort, "stop">;
133
+ clearActiveTurn: () => void;
134
+ resetToolExecutions: () => void;
135
+ clearPendingModelSwitch: () => void;
136
+ clearDispatchPending: () => void;
137
+ }
138
+ export declare function createTelegramAgentEndResetter(deps: TelegramAgentEndResetDeps): () => void;
139
+ export interface TelegramPromptDispatchLifecycleDeps<TContext> extends TelegramRuntimeEventRecorderPort {
140
+ lifecycle: Pick<TelegramRuntimeLifecyclePort, "setDispatchPending" | "clearDispatchPending">;
141
+ typing: Pick<TelegramRuntimeTypingPort, "stop">;
142
+ startTypingLoop: (ctx: TContext, chatId?: number, options?: {
143
+ target?: TelegramTypingLoopTarget;
144
+ }) => void;
145
+ updateStatus: (ctx: TContext, error?: string) => void;
146
+ }
147
+ export interface TelegramPromptDispatchRuntimeDeps<TContext> extends TelegramRuntimeEventRecorderPort {
148
+ lifecycle: TelegramPromptDispatchLifecycleDeps<TContext>["lifecycle"];
149
+ typing: TelegramRuntimeTypingPort;
150
+ getDefaultChatId: () => number | undefined;
151
+ sendTypingAction: (chatId: number, options?: {
152
+ message_thread_id?: number;
153
+ }) => Promise<unknown>;
154
+ sendAggregateTypingAction?: (chatId: number) => Promise<unknown>;
155
+ updateStatus: (ctx: TContext, error?: string) => void;
156
+ isContextActive?: (ctx: TContext) => boolean;
157
+ isTransportAvailable?: () => boolean;
158
+ getTransportAuthority?: () => string | number | undefined;
159
+ intervalMs?: number;
160
+ }
161
+ export interface TelegramPromptDispatchRuntime<TContext> {
162
+ startTypingLoop: (ctx: TContext, chatId?: number, options?: {
163
+ target?: TelegramTypingLoopTarget;
164
+ }) => void;
165
+ onPromptDispatchStart: (ctx: TContext, chatId?: number) => void;
166
+ onPromptDispatchFailure: (ctx: TContext, message: string) => void;
167
+ }
168
+ export declare function createTelegramPromptDispatchRuntime<TContext>(deps: TelegramPromptDispatchRuntimeDeps<TContext>): TelegramPromptDispatchRuntime<TContext>;
169
+ export declare function createTelegramPromptDispatchLifecycle<TContext>(deps: TelegramPromptDispatchLifecycleDeps<TContext>): {
170
+ onPromptDispatchStart: (ctx: TContext, chatId?: number) => void;
171
+ onPromptDispatchFailure: (ctx: TContext, message: string) => void;
172
+ };
@@ -0,0 +1,402 @@
1
+ /**
2
+ * Telegram bridge runtime-state helpers
3
+ * Zones: pi agent runtime state, telegram session, shared coordination
4
+ * Owns small session-local runtime primitives that are shared by orchestration but are not specific to queueing, rendering, polling, or Telegram transport
5
+ */
6
+ const TELEGRAM_TYPING_ACTION_INTERVAL_MS = 2500;
7
+ const TELEGRAM_TYPING_IDLE_DRAIN_MAX_MS = 250;
8
+ export function createTelegramBridgeRuntimeState() {
9
+ return {
10
+ nextQueuedTelegramItemOrder: 0,
11
+ nextQueuedTelegramControlOrder: 0,
12
+ activeTelegramToolExecutions: 0,
13
+ telegramTurnDispatchPending: false,
14
+ compactionInProgress: false,
15
+ foldQueuedPromptsIntoHistory: false,
16
+ setupInProgress: false,
17
+ };
18
+ }
19
+ export function createTelegramBridgeRuntime(state = createTelegramBridgeRuntimeState()) {
20
+ return {
21
+ state,
22
+ queue: {
23
+ syncCounters: (counters) => syncTelegramQueueRuntimeCounters(state, counters),
24
+ allocateItemOrder: () => allocateTelegramQueueItemOrder(state),
25
+ allocateControlOrder: () => allocateTelegramQueueControlOrder(state),
26
+ },
27
+ lifecycle: {
28
+ syncFlags: (flags) => syncTelegramLifecycleRuntimeFlags(state, flags),
29
+ getActiveToolExecutions: () => getActiveTelegramToolExecutions(state),
30
+ setActiveToolExecutions: (count) => setActiveTelegramToolExecutions(state, count),
31
+ resetActiveToolExecutions: () => resetActiveTelegramToolExecutions(state),
32
+ hasDispatchPending: () => hasTelegramDispatchPending(state),
33
+ setDispatchPending: (pending) => setTelegramDispatchPending(state, pending),
34
+ clearDispatchPending: () => clearTelegramDispatchPending(state),
35
+ isCompactionInProgress: () => isTelegramCompactionInProgress(state),
36
+ setCompactionInProgress: (inProgress) => setTelegramCompactionInProgress(state, inProgress),
37
+ shouldFoldQueuedPromptsIntoHistory: () => shouldFoldQueuedPromptsIntoHistory(state),
38
+ setFoldQueuedPromptsIntoHistory: (fold) => setFoldQueuedPromptsIntoHistory(state, fold),
39
+ },
40
+ setup: {
41
+ isInProgress: () => isTelegramSetupInProgress(state),
42
+ start: () => startTelegramSetup(state),
43
+ finish: () => finishTelegramSetup(state),
44
+ },
45
+ abort: {
46
+ hasHandler: () => hasTelegramAbortHandler(state),
47
+ setHandler: (abortHandler) => setTelegramAbortHandler(state, abortHandler),
48
+ clearHandler: () => clearTelegramAbortHandler(state),
49
+ getHandler: () => getTelegramAbortHandler(state),
50
+ abortTurn: () => abortTelegramTurn(state),
51
+ },
52
+ typing: {
53
+ start: (deps) => startTelegramTypingLoop(state, deps),
54
+ stop: () => stopTelegramTypingLoop(state),
55
+ waitForIdle: () => waitForTelegramTypingLoopIdle(state),
56
+ },
57
+ };
58
+ }
59
+ export function syncTelegramQueueRuntimeCounters(state, counters) {
60
+ if (counters.nextQueuedTelegramItemOrder !== undefined) {
61
+ state.nextQueuedTelegramItemOrder = counters.nextQueuedTelegramItemOrder;
62
+ }
63
+ if (counters.nextQueuedTelegramControlOrder !== undefined) {
64
+ state.nextQueuedTelegramControlOrder =
65
+ counters.nextQueuedTelegramControlOrder;
66
+ }
67
+ }
68
+ export function allocateTelegramQueueItemOrder(state) {
69
+ return state.nextQueuedTelegramItemOrder++;
70
+ }
71
+ export function allocateTelegramQueueControlOrder(state) {
72
+ return state.nextQueuedTelegramControlOrder++;
73
+ }
74
+ export function syncTelegramLifecycleRuntimeFlags(state, flags) {
75
+ if (flags.activeTelegramToolExecutions !== undefined) {
76
+ state.activeTelegramToolExecutions = flags.activeTelegramToolExecutions;
77
+ }
78
+ if (flags.telegramTurnDispatchPending !== undefined) {
79
+ state.telegramTurnDispatchPending = flags.telegramTurnDispatchPending;
80
+ }
81
+ if (flags.compactionInProgress !== undefined) {
82
+ state.compactionInProgress = flags.compactionInProgress;
83
+ }
84
+ if (flags.foldQueuedPromptsIntoHistory !== undefined) {
85
+ state.foldQueuedPromptsIntoHistory = flags.foldQueuedPromptsIntoHistory;
86
+ }
87
+ if (flags.setupInProgress !== undefined) {
88
+ state.setupInProgress = flags.setupInProgress;
89
+ }
90
+ }
91
+ export function getActiveTelegramToolExecutions(state) {
92
+ return state.activeTelegramToolExecutions;
93
+ }
94
+ export function setActiveTelegramToolExecutions(state, count) {
95
+ state.activeTelegramToolExecutions = count;
96
+ }
97
+ export function resetActiveTelegramToolExecutions(state) {
98
+ state.activeTelegramToolExecutions = 0;
99
+ }
100
+ export function hasTelegramDispatchPending(state) {
101
+ return state.telegramTurnDispatchPending;
102
+ }
103
+ function setTelegramDispatchPending(state, pending) {
104
+ state.telegramTurnDispatchPending = pending;
105
+ }
106
+ export function clearTelegramDispatchPending(state) {
107
+ state.telegramTurnDispatchPending = false;
108
+ }
109
+ export function isTelegramCompactionInProgress(state) {
110
+ return state.compactionInProgress;
111
+ }
112
+ export function setTelegramCompactionInProgress(state, inProgress) {
113
+ state.compactionInProgress = inProgress;
114
+ }
115
+ export function shouldFoldQueuedPromptsIntoHistory(state) {
116
+ return state.foldQueuedPromptsIntoHistory;
117
+ }
118
+ export function setFoldQueuedPromptsIntoHistory(state, fold) {
119
+ state.foldQueuedPromptsIntoHistory = fold;
120
+ }
121
+ export function isTelegramSetupInProgress(state) {
122
+ return state.setupInProgress;
123
+ }
124
+ export function startTelegramSetup(state) {
125
+ if (state.setupInProgress)
126
+ return false;
127
+ state.setupInProgress = true;
128
+ return true;
129
+ }
130
+ export function finishTelegramSetup(state) {
131
+ state.setupInProgress = false;
132
+ }
133
+ export function hasTelegramAbortHandler(state) {
134
+ return !!state.abortHandler;
135
+ }
136
+ export function setTelegramAbortHandler(state, abortHandler) {
137
+ state.abortHandler = abortHandler;
138
+ }
139
+ export function clearTelegramAbortHandler(state) {
140
+ state.abortHandler = undefined;
141
+ }
142
+ export function getTelegramAbortHandler(state) {
143
+ return state.abortHandler;
144
+ }
145
+ export function abortTelegramTurn(state) {
146
+ if (!state.abortHandler)
147
+ return false;
148
+ state.abortHandler();
149
+ return true;
150
+ }
151
+ function getTelegramTypingLoopThreadParams(target) {
152
+ const threadId = target?.threadId;
153
+ return Number.isInteger(threadId)
154
+ ? { message_thread_id: threadId }
155
+ : undefined;
156
+ }
157
+ function updateTelegramRuntimeStatusSafely(updateStatus, ctx, options) {
158
+ try {
159
+ updateStatus(ctx, options.error);
160
+ }
161
+ catch (statusError) {
162
+ try {
163
+ options.recordRuntimeEvent?.(options.category, statusError, {
164
+ phase: options.phase,
165
+ });
166
+ }
167
+ catch {
168
+ // Status diagnostics cannot escape an asynchronous runtime owner.
169
+ }
170
+ }
171
+ }
172
+ export function createTelegramTypingLoopStarter(deps) {
173
+ return (ctx, chatId, options) => {
174
+ const transportAuthority = deps.getTransportAuthority?.();
175
+ const hasTransport = () => deps.getTransportAuthority
176
+ ? transportAuthority !== undefined &&
177
+ Object.is(deps.getTransportAuthority(), transportAuthority)
178
+ : deps.isTransportAvailable?.() !== false;
179
+ if (!hasTransport())
180
+ return;
181
+ let active = true;
182
+ deps.typing.start({
183
+ chatId: chatId ?? deps.getDefaultChatId(),
184
+ target: options?.target,
185
+ intervalMs: deps.intervalMs ?? TELEGRAM_TYPING_ACTION_INTERVAL_MS,
186
+ sendTypingAction: async (targetChatId, actionOptions) => {
187
+ if (!active)
188
+ return;
189
+ if (!hasTransport()) {
190
+ deps.typing.stop();
191
+ return;
192
+ }
193
+ try {
194
+ await deps.sendTypingAction(targetChatId, actionOptions);
195
+ }
196
+ catch (error) {
197
+ if (deps.isContextActive?.(ctx) === false)
198
+ return;
199
+ if (!active)
200
+ return;
201
+ if (!hasTransport()) {
202
+ deps.typing.stop();
203
+ return;
204
+ }
205
+ const message = error instanceof Error ? error.message : String(error);
206
+ updateTelegramRuntimeStatusSafely(deps.updateStatus, ctx, {
207
+ error: message,
208
+ category: "typing",
209
+ phase: "status-update",
210
+ recordRuntimeEvent: deps.recordRuntimeEvent,
211
+ });
212
+ try {
213
+ deps.recordRuntimeEvent?.("typing", error, {
214
+ chatId: targetChatId,
215
+ });
216
+ }
217
+ catch {
218
+ // Typing diagnostics cannot escape the in-flight action owner.
219
+ }
220
+ }
221
+ },
222
+ sendAggregateTypingAction: deps.sendAggregateTypingAction
223
+ ? async (targetChatId) => {
224
+ if (!active)
225
+ return;
226
+ if (!hasTransport()) {
227
+ deps.typing.stop();
228
+ return;
229
+ }
230
+ try {
231
+ await deps.sendAggregateTypingAction?.(targetChatId);
232
+ }
233
+ catch (error) {
234
+ if (deps.isContextActive?.(ctx) === false)
235
+ return;
236
+ if (!active)
237
+ return;
238
+ if (!hasTransport()) {
239
+ deps.typing.stop();
240
+ return;
241
+ }
242
+ const message = error instanceof Error ? error.message : String(error);
243
+ updateTelegramRuntimeStatusSafely(deps.updateStatus, ctx, {
244
+ error: message,
245
+ category: "typing",
246
+ phase: "status-update",
247
+ recordRuntimeEvent: deps.recordRuntimeEvent,
248
+ });
249
+ try {
250
+ deps.recordRuntimeEvent?.("typing", error, {
251
+ chatId: targetChatId,
252
+ aggregate: true,
253
+ });
254
+ }
255
+ catch {
256
+ // Typing diagnostics cannot escape the in-flight action owner.
257
+ }
258
+ }
259
+ }
260
+ : undefined,
261
+ shouldContinue: hasTransport,
262
+ onStopped: () => {
263
+ active = false;
264
+ },
265
+ });
266
+ };
267
+ }
268
+ function getTelegramTypingLoopKey(deps) {
269
+ const threadId = deps.target?.threadId;
270
+ return `${deps.chatId ?? 0}:${Number.isInteger(threadId) ? threadId : "all"}`;
271
+ }
272
+ export function startTelegramTypingLoop(state, deps) {
273
+ if (deps.chatId === undefined || deps.chatId === 0)
274
+ return false;
275
+ const previousKey = state.typingLoopKey;
276
+ const previousDeps = state.typingLoopDeps;
277
+ const nextKey = getTelegramTypingLoopKey(deps);
278
+ if (previousDeps && previousDeps !== deps) {
279
+ previousDeps.onStopped?.();
280
+ state.typingInFlight = undefined;
281
+ }
282
+ state.typingLoopDeps = deps;
283
+ state.typingLoopKey = nextKey;
284
+ const sendTyping = () => {
285
+ const activeDeps = state.typingLoopDeps;
286
+ if (!activeDeps ||
287
+ activeDeps.chatId === undefined ||
288
+ activeDeps.chatId === 0)
289
+ return;
290
+ if (activeDeps.shouldContinue?.() === false) {
291
+ stopTelegramTypingLoop(state);
292
+ return;
293
+ }
294
+ if (state.typingInFlight)
295
+ return;
296
+ const targetChatId = activeDeps.chatId;
297
+ const threadParams = getTelegramTypingLoopThreadParams(activeDeps.target);
298
+ const typing = Promise.resolve()
299
+ .then(async () => {
300
+ await activeDeps.sendTypingAction(targetChatId, threadParams);
301
+ if (threadParams?.message_thread_id !== undefined) {
302
+ await activeDeps.sendAggregateTypingAction?.(targetChatId);
303
+ }
304
+ })
305
+ .then(() => undefined)
306
+ .catch(() => undefined);
307
+ state.typingInFlight = typing;
308
+ void typing.finally(() => {
309
+ if (state.typingInFlight === typing)
310
+ state.typingInFlight = undefined;
311
+ });
312
+ };
313
+ if (state.typingInterval) {
314
+ if (previousKey === nextKey)
315
+ return false;
316
+ sendTyping();
317
+ return true;
318
+ }
319
+ sendTyping();
320
+ state.typingInterval = setInterval(sendTyping, deps.intervalMs);
321
+ state.typingInterval.unref?.();
322
+ return true;
323
+ }
324
+ export function stopTelegramTypingLoop(state) {
325
+ if (!state.typingInterval)
326
+ return false;
327
+ clearInterval(state.typingInterval);
328
+ const activeDeps = state.typingLoopDeps;
329
+ state.typingInterval = undefined;
330
+ state.typingLoopDeps = undefined;
331
+ state.typingLoopKey = undefined;
332
+ state.typingInFlight = undefined;
333
+ activeDeps?.onStopped?.();
334
+ return true;
335
+ }
336
+ export async function waitForTelegramTypingLoopIdle(state, timeoutMs = TELEGRAM_TYPING_IDLE_DRAIN_MAX_MS) {
337
+ const inFlight = state.typingInFlight;
338
+ if (!inFlight)
339
+ return;
340
+ if (timeoutMs <= 0) {
341
+ await Promise.race([inFlight, Promise.resolve()]);
342
+ return;
343
+ }
344
+ await Promise.race([
345
+ inFlight,
346
+ new Promise((resolve) => {
347
+ setTimeout(resolve, timeoutMs);
348
+ }),
349
+ ]);
350
+ }
351
+ export function createTelegramContextAbortHandlerSetter(abort) {
352
+ return (ctx) => {
353
+ abort.setHandler(() => ctx.abort());
354
+ };
355
+ }
356
+ export function createTelegramAgentEndResetter(deps) {
357
+ return () => {
358
+ deps.abort.clearHandler();
359
+ deps.typing.stop();
360
+ deps.clearActiveTurn();
361
+ deps.resetToolExecutions();
362
+ deps.clearPendingModelSwitch();
363
+ deps.clearDispatchPending();
364
+ };
365
+ }
366
+ export function createTelegramPromptDispatchRuntime(deps) {
367
+ const startTypingLoop = createTelegramTypingLoopStarter(deps);
368
+ return {
369
+ startTypingLoop,
370
+ ...createTelegramPromptDispatchLifecycle({
371
+ lifecycle: deps.lifecycle,
372
+ typing: deps.typing,
373
+ startTypingLoop,
374
+ updateStatus: deps.updateStatus,
375
+ recordRuntimeEvent: deps.recordRuntimeEvent,
376
+ }),
377
+ };
378
+ }
379
+ export function createTelegramPromptDispatchLifecycle(deps) {
380
+ return {
381
+ onPromptDispatchStart: (ctx, chatId) => {
382
+ deps.lifecycle.setDispatchPending(true);
383
+ deps.startTypingLoop(ctx, chatId);
384
+ updateTelegramRuntimeStatusSafely(deps.updateStatus, ctx, {
385
+ category: "dispatch",
386
+ phase: "status-update",
387
+ recordRuntimeEvent: deps.recordRuntimeEvent,
388
+ });
389
+ },
390
+ onPromptDispatchFailure: (ctx, message) => {
391
+ deps.lifecycle.clearDispatchPending();
392
+ deps.typing.stop();
393
+ deps.recordRuntimeEvent?.("dispatch", new Error(message));
394
+ updateTelegramRuntimeStatusSafely(deps.updateStatus, ctx, {
395
+ error: `dispatch failed: ${message}`,
396
+ category: "dispatch",
397
+ phase: "status-update",
398
+ recordRuntimeEvent: deps.recordRuntimeEvent,
399
+ });
400
+ },
401
+ };
402
+ }