@fastagent-sh/fastagent 0.21.1 → 0.22.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 (388) hide show
  1. package/README.md +9 -12
  2. package/dist/agent.d.ts +24 -37
  3. package/dist/agent.js +7 -15
  4. package/dist/atomic-write.d.ts +13 -17
  5. package/dist/atomic-write.js +18 -29
  6. package/dist/bind.d.ts +12 -22
  7. package/dist/bind.js +18 -27
  8. package/dist/channel.d.ts +11 -33
  9. package/dist/channels/agentcore-limits.d.ts +2 -13
  10. package/dist/channels/agentcore-limits.js +2 -13
  11. package/dist/channels/agentcore-protocol.d.ts +67 -58
  12. package/dist/channels/agentcore-protocol.js +23 -15
  13. package/dist/channels/agentcore-service.d.ts +19 -33
  14. package/dist/channels/agentcore-service.js +176 -59
  15. package/dist/channels/agentcore.d.ts +39 -33
  16. package/dist/channels/agentcore.js +90 -224
  17. package/dist/channels/body.d.ts +15 -2
  18. package/dist/channels/body.js +24 -2
  19. package/dist/channels/busy.d.ts +1 -21
  20. package/dist/channels/busy.js +2 -39
  21. package/dist/channels/control.d.ts +17 -62
  22. package/dist/channels/control.js +74 -182
  23. package/dist/channels/define-channel.d.ts +39 -0
  24. package/dist/channels/define-channel.js +9 -0
  25. package/dist/channels/discover.d.ts +10 -31
  26. package/dist/channels/discover.js +37 -31
  27. package/dist/channels/feishu/bootstrap-token.d.ts +1 -8
  28. package/dist/channels/feishu/bootstrap-token.js +7 -23
  29. package/dist/channels/feishu/card.d.ts +14 -28
  30. package/dist/channels/feishu/card.js +16 -30
  31. package/dist/channels/feishu/cloud.d.ts +1 -5
  32. package/dist/channels/feishu/context-buffer.d.ts +4 -23
  33. package/dist/channels/feishu/context-buffer.js +8 -31
  34. package/dist/channels/feishu/crypto.d.ts +10 -5
  35. package/dist/channels/feishu/crypto.js +12 -19
  36. package/dist/channels/feishu/feishu-api.d.ts +2 -1
  37. package/dist/channels/feishu/feishu-api.js +5 -4
  38. package/dist/channels/feishu/feishu.d.ts +4 -10
  39. package/dist/channels/feishu/feishu.js +113 -227
  40. package/dist/channels/feishu/invoke-turn.d.ts +5 -4
  41. package/dist/channels/feishu/invoke-turn.js +36 -54
  42. package/dist/channels/feishu/model.d.ts +4 -21
  43. package/dist/channels/feishu/model.js +1 -8
  44. package/dist/channels/feishu/normalize.d.ts +2 -10
  45. package/dist/channels/feishu/normalize.js +7 -42
  46. package/dist/channels/feishu/parse.d.ts +9 -29
  47. package/dist/channels/feishu/parse.js +8 -26
  48. package/dist/channels/feishu/preview.d.ts +12 -14
  49. package/dist/channels/feishu/preview.js +108 -207
  50. package/dist/channels/feishu/register-app.d.ts +8 -23
  51. package/dist/channels/feishu/register-app.js +7 -20
  52. package/dist/channels/feishu/register-webhook.d.ts +2 -9
  53. package/dist/channels/feishu/register-webhook.js +9 -33
  54. package/dist/channels/feishu/scaffold/channel.ts +27 -19
  55. package/dist/channels/feishu/scaffold/channel.websocket.ts +31 -0
  56. package/dist/channels/feishu/setup-mode.d.ts +11 -36
  57. package/dist/channels/feishu/setup-mode.js +7 -26
  58. package/dist/channels/feishu/ws-ingress.d.ts +1 -2
  59. package/dist/channels/feishu/ws-ingress.js +6 -8
  60. package/dist/channels/http.d.ts +15 -15
  61. package/dist/channels/http.js +19 -9
  62. package/dist/channels/kit/attachment-path.d.ts +4 -5
  63. package/dist/channels/kit/attachment-path.js +10 -34
  64. package/dist/channels/kit/context-buffer.d.ts +14 -21
  65. package/dist/channels/kit/context-buffer.js +25 -38
  66. package/dist/channels/kit/delivery.d.ts +35 -0
  67. package/dist/channels/kit/delivery.js +129 -0
  68. package/dist/channels/kit/event-stream.d.ts +5 -0
  69. package/dist/channels/kit/event-stream.js +29 -0
  70. package/dist/channels/kit/invoke-turn-kit.d.ts +53 -26
  71. package/dist/channels/kit/invoke-turn-kit.js +89 -32
  72. package/dist/channels/kit/preview-kit.d.ts +18 -72
  73. package/dist/channels/kit/preview-kit.js +22 -88
  74. package/dist/channels/kit/signature.d.ts +3 -9
  75. package/dist/channels/kit/signature.js +3 -9
  76. package/dist/channels/kit/state.d.ts +1 -2
  77. package/dist/channels/kit/state.js +5 -14
  78. package/dist/channels/kit/stop-command.d.ts +1 -2
  79. package/dist/channels/kit/stop-command.js +6 -9
  80. package/dist/channels/kit/tasks.d.ts +1 -1
  81. package/dist/channels/kit/tasks.js +8 -21
  82. package/dist/channels/kit/text.d.ts +2 -16
  83. package/dist/channels/kit/text.js +23 -31
  84. package/dist/channels/kit/thread-participants.d.ts +4 -17
  85. package/dist/channels/kit/thread-participants.js +8 -55
  86. package/dist/channels/kit/transport.d.ts +26 -0
  87. package/dist/channels/kit/transport.js +20 -0
  88. package/dist/channels/kit/turn-queue.d.ts +7 -11
  89. package/dist/channels/kit/turn-queue.js +21 -39
  90. package/dist/channels/kit/turn-runner.d.ts +32 -18
  91. package/dist/channels/kit/turn-runner.js +98 -53
  92. package/dist/channels/kit/turn-store.d.ts +32 -32
  93. package/dist/channels/kit/turn-store.js +45 -88
  94. package/dist/channels/lark/lark.d.ts +1 -5
  95. package/dist/channels/lark/onboard.d.ts +3 -12
  96. package/dist/channels/lark/onboard.js +3 -13
  97. package/dist/channels/lark/scaffold/channel.ts +27 -19
  98. package/dist/channels/lark/scaffold/channel.websocket.ts +31 -0
  99. package/dist/channels/registration.d.ts +9 -35
  100. package/dist/channels/registration.js +6 -37
  101. package/dist/channels/secret.js +2 -5
  102. package/dist/channels/serve.d.ts +47 -44
  103. package/dist/channels/serve.js +165 -101
  104. package/dist/channels/slack/config-api.d.ts +4 -27
  105. package/dist/channels/slack/config-api.js +5 -34
  106. package/dist/channels/slack/context-buffer.d.ts +2 -3
  107. package/dist/channels/slack/context-buffer.js +5 -5
  108. package/dist/channels/slack/invoke-turn.d.ts +3 -1
  109. package/dist/channels/slack/invoke-turn.js +25 -34
  110. package/dist/channels/slack/manifest.js +1 -3
  111. package/dist/channels/slack/model.d.ts +1 -2
  112. package/dist/channels/slack/model.js +1 -1
  113. package/dist/channels/slack/onboard.d.ts +4 -3
  114. package/dist/channels/slack/onboard.js +8 -11
  115. package/dist/channels/slack/onboarding-state.d.ts +3 -5
  116. package/dist/channels/slack/onboarding-state.js +9 -6
  117. package/dist/channels/slack/parse.d.ts +4 -13
  118. package/dist/channels/slack/parse.js +7 -28
  119. package/dist/channels/slack/preview.d.ts +12 -2
  120. package/dist/channels/slack/preview.js +292 -269
  121. package/dist/channels/slack/reaction.d.ts +11 -3
  122. package/dist/channels/slack/reaction.js +19 -8
  123. package/dist/channels/slack/register-webhook.js +4 -7
  124. package/dist/channels/slack/scaffold/channel.ts +20 -13
  125. package/dist/channels/slack/scaffold/slack-send.ts +2 -2
  126. package/dist/channels/slack/setup-server.d.ts +1 -5
  127. package/dist/channels/slack/setup-server.js +1 -5
  128. package/dist/channels/slack/shared-api.d.ts +1 -4
  129. package/dist/channels/slack/shared-api.js +2 -13
  130. package/dist/channels/slack/slack-api.d.ts +2 -1
  131. package/dist/channels/slack/slack-api.js +6 -4
  132. package/dist/channels/slack/slack.d.ts +11 -14
  133. package/dist/channels/slack/slack.js +121 -122
  134. package/dist/channels/sse.d.ts +1 -1
  135. package/dist/channels/sse.js +1 -1
  136. package/dist/channels/telegram/context-buffer.d.ts +7 -22
  137. package/dist/channels/telegram/context-buffer.js +6 -23
  138. package/dist/channels/telegram/invoke-turn.d.ts +7 -7
  139. package/dist/channels/telegram/invoke-turn.js +24 -43
  140. package/dist/channels/telegram/parse.d.ts +24 -51
  141. package/dist/channels/telegram/parse.js +32 -84
  142. package/dist/channels/telegram/preview.d.ts +10 -1
  143. package/dist/channels/telegram/preview.js +79 -100
  144. package/dist/channels/telegram/register-webhook.js +5 -23
  145. package/dist/channels/telegram/scaffold/channel.ts +25 -18
  146. package/dist/channels/telegram/scaffold/telegram-send.ts +6 -4
  147. package/dist/channels/telegram/telegram-api.d.ts +4 -3
  148. package/dist/channels/telegram/telegram-api.js +9 -7
  149. package/dist/channels/telegram/telegram.d.ts +4 -18
  150. package/dist/channels/telegram/telegram.js +38 -94
  151. package/dist/channels/telegram/turn-store.d.ts +11 -14
  152. package/dist/channels/telegram/turn-store.js +8 -6
  153. package/dist/channels/wait-health.d.ts +4 -6
  154. package/dist/channels/wait-health.js +10 -14
  155. package/dist/cli/add-feishu.d.ts +2 -12
  156. package/dist/cli/add-feishu.js +24 -71
  157. package/dist/cli/add-slack.d.ts +5 -3
  158. package/dist/cli/add-slack.js +53 -76
  159. package/dist/cli/auth-view.d.ts +2 -16
  160. package/dist/cli/auth-view.js +2 -16
  161. package/dist/cli/commands/add.js +25 -40
  162. package/dist/cli/commands/chat.d.ts +0 -1
  163. package/dist/cli/commands/chat.js +5 -6
  164. package/dist/cli/commands/deploy/agentcore.js +60 -65
  165. package/dist/cli/commands/deploy/docker.js +50 -23
  166. package/dist/cli/commands/deploy/fly.js +23 -61
  167. package/dist/cli/commands/deploy/railway.js +23 -18
  168. package/dist/cli/commands/deploy/shared.d.ts +38 -57
  169. package/dist/cli/commands/deploy/shared.js +40 -59
  170. package/dist/cli/commands/deploy.d.ts +10 -27
  171. package/dist/cli/commands/deploy.js +38 -60
  172. package/dist/cli/commands/destroy.d.ts +4 -0
  173. package/dist/cli/commands/destroy.js +56 -0
  174. package/dist/cli/commands/dev.d.ts +2 -1
  175. package/dist/cli/commands/dev.js +20 -23
  176. package/dist/cli/commands/info.d.ts +0 -2
  177. package/dist/cli/commands/info.js +83 -49
  178. package/dist/cli/commands/init.d.ts +1 -2
  179. package/dist/cli/commands/init.js +16 -55
  180. package/dist/cli/commands/invoke.d.ts +0 -1
  181. package/dist/cli/commands/invoke.js +5 -7
  182. package/dist/cli/commands/login.d.ts +2 -1
  183. package/dist/cli/commands/login.js +33 -38
  184. package/dist/cli/commands/logs.js +3 -4
  185. package/dist/cli/commands/models.js +1 -5
  186. package/dist/cli/commands/routine-run.d.ts +6 -0
  187. package/dist/cli/commands/routine-run.js +47 -0
  188. package/dist/cli/commands/routine.d.ts +25 -0
  189. package/dist/cli/commands/routine.js +122 -0
  190. package/dist/cli/commands/start.d.ts +31 -3
  191. package/dist/cli/commands/start.js +131 -81
  192. package/dist/cli/commands/tool.js +26 -12
  193. package/dist/cli/fail.d.ts +13 -23
  194. package/dist/cli/fail.js +20 -23
  195. package/dist/cli/invoke-stream.d.ts +1 -8
  196. package/dist/cli/kernel.d.ts +6 -38
  197. package/dist/cli/kernel.js +14 -77
  198. package/dist/cli/models-view.d.ts +1 -9
  199. package/dist/cli/models-view.js +11 -22
  200. package/dist/cli/program.d.ts +5 -6
  201. package/dist/cli/program.js +120 -157
  202. package/dist/cli/serve.d.ts +57 -41
  203. package/dist/cli/serve.js +94 -121
  204. package/dist/cli/shared.d.ts +15 -61
  205. package/dist/cli/shared.js +55 -181
  206. package/dist/cli.js +1 -8
  207. package/dist/collect.d.ts +6 -0
  208. package/dist/collect.js +6 -0
  209. package/dist/core.d.ts +4 -1
  210. package/dist/core.js +9 -7
  211. package/dist/declared-secrets.d.ts +55 -0
  212. package/dist/declared-secrets.js +88 -0
  213. package/dist/deploy/agentcore/aws-cli.d.ts +91 -0
  214. package/dist/deploy/agentcore/aws-cli.js +64 -0
  215. package/dist/deploy/agentcore/destroy.d.ts +51 -0
  216. package/dist/deploy/agentcore/destroy.js +273 -0
  217. package/dist/deploy/agentcore/forwarder.js +28 -79
  218. package/dist/deploy/agentcore/logs.d.ts +2 -18
  219. package/dist/deploy/agentcore/logs.js +27 -51
  220. package/dist/deploy/agentcore/plan.d.ts +85 -105
  221. package/dist/deploy/agentcore/plan.js +152 -314
  222. package/dist/deploy/agentcore/run.d.ts +28 -28
  223. package/dist/deploy/agentcore/run.js +227 -306
  224. package/dist/deploy/agentcore/zip.d.ts +2 -15
  225. package/dist/deploy/agentcore/zip.js +3 -17
  226. package/dist/deploy/build-context.d.ts +21 -0
  227. package/dist/deploy/build-context.js +137 -0
  228. package/dist/deploy/channel-ingress.d.ts +26 -39
  229. package/dist/deploy/channel-ingress.js +57 -28
  230. package/dist/deploy/container.d.ts +20 -34
  231. package/dist/deploy/container.js +49 -100
  232. package/dist/deploy/docker/plan.d.ts +12 -11
  233. package/dist/deploy/docker/plan.js +43 -24
  234. package/dist/deploy/docker/run.d.ts +22 -25
  235. package/dist/deploy/docker/run.js +39 -37
  236. package/dist/deploy/fly/plan.d.ts +15 -44
  237. package/dist/deploy/fly/plan.js +41 -73
  238. package/dist/deploy/fly/run.d.ts +16 -51
  239. package/dist/deploy/fly/run.js +42 -95
  240. package/dist/deploy/hosts.d.ts +24 -3
  241. package/dist/deploy/hosts.js +24 -3
  242. package/dist/deploy/preflight.d.ts +47 -41
  243. package/dist/deploy/preflight.js +282 -383
  244. package/dist/deploy/railway/plan.d.ts +16 -42
  245. package/dist/deploy/railway/plan.js +42 -60
  246. package/dist/deploy/railway/run.d.ts +30 -68
  247. package/dist/deploy/railway/run.js +86 -100
  248. package/dist/deploy/registration-gate.d.ts +6 -13
  249. package/dist/deploy/residency.d.ts +37 -0
  250. package/dist/deploy/residency.js +24 -0
  251. package/dist/deploy/runner.d.ts +10 -9
  252. package/dist/deploy/runner.js +7 -18
  253. package/dist/deploy/secrets.d.ts +40 -41
  254. package/dist/deploy/secrets.js +117 -103
  255. package/dist/deploy/workspace.d.ts +50 -0
  256. package/dist/deploy/workspace.js +197 -0
  257. package/dist/dev-supervisor.d.ts +1 -9
  258. package/dist/dev-supervisor.js +21 -64
  259. package/dist/effect-port.d.ts +50 -0
  260. package/dist/effect-port.js +77 -0
  261. package/dist/engines/pi/agent-session-factory.d.ts +50 -69
  262. package/dist/engines/pi/agent-session-factory.js +249 -146
  263. package/dist/engines/pi/auth.d.ts +15 -11
  264. package/dist/engines/pi/auth.js +96 -99
  265. package/dist/engines/pi/chat.d.ts +1 -5
  266. package/dist/engines/pi/chat.js +2 -14
  267. package/dist/engines/pi/config.d.ts +53 -51
  268. package/dist/engines/pi/config.js +83 -92
  269. package/dist/engines/pi/create.d.ts +60 -75
  270. package/dist/engines/pi/create.js +108 -141
  271. package/dist/engines/pi/definition.d.ts +14 -58
  272. package/dist/engines/pi/definition.js +21 -85
  273. package/dist/engines/pi/invoke-session.d.ts +5 -25
  274. package/dist/engines/pi/invoke-session.js +209 -244
  275. package/dist/engines/pi/login.d.ts +95 -35
  276. package/dist/engines/pi/login.js +259 -107
  277. package/dist/engines/pi/machine.d.ts +31 -0
  278. package/dist/engines/pi/machine.js +106 -0
  279. package/dist/engines/pi/models.d.ts +70 -89
  280. package/dist/engines/pi/models.js +188 -81
  281. package/dist/engines/pi/open.d.ts +65 -53
  282. package/dist/engines/pi/open.js +129 -69
  283. package/dist/engines/pi/report.d.ts +3 -12
  284. package/dist/engines/pi/report.js +2 -16
  285. package/dist/engines/pi/search-tools.d.ts +1 -9
  286. package/dist/engines/pi/search-tools.js +26 -57
  287. package/dist/engines/pi/service.d.ts +2 -16
  288. package/dist/engines/pi/service.js +2 -16
  289. package/dist/engines/pi/session-builder.d.ts +5 -9
  290. package/dist/engines/pi/session-builder.js +44 -82
  291. package/dist/engines/pi/session-control.js +286 -269
  292. package/dist/engines/pi/session-effects.d.ts +14 -0
  293. package/dist/engines/pi/session-effects.js +30 -0
  294. package/dist/engines/pi/session-inheritance.d.ts +9 -18
  295. package/dist/engines/pi/session-inheritance.js +103 -160
  296. package/dist/engines/pi/session-markers.d.ts +31 -30
  297. package/dist/engines/pi/session-markers.js +26 -25
  298. package/dist/engines/pi/session-settings.d.ts +6 -22
  299. package/dist/engines/pi/session-settings.js +10 -21
  300. package/dist/engines/pi/session-store.d.ts +26 -92
  301. package/dist/engines/pi/session-store.js +96 -310
  302. package/dist/engines/pi/tool-context.d.ts +17 -45
  303. package/dist/engines/pi/tool-context.js +7 -26
  304. package/dist/engines/pi/tool.d.ts +45 -36
  305. package/dist/engines/pi/tool.js +43 -57
  306. package/dist/engines/pi/turn-kit.d.ts +14 -52
  307. package/dist/engines/pi/turn-kit.js +18 -67
  308. package/dist/engines/pi/wake-tool.d.ts +2 -10
  309. package/dist/engines/pi/wake-tool.js +7 -27
  310. package/dist/env.d.ts +27 -28
  311. package/dist/env.js +45 -50
  312. package/dist/index.js +0 -2
  313. package/dist/lark.d.ts +1 -2
  314. package/dist/lark.js +1 -2
  315. package/dist/loader.d.ts +14 -55
  316. package/dist/loader.js +24 -43
  317. package/dist/log.d.ts +2 -12
  318. package/dist/log.js +3 -24
  319. package/dist/node.d.ts +2 -15
  320. package/dist/node.js +2 -18
  321. package/dist/observe.d.ts +2 -8
  322. package/dist/open-url.d.ts +1 -1
  323. package/dist/open-url.js +1 -1
  324. package/dist/paths.d.ts +70 -134
  325. package/dist/paths.js +165 -232
  326. package/dist/pi.d.ts +4 -6
  327. package/dist/pi.js +3 -3
  328. package/dist/proxy.d.ts +16 -6
  329. package/dist/proxy.js +52 -16
  330. package/dist/runtime.d.ts +18 -12
  331. package/dist/runtime.js +18 -11
  332. package/dist/scaffold/add-channel.d.ts +14 -31
  333. package/dist/scaffold/add-channel.js +48 -112
  334. package/dist/scaffold/init.d.ts +9 -31
  335. package/dist/scaffold/init.js +45 -138
  336. package/dist/scaffold/templates/env.example +6 -4
  337. package/dist/scaffold/templates/fastagent.config.ts +36 -0
  338. package/dist/scaffold/templates.d.ts +3 -3
  339. package/dist/scaffold/templates.js +5 -8
  340. package/dist/scaffold/vendor-skill.d.ts +2 -5
  341. package/dist/scaffold/vendor-skill.js +19 -29
  342. package/dist/schedule/cron.d.ts +9 -5
  343. package/dist/schedule/cron.js +9 -11
  344. package/dist/schedule/discover.d.ts +12 -12
  345. package/dist/schedule/discover.js +43 -34
  346. package/dist/schedule/routine.d.ts +43 -0
  347. package/dist/schedule/routine.js +32 -0
  348. package/dist/schedule/run.d.ts +55 -0
  349. package/dist/schedule/run.js +146 -0
  350. package/dist/schedule/scheduler.d.ts +44 -55
  351. package/dist/schedule/scheduler.js +291 -265
  352. package/dist/schedule/state.d.ts +105 -10
  353. package/dist/schedule/state.js +293 -19
  354. package/dist/schedule/wake-alarm.d.ts +10 -23
  355. package/dist/schedule/wake-alarm.js +91 -121
  356. package/dist/schedule/wakeups.d.ts +23 -39
  357. package/dist/schedule/wakeups.js +33 -75
  358. package/dist/secrets-gate.d.ts +32 -0
  359. package/dist/secrets-gate.js +33 -0
  360. package/dist/service.d.ts +137 -98
  361. package/dist/service.js +250 -252
  362. package/dist/session-remote.d.ts +33 -44
  363. package/dist/session-remote.js +203 -192
  364. package/dist/session.d.ts +153 -228
  365. package/dist/session.js +33 -55
  366. package/dist/tunnel.d.ts +8 -36
  367. package/dist/tunnel.js +24 -65
  368. package/dist/version.d.ts +2 -2
  369. package/dist/version.js +2 -2
  370. package/package.json +10 -16
  371. package/dist/channels/agentcore-state.d.ts +0 -77
  372. package/dist/channels/agentcore-state.js +0 -276
  373. package/dist/channels/github/github.d.ts +0 -31
  374. package/dist/channels/github/github.js +0 -89
  375. package/dist/channels/github/scaffold/channel.ts +0 -25
  376. package/dist/cli/commands/attach.d.ts +0 -108
  377. package/dist/cli/commands/attach.js +0 -637
  378. package/dist/cli/commands/fire.d.ts +0 -7
  379. package/dist/cli/commands/fire.js +0 -38
  380. package/dist/cli/commands/schedule.d.ts +0 -12
  381. package/dist/cli/commands/schedule.js +0 -87
  382. package/dist/github.d.ts +0 -3
  383. package/dist/github.js +0 -2
  384. package/dist/scaffold/templates/fastagent.config.mjs +0 -23
  385. package/dist/schedule/audit.d.ts +0 -18
  386. package/dist/schedule/audit.js +0 -57
  387. package/dist/schedule/schedule.d.ts +0 -35
  388. package/dist/schedule/schedule.js +0 -23
