@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
@@ -0,0 +1,12 @@
1
+ # Standing instructions
2
+
3
+ This file, `SYSTEM.md`, is your system prompt. It is read for every message along with the rest of your definition: `AGENTS.md` if there is one, `skills/` (capabilities you load when a task calls for them) and `prompts/` (prompt templates). An edit to any of them takes effect on your next message, no restart. Code in `src/` (tools, extensions, channels, schedules) loads when you start.
4
+
5
+ Your definition is this directory: this file, `skills/`, `src/` and the config beside them. It is also your working directory, so a file you create lands here unless you put it elsewhere. Use only the tools actually listed in your system prompt.
6
+
7
+ When your tools allow it, you can improve yourself. When a task reveals something durable — a repeatable process, a standing preference, a hard-won fact — write it into your definition instead of losing it:
8
+
9
+ - A repeatable process or capability → a new skill beside this file: `skills/<name>/SKILL.md`. Read the `writing-great-skills` skill first; it is the guide to authoring skills well.
10
+ - A standing instruction or fact → edit this file.
11
+
12
+ Keep both lean: include only what changes your behavior, and delete what no longer earns its place.
@@ -2,30 +2,24 @@
2
2
  # fastagent) and uncomment what you need. Everything here is OPTIONAL — the defaults work without a .env.
3
3
 
4
4
  # --- Model auth ---
5
- # Pick auth once: `fastagent login` (a subscription/OAuth provider like openai-codex, or an API key),
5
+ # Pick auth once: `fastagent login` (an account such as ChatGPT for openai, or an API key),
6
6
  # or set a provider API key here — the variable name is provider-specific (e.g. OPENAI_API_KEY,
7
7
  # ANTHROPIC_API_KEY). `fastagent dev` then lets you choose a model from whatever you're logged into.
8
8
  # OPENAI_API_KEY=
9
9
  # ANTHROPIC_API_KEY=
10
10
 
11
- # --- Which agent (only when a workspace holds several) ---
12
- # FASTAGENT_AGENT names the agent directory to serve. It CANNOT be set here: placement resolves before
13
- # this file is read (it is what decides whose .env this is). Put it in your shell, an .envrc, or the
14
- # command: `FASTAGENT_AGENT=pm fastagent dev`.
15
-
16
11
  # --- Model selection (overrides fastagent.config) ---
17
12
  # Precedence: --model flag > FASTAGENT_MODEL > config — one chain, evaluated in whichever environment
18
- # is running. `fastagent dev` writes your first-run pick to fastagent.config; set it here to override
19
- # it. THIS FILE also declares the environment `fastagent deploy` resolves in, so a value here rides the
13
+ # is running. THIS FILE also declares the environment `fastagent deploy` resolves in, so a value here rides the
20
14
  # release manifest into the deployment and a deployment can run a model the committed config does not
21
15
  # name. That recorded value outranks the deployed box's own .env, so switching models there means
22
16
  # editing this line and redeploying.
23
- # FASTAGENT_MODEL=openai-codex/gpt-5.5
17
+ # FASTAGENT_MODEL=openai/gpt-5.5
24
18
 
25
19
  # --- Serving (fastagent start) ---
26
20
  # Port precedence: --port > PORT > config.http.port > 8787
27
21
  # PORT=8787
28
- # Machine-state root: sessions, schedule state, and channel state derive from it.
22
+ # Machine-state root: the agent's storage, schedule state, and channel state live under it.
29
23
  # Default: <agent dir>/.state. Point it at a mounted volume so a redeploy that replaces the
30
24
  # directory keeps conversations.
31
25
  # FASTAGENT_STATE_DIR=/data/.state
@@ -1,36 +1,24 @@
1
- // fastagent.config.ts — deployment choices only (model / http; code tools auto-discover from tools/).
2
- // Your agent's prompt lives in SYSTEM.md / APPEND_SYSTEM.md; its capabilities in skills/ + tools/ — never here.
3
- // An AGENTS.md in the WORKSPACE (the directory the agent is started in) is read as project context.
4
- // Model precedence: `--model` flag > FASTAGENT_MODEL env > this default.
5
- // No model is preset: `fastagent dev` shows the full model catalog (models you already have
6
- // credentials for come first; picking one that needs auth logs you in inline) and writes your choice
7
- // below. Or set it by hand to a "provider/modelId" (`fastagent models` lists them).
8
- // Self-hosted model (vLLM/Ollama/…) or your own gateway? Declare it in a models.json next to this
9
- // file and select it like any other spec — see docs/configuration.md "Custom model endpoints".
1
+ // fastagent.config.ts — the agent's configuration: its default model and how it is served. Its prompt lives in
2
+ // SYSTEM.md, its capabilities in skills/ and src/ (tools, extensions, channels, schedules) — never here.
10
3
  //
