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
@@ -11,31 +11,36 @@ import { Button } from "@/components/ui/button";
11
11
  import { Combobox } from "@/components/ui/combobox";
12
12
  import { Input } from "@/components/ui/input";
13
13
  import { notify } from "@/components/ui/notify";
14
+ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
14
15
  import { Segmented } from "@/components/ui/segmented";
16
+ import { Switch } from "@/components/ui/switch";
15
17
  import { Textarea } from "@/components/ui/textarea";
16
18
  import { ASCII_FACE } from "@/config";
17
- import { ProviderIcon } from "@/features/ai/components/provider-icon";
18
19
  import {
19
- type AiProvider,
20
- SPEACH_MODEL_PROVIDER_LIST,
21
- type SpeachModelRef,
22
- } from "@/features/ai/model.schema";
20
+ LIVE_BACKEND_MODELS,
21
+ LIVE_DEFAULTS,
22
+ LIVE_PROVIDER,
23
+ LIVE_REASONING,
24
+ type LiveSettings,
25
+ } from "@/features/ai/live.schema";
26
+ import type { AiProvider } from "@/features/ai/model.schema";
23
27
  import { MarkPalette } from "@/features/bot/components/mark-palette";
24
28
  import { MARK_SHAPES } from "@/features/bot/mark.const";
29
+ import { KEY_MIN, KeyInput } from "@/features/config/components/voice-key";
30
+ import { setConfigAction } from "@/features/config/config.action";
25
31
  import {
26
- SettingChoiceRows,
27
32
  SettingError,
28
33
  SettingGroup,
29
- SettingItems,
30
34
  SettingNote,
31
35
  SettingRailNote,
32
36
  SettingScreen,
33
37
  SettingSkeleton,
34
- SettingToggle,
35
38
  } from "@/features/settings/components/setting-ui";
36
39
  import type { SkillSummary } from "@/features/skills/skills.schema";
37
40
  import { CallHistoryRow } from "@/features/thursday/components/call-log";
38
41
  import { FACES, Face } from "@/features/thursday/components/face";