package/README.md CHANGED
@@ -16,12 +16,12 @@
16
16
  <sub>— the agent harness &amp; multi-provider LLM API under the hood</sub>
17
17
  </p>
18
18
 
19
- A file-defined agent directory can become a live service. FastAgent takes it out of the terminal and serves it in your Next/Astro app, Telegram, GitHub/webhook events, an API endpoint, or your own channel.
19
+ A file-defined agent directory can become a live service. FastAgent takes it out of the terminal and serves it in your Next/Astro app, Telegram, Slack, Feishu, an API endpoint, or your own channel.
20
20
 
21
21
  Leave the terminal. Become a live service.
22
22
 
23
23
  - **Add it to your app** — one route, your auth, your database, your host.
24
- - **Run it as a live service** — Telegram support, GitHub PR review, webhook handler, API endpoint, or custom channel.
24
+ - **Run it as a live service** — Telegram, Slack or Feishu bot, webhook handler, API endpoint, or custom channel.
25
25
 
26
26
  FastAgent is not a new agent-authoring DSL. You bring the existing definition and project layout; FastAgent provides the serving runtime and adapters around it.
27
27
 
@@ -37,8 +37,8 @@ FastAgent is the missing bridge from local agent directory to live service.
37
37
 
38
38
  ## Features
