thursday-agent 0.2.0 → 0.4.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 (541) 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 +12 -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 +25 -0
  134. package/.next/server/chunks/_051qh8u._.js +3 -0
  135. package/.next/server/chunks/{node_modules_next_04q-o58._.js → _05dla15._.js} +2 -2
  136. package/.next/server/chunks/_05h2cii._.js +1 -1
  137. package/.next/server/chunks/_0c9j6rb._.js +49 -0
  138. package/.next/server/chunks/_0fzqt2y._.js +134 -0
  139. package/.next/server/chunks/{_0vnutv9._.js → _0ioz3nd._.js} +1 -1
  140. package/.next/server/chunks/_0iwfby5._.js +3 -0
  141. package/.next/server/chunks/_0mecv0f._.js +26 -0
  142. package/.next/server/chunks/_0mh8j4m._.js +3 -0
  143. package/.next/server/chunks/_0n74zsf._.js +4 -4
  144. package/.next/server/chunks/_0obojvv._.js +3 -0
  145. package/.next/server/chunks/_0recufk._.js +49 -0
  146. package/.next/server/chunks/_0rnf-6n._.js +4 -4
  147. package/.next/server/chunks/_0sb7tlz._.js +3 -0
  148. package/.next/server/chunks/_0u10wmw._.js +5 -5
  149. package/.next/server/chunks/_0u4aiy2._.js +3 -0
  150. package/.next/server/chunks/_0wp4le3._.js +1 -1
  151. package/.next/server/chunks/_0y5fg-x._.js +1 -1
  152. package/.next/server/chunks/_1230wbx._.js +10 -0
  153. package/.next/server/chunks/_12nheja._.js +3 -0
  154. package/.next/server/chunks/_13510xh._.js +3 -0
  155. package/.next/server/chunks/_15hq89o._.js +1 -1
  156. package/.next/server/chunks/_17l5ygt._.js +49 -0
  157. package/.next/server/chunks/_18-1wcc._.js +5 -5
  158. package/.next/server/chunks/_1_5mnq4._.js +4 -4
  159. package/.next/server/chunks/_1_9mjx-._.js +3 -0
  160. package/.next/server/chunks/{_0pppbb5._.js → _1c78vw5._.js} +166 -37
  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]__092knlj._.js +3 -0
  195. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  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]__0s9dq5u._.js +3 -0
  200. package/.next/server/chunks/ssr/{[root-of-the-server]__0m1b5ky._.js → [root-of-the-server]__0s9l2sv._.js} +1 -1
  201. package/.next/server/chunks/ssr/[root-of-the-server]__0tbkdlx._.js +3 -0
  202. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +3 -0
  203. package/.next/server/chunks/ssr/{[root-of-the-server]__0f6s48x._.js → [root-of-the-server]__0xpcv9w._.js} +3 -3
  204. package/.next/server/chunks/ssr/[root-of-the-server]__0xsog8n._.js +3 -0
  205. package/.next/server/chunks/ssr/[root-of-the-server]__0xtssj3._.js +1 -1
  206. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +61 -0
  207. package/.next/server/chunks/ssr/[root-of-the-server]__15_uhip._.js +3 -0
  208. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  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]__1qfqvmg._.js → [root-of-the-server]__202p40z._.js} +2 -2
  213. package/.next/server/chunks/ssr/{_1mznrxk._.js → _001_ms1._.js} +3 -3
  214. package/.next/server/chunks/ssr/_01n3o0m._.js +3 -0
  215. package/.next/server/chunks/ssr/_0ap2fzn._.js +3 -0
  216. package/.next/server/chunks/ssr/_0fz4mf_._.js +3 -0
  217. package/.next/server/chunks/ssr/_0gb4gmf._.js +3 -0
  218. package/.next/server/chunks/ssr/_0h42fze._.js +3 -0
  219. package/.next/server/chunks/ssr/_0h7zdni._.js +1 -1
  220. package/.next/server/chunks/ssr/_0i_6q1w._.js +41 -0
  221. package/.next/server/chunks/ssr/_0ilna52._.js +42 -0
  222. package/.next/server/chunks/ssr/_0n3toaw._.js +3 -0
  223. package/.next/server/chunks/ssr/{_13punpm._.js → _0q0zan6._.js} +2 -2
  224. package/.next/server/chunks/ssr/{_077-g6s._.js → _0s99bgb._.js} +3 -3
  225. package/.next/server/chunks/ssr/_0zcjrbg._.js +3 -0
  226. package/.next/server/chunks/ssr/_0zhoc3r._.js +3 -0
  227. package/.next/server/chunks/ssr/{_1lip4th._.js → _1-_etts._.js} +2 -2
  228. package/.next/server/chunks/ssr/_1-teee5._.js +3 -3
  229. package/.next/server/chunks/ssr/_13fke0x._.js +3 -0
  230. package/.next/server/chunks/ssr/_15j2_8f._.js +3 -0
  231. package/.next/server/chunks/ssr/_1b2mjwr._.js +3 -0
  232. package/.next/server/chunks/ssr/{_09ja_w1._.js → _1f-dg-6._.js} +2 -2
  233. package/.next/server/chunks/ssr/_1fojd41._.js +4 -0
  234. package/.next/server/chunks/ssr/_1gd8q8l._.js +3 -0
  235. package/.next/server/chunks/ssr/{_1m3bsfr._.js → _1h0rw11._.js} +2 -2
  236. package/.next/server/chunks/ssr/_1jhd09t._.js +3 -0
  237. package/.next/server/chunks/ssr/{_040sk32._.js → _1lz_cq2._.js} +84 -88
  238. package/.next/server/chunks/ssr/_1nnsk7z._.js +3 -0
  239. package/.next/server/chunks/ssr/_1sji22n._.js +3 -0
  240. package/.next/server/chunks/ssr/{_0x_nu5e._.js → _1vi_uo7._.js} +2 -2
  241. package/.next/server/chunks/ssr/_1vyd1ji._.js +1 -1
  242. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +3 -0
  243. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  244. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  245. package/.next/server/chunks/ssr/{node_modules_0kxz4gt._.js → node_modules_00etblx._.js} +1 -1
  246. package/.next/server/chunks/ssr/{node_modules_18_dk7_._.js → node_modules_04jf_m8._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_0_n241r._.js → node_modules_08dhkiq._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_0n1kj4p._.js → node_modules_0940ns5._.js} +1 -1
  249. package/.next/server/chunks/ssr/{node_modules_17lrt3y._.js → node_modules_09q35v_._.js} +1 -1
  250. package/.next/server/chunks/ssr/{node_modules_1toafc-._.js → node_modules_0_-_a--._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_0lrjk5t._.js → node_modules_0arus10._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_04n7mjs._.js → node_modules_0b__sgl._.js} +1 -1
  253. package/.next/server/chunks/ssr/{node_modules_0iz1rzd._.js → node_modules_0cxaxk9._.js} +1 -1
  254. package/.next/server/chunks/ssr/{node_modules_0ndvxub._.js → node_modules_0g7fzk3._.js} +1 -1
  255. package/.next/server/chunks/ssr/{node_modules_0kl7-tn._.js → node_modules_0had7xd._.js} +1 -1
  256. package/.next/server/chunks/ssr/{node_modules_19dp7ko._.js → node_modules_0pvd7q-._.js} +1 -1
  257. package/.next/server/chunks/ssr/node_modules_0x3-ply._.js +3 -0
  258. package/.next/server/chunks/ssr/{node_modules_1dwguw_._.js → node_modules_0yugy6m._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_004qlr4._.js → node_modules_14om4ar._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_1q0p85z._.js → node_modules_14q6g4n._.js} +1 -1
  261. package/.next/server/chunks/ssr/node_modules_17bwo43._.js +55 -0
  262. package/.next/server/chunks/ssr/{node_modules_1hd-5tv._.js → node_modules_198nmll._.js} +1 -1
  263. package/.next/server/chunks/ssr/{node_modules_0m93zeg._.js → node_modules_1_pc9kq._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_1n5ygqe._.js → node_modules_1aaxuef._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_01qnv-a._.js → node_modules_1cx_ql6._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_1zu988w._.js → node_modules_1cz2hle._.js} +1 -1
  267. package/.next/server/chunks/ssr/{node_modules_1xyd7ov._.js → node_modules_1efrqxi._.js} +1 -1
  268. package/.next/server/chunks/ssr/{node_modules_13r44jq._.js → node_modules_1eg7m6c._.js} +1 -1
  269. package/.next/server/chunks/ssr/{node_modules_08d8bke._.js → node_modules_1gdh31p._.js} +1 -1
  270. package/.next/server/chunks/ssr/{node_modules_1hn8z1f._.js → node_modules_1hpopmo._.js} +1 -1
  271. package/.next/server/chunks/ssr/{node_modules_20yebtj._.js → node_modules_1qpjvy5._.js} +1 -1
  272. package/.next/server/chunks/ssr/{node_modules_09xhur7._.js → node_modules_1vh5ntv._.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_1b748ic._.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_1z4hm5e._.js} +1 -1
  275. package/.next/server/chunks/ssr/node_modules_@vercel_oidc_dist_06mk8id._.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/00rd4-v8r7axp.js +1 -0
  285. package/.next/static/chunks/08qe4as2q428z.js +3 -0
  286. package/.next/static/chunks/{31ttnjt6g35a0.js → 0ev4hyghq0mbb.js} +1 -1
  287. package/.next/static/chunks/0fl3gwe4-l6tz.js +1 -0
  288. package/.next/static/chunks/0gnqdjn2lvdad.js +2 -0
  289. package/.next/static/chunks/0hwap1-p0m5sa.js +1 -0
  290. package/.next/static/chunks/0r5qcctujhxli.js +1 -0
  291. package/.next/static/chunks/0w52rrrmuj9r9.js +1 -0
  292. package/.next/static/chunks/{07kl352c-lvcz.js → 0wcprt5ot5she.js} +1 -1
  293. package/.next/static/chunks/10teww7wt-f6h.js +1 -0
  294. package/.next/static/chunks/15m575979un5f.js +38 -0
  295. package/.next/static/chunks/17p6tk6k88dq6.js +1 -0
  296. package/.next/static/chunks/{3_h9txt3tq8t8.js → 1dkjg87pxk0n9.js} +1 -1
  297. package/.next/static/chunks/1jd09sxcjddu1.js +1 -0
  298. package/.next/static/chunks/1kq8h8wi_e0bc.js +53 -0
  299. package/.next/static/chunks/{18vhba44l1fc9.js → 1w73ece_6bheu.js} +1 -1
  300. package/.next/static/chunks/{3ard_noqapnw1.js → 214ya3n5gxeih.js} +1 -1
  301. package/.next/static/chunks/22_zkas21rpna.js +1 -0
  302. package/.next/static/chunks/2h0sd2vumhb15.js +1 -0
  303. package/.next/static/chunks/2t4vhi3m8ahya.js +1 -0
  304. package/.next/static/chunks/2tigdtz3dpcy8.js +1 -0
  305. package/.next/static/chunks/2u7xt6mxg44lf.js +1 -0
  306. package/.next/static/chunks/39j0fvpybzabl.js +40 -0
  307. package/.next/static/chunks/3akmqm77muj4-.js +1 -0
  308. package/.next/static/chunks/3cq5g494yuke8.css +1 -0
  309. package/.next/static/chunks/3woj-xd7ki5_i.js +1 -0
  310. package/.next/static/chunks/3xk7yqgomx7yq.js +1 -0
  311. package/.next/static/chunks/3zmcsnuo25zvq.js +1 -0
  312. package/.next/static/media/favicon.37o1pjldwi2uc.ico +0 -0
  313. package/README.md +47 -22
  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 -7
  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/port.mjs +65 -0
  324. package/bin/thursday.mjs +5 -33
  325. package/components/ui/shiny-text.tsx +48 -134
  326. package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/migration.sql +24 -34
  327. package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/snapshot.json +71 -145
  328. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +1 -0
  329. package/database/migrations/{20260909063821_bitter_tenebrous → 20260911030320_opposite_jack_power}/snapshot.json +57 -184
  330. package/docs/how-it-works.md +11 -7
  331. package/docs/images/face-dark.png +0 -0
  332. package/docs/images/face-light.png +0 -0
  333. package/docs/images/keeps-going.png +0 -0
  334. package/features/ai/chatgpt.ts +639 -0
  335. package/features/ai/components/chatgpt-sign-in.tsx +66 -0
  336. package/features/ai/components/model-picker.tsx +17 -1
  337. package/features/ai/components/provider-icon.tsx +1 -0
  338. package/features/ai/load-tools.ts +78 -56
  339. package/features/ai/model.schema.ts +232 -34
  340. package/features/ai/model.ts +169 -24
  341. package/features/ai/prompts/bot.prompt.ts +207 -114
  342. package/features/ai/prompts/memory-edit.prompt.ts +33 -0
  343. package/features/ai/prompts/prompt-helper.ts +45 -26
  344. package/features/ai/prompts/thursday.prompt.ts +57 -27
  345. package/features/ai/tools/bot.tool.ts +35 -52
  346. package/features/ai/tools/connected.ts +17 -4
  347. package/features/ai/tools/memory.tool.ts +181 -117
  348. package/features/ai/tools/search.tool.ts +136 -47
  349. package/features/ai/tools/tool-name.ts +2 -6
  350. package/features/ai/tools/workspace.tool.ts +5 -1
  351. package/features/bot/bot.action.ts +14 -19
  352. package/features/bot/bot.memory.ts +89 -0
  353. package/features/bot/bot.query.ts +37 -57
  354. package/features/bot/bot.run.ts +512 -242
  355. package/features/bot/bot.runner.ts +434 -120
  356. package/features/bot/bot.schema.ts +104 -19
  357. package/features/bot/bot.seed.ts +89 -16
  358. package/features/bot/components/bot-mark.tsx +122 -20
  359. package/features/bot/components/bot-room.tsx +214 -132
  360. package/features/bot/components/bot-setting.tsx +790 -402
  361. package/features/bot/components/bot-tool.tsx +2 -7
  362. package/features/bot/components/mark-palette.tsx +54 -0
  363. package/features/bot/components/path-chips.tsx +1 -1
  364. package/features/bot/components/task-badge.tsx +26 -6
  365. package/features/bot/components/task-reply.tsx +22 -33
  366. package/features/bot/components/task-setting.tsx +20 -17
  367. package/features/bot/task.query.ts +240 -34
  368. package/features/bot/task.store.ts +76 -13
  369. package/features/config/components/config-setting.tsx +265 -34
  370. package/features/config/components/models-badge.tsx +42 -0
  371. package/features/config/config.action.ts +12 -0
  372. package/features/config/config.const.ts +38 -2
  373. package/features/connectors/mcp.manager.ts +10 -2
  374. package/features/intro/components/intro.tsx +47 -46
  375. package/features/memory/components/memory-edit.tsx +340 -0
  376. package/features/memory/components/memory-setting.tsx +75 -77
  377. package/features/memory/memory.action.ts +3 -43
  378. package/features/memory/memory.edit.ts +87 -0
  379. package/features/memory/memory.query.ts +24 -42
  380. package/features/memory/memory.schema.ts +29 -106
  381. package/features/settings/components/settings.tsx +2 -0
  382. package/features/settings/settings.alert.ts +3 -1
  383. package/features/thursday/components/ascii-orb.tsx +106 -90
  384. package/features/thursday/components/boot.tsx +7 -0
  385. package/features/thursday/components/call-log.tsx +219 -92
  386. package/features/thursday/components/face.tsx +6 -4
  387. package/features/thursday/components/tab-state.tsx +97 -0
  388. package/features/thursday/components/thursday-mark.tsx +4 -1
  389. package/features/thursday/components/thursday-setting.tsx +17 -47
  390. package/features/thursday/components/thursday.tsx +208 -98
  391. package/features/thursday/thursday.action.ts +12 -17
  392. package/features/thursday/thursday.query.ts +61 -70
  393. package/features/thursday/thursday.schema.ts +20 -7
  394. package/features/thursday/tool-line.ts +85 -12
  395. package/features/thursday/use-thursday.ts +87 -60
  396. package/features/workspace/components/file-view.tsx +4 -2
  397. package/features/workspace/workspace.ts +110 -26
  398. package/lib/limits.ts +1 -1
  399. package/lib/oauth-page.ts +27 -0
  400. package/lib/realtime/openai.ts +2 -2
  401. package/lib/realtime/realtime.protocol.ts +1 -1
  402. package/lib/realtime/realtime.tap.ts +122 -0
  403. package/lib/sandbox.ts +59 -36
  404. package/package.json +1 -1
  405. package/skills/browser/SKILL.md +55 -34
  406. package/.next/server/app/api/bot/notes/route/app-paths-manifest.json +0 -3
  407. package/.next/server/app/api/bot/notes/route.js +0 -14
  408. package/.next/server/app/api/bot/notes/route_client-reference-manifest.js +0 -3
  409. package/.next/server/app/api/memory/tidy/route/app-paths-manifest.json +0 -3
  410. package/.next/server/app/api/memory/tidy/route.js +0 -22
  411. package/.next/server/app/api/memory/tidy/route.js.nft.json +0 -1
  412. package/.next/server/chunks/0d-b_next_dist_server_app-render_after-task-async-storage_external_0-exn7p.js +0 -3
  413. package/.next/server/chunks/[root-of-the-server]__0-npkh_._.js +0 -3
  414. package/.next/server/chunks/[root-of-the-server]__005var5._.js +0 -3
  415. package/.next/server/chunks/[root-of-the-server]__019dx9f._.js +0 -5
  416. package/.next/server/chunks/[root-of-the-server]__02_2sm-._.js +0 -5
  417. package/.next/server/chunks/[root-of-the-server]__04_8spk._.js +0 -3
  418. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +0 -3
  419. package/.next/server/chunks/[root-of-the-server]__06t77t4._.js +0 -11
  420. package/.next/server/chunks/[root-of-the-server]__0bed6hu._.js +0 -8
  421. package/.next/server/chunks/[root-of-the-server]__0cro2dz._.js +0 -5
  422. package/.next/server/chunks/[root-of-the-server]__0dupqt7._.js +0 -5
  423. package/.next/server/chunks/[root-of-the-server]__0emr6go._.js +0 -3
  424. package/.next/server/chunks/[root-of-the-server]__0le4d-p._.js +0 -3
  425. package/.next/server/chunks/[root-of-the-server]__0m8ywyo._.js +0 -10
  426. package/.next/server/chunks/[root-of-the-server]__0nfuugi._.js +0 -5
  427. package/.next/server/chunks/[root-of-the-server]__0p32jfz._.js +0 -12
  428. package/.next/server/chunks/[root-of-the-server]__0phdgco._.js +0 -8
  429. package/.next/server/chunks/[root-of-the-server]__0wvgrsl._.js +0 -3
  430. package/.next/server/chunks/[root-of-the-server]__10qshki._.js +0 -3
  431. package/.next/server/chunks/[root-of-the-server]__11j52t0._.js +0 -5
  432. package/.next/server/chunks/[root-of-the-server]__1692zrv._.js +0 -3
  433. package/.next/server/chunks/[root-of-the-server]__16thabu._.js +0 -3
  434. package/.next/server/chunks/[root-of-the-server]__173nhwf._.js +0 -8
  435. package/.next/server/chunks/[root-of-the-server]__1_aoyr9._.js +0 -3
  436. package/.next/server/chunks/[root-of-the-server]__1bn73ih._.js +0 -10
  437. package/.next/server/chunks/[root-of-the-server]__1bqhuh9._.js +0 -8
  438. package/.next/server/chunks/[root-of-the-server]__1cqizfq._.js +0 -5
  439. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +0 -3
  440. package/.next/server/chunks/[root-of-the-server]__1fboj2j._.js +0 -3
  441. package/.next/server/chunks/[root-of-the-server]__1lr7j9t._.js +0 -5
  442. package/.next/server/chunks/[root-of-the-server]__1oli73c._.js +0 -3
  443. package/.next/server/chunks/[root-of-the-server]__1txedx6._.js +0 -8
  444. package/.next/server/chunks/[root-of-the-server]__1untqv8._.js +0 -5
  445. package/.next/server/chunks/[root-of-the-server]__1zgpz1w._.js +0 -3
  446. package/.next/server/chunks/_00_584r._.js +0 -293
  447. package/.next/server/chunks/_012yhfm._.js +0 -39
  448. package/.next/server/chunks/_06mxlgn._.js +0 -3
  449. package/.next/server/chunks/_07rtlxv._.js +0 -3
  450. package/.next/server/chunks/_0a351g7._.js +0 -6
  451. package/.next/server/chunks/_0kjjmag._.js +0 -3
  452. package/.next/server/chunks/_0nn99o2._.js +0 -3
  453. package/.next/server/chunks/_0zuzmt_._.js +0 -39
  454. package/.next/server/chunks/_106co2o._.js +0 -3
  455. package/.next/server/chunks/_12bbv5i._.js +0 -100
  456. package/.next/server/chunks/_15q1pig._.js +0 -3
  457. package/.next/server/chunks/_19wg5yn._.js +0 -138
  458. package/.next/server/chunks/_1bt95p9._.js +0 -55
  459. package/.next/server/chunks/_1cbk7ms._.js +0 -26
  460. package/.next/server/chunks/_1drv2et._.js +0 -40
  461. package/.next/server/chunks/_1ic3bew._.js +0 -5
  462. package/.next/server/chunks/_1mxn_lb._.js +0 -3
  463. package/.next/server/chunks/_1rysr-r._.js +0 -10
  464. package/.next/server/chunks/_1u3rwbr._.js +0 -3
  465. package/.next/server/chunks/_1x7p319._.js +0 -6
  466. package/.next/server/chunks/_next-internal_server_app_api_bot_notes_route_actions_0qcsyu7.js +0 -3
  467. package/.next/server/chunks/_next-internal_server_app_api_memory_tidy_route_actions_0_cfuom.js +0 -3
  468. package/.next/server/chunks/features_bot_task_query_ts_11xuzl3._.js +0 -3
  469. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js +0 -3
  470. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0vorg6w._.js +0 -3
  471. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1tpvamf._.js +0 -3
  472. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vmaq9f._.js +0 -3
  473. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1y9-wcr._.js +0 -3
  474. package/.next/server/chunks/ssr/[externals]_node_crypto_1kn79-7._.js +0 -3
  475. package/.next/server/chunks/ssr/[root-of-the-server]__0iuoa-r._.js +0 -3
  476. package/.next/server/chunks/ssr/[root-of-the-server]__0un-erv._.js +0 -4
  477. package/.next/server/chunks/ssr/[root-of-the-server]__1-mnhyd._.js +0 -92
  478. package/.next/server/chunks/ssr/[root-of-the-server]__1bww500._.js +0 -3
  479. package/.next/server/chunks/ssr/[root-of-the-server]__1vcdast._.js +0 -3
  480. package/.next/server/chunks/ssr/[root-of-the-server]__1xwnu-h._.js +0 -3
  481. package/.next/server/chunks/ssr/_0-mc7ro._.js +0 -3
  482. package/.next/server/chunks/ssr/_01p5r6-._.js +0 -3
  483. package/.next/server/chunks/ssr/_03webdr._.js +0 -3
  484. package/.next/server/chunks/ssr/_09-0k3z._.js +0 -3
  485. package/.next/server/chunks/ssr/_0f_b_9s._.js +0 -3
  486. package/.next/server/chunks/ssr/_0fafgvl._.js +0 -3
  487. package/.next/server/chunks/ssr/_0sf1isi._.js +0 -3
  488. package/.next/server/chunks/ssr/_0su6_08._.js +0 -3
  489. package/.next/server/chunks/ssr/_0ti51xc._.js +0 -3
  490. package/.next/server/chunks/ssr/_0w5bgak._.js +0 -3
  491. package/.next/server/chunks/ssr/_0y84qo6._.js +0 -3
  492. package/.next/server/chunks/ssr/_1ciyoo3._.js +0 -3
  493. package/.next/server/chunks/ssr/_1e-dgz0._.js +0 -4
  494. package/.next/server/chunks/ssr/_1fq7zgb._.js +0 -3
  495. package/.next/server/chunks/ssr/_1g6l4uj._.js +0 -3
  496. package/.next/server/chunks/ssr/_1ruzehw._.js +0 -3
  497. package/.next/server/chunks/ssr/features_bot_components_bot-setting_tsx_01ajft6._.js +0 -4
  498. package/.next/server/chunks/ssr/features_config_components_14jqgy4._.js +0 -3
  499. package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +0 -4
  500. package/.next/server/chunks/ssr/node_modules_zod_v4_classic_external_15fmmz3.js +0 -55
  501. package/.next/static/chunks/05b6nx_o3_f_n.js +0 -1
  502. package/.next/static/chunks/0dmns-gi0raa4.js +0 -1
  503. package/.next/static/chunks/0f9sq-7q_yxyl.js +0 -1
  504. package/.next/static/chunks/0oc4_xoia77dg.css +0 -1
  505. package/.next/static/chunks/0pheo8m3a-rzi.js +0 -1
  506. package/.next/static/chunks/19i8h2t-5evjx.js +0 -1
  507. package/.next/static/chunks/1c5fcj473025q.js +0 -1
  508. package/.next/static/chunks/1pi_hbmjw-f-z.js +0 -1
  509. package/.next/static/chunks/1twt6k09vg4np.js +0 -1
  510. package/.next/static/chunks/1ytnip8wdng93.js +0 -1
  511. package/.next/static/chunks/28gotuisldmom.js +0 -1
  512. package/.next/static/chunks/2998p0y7k1c8z.js +0 -3
  513. package/.next/static/chunks/29gyb3nubj51j.js +0 -53
  514. package/.next/static/chunks/2l233xfycjpd8.js +0 -1
  515. package/.next/static/chunks/2p5n7pa3c40t-.js +0 -2
  516. package/.next/static/chunks/2ru1q132af7h7.js +0 -1
  517. package/.next/static/chunks/2t8wqycwg3y04.js +0 -2
  518. package/.next/static/chunks/2uxum7qbyeyxd.js +0 -1
  519. package/.next/static/chunks/32z_ypgtchw48.js +0 -1
  520. package/.next/static/chunks/33pyjb3xd1iez.js +0 -1
  521. package/.next/static/chunks/3omud5xunrk1f.js +0 -1
  522. package/.next/static/chunks/42dnrkbph9e-1.js +0 -1
  523. package/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
  524. package/database/migrations/20260909063821_bitter_tenebrous/migration.sql +0 -1
  525. package/features/ai/prompts/memory-tidy.prompt.ts +0 -129
  526. package/features/ai/tools/tidy.tool.ts +0 -22
  527. package/features/bot/bot.notes.ts +0 -120
  528. package/features/memory/components/memory-tidy.tsx +0 -395
  529. package/features/memory/components/memory-view.tsx +0 -84
  530. package/features/memory/memory.tidy.ts +0 -332
  531. package/features/memory/tidy.query.ts +0 -135
  532. package/features/thursday/use-call-title.ts +0 -31
  533. /package/.next/server/app/api/bot/{notes → memory/files}/route/build-manifest.json +0 -0
  534. /package/.next/server/app/api/bot/{notes → memory/files}/route/server-reference-manifest.json +0 -0
  535. /package/.next/server/app/api/bot/{notes → memory/files}/route.js.map +0 -0
  536. /package/.next/server/app/api/{memory/tidy → bot/memory}/route/build-manifest.json +0 -0
  537. /package/.next/server/app/api/{memory/tidy → bot/memory}/route/server-reference-manifest.json +0 -0
  538. /package/.next/server/app/api/{memory/tidy → bot/memory}/route.js.map +0 -0
  539. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → kaTO0UHqF1bMnWgCDik2f}/_buildManifest.js +0 -0
  540. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → kaTO0UHqF1bMnWgCDik2f}/_clientMiddlewareManifest.js +0 -0
  541. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → kaTO0UHqF1bMnWgCDik2f}/_ssgManifest.js +0 -0
