thursday-agent 0.5.0 → 0.7.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 (667) 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 +5 -4
  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 +4 -4
  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 +15 -15
  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 +9 -10
  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 -5
  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 +11 -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]__0-06t3f._.js +8 -0
  92. package/.next/server/chunks/[root-of-the-server]__02846fb._.js +8 -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]__06l05n_._.js +3 -0
  96. package/.next/server/chunks/[root-of-the-server]__07bnah_._.js +3 -0
  97. package/.next/server/chunks/[root-of-the-server]__08eae20._.js +8 -0
  98. package/.next/server/chunks/[root-of-the-server]__0_ue8oe._.js +3 -0
  99. package/.next/server/chunks/[root-of-the-server]__0btqrct._.js +3 -0
  100. package/.next/server/chunks/[root-of-the-server]__0c9fgca._.js +5 -0
  101. package/.next/server/chunks/[root-of-the-server]__0h_x6q6._.js +5 -0
  102. package/.next/server/chunks/{[root-of-the-server]__0pa2n68._.js → [root-of-the-server]__0kxrvxf._.js} +2 -2
  103. package/.next/server/chunks/{[root-of-the-server]__0q0vvt2._.js → [root-of-the-server]__0ov3iir._.js} +2 -2
  104. package/.next/server/chunks/[root-of-the-server]__0qwtlmx._.js +8 -0
  105. package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.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/_1gnjfli._.js +3 -0
  150. package/.next/server/chunks/_1kg70wc._.js +3 -3
  151. package/.next/server/chunks/_1klbcft._.js +5 -0
  152. package/.next/server/chunks/_1krd9rf._.js +4 -1
  153. package/.next/server/chunks/_1kwmzab._.js +3 -0
  154. package/.next/server/chunks/{_1pf4qe-._.js → _1oxj9fa._.js} +1 -1
  155. package/.next/server/chunks/{_1f46eie._.js → _1pcmdbb._.js} +1 -1
  156. package/.next/server/chunks/_1qgix-j._.js +3 -0
  157. package/.next/server/chunks/{lib_logger_ts_1exwjut._.js → _1rpchta._.js} +5 -5
  158. package/.next/server/chunks/_1vsej-s._.js +5 -0
  159. package/.next/server/chunks/_1yx0p_s._.js +5 -0
  160. package/.next/server/chunks/{_0rnf-6n._.js → _20fsr_z._.js} +6 -6
  161. package/.next/server/chunks/_2128hkj._.js +5 -0
  162. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_[id]_route_actions_1fstjn2.js +3 -0
  163. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_route_actions_003ccso.js +3 -0
  164. package/.next/server/chunks/_next-internal_server_app_api_workspace_missing_route_actions_1fidi6p.js +3 -0
  165. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  166. package/.next/server/chunks/features_0-cnt0l._.js +4 -0
  167. package/.next/server/chunks/features_0hdaci0._.js +4 -0
  168. package/.next/server/chunks/features_1e39j7-._.js +8 -0
  169. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
  170. package/.next/server/chunks/features_memory_1uqvksn._.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_0a7-pbw._.js} +1 -1
  172. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_17k8irj._.js → node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js} +1 -1
  173. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js → node_modules_consola_dist_chunks_prompt_mjs_107pxfn._.js} +1 -1
  174. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js → node_modules_consola_dist_chunks_prompt_mjs_15hbel8._.js} +1 -1
  175. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_18i-23e._.js +3 -0
  176. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1bewgf3._.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]__0-e011f._.js +3 -0
  185. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  186. package/.next/server/chunks/ssr/[root-of-the-server]__0lyi8i2._.js +1 -1
  187. package/.next/server/chunks/ssr/[root-of-the-server]__0pd8yr7._.js +3 -0
  188. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  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]__1mzi-ju._.js +1 -1
  192. package/.next/server/chunks/ssr/[root-of-the-server]__1nygfik._.js +5 -0
  193. package/.next/server/chunks/ssr/[root-of-the-server]__1sdphb0._.js +8 -0
  194. package/.next/server/chunks/ssr/[root-of-the-server]__1vdmfbe._.js +3 -0
  195. package/.next/server/chunks/ssr/[root-of-the-server]__1waa3rc._.js +85 -0
  196. package/.next/server/chunks/ssr/_0-2qsxo._.js +3 -0
  197. package/.next/server/chunks/ssr/_00rehl_._.js +3 -0
  198. package/.next/server/chunks/ssr/{_1lz_cq2._.js → _02oc_h5._.js} +76 -97
  199. package/.next/server/chunks/ssr/_05yghx6._.js +3 -0
  200. package/.next/server/chunks/ssr/_07nbwap._.js +3 -0
  201. package/.next/server/chunks/ssr/_08c4z-9._.js +3 -0
  202. package/.next/server/chunks/ssr/_0_qfdlw._.js +4 -0
  203. package/.next/server/chunks/ssr/{_0m2lsd1._.js → _0b6_jv-._.js} +2 -2
  204. package/.next/server/chunks/ssr/_0evkpto._.js +3 -0
  205. package/.next/server/chunks/ssr/_0geg212._.js +3 -0
  206. package/.next/server/chunks/ssr/{_1jdgjv9._.js → _0hxt2ul._.js} +2 -2
  207. package/.next/server/chunks/ssr/_0i_6q1w._.js +2 -2
  208. package/.next/server/chunks/ssr/_0lu1n_x._.js +1 -1
  209. package/.next/server/chunks/ssr/_0no7i1o._.js +3 -0
  210. package/.next/server/chunks/ssr/_0tzg--b._.js +3 -0
  211. package/.next/server/chunks/ssr/{_15j2_8f._.js → _0wzaht-._.js} +2 -2
  212. package/.next/server/chunks/ssr/_0z-g0uy._.js +3 -0
  213. package/.next/server/chunks/ssr/_114ylv7._.js +7 -0
  214. package/.next/server/chunks/ssr/_123y-ah._.js +3 -0
  215. package/.next/server/chunks/ssr/_12c-iwh._.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/_167hchk._.js +3 -0
  219. package/.next/server/chunks/ssr/{_0ap2fzn._.js → _16c6_xm._.js} +2 -2
  220. package/.next/server/chunks/ssr/_18opah7._.js +3 -0
  221. package/.next/server/chunks/ssr/_1_krfph._.js +3 -0
  222. package/.next/server/chunks/ssr/{_0rzucul._.js → _1_x5spz._.js} +3 -3
  223. package/.next/server/chunks/ssr/_1a61fc9._.js +3 -0
  224. package/.next/server/chunks/ssr/_1ey7qn-._.js +70 -0
  225. package/.next/server/chunks/ssr/_1g9vs7q._.js +3 -0
  226. package/.next/server/chunks/ssr/_1jmz33w._.js +3 -0
  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/_1w_t7h7._.js +101 -0
  230. package/.next/server/chunks/ssr/{_0s99bgb._.js → _1wyfaq_._.js} +9 -3
  231. package/.next/server/chunks/ssr/_200gt-m._.js +102 -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/features_workspace_00jz2hu._.js +8 -0
  237. package/.next/server/chunks/ssr/{_1-teee5._.js → lib_logger_ts_0-olsze._.js} +2 -7
  238. package/.next/server/chunks/ssr/{node_modules_05-n6dz._.js → node_modules_02ai7br._.js} +1 -1
  239. package/.next/server/chunks/ssr/{node_modules_1chvq5f._.js → node_modules_02deexj._.js} +1 -1
  240. package/.next/server/chunks/ssr/{node_modules_0m383r2._.js → node_modules_07za262._.js} +1 -1
  241. package/.next/server/chunks/ssr/{node_modules_07dsgkx._.js → node_modules_0_s9get._.js} +1 -1
  242. package/.next/server/chunks/ssr/{node_modules_1a0kmjl._.js → node_modules_0n3c7h0._.js} +1 -1
  243. package/.next/server/chunks/ssr/{node_modules_0zeg3x_._.js → node_modules_0od6jwr._.js} +1 -1
  244. package/.next/server/chunks/ssr/{node_modules_1y79i83._.js → node_modules_0rdt7pk._.js} +1 -1
  245. package/.next/server/chunks/ssr/{node_modules_17bwo43._.js → node_modules_0tusx4d._.js} +3 -3
  246. package/.next/server/chunks/ssr/{node_modules_04sksn9._.js → node_modules_0w1z7kz._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_1uyk91w._.js → node_modules_0wdupfz._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_0ifp389._.js → node_modules_1720w0a._.js} +1 -1
  249. package/.next/server/chunks/ssr/{node_modules_0u9da1h._.js → node_modules_18lsg7d._.js} +1 -1
  250. package/.next/server/chunks/ssr/{node_modules_1k6n600._.js → node_modules_1b94fxf._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_20c28js._.js → node_modules_1ecdo1s._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_0fkeku3._.js → node_modules_1fa9ag7._.js} +1 -1
  253. package/.next/server/chunks/ssr/{node_modules_1j8j4pt._.js → node_modules_1fv-_si._.js} +1 -1
  254. package/.next/server/chunks/ssr/{node_modules_0-dr_o7._.js → node_modules_1hf461g._.js} +1 -1
  255. package/.next/server/chunks/ssr/{node_modules_1lz0oxc._.js → node_modules_1m71ta-._.js} +1 -1
  256. package/.next/server/chunks/ssr/{node_modules_1t77e4n._.js → node_modules_1n93n-g._.js} +1 -1
  257. package/.next/server/chunks/ssr/{node_modules_16mkxuo._.js → node_modules_1n9lqu9._.js} +1 -1
  258. package/.next/server/chunks/ssr/{node_modules_1k7z2j6._.js → node_modules_1npnsvd._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_056qgf-._.js → node_modules_1rn2r0n._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_0x3-ply._.js → node_modules_1seuurl._.js} +2 -2
  261. package/.next/server/chunks/ssr/{node_modules_0bvopy2._.js → node_modules_1vq-mfk._.js} +1 -1
  262. package/.next/server/chunks/ssr/{node_modules_0iur59s._.js → node_modules_1vzyw1t._.js} +1 -1
  263. package/.next/server/chunks/ssr/{node_modules_1k8j8n0._.js → node_modules_1w359w4._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_1x0ztf4._.js → node_modules_1yajbl6._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_1-y7nni._.js → node_modules_20eqhy8._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0bkwd0u._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_019sbis._.js} +1 -1
  267. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0p9a9su._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0s6piq3._.js} +1 -1
  268. package/.next/server/chunks/ssr/{node_modules_@vercel_oidc_dist_1o553h-._.js → node_modules_@vercel_oidc_dist_05itbb1._.js} +1 -1
  269. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_trash_mjs_0px2gzr._.js +3 -0
  270. package/.next/server/middleware-build-manifest.js +3 -3
  271. package/.next/server/pages/404.html +1 -1
  272. package/.next/server/pages/500.html +1 -1
  273. package/.next/server/server-reference-manifest.js +1 -1
  274. package/.next/server/server-reference-manifest.json +68 -46
  275. package/.next/static/chunks/07vqbk_9t4em4.js +2 -0
  276. package/.next/static/chunks/08krja1zx7nqg.js +1 -0
  277. package/.next/static/chunks/0g4b348l0pve7.js +1 -0
  278. package/.next/static/chunks/0qcuwdk132jjt.js +1 -0
  279. package/.next/static/chunks/0vlgzqo9ka90v.js +1 -0
  280. package/.next/static/chunks/{11r2yp_yh9_qn.js → 0z69gvysmave7.js} +1 -1
  281. package/.next/static/chunks/0zrupxgci5gqc.js +1 -0
  282. package/.next/static/chunks/12fvz1w5ows75.js +1 -0
  283. package/.next/static/chunks/14t03ned286iu.js +1 -0
  284. package/.next/static/chunks/156xxbkrz5lzu.js +18 -0
  285. package/.next/static/chunks/1fz14reod4lft.js +1 -0
  286. package/.next/static/chunks/1g23dbabl-vkr.js +1 -0
  287. package/.next/static/chunks/1ohslk4568tm3.js +1 -0
  288. package/.next/static/chunks/1qy_rc3oxfxok.js +1 -0
  289. package/.next/static/chunks/1sbmwswc9k2-1.js +1 -0
  290. package/.next/static/chunks/1vqezbhjm3goq.js +1 -0
  291. package/.next/static/chunks/1zea7qdl-7365.js +1 -0
  292. package/.next/static/chunks/1zvqumkg7kmo0.css +1 -0
  293. package/.next/static/chunks/26hpqt3y6bogl.js +12 -0
  294. package/.next/static/chunks/2_j5mqm6d-z18.js +99 -0
  295. package/.next/static/chunks/2dt6tu7a22svs.js +1 -0
  296. package/.next/static/chunks/2h5ls3d86kya6.js +1 -0
  297. package/.next/static/chunks/2wc6y1ht6dfuy.js +1 -0
  298. package/.next/static/chunks/{435atsnhs7ksu.js → 2xr0zpll7thyi.js} +2 -2
  299. package/.next/static/chunks/31jztc-yq30m7.js +1 -0
  300. package/.next/static/chunks/391af0i8eljzk.js +1 -0
  301. package/.next/static/chunks/3bfwpww3m3x4u.js +1 -0
  302. package/.next/static/chunks/{38gweqdo4jpfj.js → 3izg0a3k87q1-.js} +5 -5
  303. package/.next/static/chunks/3p2s2cjokx1aa.js +5 -0
  304. package/.next/static/chunks/{408ueu4hfvcg7.js → 41s3fml5oivsa.js} +1 -1
  305. package/README.md +45 -193
  306. package/app/api/events/app-event.ts +6 -4
  307. package/app/api/query-key.ts +25 -16
  308. package/bin/database.mjs +37 -0
  309. package/bin/thursday.mjs +44 -28
  310. package/components/ui/custom-icon.tsx +0 -60
  311. package/components/ui/radio-group.tsx +37 -0
  312. package/components/ui/shiny-text.tsx +33 -6
  313. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/migration.sql +80 -24
  314. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/snapshot.json +689 -110
  315. package/database/migrations/20260916160713_thread_cancelled/migration.sql +2 -0
  316. package/database/migrations/{20260911030320_opposite_jack_power → 20260916160713_thread_cancelled}/snapshot.json +706 -84
  317. package/docs/how-it-works.md +40 -35
  318. package/docs/images/keeps-going.png +0 -0
  319. package/docs/images/two-minds.png +0 -0
  320. package/docs/live-calls.md +236 -0
  321. package/docs/thread-rooms.md +71 -0
  322. package/features/ai/chatgpt.ts +1 -2
  323. package/features/ai/live.schema.ts +128 -0
  324. package/features/ai/load-tools.ts +152 -79
  325. package/features/ai/model.schema.ts +2 -120
  326. package/features/ai/model.ts +52 -88
  327. package/features/ai/prompts/bot.prompt.ts +91 -214
  328. package/features/ai/prompts/live.prompt.ts +169 -0
  329. package/features/ai/prompts/prompt-helper.ts +92 -32
  330. package/features/ai/prompts/thursday.prompt.ts +164 -190
  331. package/features/ai/tools/bot.tool.ts +38 -145
  332. package/features/ai/tools/call.tool.ts +33 -5
  333. package/features/ai/tools/connected.ts +5 -3
  334. package/features/ai/tools/mcp.tool.ts +7 -4
  335. package/features/ai/tools/memory.tool.ts +35 -31
  336. package/features/ai/tools/skills.tool.ts +11 -6
  337. package/features/ai/tools/studio.tool.ts +26 -21
  338. package/features/ai/tools/tool-name.ts +3 -5
  339. package/features/ai/tools/workspace.tool.ts +33 -10
  340. package/features/artifact/artifact.action.ts +2 -2
  341. package/features/artifact/artifact.query.ts +112 -61
  342. package/features/artifact/artifact.schema.ts +8 -6
  343. package/features/artifact/components/artifact-setting.tsx +83 -33
  344. package/features/bot/bot.action.ts +43 -36
  345. package/features/bot/bot.memory.ts +137 -20
  346. package/features/bot/bot.query.ts +28 -11
  347. package/features/bot/bot.run.ts +296 -744
  348. package/features/bot/bot.runner.ts +463 -864
  349. package/features/bot/bot.schema.ts +93 -82
  350. package/features/bot/bot.seed.ts +141 -64
  351. package/features/bot/components/bot-mark.tsx +324 -232
  352. package/features/bot/components/bot-room.tsx +1613 -697
  353. package/features/bot/components/bot-roster.tsx +8 -13
  354. package/features/bot/components/bot-setting.tsx +58 -42
  355. package/features/bot/components/bot-tool.tsx +55 -87
  356. package/features/bot/components/mark-palette.tsx +35 -32
  357. package/features/bot/components/path-chips.tsx +33 -3
  358. package/features/bot/components/thread-badge.tsx +34 -0
  359. package/features/bot/components/thread-reply.tsx +639 -0
  360. package/features/bot/components/thread-setting.tsx +674 -0
  361. package/features/bot/mark.const.ts +79 -31
  362. package/features/bot/room.query.ts +889 -0
  363. package/features/bot/room.schema.ts +64 -0
  364. package/features/bot/seed-bots.ts +2 -1
  365. package/features/bot/thread.query.ts +971 -0
  366. package/features/bot/thread.store.ts +587 -0
  367. package/features/config/components/voice-key.tsx +113 -88
  368. package/features/config/config.const.ts +5 -9
  369. package/features/connectors/mcp.schema.ts +0 -2
  370. package/features/intro/components/intro.tsx +169 -139
  371. package/features/memory/components/memory-setting.tsx +2 -7
  372. package/features/memory/memory.schema.ts +14 -23
  373. package/features/settings/components/setting-ui.tsx +0 -44
  374. package/features/settings/components/settings.tsx +12 -12
  375. package/features/settings/settings.alert.ts +3 -3
  376. package/features/settings/settings.store.ts +1 -1
  377. package/features/skills/skills.schema.ts +0 -2
  378. package/features/thursday/ascii.const.ts +74 -0
  379. package/features/thursday/components/ascii-field.tsx +24 -44
  380. package/features/thursday/components/ascii-orb.tsx +525 -381
  381. package/features/thursday/components/call-log.tsx +46 -44
  382. package/features/thursday/components/face.tsx +40 -10
  383. package/features/thursday/components/side-captions.tsx +273 -0
  384. package/features/thursday/components/tab-state.tsx +14 -6
  385. package/features/thursday/components/thursday-mark.tsx +1 -0
  386. package/features/thursday/components/thursday-setting.tsx +633 -333
  387. package/features/thursday/components/thursday.tsx +315 -274
  388. package/features/thursday/components/voice-picker.tsx +255 -0
  389. package/features/thursday/face.store.ts +5 -0
  390. package/features/thursday/thursday.action.ts +96 -72
  391. package/features/thursday/thursday.query.ts +49 -30
  392. package/features/thursday/thursday.schema.ts +37 -35
  393. package/features/thursday/thursday.store.ts +14 -7
  394. package/features/thursday/tool-call.ts +3 -3
  395. package/features/thursday/tool-line.ts +5 -3
  396. package/features/thursday/use-thursday.ts +801 -457
  397. package/features/workspace/file-kind.ts +9 -0
  398. package/features/workspace/workspace.query.ts +17 -0
  399. package/features/workspace/workspace.ts +82 -36
  400. package/hooks/use-hotkey.ts +3 -2
  401. package/lib/live/live.schema.ts +26 -0
  402. package/lib/live/live.server.ts +153 -0
  403. package/lib/live/live.session.ts +574 -0
  404. package/lib/{realtime/realtime.tap.ts → live/live.tap.ts} +41 -12
  405. package/lib/live/live.transport.ts +152 -0
  406. package/lib/protocol/use-server-pages.ts +9 -5
  407. package/lib/utils.ts +21 -20
  408. package/package.json +2 -2
  409. package/public/voices/alloy.ogg +0 -0
  410. package/public/voices/ash.ogg +0 -0
  411. package/public/voices/ballad.ogg +0 -0
  412. package/public/voices/beacon.ogg +0 -0
  413. package/public/voices/bossa.ogg +0 -0
  414. package/public/voices/cedar.ogg +0 -0
  415. package/public/voices/cinder.ogg +0 -0
  416. package/public/voices/coral.ogg +0 -0
  417. package/public/voices/delta.ogg +0 -0
  418. package/public/voices/echo.ogg +0 -0
  419. package/public/voices/gleam.ogg +0 -0
  420. package/public/voices/marin.ogg +0 -0
  421. package/public/voices/meridian.ogg +0 -0
  422. package/public/voices/quartz.ogg +0 -0
  423. package/public/voices/ripple.ogg +0 -0
  424. package/public/voices/sage.ogg +0 -0
  425. package/public/voices/shimmer.ogg +0 -0
  426. package/public/voices/stone.ogg +0 -0
  427. package/public/voices/tempo.ogg +0 -0
  428. package/public/voices/verse.ogg +0 -0
  429. package/public/voices/vesper.ogg +0 -0
  430. package/public/voices/willow.ogg +0 -0
  431. package/scripts/artifact-paths.test.mts +38 -0
  432. package/scripts/bot-context.test.mts +1408 -0
  433. package/scripts/live-history.test.mts +115 -0
  434. package/scripts/live-session.test.mts +938 -0
  435. package/server.js +1 -1
  436. package/skills/browser/SKILL.md +11 -1
  437. package/skills/computer/SKILL.md +1 -1
  438. package/skills/find-skills/SKILL.md +3 -8
  439. package/skills/interactive-page/SKILL.md +12 -7
  440. package/skills/interactive-page/references/diagram.md +89 -0
  441. package/skills/interactive-page/scripts/archify/LICENSE +22 -0
  442. package/skills/interactive-page/scripts/archify/README.md +25 -0
  443. package/skills/interactive-page/scripts/archify/assets/JetBrainsMono-OFL.txt +93 -0
  444. package/skills/interactive-page/scripts/archify/assets/template.html +14934 -0
  445. package/skills/interactive-page/scripts/archify/bin/archify.mjs +2126 -0
  446. package/skills/interactive-page/scripts/archify/bin/open-artifact.mjs +86 -0
  447. package/skills/interactive-page/scripts/archify/bin/preview.mjs +653 -0
  448. package/skills/interactive-page/scripts/archify/bin/visual-check.mjs +829 -0
  449. package/skills/interactive-page/scripts/archify/delta/architecture-delta.mjs +1223 -0
  450. package/skills/interactive-page/scripts/archify/examples/agent-run.lifecycle.json +60 -0
  451. package/skills/interactive-page/scripts/archify/examples/agent-tool-call.workflow.json +94 -0
  452. package/skills/interactive-page/scripts/archify/examples/async-job-roundtrip.sequence.json +61 -0
  453. package/skills/interactive-page/scripts/archify/examples/cache-miss-request.sequence.json +82 -0
  454. package/skills/interactive-page/scripts/archify/examples/checkout-platform.base.architecture.json +31 -0
  455. package/skills/interactive-page/scripts/archify/examples/checkout-platform.head.architecture.json +31 -0
  456. package/skills/interactive-page/scripts/archify/examples/deployment-release.lifecycle.json +49 -0
  457. package/skills/interactive-page/scripts/archify/examples/event-stream.dataflow.json +57 -0
  458. package/skills/interactive-page/scripts/archify/examples/incident-response.workflow.json +64 -0
  459. package/skills/interactive-page/scripts/archify/examples/product-analytics.dataflow.json +76 -0
  460. package/skills/interactive-page/scripts/archify/examples/production-deployment.architecture.json +71 -0
  461. package/skills/interactive-page/scripts/archify/examples/release-delivery.workflow.json +62 -0
  462. package/skills/interactive-page/scripts/archify/examples/web-app.architecture.json +46 -0
  463. package/skills/interactive-page/scripts/archify/migrations/workflow-v2.mjs +279 -0
  464. package/skills/interactive-page/scripts/archify/recipes/scenarios.mjs +284 -0
  465. package/skills/interactive-page/scripts/archify/references/authoring-contract.md +243 -0
  466. package/skills/interactive-page/scripts/archify/references/delivery-contract.md +120 -0
  467. package/skills/interactive-page/scripts/archify/references/viewer-runtime.md +45 -0
  468. package/skills/interactive-page/scripts/archify/renderers/architecture/grid.mjs +62 -0
  469. package/skills/interactive-page/scripts/archify/renderers/architecture/render-architecture.mjs +1078 -0
  470. package/skills/interactive-page/scripts/archify/renderers/dataflow/README.md +104 -0
  471. package/skills/interactive-page/scripts/archify/renderers/dataflow/render-dataflow.mjs +483 -0
  472. package/skills/interactive-page/scripts/archify/renderers/lifecycle/README.md +115 -0
  473. package/skills/interactive-page/scripts/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
  474. package/skills/interactive-page/scripts/archify/renderers/sequence/README.md +114 -0
  475. package/skills/interactive-page/scripts/archify/renderers/sequence/render-sequence.mjs +464 -0
  476. package/skills/interactive-page/scripts/archify/renderers/shared/brand-marks.mjs +563 -0
  477. package/skills/interactive-page/scripts/archify/renderers/shared/cli.mjs +218 -0
  478. package/skills/interactive-page/scripts/archify/renderers/shared/desktop-readability.mjs +26 -0
  479. package/skills/interactive-page/scripts/archify/renderers/shared/diagnostics.mjs +127 -0
  480. package/skills/interactive-page/scripts/archify/renderers/shared/engineering-profiles.mjs +157 -0
  481. package/skills/interactive-page/scripts/archify/renderers/shared/generated-brand-marks.mjs +3 -0
  482. package/skills/interactive-page/scripts/archify/renderers/shared/generated-validators.mjs +13 -0
  483. package/skills/interactive-page/scripts/archify/renderers/shared/geometry.mjs +1423 -0
  484. package/skills/interactive-page/scripts/archify/renderers/shared/i18n.mjs +595 -0
  485. package/skills/interactive-page/scripts/archify/renderers/shared/layout-report.mjs +40 -0
  486. package/skills/interactive-page/scripts/archify/renderers/shared/legend.mjs +217 -0
  487. package/skills/interactive-page/scripts/archify/renderers/shared/output-path.mjs +340 -0
  488. package/skills/interactive-page/scripts/archify/renderers/shared/repository-evidence.mjs +238 -0
  489. package/skills/interactive-page/scripts/archify/renderers/shared/repository-location.mjs +58 -0
  490. package/skills/interactive-page/scripts/archify/renderers/shared/text-fit.mjs +49 -0
  491. package/skills/interactive-page/scripts/archify/renderers/shared/utils.mjs +232 -0
  492. package/skills/interactive-page/scripts/archify/renderers/shared/validator.mjs +86 -0
  493. package/skills/interactive-page/scripts/archify/renderers/workflow/README.md +223 -0
  494. package/skills/interactive-page/scripts/archify/renderers/workflow/render-workflow.mjs +35 -0
  495. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  496. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  497. package/skills/interactive-page/scripts/archify/schemas/README.md +211 -0
  498. package/skills/interactive-page/scripts/archify/schemas/architecture.schema.json +178 -0
  499. package/skills/interactive-page/scripts/archify/schemas/common.schema.json +115 -0
  500. package/skills/interactive-page/scripts/archify/schemas/dataflow.schema.json +243 -0
  501. package/skills/interactive-page/scripts/archify/schemas/lifecycle.schema.json +266 -0
  502. package/skills/interactive-page/scripts/archify/schemas/sequence.schema.json +223 -0
  503. package/skills/interactive-page/scripts/archify/schemas/workflow.schema.json +428 -0
  504. package/skills/interactive-page/scripts/archify/scripts/check-render-output.mjs +916 -0
  505. package/skills/interactive-page/scripts/archify/scripts/render-examples.mjs +26 -0
  506. package/skills/interactive-page/scripts/bundle-artifact.sh +9 -8
  507. package/skills/skill-creator/SKILL.md +4 -5
  508. package/.next/server/app/api/bot/task/[id]/route/app-paths-manifest.json +0 -3
  509. package/.next/server/app/api/bot/task/[id]/route.js +0 -16
  510. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +0 -1
  511. package/.next/server/app/api/bot/task/[id]/route_client-reference-manifest.js +0 -3
  512. package/.next/server/app/api/bot/task/route/app-paths-manifest.json +0 -3
  513. package/.next/server/app/api/bot/task/route.js +0 -16
  514. package/.next/server/app/api/bot/task/route.js.nft.json +0 -1
  515. package/.next/server/app/api/bot/task/route_client-reference-manifest.js +0 -3
  516. package/.next/server/chunks/[root-of-the-server]__026u77e._.js +0 -5
  517. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +0 -3
  518. package/.next/server/chunks/[root-of-the-server]__050zri4._.js +0 -3
  519. package/.next/server/chunks/[root-of-the-server]__0bg9710._.js +0 -3
  520. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +0 -3
  521. package/.next/server/chunks/[root-of-the-server]__0in-d5s._.js +0 -3
  522. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +0 -3
  523. package/.next/server/chunks/[root-of-the-server]__0pa9k-f._.js +0 -8
  524. package/.next/server/chunks/[root-of-the-server]__0qi_m0e._.js +0 -8
  525. package/.next/server/chunks/[root-of-the-server]__0tq0m_k._.js +0 -3
  526. package/.next/server/chunks/[root-of-the-server]__0xep6j_._.js +0 -3
  527. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +0 -5
  528. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +0 -5
  529. package/.next/server/chunks/[root-of-the-server]__144l7qt._.js +0 -8
  530. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +0 -5
  531. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +0 -3
  532. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +0 -3
  533. package/.next/server/chunks/[root-of-the-server]__1jg8t86._.js +0 -8
  534. package/.next/server/chunks/[root-of-the-server]__1lldzy9._.js +0 -3
  535. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +0 -3
  536. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +0 -3
  537. package/.next/server/chunks/[root-of-the-server]__1peqvsi._.js +0 -3
  538. package/.next/server/chunks/[root-of-the-server]__1w8gm5h._.js +0 -10
  539. package/.next/server/chunks/[root-of-the-server]__1xt39nn._.js +0 -8
  540. package/.next/server/chunks/[root-of-the-server]__1zb8mfo._.js +0 -8
  541. package/.next/server/chunks/_0-73of8._.js +0 -55
  542. package/.next/server/chunks/_0-fjql4._.js +0 -31
  543. package/.next/server/chunks/_00xh_q0._.js +0 -25
  544. package/.next/server/chunks/_051qh8u._.js +0 -3
  545. package/.next/server/chunks/_05sovvj._.js +0 -3
  546. package/.next/server/chunks/_091bi8d._.js +0 -3
  547. package/.next/server/chunks/_0fzqt2y._.js +0 -142
  548. package/.next/server/chunks/_0lr92vd._.js +0 -3
  549. package/.next/server/chunks/_0mecv0f._.js +0 -31
  550. package/.next/server/chunks/_0mh8j4m._.js +0 -3
  551. package/.next/server/chunks/_0sb7tlz._.js +0 -3
  552. package/.next/server/chunks/_0si7xzn._.js +0 -3
  553. package/.next/server/chunks/_0u10wmw._.js +0 -55
  554. package/.next/server/chunks/_0wp4le3._.js +0 -3
  555. package/.next/server/chunks/_0y5fg-x._.js +0 -3
  556. package/.next/server/chunks/_1230wbx._.js +0 -10
  557. package/.next/server/chunks/_12nheja._.js +0 -3
  558. package/.next/server/chunks/_13510xh._.js +0 -3
  559. package/.next/server/chunks/_15hq89o._.js +0 -3
  560. package/.next/server/chunks/_18-1wcc._.js +0 -55
  561. package/.next/server/chunks/_18d7-5p._.js +0 -3
  562. package/.next/server/chunks/_1c78vw5._.js +0 -237
  563. package/.next/server/chunks/_1h5_8sk._.js +0 -3
  564. package/.next/server/chunks/_1hdnxb7._.js +0 -3
  565. package/.next/server/chunks/_1j8k_j5._.js +0 -3
  566. package/.next/server/chunks/_1nula3v._.js +0 -3
  567. package/.next/server/chunks/_1php4eq._.js +0 -3
  568. package/.next/server/chunks/_1yuv4vp._.js +0 -3
  569. package/.next/server/chunks/_1zkfbaa._.js +0 -3
  570. package/.next/server/chunks/_next-internal_server_app_api_bot_task_[id]_route_actions_1_k_8u3.js +0 -3
  571. package/.next/server/chunks/_next-internal_server_app_api_bot_task_route_actions_0xln6ra.js +0 -3
  572. package/.next/server/chunks/features_0rpfxbk._.js +0 -3
  573. package/.next/server/chunks/features_1qf3cei._.js +0 -8
  574. package/.next/server/chunks/features_bot_0zt92oh._.js +0 -3
  575. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1jidylq._.js +0 -3
  576. package/.next/server/chunks/ssr/[externals]__0dizgek._.js +0 -3
  577. package/.next/server/chunks/ssr/[root-of-the-server]__0-nob52._.js +0 -4
  578. package/.next/server/chunks/ssr/[root-of-the-server]__092knlj._.js +0 -3
  579. package/.next/server/chunks/ssr/[root-of-the-server]__0mz33a7._.js +0 -3
  580. package/.next/server/chunks/ssr/[root-of-the-server]__0s4wb56._.js +0 -3
  581. package/.next/server/chunks/ssr/[root-of-the-server]__0s9dq5u._.js +0 -3
  582. package/.next/server/chunks/ssr/[root-of-the-server]__0sd3izg._.js +0 -3
  583. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +0 -3
  584. package/.next/server/chunks/ssr/[root-of-the-server]__1-13tcn._.js +0 -43
  585. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +0 -61
  586. package/.next/server/chunks/ssr/[root-of-the-server]__1zidpfl._.js +0 -3
  587. package/.next/server/chunks/ssr/_001_ms1._.js +0 -33
  588. package/.next/server/chunks/ssr/_01n3o0m._.js +0 -3
  589. package/.next/server/chunks/ssr/_04z2c7b._.js +0 -3
  590. package/.next/server/chunks/ssr/_06tssji._.js +0 -3
  591. package/.next/server/chunks/ssr/_0fk4c7d._.js +0 -3
  592. package/.next/server/chunks/ssr/_0h42fze._.js +0 -3
  593. package/.next/server/chunks/ssr/_0h7zdni._.js +0 -3
  594. package/.next/server/chunks/ssr/_0mggveb._.js +0 -3
  595. package/.next/server/chunks/ssr/_0nbpc_8._.js +0 -3
  596. package/.next/server/chunks/ssr/_0q0zan6._.js +0 -70
  597. package/.next/server/chunks/ssr/_0zcjrbg._.js +0 -3
  598. package/.next/server/chunks/ssr/_0zhoc3r._.js +0 -3
  599. package/.next/server/chunks/ssr/_11j92tu._.js +0 -3
  600. package/.next/server/chunks/ssr/_13fke0x._.js +0 -3
  601. package/.next/server/chunks/ssr/_18cymkq._.js +0 -3
  602. package/.next/server/chunks/ssr/_1ebxla1._.js +0 -3
  603. package/.next/server/chunks/ssr/_1nj4niv._.js +0 -42
  604. package/.next/server/chunks/ssr/_1ov37if._.js +0 -3
  605. package/.next/server/chunks/ssr/_1ovmc9s._.js +0 -3
  606. package/.next/server/chunks/ssr/_1sji22n._.js +0 -3
  607. package/.next/server/chunks/ssr/_1vi_uo7._.js +0 -3
  608. package/.next/server/chunks/ssr/_1vyd1ji._.js +0 -3
  609. package/.next/server/chunks/ssr/_1xx4zlb._.js +0 -3
  610. package/.next/server/chunks/ssr/components_ui_1y1l7yj._.js +0 -3
  611. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +0 -3
  612. package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +0 -27
  613. package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +0 -27
  614. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0npjf8-._.js +0 -3
  615. package/.next/static/chunks/0n3jle9kbqfr2.js +0 -40
  616. package/.next/static/chunks/0r5qcctujhxli.js +0 -1
  617. package/.next/static/chunks/10teww7wt-f6h.js +0 -1
  618. package/.next/static/chunks/126fj4pga_72k.js +0 -1
  619. package/.next/static/chunks/159udiexf6dom.js +0 -2
  620. package/.next/static/chunks/18a96rkhi4_yd.js +0 -1
  621. package/.next/static/chunks/18gi7o2ibrgh8.js +0 -3
  622. package/.next/static/chunks/1dkjg87pxk0n9.js +0 -28
  623. package/.next/static/chunks/1q9z1tohil7xn.js +0 -1
  624. package/.next/static/chunks/1sjgfets224re.js +0 -1
  625. package/.next/static/chunks/1wszsr83t01gh.js +0 -1
  626. package/.next/static/chunks/22_zkas21rpna.js +0 -1
  627. package/.next/static/chunks/2fh4-3z_q8b_w.js +0 -1
  628. package/.next/static/chunks/2h0sd2vumhb15.js +0 -1
  629. package/.next/static/chunks/2szintyibu0s5.js +0 -1
  630. package/.next/static/chunks/2t4vhi3m8ahya.js +0 -1
  631. package/.next/static/chunks/2tigdtz3dpcy8.js +0 -1
  632. package/.next/static/chunks/3-b6b7entqazs.js +0 -1
  633. package/.next/static/chunks/3786h5vayt80-.js +0 -28
  634. package/.next/static/chunks/3cq5g494yuke8.css +0 -1
  635. package/.next/static/chunks/3dmbhsv2u_8kj.js +0 -1
  636. package/.next/static/chunks/3hibbjnt85-k6.js +0 -1
  637. package/.next/static/chunks/3i0a5px-oufgc.js +0 -1
  638. package/.next/static/chunks/3wexk9qo8zuj3.js +0 -18
  639. package/.next/static/chunks/3xk7yqgomx7yq.js +0 -1
  640. package/.next/static/chunks/3xre8bu_pk1p_.js +0 -1
  641. package/.next/static/chunks/3zv6t3i77xhr_.js +0 -1
  642. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +0 -1
  643. package/docs/images/task-thread.png +0 -0
  644. package/features/bot/components/task-badge.tsx +0 -42
  645. package/features/bot/components/task-reply.tsx +0 -328
  646. package/features/bot/components/task-setting.tsx +0 -524
  647. package/features/bot/task.query.ts +0 -1079
  648. package/features/bot/task.store.ts +0 -487
  649. package/lib/realtime/client-secret.ts +0 -86
  650. package/lib/realtime/open-session.ts +0 -31
  651. package/lib/realtime/openai.ts +0 -35
  652. package/lib/realtime/realtime.audio.ts +0 -196
  653. package/lib/realtime/realtime.driver.ts +0 -489
  654. package/lib/realtime/realtime.protocol.ts +0 -393
  655. package/lib/realtime/realtime.schema.ts +0 -37
  656. package/lib/realtime/realtime.session.ts +0 -106
  657. package/lib/realtime/realtime.transport.ts +0 -384
  658. package/lib/realtime/xai.ts +0 -39
  659. /package/.next/server/app/api/bot/{task → thread}/[id]/route/build-manifest.json +0 -0
  660. /package/.next/server/app/api/bot/{task → thread}/[id]/route/server-reference-manifest.json +0 -0
  661. /package/.next/server/app/api/bot/{task → thread}/[id]/route.js.map +0 -0
  662. /package/.next/server/app/api/bot/{task → thread}/route/build-manifest.json +0 -0
  663. /package/.next/server/app/api/bot/{task → thread}/route/server-reference-manifest.json +0 -0
  664. /package/.next/server/app/api/bot/{task → thread}/route.js.map +0 -0
  665. /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_buildManifest.js +0 -0
  666. /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_clientMiddlewareManifest.js +0 -0
  667. /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_ssgManifest.js +0 -0
