thursday-agent 0.2.0 → 0.3.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 (535) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +5 -2
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +5 -5
  5. package/.next/routes-manifest.json +24 -6
  6. package/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/server/app/_global-error.html +1 -1
  10. package/.next/server/app/_global-error.rsc +2 -2
  11. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  13. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/server/app/_not-found/page.js +2 -2
  15. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/server/app/_not-found.html +1 -1
  18. package/.next/server/app/_not-found.rsc +14 -14
  19. package/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  20. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
  21. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/.next/server/app/api/artifact/route.js +3 -3
  23. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  24. package/.next/server/app/api/bot/memory/files/route/app-paths-manifest.json +3 -0
  25. package/.next/server/app/api/bot/memory/files/route.js +10 -0
  26. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -0
  27. package/.next/server/app/api/bot/memory/files/route_client-reference-manifest.js +3 -0
  28. package/.next/server/app/api/bot/memory/route/app-paths-manifest.json +3 -0
  29. package/.next/server/app/api/bot/memory/route.js +14 -0
  30. package/.next/server/app/api/bot/{notes → memory}/route.js.nft.json +1 -1
  31. package/.next/server/app/api/bot/memory/route_client-reference-manifest.js +3 -0
  32. package/.next/server/app/api/bot/route.js +6 -6
  33. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  34. package/.next/server/app/api/bot/task/[id]/route.js +8 -8
  35. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +1 -1
  36. package/.next/server/app/api/bot/task/route.js +8 -8
  37. package/.next/server/app/api/bot/task/route.js.nft.json +1 -1
  38. package/.next/server/app/api/config/route.js +5 -5
  39. package/.next/server/app/api/config/route.js.nft.json +1 -1
  40. package/.next/server/app/api/events/route.js +4 -5
  41. package/.next/server/app/api/events/route.js.nft.json +1 -1
  42. package/.next/server/app/api/file/[...path]/route.js +3 -3
  43. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  44. package/.next/server/app/api/llm-model/catalog/route.js +9 -8
  45. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  46. package/.next/server/app/api/llm-model/credits/route/app-paths-manifest.json +3 -0
  47. package/.next/server/app/api/llm-model/credits/route/build-manifest.json +12 -0
  48. package/.next/server/app/api/llm-model/credits/route/server-reference-manifest.json +4 -0
  49. package/.next/server/app/api/llm-model/credits/route.js +16 -0
  50. package/.next/server/app/api/llm-model/credits/route.js.map +5 -0
  51. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -0
  52. package/.next/server/app/api/llm-model/credits/route_client-reference-manifest.js +3 -0
  53. package/.next/server/app/api/llm-model/route.js +10 -8
  54. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  55. package/.next/server/app/api/llm-model/subscription/route/app-paths-manifest.json +3 -0
  56. package/.next/server/app/api/llm-model/subscription/route/build-manifest.json +12 -0
  57. package/.next/server/app/api/llm-model/subscription/route/server-reference-manifest.json +4 -0
  58. package/.next/server/app/api/llm-model/subscription/route.js +15 -0
  59. package/.next/server/app/api/llm-model/subscription/route.js.map +5 -0
  60. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -0
  61. package/.next/server/app/api/llm-model/subscription/route_client-reference-manifest.js +3 -0
  62. package/.next/server/app/api/mcp/[name]/route.js +4 -4
  63. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  64. package/.next/server/app/api/mcp/oauth/callback/route.js +5 -5
  65. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  66. package/.next/server/app/api/mcp/route.js +4 -4
  67. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  68. package/.next/server/app/api/mcp/tools/route.js +4 -4
  69. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  70. package/.next/server/app/api/memory/edit/route/app-paths-manifest.json +3 -0
  71. package/.next/server/app/api/memory/edit/route/build-manifest.json +12 -0
  72. package/.next/server/app/api/memory/edit/route/server-reference-manifest.json +4 -0
  73. package/.next/server/app/api/memory/edit/route.js +24 -0
  74. package/.next/server/app/api/memory/edit/route.js.map +5 -0
  75. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -0
  76. package/.next/server/app/api/memory/{tidy → edit}/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/memory/route.js +6 -7
  78. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  79. package/.next/server/app/api/skills/[source]/[name]/route.js +3 -3
  80. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  81. package/.next/server/app/api/skills/route.js +3 -3
  82. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  83. package/.next/server/app/api/thursday/call/route.js +9 -7
  84. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  85. package/.next/server/app/api/thursday/skills/route.js +9 -7
  86. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  87. package/.next/server/app/api/thursday/tool-call/route.js +17 -15
  88. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  89. package/.next/server/app/api/workspace/route.js +4 -5
  90. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  91. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
  92. package/.next/server/app/artifact/[...path]/page.js +5 -6
  93. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  94. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  95. package/.next/server/app/favicon.ico/route.js +3 -4
  96. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  97. package/.next/server/app/favicon.ico.body +0 -0
  98. package/.next/server/app/page/server-reference-manifest.json +57 -90
  99. package/.next/server/app/page.js +10 -10
  100. package/.next/server/app/page.js.nft.json +1 -1
  101. package/.next/server/app/page_client-reference-manifest.js +1 -1
  102. package/.next/server/app-paths-manifest.json +5 -2
  103. package/.next/server/chunks/[externals]__0dzuk6_._.js +3 -0
  104. package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +3 -0
  105. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +1 -1
  106. package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +3 -0
  107. package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +8 -0
  108. package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +3 -0
  109. package/.next/server/chunks/[root-of-the-server]__0ce8nf8._.js +5 -0
  110. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +3 -0
  111. package/.next/server/chunks/[root-of-the-server]__0j7z0r3._.js +12 -0
  112. package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +8 -0
  113. package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +8 -0
  114. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +3 -0
  115. package/.next/server/chunks/[root-of-the-server]__0pa2n68._.js +3 -0
  116. package/.next/server/chunks/[root-of-the-server]__0q0vvt2._.js +5 -0
  117. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +5 -0
  118. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +5 -0
  119. package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +3 -0
  120. package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +8 -0
  121. package/.next/server/chunks/[root-of-the-server]__15bjnu5._.js +5 -0
  122. package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +8 -0
  123. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +5 -0
  124. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +3 -0
  125. package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +5 -5
  126. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +3 -0
  127. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +3 -0
  128. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +11 -0
  129. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +3 -0
  130. package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +8 -0
  131. package/.next/server/chunks/_0-73of8._.js +5 -5
  132. package/.next/server/chunks/_0-fjql4._.js +26 -0
  133. package/.next/server/chunks/_00xh_q0._.js +27 -0
  134. package/.next/server/chunks/{_0pppbb5._.js → _03kp0jp._.js} +163 -36
  135. package/.next/server/chunks/_051qh8u._.js +3 -0
  136. package/.next/server/chunks/{node_modules_next_04q-o58._.js → _05dla15._.js} +2 -2
  137. package/.next/server/chunks/_05h2cii._.js +1 -1
  138. package/.next/server/chunks/_0c9j6rb._.js +49 -0
  139. package/.next/server/chunks/_0fzqt2y._.js +130 -0
  140. package/.next/server/chunks/{_0vnutv9._.js → _0ioz3nd._.js} +1 -1
  141. package/.next/server/chunks/_0iwfby5._.js +3 -0
  142. package/.next/server/chunks/_0mecv0f._.js +26 -0
  143. package/.next/server/chunks/_0mh8j4m._.js +3 -0
  144. package/.next/server/chunks/_0n74zsf._.js +4 -4
  145. package/.next/server/chunks/_0obojvv._.js +3 -0
  146. package/.next/server/chunks/_0recufk._.js +49 -0
  147. package/.next/server/chunks/_0rnf-6n._.js +4 -4
  148. package/.next/server/chunks/_0sb7tlz._.js +3 -0
  149. package/.next/server/chunks/_0u10wmw._.js +5 -5
  150. package/.next/server/chunks/_0u4aiy2._.js +3 -0
  151. package/.next/server/chunks/_0wp4le3._.js +1 -1
  152. package/.next/server/chunks/_0y5fg-x._.js +1 -1
  153. package/.next/server/chunks/_1230wbx._.js +10 -0
  154. package/.next/server/chunks/_12nheja._.js +3 -0
  155. package/.next/server/chunks/_13510xh._.js +3 -0
  156. package/.next/server/chunks/_15hq89o._.js +1 -1
  157. package/.next/server/chunks/_17l5ygt._.js +49 -0
  158. package/.next/server/chunks/_18-1wcc._.js +5 -5
  159. package/.next/server/chunks/_1_5mnq4._.js +4 -4
  160. package/.next/server/chunks/_1_9mjx-._.js +3 -0
  161. package/.next/server/chunks/_1d0j961._.js +6 -0
  162. package/.next/server/chunks/_1d5zmy8._.js +1 -1
  163. package/.next/server/chunks/_1drgfx4._.js +4 -4
  164. package/.next/server/chunks/_1f46eie._.js +3 -0
  165. package/.next/server/chunks/_1h5_8sk._.js +3 -0
  166. package/.next/server/chunks/_1hdnxb7._.js +3 -0
  167. package/.next/server/chunks/_1j8k_j5._.js +3 -0
  168. package/.next/server/chunks/_1krd9rf._.js +3 -0
  169. package/.next/server/chunks/_1nc0eui._.js +11 -0
  170. package/.next/server/chunks/_1nula3v._.js +3 -0
  171. package/.next/server/chunks/_1pf4qe-._.js +3 -0
  172. package/.next/server/chunks/_1php4eq._.js +1 -1
  173. package/.next/server/chunks/_1qxheoa._.js +3 -0
  174. package/.next/server/chunks/_1x6kd1r._.js +3 -0
  175. package/.next/server/chunks/_1yuv4vp._.js +1 -1
  176. package/.next/server/chunks/_1zjrdag._.js +3 -0
  177. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_files_route_actions_1_xd_8f.js +3 -0
  178. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_route_actions_1a8xfr7.js +3 -0
  179. package/.next/server/chunks/_next-internal_server_app_api_llm-model_credits_route_actions_0v424pb.js +3 -0
  180. package/.next/server/chunks/_next-internal_server_app_api_llm-model_subscription_route_actions_0-udcm5.js +3 -0
  181. package/.next/server/chunks/_next-internal_server_app_api_memory_edit_route_actions_02sfnmr.js +3 -0
  182. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  183. package/.next/server/chunks/features_0rpfxbk._.js +3 -0
  184. package/.next/server/chunks/features_1qf3cei._.js +3 -0
  185. package/.next/server/chunks/features_bot_0zt92oh._.js +3 -0
  186. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +3 -0
  187. package/.next/server/chunks/features_memory_1uqvksn._.js +6 -0
  188. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0a1rd09._.js → node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js} +1 -1
  189. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_06067w6._.js → node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js} +1 -1
  190. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_096ais_._.js → node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js} +1 -1
  191. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_02s3hjt._.js → node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js} +1 -1
  192. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +3 -0
  193. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0tvkfgh._.js → node_modules_consola_dist_chunks_prompt_mjs_1y49572._.js} +1 -1
  194. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  195. package/.next/server/chunks/ssr/{[root-of-the-server]__1qfqvmg._.js → [root-of-the-server]__0_69wqr._.js} +2 -2
  196. package/.next/server/chunks/ssr/[root-of-the-server]__0hg5gib._.js +1 -1
  197. package/.next/server/chunks/ssr/[root-of-the-server]__0i8ie7f._.js +3 -0
  198. package/.next/server/chunks/ssr/{[root-of-the-server]__0jsmmb-._.js → [root-of-the-server]__0mz33a7._.js} +1 -1
  199. package/.next/server/chunks/ssr/[root-of-the-server]__0tbkdlx._.js +3 -0
  200. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +3 -0
  201. package/.next/server/chunks/ssr/{[root-of-the-server]__0f6s48x._.js → [root-of-the-server]__0xpcv9w._.js} +3 -3
  202. package/.next/server/chunks/ssr/[root-of-the-server]__0xtssj3._.js +1 -1
  203. package/.next/server/chunks/ssr/[root-of-the-server]__0zkv7z_._.js +3 -0
  204. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +57 -0
  205. package/.next/server/chunks/ssr/[root-of-the-server]__15_uhip._.js +3 -0
  206. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  207. package/.next/server/chunks/ssr/{[root-of-the-server]__0m1b5ky._.js → [root-of-the-server]__1cyjywu._.js} +1 -1
  208. package/.next/server/chunks/ssr/[root-of-the-server]__1eh7hid._.js +3 -0
  209. package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +43 -0
  210. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
  211. package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +4 -0
  212. package/.next/server/chunks/ssr/[root-of-the-server]__1pduf5n._.js +3 -0
  213. package/.next/server/chunks/ssr/{_1mznrxk._.js → _001_ms1._.js} +3 -3
  214. package/.next/server/chunks/ssr/_01_6m32._.js +3 -0
  215. package/.next/server/chunks/ssr/_01n3o0m._.js +3 -0
  216. package/.next/server/chunks/ssr/_07uchnc._.js +3 -0
  217. package/.next/server/chunks/ssr/_0ap2fzn._.js +3 -0
  218. package/.next/server/chunks/ssr/_0c-ql2m._.js +3 -0
  219. package/.next/server/chunks/ssr/_0h42fze._.js +3 -0
  220. package/.next/server/chunks/ssr/_0h7zdni._.js +1 -1
  221. package/.next/server/chunks/ssr/_0i_6q1w._.js +41 -0
  222. package/.next/server/chunks/ssr/_0kbkmar._.js +3 -0
  223. package/.next/server/chunks/ssr/{_077-g6s._.js → _0mb8zc8._.js} +3 -3
  224. package/.next/server/chunks/ssr/_0mo2w06._.js +3 -0
  225. package/.next/server/chunks/ssr/{_13punpm._.js → _0q0zan6._.js} +2 -2
  226. package/.next/server/chunks/ssr/{_040sk32._.js → _0u2jv_x._.js} +76 -82
  227. package/.next/server/chunks/ssr/_0y0tiht._.js +4 -0
  228. package/.next/server/chunks/ssr/_0zhoc3r._.js +3 -0
  229. package/.next/server/chunks/ssr/_1-teee5._.js +3 -3
  230. package/.next/server/chunks/ssr/_13fke0x._.js +3 -0
  231. package/.next/server/chunks/ssr/{_1lip4th._.js → _13z3f85._.js} +2 -2
  232. package/.next/server/chunks/ssr/_14_lw10._.js +3 -0
  233. package/.next/server/chunks/ssr/_15j2_8f._.js +3 -0
  234. package/.next/server/chunks/ssr/{_09ja_w1._.js → _1eoqg_g._.js} +2 -2
  235. package/.next/server/chunks/ssr/_1sji22n._.js +3 -0
  236. package/.next/server/chunks/ssr/_1spzm8z._.js +3 -0
  237. package/.next/server/chunks/ssr/{_0x_nu5e._.js → _1vi_uo7._.js} +2 -2
  238. package/.next/server/chunks/ssr/_1vyd1ji._.js +1 -1
  239. package/.next/server/chunks/ssr/{_1m3bsfr._.js → _1xvgn77._.js} +2 -2
  240. package/.next/server/chunks/ssr/_20kd_n0._.js +42 -0
  241. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +3 -0
  242. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  243. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  244. package/.next/server/chunks/ssr/lib_date-like_ts_02is0pw._.js +3 -0
  245. package/.next/server/chunks/ssr/{node_modules_18_dk7_._.js → node_modules_063xwpp._.js} +1 -1
  246. package/.next/server/chunks/ssr/{node_modules_01qnv-a._.js → node_modules_0bvraul._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_0n1kj4p._.js → node_modules_0eu1va6._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_0kl7-tn._.js → node_modules_0h50b8n._.js} +1 -1
  249. package/.next/server/chunks/ssr/{node_modules_0_n241r._.js → node_modules_0h5hnr1._.js} +1 -1
  250. package/.next/server/chunks/ssr/{node_modules_0lrjk5t._.js → node_modules_0h7u60n._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_0ndvxub._.js → node_modules_0lm7_vm._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_13r44jq._.js → node_modules_0mwym0g._.js} +1 -1
  253. package/.next/server/chunks/ssr/{node_modules_17lrt3y._.js → node_modules_0rjg6t1._.js} +1 -1
  254. package/.next/server/chunks/ssr/node_modules_0x3-ply._.js +3 -0
  255. package/.next/server/chunks/ssr/{node_modules_004qlr4._.js → node_modules_0y_cded._.js} +1 -1
  256. package/.next/server/chunks/ssr/{node_modules_0kxz4gt._.js → node_modules_0z5tsu8._.js} +1 -1
  257. package/.next/server/chunks/ssr/{node_modules_0iz1rzd._.js → node_modules_0zp9r92._.js} +1 -1
  258. package/.next/server/chunks/ssr/{node_modules_19dp7ko._.js → node_modules_1-hc6uv._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_1q0p85z._.js → node_modules_113tz0l._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_1toafc-._.js → node_modules_124bue5._.js} +1 -1
  261. package/.next/server/chunks/ssr/node_modules_17bwo43._.js +55 -0
  262. package/.next/server/chunks/ssr/{node_modules_08d8bke._.js → node_modules_1_n3ztw._.js} +1 -1
  263. package/.next/server/chunks/ssr/{node_modules_1dwguw_._.js → node_modules_1bc7gu8._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_20yebtj._.js → node_modules_1bgb6-f._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_1n5ygqe._.js → node_modules_1h4a4pp._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_04n7mjs._.js → node_modules_1i7u1ia._.js} +1 -1
  267. package/.next/server/chunks/ssr/{node_modules_1hn8z1f._.js → node_modules_1juq3hs._.js} +1 -1
  268. package/.next/server/chunks/ssr/{node_modules_1xyd7ov._.js → node_modules_1l0qtdu._.js} +1 -1
  269. package/.next/server/chunks/ssr/{node_modules_0m93zeg._.js → node_modules_1t9cyee._.js} +1 -1
  270. package/.next/server/chunks/ssr/{node_modules_09xhur7._.js → node_modules_1uuj9x1._.js} +1 -1
  271. package/.next/server/chunks/ssr/{node_modules_1hd-5tv._.js → node_modules_1vqb6po._.js} +1 -1
  272. package/.next/server/chunks/ssr/{node_modules_1zu988w._.js → node_modules_1xx28h1._.js} +1 -1
  273. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0m9a4y0._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0d3skpl._.js} +1 -1
  274. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_13w_wy9._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0i44kk5._.js} +1 -1
  275. package/.next/server/chunks/ssr/node_modules_@vercel_oidc_dist_0qe30a_._.js +3 -0
  276. package/.next/server/chunks/ssr/{node_modules_next_dist_0w6mzq5._.js → node_modules_next_dist_0drixxt._.js} +4 -4
  277. package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +2 -2
  278. package/.next/server/instrumentation.js +1 -1
  279. package/.next/server/middleware-build-manifest.js +3 -3
  280. package/.next/server/pages/404.html +1 -1
  281. package/.next/server/pages/500.html +1 -1
  282. package/.next/server/server-reference-manifest.js +1 -1
  283. package/.next/server/server-reference-manifest.json +58 -91
  284. package/.next/static/chunks/{31ttnjt6g35a0.js → 0ev4hyghq0mbb.js} +1 -1
  285. package/.next/static/chunks/0r5qcctujhxli.js +1 -0
  286. package/.next/static/chunks/0tmgrnlje14-s.js +3 -0
  287. package/.next/static/chunks/0x79tx04dxbpp.js +1 -0
  288. package/.next/static/chunks/0xzgvc0fkdb6t.js +1 -0
  289. package/.next/static/chunks/10teww7wt-f6h.js +1 -0
  290. package/.next/static/chunks/14hgtsjg-kael.css +1 -0
  291. package/.next/static/chunks/17donp69y4do7.js +40 -0
  292. package/.next/static/chunks/{3_h9txt3tq8t8.js → 1dkjg87pxk0n9.js} +1 -1
  293. package/.next/static/chunks/1ekc7ul556kbl.js +1 -0
  294. package/.next/static/chunks/{3ard_noqapnw1.js → 1grhjo7a5a0_-.js} +1 -1
  295. package/.next/static/chunks/1kq8h8wi_e0bc.js +53 -0
  296. package/.next/static/chunks/1okqiww3pnwka.js +1 -0
  297. package/.next/static/chunks/26-pr2c9ro222.js +1 -0
  298. package/.next/static/chunks/{18vhba44l1fc9.js → 280t0_e99i276.js} +1 -1
  299. package/.next/static/chunks/28cizcdaabd4h.js +1 -0
  300. package/.next/static/chunks/2a0k6jlq0_v1u.js +2 -0
  301. package/.next/static/chunks/2fzs9fm8yarvq.js +1 -0
  302. package/.next/static/chunks/2h0sd2vumhb15.js +1 -0
  303. package/.next/static/chunks/2hw2f6zmt7fmt.js +1 -0
  304. package/.next/static/chunks/2t4vhi3m8ahya.js +1 -0
  305. package/.next/static/chunks/2tigdtz3dpcy8.js +1 -0
  306. package/.next/static/chunks/3111pj5wnjgos.js +1 -0
  307. package/.next/static/chunks/{07kl352c-lvcz.js → 3agpgkwaa321p.js} +1 -1
  308. package/.next/static/chunks/3cfi_q6d_wtci.js +1 -0
  309. package/.next/static/chunks/3ok9_x74rip3v.js +1 -0
  310. package/.next/static/chunks/3xk7yqgomx7yq.js +1 -0
  311. package/.next/static/chunks/3xpbkl66ssib5.js +38 -0
  312. package/.next/static/media/favicon.37o1pjldwi2uc.ico +0 -0
  313. package/README.md +6 -4
  314. package/app/api/bot/memory/files/route.ts +14 -0
  315. package/app/api/bot/memory/route.ts +5 -0
  316. package/app/api/events/app-event.ts +3 -5
  317. package/app/api/llm-model/credits/route.ts +11 -0
  318. package/app/api/llm-model/route.ts +6 -1
  319. package/app/api/llm-model/subscription/route.ts +11 -0
  320. package/app/api/memory/edit/route.ts +7 -0
  321. package/app/api/memory/route.ts +21 -0
  322. package/app/api/query-key.ts +19 -4
  323. package/bin/thursday.mjs +3 -0
  324. package/components/ui/shiny-text.tsx +48 -134
  325. package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/migration.sql +24 -34
  326. package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/snapshot.json +71 -145
  327. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +1 -0
  328. package/database/migrations/{20260909063821_bitter_tenebrous → 20260911030320_opposite_jack_power}/snapshot.json +57 -184
  329. package/features/ai/chatgpt.ts +617 -0
  330. package/features/ai/components/chatgpt-sign-in.tsx +66 -0
  331. package/features/ai/components/model-picker.tsx +17 -1
  332. package/features/ai/components/provider-icon.tsx +1 -0
  333. package/features/ai/load-tools.ts +58 -42
  334. package/features/ai/model.schema.ts +232 -34
  335. package/features/ai/model.ts +169 -24
  336. package/features/ai/prompts/bot.prompt.ts +156 -65
  337. package/features/ai/prompts/memory-edit.prompt.ts +33 -0
  338. package/features/ai/prompts/prompt-helper.ts +45 -26
  339. package/features/ai/prompts/thursday.prompt.ts +40 -17
  340. package/features/ai/tools/bot.tool.ts +35 -52
  341. package/features/ai/tools/connected.ts +17 -4
  342. package/features/ai/tools/memory.tool.ts +133 -72
  343. package/features/ai/tools/search.tool.ts +136 -47
  344. package/features/ai/tools/tool-name.ts +2 -5
  345. package/features/ai/tools/workspace.tool.ts +2 -1
  346. package/features/bot/bot.action.ts +8 -18
  347. package/features/bot/bot.memory.ts +89 -0
  348. package/features/bot/bot.query.ts +37 -57
  349. package/features/bot/bot.run.ts +507 -241
  350. package/features/bot/bot.runner.ts +410 -114
  351. package/features/bot/bot.schema.ts +79 -19
  352. package/features/bot/bot.seed.ts +89 -16
  353. package/features/bot/components/bot-mark.tsx +122 -20
  354. package/features/bot/components/bot-room.tsx +159 -130
  355. package/features/bot/components/bot-setting.tsx +790 -402
  356. package/features/bot/components/bot-tool.tsx +2 -6
  357. package/features/bot/components/mark-palette.tsx +54 -0
  358. package/features/bot/components/path-chips.tsx +1 -1
  359. package/features/bot/components/task-badge.tsx +26 -6
  360. package/features/bot/components/task-reply.tsx +22 -33
  361. package/features/bot/components/task-setting.tsx +20 -17
  362. package/features/bot/task.query.ts +215 -28
  363. package/features/bot/task.store.ts +53 -9
  364. package/features/config/components/config-setting.tsx +265 -34
  365. package/features/config/components/models-badge.tsx +42 -0
  366. package/features/config/config.action.ts +12 -0
  367. package/features/config/config.const.ts +38 -2
  368. package/features/connectors/mcp.manager.ts +10 -2
  369. package/features/intro/components/intro.tsx +47 -46
  370. package/features/memory/components/memory-edit.tsx +338 -0
  371. package/features/memory/components/memory-setting.tsx +75 -77
  372. package/features/memory/memory.action.ts +3 -43
  373. package/features/memory/memory.edit.ts +87 -0
  374. package/features/memory/memory.query.ts +24 -42
  375. package/features/memory/memory.schema.ts +29 -106
  376. package/features/settings/components/settings.tsx +2 -0
  377. package/features/settings/settings.alert.ts +3 -1
  378. package/features/thursday/components/ascii-orb.tsx +106 -90
  379. package/features/thursday/components/boot.tsx +7 -0
  380. package/features/thursday/components/call-log.tsx +219 -92
  381. package/features/thursday/components/face.tsx +6 -4
  382. package/features/thursday/components/tab-state.tsx +97 -0
  383. package/features/thursday/components/thursday-mark.tsx +4 -1
  384. package/features/thursday/components/thursday-setting.tsx +17 -47
  385. package/features/thursday/components/thursday.tsx +208 -95
  386. package/features/thursday/thursday.action.ts +12 -17
  387. package/features/thursday/thursday.query.ts +61 -70
  388. package/features/thursday/thursday.schema.ts +20 -7
  389. package/features/thursday/tool-line.ts +85 -11
  390. package/features/thursday/use-thursday.ts +86 -59
  391. package/features/workspace/components/file-view.tsx +4 -2
  392. package/features/workspace/workspace.ts +110 -26
  393. package/lib/limits.ts +1 -1
  394. package/lib/oauth-page.ts +27 -0
  395. package/lib/realtime/openai.ts +2 -2
  396. package/lib/realtime/realtime.protocol.ts +1 -1
  397. package/lib/realtime/realtime.tap.ts +122 -0
  398. package/lib/sandbox.ts +59 -36
  399. package/package.json +1 -1
  400. package/skills/browser/SKILL.md +55 -34
  401. package/.next/server/app/api/bot/notes/route/app-paths-manifest.json +0 -3
  402. package/.next/server/app/api/bot/notes/route.js +0 -14
  403. package/.next/server/app/api/bot/notes/route_client-reference-manifest.js +0 -3
  404. package/.next/server/app/api/memory/tidy/route/app-paths-manifest.json +0 -3
  405. package/.next/server/app/api/memory/tidy/route.js +0 -22
  406. package/.next/server/app/api/memory/tidy/route.js.nft.json +0 -1
  407. package/.next/server/chunks/0d-b_next_dist_server_app-render_after-task-async-storage_external_0-exn7p.js +0 -3
  408. package/.next/server/chunks/[root-of-the-server]__0-npkh_._.js +0 -3
  409. package/.next/server/chunks/[root-of-the-server]__005var5._.js +0 -3
  410. package/.next/server/chunks/[root-of-the-server]__019dx9f._.js +0 -5
  411. package/.next/server/chunks/[root-of-the-server]__02_2sm-._.js +0 -5
  412. package/.next/server/chunks/[root-of-the-server]__04_8spk._.js +0 -3
  413. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +0 -3
  414. package/.next/server/chunks/[root-of-the-server]__06t77t4._.js +0 -11
  415. package/.next/server/chunks/[root-of-the-server]__0bed6hu._.js +0 -8
  416. package/.next/server/chunks/[root-of-the-server]__0cro2dz._.js +0 -5
  417. package/.next/server/chunks/[root-of-the-server]__0dupqt7._.js +0 -5
  418. package/.next/server/chunks/[root-of-the-server]__0emr6go._.js +0 -3
  419. package/.next/server/chunks/[root-of-the-server]__0le4d-p._.js +0 -3
  420. package/.next/server/chunks/[root-of-the-server]__0m8ywyo._.js +0 -10
  421. package/.next/server/chunks/[root-of-the-server]__0nfuugi._.js +0 -5
  422. package/.next/server/chunks/[root-of-the-server]__0p32jfz._.js +0 -12
  423. package/.next/server/chunks/[root-of-the-server]__0phdgco._.js +0 -8
  424. package/.next/server/chunks/[root-of-the-server]__0wvgrsl._.js +0 -3
  425. package/.next/server/chunks/[root-of-the-server]__10qshki._.js +0 -3
  426. package/.next/server/chunks/[root-of-the-server]__11j52t0._.js +0 -5
  427. package/.next/server/chunks/[root-of-the-server]__1692zrv._.js +0 -3
  428. package/.next/server/chunks/[root-of-the-server]__16thabu._.js +0 -3
  429. package/.next/server/chunks/[root-of-the-server]__173nhwf._.js +0 -8
  430. package/.next/server/chunks/[root-of-the-server]__1_aoyr9._.js +0 -3
  431. package/.next/server/chunks/[root-of-the-server]__1bn73ih._.js +0 -10
  432. package/.next/server/chunks/[root-of-the-server]__1bqhuh9._.js +0 -8
  433. package/.next/server/chunks/[root-of-the-server]__1cqizfq._.js +0 -5
  434. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +0 -3
  435. package/.next/server/chunks/[root-of-the-server]__1fboj2j._.js +0 -3
  436. package/.next/server/chunks/[root-of-the-server]__1lr7j9t._.js +0 -5
  437. package/.next/server/chunks/[root-of-the-server]__1oli73c._.js +0 -3
  438. package/.next/server/chunks/[root-of-the-server]__1txedx6._.js +0 -8
  439. package/.next/server/chunks/[root-of-the-server]__1untqv8._.js +0 -5
  440. package/.next/server/chunks/[root-of-the-server]__1zgpz1w._.js +0 -3
  441. package/.next/server/chunks/_00_584r._.js +0 -293
  442. package/.next/server/chunks/_012yhfm._.js +0 -39
  443. package/.next/server/chunks/_06mxlgn._.js +0 -3
  444. package/.next/server/chunks/_07rtlxv._.js +0 -3
  445. package/.next/server/chunks/_0a351g7._.js +0 -6
  446. package/.next/server/chunks/_0kjjmag._.js +0 -3
  447. package/.next/server/chunks/_0nn99o2._.js +0 -3
  448. package/.next/server/chunks/_0zuzmt_._.js +0 -39
  449. package/.next/server/chunks/_106co2o._.js +0 -3
  450. package/.next/server/chunks/_12bbv5i._.js +0 -100
  451. package/.next/server/chunks/_15q1pig._.js +0 -3
  452. package/.next/server/chunks/_19wg5yn._.js +0 -138
  453. package/.next/server/chunks/_1bt95p9._.js +0 -55
  454. package/.next/server/chunks/_1cbk7ms._.js +0 -26
  455. package/.next/server/chunks/_1drv2et._.js +0 -40
  456. package/.next/server/chunks/_1ic3bew._.js +0 -5
  457. package/.next/server/chunks/_1mxn_lb._.js +0 -3
  458. package/.next/server/chunks/_1rysr-r._.js +0 -10
  459. package/.next/server/chunks/_1u3rwbr._.js +0 -3
  460. package/.next/server/chunks/_1x7p319._.js +0 -6
  461. package/.next/server/chunks/_next-internal_server_app_api_bot_notes_route_actions_0qcsyu7.js +0 -3
  462. package/.next/server/chunks/_next-internal_server_app_api_memory_tidy_route_actions_0_cfuom.js +0 -3
  463. package/.next/server/chunks/features_bot_task_query_ts_11xuzl3._.js +0 -3
  464. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js +0 -3
  465. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0vorg6w._.js +0 -3
  466. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1tpvamf._.js +0 -3
  467. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vmaq9f._.js +0 -3
  468. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1y9-wcr._.js +0 -3
  469. package/.next/server/chunks/ssr/[externals]_node_crypto_1kn79-7._.js +0 -3
  470. package/.next/server/chunks/ssr/[root-of-the-server]__0iuoa-r._.js +0 -3
  471. package/.next/server/chunks/ssr/[root-of-the-server]__0un-erv._.js +0 -4
  472. package/.next/server/chunks/ssr/[root-of-the-server]__1-mnhyd._.js +0 -92
  473. package/.next/server/chunks/ssr/[root-of-the-server]__1bww500._.js +0 -3
  474. package/.next/server/chunks/ssr/[root-of-the-server]__1vcdast._.js +0 -3
  475. package/.next/server/chunks/ssr/[root-of-the-server]__1xwnu-h._.js +0 -3
  476. package/.next/server/chunks/ssr/_0-mc7ro._.js +0 -3
  477. package/.next/server/chunks/ssr/_01p5r6-._.js +0 -3
  478. package/.next/server/chunks/ssr/_03webdr._.js +0 -3
  479. package/.next/server/chunks/ssr/_09-0k3z._.js +0 -3
  480. package/.next/server/chunks/ssr/_0f_b_9s._.js +0 -3
  481. package/.next/server/chunks/ssr/_0fafgvl._.js +0 -3
  482. package/.next/server/chunks/ssr/_0sf1isi._.js +0 -3
  483. package/.next/server/chunks/ssr/_0su6_08._.js +0 -3
  484. package/.next/server/chunks/ssr/_0ti51xc._.js +0 -3
  485. package/.next/server/chunks/ssr/_0w5bgak._.js +0 -3
  486. package/.next/server/chunks/ssr/_0y84qo6._.js +0 -3
  487. package/.next/server/chunks/ssr/_1ciyoo3._.js +0 -3
  488. package/.next/server/chunks/ssr/_1e-dgz0._.js +0 -4
  489. package/.next/server/chunks/ssr/_1fq7zgb._.js +0 -3
  490. package/.next/server/chunks/ssr/_1g6l4uj._.js +0 -3
  491. package/.next/server/chunks/ssr/_1ruzehw._.js +0 -3
  492. package/.next/server/chunks/ssr/features_bot_components_bot-setting_tsx_01ajft6._.js +0 -4
  493. package/.next/server/chunks/ssr/features_config_components_14jqgy4._.js +0 -3
  494. package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +0 -4
  495. package/.next/server/chunks/ssr/node_modules_zod_v4_classic_external_15fmmz3.js +0 -55
  496. package/.next/static/chunks/05b6nx_o3_f_n.js +0 -1
  497. package/.next/static/chunks/0dmns-gi0raa4.js +0 -1
  498. package/.next/static/chunks/0f9sq-7q_yxyl.js +0 -1
  499. package/.next/static/chunks/0oc4_xoia77dg.css +0 -1
  500. package/.next/static/chunks/0pheo8m3a-rzi.js +0 -1
  501. package/.next/static/chunks/19i8h2t-5evjx.js +0 -1
  502. package/.next/static/chunks/1c5fcj473025q.js +0 -1
  503. package/.next/static/chunks/1pi_hbmjw-f-z.js +0 -1
  504. package/.next/static/chunks/1twt6k09vg4np.js +0 -1
  505. package/.next/static/chunks/1ytnip8wdng93.js +0 -1
  506. package/.next/static/chunks/28gotuisldmom.js +0 -1
  507. package/.next/static/chunks/2998p0y7k1c8z.js +0 -3
  508. package/.next/static/chunks/29gyb3nubj51j.js +0 -53
  509. package/.next/static/chunks/2l233xfycjpd8.js +0 -1
  510. package/.next/static/chunks/2p5n7pa3c40t-.js +0 -2
  511. package/.next/static/chunks/2ru1q132af7h7.js +0 -1
  512. package/.next/static/chunks/2t8wqycwg3y04.js +0 -2
  513. package/.next/static/chunks/2uxum7qbyeyxd.js +0 -1
  514. package/.next/static/chunks/32z_ypgtchw48.js +0 -1
  515. package/.next/static/chunks/33pyjb3xd1iez.js +0 -1
  516. package/.next/static/chunks/3omud5xunrk1f.js +0 -1
  517. package/.next/static/chunks/42dnrkbph9e-1.js +0 -1
  518. package/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
  519. package/database/migrations/20260909063821_bitter_tenebrous/migration.sql +0 -1
  520. package/features/ai/prompts/memory-tidy.prompt.ts +0 -129
  521. package/features/ai/tools/tidy.tool.ts +0 -22
  522. package/features/bot/bot.notes.ts +0 -120
  523. package/features/memory/components/memory-tidy.tsx +0 -395
  524. package/features/memory/memory.tidy.ts +0 -332
  525. package/features/memory/tidy.query.ts +0 -135
  526. package/features/thursday/use-call-title.ts +0 -31
  527. /package/.next/server/app/api/bot/{notes → memory/files}/route/build-manifest.json +0 -0
  528. /package/.next/server/app/api/bot/{notes → memory/files}/route/server-reference-manifest.json +0 -0
  529. /package/.next/server/app/api/bot/{notes → memory/files}/route.js.map +0 -0
  530. /package/.next/server/app/api/{memory/tidy → bot/memory}/route/build-manifest.json +0 -0
  531. /package/.next/server/app/api/{memory/tidy → bot/memory}/route/server-reference-manifest.json +0 -0
  532. /package/.next/server/app/api/{memory/tidy → bot/memory}/route.js.map +0 -0
  533. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → x1cCqY0kWpR_VcYx_lWO5}/_buildManifest.js +0 -0
  534. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → x1cCqY0kWpR_VcYx_lWO5}/_clientMiddlewareManifest.js +0 -0
  535. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → x1cCqY0kWpR_VcYx_lWO5}/_ssgManifest.js +0 -0
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import { formatDistanceToNowStrict } from "date-fns";
3
4
  import {
4
5
  AudioLines,
5
6
  Captions,
@@ -7,7 +8,9 @@ import {
7
8
  ChevronRight,
8
9
  Clapperboard,
9
10
  Image as ImageIcon,
11
+ KeyRound,
10
12
  type LucideIcon,
13
+ Search,
11
14
  TriangleAlert,
12
15
  } from "lucide-react";
13
16
  import { useState } from "react";
@@ -15,12 +18,17 @@ import { queryKey } from "@/app/api/query-key";
15
18
  import { Button } from "@/components/ui/button";
16
19
  import { Input } from "@/components/ui/input";
17
20
  import { notify } from "@/components/ui/notify";
21
+ import { Skeleton } from "@/components/ui/skeleton";
22
+ import { ChatGptSignIn } from "@/features/ai/components/chatgpt-sign-in";
18
23
  import { ModelPicker } from "@/features/ai/components/model-picker";
19
24
  import { ProviderIcon } from "@/features/ai/components/provider-icon";
20
25
  import {
26
+ type AiProvider,
27
+ type GatewayCredits,
21
28
  type MediaKind,
22
29
  parseMediaModel,
23
30
  parseTextModel,
31
+ type SubscriptionUsage,
24
32
  type TextModelProviderId,
25
33
  } from "@/features/ai/model.schema";
26
34
  import { BotsMark } from "@/features/bot/components/bot-mark";
@@ -34,6 +42,7 @@ import {
34
42
  type ConfigEntry,
35
43
  type ConfigGroup,
36
44
  type ConfigStatus,
45
+ EXA_API_KEY,
37
46
  groupSatisfied,
38
47
  isConfigSet,
39
48
  } from "@/features/config/config.const";
@@ -43,6 +52,7 @@ import {
43
52
  SettingError,
44
53
  SettingGroup,
45
54
  SettingItems,
55
+ SettingNote,
46
56
  SettingRailNote,
47
57
  SettingScreen,
48
58
  SettingSkeleton,
@@ -56,6 +66,9 @@ export function ConfigSetting() {
56
66
  return <ConfigGroups section="keys" />;
57
67
  }
58
68
 
69
+ /** A key that is not a provider's still wears a mark, or its row is a hole in the column. */
70
+ const KEY_MARKS: Record<string, LucideIcon> = { [EXA_API_KEY]: Search };
71
+
59
72
  /** One mark per studio kind, drawn as the output (transcription is captions, not a mic). */
60
73
  const KIND_MARKS: Record<MediaKind, LucideIcon> = {
61
74
  image: ImageIcon,
@@ -175,46 +188,164 @@ function KeyRow({
175
188
  /** Its group must have a key and has none, so this row is waiting on the user. */
176
189
  needed: boolean;
177
190
  }) {
191
+ const credits = useGatewayCredits(entry, set);
192
+ const usage = useSubscriptionUsage(entry, set);
193
+ const plan = useSignInPlan(entry, set);
194
+ const state = usage.data
195
+ ? usageState(usage.data)
196
+ : keyState(set, needed, credits.data, entry.signIn);
197
+
178
198
  return (
179
199
  <button
180
200
  type="button"
181
- onClick={() => openConfigDialog(entry, set)}
201
+ onClick={() =>
202
+ entry.signIn ? openSignInDialog(entry) : openConfigDialog(entry, set)
203
+ }
182
204
  className="group flex w-full items-center gap-3 p-4 text-left outline-none transition-colors hover:bg-muted/50 focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:ring-inset"
183
205
  >
184
- {entry.provider && (
185
- <span className="grid size-8 shrink-0 place-items-center rounded-lg bg-muted/60">
186
- <ProviderIcon provider={entry.provider} className="size-4" />
187
- </span>
188
- )}
206
+ <span className="grid size-8 shrink-0 place-items-center rounded-lg bg-muted/60">
207
+ <KeyMark entry={entry} />
208
+ </span>
189
209
  <span className="min-w-0 flex-1 space-y-0.5">
190
210
  <span className="block truncate text-sm font-medium">
191
211
  {entry.label}
192
212
  </span>
193
213
  <span className="block truncate font-mono text-xs text-muted-foreground">
194
- {entry.key}
214
+ {/* A sign-in's config key is nothing to read; the plan it is on is */}
215
+ {entry.signIn
216
+ ? set
217
+ ? usageLine(usage.data, plan)
218
+ : "sign in with your account"
219
+ : entry.key}
195
220
  </span>
196
221
  </span>
197
222
 
198
- <span
199
- className={cn(
200
- "flex shrink-0 items-center gap-1.5 font-mono text-xs",
201
- set
202
- ? "text-muted-foreground"
203
- : needed
204
- ? WAITING_INK
205
- : "text-muted-foreground/60",
206
- )}
207
- >
208
- {set && <Check className="size-3" />}
209
- {!set && needed && <TriangleAlert className="size-3" />}
210
- {set ? "Set" : needed ? "Needed" : "Not set"}
211
- </span>
223
+ {credits.isLoading || usage.isLoading ? (
224
+ // Only this end waits, so the row keeps its shape while the gateway or the plan answers
225
+ <Skeleton className="h-3 w-20 shrink-0" />
226
+ ) : (
227
+ <span
228
+ className={cn(
229
+ "flex shrink-0 items-center gap-1.5 font-mono text-xs",
230
+ state.ink,
231
+ )}
232
+ >
233
+ {state.warn ? (
234
+ <TriangleAlert className="size-3" />
235
+ ) : (
236
+ set && <Check className="size-3" />
237
+ )}
238
+ {state.text}
239
+ </span>
240
+ )}
212
241
 
213
242
  <ChevronRight className="size-4 shrink-0 text-muted-foreground/60 transition-colors group-hover:text-foreground" />
214
243
  </button>
215
244
  );
216
245
  }
217
246
 
247
+ /** US dollars, as the gateway bills. */
248
+ const USD = new Intl.NumberFormat("en-US", {
249
+ style: "currency",
250
+ currency: "USD",
251
+ });
252
+
253
+ /**
254
+ * What a key says at the end of its row. A key only knows whether it is set, except the
255
+ * gateway's, which also says what is left on it: amber waits on a top-up, red is a refusal.
256
+ */
257
+ function keyState(
258
+ set: boolean,
259
+ needed: boolean,
260
+ credits: GatewayCredits | null | undefined,
261
+ signIn?: true,
262
+ ): { text: string; ink: string; warn: boolean } {
263
+ if (!set)
264
+ return needed
265
+ ? { text: "Needed", ink: WAITING_INK, warn: true }
266
+ : {
267
+ text: signIn ? "Signed out" : "Not set",
268
+ ink: "text-muted-foreground/60",
269
+ warn: false,
270
+ };
271
+ if (!credits)
272
+ return {
273
+ text: signIn ? "Signed in" : "Set",
274
+ ink: "text-muted-foreground",
275
+ warn: false,
276
+ };
277
+ if ("refused" in credits)
278
+ return { text: "Key refused", ink: "text-destructive", warn: true };
279
+ return {
280
+ text: `${USD.format(credits.balance)} left`,
281
+ ink: credits.low ? WAITING_INK : "text-muted-foreground",
282
+ warn: credits.low,
283
+ };
284
+ }
285
+
286
+ /** What is left on the gateway key (ai/model readGatewayCredits); any other key reads nothing. */
287
+ function useGatewayCredits(entry: ConfigEntry, set: boolean) {
288
+ return useServerRoute<GatewayCredits | null>(
289
+ set && entry.provider === "vercel-ai-gateway"
290
+ ? queryKey.gatewayCredits
291
+ : null,
292
+ );
293
+ }
294
+
295
+ /** The plan a signed-in account is on (llm-model route); a key row reads nothing. */
296
+ function useSignInPlan(entry: ConfigEntry, set: boolean) {
297
+ const { data } = useServerRoute<AiProvider[]>(
298
+ set && entry.signIn ? queryKey.llmModel : null,
299
+ );
300
+ return data?.find((provider) => provider.id === entry.provider)?.plan ?? null;
301
+ }
302
+
303
+ /** How much of the subscription's plan is used (ai/chatgpt readChatGptUsage); a key row reads nothing. */
304
+ function useSubscriptionUsage(entry: ConfigEntry, set: boolean) {
305
+ return useServerRoute<SubscriptionUsage | null>(
306
+ set && entry.signIn ? queryKey.subscriptionUsage : null,
307
+ );
308
+ }
309
+
310
+ /**
311
+ * What a subscription says at the end of its row: the share of its tightest window used. Amber
312
+ * once it is nearly or wholly spent, because the jobs on it are about to wait for the reset; red
313
+ * is a sign-in the plan refused.
314
+ */
315
+ function usageState(usage: SubscriptionUsage): {
316
+ text: string;
317
+ ink: string;
318
+ warn: boolean;
319
+ } {
320
+ if ("refused" in usage)
321
+ return { text: "Sign-in refused", ink: "text-destructive", warn: true };
322
+ return {
323
+ text: usage.spent ? "Limit reached" : `${usage.usedPercent}% used`,
324
+ ink: usage.high ? WAITING_INK : "text-muted-foreground",
325
+ warn: usage.high,
326
+ };
327
+ }
328
+
329
+ /** A signed-in row's second line: the plan as the backend names it now, and when its window frees up. */
330
+ function usageLine(
331
+ usage: SubscriptionUsage | null | undefined,
332
+ plan: string | null,
333
+ ): string {
334
+ const live = usage && !("refused" in usage) ? usage : null;
335
+ const name = `${live?.plan ?? plan ?? "unknown"} plan`;
336
+ return live?.resetsAt
337
+ ? `${name} · resets in ${formatDistanceToNowStrict(new Date(live.resetsAt))}`
338
+ : name;
339
+ }
340
+
341
+ /** Whose key it is, or what it buys when it belongs to no provider. */
342
+ function KeyMark({ entry }: { entry: ConfigEntry }) {
343
+ if (entry.provider)
344
+ return <ProviderIcon provider={entry.provider} className="size-4" />;
345
+ const Mark = KEY_MARKS[entry.key] ?? KeyRound;
346
+ return <Mark className="size-4 text-muted-foreground" />;
347
+ }
348
+
218
349
  /**
219
350
  * A choice, not a secret. Unset is normal, so the row says what runs
220
351
  * automatically. The value sits under the label rather than across the row:
@@ -438,6 +569,91 @@ function ChoiceDialog({
438
569
  );
439
570
  }
440
571
 
572
+ function openSignInDialog(entry: ConfigEntry) {
573
+ return notify.component({
574
+ className: "sm:max-w-md",
575
+ renderer: ({ close }) => <SignInDialog entry={entry} onDone={close} />,
576
+ });
577
+ }
578
+
579
+ /**
580
+ * An account instead of a key. Read live: the sign-in finishes in a window of its own, and the
581
+ * `config` signal it raises (use-thursday) is what turns this dialog to signed in.
582
+ */
583
+ function SignInDialog({
584
+ entry,
585
+ onDone,
586
+ }: {
587
+ entry: ConfigEntry;
588
+ onDone: () => void;
589
+ }) {
590
+ const { data } = useServerRoute<ConfigStatus[]>(queryKey.config);
591
+ const signedIn = isConfigSet(data, entry.key);
592
+ const plan = useSignInPlan(entry, signedIn);
593
+ const usage = useSubscriptionUsage(entry, signedIn);
594
+ const state = usage.data ? usageState(usage.data) : null;
595
+ const [signOut, signingOut] = useServerAction(removeConfigAction, {
596
+ okMessage: `Signed out of ${entry.label}`,
597
+ onOk: () => {
598
+ revalidate(queryKey.config);
599
+ revalidate(queryKey.llmModel);
600
+ onDone();
601
+ },
602
+ });
603
+
604
+ return (
605
+ <SettingDialogContent
606
+ title={entry.label}
607
+ description={
608
+ signedIn ? (
609
+ <>
610
+ Signed in ·{" "}
611
+ <span className="font-mono">{usageLine(usage.data, plan)}</span>
612
+ {state && (
613
+ <>
614
+ {" · "}
615
+ <span className={cn("font-mono", state.ink)}>{state.text}</span>
616
+ </>
617
+ )}
618
+ </>
619
+ ) : (
620
+ "Sign in with your ChatGPT account instead of a key"
621
+ )
622
+ }
623
+ footer={
624
+ <>
625
+ {signedIn && (
626
+ <Button
627
+ variant="ghost"
628
+ loading={signingOut}
629
+ onClick={() => signOut(entry.key)}
630
+ >
631
+ Sign out
632
+ </Button>
633
+ )}
634
+ <Button variant="ghost" onClick={onDone}>
635
+ {signedIn ? "Close" : "Cancel"}
636
+ </Button>
637
+ {!signedIn && <ChatGptSignIn />}
638
+ </>
639
+ }
640
+ >
641
+ <div className="space-y-2">
642
+ <SettingNote>
643
+ {signedIn
644
+ ? "Bots on this subscription spend your plan's usage, not a key. When it runs out, the job stops and says when it resets."
645
+ : "The sign-in opens in its own window. Approve it there, and this turns to signed in by itself."}
646
+ </SettingNote>
647
+ {usage.data && "refused" in usage.data && (
648
+ <SettingNote className="wrap-break-word text-destructive">
649
+ {usage.data.refused}
650
+ </SettingNote>
651
+ )}
652
+ </div>
653
+ </SettingDialogContent>
654
+ );
655
+ }
656
+
441
657
  function openConfigDialog(entry: ConfigEntry, set: boolean) {
442
658
  return notify.component({
443
659
  className: "sm:max-w-md",
@@ -458,8 +674,10 @@ function ConfigDialog({
458
674
  onDone: () => void;
459
675
  }) {
460
676
  const [value, setValue] = useState("");
677
+ const { data: credits } = useGatewayCredits(entry, set);
678
+ const state = credits ? keyState(set, false, credits) : null;
461
679
 
462
- // The model picker reads hasKey too
680
+ // The model picker reads hasKey too, and the gateway's credits sit under the same url
463
681
  const refresh = () => {
464
682
  revalidate(queryKey.config);
465
683
  revalidate(queryKey.llmModel);
@@ -487,6 +705,12 @@ function ConfigDialog({
487
705
  <>
488
706
  <span className="font-mono">{entry.key}</span>
489
707
  {entry.hint && <> · {entry.hint}</>}
708
+ {state && (
709
+ <>
710
+ {" · "}
711
+ <span className={cn("font-mono", state.ink)}>{state.text}</span>
712
+ </>
713
+ )}
490
714
  </>
491
715
  }
492
716
  footer={
@@ -513,18 +737,25 @@ function ConfigDialog({
513
737
  </>
514
738
  }
515
739
  >
516
- <Input
517
- value={value}
518
- onChange={(event) => setValue(event.target.value)}
519
- onKeyDown={(event) => {
520
- if (event.key === "Enter" && value.trim().length >= 8)
521
- save(entry.key, value);
522
- }}
523
- placeholder={set ? "New value — replaces the current key" : entry.key}
524
- spellCheck={false}
525
- type="password"
526
- autoFocus
527
- />
740
+ <div className="space-y-2">
741
+ <Input
742
+ value={value}
743
+ onChange={(event) => setValue(event.target.value)}
744
+ onKeyDown={(event) => {
745
+ if (event.key === "Enter" && value.trim().length >= 8)
746
+ save(entry.key, value);
747
+ }}
748
+ placeholder={set ? "New value — replaces the current key" : entry.key}
749
+ spellCheck={false}
750
+ type="password"
751
+ autoFocus
752
+ />
753
+ {credits && "refused" in credits && (
754
+ <SettingNote className="wrap-break-word text-destructive">
755
+ {credits.refused}
756
+ </SettingNote>
757
+ )}
758
+ </div>
528
759
  </SettingDialogContent>
529
760
  );
530
761
  }
@@ -0,0 +1,42 @@
1
+ "use client";
2
+
3
+ import { queryKey } from "@/app/api/query-key";
4
+ import {
5
+ CONFIG_GROUPS,
6
+ type ConfigStatus,
7
+ isConfigSet,
8
+ } from "@/features/config/config.const";
9
+ import { NavBadge } from "@/features/settings/components/setting-ui";
10
+ import type { SectionAlert } from "@/features/settings/settings.alert";
11
+ import { useServerRoute } from "@/lib/protocol/use-server-route";
12
+
13
+ /**
14
+ * Every studio model key, read off the catalogue so a new kind counts without a
15
+ * second list. `kind` is the test rather than the section: the bots' default model
16
+ * sits in the same section but resolves when unset (ai/model resolveDefaultModel),
17
+ * and a key with a fallback is not something waiting on anyone.
18
+ */
19
+ const MODEL_KEYS = CONFIG_GROUPS.filter(
20
+ (group) => group.section === "models",
21
+ ).flatMap((group) =>
22
+ group.entries.filter((entry) => entry.kind).map((entry) => entry.key),
23
+ );
24
+
25
+ /**
26
+ * Nobody has picked a studio model at all. Not one unpicked — all of them: each
27
+ * costs money per call, so leaving video or speech off is a choice, and a badge
28
+ * that only clears when every kind is set is a standing demand to spend. What is
29
+ * worth saying once is that the whole drawer exists, because until one is picked
30
+ * a bot that would have drawn just finds out mid-job. Picking any answers it.
31
+ * A loading read reports nothing rather than flashing a dot on every open.
32
+ */
33
+ export function useModelsAlert(): SectionAlert {
34
+ const { data, isLoading } = useServerRoute<ConfigStatus[]>(queryKey.config);
35
+ if (isLoading || !data) return null;
36
+ return MODEL_KEYS.every((key) => !isConfigSet(data, key)) ? "amber" : null;
37
+ }
38
+
39
+ /** A dot, not a count: the number would only ever be "all of them". */
40
+ export function ModelsBadge() {
41
+ return useModelsAlert() ? <NavBadge tone="amber" /> : null;
42
+ }
@@ -1,6 +1,7 @@
1
1
  "use server";
2
2
 
3
3
  import { z } from "zod";
4
+ import { startChatGptSignIn } from "@/features/ai/chatgpt";
4
5
  import { serverAction } from "@/lib/protocol/server-action";
5
6
  import { publicError } from "@/lib/public-error";
6
7
  import { acceptsChoice, CONFIG_ENTRIES, CONFIG_KEYS } from "./config.const";
@@ -17,6 +18,9 @@ export const setConfigAction = serverAction(
17
18
  .parse({ key, value });
18
19
 
19
20
  const entry = CONFIG_ENTRIES[parsed.key];
21
+ if (entry?.signIn) {
22
+ publicError(`${entry.label} takes a sign-in, not a key.`);
23
+ }
20
24
  if (entry?.choices) {
21
25
  if (!acceptsChoice(entry, parsed.value)) {
22
26
  publicError("That is not one of the options.");
@@ -31,3 +35,11 @@ export const setConfigAction = serverAction(
31
35
  export const removeConfigAction = serverAction(async (key: unknown) => {
32
36
  await removeConfig(KeySchema.parse(key));
33
37
  });
38
+
39
+ /**
40
+ * Starts signing in to ChatGPT and returns the page to open (ai/chatgpt). The answer lands on
41
+ * the server, which keeps the sign-in and signals the screen (`config`).
42
+ */
43
+ export const startChatGptSignInAction = serverAction(async () =>
44
+ startChatGptSignIn(),
45
+ );
@@ -29,6 +29,8 @@ export type ConfigEntry = {
29
29
  text?: true;
30
30
  /** Whose key this is; draws the mark in front of the row. */
31
31
  provider?: TextModelProviderId;
32
+ /** Signed in to rather than typed: the row signs in, and the write action takes no value for it. */
33
+ signIn?: true;
32
34
  /** Present means a choice, not a secret: the value may be shown and served. */
33
35
  choices?: ConfigChoice[];
34
36
  /** A studio kind. The value is `provider/model`, picked with the model picker, so ids outside `choices` are accepted. */
@@ -39,7 +41,13 @@ export type ConfigEntry = {
39
41
  * Every group id. A union, not a string, because `isCallable` looks the voice
40
42
  * group up by id and a typo there silently makes the app always callable.
41
43
  */
42
- export const CONFIG_GROUP_IDS = ["voice", "text", "bots", "studio"] as const;
44
+ export const CONFIG_GROUP_IDS = [
45
+ "voice",
46
+ "text",
47
+ "search",
48
+ "bots",
49
+ "studio",
50
+ ] as const;
43
51
  export type ConfigGroupId = (typeof CONFIG_GROUP_IDS)[number];
44
52
 
45
53
  /** The group a call runs on: one of its keys must be set (config.query isCallable). */
@@ -84,6 +92,10 @@ const MEDIA_ENTRY: Record<MediaKind, { label: string; hint: string }> = {
84
92
  },
85
93
  };
86
94
 
95
+ /** "an image model" — how a screen names one that is missing. The article differs by kind. */
96
+ export const mediaModelWords = (kind: MediaKind) =>
97
+ `${kind === "image" ? "an" : "a"} ${kind} model`;
98
+
87
99
  /** Each of these costs real money per call, so none is offered until it is picked (ai/model resolveMediaRef). */
88
100
 
89
101
  const mediaEntry = (kind: MediaKind): ConfigEntry => ({
@@ -100,6 +112,13 @@ const mediaEntry = (kind: MediaKind): ConfigEntry => ({
100
112
  ),
101
113
  });
102
114
 
115
+ /**
116
+ * What a bot searches the web with. Set, every bot searches through Exa in one HTTP call;
117
+ * unset, only a bot whose own model carries a native search has the tool at all — there is
118
+ * no borrowed model to search on (ai/tools/search.tool).
119
+ */
120
+ export const EXA_API_KEY = "EXA_API_KEY";
121
+
103
122
  /** What a bot runs on when it has not picked its own model (bot.schema `provider`/`model`). */
104
123
  export const DEFAULT_MODEL_KEY = "DEFAULT_MODEL";
105
124
 
@@ -140,10 +159,13 @@ export function acceptsChoice(entry: ConfigEntry, value: string): boolean {
140
159
  const isVoiceKey = (provider: { apiKeyName: string }) =>
141
160
  voiceKeys.includes(provider.apiKeyName);
142
161
 
143
- const keyEntry = (provider: (typeof TEXT_MODEL_PROVIDER_LIST)[number]) => ({
162
+ const keyEntry = (
163
+ provider: (typeof TEXT_MODEL_PROVIDER_LIST)[number],
164
+ ): ConfigEntry => ({
144
165
  key: provider.apiKeyName,
145
166
  label: provider.label,
146
167
  provider: provider.id,
168
+ signIn: provider.signIn,
147
169
  });
148
170
 
149
171
  export const CONFIG_GROUPS: ConfigGroup[] = [
@@ -166,6 +188,20 @@ export const CONFIG_GROUPS: ConfigGroup[] = [
166
188
  (provider) => !isVoiceKey(provider),
167
189
  ).map(keyEntry),
168
190
  },
191
+ {
192
+ id: "search",
193
+ title: "search",
194
+ hint: "how bots look things up — one key, or their own model's",
195
+ section: "keys",
196
+ require: "none",
197
+ entries: [
198
+ {
199
+ key: EXA_API_KEY,
200
+ label: "Exa",
201
+ hint: "web search in one call — dashboard.exa.ai",
202
+ },
203
+ ],
204
+ },
169
205
  {
170
206
  id: "bots",
171
207
  title: "Bots",
@@ -221,15 +221,23 @@ export class McpManager {
221
221
  return attempt;
222
222
  }
223
223
 
224
- /** Run a tool, opening or reviving the session if needed. Every call pushes the idle timer back. */
224
+ /**
225
+ * Run a tool, opening or reviving the session if needed. Every call pushes the idle timer back.
226
+ * `signal` is the only bound: the client waits forever when given none.
227
+ */
225
228
  async callTool(
226
229
  name: string,
227
230
  tool: string,
228
231
  args?: Record<string, unknown>,
232
+ signal?: AbortSignal,
229
233
  ): Promise<CallToolResult> {
230
234
  const client = await this.ensureClient(name);
231
235
  try {
232
- const result = await client.callTool({ name: tool, arguments: args });
236
+ const result = await client.callTool({
237
+ name: tool,
238
+ arguments: args,
239
+ options: signal ? { signal } : undefined,
240
+ });
233
241
  this.touch(name);
234
242
  return result;
235
243
  } catch (error) {