@fastagent-sh/fastagent 0.24.4 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/README.md +53 -82
  2. package/dist/agent-api.d.ts +452 -0
  3. package/dist/agent-api.js +201 -0
  4. package/dist/answer-text.d.ts +8 -0
  5. package/dist/answer-text.js +18 -0
  6. package/dist/atomic-write.d.ts +2 -2
  7. package/dist/atomic-write.js +2 -2
  8. package/dist/authoring.d.ts +77 -0
  9. package/dist/authoring.js +238 -0
  10. package/dist/channel.d.ts +29 -15
  11. package/dist/channel.js +4 -1
  12. package/dist/channels/agentcore-protocol.d.ts +36 -50
  13. package/dist/channels/agentcore-protocol.js +3 -3
  14. package/dist/channels/agentcore-service.d.ts +8 -18
  15. package/dist/channels/agentcore-service.js +108 -127
  16. package/dist/channels/agentcore.d.ts +8 -24
  17. package/dist/channels/agentcore.js +32 -65
  18. package/dist/channels/body.d.ts +0 -16
  19. package/dist/channels/body.js +0 -25
  20. package/dist/channels/busy.js +6 -1
  21. package/dist/channels/context.d.ts +4 -0
  22. package/dist/channels/context.js +35 -0
  23. package/dist/channels/discover.d.ts +18 -20
  24. package/dist/channels/discover.js +41 -99
  25. package/dist/channels/feishu/feishu-api.d.ts +54 -4
  26. package/dist/channels/feishu/feishu-api.js +192 -149
  27. package/dist/channels/feishu/feishu.d.ts +3 -0
  28. package/dist/channels/feishu/feishu.js +117 -106
  29. package/dist/channels/feishu/history.d.ts +55 -0
  30. package/dist/channels/feishu/history.js +199 -0
  31. package/dist/channels/feishu/invoke-turn.d.ts +13 -11
  32. package/dist/channels/feishu/invoke-turn.js +9 -10
  33. package/dist/channels/feishu/model.d.ts +2 -1
  34. package/dist/channels/feishu/normalize.js +100 -0
  35. package/dist/channels/feishu/preview.d.ts +2 -2
  36. package/dist/channels/feishu/register-webhook.d.ts +1 -0
  37. package/dist/channels/feishu/register-webhook.js +3 -2
  38. package/dist/channels/feishu/scaffold/channel.ts +65 -46
  39. package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
  40. package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
  41. package/dist/channels/feishu/setup-mode.d.ts +45 -25
  42. package/dist/channels/feishu/setup-mode.js +74 -23
  43. package/dist/channels/feishu/shared-api.d.ts +24 -6
  44. package/dist/channels/feishu/shared-api.js +30 -24
  45. package/dist/channels/kit/context-buffer.d.ts +11 -2
  46. package/dist/channels/kit/context-buffer.js +7 -4
  47. package/dist/channels/kit/delivery.d.ts +19 -3
  48. package/dist/channels/kit/delivery.js +74 -15
  49. package/dist/channels/kit/event-stream.js +2 -1
  50. package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
  51. package/dist/channels/kit/invoke-turn-kit.js +62 -71
  52. package/dist/channels/kit/place-history.d.ts +107 -0
  53. package/dist/channels/kit/place-history.js +182 -0
  54. package/dist/channels/kit/preview-kit.d.ts +9 -5
  55. package/dist/channels/kit/preview-kit.js +36 -15
  56. package/dist/channels/kit/room-threads.d.ts +46 -0
  57. package/dist/channels/kit/room-threads.js +81 -0
  58. package/dist/channels/kit/seen.js +1 -1
  59. package/dist/channels/kit/stop-command.d.ts +6 -3
  60. package/dist/channels/kit/stop-command.js +20 -18
  61. package/dist/channels/kit/thread-fork.d.ts +17 -0
  62. package/dist/channels/kit/thread-fork.js +43 -0
  63. package/dist/channels/kit/thread-participants.js +1 -1
  64. package/dist/channels/kit/transport.d.ts +5 -0
  65. package/dist/channels/kit/transport.js +5 -0
  66. package/dist/channels/kit/turn-runner.d.ts +10 -9
  67. package/dist/channels/kit/turn-runner.js +17 -19
  68. package/dist/channels/kit/turn-store.d.ts +5 -4
  69. package/dist/channels/kit/turn-store.js +5 -5
  70. package/dist/channels/lark/lark.d.ts +3 -0
  71. package/dist/channels/lark/lark.js +5 -0
  72. package/dist/channels/lark/onboard.d.ts +5 -3
  73. package/dist/channels/lark/onboard.js +14 -14
  74. package/dist/channels/lark/scaffold/channel.ts +67 -44
  75. package/dist/channels/lark/scaffold/lark-send.ts +38 -33
  76. package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
  77. package/dist/channels/respond.d.ts +0 -4
  78. package/dist/channels/respond.js +1 -1
  79. package/dist/channels/router.d.ts +18 -0
  80. package/dist/channels/router.js +68 -0
  81. package/dist/channels/serve.d.ts +5 -70
  82. package/dist/channels/serve.js +105 -287
  83. package/dist/channels/slack/history.d.ts +42 -0
  84. package/dist/channels/slack/history.js +282 -0
  85. package/dist/channels/slack/invoke-turn.d.ts +12 -5
  86. package/dist/channels/slack/invoke-turn.js +7 -5
  87. package/dist/channels/slack/manifest.d.ts +1 -4
  88. package/dist/channels/slack/manifest.js +22 -10
  89. package/dist/channels/slack/model.d.ts +2 -1
  90. package/dist/channels/slack/onboard.d.ts +0 -2
  91. package/dist/channels/slack/onboard.js +2 -4
  92. package/dist/channels/slack/onboarding-state.d.ts +0 -2
  93. package/dist/channels/slack/onboarding-state.js +0 -1
  94. package/dist/channels/slack/parse.d.ts +0 -5
  95. package/dist/channels/slack/parse.js +1 -16
  96. package/dist/channels/slack/preview.d.ts +2 -3
  97. package/dist/channels/slack/preview.js +78 -52
  98. package/dist/channels/slack/register-webhook.d.ts +1 -0
  99. package/dist/channels/slack/register-webhook.js +6 -5
  100. package/dist/channels/slack/scaffold/channel.ts +23 -24
  101. package/dist/channels/slack/scaffold/slack-send.ts +50 -43
  102. package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
  103. package/dist/channels/slack/setup-server.d.ts +19 -0
  104. package/dist/channels/slack/setup-server.js +113 -11
  105. package/dist/channels/slack/shared-api.d.ts +15 -4
  106. package/dist/channels/slack/shared-api.js +19 -14
  107. package/dist/channels/slack/slack-api.d.ts +61 -2
  108. package/dist/channels/slack/slack-api.js +28 -5
  109. package/dist/channels/slack/slack.js +97 -52
  110. package/dist/channels/slack/welcomed.js +1 -1
  111. package/dist/channels/telegram/context-buffer.d.ts +6 -1
  112. package/dist/channels/telegram/context-buffer.js +19 -0
  113. package/dist/channels/telegram/invoke-turn.d.ts +8 -4
  114. package/dist/channels/telegram/invoke-turn.js +7 -7
  115. package/dist/channels/telegram/parse.d.ts +7 -2
  116. package/dist/channels/telegram/parse.js +7 -0
  117. package/dist/channels/telegram/preview.d.ts +2 -2
  118. package/dist/channels/telegram/register-webhook.d.ts +1 -0
  119. package/dist/channels/telegram/register-webhook.js +3 -2
  120. package/dist/channels/telegram/scaffold/channel.ts +27 -28
  121. package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
  122. package/dist/channels/telegram/shared-api.d.ts +34 -0
  123. package/dist/channels/telegram/shared-api.js +79 -0
  124. package/dist/channels/telegram/telegram-api.d.ts +15 -5
  125. package/dist/channels/telegram/telegram-api.js +10 -6
  126. package/dist/channels/telegram/telegram.js +27 -21
  127. package/dist/channels/telegram/turn-store.js +1 -1
  128. package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
  129. package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
  130. package/dist/cli/add-feishu.d.ts +42 -12
  131. package/dist/cli/add-feishu.js +177 -124
  132. package/dist/cli/add-slack.d.ts +8 -3
  133. package/dist/cli/add-slack.js +115 -63
  134. package/dist/cli/auth-view.d.ts +10 -3
  135. package/dist/cli/auth-view.js +8 -6
  136. package/dist/cli/box-login.d.ts +17 -7
  137. package/dist/cli/box-login.js +46 -12
  138. package/dist/cli/commands/add.d.ts +15 -4
  139. package/dist/cli/commands/add.js +252 -143
  140. package/dist/cli/commands/auth.d.ts +6 -0
  141. package/dist/cli/commands/auth.js +50 -0
  142. package/dist/cli/commands/content.d.ts +6 -0
  143. package/dist/cli/commands/content.js +45 -0
  144. package/dist/cli/commands/deploy/agentcore.js +50 -77
  145. package/dist/cli/commands/deploy/docker.js +38 -39
  146. package/dist/cli/commands/deploy/fly.js +21 -18
  147. package/dist/cli/commands/deploy/host-login.d.ts +26 -0
  148. package/dist/cli/commands/deploy/host-login.js +90 -0
  149. package/dist/cli/commands/deploy/railway.js +21 -26
  150. package/dist/cli/commands/deploy/shared.d.ts +45 -17
  151. package/dist/cli/commands/deploy/shared.js +34 -15
  152. package/dist/cli/commands/deploy.d.ts +0 -4
  153. package/dist/cli/commands/deploy.js +237 -50
  154. package/dist/cli/commands/destroy.js +8 -6
  155. package/dist/cli/commands/dev.d.ts +0 -2
  156. package/dist/cli/commands/dev.js +20 -19
  157. package/dist/cli/commands/env.d.ts +12 -0
  158. package/dist/cli/commands/env.js +190 -0
  159. package/dist/cli/commands/info.js +95 -156
  160. package/dist/cli/commands/init.d.ts +2 -2
  161. package/dist/cli/commands/init.js +35 -33
  162. package/dist/cli/commands/invoke.d.ts +6 -0
  163. package/dist/cli/commands/invoke.js +131 -16
  164. package/dist/cli/commands/login.d.ts +31 -2
  165. package/dist/cli/commands/login.js +413 -64
  166. package/dist/cli/commands/logout.d.ts +4 -0
  167. package/dist/cli/commands/logout.js +53 -0
  168. package/dist/cli/commands/logs.js +8 -6
  169. package/dist/cli/commands/models.d.ts +2 -1
  170. package/dist/cli/commands/models.js +39 -37
  171. package/dist/cli/commands/schedules.d.ts +21 -0
  172. package/dist/cli/commands/schedules.js +143 -0
  173. package/dist/cli/commands/start.d.ts +11 -10
  174. package/dist/cli/commands/start.js +35 -62
  175. package/dist/cli/content-view.d.ts +9 -0
  176. package/dist/cli/content-view.js +26 -0
  177. package/dist/cli/fail.d.ts +9 -12
  178. package/dist/cli/fail.js +17 -14
  179. package/dist/cli/invoke-stream.d.ts +12 -3
  180. package/dist/cli/invoke-stream.js +85 -23
  181. package/dist/cli/kernel.d.ts +9 -2
  182. package/dist/cli/kernel.js +15 -6
  183. package/dist/cli/login-relay.d.ts +3 -2
  184. package/dist/cli/login-relay.js +18 -6
  185. package/dist/cli/models-view.d.ts +5 -1
  186. package/dist/cli/models-view.js +1 -1
  187. package/dist/cli/person.d.ts +10 -0
  188. package/dist/cli/person.js +23 -0
  189. package/dist/cli/program.js +421 -203
  190. package/dist/cli/serve.d.ts +13 -63
  191. package/dist/cli/serve.js +31 -121
  192. package/dist/cli/shared.d.ts +21 -48
  193. package/dist/cli/shared.js +68 -89
  194. package/dist/cli/ticket.d.ts +136 -0
  195. package/dist/cli/ticket.js +476 -0
  196. package/dist/client.d.ts +7 -0
  197. package/dist/client.js +2 -0
  198. package/dist/content/declare.d.ts +70 -0
  199. package/dist/content/declare.js +163 -0
  200. package/dist/content/file.d.ts +32 -0
  201. package/dist/content/file.js +119 -0
  202. package/dist/content/git.d.ts +41 -0
  203. package/dist/content/git.js +217 -0
  204. package/dist/content/mount.d.ts +2 -0
  205. package/dist/content/mount.js +15 -0
  206. package/dist/content/resolve.d.ts +52 -0
  207. package/dist/content/resolve.js +151 -0
  208. package/dist/content/source.d.ts +27 -0
  209. package/dist/content/source.js +53 -0
  210. package/dist/conversation-sessions.d.ts +26 -0
  211. package/dist/conversation-sessions.js +99 -0
  212. package/dist/declared-secrets.d.ts +19 -37
  213. package/dist/declared-secrets.js +16 -58
  214. package/dist/deploy/agentcore/destroy.d.ts +3 -3
  215. package/dist/deploy/agentcore/destroy.js +46 -28
  216. package/dist/deploy/agentcore/forwarder.js +105 -22
  217. package/dist/deploy/agentcore/logs.js +1 -1
  218. package/dist/deploy/agentcore/plan.d.ts +10 -24
  219. package/dist/deploy/agentcore/plan.js +31 -135
  220. package/dist/deploy/agentcore/run.d.ts +1 -1
  221. package/dist/deploy/agentcore/run.js +8 -5
  222. package/dist/deploy/agentcore/shell.d.ts +1 -1
  223. package/dist/deploy/agentcore/shell.js +5 -5
  224. package/dist/deploy/api.d.ts +34 -0
  225. package/dist/deploy/api.js +50 -0
  226. package/dist/deploy/box-shell.d.ts +6 -0
  227. package/dist/deploy/box-shell.js +7 -0
  228. package/dist/deploy/build-context.d.ts +7 -5
  229. package/dist/deploy/build-context.js +41 -35
  230. package/dist/deploy/channel-ingress.d.ts +6 -1
  231. package/dist/deploy/channel-ingress.js +18 -5
  232. package/dist/deploy/container.d.ts +22 -9
  233. package/dist/deploy/container.js +96 -55
  234. package/dist/deploy/docker/plan.d.ts +3 -2
  235. package/dist/deploy/docker/plan.js +13 -14
  236. package/dist/deploy/docker/run.d.ts +2 -2
  237. package/dist/deploy/docker/run.js +8 -4
  238. package/dist/deploy/fly/plan.d.ts +1 -1
  239. package/dist/deploy/fly/plan.js +12 -21
  240. package/dist/deploy/fly/run.d.ts +10 -6
  241. package/dist/deploy/fly/run.js +11 -6
  242. package/dist/deploy/hosts.d.ts +2 -1
  243. package/dist/deploy/hosts.js +2 -1
  244. package/dist/deploy/preflight.d.ts +21 -23
  245. package/dist/deploy/preflight.js +222 -201
  246. package/dist/deploy/railway/plan.d.ts +8 -6
  247. package/dist/deploy/railway/plan.js +15 -58
  248. package/dist/deploy/railway/run.d.ts +8 -3
  249. package/dist/deploy/railway/run.js +12 -8
  250. package/dist/deploy/residency.d.ts +5 -11
  251. package/dist/deploy/residency.js +0 -6
  252. package/dist/deploy/runner.d.ts +1 -1
  253. package/dist/deploy/runner.js +1 -1
  254. package/dist/deploy/secrets.d.ts +16 -2
  255. package/dist/deploy/secrets.js +33 -6
  256. package/dist/deploy/workspace.d.ts +11 -6
  257. package/dist/deploy/workspace.js +55 -38
  258. package/dist/dev-supervisor.d.ts +11 -2
  259. package/dist/dev-supervisor.js +51 -26
  260. package/dist/effect-port.d.ts +4 -4
  261. package/dist/effect-port.js +4 -4
  262. package/dist/environment/apt.d.ts +4 -0
  263. package/dist/environment/apt.js +32 -0
  264. package/dist/environment/declare.d.ts +59 -0
  265. package/dist/environment/declare.js +210 -0
  266. package/dist/environment/mise.d.ts +50 -0
  267. package/dist/environment/mise.js +268 -0
  268. package/dist/feishu.d.ts +2 -2
  269. package/dist/feishu.js +2 -2
  270. package/dist/git.d.ts +13 -0
  271. package/dist/git.js +55 -0
  272. package/dist/harnesses/models/catalog.d.ts +20 -0
  273. package/dist/harnesses/models/catalog.js +254 -0
  274. package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
  275. package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
  276. package/dist/harnesses/models/environment.d.ts +43 -0
  277. package/dist/harnesses/models/environment.js +82 -0
  278. package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
  279. package/dist/{engines/pi → harnesses/models}/login.js +187 -79
  280. package/dist/harnesses/models/models.d.ts +83 -0
  281. package/dist/harnesses/models/models.js +158 -0
  282. package/dist/harnesses/pi-durable/agent.d.ts +42 -0
  283. package/dist/harnesses/pi-durable/agent.js +579 -0
  284. package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
  285. package/dist/harnesses/pi-durable/defaults.js +26 -0
  286. package/dist/harnesses/pi-durable/define.d.ts +77 -0
  287. package/dist/harnesses/pi-durable/define.js +28 -0
  288. package/dist/harnesses/pi-durable/entries.d.ts +32 -0
  289. package/dist/harnesses/pi-durable/entries.js +126 -0
  290. package/dist/harnesses/pi-durable/events.d.ts +25 -0
  291. package/dist/harnesses/pi-durable/events.js +238 -0
  292. package/dist/harnesses/pi-durable/ids.d.ts +16 -0
  293. package/dist/harnesses/pi-durable/ids.js +55 -0
  294. package/dist/harnesses/pi-durable/messages.d.ts +41 -0
  295. package/dist/harnesses/pi-durable/messages.js +116 -0
  296. package/dist/harnesses/pi-durable/open.d.ts +88 -0
  297. package/dist/harnesses/pi-durable/open.js +329 -0
  298. package/dist/harnesses/pi-durable/reads.d.ts +30 -0
  299. package/dist/harnesses/pi-durable/reads.js +94 -0
  300. package/dist/harnesses/pi-durable/registry.d.ts +18 -0
  301. package/dist/harnesses/pi-durable/registry.js +56 -0
  302. package/dist/harnesses/pi-durable/release.d.ts +13 -0
  303. package/dist/harnesses/pi-durable/release.js +40 -0
  304. package/dist/harnesses/pi-durable/serve.d.ts +80 -0
  305. package/dist/harnesses/pi-durable/serve.js +156 -0
  306. package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
  307. package/dist/harnesses/pi-durable/sessions.js +47 -0
  308. package/dist/harnesses/pi-durable/storage.d.ts +4 -0
  309. package/dist/harnesses/pi-durable/storage.js +49 -0
  310. package/dist/harnesses/pi-durable/stream.d.ts +20 -0
  311. package/dist/harnesses/pi-durable/stream.js +221 -0
  312. package/dist/harnesses/pi-durable/text.d.ts +30 -0
  313. package/dist/harnesses/pi-durable/text.js +292 -0
  314. package/dist/harnesses/pi-durable/wake.d.ts +4 -0
  315. package/dist/harnesses/pi-durable/wake.js +81 -0
  316. package/dist/http/client.d.ts +6 -0
  317. package/dist/http/client.js +256 -0
  318. package/dist/http/contract.d.ts +541 -0
  319. package/dist/http/contract.js +179 -0
  320. package/dist/http/server.d.ts +34 -0
  321. package/dist/http/server.js +194 -0
  322. package/dist/index.d.ts +17 -4
  323. package/dist/index.js +10 -5
  324. package/dist/lark.d.ts +2 -2
  325. package/dist/lark.js +2 -2
  326. package/dist/locked-file.d.ts +17 -0
  327. package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
  328. package/dist/once.d.ts +6 -0
  329. package/dist/once.js +23 -0
  330. package/dist/paths.d.ts +36 -52
  331. package/dist/paths.js +66 -182
  332. package/dist/runtime.d.ts +25 -2
  333. package/dist/runtime.js +27 -0
  334. package/dist/scaffold/add-channel.d.ts +14 -27
  335. package/dist/scaffold/add-channel.js +82 -180
  336. package/dist/scaffold/init.d.ts +17 -18
  337. package/dist/scaffold/init.js +87 -99
  338. package/dist/scaffold/templates/SYSTEM.md +12 -0
  339. package/dist/scaffold/templates/env.example +4 -10
  340. package/dist/scaffold/templates/fastagent.config.ts +21 -33
  341. package/dist/scaffold/templates/gitignore +8 -1
  342. package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
  343. package/dist/scaffold/templates.d.ts +9 -4
  344. package/dist/scaffold/templates.js +7 -5
  345. package/dist/scaffold/vendor-skill.d.ts +1 -4
  346. package/dist/scaffold/vendor-skill.js +5 -6
  347. package/dist/schedule/cron.d.ts +13 -0
  348. package/dist/schedule/cron.js +52 -0
  349. package/dist/schedule/eventbridge-cron.d.ts +17 -0
  350. package/dist/schedule/eventbridge-cron.js +88 -0
  351. package/dist/schedule/schedule.d.ts +23 -0
  352. package/dist/schedule/schedule.js +34 -0
  353. package/dist/schedule/scheduler.d.ts +34 -33
  354. package/dist/schedule/scheduler.js +251 -137
  355. package/dist/schedule/state.d.ts +4 -14
  356. package/dist/schedule/state.js +7 -7
  357. package/dist/schedule/wake-alarm.d.ts +22 -2
  358. package/dist/schedule/wake-alarm.js +66 -20
  359. package/dist/schedule/wakeups.d.ts +16 -15
  360. package/dist/schedule/wakeups.js +47 -45
  361. package/dist/service.d.ts +56 -169
  362. package/dist/service.js +91 -187
  363. package/dist/serving-command.d.ts +10 -0
  364. package/dist/serving-command.js +16 -0
  365. package/dist/slack.d.ts +1 -1
  366. package/dist/slack.js +1 -1
  367. package/dist/{channels/kit/state.js → state-file.js} +6 -6
  368. package/dist/telegram.d.ts +1 -0
  369. package/dist/telegram.js +1 -0
  370. package/dist/tunnel.d.ts +3 -0
  371. package/dist/tunnel.js +12 -4
  372. package/dist/value-file.d.ts +21 -0
  373. package/dist/value-file.js +108 -0
  374. package/dist/version.d.ts +5 -0
  375. package/dist/version.js +14 -1
  376. package/package.json +18 -28
  377. package/dist/agent.d.ts +0 -106
  378. package/dist/agent.js +0 -21
  379. package/dist/channels/control.d.ts +0 -31
  380. package/dist/channels/control.js +0 -329
  381. package/dist/channels/define-channel.d.ts +0 -39
  382. package/dist/channels/define-channel.js +0 -9
  383. package/dist/channels/feishu/context-buffer.d.ts +0 -35
  384. package/dist/channels/feishu/context-buffer.js +0 -65
  385. package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
  386. package/dist/channels/http.d.ts +0 -23
  387. package/dist/channels/http.js +0 -57
  388. package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
  389. package/dist/channels/slack/context-buffer.d.ts +0 -23
  390. package/dist/channels/slack/context-buffer.js +0 -37
  391. package/dist/channels/sse.d.ts +0 -4
  392. package/dist/channels/sse.js +0 -66
  393. package/dist/cli/commands/chat.d.ts +0 -3
  394. package/dist/cli/commands/chat.js +0 -14
  395. package/dist/cli/commands/routine-run.d.ts +0 -6
  396. package/dist/cli/commands/routine-run.js +0 -46
  397. package/dist/cli/commands/routine.d.ts +0 -25
  398. package/dist/cli/commands/routine.js +0 -122
  399. package/dist/cli/commands/tool.d.ts +0 -1
  400. package/dist/cli/commands/tool.js +0 -57
  401. package/dist/collect.d.ts +0 -63
  402. package/dist/collect.js +0 -90
  403. package/dist/core.d.ts +0 -13
  404. package/dist/core.js +0 -15
  405. package/dist/engines/pi/agent-models.d.ts +0 -83
  406. package/dist/engines/pi/agent-models.js +0 -120
  407. package/dist/engines/pi/agent-session-factory.d.ts +0 -121
  408. package/dist/engines/pi/agent-session-factory.js +0 -535
  409. package/dist/engines/pi/chat.d.ts +0 -3
  410. package/dist/engines/pi/chat.js +0 -8
  411. package/dist/engines/pi/config.d.ts +0 -71
  412. package/dist/engines/pi/config.js +0 -199
  413. package/dist/engines/pi/create.d.ts +0 -170
  414. package/dist/engines/pi/create.js +0 -343
  415. package/dist/engines/pi/definition.d.ts +0 -74
  416. package/dist/engines/pi/definition.js +0 -236
  417. package/dist/engines/pi/entry-images.d.ts +0 -14
  418. package/dist/engines/pi/entry-images.js +0 -23
  419. package/dist/engines/pi/invoke-session.d.ts +0 -18
  420. package/dist/engines/pi/invoke-session.js +0 -403
  421. package/dist/engines/pi/locked-file.d.ts +0 -9
  422. package/dist/engines/pi/machine.d.ts +0 -53
  423. package/dist/engines/pi/machine.js +0 -137
  424. package/dist/engines/pi/models.d.ts +0 -200
  425. package/dist/engines/pi/models.js +0 -533
  426. package/dist/engines/pi/open.d.ts +0 -180
  427. package/dist/engines/pi/open.js +0 -270
  428. package/dist/engines/pi/openai-account-models.d.ts +0 -35
  429. package/dist/engines/pi/openai-account-models.js +0 -116
  430. package/dist/engines/pi/report.d.ts +0 -18
  431. package/dist/engines/pi/report.js +0 -59
  432. package/dist/engines/pi/retry-event.d.ts +0 -6
  433. package/dist/engines/pi/retry-event.js +0 -15
  434. package/dist/engines/pi/service.d.ts +0 -9
  435. package/dist/engines/pi/service.js +0 -14
  436. package/dist/engines/pi/session-builder.d.ts +0 -13
  437. package/dist/engines/pi/session-builder.js +0 -117
  438. package/dist/engines/pi/session-control.d.ts +0 -77
  439. package/dist/engines/pi/session-control.js +0 -908
  440. package/dist/engines/pi/session-effects.d.ts +0 -14
  441. package/dist/engines/pi/session-effects.js +0 -30
  442. package/dist/engines/pi/session-inheritance.d.ts +0 -21
  443. package/dist/engines/pi/session-inheritance.js +0 -204
  444. package/dist/engines/pi/session-markers.d.ts +0 -49
  445. package/dist/engines/pi/session-markers.js +0 -60
  446. package/dist/engines/pi/session-settings.d.ts +0 -67
  447. package/dist/engines/pi/session-settings.js +0 -119
  448. package/dist/engines/pi/session-store.d.ts +0 -69
  449. package/dist/engines/pi/session-store.js +0 -430
  450. package/dist/engines/pi/tool-context.d.ts +0 -45
  451. package/dist/engines/pi/tool-context.js +0 -31
  452. package/dist/engines/pi/tool.d.ts +0 -99
  453. package/dist/engines/pi/tool.js +0 -118
  454. package/dist/engines/pi/turn-kit.d.ts +0 -92
  455. package/dist/engines/pi/turn-kit.js +0 -288
  456. package/dist/engines/pi/wake-tool.d.ts +0 -9
  457. package/dist/engines/pi/wake-tool.js +0 -92
  458. package/dist/loader.d.ts +0 -41
  459. package/dist/loader.js +0 -116
  460. package/dist/node.d.ts +0 -3
  461. package/dist/node.js +0 -4
  462. package/dist/observe.d.ts +0 -6
  463. package/dist/observe.js +0 -47
  464. package/dist/pi.d.ts +0 -25
  465. package/dist/pi.js +0 -15
  466. package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
  467. package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
  468. package/dist/schedule/discover.d.ts +0 -17
  469. package/dist/schedule/discover.js +0 -61
  470. package/dist/schedule/routine.d.ts +0 -43
  471. package/dist/schedule/routine.js +0 -32
  472. package/dist/schedule/run.d.ts +0 -55
  473. package/dist/schedule/run.js +0 -146
  474. package/dist/secrets-gate.d.ts +0 -32
  475. package/dist/secrets-gate.js +0 -33
  476. package/dist/session-remote.d.ts +0 -47
  477. package/dist/session-remote.js +0 -460
  478. package/dist/session.d.ts +0 -466
  479. package/dist/session.js +0 -57
  480. /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
