@fastagent-sh/fastagent 0.24.4 → 0.26.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 (487) hide show
  1. package/README.md +54 -82
  2. package/dist/agent-api.d.ts +460 -0
  3. package/dist/agent-api.js +209 -0
  4. package/dist/answer-text.d.ts +8 -0
  5. package/dist/answer-text.js +18 -0
  6. package/dist/atomic-write.d.ts +2 -2
  7. package/dist/atomic-write.js +2 -2
  8. package/dist/authoring.d.ts +81 -0
  9. package/dist/authoring.js +245 -0
  10. package/dist/channel.d.ts +29 -15
  11. package/dist/channel.js +4 -1
  12. package/dist/channels/agentcore-protocol.d.ts +36 -50
  13. package/dist/channels/agentcore-protocol.js +3 -3
  14. package/dist/channels/agentcore-service.d.ts +8 -18
  15. package/dist/channels/agentcore-service.js +108 -127
  16. package/dist/channels/agentcore.d.ts +8 -24
  17. package/dist/channels/agentcore.js +32 -65
  18. package/dist/channels/body.d.ts +0 -16
  19. package/dist/channels/body.js +0 -25
  20. package/dist/channels/busy.js +6 -1
  21. package/dist/channels/context.d.ts +4 -0
  22. package/dist/channels/context.js +35 -0
  23. package/dist/channels/discover.d.ts +18 -20
  24. package/dist/channels/discover.js +41 -99
  25. package/dist/channels/feishu/feishu-api.d.ts +54 -4
  26. package/dist/channels/feishu/feishu-api.js +192 -149
  27. package/dist/channels/feishu/feishu.d.ts +3 -0
  28. package/dist/channels/feishu/feishu.js +117 -106
  29. package/dist/channels/feishu/history.d.ts +55 -0
  30. package/dist/channels/feishu/history.js +199 -0
  31. package/dist/channels/feishu/invoke-turn.d.ts +13 -11
  32. package/dist/channels/feishu/invoke-turn.js +9 -10
  33. package/dist/channels/feishu/model.d.ts +2 -1
  34. package/dist/channels/feishu/normalize.js +100 -0
  35. package/dist/channels/feishu/preview.d.ts +2 -2
  36. package/dist/channels/feishu/register-webhook.d.ts +1 -0
  37. package/dist/channels/feishu/register-webhook.js +3 -2
  38. package/dist/channels/feishu/scaffold/channel.ts +65 -46
  39. package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
  40. package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
  41. package/dist/channels/feishu/setup-mode.d.ts +45 -25
  42. package/dist/channels/feishu/setup-mode.js +74 -23
  43. package/dist/channels/feishu/shared-api.d.ts +24 -6
  44. package/dist/channels/feishu/shared-api.js +30 -24
  45. package/dist/channels/kit/context-buffer.d.ts +11 -2
  46. package/dist/channels/kit/context-buffer.js +7 -4
  47. package/dist/channels/kit/delivery.d.ts +19 -3
  48. package/dist/channels/kit/delivery.js +74 -15
  49. package/dist/channels/kit/event-stream.js +2 -1
  50. package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
  51. package/dist/channels/kit/invoke-turn-kit.js +62 -71
  52. package/dist/channels/kit/place-history.d.ts +107 -0
  53. package/dist/channels/kit/place-history.js +182 -0
  54. package/dist/channels/kit/preview-kit.d.ts +9 -5
  55. package/dist/channels/kit/preview-kit.js +36 -15
  56. package/dist/channels/kit/room-threads.d.ts +46 -0
  57. package/dist/channels/kit/room-threads.js +81 -0
  58. package/dist/channels/kit/seen.js +1 -1
  59. package/dist/channels/kit/stop-command.d.ts +6 -3
  60. package/dist/channels/kit/stop-command.js +20 -18
  61. package/dist/channels/kit/thread-fork.d.ts +17 -0
  62. package/dist/channels/kit/thread-fork.js +43 -0
  63. package/dist/channels/kit/thread-participants.js +1 -1
  64. package/dist/channels/kit/transport.d.ts +5 -0
  65. package/dist/channels/kit/transport.js +5 -0
  66. package/dist/channels/kit/turn-runner.d.ts +10 -9
  67. package/dist/channels/kit/turn-runner.js +17 -19
  68. package/dist/channels/kit/turn-store.d.ts +5 -4
  69. package/dist/channels/kit/turn-store.js +5 -5
  70. package/dist/channels/lark/lark.d.ts +3 -0
  71. package/dist/channels/lark/lark.js +5 -0
  72. package/dist/channels/lark/onboard.d.ts +5 -3
  73. package/dist/channels/lark/onboard.js +14 -14
  74. package/dist/channels/lark/scaffold/channel.ts +67 -44
  75. package/dist/channels/lark/scaffold/lark-send.ts +38 -33
  76. package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
  77. package/dist/channels/respond.d.ts +0 -4
  78. package/dist/channels/respond.js +1 -1
  79. package/dist/channels/router.d.ts +18 -0
  80. package/dist/channels/router.js +68 -0
  81. package/dist/channels/serve.d.ts +5 -70
  82. package/dist/channels/serve.js +105 -287
  83. package/dist/channels/slack/history.d.ts +42 -0
  84. package/dist/channels/slack/history.js +282 -0
  85. package/dist/channels/slack/invoke-turn.d.ts +12 -5
  86. package/dist/channels/slack/invoke-turn.js +7 -5
  87. package/dist/channels/slack/manifest.d.ts +1 -4
  88. package/dist/channels/slack/manifest.js +22 -10
  89. package/dist/channels/slack/model.d.ts +2 -1
  90. package/dist/channels/slack/onboard.d.ts +0 -2
  91. package/dist/channels/slack/onboard.js +2 -4
  92. package/dist/channels/slack/onboarding-state.d.ts +0 -2
  93. package/dist/channels/slack/onboarding-state.js +0 -1
  94. package/dist/channels/slack/parse.d.ts +0 -5
  95. package/dist/channels/slack/parse.js +1 -16
  96. package/dist/channels/slack/preview.d.ts +2 -3
  97. package/dist/channels/slack/preview.js +78 -52
  98. package/dist/channels/slack/register-webhook.d.ts +1 -0
  99. package/dist/channels/slack/register-webhook.js +6 -5
  100. package/dist/channels/slack/scaffold/channel.ts +23 -24
  101. package/dist/channels/slack/scaffold/slack-send.ts +50 -43
  102. package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
  103. package/dist/channels/slack/setup-server.d.ts +19 -0
  104. package/dist/channels/slack/setup-server.js +113 -11
  105. package/dist/channels/slack/shared-api.d.ts +15 -4
  106. package/dist/channels/slack/shared-api.js +19 -14
  107. package/dist/channels/slack/slack-api.d.ts +61 -2
  108. package/dist/channels/slack/slack-api.js +28 -5
  109. package/dist/channels/slack/slack.js +97 -52
  110. package/dist/channels/slack/welcomed.js +1 -1
  111. package/dist/channels/telegram/context-buffer.d.ts +6 -1
  112. package/dist/channels/telegram/context-buffer.js +19 -0
  113. package/dist/channels/telegram/invoke-turn.d.ts +8 -4
  114. package/dist/channels/telegram/invoke-turn.js +7 -7
  115. package/dist/channels/telegram/parse.d.ts +7 -2
  116. package/dist/channels/telegram/parse.js +7 -0
  117. package/dist/channels/telegram/preview.d.ts +2 -2
  118. package/dist/channels/telegram/register-webhook.d.ts +1 -0
  119. package/dist/channels/telegram/register-webhook.js +3 -2
  120. package/dist/channels/telegram/scaffold/channel.ts +27 -28
  121. package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
  122. package/dist/channels/telegram/shared-api.d.ts +34 -0
  123. package/dist/channels/telegram/shared-api.js +79 -0
  124. package/dist/channels/telegram/telegram-api.d.ts +15 -5
  125. package/dist/channels/telegram/telegram-api.js +10 -6
  126. package/dist/channels/telegram/telegram.js +27 -21
  127. package/dist/channels/telegram/turn-store.js +1 -1
  128. package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
  129. package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
  130. package/dist/cli/add-feishu.d.ts +42 -12
  131. package/dist/cli/add-feishu.js +177 -124
  132. package/dist/cli/add-slack.d.ts +8 -3
  133. package/dist/cli/add-slack.js +116 -64
  134. package/dist/cli/auth-view.d.ts +10 -3
  135. package/dist/cli/auth-view.js +8 -6
  136. package/dist/cli/box-login.d.ts +18 -7
  137. package/dist/cli/box-login.js +46 -12
  138. package/dist/cli/commands/add.d.ts +15 -4
  139. package/dist/cli/commands/add.js +253 -143
  140. package/dist/cli/commands/auth.d.ts +6 -0
  141. package/dist/cli/commands/auth.js +50 -0
  142. package/dist/cli/commands/content.d.ts +6 -0
  143. package/dist/cli/commands/content.js +45 -0
  144. package/dist/cli/commands/deploy/agentcore.js +50 -77
  145. package/dist/cli/commands/deploy/docker.js +38 -39
  146. package/dist/cli/commands/deploy/fly.js +21 -18
  147. package/dist/cli/commands/deploy/host-login.d.ts +26 -0
  148. package/dist/cli/commands/deploy/host-login.js +90 -0
  149. package/dist/cli/commands/deploy/railway.js +21 -26
  150. package/dist/cli/commands/deploy/shared.d.ts +45 -17
  151. package/dist/cli/commands/deploy/shared.js +34 -15
  152. package/dist/cli/commands/deploy.d.ts +0 -4
  153. package/dist/cli/commands/deploy.js +237 -50
  154. package/dist/cli/commands/destroy.js +8 -6
  155. package/dist/cli/commands/dev.d.ts +0 -2
  156. package/dist/cli/commands/dev.js +20 -19
  157. package/dist/cli/commands/env.d.ts +12 -0
  158. package/dist/cli/commands/env.js +191 -0
  159. package/dist/cli/commands/info.js +95 -156
  160. package/dist/cli/commands/init.d.ts +2 -2
  161. package/dist/cli/commands/init.js +35 -33
  162. package/dist/cli/commands/invoke.d.ts +6 -0
  163. package/dist/cli/commands/invoke.js +132 -16
  164. package/dist/cli/commands/login.d.ts +31 -2
  165. package/dist/cli/commands/login.js +416 -65
  166. package/dist/cli/commands/logout.d.ts +4 -0
  167. package/dist/cli/commands/logout.js +53 -0
  168. package/dist/cli/commands/logs.js +8 -6
  169. package/dist/cli/commands/models.d.ts +2 -1
  170. package/dist/cli/commands/models.js +39 -37
  171. package/dist/cli/commands/schedules.d.ts +21 -0
  172. package/dist/cli/commands/schedules.js +143 -0
  173. package/dist/cli/commands/start.d.ts +11 -10
  174. package/dist/cli/commands/start.js +35 -62
  175. package/dist/cli/content-view.d.ts +9 -0
  176. package/dist/cli/content-view.js +26 -0
  177. package/dist/cli/fail.d.ts +9 -12
  178. package/dist/cli/fail.js +17 -14
  179. package/dist/cli/invoke-stream.d.ts +12 -3
  180. package/dist/cli/invoke-stream.js +85 -23
  181. package/dist/cli/kernel.d.ts +9 -2
  182. package/dist/cli/kernel.js +15 -6
  183. package/dist/cli/login-relay.d.ts +6 -4
  184. package/dist/cli/login-relay.js +19 -7
  185. package/dist/cli/models-view.d.ts +5 -1
  186. package/dist/cli/models-view.js +1 -1
  187. package/dist/cli/person.d.ts +10 -0
  188. package/dist/cli/person.js +23 -0
  189. package/dist/cli/program.js +421 -203
  190. package/dist/cli/serve.d.ts +13 -63
  191. package/dist/cli/serve.js +31 -121
  192. package/dist/cli/shared.d.ts +21 -48
  193. package/dist/cli/shared.js +70 -89
  194. package/dist/cli/ticket.d.ts +136 -0
  195. package/dist/cli/ticket.js +476 -0
  196. package/dist/client.d.ts +7 -0
  197. package/dist/client.js +2 -0
  198. package/dist/content/declare.d.ts +70 -0
  199. package/dist/content/declare.js +163 -0
  200. package/dist/content/file.d.ts +32 -0
  201. package/dist/content/file.js +119 -0
  202. package/dist/content/git.d.ts +41 -0
  203. package/dist/content/git.js +220 -0
  204. package/dist/content/mount.d.ts +2 -0
  205. package/dist/content/mount.js +15 -0
  206. package/dist/content/resolve.d.ts +52 -0
  207. package/dist/content/resolve.js +151 -0
  208. package/dist/content/source.d.ts +27 -0
  209. package/dist/content/source.js +53 -0
  210. package/dist/conversation-sessions.d.ts +26 -0
  211. package/dist/conversation-sessions.js +99 -0
  212. package/dist/declared-secrets.d.ts +19 -37
  213. package/dist/declared-secrets.js +16 -58
  214. package/dist/deploy/agentcore/destroy.d.ts +3 -3
  215. package/dist/deploy/agentcore/destroy.js +46 -28
  216. package/dist/deploy/agentcore/forwarder.js +105 -22
  217. package/dist/deploy/agentcore/logs.js +1 -1
  218. package/dist/deploy/agentcore/plan.d.ts +10 -24
  219. package/dist/deploy/agentcore/plan.js +31 -135
  220. package/dist/deploy/agentcore/run.d.ts +1 -1
  221. package/dist/deploy/agentcore/run.js +8 -5
  222. package/dist/deploy/agentcore/shell.d.ts +1 -1
  223. package/dist/deploy/agentcore/shell.js +5 -5
  224. package/dist/deploy/api.d.ts +34 -0
  225. package/dist/deploy/api.js +50 -0
  226. package/dist/deploy/box-shell.d.ts +6 -0
  227. package/dist/deploy/box-shell.js +7 -0
  228. package/dist/deploy/build-context.d.ts +7 -5
  229. package/dist/deploy/build-context.js +41 -35
  230. package/dist/deploy/channel-ingress.d.ts +6 -1
  231. package/dist/deploy/channel-ingress.js +18 -5
  232. package/dist/deploy/container.d.ts +22 -9
  233. package/dist/deploy/container.js +96 -55
  234. package/dist/deploy/docker/plan.d.ts +3 -2
  235. package/dist/deploy/docker/plan.js +13 -14
  236. package/dist/deploy/docker/run.d.ts +2 -2
  237. package/dist/deploy/docker/run.js +8 -4
  238. package/dist/deploy/fly/plan.d.ts +1 -1
  239. package/dist/deploy/fly/plan.js +12 -21
  240. package/dist/deploy/fly/run.d.ts +10 -6
  241. package/dist/deploy/fly/run.js +11 -6
  242. package/dist/deploy/hosts.d.ts +2 -1
  243. package/dist/deploy/hosts.js +2 -1
  244. package/dist/deploy/preflight.d.ts +21 -23
  245. package/dist/deploy/preflight.js +223 -202
  246. package/dist/deploy/railway/plan.d.ts +8 -6
  247. package/dist/deploy/railway/plan.js +15 -58
  248. package/dist/deploy/railway/run.d.ts +8 -3
  249. package/dist/deploy/railway/run.js +12 -8
  250. package/dist/deploy/residency.d.ts +5 -11
  251. package/dist/deploy/residency.js +0 -6
  252. package/dist/deploy/runner.d.ts +1 -1
  253. package/dist/deploy/runner.js +1 -1
  254. package/dist/deploy/secrets.d.ts +16 -2
  255. package/dist/deploy/secrets.js +33 -6
  256. package/dist/deploy/workspace.d.ts +11 -6
  257. package/dist/deploy/workspace.js +55 -38
  258. package/dist/dev-supervisor.d.ts +11 -2
  259. package/dist/dev-supervisor.js +52 -27
  260. package/dist/effect-port.d.ts +4 -4
  261. package/dist/effect-port.js +4 -4
  262. package/dist/env.d.ts +0 -13
  263. package/dist/env.js +1 -44
  264. package/dist/environment/apt.d.ts +4 -0
  265. package/dist/environment/apt.js +32 -0
  266. package/dist/environment/declare.d.ts +59 -0
  267. package/dist/environment/declare.js +210 -0
  268. package/dist/environment/mise.d.ts +51 -0
  269. package/dist/environment/mise.js +272 -0
  270. package/dist/feishu.d.ts +2 -2
  271. package/dist/feishu.js +2 -2
  272. package/dist/git.d.ts +13 -0
  273. package/dist/git.js +55 -0
  274. package/dist/harnesses/models/catalog.d.ts +20 -0
  275. package/dist/harnesses/models/catalog.js +254 -0
  276. package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
  277. package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
  278. package/dist/harnesses/models/environment.d.ts +48 -0
  279. package/dist/harnesses/models/environment.js +88 -0
  280. package/dist/harnesses/models/host.d.ts +30 -0
  281. package/dist/harnesses/models/host.js +97 -0
  282. package/dist/{engines/pi → harnesses/models}/login.d.ts +66 -70
  283. package/dist/harnesses/models/login.js +439 -0
  284. package/dist/harnesses/models/models.d.ts +84 -0
  285. package/dist/harnesses/models/models.js +197 -0
  286. package/dist/harnesses/pi-durable/agent.d.ts +42 -0
  287. package/dist/harnesses/pi-durable/agent.js +581 -0
  288. package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
  289. package/dist/harnesses/pi-durable/defaults.js +26 -0
  290. package/dist/harnesses/pi-durable/define.d.ts +77 -0
  291. package/dist/harnesses/pi-durable/define.js +28 -0
  292. package/dist/harnesses/pi-durable/entries.d.ts +32 -0
  293. package/dist/harnesses/pi-durable/entries.js +126 -0
  294. package/dist/harnesses/pi-durable/events.d.ts +25 -0
  295. package/dist/harnesses/pi-durable/events.js +238 -0
  296. package/dist/harnesses/pi-durable/ids.d.ts +16 -0
  297. package/dist/harnesses/pi-durable/ids.js +55 -0
  298. package/dist/harnesses/pi-durable/messages.d.ts +41 -0
  299. package/dist/harnesses/pi-durable/messages.js +116 -0
  300. package/dist/harnesses/pi-durable/open.d.ts +95 -0
  301. package/dist/harnesses/pi-durable/open.js +330 -0
  302. package/dist/harnesses/pi-durable/reads.d.ts +30 -0
  303. package/dist/harnesses/pi-durable/reads.js +94 -0
  304. package/dist/harnesses/pi-durable/registry.d.ts +18 -0
  305. package/dist/harnesses/pi-durable/registry.js +56 -0
  306. package/dist/harnesses/pi-durable/release.d.ts +13 -0
  307. package/dist/harnesses/pi-durable/release.js +40 -0
  308. package/dist/harnesses/pi-durable/serve.d.ts +90 -0
  309. package/dist/harnesses/pi-durable/serve.js +186 -0
  310. package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
  311. package/dist/harnesses/pi-durable/sessions.js +47 -0
  312. package/dist/harnesses/pi-durable/storage.d.ts +4 -0
  313. package/dist/harnesses/pi-durable/storage.js +49 -0
  314. package/dist/harnesses/pi-durable/stream.d.ts +20 -0
  315. package/dist/harnesses/pi-durable/stream.js +221 -0
  316. package/dist/harnesses/pi-durable/text.d.ts +30 -0
  317. package/dist/harnesses/pi-durable/text.js +292 -0
  318. package/dist/harnesses/pi-durable/wake.d.ts +11 -0
  319. package/dist/harnesses/pi-durable/wake.js +90 -0
  320. package/dist/http/client.d.ts +6 -0
  321. package/dist/http/client.js +256 -0
  322. package/dist/http/contract.d.ts +541 -0
  323. package/dist/http/contract.js +179 -0
  324. package/dist/http/server.d.ts +34 -0
  325. package/dist/http/server.js +194 -0
  326. package/dist/index.d.ts +19 -4
  327. package/dist/index.js +13 -5
  328. package/dist/lark.d.ts +2 -2
  329. package/dist/lark.js +2 -2
  330. package/dist/locked-file.d.ts +17 -0
  331. package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
  332. package/dist/once.d.ts +6 -0
  333. package/dist/once.js +23 -0
  334. package/dist/paths.d.ts +36 -52
  335. package/dist/paths.js +66 -182
  336. package/dist/runtime.d.ts +25 -2
  337. package/dist/runtime.js +27 -0
  338. package/dist/scaffold/add-channel.d.ts +14 -27
  339. package/dist/scaffold/add-channel.js +82 -180
  340. package/dist/scaffold/init.d.ts +17 -18
  341. package/dist/scaffold/init.js +87 -99
  342. package/dist/scaffold/templates/SYSTEM.md +12 -0
  343. package/dist/scaffold/templates/env.example +4 -10
  344. package/dist/scaffold/templates/fastagent.config.ts +21 -33
  345. package/dist/scaffold/templates/gitignore +8 -1
  346. package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
  347. package/dist/scaffold/templates.d.ts +9 -4
  348. package/dist/scaffold/templates.js +7 -5
  349. package/dist/scaffold/vendor-skill.d.ts +1 -4
  350. package/dist/scaffold/vendor-skill.js +5 -6
  351. package/dist/schedule/cron.d.ts +13 -0
  352. package/dist/schedule/cron.js +52 -0
  353. package/dist/schedule/eventbridge-cron.d.ts +17 -0
  354. package/dist/schedule/eventbridge-cron.js +88 -0
  355. package/dist/schedule/schedule.d.ts +23 -0
  356. package/dist/schedule/schedule.js +34 -0
  357. package/dist/schedule/scheduler.d.ts +34 -33
  358. package/dist/schedule/scheduler.js +251 -137
  359. package/dist/schedule/state.d.ts +4 -14
  360. package/dist/schedule/state.js +7 -7
  361. package/dist/schedule/wake-alarm.d.ts +22 -2
  362. package/dist/schedule/wake-alarm.js +66 -20
  363. package/dist/schedule/wakeups.d.ts +16 -15
  364. package/dist/schedule/wakeups.js +47 -45
  365. package/dist/service.d.ts +56 -169
  366. package/dist/service.js +91 -187
  367. package/dist/serving-command.d.ts +10 -0
  368. package/dist/serving-command.js +16 -0
  369. package/dist/sign-in-api.d.ts +147 -0
  370. package/dist/sign-in-api.js +9 -0
  371. package/dist/slack.d.ts +1 -1
  372. package/dist/slack.js +1 -1
  373. package/dist/{channels/kit/state.js → state-file.js} +6 -6
  374. package/dist/telegram.d.ts +1 -0
  375. package/dist/telegram.js +1 -0
  376. package/dist/tunnel.d.ts +3 -0
  377. package/dist/tunnel.js +14 -5
  378. package/dist/value-file.d.ts +40 -0
  379. package/dist/value-file.js +164 -0
  380. package/dist/version.d.ts +5 -0
  381. package/dist/version.js +14 -1
  382. package/package.json +18 -28
  383. package/dist/agent.d.ts +0 -106
  384. package/dist/agent.js +0 -21
  385. package/dist/channels/control.d.ts +0 -31
  386. package/dist/channels/control.js +0 -329
  387. package/dist/channels/define-channel.d.ts +0 -39
  388. package/dist/channels/define-channel.js +0 -9
  389. package/dist/channels/feishu/context-buffer.d.ts +0 -35
  390. package/dist/channels/feishu/context-buffer.js +0 -65
  391. package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
  392. package/dist/channels/http.d.ts +0 -23
  393. package/dist/channels/http.js +0 -57
  394. package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
  395. package/dist/channels/slack/context-buffer.d.ts +0 -23
  396. package/dist/channels/slack/context-buffer.js +0 -37
  397. package/dist/channels/sse.d.ts +0 -4
  398. package/dist/channels/sse.js +0 -66
  399. package/dist/cli/commands/chat.d.ts +0 -3
  400. package/dist/cli/commands/chat.js +0 -14
  401. package/dist/cli/commands/routine-run.d.ts +0 -6
  402. package/dist/cli/commands/routine-run.js +0 -46
  403. package/dist/cli/commands/routine.d.ts +0 -25
  404. package/dist/cli/commands/routine.js +0 -122
  405. package/dist/cli/commands/tool.d.ts +0 -1
  406. package/dist/cli/commands/tool.js +0 -57
  407. package/dist/collect.d.ts +0 -63
  408. package/dist/collect.js +0 -90
  409. package/dist/core.d.ts +0 -13
  410. package/dist/core.js +0 -15
  411. package/dist/engines/pi/agent-models.d.ts +0 -83
  412. package/dist/engines/pi/agent-models.js +0 -120
  413. package/dist/engines/pi/agent-session-factory.d.ts +0 -121
  414. package/dist/engines/pi/agent-session-factory.js +0 -535
  415. package/dist/engines/pi/chat.d.ts +0 -3
  416. package/dist/engines/pi/chat.js +0 -8
  417. package/dist/engines/pi/config.d.ts +0 -71
  418. package/dist/engines/pi/config.js +0 -199
  419. package/dist/engines/pi/create.d.ts +0 -170
  420. package/dist/engines/pi/create.js +0 -343
  421. package/dist/engines/pi/definition.d.ts +0 -74
  422. package/dist/engines/pi/definition.js +0 -236
  423. package/dist/engines/pi/entry-images.d.ts +0 -14
  424. package/dist/engines/pi/entry-images.js +0 -23
  425. package/dist/engines/pi/invoke-session.d.ts +0 -18
  426. package/dist/engines/pi/invoke-session.js +0 -403
  427. package/dist/engines/pi/locked-file.d.ts +0 -9
  428. package/dist/engines/pi/login.js +0 -331
  429. package/dist/engines/pi/machine.d.ts +0 -53
  430. package/dist/engines/pi/machine.js +0 -137
  431. package/dist/engines/pi/models.d.ts +0 -200
  432. package/dist/engines/pi/models.js +0 -533
  433. package/dist/engines/pi/open.d.ts +0 -180
  434. package/dist/engines/pi/open.js +0 -270
  435. package/dist/engines/pi/openai-account-models.d.ts +0 -35
  436. package/dist/engines/pi/openai-account-models.js +0 -116
  437. package/dist/engines/pi/report.d.ts +0 -18
  438. package/dist/engines/pi/report.js +0 -59
  439. package/dist/engines/pi/retry-event.d.ts +0 -6
  440. package/dist/engines/pi/retry-event.js +0 -15
  441. package/dist/engines/pi/service.d.ts +0 -9
  442. package/dist/engines/pi/service.js +0 -14
  443. package/dist/engines/pi/session-builder.d.ts +0 -13
  444. package/dist/engines/pi/session-builder.js +0 -117
  445. package/dist/engines/pi/session-control.d.ts +0 -77
  446. package/dist/engines/pi/session-control.js +0 -908
  447. package/dist/engines/pi/session-effects.d.ts +0 -14
  448. package/dist/engines/pi/session-effects.js +0 -30
  449. package/dist/engines/pi/session-inheritance.d.ts +0 -21
  450. package/dist/engines/pi/session-inheritance.js +0 -204
  451. package/dist/engines/pi/session-markers.d.ts +0 -49
  452. package/dist/engines/pi/session-markers.js +0 -60
  453. package/dist/engines/pi/session-settings.d.ts +0 -67
  454. package/dist/engines/pi/session-settings.js +0 -119
  455. package/dist/engines/pi/session-store.d.ts +0 -69
  456. package/dist/engines/pi/session-store.js +0 -430
  457. package/dist/engines/pi/tool-context.d.ts +0 -45
  458. package/dist/engines/pi/tool-context.js +0 -31
  459. package/dist/engines/pi/tool.d.ts +0 -99
  460. package/dist/engines/pi/tool.js +0 -118
  461. package/dist/engines/pi/turn-kit.d.ts +0 -92
  462. package/dist/engines/pi/turn-kit.js +0 -288
  463. package/dist/engines/pi/wake-tool.d.ts +0 -9
  464. package/dist/engines/pi/wake-tool.js +0 -92
  465. package/dist/loader.d.ts +0 -41
  466. package/dist/loader.js +0 -116
  467. package/dist/node.d.ts +0 -3
  468. package/dist/node.js +0 -4
  469. package/dist/observe.d.ts +0 -6
  470. package/dist/observe.js +0 -47
  471. package/dist/pi.d.ts +0 -25
  472. package/dist/pi.js +0 -15
  473. package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
  474. package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
  475. package/dist/schedule/discover.d.ts +0 -17
  476. package/dist/schedule/discover.js +0 -61
  477. package/dist/schedule/routine.d.ts +0 -43
  478. package/dist/schedule/routine.js +0 -32
  479. package/dist/schedule/run.d.ts +0 -55
  480. package/dist/schedule/run.js +0 -146
  481. package/dist/secrets-gate.d.ts +0 -32
  482. package/dist/secrets-gate.js +0 -33
  483. package/dist/session-remote.d.ts +0 -47
  484. package/dist/session-remote.js +0 -460
  485. package/dist/session.d.ts +0 -466
  486. package/dist/session.js +0 -57
  487. /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
