@fastagent-sh/fastagent 0.21.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/README.md +9 -12
  2. package/dist/agent.d.ts +24 -37
  3. package/dist/agent.js +7 -15
  4. package/dist/atomic-write.d.ts +13 -17
  5. package/dist/atomic-write.js +18 -29
  6. package/dist/bind.d.ts +12 -22
  7. package/dist/bind.js +18 -27
  8. package/dist/channel.d.ts +11 -33
  9. package/dist/channels/agentcore-limits.d.ts +2 -13
  10. package/dist/channels/agentcore-limits.js +2 -13
  11. package/dist/channels/agentcore-protocol.d.ts +67 -58
  12. package/dist/channels/agentcore-protocol.js +23 -15
  13. package/dist/channels/agentcore-service.d.ts +19 -33
  14. package/dist/channels/agentcore-service.js +176 -59
  15. package/dist/channels/agentcore.d.ts +39 -33
  16. package/dist/channels/agentcore.js +90 -224
  17. package/dist/channels/body.d.ts +15 -2
  18. package/dist/channels/body.js +24 -2
  19. package/dist/channels/busy.d.ts +1 -21
  20. package/dist/channels/busy.js +2 -39
  21. package/dist/channels/control.d.ts +17 -62
  22. package/dist/channels/control.js +74 -182
  23. package/dist/channels/define-channel.d.ts +39 -0
  24. package/dist/channels/define-channel.js +9 -0
  25. package/dist/channels/discover.d.ts +10 -31
  26. package/dist/channels/discover.js +37 -31
  27. package/dist/channels/feishu/bootstrap-token.d.ts +1 -8
  28. package/dist/channels/feishu/bootstrap-token.js +7 -23
  29. package/dist/channels/feishu/card.d.ts +14 -28
  30. package/dist/channels/feishu/card.js +16 -30
  31. package/dist/channels/feishu/cloud.d.ts +1 -5
  32. package/dist/channels/feishu/context-buffer.d.ts +4 -23
  33. package/dist/channels/feishu/context-buffer.js +8 -31
  34. package/dist/channels/feishu/crypto.d.ts +10 -5
  35. package/dist/channels/feishu/crypto.js +12 -19
  36. package/dist/channels/feishu/feishu-api.d.ts +2 -1
  37. package/dist/channels/feishu/feishu-api.js +5 -4
  38. package/dist/channels/feishu/feishu.d.ts +4 -10
  39. package/dist/channels/feishu/feishu.js +113 -227
  40. package/dist/channels/feishu/invoke-turn.d.ts +5 -4
  41. package/dist/channels/feishu/invoke-turn.js +36 -54
  42. package/dist/channels/feishu/model.d.ts +4 -21
  43. package/dist/channels/feishu/model.js +1 -8
  44. package/dist/channels/feishu/normalize.d.ts +2 -10
  45. package/dist/channels/feishu/normalize.js +7 -42
  46. package/dist/channels/feishu/parse.d.ts +9 -29
  47. package/dist/channels/feishu/parse.js +8 -26
  48. package/dist/channels/feishu/preview.d.ts +12 -14
  49. package/dist/channels/feishu/preview.js +108 -207
  50. package/dist/channels/feishu/register-app.d.ts +8 -23
  51. package/dist/channels/feishu/register-app.js +7 -20
  52. package/dist/channels/feishu/register-webhook.d.ts +2 -9
  53. package/dist/channels/feishu/register-webhook.js +9 -33
  54. package/dist/channels/feishu/scaffold/channel.ts +27 -19
  55. package/dist/channels/feishu/scaffold/channel.websocket.ts +31 -0
  56. package/dist/channels/feishu/setup-mode.d.ts +11 -36
  57. package/dist/channels/feishu/setup-mode.js +7 -26
  58. package/dist/channels/feishu/ws-ingress.d.ts +1 -2
  59. package/dist/channels/feishu/ws-ingress.js +6 -8
  60. package/dist/channels/http.d.ts +15 -15
  61. package/dist/channels/http.js +19 -9
  62. package/dist/channels/kit/attachment-path.d.ts +4 -5
  63. package/dist/channels/kit/attachment-path.js +10 -34
  64. package/dist/channels/kit/context-buffer.d.ts +14 -21
  65. package/dist/channels/kit/context-buffer.js +25 -38
  66. package/dist/channels/kit/delivery.d.ts +35 -0
  67. package/dist/channels/kit/delivery.js +129 -0
  68. package/dist/channels/kit/event-stream.d.ts +5 -0
  69. package/dist/channels/kit/event-stream.js +29 -0
  70. package/dist/channels/kit/invoke-turn-kit.d.ts +53 -26
  71. package/dist/channels/kit/invoke-turn-kit.js +89 -32
  72. package/dist/channels/kit/preview-kit.d.ts +18 -72
  73. package/dist/channels/kit/preview-kit.js +22 -88
  74. package/dist/channels/kit/signature.d.ts +3 -9
  75. package/dist/channels/kit/signature.js +3 -9
  76. package/dist/channels/kit/state.d.ts +1 -2
  77. package/dist/channels/kit/state.js +5 -14
  78. package/dist/channels/kit/stop-command.d.ts +1 -2
  79. package/dist/channels/kit/stop-command.js +6 -9
  80. package/dist/channels/kit/tasks.d.ts +1 -1
  81. package/dist/channels/kit/tasks.js +8 -21
  82. package/dist/channels/kit/text.d.ts +2 -16
  83. package/dist/channels/kit/text.js +23 -31
  84. package/dist/channels/kit/thread-participants.d.ts +4 -17
  85. package/dist/channels/kit/thread-participants.js +8 -55
  86. package/dist/channels/kit/transport.d.ts +26 -0
  87. package/dist/channels/kit/transport.js +20 -0
  88. package/dist/channels/kit/turn-queue.d.ts +7 -11
  89. package/dist/channels/kit/turn-queue.js +21 -39
  90. package/dist/channels/kit/turn-runner.d.ts +32 -18
  91. package/dist/channels/kit/turn-runner.js +98 -53
  92. package/dist/channels/kit/turn-store.d.ts +32 -32
  93. package/dist/channels/kit/turn-store.js +45 -88
  94. package/dist/channels/lark/lark.d.ts +1 -5
  95. package/dist/channels/lark/onboard.d.ts +3 -12
  96. package/dist/channels/lark/onboard.js +3 -13
  97. package/dist/channels/lark/scaffold/channel.ts +27 -19
  98. package/dist/channels/lark/scaffold/channel.websocket.ts +31 -0
  99. package/dist/channels/registration.d.ts +9 -35
  100. package/dist/channels/registration.js +6 -37
  101. package/dist/channels/secret.js +2 -5
  102. package/dist/channels/serve.d.ts +47 -44
  103. package/dist/channels/serve.js +165 -101
  104. package/dist/channels/slack/config-api.d.ts +4 -27
  105. package/dist/channels/slack/config-api.js +5 -34
  106. package/dist/channels/slack/context-buffer.d.ts +2 -3
  107. package/dist/channels/slack/context-buffer.js +5 -5
  108. package/dist/channels/slack/invoke-turn.d.ts +3 -1
  109. package/dist/channels/slack/invoke-turn.js +25 -34
  110. package/dist/channels/slack/manifest.js +1 -3
  111. package/dist/channels/slack/model.d.ts +1 -2
  112. package/dist/channels/slack/model.js +1 -1
  113. package/dist/channels/slack/onboard.d.ts +4 -3
  114. package/dist/channels/slack/onboard.js +8 -11
  115. package/dist/channels/slack/onboarding-state.d.ts +3 -5
  116. package/dist/channels/slack/onboarding-state.js +9 -6
  117. package/dist/channels/slack/parse.d.ts +4 -13
  118. package/dist/channels/slack/parse.js +7 -28
  119. package/dist/channels/slack/preview.d.ts +12 -2
  120. package/dist/channels/slack/preview.js +292 -269
  121. package/dist/channels/slack/reaction.d.ts +11 -3
  122. package/dist/channels/slack/reaction.js +19 -8
  123. package/dist/channels/slack/register-webhook.js +4 -7
  124. package/dist/channels/slack/scaffold/channel.ts +20 -13
  125. package/dist/channels/slack/scaffold/slack-send.ts +2 -2
  126. package/dist/channels/slack/setup-server.d.ts +1 -5
  127. package/dist/channels/slack/setup-server.js +1 -5
  128. package/dist/channels/slack/shared-api.d.ts +1 -4
  129. package/dist/channels/slack/shared-api.js +2 -13
  130. package/dist/channels/slack/slack-api.d.ts +2 -1
  131. package/dist/channels/slack/slack-api.js +6 -4
  132. package/dist/channels/slack/slack.d.ts +11 -14
  133. package/dist/channels/slack/slack.js +121 -122
  134. package/dist/channels/sse.d.ts +1 -1
  135. package/dist/channels/sse.js +1 -1
  136. package/dist/channels/telegram/context-buffer.d.ts +7 -22
  137. package/dist/channels/telegram/context-buffer.js +6 -23
  138. package/dist/channels/telegram/invoke-turn.d.ts +7 -7
  139. package/dist/channels/telegram/invoke-turn.js +24 -43
  140. package/dist/channels/telegram/parse.d.ts +24 -51
  141. package/dist/channels/telegram/parse.js +32 -84
  142. package/dist/channels/telegram/preview.d.ts +10 -1
  143. package/dist/channels/telegram/preview.js +79 -100
  144. package/dist/channels/telegram/register-webhook.js +5 -23
  145. package/dist/channels/telegram/scaffold/channel.ts +25 -18
  146. package/dist/channels/telegram/scaffold/telegram-send.ts +6 -4
  147. package/dist/channels/telegram/telegram-api.d.ts +4 -3
  148. package/dist/channels/telegram/telegram-api.js +9 -7
  149. package/dist/channels/telegram/telegram.d.ts +4 -18
  150. package/dist/channels/telegram/telegram.js +38 -94
  151. package/dist/channels/telegram/turn-store.d.ts +11 -14
  152. package/dist/channels/telegram/turn-store.js +8 -6
  153. package/dist/channels/wait-health.d.ts +4 -6
  154. package/dist/channels/wait-health.js +10 -14
  155. package/dist/cli/add-feishu.d.ts +2 -12
  156. package/dist/cli/add-feishu.js +24 -71
  157. package/dist/cli/add-slack.d.ts +5 -3
  158. package/dist/cli/add-slack.js +53 -76
  159. package/dist/cli/auth-view.d.ts +2 -16
  160. package/dist/cli/auth-view.js +2 -16
  161. package/dist/cli/commands/add.js +25 -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 +209 -244
  275. package/dist/engines/pi/login.d.ts +95 -35
  276. package/dist/engines/pi/login.js +259 -107
  277. package/dist/engines/pi/machine.d.ts +31 -0
  278. package/dist/engines/pi/machine.js +106 -0
  279. package/dist/engines/pi/models.d.ts +70 -89
  280. package/dist/engines/pi/models.js +188 -81
  281. package/dist/engines/pi/open.d.ts +65 -53
  282. package/dist/engines/pi/open.js +129 -69
  283. package/dist/engines/pi/report.d.ts +3 -12
  284. package/dist/engines/pi/report.js +2 -16
  285. package/dist/engines/pi/search-tools.d.ts +1 -9
  286. package/dist/engines/pi/search-tools.js +26 -57
  287. package/dist/engines/pi/service.d.ts +2 -16
  288. package/dist/engines/pi/service.js +2 -16
  289. package/dist/engines/pi/session-builder.d.ts +5 -9
  290. package/dist/engines/pi/session-builder.js +44 -82
  291. package/dist/engines/pi/session-control.js +286 -269
  292. package/dist/engines/pi/session-effects.d.ts +14 -0
  293. package/dist/engines/pi/session-effects.js +30 -0
  294. package/dist/engines/pi/session-inheritance.d.ts +9 -18
  295. package/dist/engines/pi/session-inheritance.js +103 -160
  296. package/dist/engines/pi/session-markers.d.ts +31 -30
  297. package/dist/engines/pi/session-markers.js +26 -25
  298. package/dist/engines/pi/session-settings.d.ts +6 -22
  299. package/dist/engines/pi/session-settings.js +10 -21
  300. package/dist/engines/pi/session-store.d.ts +26 -92
  301. package/dist/engines/pi/session-store.js +96 -310
  302. package/dist/engines/pi/tool-context.d.ts +17 -45
  303. package/dist/engines/pi/tool-context.js +7 -26
  304. package/dist/engines/pi/tool.d.ts +45 -36
  305. package/dist/engines/pi/tool.js +43 -57
  306. package/dist/engines/pi/turn-kit.d.ts +14 -52
  307. package/dist/engines/pi/turn-kit.js +18 -67
  308. package/dist/engines/pi/wake-tool.d.ts +2 -10
  309. package/dist/engines/pi/wake-tool.js +7 -27
  310. package/dist/env.d.ts +27 -28
  311. package/dist/env.js +45 -50
  312. package/dist/index.js +0 -2
  313. package/dist/lark.d.ts +1 -2
  314. package/dist/lark.js +1 -2
  315. package/dist/loader.d.ts +14 -55
  316. package/dist/loader.js +24 -43
  317. package/dist/log.d.ts +2 -12
  318. package/dist/log.js +3 -24
  319. package/dist/node.d.ts +2 -15
  320. package/dist/node.js +2 -18
  321. package/dist/observe.d.ts +2 -8
  322. package/dist/open-url.d.ts +1 -1
  323. package/dist/open-url.js +1 -1
  324. package/dist/paths.d.ts +70 -134
  325. package/dist/paths.js +165 -232
  326. package/dist/pi.d.ts +4 -6
  327. package/dist/pi.js +3 -3
  328. package/dist/proxy.d.ts +16 -6
  329. package/dist/proxy.js +52 -16
  330. package/dist/runtime.d.ts +18 -12
  331. package/dist/runtime.js +18 -11
  332. package/dist/scaffold/add-channel.d.ts +14 -31
  333. package/dist/scaffold/add-channel.js +48 -112
  334. package/dist/scaffold/init.d.ts +9 -31
  335. package/dist/scaffold/init.js +45 -138
  336. package/dist/scaffold/templates/env.example +6 -4
  337. package/dist/scaffold/templates/fastagent.config.ts +36 -0
  338. package/dist/scaffold/templates.d.ts +3 -3
  339. package/dist/scaffold/templates.js +5 -8
  340. package/dist/scaffold/vendor-skill.d.ts +2 -5
  341. package/dist/scaffold/vendor-skill.js +19 -29
  342. package/dist/schedule/cron.d.ts +9 -5
  343. package/dist/schedule/cron.js +9 -11
  344. package/dist/schedule/discover.d.ts +12 -12
  345. package/dist/schedule/discover.js +43 -34
  346. package/dist/schedule/routine.d.ts +43 -0
  347. package/dist/schedule/routine.js +32 -0
  348. package/dist/schedule/run.d.ts +55 -0
  349. package/dist/schedule/run.js +146 -0
  350. package/dist/schedule/scheduler.d.ts +44 -55
  351. package/dist/schedule/scheduler.js +291 -265
  352. package/dist/schedule/state.d.ts +105 -10
  353. package/dist/schedule/state.js +293 -19
  354. package/dist/schedule/wake-alarm.d.ts +10 -23
  355. package/dist/schedule/wake-alarm.js +91 -121
  356. package/dist/schedule/wakeups.d.ts +23 -39
  357. package/dist/schedule/wakeups.js +33 -75
  358. package/dist/secrets-gate.d.ts +32 -0
  359. package/dist/secrets-gate.js +33 -0
  360. package/dist/service.d.ts +137 -98
  361. package/dist/service.js +250 -252
  362. package/dist/session-remote.d.ts +33 -44
  363. package/dist/session-remote.js +203 -192
  364. package/dist/session.d.ts +153 -228
  365. package/dist/session.js +33 -55
  366. package/dist/tunnel.d.ts +8 -36
  367. package/dist/tunnel.js +24 -65
  368. package/dist/version.d.ts +2 -2
  369. package/dist/version.js +2 -2
  370. package/package.json +10 -16
  371. package/dist/channels/agentcore-state.d.ts +0 -77
  372. package/dist/channels/agentcore-state.js +0 -276
  373. package/dist/channels/github/github.d.ts +0 -31
  374. package/dist/channels/github/github.js +0 -89
  375. package/dist/channels/github/scaffold/channel.ts +0 -25
  376. package/dist/cli/commands/attach.d.ts +0 -108
  377. package/dist/cli/commands/attach.js +0 -637
  378. package/dist/cli/commands/fire.d.ts +0 -7
  379. package/dist/cli/commands/fire.js +0 -38
  380. package/dist/cli/commands/schedule.d.ts +0 -12
  381. package/dist/cli/commands/schedule.js +0 -87
  382. package/dist/github.d.ts +0 -3
  383. package/dist/github.js +0 -2
  384. package/dist/scaffold/templates/fastagent.config.mjs +0 -23
  385. package/dist/schedule/audit.d.ts +0 -18
  386. package/dist/schedule/audit.js +0 -57
  387. package/dist/schedule/schedule.d.ts +0 -35
  388. package/dist/schedule/schedule.js +0 -23
