@xopcai/xopc 0.0.99 → 0.0.100

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 (349) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/src/account-manager.d.ts +3 -3
  3. package/dist/extensions/telegram/src/account-manager.js +8 -8
  4. package/dist/extensions/telegram/src/account-manager.js.map +1 -1
  5. package/dist/extensions/telegram/src/actions/message-actions.d.ts +4 -0
  6. package/dist/extensions/telegram/src/actions/message-actions.js +71 -0
  7. package/dist/extensions/telegram/src/actions/message-actions.js.map +1 -0
  8. package/dist/extensions/telegram/src/adapters/config-adapter.js +9 -1
  9. package/dist/extensions/telegram/src/adapters/config-adapter.js.map +1 -1
  10. package/dist/extensions/telegram/src/adapters/config-surface.js +1 -1
  11. package/dist/extensions/telegram/src/adapters/config-surface.js.map +1 -1
  12. package/dist/extensions/telegram/src/adapters/outbound-adapter.d.ts +2 -1
  13. package/dist/extensions/telegram/src/adapters/outbound-adapter.js +18 -4
  14. package/dist/extensions/telegram/src/adapters/outbound-adapter.js.map +1 -1
  15. package/dist/extensions/telegram/src/adapters/security-adapter.js +2 -1
  16. package/dist/extensions/telegram/src/adapters/security-adapter.js.map +1 -1
  17. package/dist/extensions/telegram/src/adapters/streaming-adapter.js +90 -6
  18. package/dist/extensions/telegram/src/adapters/streaming-adapter.js.map +1 -1
  19. package/dist/extensions/telegram/src/adapters/types.d.ts +9 -1
  20. package/dist/extensions/telegram/src/api-root.d.ts +4 -0
  21. package/dist/extensions/telegram/src/api-root.js +42 -0
  22. package/dist/extensions/telegram/src/api-root.js.map +1 -0
  23. package/dist/extensions/telegram/src/approval-delivery.d.ts +9 -0
  24. package/dist/extensions/telegram/src/approval-delivery.js +36 -0
  25. package/dist/extensions/telegram/src/approval-delivery.js.map +1 -0
  26. package/dist/extensions/telegram/src/approval-store.d.ts +25 -0
  27. package/dist/extensions/telegram/src/approval-store.js +61 -0
  28. package/dist/extensions/telegram/src/approval-store.js.map +1 -0
  29. package/dist/extensions/telegram/src/config-schema.d.ts +185 -35
  30. package/dist/extensions/telegram/src/config-schema.js +67 -45
  31. package/dist/extensions/telegram/src/config-schema.js.map +1 -1
  32. package/dist/extensions/telegram/src/conversation-id.d.ts +6 -0
  33. package/dist/extensions/telegram/src/conversation-id.js +18 -0
  34. package/dist/extensions/telegram/src/conversation-id.js.map +1 -0
  35. package/dist/extensions/telegram/src/doctor.d.ts +5 -0
  36. package/dist/extensions/telegram/src/doctor.js +80 -0
  37. package/dist/extensions/telegram/src/doctor.js.map +1 -0
  38. package/dist/extensions/telegram/src/exec-approval-handler.d.ts +7 -0
  39. package/dist/extensions/telegram/src/exec-approval-handler.js +36 -0
  40. package/dist/extensions/telegram/src/exec-approval-handler.js.map +1 -0
  41. package/dist/extensions/telegram/src/exec-approvals.d.ts +8 -0
  42. package/dist/extensions/telegram/src/exec-approvals.js +20 -0
  43. package/dist/extensions/telegram/src/exec-approvals.js.map +1 -0
  44. package/dist/extensions/telegram/src/focus-handler.d.ts +12 -0
  45. package/dist/extensions/telegram/src/focus-handler.js +55 -0
  46. package/dist/extensions/telegram/src/focus-handler.js.map +1 -0
  47. package/dist/extensions/telegram/src/group-config-resolver.d.ts +12 -0
  48. package/dist/extensions/telegram/src/group-config-resolver.js +17 -0
  49. package/dist/extensions/telegram/src/group-config-resolver.js.map +1 -0
  50. package/dist/extensions/telegram/src/inbound-coalescer.d.ts +15 -0
  51. package/dist/extensions/telegram/src/inbound-coalescer.js +107 -0
  52. package/dist/extensions/telegram/src/inbound-coalescer.js.map +1 -0
  53. package/dist/extensions/telegram/src/inbound-processor.d.ts +1 -0
  54. package/dist/extensions/telegram/src/inbound-processor.js +41 -4
  55. package/dist/extensions/telegram/src/inbound-processor.js.map +1 -1
  56. package/dist/extensions/telegram/src/network-errors.d.ts +2 -0
  57. package/dist/extensions/telegram/src/network-errors.js +23 -0
  58. package/dist/extensions/telegram/src/network-errors.js.map +1 -0
  59. package/dist/extensions/telegram/src/plugin.d.ts +11 -0
  60. package/dist/extensions/telegram/src/plugin.js +191 -57
  61. package/dist/extensions/telegram/src/plugin.js.map +1 -1
  62. package/dist/extensions/telegram/src/polling-session.d.ts +17 -0
  63. package/dist/extensions/telegram/src/polling-session.js +112 -0
  64. package/dist/extensions/telegram/src/polling-session.js.map +1 -0
  65. package/dist/extensions/telegram/src/proxy-fetch.d.ts +2 -0
  66. package/dist/extensions/telegram/src/proxy-fetch.js +14 -0
  67. package/dist/extensions/telegram/src/proxy-fetch.js.map +1 -0
  68. package/dist/extensions/telegram/src/reactions.d.ts +14 -0
  69. package/dist/extensions/telegram/src/reactions.js +48 -0
  70. package/dist/extensions/telegram/src/reactions.js.map +1 -0
  71. package/dist/extensions/telegram/src/reply-params.d.ts +15 -0
  72. package/dist/extensions/telegram/src/reply-params.js +28 -0
  73. package/dist/extensions/telegram/src/reply-params.js.map +1 -0
  74. package/dist/extensions/telegram/src/startup-errors.d.ts +3 -0
  75. package/dist/extensions/telegram/src/startup-errors.js +27 -0
  76. package/dist/extensions/telegram/src/startup-errors.js.map +1 -0
  77. package/dist/extensions/telegram/src/telegram-actions.d.ts +25 -0
  78. package/dist/extensions/telegram/src/telegram-actions.js +65 -0
  79. package/dist/extensions/telegram/src/telegram-actions.js.map +1 -0
  80. package/dist/extensions/telegram/src/thread-bindings.d.ts +15 -0
  81. package/dist/extensions/telegram/src/thread-bindings.js +22 -0
  82. package/dist/extensions/telegram/src/thread-bindings.js.map +1 -0
  83. package/dist/extensions/telegram/src/token-resolver.d.ts +8 -0
  84. package/dist/extensions/telegram/src/token-resolver.js +34 -0
  85. package/dist/extensions/telegram/src/token-resolver.js.map +1 -0
  86. package/dist/extensions/telegram/src/update-offset-store.d.ts +9 -0
  87. package/dist/extensions/telegram/src/update-offset-store.js +66 -0
  88. package/dist/extensions/telegram/src/update-offset-store.js.map +1 -0
  89. package/dist/extensions/telegram/xopc.extension.json +1 -1
  90. package/dist/gateway/static/root/assets/{agents-4KTK-Ku7.js → agents-C5jtBK-H.js} +1 -1
  91. package/dist/gateway/static/root/assets/{apps-page-DkgInY2w.js → apps-page-smJl-qf_.js} +1 -1
  92. package/dist/gateway/static/root/assets/channels-settings-CH6KgFK6.js +1 -0
  93. package/dist/gateway/static/root/assets/channels-status-swr-CV70xvY7.js +8 -0
  94. package/dist/gateway/static/root/assets/{cron-api-BRDli2Mm.js → cron-api-CgBO8B7I.js} +1 -1
  95. package/dist/gateway/static/root/assets/{cron-page-BzEr5Za8.js → cron-page-Be0cW1cR.js} +1 -1
  96. package/dist/gateway/static/root/assets/{dist-BsHh1vX0.js → dist-P8HRGUuh.js} +1 -1
  97. package/dist/gateway/static/root/assets/{extension-debug-page-TWt5q_ef.js → extension-debug-page-BowuycYu.js} +1 -1
  98. package/dist/gateway/static/root/assets/{extension-page-C3kV8ZvZ.js → extension-page-27-Zpv8O.js} +1 -1
  99. package/dist/gateway/static/root/assets/{extension-settings-page-Csy9LNC6.js → extension-settings-page-DDFa_rIq.js} +1 -1
  100. package/dist/gateway/static/root/assets/{fetch-BLLOP2CM.js → fetch-drJUxxKP.js} +1 -1
  101. package/dist/gateway/static/root/assets/{field-primitives-MXbM8HvY.js → field-primitives-BWLssxEb.js} +1 -1
  102. package/dist/gateway/static/root/assets/{heartbeat-config-api-CkoyqfRx.js → heartbeat-config-api-BVuYNYT_.js} +1 -1
  103. package/dist/gateway/static/root/assets/index-CRDAmr3W.js +4840 -0
  104. package/dist/gateway/static/root/assets/index-DjNDHzwG.css +1 -0
  105. package/dist/gateway/static/root/assets/{logs-page-B2vY41ph.js → logs-page-BDX8IrDQ.js} +1 -1
  106. package/dist/gateway/static/root/assets/{note-detail-page-B7qE5pkO.js → note-detail-page-BmQ9KeiA.js} +1 -1
  107. package/dist/gateway/static/root/assets/{note-time-NBBReVR4.js → note-time-14I9Sgqh.js} +1 -1
  108. package/dist/gateway/static/root/assets/{notes-page-CsWYaqYM.js → notes-page-BMfP0FFf.js} +1 -1
  109. package/dist/gateway/static/root/assets/{sessions-page-BPGY3SCT.js → sessions-page-C3scyChq.js} +1 -1
  110. package/dist/gateway/static/root/assets/{settings-advanced-gate-DtA451RM.js → settings-advanced-gate-2ODuCjHP.js} +1 -1
  111. package/dist/gateway/static/root/assets/{settings-form-section-DYR_SPlX.js → settings-form-section-DUoGKAiW.js} +1 -1
  112. package/dist/gateway/static/root/assets/{settings-page-BJUgZQzN.js → settings-page-CttAfOWV.js} +1 -1
  113. package/dist/gateway/static/root/assets/{share-preview-page-3u8VFmdo.js → share-preview-page-B77xqiiI.js} +1 -1
  114. package/dist/gateway/static/root/assets/{skills-page-DuyhcH4U.js → skills-page-B_bAZGzB.js} +1 -1
  115. package/dist/gateway/static/root/assets/{theme-store-e2q2yjs4.js → theme-store-BgCPrmxU.js} +1 -1
  116. package/dist/gateway/static/root/assets/url-q28QhI7l.js +3 -0
  117. package/dist/gateway/static/root/assets/{utils-B4Vw3fnc.js → utils-CCGejlcX.js} +1 -1
  118. package/dist/gateway/static/root/assets/{voice-api-key-field-BFY67Hhp.js → voice-api-key-field-DZzzihcY.js} +1 -1
  119. package/dist/gateway/static/root/assets/{workflow-page.utils-yUJ5jexd.js → workflow-page.utils-D5RMAmT4.js} +1 -1
  120. package/dist/gateway/static/root/assets/{workflows-page-DIMHCpNt.js → workflows-page-DEYpC6Bv.js} +1 -1
  121. package/dist/gateway/static/root/index.html +5 -5
  122. package/dist/package.js +1 -1
  123. package/dist/src/agent/agent-manager.d.ts +4 -0
  124. package/dist/src/agent/agent-manager.js +68 -4
  125. package/dist/src/agent/agent-manager.js.map +1 -1
  126. package/dist/src/agent/child-agent-factory.d.ts +1 -0
  127. package/dist/src/agent/child-agent-factory.js +13 -10
  128. package/dist/src/agent/child-agent-factory.js.map +1 -1
  129. package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
  130. package/dist/src/agent/embedded/run-for-session.js +1 -0
  131. package/dist/src/agent/embedded/run-for-session.js.map +1 -1
  132. package/dist/src/agent/embedded/run-turn.js +1 -17
  133. package/dist/src/agent/embedded/run-turn.js.map +1 -1
  134. package/dist/src/agent/embedded/session-runner.js +3 -1
  135. package/dist/src/agent/embedded/session-runner.js.map +1 -1
  136. package/dist/src/agent/embedded/session-tool-result-guard.d.ts +1 -0
  137. package/dist/src/agent/embedded/session-tool-result-guard.js +1 -0
  138. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  139. package/dist/src/agent/inbound/attachment-pipeline.d.ts +37 -0
  140. package/dist/src/agent/inbound/attachment-pipeline.js +169 -0
  141. package/dist/src/agent/inbound/attachment-pipeline.js.map +1 -0
  142. package/dist/src/agent/inbound/turn-dispatcher.d.ts +3 -5
  143. package/dist/src/agent/inbound/turn-dispatcher.js +1 -2
  144. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
  145. package/dist/src/agent/memory/index.d.ts +2 -0
  146. package/dist/src/agent/memory/index.js +2 -1
  147. package/dist/src/agent/memory/memory-flush.d.ts +27 -0
  148. package/dist/src/agent/memory/memory-flush.js +124 -0
  149. package/dist/src/agent/memory/memory-flush.js.map +1 -0
  150. package/dist/src/agent/messaging/outbound-coordinator.js +2 -1
  151. package/dist/src/agent/messaging/outbound-coordinator.js.map +1 -1
  152. package/dist/src/agent/messaging/stream-manager.d.ts +2 -0
  153. package/dist/src/agent/messaging/stream-manager.js +3 -0
  154. package/dist/src/agent/messaging/stream-manager.js.map +1 -1
  155. package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -4
  156. package/dist/src/agent/orchestration/agent-orchestrator.js +40 -107
  157. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  158. package/dist/src/agent/prompt/contribution.d.ts +9 -0
  159. package/dist/src/agent/prompt/contribution.js +1 -0
  160. package/dist/src/agent/prompt/safety.js +0 -10
  161. package/dist/src/agent/prompt/safety.js.map +1 -1
  162. package/dist/src/agent/prompt/sanitize-for-prompt.d.ts +6 -0
  163. package/dist/src/agent/prompt/sanitize-for-prompt.js +13 -0
  164. package/dist/src/agent/prompt/sanitize-for-prompt.js.map +1 -0
  165. package/dist/src/agent/prompt/sections/behavior.d.ts +5 -0
  166. package/dist/src/agent/prompt/sections/behavior.js +50 -0
  167. package/dist/src/agent/prompt/sections/behavior.js.map +1 -0
  168. package/dist/src/agent/prompt/sections/memory-skills.d.ts +9 -0
  169. package/dist/src/agent/prompt/sections/memory-skills.js +59 -0
  170. package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -0
  171. package/dist/src/agent/prompt/sections/messaging-runtime.d.ts +16 -0
  172. package/dist/src/agent/prompt/sections/messaging-runtime.js +69 -0
  173. package/dist/src/agent/prompt/sections/messaging-runtime.js.map +1 -0
  174. package/dist/src/agent/prompt/sections/project-context.d.ts +16 -0
  175. package/dist/src/agent/prompt/sections/project-context.js +58 -0
  176. package/dist/src/agent/prompt/sections/project-context.js.map +1 -0
  177. package/dist/src/agent/prompt/sections/tooling.d.ts +5 -0
  178. package/dist/src/agent/prompt/sections/tooling.js +119 -0
  179. package/dist/src/agent/prompt/sections/tooling.js.map +1 -0
  180. package/dist/src/agent/prompt/sections/workspace-runtime.d.ts +11 -0
  181. package/dist/src/agent/prompt/sections/workspace-runtime.js +32 -0
  182. package/dist/src/agent/prompt/sections/workspace-runtime.js.map +1 -0
  183. package/dist/src/agent/prompt/service-prompt-builder.d.ts +13 -0
  184. package/dist/src/agent/prompt/service-prompt-builder.js +54 -13
  185. package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
  186. package/dist/src/agent/prompt/subagent-context.d.ts +15 -0
  187. package/dist/src/agent/prompt/subagent-context.js +68 -0
  188. package/dist/src/agent/prompt/subagent-context.js.map +1 -0
  189. package/dist/src/agent/prompt/system-prompt-params.d.ts +53 -0
  190. package/dist/src/agent/prompt/system-prompt-params.js +74 -0
  191. package/dist/src/agent/prompt/system-prompt-params.js.map +1 -0
  192. package/dist/src/agent/prompt/system-prompt.d.ts +22 -11
  193. package/dist/src/agent/prompt/system-prompt.js +79 -193
  194. package/dist/src/agent/prompt/system-prompt.js.map +1 -1
  195. package/dist/src/agent/prompt/types.d.ts +3 -0
  196. package/dist/src/agent/service/build-direct-message-content.d.ts +5 -21
  197. package/dist/src/agent/service/build-direct-message-content.js +11 -64
  198. package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
  199. package/dist/src/agent/service/direct-turn-helpers.d.ts +1 -1
  200. package/dist/src/agent/service/direct-turn-helpers.js +7 -0
  201. package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
  202. package/dist/src/agent/service/process-direct-one-shot.d.ts +3 -3
  203. package/dist/src/agent/service/process-direct-one-shot.js +22 -17
  204. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  205. package/dist/src/agent/service/process-direct-streaming.d.ts +6 -20
  206. package/dist/src/agent/service/process-direct-streaming.js +39 -40
  207. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  208. package/dist/src/agent/service/webchat-tts.d.ts +4 -9
  209. package/dist/src/agent/service/webchat-tts.js +9 -20
  210. package/dist/src/agent/service/webchat-tts.js.map +1 -1
  211. package/dist/src/agent/service.d.ts +8 -19
  212. package/dist/src/agent/service.js +53 -11
  213. package/dist/src/agent/service.js.map +1 -1
  214. package/dist/src/agent/tools/factory.js +2 -0
  215. package/dist/src/agent/tools/factory.js.map +1 -1
  216. package/dist/src/agent/tools/index.d.ts +1 -0
  217. package/dist/src/agent/tools/index.js +2 -1
  218. package/dist/src/agent/tools/media-read-tool.d.ts +2 -0
  219. package/dist/src/agent/tools/media-read-tool.js +89 -0
  220. package/dist/src/agent/tools/media-read-tool.js.map +1 -0
  221. package/dist/src/channels/attachments/attachment-classifiers.d.ts +8 -0
  222. package/dist/src/channels/attachments/attachment-classifiers.js +11 -0
  223. package/dist/src/channels/attachments/attachment-classifiers.js.map +1 -0
  224. package/dist/src/channels/attachments/inbound-persist.d.ts +13 -34
  225. package/dist/src/channels/attachments/inbound-persist.js +34 -102
  226. package/dist/src/channels/attachments/inbound-persist.js.map +1 -1
  227. package/dist/src/channels/attachments/inbound-types.d.ts +13 -0
  228. package/dist/src/channels/attachments/inbound-types.js +30 -0
  229. package/dist/src/channels/attachments/inbound-types.js.map +1 -0
  230. package/dist/src/channels/attachments/outbound-tts-persist.d.ts +3 -12
  231. package/dist/src/channels/attachments/outbound-tts-persist.js +28 -48
  232. package/dist/src/channels/attachments/outbound-tts-persist.js.map +1 -1
  233. package/dist/src/channels/attachments/voice-stt-webchat.d.ts +3 -3
  234. package/dist/src/channels/attachments/voice-stt-webchat.js +8 -14
  235. package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
  236. package/dist/src/channels/channel-domain.d.ts +30 -2
  237. package/dist/src/channels/exec-approval-runtime.d.ts +29 -0
  238. package/dist/src/channels/exec-approval-runtime.js +30 -0
  239. package/dist/src/channels/exec-approval-runtime.js.map +1 -0
  240. package/dist/src/channels/index.js +1 -1
  241. package/dist/src/channels/plugin-types.d.ts +1 -0
  242. package/dist/src/channels/transport-types.d.ts +2 -2
  243. package/dist/src/cli/commands/channels.js +1 -1
  244. package/dist/src/cli/commands/doctor/checks/database-schema.d.ts +2 -0
  245. package/dist/src/cli/commands/doctor/checks/database-schema.js +62 -0
  246. package/dist/src/cli/commands/doctor/checks/database-schema.js.map +1 -0
  247. package/dist/src/cli/commands/doctor/flow.js +2 -0
  248. package/dist/src/cli/commands/doctor/flow.js.map +1 -1
  249. package/dist/src/cli/commands/init.js +2 -57
  250. package/dist/src/cli/commands/init.js.map +1 -1
  251. package/dist/src/cli/commands/onboard/channels/registry.js +1 -1
  252. package/dist/src/cli/commands/setup.js +6 -5
  253. package/dist/src/cli/commands/setup.js.map +1 -1
  254. package/dist/src/cli/utils/init-workspace-core.js +1 -2
  255. package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
  256. package/dist/src/config/index.js +2 -2
  257. package/dist/src/config/paths.d.ts +0 -13
  258. package/dist/src/config/paths.js +1 -20
  259. package/dist/src/config/paths.js.map +1 -1
  260. package/dist/src/config/rules.js +1 -1
  261. package/dist/src/config/schema.d.ts +24 -0
  262. package/dist/src/config/schema.js +33 -2
  263. package/dist/src/config/schema.js.map +1 -1
  264. package/dist/src/cron/executor.js +2 -2
  265. package/dist/src/gateway/heartbeat/service.js +1 -1
  266. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  267. package/dist/src/gateway/hono/routes/config-patch/channels.js +3 -3
  268. package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
  269. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  270. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  271. package/dist/src/gateway/hono/routes/media.d.ts +3 -0
  272. package/dist/src/gateway/hono/routes/media.js +50 -0
  273. package/dist/src/gateway/hono/routes/media.js.map +1 -0
  274. package/dist/src/gateway/hono/routes/sessions.js +6 -0
  275. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  276. package/dist/src/gateway/hono/routes/workspace.js +1 -87
  277. package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
  278. package/dist/src/gateway/service/sessions-api.js +3 -0
  279. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  280. package/dist/src/heartbeat/index.js +1 -1
  281. package/dist/src/media/index.d.ts +5 -0
  282. package/dist/src/media/index.js +5 -0
  283. package/dist/src/media/media-reference.d.ts +23 -0
  284. package/dist/src/media/media-reference.js +34 -0
  285. package/dist/src/media/media-reference.js.map +1 -0
  286. package/dist/src/media/paths.d.ts +5 -0
  287. package/dist/src/media/paths.js +20 -0
  288. package/dist/src/media/paths.js.map +1 -0
  289. package/dist/src/media/session-references.d.ts +8 -0
  290. package/dist/src/media/session-references.js +45 -0
  291. package/dist/src/media/session-references.js.map +1 -0
  292. package/dist/src/media/store.d.ts +19 -0
  293. package/dist/src/media/store.js +131 -0
  294. package/dist/src/media/store.js.map +1 -0
  295. package/dist/src/media/types.d.ts +34 -0
  296. package/dist/src/media/types.js +1 -0
  297. package/dist/src/media/uri.d.ts +15 -0
  298. package/dist/src/media/uri.js +51 -0
  299. package/dist/src/media/uri.js.map +1 -0
  300. package/dist/src/session/session-title.js +6 -3
  301. package/dist/src/session/session-title.js.map +1 -1
  302. package/dist/src/session/store.js +1 -1
  303. package/dist/src/session/store.js.map +1 -1
  304. package/dist/src/session/types.d.ts +12 -7
  305. package/dist/src/session/types.js.map +1 -1
  306. package/dist/src/storage/sqlite/index.d.ts +4 -1
  307. package/dist/src/storage/sqlite/index.js +6 -2
  308. package/dist/src/storage/sqlite/migrations/002_add_flush_columns.sql +3 -0
  309. package/dist/src/storage/sqlite/migrations/discover.d.ts +4 -0
  310. package/dist/src/storage/sqlite/migrations/discover.js +38 -0
  311. package/dist/src/storage/sqlite/migrations/discover.js.map +1 -0
  312. package/dist/src/storage/sqlite/migrations/discover.ts +52 -0
  313. package/dist/src/storage/sqlite/migrations/errors.d.ts +11 -0
  314. package/dist/src/storage/sqlite/migrations/errors.js +27 -0
  315. package/dist/src/storage/sqlite/migrations/errors.js.map +1 -0
  316. package/dist/src/storage/sqlite/migrations/errors.ts +32 -0
  317. package/dist/src/storage/sqlite/migrations/runner.d.ts +22 -0
  318. package/dist/src/storage/sqlite/migrations/runner.js +97 -0
  319. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -0
  320. package/dist/src/storage/sqlite/migrations/runner.ts +153 -0
  321. package/dist/src/storage/sqlite/migrations/types.d.ts +12 -0
  322. package/dist/src/storage/sqlite/migrations/types.js +1 -0
  323. package/dist/src/storage/sqlite/migrations/types.ts +13 -0
  324. package/dist/src/storage/sqlite/row-mappers.d.ts +4 -0
  325. package/dist/src/storage/sqlite/row-mappers.js +4 -0
  326. package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
  327. package/dist/src/storage/sqlite/schema-version.d.ts +6 -0
  328. package/dist/src/storage/sqlite/schema-version.js +29 -0
  329. package/dist/src/storage/sqlite/schema-version.js.map +1 -0
  330. package/dist/src/storage/sqlite/schema.d.ts +5 -3
  331. package/dist/src/storage/sqlite/schema.js +24 -28
  332. package/dist/src/storage/sqlite/schema.js.map +1 -1
  333. package/dist/src/storage/sqlite/schema.sql +2 -0
  334. package/dist/src/storage/sqlite/session-metadata.js +1 -0
  335. package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
  336. package/dist/src/storage/sqlite/session-repository.js +7 -3
  337. package/dist/src/storage/sqlite/session-repository.js.map +1 -1
  338. package/package.json +1 -1
  339. package/dist/gateway/static/root/assets/channels-settings-BxW1Xio4.js +0 -1
  340. package/dist/gateway/static/root/assets/channels-status-swr-Cxm6AvQO.js +0 -8
  341. package/dist/gateway/static/root/assets/index-BJDmBCSl.css +0 -1
  342. package/dist/gateway/static/root/assets/index-Cbg5TS5m.js +0 -4707
  343. package/dist/gateway/static/root/assets/url-DpFBIyN9.js +0 -3
  344. package/dist/src/cli/commands/onboard/workspace.d.ts +0 -14
  345. package/dist/src/cli/commands/onboard/workspace.js +0 -33
  346. package/dist/src/cli/commands/onboard/workspace.js.map +0 -1
  347. package/dist/src/cli/utils/workspace.d.ts +0 -35
  348. package/dist/src/cli/utils/workspace.js +0 -72
  349. package/dist/src/cli/utils/workspace.js.map +0 -1
