@fastagent-sh/fastagent 0.21.1 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/README.md +9 -12
  2. package/dist/agent.d.ts +24 -37
  3. package/dist/agent.js +7 -15
  4. package/dist/atomic-write.d.ts +13 -17
  5. package/dist/atomic-write.js +18 -29
  6. package/dist/bind.d.ts +12 -22
  7. package/dist/bind.js +18 -27
  8. package/dist/channel.d.ts +11 -33
  9. package/dist/channels/agentcore-limits.d.ts +2 -13
  10. package/dist/channels/agentcore-limits.js +2 -13
  11. package/dist/channels/agentcore-protocol.d.ts +67 -58
  12. package/dist/channels/agentcore-protocol.js +23 -15
  13. package/dist/channels/agentcore-service.d.ts +19 -33
  14. package/dist/channels/agentcore-service.js +176 -59
  15. package/dist/channels/agentcore.d.ts +39 -33
  16. package/dist/channels/agentcore.js +90 -224
  17. package/dist/channels/body.d.ts +15 -2
  18. package/dist/channels/body.js +24 -2
  19. package/dist/channels/busy.d.ts +1 -21
  20. package/dist/channels/busy.js +2 -39
  21. package/dist/channels/control.d.ts +17 -62
  22. package/dist/channels/control.js +74 -182
  23. package/dist/channels/define-channel.d.ts +39 -0
  24. package/dist/channels/define-channel.js +9 -0
  25. package/dist/channels/discover.d.ts +10 -31
  26. package/dist/channels/discover.js +37 -31
  27. package/dist/channels/feishu/bootstrap-token.d.ts +1 -8
  28. package/dist/channels/feishu/bootstrap-token.js +7 -23
  29. package/dist/channels/feishu/card.d.ts +14 -28
  30. package/dist/channels/feishu/card.js +16 -30
  31. package/dist/channels/feishu/cloud.d.ts +1 -5
  32. package/dist/channels/feishu/context-buffer.d.ts +4 -23
  33. package/dist/channels/feishu/context-buffer.js +8 -31
  34. package/dist/channels/feishu/crypto.d.ts +10 -5
  35. package/dist/channels/feishu/crypto.js +12 -19
  36. package/dist/channels/feishu/feishu-api.d.ts +2 -1
  37. package/dist/channels/feishu/feishu-api.js +5 -4
  38. package/dist/channels/feishu/feishu.d.ts +4 -10
  39. package/dist/channels/feishu/feishu.js +113 -227
  40. package/dist/channels/feishu/invoke-turn.d.ts +5 -4
  41. package/dist/channels/feishu/invoke-turn.js +36 -54
  42. package/dist/channels/feishu/model.d.ts +4 -21
  43. package/dist/channels/feishu/model.js +1 -8
  44. package/dist/channels/feishu/normalize.d.ts +2 -10
  45. package/dist/channels/feishu/normalize.js +7 -42
  46. package/dist/channels/feishu/parse.d.ts +9 -29
  47. package/dist/channels/feishu/parse.js +8 -26
  48. package/dist/channels/feishu/preview.d.ts +12 -14
  49. package/dist/channels/feishu/preview.js +108 -207
  50. package/dist/channels/feishu/register-app.d.ts +8 -23
  51. package/dist/channels/feishu/register-app.js +7 -20
  52. package/dist/channels/feishu/register-webhook.d.ts +2 -9
  53. package/dist/channels/feishu/register-webhook.js +9 -33
  54. package/dist/channels/feishu/scaffold/channel.ts +27 -19
  55. package/dist/channels/feishu/scaffold/channel.websocket.ts +31 -0
  56. package/dist/channels/feishu/setup-mode.d.ts +11 -36
  57. package/dist/channels/feishu/setup-mode.js +7 -26
  58. package/dist/channels/feishu/ws-ingress.d.ts +1 -2
  59. package/dist/channels/feishu/ws-ingress.js +6 -8
  60. package/dist/channels/http.d.ts +15 -15
  61. package/dist/channels/http.js +19 -9
  62. package/dist/channels/kit/attachment-path.d.ts +4 -5
  63. package/dist/channels/kit/attachment-path.js +10 -34
  64. package/dist/channels/kit/context-buffer.d.ts +14 -21
  65. package/dist/channels/kit/context-buffer.js +25 -38
  66. package/dist/channels/kit/delivery.d.ts +35 -0
  67. package/dist/channels/kit/delivery.js +129 -0
  68. package/dist/channels/kit/event-stream.d.ts +5 -0
  69. package/dist/channels/kit/event-stream.js +29 -0
  70. package/dist/channels/kit/invoke-turn-kit.d.ts +53 -26
  71. package/dist/channels/kit/invoke-turn-kit.js +89 -32
  72. package/dist/channels/kit/preview-kit.d.ts +18 -72
  73. package/dist/channels/kit/preview-kit.js +22 -88
  74. package/dist/channels/kit/signature.d.ts +3 -9
  75. package/dist/channels/kit/signature.js +3 -9
  76. package/dist/channels/kit/state.d.ts +1 -2
  77. package/dist/channels/kit/state.js +5 -14
  78. package/dist/channels/kit/stop-command.d.ts +1 -2
  79. package/dist/channels/kit/stop-command.js +6 -9
  80. package/dist/channels/kit/tasks.d.ts +1 -1
  81. package/dist/channels/kit/tasks.js +8 -21
  82. package/dist/channels/kit/text.d.ts +2 -16
  83. package/dist/channels/kit/text.js +23 -31
  84. package/dist/channels/kit/thread-participants.d.ts +4 -17
  85. package/dist/channels/kit/thread-participants.js +8 -55
  86. package/dist/channels/kit/transport.d.ts +26 -0
  87. package/dist/channels/kit/transport.js +20 -0
  88. package/dist/channels/kit/turn-queue.d.ts +7 -11
  89. package/dist/channels/kit/turn-queue.js +21 -39
  90. package/dist/channels/kit/turn-runner.d.ts +32 -18
  91. package/dist/channels/kit/turn-runner.js +98 -53
  92. package/dist/channels/kit/turn-store.d.ts +32 -32
  93. package/dist/channels/kit/turn-store.js +45 -88
  94. package/dist/channels/lark/lark.d.ts +1 -5
  95. package/dist/channels/lark/onboard.d.ts +3 -12
  96. package/dist/channels/lark/onboard.js +3 -13
  97. package/dist/channels/lark/scaffold/channel.ts +27 -19
  98. package/dist/channels/lark/scaffold/channel.websocket.ts +31 -0
  99. package/dist/channels/registration.d.ts +9 -35
  100. package/dist/channels/registration.js +6 -37
  101. package/dist/channels/secret.js +2 -5
  102. package/dist/channels/serve.d.ts +47 -44
  103. package/dist/channels/serve.js +165 -101
  104. package/dist/channels/slack/config-api.d.ts +4 -27
  105. package/dist/channels/slack/config-api.js +5 -34
  106. package/dist/channels/slack/context-buffer.d.ts +2 -3
  107. package/dist/channels/slack/context-buffer.js +5 -5
  108. package/dist/channels/slack/invoke-turn.d.ts +3 -1
  109. package/dist/channels/slack/invoke-turn.js +25 -34
  110. package/dist/channels/slack/manifest.js +1 -3
  111. package/dist/channels/slack/model.d.ts +1 -2
  112. package/dist/channels/slack/model.js +1 -1
  113. package/dist/channels/slack/onboard.d.ts +4 -3
  114. package/dist/channels/slack/onboard.js +8 -11
  115. package/dist/channels/slack/onboarding-state.d.ts +3 -5
  116. package/dist/channels/slack/onboarding-state.js +9 -6
  117. package/dist/channels/slack/parse.d.ts +4 -13
  118. package/dist/channels/slack/parse.js +7 -28
  119. package/dist/channels/slack/preview.d.ts +12 -2
  120. package/dist/channels/slack/preview.js +292 -269
  121. package/dist/channels/slack/reaction.d.ts +11 -3
  122. package/dist/channels/slack/reaction.js +19 -8
  123. package/dist/channels/slack/register-webhook.js +4 -7
  124. package/dist/channels/slack/scaffold/channel.ts +20 -13
  125. package/dist/channels/slack/scaffold/slack-send.ts +2 -2
  126. package/dist/channels/slack/setup-server.d.ts +1 -5
  127. package/dist/channels/slack/setup-server.js +1 -5
  128. package/dist/channels/slack/shared-api.d.ts +1 -4
  129. package/dist/channels/slack/shared-api.js +2 -13
  130. package/dist/channels/slack/slack-api.d.ts +2 -1
  131. package/dist/channels/slack/slack-api.js +6 -4
  132. package/dist/channels/slack/slack.d.ts +11 -14
  133. package/dist/channels/slack/slack.js +121 -122
  134. package/dist/channels/sse.d.ts +1 -1
  135. package/dist/channels/sse.js +1 -1
  136. package/dist/channels/telegram/context-buffer.d.ts +7 -22
  137. package/dist/channels/telegram/context-buffer.js +6 -23
  138. package/dist/channels/telegram/invoke-turn.d.ts +7 -7
  139. package/dist/channels/telegram/invoke-turn.js +24 -43
  140. package/dist/channels/telegram/parse.d.ts +24 -51
  141. package/dist/channels/telegram/parse.js +32 -84
  142. package/dist/channels/telegram/preview.d.ts +10 -1
  143. package/dist/channels/telegram/preview.js +79 -100
  144. package/dist/channels/telegram/register-webhook.js +5 -23
  145. package/dist/channels/telegram/scaffold/channel.ts +25 -18
  146. package/dist/channels/telegram/scaffold/telegram-send.ts +6 -4
  147. package/dist/channels/telegram/telegram-api.d.ts +4 -3
  148. package/dist/channels/telegram/telegram-api.js +9 -7
  149. package/dist/channels/telegram/telegram.d.ts +4 -18
  150. package/dist/channels/telegram/telegram.js +38 -94
  151. package/dist/channels/telegram/turn-store.d.ts +11 -14
  152. package/dist/channels/telegram/turn-store.js +8 -6
  153. package/dist/channels/wait-health.d.ts +4 -6
  154. package/dist/channels/wait-health.js +10 -14
  155. package/dist/cli/add-feishu.d.ts +2 -12
  156. package/dist/cli/add-feishu.js +24 -71
  157. package/dist/cli/add-slack.d.ts +5 -3
  158. package/dist/cli/add-slack.js +53 -76
  159. package/dist/cli/auth-view.d.ts +2 -16
  160. package/dist/cli/auth-view.js +2 -16
  161. package/dist/cli/commands/add.js +25 -40
  162. package/dist/cli/commands/chat.d.ts +0 -1
  163. package/dist/cli/commands/chat.js +5 -6
  164. package/dist/cli/commands/deploy/agentcore.js +60 -65
  165. package/dist/cli/commands/deploy/docker.js +50 -23
  166. package/dist/cli/commands/deploy/fly.js +23 -61
  167. package/dist/cli/commands/deploy/railway.js +23 -18
  168. package/dist/cli/commands/deploy/shared.d.ts +38 -57
  169. package/dist/cli/commands/deploy/shared.js +40 -59
  170. package/dist/cli/commands/deploy.d.ts +10 -27
  171. package/dist/cli/commands/deploy.js +38 -60
  172. package/dist/cli/commands/destroy.d.ts +4 -0
  173. package/dist/cli/commands/destroy.js +56 -0
  174. package/dist/cli/commands/dev.d.ts +2 -1
  175. package/dist/cli/commands/dev.js +20 -23
  176. package/dist/cli/commands/info.d.ts +0 -2
  177. package/dist/cli/commands/info.js +83 -49
  178. package/dist/cli/commands/init.d.ts +1 -2
  179. package/dist/cli/commands/init.js +16 -55
  180. package/dist/cli/commands/invoke.d.ts +0 -1
  181. package/dist/cli/commands/invoke.js +5 -7
  182. package/dist/cli/commands/login.d.ts +2 -1
  183. package/dist/cli/commands/login.js +33 -38
  184. package/dist/cli/commands/logs.js +3 -4
  185. package/dist/cli/commands/models.js +1 -5
  186. package/dist/cli/commands/routine-run.d.ts +6 -0
  187. package/dist/cli/commands/routine-run.js +47 -0
  188. package/dist/cli/commands/routine.d.ts +25 -0
  189. package/dist/cli/commands/routine.js +122 -0
  190. package/dist/cli/commands/start.d.ts +31 -3
  191. package/dist/cli/commands/start.js +131 -81
  192. package/dist/cli/commands/tool.js +26 -12
  193. package/dist/cli/fail.d.ts +13 -23
  194. package/dist/cli/fail.js +20 -23
  195. package/dist/cli/invoke-stream.d.ts +1 -8
  196. package/dist/cli/kernel.d.ts +6 -38
  197. package/dist/cli/kernel.js +14 -77
  198. package/dist/cli/models-view.d.ts +1 -9
  199. package/dist/cli/models-view.js +11 -22
  200. package/dist/cli/program.d.ts +5 -6
  201. package/dist/cli/program.js +120 -157
  202. package/dist/cli/serve.d.ts +57 -41
  203. package/dist/cli/serve.js +94 -121
  204. package/dist/cli/shared.d.ts +15 -61
  205. package/dist/cli/shared.js +55 -181
  206. package/dist/cli.js +1 -8
  207. package/dist/collect.d.ts +6 -0
  208. package/dist/collect.js +6 -0
  209. package/dist/core.d.ts +4 -1
  210. package/dist/core.js +9 -7
  211. package/dist/declared-secrets.d.ts +55 -0
  212. package/dist/declared-secrets.js +88 -0
  213. package/dist/deploy/agentcore/aws-cli.d.ts +91 -0
  214. package/dist/deploy/agentcore/aws-cli.js +64 -0
  215. package/dist/deploy/agentcore/destroy.d.ts +51 -0
  216. package/dist/deploy/agentcore/destroy.js +273 -0
  217. package/dist/deploy/agentcore/forwarder.js +28 -79
  218. package/dist/deploy/agentcore/logs.d.ts +2 -18
  219. package/dist/deploy/agentcore/logs.js +27 -51
  220. package/dist/deploy/agentcore/plan.d.ts +85 -105
  221. package/dist/deploy/agentcore/plan.js +152 -314
  222. package/dist/deploy/agentcore/run.d.ts +28 -28
  223. package/dist/deploy/agentcore/run.js +227 -306
  224. package/dist/deploy/agentcore/zip.d.ts +2 -15
  225. package/dist/deploy/agentcore/zip.js +3 -17
  226. package/dist/deploy/build-context.d.ts +21 -0
  227. package/dist/deploy/build-context.js +137 -0
  228. package/dist/deploy/channel-ingress.d.ts +26 -39
  229. package/dist/deploy/channel-ingress.js +57 -28
  230. package/dist/deploy/container.d.ts +20 -34
  231. package/dist/deploy/container.js +49 -100
  232. package/dist/deploy/docker/plan.d.ts +12 -11
  233. package/dist/deploy/docker/plan.js +43 -24
  234. package/dist/deploy/docker/run.d.ts +22 -25
  235. package/dist/deploy/docker/run.js +39 -37
  236. package/dist/deploy/fly/plan.d.ts +15 -44
  237. package/dist/deploy/fly/plan.js +41 -73
  238. package/dist/deploy/fly/run.d.ts +16 -51
  239. package/dist/deploy/fly/run.js +42 -95
  240. package/dist/deploy/hosts.d.ts +24 -3
  241. package/dist/deploy/hosts.js +24 -3
  242. package/dist/deploy/preflight.d.ts +47 -41
  243. package/dist/deploy/preflight.js +282 -383
  244. package/dist/deploy/railway/plan.d.ts +16 -42
  245. package/dist/deploy/railway/plan.js +42 -60
  246. package/dist/deploy/railway/run.d.ts +30 -68
  247. package/dist/deploy/railway/run.js +86 -100
  248. package/dist/deploy/registration-gate.d.ts +6 -13
  249. package/dist/deploy/residency.d.ts +37 -0
  250. package/dist/deploy/residency.js +24 -0
  251. package/dist/deploy/runner.d.ts +10 -9
  252. package/dist/deploy/runner.js +7 -18
  253. package/dist/deploy/secrets.d.ts +40 -41
  254. package/dist/deploy/secrets.js +117 -103
  255. package/dist/deploy/workspace.d.ts +50 -0
  256. package/dist/deploy/workspace.js +197 -0
  257. package/dist/dev-supervisor.d.ts +1 -9
  258. package/dist/dev-supervisor.js +21 -64
  259. package/dist/effect-port.d.ts +50 -0
  260. package/dist/effect-port.js +77 -0
  261. package/dist/engines/pi/agent-session-factory.d.ts +50 -69
  262. package/dist/engines/pi/agent-session-factory.js +249 -146
  263. package/dist/engines/pi/auth.d.ts +15 -11
  264. package/dist/engines/pi/auth.js +96 -99
  265. package/dist/engines/pi/chat.d.ts +1 -5
  266. package/dist/engines/pi/chat.js +2 -14
  267. package/dist/engines/pi/config.d.ts +53 -51
  268. package/dist/engines/pi/config.js +83 -92
  269. package/dist/engines/pi/create.d.ts +60 -75
  270. package/dist/engines/pi/create.js +108 -141
  271. package/dist/engines/pi/definition.d.ts +14 -58
  272. package/dist/engines/pi/definition.js +21 -85
  273. package/dist/engines/pi/invoke-session.d.ts +5 -25
  274. package/dist/engines/pi/invoke-session.js +233 -244
  275. package/dist/engines/pi/login.d.ts +95 -35
  276. package/dist/engines/pi/login.js +259 -107
  277. package/dist/engines/pi/machine.d.ts +31 -0
  278. package/dist/engines/pi/machine.js +106 -0
  279. package/dist/engines/pi/models.d.ts +70 -89
  280. package/dist/engines/pi/models.js +188 -81
  281. package/dist/engines/pi/open.d.ts +65 -53
  282. package/dist/engines/pi/open.js +129 -69
  283. package/dist/engines/pi/report.d.ts +3 -12
  284. package/dist/engines/pi/report.js +2 -16
  285. package/dist/engines/pi/search-tools.d.ts +1 -9
  286. package/dist/engines/pi/search-tools.js +26 -57
  287. package/dist/engines/pi/service.d.ts +2 -16
  288. package/dist/engines/pi/service.js +2 -16
  289. package/dist/engines/pi/session-builder.d.ts +5 -9
  290. package/dist/engines/pi/session-builder.js +44 -82
  291. package/dist/engines/pi/session-control.js +286 -269
  292. package/dist/engines/pi/session-effects.d.ts +14 -0
  293. package/dist/engines/pi/session-effects.js +30 -0
  294. package/dist/engines/pi/session-inheritance.d.ts +9 -18
  295. package/dist/engines/pi/session-inheritance.js +103 -160
  296. package/dist/engines/pi/session-markers.d.ts +31 -30
  297. package/dist/engines/pi/session-markers.js +26 -25
  298. package/dist/engines/pi/session-settings.d.ts +6 -22
  299. package/dist/engines/pi/session-settings.js +10 -21
  300. package/dist/engines/pi/session-store.d.ts +26 -92
  301. package/dist/engines/pi/session-store.js +96 -310
  302. package/dist/engines/pi/tool-context.d.ts +17 -45
  303. package/dist/engines/pi/tool-context.js +7 -26
  304. package/dist/engines/pi/tool.d.ts +45 -36
  305. package/dist/engines/pi/tool.js +43 -57
  306. package/dist/engines/pi/turn-kit.d.ts +14 -52
  307. package/dist/engines/pi/turn-kit.js +18 -67
  308. package/dist/engines/pi/wake-tool.d.ts +2 -10
  309. package/dist/engines/pi/wake-tool.js +7 -27
  310. package/dist/env.d.ts +27 -28
  311. package/dist/env.js +45 -50
  312. package/dist/index.js +0 -2
  313. package/dist/lark.d.ts +1 -2
  314. package/dist/lark.js +1 -2
  315. package/dist/loader.d.ts +14 -55
  316. package/dist/loader.js +24 -43
  317. package/dist/log.d.ts +2 -12
  318. package/dist/log.js +3 -24
  319. package/dist/node.d.ts +2 -15
  320. package/dist/node.js +2 -18
  321. package/dist/observe.d.ts +2 -8
  322. package/dist/open-url.d.ts +1 -1
  323. package/dist/open-url.js +1 -1
  324. package/dist/paths.d.ts +70 -134
  325. package/dist/paths.js +165 -232
  326. package/dist/pi.d.ts +4 -6
  327. package/dist/pi.js +3 -3
  328. package/dist/proxy.d.ts +16 -6
  329. package/dist/proxy.js +52 -16
  330. package/dist/runtime.d.ts +18 -12
  331. package/dist/runtime.js +18 -11
  332. package/dist/scaffold/add-channel.d.ts +14 -31
  333. package/dist/scaffold/add-channel.js +48 -112
  334. package/dist/scaffold/init.d.ts +9 -31
  335. package/dist/scaffold/init.js +45 -138
  336. package/dist/scaffold/templates/env.example +6 -4
  337. package/dist/scaffold/templates/fastagent.config.ts +36 -0
  338. package/dist/scaffold/templates.d.ts +3 -3
  339. package/dist/scaffold/templates.js +5 -8
  340. package/dist/scaffold/vendor-skill.d.ts +2 -5
  341. package/dist/scaffold/vendor-skill.js +19 -29
  342. package/dist/schedule/cron.d.ts +9 -5
  343. package/dist/schedule/cron.js +9 -11
  344. package/dist/schedule/discover.d.ts +12 -12
  345. package/dist/schedule/discover.js +43 -34
  346. package/dist/schedule/routine.d.ts +43 -0
  347. package/dist/schedule/routine.js +32 -0
  348. package/dist/schedule/run.d.ts +55 -0
  349. package/dist/schedule/run.js +146 -0
  350. package/dist/schedule/scheduler.d.ts +44 -55
  351. package/dist/schedule/scheduler.js +291 -265
  352. package/dist/schedule/state.d.ts +105 -10
  353. package/dist/schedule/state.js +293 -19
  354. package/dist/schedule/wake-alarm.d.ts +10 -23
  355. package/dist/schedule/wake-alarm.js +91 -121
  356. package/dist/schedule/wakeups.d.ts +23 -39
  357. package/dist/schedule/wakeups.js +33 -75
  358. package/dist/secrets-gate.d.ts +32 -0
  359. package/dist/secrets-gate.js +33 -0
  360. package/dist/service.d.ts +137 -98
  361. package/dist/service.js +250 -252
  362. package/dist/session-remote.d.ts +33 -44
  363. package/dist/session-remote.js +203 -192
  364. package/dist/session.d.ts +166 -229
  365. package/dist/session.js +33 -55
  366. package/dist/tunnel.d.ts +8 -36
  367. package/dist/tunnel.js +24 -65
  368. package/dist/version.d.ts +2 -2
  369. package/dist/version.js +2 -2
  370. package/package.json +10 -16
  371. package/dist/channels/agentcore-state.d.ts +0 -77
  372. package/dist/channels/agentcore-state.js +0 -276
  373. package/dist/channels/github/github.d.ts +0 -31
  374. package/dist/channels/github/github.js +0 -89
  375. package/dist/channels/github/scaffold/channel.ts +0 -25
  376. package/dist/cli/commands/attach.d.ts +0 -108
  377. package/dist/cli/commands/attach.js +0 -637
  378. package/dist/cli/commands/fire.d.ts +0 -7
  379. package/dist/cli/commands/fire.js +0 -38
  380. package/dist/cli/commands/schedule.d.ts +0 -12
  381. package/dist/cli/commands/schedule.js +0 -87
  382. package/dist/github.d.ts +0 -3
  383. package/dist/github.js +0 -2
  384. package/dist/scaffold/templates/fastagent.config.mjs +0 -23
  385. package/dist/schedule/audit.d.ts +0 -18
  386. package/dist/schedule/audit.js +0 -57
  387. package/dist/schedule/schedule.d.ts +0 -35
  388. package/dist/schedule/schedule.js +0 -23
