@fastagent-sh/fastagent 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/README.md +9 -12
  2. package/dist/agent.d.ts +24 -37
  3. package/dist/agent.js +7 -15
  4. package/dist/atomic-write.d.ts +13 -17
  5. package/dist/atomic-write.js +18 -29
  6. package/dist/bind.d.ts +12 -22
  7. package/dist/bind.js +18 -27
  8. package/dist/channel.d.ts +11 -33
  9. package/dist/channels/agentcore-limits.d.ts +2 -13
  10. package/dist/channels/agentcore-limits.js +2 -13
  11. package/dist/channels/agentcore-protocol.d.ts +67 -58
  12. package/dist/channels/agentcore-protocol.js +23 -15
  13. package/dist/channels/agentcore-service.d.ts +19 -33
  14. package/dist/channels/agentcore-service.js +176 -59
  15. package/dist/channels/agentcore.d.ts +39 -33
  16. package/dist/channels/agentcore.js +90 -224
  17. package/dist/channels/body.d.ts +15 -2
  18. package/dist/channels/body.js +24 -2
  19. package/dist/channels/busy.d.ts +1 -21
  20. package/dist/channels/busy.js +2 -39
  21. package/dist/channels/control.d.ts +17 -62
  22. package/dist/channels/control.js +74 -182
  23. package/dist/channels/define-channel.d.ts +39 -0
  24. package/dist/channels/define-channel.js +9 -0
  25. package/dist/channels/discover.d.ts +10 -31
  26. package/dist/channels/discover.js +37 -31
  27. package/dist/channels/feishu/bootstrap-token.d.ts +1 -8
  28. package/dist/channels/feishu/bootstrap-token.js +7 -23
  29. package/dist/channels/feishu/card.d.ts +14 -28
  30. package/dist/channels/feishu/card.js +16 -30
  31. package/dist/channels/feishu/cloud.d.ts +1 -5
  32. package/dist/channels/feishu/context-buffer.d.ts +4 -23
  33. package/dist/channels/feishu/context-buffer.js +8 -31
  34. package/dist/channels/feishu/crypto.d.ts +10 -5
  35. package/dist/channels/feishu/crypto.js +12 -19
  36. package/dist/channels/feishu/feishu-api.d.ts +2 -1
  37. package/dist/channels/feishu/feishu-api.js +5 -4
  38. package/dist/channels/feishu/feishu.d.ts +4 -10
  39. package/dist/channels/feishu/feishu.js +113 -227
  40. package/dist/channels/feishu/invoke-turn.d.ts +5 -4
  41. package/dist/channels/feishu/invoke-turn.js +36 -54
  42. package/dist/channels/feishu/model.d.ts +4 -21
  43. package/dist/channels/feishu/model.js +1 -8
  44. package/dist/channels/feishu/normalize.d.ts +2 -10
  45. package/dist/channels/feishu/normalize.js +7 -42
  46. package/dist/channels/feishu/parse.d.ts +9 -29
  47. package/dist/channels/feishu/parse.js +8 -26
  48. package/dist/channels/feishu/preview.d.ts +12 -14
  49. package/dist/channels/feishu/preview.js +108 -207
  50. package/dist/channels/feishu/register-app.d.ts +8 -23
  51. package/dist/channels/feishu/register-app.js +7 -20
  52. package/dist/channels/feishu/register-webhook.d.ts +2 -9
  53. package/dist/channels/feishu/register-webhook.js +9 -33
  54. package/dist/channels/feishu/scaffold/channel.ts +27 -19
  55. package/dist/channels/feishu/scaffold/channel.websocket.ts +31 -0
  56. package/dist/channels/feishu/setup-mode.d.ts +11 -36
  57. package/dist/channels/feishu/setup-mode.js +7 -26
  58. package/dist/channels/feishu/ws-ingress.d.ts +1 -2
  59. package/dist/channels/feishu/ws-ingress.js +6 -8
  60. package/dist/channels/http.d.ts +15 -15
  61. package/dist/channels/http.js +19 -9
  62. package/dist/channels/kit/attachment-path.d.ts +4 -5
  63. package/dist/channels/kit/attachment-path.js +10 -34
  64. package/dist/channels/kit/context-buffer.d.ts +14 -21
  65. package/dist/channels/kit/context-buffer.js +25 -38
  66. package/dist/channels/kit/delivery.d.ts +35 -0
  67. package/dist/channels/kit/delivery.js +129 -0
  68. package/dist/channels/kit/event-stream.d.ts +5 -0
  69. package/dist/channels/kit/event-stream.js +29 -0
  70. package/dist/channels/kit/invoke-turn-kit.d.ts +53 -26
  71. package/dist/channels/kit/invoke-turn-kit.js +89 -32
  72. package/dist/channels/kit/preview-kit.d.ts +18 -72
  73. package/dist/channels/kit/preview-kit.js +22 -88
  74. package/dist/channels/kit/signature.d.ts +3 -9
  75. package/dist/channels/kit/signature.js +3 -9
  76. package/dist/channels/kit/state.d.ts +1 -2
  77. package/dist/channels/kit/state.js +5 -14
  78. package/dist/channels/kit/stop-command.d.ts +1 -2
  79. package/dist/channels/kit/stop-command.js +6 -9
  80. package/dist/channels/kit/tasks.d.ts +1 -1
  81. package/dist/channels/kit/tasks.js +8 -21
  82. package/dist/channels/kit/text.d.ts +2 -16
  83. package/dist/channels/kit/text.js +23 -31
  84. package/dist/channels/kit/thread-participants.d.ts +4 -17
  85. package/dist/channels/kit/thread-participants.js +8 -55
  86. package/dist/channels/kit/transport.d.ts +26 -0
  87. package/dist/channels/kit/transport.js +20 -0
  88. package/dist/channels/kit/turn-queue.d.ts +7 -11
  89. package/dist/channels/kit/turn-queue.js +21 -39
  90. package/dist/channels/kit/turn-runner.d.ts +32 -18
  91. package/dist/channels/kit/turn-runner.js +98 -53
  92. package/dist/channels/kit/turn-store.d.ts +32 -32
  93. package/dist/channels/kit/turn-store.js +45 -88
  94. package/dist/channels/lark/lark.d.ts +1 -5
  95. package/dist/channels/lark/onboard.d.ts +3 -12
  96. package/dist/channels/lark/onboard.js +3 -13
  97. package/dist/channels/lark/scaffold/channel.ts +27 -19
  98. package/dist/channels/lark/scaffold/channel.websocket.ts +31 -0
  99. package/dist/channels/registration.d.ts +9 -35
  100. package/dist/channels/registration.js +6 -37
  101. package/dist/channels/secret.js +2 -5
  102. package/dist/channels/serve.d.ts +47 -44
  103. package/dist/channels/serve.js +165 -101
  104. package/dist/channels/slack/config-api.d.ts +4 -27
  105. package/dist/channels/slack/config-api.js +5 -34
  106. package/dist/channels/slack/context-buffer.d.ts +2 -3
  107. package/dist/channels/slack/context-buffer.js +5 -5
  108. package/dist/channels/slack/invoke-turn.d.ts +3 -1
  109. package/dist/channels/slack/invoke-turn.js +25 -34
  110. package/dist/channels/slack/manifest.js +1 -3
  111. package/dist/channels/slack/model.d.ts +1 -2
  112. package/dist/channels/slack/model.js +1 -1
  113. package/dist/channels/slack/onboard.d.ts +4 -3
  114. package/dist/channels/slack/onboard.js +8 -11
  115. package/dist/channels/slack/onboarding-state.d.ts +3 -5
  116. package/dist/channels/slack/onboarding-state.js +9 -6
  117. package/dist/channels/slack/parse.d.ts +4 -13
  118. package/dist/channels/slack/parse.js +7 -28
  119. package/dist/channels/slack/preview.d.ts +12 -2
  120. package/dist/channels/slack/preview.js +292 -269
  121. package/dist/channels/slack/reaction.d.ts +11 -3
  122. package/dist/channels/slack/reaction.js +19 -8
  123. package/dist/channels/slack/register-webhook.js +4 -7
  124. package/dist/channels/slack/scaffold/channel.ts +20 -13
  125. package/dist/channels/slack/scaffold/slack-send.ts +2 -2
  126. package/dist/channels/slack/setup-server.d.ts +1 -5
  127. package/dist/channels/slack/setup-server.js +1 -5
  128. package/dist/channels/slack/shared-api.d.ts +1 -4
  129. package/dist/channels/slack/shared-api.js +2 -13
  130. package/dist/channels/slack/slack-api.d.ts +2 -1
  131. package/dist/channels/slack/slack-api.js +6 -4
  132. package/dist/channels/slack/slack.d.ts +11 -14
  133. package/dist/channels/slack/slack.js +121 -122
  134. package/dist/channels/sse.d.ts +1 -1
  135. package/dist/channels/sse.js +1 -1
  136. package/dist/channels/telegram/context-buffer.d.ts +7 -22
  137. package/dist/channels/telegram/context-buffer.js +6 -23
  138. package/dist/channels/telegram/invoke-turn.d.ts +7 -7
  139. package/dist/channels/telegram/invoke-turn.js +24 -43
  140. package/dist/channels/telegram/parse.d.ts +24 -51
  141. package/dist/channels/telegram/parse.js +32 -84
  142. package/dist/channels/telegram/preview.d.ts +10 -1
  143. package/dist/channels/telegram/preview.js +79 -100
  144. package/dist/channels/telegram/register-webhook.js +5 -23
  145. package/dist/channels/telegram/scaffold/channel.ts +25 -18
  146. package/dist/channels/telegram/scaffold/telegram-send.ts +6 -4
  147. package/dist/channels/telegram/telegram-api.d.ts +4 -3
  148. package/dist/channels/telegram/telegram-api.js +9 -7
  149. package/dist/channels/telegram/telegram.d.ts +4 -18
  150. package/dist/channels/telegram/telegram.js +38 -94
  151. package/dist/channels/telegram/turn-store.d.ts +11 -14
  152. package/dist/channels/telegram/turn-store.js +8 -6
  153. package/dist/channels/wait-health.d.ts +4 -6
  154. package/dist/channels/wait-health.js +10 -14
  155. package/dist/cli/add-feishu.d.ts +2 -12
  156. package/dist/cli/add-feishu.js +24 -71
  157. package/dist/cli/add-slack.d.ts +5 -3
  158. package/dist/cli/add-slack.js +53 -76
  159. package/dist/cli/auth-view.d.ts +2 -16
  160. package/dist/cli/auth-view.js +2 -16
  161. package/dist/cli/commands/add.js +25 -43
  162. package/dist/cli/commands/chat.d.ts +0 -1
  163. package/dist/cli/commands/chat.js +5 -6
  164. package/dist/cli/commands/deploy/agentcore.js +60 -65
  165. package/dist/cli/commands/deploy/docker.js +50 -23
  166. package/dist/cli/commands/deploy/fly.js +23 -61
  167. package/dist/cli/commands/deploy/railway.js +23 -18
  168. package/dist/cli/commands/deploy/shared.d.ts +38 -57
  169. package/dist/cli/commands/deploy/shared.js +40 -59
  170. package/dist/cli/commands/deploy.d.ts +10 -27
  171. package/dist/cli/commands/deploy.js +38 -60
  172. package/dist/cli/commands/destroy.d.ts +4 -0
  173. package/dist/cli/commands/destroy.js +56 -0
  174. package/dist/cli/commands/dev.d.ts +2 -1
  175. package/dist/cli/commands/dev.js +20 -23
  176. package/dist/cli/commands/info.d.ts +0 -2
  177. package/dist/cli/commands/info.js +83 -49
  178. package/dist/cli/commands/init.d.ts +1 -2
  179. package/dist/cli/commands/init.js +16 -55
  180. package/dist/cli/commands/invoke.d.ts +0 -1
  181. package/dist/cli/commands/invoke.js +5 -7
  182. package/dist/cli/commands/login.d.ts +2 -1
  183. package/dist/cli/commands/login.js +33 -38
  184. package/dist/cli/commands/logs.js +3 -4
  185. package/dist/cli/commands/models.js +1 -5
  186. package/dist/cli/commands/routine-run.d.ts +6 -0
  187. package/dist/cli/commands/routine-run.js +47 -0
  188. package/dist/cli/commands/routine.d.ts +25 -0
  189. package/dist/cli/commands/routine.js +122 -0
  190. package/dist/cli/commands/start.d.ts +31 -3
  191. package/dist/cli/commands/start.js +131 -81
  192. package/dist/cli/commands/tool.js +26 -12
  193. package/dist/cli/fail.d.ts +13 -23
  194. package/dist/cli/fail.js +20 -23
  195. package/dist/cli/invoke-stream.d.ts +1 -8
  196. package/dist/cli/kernel.d.ts +6 -38
  197. package/dist/cli/kernel.js +14 -77
  198. package/dist/cli/models-view.d.ts +1 -9
  199. package/dist/cli/models-view.js +11 -22
  200. package/dist/cli/program.d.ts +5 -6
  201. package/dist/cli/program.js +120 -157
  202. package/dist/cli/serve.d.ts +57 -41
  203. package/dist/cli/serve.js +94 -121
  204. package/dist/cli/shared.d.ts +15 -61
  205. package/dist/cli/shared.js +55 -181
  206. package/dist/cli.js +1 -8
  207. package/dist/collect.d.ts +6 -0
  208. package/dist/collect.js +6 -0
  209. package/dist/core.d.ts +4 -1
  210. package/dist/core.js +9 -7
  211. package/dist/declared-secrets.d.ts +55 -0
  212. package/dist/declared-secrets.js +88 -0
  213. package/dist/deploy/agentcore/aws-cli.d.ts +91 -0
  214. package/dist/deploy/agentcore/aws-cli.js +64 -0
  215. package/dist/deploy/agentcore/destroy.d.ts +51 -0
  216. package/dist/deploy/agentcore/destroy.js +273 -0
  217. package/dist/deploy/agentcore/forwarder.js +28 -79
  218. package/dist/deploy/agentcore/logs.d.ts +2 -18
  219. package/dist/deploy/agentcore/logs.js +27 -51
  220. package/dist/deploy/agentcore/plan.d.ts +85 -105
  221. package/dist/deploy/agentcore/plan.js +152 -314
  222. package/dist/deploy/agentcore/run.d.ts +28 -28
  223. package/dist/deploy/agentcore/run.js +227 -306
  224. package/dist/deploy/agentcore/zip.d.ts +2 -15
  225. package/dist/deploy/agentcore/zip.js +3 -17
  226. package/dist/deploy/build-context.d.ts +21 -0
  227. package/dist/deploy/build-context.js +137 -0
  228. package/dist/deploy/channel-ingress.d.ts +26 -39
  229. package/dist/deploy/channel-ingress.js +57 -28
  230. package/dist/deploy/container.d.ts +20 -34
  231. package/dist/deploy/container.js +49 -100
  232. package/dist/deploy/docker/plan.d.ts +12 -11
  233. package/dist/deploy/docker/plan.js +43 -24
  234. package/dist/deploy/docker/run.d.ts +22 -25
  235. package/dist/deploy/docker/run.js +39 -37
  236. package/dist/deploy/fly/plan.d.ts +15 -44
  237. package/dist/deploy/fly/plan.js +41 -73
  238. package/dist/deploy/fly/run.d.ts +16 -51
  239. package/dist/deploy/fly/run.js +42 -95
  240. package/dist/deploy/hosts.d.ts +24 -3
  241. package/dist/deploy/hosts.js +24 -3
  242. package/dist/deploy/preflight.d.ts +47 -41
  243. package/dist/deploy/preflight.js +282 -383
  244. package/dist/deploy/railway/plan.d.ts +16 -42
  245. package/dist/deploy/railway/plan.js +42 -60
  246. package/dist/deploy/railway/run.d.ts +30 -68
  247. package/dist/deploy/railway/run.js +86 -100
  248. package/dist/deploy/registration-gate.d.ts +6 -13
  249. package/dist/deploy/residency.d.ts +37 -0
  250. package/dist/deploy/residency.js +24 -0
  251. package/dist/deploy/runner.d.ts +10 -9
  252. package/dist/deploy/runner.js +7 -18
  253. package/dist/deploy/secrets.d.ts +40 -41
  254. package/dist/deploy/secrets.js +117 -103
  255. package/dist/deploy/workspace.d.ts +50 -0
  256. package/dist/deploy/workspace.js +197 -0
  257. package/dist/dev-supervisor.d.ts +1 -9
  258. package/dist/dev-supervisor.js +21 -64
  259. package/dist/effect-port.d.ts +50 -0
  260. package/dist/effect-port.js +77 -0
  261. package/dist/engines/pi/agent-session-factory.d.ts +50 -69
  262. package/dist/engines/pi/agent-session-factory.js +249 -146
  263. package/dist/engines/pi/auth.d.ts +15 -11
  264. package/dist/engines/pi/auth.js +96 -99
  265. package/dist/engines/pi/chat.d.ts +1 -5
  266. package/dist/engines/pi/chat.js +2 -14
  267. package/dist/engines/pi/config.d.ts +53 -51
  268. package/dist/engines/pi/config.js +83 -92
  269. package/dist/engines/pi/create.d.ts +60 -75
  270. package/dist/engines/pi/create.js +108 -141
  271. package/dist/engines/pi/definition.d.ts +14 -58
  272. package/dist/engines/pi/definition.js +21 -85
  273. package/dist/engines/pi/invoke-session.d.ts +5 -25
  274. package/dist/engines/pi/invoke-session.js +209 -244
  275. package/dist/engines/pi/login.d.ts +95 -35
  276. package/dist/engines/pi/login.js +259 -107
  277. package/dist/engines/pi/machine.d.ts +31 -0
  278. package/dist/engines/pi/machine.js +106 -0
  279. package/dist/engines/pi/models.d.ts +70 -89
  280. package/dist/engines/pi/models.js +188 -81
  281. package/dist/engines/pi/open.d.ts +65 -53
  282. package/dist/engines/pi/open.js +129 -69
  283. package/dist/engines/pi/report.d.ts +3 -12
  284. package/dist/engines/pi/report.js +2 -16
  285. package/dist/engines/pi/search-tools.d.ts +1 -9
  286. package/dist/engines/pi/search-tools.js +26 -57
  287. package/dist/engines/pi/service.d.ts +2 -16
  288. package/dist/engines/pi/service.js +2 -16
  289. package/dist/engines/pi/session-builder.d.ts +5 -9
  290. package/dist/engines/pi/session-builder.js +44 -82
  291. package/dist/engines/pi/session-control.js +286 -269
  292. package/dist/engines/pi/session-effects.d.ts +14 -0
  293. package/dist/engines/pi/session-effects.js +30 -0
  294. package/dist/engines/pi/session-inheritance.d.ts +9 -18
  295. package/dist/engines/pi/session-inheritance.js +103 -160
  296. package/dist/engines/pi/session-markers.d.ts +31 -30
  297. package/dist/engines/pi/session-markers.js +26 -25
  298. package/dist/engines/pi/session-settings.d.ts +6 -22
  299. package/dist/engines/pi/session-settings.js +10 -21
  300. package/dist/engines/pi/session-store.d.ts +26 -92
  301. package/dist/engines/pi/session-store.js +96 -310
  302. package/dist/engines/pi/tool-context.d.ts +17 -45
  303. package/dist/engines/pi/tool-context.js +7 -26
  304. package/dist/engines/pi/tool.d.ts +45 -36
  305. package/dist/engines/pi/tool.js +43 -57
  306. package/dist/engines/pi/turn-kit.d.ts +14 -52
  307. package/dist/engines/pi/turn-kit.js +18 -67
  308. package/dist/engines/pi/wake-tool.d.ts +2 -10
  309. package/dist/engines/pi/wake-tool.js +7 -27
  310. package/dist/env.d.ts +27 -28
  311. package/dist/env.js +45 -50
  312. package/dist/index.js +0 -2
  313. package/dist/lark.d.ts +1 -2
  314. package/dist/lark.js +1 -2
  315. package/dist/loader.d.ts +14 -55
  316. package/dist/loader.js +24 -43
  317. package/dist/log.d.ts +2 -12
  318. package/dist/log.js +3 -24
  319. package/dist/node.d.ts +2 -15
  320. package/dist/node.js +2 -18
  321. package/dist/observe.d.ts +2 -8
  322. package/dist/open-url.d.ts +1 -1
  323. package/dist/open-url.js +1 -1
  324. package/dist/paths.d.ts +70 -134
  325. package/dist/paths.js +165 -232
  326. package/dist/pi.d.ts +4 -6
  327. package/dist/pi.js +3 -3
  328. package/dist/proxy.d.ts +16 -6
  329. package/dist/proxy.js +52 -16
  330. package/dist/runtime.d.ts +18 -12
  331. package/dist/runtime.js +18 -11
  332. package/dist/scaffold/add-channel.d.ts +14 -31
  333. package/dist/scaffold/add-channel.js +48 -112
  334. package/dist/scaffold/init.d.ts +9 -31
  335. package/dist/scaffold/init.js +45 -138
  336. package/dist/scaffold/templates/env.example +6 -4
  337. package/dist/scaffold/templates/fastagent.config.ts +36 -0
  338. package/dist/scaffold/templates.d.ts +3 -3
  339. package/dist/scaffold/templates.js +5 -8
  340. package/dist/scaffold/vendor-skill.d.ts +2 -5
  341. package/dist/scaffold/vendor-skill.js +19 -29
  342. package/dist/schedule/cron.d.ts +9 -5
  343. package/dist/schedule/cron.js +9 -11
  344. package/dist/schedule/discover.d.ts +12 -12
  345. package/dist/schedule/discover.js +43 -34
  346. package/dist/schedule/routine.d.ts +43 -0
  347. package/dist/schedule/routine.js +32 -0
  348. package/dist/schedule/run.d.ts +55 -0
  349. package/dist/schedule/run.js +146 -0
  350. package/dist/schedule/scheduler.d.ts +44 -55
  351. package/dist/schedule/scheduler.js +291 -265
  352. package/dist/schedule/state.d.ts +105 -10
  353. package/dist/schedule/state.js +293 -19
  354. package/dist/schedule/wake-alarm.d.ts +10 -23
  355. package/dist/schedule/wake-alarm.js +91 -121
  356. package/dist/schedule/wakeups.d.ts +23 -39
  357. package/dist/schedule/wakeups.js +33 -75
  358. package/dist/secrets-gate.d.ts +32 -0
  359. package/dist/secrets-gate.js +33 -0
  360. package/dist/service.d.ts +137 -98
  361. package/dist/service.js +250 -252
  362. package/dist/session-remote.d.ts +33 -44
  363. package/dist/session-remote.js +203 -192
  364. package/dist/session.d.ts +153 -228
  365. package/dist/session.js +33 -55
  366. package/dist/tunnel.d.ts +8 -36
  367. package/dist/tunnel.js +24 -65
  368. package/dist/version.d.ts +2 -2
  369. package/dist/version.js +2 -2
  370. package/package.json +10 -16
  371. package/dist/channels/agentcore-state.d.ts +0 -77
  372. package/dist/channels/agentcore-state.js +0 -276
  373. package/dist/channels/github/github.d.ts +0 -31
  374. package/dist/channels/github/github.js +0 -89
  375. package/dist/channels/github/scaffold/channel.ts +0 -25
  376. package/dist/cli/commands/attach.d.ts +0 -108
  377. package/dist/cli/commands/attach.js +0 -637
  378. package/dist/cli/commands/fire.d.ts +0 -7
  379. package/dist/cli/commands/fire.js +0 -38
  380. package/dist/cli/commands/schedule.d.ts +0 -12
  381. package/dist/cli/commands/schedule.js +0 -87
  382. package/dist/github.d.ts +0 -3
  383. package/dist/github.js +0 -2
  384. package/dist/scaffold/templates/fastagent.config.mjs +0 -23
  385. package/dist/schedule/audit.d.ts +0 -18
  386. package/dist/schedule/audit.js +0 -57
  387. package/dist/schedule/schedule.d.ts +0 -35
  388. package/dist/schedule/schedule.js +0 -23