package/dist/session.d.ts CHANGED
@@ -1,153 +1,89 @@
1
1
  /**
2
- * Session control plane — the engine-neutral serving extension beside Agent Handler
3
- * (docs/design/session-control.md). Zero dependencies, no engine import, exactly like agent.ts.
4
- *
5
- * `invoke` remains the only data plane: no run exists without one. Everything here observes a run,
6
- * modulates it, or manages the records it leaves behind — and the shape follows which of those a
7
- * call is, not the transport that carries it. A session's PROPERTIES (name, model, thinking level,
8
- * where its leaf points) are updated; things that HAPPEN to a run (steer, abort, compact) are
9
- * actions; the set of sessions is a collection. One verb over all three would make a client spell
10
- * the session id on every call and read "delete" as something dispatched INTO a session that is
11
- * about to stop existing.
2
+ * Session control plane — the engine-neutral serving extension beside Agent Handler (docs/design/session-control.md).
12
3
  */
13
4
  import type { Json, Prompt } from "./agent.ts";
14
5
  export interface SessionControl {
15
6
  capabilities(): SessionCapabilities;
16
- /** The names this agent exposes — what a composer's `/` completion LISTS. A listing, not an
17
- * invocation surface: the data plane takes prompts as text, so what typing one means (expanding
18
- * it, sending "use the X skill", filtering a menu) is the client's business. Sessionless (the
19
- * definition is a deployment fact) but ASYNC, because a definition is allowed to be live: an
20
- * implementation that re-reads it per turn must answer from that same read, or the list and the
21
- * behavior diverge. `[]` is a complete answer, not a missing one; a definition the implementation
22
- * cannot read at all is a deployment fault and MAY reject. */
7
+ /** The names this agent exposes — what a composer's `/` completion LISTS. */
23
8
  commands(): Promise<AgentCommand[]>;
24
9
  sessions: SessionCollection;
25
10
  }