@@ -0,0 +1,889 @@
1
+ import { createHash } from "node:crypto";
2
+ import type { ModelMessage } from "ai";
3
+ import { and, eq, inArray, max, or, sql } from "drizzle-orm";
4
+ import type { z } from "zod";
5
+ import { appEvents } from "@/app/api/events/app-event.server";
6
+ import { BOT_RUN } from "@/config";
7
+ import { database } from "@/database/db";
8
+ import {
9
+ threadDeliveryTable as delivery,
10
+ threadMessageTable as message,
11
+ threadRelayTable as relay,
12
+ threadTable as thread,
13
+ threadWorkTable as work,
14
+ } from "@/database/tables";
15
+ import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
16
+ import { publicError } from "@/lib/public-error";
17
+ import { THREAD_CONTINUE, tagSpeaker } from "./bot.schema";
18
+ import { RESUME_CHECK, ROOM_THURSDAY, RoomMessageSchema } from "./room.schema";
19
+ import type { ThreadMessageInput } from "./thread.query";
20
+
21
+ type Tx = Parameters<Parameters<typeof database.transaction>[0]>[0];
22
+ export type RoomWork = typeof work.$inferSelect;
23
+ const changed = () => appEvents.emit({ type: "threads" });
24
+ const terminal = (state: RoomWork["state"]) =>
25
+ state === "done" || state === "cancelled";
26
+ const messageKey = (threadId: string, bot: string, callId: string) =>
27
+ `message:${createHash("sha256")
28
+ .update(JSON.stringify([threadId, bot, callId]))
29
+ .digest("hex")}`;
30
+
31
+ /** Whether a bot has a question to the user still open. Until it is answered the bot runs nothing. */
32
+ async function isAsking(tx: Tx, threadId: string, bot: string) {
33
+ const [open] = await tx
34
+ .select({ id: work.id })
35
+ .from(work)
36
+ .where(
37
+ and(
38
+ eq(work.threadId, threadId),
39
+ eq(work.state, "external"),
40
+ eq(work.caller, bot),
41
+ ),
42
+ )
43
+ .limit(1);
44
+ return !!open;
45
+ }
46
+
47
+ /** Recover a committed send whose receipt was lost before the next transcript write. */
48
+ export async function listRoomReceipts(
49
+ threadId: string,
50
+ bot: string,
51
+ history: ModelMessage[],
52
+ ) {
53
+ const calls = history.flatMap((row) =>
54
+ row.role === "assistant" && Array.isArray(row.content)
55
+ ? row.content.flatMap((part) =>
56
+ part.type === "tool-call" && part.toolName === TOOL_NAMES.send_message
57
+ ? [part.toolCallId]
58
+ : [],
59
+ )
60
+ : [],
61
+ );
62
+ const keys = calls.map((id) => messageKey(threadId, bot, id));
63
+ const receipts = new Map<string, { messageId: string; to: string }>();
64
+ if (!keys.length) return receipts;
65
+ const [requests, replies] = await Promise.all([
66
+ database
67
+ .select({ key: work.id, to: work.bot })
68
+ .from(work)
69
+ .where(and(eq(work.threadId, threadId), inArray(work.id, keys))),
70
+ database
71
+ .select({ key: delivery.key, to: work.bot })
72
+ .from(delivery)
73
+ .innerJoin(work, eq(work.id, delivery.workId))
74
+ .where(and(eq(delivery.threadId, threadId), inArray(delivery.key, keys))),
75
+ ]);
76
+ const byKey = new Map(
77
+ [...requests, ...replies].map((row) => [row.key, row.to]),
78
+ );
79
+ for (const [index, id] of calls.entries()) {
80
+ const to = byKey.get(keys[index]);
81
+ if (to) receipts.set(id, { messageId: keys[index], to });
82
+ }
83
+ return receipts;
84
+ }
85
+
86
+ async function append(
87
+ tx: Tx,
88
+ threadId: string,
89
+ row: ThreadMessageInput & { hidden?: boolean },
90
+ ) {
91
+ const [last] = await tx
92
+ .select({ seq: max(message.seq) })
93
+ .from(message)
94
+ .where(eq(message.threadId, threadId));
95
+ const seq = (last?.seq ?? -1) + 1;
96
+ await tx.insert(message).values({ threadId, seq, ...row });
97
+ return seq;
98
+ }
99
+
100
+ /** What a participant reads where its turn broke off, before it picks up again. */
101
+ const breakNote = (run: Pick<RoomWork, "bot" | "id">, why: string) => ({
102
+ bot: run.bot,
103
+ parent: run.id,
104
+ role: "user" as const,
105
+ content: `${why} ${RESUME_CHECK}`,
106
+ note: true,
107
+ });
108
+
109
+ /** A turn tried again after a break (bot.runner) reads why first, as a resumed one does. */
110
+ export async function noteRoomBreak(run: RoomWork, why: string) {
111
+ await appendRoomMessage(run.threadId, breakNote(run, why));
112
+ }
113
+
114
+ /** Allocate at the database boundary; independent participant writers never share a counter. */
115
+ export async function appendRoomMessage(
116
+ threadId: string,
117
+ row: ThreadMessageInput & { hidden?: boolean },
118
+ ) {
119
+ const seq = await database.transaction((tx) => append(tx, threadId, row));
120
+ changed();
121
+ return seq;
122
+ }
123
+
124
+ export async function listRoomWork(threadId: string) {
125
+ return database
126
+ .select()
127
+ .from(work)
128
+ .where(eq(work.threadId, threadId))
129
+ .orderBy(work.createdAt, work.id);
130
+ }
131
+
132
+ /** Every continuation at this desk inherits the smallest threshold that its provider accepted. */
133
+ export async function roomContextBudget(threadId: string, bot: string) {
134
+ const [row] = await database
135
+ .select({
136
+ budget: sql<number | null>`min(nullif(${work.contextBudget}, 0))`,
137
+ })
138
+ .from(work)
139
+ .where(and(eq(work.threadId, threadId), eq(work.bot, bot)));
140
+ return row?.budget ?? undefined;
141
+ }
142
+
143
+ export async function lowerRoomContextBudget(run: RoomWork, budget: number) {
144
+ await database.transaction(async (tx) => {
145
+ await current(tx, run);
146
+ await tx
147
+ .update(work)
148
+ .set({ contextBudget: budget })
149
+ .where(eq(work.id, run.id));
150
+ });
151
+ changed();
152
+ }
153
+
154
+ async function current(tx: Tx, run: RoomWork) {
155
+ const [row] = await tx
156
+ .select()
157
+ .from(work)
158
+ .where(
159
+ and(
160
+ eq(work.id, run.id),
161
+ eq(work.generation, run.generation),
162
+ eq(work.state, "running"),
163
+ ),
164
+ );
165
+ if (!row) publicError("This turn is no longer running.");
166
+ return row;
167
+ }
168
+
169
+ async function deliver(tx: Tx, input: typeof delivery.$inferInsert) {
170
+ await tx.insert(delivery).values(input).onConflictDoNothing();
171
+ const [target] = await tx
172
+ .select({ bot: work.bot })
173
+ .from(work)
174
+ .where(eq(work.id, input.workId));
175
+ // A bot waiting on the user's answer reads nothing before it: its inbox holds (tellRoom wakes it)
176
+ if (target && (await isAsking(tx, input.threadId, target.bot))) return;
177
+ await tx
178
+ .update(work)
179
+ .set({ state: "queued" })
180
+ .where(
181
+ and(eq(work.id, input.workId), inArray(work.state, ["waiting", "done"])),
182
+ );
183
+ }
184
+
185
+ export async function sendRoomMessage(
186
+ run: RoomWork,
187
+ raw: z.input<typeof RoomMessageSchema> & { id: string },
188
+ ) {
189
+ const input = { ...RoomMessageSchema.parse(raw), id: raw.id };
190
+ if (input.kind === "question" && input.to !== ROOM_THURSDAY)
191
+ publicError(
192
+ "Address user questions to Thursday; use a message to contact another bot.",
193
+ );
194
+ if (input.options?.length && input.kind !== "question")
195
+ publicError("Offer answer choices only with a user question.");
196
+ const result = await database.transaction(async (tx) => {
197
+ await current(tx, run);
198
+ const key = messageKey(run.threadId, run.bot, input.id);
199
+ const [existing] = await tx.select().from(work).where(eq(work.id, key));
200
+ if (existing) return { messageId: key, to: existing.bot };
201
+ const [reply] = await tx
202
+ .select({ to: work.bot })
203
+ .from(delivery)
204
+ .innerJoin(work, eq(work.id, delivery.workId))
205
+ .where(eq(delivery.key, key));
206
+ if (reply) return { messageId: key, to: reply.to };
207
+ if (input.to === run.bot)
208
+ publicError("Continue your own work directly; choose another recipient.");
209
+ if (input.replyTo) {
210
+ const [target] = await tx
211
+ .select()
212
+ .from(work)
213
+ .where(
214
+ and(eq(work.id, input.replyTo), eq(work.threadId, run.threadId)),
215
+ );
216
+ if (
217
+ !target ||
218
+ target.bot !== run.bot ||
219
+ target.caller !== input.to ||
220
+ terminal(target.state)
221
+ )
222
+ publicError(
223
+ "Reply to an open message addressed to you from that recipient.",
224
+ );
225
+ if (target.parentId) {
226
+ await deliver(tx, {
227
+ key,
228
+ threadId: run.threadId,
229
+ workId: target.parentId,
230
+ speaker: run.bot,
231
+ text: input.text,
232
+ });
233
+ return { messageId: key, to: input.to };
234
+ }
235
+ // Thursday has no model continuation to wake; the message enters the user inbox below.
236
+ }
237
+ const all = await tx
238
+ .select()
239
+ .from(work)
240
+ .where(eq(work.threadId, run.threadId));
241
+ const bots = new Set(
242
+ all.map((row) => row.bot).filter((bot) => bot !== ROOM_THURSDAY),
243
+ );
244
+ if (
245
+ input.to !== ROOM_THURSDAY &&
246
+ !bots.has(input.to) &&
247
+ bots.size >= BOT_RUN.participants
248
+ )
249
+ publicError("This thread has reached its participant limit.");
250
+ if (
251
+ all.filter((row) => !terminal(row.state)).length >= BOT_RUN.queuedMessages
252
+ )
253
+ publicError("This thread has reached its pending message limit.");
254
+ const held =
255
+ input.to !== ROOM_THURSDAY &&
256
+ (await isAsking(tx, run.threadId, input.to));
257
+ await tx.insert(work).values({
258
+ id: key,
259
+ threadId: run.threadId,
260
+ bot: input.to,
261
+ caller: run.bot,
262
+ parentId: run.id,
263
+ state:
264
+ input.to === ROOM_THURSDAY
265
+ ? input.kind === "question"
266
+ ? "external"
267
+ : "done"
268
+ : held
269
+ ? "waiting"
270
+ : "queued",
271
+ result: input.to === ROOM_THURSDAY ? input.text : null,
272
+ options: [...new Set(input.options ?? [])],
273
+ });
274
+ if (input.to === ROOM_THURSDAY) {
275
+ await tx.insert(relay).values({
276
+ key,
277
+ threadId: run.threadId,
278
+ bot: run.bot,
279
+ text: input.text,
280
+ kind: input.kind,
281
+ messageId: input.kind === "question" ? key : null,
282
+ });
283
+ } else {
284
+ await deliver(tx, {
285
+ key,
286
+ threadId: run.threadId,
287
+ workId: key,
288
+ speaker: run.bot,
289
+ text: input.text,
290
+ });
291
+ }
292
+ await tx
293
+ .update(thread)
294
+ .set({ wrapped: false, updatedAt: new Date() })
295
+ .where(eq(thread.id, run.threadId));
296
+ return {
297
+ messageId: key,
298
+ to: input.to,
299
+ ...(held
300
+ ? {
301
+ note: `${input.to} is waiting for the user's answer and reads this after it.`,
302
+ }
303
+ : {}),
304
+ };
305
+ });
306
+ changed();
307
+ return result;
308
+ }
309
+
310
+ export async function claimRoomWork(threadId: string) {
311
+ let parked = false;
312
+ const claimed = await database.transaction(async (tx) => {
313
+ const [room] = await tx
314
+ .select()
315
+ .from(thread)
316
+ .where(eq(thread.id, threadId));
317
+ if (!room || room.status !== "running") return null;
318
+ const all = await tx
319
+ .select()
320
+ .from(work)
321
+ .where(eq(work.threadId, threadId))
322
+ .orderBy(sql`${work}.rowid`);
323
+ // A queued turn of a bot waiting on the user waits with it; the answer queues it again (tellRoom)
324
+ const asking = new Set(
325
+ all.filter((row) => row.state === "external").map((row) => row.caller),
326
+ );
327
+ for (const row of all) {
328
+ if (row.state !== "queued" || !asking.has(row.bot)) continue;
329
+ await tx
330
+ .update(work)
331
+ .set({ state: "waiting" })
332
+ .where(eq(work.id, row.id));
333
+ row.state = "waiting";
334
+ parked = true;
335
+ }
336
+ const active = all.filter((row) => row.state === "running");
337
+ if (active.length >= BOT_RUN.concurrent) return null;
338
+ const next = all.find(
339
+ (row) =>
340
+ row.state === "queued" &&
341
+ !active.some((other) => other.bot === row.bot),
342
+ );
343
+ if (!next) return null;
344
+ if (room.turns >= BOT_RUN.turns) {
345
+ await tx
346
+ .update(work)
347
+ .set({ state: "paused" })
348
+ .where(and(eq(work.threadId, threadId), eq(work.state, "queued")));
349
+ return null;
350
+ }
351
+ const [run] = await tx
352
+ .update(work)
353
+ .set({ state: "running", generation: next.generation + 1 })
354
+ .where(eq(work.id, next.id))
355
+ .returning();
356
+ await tx
357
+ .update(thread)
358
+ .set({ turns: room.turns + 1 })
359
+ .where(eq(thread.id, threadId));
360
+ return run;
361
+ });
362
+ if (claimed || parked) changed();
363
+ return claimed;
364
+ }
365
+
366
+ /** Inbox insertion and acknowledgement are one transaction, even when the model stops immediately afterward. */
367
+ export async function consumeRoomInbox(run: RoomWork): Promise<string[]> {
368
+ const texts = await database.transaction(async (tx) => {
369
+ await current(tx, run);
370
+ const rows = await tx
371
+ .select()
372
+ .from(delivery)
373
+ .where(and(eq(delivery.workId, run.id), eq(delivery.consumed, false)))
374
+ .orderBy(delivery.id);
375
+ for (const row of rows) {
376
+ const text = deliveryText(row);
377
+ await append(tx, run.threadId, {
378
+ bot: run.bot,
379
+ parent: run.id,
380
+ role: "user",
381
+ content: text,
382
+ hidden: !row.visible,
383
+ });
384
+ await tx
385
+ .update(delivery)
386
+ .set({ consumed: true })
387
+ .where(eq(delivery.id, row.id));
388
+ }
389
+ return rows.map(deliveryText);
390
+ });
391
+ if (texts.length) changed();
392
+ return texts;
393
+ }
394
+
395
+ function deliveryText(row: typeof delivery.$inferSelect) {
396
+ return row.visible
397
+ ? tagSpeaker(row.speaker === "The user" ? "user" : "thursday", row.text)
398
+ : `${row.speaker}:\n\n${row.text}`;
399
+ }
400
+
401
+ /** A normal loop end settles a conversation only after its downstream work returns. */
402
+ export async function finishRoomWork(run: RoomWork, text: string) {
403
+ await database.transaction(async (tx) => {
404
+ await current(tx, run);
405
+ const children = await tx
406
+ .select()
407
+ .from(work)
408
+ .where(eq(work.parentId, run.id));
409
+ const pending = await tx
410
+ .select({ id: delivery.id })
411
+ .from(delivery)
412
+ .where(and(eq(delivery.workId, run.id), eq(delivery.consumed, false)))
413
+ .limit(1);
414
+ // Waiting on the user's answer holds the inbox (deliver); the answer queues it (tellRoom)
415
+ const asking = await isAsking(tx, run.threadId, run.bot);
416
+ const state =
417
+ pending.length && !asking
418
+ ? "queued"
419
+ : pending.length || children.some((row) => !terminal(row.state))
420
+ ? "waiting"
421
+ : "done";
422
+ await tx
423
+ .update(work)
424
+ .set({ state, result: text })
425
+ .where(eq(work.id, run.id));
426
+ if (state !== "done") return;
427
+ if (run.parentId) {
428
+ const [parent] = await tx
429
+ .select()
430
+ .from(work)
431
+ .where(eq(work.id, run.parentId));
432
+ // An explicit reply (send_message replyTo) still unread is the answer; a
433
+ // silent ending adds nothing to it, and the reply already wakes the caller
434
+ const [replied] = text
435
+ ? []
436
+ : await tx
437
+ .select({ id: delivery.id })
438
+ .from(delivery)
439
+ .where(
440
+ and(
441
+ eq(delivery.workId, run.parentId),
442
+ eq(delivery.speaker, run.bot),
443
+ eq(delivery.consumed, false),
444
+ ),
445
+ )
446
+ .limit(1);
447
+ if (parent && parent.state !== "cancelled" && !replied) {
448
+ await deliver(tx, {
449
+ key: `return:${run.id}:${run.generation}`,
450
+ threadId: run.threadId,
451
+ workId: parent.id,
452
+ speaker: run.bot,
453
+ text: text || "This turn ended without a message.",
454
+ });
455
+ }
456
+ }
457
+ const [room] = await tx
458
+ .select()
459
+ .from(thread)
460
+ .where(eq(thread.id, run.threadId));
461
+ const all = await tx
462
+ .select()
463
+ .from(work)
464
+ .where(eq(work.threadId, run.threadId));
465
+ if (
466
+ room &&
467
+ run.bot === room.bot &&
468
+ !run.parentId &&
469
+ all.every((row) => terminal(row.state))
470
+ ) {
471
+ await tx
472
+ .update(thread)
473
+ .set({
474
+ status: text ? "done" : "waiting",
475
+ outcome: text || "The room is idle. Send a message to continue.",
476
+ pending: text ? null : { options: [THREAD_CONTINUE] },
477
+ wrapped: true,
478
+ endedAt: text ? new Date() : null,
479
+ seen: false,
480
+ updatedAt: new Date(),
481
+ })
482
+ .where(eq(thread.id, run.threadId));
483
+ if (text)
484
+ await tx
485
+ .insert(relay)
486
+ .values({
487
+ key: `report:${run.threadId}:${room.generation}`,
488
+ threadId: run.threadId,
489
+ bot: run.bot,
490
+ text,
491
+ kind: "report",
492
+ })
493
+ .onConflictDoNothing();
494
+ }
495
+ });
496
+ changed();
497
+ }
498
+
499
+ /** Called after runnable participants have been claimed; never confuse an idle room with successful work. */
500
+ export async function settleRoom(threadId: string) {
501
+ await database.transaction(async (tx) => {
502
+ const [room] = await tx
503
+ .select()
504
+ .from(thread)
505
+ .where(eq(thread.id, threadId));
506
+ if (!room || room.status !== "running") return;
507
+ const all = await tx.select().from(work).where(eq(work.threadId, threadId));
508
+ if (all.some((row) => row.state === "queued" || row.state === "running"))
509
+ return;
510
+ const question = all.find((row) => row.state === "external");
511
+ if (question) {
512
+ await tx
513
+ .update(thread)
514
+ .set({
515
+ status: "waiting",
516
+ outcome: question.result,
517
+ pending: {
518
+ options: question.options,
519
+ messageId: question.id,
520
+ bot: question.caller,
521
+ },
522
+ updatedAt: new Date(),
523
+ })
524
+ .where(eq(thread.id, threadId));
525
+ return;
526
+ }
527
+ if (all.some((row) => !terminal(row.state)) || room.wrapped) {
528
+ await tx
529
+ .update(thread)
530
+ .set({
531
+ status: "waiting",
532
+ outcome:
533
+ room.turns >= BOT_RUN.turns
534
+ ? "The room reached its automatic turn limit. Continue from the saved conversation."
535
+ : "Work is paused. Continue from the saved conversation.",
536
+ pending: { options: [THREAD_CONTINUE] },
537
+ updatedAt: new Date(),
538
+ })
539
+ .where(eq(thread.id, threadId));
540
+ return;
541
+ }
542
+ const id = crypto.randomUUID();
543
+ await tx.insert(work).values({
544
+ id,
545
+ threadId,
546
+ bot: room.bot,
547
+ caller: ROOM_THURSDAY,
548
+ state: "queued",
549
+ });
550
+ await deliver(tx, {
551
+ key: id,
552
+ threadId,
553
+ workId: id,
554
+ speaker: "Thread activity",
555
+ text: "The participants have finished their current turns. Bring together the results you received for Thursday, including anything still unresolved.",
556
+ });
557
+ await tx
558
+ .update(thread)
559
+ .set({ wrapped: true })
560
+ .where(eq(thread.id, threadId));
561
+ });
562
+ changed();
563
+ }
564
+
565
+ export async function pauseRoom(threadId: string, why: string, auto = false) {
566
+ await database.transaction(async (tx) => {
567
+ const all = await tx.select().from(work).where(eq(work.threadId, threadId));
568
+ for (const row of all.filter(
569
+ (row) => row.state === "running" || row.state === "queued",
570
+ )) {
571
+ await tx
572
+ .update(work)
573
+ .set({ state: "paused", generation: row.generation + 1 })
574
+ .where(eq(work.id, row.id));
575
+ await append(tx, threadId, breakNote(row, why));
576
+ }
577
+ await tx
578
+ .update(thread)
579
+ .set({
580
+ status: "waiting",
581
+ outcome: why,
582
+ pending: {
583
+ options: [THREAD_CONTINUE],
584
+ ...(auto ? { auto: true } : {}),
585
+ },
586
+ seen: false,
587
+ endedAt: null,
588
+ updatedAt: new Date(),
589
+ })
590
+ .where(eq(thread.id, threadId));
591
+ await tx.insert(relay).values({
592
+ key: crypto.randomUUID(),
593
+ threadId,
594
+ bot: all.find((row) => !row.parentId)?.bot ?? "Bot",
595
+ text: why,
596
+ kind: "interrupted",
597
+ accepted: auto,
598
+ });
599
+ });
600
+ changed();
601
+ }
602
+
603
+ export async function resumeRoom(threadId: string, manual = true) {
604
+ await database.transaction(async (tx) => {
605
+ await tx
606
+ .update(work)
607
+ .set({ state: "queued" })
608
+ .where(and(eq(work.threadId, threadId), eq(work.state, "paused")));
609
+ await tx
610
+ .update(thread)
611
+ .set({
612
+ status: "running",
613
+ ...(manual
614
+ ? { generation: sql`${thread.generation} + 1`, turns: 0 }
615
+ : {}),
616
+ pending: null,
617
+ outcome: null,
618
+ endedAt: null,
619
+ updatedAt: new Date(),
620
+ })
621
+ .where(eq(thread.id, threadId));
622
+ // The stop it picks up from is no longer news
623
+ await tx
624
+ .update(relay)
625
+ .set({ accepted: true })
626
+ .where(and(eq(relay.threadId, threadId), eq(relay.kind, "interrupted")));
627
+ });
628
+ changed();
629
+ }
630
+
631
+ /**
632
+ * The question words from the user side answer: the one the named bot is waiting
633
+ * on, or with no bot named the only one open. Several and none named is the
634
+ * sender's to settle, so it is refused with the list.
635
+ */
636
+ function questionFor(open: RoomWork[], recipient?: string) {
637
+ const asked = recipient
638
+ ? open.filter((row) => row.caller === recipient)
639
+ : open;
640
+ if (asked.length <= 1) return asked[0];
641
+ publicError(
642
+ `Several questions are waiting for an answer: ${asked
643
+ .map(
644
+ (row) =>
645
+ `${row.caller} (replyTo ${row.id}): “${(row.result ?? "").slice(0, 160)}”`,
646
+ )
647
+ .join("; ")}. Answer one of them by its replyTo.`,
648
+ );
649
+ }
650
+
651
+ /** Queue every turn a bot held while it waited on the user that has something to read. */
652
+ async function wake(tx: Tx, threadId: string, bot: string) {
653
+ const unread = tx
654
+ .select({ workId: delivery.workId })
655
+ .from(delivery)
656
+ .where(and(eq(delivery.threadId, threadId), eq(delivery.consumed, false)));
657
+ await tx
658
+ .update(work)
659
+ .set({ state: "queued" })
660
+ .where(
661
+ and(
662
+ eq(work.threadId, threadId),
663
+ eq(work.bot, bot),
664
+ inArray(work.state, ["waiting", "done"]),
665
+ inArray(work.id, unread),
666
+ ),
667
+ );
668
+ }
669
+
670
+ /** User messages enter the recipient's active continuation, retaining its original return route. */
671
+ export async function tellRoom(
672
+ threadId: string,
673
+ text: string,
674
+ speaker: string,
675
+ recipient?: string,
676
+ replyTo?: string,
677
+ /** False for Continue, which never answers a question. */
678
+ answering = true,
679
+ ) {
680
+ const told = await database.transaction(async (tx) => {
681
+ const [room] = await tx
682
+ .select()
683
+ .from(thread)
684
+ .where(eq(thread.id, threadId));
685
+ if (!room) publicError("No such thread.");
686
+ const all = await tx
687
+ .select()
688
+ .from(work)
689
+ .where(eq(work.threadId, threadId))
690
+ .orderBy(work.createdAt);
691
+ const open = all.filter((row) => row.state === "external");
692
+ const question = replyTo
693
+ ? (open.find((row) => row.id === replyTo) ??
694
+ publicError("That question is no longer waiting for an answer."))
695
+ : answering
696
+ ? questionFor(open, recipient)
697
+ : undefined;
698
+ const bot = question?.caller ?? recipient ?? room.bot;
699
+ let target = question
700
+ ? all.find((row) => row.id === question.parentId)
701
+ : (all.find((row) => row.bot === bot && row.state === "running") ??
702
+ all.find(
703
+ (row) =>
704
+ row.bot === bot && !terminal(row.state) && row.state !== "external",
705
+ ));
706
+ if (question) {
707
+ await tx
708
+ .update(work)
709
+ .set({ state: "done", result: text })
710
+ .where(eq(work.id, question.id));
711
+ await tx
712
+ .update(relay)
713
+ .set({ accepted: true })
714
+ .where(eq(relay.messageId, question.id));
715
+ }
716
+ if (!target) {
717
+ let parentId: string | null = null;
718
+ if (bot !== room.bot) {
719
+ let coordinator = all.findLast(
720
+ (row) =>
721
+ row.bot === room.bot && !row.parentId && row.state !== "cancelled",
722
+ );
723
+ if (!coordinator) {
724
+ coordinator = (
725
+ await tx
726
+ .insert(work)
727
+ .values({
728
+ id: crypto.randomUUID(),
729
+ threadId,
730
+ bot: room.bot,
731
+ caller: ROOM_THURSDAY,
732
+ state: "waiting",
733
+ })
734
+ .returning()
735
+ )[0];
736
+ } else if (coordinator.state === "done") {
737
+ await tx
738
+ .update(work)
739
+ .set({ state: "waiting" })
740
+ .where(eq(work.id, coordinator.id));
741
+ }
742
+ parentId = coordinator.id;
743
+ }
744
+ target = (
745
+ await tx
746
+ .insert(work)
747
+ .values({
748
+ id: crypto.randomUUID(),
749
+ threadId,
750
+ bot,
751
+ caller: parentId ? room.bot : ROOM_THURSDAY,
752
+ parentId,
753
+ state: "queued",
754
+ })
755
+ .returning()
756
+ )[0];
757
+ }
758
+ // The bot is told which question the next words answer; the screen draws only the words (hidden)
759
+ if (question)
760
+ await deliver(tx, {
761
+ key: `answer:${question.id}`,
762
+ threadId,
763
+ workId: target.id,
764
+ speaker: "Thread activity",
765
+ text: `The next message answers your question to the user: “${question.result ?? ""}”`,
766
+ });
767
+ const key = crypto.randomUUID();
768
+ await deliver(tx, {
769
+ key,
770
+ threadId,
771
+ workId: target.id,
772
+ speaker,
773
+ text,
774
+ visible: true,
775
+ });
776
+ // Answered, the bot reads again: every turn it held while waiting is queued in arrival order
777
+ if (question && !(await isAsking(tx, threadId, bot)))
778
+ await wake(tx, threadId, bot);
779
+ await tx
780
+ .update(work)
781
+ .set({ state: "queued" })
782
+ .where(and(eq(work.threadId, threadId), eq(work.state, "paused")));
783
+ await tx
784
+ .update(thread)
785
+ .set({
786
+ status: "running",
787
+ generation: sql`${thread.generation} + 1`,
788
+ turns: 0,
789
+ wrapped: false,
790
+ pending: null,
791
+ outcome: null,
792
+ endedAt: null,
793
+ seen: false,
794
+ updatedAt: new Date(),
795
+ })
796
+ .where(eq(thread.id, threadId));
797
+ // Words that start it again supersede how it last stopped or ended
798
+ await tx
799
+ .update(relay)
800
+ .set({ accepted: true })
801
+ .where(
802
+ and(
803
+ eq(relay.threadId, threadId),
804
+ inArray(relay.kind, ["interrupted", "report"]),
805
+ ),
806
+ );
807
+ return {
808
+ key,
809
+ to: bot,
810
+ answered: question
811
+ ? { bot: question.caller, question: question.result ?? "" }
812
+ : null,
813
+ };
814
+ });
815
+ changed();
816
+ return told;
817
+ }
818
+
819
+ export async function cancelRoom(threadId: string) {
820
+ await database.transaction(async (tx) => {
821
+ await tx
822
+ .update(work)
823
+ .set({ state: "cancelled", generation: sql`${work.generation} + 1` })
824
+ .where(
825
+ and(
826
+ eq(work.threadId, threadId),
827
+ inArray(work.state, [
828
+ "queued",
829
+ "running",
830
+ "waiting",
831
+ "external",
832
+ "paused",
833
+ ]),
834
+ ),
835
+ );
836
+ await tx
837
+ .update(relay)
838
+ .set({ accepted: true })
839
+ .where(eq(relay.threadId, threadId));
840
+ });
841
+ changed();
842
+ }
843
+
844
+ export async function listParticipantTranscript(
845
+ threadId: string,
846
+ bot: string,
847
+ ): Promise<ModelMessage[]> {
848
+ const [room] = await database
849
+ .select({ bot: thread.bot })
850
+ .from(thread)
851
+ .where(eq(thread.id, threadId));
852
+ // The coordinator's opening (seq 0) is written before any bot speaks
853
+ const rows = await database
854
+ .select()
855
+ .from(message)
856
+ .where(
857
+ and(
858
+ eq(message.threadId, threadId),
859
+ or(
860
+ eq(message.bot, bot),
861
+ room?.bot === bot
862
+ ? sql`${message.bot} is null AND ${message.parent} is null`
863
+ : undefined,
864
+ ),
865
+ ),
866
+ )
867
+ .orderBy(message.seq);
868
+ const compact = rows.findLastIndex((row) => row.compact);
869
+ const kept = compact > 0 ? [rows[0], ...rows.slice(compact)] : rows;
870
+ return kept.map(
871
+ (row) => ({ role: row.role, content: row.content }) as ModelMessage,
872
+ );
873
+ }
874
+
875
+ export async function listRoomRelays() {
876
+ return database
877
+ .select()
878
+ .from(relay)
879
+ .where(eq(relay.accepted, false))
880
+ .orderBy(relay.id);
881
+ }
882
+ export async function acceptRoomRelays(ids: number[]) {
883
+ if (!ids.length) return;
884
+ await database
885
+ .update(relay)
886
+ .set({ accepted: true })
887
+ .where(inArray(relay.id, ids));
888
+ changed();
889
+ }