@@ -1,21 +1,17 @@
1
+ /** Per-session FIFO execution. */
2
+ import * as Effect from "effect/Effect";
3
+ import type * as Scope from "effect/Scope";
1
4
  export interface TurnQueue<T> {
2
- /** Schedule onto the session's serial chain (runs after that session's previous turn). */
3
5
  accept(rec: T): void;
4
- /** Resolve once no turn is in flight (every per-session chain has drained). A test/observability seam
5
- * — the production runtime does NOT drain on shutdown (SIGTERM exits mid-turn by design; see the module
6
- * header), so this is not a graceful-drain hook; it just lets a caller await the fire-and-forget turns. */
6
+ /** Observation only: production shutdown does not drain channel turns. */
7
7
  idle(): Promise<void>;
8
8
  }
9
9
  export declare function createTurnQueue<T extends {
10
10
  session: string;
11
11
  }>(opts: {
12
- /** Log prefix naming the consumer (e.g. "[telegram]") — the queue itself is channel-neutral. */
13
12
  label: string;
14
- /** Executes ONE turn. The queue wraps it: dequeue in FIFO order per session. The runner owns its
15
- * own error surface; a rejection that escapes anyway is caught and logged here (never a silent
16
- * unhandled rejection), but the runner's own catch is where diagnosis belongs. */
17
- run: (rec: T) => Promise<void>;
18
- /** Fired synchronously when a record is scheduled BEHIND an active turn — the caller's hook for
19
- * queue feedback to the user (e.g. an "⏳ queued" notice). */
13
+ /** The queue diagnoses escaped failures and closes this turn's resources before its successor runs. */
14
+ run: (rec: T) => Effect.Effect<void, unknown, Scope.Scope>;
15
+ /** Synchronous queue feedback for a turn behind an active or queued predecessor. */
20
16
  onQueuedBehind?: (rec: T) => void;
21
17
  }): TurnQueue<T>;
