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,14 +1,25 @@
1
1
  import { generateText, type ToolSet, tool } from "ai";
2
2
  import z from "zod";
3
+ import { SEARCH } from "@/config";
3
4
  import type { TextModel } from "@/features/ai/model";
4
5
  import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
6
+ import { EXA_API_KEY } from "@/features/config/config.const";
7
+ import { readConfig } from "@/features/config/config.query";
5
8
  import type { Sandbox } from "@/lib/sandbox";
9
+ import { clip, errorToString } from "@/lib/utils";
6
10
 
7
11
  /**
8
- * Web search as one tool with one name. The provider-native search runs one call down on a
9
- * search-capable model (`resolveSearchModel`), never in the bot's own request: a provider tool
10
- * cannot be handed to another provider's model, names and result shapes differ per provider,
11
- * and Google cannot send its search tool alongside function tools in one request.
12
+ * Web search as one tool with one name, served whichever way this install can.
13
+ *
14
+ * Exa when its key is set: one HTTP call, the pages themselves back. Otherwise the run's own
15
+ * model's native search, one call down on a searcher that sees nothing but the question — a
16
+ * provider tool cannot be handed to another provider's model, names and result shapes differ
17
+ * per provider, and Google cannot send its search tool alongside function tools in one request.
18
+ *
19
+ * A run whose model has no search of its own (the gateway) and no Exa key gets no search tool:
20
+ * it goes to the browser. Borrowing whichever provider had a key meant a second model call on a
21
+ * model nobody picked, which is where the minute-long searches came from — search is one lookup
22
+ * or it is a job, and a job is what the browser already is.
12
23
  */
13
24
 
14
25
  /** System prompt for the model one call down; it sees nothing but the question. */
@@ -17,57 +28,135 @@ what supports it. Say plainly what you could not find or confirm — do not fill
17
28
  the gap with a guess. Every number carries the date you saw it. Be brief: this