@@ -1,28 +1,16 @@
1
1
  /**
2
- * Agent assembly (configuration-time): the engine assets (tools, prompt) plus the reusable ladder
3
- * that puts a pi agent together.
4
- *
5
- * L2 createPiAgentFromDefinition(dir, options) — load a definition directory, assemble, then L1.
6
- * L1 createPiAgent(options) — assemble from typed parts (the canonical ctor).
7
- * L0 createPiAgentFromSession({ sessionFactory }) — in invoke-session.ts (the turn mechanism).
8
- *
9
- * Above L2 sits the agent opener createPiAgentFromDir (open.ts), which both `dev` and
10
- * `start` drive. Each rung calls the one below; options narrow as you go up (L2 owns systemPrompt/skills —
11
- * they come from the definition; the openers own model/tools — from config resolution).
12
- *
13
- * Every rung assembles the same VALUE first — a {@link PiAssembly}: the lease, the session factory
14
- * and the engine thunk — and the agent is that value under the L0. The opener needs the value
15
- * itself (the control plane contends on the same lease and validates against the same registry), so
16
- * `assemblePiFromDefinition` hands it out and `createPiAgentFromDefinition` is it plus the L0.
2
+ * Agent assembly (configuration-time): the engine assets (tools, prompt) plus the reusable ladder that puts a pi agent
3
+ * together.
17
4
  */