@@ -1,54 +1,36 @@
1
- /**
2
- * Per-session serial turn execution: one turn at a time per session (FIFO chains), different
3
- * sessions concurrent. IN-MEMORY — the runtime queue holds no durability of its own. The engine lease
4
- * is the corruption floor beneath this; this adds the group-UX queue (a second summon waits its turn
5
- * instead of colliding on the lease and being dropped as "busy").
6
- *
7
- * Channel-neutral (records are opaque beyond a `session` key), shared by the stateful chat channels
8
- * (Telegram, Feishu/Lark, Slack). Durability is layered ON TOP by the caller: turn-store.ts
9
- * persists an accepted turn's intent pre-ACK and replays a crash-surviving one on the next start (L1,
10
- * process-crash recovery, at-least-once). Exactly-once / deterministic step-replay (L2) is the K-axis
11
- * backend — an external queue with distributed locking (SPEC §11) — not this in-memory queue.
12
- */
1
+ /** Per-session FIFO execution. */
2
+ import * as Effect from "effect/Effect";
3
+ import * as Fiber from "effect/Fiber";
13
4
  import { log } from "../../log.js";
14
5
  import { beginWork } from "../busy.js";
6
+ import { portError } from "../../effect-port.js";
15
7
  export function createTurnQueue(opts) {
16
8
  const { label, run, onQueuedBehind } = opts;
17
- // Per-session serial chains: a second turn for the same session waits its turn (FIFO) instead of
18
- // colliding on the engine lease and being dropped as "busy". Different sessions run concurrently.
19
9
  const chains = new Map();
20
10
  return {
21
11
  accept(rec) {
22
12
  if (chains.has(rec.session))
23
13
  onQueuedBehind?.(rec);
24
- // Process-wide busy signal (busy.ts): an accepted turn counts as in-flight work from acceptance
25
- // until its run settles — serving surfaces that must not idle mid-turn (the AgentCore adapter's
26
- // /ping) read it. Counted here, not in run(), so a QUEUED turn (accepted, waiting on the chain)
27
- // already reads as busy.
14
+ const prev = chains.get(rec.session);
15
+ // Admission counts immediately, including while waiting behind another turn.
28
16
  const workDone = beginWork();
29
- const prev = chains.get(rec.session) ?? Promise.resolve();
30
- const task = async () => {
31
- try {
32
- await run(rec);
33
- }
34
- catch (e) {
35
- log.error(`${label} turn runner rejected (session=${rec.session}; own your error surface in run()): ${String(e)}`);
36
- }
37
- };
38
- const next = prev.then(task, task); // run after this session's previous turn, in arrival order
39
- chains.set(rec.session, next);
40
- void next.finally(() => {
17
+ const fiber = Effect.runFork(Effect.scoped(Effect.gen(function* () {
18
+ // Publish the tail before execution can finish or submit another turn.
19
+ yield* Effect.yieldNow;
20
+ if (prev)
21
+ yield* Fiber.await(prev);
22
+ yield* run(rec);
23
+ })).pipe(Effect.catchCause((cause) => Effect.sync(() => log.error(`${label} turn runner rejected (session=${rec.session}; own your error surface in run()): ${String(portError(cause))}`))), Effect.ensuring(Effect.sync(() => {
41
24
  workDone();
42
- if (chains.get(rec.session) === next)
43
- chains.delete(rec.session); // drop the entry when drained
44
- });
25
+ if (chains.get(rec.session) === fiber)
26
+ chains.delete(rec.session);
27
+ }))));
28
+ chains.set(rec.session, fiber);
45
29
  },
46
- async idle() {
47
- // Await outstanding chains until none remain — a chain may schedule a follow-up turn, and each
48
- // deletes its own map entry on settle, so an emptied map means every turn ran to completion. The
49
- // tasks catch their own rejections, but allSettled keeps idle() itself total regardless.
30
+ idle: () => Effect.runPromise(Effect.gen(function* () {
31
+ // A finishing turn may enqueue more work.
50
32
  while (chains.size > 0)
51
- await Promise.allSettled([...chains.values()]);
52
- },
33
+ yield* Fiber.awaitAll([...chains.values()]);
34
+ })),
53
35
  };
54
36
  }
