thursday-agent 0.4.0 → 0.6.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 (657) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +3 -2
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/required-server-files.json +8 -1
  6. package/.next/routes-manifest.json +18 -6
  7. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  14. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/server/app/_not-found.html +1 -1
  16. package/.next/server/app/_not-found.rsc +13 -13
  17. package/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
  18. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
  19. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  20. package/.next/server/app/api/artifact/route.js +10 -6
  21. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  22. package/.next/server/app/api/bot/memory/files/route.js +6 -5
  23. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
  24. package/.next/server/app/api/bot/memory/route.js +8 -8
  25. package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
  26. package/.next/server/app/api/bot/route.js +8 -8
  27. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  28. package/.next/server/app/api/bot/thread/[id]/route/app-paths-manifest.json +3 -0
  29. package/.next/server/app/api/bot/thread/[id]/route.js +15 -0
  30. package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -0
  31. package/.next/server/app/api/bot/thread/[id]/route_client-reference-manifest.js +3 -0
  32. package/.next/server/app/api/bot/thread/route/app-paths-manifest.json +3 -0
  33. package/.next/server/app/api/bot/thread/route.js +15 -0
  34. package/.next/server/app/api/bot/thread/route.js.nft.json +1 -0
  35. package/.next/server/app/api/bot/thread/route_client-reference-manifest.js +3 -0
  36. package/.next/server/app/api/config/route.js +7 -7
  37. package/.next/server/app/api/config/route.js.nft.json +1 -1
  38. package/.next/server/app/api/events/route.js +3 -3
  39. package/.next/server/app/api/events/route.js.nft.json +1 -1
  40. package/.next/server/app/api/file/[...path]/route.js +5 -5
  41. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  42. package/.next/server/app/api/llm-model/catalog/route.js +8 -8
  43. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  44. package/.next/server/app/api/llm-model/credits/route.js +8 -8
  45. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
  46. package/.next/server/app/api/llm-model/route.js +8 -8
  47. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  48. package/.next/server/app/api/llm-model/subscription/route.js +8 -8
  49. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
  50. package/.next/server/app/api/mcp/[name]/route.js +6 -6
  51. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  52. package/.next/server/app/api/mcp/oauth/callback/route.js +4 -4
  53. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  54. package/.next/server/app/api/mcp/route.js +6 -6
  55. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  56. package/.next/server/app/api/mcp/tools/route.js +6 -6
  57. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  58. package/.next/server/app/api/memory/edit/route.js +13 -13
  59. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
  60. package/.next/server/app/api/memory/route.js +7 -6
  61. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  62. package/.next/server/app/api/skills/[source]/[name]/route.js +6 -6
  63. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  64. package/.next/server/app/api/skills/route.js +6 -6
  65. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  66. package/.next/server/app/api/thursday/call/route.js +10 -11
  67. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  68. package/.next/server/app/api/thursday/skills/route.js +10 -11
  69. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  70. package/.next/server/app/api/thursday/tool-call/route.js +15 -15
  71. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  72. package/.next/server/app/api/workspace/missing/route/app-paths-manifest.json +3 -0
  73. package/.next/server/app/api/workspace/missing/route/build-manifest.json +12 -0
  74. package/.next/server/app/api/workspace/missing/route/server-reference-manifest.json +4 -0
  75. package/.next/server/app/api/workspace/missing/route.js +12 -0
  76. package/.next/server/app/api/workspace/missing/route.js.map +5 -0
  77. package/.next/server/app/api/workspace/missing/route.js.nft.json +1 -0
  78. package/.next/server/app/api/workspace/missing/route_client-reference-manifest.js +3 -0
  79. package/.next/server/app/api/workspace/route.js +5 -4
  80. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  81. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
  82. package/.next/server/app/artifact/[...path]/page.js +4 -3
  83. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  84. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  85. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  86. package/.next/server/app/page/server-reference-manifest.json +67 -45
  87. package/.next/server/app/page.js +10 -9
  88. package/.next/server/app/page.js.nft.json +1 -1
  89. package/.next/server/app/page_client-reference-manifest.js +1 -1
  90. package/.next/server/app-paths-manifest.json +3 -2
  91. package/.next/server/chunks/[root-of-the-server]__02846fb._.js +8 -0
  92. package/.next/server/chunks/[root-of-the-server]__049f521._.js +3 -0
  93. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +3 -0
  94. package/.next/server/chunks/[root-of-the-server]__06--3q3._.js +8 -0
  95. package/.next/server/chunks/[root-of-the-server]__07bnah_._.js +3 -0
  96. package/.next/server/chunks/[root-of-the-server]__08eae20._.js +8 -0
  97. package/.next/server/chunks/[root-of-the-server]__0_ue8oe._.js +3 -0
  98. package/.next/server/chunks/[root-of-the-server]__0c9fgca._.js +5 -0
  99. package/.next/server/chunks/[root-of-the-server]__0g-ueei._.js +8 -0
  100. package/.next/server/chunks/[root-of-the-server]__0h_x6q6._.js +5 -0
  101. package/.next/server/chunks/{[root-of-the-server]__0pa2n68._.js → [root-of-the-server]__0kxrvxf._.js} +2 -2
  102. package/.next/server/chunks/{[root-of-the-server]__0q0vvt2._.js → [root-of-the-server]__0ov3iir._.js} +2 -2
  103. package/.next/server/chunks/[root-of-the-server]__0qwtlmx._.js +8 -0
  104. package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.js +3 -0
  105. package/.next/server/chunks/[root-of-the-server]__0ye3da2._.js +3 -0
  106. package/.next/server/chunks/[root-of-the-server]__0zp35ul._.js +5 -0
  107. package/.next/server/chunks/[root-of-the-server]__144u9d_._.js +3 -0
  108. package/.next/server/chunks/[root-of-the-server]__18-2tsq._.js +5 -0
  109. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +3 -0
  110. package/.next/server/chunks/[root-of-the-server]__1e2365e._.js +8 -0
  111. package/.next/server/chunks/[root-of-the-server]__1fix932._.js +8 -0
  112. package/.next/server/chunks/{[root-of-the-server]__0ce8nf8._.js → [root-of-the-server]__1g3t7vn._.js} +3 -3
  113. package/.next/server/chunks/[root-of-the-server]__1kp-83u._.js +5 -0
  114. package/.next/server/chunks/[root-of-the-server]__1kv8p3e._.js +5 -0
  115. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +2 -3
  116. package/.next/server/chunks/_02szwk8._.js +5 -0
  117. package/.next/server/chunks/_05h2cii._.js +1 -1
  118. package/.next/server/chunks/_06c9kie._.js +216 -0
  119. package/.next/server/chunks/{_1x6kd1r._.js → _07y2gj-._.js} +1 -1
  120. package/.next/server/chunks/_0a43a-0._.js +3 -0
  121. package/.next/server/chunks/_0bujjey._.js +5 -0
  122. package/.next/server/chunks/_0c9j6rb._.js +1 -1
  123. package/.next/server/chunks/_0dkd549._.js +3 -0
  124. package/.next/server/chunks/_0ej1kvv._.js +3 -0
  125. package/.next/server/chunks/_0f6ts7z._.js +3 -0
  126. package/.next/server/chunks/_0gm9hyv._.js +55 -0
  127. package/.next/server/chunks/_0i55en5._.js +25 -0
  128. package/.next/server/chunks/_0k50n27._.js +18 -0
  129. package/.next/server/chunks/_0khihjk._.js +3 -3
  130. package/.next/server/chunks/_0n74zsf._.js +5 -5
  131. package/.next/server/chunks/_0nvm9ef._.js +3 -0
  132. package/.next/server/chunks/_0p56fn0._.js +3 -0
  133. package/.next/server/chunks/_0recufk._.js +1 -1
  134. package/.next/server/chunks/_0xbkz10._.js +3 -0
  135. package/.next/server/chunks/_10tkr26._.js +3 -0
  136. package/.next/server/chunks/{_0ioz3nd._.js → _11u2kp7._.js} +1 -1
  137. package/.next/server/chunks/_11ujpya._.js +3 -0
  138. package/.next/server/chunks/_127nx_p._.js +5 -0
  139. package/.next/server/chunks/_17l5ygt._.js +1 -1
  140. package/.next/server/chunks/_19uauj6._.js +3 -0
  141. package/.next/server/chunks/_1_5mnq4._.js +5 -5
  142. package/.next/server/chunks/_1abl6t9._.js +55 -0
  143. package/.next/server/chunks/_1d0j961._.js +3 -3
  144. package/.next/server/chunks/_1dbixxz._.js +3 -0
  145. package/.next/server/chunks/_1dc_d1q._.js +98 -0
  146. package/.next/server/chunks/_1drgfx4._.js +5 -5
  147. package/.next/server/chunks/_1e48czp._.js +3 -3
  148. package/.next/server/chunks/_1f31u5x._.js +5 -0
  149. package/.next/server/chunks/_1kg70wc._.js +3 -3
  150. package/.next/server/chunks/_1klbcft._.js +5 -0
  151. package/.next/server/chunks/_1krd9rf._.js +4 -1
  152. package/.next/server/chunks/_1kwmzab._.js +3 -0
  153. package/.next/server/chunks/{_1pf4qe-._.js → _1oxj9fa._.js} +1 -1
  154. package/.next/server/chunks/{_1f46eie._.js → _1pcmdbb._.js} +1 -1
  155. package/.next/server/chunks/_1qgix-j._.js +3 -0
  156. package/.next/server/chunks/{lib_logger_ts_1exwjut._.js → _1rpchta._.js} +5 -5
  157. package/.next/server/chunks/_1vsej-s._.js +5 -0
  158. package/.next/server/chunks/_1yx0p_s._.js +5 -0
  159. package/.next/server/chunks/{_0rnf-6n._.js → _20fsr_z._.js} +6 -6
  160. package/.next/server/chunks/_2128hkj._.js +5 -0
  161. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_[id]_route_actions_1fstjn2.js +3 -0
  162. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_route_actions_003ccso.js +3 -0
  163. package/.next/server/chunks/_next-internal_server_app_api_workspace_missing_route_actions_1fidi6p.js +3 -0
  164. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  165. package/.next/server/chunks/features_0-cnt0l._.js +4 -0
  166. package/.next/server/chunks/features_0hdaci0._.js +4 -0
  167. package/.next/server/chunks/features_1e39j7-._.js +8 -0
  168. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
  169. package/.next/server/chunks/features_memory_1uqvksn._.js +1 -1
  170. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js → node_modules_consola_dist_chunks_prompt_mjs_0a7-pbw._.js} +1 -1
  171. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js → node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js} +1 -1
  172. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js → node_modules_consola_dist_chunks_prompt_mjs_107pxfn._.js} +1 -1
  173. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js → node_modules_consola_dist_chunks_prompt_mjs_15hbel8._.js} +1 -1
  174. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_18i-23e._.js +3 -0
  175. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1bewgf3._.js +3 -0
  176. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1kipdeo._.js +3 -0
  177. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1nlww1m._.js +3 -0
  178. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1q77nfx._.js +3 -0
  179. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xqdzx_._.js +3 -0
  180. package/.next/server/chunks/{node_modules_zod_v4_1801ax7._.js → node_modules_zod_v4_0lkux5-._.js} +2 -2
  181. package/.next/server/chunks/{node_modules_zod_v4_1cha_bw._.js → node_modules_zod_v4_1jmr9cq._.js} +2 -2
  182. package/.next/server/chunks/{node_modules_zod_v4_0ubdflj._.js → node_modules_zod_v4_1yrxmek._.js} +2 -2
  183. package/.next/server/chunks/node_modules_zod_v4_classic_errors_0tp0y-q.js +3 -0
  184. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  185. package/.next/server/chunks/ssr/[root-of-the-server]__0bxsfyn._.js +101 -0
  186. package/.next/server/chunks/ssr/[root-of-the-server]__0lyi8i2._.js +1 -1
  187. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  188. package/.next/server/chunks/ssr/[root-of-the-server]__172cq4x._.js +3 -0
  189. package/.next/server/chunks/ssr/[root-of-the-server]__18dthbp._.js +3 -0
  190. package/.next/server/chunks/ssr/[root-of-the-server]__18e68w8._.js +3 -0
  191. package/.next/server/chunks/ssr/[root-of-the-server]__1fll8dc._.js +3 -0
  192. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
  193. package/.next/server/chunks/ssr/[root-of-the-server]__1nygfik._.js +5 -0
  194. package/.next/server/chunks/ssr/[root-of-the-server]__1sdphb0._.js +8 -0
  195. package/.next/server/chunks/ssr/[root-of-the-server]__1waa3rc._.js +100 -0
  196. package/.next/server/chunks/ssr/_00rehl_._.js +3 -0
  197. package/.next/server/chunks/ssr/{_1lz_cq2._.js → _02oc_h5._.js} +76 -89
  198. package/.next/server/chunks/ssr/_03_928f._.js +3 -0
  199. package/.next/server/chunks/ssr/_05yghx6._.js +3 -0
  200. package/.next/server/chunks/ssr/_08c4z-9._.js +3 -0
  201. package/.next/server/chunks/ssr/_0_qfdlw._.js +4 -0
  202. package/.next/server/chunks/ssr/_0c9e5w6._.js +9 -0
  203. package/.next/server/chunks/ssr/{_0s99bgb._.js → _0dh2e1j._.js} +9 -3
  204. package/.next/server/chunks/ssr/_0dr-ddg._.js +3 -0
  205. package/.next/server/chunks/ssr/_0eaog6_._.js +3 -0
  206. package/.next/server/chunks/ssr/_0evkpto._.js +3 -0
  207. package/.next/server/chunks/ssr/_0g_rlog._.js +3 -0
  208. package/.next/server/chunks/ssr/_0geg212._.js +3 -0
  209. package/.next/server/chunks/ssr/{_1gd8q8l._.js → _0hxt2ul._.js} +2 -2
  210. package/.next/server/chunks/ssr/_0i_6q1w._.js +2 -2
  211. package/.next/server/chunks/ssr/_0lu1n_x._.js +1 -1
  212. package/.next/server/chunks/ssr/{_15j2_8f._.js → _0wzaht-._.js} +2 -2
  213. package/.next/server/chunks/ssr/_0z-g0uy._.js +3 -0
  214. package/.next/server/chunks/ssr/_123ttsf._.js +3 -0
  215. package/.next/server/chunks/ssr/_123y-ah._.js +3 -0
  216. package/.next/server/chunks/ssr/_12w42gi._.js +3 -0
  217. package/.next/server/chunks/ssr/_161kqav._.js +3 -0
  218. package/.next/server/chunks/ssr/{_0ap2fzn._.js → _16c6_xm._.js} +2 -2
  219. package/.next/server/chunks/ssr/_18opah7._.js +3 -0
  220. package/.next/server/chunks/ssr/_18xqmny._.js +3 -0
  221. package/.next/server/chunks/ssr/_1_krfph._.js +3 -0
  222. package/.next/server/chunks/ssr/{_1-_etts._.js → _1anqots._.js} +2 -2
  223. package/.next/server/chunks/ssr/_1ey7qn-._.js +70 -0
  224. package/.next/server/chunks/ssr/_1g9vs7q._.js +3 -0
  225. package/.next/server/chunks/ssr/_1jmz33w._.js +3 -0
  226. package/.next/server/chunks/ssr/{_0n3toaw._.js → _1k0spz7._.js} +2 -2
  227. package/.next/server/chunks/ssr/_1rgtxhr._.js +5 -0
  228. package/.next/server/chunks/ssr/_1slp25y._.js +3 -0
  229. package/.next/server/chunks/ssr/{_1fojd41._.js → _1x9pskj._.js} +3 -3
  230. package/.next/server/chunks/ssr/_1y6b5mr._.js +101 -0
  231. package/.next/server/chunks/ssr/_1ztk7p6._.js +7 -0
  232. package/.next/server/chunks/ssr/components_ui_tabs_tsx_0ej40b4._.js +3 -0
  233. package/.next/server/chunks/ssr/features_bot_thread_query_ts_023eklt._.js +4 -0
  234. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  235. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  236. package/.next/server/chunks/ssr/{_1-teee5._.js → lib_logger_ts_0-olsze._.js} +2 -7
  237. package/.next/server/chunks/ssr/{node_modules_0cxaxk9._.js → node_modules_00_51_v._.js} +1 -1
  238. package/.next/server/chunks/ssr/{node_modules_04jf_m8._.js → node_modules_022sipm._.js} +1 -1
  239. package/.next/server/chunks/ssr/{node_modules_0g7fzk3._.js → node_modules_0332gw4._.js} +1 -1
  240. package/.next/server/chunks/ssr/{node_modules_1cx_ql6._.js → node_modules_04vxchl._.js} +1 -1
  241. package/.next/server/chunks/ssr/{node_modules_1vh5ntv._.js → node_modules_0746rzi._.js} +1 -1
  242. package/.next/server/chunks/ssr/{node_modules_0yugy6m._.js → node_modules_0d5uzof._.js} +1 -1
  243. package/.next/server/chunks/ssr/{node_modules_09q35v_._.js → node_modules_0exkwcm._.js} +1 -1
  244. package/.next/server/chunks/ssr/{node_modules_08dhkiq._.js → node_modules_0fr-ml8._.js} +1 -1
  245. package/.next/server/chunks/ssr/{node_modules_14q6g4n._.js → node_modules_0mxvg8h._.js} +1 -1
  246. package/.next/server/chunks/ssr/{node_modules_0arus10._.js → node_modules_0qapgjr._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_1eg7m6c._.js → node_modules_0qbfyjh._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_1cz2hle._.js → node_modules_0t-9nup._.js} +1 -1
  249. package/.next/server/chunks/ssr/{node_modules_17bwo43._.js → node_modules_0tusx4d._.js} +3 -3
  250. package/.next/server/chunks/ssr/{node_modules_1efrqxi._.js → node_modules_0vsxbzp._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_0_-_a--._.js → node_modules_0vv0-fg._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_1gdh31p._.js → node_modules_0wsvp00._.js} +1 -1
  253. package/.next/server/chunks/ssr/{node_modules_1hpopmo._.js → node_modules_1-urho9._.js} +1 -1
  254. package/.next/server/chunks/ssr/{node_modules_1_pc9kq._.js → node_modules_16pi_dd._.js} +1 -1
  255. package/.next/server/chunks/ssr/{node_modules_00etblx._.js → node_modules_1d53yiq._.js} +1 -1
  256. package/.next/server/chunks/ssr/{node_modules_1aaxuef._.js → node_modules_1g1eihe._.js} +1 -1
  257. package/.next/server/chunks/ssr/{node_modules_198nmll._.js → node_modules_1gpednh._.js} +1 -1
  258. package/.next/server/chunks/ssr/{node_modules_0pvd7q-._.js → node_modules_1gu1pph._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_0b__sgl._.js → node_modules_1he1w8_._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_1qpjvy5._.js → node_modules_1lnjapm._.js} +1 -1
  261. package/.next/server/chunks/ssr/{node_modules_0940ns5._.js → node_modules_1lynj9m._.js} +1 -1
  262. package/.next/server/chunks/ssr/{node_modules_0x3-ply._.js → node_modules_1seuurl._.js} +2 -2
  263. package/.next/server/chunks/ssr/{node_modules_14om4ar._.js → node_modules_1u6w1pb._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_0had7xd._.js → node_modules_1xn6saw._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1b748ic._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_067_exa._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1z4hm5e._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0nrrdaq._.js} +1 -1
  267. package/.next/server/chunks/ssr/{node_modules_@vercel_oidc_dist_06mk8id._.js → node_modules_@vercel_oidc_dist_21a5haa._.js} +1 -1
  268. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_trash_mjs_0px2gzr._.js +3 -0
  269. package/.next/server/middleware-build-manifest.js +3 -3
  270. package/.next/server/pages/404.html +1 -1
  271. package/.next/server/pages/500.html +1 -1
  272. package/.next/server/server-reference-manifest.js +1 -1
  273. package/.next/server/server-reference-manifest.json +68 -46
  274. package/.next/static/chunks/0dr16v67vj4n7.js +2 -0
  275. package/.next/static/chunks/0g4b348l0pve7.js +1 -0
  276. package/.next/static/chunks/0joan-69kbspd.js +1 -0
  277. package/.next/static/chunks/0vlgzqo9ka90v.js +1 -0
  278. package/.next/static/chunks/0zrupxgci5gqc.js +1 -0
  279. package/.next/static/chunks/10k2xvap03z20.css +1 -0
  280. package/.next/static/chunks/18mkhstgiqcbt.js +1 -0
  281. package/.next/static/chunks/{15m575979un5f.js → 1i-u2wzub_to1.js} +2 -2
  282. package/.next/static/chunks/1kp5nfp06nj9h.js +5 -0
  283. package/.next/static/chunks/1ohslk4568tm3.js +1 -0
  284. package/.next/static/chunks/1sbmwswc9k2-1.js +1 -0
  285. package/.next/static/chunks/1t9qms5pwwa3n.js +1 -0
  286. package/.next/static/chunks/1vj_5bnbxx84e.js +1 -0
  287. package/.next/static/chunks/1vqezbhjm3goq.js +1 -0
  288. package/.next/static/chunks/{3akmqm77muj4-.js → 1wlo979mx-y3w.js} +1 -1
  289. package/.next/static/chunks/26ql4y-43xwhp.js +1 -0
  290. package/.next/static/chunks/{0fl3gwe4-l6tz.js → 2_pnccjp6j1ca.js} +1 -1
  291. package/.next/static/chunks/2a51-ywz9b2a3.js +1 -0
  292. package/.next/static/chunks/2fvdgxih7x7hr.js +1 -0
  293. package/.next/static/chunks/2jlz8zp4jax_m.js +18 -0
  294. package/.next/static/chunks/2nvepds1fu2ux.js +1 -0
  295. package/.next/static/chunks/3addj3i4-izma.js +1 -0
  296. package/.next/static/chunks/3bfwpww3m3x4u.js +1 -0
  297. package/.next/static/chunks/3gfh7nxwusbt0.js +1 -0
  298. package/.next/static/chunks/3gwa44cvz4qoi.js +1 -0
  299. package/.next/static/chunks/{38gweqdo4jpfj.js → 3izg0a3k87q1-.js} +5 -5
  300. package/.next/static/chunks/3zk6q3-3f9swq.js +99 -0
  301. package/.next/static/chunks/3zkg5iup3v4a2.js +12 -0
  302. package/.next/static/chunks/405m0bqtoihev.js +1 -0
  303. package/.next/static/chunks/42wcg3wfg_m_p.js +1 -0
  304. package/README.md +27 -216
  305. package/app/api/events/app-event.ts +6 -4
  306. package/app/api/query-key.ts +25 -16
  307. package/bin/database.mjs +37 -0
  308. package/bin/thursday.mjs +44 -28
  309. package/components/ui/custom-icon.tsx +0 -60
  310. package/components/ui/radio-group.tsx +37 -0
  311. package/components/ui/shiny-text.tsx +33 -6
  312. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/migration.sql +80 -24
  313. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/snapshot.json +689 -110
  314. package/database/migrations/20260916160713_thread_cancelled/migration.sql +2 -0
  315. package/database/migrations/{20260911030320_opposite_jack_power → 20260916160713_thread_cancelled}/snapshot.json +706 -84
  316. package/docs/how-it-works.md +39 -36
  317. package/docs/images/keeps-going.png +0 -0
  318. package/docs/images/two-minds.png +0 -0
  319. package/docs/live-calls.md +231 -0
  320. package/docs/thread-rooms.md +71 -0
  321. package/features/ai/chatgpt.ts +1 -2
  322. package/features/ai/live.schema.ts +128 -0
  323. package/features/ai/load-tools.ts +148 -77
  324. package/features/ai/model.schema.ts +2 -120
  325. package/features/ai/model.ts +52 -88
  326. package/features/ai/prompts/bot.prompt.ts +91 -214
  327. package/features/ai/prompts/live.prompt.ts +265 -0
  328. package/features/ai/prompts/prompt-helper.ts +91 -32
  329. package/features/ai/prompts/thursday.prompt.ts +125 -172
  330. package/features/ai/tools/bot.tool.ts +38 -145
  331. package/features/ai/tools/call.tool.ts +1 -1
  332. package/features/ai/tools/connected.ts +5 -3
  333. package/features/ai/tools/mcp.tool.ts +7 -4
  334. package/features/ai/tools/memory.tool.ts +35 -31
  335. package/features/ai/tools/skills.tool.ts +36 -14
  336. package/features/ai/tools/studio.tool.ts +26 -21
  337. package/features/ai/tools/tool-name.ts +2 -5
  338. package/features/ai/tools/workspace.tool.ts +33 -10
  339. package/features/artifact/artifact.action.ts +2 -2
  340. package/features/artifact/artifact.query.ts +112 -61
  341. package/features/artifact/artifact.schema.ts +8 -6
  342. package/features/artifact/components/artifact-setting.tsx +83 -33
  343. package/features/bot/bot.action.ts +43 -36
  344. package/features/bot/bot.memory.ts +137 -20
  345. package/features/bot/bot.query.ts +28 -11
  346. package/features/bot/bot.run.ts +299 -636
  347. package/features/bot/bot.runner.ts +468 -844
  348. package/features/bot/bot.schema.ts +93 -82
  349. package/features/bot/bot.seed.ts +141 -64
  350. package/features/bot/components/bot-mark.tsx +324 -232
  351. package/features/bot/components/bot-room.tsx +1613 -697
  352. package/features/bot/components/bot-roster.tsx +8 -13
  353. package/features/bot/components/bot-setting.tsx +58 -42
  354. package/features/bot/components/bot-tool.tsx +55 -87
  355. package/features/bot/components/mark-palette.tsx +35 -32
  356. package/features/bot/components/path-chips.tsx +33 -3
  357. package/features/bot/components/thread-badge.tsx +34 -0
  358. package/features/bot/components/thread-reply.tsx +639 -0
  359. package/features/bot/components/thread-setting.tsx +674 -0
  360. package/features/bot/mark.const.ts +79 -31
  361. package/features/bot/room.query.ts +889 -0
  362. package/features/bot/room.schema.ts +64 -0
  363. package/features/bot/seed-bots.ts +2 -1
  364. package/features/bot/thread.query.ts +971 -0
  365. package/features/bot/thread.store.ts +587 -0
  366. package/features/config/components/voice-key.tsx +113 -88
  367. package/features/config/config.const.ts +5 -9
  368. package/features/connectors/mcp.schema.ts +0 -2
  369. package/features/intro/components/intro.tsx +169 -139
  370. package/features/memory/components/memory-setting.tsx +2 -7
  371. package/features/memory/memory.schema.ts +14 -23
  372. package/features/settings/components/setting-ui.tsx +0 -44
  373. package/features/settings/components/settings.tsx +12 -12
  374. package/features/settings/settings.alert.ts +3 -3
  375. package/features/settings/settings.store.ts +1 -1
  376. package/features/skills/skills.schema.ts +0 -2
  377. package/features/thursday/components/ascii-field.tsx +24 -44
  378. package/features/thursday/components/ascii-orb.tsx +359 -358
  379. package/features/thursday/components/call-log.tsx +46 -44
  380. package/features/thursday/components/face.tsx +35 -10
  381. package/features/thursday/components/tab-state.tsx +3 -3
  382. package/features/thursday/components/thursday-mark.tsx +1 -0
  383. package/features/thursday/components/thursday-setting.tsx +631 -332
  384. package/features/thursday/components/thursday.tsx +106 -41
  385. package/features/thursday/components/voice-picker.tsx +255 -0
  386. package/features/thursday/thursday.action.ts +94 -68
  387. package/features/thursday/thursday.query.ts +49 -30
  388. package/features/thursday/thursday.schema.ts +27 -30
  389. package/features/thursday/thursday.store.ts +11 -7
  390. package/features/thursday/tool-call.ts +3 -3
  391. package/features/thursday/tool-line.ts +5 -3
  392. package/features/thursday/use-thursday.ts +725 -450
  393. package/features/workspace/workspace.query.ts +17 -0
  394. package/features/workspace/workspace.ts +103 -50
  395. package/lib/live/live.schema.ts +47 -0
  396. package/lib/live/live.server.ts +155 -0
  397. package/lib/live/live.session.ts +574 -0
  398. package/lib/{realtime/realtime.tap.ts → live/live.tap.ts} +41 -12
  399. package/lib/live/live.transport.ts +152 -0
  400. package/lib/protocol/use-server-pages.ts +9 -5
  401. package/lib/utils.ts +21 -20
  402. package/package.json +2 -2
  403. package/public/voices/alloy.ogg +0 -0
  404. package/public/voices/ash.ogg +0 -0
  405. package/public/voices/ballad.ogg +0 -0
  406. package/public/voices/beacon.ogg +0 -0
  407. package/public/voices/bossa.ogg +0 -0
  408. package/public/voices/cedar.ogg +0 -0
  409. package/public/voices/cinder.ogg +0 -0
  410. package/public/voices/coral.ogg +0 -0
  411. package/public/voices/delta.ogg +0 -0
  412. package/public/voices/echo.ogg +0 -0
  413. package/public/voices/gleam.ogg +0 -0
  414. package/public/voices/marin.ogg +0 -0
  415. package/public/voices/meridian.ogg +0 -0
  416. package/public/voices/quartz.ogg +0 -0
  417. package/public/voices/ripple.ogg +0 -0
  418. package/public/voices/sage.ogg +0 -0
  419. package/public/voices/shimmer.ogg +0 -0
  420. package/public/voices/stone.ogg +0 -0
  421. package/public/voices/tempo.ogg +0 -0
  422. package/public/voices/verse.ogg +0 -0
  423. package/public/voices/vesper.ogg +0 -0
  424. package/public/voices/willow.ogg +0 -0
  425. package/scripts/artifact-paths.test.mts +25 -0
  426. package/scripts/bot-context.test.mts +1408 -0
  427. package/scripts/live-history.test.mts +115 -0
  428. package/scripts/live-session.test.mts +948 -0
  429. package/server.js +1 -1
  430. package/skills/browser/SKILL.md +17 -6
  431. package/skills/computer/SKILL.md +1 -1
  432. package/skills/find-skills/SKILL.md +3 -8
  433. package/skills/interactive-page/SKILL.md +12 -7
  434. package/skills/interactive-page/references/diagram.md +89 -0
  435. package/skills/interactive-page/scripts/archify/LICENSE +22 -0
  436. package/skills/interactive-page/scripts/archify/README.md +25 -0
  437. package/skills/interactive-page/scripts/archify/assets/JetBrainsMono-OFL.txt +93 -0
  438. package/skills/interactive-page/scripts/archify/assets/template.html +14934 -0
  439. package/skills/interactive-page/scripts/archify/bin/archify.mjs +2126 -0
  440. package/skills/interactive-page/scripts/archify/bin/open-artifact.mjs +86 -0
  441. package/skills/interactive-page/scripts/archify/bin/preview.mjs +653 -0
  442. package/skills/interactive-page/scripts/archify/bin/visual-check.mjs +829 -0
  443. package/skills/interactive-page/scripts/archify/delta/architecture-delta.mjs +1223 -0
  444. package/skills/interactive-page/scripts/archify/examples/agent-run.lifecycle.json +60 -0
  445. package/skills/interactive-page/scripts/archify/examples/agent-tool-call.workflow.json +94 -0
  446. package/skills/interactive-page/scripts/archify/examples/async-job-roundtrip.sequence.json +61 -0
  447. package/skills/interactive-page/scripts/archify/examples/cache-miss-request.sequence.json +82 -0
  448. package/skills/interactive-page/scripts/archify/examples/checkout-platform.base.architecture.json +31 -0
  449. package/skills/interactive-page/scripts/archify/examples/checkout-platform.head.architecture.json +31 -0
  450. package/skills/interactive-page/scripts/archify/examples/deployment-release.lifecycle.json +49 -0
  451. package/skills/interactive-page/scripts/archify/examples/event-stream.dataflow.json +57 -0
  452. package/skills/interactive-page/scripts/archify/examples/incident-response.workflow.json +64 -0
  453. package/skills/interactive-page/scripts/archify/examples/product-analytics.dataflow.json +76 -0
  454. package/skills/interactive-page/scripts/archify/examples/production-deployment.architecture.json +71 -0
  455. package/skills/interactive-page/scripts/archify/examples/release-delivery.workflow.json +62 -0
  456. package/skills/interactive-page/scripts/archify/examples/web-app.architecture.json +46 -0
  457. package/skills/interactive-page/scripts/archify/migrations/workflow-v2.mjs +279 -0
  458. package/skills/interactive-page/scripts/archify/recipes/scenarios.mjs +284 -0
  459. package/skills/interactive-page/scripts/archify/references/authoring-contract.md +243 -0
  460. package/skills/interactive-page/scripts/archify/references/delivery-contract.md +120 -0
  461. package/skills/interactive-page/scripts/archify/references/viewer-runtime.md +45 -0
  462. package/skills/interactive-page/scripts/archify/renderers/architecture/grid.mjs +62 -0
  463. package/skills/interactive-page/scripts/archify/renderers/architecture/render-architecture.mjs +1078 -0
  464. package/skills/interactive-page/scripts/archify/renderers/dataflow/README.md +104 -0
  465. package/skills/interactive-page/scripts/archify/renderers/dataflow/render-dataflow.mjs +483 -0
  466. package/skills/interactive-page/scripts/archify/renderers/lifecycle/README.md +115 -0
  467. package/skills/interactive-page/scripts/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
  468. package/skills/interactive-page/scripts/archify/renderers/sequence/README.md +114 -0
  469. package/skills/interactive-page/scripts/archify/renderers/sequence/render-sequence.mjs +464 -0
  470. package/skills/interactive-page/scripts/archify/renderers/shared/brand-marks.mjs +563 -0
  471. package/skills/interactive-page/scripts/archify/renderers/shared/cli.mjs +218 -0
  472. package/skills/interactive-page/scripts/archify/renderers/shared/desktop-readability.mjs +26 -0
  473. package/skills/interactive-page/scripts/archify/renderers/shared/diagnostics.mjs +127 -0
  474. package/skills/interactive-page/scripts/archify/renderers/shared/engineering-profiles.mjs +157 -0
  475. package/skills/interactive-page/scripts/archify/renderers/shared/generated-brand-marks.mjs +3 -0
  476. package/skills/interactive-page/scripts/archify/renderers/shared/generated-validators.mjs +13 -0
  477. package/skills/interactive-page/scripts/archify/renderers/shared/geometry.mjs +1423 -0
  478. package/skills/interactive-page/scripts/archify/renderers/shared/i18n.mjs +595 -0
  479. package/skills/interactive-page/scripts/archify/renderers/shared/layout-report.mjs +40 -0
  480. package/skills/interactive-page/scripts/archify/renderers/shared/legend.mjs +217 -0
  481. package/skills/interactive-page/scripts/archify/renderers/shared/output-path.mjs +340 -0
  482. package/skills/interactive-page/scripts/archify/renderers/shared/repository-evidence.mjs +238 -0
  483. package/skills/interactive-page/scripts/archify/renderers/shared/repository-location.mjs +58 -0
  484. package/skills/interactive-page/scripts/archify/renderers/shared/text-fit.mjs +49 -0
  485. package/skills/interactive-page/scripts/archify/renderers/shared/utils.mjs +232 -0
  486. package/skills/interactive-page/scripts/archify/renderers/shared/validator.mjs +86 -0
  487. package/skills/interactive-page/scripts/archify/renderers/workflow/README.md +223 -0
  488. package/skills/interactive-page/scripts/archify/renderers/workflow/render-workflow.mjs +35 -0
  489. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  490. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  491. package/skills/interactive-page/scripts/archify/schemas/README.md +211 -0
  492. package/skills/interactive-page/scripts/archify/schemas/architecture.schema.json +178 -0
  493. package/skills/interactive-page/scripts/archify/schemas/common.schema.json +115 -0
  494. package/skills/interactive-page/scripts/archify/schemas/dataflow.schema.json +243 -0
  495. package/skills/interactive-page/scripts/archify/schemas/lifecycle.schema.json +266 -0
  496. package/skills/interactive-page/scripts/archify/schemas/sequence.schema.json +223 -0
  497. package/skills/interactive-page/scripts/archify/schemas/workflow.schema.json +428 -0
  498. package/skills/interactive-page/scripts/archify/scripts/check-render-output.mjs +916 -0
  499. package/skills/interactive-page/scripts/archify/scripts/render-examples.mjs +26 -0
  500. package/skills/interactive-page/scripts/bundle-artifact.sh +9 -8
  501. package/skills/skill-creator/SKILL.md +4 -5
  502. package/.next/server/app/api/bot/task/[id]/route/app-paths-manifest.json +0 -3
  503. package/.next/server/app/api/bot/task/[id]/route.js +0 -16
  504. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +0 -1
  505. package/.next/server/app/api/bot/task/[id]/route_client-reference-manifest.js +0 -3
  506. package/.next/server/app/api/bot/task/route/app-paths-manifest.json +0 -3
  507. package/.next/server/app/api/bot/task/route.js +0 -16
  508. package/.next/server/app/api/bot/task/route.js.nft.json +0 -1
  509. package/.next/server/app/api/bot/task/route_client-reference-manifest.js +0 -3
  510. package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +0 -3
  511. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +0 -3
  512. package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +0 -3
  513. package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +0 -8
  514. package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +0 -3
  515. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +0 -3
  516. package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +0 -8
  517. package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +0 -8
  518. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +0 -3
  519. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +0 -5
  520. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +0 -5
  521. package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +0 -3
  522. package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +0 -8
  523. package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +0 -8
  524. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +0 -5
  525. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +0 -3
  526. package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +0 -10
  527. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +0 -3
  528. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +0 -3
  529. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +0 -3
  530. package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +0 -8
  531. package/.next/server/chunks/_0-73of8._.js +0 -55
  532. package/.next/server/chunks/_0-fjql4._.js +0 -26
  533. package/.next/server/chunks/_00xh_q0._.js +0 -25
  534. package/.next/server/chunks/_03a0897._.js +0 -3
  535. package/.next/server/chunks/_051qh8u._.js +0 -3
  536. package/.next/server/chunks/_05sovvj._.js +0 -3
  537. package/.next/server/chunks/_0fzqt2y._.js +0 -134
  538. package/.next/server/chunks/_0mecv0f._.js +0 -26
  539. package/.next/server/chunks/_0mh8j4m._.js +0 -3
  540. package/.next/server/chunks/_0obojvv._.js +0 -3
  541. package/.next/server/chunks/_0sb7tlz._.js +0 -3
  542. package/.next/server/chunks/_0sbynis._.js +0 -3
  543. package/.next/server/chunks/_0u10wmw._.js +0 -55
  544. package/.next/server/chunks/_0u4aiy2._.js +0 -3
  545. package/.next/server/chunks/_0wp4le3._.js +0 -3
  546. package/.next/server/chunks/_0y5fg-x._.js +0 -3
  547. package/.next/server/chunks/_1230wbx._.js +0 -10
  548. package/.next/server/chunks/_12nheja._.js +0 -3
  549. package/.next/server/chunks/_13510xh._.js +0 -3
  550. package/.next/server/chunks/_15hq89o._.js +0 -3
  551. package/.next/server/chunks/_18-1wcc._.js +0 -55
  552. package/.next/server/chunks/_1_9mjx-._.js +0 -3
  553. package/.next/server/chunks/_1c78vw5._.js +0 -229
  554. package/.next/server/chunks/_1h5_8sk._.js +0 -3
  555. package/.next/server/chunks/_1hdnxb7._.js +0 -3
  556. package/.next/server/chunks/_1j8k_j5._.js +0 -3
  557. package/.next/server/chunks/_1nula3v._.js +0 -3
  558. package/.next/server/chunks/_1php4eq._.js +0 -3
  559. package/.next/server/chunks/_1yuv4vp._.js +0 -3
  560. package/.next/server/chunks/_1zjrdag._.js +0 -3
  561. package/.next/server/chunks/_next-internal_server_app_api_bot_task_[id]_route_actions_1_k_8u3.js +0 -3
  562. package/.next/server/chunks/_next-internal_server_app_api_bot_task_route_actions_0xln6ra.js +0 -3
  563. package/.next/server/chunks/features_0rpfxbk._.js +0 -3
  564. package/.next/server/chunks/features_1qf3cei._.js +0 -3
  565. package/.next/server/chunks/features_bot_0zt92oh._.js +0 -3
  566. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +0 -3
  567. package/.next/server/chunks/ssr/[externals]__0dizgek._.js +0 -3
  568. package/.next/server/chunks/ssr/[root-of-the-server]__092knlj._.js +0 -3
  569. package/.next/server/chunks/ssr/[root-of-the-server]__0mz33a7._.js +0 -3
  570. package/.next/server/chunks/ssr/[root-of-the-server]__0s9dq5u._.js +0 -3
  571. package/.next/server/chunks/ssr/[root-of-the-server]__0s9l2sv._.js +0 -3
  572. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +0 -3
  573. package/.next/server/chunks/ssr/[root-of-the-server]__0xsog8n._.js +0 -3
  574. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +0 -61
  575. package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +0 -43
  576. package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +0 -4
  577. package/.next/server/chunks/ssr/[root-of-the-server]__202p40z._.js +0 -3
  578. package/.next/server/chunks/ssr/_001_ms1._.js +0 -28
  579. package/.next/server/chunks/ssr/_01n3o0m._.js +0 -3
  580. package/.next/server/chunks/ssr/_0fz4mf_._.js +0 -3
  581. package/.next/server/chunks/ssr/_0gb4gmf._.js +0 -3
  582. package/.next/server/chunks/ssr/_0h42fze._.js +0 -3
  583. package/.next/server/chunks/ssr/_0h7zdni._.js +0 -3
  584. package/.next/server/chunks/ssr/_0ilna52._.js +0 -42
  585. package/.next/server/chunks/ssr/_0q0zan6._.js +0 -70
  586. package/.next/server/chunks/ssr/_0zcjrbg._.js +0 -3
  587. package/.next/server/chunks/ssr/_0zhoc3r._.js +0 -3
  588. package/.next/server/chunks/ssr/_13fke0x._.js +0 -3
  589. package/.next/server/chunks/ssr/_18cymkq._.js +0 -3
  590. package/.next/server/chunks/ssr/_1b2mjwr._.js +0 -3
  591. package/.next/server/chunks/ssr/_1f-dg-6._.js +0 -3
  592. package/.next/server/chunks/ssr/_1h0rw11._.js +0 -3
  593. package/.next/server/chunks/ssr/_1jhd09t._.js +0 -3
  594. package/.next/server/chunks/ssr/_1nnsk7z._.js +0 -3
  595. package/.next/server/chunks/ssr/_1ov37if._.js +0 -3
  596. package/.next/server/chunks/ssr/_1sji22n._.js +0 -3
  597. package/.next/server/chunks/ssr/_1vi_uo7._.js +0 -3
  598. package/.next/server/chunks/ssr/_1vyd1ji._.js +0 -3
  599. package/.next/server/chunks/ssr/_1xx4zlb._.js +0 -3
  600. package/.next/server/chunks/ssr/components_ui_1y1l7yj._.js +0 -3
  601. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +0 -3
  602. package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +0 -27
  603. package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +0 -27
  604. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0npjf8-._.js +0 -3
  605. package/.next/static/chunks/00rd4-v8r7axp.js +0 -1
  606. package/.next/static/chunks/08qe4as2q428z.js +0 -3
  607. package/.next/static/chunks/0gnqdjn2lvdad.js +0 -2
  608. package/.next/static/chunks/0hwap1-p0m5sa.js +0 -1
  609. package/.next/static/chunks/0r5qcctujhxli.js +0 -1
  610. package/.next/static/chunks/0w52rrrmuj9r9.js +0 -1
  611. package/.next/static/chunks/0wcprt5ot5she.js +0 -1
  612. package/.next/static/chunks/10teww7wt-f6h.js +0 -1
  613. package/.next/static/chunks/17p6tk6k88dq6.js +0 -1
  614. package/.next/static/chunks/18a96rkhi4_yd.js +0 -1
  615. package/.next/static/chunks/1dkjg87pxk0n9.js +0 -28
  616. package/.next/static/chunks/1jd09sxcjddu1.js +0 -1
  617. package/.next/static/chunks/1w73ece_6bheu.js +0 -18
  618. package/.next/static/chunks/214ya3n5gxeih.js +0 -1
  619. package/.next/static/chunks/22_zkas21rpna.js +0 -1
  620. package/.next/static/chunks/2fh4-3z_q8b_w.js +0 -1
  621. package/.next/static/chunks/2h0sd2vumhb15.js +0 -1
  622. package/.next/static/chunks/2t4vhi3m8ahya.js +0 -1
  623. package/.next/static/chunks/2tigdtz3dpcy8.js +0 -1
  624. package/.next/static/chunks/2u7xt6mxg44lf.js +0 -1
  625. package/.next/static/chunks/3786h5vayt80-.js +0 -28
  626. package/.next/static/chunks/39j0fvpybzabl.js +0 -40
  627. package/.next/static/chunks/3cq5g494yuke8.css +0 -1
  628. package/.next/static/chunks/3hibbjnt85-k6.js +0 -1
  629. package/.next/static/chunks/3woj-xd7ki5_i.js +0 -1
  630. package/.next/static/chunks/3xk7yqgomx7yq.js +0 -1
  631. package/.next/static/chunks/3zmcsnuo25zvq.js +0 -1
  632. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +0 -1
  633. package/docs/images/task-thread.png +0 -0
  634. package/features/bot/components/task-badge.tsx +0 -42
  635. package/features/bot/components/task-reply.tsx +0 -328
  636. package/features/bot/components/task-setting.tsx +0 -524
  637. package/features/bot/task.query.ts +0 -976
  638. package/features/bot/task.store.ts +0 -489
  639. package/lib/realtime/client-secret.ts +0 -86
  640. package/lib/realtime/open-session.ts +0 -31
  641. package/lib/realtime/openai.ts +0 -35
  642. package/lib/realtime/realtime.audio.ts +0 -196
  643. package/lib/realtime/realtime.driver.ts +0 -489
  644. package/lib/realtime/realtime.protocol.ts +0 -393
  645. package/lib/realtime/realtime.schema.ts +0 -37
  646. package/lib/realtime/realtime.session.ts +0 -106
  647. package/lib/realtime/realtime.transport.ts +0 -384
  648. package/lib/realtime/xai.ts +0 -39
  649. /package/.next/server/app/api/bot/{task → thread}/[id]/route/build-manifest.json +0 -0
  650. /package/.next/server/app/api/bot/{task → thread}/[id]/route/server-reference-manifest.json +0 -0
  651. /package/.next/server/app/api/bot/{task → thread}/[id]/route.js.map +0 -0
  652. /package/.next/server/app/api/bot/{task → thread}/route/build-manifest.json +0 -0
  653. /package/.next/server/app/api/bot/{task → thread}/route/server-reference-manifest.json +0 -0
  654. /package/.next/server/app/api/bot/{task → thread}/route.js.map +0 -0
  655. /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_buildManifest.js +0 -0
  656. /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_clientMiddlewareManifest.js +0 -0
  657. /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_ssgManifest.js +0 -0