@@ -1,16 +1,22 @@
1
1
  /**
2
- * Wake ALARMS for the AgentCore deployment: the piece that makes the agent's self-scheduled wake-ups (`wake`) reliable
3
- * on a host with NO resident process.
2
+ * ALARMS for the AgentCore deployment: what makes the agent's self-scheduled wake-ups (`wake`) and its schedules fire
3
+ * on a host with NO resident process. The container mirrors both through the forwarder into EventBridge Scheduler:
4
+ * - each schedule as a RECURRING cron schedule, which EventBridge fires on its own clock, the way AWS runs any
5
+ * recurring job. Mirroring only creates, changes or deletes it; nothing has to happen after a fire for the next
6
+ * one, so a failed mirror delays an edit, never stops a schedule. Because the container sets it, a schedule written
7
+ * or edited while it runs takes effect without a deploy.
8
+ * - each pending wake-up as a one-shot schedule that deletes itself once it has poked the container.
4
9
  */
5
10
  import { readFileSync } from "node:fs";
6
11
  import * as Clock from "effect/Clock";
7
12
  import * as Effect from "effect/Effect";
8
13
  import { PortFailure, portError, portJoin, portRequest } from "../effect-port.js";
9
- import { RESERVED_PATHS } from "../channels/agentcore-protocol.js";
14
+ import { RESERVED_PATHS, } from "../channels/agentcore-protocol.js";
10
15
  import { beginWork } from "../channels/busy.js";