26
- /** The deployment's sessions, as a collection. */
27
11
  export interface SessionCollection {
28
- /** Every session this DEPLOYMENT holds — what a GUI shows as its conversation list, and the only
29
- * call that is not about ONE session. Deployment-level on purpose: a multi-tenant facade in front
30
- * of one deployment MUST NOT expose it, because it answers for every user at once. Such a facade
31
- * does not need it either — `Scope.session` is the Caller's own string, so it already holds the
32
- * mapping this would return (design §5).
33
- *
34
- * The one read that MAY reject: `[]` is a complete answer for a deployment with no sessions, so
35
- * it would be a lie for a store that cannot be enumerated. Every other read stays TOTAL — their
36
- * absent fields are answers a control-less deployment gives too. */
37
- list(): Promise<SessionSummary[]>;
38
12
  /**
39
- * Copy `from`'s history up to entry `at` into a session called `into` — the growth verb beside
40
- * {@link SessionUpdate.leafEntryId}'s walk, and the two together are what make a session tree
41
- * usable. Cloning is this with the source's own `leafEntryId`.
42
- *
43
- * IDEMPOTENT: `into` is the CALLER's id (the plane never invents one), so repeating a fork that
44
- * already landed is `ok: true` and writes nothing — a client that retries a request whose response
45
- * it never saw does not get a second record. `into` naming a session that exists but came from
46
- * somewhere else rejects `invalid_command`: same id, different history is what the id would then
47
- * be lying about.
48
- *
49
- * Answers a result, not the new session: the caller minted `into` and can {@link get} it.
13
+ * Every session this DEPLOYMENT holds — what a GUI shows as its conversation list, and the only call that is not
14
+ * about ONE session. Deployment-level on purpose: a multi-tenant facade in front of one deployment MUST NOT expose
15
+ * it, because it answers for every user at once. The one read that MAY reject: `[]` is a complete answer for a
16
+ * deployment with no sessions, so it would be a lie for a store that cannot be enumerated. Every other read stays
17
+ * TOTAL.
50
18
  */
19
+ list(): Promise<SessionSummary[]>;
20
+ /** Copy `from`'s history up to entry `at` into a session called `into`. */
51
21
  fork(options: {
52
22
  from: string;
53
23
  at: string;
54
24
  into: string;
55
25
  }): Promise<SessionResult>;
56
- /** Bind an id. A PURE BINDING — an id plus the transport it travels on: no state, no lifecycle,
57
- * nothing to dispose, and it does not check that the session exists (the calls on it answer that,
58
- * each in its own vocabulary). Two handles for one id are interchangeable. */
59
26
  get(session: string): Session;
60
27
  }
