@agentorg/cli 0.0.5 → 0.0.7

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 (260) hide show
  1. package/README.md +23 -104
  2. package/dist/node_modules/@agentorg/computer/LICENSE +201 -0
  3. package/dist/node_modules/@agentorg/computer/NOTICE +2 -0
  4. package/dist/node_modules/@agentorg/computer/dist/THIRD_PARTY_LICENSES.txt +1321 -0
  5. package/dist/node_modules/@agentorg/computer/dist/sdk.js +24909 -0
  6. package/dist/node_modules/@agentorg/computer/dist/types/generated/schema.d.ts +860 -0
  7. package/dist/node_modules/@agentorg/computer/dist/types/sdk.d.ts +242 -0
  8. package/dist/node_modules/@agentorg/computer/package.json +12 -0
  9. package/dist/node_modules/@agentorg/computer-connector/dist/src/index.d.ts +1 -0
  10. package/dist/node_modules/@agentorg/computer-connector/dist/src/index.js +1 -0
  11. package/dist/node_modules/@agentorg/computer-connector/dist/src/provider.d.ts +24 -0
  12. package/dist/node_modules/@agentorg/computer-connector/dist/src/provider.js +482 -0
  13. package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.d.ts +19 -0
  14. package/dist/node_modules/@agentorg/computer-connector/dist/src/unit.js +149 -0
  15. package/dist/node_modules/@agentorg/computer-connector/package.json +33 -0
  16. package/dist/node_modules/@agentorg/computer-connector/skills/browser/SKILL.md +31 -0
  17. package/dist/node_modules/@agentorg/computer-connector/skills/computer/SKILL.md +30 -0
  18. package/dist/node_modules/@agentorg/computer-connector/skills/files/SKILL.md +28 -0
  19. package/dist/node_modules/@agentorg/computer-connector/skills/terminal/SKILL.md +39 -0
  20. package/dist/node_modules/@agentorg/computer-connector/skills/web-research/SKILL.md +29 -0
  21. package/dist/node_modules/@agentorg/hub/dist/src/hub-actor.d.ts +2 -7
  22. package/dist/node_modules/@agentorg/hub/dist/src/hub-actor.js +4 -144
  23. package/dist/node_modules/@agentorg/hub/dist/src/index.d.ts +1 -3
  24. package/dist/node_modules/@agentorg/hub/dist/src/index.js +1 -3
  25. package/dist/node_modules/@agentorg/hub/dist/src/router.d.ts +9 -58
  26. package/dist/node_modules/@agentorg/hub/dist/src/router.js +41 -414
  27. package/dist/node_modules/@agentorg/hub/dist/src/state.d.ts +17 -317
  28. package/dist/node_modules/@agentorg/hub/dist/src/state.js +42 -536
  29. package/dist/node_modules/@agentorg/hub/dist/src/validate.d.ts +1 -3
  30. package/dist/node_modules/@agentorg/hub/dist/src/validate.js +19 -17
  31. package/dist/node_modules/@agentorg/hub/package.json +0 -3
  32. package/dist/node_modules/@agentorg/interfaces/dist/src/agent-provider.d.ts +119 -0
  33. package/dist/node_modules/@agentorg/interfaces/dist/src/agent-provider.js +96 -0
  34. package/dist/node_modules/@agentorg/interfaces/dist/src/agent-settings.d.ts +42 -0
  35. package/dist/node_modules/@agentorg/interfaces/dist/src/agent-settings.js +53 -0
  36. package/dist/node_modules/@agentorg/interfaces/dist/src/chat.d.ts +93 -38
  37. package/dist/node_modules/@agentorg/interfaces/dist/src/chat.js +71 -22
  38. package/dist/node_modules/@agentorg/interfaces/dist/src/connection.d.ts +36 -0
  39. package/dist/node_modules/@agentorg/interfaces/dist/src/connection.js +31 -0
  40. package/dist/node_modules/@agentorg/interfaces/dist/src/folders.d.ts +19 -0
  41. package/dist/node_modules/@agentorg/interfaces/dist/src/folders.js +25 -0
  42. package/dist/node_modules/@agentorg/interfaces/dist/src/hub.d.ts +16 -286
  43. package/dist/node_modules/@agentorg/interfaces/dist/src/hub.js +17 -159
  44. package/dist/node_modules/@agentorg/interfaces/dist/src/index.d.ts +9 -9
  45. package/dist/node_modules/@agentorg/interfaces/dist/src/index.js +9 -9
  46. package/dist/node_modules/@agentorg/interfaces/dist/src/kv.d.ts +2 -2
  47. package/dist/node_modules/@agentorg/interfaces/dist/src/kv.js +2 -2
  48. package/dist/node_modules/@agentorg/interfaces/dist/src/llm-session.d.ts +2 -0
  49. package/dist/node_modules/@agentorg/interfaces/dist/src/llm-session.js +2 -1
  50. package/dist/node_modules/@agentorg/interfaces/dist/src/manager.d.ts +626 -0
  51. package/dist/node_modules/@agentorg/interfaces/dist/src/manager.js +349 -0
  52. package/dist/node_modules/@agentorg/interfaces/dist/src/tools.d.ts +39 -0
  53. package/dist/node_modules/@agentorg/interfaces/dist/src/tools.js +43 -0
  54. package/dist/node_modules/@agentorg/interfaces/dist/src/units.d.ts +460 -0
  55. package/dist/node_modules/@agentorg/interfaces/dist/src/units.js +204 -0
  56. package/dist/node_modules/@agentorg/looper/dist/src/index.d.ts +5 -0
  57. package/dist/node_modules/@agentorg/looper/dist/src/index.js +5 -0
  58. package/dist/node_modules/@agentorg/looper/dist/src/loop.d.ts +75 -0
  59. package/dist/node_modules/@agentorg/looper/dist/src/loop.js +332 -0
  60. package/dist/node_modules/@agentorg/looper/dist/src/looper.d.ts +71 -0
  61. package/dist/node_modules/@agentorg/looper/dist/src/looper.js +282 -0
  62. package/dist/node_modules/@agentorg/looper/dist/src/record.d.ts +99 -0
  63. package/dist/node_modules/@agentorg/looper/dist/src/record.js +278 -0
  64. package/dist/node_modules/@agentorg/looper/dist/src/tools.d.ts +11 -0
  65. package/dist/node_modules/@agentorg/looper/dist/src/tools.js +42 -0
  66. package/dist/node_modules/@agentorg/looper/dist/src/types.d.ts +147 -0
  67. package/dist/node_modules/@agentorg/looper/dist/src/types.js +32 -0
  68. package/dist/node_modules/@agentorg/looper/package.json +24 -0
  69. package/dist/node_modules/@agentorg/manager/dist/src/activity.d.ts +18 -0
  70. package/dist/node_modules/@agentorg/manager/dist/src/activity.js +65 -0
  71. package/dist/node_modules/@agentorg/manager/dist/src/control.d.ts +134 -0
  72. package/dist/node_modules/@agentorg/manager/dist/src/control.js +1115 -0
  73. package/dist/node_modules/@agentorg/manager/dist/src/form.d.ts +40 -0
  74. package/dist/node_modules/@agentorg/manager/dist/src/form.js +191 -0
  75. package/dist/node_modules/@agentorg/manager/dist/src/index.d.ts +1 -0
  76. package/dist/node_modules/@agentorg/manager/dist/src/index.js +1 -0
  77. package/dist/node_modules/@agentorg/manager/dist/src/manager.d.ts +25 -0
  78. package/dist/node_modules/@agentorg/manager/dist/src/manager.js +680 -0
  79. package/dist/node_modules/@agentorg/manager/dist/src/skills.d.ts +27 -0
  80. package/dist/node_modules/@agentorg/manager/dist/src/skills.js +152 -0
  81. package/dist/node_modules/@agentorg/manager/dist/src/stack.d.ts +454 -0
  82. package/dist/node_modules/@agentorg/manager/dist/src/stack.js +917 -0
  83. package/dist/node_modules/@agentorg/manager/package.json +30 -0
  84. package/dist/node_modules/@agentorg/mcp/dist/src/connection.d.ts +34 -0
  85. package/dist/node_modules/@agentorg/mcp/dist/src/connection.js +296 -0
  86. package/dist/node_modules/@agentorg/mcp/dist/src/index.d.ts +4 -0
  87. package/dist/node_modules/@agentorg/mcp/dist/src/index.js +4 -0
  88. package/dist/node_modules/@agentorg/mcp/dist/src/kinds.d.ts +158 -0
  89. package/dist/node_modules/@agentorg/mcp/dist/src/kinds.js +164 -0
  90. package/dist/node_modules/@agentorg/mcp/dist/src/provider.d.ts +22 -0
  91. package/dist/node_modules/@agentorg/mcp/dist/src/provider.js +197 -0
  92. package/dist/node_modules/@agentorg/mcp/dist/src/public.d.ts +6 -0
  93. package/dist/node_modules/@agentorg/mcp/dist/src/public.js +72 -0
  94. package/dist/node_modules/@agentorg/mcp/package.json +31 -0
  95. package/dist/node_modules/@agentorg/sdk/dist/src/cli.js +3 -23
  96. package/dist/node_modules/@agentorg/sdk/dist/src/client.d.ts +4 -25
  97. package/dist/node_modules/@agentorg/sdk/dist/src/client.js +5 -55
  98. package/dist/node_modules/@agentorg/sdk/dist/src/errors.d.ts +1 -1
  99. package/dist/node_modules/@agentorg/sdk/dist/src/errors.js +3 -3
  100. package/dist/node_modules/@agentorg/sdk/dist/src/filled.d.ts +21 -0
  101. package/dist/node_modules/@agentorg/sdk/dist/src/filled.js +24 -0
  102. package/dist/node_modules/@agentorg/sdk/dist/src/index.d.ts +3 -2
  103. package/dist/node_modules/@agentorg/sdk/dist/src/index.js +2 -1
  104. package/dist/node_modules/@agentorg/sdk/dist/src/interface.d.ts +6 -34
  105. package/dist/node_modules/@agentorg/sdk/dist/src/interface.js +3 -24
  106. package/dist/node_modules/@agentorg/sdk/dist/src/module-host.d.ts +8 -17
  107. package/dist/node_modules/@agentorg/sdk/dist/src/module-host.js +15 -87
  108. package/dist/node_modules/@agentorg/sdk/dist/src/module.d.ts +10 -76
  109. package/dist/node_modules/@agentorg/sdk/dist/src/module.js +3 -23
  110. package/dist/node_modules/@agentorg/sdk/dist/src/person-commands.js +0 -5
  111. package/dist/node_modules/@agentorg/sdk/dist/src/runtime.d.ts +3 -27
  112. package/dist/node_modules/@agentorg/sdk/dist/src/runtime.js +5 -100
  113. package/dist/node_modules/@agentorg/sdk/dist/src/testing.d.ts +7 -8
  114. package/dist/node_modules/@agentorg/sdk/dist/src/testing.js +12 -24
  115. package/dist/node_modules/@agentorg/sdk/package.json +4 -37
  116. package/dist/node_modules/@agentorg/shell/dist/app.css +4624 -739
  117. package/dist/node_modules/@agentorg/shell/dist/app.js +245 -202
  118. package/dist/node_modules/@agentorg/shell/package.json +23 -10
  119. package/dist/node_modules/@agentorg/wire/dist/src/frames.d.ts +2 -3
  120. package/dist/node_modules/@agentorg/wire/dist/src/frames.js +2 -3
  121. package/dist/node_modules/@agentorg/wire/dist/src/ops.d.ts +5 -34
  122. package/dist/node_modules/@agentorg/wire/dist/src/ops.js +2 -17
  123. package/dist/node_modules/assistant/dist/src/chats.d.ts +92 -0
  124. package/dist/node_modules/assistant/dist/src/chats.js +357 -0
  125. package/dist/node_modules/assistant/dist/src/engine.d.ts +42 -0
  126. package/dist/node_modules/assistant/dist/src/engine.js +160 -0
  127. package/dist/node_modules/assistant/dist/src/local-store.d.ts +3 -0
  128. package/dist/node_modules/assistant/dist/src/local-store.js +58 -0
  129. package/dist/node_modules/assistant/dist/src/provider.d.ts +21 -0
  130. package/dist/node_modules/assistant/dist/src/provider.js +259 -0
  131. package/dist/node_modules/assistant/dist/src/settings.d.ts +17 -0
  132. package/dist/node_modules/assistant/dist/src/settings.js +43 -0
  133. package/dist/node_modules/assistant/dist/src/tools.d.ts +57 -0
  134. package/dist/node_modules/assistant/dist/src/tools.js +102 -0
  135. package/dist/node_modules/assistant/package.json +30 -0
  136. package/dist/node_modules/chatgpt/dist/src/account.d.ts +52 -0
  137. package/dist/node_modules/chatgpt/dist/src/account.js +270 -0
  138. package/dist/node_modules/chatgpt/dist/src/encoding.d.ts +7 -0
  139. package/dist/node_modules/chatgpt/dist/src/encoding.js +20 -0
  140. package/dist/node_modules/chatgpt/dist/src/file-store.d.ts +9 -0
  141. package/dist/node_modules/chatgpt/dist/src/file-store.js +68 -0
  142. package/dist/node_modules/chatgpt/dist/src/index.d.ts +1 -0
  143. package/dist/node_modules/chatgpt/dist/src/index.js +1 -0
  144. package/dist/node_modules/chatgpt/dist/src/jwt.d.ts +15 -0
  145. package/dist/node_modules/chatgpt/dist/src/jwt.js +37 -0
  146. package/dist/node_modules/chatgpt/dist/src/oauth.d.ts +43 -0
  147. package/dist/node_modules/chatgpt/dist/src/oauth.js +104 -0
  148. package/dist/node_modules/chatgpt/dist/src/program.d.ts +23 -0
  149. package/dist/node_modules/chatgpt/dist/src/program.js +41 -0
  150. package/dist/node_modules/chatgpt/dist/src/responses.d.ts +54 -0
  151. package/dist/node_modules/chatgpt/dist/src/responses.js +300 -0
  152. package/dist/node_modules/chatgpt/dist/src/serve.d.ts +65 -0
  153. package/dist/node_modules/chatgpt/dist/src/serve.js +46 -0
  154. package/dist/node_modules/chatgpt/package.json +33 -0
  155. package/dist/src/api.d.ts +5 -34
  156. package/dist/src/api.js +10 -68
  157. package/dist/src/cli.js +3 -7
  158. package/dist/src/folders.d.ts +2 -0
  159. package/dist/src/folders.js +45 -0
  160. package/dist/src/gateway.d.ts +13 -8
  161. package/dist/src/gateway.js +119 -296
  162. package/dist/src/index.d.ts +4 -5
  163. package/dist/src/index.js +3 -4
  164. package/dist/src/live.d.ts +17 -0
  165. package/dist/src/live.js +109 -0
  166. package/dist/src/notes.d.ts +11 -0
  167. package/dist/src/notes.js +64 -0
  168. package/dist/src/oauth.d.ts +16 -0
  169. package/dist/src/oauth.js +46 -0
  170. package/dist/src/programs.d.ts +36 -0
  171. package/dist/src/programs.js +198 -0
  172. package/dist/src/signin.d.ts +12 -3
  173. package/dist/src/signin.js +30 -6
  174. package/package.json +4 -11
  175. package/dist/bundled/index.json +0 -6
  176. package/dist/bundled/sha256-0e91cc3d0e9762b81abc2427b5496b20f383abcd6fb97d928a8d50e956b54d1f.agentorg +0 -0
  177. package/dist/bundled/sha256-1f64ca62a0209d767d6aa6c4feb50b0653d60f10bebbc301f79bd3a37e0153c1.agentorg +0 -0
  178. package/dist/bundled/sha256-4055f8fddf6b90f3d356543f554b2a9e9a2c4a8827a8774f8f87952dc1692331.agentorg +0 -0
  179. package/dist/bundled/sha256-e356ea3c1899138a8494baf521556831006f38534fa9e92ae873e7e6956c3a46.agentorg +0 -0
  180. package/dist/node_modules/@agentorg/hub/dist/src/build.d.ts +0 -17
  181. package/dist/node_modules/@agentorg/hub/dist/src/build.js +0 -120
  182. package/dist/node_modules/@agentorg/hub/dist/src/logs.d.ts +0 -33
  183. package/dist/node_modules/@agentorg/hub/dist/src/logs.js +0 -162
  184. package/dist/node_modules/@agentorg/hub/dist/src/net.d.ts +0 -41
  185. package/dist/node_modules/@agentorg/hub/dist/src/net.js +0 -265
  186. package/dist/node_modules/@agentorg/hub/dist/src/processes.d.ts +0 -78
  187. package/dist/node_modules/@agentorg/hub/dist/src/processes.js +0 -485
  188. package/dist/node_modules/@agentorg/hub/dist/src/storage.d.ts +0 -38
  189. package/dist/node_modules/@agentorg/hub/dist/src/storage.js +0 -194
  190. package/dist/node_modules/@agentorg/interfaces/dist/src/http-egress.d.ts +0 -6
  191. package/dist/node_modules/@agentorg/interfaces/dist/src/http-egress.js +0 -7
  192. package/dist/node_modules/@agentorg/interfaces/dist/src/installer.d.ts +0 -191
  193. package/dist/node_modules/@agentorg/interfaces/dist/src/installer.js +0 -136
  194. package/dist/node_modules/@agentorg/interfaces/dist/src/layout.d.ts +0 -47
  195. package/dist/node_modules/@agentorg/interfaces/dist/src/layout.js +0 -52
  196. package/dist/node_modules/@agentorg/interfaces/dist/src/rules.d.ts +0 -35
  197. package/dist/node_modules/@agentorg/interfaces/dist/src/rules.js +0 -37
  198. package/dist/node_modules/@agentorg/interfaces/dist/src/storage-admin.d.ts +0 -23
  199. package/dist/node_modules/@agentorg/interfaces/dist/src/storage-admin.js +0 -31
  200. package/dist/node_modules/@agentorg/interfaces/dist/src/ui-shell.d.ts +0 -14
  201. package/dist/node_modules/@agentorg/interfaces/dist/src/ui-shell.js +0 -26
  202. package/dist/node_modules/@agentorg/interfaces/dist/src/ui-view.d.ts +0 -27
  203. package/dist/node_modules/@agentorg/interfaces/dist/src/ui-view.js +0 -26
  204. package/dist/node_modules/@agentorg/kit/dist/src/chat.d.ts +0 -37
  205. package/dist/node_modules/@agentorg/kit/dist/src/chat.js +0 -131
  206. package/dist/node_modules/@agentorg/kit/dist/src/components.d.ts +0 -94
  207. package/dist/node_modules/@agentorg/kit/dist/src/components.js +0 -66
  208. package/dist/node_modules/@agentorg/kit/dist/src/icons.d.ts +0 -17
  209. package/dist/node_modules/@agentorg/kit/dist/src/icons.js +0 -30
  210. package/dist/node_modules/@agentorg/kit/dist/src/index.d.ts +0 -6
  211. package/dist/node_modules/@agentorg/kit/dist/src/index.js +0 -10
  212. package/dist/node_modules/@agentorg/kit/dist/src/markdown.d.ts +0 -9
  213. package/dist/node_modules/@agentorg/kit/dist/src/markdown.js +0 -14
  214. package/dist/node_modules/@agentorg/kit/dist/src/resizable.d.ts +0 -5
  215. package/dist/node_modules/@agentorg/kit/dist/src/resizable.js +0 -8
  216. package/dist/node_modules/@agentorg/kit/dist/src/styles.d.ts +0 -11
  217. package/dist/node_modules/@agentorg/kit/dist/src/styles.js +0 -166
  218. package/dist/node_modules/@agentorg/kit/package.json +0 -44
  219. package/dist/node_modules/@agentorg/sdk/dist/frame/runtime.js +0 -753
  220. package/dist/node_modules/@agentorg/sdk/dist/host/runner.js +0 -21963
  221. package/dist/node_modules/@agentorg/sdk/dist/src/build.d.ts +0 -2
  222. package/dist/node_modules/@agentorg/sdk/dist/src/build.js +0 -2
  223. package/dist/node_modules/@agentorg/sdk/dist/src/client-http.d.ts +0 -24
  224. package/dist/node_modules/@agentorg/sdk/dist/src/client-http.js +0 -247
  225. package/dist/node_modules/@agentorg/sdk/dist/src/describe.d.ts +0 -13
  226. package/dist/node_modules/@agentorg/sdk/dist/src/describe.js +0 -16
  227. package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.d.ts +0 -8
  228. package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.js +0 -64
  229. package/dist/node_modules/@agentorg/sdk/dist/src/frame-entry.d.ts +0 -1
  230. package/dist/node_modules/@agentorg/sdk/dist/src/frame-entry.js +0 -35
  231. package/dist/node_modules/@agentorg/sdk/dist/src/frame-host.d.ts +0 -57
  232. package/dist/node_modules/@agentorg/sdk/dist/src/frame-host.js +0 -293
  233. package/dist/node_modules/@agentorg/sdk/dist/src/frame-protocol.d.ts +0 -124
  234. package/dist/node_modules/@agentorg/sdk/dist/src/frame-protocol.js +0 -16
  235. package/dist/node_modules/@agentorg/sdk/dist/src/frame.d.ts +0 -25
  236. package/dist/node_modules/@agentorg/sdk/dist/src/frame.js +0 -248
  237. package/dist/node_modules/@agentorg/sdk/dist/src/host-main.d.ts +0 -1
  238. package/dist/node_modules/@agentorg/sdk/dist/src/host-main.js +0 -60
  239. package/dist/node_modules/@agentorg/sdk/dist/src/host.d.ts +0 -25
  240. package/dist/node_modules/@agentorg/sdk/dist/src/host.js +0 -92
  241. package/dist/node_modules/@agentorg/sdk/dist/src/manifest-api.d.ts +0 -2
  242. package/dist/node_modules/@agentorg/sdk/dist/src/manifest-api.js +0 -2
  243. package/dist/node_modules/@agentorg/sdk/dist/src/manifest.d.ts +0 -56
  244. package/dist/node_modules/@agentorg/sdk/dist/src/manifest.js +0 -165
  245. package/dist/node_modules/@agentorg/sdk/dist/src/package.d.ts +0 -60
  246. package/dist/node_modules/@agentorg/sdk/dist/src/package.js +0 -538
  247. package/dist/node_modules/@agentorg/sdk/dist/src/tar.d.ts +0 -7
  248. package/dist/node_modules/@agentorg/sdk/dist/src/tar.js +0 -71
  249. package/dist/node_modules/@agentorg/shell/dist/agent-bindings.js +0 -59
  250. package/dist/node_modules/@agentorg/shell/src/agent-bindings.ts +0 -107
  251. package/dist/src/frames.d.ts +0 -23
  252. package/dist/src/frames.js +0 -78
  253. package/dist/src/layout.d.ts +0 -44
  254. package/dist/src/layout.js +0 -90
  255. package/dist/src/model.d.ts +0 -54
  256. package/dist/src/model.js +0 -299
  257. package/dist/src/rules.d.ts +0 -71
  258. package/dist/src/rules.js +0 -157
  259. package/dist/src/transfer.d.ts +0 -30
  260. package/dist/src/transfer.js +0 -110
