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
@@ -1,976 +0,0 @@
1
- import type { AssistantContent, ModelMessage, ToolContent } from "ai";
2
- import {
3
- and,
4
- desc,
5
- eq,
6
- inArray,
7
- isNotNull,
8
- isNull,
9
- lt,
10
- max,
11
- sql,
12
- } from "drizzle-orm";
13
- import { appEvents } from "@/app/api/events/app-event.server";
14
- import { INBOX_FINISHED } from "@/config";
15
- import { database } from "@/database/db";
16
- import { taskMessageTable, taskTable } from "@/database/tables";
17
- import { answerAccepted, isAnswerCall } from "@/features/ai/tools/bot.tool";
18
- import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
19
- import { clip } from "@/lib/utils";
20
- import {
21
- type ResultPart,
22
- TASK_HISTORY_PAGE,
23
- type Task,
24
- type TaskLine,
25
- type TaskPending,
26
- type TaskStatus,
27
- type TokenUsage,
28
- untagSpeaker,
29
- } from "./bot.schema";
30
-
31
- // Tasks and their threads. Bots themselves (roster, pinned tools) are bot.query.
32
-
33
- /** Every write in this file ends with this; the screen re-reads the list on it. */
34
- const changed = () => appEvents.emit({ type: "tasks" });
35
-
36
- /** Task state without the thread. `lines` is filled by `withLines` from task_message; `pending` folds into `ask`. */
37
- const taskView = {
38
- id: taskTable.id,
39
- bot: taskTable.bot,
40
- label: taskTable.label,
41
- request: taskTable.request,
42
- status: taskTable.status,
43
- outcome: taskTable.outcome,
44
- pending: taskTable.pending,
45
- seen: taskTable.seen,
46
- inputTokens: taskTable.inputTokens,
47
- outputTokens: taskTable.outputTokens,
48
- contextTokens: taskTable.contextTokens,
49
- contextBudget: taskTable.contextBudget,
50
- createdAt: taskTable.createdAt,
51
- updatedAt: taskTable.updatedAt,
52
- };
53
-
54
- type TaskRow = {
55
- id: string;
56
- bot: string;
57
- label: string;
58
- request: string;
59
- status: TaskStatus;
60
- outcome: string | null;
61
- pending: TaskPending | null;
62
- seen: boolean;
63
- inputTokens: number;
64
- outputTokens: number;
65
- contextTokens: number;
66
- contextBudget: number;
67
- createdAt: Date;
68
- updatedAt: Date;
69
- };
70
-
71
- /**
72
- * One row plus the thread's first message. `request` is what the screen shows;
73
- * `opening` is what the model reads (who is who, the job, the call it came from). The screen
74
- * skips seq 0 and shows `request` instead (linesOf).
75
- */
76
- export async function insertTask(input: {
77
- bot: string;
78
- label: string;
79
- request: string;
80
- callId?: string | null;
81
- opening: Extract<ModelMessage, { role: "user" }>["content"];
82
- }) {
83
- const { opening, ...row } = input;
84
- const [task] = await database
85
- .insert(taskTable)
86
- .values({ id: crypto.randomUUID(), status: "running", ...row })
87
- .returning();
88
- await upsertMessage(task.id, 0, {
89
- bot: null,
90
- parent: null,
91
- role: "user",
92
- content: opening,
93
- });
94
- changed();
95
- return task;
96
- }
97
-
98
- export async function updateTask(
99
- id: string,
100
- patch: Partial<{
101
- status: TaskStatus;
102
- outcome: string | null;
103
- pending: TaskPending | null;
104
- seen: boolean;
105
- endedAt: Date | null;
106
- /** Where the job compacts from now on; also written at every step (addTaskUsage). */
107
- contextBudget: number;
108
- }>,
109
- ) {
110
- await database
111
- .update(taskTable)
112
- .set({ ...patch, updatedAt: new Date() })
113
- .where(eq(taskTable.id, id));
114
- changed();
115
- }
116
-
117
- /** Bypasses `updateTask` on purpose: being seen is not movement and must not reorder the inbox by updatedAt. */
118
- export async function markSeen(ids: string[]) {
119
- if (ids.length === 0) return;
120
- await database
121
- .update(taskTable)
122
- .set({ seen: true })
123
- .where(inArray(taskTable.id, ids));
124
- changed();
125
- }
126
-
127
- /**
128
- * Adds one step's usage (added, not set: borrowed-bot steps land on the same
129
- * task in parallel) without touching updatedAt. `context` is overwritten: it is
130
- * the current window fill and threshold, not a sum. null leaves it as is.
131
- */
132
- export async function addTaskUsage(
133
- id: string,
134
- usage: TokenUsage,
135
- context: { tokens: number; budget: number } | null = null,
136
- ) {
137
- if (!usage.input && !usage.output && context === null) return;
138
- await database
139
- .update(taskTable)
140
- .set({
141
- inputTokens: sql`${taskTable.inputTokens} + ${usage.input}`,
142
- outputTokens: sql`${taskTable.outputTokens} + ${usage.output}`,
143
- ...(context === null
144
- ? {}
145
- : { contextTokens: context.tokens, contextBudget: context.budget }),
146
- })
147
- .where(eq(taskTable.id, id));
148
- changed();
149
- }
150
-
151
- /** One task as the screen sees it, thread included. null if missing. */
152
- export async function findTaskView(id: string): Promise<Task | null> {
153
- const [row] = await database
154
- .select(taskView)
155
- .from(taskTable)
156
- .where(eq(taskTable.id, id));
157
- if (!row) return null;
158
- const [task] = await withLines([row]);
159
- return task ?? null;
160
- }
161
-
162
- export async function findTask(id: string) {
163
- const [task] = await database
164
- .select()
165
- .from(taskTable)
166
- .where(eq(taskTable.id, id));
167
- return task ?? null;
168
- }
169
-
170
- /** Inbox: everything running or waiting plus the latest INBOX_FINISHED endings, newest first. `seen` is not a filter here. */
171
- export async function listInboxTasks(): Promise<Task[]> {
172
- const [open, finished] = await Promise.all([
173
- database
174
- .select(taskView)
175
- .from(taskTable)
176
- .where(inArray(taskTable.status, ["running", "waiting"]))
177
- .orderBy(desc(taskTable.updatedAt)),
178
- database
179
- .select(taskView)
180
- .from(taskTable)
181
- .where(inArray(taskTable.status, ["done", "failed"]))
182
- .orderBy(desc(taskTable.updatedAt))
183
- .limit(INBOX_FINISHED),
184
- ]);
185
- const rows = [...open, ...finished].sort(
186
- (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime(),
187
- );
188
- return withLines(rows);
189
- }
190
-
191
- /** All tasks, newest first, one page at a time. `before` is a cursor (last page's updatedAt), not an offset, because rows move in between. */
192
- export async function listTaskHistory(
193
- options: { before?: Date | null; limit?: number } = {},
194
- ): Promise<Task[]> {
195
- const rows = await database
196
- .select(taskView)
197
- .from(taskTable)
198
- .where(options.before ? lt(taskTable.updatedAt, options.before) : undefined)
199
- .orderBy(desc(taskTable.updatedAt))
200
- .limit(options.limit ?? TASK_HISTORY_PAGE);
201
- return withLines(rows);
202
- }
203
-
204
- /**
205
- * What each of these calls handed over, for the transcript the next call reads
206
- * (ai/prompts/thursday.prompt). Not the inbox: a job belongs to the call it was
207
- * opened from, and this is how it is still there once that call is over.
208
- */
209
- export async function listCallJobs(callIds: string[]) {
210
- if (!callIds.length) return [];
211
- return await database
212
- .select({
213
- id: taskTable.id,
214
- callId: taskTable.callId,
215
- label: taskTable.label,
216
- status: taskTable.status,
217
- outcome: taskTable.outcome,
218
- })
219
- .from(taskTable)
220
- .where(inArray(taskTable.callId, callIds))
221
- .orderBy(taskTable.createdAt);
222
- }
223
-
224
- export type CallJob = Awaited<ReturnType<typeof listCallJobs>>[number];
225
-
226
- /** The thread goes with it (cascade). The runner stops a live one first. */
227
- export async function deleteTask(id: string) {
228
- const removed = await database
229
- .delete(taskTable)
230
- .where(eq(taskTable.id, id))
231
- .returning({ id: taskTable.id });
232
- if (removed.length) changed();
233
- return removed.length > 0;
234
- }
235
-
236
- /** Everything finished, done or failed. Running and waiting rows stay: they are still work. */
237
- export async function deleteFinishedTasks() {
238
- const removed = await database
239
- .delete(taskTable)
240
- .where(inArray(taskTable.status, ["done", "failed"]))
241
- // The label comes back too: a job's working folder is named for it and goes
242
- // with the row (bot.runner removeFinishedTasks).
243
- .returning({ id: taskTable.id, label: taskTable.label });
244
- if (removed.length) changed();
245
- return removed;
246
- }
247
-
248
- /** Every job, newest first. The caller stops each one before deleting it (bot.runner removeTask). */
249
- export async function listAllTaskIds(): Promise<string[]> {
250
- const rows = await database
251
- .select({ id: taskTable.id })
252
- .from(taskTable)
253
- .orderBy(desc(taskTable.createdAt));
254
- return rows.map((row) => row.id);
255
- }
256
-
257
- /** Rows a previous server left as running; the runner decides which still are. */
258
- export async function listRunningTaskIds() {
259
- const rows = await database
260
- .select({ id: taskTable.id })
261
- .from(taskTable)
262
- .where(eq(taskTable.status, "running"));
263
- return rows.map((row) => row.id);
264
- }
265
-
266
- /** Every job with what names its folder and whether it still keeps it (bot.runner sweepJobFiles). */
267
- export async function listTaskFolders() {
268
- return await database
269
- .select({
270
- id: taskTable.id,
271
- label: taskTable.label,
272
- status: taskTable.status,
273
- endedAt: taskTable.endedAt,
274
- updatedAt: taskTable.updatedAt,
275
- })
276
- .from(taskTable);
277
- }
278
-
279
- /** Jobs the app parked to pick back up by itself (bot.runner parkTask), and when each may go. */
280
- export async function listAutoStoppedTasks() {
281
- const rows = await database
282
- .select({ id: taskTable.id, pending: taskTable.pending })
283
- .from(taskTable)
284
- .where(eq(taskTable.status, "waiting"));
285
- return rows.flatMap((row) =>
286
- row.pending?.auto
287
- ? [{ id: row.id, retryAt: row.pending.retryAt ?? 0 }]
288
- : [],
289
- );
290
- }
291
-
292
- /**
293
- * How many times the app has stopped this job since a person last said anything
294
- * to it: the notes it left in the thread — a break, a park — back to the last row
295
- * a person wrote: the opening, an answer, a word to a running job. Read off the
296
- * rows rather than kept as a count, so it cannot drift from what the thread shows.
297
- */
298
- export async function countStopsSinceSpoken(taskId: string): Promise<number> {
299
- const rows = await database
300
- .select({
301
- role: taskMessageTable.role,
302
- bot: taskMessageTable.bot,
303
- note: taskMessageTable.note,
304
- compact: taskMessageTable.compact,
305
- })
306
- .from(taskMessageTable)
307
- .where(
308
- and(eq(taskMessageTable.taskId, taskId), isNull(taskMessageTable.parent)),
309
- )
310
- .orderBy(desc(taskMessageTable.seq));
311
- let stops = 0;
312
- for (const row of rows) {
313
- if (row.note) {
314
- if (!row.compact) stops += 1;
315
- continue;
316
- }
317
- // A person: the opening and every answer are written with no bot, and a
318
- // word to a running job is a user row in the bot's name
319
- if (row.bot === null || row.role === "user") break;
320
- }
321
- return stops;
322
- }
323
-
324
- /** How much of a cut-off borrowed bot's prose a resume carries: its last few paragraphs. */
325
- const TAIL = { texts: 3, chars: 600 };
326
-
327
- /**
328
- * What each borrowed bot had written when its `ask_bot` call stopped, by that
329
- * call's id: its last few paragraphs, and the tool it reached for after them. A
330
- * resumed run reads it where the call's result never arrived (bot.run
331
- * resumeThread), so a part cut off half-way is carried on, not asked for afresh.
332
- */
333
- export async function listBorrowedTails(
334
- taskId: string,
335
- ): Promise<Map<string, { bot: string; tail: string }>> {
336
- const rows = await database
337
- .select({
338
- parent: taskMessageTable.parent,
339
- bot: taskMessageTable.bot,
340
- content: taskMessageTable.content,
341
- })
342
- .from(taskMessageTable)
343
- .where(
344
- and(
345
- eq(taskMessageTable.taskId, taskId),
346
- isNotNull(taskMessageTable.parent),
347
- eq(taskMessageTable.role, "assistant"),
348
- ),
349
- )
350
- .orderBy(taskMessageTable.seq);
351
-
352
- const calls = new Map<
353
- string,
354
- { bot: string; texts: string[]; then: string | null }
355
- >();
356
- for (const row of rows) {
357
- if (!row.parent) continue;
358
- const call = calls.get(row.parent) ?? {
359
- bot: row.bot ?? "",
360
- texts: [],
361
- then: null,
362
- };
363
- const content = row.content as AssistantContent;
364
- const parts =
365
- typeof content === "string"
366
- ? [{ type: "text" as const, text: content }]
367
- : content;
368
- for (const part of parts) {
369
- if (part.type === "text" && part.text.trim()) {
370
- call.texts.push(part.text.trim());
371
- call.then = null;
372
- } else if (part.type === "tool-call") {
373
- call.then =
374
- `${part.toolName} ${toolLine(part.toolName, part.input)}`.trim();
375
- }
376
- }
377
- calls.set(row.parent, call);
378
- }
379
-
380
- const tails = new Map<string, { bot: string; tail: string }>();
381
- for (const [id, call] of calls) {
382
- const tail = [
383
- ...call.texts.slice(-TAIL.texts).map((text) => clip(text, TAIL.chars)),
384
- call.then ? `Then: ${call.then}` : "",
385
- ]
386
- .filter(Boolean)
387
- .join("\n\n");
388
- if (tail) tails.set(id, { bot: call.bot, tail });
389
- }
390
- return tails;
391
- }
392
-
393
- /**
394
- * Paths a list of message contents gave `write_file`, oldest first and each once; a
395
- * path written again moves to the end. A refused write is here too, so whoever shows
396
- * them checks the disk (workspace.ts filesOnDisk).
397
- */
398
- export function writtenPathsIn(contents: unknown[]): string[] {
399
- const paths = new Set<string>();
400
- for (const content of contents) {
401
- if (!Array.isArray(content)) continue;
402
- for (const part of content as {
403
- type?: unknown;
404
- toolName?: unknown;
405
- input?: unknown;
406
- }[]) {
407
- if (
408
- part.type !== "tool-call" ||
409
- part.toolName !== TOOL_NAMES.write_file
410
- ) {
411
- continue;
412
- }
413
- const path = (part.input as { path?: unknown } | null)?.path;
414
- if (typeof path !== "string" || !path.trim()) continue;
415
- paths.delete(path.trim());
416
- paths.add(path.trim());
417
- }
418
- }
419
- return [...paths];
420
- }
421
-
422
- /** Every path this job gave `write_file`: its own bot and each bot it borrowed (writtenPathsIn). */
423
- export async function listWrittenPaths(taskId: string): Promise<string[]> {
424
- const rows = await database
425
- .select({ content: taskMessageTable.content })
426
- .from(taskMessageTable)
427
- .where(
428
- and(
429
- eq(taskMessageTable.taskId, taskId),
430
- eq(taskMessageTable.role, "assistant"),
431
- ),
432
- )
433
- .orderBy(taskMessageTable.seq);
434
- return writtenPathsIn(rows.map((row) => row.content));
435
- }
436
-
437
- /**
438
- * Finds a task by id or by exact label (case-insensitive). No looser matching:
439
- * a miss returns null and the caller lists recent tasks instead.
440
- */
441
- export async function resolveTask(ref: string) {
442
- const term = ref.trim();
443
- if (!term) return null;
444
- const whole = await findTask(term);
445
- if (whole) return whole;
446
-
447
- const lower = term.toLowerCase();
448
- const recent = await database
449
- .select()
450
- .from(taskTable)
451
- .orderBy(desc(taskTable.updatedAt))
452
- .limit(20);
453
- return recent.find((task) => task.label.toLowerCase() === lower) ?? null;
454
- }
455
-
456
- export type TaskMessageInput = {
457
- bot: string | null;
458
- parent: string | null;
459
- role: ModelMessage["role"];
460
- content: ModelMessage["content"];
461
- /** Compaction summary row; `listThread` re-reads from here. */
462
- compact?: boolean;
463
- /** Drawn as the app's own line, not as something a person or a bot said. */
464
- note?: boolean;
465
- };
466
-
467
- /**
468
- * Writes by seat, not append: a step's messages are written while streaming and
469
- * rewritten whole when it ends, and the second write must replace the first.
470
- */
471
- export async function upsertMessage(
472
- taskId: string,
473
- seq: number,
474
- message: TaskMessageInput,
475
- ) {
476
- await database
477
- .insert(taskMessageTable)
478
- .values({
479
- taskId,
480
- seq,
481
- ...message,
482
- compact: message.compact ?? false,
483
- note: message.note ?? false,
484
- })
485
- .onConflictDoUpdate({
486
- target: [taskMessageTable.taskId, taskMessageTable.seq],
487
- set: {
488
- role: message.role,
489
- content: message.content,
490
- compact: message.compact ?? false,
491
- note: message.note ?? false,
492
- },
493
- });
494
- changed();
495
- }
496
-
497
- /** Frees seats claimed while streaming but unused when the step ended. Left in, they put unmatched tool results in the thread the model re-reads. */
498
- export async function deleteMessages(taskId: string, seqs: number[]) {
499
- if (!seqs.length) return;
500
- await database
501
- .delete(taskMessageTable)
502
- .where(
503
- and(
504
- eq(taskMessageTable.taskId, taskId),
505
- inArray(taskMessageTable.seq, seqs),
506
- ),
507
- );
508
- changed();
509
- }
510
-
511
- /** Highest seq taken so far; -1 for an empty thread. */
512
- export async function lastSeq(taskId: string): Promise<number> {
513
- const [row] = await database
514
- .select({ seq: max(taskMessageTable.seq) })
515
- .from(taskMessageTable)
516
- .where(eq(taskMessageTable.taskId, taskId));
517
- return row?.seq ?? -1;
518
- }
519
-
520
- /**
521
- * The task's own thread as the model sees it: parent-less messages in order.
522
- * What a borrowed bot said inside an `ask_bot` call is not here; its result is.
523
- * After a compaction it is the opening, then the last compact row on: a summary
524
- * replaces what came after the job and the call, never the job and the call.
525
- */
526
- export async function listThread(taskId: string): Promise<ModelMessage[]> {
527
- const rows = await database
528
- .select({
529
- role: taskMessageTable.role,
530
- content: taskMessageTable.content,
531
- compact: taskMessageTable.compact,
532
- })
533
- .from(taskMessageTable)
534
- .where(
535
- and(eq(taskMessageTable.taskId, taskId), isNull(taskMessageTable.parent)),
536
- )
537
- .orderBy(taskMessageTable.seq);
538
- const from = rows.findLastIndex((row) => row.compact);
539
- const kept = from > 0 ? [rows[0], ...rows.slice(from)] : rows;
540
- return kept.map(
541
- (row) => ({ role: row.role, content: row.content }) as ModelMessage,
542
- );
543
- }
544
-
545
- /** One row in the screen's shape; `pending` folds into `ask`. */
546
- function viewOf(row: TaskRow, lines: TaskLine[]): Task {
547
- // contextTokens and contextBudget pass through in `rest`
548
- const { pending, inputTokens, outputTokens, ...rest } = row;
549
- return {
550
- ...rest,
551
- ask:
552
- row.status === "waiting"
553
- ? {
554
- question: row.outcome ?? "",
555
- options: pending?.options ?? [],
556
- auto: pending?.auto === true,
557
- }
558
- : null,
559
- tokens: { input: inputTokens, output: outputTokens },
560
- lines,
561
- };
562
- }
563
-
564
- /** Reduces every task's thread to lines and attaches them to the rows. */
565
- async function withLines(rows: TaskRow[]): Promise<Task[]> {
566
- if (rows.length === 0) return [];
567
- const messages = await database
568
- .select()
569
- .from(taskMessageTable)
570
- .where(
571
- inArray(
572
- taskMessageTable.taskId,
573
- rows.map((row) => row.id),
574
- ),
575
- )
576
- .orderBy(taskMessageTable.seq);
577
-
578
- // ask_back lines name no addressee; the task's own bot is the addressee
579
- const owners = new Map(rows.map((row) => [row.id, row.bot]));
580
- const byTask = new Map<string, TaskLine[]>();
581
- for (const message of messages) {
582
- const list = byTask.get(message.taskId) ?? [];
583
- list.push(...linesOf(message, owners.get(message.taskId) ?? ""));
584
- byTask.set(message.taskId, list);
585
- }
586
- return rows.map((row) => viewOf(row, byTask.get(row.id) ?? []));
587
- }
588
-
589
- /** One-line cap: room for a path, small enough for a row. */
590
- const LINE_MAX = 120;
591
-
592
- /** Argument names likely to carry the point, in reading order. */
593
- const TELLING = [
594
- "query",
595
- "command",
596
- "prompt",
597
- "url",
598
- "path",
599
- "pattern",
600
- "request",
601
- "question",
602
- "title",
603
- "name",
604
- "task",
605
- "text",
606
- ] as const;
607
-
608
- const stringAt = (args: Record<string, unknown>, key: string) => {
609
- const value = args[key];
610
- return typeof value === "string" && value.trim() ? value : null;
611
- };
612
-
613
- /** Model-written label on bash. null when absent; the command is then the label. */
614
- function labelOf(args: Record<string, unknown>): string | null {
615
- const note = stringAt(args, "description");
616
- return note ? clip(note, LINE_MAX) : null;
617
- }
618
-
619
- /**
620
- * One tool call as one line, for the screen. No per-tool summary table: the
621
- * label is model-written (bash `description`), other tools use the first
622
- * telling argument, else the argument shape.
623
- */
624
- export function toolLine(name: string, input: unknown): string {
625
- const args = (input ?? {}) as Record<string, unknown>;
626
- if (typeof args !== "object" || Array.isArray(args)) {
627
- return clip(String(input ?? ""), LINE_MAX);
628
- }
629
- if (name === TOOL_NAMES.bash) {
630
- return labelOf(args) ?? clip(String(args.command ?? ""), LINE_MAX);
631
- }
632
- if (name === TOOL_NAMES.tool_call || name === TOOL_NAMES.tool_search) {
633
- // For MCP the call is inside the args. Server name alone would collapse
634
- // twenty different calls into one line, and a resumed bot would repeat them
635
- const called = Array.isArray(args.tools)
636
- ? args.tools.map(String).join(", ")
637
- : String(args.tool ?? "");
638
- const passed =
639
- args.args && typeof args.args === "object"
640
- ? JSON.stringify(args.args)
641
- : "";
642
- return clip(
643
- [String(args.server ?? ""), called, passed].filter(Boolean).join(" "),
644
- LINE_MAX,
645
- );
646
- }
647
- for (const key of TELLING) {
648
- const value = stringAt(args, key);
649
- if (value) return clip(value, LINE_MAX);
650
- }
651
- for (const key of Object.keys(args)) {
652
- const value = stringAt(args, key);
653
- if (value) return clip(value, LINE_MAX);
654
- }
655
- const keys = Object.keys(args);
656
- return keys.length ? clip(JSON.stringify(args), LINE_MAX) : "";
657
- }
658
-
659
- /** Result lines carried in the list, enough for a glance. */
660
- const RESULT_LINES = 4;
661
-
662
- /** Cap for the full result, so one log file cannot flatten the browser. */
663
- const FULL_RESULT_LINES = 400;
664
-
665
- /** Everything one tool returned; only when the screen asks for more. The list carries a few lines (linesOf). */
666
- export async function readToolResult(
667
- taskId: string,
668
- toolCallId: string,
669
- ): Promise<ResultPart[] | null> {
670
- // Usually a tool row, but results of provider-run tools (search) sit inside
671
- // an assistant row, so both are scanned
672
- const rows = await database
673
- .select({ role: taskMessageTable.role, content: taskMessageTable.content })
674
- .from(taskMessageTable)
675
- .where(
676
- and(
677
- eq(taskMessageTable.taskId, taskId),
678
- inArray(taskMessageTable.role, ["tool", "assistant"]),
679
- ),
680
- );
681
- for (const row of rows) {
682
- if (typeof row.content === "string") continue;
683
- for (const part of row.content as ToolContent) {
684
- if (part.type === "tool-result" && part.toolCallId === toolCallId) {
685
- return resultParts(part.output, FULL_RESULT_LINES);
686
- }
687
- }
688
- }
689
- return null;
690
- }
691
-
692
- /** Said to a resumed run after why it stopped. The screen shows only the why (linesOf). */
693
- const IN_FLIGHT =
694
- "Anything that was under way — a command, a page loading, a download — may not have finished: check before relying on it, then carry on.";
695
-
696
- /** The thread line a stop the app made leaves (bot.runner parkTask). */
697
- export const stopNote = (why: string) => `${why} ${IN_FLIGHT}`;
698
-
699
- type StoredMessage = typeof taskMessageTable.$inferSelect;
700
-
701
- /**
702
- * One stored message as screen lines. seq 0 is the request and is drawn from the
703
- * row instead, so it yields nothing. Tool calls aimed at the user or another bot
704
- * get their own kinds because the screen draws them as speech. `owner` is the
705
- * task's bot, the addressee of an ask_back line.
706
- */
707
- function linesOf(message: StoredMessage, owner: string): TaskLine[] {
708
- const base = {
709
- seq: message.seq,
710
- bot: message.bot,
711
- parent: message.parent,
712
- at: message.createdAt,
713
- };
714
- const id = (index: number) => `${message.id}-${index}`;
715
- const content = message.content;
716
-
717
- if (message.role === "user") {
718
- if (message.seq === 0) return [];
719
- const text = typeof content === "string" ? content : textOf(content);
720
- if (!text) return [];
721
- // The app's own lines, never the user's words. `compact` alone marks a
722
- // compaction: rows written before `note` existed carry only that.
723
- if (message.compact) return [{ ...base, id: id(0), kind: "note", text }];
724
- if (message.note) {
725
- const why = text.endsWith(IN_FLIGHT)
726
- ? text.slice(0, -IN_FLIGHT.length).trimEnd()
727
- : text;
728
- return [{ ...base, id: id(0), kind: "stop", text: why }];
729
- }
730
- // Tagged with who said it for the bot (bot.schema tagSpeaker); the screen draws the words
731
- return [{ ...base, id: id(0), kind: "user", text: untagSpeaker(text) }];
732
- }
733
-
734
- if (message.role === "assistant") {
735
- const content = message.content as AssistantContent;
736
- if (typeof content === "string") {
737
- return content.trim()
738
- ? [{ ...base, id: id(0), kind: "text", text: content.trim() }]
739
- : [];
740
- }
741
- const lines: TaskLine[] = [];
742
- content.forEach((part, index) => {
743
- if (part.type === "text") {
744
- const text = part.text.trim();
745
- if (text) lines.push({ ...base, id: id(index), kind: "text", text });
746
- return;
747
- }
748
- // Result of a provider-run tool (search) arrives inside the same message
749
- if (part.type === "tool-result") {
750
- lines.push(resultLine(base, id(index), part));
751
- return;
752
- }
753
- if (part.type !== "tool-call") return;
754
- const args = (part.input ?? {}) as Record<string, unknown>;
755
- if (part.toolName === TOOL_NAMES.ask_thursday) {
756
- lines.push({
757
- ...base,
758
- id: id(index),
759
- kind: "waiting",
760
- callId: part.toolCallId,
761
- question: String(args.question ?? ""),
762
- options: optionsOf(args.options),
763
- });
764
- } else if (isAnswerCall(part.toolName)) {
765
- // The answer is a tool call but draws as text: it is the last thing said
766
- // in the thread, and taskFromRow promotes it to the result line
767
- const text = String(args.result ?? "").trim();
768
- if (text) lines.push({ ...base, id: id(index), kind: "text", text });
769
- } else if (part.toolName === TOOL_NAMES.ask_bot) {
770
- lines.push({
771
- ...base,
772
- id: id(index),
773
- kind: "ask",
774
- callId: part.toolCallId,
775
- to: String(args.bot ?? ""),
776
- text: String(args.request ?? ""),
777
- });
778
- } else if (part.toolName === TOOL_NAMES.ask_back) {
779
- // Borrowed bot asking its borrower; the addressee is not in the args
780
- lines.push({
781
- ...base,
782
- id: id(index),
783
- kind: "ask",
784
- callId: part.toolCallId,
785
- to: owner,
786
- text: String(args.question ?? ""),
787
- });
788
- } else if (part.toolName === TOOL_NAMES.bash) {
789
- // Shell line: the command is the body, the model-written label sits above it
790
- lines.push({
791
- ...base,
792
- id: id(index),
793
- kind: "tool",
794
- callId: part.toolCallId,
795
- name: part.toolName,
796
- input: clip(String(args.command ?? ""), LINE_MAX),
797
- note: labelOf(args),
798
- });
799
- } else {
800
- lines.push({
801
- ...base,
802
- id: id(index),
803
- kind: "tool",
804
- callId: part.toolCallId,
805
- name: part.toolName,
806
- input: toolLine(part.toolName, args),
807
- // Any tool's model-written `description` is its label
808
- note: labelOf(args),
809
- // File tools open from the screen, so the path also travels unclipped
810
- path:
811
- part.toolName === TOOL_NAMES.write_file
812
- ? (stringAt(args, "path") ?? null)
813
- : null,
814
- });
815
- }
816
- });
817
- return lines;
818
- }
819
-
820
- if (message.role === "tool") {
821
- const lines: TaskLine[] = [];
822
- (message.content as ToolContent).forEach((part, index) => {
823
- if (part.type !== "tool-result") return;
824
- if (isAnswerCall(part.toolName) && answerAccepted(part.output)) {
825
- // An accepted answer's result is only a confirmation; the answer itself
826
- // was drawn from the call. A rejected one is drawn: it explains the next step
827
- return;
828
- }
829
- if (part.toolName === TOOL_NAMES.ask_thursday) {
830
- // The user's answer, returned as the question's result
831
- const text = resultParts(part.output, RESULT_LINES)
832
- .flatMap((result) => (result.type === "text" ? [result.text] : []))
833
- .join("\n");
834
- lines.push({
835
- ...base,
836
- id: id(index),
837
- kind: "user",
838
- text: untagSpeaker(text),
839
- });
840
- } else if (
841
- part.toolName === TOOL_NAMES.ask_bot ||
842
- part.toolName === TOOL_NAMES.ask_back
843
- ) {
844
- // Another bot's answer: result of an ask, or of an ask_back
845
- const text = resultParts(part.output, RESULT_LINES)
846
- .flatMap((result) => (result.type === "text" ? [result.text] : []))
847
- .join("\n");
848
- lines.push({
849
- ...base,
850
- id: id(index),
851
- kind: "ask-result",
852
- callId: part.toolCallId,
853
- text,
854
- });
855
- } else {
856
- lines.push(resultLine(base, id(index), part));
857
- }
858
- });
859
- return lines;
860
- }
861
-
862
- return [];
863
- }
864
-
865
- /** List line for one tool result. Asks for one line extra to know whether it was clipped. Called for tool rows and, for provider-run tools, assistant rows. */
866
- function resultLine(
867
- base: Omit<TaskLine, "id" | "kind">,
868
- id: string,
869
- part: { toolCallId: string; toolName: string; output: unknown },
870
- ): TaskLine {
871
- const peek = resultParts(part.output, RESULT_LINES + 1);
872
- return {
873
- ...base,
874
- id,
875
- kind: "tool-result",
876
- callId: part.toolCallId,
877
- name: part.toolName,
878
- results: peek.slice(0, RESULT_LINES),
879
- more: peek.length > RESULT_LINES,
880
- };
881
- }
882
-
883
- /**
884
- * Options the model gave. Only arrays are read. Some providers serialise the
885
- * array as one string with no separator; that cannot be split back, so the
886
- * schema accepts a string (keeping the call valid) and it becomes an open
887
- * question here rather than a guess.
888
- */
889
- export function optionsOf(value: unknown): string[] {
890
- return Array.isArray(value)
891
- ? value.map((option) => String(option).trim()).filter(Boolean)
892
- : [];
893
- }
894
-
895
- function textOf(parts: Array<{ type: string; text?: string }>): string {
896
- return parts
897
- .flatMap((part) => (part.type === "text" && part.text ? [part.text] : []))
898
- .join("\n")
899
- .trim();
900
- }
901
-
902
- /** Tool output as a few glanceable parts: text becomes lines, images stay images. ai-sdk output shapes first, then our tools' shapes, then raw JSON. */
903
- function resultParts(output: unknown, limit: number): ResultPart[] {
904
- if (output == null) return [];
905
- if (typeof output === "string") return textParts(output, limit);
906
- if (typeof output !== "object") return textParts(String(output), limit);
907
-
908
- const wrapped = output as { type?: unknown; value?: unknown };
909
- switch (wrapped.type) {
910
- case "text":
911
- case "error-text":
912
- return textParts(String(wrapped.value ?? ""), limit);
913
- case "json":
914
- case "error-json":
915
- return resultParts(wrapped.value, limit);
916
- case "execution-denied":
917
- return textParts("Denied.", limit);
918
- case "content": {
919
- if (!Array.isArray(wrapped.value)) return [];
920
- const parts: ResultPart[] = [];
921
- for (const block of wrapped.value as Array<Record<string, unknown>>) {
922
- if (block.type === "text" && typeof block.text === "string") {
923
- parts.push(...textParts(block.text, limit));
924
- continue;
925
- }
926
- const image = imageSrc(block);
927
- if (image) parts.push({ type: "image", src: image });
928
- }
929
- return parts;
930
- }
931
- default:
932
- break;
933
- }
934
-
935
- const record = output as Record<string, unknown>;
936
- if (Array.isArray(record.sources)) {
937
- return (
938
- record.sources
939
- .map((source) => String((source as { title?: string })?.title ?? ""))
940
- // Untitled results would be blank rows; filter after map so slice still fills
941
- .filter(Boolean)
942
- .slice(0, limit)
943
- .map((text) => ({ type: "text" as const, text }))
944
- );
945
- }
946
- if (typeof record.stdout === "string") {
947
- return textParts(record.stdout || String(record.stderr ?? ""), limit);
948
- }
949
- if (typeof record.answer === "string") return textParts(record.answer, limit);
950
- return textParts(JSON.stringify(output), limit);
951
- }
952
-
953
- /** A file block holding an image, as something <img> can show. base64 becomes a data url, urls pass through, anything else is dropped. */
954
- function imageSrc(block: Record<string, unknown>): string | null {
955
- const mediaType = String(block.mediaType ?? "");
956
- if (!mediaType.startsWith("image/")) return null;
957
- const data = block.data as
958
- | string
959
- | { type?: string; data?: unknown; url?: string }
960
- | undefined;
961
- if (typeof data === "string") return `data:${mediaType};base64,${data}`;
962
- if (data?.type === "url" && data.url) return data.url;
963
- if (data?.type === "data" && typeof data.data === "string") {
964
- return `data:${mediaType};base64,${data.data}`;
965
- }
966
- return null;
967
- }
968
-
969
- function textParts(text: string, limit: number): ResultPart[] {
970
- return text
971
- .split("\n")
972
- .map((line) => line.trim())
973
- .filter(Boolean)
974
- .slice(0, limit)
975
- .map((line) => ({ type: "text" as const, text: line }));
976
- }