61
28
  /**
62
- * Can this id be ADDRESSED by a client? A session id is an opaque Caller string, and the data plane
63
- * takes any of it — but a control plane carries the id as a URL path segment, and three strings are
64
- * not path segments: the empty one, `.` and `..`. URL normalisation eats them before any router
65
- * sees them (`encodeURIComponent` does not help; the spec normalises `%2E` too), so a request for
66
- * `.` arrives as a request for the collection and answers about something else entirely.
67
- *
68
- * The rule lives HERE, in the contract, because both sides enforce it and they must not drift: a
69
- * transport rejects such an id rather than sending a request that will silently address its
70
- * neighbour, and an implementation refuses to MINT one (a fork target nothing could open) — while a
71
- * session a channel already created under one keeps running, and keeps appearing in `list()`, since
72
- * hiding it would be the silent half of the same problem.
29
+ * Can this id be ADDRESSED by a client? URL normalisation eats `""`, `.` and `..` before any router sees them, so a
30
+ * request for `.` would answer about the collection instead. The rule lives in the contract because both sides
31
+ * enforce it and must not drift: a transport refuses to send such an id, and an implementation refuses to MINT one.
73
32
  */
74
33
  export declare function isAddressableSession(session: string): boolean;
75
- /**
76
- * One session, bound. Every call here is about THIS session, so the id is spelled once.
77
- *
78
- * The split inside it is the one the contract is built on: {@link update} sets PROPERTIES (durable,
79
- * last-wins, applied by the next turn), while the action methods do things TO A RUN (admitted or
80
- * rejected now, outcome later on the event stream). {@link SessionResult} says which of the two a
81
- * given answer is.
82
- */
34
+ /** One session, bound. */
83
35
  export interface Session {
84
36
  readonly id: string;
85
37
  state(): Promise<SessionState>;
86
- /** `since` is an APPEND-ORDER position cursor: "every record appended after the one with this
87
- * id", regardless of branch structure. Reconstructing the active path in a branched session is
88
- * the client's job via `parentId` chains from `leafEntryId`. An unknown cursor falls back to a
89
- * full backfill (correct, merely larger). */
38
+ /**
39
+ * `since` is an APPEND-ORDER position cursor: "every record appended after the one with this id", regardless of
40
+ * branch structure.
41
+ */
90
42
  entries(options?: {
91
43
  since?: string;
92
44
  }): Promise<SessionEntries>;
93
- events(): AsyncIterable<SessionEvent>;
94
- /** Set durable session properties. Last-wins, applied by every later turn; an empty patch is a
95
- * no-op that still answers `ok: true`. Fields outside {@link SessionCapabilities.updatable}
96
- * reject `unsupported_capability`; invalid values reject `invalid_command`. Takes the same lease
97
- * as a run (`session_busy` while one is in flight).
98
- *
99
- * VALIDATION is all-or-nothing: a rejected patch leaves nothing behind, which is what makes
100
- * `ok: false` safe to retry. The WRITES need not be one operation — an engine may record each
101
- * property separately — so a failure BETWEEN them answers {@link PARTIAL_UPDATE_CODE}, naming
102
- * what landed, after an event reporting the record as it now is. */
45
+ events(): SessionEventStream;
46
+ /** Set durable session properties. */
103
47
  update(patch: SessionUpdate): Promise<SessionResult>;
104
- /** Join the active run: delivered after the current turn's tool calls, before the next model
105
- * call. Not polyfillable — its delivery point is an engine primitive. */
48
+ /**
49
+ * Join the active run: delivered after the current turn's tool calls, before the next model call. `prompt.text`
50
+ * must not be empty (`invalid_command`): a queued prompt is reported by its text ({@link PendingPrompts}).
51
+ */
106
52
  steer(prompt: Prompt): Promise<SessionResult>;
107
- /** Queue for the active run, FIFO, delivered when it is otherwise idle. */
53
+ /** Queue for the active run, FIFO, delivered when it is otherwise idle. Same non-empty `text` rule as `steer`. */
108
54
  followUp(prompt: Prompt): Promise<SessionResult>;
109
- /** Stop the active run — its queues, its retry delay, its cancellable tool work — or an in-flight
110
- * {@link compact}, which is the same kind of thing: a model call a client must be able to stop. */
55
+ /** Stop the active run — its queues, its retry delay, its cancellable tool work. */
111
56
  abort(): Promise<SessionResult>;
112
- /** Summarize the history at a session boundary. ACCEPT-FAST: a full model call, so `ok: true`
113
- * means admitted and the outcome travels as `compaction_finished{summary|error|aborted}`. */
57
+ /** Summarize the history at a session boundary. */
114
58
  compact(options?: {
115
59
  instructions?: string;
116
60
  }): Promise<SessionResult>;
117
- /** Destroy the record. The plane's only IRREVERSIBLE call, guarded by the same bearer token as
118
- * everything else — the only key the framework owns (design §14). Live {@link events} streams for
119
- * this session END; a later {@link state} answers for a session that no longer exists. */
120
61
  delete(): Promise<SessionResult>;
121
62
  }
