@asermax/tachikoma 2.0.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 (345) hide show
  1. package/README.md +64 -0
  2. package/dist/agent/adapter.d.ts +8 -0
  3. package/dist/agent/adapter.js +86 -0
  4. package/dist/agent/adapter.js.map +1 -0
  5. package/dist/agent/manager.d.ts +35 -0
  6. package/dist/agent/manager.js +76 -0
  7. package/dist/agent/manager.js.map +1 -0
  8. package/dist/agent/models.d.ts +46 -0
  9. package/dist/agent/models.js +96 -0
  10. package/dist/agent/models.js.map +1 -0
  11. package/dist/agent/side-run.d.ts +42 -0
  12. package/dist/agent/side-run.js +83 -0
  13. package/dist/agent/side-run.js.map +1 -0
  14. package/dist/app.d.ts +5 -0
  15. package/dist/app.js +79 -0
  16. package/dist/app.js.map +1 -0
  17. package/dist/channels/types.d.ts +37 -0
  18. package/dist/channels/types.js +5 -0
  19. package/dist/channels/types.js.map +1 -0
  20. package/dist/config/default-template.d.ts +1 -0
  21. package/dist/config/default-template.js +49 -0
  22. package/dist/config/default-template.js.map +1 -0
  23. package/dist/config/load.d.ts +8 -0
  24. package/dist/config/load.js +28 -0
  25. package/dist/config/load.js.map +1 -0
  26. package/dist/config/parse.d.ts +5 -0
  27. package/dist/config/parse.js +18 -0
  28. package/dist/config/parse.js.map +1 -0
  29. package/dist/config/schema.d.ts +29 -0
  30. package/dist/config/schema.js +35 -0
  31. package/dist/config/schema.js.map +1 -0
  32. package/dist/coordinator.d.ts +54 -0
  33. package/dist/coordinator.js +344 -0
  34. package/dist/coordinator.js.map +1 -0
  35. package/dist/db/core-schema.d.ts +250 -0
  36. package/dist/db/core-schema.js +19 -0
  37. package/dist/db/core-schema.js.map +1 -0
  38. package/dist/db/index.d.ts +8 -0
  39. package/dist/db/index.js +16 -0
  40. package/dist/db/index.js.map +1 -0
  41. package/dist/db/schema.d.ts +4 -0
  42. package/dist/db/schema.js +7 -0
  43. package/dist/db/schema.js.map +1 -0
  44. package/dist/db/state.d.ts +10 -0
  45. package/dist/db/state.js +36 -0
  46. package/dist/db/state.js.map +1 -0
  47. package/dist/domain/agent-events.d.ts +26 -0
  48. package/dist/domain/agent-events.js +2 -0
  49. package/dist/domain/agent-events.js.map +1 -0
  50. package/dist/domain/message.d.ts +25 -0
  51. package/dist/domain/message.js +17 -0
  52. package/dist/domain/message.js.map +1 -0
  53. package/dist/events.d.ts +9 -0
  54. package/dist/events.js +27 -0
  55. package/dist/events.js.map +1 -0
  56. package/dist/extensions/api.d.ts +118 -0
  57. package/dist/extensions/api.js +7 -0
  58. package/dist/extensions/api.js.map +1 -0
  59. package/dist/extensions/boundary/detector.d.ts +20 -0
  60. package/dist/extensions/boundary/detector.js +57 -0
  61. package/dist/extensions/boundary/detector.js.map +1 -0
  62. package/dist/extensions/boundary/idle.d.ts +10 -0
  63. package/dist/extensions/boundary/idle.js +28 -0
  64. package/dist/extensions/boundary/idle.js.map +1 -0
  65. package/dist/extensions/boundary/index.d.ts +12 -0
  66. package/dist/extensions/boundary/index.js +65 -0
  67. package/dist/extensions/boundary/index.js.map +1 -0
  68. package/dist/extensions/boundary/summary.d.ts +5 -0
  69. package/dist/extensions/boundary/summary.js +33 -0
  70. package/dist/extensions/boundary/summary.js.map +1 -0
  71. package/dist/extensions/commands/index.d.ts +7 -0
  72. package/dist/extensions/commands/index.js +21 -0
  73. package/dist/extensions/commands/index.js.map +1 -0
  74. package/dist/extensions/context/index.d.ts +7 -0
  75. package/dist/extensions/context/index.js +65 -0
  76. package/dist/extensions/context/index.js.map +1 -0
  77. package/dist/extensions/context/processor.d.ts +27 -0
  78. package/dist/extensions/context/processor.js +228 -0
  79. package/dist/extensions/context/processor.js.map +1 -0
  80. package/dist/extensions/detached-processes/index.d.ts +12 -0
  81. package/dist/extensions/detached-processes/index.js +51 -0
  82. package/dist/extensions/detached-processes/index.js.map +1 -0
  83. package/dist/extensions/detached-processes/limits.d.ts +27 -0
  84. package/dist/extensions/detached-processes/limits.js +55 -0
  85. package/dist/extensions/detached-processes/limits.js.map +1 -0
  86. package/dist/extensions/detached-processes/output.d.ts +2 -0
  87. package/dist/extensions/detached-processes/output.js +26 -0
  88. package/dist/extensions/detached-processes/output.js.map +1 -0
  89. package/dist/extensions/detached-processes/reconcile.d.ts +31 -0
  90. package/dist/extensions/detached-processes/reconcile.js +71 -0
  91. package/dist/extensions/detached-processes/reconcile.js.map +1 -0
  92. package/dist/extensions/detached-processes/repository.d.ts +33 -0
  93. package/dist/extensions/detached-processes/repository.js +62 -0
  94. package/dist/extensions/detached-processes/repository.js.map +1 -0
  95. package/dist/extensions/detached-processes/schema.d.ts +252 -0
  96. package/dist/extensions/detached-processes/schema.js +23 -0
  97. package/dist/extensions/detached-processes/schema.js.map +1 -0
  98. package/dist/extensions/detached-processes/spawn.d.ts +40 -0
  99. package/dist/extensions/detached-processes/spawn.js +137 -0
  100. package/dist/extensions/detached-processes/spawn.js.map +1 -0
  101. package/dist/extensions/detached-processes/tools.d.ts +41 -0
  102. package/dist/extensions/detached-processes/tools.js +243 -0
  103. package/dist/extensions/detached-processes/tools.js.map +1 -0
  104. package/dist/extensions/detached-processes/watcher.d.ts +7 -0
  105. package/dist/extensions/detached-processes/watcher.js +19 -0
  106. package/dist/extensions/detached-processes/watcher.js.map +1 -0
  107. package/dist/extensions/external/index.d.ts +11 -0
  108. package/dist/extensions/external/index.js +40 -0
  109. package/dist/extensions/external/index.js.map +1 -0
  110. package/dist/extensions/external/installs.d.ts +39 -0
  111. package/dist/extensions/external/installs.js +98 -0
  112. package/dist/extensions/external/installs.js.map +1 -0
  113. package/dist/extensions/external/loader.d.ts +19 -0
  114. package/dist/extensions/external/loader.js +70 -0
  115. package/dist/extensions/external/loader.js.map +1 -0
  116. package/dist/extensions/external/tools.d.ts +17 -0
  117. package/dist/extensions/external/tools.js +112 -0
  118. package/dist/extensions/external/tools.js.map +1 -0
  119. package/dist/extensions/git/commit.d.ts +19 -0
  120. package/dist/extensions/git/commit.js +44 -0
  121. package/dist/extensions/git/commit.js.map +1 -0
  122. package/dist/extensions/git/git.d.ts +11 -0
  123. package/dist/extensions/git/git.js +29 -0
  124. package/dist/extensions/git/git.js.map +1 -0
  125. package/dist/extensions/git/hooks.d.ts +10 -0
  126. package/dist/extensions/git/hooks.js +88 -0
  127. package/dist/extensions/git/hooks.js.map +1 -0
  128. package/dist/extensions/git/index.d.ts +11 -0
  129. package/dist/extensions/git/index.js +28 -0
  130. package/dist/extensions/git/index.js.map +1 -0
  131. package/dist/extensions/git/processor.d.ts +13 -0
  132. package/dist/extensions/git/processor.js +52 -0
  133. package/dist/extensions/git/processor.js.map +1 -0
  134. package/dist/extensions/git/sync.d.ts +44 -0
  135. package/dist/extensions/git/sync.js +189 -0
  136. package/dist/extensions/git/sync.js.map +1 -0
  137. package/dist/extensions/git/tools.d.ts +21 -0
  138. package/dist/extensions/git/tools.js +101 -0
  139. package/dist/extensions/git/tools.js.map +1 -0
  140. package/dist/extensions/host.d.ts +31 -0
  141. package/dist/extensions/host.js +75 -0
  142. package/dist/extensions/host.js.map +1 -0
  143. package/dist/extensions/index.d.ts +3 -0
  144. package/dist/extensions/index.js +32 -0
  145. package/dist/extensions/index.js.map +1 -0
  146. package/dist/extensions/memory/archive.d.ts +8 -0
  147. package/dist/extensions/memory/archive.js +46 -0
  148. package/dist/extensions/memory/archive.js.map +1 -0
  149. package/dist/extensions/memory/dates.d.ts +2 -0
  150. package/dist/extensions/memory/dates.js +7 -0
  151. package/dist/extensions/memory/dates.js.map +1 -0
  152. package/dist/extensions/memory/extraction.d.ts +17 -0
  153. package/dist/extensions/memory/extraction.js +218 -0
  154. package/dist/extensions/memory/extraction.js.map +1 -0
  155. package/dist/extensions/memory/index.d.ts +20 -0
  156. package/dist/extensions/memory/index.js +67 -0
  157. package/dist/extensions/memory/index.js.map +1 -0
  158. package/dist/extensions/memory/indexes.d.ts +14 -0
  159. package/dist/extensions/memory/indexes.js +64 -0
  160. package/dist/extensions/memory/indexes.js.map +1 -0
  161. package/dist/extensions/memory/layout.d.ts +20 -0
  162. package/dist/extensions/memory/layout.js +79 -0
  163. package/dist/extensions/memory/layout.js.map +1 -0
  164. package/dist/extensions/memory/maintenance.d.ts +21 -0
  165. package/dist/extensions/memory/maintenance.js +357 -0
  166. package/dist/extensions/memory/maintenance.js.map +1 -0
  167. package/dist/extensions/memory/prompts.d.ts +8 -0
  168. package/dist/extensions/memory/prompts.js +125 -0
  169. package/dist/extensions/memory/prompts.js.map +1 -0
  170. package/dist/extensions/memory/transcript.d.ts +18 -0
  171. package/dist/extensions/memory/transcript.js +79 -0
  172. package/dist/extensions/memory/transcript.js.map +1 -0
  173. package/dist/extensions/notifications/format.d.ts +5 -0
  174. package/dist/extensions/notifications/format.js +17 -0
  175. package/dist/extensions/notifications/format.js.map +1 -0
  176. package/dist/extensions/notifications/index.d.ts +13 -0
  177. package/dist/extensions/notifications/index.js +29 -0
  178. package/dist/extensions/notifications/index.js.map +1 -0
  179. package/dist/extensions/notifications/payload.d.ts +22 -0
  180. package/dist/extensions/notifications/payload.js +29 -0
  181. package/dist/extensions/notifications/payload.js.map +1 -0
  182. package/dist/extensions/notifications/router.d.ts +29 -0
  183. package/dist/extensions/notifications/router.js +55 -0
  184. package/dist/extensions/notifications/router.js.map +1 -0
  185. package/dist/extensions/notifications/tools.d.ts +12 -0
  186. package/dist/extensions/notifications/tools.js +41 -0
  187. package/dist/extensions/notifications/tools.js.map +1 -0
  188. package/dist/extensions/projects/context-provider.d.ts +9 -0
  189. package/dist/extensions/projects/context-provider.js +37 -0
  190. package/dist/extensions/projects/context-provider.js.map +1 -0
  191. package/dist/extensions/projects/git.d.ts +28 -0
  192. package/dist/extensions/projects/git.js +91 -0
  193. package/dist/extensions/projects/git.js.map +1 -0
  194. package/dist/extensions/projects/hooks.d.ts +7 -0
  195. package/dist/extensions/projects/hooks.js +42 -0
  196. package/dist/extensions/projects/hooks.js.map +1 -0
  197. package/dist/extensions/projects/index.d.ts +11 -0
  198. package/dist/extensions/projects/index.js +30 -0
  199. package/dist/extensions/projects/index.js.map +1 -0
  200. package/dist/extensions/projects/processor.d.ts +13 -0
  201. package/dist/extensions/projects/processor.js +63 -0
  202. package/dist/extensions/projects/processor.js.map +1 -0
  203. package/dist/extensions/projects/tools.d.ts +21 -0
  204. package/dist/extensions/projects/tools.js +118 -0
  205. package/dist/extensions/projects/tools.js.map +1 -0
  206. package/dist/extensions/registrations.d.ts +21 -0
  207. package/dist/extensions/registrations.js +12 -0
  208. package/dist/extensions/registrations.js.map +1 -0
  209. package/dist/extensions/repl/index.d.ts +2 -0
  210. package/dist/extensions/repl/index.js +85 -0
  211. package/dist/extensions/repl/index.js.map +1 -0
  212. package/dist/extensions/skills/agents.d.ts +17 -0
  213. package/dist/extensions/skills/agents.js +77 -0
  214. package/dist/extensions/skills/agents.js.map +1 -0
  215. package/dist/extensions/skills/delegate.d.ts +22 -0
  216. package/dist/extensions/skills/delegate.js +54 -0
  217. package/dist/extensions/skills/delegate.js.map +1 -0
  218. package/dist/extensions/skills/index.d.ts +11 -0
  219. package/dist/extensions/skills/index.js +43 -0
  220. package/dist/extensions/skills/index.js.map +1 -0
  221. package/dist/extensions/skills/reload.d.ts +8 -0
  222. package/dist/extensions/skills/reload.js +38 -0
  223. package/dist/extensions/skills/reload.js.map +1 -0
  224. package/dist/extensions/tasks/executor.d.ts +43 -0
  225. package/dist/extensions/tasks/executor.js +179 -0
  226. package/dist/extensions/tasks/executor.js.map +1 -0
  227. package/dist/extensions/tasks/expiration.d.ts +12 -0
  228. package/dist/extensions/tasks/expiration.js +17 -0
  229. package/dist/extensions/tasks/expiration.js.map +1 -0
  230. package/dist/extensions/tasks/generation.d.ts +14 -0
  231. package/dist/extensions/tasks/generation.js +70 -0
  232. package/dist/extensions/tasks/generation.js.map +1 -0
  233. package/dist/extensions/tasks/index.d.ts +14 -0
  234. package/dist/extensions/tasks/index.js +75 -0
  235. package/dist/extensions/tasks/index.js.map +1 -0
  236. package/dist/extensions/tasks/repository.d.ts +53 -0
  237. package/dist/extensions/tasks/repository.js +147 -0
  238. package/dist/extensions/tasks/repository.js.map +1 -0
  239. package/dist/extensions/tasks/schedule.d.ts +13 -0
  240. package/dist/extensions/tasks/schedule.js +32 -0
  241. package/dist/extensions/tasks/schedule.js.map +1 -0
  242. package/dist/extensions/tasks/schema.d.ts +423 -0
  243. package/dist/extensions/tasks/schema.js +45 -0
  244. package/dist/extensions/tasks/schema.js.map +1 -0
  245. package/dist/extensions/tasks/session-delivery.d.ts +18 -0
  246. package/dist/extensions/tasks/session-delivery.js +39 -0
  247. package/dist/extensions/tasks/session-delivery.js.map +1 -0
  248. package/dist/extensions/tasks/tools.d.ts +38 -0
  249. package/dist/extensions/tasks/tools.js +181 -0
  250. package/dist/extensions/tasks/tools.js.map +1 -0
  251. package/dist/extensions/telegram/buttons.d.ts +14 -0
  252. package/dist/extensions/telegram/buttons.js +49 -0
  253. package/dist/extensions/telegram/buttons.js.map +1 -0
  254. package/dist/extensions/telegram/channel.d.ts +39 -0
  255. package/dist/extensions/telegram/channel.js +201 -0
  256. package/dist/extensions/telegram/channel.js.map +1 -0
  257. package/dist/extensions/telegram/chunking.d.ts +7 -0
  258. package/dist/extensions/telegram/chunking.js +67 -0
  259. package/dist/extensions/telegram/chunking.js.map +1 -0
  260. package/dist/extensions/telegram/inbound.d.ts +7 -0
  261. package/dist/extensions/telegram/inbound.js +29 -0
  262. package/dist/extensions/telegram/inbound.js.map +1 -0
  263. package/dist/extensions/telegram/index.d.ts +13 -0
  264. package/dist/extensions/telegram/index.js +67 -0
  265. package/dist/extensions/telegram/index.js.map +1 -0
  266. package/dist/extensions/telegram/media.d.ts +39 -0
  267. package/dist/extensions/telegram/media.js +223 -0
  268. package/dist/extensions/telegram/media.js.map +1 -0
  269. package/dist/extensions/telegram/mutex.d.ts +9 -0
  270. package/dist/extensions/telegram/mutex.js +14 -0
  271. package/dist/extensions/telegram/mutex.js.map +1 -0
  272. package/dist/extensions/telegram/sending.d.ts +48 -0
  273. package/dist/extensions/telegram/sending.js +119 -0
  274. package/dist/extensions/telegram/sending.js.map +1 -0
  275. package/dist/extensions/telegram/streaming.d.ts +46 -0
  276. package/dist/extensions/telegram/streaming.js +140 -0
  277. package/dist/extensions/telegram/streaming.js.map +1 -0
  278. package/dist/extensions/telegram/tools.d.ts +80 -0
  279. package/dist/extensions/telegram/tools.js +232 -0
  280. package/dist/extensions/telegram/tools.js.map +1 -0
  281. package/dist/extensions/workflows/cleanup.d.ts +10 -0
  282. package/dist/extensions/workflows/cleanup.js +38 -0
  283. package/dist/extensions/workflows/cleanup.js.map +1 -0
  284. package/dist/extensions/workflows/index.d.ts +11 -0
  285. package/dist/extensions/workflows/index.js +42 -0
  286. package/dist/extensions/workflows/index.js.map +1 -0
  287. package/dist/extensions/workflows/loader.d.ts +27 -0
  288. package/dist/extensions/workflows/loader.js +90 -0
  289. package/dist/extensions/workflows/loader.js.map +1 -0
  290. package/dist/extensions/workflows/model.d.ts +19 -0
  291. package/dist/extensions/workflows/model.js +7 -0
  292. package/dist/extensions/workflows/model.js.map +1 -0
  293. package/dist/extensions/workflows/repository.d.ts +24 -0
  294. package/dist/extensions/workflows/repository.js +61 -0
  295. package/dist/extensions/workflows/repository.js.map +1 -0
  296. package/dist/extensions/workflows/schema.d.ts +193 -0
  297. package/dist/extensions/workflows/schema.js +20 -0
  298. package/dist/extensions/workflows/schema.js.map +1 -0
  299. package/dist/extensions/workflows/tools.d.ts +27 -0
  300. package/dist/extensions/workflows/tools.js +285 -0
  301. package/dist/extensions/workflows/tools.js.map +1 -0
  302. package/dist/log.d.ts +8 -0
  303. package/dist/log.js +15 -0
  304. package/dist/log.js.map +1 -0
  305. package/dist/main.d.ts +2 -0
  306. package/dist/main.js +27 -0
  307. package/dist/main.js.map +1 -0
  308. package/dist/migration/ask.d.ts +8 -0
  309. package/dist/migration/ask.js +24 -0
  310. package/dist/migration/ask.js.map +1 -0
  311. package/dist/migration/config.d.ts +10 -0
  312. package/dist/migration/config.js +122 -0
  313. package/dist/migration/config.js.map +1 -0
  314. package/dist/migration/context.d.ts +3 -0
  315. package/dist/migration/context.js +24 -0
  316. package/dist/migration/context.js.map +1 -0
  317. package/dist/migration/database.d.ts +8 -0
  318. package/dist/migration/database.js +51 -0
  319. package/dist/migration/database.js.map +1 -0
  320. package/dist/migration/fs.d.ts +1 -0
  321. package/dist/migration/fs.js +11 -0
  322. package/dist/migration/fs.js.map +1 -0
  323. package/dist/migration/index.d.ts +11 -0
  324. package/dist/migration/index.js +28 -0
  325. package/dist/migration/index.js.map +1 -0
  326. package/dist/migration/skills.d.ts +19 -0
  327. package/dist/migration/skills.js +77 -0
  328. package/dist/migration/skills.js.map +1 -0
  329. package/dist/scheduler.d.ts +17 -0
  330. package/dist/scheduler.js +53 -0
  331. package/dist/scheduler.js.map +1 -0
  332. package/dist/sessions/registry.d.ts +15 -0
  333. package/dist/sessions/registry.js +42 -0
  334. package/dist/sessions/registry.js.map +1 -0
  335. package/dist/workspace.d.ts +13 -0
  336. package/dist/workspace.js +32 -0
  337. package/dist/workspace.js.map +1 -0
  338. package/drizzle/0000_init.sql +19 -0
  339. package/drizzle/0001_extensions.sql +63 -0
  340. package/drizzle/meta/0000_snapshot.json +134 -0
  341. package/drizzle/meta/0001_snapshot.json +526 -0
  342. package/drizzle/meta/_journal.json +20 -0
  343. package/package.json +63 -0
  344. package/skills/skill-authoring/SKILL.md +168 -0
  345. package/skills/workflow-authoring/SKILL.md +251 -0