@@ -1,21 +1,14 @@
1
- import { BOT_NOTES, BOT_RUN, PATHS } from "@/config";
1
+ import type { ModelMessage } from "ai";
2
+ import { format } from "date-fns";
3
+ import { PATHS, PROMPT_LINE, WORKSPACE_KEEP } from "@/config";
2
4
  import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
3
- import {
4
- listJobBots,
5
- readBotNote,
6
- readBotNotesOn,
7
- } from "@/features/bot/bot.query";
8
- import type { JobBot } from "@/features/bot/bot.schema";
5
+ import { botMemoryFolder, listBotMemory } from "@/features/bot/bot.memory";
6
+ import { listJobBots, readBotMemoryOn } from "@/features/bot/bot.query";
7
+ import type { BotMemory, JobBot, TaskSpeaker } from "@/features/bot/bot.schema";
9
8
  import { findPinnedTools } from "@/features/connectors/mcp.query";
10
9
  import type { McpToolRef } from "@/features/connectors/mcp.schema";
11
- import {
12
- listAlwaysLoaded,
13
- listNoteIndex,
14
- } from "@/features/memory/memory.query";
15
- import type {
16
- MemoryAlwaysLoaded,
17
- MemoryIndexEntry,
18
- } from "@/features/memory/memory.schema";
10
+ import { listNoteIndex } from "@/features/memory/memory.query";
11
+ import type { MemoryIndexEntry } from "@/features/memory/memory.schema";
19
12
  import {
20
13
  loadSkills,
21
14
  type SkillMetadata,
@@ -25,11 +18,11 @@ import {
25
18
  openWorkspace,
26
19
  readMachineTools,
27
20
  } from "@/features/workspace/workspace";
21
+ import { toDate } from "@/lib/date-like";
28
22
  import { logger } from "@/lib/logger";
29
23
  import { clip } from "@/lib/utils";
30
24
  import { listConnectedToolNames } from "../tools/connected";
31
25
  import {
32
- carriedLines,
33
26
  type LoadedPrompt,
34
27
  logPromptSize,
35
28
  mcpToolLines,
@@ -43,60 +36,58 @@ import {
43
36
  * Each chapter decides for itself whether it is included. Assembled on every run, never cached,
44
37
  * so a skill or server added a minute ago is in the next job's prompt.
45
38
  * Two seats share this prompt: the bot holding the job, and one borrowed for a part of it
46
- * (`ask_bot`). Only identity, roster, asking and finishing differ between them.
39
+ * (`ask_bot`). Only identity, roster, asking and answering differ between them.
47
40
  *
48
41
  * @param self This run's bot name; used only to drop itself from the roster.
49
42
  * @param persona Owner's instruction for this bot from settings.
50
- * @param askedBy Name of the borrowing bot in the borrowed seat; null for the bot holding the job.
43
+ * @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.
51
44
  */
52
45
  export async function loadBotPrompt(
53
46
  self: string,
54
47
  persona?: string | null,
55
- askedBy?: string | null,
48
+ seat?: { askedBy: string; above: string[]; canBorrow: boolean } | null,
56
49
  /** The two folders that are this run's rather than the user's (bot.run). */
57
50
  folders?: { scratch: string | null; own: string },
58
51
  ): Promise<LoadedPrompt> {
59
52
  const sandbox = await openWorkspace();
60
53
  const name = self.trim();
61
- const [
62
- skills,
63
- index,
64
- carried,
65
- mcpTools,
66
- pinned,
67
- allBots,
68
- ownNote,
69
- notesOn,
70
- machine,
71
- ] = await Promise.all([
72
- loadSkills(sandbox),
73
- listNoteIndex(),
74
- listAlwaysLoaded(),
75
- // User-connected servers and the app's studio in one list (tools/connected)
76
- listConnectedToolNames(),
77
- // MCP tools this bot already holds; dropped from the listing below
78
- findPinnedTools(name),
79
- listJobBots(),
80
- // What this bot left itself; kept by the pass that runs after a job (bot.notes)
81
- readBotNote(name),
82
- readBotNotesOn(),
83
- // One `command -v` sweep; what is here decides the first command (environment)
84
- readMachineTools(sandbox),
85
- ]);
86
-
87
- // Drop self so a bot cannot call itself; a borrowed bot has no roster at all (bot.run MAX_DEPTH)
88
- const peers = askedBy ? [] : allBots.filter((bot) => bot.name !== name);
54
+ const askedBy = seat?.askedBy ?? null;
55
+ const [skills, index, mcpTools, pinned, allBots, kept, memoryOn, machine] =
56
+ await Promise.all([
57
+ loadSkills(sandbox),
58
+ listNoteIndex(),
59
+ // User-connected servers and the app's studio in one list (tools/connected)
60
+ listConnectedToolNames(),
61
+ // MCP tools this bot already holds; dropped from the listing below
62
+ findPinnedTools(name),
63
+ listJobBots(),
64
+ // What this bot kept on earlier jobs, read off its own folder (bot.memory)
65
+ listBotMemory(name),
66
+ readBotMemoryOn(),
67
+ // One `command -v` sweep; what is here decides the first command (environment)
68
+ readMachineTools(sandbox),
69
+ ]);
70
+
71
+ // Drop itself and every bot above it on this job, which are blocked waiting on
72
+ // it; the last seat the depth allows has no roster at all (config BOT_RUN.depth)
73
+ const peers =
74
+ seat && !seat.canBorrow
75
+ ? []
76
+ : allBots.filter(
77
+ (bot) => bot.name !== name && !seat?.above.includes(bot.name),
78
+ );
89
79
 
90
80
  const text = [
91
81
  askedBy ? borrowedIdentity(name, askedBy) : identity(name),
92
- memory(index, carried),
93
- notesOn ? notes(ownNote) : "",
82
+ memory(index),
94
83
  connectedTools(mcpTools, pinned),
95
84
  methods(skills),
96
85
  environment(sandbox.cwd, machine, folders),
86
+ // After Environment: its folder is named against the Cwd said there
87
+ memoryOn ? ownMemory(botMemoryFolder(name), kept) : "",
97
88
  roster(peers),
98
89
  askedBy ? askingBack(askedBy) : ASKING,
99
- askedBy ? handingUp(askedBy) : FINISHING,
90
+ askedBy ? handingUp(askedBy) : ANSWERING,
100
91
  // Last, so it is the closest thing to the work and outranks the rest
101
92
  ownerInstruction(persona),
102
93
  ]
@@ -113,20 +104,37 @@ export async function loadBotPrompt(
113
104
  };
114
105
  }
115
106
 
116
- /** Who the bot is, what machine it is on, and that guesses are not results. */
107
+ /**
108
+ * The two people every seat works between. Said before anything else, so the
109
+ * rest of the prompt — whose memory, who reads the answer — has someone to refer to.
110
+ */
111
+ const PEOPLE = `- **The user** — the one person all of this is for. They talk with Thursday by voice, and they follow this job on their screen.
112
+ - **Thursday** — their own personal assistant, one to one. She holds the conversation with them, hands bots the work that takes time, and tells them what comes back.`;
113
+
114
+ /**
115
+ * Who is who, what machine it is on, and that guesses are not results. How this
116
+ * job reached it is the first message's to say (buildTaskOpening).
117
+ */
117
118
  function identity(name: string): string {
118
119
  return [
119
120
  // Named, because the owner's prompt may not name it and its own instructions are addressed to it
120
- `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 reads them out of your report 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()}`,
121
+ `You are ${name}, one of the bots that work for the user. ${nowLine()}
122
+
123
+ ${PEOPLE}
124
+ - **You** — you do the work. Your answer goes to Thursday, not to the user, and she tells them what they need from it.`,
121
125
  MACHINE,
122
126
  NO_GUESSING,
123
127
  ].join("\n\n");
124
128
  }
125
129
 
126
- /** The borrowed seat: above it is the borrowing bot, not Thursday. */
130
+ /** The borrowed seat: between it and Thursday is the bot that borrowed it. */
127
131
  function borrowedIdentity(name: string, askedBy: string): string {
128
132
  return [
129
- `You are ${name}, a worker. ${askedBy} is holding a job Thursday handed them and has handed one part of it to you. The user speaks to Thursday and to nobody else; you never address them, and what you hand back goes into ${askedBy}'s report as-is. This thread is drawn on their screen while you work: not written to them, but not private either. ${nowLine()}`,
133
+ `You are ${name}, one of the bots that work for the user. ${nowLine()}
134
+
135
+ ${PEOPLE}
136
+ - **${askedBy}** — a bot on this job, who handed you one part of it. They cannot see your thread.
137
+ - **You** — you do that part. What you hand back goes into ${askedBy}'s work as it is, never to Thursday or the user.`,
130
138
  MACHINE,
131
139
  NO_GUESSING,
132
140
  ].join("\n\n");
@@ -154,48 +162,46 @@ Written by the person this bot works for. Where these and anything above disagre
154
162
  ${persona.trim()}`
155
163
  : "";
156
164
 
157
- /** A bot reads memory and adds to it; revising and naming are the call's (load-tools), so the chapter is that small. */
158
- function memory(
159
- index: MemoryIndexEntry[],
160
- carried: MemoryAlwaysLoaded[],
161
- ): string {
162
- const head = `## Memory
163
-
164
- What the user's assistant knows about them. Thursday keeps it as she talks with them, and everyone reads it.
165
-
166
- 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. What you learn about this machine is not memory — that is your own instructions, below.`;
167
-
168
- const alreadyKnown = carried.length
169
- ? `Already known:
170
-
171
- ${carriedLines(carried)}`
172
- : "";
173
-
174
- const listing = `path — what is under it (facts) "what the user calls it"
165
+ /**
166
+ * Thursday's memory, which a bot only reads (load-tools). The listing alone: the
167
+ * lines she carries into every call are written for her — what to call them, how
168
+ * long an answer runs — and are hers to act on, not a bot's.
169
+ */
170
+ function memory(index: MemoryIndexEntry[]): string {
171
+ return `## Thursday's memory of the user
175
172
 
176
- ${noteLines(index)}
173
+ What Thursday keeps from talking with them. Open a note from the listing with \`${TOOL_NAMES.memory_recall}\` when the job needs something about them; what you find out about them goes in your answer, and she keeps what matters.
177
174
 
178
- A topic not listed is one nobody knows anything about.`;
175
+ path — what is under it (facts) "what the user calls it"
179
176
 
180
- return [head, alreadyKnown, listing].filter(Boolean).join("\n\n");
177
+ ${noteLines(index)}`;
181
178
  }
182
179
 
183
180
  /**
184
- * The bot's own notes, carried between jobs (database bot_note). Always drawn, empty or not,
185
- * so a first job knows it has them. What belongs in them is on `report`, the only place a
186
- * change can be asked for (tools/bot.tool); the chapter is what they are and that they last.
187
- * The line about what goes in first shows only while they are empty — a standing instruction
188
- * to write something turns every job into a note, and there is nothing to nudge once a bot
189
- * has one. The count is here for the same reason: the room left is a fact, not a target.
181
+ * The bot's own memory (features/bot/bot.memory), listed by each file's first line and the day
182
+ * it last changed, both read off the disk, so what a file holds costs one line until a job opens
183
+ * it. Always drawn, so a first job knows it has one. Nothing says what usually goes in first: a
184
+ * line like that is what a first job writes, whether or not the job taught it anything.
190
185
  */
191
- function notes(own: string | null): string {
192
- return `## Your own instructions
193
-
194
- What you wrote to yourself on earlier jobs here, to get better at this machine. Only you read it, and it is the one thing that reaches your next job. What belongs in it is what working here is like — the command that turns out to be the right one, the flag it needs, the tool this platform does not have. Not what the user is like: that is Memory, above, and everyone reads that one.
195
-
196
- ${own ?? "Empty. What usually goes in first is whatever you had to find out before you could start."}
197
-
198
- (${own?.length ?? 0}/${BOT_NOTES.chars} characters)`;
186
+ function ownMemory(folder: string, kept: BotMemory): string {
187
+ const listing = kept.entries.length
188
+ ? kept.entries
189
+ .map(({ file, line, at }) => {
190
+ const said = line ? ` — ${clip(line, PROMPT_LINE.botMemory)}` : "";
191
+ return `- ${file}${said} · ${format(toDate(at), "yyyy-MM-dd")}`;
192
+ })
193
+ .join("\n")
194
+ : "Empty.";
195
+ const rest =
196
+ kept.total > kept.entries.length
197
+ ? `\n\nThe newest ${kept.entries.length} of ${kept.total}; \`ls ${folder}\` for the rest.`
198
+ : "";
199
+
200
+ return `## Your memory
201
+
202
+ What you kept from your own earlier jobs, in \`${folder}/\` under the Cwd above: 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 — with the date you found it true, and fix or delete a file that proved wrong. No passwords, keys or codes.
203
+
204
+ ${listing}${rest}`;
199
205
  }
200
206
 
201
207
  /**
@@ -256,8 +262,8 @@ Your workspace — \`${TOOL_NAMES.bash}\` runs here. Everything you write goes i
256
262
 
257
263
  - \`${PATHS.artifacts}/\` — finished work the user opens, one entry per result. Theirs, and it stays.
258
264
  - \`${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.
259
- - \`${folders?.scratch ?? PATHS.scratch}/\` — this job's working material. It goes when the job does, so nothing here is worth keeping.
260
- - \`${folders?.own ?? PATHS.bots}/\` — yours, across every job you run here. A script you wrote once and will want again, a table you built. Your own instructions can name what is in it.
265
+ - \`${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.
266
+ - \`${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.
261
267
 
262
268
  Never the directory above — that is the app you run in; outside the workspace, only where the user pointed you.`;
263
269
 
@@ -271,63 +277,150 @@ ${peers.map((bot) => `- **${bot.name}** — ${bot.description}`).join("\n")}
271
277
 
272
278
  These lines were written for the user, who reads them on their own screen: where one says "you" it means them, not you.
273
279
 
274
- 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.`;
280
+ 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.`;
275
281
  }
276
282
 
277
- /** The only place a run can stop. The user's request to buy, pay or top up is itself the go-ahead. */
283
+ /** The only place a run can stop. */
278
284
  const ASKING = `## Asking
279
285
 
280
286
  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.
281
287
 
282
288
  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.
283
289
 
284
- 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.`;
290
+ 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.`;
285
291
 
286
292
  const askingBack = (askedBy: string) => `## Asking
287
293
 
288
294
  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.`;
289
295
 
290
- 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.`;
291
-
292
296
  /**
293
- * The job ends in the thing that was asked for; no prescribed document shape.
297
+ * An answer is sized by the request, not by the shape of a document: this is where
298
+ * the only upper bound on a run is stated, and the one place that says the spoken
299
+ * line is hers to compose. Nothing here asks for a script — a bot that writes to be
300
+ * heard writes for a length rather than for a question, and the padding it adds to
301
+ * reach that length is steps, not words.
302
+ * The step cap is stated nowhere a bot reads: told the number, runs work to it. It is
303
+ * enforced where it cannot be argued with (bot.run `stepCountIs`, and `lastStep`).
294
304
  * Images in `.md` need absolute routes because a document opens from two places and relative paths resolve differently.
295
305
  */
296
- const FINISHING = `## Finishing
306
+ const ANSWERING = `## Answering
297
307
 
298
- 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}/…\`).
308
+ 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.
299
309
 
300
- \`complete: false\` when part of the request is genuinely undone — say where you got to and the user decides. ${STEP_CAP}`;
310
+ You are answering Thursday, not the user: she 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}/…\`).`;
301
311
 
302
- const handingUp = (askedBy: string) => `## Finishing
312
+ const handingUp = (askedBy: string) => `## Answering
303
313
 
304
- 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}`;
314
+ 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.`;
305
315
 
306
316
  /** How many turns of the call travel with the job: enough for one missed detail, not enough to bury the request. */
307
317
  export const OPENING_TURNS = 10;
308
- const OPENING_TURN_CHARS = 160;
318
+
319
+ /** A user message's content; every seat's first message is two text parts (buildTaskOpening). */
320
+ export type OpeningContent = Extract<ModelMessage, { role: "user" }>["content"];
309
321
 
310
322
  /**
311
- * The first message a bot reads: the request plus the last turns of the call, verbatim.
312
- * The request is one sentence the realtime model produced; a detail the user said may only be here.
313
- * Stored as the thread's first row (seq 0) so it survives a resume (bot.runner).
323
+ * The first message of the bot holding a job, stored as the thread's first row
324
+ * (seq 0, bot.runner startTask) and read whole on every resume and after every
325
+ * compaction. Two text parts: who is on this job and how it reached them, then
326
+ * the chain — the job as it was handed over and, for a job from a call, that
327
+ * call verbatim, because the request is one sentence the realtime model produced
328
+ * and a detail the user said may only be in the call. The chain is what a
329
+ * borrowed bot inherits (buildHandoff), so its headings name people and never say "you".
314
330
  */
315
331
  export function buildTaskOpening(input: {
332
+ bot: string;
316
333
  request: string;
317
334
  conversation: { role: "user" | "assistant"; text: string }[];
318
- }): string {
335
+ /** Who handed the job over: Thursday during a call, or the user on screen. */
336
+ from: TaskSpeaker;
337
+ }): OpeningContent {
319
338
  const turns = input.conversation.filter((turn) => turn.text.trim());
320
- if (!turns.length) return input.request;
339
+ const by = input.from === "user" ? "The user" : "Thursday";
340
+ const job = `## ${by} → ${input.bot}: the job\n\n${input.request.trim()}`;
341
+ const call = turns.length
342
+ ? `## The call the job came from — its last ${turns.length} turns, verbatim
343
+
344
+ 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.
321
345
 
322
- const lines = turns.map(
346
+ ${turns
347
+ .map(
323
348
  (turn) =>
324
- `${turn.role === "user" ? "user" : "thursday"}: ${clip(turn.text, OPENING_TURN_CHARS)}`,
325
- );
326
- return `${input.request}
349
+ `${turn.role === "user" ? "user" : "thursday"}: ${clip(turn.text, PROMPT_LINE.callTurn)}`,
350
+ )
351
+ .join("\n")}`
352
+ : "";
353
+ return [
354
+ { type: "text", text: whoIsWho([input.bot], input.from) },
355
+ { type: "text", text: [job, call].filter(Boolean).join("\n\n") },
356
+ ];
357
+ }
327
358
 
328
- ## The call, just before this reached you
359
+ /**
360
+ * The first message of a borrowed bot, built by the bot that borrows it (bot.run
361
+ * `ask_bot`) and never stored: the chain it inherits, copied as it is, then what
362
+ * the borrowing bot has done and the part it hands over. `bots` runs from the
363
+ * bot holding the job down to this one, so each hand-off adds one name and two
364
+ * sections and every seat reads the same shape.
365
+ */
366
+ export function buildHandoff(input: {
367
+ chain: string;
368
+ bots: string[];
369
+ did: string | null;
370
+ part: string;
371
+ }): OpeningContent {
372
+ const to = input.bots.at(-1) ?? "";
373
+ const from = input.bots.at(-2) ?? "";
374
+ const did = input.did?.trim()
375
+ ? `## ${from} → ${to}: what ${from} has done, and why this part is ${to}'s\n\n${input.did.trim()}`
376
+ : "";
377
+ const part = `## ${from} → ${to}: the part\n\n${input.part.trim()}`;
378
+ return [
379
+ { type: "text", text: whoIsWho(input.bots) },
380
+ {
381
+ type: "text",
382
+ text: [input.chain, did, part].filter(Boolean).join("\n\n"),
383
+ },
384
+ ];
385
+ }
329
386
 
