@fastagent-sh/fastagent 0.24.4 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (487) hide show
  1. package/README.md +54 -82
  2. package/dist/agent-api.d.ts +460 -0
  3. package/dist/agent-api.js +209 -0
  4. package/dist/answer-text.d.ts +8 -0
  5. package/dist/answer-text.js +18 -0
  6. package/dist/atomic-write.d.ts +2 -2
  7. package/dist/atomic-write.js +2 -2
  8. package/dist/authoring.d.ts +81 -0
  9. package/dist/authoring.js +245 -0
  10. package/dist/channel.d.ts +29 -15
  11. package/dist/channel.js +4 -1
  12. package/dist/channels/agentcore-protocol.d.ts +36 -50
  13. package/dist/channels/agentcore-protocol.js +3 -3
  14. package/dist/channels/agentcore-service.d.ts +8 -18
  15. package/dist/channels/agentcore-service.js +108 -127
  16. package/dist/channels/agentcore.d.ts +8 -24
  17. package/dist/channels/agentcore.js +32 -65
  18. package/dist/channels/body.d.ts +0 -16
  19. package/dist/channels/body.js +0 -25
  20. package/dist/channels/busy.js +6 -1
  21. package/dist/channels/context.d.ts +4 -0
  22. package/dist/channels/context.js +35 -0
  23. package/dist/channels/discover.d.ts +18 -20
  24. package/dist/channels/discover.js +41 -99
  25. package/dist/channels/feishu/feishu-api.d.ts +54 -4
  26. package/dist/channels/feishu/feishu-api.js +192 -149
  27. package/dist/channels/feishu/feishu.d.ts +3 -0
  28. package/dist/channels/feishu/feishu.js +117 -106
  29. package/dist/channels/feishu/history.d.ts +55 -0
  30. package/dist/channels/feishu/history.js +199 -0
  31. package/dist/channels/feishu/invoke-turn.d.ts +13 -11
  32. package/dist/channels/feishu/invoke-turn.js +9 -10
  33. package/dist/channels/feishu/model.d.ts +2 -1
  34. package/dist/channels/feishu/normalize.js +100 -0
  35. package/dist/channels/feishu/preview.d.ts +2 -2
  36. package/dist/channels/feishu/register-webhook.d.ts +1 -0
  37. package/dist/channels/feishu/register-webhook.js +3 -2
  38. package/dist/channels/feishu/scaffold/channel.ts +65 -46
  39. package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
  40. package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
  41. package/dist/channels/feishu/setup-mode.d.ts +45 -25
  42. package/dist/channels/feishu/setup-mode.js +74 -23
  43. package/dist/channels/feishu/shared-api.d.ts +24 -6
  44. package/dist/channels/feishu/shared-api.js +30 -24
  45. package/dist/channels/kit/context-buffer.d.ts +11 -2
  46. package/dist/channels/kit/context-buffer.js +7 -4
  47. package/dist/channels/kit/delivery.d.ts +19 -3
  48. package/dist/channels/kit/delivery.js +74 -15
  49. package/dist/channels/kit/event-stream.js +2 -1
  50. package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
  51. package/dist/channels/kit/invoke-turn-kit.js +62 -71
  52. package/dist/channels/kit/place-history.d.ts +107 -0
  53. package/dist/channels/kit/place-history.js +182 -0
  54. package/dist/channels/kit/preview-kit.d.ts +9 -5
  55. package/dist/channels/kit/preview-kit.js +36 -15
  56. package/dist/channels/kit/room-threads.d.ts +46 -0
  57. package/dist/channels/kit/room-threads.js +81 -0
  58. package/dist/channels/kit/seen.js +1 -1
  59. package/dist/channels/kit/stop-command.d.ts +6 -3
  60. package/dist/channels/kit/stop-command.js +20 -18
  61. package/dist/channels/kit/thread-fork.d.ts +17 -0
  62. package/dist/channels/kit/thread-fork.js +43 -0
  63. package/dist/channels/kit/thread-participants.js +1 -1
  64. package/dist/channels/kit/transport.d.ts +5 -0
  65. package/dist/channels/kit/transport.js +5 -0
  66. package/dist/channels/kit/turn-runner.d.ts +10 -9
  67. package/dist/channels/kit/turn-runner.js +17 -19
  68. package/dist/channels/kit/turn-store.d.ts +5 -4
  69. package/dist/channels/kit/turn-store.js +5 -5
  70. package/dist/channels/lark/lark.d.ts +3 -0
  71. package/dist/channels/lark/lark.js +5 -0
  72. package/dist/channels/lark/onboard.d.ts +5 -3
  73. package/dist/channels/lark/onboard.js +14 -14
  74. package/dist/channels/lark/scaffold/channel.ts +67 -44
  75. package/dist/channels/lark/scaffold/lark-send.ts +38 -33
  76. package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
  77. package/dist/channels/respond.d.ts +0 -4
  78. package/dist/channels/respond.js +1 -1
  79. package/dist/channels/router.d.ts +18 -0
  80. package/dist/channels/router.js +68 -0
  81. package/dist/channels/serve.d.ts +5 -70
  82. package/dist/channels/serve.js +105 -287
  83. package/dist/channels/slack/history.d.ts +42 -0
  84. package/dist/channels/slack/history.js +282 -0
  85. package/dist/channels/slack/invoke-turn.d.ts +12 -5
  86. package/dist/channels/slack/invoke-turn.js +7 -5
  87. package/dist/channels/slack/manifest.d.ts +1 -4
  88. package/dist/channels/slack/manifest.js +22 -10
  89. package/dist/channels/slack/model.d.ts +2 -1
  90. package/dist/channels/slack/onboard.d.ts +0 -2
  91. package/dist/channels/slack/onboard.js +2 -4
  92. package/dist/channels/slack/onboarding-state.d.ts +0 -2
  93. package/dist/channels/slack/onboarding-state.js +0 -1
  94. package/dist/channels/slack/parse.d.ts +0 -5
  95. package/dist/channels/slack/parse.js +1 -16
  96. package/dist/channels/slack/preview.d.ts +2 -3
  97. package/dist/channels/slack/preview.js +78 -52
  98. package/dist/channels/slack/register-webhook.d.ts +1 -0
  99. package/dist/channels/slack/register-webhook.js +6 -5
  100. package/dist/channels/slack/scaffold/channel.ts +23 -24
  101. package/dist/channels/slack/scaffold/slack-send.ts +50 -43
  102. package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
  103. package/dist/channels/slack/setup-server.d.ts +19 -0
  104. package/dist/channels/slack/setup-server.js +113 -11
  105. package/dist/channels/slack/shared-api.d.ts +15 -4
  106. package/dist/channels/slack/shared-api.js +19 -14
  107. package/dist/channels/slack/slack-api.d.ts +61 -2
  108. package/dist/channels/slack/slack-api.js +28 -5
  109. package/dist/channels/slack/slack.js +97 -52
  110. package/dist/channels/slack/welcomed.js +1 -1
  111. package/dist/channels/telegram/context-buffer.d.ts +6 -1
  112. package/dist/channels/telegram/context-buffer.js +19 -0
  113. package/dist/channels/telegram/invoke-turn.d.ts +8 -4
  114. package/dist/channels/telegram/invoke-turn.js +7 -7
  115. package/dist/channels/telegram/parse.d.ts +7 -2
  116. package/dist/channels/telegram/parse.js +7 -0
  117. package/dist/channels/telegram/preview.d.ts +2 -2
  118. package/dist/channels/telegram/register-webhook.d.ts +1 -0
  119. package/dist/channels/telegram/register-webhook.js +3 -2
  120. package/dist/channels/telegram/scaffold/channel.ts +27 -28
  121. package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
  122. package/dist/channels/telegram/shared-api.d.ts +34 -0
  123. package/dist/channels/telegram/shared-api.js +79 -0
  124. package/dist/channels/telegram/telegram-api.d.ts +15 -5
  125. package/dist/channels/telegram/telegram-api.js +10 -6
  126. package/dist/channels/telegram/telegram.js +27 -21
  127. package/dist/channels/telegram/turn-store.js +1 -1
  128. package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
  129. package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
  130. package/dist/cli/add-feishu.d.ts +42 -12
  131. package/dist/cli/add-feishu.js +177 -124
  132. package/dist/cli/add-slack.d.ts +8 -3
  133. package/dist/cli/add-slack.js +116 -64
  134. package/dist/cli/auth-view.d.ts +10 -3
  135. package/dist/cli/auth-view.js +8 -6
  136. package/dist/cli/box-login.d.ts +18 -7
  137. package/dist/cli/box-login.js +46 -12
  138. package/dist/cli/commands/add.d.ts +15 -4
  139. package/dist/cli/commands/add.js +253 -143
  140. package/dist/cli/commands/auth.d.ts +6 -0
  141. package/dist/cli/commands/auth.js +50 -0
  142. package/dist/cli/commands/content.d.ts +6 -0
  143. package/dist/cli/commands/content.js +45 -0
  144. package/dist/cli/commands/deploy/agentcore.js +50 -77
  145. package/dist/cli/commands/deploy/docker.js +38 -39
  146. package/dist/cli/commands/deploy/fly.js +21 -18
  147. package/dist/cli/commands/deploy/host-login.d.ts +26 -0
  148. package/dist/cli/commands/deploy/host-login.js +90 -0
  149. package/dist/cli/commands/deploy/railway.js +21 -26
  150. package/dist/cli/commands/deploy/shared.d.ts +45 -17
  151. package/dist/cli/commands/deploy/shared.js +34 -15
  152. package/dist/cli/commands/deploy.d.ts +0 -4
  153. package/dist/cli/commands/deploy.js +237 -50
  154. package/dist/cli/commands/destroy.js +8 -6
  155. package/dist/cli/commands/dev.d.ts +0 -2
  156. package/dist/cli/commands/dev.js +20 -19
  157. package/dist/cli/commands/env.d.ts +12 -0
  158. package/dist/cli/commands/env.js +191 -0
  159. package/dist/cli/commands/info.js +95 -156
  160. package/dist/cli/commands/init.d.ts +2 -2
  161. package/dist/cli/commands/init.js +35 -33
  162. package/dist/cli/commands/invoke.d.ts +6 -0
  163. package/dist/cli/commands/invoke.js +132 -16
  164. package/dist/cli/commands/login.d.ts +31 -2
  165. package/dist/cli/commands/login.js +416 -65
  166. package/dist/cli/commands/logout.d.ts +4 -0
  167. package/dist/cli/commands/logout.js +53 -0
  168. package/dist/cli/commands/logs.js +8 -6
  169. package/dist/cli/commands/models.d.ts +2 -1
  170. package/dist/cli/commands/models.js +39 -37
  171. package/dist/cli/commands/schedules.d.ts +21 -0
  172. package/dist/cli/commands/schedules.js +143 -0
  173. package/dist/cli/commands/start.d.ts +11 -10
  174. package/dist/cli/commands/start.js +35 -62
  175. package/dist/cli/content-view.d.ts +9 -0
  176. package/dist/cli/content-view.js +26 -0
  177. package/dist/cli/fail.d.ts +9 -12
  178. package/dist/cli/fail.js +17 -14
  179. package/dist/cli/invoke-stream.d.ts +12 -3
  180. package/dist/cli/invoke-stream.js +85 -23
  181. package/dist/cli/kernel.d.ts +9 -2
  182. package/dist/cli/kernel.js +15 -6
  183. package/dist/cli/login-relay.d.ts +6 -4
  184. package/dist/cli/login-relay.js +19 -7
  185. package/dist/cli/models-view.d.ts +5 -1
  186. package/dist/cli/models-view.js +1 -1
  187. package/dist/cli/person.d.ts +10 -0
  188. package/dist/cli/person.js +23 -0
  189. package/dist/cli/program.js +421 -203
  190. package/dist/cli/serve.d.ts +13 -63
  191. package/dist/cli/serve.js +31 -121
  192. package/dist/cli/shared.d.ts +21 -48
  193. package/dist/cli/shared.js +70 -89
  194. package/dist/cli/ticket.d.ts +136 -0
  195. package/dist/cli/ticket.js +476 -0
  196. package/dist/client.d.ts +7 -0
  197. package/dist/client.js +2 -0
  198. package/dist/content/declare.d.ts +70 -0
  199. package/dist/content/declare.js +163 -0
  200. package/dist/content/file.d.ts +32 -0
  201. package/dist/content/file.js +119 -0
  202. package/dist/content/git.d.ts +41 -0
  203. package/dist/content/git.js +220 -0
  204. package/dist/content/mount.d.ts +2 -0
  205. package/dist/content/mount.js +15 -0
  206. package/dist/content/resolve.d.ts +52 -0
  207. package/dist/content/resolve.js +151 -0
  208. package/dist/content/source.d.ts +27 -0
  209. package/dist/content/source.js +53 -0
  210. package/dist/conversation-sessions.d.ts +26 -0
  211. package/dist/conversation-sessions.js +99 -0
  212. package/dist/declared-secrets.d.ts +19 -37
  213. package/dist/declared-secrets.js +16 -58
  214. package/dist/deploy/agentcore/destroy.d.ts +3 -3
  215. package/dist/deploy/agentcore/destroy.js +46 -28
  216. package/dist/deploy/agentcore/forwarder.js +105 -22
  217. package/dist/deploy/agentcore/logs.js +1 -1
  218. package/dist/deploy/agentcore/plan.d.ts +10 -24
  219. package/dist/deploy/agentcore/plan.js +31 -135
  220. package/dist/deploy/agentcore/run.d.ts +1 -1
  221. package/dist/deploy/agentcore/run.js +8 -5
  222. package/dist/deploy/agentcore/shell.d.ts +1 -1
  223. package/dist/deploy/agentcore/shell.js +5 -5
  224. package/dist/deploy/api.d.ts +34 -0
  225. package/dist/deploy/api.js +50 -0
  226. package/dist/deploy/box-shell.d.ts +6 -0
  227. package/dist/deploy/box-shell.js +7 -0
  228. package/dist/deploy/build-context.d.ts +7 -5
  229. package/dist/deploy/build-context.js +41 -35
  230. package/dist/deploy/channel-ingress.d.ts +6 -1
  231. package/dist/deploy/channel-ingress.js +18 -5
  232. package/dist/deploy/container.d.ts +22 -9
  233. package/dist/deploy/container.js +96 -55
  234. package/dist/deploy/docker/plan.d.ts +3 -2
  235. package/dist/deploy/docker/plan.js +13 -14
  236. package/dist/deploy/docker/run.d.ts +2 -2
  237. package/dist/deploy/docker/run.js +8 -4
  238. package/dist/deploy/fly/plan.d.ts +1 -1
  239. package/dist/deploy/fly/plan.js +12 -21
  240. package/dist/deploy/fly/run.d.ts +10 -6
  241. package/dist/deploy/fly/run.js +11 -6
  242. package/dist/deploy/hosts.d.ts +2 -1
  243. package/dist/deploy/hosts.js +2 -1
  244. package/dist/deploy/preflight.d.ts +21 -23
  245. package/dist/deploy/preflight.js +223 -202
  246. package/dist/deploy/railway/plan.d.ts +8 -6
  247. package/dist/deploy/railway/plan.js +15 -58
  248. package/dist/deploy/railway/run.d.ts +8 -3
  249. package/dist/deploy/railway/run.js +12 -8
  250. package/dist/deploy/residency.d.ts +5 -11
  251. package/dist/deploy/residency.js +0 -6
  252. package/dist/deploy/runner.d.ts +1 -1
  253. package/dist/deploy/runner.js +1 -1
  254. package/dist/deploy/secrets.d.ts +16 -2
  255. package/dist/deploy/secrets.js +33 -6
  256. package/dist/deploy/workspace.d.ts +11 -6
  257. package/dist/deploy/workspace.js +55 -38
  258. package/dist/dev-supervisor.d.ts +11 -2
  259. package/dist/dev-supervisor.js +52 -27
  260. package/dist/effect-port.d.ts +4 -4
  261. package/dist/effect-port.js +4 -4
  262. package/dist/env.d.ts +0 -13
  263. package/dist/env.js +1 -44
  264. package/dist/environment/apt.d.ts +4 -0
  265. package/dist/environment/apt.js +32 -0
  266. package/dist/environment/declare.d.ts +59 -0
  267. package/dist/environment/declare.js +210 -0
  268. package/dist/environment/mise.d.ts +51 -0
  269. package/dist/environment/mise.js +272 -0
  270. package/dist/feishu.d.ts +2 -2
  271. package/dist/feishu.js +2 -2
  272. package/dist/git.d.ts +13 -0
  273. package/dist/git.js +55 -0
  274. package/dist/harnesses/models/catalog.d.ts +20 -0
  275. package/dist/harnesses/models/catalog.js +254 -0
  276. package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
  277. package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
  278. package/dist/harnesses/models/environment.d.ts +48 -0
  279. package/dist/harnesses/models/environment.js +88 -0
  280. package/dist/harnesses/models/host.d.ts +30 -0
  281. package/dist/harnesses/models/host.js +97 -0
  282. package/dist/{engines/pi → harnesses/models}/login.d.ts +66 -70
  283. package/dist/harnesses/models/login.js +439 -0
  284. package/dist/harnesses/models/models.d.ts +84 -0
  285. package/dist/harnesses/models/models.js +197 -0
  286. package/dist/harnesses/pi-durable/agent.d.ts +42 -0
  287. package/dist/harnesses/pi-durable/agent.js +581 -0
  288. package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
  289. package/dist/harnesses/pi-durable/defaults.js +26 -0
  290. package/dist/harnesses/pi-durable/define.d.ts +77 -0
  291. package/dist/harnesses/pi-durable/define.js +28 -0
  292. package/dist/harnesses/pi-durable/entries.d.ts +32 -0
  293. package/dist/harnesses/pi-durable/entries.js +126 -0
  294. package/dist/harnesses/pi-durable/events.d.ts +25 -0
  295. package/dist/harnesses/pi-durable/events.js +238 -0
  296. package/dist/harnesses/pi-durable/ids.d.ts +16 -0
  297. package/dist/harnesses/pi-durable/ids.js +55 -0
  298. package/dist/harnesses/pi-durable/messages.d.ts +41 -0
  299. package/dist/harnesses/pi-durable/messages.js +116 -0
  300. package/dist/harnesses/pi-durable/open.d.ts +95 -0
  301. package/dist/harnesses/pi-durable/open.js +330 -0
  302. package/dist/harnesses/pi-durable/reads.d.ts +30 -0
  303. package/dist/harnesses/pi-durable/reads.js +94 -0
  304. package/dist/harnesses/pi-durable/registry.d.ts +18 -0
  305. package/dist/harnesses/pi-durable/registry.js +56 -0
  306. package/dist/harnesses/pi-durable/release.d.ts +13 -0
  307. package/dist/harnesses/pi-durable/release.js +40 -0
  308. package/dist/harnesses/pi-durable/serve.d.ts +90 -0
  309. package/dist/harnesses/pi-durable/serve.js +186 -0
  310. package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
  311. package/dist/harnesses/pi-durable/sessions.js +47 -0
  312. package/dist/harnesses/pi-durable/storage.d.ts +4 -0
  313. package/dist/harnesses/pi-durable/storage.js +49 -0
  314. package/dist/harnesses/pi-durable/stream.d.ts +20 -0
  315. package/dist/harnesses/pi-durable/stream.js +221 -0
  316. package/dist/harnesses/pi-durable/text.d.ts +30 -0
  317. package/dist/harnesses/pi-durable/text.js +292 -0
  318. package/dist/harnesses/pi-durable/wake.d.ts +11 -0
  319. package/dist/harnesses/pi-durable/wake.js +90 -0
  320. package/dist/http/client.d.ts +6 -0
  321. package/dist/http/client.js +256 -0
  322. package/dist/http/contract.d.ts +541 -0
  323. package/dist/http/contract.js +179 -0
  324. package/dist/http/server.d.ts +34 -0
  325. package/dist/http/server.js +194 -0
  326. package/dist/index.d.ts +19 -4
  327. package/dist/index.js +13 -5
  328. package/dist/lark.d.ts +2 -2
  329. package/dist/lark.js +2 -2
  330. package/dist/locked-file.d.ts +17 -0
  331. package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
  332. package/dist/once.d.ts +6 -0
  333. package/dist/once.js +23 -0
  334. package/dist/paths.d.ts +36 -52
  335. package/dist/paths.js +66 -182
  336. package/dist/runtime.d.ts +25 -2
  337. package/dist/runtime.js +27 -0
  338. package/dist/scaffold/add-channel.d.ts +14 -27
  339. package/dist/scaffold/add-channel.js +82 -180
  340. package/dist/scaffold/init.d.ts +17 -18
  341. package/dist/scaffold/init.js +87 -99
  342. package/dist/scaffold/templates/SYSTEM.md +12 -0
  343. package/dist/scaffold/templates/env.example +4 -10
  344. package/dist/scaffold/templates/fastagent.config.ts +21 -33
  345. package/dist/scaffold/templates/gitignore +8 -1
  346. package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
  347. package/dist/scaffold/templates.d.ts +9 -4
  348. package/dist/scaffold/templates.js +7 -5
  349. package/dist/scaffold/vendor-skill.d.ts +1 -4
  350. package/dist/scaffold/vendor-skill.js +5 -6
  351. package/dist/schedule/cron.d.ts +13 -0
  352. package/dist/schedule/cron.js +52 -0
  353. package/dist/schedule/eventbridge-cron.d.ts +17 -0
  354. package/dist/schedule/eventbridge-cron.js +88 -0
  355. package/dist/schedule/schedule.d.ts +23 -0
  356. package/dist/schedule/schedule.js +34 -0
  357. package/dist/schedule/scheduler.d.ts +34 -33
  358. package/dist/schedule/scheduler.js +251 -137
  359. package/dist/schedule/state.d.ts +4 -14
  360. package/dist/schedule/state.js +7 -7
  361. package/dist/schedule/wake-alarm.d.ts +22 -2
  362. package/dist/schedule/wake-alarm.js +66 -20
  363. package/dist/schedule/wakeups.d.ts +16 -15
  364. package/dist/schedule/wakeups.js +47 -45
  365. package/dist/service.d.ts +56 -169
  366. package/dist/service.js +91 -187
  367. package/dist/serving-command.d.ts +10 -0
  368. package/dist/serving-command.js +16 -0
  369. package/dist/sign-in-api.d.ts +147 -0
  370. package/dist/sign-in-api.js +9 -0
  371. package/dist/slack.d.ts +1 -1
  372. package/dist/slack.js +1 -1
  373. package/dist/{channels/kit/state.js → state-file.js} +6 -6
  374. package/dist/telegram.d.ts +1 -0
  375. package/dist/telegram.js +1 -0
  376. package/dist/tunnel.d.ts +3 -0
  377. package/dist/tunnel.js +14 -5
  378. package/dist/value-file.d.ts +40 -0
  379. package/dist/value-file.js +164 -0
  380. package/dist/version.d.ts +5 -0
  381. package/dist/version.js +14 -1
  382. package/package.json +18 -28
  383. package/dist/agent.d.ts +0 -106
  384. package/dist/agent.js +0 -21
  385. package/dist/channels/control.d.ts +0 -31
  386. package/dist/channels/control.js +0 -329
  387. package/dist/channels/define-channel.d.ts +0 -39
  388. package/dist/channels/define-channel.js +0 -9
  389. package/dist/channels/feishu/context-buffer.d.ts +0 -35
  390. package/dist/channels/feishu/context-buffer.js +0 -65
  391. package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
  392. package/dist/channels/http.d.ts +0 -23
  393. package/dist/channels/http.js +0 -57
  394. package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
  395. package/dist/channels/slack/context-buffer.d.ts +0 -23
  396. package/dist/channels/slack/context-buffer.js +0 -37
  397. package/dist/channels/sse.d.ts +0 -4
  398. package/dist/channels/sse.js +0 -66
  399. package/dist/cli/commands/chat.d.ts +0 -3
  400. package/dist/cli/commands/chat.js +0 -14
  401. package/dist/cli/commands/routine-run.d.ts +0 -6
  402. package/dist/cli/commands/routine-run.js +0 -46
  403. package/dist/cli/commands/routine.d.ts +0 -25
  404. package/dist/cli/commands/routine.js +0 -122
  405. package/dist/cli/commands/tool.d.ts +0 -1
  406. package/dist/cli/commands/tool.js +0 -57
  407. package/dist/collect.d.ts +0 -63
  408. package/dist/collect.js +0 -90
  409. package/dist/core.d.ts +0 -13
  410. package/dist/core.js +0 -15
  411. package/dist/engines/pi/agent-models.d.ts +0 -83
  412. package/dist/engines/pi/agent-models.js +0 -120
  413. package/dist/engines/pi/agent-session-factory.d.ts +0 -121
  414. package/dist/engines/pi/agent-session-factory.js +0 -535
  415. package/dist/engines/pi/chat.d.ts +0 -3
  416. package/dist/engines/pi/chat.js +0 -8
  417. package/dist/engines/pi/config.d.ts +0 -71
  418. package/dist/engines/pi/config.js +0 -199
  419. package/dist/engines/pi/create.d.ts +0 -170
  420. package/dist/engines/pi/create.js +0 -343
  421. package/dist/engines/pi/definition.d.ts +0 -74
  422. package/dist/engines/pi/definition.js +0 -236
  423. package/dist/engines/pi/entry-images.d.ts +0 -14
  424. package/dist/engines/pi/entry-images.js +0 -23
  425. package/dist/engines/pi/invoke-session.d.ts +0 -18
  426. package/dist/engines/pi/invoke-session.js +0 -403
  427. package/dist/engines/pi/locked-file.d.ts +0 -9
  428. package/dist/engines/pi/login.js +0 -331
  429. package/dist/engines/pi/machine.d.ts +0 -53
  430. package/dist/engines/pi/machine.js +0 -137
  431. package/dist/engines/pi/models.d.ts +0 -200
  432. package/dist/engines/pi/models.js +0 -533
  433. package/dist/engines/pi/open.d.ts +0 -180
  434. package/dist/engines/pi/open.js +0 -270
  435. package/dist/engines/pi/openai-account-models.d.ts +0 -35
  436. package/dist/engines/pi/openai-account-models.js +0 -116
  437. package/dist/engines/pi/report.d.ts +0 -18
  438. package/dist/engines/pi/report.js +0 -59
  439. package/dist/engines/pi/retry-event.d.ts +0 -6
  440. package/dist/engines/pi/retry-event.js +0 -15
  441. package/dist/engines/pi/service.d.ts +0 -9
  442. package/dist/engines/pi/service.js +0 -14
  443. package/dist/engines/pi/session-builder.d.ts +0 -13
  444. package/dist/engines/pi/session-builder.js +0 -117
  445. package/dist/engines/pi/session-control.d.ts +0 -77
  446. package/dist/engines/pi/session-control.js +0 -908
  447. package/dist/engines/pi/session-effects.d.ts +0 -14
  448. package/dist/engines/pi/session-effects.js +0 -30
  449. package/dist/engines/pi/session-inheritance.d.ts +0 -21
  450. package/dist/engines/pi/session-inheritance.js +0 -204
  451. package/dist/engines/pi/session-markers.d.ts +0 -49
  452. package/dist/engines/pi/session-markers.js +0 -60
  453. package/dist/engines/pi/session-settings.d.ts +0 -67
  454. package/dist/engines/pi/session-settings.js +0 -119
  455. package/dist/engines/pi/session-store.d.ts +0 -69
  456. package/dist/engines/pi/session-store.js +0 -430
  457. package/dist/engines/pi/tool-context.d.ts +0 -45
  458. package/dist/engines/pi/tool-context.js +0 -31
  459. package/dist/engines/pi/tool.d.ts +0 -99
  460. package/dist/engines/pi/tool.js +0 -118
  461. package/dist/engines/pi/turn-kit.d.ts +0 -92
  462. package/dist/engines/pi/turn-kit.js +0 -288
  463. package/dist/engines/pi/wake-tool.d.ts +0 -9
  464. package/dist/engines/pi/wake-tool.js +0 -92
  465. package/dist/loader.d.ts +0 -41
  466. package/dist/loader.js +0 -116
  467. package/dist/node.d.ts +0 -3
  468. package/dist/node.js +0 -4
  469. package/dist/observe.d.ts +0 -6
  470. package/dist/observe.js +0 -47
  471. package/dist/pi.d.ts +0 -25
  472. package/dist/pi.js +0 -15
  473. package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
  474. package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
  475. package/dist/schedule/discover.d.ts +0 -17
  476. package/dist/schedule/discover.js +0 -61
  477. package/dist/schedule/routine.d.ts +0 -43
  478. package/dist/schedule/routine.js +0 -32
  479. package/dist/schedule/run.d.ts +0 -55
  480. package/dist/schedule/run.js +0 -146
  481. package/dist/secrets-gate.d.ts +0 -32
  482. package/dist/secrets-gate.js +0 -33
  483. package/dist/session-remote.d.ts +0 -47
  484. package/dist/session-remote.js +0 -460
  485. package/dist/session.d.ts +0 -466
  486. package/dist/session.js +0 -57
  487. /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