@@ -1,7 +1,13 @@
1
+ /** The durable-turn LIFECYCLE the stateful chat channels share, over the kit's parts. */
2
+ import * as Effect from "effect/Effect";
3
+ import type * as Scope from "effect/Scope";
4
+ import { type PortFailure } from "../../effect-port.ts";
1
5
  import type { ContextBuffer } from "./context-buffer.ts";
2
6
  import { type TurnRecordBase, type TurnStore } from "./turn-store.ts";
3
- /** A pending turn is the persisted intent minus its attempt count, plus live-only fields the
4
- * channel adds (a notice's message id) — never persisted, reconstructed fresh on replay. */
7
+ /**
8
+ * A pending turn is the persisted intent minus its attempt count, plus live-only fields the channel adds (a notice's
9
+ * message id).
10
+ */
5
11
  export type PendingBase<S extends TurnRecordBase> = Omit<S, "attempts">;
6
12
  export interface TurnRunnerOptions<R extends PendingBase<S>, S extends TurnRecordBase, E> {
7
13
  label: string;
@@ -19,40 +25,48 @@ export interface TurnRunnerOptions<R extends PendingBase<S>, S extends TurnRecor
19
25
  bufferKey(rec: R): string;
20
26
  /** The place, for the lifecycle log line (`chat=… thread=…`). */
21
27
  where(rec: R): string;
22
- /** Queue feedback when a turn is scheduled BEHIND an active one. Returns what the runner awaits at
23
- * dequeue (so the turn reliably takes the notice over instead of racing it) and, optionally, how
24
- * to cancel a notice that has not fired yet. `done` may reject — posting the notice is a platform
25
- * call — and the runner logs that and runs the turn anyway. */
28
+ /** Queue feedback when a turn is scheduled BEHIND an active one. */
26
29
  onQueuedBehind?(rec: R): {
27
30
  done: Promise<void>;
28
31
  cancel?: () => void;
29
32
  };
30
- /** Runs before the attempt is counted. Answer false to leave the intent untouched for a later run
31
- * (Slack: its transport is known to be down, so an Agent turn now would have nowhere to answer). */
33
+ /** Runs before the attempt is counted. */
32
34
  beforeRun?(rec: R): Promise<boolean>;
33
- /** The attempt could not be recorded (disk failure): a restart replays the turn, so say so on any
34
- * notice it holds rather than leaving it pinned at "Queued". */
35
+ /**
36
+ * The attempt could not be recorded (disk failure): a restart replays the turn, so say so on any notice it holds
37
+ * rather than leaving it pinned at "Queued".
38
+ */
35
39
  onDeferred(rec: R): void;
36
40
  /** The turn started the ceiling's worth of times without finishing: tell the asker. */
37
41
  notifyDropped(rec: R): void;
38
- /** Run the turn. `onCompleted` is the durable-commit point (the turn's `completed` event): it drops
39
- * the intent and commits the folded discussion, in that order. A throw is logged as the turn's
40
- * failure; the intent is dropped either way. */
41
42
  execute(rec: R, discussion: {
42
43
  text: string;
43
44
  consumed: E[];
44
- }, onCompleted: () => void): Promise<void>;
45
+ },
46
+ /** Called with the finished reply just before it is delivered — the point the answer becomes recoverable. */
47
+ onAnswered: (answer: string) => void): Effect.Effect<void, PortFailure, Scope.Scope>;
48
+ /**
49
+ * Deliver an answer a previous run generated but never confirmed delivering: no model, no tools, and no live
50
+ * preview — the one the answer was written for died with its process.
51
+ *
52
+ * A notice THIS process put up is a different thing and must still be settled: a record recovered behind another
53
+ * turn in the same session goes through `onQueuedBehind` like any other, so it can hold a fresh "queued" message
54
+ * or status that only this call can take over or clear.
55
+ */
56
+ deliverAnswer(rec: R, answer: string): Effect.Effect<void, PortFailure, Scope.Scope>;
45
57
  }