122
- /** The durable properties {@link Session.update} sets. Every field is optional and last-wins; which
123
- * ones a deployment accepts is {@link SessionCapabilities.updatable}. */
63
+ /** The durable properties {@link Session.update} sets. */
124
64
  export interface SessionUpdate {
125
65
  /** The display name `list()` reports — a label, not an identity: the id stays the Caller's. */
126
66
  name?: string;
127
- /** A FastAgent model spec, constrained to {@link SessionCapabilities.allowedModels}. Never a
128
- * provider credential. */
67
+ /** A FastAgent model spec, constrained to {@link SessionCapabilities.allowedModels}. */
129
68
  model?: string;
130
- /** A string because supported levels are MODEL-dependent — the set for this session's current
131
- * model is {@link SessionState.availableThinkingLevels}. */
69
+ /**
70
+ * A string because supported levels are MODEL-dependent — the set for this session's current model is {@link
71
+ * SessionState.availableThinkingLevels}.
72
+ */
132
73
  thinkingLevel?: string;
133
- /** Move the session's active leaf: the write verb for the tree `entries()` publishes, and how
134
- * sibling branches come to exist (the next turn hangs off it). Every entry `entries()` publishes
135
- * is a legal target; anything else rejects `invalid_command`. A move to where the leaf already is
136
- * writes nothing. There is no move to the ROOT — "start from nothing" is a new session, not an
137
- * emptied one. */
74
+ /**
75
+ * Move the session's active leaf: the write verb for the tree `entries()` publishes, and how sibling branches come
76
+ * to exist (the next turn hangs off it).
77
+ */
138
78
  leafEntryId?: string;
139
79
  }
140
- /** What {@link Session.update} can be asked to set. */
141
80
  export type SessionUpdateField = keyof SessionUpdate;
142
- /** Every field name, as a value — what an implementation checks a patch against, and what a
143
- * transport rejects an unknown key by. The `satisfies` anchor keeps it exhaustive: a field added to
144
- * {@link SessionUpdate} must be added here too, or this stops compiling. */
145
- export declare const UPDATE_FIELDS: readonly ["name", "model", "thinkingLevel", "leafEntryId"];
146
81
  /**
147
- * The wire form of the run actions — what a transport carries for {@link Session.steer} and its
148
- * siblings. Clients use the METHODS; this exists so a transport has one body shape to parse, and so
149
- * an implementation can answer an unknown `type` as `invalid_command` rather than crashing.
82
+ * Every field name, as a value — what an implementation checks a patch against, and what a transport rejects an
83
+ * unknown key by.
150
84
  */
