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.
- 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 +5 -4
- 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 +4 -4
- 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 +15 -15
- 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 +9 -10
- 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 -5
- 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 +11 -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]__0-06t3f._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__02846fb._.js +8 -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]__06l05n_._.js +3 -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]__0btqrct._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0c9fgca._.js +5 -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]__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/_1gnjfli._.js +3 -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_0v_7drq._.js → node_modules_consola_dist_chunks_prompt_mjs_0a7-pbw._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_17k8irj._.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_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]__0-e011f._.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]__0lyi8i2._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0pd8yr7._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
- 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]__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]__1vdmfbe._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1waa3rc._.js +85 -0
- package/.next/server/chunks/ssr/_0-2qsxo._.js +3 -0
- package/.next/server/chunks/ssr/_00rehl_._.js +3 -0
- package/.next/server/chunks/ssr/{_1lz_cq2._.js → _02oc_h5._.js} +76 -97
- package/.next/server/chunks/ssr/_05yghx6._.js +3 -0
- package/.next/server/chunks/ssr/_07nbwap._.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/{_0m2lsd1._.js → _0b6_jv-._.js} +2 -2
- package/.next/server/chunks/ssr/_0evkpto._.js +3 -0
- package/.next/server/chunks/ssr/_0geg212._.js +3 -0
- package/.next/server/chunks/ssr/{_1jdgjv9._.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/_0no7i1o._.js +3 -0
- package/.next/server/chunks/ssr/_0tzg--b._.js +3 -0
- 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/_114ylv7._.js +7 -0
- package/.next/server/chunks/ssr/_123y-ah._.js +3 -0
- package/.next/server/chunks/ssr/_12c-iwh._.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/_167hchk._.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/_1_krfph._.js +3 -0
- package/.next/server/chunks/ssr/{_0rzucul._.js → _1_x5spz._.js} +3 -3
- package/.next/server/chunks/ssr/_1a61fc9._.js +3 -0
- 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/_1rgtxhr._.js +5 -0
- package/.next/server/chunks/ssr/_1slp25y._.js +3 -0
- package/.next/server/chunks/ssr/_1w_t7h7._.js +101 -0
- package/.next/server/chunks/ssr/{_0s99bgb._.js → _1wyfaq_._.js} +9 -3
- package/.next/server/chunks/ssr/_200gt-m._.js +102 -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/features_workspace_00jz2hu._.js +8 -0
- package/.next/server/chunks/ssr/{_1-teee5._.js → lib_logger_ts_0-olsze._.js} +2 -7
- package/.next/server/chunks/ssr/{node_modules_05-n6dz._.js → node_modules_02ai7br._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1chvq5f._.js → node_modules_02deexj._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0m383r2._.js → node_modules_07za262._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_07dsgkx._.js → node_modules_0_s9get._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1a0kmjl._.js → node_modules_0n3c7h0._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0zeg3x_._.js → node_modules_0od6jwr._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1y79i83._.js → node_modules_0rdt7pk._.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_04sksn9._.js → node_modules_0w1z7kz._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1uyk91w._.js → node_modules_0wdupfz._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0ifp389._.js → node_modules_1720w0a._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0u9da1h._.js → node_modules_18lsg7d._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1k6n600._.js → node_modules_1b94fxf._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_20c28js._.js → node_modules_1ecdo1s._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0fkeku3._.js → node_modules_1fa9ag7._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1j8j4pt._.js → node_modules_1fv-_si._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0-dr_o7._.js → node_modules_1hf461g._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1lz0oxc._.js → node_modules_1m71ta-._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1t77e4n._.js → node_modules_1n93n-g._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_16mkxuo._.js → node_modules_1n9lqu9._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1k7z2j6._.js → node_modules_1npnsvd._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_056qgf-._.js → node_modules_1rn2r0n._.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_0bvopy2._.js → node_modules_1vq-mfk._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0iur59s._.js → node_modules_1vzyw1t._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1k8j8n0._.js → node_modules_1w359w4._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1x0ztf4._.js → node_modules_1yajbl6._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1-y7nni._.js → node_modules_20eqhy8._.js} +1 -1
- 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
- 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
- package/.next/server/chunks/ssr/{node_modules_@vercel_oidc_dist_1o553h-._.js → node_modules_@vercel_oidc_dist_05itbb1._.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/07vqbk_9t4em4.js +2 -0
- package/.next/static/chunks/08krja1zx7nqg.js +1 -0
- package/.next/static/chunks/0g4b348l0pve7.js +1 -0
- package/.next/static/chunks/0qcuwdk132jjt.js +1 -0
- package/.next/static/chunks/0vlgzqo9ka90v.js +1 -0
- package/.next/static/chunks/{11r2yp_yh9_qn.js → 0z69gvysmave7.js} +1 -1
- package/.next/static/chunks/0zrupxgci5gqc.js +1 -0
- package/.next/static/chunks/12fvz1w5ows75.js +1 -0
- package/.next/static/chunks/14t03ned286iu.js +1 -0
- package/.next/static/chunks/156xxbkrz5lzu.js +18 -0
- package/.next/static/chunks/1fz14reod4lft.js +1 -0
- package/.next/static/chunks/1g23dbabl-vkr.js +1 -0
- package/.next/static/chunks/1ohslk4568tm3.js +1 -0
- package/.next/static/chunks/1qy_rc3oxfxok.js +1 -0
- package/.next/static/chunks/1sbmwswc9k2-1.js +1 -0
- package/.next/static/chunks/1vqezbhjm3goq.js +1 -0
- package/.next/static/chunks/1zea7qdl-7365.js +1 -0
- package/.next/static/chunks/1zvqumkg7kmo0.css +1 -0
- package/.next/static/chunks/26hpqt3y6bogl.js +12 -0
- package/.next/static/chunks/2_j5mqm6d-z18.js +99 -0
- package/.next/static/chunks/2dt6tu7a22svs.js +1 -0
- package/.next/static/chunks/2h5ls3d86kya6.js +1 -0
- package/.next/static/chunks/2wc6y1ht6dfuy.js +1 -0
- package/.next/static/chunks/{435atsnhs7ksu.js → 2xr0zpll7thyi.js} +2 -2
- package/.next/static/chunks/31jztc-yq30m7.js +1 -0
- package/.next/static/chunks/391af0i8eljzk.js +1 -0
- package/.next/static/chunks/3bfwpww3m3x4u.js +1 -0
- package/.next/static/chunks/{38gweqdo4jpfj.js → 3izg0a3k87q1-.js} +5 -5
- package/.next/static/chunks/3p2s2cjokx1aa.js +5 -0
- package/.next/static/chunks/{408ueu4hfvcg7.js → 41s3fml5oivsa.js} +1 -1
- package/README.md +45 -193
- 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 +40 -35
- package/docs/images/keeps-going.png +0 -0
- package/docs/images/two-minds.png +0 -0
- package/docs/live-calls.md +236 -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 +152 -79
- 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 +169 -0
- package/features/ai/prompts/prompt-helper.ts +92 -32
- package/features/ai/prompts/thursday.prompt.ts +164 -190
- package/features/ai/tools/bot.tool.ts +38 -145
- package/features/ai/tools/call.tool.ts +33 -5
- 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 +11 -6
- package/features/ai/tools/studio.tool.ts +26 -21
- package/features/ai/tools/tool-name.ts +3 -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 +296 -744
- package/features/bot/bot.runner.ts +463 -864
- 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/ascii.const.ts +74 -0
- package/features/thursday/components/ascii-field.tsx +24 -44
- package/features/thursday/components/ascii-orb.tsx +525 -381
- package/features/thursday/components/call-log.tsx +46 -44
- package/features/thursday/components/face.tsx +40 -10
- package/features/thursday/components/side-captions.tsx +273 -0
- package/features/thursday/components/tab-state.tsx +14 -6
- package/features/thursday/components/thursday-mark.tsx +1 -0
- package/features/thursday/components/thursday-setting.tsx +633 -333
- package/features/thursday/components/thursday.tsx +315 -274
- package/features/thursday/components/voice-picker.tsx +255 -0
- package/features/thursday/face.store.ts +5 -0
- package/features/thursday/thursday.action.ts +96 -72
- package/features/thursday/thursday.query.ts +49 -30
- package/features/thursday/thursday.schema.ts +37 -35
- package/features/thursday/thursday.store.ts +14 -7
- package/features/thursday/tool-call.ts +3 -3
- package/features/thursday/tool-line.ts +5 -3
- package/features/thursday/use-thursday.ts +801 -457
- package/features/workspace/file-kind.ts +9 -0
- package/features/workspace/workspace.query.ts +17 -0
- package/features/workspace/workspace.ts +82 -36
- package/hooks/use-hotkey.ts +3 -2
- package/lib/live/live.schema.ts +26 -0
- package/lib/live/live.server.ts +153 -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 +38 -0
- package/scripts/bot-context.test.mts +1408 -0
- package/scripts/live-history.test.mts +115 -0
- package/scripts/live-session.test.mts +938 -0
- package/server.js +1 -1
- package/skills/browser/SKILL.md +11 -1
- 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]__026u77e._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__050zri4._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0bg9710._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0in-d5s._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0pa9k-f._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0qi_m0e._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0tq0m_k._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0xep6j_._.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]__144l7qt._.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]__1fizn31._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1jg8t86._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__1lldzy9._.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]__1peqvsi._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1w8gm5h._.js +0 -10
- package/.next/server/chunks/[root-of-the-server]__1xt39nn._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__1zb8mfo._.js +0 -8
- package/.next/server/chunks/_0-73of8._.js +0 -55
- package/.next/server/chunks/_0-fjql4._.js +0 -31
- package/.next/server/chunks/_00xh_q0._.js +0 -25
- package/.next/server/chunks/_051qh8u._.js +0 -3
- package/.next/server/chunks/_05sovvj._.js +0 -3
- package/.next/server/chunks/_091bi8d._.js +0 -3
- package/.next/server/chunks/_0fzqt2y._.js +0 -142
- package/.next/server/chunks/_0lr92vd._.js +0 -3
- package/.next/server/chunks/_0mecv0f._.js +0 -31
- package/.next/server/chunks/_0mh8j4m._.js +0 -3
- package/.next/server/chunks/_0sb7tlz._.js +0 -3
- package/.next/server/chunks/_0si7xzn._.js +0 -3
- package/.next/server/chunks/_0u10wmw._.js +0 -55
- 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/_18d7-5p._.js +0 -3
- package/.next/server/chunks/_1c78vw5._.js +0 -237
- 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/_1zkfbaa._.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 -8
- package/.next/server/chunks/features_bot_0zt92oh._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1jidylq._.js +0 -3
- package/.next/server/chunks/ssr/[externals]__0dizgek._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0-nob52._.js +0 -4
- 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]__0s4wb56._.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]__0sd3izg._.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]__1-13tcn._.js +0 -43
- package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +0 -61
- package/.next/server/chunks/ssr/[root-of-the-server]__1zidpfl._.js +0 -3
- package/.next/server/chunks/ssr/_001_ms1._.js +0 -33
- package/.next/server/chunks/ssr/_01n3o0m._.js +0 -3
- package/.next/server/chunks/ssr/_04z2c7b._.js +0 -3
- package/.next/server/chunks/ssr/_06tssji._.js +0 -3
- package/.next/server/chunks/ssr/_0fk4c7d._.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/_0mggveb._.js +0 -3
- package/.next/server/chunks/ssr/_0nbpc_8._.js +0 -3
- 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/_11j92tu._.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/_1ebxla1._.js +0 -3
- package/.next/server/chunks/ssr/_1nj4niv._.js +0 -42
- package/.next/server/chunks/ssr/_1ov37if._.js +0 -3
- package/.next/server/chunks/ssr/_1ovmc9s._.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/0n3jle9kbqfr2.js +0 -40
- package/.next/static/chunks/0r5qcctujhxli.js +0 -1
- package/.next/static/chunks/10teww7wt-f6h.js +0 -1
- package/.next/static/chunks/126fj4pga_72k.js +0 -1
- package/.next/static/chunks/159udiexf6dom.js +0 -2
- package/.next/static/chunks/18a96rkhi4_yd.js +0 -1
- package/.next/static/chunks/18gi7o2ibrgh8.js +0 -3
- package/.next/static/chunks/1dkjg87pxk0n9.js +0 -28
- package/.next/static/chunks/1q9z1tohil7xn.js +0 -1
- package/.next/static/chunks/1sjgfets224re.js +0 -1
- package/.next/static/chunks/1wszsr83t01gh.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/2szintyibu0s5.js +0 -1
- package/.next/static/chunks/2t4vhi3m8ahya.js +0 -1
- package/.next/static/chunks/2tigdtz3dpcy8.js +0 -1
- package/.next/static/chunks/3-b6b7entqazs.js +0 -1
- package/.next/static/chunks/3786h5vayt80-.js +0 -28
- package/.next/static/chunks/3cq5g494yuke8.css +0 -1
- package/.next/static/chunks/3dmbhsv2u_8kj.js +0 -1
- package/.next/static/chunks/3hibbjnt85-k6.js +0 -1
- package/.next/static/chunks/3i0a5px-oufgc.js +0 -1
- package/.next/static/chunks/3wexk9qo8zuj3.js +0 -18
- package/.next/static/chunks/3xk7yqgomx7yq.js +0 -1
- package/.next/static/chunks/3xre8bu_pk1p_.js +0 -1
- package/.next/static/chunks/3zv6t3i77xhr_.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 -1079
- package/features/bot/task.store.ts +0 -487
- 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/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_buildManifest.js +0 -0
- /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_ssgManifest.js +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
MicOff,
|
|
10
10
|
Settings2,
|
|
11
11
|
} from "lucide-react";
|
|
12
|
-
import { type ReactNode, useEffect, useRef, useState } from "react";
|
|
12
|
+
import { type ReactNode, useEffect, useMemo, useRef, useState } from "react";
|
|
13
13
|
import { queryKey } from "@/app/api/query-key";
|
|
14
14
|
import { Button } from "@/components/ui/button";
|
|
15
15
|
import { ButtonGroup } from "@/components/ui/button-group";
|
|
@@ -21,7 +21,8 @@ import {
|
|
|
21
21
|
TooltipProvider,
|
|
22
22
|
TooltipTrigger,
|
|
23
23
|
} from "@/components/ui/tooltip";
|
|
24
|
-
import {
|
|
24
|
+
import { CALL_IDLE } from "@/config";
|
|
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";
|
|
@@ -42,15 +43,22 @@ import {
|
|
|
42
43
|
type CallStatus,
|
|
43
44
|
type CaptionView,
|
|
44
45
|
FACE_DEFAULT,
|
|
46
|
+
type FaceWord,
|
|
45
47
|
type ThursdayFace,
|
|
46
48
|
} from "@/features/thursday/thursday.schema";
|
|
47
49
|
import { useThursdayStore } from "@/features/thursday/thursday.store";
|
|
48
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
type ActivityLine,
|
|
52
|
+
type CallEnd,
|
|
53
|
+
type Ringing,
|
|
54
|
+
useThursday,
|
|
55
|
+
} from "@/features/thursday/use-thursday";
|
|
49
56
|
import { ArtifactView } from "@/features/workspace/components/artifact-view";
|
|
50
57
|
import { useHotkeyLabel } from "@/hooks/use-hotkey";
|
|
51
58
|
import { useServerRoute } from "@/lib/protocol/use-server-route";
|
|
52
59
|
import { cn } from "@/lib/utils";
|
|
53
60
|
import { Face } from "./face";
|
|
61
|
+
import { SideCaptions, turnsOf, useTurnFocus } from "./side-captions";
|
|
54
62
|
import { TabState } from "./tab-state";
|
|
55
63
|
|
|
56
64
|
/**
|
|
@@ -63,10 +71,24 @@ export type { CaptionView };
|
|
|
63
71
|
|
|
64
72
|
export type CallScreenProps = {
|
|
65
73
|
status: CallStatus;
|
|
74
|
+
/** A call just failed to open or dropped; the face says so for a few seconds. */
|
|
75
|
+
failed?: boolean;
|
|
66
76
|
/** Oldest first; the last one is the turn being spoken. */
|
|
67
77
|
messages: CallMessage[];
|
|
68
|
-
tool:
|
|
78
|
+
tool: ActivityLine | null;
|
|
79
|
+
/** When the backend picked the turn up (ms); null when it is not working. */
|
|
80
|
+
thinkingSince?: number | null;
|
|
81
|
+
/** What the backend's latest reasoning summary says it is doing. */
|
|
82
|
+
thinkingTitle?: string | null;
|
|
83
|
+
/** Why the last call ended, when the user did not end it. */
|
|
84
|
+
ended?: CallEnd | null;
|
|
85
|
+
/** The word `emote` last put on the face. */
|
|
86
|
+
faceWord?: FaceWord | null;
|
|
69
87
|
onTap: () => void;
|
|
88
|
+
/** A call-back ringing; the tap answers it. */
|
|
89
|
+
ringing?: Ringing | null;
|
|
90
|
+
/** Stops the ringing without answering. */
|
|
91
|
+
onDecline?: () => void;
|
|
70
92
|
/** Wake phrase; null when the tap is the only entry point. */
|
|
71
93
|
wakePhrase?: string | null;
|
|
72
94
|
/** Hotkey in readable form (use-hotkey); null if none. */
|
|
@@ -75,8 +97,6 @@ export type CallScreenProps = {
|
|
|
75
97
|
idleLeft?: number | null;
|
|
76
98
|
/** When the line opened (ms). */
|
|
77
99
|
since?: number | null;
|
|
78
|
-
/** Mic muted (use-thursday micOff): a tool is running or a relay is being read. */
|
|
79
|
-
micOff?: boolean;
|
|
80
100
|
getSpectrum?: () => ArrayLike<number>;
|
|
81
101
|
/** The user's own mic bands, for the listening meter. */
|
|
82
102
|
getMicSpectrum?: () => ArrayLike<number>;
|
|
@@ -89,14 +109,20 @@ export type CallScreenProps = {
|
|
|
89
109
|
|
|
90
110
|
export function CallScreen({
|
|
91
111
|
status,
|
|
112
|
+
failed = false,
|
|
92
113
|
messages,
|
|
93
114
|
tool,
|
|
115
|
+
thinkingSince = null,
|
|
116
|
+
thinkingTitle = null,
|
|
117
|
+
ended = null,
|
|
118
|
+
faceWord = null,
|
|
94
119
|
onTap,
|
|
120
|
+
ringing = null,
|
|
121
|
+
onDecline,
|
|
95
122
|
wakePhrase = null,
|
|
96
123
|
hotkeyLabel = null,
|
|
97
124
|
idleLeft = null,
|
|
98
125
|
since = null,
|
|
99
|
-
micOff = false,
|
|
100
126
|
getSpectrum,
|
|
101
127
|
getMicSpectrum,
|
|
102
128
|
captionView = "center",
|
|
@@ -106,14 +132,20 @@ export function CallScreen({
|
|
|
106
132
|
// without a key the face opens the key prompt instead of a call
|
|
107
133
|
const [asking, setAsking] = useState(false);
|
|
108
134
|
const asleep = !callable && status === "idle";
|
|
109
|
-
const busy = status === "connecting";
|
|
110
|
-
const live = status !== "idle" &&
|
|
135
|
+
const busy = status === "connecting" || status === "ending";
|
|
136
|
+
const live = status !== "idle" && !busy;
|
|
111
137
|
// The caption box holds her words and nothing else, so the line she just
|
|
112
138
|
// said stays put while she listens or works.
|
|
113
139
|
const hers =
|
|
114
140
|
messages.findLast((turn) => turn.role === "assistant")?.text ?? "";
|
|
115
141
|
const sided = captionView === "sides" && status !== "idle";
|
|
116
|
-
const
|
|
142
|
+
const talk = useMemo(() => turnsOf(messages), [messages]);
|
|
143
|
+
const turns = useTurnFocus(talk, sided);
|
|
144
|
+
const lastRole = talk.at(-1)?.role;
|
|
145
|
+
// the last turn is still being said: her voice is on, or yours came after hers and she has not answered
|
|
146
|
+
const saying =
|
|
147
|
+
(lastRole === "assistant" && status === "speaking") ||
|
|
148
|
+
(lastRole === "user" && status === "listening");
|
|
117
149
|
return (
|
|
118
150
|
<div className="relative flex h-full flex-col">
|
|
119
151
|
<div className="absolute top-5 right-5 z-10">
|
|
@@ -140,7 +172,9 @@ export function CallScreen({
|
|
|
140
172
|
? "Add a speech key"
|
|
141
173
|
: live
|
|
142
174
|
? "End the call"
|
|
143
|
-
:
|
|
175
|
+
: ringing
|
|
176
|
+
? "Answer Thursday"
|
|
177
|
+
: "Call Thursday"
|
|
144
178
|
}
|
|
145
179
|
// the face never moves under the cursor; only press gives a little
|
|
146
180
|
className={cn(
|
|
@@ -149,15 +183,25 @@ export function CallScreen({
|
|
|
149
183
|
asleep && "opacity-35",
|
|
150
184
|
)}
|
|
151
185
|
>
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
186
|
+
{/* Ringing, the face swells twice and rests, like a phone's ring */}
|
|
187
|
+
<span
|
|
188
|
+
className={cn("block", ringing && "motion-safe:animate-ringing")}
|
|
189
|
+
>
|
|
190
|
+
<Face
|
|
191
|
+
look={face}
|
|
192
|
+
status={status}
|
|
193
|
+
failed={failed}
|
|
194
|
+
word={faceWord}
|
|
195
|
+
getSpectrum={getSpectrum}
|
|
196
|
+
getMicSpectrum={getMicSpectrum}
|
|
197
|
+
className="w-full"
|
|
198
|
+
/>
|
|
199
|
+
</span>
|
|
158
200
|
</button>
|
|
159
201
|
|
|
160
|
-
{sided &&
|
|
202
|
+
{sided && (
|
|
203
|
+
<SideCaptions turns={talk} focus={turns.focus} live={saying} />
|
|
204
|
+
)}
|
|
161
205
|
</div>
|
|
162
206
|
|
|
163
207
|
{/* The column is wider than the text (40rem); the side margins hold the caption chevrons (Flow) */}
|
|
@@ -169,8 +213,10 @@ export function CallScreen({
|
|
|
169
213
|
(use-thursday). */}
|
|
170
214
|
<ActivityRow
|
|
171
215
|
tool={tool}
|
|
172
|
-
|
|
173
|
-
|
|
216
|
+
thinkingSince={thinkingSince}
|
|
217
|
+
thinkingTitle={thinkingTitle}
|
|
218
|
+
listening={status === "listening" && thinkingSince === null}
|
|
219
|
+
ringing={ringing}
|
|
174
220
|
getMicSpectrum={getMicSpectrum}
|
|
175
221
|
/>
|
|
176
222
|
|
|
@@ -178,8 +224,7 @@ export function CallScreen({
|
|
|
178
224
|
`text-balance`: rebalancing changes the line count under the pager. */}
|
|
179
225
|
<Flow
|
|
180
226
|
text={sided || status === "idle" ? "" : hers}
|
|
181
|
-
|
|
182
|
-
paged
|
|
227
|
+
fadeIn
|
|
183
228
|
className="w-full max-w-160 text-center text-base"
|
|
184
229
|
/>
|
|
185
230
|
|
|
@@ -205,6 +250,10 @@ export function CallScreen({
|
|
|
205
250
|
status={status}
|
|
206
251
|
idleLeft={idleLeft}
|
|
207
252
|
since={since}
|
|
253
|
+
ended={ended}
|
|
254
|
+
behind={sided && turns.back > 0}
|
|
255
|
+
ringing={ringing !== null}
|
|
256
|
+
onDecline={onDecline}
|
|
208
257
|
wakePhrase={wakePhrase}
|
|
209
258
|
hotkeyLabel={hotkeyLabel}
|
|
210
259
|
/>
|
|
@@ -213,7 +262,7 @@ export function CallScreen({
|
|
|
213
262
|
</div>
|
|
214
263
|
</div>
|
|
215
264
|
|
|
216
|
-
{/* Documents a finished
|
|
265
|
+
{/* Documents a finished thread produced; opens itself on the artifact event */}
|
|
217
266
|
<ArtifactView />
|
|
218
267
|
|
|
219
268
|
<BotRoom />
|
|
@@ -223,7 +272,7 @@ export function CallScreen({
|
|
|
223
272
|
|
|
224
273
|
/**
|
|
225
274
|
* The corner is one group: three rooms as single buttons, everything else
|
|
226
|
-
* behind the gear.
|
|
275
|
+
* behind the gear. Threads is left out because the other corner is that room.
|
|
227
276
|
*/
|
|
228
277
|
const CORNER = ["thursday", "memory", "bot"] as const;
|
|
229
278
|
|
|
@@ -312,46 +361,6 @@ function SettingsCorner() {
|
|
|
312
361
|
/** Lines the caption box holds. */
|
|
313
362
|
const CAPTION_LINES = 3;
|
|
314
363
|
|
|
315
|
-
/**
|
|
316
|
-
* Lines a side caption keeps, by age. The newest turn is the one being said, so
|
|
317
|
-
* it gets room for a whole spoken sentence; what came before is context and
|
|
318
|
-
* decays with the type size beside it.
|
|
319
|
-
*/
|
|
320
|
-
const CAPTION_TURN_LINES = [5, 3, 2];
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Type size by age. The step is a real one — 18 / 15 / 13 — because it is what
|
|
324
|
-
* tells two turns apart once neither carries an edge.
|
|
325
|
-
*/
|
|
326
|
-
const CAPTION_SIZES = ["text-lg", "text-[15px]", "text-[13px]"];
|
|
327
|
-
|
|
328
|
-
/** Inner padding by age: a smaller turn sits on a smaller plate. */
|
|
329
|
-
const CAPTION_PADS = ["px-4 py-3", "px-3.5 py-2.5", "px-3 py-2"];
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* The plate a turn sits on: fill, no edge. The call screen's ground is the
|
|
333
|
-
* page's own — the ascii field is boot and intro only — so an outline covers
|
|
334
|
-
* nothing and ends up being the whole design.
|
|
335
|
-
*
|
|
336
|
-
* Yours is the surface `Bubble` already gives your words in the task thread
|
|
337
|
-
* (primary, light ink); hers is the page's grey. Age recedes in the fill, not
|
|
338
|
-
* in the block's opacity, which would take the ink down with it.
|
|
339
|
-
*/
|
|
340
|
-
const CAPTION_HERS = ["bg-muted", "bg-muted/70", "bg-muted/45"];
|
|
341
|
-
const CAPTION_YOURS = ["bg-primary", "bg-primary/75", "bg-primary/60"];
|
|
342
|
-
|
|
343
|
-
/** A step off a ramp above. The ramps run out at VISIBLE; the last step is the floor. */
|
|
344
|
-
function atAge(ramp: readonly string[], age: number) {
|
|
345
|
-
return ramp[age] ?? ramp[ramp.length - 1];
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/** Ink by age. Hers recedes with her plate; yours stays legible on every step of its own. */
|
|
349
|
-
const CAPTION_HERS_INK = [
|
|
350
|
-
"text-foreground",
|
|
351
|
-
"text-muted-foreground",
|
|
352
|
-
"text-muted-foreground/60",
|
|
353
|
-
];
|
|
354
|
-
|
|
355
364
|
/**
|
|
356
365
|
* Line height as a number, not a class: box height and page offset divide by
|
|
357
366
|
* it, and a class could be overridden by a later `text-*` utility.
|
|
@@ -364,20 +373,14 @@ const CAPTION_LEADING = 1.625;
|
|
|
364
373
|
*/
|
|
365
374
|
function Flow({
|
|
366
375
|
text,
|
|
367
|
-
lead,
|
|
368
376
|
lines = CAPTION_LINES,
|
|
369
|
-
|
|
370
|
-
paged = false,
|
|
377
|
+
fadeIn = false,
|
|
371
378
|
className,
|
|
372
379
|
}: {
|
|
373
380
|
text: string;
|
|
374
|
-
/** Sits inline before the text. */
|
|
375
|
-
lead?: ReactNode;
|
|
376
381
|
lines?: number;
|
|
377
|
-
/**
|
|
378
|
-
|
|
379
|
-
/** Page overflow with chevrons; needs side margin. */
|
|
380
|
-
paged?: boolean;
|
|
382
|
+
/** Each new character fades in as it arrives; what is already drawn stays put. */
|
|
383
|
+
fadeIn?: boolean;
|
|
381
384
|
className?: string;
|
|
382
385
|
}) {
|
|
383
386
|
const box = useRef<HTMLParagraphElement>(null);
|
|
@@ -392,7 +395,7 @@ function Flow({
|
|
|
392
395
|
// re-measure on width change and on every text change (streaming moves the last line)
|
|
393
396
|
useEffect(() => {
|
|
394
397
|
const node = box.current;
|
|
395
|
-
if (!node
|
|
398
|
+
if (!node) return;
|
|
396
399
|
const measure = () => {
|
|
397
400
|
const line = Number.parseFloat(getComputedStyle(node).lineHeight);
|
|
398
401
|
if (!line) return;
|
|
@@ -402,7 +405,7 @@ function Flow({
|
|
|
402
405
|
const watch = new ResizeObserver(measure);
|
|
403
406
|
watch.observe(node);
|
|
404
407
|
return () => watch.disconnect();
|
|
405
|
-
}, [text
|
|
408
|
+
}, [text]);
|
|
406
409
|
|
|
407
410
|
const steps = Math.ceil(Math.max(0, rows - lines) / lines);
|
|
408
411
|
const at = Math.max(0, rows - lines - Math.min(back, steps) * lines);
|
|
@@ -413,32 +416,24 @@ function Flow({
|
|
|
413
416
|
ref={box}
|
|
414
417
|
style={{
|
|
415
418
|
lineHeight: CAPTION_LEADING,
|
|
416
|
-
|
|
417
|
-
? { transform: `translateY(-${at * CAPTION_LEADING}em)` }
|
|
418
|
-
: {}),
|
|
419
|
+
transform: `translateY(-${at * CAPTION_LEADING}em)`,
|
|
419
420
|
}}
|
|
420
|
-
className=
|
|
421
|
+
className="break-keep transition-transform duration-200"
|
|
421
422
|
>
|
|
422
|
-
{
|
|
423
|
-
|
|
423
|
+
{fadeIn
|
|
424
|
+
? // char + index: a character already drawn keeps its key and never fades twice
|
|
425
|
+
Array.from(text).map((char, index) => (
|
|
426
|
+
<span
|
|
427
|
+
key={`${char}${index}`}
|
|
428
|
+
className="animate-in fade-in duration-300 motion-reduce:animate-none"
|
|
429
|
+
>
|
|
430
|
+
{char}
|
|
431
|
+
</span>
|
|
432
|
+
))
|
|
433
|
+
: text}
|
|
424
434
|
</p>
|
|
425
435
|
);
|
|
426
436
|
|
|
427
|
-
// No room for chevrons here (side captions): overflow is clipped and the fading last line is the only cue
|
|
428
|
-
if (!paged) {
|
|
429
|
-
return (
|
|
430
|
-
<div
|
|
431
|
-
style={fixed ? { height } : { maxHeight: height }}
|
|
432
|
-
className={cn(
|
|
433
|
-
"overflow-hidden mask-[linear-gradient(to_bottom,black_calc(100%-0.7rem),transparent_100%)]",
|
|
434
|
-
className,
|
|
435
|
-
)}
|
|
436
|
-
>
|
|
437
|
-
{body}
|
|
438
|
-
</div>
|
|
439
|
-
);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
437
|
return (
|
|
443
438
|
<div className="relative flex w-full justify-center">
|
|
444
439
|
<div
|
|
@@ -626,7 +621,7 @@ function Ear({
|
|
|
626
621
|
* which has no container either, so an outline under one of the two read as the
|
|
627
622
|
* line changing shape rather than changing state.
|
|
628
623
|
*/
|
|
629
|
-
function Activity({ tool
|
|
624
|
+
function Activity({ tool }: { tool: ActivityLine }) {
|
|
630
625
|
// a relay from a bot is a flag, like the answer tool — unless it names the bot
|
|
631
626
|
const relay = tool.kind === "relay";
|
|
632
627
|
const Icon = relay ? Flag : toolIcon(tool.name);
|
|
@@ -662,17 +657,7 @@ function Activity({ tool, micOff }: { tool: ToolRun; micOff: boolean }) {
|
|
|
662
657
|
{tool.done ? (
|
|
663
658
|
<span className={cn(look, "text-muted-foreground")}>{text}</span>
|
|
664
659
|
) : (
|
|
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>
|
|
660
|
+
<ShinyText text={text} motion="pulse" className={look} />
|
|
676
661
|
)}
|
|
677
662
|
</span>
|
|
678
663
|
);
|
|
@@ -691,7 +676,7 @@ function Mark({
|
|
|
691
676
|
icon: Icon,
|
|
692
677
|
running,
|
|
693
678
|
}: {
|
|
694
|
-
tool:
|
|
679
|
+
tool: ActivityLine;
|
|
695
680
|
/** The row the name resolved to, when the roster has one; its look, not its identity. */
|
|
696
681
|
bot: Bot | null;
|
|
697
682
|
icon: LucideIcon;
|
|
@@ -703,10 +688,10 @@ function Mark({
|
|
|
703
688
|
<BotMark
|
|
704
689
|
size={16}
|
|
705
690
|
seed={tool.bot}
|
|
706
|
-
vary={tool.bot}
|
|
707
691
|
color={bot?.icon?.color}
|
|
708
692
|
shape={bot?.icon?.shape}
|
|
709
693
|
outline={bot?.icon?.outline}
|
|
694
|
+
paint={bot?.icon?.paint}
|
|
710
695
|
notify={false}
|
|
711
696
|
/>
|
|
712
697
|
</span>
|
|
@@ -724,19 +709,25 @@ function Mark({
|
|
|
724
709
|
}
|
|
725
710
|
|
|
726
711
|
/**
|
|
727
|
-
* The activity slot: 28px, one fact at a time,
|
|
712
|
+
* The activity slot: 28px, one fact at a time, three faces. All stay mounted and
|
|
728
713
|
* 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.
|
|
714
|
+
* out, and the caption below never moves while they trade places. A tool wins
|
|
715
|
+
* over thinking: it is the same stretch of work, said more exactly.
|
|
730
716
|
*/
|
|
731
717
|
function ActivityRow({
|
|
732
718
|
tool,
|
|
733
|
-
|
|
719
|
+
thinkingSince,
|
|
720
|
+
thinkingTitle,
|
|
734
721
|
listening,
|
|
722
|
+
ringing,
|
|
735
723
|
getMicSpectrum,
|
|
736
724
|
}: {
|
|
737
|
-
tool:
|
|
738
|
-
|
|
725
|
+
tool: ActivityLine | null;
|
|
726
|
+
thinkingSince: number | null;
|
|
727
|
+
thinkingTitle: string | null;
|
|
739
728
|
listening: boolean;
|
|
729
|
+
/** Only while idle, when nothing else takes the slot. */
|
|
730
|
+
ringing: Ringing | null;
|
|
740
731
|
getMicSpectrum?: () => ArrayLike<number>;
|
|
741
732
|
}) {
|
|
742
733
|
// held past the tool so the pill has something to fade out with
|
|
@@ -744,13 +735,45 @@ function ActivityRow({
|
|
|
744
735
|
useEffect(() => {
|
|
745
736
|
if (tool) setShown(tool);
|
|
746
737
|
}, [tool]);
|
|
738
|
+
// and past the thinking, for the same reason
|
|
739
|
+
const [since, setSince] = useState(thinkingSince);
|
|
740
|
+
const [title, setTitle] = useState(thinkingTitle);
|
|
741
|
+
useEffect(() => {
|
|
742
|
+
if (thinkingSince === null) return;
|
|
743
|
+
setSince(thinkingSince);
|
|
744
|
+
setTitle(thinkingTitle);
|
|
745
|
+
}, [thinkingSince, thinkingTitle]);
|
|
747
746
|
|
|
748
747
|
const hearing = listening && !tool;
|
|
749
748
|
return (
|
|
750
|
-
|
|
749
|
+
// Ringing, who calls sits right under the face, over the hint. It leaves at
|
|
750
|
+
// once rather than fading, so the hint does not slide under a fading line
|
|
751
|
+
<div
|
|
752
|
+
className={cn(
|
|
753
|
+
"grid h-7 max-w-full items-center justify-items-center",
|
|
754
|
+
ringing && "order-first",
|
|
755
|
+
)}
|
|
756
|
+
>
|
|
757
|
+
{ringing && (
|
|
758
|
+
<span className="col-start-1 row-start-1 flex max-w-full animate-in fade-in duration-500">
|
|
759
|
+
<Ringer ringing={ringing} />
|
|
760
|
+
</span>
|
|
761
|
+
)}
|
|
751
762
|
{shown && (
|
|
752
763
|
<Fade at="col-start-1 row-start-1 max-w-full" shown={tool !== null}>
|
|
753
|
-
<Activity tool={shown}
|
|
764
|
+
<Activity tool={shown} />
|
|
765
|
+
</Fade>
|
|
766
|
+
)}
|
|
767
|
+
{since !== null && (
|
|
768
|
+
<Fade
|
|
769
|
+
at="col-start-1 row-start-1"
|
|
770
|
+
shown={thinkingSince !== null && !tool}
|
|
771
|
+
>
|
|
772
|
+
<Thinking
|
|
773
|
+
since={since}
|
|
774
|
+
title={title}
|
|
775
|
+
running={thinkingSince !== null && !tool}
|
|
776
|
+
/>
|
|
754
777
|
</Fade>
|
|
755
778
|
)}
|
|
756
779
|
<Fade at="col-start-1 row-start-1" shown={hearing}>
|
|
@@ -760,6 +783,45 @@ function ActivityRow({
|
|
|
760
783
|
);
|
|
761
784
|
}
|
|
762
785
|
|
|
786
|
+
/**
|
|
787
|
+
* Who a ringing call-back is for: the bot's face and what it has, then the job,
|
|
788
|
+
* and how many more rang with it. The words pulse while it rings.
|
|
789
|
+
*/
|
|
790
|
+
function Ringer({ ringing }: { ringing: Ringing }) {
|
|
791
|
+
const bots = useServerRoute<Bot[]>(queryKey.bot).data;
|
|
792
|
+
const bot = bots?.find((one) => one.name === ringing.bot) ?? null;
|
|
793
|
+
const says =
|
|
794
|
+
ringing.kind === "question"
|
|
795
|
+
? `${ringing.bot} has a question`
|
|
796
|
+
: ringing.kind === "done"
|
|
797
|
+
? `Answer from ${ringing.bot}`
|
|
798
|
+
: `${ringing.bot} stopped`;
|
|
799
|
+
return (
|
|
800
|
+
<span className="flex max-w-full items-center gap-1.5 text-[13px] leading-5 text-muted-foreground">
|
|
801
|
+
<span className="grid size-4.5 shrink-0 place-items-center">
|
|
802
|
+
<BotMark
|
|
803
|
+
size={16}
|
|
804
|
+
seed={ringing.bot}
|
|
805
|
+
color={bot?.icon?.color}
|
|
806
|
+
shape={bot?.icon?.shape}
|
|
807
|
+
outline={bot?.icon?.outline}
|
|
808
|
+
paint={bot?.icon?.paint}
|
|
809
|
+
// a question or a stop waits on the user; an answer only waits to be read
|
|
810
|
+
notify={ringing.kind !== "done"}
|
|
811
|
+
/>
|
|
812
|
+
</span>
|
|
813
|
+
<ShinyText text={says} motion="pulse" className="shrink-0" />
|
|
814
|
+
<span className="text-muted-foreground/40">·</span>
|
|
815
|
+
<span className="min-w-0 truncate break-keep">{ringing.label}</span>
|
|
816
|
+
{ringing.more > 0 && (
|
|
817
|
+
<span className="shrink-0 rounded-full bg-muted px-1.5 font-mono text-[10px] leading-4.5 text-foreground/70">
|
|
818
|
+
+{ringing.more}
|
|
819
|
+
</span>
|
|
820
|
+
)}
|
|
821
|
+
</span>
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
|
|
763
825
|
/** One face of a stacked slot. Hidden means invisible, untouchable and unread. */
|
|
764
826
|
function Fade({
|
|
765
827
|
at,
|
|
@@ -784,25 +846,43 @@ function Fade({
|
|
|
784
846
|
);
|
|
785
847
|
}
|
|
786
848
|
|
|
849
|
+
/** Why a call ended, as the hint says it. */
|
|
850
|
+
const ENDED: Record<CallEnd, string> = {
|
|
851
|
+
quiet: `${CALL_IDLE.hangUpMs / 1000}s of quiet`,
|
|
852
|
+
hungUp: "Thursday hung up",
|
|
853
|
+
closed: "Live closed the call",
|
|
854
|
+
dropped: "the connection dropped",
|
|
855
|
+
};
|
|
856
|
+
|
|
787
857
|
/**
|
|
788
858
|
* The only hint line on screen. Says one thing at a time; outside a call it
|
|
789
|
-
* shows
|
|
790
|
-
* elapsed time. Keyed
|
|
859
|
+
* shows why the last one ended when the user did not end it, else one way in
|
|
860
|
+
* (wake phrase or hotkey); inside a call how to end and the elapsed time. Keyed
|
|
861
|
+
* so changes fade.
|
|
791
862
|
*/
|
|
792
863
|
function Hint({
|
|
793
864
|
status,
|
|
794
865
|
idleLeft,
|
|
795
866
|
since,
|
|
867
|
+
ended,
|
|
868
|
+
behind,
|
|
869
|
+
ringing,
|
|
870
|
+
onDecline,
|
|
796
871
|
wakePhrase,
|
|
797
872
|
hotkeyLabel,
|
|
798
873
|
}: {
|
|
799
874
|
status: CallStatus;
|
|
800
875
|
idleLeft: number | null;
|
|
801
876
|
since: number | null;
|
|
877
|
+
ended: CallEnd | null;
|
|
878
|
+
/** The side captions are on an earlier turn. */
|
|
879
|
+
behind: boolean;
|
|
880
|
+
ringing: boolean;
|
|
881
|
+
onDecline?: () => void;
|
|
802
882
|
wakePhrase: string | null;
|
|
803
883
|
hotkeyLabel: string | null;
|
|
804
884
|
}) {
|
|
805
|
-
const busy = status === "connecting";
|
|
885
|
+
const busy = status === "connecting" || status === "ending";
|
|
806
886
|
const live = status !== "idle" && !busy;
|
|
807
887
|
|
|
808
888
|
let body: React.ReactNode;
|
|
@@ -813,6 +893,7 @@ function Hint({
|
|
|
813
893
|
body = (
|
|
814
894
|
<ShinyText
|
|
815
895
|
text={status === "connecting" ? "Connecting…" : "Ending…"}
|
|
896
|
+
motion="pulse"
|
|
816
897
|
className="text-muted-foreground/70"
|
|
817
898
|
/>
|
|
818
899
|
);
|
|
@@ -820,12 +901,50 @@ function Hint({
|
|
|
820
901
|
key = "quiet";
|
|
821
902
|
body = `Quiet — ending in ${idleLeft}s. Say anything to stay.`;
|
|
822
903
|
} else if (live) {
|
|
823
|
-
key = "live";
|
|
904
|
+
key = behind ? "behind" : "live";
|
|
824
905
|
body = (
|
|
825
906
|
<>
|
|
826
907
|
<span>Tap Thursday to end</span>
|
|
827
908
|
<span className="text-muted-foreground/40">·</span>
|
|
828
|
-
|
|
909
|
+
{behind ? (
|
|
910
|
+
<>
|
|
911
|
+
<kbd className="rounded-md border border-border bg-background px-1.5 py-0.5 font-mono text-[10px] text-foreground/80 shadow-[0_1px_0_var(--border)]">
|
|
912
|
+
↓
|
|
913
|
+
</kbd>
|
|
914
|
+
<span>back to now</span>
|
|
915
|
+
</>
|
|
916
|
+
) : (
|
|
917
|
+
<Elapsed since={since} />
|
|
918
|
+
)}
|
|
919
|
+
</>
|
|
920
|
+
);
|
|
921
|
+
} else if (ringing) {
|
|
922
|
+
key = "ringing";
|
|
923
|
+
// Every way in answers, so the tap stands for them all; declining is the one other act
|
|
924
|
+
body = (
|
|
925
|
+
<>
|
|
926
|
+
<span>Tap Thursday to answer</span>
|
|
927
|
+
<span className="text-muted-foreground/40">·</span>
|
|
928
|
+
<button
|
|
929
|
+
type="button"
|
|
930
|
+
onClick={onDecline}
|
|
931
|
+
className="flex items-center gap-1.5 rounded-full bg-muted py-0.5 pr-0.5 pl-2 text-foreground/80 transition-colors hover:bg-accent"
|
|
932
|
+
>
|
|
933
|
+
Not now
|
|
934
|
+
<kbd className="rounded-md border border-border bg-background px-1.5 font-mono text-[10px] text-foreground/70 shadow-[0_1px_0_var(--border)]">
|
|
935
|
+
Esc
|
|
936
|
+
</kbd>
|
|
937
|
+
</button>
|
|
938
|
+
</>
|
|
939
|
+
);
|
|
940
|
+
} else if (ended) {
|
|
941
|
+
key = `ended:${ended}`;
|
|
942
|
+
// Where the quiet warning stood, until the next call
|
|
943
|
+
body = (
|
|
944
|
+
<>
|
|
945
|
+
<span>Ended — {ENDED[ended]}</span>
|
|
946
|
+
<span className="text-muted-foreground/40">·</span>
|
|
947
|
+
<span>Tap to call again</span>
|
|
829
948
|
</>
|
|
830
949
|
);
|
|
831
950
|
} else if (wakePhrase) {
|
|
@@ -910,7 +1029,6 @@ function NeedsKey({
|
|
|
910
1029
|
<BotMark
|
|
911
1030
|
size={24}
|
|
912
1031
|
seed={DEFAULT_BOT.name}
|
|
913
|
-
vary={DEFAULT_BOT.name}
|
|
914
1032
|
color={DEFAULT_BOT.icon?.color}
|
|
915
1033
|
shape={DEFAULT_BOT.icon?.shape}
|
|
916
1034
|
outline={DEFAULT_BOT.icon?.outline}
|
|
@@ -928,6 +1046,63 @@ function NeedsKey({
|
|
|
928
1046
|
);
|
|
929
1047
|
}
|
|
930
1048
|
|
|
1049
|
+
/**
|
|
1050
|
+
* The backend has the turn: the activity line says so and counts, so the
|
|
1051
|
+
* seconds before a tool and before her voice never read as a call that has
|
|
1052
|
+
* stopped. Once a reasoning summary names what the work is, the line says that
|
|
1053
|
+
* instead. It shines where the rest of this screen pulses (the user's pick). The
|
|
1054
|
+
* seconds arrive after the first one, which is most answers.
|
|
1055
|
+
*/
|
|
1056
|
+
function Thinking({
|
|
1057
|
+
since,
|
|
1058
|
+
title,
|
|
1059
|
+
running,
|
|
1060
|
+
}: {
|
|
1061
|
+
since: number;
|
|
1062
|
+
title: string | null;
|
|
1063
|
+
running: boolean;
|
|
1064
|
+
}) {
|
|
1065
|
+
const [now, setNow] = useState(() => Date.now());
|
|
1066
|
+
// Stays mounted to fade out; the count stops with it rather than ticking unseen
|
|
1067
|
+
useEffect(() => {
|
|
1068
|
+
if (!running) return;
|
|
1069
|
+
// back from a tool, the first reading is now rather than where it paused
|
|
1070
|
+
const first = setTimeout(() => setNow(Date.now()), 0);
|
|
1071
|
+
const tick = setInterval(() => setNow(Date.now()), 1000);
|
|
1072
|
+
return () => {
|
|
1073
|
+
clearTimeout(first);
|
|
1074
|
+
clearInterval(tick);
|
|
1075
|
+
};
|
|
1076
|
+
}, [running]);
|
|
1077
|
+
const seconds = Math.max(0, Math.floor((now - since) / 1000));
|
|
1078
|
+
const words = title ? `Thinking about ${midSentence(title)}` : "Thinking…";
|
|
1079
|
+
return (
|
|
1080
|
+
<span className="flex max-w-full items-center gap-1.5 text-[13px] leading-5">
|
|
1081
|
+
{/* keyed so a new title fades in rather than replacing the words mid-sweep */}
|
|
1082
|
+
<ShinyText
|
|
1083
|
+
key={words}
|
|
1084
|
+
text={words}
|
|
1085
|
+
className="min-w-0 animate-in truncate fade-in duration-300"
|
|
1086
|
+
/>
|
|
1087
|
+
{seconds >= 1 && (
|
|
1088
|
+
<>
|
|
1089
|
+
<span className="shrink-0 text-muted-foreground/40">·</span>
|
|
1090
|
+
<span className="shrink-0 text-muted-foreground tabular-nums">
|
|
1091
|
+
{seconds}s
|
|
1092
|
+
</span>
|
|
1093
|
+
</>
|
|
1094
|
+
)}
|
|
1095
|
+
</span>
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/** A title read mid-sentence: "Checking thread status" becomes "checking thread status"; "API limits" stays. */
|
|
1100
|
+
function midSentence(title: string) {
|
|
1101
|
+
return /^\p{Lu}\p{Lu}/u.test(title)
|
|
1102
|
+
? title
|
|
1103
|
+
: title.charAt(0).toLowerCase() + title.slice(1);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
931
1106
|
/** Time since the line opened, mm:ss; only this span re-renders each second. */
|
|
932
1107
|
function Elapsed({ since }: { since: number | null }) {
|
|
933
1108
|
const [now, setNow] = useState(() => Date.now());
|
|
@@ -947,160 +1122,21 @@ function Elapsed({ since }: { since: number | null }) {
|
|
|
947
1122
|
);
|
|
948
1123
|
}
|
|
949
1124
|
|
|
950
|
-
/** Turns shown at once. */
|
|
951
|
-
const VISIBLE = 3;
|
|
952
|
-
|
|
953
|
-
/**
|
|
954
|
-
* Wheel delta per turn. Deliberately heavy — a turn is a paragraph, and a
|
|
955
|
-
* trackpad flick that pages three of them reads as losing the conversation
|
|
956
|
-
* rather than moving through it. The give is what says it is not stuck.
|
|
957
|
-
*/
|
|
958
|
-
const STEP = 360;
|
|
959
|
-
|
|
960
|
-
/** How far the plates lean while the wheel is short of a turn, px. */
|
|
961
|
-
const GIVE = 10;
|
|
962
|
-
|
|
963
|
-
/** How long the wheel keeps what it has gathered. Past this the lean springs back and the count starts over, so half a turn never waits around to be completed by the next flick. */
|
|
964
|
-
const SETTLE_MS = 220;
|
|
965
|
-
|
|
966
|
-
/**
|
|
967
|
-
* Where the wheel has wound the turns back to. Lives on the screen rather than
|
|
968
|
-
* in the plates: the three plates are small and sit off to the sides, so a
|
|
969
|
-
* wheel over the face — where the cursor is — used to reach nothing at all.
|
|
970
|
-
*/
|
|
971
|
-
function useTurnPager(messages: CallMessage[]) {
|
|
972
|
-
const [back, setBack] = useState(0);
|
|
973
|
-
const [give, setGive] = useState(0);
|
|
974
|
-
const drag = useRef(0);
|
|
975
|
-
const settle = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
976
|
-
const seen = useRef(messages.length);
|
|
977
|
-
|
|
978
|
-
const furthest = Math.max(0, messages.length - VISIBLE);
|
|
979
|
-
|
|
980
|
-
// stay on the turn being read when new turns arrive
|
|
981
|
-
useEffect(() => {
|
|
982
|
-
const grew = messages.length - seen.current;
|
|
983
|
-
seen.current = messages.length;
|
|
984
|
-
if (grew > 0) {
|
|
985
|
-
setBack((was) => (was > 0 ? Math.min(was + grew, furthest) : 0));
|
|
986
|
-
}
|
|
987
|
-
}, [messages.length, furthest]);
|
|
988
|
-
|
|
989
|
-
useEffect(
|
|
990
|
-
() => () => {
|
|
991
|
-
if (settle.current) clearTimeout(settle.current);
|
|
992
|
-
},
|
|
993
|
-
[],
|
|
994
|
-
);
|
|
995
|
-
|
|
996
|
-
const onWheel = (event: React.WheelEvent) => {
|
|
997
|
-
// nothing behind the three on screen: no travel, and no lean pretending there is
|
|
998
|
-
if (furthest === 0) return;
|
|
999
|
-
drag.current += event.deltaY;
|
|
1000
|
-
const steps = Math.trunc(drag.current / STEP);
|
|
1001
|
-
if (steps !== 0) {
|
|
1002
|
-
drag.current -= steps * STEP;
|
|
1003
|
-
setBack((was) => Math.min(furthest, Math.max(0, was - steps)));
|
|
1004
|
-
}
|
|
1005
|
-
setGive(drag.current / STEP);
|
|
1006
|
-
|
|
1007
|
-
// spring back so the give reads as resistance, not position
|
|
1008
|
-
if (settle.current) clearTimeout(settle.current);
|
|
1009
|
-
settle.current = setTimeout(() => {
|
|
1010
|
-
drag.current = 0;
|
|
1011
|
-
setGive(0);
|
|
1012
|
-
}, SETTLE_MS);
|
|
1013
|
-
};
|
|
1014
|
-
|
|
1015
|
-
const end = messages.length - back;
|
|
1016
|
-
return {
|
|
1017
|
-
shown: messages.slice(Math.max(0, end - VISIBLE), end),
|
|
1018
|
-
give,
|
|
1019
|
-
onWheel,
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
/**
|
|
1024
|
-
* Recent turns beside the face: yours on the right, hers on the left, each on
|
|
1025
|
-
* a fill with no edge. Anchored outside the face box (`right-full` /
|
|
1026
|
-
* `left-full`) so they never cover it. Older turns sit higher, smaller, and
|
|
1027
|
-
* their plate recedes.
|
|
1028
|
-
*/
|
|
1029
|
-
function SideCaptions({
|
|
1030
|
-
shown,
|
|
1031
|
-
give,
|
|
1032
|
-
}: {
|
|
1033
|
-
shown: CallMessage[];
|
|
1034
|
-
/** How far into the next turn the wheel is, -1..1; the plates lean by it. */
|
|
1035
|
-
give: number;
|
|
1036
|
-
}) {
|
|
1037
|
-
return (
|
|
1038
|
-
<>
|
|
1039
|
-
{shown.map((message, index) => {
|
|
1040
|
-
// the speaker fixes the side, so a turn never switches sides as older ones stack up
|
|
1041
|
-
const mine = message.role === "user";
|
|
1042
|
-
// 18..68 rather than 20..75: a five-line newest turn has to clear the activity line
|
|
1043
|
-
const top = 18 + (index * 50) / Math.max(1, shown.length - 1);
|
|
1044
|
-
const age = shown.length - 1 - index;
|
|
1045
|
-
const size = atAge(CAPTION_SIZES, age);
|
|
1046
|
-
const pad = atAge(CAPTION_PADS, age);
|
|
1047
|
-
const fill = atAge(mine ? CAPTION_YOURS : CAPTION_HERS, age);
|
|
1048
|
-
const ink = atAge(CAPTION_HERS_INK, age);
|
|
1049
|
-
|
|
1050
|
-
return (
|
|
1051
|
-
<div
|
|
1052
|
-
key={message.id}
|
|
1053
|
-
style={{
|
|
1054
|
-
top: `${top}%`,
|
|
1055
|
-
transform: `translateY(calc(-50% + ${-give * GIVE}px))`,
|
|
1056
|
-
}}
|
|
1057
|
-
className={cn(
|
|
1058
|
-
// fixed-width slot, natural-width plate: short lines stay short and hug the face
|
|
1059
|
-
"pointer-events-auto absolute flex w-[min(23rem,24vw)] transition-transform duration-100",
|
|
1060
|
-
// yours on the right, the side the settings corner already takes
|
|
1061
|
-
mine ? "left-full ml-6" : "right-full mr-6 justify-end",
|
|
1062
|
-
)}
|
|
1063
|
-
>
|
|
1064
|
-
{/* Not a `Bubble`: that sets its surface on the content from the
|
|
1065
|
-
parent, at a specificity a caption cannot override. One shape,
|
|
1066
|
-
two fills — and no edge on either, so the plate is the whole
|
|
1067
|
-
surface. The squared corner is the one nearest the face. */}
|
|
1068
|
-
<div
|
|
1069
|
-
className={cn(
|
|
1070
|
-
"w-fit max-w-full animate-in rounded-[18px] fade-in duration-500",
|
|
1071
|
-
pad,
|
|
1072
|
-
mine
|
|
1073
|
-
? cn(
|
|
1074
|
-
"rounded-bl-md text-primary-foreground slide-in-from-left-2",
|
|
1075
|
-
fill,
|
|
1076
|
-
)
|
|
1077
|
-
: cn("rounded-br-md slide-in-from-right-2", fill, ink),
|
|
1078
|
-
)}
|
|
1079
|
-
>
|
|
1080
|
-
{/* One truncation idiom on both sides: speech that runs past the
|
|
1081
|
-
frame fades out. An ellipsis mid-sentence reads as an error. */}
|
|
1082
|
-
<Flow
|
|
1083
|
-
text={message.text}
|
|
1084
|
-
lines={CAPTION_TURN_LINES[age] ?? 2}
|
|
1085
|
-
className={size}
|
|
1086
|
-
/>
|
|
1087
|
-
</div>
|
|
1088
|
-
</div>
|
|
1089
|
-
);
|
|
1090
|
-
})}
|
|
1091
|
-
</>
|
|
1092
|
-
);
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
1125
|
export function Thursday() {
|
|
1096
1126
|
const {
|
|
1097
1127
|
status,
|
|
1128
|
+
failed,
|
|
1098
1129
|
messages,
|
|
1099
1130
|
tool,
|
|
1131
|
+
thinkingSince,
|
|
1132
|
+
thinkingTitle,
|
|
1133
|
+
ended,
|
|
1134
|
+
faceWord,
|
|
1100
1135
|
idleLeft,
|
|
1101
1136
|
since,
|
|
1102
|
-
micOff,
|
|
1103
1137
|
call,
|
|
1138
|
+
ringing,
|
|
1139
|
+
decline,
|
|
1104
1140
|
getSpectrum,
|
|
1105
1141
|
getMicSpectrum,
|
|
1106
1142
|
wakePhrase,
|
|
@@ -1117,24 +1153,29 @@ export function Thursday() {
|
|
|
1117
1153
|
* can change during a call (NeedsKey). Unknown counts as not callable.
|
|
1118
1154
|
*/
|
|
1119
1155
|
const { data: config } = useServerRoute<ConfigStatus[]>(queryKey.config);
|
|
1120
|
-
const callable =
|
|
1121
|
-
isConfigSet(config, provider.apiKeyName),
|
|
1122
|
-
);
|
|
1156
|
+
const callable = isConfigSet(config, LIVE_PROVIDER.apiKeyName);
|
|
1123
1157
|
|
|
1124
1158
|
return (
|
|
1125
1159
|
<>
|
|
1126
1160
|
{/* the tab shows the call and what is owed while the app is off-screen */}
|
|
1127
|
-
<TabState live={status !== "idle"} />
|
|
1161
|
+
<TabState live={status !== "idle"} ringing={ringing !== null} />
|
|
1128
1162
|
<CallScreen
|
|
1129
1163
|
status={status}
|
|
1164
|
+
failed={failed}
|
|
1130
1165
|
messages={messages}
|
|
1131
1166
|
tool={tool}
|
|
1167
|
+
thinkingSince={thinkingSince}
|
|
1168
|
+
thinkingTitle={thinkingTitle}
|
|
1169
|
+
ended={ended}
|
|
1170
|
+
faceWord={faceWord}
|
|
1132
1171
|
onTap={call}
|
|
1172
|
+
// without a key the face asks for one, so nothing can answer
|
|
1173
|
+
ringing={callable ? ringing : null}
|
|
1174
|
+
onDecline={decline}
|
|
1133
1175
|
wakePhrase={wakePhrase}
|
|
1134
1176
|
hotkeyLabel={hotkeyLabel}
|
|
1135
1177
|
idleLeft={idleLeft}
|
|
1136
1178
|
since={since}
|
|
1137
|
-
micOff={micOff}
|
|
1138
1179
|
getSpectrum={getSpectrum}
|
|
1139
1180
|
getMicSpectrum={getMicSpectrum}
|
|
1140
1181
|
face={face}
|