thursday-agent 0.1.2 → 0.3.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 +5 -1
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +5 -5
- package/.next/routes-manifest.json +27 -3
- package/.next/server/app/_global-error/page.js +2 -2
- 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 +2 -2
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js +2 -2
- 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 +14 -14
- package/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- 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 +3 -3
- package/.next/server/app/api/artifact/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/files/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/bot/memory/files/route.js +10 -0
- package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -0
- package/.next/server/app/api/bot/memory/files/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/bot/memory/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/bot/memory/route/build-manifest.json +12 -0
- package/.next/server/app/api/bot/memory/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/bot/memory/route.js +14 -0
- package/.next/server/app/api/bot/memory/route.js.map +5 -0
- package/.next/server/app/api/bot/memory/route.js.nft.json +1 -0
- package/.next/server/app/api/bot/memory/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/bot/route.js +7 -7
- package/.next/server/app/api/bot/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/task/[id]/route.js +9 -9
- package/.next/server/app/api/bot/task/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/task/route.js +8 -8
- package/.next/server/app/api/bot/task/route.js.nft.json +1 -1
- package/.next/server/app/api/config/route.js +6 -6
- package/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/server/app/api/events/route.js +4 -5
- package/.next/server/app/api/events/route.js.nft.json +1 -1
- package/.next/server/app/api/file/[...path]/route.js +3 -3
- package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/catalog/route.js +10 -9
- package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/credits/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/llm-model/credits/route/build-manifest.json +12 -0
- package/.next/server/app/api/llm-model/credits/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/llm-model/credits/route.js +16 -0
- package/.next/server/app/api/llm-model/credits/route.js.map +5 -0
- package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -0
- package/.next/server/app/api/llm-model/credits/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/llm-model/route.js +10 -8
- package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/subscription/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/llm-model/subscription/route/build-manifest.json +12 -0
- package/.next/server/app/api/llm-model/subscription/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/llm-model/subscription/route.js +15 -0
- package/.next/server/app/api/llm-model/subscription/route.js.map +5 -0
- package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -0
- package/.next/server/app/api/llm-model/subscription/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/mcp/[name]/route.js +5 -5
- package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/oauth/callback/route.js +6 -6
- package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/route.js +5 -5
- package/.next/server/app/api/mcp/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/tools/route.js +5 -5
- package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/memory/edit/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/memory/edit/route/build-manifest.json +12 -0
- package/.next/server/app/api/memory/edit/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/memory/edit/route.js +24 -0
- package/.next/server/app/api/memory/edit/route.js.map +5 -0
- package/.next/server/app/api/memory/edit/route.js.nft.json +1 -0
- package/.next/server/app/api/memory/{tidy → edit}/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/memory/route.js +7 -8
- package/.next/server/app/api/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/[source]/[name]/route.js +3 -3
- package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route.js +3 -3
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/call/route.js +9 -7
- package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/skills/route.js +9 -7
- package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/tool-call/route.js +16 -15
- package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
- package/.next/server/app/api/workspace/route.js +4 -5
- package/.next/server/app/api/workspace/route.js.nft.json +1 -1
- package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
- package/.next/server/app/artifact/[...path]/page.js +5 -6
- 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 +3 -4
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/server/app/favicon.ico.body +0 -0
- package/.next/server/app/page/server-reference-manifest.json +66 -77
- package/.next/server/app/page.js +11 -11
- 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 +5 -1
- package/.next/server/chunks/[externals]__0dzuk6_._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0ce8nf8._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0j7z0r3._.js +12 -0
- package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0pa2n68._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0q0vvt2._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__11n256_._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__15bjnu5._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +10 -0
- package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +11 -0
- package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +8 -0
- package/.next/server/chunks/{_1hzrsvg._.js → _0-73of8._.js} +6 -6
- package/.next/server/chunks/{_1cbk7ms._.js → _0-fjql4._.js} +10 -10
- package/.next/server/chunks/_00xh_q0._.js +27 -0
- package/.next/server/chunks/{_0y8is-s._.js → _03a0897._.js} +1 -1
- package/.next/server/chunks/{_0pppbb5._.js → _03kp0jp._.js} +166 -35
- package/.next/server/chunks/_051qh8u._.js +3 -0
- package/.next/server/chunks/{node_modules_next_04q-o58._.js → _05dla15._.js} +2 -2
- package/.next/server/chunks/_05h2cii._.js +1 -1
- package/.next/server/chunks/_0c9j6rb._.js +49 -0
- package/.next/server/chunks/_0fzqt2y._.js +74 -44
- package/.next/server/chunks/{_0kl37zl._.js → _0ioz3nd._.js} +1 -1
- package/.next/server/chunks/_0iwfby5._.js +3 -0
- package/.next/server/chunks/{_0hin38_._.js → _0khihjk._.js} +5 -5
- package/.next/server/chunks/_0mecv0f._.js +26 -0
- package/.next/server/chunks/_0mh8j4m._.js +3 -0
- package/.next/server/chunks/{_1icgbi8._.js → _0n74zsf._.js} +2 -2
- package/.next/server/chunks/_0obojvv._.js +3 -0
- package/.next/server/chunks/_0recufk._.js +49 -0
- package/.next/server/chunks/{_1t8fv7b._.js → _0rnf-6n._.js} +2 -2
- package/.next/server/chunks/_0sb7tlz._.js +3 -0
- package/.next/server/chunks/{_0jgm3b8._.js → _0u10wmw._.js} +6 -6
- package/.next/server/chunks/{_12nr4xc._.js → _0u4aiy2._.js} +2 -2
- package/.next/server/chunks/_0wp4le3._.js +1 -1
- package/.next/server/chunks/_0y5fg-x._.js +1 -1
- package/.next/server/chunks/_1230wbx._.js +10 -0
- package/.next/server/chunks/_12nheja._.js +3 -0
- package/.next/server/chunks/_13510xh._.js +3 -0
- package/.next/server/chunks/_15hq89o._.js +1 -1
- package/.next/server/chunks/_17l5ygt._.js +49 -0
- package/.next/server/chunks/{_0ks6_sg._.js → _18-1wcc._.js} +6 -6
- package/.next/server/chunks/_1_5mnq4._.js +18 -0
- package/.next/server/chunks/{_0tzfesa._.js → _1_9mjx-._.js} +1 -1
- package/.next/server/chunks/_1d0j961._.js +6 -0
- package/.next/server/chunks/_1d5zmy8._.js +1 -1
- package/.next/server/chunks/_1drgfx4._.js +18 -0
- package/.next/server/chunks/{_1skgy7b._.js → _1e48czp._.js} +5 -5
- package/.next/server/chunks/_1f46eie._.js +3 -0
- package/.next/server/chunks/_1h5_8sk._.js +3 -0
- package/.next/server/chunks/_1hdnxb7._.js +3 -0
- package/.next/server/chunks/_1j8k_j5._.js +3 -0
- package/.next/server/chunks/{_10qam6o._.js → _1kg70wc._.js} +5 -5
- package/.next/server/chunks/_1krd9rf._.js +3 -0
- package/.next/server/chunks/_1nc0eui._.js +11 -0
- package/.next/server/chunks/_1nula3v._.js +3 -0
- package/.next/server/chunks/_1pf4qe-._.js +3 -0
- package/.next/server/chunks/_1php4eq._.js +1 -1
- package/.next/server/chunks/_1qxheoa._.js +3 -0
- package/.next/server/chunks/_1x6kd1r._.js +3 -0
- package/.next/server/chunks/_1yuv4vp._.js +1 -1
- package/.next/server/chunks/_1zjrdag._.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_bot_memory_files_route_actions_1_xd_8f.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_bot_memory_route_actions_1a8xfr7.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_llm-model_credits_route_actions_0v424pb.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_llm-model_subscription_route_actions_0-udcm5.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_memory_edit_route_actions_02sfnmr.js +3 -0
- package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
- package/.next/server/chunks/features_0rpfxbk._.js +3 -0
- package/.next/server/chunks/features_1qf3cei._.js +3 -0
- package/.next/server/chunks/features_bot_0zt92oh._.js +3 -0
- package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
- package/.next/server/chunks/features_memory_1uqvksn._.js +6 -0
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0tf290y._.js → node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0228f43._.js → node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0ir-vo2._.js → node_modules_consola_dist_chunks_prompt_mjs_0j61-ma._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0otw8ef._.js → node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js} +1 -1
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_11zjo-1._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1pycqsq._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +3 -0
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1y49572._.js +3 -0
- package/.next/server/chunks/ssr/[externals]__0dizgek._.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]__0_69wqr._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0hg5gib._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0i8ie7f._.js +3 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__0jsmmb-._.js → [root-of-the-server]__0mz33a7._.js} +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0tbkdlx._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +3 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__0f6s48x._.js → [root-of-the-server]__0xpcv9w._.js} +3 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0xtssj3._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0zkv7z_._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +57 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__15_uhip._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__1cyjywu._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1eh7hid._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +43 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +4 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1pduf5n._.js +3 -0
- package/.next/server/chunks/ssr/{_1mznrxk._.js → _001_ms1._.js} +3 -3
- package/.next/server/chunks/ssr/_01_6m32._.js +3 -0
- package/.next/server/chunks/ssr/_01n3o0m._.js +3 -0
- package/.next/server/chunks/ssr/_07uchnc._.js +3 -0
- package/.next/server/chunks/ssr/_0ap2fzn._.js +3 -0
- package/.next/server/chunks/ssr/_0c-ql2m._.js +3 -0
- package/.next/server/chunks/ssr/_0h42fze._.js +3 -0
- package/.next/server/chunks/ssr/_0h7zdni._.js +1 -1
- package/.next/server/chunks/ssr/_0i_6q1w._.js +41 -0
- package/.next/server/chunks/ssr/_0kbkmar._.js +3 -0
- package/.next/server/chunks/ssr/_0lu1n_x._.js +3 -0
- package/.next/server/chunks/ssr/{_077-g6s._.js → _0mb8zc8._.js} +3 -3
- package/.next/server/chunks/ssr/_0mo2w06._.js +3 -0
- package/.next/server/chunks/ssr/{_13punpm._.js → _0q0zan6._.js} +2 -2
- package/.next/server/chunks/ssr/{_0gd4vaa._.js → _0u2jv_x._.js} +94 -58
- package/.next/server/chunks/ssr/_0y0tiht._.js +4 -0
- package/.next/server/chunks/ssr/_0zhoc3r._.js +3 -0
- package/.next/server/chunks/ssr/_1-teee5._.js +3 -3
- package/.next/server/chunks/ssr/_13fke0x._.js +3 -0
- package/.next/server/chunks/ssr/{_0q_2f2x._.js → _13z3f85._.js} +2 -2
- package/.next/server/chunks/ssr/_14_lw10._.js +3 -0
- package/.next/server/chunks/ssr/_15j2_8f._.js +3 -0
- package/.next/server/chunks/ssr/{_0lc_7c8._.js → _1eoqg_g._.js} +2 -2
- package/.next/server/chunks/ssr/_1sji22n._.js +3 -0
- package/.next/server/chunks/ssr/_1spzm8z._.js +3 -0
- package/.next/server/chunks/ssr/{_19_o9d-._.js → _1vi_uo7._.js} +2 -2
- package/.next/server/chunks/ssr/_1vyd1ji._.js +3 -0
- package/.next/server/chunks/ssr/_1xvgn77._.js +3 -0
- package/.next/server/chunks/ssr/_20kd_n0._.js +42 -0
- package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +3 -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/lib_date-like_ts_02is0pw._.js +3 -0
- package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +27 -0
- package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +27 -0
- package/.next/server/chunks/ssr/{node_modules_1d-is1o._.js → node_modules_063xwpp._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1ub40gk._.js → node_modules_0bvraul._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1nhw9qg._.js → node_modules_0eu1va6._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0xwx4u-._.js → node_modules_0h50b8n._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_043-236._.js → node_modules_0h5hnr1._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1t0y5jt._.js → node_modules_0h7u60n._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1k29j1j._.js → node_modules_0lm7_vm._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_16i4o_3._.js → node_modules_0mwym0g._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1y8_3vg._.js → node_modules_0rjg6t1._.js} +1 -1
- package/.next/server/chunks/ssr/node_modules_0x3-ply._.js +3 -0
- package/.next/server/chunks/ssr/{node_modules_108wd2o._.js → node_modules_0y_cded._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1jatz7w._.js → node_modules_0z5tsu8._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0ls96je._.js → node_modules_0zp9r92._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_06kvvuo._.js → node_modules_1-hc6uv._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1_588_4._.js → node_modules_113tz0l._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0ipn1ho._.js → node_modules_124bue5._.js} +1 -1
- package/.next/server/chunks/ssr/node_modules_17bwo43._.js +55 -0
- package/.next/server/chunks/ssr/{node_modules_0_j7-g4._.js → node_modules_1_n3ztw._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_20ynonm._.js → node_modules_1bc7gu8._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1hn_sd5._.js → node_modules_1bgb6-f._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0bue6gy._.js → node_modules_1h4a4pp._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0fbw5-u._.js → node_modules_1i7u1ia._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1ee8gav._.js → node_modules_1juq3hs._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0_fvxnt._.js → node_modules_1l0qtdu._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_13f2md6._.js → node_modules_1t9cyee._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0y2-av4._.js → node_modules_1uuj9x1._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_00d6675._.js → node_modules_1vqb6po._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1v0077l._.js → node_modules_1xx28h1._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_092s8nx._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0d3skpl._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1nvexgu._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0i44kk5._.js} +1 -1
- package/.next/server/chunks/ssr/node_modules_@vercel_oidc_dist_0qe30a_._.js +3 -0
- package/.next/server/chunks/ssr/node_modules_consola_dist_chunks_prompt_mjs_05cwqv2._.js +47 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_0w6mzq5._.js → node_modules_next_dist_0drixxt._.js} +4 -4
- package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +2 -2
- package/.next/server/instrumentation.js +1 -1
- 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 +67 -78
- package/.next/static/chunks/{31ttnjt6g35a0.js → 0ev4hyghq0mbb.js} +1 -1
- package/.next/static/chunks/0r5qcctujhxli.js +1 -0
- package/.next/static/chunks/0tmgrnlje14-s.js +3 -0
- package/.next/static/chunks/0x79tx04dxbpp.js +1 -0
- package/.next/static/chunks/0xzgvc0fkdb6t.js +1 -0
- package/.next/static/chunks/10teww7wt-f6h.js +1 -0
- package/.next/static/chunks/14hgtsjg-kael.css +1 -0
- package/.next/static/chunks/17donp69y4do7.js +40 -0
- package/.next/static/chunks/1dkjg87pxk0n9.js +28 -0
- package/.next/static/chunks/1ekc7ul556kbl.js +1 -0
- package/.next/static/chunks/{1khakdu_iuedc.js → 1grhjo7a5a0_-.js} +1 -1
- package/.next/static/chunks/1kq8h8wi_e0bc.js +53 -0
- package/.next/static/chunks/1okqiww3pnwka.js +1 -0
- package/.next/static/chunks/26-pr2c9ro222.js +1 -0
- package/.next/static/chunks/{2ihkf6l2jowo9.js → 280t0_e99i276.js} +3 -3
- package/.next/static/chunks/28cizcdaabd4h.js +1 -0
- package/.next/static/chunks/2a0k6jlq0_v1u.js +2 -0
- package/.next/static/chunks/2fzs9fm8yarvq.js +1 -0
- package/.next/static/chunks/2h0sd2vumhb15.js +1 -0
- package/.next/static/chunks/2hw2f6zmt7fmt.js +1 -0
- package/.next/static/chunks/2t4vhi3m8ahya.js +1 -0
- package/.next/static/chunks/2tigdtz3dpcy8.js +1 -0
- package/.next/static/chunks/3111pj5wnjgos.js +1 -0
- package/.next/static/chunks/3786h5vayt80-.js +28 -0
- package/.next/static/chunks/{3aquirz5h71da.js → 3agpgkwaa321p.js} +1 -1
- package/.next/static/chunks/3cfi_q6d_wtci.js +1 -0
- package/.next/static/chunks/3ok9_x74rip3v.js +1 -0
- package/.next/static/chunks/3xk7yqgomx7yq.js +1 -0
- package/.next/static/chunks/3xpbkl66ssib5.js +38 -0
- package/.next/static/media/favicon.37o1pjldwi2uc.ico +0 -0
- package/README.md +6 -4
- package/app/api/bot/memory/files/route.ts +14 -0
- package/app/api/bot/memory/route.ts +5 -0
- package/app/api/events/app-event.client.ts +24 -0
- package/app/api/events/app-event.server.ts +45 -0
- package/app/api/events/app-event.ts +42 -0
- package/app/api/llm-model/catalog/route.ts +12 -0
- package/app/api/llm-model/credits/route.ts +11 -0
- package/app/api/llm-model/route.ts +26 -0
- package/app/api/llm-model/subscription/route.ts +11 -0
- package/app/api/memory/edit/route.ts +7 -0
- package/app/api/memory/route.ts +21 -0
- package/app/api/query-key.ts +159 -0
- package/app/api/thursday/tool-call/route.ts +67 -0
- package/bin/thursday.mjs +3 -0
- package/components/ui/button-group.tsx +45 -0
- package/components/ui/custom-icon.tsx +259 -0
- package/components/ui/dropdown-menu.tsx +271 -0
- package/components/ui/folded-text.tsx +68 -0
- package/components/ui/input-group.tsx +157 -0
- package/components/ui/json-view.tsx +240 -0
- package/components/ui/shiny-text.tsx +55 -0
- package/components/ui/text-type.tsx +213 -0
- package/components/ui/theme-sync.tsx +9 -0
- package/database/migrations/{20260908030742_rainy_marvel_zombies → 20260910173049_numerous_spirit}/migration.sql +30 -33
- package/database/migrations/{20260908030742_rainy_marvel_zombies → 20260910173049_numerous_spirit}/snapshot.json +124 -145
- package/database/migrations/20260911030320_opposite_jack_power/migration.sql +1 -0
- package/database/migrations/20260911030320_opposite_jack_power/snapshot.json +1158 -0
- package/docs/how-it-works.md +59 -0
- package/docs/images/keeps-going.png +0 -0
- package/docs/images/task-thread.png +0 -0
- package/docs/images/two-minds.png +0 -0
- package/features/ai/chatgpt.ts +617 -0
- package/features/ai/components/chatgpt-sign-in.tsx +66 -0
- package/features/ai/components/model-picker.tsx +17 -1
- package/features/ai/components/provider-icon.tsx +1 -0
- package/features/ai/load-tools.ts +105 -39
- package/features/ai/model.schema.ts +232 -34
- package/features/ai/model.ts +169 -24
- package/features/ai/prompts/bot.prompt.ts +245 -59
- package/features/ai/prompts/memory-edit.prompt.ts +33 -0
- package/features/ai/prompts/prompt-helper.ts +75 -30
- package/features/ai/prompts/thursday.prompt.ts +42 -17
- package/features/ai/tools/bot.tool.ts +32 -30
- package/features/ai/tools/connected.ts +17 -4
- package/features/ai/tools/mcp.tool.ts +5 -5
- package/features/ai/tools/memory.tool.ts +142 -74
- package/features/ai/tools/search.tool.ts +136 -47
- package/features/ai/tools/studio.tool.ts +5 -5
- package/features/ai/tools/tool-name.ts +2 -3
- package/features/ai/tools/workspace.tool.ts +33 -4
- package/features/bot/bot.action.ts +24 -7
- package/features/bot/bot.memory.ts +89 -0
- package/features/bot/bot.query.ts +41 -6
- package/features/bot/bot.run.ts +516 -210
- package/features/bot/bot.runner.ts +463 -93
- package/features/bot/bot.schema.ts +84 -7
- package/features/bot/bot.seed.ts +89 -16
- package/features/bot/components/bot-mark.tsx +122 -20
- package/features/bot/components/bot-room.tsx +519 -391
- package/features/bot/components/bot-setting.tsx +832 -341
- package/features/bot/components/bot-tool.tsx +2 -6
- package/features/bot/components/mark-palette.tsx +54 -0
- package/features/bot/components/path-chips.tsx +1 -1
- package/features/bot/components/task-badge.tsx +26 -6
- package/features/bot/components/task-reply.tsx +22 -33
- package/features/bot/components/task-setting.tsx +20 -17
- package/features/bot/task.query.ts +233 -33
- package/features/bot/task.store.ts +53 -9
- package/features/config/components/config-setting.tsx +265 -34
- package/features/config/components/models-badge.tsx +42 -0
- package/features/config/config.action.ts +12 -0
- package/features/config/config.const.ts +38 -2
- package/features/connectors/mcp.manager.ts +10 -2
- package/features/intro/components/intro.tsx +47 -46
- package/features/memory/components/memory-edit.tsx +338 -0
- package/features/memory/components/memory-setting.tsx +86 -79
- package/features/memory/memory.action.ts +3 -43
- package/features/memory/memory.edit.ts +87 -0
- package/features/memory/memory.query.ts +33 -44
- package/features/memory/memory.schema.ts +50 -97
- package/features/settings/components/settings.tsx +2 -0
- package/features/settings/settings.alert.ts +3 -1
- package/features/skills/components/skills-setting.tsx +9 -1
- package/features/thursday/components/ascii-orb.tsx +106 -90
- package/features/thursday/components/boot.tsx +7 -0
- package/features/thursday/components/call-log.tsx +219 -92
- package/features/thursday/components/face.tsx +6 -4
- package/features/thursday/components/tab-state.tsx +97 -0
- package/features/thursday/components/thursday-mark.tsx +4 -1
- package/features/thursday/components/thursday-setting.tsx +17 -47
- package/features/thursday/components/thursday.tsx +208 -95
- package/features/thursday/thursday.action.ts +12 -17
- package/features/thursday/thursday.query.ts +61 -70
- package/features/thursday/thursday.schema.ts +20 -7
- package/features/thursday/tool-line.ts +85 -11
- package/features/thursday/use-thursday.ts +86 -59
- package/features/workspace/components/file-view.tsx +4 -2
- package/features/workspace/workspace.ts +230 -13
- package/hooks/use-draft.ts +37 -0
- package/hooks/use-hotkey.ts +105 -0
- package/hooks/use-object-state.ts +51 -0
- package/hooks/use-on-visible.ts +72 -0
- package/hooks/use-theme.ts +106 -0
- package/hooks/use-wake-word.ts +262 -0
- package/lib/limits.ts +1 -1
- package/lib/oauth-page.ts +27 -0
- package/lib/realtime/openai.ts +2 -2
- package/lib/realtime/realtime.driver.ts +34 -1
- package/lib/realtime/realtime.protocol.ts +7 -1
- package/lib/realtime/realtime.tap.ts +122 -0
- package/lib/sandbox.ts +60 -29
- package/lib/tokens.ts +19 -0
- package/package.json +1 -1
- package/skills/browser/SKILL.md +55 -34
- package/.next/server/app/api/memory/tidy/route/app-paths-manifest.json +0 -3
- package/.next/server/app/api/memory/tidy/route.js +0 -23
- package/.next/server/app/api/memory/tidy/route.js.nft.json +0 -1
- package/.next/server/chunks/[root-of-the-server]__019dx9f._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__02_2sm-._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__02kt8yn._.js +0 -10
- package/.next/server/chunks/[root-of-the-server]__05luceg._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__06t77t4._.js +0 -11
- package/.next/server/chunks/[root-of-the-server]__0bed6hu._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0dupqt7._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__0h59di-._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__0j_n5l3._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0le4d-p._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0m8ywyo._.js +0 -10
- package/.next/server/chunks/[root-of-the-server]__0nfuugi._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__0phdgco._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0qjqtwo._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__0t_dqaj._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0wvgrsl._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0yk6s3w._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__0z3gelv._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__10qshki._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__113fqg5._.js +0 -12
- package/.next/server/chunks/[root-of-the-server]__11w_7_3._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__16thabu._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__173nhwf._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__1_0q_9w._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1_aoyr9._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1bqhuh9._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__1cqizfq._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__1dow0bz._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1gmn1cs._.js +0 -10
- package/.next/server/chunks/[root-of-the-server]__1lr7j9t._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__1mzp_el._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1txedx6._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__1u_qvc7._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1zgpz1w._.js +0 -3
- package/.next/server/chunks/_012yhfm._.js +0 -39
- package/.next/server/chunks/_06mxlgn._.js +0 -3
- package/.next/server/chunks/_07rtlxv._.js +0 -3
- package/.next/server/chunks/_0a351g7._.js +0 -6
- package/.next/server/chunks/_0kjjmag._.js +0 -3
- package/.next/server/chunks/_0zmestz._.js +0 -55
- package/.next/server/chunks/_0zuzmt_._.js +0 -39
- package/.next/server/chunks/_12bbv5i._.js +0 -96
- package/.next/server/chunks/_15q1pig._.js +0 -3
- package/.next/server/chunks/_1drv2et._.js +0 -36
- package/.next/server/chunks/_1ic3bew._.js +0 -5
- package/.next/server/chunks/_1mxn_lb._.js +0 -3
- package/.next/server/chunks/_1uj4_io._.js +0 -10
- package/.next/server/chunks/_1x7p319._.js +0 -6
- package/.next/server/chunks/_1yldgo4._.js +0 -55
- package/.next/server/chunks/_2050gwn._.js +0 -255
- package/.next/server/chunks/_next-internal_server_app_api_memory_tidy_route_actions_0_cfuom.js +0 -3
- package/.next/server/chunks/features_0scmr4i._.js +0 -3
- package/.next/server/chunks/features_bot_task_query_ts_11xuzl3._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0vorg6w._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0ykklj0._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1ryg3wh._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vmaq9f._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vwbnq_._.js +0 -3
- package/.next/server/chunks/ssr/[externals]_node_crypto_1kn79-7._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__01id-v3._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0b-0i32._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0dfwvr4._.js +0 -4
- package/.next/server/chunks/ssr/[root-of-the-server]__0iuoa-r._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__1-mnhyd._.js +0 -90
- package/.next/server/chunks/ssr/[root-of-the-server]__185grso._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__1minz8_._.js +0 -3
- package/.next/server/chunks/ssr/_0-mc7ro._.js +0 -3
- package/.next/server/chunks/ssr/_01p5r6-._.js +0 -3
- package/.next/server/chunks/ssr/_09-0k3z._.js +0 -3
- package/.next/server/chunks/ssr/_0ay6b01._.js +0 -3
- package/.next/server/chunks/ssr/_0cvjbuz._.js +0 -3
- package/.next/server/chunks/ssr/_0fafgvl._.js +0 -3
- package/.next/server/chunks/ssr/_0j4v8of._.js +0 -3
- package/.next/server/chunks/ssr/_0l81bzy._.js +0 -3
- package/.next/server/chunks/ssr/_0nso8tp._.js +0 -3
- package/.next/server/chunks/ssr/_0sf1isi._.js +0 -3
- package/.next/server/chunks/ssr/_0ti51xc._.js +0 -3
- package/.next/server/chunks/ssr/_0y84qo6._.js +0 -3
- package/.next/server/chunks/ssr/_10uvw3l._.js +0 -3
- package/.next/server/chunks/ssr/_1dcxzqe._.js +0 -3
- package/.next/server/chunks/ssr/_1e-dgz0._.js +0 -4
- package/.next/server/chunks/ssr/_1fq7zgb._.js +0 -3
- package/.next/server/chunks/ssr/_1jbv7m1._.js +0 -3
- package/.next/server/chunks/ssr/features_bot_components_bot-setting_tsx_01ajft6._.js +0 -4
- package/.next/server/chunks/ssr/features_config_components_14jqgy4._.js +0 -3
- package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +0 -4
- package/.next/server/chunks/ssr/lib_realtime_0aetuyp._.js +0 -24
- package/.next/server/chunks/ssr/lib_realtime_18k_aj-._.js +0 -24
- package/.next/server/chunks/ssr/node_modules_zod_v4_classic_errors_05xv7vp.js +0 -3
- package/.next/server/chunks/ssr/node_modules_zod_v4_classic_external_15fmmz3.js +0 -55
- package/.next/static/chunks/0f9sq-7q_yxyl.js +0 -1
- package/.next/static/chunks/0tydnn2kybibk.js +0 -1
- package/.next/static/chunks/0yysv1gzin17t.js +0 -1
- package/.next/static/chunks/1fr5m75pwtyic.js +0 -1
- package/.next/static/chunks/1gy3bbv7usnjo.js +0 -1
- package/.next/static/chunks/1keib_gt066gc.js +0 -1
- package/.next/static/chunks/1ytnip8wdng93.js +0 -1
- package/.next/static/chunks/21rk8w7bda-su.js +0 -1
- package/.next/static/chunks/247d-r95j8xs0.js +0 -1
- package/.next/static/chunks/28g42tw8tsvhd.js +0 -1
- package/.next/static/chunks/29gyb3nubj51j.js +0 -53
- package/.next/static/chunks/2cwjgkt_hoyhj.js +0 -22
- package/.next/static/chunks/2fq_86jvq9ymq.js +0 -2
- package/.next/static/chunks/2rbf1fpd8n80-.js +0 -22
- package/.next/static/chunks/2ukj8k69y89um.js +0 -1
- package/.next/static/chunks/2uxum7qbyeyxd.js +0 -1
- package/.next/static/chunks/2wngeetfnzxkp.js +0 -2
- package/.next/static/chunks/388-t2v72jh39.css +0 -1
- package/.next/static/chunks/3fqvc0cg-atq_.js +0 -1
- package/.next/static/chunks/3p4egvfjxpatb.js +0 -1
- package/.next/static/chunks/3qe1w1ei-huhl.js +0 -1
- package/.next/static/chunks/3xxa2j56-f3nm.js +0 -3
- package/.next/static/chunks/3y40riycdip-i.js +0 -1
- package/.next/static/chunks/45a6zbtkelph9.js +0 -1
- package/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
- package/features/ai/prompts/memory-tidy.prompt.ts +0 -123
- package/features/ai/tools/tidy.tool.ts +0 -22
- package/features/memory/components/memory-tidy.tsx +0 -395
- package/features/memory/memory.tidy.ts +0 -332
- package/features/memory/tidy.query.ts +0 -135
- package/features/thursday/use-call-title.ts +0 -31
- /package/.next/server/app/api/{memory/tidy → bot/memory/files}/route/build-manifest.json +0 -0
- /package/.next/server/app/api/{memory/tidy → bot/memory/files}/route/server-reference-manifest.json +0 -0
- /package/.next/server/app/api/{memory/tidy → bot/memory/files}/route.js.map +0 -0
- /package/.next/static/{X34BUd9bfdH27ripuwwBm → x1cCqY0kWpR_VcYx_lWO5}/_buildManifest.js +0 -0
- /package/.next/static/{X34BUd9bfdH27ripuwwBm → x1cCqY0kWpR_VcYx_lWO5}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{X34BUd9bfdH27ripuwwBm → x1cCqY0kWpR_VcYx_lWO5}/_ssgManifest.js +0 -0
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import type { ModelMessage } from "ai";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import {
|
|
3
|
+
appEventStream,
|
|
4
|
+
appEvents,
|
|
5
|
+
presence,
|
|
6
|
+
} from "@/app/api/events/app-event.server";
|
|
7
|
+
import { BOT_RUN, PATHS, WORKSPACE_KEEP } from "@/config";
|
|
8
|
+
import {
|
|
9
|
+
type ModelFailure,
|
|
10
|
+
modelErrorToString,
|
|
11
|
+
modelFailureOf,
|
|
12
|
+
} from "@/features/ai/model";
|
|
6
13
|
import {
|
|
7
14
|
buildTaskOpening,
|
|
8
15
|
OPENING_TURNS,
|
|
@@ -13,21 +20,34 @@ import {
|
|
|
13
20
|
listCallTurns,
|
|
14
21
|
} from "@/features/thursday/thursday.query";
|
|
15
22
|
import { pathsIn } from "@/features/workspace/file-kind";
|
|
16
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
closeHiddenBrowser,
|
|
25
|
+
closeJobShell,
|
|
26
|
+
jobScratch,
|
|
27
|
+
listScratchFolders,
|
|
28
|
+
pruneJobFiles,
|
|
29
|
+
removeJobScratch,
|
|
30
|
+
removeUnchangedFolders,
|
|
31
|
+
} from "@/features/workspace/workspace";
|
|
17
32
|
import { desktopNotify } from "@/lib/desktop-notify";
|
|
18
33
|
import { logger } from "@/lib/logger";
|
|
19
34
|
import { publicError } from "@/lib/public-error";
|
|
20
35
|
import { createKeyedLock } from "@/lib/queue";
|
|
21
|
-
import {
|
|
22
|
-
import { TASK_CONTINUE, type TaskStatus } from "./bot.schema";
|
|
36
|
+
import { resumeThread, runBot, type TaskEvent } from "./bot.run";
|
|
37
|
+
import { TASK_CONTINUE, type TaskPending, type TaskStatus } from "./bot.schema";
|
|
23
38
|
import {
|
|
24
39
|
addTaskUsage,
|
|
40
|
+
countStopsSinceSpoken,
|
|
41
|
+
deleteFinishedTasks,
|
|
25
42
|
deleteMessages,
|
|
26
43
|
deleteTask,
|
|
27
44
|
findTask,
|
|
28
45
|
insertTask,
|
|
29
46
|
lastSeq,
|
|
47
|
+
listAutoStoppedTasks,
|
|
48
|
+
listBorrowedTails,
|
|
30
49
|
listRunningTaskIds,
|
|
50
|
+
listTaskFolders,
|
|
31
51
|
listThread,
|
|
32
52
|
type TaskMessageInput,
|
|
33
53
|
updateTask,
|
|
@@ -35,9 +55,10 @@ import {
|
|
|
35
55
|
} from "./task.query";
|
|
36
56
|
|
|
37
57
|
/**
|
|
38
|
-
* Runs a job
|
|
39
|
-
*
|
|
40
|
-
*
|
|
58
|
+
* Runs a job so it outlives the request, writing every event to the task's
|
|
59
|
+
* thread (task_message). A run always starts from the thread. `answerTask` is
|
|
60
|
+
* the one way a person adds to it, serialized per job by `taskLock`, and
|
|
61
|
+
* `resumeTask` the one way the app picks a job back up by itself.
|
|
41
62
|
*/
|
|
42
63
|
|
|
43
64
|
type Run = {
|
|
@@ -54,6 +75,8 @@ type Run = {
|
|
|
54
75
|
type Pinned = {
|
|
55
76
|
__botRuns?: Map<string, Run>;
|
|
56
77
|
__botTaskLock?: ReturnType<typeof createKeyedLock>;
|
|
78
|
+
__botResumes?: Map<string, ReturnType<typeof setTimeout>>;
|
|
79
|
+
__botPausing?: { current: Promise<void> };
|
|
57
80
|
};
|
|
58
81
|
|
|
59
82
|
/** Pinned to globalThis: next dev reloads this module under a running run, and the abort controller and lock must be the originals. */
|
|
@@ -66,7 +89,17 @@ const running: Map<string, Run> = ((globalThis as Pinned).__botRuns ??=
|
|
|
66
89
|
*/
|
|
67
90
|
const taskLock = ((globalThis as Pinned).__botTaskLock ??= createKeyedLock());
|
|
68
91
|
|
|
69
|
-
/**
|
|
92
|
+
/** When each parked job picks itself back up (scheduleResume); one timer per job. */
|
|
93
|
+
const resumes: Map<string, ReturnType<typeof setTimeout>> = ((
|
|
94
|
+
globalThis as Pinned
|
|
95
|
+
).__botResumes ??= new Map());
|
|
96
|
+
|
|
97
|
+
/** The pause under way, if any; a returning browser waits for it (resumeStoppedTasks). */
|
|
98
|
+
const pausing = ((globalThis as Pinned).__botPausing ??= {
|
|
99
|
+
current: Promise.resolve(),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/** Opens a job. The opening message — who is who, the job, the call it came from (bot.prompt buildTaskOpening) — is the thread's first row. */
|
|
70
103
|
export async function startTask(input: {
|
|
71
104
|
bot: string;
|
|
72
105
|
request: string;
|
|
@@ -76,7 +109,11 @@ export async function startTask(input: {
|
|
|
76
109
|
const conversation = input.callId
|
|
77
110
|
? await listCallTurns(input.callId, OPENING_TURNS)
|
|
78
111
|
: [];
|
|
79
|
-
const opening = buildTaskOpening({
|
|
112
|
+
const opening = buildTaskOpening({
|
|
113
|
+
bot: input.bot,
|
|
114
|
+
request: input.request,
|
|
115
|
+
conversation,
|
|
116
|
+
});
|
|
80
117
|
const task = await insertTask({ ...input, opening });
|
|
81
118
|
launch(task.id, {
|
|
82
119
|
bot: input.bot,
|
|
@@ -106,11 +143,13 @@ export async function answerTask(id: string, answer: string) {
|
|
|
106
143
|
live.stop.abort();
|
|
107
144
|
await live.done;
|
|
108
145
|
}
|
|
146
|
+
// A person picked it up; whatever the app meant to do by itself is moot
|
|
147
|
+
forgetResume(id);
|
|
109
148
|
|
|
110
|
-
const
|
|
149
|
+
const thread = await listThread(id);
|
|
150
|
+
const { reply, as } = joinThread(task, answer, thread);
|
|
111
151
|
logger.debug(`task ${id}: ${as}`);
|
|
112
152
|
|
|
113
|
-
const thread = await listThread(id);
|
|
114
153
|
await upsertMessage(id, (await lastSeq(id)) + 1, {
|
|
115
154
|
bot: null,
|
|
116
155
|
parent: null,
|
|
@@ -121,14 +160,53 @@ export async function answerTask(id: string, answer: string) {
|
|
|
121
160
|
status: "running",
|
|
122
161
|
outcome: null,
|
|
123
162
|
pending: null,
|
|
124
|
-
|
|
163
|
+
seen: false,
|
|
125
164
|
endedAt: null,
|
|
126
165
|
});
|
|
127
|
-
//
|
|
128
|
-
launch(id, {
|
|
166
|
+
// Resumed on the rows as they were stored (bot.run resumeThread)
|
|
167
|
+
launch(id, {
|
|
168
|
+
bot: task.bot,
|
|
169
|
+
messages: resumeThread([...thread, reply], await listBorrowedTails(id)),
|
|
170
|
+
});
|
|
129
171
|
});
|
|
130
172
|
}
|
|
131
173
|
|
|
174
|
+
/**
|
|
175
|
+
* The `ask_thursday` calls still open in the step a job stopped on: a model can
|
|
176
|
+
* ask twice at once, and the one answer goes to each rather than leaving the
|
|
177
|
+
* second to read as a call cut off (bot.run resumeThread). A call that already
|
|
178
|
+
* has a result — arguments the tool refused — is not open, and the words go in
|
|
179
|
+
* as a turn instead: a second result for one call is refused outright.
|
|
180
|
+
*/
|
|
181
|
+
function openAsks(thread: ModelMessage[], stoppedOn: string): string[] {
|
|
182
|
+
const answered = new Set(
|
|
183
|
+
thread.flatMap((message) =>
|
|
184
|
+
message.role === "tool"
|
|
185
|
+
? message.content.flatMap((part) =>
|
|
186
|
+
part.type === "tool-result" ? [part.toolCallId] : [],
|
|
187
|
+
)
|
|
188
|
+
: [],
|
|
189
|
+
),
|
|
190
|
+
);
|
|
191
|
+
const step = thread.findLast(
|
|
192
|
+
(message) =>
|
|
193
|
+
message.role === "assistant" &&
|
|
194
|
+
typeof message.content !== "string" &&
|
|
195
|
+
message.content.some(
|
|
196
|
+
(part) => part.type === "tool-call" && part.toolCallId === stoppedOn,
|
|
197
|
+
),
|
|
198
|
+
);
|
|
199
|
+
const asks =
|
|
200
|
+
step?.role === "assistant" && typeof step.content !== "string"
|
|
201
|
+
? step.content.flatMap((part) =>
|
|
202
|
+
part.type === "tool-call" && part.toolName === TOOL_NAMES.ask_thursday
|
|
203
|
+
? [part.toolCallId]
|
|
204
|
+
: [],
|
|
205
|
+
)
|
|
206
|
+
: [stoppedOn];
|
|
207
|
+
return asks.filter((toolCallId) => !answered.has(toolCallId));
|
|
208
|
+
}
|
|
209
|
+
|
|
132
210
|
/**
|
|
133
211
|
* How a person's words enter the thread. A job stopped on `ask_thursday` gets
|
|
134
212
|
* them as that call's tool result (a call with no result would break the
|
|
@@ -136,23 +214,23 @@ export async function answerTask(id: string, answer: string) {
|
|
|
136
214
|
* continue has no call to answer, so it is a turn as well.
|
|
137
215
|
*/
|
|
138
216
|
function joinThread(
|
|
139
|
-
task: { status: TaskStatus; pending:
|
|
217
|
+
task: { status: TaskStatus; pending: TaskPending | null },
|
|
140
218
|
answer: string,
|
|
219
|
+
thread: ModelMessage[],
|
|
141
220
|
): { reply: ModelMessage; as: "answer" | "interruption" | "follow-up" } {
|
|
142
221
|
const pending = task.status === "waiting" ? task.pending : null;
|
|
143
|
-
|
|
222
|
+
const asks = pending?.toolCallId ? openAsks(thread, pending.toolCallId) : [];
|
|
223
|
+
if (asks.length) {
|
|
144
224
|
return {
|
|
145
225
|
as: "answer",
|
|
146
226
|
reply: {
|
|
147
227
|
role: "tool",
|
|
148
|
-
content:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
},
|
|
155
|
-
],
|
|
228
|
+
content: asks.map((toolCallId) => ({
|
|
229
|
+
type: "tool-result" as const,
|
|
230
|
+
toolCallId,
|
|
231
|
+
toolName: TOOL_NAMES.ask_thursday,
|
|
232
|
+
output: { type: "text" as const, value: answer },
|
|
233
|
+
})),
|
|
156
234
|
},
|
|
157
235
|
};
|
|
158
236
|
}
|
|
@@ -171,13 +249,17 @@ export async function cancelTask(id: string) {
|
|
|
171
249
|
return taskLock(id, async () => {
|
|
172
250
|
const task = await findTask(id);
|
|
173
251
|
if (!task) publicError("No such job.");
|
|
252
|
+
// A job that already ended has an answer in `outcome`; cancelling would
|
|
253
|
+
// write "Cancelled." over the thing it was run for.
|
|
254
|
+
if (task.endedAt) publicError("That job has already ended.");
|
|
255
|
+
forgetResume(id);
|
|
174
256
|
running.get(id)?.stop.abort();
|
|
175
257
|
await updateTask(id, {
|
|
176
258
|
status: "failed",
|
|
177
259
|
outcome: "Cancelled.",
|
|
178
260
|
pending: null,
|
|
179
261
|
// Nobody needs to be told what they just did themselves
|
|
180
|
-
|
|
262
|
+
seen: true,
|
|
181
263
|
endedAt: new Date(),
|
|
182
264
|
});
|
|
183
265
|
// Cancel is a real end, so the browser session closes here; the abort in
|
|
@@ -189,53 +271,259 @@ export async function cancelTask(id: string) {
|
|
|
189
271
|
/** Deletes the job, stopping it first if it is still running. */
|
|
190
272
|
export async function removeTask(id: string) {
|
|
191
273
|
return taskLock(id, async () => {
|
|
274
|
+
const task = await findTask(id);
|
|
275
|
+
forgetResume(id);
|
|
192
276
|
running.get(id)?.stop.abort();
|
|
193
277
|
running.delete(id);
|
|
194
278
|
void closeJobShell(id);
|
|
195
|
-
|
|
279
|
+
const gone = await deleteTask(id);
|
|
280
|
+
// The working folder's lifetime is the row's: with the job gone, what it was
|
|
281
|
+
// working with is nobody's (workspace.ts jobScratch).
|
|
282
|
+
if (gone && task) await removeJobScratch(id, task.label);
|
|
283
|
+
return gone;
|
|
196
284
|
});
|
|
197
285
|
}
|
|
198
286
|
|
|
199
287
|
/**
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
288
|
+
* Clearing finished jobs from the screen, and their working folders with them.
|
|
289
|
+
* Lives here rather than in the query because a row and a folder go together
|
|
290
|
+
* and only one of the two is the database's.
|
|
291
|
+
*/
|
|
292
|
+
export async function removeFinishedTasks(): Promise<number> {
|
|
293
|
+
const removed = await deleteFinishedTasks();
|
|
294
|
+
for (const task of removed) await removeJobScratch(task.id, task.label);
|
|
295
|
+
return removed.length;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Clears what jobs left behind by age (config WORKSPACE_KEEP), at boot and on a
|
|
300
|
+
* timer (instrumentation): a job's folder once the job ended that long ago — a job
|
|
301
|
+
* running or waiting keeps its own however old — a scratch folder no job owns once
|
|
302
|
+
* it has not changed that long, and spilled output and browser snapshots that old
|
|
303
|
+
* (pruneJobFiles). A job's folder goes under the job's lock, so a word that picks
|
|
304
|
+
* the job back up in that moment never finds its material gone. Returns the
|
|
305
|
+
* folders that went.
|
|
306
|
+
*/
|
|
307
|
+
export async function sweepJobFiles(): Promise<string[]> {
|
|
308
|
+
const cutoff = Date.now() - WORKSPACE_KEEP.forMs;
|
|
309
|
+
const stale = (task: {
|
|
310
|
+
status: TaskStatus;
|
|
311
|
+
endedAt: Date | null;
|
|
312
|
+
updatedAt: Date;
|
|
313
|
+
}) =>
|
|
314
|
+
(task.status === "done" || task.status === "failed") &&
|
|
315
|
+
(task.endedAt ?? task.updatedAt).getTime() < cutoff;
|
|
316
|
+
|
|
317
|
+
// Folders on disk; each one a job owns is taken out as its job is read
|
|
318
|
+
const unowned = new Set(await listScratchFolders());
|
|
319
|
+
const removed: string[] = [];
|
|
320
|
+
for (const task of await listTaskFolders()) {
|
|
321
|
+
const folder = jobScratch(task.id, task.label);
|
|
322
|
+
if (!unowned.delete(folder) || !stale(task)) continue;
|
|
323
|
+
await taskLock(task.id, async () => {
|
|
324
|
+
const now = await findTask(task.id);
|
|
325
|
+
if (!now || !stale(now)) return;
|
|
326
|
+
await removeJobScratch(task.id, task.label);
|
|
327
|
+
removed.push(folder);
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
removed.push(...(await removeUnchangedFolders([...unowned])));
|
|
331
|
+
await pruneJobFiles();
|
|
332
|
+
if (removed.length) {
|
|
333
|
+
logger.info(
|
|
334
|
+
`cleared ${removed.length} old job folder(s): ${removed.join(", ")}`,
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
return removed;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* At boot (instrumentation): rows the last process left as running are not
|
|
342
|
+
* running now. Each is parked the way every stop the app causes is (parkTask),
|
|
343
|
+
* so it picks itself back up once a browser is on the app. Nothing else needs
|
|
344
|
+
* to reconcile — a run that ends badly records it itself (drive), and the write
|
|
345
|
+
* that does so is durable (database/db.ts oneAtATime).
|
|
203
346
|
*/
|
|
204
347
|
export async function sweepTasks() {
|
|
205
348
|
for (const id of await listRunningTaskIds()) {
|
|
206
|
-
if (running.has(id))
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
pending: { toolCallId: null, options: [TASK_CONTINUE] },
|
|
212
|
-
reported: false,
|
|
213
|
-
endedAt: null,
|
|
214
|
-
});
|
|
349
|
+
if (!running.has(id)) {
|
|
350
|
+
await parkTask(id, {
|
|
351
|
+
why: "The server restarted while this was running.",
|
|
352
|
+
});
|
|
353
|
+
}
|
|
215
354
|
}
|
|
216
355
|
}
|
|
217
356
|
|
|
218
357
|
/**
|
|
219
|
-
* The browser closed
|
|
220
|
-
* and
|
|
221
|
-
*
|
|
358
|
+
* The browser closed, or the server is going down (instrumentation): every run
|
|
359
|
+
* stops where it is and is parked (parkTask). All at once — a run slow to let go
|
|
360
|
+
* must not keep the others running. The thread stays, and so does the window: a
|
|
361
|
+
* resume carries on in the page it left off at, including a sign-in the user is
|
|
362
|
+
* mid-way through, which only that window can finish.
|
|
222
363
|
*/
|
|
223
364
|
export async function pauseTasks(reason: string) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
365
|
+
const work = Promise.all(
|
|
366
|
+
[...running].map(([id, run]) =>
|
|
367
|
+
taskLock(id, async () => {
|
|
368
|
+
run.stop.abort();
|
|
369
|
+
await run.done;
|
|
370
|
+
const task = await findTask(id);
|
|
371
|
+
if (!task || task.status !== "running") return;
|
|
372
|
+
await parkTask(id, { why: reason });
|
|
373
|
+
}).catch((cause) => logger.error(`task ${id}: pause`, cause)),
|
|
374
|
+
),
|
|
375
|
+
).then(() => {});
|
|
376
|
+
pausing.current = work;
|
|
377
|
+
await work;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* A browser is on the app again (instrumentation `presence.onBack`): every job
|
|
382
|
+
* the app parked picks itself back up — now, or when the wait a failed model
|
|
383
|
+
* call set runs out. A pause still under way is waited for first, so a quick
|
|
384
|
+
* reload does not miss what it parks.
|
|
385
|
+
*/
|
|
386
|
+
export async function resumeStoppedTasks() {
|
|
387
|
+
await pausing.current;
|
|
388
|
+
for (const task of await listAutoStoppedTasks()) {
|
|
389
|
+
scheduleResume(task.id, task.retryAt - Date.now());
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/** One timer per job: a newer stop replaces what an older one set. */
|
|
394
|
+
function scheduleResume(id: string, inMs: number) {
|
|
395
|
+
forgetResume(id);
|
|
396
|
+
resumes.set(
|
|
397
|
+
id,
|
|
398
|
+
setTimeout(
|
|
399
|
+
() => {
|
|
400
|
+
resumes.delete(id);
|
|
401
|
+
void resumeTask(id).catch((cause) =>
|
|
402
|
+
logger.error(`task ${id}: resume`, cause),
|
|
403
|
+
);
|
|
404
|
+
},
|
|
405
|
+
Math.max(0, inMs),
|
|
406
|
+
),
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function forgetResume(id: string) {
|
|
411
|
+
clearTimeout(resumes.get(id));
|
|
412
|
+
resumes.delete(id);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Picks a parked job back up. Only with a browser on the app — nothing runs
|
|
417
|
+
* without one, and its return tries again — and only if it is still parked: a
|
|
418
|
+
* person may have answered, cancelled or deleted it since. No turn is added,
|
|
419
|
+
* because nobody said anything; the note parkTask left is what the run reads last.
|
|
420
|
+
*/
|
|
421
|
+
async function resumeTask(id: string) {
|
|
422
|
+
if (!presence.watching) return;
|
|
423
|
+
await taskLock(id, async () => {
|
|
424
|
+
const task = await findTask(id);
|
|
425
|
+
if (!task || task.status !== "waiting" || !task.pending?.auto) return;
|
|
426
|
+
if (running.has(id)) return;
|
|
427
|
+
logger.debug(`task ${id}: picking back up`);
|
|
428
|
+
const thread = await listThread(id);
|
|
429
|
+
await updateTask(id, {
|
|
430
|
+
status: "running",
|
|
431
|
+
outcome: null,
|
|
432
|
+
pending: null,
|
|
433
|
+
seen: false,
|
|
434
|
+
endedAt: null,
|
|
238
435
|
});
|
|
436
|
+
launch(id, {
|
|
437
|
+
bot: task.bot,
|
|
438
|
+
messages: resumeThread(thread, await listBorrowedTails(id)),
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Stops a job the app stopped, rather than the bot or a person: a restart, a
|
|
445
|
+
* closed browser, a model call a retry or a compaction can fix. It waits with
|
|
446
|
+
* the one continue option like any stop, with a line in its thread saying why —
|
|
447
|
+
* the resumed run reads it — and picks itself back up (scheduleResume). Unless
|
|
448
|
+
* the app has already stopped it `BOT_RUN.autoResumes` times since a person last
|
|
449
|
+
* spoke to it: that is what a job that keeps taking the server down looks like,
|
|
450
|
+
* and it waits for a person instead.
|
|
451
|
+
*/
|
|
452
|
+
async function parkTask(
|
|
453
|
+
id: string,
|
|
454
|
+
stop: {
|
|
455
|
+
why: string;
|
|
456
|
+
/** A failed model call: wait before trying again (config BOT_RUN.retryAfterMs). */
|
|
457
|
+
retry?: boolean;
|
|
458
|
+
/** Where the job compacts from now on (bot.run `budget`). */
|
|
459
|
+
budget?: number;
|
|
460
|
+
},
|
|
461
|
+
) {
|
|
462
|
+
const stops = await countStopsSinceSpoken(id);
|
|
463
|
+
const auto = stops < BOT_RUN.autoResumes;
|
|
464
|
+
const waits = BOT_RUN.retryAfterMs;
|
|
465
|
+
const inMs =
|
|
466
|
+
auto && stop.retry ? waits[Math.min(stops, waits.length - 1)] : 0;
|
|
467
|
+
|
|
468
|
+
await writeNote(id, `${stop.why} ${IN_FLIGHT}`).catch((cause) =>
|
|
469
|
+
logger.warn(`task ${id}: stop not written`, cause),
|
|
470
|
+
);
|
|
471
|
+
await writeEnding(id, {
|
|
472
|
+
status: "waiting",
|
|
473
|
+
outcome: auto
|
|
474
|
+
? `${stop.why} ${inMs ? `It tries again in ${spell(inMs)}.` : "It picks back up by itself."}`
|
|
475
|
+
: `${stop.why} It has stopped ${stops + 1} times in a row, so it waits for you. Everything it had done is still here.`,
|
|
476
|
+
pending: {
|
|
477
|
+
toolCallId: null,
|
|
478
|
+
options: [TASK_CONTINUE],
|
|
479
|
+
...(auto ? { auto: true, retryAt: Date.now() + inMs } : {}),
|
|
480
|
+
},
|
|
481
|
+
...(stop.budget ? { contextBudget: stop.budget } : {}),
|
|
482
|
+
seen: false,
|
|
483
|
+
endedAt: null,
|
|
484
|
+
});
|
|
485
|
+
if (auto) scheduleResume(id, inMs);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/** Said to a resumed run after why it stopped. */
|
|
489
|
+
const IN_FLIGHT =
|
|
490
|
+
"Anything that was under way — a command, a page loading, a download — may not have finished: check before relying on it, then carry on.";
|
|
491
|
+
|
|
492
|
+
const spell = (ms: number) =>
|
|
493
|
+
ms < 60_000
|
|
494
|
+
? `${Math.round(ms / 1000)} seconds`
|
|
495
|
+
: `${Math.round(ms / 60_000)} minutes`;
|
|
496
|
+
|
|
497
|
+
/** A line from the app in a thread no run is writing (ThreadWriter.note is the one for a run that is). */
|
|
498
|
+
async function writeNote(id: string, text: string) {
|
|
499
|
+
await upsertMessage(id, (await lastSeq(id)) + 1, {
|
|
500
|
+
bot: null,
|
|
501
|
+
parent: null,
|
|
502
|
+
role: "user",
|
|
503
|
+
content: text,
|
|
504
|
+
note: true,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* The write that tells anyone a run ended at all. Tried again: everything else
|
|
510
|
+
* in the run has happened, and a miss leaves the row `running` until the next
|
|
511
|
+
* boot. Writes are serialised, so what is left is a database that briefly
|
|
512
|
+
* cannot be written to (database/db.ts).
|
|
513
|
+
*/
|
|
514
|
+
async function writeEnding(
|
|
515
|
+
id: string,
|
|
516
|
+
patch: Parameters<typeof updateTask>[1],
|
|
517
|
+
) {
|
|
518
|
+
for (const wait of [1_000, 3_000, null]) {
|
|
519
|
+
try {
|
|
520
|
+
await updateTask(id, patch);
|
|
521
|
+
return;
|
|
522
|
+
} catch (cause) {
|
|
523
|
+
if (wait === null) throw cause;
|
|
524
|
+
logger.warn(`task ${id}: ending not written, trying again`, cause);
|
|
525
|
+
await new Promise((resolve) => setTimeout(resolve, wait));
|
|
526
|
+
}
|
|
239
527
|
}
|
|
240
528
|
}
|
|
241
529
|
|
|
@@ -258,14 +546,14 @@ function launch(id: string, input: { bot: string; messages: ModelMessage[] }) {
|
|
|
258
546
|
},
|
|
259
547
|
};
|
|
260
548
|
running.set(id, run);
|
|
261
|
-
//
|
|
262
|
-
after(()
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
|
|
549
|
+
// Held by the server, not by a request: a run also starts from a returning
|
|
550
|
+
// browser and a retry timer, where `after()` throws (no request) or waits for
|
|
551
|
+
// the event stream to close
|
|
552
|
+
void drive(id, input, stop.signal, notes)
|
|
553
|
+
.catch((cause) => {
|
|
554
|
+
logger.error(`task ${id}`, cause);
|
|
555
|
+
})
|
|
556
|
+
.finally(finish);
|
|
269
557
|
}
|
|
270
558
|
|
|
271
559
|
/**
|
|
@@ -282,6 +570,9 @@ class ThreadWriter {
|
|
|
282
570
|
{ assistant: number | null; tool: number | null; parts: StepParts }
|
|
283
571
|
>();
|
|
284
572
|
|
|
573
|
+
/** Set once the run is over: a borrowed run still unwinding must not write into a thread a resume has taken. */
|
|
574
|
+
private closed = false;
|
|
575
|
+
|
|
285
576
|
constructor(
|
|
286
577
|
private taskId: string,
|
|
287
578
|
seq: number,
|
|
@@ -289,6 +580,25 @@ class ThreadWriter {
|
|
|
289
580
|
this.seq = seq;
|
|
290
581
|
}
|
|
291
582
|
|
|
583
|
+
close() {
|
|
584
|
+
this.closed = true;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* A line from the app rather than from anyone in the room. A user row so a
|
|
589
|
+
* resumed run reads it as something it was told, and `note` so the screen
|
|
590
|
+
* draws it as a note and `rosterOf` does not take it for a person speaking.
|
|
591
|
+
*/
|
|
592
|
+
async note(text: string) {
|
|
593
|
+
await upsertMessage(this.taskId, ++this.seq, {
|
|
594
|
+
bot: null,
|
|
595
|
+
parent: null,
|
|
596
|
+
role: "user",
|
|
597
|
+
content: text,
|
|
598
|
+
note: true,
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
|
|
292
602
|
private step(event: TaskEvent) {
|
|
293
603
|
const key = `${event.bot} ${event.parent ?? ""}`;
|
|
294
604
|
let step = this.steps.get(key);
|
|
@@ -307,7 +617,7 @@ class ThreadWriter {
|
|
|
307
617
|
seq: number,
|
|
308
618
|
event: TaskEvent,
|
|
309
619
|
message: ModelMessage,
|
|
310
|
-
extra: { compact?: boolean } = {},
|
|
620
|
+
extra: { compact?: boolean; note?: boolean } = {},
|
|
311
621
|
) {
|
|
312
622
|
const input: TaskMessageInput = {
|
|
313
623
|
bot: event.bot,
|
|
@@ -315,11 +625,13 @@ class ThreadWriter {
|
|
|
315
625
|
role: message.role,
|
|
316
626
|
content: message.content,
|
|
317
627
|
compact: extra.compact ?? false,
|
|
628
|
+
note: extra.note ?? false,
|
|
318
629
|
};
|
|
319
630
|
return upsertMessage(this.taskId, seq, input);
|
|
320
631
|
}
|
|
321
632
|
|
|
322
633
|
async on(event: TaskEvent) {
|
|
634
|
+
if (this.closed) return;
|
|
323
635
|
const step = this.step(event);
|
|
324
636
|
switch (event.type) {
|
|
325
637
|
case "text":
|
|
@@ -350,8 +662,9 @@ class ThreadWriter {
|
|
|
350
662
|
type: "tool-result",
|
|
351
663
|
toolCallId: event.id,
|
|
352
664
|
toolName: event.name,
|
|
353
|
-
output:
|
|
354
|
-
|
|
665
|
+
output: event.error
|
|
666
|
+
? { type: "error-text", value: String(event.output) }
|
|
667
|
+
: typeof event.output === "string"
|
|
355
668
|
? { type: "text", value: event.output }
|
|
356
669
|
: { type: "json", value: event.output as never },
|
|
357
670
|
});
|
|
@@ -387,7 +700,7 @@ class ThreadWriter {
|
|
|
387
700
|
++this.seq,
|
|
388
701
|
event,
|
|
389
702
|
{ role: "user", content: event.text },
|
|
390
|
-
{ compact: true },
|
|
703
|
+
{ compact: true, note: true },
|
|
391
704
|
);
|
|
392
705
|
|
|
393
706
|
case "interjection":
|
|
@@ -420,7 +733,16 @@ async function drive(
|
|
|
420
733
|
let ending: {
|
|
421
734
|
status: TaskStatus;
|
|
422
735
|
outcome: string;
|
|
423
|
-
pending:
|
|
736
|
+
pending: TaskPending | null;
|
|
737
|
+
} | null = null;
|
|
738
|
+
/**
|
|
739
|
+
* What broke, as the provider said it — the thread carries it too (below) —
|
|
740
|
+
* and whose it is to fix (model.ts modelFailureOf).
|
|
741
|
+
*/
|
|
742
|
+
let broken: {
|
|
743
|
+
message: string;
|
|
744
|
+
failure: ModelFailure;
|
|
745
|
+
budget?: number;
|
|
424
746
|
} | null = null;
|
|
425
747
|
|
|
426
748
|
try {
|
|
@@ -453,18 +775,23 @@ async function drive(
|
|
|
453
775
|
outcome: event.question,
|
|
454
776
|
pending: { toolCallId: event.id, options: event.options },
|
|
455
777
|
};
|
|
456
|
-
} else if (event.type === "
|
|
457
|
-
// An
|
|
458
|
-
// The outcome is the
|
|
459
|
-
// thread line (bot.query linesOf).
|
|
460
|
-
ending =
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
778
|
+
} else if (event.type === "answer") {
|
|
779
|
+
// An answer ends the job; one the app stopped (bot.run `stopped`) waits
|
|
780
|
+
// with the continue option. The outcome is the answer text verbatim;
|
|
781
|
+
// the same text is the thread line (bot.query linesOf).
|
|
782
|
+
ending = event.stopped
|
|
783
|
+
? {
|
|
784
|
+
status: "waiting",
|
|
785
|
+
outcome: event.text,
|
|
786
|
+
pending: { toolCallId: null, options: [TASK_CONTINUE] },
|
|
787
|
+
}
|
|
788
|
+
: { status: "done", outcome: event.text, pending: null };
|
|
467
789
|
} else if (event.type === "error") {
|
|
790
|
+
broken = {
|
|
791
|
+
message: event.message,
|
|
792
|
+
failure: event.failure,
|
|
793
|
+
budget: event.budget,
|
|
794
|
+
};
|
|
468
795
|
ending = {
|
|
469
796
|
status: "failed",
|
|
470
797
|
outcome: broke(event.message),
|
|
@@ -474,16 +801,22 @@ async function drive(
|
|
|
474
801
|
},
|
|
475
802
|
});
|
|
476
803
|
} catch (cause) {
|
|
804
|
+
broken = {
|
|
805
|
+
message: modelErrorToString(cause),
|
|
806
|
+
failure: modelFailureOf(cause),
|
|
807
|
+
};
|
|
477
808
|
ending = {
|
|
478
809
|
status: "failed",
|
|
479
|
-
outcome: broke(
|
|
810
|
+
outcome: broke(broken.message),
|
|
480
811
|
pending: null,
|
|
481
812
|
};
|
|
482
813
|
} finally {
|
|
814
|
+
thread.close();
|
|
483
815
|
running.delete(id);
|
|
484
816
|
}
|
|
485
817
|
|
|
486
|
-
// Whoever aborted writes the row: cancel marks failed, answerTask relaunches
|
|
818
|
+
// Whoever aborted writes the row: cancel marks failed, answerTask relaunches,
|
|
819
|
+
// a pause parks.
|
|
487
820
|
if (signal.aborted) return;
|
|
488
821
|
|
|
489
822
|
const final = ending ?? {
|
|
@@ -491,15 +824,49 @@ async function drive(
|
|
|
491
824
|
outcome: "Stopped without handing anything back.",
|
|
492
825
|
pending: null,
|
|
493
826
|
};
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
endedAt: final.status === "waiting" ? null : new Date(),
|
|
498
|
-
});
|
|
827
|
+
// A break a moment or a compaction can fix is the app's to pick back up, not
|
|
828
|
+
// a failure for a person to find (parkTask)
|
|
829
|
+
const park = broken && broken.failure !== "fatal" ? broken : null;
|
|
499
830
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
831
|
+
try {
|
|
832
|
+
if (park) {
|
|
833
|
+
await parkTask(id, {
|
|
834
|
+
why:
|
|
835
|
+
park.failure === "overflow"
|
|
836
|
+
? `The model refused the context as too long (${park.message}); it is compacted before going on.`
|
|
837
|
+
: `The model call failed (${park.message}).`,
|
|
838
|
+
retry: park.failure === "transient",
|
|
839
|
+
budget: park.budget,
|
|
840
|
+
});
|
|
841
|
+
} else {
|
|
842
|
+
// A thread that simply stops cannot be read: the room shows a tool call
|
|
843
|
+
// with no answer, and a resumed run has no idea why. The task row says it
|
|
844
|
+
// too, but the row is a status and this is the story. Never at the cost of
|
|
845
|
+
// the status write, which is what tells anyone the job ended at all.
|
|
846
|
+
if (final.status === "failed") {
|
|
847
|
+
await thread
|
|
848
|
+
.note(`The run stopped here: ${broken?.message ?? final.outcome}`)
|
|
849
|
+
.catch((cause) =>
|
|
850
|
+
logger.warn(`task ${id}: break not written`, cause),
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
await writeEnding(id, {
|
|
854
|
+
...final,
|
|
855
|
+
seen: false,
|
|
856
|
+
endedAt: final.status === "waiting" ? null : new Date(),
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
} catch (cause) {
|
|
860
|
+
// Said plainly rather than thrown into a promise nobody awaits; the row
|
|
861
|
+
// stays `running`, which the next boot reconciles (sweepTasks)
|
|
862
|
+
logger.error(`task ${id}: could not record how it ended`, cause);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// A waiting job keeps its browser: answering resumes into the page it left
|
|
867
|
+
// off at. An ended one closes only what nobody can see (closeHiddenBrowser).
|
|
868
|
+
if (park || final.status === "waiting") void pruneJobFiles();
|
|
869
|
+
else void closeHiddenBrowser(id);
|
|
503
870
|
|
|
504
871
|
const task = await findTask(id);
|
|
505
872
|
if (!task) return;
|
|
@@ -515,6 +882,9 @@ async function drive(
|
|
|
515
882
|
return;
|
|
516
883
|
}
|
|
517
884
|
|
|
885
|
+
// A parked job picks itself back up; nobody needs telling yet
|
|
886
|
+
if (park) return;
|
|
887
|
+
|
|
518
888
|
await announce(task.label, final);
|
|
519
889
|
|
|
520
890
|
// A finished job naming a document opens it on the screen (workspace artifact-view).
|
|
@@ -526,7 +896,7 @@ async function drive(
|
|
|
526
896
|
}
|
|
527
897
|
}
|
|
528
898
|
|
|
529
|
-
/** The document
|
|
899
|
+
/** The document an answer names: the artifacts folder first, otherwise the first drawable file. */
|
|
530
900
|
function artifactIn(outcome: string): string | null {
|
|
531
901
|
const paths = pathsIn(outcome);
|
|
532
902
|
return (
|