11
- // `satisfies` is what makes your editor complete these keys and describe them on hover — and what
12
- // turns a typo into an error you see while writing rather than one `fastagent dev` reports. The
13
- // import is TYPE-only: nothing is loaded at runtime. Every key is optional; the commented lines
14
- // below carry the default.
15
- import type { FastagentConfig } from "@fastagent-sh/fastagent";
4
+ // Model precedence: `--model` flag > FASTAGENT_MODEL env > this default. No model is preset: `fastagent dev` shows
5
+ // the model catalog (models you already have credentials for come first; picking one that needs auth logs you in
6
+ // inline) and runs with your choice; set it below to keep it. `fastagent models` lists every "provider/modelId".
7
+ // A self-hosted model (vLLM, Ollama, …) or your own gateway is a provider in code: `providers: [...]`, built with
8
+ // pi-ai's `createProvider`.
9
+ //
10
+ // Every key is optional; the commented lines carry an example. `satisfies` is what makes your editor complete these
11
+ // keys and turns a typo into an error you see while writing. The import is TYPE-only: nothing is loaded at runtime,
12
+ // so the agent opens before `npm install` has run.
13
+ import type { AgentConfig } from "@fastagent-sh/fastagent";
16
14
 
17
15
  export default {
18
- // model: "openai-codex/gpt-5.5",
19
- // thinkingLevel: "high", // reasoning effort (off|minimal|low|medium|high|xhigh|max); default "medium" (pi TUI parity)
20
- // add `host: "127.0.0.1"` here to pin the bind address; default: `start` all interfaces (what containers
21
- // need), `dev` loopback. `cors: ["https://your-app.example.com"]` pins which origins a browser may call
22
- // this serve from. The default is `*` on every bind — any page your users visit can call this port and
23
- // read the reply, a loopback bind included (it stops another machine, not your own browser).
24
- // `invoke: false` withholds POST /invoke, for a serve meant to be reached only through its channels
25
- // (POST /run goes with it; `run: true` keeps that one for a scheduler of yours that calls routines by name).
26
- http: { port: 8787 },
27
- // sessionControl: true, // serve /control/* for remote observation + steering (a Web panel, a desktop app)
28
- // tools: [], // programmatically defined tools, appended after the coding ones — tools/ is the usual way
29
- // deploy: what the agent needs on the box (so `fastagent deploy` doesn't need a hand-written Dockerfile
30
- // or hand-set host variables). Uncomment as needed:
31
- // deploy: {
32
- // secrets: ["GH_TOKEN"], // extra secret env vars your tools use — deploy reads their values from .secrets/.env
33
- // apt: ["git"], // extra apt packages baked into the image (git, ripgrep, …; default repos only)
34
- // agentcore: { idleTimeoutSeconds: 180 }, // `deploy agentcore` only: idle microVM tail, 60–1209600s
35
- // },
36
- } satisfies FastagentConfig;
16
+ // model: "openai/gpt-5.5",
17
+ // thinkingLevel: "high", // reasoning effort (off|minimal|low|medium|high|xhigh|max)
18
+ http: {
19
+ port: 8787, // the port a serve listens on, for its channels' webhooks and its health check
20
+ // api: false, // serve no Agent API under /v1, whatever key the environment holds; deploy gives none a key
21
+ },
22
+ // The commands the agent needs (CLIs, runtimes, apt packages) live in context.json: `fastagent env add gh`.
23
+ // deploy: { agentcore: { idleTimeoutSeconds: 180 } }, // `deploy agentcore` only: idle microVM tail, 60–1209600s
24
+ } satisfies AgentConfig;
@@ -5,8 +5,15 @@
5
5
  # DIRECTORY, so a symlinked one (pnpm, a shared store) would show up as untracked.
6
6
  node_modules
7
7
 
8
- # machine state: sessions, channel state, schedule state
8
+ # generated from src/ every time the agent opens
9
+ .fastagent
10
+ # machine state: the agent's storage, channel state, schedule state
9
11
  .state