@@ -0,0 +1,18 @@
1
+ import type { Delivery } from "../../channels/types.ts";
2
+ import type { Logger } from "../../log.ts";
3
+ import type { TaskRepository } from "./repository.ts";
4
+ import type { TaskDefinitionRecord, TaskInstanceRecord } from "./schema.ts";
5
+ export interface SessionDeliveryDeps {
6
+ repository: TaskRepository;
7
+ deliver: (delivery: Delivery) => void;
8
+ maxHoldSeconds: number;
9
+ now: () => Date;
10
+ log: Logger;
11
+ }
12
+ export declare const renderSessionTaskText: (instance: TaskInstanceRecord, definition: TaskDefinitionRecord | null) => string;
13
+ /**
14
+ * One delivery pass: route pending session instances to the user through the
15
+ * idle-gated channel delivery, walking the pending → running → completed
16
+ * lifecycle. A failed handoff rolls the instance back to pending for retry.
17
+ */
18
+ export declare const deliverSessionTasks: ({ repository, deliver, maxHoldSeconds, now, log, }: SessionDeliveryDeps) => void;
@@ -0,0 +1,39 @@
1
+ export const renderSessionTaskText = (instance, definition) => {
2
+ const label = definition != null ? `Scheduled task: ${definition.name}` : "Scheduled task";
3
+ return `📋 ${label}\n\n${instance.prompt}`;
4
+ };
5
+ /**
6
+ * One delivery pass: route pending session instances to the user through the
7
+ * idle-gated channel delivery, walking the pending → running → completed
8
+ * lifecycle. A failed handoff rolls the instance back to pending for retry.
9
+ */
10
+ export const deliverSessionTasks = ({ repository, deliver, maxHoldSeconds, now, log, }) => {
11
+ for (const instance of repository.getPendingInstances("session")) {
12
+ const definition = instance.definitionId != null ? repository.getDefinition(instance.definitionId) : null;
13
+ repository.updateInstance(instance.id, { status: "running", startedAt: now() });
14
+ try {
15
+ deliver({
16
+ text: renderSessionTaskText(instance, definition),
17
+ gate: "idle",
18
+ // The agent acts on the task inside the session; the user sees its response.
19
+ target: "agent",
20
+ maxHoldSeconds,
21
+ metadata: { kind: "session_task", instanceId: instance.id },
22
+ });
23
+ }
24
+ catch (error) {
25
+ // Roll back so the next tick retries — otherwise the row is stuck
26
+ // running with no delivery attached.
27
+ repository.updateInstance(instance.id, { status: "pending", startedAt: null });
28
+ log.error({ instanceId: instance.id, err: error }, "session task delivery failed");
29
+ continue;
30
+ }
31
+ repository.updateInstance(instance.id, {
32
+ status: "completed",
33
+ completedAt: now(),
34
+ result: "Delivered successfully",
35
+ });
36
+ log.info({ instanceId: instance.id }, "session task delivered");
37
+ }
38
+ };
39
+ //# sourceMappingURL=session-delivery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-delivery.js","sourceRoot":"","sources":["../../../src/extensions/tasks/session-delivery.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,QAA4B,EAC5B,UAAuC,EAC/B,EAAE;IACV,MAAM,KAAK,GAAG,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,mBAAmB,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;IAE3F,OAAO,MAAM,KAAK,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC;AAC7C,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAClC,UAAU,EACV,OAAO,EACP,cAAc,EACd,GAAG,EACH,GAAG,GACiB,EAAQ,EAAE;IAC9B,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;QACjE,MAAM,UAAU,GACd,QAAQ,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAEzF,UAAU,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QAEhF,IAAI,CAAC;YACH,OAAO,CAAC;gBACN,IAAI,EAAE,qBAAqB,CAAC,QAAQ,EAAE,UAAU,CAAC;gBACjD,IAAI,EAAE,MAAM;gBACZ,6EAA6E;gBAC7E,MAAM,EAAE,OAAO;gBACf,cAAc;gBACd,QAAQ,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE;aAC5D,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kEAAkE;YAClE,qCAAqC;YACrC,UAAU,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/E,GAAG,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,8BAA8B,CAAC,CAAC;YACnF,SAAS;QACX,CAAC;QAED,UAAU,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;YACrC,MAAM,EAAE,WAAW;YACnB,WAAW,EAAE,GAAG,EAAE;YAClB,MAAM,EAAE,wBAAwB;SACjC,CAAC,CAAC;QAEH,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,EAAE,wBAAwB,CAAC,CAAC;IAClE,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { ExtensionFactory } from "@earendil-works/pi-coding-agent";
2
+ import { type Static, Type } from "typebox";
3
+ import type { TaskRepository } from "./repository.ts";
4
+ export interface ToolDeps {
5
+ repository: TaskRepository;
6
+ timezone: string | undefined;
7
+ now: () => Date;
8
+ }
9
+ export declare const CreateTaskParams: Type.TObject<{
10
+ name: Type.TString;
11
+ schedule: Type.TString;
12
+ type: Type.TUnsafe<"session" | "background">;
13
+ prompt: Type.TString;
14
+ enabled: Type.TOptional<Type.TBoolean>;
15
+ }>;
16
+ export declare const UpdateTaskParams: Type.TObject<{
17
+ task_id: Type.TString;
18
+ name: Type.TOptional<Type.TString>;
19
+ schedule: Type.TOptional<Type.TString>;
20
+ task_type: Type.TOptional<Type.TUnsafe<"session" | "background">>;
21
+ prompt: Type.TOptional<Type.TString>;
22
+ enabled: Type.TOptional<Type.TBoolean>;
23
+ }>;
24
+ export declare const ListTasksParams: Type.TObject<{
25
+ archived: Type.TOptional<Type.TBoolean>;
26
+ }>;
27
+ export declare const QueryTaskInstancesParams: Type.TObject<{
28
+ status: Type.TOptional<Type.TUnsafe<"completed" | "failed" | "running" | "pending" | "waiting">>;
29
+ task_type: Type.TOptional<Type.TUnsafe<"session" | "background">>;
30
+ definition_id: Type.TOptional<Type.TString>;
31
+ limit: Type.TOptional<Type.TNumber>;
32
+ }>;
33
+ export declare const handleCreateTask: ({ repository, timezone, now }: ToolDeps, args: Static<typeof CreateTaskParams>) => string;
34
+ export declare const handleUpdateTask: ({ repository, timezone, now }: ToolDeps, args: Static<typeof UpdateTaskParams>) => string;
35
+ export declare const handleListTasks: ({ repository, timezone }: ToolDeps, args: Static<typeof ListTasksParams>) => string;
36
+ export declare const handleQueryTaskInstances: ({ repository, timezone }: ToolDeps, args: Static<typeof QueryTaskInstancesParams>) => string;
37
+ /** pi extension factory exposing the task management tools to the agent. */
38
+ export declare const createTaskToolsFactory: (deps: ToolDeps) => ExtensionFactory;
@@ -0,0 +1,181 @@
1
+ import { StringEnum } from "@earendil-works/pi-ai";
2
+ import { Type } from "typebox";
3
+ import { formatInTimezone, formatSchedule, parseSchedule } from "./schedule.js";
4
+ const SCHEDULE_DESCRIPTION = "Cron expression (e.g., '0 9 * * *' for daily at 9 AM), bare ISO datetime interpreted in the configured timezone (e.g., '2026-04-01T15:00:00'), or ISO datetime with 'Z'/offset for an explicit zone";
5
+ export const CreateTaskParams = Type.Object({
6
+ name: Type.String({ description: "Human-readable task name" }),
7
+ schedule: Type.String({ description: SCHEDULE_DESCRIPTION }),
8
+ type: StringEnum(["session", "background"], {
9
+ description: "'session' (delivered during idle) or 'background' (isolated execution)",
10
+ }),
11
+ prompt: Type.String({ description: "Instruction the agent follows when the task fires" }),
12
+ enabled: Type.Optional(Type.Boolean({ description: "Whether the task is active (default true)" })),
13
+ });
14
+ export const UpdateTaskParams = Type.Object({
15
+ task_id: Type.String({ description: "ID of the task to update (get IDs from list_tasks)" }),
16
+ name: Type.Optional(Type.String({ description: "New human-readable name" })),
17
+ schedule: Type.Optional(Type.String({ description: SCHEDULE_DESCRIPTION })),
18
+ task_type: Type.Optional(StringEnum(["session", "background"], {
19
+ description: "Change type — 'session' or 'background'",
20
+ })),
21
+ prompt: Type.Optional(Type.String({ description: "New agent instruction" })),
22
+ enabled: Type.Optional(Type.Boolean({ description: "Enable or disable the task" })),
23
+ });
24
+ export const ListTasksParams = Type.Object({
25
+ archived: Type.Optional(Type.Boolean({
26
+ description: "Set true to show disabled (archived) tasks instead of active ones",
27
+ })),
28
+ });
29
+ export const QueryTaskInstancesParams = Type.Object({
30
+ status: Type.Optional(StringEnum(["pending", "running", "waiting", "completed", "failed"], {
31
+ description: "Filter by instance status",
32
+ })),
33
+ task_type: Type.Optional(StringEnum(["session", "background"], { description: "Filter by task type" })),
34
+ definition_id: Type.Optional(Type.String({ description: "Filter by parent task definition ID" })),
35
+ limit: Type.Optional(Type.Number({ description: "Maximum entries to return (default 20)" })),
36
+ });
37
+ const describeDefinition = (definition, timezone) => {
38
+ const status = definition.enabled ? "✓ enabled" : "✗ disabled";
39
+ const lastFired = definition.lastFiredAt != null
40
+ ? ` (last: ${formatInTimezone(definition.lastFiredAt, timezone)})`
41
+ : "";
42
+ return [
43
+ `- [${definition.id}] **${definition.name}** [${definition.taskType}] ${status}`,
44
+ ` Schedule: ${formatSchedule(definition.schedule, timezone)}${lastFired}`,
45
+ "",
46
+ ];
47
+ };
48
+ export const handleCreateTask = ({ repository, timezone, now }, args) => {
49
+ const schedule = parseSchedule(args.schedule, timezone, now());
50
+ const created = repository.createDefinition({
51
+ name: args.name,
52
+ schedule,
53
+ taskType: args.type,
54
+ prompt: args.prompt,
55
+ enabled: args.enabled ?? true,
56
+ });
57
+ return [
58
+ `Task '${created.name}' created successfully.`,
59
+ `- ID: ${created.id}`,
60
+ `- Type: ${created.taskType}`,
61
+ `- Schedule: ${formatSchedule(created.schedule, timezone)}`,
62
+ `- Enabled: ${created.enabled}`,
63
+ ].join("\n");
64
+ };
65
+ export const handleUpdateTask = ({ repository, timezone, now }, args) => {
66
+ const existing = repository.getDefinition(args.task_id);
67
+ if (existing == null)
68
+ throw new Error(`Task '${args.task_id}' not found.`);
69
+ const patch = {};
70
+ if (args.name != null)
71
+ patch.name = args.name;
72
+ if (args.prompt != null)
73
+ patch.prompt = args.prompt;
74
+ if (args.enabled != null)
75
+ patch.enabled = args.enabled;
76
+ if (args.task_type != null)
77
+ patch.taskType = args.task_type;
78
+ if (args.schedule != null) {
79
+ patch.schedule = parseSchedule(args.schedule, timezone, now());
80
+ // The old fire time is meaningless for a new schedule — one-shots require a
81
+ // null lastFiredAt to fire, and the cron anchor falls back gracefully.
82
+ patch.lastFiredAt = null;
83
+ }
84
+ if (Object.keys(patch).length === 0)
85
+ return "No updates provided.";
86
+ repository.updateDefinition(args.task_id, patch);
87
+ return `Task '${args.task_id}' updated successfully.`;
88
+ };
89
+ export const handleListTasks = ({ repository, timezone }, args) => {
90
+ const archived = args.archived ?? false;
91
+ const definitions = archived
92
+ ? repository.listDisabledDefinitions()
93
+ : repository.listEnabledDefinitions();
94
+ if (definitions.length === 0)
95
+ return `No ${archived ? "archived" : "active"} tasks found.`;
96
+ return [
97
+ "# Task Definitions",
98
+ "",
99
+ ...definitions.flatMap((definition) => describeDefinition(definition, timezone)),
100
+ ].join("\n");
101
+ };
102
+ export const handleQueryTaskInstances = ({ repository, timezone }, args) => {
103
+ const instances = repository.queryInstances({
104
+ status: args.status,
105
+ taskType: args.task_type,
106
+ definitionId: args.definition_id,
107
+ limit: args.limit ?? 20,
108
+ });
109
+ if (instances.length === 0)
110
+ return "No task instances found.";
111
+ const lines = ["# Task Instances", ""];
112
+ for (const instance of instances) {
113
+ lines.push(`- [${instance.id}] [${instance.taskType}] ${instance.status} — scheduled for ${formatInTimezone(instance.scheduledFor, timezone)}`);
114
+ if (instance.definitionId != null)
115
+ lines.push(` Definition: ${instance.definitionId}`);
116
+ if (instance.result != null)
117
+ lines.push(` Result: ${instance.result}`);
118
+ lines.push("");
119
+ }
120
+ return lines.join("\n");
121
+ };
122
+ const textResult = (text) => ({
123
+ content: [{ type: "text", text }],
124
+ details: undefined,
125
+ });
126
+ /** pi extension factory exposing the task management tools to the agent. */
127
+ export const createTaskToolsFactory = (deps) => (pi) => {
128
+ pi.registerTool({
129
+ name: "create_task",
130
+ label: "Create Task",
131
+ description: "Create a new scheduled task definition. Tasks fire on a cron schedule (recurring) or at an ISO datetime (one-shot); 'session' tasks are delivered into the conversation during idle time, 'background' tasks run autonomously in an isolated agent.",
132
+ promptSnippet: "Schedule recurring or one-shot tasks (reminders, checks, background work)",
133
+ promptGuidelines: [
134
+ "Use create_task when the user asks to be reminded, to schedule recurring work, or to run something later.",
135
+ ],
136
+ parameters: CreateTaskParams,
137
+ async execute(_toolCallId, params) {
138
+ return textResult(handleCreateTask(deps, params));
139
+ },
140
+ });
141
+ pi.registerTool({
142
+ name: "update_task",
143
+ label: "Update Task",
144
+ description: "Update an existing task definition. Only provided fields are updated; omitted fields remain unchanged. Disable a task with enabled=false instead of deleting it.",
145
+ promptSnippet: "Modify or enable/disable an existing scheduled task",
146
+ promptGuidelines: [
147
+ "Use update_task with enabled=false to archive a task the user no longer wants.",
148
+ ],
149
+ parameters: UpdateTaskParams,
150
+ async execute(_toolCallId, params) {
151
+ return textResult(handleUpdateTask(deps, params));
152
+ },
153
+ });
154
+ pi.registerTool({
155
+ name: "list_tasks",
156
+ label: "List Tasks",
157
+ description: "List task definitions. Each entry includes the task ID (needed for update_task and query_task_instances), name, type, schedule, and status. Pass archived=true to show disabled tasks.",
158
+ promptSnippet: "List scheduled task definitions",
159
+ promptGuidelines: [
160
+ "Check list_tasks before create_task to avoid scheduling duplicate tasks.",
161
+ ],
162
+ parameters: ListTasksParams,
163
+ async execute(_toolCallId, params) {
164
+ return textResult(handleListTasks(deps, params));
165
+ },
166
+ });
167
+ pi.registerTool({
168
+ name: "query_task_instances",
169
+ label: "Query Task Instances",
170
+ description: "Query task execution instances (individual firings of task definitions), optionally filtered by status, task type, or parent definition. Use this to check whether and when a task ran and what it produced.",
171
+ promptSnippet: "Inspect past and pending runs of scheduled tasks",
172
+ promptGuidelines: [
173
+ "Use query_task_instances when the user asks whether a scheduled task ran or what its outcome was.",
174
+ ],
175
+ parameters: QueryTaskInstancesParams,
176
+ async execute(_toolCallId, params) {
177
+ return textResult(handleQueryTaskInstances(deps, params));
178
+ },
179
+ });
180
+ };
181
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/extensions/tasks/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { InlineKeyboardMarkup } from "grammy/types";
2
+ export declare const MAX_BUTTON_VALUE_BYTES = 58;
3
+ export declare const MAX_BUTTON_COUNT = 100;
4
+ export interface ButtonSpec {
5
+ label: string;
6
+ value: string;
7
+ }
8
+ export declare const packCallbackData: (value: string, singleUse: boolean) => string;
9
+ export declare const unpackCallbackData: (data: string) => {
10
+ value: string;
11
+ singleUse: boolean;
12
+ } | null;
13
+ export declare const validateButtons: (rows: ButtonSpec[][]) => void;
14
+ export declare const buildInlineKeyboard: (rows: ButtonSpec[][], singleUse: boolean) => InlineKeyboardMarkup;
@@ -0,0 +1,49 @@
1
+ // Telegram caps callback_data at 64 bytes; the 5-byte prefix leaves 58 for the value.
2
+ export const MAX_BUTTON_VALUE_BYTES = 58;
3
+ export const MAX_BUTTON_COUNT = 100;
4
+ const SINGLE_USE_PREFIX = "btn1:";
5
+ const MULTI_USE_PREFIX = "btnN:";
6
+ export const packCallbackData = (value, singleUse) => `${singleUse ? SINGLE_USE_PREFIX : MULTI_USE_PREFIX}${value}`;
7
+ export const unpackCallbackData = (data) => {
8
+ if (data.startsWith(SINGLE_USE_PREFIX)) {
9
+ return { value: data.slice(SINGLE_USE_PREFIX.length), singleUse: true };
10
+ }
11
+ if (data.startsWith(MULTI_USE_PREFIX)) {
12
+ return { value: data.slice(MULTI_USE_PREFIX.length), singleUse: false };
13
+ }
14
+ return null;
15
+ };
16
+ export const validateButtons = (rows) => {
17
+ if (rows.length === 0)
18
+ throw new Error("buttons must contain at least one row");
19
+ let total = 0;
20
+ rows.forEach((row, rowIndex) => {
21
+ if (row.length === 0) {
22
+ throw new Error(`row ${rowIndex} must contain at least one button`);
23
+ }
24
+ row.forEach((button, buttonIndex) => {
25
+ if (button.label.trim().length === 0) {
26
+ throw new Error(`button at row ${rowIndex} index ${buttonIndex} has an empty label`);
27
+ }
28
+ if (button.value.length === 0) {
29
+ throw new Error(`button at row ${rowIndex} index ${buttonIndex} has an empty value`);
30
+ }
31
+ const bytes = Buffer.byteLength(button.value, "utf8");
32
+ if (bytes > MAX_BUTTON_VALUE_BYTES) {
33
+ throw new Error(`button value "${button.value.slice(0, 20)}…" exceeds the ` +
34
+ `${MAX_BUTTON_VALUE_BYTES}-byte limit (${bytes} bytes)`);
35
+ }
36
+ total += 1;
37
+ });
38
+ });
39
+ if (total > MAX_BUTTON_COUNT) {
40
+ throw new Error(`total button count (${total}) exceeds the cap (${MAX_BUTTON_COUNT})`);
41
+ }
42
+ };
43
+ export const buildInlineKeyboard = (rows, singleUse) => ({
44
+ inline_keyboard: rows.map((row) => row.map((button) => ({
45
+ text: button.label,
46
+ callback_data: packCallbackData(button.value, singleUse),
47
+ }))),
48
+ });
49
+ //# sourceMappingURL=buttons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buttons.js","sourceRoot":"","sources":["../../../src/extensions/telegram/buttons.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { Bot } from "grammy";
2
+ import type { Channel, ChannelRuntime, Delivery, Exchange } from "../../channels/types.ts";
3
+ export interface TelegramChannelOptions {
4
+ chatId: number;
5
+ allowMedia: boolean;
6
+ pushNotifications: boolean;
7
+ mediaDir: string;
8
+ /** Abort the in-flight agent run — wired from sessions.abortExchange. */
9
+ stop: () => Promise<void>;
10
+ }
11
+ export declare const STOP_COMMAND = "/stop";
12
+ export declare const STOP_ACKNOWLEDGEMENT = "\u23F9 Stopped.";
13
+ export declare class TelegramChannel implements Channel {
14
+ readonly name = "telegram";
15
+ private readonly bot;
16
+ private readonly options;
17
+ private readonly mutex;
18
+ private runtime;
19
+ private lastInboundId;
20
+ private lastOutboundId;
21
+ private activeRenderer;
22
+ constructor(bot: Bot, options: TelegramChannelOptions);
23
+ /** Last message received from the user — target for react_to_message. */
24
+ get lastInboundMessageId(): number | null;
25
+ /** Last message this channel sent — target for pin_message. */
26
+ get lastOutboundMessageId(): number | null;
27
+ start(runtime: ChannelRuntime): Promise<void>;
28
+ respond({ events }: Exchange): Promise<void>;
29
+ deliver(delivery: Delivery): Promise<void>;
30
+ status(text: string): void;
31
+ stop(): Promise<void>;
32
+ private handleText;
33
+ /** Abort the in-flight run instead of submitting — "/stop" never reaches the agent. */
34
+ private handleStop;
35
+ private handleMedia;
36
+ private sendErrorNotice;
37
+ private runtimeOrThrow;
38
+ private log;
39
+ }
@@ -0,0 +1,201 @@
1
+ import { join } from "node:path";
2
+ import { unpackCallbackData } from "./buttons.js";
3
+ import { mapButtonTap, mapMediaMessage, mapTextMessage } from "./inbound.js";
4
+ import { buildAttachment, downloadMedia, generateMediaFilename, MediaTooLargeError, resolveMedia, } from "./media.js";
5
+ import { Mutex } from "./mutex.js";
6
+ import { deliverText, startTyping } from "./sending.js";
7
+ import { StreamRenderer } from "./streaming.js";
8
+ export const STOP_COMMAND = "/stop";
9
+ export const STOP_ACKNOWLEDGEMENT = "⏹ Stopped.";
10
+ export class TelegramChannel {
11
+ name = "telegram";
12
+ bot;
13
+ options;
14
+ mutex = new Mutex();
15
+ runtime = null;
16
+ lastInboundId = null;
17
+ lastOutboundId = null;
18
+ activeRenderer = null;
19
+ constructor(bot, options) {
20
+ this.bot = bot;
21
+ this.options = options;
22
+ }
23
+ /** Last message received from the user — target for react_to_message. */
24
+ get lastInboundMessageId() {
25
+ return this.lastInboundId;
26
+ }
27
+ /** Last message this channel sent — target for pin_message. */
28
+ get lastOutboundMessageId() {
29
+ return this.lastOutboundId;
30
+ }
31
+ async start(runtime) {
32
+ this.runtime = runtime;
33
+ this.bot.on("message", async (ctx) => {
34
+ if (ctx.chat.id !== this.options.chatId)
35
+ return;
36
+ if (ctx.message.text != null) {
37
+ await this.handleText(ctx.message);
38
+ }
39
+ else {
40
+ await this.handleMedia(ctx.message);
41
+ }
42
+ });
43
+ this.bot.on("callback_query:data", async (ctx) => {
44
+ await ctx
45
+ .answerCallbackQuery()
46
+ .catch((error) => runtime.log.warn({ err: error }, "callback answer failed"));
47
+ if (ctx.callbackQuery.from.id !== this.options.chatId) {
48
+ runtime.log.debug({ userId: ctx.callbackQuery.from.id }, "dropping unauthorized tap");
49
+ return;
50
+ }
51
+ const unpacked = unpackCallbackData(ctx.callbackQuery.data);
52
+ if (unpacked == null) {
53
+ runtime.log.warn({ data: ctx.callbackQuery.data }, "unrecognized callback data");
54
+ return;
55
+ }
56
+ const messageId = ctx.callbackQuery.message?.message_id ?? null;
57
+ if (unpacked.singleUse && messageId != null) {
58
+ void this.bot.api
59
+ .editMessageReplyMarkup(this.options.chatId, messageId)
60
+ .catch((error) => runtime.log.warn({ err: error }, "keyboard removal failed"));
61
+ }
62
+ runtime.submit(mapButtonTap(unpacked.value, messageId));
63
+ });
64
+ this.bot.catch(({ error }) => {
65
+ runtime.log.error({ err: error }, "telegram update handling failed");
66
+ });
67
+ // init() validates the token via getMe before going live; start() resolves
68
+ // only when polling stops, so it runs detached.
69
+ await this.bot.init();
70
+ void this.bot
71
+ .start({
72
+ allowed_updates: ["message", "callback_query"],
73
+ onStart: (me) => runtime.log.info({ username: me.username }, "telegram bot polling"),
74
+ })
75
+ .catch((error) => runtime.log.error({ err: error }, "telegram polling crashed"));
76
+ }
77
+ async respond({ events }) {
78
+ const log = this.log();
79
+ await this.mutex.run(async () => {
80
+ const stopTyping = startTyping(this.bot.api, this.options.chatId, log);
81
+ const renderer = new StreamRenderer(this.bot.api, this.options.chatId, log);
82
+ this.activeRenderer = renderer;
83
+ try {
84
+ for await (const event of events) {
85
+ switch (event.kind) {
86
+ case "text":
87
+ await renderer.appendText(event.text);
88
+ break;
89
+ case "tool-start":
90
+ await renderer.showTransient(`⚙ ${event.toolName}`);
91
+ break;
92
+ case "status":
93
+ await renderer.showTransient(event.text);
94
+ break;
95
+ case "error":
96
+ await this.sendErrorNotice(event.message, log);
97
+ break;
98
+ default:
99
+ break;
100
+ }
101
+ }
102
+ }
103
+ finally {
104
+ this.activeRenderer = null;
105
+ stopTyping();
106
+ }
107
+ this.lastOutboundId = (await renderer.finalize()) ?? this.lastOutboundId;
108
+ });
109
+ }
110
+ async deliver(delivery) {
111
+ const log = this.log();
112
+ await this.mutex.run(async () => {
113
+ const lastId = await deliverText(this.bot.api, this.options.chatId, delivery.text, this.options.pushNotifications, log);
114
+ if (lastId != null)
115
+ this.lastOutboundId = lastId;
116
+ });
117
+ }
118
+ status(text) {
119
+ const renderer = this.activeRenderer;
120
+ if (renderer != null) {
121
+ void renderer
122
+ .showTransient(text)
123
+ .catch((error) => this.log().debug({ err: error }, "status rendering failed"));
124
+ return;
125
+ }
126
+ // No streaming message to surface the line in — show liveness via typing.
127
+ void this.bot.api
128
+ .sendChatAction(this.options.chatId, "typing")
129
+ .catch((error) => this.log().debug({ err: error }, "status typing action failed"));
130
+ }
131
+ async stop() {
132
+ if (this.bot.isRunning())
133
+ await this.bot.stop();
134
+ }
135
+ async handleText(message) {
136
+ if (message.text?.trim() === STOP_COMMAND) {
137
+ this.lastInboundId = message.message_id;
138
+ await this.handleStop();
139
+ return;
140
+ }
141
+ const inbound = mapTextMessage(message);
142
+ if (inbound == null)
143
+ return;
144
+ this.lastInboundId = message.message_id;
145
+ this.runtimeOrThrow().submit(inbound);
146
+ }
147
+ /** Abort the in-flight run instead of submitting — "/stop" never reaches the agent. */
148
+ async handleStop() {
149
+ const log = this.log();
150
+ try {
151
+ await this.options.stop();
152
+ }
153
+ catch (error) {
154
+ log.warn({ err: error }, "exchange abort failed");
155
+ }
156
+ await this.bot.api
157
+ .sendMessage(this.options.chatId, STOP_ACKNOWLEDGEMENT)
158
+ .catch((error) => log.warn({ err: error }, "stop acknowledgement failed"));
159
+ }
160
+ async handleMedia(message) {
161
+ const log = this.log();
162
+ if (!this.options.allowMedia) {
163
+ log.debug("ignoring media message — allowMedia is disabled");
164
+ return;
165
+ }
166
+ const resolved = resolveMedia(message);
167
+ if (resolved == null) {
168
+ log.debug("ignoring unresolvable media message");
169
+ return;
170
+ }
171
+ this.lastInboundId = message.message_id;
172
+ try {
173
+ const destPath = join(this.options.mediaDir, generateMediaFilename(resolved));
174
+ await downloadMedia(this.bot.api, this.bot.token, resolved, destPath);
175
+ this.runtimeOrThrow().submit(mapMediaMessage(message, buildAttachment(resolved, destPath)));
176
+ }
177
+ catch (error) {
178
+ log.warn({ err: error }, "media download failed");
179
+ const notice = error instanceof MediaTooLargeError
180
+ ? error.message
181
+ : "Failed to download the file. Please try again.";
182
+ await this.bot.api
183
+ .sendMessage(this.options.chatId, notice)
184
+ .catch((sendError) => log.warn({ err: sendError }, "media failure notice failed"));
185
+ }
186
+ }
187
+ async sendErrorNotice(message, log) {
188
+ await this.bot.api
189
+ .sendMessage(this.options.chatId, `⚠️ Error: ${message}`)
190
+ .catch((error) => log.warn({ err: error }, "error notice failed"));
191
+ }
192
+ runtimeOrThrow() {
193
+ if (this.runtime == null)
194
+ throw new Error("telegram channel not started");
195
+ return this.runtime;
196
+ }
197
+ log() {
198
+ return this.runtimeOrThrow().log;
199
+ }
200
+ }
201
+ //# sourceMappingURL=channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../../../src/extensions/telegram/channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare const TELEGRAM_MAX_MESSAGE_LENGTH = 4096;
2
+ /**
3
+ * Split text into chunks within Telegram's message length limit, preferring
4
+ * paragraph boundaries, then line boundaries, then a hard split that never
5
+ * cuts a surrogate pair in half.
6
+ */
7
+ export declare const splitMessage: (text: string, limit?: number) => string[];