@fastagent-sh/fastagent 0.24.3 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/README.md +53 -82
  2. package/dist/agent-api.d.ts +452 -0
  3. package/dist/agent-api.js +201 -0
  4. package/dist/answer-text.d.ts +8 -0
  5. package/dist/answer-text.js +18 -0
  6. package/dist/atomic-write.d.ts +2 -2
  7. package/dist/atomic-write.js +2 -2
  8. package/dist/authoring.d.ts +77 -0
  9. package/dist/authoring.js +238 -0
  10. package/dist/channel.d.ts +29 -15
  11. package/dist/channel.js +4 -1
  12. package/dist/channels/agentcore-protocol.d.ts +36 -50
  13. package/dist/channels/agentcore-protocol.js +3 -3
  14. package/dist/channels/agentcore-service.d.ts +8 -18
  15. package/dist/channels/agentcore-service.js +108 -127
  16. package/dist/channels/agentcore.d.ts +8 -24
  17. package/dist/channels/agentcore.js +32 -65
  18. package/dist/channels/body.d.ts +0 -16
  19. package/dist/channels/body.js +0 -25
  20. package/dist/channels/busy.js +6 -1
  21. package/dist/channels/context.d.ts +4 -0
  22. package/dist/channels/context.js +35 -0
  23. package/dist/channels/discover.d.ts +18 -20
  24. package/dist/channels/discover.js +41 -99
  25. package/dist/channels/feishu/feishu-api.d.ts +54 -4
  26. package/dist/channels/feishu/feishu-api.js +192 -149
  27. package/dist/channels/feishu/feishu.d.ts +3 -0
  28. package/dist/channels/feishu/feishu.js +117 -106
  29. package/dist/channels/feishu/history.d.ts +55 -0
  30. package/dist/channels/feishu/history.js +199 -0
  31. package/dist/channels/feishu/invoke-turn.d.ts +13 -11
  32. package/dist/channels/feishu/invoke-turn.js +9 -10
  33. package/dist/channels/feishu/model.d.ts +2 -1
  34. package/dist/channels/feishu/normalize.js +100 -0
  35. package/dist/channels/feishu/preview.d.ts +2 -2
  36. package/dist/channels/feishu/register-webhook.d.ts +1 -0
  37. package/dist/channels/feishu/register-webhook.js +3 -2
  38. package/dist/channels/feishu/scaffold/channel.ts +65 -46
  39. package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
  40. package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
  41. package/dist/channels/feishu/setup-mode.d.ts +45 -25
  42. package/dist/channels/feishu/setup-mode.js +74 -23
  43. package/dist/channels/feishu/shared-api.d.ts +24 -6
  44. package/dist/channels/feishu/shared-api.js +30 -24
  45. package/dist/channels/kit/context-buffer.d.ts +11 -2
  46. package/dist/channels/kit/context-buffer.js +7 -4
  47. package/dist/channels/kit/delivery.d.ts +19 -3
  48. package/dist/channels/kit/delivery.js +74 -15
  49. package/dist/channels/kit/event-stream.js +2 -1
  50. package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
  51. package/dist/channels/kit/invoke-turn-kit.js +62 -71
  52. package/dist/channels/kit/place-history.d.ts +107 -0
  53. package/dist/channels/kit/place-history.js +182 -0
  54. package/dist/channels/kit/preview-kit.d.ts +9 -5
  55. package/dist/channels/kit/preview-kit.js +36 -15
  56. package/dist/channels/kit/room-threads.d.ts +46 -0
  57. package/dist/channels/kit/room-threads.js +81 -0
  58. package/dist/channels/kit/seen.js +1 -1
  59. package/dist/channels/kit/stop-command.d.ts +6 -3
  60. package/dist/channels/kit/stop-command.js +20 -18
  61. package/dist/channels/kit/thread-fork.d.ts +17 -0
  62. package/dist/channels/kit/thread-fork.js +43 -0
  63. package/dist/channels/kit/thread-participants.js +1 -1
  64. package/dist/channels/kit/transport.d.ts +5 -0
  65. package/dist/channels/kit/transport.js +5 -0
  66. package/dist/channels/kit/turn-runner.d.ts +10 -9
  67. package/dist/channels/kit/turn-runner.js +17 -19
  68. package/dist/channels/kit/turn-store.d.ts +5 -4
  69. package/dist/channels/kit/turn-store.js +5 -5
  70. package/dist/channels/lark/lark.d.ts +3 -0
  71. package/dist/channels/lark/lark.js +5 -0
  72. package/dist/channels/lark/onboard.d.ts +5 -3
  73. package/dist/channels/lark/onboard.js +14 -14
  74. package/dist/channels/lark/scaffold/channel.ts +67 -44
  75. package/dist/channels/lark/scaffold/lark-send.ts +38 -33
  76. package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
  77. package/dist/channels/respond.d.ts +0 -4
  78. package/dist/channels/respond.js +1 -1
  79. package/dist/channels/router.d.ts +18 -0
  80. package/dist/channels/router.js +68 -0
  81. package/dist/channels/serve.d.ts +5 -70
  82. package/dist/channels/serve.js +105 -287
  83. package/dist/channels/slack/history.d.ts +42 -0
  84. package/dist/channels/slack/history.js +282 -0
  85. package/dist/channels/slack/invoke-turn.d.ts +12 -5
  86. package/dist/channels/slack/invoke-turn.js +7 -5
  87. package/dist/channels/slack/manifest.d.ts +1 -4
  88. package/dist/channels/slack/manifest.js +22 -10
  89. package/dist/channels/slack/model.d.ts +2 -1
  90. package/dist/channels/slack/onboard.d.ts +0 -2
  91. package/dist/channels/slack/onboard.js +2 -4
  92. package/dist/channels/slack/onboarding-state.d.ts +0 -2
  93. package/dist/channels/slack/onboarding-state.js +0 -1
  94. package/dist/channels/slack/parse.d.ts +0 -5
  95. package/dist/channels/slack/parse.js +1 -16
  96. package/dist/channels/slack/preview.d.ts +2 -3
  97. package/dist/channels/slack/preview.js +78 -52
  98. package/dist/channels/slack/register-webhook.d.ts +1 -0
  99. package/dist/channels/slack/register-webhook.js +6 -5
  100. package/dist/channels/slack/scaffold/channel.ts +23 -24
  101. package/dist/channels/slack/scaffold/slack-send.ts +50 -43
  102. package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
  103. package/dist/channels/slack/setup-server.d.ts +19 -0
  104. package/dist/channels/slack/setup-server.js +113 -11
  105. package/dist/channels/slack/shared-api.d.ts +15 -4
  106. package/dist/channels/slack/shared-api.js +19 -14
  107. package/dist/channels/slack/slack-api.d.ts +61 -2
  108. package/dist/channels/slack/slack-api.js +28 -5
  109. package/dist/channels/slack/slack.js +97 -52
  110. package/dist/channels/slack/welcomed.js +1 -1
  111. package/dist/channels/telegram/context-buffer.d.ts +6 -1
  112. package/dist/channels/telegram/context-buffer.js +19 -0
  113. package/dist/channels/telegram/invoke-turn.d.ts +8 -4
  114. package/dist/channels/telegram/invoke-turn.js +7 -7
  115. package/dist/channels/telegram/parse.d.ts +7 -2
  116. package/dist/channels/telegram/parse.js +7 -0
  117. package/dist/channels/telegram/preview.d.ts +2 -2
  118. package/dist/channels/telegram/register-webhook.d.ts +1 -0
  119. package/dist/channels/telegram/register-webhook.js +3 -2
  120. package/dist/channels/telegram/scaffold/channel.ts +27 -28
  121. package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
  122. package/dist/channels/telegram/shared-api.d.ts +34 -0
  123. package/dist/channels/telegram/shared-api.js +79 -0
  124. package/dist/channels/telegram/telegram-api.d.ts +15 -5
  125. package/dist/channels/telegram/telegram-api.js +10 -6
  126. package/dist/channels/telegram/telegram.js +27 -21
  127. package/dist/channels/telegram/turn-store.js +1 -1
  128. package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
  129. package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
  130. package/dist/cli/add-feishu.d.ts +42 -12
  131. package/dist/cli/add-feishu.js +177 -124
  132. package/dist/cli/add-slack.d.ts +8 -3
  133. package/dist/cli/add-slack.js +115 -63
  134. package/dist/cli/auth-view.d.ts +10 -3
  135. package/dist/cli/auth-view.js +8 -6
  136. package/dist/cli/box-login.d.ts +17 -7
  137. package/dist/cli/box-login.js +46 -12
  138. package/dist/cli/commands/add.d.ts +15 -4
  139. package/dist/cli/commands/add.js +252 -143
  140. package/dist/cli/commands/auth.d.ts +6 -0
  141. package/dist/cli/commands/auth.js +50 -0
  142. package/dist/cli/commands/content.d.ts +6 -0
  143. package/dist/cli/commands/content.js +45 -0
  144. package/dist/cli/commands/deploy/agentcore.js +50 -77
  145. package/dist/cli/commands/deploy/docker.js +38 -39
  146. package/dist/cli/commands/deploy/fly.js +21 -18
  147. package/dist/cli/commands/deploy/host-login.d.ts +26 -0
  148. package/dist/cli/commands/deploy/host-login.js +90 -0
  149. package/dist/cli/commands/deploy/railway.js +21 -26
  150. package/dist/cli/commands/deploy/shared.d.ts +45 -17
  151. package/dist/cli/commands/deploy/shared.js +34 -15
  152. package/dist/cli/commands/deploy.d.ts +0 -4
  153. package/dist/cli/commands/deploy.js +237 -50
  154. package/dist/cli/commands/destroy.js +8 -6
  155. package/dist/cli/commands/dev.d.ts +0 -2
  156. package/dist/cli/commands/dev.js +20 -19
  157. package/dist/cli/commands/env.d.ts +12 -0
  158. package/dist/cli/commands/env.js +190 -0
  159. package/dist/cli/commands/info.js +95 -156
  160. package/dist/cli/commands/init.d.ts +2 -2
  161. package/dist/cli/commands/init.js +35 -33
  162. package/dist/cli/commands/invoke.d.ts +6 -0
  163. package/dist/cli/commands/invoke.js +131 -16
  164. package/dist/cli/commands/login.d.ts +31 -2
  165. package/dist/cli/commands/login.js +413 -64
  166. package/dist/cli/commands/logout.d.ts +4 -0
  167. package/dist/cli/commands/logout.js +53 -0
  168. package/dist/cli/commands/logs.js +8 -6
  169. package/dist/cli/commands/models.d.ts +2 -1
  170. package/dist/cli/commands/models.js +39 -37
  171. package/dist/cli/commands/schedules.d.ts +21 -0
  172. package/dist/cli/commands/schedules.js +143 -0
  173. package/dist/cli/commands/start.d.ts +11 -10
  174. package/dist/cli/commands/start.js +35 -62
  175. package/dist/cli/content-view.d.ts +9 -0
  176. package/dist/cli/content-view.js +26 -0
  177. package/dist/cli/fail.d.ts +9 -12
  178. package/dist/cli/fail.js +17 -14
  179. package/dist/cli/invoke-stream.d.ts +12 -3
  180. package/dist/cli/invoke-stream.js +85 -23
  181. package/dist/cli/kernel.d.ts +9 -2
  182. package/dist/cli/kernel.js +15 -6
  183. package/dist/cli/login-relay.d.ts +3 -2
  184. package/dist/cli/login-relay.js +18 -6
  185. package/dist/cli/models-view.d.ts +5 -1
  186. package/dist/cli/models-view.js +1 -1
  187. package/dist/cli/person.d.ts +10 -0
  188. package/dist/cli/person.js +23 -0
  189. package/dist/cli/program.js +421 -203
  190. package/dist/cli/serve.d.ts +13 -63
  191. package/dist/cli/serve.js +31 -121
  192. package/dist/cli/shared.d.ts +21 -48
  193. package/dist/cli/shared.js +68 -89
  194. package/dist/cli/ticket.d.ts +136 -0
  195. package/dist/cli/ticket.js +476 -0
  196. package/dist/client.d.ts +7 -0
  197. package/dist/client.js +2 -0
  198. package/dist/content/declare.d.ts +70 -0
  199. package/dist/content/declare.js +163 -0
  200. package/dist/content/file.d.ts +32 -0
  201. package/dist/content/file.js +119 -0
  202. package/dist/content/git.d.ts +41 -0
  203. package/dist/content/git.js +217 -0
  204. package/dist/content/mount.d.ts +2 -0
  205. package/dist/content/mount.js +15 -0
  206. package/dist/content/resolve.d.ts +52 -0
  207. package/dist/content/resolve.js +151 -0
  208. package/dist/content/source.d.ts +27 -0
  209. package/dist/content/source.js +53 -0
  210. package/dist/conversation-sessions.d.ts +26 -0
  211. package/dist/conversation-sessions.js +99 -0
  212. package/dist/declared-secrets.d.ts +19 -37
  213. package/dist/declared-secrets.js +16 -58
  214. package/dist/deploy/agentcore/destroy.d.ts +3 -3
  215. package/dist/deploy/agentcore/destroy.js +46 -28
  216. package/dist/deploy/agentcore/forwarder.js +105 -22
  217. package/dist/deploy/agentcore/logs.js +1 -1
  218. package/dist/deploy/agentcore/plan.d.ts +10 -24
  219. package/dist/deploy/agentcore/plan.js +31 -135
  220. package/dist/deploy/agentcore/run.d.ts +1 -1
  221. package/dist/deploy/agentcore/run.js +8 -5
  222. package/dist/deploy/agentcore/shell.d.ts +1 -1
  223. package/dist/deploy/agentcore/shell.js +5 -5
  224. package/dist/deploy/api.d.ts +34 -0
  225. package/dist/deploy/api.js +50 -0
  226. package/dist/deploy/box-shell.d.ts +6 -0
  227. package/dist/deploy/box-shell.js +7 -0
  228. package/dist/deploy/build-context.d.ts +7 -5
  229. package/dist/deploy/build-context.js +41 -35
  230. package/dist/deploy/channel-ingress.d.ts +6 -1
  231. package/dist/deploy/channel-ingress.js +18 -5
  232. package/dist/deploy/container.d.ts +22 -9
  233. package/dist/deploy/container.js +96 -55
  234. package/dist/deploy/docker/plan.d.ts +3 -2
  235. package/dist/deploy/docker/plan.js +13 -14
  236. package/dist/deploy/docker/run.d.ts +2 -2
  237. package/dist/deploy/docker/run.js +8 -4
  238. package/dist/deploy/fly/plan.d.ts +1 -1
  239. package/dist/deploy/fly/plan.js +12 -21
  240. package/dist/deploy/fly/run.d.ts +10 -6
  241. package/dist/deploy/fly/run.js +11 -6
  242. package/dist/deploy/hosts.d.ts +2 -1
  243. package/dist/deploy/hosts.js +2 -1
  244. package/dist/deploy/preflight.d.ts +21 -23
  245. package/dist/deploy/preflight.js +222 -201
  246. package/dist/deploy/railway/plan.d.ts +8 -6
  247. package/dist/deploy/railway/plan.js +15 -58
  248. package/dist/deploy/railway/run.d.ts +8 -3
  249. package/dist/deploy/railway/run.js +12 -8
  250. package/dist/deploy/residency.d.ts +5 -11
  251. package/dist/deploy/residency.js +0 -6
  252. package/dist/deploy/runner.d.ts +1 -1
  253. package/dist/deploy/runner.js +1 -1
  254. package/dist/deploy/secrets.d.ts +16 -2
  255. package/dist/deploy/secrets.js +33 -6
  256. package/dist/deploy/workspace.d.ts +11 -6
  257. package/dist/deploy/workspace.js +55 -38
  258. package/dist/dev-supervisor.d.ts +11 -2
  259. package/dist/dev-supervisor.js +51 -26
  260. package/dist/effect-port.d.ts +4 -4
  261. package/dist/effect-port.js +4 -4
  262. package/dist/environment/apt.d.ts +4 -0
  263. package/dist/environment/apt.js +32 -0
  264. package/dist/environment/declare.d.ts +59 -0
  265. package/dist/environment/declare.js +210 -0
  266. package/dist/environment/mise.d.ts +50 -0
  267. package/dist/environment/mise.js +268 -0
  268. package/dist/feishu.d.ts +2 -2
  269. package/dist/feishu.js +2 -2
  270. package/dist/git.d.ts +13 -0
  271. package/dist/git.js +55 -0
  272. package/dist/harnesses/models/catalog.d.ts +20 -0
  273. package/dist/harnesses/models/catalog.js +254 -0
  274. package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
  275. package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
  276. package/dist/harnesses/models/environment.d.ts +43 -0
  277. package/dist/harnesses/models/environment.js +82 -0
  278. package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
  279. package/dist/{engines/pi → harnesses/models}/login.js +187 -79
  280. package/dist/harnesses/models/models.d.ts +83 -0
  281. package/dist/harnesses/models/models.js +158 -0
  282. package/dist/harnesses/pi-durable/agent.d.ts +42 -0
  283. package/dist/harnesses/pi-durable/agent.js +579 -0
  284. package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
  285. package/dist/harnesses/pi-durable/defaults.js +26 -0
  286. package/dist/harnesses/pi-durable/define.d.ts +77 -0
  287. package/dist/harnesses/pi-durable/define.js +28 -0
  288. package/dist/harnesses/pi-durable/entries.d.ts +32 -0
  289. package/dist/harnesses/pi-durable/entries.js +126 -0
  290. package/dist/harnesses/pi-durable/events.d.ts +25 -0
  291. package/dist/harnesses/pi-durable/events.js +238 -0
  292. package/dist/harnesses/pi-durable/ids.d.ts +16 -0
  293. package/dist/harnesses/pi-durable/ids.js +55 -0
  294. package/dist/harnesses/pi-durable/messages.d.ts +41 -0
  295. package/dist/harnesses/pi-durable/messages.js +116 -0
  296. package/dist/harnesses/pi-durable/open.d.ts +88 -0
  297. package/dist/harnesses/pi-durable/open.js +329 -0
  298. package/dist/harnesses/pi-durable/reads.d.ts +30 -0
  299. package/dist/harnesses/pi-durable/reads.js +94 -0
  300. package/dist/harnesses/pi-durable/registry.d.ts +18 -0
  301. package/dist/harnesses/pi-durable/registry.js +56 -0
  302. package/dist/harnesses/pi-durable/release.d.ts +13 -0
  303. package/dist/harnesses/pi-durable/release.js +40 -0
  304. package/dist/harnesses/pi-durable/serve.d.ts +80 -0
  305. package/dist/harnesses/pi-durable/serve.js +156 -0
  306. package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
  307. package/dist/harnesses/pi-durable/sessions.js +47 -0
  308. package/dist/harnesses/pi-durable/storage.d.ts +4 -0
  309. package/dist/harnesses/pi-durable/storage.js +49 -0
  310. package/dist/harnesses/pi-durable/stream.d.ts +20 -0
  311. package/dist/harnesses/pi-durable/stream.js +221 -0
  312. package/dist/harnesses/pi-durable/text.d.ts +30 -0
  313. package/dist/harnesses/pi-durable/text.js +292 -0
  314. package/dist/harnesses/pi-durable/wake.d.ts +4 -0
  315. package/dist/harnesses/pi-durable/wake.js +81 -0
  316. package/dist/http/client.d.ts +6 -0
  317. package/dist/http/client.js +256 -0
  318. package/dist/http/contract.d.ts +541 -0
  319. package/dist/http/contract.js +179 -0
  320. package/dist/http/server.d.ts +34 -0
  321. package/dist/http/server.js +194 -0
  322. package/dist/index.d.ts +17 -4
  323. package/dist/index.js +10 -5
  324. package/dist/lark.d.ts +2 -2
  325. package/dist/lark.js +2 -2
  326. package/dist/locked-file.d.ts +17 -0
  327. package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
  328. package/dist/once.d.ts +6 -0
  329. package/dist/once.js +23 -0
  330. package/dist/paths.d.ts +36 -52
  331. package/dist/paths.js +66 -182
  332. package/dist/runtime.d.ts +25 -2
  333. package/dist/runtime.js +27 -0
  334. package/dist/scaffold/add-channel.d.ts +14 -27
  335. package/dist/scaffold/add-channel.js +82 -180
  336. package/dist/scaffold/init.d.ts +17 -18
  337. package/dist/scaffold/init.js +87 -99
  338. package/dist/scaffold/templates/SYSTEM.md +12 -0
  339. package/dist/scaffold/templates/env.example +4 -10
  340. package/dist/scaffold/templates/fastagent.config.ts +21 -33
  341. package/dist/scaffold/templates/gitignore +8 -1
  342. package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
  343. package/dist/scaffold/templates.d.ts +9 -4
  344. package/dist/scaffold/templates.js +7 -5
  345. package/dist/scaffold/vendor-skill.d.ts +1 -4
  346. package/dist/scaffold/vendor-skill.js +5 -6
  347. package/dist/schedule/cron.d.ts +13 -0
  348. package/dist/schedule/cron.js +52 -0
  349. package/dist/schedule/eventbridge-cron.d.ts +17 -0
  350. package/dist/schedule/eventbridge-cron.js +88 -0
  351. package/dist/schedule/schedule.d.ts +23 -0
  352. package/dist/schedule/schedule.js +34 -0
  353. package/dist/schedule/scheduler.d.ts +34 -33
  354. package/dist/schedule/scheduler.js +251 -137
  355. package/dist/schedule/state.d.ts +4 -14
  356. package/dist/schedule/state.js +7 -7
  357. package/dist/schedule/wake-alarm.d.ts +22 -2
  358. package/dist/schedule/wake-alarm.js +66 -20
  359. package/dist/schedule/wakeups.d.ts +16 -15
  360. package/dist/schedule/wakeups.js +47 -45
  361. package/dist/service.d.ts +56 -169
  362. package/dist/service.js +91 -187
  363. package/dist/serving-command.d.ts +10 -0
  364. package/dist/serving-command.js +16 -0
  365. package/dist/slack.d.ts +1 -1
  366. package/dist/slack.js +1 -1
  367. package/dist/{channels/kit/state.js → state-file.js} +6 -6
  368. package/dist/telegram.d.ts +1 -0
  369. package/dist/telegram.js +1 -0
  370. package/dist/tunnel.d.ts +3 -0
  371. package/dist/tunnel.js +12 -4
  372. package/dist/value-file.d.ts +21 -0
  373. package/dist/value-file.js +108 -0
  374. package/dist/version.d.ts +5 -0
  375. package/dist/version.js +14 -1
  376. package/package.json +18 -28
  377. package/dist/agent.d.ts +0 -106
  378. package/dist/agent.js +0 -21
  379. package/dist/channels/control.d.ts +0 -31
  380. package/dist/channels/control.js +0 -329
  381. package/dist/channels/define-channel.d.ts +0 -39
  382. package/dist/channels/define-channel.js +0 -9
  383. package/dist/channels/feishu/context-buffer.d.ts +0 -35
  384. package/dist/channels/feishu/context-buffer.js +0 -65
  385. package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
  386. package/dist/channels/http.d.ts +0 -23
  387. package/dist/channels/http.js +0 -57
  388. package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
  389. package/dist/channels/slack/context-buffer.d.ts +0 -23
  390. package/dist/channels/slack/context-buffer.js +0 -37
  391. package/dist/channels/sse.d.ts +0 -4
  392. package/dist/channels/sse.js +0 -66
  393. package/dist/cli/commands/chat.d.ts +0 -3
  394. package/dist/cli/commands/chat.js +0 -14
  395. package/dist/cli/commands/routine-run.d.ts +0 -6
  396. package/dist/cli/commands/routine-run.js +0 -46
  397. package/dist/cli/commands/routine.d.ts +0 -25
  398. package/dist/cli/commands/routine.js +0 -122
  399. package/dist/cli/commands/tool.d.ts +0 -1
  400. package/dist/cli/commands/tool.js +0 -57
  401. package/dist/collect.d.ts +0 -63
  402. package/dist/collect.js +0 -90
  403. package/dist/core.d.ts +0 -13
  404. package/dist/core.js +0 -15
  405. package/dist/engines/pi/agent-models.d.ts +0 -83
  406. package/dist/engines/pi/agent-models.js +0 -120
  407. package/dist/engines/pi/agent-session-factory.d.ts +0 -121
  408. package/dist/engines/pi/agent-session-factory.js +0 -517
  409. package/dist/engines/pi/chat.d.ts +0 -3
  410. package/dist/engines/pi/chat.js +0 -8
  411. package/dist/engines/pi/config.d.ts +0 -71
  412. package/dist/engines/pi/config.js +0 -199
  413. package/dist/engines/pi/create.d.ts +0 -170
  414. package/dist/engines/pi/create.js +0 -343
  415. package/dist/engines/pi/definition.d.ts +0 -74
  416. package/dist/engines/pi/definition.js +0 -236
  417. package/dist/engines/pi/entry-images.d.ts +0 -14
  418. package/dist/engines/pi/entry-images.js +0 -23
  419. package/dist/engines/pi/invoke-session.d.ts +0 -18
  420. package/dist/engines/pi/invoke-session.js +0 -403
  421. package/dist/engines/pi/locked-file.d.ts +0 -9
  422. package/dist/engines/pi/machine.d.ts +0 -53
  423. package/dist/engines/pi/machine.js +0 -137
  424. package/dist/engines/pi/models.d.ts +0 -200
  425. package/dist/engines/pi/models.js +0 -533
  426. package/dist/engines/pi/open.d.ts +0 -180
  427. package/dist/engines/pi/open.js +0 -270
  428. package/dist/engines/pi/openai-account-models.d.ts +0 -35
  429. package/dist/engines/pi/openai-account-models.js +0 -116
  430. package/dist/engines/pi/report.d.ts +0 -18
  431. package/dist/engines/pi/report.js +0 -59
  432. package/dist/engines/pi/retry-event.d.ts +0 -6
  433. package/dist/engines/pi/retry-event.js +0 -15
  434. package/dist/engines/pi/service.d.ts +0 -9
  435. package/dist/engines/pi/service.js +0 -14
  436. package/dist/engines/pi/session-builder.d.ts +0 -13
  437. package/dist/engines/pi/session-builder.js +0 -117
  438. package/dist/engines/pi/session-control.d.ts +0 -77
  439. package/dist/engines/pi/session-control.js +0 -908
  440. package/dist/engines/pi/session-effects.d.ts +0 -14
  441. package/dist/engines/pi/session-effects.js +0 -30
  442. package/dist/engines/pi/session-inheritance.d.ts +0 -21
  443. package/dist/engines/pi/session-inheritance.js +0 -204
  444. package/dist/engines/pi/session-markers.d.ts +0 -49
  445. package/dist/engines/pi/session-markers.js +0 -60
  446. package/dist/engines/pi/session-settings.d.ts +0 -67
  447. package/dist/engines/pi/session-settings.js +0 -119
  448. package/dist/engines/pi/session-store.d.ts +0 -69
  449. package/dist/engines/pi/session-store.js +0 -430
  450. package/dist/engines/pi/tool-context.d.ts +0 -45
  451. package/dist/engines/pi/tool-context.js +0 -31
  452. package/dist/engines/pi/tool.d.ts +0 -99
  453. package/dist/engines/pi/tool.js +0 -118
  454. package/dist/engines/pi/turn-kit.d.ts +0 -83
  455. package/dist/engines/pi/turn-kit.js +0 -275
  456. package/dist/engines/pi/wake-tool.d.ts +0 -9
  457. package/dist/engines/pi/wake-tool.js +0 -92
  458. package/dist/loader.d.ts +0 -41
  459. package/dist/loader.js +0 -116
  460. package/dist/node.d.ts +0 -3
  461. package/dist/node.js +0 -4
  462. package/dist/observe.d.ts +0 -6
  463. package/dist/observe.js +0 -47
  464. package/dist/pi.d.ts +0 -25
  465. package/dist/pi.js +0 -15
  466. package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
  467. package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
  468. package/dist/schedule/discover.d.ts +0 -17
  469. package/dist/schedule/discover.js +0 -61
  470. package/dist/schedule/routine.d.ts +0 -43
  471. package/dist/schedule/routine.js +0 -32
  472. package/dist/schedule/run.d.ts +0 -55
  473. package/dist/schedule/run.js +0 -146
  474. package/dist/secrets-gate.d.ts +0 -32
  475. package/dist/secrets-gate.js +0 -33
  476. package/dist/session-remote.d.ts +0 -47
  477. package/dist/session-remote.js +0 -460
  478. package/dist/session.d.ts +0 -466
  479. package/dist/session.js +0 -57
  480. /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