46
58
  export interface TurnRunner<R, S> {
47
- /** Accept a turn: persist its intent (pre-ACK — a failed write throws so the platform redelivers),
48
- * record the delivery id, enqueue. Recovery re-enqueues without re-persisting. */
59
+ /**
60
+ * Accept a turn: persist its intent (pre-ACK — a failed write throws so the platform redelivers), record the
61
+ * delivery id, enqueue.
62
+ */
49
63
  submit(rec: R, persist: boolean): void;
50
- /** Re-enqueue the turns a prior crash left mid-flight; returns them so a channel can continue its
51
- * arrival counter. */
64
+ /** Re-enqueue the turns a prior crash left mid-flight; returns them so a channel can continue its arrival counter. */
52
65
  recover(): S[];
53
66
  /** Resolve once no turn is in flight — the test/observability seam. */
54
67
  idle(): Promise<void>;
55
68
  }
69
+ export declare function runQueuedTurn<R extends PendingBase<S>, S extends TurnRecordBase, E>(options: TurnRunnerOptions<R, S, E>, rec: R): Effect.Effect<void, PortFailure>;
56
70
  export declare function createTurnRunner<R extends PendingBase<S> & {
57
71
  id: string;
58
72
  session: string;
@@ -1,66 +1,111 @@
1
- /**
2
- * The durable-turn LIFECYCLE the stateful chat channels share, over the kit's parts: accept
3
- * (persist pre-ACK, dedup, enqueue) → dequeue (settle the queue notice, count the attempt against
4
- * the poison ceiling, fold the buffered discussion) → execute → end (log, drop the intent). Telegram,
5
- * Slack and Feishu each wrote this out; the copies had already drifted in small ways that were not
6
- * decisions (which one deletes its notice on defer, which one logs the duration on failure).
7
- *
8
- * What stays with the platform is everything that names a platform object: how a queue notice is
9
- * mounted and taken over, what the prompt looks like, how attachments resolve, what a dropped turn
10
- * says and where. Those arrive as hooks; the ORDER they run in is this module's.
11
- */
1
+ /** The durable-turn LIFECYCLE the stateful chat channels share, over the kit's parts. */
2
+ import * as Effect from "effect/Effect";
3
+ import * as Fiber from "effect/Fiber";
12
4
  import { log } from "../../log.js";
5
+ import { portError, portJoin } from "../../effect-port.js";
13
6
  import { createTurnQueue } from "./turn-queue.js";
14
7
  import { commitAnsweredTurn } from "./turn-store.js";
8
+ export function runQueuedTurn(options, rec) {
9
+ return Effect.gen(function* () {
10
+ const { label, store, buffer, beforeRun } = options;
11
+ if (beforeRun && !(yield* portJoin(() => beforeRun(rec))))
12
+ return;
13
+ const decision = store.startAttempt(rec.id);
14
+ if (decision === "exceeded") {
15
+ const stranded = rec.answer;
16
+ if (stranded === undefined) {
17
+ options.notifyDropped(rec);
18
+ return;
19
+ }
20
+ // The ceiling is about EXECUTION — a turn that may be crashing the process must stop being run. Delivering a
21
+ // recorded answer costs one message and no model call, so the record the store just dropped gets one last
22
+ // send instead of "please ask again" over an answer that exists.
23
+ return yield* Effect.scoped(options.deliverAnswer(rec, stranded)).pipe(Effect.matchEffect({
24
+ // The store has already said, at error level, that this turn will not be run again. Silence after that
25
+ // reads as "nothing happened"; this line is what distinguishes it from a delivered answer.
26
+ onSuccess: () => Effect.sync(() => log.info(`${label} turn ${rec.id} hit the execution ceiling, but the answer it had already recorded was ` +
27
+ `delivered (session=${rec.session})`)),
28
+ onFailure: (error) => Effect.sync(() => {
29
+ log.error(`${label} turn ${rec.id} hit the execution ceiling and its recorded answer could not be delivered ` +
30
+ `either (session=${rec.session}) — the answer is gone: ${String(error.cause)}`);
31
+ // The record is off disk, so nothing will retry this. The asker is owed an ending — without one, a
32
+ // queue notice this turn put up stays in the chat forever reading "Queued".
33
+ options.notifyDropped(rec);
34
+ }),
35
+ }));
36
+ }
37
+ if (decision === "defer") {
38
+ options.onDeferred(rec);
39
+ return;
40
+ }
41
+ const startedAt = Date.now();
42
+ // A recovered answer skips the buffer entirely: its discussion was committed when the answer was recorded, and
43
+ // peeking again would consume entries this turn never folded in.
44
+ const recovered = rec.answer;
45
+ let answered = recovered !== undefined;
46
+ // One stable prefix, so every `turn done:`/`turn failed:` has a `turn start:` to grep back to; what kind of work
47
+ // it is rides along as a field.
48
+ log.info(`${label} turn start: turn=${rec.id} session=${rec.session} ${options.where(rec)}` +
49
+ `${recovered === undefined ? "" : " mode=re-delivery (answer recovered from a prior run)"}`);
50
+ const work = recovered !== undefined
51
+ ? Effect.suspend(() => options.deliverAnswer(rec, recovered))
52
+ : Effect.suspend(() => {
53
+ const bufferKey = options.bufferKey(rec);
54
+ const discussion = buffer.peek(bufferKey);
55
+ return options.execute(rec, discussion, (answer) => {
56
+ // Only a recorded answer is recoverable — an untracked run has no record to keep it in.
57
+ answered = commitAnsweredTurn(store, buffer, {
58
+ id: rec.id,
59
+ bufferKey,
60
+ consumed: discussion.consumed,
61
+ answer,
62
+ });
63
+ });
64
+ });
65
+ const delivered = yield* Effect.scoped(work).pipe(Effect.matchEffect({
66
+ onSuccess: () => Effect.sync(() => {
67
+ log.info(`${label} turn done: turn=${rec.id} session=${rec.session} (${Date.now() - startedAt}ms)`);
68
+ return true;
69
+ }),
70
+ onFailure: (error) => Effect.sync(() => {
71
+ log.error(`${label} turn failed: turn=${rec.id} session=${rec.session} (${Date.now() - startedAt}ms): ${String(error.cause)}`);
72
+ return false;
73
+ }),
74
+ }));
75
+ // An answer that exists but did not reach the chat is the one failure worth another start: re-delivering it costs
76
+ // one message and no model call, and `startAttempt` bounds how often that is tried. Everything else — delivered,
77
+ // or failed before there was an answer — is done here. Interruption never reaches this removal.
78
+ if (delivered || !answered) {
79
+ store.remove(rec.id);
80
+ return;
81
+ }
82
+ log.warn(`${label} turn ${rec.id} produced an answer that was not delivered (session=${rec.session}) — ` +
83
+ `keeping it to re-deliver on the next start`);
84
+ });
85
+ }
15
86
  export function createTurnRunner(options) {
16
- const { label, store, buffer, seen, onQueuedBehind } = options;
87
+ const { label, store, seen, onQueuedBehind } = options;
17
88
  const notices = new Map();
18
89
  const queue = createTurnQueue({
19
90
  label,
20
- onQueuedBehind: onQueuedBehind && ((rec) => notices.set(rec.id, onQueuedBehind(rec))),
21
- run: async (rec) => {
22
- // Runs at DEQUEUE time (serialized). The queue wait is over: cancel a notice that has not
23
- // fired, then settle so the turn's preview handle is final — in the common path this await is
24
- // instant. BEFORE the ceiling check so a dropped or deferred turn can take the notice over too.
91
+ onQueuedBehind: onQueuedBehind &&
92
+ ((rec) => {
93
+ const notice = onQueuedBehind(rec);
94
+ // Observe rejection at acceptance, even if dequeue is minutes away.
95
+ const done = Effect.runFork(portJoin(() => notice.done).pipe(Effect.catchCause((cause) => Effect.sync(() => log.warn(`${label} queue notice failed: turn=${rec.id} session=${rec.session}: ${String(portError(cause))}`)))));
96
+ notices.set(rec.id, { done, cancel: notice.cancel });
97
+ }),
98
+ run: (rec) => Effect.gen(function* () {
25
99
  const notice = notices.get(rec.id);
26
- notice?.cancel?.();
27
- // The notice is the PLATFORM's feedback, not the turn: a failed post must not throw out of the
28
- // run, which would leak the persisted intent (removed only below) into a replay that burns an
29
- // attempt against the ceiling. Logged, then the turn proceeds without its handle.
30
- await notice?.done.catch((error) => log.warn(`${label} queue notice failed: turn=${rec.id} session=${rec.session}: ${String(error)}`));
31
100
  notices.delete(rec.id);
32
- if (options.beforeRun && !(await options.beforeRun(rec)))
33
- return;
34
- const decision = store.startAttempt(rec.id);
35
- if (decision === "exceeded") {
36
- options.notifyDropped(rec);
37
- return;
101
+ if (notice) {
102
+ // A broken cancel hook must still join any post already in flight.
103
+ yield* Effect.addFinalizer(() => Fiber.await(notice.done));
104
+ notice.cancel?.();
105
+ yield* Fiber.await(notice.done);
38
106
  }
39
- if (decision === "defer") {
40
- options.onDeferred(rec);
41
- return;
42
- }
43
- const startedAt = Date.now();
44
- log.info(`${label} turn start: turn=${rec.id} session=${rec.session} ${options.where(rec)}`);
45
- // Snapshot the discussion at dequeue; commit only this snapshot on `completed`, so a message
46
- // arriving while the turn runs stays buffered for the next answered turn.
47
- const bufferKey = options.bufferKey(rec);
48
- const discussion = buffer.peek(bufferKey);
49
- try {
50
- await options.execute(rec, discussion, () => commitAnsweredTurn(store, buffer, { id: rec.id, bufferKey, consumed: discussion.consumed }));
51
- log.info(`${label} turn done: turn=${rec.id} session=${rec.session} (${Date.now() - startedAt}ms)`);
52
- }
53
- catch (error) {
54
- log.error(`${label} turn failed: turn=${rec.id} session=${rec.session} (${Date.now() - startedAt}ms): ${String(error)}`);
55
- }
56
- finally {
57
- // Fallback removal for the caught-error paths (a `failed` event or a transport throw): those
58
- // never reach the completed hook. Idempotent. Only an INTERRUPTED run (this finally never
59
- // runs — a crash or SIGTERM deploy) leaves the record for replay; a transport throw is
60
- // dropped, not retried (safe retry needs an L2 delivery key).
61
- store.remove(rec.id);
62
- }
63
- },
107
+ yield* runQueuedTurn(options, rec);
108
+ }),
64
109
  });
65
110
  const submit = (rec, persist) => {
66
111
  if (persist) {
@@ -1,58 +1,58 @@
1
1
  import type { ContextBuffer } from "./context-buffer.ts";
2
- /** What every persisted turn record carries regardless of channel: identity, the session whose FIFO
3
- * chain it runs on, and how many times it has STARTED executing without finishing (0 until its first
4
- * run; bumped at each `startAttempt`). The channel's record type extends this with everything its
5
- * runner needs to re-execute the turn — a new execution field added there propagates into the
6
- * persisted record by construction. */
2
+ /** What every persisted turn record carries regardless of channel. */
7
3
  export interface TurnRecordBase {
8
4
  id: string;
9
5
  session: string;
10
6
  attempts: number;
7
+ /**
8
+ * The completed reply, recorded BEFORE it is delivered. Its presence is the difference between the two things a
9
+ * pending record can mean: absent = the turn still has to run, present = the model already ran and only delivery
10
+ * is owed. A restart therefore re-delivers an answer instead of paying for it again.
11
+ */
12
+ answer?: string;
11
13
  }
12
14
  export interface TurnStore<T extends TurnRecordBase> {
13
- /** Persist an accepted turn before the ACK. A failed write throws (→ HTTP response / WS ACK 500, so the platform redelivers). */
15
+ /** Persist an accepted turn before the ACK. */
14
16
  add(rec: T): void;
15
- /** Remove a finished turn. Post-ACK: a failed write is logged, never thrown (must not abort delivery). */
17
+ /**
18
+ * Record the completed reply so a restart can deliver it without running the turn again. `false` = there was no
19
+ * record to write it to (an untracked run), so this answer has no recovery copy.
20
+ */
21
+ answered(id: string, answer: string): boolean;
16
22
  remove(id: string): void;
17
- /** Every persisted turn a crash left behind, in ARRIVAL order (the channel's `order`), to re-enqueue
18
- * on the next start. Read-only — the ceiling is enforced per turn at `startAttempt`, so a never-run
19
- * turn's budget is untouched by a restart. Order matters: the queue rebuilds each session's FIFO
20
- * chain from re-enqueue order. */
23
+ /**
24
+ * Every persisted turn a crash left behind, in ARRIVAL order (the channel's `order`), to re-enqueue on the next
25
+ * start.
26
+ */
21
27
  recover(): T[];
22
- /** Called when a turn is about to RUN (dequeued). Returns:
23
- * - "run": bumped its persisted execution count; go ahead.
24
- * - "exceeded": over {@link MAX_TURN_ATTEMPTS} starts without finishing (killed mid-run every time,
25
- * whatever the cause); the record is dropped and the runner notifies the asker.
26
- * - "defer": the bump could not be persisted — skip this cycle (fail closed: an unpersisted count
27
- * would let a poison turn re-run forever); the record stays on disk and replays on the next start
28
- * (a restart is required — disk recovery alone does not re-run it). The runner does NOT notify.
29
- * An id with no record returns "run" (untracked): a completed turn's `remove` cleared it, so the
30
- * redelivery-double-run tail (see the header's pre-ACK window) lands here. */
28
+ /** Called when a turn is about to RUN (dequeued). */
31
29
  startAttempt(id: string): "run" | "exceeded" | "defer";
32
30
  }
33
31
  export interface TurnStoreOptions<T extends TurnRecordBase> {
34
32
  /** Log prefix naming the consumer (e.g. "[telegram]") — the store itself is channel-neutral. */
35
33
  label: string;
36
- /** Shape validation at the IO boundary: valid JSON of the WRONG SHAPE must degrade like a corrupt
37
- * file (warn + empty), not flow in as trusted data. */
34
+ /**
35
+ * Shape validation at the IO boundary: valid JSON of the WRONG SHAPE must degrade like a corrupt file (warn +
36
+ * empty), not flow in as trusted data.
37
+ */
38
38
  isRecord: (t: unknown) => t is T;
39
- /** Arrival order for {@link TurnStore.recover} — the channel knows what its ids/fields encode
40
- * (telegram: numeric update_id; lark: an explicit per-record seq). */
39
+ /**
40
+ * Arrival order for {@link TurnStore.recover} — the channel knows what its ids/fields encode (telegram: numeric
41
+ * update_id; lark: an explicit per-record seq).
42
+ */
41
43
  order: (a: T, b: T) => number;
42
44
  }
43
45
  /**
44
- * End an ANSWERED turn: drop its durable intent, then commit the discussion it folded in.
46
+ * An ANSWERED turn: record the reply for delivery, then commit the discussion it folded in. The intent is NOT
47
+ * dropped here — generating an answer is not the same event as that answer reaching the chat, and the runner drops
48
+ * the record only once delivery has settled.
45
49
  *
46
- * The ORDER is the safety property, which is why this is a function and not two lines at each call
47
- * site. A crash between the two writes may re-fold already-answered context into the next summon —
48
- * additive and harmless. The reverse order leaves intent on disk with its context already consumed,
49
- * so the replay runs the same turn with its context stripped.
50
- *
51
- * Called from the turn's `completed` event, when the fold provably lives in the durable session.
50
+ * Returns whether the answer became recoverable, so a caller does not claim a recovery that has nothing on disk.
52
51
  */
53
52
  export declare function commitAnsweredTurn<T extends TurnRecordBase, E>(store: TurnStore<T>, buffer: ContextBuffer<E>, turn: {
54
53
  id: string;
55
54
  bufferKey: string;
56
55
  consumed: E[];
57
- }): void;
56
+ answer: string;
57
+ }): boolean;
58
58
  export declare function createTurnStore<T extends TurnRecordBase>(path: string, opts: TurnStoreOptions<T>): TurnStore<T>;