11
16
  import { log } from "../log.js";
12
17
  import { scheduleFile, writeScheduleFile } from "./state.js";
13
18
  import { listWakeups } from "./wakeups.js";
19
+ import { toEventBridgeCron } from "./eventbridge-cron.js";
14
20
  const URL_FILE = "wake-alarm-url";
15
21
  /**
16
22
  * Persist the forwarder URL the adapter saw in an envelope (write-if-changed — envelopes arrive on every turn, the
@@ -41,14 +47,39 @@ export function readWakeAlarmUrl(stateRoot) {
41
47
  */
42
48
  export const MAX_SYNC_ATTEMPTS = 5;
43
49
  const RETRY_BASE_MS = 2_000;
50
+ /**
51
+ * After a whole sync gives up, how long until it is tried again, for as long as this process lives. Outside the busy
52
+ * count, so a container that is only waiting to retry can still be reclaimed; its next start mirrors again.
53
+ */
54
+ export const HEAL_MS = 5 * 60_000;
44
55
  const SYNC_TIMEOUT_MS = 10_000;
45
56
  /** Alarms due within this margin are NOT mirrored. */
46
57
  const DUE_MARGIN_MS = 5_000;
47
- /** Pending wake-ups → the desired alarm set, minus already-due entries (see {@link DUE_MARGIN_MS}). */
58
+ /**
59
+ * Pending wake-ups → the desired one-shot alarms. A wake-up already due is left out (see {@link DUE_MARGIN_MS}): the
60
+ * container is awake for it, and its wake pump fires it.
61
+ *
62
+ * ONE ID PER INSTANT, never per wake-up. An alarm deletes itself once it has fired, and a recurring wake-up's claim
63
+ * mirrors its next instant right after: an id reused for it would update the alarm EventBridge is about to delete,
64
+ * and the next instant would be deleted with it. With one id per instant, mirroring again is idempotent.
65
+ */
48
66
  export function toAlarms(pending, now) {
67
+ const earliest = now.getTime() + DUE_MARGIN_MS;
49
68
  return pending
50
- .filter((w) => Date.parse(w.fireAt) > now.getTime() + DUE_MARGIN_MS)
51
- .map((w) => ({ id: w.id, at: w.fireAt }));
69
+ .filter((w) => Date.parse(w.fireAt) > earliest)
70
+ .map((w) => ({ id: `${w.id}@${w.fireAt}`, at: w.fireAt }));
71
+ }
72
+ /**
73
+ * Each armed schedule → the recurring EventBridge schedule that fires it. Discovery admits only a cron that
74
+ * translates (schedule/discover.ts), so one that does not here is a defect, and throws.
75
+ */
76
+ export function toRecurring(schedules) {
77
+ return schedules.map((s) => {
78
+ const translated = toEventBridgeCron(s.cron);
79
+ if ("error" in translated)
80
+ throw new Error(`schedule "${s.name}" has no EventBridge form: ${translated.error}`);
81
+ return { name: s.name, expression: translated.expression, tz: s.tz ?? "UTC" };
82
+ });
52
83
  }
