elanous 0.2.28 → 0.2.31
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/{y1ltt7oCZxVpC6zVPhZ2O → LSXfY0u9QtfDbejY0Ukf_}/_buildManifest.js +1 -1
- package/apps/pwa/out/_next/static/chunks/{ab4d57c2.e90bc2cb31949045.js → 0bb0ff36.b8d418980951e5ba.js} +7 -7
- package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +27 -0
- package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +287 -0
- package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +62 -0
- package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5492-e05e26a033ba80d2.js → 1335-6731f392c35216eb.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +23 -0
- package/apps/pwa/out/_next/static/chunks/1834-50625904996a8fa8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +149 -0
- package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +41 -0
- package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8578.dff22d988cc2b106.js → 2213.2ccbada92c33ea0f.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5081.a240b63fad28663a.js → 2871.0bca6137343b3f76.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2898.fd781bc7cf01a7b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2940-619bfd8ef337c611.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2846.d6a433b8663819a5.js → 2985.39ccdecd36848b12.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +115 -0
- package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +64 -0
- package/apps/pwa/out/_next/static/chunks/{f4dfbfc0.a69fb12f854882aa.js → 3267c0e6.d34854e7b3984a6e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3278.2e5d15b53a4091c8.js +2 -0
- package/apps/pwa/out/_next/static/chunks/3541-ce3a5424ed5ad7f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3143.257997a5f1ed79df.js → 3902.e1e71aaac850a045.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{16e57f67.3ea19e893461e611.js → 409f1e57.d0649fc47691ebfe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1146.80d15ea7c6e6ee95.js → 4111.2bfedbb233ad206b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1516.83dd2c1b86b4e507.js → 4174.92ed04922709ac9e.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +36 -0
- package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +286 -0
- package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +77 -0
- package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +226 -0
- package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9938.b23e4d4dfa0114cd.js → 4999.c064a4000c2a9e94.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5173-233188df2f42c626.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1157.f08bf2b70915e176.js → 5304.04d24756f242a094.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/{7752.5cbdd0b433c54af9.js → 5307.60f2209e809bd627.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9917-9e26abc5f7772735.js → 5458-16cd7a2b51b74c8c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{6196.34d6b229079e9e28.js → 5525.86debf231e181813.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4593.10f5b9bd702d4a6c.js → 5543.a438b8ab5a13ea47.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +74 -0
- package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +94 -0
- package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7483.ba01c6c209b81bba.js → 6092.a7f99e68b188ca66.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9974.e77b4ff4884557b3.js → 6157.0c9af021de4fb31b.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3309.364573ceedbdfd5f.js → 6323.8672b4817a306928.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{94.4cfed21c0b781a06.js → 6433.fc573af22bbc9ab7.js} +4 -4
- package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{949.1e7d45ccb71580aa.js → 6517.4147878ac06d584d.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +32 -0
- package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +104 -0
- package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2528.3868070ef1be69f9.js → 6767.ea607cf0c20a25af.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +93 -0
- package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1743.563d3168e95825ef.js → 7502.ccd5b8065545edd0.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
- package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5408.377c8c543635b81f.js → 7862.30a8d6482bb238eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{65ebff95.081daeff622d238e.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{2697.76ca2ac3efef6f3b.js → 8018.a32663f04a6fc5f9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
- package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
- package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4204.a409ab6250c0f6a8.js → 9221.7d22eaf353a2d4e7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5785-ea8d2c633b6688e3.js → 9279-d28c5b7754d010ae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9398-6aed28f0a96d0d6f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/997ce8a5-2ad501927003b41b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9311.24c8f5ea793253dd.js → 9989.3694300e5f000b14.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-fa46d4588e8442c2.js → page-2ebb8fd59b9461f9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-ced0bcfc6542b3fc.js → page-349f2752d8cd37ad.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-cb249e81ed339318.js → page-0a07363b130182a1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-521ee23ac8c0abfa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-149dc1caba411bb9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6def8a8e.c81f9ca41028eccf.js → b313b242.cb1265eea908db61.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{e87d89b9.2e71c0ae475d28a1.js → e5012ffe.f727e23c231f4342.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{e117f801.e92bf10242653497.js → ebc7d829.264a0bcb6c750b50.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +1 -0
- package/apps/pwa/out/_next/static/css/{72becfd42807b50d.css → 3f5fc6f96e2cf7b2.css} +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +23 -23
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/live-run/index.html +1 -1
- package/apps/pwa/out/live-run/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/bin/elanous.mjs +7 -3
- package/graphs/context/nightly-condense.yaml +1 -0
- package/graphs/intake/intake-daily.yaml +8 -1
- package/graphs/intake/recipes.yaml +5 -0
- package/graphs/lecture/lecture-note.yaml +2 -2
- package/graphs/ops/harness-gc.yaml +1 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +15 -7
- package/graphs/units/recipes.yaml +3 -0
- package/graphs/units/release-gate-recheck.yaml +15 -0
- package/package.json +2 -1
- package/plugins/agent-team/agents/research.md +1 -0
- package/scripts/check-native-tool-wiring.ts +3 -2
- package/scripts/ci-android-unit-tests.ts +16 -0
- package/scripts/ci-typecheck-changed.ts +40 -11
- package/scripts/coord-channel-watch.sh +45 -19
- package/scripts/coord-role-pack.ts +222 -0
- package/scripts/cron-run.ts +96 -3
- package/scripts/detect-test-interference.ts +38 -5
- package/scripts/gate-pr-cache.ts +65 -0
- package/scripts/gh-surface/capture.ts +126 -0
- package/scripts/gh-surface/gh +40 -0
- package/scripts/import-graph-scc.ts +38 -0
- package/scripts/install.ps1 +19 -0
- package/scripts/intake-social.ts +181 -0
- package/scripts/lecture-note/node.ts +71 -4
- package/scripts/lib/android-toolchain.ts +32 -0
- package/scripts/lib/deterministic-env.ts +62 -0
- package/scripts/lib/gate-test-env.ts +19 -0
- package/scripts/lib/morning-report-options.ts +41 -0
- package/scripts/measure-goal-grounding-corpus.ts +2 -1
- package/scripts/pr-land-extra-remote-gates.ts +49 -0
- package/scripts/ratchets/test-interference-patterns.allowlist.txt +257 -0
- package/scripts/ratchets/test-interference-patterns.ts +367 -0
- package/scripts/release-loop/cut-branch.ts +4 -3
- package/scripts/release-loop/export-check-node.ts +0 -1
- package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
- package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
- package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
- package/scripts/release-loop/gate-batch-safe.ts +23 -0
- package/scripts/release-loop/gate-closure.ts +12 -8
- package/scripts/release-loop/gate-diff.ts +1 -1
- package/scripts/release-loop/gate-history.ts +422 -0
- package/scripts/release-loop/gate-host-mirror.ts +66 -0
- package/scripts/release-loop/gate-node.ts +806 -94
- package/scripts/release-loop/gate-partial.ts +106 -9
- package/scripts/release-loop/gate-pr-cache.ts +66 -0
- package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
- package/scripts/release-loop/gate-r2-verdict.ts +189 -0
- package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
- package/scripts/release-loop/gate-triage-node.ts +190 -0
- package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
- package/scripts/release-loop/import-graph-scc-run.ts +54 -0
- package/scripts/release-loop/import-graph-scc.ts +215 -0
- package/scripts/release-loop/node-verdict.ts +2 -0
- package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
- package/scripts/release-loop/resume-release.ts +33 -4
- package/scripts/release-loop/resume.ts +13 -5
- package/scripts/release-loop/spawn-lane.ts +51 -0
- package/scripts/release-loop/tui-node-checks.ts +23 -0
- package/scripts/release-loop/tui-sim-node.ts +3 -2
- package/scripts/release-loop/unattended-release.ts +16 -0
- package/scripts/release-loop/version-node.ts +62 -4
- package/scripts/test-deterministic.ts +46 -73
- package/scripts/train-reach-grouping.ts +48 -0
- package/scripts/tsc-incremental-cache.ts +86 -0
- package/scripts/tsc-incremental-diagnostics.ts +76 -0
- package/scripts/tsc-main-safety-net.ts +2 -2
- package/scripts/usage-rollup.ts +11 -3
- package/src/acp/client.ts +4 -1
- package/src/acp/core-turn-bridge.ts +145 -24
- package/src/acp/elanous-extensions.ts +2 -0
- package/src/acp/server.ts +2 -0
- package/src/ad-pipeline/run.ts +4 -2
- package/src/agent/ref-grounding.ts +18 -0
- package/src/agent/runner.ts +169 -3
- package/src/agent/subagent-callable.ts +3 -2
- package/src/agent-mission/review-loop.ts +6 -3
- package/src/agent-substrate/acp-implementer.ts +14 -2
- package/src/agent-substrate/pr-reviewer.ts +41 -21
- package/src/agent-substrate/self-review-cli.ts +30 -4
- package/src/autopilot/pr-manager.ts +62 -7
- package/src/briefing/brief-items.ts +24 -22
- package/src/budget/pty-usage-reemit.ts +7 -0
- package/src/budget/run-usage-rollup.ts +9 -0
- package/src/budget/usage-daily-store.ts +98 -0
- package/src/capture/tui-self-report.ts +37 -4
- package/src/chat/chat-cli.ts +10 -2
- package/src/chat/index.ts +107 -20
- package/src/chat/input-control-key.ts +5 -3
- package/src/chat/pickers/modal-runtime.ts +1 -0
- package/src/chat/pickers/modals.ts +3 -1
- package/src/chat/tool-interrupt-behavior.ts +38 -0
- package/src/chat/tool-render/dispatch.ts +5 -1
- package/src/chat/turn-typeahead.ts +191 -29
- package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
- package/src/cli/agent-cli.ts +41 -13
- package/src/cli/config-audit.ts +123 -0
- package/src/cli/dashboard-name-flag.ts +48 -0
- package/src/cli/decisions-cli.ts +80 -6
- package/src/cli/doctor-cli.ts +80 -0
- package/src/cli/log-event-names.ts +19 -0
- package/src/cli/mcp-login.ts +21 -5
- package/src/cli/msg-cli.ts +133 -2
- package/src/cli/pr-cli.ts +546 -112
- package/src/cli/pr-land-heavy-remote.ts +233 -0
- package/src/cli/pr-land-overlap-evidence.ts +167 -14
- package/src/cli/pr-land-pod-shadow-job.ts +83 -0
- package/src/cli/pr-land-pod-shadow.ts +16 -3
- package/src/cli/pr-land-virtual-rebase.ts +108 -0
- package/src/cli/pty-takeover-cli.ts +125 -16
- package/src/cli/release-cli.ts +122 -14
- package/src/cli/remote-resolve.ts +2 -1
- package/src/cli/seat-cli.ts +164 -19
- package/src/cli/self-update.ts +5 -2
- package/src/cli/tasks-cli.ts +105 -21
- package/src/cli/usage-cli.ts +146 -12
- package/src/cli/usage-daily-cli.ts +84 -0
- package/src/context-bus/context-first.ts +13 -0
- package/src/context-bus/context-now.ts +95 -7
- package/src/context-bus/ops-events.ts +75 -0
- package/src/control-plane/lease-holder.ts +12 -8
- package/src/control-plane/ledger.ts +163 -4
- package/src/control-plane/server.ts +91 -11
- package/src/core-turn/auth-rejected-notice.ts +41 -0
- package/src/core-turn/run-core-turn.ts +14 -2
- package/src/core-turn/run-goal-loop.ts +239 -4
- package/src/core-turn/seat-turn-cap.ts +79 -0
- package/src/core-turn/short-question.ts +78 -13
- package/src/core-turn/types.ts +10 -0
- package/src/dashboard/acp-active-model.ts +40 -0
- package/src/dashboard/acp-boot.ts +3 -0
- package/src/dashboard/auto-compact-runtime.ts +2 -0
- package/src/dashboard/boot-banner.ts +80 -0
- package/src/dashboard/dashboard-status-lines.ts +11 -0
- package/src/dashboard/detail-viewer-runtime.ts +15 -2
- package/src/dashboard/event-loop-stall-monitor.ts +4 -0
- package/src/dashboard/goal-loop-thinking.ts +16 -0
- package/src/dashboard/hitl-boot.ts +9 -4
- package/src/dashboard/index.ts +448 -998
- package/src/dashboard/input/chat-main-entry-runtime.ts +2 -0
- package/src/dashboard/input/chat-main-log-actions.ts +4 -0
- package/src/dashboard/input/chat-main-log-command.ts +12 -1
- package/src/dashboard/input/chat-main-plain-turn-runtime.ts +176 -4
- package/src/dashboard/input/chat-main-session.ts +14 -3
- package/src/dashboard/input/chat-main-slash-command.ts +7 -0
- package/src/dashboard/input/chat-main-turn.ts +14 -4
- package/src/dashboard/input/compact-prepass-recovery.ts +130 -0
- package/src/dashboard/input/dashboard-chord-actions.ts +10 -1
- package/src/dashboard/input/dashboard-chord-runtime.ts +2 -0
- package/src/dashboard/input/external-input-host.ts +71 -0
- package/src/dashboard/input/internal-turn.ts +261 -0
- package/src/dashboard/input/log-fold-binding.ts +18 -0
- package/src/dashboard/input/mouse-wiring.ts +17 -4
- package/src/dashboard/input/seat-autowake.ts +318 -0
- package/src/dashboard/input/turn-steer-bridge.ts +164 -0
- package/src/dashboard/log-click-runtime.ts +5 -3
- package/src/dashboard/loop-scheduler.ts +72 -0
- package/src/dashboard/running-build-status.ts +74 -0
- package/src/dashboard/seat-boot-preamble.ts +131 -0
- package/src/dashboard/seat-local-instructions.ts +305 -0
- package/src/dashboard/skill-runtime.ts +2 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +220 -1203
- package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
- package/src/dashboard/slash-runtime/index.ts +13 -0
- package/src/dashboard/slash-runtime/model-choices.ts +35 -0
- package/src/dashboard/term-slash-runtime.ts +15 -0
- package/src/dashboard/turn-busy-teardown.ts +50 -0
- package/src/dashboard/turn-preamble.ts +30 -2
- package/src/dashboard/turn-session-layers.ts +176 -0
- package/src/dashboard/turn-stream-formatter.ts +14 -6
- package/src/dashboard/turn-stream-presentation-applier.ts +8 -0
- package/src/decisions/decision-ledger.ts +45 -4
- package/src/discord-self-message.ts +4 -4
- package/src/domains/release-tool.ts +26 -10
- package/src/domains/surface-events.ts +4 -1
- package/src/domains/watch-default-scheduler.ts +8 -9
- package/src/field-note/transcribe.ts +17 -0
- package/src/fold-stack.ts +24 -1
- package/src/git-fs/dirty.ts +32 -4
- package/src/git-fs/index.ts +43 -1
- package/src/github/remote-call.ts +81 -0
- package/src/goals/registry.ts +46 -6
- package/src/goals/types.ts +7 -1
- package/src/graph-runner/runner.ts +2 -0
- package/src/grok/credential.ts +26 -0
- package/src/harness/harness-clean.ts +2 -1
- package/src/harness/harness-cli-command.ts +52 -5
- package/src/harness/harness-gc.ts +34 -6
- package/src/harness/harness-incidents.ts +57 -20
- package/src/harness/harness-pod-dispatch.ts +87 -10
- package/src/harness/harness-queue.ts +53 -4
- package/src/harness/harness-stop.ts +4 -3
- package/src/harness/harness-substrate-default.ts +78 -7
- package/src/harness/harness-worktree-auto.ts +2 -1
- package/src/harness/harness-worktrees.ts +3 -2
- package/src/hooks/dispatch.ts +2 -1
- package/src/index.ts +166 -26
- package/src/input/external-input-queue.ts +251 -0
- package/src/intake-plane/slash.ts +14 -3
- package/src/interactive-terminal-modal.ts +13 -0
- package/src/keybindings.ts +4 -1
- package/src/llm/route-decision.ts +25 -0
- package/src/llm/tool-loop-steered-rejection.ts +33 -0
- package/src/llm-stream-retry-display.ts +59 -0
- package/src/llm.ts +391 -74
- package/src/log-entry.ts +3 -3
- package/src/log-pane/search.ts +29 -4
- package/src/loops/agent-reply.ts +256 -0
- package/src/loops/budget.ts +37 -7
- package/src/loops/consensus.ts +348 -0
- package/src/loops/loop-cli.ts +3 -2
- package/src/loops/msg-address.ts +57 -0
- package/src/loops/msg-wake.ts +484 -0
- package/src/loops/observe.ts +19 -3
- package/src/loops/orchestrator/inbox.ts +60 -3
- package/src/loops/orchestrator/tick.ts +80 -6
- package/src/loops/orchestrator/traffic.ts +64 -1
- package/src/loops/registry.ts +72 -4
- package/src/market/signed-index.ts +14 -0
- package/src/mcp/mcp-oauth.ts +54 -5
- package/src/memory.ts +20 -5
- package/src/models/prompts.ts +28 -0
- package/src/msg/msg-sse-client.ts +223 -0
- package/src/msg/msg-store.ts +86 -2
- package/src/mss/logging/log-store.ts +225 -1
- package/src/native-tool-catalog.ts +125 -0
- package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
- package/src/nexus/api/http-server.ts +59 -15
- package/src/nexus/api/loop-resources.ts +19 -3
- package/src/nexus/api/ops-api.ts +13 -0
- package/src/nexus/api/project-autopsy.ts +127 -0
- package/src/nexus/api/terminals.ts +3 -0
- package/src/nexus/api/workflow-approvals.ts +2 -0
- package/src/nexus/daemon-thin-inventory.md +37 -0
- package/src/nexus/index.ts +70 -0
- package/src/nexus/onboarding/first-boot-wizard.ts +56 -2
- package/src/nexus/state/state.ts +1 -0
- package/src/oauth/codex-account-store.ts +15 -3
- package/src/oauth/codex-billing-route.ts +31 -0
- package/src/oauth/store.ts +32 -7
- package/src/onboarding/first-run.ts +28 -3
- package/src/ops/overview-cache.ts +16 -4
- package/src/ops/overview-collect.ts +19 -2
- package/src/ops/resources.ts +82 -0
- package/src/panes/log-pane.ts +67 -8
- package/src/persona/presets.ts +44 -0
- package/src/plugins/maker/connector-maker.ts +41 -0
- package/src/plugins/maker/skill-maker.ts +42 -0
- package/src/plugins/maker/wizard-generate.ts +6 -4
- package/src/pr-tool/census.ts +288 -0
- package/src/preview/terminal.ts +14 -1
- package/src/prompt-cache/types.ts +2 -0
- package/src/prompt-enhance/enhance.ts +24 -8
- package/src/prompt-library/chat-conciseness.ts +13 -0
- package/src/prompt-library/universal-preamble.ts +283 -61
- package/src/pty-shell/pty-control-ipc.ts +4 -1
- package/src/pty-shell/pty-manifest.ts +77 -5
- package/src/pty-shell/registry.ts +19 -2
- package/src/pty-shell/tui-run-state.ts +253 -0
- package/src/release-loop/gate-host-reservation.ts +97 -0
- package/src/release-loop/landing-freeze.ts +5 -0
- package/src/release-loop/light-rc.ts +32 -4
- package/src/release-loop/placement.ts +92 -1
- package/src/release-loop/rehearsal-shard-plan.ts +149 -0
- package/src/release-loop/rehearsal.ts +73 -17
- package/src/render.ts +5 -1
- package/src/repl/index.ts +20 -2
- package/src/seat-loop/seat-knowhow.ts +282 -0
- package/src/seat-loop/seat-loop.ts +41 -2
- package/src/seat-loop/seat-report.ts +42 -2
- package/src/seat-loop/traffic-signal.ts +3 -0
- package/src/self-dev/ask-launch-flow.ts +24 -3
- package/src/self-dev/decompose-compose-graph.ts +28 -27
- package/src/self-dev/decompose-proposal.ts +53 -38
- package/src/self-dev/decompose.ts +17 -0
- package/src/self-dev/dev-pipeline.ts +31 -2
- package/src/self-dev/draft-residue.ts +24 -9
- package/src/self-dev/draft-sweep.ts +59 -4
- package/src/self-dev/external-call-zero.ts +77 -0
- package/src/self-dev/launch-preflight-text.ts +6 -0
- package/src/self-dev/launch-preflight.ts +25 -3
- package/src/self-dev/local-supervisor-judge.ts +185 -0
- package/src/self-dev/run-supervisor.ts +300 -24
- package/src/self-dev/run-types.ts +20 -0
- package/src/self-dev/shard-aggregate.ts +15 -2
- package/src/self-dev/shard-plan.ts +47 -0
- package/src/self-dev/shard-run.ts +135 -12
- package/src/self-dev/spawn-lane-files.ts +19 -0
- package/src/self-health/signatures.ts +132 -0
- package/src/self-implement/app-api-budget.ts +51 -11
- package/src/self-implement/config-gate.ts +2 -1
- package/src/self-implement/doctor-visit.ts +118 -0
- package/src/self-implement/expose-gate.ts +2 -1
- package/src/self-implement/gate-artifacts.ts +405 -0
- package/src/self-implement/gate-cli.ts +212 -18
- package/src/self-implement/gate-remote.ts +110 -25
- package/src/self-implement/gate-scenario.ts +85 -0
- package/src/self-implement/goal-author-decompose.ts +80 -16
- package/src/self-implement/goal-author.ts +270 -76
- package/src/self-implement/goal-authoring-grounding.ts +1 -1
- package/src/self-implement/goal-file-name.ts +65 -0
- package/src/self-implement/graph-authority.ts +38 -6
- package/src/self-implement/graph-overlay-condition.ts +92 -1
- package/src/self-implement/ground-goal.ts +2 -1
- package/src/self-implement/heal-triage.ts +79 -0
- package/src/self-implement/host-regate.ts +74 -2
- package/src/self-implement/orchestrator.ts +14 -123
- package/src/self-implement/pr-title.ts +123 -0
- package/src/self-implement/review-mustfix-class.ts +115 -0
- package/src/self-implement/run-checkpoint.ts +235 -0
- package/src/self-implement/run-ledger.ts +266 -17
- package/src/self-implement/run-stop.ts +4 -3
- package/src/self-implement/run-ttl.ts +28 -4
- package/src/self-implement/running-runs.ts +10 -6
- package/src/self-implement/seams.ts +2 -0
- package/src/self-implement/self-implement-runtime.ts +32 -0
- package/src/self-implement/shadow-stage.ts +7 -6
- package/src/self-implement/stop-autoheal.ts +2 -1
- package/src/self-implement/train-gate-remote.ts +37 -8
- package/src/self-implement/train-reach-grouping.ts +157 -0
- package/src/self-implement/train-scenario-layers.ts +133 -0
- package/src/self-implement/uncommitted-work.ts +2 -0
- package/src/session/pending-input.ts +81 -11
- package/src/session/session-start.ts +224 -0
- package/src/session-runtime/index.ts +7 -1
- package/src/session-runtime/parallel-dispatch.ts +22 -5
- package/src/skills/tools/dev-harness.ts +6 -4
- package/src/skills/tools/ops-ledger.ts +707 -0
- package/src/skills/tools/persistent-grounding.ts +47 -7
- package/src/skills/tools/shell.ts +117 -1
- package/src/status/bar.ts +32 -2
- package/src/status/status-provider-info.ts +58 -0
- package/src/steward/resync-tick.ts +114 -23
- package/src/steward/ta-repair-event-collect.ts +158 -0
- package/src/task-agent/card-evidence.ts +25 -1
- package/src/task-agent/green-sweep.ts +8 -3
- package/src/task-agent/judge.ts +76 -0
- package/src/task-agent/land-queue.ts +79 -0
- package/src/task-agent/live-moves.ts +30 -9
- package/src/task-agent/postland-card.ts +5 -0
- package/src/task-agent/prelaunch-already-done.ts +98 -0
- package/src/task-agent/real-launch-guard.ts +37 -0
- package/src/task-agent/rejudge-on-head.ts +93 -13
- package/src/task-agent/remote-rejudge-bind.ts +62 -13
- package/src/task-agent/repair-cycle.ts +58 -7
- package/src/task-agent/repair-worker.ts +7 -0
- package/src/task-agent/run-identity.ts +200 -0
- package/src/task-agent/shadow.ts +50 -3
- package/src/task-agent/task-hand.ts +158 -5
- package/src/task-agent/train-landing.ts +77 -0
- package/src/task-agent/work-order.ts +104 -0
- package/src/task-orchestrator/surfaces/kubectl-transient-retry.ts +51 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +138 -22
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
- package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
- package/src/task-orchestrator/surfaces/pod-install-slots.ts +122 -15
- package/src/task-orchestrator/surfaces/pod-lease.ts +20 -6
- package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
- package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +103 -0
- package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
- package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +63 -0
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
- package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
- package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
- package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +208 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +237 -46
- package/src/telegram.ts +2 -4
- package/src/terminal/session-registry.ts +6 -0
- package/src/thinking-line.ts +12 -3
- package/src/tool-runtime/index.ts +4 -0
- package/src/tool-runtime/ops-ledger-runtimes.ts +84 -0
- package/src/tool-runtime/ref-consult-runtime.ts +17 -2
- package/src/tool-runtime/run-shell-runtime.ts +4 -1
- package/src/tool-runtime/self-cognition-runtimes.ts +5 -1
- package/src/tui/input/pickers.ts +732 -0
- package/src/tui/slash/mission.ts +492 -0
- package/src/tui/slash/term.ts +877 -0
- package/src/tui-client/dashboard-session.ts +9 -0
- package/src/tui.ts +53 -0
- package/src/user-config/gemini-server-tools.ts +9 -0
- package/src/user-config.ts +106 -21
- package/src/util/spawn-sync-output.ts +7 -0
- package/src/ux-sim/fake-bin.ts +154 -0
- package/src/ux-sim/fake-clock.ts +36 -0
- package/src/ux-sim/fake-llm.ts +29 -0
- package/src/ux-sim/headless-tui.ts +72 -0
- package/src/ux-sim/in-process-cli.ts +176 -0
- package/src/ux-sim/temp-git-remote.ts +82 -0
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/recipes/vlog.ts +25 -7
- package/apps/pwa/out/_next/static/chunks/1027.a0f04663d24c2779.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +0 -36
- package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1454-29d1d773d5996a49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +0 -27
- package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +0 -1
- package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +0 -32
- package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3259-86f3be56e43eaf6a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +0 -287
- package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4084.15ecaf4240bd9e77.js +0 -286
- package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +0 -8
- package/apps/pwa/out/_next/static/chunks/4565-67e4c620597965c8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +0 -104
- package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +0 -149
- package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +0 -1
- package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/599-56f2c0a5cc4a7295.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +0 -23
- package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +0 -77
- package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +0 -64
- package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +0 -2
- package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +0 -62
- package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8085-1e5fce59500a2cc2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +0 -226
- package/apps/pwa/out/_next/static/chunks/83a80514-b897b64df43ce108.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +0 -93
- package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +0 -24
- package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +0 -115
- package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +0 -41
- package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +0 -74
- package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +0 -94
- package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/973cbf1b.3bbcf2b41548eca7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-24453f6a302816b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-6c131d30bb1cf871.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-dc0772b11861af51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-66ad46ed0279feb9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-256ffd365d32e100.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e0de78ae7b99f01c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-4c741eb760f2f77c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-e9ba98f5f1440a21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-dafc901bb1b72b5f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2f6f303fa114ec24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-1634081c5272006c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live-run/page-bb1f05cd51c38944.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-646b50f63b6fe732.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-f736324afa2117c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6f131b51193a36f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-435f5e2faf02bc01.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-497e0eedf20e7890.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a8d28fdf995e16ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8966452228753c5e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-66a67eb19ebd976b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-c71267e7681da982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-a21d1e1797172692.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-781cfc5114e097da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-478157214db6a023.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-86141f12cf090b7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-7256c73bb1c36751.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-979d318a534e92da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-21050928a697ed7a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-601fb77340e63c9a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-11bf9e5725a72c22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +0 -1
- package/src/dashboard/bench-slash-runtime.ts +0 -40
- package/src/dashboard/input/search-modal-router.ts +0 -9
- package/src/dashboard/modals/pane-key-router.ts +0 -27
- package/src/dashboard/view-slash-runtime.ts +0 -48
- /package/apps/pwa/out/_next/static/{y1ltt7oCZxVpC6zVPhZ2O → LSXfY0u9QtfDbejY0Ukf_}/_ssgManifest.js +0 -0
package/src/llm.ts
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
// Auto-routes based on model name prefix, or picks the first available provider.
|
|
4
4
|
|
|
5
5
|
import { createHash } from 'node:crypto';
|
|
6
|
+
import { testFakeLlmEnabled, testFakeLlmProvider } from './ux-sim/fake-llm.js';
|
|
7
|
+
import { realpathSync } from 'node:fs';
|
|
8
|
+
import { resolve } from 'node:path';
|
|
9
|
+
import { globalAnchorPath } from './prompt-library/universal-preamble.js';
|
|
6
10
|
import type { LLMUsage } from './prompt-cache/types.js';
|
|
7
11
|
import { applyOpenRouterCacheControl, openRouterPromptCacheFamily } from './prompt-cache/openrouter.js';
|
|
8
12
|
import { detectLocale, type Locale } from './expression/locale.js';
|
|
@@ -22,13 +26,17 @@ import {
|
|
|
22
26
|
import { debug, redactSecrets, redactSecretText } from './debug/log.js';
|
|
23
27
|
import { llmUsageCostFields } from './budget/llm-cost.js';
|
|
24
28
|
import { accumulateByokUsage } from './llm/openrouter-byok-cost.js';
|
|
29
|
+
import { ACTION_PHASE_OPS_TOOLS, isSteeredShellRejection, REPAIR_PHASE_READ_ONLY_OPS_TOOLS } from './llm/tool-loop-steered-rejection.js';
|
|
25
30
|
import { ToolCallTiming } from './chat/tool-call-timing.js';
|
|
26
31
|
import {
|
|
27
32
|
dispatchWithParallelSafety,
|
|
28
33
|
isSafeForParallel,
|
|
29
34
|
} from './session-runtime/parallel-dispatch.js';
|
|
35
|
+
import { createRetryDisplayGate, type RetryDisplayStep } from './llm-stream-retry-display.js';
|
|
30
36
|
import {
|
|
31
37
|
DoomLoopTracker,
|
|
38
|
+
backoffMs,
|
|
39
|
+
classifyError,
|
|
32
40
|
decideRetry,
|
|
33
41
|
fingerprintError,
|
|
34
42
|
decideProviderFallback,
|
|
@@ -336,6 +344,8 @@ export type ToolChoice = 'auto' | 'required' | 'none' | { name: string };
|
|
|
336
344
|
|
|
337
345
|
export interface LLMOpts {
|
|
338
346
|
model?: string;
|
|
347
|
+
/** Reports the provider and model actually attempted, including fallbacks. */
|
|
348
|
+
onResolvedProvider?(provider: string, model: string): void;
|
|
339
349
|
temperature?: number;
|
|
340
350
|
maxTokens?: number;
|
|
341
351
|
signal?: AbortSignal;
|
|
@@ -388,6 +398,14 @@ export interface LLMOpts {
|
|
|
388
398
|
* e.g. driving a headless coding-agent terminal (SpawnCodingAgentHeadless
|
|
389
399
|
* + PtyShell Snapshot/Send loop). Absent ⇒ no extension (default). */
|
|
390
400
|
budgetGrant?: { tools: readonly string[]; perCall: number; ceiling: number };
|
|
401
|
+
/** TUI-GOAL-LOOP-FRICTION(#46·#63) — «종결 신호» 도구 이름(예: goal loop 의 `update_goal`).
|
|
402
|
+
* ① 도구 예산·탐색 예산·후속 단계의 거부를 받지 않는다 — 완료 신호를 «TOOL CALL REJECTED» 로
|
|
403
|
+
* 막으면 모델이 둘째 답 ⊕ 사과를 쓴다(#46).
|
|
404
|
+
* ② 한 턴의 호출이 «종결 신호뿐»이고 그 턴(또는 이전 도구 라운드)에 답 텍스트가 있으면, 신호를
|
|
405
|
+
* 디스패치한 뒤 다음 모델 턴을 열지 않고 그 답으로 끝낸다 — 빈 턴 반복 → `[NO FINAL SYNTHESIS]`(#63) 차단.
|
|
406
|
+
* ③ 종결 신호를 받은 뒤의 빈 턴 포기에도 이미 쓴 답이 있으면 `[NO FINAL SYNTHESIS]` 를 붙이지 않는다.
|
|
407
|
+
* 비우면(기본) 종전 동작 그대로. */
|
|
408
|
+
terminalToolNames?: readonly string[];
|
|
391
409
|
/** Prompt-caching toggle. Honored by Anthropic (attaches
|
|
392
410
|
* cache_control markers on system + tools + 2nd-to-last history
|
|
393
411
|
* message) and OpenAI (passes stream_options.include_usage so
|
|
@@ -4228,17 +4246,11 @@ function permitsAutomaticProviderFallback(opts: LLMOpts & { provider?: LLMProvid
|
|
|
4228
4246
|
}
|
|
4229
4247
|
}
|
|
4230
4248
|
|
|
4231
|
-
function
|
|
4249
|
+
function configuredFallbackChainSteps(): readonly string[] {
|
|
4232
4250
|
try {
|
|
4233
4251
|
const { getUserConfig } = require('./user-config.js') as typeof import('./user-config.js');
|
|
4234
4252
|
const { normalizeFallbackChain } = require('./oauth/fallback-chain.js') as typeof import('./oauth/fallback-chain.js');
|
|
4235
|
-
|
|
4236
|
-
const out: LLMProvider[] = [];
|
|
4237
|
-
for (const name of providerNamesFromFallbackChain(chain)) {
|
|
4238
|
-
const provider = PROVIDERS[name];
|
|
4239
|
-
if (provider) out.push(provider);
|
|
4240
|
-
}
|
|
4241
|
-
return out;
|
|
4253
|
+
return normalizeFallbackChain(getUserConfig().llm.fallbackChain).chain;
|
|
4242
4254
|
} catch (err) {
|
|
4243
4255
|
// ⛔ 조용히 삼키면 「설정을 못 읽었다」가 「폴백 후보가 없다」로 «둔갑»한다 —
|
|
4244
4256
|
// 호출자는 그것을 `fallback candidates exhausted` 로 보고 사람에게 그렇게 말한다.
|
|
@@ -4250,35 +4262,116 @@ function configuredFallbackProviders(): LLMProvider[] {
|
|
|
4250
4262
|
}
|
|
4251
4263
|
}
|
|
4252
4264
|
|
|
4253
|
-
|
|
4265
|
+
/** 체인 칸 하나가 후보에서 «왜» 빠졌나. ⭐ `exhausted` 를 설명 가능하게 하려고 남긴다(TUI-STREAM-RETRY).
|
|
4266
|
+
* `folded-into-earlier-step` = `codex-credits` 처럼 앞 칸과 같은 provider 로 접힌 칸 — 접는 동작 자체는
|
|
4267
|
+
* `providerNamesFromFallbackChain` 소유이고 여기선 «기록만» 한다. */
|
|
4268
|
+
export type FallbackCandidateSkipReason =
|
|
4269
|
+
| 'already-attempted'
|
|
4270
|
+
| 'not-available'
|
|
4271
|
+
| 'folded-into-earlier-step'
|
|
4272
|
+
| 'unknown-step';
|
|
4273
|
+
|
|
4274
|
+
export interface FallbackCandidateSkip {
|
|
4275
|
+
step: string;
|
|
4276
|
+
provider?: string;
|
|
4277
|
+
reason: FallbackCandidateSkipReason;
|
|
4278
|
+
}
|
|
4279
|
+
|
|
4280
|
+
function explainFallbackCandidates(
|
|
4254
4281
|
attemptedProviders: ReadonlySet<string>,
|
|
4255
4282
|
opts: LLMOpts & { provider?: LLMProvider },
|
|
4256
|
-
|
|
4283
|
+
chain: readonly string[] = configuredFallbackChainSteps(),
|
|
4284
|
+
): { candidates: string[]; skipped: FallbackCandidateSkip[] } {
|
|
4257
4285
|
// Priority:
|
|
4258
4286
|
// 1. per-call opts.provider → no fallback (caller pinned the route)
|
|
4259
4287
|
// 2. llm.provider === 'auto' → ⭐ 2026-09-24 결정: `llm.fallbackChain` 을 «먼저»(codex-rotate→openai-codex · grok),
|
|
4260
4288
|
// 그다음 체인이 «다루지 않는» 자동 후보(anthropic·gemini·local). 체인이 grok 을 뺐으면 grok 으로 새지 않는다.
|
|
4261
4289
|
// 종전엔 auto 가 체인을 통째로 무시하고 AUTOMATIC_PROVIDER_ORDER 만 걸었다.
|
|
4262
4290
|
// 3. otherwise → configured llm.fallbackChain (read from config; never baked here)
|
|
4263
|
-
|
|
4291
|
+
const candidates: string[] = [];
|
|
4292
|
+
const skipped: FallbackCandidateSkip[] = [];
|
|
4293
|
+
if (opts.provider) return { candidates, skipped };
|
|
4294
|
+
const seen = new Set<string>();
|
|
4295
|
+
const consider = (step: string, provider: LLMProvider) => {
|
|
4296
|
+
if (attemptedProviders.has(provider.name)) skipped.push({ step, provider: provider.name, reason: 'already-attempted' });
|
|
4297
|
+
else if (!provider.available()) skipped.push({ step, provider: provider.name, reason: 'not-available' });
|
|
4298
|
+
else candidates.push(provider.name);
|
|
4299
|
+
};
|
|
4300
|
+
for (const step of chain) {
|
|
4301
|
+
const name = providerNamesFromFallbackChain([step])[0];
|
|
4302
|
+
const provider = name ? PROVIDERS[name] : undefined;
|
|
4303
|
+
if (!name || !provider) {
|
|
4304
|
+
skipped.push({ step, ...(name ? { provider: name } : {}), reason: 'unknown-step' });
|
|
4305
|
+
continue;
|
|
4306
|
+
}
|
|
4307
|
+
if (seen.has(name)) {
|
|
4308
|
+
skipped.push({ step, provider: name, reason: 'folded-into-earlier-step' });
|
|
4309
|
+
continue;
|
|
4310
|
+
}
|
|
4311
|
+
seen.add(name);
|
|
4312
|
+
consider(step, provider);
|
|
4313
|
+
}
|
|
4264
4314
|
if (permitsAutomaticProviderFallback(opts)) {
|
|
4265
4315
|
const chainGoverned = new Set(providerNamesFromFallbackChain(['codex-rotate', 'grok']));
|
|
4266
|
-
const
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
return
|
|
4280
|
-
|
|
4281
|
-
|
|
4316
|
+
for (const candidate of automaticProviderCandidates()) {
|
|
4317
|
+
if (chainGoverned.has(candidate.name) || seen.has(candidate.name)) continue;
|
|
4318
|
+
seen.add(candidate.name);
|
|
4319
|
+
consider(`auto:${candidate.name}`, candidate);
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
return { candidates, skipped };
|
|
4323
|
+
}
|
|
4324
|
+
|
|
4325
|
+
function remainingFallbackProviderNames(
|
|
4326
|
+
attemptedProviders: ReadonlySet<string>,
|
|
4327
|
+
opts: LLMOpts & { provider?: LLMProvider },
|
|
4328
|
+
): string[] {
|
|
4329
|
+
return explainFallbackCandidates(attemptedProviders, opts).candidates;
|
|
4330
|
+
}
|
|
4331
|
+
|
|
4332
|
+
/** 폴백 후보를 고르는 «그 순간»에 빠진 칸과 이유를 남긴다 — `provider-fallback-exhausted` 가
|
|
4333
|
+
* 「무엇을 봤고 왜 아무도 안 남았나」를 혼자 말하지 못하던 결손(2026-10-14 TUI 실측) 수리. */
|
|
4334
|
+
function explainAndLogFallbackCandidates(
|
|
4335
|
+
attemptedProviders: ReadonlySet<string>,
|
|
4336
|
+
opts: LLMOpts & { provider?: LLMProvider },
|
|
4337
|
+
context: { failedProvider: string; turn?: number },
|
|
4338
|
+
chain?: readonly string[],
|
|
4339
|
+
): string[] {
|
|
4340
|
+
const { candidates, skipped } = explainFallbackCandidates(attemptedProviders, opts, chain);
|
|
4341
|
+
debug.log('llm.router', 'fallback-candidates', {
|
|
4342
|
+
...(context.turn !== undefined ? { turn: context.turn } : {}),
|
|
4343
|
+
failedProvider: context.failedProvider,
|
|
4344
|
+
candidates,
|
|
4345
|
+
skipped,
|
|
4346
|
+
});
|
|
4347
|
+
return candidates;
|
|
4348
|
+
}
|
|
4349
|
+
|
|
4350
|
+
/** 스트림 중 끊김 재시도 상한 — codex `DEFAULT_STREAM_MAX_RETRIES`(5) 와 같은 값. */
|
|
4351
|
+
const STREAM_DISCONNECT_MAX_RETRIES = 5;
|
|
4352
|
+
let streamDisconnectRetryDelayMs: (attempt: number) => number = backoffMs;
|
|
4353
|
+
|
|
4354
|
+
/** @internal 시험 seam — 재시도 대기(기본 `backoffMs`)를 바꾼다. `undefined` 면 원복. */
|
|
4355
|
+
export function _setStreamDisconnectRetryDelayForTest(fn: ((attempt: number) => number) | undefined): void {
|
|
4356
|
+
streamDisconnectRetryDelayMs = fn ?? backoffMs;
|
|
4357
|
+
}
|
|
4358
|
+
|
|
4359
|
+
/** 흐르던 스트림의 끊김을 같은 공급자로 다시 걸어도 되나.
|
|
4360
|
+
* ⛔ 이 스트림에서 tool_call 을 받았거나 image 를 이미 내보냈으면 아니다 — 그 조각을 다시 보내면
|
|
4361
|
+
* 부작용·화면이 두 번 생길 수 있다(실행 전이라도 «추측해서» 버리지 않는다). */
|
|
4362
|
+
function isStreamDisconnectRetryable(err: unknown, pendingCallCount: number, emittedImage: boolean): boolean {
|
|
4363
|
+
if (pendingCallCount > 0 || emittedImage) return false;
|
|
4364
|
+
if (err instanceof OverloadFailoverError) return false;
|
|
4365
|
+
return classifyError(err) === 'network-transient';
|
|
4366
|
+
}
|
|
4367
|
+
|
|
4368
|
+
function sleepUnlessAborted(ms: number, signal?: AbortSignal): Promise<void> {
|
|
4369
|
+
if (ms <= 0 || signal?.aborted) return Promise.resolve();
|
|
4370
|
+
return new Promise((resolve) => {
|
|
4371
|
+
const onAbort = () => { clearTimeout(timer); resolve(); };
|
|
4372
|
+
const timer = setTimeout(() => { signal?.removeEventListener('abort', onAbort); resolve(); }, ms);
|
|
4373
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
4374
|
+
});
|
|
4282
4375
|
}
|
|
4283
4376
|
|
|
4284
4377
|
/** @internal 시험 seam — auto 폴백 순서(체인 먼저 · 체인이 안 다루는 자동 후보 뒤)를 결정적으로 누른다. */
|
|
@@ -4286,6 +4379,14 @@ export function _remainingFallbackProviderNamesForTest(attempted: readonly strin
|
|
|
4286
4379
|
return remainingFallbackProviderNames(new Set(attempted), {});
|
|
4287
4380
|
}
|
|
4288
4381
|
|
|
4382
|
+
/** @internal 시험 seam — 체인 칸별 skip 이유 ⊕ `llm.router fallback-candidates` 관측. */
|
|
4383
|
+
export function _explainAndLogFallbackCandidatesForTest(
|
|
4384
|
+
attempted: readonly string[],
|
|
4385
|
+
chain: readonly string[],
|
|
4386
|
+
): string[] {
|
|
4387
|
+
return explainAndLogFallbackCandidates(new Set(attempted), {}, { failedProvider: attempted[0] ?? 'none' }, chain);
|
|
4388
|
+
}
|
|
4389
|
+
|
|
4289
4390
|
function terminalFallbackVerdict(
|
|
4290
4391
|
verdict: ReturnType<typeof decideProviderFallback>,
|
|
4291
4392
|
attempts: readonly ProviderFallbackAttempt[],
|
|
@@ -4388,6 +4489,9 @@ export function getProvider(model?: string): LLMProvider {
|
|
|
4388
4489
|
}
|
|
4389
4490
|
if (PROVIDERS.openrouter!.available()) return PROVIDERS.openrouter!;
|
|
4390
4491
|
|
|
4492
|
+
// Gate Pod may intentionally have no credentials. The explicit test env
|
|
4493
|
+
// supplies a deterministic answer only after every real auto candidate failed.
|
|
4494
|
+
if (testFakeLlmEnabled()) return testFakeLlmProvider;
|
|
4391
4495
|
throw new NoLlmProviderAvailableError();
|
|
4392
4496
|
}
|
|
4393
4497
|
|
|
@@ -4725,7 +4829,7 @@ export async function streamLLM(
|
|
|
4725
4829
|
debug.log('llm', 'outcome', { provider: activeProvider.name, status: 'error', kind: 'streamLLM', durationMs: Date.now() - started });
|
|
4726
4830
|
throw err;
|
|
4727
4831
|
}
|
|
4728
|
-
const remaining =
|
|
4832
|
+
const remaining = explainAndLogFallbackCandidates(attemptedProviders, opts, { failedProvider: activeProvider.name });
|
|
4729
4833
|
const verdict = decideProviderFallback({
|
|
4730
4834
|
err,
|
|
4731
4835
|
failedProvider: activeProvider.name,
|
|
@@ -4889,6 +4993,11 @@ export interface StreamWithToolsHandlers {
|
|
|
4889
4993
|
turnIndex?: number;
|
|
4890
4994
|
},
|
|
4891
4995
|
): Promise<unknown>;
|
|
4996
|
+
/** Optional: the final answer was enriched with a runtime verification
|
|
4997
|
+
* supplement (변경 파일·검증 명령·검증 최신성·루프 마감 상태). Fires just
|
|
4998
|
+
* before the `onText('', enriched)` re-emit so presentation hosts can
|
|
4999
|
+
* keep the user answer to `answer` and send `supplement` to logs. */
|
|
5000
|
+
onFinalAnswerSupplement?(info: { answer: string; supplement: string; finalText: string }): void;
|
|
4892
5001
|
/** Optional: notify when a tool_call is about to fire (for log line,
|
|
4893
5002
|
* HUD segment, etc). */
|
|
4894
5003
|
onToolCall?(call: { id: string; name: string; args: Record<string, unknown> }): void;
|
|
@@ -5674,10 +5783,13 @@ const TOOL_LOOP_PHASE_DIRECTIVES: Record<ToolLoopFollowupPhase, (autoNarrowedRea
|
|
|
5674
5783
|
'repair-action': () =>
|
|
5675
5784
|
'REPAIR ACTION REQUIRED — execution has already failed or a debugging repair step is armed. '
|
|
5676
5785
|
+ 'Stop gathering more files and move to Edit/Write/RunShell/Bash or a narrow code-intel followup (Read/Lsp/AstGrep/Grep content/count), '
|
|
5786
|
+
+ 'ops ledger/delegate tools (MsgList/MsgPost/MsgAck/Checklist*/AgentOutput) still run, '
|
|
5677
5787
|
+ 'or answer in plain text if no code change is needed (e.g. a read-only investigation whose finding is the deliverable).',
|
|
5678
5788
|
'verify-action': () =>
|
|
5679
5789
|
'VERIFY ACTION REQUIRED — edits already happened. '
|
|
5680
|
-
+ 'Stop gathering more files and move to RunShell/Bash/Agent or a narrow verification followup (Read/Lsp/Grep content/count),
|
|
5790
|
+
+ 'Stop gathering more files and move to RunShell/Bash/Agent or a narrow verification followup (Read/Lsp/Grep content/count), '
|
|
5791
|
+
+ 'ops ledger/delegate tools (MsgList/MsgPost/MsgAck/Checklist*/AgentOutput) still run, '
|
|
5792
|
+
+ 'or answer in plain text if verification is not needed.',
|
|
5681
5793
|
};
|
|
5682
5794
|
|
|
5683
5795
|
const TOOL_LOOP_PHASE_REJECTION_EVENTS: Record<ToolLoopFollowupPhase, string> = {
|
|
@@ -7719,6 +7831,7 @@ const EXPLORATORY_TOOLS = new Set([
|
|
|
7719
7831
|
]);
|
|
7720
7832
|
|
|
7721
7833
|
const INSPECT_ACTION_TOOLS = new Set([
|
|
7834
|
+
...ACTION_PHASE_OPS_TOOLS,
|
|
7722
7835
|
'Edit',
|
|
7723
7836
|
'Write',
|
|
7724
7837
|
'Bash',
|
|
@@ -7733,6 +7846,7 @@ const INSPECT_ACTION_TOOLS = new Set([
|
|
|
7733
7846
|
]);
|
|
7734
7847
|
|
|
7735
7848
|
const VERIFY_ACTION_TOOLS = new Set([
|
|
7849
|
+
...ACTION_PHASE_OPS_TOOLS,
|
|
7736
7850
|
'Edit',
|
|
7737
7851
|
'Write',
|
|
7738
7852
|
'RunShell',
|
|
@@ -7748,6 +7862,7 @@ const VERIFY_ACTION_TOOLS = new Set([
|
|
|
7748
7862
|
]);
|
|
7749
7863
|
|
|
7750
7864
|
const EXECUTION_ACTION_TOOLS = new Set([
|
|
7865
|
+
...ACTION_PHASE_OPS_TOOLS,
|
|
7751
7866
|
'RunShell',
|
|
7752
7867
|
'Bash',
|
|
7753
7868
|
'Agent',
|
|
@@ -7761,6 +7876,8 @@ const EXECUTION_ACTION_TOOLS = new Set([
|
|
|
7761
7876
|
]);
|
|
7762
7877
|
|
|
7763
7878
|
const REPAIR_ACTION_TOOLS = new Set([
|
|
7879
|
+
...REPAIR_PHASE_READ_ONLY_OPS_TOOLS,
|
|
7880
|
+
...ACTION_PHASE_OPS_TOOLS,
|
|
7764
7881
|
'Edit',
|
|
7765
7882
|
'Write',
|
|
7766
7883
|
'RunShell',
|
|
@@ -8048,6 +8165,8 @@ export function billingRouteForProvider(provider: string | undefined, model: str
|
|
|
8048
8165
|
if (name === 'local') return 'local';
|
|
8049
8166
|
try {
|
|
8050
8167
|
const auth = authKindForProvider(name, model);
|
|
8168
|
+
// CREDIT-BILLING-LABEL(10-14) — codex 회전이 크레딧 소진을 정한 호출은 구독이 아니라 크레딧이다.
|
|
8169
|
+
if (auth === 'oauth' && name === 'openai-codex' && codexCreditSpendReason()) return 'credit';
|
|
8051
8170
|
return auth === 'oauth' ? 'subscription' : auth === 'local' ? 'local' : auth === 'apikey' ? 'api' : 'unknown';
|
|
8052
8171
|
} catch {
|
|
8053
8172
|
return 'unknown';
|
|
@@ -8087,14 +8206,19 @@ export async function streamLLMWithTools(
|
|
|
8087
8206
|
const initial = finalizeStreamingProviderModel(provider, opts.model ?? provider.defaultModel);
|
|
8088
8207
|
let activeProvider = initial.provider;
|
|
8089
8208
|
let activeModel = initial.model;
|
|
8209
|
+
opts.onResolvedProvider?.(activeProvider.name, activeModel);
|
|
8090
8210
|
const attemptedProviders = new Set<string>([activeProvider.name]);
|
|
8091
8211
|
let blockedProviders: ProviderFallbackAttempt[] = [];
|
|
8092
8212
|
const effectiveModel = activeModel;
|
|
8093
8213
|
const modelFamily = getModelFamily(effectiveModel);
|
|
8214
|
+
// TUI-GPT6-GUARD-PARITY — codex «모델 행동» 가드 켬 여부(단일 원천 = models/prompts.ts
|
|
8215
|
+
// usesCodexBehaviorGuards). gpt-6 세대도 true. 넓힌 자리·안 넓힌 자리는 그 함수 주석이 정본.
|
|
8216
|
+
const codexBehaviorGuards = usesCodexBehaviorGuards(effectiveModel);
|
|
8094
8217
|
debug.log('llm.router', 'streamLLMWithTools', {
|
|
8095
8218
|
provider: provider.name,
|
|
8096
8219
|
model: effectiveModel,
|
|
8097
8220
|
modelFamily,
|
|
8221
|
+
codexBehaviorGuards,
|
|
8098
8222
|
messageCount: messages.length,
|
|
8099
8223
|
messageRoles: summarizeRoles(messages),
|
|
8100
8224
|
tools: opts.tools?.map(t => t.name),
|
|
@@ -8270,6 +8394,12 @@ export async function streamLLMWithTools(
|
|
|
8270
8394
|
};
|
|
8271
8395
|
let fullText = '';
|
|
8272
8396
|
let sawToolRound = false;
|
|
8397
|
+
// TUI-GOAL-LOOP-FRICTION — 종결 신호 도구(LLMOpts.terminalToolNames). 비면 아래 분기는 전부 꺼진다.
|
|
8398
|
+
const terminalToolNames: ReadonlySet<string> = new Set(opts.terminalToolNames ?? []);
|
|
8399
|
+
/** 이 스트림에서 종결 신호를 한 번이라도 디스패치했나. */
|
|
8400
|
+
let terminalSignalDispatched = false;
|
|
8401
|
+
/** 도구 라운드에 실린 마지막 «비지 않은» 답 텍스트(종결 신호 턴 마감·빈 턴 포기에서 쓴다). */
|
|
8402
|
+
let lastToolRoundText = '';
|
|
8273
8403
|
const agentBatchTickIntervalMs = opts.agentBatchTickIntervalMs ?? BATCH_TICK_INTERVAL_MS;
|
|
8274
8404
|
|
|
8275
8405
|
// Empty-turn guard: smaller models (gpt-5.4-mini, haiku) sometimes
|
|
@@ -8333,6 +8463,8 @@ export async function streamLLMWithTools(
|
|
|
8333
8463
|
// instructing the model to reuse prior tool_results or write its
|
|
8334
8464
|
// final answer. Codex-family-only: Claude path is unaffected.
|
|
8335
8465
|
const seenToolCallSignatures = new Map<string, number>();
|
|
8466
|
+
// TUI-INITIATIVE-S ② — 같은 도구·같은 인자가 «같은 오류»로 끝난 횟수(성공하면 지운다). 아래 L-2 차단을 gpt 계열·비탐색 도구로 넓힌다.
|
|
8467
|
+
const erroredToolCallSignatures = new Map<string, { error: string; count: number }>();
|
|
8336
8468
|
// W3-A + extension (2026-05-03) — Broad-spot dedup map. MUST live
|
|
8337
8469
|
// outside the turn loop so the counter persists across turns. (Bug
|
|
8338
8470
|
// 2026-05-03 PM: original placement inside turn loop reset the map
|
|
@@ -8588,6 +8720,32 @@ export async function streamLLMWithTools(
|
|
|
8588
8720
|
});
|
|
8589
8721
|
let evCount = 0;
|
|
8590
8722
|
let lastEvType = 'none';
|
|
8723
|
+
// ⭐ TUI-STREAM-RETRY(2026-10-14 실측) — 200 OK 로 흐르던 스트림이 소켓 끊김으로 죽으면 같은 공급자로
|
|
8724
|
+
// 다시 건다(codex `stream_max_retries` 동형). 이 턴에서 받은 tool_call·image 가 있으면 재시도하지 않는다.
|
|
8725
|
+
let streamDisconnectRetries = 0;
|
|
8726
|
+
let streamEmittedImage = false;
|
|
8727
|
+
// 끊긴 조각을 이력(turnText·fullText)에서 «조용히» 되감는다 — 화면엔 지우라고 알리지 않는다
|
|
8728
|
+
// (TUI 의 빈 델타는 «커밋»이다). 이미 보인 글과 겹치는 재시도 본문은 `retryDisplay` 가 막는다.
|
|
8729
|
+
const retryDisplay = createRetryDisplayGate();
|
|
8730
|
+
const emitRetryDisplayStep = (step: RetryDisplayStep) => {
|
|
8731
|
+
if (step.kind === 'emit') {
|
|
8732
|
+
if (step.delta) handlers.onText(step.delta, fullText);
|
|
8733
|
+
} else if (step.kind === 'diverged') {
|
|
8734
|
+
debug.log('llm.retry', 'stream-retry-display-diverged', { provider: activeProvider.name, turn, textChars: step.text.length }, { level: 'warn' });
|
|
8735
|
+
handlers.onText('', '');
|
|
8736
|
+
if (step.text) handlers.onText(step.text, fullText);
|
|
8737
|
+
}
|
|
8738
|
+
};
|
|
8739
|
+
const rewindDisconnectedStream = () => {
|
|
8740
|
+
if (turnText.length > 0) {
|
|
8741
|
+
fullText = fullText.slice(0, fullText.length - turnText.length);
|
|
8742
|
+
turnText = '';
|
|
8743
|
+
}
|
|
8744
|
+
retryDisplay.arm();
|
|
8745
|
+
turnReasoningDetails = undefined;
|
|
8746
|
+
evCount = 0;
|
|
8747
|
+
lastEvType = 'none';
|
|
8748
|
+
};
|
|
8591
8749
|
// ⚠️ idle watchdog(2026-07-17) — codex SSE 가 완료 신호 없이 hang 하는 간헐 케이스 방어. 각
|
|
8592
8750
|
// 이벤트 대기를 idle timeout 과 race — STREAM_IDLE_TIMEOUT_MS 무이벤트면 스트림 정리·탈출(받은
|
|
8593
8751
|
// 텍스트로 진행). 35분 무한 hang → 자동 복구. 원인 규명은 consume-end 부재/idle-timeout 로그가.
|
|
@@ -8600,6 +8758,7 @@ export async function streamLLMWithTools(
|
|
|
8600
8758
|
const finalized = finalizeStreamingProviderModel(activeProvider, activeModel);
|
|
8601
8759
|
activeProvider = finalized.provider;
|
|
8602
8760
|
activeModel = finalized.model;
|
|
8761
|
+
opts.onResolvedProvider?.(activeProvider.name, activeModel);
|
|
8603
8762
|
turnOpts = { ...turnOpts, model: activeModel };
|
|
8604
8763
|
streamIter = activeProvider.streamChat!(history, turnOpts)[Symbol.asyncIterator]();
|
|
8605
8764
|
}
|
|
@@ -8624,16 +8783,49 @@ export async function streamLLMWithTools(
|
|
|
8624
8783
|
activeProvider = finalized.provider;
|
|
8625
8784
|
activeModel = finalized.model;
|
|
8626
8785
|
attemptedProviders.add(activeProvider.name);
|
|
8786
|
+
streamDisconnectRetries = 0;
|
|
8627
8787
|
turnOpts = buildTurnOpts();
|
|
8628
8788
|
streamIter = undefined;
|
|
8629
8789
|
continue;
|
|
8630
8790
|
}
|
|
8631
8791
|
}
|
|
8792
|
+
if (evCount > 0 && isStreamDisconnectRetryable(err, pendingCalls.length, streamEmittedImage) && !opts.signal?.aborted) {
|
|
8793
|
+
const retryData = {
|
|
8794
|
+
provider: activeProvider.name,
|
|
8795
|
+
model: activeModel,
|
|
8796
|
+
turn,
|
|
8797
|
+
scope: 'stream-disconnect',
|
|
8798
|
+
category: 'network-transient',
|
|
8799
|
+
reason: sanitizeProviderFailureReason(err instanceof Error ? err.message : String(err)),
|
|
8800
|
+
evCount,
|
|
8801
|
+
lastEvType,
|
|
8802
|
+
rewoundTextChars: turnText.length,
|
|
8803
|
+
maxRetries: STREAM_DISCONNECT_MAX_RETRIES,
|
|
8804
|
+
};
|
|
8805
|
+
if (streamDisconnectRetries < STREAM_DISCONNECT_MAX_RETRIES) {
|
|
8806
|
+
const delayMs = streamDisconnectRetryDelayMs(streamDisconnectRetries);
|
|
8807
|
+
streamDisconnectRetries++;
|
|
8808
|
+
debug.log('llm.retry', 'retry', { ...retryData, attempt: streamDisconnectRetries, delayMs }, { level: 'warn' });
|
|
8809
|
+
rewindDisconnectedStream();
|
|
8810
|
+
await sleepUnlessAborted(delayMs, opts.signal);
|
|
8811
|
+
if (opts.signal?.aborted) throw err;
|
|
8812
|
+
streamIter = undefined;
|
|
8813
|
+
continue;
|
|
8814
|
+
}
|
|
8815
|
+
debug.log('llm.retry', 'max-attempts-exhausted', { ...retryData, attempt: streamDisconnectRetries }, { level: 'warn' });
|
|
8816
|
+
// 되감았으니 이 턴은 «출력 전» 상태다 — 아래 폴백이 다음 공급자로 깨끗이 넘어갈 수 있다.
|
|
8817
|
+
rewindDisconnectedStream();
|
|
8818
|
+
}
|
|
8632
8819
|
// 명시 provider 선택만 폴백 대상이 아니다 — `streamLLM` 과 같은 계약으로
|
|
8633
8820
|
// «원본 오류»를 그대로 올린다. 모델만 전달된 호출은 다음 provider의 기본 모델로 재시도한다.
|
|
8634
8821
|
if (opts.provider) throw err;
|
|
8822
|
+
if (evCount > 0) {
|
|
8823
|
+
debug.log('llm.router', 'fallback-candidates', {
|
|
8824
|
+
turn, failedProvider: activeProvider.name, candidates: [], skipped: [], outputEmitted: true, evCount, pendingCalls: pendingCalls.length,
|
|
8825
|
+
});
|
|
8826
|
+
}
|
|
8635
8827
|
const remaining = evCount === 0
|
|
8636
|
-
?
|
|
8828
|
+
? explainAndLogFallbackCandidates(attemptedProviders, opts, { failedProvider: activeProvider.name, turn })
|
|
8637
8829
|
: [];
|
|
8638
8830
|
const verdict = decideProviderFallback({
|
|
8639
8831
|
err,
|
|
@@ -8670,6 +8862,8 @@ export async function streamLLMWithTools(
|
|
|
8670
8862
|
activeProvider = finalized.provider;
|
|
8671
8863
|
activeModel = finalized.model;
|
|
8672
8864
|
attemptedProviders.add(activeProvider.name);
|
|
8865
|
+
// 재시도 상한은 «공급자마다» — 넘어간 공급자도 스트림 도중 끊김이면 다시 5회까지 건다.
|
|
8866
|
+
streamDisconnectRetries = 0;
|
|
8673
8867
|
turnOpts = buildTurnOpts();
|
|
8674
8868
|
streamIter = undefined;
|
|
8675
8869
|
continue;
|
|
@@ -8687,7 +8881,7 @@ export async function streamLLMWithTools(
|
|
|
8687
8881
|
if (ev.type === 'text') {
|
|
8688
8882
|
turnText += ev.delta;
|
|
8689
8883
|
fullText += ev.delta;
|
|
8690
|
-
|
|
8884
|
+
emitRetryDisplayStep(retryDisplay.onText(ev.delta, turnText));
|
|
8691
8885
|
} else if (ev.type === 'reasoning_details') {
|
|
8692
8886
|
turnReasoningDetails = ev.details;
|
|
8693
8887
|
} else if (ev.type === 'tool_call') {
|
|
@@ -8724,6 +8918,7 @@ export async function streamLLMWithTools(
|
|
|
8724
8918
|
});
|
|
8725
8919
|
}
|
|
8726
8920
|
} else if (ev.type === 'image') {
|
|
8921
|
+
streamEmittedImage = true;
|
|
8727
8922
|
// Y2·1 (2026-05-17) — forward Codex server-tool image result.
|
|
8728
8923
|
// Only fires when caller opted into opts.serverTools.imageGeneration
|
|
8729
8924
|
// and the model invoked the built-in tool. No-op when handler
|
|
@@ -8780,6 +8975,7 @@ export async function streamLLMWithTools(
|
|
|
8780
8975
|
}
|
|
8781
8976
|
|
|
8782
8977
|
// hang 진단 — for-await(SSE 스트림) 정상 종료 확정. 이 로그가 없으면 codex SSE 스트림 hang.
|
|
8978
|
+
emitRetryDisplayStep(retryDisplay.settle(turnText));
|
|
8783
8979
|
debug.log('llm.stream', 'consume-end', { turn, evCount, lastEvType, textChars: turnText.length, pendingCalls: pendingCalls.length });
|
|
8784
8980
|
const turnInfo = {
|
|
8785
8981
|
turn,
|
|
@@ -8826,6 +9022,10 @@ export async function streamLLMWithTools(
|
|
|
8826
9022
|
verificationLoopState,
|
|
8827
9023
|
finalization,
|
|
8828
9024
|
);
|
|
9025
|
+
if (finalText !== visibleText) {
|
|
9026
|
+
const answer = visibleText.trim();
|
|
9027
|
+
handlers.onFinalAnswerSupplement?.({ answer, supplement: finalText.slice(answer.length).trim(), finalText });
|
|
9028
|
+
}
|
|
8829
9029
|
if (finalText !== fullText) handlers.onText('', finalText);
|
|
8830
9030
|
emitTurnComplete(finalText);
|
|
8831
9031
|
return finalText;
|
|
@@ -8835,6 +9035,17 @@ export async function streamLLMWithTools(
|
|
|
8835
9035
|
// MAX_EMPTY_RETRIES times. Beyond that, return an explicit
|
|
8836
9036
|
// no-synthesis notice instead of silently ending the turn empty.
|
|
8837
9037
|
if (pendingCalls.length === 0 && turnText.length === 0) {
|
|
9038
|
+
// TUI-GOAL-LOOP-FRICTION(#63) — 종결 신호(update_goal)를 이미 받았고 답도 이미 썼다 = 할 말이 없는 게 맞다.
|
|
9039
|
+
// 빈 턴을 «정체»로 보고 재촉·`[NO FINAL SYNTHESIS]` 를 붙이지 않고 그 답으로 끝낸다.
|
|
9040
|
+
if (terminalSignalDispatched && lastToolRoundText.trim().length > 0) {
|
|
9041
|
+
const answer = lastToolRoundText;
|
|
9042
|
+
debug.log('goal.loop', 'empty-turn-after-terminal-signal', {
|
|
9043
|
+
turn, emptyRetries, answerChars: answer.length,
|
|
9044
|
+
}, { level: 'info' });
|
|
9045
|
+
if (answer !== fullText) handlers.onText('', answer);
|
|
9046
|
+
emitTurnComplete(answer);
|
|
9047
|
+
return answer;
|
|
9048
|
+
}
|
|
8838
9049
|
if (emptyRetries >= MAX_EMPTY_RETRIES) {
|
|
8839
9050
|
const notice = buildNoFinalSynthesisNotice('empty-turn');
|
|
8840
9051
|
const visibleText = finalizeVisibleAssistantText(
|
|
@@ -8870,6 +9081,11 @@ export async function streamLLMWithTools(
|
|
|
8870
9081
|
clearVisibleAssistantTextForToolRound(handlers, sawToolRound);
|
|
8871
9082
|
}
|
|
8872
9083
|
sawToolRound = true;
|
|
9084
|
+
if (turnText.trim().length > 0) lastToolRoundText = turnText;
|
|
9085
|
+
// TUI-GOAL-LOOP-FRICTION(#46) — 이 턴의 호출이 «종결 신호뿐»이면 예산·후속 단계 거부를 걸지 않는다.
|
|
9086
|
+
const terminalOnlyTurn = terminalToolNames.size > 0
|
|
9087
|
+
&& pendingCalls.length > 0
|
|
9088
|
+
&& pendingCalls.every((call) => terminalToolNames.has(call.name));
|
|
8873
9089
|
const wasExploratoryTurn = isExploratoryTurn(pendingCalls);
|
|
8874
9090
|
const prevExploratoryStreak = exploratoryTurnStreak;
|
|
8875
9091
|
exploratoryTurnStreak = wasExploratoryTurn ? exploratoryTurnStreak + 1 : 0;
|
|
@@ -8926,40 +9142,47 @@ export async function streamLLMWithTools(
|
|
|
8926
9142
|
// maxTurns hard-stops it, producing 0 chars of output. Hard
|
|
8927
9143
|
// rejection forces the synthesis that soft pressure couldn't.
|
|
8928
9144
|
const inSynthesisPhase =
|
|
8929
|
-
|
|
9145
|
+
!terminalOnlyTurn
|
|
9146
|
+
&& maxTurns >= BUDGET_WARNING_MIN_TURNS
|
|
8930
9147
|
&& turn >= maxTurns - FINAL_SYNTHESIS_TURNS;
|
|
8931
9148
|
const codexInspectionStillProgressing =
|
|
8932
9149
|
modelFamily === 'codex'
|
|
8933
9150
|
&& autoNarrowedReadCount > 0
|
|
8934
9151
|
&& autoNarrowedReadCount < inspectBudgetThreshold;
|
|
8935
9152
|
const inExplorationSynthesisPhase =
|
|
8936
|
-
|
|
9153
|
+
!terminalOnlyTurn
|
|
9154
|
+
&& exploratoryTurnStreak >= explorationThresholdForTurn
|
|
8937
9155
|
&& isExploratoryTurn(pendingCalls)
|
|
8938
9156
|
&& !codexInspectionStillProgressing;
|
|
8939
9157
|
const inInspectSynthesisPhase =
|
|
8940
|
-
|
|
9158
|
+
!terminalOnlyTurn
|
|
9159
|
+
&& inspectSynthesisArmed
|
|
8941
9160
|
&& inspectFollowupMode === 'synthesis'
|
|
8942
9161
|
&& pendingCalls.length > 0;
|
|
8943
9162
|
const inInspectActionPhase =
|
|
8944
|
-
|
|
9163
|
+
!terminalOnlyTurn
|
|
9164
|
+
&& inspectSynthesisArmed
|
|
8945
9165
|
&& inspectFollowupMode === 'action'
|
|
8946
9166
|
&& !verifyActionArmed
|
|
8947
9167
|
&& pendingCalls.length > 0
|
|
8948
9168
|
&& !isInspectActionTurn(pendingCalls);
|
|
8949
9169
|
const inInspectExecutionPhase =
|
|
8950
|
-
|
|
9170
|
+
!terminalOnlyTurn
|
|
9171
|
+
&& inspectSynthesisArmed
|
|
8951
9172
|
&& inspectFollowupMode === 'execution'
|
|
8952
9173
|
&& !repairActionArmed
|
|
8953
9174
|
&& !verifyActionArmed
|
|
8954
9175
|
&& pendingCalls.length > 0
|
|
8955
9176
|
&& !isExecutionActionTurn(pendingCalls);
|
|
8956
9177
|
const inRepairActionPhase =
|
|
8957
|
-
|
|
9178
|
+
!terminalOnlyTurn
|
|
9179
|
+
&& repairActionArmed
|
|
8958
9180
|
&& !verifyActionArmed
|
|
8959
9181
|
&& pendingCalls.length > 0
|
|
8960
9182
|
&& !isRepairActionTurn(pendingCalls);
|
|
8961
9183
|
const inVerifyActionPhase =
|
|
8962
|
-
|
|
9184
|
+
!terminalOnlyTurn
|
|
9185
|
+
&& verifyActionArmed
|
|
8963
9186
|
&& pendingCalls.length > 0
|
|
8964
9187
|
&& !isVerifyActionTurn(pendingCalls);
|
|
8965
9188
|
const inInspectFollowupPhase =
|
|
@@ -9009,11 +9232,18 @@ export async function streamLLMWithTools(
|
|
|
9009
9232
|
let callsToDispatch = pendingCalls;
|
|
9010
9233
|
let appendedToolResultNotice: string | null = null;
|
|
9011
9234
|
let phaseRejectionMessage: string | null = null;
|
|
9012
|
-
|
|
9235
|
+
// TUI-GOAL-LOOP-FRICTION(#46) — 섞인 턴에서도 종결 신호는 거부 대상에서 뺀다(다른 호출만 거부).
|
|
9236
|
+
const phaseRejectedCalls = getToolLoopPhaseRejectedCalls(inspectFollowupPhase, pendingCalls)
|
|
9237
|
+
.filter((call) => !terminalToolNames.has(call.name));
|
|
9013
9238
|
const phaseRejectedCallIds = new Set(phaseRejectedCalls.map((call) => call.id));
|
|
9014
9239
|
const rejectsWholeBatch = inSynthesisPhase || inExplorationSynthesisPhase || inInspectSynthesisPhase;
|
|
9240
|
+
/** 통째 거부 턴에 섞인 종결 신호 — 거부 스텁 대신 수신 확인을 준다. */
|
|
9241
|
+
const isTerminalCall = (call: { name: string }): boolean => terminalToolNames.has(call.name);
|
|
9242
|
+
const terminalAck = (call: { name: string }): string => JSON.stringify({
|
|
9243
|
+
ok: true, terminalSignal: call.name, note: 'terminal signal recorded; other tool calls in this turn did not run',
|
|
9244
|
+
});
|
|
9015
9245
|
if (rejectsWholeBatch || phaseRejectedCalls.length > 0) {
|
|
9016
|
-
const rejectedCalls = rejectsWholeBatch ? pendingCalls : phaseRejectedCalls;
|
|
9246
|
+
const rejectedCalls = rejectsWholeBatch ? pendingCalls.filter((call) => !isTerminalCall(call)) : phaseRejectedCalls;
|
|
9017
9247
|
const executedCalls = rejectsWholeBatch ? [] : pendingCalls.filter((call) => !phaseRejectedCallIds.has(call.id));
|
|
9018
9248
|
const rejectionMsg =
|
|
9019
9249
|
inspectFollowupPhase
|
|
@@ -9036,8 +9266,17 @@ export async function streamLLMWithTools(
|
|
|
9036
9266
|
phaseRejectionMessage = rejectionMsg;
|
|
9037
9267
|
if (rejectsWholeBatch) {
|
|
9038
9268
|
callsToDispatch = [];
|
|
9039
|
-
|
|
9040
|
-
|
|
9269
|
+
// 공급자 순서를 지키려고 pendingCalls 순서대로 채운다 — 종결 신호만 수신 확인, 나머지는 거부 스텁.
|
|
9270
|
+
for (const call of pendingCalls) {
|
|
9271
|
+
if (isTerminalCall(call)) {
|
|
9272
|
+
terminalSignalDispatched = true;
|
|
9273
|
+
resultBlocks.push({ type: 'tool_result', tool_use_id: call.id, content: terminalAck(call) });
|
|
9274
|
+
debug.log('goal.loop', 'terminal-signal-exempt-from-budget', {
|
|
9275
|
+
turn, maxTurns, tool: call.name, rejectedTools: rejectedCalls.map((c) => c.name),
|
|
9276
|
+
}, { level: 'info' });
|
|
9277
|
+
} else {
|
|
9278
|
+
resultBlocks.push({ type: 'tool_result', tool_use_id: call.id, content: rejectionMsg });
|
|
9279
|
+
}
|
|
9041
9280
|
}
|
|
9042
9281
|
}
|
|
9043
9282
|
// P2 (2026-05-03) — Three predicates as before, but each now consults
|
|
@@ -9288,7 +9527,9 @@ export async function streamLLMWithTools(
|
|
|
9288
9527
|
for (const call of pendingCalls) {
|
|
9289
9528
|
handlers.onToolCall?.(call);
|
|
9290
9529
|
toolCallHistory.push({ name: call.name, args: call.args });
|
|
9291
|
-
handlers.onToolResult?.({
|
|
9530
|
+
handlers.onToolResult?.({
|
|
9531
|
+
id: call.id, name: call.name, result: isTerminalCall(call) ? terminalAck(call) : phaseRejectionMessage!,
|
|
9532
|
+
});
|
|
9292
9533
|
}
|
|
9293
9534
|
}
|
|
9294
9535
|
if (!rejectsWholeBatch && hardStopText === null) {
|
|
@@ -9332,6 +9573,14 @@ export async function streamLLMWithTools(
|
|
|
9332
9573
|
result: unknown,
|
|
9333
9574
|
): void => {
|
|
9334
9575
|
if (call.name !== 'RunShell' && call.name !== 'Bash') return;
|
|
9576
|
+
if (isSteeredShellRejection(result)) {
|
|
9577
|
+
debug.log('llm.router', 'tool-loop.steered-rejection-not-failure', {
|
|
9578
|
+
turn,
|
|
9579
|
+
tool: call.name,
|
|
9580
|
+
approvalKey: (result as { approvalKey: string }).approvalKey,
|
|
9581
|
+
});
|
|
9582
|
+
return;
|
|
9583
|
+
}
|
|
9335
9584
|
const verificationAttempt = verifyActionArmed;
|
|
9336
9585
|
const executionCommand = summarizeExecutionCommand(call.name, call.args);
|
|
9337
9586
|
const executionSummary = summarizeExecutionResult(result);
|
|
@@ -9488,32 +9737,55 @@ export async function streamLLMWithTools(
|
|
|
9488
9737
|
| { kind: 'absent' }
|
|
9489
9738
|
| { kind: 'complete'; label: string }
|
|
9490
9739
|
| { kind: 'truncated'; label: string };
|
|
9491
|
-
const anchorFileState = (systemMessages: LLMMessage[], filename: string): AnchorFileState => {
|
|
9492
|
-
const
|
|
9493
|
-
const opening = new RegExp(`^=== (.+) \\(${escapedFilename}(?: @ [^)]+)?\\) ===$`, 'm');
|
|
9494
|
-
const closing = new RegExp(`^=== end ${escapedFilename}(?: @ .+)? ===$`, 'm');
|
|
9740
|
+
const anchorFileState = (systemMessages: LLMMessage[], filename: string, filePath?: string): AnchorFileState => {
|
|
9741
|
+
const opening = /^=== (.+) \(([^()]+?)(?: @ ([^)]+))?\) ===$/gm;
|
|
9495
9742
|
for (const message of systemMessages) {
|
|
9496
9743
|
if (message.role !== 'system' || typeof message.content !== 'string') continue;
|
|
9497
|
-
const openingMatch
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9501
|
-
|
|
9502
|
-
|
|
9503
|
-
|
|
9504
|
-
|
|
9744
|
+
for (const openingMatch of message.content.matchAll(opening)) {
|
|
9745
|
+
const fencedPath = openingMatch[2]!;
|
|
9746
|
+
const scope = openingMatch[3];
|
|
9747
|
+
if (fencedPath.split('/').pop() !== filename) continue;
|
|
9748
|
+
// The actual project-anchor fence names a filename + its
|
|
9749
|
+
// directory relative to this turn's cwd. Keep the full path
|
|
9750
|
+
// when one is supplied explicitly, never just its basename.
|
|
9751
|
+
const anchorPath = scope === 'instance root'
|
|
9752
|
+
? globalAnchorPath()
|
|
9753
|
+
: resolve(scope ?? '.', fencedPath);
|
|
9754
|
+
if (filePath !== undefined) {
|
|
9755
|
+
// macOS may spell the same /var path as /private/var in cwd;
|
|
9756
|
+
// Read accepts either. Canonicalize both real files so a
|
|
9757
|
+
// symlink spelling cannot turn a loaded anchor into a miss.
|
|
9758
|
+
const samePath = (path: string): string => {
|
|
9759
|
+
try { return realpathSync(path); } catch { return resolve(path); }
|
|
9760
|
+
};
|
|
9761
|
+
if (!anchorPath || samePath(anchorPath) !== samePath(filePath)) continue;
|
|
9762
|
+
}
|
|
9763
|
+
const contentStart = openingMatch.index + openingMatch[0].length;
|
|
9764
|
+
const escapedPath = fencedPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
9765
|
+
const escapedScope = scope?.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
9766
|
+
// Current fences close with their scope. Accept a legacy
|
|
9767
|
+
// scopeless closing fence as well, but never another scope.
|
|
9768
|
+
const closing = new RegExp(`^=== end ${escapedPath}${escapedScope ? `(?: @ ${escapedScope})?` : ''} ===$`, 'm');
|
|
9769
|
+
const closingMatch = closing.exec(message.content.slice(contentStart));
|
|
9770
|
+
if (closingMatch === null) continue;
|
|
9771
|
+
const content = message.content.slice(contentStart, contentStart + closingMatch.index);
|
|
9772
|
+
return content.includes('…[truncated to fit anchor budget]')
|
|
9773
|
+
? { kind: 'truncated', label: openingMatch[1] }
|
|
9774
|
+
: { kind: 'complete', label: openingMatch[1] };
|
|
9775
|
+
}
|
|
9505
9776
|
}
|
|
9506
9777
|
return { kind: 'absent' };
|
|
9507
9778
|
};
|
|
9508
|
-
const anchorStubContext = (filename: string): string => {
|
|
9509
|
-
const state = anchorFileState(messages, filename);
|
|
9779
|
+
const anchorStubContext = (filename: string, filePath?: string): string => {
|
|
9780
|
+
const state = anchorFileState(messages, filename, filePath);
|
|
9781
|
+
const namedPath = filePath ?? filename;
|
|
9510
9782
|
if (state.kind === 'absent') {
|
|
9511
|
-
return `\`${
|
|
9783
|
+
return `\`${namedPath}\` is not present in the system prompt.`;
|
|
9512
9784
|
}
|
|
9513
9785
|
if (state.kind === 'truncated') {
|
|
9514
|
-
return `Only a prefix of \`${
|
|
9786
|
+
return `Only a prefix of \`${namedPath}\` is present in the system prompt under the \`${state.label}\` anchor; the remainder is unavailable.`;
|
|
9515
9787
|
}
|
|
9516
|
-
return `The full text of \`${
|
|
9788
|
+
return `The full text of \`${namedPath}\` is present in the system prompt under the \`${state.label}\` anchor.`;
|
|
9517
9789
|
};
|
|
9518
9790
|
// W4-anchor (2026-05-03 PM) — Scope: codex family only. Glob anchor detection is permissive:
|
|
9519
9791
|
// contains 'AGENTS' or 'CLAUDE' AND contains '.md'. This catches
|
|
@@ -9575,11 +9847,10 @@ export async function streamLLMWithTools(
|
|
|
9575
9847
|
// instead. A guardian test keeps the repo's own candidates under
|
|
9576
9848
|
// the cap — see test/prompt-library-universal-preamble.test.ts.
|
|
9577
9849
|
//
|
|
9578
|
-
// Match
|
|
9579
|
-
//
|
|
9580
|
-
//
|
|
9581
|
-
//
|
|
9582
|
-
// since basename match is strict.
|
|
9850
|
+
// Match only a file whose resolved path corresponds to a complete or
|
|
9851
|
+
// truncated fence in this turn's system prompt. A same-named file in
|
|
9852
|
+
// another directory (or a policy-excluded CLAUDE.md) must remain
|
|
9853
|
+
// readable; a filename alone is not evidence that it was loaded.
|
|
9583
9854
|
const isAnchorRead = (
|
|
9584
9855
|
call: { name: string; args: Record<string, unknown> },
|
|
9585
9856
|
): { filePath: string } | null => {
|
|
@@ -9587,7 +9858,8 @@ export async function streamLLMWithTools(
|
|
|
9587
9858
|
const filePath = typeof call.args.file_path === 'string' ? call.args.file_path : '';
|
|
9588
9859
|
if (filePath.length === 0) return null;
|
|
9589
9860
|
const basename = filePath.split('/').pop() ?? '';
|
|
9590
|
-
if (basename === 'AGENTS.md' || basename === 'CLAUDE.md')
|
|
9861
|
+
if ((basename === 'AGENTS.md' || basename === 'CLAUDE.md')
|
|
9862
|
+
&& anchorFileState(messages, basename, filePath).kind !== 'absent') {
|
|
9591
9863
|
return { filePath };
|
|
9592
9864
|
}
|
|
9593
9865
|
return null;
|
|
@@ -9760,7 +10032,14 @@ export async function streamLLMWithTools(
|
|
|
9760
10032
|
// naturally rotates files (verified 2026-04-25T06:56
|
|
9761
10033
|
// reproduction: docs/CAPABILITIES → PLAN → HANDOFF → ROADMAP
|
|
9762
10034
|
// → src/code-edit/{index,apply,safety}.ts across 5 turns).
|
|
9763
|
-
|
|
10035
|
+
// TUI-INITIATIVE-S ② — 같은 호출이 같은 오류로 DEDUP_THRESHOLD 번 끝났으면 계열·도구 무관(openai-codex·gpt 계열)하게 같은 RE-CALL 차단을 건다.
|
|
10036
|
+
const repeatedError = (modelFamily === 'codex' || modelFamily === 'gpt' || activeProvider.name === 'openai-codex')
|
|
10037
|
+
? erroredToolCallSignatures.get(signatureOf(call)) : undefined;
|
|
10038
|
+
if (repeatedError && repeatedError.count >= DEDUP_THRESHOLD) {
|
|
10039
|
+
debug.log('llm.router', 'tool-loop.dedup-blocked', { turn, tool: call.name, signature: signatureOf(call), priorCount: repeatedError.count, threshold: DEDUP_THRESHOLD, reason: 'repeated-error' });
|
|
10040
|
+
return { result: `${buildDedupStub(call, repeatedError.count)} Every one of those calls failed with the same error: ${repeatedError.error.slice(0, 200)}`, isError: false, phaseRejected: false };
|
|
10041
|
+
}
|
|
10042
|
+
if (codexBehaviorGuards && EXPLORATORY_TOOLS.has(call.name)) {
|
|
9764
10043
|
// W4-anchor — Anchor file Grep blocking. AGENTS.md / CLAUDE.md
|
|
9765
10044
|
// are already in the system prompt; greppling them is pure
|
|
9766
10045
|
// token waste and trains codex to ignore the in-prompt copy.
|
|
@@ -9916,7 +10195,7 @@ export async function streamLLMWithTools(
|
|
|
9916
10195
|
const filename = anchorRead.filePath.split('/').pop() ?? anchorRead.filePath;
|
|
9917
10196
|
const stub =
|
|
9918
10197
|
`ANCHOR READ BLOCKED — \`${anchorRead.filePath}\` matches an anchor-file read. ` +
|
|
9919
|
-
`${anchorStubContext(filename)} Move to a source file (e.g. \`src/...\`) for on-disk investigation.`;
|
|
10198
|
+
`${anchorStubContext(filename, anchorRead.filePath)} Move to a source file (e.g. \`src/...\`) for on-disk investigation.`;
|
|
9920
10199
|
return { result: stub, isError: false, phaseRejected: false };
|
|
9921
10200
|
}
|
|
9922
10201
|
// W5-A — Literal-path Glob redirect. Codex uses Glob({pattern:
|
|
@@ -10065,6 +10344,13 @@ export async function streamLLMWithTools(
|
|
|
10065
10344
|
// 스펙을 프로바이더에 선언하지 않는다는 의도가 우회되지 않게.
|
|
10066
10345
|
const resultSignalsError = !!result && typeof result === 'object'
|
|
10067
10346
|
&& typeof (result as { error?: unknown }).error === 'string';
|
|
10347
|
+
{
|
|
10348
|
+
const errSig = signatureOf(call);
|
|
10349
|
+
const errText = resultSignalsError ? (result as { error: string }).error : isError ? String(result) : null;
|
|
10350
|
+
const prevErr = erroredToolCallSignatures.get(errSig);
|
|
10351
|
+
if (errText === null) erroredToolCallSignatures.delete(errSig);
|
|
10352
|
+
else erroredToolCallSignatures.set(errSig, { error: errText, count: prevErr?.error === errText ? prevErr.count + 1 : 1 });
|
|
10353
|
+
}
|
|
10068
10354
|
if (!isError && !resultSignalsError) {
|
|
10069
10355
|
for (const spec of hydrated) {
|
|
10070
10356
|
if (activeToolNames.has(spec.name)) continue;
|
|
@@ -10092,7 +10378,7 @@ export async function streamLLMWithTools(
|
|
|
10092
10378
|
// W4-A — Track Read dispatches (only successful ones; error
|
|
10093
10379
|
// results don't count as "the file is in your context"). The
|
|
10094
10380
|
// post-Read broad-search guard above reads this counter.
|
|
10095
|
-
if (call.name === 'Read' && !isError &&
|
|
10381
|
+
if (call.name === 'Read' && !isError && codexBehaviorGuards) {
|
|
10096
10382
|
dispatchedReadCount++;
|
|
10097
10383
|
}
|
|
10098
10384
|
return { result, isError, phaseRejected: false };
|
|
@@ -10285,12 +10571,25 @@ export async function streamLLMWithTools(
|
|
|
10285
10571
|
};
|
|
10286
10572
|
const partition = phaseRejectedCalls.length > 0
|
|
10287
10573
|
? { parallelActivated: false, safeCount: 0, unsafeCount: callsToDispatch.length }
|
|
10288
|
-
: await dispatchWithParallelSafety(callsToDispatch, dispatchWithPostProc);
|
|
10574
|
+
: await dispatchWithParallelSafety(callsToDispatch, dispatchWithPostProc, opts.signal);
|
|
10289
10575
|
if (phaseRejectedCalls.length > 0) {
|
|
10290
10576
|
for (let index = 0; index < callsToDispatch.length; index++) {
|
|
10577
|
+
if (opts.signal?.aborted) continue;
|
|
10291
10578
|
await dispatchWithPostProc(callsToDispatch[index]!, index);
|
|
10292
10579
|
}
|
|
10293
10580
|
}
|
|
10581
|
+
// ⭐ TUI-ESC-ABORT-TOOLS — 중단(Esc)으로 «시작하지 않은» 호출은 «중단됨» 결과로 채운다
|
|
10582
|
+
// (tool_call/tool_result 짝 유지). `phaseRejected: true` 로 둬 doom·반복 추적에서 뺀다.
|
|
10583
|
+
// 다음 바퀴 머리의 `opts.signal?.aborted` 가 루프를 멈춘다.
|
|
10584
|
+
if (opts.signal?.aborted) {
|
|
10585
|
+
let skipped = 0;
|
|
10586
|
+
for (let index = 0; index < callsToDispatch.length; index++) {
|
|
10587
|
+
if (dispatchedResults[index]) continue;
|
|
10588
|
+
dispatchedResults[index] = { result: 'Tool call not started: the turn was aborted by the user (Esc).', isError: true, phaseRejected: true };
|
|
10589
|
+
skipped++;
|
|
10590
|
+
}
|
|
10591
|
+
if (skipped > 0) debug.log('llm.tools.aborted', 'batch-remaining-skipped', { turn, skipped });
|
|
10592
|
+
}
|
|
10294
10593
|
if (debug.enabled && partition.parallelActivated) {
|
|
10295
10594
|
debug.log('llm.tool-loop.parallel', 'safe-batch-dispatch', {
|
|
10296
10595
|
safeCount: partition.safeCount,
|
|
@@ -10616,6 +10915,20 @@ export async function streamLLMWithTools(
|
|
|
10616
10915
|
// route — see routeDoomLoopToAskUser above.
|
|
10617
10916
|
history.push({ role: LOOP_SELF_NOTE_ROLE, content: postToolResultUserNote });
|
|
10618
10917
|
}
|
|
10918
|
+
// 신호뿐인 턴 · 섞인 턴(정상 디스패치 · 부분 거부 · 통째 거부의 수신 확인) 모두 — 종결 신호가 이 턴에 «받아들여졌다».
|
|
10919
|
+
if (!hardStopText && pendingCalls.some(isTerminalCall)) terminalSignalDispatched = true;
|
|
10920
|
+
// TUI-GOAL-LOOP-FRICTION(#63) — 종결 신호뿐인 턴 ⊕ 같은 턴에 쓴 답 = 이 턴이 최종 답이다.
|
|
10921
|
+
// 다음 모델 턴을 열면 할 말이 없는 모델이 빈 턴을 되풀이하고 `[NO FINAL SYNTHESIS]` 가 붙는다(10-15 22:36Z 표본).
|
|
10922
|
+
// 이 턴에 답이 없으면 종전처럼 다음 턴을 연다(앞 라운드 글은 «하겠습니다» 류 서술일 수 있다 — 모델이 답을 쓰게).
|
|
10923
|
+
if (terminalOnlyTurn && !hardStopText && !postToolResultUserNote && turnText.trim().length > 0) {
|
|
10924
|
+
const answer = turnText;
|
|
10925
|
+
debug.log('goal.loop', 'terminal-signal-finish', {
|
|
10926
|
+
turn, maxTurns, tools: pendingCalls.map((call) => call.name), answerChars: answer.length,
|
|
10927
|
+
}, { level: 'info' });
|
|
10928
|
+
if (answer !== fullText) handlers.onText('', answer);
|
|
10929
|
+
emitTurnComplete(answer);
|
|
10930
|
+
return answer;
|
|
10931
|
+
}
|
|
10619
10932
|
if (hardStopText) {
|
|
10620
10933
|
// W5-E (2026-05-03 PM) — Force-synthesis no-tools pass. Before
|
|
10621
10934
|
// emitting the [SYNTHESIS IGNORED] / [ACTION IGNORED] / [VERIFY
|
|
@@ -10651,7 +10964,7 @@ export async function streamLLMWithTools(
|
|
|
10651
10964
|
// fix shape (no-tools synthesis with prior tool_results as
|
|
10652
10965
|
// context) lifts the empty reply to substantive answer.
|
|
10653
10966
|
const isForceSynthesisFamily =
|
|
10654
|
-
|
|
10967
|
+
codexBehaviorGuards || modelFamily === 'gemini';
|
|
10655
10968
|
const shouldForceSynthesis =
|
|
10656
10969
|
isForceSynthesisFamily
|
|
10657
10970
|
&& !isUserInterventionRequired
|
|
@@ -10819,7 +11132,7 @@ export async function streamLLMWithTools(
|
|
|
10819
11132
|
let synthesizedText: string | null = null;
|
|
10820
11133
|
const shouldForceSynthesisOnBudget =
|
|
10821
11134
|
loopTermination === 'budget-exhausted'
|
|
10822
|
-
&& (
|
|
11135
|
+
&& (codexBehaviorGuards || modelFamily === 'gemini')
|
|
10823
11136
|
&& !forceSynthesisAttempted;
|
|
10824
11137
|
if (shouldForceSynthesisOnBudget) {
|
|
10825
11138
|
forceSynthesisAttempted = true;
|
|
@@ -10897,6 +11210,7 @@ export async function streamLLMWithTools(
|
|
|
10897
11210
|
import type { LLMConfig as UCLLMConfig, UserConfig } from './user-config.js';
|
|
10898
11211
|
import { loadTokens, readCodexMirrorTokens } from './oauth/store.js';
|
|
10899
11212
|
import { resolveCodexAccount, effectiveCodexHome } from './oauth/codex-account.js';
|
|
11213
|
+
import { codexCreditSpendReason } from './oauth/codex-billing-route.js';
|
|
10900
11214
|
import { join } from 'node:path';
|
|
10901
11215
|
import {
|
|
10902
11216
|
CODEX_API_BASE_URL, getCodexUserAgent, loadFreshCodexAuthState,
|
|
@@ -11620,7 +11934,10 @@ export function getProviderForConfig(
|
|
|
11620
11934
|
? decision.provider.slice('auto:'.length)
|
|
11621
11935
|
: decision.provider;
|
|
11622
11936
|
if (provider === 'auto') {
|
|
11623
|
-
if (resolvedProviderName === 'auto')
|
|
11937
|
+
if (resolvedProviderName === 'auto') {
|
|
11938
|
+
if (testFakeLlmEnabled()) return testFakeLlmProvider;
|
|
11939
|
+
throw new NoLlmProviderAvailableError();
|
|
11940
|
+
}
|
|
11624
11941
|
if (!isKnownProviderName(resolvedProviderName)) {
|
|
11625
11942
|
throw new Error(`unknown provider: ${resolvedProviderName}`);
|
|
11626
11943
|
}
|
|
@@ -11696,7 +12013,7 @@ export function getProviderForConfig(
|
|
|
11696
12013
|
// union without a case here fails loud at first call.
|
|
11697
12014
|
throw new Error(`unknown provider: ${provider as string}`);
|
|
11698
12015
|
}
|
|
11699
|
-
import { getModelFamily } from './models/prompts.js';
|
|
12016
|
+
import { getModelFamily, usesCodexBehaviorGuards } from './models/prompts.js';
|
|
11700
12017
|
import type { ModelFamily } from './models/prompts.js';
|
|
11701
12018
|
|
|
11702
12019
|
// COMPAT(llm-facade-openai-sampling-fields) · 기존 llm.ts 공개 API 유지.
|