@fastagent-sh/fastagent 0.24.3 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/README.md +53 -82
  2. package/dist/agent-api.d.ts +452 -0
  3. package/dist/agent-api.js +201 -0
  4. package/dist/answer-text.d.ts +8 -0
  5. package/dist/answer-text.js +18 -0
  6. package/dist/atomic-write.d.ts +2 -2
  7. package/dist/atomic-write.js +2 -2
  8. package/dist/authoring.d.ts +77 -0
  9. package/dist/authoring.js +238 -0
  10. package/dist/channel.d.ts +29 -15
  11. package/dist/channel.js +4 -1
  12. package/dist/channels/agentcore-protocol.d.ts +36 -50
  13. package/dist/channels/agentcore-protocol.js +3 -3
  14. package/dist/channels/agentcore-service.d.ts +8 -18
  15. package/dist/channels/agentcore-service.js +108 -127
  16. package/dist/channels/agentcore.d.ts +8 -24
  17. package/dist/channels/agentcore.js +32 -65
  18. package/dist/channels/body.d.ts +0 -16
  19. package/dist/channels/body.js +0 -25
  20. package/dist/channels/busy.js +6 -1
  21. package/dist/channels/context.d.ts +4 -0
  22. package/dist/channels/context.js +35 -0
  23. package/dist/channels/discover.d.ts +18 -20
  24. package/dist/channels/discover.js +41 -99
  25. package/dist/channels/feishu/feishu-api.d.ts +54 -4
  26. package/dist/channels/feishu/feishu-api.js +192 -149
  27. package/dist/channels/feishu/feishu.d.ts +3 -0
  28. package/dist/channels/feishu/feishu.js +117 -106
  29. package/dist/channels/feishu/history.d.ts +55 -0
  30. package/dist/channels/feishu/history.js +199 -0
  31. package/dist/channels/feishu/invoke-turn.d.ts +13 -11
  32. package/dist/channels/feishu/invoke-turn.js +9 -10
  33. package/dist/channels/feishu/model.d.ts +2 -1
  34. package/dist/channels/feishu/normalize.js +100 -0
  35. package/dist/channels/feishu/preview.d.ts +2 -2
  36. package/dist/channels/feishu/register-webhook.d.ts +1 -0
  37. package/dist/channels/feishu/register-webhook.js +3 -2
  38. package/dist/channels/feishu/scaffold/channel.ts +65 -46
  39. package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
  40. package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
  41. package/dist/channels/feishu/setup-mode.d.ts +45 -25
  42. package/dist/channels/feishu/setup-mode.js +74 -23
  43. package/dist/channels/feishu/shared-api.d.ts +24 -6
  44. package/dist/channels/feishu/shared-api.js +30 -24
  45. package/dist/channels/kit/context-buffer.d.ts +11 -2
  46. package/dist/channels/kit/context-buffer.js +7 -4
  47. package/dist/channels/kit/delivery.d.ts +19 -3
  48. package/dist/channels/kit/delivery.js +74 -15
  49. package/dist/channels/kit/event-stream.js +2 -1
  50. package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
  51. package/dist/channels/kit/invoke-turn-kit.js +62 -71
  52. package/dist/channels/kit/place-history.d.ts +107 -0
  53. package/dist/channels/kit/place-history.js +182 -0
  54. package/dist/channels/kit/preview-kit.d.ts +9 -5
  55. package/dist/channels/kit/preview-kit.js +36 -15
  56. package/dist/channels/kit/room-threads.d.ts +46 -0
  57. package/dist/channels/kit/room-threads.js +81 -0
  58. package/dist/channels/kit/seen.js +1 -1
  59. package/dist/channels/kit/stop-command.d.ts +6 -3
  60. package/dist/channels/kit/stop-command.js +20 -18
  61. package/dist/channels/kit/thread-fork.d.ts +17 -0
  62. package/dist/channels/kit/thread-fork.js +43 -0
  63. package/dist/channels/kit/thread-participants.js +1 -1
  64. package/dist/channels/kit/transport.d.ts +5 -0
  65. package/dist/channels/kit/transport.js +5 -0
  66. package/dist/channels/kit/turn-runner.d.ts +10 -9
  67. package/dist/channels/kit/turn-runner.js +17 -19
  68. package/dist/channels/kit/turn-store.d.ts +5 -4
  69. package/dist/channels/kit/turn-store.js +5 -5
  70. package/dist/channels/lark/lark.d.ts +3 -0
  71. package/dist/channels/lark/lark.js +5 -0
  72. package/dist/channels/lark/onboard.d.ts +5 -3
  73. package/dist/channels/lark/onboard.js +14 -14
  74. package/dist/channels/lark/scaffold/channel.ts +67 -44
  75. package/dist/channels/lark/scaffold/lark-send.ts +38 -33
  76. package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
  77. package/dist/channels/respond.d.ts +0 -4
  78. package/dist/channels/respond.js +1 -1
  79. package/dist/channels/router.d.ts +18 -0
  80. package/dist/channels/router.js +68 -0
  81. package/dist/channels/serve.d.ts +5 -70
  82. package/dist/channels/serve.js +105 -287
  83. package/dist/channels/slack/history.d.ts +42 -0
  84. package/dist/channels/slack/history.js +282 -0
  85. package/dist/channels/slack/invoke-turn.d.ts +12 -5
  86. package/dist/channels/slack/invoke-turn.js +7 -5
  87. package/dist/channels/slack/manifest.d.ts +1 -4
  88. package/dist/channels/slack/manifest.js +22 -10
  89. package/dist/channels/slack/model.d.ts +2 -1
  90. package/dist/channels/slack/onboard.d.ts +0 -2
  91. package/dist/channels/slack/onboard.js +2 -4
  92. package/dist/channels/slack/onboarding-state.d.ts +0 -2
  93. package/dist/channels/slack/onboarding-state.js +0 -1
  94. package/dist/channels/slack/parse.d.ts +0 -5
  95. package/dist/channels/slack/parse.js +1 -16
  96. package/dist/channels/slack/preview.d.ts +2 -3
  97. package/dist/channels/slack/preview.js +78 -52
  98. package/dist/channels/slack/register-webhook.d.ts +1 -0
  99. package/dist/channels/slack/register-webhook.js +6 -5
  100. package/dist/channels/slack/scaffold/channel.ts +23 -24
  101. package/dist/channels/slack/scaffold/slack-send.ts +50 -43
  102. package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
  103. package/dist/channels/slack/setup-server.d.ts +19 -0
  104. package/dist/channels/slack/setup-server.js +113 -11
  105. package/dist/channels/slack/shared-api.d.ts +15 -4
  106. package/dist/channels/slack/shared-api.js +19 -14
  107. package/dist/channels/slack/slack-api.d.ts +61 -2
  108. package/dist/channels/slack/slack-api.js +28 -5
  109. package/dist/channels/slack/slack.js +97 -52
  110. package/dist/channels/slack/welcomed.js +1 -1
  111. package/dist/channels/telegram/context-buffer.d.ts +6 -1
  112. package/dist/channels/telegram/context-buffer.js +19 -0
  113. package/dist/channels/telegram/invoke-turn.d.ts +8 -4
  114. package/dist/channels/telegram/invoke-turn.js +7 -7
  115. package/dist/channels/telegram/parse.d.ts +7 -2
  116. package/dist/channels/telegram/parse.js +7 -0
  117. package/dist/channels/telegram/preview.d.ts +2 -2
  118. package/dist/channels/telegram/register-webhook.d.ts +1 -0
  119. package/dist/channels/telegram/register-webhook.js +3 -2
  120. package/dist/channels/telegram/scaffold/channel.ts +27 -28
  121. package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
  122. package/dist/channels/telegram/shared-api.d.ts +34 -0
  123. package/dist/channels/telegram/shared-api.js +79 -0
  124. package/dist/channels/telegram/telegram-api.d.ts +15 -5
  125. package/dist/channels/telegram/telegram-api.js +10 -6
  126. package/dist/channels/telegram/telegram.js +27 -21
  127. package/dist/channels/telegram/turn-store.js +1 -1
  128. package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
  129. package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
  130. package/dist/cli/add-feishu.d.ts +42 -12
  131. package/dist/cli/add-feishu.js +177 -124
  132. package/dist/cli/add-slack.d.ts +8 -3
  133. package/dist/cli/add-slack.js +115 -63
  134. package/dist/cli/auth-view.d.ts +10 -3
  135. package/dist/cli/auth-view.js +8 -6
  136. package/dist/cli/box-login.d.ts +17 -7
  137. package/dist/cli/box-login.js +46 -12
  138. package/dist/cli/commands/add.d.ts +15 -4
  139. package/dist/cli/commands/add.js +252 -143
  140. package/dist/cli/commands/auth.d.ts +6 -0
  141. package/dist/cli/commands/auth.js +50 -0
  142. package/dist/cli/commands/content.d.ts +6 -0
  143. package/dist/cli/commands/content.js +45 -0
  144. package/dist/cli/commands/deploy/agentcore.js +50 -77
  145. package/dist/cli/commands/deploy/docker.js +38 -39
  146. package/dist/cli/commands/deploy/fly.js +21 -18
  147. package/dist/cli/commands/deploy/host-login.d.ts +26 -0
  148. package/dist/cli/commands/deploy/host-login.js +90 -0
  149. package/dist/cli/commands/deploy/railway.js +21 -26
  150. package/dist/cli/commands/deploy/shared.d.ts +45 -17
  151. package/dist/cli/commands/deploy/shared.js +34 -15
  152. package/dist/cli/commands/deploy.d.ts +0 -4
  153. package/dist/cli/commands/deploy.js +237 -50
  154. package/dist/cli/commands/destroy.js +8 -6
  155. package/dist/cli/commands/dev.d.ts +0 -2
  156. package/dist/cli/commands/dev.js +20 -19
  157. package/dist/cli/commands/env.d.ts +12 -0
  158. package/dist/cli/commands/env.js +190 -0
  159. package/dist/cli/commands/info.js +95 -156
  160. package/dist/cli/commands/init.d.ts +2 -2
  161. package/dist/cli/commands/init.js +35 -33
  162. package/dist/cli/commands/invoke.d.ts +6 -0
  163. package/dist/cli/commands/invoke.js +131 -16
  164. package/dist/cli/commands/login.d.ts +31 -2
  165. package/dist/cli/commands/login.js +413 -64
  166. package/dist/cli/commands/logout.d.ts +4 -0
  167. package/dist/cli/commands/logout.js +53 -0
  168. package/dist/cli/commands/logs.js +8 -6
  169. package/dist/cli/commands/models.d.ts +2 -1
  170. package/dist/cli/commands/models.js +39 -37
  171. package/dist/cli/commands/schedules.d.ts +21 -0
  172. package/dist/cli/commands/schedules.js +143 -0
  173. package/dist/cli/commands/start.d.ts +11 -10
  174. package/dist/cli/commands/start.js +35 -62
  175. package/dist/cli/content-view.d.ts +9 -0
  176. package/dist/cli/content-view.js +26 -0
  177. package/dist/cli/fail.d.ts +9 -12
  178. package/dist/cli/fail.js +17 -14
  179. package/dist/cli/invoke-stream.d.ts +12 -3
  180. package/dist/cli/invoke-stream.js +85 -23
  181. package/dist/cli/kernel.d.ts +9 -2
  182. package/dist/cli/kernel.js +15 -6
  183. package/dist/cli/login-relay.d.ts +3 -2
  184. package/dist/cli/login-relay.js +18 -6
  185. package/dist/cli/models-view.d.ts +5 -1
  186. package/dist/cli/models-view.js +1 -1
  187. package/dist/cli/person.d.ts +10 -0
  188. package/dist/cli/person.js +23 -0
  189. package/dist/cli/program.js +421 -203
  190. package/dist/cli/serve.d.ts +13 -63
  191. package/dist/cli/serve.js +31 -121
  192. package/dist/cli/shared.d.ts +21 -48
  193. package/dist/cli/shared.js +68 -89
  194. package/dist/cli/ticket.d.ts +136 -0
  195. package/dist/cli/ticket.js +476 -0
  196. package/dist/client.d.ts +7 -0
  197. package/dist/client.js +2 -0
  198. package/dist/content/declare.d.ts +70 -0
  199. package/dist/content/declare.js +163 -0
  200. package/dist/content/file.d.ts +32 -0
  201. package/dist/content/file.js +119 -0
  202. package/dist/content/git.d.ts +41 -0
  203. package/dist/content/git.js +217 -0
  204. package/dist/content/mount.d.ts +2 -0
  205. package/dist/content/mount.js +15 -0
  206. package/dist/content/resolve.d.ts +52 -0
  207. package/dist/content/resolve.js +151 -0
  208. package/dist/content/source.d.ts +27 -0
  209. package/dist/content/source.js +53 -0
  210. package/dist/conversation-sessions.d.ts +26 -0
  211. package/dist/conversation-sessions.js +99 -0
  212. package/dist/declared-secrets.d.ts +19 -37
  213. package/dist/declared-secrets.js +16 -58
  214. package/dist/deploy/agentcore/destroy.d.ts +3 -3
  215. package/dist/deploy/agentcore/destroy.js +46 -28
  216. package/dist/deploy/agentcore/forwarder.js +105 -22
  217. package/dist/deploy/agentcore/logs.js +1 -1
  218. package/dist/deploy/agentcore/plan.d.ts +10 -24
  219. package/dist/deploy/agentcore/plan.js +31 -135
  220. package/dist/deploy/agentcore/run.d.ts +1 -1
  221. package/dist/deploy/agentcore/run.js +8 -5
  222. package/dist/deploy/agentcore/shell.d.ts +1 -1
  223. package/dist/deploy/agentcore/shell.js +5 -5
  224. package/dist/deploy/api.d.ts +34 -0
  225. package/dist/deploy/api.js +50 -0
  226. package/dist/deploy/box-shell.d.ts +6 -0
  227. package/dist/deploy/box-shell.js +7 -0
  228. package/dist/deploy/build-context.d.ts +7 -5
  229. package/dist/deploy/build-context.js +41 -35
  230. package/dist/deploy/channel-ingress.d.ts +6 -1
  231. package/dist/deploy/channel-ingress.js +18 -5
  232. package/dist/deploy/container.d.ts +22 -9
  233. package/dist/deploy/container.js +96 -55
  234. package/dist/deploy/docker/plan.d.ts +3 -2
  235. package/dist/deploy/docker/plan.js +13 -14
  236. package/dist/deploy/docker/run.d.ts +2 -2
  237. package/dist/deploy/docker/run.js +8 -4
  238. package/dist/deploy/fly/plan.d.ts +1 -1
  239. package/dist/deploy/fly/plan.js +12 -21
  240. package/dist/deploy/fly/run.d.ts +10 -6
  241. package/dist/deploy/fly/run.js +11 -6
  242. package/dist/deploy/hosts.d.ts +2 -1
  243. package/dist/deploy/hosts.js +2 -1
  244. package/dist/deploy/preflight.d.ts +21 -23
  245. package/dist/deploy/preflight.js +222 -201
  246. package/dist/deploy/railway/plan.d.ts +8 -6
  247. package/dist/deploy/railway/plan.js +15 -58
  248. package/dist/deploy/railway/run.d.ts +8 -3
  249. package/dist/deploy/railway/run.js +12 -8
  250. package/dist/deploy/residency.d.ts +5 -11
  251. package/dist/deploy/residency.js +0 -6
  252. package/dist/deploy/runner.d.ts +1 -1
  253. package/dist/deploy/runner.js +1 -1
  254. package/dist/deploy/secrets.d.ts +16 -2
  255. package/dist/deploy/secrets.js +33 -6
  256. package/dist/deploy/workspace.d.ts +11 -6
  257. package/dist/deploy/workspace.js +55 -38
  258. package/dist/dev-supervisor.d.ts +11 -2
  259. package/dist/dev-supervisor.js +51 -26
  260. package/dist/effect-port.d.ts +4 -4
  261. package/dist/effect-port.js +4 -4
  262. package/dist/environment/apt.d.ts +4 -0
  263. package/dist/environment/apt.js +32 -0
  264. package/dist/environment/declare.d.ts +59 -0
  265. package/dist/environment/declare.js +210 -0
  266. package/dist/environment/mise.d.ts +50 -0
  267. package/dist/environment/mise.js +268 -0
  268. package/dist/feishu.d.ts +2 -2
  269. package/dist/feishu.js +2 -2
  270. package/dist/git.d.ts +13 -0
  271. package/dist/git.js +55 -0
  272. package/dist/harnesses/models/catalog.d.ts +20 -0
  273. package/dist/harnesses/models/catalog.js +254 -0
  274. package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
  275. package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
  276. package/dist/harnesses/models/environment.d.ts +43 -0
  277. package/dist/harnesses/models/environment.js +82 -0
  278. package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
  279. package/dist/{engines/pi → harnesses/models}/login.js +187 -79
  280. package/dist/harnesses/models/models.d.ts +83 -0
  281. package/dist/harnesses/models/models.js +158 -0
  282. package/dist/harnesses/pi-durable/agent.d.ts +42 -0
  283. package/dist/harnesses/pi-durable/agent.js +579 -0
  284. package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
  285. package/dist/harnesses/pi-durable/defaults.js +26 -0
  286. package/dist/harnesses/pi-durable/define.d.ts +77 -0
  287. package/dist/harnesses/pi-durable/define.js +28 -0
  288. package/dist/harnesses/pi-durable/entries.d.ts +32 -0
  289. package/dist/harnesses/pi-durable/entries.js +126 -0
  290. package/dist/harnesses/pi-durable/events.d.ts +25 -0
  291. package/dist/harnesses/pi-durable/events.js +238 -0
  292. package/dist/harnesses/pi-durable/ids.d.ts +16 -0
  293. package/dist/harnesses/pi-durable/ids.js +55 -0
  294. package/dist/harnesses/pi-durable/messages.d.ts +41 -0
  295. package/dist/harnesses/pi-durable/messages.js +116 -0
  296. package/dist/harnesses/pi-durable/open.d.ts +88 -0
  297. package/dist/harnesses/pi-durable/open.js +329 -0
  298. package/dist/harnesses/pi-durable/reads.d.ts +30 -0
  299. package/dist/harnesses/pi-durable/reads.js +94 -0
  300. package/dist/harnesses/pi-durable/registry.d.ts +18 -0
  301. package/dist/harnesses/pi-durable/registry.js +56 -0
  302. package/dist/harnesses/pi-durable/release.d.ts +13 -0
  303. package/dist/harnesses/pi-durable/release.js +40 -0
  304. package/dist/harnesses/pi-durable/serve.d.ts +80 -0
  305. package/dist/harnesses/pi-durable/serve.js +156 -0
  306. package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
  307. package/dist/harnesses/pi-durable/sessions.js +47 -0
  308. package/dist/harnesses/pi-durable/storage.d.ts +4 -0
  309. package/dist/harnesses/pi-durable/storage.js +49 -0
  310. package/dist/harnesses/pi-durable/stream.d.ts +20 -0
  311. package/dist/harnesses/pi-durable/stream.js +221 -0
  312. package/dist/harnesses/pi-durable/text.d.ts +30 -0
  313. package/dist/harnesses/pi-durable/text.js +292 -0
  314. package/dist/harnesses/pi-durable/wake.d.ts +4 -0
  315. package/dist/harnesses/pi-durable/wake.js +81 -0
  316. package/dist/http/client.d.ts +6 -0
  317. package/dist/http/client.js +256 -0
  318. package/dist/http/contract.d.ts +541 -0
  319. package/dist/http/contract.js +179 -0
  320. package/dist/http/server.d.ts +34 -0
  321. package/dist/http/server.js +194 -0
  322. package/dist/index.d.ts +17 -4
  323. package/dist/index.js +10 -5
  324. package/dist/lark.d.ts +2 -2
  325. package/dist/lark.js +2 -2
  326. package/dist/locked-file.d.ts +17 -0
  327. package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
  328. package/dist/once.d.ts +6 -0
  329. package/dist/once.js +23 -0
  330. package/dist/paths.d.ts +36 -52
  331. package/dist/paths.js +66 -182
  332. package/dist/runtime.d.ts +25 -2
  333. package/dist/runtime.js +27 -0
  334. package/dist/scaffold/add-channel.d.ts +14 -27
  335. package/dist/scaffold/add-channel.js +82 -180
  336. package/dist/scaffold/init.d.ts +17 -18
  337. package/dist/scaffold/init.js +87 -99
  338. package/dist/scaffold/templates/SYSTEM.md +12 -0
  339. package/dist/scaffold/templates/env.example +4 -10
  340. package/dist/scaffold/templates/fastagent.config.ts +21 -33
  341. package/dist/scaffold/templates/gitignore +8 -1
  342. package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
  343. package/dist/scaffold/templates.d.ts +9 -4
  344. package/dist/scaffold/templates.js +7 -5
  345. package/dist/scaffold/vendor-skill.d.ts +1 -4
  346. package/dist/scaffold/vendor-skill.js +5 -6
  347. package/dist/schedule/cron.d.ts +13 -0
  348. package/dist/schedule/cron.js +52 -0
  349. package/dist/schedule/eventbridge-cron.d.ts +17 -0
  350. package/dist/schedule/eventbridge-cron.js +88 -0
  351. package/dist/schedule/schedule.d.ts +23 -0
  352. package/dist/schedule/schedule.js +34 -0
  353. package/dist/schedule/scheduler.d.ts +34 -33
  354. package/dist/schedule/scheduler.js +251 -137
  355. package/dist/schedule/state.d.ts +4 -14
  356. package/dist/schedule/state.js +7 -7
  357. package/dist/schedule/wake-alarm.d.ts +22 -2
  358. package/dist/schedule/wake-alarm.js +66 -20
  359. package/dist/schedule/wakeups.d.ts +16 -15
  360. package/dist/schedule/wakeups.js +47 -45
  361. package/dist/service.d.ts +56 -169
  362. package/dist/service.js +91 -187
  363. package/dist/serving-command.d.ts +10 -0
  364. package/dist/serving-command.js +16 -0
  365. package/dist/slack.d.ts +1 -1
  366. package/dist/slack.js +1 -1
  367. package/dist/{channels/kit/state.js → state-file.js} +6 -6
  368. package/dist/telegram.d.ts +1 -0
  369. package/dist/telegram.js +1 -0
  370. package/dist/tunnel.d.ts +3 -0
  371. package/dist/tunnel.js +12 -4
  372. package/dist/value-file.d.ts +21 -0
  373. package/dist/value-file.js +108 -0
  374. package/dist/version.d.ts +5 -0
  375. package/dist/version.js +14 -1
  376. package/package.json +18 -28
  377. package/dist/agent.d.ts +0 -106
  378. package/dist/agent.js +0 -21
  379. package/dist/channels/control.d.ts +0 -31
  380. package/dist/channels/control.js +0 -329
  381. package/dist/channels/define-channel.d.ts +0 -39
  382. package/dist/channels/define-channel.js +0 -9
  383. package/dist/channels/feishu/context-buffer.d.ts +0 -35
  384. package/dist/channels/feishu/context-buffer.js +0 -65
  385. package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
  386. package/dist/channels/http.d.ts +0 -23
  387. package/dist/channels/http.js +0 -57
  388. package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
  389. package/dist/channels/slack/context-buffer.d.ts +0 -23
  390. package/dist/channels/slack/context-buffer.js +0 -37
  391. package/dist/channels/sse.d.ts +0 -4
  392. package/dist/channels/sse.js +0 -66
  393. package/dist/cli/commands/chat.d.ts +0 -3
  394. package/dist/cli/commands/chat.js +0 -14
  395. package/dist/cli/commands/routine-run.d.ts +0 -6
  396. package/dist/cli/commands/routine-run.js +0 -46
  397. package/dist/cli/commands/routine.d.ts +0 -25
  398. package/dist/cli/commands/routine.js +0 -122
  399. package/dist/cli/commands/tool.d.ts +0 -1
  400. package/dist/cli/commands/tool.js +0 -57
  401. package/dist/collect.d.ts +0 -63
  402. package/dist/collect.js +0 -90
  403. package/dist/core.d.ts +0 -13
  404. package/dist/core.js +0 -15
  405. package/dist/engines/pi/agent-models.d.ts +0 -83
  406. package/dist/engines/pi/agent-models.js +0 -120
  407. package/dist/engines/pi/agent-session-factory.d.ts +0 -121
  408. package/dist/engines/pi/agent-session-factory.js +0 -517
  409. package/dist/engines/pi/chat.d.ts +0 -3
  410. package/dist/engines/pi/chat.js +0 -8
  411. package/dist/engines/pi/config.d.ts +0 -71
  412. package/dist/engines/pi/config.js +0 -199
  413. package/dist/engines/pi/create.d.ts +0 -170
  414. package/dist/engines/pi/create.js +0 -343
  415. package/dist/engines/pi/definition.d.ts +0 -74
  416. package/dist/engines/pi/definition.js +0 -236
  417. package/dist/engines/pi/entry-images.d.ts +0 -14
  418. package/dist/engines/pi/entry-images.js +0 -23
  419. package/dist/engines/pi/invoke-session.d.ts +0 -18
  420. package/dist/engines/pi/invoke-session.js +0 -403
  421. package/dist/engines/pi/locked-file.d.ts +0 -9
  422. package/dist/engines/pi/machine.d.ts +0 -53
  423. package/dist/engines/pi/machine.js +0 -137
  424. package/dist/engines/pi/models.d.ts +0 -200
  425. package/dist/engines/pi/models.js +0 -533
  426. package/dist/engines/pi/open.d.ts +0 -180
  427. package/dist/engines/pi/open.js +0 -270
  428. package/dist/engines/pi/openai-account-models.d.ts +0 -35
  429. package/dist/engines/pi/openai-account-models.js +0 -116
  430. package/dist/engines/pi/report.d.ts +0 -18
  431. package/dist/engines/pi/report.js +0 -59
  432. package/dist/engines/pi/retry-event.d.ts +0 -6
  433. package/dist/engines/pi/retry-event.js +0 -15
  434. package/dist/engines/pi/service.d.ts +0 -9
  435. package/dist/engines/pi/service.js +0 -14
  436. package/dist/engines/pi/session-builder.d.ts +0 -13
  437. package/dist/engines/pi/session-builder.js +0 -117
  438. package/dist/engines/pi/session-control.d.ts +0 -77
  439. package/dist/engines/pi/session-control.js +0 -908
  440. package/dist/engines/pi/session-effects.d.ts +0 -14
  441. package/dist/engines/pi/session-effects.js +0 -30
  442. package/dist/engines/pi/session-inheritance.d.ts +0 -21
  443. package/dist/engines/pi/session-inheritance.js +0 -204
  444. package/dist/engines/pi/session-markers.d.ts +0 -49
  445. package/dist/engines/pi/session-markers.js +0 -60
  446. package/dist/engines/pi/session-settings.d.ts +0 -67
  447. package/dist/engines/pi/session-settings.js +0 -119
  448. package/dist/engines/pi/session-store.d.ts +0 -69
  449. package/dist/engines/pi/session-store.js +0 -430
  450. package/dist/engines/pi/tool-context.d.ts +0 -45
  451. package/dist/engines/pi/tool-context.js +0 -31
  452. package/dist/engines/pi/tool.d.ts +0 -99
  453. package/dist/engines/pi/tool.js +0 -118
  454. package/dist/engines/pi/turn-kit.d.ts +0 -83
  455. package/dist/engines/pi/turn-kit.js +0 -275
  456. package/dist/engines/pi/wake-tool.d.ts +0 -9
  457. package/dist/engines/pi/wake-tool.js +0 -92
  458. package/dist/loader.d.ts +0 -41
  459. package/dist/loader.js +0 -116
  460. package/dist/node.d.ts +0 -3
  461. package/dist/node.js +0 -4
  462. package/dist/observe.d.ts +0 -6
  463. package/dist/observe.js +0 -47
  464. package/dist/pi.d.ts +0 -25
  465. package/dist/pi.js +0 -15
  466. package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
  467. package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
  468. package/dist/schedule/discover.d.ts +0 -17
  469. package/dist/schedule/discover.js +0 -61
  470. package/dist/schedule/routine.d.ts +0 -43
  471. package/dist/schedule/routine.js +0 -32
  472. package/dist/schedule/run.d.ts +0 -55
  473. package/dist/schedule/run.js +0 -146
  474. package/dist/secrets-gate.d.ts +0 -32
  475. package/dist/secrets-gate.js +0 -33
  476. package/dist/session-remote.d.ts +0 -47
  477. package/dist/session-remote.js +0 -460
  478. package/dist/session.d.ts +0 -466
  479. package/dist/session.js +0 -57
  480. /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