53
84
  /**
54
85
  * Build the wakeups sink for an AgentCore deployment (registered via `setWakeupsSink` by `start` when
@@ -58,7 +89,7 @@ export function createWakeAlarmSink(options) {
58
89
  return Effect.gen(function* () {
59
90
  const clock = yield* Clock.Clock;
60
91
  const fork = Effect.runForkWith(yield* Effect.context());
61
- const { secret, fetchImpl = fetch, now = () => new Date(clock.currentTimeMillisUnsafe()), delay: pause } = options;
92
+ const { secret, schedules = () => [], fetchImpl = fetch, now = () => new Date(clock.currentTimeMillisUnsafe()), delay: pause, } = options;
62
93
  const delay = (ms) => (pause ? portJoin(() => pause(ms)) : Effect.sleep(ms));
63
94
  let running = false;
64
95
  let dirty = false;
@@ -68,18 +99,20 @@ export function createWakeAlarmSink(options) {
68
99
  try: () => toAlarms(listWakeups(stateRoot), now()),
69
100
  catch: (cause) => new PortFailure(cause),
70
101
  });
71
- // Nothing future to mirror: converged.
72
- if (alarms.length === 0)
73
- return true;
102
+ const recurring = toRecurring(schedules());
74
103
  const url = yield* Effect.try({
75
104
  try: () => readWakeAlarmUrl(stateRoot),
76
105
  catch: (cause) => new PortFailure(cause),
77
106
  });
78
107
  if (!url) {
79
- log.warn("[schedule] wake alarm skipped — forwarder URL not seen yet");
108
+ // Nothing to set, before the forwarder was ever seen: nothing can be pending there either.
109
+ if (alarms.length > 0 || recurring.length > 0) {
110
+ log.warn("[schedule] alarm sync skipped — forwarder URL not seen yet");
111
+ }
80
112
  return true;
81
113
  }
82
- const body = { secret, alarms };
114
+ // Sent EMPTY too: the schedules are the whole set, and the forwarder deletes one this set no longer has.
115
+ const body = { secret, alarms, schedules: recurring };
83
116
  return yield* portRequest(async (signal) => {
84
117
  const res = await fetchImpl(`${url.replace(/\/$/, "")}${RESERVED_PATHS.wakeAlarm}`, {
85
118
  method: "POST",
@@ -121,14 +154,18 @@ export function createWakeAlarmSink(options) {
121
154
  break;
122
155
  }
123
156
  }
124
- if (failures >= MAX_SYNC_ATTEMPTS) {
125
- log.error(`[schedule] wake alarm sync FAILED after ${MAX_SYNC_ATTEMPTS} attempts — pending wake-ups have no ` +
126
- `external alarm until the next store change or boot re-mirrors them`);
127
- }
157
+ if (failures < MAX_SYNC_ATTEMPTS)
158
+ return true;
159
+ log.error(`[schedule] alarm sync FAILED after ${MAX_SYNC_ATTEMPTS} attempts — new wake-ups have no alarm, and ` +
160
+ `schedule edits since the last sync have not reached EventBridge (schedules it already holds keep ` +
161
+ `firing). It is tried again every ${HEAL_MS / 60_000} minutes while this container runs, and at its next start`);
162
+ return false;
128
163
  });
164
+ /** One retry pending at a time, however many syncs gave up meanwhile. */
165
+ let healing = false;
129
166
  // Single-flight: a save arriving while the loop runs only marks it dirty, so a burst coalesces into one more pass