@@ -1,9 +1,15 @@
1
+ import { resolveRoute } from "../../../src/routing/resolve-route.js";
1
2
  import { createLogger } from "../../../src/utils/logger/index.js";
2
3
  import { init_logger } from "../../../src/utils/logger.js";
3
4
  import { normalizeTelegramCommandName, parseSlashCommand } from "../../../src/chat-commands/command-parse.js";
4
5
  import { checkMentionInTranscription } from "../../../src/voice/stt/preflight.js";
6
+ import "../../../src/voice/stt/index.js";
5
7
  import { tryConsumeTelegramClarifyFreeText } from "../../../src/gateway/clarify-runtime.js";
6
8
  import { buildTelegramUpdateKey, telegramUpdateDedupe } from "./dedupe.js";
9
+ import "../../../src/routing/index.js";
10
+ import { resolveTelegramGroupContext } from "./group-config-resolver.js";
11
+ import { buildTelegramConversationId } from "./conversation-id.js";
12
+ import { resolveTelegramFocusedSessionKey } from "./focus-handler.js";
7
13
  //#region extensions/telegram/src/inbound-processor.ts
8
14
  init_logger();
9
15
  const log = createLogger("TelegramInboundProcessor");
@@ -41,6 +47,11 @@ function extractMediaItems(message) {
41
47
  type: "voice",
42
48
  fileId: message.voice.file_id
43
49
  });
