thursday-agent 0.4.0 → 0.6.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.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +3 -2
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/required-server-files.json +8 -1
- package/.next/routes-manifest.json +18 -6
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +13 -13
- package/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/artifact/route.js +10 -6
- package/.next/server/app/api/artifact/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/files/route.js +6 -5
- package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/route.js +8 -8
- package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/route.js +8 -8
- package/.next/server/app/api/bot/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/thread/[id]/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/bot/thread/[id]/route.js +15 -0
- package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/bot/thread/[id]/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/bot/thread/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/bot/thread/route.js +15 -0
- package/.next/server/app/api/bot/thread/route.js.nft.json +1 -0
- package/.next/server/app/api/bot/thread/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/config/route.js +7 -7
- package/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/server/app/api/events/route.js +3 -3
- package/.next/server/app/api/events/route.js.nft.json +1 -1
- package/.next/server/app/api/file/[...path]/route.js +5 -5
- package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/catalog/route.js +8 -8
- package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/credits/route.js +8 -8
- package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/route.js +8 -8
- package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/subscription/route.js +8 -8
- package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/[name]/route.js +6 -6
- package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/oauth/callback/route.js +4 -4
- package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/route.js +6 -6
- package/.next/server/app/api/mcp/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/tools/route.js +6 -6
- package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/memory/edit/route.js +13 -13
- package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
- package/.next/server/app/api/memory/route.js +7 -6
- package/.next/server/app/api/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/[source]/[name]/route.js +6 -6
- package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route.js +6 -6
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/call/route.js +10 -11
- package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/skills/route.js +10 -11
- package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/tool-call/route.js +15 -15
- package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
- package/.next/server/app/api/workspace/missing/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/workspace/missing/route/build-manifest.json +12 -0
- package/.next/server/app/api/workspace/missing/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/workspace/missing/route.js +12 -0
- package/.next/server/app/api/workspace/missing/route.js.map +5 -0
- package/.next/server/app/api/workspace/missing/route.js.nft.json +1 -0
- package/.next/server/app/api/workspace/missing/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/workspace/route.js +5 -4
- package/.next/server/app/api/workspace/route.js.nft.json +1 -1
- package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
- package/.next/server/app/artifact/[...path]/page.js +4 -3
- package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
- package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/server/app/page/server-reference-manifest.json +67 -45
- package/.next/server/app/page.js +10 -9
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +3 -2
- package/.next/server/chunks/[root-of-the-server]__02846fb._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__049f521._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__05luceg._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__06--3q3._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__07bnah_._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__08eae20._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0_ue8oe._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0c9fgca._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__0g-ueei._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0h_x6q6._.js +5 -0
- package/.next/server/chunks/{[root-of-the-server]__0pa2n68._.js → [root-of-the-server]__0kxrvxf._.js} +2 -2
- package/.next/server/chunks/{[root-of-the-server]__0q0vvt2._.js → [root-of-the-server]__0ov3iir._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__0qwtlmx._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0ye3da2._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0zp35ul._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__144u9d_._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__18-2tsq._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1e2365e._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__1fix932._.js +8 -0
- package/.next/server/chunks/{[root-of-the-server]__0ce8nf8._.js → [root-of-the-server]__1g3t7vn._.js} +3 -3
- package/.next/server/chunks/[root-of-the-server]__1kp-83u._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1kv8p3e._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +2 -3
- package/.next/server/chunks/_02szwk8._.js +5 -0
- package/.next/server/chunks/_05h2cii._.js +1 -1
- package/.next/server/chunks/_06c9kie._.js +216 -0
- package/.next/server/chunks/{_1x6kd1r._.js → _07y2gj-._.js} +1 -1
- package/.next/server/chunks/_0a43a-0._.js +3 -0
- package/.next/server/chunks/_0bujjey._.js +5 -0
- package/.next/server/chunks/_0c9j6rb._.js +1 -1
- package/.next/server/chunks/_0dkd549._.js +3 -0
- package/.next/server/chunks/_0ej1kvv._.js +3 -0
- package/.next/server/chunks/_0f6ts7z._.js +3 -0
- package/.next/server/chunks/_0gm9hyv._.js +55 -0
- package/.next/server/chunks/_0i55en5._.js +25 -0
- package/.next/server/chunks/_0k50n27._.js +18 -0
- package/.next/server/chunks/_0khihjk._.js +3 -3
- package/.next/server/chunks/_0n74zsf._.js +5 -5
- package/.next/server/chunks/_0nvm9ef._.js +3 -0
- package/.next/server/chunks/_0p56fn0._.js +3 -0
- package/.next/server/chunks/_0recufk._.js +1 -1
- package/.next/server/chunks/_0xbkz10._.js +3 -0
- package/.next/server/chunks/_10tkr26._.js +3 -0
- package/.next/server/chunks/{_0ioz3nd._.js → _11u2kp7._.js} +1 -1
- package/.next/server/chunks/_11ujpya._.js +3 -0
- package/.next/server/chunks/_127nx_p._.js +5 -0
- package/.next/server/chunks/_17l5ygt._.js +1 -1
- package/.next/server/chunks/_19uauj6._.js +3 -0
- package/.next/server/chunks/_1_5mnq4._.js +5 -5
- package/.next/server/chunks/_1abl6t9._.js +55 -0
- package/.next/server/chunks/_1d0j961._.js +3 -3
- package/.next/server/chunks/_1dbixxz._.js +3 -0
- package/.next/server/chunks/_1dc_d1q._.js +98 -0
- package/.next/server/chunks/_1drgfx4._.js +5 -5
- package/.next/server/chunks/_1e48czp._.js +3 -3
- package/.next/server/chunks/_1f31u5x._.js +5 -0
- package/.next/server/chunks/_1kg70wc._.js +3 -3
- package/.next/server/chunks/_1klbcft._.js +5 -0
- package/.next/server/chunks/_1krd9rf._.js +4 -1
- package/.next/server/chunks/_1kwmzab._.js +3 -0
- package/.next/server/chunks/{_1pf4qe-._.js → _1oxj9fa._.js} +1 -1
- package/.next/server/chunks/{_1f46eie._.js → _1pcmdbb._.js} +1 -1
- package/.next/server/chunks/_1qgix-j._.js +3 -0
- package/.next/server/chunks/{lib_logger_ts_1exwjut._.js → _1rpchta._.js} +5 -5
- package/.next/server/chunks/_1vsej-s._.js +5 -0
- package/.next/server/chunks/_1yx0p_s._.js +5 -0
- package/.next/server/chunks/{_0rnf-6n._.js → _20fsr_z._.js} +6 -6
- package/.next/server/chunks/_2128hkj._.js +5 -0
- package/.next/server/chunks/_next-internal_server_app_api_bot_thread_[id]_route_actions_1fstjn2.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_bot_thread_route_actions_003ccso.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_workspace_missing_route_actions_1fidi6p.js +3 -0
- package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
- package/.next/server/chunks/features_0-cnt0l._.js +4 -0
- package/.next/server/chunks/features_0hdaci0._.js +4 -0
- package/.next/server/chunks/features_1e39j7-._.js +8 -0
- package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
- package/.next/server/chunks/features_memory_1uqvksn._.js +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js → node_modules_consola_dist_chunks_prompt_mjs_0a7-pbw._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js → node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js → node_modules_consola_dist_chunks_prompt_mjs_107pxfn._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js → node_modules_consola_dist_chunks_prompt_mjs_15hbel8._.js} +1 -1
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_18i-23e._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1bewgf3._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1kipdeo._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1nlww1m._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1q77nfx._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xqdzx_._.js +3 -0
- package/.next/server/chunks/{node_modules_zod_v4_1801ax7._.js → node_modules_zod_v4_0lkux5-._.js} +2 -2
- package/.next/server/chunks/{node_modules_zod_v4_1cha_bw._.js → node_modules_zod_v4_1jmr9cq._.js} +2 -2
- package/.next/server/chunks/{node_modules_zod_v4_0ubdflj._.js → node_modules_zod_v4_1yrxmek._.js} +2 -2
- package/.next/server/chunks/node_modules_zod_v4_classic_errors_0tp0y-q.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0bxsfyn._.js +101 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0lyi8i2._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__172cq4x._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__18dthbp._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__18e68w8._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1fll8dc._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__1nygfik._.js +5 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1sdphb0._.js +8 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1waa3rc._.js +100 -0
- package/.next/server/chunks/ssr/_00rehl_._.js +3 -0
- package/.next/server/chunks/ssr/{_1lz_cq2._.js → _02oc_h5._.js} +76 -89
- package/.next/server/chunks/ssr/_03_928f._.js +3 -0
- package/.next/server/chunks/ssr/_05yghx6._.js +3 -0
- package/.next/server/chunks/ssr/_08c4z-9._.js +3 -0
- package/.next/server/chunks/ssr/_0_qfdlw._.js +4 -0
- package/.next/server/chunks/ssr/_0c9e5w6._.js +9 -0
- package/.next/server/chunks/ssr/{_0s99bgb._.js → _0dh2e1j._.js} +9 -3
- package/.next/server/chunks/ssr/_0dr-ddg._.js +3 -0
- package/.next/server/chunks/ssr/_0eaog6_._.js +3 -0
- package/.next/server/chunks/ssr/_0evkpto._.js +3 -0
- package/.next/server/chunks/ssr/_0g_rlog._.js +3 -0
- package/.next/server/chunks/ssr/_0geg212._.js +3 -0
- package/.next/server/chunks/ssr/{_1gd8q8l._.js → _0hxt2ul._.js} +2 -2
- package/.next/server/chunks/ssr/_0i_6q1w._.js +2 -2
- package/.next/server/chunks/ssr/_0lu1n_x._.js +1 -1
- package/.next/server/chunks/ssr/{_15j2_8f._.js → _0wzaht-._.js} +2 -2
- package/.next/server/chunks/ssr/_0z-g0uy._.js +3 -0
- package/.next/server/chunks/ssr/_123ttsf._.js +3 -0
- package/.next/server/chunks/ssr/_123y-ah._.js +3 -0
- package/.next/server/chunks/ssr/_12w42gi._.js +3 -0
- package/.next/server/chunks/ssr/_161kqav._.js +3 -0
- package/.next/server/chunks/ssr/{_0ap2fzn._.js → _16c6_xm._.js} +2 -2
- package/.next/server/chunks/ssr/_18opah7._.js +3 -0
- package/.next/server/chunks/ssr/_18xqmny._.js +3 -0
- package/.next/server/chunks/ssr/_1_krfph._.js +3 -0
- package/.next/server/chunks/ssr/{_1-_etts._.js → _1anqots._.js} +2 -2
- package/.next/server/chunks/ssr/_1ey7qn-._.js +70 -0
- package/.next/server/chunks/ssr/_1g9vs7q._.js +3 -0
- package/.next/server/chunks/ssr/_1jmz33w._.js +3 -0
- package/.next/server/chunks/ssr/{_0n3toaw._.js → _1k0spz7._.js} +2 -2
- package/.next/server/chunks/ssr/_1rgtxhr._.js +5 -0
- package/.next/server/chunks/ssr/_1slp25y._.js +3 -0
- package/.next/server/chunks/ssr/{_1fojd41._.js → _1x9pskj._.js} +3 -3
- package/.next/server/chunks/ssr/_1y6b5mr._.js +101 -0
- package/.next/server/chunks/ssr/_1ztk7p6._.js +7 -0
- package/.next/server/chunks/ssr/components_ui_tabs_tsx_0ej40b4._.js +3 -0
- package/.next/server/chunks/ssr/features_bot_thread_query_ts_023eklt._.js +4 -0
- package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
- package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
- package/.next/server/chunks/ssr/{_1-teee5._.js → lib_logger_ts_0-olsze._.js} +2 -7
- package/.next/server/chunks/ssr/{node_modules_0cxaxk9._.js → node_modules_00_51_v._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_04jf_m8._.js → node_modules_022sipm._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0g7fzk3._.js → node_modules_0332gw4._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1cx_ql6._.js → node_modules_04vxchl._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1vh5ntv._.js → node_modules_0746rzi._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0yugy6m._.js → node_modules_0d5uzof._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_09q35v_._.js → node_modules_0exkwcm._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_08dhkiq._.js → node_modules_0fr-ml8._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_14q6g4n._.js → node_modules_0mxvg8h._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0arus10._.js → node_modules_0qapgjr._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1eg7m6c._.js → node_modules_0qbfyjh._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1cz2hle._.js → node_modules_0t-9nup._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_17bwo43._.js → node_modules_0tusx4d._.js} +3 -3
- package/.next/server/chunks/ssr/{node_modules_1efrqxi._.js → node_modules_0vsxbzp._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0_-_a--._.js → node_modules_0vv0-fg._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1gdh31p._.js → node_modules_0wsvp00._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1hpopmo._.js → node_modules_1-urho9._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1_pc9kq._.js → node_modules_16pi_dd._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_00etblx._.js → node_modules_1d53yiq._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1aaxuef._.js → node_modules_1g1eihe._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_198nmll._.js → node_modules_1gpednh._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0pvd7q-._.js → node_modules_1gu1pph._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0b__sgl._.js → node_modules_1he1w8_._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1qpjvy5._.js → node_modules_1lnjapm._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0940ns5._.js → node_modules_1lynj9m._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0x3-ply._.js → node_modules_1seuurl._.js} +2 -2
- package/.next/server/chunks/ssr/{node_modules_14om4ar._.js → node_modules_1u6w1pb._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0had7xd._.js → node_modules_1xn6saw._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1b748ic._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_067_exa._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1z4hm5e._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0nrrdaq._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@vercel_oidc_dist_06mk8id._.js → node_modules_@vercel_oidc_dist_21a5haa._.js} +1 -1
- package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_trash_mjs_0px2gzr._.js +3 -0
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +68 -46
- package/.next/static/chunks/0dr16v67vj4n7.js +2 -0
- package/.next/static/chunks/0g4b348l0pve7.js +1 -0
- package/.next/static/chunks/0joan-69kbspd.js +1 -0
- package/.next/static/chunks/0vlgzqo9ka90v.js +1 -0
- package/.next/static/chunks/0zrupxgci5gqc.js +1 -0
- package/.next/static/chunks/10k2xvap03z20.css +1 -0
- package/.next/static/chunks/18mkhstgiqcbt.js +1 -0
- package/.next/static/chunks/{15m575979un5f.js → 1i-u2wzub_to1.js} +2 -2
- package/.next/static/chunks/1kp5nfp06nj9h.js +5 -0
- package/.next/static/chunks/1ohslk4568tm3.js +1 -0
- package/.next/static/chunks/1sbmwswc9k2-1.js +1 -0
- package/.next/static/chunks/1t9qms5pwwa3n.js +1 -0
- package/.next/static/chunks/1vj_5bnbxx84e.js +1 -0
- package/.next/static/chunks/1vqezbhjm3goq.js +1 -0
- package/.next/static/chunks/{3akmqm77muj4-.js → 1wlo979mx-y3w.js} +1 -1
- package/.next/static/chunks/26ql4y-43xwhp.js +1 -0
- package/.next/static/chunks/{0fl3gwe4-l6tz.js → 2_pnccjp6j1ca.js} +1 -1
- package/.next/static/chunks/2a51-ywz9b2a3.js +1 -0
- package/.next/static/chunks/2fvdgxih7x7hr.js +1 -0
- package/.next/static/chunks/2jlz8zp4jax_m.js +18 -0
- package/.next/static/chunks/2nvepds1fu2ux.js +1 -0
- package/.next/static/chunks/3addj3i4-izma.js +1 -0
- package/.next/static/chunks/3bfwpww3m3x4u.js +1 -0
- package/.next/static/chunks/3gfh7nxwusbt0.js +1 -0
- package/.next/static/chunks/3gwa44cvz4qoi.js +1 -0
- package/.next/static/chunks/{38gweqdo4jpfj.js → 3izg0a3k87q1-.js} +5 -5
- package/.next/static/chunks/3zk6q3-3f9swq.js +99 -0
- package/.next/static/chunks/3zkg5iup3v4a2.js +12 -0
- package/.next/static/chunks/405m0bqtoihev.js +1 -0
- package/.next/static/chunks/42wcg3wfg_m_p.js +1 -0
- package/README.md +27 -216
- package/app/api/events/app-event.ts +6 -4
- package/app/api/query-key.ts +25 -16
- package/bin/database.mjs +37 -0
- package/bin/thursday.mjs +44 -28
- package/components/ui/custom-icon.tsx +0 -60
- package/components/ui/radio-group.tsx +37 -0
- package/components/ui/shiny-text.tsx +33 -6
- package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/migration.sql +80 -24
- package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/snapshot.json +689 -110
- package/database/migrations/20260916160713_thread_cancelled/migration.sql +2 -0
- package/database/migrations/{20260911030320_opposite_jack_power → 20260916160713_thread_cancelled}/snapshot.json +706 -84
- package/docs/how-it-works.md +39 -36
- package/docs/images/keeps-going.png +0 -0
- package/docs/images/two-minds.png +0 -0
- package/docs/live-calls.md +231 -0
- package/docs/thread-rooms.md +71 -0
- package/features/ai/chatgpt.ts +1 -2
- package/features/ai/live.schema.ts +128 -0
- package/features/ai/load-tools.ts +148 -77
- package/features/ai/model.schema.ts +2 -120
- package/features/ai/model.ts +52 -88
- package/features/ai/prompts/bot.prompt.ts +91 -214
- package/features/ai/prompts/live.prompt.ts +265 -0
- package/features/ai/prompts/prompt-helper.ts +91 -32
- package/features/ai/prompts/thursday.prompt.ts +125 -172
- package/features/ai/tools/bot.tool.ts +38 -145
- package/features/ai/tools/call.tool.ts +1 -1
- package/features/ai/tools/connected.ts +5 -3
- package/features/ai/tools/mcp.tool.ts +7 -4
- package/features/ai/tools/memory.tool.ts +35 -31
- package/features/ai/tools/skills.tool.ts +36 -14
- package/features/ai/tools/studio.tool.ts +26 -21
- package/features/ai/tools/tool-name.ts +2 -5
- package/features/ai/tools/workspace.tool.ts +33 -10
- package/features/artifact/artifact.action.ts +2 -2
- package/features/artifact/artifact.query.ts +112 -61
- package/features/artifact/artifact.schema.ts +8 -6
- package/features/artifact/components/artifact-setting.tsx +83 -33
- package/features/bot/bot.action.ts +43 -36
- package/features/bot/bot.memory.ts +137 -20
- package/features/bot/bot.query.ts +28 -11
- package/features/bot/bot.run.ts +299 -636
- package/features/bot/bot.runner.ts +468 -844
- package/features/bot/bot.schema.ts +93 -82
- package/features/bot/bot.seed.ts +141 -64
- package/features/bot/components/bot-mark.tsx +324 -232
- package/features/bot/components/bot-room.tsx +1613 -697
- package/features/bot/components/bot-roster.tsx +8 -13
- package/features/bot/components/bot-setting.tsx +58 -42
- package/features/bot/components/bot-tool.tsx +55 -87
- package/features/bot/components/mark-palette.tsx +35 -32
- package/features/bot/components/path-chips.tsx +33 -3
- package/features/bot/components/thread-badge.tsx +34 -0
- package/features/bot/components/thread-reply.tsx +639 -0
- package/features/bot/components/thread-setting.tsx +674 -0
- package/features/bot/mark.const.ts +79 -31
- package/features/bot/room.query.ts +889 -0
- package/features/bot/room.schema.ts +64 -0
- package/features/bot/seed-bots.ts +2 -1
- package/features/bot/thread.query.ts +971 -0
- package/features/bot/thread.store.ts +587 -0
- package/features/config/components/voice-key.tsx +113 -88
- package/features/config/config.const.ts +5 -9
- package/features/connectors/mcp.schema.ts +0 -2
- package/features/intro/components/intro.tsx +169 -139
- package/features/memory/components/memory-setting.tsx +2 -7
- package/features/memory/memory.schema.ts +14 -23
- package/features/settings/components/setting-ui.tsx +0 -44
- package/features/settings/components/settings.tsx +12 -12
- package/features/settings/settings.alert.ts +3 -3
- package/features/settings/settings.store.ts +1 -1
- package/features/skills/skills.schema.ts +0 -2
- package/features/thursday/components/ascii-field.tsx +24 -44
- package/features/thursday/components/ascii-orb.tsx +359 -358
- package/features/thursday/components/call-log.tsx +46 -44
- package/features/thursday/components/face.tsx +35 -10
- package/features/thursday/components/tab-state.tsx +3 -3
- package/features/thursday/components/thursday-mark.tsx +1 -0
- package/features/thursday/components/thursday-setting.tsx +631 -332
- package/features/thursday/components/thursday.tsx +106 -41
- package/features/thursday/components/voice-picker.tsx +255 -0
- package/features/thursday/thursday.action.ts +94 -68
- package/features/thursday/thursday.query.ts +49 -30
- package/features/thursday/thursday.schema.ts +27 -30
- package/features/thursday/thursday.store.ts +11 -7
- package/features/thursday/tool-call.ts +3 -3
- package/features/thursday/tool-line.ts +5 -3
- package/features/thursday/use-thursday.ts +725 -450
- package/features/workspace/workspace.query.ts +17 -0
- package/features/workspace/workspace.ts +103 -50
- package/lib/live/live.schema.ts +47 -0
- package/lib/live/live.server.ts +155 -0
- package/lib/live/live.session.ts +574 -0
- package/lib/{realtime/realtime.tap.ts → live/live.tap.ts} +41 -12
- package/lib/live/live.transport.ts +152 -0
- package/lib/protocol/use-server-pages.ts +9 -5
- package/lib/utils.ts +21 -20
- package/package.json +2 -2
- package/public/voices/alloy.ogg +0 -0
- package/public/voices/ash.ogg +0 -0
- package/public/voices/ballad.ogg +0 -0
- package/public/voices/beacon.ogg +0 -0
- package/public/voices/bossa.ogg +0 -0
- package/public/voices/cedar.ogg +0 -0
- package/public/voices/cinder.ogg +0 -0
- package/public/voices/coral.ogg +0 -0
- package/public/voices/delta.ogg +0 -0
- package/public/voices/echo.ogg +0 -0
- package/public/voices/gleam.ogg +0 -0
- package/public/voices/marin.ogg +0 -0
- package/public/voices/meridian.ogg +0 -0
- package/public/voices/quartz.ogg +0 -0
- package/public/voices/ripple.ogg +0 -0
- package/public/voices/sage.ogg +0 -0
- package/public/voices/shimmer.ogg +0 -0
- package/public/voices/stone.ogg +0 -0
- package/public/voices/tempo.ogg +0 -0
- package/public/voices/verse.ogg +0 -0
- package/public/voices/vesper.ogg +0 -0
- package/public/voices/willow.ogg +0 -0
- package/scripts/artifact-paths.test.mts +25 -0
- package/scripts/bot-context.test.mts +1408 -0
- package/scripts/live-history.test.mts +115 -0
- package/scripts/live-session.test.mts +948 -0
- package/server.js +1 -1
- package/skills/browser/SKILL.md +17 -6
- package/skills/computer/SKILL.md +1 -1
- package/skills/find-skills/SKILL.md +3 -8
- package/skills/interactive-page/SKILL.md +12 -7
- package/skills/interactive-page/references/diagram.md +89 -0
- package/skills/interactive-page/scripts/archify/LICENSE +22 -0
- package/skills/interactive-page/scripts/archify/README.md +25 -0
- package/skills/interactive-page/scripts/archify/assets/JetBrainsMono-OFL.txt +93 -0
- package/skills/interactive-page/scripts/archify/assets/template.html +14934 -0
- package/skills/interactive-page/scripts/archify/bin/archify.mjs +2126 -0
- package/skills/interactive-page/scripts/archify/bin/open-artifact.mjs +86 -0
- package/skills/interactive-page/scripts/archify/bin/preview.mjs +653 -0
- package/skills/interactive-page/scripts/archify/bin/visual-check.mjs +829 -0
- package/skills/interactive-page/scripts/archify/delta/architecture-delta.mjs +1223 -0
- package/skills/interactive-page/scripts/archify/examples/agent-run.lifecycle.json +60 -0
- package/skills/interactive-page/scripts/archify/examples/agent-tool-call.workflow.json +94 -0
- package/skills/interactive-page/scripts/archify/examples/async-job-roundtrip.sequence.json +61 -0
- package/skills/interactive-page/scripts/archify/examples/cache-miss-request.sequence.json +82 -0
- package/skills/interactive-page/scripts/archify/examples/checkout-platform.base.architecture.json +31 -0
- package/skills/interactive-page/scripts/archify/examples/checkout-platform.head.architecture.json +31 -0
- package/skills/interactive-page/scripts/archify/examples/deployment-release.lifecycle.json +49 -0
- package/skills/interactive-page/scripts/archify/examples/event-stream.dataflow.json +57 -0
- package/skills/interactive-page/scripts/archify/examples/incident-response.workflow.json +64 -0
- package/skills/interactive-page/scripts/archify/examples/product-analytics.dataflow.json +76 -0
- package/skills/interactive-page/scripts/archify/examples/production-deployment.architecture.json +71 -0
- package/skills/interactive-page/scripts/archify/examples/release-delivery.workflow.json +62 -0
- package/skills/interactive-page/scripts/archify/examples/web-app.architecture.json +46 -0
- package/skills/interactive-page/scripts/archify/migrations/workflow-v2.mjs +279 -0
- package/skills/interactive-page/scripts/archify/recipes/scenarios.mjs +284 -0
- package/skills/interactive-page/scripts/archify/references/authoring-contract.md +243 -0
- package/skills/interactive-page/scripts/archify/references/delivery-contract.md +120 -0
- package/skills/interactive-page/scripts/archify/references/viewer-runtime.md +45 -0
- package/skills/interactive-page/scripts/archify/renderers/architecture/grid.mjs +62 -0
- package/skills/interactive-page/scripts/archify/renderers/architecture/render-architecture.mjs +1078 -0
- package/skills/interactive-page/scripts/archify/renderers/dataflow/README.md +104 -0
- package/skills/interactive-page/scripts/archify/renderers/dataflow/render-dataflow.mjs +483 -0
- package/skills/interactive-page/scripts/archify/renderers/lifecycle/README.md +115 -0
- package/skills/interactive-page/scripts/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
- package/skills/interactive-page/scripts/archify/renderers/sequence/README.md +114 -0
- package/skills/interactive-page/scripts/archify/renderers/sequence/render-sequence.mjs +464 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/brand-marks.mjs +563 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/cli.mjs +218 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/desktop-readability.mjs +26 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/diagnostics.mjs +127 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/engineering-profiles.mjs +157 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/generated-brand-marks.mjs +3 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/generated-validators.mjs +13 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/geometry.mjs +1423 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/i18n.mjs +595 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/layout-report.mjs +40 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/legend.mjs +217 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/output-path.mjs +340 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/repository-evidence.mjs +238 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/repository-location.mjs +58 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/text-fit.mjs +49 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/utils.mjs +232 -0
- package/skills/interactive-page/scripts/archify/renderers/shared/validator.mjs +86 -0
- package/skills/interactive-page/scripts/archify/renderers/workflow/README.md +223 -0
- package/skills/interactive-page/scripts/archify/renderers/workflow/render-workflow.mjs +35 -0
- package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
- package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
- package/skills/interactive-page/scripts/archify/schemas/README.md +211 -0
- package/skills/interactive-page/scripts/archify/schemas/architecture.schema.json +178 -0
- package/skills/interactive-page/scripts/archify/schemas/common.schema.json +115 -0
- package/skills/interactive-page/scripts/archify/schemas/dataflow.schema.json +243 -0
- package/skills/interactive-page/scripts/archify/schemas/lifecycle.schema.json +266 -0
- package/skills/interactive-page/scripts/archify/schemas/sequence.schema.json +223 -0
- package/skills/interactive-page/scripts/archify/schemas/workflow.schema.json +428 -0
- package/skills/interactive-page/scripts/archify/scripts/check-render-output.mjs +916 -0
- package/skills/interactive-page/scripts/archify/scripts/render-examples.mjs +26 -0
- package/skills/interactive-page/scripts/bundle-artifact.sh +9 -8
- package/skills/skill-creator/SKILL.md +4 -5
- package/.next/server/app/api/bot/task/[id]/route/app-paths-manifest.json +0 -3
- package/.next/server/app/api/bot/task/[id]/route.js +0 -16
- package/.next/server/app/api/bot/task/[id]/route.js.nft.json +0 -1
- package/.next/server/app/api/bot/task/[id]/route_client-reference-manifest.js +0 -3
- package/.next/server/app/api/bot/task/route/app-paths-manifest.json +0 -3
- package/.next/server/app/api/bot/task/route.js +0 -16
- package/.next/server/app/api/bot/task/route.js.nft.json +0 -1
- package/.next/server/app/api/bot/task/route_client-reference-manifest.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__11n256_._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +0 -10
- package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +0 -8
- package/.next/server/chunks/_0-73of8._.js +0 -55
- package/.next/server/chunks/_0-fjql4._.js +0 -26
- package/.next/server/chunks/_00xh_q0._.js +0 -25
- package/.next/server/chunks/_03a0897._.js +0 -3
- package/.next/server/chunks/_051qh8u._.js +0 -3
- package/.next/server/chunks/_05sovvj._.js +0 -3
- package/.next/server/chunks/_0fzqt2y._.js +0 -134
- package/.next/server/chunks/_0mecv0f._.js +0 -26
- package/.next/server/chunks/_0mh8j4m._.js +0 -3
- package/.next/server/chunks/_0obojvv._.js +0 -3
- package/.next/server/chunks/_0sb7tlz._.js +0 -3
- package/.next/server/chunks/_0sbynis._.js +0 -3
- package/.next/server/chunks/_0u10wmw._.js +0 -55
- package/.next/server/chunks/_0u4aiy2._.js +0 -3
- package/.next/server/chunks/_0wp4le3._.js +0 -3
- package/.next/server/chunks/_0y5fg-x._.js +0 -3
- package/.next/server/chunks/_1230wbx._.js +0 -10
- package/.next/server/chunks/_12nheja._.js +0 -3
- package/.next/server/chunks/_13510xh._.js +0 -3
- package/.next/server/chunks/_15hq89o._.js +0 -3
- package/.next/server/chunks/_18-1wcc._.js +0 -55
- package/.next/server/chunks/_1_9mjx-._.js +0 -3
- package/.next/server/chunks/_1c78vw5._.js +0 -229
- package/.next/server/chunks/_1h5_8sk._.js +0 -3
- package/.next/server/chunks/_1hdnxb7._.js +0 -3
- package/.next/server/chunks/_1j8k_j5._.js +0 -3
- package/.next/server/chunks/_1nula3v._.js +0 -3
- package/.next/server/chunks/_1php4eq._.js +0 -3
- package/.next/server/chunks/_1yuv4vp._.js +0 -3
- package/.next/server/chunks/_1zjrdag._.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_bot_task_[id]_route_actions_1_k_8u3.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_bot_task_route_actions_0xln6ra.js +0 -3
- package/.next/server/chunks/features_0rpfxbk._.js +0 -3
- package/.next/server/chunks/features_1qf3cei._.js +0 -3
- package/.next/server/chunks/features_bot_0zt92oh._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +0 -3
- package/.next/server/chunks/ssr/[externals]__0dizgek._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__092knlj._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0mz33a7._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0s9dq5u._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0s9l2sv._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0xsog8n._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +0 -61
- package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +0 -43
- package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +0 -4
- package/.next/server/chunks/ssr/[root-of-the-server]__202p40z._.js +0 -3
- package/.next/server/chunks/ssr/_001_ms1._.js +0 -28
- package/.next/server/chunks/ssr/_01n3o0m._.js +0 -3
- package/.next/server/chunks/ssr/_0fz4mf_._.js +0 -3
- package/.next/server/chunks/ssr/_0gb4gmf._.js +0 -3
- package/.next/server/chunks/ssr/_0h42fze._.js +0 -3
- package/.next/server/chunks/ssr/_0h7zdni._.js +0 -3
- package/.next/server/chunks/ssr/_0ilna52._.js +0 -42
- package/.next/server/chunks/ssr/_0q0zan6._.js +0 -70
- package/.next/server/chunks/ssr/_0zcjrbg._.js +0 -3
- package/.next/server/chunks/ssr/_0zhoc3r._.js +0 -3
- package/.next/server/chunks/ssr/_13fke0x._.js +0 -3
- package/.next/server/chunks/ssr/_18cymkq._.js +0 -3
- package/.next/server/chunks/ssr/_1b2mjwr._.js +0 -3
- package/.next/server/chunks/ssr/_1f-dg-6._.js +0 -3
- package/.next/server/chunks/ssr/_1h0rw11._.js +0 -3
- package/.next/server/chunks/ssr/_1jhd09t._.js +0 -3
- package/.next/server/chunks/ssr/_1nnsk7z._.js +0 -3
- package/.next/server/chunks/ssr/_1ov37if._.js +0 -3
- package/.next/server/chunks/ssr/_1sji22n._.js +0 -3
- package/.next/server/chunks/ssr/_1vi_uo7._.js +0 -3
- package/.next/server/chunks/ssr/_1vyd1ji._.js +0 -3
- package/.next/server/chunks/ssr/_1xx4zlb._.js +0 -3
- package/.next/server/chunks/ssr/components_ui_1y1l7yj._.js +0 -3
- package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +0 -3
- package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +0 -27
- package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +0 -27
- package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0npjf8-._.js +0 -3
- package/.next/static/chunks/00rd4-v8r7axp.js +0 -1
- package/.next/static/chunks/08qe4as2q428z.js +0 -3
- package/.next/static/chunks/0gnqdjn2lvdad.js +0 -2
- package/.next/static/chunks/0hwap1-p0m5sa.js +0 -1
- package/.next/static/chunks/0r5qcctujhxli.js +0 -1
- package/.next/static/chunks/0w52rrrmuj9r9.js +0 -1
- package/.next/static/chunks/0wcprt5ot5she.js +0 -1
- package/.next/static/chunks/10teww7wt-f6h.js +0 -1
- package/.next/static/chunks/17p6tk6k88dq6.js +0 -1
- package/.next/static/chunks/18a96rkhi4_yd.js +0 -1
- package/.next/static/chunks/1dkjg87pxk0n9.js +0 -28
- package/.next/static/chunks/1jd09sxcjddu1.js +0 -1
- package/.next/static/chunks/1w73ece_6bheu.js +0 -18
- package/.next/static/chunks/214ya3n5gxeih.js +0 -1
- package/.next/static/chunks/22_zkas21rpna.js +0 -1
- package/.next/static/chunks/2fh4-3z_q8b_w.js +0 -1
- package/.next/static/chunks/2h0sd2vumhb15.js +0 -1
- package/.next/static/chunks/2t4vhi3m8ahya.js +0 -1
- package/.next/static/chunks/2tigdtz3dpcy8.js +0 -1
- package/.next/static/chunks/2u7xt6mxg44lf.js +0 -1
- package/.next/static/chunks/3786h5vayt80-.js +0 -28
- package/.next/static/chunks/39j0fvpybzabl.js +0 -40
- package/.next/static/chunks/3cq5g494yuke8.css +0 -1
- package/.next/static/chunks/3hibbjnt85-k6.js +0 -1
- package/.next/static/chunks/3woj-xd7ki5_i.js +0 -1
- package/.next/static/chunks/3xk7yqgomx7yq.js +0 -1
- package/.next/static/chunks/3zmcsnuo25zvq.js +0 -1
- package/database/migrations/20260911030320_opposite_jack_power/migration.sql +0 -1
- package/docs/images/task-thread.png +0 -0
- package/features/bot/components/task-badge.tsx +0 -42
- package/features/bot/components/task-reply.tsx +0 -328
- package/features/bot/components/task-setting.tsx +0 -524
- package/features/bot/task.query.ts +0 -976
- package/features/bot/task.store.ts +0 -489
- package/lib/realtime/client-secret.ts +0 -86
- package/lib/realtime/open-session.ts +0 -31
- package/lib/realtime/openai.ts +0 -35
- package/lib/realtime/realtime.audio.ts +0 -196
- package/lib/realtime/realtime.driver.ts +0 -489
- package/lib/realtime/realtime.protocol.ts +0 -393
- package/lib/realtime/realtime.schema.ts +0 -37
- package/lib/realtime/realtime.session.ts +0 -106
- package/lib/realtime/realtime.transport.ts +0 -384
- package/lib/realtime/xai.ts +0 -39
- /package/.next/server/app/api/bot/{task → thread}/[id]/route/build-manifest.json +0 -0
- /package/.next/server/app/api/bot/{task → thread}/[id]/route/server-reference-manifest.json +0 -0
- /package/.next/server/app/api/bot/{task → thread}/[id]/route.js.map +0 -0
- /package/.next/server/app/api/bot/{task → thread}/route/build-manifest.json +0 -0
- /package/.next/server/app/api/bot/{task → thread}/route/server-reference-manifest.json +0 -0
- /package/.next/server/app/api/bot/{task → thread}/route.js.map +0 -0
- /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_buildManifest.js +0 -0
- /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_ssgManifest.js +0 -0
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ChevronDown,
|
|
5
5
|
ChevronUp,
|
|
6
6
|
Flag,
|
|
7
|
+
Loader2,
|
|
7
8
|
type LucideIcon,
|
|
8
9
|
Mic,
|
|
9
10
|
MicOff,
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
TooltipProvider,
|
|
22
23
|
TooltipTrigger,
|
|
23
24
|
} from "@/components/ui/tooltip";
|
|
24
|
-
import {
|
|
25
|
+
import { LIVE_PROVIDER } from "@/features/ai/live.schema";
|
|
25
26
|
import { type Bot, DEFAULT_BOT } from "@/features/bot/bot.schema";
|
|
26
27
|
import { BotMark } from "@/features/bot/components/bot-mark";
|
|
27
28
|
import { BotRoom } from "@/features/bot/components/bot-room";
|
|
@@ -45,7 +46,10 @@ import {
|
|
|
45
46
|
type ThursdayFace,
|
|
46
47
|
} from "@/features/thursday/thursday.schema";
|
|
47
48
|
import { useThursdayStore } from "@/features/thursday/thursday.store";
|
|
48
|
-
import {
|
|
49
|
+
import {
|
|
50
|
+
type ActivityLine,
|
|
51
|
+
useThursday,
|
|
52
|
+
} from "@/features/thursday/use-thursday";
|
|
49
53
|
import { ArtifactView } from "@/features/workspace/components/artifact-view";
|
|
50
54
|
import { useHotkeyLabel } from "@/hooks/use-hotkey";
|
|
51
55
|
import { useServerRoute } from "@/lib/protocol/use-server-route";
|
|
@@ -63,9 +67,13 @@ export type { CaptionView };
|
|
|
63
67
|
|
|
64
68
|
export type CallScreenProps = {
|
|
65
69
|
status: CallStatus;
|
|
70
|
+
/** A call just failed to open or dropped; the face says so for a few seconds. */
|
|
71
|
+
failed?: boolean;
|
|
66
72
|
/** Oldest first; the last one is the turn being spoken. */
|
|
67
73
|
messages: CallMessage[];
|
|
68
|
-
tool:
|
|
74
|
+
tool: ActivityLine | null;
|
|
75
|
+
/** When the backend picked the turn up (ms); null when it is not working. */
|
|
76
|
+
thinkingSince?: number | null;
|
|
69
77
|
onTap: () => void;
|
|
70
78
|
/** Wake phrase; null when the tap is the only entry point. */
|
|
71
79
|
wakePhrase?: string | null;
|
|
@@ -75,8 +83,6 @@ export type CallScreenProps = {
|
|
|
75
83
|
idleLeft?: number | null;
|
|
76
84
|
/** When the line opened (ms). */
|
|
77
85
|
since?: number | null;
|
|
78
|
-
/** Mic muted (use-thursday micOff): a tool is running or a relay is being read. */
|
|
79
|
-
micOff?: boolean;
|
|
80
86
|
getSpectrum?: () => ArrayLike<number>;
|
|
81
87
|
/** The user's own mic bands, for the listening meter. */
|
|
82
88
|
getMicSpectrum?: () => ArrayLike<number>;
|
|
@@ -89,14 +95,15 @@ export type CallScreenProps = {
|
|
|
89
95
|
|
|
90
96
|
export function CallScreen({
|
|
91
97
|
status,
|
|
98
|
+
failed = false,
|
|
92
99
|
messages,
|
|
93
100
|
tool,
|
|
101
|
+
thinkingSince = null,
|
|
94
102
|
onTap,
|
|
95
103
|
wakePhrase = null,
|
|
96
104
|
hotkeyLabel = null,
|
|
97
105
|
idleLeft = null,
|
|
98
106
|
since = null,
|
|
99
|
-
micOff = false,
|
|
100
107
|
getSpectrum,
|
|
101
108
|
getMicSpectrum,
|
|
102
109
|
captionView = "center",
|
|
@@ -106,8 +113,8 @@ export function CallScreen({
|
|
|
106
113
|
// without a key the face opens the key prompt instead of a call
|
|
107
114
|
const [asking, setAsking] = useState(false);
|
|
108
115
|
const asleep = !callable && status === "idle";
|
|
109
|
-
const busy = status === "connecting";
|
|
110
|
-
const live = status !== "idle" &&
|
|
116
|
+
const busy = status === "connecting" || status === "ending";
|
|
117
|
+
const live = status !== "idle" && !busy;
|
|
111
118
|
// The caption box holds her words and nothing else, so the line she just
|
|
112
119
|
// said stays put while she listens or works.
|
|
113
120
|
const hers =
|
|
@@ -152,7 +159,9 @@ export function CallScreen({
|
|
|
152
159
|
<Face
|
|
153
160
|
look={face}
|
|
154
161
|
status={status}
|
|
162
|
+
failed={failed}
|
|
155
163
|
getSpectrum={getSpectrum}
|
|
164
|
+
getMicSpectrum={getMicSpectrum}
|
|
156
165
|
className="w-full"
|
|
157
166
|
/>
|
|
158
167
|
</button>
|
|
@@ -169,8 +178,8 @@ export function CallScreen({
|
|
|
169
178
|
(use-thursday). */}
|
|
170
179
|
<ActivityRow
|
|
171
180
|
tool={tool}
|
|
172
|
-
|
|
173
|
-
listening={status === "listening"}
|
|
181
|
+
thinkingSince={thinkingSince}
|
|
182
|
+
listening={status === "listening" && thinkingSince === null}
|
|
174
183
|
getMicSpectrum={getMicSpectrum}
|
|
175
184
|
/>
|
|
176
185
|
|
|
@@ -180,6 +189,7 @@ export function CallScreen({
|
|
|
180
189
|
text={sided || status === "idle" ? "" : hers}
|
|
181
190
|
fixed
|
|
182
191
|
paged
|
|
192
|
+
fadeIn
|
|
183
193
|
className="w-full max-w-160 text-center text-base"
|
|
184
194
|
/>
|
|
185
195
|
|
|
@@ -213,7 +223,7 @@ export function CallScreen({
|
|
|
213
223
|
</div>
|
|
214
224
|
</div>
|
|
215
225
|
|
|
216
|
-
{/* Documents a finished
|
|
226
|
+
{/* Documents a finished thread produced; opens itself on the artifact event */}
|
|
217
227
|
<ArtifactView />
|
|
218
228
|
|
|
219
229
|
<BotRoom />
|
|
@@ -223,7 +233,7 @@ export function CallScreen({
|
|
|
223
233
|
|
|
224
234
|
/**
|
|
225
235
|
* The corner is one group: three rooms as single buttons, everything else
|
|
226
|
-
* behind the gear.
|
|
236
|
+
* behind the gear. Threads is left out because the other corner is that room.
|
|
227
237
|
*/
|
|
228
238
|
const CORNER = ["thursday", "memory", "bot"] as const;
|
|
229
239
|
|
|
@@ -333,7 +343,7 @@ const CAPTION_PADS = ["px-4 py-3", "px-3.5 py-2.5", "px-3 py-2"];
|
|
|
333
343
|
* page's own — the ascii field is boot and intro only — so an outline covers
|
|
334
344
|
* nothing and ends up being the whole design.
|
|
335
345
|
*
|
|
336
|
-
* Yours is the surface `Bubble` already gives your words in
|
|
346
|
+
* Yours is the surface `Bubble` already gives your words in a thread
|
|
337
347
|
* (primary, light ink); hers is the page's grey. Age recedes in the fill, not
|
|
338
348
|
* in the block's opacity, which would take the ink down with it.
|
|
339
349
|
*/
|
|
@@ -368,6 +378,7 @@ function Flow({
|
|
|
368
378
|
lines = CAPTION_LINES,
|
|
369
379
|
fixed = false,
|
|
370
380
|
paged = false,
|
|
381
|
+
fadeIn = false,
|
|
371
382
|
className,
|
|
372
383
|
}: {
|
|
373
384
|
text: string;
|
|
@@ -378,6 +389,8 @@ function Flow({
|
|
|
378
389
|
fixed?: boolean;
|
|
379
390
|
/** Page overflow with chevrons; needs side margin. */
|
|
380
391
|
paged?: boolean;
|
|
392
|
+
/** Each new character fades in as it arrives; what is already drawn stays put. */
|
|
393
|
+
fadeIn?: boolean;
|
|
381
394
|
className?: string;
|
|
382
395
|
}) {
|
|
383
396
|
const box = useRef<HTMLParagraphElement>(null);
|
|
@@ -420,7 +433,17 @@ function Flow({
|
|
|
420
433
|
className={cn("break-keep", paged && "transition-transform duration-200")}
|
|
421
434
|
>
|
|
422
435
|
{lead}
|
|
423
|
-
{
|
|
436
|
+
{fadeIn
|
|
437
|
+
? // char + index: a character already drawn keeps its key and never fades twice
|
|
438
|
+
Array.from(text).map((char, index) => (
|
|
439
|
+
<span
|
|
440
|
+
key={`${char}${index}`}
|
|
441
|
+
className="animate-in fade-in duration-300 motion-reduce:animate-none"
|
|
442
|
+
>
|
|
443
|
+
{char}
|
|
444
|
+
</span>
|
|
445
|
+
))
|
|
446
|
+
: text}
|
|
424
447
|
</p>
|
|
425
448
|
);
|
|
426
449
|
|
|
@@ -626,7 +649,7 @@ function Ear({
|
|
|
626
649
|
* which has no container either, so an outline under one of the two read as the
|
|
627
650
|
* line changing shape rather than changing state.
|
|
628
651
|
*/
|
|
629
|
-
function Activity({ tool
|
|
652
|
+
function Activity({ tool }: { tool: ActivityLine }) {
|
|
630
653
|
// a relay from a bot is a flag, like the answer tool — unless it names the bot
|
|
631
654
|
const relay = tool.kind === "relay";
|
|
632
655
|
const Icon = relay ? Flag : toolIcon(tool.name);
|
|
@@ -662,17 +685,7 @@ function Activity({ tool, micOff }: { tool: ToolRun; micOff: boolean }) {
|
|
|
662
685
|
{tool.done ? (
|
|
663
686
|
<span className={cn(look, "text-muted-foreground")}>{text}</span>
|
|
664
687
|
) : (
|
|
665
|
-
<ShinyText text={text}
|
|
666
|
-
)}
|
|
667
|
-
{/* The mic is closed because this is running, so it travels with the line.
|
|
668
|
-
A chip, where the line has none: on the bare page a second glyph beside
|
|
669
|
-
the tool's own shares strokes with it and reads as a smudge, and the
|
|
670
|
-
plate is what says this is a state rather than more of the sentence. */}
|
|
671
|
-
{micOff && (
|
|
672
|
-
<span className="flex shrink-0 items-center gap-1 rounded-full bg-muted/60 py-0.5 pr-2 pl-1.5 font-mono text-[11px] leading-4 text-muted-foreground">
|
|
673
|
-
<MicOff className="size-3 shrink-0" />
|
|
674
|
-
mic off
|
|
675
|
-
</span>
|
|
688
|
+
<ShinyText text={text} motion="pulse" className={look} />
|
|
676
689
|
)}
|
|
677
690
|
</span>
|
|
678
691
|
);
|
|
@@ -691,7 +704,7 @@ function Mark({
|
|
|
691
704
|
icon: Icon,
|
|
692
705
|
running,
|
|
693
706
|
}: {
|
|
694
|
-
tool:
|
|
707
|
+
tool: ActivityLine;
|
|
695
708
|
/** The row the name resolved to, when the roster has one; its look, not its identity. */
|
|
696
709
|
bot: Bot | null;
|
|
697
710
|
icon: LucideIcon;
|
|
@@ -703,10 +716,10 @@ function Mark({
|
|
|
703
716
|
<BotMark
|
|
704
717
|
size={16}
|
|
705
718
|
seed={tool.bot}
|
|
706
|
-
vary={tool.bot}
|
|
707
719
|
color={bot?.icon?.color}
|
|
708
720
|
shape={bot?.icon?.shape}
|
|
709
721
|
outline={bot?.icon?.outline}
|
|
722
|
+
paint={bot?.icon?.paint}
|
|
710
723
|
notify={false}
|
|
711
724
|
/>
|
|
712
725
|
</span>
|
|
@@ -724,18 +737,19 @@ function Mark({
|
|
|
724
737
|
}
|
|
725
738
|
|
|
726
739
|
/**
|
|
727
|
-
* The activity slot: 28px, one fact at a time,
|
|
740
|
+
* The activity slot: 28px, one fact at a time, three faces. All stay mounted and
|
|
728
741
|
* cross-fade, so the line leaves wearing its last words instead of blinking
|
|
729
|
-
* out, and the caption below never moves while they trade places.
|
|
742
|
+
* out, and the caption below never moves while they trade places. A tool wins
|
|
743
|
+
* over thinking: it is the same stretch of work, said more exactly.
|
|
730
744
|
*/
|
|
731
745
|
function ActivityRow({
|
|
732
746
|
tool,
|
|
733
|
-
|
|
747
|
+
thinkingSince,
|
|
734
748
|
listening,
|
|
735
749
|
getMicSpectrum,
|
|
736
750
|
}: {
|
|
737
|
-
tool:
|
|
738
|
-
|
|
751
|
+
tool: ActivityLine | null;
|
|
752
|
+
thinkingSince: number | null;
|
|
739
753
|
listening: boolean;
|
|
740
754
|
getMicSpectrum?: () => ArrayLike<number>;
|
|
741
755
|
}) {
|
|
@@ -744,13 +758,26 @@ function ActivityRow({
|
|
|
744
758
|
useEffect(() => {
|
|
745
759
|
if (tool) setShown(tool);
|
|
746
760
|
}, [tool]);
|
|
761
|
+
// and past the thinking, for the same reason
|
|
762
|
+
const [since, setSince] = useState(thinkingSince);
|
|
763
|
+
useEffect(() => {
|
|
764
|
+
if (thinkingSince !== null) setSince(thinkingSince);
|
|
765
|
+
}, [thinkingSince]);
|
|
747
766
|
|
|
748
767
|
const hearing = listening && !tool;
|
|
749
768
|
return (
|
|
750
769
|
<div className="grid h-7 max-w-full items-center justify-items-center">
|
|
751
770
|
{shown && (
|
|
752
771
|
<Fade at="col-start-1 row-start-1 max-w-full" shown={tool !== null}>
|
|
753
|
-
<Activity tool={shown}
|
|
772
|
+
<Activity tool={shown} />
|
|
773
|
+
</Fade>
|
|
774
|
+
)}
|
|
775
|
+
{since !== null && (
|
|
776
|
+
<Fade
|
|
777
|
+
at="col-start-1 row-start-1"
|
|
778
|
+
shown={thinkingSince !== null && !tool}
|
|
779
|
+
>
|
|
780
|
+
<Thinking since={since} running={thinkingSince !== null && !tool} />
|
|
754
781
|
</Fade>
|
|
755
782
|
)}
|
|
756
783
|
<Fade at="col-start-1 row-start-1" shown={hearing}>
|
|
@@ -802,7 +829,7 @@ function Hint({
|
|
|
802
829
|
wakePhrase: string | null;
|
|
803
830
|
hotkeyLabel: string | null;
|
|
804
831
|
}) {
|
|
805
|
-
const busy = status === "connecting";
|
|
832
|
+
const busy = status === "connecting" || status === "ending";
|
|
806
833
|
const live = status !== "idle" && !busy;
|
|
807
834
|
|
|
808
835
|
let body: React.ReactNode;
|
|
@@ -813,6 +840,7 @@ function Hint({
|
|
|
813
840
|
body = (
|
|
814
841
|
<ShinyText
|
|
815
842
|
text={status === "connecting" ? "Connecting…" : "Ending…"}
|
|
843
|
+
motion="pulse"
|
|
816
844
|
className="text-muted-foreground/70"
|
|
817
845
|
/>
|
|
818
846
|
);
|
|
@@ -910,7 +938,6 @@ function NeedsKey({
|
|
|
910
938
|
<BotMark
|
|
911
939
|
size={24}
|
|
912
940
|
seed={DEFAULT_BOT.name}
|
|
913
|
-
vary={DEFAULT_BOT.name}
|
|
914
941
|
color={DEFAULT_BOT.icon?.color}
|
|
915
942
|
shape={DEFAULT_BOT.icon?.shape}
|
|
916
943
|
outline={DEFAULT_BOT.icon?.outline}
|
|
@@ -928,6 +955,44 @@ function NeedsKey({
|
|
|
928
955
|
);
|
|
929
956
|
}
|
|
930
957
|
|
|
958
|
+
/**
|
|
959
|
+
* The backend has the turn: the activity line says so and counts, so the
|
|
960
|
+
* seconds before a tool and before her voice never read as a call that has
|
|
961
|
+
* stopped. A spinner fits here as it did not on a tool: there is no glyph yet
|
|
962
|
+
* for it to take off the screen. The seconds arrive after the first one, which
|
|
963
|
+
* is most answers.
|
|
964
|
+
*/
|
|
965
|
+
function Thinking({ since, running }: { since: number; running: boolean }) {
|
|
966
|
+
const [now, setNow] = useState(() => Date.now());
|
|
967
|
+
// Stays mounted to fade out; the count stops with it rather than ticking unseen
|
|
968
|
+
useEffect(() => {
|
|
969
|
+
if (!running) return;
|
|
970
|
+
// back from a tool, the first reading is now rather than where it paused
|
|
971
|
+
const first = setTimeout(() => setNow(Date.now()), 0);
|
|
972
|
+
const tick = setInterval(() => setNow(Date.now()), 1000);
|
|
973
|
+
return () => {
|
|
974
|
+
clearTimeout(first);
|
|
975
|
+
clearInterval(tick);
|
|
976
|
+
};
|
|
977
|
+
}, [running]);
|
|
978
|
+
const seconds = Math.max(0, Math.floor((now - since) / 1000));
|
|
979
|
+
return (
|
|
980
|
+
<span className="flex max-w-full items-center gap-1.5 text-[13px] leading-5">
|
|
981
|
+
{/* the 18px slot a tool's glyph takes over when one starts */}
|
|
982
|
+
<span className="grid size-[18px] shrink-0 place-items-center">
|
|
983
|
+
<Loader2 className="size-3.5 animate-spin text-muted-foreground" />
|
|
984
|
+
</span>
|
|
985
|
+
<ShinyText text="Thinking…" motion="pulse" />
|
|
986
|
+
{seconds >= 1 && (
|
|
987
|
+
<>
|
|
988
|
+
<span className="text-muted-foreground/40">·</span>
|
|
989
|
+
<span className="text-muted-foreground tabular-nums">{seconds}s</span>
|
|
990
|
+
</>
|
|
991
|
+
)}
|
|
992
|
+
</span>
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
|
|
931
996
|
/** Time since the line opened, mm:ss; only this span re-renders each second. */
|
|
932
997
|
function Elapsed({ since }: { since: number | null }) {
|
|
933
998
|
const [now, setNow] = useState(() => Date.now());
|
|
@@ -1095,11 +1160,12 @@ function SideCaptions({
|
|
|
1095
1160
|
export function Thursday() {
|
|
1096
1161
|
const {
|
|
1097
1162
|
status,
|
|
1163
|
+
failed,
|
|
1098
1164
|
messages,
|
|
1099
1165
|
tool,
|
|
1166
|
+
thinkingSince,
|
|
1100
1167
|
idleLeft,
|
|
1101
1168
|
since,
|
|
1102
|
-
micOff,
|
|
1103
1169
|
call,
|
|
1104
1170
|
getSpectrum,
|
|
1105
1171
|
getMicSpectrum,
|
|
@@ -1117,9 +1183,7 @@ export function Thursday() {
|
|
|
1117
1183
|
* can change during a call (NeedsKey). Unknown counts as not callable.
|
|
1118
1184
|
*/
|
|
1119
1185
|
const { data: config } = useServerRoute<ConfigStatus[]>(queryKey.config);
|
|
1120
|
-
const callable =
|
|
1121
|
-
isConfigSet(config, provider.apiKeyName),
|
|
1122
|
-
);
|
|
1186
|
+
const callable = isConfigSet(config, LIVE_PROVIDER.apiKeyName);
|
|
1123
1187
|
|
|
1124
1188
|
return (
|
|
1125
1189
|
<>
|
|
@@ -1127,14 +1191,15 @@ export function Thursday() {
|
|
|
1127
1191
|
<TabState live={status !== "idle"} />
|
|
1128
1192
|
<CallScreen
|
|
1129
1193
|
status={status}
|
|
1194
|
+
failed={failed}
|
|
1130
1195
|
messages={messages}
|
|
1131
1196
|
tool={tool}
|
|
1197
|
+
thinkingSince={thinkingSince}
|
|
1132
1198
|
onTap={call}
|
|
1133
1199
|
wakePhrase={wakePhrase}
|
|
1134
1200
|
hotkeyLabel={hotkeyLabel}
|
|
1135
1201
|
idleLeft={idleLeft}
|
|
1136
1202
|
since={since}
|
|
1137
|
-
micOff={micOff}
|
|
1138
1203
|
getSpectrum={getSpectrum}
|
|
1139
1204
|
getMicSpectrum={getMicSpectrum}
|
|
1140
1205
|
face={face}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Check, ChevronDown, X } from "lucide-react";
|
|
4
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
|
+
import { Button } from "@/components/ui/button";
|
|
6
|
+
import { Input, inputClassName } from "@/components/ui/input";
|
|
7
|
+
import { ShinyText } from "@/components/ui/shiny-text";
|
|
8
|
+
import { toast } from "@/components/ui/toast";
|
|
9
|
+
import {
|
|
10
|
+
LIVE_VOICE_NOTE,
|
|
11
|
+
LIVE_VOICES,
|
|
12
|
+
voiceSamplePath,
|
|
13
|
+
} from "@/features/ai/live.schema";
|
|
14
|
+
import { Face } from "@/features/thursday/components/face";
|
|
15
|
+
import type { ThursdayFace } from "@/features/thursday/thursday.schema";
|
|
16
|
+
import { createClipTap, SPECTRUM_BANDS } from "@/lib/live/live.tap";
|
|
17
|
+
import { cn, errorToString } from "@/lib/utils";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Choosing a voice by ear. A name plays its recorded line and her own face
|
|
21
|
+
* speaks it — the same component and the same bands a call moves her with, so
|
|
22
|
+
* what you hear and see here is what the call will be. Only Save writes, so
|
|
23
|
+
* hearing eleven voices stores none of them.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const SILENT = new Array<number>(SPECTRUM_BANDS).fill(0);
|
|
27
|
+
|
|
28
|
+
export function VoicePicker({
|
|
29
|
+
voice,
|
|
30
|
+
face,
|
|
31
|
+
onChange,
|
|
32
|
+
}: {
|
|
33
|
+
/** The saved voice: what the next call opens with. */
|
|
34
|
+
voice: string;
|
|
35
|
+
face: ThursdayFace;
|
|
36
|
+
onChange: (voice: string) => void;
|
|
37
|
+
}) {
|
|
38
|
+
const [open, setOpen] = useState(false);
|
|
39
|
+
const [heard, setHeard] = useState(voice);
|
|
40
|
+
const [playing, setPlaying] = useState(false);
|
|
41
|
+
const [typed, setTyped] = useState("");
|
|
42
|
+
|
|
43
|
+
const clip = useRef<HTMLAudioElement>(null);
|
|
44
|
+
// A tap belongs to the element it routes, which exists only while the picker is open.
|
|
45
|
+
const tap = useRef<{
|
|
46
|
+
element: HTMLAudioElement;
|
|
47
|
+
clip: ReturnType<typeof createClipTap>;
|
|
48
|
+
} | null>(null);
|
|
49
|
+
// Each play and each stop takes the next number; a failure reported for an
|
|
50
|
+
// earlier one changes nothing.
|
|
51
|
+
const plays = useRef(0);
|
|
52
|
+
// The face reads the spectrum once per animation frame, so what it reads is a
|
|
53
|
+
// ref, not state: a stable function, and silence when nothing is playing.
|
|
54
|
+
const sounding = useRef(false);
|
|
55
|
+
const spectrum = useCallback(
|
|
56
|
+
() => (tap.current && sounding.current ? tap.current.clip.read() : SILENT),
|
|
57
|
+
[],
|
|
58
|
+
);
|
|
59
|
+
const showPlaying = (on: boolean) => {
|
|
60
|
+
sounding.current = on;
|
|
61
|
+
setPlaying(on);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// The element goes when the picker closes; its graph goes with it.
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!open) return;
|
|
67
|
+
return () => {
|
|
68
|
+
const held = tap.current;
|
|
69
|
+
tap.current = null;
|
|
70
|
+
if (!held) return;
|
|
71
|
+
held.element.pause();
|
|
72
|
+
void held.clip.close();
|
|
73
|
+
};
|
|
74
|
+
}, [open]);
|
|
75
|
+
|
|
76
|
+
const failed = (play: number, cause: unknown) => {
|
|
77
|
+
if (play !== plays.current) return;
|
|
78
|
+
plays.current++;
|
|
79
|
+
showPlaying(false);
|
|
80
|
+
toast.add({
|
|
81
|
+
type: "error",
|
|
82
|
+
title: "Voice sample did not play",
|
|
83
|
+
description: errorToString(cause),
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const stop = () => {
|
|
88
|
+
plays.current++;
|
|
89
|
+
const audio = clip.current;
|
|
90
|
+
if (audio) {
|
|
91
|
+
audio.pause();
|
|
92
|
+
audio.currentTime = 0;
|
|
93
|
+
}
|
|
94
|
+
showPlaying(false);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const audition = (next: string) => {
|
|
98
|
+
const audio = clip.current;
|
|
99
|
+
if (!audio) return;
|
|
100
|
+
if (playing && next === heard) {
|
|
101
|
+
stop();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
setHeard(next);
|
|
105
|
+
setTyped("");
|
|
106
|
+
// The graph is built inside the gesture that plays: an AudioContext made
|
|
107
|
+
// before one is refused. An element is routed once, so it keeps its tap.
|
|
108
|
+
if (tap.current?.element !== audio) {
|
|
109
|
+
void tap.current?.clip.close();
|
|
110
|
+
tap.current = { element: audio, clip: createClipTap(audio) };
|
|
111
|
+
}
|
|
112
|
+
void tap.current.clip.resume();
|
|
113
|
+
const play = ++plays.current;
|
|
114
|
+
audio.src = voiceSamplePath(next);
|
|
115
|
+
showPlaying(true);
|
|
116
|
+
void audio.play().catch((cause: unknown) => {
|
|
117
|
+
// A later click or a stop cut this one short; that play owns the state.
|
|
118
|
+
if (cause instanceof DOMException && cause.name === "AbortError") return;
|
|
119
|
+
failed(play, cause);
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const close = () => {
|
|
124
|
+
stop();
|
|
125
|
+
setOpen(false);
|
|
126
|
+
setTyped("");
|
|
127
|
+
setHeard(voice);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const save = () => {
|
|
131
|
+
const picked = typed.trim() || heard;
|
|
132
|
+
stop();
|
|
133
|
+
setOpen(false);
|
|
134
|
+
setTyped("");
|
|
135
|
+
setHeard(picked);
|
|
136
|
+
if (picked !== voice) onChange(picked);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
if (!open) {
|
|
140
|
+
return (
|
|
141
|
+
<button
|
|
142
|
+
type="button"
|
|
143
|
+
onClick={() => setOpen(true)}
|
|
144
|
+
aria-label="Voice"
|
|
145
|
+
className={cn(
|
|
146
|
+
inputClassName,
|
|
147
|
+
"flex items-center gap-2 text-left font-mono text-sm hover:border-ring",
|
|
148
|
+
)}
|
|
149
|
+
>
|
|
150
|
+
<span className="shrink-0">{voice}</span>
|
|
151
|
+
<span className="min-w-0 truncate text-[11px] text-muted-foreground">
|
|
152
|
+
{LIVE_VOICE_NOTE[voice as keyof typeof LIVE_VOICE_NOTE]}
|
|
153
|
+
</span>
|
|
154
|
+
<ChevronDown className="ml-auto size-3.5 shrink-0 text-muted-foreground" />
|
|
155
|
+
</button>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<div className="@container space-y-2">
|
|
161
|
+
{/* Nothing here plays through the page's own speakers but this element. */}
|
|
162
|
+
<audio
|
|
163
|
+
ref={clip}
|
|
164
|
+
onEnded={() => showPlaying(false)}
|
|
165
|
+
// A clip that breaks after it starts fails here, not in play()
|
|
166
|
+
onError={(event) => {
|
|
167
|
+
if (!sounding.current) return;
|
|
168
|
+
failed(
|
|
169
|
+
plays.current,
|
|
170
|
+
event.currentTarget.error?.message || "The clip could not be read.",
|
|
171
|
+
);
|
|
172
|
+
}}
|
|
173
|
+
>
|
|
174
|
+
<track kind="captions" />
|
|
175
|
+
</audio>
|
|
176
|
+
|
|
177
|
+
<div className="rounded-xl border border-border/60 p-3">
|
|
178
|
+
<div className="mb-2 flex items-center gap-2">
|
|
179
|
+
<span className="font-mono text-[11px] text-muted-foreground">
|
|
180
|
+
click a name to hear it
|
|
181
|
+
</span>
|
|
182
|
+
<Button
|
|
183
|
+
variant="ghost"
|
|
184
|
+
size="icon-xs"
|
|
185
|
+
className="ml-auto"
|
|
186
|
+
aria-label="Close"
|
|
187
|
+
onClick={close}
|
|
188
|
+
>
|
|
189
|
+
<X />
|
|
190
|
+
</Button>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<div className="grid gap-4 @md:grid-cols-[11rem_minmax(0,1fr)]">
|
|
194
|
+
<div className="flex flex-col items-center gap-2">
|
|
195
|
+
<Face
|
|
196
|
+
look={face}
|
|
197
|
+
status={playing ? "speaking" : "idle"}
|
|
198
|
+
getSpectrum={spectrum}
|
|
199
|
+
size={176}
|
|
200
|
+
className="w-44"
|
|
201
|
+
/>
|
|
202
|
+
<span className="text-sm font-medium">
|
|
203
|
+
{playing ? <ShinyText text={heard} /> : heard}
|
|
204
|
+
</span>
|
|
205
|
+
<span className="h-4 font-mono text-[11px] text-muted-foreground">
|
|
206
|
+
{LIVE_VOICE_NOTE[heard as keyof typeof LIVE_VOICE_NOTE]}
|
|
207
|
+
</span>
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<div className="max-h-56 min-w-0 overflow-y-auto">
|
|
211
|
+
{LIVE_VOICES.map((name) => (
|
|
212
|
+
<button
|
|
213
|
+
type="button"
|
|
214
|
+
key={name}
|
|
215
|
+
onClick={() => audition(name)}
|
|
216
|
+
className={cn(
|
|
217
|
+
"flex w-full items-center gap-2 rounded-md px-1.5 py-1.5 text-sm outline-none hover:bg-accent focus-visible:bg-accent",
|
|
218
|
+
name === heard && "bg-accent text-accent-foreground",
|
|
219
|
+
)}
|
|
220
|
+
>
|
|
221
|
+
<span className="flex-1 text-left">
|
|
222
|
+
{playing && name === heard ? <ShinyText text={name} /> : name}
|
|
223
|
+
</span>
|
|
224
|
+
<span className="shrink truncate font-mono text-[11px] text-muted-foreground">
|
|
225
|
+
{LIVE_VOICE_NOTE[name]}
|
|
226
|
+
</span>
|
|
227
|
+
<Check
|
|
228
|
+
className={cn(
|
|
229
|
+
"size-3.5 shrink-0",
|
|
230
|
+
name === voice ? "opacity-100" : "opacity-0",
|
|
231
|
+
)}
|
|
232
|
+
/>
|
|
233
|
+
</button>
|
|
234
|
+
))}
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
{/* A voice id that is not on the list still runs; it simply has no clip. */}
|
|
240
|
+
<div className="flex gap-2">
|
|
241
|
+
<Input
|
|
242
|
+
value={typed}
|
|
243
|
+
onChange={(event) => setTyped(event.target.value)}
|
|
244
|
+
placeholder="another voice id"
|
|
245
|
+
aria-label="Another voice id"
|
|
246
|
+
spellCheck={false}
|
|
247
|
+
className="font-mono text-sm"
|
|
248
|
+
/>
|
|
249
|
+
<Button className="shrink-0" onClick={save}>
|
|
250
|
+
Save
|
|
251
|
+
</Button>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
);
|
|
255
|
+
}
|