18
5
  import { toUSVString } from "node:util";
19
6
  import { NodeExecutionEnv } from "@earendil-works/pi-agent-core/node";
20
7
  import { createCodingTools, createPowerShellTool, createReadOnlyTools, } from "@earendil-works/pi-coding-agent";
21
- import { defaultAuthPath, resolveModel } from "./config.js";
22
- import { resolveSecretsDir } from "../../paths.js";
8
+ import { resolveAuthLayers, resolveModel } from "./config.js";
9
+ import { isAgentcoreRuntime, isDeployedWorkspace } from "../../paths.js";
23
10
  import { loadAgentDefinition, loadExtensionPaths } from "./definition.js";
24
11
  import { reportFindingsIfChanged } from "./report.js";
25
- import { isDeferredTool, loadTools, mergeDiscoveredTools } from "./tool.js";
12
+ import { isDeferredTool, loadTools, mergeDiscoveredTools, } from "./tool.js";
13
+ import { readSecretDeclaration } from "../../declared-secrets.js";
26
14
  import { withSearchTool } from "./search-tools.js";
27
15
  import { createPiAgentFromSession } from "./invoke-session.js";
28
16
  import { piAgentSessionFactory } from "./agent-session-factory.js";
@@ -31,27 +19,10 @@ import { piInMemorySessionRecordStore } from "./session-store.js";
31
19
  import { inProcessLease } from "./turn-kit.js";