330
- 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.
387
+ /**
388
+ * The chain out of a seat's first message, for the next hand-off. A thread
389
+ * opened before the two-part shape has its opening as one string, which is the
390
+ * whole chain there was.
391
+ */
392
+ export function chainOf(first: ModelMessage | undefined): string {
393
+ if (first?.role !== "user") return "";
394
+ if (typeof first.content === "string") return first.content;
395
+ const texts = first.content.flatMap((part) =>
396
+ part.type === "text" ? [part.text] : [],
397
+ );
398
+ return texts.at(-1) ?? "";
399
+ }
400
+
401
+ /**
402
+ * The bots on this job, and how it reached the one reading it — the last of
403
+ * `bots`. The user and Thursday are in every seat's prompt (identity); `from` is
404
+ * read only when the reader holds the job.
405
+ */
406
+ function whoIsWho(bots: string[], from?: TaskSpeaker): 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)** — ${
412
+ from === "user"
413
+ ? "the user handed you this job on their screen, not during a call"
414
+ : "Thursday handed you this job during a call"
415
+ }.`
416
+ : `- **${bot}** — holds this job and answers for it.`;
417
+ }
418
+ const by = bots[index - 1];
419
+ return index === you
420
+ ? `- **${bot} (you)** — ${by} handed you one part of it: the last section below. You answer to ${by}; nobody else hears from you.`
421
+ : `- **${bot}** — ${by} handed them one part of it.`;
422
+ });
423
+ return `## Who is on this job
331
424
 