@@ -0,0 +1,282 @@
1
+ /**
2
+ * The looper: the loops of whoever hosts it, one for each thread a message comes in on. A thread is
3
+ * a name its host gives; its record is kept under `thread/<name>/` in the store, and its loop and
4
+ * record are made when the thread is first used and then stay in memory.
5
+ *
6
+ * Turns run side by side, each in a place. There are `PLACES` of them, and one more that only a
7
+ * thread already begun (its record holds something) may take, so new threads never keep a message
8
+ * from one that is under way. A turn that finds no place waits for one, in the order it came. While
9
+ * begun threads keep five turns running, a new thread goes on waiting. `WAITING` turns may wait;
10
+ * past that a message that would start a turn is refused `busy`, and nothing of it is kept.
11
+ *
12
+ * A thread is marked in the store while a turn of it hasn't ended. A looper that closes under a
13
+ * turn, or goes without closing, leaves the mark, and `resume` on the same store goes on with that
14
+ * turn, once: the turn that goes on is not marked. A turn that ends, fails or is stopped leaves
15
+ * no mark.
16
+ */
17
+ import { createLoop } from "./loop.js";
18
+ import { createRecord } from "./record.js";
19
+ import { Refusal, } from "./types.js";
20
+ /** The turns that run at once, not counting the one more for a thread already begun. */
21
+ export const PLACES = 4;
22
+ /** The turns that may wait for a place at once. */
23
+ export const WAITING = 16;
24
+ /** Where a thread's record is kept in the looper's store. */
25
+ const recordOf = (thread) => `thread/${encodeURIComponent(thread)}/`;
26
+ /** Where a thread is marked while a turn of it hasn't ended. */
27
+ const UNFINISHED = "unfinished/";
28
+ /** The store's keys under `prefix`, as a store of its own. */
29
+ function under(store, prefix) {
30
+ return {
31
+ get: ({ key }) => store.get({ key: prefix + key }),
32
+ set: ({ key, value }) => store.set({ key: prefix + key, value }),
33
+ delete: ({ key }) => store.delete({ key: prefix + key }),
34
+ async list({ prefix: inner = "", after, limit }) {
35
+ const page = await store.list({
36
+ prefix: prefix + inner,
37
+ ...(after === undefined ? {} : { after: prefix + after }),
38
+ ...(limit === undefined ? {} : { limit }),
39
+ });
40
+ return {
41
+ keys: page.keys.map((key) => key.slice(prefix.length)),
42
+ next: page.next === null ? null : page.next.slice(prefix.length),
43
+ };
44
+ },
45
+ };
46
+ }
47
+ /**
48
+ * Make a looper. Nothing is read or run until a thread is named: a message sent in it, or its
49
+ * messages asked for.
50
+ */
51
+ export function createLooper(options) {
52
+ const { store, out, log } = options;
53
+ const threads = new Map();
54
+ /** Set while it is stopped: no turn starts until it is started. */
55
+ let stopped = options.stopped ?? false;
56
+ /** Set when it closes: no turn starts after. */
57
+ let closed = false;
58
+ /** Set once the turns that were cut off have been looked for. */
59
+ let looked = false;
60
+ /** Refuse a turn that can't start now, whatever thread it is for. */
61
+ const mayStart = () => {
62
+ if (closed)
63
+ throw new Refusal("unavailable", "This agent is closing.");
64
+ if (stopped)
65
+ throw new Refusal("busy", "It is stopped. Start it to go on.");
66
+ };
67
+ /** Messages being recorded now, each about to start a turn: stopping waits for them. */
68
+ const starting = new Set();
69
+ const started = (call) => {
70
+ const done = call.then(() => void starting.delete(done), () => void starting.delete(done));
71
+ starting.add(done);
72
+ return call;
73
+ };
74
+ /** The turns that have a place, and those waiting for one, first come first. */
75
+ const placed = new Set();
76
+ const waiting = [];
77
+ const fits = (begun) => placed.size < PLACES + (begun ? 1 : 0);
78
+ const enter = (begun) => {
79
+ let take = () => { };
80
+ const place = {
81
+ entered: new Promise((resolve) => {
82
+ take = resolve;
83
+ }),
84
+ leave() {
85
+ take();
86
+ const queued = waiting.findIndex((one) => one.place === place);
87
+ if (queued !== -1)
88
+ waiting.splice(queued, 1);
89
+ if (!placed.delete(place))
90
+ return;
91
+ // Its place goes to whoever has waited longest for one they may take.
92
+ const next = waiting.find((one) => fits(one.begun));
93
+ if (!next)
94
+ return;
95
+ waiting.splice(waiting.indexOf(next), 1);
96
+ placed.add(next.place);
97
+ next.take();
98
+ },
99
+ };
100
+ if (fits(begun)) {
101
+ placed.add(place);
102
+ take();
103
+ }
104
+ else if (waiting.length < WAITING)
105
+ waiting.push({ place, begun, take });
106
+ else
107
+ throw new Refusal("busy", "Too many turns are waiting. Wait for one to start.");
108
+ return place;
109
+ };
110
+ const open = (thread) => {
111
+ const record = createRecord(under(store, recordOf(thread)), log);
112
+ const key = UNFINISHED + encodeURIComponent(thread);
113
+ const held = {
114
+ record,
115
+ /** What is being asked of its loop now: messages, going on. */
116
+ uses: 0,
117
+ /** Whether a turn of it is running, as its mark was last asked to say. */
118
+ marked: false,
119
+ /** Its mark's writes, one after another. */
120
+ writes: Promise.resolve(),
121
+ /** Keep its mark, or take it off, after any write before. */
122
+ mark(on) {
123
+ held.writes = held.writes
124
+ .then(() => (on ? store.set({ key, value: true }) : store.delete({ key })))
125
+ .then(() => { }, (error) => log.error("A thread's mark couldn't be written.", { thread, error: String(error) }));
126
+ },
127
+ loop: createLoop({
128
+ request: options.request,
129
+ model: options.model,
130
+ enter,
131
+ record,
132
+ out: {
133
+ message: (message) => out.message(thread, message),
134
+ delta: (id, text) => out.delta(thread, id, text),
135
+ status(status) {
136
+ const running = status.state === "thinking" || status.state === "tool";
137
+ // A turn that starts is marked, but one that goes on from a cut-off has that mark
138
+ // taken off: it goes on once. A turn that ends takes its mark off, but one cut by the
139
+ // looper closing keeps it, for whoever opens the store next.
140
+ if (running && !held.marked)
141
+ held.mark(!held.loop.resumed());
142
+ else if (!running && held.marked && !closed)
143
+ held.mark(false);
144
+ held.marked = running;
145
+ out.status(thread, status);
146
+ },
147
+ },
148
+ log,
149
+ }),
150
+ };
151
+ return held;
152
+ };
153
+ /**
154
+ * Ask something of a thread's loop. A thread first named by an ask that fails, with nothing else
155
+ * asked of it meanwhile, was never used: nothing is held for it.
156
+ */
157
+ const using = async (thread, ask) => {
158
+ const known = threads.has(thread);
159
+ const held = of(thread);
160
+ held.uses++;
161
+ try {
162
+ return await started(ask(held.loop));
163
+ }
164
+ catch (error) {
165
+ if (!known && held.uses === 1)
166
+ threads.delete(thread);
167
+ throw error;
168
+ }
169
+ finally {
170
+ held.uses--;
171
+ }
172
+ };
173
+ const of = (thread) => {
174
+ const found = threads.get(thread) ?? open(thread);
175
+ threads.set(thread, found);
176
+ return found;
177
+ };
178
+ /**
179
+ * Go on with each turn that was cut off when this store was last used: by a looper closing
180
+ * under it, or going without closing. Each goes on once, and waits for a place like any turn.
181
+ * One that can't go on now keeps its mark for the next time. A stopped looper goes on with
182
+ * none, and its marks go: so does one stopped before it was asked to. Whoever hosts the looper calls this when a request can be made;
183
+ * once the marks have been read, a later call does nothing.
184
+ */
185
+ async function resume() {
186
+ if (looked || closed)
187
+ return;
188
+ looked = true;
189
+ const keys = [];
190
+ try {
191
+ let after;
192
+ do {
193
+ const page = await store.list({ prefix: UNFINISHED, ...(after ? { after } : {}) });
194
+ keys.push(...page.keys);
195
+ after = page.next ?? undefined;
196
+ } while (after);
197
+ }
198
+ catch (error) {
199
+ looked = false;
200
+ throw error;
201
+ }
202
+ for (const key of keys) {
203
+ // Closed meanwhile: what is left stays marked, for whoever opens the store next.
204
+ if (closed)
205
+ return;
206
+ const thread = decodeURIComponent(key.slice(UNFINISHED.length));
207
+ const held = of(thread);
208
+ try {
209
+ if (!stopped)
210
+ await using(thread, (loop) => loop.resume());
211
+ // A thread in a turn now keeps the mark as that turn's, and a looper that has closed
212
+ // leaves it. Otherwise nothing goes on, and it goes.
213
+ if (!held.marked && !closed)
214
+ held.mark(false);
215
+ }
216
+ catch (error) {
217
+ log.warn("A turn that was cut off didn't go on.", { key, error: String(error) });
218
+ }
219
+ }
220
+ }
221
+ return {
222
+ /**
223
+ * Say a message in a thread. It is recorded and said at once. With no turn in the thread it
224
+ * starts one, which waits for a place if none is free; a turn running or waiting takes it at
225
+ * its next model request. Refused `busy` while `WAITING` turns already wait and it would start
226
+ * one more, or while the looper is stopped; and `unavailable` once it has closed.
227
+ */
228
+ async send(thread, text) {
229
+ mayStart();
230
+ const sent = await using(thread, (loop) => loop.send(text));
231
+ // Recorded as the looper closed, its turn was cut before it began: it is marked like one.
232
+ const held = threads.get(thread);
233
+ if (closed && held && !held.marked)
234
+ held.mark(true);
235
+ return sent;
236
+ },
237
+ /** Stop a thread's turn now. A call already running finishes, and its result is kept. */
238
+ cancel: async (thread) => threads.get(thread)?.loop.cancel(),
239
+ /** What a thread's loop is doing. */
240
+ state: (thread) => threads.get(thread)?.loop.state() ?? { state: "idle" },
241
+ /** A thread's messages before `before`, oldest first, as many as fit `limit`. */
242
+ page: (thread, before, limit) => of(thread).record.page(before, limit),
243
+ /**
244
+ * Stop: every turn is cut, running or waiting, and none starts until `start`. A call already
245
+ * running finishes first, so this answers when nothing more will be written. The records stay
246
+ * as they are, to be read. A turn that was cut off earlier no longer goes on.
247
+ */
248
+ async stop() {
249
+ stopped = true;
250
+ const loops = [...threads.values()].map(({ loop }) => loop);
251
+ await Promise.all(loops.map((loop) => loop.cancel()));
252
+ // A message being recorded as this was asked is recorded first, and a call still running ends.
253
+ await Promise.all(starting);
254
+ await Promise.all(loops.map((loop) => loop.drained()));
255
+ // What was cut off earlier and hasn't gone on doesn't after a stop either: its marks go.
256
+ await resume().catch((error) => log.warn("The turns that were cut off couldn't be looked for.", { error: String(error) }));
257
+ },
258
+ /** Take messages again. The turns `stop` cut stay cut. */
259
+ start() {
260
+ stopped = false;
261
+ },
262
+ resume,
263
+ /**
264
+ * Close for good: every turn is cut, and none starts after. Each stays marked, for `resume`
265
+ * in whoever opens the store next.
266
+ */
267
+ async close() {
268
+ closed = true;
269
+ await Promise.all([...threads.values()].map(({ loop }) => loop.cancel()));
270
+ },
271
+ /** Settles when every thread's latest turn has written all it will. */
272
+ async settled() {
273
+ await Promise.all([...threads.values()].map(({ loop }) => loop.settled()));
274
+ await Promise.all([...threads.values()].map(({ writes }) => writes));
275
+ },
276
+ /** Text the model writes while it answers `requestId`, for the reply it becomes. */
277
+ delta(requestId, text) {
278
+ for (const { loop } of threads.values())
279
+ loop.delta(requestId, text);
280
+ },
281
+ };
282
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * The record a loop runs on, kept in a store: one key per message, holding the items a model reads
3
+ * for it, and for a tool message the line a person sees. It is read once, then kept in memory, and
4
+ * the oldest messages are deleted past a retention cap.
5
+ */
6
+ import { z } from "zod";
7
+ import { Item, type Log, type Shown, type Store } from "./types.js";
8
+ /** A message as the record keeps it. */
9
+ export declare const Entry: z.ZodObject<{
10
+ id: z.ZodString;
11
+ role: z.ZodEnum<{
12
+ assistant: "assistant";
13
+ tool: "tool";
14
+ user: "user";
15
+ }>;
16
+ text: z.ZodOptional<z.ZodString>;
17
+ at: z.ZodString;
18
+ items: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
19
+ type: z.ZodLiteral<"message">;
20
+ role: z.ZodEnum<{
21
+ assistant: "assistant";
22
+ user: "user";
23
+ }>;
24
+ content: z.ZodString;
25
+ }, z.core.$strip>, z.ZodObject<{
26
+ type: z.ZodLiteral<"function_call">;
27
+ callId: z.ZodString;
28
+ name: z.ZodString;
29
+ arguments: z.ZodString;
30
+ }, z.core.$strip>, z.ZodObject<{
31
+ type: z.ZodLiteral<"function_call_output">;
32
+ callId: z.ZodString;
33
+ output: z.ZodString;
34
+ }, z.core.$strip>], "type">>;
35
+ state: z.ZodOptional<z.ZodEnum<{
36
+ done: "done";
37
+ refused: "refused";
38
+ }>>;
39
+ joined: z.ZodOptional<z.ZodLiteral<true>>;
40
+ ahead: z.ZodOptional<z.ZodNumber>;
41
+ }, z.core.$strip>;
42
+ export type Entry = z.output<typeof Entry>;
43
+ /** Where a record's messages are kept in its store. */
44
+ export declare const MESSAGES = "msg/";
45
+ /** What the model is sent of the past: the newest exchanges up to this many bytes of JSON. */
46
+ export declare const INPUT_BUDGET = 400000;
47
+ /** At most this many messages are kept, in at most this many bytes, oldest deleted first. */
48
+ export declare const KEEP = 2000;
49
+ export declare const KEEP_BYTES: number;
50
+ /** The first `length` UTF-16 units of `text`, never ending inside a surrogate pair. */
51
+ export declare function head(text: string, length: number): string;
52
+ /** `text`, cut so its JSON fits `max` bytes, saying so when it is cut. */
53
+ export declare function fitted(text: string, max: number): string;
54
+ /** What the person sees of a message. */
55
+ export declare const textOf: (entry: Entry) => string;
56
+ /** A call's arguments as they are kept and shown: past their cap, a note in their place. */
57
+ export declare const argumentsOf: (args: string) => string;
58
+ /**
59
+ * A message as it is shown. A tool message whose call ran carries `tool`: the call's name, how it
60
+ * ended, its arguments and its output.
61
+ */
62
+ export declare function messageOf(entry: Entry): Shown;
63
+ /** Stored values read at once when what is kept is first loaded. */
64
+ export declare const READS = 16;
65
+ export declare function createRecord(store: Store, log: Log, limits?: {
66
+ keep: number;
67
+ keepBytes: number;
68
+ }): {
69
+ /**
70
+ * Keep a message, under `id` or its own number, and delete the oldest past the cap. A tool
71
+ * message the store refuses is still kept in memory, since its call has run. `read` is given
72
+ * for what came of a model request that had read the record up to that number: when a user
73
+ * message was said since, it is kept as `ahead` of it.
74
+ */
75
+ append(entry: Omit<Entry, "id" | "at">, id?: string, read?: number): Promise<Entry>;
76
+ /** Whether nothing is kept. */
77
+ empty(): Promise<boolean>;
78
+ /** Messages before `before`, oldest first, as many as fit `limit` and `PAGE_BUDGET`. */
79
+ page(before: string | undefined, limit: number): Promise<{
80
+ messages: Shown[];
81
+ more: boolean;
82
+ }>;
83
+ /**
84
+ * The conversation to send: the newest exchanges (each from the user message that starts a turn
85
+ * on) that fit the budget, and always the latest two, so "go on" after a long turn still has
86
+ * that turn. When those two are over the budget, their oldest function arguments and outputs
87
+ * are left out, each call still paired with an output. A message said during a turn comes after
88
+ * whatever is `ahead` of it, so the model reads it as not yet answered. `read` is the number
89
+ * up to which every user message was read, for `append` and `saidAfter`: one still being
90
+ * written is not read yet.
91
+ */
92
+ input(): Promise<{
93
+ items: Item[];
94
+ read: number;
95
+ }>;
96
+ /** Whether a user message has been stored after the one numbered `read`, which `input` gave. */
97
+ saidAfter(read: number): Promise<boolean>;
98
+ };
99
+ export type LoopRecord = ReturnType<typeof createRecord>;
@@ -0,0 +1,278 @@
1
+ /**
2
+ * The record a loop runs on, kept in a store: one key per message, holding the items a model reads
3
+ * for it, and for a tool message the line a person sees. It is read once, then kept in memory, and
4
+ * the oldest messages are deleted past a retention cap.
5
+ */
6
+ import { z } from "zod";
7
+ import { Item } from "./types.js";
8
+ /** A message as the record keeps it. */
9
+ export const Entry = z.object({
10
+ id: z.string(),
11
+ role: z.enum(["user", "assistant", "tool"]),
12
+ /** What the person sees, for a tool message; the others show their message items. */
13
+ text: z.string().optional(),
14
+ at: z.string(),
15
+ items: z.array(Item),
16
+ /** For a tool message whose call ran: how it ended. */
17
+ state: z.enum(["done", "refused"]).optional(),
18
+ /** For a user message said while a turn was running: it is part of that turn. */
19
+ joined: z.literal(true).optional(),
20
+ /**
21
+ * For what came of a model request that had read the record up to the message of this number,
22
+ * when a user message was said after that: the model reads it ahead of that message, which it
23
+ * doesn't answer.
24
+ */
25
+ ahead: z.number().optional(),
26
+ });
27
+ /** Where a record's messages are kept in its store. */
28
+ export const MESSAGES = "msg/";
29
+ const keyOf = (seq) => `${MESSAGES}${String(seq).padStart(12, "0")}`;
30
+ const seqOf = (key) => Number(key.slice(MESSAGES.length)) || 0;
31
+ // The record's limits are fixed here for now, sized for a host that carries a model request, or a
32
+ // page of messages, in one piece of about a megabyte.
33
+ /** What the model is sent of the past: the newest exchanges up to this many bytes of JSON. */
34
+ export const INPUT_BUDGET = 400_000;
35
+ /** At most this many messages are kept, in at most this many bytes, oldest deleted first. */
36
+ export const KEEP = 2000;
37
+ export const KEEP_BYTES = 16 * 1024 * 1024;
38
+ /** A stored message's text, and a call's arguments, are cut to fit these, in bytes of JSON. */
39
+ const MAX_TEXT = 192 * 1024;
40
+ const MAX_ARGUMENTS = 16 * 1024;
41
+ /** A page of messages stays under this, so whatever carries it can do so in one piece. */
42
+ const PAGE_BUDGET = 512 * 1024;
43
+ const encoder = new TextEncoder();
44
+ const size = (value) => encoder.encode(JSON.stringify(value)).byteLength;
45
+ const LEFT_OUT = "(Left out: the conversation was too large to send it.)";
46
+ const ARGUMENTS_LEFT_OUT = '{"left_out":"too large to keep"}';
47
+ /** The first `length` UTF-16 units of `text`, never ending inside a surrogate pair. */
48
+ export function head(text, length) {
49
+ const cut = text.slice(0, length);
50
+ return /[\uD800-\uDBFF]$/.test(cut) ? cut.slice(0, -1) : cut;
51
+ }
52
+ /** `text`, cut so its JSON fits `max` bytes, saying so when it is cut. */
53
+ export function fitted(text, max) {
54
+ let kept = text;
55
+ for (let bytes = size(kept); bytes > max; bytes = size(kept))
56
+ kept = `${head(kept, Math.floor((kept.length * max) / bytes) - 16)}… (cut)`;
57
+ return kept;
58
+ }
59
+ /** A message shows at most this much; the record keeps all of it. */
60
+ const MAX_SHOWN = 100_000;
61
+ /** What the person sees of a message. */
62
+ export const textOf = (entry) => head(entry.text ??
63
+ entry.items.flatMap((item) => (item.type === "message" ? [item.content] : [])).join(""), MAX_SHOWN);
64
+ /** A call's arguments as they are kept and shown: past their cap, a note in their place. */
65
+ export const argumentsOf = (args) => size(args) > MAX_ARGUMENTS ? ARGUMENTS_LEFT_OUT : args;
66
+ /**
67
+ * A message as it is shown. A tool message whose call ran carries `tool`: the call's name, how it
68
+ * ended, its arguments and its output.
69
+ */
70
+ export function messageOf(entry) {
71
+ const message = { id: entry.id, role: entry.role, text: textOf(entry), at: entry.at };
72
+ const call = entry.items.find((item) => item.type === "function_call");
73
+ if (entry.role !== "tool" || !entry.state || !call)
74
+ return message;
75
+ const output = entry.items.find((item) => item.type === "function_call_output");
76
+ return {
77
+ ...message,
78
+ tool: {
79
+ name: head(call.name, 128),
80
+ state: entry.state,
81
+ input: head(call.arguments, MAX_SHOWN),
82
+ ...(output ? { output: head(output.output, MAX_SHOWN) } : {}),
83
+ },
84
+ };
85
+ }
86
+ /** A message as it is stored: each text once, and nothing past its cap. */
87
+ const kept = (entry) => ({
88
+ ...entry,
89
+ items: entry.items.map((item) => {
90
+ if (item.type === "message")
91
+ return { ...item, content: fitted(item.content, MAX_TEXT) };
92
+ if (item.type === "function_call_output")
93
+ return { ...item, output: fitted(item.output, MAX_TEXT) };
94
+ return { ...item, arguments: argumentsOf(item.arguments) };
95
+ }),
96
+ });
97
+ /** Stored values read at once when what is kept is first loaded. */
98
+ export const READS = 16;
99
+ /** Whether a user message follows the one numbered `read`: one `stored` already, when asked so. */
100
+ const saidAfter = (records, read, stored = false) => records.some((record) => record.entry.role === "user" && seqOf(record.key) > read && !(stored && record.writing));
101
+ export function createRecord(store, log, limits = { keep: KEEP, keepBytes: KEEP_BYTES }) {
102
+ let loaded;
103
+ const load = () => {
104
+ if (loaded)
105
+ return loaded;
106
+ const attempt = (async () => {
107
+ const records = [];
108
+ let last = 0;
109
+ let bytes = 0;
110
+ let after;
111
+ do {
112
+ const page = await store.list({
113
+ prefix: MESSAGES,
114
+ limit: 1000,
115
+ ...(after ? { after } : {}),
116
+ });
117
+ // A few at a time, in order: a long record shouldn't hold up the first send one read at
118
+ // a time, nor flood its store.
119
+ for (let at = 0; at < page.keys.length; at += READS) {
120
+ const keys = page.keys.slice(at, at + READS);
121
+ const values = await Promise.all(keys.map((key) => store.get({ key })));
122
+ keys.forEach((key, i) => {
123
+ last = Math.max(last, seqOf(key));
124
+ const parsed = Entry.safeParse(values[i]?.value);
125
+ if (!parsed.success) {
126
+ log.warn("A stored message didn't read back; it is left out.", { key });
127
+ return;
128
+ }
129
+ const record = { key, entry: parsed.data, bytes: size(parsed.data) };
130
+ records.push(record);
131
+ bytes += record.bytes;
132
+ });
133
+ }
134
+ after = page.next ?? undefined;
135
+ } while (after);
136
+ return { records, last, bytes };
137
+ })();
138
+ loaded = attempt;
139
+ attempt.catch(() => {
140
+ if (loaded === attempt)
141
+ loaded = undefined;
142
+ });
143
+ return attempt;
144
+ };
145
+ return {
146
+ /**
147
+ * Keep a message, under `id` or its own number, and delete the oldest past the cap. A tool
148
+ * message the store refuses is still kept in memory, since its call has run. `read` is given
149
+ * for what came of a model request that had read the record up to that number: when a user
150
+ * message was said since, it is kept as `ahead` of it.
151
+ */
152
+ async append(entry, id, read) {
153
+ const state = await load();
154
+ const key = keyOf(++state.last);
155
+ const record = {
156
+ key,
157
+ entry: kept({
158
+ id: id ?? key.slice(MESSAGES.length),
159
+ at: new Date().toISOString(),
160
+ ...entry,
161
+ ...(read !== undefined && saidAfter(state.records, read) ? { ahead: read } : {}),
162
+ }),
163
+ bytes: 0,
164
+ writing: entry.role === "user",
165
+ };
166
+ record.bytes = size(record.entry);
167
+ state.records.push(record);
168
+ state.bytes += record.bytes;
169
+ try {
170
+ await store.set({ key, value: record.entry });
171
+ record.writing = false;
172
+ }
173
+ catch (error) {
174
+ if (entry.role !== "tool") {
175
+ state.records.splice(state.records.indexOf(record), 1);
176
+ state.bytes -= record.bytes;
177
+ throw error;
178
+ }
179
+ log.error("A tool message couldn't be stored; it is kept until a restart.", {
180
+ error: String(error),
181
+ });
182
+ }
183
+ while (state.records.length > 1 &&
184
+ (state.records.length > limits.keep || state.bytes > limits.keepBytes)) {
185
+ const oldest = state.records.shift();
186
+ state.bytes -= oldest.bytes;
187
+ await store.delete({ key: oldest.key }).catch((error) => log.warn("An old message couldn't be deleted.", {
188
+ key: oldest.key,
189
+ error: String(error),
190
+ }));
191
+ }
192
+ return record.entry;
193
+ },
194
+ /** Whether nothing is kept. */
195
+ async empty() {
196
+ return (await load()).records.length === 0;
197
+ },
198
+ /** Messages before `before`, oldest first, as many as fit `limit` and `PAGE_BUDGET`. */
199
+ async page(before, limit) {
200
+ const { records } = await load();
201
+ const end = before === undefined
202
+ ? records.length
203
+ : records.findIndex((record) => record.entry.id === before);
204
+ const messages = [];
205
+ let bytes = 0;
206
+ let start = Math.max(end, 0);
207
+ while (start > 0 && messages.length < limit) {
208
+ const { entry } = records[start - 1];
209
+ const message = messageOf(entry);
210
+ bytes += size(message);
211
+ if (bytes > PAGE_BUDGET && messages.length > 0)
212
+ break;
213
+ messages.unshift(message);
214
+ start--;
215
+ }
216
+ return { messages, more: start > 0 };
217
+ },
218
+ /**
219
+ * The conversation to send: the newest exchanges (each from the user message that starts a turn
220
+ * on) that fit the budget, and always the latest two, so "go on" after a long turn still has
221
+ * that turn. When those two are over the budget, their oldest function arguments and outputs
222
+ * are left out, each call still paired with an output. A message said during a turn comes after
223
+ * whatever is `ahead` of it, so the model reads it as not yet answered. `read` is the number
224
+ * up to which every user message was read, for `append` and `saidAfter`: one still being
225
+ * written is not read yet.
226
+ */
227
+ async input() {
228
+ const { records, last } = await load();
229
+ const unwritten = records.find((record) => record.writing);
230
+ const read = unwritten ? seqOf(unwritten.key) - 1 : last;
231
+ const exchanges = [];
232
+ /** Said during a turn, and not yet put: what is ahead of them goes first. */
233
+ const late = [];
234
+ const put = (entry) => {
235
+ if ((entry.role === "user" && !entry.joined) || exchanges.length === 0)
236
+ exchanges.push([]);
237
+ exchanges.at(-1)?.push(...entry.items);
238
+ };
239
+ /** Put the late messages numbered up to `read`. */
240
+ const putLate = (read) => {
241
+ while (late[0] && seqOf(late[0].key) <= read)
242
+ put(late.shift().entry);
243
+ };
244
+ for (const record of records) {
245
+ // Nothing to send: a user message still being written, or a line with no items.
246
+ if (record.writing || record.entry.items.length === 0)
247
+ continue;
248
+ if (record.entry.joined) {
249
+ late.push(record);
250
+ continue;
251
+ }
252
+ putLate(record.entry.ahead ?? last);
253
+ put(record.entry);
254
+ }
255
+ putLate(last);
256
+ let total = exchanges.reduce((sum, items) => sum + size(items), 0);
257
+ while (exchanges.length > 2 && total > INPUT_BUDGET)
258
+ total -= size(exchanges.shift());
259
+ const items = exchanges.flat();
260
+ for (let i = 0; i < items.length && total > INPUT_BUDGET; i++) {
261
+ const item = items[i];
262
+ if (item.type === "function_call_output" && item.output !== LEFT_OUT) {
263
+ total -= size(item.output) - size(LEFT_OUT);
264
+ items[i] = { ...item, output: LEFT_OUT };
265
+ }
266
+ else if (item.type === "function_call" && item.arguments !== ARGUMENTS_LEFT_OUT) {
267
+ total -= size(item.arguments) - size(ARGUMENTS_LEFT_OUT);
268
+ items[i] = { ...item, arguments: ARGUMENTS_LEFT_OUT };
269
+ }
270
+ }
271
+ return { items, read };
272
+ },
273
+ /** Whether a user message has been stored after the one numbered `read`, which `input` gave. */
274
+ async saidAfter(read) {
275
+ return saidAfter((await load()).records, read, true);
276
+ },
277
+ };
278
+ }
@@ -0,0 +1,11 @@
1
+ /** Running the functions a model calls, and what is kept of their output. */
2
+ import { type Outcome, type Tool } from "./types.js";
3
+ /** A function's output keeps this many characters, so one result can't fill a request. */
4
+ export declare const MAX_OUTPUT = 30000;
5
+ /**
6
+ * `text`, or its first and last `MAX_OUTPUT / 2` characters with what was cut between them: a
7
+ * failing command's error is at the end, and what it was doing at the start.
8
+ */
9
+ export declare function capped(text: string): string;
10
+ /** Run a function call: the result, or the refusal, as the function's output. */
11
+ export declare function runTool(tools: Tool[], name: string, args: string): Promise<Outcome>;