12
+ # where fastagent clones the agent's content (each clone is its repository's, not this one's). No trailing
13
+ # slash: on a deployed host it is a link itself.
14
+ /content
15
+ # the directories of this machine the agent is bound to: this machine's, never the agent's
16
+ /context.local.json
10
17
  .cache
11
18
 
12
19
  # fastagent reads the agent's env from .secrets/.env (which un-ignores its own .env.example). A bare
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: writing-great-skills
3
- description: Reference for writing and editing skills well — the vocabulary and principles that make a skill predictable.
4
- disable-model-invocation: true
3
+ description: Reference for writing and editing skills well — the vocabulary and principles that make a skill predictable. Read it before writing or changing a skill.
5
4
  ---
6
5
 
7
6
  A skill exists to wrangle determinism out of a stochastic system. **Predictability** — the agent taking the same _process_ every run, not producing the same output — is the root virtue; every lever below serves it.
@@ -2,10 +2,15 @@
2
2
  export declare const baseTemplate: (name: string) => string;
3
3
  /** Read one file from a channel's scaffold bundle (src/channels/<kind>/scaffold/<name>). */
4
4
  export declare const channelTemplate: (kind: string, name: string) => string;
5
- /** The .ts files in a channel's bundle: `channel.*` are the channel templates (one per ingress —
6
- * `channel.ts`, `channel.websocket.ts`); the rest are companion tools. */
5
+ /** The .ts files in a channel's bundle: `channel.ts` is the channel template; the rest are companion tools. */
7
6
  export declare const channelBundleFiles: (kind: string) => string[];
8
- /** package.json for the complete agent. */
9
- export declare function packageJson(name: string, version: string): string;
7
+ /**
8
+ * package.json for the complete agent: fastagent at this build's version, and the packages an agent's code is written
9
+ * against (its tools and extensions are pi-durable code, its providers pi-ai's) at the versions this build runs.
10
+ */
11
+ export declare function packageJson(name: string, build: {
12
+ version: string;
13
+ harness: Record<string, string>;
14
+ }): string;
10
15
  /** Sanitize a directory basename into a valid npm package name (lowercase, safe chars). */
11
16
  export declare function toPackageName(dir: string): string;