332
425
  ${lines.join("\n")}`;
333
426
  }
@@ -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,13 +1,13 @@
1
1
  import { format, formatDistanceToNowStrict } from "date-fns";
2
- import { MEMORY_LISTING_TOKENS, PROMPT_BUDGET, 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
12
  import { logger } from "@/lib/logger";
13
13
  import { estimateTokens, sectionTokens } from "@/lib/tokens";
@@ -58,6 +58,36 @@ export const clockNow = (now = new Date()) =>
58
58
  /** `**Now**: 2026-09-02 (Wed) 15:41 Asia/Seoul` */
59
59
  export const nowLine = (now = new Date()) => `**Now**: ${clockNow(now)}`;
60
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
+
61
91
  /** `4mo`, `12d`: short enough to read aloud. */
62
92
  function sinceLast(at: MemoryIndexEntry["lastSeenAt"]): string {
63
93
  const days = Math.floor((Date.now() - toDate(at).getTime()) / 86_400_000);
@@ -85,13 +115,15 @@ export const carriedLines = (loaded: MemoryAlwaysLoaded[]): string =>
85
115
  loaded.map((fact) => `- ${fact.text} · ${fact.path} #${fact.id}`).join("\n");
86
116
 
87
117
  /**
88
- * Whether it is time to tidy, and why: a crowded listing points at the coldest notes,
89
- * 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.
90
122
  */