130
167
  // instead of one concurrent loop each.
131
- return (stateRoot) => {
168
+ const sink = (stateRoot) => {
132
169
  dirty = true;
133
170
  if (running)
134
171
  return;
@@ -136,12 +173,21 @@ export function createWakeAlarmSink(options) {
136
173
  fork(Effect.acquireUseRelease(Effect.sync(beginWork), () =>
137
174
  // Claim notification precedes scheduler admission; retain busy ownership through that handoff.
138
175
  Effect.yieldNow.pipe(Effect.andThen(reconcile(stateRoot)), Effect.catchCause((cause) => Effect.sync(() => {
139
- // Store/clock faults cannot be repaired by another POST. A new mutation may retry the mirror.
140
- log.error(`[schedule] wake alarm reconcile failed (alarms are stale until the next store change): ${String(portError(cause))}`);
176
+ log.error(`[schedule] alarm reconcile failed (tried again in ${HEAL_MS / 60_000} minutes while this ` +
177
+ `container runs): ${String(portError(cause))}`);
178
+ return false;
141
179
  }))), (done) => Effect.sync(() => {
142
180
  running = false;
143
181
  done();
144
- })));
182
+ })).pipe(Effect.flatMap((converged) => converged || healing
183
+ ? Effect.void
184
+ : Effect.sync(() => {
185
+ healing = true;
186
+ }).pipe(Effect.andThen(delay(HEAL_MS)), Effect.andThen(Effect.sync(() => {
187
+ healing = false;
188
+ sink(stateRoot);
189
+ }))))));
145
190
  };
191
+ return sink;
146
192
  });
147
193
  }
@@ -10,9 +10,12 @@ export interface Wakeup {
10
10
  cron?: string;
11
11
  /** IANA timezone for `cron` (default UTC). */
12
12
  tz?: string;
13
- /** ONE-SHOT ONLY: consecutive busy-defer attempts. */
14
- attempts?: number;
15
13
  }
14
+ /**
15
+ * Parse a delay to milliseconds: a number is SECONDS; a string MUST carry a unit — `"<n><s|m|h|d>"` ("30m", "2h",
16
+ * "1d").
17
+ */
18
+ export declare function parseDelayMs(input: string | number): number | undefined;
16
19
  /** The minimum delay a wake-up may be scheduled for — rejects a busy-loop (`wake in 1s`, then again…). */
17
20
  export declare const MIN_WAKE_MS = 60000;
18
21
  /**
@@ -21,8 +24,6 @@ export declare const MIN_WAKE_MS = 60000;
21
24
  * deploy is one session per chat).
22
25
  */
23
26
  export declare const MAX_PENDING_WAKEUPS = 20;
24
- /** How many times a busy/transient wake is retried (deferred) before being dropped. */
25
- export declare const MAX_WAKE_ATTEMPTS = 120;
26
27
  export declare function setWakeupsSink(sink: ((stateRoot: string) => void) | undefined): void;
27
28
  /** The current pending wake-ups — read by the wake-alarm sink, which mirrors them into an external clock. */
28
29
  export declare function listWakeups(stateRoot: string): Wakeup[];
@@ -43,22 +44,22 @@ export declare function addWakeup(stateRoot: string, input: {
43
44
  tz?: string;
44
45
  }, now?: Date): AddWakeupResult;
45
46
  /**
46
- * Remove ONE pending wake-up, and only from the session that made it.
47
- *
48
- * SESSION-SCOPED WITH NO WAY AROUND IT, because `unwake` is the only caller: an agent cancels its own alarm, and
49
- * cancelling another conversation's silently is a cost with no matching benefit. There is no operator command: a
50
- * wake-up only fires while a serve is running, and a running serve is one whose
51
- * session can be spoken to (`POST /invoke`, the control plane's `follow_up`, or the chat thread it lives in), so
52
- * "the alarm is loose" and "the agent is unreachable" cannot both be true. The last resort is editing
53
- * `<stateRoot>/schedule/wakeups.json`, which needs no command.
47
+ * Remove ONE pending wake-up, and only from the session that made it: `unwake`, an agent cancelling its own alarm.
48
+ * Cancelling another conversation's silently is a cost with no matching benefit.
54
49
  */
55
50
  export declare function removeWakeup(stateRoot: string, id: string, session: string): boolean;