50
+ if (message.sticker) media.push({
51
+ type: "sticker",
52
+ fileId: message.sticker.file_id,
53
+ emoji: message.sticker.emoji
54
+ });
44
55
  return media;
45
56
  }
46
57
  /**
@@ -196,7 +207,7 @@ function createInboundProcessor(deps) {
196
207
  log.warn({ accountId }, "Bot username not available");
197
208
  return;
198
209
  }
199
- const message = ctx.message;
210
+ const message = ctx.message ?? ctx.channelPost;
200
211
  if (!message) return;
201
212
  const chatId = String(ctx.chat?.id);
202
213
  const senderId = String(ctx.from?.id);
@@ -277,14 +288,35 @@ function createInboundProcessor(deps) {
277
288
  }
278
289
  }
279
290
  const cleanContent = isGroup ? accessControl.removeBotMention(content, botUsername) : content;
280
- const sessionKey = sessionKeyService.generateSessionKey({
291
+ const groupCtx = resolveTelegramGroupContext({
292
+ account,
293
+ chatId,
294
+ threadId
295
+ });
296
+ const route = resolveRoute({
297
+ config,
298
+ channel: "telegram",
299
+ accountId,
300
+ peerKind: isGroup ? "group" : "dm",
301
+ peerId: isGroup ? chatId : senderId,
302
+ threadId: threadId ? String(threadId) : null
303
+ });
304
+ const routedAgentId = groupCtx.agentId ?? route.agentId;
305
+ const defaultSessionKey = sessionKeyService.generateSessionKey({
281
306
  source: "telegram",
282
307
  chatId,
283
308
  senderId,
284
309
  isGroup,
285
310
  threadId: threadId ? String(threadId) : void 0,
286
- accountId
311
+ accountId,
312
+ agentId: routedAgentId
313
+ });
314
+ const sessionKey = resolveTelegramFocusedSessionKey({
315
+ chatId,
316
+ threadId: threadId ? String(threadId) : void 0,
317
+ defaultSessionKey
287
318
  });
319
+ const conversationId = buildTelegramConversationId(chatId, threadId);
288
320
  const media = extractMediaItems(message);
289
321
  const bot = accountManager.getBot(accountId);
290
322
  const botToken = account.botToken;
@@ -296,7 +328,9 @@ function createInboundProcessor(deps) {
296
328
  transcribedText = mediaResult.transcribedText;
297
329
  }
298
330
  const captionIsCommand = cleanContent.trim().startsWith("/");
299
- const finalContent = transcribedText ? captionIsCommand && cleanContent ? cleanContent.trim() + (transcribedText ? `\n\n${transcribedText}` : "") : transcribedText + (cleanContent ? "\n\n" + cleanContent : "") : cleanContent;
331
+ let finalContent = transcribedText ? captionIsCommand && cleanContent ? cleanContent.trim() + (transcribedText ? `\n\n${transcribedText}` : "") : transcribedText + (cleanContent ? "\n\n" + cleanContent : "") : cleanContent;
332
+ const stickerItem = media.find((m) => m.type === "sticker");
333
+ if (stickerItem && !finalContent.trim()) finalContent = stickerItem.emoji?.trim() ? `[Sticker ${stickerItem.emoji}]` : "[Sticker]";
300
334
  const isCommand = cleanContent.trim().startsWith("/");
301
335
  log.info({
302
336
  accountId,
@@ -325,6 +359,9 @@ function createInboundProcessor(deps) {
325
359
  isGroup,
326
360
  isCommand,
327
361
  threadId: threadId ? String(threadId) : void 0,
362
+ conversationId,
363
+ channelSystemPrompt: groupCtx.systemPrompt,
364
+ channelAgentId: routedAgentId,
328
365
  media: media.length > 0 ? media : void 0,
329
366
  transcribedVoice: !!transcribedText || void 0
330
367
  },
@@ -1 +1 @@
1
- {"version":3,"file":"inbound-processor.js","names":[],"sources":["../../../../extensions/telegram/src/inbound-processor.ts"],"sourcesContent":["/**\n * Telegram Inbound Processor\n *\n * Handles inbound message processing from Telegram:\n * - Message queuing (per chat)\n * - Deduplication\n * - Access control\n * - Media download\n * - STT transcription\n * - Event publishing to bus\n */\n\nimport type { Bot, Context } from 'grammy';\nimport type { Message } from '@grammyjs/types';\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { MessageBus } from '@xopcai/xopc/infra/bus/index.js';\nimport type { TelegramAccountManager } from './account-manager.js';\nimport { telegramUpdateDedupe, buildTelegramUpdateKey } from './dedupe.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\nimport { normalizeTelegramCommandName, parseSlashCommand } from '@xopcai/xopc/chat-commands/command-parse.js';\nimport { tryConsumeTelegramClarifyFreeText } from '@xopcai/xopc/gateway/clarify-runtime.js';\nimport { checkMentionInTranscription } from '@xopcai/xopc/voice/stt/preflight.js';\n\nconst log = createLogger('TelegramInboundProcessor');\n\n/** Must bypass the per-chat queue so /abort can cancel an in-flight turn. */\nfunction isAbortSlashCommand(text: string): boolean {\n const parsed = parseSlashCommand(text);\n if (!parsed) return false;\n const cmd = normalizeTelegramCommandName(parsed.command);\n return cmd === 'abort' || cmd === 'stop' || cmd === 'cancel';\n}\n\n/** Maximum voice message duration for STT in seconds */\nconst STT_MAX_VOICE_DURATION_SECONDS = 60;\n\n// =============================================================================\n// External Service Interfaces (for dependency injection)\n// =============================================================================\n\nexport interface AccessControlService {\n normalizeAllowFromWithStore(options: { allowFrom?: Array<string | number> }): unknown;\n evaluateGroupBaseAccess(options: {\n isGroup: boolean;\n groupConfig?: unknown;\n topicConfig?: unknown;\n hasGroupAllowOverride: boolean;\n effectiveGroupAllow: unknown;\n senderId?: string;\n senderUsername?: string;\n }): { allowed: boolean; reason?: string };\n resolveRequireMention(options: {\n topicConfig?: unknown;\n groupConfig?: unknown;\n defaultRequireMention?: boolean;\n }): boolean;\n hasBotMention(options: { botUsername: string; text?: string; entities?: unknown }): boolean;\n removeBotMention(text: string, botUsername: string): string;\n}\n\nexport interface SessionKeyService {\n generateSessionKey(options: {\n source: string;\n chatId: string;\n senderId: string;\n isGroup: boolean;\n threadId?: string;\n accountId?: string;\n }): string;\n}\n\nexport interface STTService {\n transcribe(buffer: Buffer, config: unknown, options?: { language?: string }): Promise<{ text: string }>;\n isSTTAvailable(config: unknown): boolean;\n}\n\nexport interface MediaUtils {\n getMimeType(type: string, filePath?: string): string;\n}\n\n// =============================================================================\n// Dependencies Interface\n// =============================================================================\n\nexport interface InboundProcessorDeps {\n bus: MessageBus;\n config: Config;\n accountManager: TelegramAccountManager;\n // External services (injected for testability)\n accessControl: AccessControlService;\n sessionKeyService: SessionKeyService;\n sttService: STTService;\n mediaUtils: MediaUtils;\n}\n\ninterface QueuedMessage {\n ctx: Context;\n accountId: string;\n resolve: () => void;\n reject: (err: Error) => void;\n}\n\n// =============================================================================\n// Media Processing Types\n// =============================================================================\n\ninterface MediaItem {\n type: string;\n fileId: string;\n}\n\ninterface ProcessedAttachment {\n type: string;\n mimeType: string;\n data: string;\n name?: string;\n size?: number;\n}\n\n// =============================================================================\n// Helper Functions (reduce nesting in main processor)\n// =============================================================================\n\n/**\n * Extract media items from message\n */\nfunction extractMediaItems(message: Message): MediaItem[] {\n const media: MediaItem[] = [];\n \n if (message.photo?.length) {\n media.push({ type: 'photo', fileId: message.photo[message.photo.length - 1].file_id });\n }\n if (message.document) {\n media.push({ type: 'document', fileId: message.document.file_id });\n }\n if (message.video) {\n media.push({ type: 'video', fileId: message.video.file_id });\n }\n if (message.audio) {\n media.push({ type: 'audio', fileId: message.audio.file_id });\n }\n if (message.voice) {\n media.push({ type: 'voice', fileId: message.voice.file_id });\n }\n \n return media;\n}\n\n/**\n * Download + STT a Telegram voice message (for mention probe or media pipeline).\n */\nasync function downloadAndTranscribeTelegramVoice(params: {\n voice: NonNullable<Message['voice']>;\n bot: Bot;\n botToken: string;\n accountApiRoot: string;\n sttService: STTService;\n sttConfig: unknown;\n}): Promise<string> {\n const { voice, bot, botToken, accountApiRoot, sttService, sttConfig } = params;\n const voiceDuration = voice.duration || 0;\n if (voiceDuration > STT_MAX_VOICE_DURATION_SECONDS) {\n return '';\n }\n if (!sttService.isSTTAvailable(sttConfig)) {\n return '';\n }\n try {\n const file = await bot.api.getFile(voice.file_id);\n const downloadUrl = `${accountApiRoot}/file/bot${botToken}/${file.file_path}`;\n const response = await fetch(downloadUrl);\n if (!response.ok) {\n return '';\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n if (buffer.length === 0) {\n return '';\n }\n const sttResult = await sttService.transcribe(buffer, sttConfig, {\n language: (sttConfig as { provider?: string })?.provider === 'alibaba' ? 'zh' : undefined,\n });\n return sttResult.text?.trim() ?? '';\n } catch {\n return '';\n }\n}\n\n/**\n * Process a single media item (download + optional STT)\n */\nasync function processMediaItem(\n item: MediaItem,\n bot: Bot,\n botToken: string,\n accountApiRoot: string,\n message: Message,\n sttService: STTService,\n mediaUtils: MediaUtils,\n sttConfig: unknown,\n reuseVoiceTranscript?: string,\n): Promise<{ attachment: ProcessedAttachment | null; transcribedText: string }> {\n try {\n const file = await bot.api.getFile(item.fileId);\n const downloadUrl = `${accountApiRoot}/file/bot${botToken}/${file.file_path}`;\n const response = await fetch(downloadUrl);\n\n // Debug log for media download\n log.info({\n type: item.type,\n fileId: item.fileId,\n downloadUrl,\n responseStatus: response.status,\n }, 'Media download response');\n\n if (!response.ok) {\n throw new Error(`Failed to download: ${response.status}`);\n }\n\n const buffer = await response.arrayBuffer();\n\n // Debug log for buffer size\n log.info({\n type: item.type,\n fileId: item.fileId,\n bufferSize: buffer.byteLength,\n filePath: file.file_path,\n }, 'Media buffer downloaded');\n\n if (buffer.byteLength === 0) {\n log.warn({\n type: item.type,\n fileId: item.fileId,\n filePath: file.file_path,\n }, 'Media buffer is empty, may cause issues');\n }\n let transcribedText = '';\n\n // Handle voice messages with STT\n if (item.type === 'voice' && sttService.isSTTAvailable(sttConfig)) {\n if (reuseVoiceTranscript !== undefined && reuseVoiceTranscript !== '') {\n transcribedText = reuseVoiceTranscript;\n } else {\n const voiceDuration = message.voice?.duration || 0;\n if (voiceDuration <= STT_MAX_VOICE_DURATION_SECONDS) {\n try {\n const sttResult = await sttService.transcribe(Buffer.from(buffer), sttConfig, {\n language: (sttConfig as { provider?: string })?.provider === 'alibaba' ? 'zh' : undefined,\n });\n transcribedText = sttResult.text;\n } catch (sttError) {\n log.error({ sttError }, 'STT transcription failed');\n transcribedText = '[STT failed]';\n }\n } else {\n transcribedText = `[Voice message too long (>${STT_MAX_VOICE_DURATION_SECONDS}s)]`;\n }\n }\n }\n\n const base64 = Buffer.from(buffer).toString('base64');\n const mimeType = mediaUtils.getMimeType(item.type, file.file_path);\n\n // Debug log for attachment creation\n log.info({\n type: item.type,\n mimeType,\n base64Length: base64.length,\n size: buffer.byteLength,\n name: file.file_path?.split('/').pop(),\n }, 'Attachment created');\n\n return {\n attachment: {\n type: item.type,\n mimeType,\n data: base64,\n name: file.file_path?.split('/').pop(),\n size: buffer.byteLength,\n },\n transcribedText,\n };\n } catch (err) {\n log.error({ type: item.type, fileId: item.fileId, err }, 'Failed to download media');\n return { attachment: null, transcribedText: '' };\n }\n}\n\n/**\n * Process all media items\n */\nasync function processAllMedia(\n media: MediaItem[],\n bot: Bot,\n botToken: string,\n accountApiRoot: string,\n message: Message,\n sttService: STTService,\n mediaUtils: MediaUtils,\n sttConfig: unknown,\n reuseVoiceTranscript?: string,\n): Promise<{ attachments: ProcessedAttachment[]; transcribedText: string }> {\n const attachments: ProcessedAttachment[] = [];\n let transcribedText = '';\n let voiceReuseConsumed = false;\n\n for (const item of media) {\n const reuse =\n item.type === 'voice' && reuseVoiceTranscript && !voiceReuseConsumed\n ? reuseVoiceTranscript\n : undefined;\n if (reuse) {\n voiceReuseConsumed = true;\n }\n const result = await processMediaItem(\n item,\n bot,\n botToken,\n accountApiRoot,\n message,\n sttService,\n mediaUtils,\n sttConfig,\n reuse,\n );\n \n if (result.attachment) {\n attachments.push(result.attachment);\n }\n if (result.transcribedText) {\n transcribedText = result.transcribedText;\n }\n }\n\n return { attachments, transcribedText };\n}\n\n// =============================================================================\n// Main Processor Factory\n// =============================================================================\n\n/**\n * Create inbound message processor\n */\nexport function createInboundProcessor(deps: InboundProcessorDeps) {\n const {\n bus,\n config,\n accountManager,\n accessControl,\n sessionKeyService,\n sttService,\n mediaUtils,\n } = deps;\n\n const messageQueues = new Map<string, QueuedMessage[]>();\n const processingLocks = new Map<string, Promise<void>>();\n\n const getChatKey = (accountId: string, chatId: string): string => `${accountId}:${chatId}`;\n\n const processNextMessage = async (chatKey: string): Promise<void> => {\n if (processingLocks.has(chatKey)) return;\n\n const queue = messageQueues.get(chatKey);\n if (!queue || queue.length === 0) return;\n\n let lockResolve: () => void;\n const lockPromise = new Promise<void>((resolve) => {\n lockResolve = resolve;\n });\n processingLocks.set(chatKey, lockPromise);\n\n const { ctx, accountId, resolve, reject } = queue.shift()!;\n\n try {\n await processMessageInternal(ctx, accountId);\n resolve();\n } catch (err) {\n reject(err instanceof Error ? err : new Error(String(err)));\n } finally {\n lockResolve?.();\n processingLocks.delete(chatKey);\n if (queue.length > 0) {\n processNextMessage(chatKey);\n } else {\n messageQueues.delete(chatKey);\n }\n }\n };\n\n const processMessageInternal = async (ctx: Context, accountId: string) => {\n // Deduplication check\n const updateKey = buildTelegramUpdateKey(ctx);\n if (updateKey && telegramUpdateDedupe.checkAndAdd(updateKey)) {\n log.debug({ updateKey, accountId }, 'Duplicate update detected, skipping');\n return;\n }\n\n const account = accountManager.getAccount(accountId);\n if (!account) {\n log.warn({ accountId }, 'Account not found for message processing');\n return;\n }\n\n const botUsername = accountManager.getBotUsername(accountId);\n if (!botUsername) {\n log.warn({ accountId }, 'Bot username not available');\n return;\n }\n\n const message = ctx.message;\n if (!message) return;\n\n const chatId = String(ctx.chat?.id);\n const senderId = String(ctx.from?.id);\n const senderUsername = ctx.from?.username;\n const content = message.text ?? message.caption ?? '';\n const isGroup = ctx.chat?.type === 'group' || ctx.chat?.type === 'supergroup';\n const threadId = (message as { message_thread_id?: number }).message_thread_id;\n\n // Access control (group/topic allowlists, mention gating)\n const effectiveAllowFrom = accessControl.normalizeAllowFromWithStore({\n allowFrom: isGroup ? account.groupAllowFrom : account.allowFrom,\n });\n\n const baseAccess = accessControl.evaluateGroupBaseAccess({\n isGroup,\n groupConfig: account.groups?.[chatId],\n topicConfig: threadId ? account.groups?.[chatId]?.topics?.[String(threadId)] : undefined,\n hasGroupAllowOverride: !!(account.groups?.[chatId]?.allowFrom ||\n (threadId && account.groups?.[chatId]?.topics?.[String(threadId)]?.allowFrom)),\n effectiveGroupAllow: effectiveAllowFrom,\n senderId,\n senderUsername,\n });\n\n if (!baseAccess.allowed) {\n log.debug({ accountId, chatId, reason: baseAccess.reason }, 'Message blocked by base access');\n return;\n }\n\n const botEarly = accountManager.getBot(accountId);\n const botTokenEarly = account.botToken;\n const accountApiRootEarly = account.apiRoot?.replace(/\\/$/, '') || 'https://api.telegram.org';\n\n let voiceProbeText = '';\n if (\n isGroup &&\n message.voice &&\n botEarly &&\n botTokenEarly &&\n sttService.isSTTAvailable(config?.tools?.media?.audio)\n ) {\n voiceProbeText = await downloadAndTranscribeTelegramVoice({\n voice: message.voice,\n bot: botEarly,\n botToken: botTokenEarly,\n accountApiRoot: accountApiRootEarly,\n sttService,\n sttConfig: config?.tools?.media?.audio,\n });\n }\n\n if (isGroup) {\n const requireMention = accessControl.resolveRequireMention({\n topicConfig: threadId ? account.groups?.[chatId]?.topics?.[String(threadId)] : undefined,\n groupConfig: account.groups?.[chatId],\n defaultRequireMention: true,\n });\n\n const hasMedia = !!(message.photo || message.document || message.video || message.audio || message.voice);\n const captionEntities = (message as any).caption_entities;\n const voiceMention = voiceProbeText.trim();\n const hasMention =\n accessControl.hasBotMention({ botUsername, text: content, entities: message.entities }) ||\n (hasMedia &&\n accessControl.hasBotMention({\n botUsername,\n text: message.caption ?? '',\n entities: captionEntities,\n })) ||\n (voiceMention.length > 0 &&\n (accessControl.hasBotMention({ botUsername, text: voiceMention }) ||\n checkMentionInTranscription(voiceMention, [botUsername])));\n\n if (requireMention && !hasMention) {\n const isVoiceOnly =\n !!message.voice &&\n !message.photo &&\n !message.document &&\n !message.video &&\n !message.audio &&\n !(message.caption ?? '').trim() &&\n !content.trim();\n\n if (isVoiceOnly) {\n log.debug({ accountId, chatId }, 'Group voice without mention after STT probe, ignored');\n return;\n }\n\n if (!hasMedia || content.trim().length > 0) {\n log.debug({ accountId, chatId }, 'Group message without mention ignored');\n return;\n }\n log.debug({ accountId, chatId }, 'Group media message without mention - processing anyway');\n }\n }\n\n const cleanContent = isGroup ? accessControl.removeBotMention(content, botUsername) : content;\n\n // Generate session key\n const sessionKey = sessionKeyService.generateSessionKey({\n source: 'telegram',\n chatId,\n senderId,\n isGroup,\n threadId: threadId ? String(threadId) : undefined,\n accountId,\n });\n\n // Collect and process media\n const media = extractMediaItems(message);\n const bot = accountManager.getBot(accountId);\n const botToken = account.botToken;\n\n let attachments: ProcessedAttachment[] = [];\n let transcribedText = '';\n\n if (bot && botToken && media.length > 0) {\n const accountApiRoot = account.apiRoot?.replace(/\\/$/, '') || 'https://api.telegram.org';\n const mediaResult = await processAllMedia(\n media,\n bot,\n botToken,\n accountApiRoot,\n message,\n sttService,\n mediaUtils,\n config?.tools?.media?.audio,\n voiceProbeText || undefined,\n );\n attachments = mediaResult.attachments;\n transcribedText = mediaResult.transcribedText;\n }\n\n // Combine transcribed text with content. If the user caption is a slash command, put it first\n // so routing and logs match a normal `/cmd` message (STT prefix no longer hides the command).\n const captionIsCommand = cleanContent.trim().startsWith('/');\n const finalContent = transcribedText\n ? captionIsCommand && cleanContent\n ? cleanContent.trim() + (transcribedText ? `\\n\\n${transcribedText}` : '')\n : transcribedText + (cleanContent ? '\\n\\n' + cleanContent : '')\n : cleanContent;\n\n const isCommand = cleanContent.trim().startsWith('/');\n\n log.info({\n accountId,\n chatId,\n senderId,\n isGroup,\n sessionKey,\n contentLength: finalContent.length,\n attachmentCount: attachments.length,\n isCommand,\n }, 'Processing Telegram message');\n\n if (\n finalContent.trim().length > 0 &&\n !isCommand &&\n tryConsumeTelegramClarifyFreeText(sessionKey, finalContent.trim())\n ) {\n log.debug({ sessionKey }, 'Telegram: consumed message as clarify reply');\n return;\n }\n\n await bus.publishInbound({\n channel: 'telegram',\n sender_id: senderId,\n chat_id: chatId,\n content: finalContent,\n metadata: {\n accountId,\n sessionKey,\n senderUsername,\n messageId: String(message.message_id),\n isGroup,\n isCommand,\n threadId: threadId ? String(threadId) : undefined,\n media: media.length > 0 ? media : undefined,\n transcribedVoice: !!transcribedText || undefined,\n },\n attachments: attachments.length > 0 ? attachments : undefined,\n });\n };\n\n // Main enqueue function\n return (ctx: Context, accountId: string): Promise<void> => {\n const message = ctx.message;\n if (message) {\n const raw = message.text ?? message.caption ?? '';\n if (raw.trim() && isAbortSlashCommand(raw.trim())) {\n return processMessageInternal(ctx, accountId);\n }\n }\n\n const chatId = String(ctx.chat?.id);\n const chatKey = getChatKey(accountId, chatId);\n\n return new Promise((resolve, reject) => {\n const queue = messageQueues.get(chatKey) || [];\n queue.push({ ctx, accountId, resolve, reject });\n messageQueues.set(chatKey, queue);\n processNextMessage(chatKey);\n });\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inbound-processor.js","names":[],"sources":["../../../../extensions/telegram/src/inbound-processor.ts"],"sourcesContent":["/**\n * Telegram Inbound Processor\n *\n * Handles inbound message processing from Telegram:\n * - Message queuing (per chat)\n * - Deduplication\n * - Access control\n * - Media download\n * - STT transcription\n * - Event publishing to bus\n */\n\nimport type { Bot, Context } from 'grammy';\nimport type { Message } from '@grammyjs/types';\nimport type { Config } from '@xopcai/xopc/config/schema.js';\nimport type { MessageBus } from '@xopcai/xopc/infra/bus/index.js';\nimport type { TelegramAccountManager } from './account-manager.js';\nimport { telegramUpdateDedupe, buildTelegramUpdateKey } from './dedupe.js';\nimport { createLogger } from '@xopcai/xopc/utils/logger.js';\nimport { normalizeTelegramCommandName, parseSlashCommand } from '@xopcai/xopc/chat-commands/command-parse.js';\nimport { tryConsumeTelegramClarifyFreeText } from '@xopcai/xopc/gateway/clarify-runtime.js';\nimport { resolveRoute } from '@xopcai/xopc/routing/index.js';\nimport { resolveTelegramGroupContext } from './group-config-resolver.js';\nimport { resolveTelegramFocusedSessionKey } from './focus-handler.js';\nimport { buildTelegramConversationId } from './conversation-id.js';\nimport { checkMentionInTranscription } from '@xopcai/xopc/voice/stt/index.js';\n\nconst log = createLogger('TelegramInboundProcessor');\n\n/** Must bypass the per-chat queue so /abort can cancel an in-flight turn. */\nfunction isAbortSlashCommand(text: string): boolean {\n const parsed = parseSlashCommand(text);\n if (!parsed) return false;\n const cmd = normalizeTelegramCommandName(parsed.command);\n return cmd === 'abort' || cmd === 'stop' || cmd === 'cancel';\n}\n\n/** Maximum voice message duration for STT in seconds */\nconst STT_MAX_VOICE_DURATION_SECONDS = 60;\n\n// =============================================================================\n// External Service Interfaces (for dependency injection)\n// =============================================================================\n\nexport interface AccessControlService {\n normalizeAllowFromWithStore(options: { allowFrom?: Array<string | number> }): unknown;\n evaluateGroupBaseAccess(options: {\n isGroup: boolean;\n groupConfig?: unknown;\n topicConfig?: unknown;\n hasGroupAllowOverride: boolean;\n effectiveGroupAllow: unknown;\n senderId?: string;\n senderUsername?: string;\n }): { allowed: boolean; reason?: string };\n resolveRequireMention(options: {\n topicConfig?: unknown;\n groupConfig?: unknown;\n defaultRequireMention?: boolean;\n }): boolean;\n hasBotMention(options: { botUsername: string; text?: string; entities?: unknown }): boolean;\n removeBotMention(text: string, botUsername: string): string;\n}\n\nexport interface SessionKeyService {\n generateSessionKey(options: {\n source: string;\n chatId: string;\n senderId: string;\n isGroup: boolean;\n threadId?: string;\n accountId?: string;\n agentId?: string;\n }): string;\n}\n\nexport interface STTService {\n transcribe(buffer: Buffer, config: unknown, options?: { language?: string }): Promise<{ text: string }>;\n isSTTAvailable(config: unknown): boolean;\n}\n\nexport interface MediaUtils {\n getMimeType(type: string, filePath?: string): string;\n}\n\n// =============================================================================\n// Dependencies Interface\n// =============================================================================\n\nexport interface InboundProcessorDeps {\n bus: MessageBus;\n config: Config;\n accountManager: TelegramAccountManager;\n // External services (injected for testability)\n accessControl: AccessControlService;\n sessionKeyService: SessionKeyService;\n sttService: STTService;\n mediaUtils: MediaUtils;\n}\n\ninterface QueuedMessage {\n ctx: Context;\n accountId: string;\n resolve: () => void;\n reject: (err: Error) => void;\n}\n\n// =============================================================================\n// Media Processing Types\n// =============================================================================\n\ninterface MediaItem {\n type: string;\n fileId: string;\n emoji?: string;\n}\n\ninterface ProcessedAttachment {\n type: string;\n mimeType: string;\n data: string;\n name?: string;\n size?: number;\n}\n\n// =============================================================================\n// Helper Functions (reduce nesting in main processor)\n// =============================================================================\n\n/**\n * Extract media items from message\n */\nfunction extractMediaItems(message: Message): MediaItem[] {\n const media: MediaItem[] = [];\n \n if (message.photo?.length) {\n media.push({ type: 'photo', fileId: message.photo[message.photo.length - 1].file_id });\n }\n if (message.document) {\n media.push({ type: 'document', fileId: message.document.file_id });\n }\n if (message.video) {\n media.push({ type: 'video', fileId: message.video.file_id });\n }\n if (message.audio) {\n media.push({ type: 'audio', fileId: message.audio.file_id });\n }\n if (message.voice) {\n media.push({ type: 'voice', fileId: message.voice.file_id });\n }\n if (message.sticker) {\n media.push({ type: 'sticker', fileId: message.sticker.file_id, emoji: message.sticker.emoji });\n }\n\n return media;\n}\n\n/**\n * Download + STT a Telegram voice message (for mention probe or media pipeline).\n */\nasync function downloadAndTranscribeTelegramVoice(params: {\n voice: NonNullable<Message['voice']>;\n bot: Bot;\n botToken: string;\n accountApiRoot: string;\n sttService: STTService;\n sttConfig: unknown;\n}): Promise<string> {\n const { voice, bot, botToken, accountApiRoot, sttService, sttConfig } = params;\n const voiceDuration = voice.duration || 0;\n if (voiceDuration > STT_MAX_VOICE_DURATION_SECONDS) {\n return '';\n }\n if (!sttService.isSTTAvailable(sttConfig)) {\n return '';\n }\n try {\n const file = await bot.api.getFile(voice.file_id);\n const downloadUrl = `${accountApiRoot}/file/bot${botToken}/${file.file_path}`;\n const response = await fetch(downloadUrl);\n if (!response.ok) {\n return '';\n }\n const buffer = Buffer.from(await response.arrayBuffer());\n if (buffer.length === 0) {\n return '';\n }\n const sttResult = await sttService.transcribe(buffer, sttConfig, {\n language: (sttConfig as { provider?: string })?.provider === 'alibaba' ? 'zh' : undefined,\n });\n return sttResult.text?.trim() ?? '';\n } catch {\n return '';\n }\n}\n\n/**\n * Process a single media item (download + optional STT)\n */\nasync function processMediaItem(\n item: MediaItem,\n bot: Bot,\n botToken: string,\n accountApiRoot: string,\n message: Message,\n sttService: STTService,\n mediaUtils: MediaUtils,\n sttConfig: unknown,\n reuseVoiceTranscript?: string,\n): Promise<{ attachment: ProcessedAttachment | null; transcribedText: string }> {\n try {\n const file = await bot.api.getFile(item.fileId);\n const downloadUrl = `${accountApiRoot}/file/bot${botToken}/${file.file_path}`;\n const response = await fetch(downloadUrl);\n\n // Debug log for media download\n log.info({\n type: item.type,\n fileId: item.fileId,\n downloadUrl,\n responseStatus: response.status,\n }, 'Media download response');\n\n if (!response.ok) {\n throw new Error(`Failed to download: ${response.status}`);\n }\n\n const buffer = await response.arrayBuffer();\n\n // Debug log for buffer size\n log.info({\n type: item.type,\n fileId: item.fileId,\n bufferSize: buffer.byteLength,\n filePath: file.file_path,\n }, 'Media buffer downloaded');\n\n if (buffer.byteLength === 0) {\n log.warn({\n type: item.type,\n fileId: item.fileId,\n filePath: file.file_path,\n }, 'Media buffer is empty, may cause issues');\n }\n let transcribedText = '';\n\n // Handle voice messages with STT\n if (item.type === 'voice' && sttService.isSTTAvailable(sttConfig)) {\n if (reuseVoiceTranscript !== undefined && reuseVoiceTranscript !== '') {\n transcribedText = reuseVoiceTranscript;\n } else {\n const voiceDuration = message.voice?.duration || 0;\n if (voiceDuration <= STT_MAX_VOICE_DURATION_SECONDS) {\n try {\n const sttResult = await sttService.transcribe(Buffer.from(buffer), sttConfig, {\n language: (sttConfig as { provider?: string })?.provider === 'alibaba' ? 'zh' : undefined,\n });\n transcribedText = sttResult.text;\n } catch (sttError) {\n log.error({ sttError }, 'STT transcription failed');\n transcribedText = '[STT failed]';\n }\n } else {\n transcribedText = `[Voice message too long (>${STT_MAX_VOICE_DURATION_SECONDS}s)]`;\n }\n }\n }\n\n const base64 = Buffer.from(buffer).toString('base64');\n const mimeType = mediaUtils.getMimeType(item.type, file.file_path);\n\n // Debug log for attachment creation\n log.info({\n type: item.type,\n mimeType,\n base64Length: base64.length,\n size: buffer.byteLength,\n name: file.file_path?.split('/').pop(),\n }, 'Attachment created');\n\n return {\n attachment: {\n type: item.type,\n mimeType,\n data: base64,\n name: file.file_path?.split('/').pop(),\n size: buffer.byteLength,\n },\n transcribedText,\n };\n } catch (err) {\n log.error({ type: item.type, fileId: item.fileId, err }, 'Failed to download media');\n return { attachment: null, transcribedText: '' };\n }\n}\n\n/**\n * Process all media items\n */\nasync function processAllMedia(\n media: MediaItem[],\n bot: Bot,\n botToken: string,\n accountApiRoot: string,\n message: Message,\n sttService: STTService,\n mediaUtils: MediaUtils,\n sttConfig: unknown,\n reuseVoiceTranscript?: string,\n): Promise<{ attachments: ProcessedAttachment[]; transcribedText: string }> {\n const attachments: ProcessedAttachment[] = [];\n let transcribedText = '';\n let voiceReuseConsumed = false;\n\n for (const item of media) {\n const reuse =\n item.type === 'voice' && reuseVoiceTranscript && !voiceReuseConsumed\n ? reuseVoiceTranscript\n : undefined;\n if (reuse) {\n voiceReuseConsumed = true;\n }\n const result = await processMediaItem(\n item,\n bot,\n botToken,\n accountApiRoot,\n message,\n sttService,\n mediaUtils,\n sttConfig,\n reuse,\n );\n \n if (result.attachment) {\n attachments.push(result.attachment);\n }\n if (result.transcribedText) {\n transcribedText = result.transcribedText;\n }\n }\n\n return { attachments, transcribedText };\n}\n\n// =============================================================================\n// Main Processor Factory\n// =============================================================================\n\n/**\n * Create inbound message processor\n */\nexport function createInboundProcessor(deps: InboundProcessorDeps) {\n const {\n bus,\n config,\n accountManager,\n accessControl,\n sessionKeyService,\n sttService,\n mediaUtils,\n } = deps;\n\n const messageQueues = new Map<string, QueuedMessage[]>();\n const processingLocks = new Map<string, Promise<void>>();\n\n const getChatKey = (accountId: string, chatId: string): string => `${accountId}:${chatId}`;\n\n const processNextMessage = async (chatKey: string): Promise<void> => {\n if (processingLocks.has(chatKey)) return;\n\n const queue = messageQueues.get(chatKey);\n if (!queue || queue.length === 0) return;\n\n let lockResolve: () => void;\n const lockPromise = new Promise<void>((resolve) => {\n lockResolve = resolve;\n });\n processingLocks.set(chatKey, lockPromise);\n\n const { ctx, accountId, resolve, reject } = queue.shift()!;\n\n try {\n await processMessageInternal(ctx, accountId);\n resolve();\n } catch (err) {\n reject(err instanceof Error ? err : new Error(String(err)));\n } finally {\n lockResolve?.();\n processingLocks.delete(chatKey);\n if (queue.length > 0) {\n processNextMessage(chatKey);\n } else {\n messageQueues.delete(chatKey);\n }\n }\n };\n\n const processMessageInternal = async (ctx: Context, accountId: string) => {\n // Deduplication check\n const updateKey = buildTelegramUpdateKey(ctx);\n if (updateKey && telegramUpdateDedupe.checkAndAdd(updateKey)) {\n log.debug({ updateKey, accountId }, 'Duplicate update detected, skipping');\n return;\n }\n\n const account = accountManager.getAccount(accountId);\n if (!account) {\n log.warn({ accountId }, 'Account not found for message processing');\n return;\n }\n\n const botUsername = accountManager.getBotUsername(accountId);\n if (!botUsername) {\n log.warn({ accountId }, 'Bot username not available');\n return;\n }\n\n const message = ctx.message ?? ctx.channelPost;\n if (!message) return;\n\n const chatId = String(ctx.chat?.id);\n const senderId = String(ctx.from?.id);\n const senderUsername = ctx.from?.username;\n const content = message.text ?? message.caption ?? '';\n const isGroup = ctx.chat?.type === 'group' || ctx.chat?.type === 'supergroup';\n const threadId = (message as { message_thread_id?: number }).message_thread_id;\n\n // Access control (group/topic allowlists, mention gating)\n const effectiveAllowFrom = accessControl.normalizeAllowFromWithStore({\n allowFrom: isGroup ? account.groupAllowFrom : account.allowFrom,\n });\n\n const baseAccess = accessControl.evaluateGroupBaseAccess({\n isGroup,\n groupConfig: account.groups?.[chatId],\n topicConfig: threadId ? account.groups?.[chatId]?.topics?.[String(threadId)] : undefined,\n hasGroupAllowOverride: !!(account.groups?.[chatId]?.allowFrom ||\n (threadId && account.groups?.[chatId]?.topics?.[String(threadId)]?.allowFrom)),\n effectiveGroupAllow: effectiveAllowFrom,\n senderId,\n senderUsername,\n });\n\n if (!baseAccess.allowed) {\n log.debug({ accountId, chatId, reason: baseAccess.reason }, 'Message blocked by base access');\n return;\n }\n\n const botEarly = accountManager.getBot(accountId);\n const botTokenEarly = account.botToken;\n const accountApiRootEarly = account.apiRoot?.replace(/\\/$/, '') || 'https://api.telegram.org';\n\n let voiceProbeText = '';\n if (\n isGroup &&\n message.voice &&\n botEarly &&\n botTokenEarly &&\n sttService.isSTTAvailable(config?.tools?.media?.audio)\n ) {\n voiceProbeText = await downloadAndTranscribeTelegramVoice({\n voice: message.voice,\n bot: botEarly,\n botToken: botTokenEarly,\n accountApiRoot: accountApiRootEarly,\n sttService,\n sttConfig: config?.tools?.media?.audio,\n });\n }\n\n if (isGroup) {\n const requireMention = accessControl.resolveRequireMention({\n topicConfig: threadId ? account.groups?.[chatId]?.topics?.[String(threadId)] : undefined,\n groupConfig: account.groups?.[chatId],\n defaultRequireMention: true,\n });\n\n const hasMedia = !!(message.photo || message.document || message.video || message.audio || message.voice);\n const captionEntities = (message as any).caption_entities;\n const voiceMention = voiceProbeText.trim();\n const hasMention =\n accessControl.hasBotMention({ botUsername, text: content, entities: message.entities }) ||\n (hasMedia &&\n accessControl.hasBotMention({\n botUsername,\n text: message.caption ?? '',\n entities: captionEntities,\n })) ||\n (voiceMention.length > 0 &&\n (accessControl.hasBotMention({ botUsername, text: voiceMention }) ||\n checkMentionInTranscription(voiceMention, [botUsername])));\n\n if (requireMention && !hasMention) {\n const isVoiceOnly =\n !!message.voice &&\n !message.photo &&\n !message.document &&\n !message.video &&\n !message.audio &&\n !(message.caption ?? '').trim() &&\n !content.trim();\n\n if (isVoiceOnly) {\n log.debug({ accountId, chatId }, 'Group voice without mention after STT probe, ignored');\n return;\n }\n\n if (!hasMedia || content.trim().length > 0) {\n log.debug({ accountId, chatId }, 'Group message without mention ignored');\n return;\n }\n log.debug({ accountId, chatId }, 'Group media message without mention - processing anyway');\n }\n }\n\n const cleanContent = isGroup ? accessControl.removeBotMention(content, botUsername) : content;\n\n const groupCtx = resolveTelegramGroupContext({ account, chatId, threadId });\n const route = resolveRoute({\n config,\n channel: 'telegram',\n accountId,\n peerKind: isGroup ? 'group' : 'dm',\n peerId: isGroup ? chatId : senderId,\n threadId: threadId ? String(threadId) : null,\n });\n const routedAgentId = groupCtx.agentId ?? route.agentId;\n\n const defaultSessionKey = sessionKeyService.generateSessionKey({\n source: 'telegram',\n chatId,\n senderId,\n isGroup,\n threadId: threadId ? String(threadId) : undefined,\n accountId,\n agentId: routedAgentId,\n });\n\n const sessionKey = resolveTelegramFocusedSessionKey({\n chatId,\n threadId: threadId ? String(threadId) : undefined,\n defaultSessionKey,\n });\n\n const conversationId = buildTelegramConversationId(chatId, threadId);\n\n // Collect and process media\n const media = extractMediaItems(message);\n const bot = accountManager.getBot(accountId);\n const botToken = account.botToken;\n\n let attachments: ProcessedAttachment[] = [];\n let transcribedText = '';\n\n if (bot && botToken && media.length > 0) {\n const accountApiRoot = account.apiRoot?.replace(/\\/$/, '') || 'https://api.telegram.org';\n const mediaResult = await processAllMedia(\n media,\n bot,\n botToken,\n accountApiRoot,\n message,\n sttService,\n mediaUtils,\n config?.tools?.media?.audio,\n voiceProbeText || undefined,\n );\n attachments = mediaResult.attachments;\n transcribedText = mediaResult.transcribedText;\n }\n\n // Combine transcribed text with content. If the user caption is a slash command, put it first\n // so routing and logs match a normal `/cmd` message (STT prefix no longer hides the command).\n const captionIsCommand = cleanContent.trim().startsWith('/');\n let finalContent = transcribedText\n ? captionIsCommand && cleanContent\n ? cleanContent.trim() + (transcribedText ? `\\n\\n${transcribedText}` : '')\n : transcribedText + (cleanContent ? '\\n\\n' + cleanContent : '')\n : cleanContent;\n\n const stickerItem = media.find((m) => m.type === 'sticker');\n if (stickerItem && !finalContent.trim()) {\n finalContent = stickerItem.emoji?.trim()\n ? `[Sticker ${stickerItem.emoji}]`\n : '[Sticker]';\n }\n\n const isCommand = cleanContent.trim().startsWith('/');\n\n log.info({\n accountId,\n chatId,\n senderId,\n isGroup,\n sessionKey,\n contentLength: finalContent.length,\n attachmentCount: attachments.length,\n isCommand,\n }, 'Processing Telegram message');\n\n if (\n finalContent.trim().length > 0 &&\n !isCommand &&\n tryConsumeTelegramClarifyFreeText(sessionKey, finalContent.trim())\n ) {\n log.debug({ sessionKey }, 'Telegram: consumed message as clarify reply');\n return;\n }\n\n await bus.publishInbound({\n channel: 'telegram',\n sender_id: senderId,\n chat_id: chatId,\n content: finalContent,\n metadata: {\n accountId,\n sessionKey,\n senderUsername,\n messageId: String(message.message_id),\n isGroup,\n isCommand,\n threadId: threadId ? String(threadId) : undefined,\n conversationId,\n channelSystemPrompt: groupCtx.systemPrompt,\n channelAgentId: routedAgentId,\n media: media.length > 0 ? media : undefined,\n transcribedVoice: !!transcribedText || undefined,\n },\n attachments: attachments.length > 0 ? attachments : undefined,\n });\n };\n\n // Main enqueue function\n return (ctx: Context, accountId: string): Promise<void> => {\n const message = ctx.message;\n if (message) {\n const raw = message.text ?? message.caption ?? '';\n if (raw.trim() && isAbortSlashCommand(raw.trim())) {\n return processMessageInternal(ctx, accountId);\n }\n }\n\n const chatId = String(ctx.chat?.id);\n const chatKey = getChatKey(accountId, chatId);\n\n return new Promise((resolve, reject) => {\n const queue = messageQueues.get(chatKey) || [];\n queue.push({ ctx, accountId, resolve, reject });\n messageQueues.set(chatKey, queue);\n processNextMessage(chatKey);\n });\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function isRecoverableTelegramNetworkError(err: unknown): boolean;
2
+ export declare function isTelegramClientRejection(err: unknown): boolean;
@@ -0,0 +1,23 @@
1
+ //#region extensions/telegram/src/network-errors.ts
2
+ const RECOVERABLE_NETWORK_RE = /ETIMEDOUT|ENETUNREACH|EHOSTUNREACH|ECONNRESET|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|socket hang up|fetch failed|network/i;
3
+ function isRecoverableTelegramNetworkError(err) {
4
+ const text = extractErrorText(err);
5
+ return RECOVERABLE_NETWORK_RE.test(text);
6
+ }
7
+ function isTelegramClientRejection(err) {
8
+ const text = extractErrorText(err);
9
+ return /400:|403:|429:|Bad Request|Forbidden|Too Many Requests/i.test(text);
10
+ }
11
+ function extractErrorText(err) {
12
+ if (typeof err === "string") return err;
13
+ if (err instanceof Error) return err.message;
14
+ if (err && typeof err === "object" && "description" in err) {
15
+ const d = err.description;
16
+ return typeof d === "string" ? d : "";
17
+ }
18
+ return String(err);
19
+ }
20
+ //#endregion
21
+ export { isRecoverableTelegramNetworkError, isTelegramClientRejection };
22
+
23
+ //# sourceMappingURL=network-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network-errors.js","names":[],"sources":["../../../../extensions/telegram/src/network-errors.ts"],"sourcesContent":["const RECOVERABLE_NETWORK_RE =\n /ETIMEDOUT|ENETUNREACH|EHOSTUNREACH|ECONNRESET|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|socket hang up|fetch failed|network/i;\n\nexport function isRecoverableTelegramNetworkError(err: unknown): boolean {\n const text = extractErrorText(err);\n return RECOVERABLE_NETWORK_RE.test(text);\n}\n\nexport function isTelegramClientRejection(err: unknown): boolean {\n const text = extractErrorText(err);\n return /400:|403:|429:|Bad Request|Forbidden|Too Many Requests/i.test(text);\n}\n\nfunction extractErrorText(err: unknown): string {\n if (typeof err === 'string') return err;\n if (err instanceof Error) return err.message;\n if (err && typeof err === 'object' && 'description' in err) {\n const d = (err as { description?: unknown }).description;\n return typeof d === 'string' ? d : '';\n }\n return String(err);\n}\n"],"mappings":";AAAA,MAAM,yBACJ;AAEF,SAAgB,kCAAkC,KAAuB;CACvE,MAAM,OAAO,iBAAiB,IAAI;AAClC,QAAO,uBAAuB,KAAK,KAAK;;AAG1C,SAAgB,0BAA0B,KAAuB;CAC/D,MAAM,OAAO,iBAAiB,IAAI;AAClC,QAAO,0DAA0D,KAAK,KAAK;;AAG7E,SAAS,iBAAiB,KAAsB;AAC9C,KAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,KAAI,eAAe,MAAO,QAAO,IAAI;AACrC,KAAI,OAAO,OAAO,QAAQ,YAAY,iBAAiB,KAAK;EAC1D,MAAM,IAAK,IAAkC;AAC7C,SAAO,OAAO,MAAM,WAAW,IAAI;;AAErC,QAAO,OAAO,IAAI"}
@@ -8,6 +8,7 @@ import type { Config } from '@xopcai/xopc/config/index.js';
8
8
  import type { ChannelPlugin, ChannelPluginDefaults, ChannelPluginInitOptions, ChannelPluginReloadMeta, ChannelPluginStartOptions, ChannelOutboundAdapter, ChannelGatewayAdapter, ChannelStreamingAdapter, ChannelCommandAdapter } from '@xopcai/xopc/channels/plugin-types.js';