@@ -15,7 +15,7 @@ import {
15
15
  Trash2,
16
16
  Video,
17
17
  } from "lucide-react";
18
- import { useState } from "react";
18
+ import { Fragment, useState } from "react";
19
19
  import { queryKey } from "@/app/api/query-key";
20
20
  import { Button } from "@/components/ui/button";
21
21
  import { notify } from "@/components/ui/notify";
@@ -28,6 +28,8 @@ import type {
28
28
  ArtifactSet,
29
29
  ArtifactShelf,
30
30
  } from "@/features/artifact/artifact.schema";
31
+ import type { Bot } from "@/features/bot/bot.schema";
32
+ import { BotMark } from "@/features/bot/components/bot-mark";
31
33
  import {
32
34
  SettingError,
33
35
  SettingFilter,
@@ -44,14 +46,14 @@ import { revalidate, useServerRoute } from "@/lib/protocol/use-server-route";
44
46
  import { cn, formatBytes } from "@/lib/utils";
45
47
 
46
48
  /*
47
- * What the bots finished, listed the way they already file it: one entry at the
48
- * top of `artifacts/` is one artifact. A skill writes `artifacts/<name>.html`,
49
- * a job that makes a set writes `artifacts/<name>/`.
49
+ * What the bots finished, listed the way they file it: each bot writes into
50
+ * `artifacts/<bot>/`, and one entry there is one artifact. A skill writes
51
+ * `<name>.html`, a job that makes a set writes `<name>/`.
50
52
  *
51
53
  * So this is not Workspace pointed at one folder. There is no tree here: the
52
- * menu is flat and newest-first, and a folder does not open into another
53
- * listing — it opens as a sheet of what it holds, which is the thing a set of
54
- * pictures is for. Browsing a tree is Workspace's job.
54
+ * menu is newest-first under each bot's face, and a folder does not open into
55
+ * another listing — it opens as a sheet of what it holds, which is the thing a
56
+ * set of pictures is for. Browsing a tree is Workspace's job.
55
57
  */
56
58
 
57
59
  /** Every kind `viewKindOf` returns, plus the set. One icon table, as in Workspace. */
@@ -80,6 +82,7 @@ export function ArtifactSetting() {
80
82
  { keepPreviousData: true },
81
83
  );
82
84
 
85
+ const { data: bots } = useServerRoute<Bot[]>(queryKey.bot);
83
86
  const [reveal] = useServerAction(openFileAction);
84
87
 
85
88
  if (isLoading) return <SettingPanesSkeleton />;
@@ -89,7 +92,11 @@ export function ArtifactSetting() {
89
92
  const total = data?.total ?? 0;
90
93
  const needle = filter.trim().toLowerCase();
91
94
  const shown = needle
92
- ? entries.filter((entry) => entry.name.toLowerCase().includes(needle))
95
+ ? entries.filter(
96
+ (entry) =>
97
+ entry.name.toLowerCase().includes(needle) ||
98
+ entry.bot?.toLowerCase().includes(needle),
99
+ )
93
100
  : entries;
94
101
 
95
102
  // A fresh row when the open one is still listed, so a rewrite shows through
@@ -130,13 +137,29 @@ export function ArtifactSetting() {
130
137
  {needle ? "Nothing matches" : "Nothing here yet"}
131
138
  </p>
132
139
  ) : (
133
- shown.map((entry) => (
134
- <MenuRow
135
- key={entry.path}
136
- entry={entry}
137
- active={entry.path === picked?.path}
138
- onPick={() => setReading({ row: entry, file: null })}
139
- />
140
+ groupByBot(shown).map(({ bot, rows }) => (
141
+ <Fragment key={bot ?? ""}>
142
+ <span className="flex items-center gap-1.5 px-3 pt-3 pb-1 font-mono text-[10px] text-muted-foreground/60">
143
+ {bot && (
144
+ <BotMark
145
+ size={12}
146
+ seed={bot}
147
+ {...markOf(bot, bots)}
148
+ notify={false}
149
+ className="shrink-0"
150
+ />
151
+ )}
152
+ <span className="truncate">{bot ?? "Unsorted"}</span>
153
+ </span>
154
+ {rows.map((entry) => (
155
+ <MenuRow
156
+ key={entry.path}
157
+ entry={entry}
158
+ active={entry.path === picked?.path}
159
+ onPick={() => setReading({ row: entry, file: null })}
160
+ />
161
+ ))}
162
+ </Fragment>
140
163
  ))
141
164
  )}
142
165
 
@@ -170,6 +193,33 @@ export function ArtifactSetting() {
170
193
  );
171
194
  }
172
195
 
196
+ /**
197
+ * Rows under the bot that made them, in the order the rows came: newest first,
198
+ * so the bot that handed something over last is on top. Loose rows are one group.
199
+ */
200
+ function groupByBot(
201
+ entries: Artifact[],
202
+ ): { bot: string | null; rows: Artifact[] }[] {
203
+ const groups = new Map<string | null, Artifact[]>();
204
+ for (const entry of entries) {
205
+ const rows = groups.get(entry.bot) ?? [];
206
+ rows.push(entry);
207
+ groups.set(entry.bot, rows);
208
+ }
209
+ return [...groups].map(([bot, rows]) => ({ bot, rows }));
210
+ }
211
+
212
+ /** Icon from the bot list; the row only carries the name. A bot that is gone draws its seed alone. */
213
+ function markOf(name: string, bots?: Bot[]) {
214
+ const icon = bots?.find((bot) => bot.name === name)?.icon;
215
+ return {
216
+ color: icon?.color,
217
+ shape: icon?.shape,
218
+ outline: icon?.outline,
219
+ paint: icon?.paint,
220
+ };
221
+ }
222
+
173
223
  /** `4 artifacts · 34 files`, and what is not on screen. Counts rows, so it is free. */
174
224
  function countLine(shown: Artifact[], total: number, files: number): string {
175
225
  if (total === 0) return "empty";
@@ -247,7 +297,9 @@ function Reader({
247
297
  const confirmRemove = async (path: string) => {
248
298
  const confirmed = await notify.confirm({
249
299
  title: `Delete ${path.split("/").pop()}?`,
250
- description: "It is deleted from disk for good.",
300
+ description: open
301
+ ? "It is deleted from disk for good."
302
+ : "The folder and everything in it are deleted from disk for good.",
251
303
  okText: "Delete",
252
304
  destructive: true,
253
305
  });
@@ -295,25 +347,23 @@ function Reader({
295
347
  >
296
348
  <FolderOpen />
297
349
  </Button>
298
- {open && (
299
- <Button
300
- size="icon-sm"
301
- variant="ghost"
302
- aria-label="Delete"
303
- loading={removing}
304
- className="text-muted-foreground"
305
- onClick={() => confirmRemove(open.path)}
306
- >
307
- <Trash2 />
308
- </Button>
309
- )}
350
+ <Button
351
+ size="icon-sm"
352
+ variant="ghost"
353
+ aria-label="Delete"
354
+ loading={removing}
355
+ className="text-muted-foreground"
356
+ onClick={() => confirmRemove(open?.path ?? row.path)}
357
+ >
358
+ <Trash2 />
359
+ </Button>
310
360
  </div>
311
361
 
312
362
  <div className="min-h-0 flex-1 overflow-auto">
313
363
  {open ? (
314
364
  <FilePreview path={open.path} bytes={open.bytes} />
315
365
  ) : (
316
- <SetSheet name={row.name} onOpen={onOpen} />
366
+ <SetSheet path={row.path} onOpen={onOpen} />
317
367
  )}
318
368
  </div>
319
369
  </>
@@ -325,14 +375,14 @@ function Reader({
325
375
  * a set nobody opens costs one `readdir` for its count and nothing more.
326
376
  */
327
377
  function SetSheet({
328
- name,
378
+ path,
329
379
  onOpen,
330
380
  }: {
331
- name: string;
381
+ path: string;
332
382
  onOpen: (file: ArtifactFile) => void;
333
383
  }) {
334
384
  const { data, isLoading, error } = useServerRoute<ArtifactSet>(
335
- queryKey.artifactSet(name, ARTIFACT_VIEW.setFiles),
385
+ queryKey.artifactSet(path, ARTIFACT_VIEW.setFiles),
336
386
  );
337
387
 
338
388
  if (isLoading) {
@@ -418,7 +468,7 @@ function Nothing({
418
468
  <p className="max-w-lg text-sm leading-relaxed text-muted-foreground">
419
469
  {empty
420
470
  ? "Nothing finished yet. When a bot ends a job with something to hand over — a page, a report, a set of pictures — it lands here."
421
- : "Pick something on the left. A folder a bot filled is one row, and opens as a sheet."}
471
+ : "Pick something on the left. Each bot's work is under its face; a folder it filled is one row, and opens as a sheet."}
422
472
  </p>
423
473
  <Button variant="outline" onClick={onReveal}>
424
474
  <FolderOpen />
@@ -7,20 +7,20 @@ import { publicError } from "@/lib/public-error";
7
7
  import {
8
8
  createBot,
9
9
  deleteBot,
10
- findBot,
10
+ findJobBot,
11
11
  updateBot,
12
12
  writeBotMemoryOn,
13
13
  } from "./bot.query";
14
14
  import {
15
- answerTask,
16
- cancelTask,
17
- removeFinishedTasks,
18
- removeTask,
19
- startTask,
15
+ answerThread,
16
+ cancelThread,
17
+ removeFinishedThreads,
18
+ removeThread,
19
+ startThread,
20
20
  } from "./bot.runner";
21
21
  import { BotFormSchema, botIconSchema } from "./bot.schema";
22
- import { findBotSeed, rollSeedColors } from "./bot.seed";
23
- import { markSeen, resolveTask } from "./task.query";
22
+ import { findBotSeed, rollSeedIcons } from "./bot.seed";
23
+ import { markSeen, resolveThread } from "./thread.query";
24
24
 
25
25
  export const createBotAction = serverAction(async (input: unknown) => {
26
26
  const form = BotFormSchema.parse(input);
@@ -41,8 +41,8 @@ const SeedPickSchema = z.object({
41
41
  name: z.string().trim().min(1).max(80),
42
42
  provider: textModelProviderSchema.nullish(),
43
43
  model: z.string().trim().min(1).max(80).nullish(),
44
- /** The colour the intro already showed for this bot. Rolled here when the caller had no screen. */
45
- color: botIconSchema.shape.color,
44
+ /** The face the intro already showed for this bot. Rolled here when the caller had no screen. */
45
+ icon: botIconSchema.optional(),
46
46
  });
47
47
 
48
48
  /**
@@ -53,9 +53,9 @@ const SeedPickSchema = z.object({
53
53
  export const createSeedBotsAction = serverAction(async (picks: unknown) => {
54
54
  const wanted = SeedPickSchema.array().max(20).parse(picks);
55
55
 
56
- // Seeds carry no colour of their own (bot.seed); one roll covers the whole
57
- // batch so bots made together never come out the same colour
58
- const rolled = rollSeedColors();
56
+ // Seeds carry no face of their own (bot.seed); one roll covers the whole batch
57
+ // so bots made together never come out looking alike
58
+ const rolled = rollSeedIcons();
59
59
 
60
60
  const created: string[] = [];
61
61
  for (const [at, pick] of wanted.entries()) {
@@ -65,7 +65,7 @@ export const createSeedBotsAction = serverAction(async (picks: unknown) => {
65
65
  name: seed.name,
66
66
  description: seed.description,
67
67
  systemPrompt: seed.systemPrompt,
68
- icon: { ...seed.icon, color: pick.color ?? rolled[at % rolled.length] },
68
+ icon: pick.icon ?? rolled[at % rolled.length],
69
69
  provider: pick.provider,
70
70
  model: pick.model,
71
71
  toolIds: [],
@@ -84,9 +84,9 @@ export const setBotMemoryOnAction = serverAction(async (on: unknown) => {
84
84
  await writeBotMemoryOn(on === true);
85
85
  });
86
86
 
87
- // Tasks are opened by the `delegate` tool during a call, or here when the user
87
+ // Threads are opened by the `delegate` tool during a call, or here when the user
88
88
  // hands one over from the screen. Each returns at once, the run itself continues
89
- // in bot.runner behind `after()`.
89
+ // as promises held by bot.runner.
90
90
 
91
91
  /** Words a label keeps; the rest of the message is the request, which the bot reads in full. */
92
92
  const LABEL_WORDS = 4;
@@ -103,14 +103,16 @@ function labelFor(request: string): string {
103
103
  * is the whole request — there is no conversation to draw the rest from, which is
104
104
  * why the box asks for a sentence rather than a word.
105
105
  */
106
- export const startTaskAction = serverAction(
106
+ export const startThreadAction = serverAction(
107
107
  async (bot: string, request: string) => {
108
108
  const said = request.trim();
109
109
  if (!said) publicError("Nothing to hand over.");
110
- const worker = await findBot(bot);
111
- if (!worker) publicError(`No bot called "${bot}".`);
110
+ // Resolved as a delegated job is, so an install with no bots still has its worker
111
+ const worker = await findJobBot(bot);
112
+ if (!worker || worker.disabled)
113
+ publicError(`No enabled bot called "${bot}".`);
112
114
  const label = labelFor(said);
113
- const id = await startTask({
115
+ const id = await startThread({
114
116
  bot: worker.name,
115
117
  request: said,
116
118
  label,
@@ -120,33 +122,38 @@ export const startTaskAction = serverAction(
120
122
  },
121
123
  );
122
124
 
123
- export const answerTaskAction = serverAction(
124
- async (ref: string, answer: string) => {
125
- const task = await resolveTask(ref);
126
- if (!task) publicError(`No job called "${ref}".`);
125
+ export const answerThreadAction = serverAction(
126
+ async (ref: string, answer: string, recipient?: string, replyTo?: string) => {
127
+ const thread = await resolveThread(ref);
128
+ if (!thread) publicError(`No job called "${ref}".`);
127
129
  if (!answer.trim()) publicError("Nothing to tell it.");
128
- await answerTask(task.id, answer.trim());
129
- return { id: task.id, label: task.label, status: "running" as const };
130
+ await answerThread(thread.id, answer.trim(), "user", recipient, replyTo);
131
+ return { id: thread.id, label: thread.label, status: "running" as const };
130
132
  },
131
133
  );
132
134
 
133
- export const cancelTaskAction = serverAction(async (ref: string) => {
134
- const task = await resolveTask(ref);
135
- if (!task) publicError(`No job called "${ref}".`);
136
- await cancelTask(task.id);
137
- return { id: task.id, label: task.label, status: "cancelled" as const };
135
+ export const cancelThreadAction = serverAction(async (ref: string) => {
136
+ const thread = await resolveThread(ref);
137
+ if (!thread) publicError(`No job called "${ref}".`);
138
+ await cancelThread(thread.id);
139
+ return { id: thread.id, label: thread.label, status: "cancelled" as const };
138
140
  });
139
141
 
140
- /** Marks endings as had by the user: relayed on a call, or on a task list they opened. Batched, since both reach many at once. */
142
+ /** Marks threads as read by the user: opened on screen. Their relays are settled with them (thread.query markSeen). */
141
143
  export const markSeenAction = serverAction(async (ids: string[]) => {
142
144
  await markSeen(ids.filter((id) => typeof id === "string" && id));
143
145
  });
144
146
 
145
- export const deleteTaskAction = serverAction(async (id: string) => {
146
- if (!(await removeTask(id))) publicError("Task not found");
147
+ export const deleteThreadAction = serverAction(async (id: string) => {
148
+ if (!(await removeThread(id))) publicError("Thread not found");
147
149
  });
148
150
 
149
151
  /** Empties the log of what is over. Running and waiting jobs are not touched. */
150
- export const clearFinishedTasksAction = serverAction(async () => {
151
- return { removed: await removeFinishedTasks() };
152
+ export const clearFinishedThreadsAction = serverAction(async () => {
153
+ return { removed: await removeFinishedThreads() };
154
+ });
155
+
156
+ export const acceptThreadRelaysAction = serverAction(async (ids: unknown) => {
157
+ const { acceptRoomRelays } = await import("./room.query");
158
+ await acceptRoomRelays(z.number().int().positive().array().parse(ids));
152
159
  });
@@ -1,6 +1,15 @@
1
- import { open, readdir, stat } from "node:fs/promises";
1
+ import type { Stats } from "node:fs";
2
+ import {
3
+ open,
4
+ readdir,
5
+ readFile,
6
+ rm,
7
+ stat,
8
+ utimes,
9
+ writeFile,
10
+ } from "node:fs/promises";
2
11
  import { join } from "node:path";
3
- import { BOT_MEMORY_LISTED } from "@/config";
12
+ import { BOT_MEMORY_LIMITS } from "@/config";
4
13
  import { botFolder, WORKSPACE } from "@/features/workspace/workspace";
5
14
  import type { BotMemory, BotMemoryFile } from "./bot.schema";
6
15
 
@@ -19,42 +28,150 @@ const HEAD_BYTES = 1024;
19
28
 
20
29
  /**
21
30
  * Newest first. `limit` is how many are read for their first line: the prompt lists
22
- * BOT_MEMORY_LISTED, the bot's page (Settings > Bots) as many as a Workspace folder shows.
31
+ * BOT_MEMORY_LIMITS.files, the bot's page (Settings > Bots) as many as a Workspace folder shows.
23
32
  */
24
33
  export async function listBotMemory(
25
34
  bot: string,
26
- limit = BOT_MEMORY_LISTED,
35
+ limit = BOT_MEMORY_LIMITS.files,
27
36
  ): Promise<BotMemory> {
28
37
  const folder = botMemoryFolder(bot);
29
38
  const dir = join(WORKSPACE, folder);
30
- const names = await readdir(dir).catch(() => []);
31
- const found = await Promise.all(
32
- names
33
- .filter((name) => !name.startsWith("."))
34
- .map(async (name) => {
35
- const info = await stat(join(dir, name)).catch(() => null);
36
- return info?.isFile()
37
- ? { name, changed: info.mtimeMs, bytes: info.size }
38
- : null;
39
- }),
39
+ const files = (await readMemoryFolder(dir)).sort(
40
+ (a, b) => b.info.mtimeMs - a.info.mtimeMs,
40
41
  );
41
- const files = found
42
- .filter((file) => file !== null)
43
- .sort((a, b) => b.changed - a.changed);
44
42
  const entries = await Promise.all(
45
43
  files.slice(0, limit).map(
46
- async ({ name, changed, bytes }): Promise<BotMemoryFile> => ({
44
+ async ({ name, info }): Promise<BotMemoryFile> => ({
47
45
  file: name,
48
46
  path: `${folder}/${name}`,
49
47
  line: await firstLine(join(dir, name)),
50
- at: new Date(changed),
51
- bytes,
48
+ at: new Date(info.mtimeMs),
49
+ bytes: info.size,
52
50
  }),
53
51
  ),
54
52
  );
55
53
  return { folder, entries, total: files.length };
56
54
  }
57
55
 
56
+ /** What counts as a memory file, for the listing and the limits alike: a plain file, not hidden. */
57
+ async function readMemoryFolder(
58
+ dir: string,
59
+ ): Promise<{ name: string; info: Stats }[]> {
60
+ const names = await readdir(dir).catch(() => []);
61
+ const found = await Promise.all(
62
+ names
63
+ .filter((name) => !name.startsWith("."))
64
+ .map(async (name) => {
65
+ const info = await stat(join(dir, name)).catch(() => null);
66
+ return info?.isFile() ? { name, info } : null;
67
+ }),
68
+ );
69
+ return found.filter((file) => file !== null);
70
+ }
71
+
72
+ /**
73
+ * A bot's memory as it stood before a command, so what the command takes past
74
+ * BOT_MEMORY_LIMITS can be put back. A file already past the limit is held without its
75
+ * text: there is nothing within the limit to put back.
76
+ */
77
+ export type HeldBotMemory = Map<
78
+ string,
79
+ {
80
+ text: string | null;
81
+ size: number;
82
+ mtimeMs: number;
83
+ atime: Date;
84
+ mtime: Date;
85
+ }
86
+ >;
87
+
88
+ export async function holdBotMemory(bot: string): Promise<HeldBotMemory> {
89
+ const dir = join(WORKSPACE, botMemoryFolder(bot));
90
+ const held: HeldBotMemory = new Map();
91
+ await Promise.all(
92
+ (await readMemoryFolder(dir)).map(async ({ name, info }) => {
93
+ // More than four bytes a character is past the limit without reading it
94
+ const text =
95
+ info.size > BOT_MEMORY_LIMITS.chars * 4
96
+ ? null
97
+ : await readFile(join(dir, name), "utf8").catch(() => null);
98
+ held.set(name, {
99
+ text:
100
+ text !== null && charCount(text) <= BOT_MEMORY_LIMITS.chars
101
+ ? text
102
+ : null,
103
+ size: info.size,
104
+ mtimeMs: info.mtimeMs,
105
+ atime: info.atime,
106
+ mtime: info.mtime,
107
+ });
108
+ }),
109
+ );
110
+ return held;
111
+ }
112
+
113
+ /**
114
+ * Puts back what was done to a bot's memory past BOT_MEMORY_LIMITS since `held`, and says
115
+ * so in lines the bot can act on; null when nothing went past. A file written past `chars`
116
+ * goes back to what it was, or is removed when it is new; new files that take the folder
117
+ * past `files` are removed. A file that was already past the limit stays and is named.
118
+ */
119
+ export async function keepBotMemory(
120
+ bot: string,
121
+ held: HeldBotMemory,
122
+ ): Promise<string | null> {
123
+ const folder = botMemoryFolder(bot);
124
+ const dir = join(WORKSPACE, folder);
125
+ const { files: most, chars } = BOT_MEMORY_LIMITS;
126
+ const lines: string[] = [];
127
+ const fresh: string[] = [];
128
+ let count = 0;
129
+
130
+ for (const { name, info } of await readMemoryFolder(dir)) {
131
+ count += 1;
132
+ const was = held.get(name);
133
+ if (was && was.size === info.size && was.mtimeMs === info.mtimeMs) {
134
+ continue;
135
+ }
136
+ const path = join(dir, name);
137
+ const length = charCount(await readFile(path, "utf8").catch(() => ""));
138
+ if (length <= chars) {
139
+ if (!was) fresh.push(name);
140
+ continue;
141
+ }
142
+ const size = `${length.toLocaleString("en-US")} characters, past the ${chars.toLocaleString("en-US")} a memory file holds`;
143
+ if (!was) {
144
+ await rm(path, { force: true });
145
+ count -= 1;
146
+ lines.push(
147
+ `Not kept: \`${folder}/${name}\` came to ${size}, so it was removed. Write it again shorter.`,
148
+ );
149
+ } else if (was.text !== null) {
150
+ await writeFile(path, was.text);
151
+ await utimes(path, was.atime, was.mtime);
152
+ lines.push(
153
+ `Not kept: \`${folder}/${name}\` came to ${size}, so it is back as it was. Write it again shorter.`,
154
+ );
155
+ } else {
156
+ lines.push(`\`${folder}/${name}\` is ${size}. Shorten it.`);
157
+ }
158
+ }
159
+
160
+ if (count > most && fresh.length) {
161
+ await Promise.all(
162
+ fresh.map((name) => rm(join(dir, name), { force: true })),
163
+ );
164
+ const named = fresh.map((name) => `\`${folder}/${name}\``).join(", ");
165
+ lines.push(
166
+ `Not kept: your memory holds ${most} files at most and this made ${count}, so ${named} ${fresh.length === 1 ? "was" : "were"} removed. Delete or merge files no longer worth keeping, then write it again.`,
167
+ );
168
+ }
169
+ return lines.length ? lines.join("\n") : null;
170
+ }
171
+
172
+ /** A file's length as BOT_MEMORY_LIMITS counts it. */
173
+ const charCount = (text: string): number => [...text.trim()].length;
174
+
58
175
  /**
59
176
  * The line a file is listed by: its first, without a heading's `#`. A file that opens with
60
177
  * frontmatter anyway — a shape models are trained on — is listed by its `description`, or by
@@ -4,10 +4,11 @@ import {
4
4
  botMcpToolTable,
5
5
  botTable,
6
6
  mcpToolTable,
7
- taskTable,
7
+ threadTable,
8
8
  } from "@/database/tables";
9
9
  import type { TextModelProviderId } from "@/features/ai/model.schema";
10
10
  import { readConfig, writeConfig } from "@/features/config/config.query";
11
+ import { botFolderName } from "@/features/workspace/workspace";
11
12
  import {
12
13
  BOT_MEMORY_KEY,
13
14
  type BotForm,
@@ -98,17 +99,17 @@ export async function findAllBots() {
98
99
  })
99
100
  .from(botMcpToolTable)
100
101
  .innerJoin(mcpToolTable, eq(botMcpToolTable.toolId, mcpToolTable.id)),
101
- // Grouped by name; tasks point at bots by name (tables.ts task.bot)
102
+ // Grouped by name; threads point at bots by name (tables.ts thread.bot)
102
103
  database
103
104
  .select({
104
- bot: taskTable.bot,
105
- input: sql<number>`coalesce(sum(${taskTable.inputTokens}), 0)`,
106
- output: sql<number>`coalesce(sum(${taskTable.outputTokens}), 0)`,
105
+ bot: threadTable.bot,
106
+ input: sql<number>`coalesce(sum(${threadTable.inputTokens}), 0)`,
107
+ output: sql<number>`coalesce(sum(${threadTable.outputTokens}), 0)`,
107
108
  // Raw max over a timestamp column arrives as integer seconds
108
- lastJobAt: sql<number | null>`max(${taskTable.updatedAt})`,
109
+ lastJobAt: sql<number | null>`max(${threadTable.updatedAt})`,
109
110
  })
110
- .from(taskTable)
111
- .groupBy(taskTable.bot),
111
+ .from(threadTable)
112
+ .groupBy(threadTable.bot),
112
113
  ]);
113
114
 
114
115
  const byBot = new Map<string, PinnedTool[]>();
@@ -155,9 +156,25 @@ export async function findBot(name: string) {
155
156
  return bot ?? null;
156
157
  }
157
158
 
158
- /** Returns null when the name is taken: two bots with one name would be a coin toss at delegate time. */
159
+ /**
160
+ * Every name that has folders in the workspace: the rows, switched off or not,
161
+ * and DEFAULT_BOT, which works without one.
162
+ */
163
+ export async function listBotNames(): Promise<string[]> {
164
+ const rows = await database.select({ name: botTable.name }).from(botTable);
165
+ return [...new Set([...rows.map((row) => row.name), DEFAULT_BOT.name])];
166
+ }
167
+
168
+ /**
169
+ * Returns null when the name is taken: two bots with one name would be a coin
170
+ * toss at delegate time, and two whose names give one folder would share their
171
+ * memory and artifacts (workspace.ts botFolderName).
172
+ */
159
173
  export async function createBot(form: BotForm) {
160
- if (await findBot(form.name)) return null;
174
+ const folder = botFolderName(form.name).toLowerCase();
175
+ const rows = await database.select({ name: botTable.name }).from(botTable);
176
+ if (rows.some((row) => botFolderName(row.name).toLowerCase() === folder))
177
+ return null;
161
178
 
162
179
  const { toolIds, ...values } = pickedModel(form);
163
180
  const [bot] = await database.insert(botTable).values(values).returning();
@@ -170,7 +187,7 @@ export async function updateBot(name: string, patch: Partial<BotForm>) {
170
187
  // (pickedModel reads a missing field as null and would clear the other)
171
188
  const { toolIds, ...values } =
172
189
  "provider" in patch || "model" in patch ? pickedModel(patch) : patch;
173
- // Renaming would orphan pinned tools and every task sent to the old name, so name is never patched
190
+ // Renaming would orphan pinned tools and every thread sent to the old name, so name is never patched
174
191
  delete (values as { name?: string }).name;
175
192
 
176
193
  const [bot] = Object.keys(values).length