elanous 0.2.38 → 0.2.40
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/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → HjeK7zONHfR7op1hKXp4k}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{7954.4f7a8832663ee979.js → 1060.014f1f01a17aec26.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8911.bf5e712acb25fb6c.js → 1281.d81877e35b9068f4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2104.70e086d5174a4736.js → 1350.59f40e39e02d91b1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1415.79821ec7ae99acdb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1452.162bb2d9d699e82a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/147.f92f63bbc5e85fa5.js +286 -0
- package/apps/pwa/out/_next/static/chunks/1537-6bb97b5214928ea9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1661.fb425a1d8a065b72.js +149 -0
- package/apps/pwa/out/_next/static/chunks/1671-1c22b40b50b208f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1758.0204d3f48783c49d.js +90 -0
- package/apps/pwa/out/_next/static/chunks/1806.027bf78b6a94d340.js +104 -0
- package/apps/pwa/out/_next/static/chunks/2047.8f23e210995d4548.js +2 -0
- package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1632.7d87f998e714bede.js → 2066.a77257c8c350770a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2096-a938496bc996dcbd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8019.21ca554a821dad01.js → 2177.df8547f9d7215c4e.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3528.e4b8ab70d339f965.js → 2226.2cf61ec781827219.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2281-b8cede695c6c650e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6493.27ad77de7aac7966.js → 2499.02fbfd18126c10c0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7628.6b16863ac3972333.js → 2522.f2766b76d22c8bdf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{3086.fb14b60ce98b53d3.js → 2566.beaffc3a5e1fcd2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9299.24e2a7d9b6d1f91b.js → 261.0d471e8aded799f3.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2615.3c9738153de3ef3f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2727.e703d99ac414916d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2752.7904b8df0254d0ae.js +27 -0
- package/apps/pwa/out/_next/static/chunks/2762-5051a862dfa40e99.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2767-31784bfedf8e245d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2774-719820e3f5b2a3eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2829-734fe8bf2eee7347.js +1 -0
- package/apps/pwa/out/_next/static/chunks/311-32dcac79970985e8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3175-f93f7495cd28253c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3184.8da993f5502d2140.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3231-d7c981db0ff8bdcc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3250.151309c5176d6b4b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7524.ce973525d30b3d52.js → 3330.7443183b7e6fdbdf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3517.a5aa1797a9dbf2ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3567-45f676877ed9e8a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3124-561f7f037943cde2.js → 3746-f80a78f220bf37b5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3819.8a1de79b2e8c7298.js +24 -0
- package/apps/pwa/out/_next/static/chunks/39.9b37b0be4c128a83.js +77 -0
- package/apps/pwa/out/_next/static/chunks/{bb6987f9.3647e1a23b0e3217.js → 3b355b3d.6f73c98bf6f9c749.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4023.a19045970a9ce16a.js +36 -0
- package/apps/pwa/out/_next/static/chunks/{8994d93e.33ba491f95345fc2.js → 409c787b.e48c5bec8ec10456.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5041-5aada92ca215ffdd.js → 413-24c8284bda08241d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4135.e45d6ebc29e20647.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4283.65502f5d0e6ff6c0.js +287 -0
- package/apps/pwa/out/_next/static/chunks/4305-4e28fa92a7b34a5b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4335-50efa61fd7613142.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4351.0f37a6db2b34d50b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5638.107314dc479e2f37.js → 470.51a72a2348306455.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4720.ecbd1693fa151068.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8487.291666583bebe640.js → 4769.9fd582071301f382.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8509.3a54d4e61893d7cb.js → 483.725e4a61be922788.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9fe1b809.738da85c8b17e3fb.js → 4864a2ca.1c1c280a7772c5e5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4969-4b209d7307410c00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5068-c7f53862f83c0917.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5315.bc96711c24dfefe2.js +74 -0
- package/apps/pwa/out/_next/static/chunks/{8879.ac06755bcf3e44a1.js → 5383.bdfa5d886e39a826.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6142.913b44e260a3f925.js → 5436.fdf6fa8ae3e9588d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5542.efbf14f16baed4dd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5622.94893f5aea7185d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5644.8f401a25601d05fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5658.35f70eb9871a54bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5721.7bdc0e904c76ab51.js +8 -0
- package/apps/pwa/out/_next/static/chunks/5790-eef0ca20884a6bdf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5802.ef0d8598ca68fe84.js +62 -0
- package/apps/pwa/out/_next/static/chunks/5890.fb974729788dcb71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5924.5ef25cddd36d5dbf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5979-e59c099ebf8d1f35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6020.714cfeada2315e2e.js +94 -0
- package/apps/pwa/out/_next/static/chunks/6027-dfe0349d8c50f698.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7161-8f22db3ec5ed005e.js → 6051-0ae955eedb10adb9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6178.bc4730c86cf74536.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3291.f6c1005387d514bd.js → 6257.c0037b8949239f5e.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6273.d808b0dcb3c2b155.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6292.6ef1df64fa6a4c8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/647-af8dd920ba46533c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6541-170dc5c59e135c0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6624.981ef7caeb680560.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6742-a1ad4a94ba7bc37a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5203.51e5d8b5f1dcfe53.js → 6749.0744ce6eb08d40e9.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/6836-493dc55c39187949.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6856-53ac421c06039a18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1938.0e6c60ee91c4d7f5.js → 6908.06008c67f6380ea9.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6915.096931864206f522.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6925.5e181fb7dcf90193.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{de8b930d.d94c0f42acf807fc.js → 6cc1d1d6.9a98dd4622f1afc6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7203-800e11037adc41eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7219-15bdd9a80661af8e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7279.6170f591105936bb.js +93 -0
- package/apps/pwa/out/_next/static/chunks/7349-373165c7fbdcc3df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7514-a533ba0ca1cae4f4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7515.1ad6efe157fa4448.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7521.d919cc1fab80c1d9.js +24 -0
- package/apps/pwa/out/_next/static/chunks/7538.90e97bbdf9178cff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7611.85f045bf232053ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7825-39203196a12579b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7869.5e1a9a12fd70d6c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8086.1ab9103c41be884f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8099.1cccf31c1baa7e1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8179-e61fffbdb70f1152.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8265.bdeb991b34db6a06.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1026-44010f405704050c.js → 8272-025653884f9645d2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{5307.d7328020227880c2.js → 8357.1aaa713b052a78b1.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/8638-e42615f2166165b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4199-f7c6eb40cd0322f8.js → 8639-92c11d069792429e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8691.54e22831d5e8ccf8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8d173e38.18a2f7b4e1848bdb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9069.657590a84afb8fac.js +41 -0
- package/apps/pwa/out/_next/static/chunks/9125-ae588d88a0293b93.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9175.2de5209a5ce6f68a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9184.45afbf44fec87574.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{eaad0cba.771200940c529df7.js → 9189505a.980427ac048c8c60.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9311.f9f641a46a508611.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9371-a6fee8378ebfa3ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9421-3aa9ff4fa7f63d8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9992.07ce73c10bd5e6a1.js +79 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76394dc618d322c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1b948637c37b3abd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-c63400f1bcf3e47c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-95d0957267819586.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-866aac5ff226a7f3.js → page-ba957ff875a026a0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-bb6fd0714879cb87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-8f9038520d2acbef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-d4b48397e05fce2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-72d5744245dc0c27.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-37625dc8300fa43a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-fbef9d160272dbc1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-58424168df84928e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-72c12ba430ac57c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-d53f3e9ed806d7e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-4d2fbd45feee0829.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-76394dc618d322c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-8783dc0ed7590a2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-3706cb390606e930.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-9b0a86598e0111fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-4edb8df90f4537ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-83d27757e2b8060a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-47398b9ba1cc5e1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-fb86f55cfe2e681d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e22345fc8fd47b1b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-fca2e59a81744d9e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-6e96bda63100b31e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-4d17ad8e0db8cea4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-121f92766c33beaa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-43f14212c545f92d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ccec2023e7a974ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-b04f33f548b89a94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-c8792823c0917021.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-8c0e32782ceef4cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-94bd3922eb230ce8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-bca565887bafa03c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-ac1dffafe649fc6c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-52374edb5e23e455.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ad4ebca120d43ca7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-76394dc618d322c8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-718b89ce4b4ae4e4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-204eca33eeeaddec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-e58ba9bcdb9ac0f9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-98f6dd50bafd7734.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-139d722de1dcd6c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-5a4bdd72bff27057.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-6f6ab17d44f984ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-aabb7bd15fb72da9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-e4322319164a4436.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-e9efc0c8f32e2371.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-ccde99f07aaf71f7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b7478fef.5917716286213fcc.js → b84cad00.594027ebe0531fe2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/c696986b.5dc8bb1143af16d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{b7459770.6539b11860eb8a9c.js → ca3702f8.2913182e73889fa2.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/{3f0de3de-2340c532c00395db.js → d5d3cefc-373c4eb722ed848b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{89d6c04f-6b8ab341748e468a.js → d8de0de2-dd0f4ac8e5ab1832.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{framework-4b12a946f352cee2.js → framework-002b472a66935d31.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/main-49b88d47292c0476.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-fff2549cb10a133f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-32abbbba3f3b76b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-9d9cfef60c60dd7a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-cc7f483fa294034a.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +22 -22
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +21 -21
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +22 -22
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +22 -22
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +22 -22
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +21 -21
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +21 -21
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +21 -21
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +21 -21
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +21 -21
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/graphs/demo/persona-marketer/fixtures/marketer-scenario.yaml +10 -0
- package/graphs/demo/persona-marketer/persona-marketer.yaml +25 -0
- package/graphs/demo/persona-marketer/recipes.yaml +19 -0
- package/graphs/video/explainer-line.yaml +4 -1
- package/package.json +1 -1
- package/scripts/dead-code/report.ts +169 -0
- package/scripts/lib/morning-report-options.ts +3 -4
- package/scripts/lib/tui-regress-evidence.ts +56 -0
- package/scripts/morning-report.ts +5 -1
- package/scripts/public-export.ts +15 -7
- package/scripts/release-loop/export-check-node.ts +21 -3
- package/scripts/release-loop/gate-node.ts +379 -48
- package/scripts/release-loop/gate-shard-dispatch.ts +128 -0
- package/scripts/release-loop/gate-shard-receipts.ts +89 -0
- package/scripts/release-loop/gate-wall.ts +5 -5
- package/scripts/release-loop/preflight.ts +6 -2
- package/scripts/release-loop/resume-release.ts +20 -5
- package/scripts/release-loop/resume.ts +48 -0
- package/scripts/release-loop/version-node.ts +7 -2
- package/scripts/release-story/draft.ts +1 -1
- package/scripts/research-bench/README.md +53 -0
- package/scripts/research-bench/questions.json +66 -0
- package/scripts/research-bench/rubric.md +33 -0
- package/scripts/research-bench/run.ts +523 -0
- package/scripts/tui-regress.ts +85 -10
- package/src/acp/core-turn-bridge.ts +8 -0
- package/src/agent/autonomous-tools.ts +10 -3
- package/src/agent/monad-agent-turn.ts +4 -1
- package/src/agent/registry.ts +26 -2
- package/src/agent/shared-app-tools.ts +1 -1
- package/src/agent/surface-ux/build.ts +12 -3
- package/src/agent/surface-ux/types.ts +1 -1
- package/src/agent/task-notification.ts +75 -6
- package/src/agent/types.ts +3 -0
- package/src/agent-mission/driver.ts +29 -3
- package/src/agent-mission/mission-cli.ts +2 -1
- package/src/agent-substrate/review-context-pack.ts +365 -0
- package/src/agent-substrate/self-review-cli.ts +226 -17
- package/src/ask-user-question/index.ts +6 -0
- package/src/ask-user-question/inline-resolver.ts +49 -0
- package/src/auto-research/question-ladder-contract.ts +22 -3
- package/src/auto-research/research-turn.ts +350 -17
- package/src/autopilot/agent-loop.ts +1 -1
- package/src/autopilot/pty-control-loop.ts +8 -1
- package/src/boot/daemon-tools/index.ts +4 -3
- package/src/boot/daemon-tools/self-implement.ts +270 -2
- package/src/boot/daemon-tools/types.ts +2 -0
- package/src/budget/llm-cost.ts +44 -5
- package/src/budget/unified-usage.ts +17 -1
- package/src/capture/tui-self-report.ts +14 -0
- package/src/chat/index.ts +33 -7
- package/src/cli/agent-cli.ts +43 -8
- package/src/cli/intake-cli.ts +22 -1
- package/src/cli/lesson-cli.ts +19 -3
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/pod-cli.ts +17 -2
- package/src/cli/pty-takeover-cli.ts +67 -7
- package/src/cli/release-cli.ts +52 -6
- package/src/cli/repo-cli.ts +2 -1
- package/src/cli/tasks-cli.ts +36 -9
- package/src/control-plane/ledger.ts +21 -4
- package/src/core-turn/run-core-turn.ts +44 -3
- package/src/core-turn/run-goal-loop.ts +152 -8
- package/src/core-turn/types.ts +9 -0
- package/src/dashboard/chat/acp-chat.ts +2 -2
- package/src/dashboard/classic-sigquit.ts +16 -0
- package/src/dashboard/index.ts +321 -27
- package/src/dashboard/input/chat-main-interaction-opts.ts +3 -0
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +7 -2
- package/src/dashboard/input/chat-main-slash-command.ts +7 -0
- package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
- package/src/dashboard/input/dashboard-priority-key-route.ts +21 -5
- package/src/dashboard/input/external-input-host.ts +2 -0
- package/src/dashboard/sidetab-runtime.ts +228 -0
- package/src/dashboard/slash-runtime/ask-clarification.ts +7 -1
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +20 -8
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
- package/src/dashboard/term-slash-runtime.ts +16 -18
- package/src/dashboard/turn-preamble.ts +2 -0
- package/src/domains/knowledge.ts +1 -1
- package/src/esc-abort-gate.ts +33 -1
- package/src/execution-loop/launch-gate.ts +206 -1
- package/src/graph-runner/graph-cli.ts +6 -4
- package/src/graph-runner/runner.ts +31 -9
- package/src/graph-wizard/generate.ts +16 -7
- package/src/graph-wizard/mission-compose.ts +201 -0
- package/src/grok/agent-search.ts +8 -2
- package/src/grok/credential.ts +5 -0
- package/src/grounding/ref-index.ts +11 -0
- package/src/grounding/ref-vector.ts +61 -0
- package/src/grounding/sources-cli.ts +2 -2
- package/src/grounding/sources.ts +15 -1
- package/src/harness/harness-cli-command.ts +38 -9
- package/src/harness/harness-pod-dispatch.ts +7 -1
- package/src/index.ts +18 -4
- package/src/input/external-input-queue.ts +10 -0
- package/src/intake-plane/collect-telegram-saved.ts +36 -1
- package/src/intake-plane/intake-to-tasks.ts +246 -3
- package/src/lessons/friction-ledger.ts +154 -0
- package/src/live-supply/collector.ts +149 -0
- package/src/live-supply/probes.ts +52 -0
- package/src/live-supply/snapshot.ts +40 -0
- package/src/llm.ts +431 -76
- package/src/loops/orchestrator/tick.ts +8 -0
- package/src/nexus/api/harness-api.ts +2 -1
- package/src/pty/snapshot.py +132 -0
- package/src/pty-shell/pty-control-ipc.ts +29 -2
- package/src/pty-shell/pty-manifest.ts +59 -3
- package/src/pty-shell/registry.ts +2 -0
- package/src/pty-shell/tui-run-state.ts +80 -3
- package/src/release-loop/gate-host-reservation.ts +13 -4
- package/src/release-loop/gate-shard-ledger.ts +68 -0
- package/src/release-loop/merged-pr-checklist.ts +25 -2
- package/src/release-loop/rehearsal-shard-plan.ts +6 -1
- package/src/release-loop/rehearsal.ts +27 -0
- package/src/research/edge-decision.ts +124 -15
- package/src/research/gap-followup.ts +249 -0
- package/src/research/lenses/counter-evidence.ts +100 -0
- package/src/research/lenses/working-backwards.ts +89 -0
- package/src/research/plugin-discovery.ts +242 -0
- package/src/research-bridge/invoke.ts +4 -2
- package/src/research-bridge/types.ts +2 -0
- package/src/self-dev/ask-launch-flow.ts +34 -106
- package/src/self-dev/dev-cli.ts +2 -0
- package/src/self-dev/dev-pipeline.ts +8 -4
- package/src/self-dev/graph-journey-route.ts +10 -2
- package/src/self-dev/launch-preflight-text.ts +2 -2
- package/src/self-dev/launch-preflight.ts +38 -7
- package/src/self-dev/orchestrate-cli.ts +1 -0
- package/src/self-dev/run-supervisor.ts +19 -0
- package/src/self-implement/device-first.ts +8 -2
- package/src/self-implement/doctor-visit.ts +76 -58
- package/src/self-implement/gate-artifacts.ts +3 -0
- package/src/self-implement/gate-baseline.ts +75 -4
- package/src/self-implement/gate-cli.ts +317 -9
- package/src/self-implement/gate-receipt-registry.ts +180 -0
- package/src/self-implement/gate-remote.ts +145 -22
- package/src/self-implement/goal-author-clarification.ts +178 -24
- package/src/self-implement/goal-author-decompose.ts +24 -15
- package/src/self-implement/goal-author.ts +9 -5
- package/src/self-implement/host-regate.ts +120 -45
- package/src/self-implement/impl-findings-feedback.ts +188 -0
- package/src/self-implement/knowhow-pack.ts +189 -10
- package/src/self-implement/off-diff-evidence.ts +124 -0
- package/src/self-implement/orchestrator.ts +85 -7
- package/src/self-implement/run-ledger.ts +46 -8
- package/src/self-implement/run-stop.ts +12 -0
- package/src/self-implement/seams.ts +6 -3
- package/src/self-implement/self-implement-cli.ts +4 -2
- package/src/session/chat.ts +89 -15
- package/src/session-runtime/provider-circuit.ts +140 -0
- package/src/shell-runner/file-engine.ts +1 -0
- package/src/shell-runner/types.ts +4 -0
- package/src/sidetab-core/model.ts +176 -0
- package/src/skills/tools/schedule-wakeup.ts +23 -1
- package/src/skills/tools/shell.ts +51 -5
- package/src/steward/directive-audit.ts +354 -0
- package/src/surface/child-process.ts +31 -0
- package/src/surface/tui-stderr-owner.ts +48 -0
- package/src/task-agent/cover.ts +30 -12
- package/src/task-agent/judge.ts +56 -0
- package/src/task-agent/postland-card.ts +35 -2
- package/src/task-agent/rejudge-on-head.ts +46 -2
- package/src/task-agent/repair-cycle.ts +1 -1
- package/src/task-agent/task-hand.ts +129 -24
- package/src/task-agent/tier-split.ts +105 -21
- package/src/task-orchestrator/surfaces/pod-command-job.ts +330 -2
- package/src/task-orchestrator/surfaces/pod-config-snapshot.ts +123 -0
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +27 -2
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
- package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +74 -6
- package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +56 -15
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +186 -33
- package/src/tool-runtime/skill-exec-runtime.ts +95 -5
- package/src/tui/entry.ts +15 -2
- package/src/tui/inline-choice.ts +188 -0
- package/src/tui/sidetab/list.ts +2 -176
- package/src/tui/slash/term.ts +12 -1
- package/src/tui-client/dashboard-session.ts +7 -1
- package/src/user-config.ts +34 -4
- package/src/ux-sim/classic-tui-seat-scenarios.ts +1 -7
- package/src/ux-sim/fake-land-queue.ts +88 -0
- package/src/ux-sim/gate-shard-host-reroute.ts +82 -0
- package/src/ux-sim/goal-interim-trace.ts +24 -0
- package/src/ux-sim/next-tui-seat-scenarios.ts +8 -13
- package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +4 -1
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/recipes/explainer.ts +54 -2
- package/src/web-search/grok.ts +32 -6
- package/src/web-search/index.ts +8 -7
- package/src/workflow-runtime/node-catalog.ts +53 -4
- package/apps/pwa/out/_next/static/chunks/1118.a8a74ea29aac3e46.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1204-2aa830479adf80f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1341-43b7d2dc77d45c9d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1440-c3ea8882badfd9bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1698-9c11cbf97f13717e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1770-3b1fc92253ef9f2f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1923-5c1695332240246a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/213-20675f20673ba22a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/214.186a430da28338f1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2277.3bd4c0ac7f1b5996.js +0 -93
- package/apps/pwa/out/_next/static/chunks/240.e09f433f71c78ff4.js +0 -104
- package/apps/pwa/out/_next/static/chunks/2415.738b777642a02233.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2417.02151393605a7cd0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2463.cd2641a76daaa9ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2576.b9e9c629c4b84c52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/265-c021de53f0865bd9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2998-b1cc13956cd6a6e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2e4782d3.ba2f0ab2b63a53e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3130.626b54382b4dc379.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3221-1bb3f99a55088613.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280.24edb1ffd03a7f3f.js +0 -24
- package/apps/pwa/out/_next/static/chunks/3288-eb3c22a1cbf2ae68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/33.ef99e8374f96c6c4.js +0 -36
- package/apps/pwa/out/_next/static/chunks/3341-f09b9efbd7a82f70.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3389.012c70767a872f9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3410-d7c0f14b329d6fda.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3421.c87d6313a7d670f7.js +0 -287
- package/apps/pwa/out/_next/static/chunks/3422-83a3953f9bd67e26.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3587-002e24e368c515a9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3644.f12a7d821ab940af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3660.d7516588e2d875c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3695.b82e2610f4cd4ea9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3858.ca1f5bc0f577eac9.js +0 -94
- package/apps/pwa/out/_next/static/chunks/3959-e6ac4a139d9d4bcc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4032.53f62176514ec0ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4204-ef8484cbecd5d62f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4259-163129ca79913c4b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/428-eaa77df3d0c85969.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4432-97e400ffa1e161f5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/449-aa427cf2cbb75f50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4491-39a0fd32bbaf3840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4588.b7cf06d382953979.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4690.70ec8060825366ab.js +0 -32
- package/apps/pwa/out/_next/static/chunks/4804.6012b5cd33c22792.js +0 -90
- package/apps/pwa/out/_next/static/chunks/4881.e4d22d730e3b9df5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4937.ce2e340dc29cad3e.js +0 -79
- package/apps/pwa/out/_next/static/chunks/5-bb1c08d84bd71df3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5005.de98df23b37cdf3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5035.dc64a89cad5573cc.js +0 -74
- package/apps/pwa/out/_next/static/chunks/5207.1a224035455790fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5255-1b60d50eabe9f057.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5269.d0436ee6d773382a.js +0 -286
- package/apps/pwa/out/_next/static/chunks/5300.677c97e0393742e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5309.3367c4d50f52b489.js +0 -1
- package/apps/pwa/out/_next/static/chunks/552-689827d49780fa00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5539.34cc9d60622cb69b.js +0 -8
- package/apps/pwa/out/_next/static/chunks/5568.218dea0c00ca2ec7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5645.b7e3b055455a04ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5662.18cc0f30353cbd96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5671.da24fc9dc5e98325.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5b141171.324c40fd49cb6821.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6175-d4621f6a10b0cfab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6290.3eb53a20746b72ce.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6415-9307f3eafa90837f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6579-3de35d00aacd71b5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/680-2f324c4e039a5b67.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6845-331b3c7481da3ba3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7000.28157393caaf5343.js +0 -62
- package/apps/pwa/out/_next/static/chunks/7311-60a7ea80d23c7521.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7401.525d0a12f7d02c06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7438.c2cf72b66dca6aa4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7488.966b116789f3d41a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7573.2376e13c9c21f1f8.js +0 -77
- package/apps/pwa/out/_next/static/chunks/7577.ea6e9ac72e035520.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7657.8d1fb3d2f7ebe273.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7903-1435d5d2f0dd7807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7978-30a91192c5dbe3c2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8025-8795821525cf1a07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8191.3674a00f0b565c23.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8217-604955d8885c5ef2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8298-eed6f5f2585a63f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8758.ac421f726a189125.js +0 -1
- package/apps/pwa/out/_next/static/chunks/891.d6c723a51a067b36.js +0 -149
- package/apps/pwa/out/_next/static/chunks/9223.cbcc88e0e9950426.js +0 -41
- package/apps/pwa/out/_next/static/chunks/9317.6a9869039c231bb3.js +0 -24
- package/apps/pwa/out/_next/static/chunks/9383.e4755f275b3c11ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9581.da63ddf41acfad46.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9715.8c5529a0a5c41a36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9817.3009d65f0889ef1f.js +0 -2
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-76873dd80da4f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ed32b6ec5dea8f23.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-fdd40e15babf3d25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-384efc78e85e400b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-d91809c5aeed319a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-128f3522f89a81ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-595961abf3b43ad1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f41dccb76d8c0263.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-a3205c2e28b7d0d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-c39a80277814a3f4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1ab3f98194513195.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-a5246f7e254d77d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-0f92287bdb81217d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-5a37131ff63793ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-76873dd80da4f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ac4bd14bb2348bfd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c348a3959c5b5fc6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-2addd81c0d3e2906.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-da6b765f58a3eefb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-0661e40f8780c32c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-b89af1b1c8e4875b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-da8aeb82ba751cdb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-cc71317b239439db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-bde7fc1d64ffe369.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-e2797214f713fa58.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-2a35bcda70defaf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3af03deedde45032.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d1d1210f99f620ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-46d1b5500885861d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-291ab19fe2acb173.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-7f569e533ddeecba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-990129c9fee46d8f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-7737f785ebb1cdaf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f3c73a4f7ffd2f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-03be7fb347f01058.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-96b0280625e4df2b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-56855545049eb56d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-76873dd80da4f715.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-79a909c9981f0338.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-a9d9a3e66459c1e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-c383cbf2013f7069.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-f57c6a2e54dbdca4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-6b140f77593576eb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-6b767ae2d9d0adfc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-116d6198d5da0e3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-b9c9b778c7501370.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-a6c78392ab8f6335.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-455183deb4ed0cfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-6a63e99526bd63d0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31c22caafe788c08.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-941155250ed2644b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f8b6765abed6d149.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-78432194c85388f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-cdf7390829512b1b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-d5f0964a9c2e92d2.js +0 -1
- /package/apps/pwa/out/_next/static/{RrjXTwz-urRAbChP1bX02 → HjeK7zONHfR7op1hKXp4k}/_ssgManifest.js +0 -0
package/src/llm.ts
CHANGED
|
@@ -269,6 +269,10 @@ export interface LLMMessage {
|
|
|
269
269
|
role: 'system' | 'user' | 'assistant';
|
|
270
270
|
/** Plain string for text-only messages; ContentBlock[] when images are mixed in. */
|
|
271
271
|
content: string | ContentBlock[];
|
|
272
|
+
/** Codex Responses message phase, preserved when replaying a stateless turn. */
|
|
273
|
+
phase?: 'commentary' | 'partial_answer' | 'final_answer';
|
|
274
|
+
/** Opaque Codex stateless reasoning items, before this assistant message. */
|
|
275
|
+
codexReasoningItems?: Array<{ type: 'reasoning'; encrypted_content: string; summary: unknown[]; id?: string }>;
|
|
272
276
|
}
|
|
273
277
|
|
|
274
278
|
/** JSONSchema-shaped tool definition sent to the provider (no handler). */
|
|
@@ -284,6 +288,21 @@ function toolUseNames(messages: readonly LLMMessage[]): string[] {
|
|
|
284
288
|
: []);
|
|
285
289
|
}
|
|
286
290
|
|
|
291
|
+
/** Return paths for legacy tuple-form `items` schemas without logging schema
|
|
292
|
+
* values. Provider 400s often omit the rejected tool name, so these paths let
|
|
293
|
+
* the next TUI recurrence identify the source contract without logging args. */
|
|
294
|
+
function collectTupleItemsSchemaPaths(schema: unknown, path = 'parameters'): string[] {
|
|
295
|
+
if (Array.isArray(schema)) {
|
|
296
|
+
return schema.flatMap((value, index) => collectTupleItemsSchemaPaths(value, `${path}[${index}]`));
|
|
297
|
+
}
|
|
298
|
+
if (!schema || typeof schema !== 'object') return [];
|
|
299
|
+
return Object.entries(schema as Record<string, unknown>).flatMap(([key, value]) => {
|
|
300
|
+
const childPath = `${path}.${key}`;
|
|
301
|
+
const tuplePath = key === 'items' && Array.isArray(value) ? [childPath] : [];
|
|
302
|
+
return [...tuplePath, ...collectTupleItemsSchemaPaths(value, childPath)];
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
287
306
|
function mapProviderToolNamesInMessages(
|
|
288
307
|
messages: readonly LLMMessage[],
|
|
289
308
|
mapName: (name: string) => string,
|
|
@@ -340,7 +359,10 @@ function restoreProviderToolCallNames(
|
|
|
340
359
|
* (currently Anthropic only) — consumers that don't care should
|
|
341
360
|
* ignore it; `textOnly()` filters it out. */
|
|
342
361
|
export type LLMStreamEvent =
|
|
343
|
-
| { type: 'text'; delta: string }
|
|
362
|
+
| { type: 'text'; delta: string; phase?: 'commentary' | 'final' }
|
|
363
|
+
| { type: 'text_phase'; phase: 'commentary' | 'final' }
|
|
364
|
+
| { type: 'turn_end'; endTurn: boolean }
|
|
365
|
+
| { type: 'codex_reasoning_item'; item: { type: 'reasoning'; encrypted_content: string; summary: unknown[]; id?: string } }
|
|
344
366
|
| {
|
|
345
367
|
type: 'tool_call';
|
|
346
368
|
id: string;
|
|
@@ -415,6 +437,24 @@ export interface LLMOpts {
|
|
|
415
437
|
streamIdleTimeoutMs?: number;
|
|
416
438
|
/** Optional per-request usage telemetry from the provider stream. */
|
|
417
439
|
onUsage?(usage: LLMUsage): void;
|
|
440
|
+
/** Optional request-size policy. Providers that expose a serialized request
|
|
441
|
+
* can compact the normalized conversation before sending it. The callback
|
|
442
|
+
* is opt-in; providers without a serializer hook preserve their wire path. */
|
|
443
|
+
requestSizeGuard?: {
|
|
444
|
+
maxChars: number;
|
|
445
|
+
compactMessages: (
|
|
446
|
+
messages: LLMMessage[],
|
|
447
|
+
info: { provider: string; requestChars: number; maxChars: number },
|
|
448
|
+
) => Promise<{ messages: LLMMessage[]; reason: string } | null>;
|
|
449
|
+
onMeasured?: (info: {
|
|
450
|
+
provider: string;
|
|
451
|
+
requestChars: number;
|
|
452
|
+
maxChars: number;
|
|
453
|
+
compacted: boolean;
|
|
454
|
+
reason: string;
|
|
455
|
+
previousChars?: number;
|
|
456
|
+
}) => void;
|
|
457
|
+
};
|
|
418
458
|
/** Optional model role attached to this request's usage observation. */
|
|
419
459
|
usageRole?: ModelRole;
|
|
420
460
|
/** Optional per-call metering phase; absent calls keep the existing ledger shape. */
|
|
@@ -476,6 +516,9 @@ export interface LLMOpts {
|
|
|
476
516
|
* 그러면 종결 신호 뒤 빈 턴은 이 스트림에 쓴 답이 없어도 재촉·`[NO FINAL SYNTHESIS]` 없이 빈 답으로 끝낸다.
|
|
477
517
|
* 비우면(기본) 종전대로 — 답이 «어디에도» 없을 때의 경고는 그대로 보인다. */
|
|
478
518
|
terminalPriorAnswerVisible?: boolean;
|
|
519
|
+
/** Goal-loop only: a validated completion ends the provider loop after tool results settle.
|
|
520
|
+
* Omitted for ordinary terminal tools, which may need a further answer turn. */
|
|
521
|
+
terminalCompletionAccepted?: (name: string, args: Record<string, unknown>) => boolean;
|
|
479
522
|
/** Prompt-caching toggle. Honored by Anthropic (attaches
|
|
480
523
|
* cache_control markers on system + tools + 2nd-to-last history
|
|
481
524
|
* message) and OpenAI (passes stream_options.include_usage so
|
|
@@ -1628,7 +1671,8 @@ type ResponsesContentBlock =
|
|
|
1628
1671
|
* codex answer began with "tool_result 가 없다" because, from the
|
|
1629
1672
|
* model's perspective, no tool result ever arrived. */
|
|
1630
1673
|
type ResponsesInputItem =
|
|
1631
|
-
| { role: string; content: ResponsesContentBlock[] }
|
|
1674
|
+
| { role: string; content: ResponsesContentBlock[]; phase?: 'commentary' | 'partial_answer' | 'final_answer' }
|
|
1675
|
+
| { type: 'reasoning'; encrypted_content: string; summary: unknown[]; id?: string }
|
|
1632
1676
|
| { type: 'function_call'; name: string; arguments: string; call_id: string }
|
|
1633
1677
|
// Image-pipeline P3 (2026-05-05) — `output` accepts string OR a
|
|
1634
1678
|
// ContentItem[] mirroring the user-message content block shape.
|
|
@@ -1655,6 +1699,8 @@ type ResponsesInputItem =
|
|
|
1655
1699
|
* Codex variants — current gpt-5 family all true per allowlist). */
|
|
1656
1700
|
export interface MessagesToResponsesInputOpts {
|
|
1657
1701
|
acceptToolImages?: boolean;
|
|
1702
|
+
/** Server-stored continuation already contains prior reasoning items. */
|
|
1703
|
+
replayCodexReasoning?: boolean;
|
|
1658
1704
|
acceptUserMessageImages?: boolean;
|
|
1659
1705
|
onOrphanToolResult?: (callId: string) => void;
|
|
1660
1706
|
}
|
|
@@ -1827,6 +1873,9 @@ export function messagesToResponsesInput(
|
|
|
1827
1873
|
continue;
|
|
1828
1874
|
}
|
|
1829
1875
|
|
|
1876
|
+
// Stateless Codex requires the opaque reasoning item in its original
|
|
1877
|
+
// position before the corresponding assistant message/tool calls.
|
|
1878
|
+
if (m.role === 'assistant' && opts.replayCodexReasoning !== false && m.codexReasoningItems) input.push(...m.codexReasoningItems);
|
|
1830
1879
|
// Assemble the final content block list: text first (matches
|
|
1831
1880
|
// how users usually write prompts — "describe this image" then
|
|
1832
1881
|
// attachment), images second. Responses API is order-sensitive
|
|
@@ -1844,7 +1893,7 @@ export function messagesToResponsesInput(
|
|
|
1844
1893
|
// representation — emitting an empty Message wrapper would just
|
|
1845
1894
|
// add a stray empty-text block to the conversation history.
|
|
1846
1895
|
if (content.length > 0) {
|
|
1847
|
-
input.push({ role: m.role, content });
|
|
1896
|
+
input.push({ role: m.role, content, ...(m.role === 'assistant' && m.phase ? { phase: m.phase } : {}) });
|
|
1848
1897
|
}
|
|
1849
1898
|
input.push(...trailingItems);
|
|
1850
1899
|
}
|
|
@@ -2175,6 +2224,41 @@ function mapReasoningLevelToGeminiThinking(
|
|
|
2175
2224
|
/** Stream against /responses (Codex, OpenAI Responses API). Exported
|
|
2176
2225
|
* so tests can exercise header/body shape without spinning up the
|
|
2177
2226
|
* full makeCodexProvider path. */
|
|
2227
|
+
function buildCodexResponsesWireBody(
|
|
2228
|
+
body: {
|
|
2229
|
+
model: string;
|
|
2230
|
+
instructions: string;
|
|
2231
|
+
input: unknown[];
|
|
2232
|
+
tools?: unknown[];
|
|
2233
|
+
tool_choice?: unknown;
|
|
2234
|
+
reasoning?: { effort?: 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'; summary?: 'auto' | 'concise' | 'detailed' };
|
|
2235
|
+
store?: boolean;
|
|
2236
|
+
previousResponseId?: string;
|
|
2237
|
+
},
|
|
2238
|
+
promptCache: boolean,
|
|
2239
|
+
): Record<string, unknown> {
|
|
2240
|
+
const cacheKey = promptCache ? computePromptCacheKey(body.model, body.instructions) : undefined;
|
|
2241
|
+
return {
|
|
2242
|
+
...body,
|
|
2243
|
+
stream: true,
|
|
2244
|
+
store: body.store === true,
|
|
2245
|
+
...(body.tool_choice ? { tool_choice: body.tool_choice } : {}),
|
|
2246
|
+
...(body.previousResponseId ? { previous_response_id: body.previousResponseId } : {}),
|
|
2247
|
+
...(cacheKey ? { prompt_cache_key: cacheKey } : {}),
|
|
2248
|
+
...(body.reasoning ? {
|
|
2249
|
+
reasoning: body.reasoning,
|
|
2250
|
+
include: ['reasoning.encrypted_content'],
|
|
2251
|
+
} : {}),
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
function serializeCodexResponsesWireBody(
|
|
2256
|
+
body: Parameters<typeof buildCodexResponsesWireBody>[0],
|
|
2257
|
+
promptCache: boolean,
|
|
2258
|
+
): string {
|
|
2259
|
+
return JSON.stringify(buildCodexResponsesWireBody(body, promptCache));
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2178
2262
|
export async function* streamCodexResponsesEvents(
|
|
2179
2263
|
url: string,
|
|
2180
2264
|
bearer: string,
|
|
@@ -2221,6 +2305,9 @@ export async function* streamCodexResponsesEvents(
|
|
|
2221
2305
|
/** Opt-out hook (tests). When false, skips the
|
|
2222
2306
|
* `prompt_cache_key` body field; production always passes true. */
|
|
2223
2307
|
promptCache?: boolean;
|
|
2308
|
+
/** Exact body string already serialized by the request-size preflight.
|
|
2309
|
+
* Passing it through ensures the measured bytes are the bytes fetched. */
|
|
2310
|
+
serializedWireBody?: string;
|
|
2224
2311
|
/** Callback fired when the SSE stream emits `response.created`
|
|
2225
2312
|
* carrying the new response's id. Used by makeCodexProvider to
|
|
2226
2313
|
* capture the id and thread `previousResponseId` on the next
|
|
@@ -2274,32 +2361,16 @@ export async function* streamCodexResponsesEvents(
|
|
|
2274
2361
|
// value codex_cli_rs ships) so the backend
|
|
2275
2362
|
// applies the same tool/SSE conventions
|
|
2276
2363
|
const promptCache = extra.promptCache !== false;
|
|
2277
|
-
|
|
2278
|
-
//
|
|
2279
|
-
const wireBody
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
// to send only the delta input items. Default still false so any
|
|
2285
|
-
// caller that doesn't opt in (tests building bodies directly)
|
|
2286
|
-
// sees the legacy wire shape.
|
|
2364
|
+
// TUI-REQUEST-SIZE-COMPACT — the exact serializer is shared with the
|
|
2365
|
+
// preflight guard, so the size decision and fetch body cannot drift.
|
|
2366
|
+
const wireBody = buildCodexResponsesWireBody(body, promptCache);
|
|
2367
|
+
const wireJson = extra.serializedWireBody ?? JSON.stringify(wireBody);
|
|
2368
|
+
debug.log('llm.request', 'request-size', {
|
|
2369
|
+
provider: 'openai-codex',
|
|
2370
|
+
requestChars: wireJson.length,
|
|
2287
2371
|
store: body.store === true,
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
...(cacheKey ? { prompt_cache_key: cacheKey } : {}),
|
|
2291
|
-
// Reasoning opt-in (gpt-5 family). When the caller sets
|
|
2292
|
-
// body.reasoning we mirror it onto the wire AND append the
|
|
2293
|
-
// include directive that lets multi-turn requests thread the
|
|
2294
|
-
// model's encrypted reasoning context. Omit both when absent
|
|
2295
|
-
// so non-reasoning models / opt-out users see the legacy
|
|
2296
|
-
// wire shape unchanged.
|
|
2297
|
-
...(body.reasoning ? {
|
|
2298
|
-
reasoning: body.reasoning,
|
|
2299
|
-
include: ['reasoning.encrypted_content'],
|
|
2300
|
-
} : {}),
|
|
2301
|
-
};
|
|
2302
|
-
const wireJson = JSON.stringify(wireBody);
|
|
2372
|
+
previousResponseId: body.previousResponseId ? `${body.previousResponseId.slice(0, 12)}…` : null,
|
|
2373
|
+
});
|
|
2303
2374
|
const response = await fetchApiWithRetry(
|
|
2304
2375
|
url,
|
|
2305
2376
|
{
|
|
@@ -2328,6 +2399,10 @@ export async function* streamCodexResponsesEvents(
|
|
|
2328
2399
|
debug.log('llm.response.status', `codex ${response.status}`, {
|
|
2329
2400
|
url, status: response.status, elapsedMs: Date.now() - startedAt,
|
|
2330
2401
|
});
|
|
2402
|
+
let messagePhase: 'commentary' | 'final' | undefined;
|
|
2403
|
+
const codexTextPhase = (value: unknown): 'commentary' | 'final' | undefined =>
|
|
2404
|
+
value === 'commentary' || value === 'partial_answer' ? 'commentary'
|
|
2405
|
+
: value === 'final_answer' ? 'final' : undefined;
|
|
2331
2406
|
try {
|
|
2332
2407
|
for await (const line of sseLineStream(response.body!)) {
|
|
2333
2408
|
if (!line.startsWith('data: ')) continue;
|
|
@@ -2347,15 +2422,32 @@ export async function* streamCodexResponsesEvents(
|
|
|
2347
2422
|
extra.onResponseCreated(id);
|
|
2348
2423
|
}
|
|
2349
2424
|
}
|
|
2425
|
+
if (type === 'response.output_item.added' || type === 'response.output_item.done') {
|
|
2426
|
+
if (parsed.item?.type === 'message') {
|
|
2427
|
+
const phase = codexTextPhase(parsed.item.phase);
|
|
2428
|
+
if (type === 'response.output_item.added') messagePhase = phase;
|
|
2429
|
+
if (phase) {
|
|
2430
|
+
messagePhase = phase;
|
|
2431
|
+
yield { type: 'text_phase', phase };
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2350
2435
|
// Text tokens — both `response.output_text.delta` (new naming) and
|
|
2351
2436
|
// raw `output_text.delta` (older streams).
|
|
2352
2437
|
if (type.endsWith('output_text.delta')) {
|
|
2353
2438
|
const delta = parsed.delta || '';
|
|
2354
|
-
if (delta) yield { type: 'text', delta };
|
|
2439
|
+
if (delta) yield { type: 'text', delta, ...(messagePhase ? { phase: messagePhase } : {}) };
|
|
2355
2440
|
}
|
|
2356
2441
|
// Tool calls come in as `response.output_item.done` with item.type = 'function_call'.
|
|
2357
2442
|
if (type === 'response.output_item.done') {
|
|
2358
2443
|
const item = parsed.item;
|
|
2444
|
+
if (item?.type === 'reasoning' && typeof item.encrypted_content === 'string' && item.encrypted_content) {
|
|
2445
|
+
yield { type: 'codex_reasoning_item', item: {
|
|
2446
|
+
type: 'reasoning', encrypted_content: item.encrypted_content,
|
|
2447
|
+
summary: Array.isArray(item.summary) ? item.summary : [],
|
|
2448
|
+
...(typeof item.id === 'string' ? { id: item.id } : {}),
|
|
2449
|
+
} };
|
|
2450
|
+
}
|
|
2359
2451
|
if (item && item.type === 'function_call') {
|
|
2360
2452
|
let args: Record<string, unknown> = {};
|
|
2361
2453
|
try { args = item.arguments ? JSON.parse(item.arguments) : {}; } catch { /* empty */ }
|
|
@@ -2410,6 +2502,9 @@ export async function* streamCodexResponsesEvents(
|
|
|
2410
2502
|
// hit rate for codex regardless. See store=true wave (next+1)
|
|
2411
2503
|
// for the volume-side counterpart.
|
|
2412
2504
|
if (type === 'response.completed') {
|
|
2505
|
+
if (typeof parsed.response?.end_turn === 'boolean') {
|
|
2506
|
+
yield { type: 'turn_end', endTurn: parsed.response.end_turn };
|
|
2507
|
+
}
|
|
2413
2508
|
const u = parsed.response?.usage;
|
|
2414
2509
|
if (u && typeof u === 'object') {
|
|
2415
2510
|
const cached = u.input_tokens_details?.cached_tokens
|
|
@@ -4474,6 +4569,13 @@ function explainAndLogFallbackCandidates(
|
|
|
4474
4569
|
|
|
4475
4570
|
/** 스트림 중 끊김 재시도 상한 — codex `DEFAULT_STREAM_MAX_RETRIES`(5) 와 같은 값. */
|
|
4476
4571
|
const STREAM_DISCONNECT_MAX_RETRIES = 5;
|
|
4572
|
+
class StreamIdleTimeoutError extends Error {
|
|
4573
|
+
constructor(readonly idleMs: number) {
|
|
4574
|
+
super(`stream idle timeout after ${idleMs}ms`);
|
|
4575
|
+
this.name = 'StreamIdleTimeoutError';
|
|
4576
|
+
Object.assign(this, { code: 'ETIMEDOUT' });
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4477
4579
|
const STREAM_IDLE_TIMEOUT_MAX_RETRIES = 1;
|
|
4478
4580
|
let streamDisconnectRetryDelayMs: (attempt: number) => number = backoffMs;
|
|
4479
4581
|
|
|
@@ -4799,6 +4901,20 @@ type ProviderTextResult =
|
|
|
4799
4901
|
| { ok: true; full: string; usage: ObservedUsage | 'unmeasured' }
|
|
4800
4902
|
| { ok: false; full: string; error: unknown };
|
|
4801
4903
|
|
|
4904
|
+
function resolveStreamIdleTimeout(opts: LLMOpts, provider: LLMProvider, model: string): { ms: number; source: 'call' | 'config' | 'default' } {
|
|
4905
|
+
if (opts.streamIdleTimeoutMs !== undefined
|
|
4906
|
+
&& Number.isFinite(opts.streamIdleTimeoutMs) && opts.streamIdleTimeoutMs > 0) {
|
|
4907
|
+
return { ms: opts.streamIdleTimeoutMs, source: 'call' };
|
|
4908
|
+
}
|
|
4909
|
+
let configured: number | undefined;
|
|
4910
|
+
try {
|
|
4911
|
+
configured = (require('./user-config.js') as typeof import('./user-config.js')).getUserConfig().llm.streamIdleTimeoutMs;
|
|
4912
|
+
} catch { /* config lookup is fail-soft; preserve provider defaults */ }
|
|
4913
|
+
if (configured !== undefined) return { ms: configured, source: 'config' };
|
|
4914
|
+
const longIdle = usesLongReasoningIdle(getModelFamily(model), provider.name);
|
|
4915
|
+
return { ms: longIdle ? STREAM_IDLE_TIMEOUT_MS_REASONING : STREAM_IDLE_TIMEOUT_MS, source: 'default' };
|
|
4916
|
+
}
|
|
4917
|
+
|
|
4802
4918
|
function accumulateUsage(usage: ObservedUsage | undefined, received: LLMUsage): ObservedUsage {
|
|
4803
4919
|
const total = { ...usage };
|
|
4804
4920
|
for (const field of ['inputTokens', 'outputTokens', 'cacheReadInputTokens', 'cacheCreationInputTokens', 'reportedCostUsd'] as const) {
|
|
@@ -4836,10 +4952,8 @@ async function consumeProviderText(
|
|
|
4836
4952
|
// Preserve the provider or callback error that caused this close.
|
|
4837
4953
|
}
|
|
4838
4954
|
};
|
|
4839
|
-
const
|
|
4840
|
-
|
|
4841
|
-
? STREAM_IDLE_TIMEOUT_MS_REASONING : STREAM_IDLE_TIMEOUT_MS
|
|
4842
|
-
);
|
|
4955
|
+
const idleTimeout = resolveStreamIdleTimeout(opts, provider, opts.model ?? provider.defaultModel);
|
|
4956
|
+
const idleMs = idleTimeout.ms;
|
|
4843
4957
|
|
|
4844
4958
|
while (true) {
|
|
4845
4959
|
let idleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
@@ -4860,10 +4974,9 @@ async function consumeProviderText(
|
|
|
4860
4974
|
if (step.idle) {
|
|
4861
4975
|
debug.log('llm', 'stream-idle-timeout', {
|
|
4862
4976
|
provider: provider.name, model: opts.model ?? provider.defaultModel,
|
|
4863
|
-
idleMs, receivedChars: full.length, site: 'stream-llm',
|
|
4977
|
+
idleMs, idleMsSource: idleTimeout.source, receivedChars: full.length, site: 'stream-llm',
|
|
4864
4978
|
});
|
|
4865
|
-
const error = new
|
|
4866
|
-
error.name = 'StreamIdleTimeoutError';
|
|
4979
|
+
const error = new StreamIdleTimeoutError(idleMs);
|
|
4867
4980
|
// An async generator can leave return() pending behind a stalled next().
|
|
4868
4981
|
void closeIterator();
|
|
4869
4982
|
return { ok: false, full, error };
|
|
@@ -4945,6 +5058,7 @@ export async function streamLLM(
|
|
|
4945
5058
|
textChars: full.length,
|
|
4946
5059
|
usage: consumed.usage,
|
|
4947
5060
|
});
|
|
5061
|
+
(await import('./session-runtime/provider-circuit.js')).recordProviderSuccess(activeProvider.name, Date.now());
|
|
4948
5062
|
return full;
|
|
4949
5063
|
}
|
|
4950
5064
|
|
|
@@ -4962,6 +5076,7 @@ export async function streamLLM(
|
|
|
4962
5076
|
status: err.status,
|
|
4963
5077
|
kind: err.kind,
|
|
4964
5078
|
}, { level: 'warn' });
|
|
5079
|
+
(await import('./session-runtime/provider-circuit.js')).recordProviderFailure(activeProvider.name, 'overload-failover', Date.now());
|
|
4965
5080
|
activeProvider = switched;
|
|
4966
5081
|
modelOverride = undefined;
|
|
4967
5082
|
attemptedProviders.add(activeProvider.name);
|
|
@@ -4998,6 +5113,7 @@ export async function streamLLM(
|
|
|
4998
5113
|
tools: opts.tools?.map((tool) => tool.name) ?? [],
|
|
4999
5114
|
...(opts.model ? { modelOverrideDropped: opts.model } : {}),
|
|
5000
5115
|
}, { level: 'warn' });
|
|
5116
|
+
(await import('./session-runtime/provider-circuit.js')).recordProviderFailure(activeProvider.name, verdict.category, Date.now());
|
|
5001
5117
|
activeProvider = fallback;
|
|
5002
5118
|
modelOverride = undefined;
|
|
5003
5119
|
attemptedProviders.add(activeProvider.name);
|
|
@@ -5123,7 +5239,7 @@ export function resolveDefaultProvider(model?: string): LLMProvider {
|
|
|
5123
5239
|
export interface StreamWithToolsHandlers {
|
|
5124
5240
|
/** Streaming text delta — invoked for every text chunk across all turns. */
|
|
5125
5241
|
onText(delta: string, fullAcrossTurns: string): void;
|
|
5126
|
-
/**
|
|
5242
|
+
/** Transient user-visible status emitted by stream recovery (not model text). */
|
|
5127
5243
|
onStatus?(line: string): void;
|
|
5128
5244
|
/** Dispatch a tool call. Returning undefined/null throws in the loop so
|
|
5129
5245
|
* callers should always return a JSON-serializable value (can be an
|
|
@@ -8336,12 +8452,42 @@ export async function streamLLMWithTools(
|
|
|
8336
8452
|
skipProviders?: readonly string[];
|
|
8337
8453
|
} = {},
|
|
8338
8454
|
): Promise<string> {
|
|
8455
|
+
// Fixed providers keep the original synchronous launch path. Load the circuit before
|
|
8456
|
+
// selection only when it can change this turn's initial provider.
|
|
8457
|
+
const circuit = !opts.provider && !opts.initialProvider
|
|
8458
|
+
? await import('./session-runtime/provider-circuit.js')
|
|
8459
|
+
: undefined;
|
|
8339
8460
|
const provider = opts.provider ?? opts.initialProvider ?? resolveDefaultProvider(opts.model);
|
|
8340
8461
|
const initial = finalizeStreamingProviderModel(provider, opts.model ?? provider.defaultModel);
|
|
8341
8462
|
let activeProvider = initial.provider;
|
|
8342
8463
|
let activeModel = initial.model;
|
|
8464
|
+
let circuitBlockedInitialProvider: string | undefined;
|
|
8465
|
+
// SURVIVAL-PROVIDER-CIRCUIT (S2): 명시·고정 공급자(`provider`·`initialProvider`)가 없고
|
|
8466
|
+
// 회로가 열려(open) 있으면, 체인 해석(`remainingFallbackProviderNames` 순서)의 첫
|
|
8467
|
+
// closed(없으면 half-open) 공급자로 이번 턴을 연다. 모두 open 이면 원래 1순위를 그대로
|
|
8468
|
+
// 쓴다(«갈 곳 없음 = 멈춤»이 아니다) — `circuit-all-open` 관측만 남긴다.
|
|
8469
|
+
if (circuit && circuit.circuitState(activeProvider.name, Date.now()) === 'open') {
|
|
8470
|
+
const chainNames = [activeProvider.name, ...remainingFallbackProviderNames(new Set(opts.skipProviders ?? []), opts)]
|
|
8471
|
+
.filter((name) => providerByName(name)?.available());
|
|
8472
|
+
const pickedName = circuit.pickInitialProvider(chainNames, Date.now());
|
|
8473
|
+
const picked = pickedName && pickedName !== activeProvider.name ? providerByName(pickedName) : undefined;
|
|
8474
|
+
if (picked && picked.available()) {
|
|
8475
|
+
circuitBlockedInitialProvider = activeProvider.name;
|
|
8476
|
+
debug.log('tui.survival', 'turn-opened-on-fallback', { blocked: activeProvider.name, opened: picked.name });
|
|
8477
|
+
handlers.onStatus?.(`⚡ ${activeProvider.name} 회로 열림 — 이번 턴은 ${picked.name}`);
|
|
8478
|
+
const pickedInitial = finalizeStreamingProviderModel(picked, picked.defaultModel);
|
|
8479
|
+
activeProvider = pickedInitial.provider;
|
|
8480
|
+
activeModel = pickedInitial.model;
|
|
8481
|
+
} else {
|
|
8482
|
+
debug.log('tui.survival', 'circuit-all-open', { blocked: activeProvider.name });
|
|
8483
|
+
}
|
|
8484
|
+
}
|
|
8343
8485
|
opts.onResolvedProvider?.(activeProvider.name, activeModel);
|
|
8344
|
-
const attemptedProviders = new Set<string>([
|
|
8486
|
+
const attemptedProviders = new Set<string>([
|
|
8487
|
+
activeProvider.name,
|
|
8488
|
+
...(circuitBlockedInitialProvider ? [circuitBlockedInitialProvider] : []),
|
|
8489
|
+
...(opts.skipProviders ?? []),
|
|
8490
|
+
]);
|
|
8345
8491
|
let blockedProviders: ProviderFallbackAttempt[] = [];
|
|
8346
8492
|
const effectiveModel = activeModel;
|
|
8347
8493
|
const modelFamily = getModelFamily(effectiveModel);
|
|
@@ -8361,7 +8507,7 @@ export async function streamLLMWithTools(
|
|
|
8361
8507
|
tools: opts.tools?.map(t => t.name),
|
|
8362
8508
|
toolsAvailable: !!provider.streamChat && (opts.tools?.length ?? 0) > 0,
|
|
8363
8509
|
}, { level: 'info' });
|
|
8364
|
-
if (!provider.streamChat ||
|
|
8510
|
+
if (!provider.streamChat || ((opts.tools?.length ?? 0) === 0 && provider.name !== 'openai-codex')) {
|
|
8365
8511
|
// No tool support or no tools requested — delegate to plain streamLLM.
|
|
8366
8512
|
debug.log('llm.router', 'streamLLMWithTools.fallback', {
|
|
8367
8513
|
reason: !provider.streamChat ? 'provider-no-streamChat' : 'no-tools',
|
|
@@ -8522,6 +8668,8 @@ export async function streamLLMWithTools(
|
|
|
8522
8668
|
}
|
|
8523
8669
|
// OR-DEEPSEEK-TUNE — 마지막 턴의 «도구 없는» 추론(deepseek/* 만 채워진다). 매 턴 시작에 비운다.
|
|
8524
8670
|
let turnReasoningDetails: Array<Record<string, unknown>> | undefined;
|
|
8671
|
+
let turnCodexReasoningItems: LLMMessage['codexReasoningItems'];
|
|
8672
|
+
let turnCodexTextPhase: LLMMessage['phase'];
|
|
8525
8673
|
const emitTurnComplete = (finalAssistantText?: string): void => {
|
|
8526
8674
|
if (finalAssistantText && finalAssistantText.length > 0) {
|
|
8527
8675
|
history.push({
|
|
@@ -8530,18 +8678,23 @@ export async function streamLLMWithTools(
|
|
|
8530
8678
|
type: 'text', text: finalAssistantText,
|
|
8531
8679
|
...(turnReasoningDetails ? { providerMeta: { reasoningDetails: turnReasoningDetails } } : {}),
|
|
8532
8680
|
}],
|
|
8681
|
+
...(turnCodexReasoningItems?.length ? { codexReasoningItems: turnCodexReasoningItems } : {}),
|
|
8682
|
+
...(turnCodexTextPhase ? { phase: turnCodexTextPhase } : {}),
|
|
8533
8683
|
});
|
|
8534
8684
|
}
|
|
8535
8685
|
handlers.onTurnComplete?.(history.slice(initialHistoryLen));
|
|
8536
8686
|
};
|
|
8537
8687
|
let fullText = '';
|
|
8538
8688
|
let sawToolRound = false;
|
|
8689
|
+
let codexContinuationNeeded = false;
|
|
8539
8690
|
// TUI-GOAL-LOOP-FRICTION — 종결 신호 도구(LLMOpts.terminalToolNames). 비면 아래 분기는 전부 꺼진다.
|
|
8540
8691
|
const terminalToolNames: ReadonlySet<string> = new Set(opts.terminalToolNames ?? []);
|
|
8541
8692
|
/** 이 스트림에서 종결 신호를 한 번이라도 디스패치했나. */
|
|
8542
8693
|
let terminalSignalDispatched = false;
|
|
8694
|
+
let completionNeedsFinalTurn = false;
|
|
8543
8695
|
/** 도구 라운드에 실린 마지막 «비지 않은» 답 텍스트(종결 신호 턴 마감·빈 턴 포기에서 쓴다). */
|
|
8544
8696
|
let lastToolRoundText = '';
|
|
8697
|
+
let lastToolRoundTextPhase: 'commentary' | 'final' | undefined;
|
|
8545
8698
|
const agentBatchTickIntervalMs = opts.agentBatchTickIntervalMs ?? BATCH_TICK_INTERVAL_MS;
|
|
8546
8699
|
|
|
8547
8700
|
// Empty-turn guard: smaller models (gpt-5.4-mini, haiku) sometimes
|
|
@@ -8715,7 +8868,7 @@ export async function streamLLMWithTools(
|
|
|
8715
8868
|
let loopTermination: 'budget-exhausted' | 'aborted' = 'budget-exhausted';
|
|
8716
8869
|
let terminalTurn = maxTurns;
|
|
8717
8870
|
|
|
8718
|
-
for (let turn = 0; turn < maxTurns; turn++) {
|
|
8871
|
+
for (let turn = 0; turn < maxTurns || ((completionNeedsFinalTurn || codexContinuationNeeded) && turn === maxTurns); turn++) {
|
|
8719
8872
|
// ★ /cancel 범용화(대표 2026-07-12) — abort 신호가 오면 tool 루프를 즉시 중단한다. 이게 없으면
|
|
8720
8873
|
// fetch 는 abort 돼도 루프가 다음 turn 으로 계속 돌아 tool 반복(grep 폭주 등)이 멈추지 않는다.
|
|
8721
8874
|
if (opts.signal?.aborted) {
|
|
@@ -8748,6 +8901,11 @@ export async function streamLLMWithTools(
|
|
|
8748
8901
|
}
|
|
8749
8902
|
}
|
|
8750
8903
|
let turnText = '';
|
|
8904
|
+
let turnTextPhase: 'commentary' | 'final' | undefined;
|
|
8905
|
+
let turnEnd: boolean | undefined;
|
|
8906
|
+
codexContinuationNeeded = false;
|
|
8907
|
+
turnCodexReasoningItems = undefined;
|
|
8908
|
+
turnCodexTextPhase = undefined;
|
|
8751
8909
|
// TUI-TURN-NARRATION — 이 라운드에 받은 추론 요약 글자 수(내용은 남기지 않는다).
|
|
8752
8910
|
let turnReasoningChars = 0;
|
|
8753
8911
|
turnReasoningDetails = undefined;
|
|
@@ -8847,13 +9005,14 @@ export async function streamLLMWithTools(
|
|
|
8847
9005
|
// revert to auto (see above).
|
|
8848
9006
|
const buildTurnOpts = () => {
|
|
8849
9007
|
const remainingFallbacks = opts.provider ? 0 : remainingFallbackProviderNames(attemptedProviders, opts).length;
|
|
8850
|
-
const base = { ...opts, model: activeModel, tools: activeTools, remainingFallbacks };
|
|
9008
|
+
const base = { ...opts, model: activeModel, tools: completionNeedsFinalTurn ? [] : activeTools, remainingFallbacks };
|
|
8851
9009
|
return turn === 0 ? base : { ...base, toolChoice: undefined };
|
|
8852
9010
|
};
|
|
8853
9011
|
let turnOpts = buildTurnOpts();
|
|
8854
9012
|
// reasoning-heavy family(codex/claude/gemini/grok/local)는 침묵 추론 구간이 길어 idle watchdog 를
|
|
8855
9013
|
// family-aware 로 상향(2026-07-19 goal-exec → 아크4 전-family). fast/mini(gpt·other)만 45s 유지.
|
|
8856
|
-
const
|
|
9014
|
+
const idleTimeout = resolveStreamIdleTimeout(opts, activeProvider, activeModel);
|
|
9015
|
+
const streamIdleTimeoutMs = idleTimeout.ms;
|
|
8857
9016
|
// ⚠️ hang 진단(2026-07-17) — codex SSE 스트림이 완료 신호 없이 안 끝나는 케이스 확정용.
|
|
8858
9017
|
// consume-start 후 consume-end 가 없으면 = for-await(streamChat SSE) hang. lastEvType 로 어느
|
|
8859
9018
|
// 이벤트 뒤에서 멈추는지(usage/text/tool_call) 특정. 무장할 상한도 남겨 실험 런을 구별한다.
|
|
@@ -8862,6 +9021,7 @@ export async function streamLLMWithTools(
|
|
|
8862
9021
|
provider: activeProvider.name,
|
|
8863
9022
|
model: activeModel,
|
|
8864
9023
|
idleMs: streamIdleTimeoutMs,
|
|
9024
|
+
idleMsSource: idleTimeout.source,
|
|
8865
9025
|
...(modelFamily !== 'other' ? { modelFamily } : {}),
|
|
8866
9026
|
});
|
|
8867
9027
|
let evCount = 0;
|
|
@@ -8870,6 +9030,7 @@ export async function streamLLMWithTools(
|
|
|
8870
9030
|
// 다시 건다(codex `stream_max_retries` 동형). 이 턴에서 받은 tool_call·image 가 있으면 재시도하지 않는다.
|
|
8871
9031
|
let streamDisconnectRetries = 0;
|
|
8872
9032
|
let streamIdleTimeoutRetries = 0;
|
|
9033
|
+
let streamIdleRetryPartial = '';
|
|
8873
9034
|
let streamEmittedImage = false;
|
|
8874
9035
|
// 끊긴 조각을 이력(turnText·fullText)에서 «조용히» 되감는다 — 화면엔 지우라고 알리지 않는다
|
|
8875
9036
|
// (TUI 의 빈 델타는 «커밋»이다). 이미 보인 글과 겹치는 재시도 본문은 `retryDisplay` 가 막는다.
|
|
@@ -8887,6 +9048,7 @@ export async function streamLLMWithTools(
|
|
|
8887
9048
|
if (turnText.length > 0) {
|
|
8888
9049
|
fullText = fullText.slice(0, fullText.length - turnText.length);
|
|
8889
9050
|
turnText = '';
|
|
9051
|
+
turnTextPhase = undefined;
|
|
8890
9052
|
}
|
|
8891
9053
|
turnReasoningChars = 0;
|
|
8892
9054
|
retryDisplay.arm();
|
|
@@ -8898,6 +9060,19 @@ export async function streamLLMWithTools(
|
|
|
8898
9060
|
// 이벤트 대기를 idle timeout 과 race — STREAM_IDLE_TIMEOUT_MS 무이벤트면 스트림 정리·탈출(받은
|
|
8899
9061
|
// 텍스트로 진행). 35분 무한 hang → 자동 복구. 원인 규명은 consume-end 부재/idle-timeout 로그가.
|
|
8900
9062
|
let streamIter: AsyncIterator<LLMStreamEvent> | undefined;
|
|
9063
|
+
let streamAttemptAbort: AbortController | undefined;
|
|
9064
|
+
let streamAttemptAbortCleanup: (() => void) | undefined;
|
|
9065
|
+
const releaseStreamAttempt = (abort = false, reason?: unknown): void => {
|
|
9066
|
+
if (abort) streamAttemptAbort?.abort(reason);
|
|
9067
|
+
streamAttemptAbortCleanup?.();
|
|
9068
|
+
streamAttemptAbortCleanup = undefined;
|
|
9069
|
+
streamAttemptAbort = undefined;
|
|
9070
|
+
};
|
|
9071
|
+
let providerToolSchemaDiagnostics: Record<string, {
|
|
9072
|
+
originalName: string;
|
|
9073
|
+
providerName: string;
|
|
9074
|
+
tupleItemsPaths: Record<string, string>;
|
|
9075
|
+
}> | undefined;
|
|
8901
9076
|
while (true) {
|
|
8902
9077
|
let idleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
8903
9078
|
let step: { idle: true } | { idle: false; r: IteratorResult<LLMStreamEvent, void> };
|
|
@@ -8927,8 +9102,22 @@ export async function streamLLMWithTools(
|
|
|
8927
9102
|
? [turnOpts.toolChoice.name]
|
|
8928
9103
|
: []),
|
|
8929
9104
|
]);
|
|
9105
|
+
const attemptAbort = new AbortController();
|
|
9106
|
+
const forwardExternalAbort = () => attemptAbort.abort(opts.signal?.reason);
|
|
9107
|
+
if (opts.signal?.aborted) forwardExternalAbort();
|
|
9108
|
+
else opts.signal?.addEventListener('abort', forwardExternalAbort, { once: true });
|
|
9109
|
+
streamAttemptAbort = attemptAbort;
|
|
9110
|
+
streamAttemptAbortCleanup = () => opts.signal?.removeEventListener('abort', forwardExternalAbort);
|
|
9111
|
+
providerToolSchemaDiagnostics = Object.fromEntries((turnOpts.tools ?? []).map((tool, index) => [String(index), {
|
|
9112
|
+
originalName: tool.name,
|
|
9113
|
+
providerName: nameMap.toProviderName(tool.name),
|
|
9114
|
+
tupleItemsPaths: Object.fromEntries(
|
|
9115
|
+
collectTupleItemsSchemaPaths(tool.parameters).map((path, pathIndex) => [String(pathIndex), path]),
|
|
9116
|
+
),
|
|
9117
|
+
}]));
|
|
8930
9118
|
const providerOpts: LLMOpts = {
|
|
8931
9119
|
...turnOpts,
|
|
9120
|
+
signal: attemptAbort.signal,
|
|
8932
9121
|
tools: turnOpts.tools?.map((tool) => ({ ...tool, name: nameMap.toProviderName(tool.name) })),
|
|
8933
9122
|
toolChoice: turnOpts.toolChoice && typeof turnOpts.toolChoice === 'object'
|
|
8934
9123
|
? { name: nameMap.toProviderName(turnOpts.toolChoice.name) }
|
|
@@ -8944,21 +9133,25 @@ export async function streamLLMWithTools(
|
|
|
8944
9133
|
streamIter.next().then((r) => ({ idle: false as const, r })),
|
|
8945
9134
|
new Promise<{ idle: true }>((res) => { idleTimer = setTimeout(() => res({ idle: true }), streamIdleTimeoutMs); }),
|
|
8946
9135
|
]);
|
|
8947
|
-
if (step.idle)
|
|
8948
|
-
const error = new Error(`stream idle timeout after ${streamIdleTimeoutMs}ms`);
|
|
8949
|
-
error.name = 'StreamIdleTimeoutError';
|
|
8950
|
-
Object.assign(error, { code: 'ETIMEDOUT' });
|
|
8951
|
-
throw error;
|
|
8952
|
-
}
|
|
9136
|
+
if (step.idle) throw new StreamIdleTimeoutError(streamIdleTimeoutMs);
|
|
8953
9137
|
} catch (err) {
|
|
8954
9138
|
if (idleTimer) clearTimeout(idleTimer);
|
|
8955
|
-
|
|
9139
|
+
releaseStreamAttempt(true, err);
|
|
9140
|
+
if (err instanceof ApiHttpError && err.status === 400 && providerToolSchemaDiagnostics) {
|
|
9141
|
+
debug.log('llm.tool-schema', 'provider-request-rejected', {
|
|
9142
|
+
provider: activeProvider.name,
|
|
9143
|
+
model: activeModel,
|
|
9144
|
+
turn,
|
|
9145
|
+
status: err.status,
|
|
9146
|
+
tools: providerToolSchemaDiagnostics,
|
|
9147
|
+
}, { level: 'warn' });
|
|
9148
|
+
}
|
|
9149
|
+
if (err instanceof StreamIdleTimeoutError) {
|
|
8956
9150
|
debug.log('llm.stream', 'idle-timeout', {
|
|
8957
|
-
turn, evCount, lastEvType, idleMs:
|
|
9151
|
+
turn, evCount, lastEvType, idleMs: err.idleMs, idleMsSource: idleTimeout.source,
|
|
8958
9152
|
textChars: turnText.length, pendingCalls: pendingCalls.length,
|
|
8959
9153
|
}, { level: 'warn' });
|
|
8960
|
-
//
|
|
8961
|
-
// Detach cleanup so it cannot keep the user turn busy forever.
|
|
9154
|
+
// Provider iterators can queue return() behind a pending next(). Detach cleanup.
|
|
8962
9155
|
const timedOutIterator = streamIter;
|
|
8963
9156
|
if (timedOutIterator?.return) {
|
|
8964
9157
|
try { void Promise.resolve(timedOutIterator.return(undefined)).catch(() => {}); } catch { /* fail-soft cleanup */ }
|
|
@@ -8971,18 +9164,29 @@ export async function streamLLMWithTools(
|
|
|
8971
9164
|
attempt: streamIdleTimeoutRetries, maxRetries: STREAM_IDLE_TIMEOUT_MAX_RETRIES,
|
|
8972
9165
|
delayMs: 0, statusLine: '스트림 무응답 · 재시도',
|
|
8973
9166
|
}, { level: 'warn' });
|
|
8974
|
-
handlers.onStatus?.(`스트림 무응답 · 재시도 ${streamIdleTimeoutRetries}/${STREAM_IDLE_TIMEOUT_MAX_RETRIES}`);
|
|
9167
|
+
try { handlers.onStatus?.(`스트림 무응답 · 재시도 ${streamIdleTimeoutRetries}/${STREAM_IDLE_TIMEOUT_MAX_RETRIES}`); } catch { /* UI notification must not block recovery */ }
|
|
9168
|
+
streamIdleRetryPartial = turnText;
|
|
8975
9169
|
rewindDisconnectedStream();
|
|
8976
9170
|
streamIter = undefined;
|
|
8977
9171
|
continue;
|
|
8978
9172
|
}
|
|
8979
|
-
//
|
|
8980
|
-
|
|
8981
|
-
if (
|
|
8982
|
-
if (opts.provider
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
9173
|
+
// Do not replay or advance providers after a tool side effect or image escaped.
|
|
9174
|
+
if (pendingCalls.length > 0 || streamEmittedImage) break;
|
|
9175
|
+
if (opts.signal?.aborted) throw err;
|
|
9176
|
+
if (opts.provider && (turnText.length > 0 || streamIdleRetryPartial.length > 0)) {
|
|
9177
|
+
// A pinned provider cannot advance to fallback. Keep already shown partial text
|
|
9178
|
+
// and complete the turn instead of rewinding it and failing the whole response.
|
|
9179
|
+
if (turnText.length === 0 && streamIdleRetryPartial.length > 0) {
|
|
9180
|
+
turnText = streamIdleRetryPartial;
|
|
9181
|
+
fullText += streamIdleRetryPartial;
|
|
9182
|
+
}
|
|
9183
|
+
try { handlers.onStatus?.('스트림 무응답 · 재시도 소진 (부분 응답 유지)'); } catch { /* status is fail-soft */ }
|
|
9184
|
+
debug.log('llm.stream', 'idle-timeout-pinned-partial-preserved', { turn, evCount, lastEvType, textChars: turnText.length }, { level: 'warn' });
|
|
9185
|
+
break;
|
|
9186
|
+
}
|
|
9187
|
+
if (opts.provider) throw err;
|
|
9188
|
+
rewindDisconnectedStream();
|
|
9189
|
+
streamIter = undefined;
|
|
8986
9190
|
}
|
|
8987
9191
|
if (err instanceof OverloadFailoverError && !opts.provider) {
|
|
8988
9192
|
const switched = activeProvider.name === 'openai-codex'
|
|
@@ -8990,6 +9194,7 @@ export async function streamLLMWithTools(
|
|
|
8990
9194
|
: providerByName('grok');
|
|
8991
9195
|
if (switched && !attemptedProviders.has(switched.name)
|
|
8992
9196
|
&& (activeProvider.name === 'openai-codex' || switched.available()) && evCount === 0) {
|
|
9197
|
+
(circuit ?? await import('./session-runtime/provider-circuit.js')).recordProviderFailure(activeProvider.name, 'overload-failover', Date.now());
|
|
8993
9198
|
debug.log('llm.router', 'overload-failover', {
|
|
8994
9199
|
turn,
|
|
8995
9200
|
blockedProvider: activeProvider.name,
|
|
@@ -9004,13 +9209,13 @@ export async function streamLLMWithTools(
|
|
|
9004
9209
|
activeModel = finalized.model;
|
|
9005
9210
|
attemptedProviders.add(activeProvider.name);
|
|
9006
9211
|
streamDisconnectRetries = 0;
|
|
9212
|
+
streamIdleTimeoutRetries = 0;
|
|
9007
9213
|
turnOpts = buildTurnOpts();
|
|
9008
9214
|
streamIter = undefined;
|
|
9009
9215
|
continue;
|
|
9010
9216
|
}
|
|
9011
9217
|
}
|
|
9012
|
-
if (!(err instanceof
|
|
9013
|
-
&& evCount > 0 && isStreamDisconnectRetryable(err, pendingCalls.length, streamEmittedImage) && !opts.signal?.aborted) {
|
|
9218
|
+
if (!(err instanceof StreamIdleTimeoutError) && evCount > 0 && isStreamDisconnectRetryable(err, pendingCalls.length, streamEmittedImage) && !opts.signal?.aborted) {
|
|
9014
9219
|
const retryData = {
|
|
9015
9220
|
provider: activeProvider.name,
|
|
9016
9221
|
model: activeModel,
|
|
@@ -9054,6 +9259,7 @@ export async function streamLLMWithTools(
|
|
|
9054
9259
|
remainingProviders: remaining,
|
|
9055
9260
|
attempted: blockedProviders,
|
|
9056
9261
|
});
|
|
9262
|
+
(circuit ?? await import('./session-runtime/provider-circuit.js')).recordProviderFailure(activeProvider.name, verdict.category, Date.now());
|
|
9057
9263
|
blockedProviders = [...verdict.attempts];
|
|
9058
9264
|
const fallback = verdict.action === 'advance' ? providerByName(verdict.nextProvider) : undefined;
|
|
9059
9265
|
if (!fallback) {
|
|
@@ -9086,24 +9292,36 @@ export async function streamLLMWithTools(
|
|
|
9086
9292
|
attemptedProviders.add(activeProvider.name);
|
|
9087
9293
|
// 재시도 상한은 «공급자마다» — 넘어간 공급자도 스트림 도중 끊김이면 다시 5회까지 건다.
|
|
9088
9294
|
streamDisconnectRetries = 0;
|
|
9295
|
+
streamIdleTimeoutRetries = 0;
|
|
9089
9296
|
turnOpts = buildTurnOpts();
|
|
9090
9297
|
streamIter = undefined;
|
|
9091
9298
|
continue;
|
|
9092
9299
|
}
|
|
9093
9300
|
if (idleTimer) clearTimeout(idleTimer);
|
|
9094
|
-
if (step.
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9301
|
+
if (step.r.done) {
|
|
9302
|
+
(circuit ?? await import('./session-runtime/provider-circuit.js')).recordProviderSuccess(activeProvider.name, Date.now());
|
|
9303
|
+
releaseStreamAttempt();
|
|
9304
|
+
break;
|
|
9098
9305
|
}
|
|
9099
|
-
if (step.r.done) break;
|
|
9100
9306
|
const ev = step.r.value;
|
|
9101
9307
|
evCount++;
|
|
9102
9308
|
lastEvType = ev.type;
|
|
9309
|
+
// One same-provider idle retry is allowed per turn; progress clears the stale partial marker,
|
|
9310
|
+
// but does not reset that retry budget.
|
|
9311
|
+
if (streamIdleTimeoutRetries > 0) streamIdleRetryPartial = '';
|
|
9103
9312
|
if (ev.type === 'text') {
|
|
9104
9313
|
turnText += ev.delta;
|
|
9314
|
+
if (ev.phase) turnTextPhase = ev.phase;
|
|
9315
|
+
if (ev.phase) turnCodexTextPhase = ev.phase === 'final' ? 'final_answer' : 'commentary';
|
|
9105
9316
|
fullText += ev.delta;
|
|
9106
9317
|
emitRetryDisplayStep(retryDisplay.onText(ev.delta, turnText));
|
|
9318
|
+
} else if (ev.type === 'text_phase') {
|
|
9319
|
+
turnTextPhase = ev.phase;
|
|
9320
|
+
turnCodexTextPhase = ev.phase === 'final' ? 'final_answer' : 'commentary';
|
|
9321
|
+
} else if (ev.type === 'turn_end') {
|
|
9322
|
+
turnEnd = ev.endTurn;
|
|
9323
|
+
} else if (ev.type === 'codex_reasoning_item') {
|
|
9324
|
+
(turnCodexReasoningItems ??= []).push(ev.item);
|
|
9107
9325
|
} else if (ev.type === 'reasoning_details') {
|
|
9108
9326
|
turnReasoningDetails = ev.details;
|
|
9109
9327
|
} else if (ev.type === 'tool_call') {
|
|
@@ -9230,6 +9448,26 @@ export async function streamLLMWithTools(
|
|
|
9230
9448
|
}
|
|
9231
9449
|
}
|
|
9232
9450
|
|
|
9451
|
+
// Codex can explicitly mark a response as unfinished even when it emitted
|
|
9452
|
+
// text and no tools. Keep that text in history with its phase, then ask
|
|
9453
|
+
// again. The extra turn is bounded to one past maxTurns.
|
|
9454
|
+
if (pendingCalls.length === 0 && turnEnd === false) {
|
|
9455
|
+
if (turnText || turnCodexReasoningItems?.length) history.push({
|
|
9456
|
+
role: 'assistant', content: turnText,
|
|
9457
|
+
...(turnTextPhase ? { phase: turnTextPhase === 'final' ? 'final_answer' as const : 'commentary' as const } : {}),
|
|
9458
|
+
...(turnCodexReasoningItems?.length ? { codexReasoningItems: turnCodexReasoningItems } : {}),
|
|
9459
|
+
});
|
|
9460
|
+
if (turnText) {
|
|
9461
|
+
clearVisibleAssistantTextForToolRound(handlers, sawToolRound);
|
|
9462
|
+
sawToolRound = true;
|
|
9463
|
+
}
|
|
9464
|
+
codexContinuationNeeded = true;
|
|
9465
|
+
debug.log('llm.router', 'codex.end-turn-false-continue', { turn, phase: turnTextPhase ?? 'unknown', textChars: turnText.length });
|
|
9466
|
+
// The one grace turn is also unfinished. Fall through to the existing
|
|
9467
|
+
// budget notice; never present a phase-marked progress item as final.
|
|
9468
|
+
if (turn >= maxTurns) break;
|
|
9469
|
+
continue;
|
|
9470
|
+
}
|
|
9233
9471
|
// No tool calls + non-empty text = the model gave its final answer.
|
|
9234
9472
|
if (pendingCalls.length === 0 && turnText.length > 0) {
|
|
9235
9473
|
const visibleText = finalizeVisibleAssistantText(fullText, turnText, sawToolRound);
|
|
@@ -9267,7 +9505,7 @@ export async function streamLLMWithTools(
|
|
|
9267
9505
|
// TUI-H1-GOALLOOP-EMPTY-TAIL — 답이 이 스트림 «앞»에 이미 보였어도 같다(opts.terminalPriorAnswerVisible —
|
|
9268
9506
|
// 예: Bash → «끝» → 재주입 → update_goal 만 → 빈 턴). 이 스트림에 답이 없으면 빈 문자열로 끝내고 화면은
|
|
9269
9507
|
// 건드리지 않는다(onText 생략 · emitTurnComplete 는 빈 답을 이력에 안 싣는다). 마감은 호출자(goal loop) 몫.
|
|
9270
|
-
if (terminalSignalDispatched && (lastToolRoundText.trim().length > 0 || opts.terminalPriorAnswerVisible === true)) {
|
|
9508
|
+
if (!completionNeedsFinalTurn && terminalSignalDispatched && (lastToolRoundText.trim().length > 0 || opts.terminalPriorAnswerVisible === true)) {
|
|
9271
9509
|
const answer = lastToolRoundText.trim().length > 0 ? lastToolRoundText : '';
|
|
9272
9510
|
debug.log('goal.loop', 'empty-turn-after-terminal-signal', {
|
|
9273
9511
|
turn, emptyRetries, answerChars: answer.length,
|
|
@@ -9311,7 +9549,10 @@ export async function streamLLMWithTools(
|
|
|
9311
9549
|
clearVisibleAssistantTextForToolRound(handlers, sawToolRound);
|
|
9312
9550
|
}
|
|
9313
9551
|
sawToolRound = true;
|
|
9314
|
-
if (turnText.trim().length > 0)
|
|
9552
|
+
if (turnText.trim().length > 0) {
|
|
9553
|
+
lastToolRoundText = turnText;
|
|
9554
|
+
lastToolRoundTextPhase = turnTextPhase;
|
|
9555
|
+
}
|
|
9315
9556
|
// TUI-GOAL-LOOP-FRICTION(#46) — 이 턴의 호출이 «종결 신호뿐»이면 예산·후속 단계 거부를 걸지 않는다.
|
|
9316
9557
|
const terminalOnlyTurn = terminalToolNames.size > 0
|
|
9317
9558
|
&& pendingCalls.length > 0
|
|
@@ -9360,7 +9601,10 @@ export async function streamLLMWithTools(
|
|
|
9360
9601
|
...(call.providerMeta !== undefined ? { providerMeta: call.providerMeta } : {}),
|
|
9361
9602
|
});
|
|
9362
9603
|
}
|
|
9363
|
-
history.push({ role: 'assistant', content: assistantBlocks
|
|
9604
|
+
history.push({ role: 'assistant', content: assistantBlocks,
|
|
9605
|
+
...(turnTextPhase ? { phase: turnTextPhase === 'final' ? 'final_answer' as const : 'commentary' as const } : {}),
|
|
9606
|
+
...(turnCodexReasoningItems?.length ? { codexReasoningItems: turnCodexReasoningItems } : {}),
|
|
9607
|
+
});
|
|
9364
9608
|
|
|
9365
9609
|
// Final-synthesis window: in the last FINAL_SYNTHESIS_TURNS of the
|
|
9366
9610
|
// budget, refuse to execute tool calls. Each pending call gets a
|
|
@@ -11183,10 +11427,43 @@ export async function streamLLMWithTools(
|
|
|
11183
11427
|
}
|
|
11184
11428
|
// 신호뿐인 턴 · 섞인 턴(정상 디스패치 · 부분 거부 · 통째 거부의 수신 확인) 모두 — 종결 신호가 이 턴에 «받아들여졌다».
|
|
11185
11429
|
if (!hardStopText && pendingCalls.some(isTerminalCall)) terminalSignalDispatched = true;
|
|
11430
|
+
// A goal completion with evidence has already been acknowledged by dispatch. The
|
|
11431
|
+
// across-turn goal loop owns final acceptance (test evidence / rejected calls),
|
|
11432
|
+
// but no further provider request is needed to make that decision. Keep the
|
|
11433
|
+
// tool-result blocks in onTurnComplete so it can inspect the original call.
|
|
11434
|
+
const hasAcceptedCompletion = !hardStopText && opts.terminalCompletionAccepted && pendingCalls.some((call) =>
|
|
11435
|
+
isTerminalCall(call) && resultBlocks.some((block) => block.type === 'tool_result'
|
|
11436
|
+
&& block.tool_use_id === call.id && !block.isError)
|
|
11437
|
+
&& opts.terminalCompletionAccepted!(call.name, call.args));
|
|
11438
|
+
const hasVisibleAnswer = lastToolRoundText.trim().length > 0 || opts.terminalPriorAnswerVisible === true;
|
|
11439
|
+
// A completion tool can follow a commentary/progress segment on any provider.
|
|
11440
|
+
// Its successful ack does not turn that segment into a final user answer.
|
|
11441
|
+
const completionTextIsProgress = lastToolRoundTextPhase === 'commentary'
|
|
11442
|
+
|| (lastToolRoundTextPhase !== 'final' && lastToolRoundText.trim().length <= 240
|
|
11443
|
+
&& /(?:하겠습니다|드리겠습니다|할게요|할 예정입니다|확인하겠|살펴보겠|작성하겠|정리하겠|I(?:'ll| will)\b|\bnext[,]?\s+I\b)/i.test(lastToolRoundText));
|
|
11444
|
+
if (hasAcceptedCompletion && completionTextIsProgress) {
|
|
11445
|
+
completionNeedsFinalTurn = true;
|
|
11446
|
+
history.push({ role: LOOP_SELF_NOTE_ROLE, content: 'The goal completion was accepted. Write your final answer to the user now as plain text. Do not call tools or describe what you will do next.' });
|
|
11447
|
+
debug.log('goal.loop', 'completion-await-final', { turn, progressChars: lastToolRoundText.length, phase: lastToolRoundTextPhase ?? 'unknown' }, { level: 'info' });
|
|
11448
|
+
}
|
|
11449
|
+
if (hasAcceptedCompletion && hasVisibleAnswer && !completionNeedsFinalTurn) {
|
|
11450
|
+
const answer = lastToolRoundText.trim().length > 0 ? lastToolRoundText : '';
|
|
11451
|
+
const visiblePriorAnswer = opts.terminalPriorAnswerVisible === true;
|
|
11452
|
+
debug.log('goal.loop', 'accepted-terminal-completion-finish', {
|
|
11453
|
+
turn, answerChars: answer.length, priorAnswerVisible: visiblePriorAnswer,
|
|
11454
|
+
tools: pendingCalls.map((call) => call.name),
|
|
11455
|
+
}, { level: 'info' });
|
|
11456
|
+
// Every text delta was already streamed above (and fullText accumulates
|
|
11457
|
+
// all rounds). A second onText here would violate the cumulative-full
|
|
11458
|
+
// contract and duplicate text shown before this terminal tool call.
|
|
11459
|
+
const finalAnswer = answer || (opts.terminalPriorAnswerVisible ? fullText.trim() : '');
|
|
11460
|
+
emitTurnComplete(finalAnswer);
|
|
11461
|
+
return finalAnswer;
|
|
11462
|
+
}
|
|
11186
11463
|
// TUI-GOAL-LOOP-FRICTION(#63) — 종결 신호뿐인 턴 ⊕ 같은 턴에 쓴 답 = 이 턴이 최종 답이다.
|
|
11187
11464
|
// 다음 모델 턴을 열면 할 말이 없는 모델이 빈 턴을 되풀이하고 `[NO FINAL SYNTHESIS]` 가 붙는다(10-15 22:36Z 표본).
|
|
11188
11465
|
// 이 턴에 답이 없으면 종전처럼 다음 턴을 연다(앞 라운드 글은 «하겠습니다» 류 서술일 수 있다 — 모델이 답을 쓰게).
|
|
11189
|
-
if (terminalOnlyTurn && !hardStopText && !postToolResultUserNote && turnText.trim().length > 0) {
|
|
11466
|
+
if (terminalOnlyTurn && !completionNeedsFinalTurn && !hardStopText && !postToolResultUserNote && turnText.trim().length > 0) {
|
|
11190
11467
|
const answer = turnText;
|
|
11191
11468
|
debug.log('goal.loop', 'terminal-signal-finish', {
|
|
11192
11469
|
turn, maxTurns, tools: pendingCalls.map((call) => call.name), answerChars: answer.length,
|
|
@@ -11400,6 +11677,7 @@ export async function streamLLMWithTools(
|
|
|
11400
11677
|
let synthesizedText: string | null = null;
|
|
11401
11678
|
const shouldForceSynthesisOnBudget =
|
|
11402
11679
|
loopTermination === 'budget-exhausted'
|
|
11680
|
+
&& !codexContinuationNeeded
|
|
11403
11681
|
&& !forceSynthesisAttempted
|
|
11404
11682
|
&& (modelFamily === 'gemini'
|
|
11405
11683
|
|| applyCodexBehaviorGuard('force-synthesis', effectiveModel, codexGuardCandidate, true));
|
|
@@ -11867,6 +12145,8 @@ function makeCodexProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
11867
12145
|
const responsesUrl = cfgBase
|
|
11868
12146
|
? (cfgBase.endsWith('/responses') ? cfgBase : `${cfgBase.replace(/\/$/, '')}/responses`)
|
|
11869
12147
|
: `${CODEX_API_BASE_URL}/responses`;
|
|
12148
|
+
const endpointSupportsStore = !responsesUrl.includes('chatgpt.com/backend-api');
|
|
12149
|
+
const useStore = endpointSupportsStore && cfg.codexStore !== false;
|
|
11870
12150
|
// Image-pipeline P3 (2026-05-05) — gate the function_call_output
|
|
11871
12151
|
// ContentItem[] wire on the active model. gpt-5 family supports
|
|
11872
12152
|
// image_url in tool results; legacy gpt-4 / non-vision routes
|
|
@@ -11886,6 +12166,7 @@ function makeCodexProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
11886
12166
|
const { instructions, input } = messagesToResponsesInput(messages, {
|
|
11887
12167
|
acceptToolImages: codexAcceptToolImages,
|
|
11888
12168
|
acceptUserMessageImages: codexAcceptUserImages,
|
|
12169
|
+
replayCodexReasoning: !useStore,
|
|
11889
12170
|
onOrphanToolResult: (callId) => {
|
|
11890
12171
|
try { debug.log('llm.codex', 'orphan-tool-output-dropped', { callId }); }
|
|
11891
12172
|
catch { /* observation must not block the request */ }
|
|
@@ -11935,12 +12216,17 @@ function makeCodexProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
11935
12216
|
// wave for ChatGPT regardless of cfg.codexStore — the
|
|
11936
12217
|
// infrastructure stays in place for Azure/API-key paths and
|
|
11937
12218
|
// for any future ChatGPT-side policy change.
|
|
11938
|
-
const endpointSupportsStore = !responsesUrl.includes('chatgpt.com/backend-api');
|
|
11939
|
-
const useStore = endpointSupportsStore && cfg.codexStore !== false;
|
|
11940
12219
|
const delta = useStore ? getIncrementalItems(lastInput, input) : null;
|
|
11941
|
-
|
|
12220
|
+
// A stored continuation already has old reasoning. A full rebase has
|
|
12221
|
+
// no previous_response_id, so it must replay those opaque items.
|
|
12222
|
+
const wireInput = delta ?? (useStore
|
|
12223
|
+
? messagesToResponsesInput(messages, {
|
|
12224
|
+
acceptToolImages: codexAcceptToolImages,
|
|
12225
|
+
acceptUserMessageImages: codexAcceptUserImages,
|
|
12226
|
+
}).input
|
|
12227
|
+
: input);
|
|
11942
12228
|
const wirePrevId = (delta && lastResponseId) ? lastResponseId : undefined;
|
|
11943
|
-
|
|
12229
|
+
let requestBody = {
|
|
11944
12230
|
model: opts.model || model,
|
|
11945
12231
|
instructions,
|
|
11946
12232
|
input: wireInput,
|
|
@@ -11954,8 +12240,77 @@ function makeCodexProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
11954
12240
|
// can disable via llm.codexStore=false.
|
|
11955
12241
|
store: useStore,
|
|
11956
12242
|
...(wirePrevId ? { previousResponseId: wirePrevId } : {}),
|
|
11957
|
-
}
|
|
12243
|
+
};
|
|
12244
|
+
const requestGuard = opts.requestSizeGuard;
|
|
12245
|
+
const promptCache = opts.promptCache !== false;
|
|
12246
|
+
let serializedWireBody: string | undefined;
|
|
12247
|
+
if (requestGuard) {
|
|
12248
|
+
serializedWireBody = serializeCodexResponsesWireBody(requestBody, promptCache);
|
|
12249
|
+
let requestChars = serializedWireBody.length;
|
|
12250
|
+
const initialRequestChars = requestChars;
|
|
12251
|
+
let requestCompacted = false;
|
|
12252
|
+
let requestCompactReason = requestChars > requestGuard.maxChars
|
|
12253
|
+
? 'store-threading-skipped'
|
|
12254
|
+
: 'under-cap';
|
|
12255
|
+
if (requestChars > requestGuard.maxChars && !useStore) {
|
|
12256
|
+
try {
|
|
12257
|
+
const compacted = await requestGuard.compactMessages(messages, {
|
|
12258
|
+
provider: 'openai-codex', requestChars, maxChars: requestGuard.maxChars,
|
|
12259
|
+
});
|
|
12260
|
+
if (compacted) {
|
|
12261
|
+
const compactInput = messagesToResponsesInput(compacted.messages, {
|
|
12262
|
+
acceptToolImages: codexAcceptToolImages,
|
|
12263
|
+
acceptUserMessageImages: codexAcceptUserImages,
|
|
12264
|
+
// Compaction runs only when store threading is off, matching
|
|
12265
|
+
// the original non-threaded wire input policy.
|
|
12266
|
+
replayCodexReasoning: !useStore,
|
|
12267
|
+
});
|
|
12268
|
+
const compactBody = { ...requestBody, instructions: compactInput.instructions, input: compactInput.input };
|
|
12269
|
+
const compactWireBody = serializeCodexResponsesWireBody(compactBody, promptCache);
|
|
12270
|
+
const compactChars = compactWireBody.length;
|
|
12271
|
+
if (compactChars < requestChars) {
|
|
12272
|
+
messages.splice(0, messages.length, ...compacted.messages);
|
|
12273
|
+
requestBody = compactBody;
|
|
12274
|
+
serializedWireBody = compactWireBody;
|
|
12275
|
+
requestChars = compactChars;
|
|
12276
|
+
requestCompacted = true;
|
|
12277
|
+
requestCompactReason = compactChars > requestGuard.maxChars
|
|
12278
|
+
? `compaction-still-over-cap:${compacted.reason}`
|
|
12279
|
+
: compacted.reason;
|
|
12280
|
+
} else {
|
|
12281
|
+
requestCompactReason = 'compaction-no-reduction';
|
|
12282
|
+
}
|
|
12283
|
+
} else {
|
|
12284
|
+
requestCompactReason = 'compaction-no-op';
|
|
12285
|
+
}
|
|
12286
|
+
} catch (error) {
|
|
12287
|
+
requestCompactReason = 'compaction-error';
|
|
12288
|
+
debug.log('llm.request', 'request-size-compact-error', {
|
|
12289
|
+
provider: 'openai-codex',
|
|
12290
|
+
requestChars,
|
|
12291
|
+
maxChars: requestGuard.maxChars,
|
|
12292
|
+
message: error instanceof Error ? error.message : String(error),
|
|
12293
|
+
}, { level: 'warn' });
|
|
12294
|
+
}
|
|
12295
|
+
}
|
|
12296
|
+
requestGuard.onMeasured?.({
|
|
12297
|
+
provider: 'openai-codex', requestChars, maxChars: requestGuard.maxChars,
|
|
12298
|
+
compacted: requestCompacted, reason: requestCompactReason,
|
|
12299
|
+
...(requestCompacted ? { previousChars: initialRequestChars } : {}),
|
|
12300
|
+
});
|
|
12301
|
+
debug.log('llm.request', 'request-size-compact', {
|
|
12302
|
+
provider: 'openai-codex',
|
|
12303
|
+
beforeChars: initialRequestChars,
|
|
12304
|
+
afterChars: requestChars,
|
|
12305
|
+
maxChars: requestGuard.maxChars,
|
|
12306
|
+
compacted: requestCompacted,
|
|
12307
|
+
reason: requestCompactReason,
|
|
12308
|
+
});
|
|
12309
|
+
}
|
|
12310
|
+
yield* streamCodexResponsesEvents(responsesUrl, tokens.accessToken, requestBody, opts.signal, {
|
|
11958
12311
|
accountId,
|
|
12312
|
+
promptCache,
|
|
12313
|
+
...(serializedWireBody ? { serializedWireBody } : {}),
|
|
11959
12314
|
// Capture the new response id from the SSE stream so the
|
|
11960
12315
|
// next call can thread it. If the backend skips the event
|
|
11961
12316
|
// lastResponseId stays undefined and we fall back to full
|