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
package/features/bot/bot.run.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type FinishReason,
|
|
3
3
|
generateText,
|
|
4
|
-
hasToolCall,
|
|
5
4
|
type LanguageModel,
|
|
6
5
|
type LanguageModelUsage,
|
|
7
6
|
type ModelMessage,
|
|
8
7
|
type PrepareStepResult,
|
|
8
|
+
type ProviderMetadata,
|
|
9
9
|
pruneMessages,
|
|
10
|
-
type StepResult,
|
|
11
10
|
stepCountIs,
|
|
12
11
|
ToolLoopAgent,
|
|
13
12
|
type ToolSet,
|
|
@@ -18,57 +17,43 @@ import { loadTools } from "@/features/ai/load-tools";
|
|
|
18
17
|
import {
|
|
19
18
|
compactBudget,
|
|
20
19
|
getTextModel,
|
|
21
|
-
|
|
20
|
+
isContextOverflow,
|
|
21
|
+
isProviderRefusal,
|
|
22
22
|
modelErrorToString,
|
|
23
|
-
modelFailureOf,
|
|
24
23
|
resolveDefaultModel,
|
|
25
24
|
} from "@/features/ai/model";
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
chainOf,
|
|
29
|
-
loadBotPrompt,
|
|
30
|
-
} from "@/features/ai/prompts/bot.prompt";
|
|
31
|
-
import {
|
|
32
|
-
answerAccepted,
|
|
33
|
-
askBackSpec,
|
|
34
|
-
askBotSpec,
|
|
35
|
-
} from "@/features/ai/tools/bot.tool";
|
|
25
|
+
import { loadBotPrompt } from "@/features/ai/prompts/bot.prompt";
|
|
26
|
+
import { sendMessageSpec } from "@/features/ai/tools/bot.tool";
|
|
36
27
|
import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
|
|
37
28
|
import {
|
|
38
29
|
COMPACT_AT_MIN,
|
|
39
30
|
type JobBot,
|
|
40
|
-
NO_TOKENS,
|
|
41
31
|
type TokenUsage,
|
|
42
32
|
} from "@/features/bot/bot.schema";
|
|
43
33
|
import {
|
|
44
|
-
|
|
34
|
+
botBrowserSession,
|
|
45
35
|
filesOnDisk,
|
|
46
|
-
|
|
36
|
+
openBotFolders,
|
|
47
37
|
openJobScratch,
|
|
48
38
|
} from "@/features/workspace/workspace";
|
|
49
39
|
import { logger } from "@/lib/logger";
|
|
50
|
-
import { publicError } from "@/lib/public-error";
|
|
51
40
|
import { estimateTokens } from "@/lib/tokens";
|
|
52
41
|
import { findJobBot } from "./bot.query";
|
|
53
|
-
import {
|
|
54
|
-
findTask,
|
|
55
|
-
listWrittenPaths,
|
|
56
|
-
optionsOf,
|
|
57
|
-
writtenPathsIn,
|
|
58
|
-
} from "./task.query";
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* The bot loop behind `delegate`: one model with its own prompt, tools and
|
|
62
|
-
* context. Only the `answer` reaches Thursday; every event goes through
|
|
63
|
-
* `emit` and the runner (bot.runner) writes it to the task's thread.
|
|
64
|
-
*/
|
|
42
|
+
import { findThread, listWrittenPaths, writtenPathsIn } from "./thread.query";
|
|
65
43
|
|
|
66
|
-
/**
|
|
44
|
+
/** Events from one participant turn; the runner persists them in that participant's transcript. */
|
|
67
45
|
export type BotEvent =
|
|
68
46
|
/** A finished chunk of prose. */
|
|
69
47
|
| { type: "text"; text: string }
|
|
70
48
|
/** A tool call. `id` is where the result lands. */
|
|
71
|
-
| {
|
|
49
|
+
| {
|
|
50
|
+
type: "tool";
|
|
51
|
+
id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
input: unknown;
|
|
54
|
+
providerExecuted?: boolean;
|
|
55
|
+
providerOptions?: ProviderMetadata;
|
|
56
|
+
}
|
|
72
57
|
| {
|
|
73
58
|
type: "tool-result";
|
|
74
59
|
id: string;
|
|
@@ -99,211 +84,169 @@ export type BotEvent =
|
|
|
99
84
|
messages: number;
|
|
100
85
|
tokens: number;
|
|
101
86
|
}
|
|
102
|
-
/**
|
|
103
|
-
| { type: "
|
|
104
|
-
/** This bot answered a borrowed bot's `ask_back` (answerBack). No row of its own; `usage` is charged to the job. */
|
|
105
|
-
| { type: "answered"; question: string; text: string; usage: TokenUsage }
|
|
106
|
-
/**
|
|
107
|
-
* Stopped for an answer. `id` is the `ask_thursday` call the answer becomes
|
|
108
|
-
* the result of; null when asking whether to continue, then the answer is a
|
|
109
|
-
* fresh user turn.
|
|
110
|
-
*/
|
|
111
|
-
| { type: "waiting"; id: string | null; question: string; options: string[] }
|
|
87
|
+
/** Normal turn end; interruption is a runtime fact, separate from room completion. */
|
|
88
|
+
| { type: "turn-end"; text: string; stopped: boolean }
|
|
112
89
|
/**
|
|
113
|
-
* The
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* A stopped job waits to be continued; any other answer ends it.
|
|
90
|
+
* The run broke, in words a person can act on; `budget` is where to compact next
|
|
91
|
+
* time, when the model refused the context as too long; `retry` whether another try
|
|
92
|
+
* may pass (config BOT_RUN.retryMs), false when only a person can change the outcome.
|
|
117
93
|
*/
|
|
118
|
-
| { type: "
|
|
119
|
-
/**
|
|
120
|
-
* The run broke. `failure` is whose it is to fix (model.ts modelFailureOf) — a
|
|
121
|
-
* retry's, a compaction's, or a person's — and `budget` where to compact next
|
|
122
|
-
* time, when the model refused the context as too long.
|
|
123
|
-
*/
|
|
124
|
-
| {
|
|
125
|
-
type: "error";
|
|
126
|
-
message: string;
|
|
127
|
-
failure: ModelFailure;
|
|
128
|
-
budget?: number;
|
|
129
|
-
};
|
|
94
|
+
| { type: "error"; message: string; budget?: number; retry: boolean };
|
|
130
95
|
|
|
131
|
-
/** The event as the thread sees it: which
|
|
132
|
-
export type
|
|
96
|
+
/** The event as the thread sees it: which participant and continuation. */
|
|
97
|
+
export type ThreadEvent = BotEvent & { bot: string; parent: string | null };
|
|
133
98
|
|
|
134
99
|
export type RunOptions = {
|
|
135
100
|
signal?: AbortSignal;
|
|
136
|
-
depth?: number;
|
|
137
|
-
/** The `ask_bot` call this run answers; null for the job's own bot. */
|
|
138
101
|
parent?: string | null;
|
|
139
|
-
|
|
140
|
-
* The job this runs inside, for every seat on it — a borrowed bot's too. Its row
|
|
141
|
-
* names the one folder they all work in (workspace.ts jobScratch).
|
|
142
|
-
*/
|
|
143
|
-
taskId?: string | null;
|
|
144
|
-
/**
|
|
145
|
-
* The browser session this seat's shell drives (workspace.ts jobShellEnv): the
|
|
146
|
-
* job's own when unset, a borrowed bot's under its call, so two seats never click
|
|
147
|
-
* in one window.
|
|
148
|
-
*/
|
|
102
|
+
threadId?: string | null;
|
|
149
103
|
session?: string | null;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
104
|
+
caller: string;
|
|
105
|
+
owner: string;
|
|
106
|
+
contextBudget?: number;
|
|
107
|
+
notes?: () => Promise<string[]>;
|
|
108
|
+
send: (input: {
|
|
109
|
+
id: string;
|
|
110
|
+
to: string;
|
|
111
|
+
text: string;
|
|
112
|
+
kind?: "message" | "question";
|
|
113
|
+
options?: string[] | null;
|
|
114
|
+
replyTo?: string | null;
|
|
115
|
+
}) => Promise<unknown>;
|
|
116
|
+
emit: (event: ThreadEvent) => Promise<void>;
|
|
158
117
|
};
|
|
159
118
|
|
|
160
|
-
/**
|
|
161
|
-
* At the step cap the last step is forced to `answer` (lastStep) and the job goes
|
|
162
|
-
* to `waiting`. The context budget is the model's own window where that can be
|
|
163
|
-
* known (model.ts compactBudget); past it the run compacts and carries on from
|
|
164
|
-
* the summary.
|
|
165
|
-
*/
|
|
166
119
|
const MAX_STEPS = BOT_RUN.steps;
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Where a run starts: a job's thread (the opening message first time, past
|
|
170
|
-
* stretches plus new turns on resume), or an `ask_bot` brief plus `context`
|
|
171
|
-
* from the asking bot (`askedBy`).
|
|
172
|
-
*/
|
|
173
|
-
export type RunInput =
|
|
174
|
-
| { bot: string; messages: ModelMessage[] }
|
|
175
|
-
| {
|
|
176
|
-
bot: string;
|
|
177
|
-
request: string;
|
|
178
|
-
context?: string | null;
|
|
179
|
-
askedBy: string;
|
|
180
|
-
/** What the borrowing bot inherited, handed down under the part (bot.prompt buildHandoff). */
|
|
181
|
-
chain: string;
|
|
182
|
-
/** Every bot above this one on the job, the holder first; `askedBy` is the last. */
|
|
183
|
-
above: string[];
|
|
184
|
-
};
|
|
120
|
+
export type RunInput = { bot: string; messages: ModelMessage[] };
|
|
185
121
|
|
|
186
122
|
export async function runBot(
|
|
187
123
|
input: RunInput,
|
|
188
124
|
options: RunOptions,
|
|
189
125
|
): Promise<void> {
|
|
190
|
-
const depth = options.depth ?? 0;
|
|
191
126
|
const parent = options.parent ?? null;
|
|
192
|
-
const
|
|
127
|
+
const bot = await findJobBot(input.bot.trim());
|
|
128
|
+
const name = bot?.name ?? input.bot.trim();
|
|
193
129
|
const emit = (event: BotEvent) =>
|
|
194
130
|
options.emit({ ...event, bot: name, parent });
|
|
195
131
|
|
|
196
|
-
const bot = await findJobBot(name);
|
|
197
132
|
if (!bot) {
|
|
198
133
|
await emit({
|
|
199
134
|
type: "error",
|
|
200
135
|
message: `No bot named "${input.bot}". Use a name from the list.`,
|
|
201
|
-
|
|
202
|
-
});
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
// Switched off is not a bot to pick — the backstop for every fresh start
|
|
206
|
-
// (`delegate`, `ask_bot`, the screen). A resume carries `messages` instead and
|
|
207
|
-
// is let through: its thread already exists and the user can still answer it.
|
|
208
|
-
if (bot.disabled && "request" in input) {
|
|
209
|
-
await emit({
|
|
210
|
-
type: "error",
|
|
211
|
-
message: `${bot.name} is switched off. Use a name from the list.`,
|
|
212
|
-
failure: "fatal",
|
|
136
|
+
retry: false,
|
|
213
137
|
});
|
|
214
138
|
return;
|
|
215
139
|
}
|
|
140
|
+
const history = input.messages;
|
|
216
141
|
|
|
217
142
|
// Tools are built on the model: web search runs on this bot's model (load-tools).
|
|
218
143
|
const model = await resolveModel(bot);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
144
|
+
const row = options.threadId ? await findThread(options.threadId) : null;
|
|
145
|
+
// Participants share thread files while retaining their own context and browser.
|
|
146
|
+
const [scratch, { own, artifacts }] = await Promise.all([
|
|
147
|
+
options.threadId
|
|
148
|
+
? openJobScratch(options.threadId, row?.label ?? "job")
|
|
149
|
+
: null,
|
|
150
|
+
openBotFolders(name),
|
|
226
151
|
]);
|
|
227
152
|
const [prompt, tools] = await Promise.all([
|
|
228
153
|
loadBotPrompt(
|
|
229
154
|
name,
|
|
230
155
|
bot.systemPrompt,
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
askedBy: input.askedBy,
|
|
234
|
-
above: input.above,
|
|
235
|
-
canBorrow: depth < BOT_RUN.depth,
|
|
236
|
-
}
|
|
237
|
-
: null,
|
|
238
|
-
{ scratch, own },
|
|
156
|
+
{ owner: options.owner, caller: options.caller, messageId: parent },
|
|
157
|
+
{ scratch, own, artifacts },
|
|
239
158
|
),
|
|
240
159
|
loadTools({
|
|
241
160
|
target: "bot",
|
|
242
161
|
bot: name,
|
|
243
|
-
|
|
244
|
-
|
|
162
|
+
session:
|
|
163
|
+
options.session ??
|
|
164
|
+
(options.threadId ? botBrowserSession(options.threadId, name) : null),
|
|
245
165
|
model,
|
|
246
166
|
}),
|
|
247
167
|
]);
|
|
248
168
|
// What the owner set, else the model's own window, else the constant (model.ts
|
|
249
|
-
// compactBudget), and never above where this
|
|
250
|
-
// refused as too long lowers
|
|
251
|
-
//
|
|
169
|
+
// compactBudget), and never above where this participant last fit: a context the
|
|
170
|
+
// model refused as too long lowers its own number (room.query
|
|
171
|
+
// lowerRoomContextBudget). The thread row's budget only draws the meter.
|
|
252
172
|
const budget = Math.min(
|
|
253
173
|
await compactBudget(model.ref, bot.compactAt),
|
|
254
|
-
|
|
174
|
+
options.contextBudget || Number.POSITIVE_INFINITY,
|
|
255
175
|
);
|
|
256
176
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
// A borrowed bot asks back instead of asking Thursday. Any seat above the
|
|
275
|
-
// depth limit may borrow in turn, handing down the chain it was handed.
|
|
276
|
-
const seatTools =
|
|
277
|
-
"askedBy" in input ? withAskBack(tools, asks, options) : tools;
|
|
278
|
-
const agentTools =
|
|
279
|
-
depth < BOT_RUN.depth
|
|
280
|
-
? withAskBot(seatTools, {
|
|
281
|
-
name,
|
|
282
|
-
model: model.model,
|
|
283
|
-
instructions: prompt.text,
|
|
284
|
-
peers: prompt.peers,
|
|
285
|
-
depth,
|
|
286
|
-
chain: chainOf(history[0]),
|
|
287
|
-
above: "askedBy" in input ? input.above : [],
|
|
288
|
-
options,
|
|
289
|
-
emit,
|
|
290
|
-
})
|
|
291
|
-
: seatTools;
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* A compaction decided in `prepareStep` is emitted from the loop at
|
|
295
|
-
* `start-step`, not from the callback: the sdk prepares step N+1 while the
|
|
296
|
-
* loop may still be reading step N, and the row must sit between the two
|
|
297
|
-
* steps (that position is what a resume restarts from, task.query listThread).
|
|
298
|
-
*/
|
|
299
|
-
const pending: {
|
|
300
|
-
compact: Extract<BotEvent, { type: "compact" }> | null;
|
|
301
|
-
/** Emitted at the same place, after the compaction. */
|
|
302
|
-
interjections: string[];
|
|
303
|
-
} = { compact: null, interjections: [] };
|
|
304
|
-
|
|
305
|
-
/** Stops the stream when the model goes quiet (config BOT_RUN.silenceMs). */
|
|
177
|
+
// A committed question to the user ends the turn; the answer brings the bot back (room.query tellRoom).
|
|
178
|
+
let asked = false;
|
|
179
|
+
const agentTools: ToolSet = {
|
|
180
|
+
...tools,
|
|
181
|
+
[TOOL_NAMES.send_message]: tool({
|
|
182
|
+
description: sendMessageSpec.description,
|
|
183
|
+
inputSchema: sendMessageSpec.parameters,
|
|
184
|
+
execute: async (input, call) => {
|
|
185
|
+
const receipt = await options.send({ ...input, id: call.toolCallId });
|
|
186
|
+
if (input.kind === "question") asked = true;
|
|
187
|
+
return receipt;
|
|
188
|
+
},
|
|
189
|
+
}),
|
|
190
|
+
};
|
|
191
|
+
// Persist local calls before their side effects, and results before another model step.
|
|
192
|
+
// The stream can repeat these events; the writer deduplicates them by call ID.
|
|
193
|
+
const inFlight = new Set<Promise<unknown>>();
|
|
306
194
|
const quiet = silenceWatch(BOT_RUN.silenceMs);
|
|
195
|
+
for (const [toolName, held] of Object.entries(agentTools)) {
|
|
196
|
+
const execute = held.execute;
|
|
197
|
+
if (!execute) continue;
|
|
198
|
+
held.execute = (args, call) => {
|
|
199
|
+
const execution = (async () => {
|
|
200
|
+
options.signal?.throwIfAborted();
|
|
201
|
+
await emit({
|
|
202
|
+
type: "tool",
|
|
203
|
+
id: call.toolCallId,
|
|
204
|
+
name: toolName,
|
|
205
|
+
input: args,
|
|
206
|
+
});
|
|
207
|
+
quiet.hold();
|
|
208
|
+
try {
|
|
209
|
+
options.signal?.throwIfAborted();
|
|
210
|
+
let output = await execute(args, call);
|
|
211
|
+
if (
|
|
212
|
+
output &&
|
|
213
|
+
typeof output === "object" &&
|
|
214
|
+
Symbol.asyncIterator in output
|
|
215
|
+
) {
|
|
216
|
+
let last: unknown;
|
|
217
|
+
for await (const value of output as AsyncIterable<unknown>)
|
|
218
|
+
last = value;
|
|
219
|
+
output = last;
|
|
220
|
+
}
|
|
221
|
+
await emit({
|
|
222
|
+
type: "tool-result",
|
|
223
|
+
id: call.toolCallId,
|
|
224
|
+
name: toolName,
|
|
225
|
+
output,
|
|
226
|
+
});
|
|
227
|
+
return output;
|
|
228
|
+
} catch (cause) {
|
|
229
|
+
await emit({
|
|
230
|
+
type: "tool-result",
|
|
231
|
+
id: call.toolCallId,
|
|
232
|
+
name: toolName,
|
|
233
|
+
output: modelErrorToString(cause),
|
|
234
|
+
error: true,
|
|
235
|
+
});
|
|
236
|
+
throw cause;
|
|
237
|
+
} finally {
|
|
238
|
+
quiet.release();
|
|
239
|
+
}
|
|
240
|
+
})();
|
|
241
|
+
inFlight.add(execution);
|
|
242
|
+
void execution.finally(() => inFlight.delete(execution)).catch(() => {});
|
|
243
|
+
return execution;
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// The SDK can prepare the next step before the consumer has stored this one.
|
|
248
|
+
let writtenStep: Promise<void> = Promise.resolve();
|
|
249
|
+
let acknowledgeStep = () => {};
|
|
307
250
|
/** Context size the latest step went out at; an overflow shrinks the budget from it. */
|
|
308
251
|
let sent = 0;
|
|
309
252
|
|
|
@@ -311,26 +254,11 @@ export async function runBot(
|
|
|
311
254
|
model: model.model,
|
|
312
255
|
instructions: prompt.text,
|
|
313
256
|
tools: agentTools,
|
|
314
|
-
|
|
315
|
-
// forced to answer). A refused answer does not end it. `ask_thursday` has
|
|
316
|
-
// no execute, but invalid arguments come back as a tool-error and the loop
|
|
317
|
-
// would go on, so the stop is on the call itself.
|
|
318
|
-
stopWhen: [
|
|
319
|
-
stepCountIs(MAX_STEPS),
|
|
320
|
-
answerAccepted_,
|
|
321
|
-
hasToolCall(TOOL_NAMES.ask_thursday),
|
|
322
|
-
],
|
|
257
|
+
stopWhen: [stepCountIs(MAX_STEPS), () => asked],
|
|
323
258
|
prepareStep: async ({ stepNumber, steps, messages }) => {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
step = {
|
|
328
|
-
...step,
|
|
329
|
-
activeTools: Object.keys(agentTools).filter(
|
|
330
|
-
(held) => held !== TOOL_NAMES.ask_back,
|
|
331
|
-
),
|
|
332
|
-
};
|
|
333
|
-
}
|
|
259
|
+
await writtenStep;
|
|
260
|
+
options.signal?.throwIfAborted();
|
|
261
|
+
const step: NonNullable<PrepareStepResult<ToolSet>> = {};
|
|
334
262
|
// The provider's input count includes instructions and tool schemas the
|
|
335
263
|
// estimate cannot see; the estimate covers a provider that reports none.
|
|
336
264
|
const measured = steps.at(-1)?.usage.inputTokens ?? 0;
|
|
@@ -351,21 +279,20 @@ export async function runBot(
|
|
|
351
279
|
);
|
|
352
280
|
// Which files the job has is read off its rows and the disk, never asked of the model
|
|
353
281
|
const text = `${summary.text}${await filesUnder(row?.id ?? null, messages, scratch)}`;
|
|
354
|
-
|
|
282
|
+
await emit({
|
|
355
283
|
type: "compact",
|
|
356
284
|
text,
|
|
357
285
|
usage: summary.usage,
|
|
358
286
|
messages: messages.length,
|
|
359
287
|
tokens: size,
|
|
360
|
-
};
|
|
288
|
+
});
|
|
361
289
|
next = [messages[0], { role: "user", content: text }];
|
|
362
290
|
}
|
|
363
291
|
|
|
364
292
|
// Notes said during the last step go in as user turns after everything
|
|
365
293
|
// the model has (and after the summary). Not on the first step.
|
|
366
|
-
const notes = stepNumber > 0 ? (options.notes?.() ?? []) : [];
|
|
294
|
+
const notes = stepNumber > 0 ? ((await options.notes?.()) ?? []) : [];
|
|
367
295
|
if (notes.length) {
|
|
368
|
-
pending.interjections.push(...notes);
|
|
369
296
|
next = [
|
|
370
297
|
...next,
|
|
371
298
|
...notes.map((text) => ({ role: "user" as const, content: text })),
|
|
@@ -387,62 +314,74 @@ export async function runBot(
|
|
|
387
314
|
? AbortSignal.any([options.signal, quiet.signal])
|
|
388
315
|
: quiet.signal;
|
|
389
316
|
quiet.touch();
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
317
|
+
const execution = new AbortController();
|
|
318
|
+
const signal = AbortSignal.any([stop, execution.signal]);
|
|
319
|
+
let result;
|
|
320
|
+
try {
|
|
321
|
+
result = await agent.stream({
|
|
322
|
+
messages: history,
|
|
323
|
+
abortSignal: signal,
|
|
324
|
+
onStepEnd: (step) => {
|
|
325
|
+
writtenStep = new Promise<void>((resolve) => {
|
|
326
|
+
acknowledgeStep = resolve;
|
|
327
|
+
});
|
|
328
|
+
steps.push({
|
|
329
|
+
messages: step.response.messages,
|
|
330
|
+
usage: usageOf(step.usage),
|
|
331
|
+
});
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
} catch (cause) {
|
|
335
|
+
quiet.end();
|
|
336
|
+
execution.abort();
|
|
337
|
+
await Promise.allSettled([...inFlight]);
|
|
338
|
+
throw cause;
|
|
339
|
+
}
|
|
399
340
|
|
|
400
341
|
let writing = "";
|
|
401
|
-
/**
|
|
402
|
-
let last
|
|
403
|
-
/** The `ask_thursday` call the loop stopped on. */
|
|
404
|
-
let asked: { id: string; question: string; options: string[] } | null = null;
|
|
405
|
-
/** The answer (bot.tool answerSpec). */
|
|
406
|
-
let answered: { text: string; stopped: boolean } | null = null;
|
|
407
|
-
/** Index of the step being read; `lastStep` narrows the one at MAX_STEPS - 1. */
|
|
408
|
-
let stepAt = -1;
|
|
342
|
+
/** Only prose from the final step is returned to the correspondent. */
|
|
343
|
+
let last = "";
|
|
409
344
|
/** Why the latest step ended; prose cut off at the output limit is not an answer. */
|
|
410
345
|
let finish: FinishReason | null = null;
|
|
411
|
-
/** Tool calls still running: the model is not expected to send anything meanwhile. */
|
|
412
|
-
const working = new Set<string>();
|
|
413
346
|
|
|
414
|
-
/**
|
|
347
|
+
/**
|
|
348
|
+
* Every way the stream breaks, as the runner takes it: the words for the row, and
|
|
349
|
+
* where to compact next time when the context was refused as too long. The row
|
|
350
|
+
* keeps only the words, so the whole cause is logged here.
|
|
351
|
+
*/
|
|
415
352
|
const failed = (cause: unknown): Extract<BotEvent, { type: "error" }> => {
|
|
416
|
-
|
|
353
|
+
logger.error(`${name}: the model run broke`, cause);
|
|
417
354
|
const message = modelErrorToString(cause);
|
|
418
|
-
|
|
355
|
+
const retry = !isProviderRefusal(cause);
|
|
356
|
+
if (!isContextOverflow(cause)) return { type: "error", message, retry };
|
|
419
357
|
const shrunk = Math.floor(
|
|
420
358
|
Math.min(budget, sent || budget) * BOT_RUN.overflowShrink,
|
|
421
359
|
);
|
|
422
360
|
return {
|
|
423
361
|
type: "error",
|
|
424
362
|
message,
|
|
425
|
-
failure,
|
|
426
363
|
budget: Math.max(COMPACT_AT_MIN, shrunk),
|
|
364
|
+
retry,
|
|
427
365
|
};
|
|
428
366
|
};
|
|
429
367
|
|
|
430
368
|
// An abort ends the stream without a finish; release any waiting take.
|
|
431
|
-
stop.addEventListener(
|
|
369
|
+
stop.addEventListener(
|
|
370
|
+
"abort",
|
|
371
|
+
() => {
|
|
372
|
+
steps.end();
|
|
373
|
+
acknowledgeStep();
|
|
374
|
+
},
|
|
375
|
+
{ once: true },
|
|
376
|
+
);
|
|
432
377
|
try {
|
|
433
378
|
for await (const part of result.fullStream) {
|
|
434
379
|
// Anything at all is the model still there
|
|
435
380
|
quiet.touch();
|
|
436
381
|
switch (part.type) {
|
|
437
382
|
case "start-step":
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
await emit(pending.compact);
|
|
441
|
-
pending.compact = null;
|
|
442
|
-
}
|
|
443
|
-
for (const text of pending.interjections.splice(0)) {
|
|
444
|
-
await emit({ type: "interjection", text });
|
|
445
|
-
}
|
|
383
|
+
last = "";
|
|
384
|
+
writing = "";
|
|
446
385
|
break;
|
|
447
386
|
|
|
448
387
|
case "text-delta":
|
|
@@ -453,62 +392,24 @@ export async function runBot(
|
|
|
453
392
|
const text = writing.trim();
|
|
454
393
|
writing = "";
|
|
455
394
|
if (!text) break;
|
|
456
|
-
last = text;
|
|
395
|
+
last = [last, text].filter(Boolean).join("\n\n");
|
|
457
396
|
await emit({ type: "text", text });
|
|
458
397
|
break;
|
|
459
398
|
}
|
|
460
399
|
|
|
461
400
|
case "tool-call": {
|
|
462
|
-
if (part.toolName === TOOL_NAMES.ask_thursday) {
|
|
463
|
-
const args = part.input as {
|
|
464
|
-
question?: unknown;
|
|
465
|
-
options?: unknown;
|
|
466
|
-
};
|
|
467
|
-
asked = {
|
|
468
|
-
id: part.toolCallId,
|
|
469
|
-
question: String(args.question ?? ""),
|
|
470
|
-
options: optionsOf(args.options),
|
|
471
|
-
};
|
|
472
|
-
} else if (part.toolName === TOOL_NAMES.answer) {
|
|
473
|
-
const args = part.input as { result?: unknown };
|
|
474
|
-
answered = {
|
|
475
|
-
text: String(args.result ?? "").trim(),
|
|
476
|
-
// The last step offers nothing but `answer`: an answer there is the cap's doing
|
|
477
|
-
stopped: stepAt >= MAX_STEPS - 1,
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
// A tool at work sends nothing, and bounds itself (bash, connected
|
|
481
|
-
// tools, a borrowed bot's own watch); `ask_thursday` never runs
|
|
482
|
-
if (
|
|
483
|
-
!part.providerExecuted &&
|
|
484
|
-
part.toolName !== TOOL_NAMES.ask_thursday
|
|
485
|
-
) {
|
|
486
|
-
working.add(part.toolCallId);
|
|
487
|
-
quiet.hold();
|
|
488
|
-
}
|
|
489
401
|
await emit({
|
|
490
402
|
type: "tool",
|
|
491
403
|
id: part.toolCallId,
|
|
492
404
|
name: part.toolName,
|
|
493
405
|
input: part.input,
|
|
406
|
+
providerExecuted: part.providerExecuted,
|
|
407
|
+
providerOptions: part.providerMetadata,
|
|
494
408
|
});
|
|
495
409
|
break;
|
|
496
410
|
}
|
|
497
411
|
|
|
498
412
|
case "tool-result":
|
|
499
|
-
if (working.delete(part.toolCallId)) quiet.release();
|
|
500
|
-
// A refused answer is not the ending, unless the step cap ends the run
|
|
501
|
-
// on this step; then the text still reaches the user, as a stop.
|
|
502
|
-
if (
|
|
503
|
-
part.toolName === TOOL_NAMES.answer &&
|
|
504
|
-
answered &&
|
|
505
|
-
!answerAccepted(part.output)
|
|
506
|
-
) {
|
|
507
|
-
answered = {
|
|
508
|
-
text: `${answered.text}\n\n${outputText(part.output)}`,
|
|
509
|
-
stopped: true,
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
413
|
// A provider-executed tool (web search) lands here too; the step's own
|
|
513
414
|
// messages decide where it belongs (bot.runner).
|
|
514
415
|
await emit({
|
|
@@ -520,7 +421,6 @@ export async function runBot(
|
|
|
520
421
|
break;
|
|
521
422
|
|
|
522
423
|
case "tool-error":
|
|
523
|
-
if (working.delete(part.toolCallId)) quiet.release();
|
|
524
424
|
// The model reads it and carries on; the row shows it now rather than
|
|
525
425
|
// when the step ends
|
|
526
426
|
await emit({
|
|
@@ -536,18 +436,16 @@ export async function runBot(
|
|
|
536
436
|
finish = part.finishReason;
|
|
537
437
|
const step = await steps.take();
|
|
538
438
|
if (step) await emit({ type: "step", ...step, budget });
|
|
439
|
+
acknowledgeStep();
|
|
539
440
|
break;
|
|
540
441
|
}
|
|
541
442
|
|
|
542
443
|
case "abort":
|
|
543
444
|
// The job was stopped: whoever stopped it writes the row (bot.runner)
|
|
544
445
|
if (options.signal?.aborted) return;
|
|
545
|
-
// Otherwise the model went quiet (silenceWatch)
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
message: part.reason ?? "The model stopped sending.",
|
|
549
|
-
failure: "transient",
|
|
550
|
-
});
|
|
446
|
+
// Otherwise the model went quiet (silenceWatch). The sdk types `reason` as
|
|
447
|
+
// a string but hands over the signal's reason, the watch's DOMException.
|
|
448
|
+
await emit(failed(part.reason ?? "The model stopped sending."));
|
|
551
449
|
return;
|
|
552
450
|
|
|
553
451
|
case "error":
|
|
@@ -559,8 +457,11 @@ export async function runBot(
|
|
|
559
457
|
}
|
|
560
458
|
}
|
|
561
459
|
} finally {
|
|
460
|
+
execution.abort();
|
|
562
461
|
steps.end();
|
|
563
462
|
quiet.end();
|
|
463
|
+
acknowledgeStep();
|
|
464
|
+
await Promise.allSettled([...inFlight]);
|
|
564
465
|
}
|
|
565
466
|
|
|
566
467
|
try {
|
|
@@ -572,59 +473,26 @@ export async function runBot(
|
|
|
572
473
|
return;
|
|
573
474
|
}
|
|
574
475
|
|
|
575
|
-
// Asking wins over answering: the loop halts on the ask.
|
|
576
|
-
if (asked) {
|
|
577
|
-
await emit({ type: "waiting", ...asked });
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
if (answered) {
|
|
582
|
-
await emit({ type: "answer", ...answered });
|
|
583
|
-
return;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
476
|
// The provider's filter stopped the answer: there is nothing to continue past
|
|
587
477
|
if (finish === "content-filter") {
|
|
588
478
|
await emit({
|
|
589
479
|
type: "error",
|
|
590
480
|
message: "The provider's content filter stopped the response.",
|
|
591
|
-
|
|
481
|
+
retry: false,
|
|
592
482
|
});
|
|
593
483
|
return;
|
|
594
484
|
}
|
|
595
485
|
|
|
596
|
-
// The sdk stops on a step with no tool call regardless of `stopWhen`. Prose
|
|
597
|
-
// there is an answer given without the tool and ends the job like one;
|
|
598
|
-
// nothing at all, prose cut off at the output limit, or prose on the step the
|
|
599
|
-
// cap narrowed to `answer`, is a stop — continuing picks up where it broke off.
|
|
600
486
|
await emit({
|
|
601
|
-
type: "
|
|
602
|
-
text: last
|
|
603
|
-
|
|
487
|
+
type: "turn-end",
|
|
488
|
+
text: last,
|
|
489
|
+
// A turn that asked the user ends on its tool call by design, not cut off
|
|
490
|
+
stopped:
|
|
491
|
+
!asked &&
|
|
492
|
+
(finish === "length" || finish === "error" || finish === "tool-calls"),
|
|
604
493
|
});
|
|
605
494
|
}
|
|
606
495
|
|
|
607
|
-
/** The last step ended on an answer the tool accepted. `hasToolCall` would also stop on a refused one. */
|
|
608
|
-
const answerAccepted_ = ({ steps }: { steps: StepResult<ToolSet>[] }) =>
|
|
609
|
-
steps
|
|
610
|
-
.at(-1)
|
|
611
|
-
?.toolResults.some(
|
|
612
|
-
(result) =>
|
|
613
|
-
result.toolName === TOOL_NAMES.answer && answerAccepted(result.output),
|
|
614
|
-
) ?? false;
|
|
615
|
-
|
|
616
|
-
/**
|
|
617
|
-
* The step before the cap is narrowed to `answer` and required to call it,
|
|
618
|
-
* so a run out of budget ends with something a person can act on.
|
|
619
|
-
*/
|
|
620
|
-
function lastStep(stepNumber: number): NonNullable<PrepareStepResult<ToolSet>> {
|
|
621
|
-
if (stepNumber < MAX_STEPS - 1) return {};
|
|
622
|
-
return {
|
|
623
|
-
activeTools: [TOOL_NAMES.answer],
|
|
624
|
-
toolChoice: { type: "tool", toolName: TOOL_NAMES.answer },
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
|
|
628
496
|
/** Rough token weight of a message list. The provider's own count wins when it reports one (prepareStep). */
|
|
629
497
|
function sizeOf(messages: ModelMessage[]): number {
|
|
630
498
|
return messages.reduce(
|
|
@@ -643,11 +511,11 @@ function sizeOf(messages: ModelMessage[]): number {
|
|
|
643
511
|
/** Instructions for compacting. The summary replaces everything above it, opening included, so it must restate the job. */
|
|
644
512
|
const compactInstructions = (
|
|
645
513
|
words: number,
|
|
646
|
-
) => `Compact your context. The first message above —
|
|
514
|
+
) => `Compact your context. The first message above — who handed you the job, and the job — stays exactly as it is. Everything after it is replaced by what you write now, and you carry on from that first message and this alone; nothing else above can be read again. Write it for a fresh copy of you that has your tools, your instructions and that first message, but has seen none of the rest.
|
|
647
515
|
|
|
648
516
|
Cover all of it, and prefer a fact over a description of a fact:
|
|
649
517
|
|
|
650
|
-
- **Where the job stands against that first message.** Do not restate the job
|
|
518
|
+
- **Where the job stands against that first message.** Do not restate the job; say what has changed since — a choice made, a detail settled, an answer that came back, a correction, anything you are still waiting on.
|
|
651
519
|
- **What is already true.** Every value you have — numbers, names, dates, ids, urls, prices, times — written out, not referred to. A value you leave out is one the next steps go and fetch again.
|
|
652
520
|
- **Where you are.** Which page the browser is on by url, whether you are signed in and to what, what is running, what you were in the middle of. Element refs do not survive this: name what to look for, never a ref.
|
|
653
521
|
- **Files.** Every path you wrote or read, and one line on what each holds.
|
|
@@ -672,19 +540,19 @@ const FILES_HEAD =
|
|
|
672
540
|
|
|
673
541
|
/**
|
|
674
542
|
* The files a job has on disk, as lines under its compaction summary. Read off the
|
|
675
|
-
* job's rows — every `write_file
|
|
543
|
+
* job's rows — every participant's `write_file` — and off its folder,
|
|
676
544
|
* never asked of the model: a path a summary leaves out is work the next steps redo.
|
|
677
|
-
*
|
|
545
|
+
* Without a thread, the run reads only the messages it is compacting.
|
|
678
546
|
* A listing that fails costs the list, never the compaction.
|
|
679
547
|
*/
|
|
680
548
|
async function filesUnder(
|
|
681
|
-
|
|
549
|
+
threadId: string | null,
|
|
682
550
|
messages: ModelMessage[],
|
|
683
551
|
folder: string | null,
|
|
684
552
|
): Promise<string> {
|
|
685
553
|
try {
|
|
686
|
-
const written =
|
|
687
|
-
? await listWrittenPaths(
|
|
554
|
+
const written = threadId
|
|
555
|
+
? await listWrittenPaths(threadId)
|
|
688
556
|
: writtenPathsIn(messages.map((message) => message.content));
|
|
689
557
|
const files = await filesOnDisk(written, folder);
|
|
690
558
|
if (!files.length) return "";
|
|
@@ -703,12 +571,11 @@ async function filesUnder(
|
|
|
703
571
|
* The model summarizes its own context and continues from the summary. Tools
|
|
704
572
|
* are passed with calling off: providers refuse a history of tool calls
|
|
705
573
|
* without the tools that made them. The run's own instructions go too: the
|
|
706
|
-
* summary is written by the bot the
|
|
574
|
+
* summary is written by the bot the transcript belongs to, and the provider's
|
|
707
575
|
* cached prefix, instructions first, still matches the run's. A context too
|
|
708
576
|
* long to summarise whole — the very thing a compaction is for — is tried once
|
|
709
577
|
* more without the tool calls and results but the last few. A failure throws
|
|
710
|
-
* with its cause kept
|
|
711
|
-
* fix (bot.runner parkTask) and fails the rest; the thread stays.
|
|
578
|
+
* with its cause kept. The room pauses for manual recovery; the transcript stays.
|
|
712
579
|
*/
|
|
713
580
|
async function compact(
|
|
714
581
|
model: LanguageModel,
|
|
@@ -723,8 +590,8 @@ async function compact(
|
|
|
723
590
|
if (options.signal?.aborted) throw cause;
|
|
724
591
|
failure = cause;
|
|
725
592
|
}
|
|
726
|
-
if (
|
|
727
|
-
// pruneMessages drops a call together with its result, so the
|
|
593
|
+
if (isContextOverflow(failure)) {
|
|
594
|
+
// pruneMessages drops a call together with its result, so the transcript stays whole
|
|
728
595
|
const lighter = pruneMessages({
|
|
729
596
|
messages,
|
|
730
597
|
toolCalls: "before-last-4-messages",
|
|
@@ -800,7 +667,7 @@ function stepQueue() {
|
|
|
800
667
|
/**
|
|
801
668
|
* No more steps are coming; release waiting takes with `null`. Without
|
|
802
669
|
* this, a `finish-step` whose `onStepEnd` never fires (abort, provider
|
|
803
|
-
* error mid-step) parks the loop forever, and `
|
|
670
|
+
* error mid-step) parks the loop forever, and `answerThread` waits on
|
|
804
671
|
* `run.done` while holding the job's lock (bot.runner).
|
|
805
672
|
*/
|
|
806
673
|
end() {
|
|
@@ -815,7 +682,7 @@ function stepQueue() {
|
|
|
815
682
|
* arrived for that long. Held while something other than the model does the
|
|
816
683
|
* work — a tool, a compaction — since those send nothing and bound themselves;
|
|
817
684
|
* `touch` starts it over. Not the sdk's `timeout.chunkMs`: that clock keeps
|
|
818
|
-
* running while tools execute, so a long command
|
|
685
|
+
* running while tools execute, so a long command
|
|
819
686
|
* would trip it.
|
|
820
687
|
*/
|
|
821
688
|
function silenceWatch(ms: number) {
|
|
@@ -869,311 +736,107 @@ function resolveModel(bot: JobBot) {
|
|
|
869
736
|
return resolveDefaultModel().then(getTextModel);
|
|
870
737
|
}
|
|
871
738
|
|
|
872
|
-
/**
|
|
873
|
-
export
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
): Promise<string> {
|
|
877
|
-
let outcome = "";
|
|
878
|
-
let failure: string | null = null;
|
|
879
|
-
await runBot(input, {
|
|
880
|
-
...options,
|
|
881
|
-
emit: async (event) => {
|
|
882
|
-
if (event.type === "answer") {
|
|
883
|
-
outcome = event.stopped
|
|
884
|
-
? `${event.text}\n\n(As far as they got — they stopped before finishing.)`
|
|
885
|
-
: event.text;
|
|
886
|
-
}
|
|
887
|
-
if (event.type === "error") failure = event.message;
|
|
888
|
-
await options.emit(event);
|
|
889
|
-
},
|
|
890
|
-
});
|
|
891
|
-
if (failure) publicError(failure);
|
|
892
|
-
return outcome;
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
/**
|
|
896
|
-
* `ask_bot` gets its execute here, not in loadTools (loadTools importing this
|
|
897
|
-
* file would be a cycle). With no peers the tool is absent rather than refusing.
|
|
898
|
-
* The borrowed bot's events go to the same thread under this call's id, and
|
|
899
|
-
* `answer` serves its `ask_back` from `call.messages`, the context that
|
|
900
|
-
* produced this call. Exchanges ride back inside the result so this thread
|
|
901
|
-
* keeps them.
|
|
902
|
-
*/
|
|
903
|
-
function withAskBot(
|
|
904
|
-
tools: ToolSet,
|
|
905
|
-
asker: {
|
|
906
|
-
name: string;
|
|
907
|
-
model: LanguageModel;
|
|
908
|
-
instructions: string;
|
|
909
|
-
/** Bots it can call; itself excluded (bot.prompt). */
|
|
910
|
-
peers: string[];
|
|
911
|
-
depth: number;
|
|
912
|
-
/** The chain this bot inherited, handed down under the part it hands over. */
|
|
913
|
-
chain: string;
|
|
914
|
-
/** Bots above this one on the job, which are blocked waiting on it. */
|
|
915
|
-
above: string[];
|
|
916
|
-
options: RunOptions;
|
|
917
|
-
emit: (event: BotEvent) => Promise<void>;
|
|
918
|
-
},
|
|
919
|
-
): ToolSet {
|
|
920
|
-
if (asker.peers.length === 0) return tools;
|
|
921
|
-
|
|
922
|
-
const agentTools: ToolSet = {
|
|
923
|
-
...tools,
|
|
924
|
-
[TOOL_NAMES.ask_bot]: tool({
|
|
925
|
-
description: askBotSpec.description,
|
|
926
|
-
inputSchema: askBotSpec.parameters,
|
|
927
|
-
execute: async ({ bot, request, context }, call) => {
|
|
928
|
-
// A bot above is blocked waiting on this very call; borrowing it back never returns
|
|
929
|
-
if (bot === asker.name || asker.above.includes(bot)) {
|
|
930
|
-
return `${bot} is already on this job, above you and waiting on your part. Pick another bot, or do it yourself.`;
|
|
931
|
-
}
|
|
932
|
-
// The borrowed bot works in the job's folder but drives a browser session
|
|
933
|
-
// of its own, under this call's id. When it answers, the same rule as a
|
|
934
|
-
// job's end: what it showed on their screen stays, what nobody can see
|
|
935
|
-
// closes (workspace.ts closeHiddenBrowser).
|
|
936
|
-
const session = asker.options.taskId
|
|
937
|
-
? `${asker.options.session ?? asker.options.taskId}-${call.toolCallId.slice(0, 8)}`
|
|
938
|
-
: null;
|
|
939
|
-
const exchanges: { question: string; answer: string }[] = [];
|
|
940
|
-
const answer = async (question: string) => {
|
|
941
|
-
const reply = await answerBack({
|
|
942
|
-
model: asker.model,
|
|
943
|
-
instructions: asker.instructions,
|
|
944
|
-
// Same tools, calling off (see compact).
|
|
945
|
-
tools: agentTools,
|
|
946
|
-
messages: call.messages,
|
|
947
|
-
asked: { bot, request },
|
|
948
|
-
question,
|
|
949
|
-
signal: asker.options.signal,
|
|
950
|
-
});
|
|
951
|
-
await asker.emit({ type: "answered", question, ...reply });
|
|
952
|
-
exchanges.push({ question, answer: reply.text });
|
|
953
|
-
return reply.text;
|
|
954
|
-
};
|
|
955
|
-
try {
|
|
956
|
-
const outcome = await runBotToText(
|
|
957
|
-
{
|
|
958
|
-
bot,
|
|
959
|
-
request,
|
|
960
|
-
context,
|
|
961
|
-
askedBy: asker.name,
|
|
962
|
-
chain: asker.chain,
|
|
963
|
-
above: [...asker.above, asker.name],
|
|
964
|
-
},
|
|
965
|
-
{
|
|
966
|
-
...asker.options,
|
|
967
|
-
// This call's signal, not the job's: a stream that ends — the job
|
|
968
|
-
// stopping, or the model going quiet — ends the part it waited on
|
|
969
|
-
signal: call.abortSignal ?? asker.options.signal,
|
|
970
|
-
depth: asker.depth + 1,
|
|
971
|
-
parent: call.toolCallId,
|
|
972
|
-
session,
|
|
973
|
-
answer,
|
|
974
|
-
},
|
|
975
|
-
);
|
|
976
|
-
return exchanges.length
|
|
977
|
-
? `${outcome}\n\n${exchangeLines(bot, exchanges)}`
|
|
978
|
-
: outcome;
|
|
979
|
-
} finally {
|
|
980
|
-
if (session) void closeHiddenBrowser(session);
|
|
981
|
-
}
|
|
982
|
-
},
|
|
983
|
-
}),
|
|
984
|
-
};
|
|
985
|
-
return agentTools;
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
/** Appended under the answer: what the borrowed bot asked and what this bot answered. */
|
|
989
|
-
function exchangeLines(
|
|
990
|
-
bot: string,
|
|
991
|
-
exchanges: { question: string; answer: string }[],
|
|
992
|
-
): string {
|
|
993
|
-
return exchanges
|
|
994
|
-
.map(
|
|
995
|
-
({ question, answer }) =>
|
|
996
|
-
`(On the way ${bot} asked you: "${question}" — you answered: "${answer}")`,
|
|
997
|
-
)
|
|
998
|
-
.join("\n");
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
/**
|
|
1002
|
-
* A borrowed bot's tools: `ask_thursday` removed (the bot above is blocked on
|
|
1003
|
-
* this run, so a wait here never resolves), `ask_back` added when there is an
|
|
1004
|
-
* `answer`. prepareStep removes it once `asks.left` reaches zero.
|
|
1005
|
-
*/
|
|
1006
|
-
function withAskBack(
|
|
1007
|
-
tools: ToolSet,
|
|
1008
|
-
asks: { left: number },
|
|
1009
|
-
options: RunOptions,
|
|
1010
|
-
): ToolSet {
|
|
1011
|
-
const own = { ...tools };
|
|
1012
|
-
delete own[TOOL_NAMES.ask_thursday];
|
|
1013
|
-
const { answer } = options;
|
|
1014
|
-
if (!answer) return own;
|
|
1015
|
-
return {
|
|
1016
|
-
...own,
|
|
1017
|
-
[TOOL_NAMES.ask_back]: tool({
|
|
1018
|
-
description: askBackSpec.description,
|
|
1019
|
-
inputSchema: askBackSpec.parameters,
|
|
1020
|
-
execute: async ({ question }) => {
|
|
1021
|
-
asks.left -= 1;
|
|
1022
|
-
return answer(question);
|
|
1023
|
-
},
|
|
1024
|
-
}),
|
|
1025
|
-
};
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
/** Prompt for answering a borrowed bot's `ask_back`. The blocked call is restated because the sdk's `messages` stop just before it. */
|
|
1029
|
-
const answerInstructions = (
|
|
1030
|
-
asked: { bot: string; request: string },
|
|
1031
|
-
question: string,
|
|
1032
|
-
) => `You handed one part of your job to ${asked.bot}:
|
|
1033
|
-
|
|
1034
|
-
> ${asked.request.trim()}
|
|
1035
|
-
|
|
1036
|
-
Before going on, they ask you:
|
|
1037
|
-
|
|
1038
|
-
> ${question.trim()}
|
|
1039
|
-
|
|
1040
|
-
Answer from what you already have — the request as it reached you, the call it came out of, what you found before asking them. A few lines, plain text, and nothing else: no tools run here. If it is not in what you have, say so rather than guess, and say which way to go without it.`;
|
|
1041
|
-
|
|
1042
|
-
/**
|
|
1043
|
-
* One call, no loop: the asking bot's model over its own context plus the
|
|
1044
|
-
* question. A provider failure returns a fallback text instead of throwing;
|
|
1045
|
-
* only an abort propagates.
|
|
1046
|
-
*/
|
|
1047
|
-
async function answerBack(input: {
|
|
1048
|
-
model: LanguageModel;
|
|
1049
|
-
instructions: string;
|
|
1050
|
-
tools: ToolSet;
|
|
1051
|
-
messages: ModelMessage[];
|
|
1052
|
-
asked: { bot: string; request: string };
|
|
1053
|
-
question: string;
|
|
1054
|
-
signal?: AbortSignal;
|
|
1055
|
-
}): Promise<{ text: string; usage: TokenUsage }> {
|
|
1056
|
-
try {
|
|
1057
|
-
const { text, usage } = await generateText({
|
|
1058
|
-
model: input.model,
|
|
1059
|
-
system: input.instructions,
|
|
1060
|
-
tools: input.tools,
|
|
1061
|
-
toolChoice: "none",
|
|
1062
|
-
messages: [
|
|
1063
|
-
...input.messages,
|
|
1064
|
-
{
|
|
1065
|
-
role: "user",
|
|
1066
|
-
content: answerInstructions(input.asked, input.question),
|
|
1067
|
-
},
|
|
1068
|
-
],
|
|
1069
|
-
abortSignal: input.signal,
|
|
1070
|
-
// One-shot: nothing streams back, so its whole length is one silence
|
|
1071
|
-
timeout: BOT_RUN.silenceMs,
|
|
1072
|
-
});
|
|
1073
|
-
return {
|
|
1074
|
-
text:
|
|
1075
|
-
text.trim() ||
|
|
1076
|
-
"They had nothing to add. Go on with your best reading, and say what you assumed in what you hand back.",
|
|
1077
|
-
usage: usageOf(usage),
|
|
1078
|
-
};
|
|
1079
|
-
} catch (cause) {
|
|
1080
|
-
if (input.signal?.aborted) throw cause;
|
|
1081
|
-
logger.warn(`ask_back: ${modelErrorToString(cause)}`);
|
|
1082
|
-
return {
|
|
1083
|
-
text: `No answer came back (${modelErrorToString(cause)}). Go on with your best reading, and say what you assumed in what you hand back.`,
|
|
1084
|
-
usage: NO_TOKENS,
|
|
1085
|
-
};
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
/**
|
|
1090
|
-
* The stored thread as a resuming run reads it: the rows as they were written,
|
|
1091
|
-
* each tool call with its result, so a resumed run carries on the conversation
|
|
1092
|
-
* it was having and a provider's prefix cache still matches from its first call.
|
|
1093
|
-
* The one repair is a call whose result never arrived — the run was stopped
|
|
1094
|
-
* between the two (a closed browser, a restart, a model that went quiet) and a
|
|
1095
|
-
* call with no result is refused outright — which gets one saying so, right
|
|
1096
|
-
* after it. An `ask_bot` call cut off that way carries what the borrowed bot
|
|
1097
|
-
* had written by then, so its part is picked up rather than asked for again
|
|
1098
|
-
* from nothing. Nothing else changes: `compact` is the one thing that shortens
|
|
1099
|
-
* a bot's own thread.
|
|
1100
|
-
*/
|
|
1101
|
-
export function resumeThread(
|
|
1102
|
-
thread: ModelMessage[],
|
|
1103
|
-
/** Borrowed bots' last lines, by `ask_bot` call id (task.query listBorrowedTails). */
|
|
1104
|
-
borrowed: ReadonlyMap<string, { bot: string; tail: string }> = new Map(),
|
|
739
|
+
/** Build a valid model projection without changing the recorded interruption history. */
|
|
740
|
+
export function resumeTranscript(
|
|
741
|
+
transcript: ModelMessage[],
|
|
742
|
+
receipts: ReadonlyMap<string, { messageId: string; to: string }> = new Map(),
|
|
1105
743
|
): ModelMessage[] {
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
744
|
+
type Result = Extract<
|
|
745
|
+
Extract<ModelMessage, { role: "tool" }>["content"][number],
|
|
746
|
+
{ type: "tool-result" }
|
|
747
|
+
>;
|
|
748
|
+
const results = new Map<string, Result>();
|
|
749
|
+
const embedded = new Set<string>();
|
|
750
|
+
for (const message of transcript) {
|
|
1109
751
|
if (message.role !== "tool" && message.role !== "assistant") continue;
|
|
1110
|
-
if (
|
|
752
|
+
if (!Array.isArray(message.content)) continue;
|
|
1111
753
|
for (const part of message.content) {
|
|
1112
|
-
if (part.type
|
|
754
|
+
if (part.type !== "tool-result") continue;
|
|
755
|
+
if (!results.has(part.toolCallId)) results.set(part.toolCallId, part);
|
|
756
|
+
if (message.role === "assistant") embedded.add(part.toolCallId);
|
|
1113
757
|
}
|
|
1114
758
|
}
|
|
1115
|
-
|
|
1116
759
|
const out: ModelMessage[] = [];
|
|
1117
|
-
|
|
1118
|
-
for (const message of
|
|
1119
|
-
if (
|
|
1120
|
-
|
|
1121
|
-
|
|
760
|
+
const used = new Set<string>();
|
|
761
|
+
for (const message of transcript) {
|
|
762
|
+
if (message.role === "tool") {
|
|
763
|
+
const other = message.content.filter(
|
|
764
|
+
(part) => part.type !== "tool-result",
|
|
765
|
+
);
|
|
766
|
+
if (other.length) out.push({ ...message, content: other });
|
|
1122
767
|
continue;
|
|
1123
768
|
}
|
|
1124
|
-
if (owed.length) {
|
|
1125
|
-
out.push({ role: "tool", content: owed });
|
|
1126
|
-
owed = [];
|
|
1127
|
-
}
|
|
1128
|
-
out.push(message);
|
|
1129
769
|
if (message.role !== "assistant" || typeof message.content === "string") {
|
|
770
|
+
out.push(message);
|
|
1130
771
|
continue;
|
|
1131
772
|
}
|
|
1132
|
-
owed =
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
773
|
+
const owed: Result[] = [];
|
|
774
|
+
const content: typeof message.content = [];
|
|
775
|
+
for (const part of message.content) {
|
|
776
|
+
if (part.type !== "tool-call") {
|
|
777
|
+
content.push(part);
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
if (used.has(part.toolCallId)) continue;
|
|
781
|
+
let input = part.input;
|
|
782
|
+
if (typeof input === "string") {
|
|
783
|
+
try {
|
|
784
|
+
input = JSON.parse(input);
|
|
785
|
+
} catch {
|
|
786
|
+
input = undefined;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
if (!part.toolCallId || input === undefined) {
|
|
790
|
+
content.push({
|
|
791
|
+
type: "text",
|
|
792
|
+
text: "A tool argument stream was interrupted before a complete call was recorded. Inspect the saved work before continuing.",
|
|
793
|
+
});
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
const receipt =
|
|
797
|
+
part.toolName === TOOL_NAMES.send_message
|
|
798
|
+
? receipts.get(part.toolCallId)
|
|
799
|
+
: undefined;
|
|
800
|
+
const result =
|
|
801
|
+
results.get(part.toolCallId) ??
|
|
802
|
+
(receipt
|
|
803
|
+
? {
|
|
1136
804
|
type: "tool-result" as const,
|
|
1137
805
|
toolCallId: part.toolCallId,
|
|
1138
806
|
toolName: part.toolName,
|
|
1139
|
-
output: {
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
807
|
+
output: { type: "json" as const, value: receipt },
|
|
808
|
+
}
|
|
809
|
+
: undefined);
|
|
810
|
+
if (
|
|
811
|
+
part.providerExecuted &&
|
|
812
|
+
(!result || !embedded.has(part.toolCallId))
|
|
813
|
+
) {
|
|
814
|
+
content.push({
|
|
815
|
+
type: "text",
|
|
816
|
+
text: result
|
|
817
|
+
? `The provider operation ${part.toolName} returned this data before its native continuation was interrupted: ${JSON.stringify(result.output)}`
|
|
818
|
+
: `The provider operation ${part.toolName} was interrupted without a recorded result. Its remote execution state is unknown.`,
|
|
819
|
+
});
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
used.add(part.toolCallId);
|
|
823
|
+
content.push({ ...part, input });
|
|
824
|
+
if (!embedded.has(part.toolCallId))
|
|
825
|
+
owed.push(
|
|
826
|
+
result ?? {
|
|
827
|
+
type: "tool-result",
|
|
828
|
+
toolCallId: part.toolCallId,
|
|
829
|
+
toolName: part.toolName,
|
|
830
|
+
output: {
|
|
831
|
+
type: "text",
|
|
832
|
+
value:
|
|
833
|
+
"No result: execution was interrupted before a result was recorded. The outcome is unknown. Inspect the current state before repeating the action.",
|
|
1143
834
|
},
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
835
|
+
},
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
if (content.length) out.push({ ...message, content });
|
|
839
|
+
if (owed.length) out.push({ role: "tool", content: owed });
|
|
1147
840
|
}
|
|
1148
|
-
if (owed.length) out.push({ role: "tool", content: owed });
|
|
1149
841
|
return out;
|
|
1150
842
|
}
|
|
1151
|
-
|
|
1152
|
-
/** What a resumed run reads where a call's result never arrived (resumeThread). */
|
|
1153
|
-
const INTERRUPTED =
|
|
1154
|
-
"No result: the run was stopped before this call returned. Check what it did before relying on it.";
|
|
1155
|
-
|
|
1156
|
-
/** INTERRUPTED, or for a borrowed bot's part, what it had written when the run stopped. */
|
|
1157
|
-
function interrupted(
|
|
1158
|
-
call: { toolCallId: string; toolName: string },
|
|
1159
|
-
borrowed: ReadonlyMap<string, { bot: string; tail: string }>,
|
|
1160
|
-
): string {
|
|
1161
|
-
const cut =
|
|
1162
|
-
call.toolName === TOOL_NAMES.ask_bot
|
|
1163
|
-
? borrowed.get(call.toolCallId)
|
|
1164
|
-
: undefined;
|
|
1165
|
-
if (!cut) return INTERRUPTED;
|
|
1166
|
-
return `No result: the run was stopped before ${cut.bot} answered, and they are not working on it any more. What they had written by then:\n\n${cut.tail}\n\nCheck what they did before relying on it, then finish the part yourself or hand them what is left.`;
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
/** Just the text out of the shape a tool result reached the model in (ai-sdk ToolResultOutput). */
|
|
1170
|
-
function outputText(output: unknown): string {
|
|
1171
|
-
if (typeof output === "string") return output;
|
|
1172
|
-
const wrapped = output as { type?: string; value?: unknown } | null;
|
|
1173
|
-
if (wrapped && typeof wrapped === "object" && "value" in wrapped) {
|
|
1174
|
-
return typeof wrapped.value === "string"
|
|
1175
|
-
? wrapped.value
|
|
1176
|
-
: JSON.stringify(wrapped.value ?? "");
|
|
1177
|
-
}
|
|
1178
|
-
return JSON.stringify(output ?? "");
|
|
1179
|
-
}
|