package/dist/service.js CHANGED
@@ -1,20 +1,19 @@
1
- /** The product, as one call: an agent directory becomes a live service. */
1
+ /** The product, as one call: an opened agent becomes a live service, its channels, schedules and wake-ups. */
2
2
  import * as Cause from "effect/Cause";
3
3
  import * as Effect from "effect/Effect";
4
4
  import * as Exit from "effect/Exit";
5
5
  import * as Fiber from "effect/Fiber";
6
6
  import * as Scope from "effect/Scope";
7
- import { createControlPlane } from "./channels/control.js";
8
- import { createInvokeHandler } from "./channels/http.js";
7
+ import { mountChannels } from "./channels/discover.js";
9
8
  import { text } from "./channels/respond.js";
10
- import { assertCorsOrigins, parseRouteKey, pathUnderPrefix, router } from "./channels/serve.js";
11
- import { loadChannels } from "./channels/discover.js";
12
- import { loadRoutines } from "./schedule/discover.js";
13
- import { createRoutineListHandler, createRunHandler } from "./schedule/run.js";
14
- import { createScheduler } from "./schedule/scheduler.js";
9
+ import { parseRouteKey, router } from "./channels/router.js";
10
+ import { serveHandler, totalFetch } from "./channels/serve.js";
11
+ import { portCleanup } from "./effect-port.js";
12
+ import { API_PREFIX } from "./http/contract.js";
13
+ import { apiHandler, isApiPath } from "./http/server.js";
15
14
  import { log } from "./log.js";