@@ -1,10 +1,11 @@
1
- import type { FeishuGroupBehavior, FeishuSubscriptionMode } from "../feishu/setup-mode.ts";
1
+ import type { FeishuSubscriptionMode } from "../feishu/setup-mode.ts";
2
2
  /** Guided Lark-international onboarding. */
3
3
  export declare const LARK_CONSOLE_URL = "https://open.larksuite.com/page/launcher?from=backend_oneclick";
4
4
  /** Directly where the fallback token lives (and where the successful automatic mode change is visible). */
5
5
  export declare function larkEventSecurityUrl(appId: string): string;
6
6
  export interface LarkOnboardIO {
7
- openUrl(url: string): void;
7
+ /** A page for the person, and what they do there. */
8
+ openUrl(url: string, action: string): void;
8
9
  note(message: string): void;
9
10
  prompt(message: string, opts?: {
10
11
  hidden?: boolean;
@@ -20,9 +21,10 @@ export interface LarkOnboardOptions {
20
21
  /** Existing active .env values. */
21
22
  existing?: Readonly<Record<string, string | undefined>>;
22
23
  ingress?: FeishuSubscriptionMode;
23
- groupBehavior?: FeishuGroupBehavior;
24
24
  verifyCredentials(appId: string, appSecret: string): Promise<void>;
25
25
  bootstrapWebhook?(appId: string, appSecret: string): Promise<LarkBootstrapResult>;
26
+ /** The command that continues an interrupted setup: the one that started it (`add lark`, `deploy <host> --run`). */
27
+ rerun?: string;
26
28
  }
27
29
  export interface LarkOnboardCredentials {
28
30
  LARK_APP_ID: string;
@@ -4,35 +4,33 @@ export const LARK_CONSOLE_URL = "https://open.larksuite.com/page/launcher?from=b
4
4
  export function larkEventSecurityUrl(appId) {
5
5
  return `https://open.larksuite.com/app/${encodeURIComponent(appId)}/event?tab=safe`;
6
6
  }
7
- function required(value, name) {
7
+ function required(value, name, rerun) {
8
8
  const trimmed = value?.trim();
9
9
  if (!trimmed)
10
- throw new Error(`${name} is required — re-run \`fastagent add lark\` to continue setup`);
10
+ throw new Error(`${name} is required — re-run \`${rerun}\` to continue setup`);
11
11
  return trimmed;
12
12
  }
13
13
  /** Open the stable app console and collect everything the runtime needs. */
14
14
  export async function onboardLarkApp(io, opts) {
15
+ const rerun = opts.rerun ?? "fastagent add lark";
15
16
  const existingId = opts.existing?.LARK_APP_ID?.trim();
16
17
  const existingSecret = opts.existing?.LARK_APP_SECRET?.trim();
17
18
  const reuseExistingApp = Boolean(existingId && existingSecret);
18
19
  // Credentials are one App-scoped set.
19
20
  if (reuseExistingApp) {
20
- io.note(`Reusing Lark app ${existingId}; opening its Events & Callbacks configuration directly.`);
21
+ io.note(`Reusing Lark app ${existingId}.`);
21
22
  }
22
23
  else {
23
- io.note(`Create the app on Lark's one-click launcher. Opening ${LARK_CONSOLE_URL}`);
24
- io.openUrl(LARK_CONSOLE_URL);
24
+ io.openUrl(LARK_CONSOLE_URL, "create the app on Lark's one-click launcher; LARK_APP_ID and LARK_APP_SECRET are under Credentials & Basic Info");
25
25
  }
26
- const appId = required(reuseExistingApp ? existingId : await io.prompt("LARK_APP_ID (Credentials & Basic Info)", { hidden: false }), "LARK_APP_ID");
27
- const appSecret = required(reuseExistingApp ? existingSecret : await io.prompt("LARK_APP_SECRET (Credentials & Basic Info)", { hidden: true }), "LARK_APP_SECRET");
26
+ const appId = required(reuseExistingApp ? existingId : await io.prompt("LARK_APP_ID (Credentials & Basic Info)", { hidden: false }), "LARK_APP_ID", rerun);
27
+ const appSecret = required(reuseExistingApp ? existingSecret : await io.prompt("LARK_APP_SECRET (Credentials & Basic Info)", { hidden: true }), "LARK_APP_SECRET", rerun);
28
28
  await opts.verifyCredentials(appId, appSecret);
29
29
  const eventSecurityUrl = larkEventSecurityUrl(appId);
30
- io.note(`App ID / Secret verified. Opening Events & Callbacks → Security: ${eventSecurityUrl}`);
31
- io.openUrl(eventSecurityUrl);
30
+ io.note("App ID / Secret verified.");
32
31
  if (opts.ingress === "websocket") {
33
- io.note(opts.groupBehavior === "mentions"
34
- ? "Choose long connection, subscribe im.message.receive_v1, then create + publish an app version. No Verification Token or Request URL is needed."
35
- : "Choose long connection and subscribe im.message.receive_v1, but do not publish yet — context-aware group permission setup follows. No Verification Token or Request URL is needed.");
32
+ io.openUrl(eventSecurityUrl, "in Events & Callbacks, choose long connection and subscribe im.message.receive_v1, but do not publish yet: " +
33
+ "the permission check follows (no Verification Token or Request URL is needed)");
36
34
  return { LARK_APP_ID: appId, LARK_APP_SECRET: appSecret };
37
35
  }
38
36
  io.note("Trying automatic webhook-mode + Verification-Token bootstrap…");
@@ -43,11 +41,13 @@ export async function onboardLarkApp(io, opts) {
43
41
  io.note("Verification Token captured; Subscription mode changed to webhook in the app draft.");
44
42
  }
45
43
  else {
46
- io.note(`${bootstrap.manualReason ?? "Automatic bootstrap unavailable."} Open Events & Callbacks → Encryption Strategy and copy the Verification Token. You must also switch Subscription mode to webhook when setting the Request URL.`);
44
+ io.note(bootstrap.manualReason ?? "Automatic bootstrap unavailable.");
45
+ io.openUrl(eventSecurityUrl, "in Events & Callbacks → Encryption Strategy, copy the Verification Token, and switch Subscription mode to " +
46
+ "webhook when setting the Request URL");
47
47
  }
48
48
  const verificationToken = required(bootstrap.token ||
49
49
  (reuseExistingApp ? opts.existing?.LARK_VERIFICATION_TOKEN?.trim() : undefined) ||
50
- (await io.prompt("LARK_VERIFICATION_TOKEN (Events & Callbacks → Encryption Strategy)", { hidden: true })), "LARK_VERIFICATION_TOKEN");
50
+ (await io.prompt("LARK_VERIFICATION_TOKEN (Events & Callbacks → Encryption Strategy)", { hidden: true })), "LARK_VERIFICATION_TOKEN", rerun);
51
51
  return {
52
52
  LARK_APP_ID: appId,
53
53
  LARK_APP_SECRET: appSecret,
@@ -1,48 +1,71 @@
1
- import { larkChannel } from "@fastagent-sh/fastagent/lark";
2
- import { defineChannel } from "@fastagent-sh/fastagent";
1
+ import { needs } from "@fastagent-sh/fastagent";
2
+ import {
3
+ type LarkChannelOptions,
4
+ larkChannel,
5
+ larkIngress,
6
+ larkWebSocketChannel,
7
+ } from "@fastagent-sh/fastagent/lark";
3
8
 
4
- // larkChannel is the branded compatibility adapter over fastagent's canonical Feishu engine, configured
5
- // with YOUR policy. fastagent discovers this file, mounts POST /lark, and pipes the agent + state home
6
- // to the adapter. Lark international (open.larksuite.com) only; a
7
- // Feishu tenant uses `fastagent add feishu` instead. Setup (developer console):
9
+ // The branded Lark adapter over fastagent's canonical Feishu engine (verify + run + reply), configured
10
+ // with YOUR policy. Lark international (open.larksuite.com) only; a Feishu tenant uses `fastagent add
11
+ // feishu` instead.
12
+ //
13
+ // How it receives is LARK_INGRESS (webhook | websocket). Unset, `fastagent dev` connects OUT by
14
+ // WebSocket (no public URL, no tunnel), and everything else — `fastagent start`, every deployment —
15
+ // receives by webhook at POST /lark. Dev reads .secrets/.env; production reads
16
+ // .secrets/production/.env. Interactive `deploy --run` guides creation of a separate production app;
17
+ // if Lark refuses its config API, set the Request URL in the console once.
18
+ //
19
+ // `fastagent add lark` guides the console setup and validates the credentials. In the developer
20
+ // console:
8
21
  // 1. create a custom app → enable the BOT capability → copy App ID / App Secret into .env
9
22
  // 2. Permissions: add `im:message.p2p_msg:readonly` (direct messages), `im:message.group_at_msg:readonly`
10
23
  // (group @mentions), `im:message:send_as_bot` (reply), `im:resource` (attachments), and the
11
- // card scope ("Create and update card" — the live preview streams through a card). To answer bare
12
- // messages in threads the Agent takes part in, and buffer other unsummoned group/thread context, also add the
13
- // sensitive `im:message.group_msg` scope (tenant-admin approval) and publish a new version. Add a
14
- // message-read scope (e.g. `im:message:readonly`) too, so a thread's opening ask can carry the
15
- // message it quotes; without it that quote degrades to a marker in the prompt.
16
- // 3. Events & Callbacks → subscribe to `im.message.receive_v1`; copy the Verification Token into
17
- // .env; RECOMMENDED: set an Encrypt Key there and mirror it in LARK_ENCRYPT_KEY
18
- // 4. run `fastagent dev --tunnel`: it attempts to switch Subscription mode to webhook + register
19
- // the URL automatically. If this app returns a config-API 404, do both BY HAND in the console
20
- // with the server running (the platform verifies https://your.host/lark with a challenge).
21
- // 5. create a version and publish the app (a tenant admin approves it), then add the bot to a chat
22
- export default defineChannel({
23
- // The env vars this channel needs. fastagent carries them to a deployed box and refuses to serve
24
- // while one is unset — a bare process.env read gets neither guarantee. LARK_ENCRYPT_KEY is
25
- // optional, so it is NOT declared here: an undeclared read stays undeclared on purpose.
26
- secrets: ["LARK_APP_ID", "LARK_APP_SECRET", "LARK_VERIFICATION_TOKEN"],
27
- channel: (secrets) =>
28
- larkChannel({
29
- appId: secrets.LARK_APP_ID,
30
- appSecret: secrets.LARK_APP_SECRET,
31
- verificationToken: secrets.LARK_VERIFICATION_TOKEN, // authenticates inbound events
32
- encryptKey: process.env.LARK_ENCRYPT_KEY || undefined, // optional; when set, plaintext events are refused
33
- // No session modes: a chat is one session and a thread is another, and where the answer goes follows
34
- // from that (docs/design/participant-model.md).
35
- // Dev/personal bot: surface raw errors to the chat so you (and your AI agent) can act on them. The
36
- // chat is customer-facing by default — for a public bot, drop this or return a neutral string;
37
- // full details always go to the server log regardless.
38
- onError: (failed) => `⚠️ ${failed.details}`,
39
- // The channel owns transport + format (markdown card) + attachments (image→vision, file→disk) +
40
- // the live streaming preview. `route` (POLICY) is OPTIONAL — omitted, it uses defaultLarkRoute:
41
- // p2p chats always answer; groups answer on @this-bot, plus bare messages in a thread where the
42
- // Agent takes part and exactly ONE human does. Other human group/thread discussion buffers until
43
- // that place's next answered turn; @other-only messages buffer rather than triggering the Agent.
44
- // Override to customise explicit routing, reusing the export:
45
- // route: (e) => defaultLarkRoute(e, { botOpenId: "ou_xxx" }) && { session: `user:${e.sender?.sender_id?.open_id}` },
46
- // route: (e) => defaultLarkRoute(e, { botOpenId: "ou_xxx" }) && { text: `${larkEnvelope(e)}\n[extra]` },
47
- }),
48
- });
24
+ // card scope ("Create and update card" — the live preview streams through a card). So the Agent
25
+ // hears its group chats, also add `im:message.group_msg` (sensitive), `im:message:readonly` and
26
+ // `im:chat.members:read`; for webhook, `application:application:patch` lets fastagent set the
27
+ // Request URL. What each is for is in the channel guide; the channel warns about any it lacks.
28
+ // 3. Events & Callbacks → subscribe to `im.message.receive_v1`. For webhook, copy the Verification
29
+ // Token into .env (RECOMMENDED: set an Encrypt Key there and mirror it in LARK_ENCRYPT_KEY).
30
+ // 4. create a version and publish the app (a tenant admin approves it), then add the bot to a chat
31
+
32
+ // Your policy, the same whichever way the channel receives.
33
+ const policy: Pick<LarkChannelOptions, "onError" | "route"> = {
34
+ // A chat is one conversation and a thread is another, each with a session of its own, and where the
35
+ // answer goes follows from that (docs/design/participant-model.md).
36
+ // Dev/personal bot: surface raw errors to the chat so you (and your AI agent) can act on them. The
37
+ // chat is customer-facing by default — for a public bot, drop this or return a neutral string;
38
+ // full details always go to the server log regardless.
39
+ onError: (failed) => `⚠️ ${failed.details}`,
40
+ // The channel owns transport + format (markdown card) + attachments (image→vision, file→disk) +
41
+ // the live streaming preview. `route` (POLICY) is OPTIONAL — omitted, it uses defaultLarkRoute:
42
+ // p2p chats always answer; groups answer on @this-bot, plus bare messages in a thread where the
43
+ // Agent takes part and exactly ONE human does. Other group/thread discussion is read from the
44
+ // platform by that place's next answered turn; @other-only messages are discussion, not asks.
45
+ // Override to customise explicit routing, reusing the export:
46
+ // route: (e) => defaultLarkRoute(e, { botOpenId: "ou_xxx" }) && { conversation: `user:${e.sender?.sender_id?.open_id}` },
47
+ // route: (e) => defaultLarkRoute(e, { botOpenId: "ou_xxx" }) && { text: `${larkEnvelope(e)}\n[extra]` },
48
+ };
49
+
50
+ // `needs` declares the env vars this channel reads: fastagent carries them to a deployed box and
51
+ // refuses to serve while a required one is unset. LARK_ENCRYPT_KEY is optional.
52
+ export default larkIngress() === "webhook"
53
+ ? needs(
54
+ [
55
+ "LARK_APP_ID",
56
+ "LARK_APP_SECRET",
57
+ "LARK_VERIFICATION_TOKEN",
58
+ { name: "LARK_ENCRYPT_KEY", description: "when set, plaintext events are refused", optional: true },
59
+ ],
60
+ (secrets) =>
61
+ larkChannel({
62
+ appId: secrets.LARK_APP_ID,
63
+ appSecret: secrets.LARK_APP_SECRET,
64
+ verificationToken: secrets.LARK_VERIFICATION_TOKEN, // authenticates inbound events
65
+ encryptKey: secrets.LARK_ENCRYPT_KEY,
66
+ ...policy,
67
+ }),
68
+ )
69
+ : needs(["LARK_APP_ID", "LARK_APP_SECRET"], (secrets) =>
70
+ larkWebSocketChannel({ appId: secrets.LARK_APP_ID, appSecret: secrets.LARK_APP_SECRET, ...policy }),
71
+ );
@@ -1,37 +1,42 @@
1
- import { defineTool, z } from "@fastagent-sh/fastagent";
1
+ import { Type } from "@earendil-works/pi-ai";
2
+ import { defineTool } from "@earendil-works/pi-durable";
3
+ import { needs } from "@fastagent-sh/fastagent";
2
4
  import { larkTransport } from "@fastagent-sh/fastagent/lark";
3
5
 
4
6
  // Proactive delivery uses the mounted channel's credentials, gateway and token cache. With no
5
- // channel mounted (fire/invoke/tool), it reads LARK_APP_ID / LARK_APP_SECRET from the environment.
6
-
7
- export default defineTool({
8
- description:
9
- "Send a message to a Lark chat, OUTSIDE the normal reply path. Call it only for a turn NO " +
10
- "channel is carrying — a scheduled or self-scheduled (wake) turn, whose plain reply goes " +
11
- "nowhere — or to reach a chat OTHER than the one you are answering. In a normal chat turn the " +
12
- "channel streams and delivers your reply itself, so do NOT call this to answer the current " +
13
- "chat: it would post the message twice, outside the conversation thread. `chatId` (oc_…) names " +
14
- "the DESTINATION and must come from your instructions (the asking message, the schedule prompt, " +
15
- "or memory); the [lark: chat …] context line only identifies the chat you are answering — the " +
16
- "one chat this tool must not target in a chat turn. Pass exactly ONE of `text` (plain) or " +
17
- "`markdown` (rendered as a card: headings, bold, code blocks, links).",
18
- input: z.object({
19
- chatId: z.string().describe("target chat id (oc_…)"),
20
- text: z.string().optional().describe("plain text message to send"),
21
- markdown: z.string().optional().describe("markdown to send as a card"),
7
+ // channel mounted, it signs in with LARK_APP_ID / LARK_APP_SECRET itself.
8
+ export default needs(["LARK_APP_ID", "LARK_APP_SECRET"], (secrets) =>
9
+ defineTool({
10
+ name: "lark_send",
11
+ description:
12
+ "Send a message to a Lark chat, OUTSIDE the normal reply path. Call it only for a message NO " +
13
+ "channel is carrying (a scheduled or self-scheduled one, whose plain reply goes " +
14
+ "nowhere) or to reach a chat OTHER than the one you are answering. In a normal chat turn the " +
15
+ "channel streams and delivers your reply itself, so do NOT call this to answer the current " +
16
+ "chat: it would post the message twice, outside the conversation thread. `chatId` (oc_…) names " +
17
+ "the DESTINATION and must come from your instructions (the asking message, the schedule prompt, " +
18
+ "or memory); the [lark: chat …] context line only identifies the chat you are answering, the " +
19
+ "one chat this tool must not target in a chat turn. Pass exactly ONE of `text` (plain) or " +
20
+ "`markdown` (rendered as a card: headings, bold, code blocks, links).",
21
+ parameters: Type.Object({
22
+ chatId: Type.String({ description: "target chat id (oc_…)" }),
23
+ text: Type.Optional(Type.String({ description: "plain text message to send" })),
24
+ markdown: Type.Optional(Type.String({ description: "markdown to send as a card" })),
25
+ }),
26
+ execute: async ({ chatId, text, markdown }) => {
27
+ if ((text === undefined) === (markdown === undefined)) {
28
+ throw new Error("pass exactly one of `text` (plain) or `markdown` (a card)");
29
+ }
30
+ const api = larkTransport({ appId: secrets.LARK_APP_ID, appSecret: secrets.LARK_APP_SECRET });
31
+ if (text !== undefined) await api.sendText({ chatId }, text);
32
+ else {
33
+ await api.sendMessage(
34
+ chatId,
35
+ "interactive",
36
+ JSON.stringify({ schema: "2.0", body: { elements: [{ tag: "markdown", content: markdown }] } }),
37
+ );
38
+ }
39
+ return { output: [{ type: "text", text: `sent ${text !== undefined ? "message" : "card"} to chat ${chatId}` }] };
40
+ },
22
41
  }),
23
- async execute({ chatId, text, markdown }, ctx) {
24
- if ((text === undefined) === (markdown === undefined)) {
25
- throw new Error("pass exactly one of `text` (plain) or `markdown` (a card)");
26
- }
27
- const api = larkTransport(ctx.cwd);
28
- if (text !== undefined) await api.sendText({ chatId }, text);
29
- else {
30
- await api.sendMessage(chatId, "interactive", JSON.stringify({
31
- schema: "2.0",
32
- body: { elements: [{ tag: "markdown", content: markdown }] },
33
- }));
34
- }
35
- return `sent ${text !== undefined ? "message" : "card"} to chat ${chatId}`;
36
- },
37
- });
42
+ );
@@ -0,0 +1,25 @@
1
+ import { Type } from "@earendil-works/pi-ai";
2
+ import { defineTool } from "@earendil-works/pi-durable";
3
+ import { sessionIdOf } from "@fastagent-sh/fastagent";
4
+ import { larkThreads } from "@fastagent-sh/fastagent/lark";
5
+
6
+ // Reads the threads (topics) of the Lark group chat this message was asked in, and no other chat's:
7
+ // the channel names where the message runs, so the tool takes no chat id. It works in a group turn
8
+ // served by `fastagent dev`/`start`.
9
+ export default defineTool({
10
+ name: "lark_threads",
11
+ description:
12
+ "Read the threads (topics) of the Lark group chat you are answering in. Without `threadId`, list its recent " +
13
+ "threads, newest first, each with its id; with a `threadId` from that list, read that thread. Use " +
14
+ "it when a question here concerns something discussed in a thread, such as whether a problem raised there was " +
15
+ "resolved: the answer is often what a person wrote in the thread. Only this chat's threads can be read, and " +
16
+ "only in a group chat turn.",
17
+ parameters: Type.Object({
18
+ threadId: Type.Optional(Type.String({ description: "a thread id from the list (omt_…); omit it to list" })),
19
+ }),
20
+ execute: async ({ threadId }, api, context) => {
21
+ const threads = larkThreads(await sessionIdOf(api, context));
22
+ const text = threadId === undefined ? await threads.list() : await threads.read(threadId);
23
+ return { output: [{ type: "text", text }] };
24
+ },
25
+ });
@@ -1,5 +1 @@
1
- /** Shared `text/plain` reply for channels + the host (error/status responses). */
2
- export declare const textHeaders: {
3
- readonly "content-type": "text/plain";
4
- };
5
1
  export declare const text: (body: string, status: number) => Response;
@@ -1,3 +1,3 @@
1
1
  /** Shared `text/plain` reply for channels + the host (error/status responses). */
2
- export const textHeaders = { "content-type": "text/plain" };
2
+ const textHeaders = { "content-type": "text/plain" };
3
3
  export const text = (body, status) => new Response(body, { status, headers: textHeaders });
@@ -0,0 +1,18 @@
1
+ /**
2
+ * How a {@link Routes} table becomes one Fetch handler: the path rule and dispatch. Every route a serve answers
3
+ * verifies its own caller (a channel's platform signature, a host's IAM), or answers nothing worth guarding (the
4
+ * health check), so the router adds no guard of its own. Fetch-only, so any runtime can serve it; serve.ts binds it to
5
+ * node:http.
6
+ */
7
+ import type { ChannelHandler, Routes } from "../channel.ts";
8
+ /** Parse a route key: `"METHOD /path"` → `{ method, path }`, or `"/path"` → `{ path }` (any method). */
9
+ export declare function parseRouteKey(key: string): {
10
+ method?: string;
11
+ path: string;
12
+ };
13
+ /** A route key is `"METHOD /path"` or `"/path"`, with a literal path. */
14
+ export declare function assertRouteKey(key: string, describe: (problem: string) => string): void;
15
+ /** Do these two keys fight over the same request? */
16
+ export declare function routeKeysConflict(a: string, b: string): boolean;
17
+ /** One handler over `routes`: a literal path, its method or any, HEAD answered from GET, else 405 or 404. */
18
+ export declare function router(routes: Routes): ChannelHandler;
@@ -0,0 +1,68 @@
1
+ import { text } from "./respond.js";
2
+ /** Parse a route key: `"METHOD /path"` → `{ method, path }`, or `"/path"` → `{ path }` (any method). */
3
+ export function parseRouteKey(key) {
4
+ const sp = key.indexOf(" ");
5
+ return sp === -1 ? { path: key } : { method: key.slice(0, sp).toUpperCase(), path: key.slice(sp + 1) };
6
+ }
7
+ /** A route key is `"METHOD /path"` or `"/path"`, with a literal path. */
8
+ export function assertRouteKey(key, describe) {
9
+ const { method, path } = parseRouteKey(key);
10
+ if (method === "")
11
+ throw new Error(describe('a leading space is not a method — write "/path" for any method'));
12
+ if (!path.startsWith("/"))
13
+ throw new Error(describe('must start with "/"'));
14
+ // Asked of `URL` rather than by listing what it rewrites (`?`/`#`, `.`/`..`, `\`, `%2e`).
15
+ const arrives = new URL(path, "http://x").pathname;
16
+ if (arrives !== path) {
17
+ throw new Error(describe(`is not the path a request would carry — that request arrives as "${arrives}"`));
18
+ }
19
+ }
20
+ /** Do these two keys fight over the same request? */
21
+ export function routeKeysConflict(a, b) {
22
+ const ka = parseRouteKey(a);
23
+ const kb = parseRouteKey(b);
24
+ if (ka.path !== kb.path)
25
+ return false;
26
+ return ka.method === undefined || kb.method === undefined || ka.method === kb.method;
27
+ }
28
+ /** Same status and headers, no content (RFC 9110's HEAD). */
29
+ function withoutBody(res) {
30
+ void res.body?.cancel().catch(() => { });
31
+ return new Response(null, { status: res.status, statusText: res.statusText, headers: res.headers });
32
+ }
33
+ /** One handler over `routes`: a literal path, its method or any, HEAD answered from GET, else 405 or 404. */
34
+ export function router(routes) {
35
+ const byKey = new Map();
36
+ const paths = new Set();
37
+ for (const [key, handler] of Object.entries(routes)) {
38
+ assertRouteKey(key, (problem) => `route "${key}" is not a valid route key — ${problem}`);
39
+ const shadowed = [...byKey.keys()].find((other) => routeKeysConflict(other, key));
40
+ if (shadowed) {
41
+ throw new Error(`route "${key}" conflicts with "${shadowed}" — one of them would never receive a request`);
42
+ }
43
+ // Stored normalised: `parseRouteKey` upper-cases the method, so `"get /x"` validates under `GET` and would
44
+ // otherwise be looked up under a name nothing stores.
45
+ const { method, path } = parseRouteKey(key);
46
+ byKey.set(method ? `${method} ${path}` : path, handler);
47
+ paths.add(path);
48
+ }
49
+ return (req) => {
50
+ // `URL` normalises the path (`/a/../x` → `/x`) and drops query/fragment.
51
+ const path = new URL(req.url).pathname;
52
+ const answer = () => {
53
+ const exact = byKey.get(`${req.method} ${path}`) ?? byKey.get(path);
54
+ if (exact)
55
+ return exact(req);
56
+ if (req.method === "HEAD") {
57
+ const get = byKey.get(`GET ${path}`);
58
+ if (get)
59
+ return get(req);
60
+ }
61
+ return paths.has(path) ? text("method not allowed\n", 405) : text("not found\n", 404);
62
+ };
63
+ if (req.method !== "HEAD")
64
+ return answer();
65
+ const res = answer();
66
+ return res instanceof Promise ? res.then(withoutBody) : withoutBody(res);
67
+ };
68
+ }
@@ -1,76 +1,11 @@
1
- import type { IncomingMessage, ServerResponse } from "node:http";
2
- import type { ChannelHandler, Routes } from "../channel.ts";
3
- /** Parse a route key: `"METHOD /path"` → `{ method, path }`, or `"/path"` → `{ path }` (any method). */
4
- export declare function parseRouteKey(key: string): {
5
- method?: string;
6
- path: string;
7
- };
8
- /** A route key is `"METHOD /path"` or `"/path"`, with a literal path. */
9
- export declare function assertRouteKey(key: string, describe: (problem: string) => string): void;
10
- /** Do these two keys fight over the same request? */
11
- export declare function routeKeysConflict(a: string, b: string): boolean;
12
- /** A handler owning a path prefix and everything beneath it — the session control plane is the one user. */
13
- export interface PrefixMount {
14
- /** Absolute, no trailing slash, and not `/` (`/control`). */
15
- prefix: string;
16
- handler: ChannelHandler;
17
- }
18
- /** Same status and headers, no content (RFC 9110's HEAD). */
19
- export declare function withoutBody(res: Response): Response;
20
- export declare function pathUnderPrefix(path: string, prefix: string): boolean;
21
- /**
22
- * Refuse a cross-origin allow-list that cannot match anything.
23
- *
24
- * ONE check for BOTH ways in: `http.cors` in a config file, and `corsOrigins` handed to `mountAgentService` by an
25
- * embedder. `allowedOrigin` compares exact strings, so `"https://app.example.com/"` — one trailing slash — never
26
- * matches and the front end is refused with nothing pointing at the rule. A rule that silently matches nothing is
27
- * worse than one that refuses to load.
28
- */
29
- export declare function assertCorsOrigins(origins: unknown, where: string): asserts origins is string[];
30
- /**
31
- * The tables a router composes, NAMED rather than ordered.
32
- *
33
- * Two same-typed positional arguments encoded which side of the trust axis a table was on, and getting them the
34
- * wrong way round type-checked: the AgentCore adapter passed its IAM-gated routes as `unverified` and they were
35
- * reported as unauthenticated for two commits. A caller now spells the axis at the call site.
36
- */
37
- export interface RouterSurface {
38
- /** Routes that authenticate NOBODY — the router applies the JSON body gate and the cross-origin policy to them. */
39
- unverified?: Routes;
40
- /** Routes that verify their own caller (a channel's platform signature, a host's IAM). Neither guard applies. */
41
- selfVerifying?: Routes;
42
- /** Prefix-owning handlers. Always treated as unverified — the control plane is the only one. */
43
- mounts?: readonly PrefixMount[];
44
- /** `http.cors` — exact origins, or `["*"]`. Set, it REPLACES the `*` default; unset, the default stands. */
45
- corsOrigins?: readonly string[];
46
- }
47
- /**
48
- * Compose the routes that AUTHENTICATE NOBODY, the self-verifying channel routes, and the {@link PrefixMount}s
49
- * into one handler.
50
- *
51
- * That is the axis, not authorship. Two things follow from it and nothing else does: whether a browser may drive
52
- * the route, and whether its body must declare JSON. A channel route is exempt from both because it checks its
53
- * platform's signature inside itself — a Telegram webhook is public on purpose. Ours check nothing, so the router
54
- * checks for them.
55
- *
56
- * TWO TABLES, not one table plus a list of which keys are which, so the three readers (browser reachability, the JSON
57
- * body gate, the startup report) cannot answer differently.
58
- *
59
- * CAVEAT, stated because we cannot enforce it: a CUSTOM channel that verifies nothing lands in `selfVerifying`
60
- * anyway and gets neither guard. That is decision B (docs/design/session-control.md §14) and it belongs to the
61
- * channel's author, who owns the credential the platform issued — but it is an assumption here, not a property.
62
- */
63
- export declare function router(surface: RouterSurface): ChannelHandler;
64
- /**
65
- * The node:http adapter for a Fetch handler — the embedded server uses it, and an embedder mounting fastagent on its
66
- * OWN node:http server can too.
67
- */
68
- export declare function nodeListener(handler: ChannelHandler): (req: IncomingMessage, res: ServerResponse) => void;
69
- export declare function serveNode(handler: ChannelHandler, options: {
1
+ import type { ChannelHandler } from "../channel.ts";
2
+ /** The totality boundary every serving path shares; `prepare` shapes the handler's response inside it. */
3
+ export declare function totalFetch(handler: ChannelHandler, prepare?: (response: Response) => Response): (req: Request) => Promise<Response>;
4
+ /** Serve `handler` on this runtime's own server: Node's `http.Server`, or `Bun.serve`. */
5
+ export declare function serveHandler(handler: ChannelHandler, options: {
70
6
  port: number;
71
7
  host?: string;
72
8
  }): {
73
9
  listening: Promise<number>;
74
10
  close: () => Promise<void>;
75
- closeAllConnections: () => void;
76
11
  };