@@ -0,0 +1,282 @@
1
+ /**
2
+ * A Slack place's history, read when a turn runs (docs/design/place-history.md): a channel's top level from
3
+ * `conversations.history`, a thread from `conversations.replies`. What a place remembers between turns, and what a
4
+ * read leaves out, is the kit's (`createPlaceHistory`). A message's `ts` is its id and its position at once: the
5
+ * turn's ask is the read's exclusive `latest`, and the next read's cursor. Each read lists the newest page before the
6
+ * ask and stops at the cursor itself, as Feishu's does: Slack has no reliable "after this point" (`SlackRange`).
7
+ */
8
+ import { capBufferedRefs } from "../kit/context-buffer.js";
9
+ import { createPlaceHistory, } from "../kit/place-history.js";
10
+ import { threadList } from "../kit/room-threads.js";
11
+ import { CONTEXT_READ } from "../kit/transport.js";
12
+ import { slackMessageText } from "./parse.js";
13
+ import { log } from "../../log.js";
14
+ import { SlackApiError } from "./slack-api.js";
15
+ /** How many of a place's newest messages one read keeps; a place busier than this since its last answer says so. */
16
+ const PAGE_SIZE = 50;
17
+ /** What a place's first answered turn reads back, with no cursor yet. */
18
+ const FIRST_READ = 20;
19
+ /** Message subtypes that are someone saying something; every other subtype is the platform's (a join, a topic). */
20
+ const SPOKEN_SUBTYPES = new Set(["file_share", "thread_broadcast", "bot_message", "me_message"]);
21
+ /** How long a person's name is reused before it is looked up again. */
22
+ const NAMES_TTL_MS = 10 * 60_000;
23
+ /** How many of a channel's newest messages a thread list looks through. */
24
+ const THREAD_SCAN = 100;
25
+ /** A place: a channel's top level, or a thread in it. The turn record carries it as this key. */
26
+ export function slackHistoryKey(teamId, place) {
27
+ const base = `${teamId}:${place.channelId}`;
28
+ return place.threadTs ? `${base}:root:${place.threadTs}` : base;
29
+ }
30
+ /** The inverse of {@link slackHistoryKey}. Slack ids and timestamps never contain a colon. */
31
+ export function slackPlaceOf(key) {
32
+ const [teamId = "", channelId = "", , threadTs] = key.split(":");
33
+ return { teamId, channelId, ...(threadTs ? { threadTs } : {}) };
34
+ }
35
+ /**
36
+ * Order two Slack timestamps (`seconds.micros`). A double tells microseconds apart until 2^33 seconds (the year 2242),
37
+ * so plain numbers compare them exactly.
38
+ */
39
+ const compareSlackTs = (a, b) => Number(a) - Number(b);
40
+ /** Select the most recent background files of the folded messages, excluding the turn's own. */
41
+ export function collectFoldedFiles(folded, primaryIds) {
42
+ const seen = new Set(primaryIds);
43
+ const files = [];
44
+ for (const message of folded) {
45
+ for (const file of message.files) {
46
+ if (seen.has(file.key))
47
+ continue;
48
+ seen.add(file.key);
49
+ files.push({ id: file.key, from: message.from.label, messageId: message.id });
50
+ }
51
+ }
52
+ const capped = capBufferedRefs(files);
53
+ return { files: capped.kept, skipped: capped.skipped };
54
+ }
55
+ const str = (value) => (typeof value === "string" ? value : undefined);
56
+ const list = (value) => Array.isArray(value)
57
+ ? value.filter((item) => typeof item === "object" && item !== null)
58
+ : [];
59
+ const textOf = (value) => str(value?.text);
60
+ /** One run of `rich_text`, as the person wrote it. */
61
+ function inline(element) {
62
+ switch (element.type) {
63
+ case "text":
64
+ return str(element.text);
65
+ case "link":
66
+ return str(element.text) ?? str(element.url);
67
+ case "user":
68
+ return `<@${str(element.user_id)}>`;
69
+ case "usergroup":
70
+ return `<!subteam^${str(element.usergroup_id)}>`;
71
+ case "channel":
72
+ return `<#${str(element.channel_id)}>`;
73
+ case "emoji":
74
+ return `:${str(element.name)}:`;
75
+ case "broadcast":
76
+ return `@${str(element.range)}`;
77
+ case "date":
78
+ return str(element.fallback) ?? "";
79
+ default:
80
+ return undefined;
81
+ }
82
+ }
83
+ function joined(items, read, separator) {
84
+ const parts = items.map(read);
85
+ return parts.every((part) => part !== undefined) ? parts.join(separator) : undefined;
86
+ }
87
+ /** A `rich_text` block: sections, lists, quotes and code, each a run of inline elements. */
88
+ function richText(block) {
89
+ return joined(list(block.elements), (element) => {
90
+ const runs = (item) => joined(list(item.elements), inline, "");
91
+ switch (element.type) {
92
+ case "rich_text_section":
93
+ case "rich_text_preformatted":
94
+ return runs(element);
95
+ case "rich_text_quote": {
96
+ const run = runs(element);
97
+ return run === undefined ? undefined : `> ${run}`;
98
+ }
99
+ case "rich_text_list": {
100
+ // A list split by other blocks continues its numbering from `offset`.
101
+ const first = typeof element.offset === "number" ? element.offset + 1 : 1;
102
+ return joined(list(element.elements).map((item, index) => ({ item, index })), ({ item, index }) => {
103
+ const run = runs(item);
104
+ return run === undefined
105
+ ? undefined
106
+ : `${element.style === "ordered" ? `${first + index}.` : "-"} ${run}`;
107
+ }, "\n");
108
+ }
109
+ default:
110
+ return undefined;
111
+ }
112
+ },
113
+ // Each element is a block (a paragraph, a list, a quote, code): Slack does not always end one with a newline.
114
+ "\n");
115
+ }
116
+ const BLOCKS = {
117
+ header: (block) => textOf(block.text),
118
+ section: (block) => [textOf(block.text), ...list(block.fields).map(textOf)].filter(Boolean).join("\n"),
119
+ context: (block) => list(block.elements).map(textOf).filter(Boolean).join(" "),
120
+ markdown: (block) => str(block.text),
121
+ divider: () => "---",
122
+ image: (block) => `[image${str(block.alt_text) ? `: ${str(block.alt_text)}` : ""}]`,
123
+ rich_text: richText,
124
+ // A cell is `rich_text` or `raw_text`.
125
+ table: (block) => joined(Array.isArray(block.rows) ? block.rows : [], (row) => joined(list(row), (cell) => (cell.type === "raw_text" ? str(cell.text) : richText(cell)), " | "), "\n"),
126
+ };
127
+ /**
128
+ * What a message says. A Markdown post (every answer and `slack-send` post) is stored as blocks, and its `text` is a
129
+ * rendering that drops a table to ", with interactive elements" (measured), so the blocks are read when this knows them
130
+ * all, and `text` otherwise. Legacy attachments follow: an integration often says everything there.
131
+ */
132
+ function spokenText(message) {
133
+ const blocks = list(message.blocks);
134
+ const read = joined(blocks, (block) => BLOCKS[String(block.type)]?.(block), "\n");
135
+ const body = blocks.length > 0 && read !== undefined ? read : (message.text ?? "");
136
+ const attached = (message.attachments ?? []).map((attachment) => {
137
+ const parts = [attachment.pretext, attachment.title, attachment.text].filter(Boolean);
138
+ return parts.length > 0 ? parts.join("\n") : (attachment.fallback ?? "");
139
+ });
140
+ return [body, ...attached].filter((part) => part.trim() !== "").join("\n");
141
+ }
142
+ export function createSlackPlaceHistory(deps) {
143
+ const { api } = deps;
144
+ /**
145
+ * The people already looked up, named or known to have no name to find (a failed lookup), and whether the app
146
+ * lacks `users:read`. All of it expires together, so a failure, a renamed person or a scope granted by a reinstall
147
+ * is picked up after the TTL, not on every turn and not only at the next start.
148
+ */
149
+ const fresh = () => ({
150
+ named: new Map(),
151
+ unnamed: new Set(),
152
+ scopeMissing: false,
153
+ at: Date.now(),
154
+ });
155
+ let names = fresh();
156
+ /** The missing scope is said once per process: after that, each retry would only repeat it. */
157
+ let scopeWarned = false;
158
+ /** Names for the people a fold shows; one not found is shown by user id. Never rejects: a name is a label. */
159
+ const peopleNames = async (messages) => {
160
+ if (Date.now() - names.at >= NAMES_TTL_MS)
161
+ names = fresh();
162
+ const { named, unnamed } = names;
163
+ const self = deps.self();
164
+ const wanted = new Set(messages.flatMap((message) => message.user !== undefined && message.bot_id === undefined && message.user !== self.userId
165
+ ? [message.user]
166
+ : []));
167
+ const unknown = [...wanted].filter((id) => !named.has(id) && !unnamed.has(id));
168
+ if (names.scopeMissing || unknown.length === 0)
169
+ return named;
170
+ const failures = [];
171
+ await Promise.all(unknown.map(async (id) => {
172
+ try {
173
+ const name = await api.userName(id, CONTEXT_READ);
174
+ if (name)
175
+ named.set(id, name);
176
+ else
177
+ unnamed.add(id);
178
+ }
179
+ catch (error) {
180
+ unnamed.add(id);
181
+ failures.push(error);
182
+ }
183
+ }));
184
+ const missingScope = failures.find((error) => error instanceof SlackApiError && error.slackError === "missing_scope");
185
+ if (missingScope) {
186
+ names.scopeMissing = true;
187
+ if (!scopeWarned) {
188
+ scopeWarned = true;
189
+ log.warn(`${deps.label} users:read is not granted, so people are shown by user id — add it under the Slack app's OAuth & Permissions → Bot Token Scopes (an app \`fastagent add slack\` created gets it with the next \`dev --tunnel\` or \`deploy --run\`), then Reinstall to Workspace; names appear within 10 minutes, or after a restart if the reinstall issued a new Bot Token`);
190
+ }
191
+ }
192
+ else if (failures.length > 0) {
193
+ log.warn(`${deps.label} could not look up ${failures.length} name(s) (shown by user id for 10 minutes): ${String(failures[0])}`);
194
+ }
195
+ return named;
196
+ };
197
+ /** Who said it: this app, another bot, or a person (by name where `users:read` gives one). */
198
+ const speaker = (message, people) => {
199
+ const self = deps.self();
200
+ const own = (message.user !== undefined && message.user === self.userId) ||
201
+ (message.bot_id !== undefined && message.bot_id === self.botId);
202
+ if (own)
203
+ return { kind: "self", label: "you" };
204
+ if (message.bot_id !== undefined) {
205
+ return { kind: "bot", label: `bot ${message.bot_profile?.name ?? message.username ?? message.bot_id}` };
206
+ }
207
+ const name = message.user === undefined ? undefined : people.get(message.user);
208
+ return { kind: "human", label: name ?? `user ${message.user ?? "unknown"}` };
209
+ };
210
+ const read = async (key, { cursor, drop }, until) => {
211
+ const place = slackPlaceOf(key);
212
+ const range = { ...(until ? { latest: until } : {}), limit: cursor ? PAGE_SIZE : FIRST_READ };
213
+ const page = place.threadTs === undefined
214
+ ? await api.channelHistory(place.channelId, range, CONTEXT_READ).then(({ messages, hasMore }) => ({
215
+ messages: messages.reverse(),
216
+ hasMore,
217
+ }))
218
+ : await api
219
+ .threadReplies(place.channelId, place.threadTs, range, CONTEXT_READ)
220
+ .then(({ messages, hasMore }) => ({
221
+ // The root comes first whatever the range: it is this place's discussion only on a first read.
222
+ messages: messages.filter((message) => message.ts !== place.threadTs || cursor === undefined),
223
+ hasMore,
224
+ }));
225
+ const after = (ts) => cursor === undefined || compareSlackTs(ts, cursor) > 0;
226
+ const listed = page.messages.filter((message) => message.ts !== undefined);
227
+ const fresh = listed.filter((message) => after(message.ts));
228
+ const earlier = page.hasMore && fresh.length === listed.length;
229
+ const spoken = fresh.filter((message) => message.hidden !== true &&
230
+ (message.subtype === undefined || SPOKEN_SUBTYPES.has(message.subtype)) &&
231
+ !drop(message.ts));
232
+ const people = await peopleNames(spoken);
233
+ const messages = spoken
234
+ .map((message) => {
235
+ const from = speaker(message, people);
236
+ const text = slackMessageText({ text: spokenText(message), files: message.files });
237
+ // No text, attachment or file to show: an empty line would only spend the fold's budget.
238
+ if (text.trim() === "")
239
+ return undefined;
240
+ return {
241
+ id: message.ts,
242
+ at: Number(message.ts) * 1000,
243
+ from,
244
+ text,
245
+ images: [],
246
+ // Whether a file is an image is `files.info`'s answer, read when the turn loads it.
247
+ files: (message.files ?? []).flatMap((file) => file.id ? [{ key: file.id, ...(file.name ? { name: file.name } : {}) }] : []),
248
+ };
249
+ })
250
+ .filter((message) => message !== undefined);
251
+ const newest = fresh.at(-1)?.ts;
252
+ return {
253
+ covered: fresh.map((message) => message.ts),
254
+ messages,
255
+ ...(newest ? { newest } : {}),
256
+ earlier,
257
+ };
258
+ };
259
+ /** Threads are roots with replies; `conversations.history` gives their count and last reply. */
260
+ const threads = async (room) => {
261
+ const { channelId } = slackPlaceOf(room);
262
+ const { messages } = await api.channelHistory(channelId, { limit: THREAD_SCAN }, CONTEXT_READ);
263
+ const roots = messages.filter((message) => message.ts !== undefined && (message.reply_count ?? 0) > 0);
264
+ const people = await peopleNames(roots);
265
+ const summaries = roots.map((message) => ({
266
+ id: message.ts,
267
+ time: { at: Number(message.latest_reply ?? message.ts) * 1000, is: "last active" },
268
+ replies: message.reply_count,
269
+ first: { label: speaker(message, people).label, text: spokenText(message) },
270
+ }));
271
+ return threadList(summaries, `this channel's newest ${THREAD_SCAN} messages`);
272
+ };
273
+ const history = createPlaceHistory({
274
+ label: deps.label,
275
+ path: deps.path,
276
+ isCursor: (value) => typeof value === "string",
277
+ compare: compareSlackTs,
278
+ isTurnInput: deps.isTurnInput,
279
+ read,
280
+ });
281
+ return { ...history, threads };
282
+ }
@@ -1,9 +1,9 @@
1
- /** Resolve Slack file IDs at dequeue, then stream one engine-neutral Agent turn. */
2
- import type { Agent, AgentEvent } from "../../agent.ts";
1
+ /** Resolve Slack file IDs at dequeue, then stream one harness-neutral Agent turn. */
2
+ import type { Agent } from "../../agent-api.ts";
3
3
  import type * as Stream from "effect/Stream";
