thursday-agent 0.2.0 → 0.4.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 -2
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +5 -5
- package/.next/routes-manifest.json +24 -6
- 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/page_client-reference-manifest.js +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.js +14 -0
- package/.next/server/app/api/bot/{notes → memory}/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/bot/route.js +6 -6
- package/.next/server/app/api/bot/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/task/[id]/route.js +8 -8
- 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 +5 -5
- 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 +9 -8
- 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 +4 -4
- package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/oauth/callback/route.js +5 -5
- package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/route.js +4 -4
- package/.next/server/app/api/mcp/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/tools/route.js +4 -4
- 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 +6 -7
- 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 +17 -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 +57 -90
- package/.next/server/app/page.js +10 -10
- 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 -2
- 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 +1 -1
- 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 +5 -5
- 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 +12 -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/_0-73of8._.js +5 -5
- package/.next/server/chunks/_0-fjql4._.js +26 -0
- package/.next/server/chunks/_00xh_q0._.js +25 -0
- 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 +134 -0
- package/.next/server/chunks/{_0vnutv9._.js → _0ioz3nd._.js} +1 -1
- package/.next/server/chunks/_0iwfby5._.js +3 -0
- package/.next/server/chunks/_0mecv0f._.js +26 -0
- package/.next/server/chunks/_0mh8j4m._.js +3 -0
- package/.next/server/chunks/_0n74zsf._.js +4 -4
- package/.next/server/chunks/_0obojvv._.js +3 -0
- package/.next/server/chunks/_0recufk._.js +49 -0
- package/.next/server/chunks/_0rnf-6n._.js +4 -4
- package/.next/server/chunks/_0sb7tlz._.js +3 -0
- package/.next/server/chunks/_0u10wmw._.js +5 -5
- package/.next/server/chunks/_0u4aiy2._.js +3 -0
- 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/_18-1wcc._.js +5 -5
- package/.next/server/chunks/_1_5mnq4._.js +4 -4
- package/.next/server/chunks/_1_9mjx-._.js +3 -0
- package/.next/server/chunks/{_0pppbb5._.js → _1c78vw5._.js} +166 -37
- package/.next/server/chunks/_1d0j961._.js +6 -0
- package/.next/server/chunks/_1d5zmy8._.js +1 -1
- package/.next/server/chunks/_1drgfx4._.js +4 -4
- 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/_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 +3 -0
- package/.next/server/chunks/features_memory_1uqvksn._.js +6 -0
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0a1rd09._.js → node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_06067w6._.js → node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_096ais_._.js → node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js} +1 -1
- package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_02s3hjt._.js → node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js} +1 -1
- 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_0tvkfgh._.js → node_modules_consola_dist_chunks_prompt_mjs_1y49572._.js} +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__092knlj._.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]__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]__0s9dq5u._.js +3 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__0m1b5ky._.js → [root-of-the-server]__0s9l2sv._.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]__0xsog8n._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0xtssj3._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +61 -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]__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]__1qfqvmg._.js → [root-of-the-server]__202p40z._.js} +2 -2
- package/.next/server/chunks/ssr/{_1mznrxk._.js → _001_ms1._.js} +3 -3
- package/.next/server/chunks/ssr/_01n3o0m._.js +3 -0
- package/.next/server/chunks/ssr/_0ap2fzn._.js +3 -0
- package/.next/server/chunks/ssr/_0fz4mf_._.js +3 -0
- package/.next/server/chunks/ssr/_0gb4gmf._.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/_0ilna52._.js +42 -0
- package/.next/server/chunks/ssr/_0n3toaw._.js +3 -0
- package/.next/server/chunks/ssr/{_13punpm._.js → _0q0zan6._.js} +2 -2
- package/.next/server/chunks/ssr/{_077-g6s._.js → _0s99bgb._.js} +3 -3
- package/.next/server/chunks/ssr/_0zcjrbg._.js +3 -0
- package/.next/server/chunks/ssr/_0zhoc3r._.js +3 -0
- package/.next/server/chunks/ssr/{_1lip4th._.js → _1-_etts._.js} +2 -2
- package/.next/server/chunks/ssr/_1-teee5._.js +3 -3
- package/.next/server/chunks/ssr/_13fke0x._.js +3 -0
- package/.next/server/chunks/ssr/_15j2_8f._.js +3 -0
- package/.next/server/chunks/ssr/_1b2mjwr._.js +3 -0
- package/.next/server/chunks/ssr/{_09ja_w1._.js → _1f-dg-6._.js} +2 -2
- package/.next/server/chunks/ssr/_1fojd41._.js +4 -0
- package/.next/server/chunks/ssr/_1gd8q8l._.js +3 -0
- package/.next/server/chunks/ssr/{_1m3bsfr._.js → _1h0rw11._.js} +2 -2
- package/.next/server/chunks/ssr/_1jhd09t._.js +3 -0
- package/.next/server/chunks/ssr/{_040sk32._.js → _1lz_cq2._.js} +84 -88
- package/.next/server/chunks/ssr/_1nnsk7z._.js +3 -0
- package/.next/server/chunks/ssr/_1sji22n._.js +3 -0
- package/.next/server/chunks/ssr/{_0x_nu5e._.js → _1vi_uo7._.js} +2 -2
- package/.next/server/chunks/ssr/_1vyd1ji._.js +1 -1
- 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/{node_modules_0kxz4gt._.js → node_modules_00etblx._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_18_dk7_._.js → node_modules_04jf_m8._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0_n241r._.js → node_modules_08dhkiq._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0n1kj4p._.js → node_modules_0940ns5._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_17lrt3y._.js → node_modules_09q35v_._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1toafc-._.js → node_modules_0_-_a--._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0lrjk5t._.js → node_modules_0arus10._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_04n7mjs._.js → node_modules_0b__sgl._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0iz1rzd._.js → node_modules_0cxaxk9._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0ndvxub._.js → node_modules_0g7fzk3._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0kl7-tn._.js → node_modules_0had7xd._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_19dp7ko._.js → node_modules_0pvd7q-._.js} +1 -1
- package/.next/server/chunks/ssr/node_modules_0x3-ply._.js +3 -0
- package/.next/server/chunks/ssr/{node_modules_1dwguw_._.js → node_modules_0yugy6m._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_004qlr4._.js → node_modules_14om4ar._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1q0p85z._.js → node_modules_14q6g4n._.js} +1 -1
- package/.next/server/chunks/ssr/node_modules_17bwo43._.js +55 -0
- package/.next/server/chunks/ssr/{node_modules_1hd-5tv._.js → node_modules_198nmll._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0m93zeg._.js → node_modules_1_pc9kq._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1n5ygqe._.js → node_modules_1aaxuef._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_01qnv-a._.js → node_modules_1cx_ql6._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1zu988w._.js → node_modules_1cz2hle._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1xyd7ov._.js → node_modules_1efrqxi._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_13r44jq._.js → node_modules_1eg7m6c._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_08d8bke._.js → node_modules_1gdh31p._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1hn8z1f._.js → node_modules_1hpopmo._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_20yebtj._.js → node_modules_1qpjvy5._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_09xhur7._.js → node_modules_1vh5ntv._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0m9a4y0._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1b748ic._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_13w_wy9._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1z4hm5e._.js} +1 -1
- package/.next/server/chunks/ssr/node_modules_@vercel_oidc_dist_06mk8id._.js +3 -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 +58 -91
- package/.next/static/chunks/00rd4-v8r7axp.js +1 -0
- package/.next/static/chunks/08qe4as2q428z.js +3 -0
- package/.next/static/chunks/{31ttnjt6g35a0.js → 0ev4hyghq0mbb.js} +1 -1
- package/.next/static/chunks/0fl3gwe4-l6tz.js +1 -0
- package/.next/static/chunks/0gnqdjn2lvdad.js +2 -0
- package/.next/static/chunks/0hwap1-p0m5sa.js +1 -0
- package/.next/static/chunks/0r5qcctujhxli.js +1 -0
- package/.next/static/chunks/0w52rrrmuj9r9.js +1 -0
- package/.next/static/chunks/{07kl352c-lvcz.js → 0wcprt5ot5she.js} +1 -1
- package/.next/static/chunks/10teww7wt-f6h.js +1 -0
- package/.next/static/chunks/15m575979un5f.js +38 -0
- package/.next/static/chunks/17p6tk6k88dq6.js +1 -0
- package/.next/static/chunks/{3_h9txt3tq8t8.js → 1dkjg87pxk0n9.js} +1 -1
- package/.next/static/chunks/1jd09sxcjddu1.js +1 -0
- package/.next/static/chunks/1kq8h8wi_e0bc.js +53 -0
- package/.next/static/chunks/{18vhba44l1fc9.js → 1w73ece_6bheu.js} +1 -1
- package/.next/static/chunks/{3ard_noqapnw1.js → 214ya3n5gxeih.js} +1 -1
- package/.next/static/chunks/22_zkas21rpna.js +1 -0
- package/.next/static/chunks/2h0sd2vumhb15.js +1 -0
- package/.next/static/chunks/2t4vhi3m8ahya.js +1 -0
- package/.next/static/chunks/2tigdtz3dpcy8.js +1 -0
- package/.next/static/chunks/2u7xt6mxg44lf.js +1 -0
- package/.next/static/chunks/39j0fvpybzabl.js +40 -0
- package/.next/static/chunks/3akmqm77muj4-.js +1 -0
- package/.next/static/chunks/3cq5g494yuke8.css +1 -0
- package/.next/static/chunks/3woj-xd7ki5_i.js +1 -0
- package/.next/static/chunks/3xk7yqgomx7yq.js +1 -0
- package/.next/static/chunks/3zmcsnuo25zvq.js +1 -0
- package/.next/static/media/favicon.37o1pjldwi2uc.ico +0 -0
- package/README.md +47 -22
- 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.ts +3 -7
- package/app/api/llm-model/credits/route.ts +11 -0
- package/app/api/llm-model/route.ts +6 -1
- 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 +19 -4
- package/bin/port.mjs +65 -0
- package/bin/thursday.mjs +5 -33
- package/components/ui/shiny-text.tsx +48 -134
- package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/migration.sql +24 -34
- package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/snapshot.json +71 -145
- package/database/migrations/20260911030320_opposite_jack_power/migration.sql +1 -0
- package/database/migrations/{20260909063821_bitter_tenebrous → 20260911030320_opposite_jack_power}/snapshot.json +57 -184
- package/docs/how-it-works.md +11 -7
- package/docs/images/face-dark.png +0 -0
- package/docs/images/face-light.png +0 -0
- package/docs/images/keeps-going.png +0 -0
- package/features/ai/chatgpt.ts +639 -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 +78 -56
- package/features/ai/model.schema.ts +232 -34
- package/features/ai/model.ts +169 -24
- package/features/ai/prompts/bot.prompt.ts +207 -114
- package/features/ai/prompts/memory-edit.prompt.ts +33 -0
- package/features/ai/prompts/prompt-helper.ts +45 -26
- package/features/ai/prompts/thursday.prompt.ts +57 -27
- package/features/ai/tools/bot.tool.ts +35 -52
- package/features/ai/tools/connected.ts +17 -4
- package/features/ai/tools/memory.tool.ts +181 -117
- package/features/ai/tools/search.tool.ts +136 -47
- package/features/ai/tools/tool-name.ts +2 -6
- package/features/ai/tools/workspace.tool.ts +5 -1
- package/features/bot/bot.action.ts +14 -19
- package/features/bot/bot.memory.ts +89 -0
- package/features/bot/bot.query.ts +37 -57
- package/features/bot/bot.run.ts +512 -242
- package/features/bot/bot.runner.ts +434 -120
- package/features/bot/bot.schema.ts +104 -19
- package/features/bot/bot.seed.ts +89 -16
- package/features/bot/components/bot-mark.tsx +122 -20
- package/features/bot/components/bot-room.tsx +214 -132
- package/features/bot/components/bot-setting.tsx +790 -402
- package/features/bot/components/bot-tool.tsx +2 -7
- 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 +240 -34
- package/features/bot/task.store.ts +76 -13
- 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 +340 -0
- package/features/memory/components/memory-setting.tsx +75 -77
- package/features/memory/memory.action.ts +3 -43
- package/features/memory/memory.edit.ts +87 -0
- package/features/memory/memory.query.ts +24 -42
- package/features/memory/memory.schema.ts +29 -106
- package/features/settings/components/settings.tsx +2 -0
- package/features/settings/settings.alert.ts +3 -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 -98
- 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 -12
- package/features/thursday/use-thursday.ts +87 -60
- package/features/workspace/components/file-view.tsx +4 -2
- package/features/workspace/workspace.ts +110 -26
- package/lib/limits.ts +1 -1
- package/lib/oauth-page.ts +27 -0
- package/lib/realtime/openai.ts +2 -2
- package/lib/realtime/realtime.protocol.ts +1 -1
- package/lib/realtime/realtime.tap.ts +122 -0
- package/lib/sandbox.ts +59 -36
- package/package.json +1 -1
- package/skills/browser/SKILL.md +55 -34
- package/.next/server/app/api/bot/notes/route/app-paths-manifest.json +0 -3
- package/.next/server/app/api/bot/notes/route.js +0 -14
- package/.next/server/app/api/bot/notes/route_client-reference-manifest.js +0 -3
- package/.next/server/app/api/memory/tidy/route/app-paths-manifest.json +0 -3
- package/.next/server/app/api/memory/tidy/route.js +0 -22
- package/.next/server/app/api/memory/tidy/route.js.nft.json +0 -1
- package/.next/server/chunks/0d-b_next_dist_server_app-render_after-task-async-storage_external_0-exn7p.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0-npkh_._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__005var5._.js +0 -3
- 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]__04_8spk._.js +0 -3
- 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]__0cro2dz._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__0dupqt7._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__0emr6go._.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]__0p32jfz._.js +0 -12
- package/.next/server/chunks/[root-of-the-server]__0phdgco._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__0wvgrsl._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__10qshki._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__11j52t0._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__1692zrv._.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_aoyr9._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1bn73ih._.js +0 -10
- 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]__1e-ci13._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1fboj2j._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1lr7j9t._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__1oli73c._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1txedx6._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__1untqv8._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__1zgpz1w._.js +0 -3
- package/.next/server/chunks/_00_584r._.js +0 -293
- 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/_0nn99o2._.js +0 -3
- package/.next/server/chunks/_0zuzmt_._.js +0 -39
- package/.next/server/chunks/_106co2o._.js +0 -3
- package/.next/server/chunks/_12bbv5i._.js +0 -100
- package/.next/server/chunks/_15q1pig._.js +0 -3
- package/.next/server/chunks/_19wg5yn._.js +0 -138
- package/.next/server/chunks/_1bt95p9._.js +0 -55
- package/.next/server/chunks/_1cbk7ms._.js +0 -26
- package/.next/server/chunks/_1drv2et._.js +0 -40
- package/.next/server/chunks/_1ic3bew._.js +0 -5
- package/.next/server/chunks/_1mxn_lb._.js +0 -3
- package/.next/server/chunks/_1rysr-r._.js +0 -10
- package/.next/server/chunks/_1u3rwbr._.js +0 -3
- package/.next/server/chunks/_1x7p319._.js +0 -6
- package/.next/server/chunks/_next-internal_server_app_api_bot_notes_route_actions_0qcsyu7.js +0 -3
- package/.next/server/chunks/_next-internal_server_app_api_memory_tidy_route_actions_0_cfuom.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_0gzvgfv._.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_1tpvamf._.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_1y9-wcr._.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]__0iuoa-r._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0un-erv._.js +0 -4
- package/.next/server/chunks/ssr/[root-of-the-server]__1-mnhyd._.js +0 -92
- package/.next/server/chunks/ssr/[root-of-the-server]__1bww500._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__1vcdast._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__1xwnu-h._.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/_03webdr._.js +0 -3
- package/.next/server/chunks/ssr/_09-0k3z._.js +0 -3
- package/.next/server/chunks/ssr/_0f_b_9s._.js +0 -3
- package/.next/server/chunks/ssr/_0fafgvl._.js +0 -3
- package/.next/server/chunks/ssr/_0sf1isi._.js +0 -3
- package/.next/server/chunks/ssr/_0su6_08._.js +0 -3
- package/.next/server/chunks/ssr/_0ti51xc._.js +0 -3
- package/.next/server/chunks/ssr/_0w5bgak._.js +0 -3
- package/.next/server/chunks/ssr/_0y84qo6._.js +0 -3
- package/.next/server/chunks/ssr/_1ciyoo3._.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/_1g6l4uj._.js +0 -3
- package/.next/server/chunks/ssr/_1ruzehw._.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/node_modules_zod_v4_classic_external_15fmmz3.js +0 -55
- package/.next/static/chunks/05b6nx_o3_f_n.js +0 -1
- package/.next/static/chunks/0dmns-gi0raa4.js +0 -1
- package/.next/static/chunks/0f9sq-7q_yxyl.js +0 -1
- package/.next/static/chunks/0oc4_xoia77dg.css +0 -1
- package/.next/static/chunks/0pheo8m3a-rzi.js +0 -1
- package/.next/static/chunks/19i8h2t-5evjx.js +0 -1
- package/.next/static/chunks/1c5fcj473025q.js +0 -1
- package/.next/static/chunks/1pi_hbmjw-f-z.js +0 -1
- package/.next/static/chunks/1twt6k09vg4np.js +0 -1
- package/.next/static/chunks/1ytnip8wdng93.js +0 -1
- package/.next/static/chunks/28gotuisldmom.js +0 -1
- package/.next/static/chunks/2998p0y7k1c8z.js +0 -3
- package/.next/static/chunks/29gyb3nubj51j.js +0 -53
- package/.next/static/chunks/2l233xfycjpd8.js +0 -1
- package/.next/static/chunks/2p5n7pa3c40t-.js +0 -2
- package/.next/static/chunks/2ru1q132af7h7.js +0 -1
- package/.next/static/chunks/2t8wqycwg3y04.js +0 -2
- package/.next/static/chunks/2uxum7qbyeyxd.js +0 -1
- package/.next/static/chunks/32z_ypgtchw48.js +0 -1
- package/.next/static/chunks/33pyjb3xd1iez.js +0 -1
- package/.next/static/chunks/3omud5xunrk1f.js +0 -1
- package/.next/static/chunks/42dnrkbph9e-1.js +0 -1
- package/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
- package/database/migrations/20260909063821_bitter_tenebrous/migration.sql +0 -1
- package/features/ai/prompts/memory-tidy.prompt.ts +0 -129
- package/features/ai/tools/tidy.tool.ts +0 -22
- package/features/bot/bot.notes.ts +0 -120
- package/features/memory/components/memory-tidy.tsx +0 -395
- package/features/memory/components/memory-view.tsx +0 -84
- 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/bot/{notes → memory/files}/route/build-manifest.json +0 -0
- /package/.next/server/app/api/bot/{notes → memory/files}/route/server-reference-manifest.json +0 -0
- /package/.next/server/app/api/bot/{notes → memory/files}/route.js.map +0 -0
- /package/.next/server/app/api/{memory/tidy → bot/memory}/route/build-manifest.json +0 -0
- /package/.next/server/app/api/{memory/tidy → bot/memory}/route/server-reference-manifest.json +0 -0
- /package/.next/server/app/api/{memory/tidy → bot/memory}/route.js.map +0 -0
- /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → kaTO0UHqF1bMnWgCDik2f}/_buildManifest.js +0 -0
- /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → kaTO0UHqF1bMnWgCDik2f}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → kaTO0UHqF1bMnWgCDik2f}/_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,
|
|
@@ -14,34 +21,51 @@ import {
|
|
|
14
21
|
} from "@/features/thursday/thursday.query";
|
|
15
22
|
import { pathsIn } from "@/features/workspace/file-kind";
|
|
16
23
|
import {
|
|
24
|
+
closeHiddenBrowser,
|
|
17
25
|
closeJobShell,
|
|
26
|
+
jobScratch,
|
|
27
|
+
listScratchFolders,
|
|
28
|
+
pruneJobFiles,
|
|
18
29
|
removeJobScratch,
|
|
30
|
+
removeUnchangedFolders,
|
|
19
31
|
} from "@/features/workspace/workspace";
|
|
20
32
|
import { desktopNotify } from "@/lib/desktop-notify";
|
|
21
33
|
import { logger } from "@/lib/logger";
|
|
22
34
|
import { publicError } from "@/lib/public-error";
|
|
23
35
|
import { createKeyedLock } from "@/lib/queue";
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
36
|
+
import { resumeThread, runBot, type TaskEvent } from "./bot.run";
|
|
37
|
+
import {
|
|
38
|
+
TASK_CONTINUE,
|
|
39
|
+
type TaskPending,
|
|
40
|
+
type TaskSpeaker,
|
|
41
|
+
type TaskStatus,
|
|
42
|
+
tagSpeaker,
|
|
43
|
+
} from "./bot.schema";
|
|
26
44
|
import {
|
|
27
45
|
addTaskUsage,
|
|
46
|
+
countStopsSinceSpoken,
|
|
28
47
|
deleteFinishedTasks,
|
|
29
48
|
deleteMessages,
|
|
30
49
|
deleteTask,
|
|
31
50
|
findTask,
|
|
32
51
|
insertTask,
|
|
33
52
|
lastSeq,
|
|
53
|
+
listAutoStoppedTasks,
|
|
54
|
+
listBorrowedTails,
|
|
34
55
|
listRunningTaskIds,
|
|
56
|
+
listTaskFolders,
|
|
35
57
|
listThread,
|
|
58
|
+
stopNote,
|
|
36
59
|
type TaskMessageInput,
|
|
37
60
|
updateTask,
|
|
38
61
|
upsertMessage,
|
|
39
62
|
} from "./task.query";
|
|
40
63
|
|
|
41
64
|
/**
|
|
42
|
-
* Runs a job
|
|
43
|
-
*
|
|
44
|
-
*
|
|
65
|
+
* Runs a job so it outlives the request, writing every event to the task's
|
|
66
|
+
* thread (task_message). A run always starts from the thread. `answerTask` is
|
|
67
|
+
* the one way a person adds to it, serialized per job by `taskLock`, and
|
|
68
|
+
* `resumeTask` the one way the app picks a job back up by itself.
|
|
45
69
|
*/
|
|
46
70
|
|
|
47
71
|
type Run = {
|
|
@@ -58,6 +82,8 @@ type Run = {
|
|
|
58
82
|
type Pinned = {
|
|
59
83
|
__botRuns?: Map<string, Run>;
|
|
60
84
|
__botTaskLock?: ReturnType<typeof createKeyedLock>;
|
|
85
|
+
__botResumes?: Map<string, ReturnType<typeof setTimeout>>;
|
|
86
|
+
__botPausing?: { current: Promise<void> };
|
|
61
87
|
};
|
|
62
88
|
|
|
63
89
|
/** Pinned to globalThis: next dev reloads this module under a running run, and the abort controller and lock must be the originals. */
|
|
@@ -70,20 +96,38 @@ const running: Map<string, Run> = ((globalThis as Pinned).__botRuns ??=
|
|
|
70
96
|
*/
|
|
71
97
|
const taskLock = ((globalThis as Pinned).__botTaskLock ??= createKeyedLock());
|
|
72
98
|
|
|
73
|
-
/**
|
|
99
|
+
/** When each parked job picks itself back up (scheduleResume); one timer per job. */
|
|
100
|
+
const resumes: Map<string, ReturnType<typeof setTimeout>> = ((
|
|
101
|
+
globalThis as Pinned
|
|
102
|
+
).__botResumes ??= new Map());
|
|
103
|
+
|
|
104
|
+
/** The pause under way, if any; a returning browser waits for it (resumeStoppedTasks). */
|
|
105
|
+
const pausing = ((globalThis as Pinned).__botPausing ??= {
|
|
106
|
+
current: Promise.resolve(),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
/** Opens a job. The opening message — who is on it, the job, the call it came from (bot.prompt buildTaskOpening) — is the thread's first row. */
|
|
74
110
|
export async function startTask(input: {
|
|
75
111
|
bot: string;
|
|
76
112
|
request: string;
|
|
77
113
|
label: string;
|
|
78
114
|
callId?: string | null;
|
|
115
|
+
/** Who handed it over: Thursday during a call, or the user on screen. */
|
|
116
|
+
from: TaskSpeaker;
|
|
79
117
|
}) {
|
|
80
|
-
const
|
|
81
|
-
|
|
118
|
+
const { from, ...row } = input;
|
|
119
|
+
const conversation = row.callId
|
|
120
|
+
? await listCallTurns(row.callId, OPENING_TURNS)
|
|
82
121
|
: [];
|
|
83
|
-
const opening = buildTaskOpening({
|
|
84
|
-
|
|
122
|
+
const opening = buildTaskOpening({
|
|
123
|
+
bot: row.bot,
|
|
124
|
+
request: row.request,
|
|
125
|
+
conversation,
|
|
126
|
+
from,
|
|
127
|
+
});
|
|
128
|
+
const task = await insertTask({ ...row, opening });
|
|
85
129
|
launch(task.id, {
|
|
86
|
-
bot:
|
|
130
|
+
bot: row.bot,
|
|
87
131
|
messages: [{ role: "user", content: opening }],
|
|
88
132
|
});
|
|
89
133
|
return task.id;
|
|
@@ -95,14 +139,25 @@ export async function startTask(input: {
|
|
|
95
139
|
* before its next step; the step in flight finishes), or a follow-up to a
|
|
96
140
|
* finished one. Only when the run has already ended does the running case
|
|
97
141
|
* fall through to stop, append, relaunch.
|
|
142
|
+
*
|
|
143
|
+
* @param from Who said it. The words go on the thread tagged with it (bot.schema
|
|
144
|
+
* tagSpeaker): Thursday passing something on from a call and the user typing on
|
|
145
|
+
* screen reach the bot down this one pipe, and a go-ahead means something
|
|
146
|
+
* different from each. Unset for words that already carry their tags — the notes
|
|
147
|
+
* a finished run left unread (drive).
|
|
98
148
|
*/
|
|
99
|
-
export async function answerTask(
|
|
149
|
+
export async function answerTask(
|
|
150
|
+
id: string,
|
|
151
|
+
answer: string,
|
|
152
|
+
from?: TaskSpeaker,
|
|
153
|
+
) {
|
|
154
|
+
const said = from ? tagSpeaker(from, answer) : answer;
|
|
100
155
|
return taskLock(id, async () => {
|
|
101
156
|
const task = await findTask(id);
|
|
102
157
|
if (!task) publicError("No such job.");
|
|
103
158
|
|
|
104
159
|
const live = running.get(id);
|
|
105
|
-
if (live && task.status === "running" && live.note(
|
|
160
|
+
if (live && task.status === "running" && live.note(said)) {
|
|
106
161
|
logger.debug(`task ${id}: interjection queued`);
|
|
107
162
|
return;
|
|
108
163
|
}
|
|
@@ -110,11 +165,13 @@ export async function answerTask(id: string, answer: string) {
|
|
|
110
165
|
live.stop.abort();
|
|
111
166
|
await live.done;
|
|
112
167
|
}
|
|
168
|
+
// A person picked it up; whatever the app meant to do by itself is moot
|
|
169
|
+
forgetResume(id);
|
|
113
170
|
|
|
114
|
-
const
|
|
171
|
+
const thread = await listThread(id);
|
|
172
|
+
const { reply, as } = joinThread(task, said, thread);
|
|
115
173
|
logger.debug(`task ${id}: ${as}`);
|
|
116
174
|
|
|
117
|
-
const thread = await listThread(id);
|
|
118
175
|
await upsertMessage(id, (await lastSeq(id)) + 1, {
|
|
119
176
|
bot: null,
|
|
120
177
|
parent: null,
|
|
@@ -125,14 +182,53 @@ export async function answerTask(id: string, answer: string) {
|
|
|
125
182
|
status: "running",
|
|
126
183
|
outcome: null,
|
|
127
184
|
pending: null,
|
|
128
|
-
|
|
185
|
+
seen: false,
|
|
129
186
|
endedAt: null,
|
|
130
187
|
});
|
|
131
|
-
//
|
|
132
|
-
launch(id, {
|
|
188
|
+
// Resumed on the rows as they were stored (bot.run resumeThread)
|
|
189
|
+
launch(id, {
|
|
190
|
+
bot: task.bot,
|
|
191
|
+
messages: resumeThread([...thread, reply], await listBorrowedTails(id)),
|
|
192
|
+
});
|
|
133
193
|
});
|
|
134
194
|
}
|
|
135
195
|
|
|
196
|
+
/**
|
|
197
|
+
* The `ask_thursday` calls still open in the step a job stopped on: a model can
|
|
198
|
+
* ask twice at once, and the one answer goes to each rather than leaving the
|
|
199
|
+
* second to read as a call cut off (bot.run resumeThread). A call that already
|
|
200
|
+
* has a result — arguments the tool refused — is not open, and the words go in
|
|
201
|
+
* as a turn instead: a second result for one call is refused outright.
|
|
202
|
+
*/
|
|
203
|
+
function openAsks(thread: ModelMessage[], stoppedOn: string): string[] {
|
|
204
|
+
const answered = new Set(
|
|
205
|
+
thread.flatMap((message) =>
|
|
206
|
+
message.role === "tool"
|
|
207
|
+
? message.content.flatMap((part) =>
|
|
208
|
+
part.type === "tool-result" ? [part.toolCallId] : [],
|
|
209
|
+
)
|
|
210
|
+
: [],
|
|
211
|
+
),
|
|
212
|
+
);
|
|
213
|
+
const step = thread.findLast(
|
|
214
|
+
(message) =>
|
|
215
|
+
message.role === "assistant" &&
|
|
216
|
+
typeof message.content !== "string" &&
|
|
217
|
+
message.content.some(
|
|
218
|
+
(part) => part.type === "tool-call" && part.toolCallId === stoppedOn,
|
|
219
|
+
),
|
|
220
|
+
);
|
|
221
|
+
const asks =
|
|
222
|
+
step?.role === "assistant" && typeof step.content !== "string"
|
|
223
|
+
? step.content.flatMap((part) =>
|
|
224
|
+
part.type === "tool-call" && part.toolName === TOOL_NAMES.ask_thursday
|
|
225
|
+
? [part.toolCallId]
|
|
226
|
+
: [],
|
|
227
|
+
)
|
|
228
|
+
: [stoppedOn];
|
|
229
|
+
return asks.filter((toolCallId) => !answered.has(toolCallId));
|
|
230
|
+
}
|
|
231
|
+
|
|
136
232
|
/**
|
|
137
233
|
* How a person's words enter the thread. A job stopped on `ask_thursday` gets
|
|
138
234
|
* them as that call's tool result (a call with no result would break the
|
|
@@ -140,23 +236,23 @@ export async function answerTask(id: string, answer: string) {
|
|
|
140
236
|
* continue has no call to answer, so it is a turn as well.
|
|
141
237
|
*/
|
|
142
238
|
function joinThread(
|
|
143
|
-
task: { status: TaskStatus; pending:
|
|
239
|
+
task: { status: TaskStatus; pending: TaskPending | null },
|
|
144
240
|
answer: string,
|
|
241
|
+
thread: ModelMessage[],
|
|
145
242
|
): { reply: ModelMessage; as: "answer" | "interruption" | "follow-up" } {
|
|
146
243
|
const pending = task.status === "waiting" ? task.pending : null;
|
|
147
|
-
|
|
244
|
+
const asks = pending?.toolCallId ? openAsks(thread, pending.toolCallId) : [];
|
|
245
|
+
if (asks.length) {
|
|
148
246
|
return {
|
|
149
247
|
as: "answer",
|
|
150
248
|
reply: {
|
|
151
249
|
role: "tool",
|
|
152
|
-
content:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
},
|
|
159
|
-
],
|
|
250
|
+
content: asks.map((toolCallId) => ({
|
|
251
|
+
type: "tool-result" as const,
|
|
252
|
+
toolCallId,
|
|
253
|
+
toolName: TOOL_NAMES.ask_thursday,
|
|
254
|
+
output: { type: "text" as const, value: answer },
|
|
255
|
+
})),
|
|
160
256
|
},
|
|
161
257
|
};
|
|
162
258
|
}
|
|
@@ -175,13 +271,17 @@ export async function cancelTask(id: string) {
|
|
|
175
271
|
return taskLock(id, async () => {
|
|
176
272
|
const task = await findTask(id);
|
|
177
273
|
if (!task) publicError("No such job.");
|
|
274
|
+
// A job that already ended has an answer in `outcome`; cancelling would
|
|
275
|
+
// write "Cancelled." over the thing it was run for.
|
|
276
|
+
if (task.endedAt) publicError("That job has already ended.");
|
|
277
|
+
forgetResume(id);
|
|
178
278
|
running.get(id)?.stop.abort();
|
|
179
279
|
await updateTask(id, {
|
|
180
280
|
status: "failed",
|
|
181
281
|
outcome: "Cancelled.",
|
|
182
282
|
pending: null,
|
|
183
283
|
// Nobody needs to be told what they just did themselves
|
|
184
|
-
|
|
284
|
+
seen: true,
|
|
185
285
|
endedAt: new Date(),
|
|
186
286
|
});
|
|
187
287
|
// Cancel is a real end, so the browser session closes here; the abort in
|
|
@@ -194,6 +294,7 @@ export async function cancelTask(id: string) {
|
|
|
194
294
|
export async function removeTask(id: string) {
|
|
195
295
|
return taskLock(id, async () => {
|
|
196
296
|
const task = await findTask(id);
|
|
297
|
+
forgetResume(id);
|
|
197
298
|
running.get(id)?.stop.abort();
|
|
198
299
|
running.delete(id);
|
|
199
300
|
void closeJobShell(id);
|
|
@@ -217,57 +318,230 @@ export async function removeFinishedTasks(): Promise<number> {
|
|
|
217
318
|
}
|
|
218
319
|
|
|
219
320
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
* (
|
|
321
|
+
* Clears what jobs left behind by age (config WORKSPACE_KEEP), at boot and on a
|
|
322
|
+
* timer (instrumentation): a job's folder once the job ended that long ago — a job
|
|
323
|
+
* running or waiting keeps its own however old — a scratch folder no job owns once
|
|
324
|
+
* it has not changed that long, and spilled output and browser snapshots that old
|
|
325
|
+
* (pruneJobFiles). A job's folder goes under the job's lock, so a word that picks
|
|
326
|
+
* the job back up in that moment never finds its material gone. Returns the
|
|
327
|
+
* folders that went.
|
|
328
|
+
*/
|
|
329
|
+
export async function sweepJobFiles(): Promise<string[]> {
|
|
330
|
+
const cutoff = Date.now() - WORKSPACE_KEEP.forMs;
|
|
331
|
+
const stale = (task: {
|
|
332
|
+
status: TaskStatus;
|
|
333
|
+
endedAt: Date | null;
|
|
334
|
+
updatedAt: Date;
|
|
335
|
+
}) =>
|
|
336
|
+
(task.status === "done" || task.status === "failed") &&
|
|
337
|
+
(task.endedAt ?? task.updatedAt).getTime() < cutoff;
|
|
338
|
+
|
|
339
|
+
// Folders on disk; each one a job owns is taken out as its job is read
|
|
340
|
+
const unowned = new Set(await listScratchFolders());
|
|
341
|
+
const removed: string[] = [];
|
|
342
|
+
for (const task of await listTaskFolders()) {
|
|
343
|
+
const folder = jobScratch(task.id, task.label);
|
|
344
|
+
if (!unowned.delete(folder) || !stale(task)) continue;
|
|
345
|
+
await taskLock(task.id, async () => {
|
|
346
|
+
const now = await findTask(task.id);
|
|
347
|
+
if (!now || !stale(now)) return;
|
|
348
|
+
await removeJobScratch(task.id, task.label);
|
|
349
|
+
removed.push(folder);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
removed.push(...(await removeUnchangedFolders([...unowned])));
|
|
353
|
+
await pruneJobFiles();
|
|
354
|
+
if (removed.length) {
|
|
355
|
+
logger.info(
|
|
356
|
+
`cleared ${removed.length} old job folder(s): ${removed.join(", ")}`,
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
return removed;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* At boot (instrumentation): rows the last process left as running are not
|
|
364
|
+
* running now. Each is parked the way every stop the app causes is (parkTask),
|
|
365
|
+
* so it picks itself back up once a browser is on the app. Nothing else needs
|
|
366
|
+
* to reconcile — a run that ends badly records it itself (drive), and the write
|
|
367
|
+
* that does so is durable (database/db.ts oneAtATime).
|
|
225
368
|
*/
|
|
226
369
|
export async function sweepTasks() {
|
|
227
370
|
for (const id of await listRunningTaskIds()) {
|
|
228
371
|
if (!running.has(id)) {
|
|
229
|
-
await
|
|
372
|
+
await parkTask(id, {
|
|
373
|
+
why: "The server restarted while this was running.",
|
|
374
|
+
});
|
|
230
375
|
}
|
|
231
376
|
}
|
|
232
377
|
}
|
|
233
378
|
|
|
234
379
|
/**
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
380
|
+
* The browser closed, or the server is going down (instrumentation): every run
|
|
381
|
+
* stops where it is and is parked (parkTask). All at once — a run slow to let go
|
|
382
|
+
* must not keep the others running. The thread stays, and so does the window: a
|
|
383
|
+
* resume carries on in the page it left off at, including a sign-in the user is
|
|
384
|
+
* mid-way through, which only that window can finish.
|
|
385
|
+
*/
|
|
386
|
+
export async function pauseTasks(reason: string) {
|
|
387
|
+
const work = Promise.all(
|
|
388
|
+
[...running].map(([id, run]) =>
|
|
389
|
+
taskLock(id, async () => {
|
|
390
|
+
run.stop.abort();
|
|
391
|
+
await run.done;
|
|
392
|
+
const task = await findTask(id);
|
|
393
|
+
if (!task || task.status !== "running") return;
|
|
394
|
+
await parkTask(id, { why: reason });
|
|
395
|
+
}).catch((cause) => logger.error(`task ${id}: pause`, cause)),
|
|
396
|
+
),
|
|
397
|
+
).then(() => {});
|
|
398
|
+
pausing.current = work;
|
|
399
|
+
await work;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* A browser is on the app again (instrumentation `presence.onBack`): every job
|
|
404
|
+
* the app parked picks itself back up — now, or when the wait a failed model
|
|
405
|
+
* call set runs out. A pause still under way is waited for first, so a quick
|
|
406
|
+
* reload does not miss what it parks.
|
|
239
407
|
*/
|
|
240
|
-
async function
|
|
241
|
-
await
|
|
408
|
+
export async function resumeStoppedTasks() {
|
|
409
|
+
await pausing.current;
|
|
410
|
+
for (const task of await listAutoStoppedTasks()) {
|
|
411
|
+
scheduleResume(task.id, task.retryAt - Date.now());
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** One timer per job: a newer stop replaces what an older one set. */
|
|
416
|
+
function scheduleResume(id: string, inMs: number) {
|
|
417
|
+
forgetResume(id);
|
|
418
|
+
resumes.set(
|
|
419
|
+
id,
|
|
420
|
+
setTimeout(
|
|
421
|
+
() => {
|
|
422
|
+
resumes.delete(id);
|
|
423
|
+
void resumeTask(id).catch((cause) =>
|
|
424
|
+
logger.error(`task ${id}: resume`, cause),
|
|
425
|
+
);
|
|
426
|
+
},
|
|
427
|
+
Math.max(0, inMs),
|
|
428
|
+
),
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function forgetResume(id: string) {
|
|
433
|
+
clearTimeout(resumes.get(id));
|
|
434
|
+
resumes.delete(id);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Picks a parked job back up. Only with a browser on the app — nothing runs
|
|
439
|
+
* without one, and its return tries again — and only if it is still parked: a
|
|
440
|
+
* person may have answered, cancelled or deleted it since. No turn is added,
|
|
441
|
+
* because nobody said anything; the note parkTask left is what the run reads last.
|
|
442
|
+
*/
|
|
443
|
+
async function resumeTask(id: string) {
|
|
444
|
+
if (!presence.watching) return;
|
|
445
|
+
await taskLock(id, async () => {
|
|
446
|
+
const task = await findTask(id);
|
|
447
|
+
if (!task || task.status !== "waiting" || !task.pending?.auto) return;
|
|
448
|
+
if (running.has(id)) return;
|
|
449
|
+
logger.debug(`task ${id}: picking back up`);
|
|
450
|
+
const thread = await listThread(id);
|
|
451
|
+
await updateTask(id, {
|
|
452
|
+
status: "running",
|
|
453
|
+
outcome: null,
|
|
454
|
+
pending: null,
|
|
455
|
+
seen: false,
|
|
456
|
+
endedAt: null,
|
|
457
|
+
});
|
|
458
|
+
launch(id, {
|
|
459
|
+
bot: task.bot,
|
|
460
|
+
messages: resumeThread(thread, await listBorrowedTails(id)),
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Stops a job the app stopped, rather than the bot or a person: a restart, a
|
|
467
|
+
* closed browser, a model call a retry or a compaction can fix. It waits with
|
|
468
|
+
* the one continue option like any stop, with a line in its thread saying why —
|
|
469
|
+
* the resumed run reads it — and picks itself back up (scheduleResume). Unless
|
|
470
|
+
* the app has already stopped it `BOT_RUN.autoResumes` times since a person last
|
|
471
|
+
* spoke to it: that is what a job that keeps taking the server down looks like,
|
|
472
|
+
* and it waits for a person instead.
|
|
473
|
+
*/
|
|
474
|
+
async function parkTask(
|
|
475
|
+
id: string,
|
|
476
|
+
stop: {
|
|
477
|
+
why: string;
|
|
478
|
+
/** A failed model call: wait before trying again (config BOT_RUN.retryAfterMs). */
|
|
479
|
+
retry?: boolean;
|
|
480
|
+
/** Where the job compacts from now on (bot.run `budget`). */
|
|
481
|
+
budget?: number;
|
|
482
|
+
},
|
|
483
|
+
) {
|
|
484
|
+
const stops = await countStopsSinceSpoken(id);
|
|
485
|
+
const auto = stops < BOT_RUN.autoResumes;
|
|
486
|
+
const waits = BOT_RUN.retryAfterMs;
|
|
487
|
+
const inMs =
|
|
488
|
+
auto && stop.retry ? waits[Math.min(stops, waits.length - 1)] : 0;
|
|
489
|
+
|
|
490
|
+
await writeNote(id, stopNote(stop.why)).catch((cause) =>
|
|
491
|
+
logger.warn(`task ${id}: stop not written`, cause),
|
|
492
|
+
);
|
|
493
|
+
await writeEnding(id, {
|
|
242
494
|
status: "waiting",
|
|
243
|
-
outcome:
|
|
244
|
-
|
|
245
|
-
|
|
495
|
+
outcome: auto
|
|
496
|
+
? `${stop.why} ${inMs ? `It tries again in ${spell(inMs)}.` : "It picks back up by itself."}`
|
|
497
|
+
: `${stop.why} It has stopped ${stops + 1} times in a row, so it waits for you. Everything it had done is still here.`,
|
|
498
|
+
pending: {
|
|
499
|
+
toolCallId: null,
|
|
500
|
+
options: [TASK_CONTINUE],
|
|
501
|
+
...(auto ? { auto: true, retryAt: Date.now() + inMs } : {}),
|
|
502
|
+
},
|
|
503
|
+
...(stop.budget ? { contextBudget: stop.budget } : {}),
|
|
504
|
+
seen: false,
|
|
246
505
|
endedAt: null,
|
|
247
506
|
});
|
|
507
|
+
if (auto) scheduleResume(id, inMs);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const spell = (ms: number) =>
|
|
511
|
+
ms < 60_000
|
|
512
|
+
? `${Math.round(ms / 1000)} seconds`
|
|
513
|
+
: `${Math.round(ms / 60_000)} minutes`;
|
|
514
|
+
|
|
515
|
+
/** A line from the app in a thread no run is writing (ThreadWriter.note is the one for a run that is). */
|
|
516
|
+
async function writeNote(id: string, text: string) {
|
|
517
|
+
await upsertMessage(id, (await lastSeq(id)) + 1, {
|
|
518
|
+
bot: null,
|
|
519
|
+
parent: null,
|
|
520
|
+
role: "user",
|
|
521
|
+
content: text,
|
|
522
|
+
note: true,
|
|
523
|
+
});
|
|
248
524
|
}
|
|
249
525
|
|
|
250
526
|
/**
|
|
251
|
-
* The
|
|
252
|
-
*
|
|
253
|
-
*
|
|
527
|
+
* The write that tells anyone a run ended at all. Tried again: everything else
|
|
528
|
+
* in the run has happened, and a miss leaves the row `running` until the next
|
|
529
|
+
* boot. Writes are serialised, so what is left is a database that briefly
|
|
530
|
+
* cannot be written to (database/db.ts).
|
|
254
531
|
*/
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
});
|
|
269
|
-
void closeJobShell(id);
|
|
270
|
-
});
|
|
532
|
+
async function writeEnding(
|
|
533
|
+
id: string,
|
|
534
|
+
patch: Parameters<typeof updateTask>[1],
|
|
535
|
+
) {
|
|
536
|
+
for (const wait of [1_000, 3_000, null]) {
|
|
537
|
+
try {
|
|
538
|
+
await updateTask(id, patch);
|
|
539
|
+
return;
|
|
540
|
+
} catch (cause) {
|
|
541
|
+
if (wait === null) throw cause;
|
|
542
|
+
logger.warn(`task ${id}: ending not written, trying again`, cause);
|
|
543
|
+
await new Promise((resolve) => setTimeout(resolve, wait));
|
|
544
|
+
}
|
|
271
545
|
}
|
|
272
546
|
}
|
|
273
547
|
|
|
@@ -290,14 +564,14 @@ function launch(id: string, input: { bot: string; messages: ModelMessage[] }) {
|
|
|
290
564
|
},
|
|
291
565
|
};
|
|
292
566
|
running.set(id, run);
|
|
293
|
-
//
|
|
294
|
-
after(()
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
|
|
567
|
+
// Held by the server, not by a request: a run also starts from a returning
|
|
568
|
+
// browser and a retry timer, where `after()` throws (no request) or waits for
|
|
569
|
+
// the event stream to close
|
|
570
|
+
void drive(id, input, stop.signal, notes)
|
|
571
|
+
.catch((cause) => {
|
|
572
|
+
logger.error(`task ${id}`, cause);
|
|
573
|
+
})
|
|
574
|
+
.finally(finish);
|
|
301
575
|
}
|
|
302
576
|
|
|
303
577
|
/**
|
|
@@ -314,6 +588,9 @@ class ThreadWriter {
|
|
|
314
588
|
{ assistant: number | null; tool: number | null; parts: StepParts }
|
|
315
589
|
>();
|
|
316
590
|
|
|
591
|
+
/** Set once the run is over: a borrowed run still unwinding must not write into a thread a resume has taken. */
|
|
592
|
+
private closed = false;
|
|
593
|
+
|
|
317
594
|
constructor(
|
|
318
595
|
private taskId: string,
|
|
319
596
|
seq: number,
|
|
@@ -321,6 +598,10 @@ class ThreadWriter {
|
|
|
321
598
|
this.seq = seq;
|
|
322
599
|
}
|
|
323
600
|
|
|
601
|
+
close() {
|
|
602
|
+
this.closed = true;
|
|
603
|
+
}
|
|
604
|
+
|
|
324
605
|
/**
|
|
325
606
|
* A line from the app rather than from anyone in the room. A user row so a
|
|
326
607
|
* resumed run reads it as something it was told, and `note` so the screen
|
|
@@ -368,6 +649,7 @@ class ThreadWriter {
|
|
|
368
649
|
}
|
|
369
650
|
|
|
370
651
|
async on(event: TaskEvent) {
|
|
652
|
+
if (this.closed) return;
|
|
371
653
|
const step = this.step(event);
|
|
372
654
|
switch (event.type) {
|
|
373
655
|
case "text":
|
|
@@ -398,8 +680,9 @@ class ThreadWriter {
|
|
|
398
680
|
type: "tool-result",
|
|
399
681
|
toolCallId: event.id,
|
|
400
682
|
toolName: event.name,
|
|
401
|
-
output:
|
|
402
|
-
|
|
683
|
+
output: event.error
|
|
684
|
+
? { type: "error-text", value: String(event.output) }
|
|
685
|
+
: typeof event.output === "string"
|
|
403
686
|
? { type: "text", value: event.output }
|
|
404
687
|
: { type: "json", value: event.output as never },
|
|
405
688
|
});
|
|
@@ -468,10 +751,17 @@ async function drive(
|
|
|
468
751
|
let ending: {
|
|
469
752
|
status: TaskStatus;
|
|
470
753
|
outcome: string;
|
|
471
|
-
pending:
|
|
754
|
+
pending: TaskPending | null;
|
|
755
|
+
} | null = null;
|
|
756
|
+
/**
|
|
757
|
+
* What broke, as the provider said it — the thread carries it too (below) —
|
|
758
|
+
* and whose it is to fix (model.ts modelFailureOf).
|
|
759
|
+
*/
|
|
760
|
+
let broken: {
|
|
761
|
+
message: string;
|
|
762
|
+
failure: ModelFailure;
|
|
763
|
+
budget?: number;
|
|
472
764
|
} | null = null;
|
|
473
|
-
/** What broke, as the provider said it; the thread carries it too (below). */
|
|
474
|
-
let broken: string | null = null;
|
|
475
765
|
|
|
476
766
|
try {
|
|
477
767
|
await runBot(input, {
|
|
@@ -503,19 +793,23 @@ async function drive(
|
|
|
503
793
|
outcome: event.question,
|
|
504
794
|
pending: { toolCallId: event.id, options: event.options },
|
|
505
795
|
};
|
|
506
|
-
} else if (event.type === "
|
|
507
|
-
// An
|
|
508
|
-
// The outcome is the
|
|
509
|
-
// thread line (bot.query linesOf).
|
|
510
|
-
ending =
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
796
|
+
} else if (event.type === "answer") {
|
|
797
|
+
// An answer ends the job; one the app stopped (bot.run `stopped`) waits
|
|
798
|
+
// with the continue option. The outcome is the answer text verbatim;
|
|
799
|
+
// the same text is the thread line (bot.query linesOf).
|
|
800
|
+
ending = event.stopped
|
|
801
|
+
? {
|
|
802
|
+
status: "waiting",
|
|
803
|
+
outcome: event.text,
|
|
804
|
+
pending: { toolCallId: null, options: [TASK_CONTINUE] },
|
|
805
|
+
}
|
|
806
|
+
: { status: "done", outcome: event.text, pending: null };
|
|
517
807
|
} else if (event.type === "error") {
|
|
518
|
-
broken =
|
|
808
|
+
broken = {
|
|
809
|
+
message: event.message,
|
|
810
|
+
failure: event.failure,
|
|
811
|
+
budget: event.budget,
|
|
812
|
+
};
|
|
519
813
|
ending = {
|
|
520
814
|
status: "failed",
|
|
521
815
|
outcome: broke(event.message),
|
|
@@ -525,17 +819,22 @@ async function drive(
|
|
|
525
819
|
},
|
|
526
820
|
});
|
|
527
821
|
} catch (cause) {
|
|
528
|
-
broken =
|
|
822
|
+
broken = {
|
|
823
|
+
message: modelErrorToString(cause),
|
|
824
|
+
failure: modelFailureOf(cause),
|
|
825
|
+
};
|
|
529
826
|
ending = {
|
|
530
827
|
status: "failed",
|
|
531
|
-
outcome: broke(broken),
|
|
828
|
+
outcome: broke(broken.message),
|
|
532
829
|
pending: null,
|
|
533
830
|
};
|
|
534
831
|
} finally {
|
|
832
|
+
thread.close();
|
|
535
833
|
running.delete(id);
|
|
536
834
|
}
|
|
537
835
|
|
|
538
|
-
// Whoever aborted writes the row: cancel marks failed, answerTask relaunches
|
|
836
|
+
// Whoever aborted writes the row: cancel marks failed, answerTask relaunches,
|
|
837
|
+
// a pause parks.
|
|
539
838
|
if (signal.aborted) return;
|
|
540
839
|
|
|
541
840
|
const final = ending ?? {
|
|
@@ -543,37 +842,49 @@ async function drive(
|
|
|
543
842
|
outcome: "Stopped without handing anything back.",
|
|
544
843
|
pending: null,
|
|
545
844
|
};
|
|
546
|
-
// A
|
|
547
|
-
//
|
|
548
|
-
|
|
549
|
-
// write, which is what tells anyone the job ended at all.
|
|
550
|
-
if (final.status === "failed") {
|
|
551
|
-
await thread
|
|
552
|
-
.note(`The run stopped here: ${broken ?? final.outcome}`)
|
|
553
|
-
.catch((cause) => logger.warn(`task ${id}: break not written`, cause));
|
|
554
|
-
}
|
|
845
|
+
// A break a moment or a compaction can fix is the app's to pick back up, not
|
|
846
|
+
// a failure for a person to find (parkTask)
|
|
847
|
+
const park = broken && broken.failure !== "fatal" ? broken : null;
|
|
555
848
|
|
|
556
|
-
// The one write that must land: everything else in this run has already
|
|
557
|
-
// happened, and this is what tells the screen and Thursday it ended at all.
|
|
558
|
-
// Writes are serialised, so contention no longer throws here (database/db.ts);
|
|
559
|
-
// what is left is a database that cannot be written to, which a retry would
|
|
560
|
-
// not help either. Said plainly rather than thrown into `after`, where it
|
|
561
|
-
// would read as an unexplained request failure — and the row stays `running`,
|
|
562
|
-
// which the next boot reconciles (sweepTasks).
|
|
563
849
|
try {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
850
|
+
if (park) {
|
|
851
|
+
await parkTask(id, {
|
|
852
|
+
why:
|
|
853
|
+
park.failure === "overflow"
|
|
854
|
+
? `The model refused the context as too long (${park.message}); it is compacted before going on.`
|
|
855
|
+
: `The model call failed (${park.message}).`,
|
|
856
|
+
retry: park.failure === "transient",
|
|
857
|
+
budget: park.budget,
|
|
858
|
+
});
|
|
859
|
+
} else {
|
|
860
|
+
// A thread that simply stops cannot be read: the room shows a tool call
|
|
861
|
+
// with no answer, and a resumed run has no idea why. The task row says it
|
|
862
|
+
// too, but the row is a status and this is the story. Never at the cost of
|
|
863
|
+
// the status write, which is what tells anyone the job ended at all.
|
|
864
|
+
if (final.status === "failed") {
|
|
865
|
+
await thread
|
|
866
|
+
.note(`The run stopped here: ${broken?.message ?? final.outcome}`)
|
|
867
|
+
.catch((cause) =>
|
|
868
|
+
logger.warn(`task ${id}: break not written`, cause),
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
await writeEnding(id, {
|
|
872
|
+
...final,
|
|
873
|
+
seen: false,
|
|
874
|
+
endedAt: final.status === "waiting" ? null : new Date(),
|
|
875
|
+
});
|
|
876
|
+
}
|
|
569
877
|
} catch (cause) {
|
|
878
|
+
// Said plainly rather than thrown into a promise nobody awaits; the row
|
|
879
|
+
// stays `running`, which the next boot reconciles (sweepTasks)
|
|
570
880
|
logger.error(`task ${id}: could not record how it ended`, cause);
|
|
571
881
|
return;
|
|
572
882
|
}
|
|
573
883
|
|
|
574
|
-
//
|
|
575
|
-
//
|
|
576
|
-
if (final.status
|
|
884
|
+
// A waiting job keeps its browser: answering resumes into the page it left
|
|
885
|
+
// off at. An ended one closes only what nobody can see (closeHiddenBrowser).
|
|
886
|
+
if (park || final.status === "waiting") void pruneJobFiles();
|
|
887
|
+
else void closeHiddenBrowser(id);
|
|
577
888
|
|
|
578
889
|
const task = await findTask(id);
|
|
579
890
|
if (!task) return;
|
|
@@ -589,6 +900,9 @@ async function drive(
|
|
|
589
900
|
return;
|
|
590
901
|
}
|
|
591
902
|
|
|
903
|
+
// A parked job picks itself back up; nobody needs telling yet
|
|
904
|
+
if (park) return;
|
|
905
|
+
|
|
592
906
|
await announce(task.label, final);
|
|
593
907
|
|
|
594
908
|
// A finished job naming a document opens it on the screen (workspace artifact-view).
|
|
@@ -600,7 +914,7 @@ async function drive(
|
|
|
600
914
|
}
|
|
601
915
|
}
|
|
602
916
|
|
|
603
|
-
/** The document
|
|
917
|
+
/** The document an answer names: the artifacts folder first, otherwise the first drawable file. */
|
|
604
918
|
function artifactIn(outcome: string): string | null {
|
|
605
919
|
const paths = pathsIn(outcome);
|
|
606
920
|
return (
|