32
20
  // ── §1 tools ─────────────────────────────────────────────────────────────────
33
21
  //
34
- // A directory agent gets every pi coding tool. Restricting what those tools can reach belongs at the
35
- // sandbox boundary, not in an allowlist that leaves authored tools unrestricted. L1/L2 library callers
36
- // can still replace the coding defaults through `tools`; deferred tools may add `search_tools`.
37
- //
38
- // This is not a security boundary and no default here could be one: the built-in POST /invoke has no
39
- // authentication, author-written `tools/` import whatever they like, and a WebSocket or Socket-Mode
40
- // channel dials OUT, so no bind address constrains who can message the agent. Whoever can reach an
41
- // agent can use everything it mounts — put it behind something that decides who may.
42
- //
43
- // All seven come from pi-coding-agent and reach the machine through `node:fs`, bypassing the per-turn
44
- // {@link ExecutionEnv}. pi-agent-core ships env-routed look-alikes, but that seam narrows a blast
45
- // radius rather than closing one (authored `tools/` ignore it), so a real sandbox must wrap the
46
- // process instead.
47
- //
48
- // Chat receives the same tool objects through pi's `customTools` path; pi's builtin copies stay off.
22
+ // A directory agent gets every pi coding tool.
49
23
  /**
50
- * Every pi coding tool, in canonical order, rooted at the workspace it operates in.
51
- *
52
- * pi ships two overlapping groupings and neither is the whole set: `createCodingTools` is the four it
53
- * ACTIVATES for a terminal (read/bash/edit/write, no searching), `createReadOnlyTools` is
54
- * read/grep/find/ls. `read` is in both; a directory agent mounts their union.
24
+ * Every pi coding tool, in canonical order, rooted at the workspace it operates in. pi ships two overlapping groupings
25
+ * and neither is the whole set.
55
26
  */
56
27
  export const CODING_TOOL_NAMES = ["read", "grep", "find", "ls", "bash", "edit", "write"];
57
28
  export function piAllCodingTools(cwd) {
@@ -72,14 +43,7 @@ export function piAllCodingTools(cwd) {
72
43
  }).filter((tool) => tool.name !== "read");
73
44
  return [...createReadOnlyTools(cwd), ...mutating];
74
45
  }