9
9
  import type { TelegramResolvedAccount } from './adapters/index.js';
10
10
  import type { ChannelCronDeliveryAdapter } from '@xopcai/xopc/channels/plugins/types.adapters.js';
11
+ import { handleTelegramChannelAction } from './actions/message-actions.js';
11
12
  export type { TelegramResolvedAccount as TelegramAccount } from './channel.js';
12
13
  export declare class TelegramChannelPlugin implements ChannelPlugin<TelegramResolvedAccount> {
13
14
  readonly id: "telegram";
@@ -37,6 +38,11 @@ export declare class TelegramChannelPlugin implements ChannelPlugin<TelegramReso
37
38
  readonly cronDelivery: ChannelCronDeliveryAdapter;
38
39
  readonly configSurface: import("@xopcai/xopc/channels/plugins/types.adapters.js").ChannelConfigSurfaceAdapter;
39
40
  readonly onboard: import("@xopcai/xopc/channels/plugins/types.adapters.js").ChannelOnboardAdapter;
41
+ readonly doctor: {
42
+ check: (params: {
43
+ cfg: Config;
44
+ }) => Promise<import("@xopcai/xopc/channels/plugin-types.js").ChannelDoctorCheckResult[]>;
45
+ };
40
46
  readonly pairing: import("@xopcai/xopc/channels/plugins/types.adapters.js").ChannelPairingAdapter;
41
47
  private bus;
42
48
  private cfg;
@@ -48,6 +54,11 @@ export declare class TelegramChannelPlugin implements ChannelPlugin<TelegramReso
48
54
  private sessionModelHooks?;
49
55
  /** Unregister fn for the workflow-progress capability registered against the global broker. */
50
56
  private workflowProgressUnregister;
57
+ private inboundCoalescer;
58
+ private execApprovalUnregister;
59
+ readonly actions: {
60
+ handleAction: typeof handleTelegramChannelAction;
61
+ };
51
62
  config: import('@xopcai/xopc/channels/plugin-types.js').ChannelConfigAdapter<TelegramResolvedAccount>;
52
63
  security: import('@xopcai/xopc/channels/plugin-types.js').ChannelSecurityAdapter<TelegramResolvedAccount>;
53
64
  status: import('@xopcai/xopc/channels/plugin-types.js').ChannelStatusAdapter<TelegramResolvedAccount>;