91
123
  export const tidying = (index: MemoryIndexEntry[]) => ({
92
- // The age column is only shown when picking what to drop
93
- crowded: estimateTokens(noteLines(index)) > MEMORY_LISTING_TOKENS,
94
- 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),
95
127
  });
96
128
 
97
129
  /** A bot gets the whole description; `short` gives the voice prompt the first sentence only. */
@@ -158,9 +190,6 @@ export type RecentCall = {
158
190
  }[];
159
191
  };
160
192
 
161
- /** How much of a past job's report is worth carrying; the rest is asked for with `task`. */
162
- const JOB_OUTCOME = 160;
163
-
164
193
  /**
165
194
  * One turn as the transcript carries it. A `delegate` line takes what became of
166
195
  * the job: the handle to pick it back up, and how it ended — arguments alone say
@@ -173,25 +202,20 @@ function turnLine(turn: RecentCall["turns"][number], call: RecentCall): string {
173
202
  const args = `you → ${turn.tool ?? "tool"} ${clip(turn.text, PROMPT_LINE.toolArgs)}`;
174
203
  if (turn.tool !== TOOL_NAMES.delegate) return args;
175
204
 
176
- const label = ((): string | null => {
177
- try {
178
- const said = JSON.parse(turn.text) as { label?: unknown };
179
- return typeof said.label === "string" ? said.label : null;
180
- } catch {
181
- return null;
182
- }
183
- })();
205
+ const label = delegatedLabel(turn.tool, turn.text);
184
206
  const job = label ? call.jobs?.find((one) => one.label === label) : undefined;
185
207
  if (!job) return args;
186
208
 
187
- const said = job.outcome ? `: ${clip(job.outcome, JOB_OUTCOME)}` : "";
209
+ const said = job.outcome
210
+ ? `: ${clip(job.outcome, PROMPT_LINE.jobOutcome)}`
211
+ : "";
188
212
  return `you → ${turn.tool} "${job.label}" (${job.id}) — ${job.status}${said}`;
189
213
  }
190
214
 
191
215
  /** The last calls as stored, newest last, cut to a token budget. A tool turn carries the call, not the result. */
192
216
  export function recentCallLines(calls: RecentCall[], budget: number): string {
193
217
  // Newest line backwards until the budget is spent, then put it back in order.
194
- // 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
195
219
  const kept: { call: RecentCall; line: string }[] = [];
196
220
  let spent = 0;
197
221
  outer: for (let c = calls.length - 1; c >= 0; c--) {
@@ -211,12 +235,7 @@ export function recentCallLines(calls: RecentCall[], budget: number): string {
211
235
  for (const { call, line } of kept) {
212
236
  if (call !== open) {
213
237
  open = call;
214
- const when = formatDistanceToNowStrict(call.startedAt, {
215
- addSuffix: true,
216
- });
217
- lines.push(
218
- `### ${call.startedAt.toISOString().slice(0, 16).replace("T", " ")} (${when})`,
219
- );
238
+ lines.push(`### ${callStamp(call.startedAt)}`);
220
239
  }
221
240
  lines.push(line);
222
241
  }