elanous 0.2.37 → 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/{8kITumG9GAZ1LwT9POrAR → HjeK7zONHfR7op1hKXp4k}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{1746.3563617ea64023a3.js → 1060.014f1f01a17aec26.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9151.a2c51e93f9156dae.js → 1281.d81877e35b9068f4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1350.59f40e39e02d91b1.js +1 -0
- 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/{3578.4e9f9948a9a6f2f4.js → 2047.8f23e210995d4548.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/2061-7f2bbc53ae96c88b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7424.c0fe2a595d4232b5.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/{4931.95cc6dbd230774ca.js → 2177.df8547f9d7215c4e.js} +16 -16
- package/apps/pwa/out/_next/static/chunks/2200-9a453b8f99687d49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6680.6a693c28aae4cd19.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/2499.02fbfd18126c10c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6252.240578f10952e091.js → 2522.f2766b76d22c8bdf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1262.a89bb27a5b2f844e.js → 2566.beaffc3a5e1fcd2e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/261.0d471e8aded799f3.js +226 -0
- 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/{2318-450e75d07605b8fe.js → 2774-719820e3f5b2a3eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2812-f016aa0dda149287.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4725-34bed25720cc326b.js → 2829-734fe8bf2eee7347.js} +1 -1
- 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/3330.7443183b7e6fdbdf.js +1 -0
- 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/3746-f80a78f220bf37b5.js +1 -0
- 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/{4337e36d.f42c3b391b3d8f20.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/{58edce7d.f1b0c72acf13b123.js → 409c787b.e48c5bec8ec10456.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/413-24c8284bda08241d.js +1 -0
- 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/{5046.7fd5cbd859299448.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/{2375.bf364c85dbb6f085.js → 4769.9fd582071301f382.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/483.725e4a61be922788.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{de8446d3.31b73eb239fecd7b.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/{4383.18e5c54db3a22c88.js → 5383.bdfa5d886e39a826.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5436.fdf6fa8ae3e9588d.js +64 -0
- 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/{6745-5a63492933959dd9.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/{2283.edd9627b7bdfb546.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/{6819.be5c9c4d67f22922.js → 6749.0744ce6eb08d40e9.js} +16 -16
- 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/6908.06008c67f6380ea9.js +148 -0
- 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/6cc1d1d6.9a98dd4622f1afc6.js +1 -0
- 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/{2002-a43a3f380df873ec.js → 8272-025653884f9645d2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{7867.e8725745ddd1d940.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/8639-92c11d069792429e.js +1 -0
- 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/{4313.76f232c304a15bde.js → 9175.2de5209a5ce6f68a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9184.45afbf44fec87574.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8c58d09b.e8724a299658d86f.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-ba957ff875a026a0.js +1 -0
- 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-3337c6a1328c2674.js → page-4edb8df90f4537ce.js} +1 -1
- 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-1e5da297557d2354.js → page-fca2e59a81744d9e.js} +1 -1
- 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-ac2c1e6169cfce57.js → page-139d722de1dcd6c1.js} +1 -1
- 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-c1c80e345fa9d6f5.js → page-ccde99f07aaf71f7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-80464aced9614390.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{d9815f84.4918f682a45a8502.js → b84cad00.594027ebe0531fe2.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/c696986b.5dc8bb1143af16d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{709a918c.4fd3b4e2a32cb4e3.js → ca3702f8.2913182e73889fa2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/d5d3cefc-373c4eb722ed848b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5f6af561-f90b7a67f4f75d13.js → d8de0de2-dd0f4ac8e5ab1832.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-002b472a66935d31.js +1 -0
- 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/release/recipes.yaml +9 -0
- package/graphs/release/release-loop.yaml +26 -18
- package/graphs/video/explainer-line.yaml +4 -1
- package/package.json +1 -1
- package/scripts/ask-op-inbox-once.ts +17 -0
- package/scripts/brand/check.ts +13 -4
- package/scripts/dead-code/report.ts +169 -0
- package/scripts/gate-0226-accepted-remaining-90.txt +91 -0
- package/scripts/gate-0226-failure-census.ts +39 -0
- package/scripts/intake-collect-telegram-saved-stage.ts +48 -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/provision-export-redactions.ts +15 -0
- package/scripts/public-copy-lint.ts +122 -0
- package/scripts/public-export.ts +77 -2
- package/scripts/ratchets/next-tui-entry-budget.ts +124 -0
- package/scripts/ratchets/train-side-invariants.sh +7 -1
- package/scripts/release-loop/cut-branch.ts +61 -12
- package/scripts/release-loop/export-check-node.ts +21 -3
- package/scripts/release-loop/gate-node.ts +527 -60
- package/scripts/release-loop/gate-partial.ts +82 -3
- package/scripts/release-loop/gate-prewarm-plan.ts +35 -0
- package/scripts/release-loop/gate-radius-live.ts +4 -2
- 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-cap.ts +2 -1
- package/scripts/release-loop/resume-release.ts +317 -13
- package/scripts/release-loop/resume.ts +61 -5
- package/scripts/release-loop/traffic-node.ts +12 -4
- package/scripts/release-loop/traffic-transition.ts +53 -13
- package/scripts/release-loop/version-node.ts +35 -5
- 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/scripts/ux-sim.ts +1 -1
- package/scripts/video-pipeline.ts +2 -2
- package/src/acp/core-turn-bridge.ts +14 -1
- 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/run-context.ts +1 -1
- 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 +78 -7
- 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/review-observation.ts +10 -0
- package/src/agent-substrate/self-review-cli.ts +419 -42
- 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 +156 -0
- package/src/auto-research/research-turn.ts +467 -0
- package/src/autopilot/agent-loop.ts +1 -1
- package/src/autopilot/discovery/doc-lint.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/bots/screen-probe.ts +1 -1
- package/src/budget/llm-cost.ts +44 -5
- package/src/budget/unified-usage.ts +17 -1
- package/src/capture/tui-self-report.ts +24 -2
- package/src/chat/index.ts +34 -7
- package/src/chat/tool-render/dispatch.ts +8 -1
- package/src/cli/agent-cli.ts +43 -8
- package/src/cli/guardian-cli.ts +3 -1
- package/src/cli/intake-cli.ts +70 -13
- package/src/cli/lesson-cli.ts +86 -10
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/pod-cli.ts +17 -2
- package/src/cli/pr-land-overlap-evidence.ts +38 -5
- package/src/cli/pr-land-refusal.ts +1 -1
- package/src/cli/pty-takeover-cli.ts +125 -12
- package/src/cli/release-checklist-read-cli.ts +5 -2
- package/src/cli/release-cli.ts +99 -15
- package/src/cli/repo-cli.ts +2 -1
- package/src/cli/review-carry.ts +77 -0
- package/src/cli/self-update.ts +1 -1
- package/src/cli/tasks-card-show.ts +31 -1
- package/src/cli/tasks-cli.ts +98 -32
- package/src/cli/tasks-read-cli.ts +13 -5
- package/src/context-bus/context-now.ts +86 -2
- package/src/control-plane/ledger.ts +21 -4
- package/src/core-turn/run-core-turn.ts +51 -3
- package/src/core-turn/run-goal-loop.ts +152 -8
- package/src/core-turn/types.ts +12 -0
- package/src/dashboard/chat/acp-chat.ts +2 -2
- package/src/dashboard/classic-sigquit.ts +16 -0
- package/src/dashboard/index.ts +339 -44
- 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/input/terminal-modal-router.ts +8 -159
- package/src/dashboard/side-basic-runtime.ts +61 -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 +22 -8
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -2
- package/src/dashboard/term-slash-runtime.ts +18 -18
- package/src/dashboard/turn-preamble.ts +30 -4
- package/src/domains/guardian-tick.ts +9 -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/git-fs/watcher.ts +27 -22
- package/src/git-fs/worktree.ts +19 -3
- package/src/graph-runner/graph-cli.ts +6 -4
- package/src/graph-runner/graph-grow.ts +37 -9
- package/src/graph-runner/runner.ts +48 -11
- 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 +112 -36
- 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/hq/fence-wrapper.ts +1 -1
- package/src/hq/transfer.ts +1 -1
- package/src/index.ts +60 -16
- package/src/input/external-input-queue.ts +10 -0
- package/src/intake-plane/collect-telegram-saved.ts +90 -6
- package/src/intake-plane/intake-to-tasks.ts +246 -3
- package/src/interactive-terminal-modal.ts +3 -0
- package/src/keybindings.ts +17 -22
- 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/provider-credentials.ts +1 -1
- package/src/llm-tool-schema.ts +20 -0
- package/src/llm.ts +486 -61
- package/src/loops/orchestrator/inbox-once.ts +28 -0
- package/src/loops/orchestrator/inbox.ts +130 -1
- package/src/loops/orchestrator/tick.ts +14 -3
- package/src/maturity/feature-maturity.ts +1 -0
- package/src/nexus/api/channel-ask-op.ts +96 -0
- package/src/nexus/api/discord-trigger-bot.ts +28 -1
- package/src/nexus/api/harness-api.ts +2 -1
- package/src/nexus/api/telegram-trigger-bot.ts +24 -0
- package/src/nexus/api/terminals.ts +28 -6
- package/src/patents/ledger.ts +18 -1
- package/src/preview/terminal.ts +4 -2
- package/src/prompt-cache/anthropic.ts +2 -0
- package/src/prompt-enhance/enhance.ts +5 -0
- package/src/pty/snapshot.py +132 -0
- package/src/pty-shell/pty-control-ipc.ts +29 -2
- package/src/pty-shell/pty-manifest.ts +75 -5
- 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/gate-shards.ts +61 -0
- package/src/release-loop/light-rc.ts +7 -4
- 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 +28 -1
- package/src/repl/index.ts +10 -0
- package/src/research/axis-fanout.ts +133 -0
- package/src/research/edge-decision.ts +197 -0
- 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/output-router.ts +127 -0
- package/src/research/plugin-discovery.ts +242 -0
- package/src/research-bridge/format.ts +16 -1
- package/src/research-bridge/index.ts +1 -0
- package/src/research-bridge/invoke.ts +45 -7
- package/src/research-bridge/types.ts +2 -0
- package/src/self-dev/ask-launch-flow.ts +34 -106
- package/src/self-dev/decompose.ts +45 -9
- package/src/self-dev/dev-cli.ts +2 -0
- package/src/self-dev/dev-pipeline.ts +8 -4
- package/src/self-dev/draft-residue.ts +221 -2
- package/src/self-dev/draft-sweep.ts +29 -16
- 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/orchestrate.ts +1 -0
- package/src/self-dev/run-supervisor.ts +41 -7
- package/src/self-dev/shard-run.ts +260 -3
- package/src/self-implement/comment-only-source.ts +54 -0
- package/src/self-implement/device-first.ts +8 -2
- package/src/self-implement/doctor-visit.ts +100 -57
- package/src/self-implement/gate-artifacts.ts +5 -2
- package/src/self-implement/gate-baseline.ts +119 -13
- package/src/self-implement/gate-cli.ts +466 -93
- package/src/self-implement/gate-failure-signature.ts +44 -0
- package/src/self-implement/gate-receipt-registry.ts +180 -0
- package/src/self-implement/gate-remote.ts +147 -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 +82 -7
- package/src/self-implement/goal-doc/section.ts +22 -0
- package/src/self-implement/goal-supervisor-fill.ts +38 -4
- 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 +301 -9
- package/src/self-implement/l8-merge-queue.ts +198 -32
- package/src/self-implement/off-diff-evidence.ts +147 -0
- package/src/self-implement/orchestrator.ts +137 -16
- package/src/self-implement/pod-inplace-worktree.ts +82 -0
- package/src/self-implement/pod-warm-pool-profile.ts +2 -2
- package/src/self-implement/premise-review.ts +7 -5
- package/src/self-implement/run-ledger.ts +304 -8
- package/src/self-implement/run-stop.ts +12 -0
- package/src/self-implement/seams.ts +39 -13
- package/src/self-implement/self-implement-cli.ts +30 -4
- package/src/session/channel-ask-op-envelope.ts +36 -0
- package/src/session/channel-op-reply-route.ts +200 -0
- package/src/session/chat.ts +92 -15
- package/src/session/index.ts +2 -0
- package/src/session-runtime/index.ts +9 -22
- 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/runner.ts +7 -3
- package/src/skills/tools/dev-harness.ts +2 -2
- package/src/skills/tools/schedule-wakeup.ts +24 -7
- package/src/skills/tools/shell.ts +51 -5
- package/src/status/bar.ts +3 -3
- package/src/steward/directive-audit.ts +354 -0
- package/src/storage/file-lock.ts +17 -4
- package/src/surface/child-process.ts +31 -0
- package/src/surface/tui-stderr-owner.ts +48 -0
- package/src/task-agent/adopt-pr.ts +63 -2
- package/src/task-agent/cover.ts +30 -12
- package/src/task-agent/evidence-command-normalize.ts +42 -0
- package/src/task-agent/export-redactions-provision.ts +43 -0
- package/src/task-agent/judge.ts +56 -0
- package/src/task-agent/parent-host.ts +59 -12
- 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 +68 -9
- package/src/task-agent/repair-worker.ts +37 -1
- package/src/task-agent/task-hand.ts +226 -33
- package/src/task-agent/tier-split.ts +142 -24
- 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 +57 -5
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +11 -8
- package/src/task-orchestrator/surfaces/pod-pool.ts +27 -4
- 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 +310 -79
- package/src/task-orchestrator/surfaces/self-implement.ts +33 -2
- package/src/terminal/session-registry.ts +1 -0
- package/src/terminal/terminal-modal-router.ts +156 -0
- package/src/tool-hints/gate.ts +6 -4
- package/src/tool-hints/signals.ts +33 -1
- package/src/tool-runtime/skill-exec-runtime.ts +95 -5
- package/src/tui/chat/background-job-status.ts +8 -2
- package/src/tui/entry.ts +483 -32
- package/src/tui/inline-choice.ts +188 -0
- package/src/tui/sidetab/attach.ts +304 -0
- package/src/tui/sidetab/list.ts +2 -0
- package/src/tui/sidetab/nl-tool.ts +136 -0
- package/src/tui/slash/resume-command.ts +23 -0
- package/src/tui/slash/resume.ts +3 -23
- package/src/tui/slash/term-next.ts +2 -1
- package/src/tui/slash/term.ts +12 -1
- package/src/tui-client/dashboard-session.ts +7 -1
- package/src/tui-client/local-chat-turn.ts +29 -8
- package/src/user-config.ts +42 -3
- 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/fake-llm.ts +11 -5
- 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 +61 -14
- 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/1041-5841aae848fb6403.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1087.3177e54f672dc526.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1105.efe1e13503ac7a33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1224.2ceca6c180d5130b.js +0 -62
- package/apps/pwa/out/_next/static/chunks/1417-1768233ac92f8a5d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1612.81bbc19af06af16c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1766.728d42053070bb2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1773.d38e945481e04125.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1974-c12f9600da3d3c26.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1ed5e8af.cf424815c7c0efad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2061.7232dc9dc058417f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/210.90b2cbd64926cf34.js +0 -32
- package/apps/pwa/out/_next/static/chunks/244-a810d282a20f1783.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2479-fe7e188bd9402d14.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2514.03b60f266531a015.js +0 -148
- package/apps/pwa/out/_next/static/chunks/2526-a657538869888604.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2533-6f0341ff075809e9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2676.e7994c695ef0f30d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2734.3ffdf54254fb6f99.js +0 -27
- package/apps/pwa/out/_next/static/chunks/2770-23252bf3a37880b9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2969.66b8b545139d1544.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3128.a9210d08800ea6a8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3199.6a1a9b0e6cd01dc6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3212.12179fd3eee8cef1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3760-2909ddb9279281cd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3825.1921b5901bf33dce.js +0 -36
- package/apps/pwa/out/_next/static/chunks/3994-63eb884ed0547011.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4036.d54e55e1ebf5acdc.js +0 -90
- package/apps/pwa/out/_next/static/chunks/4115.5b438b99f0ae729f.js +0 -226
- package/apps/pwa/out/_next/static/chunks/4269.d8f9f34bb0fc6c43.js +0 -287
- package/apps/pwa/out/_next/static/chunks/431-4eed5bd2c5fe1719.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4324.c99ba3e83eb1b691.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4599-96eff3f2a9c242c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4825-a9d9d4e9f5892309.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4833-7934c592c5569f00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4879-68518f547a207aff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4896.f9b70285363b27b2.js +0 -24
- package/apps/pwa/out/_next/static/chunks/4937-28d437999b77c9dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/49aa54ab.80f39398e0ed0f30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5056.482687319b82638e.js +0 -104
- package/apps/pwa/out/_next/static/chunks/506.16b83d56a437a9ee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5260-20593b0a25d0afbc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5404.cc4e9fec26fd5925.js +0 -1
- package/apps/pwa/out/_next/static/chunks/576.485e83e3f3dec19a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5832-a6be14e663f65726.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5854-56648a9fe646b9a0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5925.3b1f8b135710249b.js +0 -93
- package/apps/pwa/out/_next/static/chunks/5952.294fc574a8625184.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6168.17749aa3905fa073.js +0 -74
- package/apps/pwa/out/_next/static/chunks/6416.5d50b8ec9986ca98.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6758.e7fbf532953c0783.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6795.0cb8a59730d99703.js +0 -149
- package/apps/pwa/out/_next/static/chunks/6877-84d47b7e85d0c41e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6971-fb5f9dc0a2cb5d2d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/717.522b08685979b814.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7191.e41eb8f455c7f089.js +0 -41
- package/apps/pwa/out/_next/static/chunks/7233.8e744b7513119409.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7238-97c2226f80504bd8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7285.307963afcf7e7660.js +0 -24
- package/apps/pwa/out/_next/static/chunks/7299-fbe4b8c47a87614a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7314.df0d95930b0c3f50.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7406.c0589fdf2ee66629.js +0 -1
- package/apps/pwa/out/_next/static/chunks/752-90e3e7daad3d8e39.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7524-bcd3d9928c6842d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7549.9a4de3bf231cfc52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/757-4fbaf50942b8c424.js +0 -1
- package/apps/pwa/out/_next/static/chunks/765.76ae970ceb597b5b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7893-e444a1b0809cd1e4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7956-33748cabb3a05562.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7c5ed21f-f286708e57cf88f7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8030-aa66b478b53dbfca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8051.c88c07dacbbc5f21.js +0 -8
- package/apps/pwa/out/_next/static/chunks/8080-40d781e7704d3671.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8149.80e402d4345e8dae.js +0 -77
- package/apps/pwa/out/_next/static/chunks/8205.50a5268f4e12ba0b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8231.a128feaa6f8b6079.js +0 -1
- package/apps/pwa/out/_next/static/chunks/85.4ddb1dda2ea3ffa2.js +0 -286
- package/apps/pwa/out/_next/static/chunks/8537.26517a09e8247beb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8595-e9b7081ab773a61f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8821-30cc65a61a60951f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8905.b3385aadb7b133e6.js +0 -79
- package/apps/pwa/out/_next/static/chunks/8983.246bb3a1ac38f50f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9072.18342f5941a1f3ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9123.9df04866b2d6e00f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9175-7d383df15a82e2be.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9181-bf89c07ce5b8f599.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-429bbc4504b45f71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9207.625edf45d656151c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9378.d2575c6ffd6dd756.js +0 -94
- package/apps/pwa/out/_next/static/chunks/957.db5b5c4d32a35240.js +0 -1
- package/apps/pwa/out/_next/static/chunks/958.53a8dcf4729e6997.js +0 -64
- package/apps/pwa/out/_next/static/chunks/9647.8f0cd0898c592a29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9665-26abb02665704c2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9703.e7d81b6faef1050a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9882-7a9164b3c2dacbe5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9998.b74e033efadecd10.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c604fb980a634d88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-ec2d8a4979ca9075.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cb6add08ad3c7660.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-e2eaa321ec223fe6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-5b8a09c475b5f844.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-91a77daedfbac191.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-f37fc5e974bda39b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-91429a0b78415a94.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-b95798b58263b910.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-763d53e175e17aa1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-d55023204055b12f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-89d2140d78abc810.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-82dc069abfe27f55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-25d9eee7beb552c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-770b4594c713ee97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c604fb980a634d88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ba8e0dcae4f83985.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-5c112c6d7c33656e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-09788e1aa9a87db6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-89acd5d68c0bc560.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-5c13e2c76371d797.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-653a9f18642825c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-fe986fe79b107546.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-91ea9f5869a40943.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-7824e21b999962e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-53d00a60cc75a922.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-88a1edbff62eaf1d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e931248b3f9574b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-443364c9e4a23b31.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-b9af2ac1c4737ce8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-25ab9c614c14129b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-dbcdcfac0a395a8a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-bf1de6645089ec58.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c4201761a5e839c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-c304f469ea5d70e4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8e5a238cf5e50c9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c604fb980a634d88.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-32b526069ee50b3c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-fb9e639c107f5f72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-84220c776608cedc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-e475618cbfd5ca2b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-fccd3020af2f8806.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-9c0d7198ff7b5a91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-d54b1ec9b9c6430d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8c4bef1791d732ca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-46fcc0b0bbc6fbfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-7dfda00afd172f5b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/f21fd540.63ac75328926ed30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-77fdcc873519a6cd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-d0d620d2ce235713.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-e0ef79c79337ba90.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-84b1bc71e3f9ce6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-2acb61f1363128cb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-462ff5727ceb7824.js +0 -1
- package/scripts/migrate-monad-to-elanous.ts +0 -195
- package/scripts/rebrand-elanous.ts +0 -242
- /package/apps/pwa/out/_next/static/{8kITumG9GAZ1LwT9POrAR → HjeK7zONHfR7op1hKXp4k}/_ssgManifest.js +0 -0
package/src/llm.ts
CHANGED
|
@@ -62,7 +62,7 @@ import { BUILTIN_CATALOG, reasoningEffortCeiling as reasoningEffortCeilingOf } f
|
|
|
62
62
|
import { inferProviderFromModel as registryInferProviderFromModel } from './registry/normalize.js';
|
|
63
63
|
import { closestMatches } from './tool-name-suggest.js';
|
|
64
64
|
import { createProviderToolNameMap } from './llm-tool-name.js';
|
|
65
|
-
import { isOpenRouterGrokModel, sanitizeToolSchemaForGrok } from './llm-tool-schema.js';
|
|
65
|
+
import { assertNoTopLevelToolSchemaCombinators, isOpenRouterGrokModel, sanitizeToolSchemaForGrok } from './llm-tool-schema.js';
|
|
66
66
|
import { undoTurnRuntime } from './tool-runtime/undo-turn-runtime.js';
|
|
67
67
|
import { listSnapshots } from './undo-turn/index.js';
|
|
68
68
|
// Zero-dep spec module (no tool-runtime registry) — safe for this hot path.
|
|
@@ -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;
|
|
@@ -403,6 +425,9 @@ export type ToolChoice = 'auto' | 'required' | 'none' | { name: string };
|
|
|
403
425
|
|
|
404
426
|
export interface LLMOpts {
|
|
405
427
|
model?: string;
|
|
428
|
+
/** Explicit research surface verdict from the turn router. Relaxes early
|
|
429
|
+
* exploration guards while retaining a finite tool-loop hard stop. */
|
|
430
|
+
researchTurn?: boolean;
|
|
406
431
|
/** Reports the provider and model actually attempted, including fallbacks. */
|
|
407
432
|
onResolvedProvider?(provider: string, model: string): void;
|
|
408
433
|
temperature?: number;
|
|
@@ -412,6 +437,24 @@ export interface LLMOpts {
|
|
|
412
437
|
streamIdleTimeoutMs?: number;
|
|
413
438
|
/** Optional per-request usage telemetry from the provider stream. */
|
|
414
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
|
+
};
|
|
415
458
|
/** Optional model role attached to this request's usage observation. */
|
|
416
459
|
usageRole?: ModelRole;
|
|
417
460
|
/** Optional per-call metering phase; absent calls keep the existing ledger shape. */
|
|
@@ -473,6 +516,9 @@ export interface LLMOpts {
|
|
|
473
516
|
* 그러면 종결 신호 뒤 빈 턴은 이 스트림에 쓴 답이 없어도 재촉·`[NO FINAL SYNTHESIS]` 없이 빈 답으로 끝낸다.
|
|
474
517
|
* 비우면(기본) 종전대로 — 답이 «어디에도» 없을 때의 경고는 그대로 보인다. */
|
|
475
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;
|
|
476
522
|
/** Prompt-caching toggle. Honored by Anthropic (attaches
|
|
477
523
|
* cache_control markers on system + tools + 2nd-to-last history
|
|
478
524
|
* message) and OpenAI (passes stream_options.include_usage so
|
|
@@ -1625,7 +1671,8 @@ type ResponsesContentBlock =
|
|
|
1625
1671
|
* codex answer began with "tool_result 가 없다" because, from the
|
|
1626
1672
|
* model's perspective, no tool result ever arrived. */
|
|
1627
1673
|
type ResponsesInputItem =
|
|
1628
|
-
| { 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 }
|
|
1629
1676
|
| { type: 'function_call'; name: string; arguments: string; call_id: string }
|
|
1630
1677
|
// Image-pipeline P3 (2026-05-05) — `output` accepts string OR a
|
|
1631
1678
|
// ContentItem[] mirroring the user-message content block shape.
|
|
@@ -1652,6 +1699,8 @@ type ResponsesInputItem =
|
|
|
1652
1699
|
* Codex variants — current gpt-5 family all true per allowlist). */
|
|
1653
1700
|
export interface MessagesToResponsesInputOpts {
|
|
1654
1701
|
acceptToolImages?: boolean;
|
|
1702
|
+
/** Server-stored continuation already contains prior reasoning items. */
|
|
1703
|
+
replayCodexReasoning?: boolean;
|
|
1655
1704
|
acceptUserMessageImages?: boolean;
|
|
1656
1705
|
onOrphanToolResult?: (callId: string) => void;
|
|
1657
1706
|
}
|
|
@@ -1824,6 +1873,9 @@ export function messagesToResponsesInput(
|
|
|
1824
1873
|
continue;
|
|
1825
1874
|
}
|
|
1826
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);
|
|
1827
1879
|
// Assemble the final content block list: text first (matches
|
|
1828
1880
|
// how users usually write prompts — "describe this image" then
|
|
1829
1881
|
// attachment), images second. Responses API is order-sensitive
|
|
@@ -1841,7 +1893,7 @@ export function messagesToResponsesInput(
|
|
|
1841
1893
|
// representation — emitting an empty Message wrapper would just
|
|
1842
1894
|
// add a stray empty-text block to the conversation history.
|
|
1843
1895
|
if (content.length > 0) {
|
|
1844
|
-
input.push({ role: m.role, content });
|
|
1896
|
+
input.push({ role: m.role, content, ...(m.role === 'assistant' && m.phase ? { phase: m.phase } : {}) });
|
|
1845
1897
|
}
|
|
1846
1898
|
input.push(...trailingItems);
|
|
1847
1899
|
}
|
|
@@ -2172,6 +2224,41 @@ function mapReasoningLevelToGeminiThinking(
|
|
|
2172
2224
|
/** Stream against /responses (Codex, OpenAI Responses API). Exported
|
|
2173
2225
|
* so tests can exercise header/body shape without spinning up the
|
|
2174
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
|
+
|
|
2175
2262
|
export async function* streamCodexResponsesEvents(
|
|
2176
2263
|
url: string,
|
|
2177
2264
|
bearer: string,
|
|
@@ -2218,6 +2305,9 @@ export async function* streamCodexResponsesEvents(
|
|
|
2218
2305
|
/** Opt-out hook (tests). When false, skips the
|
|
2219
2306
|
* `prompt_cache_key` body field; production always passes true. */
|
|
2220
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;
|
|
2221
2311
|
/** Callback fired when the SSE stream emits `response.created`
|
|
2222
2312
|
* carrying the new response's id. Used by makeCodexProvider to
|
|
2223
2313
|
* capture the id and thread `previousResponseId` on the next
|
|
@@ -2271,32 +2361,16 @@ export async function* streamCodexResponsesEvents(
|
|
|
2271
2361
|
// value codex_cli_rs ships) so the backend
|
|
2272
2362
|
// applies the same tool/SSE conventions
|
|
2273
2363
|
const promptCache = extra.promptCache !== false;
|
|
2274
|
-
|
|
2275
|
-
//
|
|
2276
|
-
const wireBody
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
// to send only the delta input items. Default still false so any
|
|
2282
|
-
// caller that doesn't opt in (tests building bodies directly)
|
|
2283
|
-
// 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,
|
|
2284
2371
|
store: body.store === true,
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
...(cacheKey ? { prompt_cache_key: cacheKey } : {}),
|
|
2288
|
-
// Reasoning opt-in (gpt-5 family). When the caller sets
|
|
2289
|
-
// body.reasoning we mirror it onto the wire AND append the
|
|
2290
|
-
// include directive that lets multi-turn requests thread the
|
|
2291
|
-
// model's encrypted reasoning context. Omit both when absent
|
|
2292
|
-
// so non-reasoning models / opt-out users see the legacy
|
|
2293
|
-
// wire shape unchanged.
|
|
2294
|
-
...(body.reasoning ? {
|
|
2295
|
-
reasoning: body.reasoning,
|
|
2296
|
-
include: ['reasoning.encrypted_content'],
|
|
2297
|
-
} : {}),
|
|
2298
|
-
};
|
|
2299
|
-
const wireJson = JSON.stringify(wireBody);
|
|
2372
|
+
previousResponseId: body.previousResponseId ? `${body.previousResponseId.slice(0, 12)}…` : null,
|
|
2373
|
+
});
|
|
2300
2374
|
const response = await fetchApiWithRetry(
|
|
2301
2375
|
url,
|
|
2302
2376
|
{
|
|
@@ -2325,6 +2399,10 @@ export async function* streamCodexResponsesEvents(
|
|
|
2325
2399
|
debug.log('llm.response.status', `codex ${response.status}`, {
|
|
2326
2400
|
url, status: response.status, elapsedMs: Date.now() - startedAt,
|
|
2327
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;
|
|
2328
2406
|
try {
|
|
2329
2407
|
for await (const line of sseLineStream(response.body!)) {
|
|
2330
2408
|
if (!line.startsWith('data: ')) continue;
|
|
@@ -2344,15 +2422,32 @@ export async function* streamCodexResponsesEvents(
|
|
|
2344
2422
|
extra.onResponseCreated(id);
|
|
2345
2423
|
}
|
|
2346
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
|
+
}
|
|
2347
2435
|
// Text tokens — both `response.output_text.delta` (new naming) and
|
|
2348
2436
|
// raw `output_text.delta` (older streams).
|
|
2349
2437
|
if (type.endsWith('output_text.delta')) {
|
|
2350
2438
|
const delta = parsed.delta || '';
|
|
2351
|
-
if (delta) yield { type: 'text', delta };
|
|
2439
|
+
if (delta) yield { type: 'text', delta, ...(messagePhase ? { phase: messagePhase } : {}) };
|
|
2352
2440
|
}
|
|
2353
2441
|
// Tool calls come in as `response.output_item.done` with item.type = 'function_call'.
|
|
2354
2442
|
if (type === 'response.output_item.done') {
|
|
2355
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
|
+
}
|
|
2356
2451
|
if (item && item.type === 'function_call') {
|
|
2357
2452
|
let args: Record<string, unknown> = {};
|
|
2358
2453
|
try { args = item.arguments ? JSON.parse(item.arguments) : {}; } catch { /* empty */ }
|
|
@@ -2407,6 +2502,9 @@ export async function* streamCodexResponsesEvents(
|
|
|
2407
2502
|
// hit rate for codex regardless. See store=true wave (next+1)
|
|
2408
2503
|
// for the volume-side counterpart.
|
|
2409
2504
|
if (type === 'response.completed') {
|
|
2505
|
+
if (typeof parsed.response?.end_turn === 'boolean') {
|
|
2506
|
+
yield { type: 'turn_end', endTurn: parsed.response.end_turn };
|
|
2507
|
+
}
|
|
2410
2508
|
const u = parsed.response?.usage;
|
|
2411
2509
|
if (u && typeof u === 'object') {
|
|
2412
2510
|
const cached = u.input_tokens_details?.cached_tokens
|
|
@@ -4471,6 +4569,14 @@ function explainAndLogFallbackCandidates(
|
|
|
4471
4569
|
|
|
4472
4570
|
/** 스트림 중 끊김 재시도 상한 — codex `DEFAULT_STREAM_MAX_RETRIES`(5) 와 같은 값. */
|
|
4473
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
|
+
}
|
|
4579
|
+
const STREAM_IDLE_TIMEOUT_MAX_RETRIES = 1;
|
|
4474
4580
|
let streamDisconnectRetryDelayMs: (attempt: number) => number = backoffMs;
|
|
4475
4581
|
|
|
4476
4582
|
/** @internal 시험 seam — 재시도 대기(기본 `backoffMs`)를 바꾼다. `undefined` 면 원복. */
|
|
@@ -4795,6 +4901,20 @@ type ProviderTextResult =
|
|
|
4795
4901
|
| { ok: true; full: string; usage: ObservedUsage | 'unmeasured' }
|
|
4796
4902
|
| { ok: false; full: string; error: unknown };
|
|
4797
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
|
+
|
|
4798
4918
|
function accumulateUsage(usage: ObservedUsage | undefined, received: LLMUsage): ObservedUsage {
|
|
4799
4919
|
const total = { ...usage };
|
|
4800
4920
|
for (const field of ['inputTokens', 'outputTokens', 'cacheReadInputTokens', 'cacheCreationInputTokens', 'reportedCostUsd'] as const) {
|
|
@@ -4832,10 +4952,8 @@ async function consumeProviderText(
|
|
|
4832
4952
|
// Preserve the provider or callback error that caused this close.
|
|
4833
4953
|
}
|
|
4834
4954
|
};
|
|
4835
|
-
const
|
|
4836
|
-
|
|
4837
|
-
? STREAM_IDLE_TIMEOUT_MS_REASONING : STREAM_IDLE_TIMEOUT_MS
|
|
4838
|
-
);
|
|
4955
|
+
const idleTimeout = resolveStreamIdleTimeout(opts, provider, opts.model ?? provider.defaultModel);
|
|
4956
|
+
const idleMs = idleTimeout.ms;
|
|
4839
4957
|
|
|
4840
4958
|
while (true) {
|
|
4841
4959
|
let idleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
@@ -4856,10 +4974,9 @@ async function consumeProviderText(
|
|
|
4856
4974
|
if (step.idle) {
|
|
4857
4975
|
debug.log('llm', 'stream-idle-timeout', {
|
|
4858
4976
|
provider: provider.name, model: opts.model ?? provider.defaultModel,
|
|
4859
|
-
idleMs, receivedChars: full.length, site: 'stream-llm',
|
|
4977
|
+
idleMs, idleMsSource: idleTimeout.source, receivedChars: full.length, site: 'stream-llm',
|
|
4860
4978
|
});
|
|
4861
|
-
const error = new
|
|
4862
|
-
error.name = 'StreamIdleTimeoutError';
|
|
4979
|
+
const error = new StreamIdleTimeoutError(idleMs);
|
|
4863
4980
|
// An async generator can leave return() pending behind a stalled next().
|
|
4864
4981
|
void closeIterator();
|
|
4865
4982
|
return { ok: false, full, error };
|
|
@@ -4904,6 +5021,7 @@ export async function streamLLM(
|
|
|
4904
5021
|
);
|
|
4905
5022
|
activeProvider = finalized.provider;
|
|
4906
5023
|
const activeModel = finalized.model;
|
|
5024
|
+
if (getModelFamily(activeModel) === 'claude') assertNoTopLevelToolSchemaCombinators(opts.tools);
|
|
4907
5025
|
opts.onResolvedProvider?.(activeProvider.name, activeModel);
|
|
4908
5026
|
debug.log('llm.router', 'streamLLM', {
|
|
4909
5027
|
provider: activeProvider.name,
|
|
@@ -4940,6 +5058,7 @@ export async function streamLLM(
|
|
|
4940
5058
|
textChars: full.length,
|
|
4941
5059
|
usage: consumed.usage,
|
|
4942
5060
|
});
|
|
5061
|
+
(await import('./session-runtime/provider-circuit.js')).recordProviderSuccess(activeProvider.name, Date.now());
|
|
4943
5062
|
return full;
|
|
4944
5063
|
}
|
|
4945
5064
|
|
|
@@ -4957,6 +5076,7 @@ export async function streamLLM(
|
|
|
4957
5076
|
status: err.status,
|
|
4958
5077
|
kind: err.kind,
|
|
4959
5078
|
}, { level: 'warn' });
|
|
5079
|
+
(await import('./session-runtime/provider-circuit.js')).recordProviderFailure(activeProvider.name, 'overload-failover', Date.now());
|
|
4960
5080
|
activeProvider = switched;
|
|
4961
5081
|
modelOverride = undefined;
|
|
4962
5082
|
attemptedProviders.add(activeProvider.name);
|
|
@@ -4993,6 +5113,7 @@ export async function streamLLM(
|
|
|
4993
5113
|
tools: opts.tools?.map((tool) => tool.name) ?? [],
|
|
4994
5114
|
...(opts.model ? { modelOverrideDropped: opts.model } : {}),
|
|
4995
5115
|
}, { level: 'warn' });
|
|
5116
|
+
(await import('./session-runtime/provider-circuit.js')).recordProviderFailure(activeProvider.name, verdict.category, Date.now());
|
|
4996
5117
|
activeProvider = fallback;
|
|
4997
5118
|
modelOverride = undefined;
|
|
4998
5119
|
attemptedProviders.add(activeProvider.name);
|
|
@@ -5118,6 +5239,8 @@ export function resolveDefaultProvider(model?: string): LLMProvider {
|
|
|
5118
5239
|
export interface StreamWithToolsHandlers {
|
|
5119
5240
|
/** Streaming text delta — invoked for every text chunk across all turns. */
|
|
5120
5241
|
onText(delta: string, fullAcrossTurns: string): void;
|
|
5242
|
+
/** Transient user-visible status emitted by stream recovery (not model text). */
|
|
5243
|
+
onStatus?(line: string): void;
|
|
5121
5244
|
/** Dispatch a tool call. Returning undefined/null throws in the loop so
|
|
5122
5245
|
* callers should always return a JSON-serializable value (can be an
|
|
5123
5246
|
* error object — the model will see it as a tool_result either way).
|
|
@@ -7382,6 +7505,16 @@ function resultText(result: unknown): string {
|
|
|
7382
7505
|
return '';
|
|
7383
7506
|
}
|
|
7384
7507
|
|
|
7508
|
+
/** skill_exec returns structured host metadata, but its model-facing tool result is the answer body. */
|
|
7509
|
+
function toolResultContentForCall(toolName: string, result: unknown): string {
|
|
7510
|
+
if (toolName === 'skill_exec' && result && typeof result === 'object'
|
|
7511
|
+
&& typeof (result as { output?: unknown }).output === 'string') {
|
|
7512
|
+
if ((result as { ok?: unknown }).ok === false) return JSON.stringify(result);
|
|
7513
|
+
return (result as { output: string }).output;
|
|
7514
|
+
}
|
|
7515
|
+
return typeof result === 'string' ? result : JSON.stringify(result);
|
|
7516
|
+
}
|
|
7517
|
+
|
|
7385
7518
|
function detectExecutionFailure(result: unknown): boolean {
|
|
7386
7519
|
if (!result || typeof result !== 'object') return false;
|
|
7387
7520
|
const typed = result as Record<string, unknown>;
|
|
@@ -8319,12 +8452,42 @@ export async function streamLLMWithTools(
|
|
|
8319
8452
|
skipProviders?: readonly string[];
|
|
8320
8453
|
} = {},
|
|
8321
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;
|
|
8322
8460
|
const provider = opts.provider ?? opts.initialProvider ?? resolveDefaultProvider(opts.model);
|
|
8323
8461
|
const initial = finalizeStreamingProviderModel(provider, opts.model ?? provider.defaultModel);
|
|
8324
8462
|
let activeProvider = initial.provider;
|
|
8325
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
|
+
}
|
|
8326
8485
|
opts.onResolvedProvider?.(activeProvider.name, activeModel);
|
|
8327
|
-
const attemptedProviders = new Set<string>([
|
|
8486
|
+
const attemptedProviders = new Set<string>([
|
|
8487
|
+
activeProvider.name,
|
|
8488
|
+
...(circuitBlockedInitialProvider ? [circuitBlockedInitialProvider] : []),
|
|
8489
|
+
...(opts.skipProviders ?? []),
|
|
8490
|
+
]);
|
|
8328
8491
|
let blockedProviders: ProviderFallbackAttempt[] = [];
|
|
8329
8492
|
const effectiveModel = activeModel;
|
|
8330
8493
|
const modelFamily = getModelFamily(effectiveModel);
|
|
@@ -8344,7 +8507,7 @@ export async function streamLLMWithTools(
|
|
|
8344
8507
|
tools: opts.tools?.map(t => t.name),
|
|
8345
8508
|
toolsAvailable: !!provider.streamChat && (opts.tools?.length ?? 0) > 0,
|
|
8346
8509
|
}, { level: 'info' });
|
|
8347
|
-
if (!provider.streamChat ||
|
|
8510
|
+
if (!provider.streamChat || ((opts.tools?.length ?? 0) === 0 && provider.name !== 'openai-codex')) {
|
|
8348
8511
|
// No tool support or no tools requested — delegate to plain streamLLM.
|
|
8349
8512
|
debug.log('llm.router', 'streamLLMWithTools.fallback', {
|
|
8350
8513
|
reason: !provider.streamChat ? 'provider-no-streamChat' : 'no-tools',
|
|
@@ -8409,7 +8572,9 @@ export async function streamLLMWithTools(
|
|
|
8409
8572
|
const familyDefaultMaxTurns = resolved === 0 ? Number.POSITIVE_INFINITY : (resolved || baselineForFamily);
|
|
8410
8573
|
// `let` (not const) — the conditional budget-grant hook (opts.budgetGrant)
|
|
8411
8574
|
// may extend this mid-loop when a designated multi-round tool is called.
|
|
8412
|
-
let maxTurns = opts.maxTurns ??
|
|
8575
|
+
let maxTurns = opts.maxTurns ?? (opts.researchTurn
|
|
8576
|
+
? Math.min(32, Math.max(16, familyDefaultMaxTurns))
|
|
8577
|
+
: familyDefaultMaxTurns);
|
|
8413
8578
|
const budgetGrant = opts.budgetGrant;
|
|
8414
8579
|
// ⭐ Hydration-capable tool list (F2 gap④ · 2026-07-26). The provider tool
|
|
8415
8580
|
// array used to be `opts.tools`, FIXED for the whole loop. That made
|
|
@@ -8428,7 +8593,9 @@ export async function streamLLMWithTools(
|
|
|
8428
8593
|
} catch { /* config unreadable — default 비-면제·hot-path 는 config 손상에 안 막힌다 */ }
|
|
8429
8594
|
const inspectBudgetThreshold = getInspectBudgetThreshold(history, modelFamily, codexInspectExemptFlag);
|
|
8430
8595
|
const inspectFollowupMode = getInspectFollowupMode(history);
|
|
8431
|
-
const explorationThresholdForTurn =
|
|
8596
|
+
const explorationThresholdForTurn = opts.researchTurn
|
|
8597
|
+
? Number.POSITIVE_INFINITY
|
|
8598
|
+
: getExplorationThreshold(history, maxTurns, modelFamily);
|
|
8432
8599
|
const maxTurnsUnbounded = maxTurns === Infinity;
|
|
8433
8600
|
const familyDefaultMaxTurnsUnbounded = familyDefaultMaxTurns === Infinity;
|
|
8434
8601
|
const explorationUnbounded = !Number.isFinite(explorationThresholdForTurn);
|
|
@@ -8443,6 +8610,7 @@ export async function streamLLMWithTools(
|
|
|
8443
8610
|
inspectBudgetThreshold,
|
|
8444
8611
|
inspectFollowupMode,
|
|
8445
8612
|
explorationThresholdForTurn,
|
|
8613
|
+
researchTurn: opts.researchTurn === true,
|
|
8446
8614
|
// ★ Infinity 는 JSON 직렬화 시 null 이 되므로 boolean 으로도 남긴다(관측·제1원칙).
|
|
8447
8615
|
// true = 프론티어 면제로 read/search 스트릭 컷 없음(대표 방침 2026-07-17).
|
|
8448
8616
|
explorationUnbounded,
|
|
@@ -8500,6 +8668,8 @@ export async function streamLLMWithTools(
|
|
|
8500
8668
|
}
|
|
8501
8669
|
// OR-DEEPSEEK-TUNE — 마지막 턴의 «도구 없는» 추론(deepseek/* 만 채워진다). 매 턴 시작에 비운다.
|
|
8502
8670
|
let turnReasoningDetails: Array<Record<string, unknown>> | undefined;
|
|
8671
|
+
let turnCodexReasoningItems: LLMMessage['codexReasoningItems'];
|
|
8672
|
+
let turnCodexTextPhase: LLMMessage['phase'];
|
|
8503
8673
|
const emitTurnComplete = (finalAssistantText?: string): void => {
|
|
8504
8674
|
if (finalAssistantText && finalAssistantText.length > 0) {
|
|
8505
8675
|
history.push({
|
|
@@ -8508,18 +8678,23 @@ export async function streamLLMWithTools(
|
|
|
8508
8678
|
type: 'text', text: finalAssistantText,
|
|
8509
8679
|
...(turnReasoningDetails ? { providerMeta: { reasoningDetails: turnReasoningDetails } } : {}),
|
|
8510
8680
|
}],
|
|
8681
|
+
...(turnCodexReasoningItems?.length ? { codexReasoningItems: turnCodexReasoningItems } : {}),
|
|
8682
|
+
...(turnCodexTextPhase ? { phase: turnCodexTextPhase } : {}),
|
|
8511
8683
|
});
|
|
8512
8684
|
}
|
|
8513
8685
|
handlers.onTurnComplete?.(history.slice(initialHistoryLen));
|
|
8514
8686
|
};
|
|
8515
8687
|
let fullText = '';
|
|
8516
8688
|
let sawToolRound = false;
|
|
8689
|
+
let codexContinuationNeeded = false;
|
|
8517
8690
|
// TUI-GOAL-LOOP-FRICTION — 종결 신호 도구(LLMOpts.terminalToolNames). 비면 아래 분기는 전부 꺼진다.
|
|
8518
8691
|
const terminalToolNames: ReadonlySet<string> = new Set(opts.terminalToolNames ?? []);
|
|
8519
8692
|
/** 이 스트림에서 종결 신호를 한 번이라도 디스패치했나. */
|
|
8520
8693
|
let terminalSignalDispatched = false;
|
|
8694
|
+
let completionNeedsFinalTurn = false;
|
|
8521
8695
|
/** 도구 라운드에 실린 마지막 «비지 않은» 답 텍스트(종결 신호 턴 마감·빈 턴 포기에서 쓴다). */
|
|
8522
8696
|
let lastToolRoundText = '';
|
|
8697
|
+
let lastToolRoundTextPhase: 'commentary' | 'final' | undefined;
|
|
8523
8698
|
const agentBatchTickIntervalMs = opts.agentBatchTickIntervalMs ?? BATCH_TICK_INTERVAL_MS;
|
|
8524
8699
|
|
|
8525
8700
|
// Empty-turn guard: smaller models (gpt-5.4-mini, haiku) sometimes
|
|
@@ -8693,7 +8868,7 @@ export async function streamLLMWithTools(
|
|
|
8693
8868
|
let loopTermination: 'budget-exhausted' | 'aborted' = 'budget-exhausted';
|
|
8694
8869
|
let terminalTurn = maxTurns;
|
|
8695
8870
|
|
|
8696
|
-
for (let turn = 0; turn < maxTurns; turn++) {
|
|
8871
|
+
for (let turn = 0; turn < maxTurns || ((completionNeedsFinalTurn || codexContinuationNeeded) && turn === maxTurns); turn++) {
|
|
8697
8872
|
// ★ /cancel 범용화(대표 2026-07-12) — abort 신호가 오면 tool 루프를 즉시 중단한다. 이게 없으면
|
|
8698
8873
|
// fetch 는 abort 돼도 루프가 다음 turn 으로 계속 돌아 tool 반복(grep 폭주 등)이 멈추지 않는다.
|
|
8699
8874
|
if (opts.signal?.aborted) {
|
|
@@ -8726,6 +8901,11 @@ export async function streamLLMWithTools(
|
|
|
8726
8901
|
}
|
|
8727
8902
|
}
|
|
8728
8903
|
let turnText = '';
|
|
8904
|
+
let turnTextPhase: 'commentary' | 'final' | undefined;
|
|
8905
|
+
let turnEnd: boolean | undefined;
|
|
8906
|
+
codexContinuationNeeded = false;
|
|
8907
|
+
turnCodexReasoningItems = undefined;
|
|
8908
|
+
turnCodexTextPhase = undefined;
|
|
8729
8909
|
// TUI-TURN-NARRATION — 이 라운드에 받은 추론 요약 글자 수(내용은 남기지 않는다).
|
|
8730
8910
|
let turnReasoningChars = 0;
|
|
8731
8911
|
turnReasoningDetails = undefined;
|
|
@@ -8825,13 +9005,14 @@ export async function streamLLMWithTools(
|
|
|
8825
9005
|
// revert to auto (see above).
|
|
8826
9006
|
const buildTurnOpts = () => {
|
|
8827
9007
|
const remainingFallbacks = opts.provider ? 0 : remainingFallbackProviderNames(attemptedProviders, opts).length;
|
|
8828
|
-
const base = { ...opts, model: activeModel, tools: activeTools, remainingFallbacks };
|
|
9008
|
+
const base = { ...opts, model: activeModel, tools: completionNeedsFinalTurn ? [] : activeTools, remainingFallbacks };
|
|
8829
9009
|
return turn === 0 ? base : { ...base, toolChoice: undefined };
|
|
8830
9010
|
};
|
|
8831
9011
|
let turnOpts = buildTurnOpts();
|
|
8832
9012
|
// reasoning-heavy family(codex/claude/gemini/grok/local)는 침묵 추론 구간이 길어 idle watchdog 를
|
|
8833
9013
|
// family-aware 로 상향(2026-07-19 goal-exec → 아크4 전-family). fast/mini(gpt·other)만 45s 유지.
|
|
8834
|
-
const
|
|
9014
|
+
const idleTimeout = resolveStreamIdleTimeout(opts, activeProvider, activeModel);
|
|
9015
|
+
const streamIdleTimeoutMs = idleTimeout.ms;
|
|
8835
9016
|
// ⚠️ hang 진단(2026-07-17) — codex SSE 스트림이 완료 신호 없이 안 끝나는 케이스 확정용.
|
|
8836
9017
|
// consume-start 후 consume-end 가 없으면 = for-await(streamChat SSE) hang. lastEvType 로 어느
|
|
8837
9018
|
// 이벤트 뒤에서 멈추는지(usage/text/tool_call) 특정. 무장할 상한도 남겨 실험 런을 구별한다.
|
|
@@ -8840,6 +9021,7 @@ export async function streamLLMWithTools(
|
|
|
8840
9021
|
provider: activeProvider.name,
|
|
8841
9022
|
model: activeModel,
|
|
8842
9023
|
idleMs: streamIdleTimeoutMs,
|
|
9024
|
+
idleMsSource: idleTimeout.source,
|
|
8843
9025
|
...(modelFamily !== 'other' ? { modelFamily } : {}),
|
|
8844
9026
|
});
|
|
8845
9027
|
let evCount = 0;
|
|
@@ -8847,6 +9029,8 @@ export async function streamLLMWithTools(
|
|
|
8847
9029
|
// ⭐ TUI-STREAM-RETRY(2026-10-14 실측) — 200 OK 로 흐르던 스트림이 소켓 끊김으로 죽으면 같은 공급자로
|
|
8848
9030
|
// 다시 건다(codex `stream_max_retries` 동형). 이 턴에서 받은 tool_call·image 가 있으면 재시도하지 않는다.
|
|
8849
9031
|
let streamDisconnectRetries = 0;
|
|
9032
|
+
let streamIdleTimeoutRetries = 0;
|
|
9033
|
+
let streamIdleRetryPartial = '';
|
|
8850
9034
|
let streamEmittedImage = false;
|
|
8851
9035
|
// 끊긴 조각을 이력(turnText·fullText)에서 «조용히» 되감는다 — 화면엔 지우라고 알리지 않는다
|
|
8852
9036
|
// (TUI 의 빈 델타는 «커밋»이다). 이미 보인 글과 겹치는 재시도 본문은 `retryDisplay` 가 막는다.
|
|
@@ -8864,6 +9048,7 @@ export async function streamLLMWithTools(
|
|
|
8864
9048
|
if (turnText.length > 0) {
|
|
8865
9049
|
fullText = fullText.slice(0, fullText.length - turnText.length);
|
|
8866
9050
|
turnText = '';
|
|
9051
|
+
turnTextPhase = undefined;
|
|
8867
9052
|
}
|
|
8868
9053
|
turnReasoningChars = 0;
|
|
8869
9054
|
retryDisplay.arm();
|
|
@@ -8875,9 +9060,25 @@ export async function streamLLMWithTools(
|
|
|
8875
9060
|
// 이벤트 대기를 idle timeout 과 race — STREAM_IDLE_TIMEOUT_MS 무이벤트면 스트림 정리·탈출(받은
|
|
8876
9061
|
// 텍스트로 진행). 35분 무한 hang → 자동 복구. 원인 규명은 consume-end 부재/idle-timeout 로그가.
|
|
8877
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;
|
|
8878
9076
|
while (true) {
|
|
8879
9077
|
let idleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
8880
9078
|
let step: { idle: true } | { idle: false; r: IteratorResult<LLMStreamEvent, void> };
|
|
9079
|
+
// Validate before entering the provider stream's catch/fallback boundary.
|
|
9080
|
+
// An incompatible request is deterministic and must not be retried elsewhere.
|
|
9081
|
+
if (getModelFamily(activeModel) === 'claude') assertNoTopLevelToolSchemaCombinators(turnOpts.tools);
|
|
8881
9082
|
try {
|
|
8882
9083
|
if (!streamIter) {
|
|
8883
9084
|
const finalized = finalizeStreamingProviderModel(activeProvider, activeModel);
|
|
@@ -8901,8 +9102,22 @@ export async function streamLLMWithTools(
|
|
|
8901
9102
|
? [turnOpts.toolChoice.name]
|
|
8902
9103
|
: []),
|
|
8903
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
|
+
}]));
|
|
8904
9118
|
const providerOpts: LLMOpts = {
|
|
8905
9119
|
...turnOpts,
|
|
9120
|
+
signal: attemptAbort.signal,
|
|
8906
9121
|
tools: turnOpts.tools?.map((tool) => ({ ...tool, name: nameMap.toProviderName(tool.name) })),
|
|
8907
9122
|
toolChoice: turnOpts.toolChoice && typeof turnOpts.toolChoice === 'object'
|
|
8908
9123
|
? { name: nameMap.toProviderName(turnOpts.toolChoice.name) }
|
|
@@ -8918,14 +9133,68 @@ export async function streamLLMWithTools(
|
|
|
8918
9133
|
streamIter.next().then((r) => ({ idle: false as const, r })),
|
|
8919
9134
|
new Promise<{ idle: true }>((res) => { idleTimer = setTimeout(() => res({ idle: true }), streamIdleTimeoutMs); }),
|
|
8920
9135
|
]);
|
|
9136
|
+
if (step.idle) throw new StreamIdleTimeoutError(streamIdleTimeoutMs);
|
|
8921
9137
|
} catch (err) {
|
|
8922
9138
|
if (idleTimer) clearTimeout(idleTimer);
|
|
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) {
|
|
9150
|
+
debug.log('llm.stream', 'idle-timeout', {
|
|
9151
|
+
turn, evCount, lastEvType, idleMs: err.idleMs, idleMsSource: idleTimeout.source,
|
|
9152
|
+
textChars: turnText.length, pendingCalls: pendingCalls.length,
|
|
9153
|
+
}, { level: 'warn' });
|
|
9154
|
+
// Provider iterators can queue return() behind a pending next(). Detach cleanup.
|
|
9155
|
+
const timedOutIterator = streamIter;
|
|
9156
|
+
if (timedOutIterator?.return) {
|
|
9157
|
+
try { void Promise.resolve(timedOutIterator.return(undefined)).catch(() => {}); } catch { /* fail-soft cleanup */ }
|
|
9158
|
+
}
|
|
9159
|
+
if (streamIdleTimeoutRetries < STREAM_IDLE_TIMEOUT_MAX_RETRIES
|
|
9160
|
+
&& pendingCalls.length === 0 && !streamEmittedImage && !opts.signal?.aborted) {
|
|
9161
|
+
streamIdleTimeoutRetries++;
|
|
9162
|
+
debug.log('llm.retry', 'idle-timeout-retry', {
|
|
9163
|
+
provider: activeProvider.name, model: activeModel, turn,
|
|
9164
|
+
attempt: streamIdleTimeoutRetries, maxRetries: STREAM_IDLE_TIMEOUT_MAX_RETRIES,
|
|
9165
|
+
delayMs: 0, statusLine: '스트림 무응답 · 재시도',
|
|
9166
|
+
}, { level: 'warn' });
|
|
9167
|
+
try { handlers.onStatus?.(`스트림 무응답 · 재시도 ${streamIdleTimeoutRetries}/${STREAM_IDLE_TIMEOUT_MAX_RETRIES}`); } catch { /* UI notification must not block recovery */ }
|
|
9168
|
+
streamIdleRetryPartial = turnText;
|
|
9169
|
+
rewindDisconnectedStream();
|
|
9170
|
+
streamIter = undefined;
|
|
9171
|
+
continue;
|
|
9172
|
+
}
|
|
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;
|
|
9190
|
+
}
|
|
8923
9191
|
if (err instanceof OverloadFailoverError && !opts.provider) {
|
|
8924
9192
|
const switched = activeProvider.name === 'openai-codex'
|
|
8925
9193
|
? firstAvailableFallbackProvider(attemptedProviders, opts)
|
|
8926
9194
|
: providerByName('grok');
|
|
8927
9195
|
if (switched && !attemptedProviders.has(switched.name)
|
|
8928
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());
|
|
8929
9198
|
debug.log('llm.router', 'overload-failover', {
|
|
8930
9199
|
turn,
|
|
8931
9200
|
blockedProvider: activeProvider.name,
|
|
@@ -8934,17 +9203,19 @@ export async function streamLLMWithTools(
|
|
|
8934
9203
|
status: err.status,
|
|
8935
9204
|
kind: err.kind,
|
|
8936
9205
|
}, { level: 'warn' });
|
|
9206
|
+
handlers.onStatus?.(`⚠ 공급자 전환: ${activeProvider.name} → ${switched.name} (${err.kind ?? err.name ?? 'unknown'})`);
|
|
8937
9207
|
const finalized = finalizeStreamingProviderModel(switched, switched.defaultModel);
|
|
8938
9208
|
activeProvider = finalized.provider;
|
|
8939
9209
|
activeModel = finalized.model;
|
|
8940
9210
|
attemptedProviders.add(activeProvider.name);
|
|
8941
9211
|
streamDisconnectRetries = 0;
|
|
9212
|
+
streamIdleTimeoutRetries = 0;
|
|
8942
9213
|
turnOpts = buildTurnOpts();
|
|
8943
9214
|
streamIter = undefined;
|
|
8944
9215
|
continue;
|
|
8945
9216
|
}
|
|
8946
9217
|
}
|
|
8947
|
-
if (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) {
|
|
8948
9219
|
const retryData = {
|
|
8949
9220
|
provider: activeProvider.name,
|
|
8950
9221
|
model: activeModel,
|
|
@@ -8988,6 +9259,7 @@ export async function streamLLMWithTools(
|
|
|
8988
9259
|
remainingProviders: remaining,
|
|
8989
9260
|
attempted: blockedProviders,
|
|
8990
9261
|
});
|
|
9262
|
+
(circuit ?? await import('./session-runtime/provider-circuit.js')).recordProviderFailure(activeProvider.name, verdict.category, Date.now());
|
|
8991
9263
|
blockedProviders = [...verdict.attempts];
|
|
8992
9264
|
const fallback = verdict.action === 'advance' ? providerByName(verdict.nextProvider) : undefined;
|
|
8993
9265
|
if (!fallback) {
|
|
@@ -9013,30 +9285,43 @@ export async function streamLLMWithTools(
|
|
|
9013
9285
|
tools: activeTools.map((tool) => tool.name),
|
|
9014
9286
|
...(opts.model ? { modelOverrideDropped: opts.model } : {}),
|
|
9015
9287
|
}, { level: 'warn' });
|
|
9288
|
+
handlers.onStatus?.(`⚠ 공급자 전환: ${activeProvider.name} → ${fallback.name} (${verdict.category})`);
|
|
9016
9289
|
const finalized = finalizeStreamingProviderModel(fallback, fallback.defaultModel);
|
|
9017
9290
|
activeProvider = finalized.provider;
|
|
9018
9291
|
activeModel = finalized.model;
|
|
9019
9292
|
attemptedProviders.add(activeProvider.name);
|
|
9020
9293
|
// 재시도 상한은 «공급자마다» — 넘어간 공급자도 스트림 도중 끊김이면 다시 5회까지 건다.
|
|
9021
9294
|
streamDisconnectRetries = 0;
|
|
9295
|
+
streamIdleTimeoutRetries = 0;
|
|
9022
9296
|
turnOpts = buildTurnOpts();
|
|
9023
9297
|
streamIter = undefined;
|
|
9024
9298
|
continue;
|
|
9025
9299
|
}
|
|
9026
9300
|
if (idleTimer) clearTimeout(idleTimer);
|
|
9027
|
-
if (step.
|
|
9028
|
-
|
|
9029
|
-
|
|
9301
|
+
if (step.r.done) {
|
|
9302
|
+
(circuit ?? await import('./session-runtime/provider-circuit.js')).recordProviderSuccess(activeProvider.name, Date.now());
|
|
9303
|
+
releaseStreamAttempt();
|
|
9030
9304
|
break;
|
|
9031
9305
|
}
|
|
9032
|
-
if (step.r.done) break;
|
|
9033
9306
|
const ev = step.r.value;
|
|
9034
9307
|
evCount++;
|
|
9035
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 = '';
|
|
9036
9312
|
if (ev.type === 'text') {
|
|
9037
9313
|
turnText += ev.delta;
|
|
9314
|
+
if (ev.phase) turnTextPhase = ev.phase;
|
|
9315
|
+
if (ev.phase) turnCodexTextPhase = ev.phase === 'final' ? 'final_answer' : 'commentary';
|
|
9038
9316
|
fullText += ev.delta;
|
|
9039
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);
|
|
9040
9325
|
} else if (ev.type === 'reasoning_details') {
|
|
9041
9326
|
turnReasoningDetails = ev.details;
|
|
9042
9327
|
} else if (ev.type === 'tool_call') {
|
|
@@ -9163,6 +9448,26 @@ export async function streamLLMWithTools(
|
|
|
9163
9448
|
}
|
|
9164
9449
|
}
|
|
9165
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
|
+
}
|
|
9166
9471
|
// No tool calls + non-empty text = the model gave its final answer.
|
|
9167
9472
|
if (pendingCalls.length === 0 && turnText.length > 0) {
|
|
9168
9473
|
const visibleText = finalizeVisibleAssistantText(fullText, turnText, sawToolRound);
|
|
@@ -9200,7 +9505,7 @@ export async function streamLLMWithTools(
|
|
|
9200
9505
|
// TUI-H1-GOALLOOP-EMPTY-TAIL — 답이 이 스트림 «앞»에 이미 보였어도 같다(opts.terminalPriorAnswerVisible —
|
|
9201
9506
|
// 예: Bash → «끝» → 재주입 → update_goal 만 → 빈 턴). 이 스트림에 답이 없으면 빈 문자열로 끝내고 화면은
|
|
9202
9507
|
// 건드리지 않는다(onText 생략 · emitTurnComplete 는 빈 답을 이력에 안 싣는다). 마감은 호출자(goal loop) 몫.
|
|
9203
|
-
if (terminalSignalDispatched && (lastToolRoundText.trim().length > 0 || opts.terminalPriorAnswerVisible === true)) {
|
|
9508
|
+
if (!completionNeedsFinalTurn && terminalSignalDispatched && (lastToolRoundText.trim().length > 0 || opts.terminalPriorAnswerVisible === true)) {
|
|
9204
9509
|
const answer = lastToolRoundText.trim().length > 0 ? lastToolRoundText : '';
|
|
9205
9510
|
debug.log('goal.loop', 'empty-turn-after-terminal-signal', {
|
|
9206
9511
|
turn, emptyRetries, answerChars: answer.length,
|
|
@@ -9244,7 +9549,10 @@ export async function streamLLMWithTools(
|
|
|
9244
9549
|
clearVisibleAssistantTextForToolRound(handlers, sawToolRound);
|
|
9245
9550
|
}
|
|
9246
9551
|
sawToolRound = true;
|
|
9247
|
-
if (turnText.trim().length > 0)
|
|
9552
|
+
if (turnText.trim().length > 0) {
|
|
9553
|
+
lastToolRoundText = turnText;
|
|
9554
|
+
lastToolRoundTextPhase = turnTextPhase;
|
|
9555
|
+
}
|
|
9248
9556
|
// TUI-GOAL-LOOP-FRICTION(#46) — 이 턴의 호출이 «종결 신호뿐»이면 예산·후속 단계 거부를 걸지 않는다.
|
|
9249
9557
|
const terminalOnlyTurn = terminalToolNames.size > 0
|
|
9250
9558
|
&& pendingCalls.length > 0
|
|
@@ -9293,7 +9601,10 @@ export async function streamLLMWithTools(
|
|
|
9293
9601
|
...(call.providerMeta !== undefined ? { providerMeta: call.providerMeta } : {}),
|
|
9294
9602
|
});
|
|
9295
9603
|
}
|
|
9296
|
-
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
|
+
});
|
|
9297
9608
|
|
|
9298
9609
|
// Final-synthesis window: in the last FINAL_SYNTHESIS_TURNS of the
|
|
9299
9610
|
// budget, refuse to execute tool calls. Each pending call gets a
|
|
@@ -10289,7 +10600,8 @@ export async function streamLLMWithTools(
|
|
|
10289
10600
|
// rejection without colliding with the auto-narrow path)
|
|
10290
10601
|
// - call is in SEARCH_ONLY_TOOLS
|
|
10291
10602
|
if (
|
|
10292
|
-
|
|
10603
|
+
!opts.researchTurn
|
|
10604
|
+
&& dispatchedReadCount === 0
|
|
10293
10605
|
&& autoNarrowedReadCount === 0
|
|
10294
10606
|
&& searchOnlyTurnStreak >= 3
|
|
10295
10607
|
&& SEARCH_ONLY_TOOLS.has(call.name)
|
|
@@ -11066,7 +11378,7 @@ export async function streamLLMWithTools(
|
|
|
11066
11378
|
resultBlocks.push({
|
|
11067
11379
|
type: 'tool_result',
|
|
11068
11380
|
tool_use_id: call.id,
|
|
11069
|
-
content:
|
|
11381
|
+
content: toolResultContentForCall(call.name, result),
|
|
11070
11382
|
...(isError ? { isError: true } : {}),
|
|
11071
11383
|
});
|
|
11072
11384
|
}
|
|
@@ -11115,10 +11427,43 @@ export async function streamLLMWithTools(
|
|
|
11115
11427
|
}
|
|
11116
11428
|
// 신호뿐인 턴 · 섞인 턴(정상 디스패치 · 부분 거부 · 통째 거부의 수신 확인) 모두 — 종결 신호가 이 턴에 «받아들여졌다».
|
|
11117
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
|
+
}
|
|
11118
11463
|
// TUI-GOAL-LOOP-FRICTION(#63) — 종결 신호뿐인 턴 ⊕ 같은 턴에 쓴 답 = 이 턴이 최종 답이다.
|
|
11119
11464
|
// 다음 모델 턴을 열면 할 말이 없는 모델이 빈 턴을 되풀이하고 `[NO FINAL SYNTHESIS]` 가 붙는다(10-15 22:36Z 표본).
|
|
11120
11465
|
// 이 턴에 답이 없으면 종전처럼 다음 턴을 연다(앞 라운드 글은 «하겠습니다» 류 서술일 수 있다 — 모델이 답을 쓰게).
|
|
11121
|
-
if (terminalOnlyTurn && !hardStopText && !postToolResultUserNote && turnText.trim().length > 0) {
|
|
11466
|
+
if (terminalOnlyTurn && !completionNeedsFinalTurn && !hardStopText && !postToolResultUserNote && turnText.trim().length > 0) {
|
|
11122
11467
|
const answer = turnText;
|
|
11123
11468
|
debug.log('goal.loop', 'terminal-signal-finish', {
|
|
11124
11469
|
turn, maxTurns, tools: pendingCalls.map((call) => call.name), answerChars: answer.length,
|
|
@@ -11245,7 +11590,8 @@ export async function streamLLMWithTools(
|
|
|
11245
11590
|
// synthesis attempt. Extended to gemini 2026-05-04 alongside
|
|
11246
11591
|
// W5-E/W5-F for the same pathology shape.
|
|
11247
11592
|
if (
|
|
11248
|
-
!
|
|
11593
|
+
!opts.researchTurn
|
|
11594
|
+
&& !forceSynthesisAttempted
|
|
11249
11595
|
&& noContentReadTurnStreak >= 4
|
|
11250
11596
|
&& (modelFamily === 'gemini'
|
|
11251
11597
|
|| applyCodexBehaviorGuard('force-synthesis', effectiveModel, codexGuardCandidate, true))
|
|
@@ -11331,6 +11677,7 @@ export async function streamLLMWithTools(
|
|
|
11331
11677
|
let synthesizedText: string | null = null;
|
|
11332
11678
|
const shouldForceSynthesisOnBudget =
|
|
11333
11679
|
loopTermination === 'budget-exhausted'
|
|
11680
|
+
&& !codexContinuationNeeded
|
|
11334
11681
|
&& !forceSynthesisAttempted
|
|
11335
11682
|
&& (modelFamily === 'gemini'
|
|
11336
11683
|
|| applyCodexBehaviorGuard('force-synthesis', effectiveModel, codexGuardCandidate, true));
|
|
@@ -11500,6 +11847,7 @@ function makeOpenAICompatProvider(
|
|
|
11500
11847
|
throw new Error(`${name} unavailable: configure apiKey via \`elanous setup\``);
|
|
11501
11848
|
}
|
|
11502
11849
|
const activeModel = opts.model || model;
|
|
11850
|
+
if (getModelFamily(activeModel) === 'claude') assertNoTopLevelToolSchemaCombinators(opts.tools);
|
|
11503
11851
|
const wireModel = name === 'openrouter' ? openRouterWireModel(activeModel) : activeModel;
|
|
11504
11852
|
const tools = toOpenAITools(
|
|
11505
11853
|
opts.tools,
|
|
@@ -11797,6 +12145,8 @@ function makeCodexProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
11797
12145
|
const responsesUrl = cfgBase
|
|
11798
12146
|
? (cfgBase.endsWith('/responses') ? cfgBase : `${cfgBase.replace(/\/$/, '')}/responses`)
|
|
11799
12147
|
: `${CODEX_API_BASE_URL}/responses`;
|
|
12148
|
+
const endpointSupportsStore = !responsesUrl.includes('chatgpt.com/backend-api');
|
|
12149
|
+
const useStore = endpointSupportsStore && cfg.codexStore !== false;
|
|
11800
12150
|
// Image-pipeline P3 (2026-05-05) — gate the function_call_output
|
|
11801
12151
|
// ContentItem[] wire on the active model. gpt-5 family supports
|
|
11802
12152
|
// image_url in tool results; legacy gpt-4 / non-vision routes
|
|
@@ -11816,6 +12166,7 @@ function makeCodexProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
11816
12166
|
const { instructions, input } = messagesToResponsesInput(messages, {
|
|
11817
12167
|
acceptToolImages: codexAcceptToolImages,
|
|
11818
12168
|
acceptUserMessageImages: codexAcceptUserImages,
|
|
12169
|
+
replayCodexReasoning: !useStore,
|
|
11819
12170
|
onOrphanToolResult: (callId) => {
|
|
11820
12171
|
try { debug.log('llm.codex', 'orphan-tool-output-dropped', { callId }); }
|
|
11821
12172
|
catch { /* observation must not block the request */ }
|
|
@@ -11865,12 +12216,17 @@ function makeCodexProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
11865
12216
|
// wave for ChatGPT regardless of cfg.codexStore — the
|
|
11866
12217
|
// infrastructure stays in place for Azure/API-key paths and
|
|
11867
12218
|
// for any future ChatGPT-side policy change.
|
|
11868
|
-
const endpointSupportsStore = !responsesUrl.includes('chatgpt.com/backend-api');
|
|
11869
|
-
const useStore = endpointSupportsStore && cfg.codexStore !== false;
|
|
11870
12219
|
const delta = useStore ? getIncrementalItems(lastInput, input) : null;
|
|
11871
|
-
|
|
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);
|
|
11872
12228
|
const wirePrevId = (delta && lastResponseId) ? lastResponseId : undefined;
|
|
11873
|
-
|
|
12229
|
+
let requestBody = {
|
|
11874
12230
|
model: opts.model || model,
|
|
11875
12231
|
instructions,
|
|
11876
12232
|
input: wireInput,
|
|
@@ -11884,8 +12240,77 @@ function makeCodexProvider(cfg: UCLLMConfig): LLMProvider {
|
|
|
11884
12240
|
// can disable via llm.codexStore=false.
|
|
11885
12241
|
store: useStore,
|
|
11886
12242
|
...(wirePrevId ? { previousResponseId: wirePrevId } : {}),
|
|
11887
|
-
}
|
|
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, {
|
|
11888
12311
|
accountId,
|
|
12312
|
+
promptCache,
|
|
12313
|
+
...(serializedWireBody ? { serializedWireBody } : {}),
|
|
11889
12314
|
// Capture the new response id from the SSE stream so the
|
|
11890
12315
|
// next call can thread it. If the backend skips the event
|
|
11891
12316
|
// lastResponseId stays undefined and we fall back to full
|