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
|
@@ -11,31 +11,36 @@ import { Button } from "@/components/ui/button";
|
|
|
11
11
|
import { Combobox } from "@/components/ui/combobox";
|
|
12
12
|
import { Input } from "@/components/ui/input";
|
|
13
13
|
import { notify } from "@/components/ui/notify";
|
|
14
|
+
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
|
14
15
|
import { Segmented } from "@/components/ui/segmented";
|
|
16
|
+
import { Switch } from "@/components/ui/switch";
|
|
15
17
|
import { Textarea } from "@/components/ui/textarea";
|
|
16
18
|
import { ASCII_FACE } from "@/config";
|
|
17
|
-
import { ProviderIcon } from "@/features/ai/components/provider-icon";
|
|
18
19
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
LIVE_BACKEND_MODELS,
|
|
21
|
+
LIVE_DEFAULTS,
|
|
22
|
+
LIVE_PROVIDER,
|
|
23
|
+
LIVE_REASONING,
|
|
24
|
+
type LiveSettings,
|
|
25
|
+
} from "@/features/ai/live.schema";
|
|
26
|
+
import type { AiProvider } from "@/features/ai/model.schema";
|
|
23
27
|
import { MarkPalette } from "@/features/bot/components/mark-palette";
|
|
24
28
|
import { MARK_SHAPES } from "@/features/bot/mark.const";
|
|
29
|
+
import { KEY_MIN, KeyInput } from "@/features/config/components/voice-key";
|
|
30
|
+
import { setConfigAction } from "@/features/config/config.action";
|
|
25
31
|
import {
|
|
26
|
-
SettingChoiceRows,
|
|
27
32
|
SettingError,
|
|
28
33
|
SettingGroup,
|
|
29
|
-
SettingItems,
|
|
30
34
|
SettingNote,
|
|
31
35
|
SettingRailNote,
|
|
32
36
|
SettingScreen,
|
|
33
37
|
SettingSkeleton,
|
|
34
|
-
SettingToggle,
|
|
35
38
|
} from "@/features/settings/components/setting-ui";
|
|
36
39
|
import type { SkillSummary } from "@/features/skills/skills.schema";
|
|
37
40
|
import { CallHistoryRow } from "@/features/thursday/components/call-log";
|
|
38
41
|
import { FACES, Face } from "@/features/thursday/components/face";
|
|
42
|
+
import { ThursdayMark } from "@/features/thursday/components/thursday-mark";
|
|
43
|
+
import { VoicePicker } from "@/features/thursday/components/voice-picker";
|
|
39
44
|
import {
|
|
40
45
|
ASCII_CHARSETS,
|
|
41
46
|
type AsciiCharset,
|
|
@@ -54,6 +59,7 @@ import {
|
|
|
54
59
|
CALL_BACK_MODES,
|
|
55
60
|
CAPTION_VIEWS,
|
|
56
61
|
type CallBack,
|
|
62
|
+
CallBackSchema,
|
|
57
63
|
type CaptionView,
|
|
58
64
|
type Hotkey,
|
|
59
65
|
type ThursdayFace,
|
|
@@ -69,15 +75,16 @@ import {
|
|
|
69
75
|
useHotkeyLabel,
|
|
70
76
|
} from "@/hooks/use-hotkey";
|
|
71
77
|
import { COMMON_VALIDATE } from "@/lib/limits";
|
|
78
|
+
import { LIVE_MODEL } from "@/lib/live/live.schema";
|
|
72
79
|
import { useServerAction } from "@/lib/protocol/use-server-action";
|
|
73
80
|
import { revalidate, useServerRoute } from "@/lib/protocol/use-server-route";
|
|
74
81
|
import { cn, WAITING_INK } from "@/lib/utils";
|
|
75
82
|
|
|
76
83
|
/**
|
|
77
|
-
* Settings for the call: face,
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
84
|
+
* Settings for the call: face, captions, the two models, how a call starts, and
|
|
85
|
+
* its history. Everything but the skills switch is kept in the browser
|
|
86
|
+
* (thursday.store, face.store) and read when a call opens; skills are the
|
|
87
|
+
* server's, because they are read where no browser is.
|
|
81
88
|
*/
|
|
82
89
|
export function ThursdaySetting() {
|
|
83
90
|
// local store: no waiting, no revalidation
|
|
@@ -94,98 +101,421 @@ export function ThursdaySetting() {
|
|
|
94
101
|
if (isLoading) return <SettingSkeleton rows={4} />;
|
|
95
102
|
if (error) return <SettingError message={error.message} />;
|
|
96
103
|
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
const hasKey = providers.some(
|
|
105
|
+
(entry) => entry.apiKeyName === LIVE_PROVIDER.apiKeyName && entry.hasKey,
|
|
106
|
+
);
|
|
100
107
|
|
|
101
108
|
return (
|
|
102
109
|
<SettingScreen
|
|
103
110
|
footer={
|
|
104
111
|
<SettingRailNote>
|
|
105
|
-
|
|
106
|
-
your skills go in.
|
|
112
|
+
Both of her prompts are assembled fresh on every call — memory, the
|
|
113
|
+
roster and your skills go in. Changes here apply from the next call.
|
|
107
114
|
</SettingRailNote>
|
|
108
115
|
}
|
|
109
116
|
>
|
|
110
117
|
<FacePicker value={face} onChange={setThursdayFace} />
|
|
111
118
|
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
<Captions
|
|
120
|
+
value={thursday.captionView}
|
|
121
|
+
onChange={(captionView) => patch({ captionView })}
|
|
122
|
+
/>
|
|
123
|
+
|
|
124
|
+
<ModelsSetting
|
|
125
|
+
value={thursday}
|
|
126
|
+
face={face}
|
|
127
|
+
hasKey={hasKey}
|
|
128
|
+
onChange={patch}
|
|
129
|
+
/>
|
|
130
|
+
|
|
131
|
+
{/* Every way a call starts other than pressing her face, read at once */}
|
|
132
|
+
<SettingGroup label="Starting a call">
|
|
133
|
+
<Tiles columns={3}>
|
|
134
|
+
<WakeWord
|
|
135
|
+
value={thursday.wake}
|
|
136
|
+
onChange={(wake) => patch({ wake })}
|
|
137
|
+
/>
|
|
138
|
+
<Shortcut
|
|
139
|
+
value={thursday.hotkey}
|
|
140
|
+
onChange={(hotkey) => patch({ hotkey })}
|
|
141
|
+
/>
|
|
142
|
+
<CallBackPicker
|
|
143
|
+
value={thursday.callBack}
|
|
144
|
+
onChange={(callBack) => patch({ callBack })}
|
|
145
|
+
/>
|
|
146
|
+
</Tiles>
|
|
147
|
+
</SettingGroup>
|
|
148
|
+
|
|
149
|
+
<SettingGroup label="History">
|
|
150
|
+
<Tiles columns={2}>
|
|
151
|
+
<CallHistoryRow />
|
|
152
|
+
<ResetHistory />
|
|
153
|
+
</Tiles>
|
|
154
|
+
</SettingGroup>
|
|
155
|
+
</SettingScreen>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
114
158
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
159
|
+
/** Tiles side by side in one bordered card, stacked when the column is narrow. */
|
|
160
|
+
function Tiles({ columns, children }: { columns: 2 | 3; children: ReactNode }) {
|
|
161
|
+
return (
|
|
162
|
+
<div className="@container">
|
|
163
|
+
<div
|
|
164
|
+
className={cn(
|
|
165
|
+
"grid divide-y divide-border/60 overflow-hidden rounded-xl border border-border/60",
|
|
166
|
+
columns === 3
|
|
167
|
+
? "@3xl:grid-cols-3 @3xl:divide-x @3xl:divide-y-0"
|
|
168
|
+
: "@xl:grid-cols-2 @xl:divide-x @xl:divide-y-0",
|
|
169
|
+
)}
|
|
118
170
|
>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
171
|
+
{children}
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** A tile's first line: what it is, and its switch when it has one. */
|
|
178
|
+
function TileHead({
|
|
179
|
+
label,
|
|
180
|
+
children,
|
|
181
|
+
}: {
|
|
182
|
+
label: string;
|
|
183
|
+
children?: ReactNode;
|
|
184
|
+
}) {
|
|
185
|
+
return (
|
|
186
|
+
<div className="flex min-h-5 items-center gap-3">
|
|
187
|
+
<span className="min-w-0 flex-1 truncate text-sm font-medium">
|
|
188
|
+
{label}
|
|
189
|
+
</span>
|
|
190
|
+
{children}
|
|
191
|
+
</div>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Both models a call runs on, in one card: the Live voice and the Responses
|
|
197
|
+
* backend that holds her tools (thursday.prompt). They share the OpenAI key, so
|
|
198
|
+
* a missing key is asked for once, above both.
|
|
199
|
+
*/
|
|
200
|
+
function ModelsSetting({
|
|
201
|
+
value,
|
|
202
|
+
face,
|
|
203
|
+
hasKey,
|
|
204
|
+
onChange,
|
|
205
|
+
}: {
|
|
206
|
+
value: LiveSettings;
|
|
207
|
+
/** The picker plays a sample through her own face. */
|
|
208
|
+
face: ThursdayFace;
|
|
209
|
+
hasKey: boolean;
|
|
210
|
+
onChange: (change: Partial<LiveSettings>) => void;
|
|
211
|
+
}) {
|
|
212
|
+
return (
|
|
213
|
+
<SettingGroup
|
|
214
|
+
label="Models"
|
|
215
|
+
note="Both run on your OpenAI key. Instructions are saved when you leave the field."
|
|
216
|
+
>
|
|
217
|
+
<div className="@container divide-y divide-border/60 rounded-xl border border-border/60">
|
|
218
|
+
{!hasKey && <KeyRow />}
|
|
219
|
+
|
|
220
|
+
<ModelSection name="Voice" fact="billed by the minute">
|
|
221
|
+
<div className="grid gap-4 @xl:grid-cols-2">
|
|
222
|
+
<ModelBlock label="model">
|
|
223
|
+
{/* Locked: LIVE_MODEL is the only Live model a call opens on */}
|
|
224
|
+
<Combobox
|
|
225
|
+
value={LIVE_MODEL}
|
|
226
|
+
onChange={() => undefined}
|
|
227
|
+
options={[{ value: LIVE_MODEL, label: "GPT-Live 1" }]}
|
|
228
|
+
aria-label="Voice model"
|
|
229
|
+
disabled
|
|
230
|
+
/>
|
|
231
|
+
</ModelBlock>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
{/* Its own row: opened, the picker holds her face beside the voices. */}
|
|
235
|
+
<ModelBlock label="voice">
|
|
236
|
+
<VoicePicker
|
|
237
|
+
voice={value.voice}
|
|
238
|
+
face={face}
|
|
239
|
+
onChange={(voice) =>
|
|
240
|
+
onChange({ voice: voice.trim() || LIVE_DEFAULTS.voice })
|
|
129
241
|
}
|
|
130
242
|
/>
|
|
131
|
-
|
|
132
|
-
</SettingItems>
|
|
133
|
-
</SettingGroup>
|
|
243
|
+
</ModelBlock>
|
|
134
244
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
245
|
+
<ModelBlock label="instructions">
|
|
246
|
+
<PromptField
|
|
247
|
+
value={value.voicePrompt}
|
|
248
|
+
onCommit={(voicePrompt) => onChange({ voicePrompt })}
|
|
249
|
+
placeholder="How to address you, how much to say, what to skip."
|
|
250
|
+
aria-label="Voice instructions"
|
|
251
|
+
/>
|
|
252
|
+
</ModelBlock>
|
|
253
|
+
</ModelSection>
|
|
139
254
|
|
|
140
|
-
|
|
255
|
+
<ModelSection name="Backend" fact="billed per token">
|
|
256
|
+
<ModelBlock label="model">
|
|
257
|
+
<BackendModelPicker
|
|
258
|
+
value={value.backendModel}
|
|
259
|
+
onChange={(backendModel) => onChange({ backendModel })}
|
|
260
|
+
/>
|
|
261
|
+
</ModelBlock>
|
|
141
262
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
263
|
+
{/* Auto omits the parameter, so a model without reasoning still runs */}
|
|
264
|
+
<ModelBlock label="reasoning">
|
|
265
|
+
<Segmented
|
|
266
|
+
aria-label="Reasoning effort"
|
|
267
|
+
className="w-full flex-wrap *:flex-1"
|
|
268
|
+
options={REASONING_OPTIONS}
|
|
269
|
+
value={value.reasoningEffort ?? "auto"}
|
|
270
|
+
onChange={(effort) =>
|
|
271
|
+
onChange({ reasoningEffort: effort === "auto" ? null : effort })
|
|
272
|
+
}
|
|
273
|
+
/>
|
|
274
|
+
</ModelBlock>
|
|
146
275
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
276
|
+
<ModelBlock label="tools">
|
|
277
|
+
<BackendTools
|
|
278
|
+
webSearch={value.webSearch}
|
|
279
|
+
onWebSearch={(webSearch) => onChange({ webSearch })}
|
|
280
|
+
/>
|
|
281
|
+
</ModelBlock>
|
|
151
282
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
283
|
+
<ModelBlock label="instructions">
|
|
284
|
+
<PromptField
|
|
285
|
+
value={value.backendPrompt}
|
|
286
|
+
onCommit={(backendPrompt) => onChange({ backendPrompt })}
|
|
287
|
+
placeholder="How work should be handed over, what to check first."
|
|
288
|
+
aria-label="Backend instructions"
|
|
289
|
+
/>
|
|
290
|
+
</ModelBlock>
|
|
291
|
+
</ModelSection>
|
|
292
|
+
</div>
|
|
293
|
+
</SettingGroup>
|
|
294
|
+
);
|
|
295
|
+
}
|
|
155
296
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
297
|
+
/** One model's half of the card: its name and how it bills, then what to choose. */
|
|
298
|
+
function ModelSection({
|
|
299
|
+
name,
|
|
300
|
+
fact,
|
|
301
|
+
children,
|
|
302
|
+
}: {
|
|
303
|
+
name: string;
|
|
304
|
+
fact: string;
|
|
305
|
+
children: ReactNode;
|
|
306
|
+
}) {
|
|
307
|
+
return (
|
|
308
|
+
<div className="grid gap-4 p-5 @2xl:grid-cols-[8.5rem_minmax(0,1fr)] @2xl:gap-6">
|
|
309
|
+
<span className="space-y-0.5">
|
|
310
|
+
<span className="block text-sm font-medium">{name}</span>
|
|
311
|
+
<span className="block font-mono text-[11px] text-muted-foreground">
|
|
312
|
+
{fact}
|
|
313
|
+
</span>
|
|
314
|
+
</span>
|
|
315
|
+
<div className="min-w-0 space-y-4">{children}</div>
|
|
316
|
+
</div>
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function ModelBlock({
|
|
321
|
+
label,
|
|
322
|
+
children,
|
|
323
|
+
}: {
|
|
324
|
+
label: string;
|
|
325
|
+
children: ReactNode;
|
|
326
|
+
}) {
|
|
327
|
+
return (
|
|
328
|
+
<div className="min-w-0 space-y-2">
|
|
329
|
+
<span className="block font-mono text-[11px] text-muted-foreground">
|
|
330
|
+
{label}
|
|
331
|
+
</span>
|
|
332
|
+
{children}
|
|
333
|
+
</div>
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** No key yet: paste one here, above both models, instead of leaving for Keys. */
|
|
338
|
+
function KeyRow() {
|
|
339
|
+
const [draft, setDraft] = useState("");
|
|
340
|
+
const [save, saving] = useServerAction(setConfigAction, {
|
|
341
|
+
onOk: () => {
|
|
342
|
+
revalidate(queryKey.llmModel);
|
|
343
|
+
revalidate(queryKey.config);
|
|
344
|
+
setDraft("");
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
const ready = draft.trim().length >= KEY_MIN;
|
|
348
|
+
|
|
349
|
+
return (
|
|
350
|
+
<div className="space-y-3 p-5">
|
|
351
|
+
<span className="block space-y-0.5">
|
|
352
|
+
<span className={cn("block text-sm font-medium", WAITING_INK)}>
|
|
353
|
+
No OpenAI key
|
|
354
|
+
</span>
|
|
355
|
+
<span className="block text-xs text-muted-foreground">
|
|
356
|
+
Her voice and the backend both run on it
|
|
357
|
+
</span>
|
|
358
|
+
</span>
|
|
359
|
+
<KeyInput
|
|
360
|
+
dense
|
|
361
|
+
provider={LIVE_PROVIDER}
|
|
362
|
+
saved={false}
|
|
363
|
+
value={draft}
|
|
364
|
+
ready={ready}
|
|
365
|
+
saving={saving}
|
|
366
|
+
onValue={setDraft}
|
|
367
|
+
onSubmit={() => ready && save(LIVE_PROVIDER.apiKeyName, draft)}
|
|
159
368
|
/>
|
|
369
|
+
</div>
|
|
370
|
+
);
|
|
371
|
+
}
|
|
160
372
|
|
|
161
|
-
|
|
162
|
-
|
|
373
|
+
/**
|
|
374
|
+
* The recent models as cards, and a field for any other id; the provider says
|
|
375
|
+
* at call time whether it runs. A typed id is saved on Enter or when the field
|
|
376
|
+
* is left, never per keystroke, and clearing it goes back to the default.
|
|
377
|
+
*/
|
|
378
|
+
function BackendModelPicker({
|
|
379
|
+
value,
|
|
380
|
+
onChange,
|
|
381
|
+
}: {
|
|
382
|
+
value: string;
|
|
383
|
+
onChange: (model: string) => void;
|
|
384
|
+
}) {
|
|
385
|
+
const listed = LIVE_BACKEND_MODELS.some((model) => model.id === value);
|
|
386
|
+
const other = useDraft(
|
|
387
|
+
listed ? "" : value,
|
|
388
|
+
(next) => onChange(next || LIVE_DEFAULTS.backendModel),
|
|
389
|
+
{ min: 0 },
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
return (
|
|
393
|
+
<div className="space-y-2">
|
|
394
|
+
<div
|
|
395
|
+
role="radiogroup"
|
|
396
|
+
aria-label="Backend model"
|
|
397
|
+
className="grid grid-cols-2 gap-2 @3xl:grid-cols-4"
|
|
398
|
+
>
|
|
399
|
+
{LIVE_BACKEND_MODELS.map((model) => {
|
|
400
|
+
const picked = model.id === value;
|
|
401
|
+
return (
|
|
402
|
+
<button
|
|
403
|
+
key={model.id}
|
|
404
|
+
type="button"
|
|
405
|
+
role="radio"
|
|
406
|
+
aria-checked={picked}
|
|
407
|
+
onClick={() => onChange(model.id)}
|
|
408
|
+
className={cn(
|
|
409
|
+
"min-w-0 space-y-0.5 rounded-lg border px-3 py-2.5 text-left outline-none transition-colors focus-visible:ring-3 focus-visible:ring-ring/50",
|
|
410
|
+
picked
|
|
411
|
+
? "border-foreground bg-muted/40"
|
|
412
|
+
: "border-border/60 hover:bg-muted/50",
|
|
413
|
+
)}
|
|
414
|
+
>
|
|
415
|
+
<span className="flex items-center gap-2">
|
|
416
|
+
<span className="min-w-0 flex-1 truncate text-sm font-medium">
|
|
417
|
+
{model.label}
|
|
418
|
+
</span>
|
|
419
|
+
{picked && <Check className="size-3.5 shrink-0" />}
|
|
420
|
+
</span>
|
|
421
|
+
<span className="block truncate font-mono text-[11px] text-muted-foreground">
|
|
422
|
+
{model.id} · {model.tier}
|
|
423
|
+
</span>
|
|
424
|
+
</button>
|
|
425
|
+
);
|
|
426
|
+
})}
|
|
427
|
+
</div>
|
|
428
|
+
|
|
429
|
+
<Input
|
|
430
|
+
value={other.value}
|
|
431
|
+
onChange={(event) => other.set(event.target.value)}
|
|
432
|
+
onBlur={other.commit}
|
|
433
|
+
onKeyDown={other.onKeyDown}
|
|
434
|
+
placeholder="Other model id"
|
|
435
|
+
aria-label="Other backend model id"
|
|
436
|
+
spellCheck={false}
|
|
437
|
+
className="font-mono text-sm"
|
|
438
|
+
/>
|
|
439
|
+
</div>
|
|
163
440
|
);
|
|
164
441
|
}
|
|
165
442
|
|
|
443
|
+
const REASONING_OPTIONS: readonly {
|
|
444
|
+
value: "auto" | (typeof LIVE_REASONING)[number];
|
|
445
|
+
label: string;
|
|
446
|
+
title: string;
|
|
447
|
+
}[] = [
|
|
448
|
+
{ value: "auto", label: "auto", title: "The model's own default" },
|
|
449
|
+
...LIVE_REASONING.map((effort) => ({
|
|
450
|
+
value: effort,
|
|
451
|
+
label: effort,
|
|
452
|
+
title: `Reasoning effort ${effort}`,
|
|
453
|
+
})),
|
|
454
|
+
];
|
|
455
|
+
|
|
166
456
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
457
|
+
* What the backend may reach for. Web search is this browser's setting; the
|
|
458
|
+
* skills switch hands the call `load_skill` and is the server's, because tools
|
|
459
|
+
* are built where no browser is. Off by default: reading a skill is a page of
|
|
460
|
+
* instructions arriving mid-sentence.
|
|
170
461
|
*/
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
|
|
462
|
+
function BackendTools({
|
|
463
|
+
webSearch,
|
|
464
|
+
onWebSearch,
|
|
465
|
+
}: {
|
|
466
|
+
webSearch: boolean;
|
|
467
|
+
onWebSearch: (on: boolean) => void;
|
|
468
|
+
}) {
|
|
469
|
+
const { data: skills } = useServerRoute<boolean>(queryKey.callSkills);
|
|
470
|
+
const [setSkills] = useServerAction(setCallSkillsAction, {
|
|
174
471
|
onOk: () => revalidate(queryKey.callSkills),
|
|
175
472
|
});
|
|
176
473
|
|
|
177
474
|
return (
|
|
178
|
-
<
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
475
|
+
<div className="space-y-2">
|
|
476
|
+
<div className="flex flex-wrap gap-x-7 gap-y-3">
|
|
477
|
+
<InlineSwitch
|
|
478
|
+
label="Search the web"
|
|
479
|
+
checked={webSearch}
|
|
480
|
+
onChange={onWebSearch}
|
|
481
|
+
/>
|
|
482
|
+
<InlineSwitch
|
|
483
|
+
label="Read skills herself"
|
|
484
|
+
checked={skills ?? false}
|
|
485
|
+
disabled={skills === undefined}
|
|
486
|
+
onChange={(on) => setSkills(on)}
|
|
487
|
+
/>
|
|
488
|
+
</div>
|
|
489
|
+
{webSearch && (
|
|
490
|
+
<SettingNote>
|
|
491
|
+
Each search adds to the backend's OpenAI usage.
|
|
492
|
+
</SettingNote>
|
|
493
|
+
)}
|
|
494
|
+
{skills && <InstalledSkills />}
|
|
495
|
+
</div>
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function InlineSwitch({
|
|
500
|
+
label,
|
|
501
|
+
checked,
|
|
502
|
+
disabled,
|
|
503
|
+
onChange,
|
|
504
|
+
}: {
|
|
505
|
+
label: string;
|
|
506
|
+
checked: boolean;
|
|
507
|
+
disabled?: boolean;
|
|
508
|
+
onChange: (on: boolean) => void;
|
|
509
|
+
}) {
|
|
510
|
+
return (
|
|
511
|
+
<label className="flex items-center gap-2.5 text-sm">
|
|
512
|
+
<Switch
|
|
513
|
+
checked={checked}
|
|
514
|
+
disabled={disabled}
|
|
515
|
+
onCheckedChange={onChange}
|
|
516
|
+
/>
|
|
517
|
+
{label}
|
|
518
|
+
</label>
|
|
189
519
|
);
|
|
190
520
|
}
|
|
191
521
|
|
|
@@ -203,23 +533,49 @@ function InstalledSkills() {
|
|
|
203
533
|
);
|
|
204
534
|
}
|
|
205
535
|
|
|
536
|
+
/** Added instructions: a draft while typing, saved when the field is left. */
|
|
537
|
+
function PromptField({
|
|
538
|
+
value,
|
|
539
|
+
onCommit,
|
|
540
|
+
placeholder,
|
|
541
|
+
"aria-label": ariaLabel,
|
|
542
|
+
}: {
|
|
543
|
+
value: string;
|
|
544
|
+
onCommit: (next: string) => void;
|
|
545
|
+
placeholder: string;
|
|
546
|
+
"aria-label": string;
|
|
547
|
+
}) {
|
|
548
|
+
const draft = useDraft(value, onCommit, { min: 0 });
|
|
549
|
+
|
|
550
|
+
return (
|
|
551
|
+
<Textarea
|
|
552
|
+
value={draft.value}
|
|
553
|
+
maxLength={COMMON_VALIDATE.prompt.max}
|
|
554
|
+
onChange={(event) => draft.set(event.target.value)}
|
|
555
|
+
onBlur={draft.commit}
|
|
556
|
+
placeholder={placeholder}
|
|
557
|
+
aria-label={ariaLabel}
|
|
558
|
+
/>
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
|
|
206
562
|
/**
|
|
207
563
|
* Wipes what the app has kept of its own use, in one go: calls, jobs and
|
|
208
564
|
* memory. The same set `pnpm reset` calls History, so the terminal and this
|
|
209
565
|
* button agree. Keys, bots and connectors stay.
|
|
210
566
|
*
|
|
211
|
-
* Last
|
|
212
|
-
*
|
|
213
|
-
*
|
|
567
|
+
* Last in the section, not in the rail: the rail is on screen the whole time a
|
|
568
|
+
* section is open, and the one thing here that cannot be undone should be
|
|
569
|
+
* reached by scrolling to it.
|
|
214
570
|
*/
|
|
215
571
|
function ResetHistory() {
|
|
216
572
|
const [reset, resetting] = useServerAction(resetHistoryAction, {
|
|
217
|
-
okMessage: ({ calls,
|
|
218
|
-
`Wiped ${calls} calls, ${
|
|
573
|
+
okMessage: ({ calls, threads, notes }) =>
|
|
574
|
+
`Wiped ${calls} calls, ${threads} jobs, ${notes} notes`,
|
|
219
575
|
onOk: () => {
|
|
220
576
|
// Prefix match, so every loaded history page goes too.
|
|
221
577
|
revalidate(queryKey.memory);
|
|
222
|
-
revalidate(queryKey.
|
|
578
|
+
revalidate(queryKey.threads);
|
|
223
579
|
revalidate(queryKey.callHistory(null));
|
|
224
580
|
},
|
|
225
581
|
});
|
|
@@ -236,30 +592,28 @@ function ResetHistory() {
|
|
|
236
592
|
};
|
|
237
593
|
|
|
238
594
|
return (
|
|
239
|
-
<
|
|
240
|
-
<
|
|
241
|
-
<
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
</SettingItems>
|
|
262
|
-
</SettingGroup>
|
|
595
|
+
<div className="flex min-w-0 items-center gap-3 p-4">
|
|
596
|
+
<span className="grid size-10 shrink-0 place-items-center rounded-lg bg-muted text-muted-foreground">
|
|
597
|
+
<TriangleAlert className="size-4" />
|
|
598
|
+
</span>
|
|
599
|
+
<span className="min-w-0 flex-1 space-y-0.5">
|
|
600
|
+
<span className="block truncate text-sm font-medium">
|
|
601
|
+
Reset history
|
|
602
|
+
</span>
|
|
603
|
+
<span className="block truncate text-xs text-muted-foreground">
|
|
604
|
+
Calls, jobs and memory. Keys and bots stay.
|
|
605
|
+
</span>
|
|
606
|
+
</span>
|
|
607
|
+
<Button
|
|
608
|
+
variant="outline"
|
|
609
|
+
size="sm"
|
|
610
|
+
loading={resetting}
|
|
611
|
+
onClick={confirmReset}
|
|
612
|
+
className="shrink-0 text-destructive hover:text-destructive"
|
|
613
|
+
>
|
|
614
|
+
Reset
|
|
615
|
+
</Button>
|
|
616
|
+
</div>
|
|
263
617
|
);
|
|
264
618
|
}
|
|
265
619
|
|
|
@@ -300,13 +654,18 @@ function FacePicker({
|
|
|
300
654
|
</p>
|
|
301
655
|
</div>
|
|
302
656
|
|
|
303
|
-
{/* Only the mark takes a color; the orb follows the theme (OrbFace ignores it).
|
|
657
|
+
{/* Only the mark takes a color; the orb follows the theme (OrbFace ignores it).
|
|
658
|
+
A paint covers the colour without clearing it; picking a colour takes it off. */}
|
|
304
659
|
{value.kind === "mark" && (
|
|
305
660
|
<MarkPalette
|
|
306
|
-
color={value.color}
|
|
307
|
-
themePicked={!value.color}
|
|
308
|
-
onTheme={() => patch({ color: undefined })}
|
|
309
|
-
onPick={(color) => patch({ color })}
|
|
661
|
+
color={value.paint ? undefined : value.color}
|
|
662
|
+
themePicked={!value.paint && !value.color}
|
|
663
|
+
onTheme={() => patch({ color: undefined, paint: undefined })}
|
|
664
|
+
onPick={(color) => patch({ color, paint: undefined })}
|
|
665
|
+
paint={value.paint}
|
|
666
|
+
onPaint={(paint) =>
|
|
667
|
+
patch({ paint: value.paint === paint ? undefined : paint })
|
|
668
|
+
}
|
|
310
669
|
/>
|
|
311
670
|
)}
|
|
312
671
|
|
|
@@ -430,107 +789,96 @@ function Slider({
|
|
|
430
789
|
);
|
|
431
790
|
}
|
|
432
791
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
792
|
+
const CAPTION_LABEL: Record<CaptionView, { label: string; hint: string }> = {
|
|
793
|
+
center: {
|
|
794
|
+
label: "Her last line",
|
|
795
|
+
hint: "One caption under the mark — only what she said.",
|
|
796
|
+
},
|
|
797
|
+
sides: {
|
|
798
|
+
label: "Last three turns",
|
|
799
|
+
hint: "Hers on the left, yours on the right, beside the mark.",
|
|
800
|
+
},
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
/** How much of the conversation shows while speaking, picked by what it looks like. */
|
|
804
|
+
function Captions({
|
|
439
805
|
value,
|
|
440
|
-
|
|
441
|
-
onPick,
|
|
806
|
+
onChange,
|
|
442
807
|
}: {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
value: SpeachModelRef | null | undefined;
|
|
446
|
-
hasKey: boolean;
|
|
447
|
-
onPick: (next: Omit<SpeachModelRef, "provider">) => void;
|
|
808
|
+
value: CaptionView;
|
|
809
|
+
onChange: (view: CaptionView) => void;
|
|
448
810
|
}) {
|
|
449
|
-
const picked = Boolean(value);
|
|
450
|
-
const voice = value?.voice ?? provider.defaultVoice;
|
|
451
|
-
const model = value?.model ?? "";
|
|
452
|
-
|
|
453
811
|
return (
|
|
454
|
-
<
|
|
455
|
-
<
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
{provider.label}
|
|
465
|
-
</span>
|
|
466
|
-
<span className="block truncate font-mono text-xs text-muted-foreground">
|
|
467
|
-
{model || provider.models[0].id}
|
|
468
|
-
</span>
|
|
469
|
-
</span>
|
|
470
|
-
|
|
471
|
-
{!hasKey ? (
|
|
472
|
-
<span className="flex shrink-0 items-center gap-1 font-mono text-[11px] text-muted-foreground">
|
|
473
|
-
<TriangleAlert className="size-3" />
|
|
474
|
-
No key
|
|
475
|
-
</span>
|
|
476
|
-
) : (
|
|
477
|
-
picked && <Check className="size-4 shrink-0" />
|
|
478
|
-
)}
|
|
479
|
-
</button>
|
|
480
|
-
|
|
481
|
-
{/* Model and voices only matter once this is the one answering */}
|
|
482
|
-
{picked && (
|
|
483
|
-
<div className="space-y-3 pt-3">
|
|
484
|
-
<Combobox
|
|
485
|
-
value={model}
|
|
486
|
-
onChange={(next) =>
|
|
487
|
-
onPick({ voice: value?.voice ?? null, model: next || null })
|
|
488
|
-
}
|
|
489
|
-
options={provider.models.map((entry) => ({
|
|
490
|
-
value: entry.id,
|
|
491
|
-
label: entry.label,
|
|
492
|
-
hint: entry.id,
|
|
493
|
-
}))}
|
|
494
|
-
aria-label={`${provider.label} realtime model`}
|
|
495
|
-
placeholder={provider.models[0].id}
|
|
496
|
-
empty="Not on the list — it still runs"
|
|
497
|
-
/>
|
|
498
|
-
|
|
499
|
-
<div className="flex flex-wrap gap-1.5">
|
|
500
|
-
{provider.voices.map((name) => (
|
|
812
|
+
<SettingGroup label="Captions">
|
|
813
|
+
<div className="@container">
|
|
814
|
+
<div
|
|
815
|
+
role="radiogroup"
|
|
816
|
+
aria-label="Captions"
|
|
817
|
+
className="grid gap-3 @xl:grid-cols-2"
|
|
818
|
+
>
|
|
819
|
+
{CAPTION_VIEWS.map((view) => {
|
|
820
|
+
const picked = view === value;
|
|
821
|
+
return (
|
|
501
822
|
<button
|
|
502
|
-
key={
|
|
823
|
+
key={view}
|
|
503
824
|
type="button"
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
}
|
|
825
|
+
role="radio"
|
|
826
|
+
aria-checked={picked}
|
|
827
|
+
onClick={() => onChange(view)}
|
|
507
828
|
className={cn(
|
|
508
|
-
"rounded-
|
|
509
|
-
|
|
510
|
-
? "border-foreground
|
|
511
|
-
: "border-border/60
|
|
829
|
+
"min-w-0 space-y-3 rounded-xl border p-3 text-left outline-none transition-colors focus-visible:ring-3 focus-visible:ring-ring/50",
|
|
830
|
+
picked
|
|
831
|
+
? "border-foreground"
|
|
832
|
+
: "border-border/60 hover:bg-muted/50",
|
|
512
833
|
)}
|
|
513
834
|
>
|
|
514
|
-
{
|
|
835
|
+
<CaptionSketch view={view} />
|
|
836
|
+
<span className="flex items-center gap-3 px-1 pb-0.5">
|
|
837
|
+
<span className="min-w-0 flex-1 space-y-0.5">
|
|
838
|
+
<span className="block truncate text-sm font-medium">
|
|
839
|
+
{CAPTION_LABEL[view].label}
|
|
840
|
+
</span>
|
|
841
|
+
<span className="block truncate text-xs text-muted-foreground">
|
|
842
|
+
{CAPTION_LABEL[view].hint}
|
|
843
|
+
</span>
|
|
844
|
+
</span>
|
|
845
|
+
{picked && <Check className="size-4 shrink-0" />}
|
|
846
|
+
</span>
|
|
515
847
|
</button>
|
|
516
|
-
)
|
|
517
|
-
|
|
848
|
+
);
|
|
849
|
+
})}
|
|
518
850
|
</div>
|
|
519
|
-
|
|
520
|
-
</
|
|
851
|
+
</div>
|
|
852
|
+
</SettingGroup>
|
|
521
853
|
);
|
|
522
854
|
}
|
|
523
855
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
}
|
|
856
|
+
/** The call screen in miniature: her mark, and where the words sit. */
|
|
857
|
+
function CaptionSketch({ view }: { view: CaptionView }) {
|
|
858
|
+
const line = "block h-1 max-w-full rounded-full bg-foreground/20";
|
|
859
|
+
|
|
860
|
+
return (
|
|
861
|
+
<span className="flex h-24 items-center justify-center rounded-lg bg-muted">
|
|
862
|
+
{view === "center" ? (
|
|
863
|
+
<span className="flex flex-col items-center gap-2.5">
|
|
864
|
+
<ThursdayMark size={32} />
|
|
865
|
+
<span className={cn(line, "w-28")} />
|
|
866
|
+
</span>
|
|
867
|
+
) : (
|
|
868
|
+
<span className="grid w-full grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-4 px-6">
|
|
869
|
+
<span className="space-y-1.5">
|
|
870
|
+
<span className={cn(line, "w-24")} />
|
|
871
|
+
<span className={cn(line, "w-16")} />
|
|
872
|
+
</span>
|
|
873
|
+
<ThursdayMark size={32} />
|
|
874
|
+
<span>
|
|
875
|
+
<span className={cn(line, "ml-auto w-20")} />
|
|
876
|
+
</span>
|
|
877
|
+
</span>
|
|
878
|
+
)}
|
|
879
|
+
</span>
|
|
880
|
+
);
|
|
881
|
+
}
|
|
534
882
|
|
|
535
883
|
/** Whether a call may be opened without the user. Modes are in thursday.schema CALL_BACK_MODES. */
|
|
536
884
|
function CallBackPicker({
|
|
@@ -541,23 +889,32 @@ function CallBackPicker({
|
|
|
541
889
|
onChange: (mode: CallBack) => void;
|
|
542
890
|
}) {
|
|
543
891
|
return (
|
|
544
|
-
<
|
|
545
|
-
label="
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
"Needs this tab open. A tab that has been silent since it loaded may not be allowed to make a sound — the desktop notification covers that."
|
|
549
|
-
}
|
|
550
|
-
>
|
|
551
|
-
<SettingChoiceRows
|
|
552
|
-
options={CALL_BACK_MODES.map((mode) => ({
|
|
553
|
-
value: mode,
|
|
554
|
-
label: CALL_BACK_LABEL[mode],
|
|
555
|
-
hint: CALL_BACK_HINT[mode],
|
|
556
|
-
}))}
|
|
892
|
+
<div className="min-w-0 space-y-3 p-4">
|
|
893
|
+
<TileHead label="She calls you" />
|
|
894
|
+
<RadioGroup
|
|
895
|
+
aria-label="She calls you"
|
|
557
896
|
value={value}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
897
|
+
onValueChange={(mode) => onChange(CallBackSchema.parse(mode))}
|
|
898
|
+
className="gap-2.5"
|
|
899
|
+
>
|
|
900
|
+
{CALL_BACK_MODES.map((mode) => (
|
|
901
|
+
<label
|
|
902
|
+
key={mode}
|
|
903
|
+
className="flex min-w-0 items-center gap-2.5 text-sm"
|
|
904
|
+
>
|
|
905
|
+
<RadioGroupItem value={mode} />
|
|
906
|
+
<span className="truncate">{CALL_BACK_LABEL[mode]}</span>
|
|
907
|
+
</label>
|
|
908
|
+
))}
|
|
909
|
+
</RadioGroup>
|
|
910
|
+
<SettingNote>{CALL_BACK_HINT[value]}</SettingNote>
|
|
911
|
+
{value !== "off" && (
|
|
912
|
+
<SettingNote>
|
|
913
|
+
Needs this tab open. A tab that has been silent since it loaded may
|
|
914
|
+
not be allowed to make a sound — the desktop notification covers that.
|
|
915
|
+
</SettingNote>
|
|
916
|
+
)}
|
|
917
|
+
</div>
|
|
561
918
|
);
|
|
562
919
|
}
|
|
563
920
|
|
|
@@ -568,29 +925,6 @@ const CALL_BACK_HINT: Record<CallBack, string> = {
|
|
|
568
925
|
any: "Anything a bot finishes, she opens a line to tell you.",
|
|
569
926
|
};
|
|
570
927
|
|
|
571
|
-
/** How much of the conversation shows while speaking. */
|
|
572
|
-
function Captions({
|
|
573
|
-
value,
|
|
574
|
-
onChange,
|
|
575
|
-
}: {
|
|
576
|
-
value: CaptionView;
|
|
577
|
-
onChange: (view: CaptionView) => void;
|
|
578
|
-
}) {
|
|
579
|
-
return (
|
|
580
|
-
<SettingGroup label="Captions">
|
|
581
|
-
<SettingChoiceRows
|
|
582
|
-
options={CAPTION_VIEWS.map((view) => ({
|
|
583
|
-
value: view,
|
|
584
|
-
label: CAPTION_LABEL[view].label,
|
|
585
|
-
hint: CAPTION_LABEL[view].hint,
|
|
586
|
-
}))}
|
|
587
|
-
value={value}
|
|
588
|
-
onChange={onChange}
|
|
589
|
-
/>
|
|
590
|
-
</SettingGroup>
|
|
591
|
-
);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
928
|
/**
|
|
595
929
|
* Wake word switch and phrase. Enabled means the browser recognizer holds the
|
|
596
930
|
* mic between calls. Saved on blur, not per keystroke.
|
|
@@ -613,32 +947,33 @@ function WakeWord({
|
|
|
613
947
|
const terse = draft.value.trim().split(/\s+/).length < 2;
|
|
614
948
|
|
|
615
949
|
return (
|
|
616
|
-
<
|
|
617
|
-
<
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
950
|
+
<div className="min-w-0 space-y-3 p-4">
|
|
951
|
+
<TileHead label="Wake phrase">
|
|
952
|
+
<Switch
|
|
953
|
+
aria-label="Answer to her name"
|
|
954
|
+
checked={value.enabled}
|
|
955
|
+
onCheckedChange={(enabled) => onChange({ ...value, enabled })}
|
|
956
|
+
/>
|
|
957
|
+
</TileHead>
|
|
958
|
+
<Input
|
|
959
|
+
value={draft.value}
|
|
960
|
+
maxLength={WAKE_PHRASE.max}
|
|
961
|
+
spellCheck={false}
|
|
962
|
+
disabled={!value.enabled}
|
|
963
|
+
onChange={(event) => draft.set(event.target.value)}
|
|
964
|
+
onBlur={draft.commit}
|
|
965
|
+
onKeyDown={draft.onKeyDown}
|
|
966
|
+
aria-label="Wake phrase"
|
|
967
|
+
className="font-mono text-sm"
|
|
968
|
+
/>
|
|
969
|
+
<SettingNote>
|
|
970
|
+
{!value.enabled
|
|
971
|
+
? "Between calls, the browser listens for it and picks up."
|
|
972
|
+
: terse
|
|
973
|
+
? "One word will wake her by accident — say hello first."
|
|
974
|
+
: "Heard loosely, in English. Near misses count."}
|
|
975
|
+
</SettingNote>
|
|
976
|
+
</div>
|
|
642
977
|
);
|
|
643
978
|
}
|
|
644
979
|
|
|
@@ -675,78 +1010,42 @@ function Shortcut({
|
|
|
675
1010
|
};
|
|
676
1011
|
|
|
677
1012
|
return (
|
|
678
|
-
<
|
|
679
|
-
<
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
>
|
|
685
|
-
<div className="space-y-2">
|
|
686
|
-
<button
|
|
687
|
-
type="button"
|
|
688
|
-
{...HOTKEY_CAPTURE}
|
|
689
|
-
onClick={() => {
|
|
690
|
-
setBare(false);
|
|
691
|
-
setListening(true);
|
|
692
|
-
}}
|
|
693
|
-
onBlur={() => setListening(false)}
|
|
694
|
-
onKeyDown={listening ? record : undefined}
|
|
695
|
-
className={cn(
|
|
696
|
-
"w-full rounded-lg border px-3 py-2 font-mono text-sm outline-none transition-colors focus-visible:ring-3 focus-visible:ring-ring/50",
|
|
697
|
-
listening
|
|
698
|
-
? "border-foreground/40 text-muted-foreground"
|
|
699
|
-
: "border-border/60 hover:bg-muted/50",
|
|
700
|
-
)}
|
|
701
|
-
>
|
|
702
|
-
{listening ? "Press the keys…" : (label ?? "Set a shortcut")}
|
|
703
|
-
</button>
|
|
704
|
-
<SettingNote>
|
|
705
|
-
{bare
|
|
706
|
-
? "Hold Ctrl, Alt or Cmd — a plain key is typing."
|
|
707
|
-
: listening
|
|
708
|
-
? "Esc to keep the one you have."
|
|
709
|
-
: "Only while this tab has focus. Not while you are typing."}
|
|
710
|
-
</SettingNote>
|
|
711
|
-
</div>
|
|
712
|
-
</SettingToggle>
|
|
713
|
-
</SettingGroup>
|
|
714
|
-
);
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
/** Appended to the persona, not replacing it; the voice-assistant rules stay in the server prompt. */
|
|
718
|
-
function Instructions({
|
|
719
|
-
value,
|
|
720
|
-
onSave,
|
|
721
|
-
}: {
|
|
722
|
-
value: string;
|
|
723
|
-
onSave: (systemPrompt: string) => void;
|
|
724
|
-
}) {
|
|
725
|
-
const [draft, setDraft] = useState(value);
|
|
726
|
-
|
|
727
|
-
return (
|
|
728
|
-
<SettingGroup
|
|
729
|
-
label="Instructions"
|
|
730
|
-
right={`${draft.length}/${COMMON_VALIDATE.prompt.max}`}
|
|
731
|
-
>
|
|
732
|
-
<div className="space-y-3">
|
|
733
|
-
<Textarea
|
|
734
|
-
value={draft}
|
|
735
|
-
maxLength={COMMON_VALIDATE.prompt.max}
|
|
736
|
-
onChange={(event) => setDraft(event.target.value)}
|
|
737
|
-
placeholder="Anything else she should know before the first word — how to address you, what to skip."
|
|
738
|
-
className="min-h-28"
|
|
1013
|
+
<div className="min-w-0 space-y-3 p-4">
|
|
1014
|
+
<TileHead label="Shortcut">
|
|
1015
|
+
<Switch
|
|
1016
|
+
aria-label="Answer to a key"
|
|
1017
|
+
checked={value.enabled}
|
|
1018
|
+
onCheckedChange={(enabled) => onChange({ ...value, enabled })}
|
|
739
1019
|
/>
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
1020
|
+
</TileHead>
|
|
1021
|
+
<button
|
|
1022
|
+
type="button"
|
|
1023
|
+
{...HOTKEY_CAPTURE}
|
|
1024
|
+
disabled={!value.enabled}
|
|
1025
|
+
onClick={() => {
|
|
1026
|
+
setBare(false);
|
|
1027
|
+
setListening(true);
|
|
1028
|
+
}}
|
|
1029
|
+
onBlur={() => setListening(false)}
|
|
1030
|
+
onKeyDown={listening ? record : undefined}
|
|
1031
|
+
className={cn(
|
|
1032
|
+
"flex h-8 w-full items-center justify-center rounded-lg border px-3 font-mono text-sm outline-none transition-colors focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50",
|
|
1033
|
+
listening
|
|
1034
|
+
? "border-foreground/40 text-muted-foreground"
|
|
1035
|
+
: "border-border/60 hover:bg-muted/50",
|
|
1036
|
+
)}
|
|
1037
|
+
>
|
|
1038
|
+
{listening ? "Press the keys…" : (label ?? "Set a shortcut")}
|
|
1039
|
+
</button>
|
|
1040
|
+
<SettingNote>
|
|
1041
|
+
{bare
|
|
1042
|
+
? "Hold Ctrl, Alt or Cmd — a plain key is typing."
|
|
1043
|
+
: listening
|
|
1044
|
+
? "Esc to keep the one you have."
|
|
1045
|
+
: value.enabled
|
|
1046
|
+
? "Only while this tab has focus. Not while you are typing."
|
|
1047
|
+
: "Starts a call, and ends the one that is running."}
|
|
1048
|
+
</SettingNote>
|
|
1049
|
+
</div>
|
|
751
1050
|
);
|
|
752
1051
|
}
|