thursday-agent 0.5.0 → 0.7.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 (667) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +3 -2
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/required-server-files.json +8 -1
  6. package/.next/routes-manifest.json +18 -6
  7. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  14. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/server/app/_not-found.html +1 -1
  16. package/.next/server/app/_not-found.rsc +13 -13
  17. package/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
  18. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
  19. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  20. package/.next/server/app/api/artifact/route.js +10 -6
  21. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  22. package/.next/server/app/api/bot/memory/files/route.js +5 -4
  23. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
  24. package/.next/server/app/api/bot/memory/route.js +8 -8
  25. package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
  26. package/.next/server/app/api/bot/route.js +8 -8
  27. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  28. package/.next/server/app/api/bot/thread/[id]/route/app-paths-manifest.json +3 -0
  29. package/.next/server/app/api/bot/thread/[id]/route.js +15 -0
  30. package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -0
  31. package/.next/server/app/api/bot/thread/[id]/route_client-reference-manifest.js +3 -0
  32. package/.next/server/app/api/bot/thread/route/app-paths-manifest.json +3 -0
  33. package/.next/server/app/api/bot/thread/route.js +15 -0
  34. package/.next/server/app/api/bot/thread/route.js.nft.json +1 -0
  35. package/.next/server/app/api/bot/thread/route_client-reference-manifest.js +3 -0
  36. package/.next/server/app/api/config/route.js +7 -7
  37. package/.next/server/app/api/config/route.js.nft.json +1 -1
  38. package/.next/server/app/api/events/route.js +3 -3
  39. package/.next/server/app/api/events/route.js.nft.json +1 -1
  40. package/.next/server/app/api/file/[...path]/route.js +4 -4
  41. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  42. package/.next/server/app/api/llm-model/catalog/route.js +8 -8
  43. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  44. package/.next/server/app/api/llm-model/credits/route.js +8 -8
  45. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
  46. package/.next/server/app/api/llm-model/route.js +8 -8
  47. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  48. package/.next/server/app/api/llm-model/subscription/route.js +8 -8
  49. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
  50. package/.next/server/app/api/mcp/[name]/route.js +6 -6
  51. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  52. package/.next/server/app/api/mcp/oauth/callback/route.js +4 -4
  53. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  54. package/.next/server/app/api/mcp/route.js +6 -6
  55. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  56. package/.next/server/app/api/mcp/tools/route.js +6 -6
  57. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  58. package/.next/server/app/api/memory/edit/route.js +15 -15
  59. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
  60. package/.next/server/app/api/memory/route.js +7 -6
  61. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  62. package/.next/server/app/api/skills/[source]/[name]/route.js +6 -6
  63. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  64. package/.next/server/app/api/skills/route.js +6 -6
  65. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  66. package/.next/server/app/api/thursday/call/route.js +10 -11
  67. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  68. package/.next/server/app/api/thursday/skills/route.js +9 -10
  69. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  70. package/.next/server/app/api/thursday/tool-call/route.js +15 -15
  71. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  72. package/.next/server/app/api/workspace/missing/route/app-paths-manifest.json +3 -0
  73. package/.next/server/app/api/workspace/missing/route/build-manifest.json +12 -0
  74. package/.next/server/app/api/workspace/missing/route/server-reference-manifest.json +4 -0
  75. package/.next/server/app/api/workspace/missing/route.js +12 -0
  76. package/.next/server/app/api/workspace/missing/route.js.map +5 -0
  77. package/.next/server/app/api/workspace/missing/route.js.nft.json +1 -0
  78. package/.next/server/app/api/workspace/missing/route_client-reference-manifest.js +3 -0
  79. package/.next/server/app/api/workspace/route.js +5 -5
  80. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  81. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
  82. package/.next/server/app/artifact/[...path]/page.js +4 -3
  83. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  84. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  85. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  86. package/.next/server/app/page/server-reference-manifest.json +67 -45
  87. package/.next/server/app/page.js +11 -9
  88. package/.next/server/app/page.js.nft.json +1 -1
  89. package/.next/server/app/page_client-reference-manifest.js +1 -1
  90. package/.next/server/app-paths-manifest.json +3 -2
  91. package/.next/server/chunks/[root-of-the-server]__0-06t3f._.js +8 -0
  92. package/.next/server/chunks/[root-of-the-server]__02846fb._.js +8 -0
  93. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +3 -0
  94. package/.next/server/chunks/[root-of-the-server]__06--3q3._.js +8 -0
  95. package/.next/server/chunks/[root-of-the-server]__06l05n_._.js +3 -0
  96. package/.next/server/chunks/[root-of-the-server]__07bnah_._.js +3 -0
  97. package/.next/server/chunks/[root-of-the-server]__08eae20._.js +8 -0
  98. package/.next/server/chunks/[root-of-the-server]__0_ue8oe._.js +3 -0
  99. package/.next/server/chunks/[root-of-the-server]__0btqrct._.js +3 -0
  100. package/.next/server/chunks/[root-of-the-server]__0c9fgca._.js +5 -0
  101. package/.next/server/chunks/[root-of-the-server]__0h_x6q6._.js +5 -0
  102. package/.next/server/chunks/{[root-of-the-server]__0pa2n68._.js → [root-of-the-server]__0kxrvxf._.js} +2 -2
  103. package/.next/server/chunks/{[root-of-the-server]__0q0vvt2._.js → [root-of-the-server]__0ov3iir._.js} +2 -2
  104. package/.next/server/chunks/[root-of-the-server]__0qwtlmx._.js +8 -0
  105. package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.js +3 -0
  106. package/.next/server/chunks/[root-of-the-server]__0zp35ul._.js +5 -0
  107. package/.next/server/chunks/[root-of-the-server]__144u9d_._.js +3 -0
  108. package/.next/server/chunks/[root-of-the-server]__18-2tsq._.js +5 -0
  109. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +3 -0
  110. package/.next/server/chunks/[root-of-the-server]__1e2365e._.js +8 -0
  111. package/.next/server/chunks/[root-of-the-server]__1fix932._.js +8 -0
  112. package/.next/server/chunks/{[root-of-the-server]__0ce8nf8._.js → [root-of-the-server]__1g3t7vn._.js} +3 -3
  113. package/.next/server/chunks/[root-of-the-server]__1kp-83u._.js +5 -0
  114. package/.next/server/chunks/[root-of-the-server]__1kv8p3e._.js +5 -0
  115. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +2 -3
  116. package/.next/server/chunks/_02szwk8._.js +5 -0
  117. package/.next/server/chunks/_05h2cii._.js +1 -1
  118. package/.next/server/chunks/_06c9kie._.js +216 -0
  119. package/.next/server/chunks/{_1x6kd1r._.js → _07y2gj-._.js} +1 -1
  120. package/.next/server/chunks/_0a43a-0._.js +3 -0
  121. package/.next/server/chunks/_0bujjey._.js +5 -0
  122. package/.next/server/chunks/_0c9j6rb._.js +1 -1
  123. package/.next/server/chunks/_0dkd549._.js +3 -0
  124. package/.next/server/chunks/_0ej1kvv._.js +3 -0
  125. package/.next/server/chunks/_0f6ts7z._.js +3 -0
  126. package/.next/server/chunks/_0gm9hyv._.js +55 -0
  127. package/.next/server/chunks/_0i55en5._.js +25 -0
  128. package/.next/server/chunks/_0k50n27._.js +18 -0
  129. package/.next/server/chunks/_0khihjk._.js +3 -3
  130. package/.next/server/chunks/_0n74zsf._.js +5 -5
  131. package/.next/server/chunks/_0nvm9ef._.js +3 -0
  132. package/.next/server/chunks/_0p56fn0._.js +3 -0
  133. package/.next/server/chunks/_0recufk._.js +1 -1
  134. package/.next/server/chunks/_0xbkz10._.js +3 -0
  135. package/.next/server/chunks/_10tkr26._.js +3 -0
  136. package/.next/server/chunks/{_0ioz3nd._.js → _11u2kp7._.js} +1 -1
  137. package/.next/server/chunks/_11ujpya._.js +3 -0
  138. package/.next/server/chunks/_127nx_p._.js +5 -0
  139. package/.next/server/chunks/_17l5ygt._.js +1 -1
  140. package/.next/server/chunks/_19uauj6._.js +3 -0
  141. package/.next/server/chunks/_1_5mnq4._.js +5 -5
  142. package/.next/server/chunks/_1abl6t9._.js +55 -0
  143. package/.next/server/chunks/_1d0j961._.js +3 -3
  144. package/.next/server/chunks/_1dbixxz._.js +3 -0
  145. package/.next/server/chunks/_1dc_d1q._.js +98 -0
  146. package/.next/server/chunks/_1drgfx4._.js +5 -5
  147. package/.next/server/chunks/_1e48czp._.js +3 -3
  148. package/.next/server/chunks/_1f31u5x._.js +5 -0
  149. package/.next/server/chunks/_1gnjfli._.js +3 -0
  150. package/.next/server/chunks/_1kg70wc._.js +3 -3
  151. package/.next/server/chunks/_1klbcft._.js +5 -0
  152. package/.next/server/chunks/_1krd9rf._.js +4 -1
  153. package/.next/server/chunks/_1kwmzab._.js +3 -0
  154. package/.next/server/chunks/{_1pf4qe-._.js → _1oxj9fa._.js} +1 -1
  155. package/.next/server/chunks/{_1f46eie._.js → _1pcmdbb._.js} +1 -1
  156. package/.next/server/chunks/_1qgix-j._.js +3 -0
  157. package/.next/server/chunks/{lib_logger_ts_1exwjut._.js → _1rpchta._.js} +5 -5
  158. package/.next/server/chunks/_1vsej-s._.js +5 -0
  159. package/.next/server/chunks/_1yx0p_s._.js +5 -0
  160. package/.next/server/chunks/{_0rnf-6n._.js → _20fsr_z._.js} +6 -6
  161. package/.next/server/chunks/_2128hkj._.js +5 -0
  162. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_[id]_route_actions_1fstjn2.js +3 -0
  163. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_route_actions_003ccso.js +3 -0
  164. package/.next/server/chunks/_next-internal_server_app_api_workspace_missing_route_actions_1fidi6p.js +3 -0
  165. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  166. package/.next/server/chunks/features_0-cnt0l._.js +4 -0
  167. package/.next/server/chunks/features_0hdaci0._.js +4 -0
  168. package/.next/server/chunks/features_1e39j7-._.js +8 -0
  169. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
  170. package/.next/server/chunks/features_memory_1uqvksn._.js +1 -1
  171. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js → node_modules_consola_dist_chunks_prompt_mjs_0a7-pbw._.js} +1 -1
  172. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_17k8irj._.js → node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js} +1 -1
  173. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js → node_modules_consola_dist_chunks_prompt_mjs_107pxfn._.js} +1 -1
  174. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js → node_modules_consola_dist_chunks_prompt_mjs_15hbel8._.js} +1 -1
  175. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_18i-23e._.js +3 -0
  176. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1bewgf3._.js +3 -0
  177. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1nlww1m._.js +3 -0
  178. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1q77nfx._.js +3 -0
  179. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xqdzx_._.js +3 -0
  180. package/.next/server/chunks/{node_modules_zod_v4_1801ax7._.js → node_modules_zod_v4_0lkux5-._.js} +2 -2
  181. package/.next/server/chunks/{node_modules_zod_v4_1cha_bw._.js → node_modules_zod_v4_1jmr9cq._.js} +2 -2
  182. package/.next/server/chunks/{node_modules_zod_v4_0ubdflj._.js → node_modules_zod_v4_1yrxmek._.js} +2 -2
  183. package/.next/server/chunks/node_modules_zod_v4_classic_errors_0tp0y-q.js +3 -0
  184. package/.next/server/chunks/ssr/[root-of-the-server]__0-e011f._.js +3 -0
  185. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  186. package/.next/server/chunks/ssr/[root-of-the-server]__0lyi8i2._.js +1 -1
  187. package/.next/server/chunks/ssr/[root-of-the-server]__0pd8yr7._.js +3 -0
  188. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  189. package/.next/server/chunks/ssr/[root-of-the-server]__18dthbp._.js +3 -0
  190. package/.next/server/chunks/ssr/[root-of-the-server]__18e68w8._.js +3 -0
  191. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
  192. package/.next/server/chunks/ssr/[root-of-the-server]__1nygfik._.js +5 -0
  193. package/.next/server/chunks/ssr/[root-of-the-server]__1sdphb0._.js +8 -0
  194. package/.next/server/chunks/ssr/[root-of-the-server]__1vdmfbe._.js +3 -0
  195. package/.next/server/chunks/ssr/[root-of-the-server]__1waa3rc._.js +85 -0
  196. package/.next/server/chunks/ssr/_0-2qsxo._.js +3 -0
  197. package/.next/server/chunks/ssr/_00rehl_._.js +3 -0
  198. package/.next/server/chunks/ssr/{_1lz_cq2._.js → _02oc_h5._.js} +76 -97
  199. package/.next/server/chunks/ssr/_05yghx6._.js +3 -0
  200. package/.next/server/chunks/ssr/_07nbwap._.js +3 -0
  201. package/.next/server/chunks/ssr/_08c4z-9._.js +3 -0
  202. package/.next/server/chunks/ssr/_0_qfdlw._.js +4 -0
  203. package/.next/server/chunks/ssr/{_0m2lsd1._.js → _0b6_jv-._.js} +2 -2
  204. package/.next/server/chunks/ssr/_0evkpto._.js +3 -0
  205. package/.next/server/chunks/ssr/_0geg212._.js +3 -0
  206. package/.next/server/chunks/ssr/{_1jdgjv9._.js → _0hxt2ul._.js} +2 -2
  207. package/.next/server/chunks/ssr/_0i_6q1w._.js +2 -2
  208. package/.next/server/chunks/ssr/_0lu1n_x._.js +1 -1
  209. package/.next/server/chunks/ssr/_0no7i1o._.js +3 -0
  210. package/.next/server/chunks/ssr/_0tzg--b._.js +3 -0
  211. package/.next/server/chunks/ssr/{_15j2_8f._.js → _0wzaht-._.js} +2 -2
  212. package/.next/server/chunks/ssr/_0z-g0uy._.js +3 -0
  213. package/.next/server/chunks/ssr/_114ylv7._.js +7 -0
  214. package/.next/server/chunks/ssr/_123y-ah._.js +3 -0
  215. package/.next/server/chunks/ssr/_12c-iwh._.js +3 -0
  216. package/.next/server/chunks/ssr/_12w42gi._.js +3 -0
  217. package/.next/server/chunks/ssr/_161kqav._.js +3 -0
  218. package/.next/server/chunks/ssr/_167hchk._.js +3 -0
  219. package/.next/server/chunks/ssr/{_0ap2fzn._.js → _16c6_xm._.js} +2 -2
  220. package/.next/server/chunks/ssr/_18opah7._.js +3 -0
  221. package/.next/server/chunks/ssr/_1_krfph._.js +3 -0
  222. package/.next/server/chunks/ssr/{_0rzucul._.js → _1_x5spz._.js} +3 -3
  223. package/.next/server/chunks/ssr/_1a61fc9._.js +3 -0
  224. package/.next/server/chunks/ssr/_1ey7qn-._.js +70 -0
  225. package/.next/server/chunks/ssr/_1g9vs7q._.js +3 -0
  226. package/.next/server/chunks/ssr/_1jmz33w._.js +3 -0
  227. package/.next/server/chunks/ssr/_1rgtxhr._.js +5 -0
  228. package/.next/server/chunks/ssr/_1slp25y._.js +3 -0
  229. package/.next/server/chunks/ssr/_1w_t7h7._.js +101 -0
  230. package/.next/server/chunks/ssr/{_0s99bgb._.js → _1wyfaq_._.js} +9 -3
  231. package/.next/server/chunks/ssr/_200gt-m._.js +102 -0
  232. package/.next/server/chunks/ssr/components_ui_tabs_tsx_0ej40b4._.js +3 -0
  233. package/.next/server/chunks/ssr/features_bot_thread_query_ts_023eklt._.js +4 -0
  234. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  235. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  236. package/.next/server/chunks/ssr/features_workspace_00jz2hu._.js +8 -0
  237. package/.next/server/chunks/ssr/{_1-teee5._.js → lib_logger_ts_0-olsze._.js} +2 -7
  238. package/.next/server/chunks/ssr/{node_modules_05-n6dz._.js → node_modules_02ai7br._.js} +1 -1
  239. package/.next/server/chunks/ssr/{node_modules_1chvq5f._.js → node_modules_02deexj._.js} +1 -1
  240. package/.next/server/chunks/ssr/{node_modules_0m383r2._.js → node_modules_07za262._.js} +1 -1
  241. package/.next/server/chunks/ssr/{node_modules_07dsgkx._.js → node_modules_0_s9get._.js} +1 -1
  242. package/.next/server/chunks/ssr/{node_modules_1a0kmjl._.js → node_modules_0n3c7h0._.js} +1 -1
  243. package/.next/server/chunks/ssr/{node_modules_0zeg3x_._.js → node_modules_0od6jwr._.js} +1 -1
  244. package/.next/server/chunks/ssr/{node_modules_1y79i83._.js → node_modules_0rdt7pk._.js} +1 -1
  245. package/.next/server/chunks/ssr/{node_modules_17bwo43._.js → node_modules_0tusx4d._.js} +3 -3
  246. package/.next/server/chunks/ssr/{node_modules_04sksn9._.js → node_modules_0w1z7kz._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_1uyk91w._.js → node_modules_0wdupfz._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_0ifp389._.js → node_modules_1720w0a._.js} +1 -1
  249. package/.next/server/chunks/ssr/{node_modules_0u9da1h._.js → node_modules_18lsg7d._.js} +1 -1
  250. package/.next/server/chunks/ssr/{node_modules_1k6n600._.js → node_modules_1b94fxf._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_20c28js._.js → node_modules_1ecdo1s._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_0fkeku3._.js → node_modules_1fa9ag7._.js} +1 -1
  253. package/.next/server/chunks/ssr/{node_modules_1j8j4pt._.js → node_modules_1fv-_si._.js} +1 -1
  254. package/.next/server/chunks/ssr/{node_modules_0-dr_o7._.js → node_modules_1hf461g._.js} +1 -1
  255. package/.next/server/chunks/ssr/{node_modules_1lz0oxc._.js → node_modules_1m71ta-._.js} +1 -1
  256. package/.next/server/chunks/ssr/{node_modules_1t77e4n._.js → node_modules_1n93n-g._.js} +1 -1
  257. package/.next/server/chunks/ssr/{node_modules_16mkxuo._.js → node_modules_1n9lqu9._.js} +1 -1
  258. package/.next/server/chunks/ssr/{node_modules_1k7z2j6._.js → node_modules_1npnsvd._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_056qgf-._.js → node_modules_1rn2r0n._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_0x3-ply._.js → node_modules_1seuurl._.js} +2 -2
  261. package/.next/server/chunks/ssr/{node_modules_0bvopy2._.js → node_modules_1vq-mfk._.js} +1 -1
  262. package/.next/server/chunks/ssr/{node_modules_0iur59s._.js → node_modules_1vzyw1t._.js} +1 -1
  263. package/.next/server/chunks/ssr/{node_modules_1k8j8n0._.js → node_modules_1w359w4._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_1x0ztf4._.js → node_modules_1yajbl6._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_1-y7nni._.js → node_modules_20eqhy8._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0bkwd0u._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_019sbis._.js} +1 -1
  267. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0p9a9su._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0s6piq3._.js} +1 -1
  268. package/.next/server/chunks/ssr/{node_modules_@vercel_oidc_dist_1o553h-._.js → node_modules_@vercel_oidc_dist_05itbb1._.js} +1 -1
  269. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_trash_mjs_0px2gzr._.js +3 -0
  270. package/.next/server/middleware-build-manifest.js +3 -3
  271. package/.next/server/pages/404.html +1 -1
  272. package/.next/server/pages/500.html +1 -1
  273. package/.next/server/server-reference-manifest.js +1 -1
  274. package/.next/server/server-reference-manifest.json +68 -46
  275. package/.next/static/chunks/07vqbk_9t4em4.js +2 -0
  276. package/.next/static/chunks/08krja1zx7nqg.js +1 -0
  277. package/.next/static/chunks/0g4b348l0pve7.js +1 -0
  278. package/.next/static/chunks/0qcuwdk132jjt.js +1 -0
  279. package/.next/static/chunks/0vlgzqo9ka90v.js +1 -0
  280. package/.next/static/chunks/{11r2yp_yh9_qn.js → 0z69gvysmave7.js} +1 -1
  281. package/.next/static/chunks/0zrupxgci5gqc.js +1 -0
  282. package/.next/static/chunks/12fvz1w5ows75.js +1 -0
  283. package/.next/static/chunks/14t03ned286iu.js +1 -0
  284. package/.next/static/chunks/156xxbkrz5lzu.js +18 -0
  285. package/.next/static/chunks/1fz14reod4lft.js +1 -0
  286. package/.next/static/chunks/1g23dbabl-vkr.js +1 -0
  287. package/.next/static/chunks/1ohslk4568tm3.js +1 -0
  288. package/.next/static/chunks/1qy_rc3oxfxok.js +1 -0
  289. package/.next/static/chunks/1sbmwswc9k2-1.js +1 -0
  290. package/.next/static/chunks/1vqezbhjm3goq.js +1 -0
  291. package/.next/static/chunks/1zea7qdl-7365.js +1 -0
  292. package/.next/static/chunks/1zvqumkg7kmo0.css +1 -0
  293. package/.next/static/chunks/26hpqt3y6bogl.js +12 -0
  294. package/.next/static/chunks/2_j5mqm6d-z18.js +99 -0
  295. package/.next/static/chunks/2dt6tu7a22svs.js +1 -0
  296. package/.next/static/chunks/2h5ls3d86kya6.js +1 -0
  297. package/.next/static/chunks/2wc6y1ht6dfuy.js +1 -0
  298. package/.next/static/chunks/{435atsnhs7ksu.js → 2xr0zpll7thyi.js} +2 -2
  299. package/.next/static/chunks/31jztc-yq30m7.js +1 -0
  300. package/.next/static/chunks/391af0i8eljzk.js +1 -0
  301. package/.next/static/chunks/3bfwpww3m3x4u.js +1 -0
  302. package/.next/static/chunks/{38gweqdo4jpfj.js → 3izg0a3k87q1-.js} +5 -5
  303. package/.next/static/chunks/3p2s2cjokx1aa.js +5 -0
  304. package/.next/static/chunks/{408ueu4hfvcg7.js → 41s3fml5oivsa.js} +1 -1
  305. package/README.md +45 -193
  306. package/app/api/events/app-event.ts +6 -4
  307. package/app/api/query-key.ts +25 -16
  308. package/bin/database.mjs +37 -0
  309. package/bin/thursday.mjs +44 -28
  310. package/components/ui/custom-icon.tsx +0 -60
  311. package/components/ui/radio-group.tsx +37 -0
  312. package/components/ui/shiny-text.tsx +33 -6
  313. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/migration.sql +80 -24
  314. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/snapshot.json +689 -110
  315. package/database/migrations/20260916160713_thread_cancelled/migration.sql +2 -0
  316. package/database/migrations/{20260911030320_opposite_jack_power → 20260916160713_thread_cancelled}/snapshot.json +706 -84
  317. package/docs/how-it-works.md +40 -35
  318. package/docs/images/keeps-going.png +0 -0
  319. package/docs/images/two-minds.png +0 -0
  320. package/docs/live-calls.md +236 -0
  321. package/docs/thread-rooms.md +71 -0
  322. package/features/ai/chatgpt.ts +1 -2
  323. package/features/ai/live.schema.ts +128 -0
  324. package/features/ai/load-tools.ts +152 -79
  325. package/features/ai/model.schema.ts +2 -120
  326. package/features/ai/model.ts +52 -88
  327. package/features/ai/prompts/bot.prompt.ts +91 -214
  328. package/features/ai/prompts/live.prompt.ts +169 -0
  329. package/features/ai/prompts/prompt-helper.ts +92 -32
  330. package/features/ai/prompts/thursday.prompt.ts +164 -190
  331. package/features/ai/tools/bot.tool.ts +38 -145
  332. package/features/ai/tools/call.tool.ts +33 -5
  333. package/features/ai/tools/connected.ts +5 -3
  334. package/features/ai/tools/mcp.tool.ts +7 -4
  335. package/features/ai/tools/memory.tool.ts +35 -31
  336. package/features/ai/tools/skills.tool.ts +11 -6
  337. package/features/ai/tools/studio.tool.ts +26 -21
  338. package/features/ai/tools/tool-name.ts +3 -5
  339. package/features/ai/tools/workspace.tool.ts +33 -10
  340. package/features/artifact/artifact.action.ts +2 -2
  341. package/features/artifact/artifact.query.ts +112 -61
  342. package/features/artifact/artifact.schema.ts +8 -6
  343. package/features/artifact/components/artifact-setting.tsx +83 -33
  344. package/features/bot/bot.action.ts +43 -36
  345. package/features/bot/bot.memory.ts +137 -20
  346. package/features/bot/bot.query.ts +28 -11
  347. package/features/bot/bot.run.ts +296 -744
  348. package/features/bot/bot.runner.ts +463 -864
  349. package/features/bot/bot.schema.ts +93 -82
  350. package/features/bot/bot.seed.ts +141 -64
  351. package/features/bot/components/bot-mark.tsx +324 -232
  352. package/features/bot/components/bot-room.tsx +1613 -697
  353. package/features/bot/components/bot-roster.tsx +8 -13
  354. package/features/bot/components/bot-setting.tsx +58 -42
  355. package/features/bot/components/bot-tool.tsx +55 -87
  356. package/features/bot/components/mark-palette.tsx +35 -32
  357. package/features/bot/components/path-chips.tsx +33 -3
  358. package/features/bot/components/thread-badge.tsx +34 -0
  359. package/features/bot/components/thread-reply.tsx +639 -0
  360. package/features/bot/components/thread-setting.tsx +674 -0
  361. package/features/bot/mark.const.ts +79 -31
  362. package/features/bot/room.query.ts +889 -0
  363. package/features/bot/room.schema.ts +64 -0
  364. package/features/bot/seed-bots.ts +2 -1
  365. package/features/bot/thread.query.ts +971 -0
  366. package/features/bot/thread.store.ts +587 -0
  367. package/features/config/components/voice-key.tsx +113 -88
  368. package/features/config/config.const.ts +5 -9
  369. package/features/connectors/mcp.schema.ts +0 -2
  370. package/features/intro/components/intro.tsx +169 -139
  371. package/features/memory/components/memory-setting.tsx +2 -7
  372. package/features/memory/memory.schema.ts +14 -23
  373. package/features/settings/components/setting-ui.tsx +0 -44
  374. package/features/settings/components/settings.tsx +12 -12
  375. package/features/settings/settings.alert.ts +3 -3
  376. package/features/settings/settings.store.ts +1 -1
  377. package/features/skills/skills.schema.ts +0 -2
  378. package/features/thursday/ascii.const.ts +74 -0
  379. package/features/thursday/components/ascii-field.tsx +24 -44
  380. package/features/thursday/components/ascii-orb.tsx +525 -381
  381. package/features/thursday/components/call-log.tsx +46 -44
  382. package/features/thursday/components/face.tsx +40 -10
  383. package/features/thursday/components/side-captions.tsx +273 -0
  384. package/features/thursday/components/tab-state.tsx +14 -6
  385. package/features/thursday/components/thursday-mark.tsx +1 -0
  386. package/features/thursday/components/thursday-setting.tsx +633 -333
  387. package/features/thursday/components/thursday.tsx +315 -274
  388. package/features/thursday/components/voice-picker.tsx +255 -0
  389. package/features/thursday/face.store.ts +5 -0
  390. package/features/thursday/thursday.action.ts +96 -72
  391. package/features/thursday/thursday.query.ts +49 -30
  392. package/features/thursday/thursday.schema.ts +37 -35
  393. package/features/thursday/thursday.store.ts +14 -7
  394. package/features/thursday/tool-call.ts +3 -3
  395. package/features/thursday/tool-line.ts +5 -3
  396. package/features/thursday/use-thursday.ts +801 -457
  397. package/features/workspace/file-kind.ts +9 -0
  398. package/features/workspace/workspace.query.ts +17 -0
  399. package/features/workspace/workspace.ts +82 -36
  400. package/hooks/use-hotkey.ts +3 -2
  401. package/lib/live/live.schema.ts +26 -0
  402. package/lib/live/live.server.ts +153 -0
  403. package/lib/live/live.session.ts +574 -0
  404. package/lib/{realtime/realtime.tap.ts → live/live.tap.ts} +41 -12
  405. package/lib/live/live.transport.ts +152 -0
  406. package/lib/protocol/use-server-pages.ts +9 -5
  407. package/lib/utils.ts +21 -20
  408. package/package.json +2 -2
  409. package/public/voices/alloy.ogg +0 -0
  410. package/public/voices/ash.ogg +0 -0
  411. package/public/voices/ballad.ogg +0 -0
  412. package/public/voices/beacon.ogg +0 -0
  413. package/public/voices/bossa.ogg +0 -0
  414. package/public/voices/cedar.ogg +0 -0
  415. package/public/voices/cinder.ogg +0 -0
  416. package/public/voices/coral.ogg +0 -0
  417. package/public/voices/delta.ogg +0 -0
  418. package/public/voices/echo.ogg +0 -0
  419. package/public/voices/gleam.ogg +0 -0
  420. package/public/voices/marin.ogg +0 -0
  421. package/public/voices/meridian.ogg +0 -0
  422. package/public/voices/quartz.ogg +0 -0
  423. package/public/voices/ripple.ogg +0 -0
  424. package/public/voices/sage.ogg +0 -0
  425. package/public/voices/shimmer.ogg +0 -0
  426. package/public/voices/stone.ogg +0 -0
  427. package/public/voices/tempo.ogg +0 -0
  428. package/public/voices/verse.ogg +0 -0
  429. package/public/voices/vesper.ogg +0 -0
  430. package/public/voices/willow.ogg +0 -0
  431. package/scripts/artifact-paths.test.mts +38 -0
  432. package/scripts/bot-context.test.mts +1408 -0
  433. package/scripts/live-history.test.mts +115 -0
  434. package/scripts/live-session.test.mts +938 -0
  435. package/server.js +1 -1
  436. package/skills/browser/SKILL.md +11 -1
  437. package/skills/computer/SKILL.md +1 -1
  438. package/skills/find-skills/SKILL.md +3 -8
  439. package/skills/interactive-page/SKILL.md +12 -7
  440. package/skills/interactive-page/references/diagram.md +89 -0
  441. package/skills/interactive-page/scripts/archify/LICENSE +22 -0
  442. package/skills/interactive-page/scripts/archify/README.md +25 -0
  443. package/skills/interactive-page/scripts/archify/assets/JetBrainsMono-OFL.txt +93 -0
  444. package/skills/interactive-page/scripts/archify/assets/template.html +14934 -0
  445. package/skills/interactive-page/scripts/archify/bin/archify.mjs +2126 -0
  446. package/skills/interactive-page/scripts/archify/bin/open-artifact.mjs +86 -0
  447. package/skills/interactive-page/scripts/archify/bin/preview.mjs +653 -0
  448. package/skills/interactive-page/scripts/archify/bin/visual-check.mjs +829 -0
  449. package/skills/interactive-page/scripts/archify/delta/architecture-delta.mjs +1223 -0
  450. package/skills/interactive-page/scripts/archify/examples/agent-run.lifecycle.json +60 -0
  451. package/skills/interactive-page/scripts/archify/examples/agent-tool-call.workflow.json +94 -0
  452. package/skills/interactive-page/scripts/archify/examples/async-job-roundtrip.sequence.json +61 -0
  453. package/skills/interactive-page/scripts/archify/examples/cache-miss-request.sequence.json +82 -0
  454. package/skills/interactive-page/scripts/archify/examples/checkout-platform.base.architecture.json +31 -0
  455. package/skills/interactive-page/scripts/archify/examples/checkout-platform.head.architecture.json +31 -0
  456. package/skills/interactive-page/scripts/archify/examples/deployment-release.lifecycle.json +49 -0
  457. package/skills/interactive-page/scripts/archify/examples/event-stream.dataflow.json +57 -0
  458. package/skills/interactive-page/scripts/archify/examples/incident-response.workflow.json +64 -0
  459. package/skills/interactive-page/scripts/archify/examples/product-analytics.dataflow.json +76 -0
  460. package/skills/interactive-page/scripts/archify/examples/production-deployment.architecture.json +71 -0
  461. package/skills/interactive-page/scripts/archify/examples/release-delivery.workflow.json +62 -0
  462. package/skills/interactive-page/scripts/archify/examples/web-app.architecture.json +46 -0
  463. package/skills/interactive-page/scripts/archify/migrations/workflow-v2.mjs +279 -0
  464. package/skills/interactive-page/scripts/archify/recipes/scenarios.mjs +284 -0
  465. package/skills/interactive-page/scripts/archify/references/authoring-contract.md +243 -0
  466. package/skills/interactive-page/scripts/archify/references/delivery-contract.md +120 -0
  467. package/skills/interactive-page/scripts/archify/references/viewer-runtime.md +45 -0
  468. package/skills/interactive-page/scripts/archify/renderers/architecture/grid.mjs +62 -0
  469. package/skills/interactive-page/scripts/archify/renderers/architecture/render-architecture.mjs +1078 -0
  470. package/skills/interactive-page/scripts/archify/renderers/dataflow/README.md +104 -0
  471. package/skills/interactive-page/scripts/archify/renderers/dataflow/render-dataflow.mjs +483 -0
  472. package/skills/interactive-page/scripts/archify/renderers/lifecycle/README.md +115 -0
  473. package/skills/interactive-page/scripts/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
  474. package/skills/interactive-page/scripts/archify/renderers/sequence/README.md +114 -0
  475. package/skills/interactive-page/scripts/archify/renderers/sequence/render-sequence.mjs +464 -0
  476. package/skills/interactive-page/scripts/archify/renderers/shared/brand-marks.mjs +563 -0
  477. package/skills/interactive-page/scripts/archify/renderers/shared/cli.mjs +218 -0
  478. package/skills/interactive-page/scripts/archify/renderers/shared/desktop-readability.mjs +26 -0
  479. package/skills/interactive-page/scripts/archify/renderers/shared/diagnostics.mjs +127 -0
  480. package/skills/interactive-page/scripts/archify/renderers/shared/engineering-profiles.mjs +157 -0
  481. package/skills/interactive-page/scripts/archify/renderers/shared/generated-brand-marks.mjs +3 -0
  482. package/skills/interactive-page/scripts/archify/renderers/shared/generated-validators.mjs +13 -0
  483. package/skills/interactive-page/scripts/archify/renderers/shared/geometry.mjs +1423 -0
  484. package/skills/interactive-page/scripts/archify/renderers/shared/i18n.mjs +595 -0
  485. package/skills/interactive-page/scripts/archify/renderers/shared/layout-report.mjs +40 -0
  486. package/skills/interactive-page/scripts/archify/renderers/shared/legend.mjs +217 -0
  487. package/skills/interactive-page/scripts/archify/renderers/shared/output-path.mjs +340 -0
  488. package/skills/interactive-page/scripts/archify/renderers/shared/repository-evidence.mjs +238 -0
  489. package/skills/interactive-page/scripts/archify/renderers/shared/repository-location.mjs +58 -0
  490. package/skills/interactive-page/scripts/archify/renderers/shared/text-fit.mjs +49 -0
  491. package/skills/interactive-page/scripts/archify/renderers/shared/utils.mjs +232 -0
  492. package/skills/interactive-page/scripts/archify/renderers/shared/validator.mjs +86 -0
  493. package/skills/interactive-page/scripts/archify/renderers/workflow/README.md +223 -0
  494. package/skills/interactive-page/scripts/archify/renderers/workflow/render-workflow.mjs +35 -0
  495. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  496. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  497. package/skills/interactive-page/scripts/archify/schemas/README.md +211 -0
  498. package/skills/interactive-page/scripts/archify/schemas/architecture.schema.json +178 -0
  499. package/skills/interactive-page/scripts/archify/schemas/common.schema.json +115 -0
  500. package/skills/interactive-page/scripts/archify/schemas/dataflow.schema.json +243 -0
  501. package/skills/interactive-page/scripts/archify/schemas/lifecycle.schema.json +266 -0
  502. package/skills/interactive-page/scripts/archify/schemas/sequence.schema.json +223 -0
  503. package/skills/interactive-page/scripts/archify/schemas/workflow.schema.json +428 -0
  504. package/skills/interactive-page/scripts/archify/scripts/check-render-output.mjs +916 -0
  505. package/skills/interactive-page/scripts/archify/scripts/render-examples.mjs +26 -0
  506. package/skills/interactive-page/scripts/bundle-artifact.sh +9 -8
  507. package/skills/skill-creator/SKILL.md +4 -5
  508. package/.next/server/app/api/bot/task/[id]/route/app-paths-manifest.json +0 -3
  509. package/.next/server/app/api/bot/task/[id]/route.js +0 -16
  510. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +0 -1
  511. package/.next/server/app/api/bot/task/[id]/route_client-reference-manifest.js +0 -3
  512. package/.next/server/app/api/bot/task/route/app-paths-manifest.json +0 -3
  513. package/.next/server/app/api/bot/task/route.js +0 -16
  514. package/.next/server/app/api/bot/task/route.js.nft.json +0 -1
  515. package/.next/server/app/api/bot/task/route_client-reference-manifest.js +0 -3
  516. package/.next/server/chunks/[root-of-the-server]__026u77e._.js +0 -5
  517. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +0 -3
  518. package/.next/server/chunks/[root-of-the-server]__050zri4._.js +0 -3
  519. package/.next/server/chunks/[root-of-the-server]__0bg9710._.js +0 -3
  520. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +0 -3
  521. package/.next/server/chunks/[root-of-the-server]__0in-d5s._.js +0 -3
  522. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +0 -3
  523. package/.next/server/chunks/[root-of-the-server]__0pa9k-f._.js +0 -8
  524. package/.next/server/chunks/[root-of-the-server]__0qi_m0e._.js +0 -8
  525. package/.next/server/chunks/[root-of-the-server]__0tq0m_k._.js +0 -3
  526. package/.next/server/chunks/[root-of-the-server]__0xep6j_._.js +0 -3
  527. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +0 -5
  528. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +0 -5
  529. package/.next/server/chunks/[root-of-the-server]__144l7qt._.js +0 -8
  530. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +0 -5
  531. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +0 -3
  532. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +0 -3
  533. package/.next/server/chunks/[root-of-the-server]__1jg8t86._.js +0 -8
  534. package/.next/server/chunks/[root-of-the-server]__1lldzy9._.js +0 -3
  535. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +0 -3
  536. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +0 -3
  537. package/.next/server/chunks/[root-of-the-server]__1peqvsi._.js +0 -3
  538. package/.next/server/chunks/[root-of-the-server]__1w8gm5h._.js +0 -10
  539. package/.next/server/chunks/[root-of-the-server]__1xt39nn._.js +0 -8
  540. package/.next/server/chunks/[root-of-the-server]__1zb8mfo._.js +0 -8
  541. package/.next/server/chunks/_0-73of8._.js +0 -55
  542. package/.next/server/chunks/_0-fjql4._.js +0 -31
  543. package/.next/server/chunks/_00xh_q0._.js +0 -25
  544. package/.next/server/chunks/_051qh8u._.js +0 -3
  545. package/.next/server/chunks/_05sovvj._.js +0 -3
  546. package/.next/server/chunks/_091bi8d._.js +0 -3
  547. package/.next/server/chunks/_0fzqt2y._.js +0 -142
  548. package/.next/server/chunks/_0lr92vd._.js +0 -3
  549. package/.next/server/chunks/_0mecv0f._.js +0 -31
  550. package/.next/server/chunks/_0mh8j4m._.js +0 -3
  551. package/.next/server/chunks/_0sb7tlz._.js +0 -3
  552. package/.next/server/chunks/_0si7xzn._.js +0 -3
  553. package/.next/server/chunks/_0u10wmw._.js +0 -55
  554. package/.next/server/chunks/_0wp4le3._.js +0 -3
  555. package/.next/server/chunks/_0y5fg-x._.js +0 -3
  556. package/.next/server/chunks/_1230wbx._.js +0 -10
  557. package/.next/server/chunks/_12nheja._.js +0 -3
  558. package/.next/server/chunks/_13510xh._.js +0 -3
  559. package/.next/server/chunks/_15hq89o._.js +0 -3
  560. package/.next/server/chunks/_18-1wcc._.js +0 -55
  561. package/.next/server/chunks/_18d7-5p._.js +0 -3
  562. package/.next/server/chunks/_1c78vw5._.js +0 -237
  563. package/.next/server/chunks/_1h5_8sk._.js +0 -3
  564. package/.next/server/chunks/_1hdnxb7._.js +0 -3
  565. package/.next/server/chunks/_1j8k_j5._.js +0 -3
  566. package/.next/server/chunks/_1nula3v._.js +0 -3
  567. package/.next/server/chunks/_1php4eq._.js +0 -3
  568. package/.next/server/chunks/_1yuv4vp._.js +0 -3
  569. package/.next/server/chunks/_1zkfbaa._.js +0 -3
  570. package/.next/server/chunks/_next-internal_server_app_api_bot_task_[id]_route_actions_1_k_8u3.js +0 -3
  571. package/.next/server/chunks/_next-internal_server_app_api_bot_task_route_actions_0xln6ra.js +0 -3
  572. package/.next/server/chunks/features_0rpfxbk._.js +0 -3
  573. package/.next/server/chunks/features_1qf3cei._.js +0 -8
  574. package/.next/server/chunks/features_bot_0zt92oh._.js +0 -3
  575. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1jidylq._.js +0 -3
  576. package/.next/server/chunks/ssr/[externals]__0dizgek._.js +0 -3
  577. package/.next/server/chunks/ssr/[root-of-the-server]__0-nob52._.js +0 -4
  578. package/.next/server/chunks/ssr/[root-of-the-server]__092knlj._.js +0 -3
  579. package/.next/server/chunks/ssr/[root-of-the-server]__0mz33a7._.js +0 -3
  580. package/.next/server/chunks/ssr/[root-of-the-server]__0s4wb56._.js +0 -3
  581. package/.next/server/chunks/ssr/[root-of-the-server]__0s9dq5u._.js +0 -3
  582. package/.next/server/chunks/ssr/[root-of-the-server]__0sd3izg._.js +0 -3
  583. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +0 -3
  584. package/.next/server/chunks/ssr/[root-of-the-server]__1-13tcn._.js +0 -43
  585. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +0 -61
  586. package/.next/server/chunks/ssr/[root-of-the-server]__1zidpfl._.js +0 -3
  587. package/.next/server/chunks/ssr/_001_ms1._.js +0 -33
  588. package/.next/server/chunks/ssr/_01n3o0m._.js +0 -3
  589. package/.next/server/chunks/ssr/_04z2c7b._.js +0 -3
  590. package/.next/server/chunks/ssr/_06tssji._.js +0 -3
  591. package/.next/server/chunks/ssr/_0fk4c7d._.js +0 -3
  592. package/.next/server/chunks/ssr/_0h42fze._.js +0 -3
  593. package/.next/server/chunks/ssr/_0h7zdni._.js +0 -3
  594. package/.next/server/chunks/ssr/_0mggveb._.js +0 -3
  595. package/.next/server/chunks/ssr/_0nbpc_8._.js +0 -3
  596. package/.next/server/chunks/ssr/_0q0zan6._.js +0 -70
  597. package/.next/server/chunks/ssr/_0zcjrbg._.js +0 -3
  598. package/.next/server/chunks/ssr/_0zhoc3r._.js +0 -3
  599. package/.next/server/chunks/ssr/_11j92tu._.js +0 -3
  600. package/.next/server/chunks/ssr/_13fke0x._.js +0 -3
  601. package/.next/server/chunks/ssr/_18cymkq._.js +0 -3
  602. package/.next/server/chunks/ssr/_1ebxla1._.js +0 -3
  603. package/.next/server/chunks/ssr/_1nj4niv._.js +0 -42
  604. package/.next/server/chunks/ssr/_1ov37if._.js +0 -3
  605. package/.next/server/chunks/ssr/_1ovmc9s._.js +0 -3
  606. package/.next/server/chunks/ssr/_1sji22n._.js +0 -3
  607. package/.next/server/chunks/ssr/_1vi_uo7._.js +0 -3
  608. package/.next/server/chunks/ssr/_1vyd1ji._.js +0 -3
  609. package/.next/server/chunks/ssr/_1xx4zlb._.js +0 -3
  610. package/.next/server/chunks/ssr/components_ui_1y1l7yj._.js +0 -3
  611. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +0 -3
  612. package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +0 -27
  613. package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +0 -27
  614. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0npjf8-._.js +0 -3
  615. package/.next/static/chunks/0n3jle9kbqfr2.js +0 -40
  616. package/.next/static/chunks/0r5qcctujhxli.js +0 -1
  617. package/.next/static/chunks/10teww7wt-f6h.js +0 -1
  618. package/.next/static/chunks/126fj4pga_72k.js +0 -1
  619. package/.next/static/chunks/159udiexf6dom.js +0 -2
  620. package/.next/static/chunks/18a96rkhi4_yd.js +0 -1
  621. package/.next/static/chunks/18gi7o2ibrgh8.js +0 -3
  622. package/.next/static/chunks/1dkjg87pxk0n9.js +0 -28
  623. package/.next/static/chunks/1q9z1tohil7xn.js +0 -1
  624. package/.next/static/chunks/1sjgfets224re.js +0 -1
  625. package/.next/static/chunks/1wszsr83t01gh.js +0 -1
  626. package/.next/static/chunks/22_zkas21rpna.js +0 -1
  627. package/.next/static/chunks/2fh4-3z_q8b_w.js +0 -1
  628. package/.next/static/chunks/2h0sd2vumhb15.js +0 -1
  629. package/.next/static/chunks/2szintyibu0s5.js +0 -1
  630. package/.next/static/chunks/2t4vhi3m8ahya.js +0 -1
  631. package/.next/static/chunks/2tigdtz3dpcy8.js +0 -1
  632. package/.next/static/chunks/3-b6b7entqazs.js +0 -1
  633. package/.next/static/chunks/3786h5vayt80-.js +0 -28
  634. package/.next/static/chunks/3cq5g494yuke8.css +0 -1
  635. package/.next/static/chunks/3dmbhsv2u_8kj.js +0 -1
  636. package/.next/static/chunks/3hibbjnt85-k6.js +0 -1
  637. package/.next/static/chunks/3i0a5px-oufgc.js +0 -1
  638. package/.next/static/chunks/3wexk9qo8zuj3.js +0 -18
  639. package/.next/static/chunks/3xk7yqgomx7yq.js +0 -1
  640. package/.next/static/chunks/3xre8bu_pk1p_.js +0 -1
  641. package/.next/static/chunks/3zv6t3i77xhr_.js +0 -1
  642. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +0 -1
  643. package/docs/images/task-thread.png +0 -0
  644. package/features/bot/components/task-badge.tsx +0 -42
  645. package/features/bot/components/task-reply.tsx +0 -328
  646. package/features/bot/components/task-setting.tsx +0 -524
  647. package/features/bot/task.query.ts +0 -1079
  648. package/features/bot/task.store.ts +0 -487
  649. package/lib/realtime/client-secret.ts +0 -86
  650. package/lib/realtime/open-session.ts +0 -31
  651. package/lib/realtime/openai.ts +0 -35
  652. package/lib/realtime/realtime.audio.ts +0 -196
  653. package/lib/realtime/realtime.driver.ts +0 -489
  654. package/lib/realtime/realtime.protocol.ts +0 -393
  655. package/lib/realtime/realtime.schema.ts +0 -37
  656. package/lib/realtime/realtime.session.ts +0 -106
  657. package/lib/realtime/realtime.transport.ts +0 -384
  658. package/lib/realtime/xai.ts +0 -39
  659. /package/.next/server/app/api/bot/{task → thread}/[id]/route/build-manifest.json +0 -0
  660. /package/.next/server/app/api/bot/{task → thread}/[id]/route/server-reference-manifest.json +0 -0
  661. /package/.next/server/app/api/bot/{task → thread}/[id]/route.js.map +0 -0
  662. /package/.next/server/app/api/bot/{task → thread}/route/build-manifest.json +0 -0
  663. /package/.next/server/app/api/bot/{task → thread}/route/server-reference-manifest.json +0 -0
  664. /package/.next/server/app/api/bot/{task → thread}/route.js.map +0 -0
  665. /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_buildManifest.js +0 -0
  666. /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_clientMiddlewareManifest.js +0 -0
  667. /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_ssgManifest.js +0 -0
