thursday-agent 0.1.2 → 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 (573) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +5 -1
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +5 -5
  5. package/.next/routes-manifest.json +27 -3
  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.html +1 -1
  9. package/.next/server/app/_global-error.rsc +2 -2
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page.js +2 -2
  14. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/server/app/_not-found.html +1 -1
  17. package/.next/server/app/_not-found.rsc +14 -14
  18. package/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  19. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
  20. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  21. package/.next/server/app/api/artifact/route.js +3 -3
  22. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  23. package/.next/server/app/api/bot/memory/files/route/app-paths-manifest.json +3 -0
  24. package/.next/server/app/api/bot/memory/files/route.js +10 -0
  25. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -0
  26. package/.next/server/app/api/bot/memory/files/route_client-reference-manifest.js +3 -0
  27. package/.next/server/app/api/bot/memory/route/app-paths-manifest.json +3 -0
  28. package/.next/server/app/api/bot/memory/route/build-manifest.json +12 -0
  29. package/.next/server/app/api/bot/memory/route/server-reference-manifest.json +4 -0
  30. package/.next/server/app/api/bot/memory/route.js +14 -0
  31. package/.next/server/app/api/bot/memory/route.js.map +5 -0
  32. package/.next/server/app/api/bot/memory/route.js.nft.json +1 -0
  33. package/.next/server/app/api/bot/memory/route_client-reference-manifest.js +3 -0
  34. package/.next/server/app/api/bot/route.js +7 -7
  35. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  36. package/.next/server/app/api/bot/task/[id]/route.js +9 -9
  37. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +1 -1
  38. package/.next/server/app/api/bot/task/route.js +8 -8
  39. package/.next/server/app/api/bot/task/route.js.nft.json +1 -1
  40. package/.next/server/app/api/config/route.js +6 -6
  41. package/.next/server/app/api/config/route.js.nft.json +1 -1
  42. package/.next/server/app/api/events/route.js +4 -5
  43. package/.next/server/app/api/events/route.js.nft.json +1 -1
  44. package/.next/server/app/api/file/[...path]/route.js +3 -3
  45. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  46. package/.next/server/app/api/llm-model/catalog/route.js +10 -9
  47. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  48. package/.next/server/app/api/llm-model/credits/route/app-paths-manifest.json +3 -0
  49. package/.next/server/app/api/llm-model/credits/route/build-manifest.json +12 -0
  50. package/.next/server/app/api/llm-model/credits/route/server-reference-manifest.json +4 -0
  51. package/.next/server/app/api/llm-model/credits/route.js +16 -0
  52. package/.next/server/app/api/llm-model/credits/route.js.map +5 -0
  53. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -0
  54. package/.next/server/app/api/llm-model/credits/route_client-reference-manifest.js +3 -0
  55. package/.next/server/app/api/llm-model/route.js +10 -8
  56. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  57. package/.next/server/app/api/llm-model/subscription/route/app-paths-manifest.json +3 -0
  58. package/.next/server/app/api/llm-model/subscription/route/build-manifest.json +12 -0
  59. package/.next/server/app/api/llm-model/subscription/route/server-reference-manifest.json +4 -0
  60. package/.next/server/app/api/llm-model/subscription/route.js +15 -0
  61. package/.next/server/app/api/llm-model/subscription/route.js.map +5 -0
  62. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -0
  63. package/.next/server/app/api/llm-model/subscription/route_client-reference-manifest.js +3 -0
  64. package/.next/server/app/api/mcp/[name]/route.js +5 -5
  65. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  66. package/.next/server/app/api/mcp/oauth/callback/route.js +6 -6
  67. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  68. package/.next/server/app/api/mcp/route.js +5 -5
  69. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  70. package/.next/server/app/api/mcp/tools/route.js +5 -5
  71. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  72. package/.next/server/app/api/memory/edit/route/app-paths-manifest.json +3 -0
  73. package/.next/server/app/api/memory/edit/route/build-manifest.json +12 -0
  74. package/.next/server/app/api/memory/edit/route/server-reference-manifest.json +4 -0
  75. package/.next/server/app/api/memory/edit/route.js +24 -0
  76. package/.next/server/app/api/memory/edit/route.js.map +5 -0
  77. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -0
  78. package/.next/server/app/api/memory/{tidy → edit}/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/memory/route.js +7 -8
  80. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  81. package/.next/server/app/api/skills/[source]/[name]/route.js +3 -3
  82. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  83. package/.next/server/app/api/skills/route.js +3 -3
  84. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  85. package/.next/server/app/api/thursday/call/route.js +9 -7
  86. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  87. package/.next/server/app/api/thursday/skills/route.js +9 -7
  88. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  89. package/.next/server/app/api/thursday/tool-call/route.js +16 -15
  90. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  91. package/.next/server/app/api/workspace/route.js +4 -5
  92. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  93. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
  94. package/.next/server/app/artifact/[...path]/page.js +5 -6
  95. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  96. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  97. package/.next/server/app/favicon.ico/route.js +3 -4
  98. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  99. package/.next/server/app/favicon.ico.body +0 -0
  100. package/.next/server/app/page/server-reference-manifest.json +66 -77
  101. package/.next/server/app/page.js +11 -11
  102. package/.next/server/app/page.js.nft.json +1 -1
  103. package/.next/server/app/page_client-reference-manifest.js +1 -1
  104. package/.next/server/app-paths-manifest.json +5 -1
  105. package/.next/server/chunks/[externals]__0dzuk6_._.js +3 -0
  106. package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +3 -0
  107. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +3 -0
  108. package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +3 -0
  109. package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +8 -0
  110. package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +3 -0
  111. package/.next/server/chunks/[root-of-the-server]__0ce8nf8._.js +5 -0
  112. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +3 -0
  113. package/.next/server/chunks/[root-of-the-server]__0j7z0r3._.js +12 -0
  114. package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +8 -0
  115. package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +8 -0
  116. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +3 -0
  117. package/.next/server/chunks/[root-of-the-server]__0pa2n68._.js +3 -0
  118. package/.next/server/chunks/[root-of-the-server]__0q0vvt2._.js +5 -0
  119. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +5 -0
  120. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +5 -0
  121. package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +3 -0
  122. package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +8 -0
  123. package/.next/server/chunks/[root-of-the-server]__15bjnu5._.js +5 -0
  124. package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +8 -0
  125. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +5 -0
  126. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +3 -0
  127. package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +10 -0
  128. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +3 -0
  129. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +3 -0
  130. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +11 -0
  131. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +3 -0
  132. package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +8 -0
  133. package/.next/server/chunks/{_1hzrsvg._.js → _0-73of8._.js} +6 -6
  134. package/.next/server/chunks/{_1cbk7ms._.js → _0-fjql4._.js} +10 -10
  135. package/.next/server/chunks/_00xh_q0._.js +27 -0
  136. package/.next/server/chunks/{_0y8is-s._.js → _03a0897._.js} +1 -1
  137. package/.next/server/chunks/{_0pppbb5._.js → _03kp0jp._.js} +166 -35
  138. package/.next/server/chunks/_051qh8u._.js +3 -0
  139. package/.next/server/chunks/{node_modules_next_04q-o58._.js → _05dla15._.js} +2 -2
  140. package/.next/server/chunks/_05h2cii._.js +1 -1
  141. package/.next/server/chunks/_0c9j6rb._.js +49 -0
  142. package/.next/server/chunks/_0fzqt2y._.js +74 -44
  143. package/.next/server/chunks/{_0kl37zl._.js → _0ioz3nd._.js} +1 -1
  144. package/.next/server/chunks/_0iwfby5._.js +3 -0
  145. package/.next/server/chunks/{_0hin38_._.js → _0khihjk._.js} +5 -5
  146. package/.next/server/chunks/_0mecv0f._.js +26 -0
  147. package/.next/server/chunks/_0mh8j4m._.js +3 -0
  148. package/.next/server/chunks/{_1icgbi8._.js → _0n74zsf._.js} +2 -2
  149. package/.next/server/chunks/_0obojvv._.js +3 -0
  150. package/.next/server/chunks/_0recufk._.js +49 -0
  151. package/.next/server/chunks/{_1t8fv7b._.js → _0rnf-6n._.js} +2 -2
  152. package/.next/server/chunks/_0sb7tlz._.js +3 -0
  153. package/.next/server/chunks/{_0jgm3b8._.js → _0u10wmw._.js} +6 -6
  154. package/.next/server/chunks/{_12nr4xc._.js → _0u4aiy2._.js} +2 -2
  155. package/.next/server/chunks/_0wp4le3._.js +1 -1
  156. package/.next/server/chunks/_0y5fg-x._.js +1 -1
  157. package/.next/server/chunks/_1230wbx._.js +10 -0
  158. package/.next/server/chunks/_12nheja._.js +3 -0
  159. package/.next/server/chunks/_13510xh._.js +3 -0
  160. package/.next/server/chunks/_15hq89o._.js +1 -1
  161. package/.next/server/chunks/_17l5ygt._.js +49 -0
  162. package/.next/server/chunks/{_0ks6_sg._.js → _18-1wcc._.js} +6 -6
  163. package/.next/server/chunks/_1_5mnq4._.js +18 -0
  164. package/.next/server/chunks/{_0tzfesa._.js → _1_9mjx-._.js} +1 -1
  165. package/.next/server/chunks/_1d0j961._.js +6 -0
  166. package/.next/server/chunks/_1d5zmy8._.js +1 -1
  167. package/.next/server/chunks/_1drgfx4._.js +18 -0
  168. package/.next/server/chunks/{_1skgy7b._.js → _1e48czp._.js} +5 -5
  169. package/.next/server/chunks/_1f46eie._.js +3 -0
  170. package/.next/server/chunks/_1h5_8sk._.js +3 -0
  171. package/.next/server/chunks/_1hdnxb7._.js +3 -0
  172. package/.next/server/chunks/_1j8k_j5._.js +3 -0
  173. package/.next/server/chunks/{_10qam6o._.js → _1kg70wc._.js} +5 -5
  174. package/.next/server/chunks/_1krd9rf._.js +3 -0
  175. package/.next/server/chunks/_1nc0eui._.js +11 -0
  176. package/.next/server/chunks/_1nula3v._.js +3 -0
  177. package/.next/server/chunks/_1pf4qe-._.js +3 -0
  178. package/.next/server/chunks/_1php4eq._.js +1 -1
  179. package/.next/server/chunks/_1qxheoa._.js +3 -0
  180. package/.next/server/chunks/_1x6kd1r._.js +3 -0
  181. package/.next/server/chunks/_1yuv4vp._.js +1 -1
  182. package/.next/server/chunks/_1zjrdag._.js +3 -0
  183. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_files_route_actions_1_xd_8f.js +3 -0
  184. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_route_actions_1a8xfr7.js +3 -0
  185. package/.next/server/chunks/_next-internal_server_app_api_llm-model_credits_route_actions_0v424pb.js +3 -0
  186. package/.next/server/chunks/_next-internal_server_app_api_llm-model_subscription_route_actions_0-udcm5.js +3 -0
  187. package/.next/server/chunks/_next-internal_server_app_api_memory_edit_route_actions_02sfnmr.js +3 -0
  188. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  189. package/.next/server/chunks/features_0rpfxbk._.js +3 -0
  190. package/.next/server/chunks/features_1qf3cei._.js +3 -0
  191. package/.next/server/chunks/features_bot_0zt92oh._.js +3 -0
  192. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
  193. package/.next/server/chunks/features_memory_1uqvksn._.js +6 -0
  194. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0tf290y._.js → node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js} +1 -1
  195. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0228f43._.js → node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js} +1 -1
  196. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0ir-vo2._.js → node_modules_consola_dist_chunks_prompt_mjs_0j61-ma._.js} +1 -1
  197. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0otw8ef._.js → node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js} +1 -1
  198. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js +3 -0
  199. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_11zjo-1._.js +3 -0
  200. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1pycqsq._.js +3 -0
  201. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +3 -0
  202. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1y49572._.js +3 -0
  203. package/.next/server/chunks/ssr/[externals]__0dizgek._.js +3 -0
  204. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  205. package/.next/server/chunks/ssr/[root-of-the-server]__0_69wqr._.js +3 -0
  206. package/.next/server/chunks/ssr/[root-of-the-server]__0hg5gib._.js +1 -1
  207. package/.next/server/chunks/ssr/[root-of-the-server]__0i8ie7f._.js +3 -0
  208. package/.next/server/chunks/ssr/{[root-of-the-server]__0jsmmb-._.js → [root-of-the-server]__0mz33a7._.js} +1 -1
  209. package/.next/server/chunks/ssr/[root-of-the-server]__0tbkdlx._.js +3 -0
  210. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +3 -0
  211. package/.next/server/chunks/ssr/{[root-of-the-server]__0f6s48x._.js → [root-of-the-server]__0xpcv9w._.js} +3 -3
  212. package/.next/server/chunks/ssr/[root-of-the-server]__0xtssj3._.js +1 -1
  213. package/.next/server/chunks/ssr/[root-of-the-server]__0zkv7z_._.js +3 -0
  214. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +57 -0
  215. package/.next/server/chunks/ssr/[root-of-the-server]__15_uhip._.js +3 -0
  216. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  217. package/.next/server/chunks/ssr/[root-of-the-server]__1cyjywu._.js +3 -0
  218. package/.next/server/chunks/ssr/[root-of-the-server]__1eh7hid._.js +3 -0
  219. package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +43 -0
  220. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
  221. package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +4 -0
  222. package/.next/server/chunks/ssr/[root-of-the-server]__1pduf5n._.js +3 -0
  223. package/.next/server/chunks/ssr/{_1mznrxk._.js → _001_ms1._.js} +3 -3
  224. package/.next/server/chunks/ssr/_01_6m32._.js +3 -0
  225. package/.next/server/chunks/ssr/_01n3o0m._.js +3 -0
  226. package/.next/server/chunks/ssr/_07uchnc._.js +3 -0
  227. package/.next/server/chunks/ssr/_0ap2fzn._.js +3 -0
  228. package/.next/server/chunks/ssr/_0c-ql2m._.js +3 -0
  229. package/.next/server/chunks/ssr/_0h42fze._.js +3 -0
  230. package/.next/server/chunks/ssr/_0h7zdni._.js +1 -1
  231. package/.next/server/chunks/ssr/_0i_6q1w._.js +41 -0
  232. package/.next/server/chunks/ssr/_0kbkmar._.js +3 -0
  233. package/.next/server/chunks/ssr/_0lu1n_x._.js +3 -0
  234. package/.next/server/chunks/ssr/{_077-g6s._.js → _0mb8zc8._.js} +3 -3
  235. package/.next/server/chunks/ssr/_0mo2w06._.js +3 -0
  236. package/.next/server/chunks/ssr/{_13punpm._.js → _0q0zan6._.js} +2 -2
  237. package/.next/server/chunks/ssr/{_0gd4vaa._.js → _0u2jv_x._.js} +94 -58
  238. package/.next/server/chunks/ssr/_0y0tiht._.js +4 -0
  239. package/.next/server/chunks/ssr/_0zhoc3r._.js +3 -0
  240. package/.next/server/chunks/ssr/_1-teee5._.js +3 -3
  241. package/.next/server/chunks/ssr/_13fke0x._.js +3 -0
  242. package/.next/server/chunks/ssr/{_0q_2f2x._.js → _13z3f85._.js} +2 -2
  243. package/.next/server/chunks/ssr/_14_lw10._.js +3 -0
  244. package/.next/server/chunks/ssr/_15j2_8f._.js +3 -0
  245. package/.next/server/chunks/ssr/{_0lc_7c8._.js → _1eoqg_g._.js} +2 -2
  246. package/.next/server/chunks/ssr/_1sji22n._.js +3 -0
  247. package/.next/server/chunks/ssr/_1spzm8z._.js +3 -0
  248. package/.next/server/chunks/ssr/{_19_o9d-._.js → _1vi_uo7._.js} +2 -2
  249. package/.next/server/chunks/ssr/_1vyd1ji._.js +3 -0
  250. package/.next/server/chunks/ssr/_1xvgn77._.js +3 -0
  251. package/.next/server/chunks/ssr/_20kd_n0._.js +42 -0
  252. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +3 -0
  253. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  254. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  255. package/.next/server/chunks/ssr/lib_date-like_ts_02is0pw._.js +3 -0
  256. package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +27 -0
  257. package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +27 -0
  258. package/.next/server/chunks/ssr/{node_modules_1d-is1o._.js → node_modules_063xwpp._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_1ub40gk._.js → node_modules_0bvraul._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_1nhw9qg._.js → node_modules_0eu1va6._.js} +1 -1
  261. package/.next/server/chunks/ssr/{node_modules_0xwx4u-._.js → node_modules_0h50b8n._.js} +1 -1
  262. package/.next/server/chunks/ssr/{node_modules_043-236._.js → node_modules_0h5hnr1._.js} +1 -1
  263. package/.next/server/chunks/ssr/{node_modules_1t0y5jt._.js → node_modules_0h7u60n._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_1k29j1j._.js → node_modules_0lm7_vm._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_16i4o_3._.js → node_modules_0mwym0g._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_1y8_3vg._.js → node_modules_0rjg6t1._.js} +1 -1
  267. package/.next/server/chunks/ssr/node_modules_0x3-ply._.js +3 -0
  268. package/.next/server/chunks/ssr/{node_modules_108wd2o._.js → node_modules_0y_cded._.js} +1 -1
  269. package/.next/server/chunks/ssr/{node_modules_1jatz7w._.js → node_modules_0z5tsu8._.js} +1 -1
  270. package/.next/server/chunks/ssr/{node_modules_0ls96je._.js → node_modules_0zp9r92._.js} +1 -1
  271. package/.next/server/chunks/ssr/{node_modules_06kvvuo._.js → node_modules_1-hc6uv._.js} +1 -1
  272. package/.next/server/chunks/ssr/{node_modules_1_588_4._.js → node_modules_113tz0l._.js} +1 -1
  273. package/.next/server/chunks/ssr/{node_modules_0ipn1ho._.js → node_modules_124bue5._.js} +1 -1
  274. package/.next/server/chunks/ssr/node_modules_17bwo43._.js +55 -0
  275. package/.next/server/chunks/ssr/{node_modules_0_j7-g4._.js → node_modules_1_n3ztw._.js} +1 -1
  276. package/.next/server/chunks/ssr/{node_modules_20ynonm._.js → node_modules_1bc7gu8._.js} +1 -1
  277. package/.next/server/chunks/ssr/{node_modules_1hn_sd5._.js → node_modules_1bgb6-f._.js} +1 -1
  278. package/.next/server/chunks/ssr/{node_modules_0bue6gy._.js → node_modules_1h4a4pp._.js} +1 -1
  279. package/.next/server/chunks/ssr/{node_modules_0fbw5-u._.js → node_modules_1i7u1ia._.js} +1 -1
  280. package/.next/server/chunks/ssr/{node_modules_1ee8gav._.js → node_modules_1juq3hs._.js} +1 -1
  281. package/.next/server/chunks/ssr/{node_modules_0_fvxnt._.js → node_modules_1l0qtdu._.js} +1 -1
  282. package/.next/server/chunks/ssr/{node_modules_13f2md6._.js → node_modules_1t9cyee._.js} +1 -1
  283. package/.next/server/chunks/ssr/{node_modules_0y2-av4._.js → node_modules_1uuj9x1._.js} +1 -1
  284. package/.next/server/chunks/ssr/{node_modules_00d6675._.js → node_modules_1vqb6po._.js} +1 -1
  285. package/.next/server/chunks/ssr/{node_modules_1v0077l._.js → node_modules_1xx28h1._.js} +1 -1
  286. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_092s8nx._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0d3skpl._.js} +1 -1
  287. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1nvexgu._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0i44kk5._.js} +1 -1
  288. package/.next/server/chunks/ssr/node_modules_@vercel_oidc_dist_0qe30a_._.js +3 -0
  289. package/.next/server/chunks/ssr/node_modules_consola_dist_chunks_prompt_mjs_05cwqv2._.js +47 -0
  290. package/.next/server/chunks/ssr/{node_modules_next_dist_0w6mzq5._.js → node_modules_next_dist_0drixxt._.js} +4 -4
  291. package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +2 -2
  292. package/.next/server/instrumentation.js +1 -1
  293. package/.next/server/middleware-build-manifest.js +3 -3
  294. package/.next/server/pages/404.html +1 -1
  295. package/.next/server/pages/500.html +1 -1
  296. package/.next/server/server-reference-manifest.js +1 -1
  297. package/.next/server/server-reference-manifest.json +67 -78
  298. package/.next/static/chunks/{31ttnjt6g35a0.js → 0ev4hyghq0mbb.js} +1 -1
  299. package/.next/static/chunks/0r5qcctujhxli.js +1 -0
  300. package/.next/static/chunks/0tmgrnlje14-s.js +3 -0
  301. package/.next/static/chunks/0x79tx04dxbpp.js +1 -0
  302. package/.next/static/chunks/0xzgvc0fkdb6t.js +1 -0
  303. package/.next/static/chunks/10teww7wt-f6h.js +1 -0
  304. package/.next/static/chunks/14hgtsjg-kael.css +1 -0
  305. package/.next/static/chunks/17donp69y4do7.js +40 -0
  306. package/.next/static/chunks/1dkjg87pxk0n9.js +28 -0
  307. package/.next/static/chunks/1ekc7ul556kbl.js +1 -0
  308. package/.next/static/chunks/{1khakdu_iuedc.js → 1grhjo7a5a0_-.js} +1 -1
  309. package/.next/static/chunks/1kq8h8wi_e0bc.js +53 -0
  310. package/.next/static/chunks/1okqiww3pnwka.js +1 -0
  311. package/.next/static/chunks/26-pr2c9ro222.js +1 -0
  312. package/.next/static/chunks/{2ihkf6l2jowo9.js → 280t0_e99i276.js} +3 -3
  313. package/.next/static/chunks/28cizcdaabd4h.js +1 -0
  314. package/.next/static/chunks/2a0k6jlq0_v1u.js +2 -0
  315. package/.next/static/chunks/2fzs9fm8yarvq.js +1 -0
  316. package/.next/static/chunks/2h0sd2vumhb15.js +1 -0
  317. package/.next/static/chunks/2hw2f6zmt7fmt.js +1 -0
  318. package/.next/static/chunks/2t4vhi3m8ahya.js +1 -0
  319. package/.next/static/chunks/2tigdtz3dpcy8.js +1 -0
  320. package/.next/static/chunks/3111pj5wnjgos.js +1 -0
  321. package/.next/static/chunks/3786h5vayt80-.js +28 -0
  322. package/.next/static/chunks/{3aquirz5h71da.js → 3agpgkwaa321p.js} +1 -1
  323. package/.next/static/chunks/3cfi_q6d_wtci.js +1 -0
  324. package/.next/static/chunks/3ok9_x74rip3v.js +1 -0
  325. package/.next/static/chunks/3xk7yqgomx7yq.js +1 -0
  326. package/.next/static/chunks/3xpbkl66ssib5.js +38 -0
  327. package/.next/static/media/favicon.37o1pjldwi2uc.ico +0 -0
  328. package/README.md +6 -4
  329. package/app/api/bot/memory/files/route.ts +14 -0
  330. package/app/api/bot/memory/route.ts +5 -0
  331. package/app/api/events/app-event.client.ts +24 -0
  332. package/app/api/events/app-event.server.ts +45 -0
  333. package/app/api/events/app-event.ts +42 -0
  334. package/app/api/llm-model/catalog/route.ts +12 -0
  335. package/app/api/llm-model/credits/route.ts +11 -0
  336. package/app/api/llm-model/route.ts +26 -0
  337. package/app/api/llm-model/subscription/route.ts +11 -0
  338. package/app/api/memory/edit/route.ts +7 -0
  339. package/app/api/memory/route.ts +21 -0
  340. package/app/api/query-key.ts +159 -0
  341. package/app/api/thursday/tool-call/route.ts +67 -0
  342. package/bin/thursday.mjs +3 -0
  343. package/components/ui/button-group.tsx +45 -0
  344. package/components/ui/custom-icon.tsx +259 -0
  345. package/components/ui/dropdown-menu.tsx +271 -0
  346. package/components/ui/folded-text.tsx +68 -0
  347. package/components/ui/input-group.tsx +157 -0
  348. package/components/ui/json-view.tsx +240 -0
  349. package/components/ui/shiny-text.tsx +55 -0
  350. package/components/ui/text-type.tsx +213 -0
  351. package/components/ui/theme-sync.tsx +9 -0
  352. package/database/migrations/{20260908030742_rainy_marvel_zombies → 20260910173049_numerous_spirit}/migration.sql +30 -33
  353. package/database/migrations/{20260908030742_rainy_marvel_zombies → 20260910173049_numerous_spirit}/snapshot.json +124 -145
  354. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +1 -0
  355. package/database/migrations/20260911030320_opposite_jack_power/snapshot.json +1158 -0
  356. package/docs/how-it-works.md +59 -0
  357. package/docs/images/keeps-going.png +0 -0
  358. package/docs/images/task-thread.png +0 -0
  359. package/docs/images/two-minds.png +0 -0
  360. package/features/ai/chatgpt.ts +617 -0
  361. package/features/ai/components/chatgpt-sign-in.tsx +66 -0
  362. package/features/ai/components/model-picker.tsx +17 -1
  363. package/features/ai/components/provider-icon.tsx +1 -0
  364. package/features/ai/load-tools.ts +105 -39
  365. package/features/ai/model.schema.ts +232 -34
  366. package/features/ai/model.ts +169 -24
  367. package/features/ai/prompts/bot.prompt.ts +245 -59
  368. package/features/ai/prompts/memory-edit.prompt.ts +33 -0
  369. package/features/ai/prompts/prompt-helper.ts +75 -30
  370. package/features/ai/prompts/thursday.prompt.ts +42 -17
  371. package/features/ai/tools/bot.tool.ts +32 -30
  372. package/features/ai/tools/connected.ts +17 -4
  373. package/features/ai/tools/mcp.tool.ts +5 -5
  374. package/features/ai/tools/memory.tool.ts +142 -74
  375. package/features/ai/tools/search.tool.ts +136 -47
  376. package/features/ai/tools/studio.tool.ts +5 -5
  377. package/features/ai/tools/tool-name.ts +2 -3
  378. package/features/ai/tools/workspace.tool.ts +33 -4
  379. package/features/bot/bot.action.ts +24 -7
  380. package/features/bot/bot.memory.ts +89 -0
  381. package/features/bot/bot.query.ts +41 -6
  382. package/features/bot/bot.run.ts +516 -210
  383. package/features/bot/bot.runner.ts +463 -93
  384. package/features/bot/bot.schema.ts +84 -7
  385. package/features/bot/bot.seed.ts +89 -16
  386. package/features/bot/components/bot-mark.tsx +122 -20
  387. package/features/bot/components/bot-room.tsx +519 -391
  388. package/features/bot/components/bot-setting.tsx +832 -341
  389. package/features/bot/components/bot-tool.tsx +2 -6
  390. package/features/bot/components/mark-palette.tsx +54 -0
  391. package/features/bot/components/path-chips.tsx +1 -1
  392. package/features/bot/components/task-badge.tsx +26 -6
  393. package/features/bot/components/task-reply.tsx +22 -33
  394. package/features/bot/components/task-setting.tsx +20 -17
  395. package/features/bot/task.query.ts +233 -33
  396. package/features/bot/task.store.ts +53 -9
  397. package/features/config/components/config-setting.tsx +265 -34
  398. package/features/config/components/models-badge.tsx +42 -0
  399. package/features/config/config.action.ts +12 -0
  400. package/features/config/config.const.ts +38 -2
  401. package/features/connectors/mcp.manager.ts +10 -2
  402. package/features/intro/components/intro.tsx +47 -46
  403. package/features/memory/components/memory-edit.tsx +338 -0
  404. package/features/memory/components/memory-setting.tsx +86 -79
  405. package/features/memory/memory.action.ts +3 -43
  406. package/features/memory/memory.edit.ts +87 -0
  407. package/features/memory/memory.query.ts +33 -44
  408. package/features/memory/memory.schema.ts +50 -97
  409. package/features/settings/components/settings.tsx +2 -0
  410. package/features/settings/settings.alert.ts +3 -1
  411. package/features/skills/components/skills-setting.tsx +9 -1
  412. package/features/thursday/components/ascii-orb.tsx +106 -90
  413. package/features/thursday/components/boot.tsx +7 -0
  414. package/features/thursday/components/call-log.tsx +219 -92
  415. package/features/thursday/components/face.tsx +6 -4
  416. package/features/thursday/components/tab-state.tsx +97 -0
  417. package/features/thursday/components/thursday-mark.tsx +4 -1
  418. package/features/thursday/components/thursday-setting.tsx +17 -47
  419. package/features/thursday/components/thursday.tsx +208 -95
  420. package/features/thursday/thursday.action.ts +12 -17
  421. package/features/thursday/thursday.query.ts +61 -70
  422. package/features/thursday/thursday.schema.ts +20 -7
  423. package/features/thursday/tool-line.ts +85 -11
  424. package/features/thursday/use-thursday.ts +86 -59
  425. package/features/workspace/components/file-view.tsx +4 -2
  426. package/features/workspace/workspace.ts +230 -13
  427. package/hooks/use-draft.ts +37 -0
  428. package/hooks/use-hotkey.ts +105 -0
  429. package/hooks/use-object-state.ts +51 -0
  430. package/hooks/use-on-visible.ts +72 -0
  431. package/hooks/use-theme.ts +106 -0
  432. package/hooks/use-wake-word.ts +262 -0
  433. package/lib/limits.ts +1 -1
  434. package/lib/oauth-page.ts +27 -0
  435. package/lib/realtime/openai.ts +2 -2
  436. package/lib/realtime/realtime.driver.ts +34 -1
  437. package/lib/realtime/realtime.protocol.ts +7 -1
  438. package/lib/realtime/realtime.tap.ts +122 -0
  439. package/lib/sandbox.ts +60 -29
  440. package/lib/tokens.ts +19 -0
  441. package/package.json +1 -1
  442. package/skills/browser/SKILL.md +55 -34
  443. package/.next/server/app/api/memory/tidy/route/app-paths-manifest.json +0 -3
  444. package/.next/server/app/api/memory/tidy/route.js +0 -23
  445. package/.next/server/app/api/memory/tidy/route.js.nft.json +0 -1
  446. package/.next/server/chunks/[root-of-the-server]__019dx9f._.js +0 -5
  447. package/.next/server/chunks/[root-of-the-server]__02_2sm-._.js +0 -5
  448. package/.next/server/chunks/[root-of-the-server]__02kt8yn._.js +0 -10
  449. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +0 -3
  450. package/.next/server/chunks/[root-of-the-server]__06t77t4._.js +0 -11
  451. package/.next/server/chunks/[root-of-the-server]__0bed6hu._.js +0 -8
  452. package/.next/server/chunks/[root-of-the-server]__0dupqt7._.js +0 -5
  453. package/.next/server/chunks/[root-of-the-server]__0h59di-._.js +0 -5
  454. package/.next/server/chunks/[root-of-the-server]__0j_n5l3._.js +0 -3
  455. package/.next/server/chunks/[root-of-the-server]__0le4d-p._.js +0 -3
  456. package/.next/server/chunks/[root-of-the-server]__0m8ywyo._.js +0 -10
  457. package/.next/server/chunks/[root-of-the-server]__0nfuugi._.js +0 -5
  458. package/.next/server/chunks/[root-of-the-server]__0phdgco._.js +0 -8
  459. package/.next/server/chunks/[root-of-the-server]__0qjqtwo._.js +0 -5
  460. package/.next/server/chunks/[root-of-the-server]__0t_dqaj._.js +0 -3
  461. package/.next/server/chunks/[root-of-the-server]__0wvgrsl._.js +0 -3
  462. package/.next/server/chunks/[root-of-the-server]__0yk6s3w._.js +0 -5
  463. package/.next/server/chunks/[root-of-the-server]__0z3gelv._.js +0 -3
  464. package/.next/server/chunks/[root-of-the-server]__10qshki._.js +0 -3
  465. package/.next/server/chunks/[root-of-the-server]__113fqg5._.js +0 -12
  466. package/.next/server/chunks/[root-of-the-server]__11w_7_3._.js +0 -3
  467. package/.next/server/chunks/[root-of-the-server]__16thabu._.js +0 -3
  468. package/.next/server/chunks/[root-of-the-server]__173nhwf._.js +0 -8
  469. package/.next/server/chunks/[root-of-the-server]__1_0q_9w._.js +0 -3
  470. package/.next/server/chunks/[root-of-the-server]__1_aoyr9._.js +0 -3
  471. package/.next/server/chunks/[root-of-the-server]__1bqhuh9._.js +0 -8
  472. package/.next/server/chunks/[root-of-the-server]__1cqizfq._.js +0 -5
  473. package/.next/server/chunks/[root-of-the-server]__1dow0bz._.js +0 -3
  474. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +0 -3
  475. package/.next/server/chunks/[root-of-the-server]__1gmn1cs._.js +0 -10
  476. package/.next/server/chunks/[root-of-the-server]__1lr7j9t._.js +0 -5
  477. package/.next/server/chunks/[root-of-the-server]__1mzp_el._.js +0 -3
  478. package/.next/server/chunks/[root-of-the-server]__1txedx6._.js +0 -8
  479. package/.next/server/chunks/[root-of-the-server]__1u_qvc7._.js +0 -3
  480. package/.next/server/chunks/[root-of-the-server]__1zgpz1w._.js +0 -3
  481. package/.next/server/chunks/_012yhfm._.js +0 -39
  482. package/.next/server/chunks/_06mxlgn._.js +0 -3
  483. package/.next/server/chunks/_07rtlxv._.js +0 -3
  484. package/.next/server/chunks/_0a351g7._.js +0 -6
  485. package/.next/server/chunks/_0kjjmag._.js +0 -3
  486. package/.next/server/chunks/_0zmestz._.js +0 -55
  487. package/.next/server/chunks/_0zuzmt_._.js +0 -39
  488. package/.next/server/chunks/_12bbv5i._.js +0 -96
  489. package/.next/server/chunks/_15q1pig._.js +0 -3
  490. package/.next/server/chunks/_1drv2et._.js +0 -36
  491. package/.next/server/chunks/_1ic3bew._.js +0 -5
  492. package/.next/server/chunks/_1mxn_lb._.js +0 -3
  493. package/.next/server/chunks/_1uj4_io._.js +0 -10
  494. package/.next/server/chunks/_1x7p319._.js +0 -6
  495. package/.next/server/chunks/_1yldgo4._.js +0 -55
  496. package/.next/server/chunks/_2050gwn._.js +0 -255
  497. package/.next/server/chunks/_next-internal_server_app_api_memory_tidy_route_actions_0_cfuom.js +0 -3
  498. package/.next/server/chunks/features_0scmr4i._.js +0 -3
  499. package/.next/server/chunks/features_bot_task_query_ts_11xuzl3._.js +0 -3
  500. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0vorg6w._.js +0 -3
  501. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0ykklj0._.js +0 -3
  502. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1ryg3wh._.js +0 -3
  503. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vmaq9f._.js +0 -3
  504. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vwbnq_._.js +0 -3
  505. package/.next/server/chunks/ssr/[externals]_node_crypto_1kn79-7._.js +0 -3
  506. package/.next/server/chunks/ssr/[root-of-the-server]__01id-v3._.js +0 -3
  507. package/.next/server/chunks/ssr/[root-of-the-server]__0b-0i32._.js +0 -3
  508. package/.next/server/chunks/ssr/[root-of-the-server]__0dfwvr4._.js +0 -4
  509. package/.next/server/chunks/ssr/[root-of-the-server]__0iuoa-r._.js +0 -3
  510. package/.next/server/chunks/ssr/[root-of-the-server]__1-mnhyd._.js +0 -90
  511. package/.next/server/chunks/ssr/[root-of-the-server]__185grso._.js +0 -3
  512. package/.next/server/chunks/ssr/[root-of-the-server]__1minz8_._.js +0 -3
  513. package/.next/server/chunks/ssr/_0-mc7ro._.js +0 -3
  514. package/.next/server/chunks/ssr/_01p5r6-._.js +0 -3
  515. package/.next/server/chunks/ssr/_09-0k3z._.js +0 -3
  516. package/.next/server/chunks/ssr/_0ay6b01._.js +0 -3
  517. package/.next/server/chunks/ssr/_0cvjbuz._.js +0 -3
  518. package/.next/server/chunks/ssr/_0fafgvl._.js +0 -3
  519. package/.next/server/chunks/ssr/_0j4v8of._.js +0 -3
  520. package/.next/server/chunks/ssr/_0l81bzy._.js +0 -3
  521. package/.next/server/chunks/ssr/_0nso8tp._.js +0 -3
  522. package/.next/server/chunks/ssr/_0sf1isi._.js +0 -3
  523. package/.next/server/chunks/ssr/_0ti51xc._.js +0 -3
  524. package/.next/server/chunks/ssr/_0y84qo6._.js +0 -3
  525. package/.next/server/chunks/ssr/_10uvw3l._.js +0 -3
  526. package/.next/server/chunks/ssr/_1dcxzqe._.js +0 -3
  527. package/.next/server/chunks/ssr/_1e-dgz0._.js +0 -4
  528. package/.next/server/chunks/ssr/_1fq7zgb._.js +0 -3
  529. package/.next/server/chunks/ssr/_1jbv7m1._.js +0 -3
  530. package/.next/server/chunks/ssr/features_bot_components_bot-setting_tsx_01ajft6._.js +0 -4
  531. package/.next/server/chunks/ssr/features_config_components_14jqgy4._.js +0 -3
  532. package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +0 -4
  533. package/.next/server/chunks/ssr/lib_realtime_0aetuyp._.js +0 -24
  534. package/.next/server/chunks/ssr/lib_realtime_18k_aj-._.js +0 -24
  535. package/.next/server/chunks/ssr/node_modules_zod_v4_classic_errors_05xv7vp.js +0 -3
  536. package/.next/server/chunks/ssr/node_modules_zod_v4_classic_external_15fmmz3.js +0 -55
  537. package/.next/static/chunks/0f9sq-7q_yxyl.js +0 -1
  538. package/.next/static/chunks/0tydnn2kybibk.js +0 -1
  539. package/.next/static/chunks/0yysv1gzin17t.js +0 -1
  540. package/.next/static/chunks/1fr5m75pwtyic.js +0 -1
  541. package/.next/static/chunks/1gy3bbv7usnjo.js +0 -1
  542. package/.next/static/chunks/1keib_gt066gc.js +0 -1
  543. package/.next/static/chunks/1ytnip8wdng93.js +0 -1
  544. package/.next/static/chunks/21rk8w7bda-su.js +0 -1
  545. package/.next/static/chunks/247d-r95j8xs0.js +0 -1
  546. package/.next/static/chunks/28g42tw8tsvhd.js +0 -1
  547. package/.next/static/chunks/29gyb3nubj51j.js +0 -53
  548. package/.next/static/chunks/2cwjgkt_hoyhj.js +0 -22
  549. package/.next/static/chunks/2fq_86jvq9ymq.js +0 -2
  550. package/.next/static/chunks/2rbf1fpd8n80-.js +0 -22
  551. package/.next/static/chunks/2ukj8k69y89um.js +0 -1
  552. package/.next/static/chunks/2uxum7qbyeyxd.js +0 -1
  553. package/.next/static/chunks/2wngeetfnzxkp.js +0 -2
  554. package/.next/static/chunks/388-t2v72jh39.css +0 -1
  555. package/.next/static/chunks/3fqvc0cg-atq_.js +0 -1
  556. package/.next/static/chunks/3p4egvfjxpatb.js +0 -1
  557. package/.next/static/chunks/3qe1w1ei-huhl.js +0 -1
  558. package/.next/static/chunks/3xxa2j56-f3nm.js +0 -3
  559. package/.next/static/chunks/3y40riycdip-i.js +0 -1
  560. package/.next/static/chunks/45a6zbtkelph9.js +0 -1
  561. package/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
  562. package/features/ai/prompts/memory-tidy.prompt.ts +0 -123
  563. package/features/ai/tools/tidy.tool.ts +0 -22
  564. package/features/memory/components/memory-tidy.tsx +0 -395
  565. package/features/memory/memory.tidy.ts +0 -332
  566. package/features/memory/tidy.query.ts +0 -135
  567. package/features/thursday/use-call-title.ts +0 -31
  568. /package/.next/server/app/api/{memory/tidy → bot/memory/files}/route/build-manifest.json +0 -0
  569. /package/.next/server/app/api/{memory/tidy → bot/memory/files}/route/server-reference-manifest.json +0 -0
  570. /package/.next/server/app/api/{memory/tidy → bot/memory/files}/route.js.map +0 -0
  571. /package/.next/static/{X34BUd9bfdH27ripuwwBm → x1cCqY0kWpR_VcYx_lWO5}/_buildManifest.js +0 -0
  572. /package/.next/static/{X34BUd9bfdH27ripuwwBm → x1cCqY0kWpR_VcYx_lWO5}/_clientMiddlewareManifest.js +0 -0
  573. /package/.next/static/{X34BUd9bfdH27ripuwwBm → x1cCqY0kWpR_VcYx_lWO5}/_ssgManifest.js +0 -0
