@fastagent-sh/fastagent 0.24.3 → 0.25.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 (480) hide show
  1. package/README.md +53 -82
  2. package/dist/agent-api.d.ts +452 -0
  3. package/dist/agent-api.js +201 -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 +77 -0
  9. package/dist/authoring.js +238 -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 +115 -63
  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 +17 -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 +252 -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 +190 -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 +131 -16
  164. package/dist/cli/commands/login.d.ts +31 -2
  165. package/dist/cli/commands/login.js +413 -64
  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 +3 -2
  184. package/dist/cli/login-relay.js +18 -6
  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 +68 -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 +217 -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 +222 -201
  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 +51 -26
  260. package/dist/effect-port.d.ts +4 -4
  261. package/dist/effect-port.js +4 -4
  262. package/dist/environment/apt.d.ts +4 -0
  263. package/dist/environment/apt.js +32 -0
  264. package/dist/environment/declare.d.ts +59 -0
  265. package/dist/environment/declare.js +210 -0
  266. package/dist/environment/mise.d.ts +50 -0
  267. package/dist/environment/mise.js +268 -0
  268. package/dist/feishu.d.ts +2 -2
  269. package/dist/feishu.js +2 -2
  270. package/dist/git.d.ts +13 -0
  271. package/dist/git.js +55 -0
  272. package/dist/harnesses/models/catalog.d.ts +20 -0
  273. package/dist/harnesses/models/catalog.js +254 -0
  274. package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
  275. package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
  276. package/dist/harnesses/models/environment.d.ts +43 -0
  277. package/dist/harnesses/models/environment.js +82 -0
  278. package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
  279. package/dist/{engines/pi → harnesses/models}/login.js +187 -79
  280. package/dist/harnesses/models/models.d.ts +83 -0
  281. package/dist/harnesses/models/models.js +158 -0
  282. package/dist/harnesses/pi-durable/agent.d.ts +42 -0
  283. package/dist/harnesses/pi-durable/agent.js +579 -0
  284. package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
  285. package/dist/harnesses/pi-durable/defaults.js +26 -0
  286. package/dist/harnesses/pi-durable/define.d.ts +77 -0
  287. package/dist/harnesses/pi-durable/define.js +28 -0
  288. package/dist/harnesses/pi-durable/entries.d.ts +32 -0
  289. package/dist/harnesses/pi-durable/entries.js +126 -0
  290. package/dist/harnesses/pi-durable/events.d.ts +25 -0
  291. package/dist/harnesses/pi-durable/events.js +238 -0
  292. package/dist/harnesses/pi-durable/ids.d.ts +16 -0
  293. package/dist/harnesses/pi-durable/ids.js +55 -0
  294. package/dist/harnesses/pi-durable/messages.d.ts +41 -0
  295. package/dist/harnesses/pi-durable/messages.js +116 -0
  296. package/dist/harnesses/pi-durable/open.d.ts +88 -0
  297. package/dist/harnesses/pi-durable/open.js +329 -0
  298. package/dist/harnesses/pi-durable/reads.d.ts +30 -0
  299. package/dist/harnesses/pi-durable/reads.js +94 -0
  300. package/dist/harnesses/pi-durable/registry.d.ts +18 -0
  301. package/dist/harnesses/pi-durable/registry.js +56 -0
  302. package/dist/harnesses/pi-durable/release.d.ts +13 -0
  303. package/dist/harnesses/pi-durable/release.js +40 -0
  304. package/dist/harnesses/pi-durable/serve.d.ts +80 -0
  305. package/dist/harnesses/pi-durable/serve.js +156 -0
  306. package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
  307. package/dist/harnesses/pi-durable/sessions.js +47 -0
  308. package/dist/harnesses/pi-durable/storage.d.ts +4 -0
  309. package/dist/harnesses/pi-durable/storage.js +49 -0
  310. package/dist/harnesses/pi-durable/stream.d.ts +20 -0
  311. package/dist/harnesses/pi-durable/stream.js +221 -0
  312. package/dist/harnesses/pi-durable/text.d.ts +30 -0
  313. package/dist/harnesses/pi-durable/text.js +292 -0
  314. package/dist/harnesses/pi-durable/wake.d.ts +4 -0
  315. package/dist/harnesses/pi-durable/wake.js +81 -0
  316. package/dist/http/client.d.ts +6 -0
  317. package/dist/http/client.js +256 -0
  318. package/dist/http/contract.d.ts +541 -0
  319. package/dist/http/contract.js +179 -0
  320. package/dist/http/server.d.ts +34 -0
  321. package/dist/http/server.js +194 -0
  322. package/dist/index.d.ts +17 -4
  323. package/dist/index.js +10 -5
  324. package/dist/lark.d.ts +2 -2
  325. package/dist/lark.js +2 -2
  326. package/dist/locked-file.d.ts +17 -0
  327. package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
  328. package/dist/once.d.ts +6 -0
  329. package/dist/once.js +23 -0
  330. package/dist/paths.d.ts +36 -52
  331. package/dist/paths.js +66 -182
  332. package/dist/runtime.d.ts +25 -2
  333. package/dist/runtime.js +27 -0
  334. package/dist/scaffold/add-channel.d.ts +14 -27
  335. package/dist/scaffold/add-channel.js +82 -180
  336. package/dist/scaffold/init.d.ts +17 -18
  337. package/dist/scaffold/init.js +87 -99
  338. package/dist/scaffold/templates/SYSTEM.md +12 -0
  339. package/dist/scaffold/templates/env.example +4 -10
  340. package/dist/scaffold/templates/fastagent.config.ts +21 -33
  341. package/dist/scaffold/templates/gitignore +8 -1
  342. package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
  343. package/dist/scaffold/templates.d.ts +9 -4
  344. package/dist/scaffold/templates.js +7 -5
  345. package/dist/scaffold/vendor-skill.d.ts +1 -4
  346. package/dist/scaffold/vendor-skill.js +5 -6
  347. package/dist/schedule/cron.d.ts +13 -0
  348. package/dist/schedule/cron.js +52 -0
  349. package/dist/schedule/eventbridge-cron.d.ts +17 -0
  350. package/dist/schedule/eventbridge-cron.js +88 -0
  351. package/dist/schedule/schedule.d.ts +23 -0
  352. package/dist/schedule/schedule.js +34 -0
  353. package/dist/schedule/scheduler.d.ts +34 -33
  354. package/dist/schedule/scheduler.js +251 -137
  355. package/dist/schedule/state.d.ts +4 -14
  356. package/dist/schedule/state.js +7 -7
  357. package/dist/schedule/wake-alarm.d.ts +22 -2
  358. package/dist/schedule/wake-alarm.js +66 -20
  359. package/dist/schedule/wakeups.d.ts +16 -15
  360. package/dist/schedule/wakeups.js +47 -45
  361. package/dist/service.d.ts +56 -169
  362. package/dist/service.js +91 -187
  363. package/dist/serving-command.d.ts +10 -0
  364. package/dist/serving-command.js +16 -0
  365. package/dist/slack.d.ts +1 -1
  366. package/dist/slack.js +1 -1
  367. package/dist/{channels/kit/state.js → state-file.js} +6 -6
  368. package/dist/telegram.d.ts +1 -0
  369. package/dist/telegram.js +1 -0
  370. package/dist/tunnel.d.ts +3 -0
  371. package/dist/tunnel.js +12 -4
  372. package/dist/value-file.d.ts +21 -0
  373. package/dist/value-file.js +108 -0
  374. package/dist/version.d.ts +5 -0
  375. package/dist/version.js +14 -1
  376. package/package.json +18 -28
  377. package/dist/agent.d.ts +0 -106
  378. package/dist/agent.js +0 -21
  379. package/dist/channels/control.d.ts +0 -31
  380. package/dist/channels/control.js +0 -329
  381. package/dist/channels/define-channel.d.ts +0 -39
  382. package/dist/channels/define-channel.js +0 -9
  383. package/dist/channels/feishu/context-buffer.d.ts +0 -35
  384. package/dist/channels/feishu/context-buffer.js +0 -65
  385. package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
  386. package/dist/channels/http.d.ts +0 -23
  387. package/dist/channels/http.js +0 -57
  388. package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
  389. package/dist/channels/slack/context-buffer.d.ts +0 -23
  390. package/dist/channels/slack/context-buffer.js +0 -37
  391. package/dist/channels/sse.d.ts +0 -4
  392. package/dist/channels/sse.js +0 -66
  393. package/dist/cli/commands/chat.d.ts +0 -3
  394. package/dist/cli/commands/chat.js +0 -14
  395. package/dist/cli/commands/routine-run.d.ts +0 -6
  396. package/dist/cli/commands/routine-run.js +0 -46
  397. package/dist/cli/commands/routine.d.ts +0 -25
  398. package/dist/cli/commands/routine.js +0 -122
  399. package/dist/cli/commands/tool.d.ts +0 -1
  400. package/dist/cli/commands/tool.js +0 -57
  401. package/dist/collect.d.ts +0 -63
  402. package/dist/collect.js +0 -90
  403. package/dist/core.d.ts +0 -13
  404. package/dist/core.js +0 -15
  405. package/dist/engines/pi/agent-models.d.ts +0 -83
  406. package/dist/engines/pi/agent-models.js +0 -120
  407. package/dist/engines/pi/agent-session-factory.d.ts +0 -121
  408. package/dist/engines/pi/agent-session-factory.js +0 -517
  409. package/dist/engines/pi/chat.d.ts +0 -3
  410. package/dist/engines/pi/chat.js +0 -8
  411. package/dist/engines/pi/config.d.ts +0 -71
  412. package/dist/engines/pi/config.js +0 -199
  413. package/dist/engines/pi/create.d.ts +0 -170
  414. package/dist/engines/pi/create.js +0 -343
  415. package/dist/engines/pi/definition.d.ts +0 -74
  416. package/dist/engines/pi/definition.js +0 -236
  417. package/dist/engines/pi/entry-images.d.ts +0 -14
  418. package/dist/engines/pi/entry-images.js +0 -23
  419. package/dist/engines/pi/invoke-session.d.ts +0 -18
  420. package/dist/engines/pi/invoke-session.js +0 -403
  421. package/dist/engines/pi/locked-file.d.ts +0 -9
  422. package/dist/engines/pi/machine.d.ts +0 -53
  423. package/dist/engines/pi/machine.js +0 -137
  424. package/dist/engines/pi/models.d.ts +0 -200
  425. package/dist/engines/pi/models.js +0 -533
  426. package/dist/engines/pi/open.d.ts +0 -180
  427. package/dist/engines/pi/open.js +0 -270
  428. package/dist/engines/pi/openai-account-models.d.ts +0 -35
  429. package/dist/engines/pi/openai-account-models.js +0 -116
  430. package/dist/engines/pi/report.d.ts +0 -18
  431. package/dist/engines/pi/report.js +0 -59
  432. package/dist/engines/pi/retry-event.d.ts +0 -6
  433. package/dist/engines/pi/retry-event.js +0 -15
  434. package/dist/engines/pi/service.d.ts +0 -9
  435. package/dist/engines/pi/service.js +0 -14
  436. package/dist/engines/pi/session-builder.d.ts +0 -13
  437. package/dist/engines/pi/session-builder.js +0 -117
  438. package/dist/engines/pi/session-control.d.ts +0 -77
  439. package/dist/engines/pi/session-control.js +0 -908
  440. package/dist/engines/pi/session-effects.d.ts +0 -14
  441. package/dist/engines/pi/session-effects.js +0 -30
  442. package/dist/engines/pi/session-inheritance.d.ts +0 -21
  443. package/dist/engines/pi/session-inheritance.js +0 -204
  444. package/dist/engines/pi/session-markers.d.ts +0 -49
  445. package/dist/engines/pi/session-markers.js +0 -60
  446. package/dist/engines/pi/session-settings.d.ts +0 -67
  447. package/dist/engines/pi/session-settings.js +0 -119
  448. package/dist/engines/pi/session-store.d.ts +0 -69
  449. package/dist/engines/pi/session-store.js +0 -430
  450. package/dist/engines/pi/tool-context.d.ts +0 -45
  451. package/dist/engines/pi/tool-context.js +0 -31
  452. package/dist/engines/pi/tool.d.ts +0 -99
  453. package/dist/engines/pi/tool.js +0 -118
  454. package/dist/engines/pi/turn-kit.d.ts +0 -83
  455. package/dist/engines/pi/turn-kit.js +0 -275
  456. package/dist/engines/pi/wake-tool.d.ts +0 -9
  457. package/dist/engines/pi/wake-tool.js +0 -92
  458. package/dist/loader.d.ts +0 -41
  459. package/dist/loader.js +0 -116
  460. package/dist/node.d.ts +0 -3
  461. package/dist/node.js +0 -4
  462. package/dist/observe.d.ts +0 -6
  463. package/dist/observe.js +0 -47
  464. package/dist/pi.d.ts +0 -25
  465. package/dist/pi.js +0 -15
  466. package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
  467. package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
  468. package/dist/schedule/discover.d.ts +0 -17
  469. package/dist/schedule/discover.js +0 -61
  470. package/dist/schedule/routine.d.ts +0 -43
  471. package/dist/schedule/routine.js +0 -32
  472. package/dist/schedule/run.d.ts +0 -55
  473. package/dist/schedule/run.js +0 -146
  474. package/dist/secrets-gate.d.ts +0 -32
  475. package/dist/secrets-gate.js +0 -33
  476. package/dist/session-remote.d.ts +0 -47
  477. package/dist/session-remote.js +0 -460
  478. package/dist/session.d.ts +0 -466
  479. package/dist/session.js +0 -57
  480. /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