75
- /**
76
- * Every tool an `AgentSession` registers on its own, whether or not a directory agent mounts it.
77
- *
78
- * Wider than {@link CODING_TOOL_NAMES} on purpose: pi 0.84.3 added `powershell`, which the session
79
- * registers regardless of the tools we pass. A name absent from THIS list is a name never excluded,
80
- * and an excluded name is the only thing that cannot be activated — so leaving it out would let
81
- * `tools: [read]` keep a reachable shell.
82
- */
46
+ /** Every tool an `AgentSession` registers on its own, whether or not a directory agent mounts it. */
83
47
  function piRegisteredToolNames(cwd) {
84
48
  return [
85
49
  ...createReadOnlyTools(cwd).map((tool) => tool.name),
@@ -87,24 +51,26 @@ function piRegisteredToolNames(cwd) {
87
51
  createPowerShellTool(cwd).name,
88
52
  ];
89
53
  }
90
- /** Built-ins omitted by an explicit lower-level tool list. A reused name stays mounted. */
54
+ /** Built-ins omitted by an explicit lower-level tool list. */
91
55
  function omittedBuiltinNames(mounted, cwd) {
92
56
  const mountedNames = new Set(mounted.map((tool) => tool.name));
93
57
  return [...new Set(piRegisteredToolNames(cwd))].filter((name) => !mountedNames.has(name));
94
58
  }
95
59
  /**
96
- * The full directory-agent tool set: all pi coding tools + `config.tools` + discovered `tools/`
97
- * (deduped, existing win), plus the authored names and collisions to report. One source for the
98
- * dev/start openers AND `fastagent tool`, so they all mount exactly the same set.
60
+ * The full directory-agent tool set: all pi coding tools + `config.tools` + discovered `tools/` (deduped, existing
61
+ * win), plus the authored names and collisions to report.
99
62
  */
100
63
  export async function resolveAgentTools(config, agentDir, cwd) {
101
- // Discovered `tools/` come from `agentDir` (the agent's own surface); the coding tools are
102
- // rooted at `cwd`, the WORKSPACE — the project the agent works on, which is where an author expects
103
- // `read`/`bash` to land, and which is not always the definition directory.
64
+ // Discovered `tools/` come from `agentDir` (the agent's own surface); the coding tools are rooted at `cwd`, the
65
+ // WORKSPACE.
104
66
  const discovered = await loadTools(agentDir);
105
67
  const configured = piAllCodingTools(cwd);
106
68
  const configuredNames = new Set(configured.map((tool) => tool.name));
107
69
  const configuredCollisions = [];
70
+ // The config.tools that actually MOUNT — collected here rather than re-derived from `config.tools`
71
+ // afterwards, so a tool dropped for sharing a coding tool's name cannot contribute a declaration
72
+ // (its body never runs, and gating a start on its secret would refuse to serve for nothing).
73
+ const mountedConfigTools = [];
108
74
  for (const tool of config.tools ?? []) {
109
75
  if (configuredNames.has(tool.name)) {
110
76
  configuredCollisions.push({ name: tool.name, source: "config.tools" });
@@ -112,20 +78,19 @@ export async function resolveAgentTools(config, agentDir, cwd) {
112
78
  }
113
79
  configuredNames.add(tool.name);
114
80
  configured.push(tool);
81
+ mountedConfigTools.push(tool);
115
82
  }
116
83
  const merged = mergeDiscoveredTools(configured, discovered.tools);
117
- // The built-in `search_tools` loader mounts here — the one place the agent's full tool set is
118
- // computed — so `dev`/`start`/`info`/`fastagent tool` all see the same surface (idempotent; an
119
- // agent-defined search_tools wins).
84
+ // The built-in `search_tools` loader mounts here.
120
85
  const tools = withSearchTool(merged.tools);
121
- // Builtin = a search_tools that was ABSENT before withSearchTool (a reference compare would misfire
122
- // on the deferred-authored-loader case, where withSearchTool returns a new array without adding one).
86
+ // Builtin = a search_tools that was ABSENT before withSearchTool (a reference compare would misfire on the
87
+ // deferred-authored-loader case, where withSearchTool returns a new array without adding one).
123
88
  const builtinLoaderMounted = !merged.tools.some((t) => t.name === "search_tools") && tools.some((t) => t.name === "search_tools");
124
89
  const toolCollisions = [...discovered.collisions, ...configuredCollisions, ...merged.collisions];
125
- // `toolNames` is the AUTHOR's active-by-default surface (config.tools + tools/): exclude pi coding
126
- // tools, the builtin loader (like wake, a builtin gets its own report line, not an anonymous slot in
127
- // the author's list — an author-DEFINED search_tools still shows), and deferred tools. Each name
128
- // lives in exactly ONE report slot, and deferred names live in `deferredToolNames`.
90
+ // `toolNames` is the AUTHOR's active-by-default surface (config.tools + tools/).
91
+ // The discovered tools that were DROPPED (a coding tool or config.tools already owns the name):
92
+ // asking the mounted set instead would read the winner's name as proof the loser is mounted.
93
+ const shadowed = new Set(merged.collisions.map((c) => c.name));
129
94
  const defaultNames = new Set(CODING_TOOL_NAMES);
130
95
  const toolNames = tools
131
96
  .filter((t) => !defaultNames.has(t.name) && !isDeferredTool(t) && !(builtinLoaderMounted && t.name === "search_tools"))
@@ -136,29 +101,35 @@ export async function resolveAgentTools(config, agentDir, cwd) {
136
101
  deferredToolNames: tools.filter(isDeferredTool).map((t) => t.name),
137
102
  toolCollisions,
138
103
  toolFailures: discovered.failures,
104
+ // Mounted only, and config.tools are FastagentTools too, so a programmatic tool declares the
105
+ // same way a file does.
106
+ toolSecrets: new Map([
107
+ ...[...discovered.secrets].filter(([name]) => !shadowed.has(name)),
108
+ // A programmatic tool declares the same way a file does. The source names the ENTRY, not just
109
+ // the list: `source` has to point at something the author can find, and "config.tools" alone
110
+ // locates nothing when the list has several tools. The shape was already refused by config
111
+ // validation (config.ts), so a throw here means a FastagentConfig assembled in code bypassed
112
+ // it — still the caller's own object, so it fails loudly rather than being isolated.
113
+ ...mountedConfigTools.map((tool) => {
114
+ const declaration = readSecretDeclaration(tool, `config.tools "${tool.name}"`);
115
+ if (declaration.error !== undefined)
116
+ throw new Error(declaration.error);
117
+ return [tool.name, declaration.secrets];
118
+ }),
119
+ ]),
139
120
  };
140
121
  }
141
122
  // Fastagent owns identity and project context; Pi appends skills and cwd for both serving and chat.
142
- /**
143
- * The pi engine's base prompt (segment ①), mirroring pi-coding-agent's default path with two
144
- * deviations: the pi-TUI docs section is dropped (those paths don't exist in deployments), and the
145
- * tool list is generated from the actually-mounted tools (base and toolset must agree). An authored
146
- * `persona` (from persona.md) replaces the default identity line, keeping the tools list + guidelines.
147
- */
123
+ /** The pi engine's base prompt (segment ①), mirroring pi-coding-agent's default path with two deviations. */
148
124
  export function piBasePrompt(options = {}) {
149
125
  const mounted = options.tools ?? [];
150
- // Deferred tools stay OUT of the list: their schemas are not in the request until activated, so
151
- // naming them here would invite calls to tools that don't exist yet; discovery is search_tools' job
152
- // (which IS listed — it's active). Computed from the static mounted set, so the prompt — the cached
153
- // context prefix — does not change when a tool is activated mid-session.
126
+ // Deferred tools stay OUT of the list: their schemas are not in the request until activated, so naming them here
127
+ // would invite calls to tools that don't exist yet.
154
128
  const tools = mounted.filter((t) => !isDeferredTool(t));
155
129
  const deferredCount = mounted.length - tools.length;
156
130
  const toolsList = tools.length > 0 ? tools.map((t) => `- ${t.name}: ${(t.description ?? "").split("\n")[0]}`).join("\n") : "(none)";
157
- // Segment ① identity: an authored persona (persona.md) replaces the default engine identity line
158
- // (core.md §2), keeping the tools list + guidelines below. Preserve pi's coding identity only for
159
- // the full coding surface; a partial/empty surface must not claim machine capabilities it lacks.
160
- // The four this sentence NAMES — reading, executing, editing, writing. Searching is not part of the
161
- // claim, so requiring it would demote an agent that can do everything the identity says it can.
131
+ // Segment ① identity: an authored persona (persona.md) replaces the default engine identity line (core.md §2),
132
+ // keeping the tools list + guidelines below.
162
133
  const mountedNames = new Set(mounted.map((tool) => tool.name));
163
134
  const fullCodingSurface = ["read", "bash", "edit", "write"].every((name) => mountedNames.has(name));
164
135
  const identity = options.persona?.trim() ||
@@ -168,6 +139,23 @@ export function piBasePrompt(options = {}) {
168
139
  const deferredNote = deferredCount > 0
169
140
  ? `\n\n${deferredCount} additional tool(s) are registered but inactive — use search_tools to discover and activate them before concluding a capability is missing.`
170
141
  : "";
142
+ // What takes effect when, and the agent's own path to a new capability, are the same on every host; only how long
143
+ // the storage lives differs, below. The skill it writes lives in the definition directory, which the next
144
+ // deployment replaces (or, on AgentCore, erases with everything else) — so the sentence says so, and where a skill
145
+ // that should outlast it has to go. A skill outside the definition would survive, but it is machine state, read
146
+ // once per process (machine.ts), so it would not be live.
147
+ const RUNTIME_CHANGES = ` Markdown definition files are read each turn; changes to tools, channels or configuration take effect when the service restarts. To give yourself a new capability now, write a skill — a SKILL.md in your definition's skills/ directory, with any script it needs run through bash. It lasts until the next deployment replaces that directory, so a capability that should outlast it belongs in the author's release: propose it to them.${
148
+ // Named only when mounted (a serve; not a one-shot invoke), like the deferred tools above: naming a tool the model does not
149
+ // have invites calls to it.
150
+ mountedNames.has("wake") ? " To schedule your own follow-up work, use the wake tool." : ""}`;
151
+ // How long the storage lives is the HOST's answer, not a deployment-wide one: AgentCore's managed
152
+ // mount is reset by every deploy, so telling that agent to keep work "outside the definition" would
153
+ // name a location its next deploy erases.
154
+ const deploymentNote = !isDeployedWorkspace()
155
+ ? ""
156
+ : isAgentcoreRuntime()
157
+ ? `\n\nYour workspace survives restarts, including uncommitted work; /tmp does not. Every deployment of a new version resets this host's storage entirely, so anything that must outlive a deployment belongs in an external system (a git remote, an issue tracker, a database).${RUNTIME_CHANGES}`
158
+ : `\n\nYour workspace survives restarts and deployments, including uncommitted work; /tmp does not. A new deployment replaces your definition directory with the author's release, so keep ongoing project work outside it.${RUNTIME_CHANGES}`;
171
159
  return `${identity}
172
160
 
173
161
  Available tools:
@@ -177,7 +165,7 @@ In addition to the tools above, you may have access to other custom tools depend
177
165
 
178
166
  Guidelines:
179
167
  - Be concise in your responses
180
- - Show file paths clearly when working with files`;
168
+ - Show file paths clearly when working with files${deploymentNote}`;
181
169
  }
182
170
  export function assembleSystemPrompt(options) {
183
171
  let prompt = options.base;
@@ -192,29 +180,22 @@ export function assembleSystemPrompt(options) {
192
180
  }
193
181
  return prompt;
194
182
  }
195
- /**
196
- * Shared low-level wiring: resolve the model spec against the collection, default the K ports, build
197
- * the parts. Internal — the public rungs decide the systemPrompt (L1 from instructions, L2 from the
198
- * directory) and route through here.
199
- */
183
+ /** Shared low-level wiring: resolve the model spec against the collection, default the K ports, build the parts. */
200
184
  function assemblePi(opts) {
201
185
  const cwd = opts.cwd ?? opts.env?.cwd ?? process.cwd();
202
- // Materialized here (not defaulted inside the L0) so the value carries the SAME lease instance the
203
- // agent runs under — boundary mutations must contend on it.
186
+ // Materialized here (not defaulted inside the L0) so the value carries the SAME lease instance the agent runs under
187
+ // — boundary mutations must contend on it.
204
188
  const lease = opts.lease ?? inProcessLease();
205
189
  const sessions = opts.sessions ?? piInMemorySessionRecordStore({ cwd });
206
- // The model and its runtime resolve on FIRST USE: building a ModelRuntime is async while
207
- // assembling an agent is not, so the credential read belongs on the first turn rather than in the
208
- // caller's constructor. Memoized, and shared with the control plane so a boundary mutation
209
- // validates against the registry the runs actually use.
190
+ // The model and its runtime resolve on FIRST USE.
210
191
  let engine;
211
192
  const resolveEngine = () => {
212
193
  engine ??= (async () => {
213
- // The caller's registry when there is one — the directory rung builds it from the agent's own
214
- // models.json, so a custom endpoint declared there is the one a turn resolves against.
215
- const modelRuntime = opts.models ?? (await createPiModelRuntime({ authPath: opts.authPath }));
216
- // ModelRuntime registers providers by config record, so an injected Provider INSTANCE (a
217
- // gateway, a self-hosted endpoint, a test fake) goes in through its native seam.
194
+ // The caller's registry when there is one — the directory rung builds it from the agent's own models.json, so a
195
+ // custom endpoint declared there is the one a turn resolves against.
196
+ const modelRuntime = opts.models ?? (await createPiModelRuntime({ auth: opts.auth }));
197
+ // ModelRuntime registers providers by config record, so an injected Provider INSTANCE (a gateway, a self-hosted
198
+ // endpoint, a test fake) goes in through its native seam.
218
199
  for (const provider of opts.providers ?? [])
219
200
  modelRuntime.registerNativeProvider(provider);
220
201
  return { modelRuntime, model: resolveModel(modelRuntime, opts.model) };
@@ -228,10 +209,9 @@ function assemblePi(opts) {
228
209
  tools: opts.tools,
229
210
  readDefinition: opts.readDefinition,
230
211
  cwd,
231
- ...(opts.agentDir ? { agentDir: opts.agentDir } : {}),
232
212
  ...(opts.extensionPaths ? { extensionPaths: opts.extensionPaths } : {}),
233
- // `noTools: "builtin"` leaves pi's built-ins in the registry; a lower-level replacement must also
234
- // deny every omitted coding name so a loader cannot reactivate one later.
213
+ // `noTools: "builtin"` leaves pi's built-ins in the registry; a lower-level replacement must also deny every
214
+ // omitted coding name so a loader cannot reactivate one later.
235
215
  excludedToolNames: omittedBuiltinNames(opts.tools ?? [], cwd),
236
216
  });
237
217
  return {
@@ -239,6 +219,7 @@ function assemblePi(opts) {
239
219
  sessionFactory,
240
220
  engine: resolveEngine,
241
221
  thinkingLevel: opts.thinkingLevel ?? DEFAULT_THINKING_LEVEL,
222
+ extensionPaths: opts.extensionPaths ?? [],
242
223
  };
243
224
  }
244
225
  /** The agent an assembly runs as: the L0 over its lease and session factory. */
@@ -252,7 +233,7 @@ export function createPiAgent(options) {
252
233
  model: options.model,
253
234
  thinkingLevel: options.thinkingLevel,
254
235
  providers: options.providers,
255
- authPath: options.authPath,
236
+ ...(options.authPath !== undefined ? { auth: { path: options.authPath } } : {}),
256
237
  readDefinition: () => ({
257
238
  systemPrompt: typeof instructions === "function" ? instructions() : instructions,
258
239
  skills,
@@ -265,60 +246,49 @@ export function createPiAgent(options) {
265
246
  }), options.observer);
266
247
  }
267
248
  /**
268
- * L2, as the value: load the directory (base + AGENTS.md + skills + env) and assemble. Returns the
269
- * definition so callers can surface diagnostics/collisions. The opener consumes this form because
270
- * the control plane needs the parts; {@link createPiAgentFromDefinition} is it plus the L0.
249
+ * THE model registry an agent directory runs on: pi's built-ins, the directory's own `models.json` (custom endpoints
250
+ * are definition data and travel with the artifact) layered over the machine's `~/.fastagent/models.json` (environment,
251
+ * which does not travel), and any injected Provider instance, over the given credentials.
252
+ * The directory rung assembles from it and `availableModelsFromDir` lists from it, so a layer added here reaches both.
271
253
  */
272
- export async function assemblePiFromDefinition(dir, options) {
273
- // `dir` = the agent-definition dir (persona.md/skills/); `cwd` (default = dir) is the run root where
274
- // tools operate and whose ancestors are walked for ② context.
254
+ export function definitionModelRuntime(dir, options) {
255
+ return createPiModelRuntime({ agentDir: dir, ...options });
256
+ }
257
+ /** L2, as the value: load the directory (base + AGENTS.md + skills + env) and assemble. */
258
+ export async function assemblePiFromDefinition(dir,
259
+ /** `auth` is the opener's already-resolved layers, which take the place of `authPath`. */
260
+ options) {
261
+ // `dir` = the agent-definition dir (persona.md/skills/); `cwd` (default = dir) is the run root where tools operate
262
+ // and whose ancestors are walked for ② context.
275
263
  const cwd = options.cwd ?? dir;
276
264
  const env = options.env ?? new NodeExecutionEnv({ cwd });
277
- // Boot-time load: fail-visibly at startup on a broken directory, and give callers the snapshot to
278
- // report (skills/diagnostics/collisions). Serving re-reads it through readDefinition below.
279
- // `cwd`, not `env.cwd`, for the same reason as the tools below: `cwd` is the run root whose
280
- // ancestors carry ② project context. Reading it off the env pointed the AGENTS.md walk at the
281
- // loader's directory whenever a caller supplied both.
265
+ // Boot-time load: fail-visibly at startup on a broken directory, and give callers the snapshot to report
266
+ // (skills/diagnostics/collisions).
282
267
  const definition = await loadAgentDefinition(dir, { cwd, env });
283
- // Deferred tools need their loader on every rung (idempotent — the workspace opener already applied
284
- // it; a caller's own search_tools wins).
285
- // `cwd`, not `env.cwd`: the workspace is what this option MEANS, and a caller may hand a custom env
286
- // for definition loading whose root is a different directory. Taking it off the env would silently
287
- // point the coding tools at the loader's directory.
268
+ // Deferred tools need their loader on every rung (idempotent — the workspace opener already applied it; a caller's
269
+ // own search_tools wins).
288
270
  const tools = withSearchTool(options.tools ?? piAllCodingTools(cwd));
289
- // Boot findings go through the SAME memoized reporter every later reader uses (report.ts, keyed by
290
- // the resolved dir): announced once here, and re-announced by a turn or by the control plane's
291
- // command list only when the set CHANGES — a runtime-written bad skill surfaces the moment it
292
- // appears, a static one does not spam. Log dedup, not session state (stateless invoke holds).
271
+ // Boot findings go through the SAME memoized reporter every later reader uses (report.ts, keyed by the resolved
272
+ // dir).
293
273
  reportFindingsIfChanged(definition.dir, definition);
294
- // Dir-aware default: the same secrets-dir-derived file the opener uses for this dir (the opener
295
- // passes an explicit authPath, so this only affects direct L2 callers).
296
- const authPath = options.authPath ?? defaultAuthPath(resolveSecretsDir(dir));
274
+ const auth = options.auth ?? (options.authPath === undefined ? resolveAuthLayers(dir) : { path: options.authPath });
297
275
  const assembly = assemblePi({
298
276
  model: options.model,
299
277
  thinkingLevel: options.thinkingLevel,
300
- // THE directory rung's model surface: built-ins + the agent's own models.json (custom endpoints,
301
- // which are definition data and travel with the artifact) + any injected Provider instance. This
302
- // is what makes `dev`/`start`/`invoke` and an embedded L2 caller resolve the same specs.
303
- models: await createPiModelRuntime({ agentDir: dir, authPath, providers: options.providers }),
304
- authPath,
305
- // The directory is the agent, LIVE: re-read the definition on every invoke, so AGENTS.md/skills
306
- // edits (the author's, or the agent's own self-modification) take effect on the next turn with
307
- // no process restart — restarts are reserved for code (tools/channels/config, module cache).
308
- // One read yields prompt AND skills (they can never diverge), and the
309
- // fs cost is a few reads against a model call. Broken edits stay visible: a throw-class problem
310
- // (unreadable AGENTS.md) fails that turn's invoke, and the loader's NON-fatal findings (bad
311
- // SKILL.md frontmatter, name collisions — returned as data, not thrown) are warned the moment
312
- // the finding set changes (boot findings are the baseline) — a runtime-written bad skill must
313
- // not silently vanish from the agent, and a static one must not spam every turn's log. The
314
- // next good edit heals both.
278
+ models: await definitionModelRuntime(dir, {
279
+ auth,
280
+ ...(options.providers ? { providers: options.providers } : {}),
281
+ }),
282
+ // The directory is the agent, LIVE: re-read the definition on every invoke, so AGENTS.md/skills edits (the
283
+ // author's, or the agent's own self-modification) take effect on the next turn with no process restart — restarts
284
+ // are reserved for code (tools/channels/config, module cache).
315
285
  readDefinition: async () => {
316
286
  const def = await loadAgentDefinition(dir, { cwd, env });
317
287
  reportFindingsIfChanged(def.dir, def);
318
288
  return {
319
289
  systemPrompt: assembleSystemPrompt({
320
- // Segment ①: an authored persona (persona.md, def.persona) overrides the engine identity,
321
- // re-read per turn like AGENTS.md so edits go live; options.base still wins for full control.
290
+ // Segment ①: an authored persona (persona.md, def.persona) overrides the engine identity, re-read per turn
291
+ // like AGENTS.md so edits go live.
322
292
  base: options.base ?? piBasePrompt({ tools, persona: def.persona }),
323
293
  // ② project context: AGENTS.md files (agentDir + cwd-ancestor walk) via loadProjectContextFiles.
324
294
  contextFiles: def.contextFiles,
@@ -328,9 +298,6 @@ export async function assemblePiFromDefinition(dir, options) {
328
298
  },
329
299
  tools,
330
300
  sessions: options.sessions,
331
- // Discovered so the serving assembly can WARN that it does not run them (and so the refusals
332
- // apply to the artifact either way) — `chat` is where they load. Boot-resolved: the set cannot
333
- // change without a restart, which is why this sits outside readDefinition above.
334
301
  extensionPaths: await loadExtensionPaths(dir, { cwd, env }),
335
302
  cwd,
336
303
  env,
@@ -1,25 +1,21 @@
1
1
  import { type ExecutionEnv, type Skill, type SkillDiagnostic } from "@earendil-works/pi-agent-core";
2
- /** A same-name skill collision (the discarded side). Surfaced, never swallowed. */
2
+ /** A same-name skill collision (the discarded side). */
3
3
  export interface SkillCollision {
4
4
  name: string;
5
5
  winnerPath: string;
6
6
  loserPath: string;
7
7
  }
8
- /** Result of loading a definition directory. Produced by {@link loadAgentDefinition}. */
8
+ /** Result of loading a definition directory. */
9
9
  export interface LoadedDefinition {
10
- /**
11
- * Project-context files feeding segment ② `<project_context>`, sourced via pi's `loadProjectContextFiles`:
12
- * the agentDir's own AGENTS.md/CLAUDE.md FIRST, then every AGENTS.md from root down to `cwd` (so the
13
- * file nearest `cwd` comes LAST — pi's array order). Empty when none exist. This WALKS cwd's ancestors (pi's coding-agent behaviour) — see core.md §6.
14
- */
10
+ /** Project-context files feeding segment ② `<project_context>`, sourced via pi's `loadProjectContextFiles`. */
15
11
  contextFiles: Array<{
16
12
  path: string;
17
13
  content: string;
18
14
  }>;
19
15
  /**
20
- * Verbatim `persona.md` content — the authored persona that OVERRIDES segment ①'s identity line
21
- * (piBasePrompt keeps the tool list + guidelines; NOT a full system-prompt replacement — that is L1
22
- * createPiAgent's `instructions`). undefined when absent → segment ① is the default engine identity.
16
+ * Verbatim `persona.md` content — the authored persona that OVERRIDES segment ①'s identity line (piBasePrompt keeps
17
+ * the tool list + guidelines; NOT a full system-prompt replacement — that is L1 createPiAgent's `instructions`).
18
+ * undefined when absent → segment ① is the default engine identity.
23
19
  */
24
20
  persona?: string;
25
21
  skills: Skill[];
@@ -31,62 +27,23 @@ export interface LoadedDefinition {
31
27
  dir: string;
32
28
  }
33
29
  export interface LoadAgentDefinitionOptions {
34
- /**
35
- * Working directory whose ancestors are walked for context files (segment ②). Default = `agentDir`.
36
- * The opener passes the workspace instead, so an agent that lives in `agentDir` picks up the
37
- * project's AGENTS.md up the tree (core.md scenario grid).
38
- */
30
+ /** Working directory whose ancestors are walked for context files (segment ②). */
39
31
  cwd?: string;
40
32
  env?: ExecutionEnv;
41
33
  }
42
- /** Read an agent definition. persona.md/skills come from `agentDir`; ② context = pi's loadProjectContextFiles({ cwd, agentDir }). */
43
- export declare function loadAgentDefinition(agentDir: string, options?: LoadAgentDefinitionOptions): Promise<LoadedDefinition>;
44
34
  /**
45
- * Extension entry-point FILES under `<agentDir>/extensions/`, empty when there are none.
46
- *
47
- * Paths, not loaded objects — unlike skills (data: content inline, serializable), an extension is
48
- * CODE that pi loads with jiti and binds to its own eventBus/runtime, so loading it here would
49
- * reimplement pi's loader. The engine binding hands these to pi as `additionalExtensionPaths`, which
50
- * survives `noExtensions: true` — that flag suppresses MACHINE-GLOBAL discovery (`~/.pi`), and the
51
- * definition's own extensions were only ever collateral to it. FILES, not the directory: pi's paths
52
- * are module specifiers, and a directory fails as `Cannot find module` into a
53
- * `LoadExtensionsResult.errors` entry nothing reads.
54
- *
55
- * SEPARATE from {@link loadAgentDefinition} on purpose. Prompt and skills are re-read every invoke
56
- * ("the directory is the agent, LIVE"); scanning for extension entry points is not, since the set
57
- * cannot change without a restart. Called once per assembly, like `tools/`.
58
- *
59
- * Discovery runs on BOTH paths; loading does not. `chat` hands these to pi and runs them fully.
60
- * Serving only announces them — pi's extension runtime is shared across sessions, and serving has
61
- * concurrent turns for unrelated conversations (see `PiAgentSessionFactoryOptions.extensionPaths`).
62
- * The refusals below are therefore about what the ARTIFACT may contain, and hold for both.
63
- *
64
- * Discovery follows pi's own rules, so an extension that works in pi works here:
65
- *
66
- * 1. a direct `*.ts` / `*.js` file;
67
- * 2. a subdirectory with `index.ts` / `index.js`.
68
- *
69
- * pi has a third rule — a subdirectory whose `package.json` declares a `pi` field — which is NOT
70
- * implemented here. That shape is reported rather than skipped: a definition whose extension silently
71
- * fails to load is the failure mode this whole path exists to remove.
72
- *
73
- * Containment matches skills/tools/channels/schedules (the fifth of five surfaces): a symlinked
74
- * `extensions/` escaping the agent dir is refused, and — like `loadModuleDir`, whose `entry.isFile()`
75
- * excludes them — a symlinked ENTRY is not loaded either. pi's own discovery does follow those, but
76
- * an extension reached through a link out of the definition is code the artifact does not carry: it
77
- * resolves on the authoring machine and is missing in the container. Refused loudly, never silently.
78
- *
79
- * Absent is normal and silent; a FILE at that path is not — that is an author who meant something.
35
+ * Read an agent definition. persona.md/skills come from `agentDir`; ② context = pi's loadProjectContextFiles({ cwd,
36
+ * agentDir }).
80
37
  */
38
+ export declare function loadAgentDefinition(agentDir: string, options?: LoadAgentDefinitionOptions): Promise<LoadedDefinition>;
39
+ /** Extension entry-point FILES under `<agentDir>/extensions/`, empty when there are none. */
81
40
  export declare function loadExtensionPaths(agentDir: string, options?: {
82
41
  cwd?: string;
83
42
  env?: ExecutionEnv;
84
43
  }): Promise<string[]>;
85
44
  /**
86
- * The definition's skills ALONE, resolved the same way `loadAgentDefinition` resolves them (same
87
- * loader, same containment guard, same first-wins collision rule) — for readers that need only the
88
- * names and must not pay the full load's ② context walk (every AGENTS.md from cwd to root) for them.
89
- * The control plane's `commands()` is that reader, called when a composer opens its completion list.
45
+ * The definition's skills ALONE, resolved the same way `loadAgentDefinition` resolves them (same loader, same
46
+ * containment guard, same first-wins collision rule).
90
47
  */
91
48
  export declare function loadAgentSkills(agentDir: string, options?: {
92
49
  cwd?: string;
@@ -97,6 +54,5 @@ export declare function loadAgentSkills(agentDir: string, options?: {
97
54
  collisions: SkillCollision[];
98
55
  dir: string;
99
56
  }>;
100
- /** Resolve to a canonical (symlink-free) absolute path so comparisons match `process.cwd()`'s realpath.
101
- * A non-existent path can't be realpath'd, so it stays as the plain absolute resolve. */
57
+ /** Resolve to a canonical (symlink-free) absolute path so comparisons match `process.cwd()`'s realpath. */
102
58
  export declare function canonicalPath(p: string): string;