16
- import { refuseBrokenDeclarations } from "./loader.js";
17
- import { gateSecrets } from "./secrets-gate.js";
15
+ import { once } from "./once.js";
16
+ import { createScheduler } from "./schedule/scheduler.js";
18
17
  /** Default wait for a channel's `closed` before reporting it stuck. */
19
18
  const CLOSE_DEADLINE_MS = 5_000;
20
19
  /** One deadline for all connections; a failed close must not hide a sibling that is still running. */
@@ -42,98 +41,23 @@ function closeWithin(runs, names, deadlineMs) {
42
41
  }
43
42
  /** The port a serve binds when neither a flag, `PORT` (start only) nor `http.port` names one. */
44
43
  export const DEFAULT_HTTP_PORT = 8787;
45
- /**
46
- * Does this surface serve `POST /run`, given a routine to run? It FOLLOWS `invoke` unless `run` says otherwise (see
47
- * {@link HttpSurface.run}). ONE function because the assembly mounts the route and `preflightDeploy` names it; a
48
- * default spelled twice is a default that moves once.
49
- */
50
- export function shouldServeRun(http) {
51
- return http?.run ?? http?.invoke !== false;
52
- }
53
- /**
54
- * What an anonymous caller of a port can do, worst first — the ONE wording the startup report and deploy's pre-flight
55
- * both print, each from its own facts (what mounted vs what will mount).
56
- */
57
- export function describeAnonymousSurface(open) {
58
- return [
59
- ...(open.invoke ? ["POST /invoke (run a turn with this agent's tools)"] : []),
60
- ...(open.run ? ["POST /run (run any routine this agent declares; GET /routines lists them)"] : []),
61
- ...(open.controlPrefix ? [`${open.controlPrefix}/* (read, steer or delete any session)`] : []),
62
- ];
63
- }
64
- /**
65
- * The surface this deployment serves: the DATA plane (`POST /invoke`), `GET /health`, and the discovered channels.
66
- *
67
- * `/invoke` is the framework's interface, so it is served whatever channels a definition declares (unless
68
- * `http.invoke: false`). It is RESERVED for the same reason `/control/*` is: a channel taking that path would silently replace the one route every client,
69
- * every doc and the startup line all name. `/health` stays overridable — a probe is the deployment's to shape.
70
- */
71
- export async function routesFor(agentDir, agent, stateRoot, control,
72
- /**
73
- * `http.invoke: false` withholds the data plane. Two callers, two reasons: the AgentCore adapter serves the
74
- * Runtime's `/invocations` contract instead, and an author sets it to leave the channels' signature checks as the
75
- * only way into a public port.
76
- *
77
- * `routines` mounts `POST /run` and `GET /routines` (per {@link shouldServeRun}). Passed in rather than loaded here
78
- * so the routes and the resident clock cannot disagree about which routines exist (`loadServingRoutines`).
79
- */
80
- options = {}) {
81
- const { routes, longConnections, routeChannels, collisions, failures } = await loadChannels(agentDir, {
82
- agent,
83
- stateRoot,
84
- control,
85
- });
86
- for (const c of collisions) {
87
- log.warn(`[fastagent] channel route "${c.route}" (${c.source}) collides with an earlier channel — not mounted`);
88
- }
89
- refuseBrokenDeclarations(failures);
90
- if (collisions.length > 0) {
91
- throw new Error(`${collisions.length} channel route collision(s) — two channels cannot serve one route`);
44
+ /** Mount the channels and the health check. */
45
+ export function routesFor(agent, stateRoot, channels) {
46
+ const { routes, longConnections, routeChannels } = mountChannels(channels, agent, stateRoot);
47
+ for (const key of Object.keys(routes)) {
48
+ if (isApiPath(parseRouteKey(key).path)) {
49
+ throw new Error(`route "${key}" is under ${API_PREFIX}, which the Agent API serves — move it`);
50
+ }
92
51
  }
93
- /**
94
- * Which channel key already serves this path for the method a built-in would answer — the CHANNEL's spelling, not
95
- * ours. A channel may write the method-less `"/invoke"`, and an error naming `"POST /invoke"` sends its author
96
- * grepping their own file for a string that is not in it.
97
- */
98
- const covered = (path, method) => Object.keys(routes).find((key) => {
99
- const entry = parseRouteKey(key);
100
- return entry.path === path && (entry.method === undefined || entry.method === method);
101
- });
102
52
  let ready = longConnections.length === 0;
103
53
  const health = () => (ready ? text("ok\n", 200) : text("starting\n", 503));
104
- // AgentCore serves the data plane through the Runtime's own `/invocations` contract, so the adapter opts out — and
105
- // with no `/invoke` of ours on that surface there is nothing to reserve, which is why the refusal is in here.
106
- const unverified = { ...(covered("/health", "GET") ? {} : { "GET /health": health }) };
107
- if (options.http?.invoke !== false)
108
- unverified["POST /invoke"] = createInvokeHandler(agent);
109
- // `POST /run` exists only where there is something to run, and `GET /routines` exactly where that route does:
110
- // it is the catalogue OF that route, so listing names nobody can use would be a catalogue of nothing. Both ride
111
- // this table for the reason the table exists: they authenticate nobody, so they inherit the JSON body gate, the
112
- // cross-origin policy, the reserved path and the startup report's account of what is open.
113
- if (shouldServeRun(options.http)) {
114
- const routines = options.routines ?? [];
115
- const run = createRunHandler({ agent, routines });
116
- if (run)
117
- unverified["POST /run"] = run;
118
- const list = createRoutineListHandler({ routines });
119
- if (list)
120
- unverified["GET /routines"] = list;
121
- }
122
- // ONE rule over the whole table, so the next route we add is reserved by existing here rather than by someone
123
- // remembering to write a second check for it. `/health` is exempt by construction: it is only in `ours` when no
124
- // channel already serves it, because a probe is the deployment's to shape.
125
- const taken = Object.keys(unverified).flatMap((key) => {
54
+ const probed = Object.keys(routes).some((key) => {
126
55
  const entry = parseRouteKey(key);
127
- const channelKey = covered(entry.path, entry.method ?? "");
128
- return channelKey === undefined ? [] : [{ channelKey, key }];
56
+ return entry.path === "/health" && (entry.method === undefined || entry.method === "GET");
129
57
  });
130
- if (taken.length > 0) {
131
- throw new Error(`channel route(s) ${taken.map((t) => `"${t.channelKey}"`).join(", ")} take a path this serve answers on ` +
132
- `itself (${taken.map((t) => `"${t.key}"`).join(", ")}) — rename the channel route`);
133
- }
134
58
  return {
135
- unverified,
136
- selfVerifying: routes,
59
+ // A probe is the deployment's to shape, so a channel may serve `/health` itself.
60
+ routes: probed ? routes : { ...routes, "GET /health": health },
137
61
  longConnections,
138
62
  routeChannels,
139
63
  setReady(value) {
@@ -141,78 +65,71 @@ options = {}) {
141
65
  },
142
66
  };
143
67
  }
144
- /** Refuse channel routes the control plane would swallow. */
145
- export function assertNoControlPlaneCollision(channelRoutes, plane) {
146
- const collisions = Object.keys(channelRoutes).filter((key) => pathUnderPrefix(parseRouteKey(key).path, plane.prefix));
147
- if (collisions.length > 0) {
148
- throw new Error(`channel route(s) ${collisions.map((key) => `"${key}"`).join(", ")} collide with the session control plane — ` +
149
- `rename the channel route or disable sessionControl in fastagent.config`);
150
- }
151
- }
152
- export function mountSessionControl(routes, control) {
153
- if (!control)
154
- return { routes, mounts: [] };
155
- const plane = createControlPlane(control);
156
- assertNoControlPlaneCollision(routes, plane);
157
- return { routes, mounts: [plane], controlPrefix: plane.prefix };
158
- }
159
- /**
160
- * Load the agent's `routines/`, gated.
161
- *
162
- * Separate from {@link startSchedules} because two things need the SAME list and one of them runs first: the
163
- * `POST /run` route is built with the routes (so a channel cannot take that path unnoticed), and the resident
164
- * clock starts later, inside the service's scope. Loading twice would let them disagree about which routines exist.
165
- */
166
- export async function loadServingRoutines(agentDir) {
167
- // Thrown, not exited on: this runs inside an embedder's app as well as the CLI, and a library that calls
168
- // process.exit takes a decision (degrade? retry? stop?) that belongs to its host.
169
- const { routines, secrets, failures } = await loadRoutines(agentDir);
170
- // The routines' half of the serving-path gate (the opener does the tools', loadChannels the
171
- // channels'): a routine reads its env at IMPORT time, so an unset declared value has already
172
- // produced a broken prompt — refusing here is the last point where that is a startup failure.
173
- gateSecrets({ declared: secrets, failures });
174
- refuseBrokenDeclarations(failures);
175
- return routines;
176
- }
177
- /**
178
- * Start the clock over routines {@link loadServingRoutines} already gated — on every serve, routines or not: the
179
- * agent's own wake-ups are a default capability, and this is what fires them.
180
- */
181
- export function startSchedules(agent, stateRoot, routines, options = {}) {
182
- const scheduler = Effect.runSync(createScheduler({ agent, stateRoot, routines, externalClock: options.externalClock }));
68
+ /** Start the clock: the definition's schedules, and the wake-ups the agent sets for itself, on every serve. */
69
+ export function startSchedules(agent, stateRoot, schedules, options = {}) {
70
+ const scheduler = Effect.runSync(createScheduler({
71
+ agent,
72
+ stateRoot,
73
+ schedules,
74
+ ...(options.localClock === false ? { localClock: false } : {}),
75
+ }));
183
76
  scheduler.start();
184
- if (routines.length > 0) {
185
- log.info(`[fastagent] routines: ${routines.map((r) => r.name).join(", ")}${options.externalClock ? " (external clock — no resident cron timers)" : ""}`);
186
- }
187
- return { routines, stop: () => scheduler.stop() };
77
+ if (schedules.length > 0)
78
+ log.info(`[fastagent] schedules: ${schedules.map((s) => s.name).join(", ")}`);
79
+ return scheduler;
188
80
  }
189
81
  /**
190
- * The assembly itself, over an already-opened directory: channels, the control plane, routines and long connections,
191
- * composed into one handler.
82
+ * A Service over `handler`: answered in process, or served on a server of its own. `endStreams` ends what would hold
83
+ * the server's close open (a Caller watching events), and `shutdown` stops the rest once the server has.
192
84
  */
193
- export async function mountAgentService(opened, options = {}) {
194
- const { agentDir, workspace, stateRoot, sessionControl } = opened;
195
- // Wrapped BEFORE anything consumes it: routes, the control plane and routines must all drive the same agent, so
196
- // this is a hook rather than something a caller applies afterwards.
197
- const agent = options.wrapAgent?.(opened.agent) ?? opened.agent;
85
+ export function serviceOver(handler, ready, shutdown, endStreams = async () => { }) {
86
+ let listener;
87
+ let closing;
88
+ const fetch = totalFetch(handler);
89
+ return {
90
+ fetch,
91
+ listen(port, host) {
92
+ if (closing !== undefined)
93
+ return Promise.reject(new Error("the service is closed"));
94
+ if (listener !== undefined)
95
+ return Promise.reject(new Error("the service is already listening"));
96
+ const current = serveHandler(handler, { port, ...(host === undefined ? {} : { host }) });
97
+ listener = current;
98
+ return current.listening.catch(async (error) => {
99
+ // A bind that failed holds nothing once its scope is closed, so the service may listen again, elsewhere.
100
+ if (listener === current)
101
+ listener = undefined;
102
+ await current.close();
103
+ throw error;
104
+ });
105
+ },
106
+ ready,
107
+ close() {
108
+ closing ??= (async () => {
109
+ // The server first, so nothing new reaches what stops after it; each step runs, and every failure is said.
110
+ const failures = [];
111
+ for (const step of [endStreams, () => listener?.close(), shutdown]) {
112
+ await Promise.resolve()
113
+ .then(step)
114
+ .catch((error) => failures.push(error));
115
+ }
116
+ if (failures.length > 0) {
117
+ throw failures.length === 1 ? failures[0] : new AggregateError(failures, "the service did not close cleanly");
118
+ }
119
+ })();
120
+ return closing;
121
+ },
122
+ };
123
+ }
124
+ /** The assembly itself: channels, schedules and long connections, composed into one handler. */
125
+ export async function serveAgent(opened, options = {}) {
126
+ const { agent, agentDir, stateRoot, schedules } = opened;
198
127
  const closeTimeoutMs = options.closeTimeoutMs ?? CLOSE_DEADLINE_MS;
199
- // The embedder's way in, checked like the config file's: `allowedOrigin` compares exact strings, so a stray
200
- // trailing slash would refuse the front end with nothing naming the rule.
201
- const corsOrigins = opened.http?.cors;
202
- if (corsOrigins)
203
- assertCorsOrigins(corsOrigins, "mountAgentService: http.cors");
204
- // Loaded BEFORE the routes, because `POST /run` is one of them and the resident clock below must run over the
205
- // same list — two loads would be two answers to "which routines exist".
206
- const routines = await loadServingRoutines(agentDir);
207
- const routed = await routesFor(agentDir, agent, stateRoot, sessionControl, { http: opened.http, routines });
208
- const withControl = mountSessionControl(routed.selfVerifying, opened.publishControl ? sessionControl : undefined);
128
+ const routed = routesFor(agent, stateRoot, opened.channels);
209
129
  // Composed BEFORE anything starts.
210
- const handler = router({
211
- unverified: routed.unverified,
212
- selfVerifying: withControl.routes,
213
- mounts: withControl.mounts,
214
- ...(corsOrigins ? { corsOrigins } : {}),
215
- });
130
+ const channels = router(routed.routes);
131
+ const api = options.apiKeys?.length ? apiHandler(agent, { keys: options.apiKeys }) : undefined;
132
+ const handler = api === undefined ? channels : (req) => (isApiPath(new URL(req.url).pathname) ? api.fetch(req) : channels(req));
216
133
  return Effect.runPromise(Effect.gen(function* () {
217
134
  const lifetime = yield* Scope.make();
218
135
  const abort = new AbortController();
@@ -229,21 +146,21 @@ export async function mountAgentService(opened, options = {}) {
229
146
  routed.setReady(false);
230
147
  onClosed(name, error);
231
148
  };
232
- // Scope.close alone does not join concurrent closes or retain their failure.
233
- const shutdown = yield* Effect.cached(Effect.gen(function* () {
149
+ // Scope.close alone does not join concurrent closes or retain their failure. Every later call, the rollback a
150
+ // close itself triggers included, awaits the first one's outcome.
151
+ const shutdown = once(Effect.gen(function* () {
234
152
  abort.abort();
235
153
  yield* Scope.close(lifetime, Exit.void);
236
154
  }));
237
155
  const close = () => Effect.runPromise(shutdown);
238
156
  const rollback = shutdown.pipe(Effect.catchCause((cause) => Effect.sync(() => log.error(`[fastagent] cleanup after a failed start also failed: ${String(Cause.squash(cause))}`))));
239
- const onAbort = () => {
240
- void close().catch((error) => log.error(`[fastagent] service close failed: ${String(error)}`));
241
- };
242
157
  return yield* Effect.gen(function* () {
158
+ if (api !== undefined)
159
+ yield* Effect.addFinalizer(() => portCleanup("closing the Agent API", api.dispose));
243
160
  // Registered first, so subscriptions and schedule timers stop before waiting for transports.
244
161
  yield* Effect.addFinalizer(() => closeWithin(runs, names, closeTimeoutMs).pipe(Effect.orDie));
245
- const scheduled = yield* Effect.acquireRelease(Effect.try({
246
- try: () => startSchedules(agent, stateRoot, routines),
162
+ yield* Effect.acquireRelease(Effect.try({
163
+ try: () => startSchedules(agent, stateRoot, schedules),
247
164
  catch: (error) => error,
248
165
  }), (scheduled) => Effect.sync(scheduled.stop));
249
166
  const readiness = yield* Effect.forEach(routed.longConnections, (connection) => Effect.gen(function* () {
@@ -269,10 +186,6 @@ export async function mountAgentService(opened, options = {}) {
269
186
  log.info(`[fastagent] long connection ready: ${connection.name}`);
270
187
  })), Effect.forkScoped({ startImmediately: true }));
271
188
  }));
272
- if (options.signal?.aborted)
273
- yield* shutdown;
274
- else
275
- yield* Effect.acquireRelease(Effect.sync(() => options.signal?.addEventListener("abort", onAbort, { once: true })), () => Effect.sync(() => options.signal?.removeEventListener("abort", onAbort)));
276
189
  // The public readiness waiter lives outside the scope it may roll back.
277
190
  const ready = Effect.runPromise(Effect.gen(function* () {
278
191
  yield* Effect.forEach(readiness, Fiber.join, { concurrency: "unbounded", discard: true });
@@ -287,21 +200,12 @@ export async function mountAgentService(opened, options = {}) {
287
200
  // The rejection is still delivered to callers that await ready.
288
201
  ready.catch(() => { });
289
202
  return {
290
- handler,
291
- agent,
292
- routes: { ...routed.unverified, ...withControl.routes },
203
+ ...serviceOver(handler, ready, close, async () => api?.endStreams()),
204
+ routes: routed.routes,
293
205
  agentDir,
294
- workspace,
295
- channels: {
296
- routes: routed.routeChannels,
297
- longConnections: names,
298
- },
299
- unverifiedRoutes: Object.keys(routed.unverified),
300
- ...(corsOrigins ? { corsOrigins } : {}),
301
- routines: scheduled.routines,
302
- ready,
303
- ...(withControl.controlPrefix ? { controlPrefix: withControl.controlPrefix } : {}),
304
- close,
206
+ channels: { routes: routed.routeChannels, longConnections: names },
207
+ schedules,
208
+ api: api !== undefined,
305
209
  };
306
210
  }).pipe(Scope.provide(lifetime), Effect.onError(() => rollback));
307
211
  }));
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Which command serves this process: `dev` marks it, and everything else (`start`, a deployed box, an embedder) is
3
+ * the default. A channel file reads it at import through the agent's OWN installed copy of this package, which shares
4
+ * nothing with the CLI's copy but the process environment, so the mark lives there.
5
+ */
6
+ export declare const DEV_SERVE_ENV = "FASTAGENT_DEV";
7
+ export declare function markDevServe(env?: NodeJS.ProcessEnv): void;
8
+ /** For a command that is never `dev` (`start`, `deploy`), run from a shell or a tool that a `dev` process spawned. */
9
+ export declare function unmarkDevServe(env?: NodeJS.ProcessEnv): void;
10
+ export declare function servedByDev(env?: NodeJS.ProcessEnv): boolean;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Which command serves this process: `dev` marks it, and everything else (`start`, a deployed box, an embedder) is
3
+ * the default. A channel file reads it at import through the agent's OWN installed copy of this package, which shares
4
+ * nothing with the CLI's copy but the process environment, so the mark lives there.
5
+ */
6
+ export const DEV_SERVE_ENV = "FASTAGENT_DEV";
7
+ export function markDevServe(env = process.env) {
8
+ env[DEV_SERVE_ENV] = "1";
9
+ }
10
+ /** For a command that is never `dev` (`start`, `deploy`), run from a shell or a tool that a `dev` process spawned. */
11
+ export function unmarkDevServe(env = process.env) {
12
+ delete env[DEV_SERVE_ENV];
13
+ }
14
+ export function servedByDev(env = process.env) {
15
+ return env[DEV_SERVE_ENV] === "1";
16
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Model credentials and provider sign-in as an embedding host sees them: FastAgent's own types, so a host keeps the
3
+ * credentials where it chooses and runs a sign-in in its own UI without knowing the harness. Imports nothing; the
4
+ * functions over these types are in harnesses/models/host.ts.
5
+ */
6
+ /** One provider's credential, kept by a {@link CredentialStore} whole, as it is given. */
7
+ export type Credential = {
8
+ type: "api_key";
9
+ key?: string;
10
+ env?: Record<string, string>;
11
+ } | {
12
+ type: "oauth";
13
+ access: string;
14
+ refresh: string;
15
+ expires: number;
16
+ [field: string]: unknown;
17
+ };
18
+ /**
19
+ * Where model credentials are kept, one per provider. `modify` is the only write, and it runs one at a time per
20
+ * provider (across processes, where the store can): an OAuth refresh happens inside it, and a rotated refresh token
21
+ * must never be used twice. A store it cannot read rejects; answering it as empty would let the next write replace
22
+ * every provider's credential.
23
+ */
24
+ export interface CredentialStore {
25
+ /** The stored credential, possibly expired; undefined when the provider has none. */
26
+ read(provider: string): Promise<Credential | undefined>;
27
+ /** Which providers have a credential, and of what kind; never the secrets. */
28
+ list(): Promise<readonly {
29
+ provider: string;
30
+ type: Credential["type"];
31
+ }[]>;
32
+ /** `change` returns the new credential, or undefined to leave it as it is. Resolves with what is stored after. */
33
+ modify(provider: string, change: (current: Credential | undefined) => Promise<Credential | undefined>): Promise<Credential | undefined>;
34
+ delete(provider: string): Promise<void>;
35
+ }
36
+ export type SignInMethod = Credential["type"];
37
+ /** One way to sign in to one provider, with what authenticates the provider now. */
38
+ export interface SignInOption {
39
+ provider: string;
40
+ /** The provider's name: "OpenAI", "OpenAI Codex (legacy)". */
41
+ name: string;
42
+ method: SignInMethod;
43
+ /** What signing in this way is called: the provider's own label ("Sign in with ChatGPT"), else a generic one. */
44
+ label: string;
45
+ /** An account sign-in backed by a provider subscription. */
46
+ subscription: boolean;
47
+ /** Its key comes from the environment only: there is no sign-in to run. */
48
+ external: boolean;
49
+ /**
50
+ * What authenticates the provider now: a stored credential (`OAuth`, `stored credential`), else the environment
51
+ * (a variable such as `OPENAI_API_KEY`). One credential is stored per provider, so signing in with the other method
52
+ * replaces a stored one.
53
+ */
54
+ status?: {
55
+ type: SignInMethod;
56
+ source: string;
57
+ };
58
+ /** What in the environment authenticates the provider with nothing stored: what still answers after a sign-out. */
59
+ environment?: string;
60
+ /**
61
+ * Why checking the environment for the provider failed: `environment` is then unknown, and so is `status` when
62
+ * nothing is stored.
63
+ */
64
+ problem?: string;
65
+ }
66
+ /** A question a sign-in asks. `manual_code`: the address the browser ended on after signing in, or the code its page showed. */
67
+ export type SignInPrompt = {
68
+ signal?: AbortSignal;
69
+ } & ({
70
+ type: "text" | "secret" | "manual_code";
71
+ message: string;
72
+ placeholder?: string;
73
+ } | {
74
+ type: "select";
75
+ message: string;
76
+ options: readonly {
77
+ id: string;
78
+ label: string;
79
+ description?: string;
80
+ }[];
81
+ });
82
+ /** What a sign-in tells the person: a page to open, a code to enter there, progress. */
83
+ export type SignInEvent = {
84
+ type: "info";
85
+ message: string;
86
+ links?: readonly {
87
+ url: string;
88
+ label?: string;
89
+ }[];
90
+ } | {
91
+ type: "progress";
92
+ message: string;
93
+ } | {
94
+ type: "auth_url";
95
+ url: string;
96
+ instructions?: string;
97
+ } | {
98
+ type: "device_code";
99
+ userCode: string;
100
+ verificationUri: string;
101
+ intervalSeconds?: number;
102
+ expiresInSeconds?: number;
103
+ };
104
+ /**
105
+ * How a sign-in reaches the person. `prompt` resolves with the answer (a select's option `id`); it rejects with
106
+ * {@link SignInCancelled} when the person backs out, which ends the sign-in with that error, and with any other error
107
+ * when asking failed, which fails the sign-in with it. A prompt's `signal` aborts when the sign-in no longer needs the
108
+ * answer, such as a `manual_code` question a browser callback answered first.
109
+ */
110
+ export interface SignInInteraction {
111
+ signal?: AbortSignal;
112
+ prompt(prompt: SignInPrompt): Promise<string>;
113
+ notify(event: SignInEvent): void;
114
+ }
115
+ export interface SignInRequest {
116
+ credentials: CredentialStore;
117
+ provider: string;
118
+ method: SignInMethod;
119
+ interaction: SignInInteraction;
120
+ /**
121
+ * A stable id of this installation, which Sign in with ChatGPT requires. `credentialFile` keeps one beside its
122
+ * file; a store of the host's own passes it here.
123
+ */
124
+ deviceId?: string;
125
+ }
126
+ export interface SignInResult {
127
+ provider: string;
128
+ method: SignInMethod;
129
+ /** An API key is checked with one request before it is stored: accepted, or not decidable (stored). */
130
+ verified: "ok" | "unknown" | "n/a";
131
+ }
132
+ /** What a request to a provider authenticates with. */
133
+ export interface ProviderAuth {
134
+ type: SignInMethod;
135
+ /** Where it comes from: `OAuth`, `stored credential`, an environment variable's name. */
136
+ source?: string;
137
+ /** The key or access token a request sends. */
138
+ apiKey?: string;
139
+ /** Headers a request sends, where the provider authenticates by them (an `Authorization` of its own). */
140
+ headers?: Record<string, string>;
141
+ /** Where the request goes, where the credential decides it (an enterprise endpoint). */
142
+ baseUrl?: string;
143
+ }
144
+ /** The person backed out of a sign-in, or its signal aborted: a decision, not a failure. Nothing was stored. */
145
+ export declare class SignInCancelled extends Error {
146
+ name: string;
147
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Model credentials and provider sign-in as an embedding host sees them: FastAgent's own types, so a host keeps the
3
+ * credentials where it chooses and runs a sign-in in its own UI without knowing the harness. Imports nothing; the
4
+ * functions over these types are in harnesses/models/host.ts.
5
+ */
6
+ /** The person backed out of a sign-in, or its signal aborted: a decision, not a failure. Nothing was stored. */
7
+ export class SignInCancelled extends Error {
8
+ name = "SignInCancelled";
9
+ }
package/dist/slack.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  /** `@fastagent-sh/fastagent/slack` — the first-party Slack Events API bot-channel surface. */
2
2
  export { slackChannel, defaultSlackRoute, slackEnvelope, verifySlackSignature, type SlackChannelOptions, type SlackEventEnvelope, type SlackFile, type SlackMessageEvent, type SlackRendering, type SlackRoute, type SlackFailure, } from "./channels/slack/slack.ts";
3
- export { slackTransport, type SlackTransport } from "./channels/slack/shared-api.ts";
3
+ export { slackThreads, slackTransport, type SlackTransport } from "./channels/slack/shared-api.ts";
4
4
  export type { SentSlackMessage, SlackTarget, UploadedSlackFile } from "./channels/slack/slack-api.ts";
package/dist/slack.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /** `@fastagent-sh/fastagent/slack` — the first-party Slack Events API bot-channel surface. */
2
2
  export { slackChannel, defaultSlackRoute, slackEnvelope, verifySlackSignature, } from "./channels/slack/slack.js";
3
- export { slackTransport } from "./channels/slack/shared-api.js";
3
+ export { slackThreads, slackTransport } from "./channels/slack/shared-api.js";
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Durable channel state, with no cross-instance locking: every file here is keyed by CHANNEL KIND
3
- * (`<stateRoot>/channels/<kind>/`), so what must not happen is two processes serving the SAME channel — which also
4
- * means one ingress credential in two places, and no local guard can see that. Two processes serving different
5
- * channels of one agent never touch the same file (docs/design/core.md, "the shipped file-backed implementations").
2
+ * A Caller's durable state under the state root, with no cross-instance locking: a channel's files are in its own
3
+ * directory (`<stateRoot>/channels/<the channel file's name>/`) and the schedules' in `schedule/`, so what must not
4
+ * happen is two processes serving the SAME channel — which also means one ingress credential in two places, and no
5
+ * local guard can see that (docs/design/core.md §9).
6
6
  */
7
7
  import { mkdirSync, readFileSync } from "node:fs";
8
- import { writeFileAtomic } from "../../atomic-write.js";
9
- import { log } from "../../log.js";
8
+ import { writeFileAtomic } from "./atomic-write.js";
9
+ import { log } from "./log.js";
10
10
  /** Create the channel's state home — the one shared spelling of it, so no channel invents its own. */
11
11
  export function ensureStateHome(dir) {
12
12
  mkdirSync(dir, { recursive: true });
@@ -1,2 +1,3 @@
1
1
  /** `@fastagent-sh/fastagent/telegram` — the Telegram bot channel subpath export, kept off the root surface. */
2
2
  export { telegramChannel, defaultTelegramRoute, telegramEnvelope, telegramStop, type TelegramChannelOptions, type TelegramUpdate, type TelegramMessage, type TelegramRoute, type TelegramFailure, } from "./channels/telegram/telegram.ts";
3
+ export { telegramTransport, type TelegramSendTarget, type TelegramSent, type TelegramTransport, } from "./channels/telegram/shared-api.ts";
package/dist/telegram.js CHANGED
@@ -1,2 +1,3 @@
1
1
  /** `@fastagent-sh/fastagent/telegram` — the Telegram bot channel subpath export, kept off the root surface. */
2
2
  export { telegramChannel, defaultTelegramRoute, telegramEnvelope, telegramStop, } from "./channels/telegram/telegram.js";
3
+ export { telegramTransport, } from "./channels/telegram/shared-api.js";
package/dist/tunnel.d.ts CHANGED
@@ -27,6 +27,9 @@ export declare function startCloudflareTunnel(port: number, spawnFn?: SpawnCloud
27
27
  export declare function announceWebhooks(dir: string, baseUrl: string, channels: readonly DeclaredChannel[], opts?: {
28
28
  openUrl?: (url: string) => void;
29
29
  stateRoot?: string;
30
+ env?: NodeJS.ProcessEnv;
31
+ /** {@link Registrars.leave}. */
32
+ leave?: (step: string) => void;
30
33
  }): Promise<{
31
34
  kind: string;
32
35
  outcome: RegistrationOutcome;
package/dist/tunnel.js CHANGED
@@ -7,10 +7,11 @@ import { spawn } from "node:child_process";
7
7
  import { registerFeishuWebhook } from "./channels/feishu/register-webhook.js";
8
8
  import { registerSlackWebhook } from "./channels/slack/register-webhook.js";
9
9
  import { registerTelegramWebhook } from "./channels/telegram/register-webhook.js";
10
- import { pointChannelsAt } from "./deploy/channel-ingress.js";
11
- import { dotEnvPath, loadDotEnv } from "./env.js";
10
+ import { pointChannelsAt, webhookKinds } from "./deploy/channel-ingress.js";
11
+ import { loadDotEnv } from "./env.js";
12
+ import { dotEnvPath } from "./value-file.js";
12
13
  import { installProxyFetch } from "./proxy.js";
13
- import { resolveStateRoot } from "./paths.js";
14
+ import { AGENT_ENVIRONMENT_ENV, resolveStateRoot } from "./paths.js";
14
15
  import { log } from "./log.js";
15
16
  // `(?!api\.)`: cloudflared's ERROR lines mention its request endpoint (`https://api.trycloudflare.com/tunnel`, e.g.
16
17
  // "failed to request quick Tunnel: Post ... timeout" under a flaky proxy) — without the exclusion a transient error
@@ -130,7 +131,8 @@ function lastErrorLine(tail) {
130
131
  export async function announceWebhooks(dir, baseUrl, channels, opts = {}) {
131
132
  log.info(`[fastagent] public URL: ${baseUrl}`);
132
133
  try {
133
- loadDotEnv(dir); // webhook registrars read channel credentials from .env
134
+ if (!opts.env)
135
+ loadDotEnv(dir);
134
136
  }
135
137
  catch (error) {
136
138
  // best-effort boundary: an unreadable .env (a MISSING one is already tolerated) still leaves registrars that can
@@ -141,16 +143,23 @@ export async function announceWebhooks(dir, baseUrl, channels, opts = {}) {
141
143
  // Readiness is the registrar's job: a fresh quick tunnel returns Cloudflare 530 for ~20-30s before its origin
142
144
  // connects, and each registrar absorbs that by retrying the platform call whose own URL verification reports it.
143
145
  const feishuOptions = {
146
+ env: opts.env,
144
147
  onManualRegistration: ({ consoleUrl }) => opts.openUrl?.(consoleUrl),
145
148
  };
149
+ const moving = webhookKinds(channels);
150
+ if (moving.length > 0) {
151
+ log.info(`[fastagent] pointing the selected ${moving.join(", ")} app at ${baseUrl}; only this app's Request URL changes`);
152
+ }
146
153
  return pointChannelsAt({
147
154
  baseUrl,
148
155
  channels,
149
156
  log: (message) => log.info(`[fastagent] ${message}`),
150
157
  registrars: {
151
- telegram: (url) => registerTelegramWebhook(url),
158
+ ...(opts.leave === undefined ? {} : { leave: opts.leave }),
159
+ telegram: (url) => registerTelegramWebhook(url, { env: opts.env }),
152
160
  slack: (url) => registerSlackWebhook(url, {
153
161
  stateRoot: opts.stateRoot ?? resolveStateRoot(dir),
162
+ environment: process.env[AGENT_ENVIRONMENT_ENV] === "production" ? "production" : "dev",
154
163
  log: (message) => log.info(message),
155
164
  }),
156
165
  feishu: (url, kind) => registerFeishuWebhook(url, kind, feishuOptions),