51
+ /**
52
+ * Remove ONE pending wake-up whatever session set it: the operator's `fastagent schedules unwake`, the one way out of a
53
+ * wake-up set in a session nobody can message (a schedule's own). Its caller holds the instance, so no serve's poll
54
+ * writes the store between this read and its write.
55
+ */
56
+ export declare function removeAnyWakeup(stateRoot: string, id: string): Wakeup | undefined;
56
57
  /**
57
58
  * CLAIM the FIRST due wake-up (at or before `now`) in stored order, remove + return it, or undefined if none is due.
58
59
  */
59
60
  export declare function takeFirstDueWakeup(stateRoot: string, now?: Date): Wakeup | undefined;
60
61
  /**
61
- * Re-schedule a ONE-SHOT wake whose fire failed TRANSIENTLY (its session was busy — a channel is mid-turn on it),
62
- * deferred to `fireAt`.
62
+ * Put back a ONE-SHOT wake-up its session refused for now (the process or the session's queue was full), to fire at
63
+ * `fireAt`. It was taken out of the store to fire, so it does not count against the session's cap again.
63
64
  */
64
- export declare function deferWakeup(stateRoot: string, w: Wakeup, fireAt: Date): boolean;
65
+ export declare function requeueWakeup(stateRoot: string, w: Wakeup, fireAt: Date): void;
@@ -1,11 +1,24 @@
1
1
  /**
2
2
  * The agent's self-scheduled wake-ups — the SECOND producer of scheduled invocations (the first is the author's
3
- * `routines/` files).
3
+ * `schedules/` files).
4
4
  */
5
5
  import { randomUUID } from "node:crypto";
6
6
  import { log } from "../log.js";
7
- import { cronError, nextRun } from "./cron.js";
7
+ import { cronError, nextRun, recurringCronError } from "./cron.js";
8
8
  import { readScheduleFile, scheduleFile, writeScheduleFile } from "./state.js";
9
+ /**
10
+ * Parse a delay to milliseconds: a number is SECONDS; a string MUST carry a unit — `"<n><s|m|h|d>"` ("30m", "2h",
11
+ * "1d").
12
+ */
13
+ export function parseDelayMs(input) {
14
+ if (typeof input === "number")
15
+ return Number.isFinite(input) && input > 0 ? input * 1000 : undefined;
16
+ const m = input.trim().match(/^(\d+(?:\.\d+)?)\s*(s|m|h|d)$/i); // unit REQUIRED on a string
17
+ if (!m)
18
+ return undefined;
19
+ const mult = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 }[m[2].toLowerCase()];
20
+ return Number(m[1]) * mult;
21
+ }
9
22
  /** The minimum delay a wake-up may be scheduled for — rejects a busy-loop (`wake in 1s`, then again…). */
10
23
  export const MIN_WAKE_MS = 60_000; // 1 minute
11
24
  /**
@@ -14,10 +27,6 @@ export const MIN_WAKE_MS = 60_000; // 1 minute
14
27
  * deploy is one session per chat).
15
28
  */
16
29
  export const MAX_PENDING_WAKEUPS = 20;
17
- /** How many times a busy/transient wake is retried (deferred) before being dropped. */
18
- export const MAX_WAKE_ATTEMPTS = 120;
19
- /** The minimum gap between two consecutive fires of a RECURRING wake. */
20
- const MIN_RECURRING_GAP_MS = 10 * 60_000; // 10 minutes
21
30
  /** A stored entry is a real Wakeup: the fields are present and `fireAt` is a parseable date. */