@@ -9,16 +9,18 @@ export const baseTemplate = (name) => readFileSync(new URL(`./templates/${name}`
9
9
  const channelScaffoldDir = (kind) => new URL(`../channels/${kind}/scaffold/`, import.meta.url);
10
10
  /** Read one file from a channel's scaffold bundle (src/channels/<kind>/scaffold/<name>). */
11
11
  export const channelTemplate = (kind, name) => readFileSync(new URL(name, channelScaffoldDir(kind)), "utf8");
12
- /** The .ts files in a channel's bundle: `channel.*` are the channel templates (one per ingress —
13
- * `channel.ts`, `channel.websocket.ts`); the rest are companion tools. */
12
+ /** The .ts files in a channel's bundle: `channel.ts` is the channel template; the rest are companion tools. */
14
13
  export const channelBundleFiles = (kind) => readdirSync(channelScaffoldDir(kind)).filter((f) => f.endsWith(".ts"));
15
- /** package.json for the complete agent. */
16
- export function packageJson(name, version) {
14
+ /**
15
+ * package.json for the complete agent: fastagent at this build's version, and the packages an agent's code is written
16
+ * against (its tools and extensions are pi-durable code, its providers pi-ai's) at the versions this build runs.
17
+ */
18
+ export function packageJson(name, build) {
17
19
  return `${JSON.stringify({
18
20
  name,
19
21
  private: true,
20
22
  type: "module",
21
- dependencies: { "@fastagent-sh/fastagent": `^${version}` },
23
+ dependencies: { "@fastagent-sh/fastagent": `^${build.version}`, ...build.harness },
22
24
  }, null, 2)}\n`;
23
25
  }
24
26
  /** Sanitize a directory basename into a valid npm package name (lowercase, safe chars). */
@@ -1,14 +1,11 @@
1
- import { type LoadedDefinition } from "../engines/pi/definition.ts";
2
1
  export interface VendoredSkill {
3
2
  /** The skill's real name (from SKILL.md frontmatter, per the Agent Skills spec). */
4
3
  name: string;
5
4
  description?: string;
6
- /** Workspace-relative destination (e.g. `skills/pdf`). */
5
+ /** Agent-dir-relative destination (e.g. `skills/pdf`). */
7
6
  dest: string;
8
7
  /** The skill ships a `scripts/` dir (executable code) — a trust signal for the caller. */
9
8
  hasScripts: boolean;
10
- /** Spec diagnostics for THIS skill from the runtime loader (e.g. name ≠ dir). */
11
- diagnostics: LoadedDefinition["diagnostics"];
12
9
  /** True when an existing skill was overwritten (--update); false for a fresh vendor. */
13
10
  overwritten: boolean;
14
11
  }
@@ -7,7 +7,7 @@ import { existsSync } from "node:fs";
7
7
  import { randomUUID } from "node:crypto";
8
8
  import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
9
9
  import { homedir } from "node:os";
10
- import { loadAgentDefinition } from "../engines/pi/definition.js";
10
+ import { readSkills } from "../harnesses/pi-durable/text.js";
11
11
  import { assertInsideAgentDir } from "../paths.js";
12
12
  /** Derive the destination skill name from a source ref: the last path segment, sans `#ref`. */
13
13
  function skillNameFromSource(source) {
@@ -131,17 +131,16 @@ export async function vendorSkill(agentDir, source, options = {}) {
131
131
  }
132
132
  if (overwritten)
133
133
  await rm(previous, { recursive: true, force: true });
134
- // Report via the runtime loader, matching THIS skill by EXACT directory (a substring match would prefix-pollute a
135
- // sibling `<name>-x` and break on Windows path separators).
136
- const def = await loadAgentDefinition(agentDir);
134
+ // Report via the loader the agent reads skills with, matching THIS skill by EXACT directory (a substring match
135
+ // would prefix-pollute a sibling `<name>-x` and break on Windows path separators). A skill it refuses is said by
136
+ // that loader, and is missing here.
137
137
  const rel = join("skills", name);
138
- const skill = def.skills.find((sk) => relative(agentDir, dirname(sk.filePath)) === rel);
138
+ const skill = readSkills(agentDir).find((sk) => relative(agentDir, dirname(sk.filePath)) === rel);
139
139
  return {
140
140
  name: skill?.name ?? name,
141
141
  description: skill?.description,
142
142
  dest: rel,
143
143
  hasScripts: existsSync(join(dest, "scripts")),
144
- diagnostics: def.diagnostics.filter((d) => d.path !== undefined && relative(agentDir, dirname(d.path)) === rel),
145
144
  overwritten,
146
145
  };
147
146
  }
@@ -9,3 +9,16 @@ export declare function nextRun(cron: string, tz: string | undefined, from: Date
9
9
  * constructing the Cron.
10
10
  */
11
11
  export declare function cronError(cron: string, tz: string | undefined): string | undefined;
12
+ /**
13
+ * Why `cron`/`tz` cannot be something that recurs here, or undefined if it can: THE guard every recurring producer
14
+ * shares (a `schedules/` file, a recurring `wake`), because the agent can write both, and one written wrong must not
15
+ * run turns back to back. Two consecutive instants must be at least {@link MIN_RECURRING_GAP_MS} apart, which also
16
+ * refuses croner's six-field, per-second form.
17
+ *
18
+ * A function of the expression alone, so a file's verdict never flips with the time it is read. Two consecutive
19
+ * instants under 10 minutes apart are on one day or across one midnight, and the time-of-day fields repeat every day,
20
+ * so two days of the time-of-day form (the day fields made `*`, in UTC) hold every such gap. That is conservative:
21
+ * `0,55 0,23 * * 1` is refused for the 23:55 → 00:00 pair, though Tuesday never fires. A DST change only lengthens a
22
+ * gap (croner fires a repeated hour once). A year field is refused, since what repeats every year does not need one.
23
+ */
24
+ export declare function recurringCronError(cron: string, tz: string | undefined): string | undefined;
@@ -29,3 +29,55 @@ export function cronError(cron, tz) {
29
29
  return e.message;
30
30
  }
31
31
  }
32
+ /** The minimum gap between two consecutive fires of anything recurring: a schedule, or a recurring wake-up. */
33
+ const MIN_RECURRING_GAP_MS = 10 * 60_000; // 10 minutes
34
+ /** Where the check below starts: fixed, so its verdict is the cron's and never the hour it was asked in. */
35
+ const ANCHOR = new Date("2024-01-01T00:00:00Z");
36
+ const TWO_DAYS_MS = 2 * 24 * 60 * 60_000;
37
+ /** One verdict per expression: the check walks up to ~300 instants, and every re-read of `schedules/` asks again. */
38
+ const verdicts = new Map();
39
+ /**
40
+ * Why `cron`/`tz` cannot be something that recurs here, or undefined if it can: THE guard every recurring producer
41
+ * shares (a `schedules/` file, a recurring `wake`), because the agent can write both, and one written wrong must not
42
+ * run turns back to back. Two consecutive instants must be at least {@link MIN_RECURRING_GAP_MS} apart, which also
43
+ * refuses croner's six-field, per-second form.
44
+ *
45
+ * A function of the expression alone, so a file's verdict never flips with the time it is read. Two consecutive
46
+ * instants under 10 minutes apart are on one day or across one midnight, and the time-of-day fields repeat every day,
47
+ * so two days of the time-of-day form (the day fields made `*`, in UTC) hold every such gap. That is conservative:
48
+ * `0,55 0,23 * * 1` is refused for the 23:55 → 00:00 pair, though Tuesday never fires. A DST change only lengthens a
49
+ * gap (croner fires a repeated hour once). A year field is refused, since what repeats every year does not need one.
50
+ */
51
+ export function recurringCronError(cron, tz) {
52
+ const key = `${cron}\u0000${tz ?? ""}`;
53
+ if (!verdicts.has(key))
54
+ verdicts.set(key, judge(cron, tz));
55
+ return verdicts.get(key);
56
+ }
57
+ function judge(cron, tz) {
58
+ const invalid = cronError(cron, tz);
59
+ if (invalid)
60
+ return `invalid cron/tz: ${invalid}`;
61
+ const fields = cron.trim().split(/\s+/);
62
+ if (fields.length === 7)
63
+ return "a year field is not allowed: a recurring cron repeats every year";
64
+ const first = nextRun(cron, tz, ANCHOR);
65
+ if (!first || !nextRun(cron, tz, first))
66
+ return "this cron never fires, or fires only once";
67
+ // A nickname (`@hourly`) has no fields to separate, and is walked as it is.
68
+ const timeOfDay = fields.length === 5
69
+ ? `${fields[0]} ${fields[1]} * * *`
70
+ : fields.length === 6
71
+ ? `${fields[0]} ${fields[1]} ${fields[2]} * * *`
72
+ : cron;
73
+ const clock = new Cron(timeOfDay, { timezone: "UTC" });
74
+ const end = ANCHOR.getTime() + TWO_DAYS_MS;
75
+ for (let at = clock.nextRun(ANCHOR); at && at.getTime() < end;) {
76
+ const next = clock.nextRun(at);
77
+ if (next && next.getTime() - at.getTime() < MIN_RECURRING_GAP_MS) {
78
+ return `too frequent — it must fire at most every ${MIN_RECURRING_GAP_MS / 60_000} minutes`;
79
+ }
80
+ at = next;
81
+ }
82
+ return undefined;
83
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A schedule's cron in EventBridge Scheduler's dialect: `cron(m h dom mon dow year)`, Quartz-flavoured, with exactly
3
+ * one of the two day fields `?` and 1 = Sunday. AgentCore fires each schedule from a recurring EventBridge schedule
4
+ * the container sets (schedule/wake-alarm.ts), so a schedule must translate to be one at all: discovery refuses one
5
+ * that does not, on every host, so that what runs locally also runs there.
6
+ */
7
+ /**
8
+ * Translate a 5-field cron into EventBridge Scheduler's `cron(m h dom mon dow *)`, or say why it can't be. The two
9
+ * fire on the same instants in the same zone, with one exception at a DST change: a local time the spring change
10
+ * removes (02:30 in most of the US on that day) is skipped by EventBridge and run an hour later by croner, so such a
11
+ * schedule runs once more a year on a resident host. A time the autumn change repeats runs once in both.
12
+ */
13
+ export declare function toEventBridgeCron(cron: string): {
14
+ expression: string;
15
+ } | {
16
+ error: string;
17
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * A schedule's cron in EventBridge Scheduler's dialect: `cron(m h dom mon dow year)`, Quartz-flavoured, with exactly
3
+ * one of the two day fields `?` and 1 = Sunday. AgentCore fires each schedule from a recurring EventBridge schedule
4
+ * the container sets (schedule/wake-alarm.ts), so a schedule must translate to be one at all: discovery refuses one
5
+ * that does not, on every host, so that what runs locally also runs there.
6
+ */
7
+ /**
8
+ * Remap ONE day-of-week field from standard cron numbering (0–7, 0 and 7 = Sunday) to EventBridge's (1–7,
9
+ * 1 = Sunday). Numeric items are EXPANDED to the days they select and written back as a list: endpoint-wise remapping
10
+ * cannot be right, since Sunday sits at both ends of one numbering and at the start of the other (`0-7` is every day,
11
+ * and remapping its endpoints gives `1-1`, Sundays only; `5-7` would wrap). Names mean the same day in both dialects
12
+ * and pass through.
13
+ */
14
+ function mapDowField(dow) {
15
+ const days = new Set();
16
+ const named = [];
17
+ for (const item of dow.split(",")) {
18
+ const slash = item.split("/");
19
+ if (slash.length > 2 || slash.some((part) => part === "")) {
20
+ return { error: `malformed day-of-week token "${item}"` };
21
+ }
22
+ const [body, stepText] = slash;
23
+ if (stepText !== undefined && !/^\d+$/.test(stepText))
24
+ return { error: `malformed day-of-week step "${item}"` };
25
+ const endpoints = body === "*" ? ["0", "6"] : body.split("-");
26
+ if (endpoints.length > 2 || endpoints.some((part) => part === "")) {
27
+ return { error: `malformed day-of-week token "${item}"` };
28
+ }
29
+ if (endpoints.every((part) => !/^\d+$/.test(part))) {
30
+ named.push(item);
31
+ continue;
32
+ }
33
+ if (!endpoints.every((part) => /^\d+$/.test(part))) {
34
+ return { error: `day-of-week "${item}" mixes a name and a number` };
35
+ }
36
+ const from = Number(endpoints[0]);
37
+ // A single value with a step (`1/2`) runs to the end of the week, as in croner.
38
+ const to = endpoints.length === 2 ? Number(endpoints[1]) : stepText !== undefined ? 7 : from;
39
+ const step = stepText !== undefined ? Number(stepText) : 1;
40
+ if (from > 7 || to > 7 || from > to || step === 0)
41
+ return { error: `malformed day-of-week token "${item}"` };
42
+ for (let day = from; day <= to; day += step)
43
+ days.add(day % 7);
44
+ }
45
+ const numbers = [...days].map((day) => day + 1).sort((x, y) => x - y);
46
+ // Consecutive days back into ranges, for a readable expression.
47
+ const runs = [];
48
+ for (let i = 0; i < numbers.length;) {
49
+ let j = i;
50
+ while (j + 1 < numbers.length && numbers[j + 1] === numbers[j] + 1)
51
+ j++;
52
+ runs.push(j > i ? `${numbers[i]}-${numbers[j]}` : `${numbers[i]}`);
53
+ i = j + 1;
54
+ }
55
+ return { value: [...runs, ...named].join(",") };
56
+ }
57
+ /**
58
+ * Translate a 5-field cron into EventBridge Scheduler's `cron(m h dom mon dow *)`, or say why it can't be. The two
59
+ * fire on the same instants in the same zone, with one exception at a DST change: a local time the spring change
60
+ * removes (02:30 in most of the US on that day) is skipped by EventBridge and run an hour later by croner, so such a
61
+ * schedule runs once more a year on a resident host. A time the autumn change repeats runs once in both.
62
+ */
63
+ export function toEventBridgeCron(cron) {
64
+ const fields = cron.trim().split(/\s+/);
65
+ if (fields.length !== 5) {
66
+ return { error: `EventBridge supports 5-field cron only (got ${fields.length} fields)` };
67
+ }
68
+ const [min, hour, dom, mon, dow] = fields;
69
+ if (/[L#]/i.test(dow) || /[L#]/i.test(dom)) {
70
+ return { error: "L/# day forms don't translate to EventBridge numbering — set this schedule up manually" };
71
+ }
72
+ // `?` FIRST, and not as a synonym for `*`.
73
+ if (dom === "?" || dow === "?") {
74
+ return { expression: `cron(${min} ${hour} * ${mon} ? *)` };
75
+ }
76
+ if (dom !== "*" && dow !== "*") {
77
+ return {
78
+ error: "restricting BOTH day-of-month and day-of-week (cron OR semantics) is not expressible in EventBridge",
79
+ };
80
+ }
81
+ if (dow === "*") {
82
+ return { expression: `cron(${min} ${hour} ${dom} ${mon} ? *)` };
83
+ }
84
+ const mapped = mapDowField(dow);
85
+ if ("error" in mapped)
86
+ return mapped;
87
+ return { expression: `cron(${min} ${hour} ? ${mon} ${mapped.value} *)` };
88
+ }
@@ -0,0 +1,23 @@
1
+ /** As many schedules as one conversation may have pending wake-ups: the same bound on what the agent can set going. */
2
+ export declare const MAX_SCHEDULES = 20;
3
+ /** What an author writes. */
4
+ export interface ScheduleConfig {
5
+ /** Five fields, minute first; checked when the definition is built. */
6
+ cron: string;
7
+ /** IANA timezone. Default: UTC. */
8
+ tz?: string;
9
+ /** What the agent is told when it fires: a text, or one made for the instant it fires for. */
10
+ prompt: string | ((fire: {
11
+ at: Date;
12
+ }) => string | Promise<string>);
13
+ }
14
+ /** A schedule as built: its name is its file's name. */
15
+ export interface Schedule extends ScheduleConfig {
16
+ name: string;
17
+ }
18
+ /**
19
+ * Why `config` is not a schedule this agent can run, or undefined: the one rule the build applies. Its cron passes the
20
+ * guard a recurring wake-up passes, and is one AgentCore's clock (EventBridge) can express, so a schedule that runs
21
+ * locally also runs there.
22
+ */
23
+ export declare function scheduleConfigProblem(config: ScheduleConfig): string | undefined;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A schedule: a prompt the definition runs on a cron, written in TypeScript as `defineSchedule` in `src/schedules/`
3
+ * (architecture.md §2), its name its file's. It is code, so it changes with a build and a deployment; the clock that
4
+ * fires it is scheduler.ts, or on AgentCore the recurring EventBridge schedule the container sets (wake-alarm.ts).
5
+ *
6
+ * WHAT IT IS NOT: a wake-up. The agent can schedule work for itself too (the `wake` tool, schedule/wakeups.ts). A
7
+ * schedule is written in the DEFINITION and a wake-up into the STATE by a running agent (minted id, cancellable, aimed
8
+ * back at the conversation it came from).
9
+ */
10
+ import { recurringCronError } from "./cron.js";
11
+ import { toEventBridgeCron } from "./eventbridge-cron.js";
12
+ import { MAX_PENDING_WAKEUPS } from "./wakeups.js";
13
+ /** As many schedules as one conversation may have pending wake-ups: the same bound on what the agent can set going. */
14
+ export const MAX_SCHEDULES = MAX_PENDING_WAKEUPS;
15
+ /**
16
+ * Why `config` is not a schedule this agent can run, or undefined: the one rule the build applies. Its cron passes the
17
+ * guard a recurring wake-up passes, and is one AgentCore's clock (EventBridge) can express, so a schedule that runs
18
+ * locally also runs there.
19
+ */
20
+ export function scheduleConfigProblem(config) {
21
+ if (typeof config.prompt !== "string" && typeof config.prompt !== "function")
22
+ return "its prompt is a text or a function";
23
+ if (config.prompt === "")
24
+ return "its prompt is empty";
25
+ if (typeof config.cron !== "string")
26
+ return "its cron is a text";
27
+ const invalid = recurringCronError(config.cron, config.tz);
28
+ if (invalid !== undefined)
29
+ return invalid;
30
+ const translated = toEventBridgeCron(config.cron);
31
+ return "error" in translated
32
+ ? `AgentCore's clock (EventBridge) cannot express this cron: ${translated.error}`
33
+ : undefined;
34
+ }
@@ -1,44 +1,32 @@
1
1
  import * as Effect from "effect/Effect";
2
- import { type Agent } from "../agent.ts";
2
+ import { type Agent } from "../agent-api.ts";
3
3
  import { PortFailure } from "../effect-port.ts";
4
- import { type LoadedRoutine } from "./routine.ts";
4
+ import type { Schedule } from "./schedule.ts";
5
5
  export interface Scheduler {
6
- /** Arm routines, account for a fire the previous run was killed in, and catch up overdue work once. */
6
+ /** Arm schedules, account for a fire the previous run was killed in, and catch up overdue work once. */
7
7
  start(): void;
8
8
  /** Cancel pending waits. */
9
9
  stop(): void;
10
10
  }
11
+ /** All the scheduler asks of the agent. */
12
+ export type ScheduledAgent = {
13
+ sessions: Pick<Agent["sessions"], "get" | "create">;
14
+ messages: Pick<Agent["messages"], "send" | "get">;
15
+ };
11
16
  export interface SchedulerOptions {
12
- agent: Agent;
17
+ agent: ScheduledAgent;
13
18
  stateRoot: string;
14
- /** Every routine this serve loaded. Only the ones WITH a cron are armed — the rest are reached by name. */
15
- routines: LoadedRoutine[];
19
+ /** The definition's schedules. */
20
+ schedules: readonly Schedule[];
21
+ /**
22
+ * Run a resident timer per schedule (default). Off where something outside the process delivers each instant as
23
+ * its own fire (AgentCore's recurring EventBridge schedules): one path per instant, so its delivery's reply says
24
+ * whether it ran.
25
+ */
26
+ localClock?: boolean;
16
27
  /** Override wall-clock dates; elapsed time and waits use the Effect clock. */
17
28
  now?: () => Date;
18
- /** External slot delivery owns cron timers and catch-up; local wake polling still runs. */
19
- externalClock?: boolean;
20
29
  }
21
- /**
22
- * The iterator is a Promise port inside an uninterruptible claimed occurrence, including its cleanup.
23
- *
24
- * WHAT THE TURN SAID IS NOT LOGGED. It is already durable: every fire runs in the session named in the line below
25
- * (`routine:<name>` for a cron, the asking conversation for a wake-up), and a session is persisted under
26
- * EXPORTED for the API path (`POST /run`), which runs the same turn without a claim: it has no occurrence to
27
- * claim, because nobody's grid produced it (schedule/run.ts). The resident clock's own claim/run/settle is
28
- * {@link fireRoutineOnce}.
29
- *
30
- * `<stateRoot>/sessions/` like any other. Copying the reply into the log would be a second store of the same text,
31
- * unstructured, in a stream with a wider audience and a bound that differs per host.
32
- */
33
- export declare function runTurn(agent: Agent, label: string, session: string, prompt: string): Effect.Effect<{
34
- busy: boolean;
35
- failed: string | undefined;
36
- ms: number;
37
- } | {
38
- busy: boolean;
39
- failed: string;
40
- ms: number;
41
- }, never, never>;
42
30
  export interface ScheduleFireOutcome {
43
31
  fired: boolean;
44
32
  /** A delivery whose slot was already claimed, or which is older than the newest claim (a stale replay). */
@@ -47,18 +35,31 @@ export interface ScheduleFireOutcome {
47
35
  /**
48
36
  * The occurrence was claimed but the turn was refused because the previous one is still running — the overlap
49
37
  * policy, not a fault. Reported apart from `failed` because an operator reacts to the two differently, and a
50
- * clock that reads `failed` on a public route would be reading an error that is not one.
38
+ * clock that reads `failed` would be reading an error that is not one.
51
39
  */
52
40
  skipped?: true;
53
41
  ms: number;
54
42
  }
55
43
  /** Shared resident/external claim → run → settle. */
56
- export declare function fireRoutineOnce(opts: {
57
- agent: Agent;
44
+ export declare function fireScheduleOnce(opts: {
45
+ agent: ScheduledAgent;
58
46
  stateRoot: string;
59
- routine: LoadedRoutine;
47
+ schedule: Schedule;
60
48
  /** The instant this fire is FOR. Two schedulers agree on it, which is what makes the claim exclude. */
61
49
  slot: Date;
62
50
  now?: () => Date;
63
51
  }): Effect.Effect<ScheduleFireOutcome, PortFailure>;
52
+ /**
53
+ * Fire `schedule` once, now, outside its clock (`fastagent schedules run`), the way its clock would: a newest claim no
54
+ * fire reported is accounted for first, as a boot does, then this instant is the slot, claimed and settled as any.
55
+ */
56
+ export declare function fireScheduleNow(opts: {
57
+ agent: ScheduledAgent;
58
+ stateRoot: string;
59
+ schedule: Schedule;
60
+ }): Effect.Effect<ScheduleFireOutcome & {
61
+ slot: Date;
62
+ }, PortFailure>;
63
+ /** Which session each schedule continues: one per schedule, so the agent sees what its earlier runs did. */
64
+ export declare function scheduleSessions(stateRoot: string): import("../conversation-sessions.ts").ConversationSessions;
64
65
  export declare function createScheduler(options: SchedulerOptions): Effect.Effect<Scheduler>;