85
+ export declare const UPDATE_FIELDS: readonly ["name", "model", "thinkingLevel", "leafEntryId"];
86
+ /** The wire form of the run actions — what a transport carries for {@link Session.steer} and its siblings. */
151
87
  export type SessionAction = {
152
88
  type: "steer";
153
89
  prompt: Prompt;
@@ -161,20 +97,10 @@ export type SessionAction = {
161
97
  instructions?: string;
162
98
  };
163
99
  /**
164
- * STATIC support declaration — sessionless, so nothing here may depend on a session. Two kinds of
165
- * flag, and the difference decides what a client does with them:
166
- * - GATES (`steering`, `followUp`, `compaction`, `fork`, `delete`, `updatable`): a client MUST gate
167
- * its controls on these; calling past one rejects before acceptance with
168
- * {@link UNSUPPORTED_CAPABILITY_CODE}.
169
- * - OBSERVATION QUALITY (`toolProgress`, `usage`): whether those events/state fields appear at all —
170
- * nothing to call, nothing to reject.
171
- *
172
- * `allowedModels` may live here because the registry is a deployment fact; thinking LEVELS depend on
173
- * the model a session is currently running, so they live on
174
- * {@link SessionState.availableThinkingLevels} — a static list could only answer for one model.
175
- *
176
- * `state`/`entries`/`events` and `sessions.list()` are mandatory (the reconnect contract and the
177
- * conversation list) and deliberately absent here.
100
+ * STATIC support declaration — sessionless, so nothing here may depend on a session. Two kinds of flag: GATES
101
+ * (`steering`, `followUp`, `compaction`, `fork`, `delete`, `updatable`), which a client MUST check before calling —
102
+ * calling past one rejects with {@link UNSUPPORTED_CAPABILITY_CODE} — and OBSERVATION QUALITY (`toolProgress`,
103
+ * `usage`), which only say whether those events and state fields appear at all.
178
104
  */
179
105
  export interface SessionCapabilities {
180
106
  steering: boolean;
@@ -182,86 +108,63 @@ export interface SessionCapabilities {
182
108
  compaction: boolean;
183
109
  fork: boolean;
184
110
  delete: boolean;
185
- /** Which {@link SessionUpdate} fields this deployment accepts. A patch naming anything else
186
- * rejects `unsupported_capability` — a LIST rather than a flag per field, so a client reads the
187
- * same names it writes. */
111
+ /** Which {@link SessionUpdate} fields this deployment accepts. */
188
112
  updatable: SessionUpdateField[];
189
113
  /** The specs `update({ model })` accepts — present iff `model` is updatable. */
190
114
  allowedModels?: string[];
191
115
  toolProgress: boolean;
192
116
  usage: boolean;
193
117
  }
194
- /**
195
- * One name a client can offer the user. Field NAMES follow pi's RPC `get_commands` so a client
196
- * porting from it maps directly; its `sourceInfo` (file provenance) is deliberately not carried, and
197
- * `source` is a free-form string rather than pi's closed union — which kinds exist is an engine's
198
- * business ("skill" is the only one fastagent assembles today), and an engine with none answers `[]`
199
- * rather than the contract enumerating a set it cannot know.
200
- */
118
+ /** One name a client can offer the user. */
201
119
  export interface AgentCommand {
202
120
  name: string;
203
121
  description?: string;
204
122
  source: string;
205
123
  }
206
- /** Stable `SessionResult.error.code` for a call, or an update field, the implementation does not
207
- * support — the answer to calling past a {@link SessionCapabilities} gate. */
124
+ /**
125
+ * Stable `SessionResult.error.code` for a call, or an update field, the implementation does not support — the answer
126
+ * to calling past a {@link SessionCapabilities} gate.
127
+ */
208
128
  export declare const UNSUPPORTED_CAPABILITY_CODE = "unsupported_capability";
209
- /** Stable `SessionResult.error.code` for a run action
210
- * (`steer`/`follow_up`/`abort`) called while the session has no active run — and, for `abort`, no
211
- * in-flight compaction either (`abort` is also the door out of a `compacting` state; the outcome
212
- * then travels as `compaction_finished{aborted}`). `retryable: false` — the same call fails again;
213
- * call it after `state()` shows an active run. */
129
+ /**
130
+ * Stable `SessionResult.error.code` for a run action (`steer`/`follow_up`/`abort`) called while the session has no
131
+ * active run.
132
+ */
214
133
  export declare const NO_ACTIVE_RUN_CODE = "no_active_run";
215
- /** Stable `SessionResult.error.code` for a PAYLOAD that is invalid for this runtime — an unknown
216
- * model spec, an unsupported thinking level, an entry id that is not a position, a fork onto an id
217
- * another history already holds. Permanent for that payload; a different value may succeed.
218
- * Rejected before acceptance. */
134
+ /** Stable `SessionResult.error.code` for a PAYLOAD that is invalid for this runtime. */
219
135
  export declare const INVALID_COMMAND_CODE = "invalid_command";
220
- /** Stable `SessionResult.error.code` for a write against a session that does not exist. Sessions are
221
- * created by the DATA plane (`invoke`) or copied by `fork`, never minted by an update — a write on
222
- * an unknown id (a typo, a not-yet-started conversation) must not create a ghost record. Rejected
223
- * before acceptance; retry once the session's first turn exists. */
136
+ /** Stable `SessionResult.error.code` for a write against a session that does not exist. */
224
137
  export declare const NO_SUCH_SESSION_CODE = "no_such_session";
225
- /** Stable `SessionResult.error.code` for a write rejected BEFORE acceptance with nothing durable
226
- * landed — a failed property append, a fork whose copy could not be written, or compact's admission
227
- * failing (binding the session, the local preparation). Acceptance sits where the work becomes asynchronous and
228
- * expensive: the model call — compact is accept-fast (holding the dispatch open for a full model
229
- * call would make acceptance = outcome), and post-acceptance outcomes travel as
230
- * `compaction_finished{summary|error|aborted}` events. `retryable: true` throughout: the same
231
- * command may succeed on retry (the state-dependent "nothing to compact" has its own code,
232
- * {@link NOTHING_TO_COMPACT_CODE}). */
138
+ /** Stable `SessionResult.error.code` for a write rejected BEFORE acceptance with nothing durable landed. */
233
139
  export declare const BOUNDARY_COMMAND_FAILED_CODE = "boundary_command_failed";
234
- /** Stable `SessionResult.error.code` for `compact` on a session with no compactable history yet —
235
- * a no-op, not a failure, rejected before acceptance. The {@link NO_ACTIVE_RUN_CODE} pattern:
236
- * `retryable: false` (as-is retry fails now), call it again once the session has grown. */
140
+ /**
141
+ * Stable `SessionResult.error.code` for `compact` on a session with no compactable history yet — a no-op, not a
142
+ * failure, rejected before acceptance.
143
+ */
237
144
  export declare const NOTHING_TO_COMPACT_CODE = "nothing_to_compact";
238
- /** Stable `SessionResult.error.code` for a run action that reached an active run but could not take
239
- * effect because the run raced to settlement (or the engine refused it). Distinct from
240
- * {@link NO_ACTIVE_RUN_CODE}: the run existed — and TRANSIENT: the session's next run can be acted
241
- * on. Still pre-acceptance — nothing was queued — and `retryable: false`: the same call fails
242
- * again. (A run registered without modulation controls is a capability problem, not a run problem,
243
- * and rejects with {@link UNSUPPORTED_CAPABILITY_CODE}.) */
145
+ /**
146
+ * Stable `SessionResult.error.code` for a run action that reached an active run but could not take effect because the
147
+ * run raced to settlement (or the engine refused it).
148
+ */
244
149
  export declare const RUN_COMMAND_FAILED_CODE = "run_command_failed";
245
- /** What {@link SessionCollection.list} rejects with — the only read that can (see it for why). Not a
246
- * `SessionResult`: it REJECTS, and a transport carries this code in the error body of a non-2xx
247
- * (design §13). `retryable: true` — the condition is the store's availability, not the request. */
150
+ /** What {@link SessionCollection.list} rejects with — the only read that can. `retryable: true`: the condition is
151
+ * the store's availability, not the request. */
248
152
  export declare const SESSIONS_UNAVAILABLE_CODE = "sessions_unavailable";
249
- /** Stable `SessionResult.error.code` for a multi-field {@link Session.update} that wrote some of its
250
- * fields and then failed. It exists because {@link BOUNDARY_COMMAND_FAILED_CODE} promises the
251
- * opposite — nothing durable landed — and an implementation cannot keep that promise across
252
- * properties an engine records as separate journal entries. `retryable: false`: re-sending the same
253
- * patch would re-apply what already landed, so a client reads `state()` (or the `state_changed`
254
- * this emits first, which reports the record as it now is) and decides what is left to ask for. */
153
+ /**
154
+ * Stable `SessionResult.error.code` for a multi-field {@link Session.update} that wrote some of its fields and then
155
+ * failed — the ONE code that reports durable work behind an `ok: false`. The message names what landed, and a
156
+ * `state_changed` event reporting the record as it now is precedes it.
157
+ */
255
158
  export declare const PARTIAL_UPDATE_CODE = "partial_update";
256
159
  /**
257
- * Acceptance is not outcome: `ok: true` means admitted or applied, never that the run ultimately
258
- * succeeded (outcomes are `run_settled` events / the invoke terminal). `ok: false` is guaranteed to
259
- * mean rejection BEFORE acceptance — nothing was queued or applied. ONE exception to "nothing took
260
- * effect": a rejected `abort` may still have attributed a concurrently-settling run as `aborted`
261
- * (the intent was live while the run resolved — see the guarantee boundary in the pi
262
- * implementation); the settlement is the truth. `error.retryable` means "the SAME call as-is may
263
- * succeed"; a `false` with a state-dependent code (e.g. {@link NO_ACTIVE_RUN_CODE}) invites another
264
- * call only after `state()` shows the condition changed.
160
+ * Acceptance is not outcome: `ok: true` means admitted or applied, never that the run ultimately succeeded (outcomes
161
+ * are `run_settled` events / the invoke terminal).
162
+ *
163
+ * `ok: false` means the command did not COMPLETE, which is not the same as "nothing happened". Every code except
164
+ * {@link PARTIAL_UPDATE_CODE} is a rejection before acceptance with nothing durable landed; that one reports fields
165
+ * that did land, because properties are separate journal entries and no engine here can roll them back. So the
166
+ * question "may I send this again" is answered by `retryable`, never by `ok` — a client that blindly re-sends every
167
+ * `ok: false` re-applies what a partial update already wrote.
265
168
  */
266
169
  export type SessionResult = {
267
170
  ok: true;
@@ -274,8 +177,7 @@ export type SessionResult = {
274
177
  retryable: boolean;
275
178
  };
276
179
  };
277
- /** One session in {@link SessionControl.sessions} — a conversation-list row, not a session's
278
- * contents. `session` is the CALLER's id (the string a channel minted), never a storage name. */
180
+ /** One session in {@link SessionControl.sessions} — a conversation-list row, not a session's contents. */
279
181
  export interface SessionSummary {
280
182
  session: string;
281
183
  /** Set by `update({ name })`; absent until then — a client showing a list falls back to `preview`. */
@@ -287,24 +189,23 @@ export interface SessionSummary {
287
189
  preview?: string;
288
190
  }
289
191
  export interface SessionState {
290
- /** Set by `update({ name })`, so a client that opens a session directly gets the same label the list
291
- * showed. */
192
+ /** Set by `update({ name })`, so a client that opens a session directly gets the same label the list showed. */
292
193
  name?: string;
293
- /** `compacting` refers to MANUAL compaction (`compact`) at a session boundary. Automatic overflow
294
- * compaction happens inside a run's activity window and reports as `running`. */
194
+ /** `compacting` refers to MANUAL compaction (`compact`) at a session boundary. */
295
195
  status: "idle" | "running" | "compacting";
296
196
  activeRunId?: string;
297
- /** What this session will RUN with, not what was recorded: overrides resolved against the
298
- * deployment (a model the registry lost falls back to the configured one; a level the current
299
- * model cannot do is clamped). Absent where the implementation exposes no model control. */
197
+ /** What this session will RUN with, not what was recorded. */
300
198
  model?: string;
301
199
  thinkingLevel?: string;
302
200
  /** What `update({ thinkingLevel })` accepts for THIS session — re-read after a model change. */
303
201
  availableThinkingLevels?: string[];
304
- pending: {
305
- steering: number;
306
- followUp: number;
307
- };
202
+ pending: PendingPrompts;
203
+ /**
204
+ * The NEWEST ANSWER's own numbers, not a running total: tokens and `cost` as the provider reported them for the
205
+ * latest answer on the active path that carries usage (an aborted or failed answer does not, so it reports the one
206
+ * before). `contextTokens` is how full the context is now, ABSENT when unknown (after a compaction or a context
207
+ * edit, until the next answer); `contextWindow` is the running model's.
208
+ */
308
209
  usage?: {
309
210
  inputTokens: number;
310
211
  outputTokens: number;
@@ -320,8 +221,10 @@ export interface SessionEntries {
320
221
  entries: SessionEntry[];
321
222
  leafEntryId?: string;
322
223
  }
323
- /** A durable append-only session record. `kind` guarantees a minimum vocabulary of
324
- * "user" | "assistant" | "tool"; engine-specific kinds beyond it MUST be skippable. */
224
+ /**
225
+ * A durable append-only session record. `kind` guarantees a minimum vocabulary of "user" | "assistant" | "tool";
226
+ * engine-specific kinds beyond it MUST be skippable.
227
+ */
325
228
  export interface SessionEntry {
326
229
  id: string;
327
230
  parentId?: string;
@@ -329,9 +232,31 @@ export interface SessionEntry {
329
232
  kind: string;
330
233
  data: Json;
331
234
  }
332
- /** Semantic-only: no sequence, no epoch, no session id — in-process the stream is lossless and
333
- * ordered, and those concerns belong to the transport envelope (design §13). Consumers MUST
334
- * forward or ignore unknown event types; the vocabulary is additive. */
235
+ /**
236
+ * A live event subscription, plus the ONE thing a reconnecting client cannot infer: when it started.
237
+ *
238
+ * Reconnect has to subscribe BEFORE it reads history, or an event landing between the read and the subscription is
239
+ * lost — it is live-only (`state_changed`, `run_settled`), so no cursor brings it back. Subscribing first is not
240
+ * enough on its own, because "the call returned" is not "the subscription exists": in process the registration
241
+ * happens on the first pull, and over HTTP it happens on the server before the response headers. `ready` is that
242
+ * boundary made waitable, so the recipe is subscribe → await ready → backfill, with no timing guess in it.
243
+ *
244
+ * ONE stream IS one subscription, which is what makes `ready` mean anything: readiness belongs to a subscription, so
245
+ * a stream that could start several would be promising the second one something the first established. Iterating the
246
+ * same stream twice is refused for that reason — call `events()` again, and get the readiness that goes with it.
247
+ *
248
+ * `ready` REJECTS when the subscription cannot be established at all: an unreachable endpoint, a refused token, or an
249
+ * iteration cancelled before it registered. A stream nobody iterates never settles, matching the rule that an
250
+ * iterator obtained but never driven is not subscribed.
251
+ */
252
+ export interface SessionEventStream extends AsyncIterable<SessionEvent> {
253
+ ready: Promise<void>;
254
+ }
255
+ /**
256
+ * Semantic-only: no sequence, no epoch, no session id — in-process the stream is lossless and ordered, and those
257
+ * concerns belong to the transport envelope (design §13). Consumers MUST forward or ignore unknown event types; the
258
+ * vocabulary is additive.
259
+ */
335
260
  export interface SessionEvent<TType extends string = string, TData extends Json = Json> {
336
261
  type: TType;
337
262
  timestamp: number;
@@ -386,61 +311,61 @@ export type ToolFinishedEvent = SessionEvent<"tool_finished", {
386
311
  }> & {
387
312
  runId: string;
388
313
  };
389
- /** Normalized live queue depths for the active run (L1). */
390
- export type QueueChangedEvent = SessionEvent<"queue_changed", {
391
- steering: number;
392
- followUp: number;
393
- }> & {
314
+ /**
315
+ * The prompts queued on the active run, oldest first, as the engine queued them: plain text as sent, a slash command
316
+ * already expanded (a `/skill:…` becomes the skill's text), images not included. A prompt LEAVES its list when it
317
+ * enters the conversation as a user message: from then on it is in the record and in every later model call (an abort
318
+ * can still end the run before the model answers it). Whatever is still listed when the run settles never entered
319
+ * the conversation and is dropped with the run.
320
+ */
321
+ export type PendingPrompts = {
322
+ steering: string[];
323
+ followUp: string[];
324
+ };
325
+ /** The active run's queue changed (L1); `data` is the whole queue, not a delta. */
326
+ export type QueueChangedEvent = SessionEvent<"queue_changed", PendingPrompts> & {
394
327
  runId: string;
395
328
  };
396
- /** An {@link Session.update} changed durable session state (L2; no runId — a property is set between
397
- * runs). Carries what LANDED, read back from the record: a patch that set two fields reports both,
398
- * and one that failed partway reports only what applied.
399
- *
400
- * `leafEntryId` reports a deliberate move of the branch head, which a second attached client would
401
- * otherwise have no signal for. It is NOT a general leaf feed: every turn advances the leaf too,
402
- * and that is read from `entries()`/`state()` after the run. */
329
+ /**
330
+ * Durable session state changed (L2; no runId). An {@link Session.update} reports what it landed; where
331
+ * `capabilities().usage` holds, a finished run or compaction reports the session's `usage` as it now reads, and an
332
+ * update that moved `leafEntryId` or changed `model` carries it too (absent there: the session now has none).
333
+ */
403
334
  export type StateChangedEvent = SessionEvent<"state_changed", {
404
335
  name?: string;
405
336
  model?: string;
406
337
  thinkingLevel?: string;
407
338
  leafEntryId?: string;
339
+ usage?: SessionState["usage"];
408
340
  }>;
409
- /** Manual compaction bounds (L2): every `compaction_started` is closed by exactly one
410
- * `compaction_finished` — `summary` on success, `error` on failure, `aborted: true` on a
411
- * deliberate stop (run/compaction symmetry with `run_settled{status: "aborted"}`: a client's own
412
- * abort is not a failure). In the failure and aborted cases nothing durable landed. Automatic
413
- * overflow compaction stays inside its run's activity window and does not emit these. */
341
+ /** Manual compaction bounds (L2): every `compaction_started` is closed by exactly one `compaction_finished`. */
414
342
  export type CompactionStartedEvent = SessionEvent<"compaction_started", Record<never, never>>;
415
343
  export type CompactionFinishedEvent = SessionEvent<"compaction_finished", {
416
344
  summary?: string;
417
345
  error?: string;
418
346
  aborted?: boolean;
419
347
  }>;
420
- /** A transient provider failure scheduled a summarization retry backoff (auto-compaction /
421
- * branch summaries inside a run — `runId` present — or a manual `compact` at a boundary — no
422
- * `runId`). Explains a quiet gap that would otherwise read as a hang. Deliberately unclosed:
423
- * the next event (message_*, `run_settled`, `compaction_finished`) is the closure, and the
424
- * engine's `retry_finished` carries no outcome to forward. */
348
+ /**
349
+ * A transient provider failure scheduled a summarization retry backoff (auto-compaction / branch summaries inside a
350
+ * run — `runId` present — or a manual `compact` at a boundary — no `runId`).
351
+ */
425
352
  export type RetryScheduledEvent = SessionEvent<"retry_scheduled", {
426
- /** "assistant" is an engine that retries the ANSWER request itself (pi's AgentSession does;
427
- * pi's own session does; a summarization call is the other two). */
353
+ /**
354
+ * "assistant" is an engine that retries the ANSWER request itself (pi's AgentSession does; pi's own session does;
355
+ * a summarization call is the other two).
356
+ */
428
357
  operation: "assistant" | "compaction" | "branch_summary";
429
358
  attempt: number;
430
359
  maxAttempts: number;
431
360
  delayMs: number;
432
361
  error: string;
433
362
  }>;
434
- /**
435
- * The serving process failed outside a normal run outcome (fail visibly). Emitted by TRANSPORT
436
- * adapters (design §13) when they lose the backend before ending a remote stream — an in-process
437
- * embedding cannot produce it (a dead process has no one left to emit), so it is deliberately NOT
438
- * part of {@link KnownSessionEvent}: a local L0 client would be handling a signal that cannot occur.
439
- */
363
+ /** The serving process failed outside a normal run outcome (fail visibly). */
440
364
  export type ServingErrorEvent = SessionEvent<"serving_error", {
441
365
  message: string;
442
366
  }>;
443
- /** Every event the in-process observation plane emits today: L0, L1 `queue_changed`, and the L2
444
- * events (`state_changed`, `compaction_*`, `retry_scheduled`). Remaining L2 events (turn_*) are
445
- * future vocabulary; {@link ServingErrorEvent} arrives with the transport adapter. */
367
+ /**
368
+ * Every event the in-process observation plane emits today: L0, L1 `queue_changed`, and the L2 events
369
+ * (`state_changed`, `compaction_*`, `retry_scheduled`).
370
+ */
446
371
  export type KnownSessionEvent = RunStartedEvent | RunSettledEvent | MessageStartedEvent | MessageDeltaEvent | MessageFinishedEvent | ToolStartedEvent | ToolProgressEvent | ToolFinishedEvent | QueueChangedEvent | StateChangedEvent | CompactionStartedEvent | CompactionFinishedEvent | RetryScheduledEvent;