@@ -1,13 +1,15 @@
1
1
  import { fromForwarder } from "./agentcore-protocol.js";
2
2
  import { log } from "../log.js";
3
- import { loadServingRoutines, routesFor, startSchedules } from "../service.js";
3
+ import { routesFor, serviceOver, startSchedules, } from "../service.js";
4
4
  import { agentcoreRoutes, agentcorePing } from "./agentcore.js";
5
5
  import * as Effect from "effect/Effect";
6
- import { runRoutineByName, unknownRoutine } from "../schedule/run.js";
7
- import { fireRoutineOnce } from "../schedule/scheduler.js";
6
+ import { fireScheduleOnce } from "../schedule/scheduler.js";
7
+ import { nextRun } from "../schedule/cron.js";
8
+ import { createWakeAlarmSink } from "../schedule/wake-alarm.js";
9
+ import { setWakeupsSink } from "../schedule/wakeups.js";
8
10
  import { text } from "./respond.js";
9
11
  import { activeWork, beginWork } from "./busy.js";
10
- import { router } from "./serve.js";
12
+ import { router } from "./router.js";
11
13
  import { readBodyCapped } from "./body.js";
12
14
  import { MAX_ENVELOPE_BYTES } from "./agentcore-limits.js";
13
15
  /**
@@ -29,7 +31,7 @@ export function deferAgentcoreService(stages) {
29
31
  throw error;
30
32
  });
31
33
  const taken = await prepared;
32
- // Shutdown may have arrived while the workspace was being taken.
34
+ // Shutdown may have arrived while the storage was being taken.
33
35
  if (closed)
34
36
  throw new Error("service closed during initialization");
35
37
  assembling ??= stages.assemble(taken);
@@ -40,128 +42,92 @@ export function deferAgentcoreService(stages) {
40
42
  done();
41
43
  }
42
44
  };
43
- return {
44
- handler: async (request) => {
45
- if (closed)
46
- return new Response("service closed\n", { status: 503 });
47
- if (service)
48
- return service.handler(request);
49
- const path = new URL(request.url).pathname;
50
- if (path === "/ping" && request.method === "GET")
51
- return ping(request);
52
- if (path !== "/invocations" || request.method !== "POST")
53
- return new Response("not found\n", { status: 404 });
54
- let ready;
55
- // Only the INITIALIZATION is caught here.
56
- try {
57
- ready = await initialize();
58
- }
59
- catch (error) {
60
- const message = `initialization failed: ${String(error)}`;
61
- log.error(`[agentcore] ${message}`);
62
- const body = await readBodyCapped(request, MAX_ENVELOPE_BYTES);
63
- if (!("tooLarge" in body)) {
64
- let envelope;
65
- try {
66
- envelope = JSON.parse(body.text);
67
- }
68
- catch {
69
- // Invalid envelopes retain the initialization error.
70
- }
71
- if (envelope?.kind === "probe" && fromForwarder(envelope, process.env.FASTAGENT_INGRESS_SECRET)) {
72
- return Response.json({ ok: false, error: message });
73
- }
45
+ const handler = async (request) => {
46
+ if (closed)
47
+ return new Response("service closed\n", { status: 503 });
48
+ if (service)
49
+ return service.fetch(request);
50
+ const path = new URL(request.url).pathname;
51
+ if (path === "/ping" && request.method === "GET")
52
+ return ping(request);
53
+ if (path !== "/invocations" || request.method !== "POST")
54
+ return new Response("not found\n", { status: 404 });
55
+ let ready;
56
+ // Only the INITIALIZATION is caught here.
57
+ try {
58
+ ready = await initialize();
59
+ }
60
+ catch (error) {
61
+ const message = `initialization failed: ${String(error)}`;
62
+ log.error(`[agentcore] ${message}`);
63
+ const body = await readBodyCapped(request, MAX_ENVELOPE_BYTES);
64
+ if (!("tooLarge" in body)) {
65
+ let envelope;
66
+ try {
67
+ envelope = JSON.parse(body.text);
68
+ }
69
+ catch {
70
+ // Invalid envelopes retain the initialization error.
71
+ }
72
+ if (envelope?.kind === "probe" && fromForwarder(envelope, process.env.FASTAGENT_INGRESS_SECRET)) {
73
+ return Response.json({ ok: false, error: message });
74
74
  }
75
- return new Response(`${message}\n`, { status: 503 });
76
75
  }
77
- if (closed)
78
- return new Response("service closed\n", { status: 503 });
79
- return ready.handler(request);
80
- },
81
- close() {
82
- closed = true;
83
- closing ??= (async () => {
84
- // A failed assembly already reached its caller.
85
- await (await assembling?.catch(() => undefined))?.close();
86
- })();
87
- return closing;
88
- },
76
+ return new Response(`${message}\n`, { status: 503 });
77
+ }
78
+ if (closed)
79
+ return new Response("service closed\n", { status: 503 });
80
+ return ready.fetch(request);
89
81
  };
82
+ // Nothing to wait for before the first envelope: the definition opens on it.
83
+ return serviceOver(handler, Promise.resolve(), () => {
84
+ closed = true;
85
+ closing ??= (async () => {
86
+ // A failed assembly already reached its caller.
87
+ await (await assembling?.catch(() => undefined))?.close();
88
+ })();
89
+ return closing;
90
+ });
90
91
  }
91
- export async function mountAgentcoreService(opened, options = {}) {
92
- const { agentDir, workspace, stateRoot, sessionControl } = opened;
93
- const agent = options.wrapAgent?.(opened.agent) ?? opened.agent;
94
- // NO control plane on this host, and `sessionControl: true` cannot change that. The only public way in is the
95
- // forwarder's Function URL, which relays an arbitrary `rawPath` verbatim as a webhook envelope and attaches the
96
- // ingress secret ITSELF (deploy/agentcore/forwarder.js), so every anonymous caller arrives as trusted ingress. A
97
- // channel route survives that because it checks its platform's signature; `/control/*` has no such check.
98
- //
99
- // The recipe if it is ever wanted: a `kind: "control"` envelope on the IAM-gated `InvokeAgentRuntime`, which the
100
- // forwarder never emits (the way `kind: "invoke"` runs a turn without the ingress secret). The envelope is
101
- // request/response with a buffered body, so the long-lived `GET /control/sessions/{id}/events` stream a client
102
- // renders from could not ride it.
92
+ export async function mountAgentcoreService(opened) {
93
+ const { agent, agentDir, stateRoot, schedules } = opened;
94
+ // The only public way in is the forwarder's Function URL, which relays an arbitrary `rawPath` verbatim as a webhook
95
+ // envelope and attaches the ingress secret ITSELF (deploy/agentcore/forwarder.js), so every anonymous caller arrives
96
+ // as trusted ingress. A channel route survives that because it checks its platform's signature.
103
97
  //
104
- // Every config key that cannot mean anything on this host says so: silence is how an operator concludes a setting
105
- // took effect.
106
- if (opened.http?.cors) {
107
- log.warn("[fastagent] agentcore: http.cors has no effect here — no browser reaches this container. Its ingress is the " +
108
- "forwarder's Function URL (webhooks) and the Runtime's IAM-gated API, neither of which is a page.");
109
- }
110
- if (opened.http?.invoke !== undefined) {
111
- log.warn("[fastagent] agentcore: http.invoke has no effect here — this host serves the Runtime's POST /invocations " +
112
- "contract instead of our own /invoke, and reaching it already requires bedrock-agentcore:InvokeAgentRuntime.");
113
- }
114
- if (opened.http?.run !== undefined) {
115
- log.warn("[fastagent] agentcore: http.run has no effect here — routines fire through the forwarder's " +
116
- "routine-fire envelope, which is gated by the ingress secret rather than served as an anonymous route.");
117
- }
118
- if (opened.publishControl) {
119
- log.warn("[fastagent] agentcore: sessionControl is ON but /control/* is NOT served here — this host's only public " +
120
- "ingress relays anonymous traffic as trusted, so the plane is not assembled behind it " +
121
- "(docs/design/session-control.md §14)");
122
- }
123
- // Started here, not deferred to an envelope.
124
- const routines = await loadServingRoutines(agentDir);
125
- const scheduled = startSchedules(agent, stateRoot, routines, { externalClock: true });
98
+ // Started here, not deferred to an envelope. No resident timers: each instant arrives as its own fire from the
99
+ // recurring schedule the container sets (`armAlarms`), ONE path per instant, so the reply to that delivery says
100
+ // whether it ran. The clock still pumps wake-ups; a redelivered fire claims its slot once.
101
+ const mirror = armAlarms(stateRoot, () => schedules);
102
+ const scheduled = startSchedules(agent, stateRoot, schedules, { localClock: false });
126
103
  const lazyChannels = async () => {
127
- const lazy = await routesFor(agentDir, agent, stateRoot, sessionControl, { http: { invoke: false } });
104
+ const lazy = routesFor(agent, stateRoot, opened.channels);
128
105
  if (lazy.longConnections.length > 0) {
129
106
  throw new Error(`long-connection channel(s) ${lazy.longConnections.map((c) => c.name).join(", ")} cannot serve on ` +
130
107
  `AgentCore (scale-to-zero severs resident connections) — use the channel's webhook form`);
131
108
  }
132
- // CHANNELS ONLY — nothing unverified rides the public relay. `lazy.unverified` (here just `GET /health`) is dropped
133
- // with the control plane, for the same reason: what arrives through that URL is anonymous.
134
- return { routes: lazy.selfVerifying };
109
+ return { routes: lazy.routes };
135
110
  };
136
111
  const adapterRoutes = mountAgentcore({
137
112
  agent,
138
113
  stateRoot,
139
- routines: scheduled.routines,
140
- onStateReady: options.onStateReady,
114
+ schedules: () => schedules,
115
+ ...(mirror ? { onStateReady: mirror } : {}),
141
116
  channels: lazyChannels,
142
117
  });
143
- // SELF-VERIFYING, not unverified: both paths are reached only through `InvokeAgentRuntime`, which AWS gates with
144
- // IAM. Putting them in the other table applied our JSON body gate to `POST /invocations` (whose content type is
145
- // AWS's to set) and reported two IAM-protected paths as authenticating nobody.
146
- const handler = router({ selfVerifying: adapterRoutes });
118
+ const handler = router(adapterRoutes);
147
119
  log.info(`[fastagent] agentcore: serving POST /invocations + GET /ping (FASTAGENT_AGENTCORE=1)`);
148
120
  return {
149
- handler,
150
- agent,
121
+ // Nothing to open: no port of its own, no resident connections.
122
+ ...serviceOver(handler, Promise.resolve(), async () => scheduled.stop()),
151
123
  // The adapter IS the surface here; the channel routes arrive lazily BEHIND it.
152
124
  routes: adapterRoutes,
153
125
  agentDir,
154
- workspace,
155
126
  // Channels remain lazy until the adapter receives trusted ingress.
156
127
  channels: { routes: [], longConnections: [] },
157
- // NONE: the adapter's two paths are IAM-gated and the channels behind them verify their own platform.
158
- unverifiedRoutes: [],
159
- // No `controlPrefix`: it is not served here, so nothing may report a prefix a caller could dial.
160
- routines: scheduled.routines,
161
- ready: Promise.resolve(), // nothing to open: no port of our own, no resident connections
162
- async close() {
163
- scheduled.stop();
164
- },
128
+ schedules,
129
+ // Reached only through /invocations here (SPEC.md §9.5).
130
+ api: false,
165
131
  };
166
132
  }
167
133
  /**
@@ -169,43 +135,58 @@ export async function mountAgentcoreService(opened, options = {}) {
169
135
  * surface (channels/agentcore.ts).
170
136
  */
