@fastagent-sh/fastagent 0.24.4 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (487) hide show
  1. package/README.md +54 -82
  2. package/dist/agent-api.d.ts +460 -0
  3. package/dist/agent-api.js +209 -0
  4. package/dist/answer-text.d.ts +8 -0
  5. package/dist/answer-text.js +18 -0
  6. package/dist/atomic-write.d.ts +2 -2
  7. package/dist/atomic-write.js +2 -2
  8. package/dist/authoring.d.ts +81 -0
  9. package/dist/authoring.js +245 -0
  10. package/dist/channel.d.ts +29 -15
  11. package/dist/channel.js +4 -1
  12. package/dist/channels/agentcore-protocol.d.ts +36 -50
  13. package/dist/channels/agentcore-protocol.js +3 -3
  14. package/dist/channels/agentcore-service.d.ts +8 -18
  15. package/dist/channels/agentcore-service.js +108 -127
  16. package/dist/channels/agentcore.d.ts +8 -24
  17. package/dist/channels/agentcore.js +32 -65
  18. package/dist/channels/body.d.ts +0 -16
  19. package/dist/channels/body.js +0 -25
  20. package/dist/channels/busy.js +6 -1
  21. package/dist/channels/context.d.ts +4 -0
  22. package/dist/channels/context.js +35 -0
  23. package/dist/channels/discover.d.ts +18 -20
  24. package/dist/channels/discover.js +41 -99
  25. package/dist/channels/feishu/feishu-api.d.ts +54 -4
  26. package/dist/channels/feishu/feishu-api.js +192 -149
  27. package/dist/channels/feishu/feishu.d.ts +3 -0
  28. package/dist/channels/feishu/feishu.js +117 -106
  29. package/dist/channels/feishu/history.d.ts +55 -0
  30. package/dist/channels/feishu/history.js +199 -0
  31. package/dist/channels/feishu/invoke-turn.d.ts +13 -11
  32. package/dist/channels/feishu/invoke-turn.js +9 -10
  33. package/dist/channels/feishu/model.d.ts +2 -1
  34. package/dist/channels/feishu/normalize.js +100 -0
  35. package/dist/channels/feishu/preview.d.ts +2 -2
  36. package/dist/channels/feishu/register-webhook.d.ts +1 -0
  37. package/dist/channels/feishu/register-webhook.js +3 -2
  38. package/dist/channels/feishu/scaffold/channel.ts +65 -46
  39. package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
  40. package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
  41. package/dist/channels/feishu/setup-mode.d.ts +45 -25
  42. package/dist/channels/feishu/setup-mode.js +74 -23
  43. package/dist/channels/feishu/shared-api.d.ts +24 -6
  44. package/dist/channels/feishu/shared-api.js +30 -24
  45. package/dist/channels/kit/context-buffer.d.ts +11 -2
  46. package/dist/channels/kit/context-buffer.js +7 -4
  47. package/dist/channels/kit/delivery.d.ts +19 -3
  48. package/dist/channels/kit/delivery.js +74 -15
  49. package/dist/channels/kit/event-stream.js +2 -1
  50. package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
  51. package/dist/channels/kit/invoke-turn-kit.js +62 -71
  52. package/dist/channels/kit/place-history.d.ts +107 -0
  53. package/dist/channels/kit/place-history.js +182 -0
  54. package/dist/channels/kit/preview-kit.d.ts +9 -5
  55. package/dist/channels/kit/preview-kit.js +36 -15
  56. package/dist/channels/kit/room-threads.d.ts +46 -0
  57. package/dist/channels/kit/room-threads.js +81 -0
  58. package/dist/channels/kit/seen.js +1 -1
  59. package/dist/channels/kit/stop-command.d.ts +6 -3
  60. package/dist/channels/kit/stop-command.js +20 -18
  61. package/dist/channels/kit/thread-fork.d.ts +17 -0
  62. package/dist/channels/kit/thread-fork.js +43 -0
  63. package/dist/channels/kit/thread-participants.js +1 -1
  64. package/dist/channels/kit/transport.d.ts +5 -0
  65. package/dist/channels/kit/transport.js +5 -0
  66. package/dist/channels/kit/turn-runner.d.ts +10 -9
  67. package/dist/channels/kit/turn-runner.js +17 -19
  68. package/dist/channels/kit/turn-store.d.ts +5 -4
  69. package/dist/channels/kit/turn-store.js +5 -5
  70. package/dist/channels/lark/lark.d.ts +3 -0
  71. package/dist/channels/lark/lark.js +5 -0
  72. package/dist/channels/lark/onboard.d.ts +5 -3
  73. package/dist/channels/lark/onboard.js +14 -14
  74. package/dist/channels/lark/scaffold/channel.ts +67 -44
  75. package/dist/channels/lark/scaffold/lark-send.ts +38 -33
  76. package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
  77. package/dist/channels/respond.d.ts +0 -4
  78. package/dist/channels/respond.js +1 -1
  79. package/dist/channels/router.d.ts +18 -0
  80. package/dist/channels/router.js +68 -0
  81. package/dist/channels/serve.d.ts +5 -70
  82. package/dist/channels/serve.js +105 -287
  83. package/dist/channels/slack/history.d.ts +42 -0
  84. package/dist/channels/slack/history.js +282 -0
  85. package/dist/channels/slack/invoke-turn.d.ts +12 -5
  86. package/dist/channels/slack/invoke-turn.js +7 -5
  87. package/dist/channels/slack/manifest.d.ts +1 -4
  88. package/dist/channels/slack/manifest.js +22 -10
  89. package/dist/channels/slack/model.d.ts +2 -1
  90. package/dist/channels/slack/onboard.d.ts +0 -2
  91. package/dist/channels/slack/onboard.js +2 -4
  92. package/dist/channels/slack/onboarding-state.d.ts +0 -2
  93. package/dist/channels/slack/onboarding-state.js +0 -1
  94. package/dist/channels/slack/parse.d.ts +0 -5
  95. package/dist/channels/slack/parse.js +1 -16
  96. package/dist/channels/slack/preview.d.ts +2 -3
  97. package/dist/channels/slack/preview.js +78 -52
  98. package/dist/channels/slack/register-webhook.d.ts +1 -0
  99. package/dist/channels/slack/register-webhook.js +6 -5
  100. package/dist/channels/slack/scaffold/channel.ts +23 -24
  101. package/dist/channels/slack/scaffold/slack-send.ts +50 -43
  102. package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
  103. package/dist/channels/slack/setup-server.d.ts +19 -0
  104. package/dist/channels/slack/setup-server.js +113 -11
  105. package/dist/channels/slack/shared-api.d.ts +15 -4
  106. package/dist/channels/slack/shared-api.js +19 -14
  107. package/dist/channels/slack/slack-api.d.ts +61 -2
  108. package/dist/channels/slack/slack-api.js +28 -5
  109. package/dist/channels/slack/slack.js +97 -52
  110. package/dist/channels/slack/welcomed.js +1 -1
  111. package/dist/channels/telegram/context-buffer.d.ts +6 -1
  112. package/dist/channels/telegram/context-buffer.js +19 -0
  113. package/dist/channels/telegram/invoke-turn.d.ts +8 -4
  114. package/dist/channels/telegram/invoke-turn.js +7 -7
  115. package/dist/channels/telegram/parse.d.ts +7 -2
  116. package/dist/channels/telegram/parse.js +7 -0
  117. package/dist/channels/telegram/preview.d.ts +2 -2
  118. package/dist/channels/telegram/register-webhook.d.ts +1 -0
  119. package/dist/channels/telegram/register-webhook.js +3 -2
  120. package/dist/channels/telegram/scaffold/channel.ts +27 -28
  121. package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
  122. package/dist/channels/telegram/shared-api.d.ts +34 -0
  123. package/dist/channels/telegram/shared-api.js +79 -0
  124. package/dist/channels/telegram/telegram-api.d.ts +15 -5
  125. package/dist/channels/telegram/telegram-api.js +10 -6
  126. package/dist/channels/telegram/telegram.js +27 -21
  127. package/dist/channels/telegram/turn-store.js +1 -1
  128. package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
  129. package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
  130. package/dist/cli/add-feishu.d.ts +42 -12
  131. package/dist/cli/add-feishu.js +177 -124
  132. package/dist/cli/add-slack.d.ts +8 -3
  133. package/dist/cli/add-slack.js +116 -64
  134. package/dist/cli/auth-view.d.ts +10 -3
  135. package/dist/cli/auth-view.js +8 -6
  136. package/dist/cli/box-login.d.ts +18 -7
  137. package/dist/cli/box-login.js +46 -12
  138. package/dist/cli/commands/add.d.ts +15 -4
  139. package/dist/cli/commands/add.js +253 -143
  140. package/dist/cli/commands/auth.d.ts +6 -0
  141. package/dist/cli/commands/auth.js +50 -0
  142. package/dist/cli/commands/content.d.ts +6 -0
  143. package/dist/cli/commands/content.js +45 -0
  144. package/dist/cli/commands/deploy/agentcore.js +50 -77
  145. package/dist/cli/commands/deploy/docker.js +38 -39
  146. package/dist/cli/commands/deploy/fly.js +21 -18
  147. package/dist/cli/commands/deploy/host-login.d.ts +26 -0
  148. package/dist/cli/commands/deploy/host-login.js +90 -0
  149. package/dist/cli/commands/deploy/railway.js +21 -26
  150. package/dist/cli/commands/deploy/shared.d.ts +45 -17
  151. package/dist/cli/commands/deploy/shared.js +34 -15
  152. package/dist/cli/commands/deploy.d.ts +0 -4
  153. package/dist/cli/commands/deploy.js +237 -50
  154. package/dist/cli/commands/destroy.js +8 -6
  155. package/dist/cli/commands/dev.d.ts +0 -2
  156. package/dist/cli/commands/dev.js +20 -19
  157. package/dist/cli/commands/env.d.ts +12 -0
  158. package/dist/cli/commands/env.js +191 -0
  159. package/dist/cli/commands/info.js +95 -156
  160. package/dist/cli/commands/init.d.ts +2 -2
  161. package/dist/cli/commands/init.js +35 -33
  162. package/dist/cli/commands/invoke.d.ts +6 -0
  163. package/dist/cli/commands/invoke.js +132 -16
  164. package/dist/cli/commands/login.d.ts +31 -2
  165. package/dist/cli/commands/login.js +416 -65
  166. package/dist/cli/commands/logout.d.ts +4 -0
  167. package/dist/cli/commands/logout.js +53 -0
  168. package/dist/cli/commands/logs.js +8 -6
  169. package/dist/cli/commands/models.d.ts +2 -1
  170. package/dist/cli/commands/models.js +39 -37
  171. package/dist/cli/commands/schedules.d.ts +21 -0
  172. package/dist/cli/commands/schedules.js +143 -0
  173. package/dist/cli/commands/start.d.ts +11 -10
  174. package/dist/cli/commands/start.js +35 -62
  175. package/dist/cli/content-view.d.ts +9 -0
  176. package/dist/cli/content-view.js +26 -0
  177. package/dist/cli/fail.d.ts +9 -12
  178. package/dist/cli/fail.js +17 -14
  179. package/dist/cli/invoke-stream.d.ts +12 -3
  180. package/dist/cli/invoke-stream.js +85 -23
  181. package/dist/cli/kernel.d.ts +9 -2
  182. package/dist/cli/kernel.js +15 -6
  183. package/dist/cli/login-relay.d.ts +6 -4
  184. package/dist/cli/login-relay.js +19 -7
  185. package/dist/cli/models-view.d.ts +5 -1
  186. package/dist/cli/models-view.js +1 -1
  187. package/dist/cli/person.d.ts +10 -0
  188. package/dist/cli/person.js +23 -0
  189. package/dist/cli/program.js +421 -203
  190. package/dist/cli/serve.d.ts +13 -63
  191. package/dist/cli/serve.js +31 -121
  192. package/dist/cli/shared.d.ts +21 -48
  193. package/dist/cli/shared.js +70 -89
  194. package/dist/cli/ticket.d.ts +136 -0
  195. package/dist/cli/ticket.js +476 -0
  196. package/dist/client.d.ts +7 -0
  197. package/dist/client.js +2 -0
  198. package/dist/content/declare.d.ts +70 -0
  199. package/dist/content/declare.js +163 -0
  200. package/dist/content/file.d.ts +32 -0
  201. package/dist/content/file.js +119 -0
  202. package/dist/content/git.d.ts +41 -0
  203. package/dist/content/git.js +220 -0
  204. package/dist/content/mount.d.ts +2 -0
  205. package/dist/content/mount.js +15 -0
  206. package/dist/content/resolve.d.ts +52 -0
  207. package/dist/content/resolve.js +151 -0
  208. package/dist/content/source.d.ts +27 -0
  209. package/dist/content/source.js +53 -0
  210. package/dist/conversation-sessions.d.ts +26 -0
  211. package/dist/conversation-sessions.js +99 -0
  212. package/dist/declared-secrets.d.ts +19 -37
  213. package/dist/declared-secrets.js +16 -58
  214. package/dist/deploy/agentcore/destroy.d.ts +3 -3
  215. package/dist/deploy/agentcore/destroy.js +46 -28
  216. package/dist/deploy/agentcore/forwarder.js +105 -22
  217. package/dist/deploy/agentcore/logs.js +1 -1
  218. package/dist/deploy/agentcore/plan.d.ts +10 -24
  219. package/dist/deploy/agentcore/plan.js +31 -135
  220. package/dist/deploy/agentcore/run.d.ts +1 -1
  221. package/dist/deploy/agentcore/run.js +8 -5
  222. package/dist/deploy/agentcore/shell.d.ts +1 -1
  223. package/dist/deploy/agentcore/shell.js +5 -5
  224. package/dist/deploy/api.d.ts +34 -0
  225. package/dist/deploy/api.js +50 -0
  226. package/dist/deploy/box-shell.d.ts +6 -0
  227. package/dist/deploy/box-shell.js +7 -0
  228. package/dist/deploy/build-context.d.ts +7 -5
  229. package/dist/deploy/build-context.js +41 -35
  230. package/dist/deploy/channel-ingress.d.ts +6 -1
  231. package/dist/deploy/channel-ingress.js +18 -5
  232. package/dist/deploy/container.d.ts +22 -9
  233. package/dist/deploy/container.js +96 -55
  234. package/dist/deploy/docker/plan.d.ts +3 -2
  235. package/dist/deploy/docker/plan.js +13 -14
  236. package/dist/deploy/docker/run.d.ts +2 -2
  237. package/dist/deploy/docker/run.js +8 -4
  238. package/dist/deploy/fly/plan.d.ts +1 -1
  239. package/dist/deploy/fly/plan.js +12 -21
  240. package/dist/deploy/fly/run.d.ts +10 -6
  241. package/dist/deploy/fly/run.js +11 -6
  242. package/dist/deploy/hosts.d.ts +2 -1
  243. package/dist/deploy/hosts.js +2 -1
  244. package/dist/deploy/preflight.d.ts +21 -23
  245. package/dist/deploy/preflight.js +223 -202
  246. package/dist/deploy/railway/plan.d.ts +8 -6
  247. package/dist/deploy/railway/plan.js +15 -58
  248. package/dist/deploy/railway/run.d.ts +8 -3
  249. package/dist/deploy/railway/run.js +12 -8
  250. package/dist/deploy/residency.d.ts +5 -11
  251. package/dist/deploy/residency.js +0 -6
  252. package/dist/deploy/runner.d.ts +1 -1
  253. package/dist/deploy/runner.js +1 -1
  254. package/dist/deploy/secrets.d.ts +16 -2
  255. package/dist/deploy/secrets.js +33 -6
  256. package/dist/deploy/workspace.d.ts +11 -6
  257. package/dist/deploy/workspace.js +55 -38
  258. package/dist/dev-supervisor.d.ts +11 -2
  259. package/dist/dev-supervisor.js +52 -27
  260. package/dist/effect-port.d.ts +4 -4
  261. package/dist/effect-port.js +4 -4
  262. package/dist/env.d.ts +0 -13
  263. package/dist/env.js +1 -44
  264. package/dist/environment/apt.d.ts +4 -0
  265. package/dist/environment/apt.js +32 -0
  266. package/dist/environment/declare.d.ts +59 -0
  267. package/dist/environment/declare.js +210 -0
  268. package/dist/environment/mise.d.ts +51 -0
  269. package/dist/environment/mise.js +272 -0
  270. package/dist/feishu.d.ts +2 -2
  271. package/dist/feishu.js +2 -2
  272. package/dist/git.d.ts +13 -0
  273. package/dist/git.js +55 -0
  274. package/dist/harnesses/models/catalog.d.ts +20 -0
  275. package/dist/harnesses/models/catalog.js +254 -0
  276. package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
  277. package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
  278. package/dist/harnesses/models/environment.d.ts +48 -0
  279. package/dist/harnesses/models/environment.js +88 -0
  280. package/dist/harnesses/models/host.d.ts +30 -0
  281. package/dist/harnesses/models/host.js +97 -0
  282. package/dist/{engines/pi → harnesses/models}/login.d.ts +66 -70
  283. package/dist/harnesses/models/login.js +439 -0
  284. package/dist/harnesses/models/models.d.ts +84 -0
  285. package/dist/harnesses/models/models.js +197 -0
  286. package/dist/harnesses/pi-durable/agent.d.ts +42 -0
  287. package/dist/harnesses/pi-durable/agent.js +581 -0
  288. package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
  289. package/dist/harnesses/pi-durable/defaults.js +26 -0
  290. package/dist/harnesses/pi-durable/define.d.ts +77 -0
  291. package/dist/harnesses/pi-durable/define.js +28 -0
  292. package/dist/harnesses/pi-durable/entries.d.ts +32 -0
  293. package/dist/harnesses/pi-durable/entries.js +126 -0
  294. package/dist/harnesses/pi-durable/events.d.ts +25 -0
  295. package/dist/harnesses/pi-durable/events.js +238 -0
  296. package/dist/harnesses/pi-durable/ids.d.ts +16 -0
  297. package/dist/harnesses/pi-durable/ids.js +55 -0
  298. package/dist/harnesses/pi-durable/messages.d.ts +41 -0
  299. package/dist/harnesses/pi-durable/messages.js +116 -0
  300. package/dist/harnesses/pi-durable/open.d.ts +95 -0
  301. package/dist/harnesses/pi-durable/open.js +330 -0
  302. package/dist/harnesses/pi-durable/reads.d.ts +30 -0
  303. package/dist/harnesses/pi-durable/reads.js +94 -0
  304. package/dist/harnesses/pi-durable/registry.d.ts +18 -0
  305. package/dist/harnesses/pi-durable/registry.js +56 -0
  306. package/dist/harnesses/pi-durable/release.d.ts +13 -0
  307. package/dist/harnesses/pi-durable/release.js +40 -0
  308. package/dist/harnesses/pi-durable/serve.d.ts +90 -0
  309. package/dist/harnesses/pi-durable/serve.js +186 -0
  310. package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
  311. package/dist/harnesses/pi-durable/sessions.js +47 -0
  312. package/dist/harnesses/pi-durable/storage.d.ts +4 -0
  313. package/dist/harnesses/pi-durable/storage.js +49 -0
  314. package/dist/harnesses/pi-durable/stream.d.ts +20 -0
  315. package/dist/harnesses/pi-durable/stream.js +221 -0
  316. package/dist/harnesses/pi-durable/text.d.ts +30 -0
  317. package/dist/harnesses/pi-durable/text.js +292 -0
  318. package/dist/harnesses/pi-durable/wake.d.ts +11 -0
  319. package/dist/harnesses/pi-durable/wake.js +90 -0
  320. package/dist/http/client.d.ts +6 -0
  321. package/dist/http/client.js +256 -0
  322. package/dist/http/contract.d.ts +541 -0
  323. package/dist/http/contract.js +179 -0
  324. package/dist/http/server.d.ts +34 -0
  325. package/dist/http/server.js +194 -0
  326. package/dist/index.d.ts +19 -4
  327. package/dist/index.js +13 -5
  328. package/dist/lark.d.ts +2 -2
  329. package/dist/lark.js +2 -2
  330. package/dist/locked-file.d.ts +17 -0
  331. package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
  332. package/dist/once.d.ts +6 -0
  333. package/dist/once.js +23 -0
  334. package/dist/paths.d.ts +36 -52
  335. package/dist/paths.js +66 -182
  336. package/dist/runtime.d.ts +25 -2
  337. package/dist/runtime.js +27 -0
  338. package/dist/scaffold/add-channel.d.ts +14 -27
  339. package/dist/scaffold/add-channel.js +82 -180
  340. package/dist/scaffold/init.d.ts +17 -18
  341. package/dist/scaffold/init.js +87 -99
  342. package/dist/scaffold/templates/SYSTEM.md +12 -0
  343. package/dist/scaffold/templates/env.example +4 -10
  344. package/dist/scaffold/templates/fastagent.config.ts +21 -33
  345. package/dist/scaffold/templates/gitignore +8 -1
  346. package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
  347. package/dist/scaffold/templates.d.ts +9 -4
  348. package/dist/scaffold/templates.js +7 -5
  349. package/dist/scaffold/vendor-skill.d.ts +1 -4
  350. package/dist/scaffold/vendor-skill.js +5 -6
  351. package/dist/schedule/cron.d.ts +13 -0
  352. package/dist/schedule/cron.js +52 -0
  353. package/dist/schedule/eventbridge-cron.d.ts +17 -0
  354. package/dist/schedule/eventbridge-cron.js +88 -0
  355. package/dist/schedule/schedule.d.ts +23 -0
  356. package/dist/schedule/schedule.js +34 -0
  357. package/dist/schedule/scheduler.d.ts +34 -33
  358. package/dist/schedule/scheduler.js +251 -137
  359. package/dist/schedule/state.d.ts +4 -14
  360. package/dist/schedule/state.js +7 -7
  361. package/dist/schedule/wake-alarm.d.ts +22 -2
  362. package/dist/schedule/wake-alarm.js +66 -20
  363. package/dist/schedule/wakeups.d.ts +16 -15
  364. package/dist/schedule/wakeups.js +47 -45
  365. package/dist/service.d.ts +56 -169
  366. package/dist/service.js +91 -187
  367. package/dist/serving-command.d.ts +10 -0
  368. package/dist/serving-command.js +16 -0
  369. package/dist/sign-in-api.d.ts +147 -0
  370. package/dist/sign-in-api.js +9 -0
  371. package/dist/slack.d.ts +1 -1
  372. package/dist/slack.js +1 -1
  373. package/dist/{channels/kit/state.js → state-file.js} +6 -6
  374. package/dist/telegram.d.ts +1 -0
  375. package/dist/telegram.js +1 -0
  376. package/dist/tunnel.d.ts +3 -0
  377. package/dist/tunnel.js +14 -5
  378. package/dist/value-file.d.ts +40 -0
  379. package/dist/value-file.js +164 -0
  380. package/dist/version.d.ts +5 -0
  381. package/dist/version.js +14 -1
  382. package/package.json +18 -28
  383. package/dist/agent.d.ts +0 -106
  384. package/dist/agent.js +0 -21
  385. package/dist/channels/control.d.ts +0 -31
  386. package/dist/channels/control.js +0 -329
  387. package/dist/channels/define-channel.d.ts +0 -39
  388. package/dist/channels/define-channel.js +0 -9
  389. package/dist/channels/feishu/context-buffer.d.ts +0 -35
  390. package/dist/channels/feishu/context-buffer.js +0 -65
  391. package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
  392. package/dist/channels/http.d.ts +0 -23
  393. package/dist/channels/http.js +0 -57
  394. package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
  395. package/dist/channels/slack/context-buffer.d.ts +0 -23
  396. package/dist/channels/slack/context-buffer.js +0 -37
  397. package/dist/channels/sse.d.ts +0 -4
  398. package/dist/channels/sse.js +0 -66
  399. package/dist/cli/commands/chat.d.ts +0 -3
  400. package/dist/cli/commands/chat.js +0 -14
  401. package/dist/cli/commands/routine-run.d.ts +0 -6
  402. package/dist/cli/commands/routine-run.js +0 -46
  403. package/dist/cli/commands/routine.d.ts +0 -25
  404. package/dist/cli/commands/routine.js +0 -122
  405. package/dist/cli/commands/tool.d.ts +0 -1
  406. package/dist/cli/commands/tool.js +0 -57
  407. package/dist/collect.d.ts +0 -63
  408. package/dist/collect.js +0 -90
  409. package/dist/core.d.ts +0 -13
  410. package/dist/core.js +0 -15
  411. package/dist/engines/pi/agent-models.d.ts +0 -83
  412. package/dist/engines/pi/agent-models.js +0 -120
  413. package/dist/engines/pi/agent-session-factory.d.ts +0 -121
  414. package/dist/engines/pi/agent-session-factory.js +0 -535
  415. package/dist/engines/pi/chat.d.ts +0 -3
  416. package/dist/engines/pi/chat.js +0 -8
  417. package/dist/engines/pi/config.d.ts +0 -71
  418. package/dist/engines/pi/config.js +0 -199
  419. package/dist/engines/pi/create.d.ts +0 -170
  420. package/dist/engines/pi/create.js +0 -343
  421. package/dist/engines/pi/definition.d.ts +0 -74
  422. package/dist/engines/pi/definition.js +0 -236
  423. package/dist/engines/pi/entry-images.d.ts +0 -14
  424. package/dist/engines/pi/entry-images.js +0 -23
  425. package/dist/engines/pi/invoke-session.d.ts +0 -18
  426. package/dist/engines/pi/invoke-session.js +0 -403
  427. package/dist/engines/pi/locked-file.d.ts +0 -9
  428. package/dist/engines/pi/login.js +0 -331
  429. package/dist/engines/pi/machine.d.ts +0 -53
  430. package/dist/engines/pi/machine.js +0 -137
  431. package/dist/engines/pi/models.d.ts +0 -200
  432. package/dist/engines/pi/models.js +0 -533
  433. package/dist/engines/pi/open.d.ts +0 -180
  434. package/dist/engines/pi/open.js +0 -270
  435. package/dist/engines/pi/openai-account-models.d.ts +0 -35
  436. package/dist/engines/pi/openai-account-models.js +0 -116
  437. package/dist/engines/pi/report.d.ts +0 -18
  438. package/dist/engines/pi/report.js +0 -59
  439. package/dist/engines/pi/retry-event.d.ts +0 -6
  440. package/dist/engines/pi/retry-event.js +0 -15
  441. package/dist/engines/pi/service.d.ts +0 -9
  442. package/dist/engines/pi/service.js +0 -14
  443. package/dist/engines/pi/session-builder.d.ts +0 -13
  444. package/dist/engines/pi/session-builder.js +0 -117
  445. package/dist/engines/pi/session-control.d.ts +0 -77
  446. package/dist/engines/pi/session-control.js +0 -908
  447. package/dist/engines/pi/session-effects.d.ts +0 -14
  448. package/dist/engines/pi/session-effects.js +0 -30
  449. package/dist/engines/pi/session-inheritance.d.ts +0 -21
  450. package/dist/engines/pi/session-inheritance.js +0 -204
  451. package/dist/engines/pi/session-markers.d.ts +0 -49
  452. package/dist/engines/pi/session-markers.js +0 -60
  453. package/dist/engines/pi/session-settings.d.ts +0 -67
  454. package/dist/engines/pi/session-settings.js +0 -119
  455. package/dist/engines/pi/session-store.d.ts +0 -69
  456. package/dist/engines/pi/session-store.js +0 -430
  457. package/dist/engines/pi/tool-context.d.ts +0 -45
  458. package/dist/engines/pi/tool-context.js +0 -31
  459. package/dist/engines/pi/tool.d.ts +0 -99
  460. package/dist/engines/pi/tool.js +0 -118
  461. package/dist/engines/pi/turn-kit.d.ts +0 -92
  462. package/dist/engines/pi/turn-kit.js +0 -288
  463. package/dist/engines/pi/wake-tool.d.ts +0 -9
  464. package/dist/engines/pi/wake-tool.js +0 -92
  465. package/dist/loader.d.ts +0 -41
  466. package/dist/loader.js +0 -116
  467. package/dist/node.d.ts +0 -3
  468. package/dist/node.js +0 -4
  469. package/dist/observe.d.ts +0 -6
  470. package/dist/observe.js +0 -47
  471. package/dist/pi.d.ts +0 -25
  472. package/dist/pi.js +0 -15
  473. package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
  474. package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
  475. package/dist/schedule/discover.d.ts +0 -17
  476. package/dist/schedule/discover.js +0 -61
  477. package/dist/schedule/routine.d.ts +0 -43
  478. package/dist/schedule/routine.js +0 -32
  479. package/dist/schedule/run.d.ts +0 -55
  480. package/dist/schedule/run.js +0 -146
  481. package/dist/secrets-gate.d.ts +0 -32
  482. package/dist/secrets-gate.js +0 -33
  483. package/dist/session-remote.d.ts +0 -47
  484. package/dist/session-remote.js +0 -460
  485. package/dist/session.d.ts +0 -466
  486. package/dist/session.js +0 -57
  487. /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `messages.stream` (SPEC.md §6.2): send a message and deliver it as it is written, over the Agent's own reads.