42
+ import { ThursdayMark } from "@/features/thursday/components/thursday-mark";
43
+ import { VoicePicker } from "@/features/thursday/components/voice-picker";
39
44
  import {
40
45
  ASCII_CHARSETS,
41
46
  type AsciiCharset,
@@ -54,6 +59,7 @@ import {
54
59
  CALL_BACK_MODES,
55
60
  CAPTION_VIEWS,
56
61
  type CallBack,
62
+ CallBackSchema,
57
63
  type CaptionView,
58
64
  type Hotkey,
59
65
  type ThursdayFace,
@@ -69,15 +75,16 @@ import {
69
75
  useHotkeyLabel,
70
76
  } from "@/hooks/use-hotkey";
71
77
  import { COMMON_VALIDATE } from "@/lib/limits";
78
+ import { LIVE_MODEL } from "@/lib/live/live.schema";
72
79
  import { useServerAction } from "@/lib/protocol/use-server-action";
73
80
  import { revalidate, useServerRoute } from "@/lib/protocol/use-server-route";
74
81
  import { cn, WAITING_INK } from "@/lib/utils";
75
82
 
76
83
  /**
77
- * Settings for the call: face, voice provider, captions, wake word, call-back,
78
- * shortcut, skills, reading calls back, instructions. Everything up to the
79
- * shortcut is kept in the browser (thursday.store, face.store); the two after
80
- * it are the server's, because they are read where no browser is.
84
+ * Settings for the call: face, captions, the two models, how a call starts, and
85
+ * its history. Everything but the skills switch is kept in the browser
86
+ * (thursday.store, face.store) and read when a call opens; skills are the
87
+ * server's, because they are read where no browser is.
81
88
  */
82
89
  export function ThursdaySetting() {
83
90
  // local store: no waiting, no revalidation
@@ -94,98 +101,421 @@ export function ThursdaySetting() {
94
101
  if (isLoading) return <SettingSkeleton rows={4} />;
95
102
  if (error) return <SettingError message={error.message} />;
96
103
 
97
- const picked = thursday.model?.provider ?? null;
98
- const hasKey = (name: string) =>
99
- providers.some((entry) => entry.apiKeyName === name && entry.hasKey);
104
+ const hasKey = providers.some(
105
+ (entry) => entry.apiKeyName === LIVE_PROVIDER.apiKeyName && entry.hasKey,
106
+ );
100
107
 
101
108
  return (
102
109
  <SettingScreen
103
110
  footer={
104
111
  <SettingRailNote>
105
- Her prompt is assembled fresh on every call — memory, the roster and
106
- your skills go in.
112
+ Both of her prompts are assembled fresh on every call — memory, the
113
+ roster and your skills go in. Changes here apply from the next call.
107
114
  </SettingRailNote>
108
115
  }
109
116
  >
110
117
  <FacePicker value={face} onChange={setThursdayFace} />
111
118
 
112
- {/* Read, not changed, so it sits at the top */}
113
- <CallHistoryRow />
119
+ <Captions
120
+ value={thursday.captionView}
121
+ onChange={(captionView) => patch({ captionView })}
122
+ />
123
+
124
+ <ModelsSetting
125
+ value={thursday}
126
+ face={face}
127
+ hasKey={hasKey}
128
+ onChange={patch}
129
+ />
130
+
131
+ {/* Every way a call starts other than pressing her face, read at once */}
132
+ <SettingGroup label="Starting a call">
133
+ <Tiles columns={3}>
134
+ <WakeWord
135
+ value={thursday.wake}
136
+ onChange={(wake) => patch({ wake })}
137
+ />
138
+ <Shortcut
139
+ value={thursday.hotkey}
140
+ onChange={(hotkey) => patch({ hotkey })}
141
+ />
142
+ <CallBackPicker
143
+ value={thursday.callBack}
144
+ onChange={(callBack) => patch({ callBack })}
145
+ />
146
+ </Tiles>
147
+ </SettingGroup>
148
+
149
+ <SettingGroup label="History">
150
+ <Tiles columns={2}>
151
+ <CallHistoryRow />
152
+ <ResetHistory />
153
+ </Tiles>
154
+ </SettingGroup>
155
+ </SettingScreen>
156
+ );
157
+ }
114
158
 
115
- <SettingGroup
116
- label="Voice"
117
- note={!picked && "Nothing picked — calls run on whichever key is set."}
159
+ /** Tiles side by side in one bordered card, stacked when the column is narrow. */
160
+ function Tiles({ columns, children }: { columns: 2 | 3; children: ReactNode }) {
161
+ return (
162
+ <div className="@container">
163
+ <div
164
+ className={cn(
165
+ "grid divide-y divide-border/60 overflow-hidden rounded-xl border border-border/60",
166
+ columns === 3
167
+ ? "@3xl:grid-cols-3 @3xl:divide-x @3xl:divide-y-0"
168
+ : "@xl:grid-cols-2 @xl:divide-x @xl:divide-y-0",
169
+ )}
118
170
  >
119
- <SettingItems>
120
- {SPEACH_MODEL_PROVIDER_LIST.map((provider) => (
121
- <ProviderRow
122
- key={provider.id}
123
- provider={provider}
124
- // only the picked provider gets a value; model and voice are that provider's names
125
- value={picked === provider.id ? thursday.model : null}
126
- hasKey={hasKey(provider.apiKeyName)}
127
- onPick={(next) =>
128
- patch({ model: { provider: provider.id, ...next } })
171
+ {children}
172
+ </div>
173
+ </div>
174
+ );
175
+ }
176
+
177
+ /** A tile's first line: what it is, and its switch when it has one. */
178
+ function TileHead({
179
+ label,
180
+ children,
181
+ }: {
182
+ label: string;
183
+ children?: ReactNode;
184
+ }) {
185
+ return (
186
+ <div className="flex min-h-5 items-center gap-3">
187
+ <span className="min-w-0 flex-1 truncate text-sm font-medium">
188
+ {label}
189
+ </span>
190
+ {children}
191
+ </div>
192
+ );
193
+ }
194
+
195
+ /**
196
+ * Both models a call runs on, in one card: the Live voice and the Responses
197
+ * backend that holds her tools (thursday.prompt). They share the OpenAI key, so
198
+ * a missing key is asked for once, above both.
199
+ */
200
+ function ModelsSetting({
201
+ value,
202
+ face,
203
+ hasKey,
204
+ onChange,
205
+ }: {
206
+ value: LiveSettings;
207
+ /** The picker plays a sample through her own face. */
208
+ face: ThursdayFace;
209
+ hasKey: boolean;
210
+ onChange: (change: Partial<LiveSettings>) => void;
211
+ }) {
212
+ return (
213
+ <SettingGroup
214
+ label="Models"
215
+ note="Both run on your OpenAI key. Instructions are saved when you leave the field."
216
+ >
217
+ <div className="@container divide-y divide-border/60 rounded-xl border border-border/60">
218
+ {!hasKey && <KeyRow />}
219
+
220
+ <ModelSection name="Voice" fact="billed by the minute">
221
+ <div className="grid gap-4 @xl:grid-cols-2">
222
+ <ModelBlock label="model">
223
+ {/* Locked: LIVE_MODEL is the only Live model a call opens on */}
224
+ <Combobox
225
+ value={LIVE_MODEL}
226
+ onChange={() => undefined}
227
+ options={[{ value: LIVE_MODEL, label: "GPT-Live 1" }]}
228
+ aria-label="Voice model"
229
+ disabled
230
+ />
231
+ </ModelBlock>
232
+ </div>
233
+
234
+ {/* Its own row: opened, the picker holds her face beside the voices. */}
235
+ <ModelBlock label="voice">
236
+ <VoicePicker
237
+ voice={value.voice}
238
+ face={face}
239
+ onChange={(voice) =>
240
+ onChange({ voice: voice.trim() || LIVE_DEFAULTS.voice })
129
241
  }
130
242
  />
131
- ))}
132
- </SettingItems>
133
- </SettingGroup>
243
+ </ModelBlock>
134
244
 
135
- <Captions
136
- value={thursday.captionView}
137
- onChange={(captionView) => patch({ captionView })}
138
- />
245
+ <ModelBlock label="instructions">
246
+ <PromptField
247
+ value={value.voicePrompt}
248
+ onCommit={(voicePrompt) => onChange({ voicePrompt })}
249
+ placeholder="How to address you, how much to say, what to skip."
250
+ aria-label="Voice instructions"
251
+ />
252
+ </ModelBlock>
253
+ </ModelSection>
139
254
 
140
- <WakeWord value={thursday.wake} onChange={(wake) => patch({ wake })} />
255
+ <ModelSection name="Backend" fact="billed per token">
256
+ <ModelBlock label="model">
257
+ <BackendModelPicker
258
+ value={value.backendModel}
259
+ onChange={(backendModel) => onChange({ backendModel })}
260
+ />
261
+ </ModelBlock>
141
262
 
142
- <CallBackPicker
143
- value={thursday.callBack}
144
- onChange={(callBack) => patch({ callBack })}
145
- />
263
+ {/* Auto omits the parameter, so a model without reasoning still runs */}
264
+ <ModelBlock label="reasoning">
265
+ <Segmented
266
+ aria-label="Reasoning effort"
267
+ className="w-full flex-wrap *:flex-1"
268
+ options={REASONING_OPTIONS}
269
+ value={value.reasoningEffort ?? "auto"}
270
+ onChange={(effort) =>
271
+ onChange({ reasoningEffort: effort === "auto" ? null : effort })
272
+ }
273
+ />
274
+ </ModelBlock>
146
275
 
147
- <Shortcut
148
- value={thursday.hotkey}
149
- onChange={(hotkey) => patch({ hotkey })}
150
- />
276
+ <ModelBlock label="tools">
277
+ <BackendTools
278
+ webSearch={value.webSearch}
279
+ onWebSearch={(webSearch) => onChange({ webSearch })}
280
+ />
281
+ </ModelBlock>
151
282
 
152
- {/* Server-side, unlike everything above it: the tool set is built where a
153
- call opens (ai/load-tools) */}
154
- <SkillsSetting />
283
+ <ModelBlock label="instructions">
284
+ <PromptField
285
+ value={value.backendPrompt}
286
+ onCommit={(backendPrompt) => onChange({ backendPrompt })}
287
+ placeholder="How work should be handed over, what to check first."
288
+ aria-label="Backend instructions"
289
+ />
290
+ </ModelBlock>
291
+ </ModelSection>
292
+ </div>
293
+ </SettingGroup>
294
+ );
295
+ }
155
296
 
156
- <Instructions
157
- value={thursday.systemPrompt ?? ""}
158
- onSave={(systemPrompt) => patch({ systemPrompt })}
297
+ /** One model's half of the card: its name and how it bills, then what to choose. */
298
+ function ModelSection({
299
+ name,
300
+ fact,
301
+ children,
302
+ }: {
303
+ name: string;
304
+ fact: string;
305
+ children: ReactNode;
306
+ }) {
307
+ return (
308
+ <div className="grid gap-4 p-5 @2xl:grid-cols-[8.5rem_minmax(0,1fr)] @2xl:gap-6">
309
+ <span className="space-y-0.5">
310
+ <span className="block text-sm font-medium">{name}</span>
311
+ <span className="block font-mono text-[11px] text-muted-foreground">
312
+ {fact}
313
+ </span>
314
+ </span>
315
+ <div className="min-w-0 space-y-4">{children}</div>
316
+ </div>
317
+ );
318
+ }
319
+
320
+ function ModelBlock({
321
+ label,
322
+ children,
323
+ }: {
324
+ label: string;
325
+ children: ReactNode;
326
+ }) {
327
+ return (
328
+ <div className="min-w-0 space-y-2">
329
+ <span className="block font-mono text-[11px] text-muted-foreground">
330
+ {label}
331
+ </span>
332
+ {children}
333
+ </div>
334
+ );
335
+ }
336
+
337
+ /** No key yet: paste one here, above both models, instead of leaving for Keys. */
338
+ function KeyRow() {
339
+ const [draft, setDraft] = useState("");
340
+ const [save, saving] = useServerAction(setConfigAction, {
341
+ onOk: () => {
342
+ revalidate(queryKey.llmModel);
343
+ revalidate(queryKey.config);
344
+ setDraft("");
345
+ },
346
+ });
347
+ const ready = draft.trim().length >= KEY_MIN;
348
+
349
+ return (
350
+ <div className="space-y-3 p-5">
351
+ <span className="block space-y-0.5">
352
+ <span className={cn("block text-sm font-medium", WAITING_INK)}>
353
+ No OpenAI key
354
+ </span>
355
+ <span className="block text-xs text-muted-foreground">
356
+ Her voice and the backend both run on it
357
+ </span>
358
+ </span>
359
+ <KeyInput
360
+ dense
361
+ provider={LIVE_PROVIDER}
362
+ saved={false}
363
+ value={draft}
364
+ ready={ready}
365
+ saving={saving}
366
+ onValue={setDraft}
367
+ onSubmit={() => ready && save(LIVE_PROVIDER.apiKeyName, draft)}
159
368
  />
369
+ </div>
370
+ );
371
+ }
160
372
 
161
- <ResetHistory />
162
- </SettingScreen>
373
+ /**
374
+ * The recent models as cards, and a field for any other id; the provider says
375
+ * at call time whether it runs. A typed id is saved on Enter or when the field
376
+ * is left, never per keystroke, and clearing it goes back to the default.
377
+ */
378
+ function BackendModelPicker({
379
+ value,
380
+ onChange,
381
+ }: {
382
+ value: string;
383
+ onChange: (model: string) => void;
384
+ }) {
385
+ const listed = LIVE_BACKEND_MODELS.some((model) => model.id === value);
386
+ const other = useDraft(
387
+ listed ? "" : value,
388
+ (next) => onChange(next || LIVE_DEFAULTS.backendModel),
389
+ { min: 0 },
390
+ );
391
+
392
+ return (
393
+ <div className="space-y-2">
394
+ <div
395
+ role="radiogroup"
396
+ aria-label="Backend model"
397
+ className="grid grid-cols-2 gap-2 @3xl:grid-cols-4"
398
+ >
399
+ {LIVE_BACKEND_MODELS.map((model) => {
400
+ const picked = model.id === value;
401
+ return (
402
+ <button
403
+ key={model.id}
404
+ type="button"
405
+ role="radio"
406
+ aria-checked={picked}
407
+ onClick={() => onChange(model.id)}
408
+ className={cn(
409
+ "min-w-0 space-y-0.5 rounded-lg border px-3 py-2.5 text-left outline-none transition-colors focus-visible:ring-3 focus-visible:ring-ring/50",
410
+ picked
411
+ ? "border-foreground bg-muted/40"
412
+ : "border-border/60 hover:bg-muted/50",
413
+ )}
414
+ >
415
+ <span className="flex items-center gap-2">
416
+ <span className="min-w-0 flex-1 truncate text-sm font-medium">
417
+ {model.label}
418
+ </span>
419
+ {picked && <Check className="size-3.5 shrink-0" />}
420
+ </span>
421
+ <span className="block truncate font-mono text-[11px] text-muted-foreground">
422
+ {model.id} · {model.tier}
423
+ </span>
424
+ </button>
425
+ );
426
+ })}
427
+ </div>
428
+
429
+ <Input
430
+ value={other.value}
431
+ onChange={(event) => other.set(event.target.value)}
432
+ onBlur={other.commit}
433
+ onKeyDown={other.onKeyDown}
434
+ placeholder="Other model id"
435
+ aria-label="Other backend model id"
436
+ spellCheck={false}
437
+ className="font-mono text-sm"
438
+ />
439
+ </div>
163
440
  );
164
441
  }
165
442
 
443
+ const REASONING_OPTIONS: readonly {
444
+ value: "auto" | (typeof LIVE_REASONING)[number];
445
+ label: string;
446
+ title: string;
447
+ }[] = [
448
+ { value: "auto", label: "auto", title: "The model's own default" },
449
+ ...LIVE_REASONING.map((effort) => ({
450
+ value: effort,
451
+ label: effort,
452
+ title: `Reasoning effort ${effort}`,
453
+ })),
454
+ ];
455
+
166
456
  /**
167
- * Whether the call is handed `load_skill`. Off by default: reading a skill is a
168
- * page of instructions arriving mid-sentence, and everything a skill describes
169
- * that takes time is a bot's anyway. `SettingToggle`, like Wake and Shortcut.
457
+ * What the backend may reach for. Web search is this browser's setting; the
458
+ * skills switch hands the call `load_skill` and is the server's, because tools
459
+ * are built where no browser is. Off by default: reading a skill is a page of
460
+ * instructions arriving mid-sentence.
170
461
  */
171
- function SkillsSetting() {
172
- const { data } = useServerRoute<boolean>(queryKey.callSkills);
173
- const [setOn] = useServerAction(setCallSkillsAction, {
462
+ function BackendTools({
463
+ webSearch,
464
+ onWebSearch,
465
+ }: {
466
+ webSearch: boolean;
467
+ onWebSearch: (on: boolean) => void;
468
+ }) {
469
+ const { data: skills } = useServerRoute<boolean>(queryKey.callSkills);
470
+ const [setSkills] = useServerAction(setCallSkillsAction, {
174
471
  onOk: () => revalidate(queryKey.callSkills),
175
472
  });
176
473
 
177
474
  return (
178
- <SettingGroup label="Skills">
179
- <SettingToggle
180
- label="Read a skill herself"
181
- description="A skill is how a thing is done here, written down. On, she opens one mid-call and follows it; off, only bots read them."
182
- checked={data ?? false}
183
- disabled={data === undefined}
184
- onChange={(on) => setOn(on)}
185
- >
186
- <InstalledSkills />
187
- </SettingToggle>
188
- </SettingGroup>
475
+ <div className="space-y-2">
476
+ <div className="flex flex-wrap gap-x-7 gap-y-3">
477
+ <InlineSwitch
478
+ label="Search the web"
479
+ checked={webSearch}
480
+ onChange={onWebSearch}
481
+ />
482
+ <InlineSwitch
483
+ label="Read skills herself"
484
+ checked={skills ?? false}
485
+ disabled={skills === undefined}
486
+ onChange={(on) => setSkills(on)}
487
+ />
488
+ </div>
489
+ {webSearch && (
490
+ <SettingNote>
491
+ Each search adds to the backend's OpenAI usage.
492
+ </SettingNote>
493
+ )}
494
+ {skills && <InstalledSkills />}
495
+ </div>
496
+ );
497
+ }
498
+
499
+ function InlineSwitch({
500
+ label,
501
+ checked,
502
+ disabled,
503
+ onChange,
504
+ }: {
505
+ label: string;
506
+ checked: boolean;
507
+ disabled?: boolean;
508
+ onChange: (on: boolean) => void;
509
+ }) {
510
+ return (
511
+ <label className="flex items-center gap-2.5 text-sm">
512
+ <Switch
513
+ checked={checked}
514
+ disabled={disabled}
515
+ onCheckedChange={onChange}
516
+ />
517
+ {label}
518
+ </label>
189
519
  );
190
520
  }
191
521
 
@@ -203,23 +533,49 @@ function InstalledSkills() {
203
533
  );
204
534
  }
205
535
 
536
+ /** Added instructions: a draft while typing, saved when the field is left. */
537
+ function PromptField({
538
+ value,
539
+ onCommit,
540
+ placeholder,
541
+ "aria-label": ariaLabel,
542
+ }: {
543
+ value: string;
544
+ onCommit: (next: string) => void;
545
+ placeholder: string;
546
+ "aria-label": string;
547
+ }) {
548
+ const draft = useDraft(value, onCommit, { min: 0 });
549
+
550
+ return (
551
+ <Textarea
552
+ value={draft.value}
553
+ maxLength={COMMON_VALIDATE.prompt.max}
554
+ onChange={(event) => draft.set(event.target.value)}
555
+ onBlur={draft.commit}
556
+ placeholder={placeholder}
557
+ aria-label={ariaLabel}
558
+ />
559
+ );
560
+ }
561
+
206
562
  /**
207
563
  * Wipes what the app has kept of its own use, in one go: calls, jobs and
208
564
  * memory. The same set `pnpm reset` calls History, so the terminal and this
209
565
  * button agree. Keys, bots and connectors stay.
210
566
  *
211
- * Last group in the section, not in the rail: the rail is on screen the whole
212
- * time a section is open, and the one thing here that cannot be undone should
213
- * be reached by scrolling to it.
567
+ * Last in the section, not in the rail: the rail is on screen the whole time a
568
+ * section is open, and the one thing here that cannot be undone should be
569
+ * reached by scrolling to it.
214
570
  */
215
571
  function ResetHistory() {
216
572
  const [reset, resetting] = useServerAction(resetHistoryAction, {
217
- okMessage: ({ calls, tasks, notes }) =>
218
- `Wiped ${calls} calls, ${tasks} jobs, ${notes} notes`,
573
+ okMessage: ({ calls, threads, notes }) =>
574
+ `Wiped ${calls} calls, ${threads} jobs, ${notes} notes`,
219
575
  onOk: () => {
220
576
  // Prefix match, so every loaded history page goes too.
221
577
  revalidate(queryKey.memory);
222
- revalidate(queryKey.tasks);
578
+ revalidate(queryKey.threads);
223
579
  revalidate(queryKey.callHistory(null));
224
580
  },
225
581
  });
@@ -236,30 +592,28 @@ function ResetHistory() {
236
592
  };
237
593
 
238
594
  return (
239
- <SettingGroup label="Danger zone" note="Keys, bots and connectors stay.">
240
- <SettingItems>
241
- <div className="flex items-center gap-3 p-4">
242
- <span className="grid size-10 shrink-0 place-items-center rounded-lg bg-muted text-muted-foreground">
243
- <TriangleAlert className="size-4" />
244
- </span>
245
- <span className="min-w-0 flex-1 space-y-0.5">
246
- <span className="block text-sm font-medium">Reset history</span>
247
- <span className="block text-xs text-muted-foreground">
248
- Every call, every job and everything she remembers
249
- </span>
250
- </span>
251
- <Button
252
- variant="outline"
253
- size="sm"
254
- loading={resetting}
255
- onClick={confirmReset}
256
- className="shrink-0 text-destructive hover:text-destructive"
257
- >
258
- Reset
259
- </Button>
260
- </div>
261
- </SettingItems>
262
- </SettingGroup>
595
+ <div className="flex min-w-0 items-center gap-3 p-4">
596
+ <span className="grid size-10 shrink-0 place-items-center rounded-lg bg-muted text-muted-foreground">
597
+ <TriangleAlert className="size-4" />
598
+ </span>
599
+ <span className="min-w-0 flex-1 space-y-0.5">
600
+ <span className="block truncate text-sm font-medium">
601
+ Reset history
602
+ </span>
603
+ <span className="block truncate text-xs text-muted-foreground">
604
+ Calls, jobs and memory. Keys and bots stay.
605
+ </span>
606
+ </span>
607
+ <Button
608
+ variant="outline"
609
+ size="sm"
610
+ loading={resetting}
611
+ onClick={confirmReset}
612
+ className="shrink-0 text-destructive hover:text-destructive"
613
+ >
614
+ Reset
615
+ </Button>
616
+ </div>
263
617
  );
264
618
  }
265
619
 
@@ -300,13 +654,18 @@ function FacePicker({
300
654
  </p>
301
655
  </div>
302
656
 
303
- {/* Only the mark takes a color; the orb follows the theme (OrbFace ignores it). */}
657
+ {/* Only the mark takes a color; the orb follows the theme (OrbFace ignores it).
658
+ A paint covers the colour without clearing it; picking a colour takes it off. */}
304
659
  {value.kind === "mark" && (
305
660
  <MarkPalette
306
- color={value.color}
307
- themePicked={!value.color}
308
- onTheme={() => patch({ color: undefined })}
309
- onPick={(color) => patch({ color })}
661
+ color={value.paint ? undefined : value.color}
662
+ themePicked={!value.paint && !value.color}
663
+ onTheme={() => patch({ color: undefined, paint: undefined })}
664
+ onPick={(color) => patch({ color, paint: undefined })}
665
+ paint={value.paint}
666
+ onPaint={(paint) =>
667
+ patch({ paint: value.paint === paint ? undefined : paint })
668
+ }
310
669
  />
311
670
  )}
312
671
 
@@ -430,107 +789,96 @@ function Slider({
430
789
  );
431
790
  }
432
791
 
433
- /**
434
- * One provider row: model and voice unfold only once picked. The model is a
435
- * combobox because the list is open; new ids can be typed.
436
- */
437
- function ProviderRow({
438
- provider,
792
+ const CAPTION_LABEL: Record<CaptionView, { label: string; hint: string }> = {
793
+ center: {
794
+ label: "Her last line",
795
+ hint: "One caption under the mark — only what she said.",
796
+ },
797
+ sides: {
798
+ label: "Last three turns",
799
+ hint: "Hers on the left, yours on the right, beside the mark.",
800
+ },
801
+ };
802
+
803
+ /** How much of the conversation shows while speaking, picked by what it looks like. */
804
+ function Captions({
439
805
  value,
440
- hasKey,
441
- onPick,
806
+ onChange,
442
807
  }: {
443
- provider: (typeof SPEACH_MODEL_PROVIDER_LIST)[number];
444
- /** null unless this provider is the picked one. */
445
- value: SpeachModelRef | null | undefined;
446
- hasKey: boolean;
447
- onPick: (next: Omit<SpeachModelRef, "provider">) => void;
808
+ value: CaptionView;
809
+ onChange: (view: CaptionView) => void;
448
810
  }) {
449
- const picked = Boolean(value);
450
- const voice = value?.voice ?? provider.defaultVoice;
451
- const model = value?.model ?? "";
452
-
453
811
  return (
454
- <div className={cn("p-4", picked && "bg-muted/40")}>
455
- <button
456
- type="button"
457
- disabled={picked}
458
- onClick={() => onPick({ voice: null, model: null })}
459
- className="flex w-full items-center gap-3 text-left outline-none focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-default"
460
- >
461
- <ProviderIcon provider={provider.id} className="size-4 shrink-0" />
462
- <span className="min-w-0 flex-1 space-y-0.5">
463
- <span className="block truncate text-sm font-medium">
464
- {provider.label}
465
- </span>
466
- <span className="block truncate font-mono text-xs text-muted-foreground">
467
- {model || provider.models[0].id}
468
- </span>
469
- </span>
470
-
471
- {!hasKey ? (
472
- <span className="flex shrink-0 items-center gap-1 font-mono text-[11px] text-muted-foreground">
473
- <TriangleAlert className="size-3" />
474
- No key
475
- </span>
476
- ) : (
477
- picked && <Check className="size-4 shrink-0" />
478
- )}
479
- </button>
480
-
481
- {/* Model and voices only matter once this is the one answering */}
482
- {picked && (
483
- <div className="space-y-3 pt-3">
484
- <Combobox
485
- value={model}
486
- onChange={(next) =>
487
- onPick({ voice: value?.voice ?? null, model: next || null })
488
- }
489
- options={provider.models.map((entry) => ({
490
- value: entry.id,
491
- label: entry.label,
492
- hint: entry.id,
493
- }))}
494
- aria-label={`${provider.label} realtime model`}
495
- placeholder={provider.models[0].id}
496
- empty="Not on the list — it still runs"
497
- />
498
-
499
- <div className="flex flex-wrap gap-1.5">
500
- {provider.voices.map((name) => (
812
+ <SettingGroup label="Captions">
813
+ <div className="@container">
814
+ <div
815
+ role="radiogroup"
816
+ aria-label="Captions"
817
+ className="grid gap-3 @xl:grid-cols-2"
818
+ >
819
+ {CAPTION_VIEWS.map((view) => {
820
+ const picked = view === value;
821
+ return (
501
822
  <button
502
- key={name}
823
+ key={view}
503
824
  type="button"
504
- onClick={() =>
505
- onPick({ voice: name, model: value?.model ?? null })
506
- }
825
+ role="radio"
826
+ aria-checked={picked}
827
+ onClick={() => onChange(view)}
507
828
  className={cn(
508
- "rounded-full border px-2.5 py-1 font-mono text-[11px] transition-colors outline-none focus-visible:ring-3 focus-visible:ring-ring/50",
509
- name === voice
510
- ? "border-foreground/40 text-foreground"
511
- : "border-border/60 text-muted-foreground hover:text-foreground",
829
+ "min-w-0 space-y-3 rounded-xl border p-3 text-left outline-none transition-colors focus-visible:ring-3 focus-visible:ring-ring/50",
830
+ picked
831
+ ? "border-foreground"
832
+ : "border-border/60 hover:bg-muted/50",
512
833
  )}
513
834
  >
514
- {name}
835
+ <CaptionSketch view={view} />
836
+ <span className="flex items-center gap-3 px-1 pb-0.5">
837
+ <span className="min-w-0 flex-1 space-y-0.5">
838
+ <span className="block truncate text-sm font-medium">
839
+ {CAPTION_LABEL[view].label}
840
+ </span>
841
+ <span className="block truncate text-xs text-muted-foreground">
842
+ {CAPTION_LABEL[view].hint}
843
+ </span>
844
+ </span>
845
+ {picked && <Check className="size-4 shrink-0" />}
846
+ </span>
515
847
  </button>
516
- ))}
517
- </div>
848
+ );
849
+ })}
518
850
  </div>
519
- )}
520
- </div>
851
+ </div>
852
+ </SettingGroup>
521
853
  );
522
854
  }
523
855
 
524
- const CAPTION_LABEL: Record<CaptionView, { label: string; hint: string }> = {
525
- center: {
526
- label: "Her last line",
527
- hint: "One caption under the mark — only what she said.",
528
- },
529
- sides: {
530
- label: "Last three turns",
531
- hint: "Hers on the left, yours on the right, beside the mark.",
532
- },
533
- };
856
+ /** The call screen in miniature: her mark, and where the words sit. */
857
+ function CaptionSketch({ view }: { view: CaptionView }) {
858
+ const line = "block h-1 max-w-full rounded-full bg-foreground/20";
859
+
860
+ return (
861
+ <span className="flex h-24 items-center justify-center rounded-lg bg-muted">
862
+ {view === "center" ? (
863
+ <span className="flex flex-col items-center gap-2.5">
864
+ <ThursdayMark size={32} />
865
+ <span className={cn(line, "w-28")} />
866
+ </span>
867
+ ) : (
868
+ <span className="grid w-full grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-4 px-6">
869
+ <span className="space-y-1.5">
870
+ <span className={cn(line, "w-24")} />
871
+ <span className={cn(line, "w-16")} />
872
+ </span>
873
+ <ThursdayMark size={32} />
874
+ <span>
875
+ <span className={cn(line, "ml-auto w-20")} />
876
+ </span>
877
+ </span>
878
+ )}
879
+ </span>
880
+ );
881
+ }
534
882
 
535
883
  /** Whether a call may be opened without the user. Modes are in thursday.schema CALL_BACK_MODES. */
536
884
  function CallBackPicker({
@@ -541,23 +889,32 @@ function CallBackPicker({
541
889
  onChange: (mode: CallBack) => void;
542
890
  }) {
543
891
  return (
544
- <SettingGroup
545
- label="Calls you"
546
- note={
547
- value !== "off" &&
548
- "Needs this tab open. A tab that has been silent since it loaded may not be allowed to make a sound — the desktop notification covers that."
549
- }
550
- >
551
- <SettingChoiceRows
552
- options={CALL_BACK_MODES.map((mode) => ({
553
- value: mode,
554
- label: CALL_BACK_LABEL[mode],
555
- hint: CALL_BACK_HINT[mode],
556
- }))}
892
+ <div className="min-w-0 space-y-3 p-4">
893
+ <TileHead label="She calls you" />
894
+ <RadioGroup
895
+ aria-label="She calls you"
557
896
  value={value}
558
- onChange={onChange}
559
- />
560
- </SettingGroup>
897
+ onValueChange={(mode) => onChange(CallBackSchema.parse(mode))}
898
+ className="gap-2.5"
899
+ >
900
+ {CALL_BACK_MODES.map((mode) => (
901
+ <label
902
+ key={mode}
903
+ className="flex min-w-0 items-center gap-2.5 text-sm"
904
+ >
905
+ <RadioGroupItem value={mode} />
906
+ <span className="truncate">{CALL_BACK_LABEL[mode]}</span>
907
+ </label>
908
+ ))}
909
+ </RadioGroup>
910
+ <SettingNote>{CALL_BACK_HINT[value]}</SettingNote>
911
+ {value !== "off" && (
912
+ <SettingNote>
913
+ Needs this tab open. A tab that has been silent since it loaded may
914
+ not be allowed to make a sound — the desktop notification covers that.
915
+ </SettingNote>
916
+ )}
917
+ </div>
561
918
  );
562
919
  }
563
920
 
@@ -568,29 +925,6 @@ const CALL_BACK_HINT: Record<CallBack, string> = {
568
925
  any: "Anything a bot finishes, she opens a line to tell you.",
569
926
  };
570
927
 
571
- /** How much of the conversation shows while speaking. */
572
- function Captions({
573
- value,
574
- onChange,
575
- }: {
576
- value: CaptionView;
577
- onChange: (view: CaptionView) => void;
578
- }) {
579
- return (
580
- <SettingGroup label="Captions">
581
- <SettingChoiceRows
582
- options={CAPTION_VIEWS.map((view) => ({
583
- value: view,
584
- label: CAPTION_LABEL[view].label,
585
- hint: CAPTION_LABEL[view].hint,
586
- }))}
587
- value={value}
588
- onChange={onChange}
589
- />
590
- </SettingGroup>
591
- );
592
- }
593
-
594
928
  /**
595
929
  * Wake word switch and phrase. Enabled means the browser recognizer holds the
596
930
  * mic between calls. Saved on blur, not per keystroke.
@@ -613,32 +947,33 @@ function WakeWord({
613
947
  const terse = draft.value.trim().split(/\s+/).length < 2;
614
948
 
615
949
  return (
616
- <SettingGroup label="Wake">
617
- <SettingToggle
618
- label="Answer to her name"
619
- description="Between calls, the browser listens for the phrase below and picks up when it hears it."
620
- checked={value.enabled}
621
- onChange={(enabled) => onChange({ ...value, enabled })}
622
- >
623
- <div className="space-y-2">
624
- <Input
625
- value={draft.value}
626
- maxLength={WAKE_PHRASE.max}
627
- spellCheck={false}
628
- onChange={(event) => draft.set(event.target.value)}
629
- onBlur={draft.commit}
630
- onKeyDown={draft.onKeyDown}
631
- aria-label="Wake phrase"
632
- className="font-mono text-sm"
633
- />
634
- <SettingNote>
635
- {terse
636
- ? "One word will wake her by accident — say hello first."
637
- : "Heard loosely, in English. Near misses count."}
638
- </SettingNote>
639
- </div>
640
- </SettingToggle>
641
- </SettingGroup>
950
+ <div className="min-w-0 space-y-3 p-4">
951
+ <TileHead label="Wake phrase">
952
+ <Switch
953
+ aria-label="Answer to her name"
954
+ checked={value.enabled}
955
+ onCheckedChange={(enabled) => onChange({ ...value, enabled })}
956
+ />
957
+ </TileHead>
958
+ <Input
959
+ value={draft.value}
960
+ maxLength={WAKE_PHRASE.max}
961
+ spellCheck={false}
962
+ disabled={!value.enabled}
963
+ onChange={(event) => draft.set(event.target.value)}
964
+ onBlur={draft.commit}
965
+ onKeyDown={draft.onKeyDown}
966
+ aria-label="Wake phrase"
967
+ className="font-mono text-sm"
968
+ />
969
+ <SettingNote>
970
+ {!value.enabled
971
+ ? "Between calls, the browser listens for it and picks up."
972
+ : terse
973
+ ? "One word will wake her by accident — say hello first."
974
+ : "Heard loosely, in English. Near misses count."}
975
+ </SettingNote>
976
+ </div>
642
977
  );
643
978
  }
644
979
 
@@ -675,78 +1010,42 @@ function Shortcut({
675
1010
  };
676
1011
 
677
1012
  return (
678
- <SettingGroup label="Shortcut">
679
- <SettingToggle
680
- label="Answer to a key"
681
- description="With this tab in front, the key below starts a call — and ends the one that is running."
682
- checked={value.enabled}
683
- onChange={(enabled) => onChange({ ...value, enabled })}
684
- >
685
- <div className="space-y-2">
686
- <button
687
- type="button"
688
- {...HOTKEY_CAPTURE}
689
- onClick={() => {
690
- setBare(false);
691
- setListening(true);
692
- }}
693
- onBlur={() => setListening(false)}
694
- onKeyDown={listening ? record : undefined}
695
- className={cn(
696
- "w-full rounded-lg border px-3 py-2 font-mono text-sm outline-none transition-colors focus-visible:ring-3 focus-visible:ring-ring/50",
697
- listening
698
- ? "border-foreground/40 text-muted-foreground"
699
- : "border-border/60 hover:bg-muted/50",
700
- )}
701
- >
702
- {listening ? "Press the keys…" : (label ?? "Set a shortcut")}
703
- </button>
704
- <SettingNote>
705
- {bare
706
- ? "Hold Ctrl, Alt or Cmd — a plain key is typing."
707
- : listening
708
- ? "Esc to keep the one you have."
709
- : "Only while this tab has focus. Not while you are typing."}
710
- </SettingNote>
711
- </div>
712
- </SettingToggle>
713
- </SettingGroup>
714
- );
715
- }
716
-
717
- /** Appended to the persona, not replacing it; the voice-assistant rules stay in the server prompt. */
718
- function Instructions({
719
- value,
720
- onSave,
721
- }: {
722
- value: string;
723
- onSave: (systemPrompt: string) => void;
724
- }) {
725
- const [draft, setDraft] = useState(value);
726
-
727
- return (
728
- <SettingGroup
729
- label="Instructions"
730
- right={`${draft.length}/${COMMON_VALIDATE.prompt.max}`}
731
- >
732
- <div className="space-y-3">
733
- <Textarea
734
- value={draft}
735
- maxLength={COMMON_VALIDATE.prompt.max}
736
- onChange={(event) => setDraft(event.target.value)}
737
- placeholder="Anything else she should know before the first word — how to address you, what to skip."
738
- className="min-h-28"
1013
+ <div className="min-w-0 space-y-3 p-4">
1014
+ <TileHead label="Shortcut">
1015
+ <Switch
1016
+ aria-label="Answer to a key"
1017
+ checked={value.enabled}
1018
+ onCheckedChange={(enabled) => onChange({ ...value, enabled })}
739
1019
  />
740
- <div className="flex justify-end">
741
- <Button
742
- size="sm"
743
- disabled={draft === value}
744
- onClick={() => onSave(draft)}
745
- >
746
- Save
747
- </Button>
748
- </div>
749
- </div>
750
- </SettingGroup>
1020
+ </TileHead>
1021
+ <button
1022
+ type="button"
1023
+ {...HOTKEY_CAPTURE}
1024
+ disabled={!value.enabled}
1025
+ onClick={() => {
1026
+ setBare(false);
1027
+ setListening(true);
1028
+ }}
1029
+ onBlur={() => setListening(false)}
1030
+ onKeyDown={listening ? record : undefined}
1031
+ className={cn(
1032
+ "flex h-8 w-full items-center justify-center rounded-lg border px-3 font-mono text-sm outline-none transition-colors focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50",
1033
+ listening
1034
+ ? "border-foreground/40 text-muted-foreground"
1035
+ : "border-border/60 hover:bg-muted/50",
1036
+ )}
1037
+ >
1038
+ {listening ? "Press the keys…" : (label ?? "Set a shortcut")}
1039
+ </button>
1040
+ <SettingNote>
1041
+ {bare
1042
+ ? "Hold Ctrl, Alt or Cmd — a plain key is typing."
1043
+ : listening
1044
+ ? "Esc to keep the one you have."
1045
+ : value.enabled
1046
+ ? "Only while this tab has focus. Not while you are typing."
1047
+ : "Starts a call, and ends the one that is running."}
1048
+ </SettingNote>
1049
+ </div>
751
1050
  );
752
1051
  }