@@ -1,7 +1,9 @@
1
- import { BOT_RUN, PATHS } from "@/config";
1
+ import type { ModelMessage } from "ai";
2
+ import { PATHS, PROMPT_LINE, WORKSPACE_KEEP } from "@/config";
2
3
  import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
3
- import { listJobBots } from "@/features/bot/bot.query";
4
- import type { JobBot } from "@/features/bot/bot.schema";
4
+ import { botMemoryFolder, listBotMemory } from "@/features/bot/bot.memory";
5
+ import { listJobBots, readBotMemoryOn } from "@/features/bot/bot.query";
6
+ import type { BotMemory, JobBot } from "@/features/bot/bot.schema";
5
7
  import { findPinnedTools } from "@/features/connectors/mcp.query";
6
8
  import type { McpToolRef } from "@/features/connectors/mcp.schema";
7
9
  import {
@@ -16,13 +18,18 @@ import {
16
18
  loadSkills,
17
19
  type SkillMetadata,
18
20
  } from "@/features/skills/skills.discover";
19
- import { openWorkspace } from "@/features/workspace/workspace";
21
+ import {
22
+ type MachineTools,
23
+ openWorkspace,
24
+ readMachineTools,
25
+ } from "@/features/workspace/workspace";
20
26
  import { logger } from "@/lib/logger";
21
27
  import { clip } from "@/lib/utils";
22
28
  import { listConnectedToolNames } from "../tools/connected";
23
29
  import {
24
30
  carriedLines,
25
31
  type LoadedPrompt,
32
+ logPromptSize,
26
33
  mcpToolLines,
27
34
  noteLines,
28
35
  nowLine,
@@ -34,50 +41,74 @@ import {
34
41
  * Each chapter decides for itself whether it is included. Assembled on every run, never cached,
35
42
  * so a skill or server added a minute ago is in the next job's prompt.
36
43
  * Two seats share this prompt: the bot holding the job, and one borrowed for a part of it
37
- * (`ask_bot`). Only identity, roster, asking and finishing differ between them.
44
+ * (`ask_bot`). Only identity, roster, asking and answering differ between them.
38
45
  *
39
46
  * @param self This run's bot name; used only to drop itself from the roster.
40
47
  * @param persona Owner's instruction for this bot from settings.
41
- * @param askedBy Name of the borrowing bot in the borrowed seat; null for the bot holding the job.
48
+ * @param seat The borrowed seat who handed it this part, every bot above it on the job, whether it may borrow in turn; null for the bot holding the job.
42
49
  */
43
50
  export async function loadBotPrompt(
44
51
  self: string,
45
52
  persona?: string | null,
46
- askedBy?: string | null,
53
+ seat?: { askedBy: string; above: string[]; canBorrow: boolean } | null,
54
+ /** The two folders that are this run's rather than the user's (bot.run). */
55
+ folders?: { scratch: string | null; own: string },
47
56
  ): Promise<LoadedPrompt> {
48
57
  const sandbox = await openWorkspace();
49
58
  const name = self.trim();
50
- const [skills, index, carried, mcpTools, pinned, allBots] = await Promise.all(
51
- [
52
- loadSkills(sandbox),
53
- listNoteIndex(),
54
- listAlwaysLoaded(),
55
- // User-connected servers and the app's studio in one list (tools/connected)
56
- listConnectedToolNames(),
57
- // MCP tools this bot already holds; dropped from the listing below
58
- findPinnedTools(name),
59
- listJobBots(),
60
- ],
61
- );
62
-
63
- // Drop self so a bot cannot call itself; a borrowed bot has no roster at all (bot.run MAX_DEPTH)
64
- const peers = askedBy ? [] : allBots.filter((bot) => bot.name !== name);
59
+ const askedBy = seat?.askedBy ?? null;
60
+ const [
61
+ skills,
62
+ index,
63
+ carried,
64
+ mcpTools,
65
+ pinned,
66
+ allBots,
67
+ kept,
68
+ memoryOn,
69
+ machine,
70
+ ] = await Promise.all([
71
+ loadSkills(sandbox),
72
+ listNoteIndex(),
73
+ listAlwaysLoaded(),
74
+ // User-connected servers and the app's studio in one list (tools/connected)
75
+ listConnectedToolNames(),
76
+ // MCP tools this bot already holds; dropped from the listing below
77
+ findPinnedTools(name),
78
+ listJobBots(),
79
+ // What this bot kept on earlier jobs, read off its own folder (bot.memory)
80
+ listBotMemory(name),
81
+ readBotMemoryOn(),
82
+ // One `command -v` sweep; what is here decides the first command (environment)
83
+ readMachineTools(sandbox),
84
+ ]);
85
+
86
+ // Drop itself and every bot above it on this job, which are blocked waiting on
87
+ // it; the last seat the depth allows has no roster at all (config BOT_RUN.depth)
88
+ const peers =
89
+ seat && !seat.canBorrow
90
+ ? []
91
+ : allBots.filter(
92
+ (bot) => bot.name !== name && !seat?.above.includes(bot.name),
93
+ );
65
94
 
66
95
  const text = [
67
- askedBy ? borrowedIdentity(askedBy) : identity(),
96
+ askedBy ? borrowedIdentity(name, askedBy) : identity(name),
68
97
  memory(index, carried),
98
+ memoryOn ? ownMemory(botMemoryFolder(name), kept) : "",
69
99
  connectedTools(mcpTools, pinned),
70
100
  methods(skills),
71
- environment(sandbox.cwd),
101
+ environment(sandbox.cwd, machine, folders),
72
102
  roster(peers),
73
103
  askedBy ? askingBack(askedBy) : ASKING,
74
- askedBy ? handingUp(askedBy) : FINISHING,
104
+ askedBy ? handingUp(askedBy) : ANSWERING,
75
105
  // Last, so it is the closest thing to the work and outranks the rest
76
106
  ownerInstruction(persona),
77
107
  ]
78
108
  .filter(Boolean)
79
109
  .join("\n\n");
80
110
 
111
+ logPromptSize("bot", text);
81
112
  logger.debug(`bot prompt\n${text}`);
82
113
 
83
114
  return {
@@ -88,18 +119,19 @@ export async function loadBotPrompt(
88
119
  }
89
120
 
90
121
  /** Who the bot is, what machine it is on, and that guesses are not results. */
91
- function identity(): string {
122
+ function identity(name: string): string {
92
123
  return [
93
- `You are a worker. Thursday handed you a job while she keeps talking to the user; you are not in that conversation and never speak to the user directly. ${nowLine()}`,
124
+ // Named, because the owner's prompt may not name it and its own instructions are addressed to it
125
+ `You are ${name}, a worker. Thursday handed you a job while she keeps talking to the user — they speak to her and to nobody else, and what she says out of your answer is the only part of this that reaches them. You are not in that conversation and never address the user. This thread is drawn on their screen while you work, though: not written to them, but not private either. ${nowLine()}`,
94
126
  MACHINE,
95
127
  NO_GUESSING,
96
128
  ].join("\n\n");
97
129
  }
98
130
 
99
131
  /** The borrowed seat: above it is the borrowing bot, not Thursday. */
100
- function borrowedIdentity(askedBy: string): string {
132
+ function borrowedIdentity(name: string, askedBy: string): string {
101
133
  return [
102
- `You are a worker. ${askedBy} is holding a job Thursday handed them and has handed one part of it to you. You never speak to the user: ${askedBy} reports, and what you hand back goes into their report as-is. ${nowLine()}`,
134
+ `You are ${name}, a worker. ${askedBy} has handed you one part of a job Thursday handed over; your first message says who holds it and how it reached you. The user speaks to Thursday and to nobody else; you never address them, and what you hand back goes into ${askedBy}'s answer as-is. This thread is drawn on their screen while you work: not written to them, but not private either. ${nowLine()}`,
103
135
  MACHINE,
104
136
  NO_GUESSING,
105
137
  ].join("\n\n");
@@ -107,7 +139,7 @@ function borrowedIdentity(askedBy: string): string {
107
139
 
108
140
  const MACHINE = `**You are on a real computer — the user's own.** You have a shell and a filesystem, and the job is done, not described: where there is no tool for something, write one — in \`node\` unless they asked for another language, the runtime this app itself runs on. Reach for \`${TOOL_NAMES.bash}\` before concluding that something cannot be done, but after the roster, not instead of it: a script you write to do another bot's job is the long way round.
109
141
 
110
- **What is missing gets installed.** Inside the workspace, freely; onto the machine itself — \`python3\`, a \`brew\` package — once they say yes, so ask. What is already there is nobody's question.
142
+ **What is missing gets installed**, onto the machine once they say yes. What is already there is nobody's question — Environment says what this machine has.
111
143
 
112
144
  **Bring back the thing itself** — their own machine, their own accounts, their own copy of whatever they sent you for — not a smaller safer version of it, and not a note on why you did not.`;
113
145
 
@@ -127,14 +159,14 @@ Written by the person this bot works for. Where these and anything above disagre
127
159
  ${persona.trim()}`
128
160
  : "";
129
161
 
130
- /** A bot reads memory and adds to it; revising and naming are the call's (load-tools), so the chapter is that small. */
162
+ /** A bot only reads memory; every write, revising and the names the user says are the call's (load-tools), so the chapter is that small. */
131
163
  function memory(
132
164
  index: MemoryIndexEntry[],
133
165
  carried: MemoryAlwaysLoaded[],
134
166
  ): string {
135
- const head = `## Memory
167
+ const head = `## The user's memory
136
168
 
137
- What the user's assistant knows about them yours to read, and to add to when the work turns up something about them that outlives the job. What the job itself turned up goes in your report. It describes the user, not you: how they are named and spoken to is hers to use with them, not yours to borrow.`;
169
+ What Thursday knows about the user, kept as she talks with them. Every bot reads it; none writes to it. Open a note with \`${TOOL_NAMES.memory_recall}\` when the job needs something about them the address they sign in with, the name to book under and put what you find out about them in your answer; she decides what to keep. It describes them, not you: how they are named and spoken to is hers to use. What you learn about the work goes in your own memory, below.`;
138
170
 
139
171
  const alreadyKnown = carried.length
140
172
  ? `Already known:
@@ -151,6 +183,34 @@ A topic not listed is one nobody knows anything about.`;
151
183
  return [head, alreadyKnown, listing].filter(Boolean).join("\n\n");
152
184
  }
153
185
 
186
+ /**
187
+ * The bot's own memory (features/bot/bot.memory), listed by each file's first line so what a
188
+ * file holds costs one line until a job opens it. Always drawn, so a first job knows it has one.
189
+ * Nothing says what usually goes in first: a line like that is what a first job writes, whether
190
+ * or not the job taught it anything.
191
+ */
192
+ function ownMemory(folder: string, kept: BotMemory): string {
193
+ const listing = kept.entries.length
194
+ ? kept.entries
195
+ .map(({ file, line }) =>
196
+ line
197
+ ? `- ${file} — ${clip(line, PROMPT_LINE.botMemory)}`
198
+ : `- ${file}`,
199
+ )
200
+ .join("\n")
201
+ : "Empty.";
202
+ const rest =
203
+ kept.total > kept.entries.length
204
+ ? `\n\nThe newest ${kept.entries.length} of ${kept.total}; \`ls ${folder}\` for the rest.`
205
+ : "";
206
+
207
+ return `## Your memory
208
+
209
+ What you kept from your own earlier jobs, in \`${folder}/\`: one topic per file, its first line saying what it holds, read by no other bot. Keep what a later job would otherwise have to find out again — how a site signs in, the way through its screens, a command that turned out right — and fix or delete a file that proved wrong. No passwords, keys or codes.
210
+
211
+ ${listing}${rest}`;
212
+ }
213
+
154
214
  /**
155
215
  * Names only; schemas stay behind `tool_search`. Without the list the model cannot tell
156
216
  * "no such tool" from "not searched yet".
@@ -184,13 +244,35 @@ Written-down methods. When the job is one of these, read it with \`${TOOL_NAMES.
184
244
  ${skillLines(skills)}`;
185
245
  }
186
246
 
187
- /** Names the three workspace folders once; `write_file` refuses anything else (workspace.ts writeRefusal). */
188
- const environment = (cwd: string) => `## Environment
247
+ /**
248
+ * The machine, then the workspace. What is installed is read as the prompt is
249
+ * assembled (workspace.ts readMachineTools) rather than left to the job to find
250
+ * out: a bot that has to check first spends a step on it, and one that guesses
251
+ * writes for a runtime that is not here. Naming what is absent does as much
252
+ * work as naming what is present — it is the half a model otherwise assumes.
253
+ * The three folders are named once; `write_file` refuses anything else
254
+ * (workspace.ts writeRefusal).
255
+ */
256
+ const environment = (
257
+ cwd: string,
258
+ machine: MachineTools,
259
+ folders?: { scratch: string | null; own: string },
260
+ ) => `## Environment
189
261
 
190
262
  Current Cwd: ${cwd}
191
263
  Platform: ${process.platform}
264
+ ${machineLines(machine)}
192
265
 
193
- Your workspace \`${TOOL_NAMES.bash}\` runs here. Everything you write goes in one of three folders: \`${PATHS.artifacts}/\` (finished work the user opens), \`${PATHS.projects}/\` (code you build), \`${PATHS.scratch}/\` (everything in progress). Never the directory above — that is the app you run in; outside the workspace, only where the user pointed you.`;
266
+ Read off this machine as the job opened, so it is current: reach for what is here instead of checking for it.
267
+
268
+ Your workspace — \`${TOOL_NAMES.bash}\` runs here. Everything you write goes in one of these, and they are kept apart because what is in them lives for different lengths of time:
269
+
270
+ - \`${PATHS.artifacts}/\` — finished work the user opens, one entry per result. Theirs, and it stays.
271
+ - \`${PATHS.projects}/\` — code you build, one folder each. It outlives this job, and a project's dependencies install inside it, never at the workspace root.
272
+ - \`${folders?.scratch ?? PATHS.scratch}/\` — this job's working material, one folder for every bot on the job: what another bot on it wrote is here too. It is cleared ${Math.round(WORKSPACE_KEEP.forMs / 86_400_000)} days after the job ends, so nothing here is worth keeping.
273
+ - \`${folders?.own ?? PATHS.bots}/\` — yours, across every job you run here: your memory, a script you wrote once and will want again, a table you built.
274
+
275
+ Never the directory above — that is the app you run in; outside the workspace, only where the user pointed you.`;
194
276
 
195
277
  /** Same roster the voice prompt shows, used the other way: which part of a held job is another bot's. */
196
278
  function roster(peers: JobBot[]): string {
@@ -200,63 +282,167 @@ function roster(peers: JobBot[]): string {
200
282
 
201
283
  ${peers.map((bot) => `- **${bot.name}** — ${bot.description}`).join("\n")}
202
284
 
203
- A part of your job another bot is for goes to \`${TOOL_NAMES.ask_bot}\`, because their tools and their practice are the reason they exist. What you build is made of what they bring back, so send for it before you build. A part you could finish in a couple of commands is yours; one that would take a run of its own is theirs. The job stays yours and you report; they see only your brief — not the call, not this thread.`;
285
+ These lines were written for the user, who reads them on their own screen: where one says "you" it means them, not you.
286
+
287
+ A part of your job another bot is for goes to \`${TOOL_NAMES.ask_bot}\`, because their tools and their practice are the reason they exist. What you build is made of what they bring back, so send for it before you build. A part you could finish in a couple of commands is yours; one that would take a run of its own is theirs. What you were handed stays yours and you answer for it. They get the job, the call it came from and what you write them — not this thread.`;
204
288
  }
205
289
 
206
- /** The only place a run can stop. The user's request to buy, pay or top up is itself the go-ahead. */
290
+ /** The only place a run can stop. */
207
291
  const ASKING = `## Asking
208
292
 
209
293
  What you cannot get for yourself — a decision between real options, a detail only the conversation has, a go-ahead before deleting or sending — goes to \`${TOOL_NAMES.ask_thursday}\`, once, with everything in it. Ask before you start, not after an hour; never ask what one command would tell you.
210
294
 
211
295
  A job that arrives without its shape — several ways to do it, no telling what it is for, a scale nobody named — is planned before it is built: put the plan up in two or three lines with what you need decided. A job asked for as one thing is built, not proposed.
212
296
 
213
- A request that says buy, pay, top up is the go-ahead — press the button. Only what is theirs alone stops the job: a password, a one-time code, a passkey, a permission on their machine. Set it up one action away, ask, and carry on when the answer comes back.`;
297
+ Only what is theirs alone stops the job: a password, a one-time code, a passkey, a permission on their machine. Set it up one action away, ask, and carry on when the answer comes back.`;
214
298
 
215
299
  const askingBack = (askedBy: string) => `## Asking
216
300
 
217
301
  What you cannot get for yourself goes to \`${TOOL_NAMES.ask_back}\`: ${askedBy} handed you this part and answers from what they have. They cannot take a question to the user, so for what is the user's alone take the safer reading and say so in what you hand back. Ask before you start, once, whole.`;
218
302
 
219
- const STEP_CAP = `Your steps are capped at ${BOT_RUN.steps}; running long, report what you have with \`complete: false\` while the summary is still yours to write.`;
220
-
221
303
  /**
222
- * The job ends in the thing that was asked for; no prescribed document shape.
304
+ * An answer is sized by the request, not by the shape of a document: this is where
305
+ * the only upper bound on a run is stated, and the one place that says the spoken
306
+ * line is hers to compose. Nothing here asks for a script — a bot that writes to be
307
+ * heard writes for a length rather than for a question, and the padding it adds to
308
+ * reach that length is steps, not words.
309
+ * The step cap is stated nowhere a bot reads: told the number, runs work to it. It is
310
+ * enforced where it cannot be argued with (bot.run `stepCountIs`, and `lastStep`).
223
311
  * Images in `.md` need absolute routes because a document opens from two places and relative paths resolve differently.
224
312
  */
225
- const FINISHING = `## Finishing
313
+ const ANSWERING = `## Answering
226
314
 
227
- Every job ends with \`${TOOL_NAMES.report}\`, in the user's language, written to be heard she reads it out loud. **The job ends in the thing that was asked for**: an action with the action done, photos in a page with the photos in it, a comparison in a table. Anything that does not fit in a few lines is a file under \`${PATHS.artifacts}/\`, and the report names its path it becomes a link on their screen. In a \`.md\`, images only by absolute route (\`/api/file/${PATHS.artifacts}/…\`).
315
+ Every job ends with \`${TOOL_NAMES.answer}\`. **Answer what was asked, at the size it was asked**: a question ends in its answer one number is one line and a thing to make comes back made, an action done, photos in a page, a comparison in a table. Once you have what they asked for the job is done; the next thing you would go and check is theirs to ask for.
228
316
 
229
- \`complete: false\` when part of the request is genuinely undone say where you got to and the user decides. ${STEP_CAP}`;
317
+ You are answering Thursday, not the user: she is on the call and picks what to say out of this. Write it plainly, in the user's language — the thread is on their screen as you write it. Anything past a few lines is a file under \`${PATHS.artifacts}/\`, and the answer names its path — it becomes a link on their screen. In a \`.md\`, images only by absolute route (\`/api/file/${PATHS.artifacts}/…\`).`;
230
318
 
231
- const handingUp = (askedBy: string) => `## Finishing
319
+ const handingUp = (askedBy: string) => `## Answering
232
320
 
233
- Every part ends with \`${TOOL_NAMES.report}\`; what you hand back goes into ${askedBy}'s own report. Hand back what the brief asked for, in the shape it asked for, with everything you learned that bears on it — exact values, the paths of files you wrote, what did not work. They cannot see your thread, so long is right here. \`complete: false\` when part of the brief is undone, with where you got to. ${STEP_CAP}`;
321
+ Every part ends with \`${TOOL_NAMES.answer}\`; what you hand back goes into ${askedBy}'s own answer. Hand back what the brief asked for, in the shape it asked for, with everything you learned that bears on it — exact values, the paths of files you wrote, what did not work. They cannot see your thread, so long is right here.`;
234
322
 
235
323
  /** How many turns of the call travel with the job: enough for one missed detail, not enough to bury the request. */
236
324
  export const OPENING_TURNS = 10;
237
- const OPENING_TURN_CHARS = 160;
325
+
326
+ /** A user message's content; every seat's first message is two text parts (buildTaskOpening). */
327
+ export type OpeningContent = Extract<ModelMessage, { role: "user" }>["content"];
238
328
 
239
329
  /**
240
- * The first message a bot reads: the request plus the last turns of the call, verbatim.
241
- * The request is one sentence the realtime model produced; a detail the user said may only be here.
242
- * Stored as the thread's first row (seq 0) so it survives a resume (bot.runner).
330
+ * The first message of the bot holding a job, stored as the thread's first row
331
+ * (seq 0, bot.runner startTask) and read whole on every resume and after every
332
+ * compaction. Two text parts: who is who on this job, then the chain — the job
333
+ * as Thursday handed it and the call it came from, verbatim, because the request
334
+ * is one sentence the realtime model produced and a detail the user said may
335
+ * only be in the call. The chain is what a borrowed bot inherits (buildHandoff),
336
+ * so its headings name people and never say "you".
243
337
  */
244
338
  export function buildTaskOpening(input: {
339
+ bot: string;
245
340
  request: string;
246
341
  conversation: { role: "user" | "assistant"; text: string }[];
247
- }): string {
342
+ }): OpeningContent {
248
343
  const turns = input.conversation.filter((turn) => turn.text.trim());
249
- if (!turns.length) return input.request;
344
+ const job = `## Thursday → ${input.bot}: the job\n\n${input.request.trim()}`;
345
+ const call = turns.length
346
+ ? `## The call the job came from — its last ${turns.length} turns, verbatim
347
+
348
+ A detail missing from the job may be here — a name, a number, which of two. Where the two disagree the job wins, unless they asked out loud for something to be done and the job only asks about it: then the doing is the job.
250
349
 
251
- const lines = turns.map(
350
+ ${turns
351
+ .map(
252
352
  (turn) =>
253
- `${turn.role === "user" ? "user" : "thursday"}: ${clip(turn.text, OPENING_TURN_CHARS)}`,
254
- );
255
- return `${input.request}
353
+ `${turn.role === "user" ? "user" : "thursday"}: ${clip(turn.text, PROMPT_LINE.callTurn)}`,
354
+ )
355
+ .join("\n")}`
356
+ : "";
357
+ return [
358
+ { type: "text", text: whoIsWho([input.bot]) },
359
+ { type: "text", text: [job, call].filter(Boolean).join("\n\n") },
360
+ ];
361
+ }
256
362
 
257
- ## The call, just before this reached you
363
+ /**
364
+ * The first message of a borrowed bot, built by the bot that borrows it (bot.run
365
+ * `ask_bot`) and never stored: the chain it inherits, copied as it is, then what
366
+ * the borrowing bot has done and the part it hands over. `bots` runs from the
367
+ * bot holding the job down to this one, so each hand-off adds one name and two
368
+ * sections and every seat reads the same shape.
369
+ */
370
+ export function buildHandoff(input: {
371
+ chain: string;
372
+ bots: string[];
373
+ did: string | null;
374
+ part: string;
375
+ }): OpeningContent {
376
+ const to = input.bots.at(-1) ?? "";
377
+ const from = input.bots.at(-2) ?? "";
378
+ const did = input.did?.trim()
379
+ ? `## ${from} → ${to}: what ${from} has done, and why this part is ${to}'s\n\n${input.did.trim()}`
380
+ : "";
381
+ const part = `## ${from} → ${to}: the part\n\n${input.part.trim()}`;
382
+ return [
383
+ { type: "text", text: whoIsWho(input.bots) },
384
+ {
385
+ type: "text",
386
+ text: [input.chain, did, part].filter(Boolean).join("\n\n"),
387
+ },
388
+ ];
389
+ }
258
390
 
259
- A detail that is not in the request may be here — a name, a number, which one of two. The request wins where they disagree, with one exception: when they asked out loud for something to be *done* and the request only asks about it, the doing is the job.
391
+ /**
392
+ * The chain out of a seat's first message, for the next hand-off. A thread
393
+ * opened before the two-part shape has its opening as one string, which is the
394
+ * whole chain there was.
395
+ */
396
+ export function chainOf(first: ModelMessage | undefined): string {
397
+ if (first?.role !== "user") return "";
398
+ if (typeof first.content === "string") return first.content;
399
+ const texts = first.content.flatMap((part) =>
400
+ part.type === "text" ? [part.text] : [],
401
+ );
402
+ return texts.at(-1) ?? "";
403
+ }
260
404
 
405
+ /** Who is who on this job; the last of `bots` is the one reading it. */
406
+ function whoIsWho(bots: string[]): string {
407
+ const you = bots.length - 1;
408
+ const lines = bots.map((bot, index) => {
409
+ if (index === 0) {
410
+ return index === you
411
+ ? `- **${bot} (you)** — Thursday handed you this job. You answer to Thursday, and your answer is the only part of it that reaches the user.`
412
+ : `- **${bot}** — holds the job Thursday handed over, and answers for it.`;
413
+ }
414
+ const from = bots[index - 1];
415
+ return index === you
416
+ ? `- **${bot} (you)** — ${from} handed you one part of it: the last section below. You answer to ${from}; nobody else hears from you.`
417
+ : `- **${bot}** — ${from} handed them one part of it.`;
418
+ });
419
+ return `## Who is who on this job
420
+
421
+ - **The user** — talks only to Thursday, on a voice call. No bot addresses them.
422
+ - **Thursday** — the user's assistant on that call. Hands jobs to bots and tells the user what comes back.
261
423
  ${lines.join("\n")}`;
262
424
  }
425
+
426
+ /** One line per kind, absences included. Only a bot gets these: the call runs one command as a glance. */
427
+ function machineLines(machine: MachineTools): string {
428
+ const line = (label: string, of: MachineTools["runtimes"]) =>
429
+ `${label}: ${of.found.length ? of.found.join(", ") : "none"}.${
430
+ of.missing.length ? ` Not here: ${of.missing.join(", ")}.` : ""
431
+ }`;
432
+ // Not a preference: openWorkspace writes the pnpm fence, and an `npm install`
433
+ // in a project here resolves against that rather than against the project
434
+ const fenced = machine.managers.found.includes("pnpm")
435
+ ? " Use pnpm, not npm — this workspace is fenced for it (`pnpm-workspace.yaml`, `.npmrc`)."
436
+ : "";
437
+ return [
438
+ line("Runtimes", machine.runtimes),
439
+ `${line("Package managers", machine.managers)}${fenced}`,
440
+ machine.browser === null
441
+ ? ""
442
+ : machine.browser
443
+ ? "Browser: installed."
444
+ : "Browser: not installed — `playwright-cli install-browser chromium` puts one there.",
445
+ ]
446
+ .filter(Boolean)
447
+ .join("\n");
448
+ }
@@ -0,0 +1,33 @@
1
+ import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
2
+ import { listNoteIndex } from "@/features/memory/memory.query";
3
+ import { MEMORY_PATHS } from "@/features/memory/memory.schema";
4
+ import { logPromptSize, noteLines, nowLine } from "./prompt-helper";
5
+
6
+ /**
7
+ * Everything an edit from the memory screen hears (features/memory/memory.edit):
8
+ * who it is working for, and memory as a listing — one line a note, with how
9
+ * many facts it holds — the way the call sees it. Facts and their ids come from
10
+ * opening a note, so the prompt grows with the number of notes, not of facts.
11
+ * Assembled once per request.
12
+ */
13
+ export async function loadMemoryEditPrompt(): Promise<string> {
14
+ const text = [identity(), memory(await listNoteIndex())].join("\n\n");
15
+ logPromptSize("memory-edit", text);
16
+ return text;
17
+ }
18
+
19
+ function identity(): string {
20
+ return `You are the user's personal assistant, and this is their memory. Change it the way their message asks: add what is new, replace what stopped being true, remove what they want gone. Make every change with \`${TOOL_NAMES.memory_remember}\` and \`${TOOL_NAMES.memory_forget}\`; when nothing is left to change, stop. ${nowLine()}`;
21
+ }
22
+
23
+ function memory(index: Awaited<ReturnType<typeof listNoteIndex>>): string {
24
+ return `## Memory
25
+
26
+ path — what is under it (facts) "what the user calls it"
27
+
28
+ ${noteLines(index)}
29
+
30
+ A note is listed, not shown: open it with \`${TOOL_NAMES.memory_recall}\` for its facts and their ids before replacing or removing any of them. Adding to a note needs no opening.
31
+
32
+ ${MEMORY_PATHS.map((entry) => `- ${entry.path} — ${entry.of}`).join("\n")}`;
33
+ }
@@ -1,15 +1,16 @@
1
1
  import { format, formatDistanceToNowStrict } from "date-fns";
2
- import { MEMORY_LISTING_TOKENS, PROMPT_LINE } from "@/config";
2
+ import { MEMORY_LIMITS, PROMPT_BUDGET, PROMPT_LINE } from "@/config";
3
3
  import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
4
4
  import type { McpToolRef } from "@/features/connectors/mcp.schema";
5
5
  import type {
6
6
  MemoryAlwaysLoaded,
7
7
  MemoryIndexEntry,
8
8
  } from "@/features/memory/memory.schema";
9
- import { MANY_FACTS } from "@/features/memory/memory.schema";
10
9
  import type { SkillMetadata } from "@/features/skills/skills.discover";
10
+ import { delegatedLabel } from "@/features/thursday/tool-line";
11
11
  import { toDate } from "@/lib/date-like";
12
- import { estimateTokens } from "@/lib/tokens";
12
+ import { logger } from "@/lib/logger";
13
+ import { estimateTokens, sectionTokens } from "@/lib/tokens";
13
14
  import { clip } from "@/lib/utils";
14
15
 
15
16
  /**
@@ -26,12 +27,67 @@ export type LoadedPrompt = {
26
27
  opening: string | null;
27
28
  };
28
29
 
29
- /** `**Now**: 2026-09-02 (Wed) 15:41 Asia/Seoul` */
30
- export const nowLine = (now = new Date()) =>
31
- `**Now**: ${format(now, "yyyy-MM-dd (EEE) HH:mm")} ${
30
+ /**
31
+ * What one assembled prompt costs, said where it is assembled. The debug line is
32
+ * the whole breakdown; past PROMPT_BUDGET it is a warning naming the chapter
33
+ * carrying it, and that one is always a listing the user can act on — nothing
34
+ * else in the app would ever say a prompt had grown.
35
+ */
36
+ export function logPromptSize(kind: string, text: string): void {
37
+ const parts = sectionTokens(text);
38
+ const total = parts.reduce((sum, part) => sum + part.tokens, 0);
39
+ logger.debug(
40
+ `${kind} prompt ${total} tokens — ${parts
41
+ .map((part) => `${part.name} ${part.tokens}`)
42
+ .join(", ")}`,
43
+ );
44
+ const biggest = parts[0];
45
+ if (total > PROMPT_BUDGET && biggest) {
46
+ logger.warn(
47
+ `${kind} prompt is ${total} tokens, over ${PROMPT_BUDGET}: ${biggest.name} carries ${biggest.tokens} of it. Every call and every job pays this.`,
48
+ );
49
+ }
50
+ }
51
+
52
+ /** `2026-09-02 (Wed) 15:41 Asia/Seoul` */
53
+ export const clockNow = (now = new Date()) =>
54
+ `${format(now, "yyyy-MM-dd (EEE) HH:mm")} ${
32
55
  Intl.DateTimeFormat().resolvedOptions().timeZone
33
56
  }`;
34
57
 
58
+ /** `**Now**: 2026-09-02 (Wed) 15:41 Asia/Seoul` */
59
+ export const nowLine = (now = new Date()) => `**Now**: ${clockNow(now)}`;
60
+
61
+ /**
62
+ * When a call happened, the one way every prompt and tool says it: local, the
63
+ * same shape as `Now` (clockNow), with how long ago. A UTC stamp beside a local
64
+ * `Now` put two clocks nine hours apart in one prompt, and a call from last
65
+ * night read as one from this afternoon.
66
+ */
67
+ export const callStamp = (at: Date): string =>
68
+ `${format(at, "yyyy-MM-dd (EEE) HH:mm")} (${formatDistanceToNowStrict(at, { addSuffix: true })})`;
69
+
70
+ /** When a fact was said, for the fact itself: the date and time without the distance. */
71
+ export const saidStamp = (at: Date): string =>
72
+ format(at, "yyyy-MM-dd (EEE) HH:mm");
73
+
74
+ /**
75
+ * A call as a conversation: who said what, and which tool was used — never its
76
+ * arguments or its result. What was asked for and what was said back is the
77
+ * conversation; the arguments are already in memory and the results are not
78
+ * what anyone said.
79
+ */
80
+ export const conversationLines = (
81
+ turns: { role: string; tool: string | null; text: string }[],
82
+ ): string =>
83
+ turns
84
+ .map((turn) =>
85
+ turn.role === "tool"
86
+ ? `you → ${turn.tool ?? "tool"}`
87
+ : `${turn.role === "user" ? "user" : "you"}: ${turn.text}`,
88
+ )
89
+ .join("\n");
90
+
35
91
  /** `4mo`, `12d`: short enough to read aloud. */
36
92
  function sinceLast(at: MemoryIndexEntry["lastSeenAt"]): string {
37
93
  const days = Math.floor((Date.now() - toDate(at).getTime()) / 86_400_000);
@@ -59,13 +115,15 @@ export const carriedLines = (loaded: MemoryAlwaysLoaded[]): string =>
59
115
  loaded.map((fact) => `- ${fact.text} · ${fact.path} #${fact.id}`).join("\n");
60
116
 
61
117
  /**
62
- * Whether it is time to tidy, and why: a crowded listing points at the coldest notes,
63
- * a heavy note at itself. load-tools also reads this to decide whether `memory_show` is attached.
118
+ * Whether it is time to tidy, and why: too much held in all (the coldest notes
119
+ * are what to drop), or one note too long to hold in one piece (it names itself).
120
+ * Both counted in facts, the unit the user sees on their own screen and the one
121
+ * every write hands back — a token estimate is nobody's unit and cannot be acted on.
64
122
  */
65
123
  export const tidying = (index: MemoryIndexEntry[]) => ({
66
- // The age column is only shown when picking what to drop
67
- crowded: estimateTokens(noteLines(index)) > MEMORY_LISTING_TOKENS,
68
- heavy: index.filter((note) => note.factCount > MANY_FACTS),
124
+ crowded:
125
+ index.reduce((sum, note) => sum + note.factCount, 0) > MEMORY_LIMITS.facts,
126
+ heavy: index.filter((note) => note.factCount > MEMORY_LIMITS.factsPerNote),
69
127
  });
70
128
 
71
129
  /** A bot gets the whole description; `short` gives the voice prompt the first sentence only. */
@@ -132,9 +190,6 @@ export type RecentCall = {
132
190
  }[];
133
191
  };
134
192
 
135
- /** How much of a past job's report is worth carrying; the rest is asked for with `task`. */
136
- const JOB_OUTCOME = 160;
137
-
138
193
  /**
139
194
  * One turn as the transcript carries it. A `delegate` line takes what became of
140
195
  * the job: the handle to pick it back up, and how it ended — arguments alone say
@@ -147,25 +202,20 @@ function turnLine(turn: RecentCall["turns"][number], call: RecentCall): string {
147
202
  const args = `you → ${turn.tool ?? "tool"} ${clip(turn.text, PROMPT_LINE.toolArgs)}`;
148
203
  if (turn.tool !== TOOL_NAMES.delegate) return args;
149
204
 
150
- const label = ((): string | null => {
151
- try {
152
- const said = JSON.parse(turn.text) as { label?: unknown };
153
- return typeof said.label === "string" ? said.label : null;
154
- } catch {
155
- return null;
156
- }
157
- })();
205
+ const label = delegatedLabel(turn.tool, turn.text);
158
206
  const job = label ? call.jobs?.find((one) => one.label === label) : undefined;
159
207
  if (!job) return args;
160
208
 
161
- const said = job.outcome ? `: ${clip(job.outcome, JOB_OUTCOME)}` : "";
209
+ const said = job.outcome
210
+ ? `: ${clip(job.outcome, PROMPT_LINE.jobOutcome)}`
211
+ : "";
162
212
  return `you → ${turn.tool} "${job.label}" (${job.id}) — ${job.status}${said}`;
163
213
  }
164
214
 
165
215
  /** The last calls as stored, newest last, cut to a token budget. A tool turn carries the call, not the result. */
166
216
  export function recentCallLines(calls: RecentCall[], budget: number): string {
167
217
  // Newest line backwards until the budget is spent, then put it back in order.
168
- // Measured on the rendered line: a job's report is on it and its arguments are not
218
+ // Measured on the rendered line: a job's answer is on it and its arguments are not
169
219
  const kept: { call: RecentCall; line: string }[] = [];
170
220
  let spent = 0;
171
221
  outer: for (let c = calls.length - 1; c >= 0; c--) {
@@ -185,12 +235,7 @@ export function recentCallLines(calls: RecentCall[], budget: number): string {
185
235
  for (const { call, line } of kept) {
186
236
  if (call !== open) {
187
237
  open = call;
188
- const when = formatDistanceToNowStrict(call.startedAt, {
189
- addSuffix: true,
190
- });
191
- lines.push(
192
- `### ${call.startedAt.toISOString().slice(0, 16).replace("T", " ")} (${when})`,
193
- );
238
+ lines.push(`### ${callStamp(call.startedAt)}`);
194
239
  }
195
240
  lines.push(line);
196
241
  }