4
4
  import type { PortFailure } from "../../effect-port.ts";
5
- import { type BusyRetry } from "../kit/invoke-turn-kit.ts";
6
- import type { SlackBufferedFileRef } from "./context-buffer.ts";
5
+ import { type TurnEvent } from "../kit/invoke-turn-kit.ts";
6
+ import type { SlackBufferedFileRef } from "./history.ts";
7
7
  import { type SlackApi } from "./slack-api.ts";
8
8
  export interface SlackTurnTransport {
9
9
  api: SlackApi;
@@ -18,4 +18,11 @@ export interface SlackTurnAttachments {
18
18
  skipped: number;
19
19
  };
20
20
  }
21
- export declare function slackTurnStream(agent: Agent, session: string, text: string, transport: SlackTurnTransport, attachments: SlackTurnAttachments, busyRetry?: BusyRetry): Stream.Stream<AgentEvent, PortFailure>;
21
+ /** One turn: resolve its files, then ask the agent. `key` is the turn's: the message it answers. */
22
+ export declare function slackTurnStream(agent: Agent, turn: {
23
+ session: () => Promise<string>;
24
+ /** While it runs, the room its thread-reading tool reads (a channel turn's channel). */
25
+ enter?: (sessionId: string) => () => void;
26
+ key: string;
27
+ text: string;
28
+ }, transport: SlackTurnTransport, attachments: SlackTurnAttachments): Stream.Stream<TurnEvent, PortFailure>;
@@ -1,4 +1,4 @@
1
- import { DEFAULT_BUSY_RETRY, attachedFilesManifest, attributedFileName, backgroundImagesManifest, loadBackground, missingAttachmentsNote, turnStream, } from "../kit/invoke-turn-kit.js";
1
+ import { attachedFilesManifest, attributedFileName, backgroundImagesManifest, loadBackground, missingAttachmentsNote, turnStream, promptContent, } from "../kit/invoke-turn-kit.js";
2
2
  import { SlackApiError } from "./slack-api.js";