39
39
 
40
- - **Vibe first — a directory is an agent.** Point FastAgent at the `AGENTS.md` + `skills/` you already vibed in a coding agent. Markdown instructions, reusable skills, and TypeScript tools stay as files you inspect, edit, and commit — no new DSL, no framework rewrite.
41
- - **Channels.** Serve the same agent as a GitHub PR reviewer, a Telegram bot, a Feishu or Lark bot, an HTTP/SSE endpoint, or your own adapter: verified webhooks, streaming replies, group-aware.
40
+ - **Vibe first — add a `fastagent/` folder to any project.** The agent is that folder; the project around it is what it works on, and the project's `AGENTS.md` is its context. Markdown instructions, reusable skills, and TypeScript tools stay as files you inspect, edit, and commit — no new DSL, no framework rewrite.
41
+ - **Channels.** Serve the same agent as a Telegram bot, a Slack app, a Feishu or Lark bot, an HTTP/SSE endpoint, or your own adapter: verified webhooks, streaming replies, group-aware.
42
42
  - **Models, tools & skills.** Any model provider (OpenAI, Anthropic, Google, …) via OAuth or API key; typed tools discovered from `tools/` (the filename is the name, Zod-validated); Agent Skills loaded on demand. Built on the open-source [pi](https://github.com/earendil-works/pi) harness.
43
43
  - **App embedding — your stack, we plug in.** Mount the agent in your Next / Astro / Hono / Bun / Node route with one handler, or call `invoke` like any function from your own code — your auth, your database, your infra. FastAgent composes with your app, never owns it.
44
44
  - **Deploy anywhere.** No application build step — the directory is the deployable unit. `fastagent deploy docker|fly|railway|agentcore` generates the container + target config and a runbook (`--run` drives it to completion). Local Docker gets user-owned Compose + durable state; optional `--tunnel` adds an ephemeral Quick Tunnel service for webhook channels; AWS Bedrock AgentCore gets a one-stack CloudFormation topology (webhooks via a forwarder Lambda, schedules via EventBridge). Durable ingress remains yours.
@@ -102,7 +102,7 @@ For production-style local serving:
102
102
  fastagent start
103
103
  ```
104
104
 
105
- There is no FastAgent build step: the directory is the agent.
105
+ There is no FastAgent build step: the agent folder is the deployable unit.
106
106
 
107
107
  ## Embed in an app
108
108
 
@@ -150,7 +150,7 @@ const agent = createPiAgent({
150
150
  | [Embedding](https://fastagent.sh/docs/embedding/) | Use FastAgent as a library inside your own app |
151
151
  | [Channels](https://fastagent.sh/docs/channels/) | Add webhook/bot channels |
152
152
  | [Deploy](https://fastagent.sh/docs/deploy/) | Ship the directory to Fly, Railway, or any Docker host |
153
- | [GitHub](https://fastagent.sh/docs/github/) / [Telegram](https://fastagent.sh/docs/telegram/) / [Slack](https://fastagent.sh/docs/slack/) / [Feishu and Lark](https://fastagent.sh/docs/feishu/) | First-party channel guides |
153
+ | [Telegram](https://fastagent.sh/docs/telegram/) / [Slack](https://fastagent.sh/docs/slack/) / [Feishu and Lark](https://fastagent.sh/docs/feishu/) | First-party channel guides |
154
154
  | [Channel development](https://fastagent.sh/docs/channel-development/) | Build custom channel adapters |
155
155
  | [API reference](https://fastagent.sh/docs/api-reference/) | Public TypeScript API reference |
156
156
  | [Troubleshooting](https://fastagent.sh/docs/troubleshooting/) | Common setup/runtime issues |
@@ -181,9 +181,9 @@ you register a custom provider.
181
181
  | Mounting | `createInvokeHandler`, `Routes`, `ChannelHandler` | Reference implementation, pre-1.0 |
182
182
  | Node binding | `nodeListener`, `serveNode` (from `/node`) | The one runtime-specific piece; see below |
183
183
  | pi assembly | `createPiAgentFromDir`, `createPiAgentFromDefinition`, `createPiAgent` | Usable now, may tighten before 1.0 |
184
- | Tool/channel authoring | `defineTool`, `z`, `defineSchedule`, `ChannelModule` | Usable now, may tighten before 1.0 |
184
+ | Tool/channel authoring | `defineTool`, `z`, `defineRoutine`, `ChannelModule` | Usable now, may tighten before 1.0 |
185
185
  | Injection ports | `PiSessionRecordStore`, `piSessionRecordStore`, `piInMemorySessionRecordStore`, `Lease`, `Provider` | Public because options reference them |
186
- | Not exported | The assembly's parts — `router`, `createControlPlane`, `loadTools`/`loadChannels`/`loadSchedules`, `createScheduler` — and prompt/config internals | `createAgentService` does this; no compatibility promise |
186
+ | Not exported | The assembly's parts — `router`, `createControlPlane`, `loadTools`/`loadChannels`/`loadRoutines`, `createScheduler` — and prompt/config internals | `createAgentService` does this; no compatibility promise |
187
187
 
188
188
  Subpath entry points (`./package.json` is also exported, for tools that read the version):
189
189
 
@@ -191,7 +191,6 @@ Subpath entry points (`./package.json` is also exported, for tools that read the
191
191
  - `@fastagent-sh/fastagent/node` — the engine-neutral pieces that need a Node runtime: `mountAgentService` (the assembly), `serveNode` / `nodeListener` (the `node:http` ↔ Fetch binding);
192
192
  - `@fastagent-sh/fastagent/session` — the engine-neutral session-control contract (types and error codes);
193
193
  - `@fastagent-sh/fastagent/pi` — the pi reference implementation;
194
- - `@fastagent-sh/fastagent/github` — GitHub webhook channel;
195
194
  - `@fastagent-sh/fastagent/telegram` — Telegram bot channel;
196
195
  - `@fastagent-sh/fastagent/slack` — Slack Events API bot channel;
197
196
  - `@fastagent-sh/fastagent/feishu` — canonical Feishu bot channel (飞书, open.feishu.cn);
@@ -205,9 +204,7 @@ test/ vitest suite (faux models by default) + reusable SPEC conformance
205
204
  docs/ user docs, SPEC, and maintainer design notes
206
205
  ```
207
206
 
208
- Single package, likely long-term; subpath exports (not sibling packages) are the module boundary.
209
- A `packages/` workspace split is deliberately deferred until a second published artifact with
210
- independent dependencies/versioning actually exists.
207
+ One package; subpath exports are the module boundary.
211
208
 
212
209
  ## Status
213
210
 
package/dist/agent.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Agent Handler protocol v0.1 — the engine-neutral contract (docs/SPEC.md). Pure types, zero
3
- * dependencies. Importing any engine implementation here is forbidden (`@earendil-works/pi-*` may
4
- * only appear under engines/).
2
+ * Agent Handler protocol v0.1 — the engine-neutral contract (docs/SPEC.md). Pure types: importing an engine here is
3
+ * forbidden (`@earendil-works/pi-*` may only appear under engines/).
5
4
  */
6
5
  export type Json = null | boolean | number | string | Json[] | {
7
6
  [k: string]: Json;
@@ -15,27 +14,25 @@ export interface Prompt {
15
14
  text: string;
16
15
  images?: ImageRef[];
17
16
  }
18
- /** Invocation scope. Core keeps only the `session` anchor; other fields are extensions (SPEC §8). */
19
17
  export interface Scope {
20
18
  /** Opaque session anchor: turns of the same logical conversation MUST reuse the same value. */
21
19
  session: string;
22
- /** EXTENSION (SPEC §8): the session this one branched from — a channel sets it when the place it
23
- * is invoking for was born out of another place (a thread opened in a room). Read ONLY when
24
- * `session` does not exist yet: an engine that understands it seeds the NEW session from the
25
- * parent once, at creation; after that the field is ignored, and an engine that does not
26
- * understand it ignores it entirely (the session starts empty, yesterday's behavior). */
20
+ /**
21
+ * EXTENSION (SPEC §8): the session this one branched from — a channel sets it when the place it is invoking for was
22
+ * born out of another place (a thread opened in a room).
23
+ */
27
24
  parentSession?: string;
28
- /** EXTENSION (SPEC §8): opaque markers that MAY locate the branch point inside `parentSession` —
29
- * e.g. platform message ids its transcript embeds. Best-effort by design: the first marker found
30
- * in the parent's transcript wins, and no match falls back to the parent's present. Meaningless
31
- * without `parentSession`. */
25
+ /**
26
+ * EXTENSION (SPEC §8): opaque markers that MAY locate the branch point inside `parentSession` — e.g. platform
27
+ * message ids its transcript embeds.
28
+ */
32
29
  branchHints?: string[];
33
30
  }
34
31
  export type AgentEvent = {
35
32
  type: "text";
36
33
  delta: string;
37
34
  }
38
- /** Model reasoning, streamed live. Process, NOT the answer: consumers MUST NOT fold it into the final text. */
35
+ /** Model reasoning, streamed live. */
39
36
  | {
40
37
  type: "thinking";
41
38
  delta: string;
@@ -50,10 +47,10 @@ export type AgentEvent = {
50
47
  isError: boolean;
51
48
  content: Json;
52
49
  }
53
- /** Advisory, non-terminal (engines MAY emit it): a transient internal failure scheduled a retry
54
- * with backoff — the turn is still alive. Explains a quiet gap that would otherwise read as a
55
- * hang; deliberately unclosed — the next event is its closure. Terminal consumers ignore it
56
- * (SPEC MUST 4). */
50
+ /**
51
+ * Advisory, non-terminal (engines MAY emit it): a transient internal failure scheduled a retry with backoff — the
52
+ * turn is still alive.
53
+ */
57
54
  | {
58
55
  type: "retrying";
59
56
  attempt: number;
@@ -61,14 +58,12 @@ export type AgentEvent = {
61
58
  delayMs: number;
62
59
  reason: string;
63
60
  }
64
- /** Terminal: success. `data` is attached only when the engine produces a structured result. */
61
+ /** Terminal: success. */
65
62
  | {
66
63
  type: "completed";
67
64
  data?: Json;
68
65
  }
69
- /** Terminal: failure. `retryable` means it is worth re-sending with the same session. `code` is the
70
- * optional machine-readable failure subdivision (SPEC §8) — a stable discriminator a consumer can branch
71
- * on without parsing `details` (human-facing prose). */
66
+ /** Terminal: failure. */
72
67
  | {
73
68
  type: "failed";
74
69
  details: string;
@@ -76,27 +71,19 @@ export type AgentEvent = {
76
71
  code?: string;
77
72
  };
78
73
  /**
79
- * The `failed.code` (SPEC §8 failure subdivision) the reference engine sets when a turn is rejected because
80
- * the session is BUSY — another turn is already in flight, so THIS one never started and is replay-safe.
81
- * It lives in the contract (a code VALUE, not an engine import) so a neutral consumer — the scheduler,
82
- * which re-fires a busy wake-up but not one whose turn may have run side effects — branches on it without
83
- * text-matching `details` or reaching into the engine. An internal fastagent seam (engine ↔ scheduler),
84
- * not a public cross-engine mandate.
74
+ * The `failed.code` (SPEC §8 failure subdivision) the reference engine sets when a turn is rejected because the
75
+ * session is BUSY.
85
76
  */
86
77
  export declare const SESSION_BUSY_CODE = "session_busy";
87
78
  /**
88
- * The `failed.code` set when a run was DELIBERATELY stopped — a control-plane abort, or any
89
- * engine-level abort it attributes (`stopReason: "aborted"`) — rather than failing on its
90
- * own. Channels can render cancellation distinctly from an error, and MUST treat it as a settled
91
- * outcome — durable turn-intent cleanup included — so a deliberate stop is never replayed as a
92
- * fresh turn on restart. Exported as a constant for the same reason as {@link SESSION_BUSY_CODE}:
93
- * a consumer that must branch on it should not string-match.
79
+ * The `failed.code` set when a run was DELIBERATELY stopped. A channel MAY render cancellation distinctly from an
80
+ * error, and MUST treat it as a settled outcome — durable turn-intent cleanup included — so a deliberate stop is
81
+ * never replayed as a fresh turn on restart.
94
82
  */
95
83
  export declare const ABORTED_CODE = "aborted";
96
84
  /**
97
- * One turn = one invoke, returning a single async event stream. The stream MUST terminate with
98
- * exactly one of completed / failed, or be cancelled by the caller (no terminal event). Any
99
- * AsyncIterable producer that implements this conforms (interface, not base class).
85
+ * One turn = one invoke, returning a single async event stream. The stream MUST terminate with exactly one of
86
+ * `completed` / `failed`, or be cancelled by the caller (no terminal event).
100
87
  */
101
88
  export interface Agent {
102
89
  invoke(scope: Scope, prompt: Prompt): AsyncIterable<AgentEvent>;
package/dist/agent.js CHANGED
@@ -1,23 +1,15 @@
1
1
  /**
2
- * Agent Handler protocol v0.1 — the engine-neutral contract (docs/SPEC.md). Pure types, zero
3
- * dependencies. Importing any engine implementation here is forbidden (`@earendil-works/pi-*` may
4
- * only appear under engines/).
2
+ * Agent Handler protocol v0.1 — the engine-neutral contract (docs/SPEC.md). Pure types: importing an engine here is
3
+ * forbidden (`@earendil-works/pi-*` may only appear under engines/).
5
4
  */
6
5
  /**
7
- * The `failed.code` (SPEC §8 failure subdivision) the reference engine sets when a turn is rejected because
8
- * the session is BUSY — another turn is already in flight, so THIS one never started and is replay-safe.
9
- * It lives in the contract (a code VALUE, not an engine import) so a neutral consumer — the scheduler,
10
- * which re-fires a busy wake-up but not one whose turn may have run side effects — branches on it without
11
- * text-matching `details` or reaching into the engine. An internal fastagent seam (engine ↔ scheduler),
12
- * not a public cross-engine mandate.
6
+ * The `failed.code` (SPEC §8 failure subdivision) the reference engine sets when a turn is rejected because the
7
+ * session is BUSY.
13
8
  */
14
9
  export const SESSION_BUSY_CODE = "session_busy";
15
10
  /**
16
- * The `failed.code` set when a run was DELIBERATELY stopped — a control-plane abort, or any
17
- * engine-level abort it attributes (`stopReason: "aborted"`) — rather than failing on its
18
- * own. Channels can render cancellation distinctly from an error, and MUST treat it as a settled
19
- * outcome — durable turn-intent cleanup included — so a deliberate stop is never replayed as a
20
- * fresh turn on restart. Exported as a constant for the same reason as {@link SESSION_BUSY_CODE}:
21
- * a consumer that must branch on it should not string-match.
11
+ * The `failed.code` set when a run was DELIBERATELY stopped. A channel MAY render cancellation distinctly from an
12
+ * error, and MUST treat it as a settled outcome — durable turn-intent cleanup included — so a deliberate stop is
13
+ * never replayed as a fresh turn on restart.
22
14
  */
23
15
  export const ABORTED_CODE = "aborted";
@@ -1,23 +1,19 @@
1
1
  /**
2
2
  * Write a file so a reader sees the whole thing or nothing: same-directory temp, then rename.
3
3
  *
4
- * The temp name is fixed (`<path>.tmp`). It holds wherever one process writes one state root: a
5
- * deployment runs one container, `dev`'s supervisor respawns its worker only after the old one has
6
- * EXITED (dev-supervisor.ts), and these writes are synchronous, so an exited process has none in
7
- * flight. Slack's onboarding state is the one file with two writers — `add slack`, and the
8
- * config-token rotation inside `--tunnel` webhook registration — so a second terminal running
9
- * `add slack --replace-config` can overlap a live `dev --tunnel`. Kept fixed anyway: that window is
10
- * a single write at tunnel startup, its repair is the `add slack --replace-config` the registration
11
- * failure already prints, and the fixed name is the seam several channel tests use to inject a write
12
- * failure by occupying that path with a directory. Revisit for a writer that is neither rare nor
13
- * self-repairing.
4
+ * The temp name is FIXED (`<path>.tmp`), which rests on one process writing one state root: a deployment runs one
5
+ * container, `dev`'s supervisor respawns its worker only after the old one has exited, and these writes are
6
+ * synchronous. Slack's onboarding state is the documented exception (`add slack` plus the config-token rotation at
7
+ * `--tunnel` startup); it stays fixed because that window is one rare, self-repairing write, and because the fixed
8
+ * name is the seam channel tests use to inject a write failure. Revisit before adding a writer that is neither.
14
9
  *
15
- * `mode` is applied to the temp first, so the content is never briefly world-readable.
10
+ * `mode` is applied to the temp first, so the content is never briefly world-readable, and the `chmod` is not
11
+ * redundant with it: `writeFileSync` honours `mode` only when it CREATES the file, so a temp left behind by a crashed
12
+ * writer would keep its old, possibly looser permissions.
16
13
  *
17
- * The `chmod` is NOT redundant with the `mode` option: `writeFileSync` applies `mode` only when it
18
- * CREATES the file, so a temp left behind by a crashed writer keeps its old, possibly loose
19
- * permissions and the rename publishes them (verified: 0644 survives a `{ mode: 0o600 }` write).
20
- * It runs on the temp, before the rename — the final path is then never observable with the wrong
21
- * permissions, which a chmod after the rename cannot promise.
14
+ * `sharedWriters` is for a file SEVERAL processes may write at once (the merged models file, content-addressed, so
15
+ * every writer writes the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
16
+ * let one writer's rename take the other's file and fail it with ENOENT. No test exercises that race: it needs two
17
+ * processes renaming within the same moment, which a test cannot arrange without being flaky.
22
18
  */
23
- export declare function writeFileAtomic(path: string, data: string | Buffer, mode?: number): void;
19
+ export declare function writeFileAtomic(path: string, data: string | Buffer, mode?: number, sharedWriters?: boolean): void;
@@ -1,39 +1,28 @@
1
- /**
2
- * One spelling of "a reader sees the whole file or none of it", after five copies of it drifted
3
- * apart: two identical, three with different temp names and different permission handling.
4
- *
5
- * Synchronous, and there is no async sibling: every caller either sits on a path where a KB-sized
6
- * write must complete BEFORE a transport ACK (channel state — an ACKed delivery is not redelivered)
7
- * or on a CLI/startup path where the cost is not observable. An async spelling would buy one of them
8
- * nothing and cost this module a second set of rules to keep true.
9
- */
1
+ /** One spelling of "a reader sees the whole file or none of it", for every state writer. */
10
2
  import { chmodSync, mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
+ import { randomUUID } from "node:crypto";
11
4
  import { dirname } from "node:path";
12
5
  /**
13
6
  * Write a file so a reader sees the whole thing or nothing: same-directory temp, then rename.
14
7
  *
15
- * The temp name is fixed (`<path>.tmp`). It holds wherever one process writes one state root: a
16
- * deployment runs one container, `dev`'s supervisor respawns its worker only after the old one has
17
- * EXITED (dev-supervisor.ts), and these writes are synchronous, so an exited process has none in
18
- * flight. Slack's onboarding state is the one file with two writers — `add slack`, and the
19
- * config-token rotation inside `--tunnel` webhook registration — so a second terminal running
20
- * `add slack --replace-config` can overlap a live `dev --tunnel`. Kept fixed anyway: that window is
21
- * a single write at tunnel startup, its repair is the `add slack --replace-config` the registration
22
- * failure already prints, and the fixed name is the seam several channel tests use to inject a write
23
- * failure by occupying that path with a directory. Revisit for a writer that is neither rare nor
24
- * self-repairing.
8
+ * The temp name is FIXED (`<path>.tmp`), which rests on one process writing one state root: a deployment runs one
9
+ * container, `dev`'s supervisor respawns its worker only after the old one has exited, and these writes are
10
+ * synchronous. Slack's onboarding state is the documented exception (`add slack` plus the config-token rotation at
11
+ * `--tunnel` startup); it stays fixed because that window is one rare, self-repairing write, and because the fixed
12
+ * name is the seam channel tests use to inject a write failure. Revisit before adding a writer that is neither.
25
13
  *
26
- * `mode` is applied to the temp first, so the content is never briefly world-readable.
14
+ * `mode` is applied to the temp first, so the content is never briefly world-readable, and the `chmod` is not
15
+ * redundant with it: `writeFileSync` honours `mode` only when it CREATES the file, so a temp left behind by a crashed
16
+ * writer would keep its old, possibly looser permissions.
27
17
  *
28
- * The `chmod` is NOT redundant with the `mode` option: `writeFileSync` applies `mode` only when it
29
- * CREATES the file, so a temp left behind by a crashed writer keeps its old, possibly loose
30
- * permissions and the rename publishes them (verified: 0644 survives a `{ mode: 0o600 }` write).
31
- * It runs on the temp, before the rename — the final path is then never observable with the wrong
32
- * permissions, which a chmod after the rename cannot promise.
18
+ * `sharedWriters` is for a file SEVERAL processes may write at once (the merged models file, content-addressed, so
19
+ * every writer writes the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
20
+ * let one writer's rename take the other's file and fail it with ENOENT. No test exercises that race: it needs two
21
+ * processes renaming within the same moment, which a test cannot arrange without being flaky.
33
22
  */
34
- export function writeFileAtomic(path, data, mode) {
23
+ export function writeFileAtomic(path, data, mode, sharedWriters = false) {
35
24
  mkdirSync(dirname(path), { recursive: true });
36
- const tmp = `${path}.tmp`;
25
+ const tmp = sharedWriters ? `${path}.${process.pid}.${randomUUID()}.tmp` : `${path}.tmp`;
37
26
  try {
38
27
  writeFileSync(tmp, data, mode === undefined ? undefined : { mode });
39
28
  if (mode !== undefined)
@@ -45,8 +34,8 @@ export function writeFileAtomic(path, data, mode) {
45
34
  rmSync(tmp, { force: true });
46
35
  }
47
36
  catch {
48
- // `force` only forgives ENOENT: if the temp is a directory, rmSync throws its own error and
49
- // would replace the write failure that actually explains what went wrong.
37
+ // `force` only forgives ENOENT: if the temp is a directory, rmSync throws its own error and would replace the
38
+ // write failure that actually explains what went wrong.
50
39
  }
51
40
  throw error;
52
41
  }
package/dist/bind.d.ts CHANGED
@@ -1,34 +1,24 @@
1
- /** A bindable host: an IP literal (v4/v6, brackets optional) or "localhost". No other DNS name — a
2
- * bind address must be an address of THIS machine, and resolving one is not this module's job. */
1
+ /** A bindable host: an IP literal (v4/v6, brackets optional) or "localhost". */
3
2
  export declare function isBindAddress(host: string): boolean;
4
3
  /**
5
- * The ADDRESS form of an accepted bind value: `localhost` becomes `127.0.0.1`, everything else is
6
- * already an address. Applied where a value ENTERS (the flag, `http.host`), so nothing downstream ever
7
- * holds a name — not deferring the resolution but removing it, which is the module's whole point.
8
- *
9
- * Two things go wrong otherwise, and both are silent. `server.listen` hands the name to `dns.lookup`,
10
- * which picks ONE of 127.0.0.1/::1 by rules we do not control — so what got bound is unknown here. And
11
- * `clientHost` would then write that NAME into control.json and the copyable curl, where a consumer
12
- * resolves it again, possibly to the other one.
4
+ * The ADDRESS form of an accepted bind value: `localhost` becomes `127.0.0.1`, everything else is already an address.
13
5
  */
14
6
  export declare function bindAddress(host: string): string;
15
7
  /**
16
- * How far a bind address reaches: `wildcard` (unset or all-interfaces) reaches every interface and
17
- * answers on loopback too; `loopback` is this machine only; `specific` is one interface, reachable
18
- * only as itself. Loopback covers the whole reserved range (127/8, ::1) — a `127.0.0.2` bind is no
19
- * more LAN-reachable than `127.0.0.1`.
8
+ * How far a bind address reaches: `wildcard` (unset or all-interfaces) reaches every interface and answers on
9
+ * loopback too; `loopback` is this machine only; `specific` is one interface, reachable only as itself.
20
10
  */
21
11
  export declare function classifyBind(host: string | undefined): "wildcard" | "loopback" | "specific";
22
12
  /**
23
- * Does a serve bound to `host` answer a dial of the NAME `localhost`? Only the addresses that name
24
- * resolves to (127.0.0.1 / ::1) and a wildcard bind do — `127.0.0.2` is loopback yet unreachable that
25
- * way. cloudflared dials by name, so `--tunnel` needs this question, not `classifyBind`'s reach.
13
+ * Does a serve bound to `host` answer a dial of the NAME `localhost`? Only the addresses that name resolves to
14
+ * (127.0.0.1 / ::1) and a wildcard bind do — `127.0.0.2` is loopback yet unreachable that way. That is why this is not
15
+ * {@link classifyBind}'s reach question: cloudflared dials by name, so `--tunnel` needs this one.
26
16
  */
27
17
  export declare function answersLocalhost(host: string | undefined): boolean;
28
- /** How to NAME a bind in a message: the wildcard is every interface, so calling it one address would
29
- * understate it; anything else is dialable as itself. THE renderer — the ready lines, the
30
- * already-in-use refusal and the generic bind failure all read a bind through this one, so a reader
31
- * never sees the same bind described two ways. */
18
+ /**
19
+ * How to NAME a bind in a message: the wildcard is every interface, so calling it one address would understate it;
20
+ * anything else is dialable as itself.
21
+ */
32
22
  export declare function bindLabel(host: string | undefined, port: number): string;
33
- /** The address a local client should dial for a serve bound to `host` (control.json, the ready log). */
23
+ /** The address a local client should dial for a serve bound to `host` (the ready log's curl). */
34
24
  export declare function clientHost(host: string | undefined): string;
package/dist/bind.js CHANGED
@@ -1,41 +1,32 @@
1
1
  /**
2
- * The ONE reading of a bind address, shared by everything that parses, binds, warns about, or ships
3
- * one (the CLI flag, `http.host` validation, the Node host, the deploy pre-flight). Engine- and
4
- * host-neutral on purpose: a bind address is a plain value, and two parsers of it would disagree.
2
+ * The ONE reading of a bind address, shared by everything that parses, binds, warns about, or ships one (the CLI flag, the
3
+ * Node host, the startup report).
5
4
  */
6
5
  import { isIP } from "node:net";
7
- /** Lowercase, unbracketed, IPv4-mapped IPv6 reduced to its IPv4 form — the form the checks below read.
8
- * Brackets come off only as a PAIR: a half-bracketed `[::1` must stay invalid, not become an address. */
6
+ /**
7
+ * Lowercase, unbracketed, IPv4-mapped IPv6 reduced to its IPv4 form — the form the checks below read. Brackets come
8
+ * off only as a PAIR: a half-bracketed `[::1` must stay invalid, not become an address.
9
+ */
9
10
  function normalize(host) {
10
11
  return host
11
12
  .toLowerCase()
12
13
  .replace(/^\[(.+)]$/, "$1")
13
14
  .replace(/^::ffff:/, "");
14
15
  }
15
- /** A bindable host: an IP literal (v4/v6, brackets optional) or "localhost". No other DNS name — a
16
- * bind address must be an address of THIS machine, and resolving one is not this module's job. */
16
+ /** A bindable host: an IP literal (v4/v6, brackets optional) or "localhost". */
17
17
  export function isBindAddress(host) {
18
18
  const h = normalize(host);
19
19
  return h === "localhost" || isIP(h) !== 0;
20
20
  }
21
21
  /**
22
- * The ADDRESS form of an accepted bind value: `localhost` becomes `127.0.0.1`, everything else is
23
- * already an address. Applied where a value ENTERS (the flag, `http.host`), so nothing downstream ever
24
- * holds a name — not deferring the resolution but removing it, which is the module's whole point.
25
- *
26
- * Two things go wrong otherwise, and both are silent. `server.listen` hands the name to `dns.lookup`,
27
- * which picks ONE of 127.0.0.1/::1 by rules we do not control — so what got bound is unknown here. And
28
- * `clientHost` would then write that NAME into control.json and the copyable curl, where a consumer
29
- * resolves it again, possibly to the other one.
22
+ * The ADDRESS form of an accepted bind value: `localhost` becomes `127.0.0.1`, everything else is already an address.
30
23
  */
31
24
  export function bindAddress(host) {
32
25
  return normalize(host) === "localhost" ? "127.0.0.1" : host;
33
26
  }
34
27
  /**
35
- * How far a bind address reaches: `wildcard` (unset or all-interfaces) reaches every interface and
36
- * answers on loopback too; `loopback` is this machine only; `specific` is one interface, reachable
37
- * only as itself. Loopback covers the whole reserved range (127/8, ::1) — a `127.0.0.2` bind is no
38
- * more LAN-reachable than `127.0.0.1`.
28
+ * How far a bind address reaches: `wildcard` (unset or all-interfaces) reaches every interface and answers on
29
+ * loopback too; `loopback` is this machine only; `specific` is one interface, reachable only as itself.
39
30
  */
40
31
  export function classifyBind(host) {
41
32
  if (host === undefined)
@@ -48,9 +39,9 @@ export function classifyBind(host) {
48
39
  return "specific";
49
40
  }
50
41
  /**
51
- * Does a serve bound to `host` answer a dial of the NAME `localhost`? Only the addresses that name
52
- * resolves to (127.0.0.1 / ::1) and a wildcard bind do — `127.0.0.2` is loopback yet unreachable that
53
- * way. cloudflared dials by name, so `--tunnel` needs this question, not `classifyBind`'s reach.
42
+ * Does a serve bound to `host` answer a dial of the NAME `localhost`? Only the addresses that name resolves to
43
+ * (127.0.0.1 / ::1) and a wildcard bind do — `127.0.0.2` is loopback yet unreachable that way. That is why this is not
44
+ * {@link classifyBind}'s reach question: cloudflared dials by name, so `--tunnel` needs this one.
54
45
  */
55
46
  export function answersLocalhost(host) {
56
47
  if (classifyBind(host) === "wildcard")
@@ -58,14 +49,14 @@ export function answersLocalhost(host) {
58
49
  const h = normalize(host);
59
50
  return h === "localhost" || h === "127.0.0.1" || h === "::1";
60
51
  }
61
- /** How to NAME a bind in a message: the wildcard is every interface, so calling it one address would
62
- * understate it; anything else is dialable as itself. THE renderer — the ready lines, the
63
- * already-in-use refusal and the generic bind failure all read a bind through this one, so a reader
64
- * never sees the same bind described two ways. */
52
+ /**
53
+ * How to NAME a bind in a message: the wildcard is every interface, so calling it one address would understate it;
54
+ * anything else is dialable as itself.
55
+ */
65
56
  export function bindLabel(host, port) {
66
57
  return classifyBind(host) === "wildcard" ? `port ${port}` : `${clientHost(host)}:${port}`;
67
58
  }
68
- /** The address a local client should dial for a serve bound to `host` (control.json, the ready log). */
59
+ /** The address a local client should dial for a serve bound to `host` (the ready log's curl). */
69
60
  export function clientHost(host) {
70
61
  if (classifyBind(host) === "wildcard")
71
62
  return "127.0.0.1";
package/dist/channel.d.ts CHANGED
@@ -1,55 +1,33 @@
1
1
  /**
2
- * The Channel contract — the trigger side of the product boundary (core.md §1), beside `agent.ts`
3
- * (what an engine implements) and `session.ts` (the serving control plane). Pure types, no runtime
4
- * dependency; importing a host, a framework, or an engine here is forbidden, as in those two.
5
- *
6
- * §7 fixes two module forms: a function is a route channel, an object with `connect` is a long
7
- * connection. An agent directory ships hand-written `channels/*.ts` against them, which is why they
8
- * live away from the code that serves them — a WebSocket ingress needs `LongConnection` and has no
9
- * HTTP in it, and a `ChannelModule` import must not drag `node:http` in behind it.
10
- *
11
- * How a route table becomes a running server: `channels/serve.ts`.
2
+ * The Channel contract — the trigger side of the product boundary (core.md §1), beside `agent.ts` (what an engine
3
+ * implements) and `session.ts` (the serving control plane). Pure types: importing a host, a framework, or an engine
4
+ * here is forbidden, as in those two.
12
5
  */
13
6
  import type { Agent } from "./agent.ts";
14
7
  import type { SessionControl } from "./session.ts";
15
- /** A mounted request handler (a channel's fetch, or a plain route like health). Fetch-shaped by
16
- * contract (SPEC §11): the one signature every runtime and embedding app already speaks. */
8
+ /** A mounted request handler (a channel's fetch, or a plain route like health). */
17
9
  export type ChannelHandler = (req: Request) => Response | Promise<Response>;
18
- /**
19
- * This deployment's HTTP surface: route key → handler.
20
- *
21
- * A key is `"/path"` (any method) or `"METHOD /path"`, with a LITERAL path — small on purpose, so
22
- * that "would these two fight over a request?" is string equality rather than a prediction about a
23
- * matcher, and no channel silently shadows another. `assertRouteKey` in `channels/serve.ts`
24
- * enforces it; a handler owning a prefix is a `PrefixMount`, never a key.
25
- */
10
+ /** This deployment's HTTP surface: route key → handler. */
26
11
  export type Routes = Record<string, ChannelHandler>;
27
12
  /**
28
- * What the framework hands a channel at mount time: the assembled agent plus the resolved state ROOT
29
- * (absolute; `FASTAGENT_STATE_DIR` > `<root>/.state`). Channels derive their OWN durable home from
30
- * it (`<stateRoot>/channels/<kind>/`) — they never anchor on `process.cwd()`. env is the OPERATOR
31
- * input plane; this context is how the resolved result reaches code (embedders without the agent
32
- * opener construct it explicitly).
13
+ * What the framework hands a channel at mount time: the assembled agent plus the resolved state ROOT (absolute;
14
+ * `FASTAGENT_STATE_DIR` > `<root>/.state`).
33
15
  */
34
16
  export interface ChannelContext {
35
17
  agent: Agent;
36
18
  stateRoot: string;
37
- /** The serving session-control hub, when the serve wires one (`config.sessionControl`). Channels
38
- * use it for DISPATCH only (the user-facing stop command); observation stays on the data plane. */
19
+ /** The serving session-control hub: every serve has it, so a stop command reaches the live run through it.
20
+ * `config.sessionControl` decides only whether the SAME hub is also published as `/control/*` (and wires its
21
+ * write side). Absent only when an embedder mounts a service without one. */
39
22
  control?: SessionControl;
40
23
  }
41
24
  /** A `channels/<name>.ts` route channel: receives mount context and returns its HTTP routes. */
42
25
  export type ChannelModule = (ctx: ChannelContext) => Routes;
43
- /** One logical long connection's lifecycle. `ready` settles after its first usable connection — and
44
- * when `signal` aborts before one exists it must still settle: resolution then means cancellation, not
45
- * readiness (the server skips ready-side effects once the signal is aborted; it must never hang).
46
- * `closed` resolves after abort-driven shutdown and rejects on a terminal connection failure. */
47
26
  export interface LongConnection {
48
27
  ready: Promise<void>;
49
28
  closed: Promise<void>;
50
29
  }
51
- /** A long-connection channel is an explicit module object rather than an HTTP-route factory.
52
- * The adapter owns reconnects and treats `signal` as its sole shutdown command. */
30
+ /** A long-connection channel is an explicit module object rather than an HTTP-route factory. */
53
31
  export interface LongConnectionChannelModule {
54
32
  name: string;
55
33
  connect(ctx: ChannelContext, signal: AbortSignal): LongConnection;
@@ -1,16 +1,5 @@
1
- /**
2
- * The HOST's body ceilings, and the one place they are computed.
3
- *
4
- * Lambda Function URLs cap a request at 6 MB, so the forwarder cannot deliver more than that no
5
- * matter what the adapter accepts; the body arrives base64-encoded (×4/3) inside a JSON envelope, so
6
- * the ORIGINAL body ceiling is smaller still. This is a real capability difference from a resident
7
- * host — the GitHub channel's own contract is 25 MiB — which is why `deploy agentcore` states it at
8
- * plan time rather than letting an oversized payload surface as an opaque 502.
9
- */
10
- /**
11
- * Maximum original webhook body after reserving JSON-envelope overhead and base64 expansion.
12
- * Enforced by both the public forwarder and the runtime adapter.
13
- */
1
+ /** The HOST's body ceilings, and the one place they are computed. */
2
+ /** Maximum original webhook body after reserving JSON-envelope overhead and base64 expansion. */
14
3
  export declare const MAX_WEBHOOK_BODY_BYTES: number;
15
4
  /** Largest complete AgentCore envelope accepted by the runtime adapter. */
16
5
  export declare const MAX_ENVELOPE_BYTES: number;
@@ -1,18 +1,7 @@
1
- /**
2
- * The HOST's body ceilings, and the one place they are computed.
3
- *
4
- * Lambda Function URLs cap a request at 6 MB, so the forwarder cannot deliver more than that no
5
- * matter what the adapter accepts; the body arrives base64-encoded (×4/3) inside a JSON envelope, so
6
- * the ORIGINAL body ceiling is smaller still. This is a real capability difference from a resident
7
- * host — the GitHub channel's own contract is 25 MiB — which is why `deploy agentcore` states it at
8
- * plan time rather than letting an oversized payload surface as an opaque 502.
9
- */
1
+ /** The HOST's body ceilings, and the one place they are computed. */
10
2
  /** AWS Lambda Function URLs accept request payloads up to 6 MB. */
11
3
  const FUNCTION_URL_REQUEST_LIMIT = 6 * 1000 * 1000;
12
- /**
13
- * Maximum original webhook body after reserving JSON-envelope overhead and base64 expansion.
14
- * Enforced by both the public forwarder and the runtime adapter.
15
- */
4
+ /** Maximum original webhook body after reserving JSON-envelope overhead and base64 expansion. */
16
5
  export const MAX_WEBHOOK_BODY_BYTES = Math.floor((FUNCTION_URL_REQUEST_LIMIT * 3) / 4) - (64 << 10);
17
6
  /** Largest complete AgentCore envelope accepted by the runtime adapter. */
18
7
  export const MAX_ENVELOPE_BYTES = FUNCTION_URL_REQUEST_LIMIT;