18
29
  is read by another model, not by a person.`;
19
30
 
20
- /** How many sources are worth carrying back. Past this it is noise. */
21
- const SOURCE_LIMIT = 8;
31
+ const DESCRIPTION =
32
+ "Search the web and get back what the pages say, with their links. For a fact, a price, a date, what a page says. Not for a page that has to be clicked, filled, or signed into — that is the browser.";
22
33
 
23
- /** Absent when no provider that searches has a key (features/ai/model); the bot goes to the browser instead. */
24
- export const createSearchTool = (
25
- search: TextModel | null,
34
+ const QUERY = z
35
+ .string()
36
+ .describe(
37
+ "What you want to know, as one full question. Put the place and the time in when they matter — the searcher sees nothing but this line.",
38
+ );
39
+
40
+ /** Exa's own endpoint. One POST: the whole point of this path is that it is not a model call. */
41
+ const EXA_URL = "https://api.exa.ai/search";
42
+
43
+ /** One hit as Exa sends it; only the fields that are read back are named. */
44
+ type ExaHit = {
45
+ title?: string | null;
46
+ url?: string | null;
47
+ publishedDate?: string | null;
48
+ text?: string | null;
49
+ };
50
+
51
+ async function exaSearch(
52
+ apiKey: string,
53
+ query: string,
54
+ signal: AbortSignal,
55
+ ): Promise<string> {
56
+ const response = await fetch(EXA_URL, {
57
+ method: "POST",
58
+ signal,
59
+ headers: { "content-type": "application/json", "x-api-key": apiKey },
60
+ body: JSON.stringify({
61
+ query,
62
+ type: "auto",
63
+ numResults: SEARCH.sources,
64
+ contents: {
65
+ text: { maxCharacters: SEARCH.excerptChars },
66
+ // A page Exa has not cached is fetched now, but one slow site does not hold the search
67
+ livecrawl: "fallback",
68
+ livecrawlTimeout: 5_000,
69
+ },
70
+ }),
71
+ });
72
+ // Exa's own words: only it can say whether the key is wrong, spent or rate-limited
73
+ if (!response.ok)
74
+ return `Exa answered ${response.status}: ${clip((await response.text()).trim(), 200)}`;
75
+
76
+ const body = (await response.json()) as { results?: ExaHit[] };
77
+ const hits = body.results ?? [];
78
+ if (!hits.length)
79
+ return "Nothing came back for that. Try other words, or open a page in the browser.";
80
+
81
+ return hits
82
+ .map((hit) => {
83
+ const head = [hit.title?.trim(), hit.url?.trim()]
84
+ .filter(Boolean)
85
+ .join(" — ");
86
+ const date = hit.publishedDate?.slice(0, 10);
87
+ return [date ? `${head} · ${date}` : head, hit.text?.trim()]
88
+ .filter(Boolean)
89
+ .join("\n");
90
+ })
91
+ .join("\n\n");
92
+ }
93
+
94
+ async function askSearcher(
95
+ searcher: { model: TextModel["model"]; tools: ToolSet },
96
+ query: string,
97
+ signal: AbortSignal,
98
+ ): Promise<string> {
99
+ const { text, sources } = await generateText({
100
+ model: searcher.model,
101
+ tools: searcher.tools,
102
+ system: SEARCHER,
103
+ prompt: query,
104
+ abortSignal: signal,
105
+ });
106
+
107
+ const urls = [
108
+ ...new Set(
109
+ sources.flatMap((source) =>
110
+ source.sourceType === "url"
111
+ ? [source.title ? `${source.title} — ${source.url}` : source.url]
112
+ : [],
113
+ ),
114
+ ),
115
+ ].slice(0, SEARCH.sources);
116
+
117
+ return [text.trim(), urls.length ? `Sources:\n${urls.join("\n")}` : ""]
118
+ .filter(Boolean)
119
+ .join("\n\n");
120
+ }
121
+
122
+ /** Absent when there is neither an Exa key nor a run model that searches; the bot goes to the browser instead. */
123
+ export const createSearchTool = async (
124
+ run: TextModel | null | undefined,
26
125
  sandbox: Sandbox,
27
- ): ToolSet => {
28
- if (!search?.searchTools) return {};
29
- const { model, searchTools } = search;
126
+ ): Promise<ToolSet> => {
127
+ const exaKey = await readConfig(EXA_API_KEY);
128
+ // This run's own model, never a borrowed one. A const so the closure below keeps the narrowing
129
+ const native = run?.searchTools
130
+ ? { model: run.model, tools: run.searchTools }
131
+ : null;
132
+
133
+ const search = exaKey
134
+ ? (query: string, signal: AbortSignal) => exaSearch(exaKey, query, signal)
135
+ : native
136
+ ? (query: string, signal: AbortSignal) =>
137
+ askSearcher(native, query, signal)
138
+ : null;
139
+ if (!search) return {};
30
140
 
31
141
  return {
32
142
  [TOOL_NAMES.web_search]: tool({
33
- description:
34
- "Search the web and get back an answer with its sources. For a fact, a price, a date, what a page says. Not for a page that has to be clicked, filled, or signed into — that is the browser.",
35
- inputSchema: z.object({
36
- query: z
37
- .string()
38
- .describe(
39
- "What you want to know, as one full question. Put the place and the time in when they matter — the searcher sees nothing but this line.",
40
- ),
41
- }),
143
+ description: DESCRIPTION,
144
+ inputSchema: z.object({ query: QUERY }),
42
145
  execute: async ({ query }, { abortSignal }) => {
43
- const { text, sources } = await generateText({
44
- model,
45
- tools: searchTools,
46
- system: SEARCHER,
47
- prompt: query,
48
- abortSignal,
146
+ const deadline = AbortSignal.timeout(SEARCH.timeoutMs);
147
+ const signal = abortSignal
148
+ ? AbortSignal.any([abortSignal, deadline])
149
+ : deadline;
150
+
151
+ const answer = await search(query, signal).catch((cause: unknown) => {
152
+ // The job itself was cancelled: that is not a result to hand back
153
+ if (abortSignal?.aborted) throw cause;
154
+ if (deadline.aborted)
155
+ return `The search did not come back in ${SEARCH.timeoutMs / 1000}s. Ask something narrower, or open the page in the browser.`;
156
+ return `Search failed: ${errorToString(cause)}. The browser is the other way in.`;
49
157
  });
50
158
 
51
- const urls = [
52
- ...new Set(
53
- sources.flatMap((source) =>
54
- source.sourceType === "url"
55
- ? [
56
- source.title
57
- ? `${source.title} — ${source.url}`
58
- : source.url,
59
- ]
60
- : [],
61
- ),
62
- ),
63
- ].slice(0, SOURCE_LIMIT);
64
-
65
- return sandbox.fold(
66
- [text.trim(), urls.length ? `Sources:\n${urls.join("\n")}` : ""]
67
- .filter(Boolean)
68
- .join("\n\n"),
69
- "web-search",
70
- );
159
+ return sandbox.fold(answer, "web-search");
71
160
  },
72
161
  }),
73
162
  };
@@ -8,6 +8,7 @@ export const TOOL_NAMES = {
8
8
  memory_remember: "memory_remember",
9
9
  memory_forget: "memory_forget",
10
10
  memory_show: "memory_show",
11
+ memory_conversation: "memory_conversation",
11
12
 
12
13
  bash: "bash",
13
14
  write_file: "write_file",
@@ -24,13 +25,9 @@ export const TOOL_NAMES = {
24
25
  ask_bot: "ask_bot",
25
26
  ask_thursday: "ask_thursday",
26
27
  ask_back: "ask_back",
27
- report: "report",
28
+ answer: "answer",
28
29
 
29
30
  end_call: "end_call",
30
-
31
- tidy_done: "tidy_done",
32
-
33
- update_notes: "update_notes",
34
31
  } as const;
35
32
 
36
33
  /**
@@ -1,9 +1,10 @@
1
1
  import { relative } from "node:path";
2
2
  import { type ToolSet, tool } from "ai";
3
3
  import z from "zod";
4
+ import { EXEC_TIMEOUT_MS } from "@/config";
4
5
  import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
5
6
  import { writeRefusal } from "@/features/workspace/workspace";
6
- import { EXEC_TIMEOUT_MS, type Sandbox } from "@/lib/sandbox";
7
+ import type { Sandbox } from "@/lib/sandbox";
7
8
 
8
9
  /**
9
10
  * Shell access, plus `write_file` for bots: multi-line files through a
@@ -5,12 +5,11 @@ import { textModelProviderSchema } from "@/features/ai/model.schema";
5
5
  import { serverAction } from "@/lib/protocol/server-action";
6
6
  import { publicError } from "@/lib/public-error";
7
7
  import {
8
- clearBotNote,
9
8
  createBot,
10
9
  deleteBot,
11
10
  findBot,
12
11
  updateBot,
13
- writeBotNotesOn,
12
+ writeBotMemoryOn,
14
13
  } from "./bot.query";
15
14
  import {
16
15
  answerTask,
@@ -21,7 +20,7 @@ import {
21
20
  } from "./bot.runner";
22
21
  import { BotFormSchema, botIconSchema } from "./bot.schema";
23
22
  import { findBotSeed, rollSeedColors } from "./bot.seed";
24
- import { markReported, resolveTask } from "./task.query";
23
+ import { markSeen, resolveTask } from "./task.query";
25
24
 
26
25
  export const createBotAction = serverAction(async (input: unknown) => {
27
26
  const form = BotFormSchema.parse(input);
@@ -80,18 +79,9 @@ export const deleteBotAction = serverAction(async (name: string) => {
80
79
  if (!(await deleteBot(name))) publicError("Bot not found");
81
80
  });
82
81
 
83
- /**
84
- * Throws away what a bot wrote about itself. The only human touch on notes:
85
- * they are never edited here, because a line the user typed would come back
86
- * rewritten by the bot's next report.
87
- */
88
- export const clearBotNoteAction = serverAction(async (name: string) => {
89
- await clearBotNote(name);
90
- });
91
-
92
- /** Switched off, no bot writes to its own instructions and none is shown one. What is already written stays. */
93
- export const setBotNotesOnAction = serverAction(async (on: unknown) => {
94
- await writeBotNotesOn(on === true);
82
+ /** Switched off, no bot is shown its own memory. What is already written stays on disk. */
83
+ export const setBotMemoryOnAction = serverAction(async (on: unknown) => {
84
+ await writeBotMemoryOn(on === true);
95
85
  });
96
86
 
97
87
  // Tasks are opened by the `delegate` tool during a call, or here when the user
@@ -142,9 +132,9 @@ export const cancelTaskAction = serverAction(async (ref: string) => {
142
132
  return { id: task.id, label: task.label, status: "cancelled" as const };
143
133
  });
144
134
 
145
- /** Marks tasks as relayed to the call, clearing their inbox dot. Batched because a call opening relays everything pending at once. */
146
- export const markReportedAction = serverAction(async (ids: string[]) => {
147
- await markReported(ids.filter((id) => typeof id === "string" && id));
135
+ /** Marks endings as had by the user: relayed on a call, or on a task list they opened. Batched, since both reach many at once. */
136
+ export const markSeenAction = serverAction(async (ids: string[]) => {
137
+ await markSeen(ids.filter((id) => typeof id === "string" && id));
148
138
  });
149
139
 
150
140
  export const deleteTaskAction = serverAction(async (id: string) => {
@@ -0,0 +1,89 @@
1
+ import { open, readdir, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { BOT_MEMORY_LISTED } from "@/config";
4
+ import { botFolder, WORKSPACE } from "@/features/workspace/workspace";
5
+ import type { BotMemory, BotMemoryFile } from "./bot.schema";
6
+
7
+ /**
8
+ * A bot's own memory: files it keeps in its folder, one topic each, written and read with
9
+ * its own shell. The disk is the only index — a file's first line is its listing line — so
10
+ * keeping something is one write, and no list can fall out of step with the files.
11
+ */
12
+
13
+ /** Workspace-relative, the way a prompt names it (config PATHS.bots). */
14
+ export const botMemoryFolder = (bot: string): string =>
15
+ `${botFolder(bot)}/memory`;
16
+
17
+ /** Enough of a file to find its first line in; the rest is the bot's to open. */
18
+ const HEAD_BYTES = 1024;
19
+
20
+ /**
21
+ * Newest first. `limit` is how many are read for their first line: the prompt lists
22
+ * BOT_MEMORY_LISTED, the bot's page (Settings > Bots) as many as a Workspace folder shows.
23
+ */
24
+ export async function listBotMemory(
25
+ bot: string,
26
+ limit = BOT_MEMORY_LISTED,
27
+ ): Promise<BotMemory> {
28
+ const folder = botMemoryFolder(bot);
29
+ const dir = join(WORKSPACE, folder);
30
+ const names = await readdir(dir).catch(() => []);
31
+ const found = await Promise.all(
32
+ names
33
+ .filter((name) => !name.startsWith("."))
34
+ .map(async (name) => {
35
+ const info = await stat(join(dir, name)).catch(() => null);
36
+ return info?.isFile()
37
+ ? { name, changed: info.mtimeMs, bytes: info.size }
38
+ : null;
39
+ }),
40
+ );
41
+ const files = found
42
+ .filter((file) => file !== null)
43
+ .sort((a, b) => b.changed - a.changed);
44
+ const entries = await Promise.all(
45
+ files.slice(0, limit).map(
46
+ async ({ name, changed, bytes }): Promise<BotMemoryFile> => ({
47
+ file: name,
48
+ path: `${folder}/${name}`,
49
+ line: await firstLine(join(dir, name)),
50
+ at: new Date(changed),
51
+ bytes,
52
+ }),
53
+ ),
54
+ );
55
+ return { folder, entries, total: files.length };
56
+ }
57
+
58
+ /**
59
+ * The line a file is listed by: its first, without a heading's `#`. A file that opens with
60
+ * frontmatter anyway — a shape models are trained on — is listed by its `description`, or by
61
+ * the first line after it.
62
+ */
63
+ async function firstLine(path: string): Promise<string> {
64
+ const handle = await open(path, "r").catch(() => null);
65
+ if (!handle) return "";
66
+ try {
67
+ const head = Buffer.alloc(HEAD_BYTES);
68
+ const { bytesRead } = await handle.read(head, 0, HEAD_BYTES, 0);
69
+ const lines = head
70
+ .toString("utf8", 0, bytesRead)
71
+ .split("\n")
72
+ .map((line) => line.trim())
73
+ .filter(Boolean);
74
+ if (lines[0] === "---") {
75
+ const said = lines.find((line) => line.startsWith("description:"));
76
+ if (said) {
77
+ return said
78
+ .slice("description:".length)
79
+ .trim()
80
+ .replace(/^["']|["']$/g, "");
81
+ }
82
+ const end = lines.indexOf("---", 1);
83
+ return end > 0 ? (lines[end + 1] ?? "").replace(/^#+\s*/, "") : "";
84
+ }
85
+ return (lines[0] ?? "").replace(/^#+\s*/, "");
86
+ } finally {
87
+ await handle.close();
88
+ }
89
+ }
@@ -1,9 +1,7 @@
1
1
  import { eq, inArray, sql } from "drizzle-orm";
2
- import { BOT_NOTES } from "@/config";
3
2
  import { database } from "@/database/db";
4
3
  import {
5
4
  botMcpToolTable,
6
- botNoteTable,
7
5
  botTable,
8
6
  mcpToolTable,
9
7
  taskTable,
@@ -11,11 +9,11 @@ import {
11
9
  import type { TextModelProviderId } from "@/features/ai/model.schema";
12
10
  import { readConfig, writeConfig } from "@/features/config/config.query";
13
11
  import {
14
- BOT_NOTES_KEY,
12
+ BOT_MEMORY_KEY,
15
13
  type BotForm,
16
14
  type BotIcon,
17
15
  DEFAULT_BOT,
18
- isBotNotesOn,
16
+ isBotMemoryOn,
19
17
  type JobBot,
20
18
  type PinnedTool,
21
19
  pickedModel,
@@ -31,6 +29,8 @@ const asJobBot = (row: {
31
29
  /** Empty runs on the app default model (bot.run resolveModel). */
32
30
  provider: TextModelProviderId | null;
33
31
  model: string | null;
32
+ disabled: boolean;
33
+ compactAt: number | null;
34
34
  }): JobBot => ({
35
35
  name: row.name,
36
36
  description: row.description,
@@ -38,21 +38,36 @@ const asJobBot = (row: {
38
38
  icon: row.icon,
39
39
  provider: row.provider,
40
40
  model: row.model,
41
+ disabled: row.disabled,
42
+ compactAt: row.compactAt,
41
43
  });
42
44
 
43
- /** Who a job can go to: the user's bots, or DEFAULT_BOT when there are none. */
45
+ /**
46
+ * Who a job can go to: the user's bots, or DEFAULT_BOT when there are none.
47
+ * Switched-off bots are left out here and nowhere else — this one read is what
48
+ * every prompt's roster and `delegate`'s list are built from, so off is off in
49
+ * all of them without a second rule to keep.
50
+ */
44
51
  export async function listJobBots(): Promise<JobBot[]> {
45
52
  const rows = await database
46
53
  .select()
47
54
  .from(botTable)
48
55
  .orderBy(botTable.createdAt);
49
56
 
50
- return rows.length ? rows.map(asJobBot) : [DEFAULT_BOT];
57
+ // The fallback answers "no bots exist", never "every bot is off": switching
58
+ // them all off is a choice, and conjuring a worker would undo it.
59
+ return rows.length
60
+ ? rows.filter((row) => !row.disabled).map(asJobBot)
61
+ : [DEFAULT_BOT];
51
62
  }
52
63
 
53
64
  /**
54
- * The bot a job names. Exact name first, then case-insensitive only; no looser
55
- * matching. A miss returns null so `delegate` can list the roster instead.
65
+ * The bot a job names, switched off or not: a job already under way resumes
66
+ * through here, and refusing it would strand a thread the user can still answer.
67
+ * `delegate` is what checks `disabled`, because that is where a bot is picked.
68
+ *
69
+ * Exact name first, then case-insensitive only; no looser matching. A miss
70
+ * returns null so `delegate` can list the roster instead.
56
71
  */
57
72
  export async function findJobBot(name: string): Promise<JobBot | null> {
58
73
  const row = await findBot(name);
@@ -60,13 +75,19 @@ export async function findJobBot(name: string): Promise<JobBot | null> {
60
75
 
61
76
  // Case is not a different name: the spoken name arrives through a transcript
62
77
  const said = name.trim().toLowerCase();
63
- const bots = await listJobBots();
64
- return bots.find((bot) => bot.name.toLowerCase() === said) ?? null;
78
+ const [match] = await database
79
+ .select()
80
+ .from(botTable)
81
+ .where(eq(sql`lower(${botTable.name})`, said));
82
+ if (match) return asJobBot(match);
83
+
84
+ // The worker that exists when no row does; it has no row to match against
85
+ return DEFAULT_BOT.name.toLowerCase() === said ? DEFAULT_BOT : null;
65
86
  }
66
87
 
67
88
  /** Bots with their pinned tools and token totals: a set of queries plus grouping, not a join. */
68
89
  export async function findAllBots() {
69
- const [bots, pins, spent, notes] = await Promise.all([
90
+ const [bots, pins, spent] = await Promise.all([
70
91
  database.select().from(botTable).orderBy(botTable.createdAt),
71
92
  database
72
93
  .select({
@@ -88,7 +109,6 @@ export async function findAllBots() {
88
109
  })
89
110
  .from(taskTable)
90
111
  .groupBy(taskTable.bot),
91
- database.select().from(botNoteTable),
92
112
  ]);
93
113
 
94
114
  const byBot = new Map<string, PinnedTool[]>();
@@ -110,59 +130,21 @@ export async function findAllBots() {
110
130
  : [[row.bot, new Date(Number(row.lastJobAt) * 1000)] as const],
111
131
  ),
112
132
  );
113
- const noteOf = new Map(notes.map((row) => [row.bot, row]));
114
133
  return bots.map((bot) => ({
115
134
  ...bot,
116
135
  tools: byBot.get(bot.name) ?? [],
117
136
  tokens: tokensOf.get(bot.name) ?? { input: 0, output: 0 },
118
137
  lastJobAt: lastJobOf.get(bot.name) ?? null,
119
- note: noteOf.get(bot.name)?.text ?? null,
120
- noteAt: noteOf.get(bot.name)?.updatedAt ?? null,
121
138
  }));
122
139
  }
123
140
 
124
- // A bot's own notes. Nothing here belongs to a job: the row survives every job
125
- // the bot runs and is read back into its next prompt (ai/prompts/bot.prompt).
126
-
127
- /** What this bot has written to itself. Keyed by name, so DEFAULT_BOT has one too. */
128
- export async function readBotNote(bot: string): Promise<string | null> {
129
- const [row] = await database
130
- .select({ text: botNoteTable.text })
131
- .from(botNoteTable)
132
- .where(eq(botNoteTable.bot, bot));
133
- return row?.text ?? null;
134
- }
135
-
136
- /**
137
- * The whole block, as the pass rewrote it (bot.notes). Cut rather than refused: the schema
138
- * already caps it, and a run that gets this far has handed its report back. Empty clears it.
139
- */
140
- export async function writeBotNote(bot: string, text: string): Promise<void> {
141
- const next = text.trim().slice(0, BOT_NOTES.chars).trim();
142
- if (!next) return clearBotNote(bot);
143
-
144
- const updatedAt = new Date();
145
- await database
146
- .insert(botNoteTable)
147
- .values({ bot, text: next, updatedAt })
148
- .onConflictDoUpdate({
149
- target: botNoteTable.bot,
150
- set: { text: next, updatedAt },
151
- });
152
- }
153
-
154
- /** Whether any bot keeps its own instructions at all (bot.schema BOT_NOTES_KEY). */
155
- export async function readBotNotesOn(): Promise<boolean> {
156
- return isBotNotesOn(await readConfig(BOT_NOTES_KEY));
157
- }
158
-
159
- export async function writeBotNotesOn(on: boolean): Promise<void> {
160
- await writeConfig(BOT_NOTES_KEY, on ? "on" : "off");
141
+ /** Whether bots keep their own memory at all (bot.schema BOT_MEMORY_KEY). */
142
+ export async function readBotMemoryOn(): Promise<boolean> {
143
+ return isBotMemoryOn(await readConfig(BOT_MEMORY_KEY));
161
144
  }
162
145
 
163
- /** The one thing the user does to notes: throw them away when a bot has learned something wrong. */
164
- export async function clearBotNote(bot: string): Promise<void> {
165
- await database.delete(botNoteTable).where(eq(botNoteTable.bot, bot));
146
+ export async function writeBotMemoryOn(on: boolean): Promise<void> {
147
+ await writeConfig(BOT_MEMORY_KEY, on ? "on" : "off");
166
148
  }
167
149
 
168
150
  export async function findBot(name: string) {
@@ -228,7 +210,5 @@ export async function deleteBot(name: string) {
228
210
  .delete(botTable)
229
211
  .where(eq(botTable.name, name))
230
212
  .returning({ name: botTable.name });
231
- // Notes are keyed by name with no foreign key, so nothing cascades for them.
232
- await clearBotNote(name);
233
213
  return removed.length > 0;
234
214
  }