3
3
  const MARKDOWN_INSTRUCTION = "\n\n(Format your reply as standard Markdown. Slack renders it natively. Do not use HTML or Slack control-mention syntax such as <!here>, <!channel>, or <!everyone>.)";
4
4
  async function resolveFile(transport, fileId) {
@@ -44,15 +44,17 @@ async function resolveInputs(transport, attachments) {
44
44
  promptSuffix: `${missingNote}${imageManifest}${attachedFilesManifest(allFiles)}`,
45
45
  };
46
46
  }
47
- export function slackTurnStream(agent, session, text, transport, attachments, busyRetry = DEFAULT_BUSY_RETRY) {
47
+ /** One turn: resolve its files, then ask the agent. `key` is the turn's: the message it answers. */
48
+ export function slackTurnStream(agent, turn, transport, attachments) {
48
49
  return turnStream({
49
50
  agent,
50
51
  label: transport.label,
51
- busyRetry,
52
+ session: turn.session,
53
+ ...(turn.enter === undefined ? {} : { enter: turn.enter }),
52
54
  resolve: () => resolveInputs(transport, attachments),
53
55
  turn: (resolved) => ({
54
- scope: { session },
55
- prompt: { text: `${text}${resolved.promptSuffix}${MARKDOWN_INSTRUCTION}`, images: resolved.images },
56
+ idempotencyKey: turn.key,
57
+ content: promptContent(`${turn.text}${resolved.promptSuffix}${MARKDOWN_INSTRUCTION}`, resolved.images),
56
58
  }),
57
59
  // Slack says which failures are transient; anything else (a deleted file, a missing scope) will
58
60
  // fail the same way on redelivery.
@@ -1,4 +1,3 @@
1
- export type SlackGroupBehavior = "context" | "mentions";
2
1
  export interface SlackAppManifest {
3
2
  display_information: {
4
3
  name: string;
@@ -39,11 +38,9 @@ export interface SlackAppManifest {
39
38
  token_rotation_enabled: boolean;
40
39
  };
41
40
  }
42
- export declare function slackBotScopes(groupBehavior: SlackGroupBehavior): string[];
43
- export declare function slackBotEvents(groupBehavior: SlackGroupBehavior): string[];
41
+ export declare function slackBotScopes(): string[];
44
42
  export declare function buildSlackManifest(input: {
45
43
  name: string;
46
- groupBehavior: SlackGroupBehavior;
47
44
  requestUrl?: string;
48
45
  redirectUrl?: string;
49
46
  }): SlackAppManifest;
@@ -1,4 +1,6 @@
1
- const SLACK_BASE_BOT_SCOPES = [
1
+ // One posture, as on Feishu: the agent hears the channels it is in (participant-model.md §2), so the history scopes
2
+ // and their message events are part of every app. `users:read` names the people in the history a turn reads.
3
+ const SLACK_BOT_SCOPES = [
2
4
  "app_mentions:read",
3
5
  "assistant:write",
4
6
  "chat:write",
@@ -6,15 +8,25 @@ const SLACK_BASE_BOT_SCOPES = [
6
8
  "files:write",
7
9
  "im:history",
8
10
  "reactions:write",
11
+ "channels:history",
12
+ "groups:history",
13
+ "mpim:history",
14
+ "users:read",
9
15
  ];
10
- const SLACK_CONTEXT_BOT_SCOPES = ["channels:history", "groups:history", "mpim:history"];
11
- const SLACK_BASE_BOT_EVENTS = ["app_context_changed", "app_home_opened", "app_mention", "message.im"];
12
- const SLACK_CONTEXT_BOT_EVENTS = ["message.channels", "message.groups", "message.mpim"];
13
- export function slackBotScopes(groupBehavior) {
14
- return [...SLACK_BASE_BOT_SCOPES, ...(groupBehavior === "context" ? SLACK_CONTEXT_BOT_SCOPES : [])].sort();
16
+ const SLACK_BOT_EVENTS = [
17
+ "app_context_changed",
18
+ "app_home_opened",
19
+ "app_mention",
20
+ "message.im",
21
+ "message.channels",
22
+ "message.groups",
23
+ "message.mpim",
24
+ ];
25
+ export function slackBotScopes() {
26
+ return [...SLACK_BOT_SCOPES].sort();
15
27
  }
16
- export function slackBotEvents(groupBehavior) {
17
- return [...SLACK_BASE_BOT_EVENTS, ...(groupBehavior === "context" ? SLACK_CONTEXT_BOT_EVENTS : [])].sort();
28
+ function slackBotEvents() {
29
+ return [...SLACK_BOT_EVENTS].sort();
18
30
  }
19
31
  /** Slack's bot display name is more restrictive than the app name. */
20
32
  function slackBotDisplayName(name) {
@@ -49,7 +61,7 @@ export function buildSlackManifest(input) {
49
61
  bot_user: { display_name: slackBotDisplayName(name), always_online: false },
50
62
  },
51
63
  oauth_config: {
52
- scopes: { bot: slackBotScopes(input.groupBehavior) },
64
+ scopes: { bot: slackBotScopes() },
53
65
  ...(input.redirectUrl ? { redirect_urls: [input.redirectUrl] } : {}),
54
66
  },
55
67
  settings: {
@@ -57,7 +69,7 @@ export function buildSlackManifest(input) {
57
69
  ? {
58
70
  event_subscriptions: {
59
71
  request_url: input.requestUrl,
60
- bot_events: slackBotEvents(input.groupBehavior),
72
+ bot_events: slackBotEvents(),
61
73
  },
62
74
  }
63
75
  : {}),
@@ -58,7 +58,8 @@ export interface SlackEventEnvelope {
58
58
  }>;
59
59
  }
60
60
  export interface SlackRoute {
61
- session?: string;
61
+ /** Which conversation it belongs to, the one its session is kept by (default: the thread). */
62
+ conversation?: string;
62
63
  channelId?: string;
63
64
  threadTs?: string | null;
64
65
  text?: string;
@@ -1,5 +1,4 @@
1
1
  import { createSlackApp, exchangeSlackOAuthCode, updateSlackAppManifest } from "./config-api.ts";
2
- import { type SlackGroupBehavior } from "./manifest.ts";
3
2
  import { type SlackOnboardingState } from "./onboarding-state.ts";
4
3
  export interface SlackOnboardIO {
5
4
  note(message: string): void;
@@ -33,7 +32,6 @@ export declare function onboardSlackApp(input: SlackOnboardInput, io: SlackOnboa
33
32
  }): Promise<SlackOnboardingState>;
34
33
  export declare function newSlackOnboardingState(input: {
35
34
  appName: string;
36
- groupBehavior: SlackGroupBehavior;
37
35
  configToken: string;
38
36
  configRefreshToken: string;
39
37
  /** When the pair was captured; pass it through rather than re-deriving the same expiry twice. */
@@ -22,7 +22,6 @@ export async function onboardSlackApp(input, io, deps = {}) {
22
22
  });
23
23
  const manifest = buildSlackManifest({
24
24
  name: state.appName,
25
- groupBehavior: state.groupBehavior,
26
25
  requestUrl: input.requestUrl,
27
26
  redirectUrl: input.redirectUrl,
28
27
  });
@@ -91,7 +90,7 @@ export async function onboardSlackApp(input, io, deps = {}) {
91
90
  const oauthState = randomBytes(24).toString("hex");
92
91
  const authorize = new URL("https://slack.com/oauth/v2/authorize");
93
92
  authorize.searchParams.set("client_id", state.clientId);
94
- authorize.searchParams.set("scope", slackBotScopes(state.groupBehavior).join(","));
93
+ authorize.searchParams.set("scope", slackBotScopes().join(","));
95
94
  authorize.searchParams.set("redirect_uri", input.redirectUrl);
96
95
  authorize.searchParams.set("state", oauthState);
97
96
  // The redirect lands on the tunnel hostname, which THIS machine may not resolve yet (#421).
@@ -112,7 +111,7 @@ export async function onboardSlackApp(input, io, deps = {}) {
112
111
  });
113
112
  if (oauth.appId !== state.appId)
114
113
  throw new Error("Slack OAuth installed a different app than the manifest app");
115
- if (slackBotScopes(state.groupBehavior).some((scope) => !oauth.scopes.includes(scope))) {
114
+ if (slackBotScopes().some((scope) => !oauth.scopes.includes(scope))) {
116
115
  throw new Error("Slack OAuth completed without all required bot scopes; re-run fastagent add slack to reinstall");
117
116
  }
118
117
  await io.writeRuntimeSecrets({ botToken: oauth.botToken });
@@ -130,7 +129,6 @@ export function newSlackOnboardingState(input) {
130
129
  return {
131
130
  version: 1,
132
131
  appName: input.appName,
133
- groupBehavior: input.groupBehavior,
134
132
  configToken: input.configToken,
135
133
  configRefreshToken: input.configRefreshToken,
136
134
  configTokenExpiresAt: input.configTokenExpiresAt ?? configTokenExpiry(input.now),
@@ -1,10 +1,8 @@
1
- import type { SlackGroupBehavior } from "./manifest.ts";
2
1
  /** When a token pair captured `now` stops being usable — the ONE place that answers it. */
3
2
  export declare function configTokenExpiry(now?: number): number;
4
3
  export interface SlackOnboardingState {
5
4
  version: 1;
6
5
  appName: string;
7
- groupBehavior: SlackGroupBehavior;
8
6
  appId?: string;
9
7
  /** Set before apps.manifest.create; without an appId it blocks blind duplicate-creation retries. */
10
8
  createAttemptedAt?: string;
@@ -18,7 +18,6 @@ function validState(value) {
18
18
  state !== null &&
19
19
  state.version === 1 &&
20
20
  typeof state.appName === "string" &&
21
- (state.groupBehavior === "context" || state.groupBehavior === "mentions") &&
22
21
  typeof state.configToken === "string" &&
23
22
  typeof state.configRefreshToken === "string" &&
24
23
  typeof state.configTokenExpiresAt === "number");
@@ -2,7 +2,6 @@ import type { SlackEventEnvelope, SlackMessageEvent, SlackRoute } from "./model.
2
2
  export type { SlackEventEnvelope, SlackFile, SlackMessageEvent, SlackRoute } from "./model.ts";
3
3
  /** Does this text address ANYONE — a user, a broadcast, or a user group? */
4
4
  export declare function hasSlackMention(text: string): boolean;
5
- export declare function hasSlackUserMention(text: string): boolean;
6
5
  /** Does this text mention this specific user (either form)? */
7
6
  export declare function mentionsSlackUser(text: string, userId: string): boolean;
8
7
  /** Strip every mention, e.g. before matching a bare command word or building a title. */
@@ -20,10 +19,6 @@ export declare function slackTeamId(envelope: SlackEventEnvelope): string | unde
20
19
  export declare function slackFileIds(event: SlackMessageEvent): string[];
21
20
  /** Text plus a structural marker for file-only or captioned file shares. */
22
21
  export declare function slackMessageText(event: SlackMessageEvent): string;
23
- export declare function slackSenderLabel(event: SlackMessageEvent): string;
24
- /** Main-channel discussion and each concrete thread are independent context buckets. */
25
- export declare function slackPlaceKey(teamId: string, event: Pick<SlackMessageEvent, "channel" | "thread_ts">): string;
26
- export declare function slackBufferText(text: string): string;
27
22
  export declare function slackEnvelope(envelope: SlackEventEnvelope): string;
28
23
  /** Default explicit-summon policy: DMs and app_mention events only. */
29
24
  export declare function defaultSlackRoute(envelope: SlackEventEnvelope): SlackRoute | null;
@@ -1,5 +1,4 @@
1
- import { BUFFER_LINE_MAX_CHARS } from "../kit/context-buffer.js";
2
- import { codePointPrefix, truncateCodePointPrefix } from "../kit/text.js";
1
+ import { codePointPrefix } from "../kit/text.js";
3
2
  const HUMAN_MESSAGE_SUBTYPES = new Set(["file_share", "thread_broadcast"]);
4
3
  /** Both forms Slack writes a mention in: `<@U123>` and the labelled `<@U123|name>`. */
5
4
  const mentionSource = (idPattern) => String.raw `<@${idPattern}(?:\|[^>]*)?>`;
@@ -10,9 +9,6 @@ const ANY_MENTION = String.raw `(?:${USER_MENTION}|<!(?:here|channel|everyone)(?
10
9
  export function hasSlackMention(text) {
11
10
  return new RegExp(ANY_MENTION, "i").test(text);
12
11
  }
13
- export function hasSlackUserMention(text) {
14
- return new RegExp(USER_MENTION, "i").test(text);
15
- }
16
12
  /** Escape a platform-supplied id before it becomes part of a pattern. */
17
13
  const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18
14
  /** Does this text mention this specific user (either form)? */
@@ -58,17 +54,6 @@ export function slackMessageText(event) {
58
54
  const marker = `[${files} attached file${files === 1 ? "" : "s"}]`;
59
55
  return text ? `${text}\n${marker}` : marker;
60
56
  }
61
- export function slackSenderLabel(event) {
62
- return `user ${event.user ?? "unknown"}`;
63
- }
64
- /** Main-channel discussion and each concrete thread are independent context buckets. */
65
- export function slackPlaceKey(teamId, event) {
66
- const base = `${teamId}:${event.channel ?? "unknown-channel"}`;
67
- return event.thread_ts ? `${base}:root:${event.thread_ts}` : base;
68
- }
69
- export function slackBufferText(text) {
70
- return truncateCodePointPrefix(text.replace(/\s+/g, " ").trim(), BUFFER_LINE_MAX_CHARS);
71
- }
72
57
  export function slackEnvelope(envelope) {
73
58
  const event = envelope.event;
74
59
  if (!event?.channel)
@@ -1,5 +1,4 @@
1
- /** Slack reply rendering: native Agent streams first, rate-safe edited-message compatibility second. */
2
- import type { AgentEvent } from "../../agent.ts";
1
+ import type { TurnEvent } from "../kit/invoke-turn-kit.ts";
3
2
  import * as Effect from "effect/Effect";
4
3
  import * as Stream from "effect/Stream";
5
4
  import { PortFailure } from "../../effect-port.ts";
@@ -23,7 +22,7 @@ export declare function sanitizeSlackMarkdown(markdown: string): string;
23
22
  export declare function deliverSlackAnswer(api: SlackApi, target: SlackTarget, markdown: string, previewTs?: string): Promise<void>;
24
23
  /** Settle a queue/drop/defer notice. These are authored plain strings, so the basic text API is enough. */
25
24
  export declare function settleSlackPreview(api: SlackApi, target: SlackTarget, previewTs: string | undefined, text: string): Promise<void>;
26
- export declare function slackReply(events: Stream.Stream<AgentEvent, PortFailure>, api: SlackApi, target: SlackTarget, formatError: (failure: SlackFailure) => string | undefined, options?: {
25
+ export declare function slackReply(events: Stream.Stream<TurnEvent, PortFailure>, api: SlackApi, target: SlackTarget, formatError: (failure: SlackFailure) => string | undefined, options?: {
27
26
  rendering?: SlackRendering;
28
27
  initialPreviewTs?: string;
29
28
  threadTitle?: string;