22
31
  function isWakeup(e) {
23
32
  if (!e || typeof e !== "object")
@@ -28,7 +37,6 @@ function isWakeup(e) {
28
37
  typeof w.prompt === "string" &&
29
38
  typeof w.fireAt === "string" &&
30
39
  !Number.isNaN(Date.parse(w.fireAt)) &&
31
- (w.attempts === undefined || typeof w.attempts === "number") && // a non-number would make deferWakeup's count NaN
32
40
  (w.tz === undefined || typeof w.tz === "string") &&
33
41
  // A stored cron must PARSE: a bad one would throw inside the claim's nextRun.
34
42
  (w.cron === undefined ||
@@ -74,22 +82,15 @@ export function listWakeups(stateRoot) {
74
82
  export function addWakeup(stateRoot, input, now = new Date()) {
75
83
  let fireAtDate;
76
84
  if (input.cron !== undefined) {
77
- const err = cronError(input.cron, input.tz);
85
+ // A recurring wake runs FOREVER — gated harder than a one-shot, by the rule every recurring producer shares.
86
+ const err = recurringCronError(input.cron, input.tz);
78
87
  if (err)
79
- return { ok: false, error: `invalid cron/tz: ${err}` };
80
- // A recurring wake runs FOREVER — gate its frequency harder than a one-shot: the gap between the next two
81
- // instants must be ≥ the recurring floor.
88
+ return { ok: false, error: `${err}${err.startsWith("this cron never") ? " — use `in` for a one-shot" : ""}.` };
89
+ // DERIVED from the cron — a caller-passed fireAt can't disagree with the schedule.
82
90
  const first = nextRun(input.cron, input.tz, now);
83
- const second = first && nextRun(input.cron, input.tz, first);
84
- if (!first || !second)
85
- return { ok: false, error: "this cron never fires (or fires only once) — use `in` for a one-shot." };
86
- if (second.getTime() - first.getTime() < MIN_RECURRING_GAP_MS) {
87
- return {
88
- ok: false,
89
- error: `too frequent — a recurring wake must fire at most every ${MIN_RECURRING_GAP_MS / 60_000} minutes.`,
90
- };
91
- }
92
- fireAtDate = first; // DERIVED from the cron — a caller-passed fireAt can't disagree with the schedule
91
+ if (!first)
92
+ return { ok: false, error: "this cron never fires again — use `in` for a one-shot." };
93
+ fireAtDate = first;
93
94
  }
94
95
  else {
95
96
  if (!input.fireAt)
@@ -121,22 +122,28 @@ export function addWakeup(stateRoot, input, now = new Date()) {
121
122
  return { ok: true, id, fireAt };
122
123
  }
123
124
  /**
124
- * Remove ONE pending wake-up, and only from the session that made it.
125
- *
126
- * SESSION-SCOPED WITH NO WAY AROUND IT, because `unwake` is the only caller: an agent cancels its own alarm, and
127
- * cancelling another conversation's silently is a cost with no matching benefit. There is no operator command: a
128
- * wake-up only fires while a serve is running, and a running serve is one whose
129
- * session can be spoken to (`POST /invoke`, the control plane's `follow_up`, or the chat thread it lives in), so
130
- * "the alarm is loose" and "the agent is unreachable" cannot both be true. The last resort is editing
131
- * `<stateRoot>/schedule/wakeups.json`, which needs no command.
125
+ * Remove ONE pending wake-up, and only from the session that made it: `unwake`, an agent cancelling its own alarm.
126
+ * Cancelling another conversation's silently is a cost with no matching benefit.
132
127
  */
133
128
  export function removeWakeup(stateRoot, id, session) {
129
+ return removeWhere(stateRoot, (w) => w.id === id && w.session === session) !== undefined;
130
+ }
131
+ /**
132
+ * Remove ONE pending wake-up whatever session set it: the operator's `fastagent schedules unwake`, the one way out of a
133
+ * wake-up set in a session nobody can message (a schedule's own). Its caller holds the instance, so no serve's poll
134
+ * writes the store between this read and its write.
135
+ */
136
+ export function removeAnyWakeup(stateRoot, id) {
137
+ return removeWhere(stateRoot, (w) => w.id === id);
138
+ }
139
+ function removeWhere(stateRoot, match) {
134
140
  const all = load(stateRoot);
135
- const kept = all.filter((w) => !(w.id === id && w.session === session));
136
- if (kept.length === all.length)
137
- return false;
138
- save(stateRoot, kept);
139
- return true;
141
+ const index = all.findIndex(match);
142
+ if (index === -1)
143
+ return undefined;
144
+ const [removed] = all.splice(index, 1);
145
+ save(stateRoot, all);
146
+ return removed;
140
147
  }
141
148
  /**
142
149
  * CLAIM the FIRST due wake-up (at or before `now`) in stored order, remove + return it, or undefined if none is due.
@@ -148,11 +155,10 @@ export function takeFirstDueWakeup(stateRoot, now = new Date()) {
148
155
  return undefined;
149
156
  const w = all[idx];
150
157
  if (w.cron !== undefined) {
151
- // RECURRING claim = ADVANCE IN PLACE: the entry STAYS in the store with fireAt pushed to the next cron instant
152
- // (attempts cleared).
158
+ // RECURRING claim = ADVANCE IN PLACE: the entry STAYS in the store with fireAt pushed to the next cron instant.
153
159
  const next = nextRun(w.cron, w.tz, now);
154
160
  if (next)
155
- all[idx] = { ...w, fireAt: next.toISOString(), attempts: undefined };
161
+ all[idx] = { ...w, fireAt: next.toISOString() };
156
162
  else
157
163
  all.splice(idx, 1); // the cron has no next instant — this is its final occurrence
158
164
  save(stateRoot, all);
@@ -163,13 +169,9 @@ export function takeFirstDueWakeup(stateRoot, now = new Date()) {
163
169
  return w;
164
170
  }
165
171
  /**
166
- * Re-schedule a ONE-SHOT wake whose fire failed TRANSIENTLY (its session was busy — a channel is mid-turn on it),
167
- * deferred to `fireAt`.
172
+ * Put back a ONE-SHOT wake-up its session refused for now (the process or the session's queue was full), to fire at
173
+ * `fireAt`. It was taken out of the store to fire, so it does not count against the session's cap again.
168
174
  */
169
- export function deferWakeup(stateRoot, w, fireAt) {
170
- const attempts = (w.attempts ?? 0) + 1;
171
- if (attempts > MAX_WAKE_ATTEMPTS)
172
- return false;
173
- save(stateRoot, [...load(stateRoot), { ...w, fireAt: fireAt.toISOString(), attempts }]);
174
- return true;
175
+ export function requeueWakeup(stateRoot, w, fireAt) {
176
+ save(stateRoot, [...load(stateRoot), { ...w, fireAt: fireAt.toISOString() }]);
175
177
  }
package/dist/service.d.ts CHANGED
@@ -1,194 +1,81 @@
1
- import type { Agent } from "./agent.ts";
2
- import { type PrefixMount } from "./channels/serve.ts";
3
- import { type LoadedLongConnectionChannel } from "./channels/discover.ts";
4
- import type { SessionControl } from "./session.ts";
1
+ import type { Agent } from "./agent-api.ts";
5
2
  import type { ChannelHandler, Routes } from "./channel.ts";
6
- import type { LoadedRoutine } from "./schedule/routine.ts";
7
- export interface ServingSurface {
8
- /**
9
- * The routes that AUTHENTICATE NOBODY — `GET /health`, `POST /invoke`, and `POST /run` where the definition
10
- * declares routines, minus what a channel took over or `http.invoke: false` withheld. Kept APART from the
11
- * channels' table rather than derived from it, because three decisions read it (browser reachability, the JSON
12
- * body gate, what the startup line calls unauthenticated) and must give the same answer.
13
- */
14
- unverified: Routes;
15
- /**
16
- * What the `channels/` files serve. Exempt from both guards because a channel checks its platform's signature
17
- * inside itself — an assumption about the author for a CUSTOM channel, not a property we enforce (§14).
18
- */
19
- selfVerifying: Routes;
20
- /** Prefix-owning handlers mounted beside the routes (the session control plane). */
21
- mounts?: readonly PrefixMount[];
3
+ import { type AnyChannelModule, type LoadedLongConnectionChannel } from "./channels/discover.ts";
4
+ import { type Scheduler } from "./schedule/scheduler.ts";
5
+ import type { Schedule } from "./schedule/schedule.ts";
6
+ /** The port a serve binds when neither a flag, `PORT` (start only) nor `http.port` names one. */
7
+ export declare const DEFAULT_HTTP_PORT = 8787;
8
+ /** What a serve answers: its channels' routes, and `GET /health` unless a channel serves it. */
9
+ interface ServingSurface {
10
+ routes: Routes;
22
11
  longConnections: LoadedLongConnectionChannel[];
23
- /** Route-channel basenames; the tunnel registers only this subset. */
12
+ /** Route-channel names; the tunnel registers only this subset. */
24
13
  routeChannels: string[];
25
14
  /** Flip health between 200 and 503. */
26
15
  setReady(value: boolean): void;
27
16
  }
28
- /** The port a serve binds when neither a flag, `PORT` (start only) nor `http.port` names one. */
29
- export declare const DEFAULT_HTTP_PORT = 8787;
30
- /**
31
- * What a serve publishes on its port, and to which browsers — the config file's `http` block minus `port`, carried
32
- * as-is into the assembly so every reader (the routes, the startup report, deploy's pre-flight, AgentCore's inert-key
33
- * warnings) reads ONE value. The port is not here: the assembly binds nothing, so only the CLI reads it.
34
- */
35
- export interface HttpSurface {
36
- /**
37
- * The origins a BROWSER may call this serve from. The default, with this unset, answers EVERY origin: any page your
38
- * users visit can call this port and read the reply, and every route here is unauthenticated. Set it to your front
39
- * end's real domain to take that back (`["*"]` is the default said out loud; an empty list is refused, because it
40
- * reads as "nobody" and would mean the opposite).
41
- */
42
- cors?: readonly string[];
43
- /**
44
- * Serve the data plane, `POST /invoke`. On by default: it is the framework's interface, and a deployment that can
45
- * only be reached through a chat channel is still worth curling. Set it `false` when this port is public and the
46
- * channels' own signature checks are meant to be the only way in — the route is unauthenticated and runs a turn
47
- * with the agent's full tool authority.
48
- */
49
- invoke?: boolean;
17
+ /** Mount the channels and the health check. */
18
+ export declare function routesFor(agent: Agent, stateRoot: string, channels: ReadonlyMap<string, AnyChannelModule>): ServingSurface;
19
+ /** Start the clock: the definition's schedules, and the wake-ups the agent sets for itself, on every serve. */
20
+ export declare function startSchedules(agent: Agent, stateRoot: string, schedules: readonly Schedule[], options?: {
21
+ localClock?: boolean;
22
+ }): Pick<Scheduler, "stop">;
23
+ /** What `serve()` answers (SPEC.md §8): the agent's channels, schedules and wake-ups, and `GET /health`. */
24
+ export interface Service {
25
+ /** For an app's own server to route to. */
26
+ fetch(request: Request): Promise<Response>;
27
+ /** Or a server of its own, on this runtime's server: the one way to start one. Answers the port it bound. */
28
+ listen(port: number, host?: string): Promise<number>;
29
+ /** Settles when every long connection is up: immediately when there are none. */
30
+ ready: Promise<void>;
50
31
  /**
51
- * Serve `POST /run` (and `GET /routines`), which run a routine this definition declares by name. It follows
52
- * `invoke` unless set: turning the anonymous turn endpoint off must not leave a second one open behind it. Set it
53
- * `true` for the one combination that gets wrong — no `/invoke`, but an external clock (a crontab, a CI job) driving
54
- * the routines. It has no effect where `routines/` declares nothing; there is no route then.
32
+ * Stop the server, giving the requests in flight a moment before ending them, then long connections and schedules.
33
+ * It does NOT drain the agent's messages: one takes seconds to minutes, and the deployment wants the old process gone
34
+ * in under a second. What makes that safe is that they are durable: an accepted message is answered after the
35
+ * restart, and a chat turn's intent is durable before it is accepted (`channels/kit/turn-store.ts`). A schedule
36
+ * fire's claim is written before its message: the next boot writes back the end of a message the agent took, and
37
+ * records one it never took as `interrupted`.
55
38
  */
56
- run?: boolean;
39
+ close(): Promise<void>;
57
40
  }
58
- /**
59
- * Does this surface serve `POST /run`, given a routine to run? It FOLLOWS `invoke` unless `run` says otherwise (see
60
- * {@link HttpSurface.run}). ONE function because the assembly mounts the route and `preflightDeploy` names it; a
61
- * default spelled twice is a default that moves once.
62
- */
63
- export declare function shouldServeRun(http: HttpSurface | undefined): boolean;
64
- /**
65
- * What an anonymous caller of a port can do, worst first — the ONE wording the startup report and deploy's pre-flight
66
- * both print, each from its own facts (what mounted vs what will mount).
67
- */
68
- export declare function describeAnonymousSurface(open: {
69
- invoke: boolean;
70
- run: boolean;
71
- controlPrefix?: string;
72
- }): string[];
73
- /**
74
- * The surface this deployment serves: the DATA plane (`POST /invoke`), `GET /health`, and the discovered channels.
75
- *
76
- * `/invoke` is the framework's interface, so it is served whatever channels a definition declares (unless
77
- * `http.invoke: false`). It is RESERVED for the same reason `/control/*` is: a channel taking that path would silently replace the one route every client,
78
- * every doc and the startup line all name. `/health` stays overridable — a probe is the deployment's to shape.
79
- */
80
- export declare function routesFor(agentDir: string, agent: Agent, stateRoot: string, control: SessionControl | undefined,
81
- /**
82
- * `http.invoke: false` withholds the data plane. Two callers, two reasons: the AgentCore adapter serves the
83
- * Runtime's `/invocations` contract instead, and an author sets it to leave the channels' signature checks as the
84
- * only way into a public port.
85
- *
86
- * `routines` mounts `POST /run` and `GET /routines` (per {@link shouldServeRun}). Passed in rather than loaded here
87
- * so the routes and the resident clock cannot disagree about which routines exist (`loadServingRoutines`).
88
- */
89
- options?: {
90
- http?: HttpSurface;
91
- routines?: readonly LoadedRoutine[];
92
- }): Promise<ServingSurface>;
93
- /** Refuse channel routes the control plane would swallow. */
94
- export declare function assertNoControlPlaneCollision(channelRoutes: Routes, plane: PrefixMount): void;
95
- export declare function mountSessionControl(routes: Routes, control: SessionControl | undefined): {
96
- routes: Routes;
97
- mounts: PrefixMount[];
98
- /** The prefix the plane owns, when it is published — what a startup line names. */
99
- controlPrefix?: string;
100
- };
101
- /**
102
- * Load the agent's `routines/`, gated.
103
- *
104
- * Separate from {@link startSchedules} because two things need the SAME list and one of them runs first: the
105
- * `POST /run` route is built with the routes (so a channel cannot take that path unnoticed), and the resident
106
- * clock starts later, inside the service's scope. Loading twice would let them disagree about which routines exist.
107
- */
108
- export declare function loadServingRoutines(agentDir: string): Promise<LoadedRoutine[]>;
109
- /**
110
- * Start the clock over routines {@link loadServingRoutines} already gated — on every serve, routines or not: the
111
- * agent's own wake-ups are a default capability, and this is what fires them.
112
- */
113
- export declare function startSchedules(agent: Agent, stateRoot: string, routines: LoadedRoutine[], options?: {
114
- externalClock?: boolean;
115
- }): {
116
- routines: LoadedRoutine[];
117
- stop: () => void;
118
- };
119
- export interface AgentService {
120
- /** The assembled Fetch handler: channel routes, the control plane, and health. */
121
- handler: ChannelHandler;
122
- /** The agent behind it — invoke it directly when you also want a programmatic path. */
123
- agent: Agent;
124
- /** The literal routes `handler` was composed from — for a startup line naming what is served. */
41
+ /** A serve as the CLI reports it: what it serves, beside the Service itself. */
42
+ export interface ServedAgent extends Service {
43
+ /** The literal routes the service answers, for a startup line naming them. */
125
44
  routes: Routes;
126
45
  agentDir: string;
127
- workspace: string;
128
- /**
129
- * What actually mounted, for a startup line: channel files serving routes, and long connections.
130
- */
46
+ /** What actually mounted: channels serving routes, and long connections. */
131
47
  channels: {
132
48
  routes: string[];
133
49
  longConnections: string[];
134
50
  };
135
- /**
136
- * The keys of {@link ServingSurface.unverified}: what a caller reads to describe this surface. Not derivable from
137
- * `routes`, where a channel may serve one of those paths behind its own signature check.
138
- */
139
- unverifiedRoutes: readonly string[];
140
- /**
141
- * The cross-origin allow-list this service was assembled with (`http.cors`), or `undefined` for the `*` default.
142
- * Read by the startup report for the same reason as {@link AgentService.unverifiedRoutes}: what a caller says
143
- * about this surface must come from what was actually assembled, not from re-deriving it.
144
- */
145
- corsOrigins?: readonly string[];
146
- routines: readonly LoadedRoutine[];
147
- /** Settles when every long connection is up — immediately when there are none. */
148
- ready: Promise<void>;
149
- /** The control plane's prefix, when `sessionControl` is on. */
150
- controlPrefix?: string;
151
- /**
152
- * Stop long connections and routines. It does NOT drain agent turns: a turn takes seconds to minutes, and the
153
- * deployment wants the old process gone in under a second (`SHUTDOWN_GRACE_MS` in `src/cli/serve.ts`). What makes
154
- * that safe is replay, not waiting — a chat turn's intent is durable before it is accepted and its channel
155
- * replays it on the next boot (`channels/kit/turn-store.ts`), and an in-flight HTTP/SSE caller sees the stream
156
- * drop and retries. The one path with neither is a routine fire, whose claim is written before the turn: it
157
- * stays skipped, and the next boot records it as `interrupted` rather than losing it silently.
158
- */
159
- close(): Promise<void>;
51
+ schedules: readonly Schedule[];
52
+ /** Whether the Agent API is served, under `/v1`: only with a key (SPEC.md §9.1). */
53
+ api: boolean;
160
54
  }
161
- /** What {@link mountAgentService} needs beyond an opened directory. */
162
- export interface MountAgentServiceOptions {
163
- /** Wrap the agent before anything consumes it. */
164
- wrapAgent?: (agent: Agent) => Agent;
165
- /** Aborting this closes the service, exactly like calling {@link AgentService.close}. */
166
- signal?: AbortSignal;
55
+ /**
56
+ * A Service over `handler`: answered in process, or served on a server of its own. `endStreams` ends what would hold
57
+ * the server's close open (a Caller watching events), and `shutdown` stops the rest once the server has.
58
+ */
59
+ export declare function serviceOver(handler: ChannelHandler, ready: Promise<void>, shutdown: () => Promise<void>, endStreams?: () => Promise<void>): Service;
60
+ /** What {@link serveAgent} needs beyond an opened agent. */
61
+ export interface ServeOptions {
167
62
  /** Called when a long connection ends on its own — a dropped socket-mode channel, say. */
168
63
  onChannelClosed?: (name: string, error?: unknown) => void;
169
64
  /** How long `close()` waits for a channel to stop before reporting it stuck (default 5s). */
170
65
  closeTimeoutMs?: number;
66
+ /** The keys the Agent API takes; without one it is not served (SPEC.md §9.1). */
67
+ apiKeys?: readonly string[];
171
68
  }
172
- /** What the assembly needs from an opened agent directory — the whole of it. */
173
- export interface MountableAgent {
69
+ /** What the assembly serves. */
70
+ export interface ServableAgent {
174
71
  agent: Agent;
175
- /** The definition dir: where channels/, tools/ and routines/ are read from. */
72
+ /** The definition's directory: the agent's working directory. */
176
73
  agentDir: string;
177
- /** The agent's cwd. */
178
- workspace: string;
179
- /** Where durable state lives (channel state, sessions, routine fires). */
74
+ /** Where durable state lives (channel state, schedule fires, wake-ups). */
180
75
  stateRoot: string;
181
- /** The session-control hub, when the opener built one. A serve has it whether or not `/control/*` is published:
182
- * a chat channel's stop command reaches the running turn through it. */
183
- sessionControl?: SessionControl;
184
- /** Whether that hub is ALSO served as `/control/*` (`config.sessionControl`). Required, not defaulted: an
185
- * embedder assembling this by hand would otherwise lose the plane to a 404 with nothing said anywhere. */
186
- publishControl: boolean;
187
- /** What the port publishes, and to which browsers — the config's `http` block ({@link HttpSurface}). */
188
- http?: HttpSurface;
76
+ channels: ReadonlyMap<string, AnyChannelModule>;
77
+ schedules: readonly Schedule[];
189
78
  }
190
- /**
191
- * The assembly itself, over an already-opened directory: channels, the control plane, routines and long connections,
192
- * composed into one handler.
193
- */
194
- export declare function mountAgentService(opened: MountableAgent, options?: MountAgentServiceOptions): Promise<AgentService>;
79
+ /** The assembly itself: channels, schedules and long connections, composed into one handler. */
80
+ export declare function serveAgent(opened: ServableAgent, options?: ServeOptions): Promise<ServedAgent>;
81
+ export {};