@@ -0,0 +1,179 @@
1
+ /**
2
+ * The Agent API over HTTP (docs/SPEC.md §9) as one `effect/http-api` contract: the server answers from it,
3
+ * `connectAgent` calls through it and `/v1/openapi.json` is generated from it, so none of them can describe another API
4
+ * than the one served. Built from agent-api.ts's schemas; imports nothing that needs Node, so a client runs wherever
5
+ * `fetch` does.
6
+ */
7
+ import * as Effect from "effect/Effect";
8
+ import * as Schema from "effect/Schema";
9
+ import * as SchemaIssue from "effect/SchemaIssue";
10
+ import * as SchemaTransformation from "effect/SchemaTransformation";
11
+ import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, HttpApiSecurity, OpenApi, } from "effect/http-api";
12
+ import { AgentError, AgentErrorData, AgentInfo, CompactOptions, CreateSessionOptions, Entry, EntriesOptions, IdempotencyKey, ListOptions, Message, MessageStreamEvent, SendRequest, Session, SessionChanges, SessionEvent, Usage, Wait, errorData, } from "../agent-api.js";
13
+ export const API_PREFIX = "/v1";
14
+ /** The status a refusal answers with (§7). */
15
+ export function statusOf(error) {
16
+ const reason = error.details?.reason;
17
+ switch (error.code) {
18
+ case "invalid_request":
19
+ return reason === "too_large" ? 413 : 400;
20
+ case "unauthorized":
21
+ return 401;
22
+ case "not_found":
23
+ return 404;
24
+ case "busy":
25
+ return reason === "queue_full" ? 429 : reason === "capacity" ? 503 : 409;
26
+ case "missing_model":
27
+ case "missing_tool":
28
+ return 409;
29
+ case "unavailable":
30
+ return 503;
31
+ default:
32
+ return 500;
33
+ }
34
+ }
35
+ const isAgentError = Schema.declare((u) => u instanceof AgentError);
36
+ /** A refusal's body, `{ error }`, as the `AgentError` it carries: what a client reads at any status. */
37
+ export const Refusal = Schema.Struct({ error: AgentErrorData }).pipe(Schema.decodeTo(isAgentError, SchemaTransformation.transform({
38
+ decode: ({ error }) => new AgentError(error),
39
+ encode: (error) => ({ error: errorData(error) }),
40
+ })));
41
+ /**
42
+ * `{ error }` at `status`. Encoding takes only an error whose status this is, which is how the server's answer gets its
43
+ * status; decoding takes any code, since a later server may answer with one this client does not know (§7.1).
44
+ */
45
+ function refusedWith(status) {
46
+ return Schema.Struct({ error: AgentErrorData }).pipe(Schema.decodeTo(isAgentError, SchemaTransformation.transformEffect({
47
+ decode: ({ error }) => Effect.succeed(new AgentError(error)),
48
+ encode: (error) => statusOf(error) === status
49
+ ? Effect.succeed({ error: errorData(error) })
50
+ : Effect.fail(new SchemaIssue.Forbidden({ message: `not answered with ${status}` }, error)),
51
+ })), HttpApiSchema.status(status));
52
+ }
53
+ const Refused = [400, 404, 409, 413, 429, 500, 503].map(refusedWith);
54
+ export class Authorization extends HttpApiMiddleware.Service()("fastagent/Authorization", {
55
+ security: { bearer: HttpApiSecurity.bearer },
56
+ error: refusedWith(401),
57
+ }) {
58
+ }
59
+ /** A request the contract cannot read (a path, query, header or body), refused `invalid_request`. */
60
+ export class Malformed extends HttpApiMiddleware.Service()("fastagent/Malformed", {
61
+ error: refusedWith(400),
62
+ }) {
63
+ }
64
+ const typesOf = (events) => new Set(events.members.map((member) => member.fields.type.literal));
65
+ /** The event types this version defines; a Caller ignores any other (§7.1). */
66
+ export const SESSION_EVENT_TYPES = typesOf(SessionEvent);
67
+ export const MESSAGE_STREAM_EVENT_TYPES = typesOf(MessageStreamEvent);
68
+ /** An event of a type a later server sends and this client does not know: its type, the rest unread. */
69
+ const Unknown = Schema.Struct({ type: Schema.String });
70
+ /**
71
+ * An event as server-sent: its type as the event's name, the event as its data, and an entry's id as its id, so that
72
+ * `Last-Event-ID` is the last entry a Caller received (§9.3).
73
+ */
74
+ function serverSent(events, known) {
75
+ const json = Schema.fromJsonString(events);
76
+ return Schema.Struct({ id: Schema.optional(Schema.String), event: Schema.String, data: Schema.String }).pipe(Schema.decodeTo(Schema.Union([Schema.toType(events), Unknown]), SchemaTransformation.transformEffect({
77
+ decode: ({ event, data }) => known.has(event)
78
+ ? Schema.decodeUnknownEffect(json)(data).pipe(Effect.mapError((error) => error.issue))
79
+ : Effect.succeed({ type: event }),
80
+ encode: (value) => !known.has(value.type)
81
+ ? Effect.fail(new SchemaIssue.Forbidden({ message: `${value.type} is not an event this API sends` }))
82
+ : Schema.encodeEffect(json)(value).pipe(Effect.mapError((error) => error.issue), Effect.map((data) => ({
83
+ event: value.type,
84
+ data,
85
+ ...("entry" in value && value.type === "entry" ? { id: value.entry.id } : {}),
86
+ }))),
87
+ })));
88
+ }
89
+ export const SessionEventFrame = serverSent(SessionEvent, SESSION_EVENT_TYPES);
90
+ export const MessageStreamEventFrame = serverSent(MessageStreamEvent, MESSAGE_STREAM_EVENT_TYPES);
91
+ const sessionPath = { sessionId: Schema.String };
92
+ const Page = (item) => Schema.Struct({
93
+ data: Schema.Array(item),
94
+ next: Schema.optionalKey(Schema.String),
95
+ prev: Schema.optionalKey(Schema.String),
96
+ });
97
+ const { sessionId: _, ...sendFields } = SendRequest.fields;
98
+ const { idempotencyKey: __, ...sendBody } = sendFields;
99
+ /** `POST …/messages`: the send without its session (the path's) or its key (`Idempotency-Key`). */
100
+ const SendBody = Schema.Struct({
101
+ ...sendBody,
102
+ wait: Schema.optional(Wait),
103
+ /** `messages.stream`: the answer is the message's events. */
104
+ stream: Schema.optional(Schema.Boolean),
105
+ });
106
+ /**
107
+ * A key as a header carries it: percent-encoded, as in the `by-key` path, since a header holds only Latin-1 and loses
108
+ * the spaces around a value, while a key may be any 1 to 256 characters (§9.2).
109
+ */
110
+ const KeyHeader = Schema.String.pipe(Schema.decodeTo(IdempotencyKey, SchemaTransformation.stringFromUriComponent));
111
+ const WaitQuery = { wait: Schema.optional(Schema.NumberFromString.check(Schema.isGreaterThanOrEqualTo(0))) };
112
+ const AgentGroup = HttpApiGroup.make("agent")
113
+ .add(HttpApiEndpoint.get("info", "/agent", { success: AgentInfo, error: Refused }), HttpApiEndpoint.get("usage", "/usage", { success: Usage, error: Refused }), HttpApiEndpoint.get("openapi", "/openapi.json", { success: Schema.Json, error: Refused }), HttpApiEndpoint.post("createSession", "/sessions", {
114
+ // Its options may be left out, as in process (§4): a request without a body is one without them, which the
115
+ // contract reads as `null` only when a payload schema is `null` itself.
116
+ payload: [CreateSessionOptions, Schema.Null],
117
+ success: Session.pipe(HttpApiSchema.status(201)),
118
+ error: Refused,
119
+ }), HttpApiEndpoint.get("listSessions", "/sessions", {
120
+ query: ListOptions,
121
+ success: Page(Session),
122
+ error: Refused,
123
+ }), HttpApiEndpoint.get("getSession", "/sessions/:sessionId", {
124
+ params: sessionPath,
125
+ success: Session,
126
+ error: Refused,
127
+ }), HttpApiEndpoint.patch("updateSession", "/sessions/:sessionId", {
128
+ params: sessionPath,
129
+ payload: SessionChanges,
130
+ success: Session,
131
+ error: Refused,
132
+ }), HttpApiEndpoint.get("entries", "/sessions/:sessionId/entries", {
133
+ params: sessionPath,
134
+ query: EntriesOptions,
135
+ success: Page(Entry),
136
+ error: Refused,
137
+ }), HttpApiEndpoint.get("events", "/sessions/:sessionId/events", {
138
+ params: sessionPath,
139
+ query: { after: Schema.optional(Schema.String) },
140
+ headers: { "last-event-id": Schema.optional(Schema.String) },
141
+ success: HttpApiSchema.StreamSse({ events: SessionEventFrame }),
142
+ error: Refused,
143
+ }), HttpApiEndpoint.post("cancel", "/sessions/:sessionId/cancel", {
144
+ params: sessionPath,
145
+ success: Schema.Struct({ stopped: Schema.Array(Schema.String) }),
146
+ error: Refused,
147
+ }), HttpApiEndpoint.post("compact", "/sessions/:sessionId/compact", {
148
+ params: sessionPath,
149
+ payload: [CompactOptions, Schema.Null],
150
+ success: HttpApiSchema.Accepted,
151
+ error: Refused,
152
+ }), HttpApiEndpoint.get("attachment", "/sessions/:sessionId/attachments/:ref", {
153
+ params: { ...sessionPath, ref: Schema.String },
154
+ success: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array({ contentType: "image/*" })),
155
+ error: Refused,
156
+ }), HttpApiEndpoint.post("send", "/sessions/:sessionId/messages", {
157
+ params: sessionPath,
158
+ headers: { "idempotency-key": Schema.optional(KeyHeader) },
159
+ payload: SendBody,
160
+ success: [Message, HttpApiSchema.StreamSse({ events: MessageStreamEventFrame })],
161
+ error: Refused,
162
+ }), HttpApiEndpoint.get("getMessage", "/sessions/:sessionId/messages/:messageId", {
163
+ params: { ...sessionPath, messageId: Schema.String },
164
+ query: WaitQuery,
165
+ success: Message,
166
+ error: Refused,
167
+ }), HttpApiEndpoint.get("getMessageByKey", "/sessions/:sessionId/messages/by-key/:idempotencyKey", {
168
+ params: { ...sessionPath, idempotencyKey: IdempotencyKey },
169
+ query: WaitQuery,
170
+ success: Message,
171
+ error: Refused,
172
+ }))
173
+ .middleware(Malformed)
174
+ .middleware(Authorization)
175
+ .prefix(API_PREFIX);
176
+ export class AgentHttpApi extends HttpApi.make("fastagent")
177
+ .add(AgentGroup)
178
+ .annotateMerge(OpenApi.annotations({ title: "FastAgent Agent API", version: "2" })) {
179
+ }
@@ -0,0 +1,34 @@
1
+ import { type Agent } from "../agent-api.ts";
2
+ import type { ChannelHandler } from "../channel.ts";
3
+ /** The instance's keys: several, separated by commas, so a key is replaced without a gap (§9.1). */
4
+ export declare const API_KEY_VARIABLE = "FASTAGENT_API_KEY";
5
+ /**
6
+ * Whether the definition turns the Agent API off (`http.api: false`): the one reading of it, which every serve the CLI
7
+ * runs and `deploy` make, so a key a host still holds cannot serve an API the definition turned off.
8
+ */
9
+ export declare function apiTurnedOff(config: {
10
+ http?: {
11
+ api?: boolean;
12
+ };
13
+ }): boolean;
14
+ export declare const API_TURNED_OFF = "fastagent.config.ts says http.api: false";
15
+ export declare function apiKeysFrom(value: string | undefined): string[];
16
+ export interface ApiHandler {
17
+ fetch: ChannelHandler;
18
+ /**
19
+ * Ends every open event stream with a `stream_error`, and answers once they have ended, so that the server's close
20
+ * does not wait on a Caller still watching: at most {@link STREAMS_END_MS}, past which one whose Caller stopped reading
21
+ * is left to the server's own grace.
22
+ */
23
+ endStreams(): Promise<void>;
24
+ dispose(): Promise<void>;
25
+ }
26
+ export interface ApiOptions {
27
+ keys: readonly string[];
28
+ /** For tests: the longest a request waits, and how often a quiet stream says it is open. */
29
+ waitCapSeconds?: number;
30
+ keepAliveMs?: number;
31
+ }
32
+ export declare function apiHandler(agent: Agent, options: ApiOptions): ApiHandler;
33
+ /** Whether `path` is the Agent API's, which a channel's route may not take. */
34
+ export declare function isApiPath(path: string): boolean;
@@ -0,0 +1,194 @@
1
+ /**
2
+ * The Agent API served over HTTP (SPEC.md §9): the contract's routes answered by an in-process Agent, behind the
3
+ * instance's keys. A Fetch handler, so it mounts beside the channels' routes on whatever server serves them.
4
+ */
5
+ import * as ByteSize from "effect/ByteSize";
6
+ import * as Cause from "effect/Cause";
7
+ import * as Effect from "effect/Effect";
8
+ import * as Layer from "effect/Layer";
9
+ import * as Redacted from "effect/Redacted";
10
+ import * as Schema from "effect/Schema";
11
+ import * as Stream from "effect/Stream";
12
+ import * as Sse from "effect/encoding/Sse";
13
+ import { HttpIncomingMessage, HttpRouter, HttpServer, HttpServerError, HttpServerResponse } from "effect/http";
14
+ import { HttpApiBuilder, HttpApiError, OpenApi } from "effect/http-api";
15
+ import { AgentError, LIMITS, agentError, errorData } from "../agent-api.js";
16
+ import { secretEquals } from "../channels/secret.js";
17
+ import { PortFailure, port, portAbort } from "../effect-port.js";
18
+ import { log } from "../log.js";
19
+ import { API_PREFIX, AgentHttpApi, Authorization, Malformed, MessageStreamEventFrame, SessionEventFrame, } from "./contract.js";
20
+ /** The instance's keys: several, separated by commas, so a key is replaced without a gap (§9.1). */
21
+ export const API_KEY_VARIABLE = "FASTAGENT_API_KEY";
22
+ /**
23
+ * Whether the definition turns the Agent API off (`http.api: false`): the one reading of it, which every serve the CLI
24
+ * runs and `deploy` make, so a key a host still holds cannot serve an API the definition turned off.
25
+ */
26
+ export function apiTurnedOff(config) {
27
+ return config.http?.api === false;
28
+ }
29
+ export const API_TURNED_OFF = "fastagent.config.ts says http.api: false";
30
+ export function apiKeysFrom(value) {
31
+ return (value ?? "")
32
+ .split(",")
33
+ .map((key) => key.trim())
34
+ .filter((key) => key !== "");
35
+ }
36
+ const MAX_BODY = ByteSize.mebibytes(32);
37
+ /** Proxies close a connection that says nothing for a minute or so; a comment keeps an event stream open (§9.3). */
38
+ const KEEP_ALIVE_MS = 15_000;
39
+ /** A stream told to end does in a millisecond; this bounds the wait for one whose Caller stopped reading. */
40
+ const STREAMS_END_MS = 100;
41
+ /** How soon a refused Caller may try again; the same for every refusal that says so (§9.4). */
42
+ const RETRY_AFTER_SECONDS = "1";
43
+ /** An operation's failure as the Agent API answers it: an `AgentError` as it is, anything else `internal`, logged. */
44
+ function refusal(operation) {
45
+ return (failure) => {
46
+ const error = failure.cause;
47
+ if (error instanceof AgentError)
48
+ return error;
49
+ log.error(`[api] ${operation} failed: ${String(error)}`);
50
+ return agentError("internal", `${operation} failed: ${error instanceof Error ? error.message : String(error)}`);
51
+ };
52
+ }
53
+ /** An Agent operation, told to let go if its request does (a Caller that left). */
54
+ function call(operation, run) {
55
+ return Effect.suspend(() => {
56
+ const controller = new AbortController();
57
+ return portAbort(operation, () => run(controller.signal), () => controller.abort());
58
+ }).pipe(Effect.mapError(refusal(operation)));
59
+ }
60
+ const json = (status, error) => HttpServerResponse.jsonUnsafe({ error: errorData(error) }, { status });
61
+ /**
62
+ * What the contract cannot say itself: a body over the limit, a body that is not JSON (which the contract answers 415
63
+ * with a line of text) and a route it does not have, answered as refusals like any other, and `Retry-After` on every
64
+ * refusal a Caller may send again later.
65
+ */
66
+ const Edges = HttpRouter.middleware((app) => app.pipe(Effect.catchCause((cause) => {
67
+ const error = Cause.squash(cause);
68
+ if (HttpServerError.isHttpServerError(error)) {
69
+ if (error.reason._tag === "RouteNotFound") {
70
+ return Effect.succeed(json(404, agentError("not_found", "the Agent API has no such route")));
71
+ }
72
+ if (error.reason._tag === "RequestParseError" && error.reason.reason === "BodyTooLarge") {
73
+ return Effect.succeed(json(413, agentError("invalid_request", "the request body is over 32 MiB", { reason: "too_large" })));
74
+ }
75
+ }
76
+ return Effect.failCause(cause);
77
+ }), Effect.map((response) => {
78
+ if (response.status === 415) {
79
+ return json(400, agentError("invalid_request", "a request body is JSON: send Content-Type: application/json"));
80
+ }
81
+ return response.status === 429 || response.status === 503
82
+ ? HttpServerResponse.setHeader(response, "retry-after", RETRY_AFTER_SECONDS)
83
+ : response;
84
+ })), { global: true });
85
+ export function apiHandler(agent, options) {
86
+ // An empty key matches nothing (secretEquals), so serving with one would refuse every Caller without a word.
87
+ if (options.keys.length === 0 || options.keys.some((key) => key.trim() === "")) {
88
+ throw new Error("the Agent API needs at least one key, and no key may be empty");
89
+ }
90
+ const keys = [...options.keys];
91
+ const waitCap = options.waitCapSeconds ?? LIMITS.httpWaitSeconds;
92
+ const keepAlive = options.keepAliveMs ?? KEEP_ALIVE_MS;
93
+ const capped = (wait) => (wait === undefined ? undefined : Math.min(wait, waitCap));
94
+ const closing = new AbortController();
95
+ /** The event streams being written, each until it has ended. */
96
+ const streaming = new Set();
97
+ const closed = Effect.callback((resume) => {
98
+ if (closing.signal.aborted)
99
+ return resume(Effect.void);
100
+ const onAbort = () => resume(Effect.void);
101
+ closing.signal.addEventListener("abort", onAbort, { once: true });
102
+ return Effect.sync(() => closing.signal.removeEventListener("abort", onAbort));
103
+ });
104
+ /**
105
+ * An event stream: refused on its first read with that read's error and status, as `sessions.events` and
106
+ * `messages.stream` are; then its events as server-sent, with a comment while it is quiet. A service that closes
107
+ * ends it with `stream_error`.
108
+ */
109
+ const serverSent = (operation, frame, open) => Effect.gen(function* () {
110
+ const iterator = open()[Symbol.asyncIterator]();
111
+ const first = yield* port(() => iterator.next()).pipe(Effect.onInterrupt(() => Effect.promise(async () => iterator.return?.())), Effect.mapError(refusal(operation)));
112
+ const rest = Stream.fromAsyncIterable({ [Symbol.asyncIterator]: () => iterator }, (error) => error);
113
+ const written = (event) => Schema.encodeEffect(frame)(event).pipe(Effect.map(({ id, event, data }) => Sse.encoder.write({ _tag: "Event", id, event, data })));
114
+ const endedWith = (error) => Stream.fromEffect(Effect.orDie(written({ type: "stream_error", error: errorData(error) })));
115
+ const events = (first.done ? Stream.empty : Stream.concat(Stream.make(first.value), rest)).pipe(
116
+ // Written before a failure is caught, so an event the API cannot send ends the stream as what it is.
117
+ Stream.mapEffect(written), Stream.catchCause((cause) => endedWith(refusal(operation)(new PortFailure(Cause.squash(cause))))), Stream.interruptWhen(closed), Stream.concat(Stream.suspend(() => closing.signal.aborted ? endedWith(agentError("unavailable", "the service is closing")) : Stream.empty)));
118
+ let ended;
119
+ const done = new Promise((resolve) => {
120
+ ended = resolve;
121
+ });
122
+ const body = Stream.merge(events, Stream.tick(`${keepAlive} millis`).pipe(Stream.map(() => ": open\n\n")), {
123
+ haltStrategy: "left",
124
+ }).pipe(Stream.encodeText, Stream.onStart(Effect.sync(() => streaming.add(done))), Stream.ensuring(Effect.sync(() => {
125
+ streaming.delete(done);
126
+ ended();
127
+ })));
128
+ return HttpServerResponse.stream(body, {
129
+ contentType: "text/event-stream",
130
+ headers: { "cache-control": "no-store" },
131
+ });
132
+ });
133
+ const openapi = OpenApi.fromApi(AgentHttpApi);
134
+ const handlers = HttpApiBuilder.group(AgentHttpApi, "agent", (handlers) => handlers
135
+ .handle("info", () => call("info", () => agent.info()))
136
+ .handle("usage", () => call("usage", () => agent.usage()))
137
+ .handle("openapi", () => Effect.succeed(HttpServerResponse.jsonUnsafe(openapi)))
138
+ .handle("createSession", ({ payload }) => call("sessions.create", () => agent.sessions.create(payload ?? undefined)))
139
+ .handle("listSessions", ({ query }) => call("sessions.list", () => agent.sessions.list(query)))
140
+ .handle("getSession", ({ params }) => call("sessions.get", () => agent.sessions.get(params.sessionId)))
141
+ .handle("updateSession", ({ params, payload }) => call("sessions.update", () => agent.sessions.update(params.sessionId, payload)))
142
+ .handle("entries", ({ params, query }) => call("sessions.entries", () => agent.sessions.entries(params.sessionId, query)))
143
+ .handle("events", ({ params, query, headers }) => serverSent("sessions.events", SessionEventFrame, () =>
144
+ // An EventSource reconnects to the URL it opened and says where it got to in this header (§9.3).
145
+ agent.sessions.events(params.sessionId, { after: headers["last-event-id"] ?? query.after })))
146
+ .handle("cancel", ({ params }) => call("sessions.cancel", () => agent.sessions.cancel(params.sessionId)))
147
+ .handle("compact", ({ params, payload }) => call("sessions.compact", () => agent.sessions.compact(params.sessionId, payload ?? undefined)))
148
+ .handle("attachment", ({ params }) => call("sessions.attachment", () => agent.sessions.attachment(params.sessionId, params.ref)).pipe(Effect.map(({ mimeType, data }) => HttpServerResponse.uint8Array(data, { contentType: mimeType }))))
149
+ .handle("send", ({ params, headers, payload }) => {
150
+ const { wait, stream, ...message } = payload;
151
+ const request = { ...message, sessionId: params.sessionId, idempotencyKey: headers["idempotency-key"] };
152
+ if (!stream) {
153
+ return call("messages.send", (signal) => agent.messages.send(request, { wait: capped(wait), signal }));
154
+ }
155
+ if (wait !== undefined) {
156
+ return Effect.fail(agentError("invalid_request", "a streamed message is watched, not waited for: drop wait"));
157
+ }
158
+ return serverSent("messages.stream", MessageStreamEventFrame, () => agent.messages.stream(request));
159
+ })
160
+ .handle("getMessage", ({ params, query }) => call("messages.get", (signal) => agent.messages.get(params, { wait: capped(query.wait), signal })))
161
+ .handle("getMessageByKey", ({ params, query }) => call("messages.get", (signal) => agent.messages.get(params, { wait: capped(query.wait), signal }))));
162
+ const authorization = Layer.succeed(Authorization)({
163
+ bearer: (effect, { credential }) => {
164
+ const given = Redacted.value(credential);
165
+ return keys.some((key) => secretEquals(given, key))
166
+ ? effect
167
+ : Effect.fail(agentError("unauthorized", "the request has no key this instance holds"));
168
+ },
169
+ });
170
+ // The middleware wraps the whole handler, so it also sees the answer failing to encode: the server's fault, not the
171
+ // Caller's, said in the log and answered `internal`, as Effect itself tells the two apart.
172
+ const malformed = Layer.succeed(Malformed)((effect) => Effect.catchIf(effect, HttpApiError.HttpApiSchemaError.is, (error) => {
173
+ // The middleware's own error type hides what it is; the guard above said.
174
+ const { kind, cause } = error;
175
+ if (kind !== "Body" && kind !== "ResponseHeaders") {
176
+ return Effect.fail(agentError("invalid_request", `${kind}: ${cause.message}`));
177
+ }
178
+ log.error(`[api] an answer did not match the Agent API: ${cause.message}`);
179
+ return Effect.fail(agentError("internal", `the agent's answer did not match the Agent API: ${cause.message}`));
180
+ }));
181
+ const { handler, dispose } = HttpRouter.toWebHandler(Layer.mergeAll(HttpApiBuilder.layer(AgentHttpApi), Edges).pipe(Layer.provide(handlers), Layer.provide([authorization, malformed]), Layer.provide(HttpServer.layerServices), Layer.provide(Layer.succeed(HttpIncomingMessage.MaxBodySize)(MAX_BODY))), { disableLogger: true });
182
+ return {
183
+ fetch: (request) => handler(request),
184
+ endStreams: async () => {
185
+ closing.abort();
186
+ await Promise.race([Promise.all(streaming), new Promise((resolve) => setTimeout(resolve, STREAMS_END_MS))]);
187
+ },
188
+ dispose,
189
+ };
190
+ }
191
+ /** Whether `path` is the Agent API's, which a channel's route may not take. */
192
+ export function isApiPath(path) {
193
+ return path === API_PREFIX || path.startsWith(`${API_PREFIX}/`);
194
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,17 @@
1
- export * from "./core.ts";
2
- export * from "./node.ts";
3
- export * from "./session.ts";
4
- export * from "./pi.ts";
1
+ /**
2
+ * The package's one entry (SPEC.md §8), besides each first-party channel's: the Agent API, opening an agent
3
+ * directory and serving it, and what an author writes.
4
+ */
5
+ export type { Agent, AgentErrorData, AgentInfo, CompactOptions, ContentPart, CreateSessionOptions, EntriesOptions, Entry, ErrorCode, Json, ListOptions, Message, MessageKey, MessageStatus, MessageStreamEvent, ModelRef, Page, SendRequest, Session, SessionChanges, SessionEvent, SessionSettings, SessionStatus, ThinkingLevel, Tokens, Usage, WaitOptions, } from "./agent-api.ts";
6
+ export { AgentError, LIMITS, hasEnded } from "./agent-api.ts";
7
+ export { openAgent, type LocalAgent, type OpenAgentOptions, type ServeAgentOptions, } from "./harnesses/pi-durable/serve.ts";
8
+ export type { Service } from "./service.ts";
9
+ /** What `openAgent`'s `credentials` takes: where provider credentials are kept, pi-ai's. */
10
+ export type { CredentialStore } from "@earendil-works/pi-ai";
11
+ export { defineAgent, defineSchedule, needs, type AgentConfig, type Needs, type SecretSpec, type SecretValues, } from "./harnesses/pi-durable/define.ts";
12
+ export type { ScheduleConfig } from "./schedule/schedule.ts";
13
+ export { defineChannel, type ChannelContext, type ChannelHandler, type ChannelModule, type ForkSource, type LongConnection, type LongConnectionChannelModule, type Routes, } from "./channel.ts";
14
+ export { readBodyCapped } from "./channels/body.ts";
15
+ export { text } from "./channels/respond.ts";
16
+ export { secretEquals } from "./channels/secret.ts";
17
+ export { sessionIdOf } from "./harnesses/pi-durable/ids.ts";
package/dist/index.js CHANGED
@@ -1,5 +1,10 @@
1
- // Convenience entry: the engine-neutral core plus the pi reference implementation.
2
- export * from "./core.js";
3
- export * from "./node.js";
4
- export * from "./session.js";
5
- export * from "./pi.js";
1
+ export { AgentError, LIMITS, hasEnded } from "./agent-api.js";
2
+ export { openAgent, } from "./harnesses/pi-durable/serve.js";
3
+ export { defineAgent, defineSchedule, needs, } from "./harnesses/pi-durable/define.js";
4
+ export { defineChannel, } from "./channel.js";
5
+ // What a channel reads a request with, answers with, and compares its platform's secret with (constant time).
6
+ export { readBodyCapped } from "./channels/body.js";
7
+ export { text } from "./channels/respond.js";
8
+ export { secretEquals } from "./channels/secret.js";
9
+ // The session a tool runs in, as the Agent hands it out: what a channel's thread-reading tool asks with.
10
+ export { sessionIdOf } from "./harnesses/pi-durable/ids.js";
package/dist/lark.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** `@fastagent-sh/fastagent/lark` — the Lark-international compatibility surface over the canonical Feishu engine. */
2
- export { larkChannel, larkWebSocketChannel, defaultLarkRoute, larkEnvelope, type LarkChannelOptions, type LarkWebSocketChannelOptions, type LarkMessageEvent, type LarkMessage, type LarkRoute, type LarkFailure, } from "./channels/lark/lark.ts";
3
- export { larkTransport, type FeishuTransport as LarkTransport } from "./channels/feishu/shared-api.ts";
2
+ export { larkChannel, larkIngress, larkWebSocketChannel, defaultLarkRoute, larkEnvelope, type LarkChannelOptions, type LarkWebSocketChannelOptions, type LarkMessageEvent, type LarkMessage, type LarkRoute, type LarkFailure, } from "./channels/lark/lark.ts";
3
+ export { larkThreads, larkTransport, type FeishuTransport as LarkTransport } from "./channels/feishu/shared-api.ts";
package/dist/lark.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /** `@fastagent-sh/fastagent/lark` — the Lark-international compatibility surface over the canonical Feishu engine. */
2
- export { larkChannel, larkWebSocketChannel, defaultLarkRoute, larkEnvelope, } from "./channels/lark/lark.js";
3
- export { larkTransport } from "./channels/feishu/shared-api.js";
2
+ export { larkChannel, larkIngress, larkWebSocketChannel, defaultLarkRoute, larkEnvelope, } from "./channels/lark/lark.js";
3
+ export { larkThreads, larkTransport } from "./channels/feishu/shared-api.js";
@@ -0,0 +1,17 @@
1
+ export interface LockResult<T> {
2
+ result: T;
3
+ /** New file content to persist under the lock; undefined = no write. */
4
+ next?: string;
5
+ }
6
+ /** Serialized cross-process read-modify-write of one file, replaced whole so its readers need no lock. */
7
+ export declare function withLockedFile<T>(path: string, fn: (current: string | undefined) => Promise<LockResult<T>>,
8
+ /**
9
+ * `mode`: the replaced file's permissions; default {@link SECRET_FILE_MODE}, for the credential and catalog files.
10
+ * `create: false` locks a file that may not exist without creating it (the lock is `<file>.lock` either way), for a
11
+ * lock that guards more than the file it is named after.
12
+ */
13
+ options?: {
14
+ signal?: AbortSignal;
15
+ mode?: number;
16
+ create?: boolean;
17
+ }): Promise<T>;
@@ -1,15 +1,15 @@
1
1
  /**
2
- * The one cross-process read-modify-write for a JSON file several processes share: fastagent's credentials file and a
3
- * model catalog. It takes the lock pi takes for the same files (pi-coding-agent's `FileAuthStorageBackend`), so a
4
- * fastagent writer and a pi writer queue behind each other, and it REPLACES the file rather than rewriting it in
5
- * place, which is what lets every reader of these files read without the lock: a reader sees the old file or the new
6
- * one, never one cut short.
2
+ * The one cross-process read-modify-write for a file several processes share: fastagent's credentials file, and
3
+ * `context.json` when an agent's content or environment is edited (`fastagent content` and `fastagent env` at once). It
4
+ * takes the lock pi takes for the same files (pi-coding-agent's `FileAuthStorageBackend`), so a fastagent writer and a
5
+ * pi writer queue behind each other, and it REPLACES the file rather than rewriting it in place, which is what lets
6
+ * every reader of these files read without the lock: a reader sees the old file or the new one, never one cut short.
7
7
  */
8
8
  import { existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, writeFileSync } from "node:fs";
9
9
  import { dirname, resolve } from "node:path";
10
10
  import lockfile from "proper-lockfile";
11
- import { writeFileAtomic } from "../../atomic-write.js";
12
- import { SECRET_FILE_MODE } from "../../paths.js";
11
+ import { writeFileAtomic } from "./atomic-write.js";
12
+ import { SECRET_FILE_MODE } from "./paths.js";
13
13
  const WRITE_OPTIONS = { encoding: "utf8", mode: SECRET_FILE_MODE };
14
14
  /**
15
15
  * The file a write must land IN, which is not always the path it is addressed BY. pi writes these files in place,
@@ -27,9 +27,15 @@ function writeTarget(path) {
27
27
  return link?.isSymbolicLink() ? resolve(dirname(path), readlinkSync(path)) : path;
28
28
  }
29
29
  /** Serialized cross-process read-modify-write of one file, replaced whole so its readers need no lock. */
30
- export async function withLockedFile(path, fn, options = {}) {
30
+ export async function withLockedFile(path, fn,
31
+ /**
32
+ * `mode`: the replaced file's permissions; default {@link SECRET_FILE_MODE}, for the credential and catalog files.
33
+ * `create: false` locks a file that may not exist without creating it (the lock is `<file>.lock` either way), for a
34
+ * lock that guards more than the file it is named after.
35
+ */
36
+ options = {}) {
31
37
  mkdirSync(dirname(path), { recursive: true });
32
- if (!existsSync(path)) {
38
+ if (options.create !== false && !existsSync(path)) {
33
39
  try {
34
40
  // `wx` makes this an exclusive CREATE, which is the one case `writeFileSync` honours `mode` in — so no chmod
35
41
  // after it (unlike writeFileAtomic, whose temp may already exist from a crashed writer).
@@ -73,7 +79,7 @@ export async function withLockedFile(path, fn, options = {}) {
73
79
  // Rename, not an in-place rewrite: it is what lets `read` stay unlocked, and it is the only spelling that applies
74
80
  // the mode before the content is reachable.
75
81
  if (out.next !== undefined) {
76
- writeFileAtomic(writeTarget(path), out.next, SECRET_FILE_MODE);
82
+ writeFileAtomic(writeTarget(path), out.next, options.mode ?? SECRET_FILE_MODE);
77
83
  }
78
84
  throwIfCompromised();
79
85
  result = out.result;
package/dist/once.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import * as Effect from "effect/Effect";
2
+ /**
3
+ * The first call runs `work` to the end, uninterruptibly; every call, the first included, then reads its one outcome.
4
+ * A call made while the work is running, including one the work itself causes, waits for it.
5
+ */
6
+ export declare function once<A, E, R>(work: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>;
package/dist/once.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Work that runs at most once per process, whose outcome every caller shares, success or failure.
3
+ *
4
+ * `Effect.cached` is not that in effect 4.0.x: it interrupts a run once every caller has left it, and a run that
5
+ * finishes anyway (uninterruptible) is not cached, so the next caller starts the work a second time; and a call made
6
+ * while its run is still starting joins a fiber that is not assigned yet and dies.
7
+ */
8
+ import * as Deferred from "effect/Deferred";
9
+ import * as Effect from "effect/Effect";
10
+ /**
11
+ * The first call runs `work` to the end, uninterruptibly; every call, the first included, then reads its one outcome.
12
+ * A call made while the work is running, including one the work itself causes, waits for it.
13
+ */
14
+ export function once(work) {
15
+ const outcome = Deferred.makeUnsafe();
16
+ let started = false;
17
+ return Effect.suspend(() => {
18
+ if (started)
19
+ return Deferred.await(outcome);
20
+ started = true;
21
+ return work.pipe(Effect.exit, Effect.flatMap((exit) => Deferred.done(outcome, exit)), Effect.uninterruptible, Effect.andThen(Deferred.await(outcome)));
22
+ });
23
+ }