3
+ * The session is watched before the message is sent, so nothing it writes afterwards is missed; a send whose key the
4
+ * session has seen delivers that message from wherever it is.
5
+ */
6
+ import { type Entry, type Message, type MessageStreamEvent, type Page, type SendRequest, type SessionEvent } from "../../agent-api.ts";
7
+ export interface StreamSource {
8
+ events(sessionId: string, after?: string): AsyncIterable<SessionEvent>;
9
+ /** A send, and whether its key had already been sent: the message is then delivered from where it is. */
10
+ admit(request: SendRequest): Promise<{
11
+ message: Message;
12
+ replayed: boolean;
13
+ }>;
14
+ get(sessionId: string, messageId: string): Promise<Message>;
15
+ entry(sessionId: string, entryId: string): Promise<Entry>;
16
+ entries(sessionId: string, options: {
17
+ after: string;
18
+ }): Promise<Page<Entry>>;
19
+ }
20
+ export declare function messageStream(source: StreamSource, request: SendRequest, signal: AbortSignal | undefined): AsyncIterable<MessageStreamEvent>;
@@ -0,0 +1,221 @@
1
+ /**
2
+ * `messages.stream` (SPEC.md §6.2): send a message and deliver it as it is written, over the Agent's own reads.
3
+ * The session is watched before the message is sent, so nothing it writes afterwards is missed; a send whose key the
4
+ * session has seen delivers that message from wherever it is.
5
+ */
6
+ import { AgentError, agentError, errorData, hasEnded, } from "../../agent-api.js";
7
+ const messageOf = (entry) => entry.kind === "user" ? entry.data.messageId : undefined;
8
+ /**
9
+ * The next of `events`, a read that failed as the `stream_error` it is once the message has been delivered: a session
10
+ * watched again cannot reject the stream then, or a Caller would take a message already recorded for one refused.
11
+ */
12
+ const nextOf = (events) => events.next().catch((error) => ({ done: false, value: failedRead(error) }));
13
+ const failedRead = (error) => ({
14
+ type: "stream_error",
15
+ error: errorData(error instanceof AgentError
16
+ ? error
17
+ : agentError("internal", error instanceof Error ? error.message : String(error))),
18
+ });
19
+ export function messageStream(source, request, signal) {
20
+ const { sessionId } = request;
21
+ let active;
22
+ const leave = () => {
23
+ const current = active;
24
+ active = undefined;
25
+ void current?.return?.();
26
+ };
27
+ const follow = (after) => {
28
+ leave();
29
+ active = source.events(sessionId, after)[Symbol.asyncIterator]();
30
+ return active;
31
+ };
32
+ /** From the message's `user` entry, which arrives live, through its `done`. */
33
+ async function* live(watching, id) {
34
+ let opened = false;
35
+ for (let next = await watching.next(); !next.done; next = await watching.next()) {
36
+ const event = next.value;
37
+ if (event.type === "stream_error")
38
+ return yield event;
39
+ // A queued message withdrawn by a cancel ends without ever being taken.
40
+ if (event.type === "done" && event.message.id === id)
41
+ return yield event;
42
+ if (!opened && event.type === "entry" && messageOf(event.entry) === id)
43
+ opened = true;
44
+ if (opened)
45
+ yield event;
46
+ }
47
+ }
48
+ /**
49
+ * A running message sent again, whose `user` entry was written before: its entries so far, then live. What the
50
+ * session replays is held until the message is read again, since one that ended meanwhile may have been followed by
51
+ * the next message's entries.
52
+ */
53
+ async function* running(message) {
54
+ let opening;
55
+ try {
56
+ opening = await source.entry(sessionId, message.entryId);
57
+ }
58
+ catch (error) {
59
+ return yield failedRead(error);
60
+ }
61
+ const after = follow(message.entryId);
62
+ const held = [];
63
+ for (let next = await nextOf(after); !next.done; next = await nextOf(after)) {
64
+ const event = next.value;
65
+ if (event.type === "stream_error")
66
+ return yield event;
67
+ if (event.type !== "state") {
68
+ held.push(event);
69
+ continue;
70
+ }
71
+ let now;
72
+ try {
73
+ now = await source.get(sessionId, message.id);
74
+ }
75
+ catch (error) {
76
+ return yield failedRead(error);
77
+ }
78
+ if (hasEnded(now)) {
79
+ leave();
80
+ return yield* ended(now, opening, held);
81
+ }
82
+ yield { type: "entry", entry: opening };
83
+ yield* held;
84
+ yield event;
85
+ for (let next = await nextOf(after); !next.done; next = await nextOf(after)) {
86
+ const event = next.value;
87
+ yield event;
88
+ if (event.type === "stream_error")
89
+ return;
90
+ if (event.type === "done" && event.message.id === message.id)
91
+ return;
92
+ }
93
+ return;
94
+ }
95
+ }
96
+ /** An ended message: its entries through its answer, then its `done`. */
97
+ async function* ended(done, opening, held) {
98
+ const { entryId, answer } = done;
99
+ if (entryId === undefined)
100
+ return yield { type: "done", message: done };
101
+ try {
102
+ yield { type: "entry", entry: opening ?? (await source.entry(sessionId, entryId)) };
103
+ }
104
+ catch (error) {
105
+ return yield failedRead(error);
106
+ }
107
+ if (answer === undefined)
108
+ return yield { type: "done", message: done };
109
+ const through = held?.findIndex((event) => event.type === "entry" && event.entry.id === answer.entryId) ?? -1;
110
+ if (held !== undefined && through !== -1) {
111
+ yield* held.slice(0, through + 1).filter((event) => event.type === "entry");
112
+ return yield { type: "done", message: done };
113
+ }
114
+ let cursor = entryId;
115
+ for (;;) {
116
+ let page;
117
+ try {
118
+ page = await source.entries(sessionId, { after: cursor });
119
+ }
120
+ catch (error) {
121
+ return yield failedRead(error);
122
+ }
123
+ for (const entry of page.data) {
124
+ yield { type: "entry", entry };
125
+ if (entry.id === answer.entryId)
126
+ return yield { type: "done", message: done };
127
+ }
128
+ if (page.next === undefined) {
129
+ return yield failedRead(agentError("internal", `the answer ${answer.entryId} of message ${done.id} is not in its session`));
130
+ }
131
+ cursor = page.next;
132
+ }
133
+ }
134
+ async function* events() {
135
+ try {
136
+ const watching = follow();
137
+ const snapshot = await watching.next();
138
+ if (snapshot.done || snapshot.value.type !== "state") {
139
+ if (!snapshot.done && snapshot.value.type === "stream_error")
140
+ throw new AgentError(snapshot.value.error);
141
+ throw agentError("internal", "the session's events did not begin with its state");
142
+ }
143
+ const { message, replayed } = await source.admit(request);
144
+ yield { type: "message", message };
145
+ if (hasEnded(message)) {
146
+ leave();
147
+ yield* ended(message);
148
+ }
149
+ else if (replayed && message.status === "running" && message.entryId !== undefined) {
150
+ yield* running({ ...message, entryId: message.entryId });
151
+ }
152
+ else
153
+ yield* live(watching, message.id);
154
+ }
155
+ finally {
156
+ leave();
157
+ }
158
+ }
159
+ return { [Symbol.asyncIterator]: () => leavableIterator(events(), leave, signal) };
160
+ }
161
+ /**
162
+ * A stream the Caller can leave at any point. An async generator suspended on an await parks inside it, and
163
+ * `gen.return()` queues behind the pending `next()` (async-generator semantics), so leaving first ends what it awaits
164
+ * (`leave`), then returns the generator. Leaving also silences it: a generator on its way out can still reach a
165
+ * `yield`, which must not hand an event to a Caller that left. A `signal` leaves the same way, and the read pending
166
+ * then, and any after it, rejects with the signal's reason.
167
+ */
168
+ function leavableIterator(gen, leave, signal) {
169
+ let left = false;
170
+ const teardown = async () => {
171
+ left = true;
172
+ leave();
173
+ await gen.return(undefined).catch(() => { });
174
+ };
175
+ const released = () => {
176
+ throw signal?.reason;
177
+ };
178
+ let onAbort;
179
+ const aborted = signal === undefined
180
+ ? undefined
181
+ : new Promise((_, reject) => {
182
+ onAbort = () => {
183
+ void teardown();
184
+ reject(signal.reason);
185
+ };
186
+ if (signal.aborted)
187
+ onAbort();
188
+ else
189
+ signal.addEventListener("abort", onAbort, { once: true });
190
+ });
191
+ aborted?.catch(() => { });
192
+ const stopListening = () => {
193
+ if (onAbort !== undefined)
194
+ signal?.removeEventListener("abort", onAbort);
195
+ };
196
+ return {
197
+ async next() {
198
+ if (signal?.aborted)
199
+ released();
200
+ const result = await (aborted === undefined ? gen.next() : Promise.race([gen.next(), aborted]));
201
+ if (left) {
202
+ if (signal?.aborted)
203
+ released();
204
+ return { done: true, value: undefined };
205
+ }
206
+ if (result.done)
207
+ stopListening();
208
+ return result;
209
+ },
210
+ async return() {
211
+ stopListening();
212
+ await teardown();
213
+ return { done: true, value: undefined };
214
+ },
215
+ async throw(error) {
216
+ stopListening();
217
+ await teardown();
218
+ throw error;
219
+ },
220
+ };
221
+ }
@@ -0,0 +1,30 @@
1
+ import { type PromptSection } from "@earendil-works/pi-durable";
2
+ import type { ResolvedContent } from "../../content/resolve.ts";
3
+ import type { AgentCommand } from "./agent.ts";
4
+ export interface Skill {
5
+ name: string;
6
+ description: string;
7
+ /** Absolute: what the model's `read` opens. */
8
+ filePath: string;
9
+ baseDir: string;
10
+ /** Offered only through `/skill:<name>`, never listed to the model. */
11
+ disableModelInvocation: boolean;
12
+ }
13
+ /** The agent's skills: `skills/<name>/SKILL.md`. One that breaks the specification is reported and skipped. */
14
+ export declare function readSkills(agentDir: string): Skill[];
15
+ /** Arguments as a shell splits them: by whitespace, with `"…"` or `'…'` keeping one argument together. */
16
+ export declare function parseArguments(text: string): string[];
17
+ /**
18
+ * A template's text with its arguments, in pi's format: `$1`… positional, `$@` and `$ARGUMENTS` all of them,
19
+ * `${N:-default}` a positional one or its default, `${@:N}` and `${@:N:L}` a slice from the Nth.
20
+ */
21
+ export declare function expandTemplate(body: string, args: readonly string[]): string;
22
+ /** What a Caller may offer as `/<name>`: the prompt templates, then `skill:<name>` for each skill. */
23
+ export declare function readCommands(agentDir: string): AgentCommand[];
24
+ /**
25
+ * The prompt the definition contributes: `SYSTEM.md` as written, `AGENTS.md` as project context, the skills, where it
26
+ * works, and, deployed, what of a change it makes to itself lasts. `wake`: the agent has the wake tool.
27
+ */
28
+ export declare function definitionSections(agentDir: string, content: readonly ResolvedContent[], options: {
29
+ wake: boolean;
30
+ }): PromptSection[];
@@ -0,0 +1,292 @@
1
+ /**
2
+ * The definition's text (architecture.md §3), read for each request so an edit takes effect on the next answer:
3
+ * `SYSTEM.md` and `AGENTS.md` as prompt sections, `skills/` as Agent Skills (agentskills.io) and `prompts/` as prompt
4
+ * templates. A skill is loaded as pi does it: the prompt lists each one's name, description and location, the model
5
+ * reads its `SKILL.md` when a task matches, and `/skill:<name>` loads it into the message.
6
+ */
7
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
8
+ import { basename, join } from "node:path";
9
+ import { section } from "@earendil-works/pi-durable";
10
+ import { parse as parseYaml } from "yaml";
11
+ import { log } from "../../log.js";
12
+ import { isAgentcoreRuntime, isDeployedWorkspace } from "../../paths.js";
13
+ const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
14
+ const SKILL_NAME = /^[a-z0-9]+(-[a-z0-9]+)*$/;
15
+ /** A file's YAML frontmatter and its body. A file without frontmatter is all body. */
16
+ function frontmatter(text, file) {
17
+ const match = FRONTMATTER.exec(text);
18
+ if (match === null)
19
+ return { fields: {}, body: text };
20
+ const fields = parseYaml(match[1]);
21
+ if (fields !== null && (typeof fields !== "object" || Array.isArray(fields))) {
22
+ throw new Error(`${file}: its frontmatter is not a set of fields`);
23
+ }
24
+ return { fields: (fields ?? {}), body: text.slice(match[0].length) };
25
+ }
26
+ /** Each problem once per process: the text is read for every request, and a broken file should not flood the log. */
27
+ const reported = new Set();
28
+ function report(problem) {
29
+ if (reported.has(problem))
30
+ return;
31
+ reported.add(problem);
32
+ log.warn(`[fastagent] ${problem}; it is skipped`);
33
+ }
34
+ /** The directories in `dir`. An entry that cannot be read (a symlink to nothing) is reported and skipped. */
35
+ function directories(dir) {
36
+ if (!existsSync(dir))
37
+ return [];
38
+ return readdirSync(dir)
39
+ .sort()
40
+ .filter((name) => {
41
+ if (name.startsWith("."))
42
+ return false;
43
+ try {
44
+ return statSync(join(dir, name)).isDirectory();
45
+ }
46
+ catch (error) {
47
+ report(`${join(basename(dir), name)}: ${error instanceof Error ? error.message : String(error)}`);
48
+ return false;
49
+ }
50
+ });
51
+ }
52
+ /** The agent's skills: `skills/<name>/SKILL.md`. One that breaks the specification is reported and skipped. */
53
+ export function readSkills(agentDir) {
54
+ const root = join(agentDir, "skills");
55
+ const skills = [];
56
+ for (const entry of directories(root)) {
57
+ const baseDir = join(root, entry);
58
+ const filePath = join(baseDir, "SKILL.md");
59
+ const label = `skills/${entry}/SKILL.md`;
60
+ if (!existsSync(filePath))
61
+ continue;
62
+ let fields;
63
+ try {
64
+ ({ fields } = frontmatter(readFileSync(filePath, "utf8"), label));
65
+ }
66
+ catch (error) {
67
+ report(`${label}: ${error instanceof Error ? error.message : String(error)}`);
68
+ continue;
69
+ }
70
+ const name = fields.name ?? entry;
71
+ const { description } = fields;
72
+ if (typeof name !== "string" || name.length > 64 || !SKILL_NAME.test(name)) {
73
+ report(`${label}: "name" must be lowercase letters, digits and single hyphens, at most 64 characters`);
74
+ continue;
75
+ }
76
+ if (typeof description !== "string" || description.trim() === "" || description.length > 1024) {
77
+ report(`${label}: "description" must be a text of at most 1024 characters`);
78
+ continue;
79
+ }
80
+ if (skills.some((skill) => skill.name === name)) {
81
+ report(`${label}: another skill is named "${name}"`);
82
+ continue;
83
+ }
84
+ skills.push({
85
+ name,
86
+ description: description.trim(),
87
+ filePath,
88
+ baseDir,
89
+ disableModelInvocation: fields["disable-model-invocation"] === true,
90
+ });
91
+ }
92
+ return skills;
93
+ }
94
+ /** The agent's prompt templates: `prompts/<name>.md`, a `description` in the frontmatter and the body as the text. */
95
+ function readTemplates(agentDir) {
96
+ const root = join(agentDir, "prompts");
97
+ if (!existsSync(root))
98
+ return [];
99
+ return readdirSync(root)
100
+ .sort()
101
+ .flatMap((entry) => {
102
+ if (!entry.endsWith(".md"))
103
+ return [];
104
+ const label = `prompts/${entry}`;
105
+ try {
106
+ const { fields, body } = frontmatter(readFileSync(join(root, entry), "utf8"), label);
107
+ const description = typeof fields.description === "string" ? fields.description : undefined;
108
+ return [{ name: entry.slice(0, -3), ...(description === undefined ? {} : { description }), body }];
109
+ }
110
+ catch (error) {
111
+ report(`${label}: ${error instanceof Error ? error.message : String(error)}`);
112
+ return [];
113
+ }
114
+ });
115
+ }
116
+ /** Arguments as a shell splits them: by whitespace, with `"…"` or `'…'` keeping one argument together. */
117
+ export function parseArguments(text) {
118
+ const args = [];
119
+ let current = "";
120
+ let started = false;
121
+ let quote;
122
+ for (const char of text) {
123
+ if (quote !== undefined) {
124
+ if (char === quote)
125
+ quote = undefined;
126
+ else
127
+ current += char;
128
+ }
129
+ else if (char === '"' || char === "'") {
130
+ quote = char;
131
+ started = true;
132
+ }
133
+ else if (/\s/.test(char)) {
134
+ if (started)
135
+ args.push(current);
136
+ current = "";
137
+ started = false;
138
+ }
139
+ else {
140
+ current += char;
141
+ started = true;
142
+ }
143
+ }
144
+ if (started)
145
+ args.push(current);
146
+ return args;
147
+ }
148
+ /**
149
+ * A template's text with its arguments, in pi's format: `$1`… positional, `$@` and `$ARGUMENTS` all of them,
150
+ * `${N:-default}` a positional one or its default, `${@:N}` and `${@:N:L}` a slice from the Nth.
151
+ */
152
+ export function expandTemplate(body, args) {
153
+ const all = args.join(" ");
154
+ return body.replace(/\$\{(\d+|@|ARGUMENTS):-([^}]*)\}|\$\{@:(\d+)(?::(\d+))?\}|\$(ARGUMENTS|@|\d+)/g, (_match, target, fallback, from, length, simple) => {
155
+ if (target !== undefined) {
156
+ const value = target === "@" || target === "ARGUMENTS" ? all : args[Number(target) - 1];
157
+ return value ? value : (fallback ?? "");
158
+ }
159
+ if (from !== undefined) {
160
+ const start = Math.max(0, Number(from) - 1);
161
+ return (length === undefined ? args.slice(start) : args.slice(start, start + Number(length))).join(" ");
162
+ }
163
+ return simple === "@" || simple === "ARGUMENTS" ? all : (args[Number(simple) - 1] ?? "");
164
+ });
165
+ }
166
+ /** A skill's instructions as a message carries them when `/skill:<name>` loads it, as pi does. */
167
+ function loadedSkill(skill, args) {
168
+ const { body } = frontmatter(readFileSync(skill.filePath, "utf8"), skill.filePath);
169
+ const block = `<skill name="${skill.name}" location="${skill.filePath}">\nReferences are relative to ${skill.baseDir}.\n\n${body.trim()}\n</skill>`;
170
+ return args.trim() === "" ? block : `${block}\n\n${args.trim()}`;
171
+ }
172
+ /** What a Caller may offer as `/<name>`: the prompt templates, then `skill:<name>` for each skill. */
173
+ export function readCommands(agentDir) {
174
+ return [
175
+ ...readTemplates(agentDir).map((template) => ({
176
+ name: template.name,
177
+ ...(template.description === undefined ? {} : { description: template.description }),
178
+ expand: (args) => expandTemplate(template.body, parseArguments(args)),
179
+ })),
180
+ ...readSkills(agentDir).map((skill) => ({
181
+ name: `skill:${skill.name}`,
182
+ description: skill.description,
183
+ expand: (args) => loadedSkill(skill, args),
184
+ })),
185
+ ];
186
+ }
187
+ const escapeXml = (text) => text
188
+ .replace(/&/g, "&amp;")
189
+ .replace(/</g, "&lt;")
190
+ .replace(/>/g, "&gt;")
191
+ .replace(/"/g, "&quot;")
192
+ .replace(/'/g, "&apos;");
193
+ /** The skills the model may choose, as pi lists them: a skill's instructions are loaded only when a task needs them. */
194
+ function skillsPrompt(skills) {
195
+ const listed = skills.filter((skill) => !skill.disableModelInvocation);
196
+ if (listed.length === 0)
197
+ return undefined;
198
+ return [
199
+ "The following skills provide specialized instructions for specific tasks.",
200
+ "Use the read tool to load a skill's file when the task matches its description.",
201
+ "When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.",
202
+ "",
203
+ "<available_skills>",
204
+ ...listed.flatMap((skill) => [
205
+ " <skill>",
206
+ ` <name>${escapeXml(skill.name)}</name>`,
207
+ ` <description>${escapeXml(skill.description)}</description>`,
208
+ ` <location>${escapeXml(skill.filePath)}</location>`,
209
+ " </skill>",
210
+ ]),
211
+ "</available_skills>",
212
+ ].join("\n");
213
+ }
214
+ const fileText = (path) => {
215
+ if (!existsSync(path))
216
+ return undefined;
217
+ const text = readFileSync(path, "utf8").trim();
218
+ return text === "" ? undefined : text;
219
+ };
220
+ /**
221
+ * The prompt the definition contributes: `SYSTEM.md` as written, `AGENTS.md` as project context, the skills, where it
222
+ * works, and, deployed, what of a change it makes to itself lasts. `wake`: the agent has the wake tool.
223
+ */
224
+ export function definitionSections(agentDir, content, options) {
225
+ return [
226
+ section("system", () => fileText(join(agentDir, "SYSTEM.md")), { tag: false }),
227
+ section("project_context", () => fileText(join(agentDir, "AGENTS.md"))),
228
+ section("skills", () => skillsPrompt(readSkills(agentDir))),
229
+ section("content", () => contentSection({ agentDir, content })),
230
+ section("self_change", () => (isDeployedWorkspace() ? selfChangeSection(options.wake) : undefined)),
231
+ ];
232
+ }
233
+ /**
234
+ * What takes effect when, and the agent's own path to a new capability, are the same on every host; how long the
235
+ * storage lives is the host's answer: AgentCore's managed mount is reset by every deploy, so telling that agent to keep
236
+ * work "outside the definition" would name a location its next deploy erases. The skill it writes lives in the
237
+ * definition directory, which the next deployment replaces (or, on AgentCore, erases with everything else), so the
238
+ * sentence says so, and where a skill that should outlast it has to go.
239
+ */
240
+ function selfChangeSection(wake) {
241
+ const deployment = isAgentcoreRuntime()
242
+ ? "Every deployment of a new version resets this host's storage entirely"
243
+ : "Each deployment replaces your directory with the author's release";
244
+ return (`Your directory survives restarts, including uncommitted work; /tmp does not. ${deployment}, so anything that ` +
245
+ `must outlive a deployment belongs in an external system (a git remote, an issue tracker, a database). ` +
246
+ `SYSTEM.md, AGENTS.md, skills/ and prompts/ are read for every message; changes to code in src/ (tools, ` +
247
+ `extensions, channels, schedules) or to configuration (fastagent.config.ts, context.json, package.json) take ` +
248
+ `effect when the service restarts. A tool you install yourself (apt-get, npm install -g) belongs to this machine ` +
249
+ `and is gone when its container is replaced. To give yourself a new capability now, write a skill — a SKILL.md in ` +
250
+ `your definition's skills/ directory, with any script it needs run through bash. It lasts until the next ` +
251
+ `deployment replaces that directory, so a capability that should outlast it belongs in the author's release: ` +
252
+ `propose it to them.` +
253
+ // Named only when it has the tool: naming a tool the model does not have invites calls to it.
254
+ (wake ? " To schedule your own follow-up work, use the wake tool." : ""));
255
+ }
256
+ /** What a content entry of this kind is, said to the agent: where it is, and whether another instance shares it. */
257
+ function contentKind(c) {
258
+ if (c.kind !== "github")
259
+ return "a directory on this machine";
260
+ if (!c.clone)
261
+ return `a checkout of github ${c.repo} on this machine`;
262
+ // Brought up to date in place at each start where git can do so without touching the agent's work; what the agent
263
+ // changes stays, and reaches anyone else only when pushed. The declared ref is what it follows, not a claim about
264
+ // where it is: a clone the agent moved elsewhere is left there.
265
+ const clone = `a shallow clone of github ${c.repo}${c.ref ? ` (declared ${c.ref})` : ""} in your own storage`;
266
+ return c.readonly
267
+ ? `${clone}, brought up to date each time you start`
268
+ : `${clone}: what you change in it stays, and each time you start it is brought up to date where that touches nothing of yours; push to share a change`;
269
+ }
270
+ /**
271
+ * Where the agent is and what it works on (agent-model.md §4): its own directory is itself, and each content entry is named
272
+ * with its location, whether it is the agent's to change, and where a change there goes. A result written where it
273
+ * does not last is how knowledge gets lost, so the agent is told which is which.
274
+ */
275
+ function contentSection({ agentDir, content }) {
276
+ const own = `Your working directory, ${agentDir}, is your own directory: it holds your definition, and files you create ` +
277
+ `land there unless you put them elsewhere.`;
278
+ if (content.length === 0)
279
+ return `${own} Nothing else is declared for you: you work only in your own directory.`;
280
+ const line = (c) => `- ${c.name}: ${c.location} (${contentKind(c)})${c.description !== undefined ? ` ${c.description}` : ""}`;
281
+ const worksOn = content.filter((c) => !c.readonly);
282
+ const knows = content.filter((c) => c.readonly);
283
+ return [
284
+ own,
285
+ ...(worksOn.length > 0 ? ["You work on:", ...worksOn.map(line)] : []),
286
+ ...(knows.length > 0 ? ["You know, and do not write:", ...knows.map(line)] : []),
287
+ `Run a command in one of these directories with \`cd <its location> && …\`; file tools take the location directly.` +
288
+ (worksOn.length > 0
289
+ ? " A result worth keeping belongs in a directory you work on, not in your own directory."
290
+ : " You write only in your own directory: the directories above are for reading."),
291
+ ].join("\n");
292
+ }
@@ -0,0 +1,11 @@
1
+ import { type Extension } from "@earendil-works/pi-durable";
2
+ export declare const WAKE_EXTENSION = "fastagent.wake";
3
+ export declare const WAKE_TOOLS: string[];
4
+ /**
5
+ * `ticking` says whether a clock fires the wake-ups kept in `stateRoot` now; a wake-up nothing would fire is refused.
6
+ * Without it, one always does: `dev`, `start` and AgentCore serve whatever they open.
7
+ */
8
+ export declare function wakeExtension(stateRoot: string, options?: {
9
+ now?: () => Date;
10
+ ticking?: () => boolean;
11
+ }): Extension;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * `wake` and `unwake`: the agent schedules itself back into the conversation it is in, one-shot or recurring, kept in
3
+ * the instance's state (schedule/wakeups.ts), which the scheduler fires. A pair over one store: a definition that
4
+ * defines either name gets neither.
5
+ */
6
+ import { Type } from "@earendil-works/pi-ai";
7
+ import { defineExtension, defineTool } from "@earendil-works/pi-durable";
8
+ import { addWakeup, parseDelayMs, removeWakeup } from "../../schedule/wakeups.js";
9
+ import { sessionIdOf } from "./ids.js";
10
+ export const WAKE_EXTENSION = "fastagent.wake";
11
+ export const WAKE_TOOLS = ["wake", "unwake"];
12
+ const said = (text) => ({ output: [{ type: "text", text }] });
13
+ const refused = (text) => ({ output: [{ type: "text", text }], isError: true });
14
+ const NOT_A_SESSION = "wake-ups belong to a session, and this conversation is not one (a subagent's): nothing would wake it.";
15
+ const NO_CLOCK = "nothing fires wake-ups for this agent now: the app that opened it does not serve it, so no clock runs. Do the " +
16
+ "work now, or say it cannot be scheduled.";
17
+ /**
18
+ * `ticking` says whether a clock fires the wake-ups kept in `stateRoot` now; a wake-up nothing would fire is refused.
19
+ * Without it, one always does: `dev`, `start` and AgentCore serve whatever they open.
20
+ */
21
+ export function wakeExtension(stateRoot, options = {}) {
22
+ const now = options.now ?? (() => new Date());
23
+ return defineExtension({
24
+ name: WAKE_EXTENSION,
25
+ tools: [
26
+ defineTool({
27
+ name: "wake",
28
+ description: "Schedule yourself to wake up later and continue in THIS conversation. ONE-SHOT: pass `in`, a duration " +
29
+ 'string with a unit ("30m", "2h", "1d") or a number of seconds, to resume a task after a delay. RECURRING: ' +
30
+ "pass `cron` (5-field, optional `tz`) to wake repeatedly; use it sparingly, and `unwake` with the returned " +
31
+ "id when the job is done. Exactly one of `in`/`cron`. When the time comes, a new message arrives in this " +
32
+ "same conversation with `prompt` as its instruction, tagged with the wake-up's id so you can tell it from a " +
33
+ "user's, and you keep the full context of this conversation. Its plain reply is delivered to no one: to " +
34
+ "reach a person it must call a delivery tool (a channel's send tool), as a scheduled job does.",
35
+ parameters: Type.Object({
36
+ in: Type.Optional(Type.Union([Type.String(), Type.Number()], {
37
+ description: 'one-shot delay: a duration string with a unit ("30m" / "2h" / "1d"), or a number of seconds',
38
+ })),
39
+ cron: Type.Optional(Type.String({ description: 'recurring: a 5-field cron expression (e.g. "0 9 * * *")' })),
40
+ tz: Type.Optional(Type.String({ description: 'IANA timezone for `cron` (default "UTC")' })),
41
+ prompt: Type.String({
42
+ minLength: 1,
43
+ description: "the instruction for the woken message (it arrives in this same conversation)",
44
+ }),
45
+ }),
46
+ execute: async (args, api, context) => {
47
+ if (options.ticking?.() === false)
48
+ return refused(NO_CLOCK);
49
+ if ((args.in === undefined) === (args.cron === undefined)) {
50
+ return refused("pass exactly one of `in` (one-shot) or `cron` (recurring).");
51
+ }
52
+ const session = await sessionIdOf(api, context);
53
+ if (session === undefined)
54
+ return refused(NOT_A_SESSION);
55
+ const at = now();
56
+ if (args.cron !== undefined) {
57
+ const added = addWakeup(stateRoot, { session, prompt: args.prompt, cron: args.cron, tz: args.tz }, at);
58
+ if (!added.ok)
59
+ return refused(added.error);
60
+ return said(`OK — recurring wake ${added.id} (cron "${args.cron}"${args.tz ? ` ${args.tz}` : ""}), first at ${added.fireAt}: ${args.prompt}. Use unwake({ id: "${added.id}" }) to stop it.`);
61
+ }
62
+ const ms = parseDelayMs(args.in);
63
+ if (ms === undefined) {
64
+ return refused(`couldn't parse "in" (${JSON.stringify(args.in)}): use a unit like "30m" / "2h" / "1d", or a number of seconds (a bare number as text like "120" is rejected).`);
65
+ }
66
+ const added = addWakeup(stateRoot, { session, prompt: args.prompt, fireAt: new Date(at.getTime() + ms) }, at);
67
+ if (!added.ok)
68
+ return refused(added.error);
69
+ return said(`OK — I'll wake up at ${added.fireAt} (id ${added.id}) to: ${args.prompt}. Use unwake({ id: "${added.id}" }) if it becomes unnecessary.`);
70
+ },
71
+ }),
72
+ defineTool({
73
+ name: "unwake",
74
+ description: "Cancel one of YOUR pending wake-ups (one-shot or recurring) by the id `wake` returned. Use it when a " +
75
+ "scheduled follow-up is no longer needed, especially to stop a recurring wake once its job is done.",
76
+ parameters: Type.Object({
77
+ id: Type.String({ minLength: 1, description: "the wake-up id (returned by `wake`)" }),
78
+ }),
79
+ execute: async (args, api, context) => {
80
+ const session = await sessionIdOf(api, context);
81
+ if (session === undefined)
82
+ return refused(NOT_A_SESSION);
83
+ return removeWakeup(stateRoot, args.id, session)
84
+ ? said(`OK — wake-up ${args.id} cancelled.`)
85
+ : refused(`no pending wake-up ${args.id} in this conversation (already fired, or not yours).`);
86
+ },
87
+ }),
88
+ ],
89
+ });
90
+ }