171
137
  export function mountAgentcore(options) {
172
- const { agent, stateRoot, routines, onStateReady, channels } = options;
173
- // OCCURRENCE SEMANTICS, because this host's clock is ours: `deploy` wrote the EventBridge rule and the forwarder
174
- // relays its instant behind the ingress secret, so the slot is a real grid point of that schedule and a claim
175
- // means something (dedup across redeliveries, a fire history, the overlap policy). `POST /run` — the
176
- // unauthenticated API — is NOT this and is not served here at all.
177
- const fireRoutine = async (name, occurrence) => {
178
- const routine = routines.find((r) => r.name === name);
179
- if (!routine)
180
- return unknownRoutine(name, routines);
181
- const outcome = await Effect.runPromise(fireRoutineOnce({ agent, stateRoot, routine, slot: occurrence }).pipe(Effect.mapError((e) => e.cause))).catch((cause) => {
182
- // `fireRoutineOnce`'s only failure is a claim-state fault, which happens BEFORE any claim exists — the
138
+ const { agent, stateRoot, schedules, onStateReady, channels } = options;
139
+ // OCCURRENCE SEMANTICS, because this host's clock is ours: the container set the recurring schedule that names this
140
+ // instant and the forwarder relays it behind the ingress secret, so a claim means something (dedup across
141
+ // EventBridge's redeliveries, a fire history, the overlap policy).
142
+ const fireSchedule = async (name, occurrence) => {
143
+ const schedule = schedules().find((s) => s.name === name);
144
+ // EventBridge can fire what a release has not reached yet (a mirror still in flight, or one that failed): a fire
145
+ // for a schedule since removed, or for an instant its cron no longer has, is answered as skipped, not run — and not
146
+ // as an error the forwarder would make EventBridge retry.
147
+ const skip = (why) => {
148
+ log.info(`[schedule] ${name}: alarm for ${occurrence.toISOString()} skipped — ${why}`);
149
+ return Response.json({ slot: occurrence.toISOString(), fired: false, skippedReason: why, ms: 0 });
150
+ };
151
+ if (!schedule)
152
+ return skip("no such schedule any more");
153
+ if (nextRun(schedule.cron, schedule.tz, new Date(occurrence.getTime() - 1))?.getTime() !== occurrence.getTime()) {
154
+ return skip(`not an instant of its cron "${schedule.cron}" any more`);
155
+ }
156
+ const outcome = await Effect.runPromise(fireScheduleOnce({ agent, stateRoot, schedule, slot: occurrence }).pipe(Effect.mapError((e) => e.cause))).catch((cause) => {
157
+ // `fireScheduleOnce`'s only failure is a claim-state fault, which happens BEFORE any claim exists — the
183
158
  // occurrence is unburned, so the forwarder's throw makes EventBridge retry it, which is the right answer.
184
159
  log.error(`[schedule] firing "${name}" for ${occurrence.toISOString()} failed: ${String(cause)}`);
185
160
  return undefined;
186
161
  });
187
162
  if (outcome === undefined) {
188
- return text(`routine "${name}": claim state unavailable, nothing was claimed — retry\n`, 500);
163
+ return text(`schedule "${name}": claim state unavailable, nothing was claimed — retry\n`, 500);
189
164
  }
190
165
  return Response.json({ slot: occurrence.toISOString(), ...outcome });
191
166
  };
192
- // BY NAME, on the IAM door. `POST /run`'s contract, through the only ingress this host has for a caller AWS has
193
- // already identified — which makes it stricter here than the anonymous route other hosts publish. A routine
194
- // without a cron is reachable ONLY this way on this host, and that is the point: nothing is unreachable.
195
- const runRoutine = async (name) => {
196
- const routine = routines.find((r) => r.name === name);
197
- if (!routine)
198
- return unknownRoutine(name, routines);
199
- return Response.json(await runRoutineByName(agent, routine));
200
- };
201
167
  return agentcoreRoutes({
202
168
  channels,
203
- agent,
204
169
  stateRoot,
205
170
  isBusy: () => activeWork() > 0,
206
171
  // What separates a forwarder envelope from any IAM principal's InvokeAgentRuntime call.
207
172
  ingressSecret: process.env.FASTAGENT_INGRESS_SECRET,
208
173
  onStateReady,
209
- ...(routines.length > 0 ? { fireRoutine, runRoutine } : {}),
174
+ fireSchedule,
210
175
  });
211
176
  }
177
+ /**
178
+ * The alarm mirror: each schedule as a recurring EventBridge schedule and each pending wake-up as a one-shot one, set
179
+ * by the forwarder (schedule/wake-alarm.ts), so a container AgentCore reclaimed is woken for them. Installed BEFORE the
180
+ * clock starts: the first wake poll may advance a recurring entry, and that save must already re-arm its alarm.
181
+ * Without the wake secret there is no way to set one, which is said.
182
+ */
183
+ function armAlarms(stateRoot, schedules) {
184
+ const secret = process.env.FASTAGENT_WAKE_SECRET;
185
+ if (!secret) {
186
+ log.warn("[fastagent] FASTAGENT_WAKE_SECRET is missing; wake-ups and schedules cannot wake a reclaimed container");
187
+ return undefined;
188
+ }
189
+ const sink = Effect.runSync(createWakeAlarmSink({ secret, schedules }));
190
+ setWakeupsSink(sink);
191
+ return () => sink(stateRoot);
192
+ }
@@ -1,4 +1,3 @@
1
- import type { Agent } from "../agent.ts";
2
1
  import type { ChannelHandler, Routes } from "../channel.ts";
3
2
  /**
4
3
  * What the lazy factory hands back: the CHANNELS' routes, and nothing else.
@@ -8,10 +7,8 @@ import type { ChannelHandler, Routes } from "../channel.ts";
8
7
  * so behind THIS door an anonymous caller and an IAM one are the same thing. A channel route survives that because
9
8
  * it verifies the platform's signature inside itself; nothing fastagent serves does.
10
9
  *
11
- * The other door is the Runtime's own, IAM-gated: the forwarder emits only `webhook`, `routine-fire`, `wake-poke`
12
- * and `probe`, so any other KIND can only come from a direct `InvokeAgentRuntime` call. That is what lets
13
- * `kind: "invoke"` run a turn here with no ingress secret, and it is where anything else that needs a real caller
14
- * identity belongs.
10
+ * The other door is the Runtime's own, IAM-gated: a direct `InvokeAgentRuntime` call, which carries no ingress
11
+ * secret, and which this container answers only with a `probe`.
15
12
  */
16
13
  export interface RouteSurface {
17
14
  routes: Routes;
@@ -19,32 +16,19 @@ export interface RouteSurface {
19
16
  export interface AgentcoreAdapterOptions {
20
17
  /** The channel surface. */
21
18
  channels: () => Promise<RouteSurface> | RouteSurface;
22
- agent: Agent;
23
19
  /** Where the forwarder URL from envelopes is persisted for the wake-alarm sink (the state root). */
24
20
  stateRoot: string;
25
21
  /** Process-wide background-work signal (busy.ts `activeWork() > 0`) — injected for tests. */
26
22
  isBusy: () => boolean;
27
23
  /**
28
- * Fire ONE declared schedule for the occurrence EventBridge named — the claim/run/settle the resident clock uses,
29
- * not the `POST /run` API.
24
+ * Fire ONE declared schedule for the occurrence EventBridge named — the claim/run/settle the resident clock uses.
30
25
  *
31
- * THIS IS WHERE OCCURRENCE SEMANTICS LIVE ON THIS HOST, and it is separate from that route on purpose. `deploy`
32
- * wrote the rule, injected `<aws.scheduler.scheduled-time>` and the forwarder relays it behind the ingress
33
- * secret, so this caller is one we produced and authenticated: the instant it names really is a grid point of
34
- * that schedule, which is what makes a claim (and therefore dedup across EventBridge's redeliveries, a fire
35
- * history and the overlap policy) mean anything. `POST /run` has none of that — it is an unauthenticated API
36
- * whose caller cannot be told which occurrence it means, so it does not pretend to (schedule/run.ts).
37
- *
38
- * Undefined when the definition declares no schedules.
39
- */
40
- fireRoutine?: (name: string, occurrence: Date) => Promise<Response>;
41
- /**
42
- * Run a declared routine BY NAME — the `POST /run` contract, for the host that publishes no routes.
43
- *
44
- * Undefined when the definition declares none. Note what this does NOT do: no occurrence, no claim, no fire
45
- * history. Those belong to {@link fireRoutine}, whose caller is a clock we wrote.
26
+ * The container set the recurring schedule that names this instant and the forwarder relays it behind the ingress
27
+ * secret, so this caller is one we produced and authenticated, which is what makes a claim (and therefore dedup
28
+ * across EventBridge's redeliveries, a fire history and the overlap policy) mean anything. Always present: a
29
+ * schedule can be added while the container runs, and a fire for one since removed is answered by it, as skipped.
46
30
  */
47
- runRoutine?: (name: string) => Promise<Response>;
31
+ fireSchedule: (name: string, occurrence: Date) => Promise<Response>;
48
32
  /** FASTAGENT_INGRESS_SECRET: what makes an envelope the FORWARDER's rather than any IAM principal's. */
49
33
  ingressSecret?: string;
50
34
  /** Runs once on activation, after accepting the current forwarder callback URL. */
@@ -1,14 +1,14 @@
1
- /** AWS AgentCore Runtime adapter: serve fastagent's whole HTTP surface through the Runtime's service contract. */
1
+ /** AWS AgentCore Runtime adapter: serve the channels, the schedules' fires and the wake pokes through the Runtime's service contract. */
2
2
  import { Buffer } from "node:buffer";
3
3
  import * as Effect from "effect/Effect";
4
4
  import { PortFailure, portJoin } from "../effect-port.js";
5
- import { ENVELOPE_KINDS, fromForwarder } from "./agentcore-protocol.js";
5
+ import { ENVELOPE_KINDS, fromForwarder, } from "./agentcore-protocol.js";
6
6
  import { beginWork } from "./busy.js";
7
- import { router } from "../channels/serve.js";
7
+ import { router } from "../channels/router.js";
8
8
  import { log } from "../log.js";
9
+ import { once } from "../once.js";
9
10
  import { rememberWakeAlarmUrl } from "../schedule/wake-alarm.js";
10
11
  import { readBodyCapped } from "./body.js";
11
- import { createInvokeHandler } from "./http.js";
12
12
  import { text } from "./respond.js";
13
13
  import { MAX_ENVELOPE_BYTES, MAX_WEBHOOK_BODY_BYTES } from "./agentcore-limits.js";
14
14
  const jsonHeaders = { "content-type": "application/json" };
@@ -18,18 +18,13 @@ const json = (body, status) => new Response(`${JSON.stringify(body)}\n`, { statu
18
18
  */
19
19
  function createActivation(deps) {
20
20
  const { stateRoot, onStateReady } = deps;
21
- // UNINTERRUPTIBLE, because the outcome is CACHED: `Effect.cached` memoizes whatever exit it sees,
22
- // interruption included. A once-per-process activation that remembered "interrupted" would answer
23
- // every later envelope with an empty cause instead of the success or the diagnosable failure this
24
- // block promises. Both are already unreachable (no caller passes a signal), which is exactly why
25
- // the invariant has to be written down rather than relied on.
26
- const stateReady = Effect.runSync(Effect.cached(portJoin(async () => {
21
+ const stateReady = once(portJoin(async () => {
27
22
  onStateReady?.();
28
- }).pipe(Effect.uninterruptible)));
29
- const channels = Effect.runSync(Effect.cached(portJoin(async () => {
23
+ }));
24
+ const channels = once(portJoin(async () => {
30
25
  const surface = await deps.channels();
31
- return router({ selfVerifying: surface.routes });
32
- }).pipe(Effect.uninterruptible)));
26
+ return router(surface.routes);
27
+ }));
33
28
  return {
34
29
  prepare: (envelope) => Effect.gen(function* () {
35
30
  // Use the current callback URL rather than the one persisted by an earlier deployment.
@@ -46,9 +41,19 @@ function createActivation(deps) {
46
41
  };
47
42
  }
48
43
  export function agentcoreRoutes(options) {
49
- const { channels, agent, stateRoot, isBusy, fireRoutine, runRoutine, ingressSecret, onStateReady } = options;
44
+ const { channels, stateRoot, isBusy, fireSchedule, ingressSecret, onStateReady } = options;
50
45
  const activation = createActivation({ stateRoot, onStateReady, channels });
51
- const invokeHandler = createInvokeHandler(agent);
46
+ const carried = (request) => {
47
+ const { method, path, query, headers, bodyB64 } = request;
48
+ return new Request(`http://agentcore.local${path}${typeof query === "string" && query !== "" ? `?${query}` : ""}`, {
49
+ method,
50
+ headers: headers ?? {},
51
+ body: typeof bodyB64 === "string" && method !== "GET" && method !== "HEAD"
52
+ ? Buffer.from(bodyB64, "base64")
53
+ : undefined,
54
+ });
55
+ };
56
+ const malformed = (request) => typeof request.method !== "string" || typeof request.path !== "string" || !request.path.startsWith("/");
52
57
  const handleInvocation = async (req) => {
53
58
  const body = await readBodyCapped(req, MAX_ENVELOPE_BYTES);
54
59
  if ("tooLarge" in body)
@@ -66,10 +71,10 @@ export function agentcoreRoutes(options) {
66
71
  // The forwarder, or another IAM principal? See `fromForwarder` for what that actually decides.
67
72
  const trusted = fromForwarder(envelope, ingressSecret);
68
73
  if (!trusted) {
69
- // The IAM door's kinds: AWS authenticated this caller, so no ingress secret is expected or wanted. A `probe`
70
- // here only opens the workspace (the deferred wrapper did that before this line) and says so: it is how
71
- // `login --deployment` gets a workspace to log in, after a reset, on a runtime nothing has invoked yet.
72
- if (envelope.kind !== "invoke" && envelope.kind !== "routine-run" && envelope.kind !== "probe") {
74
+ // The IAM door's one kind: AWS authenticated this caller, so no ingress secret is expected or wanted. A `probe`
75
+ // here only opens the deployed definition (the deferred wrapper did that before this line) and says so: it is
76
+ // how `login --deployment` gets a definition to log in, after a reset, on a runtime nothing has invoked yet.
77
+ if (envelope.kind !== "probe") {
73
78
  log.warn(`[agentcore] rejected an unauthenticated "${envelope.kind}" envelope`);
74
79
  return text("forbidden\n", 403);
75
80
  }
@@ -87,10 +92,9 @@ export function agentcoreRoutes(options) {
87
92
  return json({ ok: false, error: `activation failed: ${String(e)}` }, 200);
88
93
  return text(`activation failed: ${String(e)}\n`, 503);
89
94
  }
90
- // Public invokes do not activate channels.
91
95
  let constructionError;
92
96
  let dispatch;
93
- if (trusted && envelope.kind !== "invoke") {
97
+ if (trusted) {
94
98
  try {
95
99
  dispatch = await Effect.runPromise(activation.channels.pipe(Effect.mapError((error) => error.cause)));
96
100
  }
@@ -101,10 +105,9 @@ export function agentcoreRoutes(options) {
101
105
  }
102
106
  switch (envelope.kind) {
103
107
  case "webhook": {
104
- const { method, path, query, headers, bodyB64 } = envelope;
105
- if (typeof method !== "string" || typeof path !== "string" || !path.startsWith("/")) {
108
+ const { bodyB64 } = envelope;
109
+ if (malformed(envelope))
106
110
  return text('webhook envelope needs { "method": string, "path": "/..." }\n', 400);
107
- }
108
111
  if (typeof bodyB64 === "string" && Buffer.byteLength(bodyB64, "base64") > MAX_WEBHOOK_BODY_BYTES) {
109
112
  return json({
110
113
  status: 413,
@@ -112,13 +115,7 @@ export function agentcoreRoutes(options) {
112
115
  bodyB64: Buffer.from("payload too large\n").toString("base64"),
113
116
  }, 200);
114
117
  }
115
- const inner = new Request(`http://agentcore.local${path}${typeof query === "string" && query !== "" ? `?${query}` : ""}`, {
116
- method,
117
- headers: headers ?? {},
118
- body: typeof bodyB64 === "string" && method !== "GET" && method !== "HEAD"
119
- ? Buffer.from(bodyB64, "base64")
120
- : undefined,
121
- });
118
+ const inner = carried(envelope);
122
119
  // A construction failure is the request's failure (503 through the forwarder, so the platform retries and the
123
120
  // operator sees the message), never a silently-empty channel.
124
121
  if (!dispatch)
@@ -138,36 +135,16 @@ export function agentcoreRoutes(options) {
138
135
  };
139
136
  return json(reply, 200);
140
137
  }
141
- case "routine-fire": {
138
+ case "schedule-fire": {
142
139
  const { name, occurrence } = envelope;
143
140
  if (typeof name !== "string" || typeof occurrence !== "string" || Number.isNaN(Date.parse(occurrence))) {
144
- return text('routine-fire envelope needs { "name": string, "occurrence": ISO-date }\n', 400);
141
+ return text('schedule-fire envelope needs { "name": string, "occurrence": ISO-date }\n', 400);
145
142
  }
146
- // No schedules in this definition: nothing to fire, and no rule should have survived a deploy that removed
147
- // them either.
148
- if (!fireRoutine)
149
- return text(`no routines in this deployment (routine-fire "${name}")\n`, 404);
150
143
  // The whole agent turn runs inside this request — but the CALLER (the forwarder Lambda) may time out and drop
151
144
  // the connection while the turn keeps running server-side.
152
145
  const workDone = beginWork();
153
146
  try {
154
- return await fireRoutine(name, new Date(occurrence));
155
- }
156
- finally {
157
- workDone();
158
- }
159
- }
160
- case "routine-run": {
161
- const { name } = envelope;
162
- if (typeof name !== "string" || name === "") {
163
- return text('routine-run envelope needs { "name": string }\n', 400);
164
- }
165
- if (!runRoutine)
166
- return text(`no routines in this deployment (routine-run "${name}")\n`, 404);
167
- // The whole agent turn runs inside this request; the caller may time out while it keeps running.
168
- const workDone = beginWork();
169
- try {
170
- return await runRoutine(name);
147
+ return await fireSchedule(name, new Date(occurrence));
171
148
  }
172
149
  finally {
173
150
  workDone();
@@ -187,16 +164,6 @@ export function agentcoreRoutes(options) {
187
164
  ? { ok: true }
188
165
  : { ok: false, error: `channel construction failed: ${constructionError}` }, 200);
189
166
  }
190
- case "invoke": {
191
- // Reuse the HTTP channel's handler wholesale (SSE, cancellation, backpressure) by handing it the shape it
192
- // already validates — one protocol, one implementation.
193
- const inner = new Request("http://agentcore.local/invoke", {
194
- method: "POST",
195
- headers: jsonHeaders,
196
- body: JSON.stringify({ session: envelope.session, text: envelope.text }),
197
- });
198
- return invokeHandler(inner);
199
- }
200
167
  default:
201
168
  return text(`unknown envelope kind "${envelope.kind}"\n`, 400);
202
169
  }
@@ -1,19 +1,3 @@
1
- /**
2
- * Refuse a request to one of OUR routes that does not declare a JSON body — `undefined` when it does.
3
- *
4
- * This is what makes "a foreign origin simply gets no CORS headers" safe. Withholding the headers stops a page from
5
- * READING the reply; it does not stop the request. A cross-origin POST carrying `text/plain` (or a form's
6
- * `multipart/form-data`) is a CORS *simple request*: no preflight, sent regardless, and the turn it asks for runs.
7
- * Demanding `application/json` takes the request out of that class, so the browser must preflight it — and a
8
- * preflight we do not answer is a request that is never sent.
9
- *
10
- * Asked of the ROUTE, never of "does this have a body": the control plane reads an empty body as `{}`, so a
11
- * body-less POST would otherwise walk straight through the gate.
12
- *
13
- * NOT applied to channel routes. Their caller is a platform's server with its own content types (Slack posts
14
- * `application/x-www-form-urlencoded` for some payloads) and its own signature check, and a page cannot forge that.
15
- */
16
- export declare function refuseNonJsonBody(req: Request): Response | undefined;
17
1
  /** Read a request body with a hard byte cap (real bytes). */
18
2
  export declare function readBodyCapped(req: Request, max: number): Promise<{
19
3
  text: string;
@@ -1,28 +1,3 @@
1
- import { text } from "./respond.js";
2
- /**
3
- * Refuse a request to one of OUR routes that does not declare a JSON body — `undefined` when it does.
4
- *
5
- * This is what makes "a foreign origin simply gets no CORS headers" safe. Withholding the headers stops a page from
6
- * READING the reply; it does not stop the request. A cross-origin POST carrying `text/plain` (or a form's
7
- * `multipart/form-data`) is a CORS *simple request*: no preflight, sent regardless, and the turn it asks for runs.
8
- * Demanding `application/json` takes the request out of that class, so the browser must preflight it — and a
9
- * preflight we do not answer is a request that is never sent.
10
- *
11
- * Asked of the ROUTE, never of "does this have a body": the control plane reads an empty body as `{}`, so a
12
- * body-less POST would otherwise walk straight through the gate.
13
- *
14
- * NOT applied to channel routes. Their caller is a platform's server with its own content types (Slack posts
15
- * `application/x-www-form-urlencoded` for some payloads) and its own signature check, and a page cannot forge that.
16
- */
17
- export function refuseNonJsonBody(req) {
18
- // Parameters are part of the header (`application/json; charset=utf-8`), so compare the media type alone.
19
- const mediaType = (req.headers.get("content-type") ?? "").split(";")[0]?.trim().toLowerCase();
20
- if (mediaType === "application/json")
21
- return undefined;
22
- // Says what is required, and does not echo what arrived: reflecting a request header into a response body is a
23
- // habit worth not having, and the sender already knows what they sent.
24
- return text("content-type must be application/json\n", 415);
25
- }
26
1
  /** Read a request body with a hard byte cap (real bytes). */
27
2
  export async function readBodyCapped(req, max) {
28
3
  if (!req.body)
@@ -1,4 +1,9 @@
1
- /** Webhooks ACK before background turns finish, so open requests cannot determine runtime idleness. */
1
+ /**
2
+ * The process's work in flight: every message not yet settled (counted by the Agent, pi-durable/agent.ts), and the
3
+ * channel, schedule and AgentCore work that has not reached an accepted message yet. Webhooks ACK before their turns
4
+ * finish, so open requests cannot tell whether the process is idle; this can. Read by AgentCore's `/ping` and by
5
+ * `dev`'s restart.
6
+ */
2
7
  let inFlight = 0;
3
8
  /** Mark background work as started. */
4
9
  export function beginWork() {
@@ -0,0 +1,4 @@
1
+ import type { Agent } from "../agent-api.ts";
2
+ import type { ChannelContext } from "../channel.ts";
3
+ /** The context of the channel `name` (its file's name under `src/channels/`), its state under `stateRoot`. */
4
+ export declare function channelContext(agent: Agent, stateRoot: string, name: string): ChannelContext;