@@ -0,0 +1,938 @@
1
+ import assert from "node:assert/strict";
2
+ import { afterEach, mock, test } from "node:test";
3
+ import { LIVE_CALL } from "../config.ts";
4
+ import type {
5
+ LiveActivity,
6
+ LiveReasoning,
7
+ LiveToolCall,
8
+ LiveTurn,
9
+ } from "../lib/live/live.session.ts";
10
+
11
+ let wire: {
12
+ on: {
13
+ event(event: Record<string, unknown>): void;
14
+ dropped(message: string): void;
15
+ };
16
+ negotiate(sdp: string): Promise<string>;
17
+ };
18
+ let sent: Record<string, unknown>[] = [];
19
+ let released = false;
20
+ mock.module("../lib/live/live.transport.ts", {
21
+ namedExports: {
22
+ createWebRtcTransport: (options: typeof wire) => {
23
+ wire = options;
24
+ return {
25
+ connect: async () => {
26
+ assert.equal(await wire.negotiate("offer"), "answer");
27
+ wire.on.event({ type: "session.started" });
28
+ },
29
+ send: (event: Record<string, unknown>) => sent.push(event),
30
+ close: () => {
31
+ released = true;
32
+ },
33
+ };
34
+ },
35
+ },
36
+ });
37
+ const { appendChunks, createLiveSession } = await import(
38
+ "../lib/live/live.session.ts"
39
+ );
40
+ const { acceptedReasoning, createLiveCall } = await import(
41
+ "../lib/live/live.server.ts"
42
+ );
43
+
44
+ const sessions: ReturnType<typeof createLiveSession>[] = [];
45
+ afterEach(async () => {
46
+ for (const session of sessions.splice(0)) {
47
+ const closed = session.close();
48
+ wire.on.event({
49
+ type: "session.closed",
50
+ reason: "close_requested",
51
+ usage: { seconds: 1 },
52
+ });
53
+ await closed;
54
+ }
55
+ mock.restoreAll();
56
+ });
57
+
58
+ async function connect({
59
+ runTool = async () => "ok",
60
+ }: {
61
+ runTool?: (call: LiveToolCall) => Promise<string>;
62
+ } = {}) {
63
+ sent = [];
64
+ released = false;
65
+ const levels = { output: 0 };
66
+ const turns: LiveTurn[] = [];
67
+ const warnings: string[] = [];
68
+ const failures: string[] = [];
69
+ const activities: LiveActivity[] = [];
70
+ const reasonings: LiveReasoning[] = [];
71
+ const closes: { reason: string; seconds: number | null }[] = [];
72
+ const session = createLiveSession({
73
+ initialize: async (sdp) => {
74
+ assert.equal(sdp, "offer");
75
+ return "answer";
76
+ },
77
+ audio: {
78
+ element: { muted: false } as HTMLAudioElement,
79
+ listen() {},
80
+ levels: () => levels,
81
+ },
82
+ on: {
83
+ runTool,
84
+ reasoning: (part) => reasonings.push(part),
85
+ turn: (turn) => turns.push(turn),
86
+ warn: (message) => warnings.push(message),
87
+ failed: (message) => failures.push(message),
88
+ activity: (activity) => activities.push(activity),
89
+ finalized: (close) => closes.push(close),
90
+ },
91
+ });
92
+ sessions.push(session);
93
+ await session.connect();
94
+ return {
95
+ session,
96
+ levels,
97
+ turns,
98
+ warnings,
99
+ failures,
100
+ activities,
101
+ reasonings,
102
+ closes,
103
+ };
104
+ }
105
+
106
+ function nested(event: Record<string, unknown>) {
107
+ wire.on.event({
108
+ type: "response.event",
109
+ delegation_id: "delegation-a",
110
+ event,
111
+ });
112
+ }
113
+ const functionCall = (call_id: string) =>
114
+ nested({
115
+ type: "response.output_item.done",
116
+ item: {
117
+ type: "function_call",
118
+ id: `item-${call_id}`,
119
+ call_id,
120
+ name: "lookup",
121
+ arguments: "{}",
122
+ },
123
+ });
124
+ const count = (type: string) =>
125
+ sent.filter((event) => event.type === type).length;
126
+ const tick = () => new Promise<void>((resolve) => setImmediate(resolve));
127
+
128
+ test("the backend waits for every function output and continues once, using the envelope's response", async () => {
129
+ const pending = new Map<string, (value: string) => void>();
130
+ const { activities } = await connect({
131
+ runTool: (call) => new Promise((resolve) => pending.set(call.id, resolve)),
132
+ });
133
+ nested({ type: "response.created", response: { id: "r1" } });
134
+ nested({ type: "response.function_call_arguments.done", arguments: "{}" });
135
+ functionCall("a");
136
+ functionCall("b");
137
+ await tick();
138
+ assert.equal(pending.size, 2);
139
+ assert.equal(activities.at(-1)?.working, true);
140
+ nested({ type: "response.completed", response: { id: "r1", output: [] } });
141
+ pending.get("a")?.("first");
142
+ await tick();
143
+ assert.equal(count("response.item.create"), 1);
144
+ assert.equal(count("response.create"), 0);
145
+ pending.get("b")?.("second");
146
+ await tick();
147
+ assert.equal(count("response.item.create"), 2);
148
+ assert.equal(count("response.create"), 1);
149
+ // A repeated terminal snapshot and a repeated item run nothing twice
150
+ nested({ type: "response.completed", response: { id: "r1" } });
151
+ functionCall("a");
152
+ await tick();
153
+ assert.equal(count("response.create"), 1);
154
+ assert.equal(count("response.item.create"), 2);
155
+ });
156
+
157
+ test("an incomplete response that asked for tools is continued once, and a second in a row only warns", async () => {
158
+ const { warnings } = await connect();
159
+ nested({ type: "response.created", response: { id: "r1" } });
160
+ functionCall("a");
161
+ nested({ type: "response.incomplete", response: { id: "r1" } });
162
+ await tick();
163
+ assert.equal(count("response.item.create"), 1);
164
+ assert.equal(count("response.create"), 1);
165
+ assert.equal(warnings.length, 0);
166
+ // The continuation runs out again: its output still goes in, and nothing continues it
167
+ nested({ type: "response.created", response: { id: "r2" } });
168
+ functionCall("b");
169
+ nested({ type: "response.incomplete", response: { id: "r2" } });
170
+ await tick();
171
+ assert.equal(count("response.item.create"), 2);
172
+ assert.equal(count("response.create"), 1);
173
+ assert.equal(warnings.length, 1);
174
+ // A failed response is never continued
175
+ nested({ type: "response.created", response: { id: "r3" } });
176
+ functionCall("c");
177
+ nested({ type: "response.failed", response: { id: "r3" } });
178
+ await tick();
179
+ assert.equal(count("response.item.create"), 3);
180
+ assert.equal(count("response.create"), 1);
181
+ });
182
+
183
+ test("a call completed before one the output cap cut off still has its result continued", async () => {
184
+ let ran = 0;
185
+ await connect({
186
+ runTool: async () => {
187
+ ran += 1;
188
+ return "ok";
189
+ },
190
+ });
191
+ nested({ type: "response.created", response: { id: "r1" } });
192
+ functionCall("a");
193
+ nested({
194
+ type: "response.output_item.done",
195
+ item: {
196
+ type: "function_call",
197
+ id: "item-cut",
198
+ call_id: "cut",
199
+ name: "delegate",
200
+ arguments: '{"bot":"Ana',
201
+ status: "incomplete",
202
+ },
203
+ });
204
+ await tick();
205
+ await tick();
206
+ assert.equal(ran, 1);
207
+ assert.equal(count("response.item.create"), 1);
208
+ assert.equal(count("response.create"), 1);
209
+ // The continuation is cut off the same way: its result goes in, nothing continues it
210
+ nested({ type: "response.created", response: { id: "r2" } });
211
+ functionCall("b");
212
+ nested({
213
+ type: "response.output_item.done",
214
+ item: {
215
+ type: "function_call",
216
+ id: "item-cut-again",
217
+ call_id: "cut-again",
218
+ name: "delegate",
219
+ arguments: '{"bot":"Ana',
220
+ status: "incomplete",
221
+ },
222
+ });
223
+ await tick();
224
+ await tick();
225
+ assert.equal(ran, 2);
226
+ assert.equal(count("response.item.create"), 2);
227
+ assert.equal(count("response.create"), 1);
228
+ });
229
+
230
+ test("a finished reasoning summary part is reported once, whole, with its place in the call", async () => {
231
+ const { reasonings } = await connect();
232
+ nested({ type: "response.created", response: { id: "r1" } });
233
+ const part = (event: Record<string, unknown>) =>
234
+ nested({ item_id: "rs_1", output_index: 0, ...event });
235
+ part({
236
+ type: "response.reasoning_summary_text.delta",
237
+ summary_index: 0,
238
+ delta: "**Comparing",
239
+ });
240
+ part({
241
+ type: "response.reasoning_summary_text.done",
242
+ summary_index: 0,
243
+ text: "**Comparing markets**\n\nRates first.",
244
+ });
245
+ part({
246
+ type: "response.reasoning_summary_text.done",
247
+ summary_index: 1,
248
+ text: "**Handing over**",
249
+ });
250
+ await tick();
251
+ assert.deepEqual(
252
+ reasonings.map(({ id, text }) => [id, text]),
253
+ [
254
+ ["rs_1:0", "**Comparing markets**\n\nRates first."],
255
+ ["rs_1:1", "**Handing over**"],
256
+ ],
257
+ );
258
+ assert.ok(reasonings.every((part) => part.seq >= 0));
259
+ });
260
+
261
+ test("a function call cut off by the output cap is never run, and its response stops counting as work", async () => {
262
+ let ran = 0;
263
+ const { activities, turns } = await connect({
264
+ runTool: async () => {
265
+ ran += 1;
266
+ return "ok";
267
+ },
268
+ });
269
+ nested({ type: "response.created", response: { id: "r1" } });
270
+ await tick();
271
+ assert.equal(activities.at(-1)?.working, true);
272
+ nested({
273
+ type: "response.output_item.done",
274
+ item: {
275
+ type: "function_call",
276
+ id: "item-cut",
277
+ call_id: "cut",
278
+ name: "delegate",
279
+ arguments: '{"bot":"Analyst',
280
+ status: "incomplete",
281
+ },
282
+ });
283
+ // What Live sends instead of a terminal event for that response
284
+ wire.on.event({
285
+ type: "error",
286
+ error: { message: "Responses handoff incomplete." },
287
+ });
288
+ await tick();
289
+ assert.equal(ran, 0);
290
+ assert.equal(turns.filter((turn) => turn.role === "tool").length, 0);
291
+ assert.equal(count("response.item.create"), 0);
292
+ assert.equal(count("response.create"), 0);
293
+ assert.equal(activities.at(-1)?.working, false);
294
+ });
295
+
296
+ test("captions keep exact fragments through overlap and late delivery, and never show backend text", async (context) => {
297
+ context.mock.timers.enable({ apis: ["setTimeout"] });
298
+ const { session, turns } = await connect();
299
+ const fragment = (
300
+ type: string,
301
+ id: string,
302
+ start: number,
303
+ end: number,
304
+ delta: string,
305
+ ) =>
306
+ wire.on.event({ type, event_id: id, start_ms: start, end_ms: end, delta });
307
+ fragment("session.input_transcript.delta", "u1", 100, 200, "Please ");
308
+ fragment("session.output_transcript.delta", "a1", 150, 250, "Sure.");
309
+ fragment("session.input_transcript.delta", "u3", 400, 500, "it.");
310
+ fragment("session.input_transcript.delta", "u2", 250, 350, "find ");
311
+ fragment("session.input_transcript.delta", "u2", 250, 350, "find ");
312
+ nested({ type: "response.output_text.delta", delta: "private backend text" });
313
+ context.mock.timers.tick(LIVE_CALL.transcriptSaveMs);
314
+
315
+ const saved = turns.filter((turn) => turn.done);
316
+ assert.deepEqual(
317
+ saved.map((turn) => turn.text),
318
+ ["Please find it.", "Sure."],
319
+ );
320
+ assert.equal(saved[0].seq, 100);
321
+ assert.equal(saved[1].seq, 150);
322
+ assert.deepEqual(saved[0].fragments, [
323
+ { start: 100, end: 200, text: "Please " },
324
+ { start: 250, end: 350, text: "find " },
325
+ { start: 400, end: 500, text: "it." },
326
+ ]);
327
+
328
+ // A fragment after the checkpoint revises the same group, originals included
329
+ fragment("session.input_transcript.delta", "u4", 520, 600, " Now.");
330
+ context.mock.timers.tick(LIVE_CALL.transcriptSaveMs);
331
+ const revised = turns
332
+ .filter((turn) => turn.done && turn.id === saved[0].id)
333
+ .at(-1);
334
+ assert.equal(revised?.text, "Please find it. Now.");
335
+ assert.equal(revised?.fragments?.length, 4);
336
+ assert.equal(
337
+ turns.some((turn) => turn.text.includes("private backend text")),
338
+ false,
339
+ );
340
+
341
+ const close = session.close();
342
+ assert.equal(released, false);
343
+ wire.on.event({
344
+ type: "session.closed",
345
+ reason: "close_requested",
346
+ usage: { seconds: 12 },
347
+ });
348
+ await close;
349
+ assert.equal(released, true);
350
+ });
351
+
352
+ test("closing never starts a late tool", async () => {
353
+ let executed = 0;
354
+ const { session, failures } = await connect({
355
+ runTool: async () => {
356
+ executed++;
357
+ return "ok";
358
+ },
359
+ });
360
+ const closing = session.close();
361
+ nested({ type: "response.created", response: { id: "r" } });
362
+ functionCall("late");
363
+ wire.on.event({ type: "session.closed", reason: "close_requested" });
364
+ await closing;
365
+ assert.equal(executed, 0);
366
+ assert.equal(failures.length, 0);
367
+ });
368
+
369
+ test("closing waits for session.closed and reports the reason and billed seconds", async () => {
370
+ const { session, closes, failures } = await connect();
371
+ const closing = session.close();
372
+ assert.equal(sent.at(-1)?.type, "session.close");
373
+ assert.equal(released, false);
374
+ wire.on.event({
375
+ type: "session.closed",
376
+ reason: "close_requested",
377
+ usage: { seconds: 42 },
378
+ });
379
+ await closing;
380
+ assert.deepEqual(closes, [{ reason: "close_requested", seconds: 42 }]);
381
+ assert.equal(failures.length, 0);
382
+ assert.equal(released, true);
383
+ });
384
+
385
+ test("a session the provider closes fails the call and still reports usage", async () => {
386
+ const { closes, failures } = await connect();
387
+ wire.on.event({ type: "session.closed", reason: "idle_timeout" });
388
+ assert.deepEqual(closes, [{ reason: "idle_timeout", seconds: null }]);
389
+ assert.match(failures[0], /idle_timeout/);
390
+ assert.equal(released, true);
391
+ });
392
+
393
+ test("a close with no confirmation times out, says so, and releases media", async (context) => {
394
+ context.mock.timers.enable({ apis: ["setTimeout", "setInterval"] });
395
+ const { session, warnings, closes } = await connect();
396
+ const closing = session.close();
397
+ context.mock.timers.tick(LIVE_CALL.closeMs);
398
+ await closing;
399
+ assert.equal(released, true);
400
+ assert.equal(closes.length, 0);
401
+ assert.match(warnings[0], /final session usage/);
402
+ });
403
+
404
+ test("activity keeps reporting while she speaks, and names the tools while they run", async (context) => {
405
+ context.mock.timers.enable({ apis: ["setInterval"] });
406
+ const pending: ((value: string) => void)[] = [];
407
+ const { activities, levels } = await connect({
408
+ runTool: () => new Promise((resolve) => pending.push(resolve)),
409
+ });
410
+ levels.output = 0.2;
411
+ const before = activities.length;
412
+ context.mock.timers.tick(100);
413
+ context.mock.timers.tick(100);
414
+ context.mock.timers.tick(100);
415
+ assert.ok(
416
+ activities.slice(before).filter((activity) => activity.speaking).length >=
417
+ 3,
418
+ );
419
+
420
+ nested({ type: "response.created", response: { id: "r1" } });
421
+ functionCall("a");
422
+ await tick();
423
+ assert.equal(activities.at(-1)?.working, true);
424
+ assert.deepEqual(activities.at(-1)?.tools, ["lookup"]);
425
+ pending[0]("done");
426
+ await tick();
427
+ });
428
+
429
+ test("updates go out one at a time by kind, settle on their own acknowledgement, and are never replayed", async (context) => {
430
+ context.mock.timers.enable({ apis: ["setTimeout"] });
431
+ const { session, warnings } = await connect();
432
+ const first = session.append("instructions", "Greet the user.");
433
+ const second = session.append("commentary", "Scout found three flights.");
434
+ assert.equal(sent.length, 1);
435
+ assert.equal(sent[0].type, "session.instructions.append");
436
+ assert.equal(sent[0].delegation_id, null);
437
+ assert.equal(sent[0].content, "Greet the user.");
438
+
439
+ context.mock.timers.tick(LIVE_CALL.appendMs);
440
+ assert.equal(await first, false);
441
+ assert.match(warnings[0], /delivery is unknown/);
442
+ assert.equal(sent.length, 2);
443
+ assert.equal(sent[1].type, "session.commentary.append");
444
+
445
+ // A late acknowledgement for the first sends nothing more
446
+ wire.on.event({
447
+ type: "session.instructions.appended",
448
+ client_event_id: sent[0].event_id,
449
+ });
450
+ assert.equal(sent.length, 2);
451
+ wire.on.event({
452
+ type: "session.commentary.appended",
453
+ client_event_id: sent[1].event_id,
454
+ });
455
+ assert.equal(await second, true);
456
+ assert.equal(sent.length, 2);
457
+ });
458
+
459
+ test("a long update goes chunk by chunk, and a rejected chunk drops the rest of it", async () => {
460
+ const { session, warnings } = await connect();
461
+ const long = "word ".repeat(200);
462
+ const whole = session.append("commentary", long);
463
+ const parts: string[] = [];
464
+ while (sent.length > parts.length) {
465
+ const chunk = sent[parts.length];
466
+ parts.push(String(chunk.content));
467
+ wire.on.event({
468
+ type: "session.commentary.appended",
469
+ client_event_id: chunk.event_id,
470
+ });
471
+ }
472
+ assert.equal(await whole, true);
473
+ assert.ok(parts.length > 1);
474
+ assert.equal(parts.join(""), long);
475
+
476
+ const before = sent.length;
477
+ const rejected = session.append("commentary", long);
478
+ wire.on.event({
479
+ type: "error",
480
+ error: {
481
+ message: "Update refused",
482
+ client_event_id: sent[before].event_id,
483
+ },
484
+ });
485
+ assert.equal(await rejected, false);
486
+ assert.equal(sent.length, before + 1);
487
+ assert.match(warnings.at(-1) ?? "", /Update refused/);
488
+
489
+ const next = session.append(
490
+ "thinking",
491
+ "The user stopped a thread on screen.",
492
+ );
493
+ assert.equal(sent.at(-1)?.type, "session.thinking.append");
494
+ wire.on.event({
495
+ type: "session.thinking.appended",
496
+ client_event_id: sent.at(-1)?.event_id,
497
+ });
498
+ assert.equal(await next, true);
499
+ });
500
+
501
+ test("update chunks stay within the byte bound for any script and keep words whole", () => {
502
+ const encoder = new TextEncoder();
503
+ // Three UTF-8 bytes each, with spaces between words
504
+ const symbols = "\u2600\u2601\u2602\u2603 ".repeat(80);
505
+ const emoji = "🙂".repeat(300);
506
+ const english = "The flight leaves at nine. ".repeat(60);
507
+ for (const text of [symbols, emoji, english]) {
508
+ const chunks = appendChunks(text);
509
+ assert.ok(chunks.length > 1);
510
+ assert.equal(chunks.join(""), text);
511
+ for (const chunk of chunks) assert.ok(encoder.encode(chunk).length <= 480);
512
+ }
513
+ for (const chunk of appendChunks(english).slice(0, -1)) {
514
+ assert.match(chunk, /\s$/);
515
+ }
516
+ assert.deepEqual(appendChunks(""), []);
517
+ });
518
+
519
+ const backend = (overrides: Record<string, unknown> = {}) => ({
520
+ model: "gpt-5.6-luna",
521
+ instructions: "Tools only",
522
+ tools: [
523
+ {
524
+ name: "lookup",
525
+ description: "Look up an item",
526
+ parameters: { type: "object" as const, properties: {} },
527
+ },
528
+ ],
529
+ reasoning: null,
530
+ webSearch: false,
531
+ ...overrides,
532
+ });
533
+
534
+ function captureFetch() {
535
+ const requests: Record<string, any>[] = [];
536
+ mock.method(globalThis, "fetch", async (url: string, init: RequestInit) => {
537
+ assert.equal(url, "https://api.openai.com/v1/live/sessions");
538
+ requests.push(JSON.parse(init.body as string));
539
+ return Response.json(
540
+ {
541
+ session: { id: "live-example" },
542
+ transport: { type: "webrtc", sdp: "answer" },
543
+ },
544
+ { status: 201 },
545
+ );
546
+ });
547
+ return requests;
548
+ }
549
+
550
+ test("startup sends voice and backend apart, seeds no history, and keeps the key on the server", async () => {
551
+ const requests = captureFetch();
552
+ const connection = await createLiveCall({
553
+ apiKey: "test-key",
554
+ sdp: "offer",
555
+ voice: "marin",
556
+ instructions: "Conversation only",
557
+ backend: backend(),
558
+ });
559
+ const [request] = requests;
560
+ assert.equal(request.session.model, "gpt-live-1");
561
+ assert.equal(request.session.instructions, "Conversation only");
562
+ // Earlier calls are the backend's to read; the voice opens on nothing but its instructions
563
+ assert.equal("input" in request.session, false);
564
+ assert.equal(request.session.audio.output.voice, "marin");
565
+ assert.equal(request.session.store, false);
566
+ assert.equal(request.session.delegation.type, "responses");
567
+ const responses = request.session.delegation.responses;
568
+ assert.equal(responses.model, "gpt-5.6-luna");
569
+ assert.equal(responses.instructions, "Tools only");
570
+ assert.equal(responses.tools.length, 1);
571
+ assert.equal("strict" in responses.tools[0], false);
572
+ assert.equal("reasoning" in responses, false);
573
+ assert.equal(
574
+ responses.tools.some(
575
+ (tool: { type: string }) => tool.type === "web_search",
576
+ ),
577
+ false,
578
+ );
579
+ assert.equal(JSON.stringify(connection).includes("test-key"), false);
580
+ });
581
+
582
+ test("reasoning and web search are sent only when given", async () => {
583
+ const requests = captureFetch();
584
+ await createLiveCall({
585
+ apiKey: "test-key",
586
+ sdp: "offer",
587
+ voice: "cedar",
588
+ instructions: "Talk",
589
+ backend: backend({
590
+ model: "gpt-4.1",
591
+ reasoning: { effort: "low", summary: "auto" },
592
+ webSearch: true,
593
+ }),
594
+ });
595
+ const responses = requests[0].session.delegation.responses;
596
+ assert.equal(responses.model, "gpt-4.1");
597
+ assert.deepEqual(responses.reasoning, { effort: "low", summary: "auto" });
598
+ assert.deepEqual(responses.tools.at(-1), { type: "web_search" });
599
+ });
600
+
601
+ test("a provider refusal reaches the caller unchanged", async () => {
602
+ mock.method(globalThis, "fetch", async () =>
603
+ Response.json(
604
+ { error: { message: "This project cannot access gpt-live-1" } },
605
+ { status: 403 },
606
+ ),
607
+ );
608
+ await assert.rejects(
609
+ createLiveCall({
610
+ apiKey: "test",
611
+ sdp: "offer",
612
+ voice: "marin",
613
+ instructions: "Talk",
614
+ backend: backend(),
615
+ }),
616
+ /This project cannot access gpt-live-1/,
617
+ );
618
+ });
619
+
620
+ /** A token-count endpoint whose models refuse the reasoning settings they are given. */
621
+ function refusingFetch(refuses: Record<string, string[]>) {
622
+ const asked: string[] = [];
623
+ mock.method(globalThis, "fetch", async (url: string, init: RequestInit) => {
624
+ assert.equal(url, "https://api.openai.com/v1/responses/input_tokens");
625
+ const body = JSON.parse(init.body as string);
626
+ asked.push(`${body.model} ${JSON.stringify(body.reasoning)}`);
627
+ const refused = (refuses[body.model] ?? []).find(
628
+ (setting) => setting in body.reasoning,
629
+ );
630
+ return refused
631
+ ? Response.json(
632
+ {
633
+ error: {
634
+ message: `Unsupported parameter: 'reasoning.${refused}' is not supported with this model.`,
635
+ param: `reasoning.${refused}`,
636
+ code: "unsupported_parameter",
637
+ },
638
+ },
639
+ { status: 400 },
640
+ )
641
+ : Response.json({ input_tokens: 7 });
642
+ });
643
+ return asked;
644
+ }
645
+
646
+ test("a reasoning setting the backend model refuses is dropped before the call, and the answer is kept", async () => {
647
+ const asked = refusingFetch({ "gpt-4.1": ["effort"], legacy: ["summary"] });
648
+ const check = (model: string, effort: string | null) =>
649
+ acceptedReasoning({ apiKey: "test", model, effort });
650
+
651
+ assert.deepEqual(await check("gpt-4.1", "low"), { summary: "auto" });
652
+ assert.deepEqual(await check("gpt-4.1", "low"), { summary: "auto" });
653
+ assert.deepEqual(await check("gpt-5.6-luna", "low"), {
654
+ effort: "low",
655
+ summary: "auto",
656
+ });
657
+ assert.deepEqual(await check("gpt-5.6-luna", null), { summary: "auto" });
658
+ assert.equal(await check("gpt-4.1", "none"), null);
659
+ assert.deepEqual(await check("legacy", "high"), { effort: "high" });
660
+ assert.deepEqual(asked, [
661
+ 'gpt-4.1 {"effort":"low","summary":"auto"}',
662
+ 'gpt-4.1 {"summary":"auto"}',
663
+ 'gpt-5.6-luna {"effort":"low","summary":"auto"}',
664
+ 'gpt-5.6-luna {"summary":"auto"}',
665
+ 'gpt-4.1 {"effort":"none"}',
666
+ 'legacy {"effort":"high","summary":"auto"}',
667
+ 'legacy {"effort":"high"}',
668
+ ]);
669
+ });
670
+
671
+ test("any other answer keeps the chosen settings and is asked again next call", async () => {
672
+ let asked = 0;
673
+ mock.method(globalThis, "fetch", async () => {
674
+ asked += 1;
675
+ return asked === 1
676
+ ? Response.json(
677
+ { error: { message: "Incorrect API key provided", param: null } },
678
+ { status: 401 },
679
+ )
680
+ : Promise.reject(new TypeError("fetch failed"));
681
+ });
682
+ const check = () =>
683
+ acceptedReasoning({ apiKey: "test", model: "gpt-5.6-sol", effort: "high" });
684
+
685
+ assert.deepEqual(await check(), { effort: "high", summary: "auto" });
686
+ assert.deepEqual(await check(), { effort: "high", summary: "auto" });
687
+ assert.equal(asked, 2);
688
+ });
689
+
690
+ test("stored settings keep OpenAI choices and the shared instruction, drop a Grok voice, and recover field by field", async () => {
691
+ const { LIVE_DEFAULTS, migrateLiveSettings } = await import(
692
+ "../features/ai/live.schema.ts"
693
+ );
694
+ const openai = migrateLiveSettings({
695
+ model: {
696
+ provider: "openai",
697
+ voice: "cedar",
698
+ model: "gpt-live-1",
699
+ backendModel: "gpt-5.6-sol",
700
+ },
701
+ systemPrompt: "Call me Sam.",
702
+ captionView: "sides",
703
+ });
704
+ assert.equal(openai.voice, "cedar");
705
+ assert.equal(openai.backendModel, "gpt-5.6-sol");
706
+ assert.equal(openai.voicePrompt, "Call me Sam.");
707
+ assert.equal(openai.backendPrompt, "Call me Sam.");
708
+ assert.equal(openai.captionView, "sides");
709
+ assert.equal(openai.reasoningEffort, LIVE_DEFAULTS.reasoningEffort);
710
+ assert.equal(openai.webSearch, false);
711
+ assert.equal("model" in openai, false);
712
+ assert.equal("systemPrompt" in openai, false);
713
+
714
+ const grok = migrateLiveSettings({
715
+ model: { provider: "xai", voice: "Ara", model: "grok-voice" },
716
+ });
717
+ assert.equal(grok.voice, LIVE_DEFAULTS.voice);
718
+ assert.equal(grok.backendModel, LIVE_DEFAULTS.backendModel);
719
+
720
+ const broken = migrateLiveSettings({
721
+ voice: 42,
722
+ backendModel: "gpt-4.1",
723
+ reasoningEffort: "extreme",
724
+ webSearch: true,
725
+ });
726
+ assert.equal(broken.voice, LIVE_DEFAULTS.voice);
727
+ assert.equal(broken.backendModel, "gpt-4.1");
728
+ assert.equal(broken.reasoningEffort, LIVE_DEFAULTS.reasoningEffort);
729
+ assert.equal(broken.webSearch, true);
730
+
731
+ // A stored choice survives a change of default: auto stays auto
732
+ assert.equal(
733
+ migrateLiveSettings({ reasoningEffort: null }).reasoningEffort,
734
+ null,
735
+ );
736
+
737
+ assert.deepEqual(migrateLiveSettings(null), LIVE_DEFAULTS);
738
+ });
739
+
740
+ test("both call prompts open as one Thursday: the voice gets a two-line delegation policy and memory and no earlier calls, the backend asks before handing work over, and every call has an opening", async () => {
741
+ let profileFacts = 200;
742
+ let samFacts = 2;
743
+ const botMock = mock.module("../features/bot/bot.query.ts", {
744
+ namedExports: {
745
+ listJobBots: async () => [
746
+ { name: "Scout", description: "Finds things out on the web" },
747
+ ],
748
+ readBotMemoryOn: async () => true,
749
+ },
750
+ });
751
+ const skillsMock = mock.module("../features/skills/skills.discover.ts", {
752
+ namedExports: {
753
+ loadSkills: async () => [
754
+ { name: "browser", description: "Any browser.", path: "/browser" },
755
+ ],
756
+ },
757
+ });
758
+ const connectedMock = mock.module("../features/ai/tools/connected.ts", {
759
+ namedExports: {
760
+ listConnectedToolNames: async () => [
761
+ { server: "studio", name: "generate_image" },
762
+ { server: "github", name: "create_issue" },
763
+ ],
764
+ },
765
+ });
766
+ const workspaceMock = mock.module("../features/workspace/workspace.ts", {
767
+ namedExports: { openWorkspace: async () => ({ cwd: "/workspace" }) },
768
+ });
769
+ const memoryMock = mock.module("../features/memory/memory.query.ts", {
770
+ namedExports: {
771
+ listAlwaysLoaded: async () => [
772
+ { id: 1, path: "profile", text: "Prefer brief replies." },
773
+ ],
774
+ readNotes: async () => ({
775
+ notes: [
776
+ {
777
+ path: "profile",
778
+ facts: Array.from({ length: profileFacts }, (_, index) => ({
779
+ id: index + 1,
780
+ text: index === 0 ? "Prefer brief replies." : `Fact ${index}`,
781
+ })),
782
+ },
783
+ ],
784
+ }),
785
+ listNoteIndex: async () => [
786
+ {
787
+ path: "people/sam",
788
+ description: "Their brother",
789
+ aliases: ["Sam"],
790
+ factCount: samFacts,
791
+ lastSeenAt: new Date(),
792
+ },
793
+ ],
794
+ },
795
+ });
796
+ const callMock = mock.module("../features/thursday/thursday.query.ts", {
797
+ namedExports: {
798
+ listRecentTurns: async () => [
799
+ {
800
+ callId: "c1",
801
+ startedAt: new Date("2026-09-13T10:00:00Z"),
802
+ turns: [
803
+ { role: "user", tool: null, text: "Book the dentist.", seq: 1 },
804
+ { role: "tool", tool: "delegate", text: '{"bot":"Scout"}', seq: 2 },
805
+ { role: "assistant", tool: null, text: "Scout has it.", seq: 3 },
806
+ ],
807
+ },
808
+ ],
809
+ readCallSkillsOn: async () => false,
810
+ },
811
+ });
812
+ const threadMock = mock.module("../features/bot/thread.query.ts", {
813
+ namedExports: { listCallJobs: async () => [] },
814
+ });
815
+ try {
816
+ const { loadLivePrompt } = await import(
817
+ "../features/ai/prompts/live.prompt.ts"
818
+ );
819
+ const { loadThursdayPrompt } = await import(
820
+ "../features/ai/prompts/thursday.prompt.ts"
821
+ );
822
+ const on = await loadLivePrompt({
823
+ voicePrompt: "Use a calm voice.",
824
+ locale: "ko-KR",
825
+ });
826
+ assert.match(on.text, /modeled on Friday, the AI in \*Iron Man\*/);
827
+ assert.match(on.text, /Prefer brief replies/);
828
+ assert.match(
829
+ on.text,
830
+ /\n\n## Always\n\nIMPORTANT — always follow this: [^\n]+\n\nBackchannel policy: Use moderate backchannels\. .*\n\nInterruption policy: Stop speaking when the user interrupts\. Listen to what they say\.\n\nDelegation policy:\nDelegate to the backend everything [^\n]+\nWhatever they tell you about themselves[^\n]+unless it is already written below\.\nAnswer from what the backend returns[^\n]+\n\n## What you know about them\n/,
831
+ );
832
+ // Only the ending rule carries the stamp
833
+ assert.equal(on.text.split("IMPORTANT").length, 2);
834
+ assert.match(
835
+ on.text,
836
+ /When the user speaks at length, acknowledge now and then/,
837
+ );
838
+ // What the backend can do, and when to hand over, are no longer the voice's to read
839
+ assert.equal(
840
+ /Backend tools|Delegate to the backend when|What bots can reach for|- Web:/.test(
841
+ on.text,
842
+ ),
843
+ false,
844
+ );
845
+ assert.match(on.text, /- people\/sam — Their brother \(2\) "Sam"/);
846
+ assert.match(on.text, /What is in these notes, the backend recalls\./);
847
+ // The roster, threads and earlier calls are the backend's to read
848
+ assert.equal(on.text.includes("Scout"), false);
849
+ assert.equal(
850
+ /thread|\bseen\b|## Earlier calls|dentist|works beside you/.test(on.text),
851
+ false,
852
+ );
853
+ assert.equal("input" in on, false);
854
+ assert.equal(
855
+ /ko-KR|browser's setting|language they use/.test(on.text),
856
+ false,
857
+ );
858
+ assert.equal(/memory_|generate_|load_skill|`/.test(on.text), false);
859
+ // The one tool name the voice holds: the ending rule, where it makes ending a thing to do
860
+ assert.equal(on.text.split("end_call").length, 2);
861
+ assert.match(
862
+ on.text,
863
+ /immediately, without thinking, use the end_call tool\./,
864
+ );
865
+ assert.equal(on.text.endsWith("Use a calm voice."), true);
866
+ assert.match(on.opening, /The call has just started/);
867
+
868
+ // One Thursday: the backend opens with the voice's own words and is never told it is a part
869
+ const backend = await loadThursdayPrompt(null);
870
+ const withoutClock = (text: string) =>
871
+ text.replace(/\*\*Now\*\*: [^\n]+/, "");
872
+ const identity = on.text.slice(0, on.text.indexOf("\n\n## Always"));
873
+ const ending = /IMPORTANT — always follow this: [^\n]+/.exec(on.text)?.[0];
874
+ assert.equal(
875
+ withoutClock(backend).startsWith(
876
+ `${withoutClock(identity)}\n\n${ending}\n\n`,
877
+ ),
878
+ true,
879
+ );
880
+ assert.match(
881
+ backend,
882
+ /\*\*Keep memory clean as you write\.\*\* A fact that repeats, narrows or changes one already in the note replaces it/,
883
+ );
884
+ for (const heading of [
885
+ "## Memory",
886
+ "## Background work",
887
+ "## This computer",
888
+ "## Return the result",
889
+ "## Earlier calls",
890
+ ])
891
+ assert.equal(backend.includes(`\n${heading}\n`), true, heading);
892
+ assert.equal(backend.includes("## Voice conversation context"), false);
893
+ assert.equal(/backend of Thursday|voice model/.test(backend), false);
894
+ // The end_call name sits in the ending rule only
895
+ assert.equal(backend.split("end_call").length, 2);
896
+ assert.match(backend, /\*\*Ask once before handing work over\.\*\*/);
897
+ assert.match(backend, /Each bot keeps its own memory from job to job/);
898
+ assert.match(backend, /they come from bots, not the user/);
899
+ assert.match(backend, /Book the dentist\./);
900
+ assert.equal(backend.includes("grown past what it holds well"), false);
901
+
902
+ // Tidying memory is the backend's: the voice neither reads it nor opens with it
903
+ samFacts = 60;
904
+ const heavy = await loadLivePrompt({ locale: null });
905
+ assert.equal(/tidying|grown past/.test(heavy.text), false);
906
+ assert.match(heavy.opening, /The call has just started/);
907
+ assert.match(
908
+ await loadThursdayPrompt(null),
909
+ /grown past what it holds well \(people\/sam\): say so once in what you return/,
910
+ );
911
+ samFacts = 2;
912
+
913
+ profileFacts = 0;
914
+ const first = await loadLivePrompt({ locale: "ko-KR" });
915
+ assert.match(first.text, /## First call/);
916
+ // The one call that opens with nothing: she says who she is, then learns who they are
917
+ assert.match(first.opening ?? "", /say who you are/);
918
+ assert.match(first.opening ?? "", /ask what to call them/);
919
+ assert.match(first.opening ?? "", /ko-KR/);
920
+ assert.match(first.text, /what they do, how old they are, where they live/);
921
+
922
+ // A call the page placed says so, ahead of even the first-call opening
923
+ const rung = await loadLivePrompt({
924
+ locale: "ko-KR",
925
+ calledBack: true,
926
+ });
927
+ assert.match(rung.opening, /You placed this call/);
928
+ assert.match(rung.opening, /say that is why you called/);
929
+ } finally {
930
+ memoryMock.restore();
931
+ callMock.restore();
932
+ botMock.restore();
933
+ skillsMock.restore();
934
+ connectedMock.restore();
935
+ workspaceMock.restore();
936
+ threadMock.restore();
937
+ }
938
+ });